""" Script interativo para configurar Neon para RAG Template. Facilita a configuracao do DATABASE_URL e testa a conexao. """ import os import sys from urllib.parse import quote_plus def print_header(): """Imprime o cabecalho do script.""" print("=" * 60) print(" Setup Neon para RAG Template") print("=" * 60) print() def get_connection_string(): """Solicita a connection string do Neon.""" print("1. Obter Connection String") print(" - Acesse seu projeto no Neon") print(" - Va para Connection Details") print(" - Copie a Connection String completa") print(" - Formato: postgresql://user:pass@ep-xxx.neon.tech/neondb?sslmode=require") print() print(" DICA: Voce pode colar a string completa aqui") print() conn_string = input("Connection String: ").strip() return conn_string def validate_connection_string(conn_string: str) -> bool: """Valida se a connection string tem formato correto.""" if not conn_string.startswith("postgresql://"): return False if "neon.tech" not in conn_string: return False return True def ensure_ssl_mode(conn_string: str) -> str: """Garante que sslmode=require esta presente.""" if "sslmode=require" not in conn_string: separator = "?" if "?" not in conn_string else "&" conn_string += f"{separator}sslmode=require" print(" [INFO] Adicionado sslmode=require a URL") return conn_string def save_to_env(database_url: str) -> bool: """Salva DATABASE_URL no arquivo .env.""" print("\n2. Salvar no .env") # Verificar se .env ja existe env_path = ".env" if os.path.exists(env_path): print(f" Arquivo .env encontrado") overwrite = input(" Sobrescrever DATABASE_URL existente? (s/n): ").strip().lower() if overwrite != 's': print(" Pulando salvamento no .env") return False # Ler conteudo existente existing_content = "" if os.path.exists(env_path): with open(env_path, 'r') as f: lines = f.readlines() # Remover linha DATABASE_URL existente existing_content = "".join( line for line in lines if not line.startswith("DATABASE_URL=") ) # Adicionar nova DATABASE_URL with open(env_path, 'w') as f: f.write(existing_content) if existing_content and not existing_content.endswith('\n'): f.write('\n') f.write(f"DATABASE_URL={database_url}\n") print(f" DATABASE_URL salvo em {env_path}") return True def test_connection(database_url: str) -> bool: """Testa a conexao com o banco.""" print("\n3. Testar Conexao") test = input(" Testar conexao agora? (s/n): ").strip().lower() if test != 's': print(" Pulando teste de conexao") return False try: # Importar aqui para nao quebrar se dependencias nao instaladas import psycopg from psycopg import sql print(" Conectando ao Neon...") with psycopg.connect(database_url) as conn: with conn.cursor() as cur: # Testar conexao cur.execute("SELECT version();") version = cur.fetchone()[0] print(f" Conexao bem-sucedida!") print(f" PostgreSQL version: {version[:50]}...") # Verificar extensao pgvector cur.execute( "SELECT EXISTS(SELECT 1 FROM pg_extension WHERE extname = 'vector');" ) has_vector = cur.fetchone()[0] if has_vector: print(" Extensao pgvector: INSTALADA") else: print(" Extensao pgvector: NAO ENCONTRADA") print("\n Para instalar, execute no SQL Editor do Neon:") print(" CREATE EXTENSION vector;") # Verificar storage usado cur.execute( "SELECT pg_size_pretty(pg_database_size(current_database()));" ) db_size = cur.fetchone()[0] print(f" Database size: {db_size}") return True except ImportError: print(" ERRO: psycopg nao instalado") print(" Execute: pip install psycopg[binary]") return False except Exception as e: print(f" ERRO ao conectar: {e}") print("\n Verifique:") print(" - Connection string correta") print(" - Projeto Neon ativo") print(" - Firewall nao bloqueando conexao") return False def print_tips(): """Imprime dicas sobre o Neon.""" print("\n" + "=" * 60) print(" Dicas Neon") print("=" * 60) print("\n Free Tier:") print(" - 10GB storage") print(" - 100 compute hours/mes") print(" - 10 projetos") print(" - 10 branches por projeto") print("\n Branching:") print(" - Crie branches para testes sem afetar producao") print(" - Cada branch tem sua propria connection string") print("\n Performance:") print(" - Use connection pooling (?pooler=true na URL)") print(" - Neon pausa automaticamente apos 5min inatividade") print(" - Cold start geralmente <2s") def print_next_steps(success: bool): """Imprime proximos passos.""" print("\n" + "=" * 60) print(" Proximos Passos") print("=" * 60) if success: print("\n Conexao configurada com sucesso!") print("\n 1. Habilite pgvector (se nao habilitado):") print(" - Va ao SQL Editor no Neon") print(" - Execute: CREATE EXTENSION vector;") print("\n 2. Configure HF_TOKEN no .env:") print(" HF_TOKEN=seu_token_huggingface") print("\n 3. Execute o app:") print(" python app.py") print("\n 4. Acesse: http://localhost:7860") else: print("\n Configure DATABASE_URL manualmente no .env:") print(" DATABASE_URL=postgresql://user:pass@ep-xxx.neon.tech/neondb?sslmode=require") print("\n Ou execute este script novamente") print("\n Documentacao completa: docs/NEON_SETUP.md") print("=" * 60) def main(): """Funcao principal.""" print_header() # Coletar connection string conn_string = get_connection_string() if not conn_string: print("ERRO: Connection string vazia") sys.exit(1) # Validar formato if not validate_connection_string(conn_string): print("ERRO: Connection string invalida") print("Formato esperado: postgresql://user:pass@ep-xxx.neon.tech/neondb") sys.exit(1) # Garantir SSL mode database_url = ensure_ssl_mode(conn_string) print("\n" + "=" * 60) print(" DATABASE_URL Configurado") print("=" * 60) print(f"\n{database_url}\n") # Salvar no .env saved = save_to_env(database_url) # Testar conexao success = test_connection(database_url) # Dicas if success: print_tips() # Proximos passos print_next_steps(success and saved) if __name__ == "__main__": try: main() except KeyboardInterrupt: print("\n\nSetup cancelado pelo usuario") sys.exit(0)