|
import streamlit as st |
|
import os |
|
import google.generativeai as genai |
|
import json |
|
from PIL import Image |
|
import re |
|
import json |
|
import tempfile |
|
|
|
|
|
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() |
|
|
|
|
|
if "conversation_history" not in st.session_state: |
|
st.session_state.conversation_history = [] |
|
if "uploaded_file_part" not in st.session_state: |
|
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] |
|
|
|
response = chat.send_message(prompt) |
|
|
|
|
|
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): |
|
|
|
try: |
|
json_string = response.replace('```json', '').replace('```', '').strip() |
|
|
|
|
|
problems_list = json.loads(json_string) |
|
|
|
|
|
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 |
|
|
|
|
|
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") |
|
|
|
|
|
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: |
|
|
|
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: |
|
|
|
st.write("Processing your answer...") |
|
|
|
|
|
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) |
|
|
|
|
|
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"): |
|
|
|
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 🤖 ✨") |