Add Gradio application and dependencies
Browse files- app.py +153 -0
- requirements.txt +5 -0
app.py
ADDED
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import pandas as pd
|
3 |
+
from datasets import load_dataset
|
4 |
+
from googletrans import Translator
|
5 |
+
from huggingface_hub import login
|
6 |
+
import os
|
7 |
+
|
8 |
+
# --- 定数と初期設定 ---
|
9 |
+
# Hugging Faceトークンを環境変数から取得
|
10 |
+
HF_TOKEN = os.environ.get("HF_TOKEN")
|
11 |
+
|
12 |
+
# --- グローバル変数 ---
|
13 |
+
# データは一度だけロードする
|
14 |
+
dataset = None
|
15 |
+
df = None
|
16 |
+
category_counts = None
|
17 |
+
|
18 |
+
# --- データ処理関数 ---
|
19 |
+
def load_and_process_data():
|
20 |
+
"""データセットをロードし、グローバル変数を初期化する"""
|
21 |
+
global dataset, df, category_counts
|
22 |
+
if dataset is not None:
|
23 |
+
return
|
24 |
+
|
25 |
+
try:
|
26 |
+
# トークンがあればログイン
|
27 |
+
if HF_TOKEN:
|
28 |
+
login(token=HF_TOKEN)
|
29 |
+
dataset = load_dataset("cais/hle", split="test")
|
30 |
+
# 画像データを扱うため、Pandasに変換するのはメタデータのみ
|
31 |
+
df = dataset.remove_columns(['image_preview', 'rationale_image']).to_pandas()
|
32 |
+
category_counts = df['category'].value_counts()
|
33 |
+
print("データセットのロードと前処理が完了しました。")
|
34 |
+
except Exception as e:
|
35 |
+
print(f"データセットのロードエラー: {e}")
|
36 |
+
# エラーが発生した場合、アプリがクラッシュしないように空のデータフレームを設定
|
37 |
+
df = pd.DataFrame(columns=['id', 'question', 'category'])
|
38 |
+
category_counts = pd.Series()
|
39 |
+
|
40 |
+
# --- 翻訳関数 ---
|
41 |
+
translator = Translator()
|
42 |
+
def translate_text(text, dest_lang='ja'):
|
43 |
+
if not text or not isinstance(text, str):
|
44 |
+
return ""
|
45 |
+
try:
|
46 |
+
# Translatorインスタンスを再利用
|
47 |
+
return translator.translate(text, dest=dest_lang).text
|
48 |
+
except Exception as e:
|
49 |
+
return f"翻訳エラー: {e}"
|
50 |
+
|
51 |
+
# --- Gradioイベントハンドラ ---
|
52 |
+
def on_category_change(selected_category):
|
53 |
+
"""カテゴリが変更されたときに、問題のドロップダウンを更新する"""
|
54 |
+
if selected_category == "全カテゴリ":
|
55 |
+
filtered_indices = df.index
|
56 |
+
else:
|
57 |
+
filtered_indices = df[df['category'] == selected_category].index
|
58 |
+
|
59 |
+
# 選択肢を (表示名, 値) のタプル形式で作成
|
60 |
+
question_choices = [
|
61 |
+
(f"{df.loc[idx, 'question'][:80]}...", idx) for idx in filtered_indices
|
62 |
+
]
|
63 |
+
|
64 |
+
if not question_choices:
|
65 |
+
# 選択肢がない場合は、表示をクリアし、選択不可にする
|
66 |
+
return gr.Dropdown(choices=[], label="問題 (該当なし)", interactive=False, value=None)
|
67 |
+
else:
|
68 |
+
return gr.Dropdown(choices=question_choices, label="問題を選択", interactive=True, value=question_choices[0][1])
|
69 |
+
|
70 |
+
def on_question_change(selected_index):
|
71 |
+
"""問題が選択されたときに、すべての詳細表示を更新する"""
|
72 |
+
if selected_index is None or pd.isna(selected_index):
|
73 |
+
# 空の出力をまとめて返す
|
74 |
+
empty_outputs = [gr.Markdown(visible=False)] * 6 + [gr.Image(visible=False)] * 2
|
75 |
+
return tuple(empty_outputs)
|
76 |
+
|
77 |
+
# 元のHugging Face Datasetから完全なエントリを取得
|
78 |
+
entry = dataset[int(selected_index)]
|
79 |
+
|
80 |
+
# 各要素の翻訳
|
81 |
+
q_trans = translate_text(entry['question'])
|
82 |
+
a_trans = translate_text(entry['answer'])
|
83 |
+
r_trans = translate_text(entry.get('rationale', ''))
|
84 |
+
|
85 |
+
# 出力コンポーネントの値を生成
|
86 |
+
outputs = {
|
87 |
+
"question_md": gr.Markdown(f"### 質問\n---\n**原文:**\n{entry['question']}\n\n**日本語訳:**\n{q_trans}", visible=True),
|
88 |
+
"question_img": gr.Image(entry.get('image_preview'), label="質問画像", visible=bool(entry.get('image_preview'))),
|
89 |
+
"answer_md": gr.Markdown(f"### 回答\n---\n**原文:**\n{entry['answer']}\n\n**日本語訳:**\n{a_trans}", visible=True),
|
90 |
+
"rationale_md": gr.Markdown(f"### 解説\n---\n**原文:**\n{entry.get('rationale', 'N/A')}\n\n**日本語訳:**\n{r_trans}", visible=bool(entry.get('rationale'))),
|
91 |
+
"rationale_img": gr.Image(entry.get('rationale_image'), label="解説画像", visible=bool(entry.get('rationale_image'))),
|
92 |
+
"metadata_md": gr.Markdown(f"**ID:** `{entry['id']}`<br>**分野:** `{entry['raw_subject']}`<br>**回答タイプ:** `{entry['answer_type']}`", visible=True),
|
93 |
+
"json_output": gr.JSON({k: str(v) for k, v in entry.items()}, label="元のデータ", visible=True)
|
94 |
+
}
|
95 |
+
|
96 |
+
# 定義された順序で値を返す
|
97 |
+
return (
|
98 |
+
outputs["question_md"],
|
99 |
+
outputs["question_img"],
|
100 |
+
outputs["answer_md"],
|
101 |
+
outputs["rationale_md"],
|
102 |
+
outputs["rationale_img"],
|
103 |
+
outputs["metadata_md"],
|
104 |
+
outputs["json_output"]
|
105 |
+
)
|
106 |
+
|
107 |
+
# --- Gradio UI構築 ---
|
108 |
+
def create_demo():
|
109 |
+
# アプリケーション起動時に一度だけデータをロード
|
110 |
+
load_and_process_data()
|
111 |
+
|
112 |
+
with gr.Blocks(theme=gr.themes.Soft(), title="HLE Dataset Viewer") as demo:
|
113 |
+
gr.Markdown("# Humanity's Last Exam (HLE) Dataset Viewer")
|
114 |
+
gr.Markdown("Hugging Face `cais/hle`データセットを探索し、日本語訳を確認できます。")
|
115 |
+
|
116 |
+
with gr.Row():
|
117 |
+
with gr.Column(scale=1, min_width=350):
|
118 |
+
gr.Markdown("## 操作パネル")
|
119 |
+
category_dd = gr.Dropdown(
|
120 |
+
choices=["全カテゴリ"] + sorted(category_counts.index.tolist()),
|
121 |
+
value="全カテゴリ",
|
122 |
+
label="1. カテゴリを選択"
|
123 |
+
)
|
124 |
+
question_dd = gr.Dropdown(label="2. 問題を選択", interactive=False)
|
125 |
+
|
126 |
+
gr.Markdown("### カテゴリ別問題数")
|
127 |
+
gr.Dataframe(value=pd.DataFrame(category_counts).reset_index(), headers=['カテゴリ', '問題数'], interactive=False)
|
128 |
+
|
129 |
+
with gr.Column(scale=3):
|
130 |
+
# 出力エリアのプレースホルダー
|
131 |
+
metadata_md = gr.Markdown(visible=False)
|
132 |
+
question_md = gr.Markdown(visible=False)
|
133 |
+
question_img = gr.Image(label="質問画像", visible=False)
|
134 |
+
answer_md = gr.Markdown(visible=False)
|
135 |
+
rationale_md = gr.Markdown(visible=False)
|
136 |
+
rationale_img = gr.Image(label="解説画像", visible=False)
|
137 |
+
json_output = gr.JSON(label="元のデータ", visible=False)
|
138 |
+
|
139 |
+
# イベントリスナーを設定
|
140 |
+
category_dd.change(fn=on_category_change, inputs=category_dd, outputs=question_dd)
|
141 |
+
question_dd.change(fn=on_question_change, inputs=question_dd, outputs=[
|
142 |
+
question_md, question_img, answer_md, rationale_md, rationale_img, metadata_md, json_output
|
143 |
+
])
|
144 |
+
|
145 |
+
# 初期表示のために最初のカテゴリ変更イベントをトリガー
|
146 |
+
demo.load(fn=on_category_change, inputs=category_dd, outputs=question_dd)
|
147 |
+
|
148 |
+
return demo
|
149 |
+
|
150 |
+
# --- アプリケーション起動 ---
|
151 |
+
if __name__ == "__main__":
|
152 |
+
app = create_demo()
|
153 |
+
app.launch()
|
requirements.txt
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
gradio
|
2 |
+
datasets
|
3 |
+
pandas
|
4 |
+
googletrans==4.0.0-rc1
|
5 |
+
huggingface_hub
|