diff --git a/backend/internal/service/model_capability.go b/backend/internal/service/model_capability.go index a67c6c6d9..944985f2c 100644 --- a/backend/internal/service/model_capability.go +++ b/backend/internal/service/model_capability.go @@ -6,7 +6,6 @@ import ( "sort" "strconv" "strings" - "unicode/utf8" "infinite-canvas/backend/internal/model" ) @@ -355,9 +354,6 @@ func (s *Service) ValidateTaskCapability(input map[string]any) error { } func validateVideoTask(profile *VideoCapabilityConfig, input canvasGenerationInput) error { - if utf8.RuneCountInString(input.Prompt) > profile.References.PromptMaxChars { - return BadAuthRequest(fmt.Sprintf("提示词超过当前模型限制(最多 %d 字)", profile.References.PromptMaxChars)) - } if len(input.ReferenceImages) > profile.References.MaxImages || len(input.ReferenceVideos) > profile.References.MaxVideos || len(input.ReferenceAudios) > profile.References.MaxAudios { return BadAuthRequest("参考素材数量超过当前模型限制") } @@ -410,9 +406,6 @@ func validateImageTask(profile *ImageCapabilityConfig, input canvasGenerationInp if profile == nil { return nil } - if utf8.RuneCountInString(input.Prompt) > profile.References.PromptMaxChars { - return BadAuthRequest(fmt.Sprintf("提示词超过当前模型限制(最多 %d 字)", profile.References.PromptMaxChars)) - } if len(input.ReferenceImages) > profile.References.MaxImages { return BadAuthRequest(fmt.Sprintf("当前图片模型最多支持 %d 张参考图", profile.References.MaxImages)) } diff --git a/web/src/components/canvas/canvas-config-node-panel.tsx b/web/src/components/canvas/canvas-config-node-panel.tsx index 8fe9cb25e..9788a2cdc 100644 --- a/web/src/components/canvas/canvas-config-node-panel.tsx +++ b/web/src/components/canvas/canvas-config-node-panel.tsx @@ -57,9 +57,9 @@ export function CanvasConfigNodePanel({ node, isRunning, inputSummary, onConfigC const hasAnyInput = Boolean(inputSummary.textCount || inputSummary.imageCount || inputSummary.videoCount || inputSummary.audioCount); const hasComposerContent = Boolean((node.metadata?.composerContent ?? node.metadata?.prompt ?? "").trim()); const capabilityError = imageProfile - ? imageCapabilityError(imageProfile, node.metadata?.composerContent ?? node.metadata?.prompt ?? "", inputSummary) + ? imageCapabilityError(imageProfile, inputSummary) : videoProfile - ? videoCapabilityError(videoProfile, config.videoSeconds, node.metadata?.composerContent ?? node.metadata?.prompt ?? "", inputSummary, node.metadata?.videoEditOperation) + ? videoCapabilityError(videoProfile, config.videoSeconds, inputSummary, node.metadata?.videoEditOperation) : ""; const canGenerate = (hasComposerContent || (mode === "audio" ? inputSummary.textCount > 0 : hasAnyInput)) && !capabilityError; @@ -252,17 +252,15 @@ function videoConfigPatch(key: keyof AiConfig, value: string) { return { [key]: value }; } -function videoCapabilityError(profile: NonNullable["video"]>, seconds: string, prompt: string, input: CanvasConfigNodePanelProps["inputSummary"], operation?: string) { +function videoCapabilityError(profile: NonNullable["video"]>, seconds: string, input: CanvasConfigNodePanelProps["inputSummary"], operation?: string) { if (!videoDurationAllowed(profile, Number(seconds))) return "当前模型不支持该视频时长"; - if (Array.from(prompt).length > profile.references.promptMaxChars) return `提示词超过模型限制(最多 ${profile.references.promptMaxChars} 字)`; if (input.imageCount > profile.references.maxImages || input.videoCount > profile.references.maxVideos || input.audioCount > profile.references.maxAudios) return "参考素材数量超过当前模型限制"; const resolvedOperation = operation || (input.audioCount > 0 && input.imageCount === 0 && input.videoCount === 0 ? "audio_to_video" : input.videoCount > 0 ? "extend" : input.imageCount > 0 ? "image_to_video" : "text_to_video"); if (!profile.operations.includes(resolvedOperation)) return "当前模型不支持该生成模式"; return ""; } -function imageCapabilityError(profile: ImageCapabilityConfig, prompt: string, input: CanvasConfigNodePanelProps["inputSummary"]) { - if (Array.from(prompt).length > profile.references.promptMaxChars) return `提示词超过模型限制(最多 ${profile.references.promptMaxChars} 字)`; +function imageCapabilityError(profile: ImageCapabilityConfig, input: CanvasConfigNodePanelProps["inputSummary"]) { if (input.imageCount > profile.references.maxImages) return `当前图片模型最多支持 ${profile.references.maxImages} 张参考图`; return ""; } diff --git a/web/src/pages/create/index.tsx b/web/src/pages/create/index.tsx index 93cb2ac26..13559d65b 100644 --- a/web/src/pages/create/index.tsx +++ b/web/src/pages/create/index.tsx @@ -314,28 +314,12 @@ export default function CreatePage() { toast.error("当前模型不支持所选视频时长,请重新选择"); return; } - if (mode === "video" && Array.from(text).length > videoProfile.references.promptMaxChars) { - toast.error(`提示词超过当前模型限制(最多 ${videoProfile.references.promptMaxChars} 字)`); - return; - } - if (mode === "image" && Array.from(text).length > imageProfile.references.promptMaxChars) { - toast.error(`提示词超过当前模型限制(最多 ${imageProfile.references.promptMaxChars} 字)`); - return; - } const settings = { ratio, seconds, quality, videoQuality, count }; const references = selectedCreationReferences(text, mentionReferences); // 后端对图片和视频使用不同的参考字段;这里先拆分,避免媒体类型在写入任务时被误判。 const referenceImages = attachments.filter(isImageAttachment); const referenceVideos = attachments.filter(isVideoAttachment); const expandedPrompt = expandCreationPrompt(text, references, attachments); - if (mode === "video" && Array.from(expandedPrompt).length > videoProfile.references.promptMaxChars) { - toast.error(`引用展开后提示词超过当前模型限制(最多 ${videoProfile.references.promptMaxChars} 字)`); - return; - } - if (mode === "image" && Array.from(expandedPrompt).length > imageProfile.references.promptMaxChars) { - toast.error(`引用展开后提示词超过当前模型限制(最多 ${imageProfile.references.promptMaxChars} 字)`); - return; - } const referenceMetadata = creationReferenceMetadata(references); followLatestMessageRef.current = true; const userMessage = newMessage("user", text, { mode, model: selectedModel, attachments, references, settings }); @@ -744,7 +728,7 @@ function CreationComposer(props: ComposerProps) {
- + {props.attachments.length ?
{props.attachments.map((item) =>
{isVideoAttachment(item) ?
)}
: null}
diff --git a/web/src/services/api/image.ts b/web/src/services/api/image.ts index a857c7cc9..7575a5c72 100644 --- a/web/src/services/api/image.ts +++ b/web/src/services/api/image.ts @@ -216,8 +216,7 @@ function resolveImageRequestSize(profile: ImageCapabilityConfig, quality: string return value ? { parameter: request.parameter, value } : undefined; } -function validateImageCapability(profile: ImageCapabilityConfig, prompt: string, references: ReferenceImage[], mask?: ReferenceImage) { - if (Array.from(prompt).length > profile.references.promptMaxChars) throw new Error(`提示词超过当前模型限制(最多 ${profile.references.promptMaxChars} 字)`); +function validateImageCapability(profile: ImageCapabilityConfig, references: ReferenceImage[], mask?: ReferenceImage) { if (references.length > profile.references.maxImages) throw new Error(`当前图片模型最多支持 ${profile.references.maxImages} 张参考图`); if (mask && !profile.references.maskSupported) throw new Error("当前图片模型不支持蒙版编辑"); if (profile.references.maxImageBytes > 0 && references.some((image) => (image.bytes || 0) > profile.references.maxImageBytes)) throw new Error("参考图片文件超过当前模型大小限制"); @@ -811,7 +810,7 @@ export async function requestGeneration(config: AiConfig, prompt: string, option const selectedModel = config.model || config.imageModel; const requestConfig = resolveModelRequestConfig(config, selectedModel); const imageProfile = modelCapabilityConfigFor(config, selectedModel).image!; - validateImageCapability(imageProfile, prompt, []); + validateImageCapability(imageProfile, []); const normalizedImage = normalizeImageValue(imageProfile, config); const n = Number(normalizedImage.count); if (requestConfig.apiFormat === "gemini") { @@ -896,7 +895,7 @@ export async function requestEdit(config: AiConfig, prompt: string, references: const selectedModel = config.model || config.imageModel; const requestConfig = resolveModelRequestConfig(config, selectedModel); const imageProfile = modelCapabilityConfigFor(config, selectedModel).image!; - validateImageCapability(imageProfile, prompt, references, mask); + validateImageCapability(imageProfile, references, mask); const normalizedImage = normalizeImageValue(imageProfile, config); const n = Number(normalizedImage.count); const requestPrompt = buildImageReferencePromptText(prompt, references); diff --git a/web/src/services/api/video.ts b/web/src/services/api/video.ts index 6e94fed4f..64d894749 100644 --- a/web/src/services/api/video.ts +++ b/web/src/services/api/video.ts @@ -61,7 +61,7 @@ export async function createVideoGenerationTask(config: AiConfig, prompt: string const selectedModel = (config.model || config.videoModel).trim(); const requestConfig = resolveModelRequestConfig(config, selectedModel); assertVideoConfig(requestConfig, requestConfig.model); - assertVideoCapability(modelCapabilityConfigFor(config, selectedModel).video!, prompt, references, videoReferences, audioReferences, config.videoSeconds); + assertVideoCapability(modelCapabilityConfigFor(config, selectedModel).video!, references, videoReferences, audioReferences, config.videoSeconds); if (requestConfig.interfaceType === "newapi-channel-2") { return createVideoGenerationsTask(requestConfig, selectedModel, prompt, references, videoReferences, audioReferences, options); } @@ -80,8 +80,7 @@ export async function createVideoGenerationTask(config: AiConfig, prompt: string return createOpenAIVideoTask(requestConfig, selectedModel, prompt, references, options); } -function assertVideoCapability(profile: NonNullable["video"]>, prompt: string, references: ReferenceImage[], videoReferences: ReferenceVideo[], audioReferences: ReferenceAudio[], seconds: string) { - if (Array.from(prompt).length > profile.references.promptMaxChars) throw new Error(`提示词超过当前模型限制(最多 ${profile.references.promptMaxChars} 字)`); +function assertVideoCapability(profile: NonNullable["video"]>, references: ReferenceImage[], videoReferences: ReferenceVideo[], audioReferences: ReferenceAudio[], seconds: string) { if (references.length > profile.references.maxImages || videoReferences.length > profile.references.maxVideos || audioReferences.length > profile.references.maxAudios) throw new Error("参考素材数量超过当前模型限制"); if (!videoDurationAllowed(profile, Number(seconds))) throw new Error("视频时长不在当前模型支持范围内"); if (profile.references.maxImageBytes > 0 && references.some((image) => (image.bytes || 0) > profile.references.maxImageBytes)) throw new Error("参考图片文件超过当前模型大小限制");