2025-05-02 13:59:46 +08:00
package relay
import (
"bytes"
"fmt"
"io"
"net/http"
"strings"
2025-10-11 15:30:09 +08:00
"github.com/QuantumNous/new-api/common"
2026-01-26 20:20:16 +08:00
appconstant "github.com/QuantumNous/new-api/constant"
2025-10-11 15:30:09 +08:00
"github.com/QuantumNous/new-api/dto"
relaycommon "github.com/QuantumNous/new-api/relay/common"
2026-01-26 20:20:16 +08:00
relayconstant "github.com/QuantumNous/new-api/relay/constant"
2025-10-11 15:30:09 +08:00
"github.com/QuantumNous/new-api/relay/helper"
"github.com/QuantumNous/new-api/service"
"github.com/QuantumNous/new-api/setting/model_setting"
"github.com/QuantumNous/new-api/types"
2025-05-02 13:59:46 +08:00
"github.com/gin-gonic/gin"
)
2025-08-14 20:05:06 +08:00
func ResponsesHelper ( c * gin . Context , info * relaycommon . RelayInfo ) ( newAPIError * types . NewAPIError ) {
info . InitChannelMeta ( c )
2026-01-26 20:20:16 +08:00
if info . RelayMode == relayconstant . RelayModeResponsesCompact {
switch info . ApiType {
case appconstant . APITypeOpenAI , appconstant . APITypeCodex :
default :
return types . NewErrorWithStatusCode (
fmt . Errorf ( "unsupported endpoint %q for api type %d" , "/v1/responses/compact" , info . ApiType ) ,
types . ErrorCodeInvalidRequest ,
http . StatusBadRequest ,
types . ErrOptionWithSkipRetry ( ) ,
)
}
}
2025-05-02 13:59:46 +08:00
2026-01-26 20:20:16 +08:00
var responsesReq * dto . OpenAIResponsesRequest
switch req := info . Request . ( type ) {
case * dto . OpenAIResponsesRequest :
responsesReq = req
case * dto . OpenAIResponsesCompactionRequest :
responsesReq = & dto . OpenAIResponsesRequest {
Model : req . Model ,
Input : req . Input ,
Instructions : req . Instructions ,
PreviousResponseID : req . PreviousResponseID ,
}
default :
return types . NewErrorWithStatusCode (
fmt . Errorf ( "invalid request type, expected dto.OpenAIResponsesRequest or dto.OpenAIResponsesCompactionRequest, got %T" , info . Request ) ,
types . ErrorCodeInvalidRequest ,
http . StatusBadRequest ,
types . ErrOptionWithSkipRetry ( ) ,
)
2025-05-02 13:59:46 +08:00
}
2025-05-05 00:40:16 +08:00
2025-08-28 15:11:55 +08:00
request , err := common . DeepCopy ( responsesReq )
2025-08-23 13:13:10 +08:00
if err != nil {
return types . NewError ( fmt . Errorf ( "failed to copy request to GeneralOpenAIRequest: %w" , err ) , types . ErrorCodeInvalidRequest , types . ErrOptionWithSkipRetry ( ) )
}
err = helper . ModelMappedHelper ( c , info , request )
2025-05-02 13:59:46 +08:00
if err != nil {
2025-07-30 22:35:31 +08:00
return types . NewError ( err , types . ErrorCodeChannelModelMappedError , types . ErrOptionWithSkipRetry ( ) )
2025-05-02 13:59:46 +08:00
}
2025-06-20 16:02:23 +08:00
2025-08-14 20:05:06 +08:00
adaptor := GetAdaptor ( info . ApiType )
2025-05-02 13:59:46 +08:00
if adaptor == nil {
2025-08-14 20:05:06 +08:00
return types . NewError ( fmt . Errorf ( "invalid api type: %d" , info . ApiType ) , types . ErrorCodeInvalidApiType , types . ErrOptionWithSkipRetry ( ) )
2025-05-02 13:59:46 +08:00
}
2025-08-14 20:05:06 +08:00
adaptor . Init ( info )
2025-05-02 13:59:46 +08:00
var requestBody io . Reader
2025-09-11 21:02:12 +08:00
if model_setting . GetGlobalSettings ( ) . PassThroughRequestEnabled || info . ChannelSetting . PassThroughBodyEnabled {
2026-02-12 01:51:17 +08:00
storage , err := common . GetBodyStorage ( c )
2025-05-02 13:59:46 +08:00
if err != nil {
2025-07-30 22:35:31 +08:00
return types . NewError ( err , types . ErrorCodeReadRequestBodyFailed , types . ErrOptionWithSkipRetry ( ) )
2025-05-02 13:59:46 +08:00
}
2026-02-12 01:51:17 +08:00
requestBody = common . ReaderOnly ( storage )
2025-05-02 13:59:46 +08:00
} else {
2025-08-14 20:05:06 +08:00
convertedRequest , err := adaptor . ConvertOpenAIResponsesRequest ( c , info , * request )
2025-05-02 13:59:46 +08:00
if err != nil {
2025-07-30 22:35:31 +08:00
return types . NewError ( err , types . ErrorCodeConvertRequestFailed , types . ErrOptionWithSkipRetry ( ) )
2025-05-02 13:59:46 +08:00
}
2026-01-20 23:43:29 +08:00
relaycommon . AppendRequestConversionFromRequest ( info , convertedRequest )
2025-08-15 14:52:17 +08:00
jsonData , err := common . Marshal ( convertedRequest )
2025-05-02 13:59:46 +08:00
if err != nil {
2025-07-30 22:35:31 +08:00
return types . NewError ( err , types . ErrorCodeConvertRequestFailed , types . ErrOptionWithSkipRetry ( ) )
2025-05-02 13:59:46 +08:00
}
2025-10-02 00:14:35 +08:00
// remove disabled fields for OpenAI Responses API
jsonData , err = relaycommon . RemoveDisabledFields ( jsonData , info . ChannelOtherSettings )
if err != nil {
return types . NewError ( err , types . ErrorCodeConvertRequestFailed , types . ErrOptionWithSkipRetry ( ) )
}
2025-05-02 13:59:46 +08:00
// apply param override
2025-08-14 20:05:06 +08:00
if len ( info . ParamOverride ) > 0 {
2025-11-22 18:27:17 +08:00
jsonData , err = relaycommon . ApplyParamOverride ( jsonData , info . ParamOverride , relaycommon . BuildParamOverrideContext ( info ) )
2025-05-02 13:59:46 +08:00
if err != nil {
2026-02-22 00:10:49 +08:00
return newAPIErrorFromParamOverride ( err )
2025-05-02 13:59:46 +08:00
}
}
if common . DebugEnabled {
println ( "requestBody: " , string ( jsonData ) )
}
requestBody = bytes . NewBuffer ( jsonData )
}
var httpResp * http . Response
2025-08-14 20:05:06 +08:00
resp , err := adaptor . DoRequest ( c , info , requestBody )
2025-05-02 13:59:46 +08:00
if err != nil {
2025-07-19 11:29:31 +08:00
return types . NewOpenAIError ( err , types . ErrorCodeDoRequestFailed , http . StatusInternalServerError )
2025-05-02 13:59:46 +08:00
}
statusCodeMappingStr := c . GetString ( "status_code_mapping" )
if resp != nil {
httpResp = resp . ( * http . Response )
if httpResp . StatusCode != http . StatusOK {
2025-09-10 15:30:23 +08:00
newAPIError = service . RelayErrorHandler ( c . Request . Context ( ) , httpResp , false )
2025-05-02 13:59:46 +08:00
// reset status code 重置状态码
2025-07-10 15:02:40 +08:00
service . ResetStatusCode ( newAPIError , statusCodeMappingStr )
return newAPIError
2025-05-02 13:59:46 +08:00
}
}
2025-08-14 20:05:06 +08:00
usage , newAPIError := adaptor . DoResponse ( c , httpResp , info )
2025-07-10 15:02:40 +08:00
if newAPIError != nil {
2025-05-02 13:59:46 +08:00
// reset status code 重置状态码
2025-07-10 15:02:40 +08:00
service . ResetStatusCode ( newAPIError , statusCodeMappingStr )
return newAPIError
2025-05-02 13:59:46 +08:00
}
2026-01-26 20:20:16 +08:00
usageDto := usage . ( * dto . Usage )
if info . RelayMode == relayconstant . RelayModeResponsesCompact {
originModelName := info . OriginModelName
originPriceData := info . PriceData
_ , err := helper . ModelPriceHelper ( c , info , info . GetEstimatePromptTokens ( ) , & types . TokenCountMeta { } )
if err != nil {
info . OriginModelName = originModelName
info . PriceData = originPriceData
return types . NewError ( err , types . ErrorCodeModelPriceError , types . ErrOptionWithSkipRetry ( ) )
}
postConsumeQuota ( c , info , usageDto )
info . OriginModelName = originModelName
info . PriceData = originPriceData
return nil
}
2025-08-14 20:05:06 +08:00
if strings . HasPrefix ( info . OriginModelName , "gpt-4o-audio" ) {
2026-01-26 20:20:16 +08:00
service . PostAudioConsumeQuota ( c , info , usageDto , "" )
2025-05-02 13:59:46 +08:00
} else {
2026-01-26 20:20:16 +08:00
postConsumeQuota ( c , info , usageDto )
2025-05-02 13:59:46 +08:00
}
return nil
}