Create app.py
Browse files
app.py
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
from transformers import pipeline
|
| 3 |
+
from PIL import Image
|
| 4 |
+
import requests
|
| 5 |
+
import torch
|
| 6 |
+
|
| 7 |
+
# Verifique se uma GPU está disponível e configure o dispositivo
|
| 8 |
+
# Se você tiver um Hugging Face Space com GPU, use "cuda". Caso contrário, use "cpu".
|
| 9 |
+
device = "cuda" if torch.cuda.is_available() else "cpu"
|
| 10 |
+
|
| 11 |
+
# Inicializa o pipeline do modelo MedGemma
|
| 12 |
+
# O modelo google/medgemma-4b-it é uma variante de 4 bilhões de parâmetros
|
| 13 |
+
# O torch_dtype=torch.bfloat16 é recomendado para desempenho em GPUs mais recentes
|
| 14 |
+
# Certifique-se de que a versão do transformers seja >= 4.50.0
|
| 15 |
+
try:
|
| 16 |
+
medgemma_pipe = pipeline(
|
| 17 |
+
"image-text-to-text",
|
| 18 |
+
model="google/medgemma-4b-it",
|
| 19 |
+
torch_dtype=torch.bfloat16,
|
| 20 |
+
device=device,
|
| 21 |
+
)
|
| 22 |
+
except Exception as e:
|
| 23 |
+
print(f"Erro ao carregar o modelo MedGemma: {e}")
|
| 24 |
+
print("Verifique se você aceitou os termos de uso na página do modelo Hugging Face e se suas dependências estão corretas.")
|
| 25 |
+
# Se o modelo não carregar, use uma função dummy para que a interface ainda funcione
|
| 26 |
+
def medgemma_pipe(messages, max_new_tokens):
|
| 27 |
+
print("Modelo não carregado, usando função dummy.")
|
| 28 |
+
return [{"generated_text": [{"content": "Desculpe, o modelo não pôde ser carregado. Verifique os logs."}]}]
|
| 29 |
+
|
| 30 |
+
def process_medical_query(image_input, text_input):
|
| 31 |
+
"""
|
| 32 |
+
Processa uma consulta médica que pode incluir uma imagem e/ou texto.
|
| 33 |
+
"""
|
| 34 |
+
messages = []
|
| 35 |
+
|
| 36 |
+
# O MedGemma é otimizado para aplicações médicas com geração de texto [cite: 113]
|
| 37 |
+
# Se uma imagem for fornecida, adicione-a ao conteúdo da mensagem do usuário
|
| 38 |
+
if image_input:
|
| 39 |
+
# O modelo espera imagens normalizadas para 896x896 pixels [cite: 232]
|
| 40 |
+
# Embora o pipeline possa lidar com isso automaticamente, é uma boa prática estar ciente
|
| 41 |
+
image = image_input.convert("RGB") # Garante que a imagem esteja em formato RGB
|
| 42 |
+
|
| 43 |
+
# A role 'system' pode ser usada para instruir o modelo, como ser um 'radiologista' [cite: 141, 142]
|
| 44 |
+
messages.append({"role": "system", "content": [{"type": "text", "text": "Você é um assistente médico especialista."}]})
|
| 45 |
+
|
| 46 |
+
# A role 'user' contém a pergunta e a imagem [cite: 145, 146, 147, 148, 149]
|
| 47 |
+
user_content = []
|
| 48 |
+
if text_input:
|
| 49 |
+
user_content.append({"type": "text", "text": text_input})
|
| 50 |
+
user_content.append({"type": "image", "image": image})
|
| 51 |
+
messages.append({"role": "user", "content": user_content})
|
| 52 |
+
|
| 53 |
+
elif text_input:
|
| 54 |
+
messages.append({"role": "system", "content": [{"type": "text", "text": "Você é um assistente médico especialista."}]})
|
| 55 |
+
messages.append({"role": "user", "content": [{"type": "text", "text": text_input}]})
|
| 56 |
+
else:
|
| 57 |
+
return "Por favor, forneça uma imagem e/ou uma pergunta."
|
| 58 |
+
|
| 59 |
+
try:
|
| 60 |
+
# A geração de texto é o principal objetivo do MedGemma [cite: 113]
|
| 61 |
+
# max_new_tokens define o comprimento máximo da resposta gerada
|
| 62 |
+
output = medgemma_pipe(text=messages, max_new_tokens=500)
|
| 63 |
+
|
| 64 |
+
# O resultado é uma lista de dicionários; precisamos extrair o texto gerado
|
| 65 |
+
generated_text = output[0]["generated_text"][-1]["content"]
|
| 66 |
+
return generated_text
|
| 67 |
+
except Exception as e:
|
| 68 |
+
return f"Ocorreu um erro durante a inferência: {e}. Verifique a entrada ou os logs do Space."
|
| 69 |
+
|
| 70 |
+
# Configuração da interface Gradio
|
| 71 |
+
# O MedGemma suporta entrada de texto e visão, e saída de texto [cite: 210, 211]
|
| 72 |
+
iface = gr.Interface(
|
| 73 |
+
fn=process_medical_query,
|
| 74 |
+
inputs=[
|
| 75 |
+
gr.Image(type="pil", label="Envie uma Imagem Médica (Opcional)"),
|
| 76 |
+
gr.Textbox(lines=5, placeholder="Descreva a imagem ou faça uma pergunta médica...", label="Sua Pergunta/Descrição"),
|
| 77 |
+
],
|
| 78 |
+
outputs="text",
|
| 79 |
+
title="⚕️ Assistente Médico com MedGemma 4B ⚕️",
|
| 80 |
+
description=(
|
| 81 |
+
"Este é um demonstrador interativo utilizando o modelo Google MedGemma 4B, "
|
| 82 |
+
"treinado para compreensão de texto e imagem médica[cite: 91]. "
|
| 83 |
+
"Envie uma imagem médica (como um raio-X) e/ou faça uma pergunta para obter uma análise. "
|
| 84 |
+
"Lembre-se: As saídas geradas por modelos de IA são **preliminares** e **não devem ser usadas para diagnóstico ou tratamento clínico**[cite: 463, 464, 469]."
|
| 85 |
+
),
|
| 86 |
+
live=False,
|
| 87 |
+
allow_flagging="auto",
|
| 88 |
+
examples=[
|
| 89 |
+
[None, "Quais são os principais riscos de diabetes não controlada?"],
|
| 90 |
+
["https://upload.wikimedia.org/wikipedia/commons/c/c8/Chest.jpg", "Descreva este raio-X do tórax."],
|
| 91 |
+
["https://upload.wikimedia.org/wikipedia/commons/c/c8/Chest.jpg", "Há sinais de pneumonia nesta imagem?"],
|
| 92 |
+
]
|
| 93 |
+
)
|
| 94 |
+
|
| 95 |
+
# Inicia a interface Gradio
|
| 96 |
+
if __name__ == "__main__":
|
| 97 |
+
iface.launch()
|