Toya0421 commited on
Commit
69154a3
·
verified ·
1 Parent(s): 9fd939c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +137 -119
app.py CHANGED
@@ -3,7 +3,7 @@ from openai import OpenAI
3
  from datasets import Dataset
4
  from datetime import datetime, timedelta
5
  import pandas as pd
6
- import time, os, random, tempfile, json
7
 
8
  # --- API / HF 設定 ---
9
  API_KEY = os.getenv("API_KEY")
@@ -14,8 +14,8 @@ LOG_FILE = "reading_logs.csv"
14
 
15
  client = OpenAI(base_url=BASE_URL, api_key=API_KEY)
16
 
17
- # --- passage.csv 読み込み ---
18
- passages_df = pd.read_csv("passage.csv")
19
 
20
  # --- 状態変数 ---
21
  used_passages = set()
@@ -23,19 +23,78 @@ current_user_id = None
23
  current_level = None
24
 
25
 
26
- def rewrite_level(text, target_level): # 変更点
 
 
27
 
 
 
 
 
 
 
 
 
 
28
 
29
- # --- Level → Flesch Reading Ease Score の変換表 ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  level_to_flesch = {
31
- 1: 90, # 例: とても易しい
32
- 2: 70, # 例: 易しい
33
- 3: 55, # 例: 標準
34
- 4: 40, # 例: やや難しい
35
- 5: 25 # 例: 難しい
36
  }
37
 
38
- # target_level を Flesch Score に変換(デフォルト 55)
39
  target_flesch = level_to_flesch[int(target_level)]
40
 
41
  prompt = f"""
@@ -43,10 +102,9 @@ Rewrite the following passage so it fits about {target_flesch} Flesch Reading Ea
43
  - Preserve the original meaning faithfully.
44
  - Do not add new information or remove essential information.
45
  - Output only the rewritten passage. Do not include explanations.
46
-
47
-
48
  {text}
49
  """
 
50
  resp = client.chat.completions.create(
51
  model="google/gemma-3-27b-it:free",
52
  messages=[{"role": "user", "content": prompt}],
@@ -56,29 +114,14 @@ Rewrite the following passage so it fits about {target_flesch} Flesch Reading Ea
56
  return resp.choices[0].message.content.strip()
57
 
58
 
59
- def split_pages(text, words=120): #ページ分割
60
  w = text.split()
61
- pages = [" ".join(w[i:i+words]) for i in range(0, len(w), words)]
62
- return pages if pages else [text]
63
 
64
 
65
- def get_new_passage_random():
66
- """ジャンル関係なくランダムに取得"""
67
- global used_passages
68
- df = passages_df
69
-
70
- available = [pid for pid in df["passage_id"].unique() if pid not in used_passages]
71
- if not available:
72
- used_passages.clear()
73
- available = list(df["passage_id"].unique())
74
-
75
- pid = random.choice(available)
76
- row = df[df["passage_id"] == pid].iloc[0]
77
-
78
- used_passages.add(pid)
79
-
80
- return pid, row["text"], row.get("original_level", None)
81
-
82
 
83
  def save_log(entry):
84
  df = pd.DataFrame([entry])
@@ -86,7 +129,7 @@ def save_log(entry):
86
  df.to_csv(LOG_FILE, mode="a", index=False, header=False)
87
  else:
88
  df.to_csv(LOG_FILE, index=False)
89
- # push to HF
90
  all_logs = pd.read_csv(LOG_FILE)
91
  tmp_dir = tempfile.mkdtemp()
92
  tmp_path = os.path.join(tmp_dir, "data.parquet")
@@ -95,13 +138,12 @@ def save_log(entry):
95
  dataset.push_to_hub(DATASET_REPO, token=HF_TOKEN)
96
 
97
 
98
- # ============================
99
- # コールバック
100
- # ============================
101
 
102
  def start_test(student_id, level_input):
103
- """開始:ジャンル選択なし版"""
104
- global current_user_id, current_level, used_passages # 変更点
105
  used_passages = set()
106
 
107
  action = "start_pushed"
@@ -109,7 +151,7 @@ def start_test(student_id, level_input):
109
 
110
  entry = {
111
  "user_id": student_id,
112
- "assigned_level": current_level, # 変更点
113
  "passage_id": None,
114
  "original_level": None,
115
  "action_time": now,
@@ -119,17 +161,16 @@ def start_test(student_id, level_input):
119
  save_log(entry)
120
 
121
  if not student_id or str(student_id).strip() == "":
122
- # 初期無効状態
123
  return (
124
  "", "", json.dumps([]), 0, "",
125
  0, "", None, None,
126
- gr.update(interactive=False, visible=False), # prev_btn
127
- gr.update(interactive=False, visible=True), # next_btn (visible but disabled)
128
- gr.update(interactive=False, visible=False) # finish_btn (hidden)
129
  )
130
 
131
  current_user_id = str(student_id).strip()
132
- current_level = int(level_input) # 変更点
133
 
134
  pid, text, orig_lev = get_new_passage_random()
135
  if text is None:
@@ -141,22 +182,22 @@ def start_test(student_id, level_input):
141
  gr.update(interactive=False, visible=False)
142
  )
143
 
144
- rewritten = rewrite_level(text, current_level) # 変更点
145
  pages = split_pages(rewritten)
146
  total = len(pages)
147
 
148
- # 最初のページ設定
149
- prev_upd = gr.update(interactive=False, visible=False)
150
- # next_btn は常に visible、ただしページ数1なら非表示して finish を表示する
151
  if total == 1:
 
152
  next_upd = gr.update(interactive=False, visible=False)
153
  finish_upd = gr.update(interactive=True, visible=True)
154
  else:
 
155
  next_upd = gr.update(interactive=True, visible=True)
156
  finish_upd = gr.update(interactive=False, visible=False)
157
 
158
  page_num = 1
159
  now = (datetime.utcnow() + timedelta(hours=9)).isoformat()
 
160
  entry = {
161
  "user_id": current_user_id,
162
  "assigned_level": current_level,
@@ -167,6 +208,7 @@ def start_test(student_id, level_input):
167
  "page_text": pages[0]
168
  }
169
  save_log(entry)
 
170
  return (
171
  pages[0],
172
  f"1 / {total}",
@@ -182,31 +224,30 @@ def start_test(student_id, level_input):
182
  )
183
 
184
 
 
 
 
 
185
  def next_page(pages_json, current_page, total_pages, pid, orig_lev):
186
  now = (datetime.utcnow() + timedelta(hours=9)).isoformat()
187
 
188
- action = "next_pushed"
189
-
190
  entry = {
191
  "user_id": current_user_id,
192
- "assigned_level": current_level, # 変更点
193
  "passage_id": pid,
194
  "original_level": orig_lev,
195
  "action_time": now,
196
- "action_type": action,
197
  "page_text": None
198
  }
199
  save_log(entry)
200
-
201
  pages = json.loads(pages_json)
202
  if not pages:
203
- # 安全措置
204
- return (
205
- "", "", json.dumps([]), 0,
206
- gr.update(interactive=False, visible=False),
207
- gr.update(interactive=False, visible=False),
208
- gr.update(interactive=False, visible=False)
209
- )
210
 
211
  new_page = min(current_page + 1, total_pages - 1)
212
 
@@ -222,72 +263,56 @@ def next_page(pages_json, current_page, total_pages, pid, orig_lev):
222
  }
223
  save_log(entry2)
224
 
225
- # 最終ページに到達した場合は next ボタンではページ遷移して finish ボタンを表示する仕様にする
226
- # ここでは new_page が最後のインデックスであれば prev を有効、next を隠し finish を表示
227
  if new_page == total_pages - 1:
228
- # 記録
229
- prev_upd = gr.update(interactive=True, visible=True)
230
- next_upd = gr.update(interactive=False, visible=False)
231
- finish_upd = gr.update(interactive=True, visible=True)
232
  return (
233
  pages[new_page],
234
  f"{new_page+1} / {total_pages}",
235
  json.dumps(pages),
236
  new_page,
237
- prev_upd,
238
- next_upd,
239
- finish_upd
240
  )
241
 
242
- prev_enabled = (new_page > 0)
243
- prev_upd = gr.update(interactive=prev_enabled, visible=prev_enabled)
244
- next_upd = gr.update(interactive=True, visible=True)
245
- finish_upd = gr.update(interactive=False, visible=False)
246
  return (
247
  pages[new_page],
248
  f"{new_page+1} / {total_pages}",
249
  json.dumps(pages),
250
  new_page,
251
- prev_upd,
252
- next_upd,
253
- finish_upd
254
  )
255
 
256
 
257
  def prev_page(pages_json, current_page, total_pages, pid, orig_lev):
258
  now = (datetime.utcnow() + timedelta(hours=9)).isoformat()
259
-
260
- action = "prev_pushed"
261
-
262
  entry = {
263
  "user_id": current_user_id,
264
- "assigned_level": current_level, # 変更点
265
  "passage_id": pid,
266
  "original_level": orig_lev,
267
  "action_time": now,
268
- "action_type": action,
269
  "page_text": None
270
  }
271
  save_log(entry)
272
-
273
  pages = json.loads(pages_json)
274
  if not pages:
275
- return (
276
- "", "", json.dumps([]), 0,
277
- gr.update(interactive=False, visible=False),
278
- gr.update(interactive=False, visible=False),
279
- gr.update(interactive=False, visible=False)
280
- )
281
 
282
  new_page = max(current_page - 1, 0)
283
 
284
-
285
- # 最終ページから戻った場合は next を再表示して finish を隠す
286
  prev_upd = gr.update(interactive=(new_page > 0), visible=(new_page > 0))
287
- # if we're now on last page (only possible if total_pages==1), show finish; otherwise show next
288
  next_visible = (new_page < total_pages - 1)
289
  next_upd = gr.update(interactive=next_visible, visible=next_visible)
290
  finish_upd = gr.update(interactive=(not next_visible), visible=(not next_visible))
 
291
  now2 = (datetime.utcnow() + timedelta(hours=9)).isoformat()
292
  entry2 = {
293
  "user_id": current_user_id,
@@ -317,7 +342,7 @@ def finish_or_retire(pages_json, current_page, pid, orig_lev, action):
317
 
318
  entry = {
319
  "user_id": current_user_id,
320
- "assigned_level": current_level, # 変更点
321
  "passage_id": pid,
322
  "original_level": orig_lev,
323
  "action_time": now,
@@ -326,7 +351,6 @@ def finish_or_retire(pages_json, current_page, pid, orig_lev, action):
326
  }
327
  save_log(entry)
328
 
329
- # 新しい教材取得
330
  new_pid, new_text, new_orig_lev = get_new_passage_random()
331
  if new_text is None:
332
  return (
@@ -337,20 +361,19 @@ def finish_or_retire(pages_json, current_page, pid, orig_lev, action):
337
  gr.update(interactive=False, visible=False)
338
  )
339
 
340
- rewritten = rewrite_level(new_text, current_level) # 変更点
341
  new_pages = split_pages(rewritten)
342
- new_start = (datetime.utcnow() + timedelta(hours=9)).isoformat()
343
  total = len(new_pages)
344
 
345
- # 新教材の最初のページ表示設定
346
- prev_upd = gr.update(interactive=False, visible=False)
347
  if total == 1:
 
348
  next_upd = gr.update(interactive=False, visible=False)
349
  finish_upd = gr.update(interactive=True, visible=True)
350
  else:
 
351
  next_upd = gr.update(interactive=True, visible=True)
352
  finish_upd = gr.update(interactive=False, visible=False)
353
- page_num = 1
354
  now2 = (datetime.utcnow() + timedelta(hours=9)).isoformat()
355
  entry2 = {
356
  "user_id": current_user_id,
@@ -358,7 +381,7 @@ def finish_or_retire(pages_json, current_page, pid, orig_lev, action):
358
  "passage_id": new_pid,
359
  "original_level": new_orig_lev,
360
  "action_time": now2,
361
- "action_type": f"page_displayed_{page_num}",
362
  "page_text": new_pages[0]
363
  }
364
  save_log(entry2)
@@ -371,29 +394,32 @@ def finish_or_retire(pages_json, current_page, pid, orig_lev, action):
371
  total,
372
  new_pid,
373
  new_orig_lev,
374
- current_level, # 変更点
375
  prev_upd,
376
  next_upd,
377
  finish_upd
378
  )
379
 
380
 
381
- # ============================
382
- # UI
383
- # ============================
384
 
385
  with gr.Blocks() as demo:
386
  gr.Markdown("# 📚 Reading Exercise")
387
 
388
  student_id_input = gr.Textbox(label="学生番号(必須)")
389
- level_input = gr.Dropdown(choices=[1,2,3,4,5], label="あなたの Reading Level(Level Testの結果を選択)", value=3) # 変更点
 
 
 
 
390
 
391
  start_btn = gr.Button("スタート")
392
 
393
  text_display = gr.Textbox(label="教材", lines=18, interactive=False)
394
  page_display = gr.Textbox(label="進行状況", lines=1, interactive=False)
395
 
396
- # hidden state
397
  hidden_pages = gr.Textbox(visible=False)
398
  hidden_page_index = gr.Number(visible=False)
399
  hidden_total_pages = gr.Number(visible=False)
@@ -404,25 +430,22 @@ with gr.Blocks() as demo:
404
  with gr.Row():
405
  prev_btn = gr.Button("◀ 前へ", interactive=False, visible=False)
406
  next_btn = gr.Button("次へ ▶", interactive=False, visible=False)
407
- # finish_btn は UI 上では通常表示しない(最終ページで表示する)
408
  finish_btn = gr.Button("読み終えた", interactive=False, visible=False)
409
 
410
  retire_btn = gr.Button("リタイア")
411
 
412
- # Start
413
  start_btn.click(
414
  fn=start_test,
415
  inputs=[student_id_input, level_input],
416
  outputs=[
417
  text_display, page_display,
418
  hidden_pages, hidden_page_index,
419
- hidden_total_pages, hidden_passage_id,
420
  hidden_orig_lev, hidden_assigned_lev,
421
  prev_btn, next_btn, finish_btn
422
  ]
423
  )
424
 
425
- # Next
426
  next_btn.click(
427
  fn=next_page,
428
  inputs=[
@@ -437,7 +460,6 @@ with gr.Blocks() as demo:
437
  ]
438
  )
439
 
440
- # Prev
441
  prev_btn.click(
442
  fn=prev_page,
443
  inputs=[
@@ -452,7 +474,6 @@ with gr.Blocks() as demo:
452
  ]
453
  )
454
 
455
- # Finish (最終ページで表示されるボタン)
456
  finish_btn.click(
457
  fn=lambda p, i, pid, o: finish_or_retire(p, i, pid, o, "finished"),
458
  inputs=[hidden_pages, hidden_page_index, hidden_passage_id, hidden_orig_lev],
@@ -465,11 +486,8 @@ with gr.Blocks() as demo:
465
  ]
466
  )
467
 
468
- # Retire
469
  retire_btn.click(
470
- fn=lambda p, i, pid, o: finish_or_retire(
471
- p, i, pid, o, "retire"
472
- ),
473
  inputs=[
474
  hidden_pages, hidden_page_index,
475
  hidden_passage_id, hidden_orig_lev
@@ -477,9 +495,9 @@ with gr.Blocks() as demo:
477
  outputs=[
478
  text_display, page_display,
479
  hidden_pages, hidden_page_index,
480
- hidden_total_pages,
481
- hidden_passage_id, hidden_orig_lev,
482
- hidden_assigned_lev, prev_btn, next_btn, finish_btn
483
  ]
484
  )
485
 
 
3
  from datasets import Dataset
4
  from datetime import datetime, timedelta
5
  import pandas as pd
6
+ import time, os, random, tempfile, json, glob
7
 
8
  # --- API / HF 設定 ---
9
  API_KEY = os.getenv("API_KEY")
 
14
 
15
  client = OpenAI(base_url=BASE_URL, api_key=API_KEY)
16
 
17
+ # --- passage_information.xlsx 読み込み (Text# と flesch_score 使用) ---
18
+ passage_info_df = pd.read_excel("passage_information.xlsx")
19
 
20
  # --- 状態変数 ---
21
  used_passages = set()
 
23
  current_level = None
24
 
25
 
26
+ # ======================================================
27
+ # 新しい教材管理:passages フォルダからランダム選択
28
+ # ======================================================
29
 
30
+ def load_passage_file(text_id):
31
+ """
32
+ passages/pg{text_id}.txt を読み込み、内容を返す。
33
+ """
34
+ path = f"passages/pg{text_id}.txt"
35
+ if not os.path.exists(path):
36
+ return None
37
+ with open(path, "r", encoding="utf-8") as f:
38
+ return f.read()
39
 
40
+ def get_new_passage_random():
41
+ """
42
+ passages フォルダからランダムに教材を選び(pg◯.txt)、
43
+ passage_information.xlsx の Text# の flesch_score を original_level として返す。
44
+ """
45
+ global used_passages
46
+
47
+ # --- pg*.txt を取得 ---
48
+ files = glob.glob("passages/pg*.txt")
49
+ if not files:
50
+ return None, None, None
51
+
52
+ # --- ファイル名から Text# (整数) を抽出 ---
53
+ all_ids = []
54
+ for f in files:
55
+ name = os.path.basename(f)
56
+ num = name.replace("pg", "").replace(".txt", "")
57
+ if num.isdigit():
58
+ all_ids.append(int(num))
59
+
60
+ # --- 未使用の ID を優先 ---
61
+ available = [pid for pid in all_ids if pid not in used_passages]
62
+ if not available:
63
+ used_passages.clear()
64
+ available = list(all_ids)
65
+
66
+ # --- ランダムに選択 ---
67
+ text_id = random.choice(available)
68
+ used_passages.add(text_id)
69
+
70
+ # --- テキスト読み込み ---
71
+ text = load_passage_file(text_id)
72
+ if text is None:
73
+ return None, None, None
74
+
75
+ # --- Excel から original_level (flesch_score) を取得 ---
76
+ row = passage_info_df[passage_info_df["Text#"] == text_id]
77
+ if len(row) == 0:
78
+ orig_level = None
79
+ else:
80
+ orig_level = row.iloc[0]["flesch_score"]
81
+
82
+ return text_id, text, orig_level
83
+
84
+
85
+ # ======================================================
86
+ # Rewrite
87
+ # ======================================================
88
+
89
+ def rewrite_level(text, target_level):
90
  level_to_flesch = {
91
+ 1: 90,
92
+ 2: 70,
93
+ 3: 55,
94
+ 4: 40,
95
+ 5: 25
96
  }
97
 
 
98
  target_flesch = level_to_flesch[int(target_level)]
99
 
100
  prompt = f"""
 
102
  - Preserve the original meaning faithfully.
103
  - Do not add new information or remove essential information.
104
  - Output only the rewritten passage. Do not include explanations.
 
 
105
  {text}
106
  """
107
+
108
  resp = client.chat.completions.create(
109
  model="google/gemma-3-27b-it:free",
110
  messages=[{"role": "user", "content": prompt}],
 
114
  return resp.choices[0].message.content.strip()
115
 
116
 
117
+ def split_pages(text, words=120):
118
  w = text.split()
119
+ return [" ".join(w[i:i+words]) for i in range(0, len(w), words)] or [text]
 
120
 
121
 
122
+ # ======================================================
123
+ # Save Log
124
+ # ======================================================
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
 
126
  def save_log(entry):
127
  df = pd.DataFrame([entry])
 
129
  df.to_csv(LOG_FILE, mode="a", index=False, header=False)
130
  else:
131
  df.to_csv(LOG_FILE, index=False)
132
+
133
  all_logs = pd.read_csv(LOG_FILE)
134
  tmp_dir = tempfile.mkdtemp()
135
  tmp_path = os.path.join(tmp_dir, "data.parquet")
 
138
  dataset.push_to_hub(DATASET_REPO, token=HF_TOKEN)
139
 
140
 
141
+ # ======================================================
142
+ # Start
143
+ # ======================================================
144
 
145
  def start_test(student_id, level_input):
146
+ global current_user_id, current_level, used_passages
 
147
  used_passages = set()
148
 
149
  action = "start_pushed"
 
151
 
152
  entry = {
153
  "user_id": student_id,
154
+ "assigned_level": current_level,
155
  "passage_id": None,
156
  "original_level": None,
157
  "action_time": now,
 
161
  save_log(entry)
162
 
163
  if not student_id or str(student_id).strip() == "":
 
164
  return (
165
  "", "", json.dumps([]), 0, "",
166
  0, "", None, None,
167
+ gr.update(interactive=False, visible=False),
168
+ gr.update(interactive=False, visible=True),
169
+ gr.update(interactive=False, visible=False)
170
  )
171
 
172
  current_user_id = str(student_id).strip()
173
+ current_level = int(level_input)
174
 
175
  pid, text, orig_lev = get_new_passage_random()
176
  if text is None:
 
182
  gr.update(interactive=False, visible=False)
183
  )
184
 
185
+ rewritten = rewrite_level(text, current_level)
186
  pages = split_pages(rewritten)
187
  total = len(pages)
188
 
 
 
 
189
  if total == 1:
190
+ prev_upd = gr.update(interactive=False, visible=False)
191
  next_upd = gr.update(interactive=False, visible=False)
192
  finish_upd = gr.update(interactive=True, visible=True)
193
  else:
194
+ prev_upd = gr.update(interactive=False, visible=False)
195
  next_upd = gr.update(interactive=True, visible=True)
196
  finish_upd = gr.update(interactive=False, visible=False)
197
 
198
  page_num = 1
199
  now = (datetime.utcnow() + timedelta(hours=9)).isoformat()
200
+
201
  entry = {
202
  "user_id": current_user_id,
203
  "assigned_level": current_level,
 
208
  "page_text": pages[0]
209
  }
210
  save_log(entry)
211
+
212
  return (
213
  pages[0],
214
  f"1 / {total}",
 
224
  )
225
 
226
 
227
+ # ======================================================
228
+ # Next / Prev / Finish(以下は元コードのまま)
229
+ # ======================================================
230
+
231
  def next_page(pages_json, current_page, total_pages, pid, orig_lev):
232
  now = (datetime.utcnow() + timedelta(hours=9)).isoformat()
233
 
 
 
234
  entry = {
235
  "user_id": current_user_id,
236
+ "assigned_level": current_level,
237
  "passage_id": pid,
238
  "original_level": orig_lev,
239
  "action_time": now,
240
+ "action_type": "next_pushed",
241
  "page_text": None
242
  }
243
  save_log(entry)
244
+
245
  pages = json.loads(pages_json)
246
  if not pages:
247
+ return ("", "", json.dumps([]), 0,
248
+ gr.update(interactive=False, visible=False),
249
+ gr.update(interactive=False, visible=False),
250
+ gr.update(interactive=False, visible=False))
 
 
 
251
 
252
  new_page = min(current_page + 1, total_pages - 1)
253
 
 
263
  }
264
  save_log(entry2)
265
 
 
 
266
  if new_page == total_pages - 1:
 
 
 
 
267
  return (
268
  pages[new_page],
269
  f"{new_page+1} / {total_pages}",
270
  json.dumps(pages),
271
  new_page,
272
+ gr.update(interactive=True, visible=True),
273
+ gr.update(interactive=False, visible=False),
274
+ gr.update(interactive=True, visible=True)
275
  )
276
 
 
 
 
 
277
  return (
278
  pages[new_page],
279
  f"{new_page+1} / {total_pages}",
280
  json.dumps(pages),
281
  new_page,
282
+ gr.update(interactive=(new_page > 0), visible=(new_page > 0)),
283
+ gr.update(interactive=True, visible=True),
284
+ gr.update(interactive=False, visible=False)
285
  )
286
 
287
 
288
  def prev_page(pages_json, current_page, total_pages, pid, orig_lev):
289
  now = (datetime.utcnow() + timedelta(hours=9)).isoformat()
290
+
 
 
291
  entry = {
292
  "user_id": current_user_id,
293
+ "assigned_level": current_level,
294
  "passage_id": pid,
295
  "original_level": orig_lev,
296
  "action_time": now,
297
+ "action_type": "prev_pushed",
298
  "page_text": None
299
  }
300
  save_log(entry)
301
+
302
  pages = json.loads(pages_json)
303
  if not pages:
304
+ return ("", "", json.dumps([]), 0,
305
+ gr.update(interactive=False, visible=False),
306
+ gr.update(interactive=False, visible=False),
307
+ gr.update(interactive=False, visible=False))
 
 
308
 
309
  new_page = max(current_page - 1, 0)
310
 
 
 
311
  prev_upd = gr.update(interactive=(new_page > 0), visible=(new_page > 0))
 
312
  next_visible = (new_page < total_pages - 1)
313
  next_upd = gr.update(interactive=next_visible, visible=next_visible)
314
  finish_upd = gr.update(interactive=(not next_visible), visible=(not next_visible))
315
+
316
  now2 = (datetime.utcnow() + timedelta(hours=9)).isoformat()
317
  entry2 = {
318
  "user_id": current_user_id,
 
342
 
343
  entry = {
344
  "user_id": current_user_id,
345
+ "assigned_level": current_level,
346
  "passage_id": pid,
347
  "original_level": orig_lev,
348
  "action_time": now,
 
351
  }
352
  save_log(entry)
353
 
 
354
  new_pid, new_text, new_orig_lev = get_new_passage_random()
355
  if new_text is None:
356
  return (
 
361
  gr.update(interactive=False, visible=False)
362
  )
363
 
364
+ rewritten = rewrite_level(new_text, current_level)
365
  new_pages = split_pages(rewritten)
 
366
  total = len(new_pages)
367
 
 
 
368
  if total == 1:
369
+ prev_upd = gr.update(interactive=False, visible=False)
370
  next_upd = gr.update(interactive=False, visible=False)
371
  finish_upd = gr.update(interactive=True, visible=True)
372
  else:
373
+ prev_upd = gr.update(interactive=False, visible=False)
374
  next_upd = gr.update(interactive=True, visible=True)
375
  finish_upd = gr.update(interactive=False, visible=False)
376
+
377
  now2 = (datetime.utcnow() + timedelta(hours=9)).isoformat()
378
  entry2 = {
379
  "user_id": current_user_id,
 
381
  "passage_id": new_pid,
382
  "original_level": new_orig_lev,
383
  "action_time": now2,
384
+ "action_type": "page_displayed_1",
385
  "page_text": new_pages[0]
386
  }
387
  save_log(entry2)
 
394
  total,
395
  new_pid,
396
  new_orig_lev,
397
+ current_level,
398
  prev_upd,
399
  next_upd,
400
  finish_upd
401
  )
402
 
403
 
404
+ # ======================================================
405
+ # UI
406
+ # ======================================================
407
 
408
  with gr.Blocks() as demo:
409
  gr.Markdown("# 📚 Reading Exercise")
410
 
411
  student_id_input = gr.Textbox(label="学生番号(必須)")
412
+ level_input = gr.Dropdown(
413
+ choices=[1,2,3,4,5],
414
+ label="あなたの Reading Level(Level Testの結果を選択)",
415
+ value=3
416
+ )
417
 
418
  start_btn = gr.Button("スタート")
419
 
420
  text_display = gr.Textbox(label="教材", lines=18, interactive=False)
421
  page_display = gr.Textbox(label="進行状況", lines=1, interactive=False)
422
 
 
423
  hidden_pages = gr.Textbox(visible=False)
424
  hidden_page_index = gr.Number(visible=False)
425
  hidden_total_pages = gr.Number(visible=False)
 
430
  with gr.Row():
431
  prev_btn = gr.Button("◀ 前へ", interactive=False, visible=False)
432
  next_btn = gr.Button("次へ ▶", interactive=False, visible=False)
 
433
  finish_btn = gr.Button("読み終えた", interactive=False, visible=False)
434
 
435
  retire_btn = gr.Button("リタイア")
436
 
 
437
  start_btn.click(
438
  fn=start_test,
439
  inputs=[student_id_input, level_input],
440
  outputs=[
441
  text_display, page_display,
442
  hidden_pages, hidden_page_index,
443
+ hidden_total_pages, hidden_passage_id,
444
  hidden_orig_lev, hidden_assigned_lev,
445
  prev_btn, next_btn, finish_btn
446
  ]
447
  )
448
 
 
449
  next_btn.click(
450
  fn=next_page,
451
  inputs=[
 
460
  ]
461
  )
462
 
 
463
  prev_btn.click(
464
  fn=prev_page,
465
  inputs=[
 
474
  ]
475
  )
476
 
 
477
  finish_btn.click(
478
  fn=lambda p, i, pid, o: finish_or_retire(p, i, pid, o, "finished"),
479
  inputs=[hidden_pages, hidden_page_index, hidden_passage_id, hidden_orig_lev],
 
486
  ]
487
  )
488
 
 
489
  retire_btn.click(
490
+ fn=lambda p, i, pid, o: finish_or_retire(p, i, pid, o, "retire"),
 
 
491
  inputs=[
492
  hidden_pages, hidden_page_index,
493
  hidden_passage_id, hidden_orig_lev
 
495
  outputs=[
496
  text_display, page_display,
497
  hidden_pages, hidden_page_index,
498
+ hidden_total_pages, hidden_passage_id,
499
+ hidden_orig_lev, hidden_assigned_lev,
500
+ prev_btn, next_btn, finish_btn
501
  ]
502
  )
503