# app.py import streamlit as st import pytesseract from PIL import Image import fitz # PyMuPDF import io import requests import re from fpdf import FPDF from datetime import datetime # --- Config --- API_URL = "https://openrouter.ai/api/v1/chat/completions" API_KEY = "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" MODEL = "mistralai/mistral-7b-instruct" # Set page config st.set_page_config( page_title="๐Ÿ”ฌ Science Lab Assistant", layout="centered", page_icon="๐Ÿ”ฌ", initial_sidebar_state="expanded" ) # Custom CSS for styling st.markdown(""" """, unsafe_allow_html=True) # Header st.markdown('

๐Ÿ”ฌ Science Lab Assistant

', unsafe_allow_html=True) # Introduction st.markdown("""

Your all-in-one science companion! Design experiments, generate reports, and get AI-powered feedback on your lab work.

""", unsafe_allow_html=True) # Experiment templates experiments = { "Vinegar + Baking Soda": { "hypothesis": "Mixing vinegar and baking soda will produce bubbles due to a chemical reaction.", "concept": "Acid-base reaction producing carbon dioxide." }, "Floating Egg": { "hypothesis": "An egg will float in salt water but sink in plain water.", "concept": "Density difference between saltwater and freshwater." }, "Lemon Battery": { "hypothesis": "A lemon can produce electricity to power a small LED.", "concept": "Chemical energy conversion to electrical energy." } } # AI Query Function def query_ai(prompt): headers = { "Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json" } payload = { "model": MODEL, "messages": [ {"role": "system", "content": "You are a helpful science teacher providing detailed explanations."}, {"role": "user", "content": prompt} ], "temperature": 0.7 } try: response = requests.post(API_URL, headers=headers, json=payload, timeout=120) response.raise_for_status() return response.json()['choices'][0]['message']['content'] except requests.exceptions.HTTPError as err: st.error(f"API Error: {err.response.status_code} - {err.response.text}") return None except Exception as e: st.error(f"Error connecting to AI service: {str(e)}") return None # Navigation app_mode = st.radio("Choose Mode:", ["๐Ÿงช Experiment Assistant", "๐Ÿ“ Lab Report Analyzer"], horizontal=True, label_visibility="collapsed") # Sidebar with st.sidebar: st.markdown("### ๐Ÿงช Experiment Templates") st.caption("Quickly start with these pre-defined experiments:") selected_exp = st.selectbox("Choose an experiment template:", list(experiments.keys()) + ["Custom Experiment"]) st.markdown("---") st.markdown("### ๐Ÿ“˜ Science Glossary Helper") term = st.text_input("Enter a science term (e.g., osmosis, catalyst)") if term: with st.spinner("Looking up term..."): ai_response = query_ai(f"Explain the term '{term}' in simple words for a student.") if ai_response: st.markdown(f"
{ai_response}
", unsafe_allow_html=True) # --- Experiment Assistant Section --- if app_mode == "๐Ÿงช Experiment Assistant": st.markdown('

๐Ÿ” Design Your Experiment

', unsafe_allow_html=True) with st.form("experiment_form"): # Pre-fill if template selected if selected_exp != "Custom Experiment" and selected_exp in experiments: default_hypo = experiments[selected_exp]["hypothesis"] concept = experiments[selected_exp]["concept"] exp_name = selected_exp else: default_hypo = "" concept = "" exp_name = st.text_input("Experiment Name", placeholder="e.g., Effect of Temperature on Enzyme Activity") hypo = st.text_area("Your Hypothesis", value=default_hypo, placeholder="What do you predict will happen?") materials = st.text_area("Materials Needed", placeholder="List all materials needed for this experiment") procedure = st.text_area("Procedure Steps", placeholder="Step-by-step instructions for conducting the experiment") submit = st.form_submit_button("๐Ÿ” Generate Experiment Guide", use_container_width=True) if submit: if not exp_name or not hypo: st.warning("Please provide at least an experiment name and hypothesis") st.stop() with st.spinner("Designing your experiment guide..."): prompt = f""" Create a comprehensive guide for a science experiment with the following details: Experiment Name: {exp_name} Hypothesis: {hypo} Materials: {materials if materials else 'Not specified'} Procedure: {procedure if procedure else 'Not specified'} Please provide: 1. A clear explanation of the scientific concept behind the experiment 2. Step-by-step instructions for conducting the experiment 3. Safety precautions 4. Expected results and why they're expected 5. How to interpret the results """ explanation = query_ai(prompt) if explanation: st.success("โœ… Experiment Guide Generated!") st.balloons() # Display explanation st.markdown("### ๐Ÿงช Experiment Guide") st.markdown(f"
{explanation}
", unsafe_allow_html=True) # Generate PDF report def generate_pdf_report(exp_name, hypo, explanation, materials, procedure): pdf = FPDF() pdf.add_page() pdf.set_font("Arial", size=12) # Title pdf.set_font("Arial", 'B', 16) pdf.cell(200, 10, txt="Science Experiment Guide", ln=True, align='C') pdf.ln(15) # Experiment details pdf.set_font("Arial", 'B', 14) pdf.cell(0, 10, txt=f"Experiment: {exp_name}", ln=True) pdf.ln(5) pdf.set_font("Arial", 'B', 12) pdf.cell(0, 10, txt="Hypothesis:", ln=True) pdf.set_font("Arial", '', 12) pdf.multi_cell(0, 8, txt=hypo) pdf.ln(5) if materials: pdf.set_font("Arial", 'B', 12) pdf.cell(0, 10, txt="Materials:", ln=True) pdf.set_font("Arial", '', 12) pdf.multi_cell(0, 8, txt=materials) pdf.ln(5) if procedure: pdf.set_font("Arial", 'B', 12) pdf.cell(0, 10, txt="Procedure:", ln=True) pdf.set_font("Arial", '', 12) pdf.multi_cell(0, 8, txt=procedure) pdf.ln(10) pdf.set_font("Arial", 'B', 12) pdf.cell(0, 10, txt="Experiment Guide:", ln=True) pdf.set_font("Arial", '', 12) pdf.multi_cell(0, 8, txt=explanation) filename = f"experiment_guide_{datetime.now().strftime('%Y%m%d%H%M%S')}.pdf" pdf.output(filename) return filename pdf_file = generate_pdf_report(exp_name, hypo, explanation, materials, procedure) with open(pdf_file, "rb") as file: st.download_button("๐Ÿ“„ Download Experiment Guide (PDF)", file, file_name=f"{exp_name}_guide.pdf", use_container_width=True) # Experiment examples st.markdown("---") st.markdown('

๐Ÿ”ฌ Popular Science Experiments

', unsafe_allow_html=True) col1, col2 = st.columns(2) with col1: with st.container(): st.markdown('
', unsafe_allow_html=True) st.markdown("#### ๐Ÿงซ Vinegar + Baking Soda") st.markdown("**Hypothesis:** Mixing vinegar and baking soda will produce bubbles due to a chemical reaction.") st.markdown("**Concept:** Acid-base reaction producing carbon dioxide.") if st.button("Try This Experiment", key="vinegar", use_container_width=True): st.session_state.selected_exp = "Vinegar + Baking Soda" st.markdown('
', unsafe_allow_html=True) with st.container(): st.markdown('
', unsafe_allow_html=True) st.markdown("#### ๐Ÿฅš Floating Egg") st.markdown("**Hypothesis:** An egg will float in salt water but sink in plain water.") st.markdown("**Concept:** Density difference between saltwater and freshwater.") if st.button("Try This Experiment", key="egg", use_container_width=True): st.session_state.selected_exp = "Floating Egg" st.markdown('
', unsafe_allow_html=True) with col2: with st.container(): st.markdown('
', unsafe_allow_html=True) st.markdown("#### ๐Ÿ‹ Lemon Battery") st.markdown("**Hypothesis:** A lemon can produce electricity to power a small LED.") st.markdown("**Concept:** Chemical energy conversion to electrical energy.") if st.button("Try This Experiment", key="lemon", use_container_width=True): st.session_state.selected_exp = "Lemon Battery" st.markdown('
', unsafe_allow_html=True) with st.container(): st.markdown('
', unsafe_allow_html=True) st.markdown("#### ๐ŸŒˆ Rainbow in a Glass") st.markdown("**Hypothesis:** Different sugar solutions can form colorful layers in a glass.") st.markdown("**Concept:** Density gradient formation.") if st.button("Try This Experiment", key="rainbow", use_container_width=True): st.session_state.selected_exp = "Custom Experiment" st.session_state.custom_exp = "Rainbow in a Glass" st.session_state.custom_hypo = "Different sugar solutions will form distinct layers based on their density." st.markdown('
', unsafe_allow_html=True) # --- Lab Report Analyzer Section --- else: # --- File Upload --- st.markdown('

๐Ÿ“ค Upload Your Lab Report

', unsafe_allow_html=True) uploaded_file = st.file_uploader("Upload image (JPG, PNG) or PDF", type=["jpg", "jpeg", "png", "pdf"], label_visibility="collapsed") lab_text = "" if uploaded_file: file_bytes = uploaded_file.read() file_ext = uploaded_file.name.split(".")[-1].lower() if file_ext == "pdf": doc = fitz.open(stream=file_bytes, filetype="pdf") for page in doc: lab_text += page.get_text() else: image = Image.open(io.BytesIO(file_bytes)) lab_text = pytesseract.image_to_string(image) # Allow text editing st.markdown('

โœ๏ธ Extracted Text

', unsafe_allow_html=True) st.caption("Review and edit the extracted text if needed before analysis") lab_text = st.text_area("", lab_text, height=300, label_visibility="collapsed") # --- AI Evaluation --- if lab_text.strip(): # -- AI Evaluation Prompt -- full_prompt = f"""You are a science teacher evaluating a student's lab report. Please provide a comprehensive analysis: Lab Report: {lab_text} Evaluation Guidelines: 1. **Section Check**: Identify which of these sections are present and which are missing: - Title - Objective - Hypothesis - Materials - Procedure - Observations - Results - Conclusion - References 2. **Completeness Score**: - Assign a numerical score from 1-10 based on completeness - Justify the score based on missing sections and content quality 3. **Improvement Tips**: - For each missing section, explain why it's important - Provide specific suggestions for improvement (e.g., "Try writing a more detailed observation section by including quantitative data") - Highlight any sections that need more detail or clarity 4. **Structure Response**: - Start with: "### Missing Sections:" - Then: "### Completeness Score: X/10" - Then: "### Improvement Tips:" - Finally: "### Detailed Feedback:" Be concise but thorough in your analysis. """ if st.button("๐Ÿงช Analyze Report", use_container_width=True): with st.spinner("๐Ÿ” Analyzing report with AI. This may take 20-30 seconds..."): result = query_ai(full_prompt) if result: st.success("โœ… Analysis Complete!") st.balloons() # Extract score using regex score_match = re.search(r"Completeness Score:\s*(\d+)/10", result, re.IGNORECASE) score = int(score_match.group(1)) if score_match else None # Display score in a card if score is not None: with st.container(): st.markdown('
', unsafe_allow_html=True) # Create columns for score visualization col1, col2 = st.columns([1, 3]) with col1: st.markdown(f"

{score}/10

", unsafe_allow_html=True) st.markdown("

Completeness Score

", unsafe_allow_html=True) with col2: # Create a color gradient based on score if score >= 8: color = "#28b463" # Green elif score >= 5: color = "#f39c12" # Orange else: color = "#e74c3c" # Red # Display progress bar with styling st.progress(score/10, text=f"{score*10}% complete") st.markdown( f"", unsafe_allow_html=True ) st.markdown('
', unsafe_allow_html=True) # Display AI analysis with formatting st.markdown("## ๐Ÿ“ Analysis Results") # Split sections for better display sections = { "Missing Sections": None, "Improvement Tips": None, "Detailed Feedback": None } current_section = None for line in result.split('\n'): if "### Missing Sections:" in line: current_section = "Missing Sections" sections[current_section] = [] elif "### Improvement Tips:" in line: current_section = "Improvement Tips" sections[current_section] = [] elif "### Detailed Feedback:" in line: current_section = "Detailed Feedback" sections[current_section] = [] elif current_section and line.strip(): sections[current_section].append(line) # Display each section if sections["Missing Sections"]: st.markdown("### ๐Ÿ” Missing Sections") missing_text = '\n'.join(sections["Missing Sections"]) st.markdown(f'
{missing_text}
', unsafe_allow_html=True) if sections["Improvement Tips"]: st.markdown("### ๐Ÿ’ก Improvement Tips") tips_text = '\n'.join(sections["Improvement Tips"]) st.markdown(f'
{tips_text}
', unsafe_allow_html=True) if sections["Detailed Feedback"]: st.markdown("### ๐Ÿ“‹ Detailed Feedback") st.write('\n'.join(sections["Detailed Feedback"])) # Show full AI response in expander with st.expander("View Full AI Analysis"): st.markdown(result) # --- Question Answering Section --- st.markdown("---") st.markdown('

โ“ Ask About Your Report

', unsafe_allow_html=True) col1, col2 = st.columns([3, 1]) with col1: user_question = st.text_input("Ask a question about your lab report", placeholder="e.g., How can I improve my hypothesis?") with col2: st.markdown("
", unsafe_allow_html=True) ask_button = st.button("๐Ÿ” Ask Question", use_container_width=True) if (ask_button or user_question) and user_question.strip(): with st.spinner("Thinking..."): followup_prompt = f"""Lab Report: {lab_text} Question: {user_question} Answer the question based on the lab report. If the question can't be answered from the report, suggest what information the student should add to answer it. """ followup_response = query_ai(followup_prompt) if followup_response: st.markdown("### ๐Ÿ’ฌ AI Response") st.markdown(f'
{followup_response}
', unsafe_allow_html=True) else: # Show sample report if no file uploaded st.markdown("---") st.markdown('

๐Ÿ“ Sample Lab Report

', unsafe_allow_html=True) st.markdown(""" **Title:** Effect of Temperature on Enzyme Activity **Objective:** To investigate how temperature affects catalase enzyme activity **Hypothesis:** Enzyme activity will increase with temperature up to 37ยฐC, then decrease **Materials:** Test tubes, hydrogen peroxide, liver extract, thermometer **Procedure:** 1. Prepare test tubes at 5 different temperatures 2. Add equal amounts of hydrogen peroxide and liver extract 3. Measure oxygen production **Observations:** More bubbles at 37ยฐC compared to lower or higher temperatures **Conclusion:** Enzyme activity peaks at body temperature """) st.info("๐Ÿ‘† Upload your own lab report to get a personalized analysis!") # Footer st.markdown("---") st.markdown('', unsafe_allow_html=True)