| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- package gemini
- import (
- "io"
- "net/http"
- "one-api/common"
- "one-api/dto"
- relaycommon "one-api/relay/common"
- "one-api/relay/helper"
- "one-api/service"
- "one-api/types"
- "strings"
- "github.com/gin-gonic/gin"
- )
- func GeminiTextGenerationHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *http.Response) (*dto.Usage, *types.NewAPIError) {
- defer common.CloseResponseBodyGracefully(resp)
- // 读取响应体
- responseBody, err := io.ReadAll(resp.Body)
- if err != nil {
- return nil, types.NewError(err, types.ErrorCodeBadResponseBody)
- }
- if common.DebugEnabled {
- println(string(responseBody))
- }
- // 解析为 Gemini 原生响应格式
- var geminiResponse GeminiChatResponse
- err = common.Unmarshal(responseBody, &geminiResponse)
- if err != nil {
- return nil, types.NewError(err, types.ErrorCodeBadResponseBody)
- }
- // 计算使用量(基于 UsageMetadata)
- usage := dto.Usage{
- PromptTokens: geminiResponse.UsageMetadata.PromptTokenCount,
- CompletionTokens: geminiResponse.UsageMetadata.CandidatesTokenCount + geminiResponse.UsageMetadata.ThoughtsTokenCount,
- TotalTokens: geminiResponse.UsageMetadata.TotalTokenCount,
- }
- usage.CompletionTokenDetails.ReasoningTokens = geminiResponse.UsageMetadata.ThoughtsTokenCount
- for _, detail := range geminiResponse.UsageMetadata.PromptTokensDetails {
- if detail.Modality == "AUDIO" {
- usage.PromptTokensDetails.AudioTokens = detail.TokenCount
- } else if detail.Modality == "TEXT" {
- usage.PromptTokensDetails.TextTokens = detail.TokenCount
- }
- }
- // 直接返回 Gemini 原生格式的 JSON 响应
- jsonResponse, err := common.Marshal(geminiResponse)
- if err != nil {
- return nil, types.NewError(err, types.ErrorCodeBadResponseBody)
- }
- common.IOCopyBytesGracefully(c, resp, jsonResponse)
- return &usage, nil
- }
- func GeminiTextGenerationStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *http.Response) (*dto.Usage, *types.NewAPIError) {
- var usage = &dto.Usage{}
- var imageCount int
- helper.SetEventStreamHeaders(c)
- responseText := strings.Builder{}
- helper.StreamScannerHandler(c, resp, info, func(data string) bool {
- var geminiResponse GeminiChatResponse
- err := common.UnmarshalJsonStr(data, &geminiResponse)
- if err != nil {
- common.LogError(c, "error unmarshalling stream response: "+err.Error())
- return false
- }
- // 统计图片数量
- for _, candidate := range geminiResponse.Candidates {
- for _, part := range candidate.Content.Parts {
- if part.InlineData != nil && part.InlineData.MimeType != "" {
- imageCount++
- }
- if part.Text != "" {
- responseText.WriteString(part.Text)
- }
- }
- }
- // 更新使用量统计
- if geminiResponse.UsageMetadata.TotalTokenCount != 0 {
- usage.PromptTokens = geminiResponse.UsageMetadata.PromptTokenCount
- usage.CompletionTokens = geminiResponse.UsageMetadata.CandidatesTokenCount + geminiResponse.UsageMetadata.ThoughtsTokenCount
- usage.TotalTokens = geminiResponse.UsageMetadata.TotalTokenCount
- usage.CompletionTokenDetails.ReasoningTokens = geminiResponse.UsageMetadata.ThoughtsTokenCount
- for _, detail := range geminiResponse.UsageMetadata.PromptTokensDetails {
- if detail.Modality == "AUDIO" {
- usage.PromptTokensDetails.AudioTokens = detail.TokenCount
- } else if detail.Modality == "TEXT" {
- usage.PromptTokensDetails.TextTokens = detail.TokenCount
- }
- }
- }
- // 直接发送 GeminiChatResponse 响应
- err = helper.StringData(c, data)
- if err != nil {
- common.LogError(c, err.Error())
- }
- return true
- })
- if imageCount != 0 {
- if usage.CompletionTokens == 0 {
- usage.CompletionTokens = imageCount * 258
- }
- }
- // 如果usage.CompletionTokens为0,则使用本地统计的completion tokens
- if usage.CompletionTokens == 0 {
- str := responseText.String()
- if len(str) > 0 {
- usage = service.ResponseText2Usage(responseText.String(), info.UpstreamModelName, info.PromptTokens)
- } else {
- // 空补全,不需要使用量
- usage = &dto.Usage{}
- }
- }
- // 移除流式响应结尾的[Done],因为Gemini API没有发送Done的行为
- //helper.Done(c)
- return usage, nil
- }
|