# app.py from flask import Flask, render_template, request, send_file, redirect, url_for import os import logging from utils.meldrx import MeldRxAPI from utils.oneclick import generate_discharge_paper_one_click logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) app = Flask(__name__) # Configuration from environment variables CLIENT_ID = os.getenv("MELDRX_CLIENT_ID", "04bdc9f9a23d488a868b93d594ee5a4a") CLIENT_SECRET = os.getenv("MELDRX_CLIENT_SECRET", None) WORKSPACE_ID = os.getenv("MELDRX_WORKSPACE_ID", "09ed4f76-b5ac-42bf-92d5-496933203dbe") SPACE_URL = os.getenv("SPACE_URL", "https://multitransformer-tonic-discharge-guard.hf.space") REDIRECT_URI = f"{SPACE_URL}/auth/callback" # Initialize MeldRx API meldrx_api = MeldRxAPI( client_id=CLIENT_ID, client_secret=CLIENT_SECRET, workspace_id=WORKSPACE_ID, redirect_uri=REDIRECT_URI ) @app.route('/') def index(): return render_template('index.html') @app.route('/auth', methods=['GET', 'POST']) def auth(): if request.method == 'POST': auth_code = request.form.get('auth_code') if auth_code and meldrx_api.authenticate_with_code(auth_code): return redirect(url_for('dashboard')) return render_template('auth.html', auth_url=meldrx_api.get_authorization_url(), auth_result="Authentication failed") return render_template('auth.html', auth_url=meldrx_api.get_authorization_url()) @app.route('/auth/callback', methods=['GET']) def auth_callback(): auth_code = request.args.get('code') if auth_code and meldrx_api.authenticate_with_code(auth_code): return redirect(url_for('dashboard')) return render_template('auth.html', auth_url=meldrx_api.get_authorization_url(), auth_result="Callback failed") @app.route('/dashboard', methods=['GET']) def dashboard(): if not meldrx_api.access_token: return redirect(url_for('auth')) patients_data = meldrx_api.get_patients() if not patients_data or "entry" not in patients_data: return render_template('dashboard.html', error="Failed to fetch patient data") patients = [entry['resource'] for entry in patients_data.get('entry', [])] return render_template('dashboard.html', patients=patients, authenticated=True) @app.route('/oneclick', methods=['GET', 'POST']) def one_click(): if not meldrx_api.access_token: return redirect(url_for('auth')) if request.method == 'POST': patient_id = request.form.get('patient_id', '').strip() first_name = request.form.get('first_name', '').strip() last_name = request.form.get('last_name', '').strip() action = request.form.get('action', '') pdf_path, status, display_summary = generate_discharge_paper_one_click( meldrx_api, patient_id, first_name, last_name ) if action == "Display Summary" and display_summary: return render_template('oneclick.html', status=status, summary=display_summary.replace('\n', '
')) elif action == "Generate PDF" and pdf_path: return send_file(pdf_path, as_attachment=True, download_name=f"discharge_summary_{patient_id or 'patient'}.pdf") return render_template('oneclick.html', status=status, summary=display_summary.replace('\n', '
') if display_summary else None) return render_template('oneclick.html') if __name__ == '__main__': port = int(os.getenv("PORT", 7860)) app.run(debug=False, host='0.0.0.0', port=port) # utils/oneclick.py from typing import Tuple, Optional from .meldrx import MeldRxAPI from .responseparser import PatientDataExtractor from .pdfutils import PDFGenerator import logging import json logger = logging.getLogger(__name__) def generate_discharge_paper_one_click( api: MeldRxAPI, patient_id: str = "", first_name: str = "", last_name: str = "" ) -> Tuple[Optional[str], str, Optional[str]]: """ Generate a discharge summary PDF and upload it to MeldRx patient data. Args: api: Initialized MeldRxAPI instance patient_id: Optional patient ID filter first_name: Optional first name filter last_name: Optional last name filter Returns: Tuple of (pdf_path, status_message, display_summary) """ try: # Get patient data from MeldRx API patients_data = api.get_patients() if not patients_data or "entry" not in patients_data: return None, "Failed to fetch patient data", None # Create PatientDataExtractor instance extractor = PatientDataExtractor(patients_data, "json") # Filter patients based on input matching_patients = [] matching_indices = [] for i in range(len(extractor.patients)): extractor.set_patient_by_index(i) patient_data = extractor.get_patient_dict() if (not patient_id or patient_data["id"] == patient_id) and \ (not first_name or patient_data["first_name"].lower() == first_name.lower()) and \ (not last_name or patient_data["last_name"].lower() == last_name.lower()): matching_patients.append(patient_data) matching_indices.append(i) if not matching_patients: return None, "No matching patients found", None # Use the first matching patient patient_data = matching_patients[0] patient_index = matching_indices[0] extractor.set_patient_by_index(patient_index) # Format the discharge summary text summary_text = format_discharge_summary(patient_data) # Generate PDF pdf_gen = PDFGenerator() filename = f"discharge_{patient_data['id'] or 'summary'}_{patient_data['last_name']}.pdf" pdf_path = pdf_gen.generate_pdf_from_text(summary_text, filename) # Prepare and upload discharge summary to MeldRx if pdf_path: # Convert summary to escaped JSON discharge_summary_json = json.dumps(summary_text) # Get the original patient resource patient_resource = extractor.patients[patient_index] # Add discharge_summary as an extension if "extension" not in patient_resource: patient_resource["extension"] = [] patient_resource["extension"].append({ "url": "http://example.com/fhir/StructureDefinition/discharge-summary", "valueString": discharge_summary_json }) # Update the patient in MeldRx update_success = api.update_fhir_patient(patient_data["id"], patient_resource) status_message = "Discharge summary generated and uploaded successfully" if update_success \ else "Discharge summary generated but failed to upload to MeldRx" return pdf_path, status_message, summary_text return None, "Failed to generate PDF", summary_text except Exception as e: logger.error(f"Error in one-click discharge generation: {str(e)}") return None, f"Error: {str(e)}", None def format_discharge_summary(patient_data: dict) -> str: """Format patient data into a discharge summary text.""" summary = [ "DISCHARGE SUMMARY", "", "PATIENT INFORMATION", f"Name: {patient_data['name_prefix']} {patient_data['first_name']} {patient_data['last_name']}", f"Date of Birth: {patient_data['dob']}", f"Age: {patient_data['age']}", f"Gender: {patient_data['sex']}", f"Patient ID: {patient_data['id']}", "", "CONTACT INFORMATION", f"Address: {patient_data['address']}", f"City: {patient_data['city']}, {patient_data['state']} {patient_data['zip_code']}", f"Phone: {patient_data['phone']}", "", "ADMISSION INFORMATION", f"Admission Date: {patient_data['admission_date']}", f"Discharge Date: {patient_data['discharge_date']}", f"Diagnosis: {patient_data['diagnosis']}", "", "MEDICATIONS", f"{patient_data['medications']}", "", "PHYSICIAN INFORMATION", f"Physician: Dr. {patient_data['doctor_first_name']} {patient_data['doctor_last_name']}", f"Hospital: {patient_data['hospital_name']}", f"Address: {patient_data['doctor_address']}", f"City: {patient_data['doctor_city']}, {patient_data['doctor_state']} {patient_data['doctor_zip']}", ] return "\n".join(line for line in summary if line.strip() or line == "")