{ "cells": [ { "cell_type": "code", "execution_count": null, "id": "6cc85af8", "metadata": { "vscode": { "languageId": "plaintext" } }, "outputs": [], "source": [ "# 1. KAGGLE DEPENDENCIES\n", "!pip install langchain-core langchain-google-genai pypdf -q\n", "\n", "import os\n", "from langchain_google_genai import ChatGoogleGenerativeAI\n", "from langchain_core.prompts import PromptTemplate\n", "from IPython.display import display, Markdown\n", "from kaggle_secrets import UserSecretsClient\n", "\n", "# 2. API KEY SETUP\n", "try:\n", " # Fetches 'GOOGLE_API_KEY' from your Kaggle notebook secrets\n", " user_secrets = UserSecretsClient()\n", " os.environ[\"GOOGLE_API_KEY\"] = user_secrets.get_secret(\"GOOGLE_API_KEY\")\n", " print(\"✅ Google API Key loaded successfully from Kaggle Secrets.\")\n", "except Exception as e:\n", " print(f\"❌ Could not load API key from Kaggle Secrets: {e}\")\n", " print(\"Make sure you've added 'GOOGLE_API_KEY' in Add-ons > Secrets.\")\n", "\n", "\n", "llm = ChatGoogleGenerativeAI(\n", " model=\"gemini-2.5-flash\", \n", " temperature=0.2, \n", " max_output_tokens=2048\n", ")\n", "\n", "print(\"Environment initialized and LLM loaded successfully. Ready to cook.\")\n", "\n", "print(\"Environment initialized and LLM loaded successfully.\")\n", "\n", "# 3. UPGRADED PROMPT \n", "academic_prompt = PromptTemplate.from_template(\"\"\"\n", "You are a senior AI researcher writing a rebuttal for a peer-reviewed manuscript.\n", "\n", "[Paper Context from Document]\n", "{paper_context}\n", "\n", "[Technical Guardrails]\n", "{technical_guardrails}\n", "\n", "[Reviewer Comment]\n", "{reviewer_comment}\n", "\n", "[Instruction - Chain of Thought]\n", "1. Identify the core critique.\n", "2. Formulate a defense or concession based strictly on the [Paper Context] and [Technical Guardrails].\n", "3. Draft the final academic response.\n", "\n", "[Format Example - Few Shot]\n", "Reviewer: \"The dataset is too small.\"\n", "Draft: \"We thank the reviewer for this observation. While our dataset of 200 images is limited, we frame this as a single-environment proof-of-concept for consumer webcams, rather than a generalized solution. We have updated Section 4 to reflect this limitation.\"\n", "\n", "Draft the final response below:\n", "\"\"\")\n", "\n", "# Modern syntax: completely bypasses the buggy LLMChain module!\n", "rebuttal_chain = academic_prompt | llm\n", "\n", "# 4. DATA PIPELINE\n", "paper_context = \"\"\"\n", "Title: Evaluating Deployment Stability in Consumer-Webcam Face Anti-Spoofing.\n", "Findings: Base MobileNetV2 drops cross-dataset accuracy (NUAA 84.33% to 61.44%) but live webcam stability massively improves (P(real) ~ 0.998, zero flips). \n", "Limitations: Single Logitech C270 camera, one subject, LSTM uses test set for early stopping.\n", "\"\"\"\n", "\n", "technical_guardrails = \"\"\"\n", "1. Strictly ensure that liveness threshold logic is described as occurring AFTER the softmax layer. Do not allow the AI to mention evaluating thresholds directly from raw logits.\n", "2. Acknowledge LSTM results as an exploratory finding due to early stopping on the test set.\n", "\"\"\"\n", "\n", "comments = [\n", " \"1: weak accept... However, the study is limited by small and narrow custom data. The webcam-specific data includes 200 photographs and 40 videos collected using one Logitech C270 camera.\",\n", " \"0: borderline paper... The LSTM uses its test set for early stopping, which makes the reported 100% accuracy unreliable.\",\n", " \"-3: strong reject... The fine-tuned model also degrades on NUAA from 84.33% to 61.44% accuracy, especially on spoof detection, which raises a serious security concern.\",\n", " \"1: weak accept... A more structured presentation of the three models, along with a workflow diagram illustrating the relationships among datasets, training stages, and evaluation protocols, would greatly improve readability.\"\n", "]\n", "\n", "# 5. EXECUTION LOOP\n", "responses = []\n", "for i, comment in enumerate(comments, 1):\n", " try:\n", " # Using .invoke() for modern LangChain execution\n", " response = rebuttal_chain.invoke({\n", " \"paper_context\": paper_context,\n", " \"reviewer_comment\": comment,\n", " \"technical_guardrails\": technical_guardrails\n", " })\n", " \n", " responses.append(response.content)\n", " \n", " display(Markdown(f\"### 📝 Reviewer Comment {i}\"))\n", " display(Markdown(f\"> *{comment[:150]}...*\"))\n", " display(Markdown(f\"**🤖 Agent Rebuttal Draft:**\\n\\n{response.content}\"))\n", " display(Markdown(\"---\"))\n", " \n", " except Exception as e:\n", " responses.append(f\"[ERROR] Failed to process: {str(e)}\")\n", " display(Markdown(f\"**❌ Error on Comment {i}:** {str(e)}\"))\n", " display(Markdown(\"---\"))" ] } ], "metadata": { "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 5 }