PericlesRodrigues01 commited on
Commit
80dede2
·
verified ·
1 Parent(s): 7af6773

Upload 7 files

Browse files
Files changed (7) hide show
  1. .dockerignore +31 -0
  2. Dockerfile +27 -0
  3. api.py +26 -0
  4. inteligencia.py +69 -0
  5. main.py +129 -0
  6. requirements.txt +0 -0
  7. yolov8m.pt +3 -0
.dockerignore ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 1. Segurança (O MAIS IMPORTANTE)
2
+ .env
3
+ .git
4
+ .gitignore
5
+
6
+ # 2. Lixo do Python (Compilados locais que quebram no Linux)
7
+ __pycache__
8
+ *.pyc
9
+ *.pyo
10
+ *.pyd
11
+
12
+ # 3. Ambiente Virtual (O erro mais comum)
13
+ # Nunca envie sua pasta venv, o Docker cria o ambiente dele sozinho!
14
+ venv/
15
+ env/
16
+ .venv/
17
+
18
+ # 4. Configurações de IDE (VS Code, Pycharm)
19
+ .vscode/
20
+ .idea/
21
+
22
+ # 5. Arquivos temporários gerados pelo seu código
23
+ # Não precisamos das fotos de teste ou recortes no servidor
24
+ teste/
25
+ recortes/
26
+ temp_envio.jpg
27
+ *.jpg
28
+ *.png
29
+
30
+ # 6. Logs e pastas do YOLO (Ultralytics cria a pasta 'runs')
31
+ runs/
Dockerfile ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Usa uma imagem Python leve
2
+ FROM python:3.10-slim
3
+
4
+ # Define o diretório de trabalho
5
+ WORKDIR /app
6
+
7
+ # Instala dependências do sistema (necessário para OpenCV/EasyOCR)
8
+ RUN apt-get update && apt-get install -y \
9
+ libgl1-mesa-glx \
10
+ libglib2.0-0 \
11
+ && rm -rf /var/lib/apt/lists/*
12
+
13
+ # Copia os requisitos e instala
14
+ COPY requirements.txt .
15
+ RUN pip install --no-cache-dir -r requirements.txt
16
+
17
+ # Copia o resto do código
18
+ COPY . .
19
+
20
+ # Cria a pasta de usuário (Hugging Face exige permissão especial)
21
+ RUN useradd -m -u 1000 user
22
+ USER user
23
+ ENV HOME=/home/user \
24
+ PATH=/home/user/.local/bin:$PATH
25
+
26
+ # Comando para rodar na porta 7860 (Padrão do Hugging Face)
27
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
api.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, UploadFile, File
2
+ import shutil
3
+ import os
4
+
5
+ # AQUI ESTÁ O SEGREDO: Importamos sua função pronta!
6
+ from inteligencia import analisar_imagem_agora
7
+
8
+ app = FastAPI()
9
+
10
+ @app.post("/analisar")
11
+ async def api_analisar(arquivo: UploadFile = File(...)):
12
+ # 1. Salva o arquivo que chegou via internet num temp
13
+ nome_temp = f"temp_{arquivo.filename}"
14
+
15
+ with open(nome_temp, "wb") as buffer:
16
+ shutil.copyfileobj(arquivo.file, buffer)
17
+
18
+ # 2. Chama a SUA inteligência que já estava pronta
19
+ # Ela vai fazer o OCR, chamar o Gemini e devolver o resultado
20
+ resultado = analisar_imagem_agora(nome_temp)
21
+
22
+ # 3. Limpa a sujeira (apaga a imagem temp)
23
+ os.remove(nome_temp)
24
+
25
+ # 4. Devolve o resultado para o cliente (main.py ou app)
26
+ return resultado
inteligencia.py ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import google.generativeai as genai
2
+ import easyocr
3
+ from dotenv import load_dotenv
4
+ import os
5
+ import cv2 # ADICIONE ESTA LINHA
6
+
7
+ # --- CONFIGURAÇÕES (Carregam apenas uma vez) ---
8
+ load_dotenv()
9
+ chave_api = os.getenv("GOOGLE_API_KEY") # <--- RECOLOQUE SUA CHAVE AQUI
10
+ genai.configure(api_key=chave_api)
11
+ model = genai.GenerativeModel('gemini-2.5-flash')
12
+
13
+ print("Inicializando OCR e IA... (Isso acontece só uma vez)")
14
+ # Mantenha gpu=False se não tiver CUDA configurado
15
+ reader = easyocr.Reader(['pt', 'en'], gpu=False)
16
+
17
+ def analisar_imagem_agora(caminho_imagem):
18
+ print(f"\n--- 🧠 INICIANDO ANÁLISE: {caminho_imagem} ---")
19
+
20
+ # 1. OCR (LEITURA) - FORMA MAIS SEGURA
21
+ try:
22
+ print("Executando OCR...")
23
+ # CORREÇÃO: Carregar e converter para escala de cinza
24
+ img = cv2.imread(caminho_imagem)
25
+ img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
26
+
27
+ resultados_brutos = reader.readtext(img_gray)
28
+
29
+ # Vamos extrair só o texto manualmente para não dar erro de desempacotamento
30
+ lista_textos = []
31
+ for item in resultados_brutos:
32
+ # O formato do item é: ( [caixa], "texto lido", confiança )
33
+ if len(item) >= 2:
34
+ texto = item[1]
35
+ lista_textos.append(texto)
36
+ texto_detectado = " ".join(lista_textos)
37
+ print(f"📖 Texto Bruto: {texto_detectado}")
38
+
39
+ if len(texto_detectado) < 2:
40
+ print("⚠️ Pouco texto. A identificação pode falhar.")
41
+ return
42
+
43
+ except Exception as e:
44
+ print(f"Erro no OCR: {e}")
45
+ return
46
+
47
+
48
+
49
+ # 2. IA (INTERPRETAÇÃO)
50
+ prompt = f"""
51
+ Analise este texto de rótulo de produto: "{texto_detectado}"
52
+ Identifique: Categoria | Marca | Detalhes.
53
+ Responda apenas nesse formato e não escreva textos longos. Se não souber, diga "Não identificado".
54
+ """
55
+
56
+ try:
57
+ response = model.generate_content(prompt)
58
+ print(f"🤖 RESPOSTA IA: {response.text}") # Isso aparece no servidor (OK)
59
+
60
+ # --- O SEGREDO ESTÁ AQUI: TEM QUE TER O RETURN ---
61
+ return {
62
+ "texto_lido": texto_detectado,
63
+ "analise_ia": response.text
64
+ }
65
+ # -------------------------------------------------
66
+
67
+ except Exception as e:
68
+ print(f"Erro na IA: {e}")
69
+ return {"texto_lido": "Erro", "analise_ia": "Erro na IA"}
main.py ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ from ultralytics import YOLO
3
+ import os
4
+ import time
5
+ import requests # <--- ADICIONADO: Necessário para falar com a API
6
+
7
+ # --- REMOVIDO: from inteligencia import ...
8
+ # Não importamos mais a inteligência aqui, pois ela roda no servidor (api.py)
9
+
10
+ # Cria pastas para organizar
11
+ os.makedirs('resultados/recortes', exist_ok=True)
12
+
13
+ print("Carregando modelo YOLO (Visão)... aguarde.")
14
+ model = YOLO('yolov8m.pt')
15
+ print('Modelo carregado com sucesso!')
16
+
17
+ def read_image():
18
+ cap = cv2.VideoCapture(0)
19
+ cap.set(3, 1280)
20
+ cap.set(4, 720)
21
+
22
+ print('\n--- SISTEMA CLIENTE INICIADO ---')
23
+ print('📷 Aponte para o produto.')
24
+ print('📡 O processamento será feito pela API.')
25
+ print('🔘 Pressione "ESPAÇO" para enviar.')
26
+ print('❌ Pressione "q" para SAIR.\n')
27
+
28
+ while True:
29
+ success, frame = cap.read()
30
+ if not success:
31
+ print('Falha ao capturar imagem.')
32
+ break
33
+
34
+ # Faz a detecção
35
+ results = model.predict(frame, conf=0.5, verbose=False)
36
+
37
+ frame_anotado = frame.copy()
38
+ recorte_atual = None
39
+
40
+ # Loop por cada detecção
41
+ for box in results[0].boxes:
42
+ classe_id = int(box.cls[0])
43
+ name = model.names[classe_id]
44
+
45
+ # Filtro de pessoas
46
+ if name == 'person':
47
+ continue
48
+
49
+ confianca = float(box.conf[0])
50
+
51
+ if confianca > 0.6:
52
+ x1, y1, x2, y2 = map(int, box.xyxy[0])
53
+
54
+ # Desenha o retângulo
55
+ cv2.rectangle(frame_anotado, (x1, y1), (x2, y2), (0, 255, 0), 2)
56
+
57
+ texto = f"{name.upper()} {confianca:.2f}"
58
+ cv2.putText(frame_anotado, texto, (x1, y1 - 10),
59
+ cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
60
+
61
+ # Prepara o recorte com limites seguros
62
+ h, w, _ = frame.shape
63
+ x1, y1 = max(0, x1), max(0, y1)
64
+ x2, y2 = min(w, x2), min(h, y2)
65
+
66
+ recorte_atual = frame[y1:y2, x1:x2]
67
+
68
+ cv2.putText(frame_anotado, "PRODUTO DETECTADO! (Espaco para Enviar)", (50, 50),
69
+ cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
70
+
71
+ cv2.imshow("Camera Cliente", frame_anotado)
72
+
73
+ key = cv2.waitKey(1)
74
+ if key == ord('q'):
75
+ break
76
+ elif key == 32: # ESPAÇO
77
+ if recorte_atual is not None:
78
+ # Salva temporariamente para envio
79
+ nome_arquivo = "temp_envio.jpg"
80
+ cv2.imwrite(nome_arquivo, recorte_atual)
81
+
82
+ print("📡 Enviando imagem para a API...")
83
+
84
+ try:
85
+ url = "http://127.0.0.1:8000/analisar"
86
+
87
+ # CORREÇÃO DO ARQUIVO ABERTO:
88
+ # Usamos 'with open' para garantir que o arquivo feche após o envio
89
+ with open(nome_arquivo, 'rb') as f:
90
+ arquivos = {'arquivo': f}
91
+ resposta = requests.post(url, files=arquivos)
92
+
93
+ # Agora o arquivo já está fechado, o código pode continuar
94
+
95
+ if resposta.status_code == 200:
96
+ dados = resposta.json()
97
+
98
+ # Verifica se dados não veio vazio
99
+ if dados:
100
+ print("\n" + "="*40)
101
+ print(f"📖 Texto Lido: {dados.get('texto_lido')}")
102
+ print(f"🤖 Análise IA: {dados.get('analise_ia')}")
103
+ print("="*40 + "\n")
104
+ else:
105
+ print("⚠️ A API retornou dados vazios.")
106
+ else:
107
+ print(f"❌ Erro na API: {resposta.status_code}")
108
+
109
+ except Exception as e:
110
+ print(f"❌ Erro: {e}")
111
+
112
+ # Agora sim pode deletar, pois o 'with open' já fechou o arquivo
113
+ if os.path.exists(nome_arquivo):
114
+ try:
115
+ os.remove(nome_arquivo)
116
+ except:
117
+ pass # Se não der pra deletar, tudo bem, ele sobrescreve na próxima
118
+ else:
119
+ print("⚠️ Nada detectado para enviar.")
120
+
121
+ cap.release()
122
+ cv2.destroyAllWindows()
123
+ # Limpa o arquivo temporário ao sair, se existir
124
+ if os.path.exists("temp_envio.jpg"):
125
+ os.remove("temp_envio.jpg")
126
+ print("Programa encerrado.")
127
+
128
+ if __name__ == "__main__":
129
+ read_image()
requirements.txt ADDED
Binary file (258 Bytes). View file
 
yolov8m.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5d4a90cdc7a21786cc59cd19778e9eafff836df9e2da32524737c7ee6efe4fe5
3
+ size 52136884