kit初版,模型引入,agent优化

This commit is contained in:
2026-04-13 00:41:23 +08:00
parent 9b053e302b
commit c435ab15cf
14097 changed files with 5032 additions and 2676248 deletions

View File

@@ -0,0 +1,289 @@
"use client";
import {
createContext,
useCallback,
useContext,
useEffect,
useMemo,
useState,
type ReactNode,
} from "react";
import type { Session, Tag, ImageAsset, ChatMessage } from "./types";
import {
loadSessions,
saveSessions,
createSession as storeCreateSession,
updateSession as storeUpdateSession,
deleteSession as storeDeleteSession,
loadTags,
saveTags,
addTag as storeAddTag,
deleteTag as storeDeleteTag,
loadAssets,
addAsset as storeAddAsset,
updateAsset as storeUpdateAsset,
deleteAsset as storeDeleteAsset,
toggleFavorite as storeToggleFavorite,
generateId,
} from "./store";
interface AppContextValue {
// 会话
sessions: Session[];
activeSessionId: string | null;
activeSession: Session | null;
createSession: () => Session;
switchSession: (id: string) => void;
deleteSession: (id: string) => void;
renameSession: (id: string, title: string) => void;
updateSessionTags: (id: string, tags: string[]) => void;
appendMessage: (sessionId: string, message: ChatMessage) => void;
updateSessionThumbnail: (sessionId: string, url: string) => void;
// 标签
tags: Tag[];
addTag: (name: string, color: string) => Tag;
deleteTag: (id: string) => void;
selectedTagIds: string[];
setSelectedTagIds: (ids: string[]) => void;
// 图片资源
assets: ImageAsset[];
addAsset: (asset: ImageAsset) => void;
updateAsset: (id: string, patch: Partial<ImageAsset>) => void;
deleteAssetById: (id: string) => void;
toggleFavorite: (id: string) => boolean;
// 右侧面板
detailImage: ImageAsset | null;
setDetailImage: (asset: ImageAsset | null) => void;
// 左栏折叠
sidebarCollapsed: boolean;
setSidebarCollapsed: (v: boolean) => void;
}
const AppContext = createContext<AppContextValue | null>(null);
export function useApp(): AppContextValue {
const ctx = useContext(AppContext);
if (!ctx) throw new Error("useApp must be used within AppProvider");
return ctx;
}
export function AppProvider({ children }: { children: ReactNode }) {
const [sessions, setSessions] = useState<Session[]>([]);
const [activeSessionId, setActiveSessionId] = useState<string | null>(null);
const [tags, setTags] = useState<Tag[]>([]);
const [assets, setAssets] = useState<ImageAsset[]>([]);
const [selectedTagIds, setSelectedTagIds] = useState<string[]>([]);
const [detailImage, setDetailImage] = useState<ImageAsset | null>(null);
const [sidebarCollapsed, setSidebarCollapsed] = useState(() => {
if (typeof window !== "undefined") return window.innerWidth < 768;
return false;
});
const [initialized, setInitialized] = useState(false);
// 初始化:从 localStorage 加载
useEffect(() => {
setSessions(loadSessions());
setTags(loadTags());
setAssets(loadAssets());
setInitialized(true);
}, []);
// 初始化后,如果没有会话则自动创建一个
useEffect(() => {
if (!initialized) return;
if (sessions.length === 0) {
const s = storeCreateSession();
setSessions([s]);
setActiveSessionId(s.id);
} else if (!activeSessionId) {
setActiveSessionId(sessions[0].id);
}
}, [initialized, sessions.length, activeSessionId]);
const activeSession = useMemo(
() => sessions.find((s) => s.id === activeSessionId) ?? null,
[sessions, activeSessionId]
);
// --- 会话操作 ---
const createSession = useCallback(() => {
const s = storeCreateSession();
setSessions((prev) => [s, ...prev]);
setActiveSessionId(s.id);
setDetailImage(null);
return s;
}, []);
const switchSession = useCallback((id: string) => {
setActiveSessionId(id);
setDetailImage(null);
if (typeof window !== "undefined" && window.innerWidth < 768) {
setSidebarCollapsed(true);
}
}, []);
const deleteSessionCb = useCallback(
(id: string) => {
storeDeleteSession(id);
setSessions((prev) => {
const next = prev.filter((s) => s.id !== id);
if (activeSessionId === id) {
if (next.length > 0) {
setActiveSessionId(next[0].id);
} else {
const s = storeCreateSession();
next.push(s);
setActiveSessionId(s.id);
}
}
return next;
});
setAssets((prev) => prev.filter((a) => a.sessionId !== id));
setDetailImage(null);
},
[activeSessionId]
);
const renameSession = useCallback((id: string, title: string) => {
setSessions((prev) =>
prev.map((s) => {
if (s.id !== id) return s;
const updated = { ...s, title, updatedAt: Date.now() };
storeUpdateSession(updated);
return updated;
})
);
}, []);
const updateSessionTags = useCallback((id: string, tagIds: string[]) => {
setSessions((prev) =>
prev.map((s) => {
if (s.id !== id) return s;
const updated = { ...s, tags: tagIds, updatedAt: Date.now() };
storeUpdateSession(updated);
return updated;
})
);
}, []);
const appendMessage = useCallback((sessionId: string, message: ChatMessage) => {
setSessions((prev) =>
prev.map((s) => {
if (s.id !== sessionId) return s;
const updated = {
...s,
messages: [...s.messages, message],
updatedAt: Date.now(),
};
// 用首条用户消息作为自动标题
if (message.role === "user" && s.messages.length === 0) {
updated.title = message.content.slice(0, 30) + (message.content.length > 30 ? "…" : "");
}
storeUpdateSession(updated);
return updated;
})
);
}, []);
const updateSessionThumbnail = useCallback((sessionId: string, url: string) => {
setSessions((prev) =>
prev.map((s) => {
if (s.id !== sessionId) return s;
const updated = { ...s, thumbnail: url, updatedAt: Date.now() };
storeUpdateSession(updated);
return updated;
})
);
}, []);
// --- 标签操作 ---
const addTag = useCallback((name: string, color: string) => {
const t = storeAddTag(name, color);
setTags(loadTags());
return t;
}, []);
const deleteTagCb = useCallback((id: string) => {
storeDeleteTag(id);
setTags(loadTags());
setSelectedTagIds((prev) => prev.filter((tid) => tid !== id));
}, []);
// --- 资源操作 ---
const addAssetCb = useCallback((asset: ImageAsset) => {
storeAddAsset(asset);
setAssets((prev) => [asset, ...prev]);
}, []);
const updateAssetCb = useCallback((id: string, patch: Partial<ImageAsset>) => {
storeUpdateAsset(id, patch);
setAssets((prev) => prev.map((a) => (a.id === id ? { ...a, ...patch } : a)));
setDetailImage((prev) => (prev && prev.id === id ? { ...prev, ...patch } : prev));
}, []);
const deleteAssetCb = useCallback((id: string) => {
storeDeleteAsset(id);
setAssets((prev) => prev.filter((a) => a.id !== id));
setDetailImage((prev) => (prev && prev.id === id ? null : prev));
}, []);
const toggleFavoriteCb = useCallback((id: string) => {
const result = storeToggleFavorite(id);
setAssets((prev) =>
prev.map((a) => (a.id === id ? { ...a, favorited: result } : a))
);
setDetailImage((prev) =>
prev && prev.id === id ? { ...prev, favorited: result } : prev
);
return result;
}, []);
const value = useMemo<AppContextValue>(
() => ({
sessions,
activeSessionId,
activeSession,
createSession,
switchSession,
deleteSession: deleteSessionCb,
renameSession,
updateSessionTags,
appendMessage,
updateSessionThumbnail,
tags,
addTag,
deleteTag: deleteTagCb,
selectedTagIds,
setSelectedTagIds,
assets,
addAsset: addAssetCb,
updateAsset: updateAssetCb,
deleteAssetById: deleteAssetCb,
toggleFavorite: toggleFavoriteCb,
detailImage,
setDetailImage,
sidebarCollapsed,
setSidebarCollapsed,
}),
[
sessions, activeSessionId, activeSession,
createSession, switchSession, deleteSessionCb,
renameSession, updateSessionTags, appendMessage, updateSessionThumbnail,
tags, addTag, deleteTagCb, selectedTagIds,
assets, addAssetCb, updateAssetCb, deleteAssetCb, toggleFavoriteCb,
detailImage, sidebarCollapsed,
]
);
if (!initialized) return null;
return <AppContext.Provider value={value}>{children}</AppContext.Provider>;
}