Ali2206 commited on
Commit
b357880
·
1 Parent(s): b224fad

Integrate TxAgent into CPS API: add TxAgent files, update requirements, fix imports and database collections

Browse files
Files changed (2) hide show
  1. api/routes/txagent.py +263 -0
  2. requirements.txt +2 -1
api/routes/txagent.py CHANGED
@@ -415,4 +415,267 @@ async def get_chats(current_user: dict = Depends(get_current_user)):
415
  logger.error(f"Error getting chats: {e}")
416
  raise HTTPException(status_code=500, detail="Failed to get chats")
417
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
418
 
 
415
  logger.error(f"Error getting chats: {e}")
416
  raise HTTPException(status_code=500, detail="Failed to get chats")
417
 
418
+ @router.get("/patients/{patient_id}/analysis-reports/pdf")
419
+ async def get_patient_analysis_reports_pdf(
420
+ patient_id: str = Path(...),
421
+ current_user: dict = Depends(get_current_user)
422
+ ):
423
+ """Generate PDF analysis reports for a specific patient"""
424
+ try:
425
+ if not any(role in current_user.get('roles', []) for role in ['doctor', 'admin']):
426
+ raise HTTPException(status_code=403, detail="Only doctors and admins can generate PDF reports")
427
+
428
+ logger.info(f"Generating PDF analysis reports for patient {patient_id} by {current_user['email']}")
429
+
430
+ # Import database collections
431
+ from db.mongo import db
432
+ analysis_collection = db.analysis_results
433
+
434
+ # Find analysis results for the patient
435
+ analysis_results = await analysis_collection.find({"patient_id": patient_id}).to_list(length=None)
436
+
437
+ if not analysis_results:
438
+ raise HTTPException(status_code=404, detail="No analysis results found for this patient")
439
+
440
+ # Create a simple PDF report
441
+ from reportlab.lib.pagesizes import letter
442
+ from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
443
+ from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
444
+ from reportlab.lib.units import inch
445
+ from reportlab.lib import colors
446
+ import io
447
+
448
+ # Create PDF buffer
449
+ buffer = io.BytesIO()
450
+ doc = SimpleDocTemplate(buffer, pagesize=letter)
451
+ styles = getSampleStyleSheet()
452
+ story = []
453
+
454
+ # Title
455
+ title_style = ParagraphStyle(
456
+ 'CustomTitle',
457
+ parent=styles['Heading1'],
458
+ fontSize=16,
459
+ spaceAfter=30,
460
+ alignment=1 # Center alignment
461
+ )
462
+ story.append(Paragraph("Patient Analysis Report", title_style))
463
+ story.append(Spacer(1, 12))
464
+
465
+ # Patient Information
466
+ story.append(Paragraph("Patient Information", styles['Heading2']))
467
+ story.append(Spacer(1, 12))
468
+
469
+ # Get patient info from first analysis result
470
+ first_result = analysis_results[0]
471
+ patient_info = [
472
+ ["Patient ID:", patient_id],
473
+ ["Analysis Date:", first_result.get('timestamp', 'N/A')],
474
+ ]
475
+
476
+ patient_table = Table(patient_info, colWidths=[2*inch, 4*inch])
477
+ patient_table.setStyle(TableStyle([
478
+ ('BACKGROUND', (0, 0), (0, -1), colors.grey),
479
+ ('TEXTCOLOR', (0, 0), (0, -1), colors.whitesmoke),
480
+ ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
481
+ ('FONTNAME', (0, 0), (-1, -1), 'Helvetica-Bold'),
482
+ ('FONTSIZE', (0, 0), (-1, -1), 10),
483
+ ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
484
+ ('BACKGROUND', (1, 0), (1, -1), colors.beige),
485
+ ('GRID', (0, 0), (-1, -1), 1, colors.black)
486
+ ]))
487
+ story.append(patient_table)
488
+ story.append(Spacer(1, 20))
489
+
490
+ # Analysis Results
491
+ story.append(Paragraph("Analysis Results", styles['Heading2']))
492
+ story.append(Spacer(1, 12))
493
+
494
+ for i, result in enumerate(analysis_results):
495
+ # Risk Assessment
496
+ suicide_risk = result.get('suicide_risk', {})
497
+ risk_level = suicide_risk.get('level', 'none') if isinstance(suicide_risk, dict) else 'none'
498
+ risk_score = suicide_risk.get('score', 0.0) if isinstance(suicide_risk, dict) else 0.0
499
+ risk_factors = suicide_risk.get('factors', []) if isinstance(suicide_risk, dict) else []
500
+
501
+ story.append(Paragraph(f"Analysis #{i+1}", styles['Heading3']))
502
+ story.append(Spacer(1, 6))
503
+
504
+ analysis_data = [
505
+ ["Risk Level:", risk_level.upper()],
506
+ ["Risk Score:", f"{risk_score:.2f}"],
507
+ ["Risk Factors:", ", ".join(risk_factors) if risk_factors else "None identified"],
508
+ ["Analysis Date:", result.get('timestamp', 'N/A')],
509
+ ]
510
+
511
+ analysis_table = Table(analysis_data, colWidths=[2*inch, 4*inch])
512
+ analysis_table.setStyle(TableStyle([
513
+ ('BACKGROUND', (0, 0), (0, -1), colors.lightblue),
514
+ ('TEXTCOLOR', (0, 0), (0, -1), colors.black),
515
+ ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
516
+ ('FONTNAME', (0, 0), (-1, -1), 'Helvetica'),
517
+ ('FONTSIZE', (0, 0), (-1, -1), 9),
518
+ ('BOTTOMPADDING', (0, 0), (-1, 0), 6),
519
+ ('BACKGROUND', (1, 0), (1, -1), colors.white),
520
+ ('GRID', (0, 0), (-1, -1), 1, colors.black)
521
+ ]))
522
+ story.append(analysis_table)
523
+ story.append(Spacer(1, 12))
524
+
525
+ # Summary if available
526
+ if result.get('summary'):
527
+ story.append(Paragraph("Summary:", styles['Heading4']))
528
+ story.append(Paragraph(result['summary'], styles['Normal']))
529
+ story.append(Spacer(1, 12))
530
+
531
+ # Build PDF
532
+ doc.build(story)
533
+ buffer.seek(0)
534
+
535
+ return StreamingResponse(
536
+ buffer,
537
+ media_type="application/pdf",
538
+ headers={"Content-Disposition": f"attachment; filename=patient_{patient_id}_analysis_reports.pdf"}
539
+ )
540
+
541
+ except Exception as e:
542
+ logger.error(f"Error generating PDF report for patient {patient_id}: {str(e)}")
543
+ raise HTTPException(status_code=500, detail=f"Failed to generate PDF report: {str(e)}")
544
+
545
+ @router.get("/patients/analysis-reports/all/pdf")
546
+ async def get_all_patients_analysis_reports_pdf(
547
+ current_user: dict = Depends(get_current_user)
548
+ ):
549
+ """Generate PDF analysis reports for all patients"""
550
+ try:
551
+ if not any(role in current_user.get('roles', []) for role in ['doctor', 'admin']):
552
+ raise HTTPException(status_code=403, detail="Only doctors and admins can generate PDF reports")
553
+
554
+ logger.info(f"Generating PDF analysis reports for all patients by {current_user['email']}")
555
+
556
+ # Import database collections
557
+ from db.mongo import db
558
+ analysis_collection = db.analysis_results
559
+
560
+ # Find all analysis results
561
+ analysis_results = await analysis_collection.find({}).to_list(length=None)
562
+
563
+ if not analysis_results:
564
+ raise HTTPException(status_code=404, detail="No analysis results found")
565
+
566
+ # Create a simple PDF report
567
+ from reportlab.lib.pagesizes import letter
568
+ from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
569
+ from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
570
+ from reportlab.lib.units import inch
571
+ from reportlab.lib import colors
572
+ import io
573
+
574
+ # Create PDF buffer
575
+ buffer = io.BytesIO()
576
+ doc = SimpleDocTemplate(buffer, pagesize=letter)
577
+ styles = getSampleStyleSheet()
578
+ story = []
579
+
580
+ # Title
581
+ title_style = ParagraphStyle(
582
+ 'CustomTitle',
583
+ parent=styles['Heading1'],
584
+ fontSize=16,
585
+ spaceAfter=30,
586
+ alignment=1 # Center alignment
587
+ )
588
+ story.append(Paragraph("All Patients Analysis Reports", title_style))
589
+ story.append(Spacer(1, 12))
590
+
591
+ # Summary
592
+ story.append(Paragraph("Summary", styles['Heading2']))
593
+ story.append(Spacer(1, 12))
594
+
595
+ summary_data = [
596
+ ["Total Analysis Reports:", str(len(analysis_results))],
597
+ ["Generated Date:", datetime.now().strftime("%Y-%m-%d %H:%M:%S")],
598
+ ["Generated By:", current_user['email']],
599
+ ]
600
+
601
+ summary_table = Table(summary_data, colWidths=[2*inch, 4*inch])
602
+ summary_table.setStyle(TableStyle([
603
+ ('BACKGROUND', (0, 0), (0, -1), colors.grey),
604
+ ('TEXTCOLOR', (0, 0), (0, -1), colors.whitesmoke),
605
+ ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
606
+ ('FONTNAME', (0, 0), (-1, -1), 'Helvetica-Bold'),
607
+ ('FONTSIZE', (0, 0), (-1, -1), 10),
608
+ ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
609
+ ('BACKGROUND', (1, 0), (1, -1), colors.beige),
610
+ ('GRID', (0, 0), (-1, -1), 1, colors.black)
611
+ ]))
612
+ story.append(summary_table)
613
+ story.append(Spacer(1, 20))
614
+
615
+ # Group results by patient
616
+ patient_results = {}
617
+ for result in analysis_results:
618
+ patient_id = result.get('patient_id', 'unknown')
619
+ if patient_id not in patient_results:
620
+ patient_results[patient_id] = []
621
+ patient_results[patient_id].append(result)
622
+
623
+ # Patient Reports
624
+ for patient_id, results in patient_results.items():
625
+ story.append(Paragraph(f"Patient: {patient_id}", styles['Heading2']))
626
+ story.append(Spacer(1, 12))
627
+
628
+ for i, result in enumerate(results):
629
+ # Risk Assessment
630
+ suicide_risk = result.get('suicide_risk', {})
631
+ risk_level = suicide_risk.get('level', 'none') if isinstance(suicide_risk, dict) else 'none'
632
+ risk_score = suicide_risk.get('score', 0.0) if isinstance(suicide_risk, dict) else 0.0
633
+ risk_factors = suicide_risk.get('factors', []) if isinstance(suicide_risk, dict) else []
634
+
635
+ story.append(Paragraph(f"Analysis #{i+1}", styles['Heading3']))
636
+ story.append(Spacer(1, 6))
637
+
638
+ analysis_data = [
639
+ ["Risk Level:", risk_level.upper()],
640
+ ["Risk Score:", f"{risk_score:.2f}"],
641
+ ["Risk Factors:", ", ".join(risk_factors) if risk_factors else "None identified"],
642
+ ["Analysis Date:", result.get('timestamp', 'N/A')],
643
+ ]
644
+
645
+ analysis_table = Table(analysis_data, colWidths=[2*inch, 4*inch])
646
+ analysis_table.setStyle(TableStyle([
647
+ ('BACKGROUND', (0, 0), (0, -1), colors.lightblue),
648
+ ('TEXTCOLOR', (0, 0), (0, -1), colors.black),
649
+ ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
650
+ ('FONTNAME', (0, 0), (-1, -1), 'Helvetica'),
651
+ ('FONTSIZE', (0, 0), (-1, -1), 9),
652
+ ('BOTTOMPADDING', (0, 0), (-1, 0), 6),
653
+ ('BACKGROUND', (1, 0), (1, -1), colors.white),
654
+ ('GRID', (0, 0), (-1, -1), 1, colors.black)
655
+ ]))
656
+ story.append(analysis_table)
657
+ story.append(Spacer(1, 12))
658
+
659
+ # Summary if available
660
+ if result.get('summary'):
661
+ story.append(Paragraph("Summary:", styles['Heading4']))
662
+ story.append(Paragraph(result['summary'], styles['Normal']))
663
+ story.append(Spacer(1, 12))
664
+
665
+ story.append(Spacer(1, 20))
666
+
667
+ # Build PDF
668
+ doc.build(story)
669
+ buffer.seek(0)
670
+
671
+ return StreamingResponse(
672
+ buffer,
673
+ media_type="application/pdf",
674
+ headers={"Content-Disposition": f"attachment; filename=all_patients_analysis_reports_{datetime.now().strftime('%Y%m%d')}.pdf"}
675
+ )
676
+
677
+ except Exception as e:
678
+ logger.error(f"Error generating PDF report for all patients: {str(e)}")
679
+ raise HTTPException(status_code=500, detail=f"Failed to generate PDF report: {str(e)}")
680
+
681
 
requirements.txt CHANGED
@@ -30,4 +30,5 @@ fitz
30
  python-docx
31
  pyfcm
32
  httpx
33
- jwt
 
 
30
  python-docx
31
  pyfcm
32
  httpx
33
+ jwt
34
+ reportlab>=3.6.0