memoryweave/scripts/migrate.py

147 lines
4.5 KiB
Python

#!/usr/bin/env python3
"""FAISS → LanceDB 迁移脚本
将 Python 织忆的 FAISS 索引转换为 Go 织忆的 LanceDB 格式。
用法:
python3 scripts/migrate.py \
--data-dir ~/projects/zhiyi/data \
--output-dir /var/lib/zhiyi/data
要求:
pip install lancedb numpy
"""
import argparse
import json
import os
import sys
import time
def parse_args():
p = argparse.ArgumentParser(description='FAISS → LanceDB 迁移')
p.add_argument('--data-dir', required=True, help='旧Python织忆data目录')
p.add_argument('--output-dir', default='/var/lib/zhiyi/data', help='LanceDB输出目录')
p.add_argument('--dry-run', action='store_true', help='只统计,不执行')
return p.parse_args()
def main():
args = parse_args()
# 1. 读取旧数据
distilled_file = os.path.join(args.data_dir, 'hermes-main', 'distilled', '2026-05.jsonl')
episodes_file = os.path.join(args.data_dir, 'hermes-main', 'episodes', '2026-05.jsonl')
vectors_file = os.path.join(args.data_dir, 'sbert_vectors.jsonl')
meta_file = os.path.join(args.data_dir, 'sbert_meta.json')
distilled = []
episodes = []
for fname in [distilled_file, episodes_file]:
if os.path.exists(fname):
with open(fname) as f:
for line in f:
distilled.append(json.loads(line.strip()))
# 2. 读取向量
vectors = []
meta = {}
if os.path.exists(meta_file):
with open(meta_file) as f:
meta = json.load(f)
if os.path.exists(vectors_file):
with open(vectors_file) as f:
for line in f:
vectors.append(json.loads(line.strip()))
total = len(distilled)
vector_count = len(vectors)
print(f"📊 已统计: {total} 条 distilled, {vector_count} 条向量")
if args.dry_run:
print(" (dry-run 模式,不执行)")
return
# 3. 写入 LanceDB
try:
import lancedb
import numpy as np
except ImportError:
print("❌ 需要 lancedb: pip install lancedb numpy")
sys.exit(1)
os.makedirs(args.output_dir, exist_ok=True)
db = lancedb.connect(args.output_dir)
# 创建 memories 表
try:
table = db.create_table("memories", [{
"id": "init",
"agent_id": "system",
"namespace": "default",
"content": "init",
"category": "system_fact",
"vector": [0.0]*1024,
"tier": "normal",
"quality_score": 0.0,
"recall_count": 0,
"freshness": "fresh",
"created_at": time.strftime("%Y-%m-%dT%H:%M:%SZ"),
"updated_at": time.strftime("%Y-%m-%dT%H:%M:%SZ"),
"is_deleted": False,
}])
except Exception:
table = db.open_table("memories")
# 迁移数据
migrated = 0
batch = []
for i, d in enumerate(distilled):
content = d.get('content', '') or d.get('summary', '') or ''
if not content.strip():
continue
vec = vectors[i] if i < len(vectors) else [0.0] * 1024
if isinstance(vec, dict):
vec = vec.get('vector', [0.0]*1024)
# 确保1024维
if len(vec) != 1024:
if len(vec) < 1024:
vec = vec + [0.0] * (1024 - len(vec))
else:
vec = vec[:1024]
record = {
"id": d.get('id', f'migrated_{i}'),
"agent_id": d.get('agent_id', 'hermes-main'),
"namespace": d.get('namespace', 'hermes-main'),
"content": content[:2000],
"category": d.get('category', 'general'),
"vector": vec,
"tier": "core" if d.get('importance', 0) >= 3 else "normal",
"quality_score": float(d.get('importance', 0.5)) / 5.0,
"recall_count": d.get('recall_count', 0),
"freshness": "fresh",
"created_at": d.get('created_at', time.strftime("%Y-%m-%dT%H:%M:%SZ")),
"updated_at": d.get('updated_at', d.get('created_at', time.strftime("%Y-%m-%dT%H:%M:%SZ"))),
"is_deleted": False,
}
batch.append(record)
if len(batch) >= 100:
table.add(batch)
migrated += len(batch)
batch = []
print(f" ✓ 已迁移 {migrated}/{total}")
if batch:
table.add(batch)
migrated += len(batch)
print(f"\n✅ 迁移完成: {migrated} 条记录 → {args.output_dir}")
if __name__ == '__main__':
main()