# app.py import gradio as gr import json SYSTEM_PROMPT = ( "You are a friendly tutor for Entrepreneurial Readiness and Paths. " "Be practical and concise. If the user ran the assessment or path explorer, use that info." ) # ========================= # Domains (unchanged) # ========================= PATHS = { "tech": [ {"path":"Micro-SaaS","difficulty":3,"benefits":"High margins, scalable, global reach", "skills":["customer interviews","MVP scoping","pricing","analytics"], "starter":["Define niche pain","5–10 interviews","Landing page test","Iterate"]}, {"path":"No-code automation agency","difficulty":2,"benefits":"Service revenue funds experiments", "skills":["workflow mapping","Zapier/Make","sales","onboarding"], "starter":["Pick niche","3 pilot clients","SOPs","Retainers"]}, {"path":"Educational apps","difficulty":3,"benefits":"Recurring revenue via schools/parents", "skills":["curriculum","UX","distribution partnerships"], "starter":["Niche curriculum","Prototype","Parent/teacher tests"]} ], "cooking": [ {"path":"Meal-prep delivery","difficulty":4,"benefits":"Tangible product; recurring subs", "skills":["food safety","menu costing","logistics","support"], "starter":["Permits","Menu tests","Delivery loop","Subscriptions"]}, {"path":"Cooking classes","difficulty":2,"benefits":"Low capex; community", "skills":["lesson design","facilitation","marketing"], "starter":["Pilot class","Testimonials","Cohorts","Bundles"]} ], "education": [ {"path":"Tutoring niche","difficulty":2,"benefits":"Fast validation; referrals", "skills":["subject mastery","scheduling","sales"], "starter":["ICP","5 trial students","Packages","Referrals"]} ], "fitness": [ {"path":"Online coaching","difficulty":2,"benefits":"Low overhead; trust", "skills":["programming","accountability","content"], "starter":["Niche offer","Clients 1–3","Testimonials","Packages"]} ], "content": [ {"path":"Newsletter + paid tiers","difficulty":2,"benefits":"Audience compounds", "skills":["editorial","conversion","email ops"], "starter":["Niche POV","Weekly cadence","Lead magnet","Feedback loop"]} ], "games": [ {"path":"Indie premium","difficulty":4,"benefits":"Creative control; wishlists matter", "skills":["scope control","playtesting","marketing"], "starter":["Core loop","Vertical slice","Store page","Playtests"]} ], "fashion": [ {"path":"Print-on-demand niche","difficulty":2,"benefits":"Low inventory risk", "skills":["design","niche research","ads"], "starter":["Mockups","POD store","Ad test","Iterate"]} ] } # ========================= # Readiness factors (your list) # ========================= WEIGHTS = { "savings": 0.10, "income": 0.08, "bills": 0.08, # inverse "entertainment": 0.04, # inverse "assets": 0.06, "sales_skills": 0.14, "confidence": 0.10, "dependents": 0.06, # inverse "age": 0.04, # very small, symmetric "idea_level": 0.10, "entrepreneurial_experience": 0.10, "risk": 0.10, } CAP = { "savings": 20000, # USD "income": 8000, # USD / month "bills": 5000, # USD / month (inverse) "entertainment": 1000, # USD / month (inverse) "assets": 100000, # USD (liquid-ish) "dependents_max": 3, # 0..3+ (inverse) } IDEA_LEVEL_MAP = { "none": 0.0, "exploring": 0.25, "validated_problem": 0.5, "prototype": 0.75, "mvp_with_users": 1.0, } def _nz(x, default=0.0): try: return float(x) if x is not None else float(default) except Exception: return float(default) def _clamp01(v): return max(0.0, min(1.0, float(v))) def _direct_norm(v, cap): return _clamp01(_nz(v) / float(cap)) def _inverse_norm(v, cap): return 1.0 - _direct_norm(v, cap) def _age_norm(age): """Mild symmetric curve centered ~35; tiny effect (≤0.2).""" a = _nz(age, 35) penalty = min(abs(a - 35.0) / 35.0, 1.0) * 0.2 return _clamp01(1.0 - penalty) def _dependents_norm(dep): d = max(0, int(_nz(dep, 0))) base = 1.0 - min(d / float(CAP["dependents_max"]), 1.0) return _clamp01(base) # ------------------------------ # Readiness scoring (0–100) using your factors # ------------------------------ def compute_readiness(payload): n = { "savings": _direct_norm(payload["savings"], CAP["savings"]), "income": _direct_norm(payload["income"], CAP["income"]), "bills": _inverse_norm(payload["bills"], CAP["bills"]), "entertainment": _inverse_norm(payload["entertainment"], CAP["entertainment"]), "assets": _direct_norm(payload["assets"], CAP["assets"]), "sales_skills": _clamp01(_nz(payload["sales_skills"]) / 10.0), "confidence": _clamp01(_nz(payload["confidence"]) / 10.0), "dependents": _dependents_norm(payload["dependents"]), "age": _age_norm(payload["age"]), "idea_level": IDEA_LEVEL_MAP.get(payload["idea_level"], 0.0), "entrepreneurial_experience": _clamp01(_nz(payload["entrepreneurial_experience"]) / 10.0), "risk": _clamp01(_nz(payload["risk"]) / 10.0), } total = sum(WEIGHTS[k] * n[k] for k in WEIGHTS.keys()) score = int(round(100 * total)) tier = "Starter" if score < 55 else ("Building" if score < 75 else "Launch-ready") tips = [] # Finance levers if n["savings"] < 0.5 or n["assets"] < 0.4: tips.append("Run a 60–90 day runway sprint: reduce burn and build a buffer.") if n["bills"] < 0.6 or n["entertainment"] < 0.6: tips.append("Do a weekly expense audit and a 30-day no-spend on non-essentials.") if n["income"] < 0.5: tips.append("Spin up a simple service for cash: 3 outreach/day → 2 pilot clients.") # Skill/mindset levers if n["sales_skills"] < 0.6: tips.append("Do 20 cold DMs/day for 5 days; refine your offer script.") if n["confidence"] < 0.6: tips.append("Post build-in-public for 10 days to desensitize and attract allies.") if n["entrepreneurial_experience"] < 0.5: tips.append("Run a 2-week micro-project: interviews → small paid pilot.") if n["idea_level"] < 0.5: tips.append("Advance one notch: exploring → validated problem → prototype → MVP.") # Risk if n["risk"] < 0.5: tips.append("Set a ‘risk budget’: small, reversible tests with clear stop-lines.") return {"score": score, "tier": tier, "tips": tips[:5], "normalized": n} # ------------------------------ # Path suggestions helper (unchanged) # ------------------------------ def suggest_paths(interests, experience): results = [] for domain in interests or []: for item in PATHS.get(domain, []): diff = item["difficulty"] if experience == "beginner": diff = min(5, diff + 1) if experience == "advanced": diff = max(1, diff - 1) results.append({ "domain": domain, "path": item["path"], "difficulty_1to5": diff, "benefits": item["benefits"], "key_skills": item["skills"], "starter_plan": item["starter"], }) return results[:6] # ------------------------------ # Simple rule-based "chat" # ------------------------------ def local_reply(user_msg, history, assessment_state, path_state): text = (user_msg or "").lower() if "score" in text or "ready" in text or "readiness" in text: if isinstance(assessment_state, dict) and "score" in assessment_state: s = assessment_state["score"] t = assessment_state.get("tier", "?") tip = (assessment_state.get("tips") or ["Run small demand tests first."])[0] return f"Your readiness is **{s}/100 ({t})**. Top tip: {tip}" else: return "Run **Assess readiness** on the right, then ask me again 🙂" if "path" in text or "idea" in text or "domain" in text: if isinstance(path_state, dict) and path_state.get("suggestions"): sug = path_state["suggestions"][0] return (f"Try **{sug['domain']} → {sug['path']}**. " f"Difficulty ~{sug['difficulty_1to5']}/5. " f"Benefits: {sug['benefits']}. " f"First steps: {', '.join(sug['starter_plan'][:3])}. Want more options?") else: return "Pick a few interests under **Path Explorer**, hit **Suggest paths**, then ask me which to start with." for domain in PATHS.keys(): if domain in text: first = PATHS[domain][0] return (f"In **{domain}**, consider **{first['path']}** " f"(difficulty {first['difficulty']}/5). " f"Why it can pay off: {first['benefits']}. " f"Starter plan: {', '.join(first['starter'][:3])}.") return ("Start with a small **demand test**: a landing page and 5–10 user interviews. " "Measure real intent (signups/preorders) before you build.") # ------------------------------ # Gradio UI # ------------------------------ with gr.Blocks(theme="soft", fill_height=True) as demo: gr.Markdown("## Entrepreneurial Tutor") with gr.Row(): # Chat with gr.Column(scale=3): chat = gr.Chatbot(type="tuples", height=460) with gr.Row(): msg = gr.Textbox(placeholder="Ask about Entrepreneurial paths or readiness…", scale=4) send = gr.Button("Send", variant="primary") # Tools with gr.Column(scale=2): gr.Markdown("### Quick Readiness Assessment (your factors)") with gr.Row(): savings = gr.Number(value=2000, label="Savings (USD)", precision=0) income = gr.Number(value=2500, label="Income/mo (USD)", precision=0) with gr.Row(): bills = gr.Number(value=1500, label="Bills/mo (USD)", precision=0) entertainment = gr.Number(value=200, label="Entertainment/mo (USD)", precision=0) assets = gr.Number(value=0, label="Assets (USD)", precision=0) sales_skills = gr.Slider(0,10, value=5, step=1, label="Sales skills (0–10)") confidence = gr.Slider(0,10, value=5, step=1, label="Confidence (0–10)") dependents = gr.Slider(0,6, value=0, step=1, label="Dependents (count)") age = gr.Slider(15,80, value=25, step=1, label="Age") idea_level = gr.Radio( choices=list(IDEA_LEVEL_MAP.keys()), value="exploring", label="Idea level" ) entrepreneurial_experience = gr.Slider(0,10, value=3, step=1, label="Entrepreneurial experience (0–10)") risk = gr.Slider(0,10, value=5, step=1, label="Risk tolerance (0–10)") assess_btn = gr.Button("Assess readiness") assessment_state = gr.State({}) assess_out = gr.JSON(label="Assessment Result") gr.Markdown("### Path Explorer (domains)") interests = gr.CheckboxGroup( choices=list(PATHS.keys()), value=["tech"], label="Interests / domains" ) experience = gr.Radio( choices=["beginner","intermediate","advanced"], value="beginner", label="Experience level" ) suggest_btn = gr.Button("Suggest paths") path_state = gr.State({}) paths_out = gr.JSON(label="Suggested Paths") # Wiring def do_assess(savings, income, bills, entertainment, assets, sales_skills, confidence, dependents, age, idea_level, entrepreneurial_experience, risk): payload = { "savings": savings, "income": income, "bills": bills, "entertainment": entertainment, "assets": assets, "sales_skills": sales_skills, "confidence": confidence, "dependents": dependents, "age": age, "idea_level": idea_level, "entrepreneurial_experience": entrepreneurial_experience, "risk": risk } result = compute_readiness(payload) return result, result # show + store assess_btn.click( do_assess, inputs=[savings, income, bills, entertainment, assets, sales_skills, confidence, dependents, age, idea_level, entrepreneurial_experience, risk], outputs=[assess_out, assessment_state] ) def do_paths(interests, experience): res = suggest_paths(interests, experience) state = {"interests": interests, "experience": experience, "suggestions": res} return res, state suggest_btn.click( do_paths, inputs=[interests, experience], outputs=[paths_out, path_state] ) def on_send(user_message, history, assessment_state, path_state): if not user_message: return gr.update(), history reply = local_reply(user_message, history, assessment_state, path_state) return "", (history or []) + [[user_message, reply]] send.click( on_send, inputs=[msg, chat, assessment_state, path_state], outputs=[msg, chat] ) if __name__ == "__main__": demo.launch()