import streamlit as st import sqlite3 import time import datetime from PIL import Image import google.generativeai as genai import os from reportlab.pdfgen import canvas from reportlab.lib.pagesizes import A4, letter from io import BytesIO import tempfile import json import re from reportlab.platypus import Paragraph, Frame, Spacer from reportlab.lib.styles import getSampleStyleSheet import shutil from pdfutils import generate_quiz_content, create_pdf, create_json, generate_metadata, merge_json_strings, generate_text, clean_markdown MODEL_ID = "gemini-2.0-flash-exp" api_key = os.getenv("GEMINI_API_KEY") model_id = MODEL_ID genai.configure(api_key=api_key) if "model" not in st.session_state: st.session_state.model = genai.GenerativeModel(MODEL_ID) if "chat" not in st.session_state: st.session_state.chat = st.session_state.model.start_chat() def get_system_instruction(username): """ Retrieves the system instruction for the user from the database. """ conn = sqlite3.connect('users.db') c = conn.cursor() c.execute('SELECT instruction FROM system_instructions WHERE username=?', (username,)) instruction = c.fetchone() conn.close() if instruction: return instruction[0] else: return "Default system instruction." def save_user_prompt(username, prompt_time, prompt_type): """ Saves the user prompt to the database for monitoring purposes. """ conn = sqlite3.connect('users.db') c = conn.cursor() c.execute('INSERT INTO user_prompts(username, prompt_time, prompt_type) VALUES (?,?,?)', (username, prompt_time, prompt_type)) conn.commit() conn.close() def show_text_prompt(): st.subheader("Text Prompt") username = st.session_state["username"] st.write(f"Welcome, {username}! This page allows you to generate questions based on user inputs.") # Display username and logout button on every page st.sidebar.write(f"Current user: {st.session_state['username']}") # User inputs # Course selection course = st.text_input("Enter Course", "e.g.,Bachelor of Secondary Education") # Year level selection year_level = st.selectbox("Select Year Level", ["1st Year", "2nd Year", "3rd Year", "4th Year"]) # Subject selection subject = st.text_input("Enter Subject", "e.g.,The Teaching Profession, Facilitating Learner-Centered Teaching") # Topic selection topic = st.text_input("Enter Topic", "e.g., Teacher as a professional, Introduction to Learner-Centered Teaching") # Question type selection question_type = st.selectbox("Select Question Type", ["Multiple Choice", "True or False", "Short Response", "Essay Type"]) difficulty = st.selectbox("Select Difficulty",["easy","average","hard"]) #number of questions to generate if question_type != "Essay Type": num_questions = st.selectbox("Number of Questions to Generate", [10, 20, 30, 40, 50]) else: num_questions = st.selectbox("Number of Questions to Generate", [1, 2, 3, 4, 5]) # Combine user inputs into a prompt prompt = f"""Refer to the uploaded document. Generate a {question_type} question for a {year_level} {course} student in {subject} on the topic of {topic} with a {difficulty} difficulty level. The questions should require higher order thinking skills. """ if question_type == "Multiple Choice": prompt += """Provide 4 choices. Provide the correct answer in the format 'Answer: A'. Use the following JSON format for each question: [{ "question": "Your question here?", "options": ["Option A", "Option B", "Option C", "Option D"], "correct_answer": "full text of the correct answer" }, ... more questions] Ensure that the response only contains the JSON array of questions and nothing else. """ elif question_type == "True or False": prompt += """Indicate whether the statement is true or false. Keep the statement brief and concise. Use the following JSON format for each question: [{ "statement": "Your statement here", "options": ["True", "False"], "correct_answer": True" }, ... more questions] Ensure that the response only contains the JSON array of questions and nothing else. """ elif question_type == "Short Response": prompt += """Create question that require a word or short phrase as answer. Use the following JSON format for each question: [{ "question": "Your question here?", "correct_answer": A word or phrase" }, ... more questions] Ensure that the response only contains the JSON array of questions and nothing else. """ elif question_type == "Essay Type": prompt += """Create questions that require a short essay between 300 to 500 words. Provide a detailed answer. Use the following JSON format for each question: [{ "question": "Your question here?", "correct_answer": The essay answer goes here." }, ... more questions] Ensure that the response only contains the JSON array of questions and nothing else. """ if not question_type == "Essay Type": prompt += f"Generate 10 questions. Do not repeat questions you have already given in previous prompts. Exclude markdown tags in the response." else: prompt += f" Generate {num_questions} questions. Do not repeat questions you have already given in previous prompts. Exclude markdown tags in the response" full_quiz = "" # Send button if st.button("Generate Questions"): if question_type == "Essay Type": #prompt once with st.spinner('Generating questions...'): full_quiz = clean_markdown(generate_text(prompt)) else: if num_questions == 10: #prompt once with st.spinner('Generating questions...'): full_quiz = clean_markdown(generate_text(prompt)) else: #prompt multiple times times = num_questions//10 for i in range(times): with st.spinner('Generating questions...'): response = generate_text(prompt) if i==0: full_quiz = clean_markdown(response) else: full_quiz = merge_json_strings(full_quiz, response) metadata = generate_metadata(subject, topic, num_questions, question_type) try: # Attempt to load the string as JSON to validate it content = json.loads(full_quiz) except json.JSONDecodeError: st.error("Error: Invalid JSON string for quiz content.") st.stop() json_string = create_json(metadata, content) quiz_markdown = generate_quiz_content(json_string) st.markdown(quiz_markdown) pdf_path = create_pdf(json_string) if pdf_path: """Click the button to download the generated PDF.""" try: with open(pdf_path, "rb") as f: st.download_button("Download PDF", f, file_name=os.path.basename(pdf_path)) except Exception as e: st.error(f"Error handling file download: {e}") else: st.error("Failed to generate the PDF. Please try again.") #record the prompt for monitoring save_user_prompt(username, datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "Multimodal") if st.session_state["authenticated"]: show_text_prompt() else: if not st.session_state["is_starting"]: st.write("You are not authenticated. Please log in to access this page.")