louiecerv's picture
Merge branch 'main' of https://huggingface.co/spaces/louiecerv/problem_solving_ai_tutor
4a228f8
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 🤖 ✨")