andy-stack_vaultkeeper-ai/Services/ConversationNamingService.ts
Andrew Beal 38c9809a27 feat: add AI-powered conversation naming with Gemini integration
Implement automatic conversation title generation using Gemini API. Add IConversationNamingService interface with GeminiConversationNamingService implementation. Integrate naming service into ChatService to generate titles on first user message. Update ConversationFileSystemService to support title updates via file renaming.
2025-10-17 16:18:23 +01:00

53 lines
2.1 KiB
TypeScript

import { Resolve } from "./DependencyService";
import { Services } from "./Services";
import type { IConversationNamingService } from "AIClasses/IConversationNamingService";
import type { ConversationFileSystemService } from "./ConversationFileSystemService";
import type { Conversation } from "Conversations/Conversation";
export class ConversationNamingService {
private namingProvider: IConversationNamingService | undefined;
private conversationService: ConversationFileSystemService;
constructor() {
this.conversationService = Resolve<ConversationFileSystemService>(Services.ConversationFileSystemService);
}
public resolveNamingProvider() {
this.namingProvider = Resolve<IConversationNamingService>(Services.IConversationNamingService);
}
public async requestName(conversation: Conversation, userPrompt: string, abortController: AbortController): Promise<void> {
if (!this.namingProvider) {
return;
}
const conversationPath = this.conversationService.getCurrentConversationPath();
if (!conversationPath) {
return;
}
try {
const generatedName: string = await this.namingProvider.generateName(userPrompt, abortController.signal);
const validatedName: string = this.validateName(generatedName);
const stillExists = this.conversationService.getCurrentConversationPath() === conversationPath;
if (!stillExists) {
return;
}
await this.conversationService.updateConversationTitle(conversationPath, validatedName);
conversation.title = validatedName;
} catch (error) {
if (error instanceof Error && error.name === 'AbortError') {
return;
}
console.error("Failed to generate name:", error);
}
}
private validateName(generatedName: string): string {
const cleanedTitle = generatedName.trim().replace(/^["']|["']$/g, "");
return cleanedTitle.split(/\s+/).slice(0, 6).join(" ");
}
}