""" 🎭 AI 감정 뢄석기 Hugging Face Spaces 배포용 μ™„μ„± μ½”λ“œ """ import gradio as gr from transformers import pipeline import logging import os # λ‘œκΉ… μ„€μ • logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # μ „μ—­ λ³€μˆ˜λ‘œ λͺ¨λΈ νŒŒμ΄ν”„λΌμΈ μ €μž₯ sentiment_pipeline = None def load_model(): """λͺ¨λΈ λ‘œλ”© ν•¨μˆ˜ - μ•± μ‹œμž‘μ‹œ ν•œλ²ˆλ§Œ μ‹€ν–‰""" global sentiment_pipeline try: logger.info("πŸ€– 감정 뢄석 λͺ¨λΈμ„ λ‘œλ”© 쀑...") # λ‹€κ΅­μ–΄ 지원 λͺ¨λΈ μ‚¬μš© (ν•œκ΅­μ–΄ 포함) sentiment_pipeline = pipeline( "sentiment-analysis", model="nlptown/bert-base-multilingual-uncased-sentiment", return_all_scores=False ) logger.info("βœ… λͺ¨λΈ λ‘œλ”© μ™„λ£Œ!") return True except Exception as e: logger.error(f"❌ λͺ¨λΈ λ‘œλ”© μ‹€νŒ¨: {str(e)}") # κΈ°λ³Έ λͺ¨λΈλ‘œ fallback try: sentiment_pipeline = pipeline("sentiment-analysis") logger.info("βœ… κΈ°λ³Έ λͺ¨λΈλ‘œ λ‘œλ”© μ™„λ£Œ!") return True except Exception as e2: logger.error(f"❌ κΈ°λ³Έ λͺ¨λΈλ„ λ‘œλ”© μ‹€νŒ¨: {str(e2)}") return False def analyze_sentiment(text): """ 감정 뢄석 메인 ν•¨μˆ˜ Args: text (str): 뢄석할 ν…μŠ€νŠΈ Returns: str: 뢄석 κ²°κ³Ό (λ§ˆν¬λ‹€μš΄ ν˜•μ‹) """ # μž…λ ₯ 검증 if not text or not text.strip(): return """ ### ⚠️ μ•Œλ¦Ό ν…μŠ€νŠΈλ₯Ό μž…λ ₯ν•΄μ£Όμ„Έμš”! 😊 **μ‚¬μš©λ²•**: μ•„λž˜ μ˜ˆμ‹œλ₯Ό μ°Έκ³ ν•˜κ±°λ‚˜ 직접 λ¬Έμž₯을 μž…λ ₯ν•΄λ³΄μ„Έμš”. """ # ν…μŠ€νŠΈ 길이 μ œν•œ if len(text) > 1000: return """ ### ❌ 였λ₯˜ ν…μŠ€νŠΈκ°€ λ„ˆλ¬΄ κΉλ‹ˆλ‹€. 1000자 μ΄ν•˜λ‘œ μž…λ ₯ν•΄μ£Όμ„Έμš”. """ try: logger.info(f"πŸ“ 뢄석 μ‹œμž‘: {text[:50]}...") # AI λͺ¨λΈλ‘œ 감정 뢄석 result = sentiment_pipeline(text)[0] # κ²°κ³Ό 처리 label = result['label'] confidence = result['score'] logger.info(f"🎯 뢄석 κ²°κ³Ό: {label} ({confidence:.3f})") # 라벨 λ§€ν•‘ (λ‹€κ΅­μ–΄ λͺ¨λΈ 지원) emoji, korean_label, description = map_sentiment_label(label, confidence) # κ²°κ³Ό ν¬λ§·νŒ… result_markdown = f""" ### {emoji} 감정 뢄석 κ²°κ³Ό **🎭 감정**: {korean_label} **πŸ“Š 확신도**: {confidence:.1%} **πŸ” 상세**: {description} --- **βš™οΈ λͺ¨λΈ 정보**: {label} (원본) **⏰ 뢄석 μ™„λ£Œ**: βœ… """ return result_markdown except Exception as e: logger.error(f"πŸ’₯ 뢄석 쀑 였λ₯˜: {str(e)}") return f""" ### ❌ 뢄석 였λ₯˜ μ£„μ†‘ν•©λ‹ˆλ‹€. 뢄석 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. **였λ₯˜ λ‚΄μš©**: {str(e)} **ν•΄κ²° 방법**: - ν…μŠ€νŠΈλ₯Ό λ‹€μ‹œ ν™•μΈν•΄μ£Όμ„Έμš” - μž μ‹œ ν›„ λ‹€μ‹œ μ‹œλ„ν•΄μ£Όμ„Έμš” - λ¬Έμ œκ°€ μ§€μ†λ˜λ©΄ μƒˆλ‘œκ³ μΉ¨ ν•΄μ£Όμ„Έμš” """ def map_sentiment_label(label, confidence): """ λͺ¨λΈ 라벨을 ν•œκ΅­μ–΄λ‘œ λ§€ν•‘ν•˜κ³  μ„€λͺ… μΆ”κ°€ Args: label (str): λͺ¨λΈ 좜λ ₯ 라벨 confidence (float): 신뒰도 점수 Returns: tuple: (이λͺ¨μ§€, ν•œκ΅­μ–΄ 라벨, μ„€λͺ…) """ label_str = str(label).upper() # 긍정 감정 (POSITIVE, 4 STARS, 5 STARS) if any(pos in label_str for pos in ['POSITIVE', '5', '4']): if confidence > 0.8: return "😍", "맀우 긍정적", "μ•„μ£Ό 쒋은 감정이 λŠκ»΄μ§‘λ‹ˆλ‹€!" else: return "😊", "긍정적", "쒋은 감정이 λŠκ»΄μ§‘λ‹ˆλ‹€." # λΆ€μ • 감정 (NEGATIVE, 1 STAR, 2 STARS) elif any(neg in label_str for neg in ['NEGATIVE', '1', '2']): if confidence > 0.8: return "😒", "맀우 뢀정적", "κ°•ν•œ 뢀정적 감정이 λŠκ»΄μ§‘λ‹ˆλ‹€." else: return "😟", "뢀정적", "뢀정적 감정이 λŠκ»΄μ§‘λ‹ˆλ‹€." # 쀑립 감정 (3 STARS, NEUTRAL) else: return "😐", "쀑립적", "νŠΉλ³„ν•œ 감정이 λŠκ»΄μ§€μ§€ μ•ŠμŠ΅λ‹ˆλ‹€." def create_interface(): """Gradio μΈν„°νŽ˜μ΄μŠ€ 생성""" # CSS μŠ€νƒ€μΌλ§ custom_css = """ .gradio-container { font-family: 'Noto Sans KR', -apple-system, BlinkMacSystemFont, sans-serif; max-width: 900px; margin: 0 auto; } .main-header { text-align: center; padding: 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 10px; margin-bottom: 20px; } .footer-info { text-align: center; margin-top: 20px; padding: 15px; background-color: #f8f9fa; border-radius: 8px; font-size: 14px; color: #6c757d; } """ # μΈν„°νŽ˜μ΄μŠ€ 생성 with gr.Blocks( css=custom_css, theme=gr.themes.Soft( primary_hue="blue", secondary_hue="purple", neutral_hue="gray" ), title="🎭 AI 감정 뢄석기" ) as demo: # 헀더 gr.HTML("""

🎭 AI 감정 뢄석기

트랜슀포머 기반 λ‹€κ΅­μ–΄ 감정 뢄석 도ꡬ

""") # 메인 μΈν„°νŽ˜μ΄μŠ€ with gr.Row(): with gr.Column(scale=1): text_input = gr.Textbox( placeholder="감정을 뢄석할 ν…μŠ€νŠΈλ₯Ό μž…λ ₯ν•˜μ„Έμš”...\n예: '였늘 정말 쒋은 ν•˜λ£¨μ˜€μ–΄μš”!'", lines=4, label="πŸ“ ν…μŠ€νŠΈ μž…λ ₯", max_lines=8 ) analyze_btn = gr.Button( "πŸ” 감정 λΆ„μ„ν•˜κΈ°", variant="primary", size="lg" ) clear_btn = gr.Button( "πŸ—‘οΈ μ΄ˆκΈ°ν™”", variant="secondary" ) with gr.Column(scale=1): result_output = gr.Markdown( value=""" ### πŸ‘‹ ν™˜μ˜ν•©λ‹ˆλ‹€! μ™Όμͺ½μ— ν…μŠ€νŠΈλ₯Ό μž…λ ₯ν•˜κ³  **'감정 λΆ„μ„ν•˜κΈ°'** λ²„νŠΌμ„ ν΄λ¦­ν•˜λ©΄ AIκ°€ ν…μŠ€νŠΈμ˜ 감정을 λΆ„μ„ν•΄λ“œλ¦½λ‹ˆλ‹€. **✨ νŠΉμ§•**: - 🌍 λ‹€κ΅­μ–΄ 지원 (ν•œκ΅­μ–΄ μ΅œμ ν™”) - 🎯 높은 정확도 - ⚑ λΉ λ₯Έ 뢄석 속도 """, label="🎯 뢄석 κ²°κ³Ό" ) # μ˜ˆμ‹œ 데이터 gr.Markdown("### πŸ“š μ˜ˆμ‹œ λ¬Έμž₯λ“€") examples = gr.Examples( examples=[ ["였늘 정말 기뢄이 μ’‹μ•„μš”! 🌟"], ["이 μ˜ν™”λŠ” 정말 μ§€λ£¨ν•˜κ³  μž¬λ―Έμ—†μ–΄μš” 😴"], ["κ·Έλƒ₯ ν‰λ²”ν•œ ν•˜λ£¨μ˜€μ–΄μš”."], ["ν—ˆκΉ…νŽ˜μ΄μŠ€ μ›Œν¬μˆ λ„ˆλ¬΄ μž¬λ―Έμžˆμ–΄μš”! πŸš€"], ["AI 기술이 정말 μ‹ κΈ°ν•˜κ³  λ†€λΌμ›Œμš” πŸ€–"], ["이번 ν”„λ‘œμ νŠΈλŠ” μ™„μ „ μ‹€νŒ¨ν–ˆμ–΄μš”... 😞"], ["μƒˆλ‘œμš΄ 도전이 κΈ°λŒ€λ˜κ³  μ„€λ ˆμ–΄μš”!"], ["날씨가 흐리고 μš°μšΈν•΄μš”"], ["μΉœκ΅¬λ“€κ³Ό ν•¨κ»˜ν•œ μ‹œκ°„μ΄ ν–‰λ³΅ν–ˆμ–΄μš”"], ["μ‹œν—˜ κ²°κ³Όκ°€ κ±±μ •λΌμš”"] ], inputs=text_input, label="ν΄λ¦­ν•˜λ©΄ μžλ™ μž…λ ₯λ©λ‹ˆλ‹€" ) # 이벀트 ν•Έλ“€λŸ¬ analyze_btn.click( fn=analyze_sentiment, inputs=text_input, outputs=result_output ) clear_btn.click( fn=lambda: ("", """ ### πŸ‘‹ ν™˜μ˜ν•©λ‹ˆλ‹€! μ™Όμͺ½μ— ν…μŠ€νŠΈλ₯Ό μž…λ ₯ν•˜κ³  **'감정 λΆ„μ„ν•˜κΈ°'** λ²„νŠΌμ„ ν΄λ¦­ν•˜λ©΄ AIκ°€ ν…μŠ€νŠΈμ˜ 감정을 λΆ„μ„ν•΄λ“œλ¦½λ‹ˆλ‹€. """), outputs=[text_input, result_output] ) # Enter ν‚€λ‘œλ„ 뢄석 κ°€λŠ₯ text_input.submit( fn=analyze_sentiment, inputs=text_input, outputs=result_output ) # ν‘Έν„° 정보 gr.HTML(""" """) return demo def main(): """메인 μ‹€ν–‰ ν•¨μˆ˜""" print("🎭 AI 감정 뢄석기 μ‹œμž‘!") # λͺ¨λΈ λ‘œλ”© if not load_model(): print("❌ λͺ¨λΈ λ‘œλ”© μ‹€νŒ¨! 앱을 μ‹œμž‘ν•  수 μ—†μŠ΅λ‹ˆλ‹€.") return # μΈν„°νŽ˜μ΄μŠ€ 생성 demo = create_interface() # 개발 ν™˜κ²½ vs 배포 ν™˜κ²½ μ„€μ • if os.getenv("SPACE_ID"): # Hugging Face Spacesμ—μ„œ μ‹€ν–‰ 쀑 print("πŸš€ Hugging Face Spacesμ—μ„œ 앱을 μ‹œμž‘ν•©λ‹ˆλ‹€...") demo.launch( server_name="0.0.0.0", server_port=7860, share=False # Spacesμ—μ„œλŠ” μžλ™μœΌλ‘œ 곡개됨 ) else: # λ‘œμ»¬μ—μ„œ μ‹€ν–‰ 쀑 print("πŸ’» 둜컬 ν™˜κ²½μ—μ„œ 앱을 μ‹œμž‘ν•©λ‹ˆλ‹€...") demo.launch( share=True, # λ‘œμ»¬μ—μ„œλŠ” 곡개 링크 생성 server_port=7860 ) if __name__ == "__main__": main()