Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -9,10 +9,7 @@ import base64
|
|
9 |
import joblib
|
10 |
from datetime import datetime
|
11 |
import shutil
|
12 |
-
|
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
|
17 |
import glob
|
18 |
|
@@ -130,112 +127,84 @@ def build_table(title, rows):
|
|
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 |
-
|
134 |
-
styles = getSampleStyleSheet()
|
135 |
-
title_style = ParagraphStyle(
|
136 |
-
name='Title',
|
137 |
-
fontSize=16,
|
138 |
-
leading=20,
|
139 |
-
alignment=1,
|
140 |
-
spaceAfter=20,
|
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,
|
154 |
-
leading=14,
|
155 |
-
spaceAfter=10,
|
156 |
-
textColor=colors.black,
|
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 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
239 |
except Exception as e:
|
240 |
print(f"Error saving PDF: {str(e)}") # Debug log
|
241 |
return f"Error saving PDF: {str(e)}", None
|
|
|
9 |
import joblib
|
10 |
from datetime import datetime
|
11 |
import shutil
|
12 |
+
import pdfkit
|
|
|
|
|
|
|
13 |
import atexit
|
14 |
import glob
|
15 |
|
|
|
127 |
# Function to save the health report to PDF
|
128 |
def save_results_to_pdf(profile_image_base64, test_results, summary, patient_name, patient_age, patient_gender, patient_id, filename):
|
129 |
try:
|
130 |
+
# Generate HTML content
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
131 |
current_date = datetime.now().strftime("%B %d, %Y")
|
132 |
+
health_card_html = f"""
|
133 |
+
<!DOCTYPE html>
|
134 |
+
<html>
|
135 |
+
<head>
|
136 |
+
<style>
|
137 |
+
body {{ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; max-width: 700px; margin: 20px auto; color: #1a1a1a; }}
|
138 |
+
#health-card {{ border-radius: 16px; background: linear-gradient(135deg, #e3f2fd 0%, #f3e5f5 100%); border: 2px solid #ddd; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15); padding: 30px; }}
|
139 |
+
.header {{ background-color: rgba(255, 255, 255, 0.9); border-radius: 12px; padding: 20px; margin-bottom: 25px; border: 1px solid #e0e0e0; display: flex; align-items: center; }}
|
140 |
+
.header-title {{ background: linear-gradient(135deg, #64b5f6, #42a5f5); padding: 8px 16px; border-radius: 8px; margin-right: 20px; }}
|
141 |
+
.header-title h3 {{ margin: 0; color: white; font-size: 16px; font-weight: 600; }}
|
142 |
+
.header-date {{ margin-left: auto; text-align: right; color: #666; font-size: 12px; }}
|
143 |
+
.profile {{ display: flex; align-items: center; }}
|
144 |
+
.profile img {{ width: 90px; height: 90px; border-radius: 50%; margin-right: 20px; border: 3px solid #fff; box-shadow: 0 4px 12px rgba(0,0,0,0.1); }}
|
145 |
+
.results {{ background-color: rgba(255, 255, 255, 0.95); border-radius: 12px; padding: 25px; margin-bottom: 25px; border: 1px solid #e0e0e0; }}
|
146 |
+
.summary {{ background-color: rgba(255, 255, 255, 0.95); padding: 20px; border-radius: 12px; border: 1px solid #e0e0e0; margin-bottom: 25px; }}
|
147 |
+
.summary h4 {{ margin: 0 0 15px 0; color: #2c3e50; font-size: 18px; font-weight: 600; }}
|
148 |
+
.buttons {{ display: flex; gap: 15px; justify-content: center; flex-wrap: wrap; }}
|
149 |
+
button:disabled {{ 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); }}
|
150 |
+
button {{ padding: 12px 24px; background: linear-gradient(135deg, #2196f3, #1976d2); color: white; border: none; border-radius: 8px; cursor: pointer; font-weight: 600; font-size: 14px; box-shadow: 0 4px 12px rgba(33, 150, 243, 0.3); }}
|
151 |
+
@media print {{ .gradio-container {{ display: block; }} #health-card {{ display: block; }} }}
|
152 |
+
</style>
|
153 |
+
</head>
|
154 |
+
<body>
|
155 |
+
<div id="health-card">
|
156 |
+
<div class="header">
|
157 |
+
<div class="header-title"><h3>HEALTH CARD</h3></div>
|
158 |
+
<div class="header-date">
|
159 |
+
<div>Report Date: {current_date}</div>
|
160 |
+
{f'<div>Patient ID: {patient_id}</div>' if patient_id else ''}
|
161 |
+
</div>
|
162 |
+
</div>
|
163 |
+
<div class="profile">
|
164 |
+
<img src="data:image/png;base64,{profile_image_base64}" alt="Profile">
|
165 |
+
<div>
|
166 |
+
<h2>{patient_name if patient_name else 'Lab Test Results'}</h2>
|
167 |
+
<p>{f'Age: {patient_age} | Gender: {patient_gender}' if patient_age and patient_gender else 'AI-Generated Health Analysis'}</p>
|
168 |
+
<p>Face-Based Health Analysis Report</p>
|
169 |
+
</div>
|
170 |
+
</div>
|
171 |
+
<div class="results">
|
172 |
+
{test_results['Hematology']}
|
173 |
+
{test_results['Iron Panel']}
|
174 |
+
{test_results['Liver & Kidney']}
|
175 |
+
{test_results['Electrolytes']}
|
176 |
+
{test_results['Vitals']}
|
177 |
+
</div>
|
178 |
+
<div class="summary">
|
179 |
+
<h4>📝 Summary & Recommendations</h4>
|
180 |
+
<div>{summary}</div>
|
181 |
+
</div>
|
182 |
+
<div class="buttons">
|
183 |
+
<button disabled>📥 Download Report</button>
|
184 |
+
<button>📞 Find Labs Near Me</button>
|
185 |
+
</div>
|
186 |
+
</div>
|
187 |
+
</body>
|
188 |
+
</html>
|
189 |
+
"""
|
190 |
+
|
191 |
+
# Save HTML to a temporary file
|
192 |
+
html_temp_path = "/tmp/health_card.html"
|
193 |
+
with open(html_temp_path, "w", encoding="utf-8") as f:
|
194 |
+
f.write(health_card_html)
|
195 |
+
|
196 |
+
# Convert HTML to PDF using pdfkit
|
197 |
+
pdfkit.from_file(html_temp_path, filename, options={"quiet": ""})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
198 |
print(f"PDF generated successfully at: {filename}") # Debug log
|
199 |
+
|
200 |
+
# Move to /tmp for Gradio access
|
201 |
+
temp_pdf_path = "/tmp/" + os.path.basename(filename)
|
202 |
+
shutil.copy(filename, temp_pdf_path)
|
203 |
+
|
204 |
+
if os.path.exists(temp_pdf_path) and os.access(temp_pdf_path, os.R_OK):
|
205 |
+
return f"PDF saved successfully as {filename}", temp_pdf_path
|
206 |
+
else:
|
207 |
+
return "Error: PDF file not accessible.", None
|
208 |
except Exception as e:
|
209 |
print(f"Error saving PDF: {str(e)}") # Debug log
|
210 |
return f"Error saving PDF: {str(e)}", None
|