File size: 7,404 Bytes
ca27c07
 
 
346db8d
ca27c07
 
 
 
ad27fcf
0ae7414
ca27c07
 
0e679fe
 
 
 
 
 
c3e24fe
0e679fe
 
ca27c07
 
 
 
 
 
 
0a8c581
1883518
 
 
 
ad27fcf
ca27c07
 
 
 
 
 
 
 
 
ad27fcf
ca27c07
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ad27fcf
ca27c07
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ad27fcf
ca27c07
 
 
ad27fcf
ca27c07
 
 
 
0ae7414
 
cd93920
d48ae52
cd93920
0ae7414
d48ae52
cd93920
ca27c07
 
 
ad27fcf
 
 
ca27c07
 
 
 
 
 
 
 
 
 
 
ad27fcf
ca27c07
 
 
 
ad27fcf
ca27c07
 
ad27fcf
cd93920
ca27c07
 
 
383b796
ca27c07
 
ad27fcf
ca27c07
 
 
ad27fcf
ca27c07
 
ad27fcf
ca27c07
 
ad27fcf
ca27c07
 
 
ad27fcf
ca27c07
 
 
 
 
ad27fcf
 
ca27c07
 
9dc334f
ad27fcf
9dc334f
 
 
ca27c07
9dc334f
ca27c07
 
 
ad27fcf
ca27c07
 
 
ad27fcf
ca27c07
 
 
f66fe0a
ca27c07
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
import streamlit as st
import pandas as pd
import os
from src.FisrtModule.module1 import MisconceptionModel
from src.SecondModule.module2 import SimilarQuestionGenerator
from src.ThirdModule.module3 import AnswerVerifier
import logging
from typing import Optional, Tuple
from latex_formatter import LatexFormatter

logging.basicConfig(level=logging.DEBUG)

# Initialize Misconception Model
@st.cache_resource
def load_misconception_model():
    return MisconceptionModel(
        model_name="minsuas/Misconceptions__1",
        misconception_mapping_path=os.path.join(data_path, 'misconception_mapping.parquet'),
        misconception_embs_paths=[os.path.join(data_path, f'embs_misconception-9-9.npy')]
    )

# Streamlit ํŽ˜์ด์ง€ ๊ธฐ๋ณธ ์„ค์ •
st.set_page_config(
    page_title="MisconcepTutor", 
    layout="wide", 
    initial_sidebar_state="expanded"
)

@st.cache_resource
def load_answer_verifier():
    """๋‹ต์•ˆ ๊ฒ€์ฆ ๋ชจ๋ธ ๋กœ๋“œ"""
    from src.ThirdModule.module3 import AnswerVerifier
    return AnswerVerifier()

# ๊ฒฝ๋กœ ์„ค์ •
base_path = os.path.dirname(os.path.abspath(__file__))
data_path = os.path.join(base_path, 'Data')
misconception_csv_path = os.path.join(data_path, 'misconception_mapping.csv')

# ๋กœ๊น… ์„ค์ •
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# ์„ธ์…˜ ์ƒํƒœ ์ดˆ๊ธฐํ™”
if 'initialized' not in st.session_state:
    st.session_state.initialized = True
    st.session_state.wrong_questions = []
    st.session_state.misconceptions = []
    st.session_state.current_question_index = 0
    st.session_state.generated_questions = []
    st.session_state.current_step = 'initial'
    st.session_state.selected_wrong_answer = None
    st.session_state.questions = []
    logger.info("Session state initialized")

# ๋ฌธ์ œ ์ƒ์„ฑ๊ธฐ ์ดˆ๊ธฐํ™”
@st.cache_resource
def load_question_generator():
    """๋ฌธ์ œ ์ƒ์„ฑ ๋ชจ๋ธ ๋กœ๋“œ"""
    if not os.path.exists(misconception_csv_path):
        st.error(f"CSV ํŒŒ์ผ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค: {misconception_csv_path}")
        raise FileNotFoundError(f"CSV ํŒŒ์ผ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค: {misconception_csv_path}")
    return SimilarQuestionGenerator(misconception_csv_path=misconception_csv_path)

# CSV ๋ฐ์ดํ„ฐ ๋กœ๋“œ ํ•จ์ˆ˜
@st.cache_data
def load_data(data_file='/train.csv'):
    try:
        file_path = os.path.join(data_path, data_file.lstrip('/'))
        df = pd.read_csv(file_path)
        logger.info(f"Data loaded successfully from {file_path}")
        return df
    except FileNotFoundError:
        st.error(f"ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {data_file}")
        logger.error(f"File not found: {data_file}")
        return None

def start_quiz():
    """ํ€ด์ฆˆ ์‹œ์ž‘ ๋ฐ ์ดˆ๊ธฐํ™”"""
    df = load_data()
    if df is None or df.empty:
        st.error("๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ์…‹์„ ํ™•์ธํ•ด์ฃผ์„ธ์š”.")
        return

    st.session_state.questions = df.sample(n=10, random_state=42)
    st.session_state.current_step = 'quiz'
    st.session_state.current_question_index = 0
    st.session_state.wrong_questions = []
    st.session_state.misconceptions = []
    st.session_state.generated_questions = []
    logger.info("Quiz started")

def handle_answer(answer, current_q):
    """๋‹ต๋ณ€ ์ฒ˜๋ฆฌ"""
    if answer != current_q['CorrectAnswer']:
        wrong_q_dict = current_q.to_dict()
        st.session_state.wrong_questions.append(wrong_q_dict)
        st.session_state.selected_wrong_answer = answer

        misconception_key = f'Misconception{answer}Id'
        misconception_id = current_q.get(misconception_key)
        st.session_state.misconceptions.append(misconception_id)

    st.session_state.current_question_index += 1
    if st.session_state.current_question_index >= 10:
        st.session_state.current_step = 'review'

# ์ „์—ญ LaTeX ํฌ๋งทํ„ฐ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
latex_formatter = LatexFormatter()

def display_math_content(content: str):
    """์ˆ˜ํ•™ ๋‚ด์šฉ์„ ํ™”๋ฉด์— ํ‘œ์‹œ"""
    formatted_content = latex_formatter.format_expression(content)
    st.markdown(formatted_content, unsafe_allow_html=True)

def main():
    """๋ฉ”์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ์ง"""
    st.title("MisconcepTutor")

    # Misconception Model ๋กœ๋“œ
    misconception_model = load_misconception_model()

    # ์ดˆ๊ธฐ ํ™”๋ฉด
    if st.session_state.current_step == 'initial':
        st.write("#### ํ•™์Šต์„ ์‹œ์ž‘ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. 10๊ฐœ์˜ ๋ฌธ์ œ๋ฅผ ํ’€์–ด๋ณผ๊นŒ์š”?")
        if st.button("ํ•™์Šต ์‹œ์ž‘", key="start_quiz"):
            start_quiz()
            st.rerun()

    # ํ€ด์ฆˆ ํ™”๋ฉด
    elif st.session_state.current_step == 'quiz':
        current_q = st.session_state.questions.iloc[st.session_state.current_question_index]

        # ์ง„ํ–‰ ์ƒํ™ฉ ํ‘œ์‹œ
        progress = st.session_state.current_question_index / 10
        st.progress(progress)
        st.write(f"### ๋ฌธ์ œ {st.session_state.current_question_index + 1}/10")

        # ๋ฌธ์ œ ํ‘œ์‹œ
        st.markdown("---")
        display_math_content(current_q['QuestionText'])

        # ๋ณด๊ธฐ ํ‘œ์‹œ
        col1, col2 = st.columns(2)
        with col1:
            if st.button(latex_formatter.format_expression(f"A) {current_q['AnswerAText']}"), key="A"):
                handle_answer('A', current_q)
                st.rerun()
            if st.button(latex_formatter.format_expression(f"C) {current_q['AnswerCText']}"), key="C"):
                handle_answer('C', current_q)
                st.rerun()
        with col2:
            if st.button(latex_formatter.format_expression(f"B) {current_q['AnswerBText']}"), key="B"):
                handle_answer('B', current_q)
                st.rerun()
            if st.button(latex_formatter.format_expression(f"D) {current_q['AnswerDText']}"), key="D"):
                handle_answer('D', current_q)
                st.rerun()

    # ๋ณต์Šต ํ™”๋ฉด
    elif st.session_state.current_step == 'review':
        st.write("### ํ•™์Šต ๊ฒฐ๊ณผ")

        # ๊ฒฐ๊ณผ ํ†ต๊ณ„
        col1, col2, col3 = st.columns(3)
        col1.metric("์ด ๋ฌธ์ œ ์ˆ˜", 10)
        col2.metric("๋งž์€ ๋ฌธ์ œ", 10 - len(st.session_state.wrong_questions))
        col3.metric("ํ‹€๋ฆฐ ๋ฌธ์ œ", len(st.session_state.wrong_questions))

        # ํ‹€๋ฆฐ ๋ฌธ์ œ ๋ถ„์„
        if st.session_state.wrong_questions:
            st.write("### โœ๏ธ ํ‹€๋ฆฐ ๋ฌธ์ œ ๋ถ„์„")
            tabs = st.tabs([f"๐Ÿ“ ํ‹€๋ฆฐ ๋ฌธ์ œ #{i + 1}" for i in range(len(st.session_state.wrong_questions))])

            for i, (tab, (wrong_q, misconception_id)) in enumerate(zip(
                tabs,
                zip(st.session_state.wrong_questions, st.session_state.misconceptions)
            )):
                with tab:
                    st.write("**๐Ÿ“‹ ๋ฌธ์ œ:**")
                    st.write(wrong_q['QuestionText'])
                    st.write("**โœ… ์ •๋‹ต:**", wrong_q['CorrectAnswer'])

                    st.write("---")
                    st.write("**๐Ÿ” ๊ด€๋ จ๋œ Misconception:**")
                    if misconception_id and not pd.isna(misconception_id):
                        misconception_text = misconception_model.misconception_names.get(misconception_id, "์ •๋ณด ์—†์Œ")
                        st.info(f"Misconception ID: {int(misconception_id)}\n\n{misconception_text}")
                    else:
                        st.info("Misconception ์ •๋ณด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.")

if __name__ == "__main__":
    main()