Spaces:
Running
Running
Download routes/planning.py from Success-dev/venthrive-api: direct link, hf CLI and curl.
- Browser
- Download file 4.81 kB
-
https://huggingface.co/spaces/Success-dev/venthrive-api/resolve/main/routes/planning.py
- Command line
-
hf download hf://spaces/Success-dev/venthrive-api/routes/planning.py
-
curl -L -o planning.py https://huggingface.co/spaces/Success-dev/venthrive-api/resolve/main/routes/planning.py
4.81 kB
| """ | |
| Planning AI Suggestions | |
| ────────────────────────────────────────────────────────────────────────────── | |
| Reads the business profile and generates actionable task / milestone suggestions | |
| grounded in the BFF data and "Built on Rock" philosophy. | |
| Routes: | |
| POST /api/planning/suggest → task or milestone suggestions | |
| """ | |
| import json | |
| from datetime import datetime, timedelta | |
| 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 SuggestRequest(BaseModel): | |
| userId: str | |
| businessId: str | |
| type: str # "tasks" | "milestones" | |
| existing: list[str] = [] # existing task/milestone titles (to avoid duplicates) | |
| def _read_context(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", "marketData", "businessModel"]: | |
| doc = biz.collection("profile_output").document(key).get() | |
| if doc.exists: | |
| ctx[key] = doc.to_dict() | |
| s1 = biz.collection("bff").document("section1").get() | |
| if s1.exists: | |
| ctx["section1"] = s1.to_dict() | |
| return ctx | |
| def suggest_planning_items( | |
| body: SuggestRequest, | |
| user: dict = Depends(with_rate_limit("generation")), | |
| ): | |
| if body.type not in ("tasks", "milestones"): | |
| raise HTTPException(status_code=400, detail="type must be 'tasks' or 'milestones'") | |
| ctx = _read_context(body.userId, body.businessId) | |
| biz_name = ctx.get("businessIdentity", {}).get("businessName", "this business") | |
| sector = ctx.get("businessIdentity", {}).get("sector", "") | |
| value_prop = ctx.get("businessIdentity", {}).get("valueProposition", "") | |
| summary = ctx.get("businessIdentity", {}).get("summary", "") | |
| book_ctx = query_book_context( | |
| f"action plan milestones tasks Nigerian entrepreneur {sector}", top_k=2 | |
| ) | |
| existing_str = ( | |
| f"\nDo NOT duplicate any of these existing items: {body.existing}" | |
| if body.existing else "" | |
| ) | |
| system = ( | |
| "You are a business consultant helping a Nigerian entrepreneur plan their next steps. " | |
| "Suggest practical, specific, achievable actions grounded in the Business Footing Framework. " | |
| "All suggestions must be relevant to their specific business — no generic advice. " | |
| "Write in plain English. Return ONLY valid JSON." | |
| + (f"\n\n{book_ctx}" if book_ctx else "") | |
| ) | |
| if body.type == "tasks": | |
| prompt = f""" | |
| Business: {biz_name} ({sector}) | |
| Value proposition: {value_prop} | |
| Summary: {summary[:400]} | |
| {existing_str} | |
| Generate exactly 5 actionable Kanban tasks for this business right now. | |
| Tasks should be specific, achievable within 2 weeks, and move the business forward. | |
| Spread them across different priorities: some for this week, some for next week. | |
| Return JSON: | |
| {{ | |
| "suggestions": [ | |
| {{ | |
| "title": "specific task title", | |
| "description": "why this matters for {biz_name}", | |
| "column": "todo" | |
| }}, | |
| ... | |
| ] | |
| }} | |
| column must be one of: "todo", "in_progress", "done" | |
| Most tasks should be "todo" unless clearly already started. | |
| """ | |
| else: # milestones | |
| today = datetime.now() | |
| dates = [(today + timedelta(days=d)).strftime("%Y-%m-%d") for d in [30, 60, 90, 180, 365]] | |
| prompt = f""" | |
| Business: {biz_name} ({sector}) | |
| Value proposition: {value_prop} | |
| Summary: {summary[:400]} | |
| {existing_str} | |
| Generate exactly 5 business milestones for the next 12 months. | |
| Milestones should be measurable achievements that mark significant progress. | |
| Space them across different timeframes. | |
| Available target dates to choose from: {dates} | |
| (Choose the most appropriate date for each milestone) | |
| Return JSON: | |
| {{ | |
| "suggestions": [ | |
| {{ | |
| "title": "milestone title (specific and measurable)", | |
| "targetDate": "YYYY-MM-DD" | |
| }}, | |
| ... | |
| ] | |
| }} | |
| """ | |
| try: | |
| result = call_groq_json( | |
| system, prompt, model=HEAVY_MODEL, max_tokens=800, | |
| fixture=f"planning_{body.type}", | |
| ) | |
| suggestions = result.get("suggestions", []) | |
| if not suggestions: | |
| raise ValueError("No suggestions returned") | |
| return {"suggestions": suggestions} | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=f"Suggestion generation failed: {str(e)}") | |