File size: 2,809 Bytes
acbd5b9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import gradio as gr
import requests
import os
import json
import re

MISTRAL_API_KEY = os.getenv("MISTRAL_API_KEY")
MISTRAL_API_URL = "https://api.mistral.ai/v1/chat/completions"

PROMPT_TEMPLATE = """
You are a clinical triage assistant. A patient describes their symptoms as follows:

"{symptoms}"

Based on standard triage protocols, output ONLY the following fields in JSON:
1. urgency_level: [Low, Moderate, High, Emergency]
2. possible_condition: A concise possible diagnosis
3. recommended_action: Clear next steps for the patient

Respond only in valid JSON. Do not include triple backticks or markdown formatting.
"""

def build_prompt(symptom_description: str) -> str:
    """
    Construct a natural language prompt based on symptom description.

    Args:
        symptom_description (str): Free-text input of patient symptoms

    Returns:
        str: LLM-ready prompt
    """
    return PROMPT_TEMPLATE.format(symptoms=symptom_description)

def extract_json(text: str) -> str:
    """
    Extract JSON object from response string, including inside code blocks.

    Args:
        text (str): Raw response from LLM

    Returns:
        str: JSON-formatted string
    """
    # Match {...} pattern even inside markdown blocks
    match = re.search(r"\{.*\}", text, re.DOTALL)
    return match.group(0) if match else text.strip()

def triage_response(symptoms: str) -> dict:
    """
    Sends a triage prompt to Mistral API and parses the JSON response.

    Args:
        symptoms (str): Description of patient symptoms

    Returns:
        dict: Dictionary with urgency_level, possible_condition, and recommended_action
    """
    prompt = build_prompt(symptoms)

    headers = {
        "Authorization": f"Bearer {MISTRAL_API_KEY}",
        "Content-Type": "application/json"
    }

    body = {
        "model": "mistral-medium",
        "messages": [{"role": "user", "content": prompt}],
        "temperature": 0.3
    }

    try:
        response = requests.post(MISTRAL_API_URL, headers=headers, json=body)
        response.raise_for_status()
        raw_output = response.json()["choices"][0]["message"]["content"]
        cleaned_output = extract_json(raw_output)
        try:
            return json.loads(cleaned_output)
        except Exception as e:
            return {"error": "Invalid JSON format", "raw_output": raw_output, "exception": str(e)}
    except Exception as e:
        return {"error": str(e)}

# Launch Gradio app with MCP support
demo = gr.Interface(
    fn=triage_response,
    inputs=gr.Textbox(lines=4, label="Enter patient's symptoms"),
    outputs="json",
    title="Clinical Triage Assistant",
    description="An MCP-compatible AI-powered tool that triages patient symptoms using Mistral API."
)

if __name__ == "__main__":
    demo.launch(mcp_server=True)