khjhs60199 commited on
Commit
d43b3e6
·
verified ·
1 Parent(s): 9bf2819

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +175 -103
app.py CHANGED
@@ -96,26 +96,60 @@ class NewsApp:
96
  needs_update = (current_time - self.last_progress_update) < 5 # 5秒內的更新才顯示
97
  return self.current_progress, needs_update
98
 
99
- def get_latest_news(self, category: str = "all", limit: int = 50, force_refresh: bool = False) -> str:
100
- """獲取最新新聞並格式化顯示"""
 
 
101
  try:
102
  # 檢查是否需要刷新(避免無意義的閃爍)
103
  current_time = time.time()
104
- if not force_refresh and (current_time - self.last_news_update) < 10:
105
- # 10秒內不重複查詢,除非強制刷新
106
  pass
107
 
108
  self.last_news_update = current_time
109
 
110
- # 記錄分類選擇
111
- logger.info(f"獲取新聞 - 分類: {category}, 限制: {limit}")
112
 
113
- news_data = self.db.get_recent_news(category=category, limit=limit)
114
- if not news_data:
115
- return f"📰 暫無 {self._get_category_name(category)} 新聞資料,請先執行爬蟲任務"
 
 
 
116
 
117
- # 添加分類標題
118
- category_title = f"📊 當前顯示: {self._get_category_name(category)} ({len(news_data)} 篇)"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  formatted_news = format_news_for_display(news_data)
120
 
121
  return f"<div style='background: #e3f2fd; padding: 10px; margin-bottom: 15px; border-radius: 5px; text-align: center; font-weight: bold;'>{category_title}</div>{formatted_news}"
@@ -132,6 +166,16 @@ class NewsApp:
132
  "tw_stock": "台股新聞"
133
  }
134
  return category_names.get(category, category)
 
 
 
 
 
 
 
 
 
 
135
 
136
  def manual_crawl(self) -> str:
137
  """手動觸發爬蟲"""
@@ -145,8 +189,8 @@ class NewsApp:
145
  self.is_crawling = True
146
  self.update_progress("🚀 手動爬蟲開始")
147
 
148
- # 使用新的即時爬蟲方法
149
- results = self.crawler.crawl_all_categories(max_articles_per_category=5)
150
 
151
  total_articles = sum(len(articles) for articles in results.values())
152
  result_message = f"✅ 手動爬蟲完成,總共處理 {total_articles} 篇文章"
@@ -168,6 +212,7 @@ class NewsApp:
168
  return f"""
169
  📊 **新聞統計**
170
  - 總新聞數量: {stats.get('total_news', 0)}
 
171
  - 美股新聞: {stats.get('us_stock_count', 0)}
172
  - 台股新聞: {stats.get('tw_stock_count', 0)}
173
  - 正面新聞: {stats.get('positive_count', 0)} 😊
@@ -179,10 +224,16 @@ class NewsApp:
179
  logger.error(f"獲取統計資訊錯誤: {e}")
180
  return f"❌ 獲取統計資訊失敗: {str(e)}"
181
 
182
- def get_news_api_data(self, category: str = "all", limit: int = 50) -> Dict:
 
183
  """獲取新聞API數據"""
184
  try:
185
- news_data = self.db.get_recent_news(category=category, limit=limit)
 
 
 
 
 
186
 
187
  # 轉換為JSON友好格式
188
  api_data = []
@@ -221,11 +272,13 @@ app = NewsApp()
221
  # API 路由
222
  @flask_app.route('/api/news', methods=['GET'])
223
  def api_get_news():
224
- """獲取新聞列表API"""
225
  category = request.args.get('category', 'all')
226
- limit = int(request.args.get('limit', 50))
 
 
227
 
228
- result = app.get_news_api_data(category, limit)
229
  return jsonify(result)
230
 
231
  @flask_app.route('/api/stats', methods=['GET'])
@@ -305,19 +358,19 @@ def create_interface():
305
  ) as interface:
306
 
307
  gr.Markdown("""
308
- # 📈 股市新聞情緒分析器 - 即時版
309
 
310
  🤖 自動爬取鉅亨網美股和台股新聞,並進行即時中文情緒分析
311
 
312
  ⚡ **即時處理**: 每篇文章完成後立即分析並存檔
313
  🎯 **智能分析**: 使用 RoBERTa 模型進行情緒分析
314
- 🔄 **去重處理**: 自動過濾重複新聞
315
  📊 **API接口**: 提供RESTful API獲取分析結果
316
  """)
317
 
318
  with gr.Tab("📰 最新新聞"):
319
  with gr.Row():
320
- with gr.Column(scale=2):
321
  category_radio = gr.Radio(
322
  choices=[
323
  ("所有新聞", "all"),
@@ -325,31 +378,56 @@ def create_interface():
325
  ("台股新聞", "tw_stock")
326
  ],
327
  value="all",
328
- label="📋 新聞分類",
329
- info="選擇要顯示的新聞類型"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
330
  )
331
- with gr.Column(scale=1):
332
- refresh_btn = gr.Button("🔄 重新整理", variant="primary")
333
- manual_crawl_btn = gr.Button("🚀 手動爬取", variant="secondary")
334
-
335
- # 進度顯示 - 只在有更新時顯示
336
- progress_display = gr.Textbox(
337
- label="📊 系統狀態",
338
- value=app.current_progress,
339
- interactive=False,
340
- elem_classes=["progress-box"],
341
- lines=1
342
- )
343
 
344
  news_display = gr.HTML(
345
  label="新聞內容",
346
- value=app.get_latest_news("all", force_refresh=True)
347
  )
348
  crawl_result = gr.Textbox(label="爬取結果", visible=False)
349
 
350
- # 狀態變量,用於追蹤當前選擇的分類
351
- current_category = gr.State("all")
352
-
353
  # 更新函數
354
  def update_progress_only():
355
  """只更新進度,不更新新聞"""
@@ -357,54 +435,64 @@ def create_interface():
357
  if needs_update or app.is_crawling:
358
  return progress
359
  else:
360
- return gr.update() # 不更新
 
 
 
 
 
361
 
362
- def refresh_news(category):
363
- """刷新新聞內容"""
364
- logger.info(f"刷新新聞 - 用戶選擇分類: {category}")
365
- return app.get_latest_news(category, force_refresh=True), category
366
 
367
- def handle_manual_crawl(current_cat):
368
  """處理手動爬蟲"""
369
  result = app.manual_crawl()
370
- # 爬取完成後自動刷新當前分類的新聞
371
- news = app.get_latest_news(current_cat, force_refresh=True)
372
  return result, news
373
 
374
- # 進度更新定時器 - 降低頻率,減少閃爍
375
- progress_timer = gr.Timer(value=10) # 每10秒檢查一次進度
376
  progress_timer.tick(
377
  fn=update_progress_only,
378
  outputs=[progress_display]
379
  )
380
 
381
  # 綁定事件
 
 
 
 
 
 
382
  refresh_btn.click(
383
- refresh_news,
384
- inputs=[category_radio],
385
- outputs=[news_display, current_category]
386
  )
387
 
388
  manual_crawl_btn.click(
389
  handle_manual_crawl,
390
- inputs=[current_category],
391
  outputs=[crawl_result, news_display]
392
  ).then(
393
  lambda: gr.update(visible=True),
394
  outputs=[crawl_result]
395
  )
396
 
 
397
  category_radio.change(
398
- refresh_news,
399
- inputs=[category_radio],
400
- outputs=[news_display, current_category]
401
  )
402
 
403
  # 初始載入
404
  interface.load(
405
- refresh_news,
406
- inputs=[gr.State("all")],
407
- outputs=[news_display, current_category]
408
  )
409
 
410
  with gr.Tab("📊 統計資訊"):
@@ -420,38 +508,20 @@ def create_interface():
420
 
421
  ### 🔗 接口列表
422
 
423
- #### 1. 獲取新聞列表
424
  ```
425
- GET /api/news?category={all|us_stock|tw_stock}&limit={數量}
426
  ```
427
 
428
  **參數:**
429
  - `category`: 新聞分類 (可選,默認: all)
430
- - `all`: 所有新聞
431
- - `us_stock`: 美股新聞
432
- - `tw_stock`: 台股新聞
433
- - `limit`: 返回數量 (可選,默認: 50)
434
-
435
- **響應示例:**
436
- ```json
437
- {
438
- "success": true,
439
- "count": 10,
440
- "data": [
441
- {
442
- "id": 1,
443
- "title": "美股標題",
444
- "content": "新聞內容...",
445
- "url": "https://...",
446
- "source": "鉅亨網",
447
- "category": "us_stock",
448
- "published_date": "2024-01-01T12:00:00",
449
- "sentiment": "positive",
450
- "sentiment_score": 0.85,
451
- "created_date": "2024-01-01T12:05:00"
452
- }
453
- ]
454
- }
455
  ```
456
 
457
  #### 2. 獲取統計信息
@@ -475,17 +545,13 @@ def create_interface():
475
  ```python
476
  import requests
477
 
478
- # 獲取所有新聞
479
- response = requests.get('http://localhost:5000/api/news')
480
  news_data = response.json()
481
 
482
- # 獲取美股新聞
483
- response = requests.get('http://localhost:5000/api/news?category=us_stock&limit=10')
484
- us_news = response.json()
485
-
486
- # 獲取台股新聞
487
- response = requests.get('http://localhost:5000/api/news?category=tw_stock&limit=10')
488
- tw_news = response.json()
489
  ```
490
  """)
491
 
@@ -497,22 +563,28 @@ def create_interface():
497
  - **實時分析**: 每篇文章爬取完成立即進行情緒分析
498
  - **即時存檔**: 分析完成後立即保存到SQLite資料庫
499
  - **智能刷新**: 避免無意義的頁面閃爍
500
- - **分類顯示**: 支援美股、台股、全部新聞分類查看
 
 
 
 
 
 
501
 
502
  ### 📊 情緒分析
503
- - **模型**: `uer/roberta-base-finetuned-jd-binary-chinese`
504
- - **分類**: 正面 (綠色) / 負面 (紅色) / 中性 (灰色)
505
  - **準確性**: 針對中文金融新聞優化
506
 
507
  ### 🕷️ 新聞來源
508
  - **美股**: https://news.cnyes.com/news/cat/us_stock
509
  - **台股**: https://news.cnyes.com/news/cat/tw_stock_news
510
- - **頻率**: 每30分鐘自動更新
511
 
512
  ### 📱 介面優化
513
- - **防閃爍**: 智能更新機制,減少不必要的刷新
514
- - **分類標示**: 清楚顯示當前查看的新聞分類
515
- - **狀態追蹤**: 實時顯示系統運行狀態
516
  """)
517
 
518
  return interface
@@ -531,7 +603,7 @@ if __name__ == "__main__":
531
  print("🚀 啟動股市新聞情緒分析器...")
532
  print("📊 網頁介面: http://localhost:7860")
533
  print("🔌 API接口: http://localhost:5000")
534
- print("💡 首次啟動需要下載模型,請耐心等待...")
535
 
536
  # 啟動Gradio介面
537
  interface = create_interface()
 
96
  needs_update = (current_time - self.last_progress_update) < 5 # 5秒內的更新才顯示
97
  return self.current_progress, needs_update
98
 
99
+ def get_latest_news(self, category: str = "all", days: int = 7,
100
+ keyword: str = "", sentiment_filter: str = "all",
101
+ force_refresh: bool = False) -> str:
102
+ """獲取最新新聞並格式化顯示 - 增強版"""
103
  try:
104
  # 檢查是否需要刷新(避免無意義的閃爍)
105
  current_time = time.time()
106
+ if not force_refresh and (current_time - self.last_news_update) < 5:
107
+ # 5秒內不重複查詢,除非強制刷新
108
  pass
109
 
110
  self.last_news_update = current_time
111
 
112
+ # 記錄查詢參數
113
+ logger.info(f"獲取新聞 - 分類: {category}, 天數: {days}, 關鍵字: '{keyword}', 情緒: {sentiment_filter}")
114
 
115
+ news_data = self.db.get_recent_news(
116
+ category=category,
117
+ days=days,
118
+ keyword=keyword,
119
+ sentiment_filter=sentiment_filter
120
+ )
121
 
122
+ if not news_data:
123
+ filter_desc = []
124
+ if category != "all":
125
+ filter_desc.append(f"分類: {self._get_category_name(category)}")
126
+ if days > 0:
127
+ filter_desc.append(f"時間: {days}天內")
128
+ if keyword:
129
+ filter_desc.append(f"關鍵字: '{keyword}'")
130
+ if sentiment_filter != "all":
131
+ filter_desc.append(f"情緒: {self._get_sentiment_name(sentiment_filter)}")
132
+
133
+ filter_text = "、".join(filter_desc) if filter_desc else "所有條件"
134
+ return f"📰 暫無符合條件的新聞資料 ({filter_text}),請調整篩選條件或執行爬蟲任務"
135
+
136
+ # 添加查詢結果標題
137
+ filter_parts = []
138
+ if category != "all":
139
+ filter_parts.append(self._get_category_name(category))
140
+ if days > 0:
141
+ filter_parts.append(f"{days}天內")
142
+ if keyword:
143
+ filter_parts.append(f"關鍵字「{keyword}」")
144
+ if sentiment_filter != "all":
145
+ filter_parts.append(f"{self._get_sentiment_name(sentiment_filter)}情緒")
146
+
147
+ if filter_parts:
148
+ title_desc = " | ".join(filter_parts)
149
+ else:
150
+ title_desc = "所有新聞"
151
+
152
+ category_title = f"📊 當前顯示: {title_desc} ({len(news_data)} 篇)"
153
  formatted_news = format_news_for_display(news_data)
154
 
155
  return f"<div style='background: #e3f2fd; padding: 10px; margin-bottom: 15px; border-radius: 5px; text-align: center; font-weight: bold;'>{category_title}</div>{formatted_news}"
 
166
  "tw_stock": "台股新聞"
167
  }
168
  return category_names.get(category, category)
169
+
170
+ def _get_sentiment_name(self, sentiment: str) -> str:
171
+ """獲取情緒中文名稱"""
172
+ sentiment_names = {
173
+ "all": "所有",
174
+ "positive": "正面",
175
+ "negative": "負面",
176
+ "neutral": "中性"
177
+ }
178
+ return sentiment_names.get(sentiment, sentiment)
179
 
180
  def manual_crawl(self) -> str:
181
  """手動觸發爬蟲"""
 
189
  self.is_crawling = True
190
  self.update_progress("🚀 手動爬蟲開始")
191
 
192
+ # 使用新的即時爬蟲方法 - 移除限制
193
+ results = self.crawler.crawl_all_categories(max_articles_per_category=20) # 增加到20篇
194
 
195
  total_articles = sum(len(articles) for articles in results.values())
196
  result_message = f"✅ 手動爬蟲完成,總共處理 {total_articles} 篇文章"
 
212
  return f"""
213
  📊 **新聞統計**
214
  - 總新聞數量: {stats.get('total_news', 0)}
215
+ - 近7天新聞: {stats.get('recent_news', 0)}
216
  - 美股新聞: {stats.get('us_stock_count', 0)}
217
  - 台股新聞: {stats.get('tw_stock_count', 0)}
218
  - 正面新聞: {stats.get('positive_count', 0)} 😊
 
224
  logger.error(f"獲取統計資訊錯誤: {e}")
225
  return f"❌ 獲取統計資訊失敗: {str(e)}"
226
 
227
+ def get_news_api_data(self, category: str = "all", days: int = 7,
228
+ keyword: str = "", sentiment_filter: str = "all") -> Dict:
229
  """獲取新聞API數據"""
230
  try:
231
+ news_data = self.db.get_recent_news(
232
+ category=category,
233
+ days=days,
234
+ keyword=keyword,
235
+ sentiment_filter=sentiment_filter
236
+ )
237
 
238
  # 轉換為JSON友好格式
239
  api_data = []
 
272
  # API 路由
273
  @flask_app.route('/api/news', methods=['GET'])
274
  def api_get_news():
275
+ """獲取新聞列表API - 增強版"""
276
  category = request.args.get('category', 'all')
277
+ days = int(request.args.get('days', 7))
278
+ keyword = request.args.get('keyword', '')
279
+ sentiment_filter = request.args.get('sentiment', 'all')
280
 
281
+ result = app.get_news_api_data(category, days, keyword, sentiment_filter)
282
  return jsonify(result)
283
 
284
  @flask_app.route('/api/stats', methods=['GET'])
 
358
  ) as interface:
359
 
360
  gr.Markdown("""
361
+ # 📈 股市新聞情緒分析器 - 全功能版
362
 
363
  🤖 自動爬取鉅亨網美股和台股新聞,並進行即時中文情緒分析
364
 
365
  ⚡ **即時處理**: 每篇文章完成後立即分析並存檔
366
  🎯 **智能分析**: 使用 RoBERTa 模型進行情緒分析
367
+ 🔍 **多條件篩選**: 支援時間段、關鍵字、情緒篩選
368
  📊 **API接口**: 提供RESTful API獲取分析結果
369
  """)
370
 
371
  with gr.Tab("📰 最新新聞"):
372
  with gr.Row():
373
+ with gr.Column(scale=1):
374
  category_radio = gr.Radio(
375
  choices=[
376
  ("所有新聞", "all"),
 
378
  ("台股新聞", "tw_stock")
379
  ],
380
  value="all",
381
+ label="📋 新聞分類"
382
+ )
383
+
384
+ days_slider = gr.Slider(
385
+ minimum=0,
386
+ maximum=30,
387
+ value=7,
388
+ step=1,
389
+ label="📅 時間範圍 (天)",
390
+ info="0表示不限制時間"
391
+ )
392
+
393
+ keyword_input = gr.Textbox(
394
+ label="🔍 關鍵字搜尋",
395
+ placeholder="輸入關鍵字搜尋新聞...",
396
+ value=""
397
+ )
398
+
399
+ sentiment_radio = gr.Radio(
400
+ choices=[
401
+ ("所有情緒", "all"),
402
+ ("正面情緒", "positive"),
403
+ ("負面情緒", "negative"),
404
+ ("中性情緒", "neutral")
405
+ ],
406
+ value="all",
407
+ label="😊 情緒篩選"
408
+ )
409
+
410
+ with gr.Column(scale=2):
411
+ with gr.Row():
412
+ search_btn = gr.Button("🔍 搜尋新聞", variant="primary")
413
+ refresh_btn = gr.Button("🔄 重新整理", variant="secondary")
414
+ manual_crawl_btn = gr.Button("🚀 手動爬取", variant="secondary")
415
+
416
+ # 進度顯示
417
+ progress_display = gr.Textbox(
418
+ label="📊 系統狀態",
419
+ value=app.current_progress,
420
+ interactive=False,
421
+ elem_classes=["progress-box"],
422
+ lines=1
423
  )
 
 
 
 
 
 
 
 
 
 
 
 
424
 
425
  news_display = gr.HTML(
426
  label="新聞內容",
427
+ value=app.get_latest_news("all", 7, "", "all", force_refresh=True)
428
  )
429
  crawl_result = gr.Textbox(label="爬取結果", visible=False)
430
 
 
 
 
431
  # 更新函數
432
  def update_progress_only():
433
  """只更新進度,不更新新聞"""
 
435
  if needs_update or app.is_crawling:
436
  return progress
437
  else:
438
+ return gr.update()
439
+
440
+ def search_news(category, days, keyword, sentiment):
441
+ """搜尋新聞"""
442
+ logger.info(f"搜尋新聞 - 分類: {category}, 天數: {days}, 關鍵字: '{keyword}', 情緒: {sentiment}")
443
+ return app.get_latest_news(category, days, keyword, sentiment, force_refresh=True)
444
 
445
+ def refresh_current_search(category, days, keyword, sentiment):
446
+ """刷新當前搜尋"""
447
+ return app.get_latest_news(category, days, keyword, sentiment, force_refresh=True)
 
448
 
449
+ def handle_manual_crawl(category, days, keyword, sentiment):
450
  """處理手動爬蟲"""
451
  result = app.manual_crawl()
452
+ # 爬取完成後自動刷新當前搜尋
453
+ news = app.get_latest_news(category, days, keyword, sentiment, force_refresh=True)
454
  return result, news
455
 
456
+ # 進度更新定時器
457
+ progress_timer = gr.Timer(value=10)
458
  progress_timer.tick(
459
  fn=update_progress_only,
460
  outputs=[progress_display]
461
  )
462
 
463
  # 綁定事件
464
+ search_btn.click(
465
+ search_news,
466
+ inputs=[category_radio, days_slider, keyword_input, sentiment_radio],
467
+ outputs=[news_display]
468
+ )
469
+
470
  refresh_btn.click(
471
+ refresh_current_search,
472
+ inputs=[category_radio, days_slider, keyword_input, sentiment_radio],
473
+ outputs=[news_display]
474
  )
475
 
476
  manual_crawl_btn.click(
477
  handle_manual_crawl,
478
+ inputs=[category_radio, days_slider, keyword_input, sentiment_radio],
479
  outputs=[crawl_result, news_display]
480
  ).then(
481
  lambda: gr.update(visible=True),
482
  outputs=[crawl_result]
483
  )
484
 
485
+ # 分類改變時自動搜尋
486
  category_radio.change(
487
+ search_news,
488
+ inputs=[category_radio, days_slider, keyword_input, sentiment_radio],
489
+ outputs=[news_display]
490
  )
491
 
492
  # 初始載入
493
  interface.load(
494
+ lambda: app.get_latest_news("all", 7, "", "all", force_refresh=True),
495
+ outputs=[news_display]
 
496
  )
497
 
498
  with gr.Tab("📊 統計資訊"):
 
508
 
509
  ### 🔗 接口列表
510
 
511
+ #### 1. 獲取新聞列表 (增強版)
512
  ```
513
+ GET /api/news?category={all|us_stock|tw_stock}&days={天數}&keyword={關鍵字}&sentiment={all|positive|negative|neutral}
514
  ```
515
 
516
  **參數:**
517
  - `category`: 新聞分類 (可選,默認: all)
518
+ - `days`: 時間範圍天數 (可選,默認: 7,0表示不限制)
519
+ - `keyword`: 關鍵字搜尋 (可選)
520
+ - `sentiment`: 情緒篩選 (可選,默認: all)
521
+
522
+ **示例:**
523
+ ```
524
+ /api/news?category=us_stock&days=3&keyword=AI&sentiment=positive
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
525
  ```
526
 
527
  #### 2. 獲取統計信息
 
545
  ```python
546
  import requests
547
 
548
+ # 獲取所有正面情緒的美股新聞
549
+ response = requests.get('http://localhost:5000/api/news?category=us_stock&sentiment=positive')
550
  news_data = response.json()
551
 
552
+ # 搜尋包含"AI"關鍵字的新聞
553
+ response = requests.get('http://localhost:5000/api/news?keyword=AI&days=3')
554
+ ai_news = response.json()
 
 
 
 
555
  ```
556
  """)
557
 
 
563
  - **實時分析**: 每篇文章爬取完成立即進行情緒分析
564
  - **即時存檔**: 分析完成後立即保存到SQLite資料庫
565
  - **智能刷新**: 避免無意義的頁面閃爍
566
+ - **去重處理**: 智能檢測重複文章,降低重複度閾值
567
+
568
+ ### 🔍 多條件篩選
569
+ - **時間篩選**: 支援0-30天的時間範圍選擇
570
+ - **關鍵字搜尋**: 支援標題和內容的關鍵字搜尋
571
+ - **情緒篩選**: 可按正面、負面、中性情緒篩選
572
+ - **分類篩選**: 支援美股、台股分類查看
573
 
574
  ### 📊 情緒分析
575
+ - **混合模型**: RoBERTa模型 + 關鍵字分析
576
+ - **容錯處理**: 模型失敗時自動使用關鍵字分析
577
  - **準確性**: 針對中文金融新聞優化
578
 
579
  ### 🕷️ 新聞來源
580
  - **美股**: https://news.cnyes.com/news/cat/us_stock
581
  - **台股**: https://news.cnyes.com/news/cat/tw_stock_news
582
+ - **無限制**: 移除文章數量限制,爬取更多新聞
583
 
584
  ### 📱 介面優化
585
+ - **防閃爍**: 智能更新機制
586
+ - **多條件篩選**: 支援複合條件搜尋
587
+ - **即時反饋**: 詳細的搜尋結果統計
588
  """)
589
 
590
  return interface
 
603
  print("🚀 啟動股市新聞情緒分析器...")
604
  print("📊 網頁介面: http://localhost:7860")
605
  print("🔌 API接口: http://localhost:5000")
606
+ print("💡 新功能: 時間段篩選、關鍵字搜尋、情緒篩選")
607
 
608
  # 啟動Gradio介面
609
  interface = create_interface()