Spaces:
Sleeping
Sleeping
File size: 8,404 Bytes
3295172 204691d 3295172 897d4ed 3295172 897d4ed 3295172 897d4ed 3295172 897d4ed 3295172 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | ---
title: AutoStream AI Sales Agent
emoji: ⬛
colorFrom: gray
colorTo: red
sdk: docker
app_file: app.py
pinned: false
---
# AutoStream AI Sales Agent
A **LangGraph**-powered conversational AI agent that acts as an intelligent sales assistant for **AutoStream** — an automated video editing SaaS for content creators.
Built for the ServiceHive / Inflx ML Intern assignment: _Social-to-Lead Agentic Workflow_.
---
## Features
| Capability | Implementation |
|---|---|
| Intent detection | LLM classifier — 4 labels: `greeting`, `inquiry`, `high_intent`, `collecting` |
| RAG knowledge retrieval | BM25 search over structured JSON knowledge base |
| Lead qualification | Progressive field collection (name → email → platform) |
| Tool execution guard | `mock_lead_capture` fires **only** after all 3 fields collected |
| State persistence | Full conversation history via LangGraph `AgentState` across turns |
| Multi-LLM support | Groq llama-3.3-70b (default) · Claude 3 Haiku · GPT-4o-mini · Gemini 2.0 Flash |
---
## Quick Start
### 1. Clone & install
```bash
git clone <repo-url> autostream-agent
cd autostream-agent
pip install -r requirements.txt
```
### 2. Configure API key
```bash
cp .env.example .env
# Edit .env — add ONE of:
# GROQ_API_KEY=gsk_... ← llama-3.3-70b-versatile (default, free + fast)
# ANTHROPIC_API_KEY=sk-ant-... ← Claude 3 Haiku
# OPENAI_API_KEY=sk-... ← GPT-4o-mini
# GOOGLE_API_KEY=... ← Gemini 2.0 Flash
```
### 3. Run
```bash
# Interactive chat
python main.py
# Scripted demo (for recording the demo video)
python demo.py
# Debug mode — shows intent label + lead state after every turn
DEBUG=1 python main.py
```
---
## Example Conversation
```
You: Hi, tell me about your pricing.
Agent: AutoStream has two plans:
• Basic ($29/mo) — 10 videos/month, 720p, email support
• Pro ($79/mo) — Unlimited videos, 4K, AI captions, 24/7 support
You: I want to sign up for Pro for my YouTube channel.
Agent: That's fantastic! Let's get you set up. What's your full name?
You: Alex Johnson
Agent: Great to meet you, Alex! What's your email address?
You: alex@example.com
Agent: Almost there! Which creator platform are you primarily on?
You: YouTube
Lead captured successfully: Alex Johnson, alex@example.com, YouTube
Agent: You're all set, Alex! Our team will reach out to alex@example.com shortly.
Start your free trial at autostream.io/signup
```
---
## Architecture
### Why LangGraph?
LangGraph was chosen over AutoGen because this workflow requires a **deterministic state machine** with clearly defined transitions. The lead qualification pipeline has discrete stages — greeting, inquiry, high-intent detection, field collection, and capture — that map directly onto LangGraph's node/edge model. LangGraph makes conditional routing explicit (no ambiguous agent-to-agent negotiation) and provides typed state that is immutable between graph invocations, preventing hidden side effects.
### How state is managed
State is a typed Python dict (`AgentState`) with these fields: conversation `messages`, classified `intent`, `collecting_lead` flag, individual lead fields (`lead_name`, `lead_email`, `lead_platform`), a `lead_captured` boolean, and `rag_context` for the current turn's retrieval result.
The `messages` field uses LangGraph's `add_messages` reducer — new messages are **appended** on each node invocation rather than replacing the list, preserving full conversation history across all turns. All other fields are plain values updated by returning a partial dict from each node. Between CLI turns, the full state dict is kept in memory and re-passed to `app.invoke()`.
### Graph topology
```
User message
│
▼
classify_intent ──► (greeting / high_intent / unknown)
│ │
│ inquiry │
▼ │
retrieve_rag │
│ │
└──────────┬─────────────┘
▼
generate_response ──► END
▲
collecting │
▼ │
extract_lead_fields
│ incomplete
│──────────────► generate_response ──► END
│ complete
▼
capture_lead ──► generate_response ──► END
```
### RAG pipeline
The knowledge base (`knowledge_base/autostream_kb.json`) contains company info, plan details, policies, and FAQs. On startup, `KnowledgeBaseRetriever` chunks each entry into a document and builds a **BM25Okapi** index (`rank-bm25`). On each inquiry turn, the top-3 highest-scoring chunks are injected into the LLM system prompt as grounded context. BM25 was chosen over vector embeddings to avoid heavy dependencies (no 500 MB model download) while still providing relevance-ranked retrieval suitable for this knowledge base size.
---
## WhatsApp Webhook Integration
To deploy this agent on WhatsApp Business:
### 1. Set up WhatsApp Business API
Register a Meta for Developers account, create a WhatsApp Business App, and obtain a `PHONE_NUMBER_ID` and `WHATSAPP_TOKEN`.
### 2. Build a webhook server (FastAPI example)
```python
from fastapi import FastAPI, Request
import httpx, redis, json
from agent.graph import get_app
from agent.state import AgentState
from langchain_core.messages import HumanMessage
app_server = FastAPI()
redis_client = redis.Redis()
agent = get_app()
@app_server.get("/webhook")
async def verify(hub_mode: str, hub_verify_token: str, hub_challenge: str):
if hub_verify_token == "YOUR_VERIFY_TOKEN":
return int(hub_challenge)
@app_server.post("/webhook")
async def receive_message(request: Request):
body = await request.json()
msg_obj = body["entry"][0]["changes"][0]["value"]["messages"][0]
phone = msg_obj["from"]
text = msg_obj["text"]["body"]
# Load or initialise session state from Redis
raw = redis_client.get(f"session:{phone}")
state: AgentState = json.loads(raw) if raw else _initial_state()
# Run agent
state = agent.invoke({
**state,
"messages": state["messages"] + [HumanMessage(content=text)],
})
# Persist updated state
redis_client.setex(f"session:{phone}", 86400, json.dumps(state, default=str))
# Send reply via WhatsApp Cloud API
reply = next(m.content for m in reversed(state["messages"]) if hasattr(m, "content"))
async with httpx.AsyncClient() as client:
await client.post(
f"https://graph.facebook.com/v18.0/{PHONE_NUMBER_ID}/messages",
headers={"Authorization": f"Bearer {WHATSAPP_TOKEN}"},
json={"messaging_product": "whatsapp", "to": phone,
"text": {"body": reply}},
)
return {"status": "ok"}
```
### 3. Expose & register
Deploy the server (e.g. Railway, Fly.io) and register the public URL in the Meta Developer Console as your webhook endpoint.
---
## Project Structure
```
autostream-agent/
├── knowledge_base/
│ └── autostream_kb.json # Pricing, policies, FAQs
├── rag/
│ ├── __init__.py
│ └── retriever.py # BM25 retriever
├── agent/
│ ├── __init__.py
│ ├── state.py # AgentState TypedDict
│ ├── llm.py # Multi-provider LLM factory
│ ├── tools.py # mock_lead_capture
│ ├── nodes.py # Graph node functions
│ └── graph.py # LangGraph assembly + compile
├── main.py # Interactive CLI
├── demo.py # Scripted demo for video recording
├── requirements.txt
├── .env.example
└── README.md
```
---
## Evaluation Mapping
| Criterion | Where |
|---|---|
| Agent reasoning & intent detection | `agent/nodes.py` → `classify_intent` |
| Correct use of RAG | `rag/retriever.py` + `agent/nodes.py` → `retrieve_rag` |
| Clean state management | `agent/state.py` + LangGraph `add_messages` |
| Proper tool calling logic | `agent/nodes.py` → `capture_lead` + `_route_after_extract` guard |
| Code clarity & structure | Modular single-responsibility files |
| Real-world deployability | WhatsApp webhook section above |
|