DetectiveShadow commited on
Commit
4fcbd38
·
verified ·
1 Parent(s): e3d0eab

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +137 -64
app.py CHANGED
@@ -1,13 +1,15 @@
 
1
  import gradio as gr
 
2
 
3
- # ------------------------------
4
- # Data (minimal, in-file)
5
- # ------------------------------
6
- RUBRIC_WEIGHTS = {
7
- "grit": 0.18, "risk": 0.12, "time_per_week": 0.14, "runway_months": 0.16,
8
- "customer_access": 0.12, "validation_skill": 0.10, "ops_skill": 0.08, "finance_skill": 0.10
9
- }
10
 
 
 
 
11
  PATHS = {
12
  "tech": [
13
  {"path":"Micro-SaaS","difficulty":3,"benefits":"High margins, scalable, global reach",
@@ -55,56 +57,116 @@ PATHS = {
55
  ]
56
  }
57
 
58
- SYSTEM_PROMPT = (
59
- "You are a friendly tutor for Entrepreneurial Readiness and Paths. "
60
- "Be practical and concise. If the user ran the assessment or path explorer, use that info."
61
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
  # ------------------------------
64
- # Readiness scoring (0–100)
65
  # ------------------------------
66
  def compute_readiness(payload):
67
- # normalize
68
- grit = payload["grit"]/10
69
- risk = payload["risk"]/10
70
- time_norm = min(payload["time_per_week"], 40)/40
71
- runway_norm = min(payload["runway_months"], 24)/24
72
- customer_access = payload["customer_access"]/10
73
- validation_skill = payload["validation_skill"]/10
74
- ops_skill = payload["ops_skill"]/10
75
- finance_skill = payload["finance_skill"]/10
76
-
77
- score = 100 * (
78
- RUBRIC_WEIGHTS["grit"]*grit +
79
- RUBRIC_WEIGHTS["risk"]*risk +
80
- RUBRIC_WEIGHTS["time_per_week"]*time_norm +
81
- RUBRIC_WEIGHTS["runway_months"]*runway_norm +
82
- RUBRIC_WEIGHTS["customer_access"]*customer_access +
83
- RUBRIC_WEIGHTS["validation_skill"]*validation_skill +
84
- RUBRIC_WEIGHTS["ops_skill"]*ops_skill +
85
- RUBRIC_WEIGHTS["finance_skill"]*finance_skill
86
- )
87
- score = int(round(score))
88
  tier = "Starter" if score < 55 else ("Building" if score < 75 else "Launch-ready")
89
 
90
  tips = []
91
- if runway_norm < 0.35: tips.append("Build 6–12 months runway or run as a side project.")
92
- if time_norm < 0.5: tips.append("Protect ~8–12 hrs/week for interviews & experiments.")
93
- if customer_access < 0.6: tips.append("Line up 1020 target users for interviews.")
94
- if validation_skill < 0.6: tips.append("Run a demand test (landing page/preorder) before building.")
95
- if finance_skill < 0.5: tips.append("Track cash runway monthly.")
96
- if ops_skill < 0.5: tips.append("Create a weekly ops checklist to reduce chaos.")
97
- return {"score":score, "tier":tier, "tips":tips}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
 
99
  # ------------------------------
100
- # Path suggestions helper
101
  # ------------------------------
102
  def suggest_paths(interests, experience):
103
  results = []
104
  for domain in interests or []:
105
  for item in PATHS.get(domain, []):
106
  diff = item["difficulty"]
107
- # adjust for experience
108
  if experience == "beginner": diff = min(5, diff + 1)
109
  if experience == "advanced": diff = max(1, diff - 1)
110
  results.append({
@@ -115,7 +177,6 @@ def suggest_paths(interests, experience):
115
  "key_skills": item["skills"],
116
  "starter_plan": item["starter"],
117
  })
118
- # keep it short
119
  return results[:6]
120
 
121
  # ------------------------------
@@ -124,16 +185,15 @@ def suggest_paths(interests, experience):
124
  def local_reply(user_msg, history, assessment_state, path_state):
125
  text = (user_msg or "").lower()
126
 
127
- # reference readiness
128
  if "score" in text or "ready" in text or "readiness" in text:
129
  if isinstance(assessment_state, dict) and "score" in assessment_state:
130
  s = assessment_state["score"]
131
  t = assessment_state.get("tier", "?")
132
- return f"Your readiness is **{s}/100 ({t})**. Top tip: {assessment_state.get('tips', ['Run small demand tests first.'])[0]}"
 
133
  else:
134
  return "Run **Assess readiness** on the right, then ask me again 🙂"
135
 
136
- # reference paths
137
  if "path" in text or "idea" in text or "domain" in text:
138
  if isinstance(path_state, dict) and path_state.get("suggestions"):
139
  sug = path_state["suggestions"][0]
@@ -144,7 +204,6 @@ def local_reply(user_msg, history, assessment_state, path_state):
144
  else:
145
  return "Pick a few interests under **Path Explorer**, hit **Suggest paths**, then ask me which to start with."
146
 
147
- # detect domain mention
148
  for domain in PATHS.keys():
149
  if domain in text:
150
  first = PATHS[domain][0]
@@ -152,7 +211,6 @@ def local_reply(user_msg, history, assessment_state, path_state):
152
  f"(difficulty {first['difficulty']}/5). "
153
  f"Why it can pay off: {first['benefits']}. "
154
  f"Starter plan: {', '.join(first['starter'][:3])}.")
155
- # default helpful tip
156
  return ("Start with a small **demand test**: a landing page and 5–10 user interviews. "
157
  "Measure real intent (signups/preorders) before you build.")
158
 
@@ -160,7 +218,7 @@ def local_reply(user_msg, history, assessment_state, path_state):
160
  # Gradio UI
161
  # ------------------------------
162
  with gr.Blocks(theme="soft", fill_height=True) as demo:
163
- gr.Markdown("## Entrepreneurial Tutor testing \nAsk about readiness or paths. Use the tools on the right to feed me context.")
164
 
165
  with gr.Row():
166
  # Chat
@@ -172,21 +230,32 @@ with gr.Blocks(theme="soft", fill_height=True) as demo:
172
 
173
  # Tools
174
  with gr.Column(scale=2):
175
- gr.Markdown("### Quick Readiness Assessment")
176
- grit = gr.Slider(0,10, value=6, step=1, label="Grit / persistence")
177
- risk = gr.Slider(0,10, value=5, step=1, label="Comfort with risk")
178
- time_per_week = gr.Slider(0,40, value=8, step=1, label="Time available per week (hrs)")
179
- runway_months = gr.Slider(0,24, value=3, step=1, label="Financial runway (months)")
180
- customer_access = gr.Slider(0,10, value=5, step=1, label="Access to target customers")
181
- validation_skill = gr.Slider(0,10, value=4, step=1, label="Validation / testing skill")
182
- ops_skill = gr.Slider(0,10, value=4, step=1, label="Operations / delivery skill")
183
- finance_skill = gr.Slider(0,10, value=3, step=1, label="Finance / budgeting")
 
 
 
 
 
 
 
 
 
 
 
184
 
185
  assess_btn = gr.Button("Assess readiness")
186
  assessment_state = gr.State({})
187
  assess_out = gr.JSON(label="Assessment Result")
188
 
189
- gr.Markdown("### Path Explorer")
190
  interests = gr.CheckboxGroup(
191
  choices=list(PATHS.keys()),
192
  value=["tech"],
@@ -202,18 +271,22 @@ with gr.Blocks(theme="soft", fill_height=True) as demo:
202
  paths_out = gr.JSON(label="Suggested Paths")
203
 
204
  # Wiring
205
- def do_assess(grit, risk, time_per_week, runway_months, customer_access, validation_skill, ops_skill, finance_skill):
 
 
206
  payload = {
207
- "grit":grit,"risk":risk,"time_per_week":time_per_week,"runway_months":runway_months,
208
- "customer_access":customer_access,"validation_skill":validation_skill,
209
- "ops_skill":ops_skill,"finance_skill":finance_skill
210
  }
211
  result = compute_readiness(payload)
212
  return result, result # show + store
213
 
214
  assess_btn.click(
215
  do_assess,
216
- inputs=[grit, risk, time_per_week, runway_months, customer_access, validation_skill, ops_skill, finance_skill],
 
 
217
  outputs=[assess_out, assessment_state]
218
  )
219
 
 
1
+ # app.py
2
  import gradio as gr
3
+ import json
4
 
5
+ SYSTEM_PROMPT = (
6
+ "You are a friendly tutor for Entrepreneurial Readiness and Paths. "
7
+ "Be practical and concise. If the user ran the assessment or path explorer, use that info."
8
+ )
 
 
 
9
 
10
+ # =========================
11
+ # Domains (unchanged)
12
+ # =========================
13
  PATHS = {
14
  "tech": [
15
  {"path":"Micro-SaaS","difficulty":3,"benefits":"High margins, scalable, global reach",
 
57
  ]
58
  }
59
 
60
+ # =========================
61
+ # Readiness factors (your list)
62
+ # =========================
63
+ WEIGHTS = {
64
+ "savings": 0.10,
65
+ "income": 0.08,
66
+ "bills": 0.08, # inverse
67
+ "entertainment": 0.04, # inverse
68
+ "assets": 0.06,
69
+ "sales_skills": 0.14,
70
+ "confidence": 0.10,
71
+ "dependents": 0.06, # inverse
72
+ "age": 0.04, # very small, symmetric
73
+ "idea_level": 0.10,
74
+ "entrepreneurial_experience": 0.10,
75
+ "risk": 0.10,
76
+ }
77
+
78
+ CAP = {
79
+ "savings": 20000, # USD
80
+ "income": 8000, # USD / month
81
+ "bills": 5000, # USD / month (inverse)
82
+ "entertainment": 1000, # USD / month (inverse)
83
+ "assets": 100000, # USD (liquid-ish)
84
+ "dependents_max": 3, # 0..3+ (inverse)
85
+ }
86
+
87
+ IDEA_LEVEL_MAP = {
88
+ "none": 0.0,
89
+ "exploring": 0.25,
90
+ "validated_problem": 0.5,
91
+ "prototype": 0.75,
92
+ "mvp_with_users": 1.0,
93
+ }
94
+
95
+ def _nz(x, default=0.0):
96
+ try:
97
+ return float(x) if x is not None else float(default)
98
+ except Exception:
99
+ return float(default)
100
+
101
+ def _clamp01(v): return max(0.0, min(1.0, float(v)))
102
+ def _direct_norm(v, cap): return _clamp01(_nz(v) / float(cap))
103
+ def _inverse_norm(v, cap): return 1.0 - _direct_norm(v, cap)
104
+
105
+ def _age_norm(age):
106
+ """Mild symmetric curve centered ~35; tiny effect (≤0.2)."""
107
+ a = _nz(age, 35)
108
+ penalty = min(abs(a - 35.0) / 35.0, 1.0) * 0.2
109
+ return _clamp01(1.0 - penalty)
110
+
111
+ def _dependents_norm(dep):
112
+ d = max(0, int(_nz(dep, 0)))
113
+ base = 1.0 - min(d / float(CAP["dependents_max"]), 1.0)
114
+ return _clamp01(base)
115
 
116
  # ------------------------------
117
+ # Readiness scoring (0–100) using your factors
118
  # ------------------------------
119
  def compute_readiness(payload):
120
+ n = {
121
+ "savings": _direct_norm(payload["savings"], CAP["savings"]),
122
+ "income": _direct_norm(payload["income"], CAP["income"]),
123
+ "bills": _inverse_norm(payload["bills"], CAP["bills"]),
124
+ "entertainment": _inverse_norm(payload["entertainment"], CAP["entertainment"]),
125
+ "assets": _direct_norm(payload["assets"], CAP["assets"]),
126
+ "sales_skills": _clamp01(_nz(payload["sales_skills"]) / 10.0),
127
+ "confidence": _clamp01(_nz(payload["confidence"]) / 10.0),
128
+ "dependents": _dependents_norm(payload["dependents"]),
129
+ "age": _age_norm(payload["age"]),
130
+ "idea_level": IDEA_LEVEL_MAP.get(payload["idea_level"], 0.0),
131
+ "entrepreneurial_experience": _clamp01(_nz(payload["entrepreneurial_experience"]) / 10.0),
132
+ "risk": _clamp01(_nz(payload["risk"]) / 10.0),
133
+ }
134
+
135
+ total = sum(WEIGHTS[k] * n[k] for k in WEIGHTS.keys())
136
+ score = int(round(100 * total))
 
 
 
 
137
  tier = "Starter" if score < 55 else ("Building" if score < 75 else "Launch-ready")
138
 
139
  tips = []
140
+ # Finance levers
141
+ if n["savings"] < 0.5 or n["assets"] < 0.4:
142
+ tips.append("Run a 6090 day runway sprint: reduce burn and build a buffer.")
143
+ if n["bills"] < 0.6 or n["entertainment"] < 0.6:
144
+ tips.append("Do a weekly expense audit and a 30-day no-spend on non-essentials.")
145
+ if n["income"] < 0.5:
146
+ tips.append("Spin up a simple service for cash: 3 outreach/day → 2 pilot clients.")
147
+ # Skill/mindset levers
148
+ if n["sales_skills"] < 0.6:
149
+ tips.append("Do 20 cold DMs/day for 5 days; refine your offer script.")
150
+ if n["confidence"] < 0.6:
151
+ tips.append("Post build-in-public for 10 days to desensitize and attract allies.")
152
+ if n["entrepreneurial_experience"] < 0.5:
153
+ tips.append("Run a 2-week micro-project: interviews → small paid pilot.")
154
+ if n["idea_level"] < 0.5:
155
+ tips.append("Advance one notch: exploring → validated problem → prototype → MVP.")
156
+ # Risk
157
+ if n["risk"] < 0.5:
158
+ tips.append("Set a ‘risk budget’: small, reversible tests with clear stop-lines.")
159
+
160
+ return {"score": score, "tier": tier, "tips": tips[:5], "normalized": n}
161
 
162
  # ------------------------------
163
+ # Path suggestions helper (unchanged)
164
  # ------------------------------
165
  def suggest_paths(interests, experience):
166
  results = []
167
  for domain in interests or []:
168
  for item in PATHS.get(domain, []):
169
  diff = item["difficulty"]
 
170
  if experience == "beginner": diff = min(5, diff + 1)
171
  if experience == "advanced": diff = max(1, diff - 1)
172
  results.append({
 
177
  "key_skills": item["skills"],
178
  "starter_plan": item["starter"],
179
  })
 
180
  return results[:6]
181
 
182
  # ------------------------------
 
185
  def local_reply(user_msg, history, assessment_state, path_state):
186
  text = (user_msg or "").lower()
187
 
 
188
  if "score" in text or "ready" in text or "readiness" in text:
189
  if isinstance(assessment_state, dict) and "score" in assessment_state:
190
  s = assessment_state["score"]
191
  t = assessment_state.get("tier", "?")
192
+ tip = (assessment_state.get("tips") or ["Run small demand tests first."])[0]
193
+ return f"Your readiness is **{s}/100 ({t})**. Top tip: {tip}"
194
  else:
195
  return "Run **Assess readiness** on the right, then ask me again 🙂"
196
 
 
197
  if "path" in text or "idea" in text or "domain" in text:
198
  if isinstance(path_state, dict) and path_state.get("suggestions"):
199
  sug = path_state["suggestions"][0]
 
204
  else:
205
  return "Pick a few interests under **Path Explorer**, hit **Suggest paths**, then ask me which to start with."
206
 
 
207
  for domain in PATHS.keys():
208
  if domain in text:
209
  first = PATHS[domain][0]
 
211
  f"(difficulty {first['difficulty']}/5). "
212
  f"Why it can pay off: {first['benefits']}. "
213
  f"Starter plan: {', '.join(first['starter'][:3])}.")
 
214
  return ("Start with a small **demand test**: a landing page and 5–10 user interviews. "
215
  "Measure real intent (signups/preorders) before you build.")
216
 
 
218
  # Gradio UI
219
  # ------------------------------
220
  with gr.Blocks(theme="soft", fill_height=True) as demo:
221
+ gr.Markdown("## Entrepreneurial Tutor (domains kept, assessment replaced)")
222
 
223
  with gr.Row():
224
  # Chat
 
230
 
231
  # Tools
232
  with gr.Column(scale=2):
233
+ gr.Markdown("### Quick Readiness Assessment (your factors)")
234
+ with gr.Row():
235
+ savings = gr.Number(value=2000, label="Savings (USD)", precision=0)
236
+ income = gr.Number(value=2500, label="Income/mo (USD)", precision=0)
237
+ with gr.Row():
238
+ bills = gr.Number(value=1500, label="Bills/mo (USD)", precision=0)
239
+ entertainment = gr.Number(value=200, label="Entertainment/mo (USD)", precision=0)
240
+ assets = gr.Number(value=0, label="Assets (USD)", precision=0)
241
+
242
+ sales_skills = gr.Slider(0,10, value=5, step=1, label="Sales skills (0–10)")
243
+ confidence = gr.Slider(0,10, value=5, step=1, label="Confidence (0–10)")
244
+ dependents = gr.Slider(0,6, value=0, step=1, label="Dependents (count)")
245
+ age = gr.Slider(15,80, value=25, step=1, label="Age")
246
+ idea_level = gr.Radio(
247
+ choices=list(IDEA_LEVEL_MAP.keys()),
248
+ value="exploring",
249
+ label="Idea level"
250
+ )
251
+ entrepreneurial_experience = gr.Slider(0,10, value=3, step=1, label="Entrepreneurial experience (0–10)")
252
+ risk = gr.Slider(0,10, value=5, step=1, label="Risk tolerance (0–10)")
253
 
254
  assess_btn = gr.Button("Assess readiness")
255
  assessment_state = gr.State({})
256
  assess_out = gr.JSON(label="Assessment Result")
257
 
258
+ gr.Markdown("### Path Explorer (domains)")
259
  interests = gr.CheckboxGroup(
260
  choices=list(PATHS.keys()),
261
  value=["tech"],
 
271
  paths_out = gr.JSON(label="Suggested Paths")
272
 
273
  # Wiring
274
+ def do_assess(savings, income, bills, entertainment, assets,
275
+ sales_skills, confidence, dependents, age,
276
+ idea_level, entrepreneurial_experience, risk):
277
  payload = {
278
+ "savings": savings, "income": income, "bills": bills, "entertainment": entertainment, "assets": assets,
279
+ "sales_skills": sales_skills, "confidence": confidence, "dependents": dependents, "age": age,
280
+ "idea_level": idea_level, "entrepreneurial_experience": entrepreneurial_experience, "risk": risk
281
  }
282
  result = compute_readiness(payload)
283
  return result, result # show + store
284
 
285
  assess_btn.click(
286
  do_assess,
287
+ inputs=[savings, income, bills, entertainment, assets,
288
+ sales_skills, confidence, dependents, age,
289
+ idea_level, entrepreneurial_experience, risk],
290
  outputs=[assess_out, assessment_state]
291
  )
292