openfree commited on
Commit
b378e61
·
verified ·
1 Parent(s): 08e687f

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +386 -0
app.py ADDED
@@ -0,0 +1,386 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import pandas as pd
3
+ import numpy as np
4
+ from datetime import datetime
5
+ import plotly.graph_objects as go
6
+
7
+ class StartupValuationCalculator:
8
+ def __init__(self):
9
+ # 업종별 벤치마크 멀티플 (EV/ARR)
10
+ self.industry_multiples = {
11
+ "SaaS - B2B": {"low": 3, "mid": 6, "high": 10},
12
+ "SaaS - B2C": {"low": 2, "mid": 4, "high": 7},
13
+ "마켓플레이스": {"low": 2, "mid": 5, "high": 8},
14
+ "이커머스": {"low": 1, "mid": 2.5, "high": 4},
15
+ "핀테크": {"low": 3, "mid": 5, "high": 8},
16
+ "헬스케어": {"low": 4, "mid": 7, "high": 12},
17
+ "AI/딥테크": {"low": 5, "mid": 8, "high": 15},
18
+ "기타": {"low": 2, "mid": 4, "high": 6}
19
+ }
20
+
21
+ # 성장률 조정 계수
22
+ self.growth_adjustments = {
23
+ "0-20%": 0.7,
24
+ "20-50%": 0.9,
25
+ "50-100%": 1.1,
26
+ "100-200%": 1.3,
27
+ "200%+": 1.5
28
+ }
29
+
30
+ # 단위경제 점수 가중치
31
+ self.unit_economics_weights = {
32
+ "ltv_cac_ratio": 0.3,
33
+ "gross_margin": 0.3,
34
+ "retention": 0.2,
35
+ "payback": 0.2
36
+ }
37
+
38
+ def calculate_arr(self, monthly_revenue, revenue_type):
39
+ """월 매출을 연간 반복 매출(ARR)로 변환"""
40
+ if revenue_type == "구독형 (SaaS)":
41
+ return monthly_revenue * 12
42
+ elif revenue_type == "거래수수료형":
43
+ return monthly_revenue * 12 * 0.8 # 거래수수료는 변동성 고려
44
+ else:
45
+ return monthly_revenue * 12 * 0.6 # 일회성 매출은 더 할인
46
+
47
+ def calculate_ltv(self, arpu, gross_margin, monthly_churn):
48
+ """LTV 계산"""
49
+ if monthly_churn == 0:
50
+ monthly_churn = 0.01 # 최소 이탈률
51
+ return arpu * (gross_margin / 100) / monthly_churn
52
+
53
+ def calculate_cac(self, monthly_marketing, monthly_sales, new_customers):
54
+ """CAC 계산"""
55
+ if new_customers == 0:
56
+ return 0
57
+ return (monthly_marketing + monthly_sales) / new_customers
58
+
59
+ def calculate_payback(self, cac, arpu, gross_margin):
60
+ """Payback Period 계산 (개월)"""
61
+ if arpu * (gross_margin / 100) == 0:
62
+ return 999
63
+ return cac / (arpu * (gross_margin / 100))
64
+
65
+ def get_unit_economics_score(self, ltv_cac_ratio, gross_margin, retention_rate, payback_months):
66
+ """단위경제 점수 계산 (0-100)"""
67
+ scores = {
68
+ "ltv_cac_ratio": min(100, (ltv_cac_ratio / 3) * 100) if ltv_cac_ratio > 0 else 0,
69
+ "gross_margin": min(100, gross_margin * 1.25),
70
+ "retention": retention_rate,
71
+ "payback": max(0, 100 - (payback_months / 24) * 100) if payback_months < 999 else 0
72
+ }
73
+
74
+ total_score = sum(scores[key] * self.unit_economics_weights[key] for key in scores)
75
+ return total_score
76
+
77
+ def get_growth_category(self, growth_rate):
78
+ """성장률 카테고리 결정"""
79
+ if growth_rate < 20:
80
+ return "0-20%"
81
+ elif growth_rate < 50:
82
+ return "20-50%"
83
+ elif growth_rate < 100:
84
+ return "50-100%"
85
+ elif growth_rate < 200:
86
+ return "100-200%"
87
+ else:
88
+ return "200%+"
89
+
90
+ def calculate_valuation(self, data):
91
+ """종합 가치평가 계산"""
92
+ # ARR 계산
93
+ arr = self.calculate_arr(data["monthly_revenue"], data["revenue_type"])
94
+
95
+ # 단위경제 계산
96
+ ltv = self.calculate_ltv(data["arpu"], data["gross_margin"], data["monthly_churn"])
97
+ cac = self.calculate_cac(data["monthly_marketing"], data["monthly_sales"], data["new_customers"])
98
+ ltv_cac_ratio = ltv / cac if cac > 0 else 0
99
+ payback = self.calculate_payback(cac, data["arpu"], data["gross_margin"])
100
+
101
+ # 단위경제 점수
102
+ ue_score = self.get_unit_economics_score(
103
+ ltv_cac_ratio, data["gross_margin"], data["retention_rate"], payback
104
+ )
105
+
106
+ # 기본 멀티플 선택
107
+ multiples = self.industry_multiples[data["industry"]]
108
+ if ue_score >= 80:
109
+ base_multiple = multiples["high"]
110
+ elif ue_score >= 50:
111
+ base_multiple = multiples["mid"]
112
+ else:
113
+ base_multiple = multiples["low"]
114
+
115
+ # 성장률 조정
116
+ growth_adj = self.growth_adjustments[self.get_growth_category(data["growth_rate"])]
117
+ adjusted_multiple = base_multiple * growth_adj
118
+
119
+ # 스테이지 조정
120
+ stage_adj = {
121
+ "MVP/베타": 0.7,
122
+ "초기 매출": 0.85,
123
+ "성장 단계": 1.0,
124
+ "수익성 확보": 1.2
125
+ }
126
+ final_multiple = adjusted_multiple * stage_adj[data["stage"]]
127
+
128
+ # 최종 가치평가
129
+ valuation = arr * final_multiple
130
+
131
+ # 런웨이 계산
132
+ runway = data["cash_balance"] / data["burn_rate"] if data["burn_rate"] > 0 else 999
133
+
134
+ return {
135
+ "valuation": valuation,
136
+ "arr": arr,
137
+ "multiple": final_multiple,
138
+ "ltv": ltv,
139
+ "cac": cac,
140
+ "ltv_cac_ratio": ltv_cac_ratio,
141
+ "payback": payback,
142
+ "ue_score": ue_score,
143
+ "runway": runway
144
+ }
145
+
146
+ def create_comparison_chart(self, valuation, industry, arr):
147
+ """동종업계 비교 차트 생성"""
148
+ multiples = self.industry_multiples[industry]
149
+
150
+ fig = go.Figure()
151
+
152
+ # 업계 범위
153
+ low_val = arr * multiples["low"]
154
+ mid_val = arr * multiples["mid"]
155
+ high_val = arr * multiples["high"]
156
+
157
+ # 막대 그래프
158
+ fig.add_trace(go.Bar(
159
+ x=["하위 25%", "중간값", "상위 25%", "현재 기업"],
160
+ y=[low_val, mid_val, high_val, valuation],
161
+ text=[f"${low_val/1000000:.1f}M", f"${mid_val/1000000:.1f}M",
162
+ f"${high_val/1000000:.1f}M", f"${valuation/1000000:.1f}M"],
163
+ textposition="outside",
164
+ marker_color=["lightgray", "gray", "darkgray", "blue"]
165
+ ))
166
+
167
+ fig.update_layout(
168
+ title=f"{industry} 업계 가치평가 비교",
169
+ yaxis_title="기업가치 (USD)",
170
+ showlegend=False,
171
+ height=400
172
+ )
173
+
174
+ return fig
175
+
176
+ def create_ui():
177
+ calculator = StartupValuationCalculator()
178
+
179
+ def process_valuation(
180
+ company_name, founded_year, industry, stage, revenue_type,
181
+ monthly_revenue, growth_rate, arpu, gross_margin, monthly_churn,
182
+ retention_rate, new_customers, monthly_marketing, monthly_sales,
183
+ cash_balance, burn_rate
184
+ ):
185
+ # 입력값 검증
186
+ if monthly_revenue <= 0:
187
+ return "월 매출을 입력해주세요.", None, None
188
+
189
+ # 데이터 준비
190
+ data = {
191
+ "company_name": company_name,
192
+ "founded_year": founded_year,
193
+ "industry": industry,
194
+ "stage": stage,
195
+ "revenue_type": revenue_type,
196
+ "monthly_revenue": monthly_revenue * 1000, # 천 달러 단위로 입력받음
197
+ "growth_rate": growth_rate,
198
+ "arpu": arpu,
199
+ "gross_margin": gross_margin,
200
+ "monthly_churn": monthly_churn / 100,
201
+ "retention_rate": retention_rate,
202
+ "new_customers": new_customers,
203
+ "monthly_marketing": monthly_marketing * 1000,
204
+ "monthly_sales": monthly_sales * 1000,
205
+ "cash_balance": cash_balance * 1000,
206
+ "burn_rate": burn_rate * 1000
207
+ }
208
+
209
+ # 가치평가 계산
210
+ results = calculator.calculate_valuation(data)
211
+
212
+ # 결과 포맷팅
213
+ valuation_text = f"""
214
+ # 🚀 {company_name} 가치평가 결과
215
+
216
+ ## 📊 주요 지표
217
+ - **기업가치**: ${results['valuation']/1000000:.1f}M (₩{results['valuation']/1000000*1300:.0f}억)
218
+ - **ARR**: ${results['arr']/1000000:.1f}M
219
+ - **적용 멀티플**: {results['multiple']:.1f}x
220
+
221
+ ## 💰 단위경제
222
+ - **LTV**: ${results['ltv']:.0f}
223
+ - **CAC**: ${results['cac']:.0f}
224
+ - **LTV/CAC**: {results['ltv_cac_ratio']:.1f}x
225
+ - **Payback Period**: {results['payback']:.1f}개월
226
+ - **단위경제 점수**: {results['ue_score']:.0f}/100
227
+
228
+ ## 🏃 재무 건전성
229
+ - **현금 런웨이**: {results['runway']:.1f}개월
230
+ - **월간 번레이트**: ${burn_rate}K
231
+
232
+ ## 💡 평가 인사이트
233
+ """
234
+ # 인사이트 추가
235
+ if results['ltv_cac_ratio'] < 1:
236
+ valuation_text += "- ⚠️ LTV/CAC 비율이 1 미만입니다. 마케팅 효율성 개선이 필요합니다.\n"
237
+ elif results['ltv_cac_ratio'] > 3:
238
+ valuation_text += "- ✅ 우수한 LTV/CAC 비율을 보이고 있습니다.\n"
239
+
240
+ if results['runway'] < 12:
241
+ valuation_text += "- ⚠️ 런웨이가 12개월 미만입니다. 추가 자금조달을 고려하세요.\n"
242
+
243
+ if gross_margin < 60:
244
+ valuation_text += "- 📈 매출총이익률 개선 여지가 있습니다. (업계 평균: 70-80%)\n"
245
+
246
+ # 비교 차트 생성
247
+ comparison_chart = calculator.create_comparison_chart(
248
+ results['valuation'], industry, results['arr']
249
+ )
250
+
251
+ # 상세 분석 테이블
252
+ metrics_df = pd.DataFrame({
253
+ "지표": ["월 매출", "연 성장률", "매출총이익률", "월 이탈률", "고객 유지율"],
254
+ "현재 값": [f"${monthly_revenue}K", f"{growth_rate}%", f"{gross_margin}%",
255
+ f"{monthly_churn}%", f"{retention_rate}%"],
256
+ "업계 평균": ["N/A", "50-100%", "70-80%", "2-5%", "80-90%"]
257
+ })
258
+
259
+ return valuation_text, comparison_chart, metrics_df
260
+
261
+ # Gradio UI
262
+ with gr.Blocks(title="스타트업 가치평가 계산기", theme=gr.themes.Soft()) as demo:
263
+ gr.Markdown("""
264
+ # 🦄 스타트업 가치평가 자동화 시스템
265
+
266
+ 간단한 정보 입력만으로 귀사의 예상 기업가치를 산출하고 동종업계와 비교해드립니다.
267
+ """)
268
+
269
+ with gr.Tab("기본 정보"):
270
+ with gr.Row():
271
+ company_name = gr.Textbox(label="회사명", value="우리 스타트업")
272
+ founded_year = gr.Slider(2015, 2024, value=2022, step=1, label="설립연도")
273
+
274
+ with gr.Row():
275
+ industry = gr.Dropdown(
276
+ choices=list(calculator.industry_multiples.keys()),
277
+ value="SaaS - B2B",
278
+ label="산업 분류"
279
+ )
280
+ stage = gr.Radio(
281
+ choices=["MVP/베타", "초기 매출", "성장 단계", "수익성 확보"],
282
+ value="초기 매출",
283
+ label="사업 단계"
284
+ )
285
+
286
+ revenue_type = gr.Radio(
287
+ choices=["구독형 (SaaS)", "거래수수료형", "일회성 판매"],
288
+ value="구독형 (SaaS)",
289
+ label="수익 모델"
290
+ )
291
+
292
+ with gr.Tab("매출 및 성장"):
293
+ gr.Markdown("### 💰 매출 정보 (단위: 천 달러)")
294
+ with gr.Row():
295
+ monthly_revenue = gr.Number(label="월 매출 ($K)", value=50)
296
+ growth_rate = gr.Slider(0, 300, value=100, step=10,
297
+ label="연간 성장률 (%)")
298
+
299
+ with gr.Row():
300
+ arpu = gr.Number(label="고객당 평균 매출 (ARPU) ($)", value=100)
301
+ gross_margin = gr.Slider(0, 100, value=70, step=5,
302
+ label="매출총이익률 (%)")
303
+
304
+ with gr.Tab("고객 및 마케팅"):
305
+ gr.Markdown("### 👥 고객 지표")
306
+ with gr.Row():
307
+ retention_rate = gr.Slider(0, 100, value=85, step=5,
308
+ label="월간 고객 유지율 (%)")
309
+ monthly_churn = gr.Slider(0, 20, value=3, step=0.5,
310
+ label="월 이탈률 (%)")
311
+
312
+ gr.Markdown("### 📢 마케팅 효율성")
313
+ with gr.Row():
314
+ new_customers = gr.Number(label="월 신규 고객 수", value=50)
315
+ monthly_marketing = gr.Number(label="월 마케팅 비용 ($K)", value=20)
316
+ monthly_sales = gr.Number(label="월 영업 비용 ($K)", value=15)
317
+
318
+ with gr.Tab("재무 현황"):
319
+ gr.Markdown("### 💸 현금 상황 (단위: 천 달러)")
320
+ with gr.Row():
321
+ cash_balance = gr.Number(label="현금 잔고 ($K)", value=1000)
322
+ burn_rate = gr.Number(label="월 번레이트 ($K)", value=80)
323
+
324
+ # 평가 실행 버튼
325
+ evaluate_btn = gr.Button("🔍 가치평가 실행", variant="primary", size="lg")
326
+
327
+ # 결과 출력
328
+ with gr.Row():
329
+ with gr.Column(scale=2):
330
+ valuation_output = gr.Markdown(label="평가 결과")
331
+ with gr.Column(scale=1):
332
+ metrics_table = gr.DataFrame(label="주요 지표 비교")
333
+
334
+ comparison_chart = gr.Plot(label="동종업계 비교")
335
+
336
+ # 이벤트 연결
337
+ evaluate_btn.click(
338
+ process_valuation,
339
+ inputs=[
340
+ company_name, founded_year, industry, stage, revenue_type,
341
+ monthly_revenue, growth_rate, arpu, gross_margin, monthly_churn,
342
+ retention_rate, new_customers, monthly_marketing, monthly_sales,
343
+ cash_balance, burn_rate
344
+ ],
345
+ outputs=[valuation_output, comparison_chart, metrics_table]
346
+ )
347
+
348
+ # 예시 데이터 버튼들
349
+ gr.Markdown("### 📝 예시 데이터로 테스트하기")
350
+ with gr.Row():
351
+ gr.Button("SaaS 스타트업 예시").click(
352
+ lambda: [
353
+ "테크 스타트업", 2021, "SaaS - B2B", "성장 단계", "구독형 (SaaS)",
354
+ 100, 150, 200, 75, 2,
355
+ 90, 40, 30, 20,
356
+ 2000, 120
357
+ ],
358
+ outputs=[
359
+ company_name, founded_year, industry, stage, revenue_type,
360
+ monthly_revenue, growth_rate, arpu, gross_margin, monthly_churn,
361
+ retention_rate, new_customers, monthly_marketing, monthly_sales,
362
+ cash_balance, burn_rate
363
+ ]
364
+ )
365
+
366
+ gr.Button("이커머스 예시").click(
367
+ lambda: [
368
+ "온라인 쇼핑몰", 2022, "이커머스", "초기 매출", "일회성 판매",
369
+ 80, 80, 50, 40, 5,
370
+ 70, 100, 25, 10,
371
+ 500, 70
372
+ ],
373
+ outputs=[
374
+ company_name, founded_year, industry, stage, revenue_type,
375
+ monthly_revenue, growth_rate, arpu, gross_margin, monthly_churn,
376
+ retention_rate, new_customers, monthly_marketing, monthly_sales,
377
+ cash_balance, burn_rate
378
+ ]
379
+ )
380
+
381
+ return demo
382
+
383
+ # 실행
384
+ if __name__ == "__main__":
385
+ demo = create_ui()
386
+ demo.launch(share=True)