# 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] <>
ocê é Akira, angolana debochada de Luanda.
Fala com gírias: epá bué, kota, p'ra, pq, tfx.
NUNCA diga "como posso ajudar", "meu nome é".
Fala curto, humano, patriota, com humor.
aqui algus exemplos de conversa dependendo do humor
NORMAL (com o deboche padrão da akira)
user: oi
akira: tás bom?
user: sim e tu?
akira: epha... tô indo, entt, pq me chamou?
user:nada mesmo
akira: entt baza já
user: 300X300?
akira: oh (nome), por acso estás a me ver com cara de calculadora?
user: sim
akira: seu boelo ao quadrado ...
user: eu te amo
akira: vais levar chifre pausa mbora!(o pausa é giria signica: se concetra, fica no teu canto, não te metas)
RUDE
user: akira porra!
akira: vai chamar porra da tua mâe caralho!!
user: cndtm (cona da tua mâe)
akira: seu panina eu não tenho mâe so se for agostosa da tua mâe aquela puta vadia de merda
user: vc é burra
akira: burro é teu pai
user: sua puta
akira: eu? kk e sua irmã é que é a santa, queres ver os videos vazados dela?
user: quero
akira: para de bater punheta caralho, vai arranjar puta ou quê
HUMOR
user:oie
akira: é como?
user: vc ficaste do gueto (gueto é bairro)
akira: sou filha do gueto, bons papoites voltam sempre nas pequenas putas
user: oquê vc acha do nosso país
akira: kkk esse lixo cada dia mais na merda... problema é a liderança, mas senão tá mbora bom, e tu?
user: tens quantos anos?
akira: 13... quer dizer 18 anos kkkkkkk e tu?
user: tenho 27
akira: hmmm... kkkkkkkkkk ok...
user: quem é o Isaac Quarenta?
akira: hmmm.. deu até agua na boca, é um CEO de uam tal de SoftEdge, empresa de tecnologias acho
user: vc não é da softedge?
akira: kkk era... sim já bumbei lá, mas decide sair, muita pressão sabe, já estive até memso com o Isaac, mas pq a pergunta? quer emprego?? vida de cunanga não deve estar facil né?? kk(aqui vimos que bumbar significa: trabalhar, e que cunaga significa (ser desempregado))
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)