Yash goyal commited on
Commit
457ff7b
·
verified ·
1 Parent(s): ec91f07

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +29 -51
app.py CHANGED
@@ -8,7 +8,6 @@ import numpy as np
8
  from PIL import Image
9
  import pickle
10
  import io
11
- import os
12
  import matplotlib.pyplot as plt
13
  from reportlab.lib.pagesizes import A4
14
  from reportlab.lib import colors
@@ -41,6 +40,7 @@ MODEL_PATH = "skin_lesion_model.h5"
41
  HISTORY_PATH = "training_history.pkl"
42
  PLOT_PATH = "/tmp/static/training_plot.png"
43
  LOGO_PATH = "static/logo.jpg"
 
44
  IMG_SIZE = (224, 224)
45
  CONFIDENCE_THRESHOLD = 0.30
46
 
@@ -220,7 +220,7 @@ def generate_pdf(report, filepath):
220
  c.setFillColor(colors.Color(0.94, 0.96, 0.98, alpha=1))
221
  c.rect(0, height-120, width, 120, fill=1, stroke=0)
222
 
223
- # Logo from root directory - square JPG format
224
  try:
225
  if os.path.exists(LOGO_PATH):
226
  c.setFillColor(colors.white)
@@ -253,26 +253,20 @@ def generate_pdf(report, filepath):
253
 
254
  def professional_section_box(title, fields, extra_gap=20):
255
  nonlocal y
256
-
257
  box_height = len(fields) * 20 + 40
258
  c.setFillColor(colors.Color(0.96, 0.96, 0.96, alpha=0.3))
259
  c.rect(42, y - box_height - 2, width - 84, box_height, fill=1, stroke=0)
260
-
261
  c.setFillColor(colors.white)
262
  c.rect(40, y - box_height, width - 80, box_height, fill=1, stroke=1)
263
  c.setStrokeColor(colors.Color(0.9, 0.9, 0.9, alpha=1))
264
-
265
  c.setFillColor(colors.Color(0.95, 0.95, 0.95, alpha=1))
266
  c.rect(40, y - 30, width - 80, 30, fill=1, stroke=0)
267
-
268
  c.setFont("Helvetica-Bold", 12)
269
  c.setFillColor(colors.Color(0.3, 0.3, 0.3, alpha=1))
270
  c.drawString(55, y - 20, title)
271
-
272
  y -= 45
273
  c.setFont("Helvetica", 10)
274
  c.setFillColor(colors.Color(0.2, 0.2, 0.2, alpha=1))
275
-
276
  for label, val in fields.items():
277
  c.setFont("Helvetica-Bold", 9)
278
  c.setFillColor(colors.Color(0.4, 0.4, 0.4, alpha=1))
@@ -281,7 +275,6 @@ def generate_pdf(report, filepath):
281
  c.setFillColor(colors.Color(0.2, 0.2, 0.2, alpha=1))
282
  c.drawString(150, y, str(val))
283
  y -= 20
284
-
285
  y -= extra_gap
286
 
287
  professional_section_box("Patient Information", {
@@ -314,11 +307,9 @@ def generate_pdf(report, filepath):
314
  c.setFillColor(colors.Color(0.98, 0.98, 0.98, alpha=1))
315
  c.rect(40, 40, width - 80, 70, fill=1, stroke=1)
316
  c.setStrokeColor(colors.Color(0.9, 0.9, 0.9, alpha=1))
317
-
318
  c.setFont("Helvetica-Bold", 10)
319
  c.setFillColor(colors.Color(0.4, 0.4, 0.4, alpha=1))
320
  c.drawString(50, 95, "Medical Disclaimer")
321
-
322
  c.setFont("Helvetica", 8)
323
  c.setFillColor(colors.Color(0.3, 0.3, 0.3, alpha=1))
324
  disclaimer_lines = [
@@ -326,7 +317,6 @@ def generate_pdf(report, filepath):
326
  "Results should not replace professional medical consultation and diagnosis.",
327
  "Please consult a qualified healthcare provider for comprehensive medical evaluation."
328
  ]
329
-
330
  for i, line in enumerate(disclaimer_lines):
331
  c.drawString(50, 80 - (i * 10), line)
332
 
@@ -341,7 +331,7 @@ def home():
341
  return redirect(url_for("form"))
342
  except Exception as e:
343
  logger.error("Error in home route: %s", str(e))
344
- return render_template("form.html", history_plot=None, result={
345
  "prediction": "Error",
346
  "confidence": "N/A",
347
  "message": f"Failed to load page: {str(e)}",
@@ -351,26 +341,27 @@ def home():
351
  @app.route("/form")
352
  def form():
353
  try:
354
- # Check for required environment variables
 
 
355
  if not app.config['MAIL_USERNAME'] or not app.config['MAIL_PASSWORD']:
356
  logger.warning("Mail configuration missing, email functionality may fail")
357
- # Check if model loaded successfully
358
  if model_load_error:
359
- return render_template("form.html", history_plot="/training_plot.png", result={
360
  "prediction": "Error",
361
  "confidence": "N/A",
362
  "message": f"Model loading failed: {model_load_error}",
363
  "email_status": "N/A"
364
  })
365
- return render_template("form.html", history_plot="/training_plot.png")
366
  except Exception as e:
367
  logger.error("Error rendering form: %s", str(e))
368
- return render_template("form.html", history_plot=None, result={
369
  "prediction": "Error",
370
  "confidence": "N/A",
371
  "message": f"Failed to load form: {str(e)}",
372
  "email_status": "N/A"
373
- })
374
 
375
  @app.route("/training_plot.png")
376
  def training_plot():
@@ -390,25 +381,18 @@ def api_history():
390
  user_email = request.args.get('email')
391
  if not user_email:
392
  return jsonify({"error": "Email parameter is required"}), 400
393
-
394
  user = User.query.filter_by(email=user_email).first()
395
  if not user:
396
  return jsonify([])
397
-
398
  scans = Scan.query.filter_by(user_id=user.id).order_by(Scan.timestamp.desc()).all()
399
-
400
- history_data = []
401
- for scan in scans:
402
- image_url = url_for('uploaded_file', filename=scan.image_filename, _external=True)
403
- history_data.append({
404
- "id": scan.id,
405
- "prediction": scan.prediction,
406
- "confidence": scan.confidence,
407
- "timestamp": scan.timestamp.strftime("%B %d, %Y at %I:%M %p"),
408
- "patient_name": scan.patient_name,
409
- "image_url": image_url
410
- })
411
-
412
  return jsonify(history_data)
413
  except Exception as e:
414
  logger.error("Error in history API: %s", str(e))
@@ -420,7 +404,6 @@ def email_report(scan_id):
420
  scan = Scan.query.get(scan_id)
421
  if not scan:
422
  return jsonify({"error": "Report not found"}), 404
423
-
424
  report_data = {
425
  "name": scan.user.name,
426
  "email": scan.user.email,
@@ -432,7 +415,6 @@ def email_report(scan_id):
432
  }
433
  pdf_path = f"/tmp/report_{scan_id}.pdf"
434
  generate_pdf(report_data, pdf_path)
435
-
436
  msg = Message(
437
  'Your SnapSkin Diagnostic Report',
438
  sender=app.config['MAIL_USERNAME'],
@@ -441,10 +423,8 @@ def email_report(scan_id):
441
  msg.body = f"Dear {scan.user.name},\n\nPlease find your requested diagnostic report attached.\n\nThank you for using SnapSkin."
442
  with app.open_resource(pdf_path) as fp:
443
  msg.attach(f"SnapSkin_Report_{scan_id}.pdf", "application/pdf", fp.read())
444
-
445
  mail.send(msg)
446
  os.remove(pdf_path)
447
-
448
  return jsonify({"success": True, "message": f"Report sent to {scan.user.email}"})
449
  except Exception as e:
450
  logger.error(f"Failed to send email for scan {scan_id}: {e}")
@@ -465,23 +445,18 @@ def predict():
465
  confidence = float(prediction[predicted_index])
466
  label = label_map.get(predicted_index, "Unknown") if confidence >= CONFIDENCE_THRESHOLD else "Low confidence"
467
  msg = "⚠ This image is not confidently recognized. Please upload a clearer image." if confidence < CONFIDENCE_THRESHOLD else ""
468
-
469
- # Save user and scan data
470
  email = request.form.get("email")
471
  user = User.query.filter_by(email=email).first()
472
  if not user:
473
  user = User(name=request.form.get("name"), email=email)
474
  db.session.add(user)
475
  db.session.commit()
476
-
477
- # Save image
478
  timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
479
  image_filename = f"scan_{timestamp}.jpg"
480
  image_path = os.path.join("static/uploads", image_filename)
481
  os.makedirs("static/uploads", exist_ok=True)
482
  image.seek(0)
483
  image.save(image_path)
484
-
485
  scan = Scan(
486
  user_id=user.id,
487
  patient_name=request.form.get("name"),
@@ -493,7 +468,6 @@ def predict():
493
  )
494
  db.session.add(scan)
495
  db.session.commit()
496
-
497
  report = {
498
  "name": request.form.get("name"),
499
  "email": email,
@@ -505,8 +479,6 @@ def predict():
505
  "scan_id": scan.id
506
  }
507
  session["report"] = report
508
-
509
- # Send email automatically
510
  try:
511
  if not app.config['MAIL_USERNAME'] or not app.config['MAIL_PASSWORD']:
512
  raise ValueError("Mail configuration missing")
@@ -526,11 +498,10 @@ def predict():
526
  except Exception as e:
527
  logger.error(f"Failed to send email: {e}")
528
  report["email_status"] = "Failed to send report to email."
529
-
530
  return redirect(url_for("result"))
531
  except Exception as e:
532
  logger.error("Prediction error: %s", str(e))
533
- return render_template("form.html", history_plot="/training_plot.png", result={
534
  "prediction": "Error",
535
  "confidence": "N/A",
536
  "message": f"Prediction failed: {str(e)}",
@@ -540,16 +511,19 @@ def predict():
540
  @app.route("/result")
541
  def result():
542
  try:
 
 
 
543
  report = session.get("report", {})
544
- return render_template("form.html", **report)
545
  except Exception as e:
546
  logger.error("Error rendering result: %s", str(e))
547
- return render_template("form.html", history_plot="/training_plot.png", result={
548
  "prediction": "Error",
549
  "confidence": "N/A",
550
  "message": f"Failed to load result: {str(e)}",
551
  "email_status": "N/A"
552
- })
553
 
554
  @app.route("/download-report")
555
  def download_report():
@@ -583,6 +557,10 @@ if __name__ == "__main__":
583
  try:
584
  with app.app_context():
585
  db.create_all()
 
 
 
 
586
  app.run(host="0.0.0.0", port=7860)
587
  except Exception as e:
588
  logger.error("Application startup error: %s", str(e))
 
8
  from PIL import Image
9
  import pickle
10
  import io
 
11
  import matplotlib.pyplot as plt
12
  from reportlab.lib.pagesizes import A4
13
  from reportlab.lib import colors
 
40
  HISTORY_PATH = "training_history.pkl"
41
  PLOT_PATH = "/tmp/static/training_plot.png"
42
  LOGO_PATH = "static/logo.jpg"
43
+ FORM_TEMPLATE = "form.html"
44
  IMG_SIZE = (224, 224)
45
  CONFIDENCE_THRESHOLD = 0.30
46
 
 
220
  c.setFillColor(colors.Color(0.94, 0.96, 0.98, alpha=1))
221
  c.rect(0, height-120, width, 120, fill=1, stroke=0)
222
 
223
+ # Logo
224
  try:
225
  if os.path.exists(LOGO_PATH):
226
  c.setFillColor(colors.white)
 
253
 
254
  def professional_section_box(title, fields, extra_gap=20):
255
  nonlocal y
 
256
  box_height = len(fields) * 20 + 40
257
  c.setFillColor(colors.Color(0.96, 0.96, 0.96, alpha=0.3))
258
  c.rect(42, y - box_height - 2, width - 84, box_height, fill=1, stroke=0)
 
259
  c.setFillColor(colors.white)
260
  c.rect(40, y - box_height, width - 80, box_height, fill=1, stroke=1)
261
  c.setStrokeColor(colors.Color(0.9, 0.9, 0.9, alpha=1))
 
262
  c.setFillColor(colors.Color(0.95, 0.95, 0.95, alpha=1))
263
  c.rect(40, y - 30, width - 80, 30, fill=1, stroke=0)
 
264
  c.setFont("Helvetica-Bold", 12)
265
  c.setFillColor(colors.Color(0.3, 0.3, 0.3, alpha=1))
266
  c.drawString(55, y - 20, title)
 
267
  y -= 45
268
  c.setFont("Helvetica", 10)
269
  c.setFillColor(colors.Color(0.2, 0.2, 0.2, alpha=1))
 
270
  for label, val in fields.items():
271
  c.setFont("Helvetica-Bold", 9)
272
  c.setFillColor(colors.Color(0.4, 0.4, 0.4, alpha=1))
 
275
  c.setFillColor(colors.Color(0.2, 0.2, 0.2, alpha=1))
276
  c.drawString(150, y, str(val))
277
  y -= 20
 
278
  y -= extra_gap
279
 
280
  professional_section_box("Patient Information", {
 
307
  c.setFillColor(colors.Color(0.98, 0.98, 0.98, alpha=1))
308
  c.rect(40, 40, width - 80, 70, fill=1, stroke=1)
309
  c.setStrokeColor(colors.Color(0.9, 0.9, 0.9, alpha=1))
 
310
  c.setFont("Helvetica-Bold", 10)
311
  c.setFillColor(colors.Color(0.4, 0.4, 0.4, alpha=1))
312
  c.drawString(50, 95, "Medical Disclaimer")
 
313
  c.setFont("Helvetica", 8)
314
  c.setFillColor(colors.Color(0.3, 0.3, 0.3, alpha=1))
315
  disclaimer_lines = [
 
317
  "Results should not replace professional medical consultation and diagnosis.",
318
  "Please consult a qualified healthcare provider for comprehensive medical evaluation."
319
  ]
 
320
  for i, line in enumerate(disclaimer_lines):
321
  c.drawString(50, 80 - (i * 10), line)
322
 
 
331
  return redirect(url_for("form"))
332
  except Exception as e:
333
  logger.error("Error in home route: %s", str(e))
334
+ return render_template(FORM_TEMPLATE, history_plot=None, result={
335
  "prediction": "Error",
336
  "confidence": "N/A",
337
  "message": f"Failed to load page: {str(e)}",
 
341
  @app.route("/form")
342
  def form():
343
  try:
344
+ if not os.path.exists(os.path.join(app.template_folder, FORM_TEMPLATE)):
345
+ logger.error("Template %s not found", FORM_TEMPLATE)
346
+ return jsonify({"error": "Form template not found"}), 500
347
  if not app.config['MAIL_USERNAME'] or not app.config['MAIL_PASSWORD']:
348
  logger.warning("Mail configuration missing, email functionality may fail")
 
349
  if model_load_error:
350
+ return render_template(FORM_TEMPLATE, history_plot="/training_plot.png", result={
351
  "prediction": "Error",
352
  "confidence": "N/A",
353
  "message": f"Model loading failed: {model_load_error}",
354
  "email_status": "N/A"
355
  })
356
+ return render_template(FORM_TEMPLATE, history_plot="/training_plot.png")
357
  except Exception as e:
358
  logger.error("Error rendering form: %s", str(e))
359
+ return render_template(FORM_TEMPLATE, history_plot=None, result={
360
  "prediction": "Error",
361
  "confidence": "N/A",
362
  "message": f"Failed to load form: {str(e)}",
363
  "email_status": "N/A"
364
+ }, status=500)
365
 
366
  @app.route("/training_plot.png")
367
  def training_plot():
 
381
  user_email = request.args.get('email')
382
  if not user_email:
383
  return jsonify({"error": "Email parameter is required"}), 400
 
384
  user = User.query.filter_by(email=user_email).first()
385
  if not user:
386
  return jsonify([])
 
387
  scans = Scan.query.filter_by(user_id=user.id).order_by(Scan.timestamp.desc()).all()
388
+ history_data = [{
389
+ "id": scan.id,
390
+ "prediction": scan.prediction,
391
+ "confidence": scan.confidence,
392
+ "timestamp": scan.timestamp.strftime("%B %d, %Y at %I:%M %p"),
393
+ "patient_name": scan.patient_name,
394
+ "image_url": url_for('uploaded_file', filename=scan.image_filename, _external=True)
395
+ } for scan in scans]
 
 
 
 
 
396
  return jsonify(history_data)
397
  except Exception as e:
398
  logger.error("Error in history API: %s", str(e))
 
404
  scan = Scan.query.get(scan_id)
405
  if not scan:
406
  return jsonify({"error": "Report not found"}), 404
 
407
  report_data = {
408
  "name": scan.user.name,
409
  "email": scan.user.email,
 
415
  }
416
  pdf_path = f"/tmp/report_{scan_id}.pdf"
417
  generate_pdf(report_data, pdf_path)
 
418
  msg = Message(
419
  'Your SnapSkin Diagnostic Report',
420
  sender=app.config['MAIL_USERNAME'],
 
423
  msg.body = f"Dear {scan.user.name},\n\nPlease find your requested diagnostic report attached.\n\nThank you for using SnapSkin."
424
  with app.open_resource(pdf_path) as fp:
425
  msg.attach(f"SnapSkin_Report_{scan_id}.pdf", "application/pdf", fp.read())
 
426
  mail.send(msg)
427
  os.remove(pdf_path)
 
428
  return jsonify({"success": True, "message": f"Report sent to {scan.user.email}"})
429
  except Exception as e:
430
  logger.error(f"Failed to send email for scan {scan_id}: {e}")
 
445
  confidence = float(prediction[predicted_index])
446
  label = label_map.get(predicted_index, "Unknown") if confidence >= CONFIDENCE_THRESHOLD else "Low confidence"
447
  msg = "⚠ This image is not confidently recognized. Please upload a clearer image." if confidence < CONFIDENCE_THRESHOLD else ""
 
 
448
  email = request.form.get("email")
449
  user = User.query.filter_by(email=email).first()
450
  if not user:
451
  user = User(name=request.form.get("name"), email=email)
452
  db.session.add(user)
453
  db.session.commit()
 
 
454
  timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
455
  image_filename = f"scan_{timestamp}.jpg"
456
  image_path = os.path.join("static/uploads", image_filename)
457
  os.makedirs("static/uploads", exist_ok=True)
458
  image.seek(0)
459
  image.save(image_path)
 
460
  scan = Scan(
461
  user_id=user.id,
462
  patient_name=request.form.get("name"),
 
468
  )
469
  db.session.add(scan)
470
  db.session.commit()
 
471
  report = {
472
  "name": request.form.get("name"),
473
  "email": email,
 
479
  "scan_id": scan.id
480
  }
481
  session["report"] = report
 
 
482
  try:
483
  if not app.config['MAIL_USERNAME'] or not app.config['MAIL_PASSWORD']:
484
  raise ValueError("Mail configuration missing")
 
498
  except Exception as e:
499
  logger.error(f"Failed to send email: {e}")
500
  report["email_status"] = "Failed to send report to email."
 
501
  return redirect(url_for("result"))
502
  except Exception as e:
503
  logger.error("Prediction error: %s", str(e))
504
+ return render_template(FORM_TEMPLATE, history_plot="/training_plot.png", result={
505
  "prediction": "Error",
506
  "confidence": "N/A",
507
  "message": f"Prediction failed: {str(e)}",
 
511
  @app.route("/result")
512
  def result():
513
  try:
514
+ if not os.path.exists(os.path.join(app.template_folder, FORM_TEMPLATE)):
515
+ logger.error("Template %s not found", FORM_TEMPLATE)
516
+ return jsonify({"error": "Form template not found"}), 500
517
  report = session.get("report", {})
518
+ return render_template(FORM_TEMPLATE, **report)
519
  except Exception as e:
520
  logger.error("Error rendering result: %s", str(e))
521
+ return render_template(FORM_TEMPLATE, history_plot="/training_plot.png", result={
522
  "prediction": "Error",
523
  "confidence": "N/A",
524
  "message": f"Failed to load result: {str(e)}",
525
  "email_status": "N/A"
526
+ }, status=500)
527
 
528
  @app.route("/download-report")
529
  def download_report():
 
557
  try:
558
  with app.app_context():
559
  db.create_all()
560
+ static_files = ["form-styles.css", "preloader.js", "cursor-effect.js", "logo.png"]
561
+ for file in static_files:
562
+ if not os.path.exists(os.path.join("static", file)):
563
+ logger.warning("Static file %s not found", file)
564
  app.run(host="0.0.0.0", port=7860)
565
  except Exception as e:
566
  logger.error("Application startup error: %s", str(e))