Toya0421 commited on
Commit
0d155b7
·
verified ·
1 Parent(s): 4cd5d7d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +89 -121
app.py CHANGED
@@ -1,52 +1,34 @@
1
  import gradio as gr
2
- import random
3
- import json
4
  from openai import OpenAI
 
5
 
6
- # ✅ APIキーここに直接指定
7
  API_KEY = "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"
 
 
 
 
 
 
 
 
 
 
8
 
9
- # OpenRouterクライアント設定
 
 
10
  client = OpenAI(
11
- base_url="https://openrouter.ai/api/v1",
12
  api_key=API_KEY
13
  )
14
 
15
- # ===== Lexileレベルごとの教材 =====
16
- materials = {
17
- 300: [
18
- "The cat is on the mat.",
19
- "A boy runs in the park.",
20
- "She has a red apple."
21
- ],
22
- 600: [
23
- "The young girl likes to read books after school.",
24
- "A small bird made a nest in the tree near the house.",
25
- "The sun sets behind the mountains every evening."
26
- ],
27
- 850: [
28
- "Many students find mathematics both challenging and rewarding.",
29
- "Farmers often depend on weather forecasts to plan their work.",
30
- "The history of flight began with dreams of human wings."
31
- ],
32
- 1050: [
33
- "Scientific discoveries often arise from unexpected observations.",
34
- "Economic systems rely on trust between consumers and producers.",
35
- "The poet’s work explores the relationship between nature and emotion."
36
- ],
37
- 1250: [
38
- "Philosophical inquiry seeks to understand the foundations of knowledge and ethics.",
39
- "Technological innovation continuously reshapes modern societies.",
40
- "Globalization has transformed the way nations interact politically and economically."
41
- ]
42
- }
43
-
44
- # ===== 問題生成 =====
45
  def generate_question(text):
46
  prompt = f"""
47
  Read the following passage and generate ONE multiple-choice question with 4 options (A–D).
48
- Clearly mark the correct answer in the format below.
49
- Return ONLY in this format:
50
 
51
  Q: <question text>
52
  A. <option>
@@ -65,101 +47,87 @@ def generate_question(text):
65
  max_tokens=400,
66
  temperature=0.7,
67
  )
68
- full_output = response.choices[0].message.content.strip()
69
-
70
- # --- 正解を抽出 ---
71
- match = re.search(r"Correct:\s*([A-D])", full_output, re.IGNORECASE)
72
- correct_option = match.group(1).upper() if match else None
73
-
74
- # --- 「Correct:」行を削除して受験者には非表示にする ---
75
- visible_question = re.sub(r"(?i)Correct:\s*[A-D]", "", full_output).strip()
76
-
77
- return visible_question, correct_option
78
-
 
79
 
80
- # ===== テスト初期化 =====
81
  def start_test():
82
- state = {
83
- "level": 850, # 初期レベル(中間)
84
- "asked": [],
85
- "score": 0,
86
- "count": 0
87
- }
88
- return state, "✅ Test started! Please read the passage carefully.", "", "", [], ""
89
-
90
- # ===== 最初の問題を取得 =====
91
- def get_first_question(state):
92
- text = random.choice(materials[state["level"]])
93
- state["asked"].append(text)
94
- q = generate_question(text)
95
- state["current_q"] = q
96
- return state, text, q["question"], "", q["choices"], ""
97
-
98
- # ===== 回答処理 =====
99
- def next_step(state, user_choice):
100
- if not state or "current_q" not in state:
101
- return state, "Please start the test first.", "", "", [], ""
102
-
103
- correct = user_choice == state["current_q"]["answer"]
104
- feedback = "✅ Correct!" if correct else f"❌ Incorrect. The correct answer was {state['current_q']['answer']}."
105
-
106
- # レベル変動
107
- if correct:
108
- state["level"] = min(1250, state["level"] + 250)
109
- state["score"] += 1
110
  else:
111
- state["level"] = max(300, state["level"] - 250)
112
-
113
- state["count"] += 1
114
-
115
- # 5問で終了
116
- if state["count"] >= 5:
117
- result = f"🎯 Test finished! Your estimated reading ability corresponds to approximately {state['level']}L."
118
- return state, result, "", "", [], ""
119
-
120
- # 新しい教材重複なしで選択
121
- available = [t for t in materials[state["level"]] if t not in state["asked"]]
122
- if not available:
123
- available = materials[state["level"]]
124
- text = random.choice(available)
125
- state["asked"].append(text)
126
 
127
- q = generate_question(text)
128
- state["current_q"] = q
 
129
 
130
- # 次の問題を返す(選択肢リセット)
131
- return state, text, q["question"], "", q["choices"], feedback
132
 
133
- # ===== Gradio UI =====
134
- with gr.Blocks() as demo:
135
- gr.Markdown("## 📘 Adaptive Reading Test")
136
 
137
- state = gr.State()
138
- passage = gr.Textbox(label="Reading Passage", lines=6, interactive=False)
139
- question = gr.Textbox(label="Question", lines=2, interactive=False)
140
- feedback = gr.Textbox(label="Feedback", lines=2, interactive=False)
141
- choices = gr.Radio(label="Your Answer", choices=["A", "B", "C", "D"], value=None)
142
- msg = gr.Textbox(label="Message", lines=2, interactive=False)
143
 
144
- with gr.Row():
145
- start_btn = gr.Button("▶️ Start Test")
146
- next_btn = gr.Button("➡️ Submit & Next")
147
 
148
- # スタートボタン
149
  start_btn.click(
150
- start_test,
151
- outputs=[state, msg, passage, question, choices, feedback]
152
- ).then(
153
- get_first_question,
154
- inputs=state,
155
- outputs=[state, passage, question, choices, feedback]
156
  )
157
 
158
- # 次の問題ボタン
159
- next_btn.click(
160
- next_step,
161
- inputs=[state, choices],
162
- outputs=[state, passage, question, choices, feedback, msg]
163
  )
164
 
165
- demo.launch(share=True)
 
1
  import gradio as gr
 
 
2
  from openai import OpenAI
3
+ import random
4
 
5
+ # ✅ OpenRouter APIキーここに直接書く)
6
  API_KEY = "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"
7
+ BASE_URL = "https://openrouter.ai/api/v1"
8
+
9
+ # --- Lexile難易度別教材 ---
10
+ texts = {
11
+ 300: "Tom has a red ball. He plays with it in the park. The sun is bright.",
12
+ 600: "A young boy found a lost puppy near the river. He decided to take care of it.",
13
+ 850: "Sarah enjoyed reading stories about ancient civilizations and their discoveries.",
14
+ 1050: "The scientist developed a new hypothesis about the evolution of animal behavior.",
15
+ 1250: "Philosophers have long debated the intricate relationship between free will and determinism."
16
+ }
17
 
18
+ levels = [300, 600, 850, 1050, 1250]
19
+
20
+ # --- OpenAIクライアント設定 ---
21
  client = OpenAI(
22
+ base_url=BASE_URL,
23
  api_key=API_KEY
24
  )
25
 
26
+ # --- AIに問題生成を依頼 ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  def generate_question(text):
28
  prompt = f"""
29
  Read the following passage and generate ONE multiple-choice question with 4 options (A–D).
30
+ Clearly mark the correct answer with an asterisk (*).
31
+ The format must be:
32
 
33
  Q: <question text>
34
  A. <option>
 
47
  max_tokens=400,
48
  temperature=0.7,
49
  )
50
+ return response.choices[0].message.content.strip()
51
+
52
+ # --- 適応型テストの進行 ---
53
+ def adaptive_test(prev_level, prev_correct):
54
+ idx = levels.index(prev_level)
55
+ if prev_correct and idx < len(levels) - 1:
56
+ new_level = levels[idx + 1]
57
+ elif not prev_correct and idx > 0:
58
+ new_level = levels[idx - 1]
59
+ else:
60
+ new_level = prev_level
61
+ return new_level
62
 
63
+ # --- テスト開始 ---
64
  def start_test():
65
+ level = 850 # 中間レベルから開始
66
+ text = texts[level]
67
+ question = generate_question(text)
68
+ return f"Lexile: {level}L", text, question, level, None, ""
69
+
70
+ # --- 回答を処理して次へ ---
71
+ def next_step(prev_level, user_answer, question_text):
72
+ # 正解の抽出
73
+ correct_option = None
74
+ for line in question_text.splitlines():
75
+ if line.lower().startswith("correct:"):
76
+ correct_option = line.split(":")[1].strip().upper()
77
+ break
78
+
79
+ correct = (user_answer == correct_option)
80
+
81
+ # レベルを更新
82
+ new_level = adaptive_test(prev_level, correct)
83
+ new_text = texts[new_level]
84
+ new_question = generate_question(new_text)
85
+
86
+ feedback = "✅ Correct!" if correct else "❌ Incorrect."
87
+ if new_level == prev_level:
88
+ feedback += f"\n🎯 Your estimated reading level is **{new_level}L** (final)."
 
 
 
 
89
  else:
90
+ feedback += f"\n➡️ Moving to next level: **{new_level}L**"
91
+
92
+ # 回答欄をリセットするために "" を返す
93
+ return (
94
+ feedback,
95
+ f"Lexile: {new_level}L",
96
+ new_text,
97
+ new_question,
98
+ new_level,
99
+ None, # user_answerリセット
100
+ ""
101
+ )
 
 
 
102
 
103
+ # --- Gradio UI ---
104
+ with gr.Blocks() as demo:
105
+ gr.Markdown("# 📘 Adaptive Reading Level Test (Lexile-based)")
106
 
107
+ start_btn = gr.Button("▶️ Start Test")
 
108
 
109
+ level_display = gr.Textbox(label="Current Level", interactive=False)
110
+ text_display = gr.Textbox(label="Reading Passage", lines=6, interactive=False)
111
+ question_display = gr.Textbox(label="Generated Question", lines=8, interactive=False)
112
 
113
+ user_answer = gr.Radio(choices=["A", "B", "C", "D"], label="Your Answer")
114
+ submit_btn = gr.Button("Submit Answer")
 
 
 
 
115
 
116
+ feedback_display = gr.Markdown()
117
+ hidden_level = gr.Number(visible=False)
 
118
 
119
+ # --- Start Test ---
120
  start_btn.click(
121
+ fn=start_test,
122
+ inputs=[],
123
+ outputs=[level_display, text_display, question_display, hidden_level, user_answer, feedback_display]
 
 
 
124
  )
125
 
126
+ # --- Submit & Move to Next ---
127
+ submit_btn.click(
128
+ fn=next_step,
129
+ inputs=[hidden_level, user_answer, question_display],
130
+ outputs=[feedback_display, level_display, text_display, question_display, hidden_level, user_answer, feedback_display]
131
  )
132
 
133
+ demo.launch()