import streamlit as st import os import google.generativeai as genai import json from PIL import Image import re import json import tempfile # Define constants TEXT_PROMPT = """Use the provided document. Read the list of quadratic equations. Return your response as a JSON list. Do not include any extra text, explanations, or backslashes. Example JSON output: [ "x^2 - 5x + 6 = 0", "2x^2 + 3x - 1 = 0", "x^2 - 9 = 0", "3x^2 - 2x + 4 = 0", "x^2 + 8x + 15 = 0" ] """ MODEL_ID = "gemini-2.0-flash-exp" try: api_key = os.getenv("GEMINI_API_KEY") model_id = MODEL_ID genai.configure(api_key=api_key) except Exception as e: st.error(f"Error: {e}") st.stop() model = genai.GenerativeModel(MODEL_ID) chat = model.start_chat() def get_local_file_path(img_file="problem1.png"): """ Returns the path to the local PDF file. """ try: file_path = os.path.join("problems", img_file) if not os.path.exists(file_path): raise FileNotFoundError(f"{file_path} does not exist.") return file_path except Exception as e: st.error(f"Failed to find the local file: {e}") st.stop() # Stop if the file is not found # Initialize conversation history in Streamlit session state if "conversation_history" not in st.session_state: st.session_state.conversation_history = [] if "uploaded_file_part" not in st.session_state: # Store the file *part* st.session_state.uploaded_file_part = None if "uploaded_pdf_path" not in st.session_state: st.session_state.uploaded_pdf_path = get_local_file_path() def multimodal_prompt(pdf_path, text_prompt, file_type="PDF"): """ Sends a multimodal prompt to Gemini, handling file uploads efficiently. Args: pdf_path: The path to the file (PDF or image). text_prompt: The text prompt for the model. file_type: "PDF" or "image" to specify the file type. Returns: The model's response as a string, or an error message. """ try: if file_type == "PDF": mime_type = "application/pdf" elif file_type == "image": import mimetypes mime_type, _ = mimetypes.guess_type(pdf_path) if mime_type is None: return "Could not determine MIME type for image. Please check the file path or type." else: return "Invalid file_type. Must be 'PDF' or 'image'." pdf_part = genai.upload_file(pdf_path, mime_type=mime_type) prompt = [text_prompt, pdf_part] # First turn includes the actual file response = chat.send_message(prompt) # Update conversation history st.session_state.conversation_history.append({"role": "user", "content": text_prompt, "has_file": True}) st.session_state.conversation_history.append({"role": "assistant", "content": response.text}) return response.text except Exception as e: return f"An error occurred: {e}" def get_equation(response): # Remove the ```json and ``` and extra spaces. try: json_string = response.replace('```json', '').replace('```', '').strip() # Parse the JSON string into a Python list. problems_list = json.loads(json_string) # return the first item found return problems_list[0] except json.JSONDecodeError: st.error("Invalid JSON format in the response.") return None except Exception as e: st.error(f"An unexpected error occurred: {e}") return None if "problem_step" not in st.session_state: st.session_state.problem_step = 0 # --- Main Page --- st.title("๐Ÿ“šโ“Problem Solving Tutor") about = """ **How to use this App** Replace this placeholder with the actual text. """ with st.spinner("Loading the problem..."): if st.session_state.get("uploaded_pdf_path") is None: st.session_state.uploaded_pdf_path = get_local_file_path("problem1.png") filepath = st.session_state.uploaded_pdf_path response = multimodal_prompt(filepath, TEXT_PROMPT, file_type="image") # --- Display the image --- st.image(filepath, caption="Problem Image", use_container_width=True) equation = get_equation(response) st.write(f"**Equation:** {equation}") problem_step = st.session_state.problem_step if problem_step == 0: #Show instructions to submit the answer st.write("Please write down your answer in a piece of paper. Take a picture of the paper and submit it in the next step.") st.write("Click the button below to proceed.") img_file_buffer = st.camera_input("Take a picture of your answer.") if img_file_buffer is not None: # process the answer st.write("Processing your answer...") # Save the image to a temporary file with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as temp_file: temp_file.write(img_file_buffer.read()) image_path = temp_file.name st.write("Image saved to:", image_path) # create the text prompt text_prompt = """Use the provided image. The image shows, my answer to the problem. If the image is not clear ask for another image and do not perform any of the following instructions. If the image is clear, evaluate the answer as either correct or incorrect. If the answer is incorrect, do not provide the correct answer. Provide feedback how can the student improve their answer. If the answer is correct, provide feedback that the answer is correct and discuss the solution. If the student used the factoring method, ask the student to try again and next time use the quadratic formula method. The goal is to solve the problem using the quadratic formula method do not ask the student to use the factoring method. """ if st.button("Ask Tutor for Feedback"): if text_prompt: with st.spinner("AI is thinking..."): response = multimodal_prompt(image_path, text_prompt, file_type="image") st.markdown(response) if st.button("Next"): # Evaluate the response if "Correct" in response: st.write("Correct! ๐ŸŽ‰") st.session_state.problem_step = 1 else: st.write("Incorrect. ๐Ÿ˜ž") st.session_state.problem_step = 0 else: st.write("Please take a picture of your answer.") st.markdown("Visit our Hugging Face Space!") st.markdown("ยฉ 2025 WVSU AI Dev Team ๐Ÿค– โœจ")