Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -45,7 +45,6 @@ def load_prompt(level):
|
|
| 45 |
def chat_process(message, display_history, full_logs, prompt_level):
|
| 46 |
"""
|
| 47 |
チャット処理を行う関数
|
| 48 |
-
Stateの更新漏れを防ぐため、リストは + 演算子で新しく生成して返す
|
| 49 |
"""
|
| 50 |
if display_history is None: display_history = []
|
| 51 |
if full_logs is None: full_logs = []
|
|
@@ -58,7 +57,6 @@ def chat_process(message, display_history, full_logs, prompt_level):
|
|
| 58 |
"timestamp": current_time_user
|
| 59 |
}
|
| 60 |
|
| 61 |
-
# 【修正】appendではなく新しいリストを作成して結合 (State更新を確実にするため)
|
| 62 |
temp_display = display_history + [user_msg_data]
|
| 63 |
temp_logs = full_logs + [user_msg_data]
|
| 64 |
|
|
@@ -72,7 +70,6 @@ def chat_process(message, display_history, full_logs, prompt_level):
|
|
| 72 |
ai_response = ""
|
| 73 |
try:
|
| 74 |
model_name = "google/gemini-2.5-flash"
|
| 75 |
-
# model_name = "google/gemma-3-27b-it:free"
|
| 76 |
|
| 77 |
response = client.chat.completions.create(
|
| 78 |
model=model_name,
|
|
@@ -98,11 +95,9 @@ def chat_process(message, display_history, full_logs, prompt_level):
|
|
| 98 |
"timestamp": current_time_ai
|
| 99 |
}
|
| 100 |
|
| 101 |
-
# 【修正】最終的な新しいリストを作成
|
| 102 |
new_display = temp_display + [ai_msg_data]
|
| 103 |
new_logs = temp_logs + [ai_msg_data]
|
| 104 |
|
| 105 |
-
# 戻り値: (入力欄クリア, Chatbot表示更新, 画面用State更新, 保存用State更新)
|
| 106 |
return "", new_display, new_display, new_logs
|
| 107 |
|
| 108 |
def change_difficulty_logic(new_level, full_logs):
|
|
@@ -124,20 +119,17 @@ def change_difficulty_logic(new_level, full_logs):
|
|
| 124 |
"timestamp": current_time
|
| 125 |
}
|
| 126 |
|
| 127 |
-
# 新しい画面用履歴(これまでの会話は消え、通知だけ入る)
|
| 128 |
new_display_history = [msg_data]
|
| 129 |
-
|
| 130 |
-
# 【修正】全保存用履歴には追記する(新しいリストを作成)
|
| 131 |
new_full_logs = full_logs + [msg_data]
|
| 132 |
|
| 133 |
-
# 戻り値: (Chatbot表示更新, 画面用State更新, 保存用State更新, 難易度State更新)
|
| 134 |
return new_display_history, new_display_history, new_full_logs, new_level
|
| 135 |
|
| 136 |
def export_csv_logic(user_id, user_name, full_logs):
|
| 137 |
print(f"Exporting CSV for UserID: {user_id}, Name: '{user_name}'")
|
| 138 |
|
| 139 |
if not user_name or not user_name.strip():
|
| 140 |
-
|
|
|
|
| 141 |
return None
|
| 142 |
|
| 143 |
if not full_logs:
|
|
@@ -168,6 +160,18 @@ def export_csv_logic(user_id, user_name, full_logs):
|
|
| 168 |
gr.Warning(f"CSV保存エラー: {e}")
|
| 169 |
return None
|
| 170 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
# --- UI Definition ---
|
| 172 |
with gr.Blocks() as demo:
|
| 173 |
# ステート定義
|
|
@@ -176,43 +180,64 @@ with gr.Blocks() as demo:
|
|
| 176 |
full_logs_state = gr.State([]) # 保存用
|
| 177 |
prompt_level_state = gr.State("Beginner")
|
| 178 |
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 182 |
user_name_input = gr.Textbox(
|
| 183 |
-
label="お名前
|
| 184 |
-
placeholder="
|
| 185 |
scale=2
|
| 186 |
)
|
| 187 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 188 |
|
| 189 |
-
|
| 190 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 191 |
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
label="
|
| 196 |
-
|
| 197 |
-
interactive=True
|
| 198 |
)
|
|
|
|
| 199 |
|
| 200 |
-
#
|
| 201 |
-
chatbot = gr.Chatbot(type="messages", height=500)
|
| 202 |
-
|
| 203 |
-
# 入力エリア
|
| 204 |
-
msg_input = gr.Textbox(
|
| 205 |
-
placeholder="メッセージを入力してください... (Enterで送信)",
|
| 206 |
-
label="Chat Input",
|
| 207 |
-
lines=1
|
| 208 |
-
)
|
| 209 |
-
send_btn = gr.Button("送信", variant="primary")
|
| 210 |
|
| 211 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 212 |
|
| 213 |
-
#
|
| 214 |
-
# 入力: [メッセージ, 画面履歴, 保存履歴, 難易度]
|
| 215 |
-
# 出力: [入力欄, チャットボット, 画面履歴State, 保存履歴State] ← 全て更新する
|
| 216 |
chat_event_args = {
|
| 217 |
"fn": chat_process,
|
| 218 |
"inputs": [msg_input, display_history_state, full_logs_state, prompt_level_state],
|
|
@@ -222,16 +247,15 @@ with gr.Blocks() as demo:
|
|
| 222 |
msg_input.submit(**chat_event_args)
|
| 223 |
send_btn.click(**chat_event_args)
|
| 224 |
|
| 225 |
-
#
|
| 226 |
-
# 入力: [難易度, 保存履歴]
|
| 227 |
-
# 出力: [チャットボット, 画面履歴State, 保存履歴State, 難易度State] ← 全て更新する
|
| 228 |
level_radio.change(
|
| 229 |
fn=change_difficulty_logic,
|
| 230 |
inputs=[level_radio, full_logs_state],
|
| 231 |
outputs=[chatbot, display_history_state, full_logs_state, prompt_level_state]
|
| 232 |
)
|
| 233 |
|
| 234 |
-
#
|
|
|
|
| 235 |
export_btn.click(
|
| 236 |
fn=export_csv_logic,
|
| 237 |
inputs=[user_id_state, user_name_input, full_logs_state],
|
|
|
|
| 45 |
def chat_process(message, display_history, full_logs, prompt_level):
|
| 46 |
"""
|
| 47 |
チャット処理を行う関数
|
|
|
|
| 48 |
"""
|
| 49 |
if display_history is None: display_history = []
|
| 50 |
if full_logs is None: full_logs = []
|
|
|
|
| 57 |
"timestamp": current_time_user
|
| 58 |
}
|
| 59 |
|
|
|
|
| 60 |
temp_display = display_history + [user_msg_data]
|
| 61 |
temp_logs = full_logs + [user_msg_data]
|
| 62 |
|
|
|
|
| 70 |
ai_response = ""
|
| 71 |
try:
|
| 72 |
model_name = "google/gemini-2.5-flash"
|
|
|
|
| 73 |
|
| 74 |
response = client.chat.completions.create(
|
| 75 |
model=model_name,
|
|
|
|
| 95 |
"timestamp": current_time_ai
|
| 96 |
}
|
| 97 |
|
|
|
|
| 98 |
new_display = temp_display + [ai_msg_data]
|
| 99 |
new_logs = temp_logs + [ai_msg_data]
|
| 100 |
|
|
|
|
| 101 |
return "", new_display, new_display, new_logs
|
| 102 |
|
| 103 |
def change_difficulty_logic(new_level, full_logs):
|
|
|
|
| 119 |
"timestamp": current_time
|
| 120 |
}
|
| 121 |
|
|
|
|
| 122 |
new_display_history = [msg_data]
|
|
|
|
|
|
|
| 123 |
new_full_logs = full_logs + [msg_data]
|
| 124 |
|
|
|
|
| 125 |
return new_display_history, new_display_history, new_full_logs, new_level
|
| 126 |
|
| 127 |
def export_csv_logic(user_id, user_name, full_logs):
|
| 128 |
print(f"Exporting CSV for UserID: {user_id}, Name: '{user_name}'")
|
| 129 |
|
| 130 |
if not user_name or not user_name.strip():
|
| 131 |
+
# Start画面でチェックしているので基本ここには来ないはずだが念のため
|
| 132 |
+
gr.Warning("名前が正しく取得できませんでした")
|
| 133 |
return None
|
| 134 |
|
| 135 |
if not full_logs:
|
|
|
|
| 160 |
gr.Warning(f"CSV保存エラー: {e}")
|
| 161 |
return None
|
| 162 |
|
| 163 |
+
# --- 新規追加: スタートボタン処理 ---
|
| 164 |
+
def start_app_logic(user_name):
|
| 165 |
+
"""
|
| 166 |
+
名前が入力されているか確認し、画面表示を切り替える
|
| 167 |
+
"""
|
| 168 |
+
if not user_name or not user_name.strip():
|
| 169 |
+
raise gr.Error("お名前を入力してください。")
|
| 170 |
+
|
| 171 |
+
# Start画面を隠し(False)、Main画面を表示(True)
|
| 172 |
+
return gr.update(visible=False), gr.update(visible=True)
|
| 173 |
+
|
| 174 |
+
|
| 175 |
# --- UI Definition ---
|
| 176 |
with gr.Blocks() as demo:
|
| 177 |
# ステート定義
|
|
|
|
| 180 |
full_logs_state = gr.State([]) # 保存用
|
| 181 |
prompt_level_state = gr.State("Beginner")
|
| 182 |
|
| 183 |
+
# =========================================
|
| 184 |
+
# 1. スタート画面 (初期状態: 表示)
|
| 185 |
+
# =========================================
|
| 186 |
+
with gr.Column(visible=True) as start_screen:
|
| 187 |
+
gr.Markdown("# AI Chatbot System")
|
| 188 |
+
gr.Markdown("学習を始めるには、お名前を入力して「解答開始」を押してください。")
|
| 189 |
+
|
| 190 |
+
# 名前入力欄をここに移動
|
| 191 |
user_name_input = gr.Textbox(
|
| 192 |
+
label="お名前",
|
| 193 |
+
placeholder="山田 太郎",
|
| 194 |
scale=2
|
| 195 |
)
|
| 196 |
+
|
| 197 |
+
start_btn = gr.Button("解答開始", variant="primary", size="lg")
|
| 198 |
+
|
| 199 |
+
# =========================================
|
| 200 |
+
# 2. メインチャット画面 (初期状態: 非表示)
|
| 201 |
+
# =========================================
|
| 202 |
+
with gr.Column(visible=False) as main_screen:
|
| 203 |
+
gr.Markdown("# Multi-Level AI Chatbot")
|
| 204 |
+
|
| 205 |
+
with gr.Row():
|
| 206 |
+
# エクスポートボタンのみここに配置(名前はstart_screenのものを使用)
|
| 207 |
+
export_btn = gr.DownloadButton("📥 会話をCSVで保存", scale=1)
|
| 208 |
|
| 209 |
+
with gr.Row():
|
| 210 |
+
gr.Markdown("## 問題の難易度を選択してください(初級から順番に取り組んでください)")
|
| 211 |
+
|
| 212 |
+
with gr.Row():
|
| 213 |
+
level_radio = gr.Radio(
|
| 214 |
+
["Beginner", "Intermediate", "Advanced"],
|
| 215 |
+
label="Difficulty Level",
|
| 216 |
+
value="Beginner",
|
| 217 |
+
interactive=True
|
| 218 |
+
)
|
| 219 |
+
|
| 220 |
+
# Chatbotコンポーネント
|
| 221 |
+
chatbot = gr.Chatbot(type="messages", height=500)
|
| 222 |
|
| 223 |
+
# 入力エリア
|
| 224 |
+
msg_input = gr.Textbox(
|
| 225 |
+
placeholder="メッセージを入力してください... (Enterで送信)",
|
| 226 |
+
label="Chat Input",
|
| 227 |
+
lines=1
|
|
|
|
| 228 |
)
|
| 229 |
+
send_btn = gr.Button("送信", variant="primary")
|
| 230 |
|
| 231 |
+
# --- Event Handling ---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 232 |
|
| 233 |
+
# A. スタートボタンの処理 (新規)
|
| 234 |
+
start_btn.click(
|
| 235 |
+
fn=start_app_logic,
|
| 236 |
+
inputs=[user_name_input],
|
| 237 |
+
outputs=[start_screen, main_screen]
|
| 238 |
+
)
|
| 239 |
|
| 240 |
+
# B. メッセージ送信時の処理
|
|
|
|
|
|
|
| 241 |
chat_event_args = {
|
| 242 |
"fn": chat_process,
|
| 243 |
"inputs": [msg_input, display_history_state, full_logs_state, prompt_level_state],
|
|
|
|
| 247 |
msg_input.submit(**chat_event_args)
|
| 248 |
send_btn.click(**chat_event_args)
|
| 249 |
|
| 250 |
+
# C. 難易度変更時の処理
|
|
|
|
|
|
|
| 251 |
level_radio.change(
|
| 252 |
fn=change_difficulty_logic,
|
| 253 |
inputs=[level_radio, full_logs_state],
|
| 254 |
outputs=[chatbot, display_history_state, full_logs_state, prompt_level_state]
|
| 255 |
)
|
| 256 |
|
| 257 |
+
# D. CSV保存処理
|
| 258 |
+
# 注意: start_screenにある user_name_input の値を読み取ります(非表示でも値は残ります)
|
| 259 |
export_btn.click(
|
| 260 |
fn=export_csv_logic,
|
| 261 |
inputs=[user_id_state, user_name_input, full_logs_state],
|