File size: 4,672 Bytes
1802cfd
 
 
 
dfe1a09
1802cfd
 
 
 
 
 
 
dfe1a09
 
1802cfd
dfe1a09
1802cfd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dfe1a09
bb55287
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
from flask import Flask, request, jsonify
from PIL import Image
from io import BytesIO
import numpy as np

import os
from keras.models import load_model
from keras.preprocessing import image
import warnings
import random
import base64


# Folder de imagens de Raios-X 
RANDOM_XRAYS_DIR = 'random_xrays'


warnings.filterwarnings("ignore")

app = Flask(__name__, static_folder='.', static_url_path='/')

# ===========================
# Carregamento do modelo
# ===========================
MODEL_PATH = 'modelo_raiox.keras'
MODEL = None

try:
    if not os.path.exists(MODEL_PATH):
        print(f"❌ Arquivo de modelo '{MODEL_PATH}' não encontrado. A predição não funcionará.")
    else:
        MODEL = load_model(MODEL_PATH, compile=False)
        print("✅ Modelo carregado com sucesso.")
except Exception as e:
    print(f"❌ Erro ao carregar o modelo: {e}")

# ===========================
# Função de predição (Adaptada para Flask)
# ===========================
def predict_image(img_data):
    """
    Realiza a predição em um objeto PIL Image.
    Retorna um dicionário com a classe, probabilidade e cores.
    """
    if MODEL is None:
        return {
            "classe": "Erro",
            "prob": 0,
            "cor": "#ff0000",
            "mensagem": "Modelo não carregado."
        }

    IMAGE_HEIGHT, IMAGE_WIDTH = 96, 96
    categories = ['Normal', 'Tuberculose']

    # 1. Pré-processamento
    img = img_data.convert("RGB").resize((IMAGE_HEIGHT, IMAGE_WIDTH))
    img = image.img_to_array(img)
    img = np.expand_dims(img, axis=0) / 255.0

    # 2. Predição
    pred = MODEL.predict(img, verbose=0)
    classe_idx = np.argmax(pred)
    prob = np.max(pred) * 100

    # 3. Formatação do resultado
    classe = categories[classe_idx]
    cor_classe = "#5dade2" if classe_idx == 0 else "#e74c3c"

    return {
        "classe": classe,
        "prob": round(prob),
        "cor": cor_classe,
        "mensagem": "Predição realizada com sucesso."
    }

# ===========================
# Rotas do Flask

@app.route('/random_predict', methods=['GET'])
def random_predict():
    """Endpoint para buscar uma imagem aleatória local, realizar a predição e retornar a imagem em base64 e o resultado."""
    
    if not os.path.exists(RANDOM_XRAYS_DIR) or not os.listdir(RANDOM_XRAYS_DIR):
        return jsonify({"error": "Imagens aleatórias não encontradas. Verifique o download."}), 500

    # 1. Escolher uma imagem localmente
    imagens_locais = os.listdir(RANDOM_XRAYS_DIR)
    nome_imagem = random.choice(imagens_locais)
    local_path = os.path.join(RANDOM_XRAYS_DIR, nome_imagem)
    
    try:
        # 2. Carregar a imagem para predição
        with open(local_path, 'rb') as f:
            img_data = f.read()
        
        # 3. Realizar a predição
        img = Image.open(BytesIO(img_data))
        result = predict_image(img)
        
        # 4. Codificar a imagem em Base64 para envio ao frontend
        img_base64 = base64.b64encode(img_data).decode('utf-8')
        
        # 5. Combinar resultado da predição com a imagem
        result['image_base64'] = img_base64
        result['image_mimetype'] = 'image/png' # Assumindo que as imagens são PNG
        
        return jsonify(result)

    except Exception as e:
        print(f"Erro interno no random_predict (local): {e}")
        return jsonify({"error": f"Erro interno: {e}"}), 500


@app.route('/')
def index():
    """Serve o arquivo HTML principal."""
    # O Flask está configurado para servir arquivos estáticos da pasta atual.
    # A rota '/' irá servir o index.html.
    return app.send_static_file('index.html')

@app.route('/predict', methods=['POST'])
def predict():
    """Endpoint para receber o arquivo e realizar a predição."""
    if 'file' not in request.files:
        return jsonify({"error": "Nenhum arquivo enviado"}), 400
    
    file = request.files['file']
    
    if file.filename == '':
        return jsonify({"error": "Nome de arquivo vazio"}), 400
    
    if file and file.filename.endswith('.png'):
        try:
            # Lê o arquivo diretamente para um objeto PIL Image
            img = Image.open(BytesIO(file.read()))
            
            # Realiza a predição
            result = predict_image(img)
            
            return jsonify(result)
        
        except Exception as e:
            print(f"Erro durante a predição: {e}")
            return jsonify({"error": f"Erro interno durante a predição: {e}"}), 500
    
    return jsonify({"error": "Formato de arquivo inválido. Apenas .png é aceito."}), 400

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=7860)