From 9a22d1a690db4b67383e9bd6814a6dba5ab4171d Mon Sep 17 00:00:00 2001 From: song Date: Tue, 13 Jan 2026 13:25:55 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=8F=90=E5=8F=96=20getOrCreateGem?= =?UTF-8?q?iniParts=20=E5=87=8F=E5=B0=91=E9=87=8D=E5=A4=8D=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将两个 merge 函数中重复的 Gemini 响应结构访问逻辑提取为公共函数。 --- .../service/antigravity_gateway_service.go | 135 +++++++----------- 1 file changed, 53 insertions(+), 82 deletions(-) diff --git a/backend/internal/service/antigravity_gateway_service.go b/backend/internal/service/antigravity_gateway_service.go index 67f65929..001afba6 100644 --- a/backend/internal/service/antigravity_gateway_service.go +++ b/backend/internal/service/antigravity_gateway_service.go @@ -1689,120 +1689,93 @@ returnResponse: return &antigravityStreamResult{usage: usage, firstTokenMs: firstTokenMs}, nil } +// getOrCreateGeminiParts 获取 Gemini 响应的 parts 结构,返回深拷贝和更新回调 +func getOrCreateGeminiParts(response map[string]any) (result map[string]any, existingParts []any, setParts func([]any)) { + // 深拷贝 response + result = make(map[string]any) + for k, v := range response { + result[k] = v + } + + // 获取或创建 candidates + candidates, ok := result["candidates"].([]any) + if !ok || len(candidates) == 0 { + candidates = []any{map[string]any{}} + } + + // 获取第一个 candidate + candidate, ok := candidates[0].(map[string]any) + if !ok { + candidate = make(map[string]any) + candidates[0] = candidate + } + + // 获取或创建 content + content, ok := candidate["content"].(map[string]any) + if !ok { + content = map[string]any{"role": "model"} + candidate["content"] = content + } + + // 获取现有 parts + existingParts, ok = content["parts"].([]any) + if !ok { + existingParts = []any{} + } + + // 返回更新回调 + setParts = func(newParts []any) { + content["parts"] = newParts + result["candidates"] = candidates + } + + return result, existingParts, setParts +} + // mergeImagePartsToResponse 将收集到的图片 parts 合并到 Gemini 响应中 -// 这是因为流式响应中,图片可能在某个 chunk 返回,而最终 chunk 可能不包含图片 func mergeImagePartsToResponse(response map[string]any, imageParts []map[string]any) map[string]any { if len(imageParts) == 0 { return response } - // 深拷贝 response 避免修改原始数据 - result := make(map[string]any) - for k, v := range response { - result[k] = v - } - - // 获取或创建 candidates - candidates, ok := result["candidates"].([]any) - if !ok || len(candidates) == 0 { - candidates = []any{map[string]any{}} - } - - // 获取第一个 candidate - candidate, ok := candidates[0].(map[string]any) - if !ok { - candidate = make(map[string]any) - candidates[0] = candidate - } - - // 获取或创建 content - content, ok := candidate["content"].(map[string]any) - if !ok { - content = map[string]any{"role": "model"} - candidate["content"] = content - } - - // 获取现有 parts - existingParts, ok := content["parts"].([]any) - if !ok { - existingParts = []any{} - } + result, existingParts, setParts := getOrCreateGeminiParts(response) // 检查现有 parts 中是否已经有图片 - hasExistingImage := false for _, p := range existingParts { if pm, ok := p.(map[string]any); ok { if _, hasInline := pm["inlineData"]; hasInline { - hasExistingImage = true - break + return result // 已有图片,不重复添加 } } } - // 如果没有现有图片,添加收集到的图片 parts - if !hasExistingImage { - for _, imgPart := range imageParts { - existingParts = append(existingParts, imgPart) - } - content["parts"] = existingParts + // 添加收集到的图片 parts + for _, imgPart := range imageParts { + existingParts = append(existingParts, imgPart) } - - result["candidates"] = candidates + setParts(existingParts) return result } // mergeTextPartsToResponse 将收集到的文本合并到 Gemini 响应中 -// 流式响应是增量的,需要累积所有文本片段 func mergeTextPartsToResponse(response map[string]any, textParts []string) map[string]any { if len(textParts) == 0 { return response } - // 合并所有文本 mergedText := strings.Join(textParts, "") - - // 深拷贝 response 避免修改原始数据 - result := make(map[string]any) - for k, v := range response { - result[k] = v - } - - // 获取或创建 candidates - candidates, ok := result["candidates"].([]any) - if !ok || len(candidates) == 0 { - candidates = []any{map[string]any{}} - } - - // 获取第一个 candidate - candidate, ok := candidates[0].(map[string]any) - if !ok { - candidate = make(map[string]any) - candidates[0] = candidate - } - - // 获取或创建 content - content, ok := candidate["content"].(map[string]any) - if !ok { - content = map[string]any{"role": "model"} - candidate["content"] = content - } - - // 获取现有 parts - existingParts, ok := content["parts"].([]any) - if !ok { - existingParts = []any{} - } + result, existingParts, setParts := getOrCreateGeminiParts(response) // 查找并更新第一个 text part,或创建新的 - textUpdated := false newParts := make([]any, 0, len(existingParts)+1) + textUpdated := false + for _, p := range existingParts { pm, ok := p.(map[string]any) if !ok { newParts = append(newParts, p) continue } - // 跳过空文本的 part(可能只有 thoughtSignature) if _, hasText := pm["text"]; hasText && !textUpdated { // 用累积的文本替换 newPart := make(map[string]any) @@ -1817,13 +1790,11 @@ func mergeTextPartsToResponse(response map[string]any, textParts []string) map[s } } - // 如果没有找到 text part,添加一个新的 if !textUpdated { newParts = append([]any{map[string]any{"text": mergedText}}, newParts...) } - content["parts"] = newParts - result["candidates"] = candidates + setParts(newParts) return result }