diff --git a/app/(admin)/settings/admin-settings-client.tsx b/app/(admin)/settings/admin-settings-client.tsx index 804b086..df4d76c 100644 --- a/app/(admin)/settings/admin-settings-client.tsx +++ b/app/(admin)/settings/admin-settings-client.tsx @@ -2553,9 +2553,9 @@ export function AdminSettingsClient() { {siteSettings.bannerEnabled && ( <> -
+
- setSiteSettings({ ...siteSettings, bannerText: e.target.value })} @@ -2963,11 +2963,11 @@ export function AdminSettingsClient() {
- + -
+
- setTutorialVideoForm({ ...tutorialVideoForm, videoUrl: e.target.value })} placeholder="视频URL(上传后自动填充或手动输入)" @@ -3020,7 +3020,7 @@ export function AdminSettingsClient() {
-
+
@@ -3067,7 +3067,7 @@ export function AdminSettingsClient() { + @@ -3130,8 +3130,8 @@ export function AdminSettingsClient() {
)} - - + + )} {/* 导航链接列表 */} diff --git a/app/(chat)/api/chat/route.ts b/app/(chat)/api/chat/route.ts index fa0f4c1..48b8c7d 100644 --- a/app/(chat)/api/chat/route.ts +++ b/app/(chat)/api/chat/route.ts @@ -105,11 +105,14 @@ function hasAnnotatedImage(messages: ChatMessage[]): boolean { const ANNOTATION_SYSTEM_PROMPT = "【重要】用户提供的图片上有标注线条(如箭头、圆圈、画笔痕迹或文字说明),这些标注是用户用来指示需要修改的区域或方向。请仔细理解标注的含义,按照标注指示进行编辑,但在生成的新图片中不要保留这些标注线条,输出干净的编辑结果。"; /** - * 自定义消息转换函数,支持将图片 URL 转换为 base64(仅用于 Gemini) + * 自定义消息转换函数 + * 注意:gemini-image 和 huanke-gemini 都需要 URL 格式(不是 Base64) + * 因为这些 provider 内部会自行处理图片上传到 S3 */ async function convertMessagesWithImages(messages: ChatMessage[], providerType: string) { - // 千问视频需要真实的 HTTP URL,不能用 base64 - // 只有 Gemini 需要 base64 + // 所有 provider 都使用 URL 格式传输图片 + // gemini-image 和 huanke-gemini 内部会将 Base64 转换为 S3 URL + // 这里不再进行 Base64 转换,直接返回标准格式 if (providerType !== "gemini") { return convertToModelMessages(messages); } @@ -146,26 +149,15 @@ async function convertMessagesWithImages(messages: ChatMessage[], providerType: text: textContent, }); } else if (part.type === "file" && part.url) { - // 将图片 URL 转换为 base64 - try { - const base64Data = await convertImageUrlToBase64(part.url); - content.push({ - type: "image_url", - image_url: { - url: base64Data, - }, - }); - console.log("[Message Convert] Image converted to base64 and formatted as image_url"); - } catch (error) { - console.error("[Message Convert] Failed to convert image, using URL:", error); - // 失败时仍然尝试使用 URL - content.push({ - type: "image_url", - image_url: { - url: part.url, - }, - }); - } + // 直接使用 URL 格式(不再转换为 Base64) + // gemini-image 和 huanke-gemini provider 内部会处理图片上传 + content.push({ + type: "image_url", + image_url: { + url: part.url, + }, + }); + console.log("[Message Convert] Image kept as URL format:", part.url.substring(0, 80) + "..."); } } @@ -744,8 +736,10 @@ export async function POST(request: Request) { } // ========== Gemini 图片生成独立处理 ========== - if ((languageModel as any).provider === "gemini-image" && typeof (languageModel as any).doGenerate === "function") { - console.log("[Chat API] Using Gemini image generation"); + // 支持 gemini-image 和 huanke-gemini 两种图片生成 provider + const isGeminiImageProvider = ["gemini-image", "huanke-gemini"].includes((languageModel as any).provider); + if (isGeminiImageProvider && typeof (languageModel as any).doGenerate === "function") { + console.log("[Chat API] Using Gemini image generation, provider:", (languageModel as any).provider); console.log("[Chat API] Image params:", requestBody.imageParams); // 🆕 获取备用模型配置 @@ -767,8 +761,10 @@ export async function POST(request: Request) { const messagesForGemini = lastUserMessage ? [lastUserMessage] : uiMessages; console.log("[Chat API] Gemini: Using only last user message (no history context)"); - // 转换消息,Gemini 需要 base64 格式的图片 - const modelMessages = await convertMessagesWithImages(messagesForGemini, "gemini"); + // 转换消息:gemini-image 需要 base64 格式,huanke-gemini 需要 URL 格式 + const providerForConvert = (languageModel as any).provider === "huanke-gemini" ? "huanke-gemini" : "gemini"; + const modelMessages = await convertMessagesWithImages(messagesForGemini, providerForConvert); + console.log("[Chat API] Message conversion provider:", providerForConvert); // 调用 doGenerate 获取图片(如果是备用模型,传入 overrideModelId) const result = await (languageModel as any).doGenerate({