ResearchPilot-AI / README.md
Visal9252's picture
Update README.md
cf58d99 verified
|
Raw
History Blame Contribute Delete
26.7 kB
---
title: 'ResearchPilot AI '
sdk: docker
emoji: 🌍
colorFrom: indigo
colorTo: purple
thumbnail: >-
https://cdn-uploads.huggingface.co/production/uploads/64ea5e1dc68ddc867b5ec02f/r8wTLNQPQIfsQjgazt_I5.png
short_description: ResearchPilot AI is an Autonomous Multi-Agent Research Syste
---
<div align="center">
# 🧭 ResearchPilot AI
### Autonomous Multi-Agent Research System
**Give it a topic β†’ Get a complete, evidence-backed research report with charts, citations, and PDF export.**
ResearchPilot AI runs a coordinated team of specialised AI agents β€” each with a focused job β€” orchestrated by LangGraph. It plans, routes, searches, analyses, fact-checks, visualises, writes, and self-grades, all from one query.
[![Python](https://img.shields.io/badge/Python-3.11+-3776AB?logo=python&logoColor=white)](https://python.org)
[![LangGraph](https://img.shields.io/badge/LangGraph-Orchestration-7C3AED)](https://langchain-ai.github.io/langgraph/)
[![Groq](https://img.shields.io/badge/Groq-Llama_3.3_70B-F97316)](https://groq.com)
[![Streamlit](https://img.shields.io/badge/UI-Streamlit-FF4B4B?logo=streamlit&logoColor=white)](https://streamlit.io)
[![Plotly](https://img.shields.io/badge/Charts-Plotly-3F4F75)](https://plotly.com)
[![ReportLab](https://img.shields.io/badge/PDF-ReportLab-1E3A5F)](https://www.reportlab.com)
[![License: MIT](https://img.shields.io/badge/License-MIT-22C55E)](LICENSE)
[πŸš€ Live Demo](#) Β· [πŸ“„ Report Sample](#) Β· [πŸ‘¨β€πŸ’» Portfolio](https://vishal-lazrus-portfolio.vercel.app/)
</div>
---
## πŸ“Œ Table of Contents
| # | Section |
|---|---|
| 1 | [What is ResearchPilot AI?](#-what-is-researchpilot-ai) |
| 2 | [What Makes It Different](#-what-makes-it-different) |
| 3 | [Architecture](#-architecture) |
| 4 | [How It Works β€” Real Example](#-how-it-works--real-example) |
| 5 | [Folder Structure](#-folder-structure) |
| 6 | [The Five Agents](#-the-five-agents) |
| 7 | [The Six Chart Types](#-the-six-chart-types) |
| 8 | [Getting API Keys (Free)](#-getting-api-keys-free) |
| 9 | [Installation & Setup](#-installation--setup) |
| 10 | [Running the Project](#-running-the-project) |
| 11 | [Deploy to Hugging Face Spaces](#-deploy-to-hugging-face-spaces) |
| 12 | [Concepts Covered](#-concepts-covered) |
| 13 | [Troubleshooting](#-troubleshooting) |
| 14 | [Roadmap](#-roadmap) |
| 15 | [Connect With Me](#-connect-with-me) |
---
## πŸ€” What is ResearchPilot AI?
ResearchPilot AI is a **multi-agent AI research system** built with LangGraph. You type one query β€” say, *"Impact of AI on healthcare market growth"* β€” and it autonomously runs an 8-node pipeline:
```
Query β†’ Plan β†’ Route β†’ Research + Analyse β†’ Visualise β†’ Write β†’ Grade β†’ Deliver
```
The system produces:
- βœ… A **structured markdown report** (Executive Summary β†’ Key Findings β†’ Analysis β†’ Expert Perspective β†’ Conclusion β†’ References)
- πŸ“Š Up to **6 interactive Plotly charts** generated from real statistical data
- πŸ“„ A **professional academic PDF** with embedded charts and APA citations
- πŸ—‚οΈ A **CSV file** of the raw statistics for further analysis
> This is not a chatbot wrapper. It implements the **planner β†’ router β†’ workers β†’ critic** pattern used in production agentic AI systems.
### Who is this for?
| πŸŽ“ Students | πŸ’Ό Professionals | πŸ§‘β€πŸ’» Developers |
|---|---|---|
| Research papers, literature reviews, assignment prep | Market research, competitive analysis, technology evaluation | Learn LangGraph, conditional routing, agentic design patterns |
---
## ✨ What Makes It Different
| Feature | What it does |
|---|---|
| πŸ”€ **Dynamic Router Agent** | One LLM call decides *per-query* which of 5 specialist agents to activate. A history question never wastes time running a Statistics agent. A finance query gets Fact Checker. Nothing runs unless it adds value. |
| πŸ“Š **Statistics β†’ Charts pipeline** | The Statistics agent returns *structured JSON* (not prose) β€” metrics, time-series, regional breakdowns β€” which directly drives 6 Plotly chart types with no extra LLM calls. |
| πŸŽ“ **Persona-driven Domain Expert** | Adopts a credentialed persona per domain ("Dr. Sarah Chen, Harvard physician" for healthcare; "Marcus Reid, ex-Goldman analyst" for finance) β€” sharper than a generic "you are an expert" prompt. |
| βœ… **Dedicated Fact Checker** | Extracts specific claims, runs independent search evidence per claim, labels each: Verified / Partially True / Disputed / Unverifiable. |
| πŸ† **Self-grading + auto-retry** | Quality Gate scores the report 0–10 against five weighted criteria. Below 7 β†’ automatic retry with explicit feedback. Capped at 2 retries to prevent runaway cost. |
| πŸ–ΌοΈ **Cover runs after scoring** | The SVG cover card is generated *last* β€” after Quality Gate β€” so it always shows the real quality score, not zero. |
| πŸ“„ **ReportLab academic PDF** | Flowable single-column layout, deep-blue academic headings, horizontal rule separators, charts embedded directly under their matching report section. |
---
## πŸ—οΈ Architecture
> **Exact node execution order as wired in `graph/graph_builder.py`:**
```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ USER QUERY β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 🧠 PLANNER β”‚
β”‚ β”‚
β”‚ β€’ Detects domain β”‚
β”‚ β€’ Builds 3 tasks β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ πŸ”€ ROUTER β”‚
β”‚ β”‚
β”‚ Single LLM call β”‚
β”‚ β†’ active_agents β”‚
β”‚ list in state β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ βš™οΈ WORKERS NODE β”‚
β”‚ Only activated agents run β”‚
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ πŸ”Research β”‚ β”‚ πŸ“ŠStats β”‚ β”‚ πŸŽ“Domain Expert β”‚ β”‚
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ 3 Tavily β”‚ β”‚ Structured β”‚ β”‚ Persona prompt β”‚ β”‚
β”‚ β”‚ searches β”‚ β”‚ JSON β†’ β”‚ β”‚ per domain β”‚ β”‚
β”‚ β”‚ β†’ LLM β”‚ β”‚ chart data β”‚ β”‚ β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
β”‚ β”‚ βœ…Fact β”‚ β”‚ πŸ“–Refs β”‚ β”‚ β”‚
β”‚ β”‚ Checker β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ Claim-by- β”‚ β”‚ APA format β”‚ β”‚ β”‚
β”‚ β”‚ claim β”‚ β”‚ citations β”‚ β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ Virtual File System β”‚
β”‚ (shared dict living in state) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ πŸ“ˆ VISUALIZATION β”‚
β”‚ β”‚
β”‚ Statistics JSON β”‚
β”‚ β†’ 6 Plotly chartsβ”‚
β”‚ (no LLM call) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ ✍️ WRITER β”‚
β”‚ β”‚
β”‚ Reads all 5 VFS β”‚
β”‚ files β†’ builds β”‚
β”‚ final report β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€ πŸ† QUALITY GATE │◄────────────────────┐
β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ LLM scores 0-10 β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ β”‚
β”‚ score β‰₯ 7 β”‚ score < 7 (max 2 retries) β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”˜ └──────────────────────► Writer
β”‚ β–Ό
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚ πŸ–ΌοΈ COVER β”‚
β”‚ β”‚ β”‚
β”‚ β”‚ SVG card with β”‚
β”‚ β”‚ real score baked β”‚
β”‚ β”‚ in (runs last) β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
STREAMLIT UI
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ πŸ”¬ Research β”‚ πŸ“Š Data&Charts β”‚
β”‚ πŸ“– Referencesβ”‚ πŸ“„ Report β”‚
β”‚ β”‚ ⏱️ Trace β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
MD Β· CSV Β· PDF downloads
```
---
## ⚑ How It Works β€” Real Example
**Query typed:** `"Impact of AI on healthcare market growth: adoption rates, investment trends and future outlook"`
| Step | Node | What happens |
|---|---|---|
| 1 | **Planner** | Detects `topic_domain = "healthcare"`. Creates tasks: search clinical data, find market numbers, locate key organisations. |
| 2 | **Router** | One LLM call β†’ `["research", "statistics", "domain_expert", "fact_checker", "citation"]`. All 5 activate because healthcare needs everything. |
| 3a | **Research** | Runs 3 Tavily searches: raw query + "latest developments 2025" + "key findings evidence". LLM synthesises into structured deep-research. Writes `research_deep.txt` to VFS. |
| 3b | **Statistics** | Searches for "$45B market size", "29% CAGR" etc. Forces LLM to return exact JSON schema (metrics array + trends array + comparisons array). Writes `statistics.txt` + `statistics_data.csv`. |
| 3c | **Domain Expert** | Persona: *"Dr. Sarah Chen, Harvard-trained physician"*. Reads `research_deep.txt`, adds clinical nuance. Writes `expert_analysis.txt`. |
| 3d | **Fact Checker** | Extracts 6 specific claims. Verifies 4 individually via fresh Tavily searches. Labels βœ…/⚠️/❌. Writes `fact_check.txt`. |
| 3e | **References** | Formats all sources from `raw_search.txt` into APA JSON. Writes `references.txt`. Returns structured `citations` list. |
| 4 | **Visualization** | No LLM call. Reads `structured_data` dict β†’ builds 6 Plotly figures β†’ stores as JSON strings in `chart_json`. |
| 5 | **Writer** | Checks each VFS key. Builds context from whichever files exist. One large LLM call produces 9-section markdown report. |
| 6 | **Quality Gate** | LLM scores the report: **7.5/10**. `should_retry()` returns `"done"`. Routes to Cover. |
| 7 | **Cover** | Now has `quality_score = 7.5`. Generates SVG card with real score baked in. |
| **End** | **UI** | 5 sections rendered. Download MD + CSV + PDF available. |
---
## πŸ“ Folder Structure
```
ResearchPilot AI/ ← root folder
β”‚
β”œβ”€β”€ graph/ ← LangGraph nodes (the "brain")
β”‚ β”œβ”€β”€ __init__.py
β”‚ β”œβ”€β”€ state.py ← ResearchState TypedDict β€” shared memory
β”‚ β”‚ every node reads from and writes to
β”‚ β”œβ”€β”€ llm_factory.py ← get_llm() β€” Groq primary, Gemini fallback
β”‚ β”‚ every node imports this, never hardcodes
β”‚ β”œβ”€β”€ planner.py ← Node 1: detects domain, builds task list
β”‚ β”œβ”€β”€ router.py ← Node 2: LLM β†’ active_agents list
β”‚ β”œβ”€β”€ workers.py ← Node 3: all 5 specialist agents
β”‚ β”‚ conditionally called by if "agent" in active_agents
β”‚ β”œβ”€β”€ visualization.py ← Node 4: structured_data JSON β†’ 6 Plotly charts
β”‚ β”‚ (no LLM call β€” pure Python/Plotly)
β”‚ β”œβ”€β”€ synthesizer.py ← Node 5 (displayed as "Writer"):
β”‚ β”‚ reads VFS β†’ one LLM call β†’ final report
β”‚ β”œβ”€β”€ quality_gate.py ← Node 6: scores report + should_retry() function
β”‚ β”‚ drives the conditional edge / retry loop
β”‚ β”œβ”€β”€ thumbnail.py ← Node 7 (displayed as "Cover"):
β”‚ β”‚ runs AFTER quality_gate so score exists
β”‚ └── graph_builder.py ← Wires all 7 nodes + edges + conditional edge
β”‚ into one compiled StateGraph object
β”‚
β”œβ”€β”€ tools/ ← Utilities used by nodes (not nodes themselves)
β”‚ β”œβ”€β”€ __init__.py
β”‚ β”œβ”€β”€ search_tool.py ← web_search() wraps Tavily API
β”‚ β”‚ returns plain string for LLM context
β”‚ β”œβ”€β”€ file_system.py ← vfs_write() / vfs_read() helpers
β”‚ β”‚ copy-on-write to keep state immutable
β”‚ └── pdf_generator.py ← ReportLab flowable PDF
β”‚ strips duplicate References section,
β”‚ embeds charts under matching headings
β”‚
β”œβ”€β”€ ui/
β”‚ └── app.py ← Single-page Streamlit UI (~800 lines)
β”‚ st.session_state caches results so
β”‚ download clicks don't re-run the pipeline
β”‚
β”œβ”€β”€ .streamlit/
β”‚ └── config.toml ← Dark theme + port 7860 for HF Spaces
β”‚
β”œβ”€β”€ Dockerfile ← Production Docker image for HF Spaces
β”œβ”€β”€ main.py ← Terminal test runner (no UI)
β”œβ”€β”€ app.py ← HF Spaces entry point
β”œβ”€β”€ requirements.txt
β”œβ”€β”€ .env.example ← API key template
β”œβ”€β”€ .gitignore ← Excludes .env, __pycache__, *.pdf
└── README.md
```
---
## πŸ€– The Five Agents
| Agent | File | Activates when | What it produces |
|---|---|---|---|
| **Research** | `workers.py` | Always | 3-angle Tavily search + LLM synthesis β†’ `research_deep.txt` |
| **Statistics** | `workers.py` | Topic has numbers/trends | Structured JSON (metrics + trends + comparisons) + CSV β†’ `statistics.txt` |
| **Domain Expert** | `workers.py` | Specialised topic | Persona-primed analysis β†’ `expert_analysis.txt` |
| **Fact Checker** | `workers.py` | Claims need verification | Per-claim Tavily verify β†’ `fact_check.txt` |
| **References** | `workers.py` | Citations add value | APA-formatted JSON list β†’ `references.txt` |
All agents share data through the **Virtual File System** β€” a `Dict[str, str]` inside LangGraph state. Zero disk I/O.
---
## πŸ“Š The Six Chart Types
All generated from Statistics agent JSON with zero extra LLM calls:
| # | Chart | Driven by |
|---|---|---|
| 1 | **Horizontal Bar** | `metrics` array |
| 2 | **Multi-series Area / Trend** | `trends[].data_points` |
| 3 | **Donut / Pie** | `comparisons` array |
| 4 | **Gauge** | First 0–100 metric value |
| 5 | **Bubble Scatter** | All `metrics` (size = relative value) |
| 6 | **Year-on-Year Bar** | `trends[0].data_points` |
---
## πŸ”‘ Getting API Keys (Free)
### Groq β€” Primary LLM ⭐ Required
Fast open-source inference (14,400 free requests/day):
1. [console.groq.com](https://console.groq.com) β†’ Sign up β†’ API Keys β†’ Create
2. Copy: `gsk_...`
### Tavily β€” Web Search βœ… Required
Real-time web search for agents:
1. [app.tavily.com](https://app.tavily.com) β†’ Sign up β†’ Dashboard
2. Copy: `tvly-...`
3. Free: 1,000 searches/month
### Google Gemini β€” Fallback LLM (optional)
Only needed if no Groq key:
1. [aistudio.google.com](https://aistudio.google.com) β†’ Get API Key
2. Copy: `AIzaSy...`
### LangSmith β€” Tracing (optional but recommended)
See every node execution, LLM call, and retry as a visual timeline:
1. [smith.langchain.com](https://smith.langchain.com) β†’ Settings β†’ API Keys β†’ Create
2. Copy: `lsv2_...`
---
## βš™οΈ Installation & Setup
**Prerequisites:** Python 3.11+, Git
```bash
# 1. Clone
git clone https://github.com/vishal815/ResearchPilot-AI.git
cd ResearchPilot-AI
# 2. Virtual environment
python -m venv .venv
# 3. Activate
# Windows:
.venv\Scripts\activate
# Mac/Linux:
source .venv/bin/activate
# 4. Install dependencies
pip install -r requirements.txt
# 5. Set up API keys
cp .env.example .env
# Now open .env and fill in your keys
```
Your `.env` file:
```env
GROQ_API_KEY=gsk_your_key_here
TAVILY_API_KEY=tvly_your_key_here
# GOOGLE_API_KEY=AIzaSy_your_key_here (optional fallback)
# LANGCHAIN_API_KEY=lsv2_your_key_here (optional tracing)
# LANGCHAIN_TRACING_V2=true
# LANGCHAIN_PROJECT=researchpilot-ai
```
---
## ▢️ Running the Project
### Terminal mode (test the pipeline first)
```bash
python main.py
```
Output:
```
============================================================
ResearchPilot AI
Query: Impact of AI on healthcare market growth...
============================================================
[NODE: PLANNER] Domain detected: healthcare | 3 tasks created
[NODE: ROUTER] Activated: ['research', 'statistics', 'domain_expert', 'fact_checker', 'citation']
[NODE: WORKERS] Research done | Statistics: 8 metrics, 3 trends | Expert done | FactCheck done | Refs: 8 sources
[NODE: VISUALIZATION] 6 charts generated
[NODE: WRITER] Report generated
[NODE: QUALITY_GATE] Score: 7.5/10
[NODE: COVER] SVG cover card generated
============================================================
Total time: 52.3s | Saved to output_report_v2.md
```
### Streamlit Web UI
```bash
streamlit run ui/app.py
```
Opens at `http://localhost:8501`
---
## 🐳 Deploy to Hugging Face Spaces
The project ships with a ready `Dockerfile` that targets port 7860 (Hugging Face's required port).
### Step 1 β€” Push to GitHub
```bash
git add .
git commit -m "Initial ResearchPilot AI upload"
git push origin main
```
### Step 2 β€” Create a Hugging Face Space
1. Go to [huggingface.co/spaces](https://huggingface.co/spaces)
2. Click **Create new Space**
3. Set:
- **Space name:** `ResearchPilot-AI`
- **License:** MIT
- **SDK:** **Docker** ← important, not Streamlit
- **Visibility:** Public
### Step 3 β€” Add API Keys as Secrets
> ⚠️ Never put real API keys in code or `Dockerfile`. Use HF Secrets β€” they're injected as environment variables at runtime, invisible in the repo.
Go to your Space β†’ **Settings** β†’ **Repository secrets** β†’ **New secret**:
| Secret Name | Value | Required? |
|---|---|---|
| `GROQ_API_KEY` | Your Groq key (`gsk_...`) | βœ… Required |
| `TAVILY_API_KEY` | Your Tavily key (`tvly_...`) | βœ… Required |
| `LANGCHAIN_API_KEY` | Your LangSmith key (`lsv2_...`) | Optional |
| `LANGCHAIN_TRACING_V2` | `true` | Optional (with LangSmith) |
| `GOOGLE_API_KEY` | Your Gemini key | Optional fallback |
**Why secrets, not `.env`?** HF Spaces clones your repo publicly β€” your `.env` must never be committed (it's in `.gitignore`). Secrets are stored encrypted in HF's vault and injected at container start time.
Your `Dockerfile` already sets:
```dockerfile
ENV LANGCHAIN_PROJECT="researchpilot-ai"
```
This constant is safe to hardcode because it's not sensitive β€” it's just the project name in LangSmith's dashboard.
The `LANGCHAIN_TRACING_V2=true` env var activates LangSmith auto-tracing β€” set it as a secret alongside your `LANGCHAIN_API_KEY`. Once both are set, every run appears in your [LangSmith dashboard](https://smith.langchain.com) showing exactly which node ran, how long each LLM call took, and the full prompt/response for every agent call.
### Step 4 β€” Link GitHub Repo
In your Space β†’ **Files** β†’ **Connect to GitHub repo** β†’ select your repo β†’ HF auto-builds on every push.
Or push directly to the HF Space's git remote:
```bash
git remote add hf https://huggingface.co/spaces/YOUR_HF_USERNAME/ResearchPilot-AI
git push hf main
```
### Step 5 β€” Wait for Build
HF Spaces shows a build log. The first build takes ~3-5 minutes (downloads dependencies). After that, code-only pushes rebuild in ~60 seconds.
---
## πŸ“š Concepts Covered
| Concept | Where in code | One-line description |
|---|---|---|
| **Agentic AI** | All nodes | Agents decide and act, not just reply |
| **LangGraph StateGraph** | `graph_builder.py` | Stateful multi-node orchestration with cycles |
| **Conditional Edge / Routing** | `graph_builder.py` + `quality_gate.py` | `should_retry()` returns string β†’ LangGraph picks next node |
| **Shared State (TypedDict)** | `state.py` | One dict flows through every node β€” how agents "talk" |
| **Tool Use** | `search_tool.py` | Agents calling Tavily external API |
| **Virtual File System** | `file_system.py` | Dict-as-filesystem for zero-I/O context sharing |
| **Persona Priming** | `workers.py` | Named, credentialed identity β†’ sharper domain output |
| **Structured Output Forcing** | `workers.py` | Force LLM to return exact JSON schema for deterministic chart rendering |
| **LLM-as-Judge** | `quality_gate.py` | Separate LLM call evaluates the first LLM's output |
| **Self-Correction Loop** | `quality_gate.py` | Cycle in graph capped by `retry_count` |
| **RAG** | `workers.py` | Search first β†’ synthesise over retrieved context |
| **Flowable PDF** | `pdf_generator.py` | ReportLab auto-layout vs. manual x/y coordinate mess |
| **Streamlit Session State** | `ui/app.py` | Cache results across reruns so downloads don't re-trigger agents |
---
## πŸ”§ Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| `ModuleNotFoundError` | venv not activated | `.venv\Scripts\activate` then `pip install -r requirements.txt` |
| `ImportError: cannot import name 'web_search'` | Old `search_tool.py` | Confirm file has `def web_search(query, max_results=5):` |
| Charts missing / only 1 chart | rgba color bug (old version) | Make sure you have the latest `visualization.py` |
| Cover shows `Score: 0.0` | Old graph wiring (cover before quality_gate) | Make sure you have the latest `graph_builder.py` |
| PDF has two References sections | LLM writes its own + structured list | Make sure you have latest `pdf_generator.py` with `_strip_references_section()` |
| `kaleido` error in PDF | Wrong kaleido version | `pip install kaleido==0.2.1` (pin to 0.2.1 exactly) |
| Page "resets" on download | Old `app.py` without session_state cache | Make sure you have latest `ui/app.py` |
| `429` rate limit | Hit LLM free tier | Wait 60s and retry, or switch to Gemini fallback |
---
## πŸ›£οΈ Roadmap
- [ ] AI-generated cover image via Pollinations AI (free, no key needed)
- [ ] LangGraph checkpointing for session memory across multiple queries
- [ ] Upload a PDF/document as additional research context
- [ ] Model selector in UI (Groq / Gemini / OpenRouter)
- [ ] Auto-generate PowerPoint slide deck from the report
- [ ] LangSmith evaluation dashboard integration
---
## πŸ“œ License
MIT License β€” free to use, modify, and distribute with attribution.
---
## πŸ™ Acknowledgements
[LangGraph](https://langchain-ai.github.io/langgraph/) Β· [Groq](https://groq.com) Β· [Google Gemini](https://aistudio.google.com) Β· [Tavily](https://tavily.com) Β· [Plotly](https://plotly.com) Β· [Streamlit](https://streamlit.io) Β· [ReportLab](https://www.reportlab.com) Β· [LangSmith](https://smith.langchain.com)
---
## πŸ‘¨β€πŸ’» Connect With Me
<div align="center">
[🌐 Portfolio](https://vishal-lazrus-portfolio.vercel.app/) &nbsp;β€’&nbsp;
[πŸ’Ό LinkedIn](https://www.linkedin.com/in/vishal-lazrus/) &nbsp;β€’&nbsp;
[πŸ™ GitHub](https://github.com/vishal815)
**If this helped you learn something, give it a ⭐ on GitHub!**
*Built by Vishal Lazrus during AI Internship at Infosys, June 2026*
</div>