import streamlit as st import pandas as pd import os import logging from module2 import SimilarQuestionGenerator, generate_similar_question # 로깅 설정 logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # Streamlit 페이지 기본 설정 st.set_page_config( page_title="MisconcepTutor", layout="wide", initial_sidebar_state="expanded" ) # 경로 설정 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') # 세션 상태 초기화 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' # 메인 애플리케이션 로직 def main(): st.title("MisconcepTutor") generator = load_question_generator() 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("---") st.write(current_q['QuestionText']) col1, col2 = st.columns(2) with col1: if st.button(f"A) {current_q['AnswerAText']}", key="A"): handle_answer('A', current_q) st.rerun() if st.button(f"C) {current_q['AnswerCText']}", key="C"): handle_answer('C', current_q) st.rerun() with col2: if st.button(f"B) {current_q['AnswerBText']}", key="B"): handle_answer('B', current_q) st.rerun() if st.button(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 len(st.session_state.wrong_questions) == 0: st.balloons() st.success("🎉 모든 문제를 맞추셨습니다!") elif len(st.session_state.wrong_questions) <= 3: st.success("잘 하셨어요! 조금만 더 연습하면 완벽해질 거예요!") else: st.info("천천히 개념을 복습해 보세요. 연습하면 나아질 겁니다.") if st.session_state.wrong_questions: st.write("### ✍️ 틀린 문제 분석") for i, (wrong_q, misconception_id) in enumerate(zip( st.session_state.wrong_questions, st.session_state.misconceptions )): with st.expander(f"📝 틀린 문제 #{i + 1}"): st.write(wrong_q['QuestionText']) st.write(f"✅ 정답: {wrong_q['CorrectAnswer']}") if misconception_id: misconception_text = generator.get_misconception_text(misconception_id) st.info(f"Misconception: {misconception_text}") if st.button(f"📚 유사 문제 풀기 #{i + 1}", key=f"retry_{i}"): new_question = generate_similar_question(wrong_q, misconception_id, generator) if new_question: st.write("### 🎯 유사 문제") st.write(new_question['question']) for choice, text in new_question['choices'].items(): st.write(f"{choice}) {text}") st.write(f"✅ 정답: {new_question['correct']}") st.write(f"📝 해설: {new_question['explanation']}") else: st.error("유사 문제를 생성할 수 없습니다.") if __name__ == "__main__": main()