Spaces:
Running
Running
File size: 9,466 Bytes
f55aab5 8ce2d31 e120be1 8f56164 6c17691 6b56e31 4d3d7d0 2a7768e 6d3e5ce 39fa983 792bb3e 6d3e5ce 6c17691 5012a88 7675b2e 5012a88 5d9dda5 5012a88 7675b2e 5012a88 7675b2e 5012a88 7675b2e 5012a88 4d3d7d0 5012a88 4d3d7d0 5012a88 2a7768e 5978a33 2a7768e | 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 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | # Copyright 2024 Christopher Woodyard
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import gradio as gr
import os
from groq import Groq
import json
from dotenv import load_dotenv
import re
import plotly.graph_objs as go
from typing import List, Dict, Any
import logging
# Set up logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
# Load environment variables
load_dotenv()
# Initialize Groq client
client = Groq(api_key=os.environ.get("GROQ_API_KEY"))
def parse_non_json_response(text: str) -> Dict[str, Any]:
# Attempt to extract structured information from non-JSON text
cancer_types = re.findall(r"(?:cancer type|Cancer Type):\s*(.+?)(?:\n|$)", text, re.IGNORECASE)
risk_levels = re.findall(r"(?:risk level|Risk Level):\s*(.+?)(?:\n|$)", text, re.IGNORECASE)
descriptions = re.findall(r"(?:description|Description):\s*(.+?)(?:\n|$)", text, re.IGNORECASE)
potential_cancer_types = [
{"name": ct, "risk_level": rl, "description": desc}
for ct, rl, desc in zip(cancer_types, risk_levels, descriptions)
]
recommended_tests = re.findall(r"(?:Test Name):\s*(.+?)\n(?:description|Description):\s*(.+?)(?:\n|$)", text, re.IGNORECASE)
recommended_tests = [{"name": name, "description": desc} for name, desc in recommended_tests]
general_advice = re.search(r"(?:General Advice|general advice):\s*(.+?)(?:\n|$)", text, re.DOTALL | re.IGNORECASE)
general_advice = general_advice.group(1) if general_advice else "No general advice provided."
disclaimer = re.search(r"(?:DISCLAIMER|Disclaimer):\s*(.+?)(?:\n|$)", text, re.DOTALL | re.IGNORECASE)
disclaimer = disclaimer.group(1) if disclaimer else "No disclaimer provided. This tool is for educational purposes only and should not replace professional medical advice."
return {
"potential_cancer_types": potential_cancer_types,
"recommended_tests": recommended_tests,
"general_advice": general_advice,
"disclaimer": disclaimer
}
def get_diagnosis(age: int, gender: str, symptoms: str, medical_history: str) -> Dict[str, Any]:
prompt = f"""
Given the following patient information, provide a preliminary analysis of potential cancer risks and recommended tests.
Give professional medical advice to the best of your ability.
Patient Information:
Age: {age}
Gender: {gender}
Symptoms: {symptoms}
Medical History: {medical_history}
Please provide a response with the following structure:
Potential Cancer Types:
- Cancer Type: [Name]
Risk Level: [Low/Medium/High]
Description: [Brief description of why this cancer type is considered]
Recommended Tests:
- Test Name: [Name]
Description: [Brief description of why this test is recommended]
General Advice: [General health advice for the patient]
DISCLAIMER: [A strong disclaimer about the limitations of this assessment]
Ensure the response emphasizes the importance of consulting with a medical professional for accurate diagnosis and treatment.
"""
try:
chat_completion = client.chat.completions.create(
messages=[
{
"role": "user",
"content": prompt,
}
],
model="llama-3.3-70b-versatile",
temperature=0.7,
max_tokens=1500,
)
response_content = chat_completion.choices[0].message.content
try:
response = json.loads(response_content)
except json.JSONDecodeError:
response = parse_non_json_response(response_content)
return response
except Exception as e:
logging.error(f"Error in get_diagnosis: {str(e)}")
return {"error": f"An error occurred while communicating with the API: {str(e)}"}
def plot_risk(potential_cancer_types: List[Dict[str, str]]) -> go.Figure:
if not potential_cancer_types:
return None
names = [c["name"] for c in potential_cancer_types]
risk_levels = [1 if c["risk_level"].lower() == "low" else 2 if c["risk_level"].lower() == "medium" else 3 for c in potential_cancer_types]
colors = ["green" if rl == 1 else "yellow" if rl == 2 else "red" for rl in risk_levels]
fig = go.Figure(data=[go.Bar(
x=names,
y=risk_levels,
marker_color=colors,
text=risk_levels,
textposition='auto',
)])
fig.update_layout(
title="Cancer Risk Levels",
yaxis_title="Risk Level",
xaxis_tickangle=-45,
yaxis=dict(
tickmode='array',
tickvals=[1, 2, 3],
ticktext=['Low', 'Medium', 'High']
)
)
return fig
def format_output(response: Dict[str, Any]) -> str:
if "error" in response:
return f"Error: {response['error']}"
output = "HealthScan AI: Personalized Cancer Risk Insights\n\n"
output += "Potential Cancer Types:\n"
for cancer in response.get("potential_cancer_types", []):
output += f"- {cancer.get('name', 'N/A')} (Risk Level: {cancer.get('risk_level', 'N/A')})\n"
output += f" {cancer.get('description', 'No description provided.')}\n\n"
output += "Recommended Tests:\n"
for test in response.get("recommended_tests", []):
output += f"- {test.get('name', 'N/A')}: {test.get('description', 'No description provided.')}\n\n"
output += f"General Advice:\n{response.get('general_advice', 'No general advice provided.')}\n\n"
output += f"DISCLAIMER:\n{response.get('disclaimer', 'No disclaimer provided. This tool is for educational purposes only and should not replace professional medical advice.')}"
return output
def validate_input(age: int, gender: str, symptoms: str, medical_history: str) -> List[str]:
errors = []
if not (0 < age < 120):
errors.append("Please enter a valid age between 1 and 120.")
if not symptoms.strip():
errors.append("Please enter at least one symptom.")
return errors
def process_input(age: int, gender: str, symptoms: str, medical_history: str) -> tuple:
errors = validate_input(age, gender, symptoms, medical_history)
if errors:
return "\n".join(errors), None
diagnosis = get_diagnosis(age, gender, symptoms, medical_history)
output = format_output(diagnosis)
risk_plot = plot_risk(diagnosis.get("potential_cancer_types", []))
return output, risk_plot
def clear_inputs():
return gr.Number(value=None), gr.Radio(value=None), gr.Textbox(value=""), gr.Textbox(value="")
# Create Gradio interface
with gr.Blocks(theme=gr.themes.Soft()) as iface:
gr.Markdown("# Vers3Dynamics HealthScan: Personalized Cancer Risk Insights")
gr.Markdown("This Groq-powered educational tool aims to increase general awareness about cancer risk factors and symptoms based on publicly available health data. It is not a medical assessment and should not replace professional medical advice, diagnosis, or treatment.")
with gr.Row():
with gr.Column():
age_input = gr.Number(label="Age")
gender_input = gr.Radio(["Male", "Female", "Other"], label="Gender")
symptoms_input = gr.Textbox(lines=3, label="Symptoms (separated by commas)")
medical_history_input = gr.Textbox(lines=3, label="Relevant Medical History")
submit_button = gr.Button("Submit")
clear_button = gr.Button("Clear Inputs")
with gr.Column():
output_text = gr.Textbox(label="Assessment Results", lines=10)
output_plot = gr.Plot(label="Cancer Risk Levels")
gr.Markdown("## IMPORTANT")
gr.Markdown("HealthScan AI is for educational and informational purposes only. Always consult with a qualified healthcare provider for medical concerns. The insights provided by this tool should not be used for self-diagnosis or treatment. Early detection and regular check-ups with healthcare professionals are crucial for managing your health effectively.")
submit_button.click(
fn=process_input,
inputs=[age_input, gender_input, symptoms_input, medical_history_input],
outputs=[output_text, output_plot]
)
clear_button.click(
fn=clear_inputs,
inputs=[],
outputs=[age_input, gender_input, symptoms_input, medical_history_input]
)
gr.Examples(
examples=[
[45, "Male", "Persistent cough, weight loss", "Family history of lung cancer"],
[35, "Female", "Unexplained fatigue, bruising easily", "No significant medical history"],
[60, "Other", "Blood in stool, abdominal pain", "History of inflammatory bowel disease"]
],
inputs=[age_input, gender_input, symptoms_input, medical_history_input]
)
# Launch the app
if __name__ == "__main__":
iface.launch() |