NewsCheck / app.py
lune-lune's picture
Update app.py
93a4142 verified
import gradio as gr
from google import genai
import time
import os
# 外部ファイルの読み込み(news_collector.py と ai_analyst.py が同じ場所にある前提)
from news_collector import fetch_rss_news
from ai_analyst import analyze_news
def run_insight_process(api_key):
"""
ニュース取得から解析までを順次実行し、ログをリアルタイムで画面に返す関数
"""
if not api_key or len(api_key) < 10:
yield "❌ エラー: 有効なGemini APIキーをサイドバーに入力してください。"
return
# 新しいSDKではClientを渡す形が望ましい
# 新しいSDKではClientを渡す形が望ましいが、既存の構成を尊重して環境変数経由にする
log_output = "🚀 投資インサイト解析を開始します...\n"
yield log_output
try:
# 1. ニュース収集
log_output += "📡 ニュースサイトから最新記事を収集中...\n"
yield log_output
articles = fetch_rss_news()
if not articles:
yield log_output + "❌ ニュースの取得に失敗したか、記事が見つかりませんでした。"
return
log_output += f"✅ {len(articles)}件のニュースを取得しました。上位5件を解析します。\n\n"
yield log_output
# 2. 解析ループ(上位5件)
top_articles = articles[:5]
for i, article in enumerate(top_articles):
log_output += f"🔍 解析中 ({i+1}/{len(top_articles)}): {article['title']}\n"
yield log_output
# AI解析の実行
try:
res = analyze_news(article, api_key)
# スコアの数値化とバリデーション
try:
score = int(res.get('market_impact_score', 0))
except:
score = 0
# スコアに応じたアイコンと符号
if score > 0:
score_display = f"+{score}"
icon = "📈"
elif score < 0:
score_display = f"{score}"
icon = "📉"
else:
score_display = "0"
icon = "➖"
# レポートの構築(文字バラバラ対策済み)
report = f"===== 【分析結果】 {icon} スコア: {score_display} / 10 =====\n"
report += f"■ 歴史的類似性:\n{res.get('historical_precedent', '情報なし')}\n\n"
# リスト形式のデータ(弱気視点)が文章で返ってきた場合でも正しく表示する処理
report += f"■ 警戒すべきリスク/弱気視点:\n"
bearish = res.get('bearish_view', [])
if isinstance(bearish, list):
for r in bearish:
report += f" ・{str(r)}\n"
else:
report += f" ・{str(bearish)}\n"
# リスト形式のデータ(影響セクター)の表示処理
report += f"\n■ 影響セクター:\n"
sectors = res.get('sector_impact', [])
if isinstance(sectors, list):
report += f"{', '.join([str(s) for s in sectors])}\n"
else:
report += f"{str(sectors)}\n"
report += "==========================================\n\n"
log_output += report
yield log_output
except Exception as e:
log_output += f"⚠️ この記事の解析中にエラーが発生しました: {str(e)}\n\n"
yield log_output
# 無料枠のAPI制限を考慮して少し待機
if i < len(top_articles) - 1:
time.sleep(2)
log_output += "🎉 すべての解析作業が完了しました。"
yield log_output
except Exception as e:
yield log_output + f"\n❌ システムエラーが発生しました: {str(e)}"
# --- Gradio UIのデザイン ---
with gr.Blocks() as demo:
gr.Markdown("""
# 📈 AI投資インサイト・アナライザー
最新の経済ニュースを取得し、Gemini 2.5 Flashが投資判断を21段階でスコアリングします。
""")
with gr.Sidebar():
gr.Markdown("### 設定")
api_input = gr.Textbox(
label="1. Gemini API Key",
type="password",
placeholder="AI Studioのキーを貼り付け"
)
start_btn = gr.Button("解析実行", variant="primary")
gr.Markdown("---")
gr.Markdown("[APIキーの取得はこちら(無料)](https://aistudio.google.com/app/apikey)")
# 実行ログ兼レポート表示エリア
status_log = gr.Textbox(
label="実行ログおよび詳細レポート",
lines=30,
interactive=False
)
# ボタンクリック時の動作
start_btn.click(
fn=run_insight_process,
inputs=[api_input],
outputs=status_log
)
# アプリの起動
if __name__ == "__main__":
demo.launch(theme=gr.themes.Soft())