diff --git a/lib/ai/providers/volcano-vision.ts b/lib/ai/providers/volcano-vision.ts index 9d89e32ea..f7fc4c781 100644 --- a/lib/ai/providers/volcano-vision.ts +++ b/lib/ai/providers/volcano-vision.ts @@ -1,12 +1,73 @@ import "server-only"; import { uploadFile } from "@/lib/storage/service"; +import { getDefaultStorageConfig } from "@/lib/db/queries"; interface VolcanoVisionConfig { apiKey: string; baseURL: string; } +type VolcanoUrlRewriteConfig = { + publicOrigin: string; + endpointBase: string; + bucket: string; +}; + +let cachedRewriteConfig: VolcanoUrlRewriteConfig | null | undefined; + +async function getVolcanoUrlRewriteConfig(): Promise { + if (cachedRewriteConfig !== undefined) { + return cachedRewriteConfig; + } + + try { + const storageConfig = await getDefaultStorageConfig(); + if ( + !storageConfig || + storageConfig.type !== "s3" || + !storageConfig.endpoint || + !storageConfig.bucket || + !storageConfig.publicUrl + ) { + cachedRewriteConfig = null; + return null; + } + + const publicOrigin = new URL(storageConfig.publicUrl).origin; + const endpointBase = storageConfig.endpoint.replace(/\/+$/, ""); + + cachedRewriteConfig = { + publicOrigin, + endpointBase, + bucket: storageConfig.bucket, + }; + return cachedRewriteConfig; + } catch { + cachedRewriteConfig = null; + return null; + } +} + +async function rewriteUploadPublicUrlForVolcano(url: string): Promise { + if (!/^https?:\/\//i.test(url)) return url; + + const config = await getVolcanoUrlRewriteConfig(); + if (!config) return url; + + try { + const parsed = new URL(url); + if (parsed.origin !== config.publicOrigin) return url; + if (!parsed.pathname.startsWith("/uploads/")) return url; + + const rewritten = `${config.endpointBase}/${config.bucket}${parsed.pathname}${parsed.search}`; + console.log("[Volcano Vision] Rewrote upload URL for provider fetch:", rewritten); + return rewritten; + } catch { + return url; + } +} + /** * 压缩图片生成缩略图(使用 sharp) */ @@ -251,11 +312,13 @@ async function convertMessagesToVolcanoFormat(messages: any[]): Promise<{ prompt // Base64格式:需要先上传到S3获取URL console.log("[Volcano Vision] Found Base64 image, uploading to S3..."); const uploaded = await uploadImageToS3(imageUrl); - processedImages.push(uploaded.original); + const rewritten = await rewriteUploadPublicUrlForVolcano(uploaded.original); + processedImages.push(rewritten); } else { // URL格式:直接使用 - processedImages.push(imageUrl); - console.log("[Volcano Vision] Using image URL directly:", imageUrl.substring(0, 80) + "..."); + const rewritten = await rewriteUploadPublicUrlForVolcano(imageUrl); + processedImages.push(rewritten); + console.log("[Volcano Vision] Using image URL directly:", rewritten.substring(0, 80) + "..."); } }