import streamlit as st import feedparser from transformers import pipeline import requests import datetime # Streamlitの設定 st.set_page_config(page_title="今日のテクノロジーニュース", layout="wide") st.title("📡 今日のテクノロジーニュース") # RSSフィードのURL rss_url = "https://rss.nytimes.com/services/xml/rss/nyt/Technology.xml" # 利用可能な翻訳モデルのリスト models = [ { "name": "facebook/nllb-200-distilled-600M", "description": "Translation • Updated Feb 15 • 322k • 504", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "facebook/mbart-large-50-many-to-many-mmt", "description": "Translation • Updated Sep 29, 2023 • 646k • 278", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "facebook/nllb-200-3.3B", "description": "Translation • Updated Feb 12, 2023 • 28.9k • 249", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "google/madlad400-10b-mt", "description": "Translation • Updated Apr 12 • 1.76k • 84", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "ken11/mbart-ja-en", "description": "Translation • Updated Oct 13, 2021 • 63 • 3", "src_lang": "jpn_Jpan", "tgt_lang": "eng_Latn" }, { "name": "facebook/nllb-200-1.3B", "description": "Translation • Updated Feb 12, 2023 • 14.6k • 44", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "facebook/nllb-200-distilled-1.3B", "description": "Translation • Updated Feb 12, 2023 • 101k • 98", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "alirezamsh/small100", "description": "Translation • Updated Jul 23 • 1.85k • 60", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "Unbabel/wmt22-cometkiwi-da", "description": "Translation • Updated Oct 13, 2023 • 1 • 24", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "ychenNLP/nllb-200-3.3B-easyproject", "description": "Translation • Updated Aug 30, 2023 • 73 • 2", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "JustFrederik/sugoi-v3.3-ja-en-ct2-float16", "description": "Translation • Updated May 10, 2023 • 2", "src_lang": "jpn_Jpan", "tgt_lang": "eng_Latn" }, { "name": "JustFrederik/sugoi-v3.3-ja-en-ct2-int8", "description": "Translation • Updated May 10, 2023 • 22 • 1", "src_lang": "jpn_Jpan", "tgt_lang": "eng_Latn" }, { "name": "JustFrederik/sugoi-v4-ja-en-ct2-float16", "description": "Translation • Updated May 10, 2023 • 13 • 1", "src_lang": "jpn_Jpan", "tgt_lang": "eng_Latn" }, { "name": "JustFrederik/sugoi-v4-ja-en-ct2-int8", "description": "Translation • Updated May 10, 2023", "src_lang": "jpn_Jpan", "tgt_lang": "eng_Latn" }, { "name": "JustFrederik/sugoi-v4-ja-en-ct2", "description": "Translation • Updated May 10, 2023 • 20 • 1", "src_lang": "jpn_Jpan", "tgt_lang": "eng_Latn" }, { "name": "JustFrederik/sugoi-v3.3-ja-en-ct2", "description": "Translation • Updated May 10, 2023", "src_lang": "jpn_Jpan", "tgt_lang": "eng_Latn" }, { "name": "JustFrederik/nllb-200-distilled-600M-ct2-int8", "description": "Translation • Updated May 15, 2023 • 225", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "JustFrederik/nllb-200-distilled-1.3B-ct2-int8", "description": "Translation • Updated May 15, 2023 • 74 • 1", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "JustFrederik/nllb-200-1.3B-ct2-int8", "description": "Translation • Updated May 15, 2023 • 12", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "JustFrederik/nllb-200-1.3B-ct2-float16", "description": "Translation • Updated May 15, 2023 • 6", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "JustFrederik/nllb-200-1.3B-ct2", "description": "Translation • Updated May 15, 2023 • 14", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "JustFrederik/nllb-200-distilled-1.3B-ct2", "description": "Translation • Updated May 15, 2023 • 3", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "JustFrederik/nllb-200-distilled-1.3B-ct2-float16", "description": "Translation • Updated May 15, 2023 • 7 • 1", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "JustFrederik/nllb-200-distilled-600M-ct2", "description": "Translation • Updated May 15, 2023 • 4", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "JustFrederik/nllb-200-distilled-600M-ct2-float16", "description": "Translation • Updated May 15, 2023 • 8", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "JustFrederik/nllb-200-3.3B-ct2-float16", "description": "Translation • Updated May 15, 2023 • 26 • 3", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "Babelscape/mrebel-large", "description": "Translation • Updated Jun 21, 2023 • 67.5k • 66", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "Babelscape/mrebel-large-32", "description": "Translation • Updated Jun 23, 2023 • 97 • 6", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "Babelscape/mrebel-base", "description": "Translation • Updated Jun 23, 2023 • 66 • 5", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "winstxnhdw/nllb-200-distilled-1.3B-ct2-int8", "description": "Translation • Updated Aug 3, 2023 • 2.42k • 4", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "michaelfeil/ct2fast-nllb-200-distilled-1.3B", "description": "Translation • Updated Dec 10, 2023 • 10 • 1", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "michaelfeil/ct2fast-nllb-200-3.3B", "description": "Translation • Updated Jul 21, 2023 • 36 • 11", "src_lang": "eng_Latn", "tgt_lang": "jpn_Jpan" }, { "name": "qiyuw/WSPAlign-xlm-base", "description": "Translation • Updated Mar 18 • 4", "src_lang": "xlm_Latn", "tgt_lang": "jpn_Jpan" }, # 既存のモデルを以下に追加できます ] # プルダウンメニューでモデルを選択 st.sidebar.header("翻訳モデルの選択") selected_model = st.sidebar.selectbox( "使用する翻訳モデルを選択してください:", options=models, format_func=lambda x: f"{x['name']} - {x['description']}" ) @st.cache_resource def load_translation_model(model_name, src_lang, tgt_lang): """ 選択された翻訳モデルをロードし、キャッシュします。 """ try: translator = pipeline( "translation", model=model_name, src_lang=src_lang, tgt_lang=tgt_lang ) return translator except Exception as e: st.error(f"翻訳モデルのロード中にエラーが発生しました: {e}") return None @st.cache_data def translate_text(_translator, text): """ テキストを日本語に翻訳します。 翻訳結果をキャッシュします。 """ if not _translator: return "翻訳エラー" try: translation = _translator(text, max_length=500)[0]['translation_text'] return translation except Exception as e: st.error(f"翻訳中にエラーが発生しました: {e}") return "翻訳エラー" @st.cache_data(ttl=3600) def fetch_rss_feed(url): """ RSSフィードを取得し、XMLを保存してパースします。 キャッシュの有効期限は1時間です。 """ try: response = requests.get(url) if response.status_code != 200: st.error(f"RSSフィードの取得に失敗しました。ステータスコード: {response.status_code}") return None # フィードのXMLを保存(データセットとして蓄積) now = datetime.datetime.now() filename = now.strftime("feed_%Y%m%d_%H%M%S.xml") with open(filename, 'wb') as f: f.write(response.content) # フィードをパース feed = feedparser.parse(response.content) return feed except Exception as e: st.error(f"RSSフィードの取得中にエラーが発生しました: {e}") return None # フィードを取得 feed = fetch_rss_feed(rss_url) if feed is None: st.stop() # フィードの取得に失敗した場合、アプリを停止します # 翻訳モデルをロード translator = load_translation_model(selected_model['name'], selected_model['src_lang'], selected_model['tgt_lang']) # フィード内の記事をパースしてタイトルと説明を翻訳 for entry in feed.entries: # タイトルと説明を取得 title = entry.title description = entry.description # タイトルと説明を日本語に翻訳(翻訳結果をキャッシュ) translated_title = translate_text(translator, title) translated_description = translate_text(translator, description) # Markdown形式で表示 st.markdown(f"### **タイトル(英語):** {title}") st.markdown(f"**タイトル(日本語):** {translated_title}") st.markdown(f"**概要(英語):**") st.write(description) st.markdown(f"**概要(日本語):**") st.write(translated_description) st.markdown(f"[🌐 続きを読む]({entry.link})") st.markdown("---") # キャッシュをクリアするボタン if st.button("キャッシュをクリア"): load_translation_model.clear(selected_model['name'], selected_model['src_lang'], selected_model['tgt_lang']) translate_text.clear() fetch_rss_feed.clear() st.success("キャッシュをクリアしました。")