Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -10,7 +10,7 @@ import joblib
|
|
10 |
from datetime import datetime
|
11 |
import shutil
|
12 |
from reportlab.lib.pagesizes import letter
|
13 |
-
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
|
14 |
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
15 |
from reportlab.lib import colors
|
16 |
import atexit
|
@@ -128,7 +128,7 @@ def build_table(title, rows):
|
|
128 |
return html
|
129 |
|
130 |
# Function to save the health report to PDF
|
131 |
-
def save_results_to_pdf(test_results,
|
132 |
try:
|
133 |
doc = SimpleDocTemplate(filename, pagesize=letter)
|
134 |
styles = getSampleStyleSheet()
|
@@ -141,6 +141,13 @@ def save_results_to_pdf(test_results, test_values, filename):
|
|
141 |
textColor=colors.black,
|
142 |
fontName='Helvetica-Bold'
|
143 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
144 |
body_style = ParagraphStyle(
|
145 |
name='Body',
|
146 |
fontSize=12,
|
@@ -150,37 +157,62 @@ def save_results_to_pdf(test_results, test_values, filename):
|
|
150 |
fontName='Helvetica'
|
151 |
)
|
152 |
|
153 |
-
flowables = [
|
154 |
-
|
155 |
-
#
|
156 |
-
|
157 |
-
|
158 |
-
"
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
174 |
}
|
175 |
-
|
176 |
for section_name, html in test_results.items():
|
177 |
flowables.append(Paragraph(section_name, styles['Heading2']))
|
178 |
table_data = [["Test", "Result", "Range", "Level"]]
|
179 |
-
for label in
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
table_data.append([label, f"{value:.2f}" if label not in ["WBC Count", "Platelet Count"] else f"{value:.0f}", f"{test_ranges[label][0]} - {test_ranges[label][1]}", level])
|
184 |
table = Table(table_data)
|
185 |
table.setStyle(TableStyle([
|
186 |
('BACKGROUND', (0, 0), (-1, 0), colors.grey),
|
@@ -190,14 +222,22 @@ def save_results_to_pdf(test_results, test_values, filename):
|
|
190 |
('FONTSIZE', (0, 0), (-1, 0), 12),
|
191 |
('BOTTOMPADDING', (0, 0), (-1, 0), 12),
|
192 |
('BACKGROUND', (0, 1), (-1, -1), colors.beige),
|
193 |
-
('GRID', (0, 0), (-1, -1), 1, colors.black)
|
|
|
194 |
]))
|
195 |
flowables.append(table)
|
196 |
flowables.append(Spacer(1, 12))
|
197 |
-
|
|
|
|
|
|
|
|
|
|
|
198 |
doc.build(flowables)
|
|
|
199 |
return f"PDF saved successfully as {filename}", filename
|
200 |
except Exception as e:
|
|
|
201 |
return f"Error saving PDF: {str(e)}", None
|
202 |
|
203 |
# Build health card layout
|
@@ -246,7 +286,6 @@ def build_health_card(profile_image, test_results, summary, pdf_filepath, patien
|
|
246 |
</div>
|
247 |
|
248 |
<div style="display: flex; gap: 15px; justify-content: center; flex-wrap: wrap;">
|
249 |
-
<!-- Disabled the direct download link to rely on Gradio File component -->
|
250 |
<button disabled style="padding: 12px 24px; background: #ccc; color: white; border: none; border-radius: 8px; cursor: not-allowed; font-weight: 600; font-size: 14px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);">
|
251 |
📥 Download Report
|
252 |
</button>
|
@@ -346,7 +385,16 @@ def analyze_face(input_data):
|
|
346 |
profile_image_base64 = base64.b64encode(buffer).decode('utf-8')
|
347 |
|
348 |
pdf_filename = f"Health_Report_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.pdf"
|
349 |
-
pdf_result, pdf_filepath = save_results_to_pdf(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
350 |
|
351 |
if pdf_filepath:
|
352 |
temp_pdf_path = "/tmp/" + os.path.basename(pdf_filepath)
|
|
|
10 |
from datetime import datetime
|
11 |
import shutil
|
12 |
from reportlab.lib.pagesizes import letter
|
13 |
+
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, Image
|
14 |
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
15 |
from reportlab.lib import colors
|
16 |
import atexit
|
|
|
128 |
return html
|
129 |
|
130 |
# Function to save the health report to PDF
|
131 |
+
def save_results_to_pdf(profile_image_base64, test_results, summary, patient_name, patient_age, patient_gender, patient_id, filename):
|
132 |
try:
|
133 |
doc = SimpleDocTemplate(filename, pagesize=letter)
|
134 |
styles = getSampleStyleSheet()
|
|
|
141 |
textColor=colors.black,
|
142 |
fontName='Helvetica-Bold'
|
143 |
)
|
144 |
+
header_style = ParagraphStyle(
|
145 |
+
name='Header',
|
146 |
+
fontSize=14,
|
147 |
+
leading=16,
|
148 |
+
textColor=colors.darkblue,
|
149 |
+
fontName='Helvetica-Bold'
|
150 |
+
)
|
151 |
body_style = ParagraphStyle(
|
152 |
name='Body',
|
153 |
fontSize=12,
|
|
|
157 |
fontName='Helvetica'
|
158 |
)
|
159 |
|
160 |
+
flowables = []
|
161 |
+
|
162 |
+
# Header with Profile Image and Patient Details
|
163 |
+
current_date = datetime.now().strftime("%B %d, %Y")
|
164 |
+
header_table_data = [
|
165 |
+
[Paragraph("HEALTH CARD", header_style), "", Paragraph(f"Report Date: {current_date}<br/>{f'Patient ID: {patient_id}' if patient_id else ''}", body_style)]
|
166 |
+
]
|
167 |
+
header_table = Table(header_table_data, colWidths=[100, 300, 150])
|
168 |
+
header_table.setStyle(TableStyle([
|
169 |
+
('BACKGROUND', (0, 0), (0, 0), colors.lightblue),
|
170 |
+
('BACKGROUND', (2, 0), (2, 0), colors.lightgrey),
|
171 |
+
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
|
172 |
+
('ALIGN', (0, 0), (0, 0), 'LEFT'),
|
173 |
+
('ALIGN', (2, 0), (2, 0), 'RIGHT'),
|
174 |
+
]))
|
175 |
+
flowables.append(header_table)
|
176 |
+
|
177 |
+
# Profile Image and Patient Info
|
178 |
+
if profile_image_base64:
|
179 |
+
import io
|
180 |
+
from reportlab.lib.utils import ImageReader
|
181 |
+
img_data = base64.b64decode(profile_image_base64)
|
182 |
+
img_file = io.BytesIO(img_data)
|
183 |
+
img = ImageReader(img_file)
|
184 |
+
img_width = 90
|
185 |
+
img_height = 90
|
186 |
+
img.drawHeight = img_height * 0.5
|
187 |
+
img.drawWidth = img_width * 0.5
|
188 |
+
patient_info = f"{patient_name if patient_name else 'Lab Test Results'}<br/>{f'Age: {patient_age} | Gender: {patient_gender}' if patient_age and patient_gender else 'AI-Generated Health Analysis'}<br/>Face-Based Health Analysis Report"
|
189 |
+
profile_table_data = [[Image(img, width=img_width, height=img_height), Paragraph(patient_info, body_style)]]
|
190 |
+
profile_table = Table(profile_table_data, colWidths=[100, 400])
|
191 |
+
profile_table.setStyle(TableStyle([
|
192 |
+
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
|
193 |
+
('LEFTPADDING', (0, 0), (0, 0), 0),
|
194 |
+
('RIGHTPADDING', (1, 0), (1, 0), 10),
|
195 |
+
]))
|
196 |
+
flowables.append(profile_table)
|
197 |
+
flowables.append(Spacer(1, 20))
|
198 |
+
|
199 |
+
# Test Results Sections
|
200 |
+
section_tests = {
|
201 |
+
"Hematology": [("Hemoglobin", (13.5, 17.5)), ("WBC Count", (4.0, 11.0)), ("Platelet Count", (150, 450))],
|
202 |
+
"Iron Panel": [("Iron", (60, 170)), ("Ferritin", (30, 300)), ("TIBC", (250, 400))],
|
203 |
+
"Liver & Kidney": [("Bilirubin", (0.3, 1.2)), ("Creatinine", (0.6, 1.2)), ("Urea", (7, 20))],
|
204 |
+
"Electrolytes": [("Sodium", (135, 145)), ("Potassium", (3.5, 5.1))],
|
205 |
+
"Vitals": [("SpO2", (95, 100)), ("Heart Rate", (60, 100)), ("Respiratory Rate", (12, 20)),
|
206 |
+
("Temperature", (97, 99)), ("BP Systolic", (90, 120)), ("BP Diastolic", (60, 80))]
|
207 |
}
|
208 |
+
|
209 |
for section_name, html in test_results.items():
|
210 |
flowables.append(Paragraph(section_name, styles['Heading2']))
|
211 |
table_data = [["Test", "Result", "Range", "Level"]]
|
212 |
+
for label, ref_range in section_tests.get(section_name, []):
|
213 |
+
value = float(test_results[section_name].split(f'{label}</td><td style="padding:10px 8px;text-align:center;color:#2c3e50;font-weight:600;">')[1].split('</td>')[0]) if label in test_results[section_name] else ref_range[0] + random.uniform(-1, 1)
|
214 |
+
level, _, _ = get_risk_color(value, ref_range)
|
215 |
+
table_data.append([label, f"{value:.2f}" if label not in ["WBC Count", "Platelet Count"] else f"{value:.0f}", f"{ref_range[0]} - {ref_range[1]}", f"{level}"])
|
|
|
216 |
table = Table(table_data)
|
217 |
table.setStyle(TableStyle([
|
218 |
('BACKGROUND', (0, 0), (-1, 0), colors.grey),
|
|
|
222 |
('FONTSIZE', (0, 0), (-1, 0), 12),
|
223 |
('BOTTOMPADDING', (0, 0), (-1, 0), 12),
|
224 |
('BACKGROUND', (0, 1), (-1, -1), colors.beige),
|
225 |
+
('GRID', (0, 0), (-1, -1), 1, colors.black),
|
226 |
+
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
|
227 |
]))
|
228 |
flowables.append(table)
|
229 |
flowables.append(Spacer(1, 12))
|
230 |
+
|
231 |
+
# Summary & Recommendations
|
232 |
+
flowables.append(Paragraph("Summary & Recommendations", styles['Heading2']))
|
233 |
+
flowables.append(Paragraph(summary.replace("<ul>", "").replace("</ul>", "").replace("<li>", "\u2022 ").replace("</li>", "<br/>"), body_style))
|
234 |
+
flowables.append(Spacer(1, 20))
|
235 |
+
|
236 |
doc.build(flowables)
|
237 |
+
print(f"PDF generated successfully at: {filename}") # Debug log
|
238 |
return f"PDF saved successfully as {filename}", filename
|
239 |
except Exception as e:
|
240 |
+
print(f"Error saving PDF: {str(e)}") # Debug log
|
241 |
return f"Error saving PDF: {str(e)}", None
|
242 |
|
243 |
# Build health card layout
|
|
|
286 |
</div>
|
287 |
|
288 |
<div style="display: flex; gap: 15px; justify-content: center; flex-wrap: wrap;">
|
|
|
289 |
<button disabled style="padding: 12px 24px; background: #ccc; color: white; border: none; border-radius: 8px; cursor: not-allowed; font-weight: 600; font-size: 14px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);">
|
290 |
📥 Download Report
|
291 |
</button>
|
|
|
385 |
profile_image_base64 = base64.b64encode(buffer).decode('utf-8')
|
386 |
|
387 |
pdf_filename = f"Health_Report_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.pdf"
|
388 |
+
pdf_result, pdf_filepath = save_results_to_pdf(
|
389 |
+
profile_image_base64,
|
390 |
+
test_results,
|
391 |
+
summary,
|
392 |
+
current_patient_details['name'],
|
393 |
+
current_patient_details['age'],
|
394 |
+
current_patient_details['gender'],
|
395 |
+
current_patient_details['id'],
|
396 |
+
pdf_filename
|
397 |
+
)
|
398 |
|
399 |
if pdf_filepath:
|
400 |
temp_pdf_path = "/tmp/" + os.path.basename(pdf_filepath)
|