Files
ttstd-infinite-canvas/web/src/services/creation-conversation-store.ts

70 lines
3.0 KiB
TypeScript

import { localForageStorageForScope } from "@/lib/localforage-storage";
import { getActiveUserScope } from "@/lib/user-scope";
export const CREATION_CONVERSATIONS_KEY = "creation-conversations-v1";
type PendingCreationMessage = {
id: string;
role: "user" | "assistant";
mode?: string;
status?: string;
taskIds?: string[];
};
export type StoredCreationConversation = {
id: string;
messages: PendingCreationMessage[];
};
export function updateCreationConversationSnapshot<T extends { id: string }>(conversations: T[], conversationId: string, updater: (conversation: T) => T) {
return conversations.map((conversation) => (conversation.id === conversationId ? updater(conversation) : conversation));
}
// 对话、生成任务与素材是独立持久状态;删除历史记录不能在这里级联清理任务或资源。
export function removeCreationConversationSnapshot<T extends { id: string }>(conversations: T[], conversationId: string) {
if (!conversationId) throw new Error("缺少要删除的创作对话 ID");
const next = conversations.filter((conversation) => conversation.id !== conversationId);
if (next.length === conversations.length) throw new Error("要删除的创作对话不存在");
return next;
}
function isRecoverableCreationMessage(message: PendingCreationMessage) {
if (message.role !== "assistant" || !message.taskIds?.length) return false;
return message.mode === "text" ? message.status === "streaming" || message.status === "pending" : message.status === "pending";
}
export function pendingCreationTaskKey(conversations: StoredCreationConversation[]) {
return conversations
.flatMap((conversation) => conversation.messages.flatMap((message) => (isRecoverableCreationMessage(message) ? [`${conversation.id}:${message.id}:${(message.taskIds || []).join(",")}`] : [])))
.join("|");
}
export function pendingCreationTaskIds(conversations: StoredCreationConversation[]) {
const taskIds = conversations.flatMap((conversation) =>
conversation.messages.flatMap((message) => {
if (!isRecoverableCreationMessage(message)) return [];
return message.taskIds || [];
}),
);
return Array.from(new Set(taskIds));
}
export async function loadCreationConversations<T extends StoredCreationConversation>() {
const storage = localForageStorageForScope(getActiveUserScope());
const value = await storage.getItem(CREATION_CONVERSATIONS_KEY);
if (!value) return null;
let parsed: unknown;
try {
parsed = JSON.parse(value);
} catch {
throw new Error("创作对话持久状态无效");
}
if (!Array.isArray(parsed)) throw new Error("创作对话持久状态无效");
return parsed as T[];
}
export async function saveCreationConversations<T extends StoredCreationConversation>(conversations: T[]) {
const storage = localForageStorageForScope(getActiveUserScope());
await storage.setItem(CREATION_CONVERSATIONS_KEY, JSON.stringify(conversations));
}