A production-grade AI agent that evaluates startup pitches using a custom ReAct (Reasoning + Acting) loop β no LangChain, no frameworks. Built from scratch with real-time WebSocket streaming, multi-provider LLM support, and live web research via Tavily.
v2 is a complete rebuild. v1 used LangChain + Streamlit + OpenAI. v2 replaces everything with a custom agent, FastAPI backend, and Next.js frontend with glassmorphism UI.
| Feature | Generic AI Chatbots | PitchPal v2 |
|---|---|---|
| Agent Architecture | LangChain wrappers | Custom ReAct loop built from scratch |
| Research | No web access | Live Tavily search with domain filtering |
| Scoring | Inconsistent text output | Structured JSON with 5-7 scored dimensions |
| Caching | None | Semantic (embedding-based) + evaluation (hash-based) |
| Streaming | Wait for full response | Real-time WebSocket step-by-step streaming |
| Deck Analysis | Text only | PDF/PPTX upload with Gemini Vision OCR |
| Reliability | Raw LLM output | 5-strategy JSON repair + retry with fallback |
+-----------------------+
| Next.js Frontend |
| (Glassmorphism UI) |
+----------+------------+
|
WebSocket / REST
|
+----------v------------+
| FastAPI Backend |
| |
| +-- Security Layer --+-----> Input Sanitization
| | Rate Limiter |-----> IP-based (3/5 per 24h)
| | Prompt Injection |-----> 16+ pattern detection
| +--------------------+
| |
| +-- Cache Layer -----+-----> Evaluation Cache (SHA-256)
| | |-----> Semantic Cache (embeddings)
| +--------------------+
| |
| +-- ReAct Agent -----+-----> 12-step budget
| | (Custom Loop) |-----> Role-specific prompts
| | |-----> 5-strategy JSON repair
| +--------+-----------+
| | |
+-----------+-----------+
|
+-----------------+------------------+
| | |
+-------v------+ +-------v------+ +-------v-------+
| Gemini / Groq| | Tavily Search| | Gemini Vision |
| LLM Provider | | (4 tools) | | (PDF OCR) |
+--------------+ +--------------+ +---------------+
- Hand-built ReAct loop with Thought β Action β Observation cycling
- 12-step budget to prevent infinite loops and control costs
- Role-specific evaluation: Startup founder (5 dimensions) vs Investor (7 dimensions)
- 5-strategy JSON repair pipeline: regex extraction, bracket fixing, truncation repair, trailing comma fix, markdown fence stripping
- Retry with exponential backoff + provider fallback on failure
- 4 providers supported: Gemini, Groq, OpenAI, Anthropic
- Single config switch via
LLM_PROVIDERenv var - Automatic fallback if primary provider fails
- 4 specialized search tools with domain filtering:
search_market_dataβ market size, growth rates, industry reportssearch_competitor_infoβ competitor analysis, market positioningsearch_industry_trendsβ emerging trends, technology shiftssearch_financial_benchmarksβ funding rounds, revenue benchmarks
- Semantic caching of search results to avoid duplicate API calls
- Evaluation cache: SHA-256 hash of (pitch + role) β deterministic scores for identical pitches
- Semantic cache: Gemini
text-embedding-001embeddings (768-dim) with cosine similarity at 0.72 threshold - Similarity detection: Warns when a pitch is similar to a previously evaluated one (0.87 threshold)
- 24-hour TTL with disk persistence (survives server restarts)
- PyMuPDF for text extraction + slide rendering
- Gemini Vision OCR fallback for image-based PDFs (no text layer)
- python-pptx for PowerPoint file support
- Deck quality analysis: design, narrative, data visualization scores (0-10)
- Automatic startup name detection from slide content
- 20MB file size limit with early validation
- HTML/script stripping β prevents XSS via pitch text
- Prompt injection detection β 16+ regex patterns catch jailbreak attempts
- Unicode NFKD normalization β prevents bypass with look-alike characters (Greek omicron, zero-width joiners)
- Length enforcement β min 50, max 5,000 characters
- CORS hardening β explicit methods and headers, no wildcards
- Sanitized error messages β no internal details leaked to clients
- IP-based with role-specific limits: 3 evaluations/24h (startup), 5/24h (investor)
- Cache hits bypass rate limits β zero API cost, no reason to limit
- Thread-safe with
threading.Lock - Auto-reset on window expiry
- Step-by-step agent streaming β see each Thought, Action, and Observation live
- Rate limit status included in start message
- Similar pitch warnings streamed before evaluation begins
- Graceful error handling with WebSocket close
- Cryptographic share IDs using
secrets.token_urlsafe(24) - 7-day TTL with automatic expiry
- View counter tracking
- FIFO eviction at 1,000 entries
- Access code authentication with 6-hour session tokens
- 7-dimension analysis: Market Opportunity, Revenue & Unit Economics, Scalability, Competitive Moat, Team & Execution, Risk Assessment, Exit Potential
- vs. Startup mode (5 dimensions): Problem Clarity, Market Opportunity, Business Model, Competitive Advantage, Team Strength
- Glassmorphism UI with backdrop blur, translucent surfaces, floating orbs
- Dark/Light theme with OS preference detection and localStorage persistence
- Framer Motion animations β staggered fade-ins, card hover effects, modal transitions
- Recharts data visualization β radar charts, bar charts for dimension scores
- PDF export via html2canvas-pro + jsPDF
- Evaluation history stored in localStorage
- Pitch comparison β side-by-side analysis of multiple evaluations
- Responsive design β mobile, tablet, desktop breakpoints
- Structured NDJSON logging with event types, timestamps, and context
- In-memory metrics: latency percentiles (p50/p95/p99), cache hit rate, error rate
- Live
/metricsand/statsendpoints for monitoring
| Layer | Technology | Purpose |
|---|---|---|
| Frontend | Next.js 16, React 19, TypeScript 5 | App Router, SSR, type safety |
| Styling | Tailwind CSS v4, Framer Motion | Glassmorphism UI, animations |
| Charts | Recharts | Radar + bar chart visualizations |
| Export | html2canvas-pro, jsPDF | PDF report generation |
| Backend | FastAPI, Uvicorn | REST API + WebSocket server |
| LLM | Gemini, Groq, OpenAI, Anthropic | Multi-provider abstraction |
| Search | Tavily | Live web research with domain filtering |
| PyMuPDF, python-pptx | Deck parsing + slide rendering | |
| Vision | Gemini Vision | OCR for image-based PDFs |
| Embeddings | Gemini text-embedding-001 | Semantic cache (768-dim, cosine similarity) |
| Testing | pytest, httpx | 87 tests across 7 test files |
| Deployment | Docker, Vercel, Render | Containerized + cloud deploy |
| Method | Endpoint | Description |
|---|---|---|
GET |
/ |
Health check |
GET |
/health |
Health check (alias) |
GET |
/sample-pitches |
3 sample startup pitches |
GET |
/stats |
Server stats, cache stats, rate limiter stats |
GET |
/metrics |
Live latency percentiles, error rate, cache hit rate |
GET |
/rate-limit/status |
Current rate limit for requesting IP |
POST |
/evaluate |
Synchronous pitch evaluation (REST) |
POST |
/verify-code |
Investor access code β 6-hour session token |
POST |
/upload-deck |
PDF/PPTX upload β text extraction + deck quality |
POST |
/share |
Create shareable evaluation link (7-day TTL) |
GET |
/eval/{share_id} |
Retrieve shared evaluation |
DELETE |
/cache/clear |
Clear all caches |
DELETE |
/cache/entry |
Delete specific cache entry |
WebSocket |
/ws/evaluate |
Real-time ReAct agent streaming |
- Python 3.11+
- Node.js 20+
- Gemini API Key (free tier available)
- Tavily API Key (free tier: 1,000 searches/month)
cd backend
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txtCreate backend/.env:
GEMINI_API_KEY=your_gemini_key
TAVILY_API_KEY=your_tavily_key
INVESTOR_ACCESS_CODE=your_secret_code
LLM_PROVIDER=gemini
FRONTEND_URL=http://localhost:3000
ENV=developmentpython -m uvicorn app.main:app --reload --port 8000cd frontend
npm installCreate frontend/.env.local:
NEXT_PUBLIC_API_URL=http://localhost:8000npm run devcd backend
python -m pytest tests/ -v87 passed in 5.4s
docker compose up --buildThis starts both services:
- Backend:
http://localhost:8000 - Frontend:
http://localhost:3000
| Service | Platform | Cost |
|---|---|---|
| Frontend | Vercel | Free |
| Backend | Render | Free |
| Keep-alive | UptimeRobot | Free |
See deployment steps in the Deployment Plan section below.
- Push code to GitHub
- Render: Create Web Service β root dir
backendβ buildpip install -r requirements.txtβ startuvicorn app.main:app --host 0.0.0.0 --port 8000β add env vars - Vercel: Import repo β root dir
frontendβ addNEXT_PUBLIC_API_URLenv var pointing to Render URL - Render: Update
FRONTEND_URLenv var to Vercel URL (for CORS) - UptimeRobot: Monitor
https://your-app.onrender.com/healthevery 14 min (prevents cold starts)
PitchPal-v2/
βββ backend/
β βββ app/
β β βββ main.py # FastAPI app + REST + WebSocket endpoints
β β βββ config.py # Environment configuration
β β βββ security.py # Input sanitization + injection detection
β β βββ logger.py # Structured NDJSON logging
β β βββ metrics.py # In-memory performance metrics
β β βββ models/
β β β βββ schemas.py # Pydantic models (evaluation, deck, agent steps)
β β βββ agent/
β β βββ react_agent.py # Custom ReAct loop (no frameworks)
β β βββ llm.py # Multi-provider LLM abstraction
β β βββ tools.py # 4 Tavily search tools with domain filtering
β β βββ deck_analyzer.py # PDF/PPTX parsing + Gemini Vision OCR
β β βββ evaluation_cache.py # SHA-256 hash-based evaluation cache
β β βββ semantic_cache.py # Embedding-based similarity cache
β β βββ share_store.py # Shareable evaluation links (7-day TTL)
β β βββ rate_limiter.py # IP-based rate limiting
β βββ tests/
β β βββ test_api.py # 17 API integration tests
β β βββ test_security.py # 10 input sanitization tests
β β βββ test_rate_limiter.py # 7 rate limiter tests
β β βββ test_evaluation_cache.py# 8 cache tests
β β βββ test_share_store.py # 6 share store tests
β β βββ test_agent_quality.py # 39 agent quality benchmarks
β βββ requirements.txt
β βββ Dockerfile
βββ frontend/
β βββ src/
β β βββ app/
β β β βββ page.tsx # Landing page (role selection)
β β β βββ evaluate/page.tsx # Main evaluation interface
β β β βββ eval/[id]/page.tsx # Shared evaluation view
β β β βββ history/page.tsx # Evaluation history
β β β βββ compare/page.tsx # Side-by-side pitch comparison
β β β βββ why/page.tsx # Feature comparison page
β β βββ components/
β β β βββ AgentStream.tsx # Real-time agent step streaming
β β β βββ EvaluationResults.tsx# Structured scoring display
β β β βββ PitchForm.tsx # Pitch input form
β β β βββ DeckUpload.tsx # PDF/PPTX upload component
β β β βββ RadarChart.tsx # Dimension radar chart
β β β βββ ScoreBarChart.tsx # Score bar visualization
β β β βββ ShareButton.tsx # Share + PDF export
β β β βββ Header.tsx # Navigation + theme toggle
β β β βββ ThemeProvider.tsx # Dark/light theme context
β β βββ lib/
β β βββ api.ts # API client + WebSocket
β β βββ auth.ts # Role + token management
β β βββ storage.ts # LocalStorage for history
β β βββ pdfExport.ts # PDF export utilities
β βββ package.json
β βββ Dockerfile
βββ docker-compose.yml
βββ README.md
87 tests across 7 files, covering:
| Test File | Count | What It Tests |
|---|---|---|
test_api.py |
17 | Health, rate limits, auth, cache, shares, deck upload, stats |
test_security.py |
10 | HTML stripping, injection detection, Unicode normalization |
test_rate_limiter.py |
7 | Limits, window reset, IP isolation, thread safety |
test_evaluation_cache.py |
8 | Set/get, TTL, role separation, key normalization |
test_share_store.py |
6 | Create/get, view counter, expiry, FIFO eviction |
test_agent_quality.py |
39 | Schema validation, JSON repair, score consistency, benchmarks |
| Aspect | v1 | v2 |
|---|---|---|
| Agent | LangChain create_react_agent |
Custom ReAct loop from scratch |
| LLM | OpenAI GPT-4 only | Gemini |
| Frontend | Streamlit | Next.js 16 + React 19 + Tailwind |
| Backend | Streamlit server | FastAPI + WebSocket |
| Search | LangChain tools (no real web) | Tavily live search (4 specialized tools) |
| Caching | None | Semantic (embeddings) + evaluation (SHA-256) |
| Streaming | Streamlit spinner | Real-time WebSocket step streaming |
| File Upload | None | PDF/PPTX with Gemini Vision OCR |
| Security | None | Input sanitization, rate limiting, injection detection |
| Testing | None | 87 tests (pytest) |
| Deployment | Streamlit Cloud | Docker + Vercel + Render |
| Design | Default Streamlit | Glassmorphism with dark/light themes |
Jeet Patel
- GitHub: Jeet-51
MIT License - see LICENSE file for details.