Jintonic92 commited on
Commit
d9a31b5
Β·
verified Β·
1 Parent(s): 829ef0f

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +487 -0
app.py ADDED
@@ -0,0 +1,487 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import os
4
+ from src.SecondModule.module2 import SimilarQuestionGenerator
5
+ from src.ThirdModule.module3 import AnswerVerifier
6
+ import logging
7
+ from typing import Optional, Tuple
8
+ #from latex_formatter import LatexFormatter # LaTeX 포맷터 import
9
+ from pylatexenc.latex2text import LatexNodes2Text
10
+
11
+
12
+ logging.basicConfig(level=logging.DEBUG)
13
+
14
+
15
+ # Streamlit νŽ˜μ΄μ§€ κΈ°λ³Έ μ„€μ •
16
+ st.set_page_config(
17
+ page_title="MisconcepTutor",
18
+ layout="wide",
19
+ initial_sidebar_state="expanded"
20
+ )
21
+
22
+ @st.cache_resource
23
+ def load_answer_verifier():
24
+ """λ‹΅μ•ˆ 검증 λͺ¨λΈ λ‘œλ“œ"""
25
+ from src.ThirdModule.module3 import AnswerVerifier
26
+ return AnswerVerifier()
27
+
28
+ # 경둜 μ„€μ •
29
+ base_path = os.path.dirname(os.path.abspath(__file__))
30
+ data_path = os.path.join(base_path, 'Data')
31
+ misconception_csv_path = os.path.join(data_path, 'misconception_mapping.csv')
32
+
33
+ # λ‘œκΉ… μ„€μ •
34
+ logging.basicConfig(level=logging.INFO)
35
+ logger = logging.getLogger(__name__)
36
+
37
+ # μ„Έμ…˜ μƒνƒœ μ΄ˆκΈ°ν™” - κ°€μž₯ λ¨Όμ € μ‹€ν–‰λ˜λ„λ‘ μ΅œμƒλ‹¨μ— 배치
38
+ if 'initialized' not in st.session_state:
39
+ st.session_state.initialized = True
40
+ st.session_state.wrong_questions = []
41
+ st.session_state.misconceptions = []
42
+ st.session_state.current_question_index = 0
43
+ st.session_state.generated_questions = []
44
+ st.session_state.current_step = 'initial'
45
+ st.session_state.selected_wrong_answer = None
46
+ st.session_state.questions = []
47
+ logger.info("Session state initialized")
48
+
49
+ # 문제 생성기 μ΄ˆκΈ°ν™”
50
+ @st.cache_resource
51
+ def load_question_generator():
52
+ """문제 생성 λͺ¨λΈ λ‘œλ“œ"""
53
+ if not os.path.exists(misconception_csv_path):
54
+ st.error(f"CSV 파일이 μ‘΄μž¬ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€: {misconception_csv_path}")
55
+ raise FileNotFoundError(f"CSV 파일이 μ‘΄μž¬ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€: {misconception_csv_path}")
56
+ return SimilarQuestionGenerator(misconception_csv_path=misconception_csv_path)
57
+
58
+ # CSV 데이터 λ‘œλ“œ ν•¨μˆ˜
59
+ @st.cache_data
60
+ def load_data(data_file = '/train.csv'):
61
+ try:
62
+ file_path = os.path.join(data_path, data_file.lstrip('/'))
63
+ df = pd.read_csv(file_path)
64
+ logger.info(f"Data loaded successfully from {file_path}")
65
+ return df
66
+ except FileNotFoundError:
67
+ st.error(f"νŒŒμΌμ„ 찾을 수 μ—†μŠ΅λ‹ˆλ‹€: {data_file}")
68
+ logger.error(f"File not found: {data_file}")
69
+ return None
70
+
71
+ def start_quiz():
72
+ """ν€΄μ¦ˆ μ‹œμž‘ 및 μ΄ˆκΈ°ν™”"""
73
+ df = load_data()
74
+ if df is None or df.empty:
75
+ st.error("데이터λ₯Ό 뢈러올 수 μ—†μŠ΅λ‹ˆλ‹€. 데이터셋을 ν™•μΈν•΄μ£Όμ„Έμš”.")
76
+ return
77
+
78
+ st.session_state.questions = df.sample(n=10, random_state=42)
79
+ st.session_state.current_step = 'quiz'
80
+ st.session_state.current_question_index = 0
81
+ st.session_state.wrong_questions = []
82
+ st.session_state.misconceptions = []
83
+ st.session_state.generated_questions = []
84
+ logger.info("Quiz started")
85
+
86
+
87
+ def generate_similar_question(wrong_q, misconception_id, generator):
88
+ """μœ μ‚¬ 문제 생성"""
89
+ logger.info(f"Generating similar question for misconception_id: {misconception_id}")
90
+
91
+ # μž…λ ₯ 데이터 μœ νš¨μ„± 검사
92
+ if not isinstance(wrong_q, dict):
93
+ logger.error(f"Invalid wrong_q type: {type(wrong_q)}")
94
+ st.error("μœ μ‚¬ 문제 생성에 ν•„μš”ν•œ 데이터 ν˜•μ‹μ΄ 잘λͺ»λ˜μ—ˆμŠ΅λ‹ˆλ‹€.")
95
+ return None
96
+
97
+ try:
98
+ # misconception_idκ°€ μ—†κ±°λ‚˜ NaN인 경우 λ‹€λ₯Έ misconception μ‚¬μš©
99
+ if pd.isna(misconception_id):
100
+ logger.info("Original misconception_id is NaN, trying to find alternative")
101
+ # ν˜„μž¬κΉŒμ§€ λ‚˜μ˜¨ misconceptionλ“€ μ€‘μ—μ„œ 선택
102
+ available_misconceptions = [m for m in st.session_state.misconceptions if not pd.isna(m)]
103
+
104
+ if available_misconceptions:
105
+ # κ°€μž₯ μ΅œκ·Όμ— λ‚˜μ˜¨ misconception 선택
106
+ misconception_id = available_misconceptions[-1]
107
+ logger.info(f"Using alternative misconception_id: {misconception_id}")
108
+ else:
109
+ # κΈ°λ³Έ misconception ID μ‚¬μš© (예: κ°€μž₯ 기본적인 misconception)
110
+ misconception_id = 2001 # μ μ ˆν•œ κΈ°λ³Έκ°’μœΌλ‘œ μˆ˜μ • ν•„μš”
111
+ logger.info(f"Using default misconception_id: {misconception_id}")
112
+
113
+ # 데이터 μ€€λΉ„ (νŠœν”Œ λ³€ν™˜ λ°©μ§€)
114
+ input_data = {
115
+ 'construct_name': str(wrong_q.get('ConstructName', '')),
116
+ 'subject_name': str(wrong_q.get('SubjectName', '')),
117
+ 'question_text': str(wrong_q.get('QuestionText', '')),
118
+ 'correct_answer_text': str(wrong_q.get(f'Answer{wrong_q["CorrectAnswer"]}Text', '')),
119
+ 'wrong_answer_text': str(wrong_q.get(f'Answer{st.session_state.selected_wrong_answer}Text', '')),
120
+ 'misconception_id': int(misconception_id)
121
+ }
122
+
123
+ logger.info(f"Prepared input data: {input_data}")
124
+
125
+ with st.spinner("πŸ“ μœ μ‚¬ 문제λ₯Ό μƒμ„±ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€..."):
126
+ # μœ μ‚¬ 문제 생성 호좜
127
+ generated_q, _ = generator.generate_similar_question_with_text(
128
+ construct_name=input_data['construct_name'],
129
+ subject_name=input_data['subject_name'],
130
+ question_text=input_data['question_text'],
131
+ correct_answer_text=input_data['correct_answer_text'],
132
+ wrong_answer_text=input_data['wrong_answer_text'],
133
+ misconception_id=input_data['misconception_id']
134
+ )
135
+
136
+ if generated_q:
137
+ verifier = load_answer_verifier()
138
+ with st.status("πŸ€” AIκ°€ 문제λ₯Ό κ²€ν† ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€..."):
139
+ st.write("λ‹΅μ•ˆμ˜ 정확성을 κ²€μ¦ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€...")
140
+ verified_answer = verifier.verify_answer(
141
+ question=generated_q.question,
142
+ choices=generated_q.choices
143
+ )
144
+
145
+ if verified_answer:
146
+ logger.info(f"Answer verified: {verified_answer}")
147
+ st.write("βœ… 검증 μ™„λ£Œ!")
148
+ result = {
149
+ 'question': generated_q.question,
150
+ 'choices': generated_q.choices,
151
+ 'correct': verified_answer,
152
+ 'explanation': generated_q.explanation
153
+ }
154
+ st.session_state['current_similar_question_answer'] = verified_answer
155
+ return result
156
+ else:
157
+ logger.warning("Answer verification failed, using original answer")
158
+ st.write("⚠️ 검증에 μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€. 원본 λ‹΅μ•ˆμ„ μ‚¬μš©ν•©λ‹ˆλ‹€.")
159
+ result = {
160
+ 'question': generated_q.question,
161
+ 'choices': generated_q.choices,
162
+ 'correct': generated_q.correct_answer,
163
+ 'explanation': generated_q.explanation
164
+ }
165
+ st.session_state['current_similar_question_answer'] = generated_q.correct_answer
166
+ return result
167
+
168
+ except Exception as e:
169
+ logger.error(f"Error in generate_similar_question: {str(e)}")
170
+ st.error(f"문제 생성 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€: {str(e)}")
171
+ return None
172
+
173
+ return None
174
+
175
+ def handle_answer(answer, current_q):
176
+ """λ‹΅λ³€ 처리"""
177
+ if answer != current_q['CorrectAnswer']:
178
+ wrong_q_dict = current_q.to_dict()
179
+ st.session_state.wrong_questions.append(wrong_q_dict)
180
+ st.session_state.selected_wrong_answer = answer
181
+
182
+ misconception_key = f'Misconception{answer}Id'
183
+ misconception_id = current_q.get(misconception_key)
184
+ st.session_state.misconceptions.append(misconception_id)
185
+
186
+ st.session_state.current_question_index += 1
187
+ if st.session_state.current_question_index >= 10:
188
+ st.session_state.current_step = 'review'
189
+
190
+ # μ „μ—­ LaTeX 포맷터 μΈμŠ€ν„΄μŠ€ 생성
191
+ latex_formatter = LatexFormatter()
192
+
193
+ def display_math_content(content: str):
194
+ """μˆ˜ν•™ λ‚΄μš©μ„ 화면에 ν‘œμ‹œ"""
195
+ formatted_content = latex_formatter.format_expression(content)
196
+ st.latex(formatted_content)
197
+ st.markdown(formatted_content, unsafe_allow_html=True)
198
+
199
+ def format_answer_choice(choice: str) -> str:
200
+ """선택지 LaTeX ν¬λ§·νŒ…"""
201
+ return latex_formatter.format_expression(choice)
202
+
203
+ def display_question_and_answers(question_text: str, answers: dict):
204
+ """
205
+ Display the question and its answer choices in a formatted layout.
206
+ Args:
207
+ question_text (str): LaTeX-formatted question text.
208
+ answers (dict): A dictionary of answer choices (keys: 'A', 'B', 'C', 'D').
209
+ """
210
+ # Display the question
211
+ st.write("### 문제")
212
+ st.latex(question_text)
213
+
214
+ # Arrange the answers in two columns
215
+ col1, col2 = st.columns(2)
216
+ with col1:
217
+ if st.button(f"A) {answers['A']}", key="A"):
218
+ return 'A'
219
+ if st.button(f"C) {answers['C']}", key="C"):
220
+ return 'C'
221
+ with col2:
222
+ if st.button(f"B) {answers['B']}", key="B"):
223
+ return 'B'
224
+ if st.button(f"D) {answers['D']}", key="D"):
225
+ return 'D'
226
+
227
+ return None
228
+
229
+ def main():
230
+ """메인 μ• ν”Œλ¦¬μΌ€μ΄μ…˜ 둜직"""
231
+ st.title("MisconcepTutor")
232
+
233
+ # Generator μ΄ˆκΈ°ν™”
234
+ generator = load_question_generator()
235
+
236
+ # 초기 ν™”λ©΄
237
+ if st.session_state.current_step == 'initial':
238
+ st.write("#### ν•™μŠ΅μ„ μ‹œμž‘ν•˜κ² μŠ΅λ‹ˆλ‹€. 10개의 문제λ₯Ό ν’€μ–΄λ³ΌκΉŒμš”?")
239
+ if st.button("ν•™μŠ΅ μ‹œμž‘", key="start_quiz"):
240
+ start_quiz()
241
+ st.rerun()
242
+
243
+ # ν€΄μ¦ˆ ν™”λ©΄
244
+ # elif st.session_state.current_step == 'quiz':
245
+ # current_q = st.session_state.questions.iloc[st.session_state.current_question_index]
246
+
247
+ # # μ§„ν–‰ 상황 ν‘œμ‹œ
248
+ # progress = st.session_state.current_question_index / 10
249
+ # st.progress(progress)
250
+ # st.write(f"### 문제 {st.session_state.current_question_index + 1}/10")
251
+
252
+ # # 문제 ν‘œμ‹œ
253
+ # st.markdown("---")
254
+ # #display_math_question(current_q['QuestionText'])
255
+ # display_math_content(current_q['QuestionText']) # display_math_question λŒ€μ‹  display_math_content μ‚¬μš©
256
+
257
+ # # 보기 ν‘œμ‹œ
258
+ # col1, col2 = st.columns(2)
259
+ # with col1:
260
+ # if st.button(f"A) {latex_formatter.format_expression(current_q['AnswerAText'])}", key="A"):
261
+ # handle_answer('A', current_q)
262
+ # st.rerun()
263
+ # if st.button(f"C) {latex_formatter.format_expression(current_q['AnswerCText'])}", key="C"):
264
+ # handle_answer('C', current_q)
265
+ # st.rerun()
266
+ # with col2:
267
+ # if st.button(f"B) {latex_formatter.format_expression(current_q['AnswerBText'])}", key="B"):
268
+ # handle_answer('B', current_q)
269
+ # st.rerun()
270
+ # if st.button(f"D) {latex_formatter.format_expression(current_q['AnswerDText'])}", key="D"):
271
+ # handle_answer('D', current_q)
272
+ # st.rerun()
273
+ # ν€΄μ¦ˆ ν™”λ©΄
274
+ elif st.session_state.current_step == 'quiz':
275
+ current_q = st.session_state.questions.iloc[st.session_state.current_question_index]
276
+
277
+ # μ§„ν–‰ 상황 ν‘œμ‹œ
278
+ progress = st.session_state.current_question_index / 10
279
+ st.progress(progress)
280
+ st.write(f"### 문제 {st.session_state.current_question_index + 1}/10")
281
+
282
+ # Extract question and answers
283
+ question_text = current_q['QuestionText'] # LaTeX content for the question
284
+ answers = {
285
+ 'A': current_q['AnswerAText'],
286
+ 'B': current_q['AnswerBText'],
287
+ 'C': current_q['AnswerCText'],
288
+ 'D': current_q['AnswerDText']
289
+ }
290
+
291
+ # Display the question and answers
292
+ selected_answer = display_question_and_answers(question_text, answers)
293
+
294
+ # Handle answer selection
295
+ if selected_answer:
296
+ handle_answer(selected_answer, current_q)
297
+ st.rerun()
298
+ # 볡슡 ν™”λ©΄
299
+ elif st.session_state.current_step == 'review':
300
+ st.write("### ν•™μŠ΅ κ²°κ³Ό")
301
+
302
+ # κ²°κ³Ό 톡계
303
+ col1, col2, col3 = st.columns(3)
304
+ col1.metric("총 문제 수", 10)
305
+ col2.metric("λ§žμ€ 문제", 10 - len(st.session_state.wrong_questions))
306
+ col3.metric("ν‹€λ¦° 문제", len(st.session_state.wrong_questions))
307
+
308
+ # 결과에 λ”°λ₯Έ λ©”μ‹œμ§€ ν‘œμ‹œ
309
+ if len(st.session_state.wrong_questions) == 0:
310
+ st.balloons() # μΆ•ν•˜ 효과
311
+ st.success("πŸŽ‰ μΆ•ν•˜ν•©λ‹ˆλ‹€! λͺ¨λ“  문제λ₯Ό λ§žμΆ”μ…¨μ–΄μš”!")
312
+ st.markdown("""
313
+ ### πŸ† μˆ˜ν•™μ™•μ΄μ‹­λ‹ˆλ‹€!
314
+ μ™„λ²½ν•œ 점수λ₯Ό λ°›μœΌμ…¨λ„€μš”! μˆ˜ν•™μ  κ°œλ…μ„ μ •ν™•ν•˜κ²Œ μ΄ν•΄ν•˜κ³  계신 것 κ°™μŠ΅λ‹ˆλ‹€.
315
+ """)
316
+ elif len(st.session_state.wrong_questions) <= 3:
317
+ st.success("잘 ν•˜μ…¨μ–΄μš”! 쑰금만 더 μ—°μŠ΅ν•˜λ©΄ μ™„λ²½ν•  κ±°μ˜ˆμš”!")
318
+ else:
319
+ st.info("천천히 κ°œλ…μ„ λ³΅μŠ΅ν•΄λ³΄μ•„μš”. μ—°μŠ΅ν•˜λ‹€ 보면 λŠ˜μ–΄λ‚  κ±°μ˜ˆμš”!")
320
+
321
+ # λ„€λΉ„κ²Œμ΄μ…˜ λ²„νŠΌ
322
+ col1, col2 = st.columns(2)
323
+ with col1:
324
+ if st.button("πŸ”„ μƒˆλ‘œμš΄ 문제 μ„ΈνŠΈ μ‹œμž‘ν•˜κΈ°", use_container_width=True):
325
+ start_quiz()
326
+ st.rerun()
327
+ with col2:
328
+ if st.button("🏠 처음으둜 λŒμ•„κ°€κΈ°", use_container_width=True):
329
+ st.session_state.clear()
330
+ st.rerun()
331
+
332
+ # ν‹€λ¦° 문제 뢄석 λΆ€λΆ„
333
+ if st.session_state.wrong_questions:
334
+ st.write("### ✍️ ν‹€λ¦° 문제 뢄석")
335
+ tabs = st.tabs([f"πŸ“ ν‹€λ¦° 문제 #{i + 1}" for i in range(len(st.session_state.wrong_questions))])
336
+
337
+ for i, (tab, (wrong_q, misconception_id)) in enumerate(zip(
338
+ tabs,
339
+ zip(st.session_state.wrong_questions, st.session_state.misconceptions)
340
+ )):
341
+ with tab:
342
+ st.write("**πŸ“‹ 문제:**")
343
+ st.write(wrong_q['QuestionText'])
344
+ st.write("**βœ… μ •λ‹΅:**", wrong_q['CorrectAnswer'])
345
+
346
+ st.write("---")
347
+ st.write("**πŸ” κ΄€λ ¨λœ Misconception:**")
348
+ if misconception_id and not pd.isna(misconception_id):
349
+ misconception_text = generator.get_misconception_text(misconception_id)
350
+ st.info(f"Misconception ID: {int(misconception_id)}\n\n{misconception_text}")
351
+ else:
352
+ st.info("Misconception 정보가 μ—†μŠ΅λ‹ˆλ‹€.")
353
+
354
+ if st.button(f"πŸ“š μœ μ‚¬ 문제 ν’€κΈ°", key=f"retry_{i}"):
355
+ st.session_state[f"show_similar_question_{i}"] = True
356
+ st.session_state[f"similar_question_answered_{i}"] = False
357
+ st.rerun()
358
+
359
+ if st.session_state.get(f"show_similar_question_{i}", False):
360
+ st.divider()
361
+ new_question = generate_similar_question(wrong_q, misconception_id, generator)
362
+ if new_question:
363
+ st.write("### 🎯 μœ μ‚¬ 문제")
364
+ #st.write(new_question['question'])
365
+ display_math_question(new_question['question'])
366
+
367
+
368
+ # λ‹΅λ³€ μƒνƒœ 확인
369
+ answered = st.session_state.get(f"similar_question_answered_{i}", False)
370
+
371
+ # 보기 ν‘œμ‹œ
372
+ st.write("**보기:**")
373
+ col1, col2 = st.columns(2)
374
+
375
+ # # λ‹΅λ³€ν•˜μ§€ μ•Šμ€ κ²½μš°μ—λ§Œ λ²„νŠΌ ν™œμ„±ν™”
376
+ # if not answered:
377
+ # with col1:
378
+ # for option in ['A', 'C']:
379
+ # if st.button(
380
+ # f"{option}) {new_question['choices'][option]}",
381
+ # key=f"similar_{option}_{i}"
382
+ # ):
383
+ # st.session_state[f"similar_question_answered_{i}"] = True
384
+ # st.session_state[f"selected_answer_{i}"] = option
385
+ # correct_answer = st.session_state.get('current_similar_question_answer')
386
+ # if option == correct_answer:
387
+ # st.session_state[f"is_correct_{i}"] = True
388
+ # else:
389
+ # st.session_state[f"is_correct_{i}"] = False
390
+ # st.rerun()
391
+
392
+ # with col2:
393
+ # for option in ['B', 'D']:
394
+ # if st.button(
395
+ # f"{option}) {new_question['choices'][option]}",
396
+ # key=f"similar_{option}_{i}"
397
+ # ):
398
+ # st.session_state[f"similar_question_answered_{i}"] = True
399
+ # st.session_state[f"selected_answer_{i}"] = option
400
+ # correct_answer = st.session_state.get('current_similar_question_answer')
401
+ # if option == correct_answer:
402
+ # st.session_state[f"is_correct_{i}"] = True
403
+ # else:
404
+ # st.session_state[f"is_correct_{i}"] = False
405
+ # st.rerun()
406
+ # λ‹΅λ³€ν•˜μ§€ μ•Šμ€ κ²½μš°μ—λ§Œ λ²„νŠΌ ν™œμ„±ν™”
407
+ if not answered:
408
+ with col1:
409
+ for option in ['A', 'C']:
410
+ if st.button(
411
+ f"{option}) {latex_formatter.format_expression(new_question['choices'][option])}",
412
+ key=f"similar_{option}_{i}"
413
+ ):
414
+ st.session_state[f"similar_question_answered_{i}"] = True
415
+ st.session_state[f"selected_answer_{i}"] = option
416
+ correct_answer = st.session_state.get('current_similar_question_answer')
417
+ if option == correct_answer:
418
+ st.session_state[f"is_correct_{i}"] = True
419
+ else:
420
+ st.session_state[f"is_correct_{i}"] = False
421
+ st.rerun()
422
+
423
+ with col2:
424
+ for option in ['B', 'D']:
425
+ if st.button(
426
+ f"{option}) {format_math_expression(new_question['choices'][option])}",
427
+ key=f"similar_{option}_{i}"
428
+ ):
429
+ st.session_state[f"similar_question_answered_{i}"] = True
430
+ st.session_state[f"selected_answer_{i}"] = option
431
+ correct_answer = st.session_state.get('current_similar_question_answer')
432
+ if option == correct_answer:
433
+ st.session_state[f"is_correct_{i}"] = True
434
+ else:
435
+ st.session_state[f"is_correct_{i}"] = False
436
+ st.rerun()
437
+ # λ‹΅λ³€ν•œ 경우 κ²°κ³Ό ν‘œμ‹œ
438
+ if answered:
439
+ is_correct = st.session_state.get(f"is_correct_{i}", False)
440
+ correct_answer = st.session_state.get('current_similar_question_answer')
441
+ if is_correct:
442
+ st.success("βœ… μ •λ‹΅μž…λ‹ˆλ‹€!")
443
+ else:
444
+ st.error(f"❌ ν‹€λ ΈμŠ΅λ‹ˆλ‹€. 정닡은 {correct_answer}μž…λ‹ˆλ‹€.")
445
+
446
+ # ν•΄μ„€ ν‘œμ‹œ
447
+ st.write("---")
448
+ st.write("**πŸ“ ν•΄μ„€:**", new_question['explanation'])
449
+
450
+ # λ‹€μ‹œ ν’€κΈ° λ²„νŠΌ
451
+ if st.button("πŸ”„ λ‹€μ‹œ ν’€κΈ°", key=f"reset_{i}"):
452
+ st.session_state[f"similar_question_answered_{i}"] = False
453
+ st.session_state[f"selected_answer_{i}"] = None
454
+ st.session_state[f"is_correct_{i}"] = None
455
+ st.rerun()
456
+
457
+ # 문제 λ‹«κΈ° λ²„νŠΌ
458
+ if st.button("❌ 문제 λ‹«κΈ°", key=f"close_{i}"):
459
+ st.session_state[f"show_similar_question_{i}"] = False
460
+ st.session_state[f"similar_question_answered_{i}"] = False
461
+ st.session_state[f"selected_answer_{i}"] = None
462
+ st.session_state[f"is_correct_{i}"] = None
463
+ st.rerun()
464
+
465
+ # ν™”λ©΄ μ•„λž˜ μ—¬λ°± μΆ”κ°€
466
+ st.markdown("<br>" * 5, unsafe_allow_html=True) # 5μ€„μ˜ 빈 쀄 μΆ”κ°€
467
+ st.markdown("""
468
+ <div style="height: 100px;">
469
+ </div>
470
+ """, unsafe_allow_html=True) # μΆ”κ°€ μ—¬λ°±
471
+ else:
472
+ st.error("μœ μ‚¬ 문제λ₯Ό 생성할 수 μ—†μŠ΅λ‹ˆλ‹€.")
473
+ if st.button("❌ λ‹«κΈ°", key=f"close_error_{i}"):
474
+ st.session_state[f"show_similar_question_{i}"] = False
475
+ st.rerun()
476
+ # ν™”λ©΄ μ•„λž˜ μ—¬λ°± μΆ”κ°€
477
+ st.markdown("<br>" * 5, unsafe_allow_html=True) # 5μ€„μ˜ 빈 쀄 μΆ”κ°€
478
+ st.markdown("""
479
+ <div style="height: 100px;">
480
+ </div>
481
+ """, unsafe_allow_html=True) # μΆ”κ°€ μ—¬λ°±
482
+ if __name__ == "__main__":
483
+ main()
484
+
485
+ # random_state 42μ—μ„œ μ •λ‹΅
486
+ # D C A A C
487
+ # A B B B B