SE_MED_I / app.py
HaileyIsNotAPig's picture
Upload app.py
927b017 verified
Raw History Blame Contribute Delete
7.36 kB
import sqlite3
import streamlit as st
import random
import time
from datetime import datetime, timedelta
class QuizApp:
def __init__(self):
self.conn = sqlite3.connect('exam.db')
self.cursor = self.conn.cursor()
self.initialize_session_state()
def fetch_questions(self, year, trial, paper_id):
self.cursor.execute('''
SELECT question_id, question, option_A, option_B, option_C, option_D, answer
FROM exam_questions
WHERE year = ? AND trial = ? AND id = ?
''', (year, trial, paper_id))
questions = self.cursor.fetchall()
return questions
def initialize_session_state(self):
if 'questions' not in st.session_state:
st.session_state['questions'] = []
if 'user_answers' not in st.session_state:
st.session_state['user_answers'] = {}
if 'current_question_index' not in st.session_state:
st.session_state['current_question_index'] = 0
if 'start_time' not in st.session_state:
st.session_state['start_time'] = time.time()
if 'quiz_ended' not in st.session_state:
st.session_state['quiz_ended'] = False
if 'score' not in st.session_state:
st.session_state['score'] = 0
if 'wrong_answers' not in st.session_state:
st.session_state['wrong_answers'] = []
if 'quiz_started' not in st.session_state:
st.session_state['quiz_started'] = False
if 'end_time' not in st.session_state:
st.session_state['end_time'] = datetime.now() + timedelta(minutes=120)
if 'question_order' not in st.session_state:
st.session_state['question_order'] = []
def extract_image_url(self, question_text):
img_tag_start = '<img src="'
img_tag_end = '"'
start_index = question_text.find(img_tag_start)
if start_index != -1:
end_index = question_text.find(img_tag_end, start_index+len(img_tag_start))
if end_index != -1:
return question_text[start_index+len(img_tag_start):end_index]
return None
def show_question(self, index):
question_id, question, option_A, option_B, option_C, option_D, _ = st.session_state['questions'][index]
options = ['A', 'B', 'C', 'D']
options_text = [option_A, option_B, option_C, option_D]
selected_option = st.session_state['user_answers'].get(question_id, None)
image_url = self.extract_image_url(question)
if image_url:
question = question.replace(f'<img src="{image_url}" />', '')
return question, options_text, options, selected_option, image_url
def submit_answer(self, selected_option):
question_id = st.session_state['questions'][st.session_state['current_question_index']][0]
st.session_state['user_answers'][question_id] = selected_option
def next_question(self):
if st.session_state['current_question_index'] < len(st.session_state['questions'])-1:
st.session_state['current_question_index']+=1
else:
self.end_quiz()
def end_quiz(self):
score = 0
wrong_answers = []
for question in st.session_state['questions']:
question_id, _, _, _, _, _, correct_answer = question
if str(st.session_state['user_answers'].get(question_id)) == correct_answer:
score+=1
else:
wrong_answers.append((question_id, correct_answer))
st.session_state['score'] = score
st.session_state['wrong_answers'] = sorted(wrong_answers, key=lambda x: int(x[0]))
st.session_state['quiz_ended'] = True
def render_quiz(self):
timer_placeholder = st.empty()
if not st.session_state['quiz_ended']:
question, options_text, options, selected_option, image_url = self.show_question(st.session_state['current_question_index'])
st.write(f"{st.session_state['current_question_index']+1}. {question}")
if image_url:
st.image(image_url)
# Ensure form submission logic is handled correctly
with st.form(key="quiz_form"):
selected_option_text = st.radio("Choose an option", options_text, index=options_text.index(selected_option) if selected_option else 0)
submit_button = st.form_submit_button(label="Submit Answer")
if submit_button:
selected_option = options[options_text.index(selected_option_text)]
print(selected_option, selected_option_text)
self.submit_answer(selected_option)
self.next_question()
st.experimental_rerun()
st.button("End Quiz", on_click=self.end_quiz)
# Dynamic countdown timer
remaining_time = st.session_state['end_time'] - datetime.now()
if remaining_time.total_seconds()>0:
minutes, seconds = divmod(remaining_time.total_seconds(), 60)
timer_placeholder.markdown(f"## 剩餘時間: {int(minutes):02d}:{int(seconds):02d}")
time.sleep(1)
st.experimental_rerun()
else:
self.end_quiz()
else:
st.write(f"Score: {st.session_state['score']}/{len(st.session_state['questions'])}")
selected_id = st.selectbox("Select Question to View Details", range(1, len(st.session_state['questions'])+1))
if selected_id-1 is not None:
question = st.session_state['questions'][selected_id-1]
st.write(f"試卷題號: {question[0]}")
st.write(f"{question[1]}")
st.write(f"A. {question[2]}")
st.write(f"B. {question[3]}")
st.write(f"C. {question[4]}")
st.write(f"D. {question[5]}")
st.write(f"答案: {question[6]}")
def render(self):
if not st.session_state['quiz_started']:
st.title("考古題選擇")
year = st.selectbox("年份", ['111', '112', '113'])
trial = st.selectbox("場次", ("寒考", "暑考"))
paper_id = st.selectbox("考卷", ("醫師(一)", "醫師(二)"))
if st.button("Submit"):
if trial == "寒考":
trial_q = 1
else:
trial_q = 2
if paper_id == "醫師(一)":
id_q = 1
else:
id_q = 2
st.session_state['questions'] = self.fetch_questions(year, trial_q, id_q)
if st.session_state['questions']:
random.shuffle(st.session_state['questions'])
st.session_state['question_order'] = [q[0] for q in st.session_state['questions']]
st.session_state['quiz_started'] = True
st.session_state['end_time'] = datetime.now()+timedelta(minutes=120)
st.experimental_rerun()
else:
st.write("找不到對應的考卷,請重新選擇。")
else:
self.render_quiz()
if __name__ == "__main__":
app = QuizApp()
app.render()