|
import streamlit as st |
|
import google.generativeai as genai |
|
import os |
|
|
|
import io |
|
from typing import Optional, Tuple, Any |
|
|
|
|
|
|
|
|
|
GEMINI_API_KEY = st.secrets.get("GEMINI_API_KEY", os.environ.get("GEMINI_API_KEY")) |
|
|
|
|
|
genai_client_configured = False |
|
if GEMINI_API_KEY: |
|
try: |
|
genai.configure(api_key=GEMINI_API_KEY) |
|
genai_client_configured = True |
|
except Exception as e: |
|
st.error(f"Fatal Error: Failed to configure Google Generative AI. Check API Key and permissions. Details: {e}") |
|
st.stop() |
|
else: |
|
st.error("β οΈ Gemini API Key not found. Please configure `GEMINI_API_KEY` in Streamlit secrets or environment variables.") |
|
st.stop() |
|
|
|
|
|
|
|
MODEL_NAME = 'gemini-1.5-pro-latest' |
|
|
|
if genai_client_configured: |
|
try: |
|
model = genai.GenerativeModel(MODEL_NAME) |
|
|
|
except Exception as e: |
|
st.error(f"Fatal Error: Failed to initialize Gemini model ({MODEL_NAME}). Details: {e}") |
|
st.stop() |
|
else: |
|
st.error("AI Model could not be initialized due to configuration issues.") |
|
st.stop() |
|
|
|
|
|
|
|
|
|
|
|
|
|
AGENTIC_ANALYSIS_PROMPT_TEMPLATE = """ |
|
**Simulated Clinical Reasoning Agent Task:** |
|
|
|
**Role:** You are an AI assistant simulating an agentic clinical reasoning process to support a healthcare professional. Your goal is NOT to diagnose, but to structure information, generate possibilities, and suggest logical next steps based *strictly* on the provided information. |
|
|
|
**Input Data:** You will receive unstructured clinical information (e.g., symptoms, history, basic findings). Assume this is the *only* information available unless stated otherwise. |
|
|
|
**Simulated Agentic Steps (Perform these sequentially in your response):** |
|
|
|
1. **Information Extraction & Structuring:** |
|
* Identify and list the key patient demographics (age, sex, if provided). |
|
* List the primary symptoms and signs presented. |
|
* Summarize relevant medical history points. |
|
* Note any explicitly mentioned negative findings (pertinent negatives). |
|
|
|
2. **Differential Considerations Generation:** |
|
* Based *only* on the structured information from Step 1, generate a list of **potential differential considerations** (possible conditions that *could* explain the findings). |
|
* **Use cautious and probabilistic language:** "could be consistent with," "warrants consideration," "less likely but possible," "should be ruled out." **AVOID definitive statements.** |
|
* Briefly state the primary rationale linking each consideration to the key findings. |
|
|
|
3. **Information Gap Analysis:** |
|
* Identify critical pieces of information typically needed for assessment that are missing from the input (e.g., specific lab results, imaging details, physical exam specifics, duration/onset details). |
|
|
|
4. **Suggested Next Steps for Investigation (for the Clinician):** |
|
* Propose logical next steps a **healthcare professional might consider** to narrow down the possibilities or gather missing information. |
|
* Categorize suggestions (e.g., Further History Taking, Physical Examination Points, Laboratory Tests, Imaging Studies). |
|
* Frame these as *suggestions* for the clinician's judgment (e.g., "Consider ordering...", "Assessment of X may be informative", "Further questioning about Y could clarify..."). |
|
|
|
5. **Mandatory Disclaimer:** Conclude with: "This AI-generated analysis is for informational support only. It is **NOT** a diagnosis and cannot replace the judgment of a qualified healthcare professional who must consider the full clinical context, conduct necessary examinations, and interpret investigations." |
|
|
|
**Input Clinical Information:** |
|
--- |
|
{text_input} |
|
--- |
|
|
|
**Agentic Analysis:** |
|
""" |
|
|
|
def run_agentic_reasoning(text_input: str) -> Tuple[Optional[str], Optional[str]]: |
|
""" |
|
Simulates an agentic reasoning process on clinical text using the Gemini model. |
|
|
|
Args: |
|
text_input: The clinical information provided by the user. |
|
|
|
Returns: |
|
A tuple containing: |
|
- The structured analysis text (str) if successful, None otherwise. |
|
- An error message (str) if an error occurred, None otherwise. |
|
""" |
|
if not text_input or not text_input.strip(): |
|
return None, "Input text cannot be empty." |
|
try: |
|
prompt = AGENTIC_ANALYSIS_PROMPT_TEMPLATE.format(text_input=text_input) |
|
|
|
|
|
|
|
response = model.generate_content(prompt) |
|
|
|
|
|
if response.parts: |
|
return response.text, None |
|
elif response.prompt_feedback.block_reason: |
|
return None, f"Analysis blocked by safety filters: {response.prompt_feedback.block_reason.name}. Please review input for potentially harmful content or adjust safety settings if appropriate." |
|
else: |
|
|
|
candidate = response.candidates[0] if response.candidates else None |
|
if candidate and candidate.finish_reason != "STOP": |
|
return None, f"Analysis stopped prematurely. Reason: {candidate.finish_reason.name}. The input might be too complex or ambiguous." |
|
else: |
|
return None, "Received an empty or unexpected response from the AI model. The model may not have been able to process the request." |
|
|
|
except Exception as e: |
|
st.error(f"Critical Error during AI Analysis: {e}", icon="π¨") |
|
|
|
return None, f"An error occurred while communicating with the AI model. Please try again later or check the input. Details: {e}" |
|
|
|
|
|
|
|
|
|
def main(): |
|
st.set_page_config( |
|
page_title="Agentic AI Clinical Reasoning Support", |
|
layout="wide", |
|
initial_sidebar_state="expanded" |
|
) |
|
|
|
|
|
st.title("π€ Agentic AI: Clinical Reasoning Support Tool") |
|
st.caption(f"Powered by Google Gemini ({MODEL_NAME})") |
|
st.markdown("---") |
|
|
|
|
|
st.warning( |
|
""" |
|
**π΄ EXTREMELY IMPORTANT DISCLAIMER π΄** |
|
* This tool **SIMULATES** an AI reasoning process. It **DOES NOT DIAGNOSE** diseases or provide medical advice. |
|
* Outputs are based **SOLELY** on the text input and the AI's internal knowledge, which may be incomplete or contain inaccuracies. **It lacks real-world clinical context.** |
|
* **NEVER** use this tool for actual patient diagnosis, treatment decisions, or clinical management. It is intended for **educational and conceptual purposes ONLY**, potentially aiding clinicians in organizing thoughts or exploring possibilities. |
|
* **ALWAYS rely on the expertise and judgment of qualified healthcare professionals.** |
|
* **PRIVACY ALERT:** Do **NOT** enter identifiable patient information (PHI) unless you comply with all legal and ethical requirements (e.g., HIPAA, GDPR, patient consent). You are responsible for the data you input. |
|
""", |
|
icon="β οΈ" |
|
) |
|
st.markdown("---") |
|
|
|
|
|
st.header("Clinical Information Input") |
|
st.markdown("Enter de-identified clinical information below (e.g., symptoms, brief history, key findings). The AI will attempt a structured analysis.") |
|
|
|
text_input = st.text_area( |
|
"Enter Clinical Data:", |
|
height=300, |
|
placeholder="Example: A 68-year-old male presents with sudden onset shortness of breath and pleuritic chest pain. History of recent long-haul flight. Vitals show tachycardia (HR 110) and mild hypoxia (SpO2 92% on room air). No significant cardiac history mentioned...", |
|
key="clinical_text_input" |
|
) |
|
|
|
|
|
analyze_button = st.button("βΆοΈ Run Agentic Analysis", key="analyze_button", type="primary", help="Click to start the simulated reasoning process.") |
|
|
|
st.markdown("---") |
|
|
|
|
|
st.header("Analysis Results") |
|
|
|
if analyze_button: |
|
if text_input: |
|
with st.spinner("π§ Simulating agentic reasoning... Please wait."): |
|
analysis_result, error_message = run_agentic_reasoning(text_input) |
|
|
|
if error_message: |
|
st.error(f"Analysis Failed: {error_message}", icon="β") |
|
elif analysis_result: |
|
st.markdown("**Simulated Agent Analysis Output:**") |
|
st.markdown(analysis_result) |
|
else: |
|
st.error("An unexpected issue occurred. No analysis was returned.", icon="β") |
|
else: |
|
st.warning("Please enter clinical information in the text area above before analyzing.", icon="βοΈ") |
|
else: |
|
st.info("Analysis results will appear here after you enter information and click 'Run Agentic Analysis'.") |
|
|
|
|
|
st.sidebar.header("About This Tool") |
|
st.sidebar.info( |
|
"This application demonstrates how an AI model (Gemini) can be prompted to simulate " |
|
"a structured, agent-like approach to analyzing clinical information. It focuses on " |
|
"differential considerations and suggesting investigation pathways for **clinician review**." |
|
) |
|
with st.sidebar.expander("View the Agentic Prompt Structure"): |
|
st.markdown(f"```plaintext\n{AGENTIC_ANALYSIS_PROMPT_TEMPLATE.split('---')[0]} ... [Input Text] ...\n```") |
|
st.caption("The prompt guides the AI to break down the task into logical steps.") |
|
|
|
st.sidebar.header("Ethical Considerations") |
|
st.sidebar.error( |
|
"**Crucial Reminder:** This AI is a tool, not a clinician. It has limitations and biases. " |
|
"Clinical decisions require human expertise, empathy, and comprehensive patient assessment. " |
|
"Misuse can lead to harm." |
|
) |
|
|
|
if __name__ == "__main__": |
|
main() |