rajkhanke commited on
Commit
c983344
·
verified ·
1 Parent(s): abe16b7

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +433 -0
app.py ADDED
@@ -0,0 +1,433 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, render_template, request, jsonify, session, redirect, url_for, send_file
2
+ import google.generativeai as genai
3
+ import PyPDF2
4
+ import os
5
+ import re
6
+ import io
7
+ from datetime import datetime
8
+ from twilio.rest import Client
9
+ from reportlab.lib.pagesizes import letter
10
+ from reportlab.lib import colors
11
+ from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
12
+ from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image, ListItem, ListFlowable
13
+ from reportlab.lib.units import inch
14
+ from reportlab.lib.enums import TA_CENTER, TA_JUSTIFY
15
+
16
+ app = Flask(__name__)
17
+
18
+ app.secret_key = '688ed745a74bdd7ac238f5b50f4104fb87d6774b8b0a4e06e7e18ac5ed0fa31c' # Add this for session management
19
+ upload_base = os.getenv('UPLOAD_DIR', 'static')
20
+ upload_folder = os.path.join(upload_base, 'uploads')
21
+ pdf_folder = os.path.join(upload_base, 'pdfs')
22
+
23
+ app.config['UPLOAD_FOLDER'] = upload_folder
24
+ app.config['PDF_FOLDER'] = pdf_folder
25
+ os.makedirs(upload_folder, exist_ok=True)
26
+ os.makedirs(pdf_folder, exist_ok=True)
27
+
28
+ # Gemini API Configuration
29
+ genai.configure(api_key="AIzaSyCizcswP6vlKDMdB3HRAtVi2JbifOpbPvA")
30
+
31
+ generation_config = {
32
+ "temperature": 1,
33
+ "top_p": 0.95,
34
+ "top_k": 40,
35
+ "max_output_tokens": 8192,
36
+ }
37
+
38
+ model = genai.GenerativeModel(
39
+ model_name="gemini-2.0-flash",
40
+ generation_config=generation_config,
41
+ )
42
+
43
+ # Twilio Configuration
44
+ ACCOUNT_SID = 'AC490e071f8d01bf0df2f03d086c788d87'
45
+ AUTH_TOKEN = '224b23b950ad5a4052aba15893fdf083'
46
+ TWILIO_FROM = 'whatsapp:+14155238886'
47
+
48
+ def extract_text_from_pdf(pdf_file):
49
+ try:
50
+ pdf_reader = PyPDF2.PdfReader(pdf_file)
51
+ text = ""
52
+ for page in pdf_reader.pages:
53
+ text += page.extract_text()
54
+ return text.strip()
55
+ except Exception as e:
56
+ print(f"Error extracting PDF text: {e}")
57
+ return ""
58
+
59
+ def extract_care_plan_format(pdf_text):
60
+ """Extract the care plan format from PDF text"""
61
+ try:
62
+ # Find sections and their content in the PDF using regex
63
+ sections = re.findall(
64
+ r'([A-Z][A-Z\s]+)[:|\n]((?:(?!\n[A-Z][A-Z\s]+[:|\n]).)*)',
65
+ pdf_text,
66
+ re.DOTALL
67
+ )
68
+
69
+ if sections:
70
+ format_template = ""
71
+ for section, content in sections:
72
+ format_template += f"{section.strip()}:\n"
73
+ # Extract bullet points if they exist and remove any asterisks
74
+ bullets = re.findall(r'[-•*]\s*(.*?)(?=[-•*]|\n|$)', content)
75
+ if bullets:
76
+ for bullet in bullets:
77
+ format_template += f"- {bullet.strip()}\n"
78
+ format_template += "\n"
79
+ return format_template
80
+ return None
81
+ except Exception as e:
82
+ print(f"Error extracting format: {e}")
83
+ return None
84
+
85
+ def create_care_plan_pdf(care_plan_text, patient_name="Patient"):
86
+ """Generate a beautifully formatted PDF with the care plan"""
87
+ buffer = io.BytesIO()
88
+ doc = SimpleDocTemplate(buffer, pagesize=letter)
89
+ styles = getSampleStyleSheet()
90
+
91
+ # Create custom styles
92
+ styles.add(ParagraphStyle(
93
+ name='Title',
94
+ parent=styles['Heading1'],
95
+ fontSize=18,
96
+ alignment=TA_CENTER,
97
+ spaceAfter=20,
98
+ textColor=colors.HexColor('#0d6efd')
99
+ ))
100
+
101
+ styles.add(ParagraphStyle(
102
+ name='SectionHeading',
103
+ parent=styles['Heading2'],
104
+ fontSize=14,
105
+ spaceAfter=6,
106
+ spaceBefore=12,
107
+ textColor=colors.HexColor('#0a58ca')
108
+ ))
109
+
110
+ styles.add(ParagraphStyle(
111
+ name='BodyText',
112
+ parent=styles['Normal'],
113
+ fontSize=11,
114
+ alignment=TA_JUSTIFY,
115
+ spaceBefore=2,
116
+ spaceAfter=2
117
+ ))
118
+
119
+ # Add logo path or use a placeholder
120
+ # logo_path = os.path.join("static", "images", "logo.png")
121
+
122
+ # Create story elements
123
+ story = []
124
+
125
+ # Add title
126
+ timestamp = datetime.now().strftime("%B %d, %Y")
127
+ title = Paragraph(f"UPDATED CARE PLAN<br/><br/>{timestamp}", styles["Title"])
128
+ story.append(title)
129
+ story.append(Spacer(1, 0.25*inch))
130
+
131
+ # Patient name
132
+ patient_info = Paragraph(f"<b>Patient:</b> {patient_name}", styles["BodyText"])
133
+ story.append(patient_info)
134
+ story.append(Spacer(1, 0.15*inch))
135
+
136
+ # Process care plan sections
137
+ sections = care_plan_text.split("\n\n")
138
+ for section in sections:
139
+ if not section.strip():
140
+ continue
141
+
142
+ lines = section.strip().split("\n")
143
+ if not lines:
144
+ continue
145
+
146
+ # Add section heading
147
+ heading_line = lines[0].strip()
148
+ if ":" in heading_line:
149
+ heading = heading_line.split(":", 1)[0].strip()
150
+ story.append(Paragraph(heading, styles["SectionHeading"]))
151
+
152
+ # Process bullet points and content
153
+ content_lines = lines[1:] if len(lines) > 1 else []
154
+ bullet_items = []
155
+ normal_text = ""
156
+
157
+ for line in content_lines:
158
+ line = line.strip()
159
+ if line.startswith("-") or line.startswith("•"):
160
+ bullet_text = line[1:].strip()
161
+ bullet_items.append(ListItem(Paragraph(bullet_text, styles["BodyText"])))
162
+ else:
163
+ normal_text += line + " "
164
+
165
+ # Add normal text if present
166
+ if normal_text:
167
+ story.append(Paragraph(normal_text, styles["BodyText"]))
168
+
169
+ # Add bullet points if present
170
+ if bullet_items:
171
+ bullet_list = ListFlowable(
172
+ bullet_items,
173
+ bulletType='bullet',
174
+ start=None,
175
+ bulletFontName='Helvetica',
176
+ bulletFontSize=11,
177
+ leftIndent=20,
178
+ bulletOffsetY=0
179
+ )
180
+ story.append(bullet_list)
181
+
182
+ story.append(Spacer(1, 0.1*inch))
183
+
184
+ # Add footer
185
+ footer_text = """This care plan has been automatically generated based on your feedback. Please consult with your healthcare provider before making any changes to your current treatment plan."""
186
+ footer = Paragraph(f"<i>{footer_text}</i>", styles["BodyText"])
187
+ story.append(Spacer(1, 0.25*inch))
188
+ story.append(footer)
189
+
190
+ # Build PDF
191
+ doc.build(story)
192
+ buffer.seek(0)
193
+ return buffer
194
+
195
+ def send_whatsapp_message(message, recipient, pdf_data=None, pdf_name=None):
196
+ """
197
+ Sends a WhatsApp message using Twilio.
198
+ If pdf_data is provided, it attaches the PDF to the message.
199
+ """
200
+ try:
201
+ client = Client(ACCOUNT_SID, AUTH_TOKEN)
202
+
203
+ # Check if recipient needs WhatsApp prefix
204
+ if not recipient.startswith('whatsapp:'):
205
+ recipient = f'whatsapp:{recipient}'
206
+
207
+ message_params = {
208
+ 'from_': TWILIO_FROM,
209
+ 'body': message,
210
+ 'to': recipient
211
+ }
212
+
213
+ # If we have a PDF to send, attach it
214
+ if pdf_data and pdf_name:
215
+ # Create a temporary file
216
+ temp_pdf_path = os.path.join(app.config['PDF_FOLDER'], pdf_name)
217
+ with open(temp_pdf_path, 'wb') as f:
218
+ f.write(pdf_data.getvalue())
219
+
220
+ # Add media URL (would be your app's URL in production)
221
+ media_url = f'https://your-app-domain.com/static/pdfs/{pdf_name}'
222
+
223
+ # In development, use a public URL service like ngrok
224
+ # or just mention that we'd need a public URL in production
225
+ # For now, we'll just send the message without the attachment
226
+ message_params['body'] += "\n\nYour care plan PDF has been generated and would normally be attached here. Due to development environment limitations, please view it in the web interface."
227
+
228
+ msg = client.messages.create(**message_params)
229
+ return {
230
+ 'success': True,
231
+ 'sid': msg.sid
232
+ }
233
+ except Exception as e:
234
+ print(f"Error sending WhatsApp message: {e}")
235
+ return {
236
+ 'success': False,
237
+ 'error': str(e)
238
+ }
239
+
240
+ @app.route('/')
241
+ def index():
242
+ return render_template('index.html')
243
+
244
+ @app.route('/switch_role', methods=['POST'])
245
+ def switch_role():
246
+ role = request.form.get('role')
247
+ session['role'] = role
248
+ return jsonify({'success': True, 'role': role})
249
+
250
+ @app.route('/doctor_dashboard')
251
+ def doctor_dashboard():
252
+ if session.get('role') != 'doctor':
253
+ return redirect('/')
254
+ return render_template('doctor_dashboard.html')
255
+
256
+ @app.route('/download_pdf/<filename>')
257
+ def download_pdf(filename):
258
+ try:
259
+ return send_file(
260
+ os.path.join(app.config['PDF_FOLDER'], filename),
261
+ as_attachment=True,
262
+ download_name=filename
263
+ )
264
+ except Exception as e:
265
+ return jsonify({'success': False, 'error': str(e)})
266
+
267
+ @app.route('/submit_feedback', methods=['POST'])
268
+ def submit_feedback():
269
+ try:
270
+ feedback = request.form.get('feedback', '')
271
+ patient_name = request.form.get('patient_name', 'Patient')
272
+ patient_phone = request.form.get('patient_phone', '')
273
+ care_plan_text = ""
274
+ care_plan_format = None
275
+
276
+ if 'care_plan_pdf' in request.files:
277
+ pdf_file = request.files['care_plan_pdf']
278
+ if pdf_file.filename != '':
279
+ care_plan_text = extract_text_from_pdf(pdf_file)
280
+ care_plan_format = extract_care_plan_format(care_plan_text)
281
+
282
+ # If no format is found in the PDF, use a default format
283
+ if not care_plan_format:
284
+ care_plan_format = """
285
+ ASSESSMENT:
286
+ [Assessment details]
287
+
288
+ DAILY CARE PLAN:
289
+ Morning:
290
+ - [Morning activities]
291
+ Afternoon:
292
+ - [Afternoon activities]
293
+ Evening:
294
+ - [Evening activities]
295
+
296
+ MEDICATIONS:
297
+ - [Medication details]
298
+
299
+ ADDITIONAL RECOMMENDATIONS:
300
+ - [Recommendations]
301
+
302
+ FOLLOW-UP:
303
+ [Follow-up details]
304
+ """
305
+
306
+ # Define emergency keywords to check for severe symptoms
307
+ emergency_keywords = [
308
+ # Cardiovascular
309
+ "severe chest pain", "heart attack", "shortness of breath",
310
+ "dizziness", "loss of consciousness", "extreme pain",
311
+
312
+ # Neurological
313
+ "sudden weakness", "confusion", "slurred speech", "severe headache",
314
+
315
+ # Respiratory
316
+ "difficulty breathing", "severe shortness of breath", "wheezing", "respiratory distress",
317
+
318
+ # Gastrointestinal
319
+ "severe abdominal pain", "persistent vomiting", "uncontrolled bleeding",
320
+
321
+ # Others
322
+ "severe allergic reaction", "anaphylaxis"
323
+ ]
324
+
325
+ feedback_lower = feedback.lower()
326
+ is_emergency = any(keyword in feedback_lower for keyword in emergency_keywords)
327
+
328
+ if is_emergency:
329
+ # Store emergency notification
330
+ emergency_data = {
331
+ 'patient_name': patient_name,
332
+ 'patient_phone': patient_phone,
333
+ 'patient_feedback': feedback,
334
+ 'timestamp': datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
335
+ 'status': 'urgent'
336
+ }
337
+
338
+ # In a real application, you would store this in a database
339
+ # For now, we'll use a global variable (not recommended for production)
340
+ if not hasattr(app, 'emergency_notifications'):
341
+ app.emergency_notifications = []
342
+ app.emergency_notifications.append(emergency_data)
343
+
344
+ # If emergency symptoms are detected, instruct immediate emergency response
345
+ emergency_message = (
346
+ "Emergency symptoms detected. Please call emergency services immediately at 104/108/109/112."
347
+ )
348
+
349
+ # Send emergency message to patient if phone number is provided
350
+ if patient_phone:
351
+ send_whatsapp_message(
352
+ message=emergency_message,
353
+ recipient=patient_phone
354
+ )
355
+
356
+ return jsonify({
357
+ 'success': True,
358
+ 'is_emergency': True,
359
+ 'updated_plan': emergency_message
360
+ })
361
+
362
+ # Prepare a prompt for Gemini AI for a perfect, attractively formatted day care plan.
363
+ prompt = f"""
364
+ Patient Care Plan Update Request:
365
+ Patient Name: {patient_name}
366
+ Current Symptoms and Feedback: {feedback}
367
+ Current Care Plan (extracted from PDF): {care_plan_text}
368
+ Based on the patient's feedback and current care plan, please provide an updated, perfect daily care plan in the exact following format:
369
+ {care_plan_format}
370
+ Please ensure the following:
371
+ - The response is well-structured with clear section headings.
372
+ - Use bullet points for list items without including any asterisk (*) symbols.
373
+ - Format the text attractively and professionally.
374
+ - Remove any extraneous symbols.
375
+ """
376
+ # Get response from Gemini AI
377
+ response = model.generate_content(prompt)
378
+ # Remove any asterisk symbols from the response text
379
+ updated_plan = response.text.replace("*", "")
380
+
381
+ # Generate PDF
382
+ pdf_buffer = create_care_plan_pdf(updated_plan, patient_name)
383
+
384
+ # Save the PDF to file system with a unique name
385
+ timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
386
+ safe_name = re.sub(r'[^a-zA-Z0-9]', '_', patient_name)
387
+ pdf_filename = f"care_plan_{safe_name}_{timestamp}.pdf"
388
+ pdf_path = os.path.join(app.config['PDF_FOLDER'], pdf_filename)
389
+
390
+ with open(pdf_path, 'wb') as f:
391
+ f.write(pdf_buffer.getvalue())
392
+
393
+ # Reset the buffer pointer for potential reuse
394
+ pdf_buffer.seek(0)
395
+
396
+ # Send WhatsApp message with PDF if phone number is provided
397
+ message_result = None
398
+ if patient_phone:
399
+ message_result = send_whatsapp_message(
400
+ message=f"Hello {patient_name}, your updated care plan is ready. Please review it and contact your healthcare provider if you have any questions.",
401
+ recipient=patient_phone,
402
+ pdf_data=pdf_buffer,
403
+ pdf_name=pdf_filename
404
+ )
405
+
406
+ return jsonify({
407
+ 'success': True,
408
+ 'updated_plan': updated_plan,
409
+ 'pdf_filename': pdf_filename,
410
+ 'message_sent': message_result['success'] if message_result else False,
411
+ 'is_emergency': False
412
+ })
413
+
414
+ except Exception as e:
415
+ import traceback
416
+ traceback.print_exc()
417
+ return jsonify({
418
+ 'success': False,
419
+ 'error': str(e)
420
+ })
421
+
422
+
423
+ @app.route('/get_emergency_notifications')
424
+ def get_emergency_notifications():
425
+ if session.get('role') != 'doctor':
426
+ return jsonify({'success': False, 'error': 'Unauthorized'})
427
+
428
+ notifications = getattr(app, 'emergency_notifications', [])
429
+ return jsonify({'success': True, 'notifications': notifications})
430
+
431
+
432
+ if __name__ == '__main__':
433
+ app.run(debug=True)