fix(media,canvas): 对象存储参考素材优先 URL,并同步清理图片引用提示词 (#434)

* fix(media): 对象存储参考素材 - 协议支持 URL 时优先发送签名链接

开启对象存储后,支持 URL 的上游协议优先发送 OSS/COS/七牛/S3 签名链接;必须传字节的协议仍走 Base64 或 multipart。本地资源回退字节,签发失败直接报错,不自动重发生成。

* fix(canvas): 图片引用清理 - 取消引用时同步移除提示词引用
This commit is contained in:
Rou
2026-09-07 22:28:19 +08:00
committed by GitHub
parent 469627c792
commit 21b83eca2e
9 changed files with 339 additions and 41 deletions

View File

@@ -23,6 +23,34 @@ import (
const testReferenceImageDataURL = "data:image/png;base64,aGVsbG8="
const testGeminiReferenceImageDataURL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII="
func TestProviderMediaHydrationPolicyPrefersObjectURLs(t *testing.T) {
prefer := providerMediaHydrationPolicyFor(context.Background(), canvasGenerationInput{Config: providerConfig{InterfaceType: string(model.ChannelInterfaceGrokImage)}})
if prefer.requireURL || !prefer.preferURL {
t.Fatalf("grok image policy = %#v", prefer)
}
required := providerMediaHydrationPolicyFor(context.Background(), canvasGenerationInput{Config: providerConfig{InterfaceType: string(model.ChannelInterfaceMiniMaxVideo)}})
if !required.requireURL || !required.preferURL {
t.Fatalf("minimax policy = %#v", required)
}
bytesOnly := providerMediaHydrationPolicyFor(context.Background(), canvasGenerationInput{Config: providerConfig{InterfaceType: string(model.ChannelInterfaceGeminiImage)}})
if bytesOnly.requireURL || bytesOnly.preferURL {
t.Fatalf("gemini image policy = %#v", bytesOnly)
}
masked := providerMediaHydrationPolicyFor(context.Background(), canvasGenerationInput{Config: providerConfig{InterfaceType: string(model.ChannelInterfaceOpenAIImage)}, Mask: &providerMedia{ID: "mask"}})
if masked.requireURL || masked.preferURL {
t.Fatalf("openai mask policy = %#v", masked)
}
if resourceUsesObjectStorage(&model.Resource{Provider: "aliyun"}) != true {
t.Fatal("aliyun should use object storage URLs")
}
if resourceUsesObjectStorage(&model.Resource{Provider: "tencent"}) != true || resourceUsesObjectStorage(&model.Resource{Provider: "qiniu"}) != true || resourceUsesObjectStorage(&model.Resource{Provider: "s3"}) != true {
t.Fatal("cos/kodo/s3 should use object storage URLs")
}
if resourceUsesObjectStorage(&model.Resource{Provider: "local"}) {
t.Fatal("local resources should fall back to protocol-compatible bytes")
}
}
func TestProviderRequestErrorDetails(t *testing.T) {
tests := []struct {
name string