feat(*): 技能库与认证体验 - 重构共享技能库并优化登录页面与默认创作入口

This commit is contained in:
ddCat committed 2026-08-02 16:27:22 +08:00
1 parent 219809c320
commit adbbe96ce4
28 files changed
+2480 -963

No files matched your search

+4 -4
View File
@@ -295,7 +295,7 @@ function InfiniteCanvasPage() {
);
const {
activatedSkills,
addedSkills,
clearCanvasFiles,
createAndOpenProject,
currentProject,
@@ -798,7 +798,7 @@ function InfiniteCanvasPage() {
hoveredNodeId,
dragPreview,
collapsingBatchIds,
activatedSkills,
addedSkills,
directorScenes: currentProject?.directorScenes,
toolbarNodeId,
infoNodeId,
@@ -1089,7 +1089,7 @@ function InfiniteCanvasPage() {
const handleGenerateNode = useCanvasGenerationExecutor({
projectId,
domainProjectId: currentProject?.projectId,
activatedSkills,
addedSkills,
nodesRef,
connectionsRef,
setNodes,
@@ -1145,7 +1145,7 @@ function InfiniteCanvasPage() {
const handleRetryNode = useCanvasGenerationRetry({
projectId,
domainProjectId: currentProject?.projectId,
activatedSkills,
addedSkills,
nodesRef,
connectionsRef,
setNodes,
@@ -9,7 +9,7 @@ import { buildPortraitTexturePrompt } from "@/lib/canvas/canvas-portrait-texture
import { expandSkillMentions } from "@/lib/canvas/canvas-skill-mentions";
import { generationFailureMetadata } from "@/lib/generation-error";
import { navigateToSettings } from "@/lib/settings-navigation";
import type { UpdreamSkill } from "@/services/api/skills";
import type { Skill } from "@/services/api/skills";
import type { GenerationTask } from "@/services/api/task-center";
import { useConfigStore, useEffectiveConfig } from "@/stores/use-config-store";
import { CanvasNodeType, type CanvasConnection, type CanvasNodeData } from "@/types/canvas";
@@ -21,7 +21,7 @@ import { executeTextGeneration } from "./canvas-text-generation-executor";
type UseCanvasGenerationExecutorOptions = {
projectId: string;
domainProjectId?: string;
activatedSkills: UpdreamSkill[];
addedSkills: Skill[];
nodesRef: { current: CanvasNodeData[] };
connectionsRef: { current: CanvasConnection[] };
setNodes: Dispatch<SetStateAction<CanvasNodeData[]>>;
@@ -47,7 +47,7 @@ export type CanvasNodeGenerationOptions = {
export function useCanvasGenerationExecutor({
projectId,
domainProjectId,
activatedSkills,
addedSkills,
nodesRef,
connectionsRef,
setNodes,
@@ -142,7 +142,7 @@ export function useCanvasGenerationExecutor({
return;
}
const expandedPrompt = expandSkillMentions(rawGenerationContext.prompt, activatedSkills);
const expandedPrompt = expandSkillMentions(rawGenerationContext.prompt, addedSkills);
const effectivePrompt = expandedPrompt.trim();
const generationContext = { ...rawGenerationContext, prompt: effectivePrompt };
if (mode === "audio" && generationContext.characterReferences.length) {
@@ -233,6 +233,6 @@ export function useCanvasGenerationExecutor({
setRunningNodeId(null);
}
},
[activatedSkills, bindGenerationTask, domainProjectId, effectiveConfig, finishGenerationRequest, isAiConfigReady, message, nodesRef, connectionsRef, projectId, setConnections, setDialogNodeId, setNodes, setRunningNodeId, setSelectedConnectionId, setSelectedNodeIds, startGenerationRequest],
[addedSkills, bindGenerationTask, domainProjectId, effectiveConfig, finishGenerationRequest, isAiConfigReady, message, nodesRef, connectionsRef, projectId, setConnections, setDialogNodeId, setNodes, setRunningNodeId, setSelectedConnectionId, setSelectedNodeIds, startGenerationRequest],
);
}
@@ -27,7 +27,7 @@ import { generationFailureMetadata, unchangedModeratedPrompt } from "@/lib/gener
import { navigateToSettings } from "@/lib/settings-navigation";
import { storeGeneratedAudio } from "@/services/api/audio";
import { storeGeneratedVideo } from "@/services/api/video";
import type { UpdreamSkill } from "@/services/api/skills";
import type { Skill } from "@/services/api/skills";
import type { GenerationTask } from "@/services/api/task-center";
import { resolveImageUrl, uploadImage } from "@/services/image-storage";
import { resolveModelRequestConfig, useConfigStore, useEffectiveConfig } from "@/stores/use-config-store";
@@ -36,7 +36,7 @@ import { CanvasNodeType, type CanvasConnection, type CanvasNodeData } from "@/ty
type UseCanvasGenerationRetryOptions = {
projectId: string;
domainProjectId?: string;
activatedSkills: UpdreamSkill[];
addedSkills: Skill[];
nodesRef: { current: CanvasNodeData[] };
connectionsRef: { current: CanvasConnection[] };
setNodes: Dispatch<SetStateAction<CanvasNodeData[]>>;
@@ -50,7 +50,7 @@ const NODE_STATUS_LOADING = "loading" as const;
const NODE_STATUS_SUCCESS = "success" as const;
const NODE_STATUS_ERROR = "error" as const;
export function useCanvasGenerationRetry({ projectId, domainProjectId, activatedSkills, nodesRef, connectionsRef, setNodes, setRunningNodeId, startGenerationRequest, finishGenerationRequest, bindGenerationTask }: UseCanvasGenerationRetryOptions) {
export function useCanvasGenerationRetry({ projectId, domainProjectId, addedSkills, nodesRef, connectionsRef, setNodes, setRunningNodeId, startGenerationRequest, finishGenerationRequest, bindGenerationTask }: UseCanvasGenerationRetryOptions) {
const { message } = App.useApp();
const effectiveConfig = useEffectiveConfig();
const isAiConfigReady = useConfigStore((state) => state.isAiConfigReady);
@@ -93,7 +93,7 @@ export function useCanvasGenerationRetry({ projectId, domainProjectId, activated
setNodes((current) => current.map((item) => (item.id === node.id ? { ...item, metadata: { ...item.metadata, status: NODE_STATUS_ERROR, ...failure } } : item)));
return;
}
const context = rawContext ? { ...rawContext, prompt: expandSkillMentions(rawContext.prompt, activatedSkills) } : null;
const context = rawContext ? { ...rawContext, prompt: expandSkillMentions(rawContext.prompt, addedSkills) } : null;
const prompt = (context?.characterReferences.length ? context.prompt : savedImageMetadata?.prompt || context?.prompt || "").trim();
if (!prompt) {
message.warning("找不到提示词,无法重试");
@@ -210,7 +210,7 @@ export function useCanvasGenerationRetry({ projectId, domainProjectId, activated
setRunningNodeId(null);
}
},
[activatedSkills, bindGenerationTask, connectionsRef, domainProjectId, effectiveConfig, finishGenerationRequest, isAiConfigReady, message, nodesRef, projectId, setNodes, setRunningNodeId, startGenerationRequest],
[addedSkills, bindGenerationTask, connectionsRef, domainProjectId, effectiveConfig, finishGenerationRequest, isAiConfigReady, message, nodesRef, projectId, setNodes, setRunningNodeId, startGenerationRequest],
);
}
@@ -5,7 +5,7 @@ import { useNavigate } from "react-router";
import type { CanvasBackgroundMode } from "@/lib/canvas-theme";
import { removeCanvasDrawing } from "@/lib/canvas/canvas-drawing-storage";
import { hydrateAssistantImages, hydrateCanvasImages, resetInterruptedGeneration } from "@/lib/canvas/canvas-project-generation";
import { listActivatedSkills, type UpdreamSkill } from "@/services/api/skills";
import { listAddedSkills, type Skill } from "@/services/api/skills";
import { createCanvasProjectWithRemoteSync, saveRemoteUserDataNow } from "@/services/user-data-sync";
import { flushCanvasStorePersistence, useCanvasStore } from "@/stores/canvas/use-canvas-store";
import type { CanvasAssistantSession, CanvasConnection, CanvasNodeData, CanvasNodeMetadata, ViewportTransform } from "@/types/canvas";
@@ -72,7 +72,7 @@ export function useCanvasProjectLifecycle({
const renameProject = useCanvasStore((state) => state.renameProject);
const deleteProjects = useCanvasStore((state) => state.deleteProjects);
const currentProject = useCanvasStore((state) => state.projects.find((project) => project.id === projectId));
const [activatedSkills, setActivatedSkills] = useState<UpdreamSkill[]>([]);
const [addedSkills, setAddedSkills] = useState<Skill[]>([]);
const viewportSaveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
useEffect(() => {
@@ -130,12 +130,12 @@ export function useCanvasProjectLifecycle({
useEffect(() => {
if (!projectLoaded) return;
let cancelled = false;
listActivatedSkills()
listAddedSkills()
.then(({ skills }) => {
if (!cancelled) setActivatedSkills(skills);
if (!cancelled) setAddedSkills(skills);
})
.catch(() => {
if (!cancelled) setActivatedSkills([]);
if (!cancelled) setAddedSkills([]);
});
return () => {
cancelled = true;
@@ -218,7 +218,7 @@ export function useCanvasProjectLifecycle({
}, [cleanupCanvasFiles, projectId]);
return {
activatedSkills,
addedSkills,
clearCanvasFiles,
createAndOpenProject,
currentProject,
@@ -6,7 +6,7 @@ import { sameNodeSemanticData } from "@/lib/canvas/canvas-project-domain";
import { shouldReduceCanvasMediaEffects } from "@/lib/canvas/canvas-performance-mode";
import { buildCanvasResourceReferences, buildNodeMentionReferences } from "@/lib/canvas/canvas-resource-references";
import { buildSkillMentionReferences } from "@/lib/canvas/canvas-skill-mentions";
import type { UpdreamSkill } from "@/services/api/skills";
import type { Skill } from "@/services/api/skills";
import type { Asset, ImageAsset } from "@/stores/use-asset-store";
import type { DirectorScene } from "@/types/director";
import { CanvasNodeType, type CanvasConnection, type CanvasMediaPerformanceMode, type CanvasNodeData, type ContextMenuState, type ViewportTransform } from "@/types/canvas";
@@ -24,7 +24,7 @@ type UseCanvasRenderModelOptions = {
hoveredNodeId: string | null;
dragPreview: DragPreview;
collapsingBatchIds: Set<string>;
activatedSkills: UpdreamSkill[];
addedSkills: Skill[];
directorScenes?: DirectorScene[];
toolbarNodeId: string | null;
infoNodeId: string | null;
@@ -55,7 +55,7 @@ export function useCanvasRenderModel({
hoveredNodeId,
dragPreview,
collapsingBatchIds,
activatedSkills,
addedSkills,
directorScenes,
toolbarNodeId,
infoNodeId,
@@ -245,7 +245,7 @@ export function useCanvasRenderModel({
const activeDirectorScene = useMemo(() => directorScenes?.find((scene) => scene.id === activeDirectorNode?.metadata?.directorSceneId) || null, [activeDirectorNode?.metadata?.directorSceneId, directorScenes]);
const canvasResourceReferences = useMemo(() => buildCanvasResourceReferences(semanticNodes, connections, dialogNodeId || activeNodeId), [activeNodeId, connections, dialogNodeId, semanticNodes]);
const resourceReferenceByNodeId = useMemo(() => new Map(canvasResourceReferences.map((reference) => [reference.nodeId, reference])), [canvasResourceReferences]);
const skillMentionReferences = useMemo(() => buildSkillMentionReferences(activatedSkills), [activatedSkills]);
const skillMentionReferences = useMemo(() => buildSkillMentionReferences(addedSkills), [addedSkills]);
const mentionReferencesByNodeId = useMemo(() => {
const map = new Map<string, ReturnType<typeof buildNodeMentionReferences>>();
semanticNodes.forEach((node) => map.set(node.id, [...buildNodeMentionReferences(node, semanticNodes, connections), ...skillMentionReferences]));