自动模式补发历史图片
This commit is contained in:
parent
ffd2d1a291
commit
84e22bcccb
@ -124,6 +124,54 @@ function applyHiddenPromptToMessages(messages: ChatMessage[], hiddenPrompt?: str
|
|||||||
return cloned;
|
return cloned;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function guessImageMediaType(url: string): string {
|
||||||
|
const cleanUrl = url.split("?")[0]?.toLowerCase() || "";
|
||||||
|
if (cleanUrl.endsWith(".jpg") || cleanUrl.endsWith(".jpeg")) return "image/jpeg";
|
||||||
|
if (cleanUrl.endsWith(".webp")) return "image/webp";
|
||||||
|
if (cleanUrl.endsWith(".gif")) return "image/gif";
|
||||||
|
if (cleanUrl.endsWith(".bmp")) return "image/bmp";
|
||||||
|
if (cleanUrl.endsWith(".svg")) return "image/svg+xml";
|
||||||
|
return "image/png";
|
||||||
|
}
|
||||||
|
|
||||||
|
function injectHistoryImagesToLastUserMessage(
|
||||||
|
messages: ChatMessage[],
|
||||||
|
historyImages: string[]
|
||||||
|
): ChatMessage[] {
|
||||||
|
if (!historyImages || historyImages.length === 0) return messages;
|
||||||
|
|
||||||
|
let lastUserIndex = -1;
|
||||||
|
for (let i = messages.length - 1; i >= 0; i--) {
|
||||||
|
if (messages[i]?.role === "user") {
|
||||||
|
lastUserIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastUserIndex < 0) return messages;
|
||||||
|
|
||||||
|
const lastUserMessage = messages[lastUserIndex];
|
||||||
|
const hasExistingImage = lastUserMessage.parts?.some(
|
||||||
|
(p: any) => p.type === "file" || p.type === "image" || p.type === "image_url"
|
||||||
|
);
|
||||||
|
if (hasExistingImage) return messages;
|
||||||
|
|
||||||
|
const imageParts = historyImages.map((url, index) => ({
|
||||||
|
type: "file" as const,
|
||||||
|
url,
|
||||||
|
name: `history-image-${index + 1}`,
|
||||||
|
mediaType: guessImageMediaType(url),
|
||||||
|
mimeType: guessImageMediaType(url),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const updatedMessage: ChatMessage = {
|
||||||
|
...lastUserMessage,
|
||||||
|
parts: [...lastUserMessage.parts, ...imageParts],
|
||||||
|
};
|
||||||
|
|
||||||
|
return messages.map((msg, idx) => (idx === lastUserIndex ? updatedMessage : msg));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自定义消息转换函数
|
* 自定义消息转换函数
|
||||||
* 注意:gemini-image 和 huanke-gemini 都需要 URL 格式(不是 Base64)
|
* 注意:gemini-image 和 huanke-gemini 都需要 URL 格式(不是 Base64)
|
||||||
@ -823,7 +871,8 @@ export async function POST(request: Request) {
|
|||||||
|
|
||||||
// 只传递最后一条用户消息,避免上下文历史干扰生图效果
|
// 只传递最后一条用户消息,避免上下文历史干扰生图效果
|
||||||
const lastUserMessage = uiMessagesForModel.filter((m) => m.role === "user").pop();
|
const lastUserMessage = uiMessagesForModel.filter((m) => m.role === "user").pop();
|
||||||
const messagesForGemini = lastUserMessage ? [lastUserMessage] : uiMessagesForModel;
|
let messagesForGemini = lastUserMessage ? [lastUserMessage] : uiMessagesForModel;
|
||||||
|
messagesForGemini = injectHistoryImagesToLastUserMessage(messagesForGemini, smartAutoHistoryImages);
|
||||||
console.log("[Chat API] Gemini: Using only last user message (no history context)");
|
console.log("[Chat API] Gemini: Using only last user message (no history context)");
|
||||||
|
|
||||||
// 转换消息:gemini-image 需要 base64 格式,huanke-gemini 需要 URL 格式
|
// 转换消息:gemini-image 需要 base64 格式,huanke-gemini 需要 URL 格式
|
||||||
@ -971,7 +1020,10 @@ export async function POST(request: Request) {
|
|||||||
console.log("[Chat API] Executing Volcano Vision failover...");
|
console.log("[Chat API] Executing Volcano Vision failover...");
|
||||||
|
|
||||||
// 转换消息(火山引擎会自动处理 Base64)
|
// 转换消息(火山引擎会自动处理 Base64)
|
||||||
const volcanoMessages = await convertMessagesWithImages(uiMessagesForModel, "volcano");
|
const volcanoMessages = await convertMessagesWithImages(
|
||||||
|
injectHistoryImagesToLastUserMessage(uiMessagesForModel, smartAutoHistoryImages),
|
||||||
|
"volcano"
|
||||||
|
);
|
||||||
|
|
||||||
// 调用火山引擎生成(故障转移时只生成 1 张,保持与 Gemini 一致)
|
// 调用火山引擎生成(故障转移时只生成 1 张,保持与 Gemini 一致)
|
||||||
const volcanoResult = await (volcanoLanguageModel as any).doGenerate({
|
const volcanoResult = await (volcanoLanguageModel as any).doGenerate({
|
||||||
@ -1189,32 +1241,7 @@ export async function POST(request: Request) {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🆕 如果使用了历史图片,将其注入到消息中(支持多张)
|
messagesForAlibaba = injectHistoryImagesToLastUserMessage(messagesForAlibaba, smartAutoHistoryImages);
|
||||||
if (smartAutoHistoryImages.length > 0 && messagesForAlibaba.length > 0) {
|
|
||||||
console.log("[Chat API] 🖼️ Injecting", smartAutoHistoryImages.length, "history image(s) into message");
|
|
||||||
messagesForAlibaba = messagesForAlibaba.map((msg) => {
|
|
||||||
// 检查消息中是否已有图片
|
|
||||||
const hasExistingImage = msg.parts.some(
|
|
||||||
(p: any) => p.type === "file" || p.type === "image"
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!hasExistingImage) {
|
|
||||||
// 注入所有历史图片
|
|
||||||
const imageParts = smartAutoHistoryImages.map((url) => ({
|
|
||||||
type: "file" as const,
|
|
||||||
url,
|
|
||||||
mediaType: "image/png",
|
|
||||||
mimeType: "image/png",
|
|
||||||
}));
|
|
||||||
return {
|
|
||||||
...msg,
|
|
||||||
// @ts-ignore - 类型兼容性问题,运行时正确
|
|
||||||
parts: [...msg.parts, ...imageParts],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return msg;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const tryGenerateImage = async (modelIdToUse: string, isRetry: boolean) => {
|
const tryGenerateImage = async (modelIdToUse: string, isRetry: boolean) => {
|
||||||
// 转换消息(阿里生图支持 URL,会自动上传 base64)
|
// 转换消息(阿里生图支持 URL,会自动上传 base64)
|
||||||
@ -1435,6 +1462,8 @@ export async function POST(request: Request) {
|
|||||||
return msg;
|
return msg;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
messagesForVolcano = injectHistoryImagesToLastUserMessage(messagesForVolcano, smartAutoHistoryImages);
|
||||||
|
|
||||||
const volcanoStream = createUIMessageStream({
|
const volcanoStream = createUIMessageStream({
|
||||||
execute: async ({ writer }) => {
|
execute: async ({ writer }) => {
|
||||||
@ -1763,7 +1792,10 @@ export async function POST(request: Request) {
|
|||||||
console.log("[Chat API] Provider type:", (languageModel as any).provider); // 调试日志
|
console.log("[Chat API] Provider type:", (languageModel as any).provider); // 调试日志
|
||||||
|
|
||||||
// 转换消息,对于 Gemini 和千问视频将图片 URL 转换为 base64
|
// 转换消息,对于 Gemini 和千问视频将图片 URL 转换为 base64
|
||||||
const convertedMessages = await convertMessagesWithImages(uiMessagesForModel, (languageModel as any).provider || "");
|
const convertedMessages = await convertMessagesWithImages(
|
||||||
|
injectHistoryImagesToLastUserMessage(uiMessagesForModel, smartAutoHistoryImages),
|
||||||
|
(languageModel as any).provider || ""
|
||||||
|
);
|
||||||
console.log("[Chat API] Messages converted, count:", convertedMessages.length); // 调试日志
|
console.log("[Chat API] Messages converted, count:", convertedMessages.length); // 调试日志
|
||||||
|
|
||||||
// 🆕 检测是否是视频模型
|
// 🆕 检测是否是视频模型
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user