File size: 4,810 Bytes
e561008
 
 
 
 
 
 
 
 
 
 
 
 
 
 
889e86b
e561008
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
889e86b
e561008
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
020705e
 
 
 
e561008
 
 
 
 
 
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
"""
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


@router.post("/suggest")
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)}")