Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| # -*- coding: utf-8 -*- | |
| """ | |
| 허깅페이스 배포용 Agentic AI 글로벌 파트너 DB 분석 대시보드 | |
| ✅ Gmail SMTP 이메일 발송 | |
| ✅ 파스텔톤 차트 색상 | |
| ✅ 생태계별 최적화된 대시보드 | |
| ✅ jeongkee10@gmission.com 수신 | |
| """ | |
| import os | |
| import subprocess | |
| import sys | |
| import datetime | |
| import traceback | |
| import gc | |
| import smtplib | |
| from email.mime.text import MIMEText | |
| from email.mime.multipart import MIMEMultipart | |
| import ssl | |
| import re | |
| # 패키지 설치 함수 | |
| def install_packages(): | |
| packages = ['gradio>=4.0.0', 'plotly>=5.0.0', 'pandas>=2.0.0', 'openpyxl>=3.0.0'] | |
| for package in packages: | |
| try: | |
| pkg_name = package.split('>=')[0] | |
| __import__(pkg_name) | |
| except ImportError: | |
| print(f"Installing {package}...") | |
| subprocess.check_call([sys.executable, "-m", "pip", "install", package]) | |
| # 패키지 설치 실행 | |
| try: | |
| install_packages() | |
| print("✅ 패키지 설치 완료") | |
| except Exception as e: | |
| print(f"⚠️ 패키지 설치 오류: {e}") | |
| import pandas as pd | |
| import gradio as gr | |
| # Gradio 버전 호환성 확인 | |
| try: | |
| gradio_version = gr.__version__ | |
| print(f"✅ Gradio 버전: {gradio_version}") | |
| except: | |
| print("⚠️ Gradio 버전 확인 불가") | |
| try: | |
| import plotly.express as px | |
| import plotly.graph_objects as go | |
| from plotly.subplots import make_subplots | |
| PLOTLY_AVAILABLE = True | |
| print("✅ Plotly 사용 가능") | |
| except ImportError: | |
| print("⚠️ Plotly 없음 - 차트 기능 제한") | |
| PLOTLY_AVAILABLE = False | |
| from typing import Tuple, List, Dict, Any, Optional | |
| # ==================== 설정 및 색상 정의 ==================== | |
| # 파스텔톤 색상 팔레트 | |
| PASTEL_COLORS = { | |
| 'primary_palette': ['#FFB3BA', '#FFDFBA', '#FFFFBA', '#BAFFC9', '#BAE1FF', '#E5BAFF', '#FFBAE5'], | |
| 'secondary_palette': ['#FFD6D6', '#FFEBD6', '#FFFFD6', '#D6FFE0', '#D6EBFF', '#E0D6FF', '#FFD6EB'], | |
| 'ecosystem_colors': { | |
| 'Infra': '#FFB3BA', # 파스텔 핑크 | |
| 'Foundation Model': '#BAFFC9', # 파스텔 그린 | |
| 'Platform / Agentic AI Pipeline': '#BAE1FF', # 파스텔 블루 | |
| 'Application': '#FFDFBA', # 파스텔 오렌지 | |
| '전체': '#E5BAFF' # 파스텔 퍼플 | |
| }, | |
| 'importance_colors': { | |
| 5: '#FFB3BA', # S급 - 파스텔 핑크 | |
| 4: '#FFDFBA', # A급 - 파스텔 오렌지 | |
| 3: '#BAE1FF', # B급 - 파스텔 블루 | |
| 2: '#BAFFC9', # C급 - 파스텔 그린 | |
| 1: '#E5E5E5' # D급 - 파스텔 그레이 | |
| } | |
| } | |
| # 생태계 카테고리 | |
| ECOSYSTEM_CATEGORIES = [ | |
| "전체", | |
| "Infra", | |
| "Foundation Model", | |
| "Platform / Agentic AI Pipeline", | |
| "Application" | |
| ] | |
| # 생태계별 최적화된 컬럼 매핑 | |
| ECOSYSTEM_OPTIMIZED_COLUMNS = { | |
| 'Infra': { | |
| 'primary': ['기업명', '중요도', 'HQ_국가', '설립연도', 'PrimaryLLM', 'LLM_Deployment', '주요제품'], | |
| 'charts': ['중요도_분포', '국가별_분포', '설립연도_분포', 'LLM_배포방식'], | |
| 'focus': 'infrastructure and deployment capabilities' | |
| }, | |
| 'Foundation Model': { | |
| 'primary': ['기업명', '중요도', 'HQ_국가', 'PrimaryLLM', 'OpenSource여부', 'LLM_Deployment', '창업자'], | |
| 'charts': ['중요도_분포', 'OpenSource_분포', 'LLM_종류', '국가별_분포'], | |
| 'focus': 'model development and open-source contributions' | |
| }, | |
| 'Platform / Agentic AI Pipeline': { | |
| 'primary': ['기업명', '중요도', 'Application_Domain', 'PrimaryLLM', 'STT_TTS지원', 'TargetCustomer', 'PricingModel'], | |
| 'charts': ['중요도_분포', '응용도메인_분포', 'STT_TTS_지원', '타겟고객'], | |
| 'focus': 'platform integration and agentic workflows' | |
| }, | |
| 'Application': { | |
| 'primary': ['기업명', '중요도', 'Application_Domain', 'TargetCustomer', 'PricingModel', 'KoreaSupport', 'STT_TTS지원'], | |
| 'charts': ['중요도_분포', '응용도메인_분포', '가격정책', '한국지원'], | |
| 'focus': 'end-user applications and market solutions' | |
| } | |
| } | |
| # 컬럼 매핑 | |
| EXACT_COLUMN_MAPPING = { | |
| '기업명': ['기업명', 'CompanyName', 'company', 'name'], | |
| '중요도': ['중요도', 'Importance', 'Priority'], | |
| 'Ecosystem_Category': ['Ecosystem Category', 'Ecosystem_Category'], | |
| 'HQ_국가': ['HQ_국가', 'HQ_Country', 'Country'], | |
| '설립연도': ['설립연도', 'FoundedYear', 'Founded'], | |
| '주요투자자': ['주요투자자', 'KeyInvestors', 'Investors'], | |
| '기업개요': ['기업개요', 'CompanySummary', 'Summary'], | |
| '웹사이트': ['웹사이트', 'Website', 'WebsiteURL'], | |
| '문의URL': ['문의URL', 'ContactURL', 'Contact_URL'], | |
| '이메일': ['이메일', 'Email', 'EmailAddress'], | |
| '전화번호': ['전화번호', 'PhoneNumber', 'phone'], | |
| 'HQ_도시': ['HQ_도시', 'HQ_City', 'City'], | |
| '창업자': ['창업자', 'Founders', 'founder'], | |
| 'Application_Domain': ['Application_Domain', 'Application Domain'], | |
| 'PrimaryLLM': ['PrimaryLLM', 'Primary LLM'], | |
| 'LLM_Deployment': ['LLM_Deployment', 'LLM Deployment'], | |
| 'OpenSource여부': ['OpenSource여부', 'OpenSource'], | |
| '주요제품': ['주요제품', 'KeyProducts', 'Products'], | |
| 'STT_TTS지원': ['STT_TTS지원', 'STT_TTS'], | |
| 'TargetCustomer': ['TargetCustomer', 'Target Customer'], | |
| 'PricingModel': ['PricingModel', 'Pricing Model'], | |
| 'KoreaSupport': ['KoreaSupport', 'Korea Support'], | |
| 'PartnershipProgram': ['PartnershipProgram', 'Partnership Program'] | |
| } | |
| # ==================== Gmail SMTP 이메일 시스템 ==================== | |
| class GmailEmailSystem: | |
| def __init__(self): | |
| self.email_history = [] | |
| self.smtp_server = "smtp.gmail.com" | |
| self.port = 587 | |
| # 허깅페이스 Secrets에서 이메일 정보 가져오기 | |
| self.gmail_email = os.getenv("GMAIL_EMAIL", "") | |
| self.gmail_password = os.getenv("GMAIL_PASSWORD", "") | |
| self.recipient_email = os.getenv("RECIPIENT_EMAIL", "jeongkee10@gmission.com") | |
| print(f"📧 Gmail 설정: {self.gmail_email[:5] if self.gmail_email else '미설정'}***@gmail.com → {self.recipient_email}") | |
| def validate_email(self, email: str) -> bool: | |
| """이메일 주소 유효성 검증""" | |
| pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' | |
| return re.match(pattern, email) is not None | |
| def send_email(self, subject: str, body: str, company_name: str, target_email: str) -> Tuple[bool, str]: | |
| """Gmail SMTP를 통한 실제 이메일 발송""" | |
| try: | |
| if not self.gmail_email or not self.gmail_password: | |
| return False, "Gmail 계정 정보가 설정되지 않았습니다. 허깅페이스 Secrets를 확인하세요." | |
| if not self.validate_email(target_email): | |
| return False, f"올바르지 않은 이메일 주소: {target_email}" | |
| # 이메일 메시지 생성 | |
| message = MIMEMultipart() | |
| message["From"] = self.gmail_email | |
| message["To"] = self.recipient_email # 항상 jeongkee10@gmission.com으로 발송 | |
| message["Subject"] = f"[파트너십 제안] {subject}" | |
| # 이메일 본문 (원본 대상과 내용 포함) | |
| enhanced_body = f""" | |
| G-Mission 파트너십 팀에게, | |
| 다음 기업에 대한 파트너십 제안서가 대시보드에서 생성되었습니다: | |
| 원본 대상 기업: {company_name} | |
| 원본 이메일 주소: {target_email} | |
| 생성 시간: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')} | |
| === 파트너십 제안 내용 === | |
| {body} | |
| === 다음 단계 === | |
| 1. 제안 내용 검토 | |
| 2. 필요시 내용 수정 | |
| 3. {target_email}로 직접 발송 | |
| 4. 결과 추적 및 관리 | |
| --- | |
| 이 이메일은 Agentic AI 파트너 DB 분석 대시보드에서 자동 생성되었습니다. | |
| """ | |
| message.attach(MIMEText(enhanced_body, "plain", "utf-8")) | |
| # Gmail SMTP 서버 연결 및 발송 | |
| context = ssl.create_default_context() | |
| with smtplib.SMTP(self.smtp_server, self.port) as server: | |
| server.starttls(context=context) | |
| server.login(self.gmail_email, self.gmail_password) | |
| server.sendmail(self.gmail_email, self.recipient_email, message.as_string()) | |
| # 발송 기록 | |
| self.record_email_send(company_name, target_email, subject, body[:100]) | |
| return True, f"✅ 이메일이 {self.recipient_email}로 성공적으로 발송되었습니다!" | |
| except smtplib.SMTPAuthenticationError: | |
| return False, "❌ Gmail 인증 실패. 앱 비밀번호를 확인하세요." | |
| except smtplib.SMTPException as e: | |
| return False, f"❌ SMTP 오류: {str(e)}" | |
| except Exception as e: | |
| return False, f"❌ 이메일 발송 실패: {str(e)}" | |
| def create_partnership_email(self, company_name: str, email: str, ecosystem_category: str, | |
| importance: int = 3, country: str = "", website: str = "") -> Tuple[str, str, str]: | |
| """개선된 파트너십 이메일 생성""" | |
| try: | |
| if not email or '@' not in str(email) or str(email) in ['정보 없음', 'N/A']: | |
| return "", "", "" | |
| # 생태계별 맞춤 제목 | |
| ecosystem_subjects = { | |
| "Infra": f"Infrastructure Partnership Opportunity - {company_name} & G-Mission", | |
| "Foundation Model": f"AI Foundation Model Collaboration - {company_name} & G-Mission", | |
| "Platform / Agentic AI Pipeline": f"Agentic AI Platform Partnership - {company_name} & G-Mission", | |
| "Application": f"AI Application Partnership Proposal - {company_name} & G-Mission" | |
| } | |
| subject = ecosystem_subjects.get(ecosystem_category, | |
| f"Strategic AI Partnership Proposal - {company_name} & G-Mission") | |
| # 중요도별 접근 방식 | |
| importance_approaches = { | |
| 5: "We have identified your company as a top-tier strategic partner", | |
| 4: "We have identified your company as a key strategic partner", | |
| 3: "We have identified your company as a promising strategic partner", | |
| 2: "We are interested in exploring partnership opportunities", | |
| 1: "We would like to discuss potential collaboration opportunities" | |
| } | |
| approach = importance_approaches.get(int(importance), | |
| "We are interested in exploring partnership opportunities") | |
| # 생태계별 협력 방안 | |
| ecosystem_focus = { | |
| "Infra": """ | |
| INFRASTRUCTURE COLLABORATION FOCUS: | |
| • AI compute infrastructure optimization and resource sharing | |
| • Cloud deployment strategies for Korean market | |
| • Hardware-software integration solutions | |
| • Scalable AI infrastructure development""", | |
| "Foundation Model": """ | |
| FOUNDATION MODEL COLLABORATION FOCUS: | |
| • Korean language model development and fine-tuning | |
| • Model licensing and technology transfer opportunities | |
| • Joint research in multilingual AI capabilities | |
| • Open-source collaboration initiatives""", | |
| "Platform / Agentic AI Pipeline": """ | |
| PLATFORM INTEGRATION FOCUS: | |
| • API integration and interoperability solutions | |
| • Agentic workflow automation partnerships | |
| • Platform ecosystem development | |
| • Enterprise AI orchestration solutions""", | |
| "Application": """ | |
| APPLICATION PARTNERSHIP FOCUS: | |
| • Market-specific AI application development | |
| • Customer success case studies and joint marketing | |
| • Industry-vertical solution partnerships | |
| • Korean market entry and expansion strategies""" | |
| } | |
| collaboration_details = ecosystem_focus.get(ecosystem_category, | |
| "• Strategic technology partnership development") | |
| current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') | |
| body = f"""Dear {company_name} Partnership Team, | |
| Greetings from G-Mission! | |
| {approach} in the '{ecosystem_category}' space through our comprehensive analysis of 155+ global Agentic AI companies. | |
| {collaboration_details} | |
| KEY PARTNERSHIP OPPORTUNITIES: | |
| • Technology integration and joint product development | |
| • Market expansion in Korea and APAC region | |
| • Strategic alliance in enterprise AI solutions | |
| • Investment and business development collaboration | |
| ABOUT G-MISSION: | |
| G-Mission is a leading AI technology company focused on developing innovative solutions for the Korean and APAC markets. We specialize in enterprise AI implementations and strategic partnerships with global technology leaders. | |
| NEXT STEPS: | |
| We would be delighted to schedule an introductory partnership discussion to explore mutual opportunities. Our team can share detailed market insights, partnership frameworks, and collaboration proposals tailored to your strategic objectives. | |
| Would you be available for a partnership discussion in the coming weeks? | |
| Best regards, | |
| G-Mission Partnership Development Team | |
| Email: jeongkee10@gmission.com | |
| Website: https://gmission.com | |
| --- | |
| This partnership proposal was generated through our Agentic AI Global Partner Database Analysis. | |
| Generated on: {current_time} | |
| Analysis Confidence: {"High" if importance >= 4 else "Medium" if importance >= 3 else "Standard"}""" | |
| return subject, body, str(email) | |
| except Exception as e: | |
| print(f"이메일 생성 오류: {e}") | |
| return "", "", "" | |
| def record_email_send(self, company_name: str, email: str, subject: str, body_preview: str) -> bool: | |
| """이메일 발송 기록""" | |
| try: | |
| record = { | |
| 'timestamp': datetime.datetime.now(), | |
| 'company_name': str(company_name), | |
| 'target_email': str(email), | |
| 'subject': str(subject), | |
| 'body_preview': str(body_preview), | |
| 'recipient': self.recipient_email, | |
| 'status': '발송 완료', | |
| 'send_date': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') | |
| } | |
| self.email_history.append(record) | |
| return True | |
| except: | |
| return False | |
| def get_email_history_text(self) -> str: | |
| """이메일 발송 이력 반환""" | |
| if not self.email_history: | |
| return """📧 **이메일 발송 현황** | |
| 아직 발송된 이메일이 없습니다. | |
| **사용 방법:** | |
| 1. 기업 분석 실행 | |
| 2. 📧 이메일 탭에서 내용 확인/수정 | |
| 3. '실제 이메일 발송' 버튼 클릭 | |
| 4. 이메일이 jeongkee10@gmission.com으로 발송됩니다""" | |
| history_text = f"📧 **이메일 발송 현황** (총 {len(self.email_history)}건)\n\n" | |
| for i, record in enumerate(reversed(self.email_history), 1): | |
| history_text += f""" | |
| **{i}. {record['company_name']}** | |
| - 발송일시: {record['send_date']} | |
| - 대상 이메일: {record['target_email']} | |
| - 실제 수신: {record['recipient']} | |
| - 제목: {record['subject'][:50]}... | |
| - 상태: ✅ {record['status']} | |
| --- | |
| """ | |
| return history_text | |
| # ==================== 데이터 처리 시스템 ==================== | |
| class OptimizedDataProcessor: | |
| def find_column_mapping(df_columns: List[str]) -> Dict[str, str]: | |
| """컬럼 매핑 찾기""" | |
| mapping = {} | |
| for standard_name, possible_names in EXACT_COLUMN_MAPPING.items(): | |
| for possible_name in possible_names: | |
| if possible_name in df_columns: | |
| mapping[standard_name] = possible_name | |
| break | |
| return mapping | |
| def safe_numeric_conversion(series: pd.Series) -> pd.Series: | |
| """안전한 숫자 변환""" | |
| try: | |
| processed = series.astype(str).copy() | |
| processed = processed.replace(['정보 없음', 'nan', 'null', 'NaN', '', 'N/A'], '0') | |
| grade_mapping = {'S': '5', 'A': '4', 'B': '3', 'C': '2', 'D': '1'} | |
| processed = processed.replace(grade_mapping) | |
| processed = processed.str.replace(r'[^\d.]', '', regex=True).replace('', '0') | |
| return pd.to_numeric(processed, errors='coerce').fillna(0) | |
| except: | |
| return pd.Series([0] * len(series)) | |
| def process_data(df: pd.DataFrame) -> pd.DataFrame: | |
| """데이터 처리 메인 함수""" | |
| try: | |
| if df is None or df.empty: | |
| return pd.DataFrame() | |
| column_mapping = OptimizedDataProcessor.find_column_mapping(df.columns.tolist()) | |
| processed_df = pd.DataFrame() | |
| for standard_name, original_name in column_mapping.items(): | |
| if original_name in df.columns: | |
| processed_df[standard_name] = df[original_name].copy() | |
| # 필수 컬럼 보장 | |
| if '기업명' not in processed_df.columns: | |
| processed_df['기업명'] = df.iloc[:, 1] if len(df.columns) > 1 else [f"기업_{i+1}" for i in range(len(df))] | |
| if 'Ecosystem_Category' not in processed_df.columns: | |
| processed_df['Ecosystem_Category'] = '미분류' | |
| # 중요도 처리 | |
| if '중요도' in processed_df.columns: | |
| processed_df['중요도'] = OptimizedDataProcessor.safe_numeric_conversion(processed_df['중요도']) | |
| processed_df['중요도등급'] = processed_df['중요도'].apply( | |
| lambda x: 'S급 (최우선)' if x == 5 else | |
| 'A급 (핵심)' if x == 4 else | |
| 'B급 (유망)' if x == 3 else | |
| 'C급 (관심)' if x == 2 else | |
| 'D급 (참고)' if x == 1 else '미분류' | |
| ) | |
| processed_df = processed_df.fillna('정보 없음') | |
| # 메모리 최적화 | |
| for col in processed_df.columns: | |
| if processed_df[col].dtype == 'object': | |
| processed_df[col] = processed_df[col].astype('category') | |
| return processed_df | |
| except Exception as e: | |
| print(f"데이터 처리 오류: {e}") | |
| return df if df is not None else pd.DataFrame() | |
| # ==================== 파스텔톤 차트 생성 시스템 ==================== | |
| class PastelChartGenerator: | |
| def create_ecosystem_optimized_charts(df: pd.DataFrame, ecosystem_filter: str = "전체") -> Tuple[Any, Any, Any, Any, str]: | |
| """생태계별 최적화된 파스텔톤 차트 생성""" | |
| try: | |
| if not PLOTLY_AVAILABLE or df is None or df.empty: | |
| return None, None, None, None, "데이터가 없거나 Plotly를 사용할 수 없습니다." | |
| # 데이터 필터링 | |
| if ecosystem_filter != "전체": | |
| filtered_df = df[df['Ecosystem_Category'] == ecosystem_filter].copy() | |
| filter_info = f"'{ecosystem_filter}' 생태계" | |
| else: | |
| filtered_df = df.copy() | |
| filter_info = "전체 생태계" | |
| if filtered_df.empty: | |
| return None, None, None, None, f"{ecosystem_filter} 카테고리에 기업이 없습니다." | |
| # 요약 정보 생성 | |
| total_companies = len(filtered_df) | |
| s_grade = len(filtered_df[filtered_df['중요도'] == 5]) if '중요도' in filtered_df.columns else 0 | |
| a_grade = len(filtered_df[filtered_df['중요도'] == 4]) if '중요도' in filtered_df.columns else 0 | |
| countries = filtered_df['HQ_국가'].nunique() if 'HQ_국가' in filtered_df.columns else 0 | |
| # 생태계별 특화 분석 | |
| ecosystem_focus = ECOSYSTEM_OPTIMIZED_COLUMNS.get(ecosystem_filter, {}).get('focus', 'comprehensive analysis') | |
| summary_text = f"""### 📊 {filter_info} 분석 요약 | |
| **총 기업 수:** {total_companies:,}개 | |
| **S급 최우선 기업:** {s_grade}개 | |
| **A급 핵심 기업:** {a_grade}개 | |
| **참여 국가:** {countries}개국 | |
| **분석 포커스:** {ecosystem_focus} | |
| **전략적 기회:** {s_grade + a_grade}개 핵심 기업이 전체의 {((s_grade + a_grade) / total_companies * 100):.1f}%""" | |
| # 1. 생태계별 파스텔톤 분포 차트 | |
| if ecosystem_filter == "전체": | |
| ecosystem_counts = filtered_df['Ecosystem_Category'].value_counts() | |
| ecosystem_colors = [PASTEL_COLORS['ecosystem_colors'].get(eco, PASTEL_COLORS['primary_palette'][i % 7]) | |
| for i, eco in enumerate(ecosystem_counts.index)] | |
| fig1 = px.pie( | |
| values=ecosystem_counts.values, | |
| names=ecosystem_counts.index, | |
| title=f"🏗️ 생태계별 기업 분포 (총 {total_companies}개)", | |
| color_discrete_sequence=ecosystem_colors | |
| ) | |
| fig1.update_traces(textposition='inside', textinfo='percent+label', | |
| textfont=dict(size=12, color='white')) | |
| else: | |
| fig1 = go.Figure(data=[go.Pie( | |
| labels=[ecosystem_filter], | |
| values=[total_companies], | |
| marker_colors=[PASTEL_COLORS['ecosystem_colors'].get(ecosystem_filter, '#E5BAFF')], | |
| textinfo='value+label', | |
| textfont=dict(size=14, color='white') | |
| )]) | |
| fig1.update_layout(title=f"🏗️ {ecosystem_filter} 생태계 ({total_companies}개 기업)") | |
| fig1.update_layout( | |
| font=dict(size=14), | |
| plot_bgcolor='rgba(0,0,0,0)', | |
| paper_bgcolor='rgba(0,0,0,0)', | |
| height=400 | |
| ) | |
| # 2. 중요도별 파스텔톤 분포 차트 | |
| if '중요도' in filtered_df.columns: | |
| importance_counts = filtered_df['중요도'].value_counts().sort_index(ascending=False) | |
| grade_names = {5: 'S급', 4: 'A급', 3: 'B급', 2: 'C급', 1: 'D급'} | |
| if not importance_counts.empty: | |
| x_labels = [grade_names.get(grade, f'{grade}급') for grade in importance_counts.index] | |
| y_values = importance_counts.values | |
| bar_colors = [PASTEL_COLORS['importance_colors'].get(grade, '#E5E5E5') | |
| for grade in importance_counts.index] | |
| fig2 = go.Figure(data=[ | |
| go.Bar(x=x_labels, y=y_values, | |
| marker_color=bar_colors, | |
| text=y_values, textposition='auto', | |
| textfont=dict(size=12, color='black')) | |
| ]) | |
| fig2.update_layout( | |
| title=f"⭐ {filter_info} 중요도별 분포", | |
| xaxis_title="중요도 등급", | |
| yaxis_title="기업 수", | |
| font=dict(size=14), | |
| plot_bgcolor='rgba(0,0,0,0)', | |
| paper_bgcolor='rgba(0,0,0,0)', | |
| height=400 | |
| ) | |
| else: | |
| fig2 = go.Figure() | |
| else: | |
| fig2 = go.Figure() | |
| # 3. 생태계별 최적화된 추가 차트 | |
| fig3 = PastelChartGenerator.create_ecosystem_specific_chart(filtered_df, ecosystem_filter) | |
| # 4. 생태계별 상세 분석 차트 | |
| fig4 = PastelChartGenerator.create_detailed_analysis_chart(filtered_df, ecosystem_filter) | |
| return fig1, fig2, fig3, fig4, summary_text | |
| except Exception as e: | |
| print(f"차트 생성 오류: {e}") | |
| return None, None, None, None, f"차트 생성 중 오류: {str(e)}" | |
| def create_ecosystem_specific_chart(df: pd.DataFrame, ecosystem_filter: str) -> Any: | |
| """생태계별 특화 차트 생성""" | |
| try: | |
| if ecosystem_filter == "Infra": | |
| # 인프라: LLM 배포 방식 분포 | |
| if 'LLM_Deployment' in df.columns: | |
| deployment_counts = df['LLM_Deployment'].value_counts().head(8) | |
| if not deployment_counts.empty: | |
| fig = px.bar( | |
| x=deployment_counts.index, | |
| y=deployment_counts.values, | |
| title="🚀 LLM 배포 방식 분포", | |
| color_discrete_sequence=PASTEL_COLORS['primary_palette'] | |
| ) | |
| fig.update_layout(xaxis_title="배포 방식", yaxis_title="기업 수") | |
| return fig | |
| elif ecosystem_filter == "Foundation Model": | |
| # 파운데이션 모델: 오픈소스 여부 분포 | |
| if 'OpenSource여부' in df.columns: | |
| opensource_counts = df['OpenSource여부'].value_counts() | |
| if not opensource_counts.empty: | |
| fig = px.pie( | |
| values=opensource_counts.values, | |
| names=opensource_counts.index, | |
| title="🔓 오픈소스 여부 분포", | |
| color_discrete_sequence=PASTEL_COLORS['secondary_palette'] | |
| ) | |
| return fig | |
| elif ecosystem_filter == "Platform / Agentic AI Pipeline": | |
| # 플랫폼: 응용 도메인 분포 | |
| if 'Application_Domain' in df.columns: | |
| domain_counts = df['Application_Domain'].value_counts().head(10) | |
| if not domain_counts.empty: | |
| fig = px.bar( | |
| x=domain_counts.values, | |
| y=domain_counts.index, | |
| orientation='h', | |
| title="🎯 응용 도메인별 분포", | |
| color_discrete_sequence=PASTEL_COLORS['primary_palette'] | |
| ) | |
| fig.update_layout(xaxis_title="기업 수", yaxis_title="응용 도메인") | |
| return fig | |
| elif ecosystem_filter == "Application": | |
| # 애플리케이션: 타겟 고객 분포 | |
| if 'TargetCustomer' in df.columns: | |
| customer_counts = df['TargetCustomer'].value_counts().head(8) | |
| if not customer_counts.empty: | |
| fig = px.bar( | |
| x=customer_counts.index, | |
| y=customer_counts.values, | |
| title="👥 타겟 고객별 분포", | |
| color_discrete_sequence=PASTEL_COLORS['primary_palette'] | |
| ) | |
| fig.update_layout(xaxis_title="타겟 고객", yaxis_title="기업 수") | |
| return fig | |
| else: | |
| # 전체: 국가별 분포 | |
| if 'HQ_국가' in df.columns: | |
| country_counts = df['HQ_국가'].value_counts().head(10) | |
| if not country_counts.empty: | |
| fig = px.bar( | |
| x=country_counts.values, | |
| y=country_counts.index, | |
| orientation='h', | |
| title="🌍 주요 국가별 기업 수", | |
| color_discrete_sequence=PASTEL_COLORS['primary_palette'] | |
| ) | |
| fig.update_layout(xaxis_title="기업 수", yaxis_title="국가") | |
| return fig | |
| return go.Figure() | |
| except Exception as e: | |
| print(f"생태계별 차트 생성 오류: {e}") | |
| return go.Figure() | |
| def create_detailed_analysis_chart(df: pd.DataFrame, ecosystem_filter: str) -> Any: | |
| """상세 분석 차트 생성""" | |
| try: | |
| if ecosystem_filter == "Infra": | |
| # 인프라: 설립연도별 분포 | |
| if '설립연도' in df.columns: | |
| years = df['설립연도'][df['설립연도'] > 0] | |
| if not years.empty: | |
| fig = px.histogram( | |
| x=years, | |
| nbins=20, | |
| title="📅 설립연도별 분포", | |
| color_discrete_sequence=[PASTEL_COLORS['ecosystem_colors']['Infra']] | |
| ) | |
| fig.update_layout(xaxis_title="설립연도", yaxis_title="기업 수") | |
| return fig | |
| elif ecosystem_filter == "Foundation Model": | |
| # 파운데이션 모델: PrimaryLLM 분포 | |
| if 'PrimaryLLM' in df.columns: | |
| llm_counts = df['PrimaryLLM'].value_counts().head(8) | |
| if not llm_counts.empty: | |
| fig = px.bar( | |
| x=llm_counts.index, | |
| y=llm_counts.values, | |
| title="🤖 주요 LLM 모델 분포", | |
| color_discrete_sequence=PASTEL_COLORS['primary_palette'] | |
| ) | |
| fig.update_layout(xaxis_title="LLM 모델", yaxis_title="기업 수") | |
| return fig | |
| elif ecosystem_filter == "Platform / Agentic AI Pipeline": | |
| # 플랫폼: STT/TTS 지원 현황 | |
| if 'STT_TTS지원' in df.columns: | |
| stt_counts = df['STT_TTS지원'].value_counts() | |
| if not stt_counts.empty: | |
| fig = px.pie( | |
| values=stt_counts.values, | |
| names=stt_counts.index, | |
| title="🎤 STT/TTS 지원 현황", | |
| color_discrete_sequence=PASTEL_COLORS['secondary_palette'] | |
| ) | |
| return fig | |
| elif ecosystem_filter == "Application": | |
| # 애플리케이션: 한국 지원 현황 | |
| if 'KoreaSupport' in df.columns: | |
| korea_counts = df['KoreaSupport'].value_counts() | |
| if not korea_counts.empty: | |
| fig = px.pie( | |
| values=korea_counts.values, | |
| names=korea_counts.index, | |
| title="🇰🇷 한국 시장 지원 현황", | |
| color_discrete_sequence=PASTEL_COLORS['primary_palette'] | |
| ) | |
| return fig | |
| else: | |
| # 전체: 중요도와 설립연도 상관관계 | |
| if '중요도' in df.columns and '설립연도' in df.columns: | |
| valid_data = df[(df['중요도'] > 0) & (df['설립연도'] > 0)] | |
| if not valid_data.empty: | |
| fig = px.scatter( | |
| valid_data, | |
| x='설립연도', | |
| y='중요도', | |
| size=[10] * len(valid_data), | |
| title="📊 설립연도 vs 중요도 분포", | |
| color_discrete_sequence=[PASTEL_COLORS['ecosystem_colors']['전체']] | |
| ) | |
| fig.update_layout(xaxis_title="설립연도", yaxis_title="중요도") | |
| return fig | |
| return go.Figure() | |
| except Exception as e: | |
| print(f"상세 분석 차트 생성 오류: {e}") | |
| return go.Figure() | |
| # ==================== 기업 분석 시스템 ==================== | |
| def analyze_company_comprehensive(df: pd.DataFrame, company_name: str, email_system: GmailEmailSystem) -> Tuple[str, str, str, str]: | |
| """종합적인 기업 분석 (생태계별 최적화)""" | |
| try: | |
| if df is None or df.empty or not company_name: | |
| return "기업을 선택해주세요.", "", "", "" | |
| # 기업 데이터 찾기 | |
| company_data = df[df['기업명'] == company_name] | |
| if company_data.empty: | |
| return f"'{company_name}' 기업을 찾을 수 없습니다.", "", "", "" | |
| data = company_data.iloc[0] | |
| def safe_get(field, default='정보 없음'): | |
| value = data.get(field, default) | |
| if pd.isna(value) or str(value).strip() in ['', 'nan', 'NaN', 'N/A']: | |
| return default | |
| return str(value) | |
| # 기업 정보 추출 | |
| company_name_clean = safe_get('기업명') | |
| ecosystem_cat = safe_get('Ecosystem_Category') | |
| importance = safe_get('중요도', 0) | |
| importance_grade = safe_get('중요도등급', '미분류') | |
| email_address = safe_get('이메일') | |
| country = safe_get('HQ_국가') | |
| website = safe_get('웹사이트') | |
| # 생태계별 최적화된 분석 | |
| optimized_info = ECOSYSTEM_OPTIMIZED_COLUMNS.get(ecosystem_cat, {}) | |
| primary_columns = optimized_info.get('primary', []) | |
| focus_area = optimized_info.get('focus', 'comprehensive business analysis') | |
| # 액션 추천 | |
| action_recommendations = { | |
| 5: "🚀 **최우선 협력 추진** - S급 전략적 파트너로 즉시 파트너십 개시", | |
| 4: "🎯 **핵심 파트너십 개발** - A급 중요 기업으로 상세 협력 방안 수립", | |
| 3: "🤝 **전술적 협력 검토** - B급 유망 파트너로 단계적 접근", | |
| 2: "👀 **시장 동향 모니터링** - C급 관심 기업으로 지속 관찰", | |
| 1: "📋 **정보 수집 및 분석** - D급 참고 기업으로 기본 정보 축적" | |
| } | |
| try: | |
| importance_num = float(importance) | |
| action_recommendation = action_recommendations.get(int(importance_num), "📋 **기본 정보 수집**") | |
| except: | |
| action_recommendation = "📋 **기본 정보 수집**" | |
| # 생태계별 상세 분석 생성 | |
| ecosystem_analysis = generate_ecosystem_specific_analysis(data, ecosystem_cat, primary_columns) | |
| # 최종 분석 결과 | |
| analysis = f"""# 🏢 {company_name_clean} 종합 분석 | |
| ## ✅ 생태계별 최적화 분석 완료! | |
| ## ⭐ 전략적 평가 | |
| - **전략적 중요도:** {importance}/5점 ({importance_grade}) | |
| - **생태계 분류:** {ecosystem_cat} | |
| - **분석 포커스:** {focus_area} | |
| - **권장 액션:** {action_recommendation} | |
| --- | |
| ## 📍 기업 기본 정보 | |
| - **본사 위치:** {country} - {safe_get('HQ_도시')} | |
| - **설립 연도:** {safe_get('설립연도')} | |
| - **창업자:** {safe_get('창업자')} | |
| - **주요 투자자:** {safe_get('주요투자자')} | |
| ## 🎯 기업 개요 | |
| {safe_get('기업개요')} | |
| {ecosystem_analysis} | |
| ## 🔗 연락처 및 웹 정보 | |
| - **공식 웹사이트:** {website} | |
| - **문의 페이지:** {safe_get('문의URL')} | |
| - **이메일:** {email_address} | |
| - **전화번호:** {safe_get('전화번호')} | |
| --- | |
| ## 💡 맞춤형 파트너십 전략 | |
| {generate_partnership_strategy(ecosystem_cat, int(importance) if str(importance).isdigit() else 3)} | |
| --- | |
| **✨ 이메일 탭으로 이동하면 자동 생성된 맞춤형 파트너십 이메일을 확인할 수 있습니다!** | |
| **📧 '실제 이메일 발송' 버튼으로 jeongkee10@gmission.com에 이메일을 발송할 수 있습니다.**""" | |
| # 이메일 자동 생성 | |
| if email_address != '정보 없음' and '@' in email_address: | |
| subject, body, recipient = email_system.create_partnership_email( | |
| company_name_clean, email_address, ecosystem_cat, int(importance) if str(importance).isdigit() else 3, country, website | |
| ) | |
| return analysis, subject, body, recipient | |
| else: | |
| return analysis, "", "", "" | |
| except Exception as e: | |
| error_msg = f"기업 분석 오류: {str(e)}" | |
| print(error_msg) | |
| return error_msg, "", "", "" | |
| def generate_ecosystem_specific_analysis(data, ecosystem_cat: str, primary_columns: List[str]) -> str: | |
| """생태계별 특화 분석 생성""" | |
| def safe_get(field, default='정보 없음'): | |
| value = data.get(field, default) | |
| if pd.isna(value) or str(value).strip() in ['', 'nan', 'NaN', 'N/A']: | |
| return default | |
| return str(value) | |
| if ecosystem_cat == "Infra": | |
| return f""" | |
| ## 🏗️ 인프라 생태계 전문 분석 | |
| - **주요 LLM:** {safe_get('PrimaryLLM')} | |
| - **배포 방식:** {safe_get('LLM_Deployment')} | |
| - **주요 제품/서비스:** {safe_get('주요제품')} | |
| - **파트너십 프로그램:** {safe_get('PartnershipProgram')} | |
| **인프라 특화 협력 방안:** | |
| • GPU/클라우드 리소스 공동 활용 및 최적화 | |
| • AI 워크로드 배포 및 스케일링 기술 협력 | |
| • 한국 데이터센터 및 엣지 컴퓨팅 구축 | |
| • 고성능 AI 인프라 공동 개발""" | |
| elif ecosystem_cat == "Foundation Model": | |
| return f""" | |
| ## 🤖 파운데이션 모델 생태계 전문 분석 | |
| - **주요 LLM:** {safe_get('PrimaryLLM')} | |
| - **오픈소스 여부:** {safe_get('OpenSource여부')} | |
| - **배포 방식:** {safe_get('LLM_Deployment')} | |
| - **타겟 고객:** {safe_get('TargetCustomer')} | |
| **파운데이션 모델 특화 협력 방안:** | |
| • 한국어 특화 모델 공동 개발 및 Fine-tuning | |
| • 모델 라이센싱 및 기술 이전 협력 | |
| • 멀티모달 AI 모델 공동 연구 | |
| • 오픈소스 생태계 기여 및 협력""" | |
| elif ecosystem_cat == "Platform / Agentic AI Pipeline": | |
| return f""" | |
| ## 🔗 플랫폼/에이전틱 AI 파이프라인 전문 분석 | |
| - **응용 도메인:** {safe_get('Application_Domain')} | |
| - **STT/TTS 지원:** {safe_get('STT_TTS지원')} | |
| - **타겟 고객:** {safe_get('TargetCustomer')} | |
| - **가격 정책:** {safe_get('PricingModel')} | |
| **플랫폼 특화 협력 방안:** | |
| • API 연동 및 상호 운용성 확보 | |
| • 에이전틱 워크플로우 자동화 플랫폼 구축 | |
| • 엔터프라이즈 AI 오케스트레이션 솔루션 | |
| • 통합 플랫폼 생태계 공동 개발""" | |
| elif ecosystem_cat == "Application": | |
| return f""" | |
| ## 📱 애플리케이션 생태계 전문 분석 | |
| - **응용 도메인:** {safe_get('Application_Domain')} | |
| - **타겟 고객:** {safe_get('TargetCustomer')} | |
| - **가격 정책:** {safe_get('PricingModel')} | |
| - **한국 지원:** {safe_get('KoreaSupport')} | |
| **애플리케이션 특화 협력 방안:** | |
| • 산업별 맞춤형 AI 솔루션 공동 개발 | |
| • 한국 시장 진출 및 현지화 협력 | |
| • B2B/B2C 고객 사례 공유 및 공동 마케팅 | |
| • 실제 비즈니스 적용 사례 구축""" | |
| else: | |
| return f""" | |
| ## 🔍 종합 기술 분석 | |
| - **주요 기술:** {safe_get('주요제품')} | |
| - **응용 분야:** {safe_get('Application_Domain')} | |
| - **시장 접근:** {safe_get('TargetCustomer')} | |
| **종합 협력 방안:** | |
| • 기술 통합 및 공동 개발 | |
| • 시장 확장 전략 협력 | |
| • 혁신 생태계 구축""" | |
| def generate_partnership_strategy(ecosystem_cat: str, importance: int) -> str: | |
| """파트너십 전략 생성""" | |
| strategies = { | |
| "Infra": """ | |
| **인프라 파트너십 전략:** | |
| 1. **기술 협력**: 클라우드 인프라 공동 구축 및 최적화 | |
| 2. **시장 진출**: 한국/APAC 데이터센터 확장 협력 | |
| 3. **투자 협력**: 인프라 투자 펀드 공동 조성 | |
| 4. **표준화**: AI 인프라 표준 개발 공동 참여""", | |
| "Foundation Model": """ | |
| **파운데이션 모델 파트너십 전략:** | |
| 1. **기술 협력**: 한국어 LLM 공동 개발 및 최적화 | |
| 2. **라이센싱**: 모델 기술 이전 및 라이센싱 협력 | |
| 3. **연구 협력**: 공동 연구소 설립 및 인재 교류 | |
| 4. **생태계**: 오픈소스 기여 및 커뮤니티 구축""", | |
| "Platform / Agentic AI Pipeline": """ | |
| **플랫폼 파트너십 전략:** | |
| 1. **통합 협력**: API 상호 연동 및 플랫폼 통합 | |
| 2. **솔루션**: 엔터프라이즈 AI 솔루션 공동 개발 | |
| 3. **마케팅**: 공동 고객 확보 및 시장 개척 | |
| 4. **표준화**: 에이전틱 AI 표준 및 프로토콜 개발""", | |
| "Application": """ | |
| **애플리케이션 파트너십 전략:** | |
| 1. **현지화**: 한국 시장 맞춤형 애플리케이션 개발 | |
| 2. **고객 확보**: 공동 세일즈 및 마케팅 협력 | |
| 3. **사례 구축**: 성공 사례 공동 개발 및 홍보 | |
| 4. **투자**: 후속 투자 및 사업 확장 협력""" | |
| } | |
| base_strategy = strategies.get(ecosystem_cat, "**종합 파트너십 전략:** 기술, 시장, 투자 전방위 협력") | |
| if importance >= 4: | |
| priority = "\n\n**🚀 최우선 추진 권장:** 즉시 파트너십 개시 및 전담팀 구성" | |
| elif importance >= 3: | |
| priority = "\n\n**🎯 중점 검토 권장:** 단계별 협력 방안 수립 및 파일럿 프로젝트 진행" | |
| else: | |
| priority = "\n\n**👀 지속 모니터링:** 시장 동향 관찰 및 기회 발굴" | |
| return base_strategy + priority | |
| # ==================== 파일 처리 ==================== | |
| def process_uploaded_file(file): | |
| """파일 업로드 처리""" | |
| if file is None: | |
| return None, "파일을 업로드해주세요." | |
| try: | |
| file_path = file.name if hasattr(file, 'name') else str(file) | |
| if file_path.endswith('.csv'): | |
| df = pd.read_csv(file_path, encoding='utf-8-sig') | |
| elif file_path.endswith(('.xlsx', '.xls')): | |
| df = pd.read_excel(file_path) | |
| else: | |
| return None, "CSV 또는 Excel 파일을 업로드해주세요." | |
| if df.empty: | |
| return None, "빈 파일입니다." | |
| processed_df = OptimizedDataProcessor.process_data(df) | |
| success_msg = f"✅ 파일 처리 완료!\n- 총 기업 수: {len(processed_df):,}개\n- 컬럼 수: {len(processed_df.columns)}개" | |
| # 메모리 최적화 | |
| del df | |
| gc.collect() | |
| return processed_df, success_msg | |
| except Exception as e: | |
| return None, f"파일 처리 오류: {str(e)}" | |
| # ==================== 메인 대시보드 ==================== | |
| def create_huggingface_dashboard(): | |
| """허깅페이스 배포용 메인 대시보드""" | |
| # Gmail 이메일 시스템 초기화 | |
| email_system = GmailEmailSystem() | |
| # 커스텀 CSS | |
| custom_css = """ | |
| .gradio-container { | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif !important; | |
| max-width: 1400px !important; | |
| margin: 0 auto !important; | |
| } | |
| .ecosystem-card { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| border-radius: 10px; | |
| padding: 20px; | |
| margin: 10px; | |
| color: white; | |
| } | |
| .pastel-btn { | |
| background: linear-gradient(135deg, #FFB3BA 0%, #FFDFBA 100%); | |
| border: none; | |
| border-radius: 8px; | |
| color: #333; | |
| font-weight: bold; | |
| } | |
| """ | |
| with gr.Blocks( | |
| theme=gr.themes.Soft(primary_hue="blue", secondary_hue="cyan"), | |
| title="G-Mission Agentic AI Partner Database", | |
| css=custom_css | |
| ) as demo: | |
| # 헤더 | |
| gr.Markdown(""" | |
| # 🚀 G-Mission Agentic AI 글로벌 파트너 DB 분석 대시보드 | |
| ### ✅ 허깅페이스 배포 완료 | ✅ Gmail SMTP 이메일 | ✅ 파스텔톤 차트 | ✅ 생태계별 최적화 | |
| **155개 글로벌 Agentic AI 기업 완벽 분석** | **실시간 파트너십 이메일 발송** | |
| **주요 기능:** | |
| - 🎨 **파스텔톤 시각화**: 생태계별 맞춤 색상으로 직관적 분석 | |
| - 🏗️ **생태계별 최적화**: Infra, Foundation Model, Platform, Application 특화 분석 | |
| - 📧 **Gmail SMTP 연동**: jeongkee10@gmission.com으로 실시간 이메일 발송 | |
| - 🎯 **맞춤형 파트너십**: 기업별/생태계별 최적화된 협력 제안 | |
| """) | |
| # 상태 변수 | |
| df_state = gr.State(value=None) | |
| # 파일 업로드 | |
| with gr.Row(): | |
| with gr.Column(): | |
| file_upload = gr.File( | |
| label="📁 Agentic AI 기업 데이터베이스 업로드", | |
| file_types=['.csv', '.xlsx', '.xls'], | |
| file_count="single" | |
| ) | |
| upload_status = gr.Markdown("📋 **현재 상태:** 파일을 업로드해주세요.") | |
| # 메인 탭 | |
| with gr.Tabs(): | |
| # 탭 1: 파스텔톤 시장 분석 | |
| with gr.TabItem("🎨 파스텔톤 시장 분석"): | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| market_ecosystem_filter = gr.Dropdown( | |
| choices=ECOSYSTEM_CATEGORIES, | |
| value="전체", | |
| label="🏗️ 생태계 필터", | |
| info="특정 생태계 선택 시 해당 영역에 최적화된 분석 제공" | |
| ) | |
| market_analysis_btn = gr.Button( | |
| "🎨 파스텔톤 분석 실행", | |
| variant="primary", | |
| size="lg" | |
| ) | |
| market_summary = gr.Markdown( | |
| "생태계를 선택하고 분석을 실행하면 맞춤형 요약이 표시됩니다.", | |
| label="📊 분석 요약" | |
| ) | |
| with gr.Row(): | |
| with gr.Column(): | |
| chart1 = gr.Plot(label="🏗️ 생태계별 분포") | |
| with gr.Column(): | |
| chart2 = gr.Plot(label="⭐ 중요도별 분포") | |
| with gr.Row(): | |
| with gr.Column(): | |
| chart3 = gr.Plot(label="🎯 생태계별 특화 분석") | |
| with gr.Column(): | |
| chart4 = gr.Plot(label="📊 상세 분석") | |
| # 탭 2: 생태계별 최적화 기업 분석 | |
| with gr.TabItem("🏢 생태계별 최적화 기업 분석"): | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| ecosystem_filter_company = gr.Dropdown( | |
| choices=ECOSYSTEM_CATEGORIES, | |
| value="전체", | |
| label="🏗️ 생태계별 필터링", | |
| info="각 생태계에 최적화된 컬럼과 분석 제공" | |
| ) | |
| company_dropdown = gr.Dropdown( | |
| choices=[], | |
| label="🏢 기업 선택", | |
| info="생태계별 필터링 후 기업 선택" | |
| ) | |
| analyze_company_btn = gr.Button( | |
| "🔍 생태계별 최적화 분석 실행", | |
| variant="primary", | |
| size="lg" | |
| ) | |
| # 생태계별 정보 표시 | |
| ecosystem_info = gr.Markdown( | |
| """### 🏗️ 생태계별 최적화 정보 | |
| **Infra**: LLM 배포, 인프라 기술, 파트너십 프로그램 | |
| **Foundation Model**: LLM 모델, 오픈소스, 기술 이전 | |
| **Platform**: 응용도메인, STT/TTS, 타겟고객, 가격정책 | |
| **Application**: 타겟고객, 가격정책, 한국지원, 애플리케이션""", | |
| label="생태계별 특화 정보" | |
| ) | |
| with gr.Column(scale=2): | |
| company_analysis = gr.Markdown( | |
| """# 🏢 생태계별 최적화 기업 분석 | |
| 생태계를 선택하고 기업을 선택한 후 분석을 실행하면: | |
| **🎯 생태계별 특화 분석:** | |
| - **Infra**: 인프라 기술, 배포 방식, 파트너십 중심 분석 | |
| - **Foundation Model**: LLM 모델, 오픈소스, 기술력 중심 분석 | |
| - **Platform**: 플랫폼 통합, API, 에이전틱 파이프라인 중심 분석 | |
| - **Application**: 실제 응용, 시장 접근, 고객 중심 분석 | |
| **✨ 각 생태계에 최적화된 맞춤형 파트너십 전략이 제공됩니다!**""", | |
| label="기업 상세 분석" | |
| ) | |
| # 탭 3: Gmail SMTP 이메일 시스템 | |
| with gr.TabItem("📧 Gmail SMTP 이메일"): | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.Markdown("""## 📧 Gmail SMTP 이메일 시스템 | |
| **설정 상태:** | |
| - 📧 Gmail 계정: 허깅페이스 Secrets에서 로드 | |
| - 🎯 수신 이메일: jeongkee10@gmission.com (고정) | |
| - 🔐 보안: Gmail 앱 비밀번호 사용 | |
| **사용 방법:** | |
| 1. 기업 분석 실행 → 이메일 자동 생성 | |
| 2. 아래에서 이메일 내용 확인/수정 | |
| 3. '실제 이메일 발송' 버튼 클릭 | |
| 4. jeongkee10@gmission.com으로 이메일 발송됨""") | |
| # 이메일 필드들 | |
| email_recipient = gr.Textbox( | |
| label="📧 대상 기업 이메일 (참조용)", | |
| placeholder="기업 분석 후 자동 입력됩니다", | |
| interactive=True | |
| ) | |
| email_subject = gr.Textbox( | |
| label="📧 이메일 제목 (수정 가능)", | |
| placeholder="기업 분석 후 자동 생성됩니다", | |
| interactive=True | |
| ) | |
| email_body = gr.Textbox( | |
| label="📧 이메일 내용 (수정 가능)", | |
| lines=15, | |
| placeholder="기업 분석 후 생태계별 맞춤형 이메일이 자동 생성됩니다", | |
| interactive=True | |
| ) | |
| # 실제 이메일 발송 버튼 | |
| real_email_send_btn = gr.Button( | |
| "📧 실제 Gmail로 이메일 발송 (→ jeongkee10@gmission.com)", | |
| variant="primary", | |
| size="lg" | |
| ) | |
| email_send_status = gr.Markdown( | |
| """### 📧 이메일 발송 안내 | |
| 기업 분석을 실행하면 해당 기업에 맞는 맞춤형 파트너십 이메일이 자동 생성됩니다. | |
| 내용을 확인/수정한 후 '실제 Gmail로 이메일 발송' 버튼을 클릭하면 | |
| **jeongkee10@gmission.com**으로 이메일이 발송됩니다. | |
| **발송되는 이메일에는:** | |
| - 원본 대상 기업 정보 | |
| - 파트너십 제안 내용 | |
| - 다음 단계 가이드 | |
| - 대시보드 링크가 포함됩니다.""", | |
| label="발송 상태" | |
| ) | |
| # 탭 4: 이메일 발송 현황 | |
| with gr.TabItem("📧 이메일 발송 현황"): | |
| with gr.Column(): | |
| refresh_email_btn = gr.Button( | |
| "🔄 발송 현황 새로고침", | |
| variant="primary" | |
| ) | |
| email_history_display = gr.Markdown( | |
| email_system.get_email_history_text(), | |
| label="📧 이메일 발송 이력" | |
| ) | |
| # ==================== 이벤트 핸들러 ==================== | |
| # 1. 파일 업로드 | |
| def handle_file_upload(file): | |
| try: | |
| df, status = process_uploaded_file(file) | |
| if df is not None: | |
| company_names = sorted(df['기업명'].unique().tolist()) | |
| return ( | |
| df, | |
| status, | |
| gr.update(choices=company_names, value=None) | |
| ) | |
| else: | |
| return None, status, gr.update(choices=[], value=None) | |
| except Exception as e: | |
| return None, f"파일 업로드 오류: {str(e)}", gr.update(choices=[], value=None) | |
| file_upload.upload( | |
| fn=handle_file_upload, | |
| inputs=[file_upload], | |
| outputs=[df_state, upload_status, company_dropdown] | |
| ) | |
| # 2. 파스텔톤 시장 분석 | |
| def handle_market_analysis(df, ecosystem_filter): | |
| try: | |
| if df is None or df.empty: | |
| return None, None, None, None, "데이터 파일을 업로드해주세요." | |
| return PastelChartGenerator.create_ecosystem_optimized_charts(df, ecosystem_filter) | |
| except Exception as e: | |
| return None, None, None, None, f"시장 분석 오류: {str(e)}" | |
| market_analysis_btn.click( | |
| fn=handle_market_analysis, | |
| inputs=[df_state, market_ecosystem_filter], | |
| outputs=[chart1, chart2, chart3, chart4, market_summary] | |
| ) | |
| # 3. 생태계별 기업 필터링 | |
| def update_company_dropdown(df, ecosystem_filter): | |
| try: | |
| if df is None or df.empty: | |
| return gr.update(choices=[]) | |
| if ecosystem_filter != "전체": | |
| filtered_df = df[df['Ecosystem_Category'] == ecosystem_filter] | |
| else: | |
| filtered_df = df | |
| company_names = sorted(filtered_df['기업명'].unique().tolist()) | |
| return gr.update(choices=company_names, value=None) | |
| except Exception as e: | |
| return gr.update(choices=[]) | |
| ecosystem_filter_company.change( | |
| fn=update_company_dropdown, | |
| inputs=[df_state, ecosystem_filter_company], | |
| outputs=[company_dropdown] | |
| ) | |
| # 4. 🔥 핵심: 생태계별 최적화 기업 분석 + 이메일 자동 생성 | |
| analyze_company_btn.click( | |
| fn=lambda df, company: analyze_company_comprehensive(df, company, email_system), | |
| inputs=[df_state, company_dropdown], | |
| outputs=[ | |
| company_analysis, # 기업 분석 결과 | |
| email_subject, # 이메일 제목 자동 입력 | |
| email_body, # 이메일 내용 자동 입력 | |
| email_recipient # 받는 사람 자동 입력 | |
| ] | |
| ) | |
| # 5. 실제 Gmail 이메일 발송 | |
| def handle_real_email_send(recipient, subject, body): | |
| try: | |
| if not recipient or '@' not in recipient: | |
| return "올바른 대상 기업 이메일 주소가 필요합니다." | |
| if not subject or not body: | |
| return "이메일 제목과 내용을 입력해주세요." | |
| # 회사명 추출 | |
| company_name = recipient.split('@')[0].capitalize() | |
| # 실제 Gmail 발송 | |
| success, message = email_system.send_email(subject, body, company_name, recipient) | |
| return message | |
| except Exception as e: | |
| return f"이메일 발송 처리 오류: {str(e)}" | |
| real_email_send_btn.click( | |
| fn=handle_real_email_send, | |
| inputs=[email_recipient, email_subject, email_body], | |
| outputs=[email_send_status] | |
| ) | |
| # 6. 이메일 현황 새로고침 | |
| refresh_email_btn.click( | |
| fn=lambda: email_system.get_email_history_text(), | |
| outputs=[email_history_display] | |
| ) | |
| return demo | |
| # ==================== 메인 실행 ==================== | |
| def main(): | |
| """메인 실행 함수""" | |
| print("🚀 G-Mission 허깅페이스 배포용 Agentic AI 대시보드 시작!") | |
| print("✅ Gmail SMTP 이메일 시스템") | |
| print("✅ 파스텔톤 차트 색상") | |
| print("✅ 생태계별 최적화") | |
| print("✅ jeongkee10@gmission.com 수신") | |
| try: | |
| demo = create_huggingface_dashboard() | |
| # 허깅페이스 배포용 launch 설정 | |
| demo.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| debug=False, | |
| share=False | |
| ) | |
| print("✅ 허깅페이스 배포용 대시보드 실행 성공!") | |
| except Exception as e: | |
| print(f"❌ 대시보드 실행 오류: {e}") | |
| traceback.print_exc() | |
| if __name__ == "__main__": | |
| main() | |