Download app.py from DetectiveShadow/Entrepreneurial_Testing: direct link, hf CLI and curl.
- Browser
- Download file 13.6 kB
-
https://huggingface.co/spaces/DetectiveShadow/Entrepreneurial_Testing/resolve/main/app.py
- Command line
-
hf download hf://spaces/DetectiveShadow/Entrepreneurial_Testing/app.py
-
curl -L -o app.py https://huggingface.co/spaces/DetectiveShadow/Entrepreneurial_Testing/resolve/main/app.py
13.6 kB
| # 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() | |