Spaces:
Sleeping
Sleeping
| # ============================================ | |
| # ๐ 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() | |