sunbal7 commited on
Commit
f4ab78b
·
verified ·
1 Parent(s): 30f08b7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +31 -377
app.py CHANGED
@@ -1,7 +1,5 @@
1
  # app.py
2
  import streamlit as st
3
- import pytesseract
4
- from PIL import Image
5
  import fitz # PyMuPDF
6
  import io
7
  import requests
@@ -9,33 +7,16 @@ import re
9
  import os
10
  from fpdf import FPDF
11
  from datetime import datetime
12
-
13
- # --- Load Environment Variables ---
14
- from dotenv import load_dotenv
15
- load_dotenv() # Load environment variables from .env file
16
 
17
  # --- Config ---
18
  API_URL = "https://openrouter.ai/api/v1/chat/completions"
19
-
20
- # Retrieve API key from Streamlit secrets or environment variables
21
- try:
22
- OPENROUTER_API_KEY = st.secrets["OPENROUTER_API_KEY"]
23
- except (KeyError, FileNotFoundError):
24
- # Fallback for local development
25
- OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY", "")
26
-
27
  MODEL = "mistralai/mistral-7b-instruct"
28
 
29
- # Set Tesseract path for different environments
30
- try:
31
- # For Windows
32
- if os.name == 'nt':
33
- pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
34
- # For Linux (Streamlit Sharing)
35
- elif 'tesseract' not in os.environ.get('PATH', ''):
36
- pytesseract.pytesseract.tesseract_cmd = '/usr/bin/tesseract'
37
- except Exception as e:
38
- st.warning(f"Tesseract configuration issue: {str(e)}")
39
 
40
  # Set page config
41
  st.set_page_config(
@@ -48,92 +29,7 @@ st.set_page_config(
48
  # Custom CSS for styling
49
  st.markdown("""
50
  <style>
51
- .header {
52
- font-size: 36px;
53
- color: #2e86c1;
54
- text-align: center;
55
- padding: 20px;
56
- }
57
- .subheader {
58
- font-size: 24px;
59
- color: #28b463;
60
- border-bottom: 2px solid #f4d03f;
61
- padding-bottom: 10px;
62
- margin-top: 30px;
63
- }
64
- .stButton>button {
65
- background-color: #28b463 !important;
66
- color: white !important;
67
- border-radius: 8px;
68
- padding: 8px 20px;
69
- transition: all 0.3s;
70
- }
71
- .stButton>button:hover {
72
- background-color: #239b56 !important;
73
- transform: scale(1.05);
74
- }
75
- .score-card {
76
- background: linear-gradient(135deg, #e8f8f5, #d1f2eb);
77
- border-radius: 15px;
78
- padding: 20px;
79
- box-shadow: 0 4px 8px rgba(0,0,0,0.1);
80
- margin-bottom: 20px;
81
- }
82
- .highlight {
83
- background-color: #f9e79f;
84
- padding: 5px;
85
- border-radius: 5px;
86
- font-weight: bold;
87
- }
88
- .tip-box {
89
- background-color: #eafaf1;
90
- border-left: 5px solid #28b463;
91
- padding: 15px;
92
- margin: 15px 0;
93
- border-radius: 0 8px 8px 0;
94
- }
95
- .error-box {
96
- background-color: #fdecea;
97
- border-left: 5px solid #e74c3c;
98
- padding: 15px;
99
- margin: 15px 0;
100
- border-radius: 0 8px 8px 0;
101
- }
102
- .experiment-card {
103
- background: linear-gradient(135deg, #f0f7ff, #e1effe);
104
- border-radius: 15px;
105
- padding: 20px;
106
- box-shadow: 0 4px 8px rgba(0,0,0,0.1);
107
- margin-bottom: 20px;
108
- transition: all 0.3s;
109
- }
110
- .experiment-card:hover {
111
- transform: translateY(-5px);
112
- box-shadow: 0 6px 12px rgba(0,0,0,0.15);
113
- }
114
- .concept-box {
115
- background-color: #ebf5fb;
116
- border-left: 5px solid #3498db;
117
- padding: 15px;
118
- margin: 15px 0;
119
- border-radius: 0 8px 8px 0;
120
- }
121
- [data-testid="stSidebar"] {
122
- background: linear-gradient(180deg, #e8f8f5, #d1f2eb) !important;
123
- }
124
- .footer {
125
- text-align: center;
126
- padding: 20px;
127
- color: #7f8c8d;
128
- font-size: 14px;
129
- }
130
- .ocr-warning {
131
- background-color: #fef9e7;
132
- border-left: 5px solid #f1c40f;
133
- padding: 15px;
134
- margin: 15px 0;
135
- border-radius: 0 8px 8px 0;
136
- }
137
  </style>
138
  """, unsafe_allow_html=True)
139
 
@@ -148,6 +44,22 @@ st.markdown("""
148
  </div>
149
  """, unsafe_allow_html=True)
150
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  # Experiment templates
152
  experiments = {
153
  "Vinegar + Baking Soda": {
@@ -167,7 +79,7 @@ experiments = {
167
  # AI Query Function
168
  def query_ai(prompt):
169
  headers = {
170
- "Authorization": f"Bearer {API_KEY}",
171
  "Content-Type": "application/json"
172
  }
173
  payload = {
@@ -209,169 +121,18 @@ with st.sidebar:
209
  ai_response = query_ai(f"Explain the term '{term}' in simple words for a student.")
210
  if ai_response:
211
  st.markdown(f"<div class='concept-box'>{ai_response}</div>", unsafe_allow_html=True)
212
- else:
213
- st.warning("Couldn't retrieve definition. Please try again.")
214
 
215
  # --- Experiment Assistant Section ---
216
  if app_mode == "🧪 Experiment Assistant":
217
- st.markdown('<p class="subheader">🔍 Design Your Experiment</p>', unsafe_allow_html=True)
218
-
219
- with st.form("experiment_form"):
220
- # Pre-fill if template selected
221
- if selected_exp != "Custom Experiment" and selected_exp in experiments:
222
- default_hypo = experiments[selected_exp]["hypothesis"]
223
- concept = experiments[selected_exp]["concept"]
224
- exp_name = selected_exp
225
- else:
226
- default_hypo = ""
227
- concept = ""
228
- exp_name = st.text_input("Experiment Name", placeholder="e.g., Effect of Temperature on Enzyme Activity")
229
-
230
- hypo = st.text_area("Your Hypothesis", value=default_hypo,
231
- placeholder="What do you predict will happen?")
232
-
233
- materials = st.text_area("Materials Needed",
234
- placeholder="List all materials needed for this experiment")
235
-
236
- procedure = st.text_area("Procedure Steps",
237
- placeholder="Step-by-step instructions for conducting the experiment")
238
-
239
- submit = st.form_submit_button("🔍 Generate Experiment Guide", use_container_width=True)
240
-
241
- if submit:
242
- if not exp_name or not hypo:
243
- st.warning("Please provide at least an experiment name and hypothesis")
244
- st.stop()
245
-
246
- with st.spinner("Designing your experiment guide..."):
247
- prompt = f"""
248
- Create a comprehensive guide for a science experiment with the following details:
249
-
250
- Experiment Name: {exp_name}
251
- Hypothesis: {hypo}
252
- Materials: {materials if materials else 'Not specified'}
253
- Procedure: {procedure if procedure else 'Not specified'}
254
-
255
- Please provide:
256
- 1. A clear explanation of the scientific concept behind the experiment
257
- 2. Step-by-step instructions for conducting the experiment
258
- 3. Safety precautions
259
- 4. Expected results and why they're expected
260
- 5. How to interpret the results
261
- """
262
-
263
- explanation = query_ai(prompt)
264
-
265
- if explanation:
266
- st.success("✅ Experiment Guide Generated!")
267
- st.balloons()
268
-
269
- # Display explanation
270
- st.markdown("### 🧪 Experiment Guide")
271
- st.markdown(f"<div class='tip-box'>{explanation}</div>", unsafe_allow_html=True)
272
-
273
- # Generate PDF report
274
- def generate_pdf_report(exp_name, hypo, explanation, materials, procedure):
275
- pdf = FPDF()
276
- pdf.add_page()
277
- pdf.set_font("Arial", size=12)
278
-
279
- # Title
280
- pdf.set_font("Arial", 'B', 16)
281
- pdf.cell(200, 10, txt="Science Experiment Guide", ln=True, align='C')
282
- pdf.ln(15)
283
-
284
- # Experiment details
285
- pdf.set_font("Arial", 'B', 14)
286
- pdf.cell(0, 10, txt=f"Experiment: {exp_name}", ln=True)
287
- pdf.ln(5)
288
-
289
- pdf.set_font("Arial", 'B', 12)
290
- pdf.cell(0, 10, txt="Hypothesis:", ln=True)
291
- pdf.set_font("Arial", '', 12)
292
- pdf.multi_cell(0, 8, txt=hypo)
293
- pdf.ln(5)
294
-
295
- if materials:
296
- pdf.set_font("Arial", 'B', 12)
297
- pdf.cell(0, 10, txt="Materials:", ln=True)
298
- pdf.set_font("Arial", '', 12)
299
- pdf.multi_cell(0, 8, txt=materials)
300
- pdf.ln(5)
301
-
302
- if procedure:
303
- pdf.set_font("Arial", 'B', 12)
304
- pdf.cell(0, 10, txt="Procedure:", ln=True)
305
- pdf.set_font("Arial", '', 12)
306
- pdf.multi_cell(0, 8, txt=procedure)
307
- pdf.ln(10)
308
-
309
- pdf.set_font("Arial", 'B', 12)
310
- pdf.cell(0, 10, txt="Experiment Guide:", ln=True)
311
- pdf.set_font("Arial", '', 12)
312
- pdf.multi_cell(0, 8, txt=explanation)
313
-
314
- filename = f"experiment_guide_{datetime.now().strftime('%Y%m%d%H%M%S')}.pdf"
315
- pdf.output(filename)
316
- return filename
317
-
318
- pdf_file = generate_pdf_report(exp_name, hypo, explanation, materials, procedure)
319
- with open(pdf_file, "rb") as file:
320
- st.download_button("📄 Download Experiment Guide (PDF)", file,
321
- file_name=f"{exp_name}_guide.pdf",
322
- use_container_width=True)
323
-
324
- # Experiment examples
325
- st.markdown("---")
326
- st.markdown('<p class="subheader">�� Popular Science Experiments</p>', unsafe_allow_html=True)
327
-
328
- col1, col2 = st.columns(2)
329
- with col1:
330
- with st.container():
331
- st.markdown('<div class="experiment-card">', unsafe_allow_html=True)
332
- st.markdown("#### 🧫 Vinegar + Baking Soda")
333
- st.markdown("**Hypothesis:** Mixing vinegar and baking soda will produce bubbles due to a chemical reaction.")
334
- st.markdown("**Concept:** Acid-base reaction producing carbon dioxide.")
335
- if st.button("Try This Experiment", key="vinegar", use_container_width=True):
336
- st.session_state.selected_exp = "Vinegar + Baking Soda"
337
- st.markdown('</div>', unsafe_allow_html=True)
338
-
339
- with st.container():
340
- st.markdown('<div class="experiment-card">', unsafe_allow_html=True)
341
- st.markdown("#### 🥚 Floating Egg")
342
- st.markdown("**Hypothesis:** An egg will float in salt water but sink in plain water.")
343
- st.markdown("**Concept:** Density difference between saltwater and freshwater.")
344
- if st.button("Try This Experiment", key="egg", use_container_width=True):
345
- st.session_state.selected_exp = "Floating Egg"
346
- st.markdown('</div>', unsafe_allow_html=True)
347
-
348
- with col2:
349
- with st.container():
350
- st.markdown('<div class="experiment-card">', unsafe_allow_html=True)
351
- st.markdown("#### 🍋 Lemon Battery")
352
- st.markdown("**Hypothesis:** A lemon can produce electricity to power a small LED.")
353
- st.markdown("**Concept:** Chemical energy conversion to electrical energy.")
354
- if st.button("Try This Experiment", key="lemon", use_container_width=True):
355
- st.session_state.selected_exp = "Lemon Battery"
356
- st.markdown('</div>', unsafe_allow_html=True)
357
-
358
- with st.container():
359
- st.markdown('<div class="experiment-card">', unsafe_allow_html=True)
360
- st.markdown("#### 🌈 Rainbow in a Glass")
361
- st.markdown("**Hypothesis:** Different sugar solutions can form colorful layers in a glass.")
362
- st.markdown("**Concept:** Density gradient formation.")
363
- if st.button("Try This Experiment", key="rainbow", use_container_width=True):
364
- st.session_state.selected_exp = "Custom Experiment"
365
- st.session_state.custom_exp = "Rainbow in a Glass"
366
- st.session_state.custom_hypo = "Different sugar solutions will form distinct layers based on their density."
367
- st.markdown('</div>', unsafe_allow_html=True)
368
 
369
  # --- Lab Report Analyzer Section ---
370
  else:
371
  # --- File Upload ---
372
  st.markdown('<p class="subheader">📤 Upload Your Lab Report</p>', unsafe_allow_html=True)
373
- uploaded_file = st.file_uploader("Upload image (JPG, PNG) or PDF",
374
- type=["jpg", "jpeg", "png", "pdf"],
375
  label_visibility="collapsed")
376
 
377
  lab_text = ""
@@ -388,34 +149,8 @@ else:
388
  except Exception as e:
389
  st.error(f"Error reading PDF: {str(e)}")
390
  else:
391
- try:
392
- image = Image.open(io.BytesIO(file_bytes))
393
- st.image(image, caption="Uploaded Image", width=300)
394
-
395
- # OCR processing
396
- with st.spinner("Extracting text from image..."):
397
- try:
398
- lab_text = pytesseract.image_to_string(image)
399
- st.success("✅ Text extracted from image!")
400
- except pytesseract.pytesseract.TesseractNotFoundError:
401
- st.error("""
402
- **Tesseract OCR not found!**
403
-
404
- To enable image text extraction:
405
- 1. Install Tesseract OCR on your system
406
- 2. Add it to your system PATH
407
- 3. Restart the application
408
-
409
- For Windows: Download from [UB-Mannheim/tesseract](https://github.com/UB-Mannheim/tesseract/wiki)
410
- For Linux: `sudo apt install tesseract-ocr`
411
- For Mac: `brew install tesseract`
412
- """)
413
- st.stop()
414
- except Exception as e:
415
- st.error(f"OCR Error: {str(e)}")
416
- st.stop()
417
- except Exception as e:
418
- st.error(f"Error processing image: {str(e)}")
419
 
420
  # Allow text editing
421
  if lab_text:
@@ -469,89 +204,8 @@ else:
469
  st.success("✅ Analysis Complete!")
470
  st.balloons()
471
 
472
- # Extract score using regex
473
- score_match = re.search(r"Completeness Score:\s*(\d+)/10", result, re.IGNORECASE)
474
- score = int(score_match.group(1)) if score_match else None
475
-
476
- # Display score in a card
477
- if score is not None:
478
- with st.container():
479
- st.markdown('<div class="score-card">', unsafe_allow_html=True)
480
-
481
- # Create columns for score visualization
482
- col1, col2 = st.columns([1, 3])
483
-
484
- with col1:
485
- st.markdown(f"<h2 style='text-align: center; color: #28b463;'>{score}/10</h2>",
486
- unsafe_allow_html=True)
487
- st.markdown("<h4 style='text-align: center;'>Completeness Score</h4>",
488
- unsafe_allow_html=True)
489
-
490
- with col2:
491
- # Create a color gradient based on score
492
- if score >= 8:
493
- color = "#28b463" # Green
494
- elif score >= 5:
495
- color = "#f39c12" # Orange
496
- else:
497
- color = "#e74c3c" # Red
498
-
499
- # Display progress bar with styling
500
- st.progress(score/10, text=f"{score*10}% complete")
501
- st.markdown(
502
- f"<style>"
503
- f".stProgress > div > div > div {{"
504
- f" background-color: {color} !important;"
505
- f" border-radius: 10px;"
506
- f"}}"
507
- f"</style>",
508
- unsafe_allow_html=True
509
- )
510
-
511
- st.markdown('</div>', unsafe_allow_html=True)
512
-
513
- # Display AI analysis with formatting
514
- st.markdown("## 📝 Analysis Results")
515
-
516
- # Split sections for better display
517
- sections = {
518
- "Missing Sections": None,
519
- "Improvement Tips": None,
520
- "Detailed Feedback": None
521
- }
522
-
523
- current_section = None
524
- for line in result.split('\n'):
525
- if "### Missing Sections:" in line:
526
- current_section = "Missing Sections"
527
- sections[current_section] = []
528
- elif "### Improvement Tips:" in line:
529
- current_section = "Improvement Tips"
530
- sections[current_section] = []
531
- elif "### Detailed Feedback:" in line:
532
- current_section = "Detailed Feedback"
533
- sections[current_section] = []
534
- elif current_section and line.strip():
535
- sections[current_section].append(line)
536
-
537
- # Display each section
538
- if sections["Missing Sections"]:
539
- st.markdown("### 🔍 Missing Sections")
540
- missing_text = '\n'.join(sections["Missing Sections"])
541
- st.markdown(f'<div class="highlight">{missing_text}</div>', unsafe_allow_html=True)
542
-
543
- if sections["Improvement Tips"]:
544
- st.markdown("### 💡 Improvement Tips")
545
- tips_text = '\n'.join(sections["Improvement Tips"])
546
- st.markdown(f'<div class="tip-box">{tips_text}</div>', unsafe_allow_html=True)
547
-
548
- if sections["Detailed Feedback"]:
549
- st.markdown("### 📋 Detailed Feedback")
550
- st.write('\n'.join(sections["Detailed Feedback"]))
551
-
552
- # Show full AI response in expander
553
- with st.expander("View Full AI Analysis"):
554
- st.markdown(result)
555
 
556
  # --- Question Answering Section ---
557
  st.markdown("---")
 
1
  # app.py
2
  import streamlit as st
 
 
3
  import fitz # PyMuPDF
4
  import io
5
  import requests
 
7
  import os
8
  from fpdf import FPDF
9
  from datetime import datetime
10
+ from PIL import Image
11
+ import base64
12
+ import json
 
13
 
14
  # --- Config ---
15
  API_URL = "https://openrouter.ai/api/v1/chat/completions"
 
 
 
 
 
 
 
 
16
  MODEL = "mistralai/mistral-7b-instruct"
17
 
18
+ # Retrieve API key from environment variable (set in Hugging Face secrets)
19
+ OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY")
 
 
 
 
 
 
 
 
20
 
21
  # Set page config
22
  st.set_page_config(
 
29
  # Custom CSS for styling
30
  st.markdown("""
31
  <style>
32
+ /* (Keep all your existing CSS styles here) */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  </style>
34
  """, unsafe_allow_html=True)
35
 
 
44
  </div>
45
  """, unsafe_allow_html=True)
46
 
47
+ # API Key Check
48
+ if not OPENROUTER_API_KEY:
49
+ st.error("""
50
+ **API Key Not Configured!**
51
+
52
+ Please add your OpenRouter API key to Hugging Face Spaces secrets:
53
+ 1. Go to your Space settings
54
+ 2. Select "Variables and secrets"
55
+ 3. Add a secret named: `OPENROUTER_API_KEY`
56
+ 4. Set its value to your actual API key
57
+ 5. Redeploy the space
58
+
59
+ Without this key, the AI features won't work.
60
+ """)
61
+ st.stop()
62
+
63
  # Experiment templates
64
  experiments = {
65
  "Vinegar + Baking Soda": {
 
79
  # AI Query Function
80
  def query_ai(prompt):
81
  headers = {
82
+ "Authorization": f"Bearer {OPENROUTER_API_KEY}",
83
  "Content-Type": "application/json"
84
  }
85
  payload = {
 
121
  ai_response = query_ai(f"Explain the term '{term}' in simple words for a student.")
122
  if ai_response:
123
  st.markdown(f"<div class='concept-box'>{ai_response}</div>", unsafe_allow_html=True)
 
 
124
 
125
  # --- Experiment Assistant Section ---
126
  if app_mode == "🧪 Experiment Assistant":
127
+ # (Keep all your experiment assistant code here unchanged)
128
+ pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
 
130
  # --- Lab Report Analyzer Section ---
131
  else:
132
  # --- File Upload ---
133
  st.markdown('<p class="subheader">📤 Upload Your Lab Report</p>', unsafe_allow_html=True)
134
+ uploaded_file = st.file_uploader("Upload PDF only (image support coming soon)",
135
+ type=["pdf"],
136
  label_visibility="collapsed")
137
 
138
  lab_text = ""
 
149
  except Exception as e:
150
  st.error(f"Error reading PDF: {str(e)}")
151
  else:
152
+ st.warning("Image upload is temporarily disabled. Please upload PDF files only.")
153
+ st.info("Tip: Convert images to PDF using free online tools")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
 
155
  # Allow text editing
156
  if lab_text:
 
204
  st.success("✅ Analysis Complete!")
205
  st.balloons()
206
 
207
+ # (Keep all your analysis result display code here unchanged)
208
+ pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
 
210
  # --- Question Answering Section ---
211
  st.markdown("---")