Ali2206 commited on
Commit
038b1ff
·
verified ·
1 Parent(s): ee631af

Update endpoints.py

Browse files
Files changed (1) hide show
  1. endpoints.py +249 -2
endpoints.py CHANGED
@@ -1,5 +1,5 @@
1
  from fastapi import APIRouter, Depends, HTTPException, UploadFile, File, Query, Form, Path
2
- from fastapi.responses import StreamingResponse, JSONResponse
3
  from fastapi.encoders import jsonable_encoder
4
  from typing import Optional, List
5
  from pydantic import BaseModel
@@ -14,6 +14,11 @@ from datetime import datetime
14
  from bson import ObjectId
15
  import asyncio
16
  from bson.errors import InvalidId
 
 
 
 
 
17
 
18
  # Define the ChatRequest model with an optional patient_id
19
  class ChatRequest(BaseModel):
@@ -45,7 +50,7 @@ def create_router(agent, logger, patients_collection, analysis_collection, users
45
  "status": "running",
46
  "timestamp": datetime.utcnow().isoformat(),
47
  "version": "2.6.0",
48
- "features": ["chat", "voice-input", "voice-output", "patient-analysis", "report-upload"]
49
  }
50
 
51
  @router.get("/patients/analysis-results")
@@ -80,6 +85,248 @@ def create_router(agent, logger, patients_collection, analysis_collection, users
80
  logger.error(f"Error fetching analysis results: {e}")
81
  raise HTTPException(status_code=500, detail="Failed to retrieve analysis results")
82
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  @router.post("/chat-stream")
84
  async def chat_stream_endpoint(
85
  request: ChatRequest,
 
1
  from fastapi import APIRouter, Depends, HTTPException, UploadFile, File, Query, Form, Path
2
+ from fastapi.responses import StreamingResponse, JSONResponse, FileResponse
3
  from fastapi.encoders import jsonable_encoder
4
  from typing import Optional, List
5
  from pydantic import BaseModel
 
14
  from bson import ObjectId
15
  import asyncio
16
  from bson.errors import InvalidId
17
+ import base64
18
+ import os
19
+ from pathlib import Path as PathLib
20
+ import tempfile
21
+ import subprocess
22
 
23
  # Define the ChatRequest model with an optional patient_id
24
  class ChatRequest(BaseModel):
 
50
  "status": "running",
51
  "timestamp": datetime.utcnow().isoformat(),
52
  "version": "2.6.0",
53
+ "features": ["chat", "voice-input", "voice-output", "patient-analysis", "report-upload", "patient-reports-pdf", "all-patients-reports-pdf"]
54
  }
55
 
56
  @router.get("/patients/analysis-results")
 
85
  logger.error(f"Error fetching analysis results: {e}")
86
  raise HTTPException(status_code=500, detail="Failed to retrieve analysis results")
87
 
88
+ @router.get("/patients/{patient_id}/analysis-reports/pdf")
89
+ async def get_patient_analysis_reports_pdf(
90
+ patient_id: str = Path(..., description="The ID of the patient"),
91
+ current_user: dict = Depends(get_current_user)
92
+ ):
93
+ logger.info(f"Generating PDF analysis reports for patient {patient_id} by {current_user['email']}")
94
+ try:
95
+ # Fetch patient details
96
+ patient = await patients_collection.find_one({"fhir_id": patient_id})
97
+ if not patient:
98
+ raise HTTPException(status_code=404, detail="Patient not found")
99
+
100
+ # Fetch all analyses for the patient
101
+ analyses = await analysis_collection.find({"patient_id": patient_id}).sort("timestamp", -1).to_list(length=None)
102
+ if not analyses:
103
+ raise HTTPException(status_code=404, detail="No analysis reports found for this patient")
104
+
105
+ # Creating LaTeX document
106
+ latex_content = r"""
107
+ \documentclass[a4paper,12pt]{article}
108
+ \usepackage[utf8]{inputenc}
109
+ \usepackage[T1]{fontenc}
110
+ \usepackage{lmodern}
111
+ \usepackage{geometry}
112
+ \geometry{margin=1in}
113
+ \usepackage{enumitem}
114
+ \usepackage{fancyhdr}
115
+ \usepackage{lastpage}
116
+ \usepackage{datetime}
117
+ \pagestyle{fancy}
118
+ \fancyhf{}
119
+ \rhead{Patient Analysis Report}
120
+ \lhead{\today}
121
+ \cfoot{Page \thepage\ of \pageref{LastPage}}
122
+ \begin{document}
123
+ """
124
+
125
+ # Adding patient information
126
+ patient_name = patient.get("full_name", "Unknown")
127
+ latex_content += f"""
128
+ \\section*{{Analysis Reports for {patient_name} (ID: {patient_id})}}
129
+ \\textbf{{Patient Name:}} {patient_name}\\\\
130
+ \\textbf{{Patient ID:}} {patient_id}\\\\
131
+ \\textbf{{Generated on:}} \\today\\\\
132
+ """
133
+
134
+ # Adding analysis reports
135
+ for idx, analysis in enumerate(analyses, 1):
136
+ timestamp = analysis.get("timestamp", datetime.utcnow()).strftime("%Y-%m-%d %H:%M:%S")
137
+ suicide_risk = analysis.get("suicide_risk", {})
138
+ risk_level = suicide_risk.get("level", "none").capitalize()
139
+ risk_score = suicide_risk.get("score", 0.0)
140
+ risk_factors = ", ".join(suicide_risk.get("factors", [])) or "None"
141
+
142
+ latex_content += f"""
143
+ \\subsection*{{Report {idx} - {timestamp}}}
144
+ \\begin{{description}}
145
+ \\item[Risk Level:] {risk_level}
146
+ \\item[Risk Score:] {risk_score:.2f}
147
+ \\item[Risk Factors:] {risk_factors}
148
+ """
149
+
150
+ # Adding additional analysis details if available
151
+ if analysis.get("summary"):
152
+ latex_content += f" \\item[Summary:] {analysis['summary']}\n"
153
+ if analysis.get("recommendations"):
154
+ recommendations = ", ".join(analysis["recommendations"]) if isinstance(analysis["recommendations"], list) else analysis["recommendations"]
155
+ latex_content += f" \\item[Recommendations:] {recommendations}\n"
156
+
157
+ latex_content += r"\end{description}\vspace{0.5cm}"
158
+
159
+ latex_content += r"\end{document}"
160
+
161
+ # Creating temporary directory for LaTeX compilation
162
+ with tempfile.TemporaryDirectory() as tmpdirname:
163
+ latex_file = PathLib(tmpdirname) / "report.tex"
164
+ pdf_file = PathLib(tmpdirname) / "report.pdf"
165
+
166
+ # Writing LaTeX content to file
167
+ with open(latex_file, "w", encoding="utf-8") as f:
168
+ f.write(latex_content)
169
+
170
+ # Compiling LaTeX to PDF using pdflatex
171
+ try:
172
+ subprocess.run(
173
+ ["pdflatex", "-output-directory", tmpdirname, str(latex_file)],
174
+ check=True,
175
+ stdout=subprocess.PIPE,
176
+ stderr=subprocess.PIPE,
177
+ text=True
178
+ )
179
+ except subprocess.CalledProcessError as e:
180
+ logger.error(f"LaTeX compilation failed: {e.stderr}")
181
+ raise HTTPException(status_code=500, detail="Failed to generate PDF report")
182
+
183
+ if not pdf_file.exists():
184
+ raise HTTPException(status_code=500, detail="PDF generation failed")
185
+
186
+ # Reading the generated PDF
187
+ with open(pdf_file, "rb") as f:
188
+ pdf_content = f.read()
189
+
190
+ # Returning the PDF as a response
191
+ return FileResponse(
192
+ pdf_file,
193
+ media_type="application/pdf",
194
+ headers={"Content-Disposition": f"attachment; filename={patient_name.replace(' ', '_')}_{patient_id}_analysis_reports.pdf"}
195
+ )
196
+
197
+ except HTTPException:
198
+ raise
199
+ except Exception as e:
200
+ logger.error(f"Error generating PDF report for patient {patient_id}: {str(e)}")
201
+ raise HTTPException(status_code=500, detail=f"Failed to generate PDF report: {str(e)}")
202
+
203
+ @router.get("/patients/analysis-reports/all/pdf")
204
+ async def get_all_patients_analysis_reports_pdf(
205
+ current_user: dict = Depends(get_current_user)
206
+ ):
207
+ logger.info(f"Generating PDF analysis reports for all patients by {current_user['email']}")
208
+ try:
209
+ # Fetch all patients
210
+ patients = await patients_collection.find().to_list(length=None)
211
+ if not patients:
212
+ raise HTTPException(status_code=404, detail="No patients found")
213
+
214
+ # Creating LaTeX document
215
+ latex_content = r"""
216
+ \documentclass[a4paper,12pt]{article}
217
+ \usepackage[utf8]{inputenc}
218
+ \usepackage[T1]{fontenc}
219
+ \usepackage{lmodern}
220
+ \usepackage{geometry}
221
+ \geometry{margin=1in}
222
+ \usepackage{enumitem}
223
+ \usepackage{fancyhdr}
224
+ \usepackage{lastpage}
225
+ \usepackage{datetime}
226
+ \pagestyle{fancy}
227
+ \fancyhf{}
228
+ \rhead{All Patients Analysis Reports}
229
+ \lhead{\today}
230
+ \cfoot{Page \thepage\ of \pageref{LastPage}}
231
+ \begin{document}
232
+ \section*{Analysis Reports for All Patients}
233
+ \textbf{Generated on:} \today\\\\
234
+ """
235
+
236
+ # Flag to track if any analyses exist
237
+ has_analyses = False
238
+
239
+ # Iterate through each patient
240
+ for patient in patients:
241
+ patient_id = patient.get("fhir_id")
242
+ patient_name = patient.get("full_name", "Unknown")
243
+
244
+ # Fetch all analyses for the current patient
245
+ analyses = await analysis_collection.find({"patient_id": patient_id}).sort("timestamp", -1).to_list(length=None)
246
+ if not analyses:
247
+ continue # Skip patients with no analyses
248
+
249
+ has_analyses = True
250
+
251
+ # Adding patient section
252
+ latex_content += f"""
253
+ \\section*{{Patient: {patient_name} (ID: {patient_id})}}
254
+ \\textbf{{Patient Name:}} {patient_name}\\\\
255
+ \\textbf{{Patient ID:}} {patient_id}\\\\
256
+ """
257
+
258
+ # Adding analysis reports for the patient
259
+ for idx, analysis in enumerate(analyses, 1):
260
+ timestamp = analysis.get("timestamp", datetime.utcnow()).strftime("%Y-%m-%d %H:%M:%S")
261
+ suicide_risk = analysis.get("suicide_risk", {})
262
+ risk_level = suicide_risk.get("level", "none").capitalize()
263
+ risk_score = suicide_risk.get("score", 0.0)
264
+ risk_factors = ", ".join(suicide_risk.get("factors", [])) or "None"
265
+
266
+ latex_content += f"""
267
+ \\subsection*{{Report {idx} - {timestamp}}}
268
+ \\begin{{description}}
269
+ \\item[Risk Level:] {risk_level}
270
+ \\item[Risk Score:] {risk_score:.2f}
271
+ \\item[Risk Factors:] {risk_factors}
272
+ """
273
+
274
+ # Adding additional analysis details if available
275
+ if analysis.get("summary"):
276
+ latex_content += f" \\item[Summary:] {analysis['summary']}\n"
277
+ if analysis.get("recommendations"):
278
+ recommendations = ", ".join(analysis["recommendations"]) if isinstance(analysis["recommendations"], list) else analysis["recommendations"]
279
+ latex_content += f" \\item[Recommendations:] {recommendations}\n"
280
+
281
+ latex_content += r"\end{description}\vspace{0.5cm}"
282
+
283
+ latex_content += r"\end{document}"
284
+
285
+ if not has_analyses:
286
+ raise HTTPException(status_code=404, detail="No analysis reports found for any patients")
287
+
288
+ # Creating temporary directory for LaTeX compilation
289
+ with tempfile.TemporaryDirectory() as tmpdirname:
290
+ latex_file = PathLib(tmpdirname) / "all_reports.tex"
291
+ pdf_file = PathLib(tmpdirname) / "all_reports.pdf"
292
+
293
+ # Writing LaTeX content to file
294
+ with open(latex_file, "w", encoding="utf-8") as f:
295
+ f.write(latex_content)
296
+
297
+ # Compiling LaTeX to PDF using pdflatex
298
+ try:
299
+ subprocess.run(
300
+ ["pdflatex", "-output-directory", tmpdirname, str(latex_file)],
301
+ check=True,
302
+ stdout=subprocess.PIPE,
303
+ stderr=subprocess.PIPE,
304
+ text=True
305
+ )
306
+ except subprocess.CalledProcessError as e:
307
+ logger.error(f"LaTeX compilation failed: {e.stderr}")
308
+ raise HTTPException(status_code=500, detail="Failed to generate PDF report")
309
+
310
+ if not pdf_file.exists():
311
+ raise HTTPException(status_code=500, detail="PDF generation failed")
312
+
313
+ # Reading the generated PDF
314
+ with open(pdf_file, "rb") as f:
315
+ pdf_content = f.read()
316
+
317
+ # Returning the PDF as a response
318
+ return FileResponse(
319
+ pdf_file,
320
+ media_type="application/pdf",
321
+ headers={"Content-Disposition": f"attachment; filename=all_patients_analysis_reports_{datetime.utcnow().strftime('%Y%m%d')}.pdf"}
322
+ )
323
+
324
+ except HTTPException:
325
+ raise
326
+ except Exception as e:
327
+ logger.error(f"Error generating PDF report for all patients: {str(e)}")
328
+ raise HTTPException(status_code=500, detail=f"Failed to generate PDF report: {str(e)}")
329
+
330
  @router.post("/chat-stream")
331
  async def chat_stream_endpoint(
332
  request: ChatRequest,