Files
OllaHub/scripts/init-db.ts
T
Evandro Fonseca Junior f96d4ed696 refactor(api): remove MCP marketplace cache integration
Removed dependencies on MCPCacheRepository and PulseMCPService from MCP routes to simplify installation and listing logic, avoiding reliance on potentially stale cached data and streamlining the codebase. Updated available-for-chat filter to include MCPs without explicit status.
2025-10-29 15:35:15 -03:00

192 lines
5.4 KiB
TypeScript

import Database from "better-sqlite3";
import path from "path";
import fs from "fs";
import { ensureModelExists } from "@/lib/ollama";
let db: Database.Database | null = null;
function getDatabase(): Database.Database {
if (!db) {
const dbPath = path.join(process.cwd(), "database", "ollahub.db");
// Garantir que o diretório existe
const dbDir = path.dirname(dbPath);
if (!fs.existsSync(dbDir)) {
fs.mkdirSync(dbDir, { recursive: true });
}
db = new Database(dbPath);
// Configurações de performance
db.pragma("journal_mode = WAL");
db.pragma("synchronous = NORMAL");
db.pragma("foreign_keys = ON");
db.pragma("cache_size = 10000");
db.pragma("temp_store = memory");
}
return db;
}
function runMigrations(db: Database.Database): void {
// Criar tabela de migrações
db.exec(`
CREATE TABLE IF NOT EXISTS _migrations (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
applied_at INTEGER NOT NULL
);
`);
// Verificar migrações aplicadas
const applied = db.prepare("SELECT name FROM _migrations").all() as Array<{
name: string;
}>;
const appliedNames = new Set(applied.map((m) => m.name));
// Aplicar migração inicial se não foi aplicada
if (!appliedNames.has("001_initial_schema")) {
console.log("📋 Aplicando migração: 001_initial_schema");
const schemaPath = path.join(process.cwd(), "database", "schema.sql");
const schema = fs.readFileSync(schemaPath, "utf-8");
db.exec(schema);
// Registrar migração
db.prepare("INSERT INTO _migrations (name, applied_at) VALUES (?, ?)").run(
"001_initial_schema",
Date.now()
);
console.log("✅ Migração 001_initial_schema aplicada");
}
// Aplicar migração para tabela MCP se não foi aplicada
if (!appliedNames.has("002_mcp_installations")) {
console.log("📋 Aplicando migração: 002_mcp_installations");
db.exec(`
-- Tabela para gerenciar MCPs instalados
CREATE TABLE IF NOT EXISTS mcp_installations (
id TEXT PRIMARY KEY,
owner TEXT NOT NULL,
repo TEXT NOT NULL,
name TEXT NOT NULL,
config JSON NOT NULL,
tools JSON,
installed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Índices para performance
CREATE INDEX IF NOT EXISTS idx_mcp_owner_repo ON mcp_installations(owner, repo);
CREATE INDEX IF NOT EXISTS idx_mcp_installed_at ON mcp_installations(installed_at DESC);
`);
// Registrar migração
db.prepare("INSERT INTO _migrations (name, applied_at) VALUES (?, ?)").run(
"002_mcp_installations",
Date.now()
);
console.log("✅ Migração 002_mcp_installations aplicada");
}
// Migração de marketplace removida
// Inicializar extensão vetorial se disponível
try {
const extPath = path.join(
process.cwd(),
"database",
"extensions",
"vector.so"
);
if (fs.existsSync(extPath)) {
db.loadExtension(extPath);
// Inicializar índice vetorial
db.exec(`
SELECT vector_init('embeddings', 'vector', 'type=FLOAT32,dimension=384');
`);
// Quantizar para busca mais rápida
db.exec(`
SELECT vector_quantize('embeddings', 'vector');
`);
console.log("🔍 Extensão vetorial carregada e inicializada");
} else {
console.log(
"⚠️ Extensão vetorial não encontrada - busca vetorial desabilitada"
);
}
} catch (error) {
console.log("⚠️ Erro ao carregar extensão vetorial:", error);
}
}
export async function initializeDatabase(): Promise<void> {
console.log("🔧 Inicializando banco de dados OllaHub...");
try {
// Conectar ao banco
const db = getDatabase();
// Executar migrações
runMigrations(db);
console.log("✅ Banco de dados inicializado com sucesso!");
} catch (error) {
console.error("❌ Erro ao inicializar banco de dados:", error);
throw error;
}
}
export async function initializeTitleModel(): Promise<void> {
console.log("🤖 Verificando modelo para geração de títulos...");
try {
await ensureModelExists(
"qwen2.5:0.5b",
"Este modelo será usado para gerar títulos automáticos das conversas"
);
console.log("✅ Modelo de título pronto!");
} catch (error) {
console.error("❌ Erro ao inicializar modelo de título:", error);
console.log("⚠️ Títulos de conversa podem não funcionar corretamente");
}
}
export async function initializeEmbeddingModel(): Promise<void> {
console.log("🔍 Verificando modelo para embeddings...");
try {
await ensureModelExists(
"nomic-embed-text",
"Este modelo será usado para busca vetorial das mensagens (274MB - 768 dimensões)"
);
console.log("✅ Modelo de embedding pronto!");
} catch (error) {
console.error("❌ Erro ao inicializar modelo de embedding:", error);
console.log("⚠️ Busca vetorial desabilitada - usando fallback");
}
}
// Executar se chamado diretamente
if (require.main === module) {
Promise.all([
initializeDatabase(),
initializeTitleModel(),
initializeEmbeddingModel(),
])
.then(async () => {
console.log("🎉 Inicialização concluída");
process.exit(0);
})
.catch((error) => {
console.error("💥 Falha na inicialização:", error);
process.exit(1);
});
}