File size: 5,883 Bytes
2c9f880
 
 
bc9c9ab
2c9f880
 
 
 
 
 
 
 
3692f8e
2c9f880
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65f4d38
 
12e96ed
 
 
 
 
 
 
2c9f880
 
 
12e96ed
65f4d38
 
 
 
 
 
 
 
7ce4819
bee9e2b
 
 
 
 
 
 
2badcc4
 
2c9f880
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
from fastapi import FastAPI, File, UploadFile, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from huggingface_hub import login
import os
from transformers import pipeline
from PIL import Image
import io
import base64
from datetime import datetime
from typing import Optional

# Login no Hugging Face
#login(new_session=False)

app = FastAPI(
    title="CareLink Medical API",
    description="API para análise de exames médicos usando IA",
    version="1.0.0"
)

# Configurar CORS para permitir requisições do frontend
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # Em produção, especifique o domínio do frontend
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Inicializar o pipeline do modelo (fazer isso uma vez no startup)
print("Carregando modelo MedGemma...")
pipe = None

import os
from transformers import pipeline

def get_hf_token():
        return (
                os.environ.get("HUGGINGFACE_HUB_TOKEN")
                or os.environ.get("HF_TOKEN")
                )

@app.on_event("startup")
async def startup_event():
    global pipe
    token = get_hf_token()
    if not token:
        raise RuntimeError("HF_TOKEN não encontrado no ambiente")
    pipe = pipeline(
        "image-text-to-text",
        model="google/medgemma-4b-it",
        token=token   # 👈 ESTE é o ponto crítico
    )
    print("Modelo MedGemma carregado com sucesso!")
    import logging
    logging.basicConfig(level=logging.INFO)
    logging.info("===================================")
    logging.info("🚀 Application ready")
    logging.info(f"🌐 Space URL: {SPACE_URL}")
    logging.info(f"📡 Gradio endpoint: {SPACE_URL}/run/predict")
    logging.info("===================================")


@app.get("/")
def root():
    return {
        "message": "CareLink Medical API",
        "status": "online",
        "version": "1.0.0",
        "endpoints": {
            "analyze_exam": "/api/analyze-exam (POST)",
            "health": "/health (GET)"
        }
    }


@app.get("/health")
def health_check():
    return {
        "status": "healthy",
        "model_loaded": pipe is not None,
        "timestamp": datetime.now().isoformat()
    }


@app.post("/api/analyze-exam")
async def analyze_exam(
    file: UploadFile = File(...),
    patient_name: Optional[str] = None
):
    """
    Analisa uma imagem de exame médico usando o modelo MedGemma.
    
    - **file**: Imagem do exame (JPEG, PNG, etc)
    - **patient_name**: Nome do paciente (opcional)
    """
    
    if pipe is None:
        raise HTTPException(
            status_code=503,
            detail="Modelo ainda não foi carregado. Tente novamente em alguns instantes."
        )
    
    # Validar tipo de arquivo
    if not file.content_type.startswith('image/'):
        raise HTTPException(
            status_code=400,
            detail="O arquivo enviado não é uma imagem válida"
        )
    
    try:
        # Ler a imagem
        contents = await file.read()
        image = Image.open(io.BytesIO(contents))
        
        # Converter imagem para base64 para retornar ao frontend (opcional)
        buffered = io.BytesIO()
        image.save(buffered, format=image.format or "PNG")
        img_base64 = base64.b64encode(buffered.getvalue()).decode()
        
        # Preparar mensagem para o modelo
        messages = [
            {
                "role": "user",
                "content": [
                    {"type": "image", "image": image},
                    {
                        "type": "text",
                        "text": "Analise esta imagem de exame médico. Descreva o que você observa, "
                                "identifique possíveis achados clínicos e forneça uma análise detalhada. "
                                "Se possível, indique se há algo que requer atenção médica."
                    }
                ]
            }
        ]
        
        # Processar com o modelo
        print(f"Analisando exame para paciente: {patient_name or 'não especificado'}")
        result = pipe(messages)
        
        # Extrair a resposta do modelo
        analysis_text = ""
        if isinstance(result, list) and len(result) > 0:
            if isinstance(result[0], dict) and "generated_text" in result[0]:
                analysis_text = result[0]["generated_text"]
            else:
                analysis_text = str(result[0])
        else:
            analysis_text = str(result)
        
        # Montar resposta estruturada
        response = {
            "success": True,
            "timestamp": datetime.now().isoformat(),
            "patient_name": patient_name,
            "file_info": {
                "filename": file.filename,
                "content_type": file.content_type,
                "size_bytes": len(contents)
            },
            "analysis": {
                "model": "google/medgemma-4b-it",
                "result": analysis_text,
                "confidence": "high"  # Você pode adicionar lógica para calcular confiança
            },
            "image_preview": f"data:image/png;base64,{img_base64[:100]}..."  # Preview truncado
        }
        
        print(f"Análise concluída com sucesso para: {file.filename}")
        return response
        
    except Exception as e:
        print(f"Erro ao processar imagem: {str(e)}")
        raise HTTPException(
            status_code=500,
            detail=f"Erro ao processar a imagem: {str(e)}"
        )


@app.get("/api/test-model")
def test_model():
    """Endpoint para testar se o modelo está funcionando"""
    if pipe is None:
        return {"status": "error", "message": "Modelo não carregado"}
    return {
        "status": "ok",
        "model": "google/medgemma-4b-it",
        "message": "Modelo carregado e pronto para uso"
    }