From ffbe992f6452a9c4cf960026ef48de6aaacb69fb Mon Sep 17 00:00:00 2001 From: Ryan Chen Date: Fri, 10 Apr 2026 13:26:47 -0400 Subject: [PATCH] Add management command to rename conversations Conversations with >10 messages get an LLM-generated summary title. Conversations with <=10 messages get the first user message truncated to 100 chars. Supports --dry-run for previewing changes. Co-Authored-By: Claude Opus 4.6 --- scripts/rename_conversations.py | 97 +++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 scripts/rename_conversations.py diff --git a/scripts/rename_conversations.py b/scripts/rename_conversations.py new file mode 100644 index 0000000..0ef8044 --- /dev/null +++ b/scripts/rename_conversations.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 +""" +Management command to rename all conversations. + +- Conversations with >10 messages: renamed to an LLM-generated summary +- Conversations with <=10 messages: renamed to a truncation of the first user message +""" + +import argparse +import asyncio +import os + +from tortoise import Tortoise + +from blueprints.conversation.models import Conversation, Speaker +from llm import LLMClient + + +async def rename_conversations(dry_run: bool = False): + """Rename all conversations based on message count.""" + + database_url = os.getenv("DATABASE_URL", "sqlite://raggr.db") + await Tortoise.init( + db_url=database_url, + modules={ + "models": [ + "blueprints.users.models", + "blueprints.conversation.models", + ] + }, + ) + + try: + llm = LLMClient() + conversations = await Conversation.all().prefetch_related("messages") + + renamed = 0 + skipped = 0 + + for conversation in conversations: + messages = sorted(conversation.messages, key=lambda m: m.created_at) + user_messages = [m for m in messages if m.speaker == Speaker.USER] + + if not user_messages: + skipped += 1 + continue + + if len(messages) > 10: + # Summarize via LLM + message_text = "\n".join( + f"{m.speaker.value}: {m.text}" for m in messages[:30] + ) + new_name = llm.chat( + prompt=message_text, + system_prompt=( + "You are naming a conversation. Given the messages below, " + "produce a short, descriptive title (max 8 words). " + "Reply with ONLY the title, nothing else." + ), + ) + new_name = new_name.strip().strip('"').strip("'")[:100] + else: + # Truncate first user message + new_name = user_messages[0].text[:100] + + old_name = conversation.name + if old_name == new_name: + skipped += 1 + continue + + if dry_run: + print(f" [dry-run] '{old_name}' -> '{new_name}'") + else: + conversation.name = new_name + await conversation.save() + print(f" '{old_name}' -> '{new_name}'") + + renamed += 1 + + print(f"\nRenamed: {renamed} Skipped: {skipped}") + if dry_run: + print("(dry run — no changes were saved)") + finally: + await Tortoise.close_connections() + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Rename conversations based on message count" + ) + parser.add_argument( + "--dry-run", + action="store_true", + help="Preview renames without saving", + ) + args = parser.parse_args() + asyncio.run(rename_conversations(dry_run=args.dry_run))