import gradio as gr import pandas as pd from scraper import YahooFinanceScraper from sentiment_analyzer import NewsAnalyzer # Import new class import time from collections import Counter # For counting themes/impacts # --- MODIFIED BLOCK 1 --- # เราจะโหลด Scraper (เบา) แต่จะยังไม่โหลด Analyzer (หนัก) print("Initializing Yahoo Finance News Analyzer...") scraper = YahooFinanceScraper() analyzer = None # <-- ตั้งเป็น None ก่อน จะโหลดเมื่อถูกเรียกใช้ครั้งแรก # --- END MODIFIED BLOCK --- def get_sentiment_color(sentiment): """กำหนดสีตาม sentiment""" colors = { "Positive": "🟢", "Negative": "🔴", "Neutral": "🟡" } return colors.get(sentiment, "⚪") def get_impact_color(impact): """กำหนดสีตาม impact""" colors = { "Opportunity": "🟢", "Risk": "🔴", "Neutral": "🟡" } return colors.get(impact, "⚪") def analyze_news(search_type, search_input, num_articles): """ ฟังก์ชันหลักในการวิเคราะห์ข่าว """ # --- MODIFIED BLOCK 2: LAZY LOADING --- # ตรวจสอบว่า analyzer ถูกโหลดหรือยัง global analyzer if analyzer is None: # ถ้ายัง ให้แสดงสถานะว่ากำลังโหลด yield "⌛ กำลังโหลดโมเดล AI (ครั้งแรก)...", None, "⌛ กำลังโหลดโมเดล AI (ครั้งแรก)..." print("Analyzer not loaded. Initializing NewsAnalyzer (lazy)...") # นี่คือจุดที่จะโหลดโมเดล (ใช้เวลา 1-2 นาทีในครั้งแรก) analyzer = NewsAnalyzer() print("Analyzer loaded successfully.") # --- END MODIFIED BLOCK --- try: yield "กำลังดึงข่าว...", None, "กำลังดึงข่าว..." # <-- แก้ไข Output ที่ 3 ด้วย if search_type == "Latest News": news_list = scraper.get_latest_news(max_articles=int(num_articles)) elif search_type == "Stock Symbol": if not search_input: yield "⚠️ กรุณาใส่ ticker symbol (เช่น AAPL, TSLA)", None, None return news_list = scraper.get_latest_news(symbol=search_input.upper(), max_articles=int(num_articles)) else: # Keyword search if not search_input: yield "⚠️ กรุณาใส่คำค้นหา", None, None return news_list = scraper.search_news(keyword=search_input, max_articles=int(num_articles)) if not news_list: yield "❌ ไม่พบข่าว กรุณาลองใหม่อีกครั้ง", None, None return yield f"พบข่าว {len(news_list)} รายการ | กำลังวิเคราะห์...", None, f"พบข่าว {len(news_list)} รายการ | กำลังวิเคราะห์..." results = analyzer.analyze_batch(news_list) # (ส่วนที่เหลือของฟังก์ชันเหมือนเดิม) total = len(results) positive = sum(1 for r in results if r['sentiment'] == 'Positive') negative = sum(1 for r in results if r['sentiment'] == 'Negative') neutral = sum(1 for r in results if r['sentiment'] == 'Neutral') avg_score = sum(r['score'] for r in results) / total if total > 0 else 0 theme_counts = Counter(r.get('theme', 'N/A') for r in results) impact_counts = Counter(r.get('impact', 'N/A') for r in results) if positive > negative and positive > neutral: overall = "📈 Positive (Bullish)" elif negative > positive and negative > neutral: overall = "📉 Negative (Bearish)" else: overall = "📊 Neutral" summary = f"""## 📊 สรุปผลการวิเคราะห์ **ภาพรวม:** {overall} | **คะแนนเฉลี่ย:** {avg_score:.2f}/1.0 ### การกระจาย Sentiment - 🟢 Positive: {positive} ({positive/total*100:.1f}%) - 🔴 Negative: {negative} ({negative/total*100:.1f}%) - 🟡 Neutral: {neutral} ({neutral/total*100:.1f}%) --- ### 📌 สรุปหัวข้อ (Themes) """ for theme, count in theme_counts.most_common(): summary += f"- **{theme}:** {count} รายการ ({count/total*100:.1f}%)\n" summary += "\n---\n" # เพิ่มเส้นคั่น summary += "\n### ⚡ สรุปผลกระทบ (Impact)\n" for impact, count in impact_counts.most_common(): emoji = get_impact_color(impact) summary += f"- {emoji} **{impact}:** {count} รายการ ({count/total*100:.1f}%)\n" summary += "\n\n---\n\n## 📰 รายละเอียดแต่ละข่าว\n\n" detailed_results = "" for i, result in enumerate(results, 1): s_emoji = get_sentiment_color(result['sentiment']) i_emoji = get_impact_color(result.get('impact', 'N/A')) detailed_results += f"""### {i}. {s_emoji} {result['title']} **Theme:** {result.get('theme', 'N/A')} | **Impact:** {i_emoji} {result.get('impact', 'N/A')} **Sentiment:** {result['sentiment']} | **Score:** {result['score']:.2f} **เผยแพร่:** {result['published']} **คำอธิบาย:** {result['explanation']} {result['summary'][:200]}{'...' if len(result['summary']) > 200 else ''} [🔗 อ่านต่อ]({result['link']}) ---""" df_data = [] for result in results: df_data.append({ 'Title': result['title'][:60] + '...' if len(result['title']) > 60 else result['title'], 'Theme': result.get('theme', 'N/A'), 'Impact': f"{get_impact_color(result.get('impact', 'N/A'))} {result.get('impact', 'N/A')}", 'Sentiment': f"{get_sentiment_color(result['sentiment'])} {result['sentiment']}", 'Score': f"{result['score']:.2f}", 'Published': result['published'], 'Link': result['link'] }) df = pd.DataFrame(df_data) final_output = summary + detailed_results yield final_output, df, "✅ วิเคราะห์เสร็จสมบูรณ์!" except Exception as e: error_msg = f"❌ เกิดข้อผิดพลาด: {str(e)}" yield error_msg, None, error_msg # --- (Interface Block: ไม่มีการเปลี่ยนแปลง) --- with gr.Blocks(title="Yahoo Finance News Analyzer", theme=gr.themes.Soft()) as demo: gr.Markdown(""" # 📈 Yahoo Finance News Analyzer วิเคราะห์ข่าวการเงินจาก Yahoo Finance ด้วย AI แบบครบวงจร 🔍 **ฟีเจอร์:** - วิเคราะห์ Sentiment (ความรู้สึก) - วิเคราะห์ Theme (หัวข้อข่าว) - วิเคราะห์ Impact (ผลกระทบ: โอกาส หรือ ความเสี่ยง) - ให้คะแนนความมั่นใจและคำอธิบาย - รองรับค้นหาตาม Stock Symbol และ Keyword """) with gr.Row(): with gr.Column(scale=1): search_type = gr.Radio( choices=["Latest News", "Stock Symbol", "Keyword"], value="Latest News", label="ประเภทการค้นหา" ) search_input = gr.Textbox( label="Ticker Symbol / Keyword", placeholder="เช่น AAPL, TSLA, AI, cryptocurrency", info="ใส่เฉพาะเมื่อเลือก Stock Symbol หรือ Keyword" ) num_articles = gr.Slider( minimum=5, maximum=20, value=10, step=1, label="จำนวนข่าว" ) analyze_btn = gr.Button("🔍 วิเคราะห์ข่าว", variant="primary", size="lg") status = gr.Textbox(label="สถานะ", interactive=False) with gr.Column(scale=2): results_md = gr.Markdown("### กดปุ่ม 'วิเคราะห์ข่าว' เพื่อเริ่มต้น") with gr.Row(): results_table = gr.Dataframe( label="📊 ตารางสรุปผล", wrap=True ) gr.Markdown(""" --- ### 💡 วิธีใช้งาน: 1. เลือกประเภทการค้นหา (ข่าวล่าสุด / หุ้นเฉพาะ / คำค้นหา) 2. ใส่ ticker symbol หรือ keyword (ถ้าต้องการ) 3. เลือกจำนวนข่าวที่ต้องการวิเคราะห์ 4. กดปุ่ม "วิเคราะห์ข่าว" ### 🎯 ตัวอย่าง Stock Symbols: - **AAPL** - Apple Inc. - **TSLA** - Tesla - **NVDA** - Nvidia - **MSFT** - Microsoft - **GOOGL** - Google ### 📌 หมายเหตุ: - **Sentiment:** Positive (ดี), Negative (แย่), Neutral (กลาง) - **Theme:** หัวข้อหลักของข่าว (เช่น ผลประกอบการ, สินค้าใหม่) - **Impact:** ผลกระทบต่อบริษัท (🟢 Opportunity - โอกาส, 🔴 Risk - ความเสี่ยง) """) analyze_btn.click( fn=analyze_news, inputs=[search_type, search_input, num_articles], outputs=[results_md, results_table, status] ) # Launch app if __name__ == "__main__": demo.queue() demo.launch(share=False)