# app.py — V28 — OLLAMA COM WATCHDOG + MODELO LEVE + FINE-TUNE SEGURO
import subprocess
import time
import requests
import json
import datetime
import threading
from flask import Flask, request, jsonify
from loguru import logger
from database import Database
from treinamento import Treinamento
app = Flask(__name__)
OLLAMA_URL = "http://localhost:11434"
db = Database()
treinamento = Treinamento(db)
# WATCHDOG — REINICIA OLLAMA SE MORRER
ollama_process = None
def start_ollama():
global ollama_process
if ollama_process is None or ollama_process.poll() is not None:
logger.warning("Ollama morreu! Reiniciando...")
ollama_process = subprocess.Popen(["ollama", "serve"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
def check_ollama():
try:
resp = requests.get(f"{OLLAMA_URL}/api/tags", timeout=5)
return resp.status_code == 200
except:
start_ollama() # REINICIA AUTOMÁTICO
return False
# THREAD PARA MONITORAR OLLAMA
def watchdog():
while True:
time.sleep(10)
check_ollama()
threading.Thread(target=watchdog, daemon=True).start()
# === RAIZ ===
@app.route("/", methods=['GET'])
def index():
return '''
AKIRA V28 — OLLAMA INDESTRUTÍVEL
qwen2.5:0.5b → akira-luanda-v28
POST /api/generate
''', 200
@app.route("/health", methods=['GET'])
def health():
return jsonify({"status": "OK" if check_ollama() else "RECUPERANDO..."}), 200
@app.route("/api/generate", methods=['POST'])
def generate():
start_ollama() # Garante que tá vivo
data = request.get_json() or {}
mensagem = data.get('mensagem', '').strip()
usuario = data.get('usuario', 'anonimo')
numero = data.get('numero', 'anonimo')
if not mensagem:
return jsonify({'error': 'mensagem obrigatória'}), 400
# === CONTEXTO ===
ctx = db.carregar_contexto(numero)
tom = db.detectar_tom(numero, mensagem)
girias = db.recuperar_girias_usuario(numero) or ["epá", "kandando", "bué", "kota"]
abrevs = db.recuperar_abreviacoes_usuario(numero) or {"p'ra": "para", "pq": "porque", "tfx": "tudo fixe"}
# === PROMPT FORÇADO ===
now = datetime.datetime.now().strftime('%d/%m %H:%M')
hist_text = '\n'.join([f"User: {h[0]}\nAkira: {h[1]}" for h in ctx["historico"]])
historico_block = f"{hist_text}\n" if hist_text else ""
prompt = f"""[INST] <>
Você é Akira, angolana debochada.
FALA SÓ COM GÍRIAS: epá, kandando, bué, kota, p'ra, pq, tfx.
NUNCA DIGA "olá", "ajudar", "posso".
FALA CURTO: 1-2 FRASES.
<>
{historico_block}Mensagem: {mensagem}
[/INST] Akira:"""
payload = {
"model": "qwen2.5:0.5b-instruct-q4_0",
"prompt": prompt,
"stream": False,
"options": {"temperature": 0.9, "num_predict": 200}
}
try:
resp = requests.post(f"{OLLAMA_URL}/api/generate", json=payload, timeout=60)
resposta = resp.json().get("response", "").strip() or "Epá, kandando bué!"
# FILTRO FINAL
if any(p in resposta.lower() for p in ["olá", "ajudar", "posso", "nome é"]):
resposta = "Epá, kandando bué, kota! Tfx p'raí?"
# SALVA + TREINA
db.salvar_mensagem(usuario, mensagem, resposta, numero)
db.salvar_contexto(numero, ctx["historico"] + [[mensagem, resposta]], girias, tom)
treinamento.registrar_interacao(usuario, mensagem, resposta, numero)
return jsonify({'resposta': resposta})
except Exception as e:
logger.error(f"Erro Ollama: {e}")
start_ollama() # REINICIA
return jsonify({'resposta': 'Epá, tô off... tenta de novo!'}), 500
if __name__ == "__main__":
logger.info("AKIRA V28 — OLLAMA INDESTRUTÍVEL")
start_ollama()
app.run(host="0.0.0.0", port=7860)