openfree commited on
Commit
f6f4ad9
Β·
verified Β·
1 Parent(s): e86e389

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +464 -429
app.py CHANGED
@@ -29,25 +29,130 @@ class StartupValuationCalculator:
29
  "200%+": 1.5
30
  }
31
 
32
- # λ‹¨μœ„κ²½μ œ 점수 κ°€μ€‘μΉ˜
33
- self.unit_economics_weights = {
34
- "ltv_cac_ratio": 0.3,
35
- "gross_margin": 0.3,
36
- "retention": 0.2,
37
- "payback": 0.2
 
38
  }
39
 
40
- # IP μžμ‚° κ°€μΉ˜ κ°€μ€‘μΉ˜
41
- self.ip_asset_weights = {
42
- "patents": 0.25,
43
- "papers": 0.15,
44
- "domains": 0.15,
45
- "trademarks": 0.10,
46
- "github": 0.10,
47
- "awards": 0.10,
48
- "team": 0.15
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  }
50
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  def calculate_arr(self, monthly_revenue, revenue_type):
52
  """μ›” λ§€μΆœμ„ μ—°κ°„ 반볡 맀좜(ARR)둜 λ³€ν™˜"""
53
  if revenue_type == "κ΅¬λ…ν˜• (SaaS)":
@@ -75,129 +180,82 @@ class StartupValuationCalculator:
75
  return 999
76
  return cac / (arpu * (gross_margin / 100))
77
 
78
- def get_unit_economics_score(self, ltv_cac_ratio, gross_margin, retention_rate, payback_months):
79
- """λ‹¨μœ„κ²½μ œ 점수 계산 (0-100)"""
80
- scores = {
81
- "ltv_cac_ratio": min(100, (ltv_cac_ratio / 3) * 100) if ltv_cac_ratio > 0 else 0,
82
- "gross_margin": min(100, gross_margin * 1.25),
83
- "retention": retention_rate,
84
- "payback": max(0, 100 - (payback_months / 24) * 100) if payback_months < 999 else 0
85
- }
86
-
87
- total_score = sum(scores[key] * self.unit_economics_weights[key] for key in scores)
88
- return total_score
89
-
90
- def evaluate_domain(self, domains):
91
- """도메인 κ°€μΉ˜ 평가"""
92
- if not domains:
93
- return 0
94
 
95
- domain_list = [d.strip() for d in domains.split(',') if d.strip()]
96
- score = 0
 
 
97
 
98
- for domain in domain_list:
99
- parsed = urlparse(domain if domain.startswith('http') else f'http://{domain}')
100
- domain_name = parsed.netloc or parsed.path
 
 
 
 
 
 
 
101
 
102
- # .com 도메인 가산점
103
- if domain_name.endswith('.com'):
104
- score += 30
105
- elif domain_name.endswith(('.io', '.ai', '.tech')):
106
- score += 20
 
 
 
 
 
107
  else:
108
- score += 10
109
 
110
- # 짧은 도메인 가산점
111
- name_length = len(domain_name.split('.')[0])
112
- if name_length <= 5:
113
- score += 20
114
- elif name_length <= 8:
115
- score += 10
116
-
117
- return min(100, score / len(domain_list))
118
-
119
- def evaluate_patents(self, patent_filed, patent_granted):
120
- """νŠΉν—ˆ κ°€μΉ˜ 평가"""
121
- score = 0
122
- score += patent_filed * 15 # μΆœμ› νŠΉν—ˆλ‹Ή 15점
123
- score += patent_granted * 30 # 등둝 νŠΉν—ˆλ‹Ή 30점
124
- return min(100, score)
125
-
126
- def evaluate_papers(self, papers):
127
- """λ…Όλ¬Έ κ°€μΉ˜ 평가"""
128
- if not papers:
129
- return 0
130
-
131
- paper_count = len([p.strip() for p in papers.split('\n') if p.strip()])
132
- score = paper_count * 20 # λ…Όλ¬Έλ‹Ή 20점
133
-
134
- # μ£Όμš” ν•™νšŒ/저널 ν‚€μ›Œλ“œ 체크
135
- prestigious_keywords = ['Nature', 'Science', 'IEEE', 'ACM', 'CVPR', 'NeurIPS', 'ICML']
136
- for keyword in prestigious_keywords:
137
- if keyword.lower() in papers.lower():
138
- score += 10
139
-
140
- return min(100, score)
141
-
142
- def evaluate_github(self, github_url, github_stars):
143
- """GitHub μ €μž₯μ†Œ 평가"""
144
- if not github_url:
145
- return 0
146
-
147
- score = 0
148
- if github_stars >= 1000:
149
- score = 80
150
- elif github_stars >= 500:
151
- score = 60
152
- elif github_stars >= 100:
153
- score = 40
154
- elif github_stars >= 50:
155
- score = 20
156
  else:
157
- score = 10
158
-
159
- return score
160
-
161
- def evaluate_team(self, team_size, phd_count, serial_entrepreneurs, big_tech_experience):
162
- """νŒ€ μ—­λŸ‰ 평가"""
163
- score = 0
164
-
165
- # νŒ€ 규λͺ¨
166
- if team_size >= 20:
167
- score += 20
168
- elif team_size >= 10:
169
- score += 15
170
- elif team_size >= 5:
171
- score += 10
172
-
173
- # 박사 ν•™μœ„
174
- score += min(30, phd_count * 10)
175
 
176
- # 연쇄창업가
177
- score += min(30, serial_entrepreneurs * 15)
 
 
178
 
179
- # λΉ…ν…Œν¬ κ²½ν—˜
180
- score += min(20, big_tech_experience * 5)
 
 
 
181
 
182
- return min(100, score)
183
-
184
- def calculate_ip_score(self, ip_data):
185
- """μ§€μ μž¬μ‚° μ’…ν•© 점수 계산"""
186
- scores = {
187
- "patents": self.evaluate_patents(ip_data["patent_filed"], ip_data["patent_granted"]),
188
- "papers": self.evaluate_papers(ip_data["papers"]),
189
- "domains": self.evaluate_domain(ip_data["domains"]),
190
- "trademarks": min(100, ip_data["trademarks"] * 20),
191
- "github": self.evaluate_github(ip_data["github_url"], ip_data["github_stars"]),
192
- "awards": min(100, ip_data["awards"] * 25),
193
- "team": self.evaluate_team(
194
- ip_data["team_size"], ip_data["phd_count"],
195
- ip_data["serial_entrepreneurs"], ip_data["big_tech_experience"]
196
- )
197
- }
198
 
199
- total_score = sum(scores[key] * self.ip_asset_weights[key] for key in scores)
200
- return total_score, scores
201
 
202
  def get_growth_category(self, growth_rate):
203
  """μ„±μž₯λ₯  μΉ΄ν…Œκ³ λ¦¬ κ²°μ •"""
@@ -212,128 +270,60 @@ class StartupValuationCalculator:
212
  else:
213
  return "200%+"
214
 
215
- def calculate_valuation(self, data, ip_data):
216
- """μ’…ν•© κ°€μΉ˜ν‰κ°€ 계산"""
217
- # ARR 계산
218
- arr = self.calculate_arr(data["monthly_revenue"], data["revenue_type"])
219
-
220
- # λ‹¨μœ„κ²½μ œ 계산
221
- ltv = self.calculate_ltv(data["arpu"], data["gross_margin"], data["monthly_churn"])
222
- cac = self.calculate_cac(data["monthly_marketing"], data["monthly_sales"], data["new_customers"])
223
- ltv_cac_ratio = ltv / cac if cac > 0 else 0
224
- payback = self.calculate_payback(cac, data["arpu"], data["gross_margin"])
225
-
226
- # λ‹¨μœ„κ²½μ œ 점수
227
- ue_score = self.get_unit_economics_score(
228
- ltv_cac_ratio, data["gross_margin"], data["retention_rate"], payback
229
- )
230
-
231
- # IP μžμ‚° 점수
232
- ip_score, ip_breakdown = self.calculate_ip_score(ip_data)
233
-
234
- # μ’…ν•© 점수 (λ‹¨μœ„κ²½μ œ 60%, IP 40%)
235
- combined_score = ue_score * 0.6 + ip_score * 0.4
236
-
237
- # κΈ°λ³Έ λ©€ν‹°ν”Œ 선택
238
- multiples = self.industry_multiples[data["industry"]]
239
- if combined_score >= 80:
240
- base_multiple = multiples["high"]
241
- elif combined_score >= 50:
242
- base_multiple = multiples["mid"]
243
- else:
244
- base_multiple = multiples["low"]
245
-
246
- # μ„±μž₯λ₯  μ‘°μ •
247
- growth_adj = self.growth_adjustments[self.get_growth_category(data["growth_rate"])]
248
- adjusted_multiple = base_multiple * growth_adj
249
-
250
- # μŠ€ν…Œμ΄μ§€ μ‘°μ •
251
- stage_adj = {
252
- "MVP/베타": 0.7,
253
- "초기 맀좜": 0.85,
254
- "μ„±μž₯ 단계": 1.0,
255
- "μˆ˜μ΅μ„± 확보": 1.2
256
- }
257
-
258
- # IP μžμ‚° 프리미엄 (μ΅œλŒ€ 20%)
259
- ip_premium = 1 + (ip_score / 100 * 0.2)
260
-
261
- final_multiple = adjusted_multiple * stage_adj[data["stage"]] * ip_premium
262
-
263
- # μ΅œμ’… κ°€μΉ˜ν‰κ°€
264
- valuation = arr * final_multiple
265
-
266
- # λŸ°μ›¨μ΄ 계산
267
- runway = data["cash_balance"] / data["burn_rate"] if data["burn_rate"] > 0 else 999
268
-
269
- return {
270
- "valuation": valuation,
271
- "arr": arr,
272
- "multiple": final_multiple,
273
- "ltv": ltv,
274
- "cac": cac,
275
- "ltv_cac_ratio": ltv_cac_ratio,
276
- "payback": payback,
277
- "ue_score": ue_score,
278
- "ip_score": ip_score,
279
- "ip_breakdown": ip_breakdown,
280
- "combined_score": combined_score,
281
- "runway": runway
282
- }
283
-
284
- def create_comparison_chart(self, valuation, industry, arr):
285
- """동쒅업계 비ꡐ 차트 생성"""
286
- multiples = self.industry_multiples[industry]
287
-
288
  fig = go.Figure()
289
 
290
- # 업계 λ²”μœ„
291
- low_val = arr * multiples["low"]
292
- mid_val = arr * multiples["mid"]
293
- high_val = arr * multiples["high"]
 
 
294
 
295
- # λ§‰λŒ€ κ·Έλž˜ν”„
296
  fig.add_trace(go.Bar(
297
- x=["ν•˜μœ„ 25%", "쀑간값", "μƒμœ„ 25%", "ν˜„μž¬ κΈ°μ—…"],
298
- y=[low_val, mid_val, high_val, valuation],
299
- text=[f"${low_val/1000000:.1f}M", f"${mid_val/1000000:.1f}M",
300
- f"${high_val/1000000:.1f}M", f"${valuation/1000000:.1f}M"],
301
  textposition="outside",
302
- marker_color=["lightgray", "gray", "darkgray", "blue"]
303
  ))
304
 
 
305
  fig.update_layout(
306
- title=f"{industry} 업계 κ°€μΉ˜ν‰κ°€ 비ꡐ",
307
- yaxis_title="κΈ°μ—…κ°€μΉ˜ (USD)",
308
  showlegend=False,
309
  height=400
310
  )
311
 
312
  return fig
313
 
314
- def create_ip_breakdown_chart(self, ip_breakdown):
315
- """IP μžμ‚° 뢄석 차트"""
316
- categories = list(ip_breakdown.keys())
317
- values = list(ip_breakdown.values())
318
-
319
- fig = go.Figure(data=[
320
- go.Radar(
321
- r=values,
322
- theta=categories,
323
- fill='toself',
324
- name='IP μžμ‚° 점수'
325
- )
326
- ])
327
 
 
 
 
 
 
 
 
 
 
328
  fig.update_layout(
329
  polar=dict(
330
  radialaxis=dict(
331
  visible=True,
332
  range=[0, 100]
333
- )
334
- ),
335
  showlegend=False,
336
- title="μ§€μ μž¬μ‚° μžμ‚° 뢄석"
337
  )
338
 
339
  return fig
@@ -342,26 +332,26 @@ def create_ui():
342
  calculator = StartupValuationCalculator()
343
 
344
  def process_valuation(
 
 
345
  company_name, founded_year, industry, stage, revenue_type,
 
346
  monthly_revenue, growth_rate, arpu, gross_margin, monthly_churn,
347
  retention_rate, new_customers, monthly_marketing, monthly_sales,
 
348
  cash_balance, burn_rate,
349
- # IP κ΄€λ ¨ μž…λ ₯
350
- domains, patent_filed, patent_granted, papers, trademarks,
351
- github_url, github_stars, awards, partnerships,
352
- team_size, phd_count, serial_entrepreneurs, big_tech_experience,
353
- media_coverage, app_downloads, social_followers
 
 
354
  ):
355
- # μž…λ ₯κ°’ 검증
356
- if monthly_revenue <= 0:
357
- return "μ›” λ§€μΆœμ„ μž…λ ₯ν•΄μ£Όμ„Έμš”.", None, None, None
358
-
359
  # 데이터 μ€€λΉ„
360
  data = {
361
  "company_name": company_name,
362
- "founded_year": founded_year,
363
  "industry": industry,
364
- "stage": stage,
365
  "revenue_type": revenue_type,
366
  "monthly_revenue": monthly_revenue * 1000,
367
  "growth_rate": growth_rate,
@@ -376,285 +366,330 @@ def create_ui():
376
  "burn_rate": burn_rate * 1000
377
  }
378
 
379
- ip_data = {
380
- "domains": domains,
381
- "patent_filed": patent_filed,
382
- "patent_granted": patent_granted,
383
- "papers": papers,
384
- "trademarks": trademarks,
385
- "github_url": github_url,
386
- "github_stars": github_stars,
387
- "awards": awards,
388
  "partnerships": partnerships,
389
- "team_size": team_size,
390
- "phd_count": phd_count,
391
- "serial_entrepreneurs": serial_entrepreneurs,
392
- "big_tech_experience": big_tech_experience,
393
- "media_coverage": media_coverage,
394
- "app_downloads": app_downloads,
395
- "social_followers": social_followers
 
 
 
 
 
 
 
 
396
  }
397
 
398
  # κ°€μΉ˜ν‰κ°€ 계산
399
- results = calculator.calculate_valuation(data, ip_data)
 
 
 
 
400
 
401
  # κ²°κ³Ό ν¬λ§·νŒ…
402
- valuation_text = f"""
403
- # πŸš€ {company_name} κ°€μΉ˜ν‰κ°€ κ²°κ³Ό
404
-
405
- ## πŸ“Š μ£Όμš” μ§€ν‘œ
406
- - **κΈ°μ—…κ°€μΉ˜**: ${results['valuation']/1000000:.1f}M (β‚©{results['valuation']/1000000*1300:.0f}μ–΅)
407
- - **ARR**: ${results['arr']/1000000:.1f}M
408
- - **적용 λ©€ν‹°ν”Œ**: {results['multiple']:.1f}x
409
 
410
- ## πŸ’° λ‹¨μœ„κ²½μ œ
411
- - **LTV**: ${results['ltv']:.0f}
412
- - **CAC**: ${results['cac']:.0f}
413
- - **LTV/CAC**: {results['ltv_cac_ratio']:.1f}x
414
- - **Payback Period**: {results['payback']:.1f}κ°œμ›”
415
- - **λ‹¨μœ„κ²½μ œ 점수**: {results['ue_score']:.0f}/100
416
-
417
- ## 🎯 μ§€μ μž¬μ‚° 및 λ¬΄ν˜•μžμ‚°
418
- - **IP μžμ‚° 점수**: {results['ip_score']:.0f}/100
419
- - **μ’…ν•© 점수**: {results['combined_score']:.0f}/100
420
 
421
- ### IP μžμ‚° μ„ΈλΆ€ 평가:
422
- - νŠΉν—ˆ: {results['ip_breakdown']['patents']:.0f}/100
423
- - λ…Όλ¬Έ: {results['ip_breakdown']['papers']:.0f}/100
424
- - 도메인: {results['ip_breakdown']['domains']:.0f}/100
425
- - μƒν‘œκΆŒ: {results['ip_breakdown']['trademarks']:.0f}/100
426
- - μ˜€ν”ˆμ†ŒμŠ€: {results['ip_breakdown']['github']:.0f}/100
427
- - μˆ˜μƒμ‹€μ : {results['ip_breakdown']['awards']:.0f}/100
428
- - νŒ€ μ—­λŸ‰: {results['ip_breakdown']['team']:.0f}/100
 
 
 
429
 
430
- ## πŸƒ 재무 건전성
431
- - **ν˜„κΈˆ λŸ°μ›¨μ΄**: {results['runway']:.1f}κ°œμ›”
432
- - **μ›”κ°„ 번레이트**: ${burn_rate}K
 
433
 
434
- ## πŸ’‘ 평가 μΈμ‚¬μ΄νŠΈ
 
 
 
 
 
 
435
  """
436
- # μΈμ‚¬μ΄νŠΈ μΆ”κ°€
437
- if results['ltv_cac_ratio'] < 1:
438
- valuation_text += "- ⚠️ LTV/CAC λΉ„μœ¨μ΄ 1 λ―Έλ§Œμž…λ‹ˆλ‹€. λ§ˆμΌ€νŒ… νš¨μœ¨μ„± κ°œμ„ μ΄ ν•„μš”ν•©λ‹ˆλ‹€.\n"
439
- elif results['ltv_cac_ratio'] > 3:
440
- valuation_text += "- βœ… μš°μˆ˜ν•œ LTV/CAC λΉ„μœ¨μ„ 보이고 μžˆμŠ΅λ‹ˆλ‹€.\n"
441
-
442
- if results['runway'] < 12:
443
- valuation_text += "- ⚠️ λŸ°μ›¨μ΄κ°€ 12κ°œμ›” λ―Έλ§Œμž…λ‹ˆλ‹€. μΆ”κ°€ μžκΈˆμ‘°λ‹¬μ„ κ³ λ €ν•˜μ„Έμš”.\n"
444
-
445
- if gross_margin < 60:
446
- valuation_text += "- πŸ“ˆ 맀좜총이읡λ₯  κ°œμ„  μ—¬μ§€κ°€ μžˆμŠ΅λ‹ˆλ‹€. (업계 평균: 70-80%)\n"
447
-
448
- if results['ip_score'] > 70:
449
- valuation_text += "- πŸ† κ°•λ ₯ν•œ IP 포트폴리였λ₯Ό λ³΄μœ ν•˜κ³  μžˆμ–΄ κ°€μΉ˜ν‰κ°€μ— 프리미엄이 μ μš©λ˜μ—ˆμŠ΅λ‹ˆλ‹€.\n"
450
 
451
- # 비ꡐ 차트 생성
452
- comparison_chart = calculator.create_comparison_chart(
453
- results['valuation'], industry, results['arr']
454
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
455
 
456
- # IP 뢄석 차트
457
- ip_chart = calculator.create_ip_breakdown_chart(results['ip_breakdown'])
 
 
 
 
 
 
 
 
 
 
 
458
 
459
- # 상세 뢄석 ν…Œμ΄λΈ”
460
- metrics_df = pd.DataFrame({
461
- "μ§€ν‘œ": ["μ›” 맀좜", "μ—° μ„±μž₯λ₯ ", "맀좜총이읡λ₯ ", "μ›” μ΄νƒˆλ₯ ", "고객 μœ μ§€μœ¨", "IP μžμ‚° 점수"],
462
- "ν˜„μž¬ κ°’": [f"${monthly_revenue}K", f"{growth_rate}%", f"{gross_margin}%",
463
- f"{monthly_churn}%", f"{retention_rate}%", f"{results['ip_score']:.0f}/100"],
464
- "업계 평균": ["N/A", "50-100%", "70-80%", "2-5%", "80-90%", "50/100"]
465
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
466
 
467
- return valuation_text, comparison_chart, ip_chart, metrics_df
468
 
469
  # Gradio UI
470
- with gr.Blocks(title="μŠ€νƒ€νŠΈμ—… κ°€μΉ˜ν‰κ°€ 계산기", theme=gr.themes.Soft()) as demo:
471
- gr.Markdown("""
472
- # πŸ¦„ μŠ€νƒ€νŠΈμ—… κ°€μΉ˜ν‰κ°€ μžλ™ν™” μ‹œμŠ€ν…œ v2.0
 
 
 
 
 
473
 
474
- κ°„λ‹¨ν•œ 정보 μž…λ ₯만으둜 κ·€μ‚¬μ˜ μ˜ˆμƒ κΈ°μ—…κ°€μΉ˜λ₯Ό μ‚°μΆœν•˜κ³  동쒅업계와 λΉ„κ΅ν•΄λ“œλ¦½λ‹ˆλ‹€.
475
- 이제 μ§€μ μž¬μ‚°κ³Ό λ¬΄ν˜•μžμ‚°κΉŒμ§€ μ’…ν•©μ μœΌλ‘œ ν‰κ°€ν•©λ‹ˆλ‹€.
 
476
  """)
477
 
478
- with gr.Tab("κΈ°λ³Έ 정보"):
479
  with gr.Row():
480
- company_name = gr.Textbox(label="νšŒμ‚¬λͺ…", value="우리 μŠ€νƒ€νŠΈμ—…")
481
- founded_year = gr.Slider(2015, 2024, value=2022, step=1, label="섀립연도")
482
 
483
  with gr.Row():
484
  industry = gr.Dropdown(
485
  choices=list(calculator.industry_multiples.keys()),
486
  value="SaaS - B2B",
487
- label="μ‚°μ—… λΆ„λ₯˜"
488
  )
489
  stage = gr.Radio(
490
  choices=["MVP/베타", "초기 맀좜", "μ„±μž₯ 단계", "μˆ˜μ΅μ„± 확보"],
491
  value="초기 맀좜",
492
- label="사업 단계"
493
  )
494
 
495
  revenue_type = gr.Radio(
496
  choices=["κ΅¬λ…ν˜• (SaaS)", "κ±°λž˜μˆ˜μˆ˜λ£Œν˜•", "μΌνšŒμ„± 판맀"],
497
  value="κ΅¬λ…ν˜• (SaaS)",
498
- label="수읡 λͺ¨λΈ"
499
  )
500
 
501
- with gr.Tab("맀좜 및 μ„±μž₯"):
502
- gr.Markdown("### πŸ’° 맀좜 정보 (λ‹¨μœ„: 천 λ‹¬λŸ¬)")
503
  with gr.Row():
504
- monthly_revenue = gr.Number(label="μ›” 맀좜 ($K)", value=50)
505
- growth_rate = gr.Slider(0, 300, value=100, step=10,
506
- label="μ—°κ°„ μ„±μž₯λ₯  (%)")
 
507
 
508
- with gr.Row():
509
- arpu = gr.Number(label="고객당 평균 맀좜 (ARPU) ($)", value=100)
510
- gross_margin = gr.Slider(0, 100, value=70, step=5,
511
- label="맀좜총이읡λ₯  (%)")
512
-
513
- with gr.Tab("고객 및 λ§ˆμΌ€νŒ…"):
514
- gr.Markdown("### πŸ‘₯ 고객 μ§€ν‘œ")
515
- with gr.Row():
516
- retention_rate = gr.Slider(0, 100, value=85, step=5,
517
- label="μ›”κ°„ 고객 μœ μ§€μœ¨ (%)")
518
- monthly_churn = gr.Slider(0, 20, value=3, step=0.5,
519
- label="μ›” μ΄νƒˆλ₯  (%)")
520
 
521
- gr.Markdown("### πŸ“’ λ§ˆμΌ€νŒ… νš¨μœ¨μ„±")
522
  with gr.Row():
523
- new_customers = gr.Number(label="μ›” μ‹ κ·œ 고객 수", value=50)
524
- monthly_marketing = gr.Number(label="μ›” λ§ˆμΌ€νŒ… λΉ„μš© ($K)", value=20)
525
- monthly_sales = gr.Number(label="μ›” μ˜μ—… λΉ„μš© ($K)", value=15)
526
-
527
- with gr.Tab("μ§€μ μž¬μ‚° 및 기술"):
528
- gr.Markdown("### πŸ“š νŠΉν—ˆ 및 λ…Όλ¬Έ")
529
- with gr.Row():
530
- patent_filed = gr.Number(label="μΆœμ› νŠΉν—ˆ 수", value=2)
531
- patent_granted = gr.Number(label="등둝 νŠΉν—ˆ 수", value=1)
532
- trademarks = gr.Number(label="μƒν‘œκΆŒ 수", value=1)
533
-
534
- papers = gr.Textbox(
535
- label="λ°œν‘œ λ…Όλ¬Έ (ν•œ 쀄에 ν•˜λ‚˜μ”©, URL 포함 κ°€λŠ₯)",
536
- lines=3,
537
- placeholder="예: https://arxiv.org/abs/2301.12345 - AI Model Optimization\nICML 2023 - Novel Approach to Machine Learning"
538
- )
539
 
540
- gr.Markdown("### 🌐 λ””μ§€ν„Έ μžμ‚°")
541
- domains = gr.Textbox(
542
- label="보유 도메인 (μ‰Όν‘œλ‘œ ꡬ뢄)",
543
- placeholder="예: mycompany.com, mycompany.ai, myproduct.io"
544
- )
545
 
 
546
  with gr.Row():
547
- github_url = gr.Textbox(
548
- label="GitHub μ €μž₯μ†Œ URL",
549
- placeholder="https://github.com/yourcompany/yourrepo"
550
- )
551
- github_stars = gr.Number(label="GitHub μŠ€νƒ€ 수", value=100)
 
 
 
552
 
553
- gr.Markdown("### πŸ† 인증 및 μˆ˜μƒ")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
554
  with gr.Row():
555
- awards = gr.Number(label="μ£Όμš” μˆ˜μƒ 싀적 수", value=1)
556
- partnerships = gr.Number(label="μ „λž΅μ  νŒŒνŠΈλ„ˆμ‹­ 수", value=2)
557
-
558
- with gr.Tab("νŒ€ 및 λΈŒλžœλ“œ"):
559
- gr.Markdown("### πŸ‘₯ νŒ€ ꡬ성")
560
  with gr.Row():
561
- team_size = gr.Number(label="전체 νŒ€ 규λͺ¨", value=10)
562
- phd_count = gr.Number(label="박사 ν•™μœ„ 보유자 수", value=1)
 
563
 
564
  with gr.Row():
565
- serial_entrepreneurs = gr.Number(label="연쇄창업가 수", value=1)
566
- big_tech_experience = gr.Number(label="λΉ…ν…Œν¬ μΆœμ‹  인원", value=2)
 
 
567
 
568
- gr.Markdown("### πŸ“± λΈŒλžœλ“œ 및 μ‚¬μš©μž 기반")
569
  with gr.Row():
570
- media_coverage = gr.Number(label="μ£Όμš” μ–Έλ‘  보도 수", value=5)
571
- app_downloads = gr.Number(label="μ•± λ‹€μš΄λ‘œλ“œ 수 (만)", value=10)
572
- social_followers = gr.Number(label="μ†Œμ…œλ―Έλ””μ–΄ νŒ”λ‘œμ›Œ (천)", value=50)
573
 
574
- with gr.Tab("재무 ν˜„ν™©"):
575
- gr.Markdown("### πŸ’Έ ν˜„κΈˆ 상황 (λ‹¨μœ„: 천 λ‹¬λŸ¬)")
576
  with gr.Row():
577
- cash_balance = gr.Number(label="ν˜„κΈˆ μž”κ³  ($K)", value=1000)
578
- burn_rate = gr.Number(label="μ›” 번레이트 ($K)", value=80)
579
 
580
  # 평가 μ‹€ν–‰ λ²„νŠΌ
581
- evaluate_btn = gr.Button("πŸ” κ°€μΉ˜ν‰κ°€ μ‹€ν–‰", variant="primary", size="lg")
582
 
583
  # κ²°κ³Ό 좜λ ₯
584
  with gr.Row():
585
  with gr.Column(scale=2):
586
- valuation_output = gr.Markdown(label="평가 κ²°κ³Ό")
587
  with gr.Column(scale=1):
588
- metrics_table = gr.DataFrame(label="μ£Όμš” μ§€ν‘œ 비ꡐ")
589
 
590
  with gr.Row():
591
- comparison_chart = gr.Plot(label="동쒅업계 비ꡐ")
592
- ip_chart = gr.Plot(label="IP μžμ‚° 뢄석")
593
 
594
  # 이벀트 μ—°κ²°
595
  evaluate_btn.click(
596
  process_valuation,
597
  inputs=[
 
598
  company_name, founded_year, industry, stage, revenue_type,
599
  monthly_revenue, growth_rate, arpu, gross_margin, monthly_churn,
600
  retention_rate, new_customers, monthly_marketing, monthly_sales,
601
  cash_balance, burn_rate,
602
- domains, patent_filed, patent_granted, papers, trademarks,
603
- github_url, github_stars, awards, partnerships,
604
- team_size, phd_count, serial_entrepreneurs, big_tech_experience,
605
- media_coverage, app_downloads, social_followers
 
606
  ],
607
- outputs=[valuation_output, comparison_chart, ip_chart, metrics_table]
608
  )
609
 
610
- # μ˜ˆμ‹œ 데이터 λ²„νŠΌλ“€
611
- gr.Markdown("### πŸ“ μ˜ˆμ‹œ λ°μ΄ν„°λ‘œ ν…ŒμŠ€νŠΈν•˜κΈ°")
612
  with gr.Row():
613
- gr.Button("AI μŠ€νƒ€νŠΈμ—… μ˜ˆμ‹œ").click(
614
  lambda: [
615
- "AI Tech Corp", 2021, "AI/λ”₯ν…Œν¬", "μ„±μž₯ 단계", "κ΅¬λ…ν˜• (SaaS)",
616
- 100, 150, 200, 75, 2,
617
- 90, 40, 30, 20,
618
- 2000, 120,
619
- "aitech.com, aitech.ai", 5, 2,
620
- "NeurIPS 2023 - Novel AI Architecture\nhttps://arxiv.org/abs/2023.12345", 3,
621
- "https://github.com/aitech/core", 500, 3, 5,
622
- 15, 3, 2, 4,
623
- 10, 50, 100
624
  ],
625
  outputs=[
626
- company_name, founded_year, industry, stage, revenue_type,
627
  monthly_revenue, growth_rate, arpu, gross_margin, monthly_churn,
628
  retention_rate, new_customers, monthly_marketing, monthly_sales,
629
  cash_balance, burn_rate,
630
- domains, patent_filed, patent_granted, papers, trademarks,
631
- github_url, github_stars, awards, partnerships,
632
- team_size, phd_count, serial_entrepreneurs, big_tech_experience,
633
- media_coverage, app_downloads, social_followers
 
634
  ]
635
  )
636
 
637
- gr.Button("λ°”μ΄μ˜€ν…Œν¬ μ˜ˆμ‹œ").click(
638
  lambda: [
639
- "BioHealth Inc", 2020, "ν—¬μŠ€μΌ€μ–΄", "초기 맀좜", "κ΅¬λ…ν˜• (SaaS)",
640
- 80, 200, 500, 85, 1,
641
- 95, 20, 40, 30,
642
- 3000, 150,
643
- "biohealth.com, biohealth.health", 8, 4,
644
- "Nature Medicine 2023 - Breakthrough in Drug Discovery\nScience 2023 - Novel Biomarker", 5,
645
- "https://github.com/biohealth/research", 200, 5, 3,
646
- 25, 8, 1, 3,
647
- 15, 5, 30
648
  ],
649
  outputs=[
650
- company_name, founded_year, industry, stage, revenue_type,
651
  monthly_revenue, growth_rate, arpu, gross_margin, monthly_churn,
652
  retention_rate, new_customers, monthly_marketing, monthly_sales,
653
  cash_balance, burn_rate,
654
- domains, patent_filed, patent_granted, papers, trademarks,
655
- github_url, github_stars, awards, partnerships,
656
- team_size, phd_count, serial_entrepreneurs, big_tech_experience,
657
- media_coverage, app_downloads, social_followers
 
658
  ]
659
  )
660
 
 
29
  "200%+": 1.5
30
  }
31
 
32
+ # λ²„ν¬μŠ€ 방법 μΉ΄ν…Œκ³ λ¦¬λ³„ μ΅œλŒ€κ°’ ($500K each)
33
+ self.berkus_max_values = {
34
+ "sound_idea": 500000,
35
+ "prototype": 500000,
36
+ "quality_team": 500000,
37
+ "strategic_relationships": 500000,
38
+ "product_rollout": 500000
39
  }
40
 
41
+ # μŠ€μ½”μ–΄μΉ΄λ“œ κ°€μ€‘μΉ˜
42
+ self.scorecard_weights = {
43
+ "team": 0.30,
44
+ "market_size": 0.25,
45
+ "product": 0.15,
46
+ "competition": 0.10,
47
+ "marketing": 0.10,
48
+ "need_for_funding": 0.05,
49
+ "other": 0.05
50
+ }
51
+
52
+ # 언어별 ν…μŠ€νŠΈ
53
+ self.translations = {
54
+ "ko": {
55
+ "title": "πŸ¦„ μŠ€νƒ€νŠΈμ—… κ°€μΉ˜ν‰κ°€ μžλ™ν™” μ‹œμŠ€ν…œ v3.0",
56
+ "subtitle": "λ²„ν¬μŠ€ 방법과 μŠ€μ½”μ–΄μΉ΄λ“œ 방법을 ν¬ν•¨ν•œ μ’…ν•© 평가",
57
+ "valuation_result": "κ°€μΉ˜ν‰κ°€ κ²°κ³Ό",
58
+ "company_value": "κΈ°μ—…κ°€μΉ˜",
59
+ "arr": "μ—°κ°„ 반볡 맀좜",
60
+ "multiple": "적용 λ©€ν‹°ν”Œ",
61
+ "unit_economics": "λ‹¨μœ„κ²½μ œ",
62
+ "berkus_score": "λ²„ν¬μŠ€ 평가",
63
+ "scorecard_score": "μŠ€μ½”μ–΄μΉ΄λ“œ 평가",
64
+ "financial_health": "재무 건전성",
65
+ "insights": "평가 μΈμ‚¬μ΄νŠΈ"
66
+ },
67
+ "en": {
68
+ "title": "πŸ¦„ Startup Valuation System v3.0",
69
+ "subtitle": "Comprehensive valuation with Berkus and Scorecard methods",
70
+ "valuation_result": "Valuation Result",
71
+ "company_value": "Company Value",
72
+ "arr": "Annual Recurring Revenue",
73
+ "multiple": "Applied Multiple",
74
+ "unit_economics": "Unit Economics",
75
+ "berkus_score": "Berkus Score",
76
+ "scorecard_score": "Scorecard Score",
77
+ "financial_health": "Financial Health",
78
+ "insights": "Valuation Insights"
79
+ }
80
  }
81
 
82
+ def calculate_berkus_score(self, berkus_data):
83
+ """λ²„ν¬μŠ€ λ°©λ²•μœΌλ‘œ 평가 (μ΅œλŒ€ $2.5M)"""
84
+ scores = {}
85
+ total = 0
86
+
87
+ # 1. κ±΄μ „ν•œ 아이디어 (Sound Idea)
88
+ idea_score = min(100, berkus_data["idea_validation"] + berkus_data["market_research"] * 10)
89
+ scores["sound_idea"] = self.berkus_max_values["sound_idea"] * (idea_score / 100)
90
+
91
+ # 2. ν”„λ‘œν† νƒ€μž… (Prototype)
92
+ prototype_score = 0
93
+ if berkus_data["prototype_stage"] == "μ—†μŒ":
94
+ prototype_score = 0
95
+ elif berkus_data["prototype_stage"] == "컨셉/λͺ©μ—…":
96
+ prototype_score = 30
97
+ elif berkus_data["prototype_stage"] == "μž‘λ™ ν”„λ‘œν† νƒ€μž…":
98
+ prototype_score = 60
99
+ elif berkus_data["prototype_stage"] == "베타 버전":
100
+ prototype_score = 80
101
+ elif berkus_data["prototype_stage"] == "μΆœμ‹œ 버전":
102
+ prototype_score = 100
103
+ scores["prototype"] = self.berkus_max_values["prototype"] * (prototype_score / 100)
104
+
105
+ # 3. μš°μˆ˜ν•œ νŒ€ (Quality Team)
106
+ team_score = min(100,
107
+ berkus_data["team_experience"] * 20 +
108
+ berkus_data["domain_expertise"] * 15 +
109
+ berkus_data["startup_experience"] * 15
110
+ )
111
+ scores["quality_team"] = self.berkus_max_values["quality_team"] * (team_score / 100)
112
+
113
+ # 4. μ „λž΅μ  관계 (Strategic Relationships)
114
+ relationship_score = min(100,
115
+ berkus_data["partnerships"] * 15 +
116
+ berkus_data["advisors"] * 10 +
117
+ berkus_data["pilot_customers"] * 25
118
+ )
119
+ scores["strategic_relationships"] = self.berkus_max_values["strategic_relationships"] * (relationship_score / 100)
120
+
121
+ # 5. μ œν’ˆ μΆœμ‹œ/판맀 (Product Rollout)
122
+ if berkus_data["sales_started"]:
123
+ rollout_score = min(100, 50 + berkus_data["customer_validation"] * 10)
124
+ else:
125
+ rollout_score = berkus_data["launch_readiness"]
126
+ scores["product_rollout"] = self.berkus_max_values["product_rollout"] * (rollout_score / 100)
127
+
128
+ total = sum(scores.values())
129
+ return total, scores
130
+
131
+ def calculate_scorecard_valuation(self, scorecard_data, base_valuation):
132
+ """μŠ€μ½”μ–΄μΉ΄λ“œ λ°©λ²•μœΌλ‘œ μ‘°μ •λœ κ°€μΉ˜ν‰κ°€"""
133
+ adjustments = {}
134
+
135
+ # 각 μš”μ†Œλ³„ μ‘°μ • λΉ„μœ¨ 계산 (0.5 ~ 1.5)
136
+ adjustments["team"] = scorecard_data["team_strength"] / 100 # 0-100 -> 0-1
137
+ adjustments["market_size"] = scorecard_data["market_opportunity"] / 100
138
+ adjustments["product"] = scorecard_data["product_stage"] / 100
139
+ adjustments["competition"] = scorecard_data["competitive_advantage"] / 100
140
+ adjustments["marketing"] = scorecard_data["marketing_channels"] / 100
141
+ adjustments["need_for_funding"] = scorecard_data["funding_efficiency"] / 100
142
+ adjustments["other"] = scorecard_data["other_factors"] / 100
143
+
144
+ # 가쀑 평균 계산
145
+ weighted_score = 0
146
+ for factor, weight in self.scorecard_weights.items():
147
+ # 각 점수λ₯Ό 0.5 ~ 1.5 λ²”μœ„λ‘œ λ³€ν™˜ (50점이 1.0)
148
+ adjusted_score = 0.5 + (adjustments[factor])
149
+ weighted_score += adjusted_score * weight
150
+
151
+ # κΈ°λ³Έ κ°€μΉ˜ν‰κ°€μ— μ‘°μ • λΉ„μœ¨ 적용
152
+ adjusted_valuation = base_valuation * weighted_score
153
+
154
+ return adjusted_valuation, adjustments, weighted_score
155
+
156
  def calculate_arr(self, monthly_revenue, revenue_type):
157
  """μ›” λ§€μΆœμ„ μ—°κ°„ 반볡 맀좜(ARR)둜 λ³€ν™˜"""
158
  if revenue_type == "κ΅¬λ…ν˜• (SaaS)":
 
180
  return 999
181
  return cac / (arpu * (gross_margin / 100))
182
 
183
+ def calculate_valuation(self, data, berkus_data, scorecard_data, use_revenue_multiple=True):
184
+ """μ’…ν•© κ°€μΉ˜ν‰κ°€ 계산"""
185
+ results = {}
 
 
 
 
 
 
 
 
 
 
 
 
 
186
 
187
+ # 1. λ²„ν¬μŠ€ 방법 평가
188
+ berkus_valuation, berkus_scores = self.calculate_berkus_score(berkus_data)
189
+ results["berkus_valuation"] = berkus_valuation
190
+ results["berkus_scores"] = berkus_scores
191
 
192
+ # 2. 맀좜 기반 평가 (맀좜이 μžˆλŠ” 경우)
193
+ if data["monthly_revenue"] > 0 and use_revenue_multiple:
194
+ # ARR 계산
195
+ arr = self.calculate_arr(data["monthly_revenue"], data["revenue_type"])
196
+
197
+ # λ‹¨μœ„κ²½μ œ 계산
198
+ ltv = self.calculate_ltv(data["arpu"], data["gross_margin"], data["monthly_churn"])
199
+ cac = self.calculate_cac(data["monthly_marketing"], data["monthly_sales"], data["new_customers"])
200
+ ltv_cac_ratio = ltv / cac if cac > 0 else 0
201
+ payback = self.calculate_payback(cac, data["arpu"], data["gross_margin"])
202
 
203
+ # λ©€ν‹°ν”Œ κ²°μ •
204
+ multiples = self.industry_multiples[data["industry"]]
205
+ growth_category = self.get_growth_category(data["growth_rate"])
206
+ growth_adj = self.growth_adjustments[growth_category]
207
+
208
+ # κΈ°λ³Έ λ©€ν‹°ν”Œ 선택
209
+ if ltv_cac_ratio >= 3:
210
+ base_multiple = multiples["high"]
211
+ elif ltv_cac_ratio >= 1.5:
212
+ base_multiple = multiples["mid"]
213
  else:
214
+ base_multiple = multiples["low"]
215
 
216
+ adjusted_multiple = base_multiple * growth_adj
217
+
218
+ # 맀좜 기반 κ°€μΉ˜ν‰κ°€
219
+ revenue_valuation = arr * adjusted_multiple
220
+
221
+ results["arr"] = arr
222
+ results["ltv"] = ltv
223
+ results["cac"] = cac
224
+ results["ltv_cac_ratio"] = ltv_cac_ratio
225
+ results["payback"] = payback
226
+ results["multiple"] = adjusted_multiple
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  else:
228
+ revenue_valuation = 0
229
+ results["arr"] = 0
230
+ results["ltv"] = 0
231
+ results["cac"] = 0
232
+ results["ltv_cac_ratio"] = 0
233
+ results["payback"] = 0
234
+ results["multiple"] = 0
235
+
236
+ # 3. κΈ°λ³Έ κ°€μΉ˜ν‰κ°€ κ²°μ • (λ²„ν¬μŠ€ vs 맀좜 기반)
237
+ if revenue_valuation > berkus_valuation * 1.5:
238
+ base_valuation = revenue_valuation
239
+ valuation_method = "revenue_multiple"
240
+ else:
241
+ base_valuation = max(berkus_valuation, revenue_valuation)
242
+ valuation_method = "berkus"
 
 
 
243
 
244
+ # 4. μŠ€μ½”μ–΄μΉ΄λ“œ μ‘°μ •
245
+ final_valuation, scorecard_adjustments, weighted_score = self.calculate_scorecard_valuation(
246
+ scorecard_data, base_valuation
247
+ )
248
 
249
+ results["base_valuation"] = base_valuation
250
+ results["final_valuation"] = final_valuation
251
+ results["valuation_method"] = valuation_method
252
+ results["scorecard_adjustments"] = scorecard_adjustments
253
+ results["scorecard_multiplier"] = weighted_score
254
 
255
+ # 5. λŸ°μ›¨μ΄ 계산
256
+ results["runway"] = data["cash_balance"] / data["burn_rate"] if data["burn_rate"] > 0 else 999
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
 
258
+ return results
 
259
 
260
  def get_growth_category(self, growth_rate):
261
  """μ„±μž₯λ₯  μΉ΄ν…Œκ³ λ¦¬ κ²°μ •"""
 
270
  else:
271
  return "200%+"
272
 
273
+ def create_valuation_comparison_chart(self, results, language="ko"):
274
+ """평가 방법별 비ꡐ 차트"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275
  fig = go.Figure()
276
 
277
+ methods = ["Berkus", "Revenue Multiple", "Scorecard Adjusted"]
278
+ values = [
279
+ results["berkus_valuation"],
280
+ results["base_valuation"] if results["valuation_method"] == "revenue_multiple" else 0,
281
+ results["final_valuation"]
282
+ ]
283
 
 
284
  fig.add_trace(go.Bar(
285
+ x=methods,
286
+ y=values,
287
+ text=[f"${v/1000000:.2f}M" for v in values],
 
288
  textposition="outside",
289
+ marker_color=["lightblue", "lightgreen", "darkblue"]
290
  ))
291
 
292
+ title = "평가 방법별 κΈ°μ—…κ°€μΉ˜ 비ꡐ" if language == "ko" else "Valuation by Method"
293
  fig.update_layout(
294
+ title=title,
295
+ yaxis_title="Valuation (USD)",
296
  showlegend=False,
297
  height=400
298
  )
299
 
300
  return fig
301
 
302
+ def create_scorecard_radar_chart(self, adjustments, language="ko"):
303
+ """μŠ€μ½”μ–΄μΉ΄λ“œ μš”μ†Œλ³„ 점수 λ ˆμ΄λ” 차트"""
304
+ categories = list(adjustments.keys())
305
+ if language == "ko":
306
+ categories_display = ["νŒ€", "μ‹œμž₯규λͺ¨", "μ œν’ˆ", "경쟁λ ₯", "λ§ˆμΌ€νŒ…", "자금효율", "기타"]
307
+ else:
308
+ categories_display = ["Team", "Market", "Product", "Competition", "Marketing", "Funding", "Other"]
 
 
 
 
 
 
309
 
310
+ values = [adjustments[cat] * 100 for cat in categories]
311
+
312
+ fig = go.Figure(data=go.Scatterpolar(
313
+ r=values,
314
+ theta=categories_display,
315
+ fill='toself'
316
+ ))
317
+
318
+ title = "μŠ€μ½”μ–΄μΉ΄λ“œ 평가 μš”μ†Œ" if language == "ko" else "Scorecard Factors"
319
  fig.update_layout(
320
  polar=dict(
321
  radialaxis=dict(
322
  visible=True,
323
  range=[0, 100]
324
+ )),
 
325
  showlegend=False,
326
+ title=title
327
  )
328
 
329
  return fig
 
332
  calculator = StartupValuationCalculator()
333
 
334
  def process_valuation(
335
+ language,
336
+ # κΈ°λ³Έ 정보
337
  company_name, founded_year, industry, stage, revenue_type,
338
+ # 맀좜 정보
339
  monthly_revenue, growth_rate, arpu, gross_margin, monthly_churn,
340
  retention_rate, new_customers, monthly_marketing, monthly_sales,
341
+ # 재무 정보
342
  cash_balance, burn_rate,
343
+ # λ²„ν¬μŠ€ 방법 μž…λ ₯
344
+ idea_validation, market_research, prototype_stage, team_experience,
345
+ domain_expertise, startup_experience, partnerships, advisors,
346
+ pilot_customers, sales_started, customer_validation, launch_readiness,
347
+ # μŠ€μ½”μ–΄μΉ΄λ“œ μž…λ ₯
348
+ team_strength, market_opportunity, product_stage, competitive_advantage,
349
+ marketing_channels, funding_efficiency, other_factors
350
  ):
 
 
 
 
351
  # 데이터 μ€€λΉ„
352
  data = {
353
  "company_name": company_name,
 
354
  "industry": industry,
 
355
  "revenue_type": revenue_type,
356
  "monthly_revenue": monthly_revenue * 1000,
357
  "growth_rate": growth_rate,
 
366
  "burn_rate": burn_rate * 1000
367
  }
368
 
369
+ berkus_data = {
370
+ "idea_validation": idea_validation,
371
+ "market_research": market_research,
372
+ "prototype_stage": prototype_stage,
373
+ "team_experience": team_experience,
374
+ "domain_expertise": domain_expertise,
375
+ "startup_experience": startup_experience,
 
 
376
  "partnerships": partnerships,
377
+ "advisors": advisors,
378
+ "pilot_customers": pilot_customers,
379
+ "sales_started": sales_started,
380
+ "customer_validation": customer_validation,
381
+ "launch_readiness": launch_readiness
382
+ }
383
+
384
+ scorecard_data = {
385
+ "team_strength": team_strength,
386
+ "market_opportunity": market_opportunity,
387
+ "product_stage": product_stage,
388
+ "competitive_advantage": competitive_advantage,
389
+ "marketing_channels": marketing_channels,
390
+ "funding_efficiency": funding_efficiency,
391
+ "other_factors": other_factors
392
  }
393
 
394
  # κ°€μΉ˜ν‰κ°€ 계산
395
+ use_revenue = monthly_revenue > 0
396
+ results = calculator.calculate_valuation(data, berkus_data, scorecard_data, use_revenue)
397
+
398
+ # 언어별 ν…μŠ€νŠΈ
399
+ t = calculator.translations[language]
400
 
401
  # κ²°κ³Ό ν¬λ§·νŒ…
402
+ if language == "ko":
403
+ valuation_text = f"""
404
+ # πŸš€ {company_name} {t['valuation_result']}
 
 
 
 
405
 
406
+ ## πŸ“Š μ’…ν•© 평가
407
+ - **{t['company_value']}**: ${results['final_valuation']/1000000:.2f}M
408
+ - **평가 방법**: {'맀좜 λ©€ν‹°ν”Œ' if results['valuation_method'] == 'revenue_multiple' else 'λ²„ν¬μŠ€ 방법'} + μŠ€μ½”μ–΄μΉ΄λ“œ μ‘°μ •
409
+ - **μŠ€μ½”μ–΄μΉ΄λ“œ μ‘°μ • 배수**: {results['scorecard_multiplier']:.2f}x
 
 
 
 
 
 
410
 
411
+ ## 🎯 {t['berkus_score']} (μ΅œλŒ€ $2.5M)
412
+ - **총 평가앑**: ${results['berkus_valuation']/1000000:.2f}M
413
+ - κ±΄μ „ν•œ 아이디어: ${results['berkus_scores']['sound_idea']/1000:.0f}K
414
+ - ν”„λ‘œν† νƒ€μž…: ${results['berkus_scores']['prototype']/1000:.0f}K
415
+ - μš°μˆ˜ν•œ νŒ€: ${results['berkus_scores']['quality_team']/1000:.0f}K
416
+ - μ „λž΅μ  관계: ${results['berkus_scores']['strategic_relationships']/1000:.0f}K
417
+ - μ œν’ˆ μΆœμ‹œ: ${results['berkus_scores']['product_rollout']/1000:.0f}K
418
+ """
419
+ else:
420
+ valuation_text = f"""
421
+ # πŸš€ {company_name} {t['valuation_result']}
422
 
423
+ ## πŸ“Š Summary
424
+ - **{t['company_value']}**: ${results['final_valuation']/1000000:.2f}M
425
+ - **Method**: {'Revenue Multiple' if results['valuation_method'] == 'revenue_multiple' else 'Berkus Method'} + Scorecard
426
+ - **Scorecard Multiplier**: {results['scorecard_multiplier']:.2f}x
427
 
428
+ ## 🎯 {t['berkus_score']} (Max $2.5M)
429
+ - **Total**: ${results['berkus_valuation']/1000000:.2f}M
430
+ - Sound Idea: ${results['berkus_scores']['sound_idea']/1000:.0f}K
431
+ - Prototype: ${results['berkus_scores']['prototype']/1000:.0f}K
432
+ - Quality Team: ${results['berkus_scores']['quality_team']/1000:.0f}K
433
+ - Strategic Relationships: ${results['berkus_scores']['strategic_relationships']/1000:.0f}K
434
+ - Product Rollout: ${results['berkus_scores']['product_rollout']/1000:.0f}K
435
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
436
 
437
+ # 맀좜 기반 평가 μΆ”κ°€ (맀좜이 μžˆλŠ” 경우)
438
+ if use_revenue and results['arr'] > 0:
439
+ if language == "ko":
440
+ valuation_text += f"""
441
+ ## πŸ’° 맀좜 기반 평가
442
+ - **ARR**: ${results['arr']/1000000:.2f}M
443
+ - **적용 λ©€ν‹°ν”Œ**: {results['multiple']:.1f}x
444
+ - **LTV/CAC**: {results['ltv_cac_ratio']:.1f}x
445
+ - **Payback**: {results['payback']:.1f}κ°œμ›”
446
+ """
447
+ else:
448
+ valuation_text += f"""
449
+ ## πŸ’° Revenue-based Valuation
450
+ - **ARR**: ${results['arr']/1000000:.2f}M
451
+ - **Multiple**: {results['multiple']:.1f}x
452
+ - **LTV/CAC**: {results['ltv_cac_ratio']:.1f}x
453
+ - **Payback**: {results['payback']:.1f} months
454
+ """
455
 
456
+ # 재무 건전성
457
+ if language == "ko":
458
+ valuation_text += f"""
459
+ ## πŸƒ {t['financial_health']}
460
+ - **ν˜„κΈˆ λŸ°μ›¨μ΄**: {results['runway']:.1f}κ°œμ›”
461
+ - **μ›”κ°„ 번레이트**: ${burn_rate}K
462
+ """
463
+ else:
464
+ valuation_text += f"""
465
+ ## πŸƒ {t['financial_health']}
466
+ - **Cash Runway**: {results['runway']:.1f} months
467
+ - **Monthly Burn Rate**: ${burn_rate}K
468
+ """
469
 
470
+ # 차트 생성
471
+ comparison_chart = calculator.create_valuation_comparison_chart(results, language)
472
+ scorecard_chart = calculator.create_scorecard_radar_chart(results['scorecard_adjustments'], language)
473
+
474
+ # 상세 ν…Œμ΄λΈ”
475
+ if language == "ko":
476
+ methods_df = pd.DataFrame({
477
+ "평가 방법": ["λ²„ν¬μŠ€ 방법", "맀좜 λ©€ν‹°ν”Œ", "μŠ€μ½”μ–΄μΉ΄λ“œ μ‘°μ •", "μ΅œμ’… 평가"],
478
+ "평가앑": [
479
+ f"${results['berkus_valuation']/1000000:.2f}M",
480
+ f"${results['base_valuation']/1000000:.2f}M" if results['valuation_method'] == 'revenue_multiple' else "N/A",
481
+ f"{results['scorecard_multiplier']:.2f}x",
482
+ f"${results['final_valuation']/1000000:.2f}M"
483
+ ]
484
+ })
485
+ else:
486
+ methods_df = pd.DataFrame({
487
+ "Method": ["Berkus Method", "Revenue Multiple", "Scorecard Adjustment", "Final Valuation"],
488
+ "Value": [
489
+ f"${results['berkus_valuation']/1000000:.2f}M",
490
+ f"${results['base_valuation']/1000000:.2f}M" if results['valuation_method'] == 'revenue_multiple' else "N/A",
491
+ f"{results['scorecard_multiplier']:.2f}x",
492
+ f"${results['final_valuation']/1000000:.2f}M"
493
+ ]
494
+ })
495
 
496
+ return valuation_text, comparison_chart, scorecard_chart, methods_df
497
 
498
  # Gradio UI
499
+ with gr.Blocks(title="Startup Valuation Calculator", theme=gr.themes.Soft()) as demo:
500
+ # μ–Έμ–΄ 선택
501
+ language = gr.Radio(
502
+ choices=[("ν•œκ΅­μ–΄", "ko"), ("English", "en")],
503
+ value="ko",
504
+ label="Language / μ–Έμ–΄",
505
+ type="value"
506
+ )
507
 
508
+ gr.Markdown("""
509
+ # πŸ¦„ μŠ€νƒ€νŠΈμ—… κ°€μΉ˜ν‰κ°€ μžλ™ν™” μ‹œμŠ€ν…œ v3.0
510
+ ### λ²„ν¬μŠ€ 방법과 μŠ€μ½”μ–΄μΉ΄λ“œ 방법을 ν¬ν•¨ν•œ μ’…ν•© 평가
511
  """)
512
 
513
+ with gr.Tab("κΈ°λ³Έ 정보 / Basic Info"):
514
  with gr.Row():
515
+ company_name = gr.Textbox(label="νšŒμ‚¬λͺ… / Company Name", value="우리 μŠ€νƒ€νŠΈμ—…")
516
+ founded_year = gr.Slider(2015, 2024, value=2022, step=1, label="섀립연도 / Founded Year")
517
 
518
  with gr.Row():
519
  industry = gr.Dropdown(
520
  choices=list(calculator.industry_multiples.keys()),
521
  value="SaaS - B2B",
522
+ label="μ‚°μ—… λΆ„λ₯˜ / Industry"
523
  )
524
  stage = gr.Radio(
525
  choices=["MVP/베타", "초기 맀좜", "μ„±μž₯ 단계", "μˆ˜μ΅μ„± 확보"],
526
  value="초기 맀좜",
527
+ label="사업 단계 / Stage"
528
  )
529
 
530
  revenue_type = gr.Radio(
531
  choices=["κ΅¬λ…ν˜• (SaaS)", "κ±°λž˜μˆ˜μˆ˜λ£Œν˜•", "μΌνšŒμ„± 판맀"],
532
  value="κ΅¬λ…ν˜• (SaaS)",
533
+ label="수읡 λͺ¨λΈ / Revenue Model"
534
  )
535
 
536
+ with gr.Tab("λ²„ν¬μŠ€ 평가 / Berkus Method"):
537
+ gr.Markdown("### πŸ’‘ 아이디어 검증 / Idea Validation")
538
  with gr.Row():
539
+ idea_validation = gr.Slider(0, 100, value=70, step=10,
540
+ label="아이디어 검증 μˆ˜μ€€ / Idea Validation Level (%)")
541
+ market_research = gr.Slider(0, 10, value=5, step=1,
542
+ label="μ‹œμž₯ 쑰사 깊이 / Market Research Depth (1-10)")
543
 
544
+ gr.Markdown("### πŸ”§ ν”„λ‘œν† νƒ€μž… / Prototype")
545
+ prototype_stage = gr.Radio(
546
+ choices=["μ—†μŒ", "컨셉/λͺ©μ—…", "μž‘λ™ ν”„λ‘œν† νƒ€μž…", "베타 버전", "μΆœμ‹œ 버전"],
547
+ value="베타 버전",
548
+ label="ν”„λ‘œν† νƒ€μž… 단계 / Prototype Stage"
549
+ )
 
 
 
 
 
 
550
 
551
+ gr.Markdown("### πŸ‘₯ νŒ€ μ—­λŸ‰ / Team Quality")
552
  with gr.Row():
553
+ team_experience = gr.Slider(0, 5, value=3, step=1,
554
+ label="νŒ€ 평균 κ²½λ ₯(λ…„) / Average Experience (years)")
555
+ domain_expertise = gr.Slider(0, 5, value=3, step=1,
556
+ label="도메인 μ „λ¬Έμ„± / Domain Expertise (1-5)")
557
+ startup_experience = gr.Slider(0, 5, value=2, step=1,
558
+ label="μŠ€νƒ€νŠΈμ—… κ²½ν—˜ / Startup Experience (1-5)")
 
 
 
 
 
 
 
 
 
 
559
 
560
+ gr.Markdown("### 🀝 μ „λž΅μ  관계 / Strategic Relationships")
561
+ with gr.Row():
562
+ partnerships = gr.Number(label="μ „λž΅μ  νŒŒνŠΈλ„ˆμ‹­ 수 / Strategic Partnerships", value=2)
563
+ advisors = gr.Number(label="κ³ λ¬Έ/λ©˜ν†  수 / Advisors/Mentors", value=3)
564
+ pilot_customers = gr.Number(label="파일럿 고객 수 / Pilot Customers", value=5)
565
 
566
+ gr.Markdown("### πŸš€ μ œν’ˆ μΆœμ‹œ / Product Rollout")
567
  with gr.Row():
568
+ sales_started = gr.Checkbox(label="맀좜 λ°œμƒ μ‹œμž‘ / Sales Started", value=True)
569
+ customer_validation = gr.Slider(0, 10, value=5, step=1,
570
+ label="고객 검증 μˆ˜μ€€ / Customer Validation (1-10)")
571
+ launch_readiness = gr.Slider(0, 100, value=80, step=10,
572
+ label="μΆœμ‹œ 쀀비도 / Launch Readiness (%)")
573
+
574
+ with gr.Tab("μŠ€μ½”μ–΄μΉ΄λ“œ 평가 / Scorecard"):
575
+ gr.Markdown("### 각 μš”μ†Œλ₯Ό 동일 μŠ€ν…Œμ΄μ§€ 평균 λŒ€λΉ„ 평가 (50 = 평균)")
576
 
577
+ team_strength = gr.Slider(0, 100, value=60, step=5,
578
+ label="νŒ€ μ—­λŸ‰ / Team Strength")
579
+ market_opportunity = gr.Slider(0, 100, value=70, step=5,
580
+ label="μ‹œμž₯ 기회 / Market Opportunity")
581
+ product_stage = gr.Slider(0, 100, value=65, step=5,
582
+ label="μ œν’ˆ 완성도 / Product Maturity")
583
+ competitive_advantage = gr.Slider(0, 100, value=55, step=5,
584
+ label="경쟁 μš°μœ„ / Competitive Advantage")
585
+ marketing_channels = gr.Slider(0, 100, value=50, step=5,
586
+ label="λ§ˆμΌ€νŒ…/판맀 / Marketing & Sales")
587
+ funding_efficiency = gr.Slider(0, 100, value=60, step=5,
588
+ label="자금 νš¨μœ¨μ„± / Funding Efficiency")
589
+ other_factors = gr.Slider(0, 100, value=50, step=5,
590
+ label="기타 μš”μ†Œ / Other Factors")
591
+
592
+ with gr.Tab("맀좜 정보 / Revenue (Optional)"):
593
+ gr.Markdown("### πŸ’° 맀좜이 μžˆλŠ” 경우만 μž…λ ₯ / Only if you have revenue")
594
  with gr.Row():
595
+ monthly_revenue = gr.Number(label="μ›” 맀좜 / Monthly Revenue ($K)", value=0)
596
+ growth_rate = gr.Slider(0, 300, value=0, step=10,
597
+ label="μ—°κ°„ μ„±μž₯λ₯  / Annual Growth Rate (%)")
598
+
 
599
  with gr.Row():
600
+ arpu = gr.Number(label="ARPU ($)", value=0)
601
+ gross_margin = gr.Slider(0, 100, value=0, step=5,
602
+ label="맀좜총이읡λ₯  / Gross Margin (%)")
603
 
604
  with gr.Row():
605
+ retention_rate = gr.Slider(0, 100, value=0, step=5,
606
+ label="고객 μœ μ§€μœ¨ / Retention Rate (%)")
607
+ monthly_churn = gr.Slider(0, 20, value=0, step=0.5,
608
+ label="μ›” μ΄νƒˆλ₯  / Monthly Churn (%)")
609
 
 
610
  with gr.Row():
611
+ new_customers = gr.Number(label="μ›” μ‹ κ·œ 고객 / New Customers/Month", value=0)
612
+ monthly_marketing = gr.Number(label="μ›” λ§ˆμΌ€νŒ… λΉ„μš© / Marketing Cost ($K)", value=0)
613
+ monthly_sales = gr.Number(label="μ›” μ˜μ—… λΉ„μš© / Sales Cost ($K)", value=0)
614
 
615
+ with gr.Tab("재무 ν˜„ν™© / Financials"):
616
+ gr.Markdown("### πŸ’Έ ν˜„κΈˆ 상황 / Cash Position ($K)")
617
  with gr.Row():
618
+ cash_balance = gr.Number(label="ν˜„κΈˆ μž”κ³  / Cash Balance ($K)", value=1000)
619
+ burn_rate = gr.Number(label="μ›” 번레이트 / Monthly Burn Rate ($K)", value=80)
620
 
621
  # 평가 μ‹€ν–‰ λ²„νŠΌ
622
+ evaluate_btn = gr.Button("πŸ” κ°€μΉ˜ν‰κ°€ μ‹€ν–‰ / Run Valuation", variant="primary", size="lg")
623
 
624
  # κ²°κ³Ό 좜λ ₯
625
  with gr.Row():
626
  with gr.Column(scale=2):
627
+ valuation_output = gr.Markdown(label="평가 κ²°κ³Ό / Results")
628
  with gr.Column(scale=1):
629
+ methods_table = gr.DataFrame(label="평가 방법 비ꡐ / Method Comparison")
630
 
631
  with gr.Row():
632
+ comparison_chart = gr.Plot(label="평가 방법 비ꡐ / Valuation Comparison")
633
+ scorecard_chart = gr.Plot(label="μŠ€μ½”μ–΄μΉ΄λ“œ 뢄석 / Scorecard Analysis")
634
 
635
  # 이벀트 μ—°κ²°
636
  evaluate_btn.click(
637
  process_valuation,
638
  inputs=[
639
+ language,
640
  company_name, founded_year, industry, stage, revenue_type,
641
  monthly_revenue, growth_rate, arpu, gross_margin, monthly_churn,
642
  retention_rate, new_customers, monthly_marketing, monthly_sales,
643
  cash_balance, burn_rate,
644
+ idea_validation, market_research, prototype_stage, team_experience,
645
+ domain_expertise, startup_experience, partnerships, advisors,
646
+ pilot_customers, sales_started, customer_validation, launch_readiness,
647
+ team_strength, market_opportunity, product_stage, competitive_advantage,
648
+ marketing_channels, funding_efficiency, other_factors
649
  ],
650
+ outputs=[valuation_output, comparison_chart, scorecard_chart, methods_table]
651
  )
652
 
653
+ # μ˜ˆμ‹œ 데이터
654
+ gr.Markdown("### πŸ“ μ˜ˆμ‹œ 데이터 / Example Data")
655
  with gr.Row():
656
+ gr.Button("초기 μŠ€νƒ€νŠΈμ—… / Early Startup").click(
657
  lambda: [
658
+ "ko", "ν…Œν¬ μŠ€νƒ€νŠΈμ—…", 2023, "AI/λ”₯ν…Œν¬", "MVP/베타", "κ΅¬λ…ν˜• (SaaS)",
659
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 500, 50,
660
+ 80, 7, "베타 버전", 2, 4, 1, 1, 2, 3, False, 0, 70,
661
+ 70, 65, 55, 60, 45, 50, 50
 
 
 
 
 
662
  ],
663
  outputs=[
664
+ language, company_name, founded_year, industry, stage, revenue_type,
665
  monthly_revenue, growth_rate, arpu, gross_margin, monthly_churn,
666
  retention_rate, new_customers, monthly_marketing, monthly_sales,
667
  cash_balance, burn_rate,
668
+ idea_validation, market_research, prototype_stage, team_experience,
669
+ domain_expertise, startup_experience, partnerships, advisors,
670
+ pilot_customers, sales_started, customer_validation, launch_readiness,
671
+ team_strength, market_opportunity, product_stage, competitive_advantage,
672
+ marketing_channels, funding_efficiency, other_factors
673
  ]
674
  )
675
 
676
+ gr.Button("μ„±μž₯ 단계 / Growth Stage").click(
677
  lambda: [
678
+ "en", "SaaS Corp", 2021, "SaaS - B2B", "μ„±μž₯ 단계", "κ΅¬λ…ν˜• (SaaS)",
679
+ 100, 150, 200, 75, 2, 90, 40, 30, 20, 2000, 120,
680
+ 90, 9, "μΆœμ‹œ 버전", 5, 5, 3, 5, 5, 20, True, 8, 95,
681
+ 85, 80, 75, 70, 65, 75, 60
 
 
 
 
 
682
  ],
683
  outputs=[
684
+ language, company_name, founded_year, industry, stage, revenue_type,
685
  monthly_revenue, growth_rate, arpu, gross_margin, monthly_churn,
686
  retention_rate, new_customers, monthly_marketing, monthly_sales,
687
  cash_balance, burn_rate,
688
+ idea_validation, market_research, prototype_stage, team_experience,
689
+ domain_expertise, startup_experience, partnerships, advisors,
690
+ pilot_customers, sales_started, customer_validation, launch_readiness,
691
+ team_strength, market_opportunity, product_stage, competitive_advantage,
692
+ marketing_channels, funding_efficiency, other_factors
693
  ]
694
  )
695