Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import requests | |
| import json | |
| import os | |
| # ==================== API Functions ==================== | |
| def analyze_provider_notes(provider_notes, api_url, progress=gr.Progress()): | |
| """Send provider notes to backend API for analysis""" | |
| if not provider_notes or not provider_notes.strip(): | |
| return generate_empty_response() | |
| progress(0, desc="Starting analysis...") | |
| try: | |
| payload = {"provider_notes": provider_notes} | |
| progress(0.3, desc="Sending request to API...") | |
| response = requests.post( | |
| f"{api_url}/api/v1/analyze", | |
| json=payload, | |
| headers={"Content-Type": "application/json"}, | |
| timeout=60 | |
| ) | |
| progress(0.6, desc="Processing response...") | |
| response.raise_for_status() | |
| result = response.json() | |
| progress(0.9, desc="Formatting results...") | |
| formatted_response = format_complete_response(result) | |
| progress(1.0, desc="Complete!") | |
| return formatted_response | |
| except requests.exceptions.Timeout: | |
| return "β **Request Timeout**\n\nThe API is taking too long to respond. Please try again." | |
| except requests.exceptions.HTTPError as e: | |
| return f"β **HTTP Error {e.response.status_code}**\n\n{e.response.text}" | |
| except requests.exceptions.RequestException as e: | |
| return f"β **Request Error**\n\n{str(e)}" | |
| except Exception as e: | |
| return f"β **Unexpected Error**\n\n{str(e)}" | |
| def generate_empty_response(): | |
| """Generate empty response message""" | |
| return """ | |
| ### π¬ Welcome to Medical Coding (ICD-10) Assistant | |
| Please enter provider notes in the text box below and click **Send** to analyze. | |
| **Tips:** | |
| - Provide detailed clinical documentation | |
| - Include symptoms, diagnoses, and procedures | |
| - Be specific about treatments and prescriptions | |
| **How to use:** | |
| 1. Select an example from the sidebar, or | |
| 2. Upload documents via the Upload button | |
| 3. Type your own clinical notes below | |
| 4. Click the **Send** button | |
| 5. Review the ICD-10 and CPT codes generated | |
| """ | |
| def format_complete_response(result): | |
| """Format complete analysis response""" | |
| output = "---\n\n" | |
| if result.get("overall_summary"): | |
| output += f"### π Overall Summary\n\n{result['overall_summary']}\n\n---\n\n" | |
| output += "### π₯ ICD-10 Diagnostic Codes\n\n" | |
| icd_codes = result.get("icd_codes", []) | |
| if icd_codes: | |
| for idx, icd in enumerate(icd_codes, 1): | |
| output += f"**{idx}. {icd.get('code', 'N/A')}** - {icd.get('description', 'N/A')}\n\n" | |
| output += f"*Explanation:* {icd.get('explanation', 'N/A')}\n\n" | |
| else: | |
| output += "*No ICD-10 codes identified*\n\n" | |
| output += "---\n\n" | |
| output += "### πΌ CPT Procedure Codes\n\n" | |
| cpt_codes = result.get("cpt_codes", []) | |
| if cpt_codes: | |
| for idx, cpt in enumerate(cpt_codes, 1): | |
| output += f"**{idx}. {cpt.get('code', 'N/A')}** - {cpt.get('description', 'N/A')}\n\n" | |
| output += f"*Explanation:* {cpt.get('explanation', 'N/A')}\n\n" | |
| else: | |
| output += "*No CPT codes identified*\n\n" | |
| return output | |
| # ==================== Example Notes ==================== | |
| EXAMPLES = { | |
| "Acute Bronchitis": """Patient presents with acute bronchitis. Cough for 5 days, productive with yellow sputum. Lung exam reveals diffuse wheezing. Prescribed azithromycin 500mg.""", | |
| "Type 2 Diabetes": """Patient with type 2 diabetes mellitus, uncontrolled. HbA1c 9.2%. Discussed diet and medication compliance. Adjusted insulin dosing. Referred to diabetes educator.""", | |
| "Hypertension Follow-up": """Follow-up visit for hypertension. Blood pressure 145/92. Patient reports good medication compliance. Continue current antihypertensive regimen. Return in 3 months.""", | |
| } | |
| def load_example(example_name): | |
| """Load example provider notes""" | |
| return EXAMPLES.get(example_name, "") | |
| # ==================== Load External CSS ==================== | |
| def load_css(): | |
| """Load external CSS file""" | |
| css_path = os.path.join(os.path.dirname(__file__), "assets", "styles.css") | |
| try: | |
| with open(css_path, "r", encoding="utf-8") as f: | |
| return f.read() | |
| except FileNotFoundError: | |
| print("Warning: styles.css not found") | |
| return "" | |
| # ==================== Gradio Interface ==================== | |
| with gr.Blocks(css=load_css(), theme=gr.themes.Soft(), title="Medical Coding (ICD-10) Assistant") as demo: | |
| api_url_state = gr.State(value="https://Distopia22-icd-cpt-coding-api.hf.space") | |
| # Header | |
| gr.HTML(""" | |
| <div class="header-container"> | |
| <h1>π₯ Medical Coding (ICD-10) Assistant</h1> | |
| <p>AI-Powered Medical Coding Analysis using Groq LLaMA 3.3 70B</p> | |
| </div> | |
| """) | |
| with gr.Row(elem_classes="main-container"): | |
| # Left Sidebar | |
| with gr.Column(scale=1, min_width=280, elem_classes="sidebar"): | |
| gr.HTML('<div class="sidebar-title">π Example Cases</div>') | |
| example_buttons = {} | |
| for example_name in EXAMPLES.keys(): | |
| btn = gr.Button( | |
| f"π {example_name}", | |
| elem_classes="example-btn" | |
| ) | |
| example_buttons[example_name] = btn | |
| gr.Markdown("---") | |
| # Upload Document Section - Redirects to API Docs | |
| gr.HTML('<div class="sidebar-title">π€ Upload Document</div>') | |
| gr.HTML(""" | |
| <a href="https://distopia22-icd-cpt-coding-api-backend.hf.space/docs" target="_blank" style="text-decoration: none;"> | |
| <button class="upload-redirect-button"> | |
| π Upload via API Docs | |
| </button> | |
| </a> | |
| <div style="background: rgba(255,255,255,0.1); padding: 10px; border-radius: 8px; margin-top: 10px;"> | |
| <p style="color: #e0f7f4; font-size: 0.8rem; margin: 5px 0; text-align: center;"> | |
| π Only .txt format allowed | |
| </p> | |
| <p style="color: #ffffff; font-size: 0.75rem; margin: 5px 0; text-align: center; opacity: 0.7;"> | |
| Click button to upload files | |
| </p> | |
| </div> | |
| """) | |
| # Right Chat Area | |
| with gr.Column(scale=3, elem_classes="chat-container"): | |
| output_area = gr.Markdown( | |
| value=generate_empty_response(), | |
| elem_classes="output-area", | |
| label="" | |
| ) | |
| with gr.Group(elem_classes="input-container"): | |
| with gr.Row(): | |
| provider_notes_input = gr.Textbox( | |
| label="", | |
| placeholder="Enter clinical provider notes here...", | |
| lines=3, | |
| max_lines=5, | |
| show_label=False, | |
| elem_classes="prompt-input" | |
| ) | |
| with gr.Row(): | |
| send_btn = gr.Button("π Send", elem_classes="send-button", size="sm") | |
| clear_btn = gr.Button("ποΈ Clear", elem_classes="clear-button", size="sm") | |
| # Footer | |
| gr.HTML(""" | |
| <div class="footer"> | |
| <p>Powered by <strong>Groq LLaMA 3.3 70B</strong> | <strong>FastAPI</strong> | <strong>Gradio</strong></p> | |
| <p>Β© 2025 Medical Coding Assistant - Secure & HIPAA Compliant</p> | |
| </div> | |
| """) | |
| # ==================== Event Handlers ==================== | |
| # Example button clicks | |
| for example_name, btn in example_buttons.items(): | |
| btn.click( | |
| fn=lambda name=example_name: load_example(name), | |
| outputs=[provider_notes_input] | |
| ) | |
| # Send button - Analyze notes | |
| send_btn.click( | |
| fn=analyze_provider_notes, | |
| inputs=[provider_notes_input, api_url_state], | |
| outputs=[output_area] | |
| ) | |
| # Clear button | |
| clear_btn.click( | |
| fn=lambda: ("", generate_empty_response()), | |
| outputs=[provider_notes_input, output_area] | |
| ) | |
| # Launch | |
| if __name__ == "__main__": | |
| demo.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| show_error=True | |
| ) |