kit初版,模型引入,agent优化
This commit is contained in:
160
art-agent/frontend/src/lib/store.ts
Normal file
160
art-agent/frontend/src/lib/store.ts
Normal file
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* 基于 localStorage 的客户端持久化存储。
|
||||
* 提供会话、标签、图片资源的 CRUD 操作。
|
||||
*/
|
||||
|
||||
import type { Session, Tag, ImageAsset, ChatMessage } from "./types";
|
||||
|
||||
const STORAGE_KEYS = {
|
||||
sessions: "epeekit-sessions",
|
||||
tags: "epeekit-tags",
|
||||
assets: "epeekit-assets",
|
||||
} as const;
|
||||
|
||||
// --------------- 内置标签 ---------------
|
||||
|
||||
const BUILTIN_TAGS: Tag[] = [
|
||||
{ id: "tag-ui", name: "UI", color: "#6366f1", builtin: true },
|
||||
{ id: "tag-icon", name: "Icon", color: "#f59e0b", builtin: true },
|
||||
{ id: "tag-illustration", name: "原画", color: "#10b981", builtin: true },
|
||||
{ id: "tag-style", name: "风格探索", color: "#ec4899", builtin: true },
|
||||
{ id: "tag-character", name: "立绘", color: "#8b5cf6", builtin: true },
|
||||
{ id: "tag-concept", name: "概念图", color: "#06b6d4", builtin: true },
|
||||
];
|
||||
|
||||
// --------------- 通用 helpers ---------------
|
||||
|
||||
function readJSON<T>(key: string, fallback: T): T {
|
||||
if (typeof window === "undefined") return fallback;
|
||||
try {
|
||||
const raw = localStorage.getItem(key);
|
||||
return raw ? (JSON.parse(raw) as T) : fallback;
|
||||
} catch {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
function writeJSON<T>(key: string, data: T) {
|
||||
if (typeof window === "undefined") return;
|
||||
localStorage.setItem(key, JSON.stringify(data));
|
||||
}
|
||||
|
||||
// --------------- ID 生成 ---------------
|
||||
|
||||
let counter = 0;
|
||||
export function generateId(prefix = ""): string {
|
||||
counter++;
|
||||
const ts = Date.now().toString(36);
|
||||
const rand = Math.random().toString(36).slice(2, 6);
|
||||
return `${prefix}${ts}-${rand}-${counter}`;
|
||||
}
|
||||
|
||||
// --------------- 标签 ---------------
|
||||
|
||||
export function loadTags(): Tag[] {
|
||||
const custom = readJSON<Tag[]>(STORAGE_KEYS.tags, []);
|
||||
const builtinIds = new Set(BUILTIN_TAGS.map((t) => t.id));
|
||||
const merged = [...BUILTIN_TAGS, ...custom.filter((t) => !builtinIds.has(t.id))];
|
||||
return merged;
|
||||
}
|
||||
|
||||
export function saveTags(tags: Tag[]) {
|
||||
const custom = tags.filter((t) => !t.builtin);
|
||||
writeJSON(STORAGE_KEYS.tags, custom);
|
||||
}
|
||||
|
||||
export function addTag(name: string, color: string): Tag {
|
||||
const tag: Tag = { id: generateId("tag-"), name, color, builtin: false };
|
||||
const existing = loadTags();
|
||||
saveTags([...existing, tag]);
|
||||
return tag;
|
||||
}
|
||||
|
||||
export function deleteTag(tagId: string) {
|
||||
const tags = loadTags().filter((t) => t.id !== tagId && !t.builtin);
|
||||
saveTags(tags);
|
||||
}
|
||||
|
||||
// --------------- 会话 ---------------
|
||||
|
||||
export function loadSessions(): Session[] {
|
||||
return readJSON<Session[]>(STORAGE_KEYS.sessions, []);
|
||||
}
|
||||
|
||||
export function saveSessions(sessions: Session[]) {
|
||||
writeJSON(STORAGE_KEYS.sessions, sessions);
|
||||
}
|
||||
|
||||
export function createSession(): Session {
|
||||
const now = Date.now();
|
||||
const session: Session = {
|
||||
id: generateId("sess-"),
|
||||
title: "新对话",
|
||||
tags: [],
|
||||
messages: [],
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
};
|
||||
const sessions = loadSessions();
|
||||
saveSessions([session, ...sessions]);
|
||||
return session;
|
||||
}
|
||||
|
||||
export function updateSession(session: Session) {
|
||||
const sessions = loadSessions();
|
||||
const idx = sessions.findIndex((s) => s.id === session.id);
|
||||
if (idx >= 0) {
|
||||
sessions[idx] = { ...session, updatedAt: Date.now() };
|
||||
} else {
|
||||
sessions.unshift({ ...session, updatedAt: Date.now() });
|
||||
}
|
||||
saveSessions(sessions);
|
||||
}
|
||||
|
||||
export function deleteSession(sessionId: string) {
|
||||
const sessions = loadSessions().filter((s) => s.id !== sessionId);
|
||||
saveSessions(sessions);
|
||||
// 同时删除关联的图片资源
|
||||
const assets = loadAssets().filter((a) => a.sessionId !== sessionId);
|
||||
saveAssets(assets);
|
||||
}
|
||||
|
||||
// --------------- 图片资源 ---------------
|
||||
|
||||
export function loadAssets(): ImageAsset[] {
|
||||
return readJSON<ImageAsset[]>(STORAGE_KEYS.assets, []);
|
||||
}
|
||||
|
||||
export function saveAssets(assets: ImageAsset[]) {
|
||||
writeJSON(STORAGE_KEYS.assets, assets);
|
||||
}
|
||||
|
||||
export function addAsset(asset: ImageAsset) {
|
||||
const assets = loadAssets();
|
||||
assets.unshift(asset);
|
||||
saveAssets(assets);
|
||||
}
|
||||
|
||||
export function updateAsset(assetId: string, patch: Partial<ImageAsset>) {
|
||||
const assets = loadAssets();
|
||||
const idx = assets.findIndex((a) => a.id === assetId);
|
||||
if (idx >= 0) {
|
||||
assets[idx] = { ...assets[idx], ...patch };
|
||||
saveAssets(assets);
|
||||
}
|
||||
}
|
||||
|
||||
export function deleteAsset(assetId: string) {
|
||||
saveAssets(loadAssets().filter((a) => a.id !== assetId));
|
||||
}
|
||||
|
||||
export function toggleFavorite(assetId: string): boolean {
|
||||
const assets = loadAssets();
|
||||
const idx = assets.findIndex((a) => a.id === assetId);
|
||||
if (idx >= 0) {
|
||||
assets[idx].favorited = !assets[idx].favorited;
|
||||
saveAssets(assets);
|
||||
return assets[idx].favorited;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
Reference in New Issue
Block a user