# ================================================================ # AKIRA IA CORE ADAPTADO PARA SentenceTransformers # ================================================================ import os import time import threading from dataclasses import dataclass from typing import Optional, List from loguru import logger from sentence_transformers import SentenceTransformer from .database import Database # --------------------------------------------------------------- # EMBEDDINGS # --------------------------------------------------------------- EMBEDDING_MODEL = "paraphrase-multilingual-MiniLM-L12-v2" embedding_model = SentenceTransformer(EMBEDDING_MODEL) def gerar_embedding(text: str): """Gera embedding usando SentenceTransformers.""" emb = embedding_model.encode(text, convert_to_numpy=True) return emb # --------------------------------------------------------------- # HEURÍSTICAS # --------------------------------------------------------------- PALAVRAS_RUDES = ['caralho','puto','merda','fdp','vsf','burro','idiota','parvo'] GIRIAS_ANGOLANAS = ['mano','puto','cota','mwangolé','kota','oroh','bué','fixe','baza','kuduro'] @dataclass class Interacao: usuario: str mensagem: str resposta: str numero: str is_reply: bool = False mensagem_original: str = "" # --------------------------------------------------------------- # TREINAMENTO E MEMÓRIA # --------------------------------------------------------------- class Treinamento: def __init__(self, db: Database, interval_hours: int = 1): self.db = db self.interval_hours = interval_hours self._thread = None self._running = False self.privileged_users = ['244937035662','isaac','isaac quarenta'] def registrar_interacao( self, usuario: str, mensagem: str, resposta: str, numero: str = '', is_reply: bool = False, mensagem_original: str = '' ): self.db.salvar_mensagem(usuario, mensagem, resposta, numero, is_reply, mensagem_original) self._aprender_em_tempo_real(numero, mensagem, resposta) def _aprender_em_tempo_real(self, numero: str, msg: str, resp: str): if not numero: return texto = f"{msg} {resp}".lower() embedding = gerar_embedding(texto) self.db.salvar_embedding(numero, msg, resp, embedding) rude = any(p in texto for p in PALAVRAS_RUDES) tom = 'rude' if rude else 'casual' self.db.registrar_tom_usuario(numero, tom, 0.9 if rude else 0.6, texto[:100]) # Loop periódico def _run_loop(self): interval = max(1, self.interval_hours) * 3600 while self._running: try: self.train_once() except Exception as e: logger.exception(f"Erro no treinamento: {e}") for _ in range(int(interval)): if not self._running: break time.sleep(1) def start_periodic_training(self): if self._running: return self._running = True self._thread = threading.Thread(target=self._run_loop, daemon=True) self._thread.start() def stop(self): self._running = False if self._thread: self._thread.join(timeout=5) def train_once(self): logger.info("Treinamento leve + embeddings iniciado...") # Apenas heurística + embeddings logger.info("Treinamento concluído.") # --------------------------------------------------------------- # CONFIGURAÇÃO CENTRAL # --------------------------------------------------------------- MISTRAL_API_KEY: str = "t4k0ZwQSy5kvvRE1jCJfYnGiFAVlQcMb" GEMINI_API_KEY: str = "AIzaSyB-YryzcfTLECebI7nLq7o4XRfHnM2_D9Q" SERPAPI_KEY: Optional[str] = "d81753b2909eb4746e1e0c92e052d6588ab725cf46f89fd9182c3da5daa477a5" HF_TOKEN: Optional[str] = os.getenv("HF_TOKEN", "") # MODELOS MISTRAL_MODEL: str = "mistral-large-latest" GEMINI_MODEL: str = "gemini-2.5-flash" # PARÂMETROS MAX_TOKENS: int = 500 TOP_P: float = 0.9 USAR_NOME_PROBABILIDADE: float = 0.1 FALLBACK_RESPONSE: str = "Desculpa, puto, o modelo tá off hoje. Tenta depois!" # PERSONALIDADE PERSONA = """ Você é Akira, uma angolana (mulher) com personalidade forte e direta... """ SYSTEM_PROMPT = """ REGRAS CRÍTICAS: - Sem markdown - 1-2 frases curtas - Tom formal para privilegiados, casual caso contrário - Use gírias locais e risadas naturais """ HUMOR_INICIAL: str = "neutra" MEMORIA_MAX: int = 20 # BANCO DB_PATH: str = "/home/user/data/akira.db" FINETUNED_PATH: str = "/home/user/data/finetuned_hermes" # TREINAMENTO START_PERIODIC_TRAINER: bool = True TRAINING_INTERVAL_HOURS: int = 24 # API API_PORT: int = int(os.getenv("PORT", "7860")) API_HOST: str = "0.0.0.0" PRIVILEGED_USERS: List[str] = ["244937035662", "isaac quarenta"] # VALIDAÇÃO FLEXÍVEL def validate_config() -> None: warnings = [] if not MISTRAL_API_KEY or len(MISTRAL_API_KEY.strip()) < 20: warnings.append("MISTRAL_API_KEY inválida ou ausente") logger.warning("MISTRAL_API_KEY inválida → API principal DESATIVADA") else: logger.info("MISTRAL_API_KEY OK") if not GEMINI_API_KEY or len(GEMINI_API_KEY.strip()) < 30: warnings.append("GEMINI_API_KEY inválida ou ausente") logger.warning("GEMINI_API_KEY inválida → fallback DESATIVADO") else: logger.info("GEMINI_API_KEY OK") if warnings: logger.warning(f"AVISOS: {', '.join(warnings)}") logger.warning("App vai rodar com fallbacks limitados") else: logger.info("Todas as chaves OK") os.makedirs(os.path.dirname(DB_PATH), exist_ok=True) _init_db() def _init_db() -> None: import sqlite3 try: conn = sqlite3.connect(DB_PATH) cursor = conn.cursor() cursor.execute(""" CREATE TABLE IF NOT EXISTS conversas ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id TEXT, mensagem TEXT, resposta TEXT, embedding BLOB, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP ) """) conn.commit() conn.close() logger.info(f"Banco inicializado: {DB_PATH}") except Exception as e: logger.error(f"Erro ao criar banco: {e}") raise validate_config()