Toya0421 commited on
Commit
d7e4bc5
·
verified ·
1 Parent(s): 70c9ef9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +89 -179
app.py CHANGED
@@ -1,199 +1,109 @@
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難易度別教材(各3文) ---
10
- texts = {
11
- 300: [
12
- "Tom has a red ball. He plays with it in the park. The sun is bright.",
13
- "A dog runs after a stick. The boy laughs as the dog brings it back.",
14
- "The girl eats an apple under the tree while the wind blows softly."
15
  ],
16
  600: [
17
- "A young boy found a lost puppy near the river. He decided to take care of it.",
18
- "Mary saw a rainbow after the rain stopped and felt happy.",
19
- "The teacher asked the students to write a short story about friendship."
20
  ],
21
- 850: [
22
- "Sarah enjoyed reading stories about ancient civilizations and their discoveries.",
23
- "During the festival, people decorated the streets with lights and music.",
24
- "James wanted to learn how airplanes could stay in the sky for so long."
25
  ],
26
- 1050: [
27
- "The scientist developed a new hypothesis about the evolution of animal behavior.",
28
- "Farmers began to adopt sustainable methods to protect soil health.",
29
- "A historian analyzed old letters to understand social changes during the war."
30
  ],
31
- 1250: [
32
- "Philosophers have long debated the intricate relationship between free will and determinism.",
33
- "Modern architecture often reflects both functionality and aesthetic simplicity.",
34
- "Researchers in neuroscience continue to explore how memory is formed and stored."
35
  ]
36
  }
37
 
38
- levels = [300, 600, 850, 1050, 1250]
39
-
40
- # --- OpenAIクライアント設定 ---
41
- client = OpenAI(base_url=BASE_URL, api_key=API_KEY)
42
-
43
- # --- 出題済みテキストを管理するセット ---
44
- used_texts = set()
45
-
46
- # --- AIに問題生成を依頼 ---
47
- def generate_question(text):
48
- prompt = f"""
49
- Read the following passage and generate ONE multiple-choice question with 4 options (A–D).
50
- Clearly mark the correct answer with an asterisk (*).
51
- The format must be:
52
-
53
- Q: <question text>
54
- A. <option>
55
- B. <option>
56
- C. <option>
57
- D. <option>
58
-
59
- Passage:
60
- {text}
61
- """
62
 
63
- response = client.chat.completions.create(
64
- model="google/gemma-3-27b-it:free",
65
- messages=[{"role": "user", "content": prompt}],
66
- max_tokens=400,
67
- temperature=0.7,
68
- )
69
- raw_output = response.choices[0].message.content.strip()
70
-
71
- # --- 正解の抽出 ---
72
- correct_option = None
73
- for line in raw_output.splitlines():
74
- if line.lower().startswith("correct:"):
75
- correct_option = line.split(":")[1].strip().upper()
76
- break
77
-
78
- # --- アスタリスク除去(*印があっても削除) ---
79
- cleaned_lines = []
80
- for line in raw_output.splitlines():
81
- if "*" in line:
82
- line = line.replace("*", "").strip()
83
- # Correct行は表示しない
84
- if not line.lower().startswith("correct:"):
85
- cleaned_lines.append(line)
86
-
87
- cleaned_output = "\n".join(cleaned_lines)
88
- return cleaned_output, correct_option
89
-
90
-
91
- # --- 適応型テストの進行 ---
92
- def adaptive_test(prev_level, prev_correct):
93
- idx = levels.index(prev_level)
94
- if prev_correct and idx < len(levels) - 1:
95
- new_level = levels[idx + 1]
96
- elif not prev_correct and idx > 0:
97
- new_level = levels[idx - 1]
98
- else:
99
- new_level = prev_level
100
- return new_level
101
-
102
-
103
- # --- 未使用の文章を取得 ---
104
- def get_unused_text(level):
105
- available = [t for t in texts[level] if (level, t) not in used_texts]
106
  if not available:
107
- # すべて使った場合はリセット
108
- used_texts.clear()
109
- available = texts[level]
110
- chosen = random.choice(available)
111
- used_texts.add((level, chosen))
112
- return chosen
113
-
114
-
115
- # --- テスト開始 ---
116
- def start_test():
117
- level = 850 # 中間レベルから開始
118
- text = get_unused_text(level)
119
- question, correct = generate_question(text)
120
- return f"Lexile: {level}L", text, question, level, correct, ""
121
-
122
-
123
- # --- 回答を処理して次へ ---
124
- def next_step(prev_level, user_answer, question_text, correct_option):
125
- if correct_option is None:
126
- feedback = "⚠️ No correct answer found in the generated question."
127
- return feedback, f"Lexile: {prev_level}L", "", "", prev_level, None, ""
128
-
129
- correct = (user_answer == correct_option)
130
-
131
- # レベルを更新
132
- new_level = adaptive_test(prev_level, correct)
133
- new_text = get_unused_text(new_level)
134
- new_question, new_correct = generate_question(new_text)
135
-
136
- feedback = "✅ Correct!" if correct else "❌ Incorrect."
137
- if new_level == prev_level:
138
- feedback += f"\n🎯 Your estimated reading level is **{new_level}L** (final)."
139
- else:
140
- feedback += f"\n➡️ Moving to next level: **{new_level}L**"
141
-
142
- return (
143
- feedback,
144
- f"Lexile: {new_level}L",
145
- new_text,
146
- new_question,
147
- new_level,
148
- new_correct,
149
- ""
150
- )
151
 
 
 
 
 
152
 
153
- # --- Gradio UI ---
154
- with gr.Blocks() as demo:
155
- gr.Markdown("# 📘 Adaptive Reading Level Test (Lexile-based)")
156
-
157
- start_btn = gr.Button("▶️ Start Test")
158
-
159
- level_display = gr.Textbox(label="Current Level", interactive=False)
160
- text_display = gr.Textbox(label="Reading Passage", lines=6, interactive=False)
161
- question_display = gr.Textbox(label="Generated Question", lines=8, interactive=False)
162
-
163
- user_answer = gr.Radio(choices=["A", "B", "C", "D"], label="Your Answer")
164
- submit_btn = gr.Button("Submit Answer")
165
-
166
- feedback_display = gr.Markdown()
167
- hidden_level = gr.Number(visible=False)
168
- hidden_correct = gr.Textbox(visible=False)
169
-
170
- # --- Start Test ---
171
- start_btn.click(
172
- fn=start_test,
173
- inputs=[],
174
- outputs=[
175
- level_display,
176
- text_display,
177
- question_display,
178
- hidden_level,
179
- hidden_correct,
180
- feedback_display,
181
- ],
182
- )
183
 
184
- # --- Submit & Move to Next ---
185
- submit_btn.click(
 
 
186
  fn=next_step,
187
- inputs=[hidden_level, user_answer, question_display, hidden_correct],
188
- outputs=[
189
- feedback_display,
190
- level_display,
191
- text_display,
192
- question_display,
193
- hidden_level,
194
- hidden_correct,
195
- feedback_display,
196
- ],
197
  )
198
 
 
 
 
199
  demo.launch()
 
1
+ import os
 
2
  import random
3
+ import gradio as gr
4
 
5
+ # OpenRouter APIキーを指定
6
  API_KEY = "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"
7
+
8
+ # Lexileレベルごとの文章セット(各3問)
9
+ texts_by_level = {
10
+ 400: [
11
+ {"text": "Tom has a little dog. The dog likes to run in the park.", "question": "What does Tom's dog like to do?", "options": ["Run in the park", "Sleep all day", "Eat candy", "Climb trees"], "answer": "Run in the park"},
12
+ {"text": "The sun is bright today. Many children are playing outside.", "question": "Where are the children playing?", "options": ["Outside", "In school", "At night", "In the house"], "answer": "Outside"},
13
+ {"text": "Anna has a red ball. She throws it to her friend in the garden.", "question": "Where does Anna throw the ball?", "options": ["In the garden", "In the kitchen", "In the school", "In the store"], "answer": "In the garden"},
 
14
  ],
15
  600: [
16
+ {"text": "Sara goes to the library every Saturday. She likes to read mystery books.", "question": "What kind of books does Sara like?", "options": ["Mystery books", "Science books", "History books", "Cooking books"], "answer": "Mystery books"},
17
+ {"text": "A frog can jump far. It uses its strong legs to move fast.", "question": "What helps the frog jump far?", "options": ["Its strong legs", "Its arms", "Its eyes", "Its color"], "answer": "Its strong legs"},
18
+ {"text": "Ben plants some seeds in the garden. After a few days, small plants grow.", "question": "What happens after a few days?", "options": ["Small plants grow", "The seeds disappear", "It starts to snow", "The garden becomes empty"], "answer": "Small plants grow"},
19
  ],
20
+ 800: [
21
+ {"text": "David wanted to learn how machines work. He took apart an old radio to see the parts inside.", "question": "Why did David take apart the radio?", "options": ["To see the parts inside", "To break it", "To sell it", "To clean it"], "answer": "To see the parts inside"},
22
+ {"text": "In winter, many animals rest or sleep for a long time. This is called hibernation.", "question": "What do animals do during hibernation?", "options": ["Sleep for a long time", "Eat more food", "Play outside", "Travel to other countries"], "answer": "Sleep for a long time"},
23
+ {"text": "Lisa looked through the telescope and saw bright stars in the night sky.", "question": "What did Lisa use to see the stars?", "options": ["A telescope", "A microscope", "A flashlight", "A magnifier"], "answer": "A telescope"},
24
  ],
25
+ 1000: [
26
+ {"text": "Plants use sunlight to make food. This process is called photosynthesis.", "question": "What do plants use to make food?", "options": ["Sunlight", "Wind", "Soil", "Rain"], "answer": "Sunlight"},
27
+ {"text": "Electric cars are better for the environment because they produce less pollution.", "question": "Why are electric cars better for the environment?", "options": ["They produce less pollution", "They are faster", "They use gasoline", "They make noise"], "answer": "They produce less pollution"},
28
+ {"text": "The computer stores data in its memory. This allows users to save their work.", "question": "What does the computer store in its memory?", "options": ["Data", "Food", "Games", "Pictures only"], "answer": "Data"},
29
  ],
30
+ 1200: [
31
+ {"text": "The scientist observed how the new medicine affected the cells under a microscope.", "question": "What did the scientist use to see the cells?", "options": ["A microscope", "A telescope", "A camera", "A ruler"], "answer": "A microscope"},
32
+ {"text": "During the experiment, the temperature was carefully controlled to ensure accurate results.", "question": "Why was the temperature controlled?", "options": ["To ensure accurate results", "To make it hotter", "To test faster", "To make it colder"], "answer": "To ensure accurate results"},
33
+ {"text": "Researchers developed a new algorithm that can predict weather patterns more accurately.", "question": "What can the new algorithm do?", "options": ["Predict weather patterns", "Make maps", "Control the wind", "Measure temperature"], "answer": "Predict weather patterns"},
34
  ]
35
  }
36
 
37
+ # 状態管理
38
+ state = {
39
+ "current_level": 600,
40
+ "question_count": 0,
41
+ "used_texts": set(),
42
+ "correct_count": 0,
43
+ "finished": False
44
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
+ def get_next_question():
47
+ level_texts = texts_by_level[state["current_level"]]
48
+ available = [t for t in level_texts if t["text"] not in state["used_texts"]]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  if not available:
50
+ return None
51
+ question = random.choice(available)
52
+ state["used_texts"].add(question["text"])
53
+ return question
54
+
55
+ def check_answer(user_answer):
56
+ correct = state["current_question"]["answer"]
57
+ return user_answer == correct
58
+
59
+ def quiz_flow(user_answer=None):
60
+ if state["finished"]:
61
+ return "テストはすでに終了しています。再開するにはページをリロードしてください。", None, None, None
62
+
63
+ # 回答処理
64
+ if user_answer is not None:
65
+ if check_answer(user_answer):
66
+ state["correct_count"] += 1
67
+ state["current_level"] = min(state["current_level"] + 200, 1200)
68
+ else:
69
+ state["current_level"] = max(state["current_level"] - 200, 400)
70
+ state["question_count"] += 1
71
+
72
+ # 5問で終了
73
+ if state["question_count"] >= 5:
74
+ state["finished"] = True
75
+ return f"✅ テスト終了!あなたの推定読解レベルは {state['current_level']}L です。", None, None, None
76
+
77
+ # 次の問題取得
78
+ question = get_next_question()
79
+ if not question:
80
+ state["finished"] = True
81
+ return f"📘 これ以上の問題がありません。あなたの推定レベルは {state['current_level']}L です。", None, None, None
82
+
83
+ state["current_question"] = question
84
+ return question["text"], question["question"], question["options"], None
85
+
86
+ # Gradio UI
87
+ with gr.Blocks() as demo:
88
+ gr.Markdown("## 📖 英文読解テスト(全5問)")
 
 
 
 
 
89
 
90
+ passage = gr.Textbox(label="文章", interactive=False, lines=4)
91
+ question_box = gr.Textbox(label="問題", interactive=False)
92
+ options = gr.Radio(label="選択肢", choices=[])
93
+ result = gr.Textbox(label="結果表示", interactive=False)
94
 
95
+ next_btn = gr.Button("次へ")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
97
+ def next_step(user_choice):
98
+ return quiz_flow(user_choice)
99
+
100
+ next_btn.click(
101
  fn=next_step,
102
+ inputs=[options],
103
+ outputs=[passage, question_box, options, result],
 
 
 
 
 
 
 
 
104
  )
105
 
106
+ # 初期化時に最初の問題表示
107
+ demo.load(fn=quiz_flow, inputs=None, outputs=[passage, question_box, options, result])
108
+
109
  demo.launch()