refactor: 提取 getOrCreateGeminiParts 减少重复代码

将两个 merge 函数中重复的 Gemini 响应结构访问逻辑提取为公共函数。
This commit is contained in:
song
2026-01-13 13:25:55 +08:00
parent c9d21d53e6
commit 9a22d1a690

View File

@@ -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
}