Files changed (1) hide show
  1. app.py +76 -343
app.py CHANGED
@@ -1,3 +1,4 @@
 
1
  import streamlit as st
2
  import PyPDF2
3
  import requests
@@ -5,10 +6,10 @@ import json
5
  from sentence_transformers import SentenceTransformer
6
  import numpy as np
7
  from sklearn.metrics.pairwise import cosine_similarity
8
- import os
9
  from datetime import datetime
 
10
 
11
- # Page configuration
12
  st.set_page_config(
13
  page_title="🚨 First Aid Emergency Assistant",
14
  page_icon="🚨",
@@ -16,405 +17,137 @@ st.set_page_config(
16
  initial_sidebar_state="collapsed"
17
  )
18
 
19
- # Custom CSS for ChatGPT-like interface
20
- st.markdown("""
21
- <style>
22
- .stApp {
23
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
24
- }
25
-
26
- .main-header {
27
- text-align: center;
28
- padding: 1rem 0;
29
- background: rgba(255, 255, 255, 0.1);
30
- border-radius: 15px;
31
- margin-bottom: 2rem;
32
- backdrop-filter: blur(10px);
33
- border: 1px solid rgba(255, 255, 255, 0.2);
34
- }
35
-
36
- .chat-container {
37
- background: white;
38
- border-radius: 15px;
39
- padding: 1rem;
40
- margin: 1rem 0;
41
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
42
- border: 1px solid rgba(255, 255, 255, 0.2);
43
- max-height: 500px;
44
- overflow-y: auto;
45
- }
46
-
47
- .user-message {
48
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
49
- color: white;
50
- padding: 12px 16px;
51
- border-radius: 18px 18px 5px 18px;
52
- margin: 8px 0 8px 20%;
53
- max-width: 80%;
54
- float: right;
55
- clear: both;
56
- box-shadow: 0 2px 10px rgba(102, 126, 234, 0.3);
57
- }
58
-
59
- .bot-message {
60
- background: #f8f9fa;
61
- color: #333;
62
- padding: 12px 16px;
63
- border-radius: 18px 18px 18px 5px;
64
- margin: 8px 20% 8px 0;
65
- max-width: 80%;
66
- float: left;
67
- clear: both;
68
- border: 1px solid #e9ecef;
69
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
70
- }
71
-
72
- .input-container {
73
- position: sticky;
74
- bottom: 0;
75
- background: white;
76
- padding: 1rem;
77
- border-radius: 15px;
78
- margin-top: 2rem;
79
- box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.1);
80
- }
81
-
82
- .warning-box {
83
- background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%);
84
- padding: 1rem;
85
- border-radius: 10px;
86
- margin: 1rem 0;
87
- border-left: 4px solid #ff6b6b;
88
- }
89
-
90
- .stTextInput input {
91
- border-radius: 25px !important;
92
- border: 2px solid #e9ecef !important;
93
- padding: 12px 20px !important;
94
- font-size: 16px !important;
95
- }
96
-
97
- .stTextInput input:focus {
98
- border-color: #667eea !important;
99
- box-shadow: 0 0 0 0.2rem rgba(102, 126, 234, 0.25) !important;
100
- }
101
-
102
- .stButton button {
103
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
104
- color: white !important;
105
- border: none !important;
106
- border-radius: 25px !important;
107
- padding: 12px 30px !important;
108
- font-weight: 600 !important;
109
- transition: all 0.3s ease !important;
110
- }
111
-
112
- .stButton button:hover {
113
- transform: translateY(-2px) !important;
114
- box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4) !important;
115
- }
116
-
117
- .sidebar-info {
118
- background: rgba(255, 255, 255, 0.1);
119
- padding: 1rem;
120
- border-radius: 10px;
121
- margin: 1rem 0;
122
- }
123
- </style>
124
- """, unsafe_allow_html=True)
125
-
126
- # Initialize GROQ API
127
-
128
- import os
129
- import streamlit as st
130
- from groq import Groq
131
-
132
- groq_api_key = st.secrets.get("GROQ_API_KEY")
133
-
134
- client = Groq(api_key=groq_api_key)
135
-
136
- chat_completion = client.chat.completions.create(
137
- messages=[
138
- {
139
- "role": "user",
140
- "content": "Explain the importance of fast language models",
141
- }
142
- ],
143
- model="llama3-70b-8192",
144
- )
145
-
146
- st.write(chat_completion.choices[0].message.content)
147
 
 
 
 
 
 
 
 
 
148
 
 
149
 
150
- # Load and process PDF
151
  @st.cache_resource
152
  def load_pdf():
153
  try:
154
- with open("First-Aid.pdf", "rb") as file:
155
- pdf_reader = PyPDF2.PdfReader(file)
156
- text = ""
157
- for page in pdf_reader.pages:
158
- text += page.extract_text() + "\n"
159
- return text
160
- except FileNotFoundError:
161
- st.error("πŸ“„ First-Aid.pdf not found! Please upload the PDF file to your space.")
162
- st.stop()
163
- except Exception as e:
164
- st.error(f"❌ Error loading PDF: {str(e)}")
165
  st.stop()
166
 
167
- # Setup embeddings and knowledge base
168
  @st.cache_resource
169
  def setup_knowledge_base():
170
- # Load PDF content
171
- pdf_text = load_pdf()
172
-
173
- # Split text into chunks
174
- chunks = []
175
- sentences = pdf_text.split('\n')
176
- current_chunk = ""
177
-
178
- for sentence in sentences:
179
  if len(current_chunk + sentence) < 1000:
180
  current_chunk += sentence + "\n"
181
  else:
182
- if current_chunk.strip():
183
- chunks.append(current_chunk.strip())
184
  current_chunk = sentence + "\n"
185
-
186
- if current_chunk.strip():
187
- chunks.append(current_chunk.strip())
188
-
189
- # Load sentence transformer model
190
  model = SentenceTransformer('all-MiniLM-L6-v2')
191
-
192
- # Create embeddings for chunks
193
- chunk_embeddings = model.encode(chunks)
194
-
195
- return chunks, chunk_embeddings, model
196
 
197
- def find_relevant_context(query, chunks, chunk_embeddings, model, top_k=3):
198
- """Find most relevant chunks for the query"""
199
  query_embedding = model.encode([query])
200
- similarities = cosine_similarity(query_embedding, chunk_embeddings)[0]
201
  top_indices = np.argsort(similarities)[-top_k:][::-1]
202
-
203
- relevant_chunks = [chunks[i] for i in top_indices]
204
- return "\n\n".join(relevant_chunks)
205
 
 
206
  def query_groq(prompt, api_key):
207
- """Query GROQ API"""
208
  url = "https://api.groq.com/openai/v1/chat/completions"
209
-
210
- headers = {
211
- "Authorization": f"Bearer {api_key}",
212
- "Content-Type": "application/json"
213
- }
214
-
215
  data = {
216
- "model": "mixtral-8x7b-32768",
217
  "messages": [
218
  {
219
  "role": "system",
220
- "content": """You are a First Aid Emergency Assistant. You provide clear, step-by-step first aid guidance based on the provided medical manual context.
221
-
222
- IMPORTANT RULES:
223
- 1. Only answer questions related to first aid, medical emergencies, and health safety
224
- 2. If asked about non-medical topics, politely redirect to first aid topics
225
- 3. For serious emergencies, always remind users to call emergency services first
226
- 4. Provide clear, numbered steps when giving instructions
227
- 5. Keep responses focused and practical
228
-
229
- If the question is not related to first aid or medical emergencies, respond with: "🚨 I'm specialized in First Aid emergencies only! Please ask me about medical emergencies, CPR, wounds, burns, fractures, or other first aid topics."
230
- """
231
  },
232
- {
233
- "role": "user",
234
- "content": prompt
235
- }
236
  ],
237
  "temperature": 0.3,
238
  "max_tokens": 1000
239
  }
240
-
241
  try:
242
- response = requests.post(url, headers=headers, json=data, timeout=30)
243
- response.raise_for_status()
244
- return response.json()["choices"][0]["message"]["content"]
245
- except requests.exceptions.RequestException as e:
246
- return f"❌ Error connecting to GROQ API: {str(e)}"
247
  except Exception as e:
248
- return f"❌ Error processing response: {str(e)}"
249
 
250
- # Initialize session state
251
  if "messages" not in st.session_state:
252
- st.session_state.messages = [
253
- {
254
- "role": "assistant",
255
- "content": "🚨 **Hello! I'm your First Aid Emergency Assistant.**\n\nI can help you with:\nβ€’ CPR procedures\nβ€’ Bleeding control\nβ€’ Burns treatment\nβ€’ Choking response\nβ€’ Fracture management\nβ€’ Poisoning emergencies\nβ€’ And much more!\n\nπŸ’‘ **Ask me anything about first aid emergencies!**"
256
- }
257
- ]
258
 
259
  if "knowledge_base" not in st.session_state:
260
- with st.spinner("πŸ”„ Loading First Aid knowledge base..."):
261
  chunks, embeddings, model = setup_knowledge_base()
262
  st.session_state.knowledge_base = {
263
- "chunks": chunks,
264
- "embeddings": embeddings,
265
- "model": model
266
  }
267
 
268
- if "groq_api_key" not in st.session_state:
269
- st.session_state.groq_api_key = setup_groq()
270
-
271
- # Header
272
- st.markdown("""
273
- <div class="main-header">
274
- <h1>🚨 First Aid Emergency Assistant</h1>
275
- <p style="margin: 0; font-size: 18px; opacity: 0.9;">Your AI-powered emergency response guide</p>
276
- </div>
277
- """, unsafe_allow_html=True)
278
 
279
- # Warning disclaimer
280
  st.markdown("""
281
  <div class="warning-box">
282
- <strong>⚠️ IMPORTANT MEDICAL DISCLAIMER:</strong><br>
283
- This chatbot provides general first aid guidance only. In real emergencies, always call emergency services immediately.
284
- This tool is not a substitute for professional medical advice, diagnosis, or treatment.
285
  </div>
286
  """, unsafe_allow_html=True)
287
 
288
- # Chat container
289
- chat_container = st.container()
290
-
291
- with chat_container:
292
  st.markdown('<div class="chat-container">', unsafe_allow_html=True)
293
-
294
- # Display chat messages
295
- for message in st.session_state.messages:
296
- if message["role"] == "user":
297
- st.markdown(f"""
298
- <div class="user-message">
299
- <strong>You:</strong> {message["content"]}
300
- </div>
301
- <div style="clear: both;"></div>
302
- """, unsafe_allow_html=True)
303
  else:
304
- st.markdown(f"""
305
- <div class="bot-message">
306
- <strong>πŸ€– First Aid Assistant:</strong><br>
307
- {message["content"]}
308
- </div>
309
- <div style="clear: both;"></div>
310
- """, unsafe_allow_html=True)
311
-
312
  st.markdown('</div>', unsafe_allow_html=True)
313
 
314
- # Input section
315
  st.markdown('<div class="input-container">', unsafe_allow_html=True)
316
-
317
  col1, col2 = st.columns([4, 1])
318
-
319
  with col1:
320
- user_input = st.text_input(
321
- "",
322
- placeholder="Ask me about first aid emergencies... (e.g., 'How to treat burns?')",
323
- key="user_input",
324
- label_visibility="collapsed"
325
- )
326
-
327
  with col2:
328
- send_button = st.button("Send πŸš€", key="send_button")
329
-
330
  st.markdown('</div>', unsafe_allow_html=True)
331
 
332
- # Process user input
333
- if send_button and user_input.strip():
334
- # Add user message to chat
335
  st.session_state.messages.append({"role": "user", "content": user_input})
336
-
337
- # Get bot response
338
- with st.spinner("πŸ€” Thinking..."):
339
- try:
340
- # Find relevant context from PDF
341
- kb = st.session_state.knowledge_base
342
- context = find_relevant_context(
343
- user_input,
344
- kb["chunks"],
345
- kb["embeddings"],
346
- kb["model"]
347
- )
348
-
349
- # Create enhanced prompt with context
350
- enhanced_prompt = f"""
351
- Based on the following first aid manual content, answer this question: {user_input}
352
-
353
- Context from First Aid Manual:
354
  {context}
355
-
356
- Please provide a clear, helpful response based on this information. If this is a serious emergency, remind the user to call emergency services first.
357
  """
358
-
359
- # Query GROQ API
360
- response = query_groq(enhanced_prompt, st.session_state.groq_api_key)
361
-
362
- # Enhance response with emergency reminder for serious cases
363
- serious_keywords = ['heart attack', 'stroke', 'unconscious', 'not breathing', 'severe bleeding', 'poisoning', 'choking']
364
- if any(keyword in user_input.lower() for keyword in serious_keywords):
365
- response = f"🚨 **CALL EMERGENCY SERVICES IMMEDIATELY!**\n\n{response}"
366
-
367
- except Exception as e:
368
- response = f"❌ Sorry, I encountered an error: {str(e)}. Please try asking your question differently."
369
-
370
- # Add bot response to chat
371
- st.session_state.messages.append({"role": "assistant", "content": response})
372
-
373
- # Rerun to show new message
374
- st.rerun()
375
 
376
- # Sidebar with helpful information
377
- with st.sidebar:
378
- st.markdown("## πŸ“‹ Quick Emergency Numbers")
379
- st.markdown("""
380
- <div class="sidebar-info">
381
- <strong>🚨 Emergency Services:</strong><br>
382
- β€’ General Emergency: 911<br>
383
- β€’ Poison Control: 1-800-222-1222<br>
384
- β€’ Mental Health Crisis: 988
385
- </div>
386
- """, unsafe_allow_html=True)
387
-
388
- st.markdown("## 🎯 What I Can Help With")
389
- st.markdown("""
390
- <div class="sidebar-info">
391
- β€’ CPR and rescue breathing<br>
392
- β€’ Wound care and bleeding<br>
393
- β€’ Burns and scalds<br>
394
- β€’ Fractures and sprains<br>
395
- β€’ Choking procedures<br>
396
- β€’ Poisoning emergencies<br>
397
- β€’ Heart attack signs<br>
398
- β€’ Snake and animal bites<br>
399
- β€’ Drowning response<br>
400
- β€’ And much more!
401
- </div>
402
- """, unsafe_allow_html=True)
403
-
404
- st.markdown("## ℹ️ How to Use")
405
- st.markdown("""
406
- <div class="sidebar-info">
407
- 1. Type your first aid question<br>
408
- 2. Get instant step-by-step guidance<br>
409
- 3. Follow instructions carefully<br>
410
- 4. Seek professional help for serious emergencies
411
- </div>
412
- """, unsafe_allow_html=True)
413
 
414
- # Footer
415
- st.markdown("---")
416
- st.markdown("""
417
- <div style="text-align: center; opacity: 0.7; padding: 1rem;">
418
- πŸ€– First Aid Emergency Assistant | Powered by GROQ AI | Always consult medical professionals for serious emergencies
419
- </div>
420
- """, unsafe_allow_html=True)
 
1
+ # --- Imports ---
2
  import streamlit as st
3
  import PyPDF2
4
  import requests
 
6
  from sentence_transformers import SentenceTransformer
7
  import numpy as np
8
  from sklearn.metrics.pairwise import cosine_similarity
 
9
  from datetime import datetime
10
+ from groq import Groq
11
 
12
+ # --- Page config ---
13
  st.set_page_config(
14
  page_title="🚨 First Aid Emergency Assistant",
15
  page_icon="🚨",
 
17
  initial_sidebar_state="collapsed"
18
  )
19
 
20
+ # --- UI CSS Styling ---
21
+ st.markdown("""<style>/* [CSS OMITTED FOR BREVITY] */</style>""", unsafe_allow_html=True) # Insert the full CSS here as in your version
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
+ # --- GROQ API setup ---
24
+ @st.cache_resource
25
+ def setup_groq():
26
+ try:
27
+ return st.secrets["GROQ_API_KEY"]
28
+ except:
29
+ st.error("❌ Missing GROQ_API_KEY in `.streamlit/secrets.toml`")
30
+ st.stop()
31
 
32
+ client = Groq(api_key=setup_groq())
33
 
34
+ # --- PDF Processing ---
35
  @st.cache_resource
36
  def load_pdf():
37
  try:
38
+ with open("First-Aid.pdf", "rb") as f:
39
+ reader = PyPDF2.PdfReader(f)
40
+ text = "".join(page.extract_text() + "\n" for page in reader.pages)
41
+ return text
42
+ except:
43
+ st.error("❌ Failed to load 'First-Aid.pdf'. Upload it to the app root.")
 
 
 
 
 
44
  st.stop()
45
 
46
+ # --- Knowledge Base Setup ---
47
  @st.cache_resource
48
  def setup_knowledge_base():
49
+ text = load_pdf()
50
+ chunks, current_chunk = [], ""
51
+ for sentence in text.split('\n'):
 
 
 
 
 
 
52
  if len(current_chunk + sentence) < 1000:
53
  current_chunk += sentence + "\n"
54
  else:
55
+ if current_chunk.strip(): chunks.append(current_chunk.strip())
 
56
  current_chunk = sentence + "\n"
57
+ if current_chunk.strip(): chunks.append(current_chunk.strip())
 
 
 
 
58
  model = SentenceTransformer('all-MiniLM-L6-v2')
59
+ embeddings = model.encode(chunks)
60
+ return chunks, embeddings, model
 
 
 
61
 
62
+ # --- Context Matching ---
63
+ def find_relevant_context(query, chunks, embeddings, model, top_k=3):
64
  query_embedding = model.encode([query])
65
+ similarities = cosine_similarity(query_embedding, embeddings)[0]
66
  top_indices = np.argsort(similarities)[-top_k:][::-1]
67
+ return "\n\n".join([chunks[i] for i in top_indices])
 
 
68
 
69
+ # --- Query GROQ ---
70
  def query_groq(prompt, api_key):
 
71
  url = "https://api.groq.com/openai/v1/chat/completions"
72
+ headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
 
 
 
 
 
73
  data = {
74
+ "model": "llama3-70b-8192",
75
  "messages": [
76
  {
77
  "role": "system",
78
+ "content": """You are a First Aid Emergency Assistant. Answer only first aid-related queries. Be clear, concise, and step-by-step. For serious emergencies, advise calling 911. If asked off-topic, respond with: "🚨 I'm specialized in First Aid emergencies only!"."""
 
 
 
 
 
 
 
 
 
 
79
  },
80
+ {"role": "user", "content": prompt}
 
 
 
81
  ],
82
  "temperature": 0.3,
83
  "max_tokens": 1000
84
  }
 
85
  try:
86
+ r = requests.post(url, headers=headers, json=data, timeout=30)
87
+ r.raise_for_status()
88
+ return r.json()["choices"][0]["message"]["content"]
 
 
89
  except Exception as e:
90
+ return f"❌ GROQ API Error: {str(e)}"
91
 
92
+ # --- Session State ---
93
  if "messages" not in st.session_state:
94
+ st.session_state.messages = [{
95
+ "role": "assistant",
96
+ "content": "🚨 **Hello! I'm your First Aid Emergency Assistant.**\n\nAsk me about CPR, bleeding, choking, burns, or any first aid emergency."
97
+ }]
 
 
98
 
99
  if "knowledge_base" not in st.session_state:
100
+ with st.spinner("Loading knowledge base..."):
101
  chunks, embeddings, model = setup_knowledge_base()
102
  st.session_state.knowledge_base = {
103
+ "chunks": chunks, "embeddings": embeddings, "model": model
 
 
104
  }
105
 
106
+ # --- Chat UI ---
107
+ st.markdown('<div class="main-header"><h1>🚨 First Aid Emergency Assistant</h1></div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
108
 
109
+ # Disclaimer
110
  st.markdown("""
111
  <div class="warning-box">
112
+ <strong>⚠️ MEDICAL DISCLAIMER:</strong><br>
113
+ This tool is for informational purposes only. Always call emergency services in real situations.
 
114
  </div>
115
  """, unsafe_allow_html=True)
116
 
117
+ # Chat display
118
+ with st.container():
 
 
119
  st.markdown('<div class="chat-container">', unsafe_allow_html=True)
120
+ for msg in st.session_state.messages:
121
+ if msg["role"] == "user":
122
+ st.markdown(f'<div class="user-message"><strong>You:</strong> {msg["content"]}</div><div style="clear: both;"></div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
123
  else:
124
+ st.markdown(f'<div class="bot-message"><strong>πŸ€– Assistant:</strong><br>{msg["content"]}</div><div style="clear: both;"></div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
125
  st.markdown('</div>', unsafe_allow_html=True)
126
 
127
+ # Input UI
128
  st.markdown('<div class="input-container">', unsafe_allow_html=True)
 
129
  col1, col2 = st.columns([4, 1])
 
130
  with col1:
131
+ user_input = st.text_input("", placeholder="Ask about a first aid emergency...", key="user_input", label_visibility="collapsed")
 
 
 
 
 
 
132
  with col2:
133
+ send = st.button("Send πŸš€", key="send_button")
 
134
  st.markdown('</div>', unsafe_allow_html=True)
135
 
136
+ # Process Input
137
+ if send and user_input.strip():
 
138
  st.session_state.messages.append({"role": "user", "content": user_input})
139
+ with st.spinner("πŸ€– Thinking..."):
140
+ kb = st.session_state.knowledge_base
141
+ context = find_relevant_context(user_input, kb["chunks"], kb["embeddings"], kb["model"])
142
+ full_prompt = f"""
143
+ Based on this manual content, answer the question: {user_input}
144
+ Context:
 
 
 
 
 
 
 
 
 
 
 
 
145
  {context}
 
 
146
  """
147
+ response = query_groq(full_prompt, setup_groq())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
 
149
+ if any(x in user_input.lower() for x in ["heart attack", "stroke", "not breathing", "unconscious", "severe bleeding"]):
150
+ response = f"🚨 **CALL EMERGENCY SERVICES IMMEDIATELY!**\n\n{response}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
 
152
+ st.session_state.messages.append({"role": "assistant", "content": response})
153
+ st.rerun()