feat(assets): 素材选择器 - 支持按媒体类型筛选并覆盖远程项目资产

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
ddCat
2026-09-09 10:34:10 +08:00
parent 7336945623
commit 9acac6cbbe
6 changed files with 92 additions and 7 deletions

View File

@@ -50,6 +50,7 @@ export function AssetPickerModal({ open, multiple = true, onInsert, onClose }: P
category: normalizeAssetCategory(asset.category),
archived: asset.status === "archived",
kindLabel: asset.kind === "image" ? "图片" : asset.kind === "video" ? "视频" : asset.kind === "audio" ? "音频" : "文本",
mediaKind: asset.kind,
asset,
searchText: (asset.tags || []).join(" "),
})),
@@ -62,6 +63,7 @@ export function AssetPickerModal({ open, multiple = true, onInsert, onClose }: P
<AssetLibraryPickerModal
remoteLibrary
open={open}
mediaKinds={["image", "video", "audio", "text"]}
items={items}
categoryLabels={{ ...categoryLabels, ...externalAssetSources.categoryLabels }}
folders={externalAssetSources.folders}

View File

@@ -1,6 +1,6 @@
import { useMemo } from "react";
import { AssetLibraryPickerModal, type AssetLibraryPickerItem } from "@/components/assets/asset-library-picker-modal";
import { AssetLibraryPickerModal, type AssetLibraryPickerItem, type AssetPickerMediaKind } from "@/components/assets/asset-library-picker-modal";
import { useExternalAssetSources } from "@/hooks/use-external-asset-sources";
import { externalAssetToInsertPayload, type InsertAssetPayload } from "@/components/canvas/asset-picker-modal";
import { compileCharacterReferencePrompt } from "@/lib/canvas/canvas-character-reference";
@@ -55,12 +55,15 @@ export function CanvasProjectAssetModal({
character?.character?.representations.find((representation) => representation.role === "primary") ||
character?.character?.representations.find((representation) => representation.role === "front");
const remoteResourceId = resourceIdFromStorageKey(project?.storageKey);
// 项目资产可能只有服务端记录、没有本地素材,媒体类型要显式声明,筛选才能覆盖它们。
const mediaKind = character ? undefined : pickerMediaKind(media?.kind || project?.mediaType);
return {
id: item.id,
title: character?.title || project?.title || media?.title || "未命名资产",
category: item.category,
folderId: item.folderId,
kindLabel: character ? "角色卡" : (media?.kind || project?.mediaType) === "video" ? "视频" : (media?.kind || project?.mediaType) === "audio" ? "音频" : (media?.kind || project?.mediaType) === "text" ? "文本" : "图片",
kindLabel: character ? "角色卡" : mediaKind === "video" ? "视频" : mediaKind === "audio" ? "音频" : mediaKind === "text" ? "文本" : "图片",
mediaKind,
asset: media,
imageUrl: coverRepresentation ? resourceFileUrl(coverRepresentation.resourceId) : project?.mediaType === "image" && remoteResourceId ? resourceFileUrl(remoteResourceId) : undefined,
imageStorageKey: coverRepresentation ? `resource:${coverRepresentation.resourceId}` : undefined,
@@ -77,6 +80,7 @@ export function CanvasProjectAssetModal({
<AssetLibraryPickerModal
remoteLibrary={!detail}
open={open}
mediaKinds={["image", "video", "audio", "text"]}
items={pickerItems}
categoryLabels={{ ...categoryLabels, ...externalAssetSources.categoryLabels }}
initialCategory={initialCategory}
@@ -117,6 +121,10 @@ export function CanvasProjectAssetModal({
);
}
function pickerMediaKind(value?: string): AssetPickerMediaKind {
return value === "video" || value === "audio" || value === "text" ? value : "image";
}
function toInsertPayload(item: ProjectPickerItem): InsertAssetPayload {
if (item.character?.character) {
return projectCharacterToInsertPayload(item.character);