160 lines
5.8 KiB
Python
Executable File
160 lines
5.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Enhanced memory storage with metadata support
|
|
Usage: store_memory.py "Memory text" [--tags tag1,tag2] [--importance medium]
|
|
[--confidence high] [--source user|inferred|external]
|
|
[--verified] [--expires 2026-03-01] [--related id1,id2]
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
import sys
|
|
import urllib.request
|
|
import uuid
|
|
from datetime import datetime, timedelta
|
|
|
|
QDRANT_URL = "http://10.0.0.40:6333"
|
|
COLLECTION_NAME = "kimi_memories"
|
|
OLLAMA_URL = "http://10.0.0.10:11434/v1"
|
|
|
|
def get_embedding(text):
|
|
"""Generate embedding using snowflake-arctic-embed2 via Ollama"""
|
|
data = json.dumps({
|
|
"model": "snowflake-arctic-embed2",
|
|
"input": text[:8192]
|
|
}).encode()
|
|
|
|
req = urllib.request.Request(
|
|
f"{OLLAMA_URL}/embeddings",
|
|
data=data,
|
|
headers={"Content-Type": "application/json"}
|
|
)
|
|
|
|
try:
|
|
with urllib.request.urlopen(req, timeout=30) as response:
|
|
result = json.loads(response.read().decode())
|
|
return result["data"][0]["embedding"]
|
|
except Exception as e:
|
|
print(f"Error generating embedding: {e}", file=sys.stderr)
|
|
return None
|
|
|
|
def store_memory(text, embedding, tags=None, importance="medium", date=None,
|
|
source="conversation", confidence="high", source_type="user",
|
|
verified=True, expires_at=None, related_memories=None):
|
|
"""Store memory in Qdrant with enhanced metadata"""
|
|
|
|
if date is None:
|
|
date = datetime.now().strftime("%Y-%m-%d")
|
|
|
|
# Generate a UUID for the point ID
|
|
point_id = str(uuid.uuid4())
|
|
|
|
# Build payload with all metadata
|
|
payload = {
|
|
"text": text,
|
|
"date": date,
|
|
"tags": tags or [],
|
|
"importance": importance,
|
|
"source": source,
|
|
"confidence": confidence, # high/medium/low
|
|
"source_type": source_type, # user/inferred/external
|
|
"verified": verified, # bool
|
|
"created_at": datetime.now().isoformat(),
|
|
"access_count": 0,
|
|
"last_accessed": datetime.now().isoformat()
|
|
}
|
|
|
|
# Optional metadata
|
|
if expires_at:
|
|
payload["expires_at"] = expires_at
|
|
if related_memories:
|
|
payload["related_memories"] = related_memories
|
|
|
|
# Qdrant upsert format
|
|
upsert_data = {
|
|
"points": [
|
|
{
|
|
"id": point_id,
|
|
"vector": embedding,
|
|
"payload": payload
|
|
}
|
|
]
|
|
}
|
|
|
|
req = urllib.request.Request(
|
|
f"{QDRANT_URL}/collections/{COLLECTION_NAME}/points?wait=true",
|
|
data=json.dumps(upsert_data).encode(),
|
|
headers={"Content-Type": "application/json"},
|
|
method="PUT"
|
|
)
|
|
|
|
try:
|
|
with urllib.request.urlopen(req, timeout=10) as response:
|
|
result = json.loads(response.read().decode())
|
|
if result.get("status") == "ok":
|
|
return point_id
|
|
else:
|
|
print(f"Qdrant response: {result}", file=sys.stderr)
|
|
return None
|
|
except urllib.error.HTTPError as e:
|
|
error_body = e.read().decode()
|
|
print(f"HTTP Error {e.code}: {error_body}", file=sys.stderr)
|
|
return None
|
|
except Exception as e:
|
|
print(f"Error storing memory: {e}", file=sys.stderr)
|
|
return None
|
|
|
|
def link_memories(point_id, related_ids):
|
|
"""Link this memory to related memories (bidirectional)"""
|
|
# Update this memory to include related
|
|
# Then update each related memory to include this one
|
|
pass # Implementation would update existing points
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser(description="Store a memory in Qdrant with metadata")
|
|
parser.add_argument("text", help="Memory text to store")
|
|
parser.add_argument("--tags", help="Comma-separated tags")
|
|
parser.add_argument("--importance", default="medium", choices=["low", "medium", "high"])
|
|
parser.add_argument("--date", help="Date in YYYY-MM-DD format")
|
|
parser.add_argument("--source", default="conversation", help="Source of the memory")
|
|
parser.add_argument("--confidence", default="high", choices=["high", "medium", "low"],
|
|
help="Confidence in this memory's accuracy")
|
|
parser.add_argument("--source-type", default="user", choices=["user", "inferred", "external"],
|
|
help="How this memory was obtained")
|
|
parser.add_argument("--verified", action="store_true", default=True,
|
|
help="Whether this memory has been verified")
|
|
parser.add_argument("--expires", help="Expiration date YYYY-MM-DD (for temporary memories)")
|
|
parser.add_argument("--related", help="Comma-separated related memory IDs")
|
|
|
|
args = parser.parse_args()
|
|
|
|
# Parse tags and related memories
|
|
tags = [t.strip() for t in args.tags.split(",")] if args.tags else []
|
|
related = [r.strip() for r in args.related.split(",")] if args.related else None
|
|
|
|
print(f"Generating embedding...")
|
|
embedding = get_embedding(args.text)
|
|
|
|
if embedding is None:
|
|
print("❌ Failed to generate embedding", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
print(f"Storing memory (vector dim: {len(embedding)})...")
|
|
point_id = store_memory(
|
|
args.text, embedding, tags, args.importance, args.date, args.source,
|
|
args.confidence, args.source_type, args.verified, args.expires, related
|
|
)
|
|
|
|
if point_id:
|
|
print(f"✅ Memory stored successfully")
|
|
print(f" ID: {point_id}")
|
|
print(f" Tags: {tags}")
|
|
print(f" Importance: {args.importance}")
|
|
print(f" Confidence: {args.confidence}")
|
|
print(f" Source: {args.source_type}")
|
|
if args.expires:
|
|
print(f" Expires: {args.expires}")
|
|
else:
|
|
print(f"❌ Failed to store memory", file=sys.stderr)
|
|
sys.exit(1)
|