#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 🗄️ SCRIPT DE MIGRAÇÃO - LSTM MEMORY SYSTEM TABLES Descrição: Cria as tabelas necessárias para o LSTM Memory System Data: Junho 2026 Autor: Akira Development Team Uso: python migrate_lstm_tables.py # Criar tabelas python migrate_lstm_tables.py --drop # Dropar e recriar (CUIDADO!) python migrate_lstm_tables.py --check # Verificar se existem """ import sqlite3 import argparse import sys from pathlib import Path from typing import Optional import logging # Setup logging logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s' ) logger = logging.getLogger(__name__) class LSTMTablesMigration: """Gerencia migração de tabelas LSTM.""" def __init__(self, db_path: str = "database.db"): """ Inicializa migração. Args: db_path: Caminho para o banco de dados """ self.db_path = db_path self.conn = None def connect(self) -> bool: """Conecta ao banco de dados.""" try: self.conn = sqlite3.connect(self.db_path) self.conn.row_factory = sqlite3.Row logger.info(f"✅ Conectado ao banco: {self.db_path}") return True except Exception as e: logger.error(f"❌ Erro ao conectar: {e}") return False def close(self): """Fecha conexão ao banco.""" if self.conn: self.conn.close() logger.info("✅ Conexão fechada") def table_exists(self, table_name: str) -> bool: """Verifica se tabela existe.""" try: cursor = self.conn.cursor() cursor.execute( "SELECT name FROM sqlite_master WHERE type='table' AND name=?", (table_name,) ) exists = cursor.fetchone() is not None logger.info(f"{'✅' if exists else '⚠️ '} Tabela '{table_name}': {'Existe' if exists else 'Não existe'}") return exists except Exception as e: logger.error(f"❌ Erro ao verificar tabela: {e}") return False def drop_tables(self): """Drop das tabelas LSTM (CUIDADO!).""" try: cursor = self.conn.cursor() logger.warning("⚠️ Dropando tabelas LSTM...") cursor.execute("DROP TABLE IF EXISTS lstm_message_links") cursor.execute("DROP TABLE IF EXISTS lstm_contexto") self.conn.commit() logger.warning("✅ Tabelas dropadas") except Exception as e: logger.error(f"❌ Erro ao dropar tabelas: {e}") self.conn.rollback() return False return True def create_lstm_contexto_table(self) -> bool: """Cria tabela lstm_contexto.""" try: cursor = self.conn.cursor() sql = """ CREATE TABLE IF NOT EXISTS lstm_contexto ( -- Identificadores context_id VARCHAR(255) PRIMARY KEY, numero_usuario VARCHAR(50) NOT NULL, -- Análise de Tópicos topic_principal VARCHAR(255), subtopicas JSON, conversation_path JSON, -- Contexto Comportamental interaction_pattern VARCHAR(50), emotional_state VARCHAR(50), -- Perguntas e Conhecimento unanswered_questions JSON, assumed_knowledge JSON, -- Qualidade e Análise last_key_message TEXT, context_switches INTEGER DEFAULT 0, contradictions JSON, -- Timestamps created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- Dados Adicionais metadata JSON, -- Índices UNIQUE(context_id), INDEX idx_usuario (numero_usuario), INDEX idx_created (created_at), INDEX idx_context_id (context_id) ) """ cursor.execute(sql) self.conn.commit() logger.info("✅ Tabela 'lstm_contexto' criada com sucesso") return True except Exception as e: logger.error(f"❌ Erro ao criar 'lstm_contexto': {e}") self.conn.rollback() return False def create_lstm_message_links_table(self) -> bool: """Cria tabela lstm_message_links.""" try: cursor = self.conn.cursor() sql = """ CREATE TABLE IF NOT EXISTS lstm_message_links ( -- Identificadores id INTEGER PRIMARY KEY AUTOINCREMENT, context_id VARCHAR(255) NOT NULL, message_id VARCHAR(255) NOT NULL, parent_message_id VARCHAR(255), -- Análise topic_changed BOOLEAN DEFAULT FALSE, context_switch_type VARCHAR(50), relevance_score FLOAT DEFAULT 0.0, -- Timestamps created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- Índices UNIQUE(context_id, message_id), INDEX idx_context (context_id), INDEX idx_message (message_id), INDEX idx_parent (parent_message_id), INDEX idx_created (created_at), -- Foreign Key (opcional) FOREIGN KEY (context_id) REFERENCES lstm_contexto(context_id) ON DELETE CASCADE ON UPDATE CASCADE ) """ cursor.execute(sql) self.conn.commit() logger.info("✅ Tabela 'lstm_message_links' criada com sucesso") return True except Exception as e: logger.error(f"❌ Erro ao criar 'lstm_message_links': {e}") self.conn.rollback() return False def verify_tables(self) -> bool: """Verifica se tabelas foram criadas corretamente.""" logger.info("\n📋 Verificando estrutura das tabelas...\n") try: cursor = self.conn.cursor() # Verificar lstm_contexto logger.info("🔍 Estrutura de 'lstm_contexto':") cursor.execute("PRAGMA table_info(lstm_contexto)") columns = cursor.fetchall() for col in columns: logger.info(f" - {col[1]}: {col[2]}") # Verificar lstm_message_links logger.info("\n🔍 Estrutura de 'lstm_message_links':") cursor.execute("PRAGMA table_info(lstm_message_links)") columns = cursor.fetchall() for col in columns: logger.info(f" - {col[1]}: {col[2]}") return True except Exception as e: logger.error(f"❌ Erro ao verificar estrutura: {e}") return False def insert_sample_data(self) -> bool: """Insere dados de sample para teste.""" logger.info("\n📝 Inserindo dados de sample...\n") try: cursor = self.conn.cursor() # Sample data para lstm_contexto cursor.execute(""" INSERT OR IGNORE INTO lstm_contexto ( context_id, numero_usuario, topic_principal, subtopicas, conversation_path, interaction_pattern, emotional_state, unanswered_questions, assumed_knowledge ) VALUES ( 'belmira:None:pv', 'belmira', 'anemia falciforme', '["definição", "genética", "hemoglobina"]', '["intro", "definição"]', 'perguntador', 'curiosidade', '["cura", "tratamento"]', '["o -que é anemia", "é doença genética"]' ) """) # Sample data para lstm_message_links cursor.execute(""" INSERT OR IGNORE INTO lstm_message_links ( context_id, message_id, parent_message_id, topic_changed, relevance_score ) VALUES ( 'belmira:None:pv', 'msg_001', NULL, FALSE, 1.0 ) """) self.conn.commit() logger.info("✅ Dados de sample inseridos") return True except Exception as e: logger.error(f"❌ Erro ao inserir dados: {e}") self.conn.rollback() return False def get_table_stats(self) -> bool: """Mostra estatísticas das tabelas.""" logger.info("\n📊 Estatísticas das Tabelas:\n") try: cursor = self.conn.cursor() # Contar registros em lstm_contexto cursor.execute("SELECT COUNT(*) FROM lstm_contexto") count = cursor.fetchone()[0] logger.info(f" lstm_contexto: {count} registros") # Contar registros em lstm_message_links cursor.execute("SELECT COUNT(*) FROM lstm_message_links") count = cursor.fetchone()[0] logger.info(f" lstm_message_links: {count} registros") return True except Exception as e: logger.error(f"❌ Erro ao contar registros: {e}") return False def run_migration(self, drop_first: bool = False): """Executa migração completa.""" logger.info("=" * 60) logger.info("🚀 INICIANDO MIGRAÇÃO - LSTM MEMORY SYSTEM") logger.info("=" * 60) # Conectar ao banco if not self.connect(): return False # Dropar tabelas se solicitado if drop_first: logger.warning("⚠️ ATENÇÃO: Você escolheu dropar as tabelas!") if not self.drop_tables(): self.close() return False # Criar tabelas logger.info("\n📝 Criando tabelas...") if not self.create_lstm_contexto_table(): self.close() return False if not self.create_lstm_message_links_table(): self.close() return False # Verificar se foram criadas logger.info("\n✅ Verificando tabelas criadas...") self.table_exists("lstm_contexto") self.table_exists("lstm_message_links") # Inserir sample data if not drop_first: # Não inserir se dropar self.insert_sample_data() # Mostrar estrutura self.verify_tables() # Mostrar stats self.get_table_stats() # Fechar conexão self.close() logger.info("\n" + "=" * 60) logger.info("✅ MIGRAÇÃO CONCLUÍDA COM SUCESSO!") logger.info("=" * 60) return True def main(): """Função principal.""" parser = argparse.ArgumentParser( description='🗄️ Script de Migração - LSTM Memory System Tables' ) parser.add_argument( '--db', type=str, default='database.db', help='Caminho para o banco de dados (default: database.db)' ) parser.add_argument( '--drop', action='store_true', help='Dropar tabelas LSTM antes de recriar (CUIDADO!)' ) parser.add_argument( '--check', action='store_true', help='Apenas verificar se tabelas existem' ) args = parser.parse_args() # Criar instância de migração migration = LSTMTablesMigration(db_path=args.db) # Modo check if args.check: if not migration.connect(): return 1 logger.info("🔍 Verificando tabelas LSTM...") lstm_contexto_exists = migration.table_exists('lstm_contexto') lstm_message_links_exists = migration.table_exists('lstm_message_links') migration.close() if lstm_contexto_exists and lstm_message_links_exists: logger.info("✅ Todas as tabelas LSTM existem!") return 0 else: logger.warning("⚠️ Nem todas as tabelas LSTM existem. Execute sem --check") return 1 # Modo migração completa if migration.run_migration(drop_first=args.drop): return 0 else: return 1 if __name__ == '__main__': sys.exit(main())