sunbal7 commited on
Commit
65bd2d8
·
verified ·
1 Parent(s): 10fdc1d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +276 -569
app.py CHANGED
@@ -1,622 +1,329 @@
1
  # app.py
2
- import streamlit as st
3
- import pytesseract
4
- from PIL import Image
5
- import io
6
- import requests
7
- import re
8
- from fpdf import FPDF
9
- from datetime import datetime
10
  import os
11
- import pdfplumber # Alternative PDF library
12
-
13
-
14
- API_KEY = os.environ.get('OPENROUTER_API_KEY')
15
- if not API_KEY:
16
- st.error("""
17
- **API Key Not Configured!**
18
-
19
- Please add your API key to Hugging Face Spaces secrets:
20
- 1. Go to your Space settings
21
- 2. Select "Variables and secrets"
22
- 3. Add a secret named: `OPENROUTER_API_KEY`
23
- 4. Set its value to your actual API key
24
- 5. Redeploy the space
25
- """)
26
- st.stop()
27
 
28
- # --- API Configuration ---
29
- API_URL = "https://api.groq.com/openai/v1/chat/completions"
30
- MODEL = "llama3-70b-8192"
31
 
32
- # Set Tesseract path for different environments
33
- try:
34
- # For Windows
35
- if os.name == 'nt':
36
- pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
37
- # For Linux
38
- elif 'tesseract' not in os.environ.get('PATH', ''):
39
- pytesseract.pytesseract.tesseract_cmd = '/usr/bin/tesseract'
40
- except Exception as e:
41
- st.warning(f"Tesseract configuration issue: {str(e)}")
42
 
43
- # Set page config
44
  st.set_page_config(
45
- page_title="🔬 Science Lab Assistant",
46
- layout="centered",
47
- page_icon="🔬",
48
  initial_sidebar_state="expanded"
49
  )
50
 
51
  # Custom CSS for styling
52
  st.markdown("""
53
- <style>
54
- .header {
55
- font-size: 36px;
56
- color: #2e86c1;
57
- text-align: center;
58
- padding: 20px;
59
- }
60
- .subheader {
61
- font-size: 24px;
62
- color: #28b463;
63
- border-bottom: 2px solid #f4d03f;
64
- padding-bottom: 10px;
65
- margin-top: 30px;
66
- }
67
- .stButton>button {
68
- background-color: #28b463 !important;
69
- color: white !important;
70
- border-radius: 8px;
71
- padding: 8px 20px;
72
- transition: all 0.3s;
73
- }
74
- .stButton>button:hover {
75
- background-color: #239b56 !important;
76
- transform: scale(1.05);
77
- }
78
- .score-card {
79
- background: linear-gradient(135deg, #e8f8f5, #d1f2eb);
80
- border-radius: 15px;
81
- padding: 20px;
82
- box-shadow: 0 4px 8px rgba(0,0,0,0.1);
83
- margin-bottom: 20px;
84
- }
85
- .highlight {
86
- background-color: #f9e79f;
87
- padding: 5px;
88
- border-radius: 5px;
89
- font-weight: bold;
90
  }
91
- .tip-box {
92
- background-color: #eafaf1;
93
- border-left: 5px solid #28b463;
94
- padding: 15px;
95
- margin: 15px 0;
96
- border-radius: 0 8px 8px 0;
97
  }
98
- .error-box {
99
- background-color: #fdecea;
100
- border-left: 5px solid #e74c3c;
101
- padding: 15px;
102
- margin: 15px 0;
103
- border-radius: 0 8px 8px 0;
 
 
104
  }
105
- .experiment-card {
106
- background: linear-gradient(135deg, #f0f7ff, #e1effe);
 
107
  border-radius: 15px;
108
- padding: 20px;
109
- box-shadow: 0 4px 8px rgba(0,0,0,0.1);
110
- margin-bottom: 20px;
111
- transition: all 0.3s;
112
  }
113
- .experiment-card:hover {
 
114
  transform: translateY(-5px);
115
- box-shadow: 0 6px 12px rgba(0,0,0,0.15);
116
  }
117
- .concept-box {
118
- background-color: #ebf5fb;
119
- border-left: 5px solid #3498db;
120
- padding: 15px;
121
- margin: 15px 0;
122
- border-radius: 0 8px 8px 0;
 
 
 
 
 
 
123
  }
124
- [data-testid="stSidebar"] {
125
- background: linear-gradient(180deg, #e8f8f5, #d1f2eb) !important;
 
 
126
  }
 
 
 
 
 
 
 
 
 
 
127
  .footer {
128
  text-align: center;
129
- padding: 20px;
130
- color: #7f8c8d;
131
- font-size: 14px;
 
132
  }
133
- .ocr-warning {
134
- background-color: #fef9e7;
135
- border-left: 5px solid #f1c40f;
136
- padding: 15px;
137
- margin: 15px 0;
138
- border-radius: 0 8px 8px 0;
 
 
 
139
  }
140
- </style>
141
- """, unsafe_allow_html=True)
142
 
143
- # Header
144
- st.markdown('<p class="header">🔬 Science Lab Assistant</p>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
145
 
146
- # Introduction
147
- st.markdown("""
148
- <div style="text-align: center; margin-bottom: 30px;">
149
- <p style="font-size: 18px;">Your all-in-one science companion! Design experiments, generate reports,
150
- and get AI-powered feedback on your lab work.</p>
151
- </div>
152
- """, unsafe_allow_html=True)
 
 
 
 
 
 
 
 
153
 
154
- # Experiment templates
155
- experiments = {
156
- "Vinegar + Baking Soda": {
157
- "hypothesis": "Mixing vinegar and baking soda will produce bubbles due to a chemical reaction.",
158
- "concept": "Acid-base reaction producing carbon dioxide."
159
- },
160
- "Floating Egg": {
161
- "hypothesis": "An egg will float in salt water but sink in plain water.",
162
- "concept": "Density difference between saltwater and freshwater."
163
- },
164
- "Lemon Battery": {
165
- "hypothesis": "A lemon can produce electricity to power a small LED.",
166
- "concept": "Chemical energy conversion to electrical energy."
167
- }
168
  }
169
 
170
- # AI Query Function
171
- # Replace the query_ai function with this version
172
- def query_ai(prompt):
173
- headers = {
174
- "Authorization": f"Bearer {API_KEY}",
175
- "Content-Type": "application/json"
176
- }
177
- payload = {
178
- "model": MODEL,
179
- "messages": [
180
- {"role": "system", "content": "You are a helpful science teacher providing detailed explanations."},
181
- {"role": "user", "content": prompt}
182
- ],
183
- "temperature": 0.7
184
- }
 
 
 
 
 
 
 
 
 
185
  try:
186
- response = requests.post(API_URL, headers=headers, json=payload, timeout=120)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
 
188
- # Check for 401 Unauthorized specifically
189
- if response.status_code == 401:
190
- st.error("""
191
- **Invalid API Key!**
192
-
193
- Your Groq API key is either:
194
- - Missing
195
- - Incorrect
196
- - Expired
197
-
198
- Please check your .env file and ensure you have a valid key.
199
- """)
200
- return None
201
-
202
- response.raise_for_status()
203
- return response.json()['choices'][0]['message']['content']
204
- except requests.exceptions.HTTPError as err:
205
- st.error(f"API Error: {err.response.status_code} - {err.response.text}")
206
- return None
207
  except Exception as e:
208
- st.error(f"Error connecting to AI service: {str(e)}")
209
  return None
210
- # Navigation
211
- app_mode = st.radio("Choose Mode:", ["🧪 Experiment Assistant", "📝 Lab Report Analyzer"],
212
- horizontal=True, label_visibility="collapsed")
213
 
214
- # Sidebar
215
- with st.sidebar:
216
- st.markdown("### 🧪 Experiment Templates")
217
- st.caption("Quickly start with these pre-defined experiments:")
 
218
 
219
- selected_exp = st.selectbox("Choose an experiment template:",
220
- list(experiments.keys()) + ["Custom Experiment"])
 
 
 
 
221
 
222
- st.markdown("---")
223
- st.markdown("### 📘 Science Glossary Helper")
224
- term = st.text_input("Enter a science term (e.g., osmosis, catalyst)")
225
- if term:
226
- with st.spinner("Looking up term..."):
227
- ai_response = query_ai(f"Explain the term '{term}' in simple words for a student.")
228
- if ai_response:
229
- st.markdown(f"<div class='concept-box'>{ai_response}</div>", unsafe_allow_html=True)
230
- else:
231
- st.warning("Couldn't retrieve definition. Please try again.")
232
 
233
- # --- Experiment Assistant Section ---
234
- if app_mode == "🧪 Experiment Assistant":
235
- st.markdown('<p class="subheader">🔍 Design Your Experiment</p>', unsafe_allow_html=True)
 
 
 
 
 
 
236
 
237
- with st.form("experiment_form"):
238
- # Pre-fill if template selected
239
- if selected_exp != "Custom Experiment" and selected_exp in experiments:
240
- default_hypo = experiments[selected_exp]["hypothesis"]
241
- concept = experiments[selected_exp]["concept"]
242
- exp_name = selected_exp
243
- else:
244
- default_hypo = ""
245
- concept = ""
246
- exp_name = st.text_input("Experiment Name", placeholder="e.g., Effect of Temperature on Enzyme Activity")
247
-
248
- hypo = st.text_area("Your Hypothesis", value=default_hypo,
249
- placeholder="What do you predict will happen?")
250
-
251
- materials = st.text_area("Materials Needed",
252
- placeholder="List all materials needed for this experiment")
253
 
254
- procedure = st.text_area("Procedure Steps",
255
- placeholder="Step-by-step instructions for conducting the experiment")
 
 
256
 
257
- submit = st.form_submit_button("🔍 Generate Experiment Guide", use_container_width=True)
258
-
259
- if submit:
260
- if not exp_name or not hypo:
261
- st.warning("Please provide at least an experiment name and hypothesis")
262
- st.stop()
263
-
264
- with st.spinner("Designing your experiment guide..."):
265
- prompt = f"""
266
- Create a comprehensive guide for a science experiment with the following details:
267
-
268
- Experiment Name: {exp_name}
269
- Hypothesis: {hypo}
270
- Materials: {materials if materials else 'Not specified'}
271
- Procedure: {procedure if procedure else 'Not specified'}
272
-
273
- Please provide:
274
- 1. A clear explanation of the scientific concept behind the experiment
275
- 2. Step-by-step instructions for conducting the experiment
276
- 3. Safety precautions
277
- 4. Expected results and why they're expected
278
- 5. How to interpret the results
279
- """
280
-
281
- explanation = query_ai(prompt)
282
 
283
- if explanation:
284
- st.success(" Experiment Guide Generated!")
285
- st.balloons()
286
-
287
- # Display explanation
288
- st.markdown("### 🧪 Experiment Guide")
289
- st.markdown(f"<div class='tip-box'>{explanation}</div>", unsafe_allow_html=True)
290
-
291
- # Generate PDF report
292
- def generate_pdf_report(exp_name, hypo, explanation, materials, procedure):
293
- pdf = FPDF()
294
- pdf.add_page()
295
- pdf.set_font("Arial", size=12)
296
-
297
- # Title
298
- pdf.set_font("Arial", 'B', 16)
299
- pdf.cell(200, 10, txt="Science Experiment Guide", ln=True, align='C')
300
- pdf.ln(15)
301
-
302
- # Experiment details
303
- pdf.set_font("Arial", 'B', 14)
304
- pdf.cell(0, 10, txt=f"Experiment: {exp_name}", ln=True)
305
- pdf.ln(5)
306
-
307
- pdf.set_font("Arial", 'B', 12)
308
- pdf.cell(0, 10, txt="Hypothesis:", ln=True)
309
- pdf.set_font("Arial", '', 12)
310
- pdf.multi_cell(0, 8, txt=hypo)
311
- pdf.ln(5)
312
-
313
- if materials:
314
- pdf.set_font("Arial", 'B', 12)
315
- pdf.cell(0, 10, txt="Materials:", ln=True)
316
- pdf.set_font("Arial", '', 12)
317
- pdf.multi_cell(0, 8, txt=materials)
318
- pdf.ln(5)
319
-
320
- if procedure:
321
- pdf.set_font("Arial", 'B', 12)
322
- pdf.cell(0, 10, txt="Procedure:", ln=True)
323
- pdf.set_font("Arial", '', 12)
324
- pdf.multi_cell(0, 8, txt=procedure)
325
- pdf.ln(10)
326
-
327
- pdf.set_font("Arial", 'B', 12)
328
- pdf.cell(0, 10, txt="Experiment Guide:", ln=True)
329
- pdf.set_font("Arial", '', 12)
330
- pdf.multi_cell(0, 8, txt=explanation)
331
-
332
- filename = f"experiment_guide_{datetime.now().strftime('%Y%m%d%H%M%S')}.pdf"
333
- pdf.output(filename)
334
- return filename
335
-
336
- pdf_file = generate_pdf_report(exp_name, hypo, explanation, materials, procedure)
337
- with open(pdf_file, "rb") as file:
338
- st.download_button("📄 Download Experiment Guide (PDF)", file,
339
- file_name=f"{exp_name}_guide.pdf",
340
- use_container_width=True)
341
 
342
- # Experiment examples
343
- st.markdown("---")
344
- st.markdown('<p class="subheader">🔬 Popular Science Experiments</p>', unsafe_allow_html=True)
345
 
346
- col1, col2 = st.columns(2)
347
  with col1:
348
- with st.container():
349
- st.markdown('<div class="experiment-card">', unsafe_allow_html=True)
350
- st.markdown("#### 🧫 Vinegar + Baking Soda")
351
- st.markdown("**Hypothesis:** Mixing vinegar and baking soda will produce bubbles due to a chemical reaction.")
352
- st.markdown("**Concept:** Acid-base reaction producing carbon dioxide.")
353
- if st.button("Try This Experiment", key="vinegar", use_container_width=True):
354
- st.session_state.selected_exp = "Vinegar + Baking Soda"
355
- st.markdown('</div>', unsafe_allow_html=True)
356
-
357
- with st.container():
358
- st.markdown('<div class="experiment-card">', unsafe_allow_html=True)
359
- st.markdown("#### 🥚 Floating Egg")
360
- st.markdown("**Hypothesis:** An egg will float in salt water but sink in plain water.")
361
- st.markdown("**Concept:** Density difference between saltwater and freshwater.")
362
- if st.button("Try This Experiment", key="egg", use_container_width=True):
363
- st.session_state.selected_exp = "Floating Egg"
364
- st.markdown('</div>', unsafe_allow_html=True)
365
-
366
- with col2:
367
- with st.container():
368
- st.markdown('<div class="experiment-card">', unsafe_allow_html=True)
369
- st.markdown("#### 🍋 Lemon Battery")
370
- st.markdown("**Hypothesis:** A lemon can produce electricity to power a small LED.")
371
- st.markdown("**Concept:** Chemical energy conversion to electrical energy.")
372
- if st.button("Try This Experiment", key="lemon", use_container_width=True):
373
- st.session_state.selected_exp = "Lemon Battery"
374
- st.markdown('</div>', unsafe_allow_html=True)
375
-
376
- with st.container():
377
- st.markdown('<div class="experiment-card">', unsafe_allow_html=True)
378
- st.markdown("#### 🌈 Rainbow in a Glass")
379
- st.markdown("**Hypothesis:** Different sugar solutions can form colorful layers in a glass.")
380
- st.markdown("**Concept:** Density gradient formation.")
381
- if st.button("Try This Experiment", key="rainbow", use_container_width=True):
382
- st.session_state.selected_exp = "Custom Experiment"
383
- st.session_state.custom_exp = "Rainbow in a Glass"
384
- st.session_state.custom_hypo = "Different sugar solutions will form distinct layers based on their density."
385
- st.markdown('</div>', unsafe_allow_html=True)
386
-
387
- # --- Lab Report Analyzer Section ---
388
- else:
389
- # --- File Upload ---
390
- st.markdown('<p class="subheader">📤 Upload Your Lab Report</p>', unsafe_allow_html=True)
391
- uploaded_file = st.file_uploader("Upload image (JPG, PNG) or PDF",
392
- type=["jpg", "jpeg", "png", "pdf"],
393
- label_visibility="collapsed")
394
-
395
- lab_text = ""
396
- if uploaded_file:
397
- file_bytes = uploaded_file.read()
398
- file_ext = uploaded_file.name.split(".")[-1].lower()
399
-
400
- if file_ext == "pdf":
401
- try:
402
- with pdfplumber.open(io.BytesIO(file_bytes)) as pdf:
403
- for page in pdf.pages:
404
- lab_text += page.extract_text() + "\n"
405
- st.success("✅ PDF text extracted successfully!")
406
- except Exception as e:
407
- st.error(f"Error reading PDF: {str(e)}")
408
- else:
409
- try:
410
- image = Image.open(io.BytesIO(file_bytes))
411
- st.image(image, caption="Uploaded Image", width=300)
412
-
413
- # OCR processing
414
- with st.spinner("Extracting text from image..."):
415
- try:
416
- lab_text = pytesseract.image_to_string(image)
417
- st.success("✅ Text extracted from image!")
418
- except pytesseract.pytesseract.TesseractNotFoundError:
419
- st.error("""
420
- **Tesseract OCR not found!**
421
-
422
- To enable image text extraction:
423
- 1. Install Tesseract OCR on your system
424
- 2. Add it to your system PATH
425
- 3. Restart the application
426
-
427
- For Windows: Download from [UB-Mannheim/tesseract](https://github.com/UB-Mannheim/tesseract/wiki)
428
- For Linux: `sudo apt install tesseract-ocr`
429
- For Mac: `brew install tesseract`
430
- """)
431
- st.stop()
432
- except Exception as e:
433
- st.error(f"OCR Error: {str(e)}")
434
- st.stop()
435
- except Exception as e:
436
- st.error(f"Error processing image: {str(e)}")
437
-
438
- # Allow text editing
439
- if lab_text:
440
- st.markdown('<p class="subheader">✍️ Extracted Text</p>', unsafe_allow_html=True)
441
- st.caption("Review and edit the extracted text if needed before analysis")
442
- lab_text = st.text_area("", lab_text, height=300, label_visibility="collapsed")
443
-
444
- # --- AI Evaluation ---
445
- if lab_text.strip():
446
- # -- AI Evaluation Prompt --
447
- full_prompt = f"""You are a science teacher evaluating a student's lab report. Please provide a comprehensive analysis:
448
-
449
- Lab Report:
450
- {lab_text}
451
-
452
- Evaluation Guidelines:
453
- 1. **Section Check**: Identify which of these sections are present and which are missing:
454
- - Title
455
- - Objective
456
- - Hypothesis
457
- - Materials
458
- - Procedure
459
- - Observations
460
- - Results
461
- - Conclusion
462
- - References
463
 
464
- 2. **Completeness Score**:
465
- - Assign a numerical score from 1-10 based on completeness
466
- - Justify the score based on missing sections and content quality
467
 
468
- 3. **Improvement Tips**:
469
- - For each missing section, explain why it's important
470
- - Provide specific suggestions for improvement (e.g., "Try writing a more detailed observation section by including quantitative data")
471
- - Highlight any sections that need more detail or clarity
 
472
 
473
- 4. **Structure Response**:
474
- - Start with: "### Missing Sections:"
475
- - Then: "### Completeness Score: X/10"
476
- - Then: "### Improvement Tips:"
477
- - Finally: "### Detailed Feedback:"
478
 
479
- Be concise but thorough in your analysis.
480
- """
481
-
482
- if st.button("🧪 Analyze Report", use_container_width=True):
483
- with st.spinner("🔍 Analyzing report with AI. This may take 20-30 seconds..."):
484
- result = query_ai(full_prompt)
485
-
486
- if result:
487
- st.success("✅ Analysis Complete!")
488
- st.balloons()
489
-
490
- # Extract score using regex
491
- score_match = re.search(r"Completeness Score:\s*(\d+)/10", result, re.IGNORECASE)
492
- score = int(score_match.group(1)) if score_match else None
493
-
494
- # Display score in a card
495
- if score is not None:
496
- with st.container():
497
- st.markdown('<div class="score-card">', unsafe_allow_html=True)
498
-
499
- # Create columns for score visualization
500
- col1, col2 = st.columns([1, 3])
501
-
502
- with col1:
503
- st.markdown(f"<h2 style='text-align: center; color: #28b463;'>{score}/10</h2>",
504
- unsafe_allow_html=True)
505
- st.markdown("<h4 style='text-align: center;'>Completeness Score</h4>",
506
- unsafe_allow_html=True)
507
-
508
- with col2:
509
- # Create a color gradient based on score
510
- if score >= 8:
511
- color = "#28b463" # Green
512
- elif score >= 5:
513
- color = "#f39c12" # Orange
514
- else:
515
- color = "#e74c3c" # Red
516
-
517
- # Display progress bar with styling
518
- st.progress(score/10, text=f"{score*10}% complete")
519
- st.markdown(
520
- f"<style>"
521
- f".stProgress > div > div > div {{"
522
- f" background-color: {color} !important;"
523
- f" border-radius: 10px;"
524
- f"}}"
525
- f"</style>",
526
- unsafe_allow_html=True
527
- )
528
-
529
- st.markdown('</div>', unsafe_allow_html=True)
530
-
531
- # Display AI analysis with formatting
532
- st.markdown("## 📝 Analysis Results")
533
-
534
- # Split sections for better display
535
- sections = {
536
- "Missing Sections": None,
537
- "Improvement Tips": None,
538
- "Detailed Feedback": None
539
- }
540
-
541
- current_section = None
542
- for line in result.split('\n'):
543
- if "### Missing Sections:" in line:
544
- current_section = "Missing Sections"
545
- sections[current_section] = []
546
- elif "### Improvement Tips:" in line:
547
- current_section = "Improvement Tips"
548
- sections[current_section] = []
549
- elif "### Detailed Feedback:" in line:
550
- current_section = "Detailed Feedback"
551
- sections[current_section] = []
552
- elif current_section and line.strip():
553
- sections[current_section].append(line)
554
-
555
- # Display each section
556
- if sections["Missing Sections"]:
557
- st.markdown("### 🔍 Missing Sections")
558
- missing_text = '\n'.join(sections["Missing Sections"])
559
- st.markdown(f'<div class="highlight">{missing_text}</div>', unsafe_allow_html=True)
560
-
561
- if sections["Improvement Tips"]:
562
- st.markdown("### 💡 Improvement Tips")
563
- tips_text = '\n'.join(sections["Improvement Tips"])
564
- st.markdown(f'<div class="tip-box">{tips_text}</div>', unsafe_allow_html=True)
565
-
566
- if sections["Detailed Feedback"]:
567
- st.markdown("### 📋 Detailed Feedback")
568
- st.write('\n'.join(sections["Detailed Feedback"]))
569
-
570
- # Show full AI response in expander
571
- with st.expander("View Full AI Analysis"):
572
- st.markdown(result)
573
-
574
- # --- Question Answering Section ---
575
- st.markdown("---")
576
- st.markdown('<p class="subheader">❓ Ask About Your Report</p>', unsafe_allow_html=True)
577
 
578
- col1, col2 = st.columns([3, 1])
579
- with col1:
580
- user_question = st.text_input("Ask a question about your lab report",
581
- placeholder="e.g., How can I improve my hypothesis?")
582
- with col2:
583
- st.markdown("<div style='height: 28px;'></div>", unsafe_allow_html=True)
584
- ask_button = st.button("🔍 Ask Question", use_container_width=True)
 
 
 
 
 
 
 
 
 
585
 
586
- if (ask_button or user_question) and user_question.strip():
587
- with st.spinner("Thinking..."):
588
- followup_prompt = f"""Lab Report:
589
- {lab_text}
 
 
 
590
 
591
- Question: {user_question}
592
-
593
- Answer the question based on the lab report. If the question can't be answered from the report,
594
- suggest what information the student should add to answer it.
595
- """
596
- followup_response = query_ai(followup_prompt)
 
 
597
 
598
- if followup_response:
599
- st.markdown("### 💬 AI Response")
600
- st.markdown(f'<div class="tip-box">{followup_response}</div>', unsafe_allow_html=True)
601
- else:
602
- # Show sample report if no file uploaded
603
- st.markdown("---")
604
- st.markdown('<p class="subheader">📝 Sample Lab Report</p>', unsafe_allow_html=True)
605
- st.markdown("""
606
- **Title:** Effect of Temperature on Enzyme Activity
607
- **Objective:** To investigate how temperature affects catalase enzyme activity
608
- **Hypothesis:** Enzyme activity will increase with temperature up to 37°C, then decrease
609
- **Materials:** Test tubes, hydrogen peroxide, liver extract, thermometer
610
- **Procedure:**
611
- 1. Prepare test tubes at 5 different temperatures
612
- 2. Add equal amounts of hydrogen peroxide and liver extract
613
- 3. Measure oxygen production
614
- **Observations:** More bubbles at 37°C compared to lower or higher temperatures
615
- **Conclusion:** Enzyme activity peaks at body temperature
616
- """)
617
-
618
- st.info("👆 Upload your own lab report to get a personalized analysis!")
619
 
620
- # Footer
621
- st.markdown("---")
622
- st.markdown('<div class="footer">🔬 Science Lab Assistant | Made for Students & Educators</div>', unsafe_allow_html=True)
 
1
  # app.py
 
 
 
 
 
 
 
 
2
  import os
3
+ import streamlit as st
4
+ from groq import Groq
5
+ import time
6
+ import plotly.express as px
7
+ from dotenv import load_dotenv
 
 
 
 
 
 
 
 
 
 
 
8
 
9
+ # Load environment variables
10
+ load_dotenv()
 
11
 
12
+ # Initialize Groq client
13
+ client = Groq(api_key=os.getenv("GROQ_API_KEY"))
 
 
 
 
 
 
 
 
14
 
15
+ # Set up Streamlit page
16
  st.set_page_config(
17
+ page_title="Legal Rights Explorer",
18
+ page_icon="⚖️",
19
+ layout="wide",
20
  initial_sidebar_state="expanded"
21
  )
22
 
23
  # Custom CSS for styling
24
  st.markdown("""
25
+ <style>
26
+ :root {
27
+ --primary: #4361ee;
28
+ --secondary: #3f37c9;
29
+ --accent: #4895ef;
30
+ --success: #4cc9f0;
31
+ --dark: #3a0ca3;
32
+ --light: #f8f9fa;
33
+ --text: #212529;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  }
35
+
36
+ .stApp {
37
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
38
+ color: var(--text);
 
 
39
  }
40
+
41
+ .header {
42
+ background: linear-gradient(90deg, var(--dark) 0%, var(--primary) 100%);
43
+ color: white;
44
+ padding: 1.5rem;
45
+ border-radius: 0 0 20px 20px;
46
+ box-shadow: 0 4px 20px rgba(0,0,0,0.15);
47
+ margin-bottom: 2rem;
48
  }
49
+
50
+ .card {
51
+ background: white;
52
  border-radius: 15px;
53
+ padding: 1.5rem;
54
+ box-shadow: 0 6px 15px rgba(0,0,0,0.1);
55
+ margin-bottom: 1.5rem;
56
+ transition: transform 0.3s ease;
57
  }
58
+
59
+ .card:hover {
60
  transform: translateY(-5px);
61
+ box-shadow: 0 10px 25px rgba(0,0,0,0.15);
62
  }
63
+
64
+ .scenario-btn {
65
+ width: 100%;
66
+ padding: 1rem;
67
+ background: linear-gradient(90deg, var(--accent) 0%, var(--success) 100%);
68
+ color: white;
69
+ border: none;
70
+ border-radius: 12px;
71
+ font-weight: 600;
72
+ margin: 0.5rem 0;
73
+ cursor: pointer;
74
+ transition: all 0.3s ease;
75
  }
76
+
77
+ .scenario-btn:hover {
78
+ background: linear-gradient(90deg, var(--secondary) 0%, var(--primary) 100%);
79
+ transform: scale(1.02);
80
  }
81
+
82
+ .response-card {
83
+ background: rgba(255, 255, 255, 0.95);
84
+ border-left: 5px solid var(--primary);
85
+ border-radius: 10px;
86
+ padding: 1.5rem;
87
+ margin-top: 1.5rem;
88
+ box-shadow: 0 4px 15px rgba(0,0,0,0.08);
89
+ }
90
+
91
  .footer {
92
  text-align: center;
93
+ padding: 1.5rem;
94
+ margin-top: 2rem;
95
+ color: var(--text);
96
+ font-size: 0.9rem;
97
  }
98
+
99
+ @media (max-width: 768px) {
100
+ .header {
101
+ padding: 1rem;
102
+ }
103
+
104
+ .card {
105
+ padding: 1rem;
106
+ }
107
  }
108
+ </style>
109
+ """, unsafe_allow_html=True)
110
 
111
+ # Country data with flags
112
+ COUNTRIES = {
113
+ "🇺🇸 United States": "US",
114
+ "🇬🇧 United Kingdom": "UK",
115
+ "🇨🇦 Canada": "Canada",
116
+ "🇦🇺 Australia": "Australia",
117
+ "🇮🇳 India": "India",
118
+ "🇩🇪 Germany": "Germany",
119
+ "🇫🇷 France": "France",
120
+ "🇯🇵 Japan": "Japan",
121
+ "🇧🇷 Brazil": "Brazil",
122
+ "🇿🇦 South Africa": "South Africa",
123
+ "🇪🇸 Spain": "Spain",
124
+ "🇮🇹 Italy": "Italy"
125
+ }
126
 
127
+ # Common legal scenarios
128
+ SCENARIOS = [
129
+ "Traffic Stop by Police",
130
+ "Workplace Discrimination",
131
+ "Rental Housing Issues",
132
+ "Medical Emergency Rights",
133
+ "Consumer Protection",
134
+ "Arrest or Detention",
135
+ "Border Crossing",
136
+ "Online Privacy",
137
+ "Employment Termination",
138
+ "Debt Collection",
139
+ "Freedom of Speech",
140
+ "Immigration Rights"
141
+ ]
142
 
143
+ # LLM models available on Groq
144
+ MODELS = {
145
+ "Llama3-70b-8192": "llama3-70b-8192",
146
+ "Llama3-8b-8192": "llama3-8b-8192",
147
+ "Mixtral-8x7b-32768": "mixtral-8x7b-32768",
148
+ "Gemma-7b-It": "gemma-7b-it"
 
 
 
 
 
 
 
 
149
  }
150
 
151
+ # Function to get rights information from Groq API
152
+ def get_legal_rights(country, scenario, model_name):
153
+ """Get legal rights information using Groq API"""
154
+ system_prompt = f"""
155
+ You are an expert legal assistant specializing in {country} law.
156
+ Provide clear, accurate information about an individual's rights in the given scenario.
157
+
158
+ Guidelines:
159
+ - List 5-7 key rights as bullet points
160
+ - Use plain language understandable to non-lawyers
161
+ - Include relevant legal references when appropriate
162
+ - Highlight any critical actions the person should take
163
+ - Mention any country-specific variations
164
+ - Keep response under 300 words
165
+ - Format with emojis for readability
166
+ """
167
+
168
+ user_prompt = f"""
169
+ Scenario: {scenario}
170
+ Country: {country}
171
+
172
+ Please provide a comprehensive list of rights for this situation in {country}.
173
+ """
174
+
175
  try:
176
+ chat_completion = client.chat.completions.create(
177
+ messages=[
178
+ {
179
+ "role": "system",
180
+ "content": system_prompt
181
+ },
182
+ {
183
+ "role": "user",
184
+ "content": user_prompt
185
+ }
186
+ ],
187
+ model=model_name,
188
+ temperature=0.3,
189
+ max_tokens=1024,
190
+ top_p=1,
191
+ stream=False,
192
+ stop=None,
193
+ )
194
 
195
+ return chat_completion.choices[0].message.content
196
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
  except Exception as e:
198
+ st.error(f"Error fetching data: {str(e)}")
199
  return None
 
 
 
200
 
201
+ # Function to display response with animation
202
+ def display_response(response):
203
+ """Display the response with typing animation effect"""
204
+ message_placeholder = st.empty()
205
+ full_response = ""
206
 
207
+ # Simulate stream of response with milliseconds delay
208
+ for chunk in response.split():
209
+ full_response += chunk + " "
210
+ time.sleep(0.05)
211
+ # Add a blinking cursor to simulate typing
212
+ message_placeholder.markdown(f'<div class="response-card">{full_response}▌</div>', unsafe_allow_html=True)
213
 
214
+ # Display final message without the cursor
215
+ message_placeholder.markdown(f'<div class="response-card">{response}</div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
216
 
217
+ # Main app
218
+ def main():
219
+ # Header section
220
+ st.markdown("""
221
+ <div class="header">
222
+ <h1>Legal Rights Explorer</h1>
223
+ <p>Know your rights in any situation, anywhere in the world</p>
224
+ </div>
225
+ """, unsafe_allow_html=True)
226
 
227
+ # Sidebar for settings
228
+ with st.sidebar:
229
+ st.markdown("## ⚙️ Settings")
230
+ selected_model = st.selectbox("Select AI Model", list(MODELS.keys()), index=0)
 
 
 
 
 
 
 
 
 
 
 
 
231
 
232
+ st.markdown("---")
233
+ st.markdown("### About")
234
+ st.markdown("This app helps you understand your legal rights in various situations across different countries using AI technology.")
235
+ st.markdown("Powered by Groq API and open-source LLMs.")
236
 
237
+ st.markdown("---")
238
+ st.markdown("### How to Use")
239
+ st.markdown("1. Select your country 🇬🇧")
240
+ st.markdown("2. Choose a legal scenario 🚔")
241
+ st.markdown("3. Get instant rights information ⚖️")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
 
243
+ st.markdown("---")
244
+ st.markdown("Built with ❤️ for legal empowerment")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
 
246
+ # Main content columns
247
+ col1, col2 = st.columns([1, 2])
 
248
 
 
249
  with col1:
250
+ st.markdown("### 🌍 Select Your Country")
251
+ country_display = st.selectbox("Choose country", list(COUNTRIES.keys()), index=0)
252
+ country_code = COUNTRIES[country_display]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
 
254
+ st.markdown("### 🚨 Choose a Scenario")
 
 
255
 
256
+ # Create buttons for each scenario
257
+ for scenario in SCENARIOS:
258
+ if st.button(scenario, key=scenario, use_container_width=True,
259
+ help=f"Click to see your rights for {scenario}"):
260
+ st.session_state.selected_scenario = scenario
261
 
262
+ # Custom scenario input
263
+ custom_scenario = st.text_input("Or enter your own scenario:")
264
+ if custom_scenario:
265
+ st.session_state.selected_scenario = custom_scenario
 
266
 
267
+ # Add some visualizations
268
+ st.markdown("### 📊 Global Rights Awareness")
269
+ countries = list(COUNTRIES.values())
270
+ awareness = [80, 75, 70, 65, 60, 55, 50, 45, 40, 35, 30, 25] # Simulated data
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
 
272
+ fig = px.bar(
273
+ x=countries,
274
+ y=awareness,
275
+ labels={'x': 'Country', 'y': 'Awareness Level'},
276
+ color=awareness,
277
+ color_continuous_scale='Blues'
278
+ )
279
+ fig.update_layout(
280
+ title='Rights Awareness by Country',
281
+ plot_bgcolor='rgba(0,0,0,0)',
282
+ paper_bgcolor='rgba(0,0,0,0)'
283
+ )
284
+ st.plotly_chart(fig, use_container_width=True)
285
+
286
+ with col2:
287
+ st.markdown("### ⚖️ Your Legal Rights")
288
 
289
+ if 'selected_scenario' in st.session_state and st.session_state.selected_scenario:
290
+ with st.spinner(f"Getting your rights for {st.session_state.selected_scenario} in {country_code}..."):
291
+ response = get_legal_rights(
292
+ country_code,
293
+ st.session_state.selected_scenario,
294
+ MODELS[selected_model]
295
+ )
296
 
297
+ if response:
298
+ display_response(response)
299
+ else:
300
+ st.error("Failed to get response. Please try again.")
301
+ else:
302
+ st.info("Please select a legal scenario from the left panel to see your rights.")
303
+ st.image("https://images.unsplash.com/photo-1589391886645-d51941baf7fb?auto=format&fit=crop&w=600&h=400",
304
+ caption="Know Your Rights, Exercise Your Freedom")
305
 
306
+ st.markdown("""
307
+ <div class="card">
308
+ <h3>Why Know Your Rights?</h3>
309
+ <p>Understanding your legal rights empowers you to:</p>
310
+ <ul>
311
+ <li>Protect yourself in difficult situations</li>
312
+ <li>Make informed decisions</li>
313
+ <li>Prevent exploitation</li>
314
+ <li>Access justice when needed</li>
315
+ <li>Confidently navigate legal systems</li>
316
+ </ul>
317
+ </div>
318
+ """, unsafe_allow_html=True)
319
+
320
+ # Footer
321
+ st.markdown("""
322
+ <div class="footer">
323
+ <p>Legal Rights Explorer | For Educational Purposes Only | Not Legal Advice</p>
324
+ <p>Always consult a qualified attorney for your specific legal situation</p>
325
+ </div>
326
+ """, unsafe_allow_html=True)
327
 
328
+ if __name__ == "__main__":
329
+ main()