""" 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 @router.post("/start") 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": "", "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)}") @router.post("/report") 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)}")