Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import requests | |
| from pipelines import generate_quiz | |
| import shelve | |
| from dataclasses import dataclass | |
| from typing import Literal | |
| import streamlit.components.v1 as components | |
| st.title(":red[DEV] *the Quizbot* 🤖") | |
| st.subheader("Hey there! I'm **Dev** the QuizBot! Ready to flaunt your smarts in a topic of your choice?", divider='grey') | |
| def warn(): | |
| st.write("Please choose from the given options.") | |
| class Message: | |
| origin: Literal["human", "ai"] | |
| message: str | |
| def load_css(): | |
| with open("static/styles.css", "r") as f: | |
| st.markdown(f"<style>{f.read()}</style>", unsafe_allow_html=True) | |
| def initialize_session_state(): | |
| defaults = { | |
| "quiz": None, | |
| "current_question_index": 0, | |
| "responses": [], | |
| "interactions": [], | |
| "quiz_completed": False, | |
| "topic": None, | |
| "messages": load_chat_history() | |
| } | |
| for key, value in defaults.items(): | |
| if key not in st.session_state: | |
| st.session_state[key] = value | |
| def load_chat_history(): | |
| with shelve.open("chat_history") as db: | |
| return db.get("messages", []) | |
| def save_chat_history(messages): | |
| with shelve.open("chat_history") as db: | |
| db["messages"] = messages | |
| from urllib.parse import quote | |
| def fetch_wikipedia_link(topic: str) -> str | None: | |
| try: | |
| encoded_topic = quote(topic) | |
| api_url = f"https://en.wikipedia.org/api/rest_v1/page/summary/{encoded_topic}" | |
| headers = { | |
| "User-Agent": "QuizBot/1.0 (https://huggingface.co/your-space) Python/3.x" | |
| } | |
| response = requests.get(api_url, headers=headers, timeout=5) | |
| if response.status_code != 200: | |
| st.error(f"Failed to fetch Wikipedia content for '{topic}' (status {response.status_code})") | |
| return None | |
| data = response.json() | |
| return data.get("content_urls", {}).get("desktop", {}).get("page") | |
| except requests.RequestException as e: | |
| st.error(f"Network error: {e}") | |
| return None | |
| load_css() | |
| initialize_session_state() | |
| placeholder = st.container() | |
| if st.session_state.quiz is None: | |
| st.session_state.interactions = [] | |
| with st.form("generate_quiz_form"): | |
| st.markdown('**Enter a Topic:**') | |
| cols = st.columns((4, 1)) | |
| topic = cols[0].text_input("Topic:", label_visibility="collapsed") | |
| generate_button = cols[1].form_submit_button("Generate Quiz") | |
| if generate_button: | |
| if topic: | |
| link = fetch_wikipedia_link(topic) | |
| if link: | |
| for _ in range(2): | |
| try: | |
| quiz = generate_quiz(link) | |
| if quiz: | |
| st.session_state.quiz = quiz | |
| st.session_state.current_question_index = 0 | |
| st.session_state.responses = [] | |
| st.session_state.quiz_completed = False | |
| st.rerun() | |
| except Exception as e: | |
| st.error(f"Failed to generate quiz: {e}") | |
| else: | |
| st.error("Please enter a topic.") | |
| else: | |
| with st.form("quiz_form"): | |
| if st.session_state.quiz_completed: | |
| st.markdown("## Results") | |
| score = sum(1 for interaction in st.session_state.interactions if interaction["is_correct"]) | |
| if score > len(st.session_state.quiz['questions']): | |
| score = len(st.session_state.quiz['questions']) | |
| st.markdown(f"Your score: {score} out of {len(st.session_state.quiz['questions'])}") | |
| try_again_button = st.form_submit_button("Try Again") | |
| if try_again_button: | |
| for key in ["quiz", "current_question_index", "responses", "interactions", "quiz_completed", "topic"]: | |
| st.session_state[key] = None if key == "quiz" else 0 if key == "current_question_index" else [] | |
| st.cache_data.clear() | |
| st.rerun() | |
| else: | |
| current_question_index = st.session_state.current_question_index | |
| if current_question_index < len(st.session_state.quiz["questions"]): | |
| question = st.session_state.quiz["questions"][current_question_index] | |
| question_text = question.get('question', question.get('statement', question.get('prompt', ''))) | |
| options = question.get("options", []) | |
| st.markdown(f"**Question {current_question_index + 1}:** {question_text}") | |
| if options: | |
| st.markdown("Choices:") | |
| for option in options: | |
| st.markdown(option) | |
| user_response = st.text_input("Your answer:", key=f"input_{current_question_index}") | |
| submit_button = st.form_submit_button("Submit Answer") | |
| if submit_button: | |
| st.session_state[f"answer_{current_question_index}"] = user_response | |
| correct_answer = question.get("right_option", question.get("answer")) | |
| if options and options[0].lower() in ['true', 'false']: | |
| invalid_option = user_response.lower() not in ["true", "false"] | |
| else: | |
| valid_options = [opt[0].lower() for opt in options] | |
| invalid_option = user_response.lower() not in valid_options and question.get("statement") is None | |
| is_correct = user_response.lower() == correct_answer.lower() | |
| st.session_state.responses.append(user_response) | |
| st.session_state.interactions.append({ | |
| "question": question_text, | |
| "user_response": user_response, | |
| "correct_answer": correct_answer, | |
| "is_correct": is_correct, | |
| "invalid_option": invalid_option, | |
| "options": options | |
| }) | |
| if not invalid_option: | |
| st.session_state.current_question_index += 1 | |
| if st.session_state.current_question_index >= len(st.session_state.quiz["questions"]): | |
| st.session_state.quiz_completed = True | |
| st.rerun() | |
| else: | |
| warn() | |
| with placeholder.container(): | |
| if st.session_state.interactions: | |
| i = 0 | |
| for idx, interaction in enumerate(st.session_state.interactions): | |
| if interaction['invalid_option']: | |
| continue | |
| options_html = "<br>".join(interaction['options']) | |
| question_html = f"Question {i + 1}: {interaction['question']}<br>Choices:<br>{options_html}" | |
| div = f""" | |
| <div class="chat-row"> | |
| <img class="chat-icon" src="/static/ai_icon.png" width=32 height=32> | |
| <div class="chat-bubble ai-bubble"> | |
| {question_html} | |
| </div> | |
| </div> | |
| """ | |
| st.markdown(div, unsafe_allow_html=True) | |
| user_response_html = f"Your answer: {interaction['user_response']}" | |
| div = f""" | |
| <div class="chat-row row-reverse"> | |
| <img class="chat-icon" src="/static/user_icon.png" width=32 height=32> | |
| <div class="chat-bubble human-bubble"> | |
| {user_response_html} | |
| </div> | |
| </div> | |
| """ | |
| st.markdown(div, unsafe_allow_html=True) | |
| feedback_html = f"Correct! The correct answer is: {interaction['correct_answer']}" if interaction['is_correct'] else f"Wrong. The correct answer is: {interaction['correct_answer']}" | |
| div = f""" | |
| <div class="chat-row"> | |
| <img class="chat-icon" src="/static/ai_icon.png" width=32 height=32> | |
| <div class="chat-bubble ai-bubble"> | |
| {feedback_html} | |
| </div> | |
| </div> | |
| """ | |
| if idx == len(st.session_state.interactions) - 1: | |
| div = f'<div id="last-message">{div}</div>' | |
| st.markdown(div, unsafe_allow_html=True) | |
| i += 1 | |
| save_chat_history(st.session_state.messages) | |
| components.html(""" | |
| <script> | |
| const streamlitDoc = window.parent.document; | |
| function scrollToBottom() { | |
| const lastMessage = streamlitDoc.getElementById('last-message'); | |
| if (lastMessage) { | |
| lastMessage.scrollIntoView({ behavior: 'smooth' }); | |
| } | |
| } | |
| function focusInput() { | |
| const answerInput = streamlitDoc.getElementById('answer_input'); | |
| if (answerInput) { | |
| answerInput.focus(); | |
| } | |
| } | |
| scrollToBottom(); | |
| focusInput(); | |
| const buttons = Array.from( | |
| streamlitDoc.querySelectorAll('.stButton > button') | |
| ); | |
| const submitButton = buttons.find( | |
| el => el.innerText === 'Submit Answer' | |
| ); | |
| streamlitDoc.addEventListener('keydown', function(e) { | |
| if (e.key === 'Enter') { | |
| submitButton.click(); | |
| setTimeout(() => { | |
| scrollToBottom(); | |
| focusInput(); | |
| }, 500); | |
| } | |
| }); | |
| </script> | |
| """, height=0, width=0) | |