A Perplexity-style AI chat application featuring real-time streaming responses, RAG-powered document retrieval, interactive PDF viewer with citations, and generative UI components.
- π€ Streaming AI Responses - Real-time token-by-token streaming with GPT-4o-mini
- π RAG (Retrieval-Augmented Generation) - Context-aware responses from PDF documents
- π Interactive Citations - Clickable
[1, p.2]citations that open PDF viewer - π PDF Viewer - Smooth slide-in viewer with page navigation and search
- π¨ Generative UI - Dynamic components (FinancialCard) streamed with responses
- π Tool Call Indicators - Visual feedback (π Searching... π Reading...)
- β Dark Mode - Manual theme toggle
- β Responsive Design - Mobile-first, adaptive layouts
- β PDF Text Search - Highlight search terms in documents
- β Smooth Animations - Framer Motion for all transitions
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β β β β β β
β Next.js 14 βββββββββββ€ FastAPI βββββββββββ€ OpenAI β
β Frontend β SSE β Backend β API β GPT-4o-mini β
β β β β β β
β - Chat UI β β - LangChain β βββββββββββββββββββ
β - PDF Viewer β β - PDF Extract β
β - State (Zustand)β β - Queue Mgmt β
β β β β
βββββββββββββββββββ βββββββββββββββββββ
β
βΌ
βββββββββββββββββββ
β PyPDF2 β
β PDF Files β
βββββββββββββββββββ
// Backend sends:
data: {"type": "tool", "content": "π Searching documents..."}
data: {"type": "token", "content": "RAG combines"}
data: {"type": "ui", "component": "FinancialCard", "data": {...}}
data: [DONE]
// Frontend handles:
- Tool calls β Display indicators
- Tokens β Append to message
- UI β Render components- Node.js 18+
- Python 3.11+
- OpenAI API Key
cd backend
# Create virtual environment
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Create .env file
echo "OPENAI_API_KEY=your-api-key-here" > .env
# Run server
python -m uvicorn main:app --reload
# Server runs on http://localhost:8000cd frontend
# Install dependencies
npm install
# Run development server
npm run dev
# App runs on http://localhost:3000Open http://localhost:3000 in your browser.
calQuity_1/
βββ backend/
β βββ agent.py # LangGraph agent & streaming logic
β βββ main.py # FastAPI app & SSE endpoint
β βββ queue_manager.py # Asyncio semaphore queue
β βββ api/
β β βββ pdf.py # PDF extraction & serving
β βββ assets/
β β βββ sample.pdf # Demo 3-page PDF
β βββ requirements.txt
βββ frontend/
β βββ app/
β β βββ page.tsx # Main chat page
β β βββ layout.tsx # Root layout
β β βββ globals.css # Tailwind + theme
β βββ components/
β β βββ chat/
β β β βββ ChatLayout.tsx # Main chat container
β β β βββ MessageList.tsx # Message rendering
β β β βββ ChatInput.tsx # Input field
β β βββ pdf/
β β β βββ PDFViewer.tsx # PDF viewer modal
β β βββ gen-ui/
β β βββ FinancialCard.tsx # Generative UI component
β βββ store/
β β βββ chatStore.ts # Zustand state management
β βββ next.config.ts # API proxy config
β βββ package.json
βββ README.md
| Library | Version | Purpose |
|---|---|---|
| Next.js | 14.2.24 | React framework with App Router |
| TypeScript | 5.x | Type safety |
| Tailwind CSS | 4.0.0 | Utility-first styling |
| Framer Motion | 11.x | Smooth animations |
| Zustand | 5.x | Lightweight state management |
| Lucide React | - | Icon library |
| uuid | - | Message ID generation |
| Library | Version | Purpose |
|---|---|---|
| FastAPI | 0.115.6 | High-performance API framework |
| LangChain | Latest | LLM orchestration |
| LangChain-OpenAI | Latest | OpenAI integration |
| OpenAI | Latest | GPT-4o-mini API client |
| PyPDF2 | Latest | PDF text extraction |
| ReportLab | Latest | PDF generation |
| Python-dotenv | Latest | Environment variables |
Choice: In-memory asyncio.Semaphore (3 concurrent requests)
Rationale:
- β Simple, no external dependencies (Redis/Celery)
- β Perfect for demo/MVP
- β Fast response times
- β Not suitable for production scale (no persistence)
Alternative: Redis Queue for production deployments
Choice: Extract full PDF text, inject first 4000 chars into prompt
Rationale:
- β Simple, fast for small documents
- β No vector DB setup required
- β Works well for demo (3-page PDF)
- β Doesn't scale to large documents
Alternative: Vector embeddings (FAISS/Chroma) for production
Choice: Zustand over Redux/Context API
Rationale:
- β Minimal boilerplate
- β
Simple API (
useChatStore) - β Perfect for this app size
- β TypeScript support
Choice: <iframe> with browser PDF viewer
Rationale:
- β Zero dependencies
- β Built-in search/navigation
- β
#page=Xand#search=termsupport - β Limited customization
Alternative: react-pdf for more control
Choice: model.astream() instead of LangGraph events
Rationale:
- β Simpler implementation
- β Direct token streaming
- β Fewer edge cases
- β Less visibility into intermediate steps
Trade-off: Simplified architecture over detailed observability
- PDF Viewer: Spring-physics slide-in (300-400ms)
- Messages: Fade + slide up on entrance
- Tool Indicators: Pulsing dots
- Streaming Cursor: Blue pulse effect
- Dark Mode: Smooth color transitions
- Mobile (
< 640px): Full-screen PDF, larger touch targets - Desktop (
β₯ 768px): 55/45 chat/PDF split, condensed UI
Create .env in backend/ directory:
OPENAI_API_KEY=sk-proj-...your-key-here- Single Document: Currently supports one PDF at a time
- No Vector Search: Simple text extraction, not semantic search
- In-Memory Queue: Not persistent across restarts
- Citation Format: Relies on LLM following format instructions
Both servers must run simultaneously:
# Terminal 1 - Backend
cd backend && python -m uvicorn main:app --reload
# Terminal 2 - Frontend
cd frontend && npm run dev- Add Docker/docker-compose
- Implement Redis queue
- Add vector embeddings
- Enable multi-document support
- Add rate limiting
- Implement user authentication
MIT
- Perplexity for UI inspiration
- LangChain for RAG framework
- Vercel AI SDK for streaming patterns