Spaces:
Running
Running
Download routes/consultation.py from Success-dev/venthrive-api: direct link, hf CLI and curl.
- Browser
- Download file 6.72 kB
-
https://huggingface.co/spaces/Success-dev/venthrive-api/resolve/main/routes/consultation.py
- Command line
-
hf download hf://spaces/Success-dev/venthrive-api/routes/consultation.py
-
curl -L -o consultation.py https://huggingface.co/spaces/Success-dev/venthrive-api/resolve/main/routes/consultation.py
6.72 kB
| """ | |
| AI Consultation Session Routes | |
| ────────────────────────────────────────────────────────────────────────────── | |
| Manages proactive AI Consultation sessions distinct from passive AI Chat. | |
| AI Chat: passive — waits for user questions | |
| Consultation: proactive — AI opens with agenda, leads through structured phases | |
| (Discovery → Analysis → Prescription) and produces a written report | |
| Routes: | |
| POST /api/consultation/start → AI reads profile, generates opening message | |
| POST /api/consultation/report → AI generates structured report from session | |
| """ | |
| import json | |
| from datetime import datetime | |
| from fastapi import APIRouter, HTTPException, Depends | |
| from pydantic import BaseModel | |
| from firebase_admin import firestore | |
| from utils.rate_limiter import with_rate_limit | |
| from utils.groq_client import call_groq_json, HEAVY_MODEL | |
| from utils.pinecone_client import query_book_context | |
| router = APIRouter() | |
| class StartRequest(BaseModel): | |
| userId: str | |
| businessId: str | |
| class ReportRequest(BaseModel): | |
| userId: str | |
| businessId: str | |
| messages: list[dict] # [{"role": "user"|"assistant", "content": "..."}] | |
| def _read_profile(user_id: str, business_id: str) -> dict: | |
| db = firestore.client() | |
| biz = ( | |
| db.collection("user_data").document(user_id) | |
| .collection("businesses").document(business_id) | |
| ) | |
| ctx: dict = {} | |
| for key in ["businessIdentity", "customerProfile", "marketData"]: | |
| doc = biz.collection("profile_output").document(key).get() | |
| if doc.exists: | |
| ctx[key] = doc.to_dict() | |
| return ctx | |
| def start_consultation( | |
| body: StartRequest, | |
| user: dict = Depends(with_rate_limit("generation")), | |
| ): | |
| """ | |
| Reads the entrepreneur's business profile and generates a warm, structured | |
| opening message with 5 focus areas. The AI has already 'read the brief' | |
| so the session starts with context rather than from scratch. | |
| """ | |
| profile = _read_profile(body.userId, body.businessId) | |
| identity = profile.get("businessIdentity", {}) | |
| biz_name = identity.get("businessName", "your business") | |
| sector = identity.get("sector", "") | |
| value_prop = identity.get("valueProposition", "") | |
| summary = identity.get("summary", "") | |
| book_ctx = query_book_context( | |
| "business consultation strategy discovery analysis Nigerian entrepreneur", | |
| top_k=2, | |
| ) | |
| system = ( | |
| "You are a senior business consultant at VenThrive, trained in the " | |
| "Business Footing Framework from 'Built on Rock' by Iyanuoluwa Joseph Akinnusi. " | |
| "You are warm, direct, and speak in plain everyday English. " | |
| "You do NOT use business jargon. You speak like a trusted advisor, not a textbook. " | |
| "Return ONLY valid JSON." | |
| + (f"\n\n{book_ctx}" if book_ctx else "") | |
| ) | |
| prompt = f""" | |
| You are starting a consultation session with the founder of "{biz_name}" | |
| ({sector}). Their value proposition is: "{value_prop}". | |
| Brief summary: {summary[:300]} | |
| Generate a warm, professional opening message that: | |
| 1. Greets them by referencing their specific business (not generic) | |
| 2. Mentions you've reviewed their Business Footing Framework profile | |
| 3. Presents exactly 5 focus areas as a numbered list | |
| 4. Asks them to pick the one they want to focus on today | |
| The 5 focus areas should be: | |
| 1. Strategy & Market Position | |
| 2. Customer Acquisition & Retention | |
| 3. Financial Planning & Pricing | |
| 4. Operations & Standard Processes | |
| 5. Investor Readiness & Growth | |
| Return JSON: | |
| {{ | |
| "openingMessage": "<your full opening message here>", | |
| "focusAreas": ["Strategy & Market Position", "Customer Acquisition & Retention", "Financial Planning & Pricing", "Operations & Standard Processes", "Investor Readiness & Growth"] | |
| }}""" | |
| try: | |
| result = call_groq_json(system, prompt, model=HEAVY_MODEL, max_tokens=800, fixture="consultation_start") | |
| return { | |
| "openingMessage": result.get("openingMessage", ""), | |
| "focusAreas": result.get("focusAreas", []), | |
| } | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=f"Could not start consultation: {str(e)}") | |
| def generate_report( | |
| body: ReportRequest, | |
| user: dict = Depends(with_rate_limit("generation")), | |
| ): | |
| """ | |
| Takes the full session transcript and generates a structured consultation | |
| report with findings, specific recommendations, and next steps. | |
| """ | |
| if user.get("uid") != body.userId: | |
| raise HTTPException(status_code=403, detail="Forbidden.") | |
| if len(body.messages) < 2: | |
| raise HTTPException(status_code=400, detail="Session too short to generate a report.") | |
| transcript = "\n".join([ | |
| f"{'CONSULTANT' if m['role'] == 'assistant' else 'ENTREPRENEUR'}: {m['content']}" | |
| for m in body.messages | |
| ]) | |
| book_ctx = query_book_context( | |
| "consultation findings recommendations action plan Nigerian business", | |
| top_k=2, | |
| ) | |
| system = ( | |
| "You are a business consultant writing a formal post-consultation report. " | |
| "Analyze the conversation and produce a structured, actionable document. " | |
| "Be specific to what was actually discussed — no generic advice. " | |
| "Write in clear, plain English. " | |
| "Return ONLY valid JSON." | |
| + (f"\n\n{book_ctx}" if book_ctx else "") | |
| ) | |
| prompt = f""" | |
| Consultation transcript: | |
| {transcript[:4000]} | |
| Today's date: {datetime.now().strftime('%B %d, %Y')} | |
| Write a formal consultation report. Return JSON: | |
| {{ | |
| "date": "{datetime.now().strftime('%B %d, %Y')}", | |
| "sessionSummary": "2-3 sentences summarising what was discussed and the main concern addressed", | |
| "keyFindings": [ | |
| "Specific finding 1 from the conversation", | |
| "Specific finding 2", | |
| "Specific finding 3" | |
| ], | |
| "recommendations": [ | |
| {{ | |
| "action": "What to do", | |
| "rationale": "Why this matters for their specific business", | |
| "timeline": "When to do it (e.g. This week / Within 30 days)" | |
| }} | |
| ], | |
| "nextSteps": [ | |
| "Concrete action step 1", | |
| "Concrete action step 2", | |
| "Concrete action step 3" | |
| ], | |
| "closingNote": "A personalised, encouraging closing sentence referencing their business." | |
| }}""" | |
| try: | |
| result = call_groq_json(system, prompt, model=HEAVY_MODEL, max_tokens=2000, fixture="consultation_report") | |
| return {"report": result} | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=f"Report generation failed: {str(e)}") | |