jeongkee's picture
Upload app.py
5e1f972 verified
# ============================================
# ๐Ÿ“˜ Vision LLM Agentic AI ํ”„๋กœ์ ํŠธ ๊ฒฌ์  ์‹œ์Šคํ…œ
# - ๋ณด์ˆ˜์  MM ์‚ฐ์ • / ์˜คํ”ˆ์†Œ์Šค ์ค‘์‹ฌ
# - Phase๋ณ„ ์ƒ์„ธ ์‚ฌ์ด์ง•
# - PDF/Excel ๋‹ค์šด๋กœ๋“œ ๊ธฐ๋Šฅ
# - Hugging Face Spaces ์ตœ์ ํ™”
# ============================================
import sys
import os
import math
import time
import warnings
warnings.filterwarnings("ignore")
# Hugging Face Spaces๋Š” requirements.txt๋กœ ํŒจํ‚ค์ง€ ๊ด€๋ฆฌ
import gradio as gr
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from fpdf import FPDF
import json
from datetime import datetime
print("โœ… ํŒจํ‚ค์ง€ ๋กœ๋“œ ์™„๋ฃŒ!\n" + "="*70)
# ============================================
# ๐Ÿ’ฐ ๊ธˆ์•ก ์‚ฐ์ถœ ๊ธฐ์ค€ (๋ช…ํ™•ํžˆ ์ •์˜)
# ============================================
CURRENCY_INFO = {
"base": "KRW",
"unit": "์–ต์›",
"display_factor": 100_000_000,
}
# ์ธ๊ฑด๋น„ (์›ํ™” ๊ธฐ์ค€)
LABOR_RATES = {
"Senior_Engineer": 18_000_000,
"Mid_Engineer": 15_000_000,
"Junior_Engineer": 12_000_000,
"Architect": 20_000_000,
"Average": 15_000_000,
}
LABOR_COST_PER_MM = LABOR_RATES["Average"]
# GPU ๋‹จ๊ฐ€ (์›ํ™” ๊ธฐ์ค€)
GPU_COSTS_KRW = {
'A100_80GB': 4_000_000_000,
'H100_80GB': 6_000_000_000,
'A100_40GB': 2_500_000_000,
'L40S': 1_500_000_000,
}
GPU_COST = {k: v / CURRENCY_INFO['display_factor'] for k, v in GPU_COSTS_KRW.items()}
# ์„œ๋ฒ„ ๋‹จ๊ฐ€
SERVER_COSTS_KRW = {
'CPU_High_End': 50_000_000,
'CPU_Mid_Range': 30_000_000,
'RAM_256GB': 10_000_000,
'RAM_512GB': 20_000_000,
}
STORAGE_COST_PER_TB = 2_000_000
OSS_SETUP_COST_PER_MM = 3_000_000
EXCHANGE_RATE_INFO = {
"USD_to_KRW": 1330,
"note": "GPU ๊ฐ€๊ฒฉ์€ ๋ฏธ๊ตญ ์‹œ์žฅ๊ฐ€๋ฅผ ํ™˜์œจ ์ ์šฉํ•˜์—ฌ ์‚ฐ์ •"
}
# ๋ณด์ˆ˜์  ์•ˆ์ „๊ณ„์ˆ˜
SAFETY_FACTOR = 1.4
GPU_EFFICIENCY = 0.65
PARALLEL_EFFICIENCY = 0.70
OSS_LABOR_MULTIPLIER = 1.5
# ============================================
# Value Chain Phase ์ •์˜
# ============================================
VALUE_CHAIN_PHASES = {
"Phase1_DataPrep": {
"name": "Phase 1: ๋ฐ์ดํ„ฐ ์ค€๋น„ ๋ฐ ๊ธฐ๋ฐ˜ ๊ตฌ์ถ•",
"description": "๋ฌธ์„œ ์ˆ˜์ง‘, ์ „์ฒ˜๋ฆฌ, ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ, ์˜จํ†จ๋กœ์ง€ ์„ค๊ณ„",
"base_mm_ratio": 0.39,
"roles": ["Data Engineer", "Data Architect", "Ontology Engineer"],
"oss_stack": [
"PyMuPDF (๋ฌธ์„œ ํŒŒ์‹ฑ)",
"OpenCV (์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ)",
"LayoutParser (ํ‘œ ์ธ์‹)",
"spaCy (NLP)",
"PostgreSQL (๋ฉ”ํƒ€DB)",
"Neo4j (๊ทธ๋ž˜ํ”„DB)",
"Apache Airflow (์›Œํฌํ”Œ๋กœ)",
"DVC (๋ฐ์ดํ„ฐ ๋ฒ„์ „๊ด€๋ฆฌ)"
]
},
"Phase2_Training": {
"name": "Phase 2: ๋ชจ๋ธ ํ•™์Šต ๋ฐ ์ตœ์ ํ™”",
"description": "Vision LLM Fine-Tuning, Q-LoRA, Validation",
"base_mm_ratio": 0.23,
"roles": ["ML Engineer", "AI Architect", "Research Engineer"],
"oss_stack": [
"PyTorch (๋”ฅ๋Ÿฌ๋‹)",
"PEFT/LoRA (ํšจ์œจ์  ํ•™์Šต)",
"Hugging Face Transformers",
"Albumentations (์ฆ๊ฐ•)",
"InternVL 3.5 (Vision LLM)",
"Unsloth (ํ•™์Šต ๊ฐ€์†)",
"MLflow (์‹คํ—˜ ์ถ”์ )",
"Weights & Biases (๋ชจ๋‹ˆํ„ฐ๋ง)"
]
},
"Phase3_AgenticDev": {
"name": "Phase 3: Agentic AI ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ",
"description": "Agent ์„ค๊ณ„, Workflow, Tool ์—ฐ๋™, RAG",
"base_mm_ratio": 0.17,
"roles": ["AI Architect", "Backend Engineer", "ML Engineer"],
"oss_stack": [
"LangGraph (Agent ํ”„๋ ˆ์ž„์›Œํฌ)",
"LangChain (LLM ์ฒด์ธ)",
"CrewAI (Multi-Agent)",
"Qdrant (Vector DB)",
"FAISS (๋ฒกํ„ฐ ๊ฒ€์ƒ‰)",
"Redis (Memory)",
"FastAPI (API)",
"n8n (์›Œํฌํ”Œ๋กœ ์ž๋™ํ™”)"
]
},
"Phase4_Deployment": {
"name": "Phase 4: ๋ฐฐํฌยท์šด์˜ ๋ฐ ์ง€์† ๊ฐœ์„ ",
"description": "Docker/K8s ๋ฐฐํฌ, ๋ชจ๋‹ˆํ„ฐ๋ง, ์žฌํ•™์Šต ์ž๋™ํ™”",
"base_mm_ratio": 0.21,
"roles": ["DevOps Engineer", "MLOps Engineer", "SRE"],
"oss_stack": [
"Docker (์ปจํ…Œ์ด๋„ˆ)",
"Kubernetes (์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜)",
"Prometheus (๋ฉ”ํŠธ๋ฆญ)",
"Grafana (์‹œ๊ฐํ™”)",
"ELK Stack (๋กœ๊ทธ)",
"ArgoCD (GitOps)",
"Kubeflow (ML ํŒŒ์ดํ”„๋ผ์ธ)",
"GitLab CI/CD"
]
}
}
# ============================================
# Function Points
# ============================================
FP_COEFFICIENTS = {
"A-01": 0.00003, "A-02": 0.000015, "A-03": 0.00004, "A-04": 0.00008,
"A-05": 0.00006, "A-06": 0.00005, "A-07": 0.000055,
"B-01": 0.00004, "B-02": 0.00003, "B-03": 0.00005, "B-04": 0.00004,
"C-01": 0.00005, "C-02": 0.00007, "C-03": 0.00004, "C-04": 0.00003,
"D-01": 0.00009, "D-02": 0.00006, "D-03": 0.00015, "D-04": 0.00006, "D-05": 0.00004,
"F-01": 0.00005, "F-02": 0.00008, "F-03": 0.00007, "F-04": 0.00009, "F-05": 0.00007,
"G-01": 0.00008, "G-02": 0.00006, "G-03": 0.00004, "G-04": 0.00007,
"H-01": 0.00004, "H-02": 0.00005, "H-03": 0.00008, "H-04": 0.00003,
}
FP_TO_PHASE = {
"Phase1_DataPrep": ["A-01", "A-02", "A-03", "A-04", "A-05", "A-06", "A-07",
"B-01", "B-02", "B-03", "B-04", "C-01", "C-02", "C-03", "C-04"],
"Phase2_Training": ["D-01", "D-02", "D-03", "D-04", "D-05"],
"Phase3_AgenticDev": ["F-01", "F-02", "F-03", "F-04", "F-05"],
"Phase4_Deployment": ["G-01", "G-02", "G-03", "G-04", "H-01", "H-02", "H-03", "H-04"]
}
# ============================================
# ํ•ต์‹ฌ ๊ณ„์‚ฐ ํ•จ์ˆ˜
# ============================================
def calculate_phase_mm(phase_id, N_pages, doc_complexity, language_mix,
table_ratio, image_quality, model_size,
training_epochs, agent_complexity):
"""Phase๋ณ„ MM ๊ณ„์‚ฐ"""
fps = FP_TO_PHASE.get(phase_id, [])
total_mm = 0.0
fp_details = []
if N_pages <= 10000:
scale_factor = 1.0
elif N_pages <= 100000:
scale_factor = 4.5
else:
scale_factor = 12.0
for fp in fps:
coeff = FP_COEFFICIENTS.get(fp, 0.00005)
base_mm = coeff * N_pages * scale_factor
if phase_id == "Phase1_DataPrep":
weight = (doc_complexity * language_mix *
(1 + table_ratio) * image_quality)
if fp in ["A-04", "A-05"]:
weight *= (1 + table_ratio*0.5)
elif phase_id == "Phase2_Training":
weight = model_size * (1 + training_epochs/10) * image_quality
if fp == "D-03":
weight *= 1.8
elif phase_id == "Phase3_AgenticDev":
weight = agent_complexity * doc_complexity
else:
weight = (doc_complexity + agent_complexity) / 2
mm = base_mm * weight * OSS_LABOR_MULTIPLIER * SAFETY_FACTOR
total_mm += mm
fp_details.append({
"FP": fp,
"Base_MM": round(base_mm, 3),
"Weight": round(weight, 2),
"Final_MM": round(mm, 2)
})
return total_mm, fp_details
def calculate_hardware(phase_id, N_pages, model_size, training_epochs,
deployment_type, sla_level):
"""Phase๋ณ„ HW ์‚ฌ์ด์ง•"""
hw = {}
if phase_id == "Phase1_DataPrep":
base_gpu = max(2, math.ceil(N_pages / 5000 * SAFETY_FACTOR))
hw["Preprocess_GPU"] = min(base_gpu, 8)
hw["GPU_Type"] = "L40S"
hw["CPU_Cores"] = 16 * hw["Preprocess_GPU"]
hw["RAM_GB"] = 64 * hw["Preprocess_GPU"]
hw["Storage_TB"] = round(max(10, N_pages * 0.5 / 1000000), 1)
elif phase_id == "Phase2_Training":
base_gpu = max(4, math.ceil(N_pages * training_epochs / 3000 * model_size * SAFETY_FACTOR))
hw["Training_GPU"] = base_gpu
hw["GPU_Type"] = "A100_80GB"
hw["CPU_Cores"] = 32 * hw["Training_GPU"]
hw["RAM_GB"] = 128 * hw["Training_GPU"]
hw["Storage_TB"] = round(max(50, N_pages * training_epochs * 2.0 / 1000000), 1)
elif phase_id == "Phase3_AgenticDev":
hw["Dev_GPU"] = max(2, math.ceil(model_size * 2))
hw["GPU_Type"] = "A100_40GB"
hw["VectorDB_Instances"] = max(2, math.ceil(N_pages / 100000))
hw["CPU_Cores"] = 32
hw["RAM_GB"] = 256
hw["Storage_TB"] = round(max(20, N_pages * 1.0 / 1000000), 1)
else:
qps_estimate = N_pages / 10000
base_gpu = max(2, math.ceil(qps_estimate * sla_level * SAFETY_FACTOR))
hw["Inference_GPU"] = base_gpu
hw["GPU_Type"] = "A100_80GB"
hw["K8s_Nodes"] = max(3, math.ceil(base_gpu / 2))
hw["CPU_Cores"] = 64
hw["RAM_GB"] = 512
hw["Storage_TB"] = round(max(100, N_pages * 2.0 / 1000000), 1)
return hw
def estimate_cost(hw, mm, phase_id):
"""๋น„์šฉ ์‚ฐ์ •"""
labor_cost_krw = mm * LABOR_COST_PER_MM
labor_cost = labor_cost_krw / CURRENCY_INFO['display_factor']
gpu_cost = 0
if "Training_GPU" in hw:
gpu_type = hw.get("GPU_Type", "A100_80GB")
gpu_cost = hw["Training_GPU"] * GPU_COST.get(gpu_type, 40.0)
elif "Preprocess_GPU" in hw:
gpu_type = hw.get("GPU_Type", "L40S")
gpu_cost = hw["Preprocess_GPU"] * GPU_COST.get(gpu_type, 15.0)
elif "Inference_GPU" in hw:
gpu_type = hw.get("GPU_Type", "A100_80GB")
gpu_cost = hw["Inference_GPU"] * GPU_COST.get(gpu_type, 40.0)
elif "Dev_GPU" in hw:
gpu_type = hw.get("GPU_Type", "A100_40GB")
gpu_cost = hw["Dev_GPU"] * GPU_COST.get(gpu_type, 25.0)
server_cost_krw = 0
if hw.get("CPU_Cores", 0) >= 32:
server_cost_krw += SERVER_COSTS_KRW['CPU_High_End']
elif hw.get("CPU_Cores", 0) >= 16:
server_cost_krw += SERVER_COSTS_KRW['CPU_Mid_Range']
if hw.get("RAM_GB", 0) >= 512:
server_cost_krw += SERVER_COSTS_KRW['RAM_512GB']
elif hw.get("RAM_GB", 0) >= 256:
server_cost_krw += SERVER_COSTS_KRW['RAM_256GB']
server_cost = server_cost_krw / CURRENCY_INFO['display_factor']
storage_cost_krw = 0
if "Storage_TB" in hw:
storage_cost_krw = hw["Storage_TB"] * STORAGE_COST_PER_TB
storage_cost = storage_cost_krw / CURRENCY_INFO['display_factor']
oss_setup_cost_krw = mm * OSS_SETUP_COST_PER_MM
oss_setup_cost = oss_setup_cost_krw / CURRENCY_INFO['display_factor']
hw_total = gpu_cost + server_cost + storage_cost
infra_cost = hw_total * 0.3
total_cost = labor_cost + gpu_cost + server_cost + storage_cost + oss_setup_cost + infra_cost
return {
"Labor": round(labor_cost, 1),
"GPU": round(gpu_cost, 1),
"Server": round(server_cost, 1),
"Storage": round(storage_cost, 1),
"OSS_Setup": round(oss_setup_cost, 1),
"Infrastructure": round(infra_cost, 1),
"Total": round(total_cost, 1),
}
# ============================================
# ๋ฉ”์ธ ๊ฒฌ์  ํ•จ์ˆ˜
# ============================================
def run_estimation(N_pages, doc_complexity, language_mix, table_ratio,
image_quality, model_size, training_epochs,
agent_complexity, deployment_type, sla_level,
security_level):
"""์ „์ฒด ๊ฒฌ์  ์‹คํ–‰"""
try:
if N_pages < 1000:
return ("โŒ ๋ฌธ์„œ ์ˆ˜๋Š” ์ตœ์†Œ 1,000์žฅ ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.",) + (None,) * 7
results = {}
total_mm = 0
phase_ids = ["Phase1_DataPrep", "Phase2_Training", "Phase3_AgenticDev", "Phase4_Deployment"]
for phase_id in phase_ids:
phase_info = VALUE_CHAIN_PHASES[phase_id]
mm, fp_details = calculate_phase_mm(
phase_id, N_pages, doc_complexity, language_mix,
table_ratio/100, image_quality, model_size,
training_epochs, agent_complexity
)
if phase_id == "Phase4_Deployment":
mm *= (sla_level * security_level)
mm *= deployment_type
total_mm += mm
hw = calculate_hardware(
phase_id, N_pages, model_size, training_epochs,
deployment_type, sla_level
)
cost = estimate_cost(hw, mm, phase_id)
results[phase_id] = {
"name": phase_info["name"],
"mm": round(mm, 1),
"hw": hw,
"cost": cost,
"fp_details": fp_details,
"oss_stack": phase_info["oss_stack"]
}
duration_months = (
results["Phase1_DataPrep"]["mm"] / 8 +
max(results["Phase2_Training"]["mm"] / 10,
results["Phase3_AgenticDev"]["mm"] / 6) * PARALLEL_EFFICIENCY +
results["Phase4_Deployment"]["mm"] / 8
)
duration_months = math.ceil(duration_months * 1.2)
summary = generate_summary(results, total_mm, duration_months, N_pages)
phase_chart = create_phase_chart(results)
cost_chart = create_cost_breakdown(results)
timeline_chart = create_timeline(results, duration_months)
hw_table = create_hw_table(results)
oss_table = create_oss_table(results)
pdf_path = generate_pdf(results, total_mm, duration_months, N_pages)
excel_path = generate_excel(results, total_mm, duration_months, N_pages)
return summary, phase_chart, cost_chart, timeline_chart, hw_table, oss_table, pdf_path, excel_path
except Exception as e:
import traceback
error_detail = traceback.format_exc()
error_msg = f"โŒ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}\n\n์ƒ์„ธ:\n{error_detail}"
return (error_msg,) + (None,) * 7
def generate_summary(results, total_mm, duration_months, N_pages):
"""์š”์•ฝ ์ƒ์„ฑ"""
total_cost = sum(r["cost"]["Total"] for r in results.values())
total_labor = sum(r["cost"]["Labor"] for r in results.values())
total_gpu = sum(r["cost"]["GPU"] for r in results.values())
total_oss = sum(r["cost"]["OSS_Setup"] for r in results.values())
summary = f"""
# ๐Ÿ“Š Vision LLM Agentic AI ํ”„๋กœ์ ํŠธ ๊ฒฌ์ ์„œ
## ๐Ÿ’ฐ ๊ธˆ์•ก ์‚ฐ์ถœ ๊ธฐ์ค€
- **๊ธฐ์ค€ ํ†ตํ™”**: ์›ํ™” (KRW)
- **ํ‘œ์‹œ ๋‹จ์œ„**: ์–ต์› (1์–ต = 100,000,000์›)
- **ํ™˜์œจ ์ฐธ์กฐ**: USD 1,330์› (2024๋…„ 11์›” ๊ธฐ์ค€)
### ๋‹จ๊ฐ€ ์ •๋ณด
- **์ธ๊ฑด๋น„**: 1,500๋งŒ์›/MM (Man-Month)
- **GPU ๋‹จ๊ฐ€**: A100 80GB 40์–ต์›, H100 80GB 60์–ต์›
- **OSS ๊ตฌ์ถ•๋น„**: 300๋งŒ์›/MM
- **์Šคํ† ๋ฆฌ์ง€**: 200๋งŒ์›/TB
## ํ”„๋กœ์ ํŠธ ๊ฐœ์š”
- **์ฒ˜๋ฆฌ ๋Œ€์ƒ**: {N_pages:,}์žฅ
- **์ด ์†Œ์š” ์ธ๋ ฅ**: {total_mm:.1f} MM
- **์˜ˆ์ƒ ๊ธฐ๊ฐ„**: {duration_months}๊ฐœ์›”
- **์ด ์˜ˆ์ƒ ๋น„์šฉ**: {total_cost:.1f}์–ต์› ({int(total_cost * 100_000_000):,}์›)
## Phase๋ณ„ ์š”์•ฝ
### {results["Phase1_DataPrep"]["name"]}
- ์ธ๋ ฅ: {results["Phase1_DataPrep"]["mm"]:.1f} MM
- ๋น„์šฉ: {results["Phase1_DataPrep"]["cost"]["Total"]:.1f}์–ต์›
- ์ฃผ์š” HW: {results["Phase1_DataPrep"]["hw"].get("GPU_Type", "N/A")} ร— {results["Phase1_DataPrep"]["hw"].get("Preprocess_GPU", 0)}๋Œ€
### {results["Phase2_Training"]["name"]}
- ์ธ๋ ฅ: {results["Phase2_Training"]["mm"]:.1f} MM
- ๋น„์šฉ: {results["Phase2_Training"]["cost"]["Total"]:.1f}์–ต์›
- ์ฃผ์š” HW: {results["Phase2_Training"]["hw"].get("GPU_Type", "N/A")} ร— {results["Phase2_Training"]["hw"].get("Training_GPU", 0)}๋Œ€
### {results["Phase3_AgenticDev"]["name"]}
- ์ธ๋ ฅ: {results["Phase3_AgenticDev"]["mm"]:.1f} MM
- ๋น„์šฉ: {results["Phase3_AgenticDev"]["cost"]["Total"]:.1f}์–ต์›
- ์ฃผ์š” HW: {results["Phase3_AgenticDev"]["hw"].get("GPU_Type", "N/A")} ร— {results["Phase3_AgenticDev"]["hw"].get("Dev_GPU", 0)}๋Œ€
### {results["Phase4_Deployment"]["name"]}
- ์ธ๋ ฅ: {results["Phase4_Deployment"]["mm"]:.1f} MM
- ๋น„์šฉ: {results["Phase4_Deployment"]["cost"]["Total"]:.1f}์–ต์›
- ์ฃผ์š” HW: {results["Phase4_Deployment"]["hw"].get("GPU_Type", "N/A")} ร— {results["Phase4_Deployment"]["hw"].get("Inference_GPU", 0)}๋Œ€
## ๋น„์šฉ ๊ตฌ์„ฑ
- **์ธ๊ฑด๋น„**: {total_labor:.1f}์–ต์› ({total_labor/total_cost*100:.1f}%)
- **GPU**: {total_gpu:.1f}์–ต์› ({total_gpu/total_cost*100:.1f}%)
- **OSS ๊ตฌ์ถ•**: {total_oss:.1f}์–ต์› ({total_oss/total_cost*100:.1f}%)
- **๊ธฐํƒ€ ์ธํ”„๋ผ**: {sum(r["cost"]["Infrastructure"] for r in results.values()):.1f}์–ต์›
---
๐Ÿ’ก **์ฐธ๊ณ ์‚ฌํ•ญ**
- ๋ณธ ๊ฒฌ์ ์€ ๋ณด์ˆ˜์  ๊ด€์ ์—์„œ ์‚ฐ์ • (์•ˆ์ „๊ณ„์ˆ˜ 1.4)
- ์˜คํ”ˆ์†Œ์Šค ๊ธฐ๋ฐ˜์œผ๋กœ ์ƒ์šฉ ๋Œ€๋น„ 1.5๋ฐฐ ์ธ๋ ฅ ๋ฐ˜์˜
- ์‹ค์ œ ํ”„๋กœ์ ํŠธ ์ง„ํ–‰ ์‹œ ยฑ15% ์กฐ์ • ๊ฐ€๋Šฅ
"""
return summary
# ============================================
# PDF ์ƒ์„ฑ ํ•จ์ˆ˜
# ============================================
def generate_pdf(results, total_mm, duration_months, N_pages):
"""PDF ๊ฒฌ์ ์„œ ์ƒ์„ฑ"""
try:
pdf = FPDF(orientation='P', unit='mm', format='A4')
pdf.add_page()
pdf.set_margins(25, 15, 25)
pdf.set_auto_page_break(auto=True, margin=15)
# ๊ธฐ๋ณธ ํฐํŠธ ์‚ฌ์šฉ (ํ•œ๊ธ€ ์ง€์› ์ œํ•œ์ )
pdf.set_font('Arial', '', 10)
# ์ œ๋ชฉ
pdf.set_font('Arial', 'B', 16)
pdf.cell(0, 10, 'Vision LLM Agentic AI Estimate', ln=1, align='C')
pdf.ln(3)
pdf.set_font('Arial', '', 9)
pdf.cell(0, 5, f'Date: {datetime.now().strftime("%Y-%m-%d")}', ln=1, align='R')
pdf.ln(5)
# 1. ๊ธˆ์•ก ๊ธฐ์ค€
pdf.set_font('Arial', 'B', 11)
pdf.cell(0, 7, '1. Cost Basis', ln=1)
pdf.set_font('Arial', '', 9)
pdf.cell(0, 5, 'Currency: KRW (Korean Won)', ln=1)
pdf.cell(0, 5, 'Unit: 100M KRW', ln=1)
pdf.cell(0, 5, 'Labor: 15M KRW/MM', ln=1)
pdf.cell(0, 5, 'GPU A100 80GB: 4B KRW', ln=1)
pdf.cell(0, 5, 'OSS Setup: 3M KRW/MM', ln=1)
pdf.ln(3)
# 2. ๊ฐœ์š”
pdf.set_font('Arial', 'B', 11)
pdf.cell(0, 7, '2. Project Overview', ln=1)
pdf.set_font('Arial', '', 9)
total_cost = sum(r["cost"]["Total"] for r in results.values())
pdf.cell(0, 5, f'Documents: {N_pages:,} pages', ln=1)
pdf.cell(0, 5, f'Manpower: {total_mm:.1f} MM', ln=1)
pdf.cell(0, 5, f'Duration: {duration_months} months', ln=1)
pdf.cell(0, 5, f'Total Cost: {total_cost:.1f}B KRW', ln=1)
pdf.ln(3)
# 3. Phase๋ณ„ ์ƒ์„ธ
pdf.set_font('Arial', 'B', 11)
pdf.cell(0, 7, '3. Phase Details', ln=1)
pdf.ln(2)
for i, (phase_id, data) in enumerate(results.items(), 1):
pdf.set_font('Arial', 'B', 10)
phase_name = f"Phase {i}"
pdf.cell(0, 6, phase_name, ln=1)
pdf.set_font('Arial', '', 9)
pdf.cell(0, 4, f' MM: {data["mm"]:.1f}', ln=1)
pdf.cell(0, 4, f' Cost: {data["cost"]["Total"]:.1f}B KRW', ln=1)
pdf.cell(0, 4, f' Labor: {data["cost"]["Labor"]:.1f}B', ln=1)
pdf.cell(0, 4, f' GPU: {data["cost"]["GPU"]:.1f}B', ln=1)
pdf.ln(1)
pdf.ln(3)
# 4. HW ์š”์•ฝ
pdf.add_page()
pdf.set_font('Arial', 'B', 11)
pdf.cell(0, 7, '4. Hardware Summary', ln=1)
pdf.ln(2)
for phase_id, data in results.items():
hw = data["hw"]
pdf.set_font('Arial', '', 9)
if "Training_GPU" in hw:
pdf.cell(0, 4, f'Training: {hw["GPU_Type"]} x{hw["Training_GPU"]}', ln=1)
elif "Preprocess_GPU" in hw:
pdf.cell(0, 4, f'Preprocess: {hw["GPU_Type"]} x{hw["Preprocess_GPU"]}', ln=1)
elif "Inference_GPU" in hw:
pdf.cell(0, 4, f'Inference: {hw["GPU_Type"]} x{hw["Inference_GPU"]}', ln=1)
elif "Dev_GPU" in hw:
pdf.cell(0, 4, f'Dev: {hw["GPU_Type"]} x{hw["Dev_GPU"]}', ln=1)
pdf.cell(0, 4, f' CPU: {hw.get("CPU_Cores", 0)} cores', ln=1)
pdf.cell(0, 4, f' RAM: {hw.get("RAM_GB", 0)} GB', ln=1)
pdf.cell(0, 4, f' Storage: {hw.get("Storage_TB", 0)} TB', ln=1)
pdf.ln(1)
timestamp = int(time.time())
pdf_path = f'/tmp/Estimate_{timestamp}.pdf'
pdf.output(pdf_path)
return pdf_path
except Exception as e:
print(f"PDF generation error: {e}")
return None
# ============================================
# Excel ์ƒ์„ฑ ํ•จ์ˆ˜
# ============================================
def generate_excel(results, total_mm, duration_months, N_pages):
"""Excel ๊ฒฌ์ ์„œ ์ƒ์„ฑ"""
try:
timestamp = int(time.time())
excel_path = f'/tmp/Estimate_{timestamp}.xlsx'
with pd.ExcelWriter(excel_path, engine='xlsxwriter') as writer:
# 1. ์š”์•ฝ
total_cost = sum(r["cost"]["Total"] for r in results.values())
summary_data = {
'Item': ['Documents', 'Manpower', 'Duration', 'Total Cost (100M KRW)', 'Total Cost (KRW)'],
'Value': [
f'{N_pages:,} pages',
f'{total_mm:.1f} MM',
f'{duration_months} months',
f'{total_cost:.1f}',
f'{int(total_cost * 100_000_000):,}'
]
}
pd.DataFrame(summary_data).to_excel(writer, sheet_name='Summary', index=False)
# 2. Phase๋ณ„ ์ƒ์„ธ
phase_data = []
for phase_id, data in results.items():
phase_data.append({
'Phase': data["name"].split(":")[1].strip(),
'MM': round(data["mm"], 1),
'Labor (100M)': round(data["cost"]["Labor"], 1),
'GPU (100M)': round(data["cost"]["GPU"], 1),
'OSS Setup (100M)': round(data["cost"]["OSS_Setup"], 1),
'Total (100M)': round(data["cost"]["Total"], 1)
})
pd.DataFrame(phase_data).to_excel(writer, sheet_name='Phase Details', index=False)
# 3. HW
hw_data = []
for phase_id, data in results.items():
hw = data["hw"]
hw_row = {'Phase': data["name"].split(":")[1].strip()}
hw_row.update(hw)
hw_data.append(hw_row)
pd.DataFrame(hw_data).to_excel(writer, sheet_name='Hardware', index=False)
# 4. OSS
oss_data = []
for phase_id, data in results.items():
for oss in data["oss_stack"]:
oss_data.append({
'Phase': data["name"].split(":")[1].strip(),
'Open Source': oss
})
pd.DataFrame(oss_data).to_excel(writer, sheet_name='Open Source', index=False)
return excel_path
except Exception as e:
print(f"Excel generation error: {e}")
return None
# ============================================
# ์‹œ๊ฐํ™” ํ•จ์ˆ˜
# ============================================
def create_phase_chart(results):
"""Phase๋ณ„ ๋น„๊ต ์ฐจํŠธ"""
names = [results[p]["name"].split(":")[1].strip() for p in results.keys()]
mms = [results[p]["mm"] for p in results.keys()]
costs = [results[p]["cost"]["Total"] for p in results.keys()]
fig = make_subplots(
rows=1, cols=2,
subplot_titles=('Phase Manpower (MM)', 'Phase Cost (100M KRW)'),
specs=[[{'type':'bar'}, {'type':'bar'}]]
)
fig.add_trace(
go.Bar(x=names, y=mms, text=[f"{m:.1f}" for m in mms],
textposition='auto', marker_color='#3498db'),
row=1, col=1
)
fig.add_trace(
go.Bar(x=names, y=costs, text=[f"{c:.1f}" for c in costs],
textposition='auto', marker_color='#e74c3c'),
row=1, col=2
)
fig.update_layout(height=400, showlegend=False, title_text="Phase Comparison", title_x=0.5)
return fig
def create_cost_breakdown(results):
"""๋น„์šฉ ๊ตฌ์„ฑ ์ฐจํŠธ"""
categories = []
values = []
for phase_id, data in results.items():
name = data["name"].split(":")[1].strip()
categories.append(f"{name}\nLabor")
values.append(data["cost"]["Labor"])
categories.append(f"{name}\nGPU")
values.append(data["cost"]["GPU"])
fig = go.Figure(data=[go.Pie(
labels=categories,
values=values,
hole=.4,
textinfo='label+percent',
textposition='outside'
)])
fig.update_layout(title_text="Cost Breakdown", height=500)
return fig
def create_timeline(results, duration_months):
"""ํƒ€์ž„๋ผ์ธ ์ฐจํŠธ"""
phase_durations = {}
start = 0
p1_dur = math.ceil(results["Phase1_DataPrep"]["mm"] / 8)
phase_durations["Phase1_DataPrep"] = (start, p1_dur)
start += p1_dur
p2_dur = math.ceil(results["Phase2_Training"]["mm"] / 10)
p3_dur = math.ceil(results["Phase3_AgenticDev"]["mm"] / 6)
parallel = max(p2_dur, p3_dur)
phase_durations["Phase2_Training"] = (start, p2_dur)
phase_durations["Phase3_AgenticDev"] = (start, p3_dur)
start += parallel
p4_dur = math.ceil(results["Phase4_Deployment"]["mm"] / 8)
phase_durations["Phase4_Deployment"] = (start, p4_dur)
fig = go.Figure()
colors = ['#3498db', '#e74c3c', '#2ecc71', '#f39c12']
for i, (phase_id, (s, d)) in enumerate(phase_durations.items()):
name = results[phase_id]["name"].split(":")[1].strip()
fig.add_trace(go.Bar(
y=[name], x=[d], base=s, orientation='h',
marker=dict(color=colors[i]), text=f"{d}mo",
textposition='inside', name=name
))
fig.update_layout(
title="Project Timeline", xaxis_title="Months", yaxis_title="Phase",
barmode='overlay', height=400, showlegend=False
)
return fig
def create_hw_table(results):
"""HW ํ…Œ์ด๋ธ”"""
rows = []
for phase_id, data in results.items():
row = {"Phase": data["name"].split(":")[1].strip()}
row.update(data["hw"])
rows.append(row)
return pd.DataFrame(rows)
def create_oss_table(results):
"""OSS ํ…Œ์ด๋ธ”"""
rows = []
for phase_id, data in results.items():
name = data["name"].split(":")[1].strip()
for i, oss in enumerate(data["oss_stack"]):
rows.append({
"Phase": name if i == 0 else "",
"No": i+1,
"Open Source": oss
})
return pd.DataFrame(rows)
# ============================================
# Gradio UI
# ============================================
EXAMPLES = [
[10000, 0.7, 0.8, 20, 0.8, 0.8, 3, 0.8, 1.0, 1.0, 1.0],
[50000, 1.0, 1.0, 40, 1.0, 1.0, 3, 1.0, 1.0, 1.0, 1.0],
[100000, 1.3, 1.3, 60, 1.0, 1.0, 5, 1.3, 1.0, 1.2, 1.3],
[500000, 1.6, 1.5, 80, 1.3, 1.3, 5, 1.6, 1.4, 1.5, 1.6],
]
with gr.Blocks(title="Vision LLM Agentic AI ๊ฒฌ์ ", theme=gr.themes.Soft()) as demo:
gr.Markdown("""
# ๐Ÿ“˜ Vision LLM ๊ธฐ๋ฐ˜ Agentic AI ํ”„๋กœ์ ํŠธ ๊ฒฌ์  ์‹œ์Šคํ…œ
**๋ณด์ˆ˜์  ๊ฒฌ์  / ์˜คํ”ˆ์†Œ์Šค ์ค‘์‹ฌ / Phase๋ณ„ ์ƒ์„ธ ๋ถ„์„ / PDFยทExcel ๋‹ค์šด๋กœ๋“œ**
๐Ÿ’ฐ **๊ธˆ์•ก ๊ธฐ์ค€**: ์›ํ™”(KRW), ๋‹จ์œ„: ์–ต์› | ํ™˜์œจ: USD 1,330์›
""")
with gr.Tab("๐Ÿ“‹ ํŒŒ๋ผ๋ฏธํ„ฐ ์ž…๋ ฅ"):
gr.Markdown("## 1๏ธโƒฃ ํ”„๋กœ์ ํŠธ ๊ทœ๋ชจ")
N_pages = gr.Number(label="๐Ÿ“„ ๋ฌธ์„œ ํŽ˜์ด์ง€ ์ˆ˜", value=10000)
gr.Markdown("## 2๏ธโƒฃ ๋ฌธ์„œ ํŠน์„ฑ")
with gr.Row():
doc_complexity = gr.Slider(0.7, 1.6, value=1.0, step=0.1,
label="๐Ÿ“Š ๋ฌธ์„œ ๋ณต์žก๋„", info="0.7=๋‹จ์ˆœ, 1.0=๋ณดํ†ต, 1.3=๋ณต์žก, 1.6=๋งค์šฐ๋ณต์žก")
language_mix = gr.Slider(0.8, 1.5, value=1.0, step=0.1,
label="๐ŸŒ ์–ธ์–ด ๋ณต์žก๋„", info="0.8=๋‹จ์ผ, 1.0=์ด์ค‘, 1.3=๋‹ค๊ตญ์–ด")
with gr.Row():
table_ratio = gr.Slider(0, 100, value=40, step=5,
label="๐Ÿ“‹ ํ‘œ ๋น„์œจ (%)")
image_quality = gr.Slider(0.8, 1.6, value=1.0, step=0.1,
label="๐Ÿ–ผ๏ธ ์ด๋ฏธ์ง€ ํ’ˆ์งˆ", info="0.8=๊ณ , 1.0=์ค‘, 1.3=์ €")
gr.Markdown("## 3๏ธโƒฃ ๋ชจ๋ธ ๋ฐ ํ•™์Šต")
with gr.Row():
model_size = gr.Slider(0.8, 1.6, value=1.0, step=0.1,
label="๐Ÿค– ๋ชจ๋ธ ํฌ๊ธฐ", info="0.8=์†Œํ˜•, 1.0=์ค‘ํ˜•, 1.3=๋Œ€ํ˜•")
training_epochs = gr.Slider(1, 10, value=3, step=1,
label="๐Ÿ”„ ํ•™์Šต Epoch")
gr.Markdown("## 4๏ธโƒฃ Agentic AI ๋ฐ ๋ฐฐํฌ")
with gr.Row():
agent_complexity = gr.Slider(0.8, 1.6, value=1.0, step=0.1,
label="๐ŸŽฏ Agent ๋ณต์žก๋„", info="0.8=๊ธฐ๋ณธ, 1.0=ํ‘œ์ค€, 1.3=๊ณ ๊ธ‰")
deployment_type = gr.Slider(0.9, 1.4, value=1.0, step=0.1,
label="๐Ÿ—๏ธ ๋ฐฐํฌ ํ™˜๊ฒฝ", info="0.9=Cloud, 1.0=On-Prem, 1.4=Air-Gap")
gr.Markdown("## 5๏ธโƒฃ ์šด์˜ ์š”๊ตฌ์‚ฌํ•ญ")
with gr.Row():
sla_level = gr.Slider(1.0, 1.5, value=1.0, step=0.1,
label="๐Ÿ“ˆ SLA ๋“ฑ๊ธ‰", info="1.0=ํ‘œ์ค€, 1.2=๋†’์Œ, 1.5=๋ฏธ์…˜ํฌ๋ฆฌํ‹ฐ์ปฌ")
security_level = gr.Slider(1.0, 1.6, value=1.0, step=0.1,
label="๐Ÿ” ๋ณด์•ˆ ๋“ฑ๊ธ‰", info="1.0=์ผ๋ฐ˜, 1.3=๊ฐ•ํ™”, 1.6=์ตœ๊ณ ")
estimate_btn = gr.Button("๐Ÿš€ ๊ฒฌ์  ์‚ฐ์ •", variant="primary", size="lg")
gr.Markdown("### ๐Ÿ“Œ ์˜ˆ์ œ ์‹œ๋‚˜๋ฆฌ์˜ค")
gr.Examples(
examples=EXAMPLES,
inputs=[N_pages, doc_complexity, language_mix, table_ratio,
image_quality, model_size, training_epochs, agent_complexity,
deployment_type, sla_level, security_level],
)
with gr.Tab("๐Ÿ“Š ๊ฒฌ์  ๊ฒฐ๊ณผ"):
summary_text = gr.Markdown()
gr.Markdown("### ๐Ÿ“ฅ ๊ฒฌ์ ์„œ ๋‹ค์šด๋กœ๋“œ")
with gr.Row():
pdf_download = gr.File(label="๐Ÿ“„ PDF")
excel_download = gr.File(label="๐Ÿ“Š Excel")
with gr.Row():
phase_chart = gr.Plot()
cost_chart = gr.Plot()
timeline_chart = gr.Plot()
gr.Markdown("### ๐Ÿ’ป ํ•˜๋“œ์›จ์–ด")
hw_table = gr.Dataframe()
gr.Markdown("### ๐Ÿ”ง ์˜คํ”ˆ์†Œ์Šค")
oss_table = gr.Dataframe()
with gr.Tab("โ„น๏ธ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ€์ด๋“œ"):
gr.Markdown("""
# ๐Ÿ“– ํŒŒ๋ผ๋ฏธํ„ฐ ์ƒ์„ธ ์„ค๋ช…
## ๐Ÿ“Š ๋ฌธ์„œ ๋ณต์žก๋„
- **0.7 (๋‹จ์ˆœ)**: ํ…์ŠคํŠธ ์œ„์ฃผ, ํ‘œ ์—†์Œ
- **1.0 (๋ณดํ†ต)**: ํ…์ŠคํŠธ + ๋‹จ์ˆœ ํ‘œ
- **1.3 (๋ณต์žก)**: ํ…์ŠคํŠธ + ๋ณต์žกํ•œ ํ‘œ + ์ด๋ฏธ์ง€
- **1.6 (๋งค์šฐ๋ณต์žก)**: ๋‹ค๋‹จ ๋ ˆ์ด์•„์›ƒ + ์ˆ˜์‹ + ๋‹ค๊ตญ์–ด
## ๐ŸŒ ์–ธ์–ด ๋ณต์žก๋„
- **0.8 (๋‹จ์ผ)**: ํ•œ๊ตญ์–ด๋งŒ
- **1.0 (์ด์ค‘)**: ํ•œ๊ตญ์–ด + ์˜์–ด
- **1.3 (๋‹ค๊ตญ์–ด)**: ํ•œ/์˜/์ผ/์ค‘ ํ˜ผํ•ฉ
- **1.5 (ํŠน์ˆ˜)**: ๋‹ค๊ตญ์–ด + ํŠน์ˆ˜๋ฌธ์ž
## ๐Ÿ“‹ ํ‘œ ๋น„์œจ
- ์ „์ฒด ๋ฌธ์„œ ์ค‘ ํ‘œ๊ฐ€ ํฌํ•จ๋œ ๋น„์œจ (%)
- ํ‘œ ๊ตฌ์กฐ ์ธ์‹์€ ๊ฐ€์žฅ ๋ณต์žกํ•œ ์ž‘์—…
## ๐Ÿ–ผ๏ธ ์ด๋ฏธ์ง€ ํ’ˆ์งˆ
- **0.8 (๊ณ ํ’ˆ์งˆ)**: ์Šค์บ” 300dpi+
- **1.0 (๋ณดํ†ต)**: ์Šค์บ” 200dpi
- **1.3 (์ €ํ’ˆ์งˆ)**: ์Šค์บ” 150dpi
- **1.6 (๋งค์šฐ๋‚ฎ์Œ)**: ์‚ฌ์ง„์ดฌ์˜, ์™œ๊ณก
## ๐Ÿค– ๋ชจ๋ธ ํฌ๊ธฐ
- **0.8 (์†Œํ˜•)**: 2B~7B ํŒŒ๋ผ๋ฏธํ„ฐ
- **1.0 (์ค‘ํ˜•)**: 8B~14B
- **1.3 (๋Œ€ํ˜•)**: 20B~40B
- **1.6 (์ดˆ๋Œ€ํ˜•)**: 70B+
## ๐ŸŽฏ Agent ๋ณต์žก๋„
- **0.8 (๊ธฐ๋ณธ)**: ๋‹จ์ผ Agent, ๋‹จ์ˆœ RAG
- **1.0 (ํ‘œ์ค€)**: 2~3 Agent
- **1.3 (๊ณ ๊ธ‰)**: Multi-Agent, ๋ณต์žกํ•œ Tool
- **1.6 (์—”ํ„ฐํ”„๋ผ์ด์ฆˆ)**: Self-Learning
## ๐Ÿ—๏ธ ๋ฐฐํฌ ํ™˜๊ฒฝ
- **0.9 (Cloud)**: AWS/GCP/Azure
- **1.0 (On-Premise)**: ์ž์ฒด ์„œ๋ฒ„
- **1.4 (Air-Gap)**: ํ์‡„๋ง, ๊ณ ๋ณด์•ˆ
## ๐Ÿ“ˆ SLA ๋“ฑ๊ธ‰
- **1.0 (ํ‘œ์ค€)**: 99% ๊ฐ€์šฉ์„ฑ
- **1.2 (๋†’์Œ)**: 99.5% ๊ฐ€์šฉ์„ฑ
- **1.5 (๋ฏธ์…˜ํฌ๋ฆฌํ‹ฐ์ปฌ)**: 99.9% ๊ฐ€์šฉ์„ฑ
## ๐Ÿ” ๋ณด์•ˆ ๋“ฑ๊ธ‰
- **1.0 (์ผ๋ฐ˜)**: ๊ธฐ๋ณธ ์ธ์ฆ/์•”ํ˜ธํ™”
- **1.3 (๊ฐ•ํ™”)**: ๋‹ค์ค‘ ์ธ์ฆ, ๊ฐ์‚ฌ ๋กœ๊ทธ
- **1.6 (์ตœ๊ณ )**: Zero-Trust, ์™„์ „ ๊ฒฉ๋ฆฌ
---
## ๐Ÿ’ฐ ๊ธˆ์•ก ์‚ฐ์ถœ ๊ธฐ์ค€
### ํ†ตํ™” ๋ฐ ๋‹จ์œ„
- **๊ธฐ์ค€**: ์›ํ™” (KRW)
- **ํ‘œ์‹œ**: ์–ต์›
- **ํ™˜์œจ**: USD 1,330์›
### ์ธ๊ฑด๋น„
- **1 MM = 15,000,000์›** (1,500๋งŒ์›/์›”)
### GPU ๋‹จ๊ฐ€
- **A100 80GB: 40์–ต์›** (โ‰ˆ $30,000)
- **H100 80GB: 60์–ต์›** (โ‰ˆ $45,000)
### ๊ธฐํƒ€
- **OSS ๊ตฌ์ถ•: 300๋งŒ์›/MM**
- **์Šคํ† ๋ฆฌ์ง€: 200๋งŒ์›/TB**
""")
with gr.Tab("๐Ÿ’ฐ ๊ธˆ์•ก ์ƒ์„ธ"):
gr.Markdown(f"""
# ๐Ÿ’ฐ ๊ธˆ์•ก ์‚ฐ์ถœ ์ƒ์„ธ
## ์ธ๊ฑด๋น„ (์›ํ™”)
| ์ง๊ธ‰ | ์›” ๋‹จ๊ฐ€ | ์—ฐ๋ด‰ ํ™˜์‚ฐ |
|------|---------|----------|
| ์•„ํ‚คํ…ํŠธ | {LABOR_RATES['Architect']:,}์› | {LABOR_RATES['Architect']*12:,}์› |
| ์‹œ๋‹ˆ์–ด | {LABOR_RATES['Senior_Engineer']:,}์› | {LABOR_RATES['Senior_Engineer']*12:,}์› |
| ์ค‘๊ธ‰ | {LABOR_RATES['Mid_Engineer']:,}์› | {LABOR_RATES['Mid_Engineer']*12:,}์› |
| ์ฃผ๋‹ˆ์–ด | {LABOR_RATES['Junior_Engineer']:,}์› | {LABOR_RATES['Junior_Engineer']*12:,}์› |
| **ํ‰๊ท ** | **{LABOR_RATES['Average']:,}์›** | **{LABOR_RATES['Average']*12:,}์›** |
## GPU ๋‹จ๊ฐ€ (์›ํ™”)
| GPU | ๋‹จ๊ฐ€ (์›) | ๋‹จ๊ฐ€ (๋‹ฌ๋Ÿฌ) | ์šฉ๋„ |
|-----|-----------|------------|------|
| H100 80GB | {GPU_COSTS_KRW['H100_80GB']:,}์› | $45,000 | ๋Œ€๊ทœ๋ชจ ํ•™์Šต |
| A100 80GB | {GPU_COSTS_KRW['A100_80GB']:,}์› | $30,000 | ํ‘œ์ค€ ํ•™์Šต |
| A100 40GB | {GPU_COSTS_KRW['A100_40GB']:,}์› | $18,750 | ๊ฐœ๋ฐœ/ํ…Œ์ŠคํŠธ |
| L40S | {GPU_COSTS_KRW['L40S']:,}์› | $11,250 | ์ „์ฒ˜๋ฆฌ |
## ๊ธฐํƒ€ ๋น„์šฉ
| ํ•ญ๋ชฉ | ๋‹จ๊ฐ€ | ๋‹จ์œ„ |
|------|------|------|
| ์Šคํ† ๋ฆฌ์ง€ (NVMe) | {STORAGE_COST_PER_TB:,}์› | TB |
| OSS ๊ตฌ์ถ• | {OSS_SETUP_COST_PER_MM:,}์› | MM |
| ๊ณ ๊ธ‰ ์„œ๋ฒ„ | {SERVER_COSTS_KRW['CPU_High_End']:,}์› | ๋Œ€ |
| RAM 512GB | {SERVER_COSTS_KRW['RAM_512GB']:,}์› | ์„ธํŠธ |
## ๋น„์šฉ ์‚ฐ์ • ๊ณต์‹
```
Total = Labor + GPU + Server + Storage + OSS + Infrastructure
Labor = MM ร— 15,000,000์›
GPU = GPU_Count ร— GPU_Unit_Price
OSS = MM ร— 3,000,000์›
Infrastructure = (GPU + Server + Storage) ร— 0.3
```
## ์•ˆ์ „๊ณ„์ˆ˜
- **์•ˆ์ „๊ณ„์ˆ˜**: 1.4 (40% ๋ฒ„ํผ)
- **GPU ํšจ์œจ**: 0.65 (65% ํ™œ์šฉ๋ฅ )
- **OSS ์ธ๋ ฅ**: 1.5๋ฐฐ (์ƒ์šฉ ๋Œ€๋น„)
""")
estimate_btn.click(
fn=run_estimation,
inputs=[N_pages, doc_complexity, language_mix, table_ratio,
image_quality, model_size, training_epochs, agent_complexity,
deployment_type, sla_level, security_level],
outputs=[summary_text, phase_chart, cost_chart, timeline_chart,
hw_table, oss_table, pdf_download, excel_download]
)
if __name__ == "__main__":
print("๐Ÿš€ Starting Gradio app...")
demo.launch()