Spaces:
Running
Running
| # ================================================================ | |
| # 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'] | |
| 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 = 1000 | |
| 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() | |