2025-10-04 12:10:22 +00:00
|
|
|
import { Path } from "Enums/Path";
|
2025-09-30 20:20:24 +00:00
|
|
|
import { Resolve } from "./DependencyService";
|
|
|
|
|
import { FileSystemService } from "./FileSystemService";
|
|
|
|
|
import { Services } from "./Services";
|
2025-10-04 12:10:22 +00:00
|
|
|
import { Conversation } from "Conversations/Conversation";
|
2025-10-05 12:06:05 +00:00
|
|
|
import { ConversationContent } from "Conversations/ConversationContent";
|
2025-10-13 12:14:54 +00:00
|
|
|
import { Copy } from "Enums/Copy";
|
2025-11-17 19:02:15 +00:00
|
|
|
import { Exception } from "Helpers/Exception";
|
2025-09-30 20:20:24 +00:00
|
|
|
|
|
|
|
|
export class ConversationFileSystemService {
|
|
|
|
|
|
|
|
|
|
private fileSystemService: FileSystemService;
|
|
|
|
|
private currentConversationPath: string | null = null;
|
|
|
|
|
|
|
|
|
|
public constructor() {
|
|
|
|
|
this.fileSystemService = Resolve<FileSystemService>(Services.FileSystemService);
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-05 12:06:05 +00:00
|
|
|
public generateConversationPath(conversation: Conversation): string {
|
|
|
|
|
return `${Path.Conversations}/${conversation.title}.json`;
|
2025-09-30 20:20:24 +00:00
|
|
|
}
|
|
|
|
|
|
2025-11-17 19:02:15 +00:00
|
|
|
public async saveConversation(conversation: Conversation): Promise<string | Error> {
|
2025-09-30 20:20:24 +00:00
|
|
|
if (!this.currentConversationPath) {
|
2025-10-05 12:06:05 +00:00
|
|
|
this.currentConversationPath = this.generateConversationPath(conversation);
|
2025-09-30 20:20:24 +00:00
|
|
|
}
|
|
|
|
|
|
2025-10-22 09:06:32 +00:00
|
|
|
conversation.updated = new Date();
|
|
|
|
|
|
2025-09-30 20:20:24 +00:00
|
|
|
const conversationData = {
|
2025-10-04 12:10:22 +00:00
|
|
|
title: conversation.title,
|
|
|
|
|
created: conversation.created.toISOString(),
|
2025-10-22 09:06:32 +00:00
|
|
|
updated: conversation.updated.toISOString(),
|
2025-10-13 12:14:54 +00:00
|
|
|
contents: conversation.contents
|
2025-11-10 13:44:16 +00:00
|
|
|
.filter(content => content.content !== Copy.ApiRequestAborted.toString())
|
2025-10-13 12:14:54 +00:00
|
|
|
.map(content => ({
|
|
|
|
|
role: content.role,
|
|
|
|
|
content: content.content,
|
2025-10-29 19:41:05 +00:00
|
|
|
promptContent: content.promptContent,
|
2025-10-20 07:30:08 +00:00
|
|
|
functionCall: content.functionCall,
|
2025-10-13 12:14:54 +00:00
|
|
|
timestamp: content.timestamp.toISOString(),
|
|
|
|
|
isFunctionCall: content.isFunctionCall,
|
2025-10-19 13:23:24 +00:00
|
|
|
isFunctionCallResponse: content.isFunctionCallResponse,
|
2025-11-19 20:30:53 +00:00
|
|
|
toolId: content.toolId,
|
|
|
|
|
errorType: content.errorType
|
2025-10-13 12:14:54 +00:00
|
|
|
}))
|
2025-09-30 20:20:24 +00:00
|
|
|
};
|
|
|
|
|
|
2025-11-24 21:29:54 +00:00
|
|
|
const result = await this.fileSystemService.writeObjectToFile(this.currentConversationPath, conversationData, true, false);
|
2025-11-17 19:02:15 +00:00
|
|
|
|
|
|
|
|
if (result instanceof Error) {
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-30 20:20:24 +00:00
|
|
|
return this.currentConversationPath;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-17 19:02:15 +00:00
|
|
|
public resetCurrentConversation() {
|
2025-09-30 20:20:24 +00:00
|
|
|
this.currentConversationPath = null;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-05 12:37:28 +00:00
|
|
|
public getCurrentConversationPath(): string | null {
|
|
|
|
|
return this.currentConversationPath;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-17 19:02:15 +00:00
|
|
|
public setCurrentConversationPath(filePath: string) {
|
2025-10-05 13:15:04 +00:00
|
|
|
this.currentConversationPath = filePath;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-17 19:02:15 +00:00
|
|
|
public async deleteCurrentConversation(): Promise<void | Error> {
|
2025-10-03 21:14:30 +00:00
|
|
|
if (!this.currentConversationPath) {
|
2025-11-17 19:02:15 +00:00
|
|
|
return;
|
2025-10-03 21:14:30 +00:00
|
|
|
}
|
|
|
|
|
|
2025-11-17 19:02:15 +00:00
|
|
|
const result = await this.fileSystemService.deleteFile(this.currentConversationPath, true);
|
2025-10-03 21:14:30 +00:00
|
|
|
|
2025-11-17 19:02:15 +00:00
|
|
|
if (result instanceof Error) {
|
|
|
|
|
return result;
|
2025-10-03 21:14:30 +00:00
|
|
|
}
|
|
|
|
|
|
2025-11-17 19:02:15 +00:00
|
|
|
this.resetCurrentConversation();
|
2025-10-03 21:14:30 +00:00
|
|
|
}
|
|
|
|
|
|
2025-10-05 12:06:05 +00:00
|
|
|
public async getAllConversations(): Promise<Conversation[]> {
|
2025-10-12 22:11:36 +00:00
|
|
|
const files = await this.fileSystemService.listFilesInDirectory(Path.Conversations, false, true);
|
2025-10-05 12:06:05 +00:00
|
|
|
const conversations: Conversation[] = [];
|
|
|
|
|
|
|
|
|
|
for (const file of files) {
|
2025-11-17 19:02:15 +00:00
|
|
|
const result = await this.fileSystemService.readObjectFromFile(file.path, true);
|
|
|
|
|
if (result instanceof Error) {
|
|
|
|
|
Exception.log(`Failed to load conversation: ${file.path}`);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (Conversation.isConversationData(result)) {
|
2025-10-05 12:06:05 +00:00
|
|
|
const conversation: Conversation = new Conversation();
|
2025-11-17 19:02:15 +00:00
|
|
|
conversation.title = result.title;
|
|
|
|
|
conversation.created = new Date(result.created);
|
|
|
|
|
conversation.updated = new Date(result.updated);
|
|
|
|
|
conversation.contents = result.contents.map(content => {
|
2025-10-06 22:01:20 +00:00
|
|
|
return new ConversationContent(
|
2025-11-17 19:02:15 +00:00
|
|
|
content.role,
|
|
|
|
|
content.content,
|
|
|
|
|
content.promptContent,
|
|
|
|
|
content.functionCall,
|
|
|
|
|
new Date(content.timestamp),
|
|
|
|
|
content.isFunctionCall,
|
|
|
|
|
content.isFunctionCallResponse,
|
2025-11-19 20:30:53 +00:00
|
|
|
content.toolId,
|
|
|
|
|
content.errorType
|
2025-11-17 19:02:15 +00:00
|
|
|
);
|
2025-10-05 12:06:05 +00:00
|
|
|
});
|
|
|
|
|
conversations.push(conversation);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return conversations;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-17 19:02:15 +00:00
|
|
|
public async updateConversationTitle(oldPath: string, newTitle: string): Promise<void | Error> {
|
2025-10-17 15:18:23 +00:00
|
|
|
const newPath = `${Path.Conversations}/${newTitle}.json`;
|
|
|
|
|
|
|
|
|
|
const result = await this.fileSystemService.moveFile(oldPath, newPath, true);
|
|
|
|
|
|
2025-11-17 19:02:15 +00:00
|
|
|
if (result instanceof Error) {
|
|
|
|
|
return result;
|
2025-10-17 15:18:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.currentConversationPath === oldPath) {
|
|
|
|
|
this.currentConversationPath = newPath;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-30 20:20:24 +00:00
|
|
|
}
|