A production-grade, full-stack AI research assistant inspired by ChatGPT and Gemini. Powered by FastAPI, LangGraph, Google Gemini 2.5 Flash, Tavily Search, React 19, TypeScript, and Tailwind CSS.
- Agentic Workflow with LangGraph: Parallel fan-out and fan-in execution for independent search and document extraction tasks.
- Deconstructive Planner Node: Breaks down complex user inquiries into targeted parallel queries with Pydantic structured validation.
- Parallel Research Pipeline:
- Live Web Research: Concurrent multi-query search via Tavily.
- Multi-Format Document Extraction: Extensible document parser supporting PDF, DOCX, Markdown, and TXT with chunking and semantic keyword retrieval.
- Evidence Aggregator: Eliminates duplicate findings, preserves strict source attribution, and distinguishes web URLs from document citations.
- Grounded Writer Node: Synthesizes structured, rigorous Markdown reports adhering to academic/analytical standards without hallucinating facts.
- Real-Time Streaming Progress: Server-Sent Events (SSE) streaming live stage transitions, task decompositions, evidence counts, and generated reports.
- Modern Chatbot Interface: Sleek dark-mode UI with collapsible sidebar, session history, file attachment chips, interactive multi-stage timeline, and verified sources drawer.
- 100% Comprehensive Test Suite: Pytest unit and integration tests covering all nodes, failure containment, and partial research fallbacks.
- Full Docker Support: Multi-stage Dockerfiles and Docker Compose configuration.
+---------------------------------------+
| User Interface |
| (React 19, TypeScript, Tailwind) |
+-------------------+-------------------+
|
SSE /api/research/stream | POST /api/files/upload
v
+---------------------------------------------------------------------------------------------------+
| FastAPI Backend |
| |
| +-------------------+ |
| | Planner Node | |
| | (Gemini 2.5 Flash)| |
| +---------+---------+ |
| | |
| +-------------------+-------------------+ |
| | | |
| v (Parallel) v (Parallel) |
| +---------------------+ +---------------------+ |
| | Web Search Node | | File Search Node | |
| | (Tavily Service) | | (Registry & Loaders)| |
| +----------+----------+ +----------+----------+ |
| | | |
| +-------------------+-------------------+ |
| | |
| v |
| +---------------------------+ |
| | Evidence Aggregator Node | |
| | (Deduplication & Mapping) | |
| +-------------+-------------+ |
| | |
| v |
| +---------------------------+ |
| | Writer Node | |
| | (Structured Markdown Doc) | |
| +---------------------------+ |
+---------------------------------------------------------------------------------------------------+
llm-report-writer/
├── backend/
│ ├── app/
│ │ ├── api/
│ │ │ ├── routes/
│ │ │ │ ├── chat.py # Research sync & SSE stream endpoints
│ │ │ │ └── files.py # Document upload & delete endpoints
│ │ │ └── __init__.py
│ │ ├── core/
│ │ │ ├── config.py # Pydantic BaseSettings & environment
│ │ │ └── logging.py # Structured logger
│ │ ├── graph/
│ │ │ ├── state.py # ResearchState TypedDict with reducers
│ │ │ └── research_graph.py # LangGraph compilation & parallel routing
│ │ ├── loaders/
│ │ │ ├── base.py # BaseFileLoader interface & DocumentChunk
│ │ │ ├── pdf_loader.py # PyPDF text extractor
│ │ │ ├── docx_loader.py # Python-docx parser
│ │ │ ├── markdown_loader.py # Structured markdown loader
│ │ │ ├── text_loader.py # Plaintext loader & chunking utility
│ │ │ └── registry.py # Extensible LoaderRegistry
│ │ ├── nodes/
│ │ │ ├── planner.py # Objective & task decomposition
│ │ │ ├── web_search.py # Concurrent Tavily searches
│ │ │ ├── file_search.py # Multi-document retrieval
│ │ │ ├── evidence_aggregator.py# Merging & deduplication
│ │ │ └── writer.py # Final analytical Markdown report
│ │ ├── schemas/
│ │ │ ├── plan.py # ResearchTask & ResearchPlan
│ │ │ ├── evidence.py # Evidence & AggregatedEvidence
│ │ │ └── report.py # Request, response, and SSE payloads
│ │ ├── services/
│ │ │ ├── llm_service.py # Gemini 2.5 Flash abstraction
│ │ │ ├── tavily_service.py # Tavily search abstraction
│ │ │ └── file_service.py # File chunk indexing & retrieval
│ │ ├── __init__.py
│ │ └── main.py # FastAPI app entrypoint & lifespan
│ ├── requirements.txt
│ └── uploads/ # Uploaded documents storage
│
├── frontend/
│ ├── src/
│ │ ├── components/
│ │ │ ├── chat/
│ │ │ │ ├── ChatContainer.tsx
│ │ │ │ ├── ChatInput.tsx
│ │ │ │ ├── ChatMessage.tsx
│ │ │ │ └── MarkdownMessage.tsx
│ │ │ ├── research/
│ │ │ │ ├── EvidenceDrawer.tsx
│ │ │ │ ├── FileUploader.tsx
│ │ │ │ ├── ReportActions.tsx
│ │ │ │ └── ResearchProgress.tsx
│ │ │ └── sidebar/
│ │ │ └── Sidebar.tsx
│ │ ├── hooks/
│ │ │ ├── useChat.ts
│ │ │ └── useResearch.ts
│ │ ├── services/
│ │ │ └── api.ts
│ │ ├── types/
│ │ │ └── research.ts
│ │ ├── App.tsx
│ │ ├── index.css
│ │ └── main.tsx
│ ├── package.json
│ └── vite.config.ts
│
├── tests/
│ ├── fixtures/
│ │ ├── sample.txt
│ │ ├── sample.md
│ │ ├── sample.pdf
│ │ └── sample.docx
│ ├── unit/
│ │ ├── test_loaders.py
│ │ ├── test_planner.py
│ │ ├── test_web_search.py
│ │ ├── test_file_search.py
│ │ ├── test_evidence_aggregator.py
│ │ └── test_writer.py
│ └── integration/
│ └── test_research_graph.py
│
├── docker/
│ ├── backend.Dockerfile
│ └── frontend.Dockerfile
├── docker-compose.yml
├── .env.example
└── README.md
Copy .env.example to .env in the root directory:
cp .env.example .envConfigure your API keys:
GOOGLE_API_KEY=your_google_api_key
TAVILY_API_KEY=your_tavily_api_key
GEMINI_MODEL=gemini-2.5-flash(Note: The system includes complete fallback/mocking resilience so test suites and local testing run seamlessly even without live API keys).
Start the entire full-stack application with a single command:
docker compose up --build- Frontend App: http://localhost:3000
- FastAPI Documentation: http://localhost:8000/api/docs
- Health Check: http://localhost:8000/api/health
# 1. Install dependencies
pip install -r backend/requirements.txt
# 2. Run FastAPI server
cd backend
python -m uvicorn app.main:app --host 0.0.0.0 --port 8000 --reloadcd frontend
npm install
npm run devVisit http://localhost:5173 to interact with the assistant.
Run the complete test suite:
pytest -vTests verify:
- Individual file loaders (
.txt,.md,.docx,.pdf) and the registry. planner_nodewith structured outputs and fallback generation.web_search_nodeconcurrency, Tavily API calls, and partial failure isolation.file_search_nodekeyword/semantic retrieval and corrupt file handling.evidence_aggregator_nodecontent deduplication and source separation.writer_nodemarkdown report structure, citations, and uncertainty flagging.- End-to-end integration workflows: Web-only, File-only, Combined, and Failure resilience scenarios.
POST /api/research
{
"query": "Analyze multimodal medical AI advances",
"files": [
{
"id": "abc-123",
"filename": "clinical_notes.pdf",
"file_type": ".pdf",
"file_path": "/tmp/research_assistant/uploads/abc-123_clinical_notes.pdf"
}
]
}POST /api/research/stream
Emits real-time event stream:
event: progress(planning,planning_complete,researching,web_search_done,file_search_done,aggregating,writing)event: complete(Final Markdown report and verified sources)
POST /api/files/upload (Multipart form-data with files)
GET /api/health