File size: 10,439 Bytes
880d704 99fb303 880d704 99fb303 880d704 d5e84de d8db7a8 d5e84de d8db7a8 880d704 99fb303 880d704 2c5f362 99fb303 2c5f362 d5e84de 880d704 d5e84de 880d704 d5e84de 2c5f362 880d704 2c5f362 880d704 2c5f362 d5e84de 2c5f362 880d704 2c5f362 d5e84de 880d704 2c5f362 880d704 2c5f362 880d704 d5e84de 2c5f362 880d704 2c5f362 880d704 d5e84de 2c5f362 d5e84de 880d704 6ccf417 2c5f362 6ccf417 2c5f362 6dead6e 880d704 2c5f362 880d704 2c5f362 880d704 2c5f362 880d704 2c5f362 880d704 2c5f362 880d704 d5e84de d8db7a8 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
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) |