// One-off: re-embed existing Chroma collections with a new embedding model. Reuses already- // stored document text + metadata + ids — does NOT re-run migrate-memory-to-chroma.ts's USER.md // parsing or extract-daily-memory.ts's LLM extraction, since only the embedding vectors need to // change, not the underlying facts. Run whenever EMBED_MODEL changes in memory-vector.ts. import { ChromaClient } from 'chromadb'; import { addVector, USER_FACTS_COLLECTION, DAILY_EXTRACTS_COLLECTION } from '../src/gateway/memory-vector'; const CHROMA_HOST = 'localhost'; const CHROMA_PORT = 8100; async function reembedCollection(name: string) { const client = new ChromaClient({ host: CHROMA_HOST, port: CHROMA_PORT }); let existing: { ids: string[]; documents: (string | null)[]; metadatas: any[] } | null = null; try { const col = await client.getCollection({ name }); const res = await col.get({ limit: 10000 }); existing = { ids: res.ids || [], documents: res.documents || [], metadatas: res.metadatas || [] }; } catch (err: any) { console.log(`[${name}] no existing collection or empty (${err.message}) — nothing to reembed`); return; } console.log(`[${name}] ${existing.ids.length}개 기존 항목 발견, 재임베딩 시작`); await client.deleteCollection({ name }); let done = 0, failed = 0; for (let i = 0; i < existing.ids.length; i++) { const id = existing.ids[i]; const text = existing.documents[i]; const metadata = existing.metadatas[i] || undefined; if (!text) continue; try { await addVector(name, { id, text, metadata }); done++; if (done % 50 === 0) console.log(`[${name}] ${done}/${existing.ids.length}...`); } catch (err: any) { failed++; console.warn(`[${name}] failed ${id}: ${err.message}`); } } console.log(`[${name}] 완료 — ${done}개 재임베딩, ${failed}개 실패`); } async function main() { await reembedCollection(USER_FACTS_COLLECTION); await reembedCollection(DAILY_EXTRACTS_COLLECTION); } main().then(() => process.exit(0)).catch(err => { console.error(err); process.exit(1); });