79 lines
2.4 KiB
Python
79 lines
2.4 KiB
Python
"""One-time migration: convert existing timestamped UserNotes into profile summaries.
|
|
|
|
Run with: python scripts/migrate_notes_to_profiles.py
|
|
|
|
Requires .env with DB_CONNECTION_STRING and LLM env vars.
|
|
"""
|
|
import asyncio
|
|
import os
|
|
import sys
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
|
|
|
|
from dotenv import load_dotenv
|
|
load_dotenv()
|
|
|
|
from utils.database import Database
|
|
from utils.llm_client import LLMClient
|
|
|
|
|
|
async def main():
|
|
db = Database()
|
|
if not await db.init():
|
|
print("Database not available.")
|
|
return
|
|
|
|
llm = LLMClient(
|
|
base_url=os.getenv("LLM_BASE_URL", ""),
|
|
model=os.getenv("LLM_MODEL", "gpt-4o-mini"),
|
|
api_key=os.getenv("LLM_API_KEY", "not-needed"),
|
|
)
|
|
|
|
states = await db.load_all_user_states()
|
|
migrated = 0
|
|
|
|
for state in states:
|
|
notes = state.get("user_notes", "")
|
|
if not notes or not notes.strip():
|
|
continue
|
|
|
|
# Check if already looks like a profile (no timestamps)
|
|
if not any(line.strip().startswith("[") for line in notes.split("\n")):
|
|
print(f" User {state['user_id']}: already looks like a profile, skipping.")
|
|
continue
|
|
|
|
print(f" User {state['user_id']}: migrating notes...")
|
|
print(f" Old: {notes[:200]}")
|
|
|
|
# Ask LLM to summarize notes into a profile
|
|
result = await llm.extract_memories(
|
|
conversation=[{"role": "user", "content": f"Here are observation notes about a user:\n{notes}"}],
|
|
username="unknown",
|
|
current_profile="",
|
|
)
|
|
|
|
if result and result.get("profile_update"):
|
|
profile = result["profile_update"]
|
|
print(f" New: {profile[:200]}")
|
|
await db.save_user_state(
|
|
user_id=state["user_id"],
|
|
offense_count=state["offense_count"],
|
|
immune=state["immune"],
|
|
off_topic_count=state["off_topic_count"],
|
|
baseline_coherence=state.get("baseline_coherence", 0.85),
|
|
user_notes=profile,
|
|
warned=state.get("warned", False),
|
|
last_offense_at=state.get("last_offense_at"),
|
|
)
|
|
migrated += 1
|
|
else:
|
|
print(f" No profile generated, keeping existing notes.")
|
|
|
|
await llm.close()
|
|
await db.close()
|
|
print(f"\nMigrated {migrated}/{len(states)} user profiles.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|