From a67af0485e4720e6e9ca38a89b95448564eafea7 Mon Sep 17 00:00:00 2001 From: ccnetcore Date: Sun, 11 Jan 2026 17:27:57 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=20Gemini=20=E5=9B=BE?= =?UTF-8?q?=E7=89=87=20base64=20=E8=8E=B7=E5=8F=96=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 从最后一个 part 逆序查找 inlineData 和 text,避免只读取首个 part 导致图片缺失 支持根据 inlineData.mimeType 动态生成 data:image 前缀 增强对多 part 返回结构的兼容性,提高图片解析成功率 --- .../Gemini/GeminiGenerateContentAcquirer.cs | 66 +++++++++++-------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Dtos/Gemini/GeminiGenerateContentAcquirer.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Dtos/Gemini/GeminiGenerateContentAcquirer.cs index 65012772..ca70532a 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Dtos/Gemini/GeminiGenerateContentAcquirer.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Dtos/Gemini/GeminiGenerateContentAcquirer.cs @@ -109,46 +109,58 @@ public static class GeminiGenerateContentAcquirer /// /// 获取图片 base64(包含 data:image 前缀) - /// 优先从 inlineData.data 中获取,其次从 markdown text 中解析 + /// 从最后一个 part 开始查找 inlineData,找不到再从最后一个 part 开始查找 text /// public static string GetImagePrefixBase64(JsonElement response) { - // Step 1: 优先尝试从 candidates[0].content.parts[0].inlineData.data 获取 - var inlineBase64 = response - .GetPath("candidates", 0, "content", "parts", 0, "inlineData", "data") - .GetString(); - - if (!string.IsNullOrEmpty(inlineBase64)) - { - // 默认按 png 格式拼接前缀 - return $"data:image/png;base64,{inlineBase64}"; - } - - // Step 2: fallback,从 candidates[0].content.parts[0].text 中解析 markdown 图片 - var text = response - .GetPath("candidates", 0, "content", "parts", 0, "text") - .GetString(); - - if (string.IsNullOrEmpty(text)) + var parts = response.GetPath("candidates", 0, "content", "parts"); + if (!parts.HasValue || parts.Value.ValueKind != JsonValueKind.Array) { return string.Empty; } - // markdown 图片格式: ![image](data:image/png;base64,xxx) - var startMarker = "(data:image/"; - var startIndex = text.IndexOf(startMarker, StringComparison.Ordinal); - if (startIndex < 0) + var partsArray = parts.Value.EnumerateArray().ToList(); + if (partsArray.Count == 0) { return string.Empty; } - startIndex += 1; // 跳过 "(" - var endIndex = text.IndexOf(')', startIndex); - if (endIndex <= startIndex) + // Step 1: 从最后一个 part 开始查找 inlineData + for (int i = partsArray.Count - 1; i >= 0; i--) { - return string.Empty; + var inlineBase64 = partsArray[i].GetPath("inlineData", "data").GetString(); + if (!string.IsNullOrEmpty(inlineBase64)) + { + var mimeType = partsArray[i].GetPath("inlineData", "mimeType").GetString() ?? "image/png"; + return $"data:{mimeType};base64,{inlineBase64}"; + } } - return text.Substring(startIndex, endIndex - startIndex); + // Step 2: 从最后一个 part 开始查找 text 中的 markdown 图片 + for (int i = partsArray.Count - 1; i >= 0; i--) + { + var text = partsArray[i].GetPath("text").GetString(); + if (string.IsNullOrEmpty(text)) + { + continue; + } + + // markdown 图片格式: ![image](data:image/png;base64,xxx) + var startMarker = "(data:image/"; + var startIndex = text.IndexOf(startMarker, StringComparison.Ordinal); + if (startIndex < 0) + { + continue; + } + + startIndex += 1; // 跳过 "(" + var endIndex = text.IndexOf(')', startIndex); + if (endIndex > startIndex) + { + return text.Substring(startIndex, endIndex - startIndex); + } + } + + return string.Empty; } } \ No newline at end of file