SuriRaja commited on
Commit
fc02113
·
verified ·
1 Parent(s): 7137a38

Update routes.py

Browse files
Files changed (1) hide show
  1. routes.py +16 -596
routes.py CHANGED
@@ -1,6 +1,3 @@
1
- import os
2
- import json
3
- from datetime import datetime, date, timedelta
4
  from flask import render_template, request, redirect, url_for, flash, jsonify, send_from_directory
5
  from flask_login import login_user, logout_user, login_required, current_user
6
  from werkzeug.security import check_password_hash, generate_password_hash
@@ -10,616 +7,39 @@ from models import *
10
  from forms import *
11
  from utils import generate_treatment_pdf, allowed_file, save_uploaded_image
12
  from ai_services import medical_ai
 
 
 
 
 
 
 
 
 
13
 
 
14
  @app.route('/dashboard')
15
  @login_required
16
  def dashboard():
17
- # Get dashboard statistics
18
  total_patients = Patient.query.count()
19
  today_visits = Visit.query.filter(Visit.visit_date >= date.today()).count()
20
-
21
- # Get recent patients
22
  recent_patients = Patient.query.order_by(Patient.last_visit.desc().nullslast()).limit(6).all()
23
-
24
- # Get upcoming follow-ups
25
  upcoming_followups = Visit.query.filter(
26
  Visit.follow_up_date >= date.today(),
27
  Visit.follow_up_date <= date.today() + timedelta(days=7)
28
  ).limit(5).all()
29
-
30
- # Get low stock items
31
  low_stock_items = Inventory.query.filter(
32
  Inventory.current_stock <= Inventory.min_threshold
33
  ).limit(5).all()
34
-
35
- # Get user preferences for briefing
36
  preferences = current_user.briefing_preferences
37
  if not preferences:
38
  preferences = BriefingPreference(user_id=current_user.id)
39
  db.session.add(preferences)
40
  db.session.commit()
41
-
42
  return render_template('dashboard.html',
43
- total_patients=total_patients,
44
- today_visits=today_visits,
45
- recent_patients=recent_patients,
46
- upcoming_followups=upcoming_followups,
47
- low_stock_items=low_stock_items,
48
- preferences=preferences)
49
-
50
- @app.route('/login', methods=['GET', 'POST'])
51
- def login():
52
- if current_user.is_authenticated:
53
- return redirect(url_for('dashboard'))
54
-
55
- form = LoginForm()
56
- if form.validate_on_submit():
57
- user = User.query.filter_by(username=form.username.data).first()
58
- if user and check_password_hash(user.password_hash, form.password.data):
59
- login_user(user)
60
- next_page = request.args.get('next')
61
- return redirect(next_page) if next_page else redirect(url_for('dashboard'))
62
- flash('Invalid username or password', 'danger')
63
-
64
- return render_template('login.html', form=form)
65
-
66
- @app.route('/logout')
67
- @login_required
68
- def logout():
69
- logout_user()
70
- return redirect(url_for('login'))
71
-
72
- @app.route('/patients')
73
- @login_required
74
- def patients():
75
- search = request.args.get('search', '')
76
- page = request.args.get('page', 1, type=int)
77
-
78
- query = Patient.query
79
- if search:
80
- query = query.filter(
81
- db.or_(
82
- Patient.first_name.contains(search),
83
- Patient.last_name.contains(search),
84
- Patient.patient_id.contains(search)
85
- )
86
- )
87
-
88
- patients = query.order_by(Patient.last_name, Patient.first_name).paginate(
89
- page=page, per_page=20, error_out=False
90
- )
91
-
92
- return render_template('patients.html', patients=patients, search=search)
93
-
94
- @app.route('/patients/new', methods=['GET', 'POST'])
95
- @login_required
96
- def new_patient():
97
- form = PatientForm()
98
- if form.validate_on_submit():
99
- # Generate patient ID
100
- latest_patient = Patient.query.order_by(Patient.id.desc()).first()
101
- patient_id = f"P{(latest_patient.id + 1):06d}" if latest_patient else "P000001"
102
-
103
- patient = Patient(
104
- patient_id=patient_id,
105
- first_name=form.first_name.data,
106
- last_name=form.last_name.data,
107
- date_of_birth=form.date_of_birth.data,
108
- gender=form.gender.data,
109
- phone=form.phone.data,
110
- email=form.email.data,
111
- address=form.address.data,
112
- emergency_contact=form.emergency_contact.data,
113
- emergency_phone=form.emergency_phone.data,
114
- allergies=form.allergies.data,
115
- medical_history=form.medical_history.data,
116
- insurance_info=form.insurance_info.data,
117
- doctor_id=current_user.id
118
- )
119
-
120
- db.session.add(patient)
121
- db.session.commit()
122
- flash(f'Patient {patient.full_name} added successfully!', 'success')
123
- return redirect(url_for('patient_detail', id=patient.id))
124
-
125
- return render_template('patient_detail.html', form=form, patient=None, is_new=True)
126
-
127
- @app.route('/patients/<int:id>')
128
- @login_required
129
- def patient_detail(id):
130
- patient = Patient.query.get_or_404(id)
131
- visits = patient.visits.order_by(Visit.visit_date.desc()).all()
132
- images = patient.images.order_by(PatientImage.upload_date.desc()).all()
133
- treatment_plans = patient.treatment_plans.order_by(TreatmentPlan.created_at.desc()).all()
134
-
135
- # Forms for adding new data
136
- visit_form = VisitForm()
137
- note_form = VisitNoteForm()
138
- image_form = ImageUploadForm()
139
-
140
- return render_template('patient_detail.html',
141
- patient=patient,
142
- visits=visits,
143
- images=images,
144
- treatment_plans=treatment_plans,
145
- visit_form=visit_form,
146
- note_form=note_form,
147
- image_form=image_form,
148
- is_new=False)
149
-
150
- @app.route('/patients/<int:id>/edit', methods=['GET', 'POST'])
151
- @login_required
152
- def edit_patient(id):
153
- patient = Patient.query.get_or_404(id)
154
- form = PatientForm(obj=patient)
155
-
156
- if form.validate_on_submit():
157
- form.populate_obj(patient)
158
- db.session.commit()
159
- flash(f'Patient {patient.full_name} updated successfully!', 'success')
160
- return redirect(url_for('patient_detail', id=patient.id))
161
-
162
- return render_template('patient_detail.html', form=form, patient=patient, is_edit=True)
163
-
164
- @app.route('/patients/<int:patient_id>/visits/new', methods=['POST'])
165
- @login_required
166
- def new_visit(patient_id):
167
- patient = Patient.query.get_or_404(patient_id)
168
- form = VisitForm()
169
-
170
- if form.validate_on_submit():
171
- visit = Visit(
172
- patient_id=patient.id,
173
- visit_type=form.visit_type.data,
174
- chief_complaint=form.chief_complaint.data,
175
- diagnosis=form.diagnosis.data,
176
- treatment_notes=form.treatment_notes.data,
177
- follow_up_date=form.follow_up_date.data
178
- )
179
-
180
- db.session.add(visit)
181
- patient.last_visit = datetime.utcnow()
182
- db.session.commit()
183
- flash('Visit added successfully!', 'success')
184
- else:
185
- for field, errors in form.errors.items():
186
- for error in errors:
187
- flash(f'{field}: {error}', 'danger')
188
-
189
- return redirect(url_for('patient_detail', id=patient_id))
190
-
191
- @app.route('/visits/<int:visit_id>/notes/new', methods=['POST'])
192
- @login_required
193
- def new_visit_note(visit_id):
194
- visit = Visit.query.get_or_404(visit_id)
195
- form = VisitNoteForm()
196
-
197
- if form.validate_on_submit():
198
- note = VisitNote(
199
- visit_id=visit.id,
200
- author_id=current_user.id,
201
- content=form.content.data,
202
- note_type=form.note_type.data
203
- )
204
-
205
- db.session.add(note)
206
- db.session.commit()
207
- flash('Note added successfully!', 'success')
208
- else:
209
- for field, errors in form.errors.items():
210
- for error in errors:
211
- flash(f'{field}: {error}', 'danger')
212
-
213
- return redirect(url_for('patient_detail', id=visit.patient_id))
214
-
215
- @app.route('/patients/<int:patient_id>/images/upload', methods=['POST'])
216
- @login_required
217
- def upload_image(patient_id):
218
- patient = Patient.query.get_or_404(patient_id)
219
- form = ImageUploadForm()
220
-
221
- if form.validate_on_submit():
222
- file = form.image.data
223
- if file and allowed_file(file.filename):
224
- filename = save_uploaded_image(file)
225
-
226
- image = PatientImage(
227
- patient_id=patient.id,
228
- filename=filename,
229
- original_filename=file.filename,
230
- description=form.description.data,
231
- body_location=form.body_location.data,
232
- image_type=form.image_type.data,
233
- uploaded_by_id=current_user.id
234
- )
235
-
236
- db.session.add(image)
237
- db.session.commit()
238
- flash('Image uploaded successfully!', 'success')
239
- else:
240
- flash('Invalid file type. Please upload an image.', 'danger')
241
- else:
242
- for field, errors in form.errors.items():
243
- for error in errors:
244
- flash(f'{field}: {error}', 'danger')
245
-
246
- return redirect(url_for('patient_detail', id=patient_id))
247
-
248
- @app.route('/uploads/<filename>')
249
- @login_required
250
- def uploaded_file(filename):
251
- return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
252
-
253
- @app.route('/treatment-planner')
254
- @login_required
255
- def treatment_planner():
256
- patients = Patient.query.order_by(Patient.last_name, Patient.first_name).all()
257
- conditions = Condition.query.order_by(Condition.name).all()
258
- templates = TreatmentTemplate.query.filter_by(is_active=True).order_by(TreatmentTemplate.name).all()
259
-
260
- return render_template('treatment_planner.html',
261
- patients=patients,
262
- conditions=conditions,
263
- templates=templates)
264
-
265
- @app.route('/treatment-plans/new', methods=['POST'])
266
- @login_required
267
- def new_treatment_plan():
268
- form = TreatmentPlanForm()
269
- patient_id = request.form.get('patient_id', type=int)
270
- template_id = request.form.get('template_id', type=int)
271
-
272
- if form.validate_on_submit() and patient_id:
273
- treatment_plan = TreatmentPlan(
274
- patient_id=patient_id,
275
- diagnosis=form.diagnosis.data,
276
- medications=form.medications.data,
277
- instructions=form.instructions.data,
278
- duration=form.duration.data,
279
- follow_up_date=form.follow_up_date.data,
280
- notes=form.notes.data,
281
- created_by_id=current_user.id,
282
- template_id=template_id if template_id else None
283
- )
284
-
285
- db.session.add(treatment_plan)
286
- db.session.commit()
287
- flash('Treatment plan created successfully!', 'success')
288
- return redirect(url_for('patient_detail', id=patient_id))
289
- else:
290
- flash('Please fill in all required fields.', 'danger')
291
-
292
- return redirect(url_for('treatment_planner'))
293
-
294
- @app.route('/treatment-plans/<int:id>/pdf')
295
- @login_required
296
- def treatment_plan_pdf(id):
297
- treatment_plan = TreatmentPlan.query.get_or_404(id)
298
- return generate_treatment_pdf(treatment_plan)
299
-
300
- @app.route('/api/templates/<int:condition_id>')
301
- @login_required
302
- def get_templates_by_condition(condition_id):
303
- templates = TreatmentTemplate.query.filter_by(
304
- condition_id=condition_id,
305
- is_active=True
306
- ).all()
307
-
308
- return jsonify([{
309
- 'id': t.id,
310
- 'name': t.name,
311
- 'medications': t.medications,
312
- 'instructions': t.instructions,
313
- 'duration': t.duration,
314
- 'follow_up_weeks': t.follow_up_weeks
315
- } for t in templates])
316
-
317
- @app.route('/admin')
318
- @login_required
319
- def admin():
320
- if current_user.role.name != 'Admin':
321
- flash('Access denied. Admin privileges required.', 'danger')
322
- return redirect(url_for('dashboard'))
323
-
324
- # Get statistics for admin dashboard
325
- total_users = User.query.count()
326
- total_patients = Patient.query.count()
327
- total_visits = Visit.query.count()
328
- low_stock_count = Inventory.query.filter(
329
- Inventory.current_stock <= Inventory.min_threshold
330
- ).count()
331
-
332
- return render_template('admin.html',
333
- total_users=total_users,
334
- total_patients=total_patients,
335
- total_visits=total_visits,
336
- low_stock_count=low_stock_count)
337
-
338
- @app.route('/admin/users')
339
- @login_required
340
- def admin_users():
341
- if current_user.role.name != 'Admin':
342
- flash('Access denied. Admin privileges required.', 'danger')
343
- return redirect(url_for('dashboard'))
344
-
345
- users = User.query.order_by(User.last_name, User.first_name).all()
346
- return render_template('admin.html', section='users', users=users)
347
-
348
- @app.route('/admin/inventory')
349
- @login_required
350
- def admin_inventory():
351
- if current_user.role.name != 'Admin':
352
- flash('Access denied. Admin privileges required.', 'danger')
353
- return redirect(url_for('dashboard'))
354
-
355
- inventory = Inventory.query.order_by(Inventory.item_name).all()
356
- form = InventoryForm()
357
- return render_template('admin.html', section='inventory', inventory=inventory, form=form)
358
-
359
- @app.route('/admin/templates')
360
- @login_required
361
- def admin_templates():
362
- if current_user.role.name != 'Admin':
363
- flash('Access denied. Admin privileges required.', 'danger')
364
- return redirect(url_for('dashboard'))
365
-
366
- templates = TreatmentTemplate.query.order_by(TreatmentTemplate.name).all()
367
- conditions = Condition.query.order_by(Condition.name).all()
368
- template_form = TreatmentTemplateForm()
369
- condition_form = ConditionForm()
370
-
371
- # Populate condition choices
372
- template_form.condition_id.choices = [(0, 'Select Condition')] + [(c.id, c.name) for c in conditions]
373
-
374
- return render_template('admin.html',
375
- section='templates',
376
- templates=templates,
377
- conditions=conditions,
378
- template_form=template_form,
379
- condition_form=condition_form)
380
-
381
- @app.route('/admin/inventory/new', methods=['POST'])
382
- @login_required
383
- def new_inventory_item():
384
- if current_user.role.name != 'Admin':
385
- flash('Access denied.', 'danger')
386
- return redirect(url_for('dashboard'))
387
-
388
- form = InventoryForm()
389
- if form.validate_on_submit():
390
- item = Inventory(
391
- item_name=form.item_name.data,
392
- category=form.category.data,
393
- current_stock=form.current_stock.data,
394
- min_threshold=form.min_threshold.data,
395
- unit=form.unit.data,
396
- supplier=form.supplier.data
397
- )
398
-
399
- db.session.add(item)
400
- db.session.commit()
401
- flash('Inventory item added successfully!', 'success')
402
- else:
403
- for field, errors in form.errors.items():
404
- for error in errors:
405
- flash(f'{field}: {error}', 'danger')
406
-
407
- return redirect(url_for('admin_inventory'))
408
-
409
- @app.route('/admin/templates/new', methods=['POST'])
410
- @login_required
411
- def new_treatment_template():
412
- if current_user.role.name != 'Admin':
413
- flash('Access denied.', 'danger')
414
- return redirect(url_for('dashboard'))
415
-
416
- form = TreatmentTemplateForm()
417
- conditions = Condition.query.all()
418
- form.condition_id.choices = [(0, 'Select Condition')] + [(c.id, c.name) for c in conditions]
419
-
420
- if form.validate_on_submit():
421
- template = TreatmentTemplate(
422
- name=form.name.data,
423
- description=form.description.data,
424
- condition_id=form.condition_id.data if form.condition_id.data != 0 else None,
425
- medications=form.medications.data,
426
- instructions=form.instructions.data,
427
- duration=form.duration.data,
428
- follow_up_weeks=form.follow_up_weeks.data
429
- )
430
-
431
- db.session.add(template)
432
- db.session.commit()
433
- flash('Treatment template added successfully!', 'success')
434
- else:
435
- for field, errors in form.errors.items():
436
- for error in errors:
437
- flash(f'{field}: {error}', 'danger')
438
-
439
- return redirect(url_for('admin_templates'))
440
-
441
- @app.route('/admin/conditions/new', methods=['POST'])
442
- @login_required
443
- def new_condition():
444
- if current_user.role.name != 'Admin':
445
- flash('Access denied.', 'danger')
446
- return redirect(url_for('dashboard'))
447
-
448
- form = ConditionForm()
449
- if form.validate_on_submit():
450
- condition = Condition(
451
- name=form.name.data,
452
- description=form.description.data,
453
- icd_code=form.icd_code.data,
454
- category=form.category.data
455
- )
456
-
457
- db.session.add(condition)
458
- db.session.commit()
459
- flash('Condition added successfully!', 'success')
460
- else:
461
- for field, errors in form.errors.items():
462
- for error in errors:
463
- flash(f'{field}: {error}', 'danger')
464
-
465
- return redirect(url_for('admin_templates'))
466
-
467
- @app.route('/ai-assistant')
468
- @login_required
469
- def ai_assistant():
470
- patients = Patient.query.order_by(Patient.last_name, Patient.first_name).all()
471
- return render_template('ai_treatment_assistant.html', patients=patients)
472
-
473
- @app.route('/api/ai/analyze-symptoms', methods=['POST'])
474
- @login_required
475
- def ai_analyze_symptoms():
476
- try:
477
- data = request.get_json()
478
- patient = Patient.query.get_or_404(data['patient_id'])
479
-
480
- # Prepare patient data for AI analysis
481
- patient_data = {
482
- 'age': patient.age,
483
- 'gender': patient.gender or 'Not specified',
484
- 'medical_history': patient.medical_history or 'None provided',
485
- 'allergies': patient.allergies or 'None known',
486
- 'current_medications': 'To be assessed' # Could be enhanced with medication tracking
487
- }
488
-
489
- # Get AI recommendations
490
- treatment_plan = medical_ai.generate_treatment_plan(
491
- patient_data,
492
- data['symptoms'],
493
- data.get('suspected_diagnosis')
494
- )
495
-
496
- differential_diagnosis = medical_ai.suggest_differential_diagnosis(
497
- data['symptoms'],
498
- patient.age,
499
- patient.medical_history or ''
500
- )
501
-
502
- # Check for drug interactions if medications are mentioned
503
- medications = []
504
- if 'medications' in treatment_plan:
505
- # Extract medication names from the treatment plan
506
- # This is a simplified extraction - could be enhanced with NLP
507
- medications = [med.strip() for med in str(treatment_plan.get('medications', '')).split('\n') if med.strip()]
508
-
509
- drug_interactions = medical_ai.check_drug_interactions(medications, patient.allergies or '')
510
-
511
- # Generate patient education
512
- patient_education = medical_ai.generate_patient_education(
513
- data.get('suspected_diagnosis', 'General condition'),
514
- str(treatment_plan.get('medications', ''))
515
- )
516
-
517
- return jsonify({
518
- 'success': True,
519
- 'treatment_plan': treatment_plan,
520
- 'differential_diagnosis': differential_diagnosis.get('diagnoses', []),
521
- 'drug_interactions': drug_interactions,
522
- 'patient_education': patient_education
523
- })
524
-
525
- except Exception as e:
526
- app.logger.error(f"AI analysis error: {str(e)}")
527
- return jsonify({
528
- 'success': False,
529
- 'error': 'AI analysis service temporarily unavailable'
530
- }), 500
531
-
532
- @app.route('/api/ai/smart-templates/<int:condition_id>')
533
- @login_required
534
- def ai_smart_templates(condition_id):
535
- try:
536
- condition = Condition.query.get_or_404(condition_id)
537
- patient_id = request.args.get('patient_id')
538
-
539
- patient_demographics = {}
540
- if patient_id:
541
- patient = Patient.query.get(patient_id)
542
- if patient:
543
- patient_demographics = {
544
- 'age': patient.age,
545
- 'gender': patient.gender,
546
- 'medical_history': patient.medical_history,
547
- 'allergies': patient.allergies
548
- }
549
-
550
- smart_templates = medical_ai.smart_template_suggestions(
551
- condition.name,
552
- patient_demographics
553
- )
554
-
555
- return jsonify({
556
- 'success': True,
557
- 'templates': smart_templates
558
- })
559
-
560
- except Exception as e:
561
- app.logger.error(f"Smart template error: {str(e)}")
562
- return jsonify({
563
- 'success': False,
564
- 'error': 'Smart template service unavailable'
565
- }), 500
566
-
567
- @app.route('/api/ai/predict-outcome', methods=['POST'])
568
- @login_required
569
- def ai_predict_outcome():
570
- try:
571
- data = request.get_json()
572
- patient = Patient.query.get_or_404(data['patient_id'])
573
-
574
- patient_data = {
575
- 'age': patient.age,
576
- 'gender': patient.gender,
577
- 'medical_history': patient.medical_history,
578
- 'allergies': patient.allergies
579
- }
580
-
581
- outcome_prediction = medical_ai.predict_treatment_outcome(
582
- patient_data,
583
- data['treatment_plan']
584
- )
585
-
586
- return jsonify({
587
- 'success': True,
588
- 'prediction': outcome_prediction
589
- })
590
-
591
- except Exception as e:
592
- app.logger.error(f"Outcome prediction error: {str(e)}")
593
- return jsonify({
594
- 'success': False,
595
- 'error': 'Outcome prediction service unavailable'
596
- }), 500
597
-
598
- @app.route('/admin/briefing-preferences', methods=['GET', 'POST'])
599
- @login_required
600
- def briefing_preferences():
601
- preferences = current_user.briefing_preferences
602
- if not preferences:
603
- preferences = BriefingPreference(user_id=current_user.id)
604
- db.session.add(preferences)
605
- db.session.commit()
606
-
607
- form = BriefingPreferencesForm(obj=preferences)
608
-
609
- if form.validate_on_submit():
610
- form.populate_obj(preferences)
611
- db.session.commit()
612
- flash('Briefing preferences updated successfully!', 'success')
613
- return redirect(url_for('dashboard'))
614
-
615
- return render_template('admin.html', section='briefing', form=form)
616
-
617
- # Error handlers
618
- @app.errorhandler(404)
619
- def not_found_error(error):
620
- return render_template('base.html', error_message='Page not found'), 404
621
-
622
- @app.errorhandler(500)
623
- def internal_error(error):
624
- db.session.rollback()
625
- return render_template('base.html', error_message='Internal server error'), 500
 
 
 
 
1
  from flask import render_template, request, redirect, url_for, flash, jsonify, send_from_directory
2
  from flask_login import login_user, logout_user, login_required, current_user
3
  from werkzeug.security import check_password_hash, generate_password_hash
 
7
  from forms import *
8
  from utils import generate_treatment_pdf, allowed_file, save_uploaded_image
9
  from ai_services import medical_ai
10
+ from datetime import datetime, date, timedelta
11
+ import os, json
12
+
13
+ # ✅ Hugging Face will hit this
14
+ @app.route('/')
15
+ def root_or_dashboard():
16
+ if current_user.is_authenticated:
17
+ return redirect(url_for('dashboard'))
18
+ return "<h1>DermatologyTracker is Live!</h1><p>Please <a href='/login'>Login</a></p>"
19
 
20
+ # ✅ Actual dashboard — must be a different route
21
  @app.route('/dashboard')
22
  @login_required
23
  def dashboard():
 
24
  total_patients = Patient.query.count()
25
  today_visits = Visit.query.filter(Visit.visit_date >= date.today()).count()
 
 
26
  recent_patients = Patient.query.order_by(Patient.last_visit.desc().nullslast()).limit(6).all()
 
 
27
  upcoming_followups = Visit.query.filter(
28
  Visit.follow_up_date >= date.today(),
29
  Visit.follow_up_date <= date.today() + timedelta(days=7)
30
  ).limit(5).all()
 
 
31
  low_stock_items = Inventory.query.filter(
32
  Inventory.current_stock <= Inventory.min_threshold
33
  ).limit(5).all()
 
 
34
  preferences = current_user.briefing_preferences
35
  if not preferences:
36
  preferences = BriefingPreference(user_id=current_user.id)
37
  db.session.add(preferences)
38
  db.session.commit()
 
39
  return render_template('dashboard.html',
40
+ total_patients=total_patients,
41
+ today_visits=today_visits,
42
+ recent_patients=recent_patients,
43
+ upcoming_followups=upcoming_followups,
44
+ low_stock_items=low_stock_items,
45
+ preferences=preferences)