Spaces:
Sleeping
Sleeping
import gradio as gr | |
import os | |
from utils import ( | |
process_image, | |
extract_dicom_metadata, | |
format_report, | |
setup_analysis, | |
analyze_with_model | |
) | |
from prompts import generate_prompt | |
# Configuração do tema personalizado | |
custom_theme = gr.themes.Soft( | |
primary_hue="teal", | |
secondary_hue="blue", | |
font=[gr.themes.GoogleFont("Roboto"), "sans-serif"], | |
neutral_hue="zinc" | |
) | |
# Configuração do CSS personalizado | |
custom_css = """ | |
.container { | |
max-width: 1400px; | |
margin: 0 auto; | |
} | |
.header { | |
text-align: center; | |
margin-bottom: 2rem; | |
padding: 2rem; | |
background: linear-gradient(135deg, #00796b, #0288d1); | |
color: white; | |
border-radius: 10px; | |
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
} | |
.header h1 { | |
font-size: 2.5rem; | |
margin-bottom: 0.5rem; | |
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1); | |
} | |
.header p { | |
font-size: 1.2rem; | |
opacity: 0.95; | |
} | |
.report-container { | |
background: white; | |
padding: 25px; | |
border-radius: 15px; | |
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
margin: 20px 0; | |
border: 1px solid #e2e8f0; | |
} | |
.report-section { | |
margin: 20px 0; | |
padding: 15px; | |
border-left: 4px solid #00796b; | |
background: #f0f7f6; | |
border-radius: 0 10px 10px 0; | |
} | |
.report-section h3 { | |
color: #00695c; | |
margin-bottom: 12px; | |
font-size: 1.2rem; | |
font-weight: 600; | |
} | |
.input-section { | |
background: #ffffff; | |
padding: 20px; | |
border-radius: 10px; | |
margin-bottom: 15px; | |
border: 1px solid #e2e8f0; | |
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); | |
} | |
.image-gallery { | |
display: grid; | |
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
gap: 1rem; | |
margin: 1rem 0; | |
padding: 15px; | |
background: #f8fafb; | |
border-radius: 10px; | |
} | |
.comparison-section { | |
background: #e8f5e9; | |
padding: 20px; | |
border-radius: 10px; | |
margin: 15px 0; | |
border: 1px dashed #00796b; | |
} | |
.button-primary { | |
background: linear-gradient(135deg, #00796b, #00897b) !important; | |
border: none !important; | |
color: white !important; | |
padding: 12px 24px !important; | |
font-size: 1.1rem !important; | |
transition: all 0.3s ease !important; | |
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !important; | |
} | |
.button-primary:hover { | |
transform: translateY(-2px) !important; | |
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15) !important; | |
background: linear-gradient(135deg, #00897b, #00796b) !important; | |
} | |
.footer { | |
text-align: center; | |
margin-top: 2rem; | |
padding: 1.5rem; | |
color: #4a5568; | |
font-size: 0.9rem; | |
border-top: 1px solid #e2e8f0; | |
} | |
.metadata-box { | |
background: #f8fafb; | |
border: 1px solid #e2e8f0; | |
border-radius: 10px; | |
padding: 15px; | |
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); | |
} | |
.tabs-container { | |
margin: 20px 0; | |
} | |
.patient-info { | |
background: #ffffff; | |
padding: 20px; | |
border-radius: 10px; | |
margin-bottom: 15px; | |
border: 1px solid #e2e8f0; | |
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); | |
} | |
/* Additional styling for better visual hierarchy */ | |
.gr-form { | |
border: none !important; | |
background: transparent !important; | |
} | |
.gr-input { | |
border: 1px solid #e2e8f0 !important; | |
border-radius: 8px !important; | |
transition: all 0.3s ease !important; | |
} | |
.gr-input:focus { | |
border-color: #00796b !important; | |
box-shadow: 0 0 0 2px rgba(0, 121, 107, 0.1) !important; | |
} | |
.gr-radio { | |
accent-color: #00796b !important; | |
} | |
.gr-button-secondary { | |
border: 1px solid #00796b !important; | |
color: #00796b !important; | |
} | |
.gr-accordion { | |
border: 1px solid #e2e8f0 !important; | |
border-radius: 10px !important; | |
margin-bottom: 15px !important; | |
} | |
.gr-accordion-title { | |
color: #00695c !important; | |
} | |
""" | |
def analyze_images( | |
current_images, | |
region_type, | |
clinical_history, | |
previous_images=None, | |
patient_id=None, | |
patient_age=None, | |
patient_gender=None | |
): | |
"""Analisa múltiplas imagens com suporte a comparação.""" | |
try: | |
results = [] | |
metadata_list = [] | |
# Processar informações do paciente | |
patient_info = { | |
'id': patient_id or 'Não informado', | |
'age': patient_age or 'Não informado', | |
'gender': patient_gender or 'Não informado' | |
} | |
# Processar imagens atuais | |
for img in current_images: | |
image = process_image(img) | |
metadata = {} | |
if img.name.lower().endswith('.dcm'): | |
metadata = extract_dicom_metadata(img.name) | |
# Gerar prompt considerando imagens anteriores | |
prompt = generate_prompt( | |
clinical_history=clinical_history, | |
image_type=region_type, | |
previous_exam=previous_images is not None | |
) | |
# Análise | |
model = setup_analysis() | |
result = analyze_with_model(model, image, prompt) | |
analysis_result = { | |
'qualidade_imagem': 'Imagem de boa qualidade, com adequada inspiração e penetração.', | |
'regiao_anatomica': 'Tórax' if region_type == 'thorax' else 'Abdômen', | |
'achados': result, | |
'impressao': 'Análise realizada com sucesso.' | |
} | |
if previous_images: | |
analysis_result['comparacao'] = 'Análise comparativa realizada com exames anteriores.' | |
results.append(format_report(analysis_result)) | |
metadata_list.append(metadata) | |
return results, metadata_list, patient_info | |
except Exception as e: | |
return [f"Erro durante análise: {str(e)}"], [], {} | |
# Interface Gradio | |
with gr.Blocks(theme=custom_theme, css=custom_css) as app: | |
with gr.Column(elem_classes="container"): | |
# Header | |
with gr.Column(elem_classes="header"): | |
gr.Markdown("# Sistema Inteligente de Análise Radiológica") | |
gr.Markdown("### Desenvolvido por Dr. Paulo Roberto Maciel") | |
gr.Markdown("*Tecnologia avançada para diagnóstico preciso*") | |
with gr.Tabs(elem_classes="tabs-container"): | |
# Aba de Análise | |
with gr.TabItem("📋 Nova Análise"): | |
with gr.Row(): | |
# Coluna de Entrada | |
with gr.Column(scale=1): | |
with gr.Column(elem_classes="input-section"): | |
# Informações do Paciente (Opcional) | |
with gr.Column(elem_classes="patient-info"): | |
gr.Markdown("### 👤 Informações do Paciente (Opcional)") | |
patient_id = gr.Textbox( | |
label="ID do Paciente", | |
placeholder="Digite o identificador do paciente..." | |
) | |
patient_age = gr.Number( | |
label="Idade do Paciente", | |
minimum=0, | |
maximum=150, | |
step=1 | |
) | |
patient_gender = gr.Radio( | |
choices=["Masculino", "Feminino", "Outro"], | |
label="Gênero do Paciente", | |
value=None | |
) | |
gr.Markdown("### 🖼️ Imagens Atuais") | |
current_images = gr.File( | |
label="Upload das Imagens", | |
file_types=[".dcm", ".jpg", ".jpeg", ".png"], | |
file_count="multiple", | |
elem_classes="file-input" | |
) | |
region_type = gr.Radio( | |
choices=[("thorax", "Tórax"), ("abdomen", "Abdômen")], | |
label="Região Anatômica", | |
value="thorax" | |
) | |
with gr.Accordion("📝 Histórico Clínico (Opcional)", open=False): | |
clinical_history = gr.Textbox( | |
label="Histórico do Paciente", | |
placeholder="Descreva o histórico clínico do paciente...", | |
lines=4 | |
) | |
with gr.Accordion("🔄 Comparação com Exames Anteriores", open=False): | |
previous_images = gr.File( | |
label="Upload de Imagens Anteriores", | |
file_types=[".dcm", ".jpg", ".jpeg", ".png"], | |
file_count="multiple", | |
elem_classes="file-input" | |
) | |
analyze_btn = gr.Button( | |
"✨ Realizar Análise", | |
variant="primary", | |
elem_classes="button-primary" | |
) | |
# Coluna de Resultados | |
with gr.Column(scale=2): | |
with gr.Tabs(): | |
with gr.TabItem("📊 Resultados"): | |
with gr.Row(): | |
image_gallery = gr.Gallery( | |
label="Imagens Analisadas", | |
elem_classes="image-gallery" | |
) | |
with gr.Row(): | |
report_output = gr.HTML( | |
label="Laudos Médicos", | |
elem_classes="report-output" | |
) | |
with gr.TabItem("ℹ️ Metadados"): | |
patient_info_output = gr.JSON( | |
label="Informações do Paciente", | |
elem_classes="metadata-box" | |
) | |
metadata_output = gr.JSON( | |
label="Metadados dos Exames", | |
elem_classes="metadata-box" | |
) | |
# Aba de Histórico | |
with gr.TabItem("📚 Histórico de Análises"): | |
gr.Markdown("### Histórico de Análises Anteriores") | |
# TODO: Implementar visualização do histórico | |
# Instruções | |
with gr.Accordion("❓ Instruções de Uso", open=False): | |
gr.Markdown(""" | |
### Como Utilizar o Sistema | |
1. 👤 Opcionalmente, preencha as informações do paciente | |
2. 📤 Faça upload das imagens radiológicas (DICOM, JPG ou PNG) | |
3. 🔍 Selecione a região anatômica correspondente | |
4. 📝 Se desejar, adicione o histórico clínico do paciente | |
5. 🔄 Para comparação, faça upload de exames anteriores | |
6. ✨ Clique em "Realizar Análise" | |
O sistema processará todas as imagens e gerará laudos detalhados automaticamente. | |
""") | |
# Footer | |
with gr.Column(elem_classes="footer"): | |
gr.Markdown("© 2024 Dr. Paulo Roberto Maciel - Todos os direitos reservados") | |
gr.Markdown("Sistema desenvolvido para auxiliar profissionais de saúde no diagnóstico radiológico") | |
# Eventos | |
current_images.change( | |
lambda x: x, | |
inputs=[current_images], | |
outputs=[image_gallery] | |
) | |
analyze_btn.click( | |
analyze_images, | |
inputs=[ | |
current_images, | |
region_type, | |
clinical_history, | |
previous_images, | |
patient_id, | |
patient_age, | |
patient_gender | |
], | |
outputs=[ | |
report_output, | |
metadata_output, | |
patient_info_output | |
] | |
) | |
if __name__ == "__main__": | |
app.launch() |