Spaces:
Sleeping
Sleeping
File size: 11,261 Bytes
ee199e4 a41e96c ae968de a41e96c ee199e4 a41e96c dd081fe a41e96c ae968de ee199e4 a41e96c ee199e4 a41e96c ee199e4 a41e96c ae968de a41e96c ee199e4 a41e96c ee199e4 a41e96c ee199e4 a41e96c ee199e4 a41e96c ee199e4 a41e96c dd081fe a41e96c ee199e4 a41e96c ee199e4 a41e96c ab26d2c a41e96c ab26d2c a41e96c ee199e4 a41e96c ab26d2c a41e96c ab26d2c a41e96c ee199e4 a41e96c ab26d2c a41e96c ee199e4 a41e96c ee199e4 a41e96c ee199e4 a41e96c ee199e4 a41e96c dd081fe a41e96c ee199e4 a41e96c ee199e4 a41e96c dd081fe | 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 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 | import gradio as gr
import requests
import pandas as pd
from dotenv import load_dotenv
import os
load_dotenv()
# --- 環境変数と定数の設定 ---
# NewsAPI設定
NEWS_API_URL = os.getenv("NEWS_API_URL", "https://newsapi.org/v2/everything")
NEWS_API_KEY = os.getenv("API_KEY")
# Alpha Vantage API設定
ALPHA_VANTAGE_API_URL = "https://www.alphavantage.co/query"
ALPHA_VANTAGE_API_KEY = os.getenv("ALPHA_VANTAGE_API_KEY") # 環境変数から読み込む
# --- ニュース検索機能 ---
def fetch_news(query="ecolab", sort_by="publishedAt", page_size=10, language="auto"):
"""
NewsAPIからニュース情報を取得する関数
"""
if not NEWS_API_KEY:
return pd.DataFrame(), "❌ NewsAPIのAPIキーが設定されていません。"
try:
headers = {
"X-API-Key": NEWS_API_KEY,
"User-Agent": "NewsApp/1.0"
}
params = {
"q": query,
"sortBy": sort_by,
"pageSize": page_size,
}
# 言語設定
if language in ["en", "jp"]:
params["language"] = language
elif language == "auto" and not any('\u3040' <= char <= '\u309F' or '\u30A0' <= char <= '\u30FF' or '\u4E00' <= char <= '\u9FAF' for char in query):
params["language"] = "en"
response = requests.get(NEWS_API_URL, headers=headers, params=params)
response.raise_for_status() # エラーがあれば例外を発生させる
data = response.json()
if data["status"] == "ok" and data["totalResults"] > 0:
articles = data["articles"]
news_data = [{
"タイトル": article.get("title"),
"説明": article.get("description"),
"ソース": article.get("source", {}).get("name"),
"公開日": article.get("publishedAt"),
"URL": article.get("url")
} for article in articles]
df = pd.DataFrame(news_data)
return df, f"✅ {len(articles)}件のニュースを取得しました"
else:
return pd.DataFrame(), "❌ ニュースが見つかりませんでした"
except requests.exceptions.RequestException as e:
return pd.DataFrame(), f"❌ APIリクエストエラー: {e}"
except Exception as e:
return pd.DataFrame(), f"❌ 不明なエラーが発生しました: {e}"
def search_news(query: str, sort_by: str, page_size: int, language: str):
if not query.strip():
return pd.DataFrame(), "❌ 検索キーワードを入力してください"
return fetch_news(query, sort_by, page_size, language)
# --- 暗号資産情報取得機能 ---
def fetch_crypto_data(function, symbol, market):
"""
Alpha Vantage APIから暗号資産の情報を取得する関数
"""
if not ALPHA_VANTAGE_API_KEY:
return pd.DataFrame(), "❌ Alpha VantageのAPIキーが設定されていません。"
if not symbol.strip() or not market.strip():
return pd.DataFrame(), "❌ 通貨シンボルと市場を両方入力してください。"
params = {
"apikey": ALPHA_VANTAGE_API_KEY,
"function": function
}
# functionに応じてパラメータを動的に設定
if function == "CURRENCY_EXCHANGE_RATE":
params["from_currency"] = symbol.strip()
params["to_currency"] = market.strip()
else:
params["symbol"] = symbol.strip()
params["market"] = market.strip()
try:
response = requests.get(ALPHA_VANTAGE_API_URL, params=params)
response.raise_for_status()
data = response.json()
# APIからのエラーメッセージをチェック
if "Error Message" in data:
return pd.DataFrame(), f"❌ APIエラー: {data['Error Message']}"
if "Information" in data:
return pd.DataFrame(), f"ℹ️ API情報: {data['Information']}"
if not data:
return pd.DataFrame(), "❌ APIから有効なデータが返されませんでした。"
# 取得したデータに応じてDataFrameに変換
if function == "CURRENCY_EXCHANGE_RATE":
key = "Realtime Currency Exchange Rate"
if key in data:
# データを整形してDataFrameに
rate_data = {
"項目": list(data[key].keys()),
"値": list(data[key].values())
}
df = pd.DataFrame(rate_data)
return df, f"✅ {symbol}/{market}のリアルタイム価格を取得しました。"
else:
return pd.DataFrame(), "❌ リアルタイム価格のデータを取得できませんでした。"
else: # 時系列データ (DAILY, WEEKLY, MONTHLY)
# "Time Series (...)" というキーを探す
ts_key = next((k for k in data.keys() if k.startswith("Time Series")), None)
if ts_key and data[ts_key]:
df = pd.DataFrame.from_dict(data[ts_key], orient='index')
df.index.name = "日付"
# カラム名を分かりやすく変更
df.columns = [col.split('. ')[1] for col in df.columns]
return df, f"✅ {symbol}/{market}の{function.replace('DIGITAL_CURRENCY_', '')}データを取得しました。"
else:
return pd.DataFrame(), "❌ 時系列データを取得できませんでした。シンボルや市場が正しいか確認してください。"
except requests.exceptions.RequestException as e:
return pd.DataFrame(), f"❌ APIリクエストエラー: {e}"
except Exception as e:
return pd.DataFrame(), f"❌ 不明なエラーが発生しました: {e}"
# --- Gradioインターフェース ---
with gr.Blocks(title="📰 総合情報検索アプリ", theme=gr.themes.Soft()) as demo:
gr.Markdown("# 📰 総合情報検索アプリ")
gr.Markdown("ニュース検索と暗号資産の価格情報を取得できます。")
with gr.Tabs():
# --- ニュース検索タブ ---
with gr.TabItem("📰 ニュース検索"):
gr.Markdown(
"""
**使い方:**
1. 検索キーワードを入力(日本語・英語両方対応)
2. 言語とソート方法を選択
3. 取得件数を選択
4. 「ニュース検索」ボタンをクリック
"""
)
with gr.Row():
with gr.Column(scale=1):
news_query_input = gr.Textbox(
label="🔍 検索キーワード",
placeholder="例: 東京, トヨタ, AI, technology...",
value="Ecolab"
)
language_dropdown = gr.Dropdown(
choices=[("自動検出", "auto"), ("日本語", "jp"), ("英語", "en"), ("すべての言語", "all")],
label="🌐 言語", value="auto"
)
sort_by_dropdown = gr.Dropdown(
choices=["publishedAt", "relevancy", "popularity"],
label="📊 ソート方法", value="publishedAt"
)
page_size_slider = gr.Slider(
minimum=5, maximum=50, value=10, step=5, label="📄 取得件数"
)
news_search_btn = gr.Button("🔍 ニュース検索", variant="primary")
with gr.Column(scale=3):
news_status_output = gr.Textbox(label="📋 ステータス", interactive=False)
news_results_df = gr.DataFrame(label="📰 ニュース結果", wrap=True, interactive=False)
# --- 暗号資産検索タブ ---
with gr.TabItem("🪙 暗号資産検索"):
gr.Markdown(
"""
**使い方:**
1. 取得したいデータの種類を選択
2. 暗号資産のシンボルを入力 (例: `BTC`, `ETH`)
3. 取引市場の通貨を入力 (例: `USD`, `EUR`)
4. 「データ取得」ボタンをクリック
**注:** `JPY`などの一部市場は、時系列データ(日足・週足・月足)でエラーになる場合があります。その際は`USD`など主要な市場をお試しください。
"""
)
with gr.Row():
with gr.Column(scale=1):
crypto_function_dropdown = gr.Dropdown(
label="📊 データ種別",
choices=[
("日足データ", "DIGITAL_CURRENCY_DAILY"),
("週足データ", "DIGITAL_CURRENCY_WEEKLY"),
("月足データ", "DIGITAL_CURRENCY_MONTHLY"),
("リアルタイム価格", "CURRENCY_EXCHANGE_RATE")
],
value="DIGITAL_CURRENCY_DAILY"
)
crypto_symbol_input = gr.Textbox(
label="🪙 通貨シンボル",
placeholder="例: BTC",
value="BTC"
)
crypto_market_input = gr.Textbox(
label="💴 取引市場",
placeholder="例: USD",
value="USD"
)
crypto_search_btn = gr.Button("🔍 データ取得", variant="primary")
with gr.Column(scale=3):
crypto_status_output = gr.Textbox(label="📋 ステータス", interactive=False)
crypto_results_df = gr.DataFrame(label="📈 暗号資産データ", wrap=True, interactive=False)
# --- イベントハンドラー ---
# ニュース検索
news_search_btn.click(
fn=search_news,
inputs=[news_query_input, sort_by_dropdown, page_size_slider, language_dropdown],
outputs=[news_results_df, news_status_output]
)
news_query_input.submit(
fn=search_news,
inputs=[news_query_input, sort_by_dropdown, page_size_slider, language_dropdown],
outputs=[news_results_df, news_status_output]
)
# 暗号資産検索
crypto_search_btn.click(
fn=fetch_crypto_data,
inputs=[crypto_function_dropdown, crypto_symbol_input, crypto_market_input],
outputs=[crypto_results_df, crypto_status_output]
)
# Enterキーでの実行(Textboxのみ)
for inp in [crypto_symbol_input, crypto_market_input]:
inp.submit(
fn=fetch_crypto_data,
inputs=[crypto_function_dropdown, crypto_symbol_input, crypto_market_input],
outputs=[crypto_results_df, crypto_status_output]
)
# 初期ロード時のデータ表示
demo.load(
fn=lambda: search_news("Ecolab", "publishedAt", 10, "auto"),
outputs=[news_results_df, news_status_output]
)
# アプリ起動
if __name__ == "__main__":
demo.launch()
|