refactor: 提取 getOrCreateGeminiParts 减少重复代码
将两个 merge 函数中重复的 Gemini 响应结构访问逻辑提取为公共函数。
This commit is contained in:
@@ -1689,120 +1689,93 @@ returnResponse:
|
|||||||
return &antigravityStreamResult{usage: usage, firstTokenMs: firstTokenMs}, nil
|
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 响应中
|
// mergeImagePartsToResponse 将收集到的图片 parts 合并到 Gemini 响应中
|
||||||
// 这是因为流式响应中,图片可能在某个 chunk 返回,而最终 chunk 可能不包含图片
|
|
||||||
func mergeImagePartsToResponse(response map[string]any, imageParts []map[string]any) map[string]any {
|
func mergeImagePartsToResponse(response map[string]any, imageParts []map[string]any) map[string]any {
|
||||||
if len(imageParts) == 0 {
|
if len(imageParts) == 0 {
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
// 深拷贝 response 避免修改原始数据
|
result, existingParts, setParts := getOrCreateGeminiParts(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{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查现有 parts 中是否已经有图片
|
// 检查现有 parts 中是否已经有图片
|
||||||
hasExistingImage := false
|
|
||||||
for _, p := range existingParts {
|
for _, p := range existingParts {
|
||||||
if pm, ok := p.(map[string]any); ok {
|
if pm, ok := p.(map[string]any); ok {
|
||||||
if _, hasInline := pm["inlineData"]; hasInline {
|
if _, hasInline := pm["inlineData"]; hasInline {
|
||||||
hasExistingImage = true
|
return result // 已有图片,不重复添加
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果没有现有图片,添加收集到的图片 parts
|
// 添加收集到的图片 parts
|
||||||
if !hasExistingImage {
|
for _, imgPart := range imageParts {
|
||||||
for _, imgPart := range imageParts {
|
existingParts = append(existingParts, imgPart)
|
||||||
existingParts = append(existingParts, imgPart)
|
|
||||||
}
|
|
||||||
content["parts"] = existingParts
|
|
||||||
}
|
}
|
||||||
|
setParts(existingParts)
|
||||||
result["candidates"] = candidates
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// mergeTextPartsToResponse 将收集到的文本合并到 Gemini 响应中
|
// mergeTextPartsToResponse 将收集到的文本合并到 Gemini 响应中
|
||||||
// 流式响应是增量的,需要累积所有文本片段
|
|
||||||
func mergeTextPartsToResponse(response map[string]any, textParts []string) map[string]any {
|
func mergeTextPartsToResponse(response map[string]any, textParts []string) map[string]any {
|
||||||
if len(textParts) == 0 {
|
if len(textParts) == 0 {
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
// 合并所有文本
|
|
||||||
mergedText := strings.Join(textParts, "")
|
mergedText := strings.Join(textParts, "")
|
||||||
|
result, existingParts, setParts := getOrCreateGeminiParts(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{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查找并更新第一个 text part,或创建新的
|
// 查找并更新第一个 text part,或创建新的
|
||||||
textUpdated := false
|
|
||||||
newParts := make([]any, 0, len(existingParts)+1)
|
newParts := make([]any, 0, len(existingParts)+1)
|
||||||
|
textUpdated := false
|
||||||
|
|
||||||
for _, p := range existingParts {
|
for _, p := range existingParts {
|
||||||
pm, ok := p.(map[string]any)
|
pm, ok := p.(map[string]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
newParts = append(newParts, p)
|
newParts = append(newParts, p)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// 跳过空文本的 part(可能只有 thoughtSignature)
|
|
||||||
if _, hasText := pm["text"]; hasText && !textUpdated {
|
if _, hasText := pm["text"]; hasText && !textUpdated {
|
||||||
// 用累积的文本替换
|
// 用累积的文本替换
|
||||||
newPart := make(map[string]any)
|
newPart := make(map[string]any)
|
||||||
@@ -1817,13 +1790,11 @@ func mergeTextPartsToResponse(response map[string]any, textParts []string) map[s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果没有找到 text part,添加一个新的
|
|
||||||
if !textUpdated {
|
if !textUpdated {
|
||||||
newParts = append([]any{map[string]any{"text": mergedText}}, newParts...)
|
newParts = append([]any{map[string]any{"text": mergedText}}, newParts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
content["parts"] = newParts
|
setParts(newParts)
|
||||||
result["candidates"] = candidates
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user