Spaces:
Sleeping
Sleeping
| 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") | |
| API_KEY = os.getenv("API_KEY") | |
| def fetch_news(query="ecolab", sort_by="publishedAt", page_size=10, language="auto"): | |
| """ | |
| NewsAPIからニュース情報を取得する関数 | |
| """ | |
| try: | |
| # NewsAPIの正しいヘッダー形式 | |
| headers = { | |
| "X-API-Key": API_KEY, | |
| "User-Agent": "NewsApp/1.0" | |
| } | |
| # 日本語検索の場合は日本語も含める | |
| params = { | |
| "q": query, | |
| "sortBy": sort_by, | |
| "pageSize": page_size, | |
| } | |
| # 言語設定を動的に決定 | |
| if language == "all": | |
| # すべての言語で検索(言語制限なし) | |
| pass | |
| elif language == "jp": | |
| # 日本語のソースも含めるため、言語制限を外すか日本語圏のソースを指定 | |
| pass # NewsAPIの日本語サポートは限定的なので制限を外す | |
| elif language == "en": | |
| params["language"] = "en" | |
| elif language == "auto": | |
| # 日本語文字が含まれている場合は言語制限を外す | |
| if any('\u3040' <= char <= '\u309F' or '\u30A0' <= char <= '\u30FF' or '\u4E00' <= char <= '\u9FAF' for char in query): | |
| pass # 言語制限なしで検索 | |
| else: | |
| params["language"] = "en" | |
| response = requests.get(NEWS_API_URL, headers=headers, params=params) | |
| if response.status_code == 200: | |
| data = response.json() | |
| if data["status"] == "ok" and data["totalResults"] > 0: | |
| articles = data["articles"] | |
| # データを整理 | |
| news_data = [] | |
| for article in articles: | |
| news_data.append({ | |
| "タイトル": article.get("title", "N/A"), | |
| "説明": article.get("description", "N/A"), | |
| "ソース": article.get("source", {}).get("name", "N/A"), | |
| "公開日": article.get("publishedAt", "N/A"), | |
| "URL": article.get("url", "N/A") | |
| }) | |
| # DataFrameに変換 | |
| df = pd.DataFrame(news_data) | |
| return df, f"✅ {len(articles)}件のニュースを取得しました" | |
| else: | |
| return pd.DataFrame(), "❌ ニュースが見つかりませんでした" | |
| else: | |
| return pd.DataFrame(), f"❌ APIエラー: {response.status_code} - {response.text}" | |
| except Exception as e: | |
| return pd.DataFrame(), f"❌ エラーが発生しました: {str(e)}" | |
| def search_news(query: str, sort_by: str, page_size: int, language: str = "auto"): | |
| """ | |
| Main function for searching news. | |
| Args: | |
| query (str): The search keyword for news articles. | |
| sort_by (str): The sorting method for the news results. | |
| page_size (int): The number of news articles to retrieve. | |
| language (str): Language for search results. | |
| Returns: | |
| tuple: DataFrame and status message | |
| """ | |
| if not query.strip(): | |
| return pd.DataFrame(), "❌ 検索キーワードを入力してください" | |
| df, message = fetch_news(query, sort_by, page_size, language) | |
| return df, message | |
| # Gradioインターフェース | |
| with gr.Blocks(title="📰 News API アプリ", theme=gr.themes.Soft()) as demo: | |
| gr.Markdown( | |
| """ | |
| # 📰 News API ニュース検索アプリ | |
| NewsAPIを使用してリアルタイムのニュース情報を検索・取得できます。 | |
| **🔥 日本語検索対応!** | |
| **使い方:** | |
| 1. 検索キーワードを入力(日本語・英語両方対応) | |
| 2. 言語とソート方法を選択 | |
| 3. 取得件数を選択 | |
| 4. 「ニュース検索」ボタンをクリック | |
| """ | |
| ) | |
| with gr.Row(): | |
| with gr.Column(): | |
| # 入力コンポーネント | |
| query_input = gr.Textbox( | |
| label="🔍 検索キーワード", | |
| placeholder="例: 東京, トヨタ, AI, ecolab, 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="📄 取得件数" | |
| ) | |
| search_btn = gr.Button("🔍 ニュース検索", variant="primary") | |
| with gr.Column(): | |
| # 出力コンポーネント | |
| status_output = gr.Textbox( | |
| label="📋 ステータス", | |
| interactive=False | |
| ) | |
| # 結果表示 | |
| results_df = gr.Dataframe( | |
| label="📰 ニュース結果", | |
| wrap=True, | |
| row_count=30, | |
| interactive=False | |
| ) | |
| # イベントハンドラー | |
| search_btn.click( | |
| fn=search_news, | |
| inputs=[query_input, sort_by_dropdown, page_size_slider, language_dropdown], | |
| outputs=[results_df, status_output], | |
| show_api=True, | |
| ) | |
| # Enter キーでも検索可能 | |
| query_input.submit( | |
| fn=search_news, | |
| inputs=[query_input, sort_by_dropdown, page_size_slider, language_dropdown], | |
| outputs=[results_df, status_output], | |
| show_api=False, | |
| ) | |
| # 初期ロード時にデフォルト検索を実行 | |
| demo.load( | |
| fn=lambda: search_news("ecolab", "publishedAt", 10, "auto"), | |
| outputs=[results_df, status_output], | |
| show_api=False, | |
| ) | |
| # アプリ起動 | |
| if __name__ == "__main__": | |
| demo.launch(mcp_server=True) | |