mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-04-19 11:28:38 +00:00
Merge pull request #2256 from seefs001/feature/gemini-3-openai
feat: Fill thoughtSignature only for Gemini/Vertex channels using OpenAI format
This commit is contained in:
@@ -177,7 +177,7 @@ func (a *Adaptor) ConvertOpenAIRequest(c *gin.Context, info *relaycommon.RelayIn
|
|||||||
return nil, errors.New("request is nil")
|
return nil, errors.New("request is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
geminiRequest, err := CovertGemini2OpenAI(c, *request, info)
|
geminiRequest, err := CovertOpenAI2Gemini(c, *request, info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ var geminiSupportedMimeTypes = map[string]bool{
|
|||||||
"video/flv": true,
|
"video/flv": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const thoughtSignatureBypassValue = "context_engineering_is_the_way_to_go"
|
||||||
|
|
||||||
// Gemini 允许的思考预算范围
|
// Gemini 允许的思考预算范围
|
||||||
const (
|
const (
|
||||||
pro25MinBudget = 128
|
pro25MinBudget = 128
|
||||||
@@ -181,7 +183,7 @@ func ThinkingAdaptor(geminiRequest *dto.GeminiChatRequest, info *relaycommon.Rel
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setting safety to the lowest possible values since Gemini is already powerless enough
|
// Setting safety to the lowest possible values since Gemini is already powerless enough
|
||||||
func CovertGemini2OpenAI(c *gin.Context, textRequest dto.GeneralOpenAIRequest, info *relaycommon.RelayInfo) (*dto.GeminiChatRequest, error) {
|
func CovertOpenAI2Gemini(c *gin.Context, textRequest dto.GeneralOpenAIRequest, info *relaycommon.RelayInfo) (*dto.GeminiChatRequest, error) {
|
||||||
|
|
||||||
geminiRequest := dto.GeminiChatRequest{
|
geminiRequest := dto.GeminiChatRequest{
|
||||||
Contents: make([]dto.GeminiChatContent, 0, len(textRequest.Messages)),
|
Contents: make([]dto.GeminiChatContent, 0, len(textRequest.Messages)),
|
||||||
@@ -193,6 +195,10 @@ func CovertGemini2OpenAI(c *gin.Context, textRequest dto.GeneralOpenAIRequest, i
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attachThoughtSignature := (info.ChannelType == constant.ChannelTypeGemini ||
|
||||||
|
info.ChannelType == constant.ChannelTypeVertexAi) &&
|
||||||
|
model_setting.GetGeminiSettings().FunctionCallThoughtSignatureEnabled
|
||||||
|
|
||||||
if model_setting.IsGeminiModelSupportImagine(info.UpstreamModelName) {
|
if model_setting.IsGeminiModelSupportImagine(info.UpstreamModelName) {
|
||||||
geminiRequest.GenerationConfig.ResponseModalities = []string{
|
geminiRequest.GenerationConfig.ResponseModalities = []string{
|
||||||
"TEXT",
|
"TEXT",
|
||||||
@@ -371,6 +377,8 @@ func CovertGemini2OpenAI(c *gin.Context, textRequest dto.GeneralOpenAIRequest, i
|
|||||||
content := dto.GeminiChatContent{
|
content := dto.GeminiChatContent{
|
||||||
Role: message.Role,
|
Role: message.Role,
|
||||||
}
|
}
|
||||||
|
shouldAttachThoughtSignature := attachThoughtSignature && (message.Role == "assistant" || message.Role == "model")
|
||||||
|
signatureAttached := false
|
||||||
// isToolCall := false
|
// isToolCall := false
|
||||||
if message.ToolCalls != nil {
|
if message.ToolCalls != nil {
|
||||||
// message.Role = "model"
|
// message.Role = "model"
|
||||||
@@ -388,6 +396,10 @@ func CovertGemini2OpenAI(c *gin.Context, textRequest dto.GeneralOpenAIRequest, i
|
|||||||
Arguments: args,
|
Arguments: args,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
if shouldAttachThoughtSignature && !signatureAttached && hasFunctionCallContent(toolCall.FunctionCall) && len(toolCall.ThoughtSignature) == 0 {
|
||||||
|
toolCall.ThoughtSignature = json.RawMessage(strconv.Quote(thoughtSignatureBypassValue))
|
||||||
|
signatureAttached = true
|
||||||
|
}
|
||||||
parts = append(parts, toolCall)
|
parts = append(parts, toolCall)
|
||||||
tool_call_ids[call.ID] = call.Function.Name
|
tool_call_ids[call.ID] = call.Function.Name
|
||||||
}
|
}
|
||||||
@@ -496,6 +508,28 @@ func CovertGemini2OpenAI(c *gin.Context, textRequest dto.GeneralOpenAIRequest, i
|
|||||||
return &geminiRequest, nil
|
return &geminiRequest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hasFunctionCallContent(call *dto.FunctionCall) bool {
|
||||||
|
if call == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(call.FunctionName) != "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := call.Arguments.(type) {
|
||||||
|
case nil:
|
||||||
|
return false
|
||||||
|
case string:
|
||||||
|
return strings.TrimSpace(v) != ""
|
||||||
|
case map[string]interface{}:
|
||||||
|
return len(v) > 0
|
||||||
|
case []interface{}:
|
||||||
|
return len(v) > 0
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Helper function to get a list of supported MIME types for error messages
|
// Helper function to get a list of supported MIME types for error messages
|
||||||
func getSupportedMimeTypesList() []string {
|
func getSupportedMimeTypesList() []string {
|
||||||
keys := make([]string, 0, len(geminiSupportedMimeTypes))
|
keys := make([]string, 0, len(geminiSupportedMimeTypes))
|
||||||
|
|||||||
@@ -296,7 +296,7 @@ func (a *Adaptor) ConvertOpenAIRequest(c *gin.Context, info *relaycommon.RelayIn
|
|||||||
info.UpstreamModelName = claudeReq.Model
|
info.UpstreamModelName = claudeReq.Model
|
||||||
return vertexClaudeReq, nil
|
return vertexClaudeReq, nil
|
||||||
} else if a.RequestMode == RequestModeGemini {
|
} else if a.RequestMode == RequestModeGemini {
|
||||||
geminiRequest, err := gemini.CovertGemini2OpenAI(c, *request, info)
|
geminiRequest, err := gemini.CovertOpenAI2Gemini(c, *request, info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ type GeminiSettings struct {
|
|||||||
SupportedImagineModels []string `json:"supported_imagine_models"`
|
SupportedImagineModels []string `json:"supported_imagine_models"`
|
||||||
ThinkingAdapterEnabled bool `json:"thinking_adapter_enabled"`
|
ThinkingAdapterEnabled bool `json:"thinking_adapter_enabled"`
|
||||||
ThinkingAdapterBudgetTokensPercentage float64 `json:"thinking_adapter_budget_tokens_percentage"`
|
ThinkingAdapterBudgetTokensPercentage float64 `json:"thinking_adapter_budget_tokens_percentage"`
|
||||||
|
FunctionCallThoughtSignatureEnabled bool `json:"function_call_thought_signature_enabled"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 默认配置
|
// 默认配置
|
||||||
@@ -29,6 +30,7 @@ var defaultGeminiSettings = GeminiSettings{
|
|||||||
},
|
},
|
||||||
ThinkingAdapterEnabled: false,
|
ThinkingAdapterEnabled: false,
|
||||||
ThinkingAdapterBudgetTokensPercentage: 0.6,
|
ThinkingAdapterBudgetTokensPercentage: 0.6,
|
||||||
|
FunctionCallThoughtSignatureEnabled: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 全局实例
|
// 全局实例
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
|
"configVersion": 0,
|
||||||
"workspaces": {
|
"workspaces": {
|
||||||
"": {
|
"": {
|
||||||
"name": "react-template",
|
"name": "react-template",
|
||||||
|
|||||||
@@ -69,6 +69,8 @@
|
|||||||
"Gemini思考适配设置": "Gemini thinking adaptation settings",
|
"Gemini思考适配设置": "Gemini thinking adaptation settings",
|
||||||
"Gemini版本设置": "Gemini version settings",
|
"Gemini版本设置": "Gemini version settings",
|
||||||
"Gemini设置": "Gemini settings",
|
"Gemini设置": "Gemini settings",
|
||||||
|
"启用FunctionCall思维签名填充": "Enable FunctionCall thoughtSignature fill",
|
||||||
|
"仅为使用OpenAI格式的Gemini/Vertex渠道填充thoughtSignature": "Fill thoughtSignature only for Gemini/Vertex channels using the OpenAI format",
|
||||||
"GitHub": "GitHub",
|
"GitHub": "GitHub",
|
||||||
"GitHub Client ID": "GitHub Client ID",
|
"GitHub Client ID": "GitHub Client ID",
|
||||||
"GitHub Client Secret": "GitHub Client Secret",
|
"GitHub Client Secret": "GitHub Client Secret",
|
||||||
|
|||||||
@@ -71,6 +71,8 @@
|
|||||||
"Gemini思考适配设置": "Paramètres d'adaptation de la pensée Gemini",
|
"Gemini思考适配设置": "Paramètres d'adaptation de la pensée Gemini",
|
||||||
"Gemini版本设置": "Paramètres de version Gemini",
|
"Gemini版本设置": "Paramètres de version Gemini",
|
||||||
"Gemini设置": "Paramètres Gemini",
|
"Gemini设置": "Paramètres Gemini",
|
||||||
|
"启用FunctionCall思维签名填充": "Activer le remplissage de thoughtSignature pour FunctionCall",
|
||||||
|
"仅为使用OpenAI格式的Gemini/Vertex渠道填充thoughtSignature": "Remplit thoughtSignature uniquement pour les canaux Gemini/Vertex utilisant le format OpenAI",
|
||||||
"GitHub": "GitHub",
|
"GitHub": "GitHub",
|
||||||
"GitHub Client ID": "ID client GitHub",
|
"GitHub Client ID": "ID client GitHub",
|
||||||
"GitHub Client Secret": "Secret client GitHub",
|
"GitHub Client Secret": "Secret client GitHub",
|
||||||
|
|||||||
@@ -69,6 +69,8 @@
|
|||||||
"Gemini思考适配设置": "Gemini思考モード設定",
|
"Gemini思考适配设置": "Gemini思考モード設定",
|
||||||
"Gemini版本设置": "Geminiバージョン設定",
|
"Gemini版本设置": "Geminiバージョン設定",
|
||||||
"Gemini设置": "Gemini設定",
|
"Gemini设置": "Gemini設定",
|
||||||
|
"启用FunctionCall思维签名填充": "FunctionCall用のthoughtSignature自動付与を有効化",
|
||||||
|
"仅为使用OpenAI格式的Gemini/Vertex渠道填充thoughtSignature": "OpenAI形式を利用するGemini/VertexチャネルにのみthoughtSignatureを付与します",
|
||||||
"GitHub": "GitHub",
|
"GitHub": "GitHub",
|
||||||
"GitHub Client ID": "GitHub Client ID",
|
"GitHub Client ID": "GitHub Client ID",
|
||||||
"GitHub Client Secret": "GitHub Client Secret",
|
"GitHub Client Secret": "GitHub Client Secret",
|
||||||
|
|||||||
@@ -73,6 +73,8 @@
|
|||||||
"Gemini思考适配设置": "Настройки адаптации мышления Gemini",
|
"Gemini思考适配设置": "Настройки адаптации мышления Gemini",
|
||||||
"Gemini版本设置": "Настройки версии Gemini",
|
"Gemini版本设置": "Настройки версии Gemini",
|
||||||
"Gemini设置": "Настройки Gemini",
|
"Gemini设置": "Настройки Gemini",
|
||||||
|
"启用FunctionCall思维签名填充": "Включить автозаполнение thoughtSignature для FunctionCall",
|
||||||
|
"仅为使用OpenAI格式的Gemini/Vertex渠道填充thoughtSignature": "Заполнять thoughtSignature только для каналов Gemini/Vertex, использующих формат OpenAI",
|
||||||
"GitHub": "GitHub",
|
"GitHub": "GitHub",
|
||||||
"GitHub Client ID": "ID клиента GitHub",
|
"GitHub Client ID": "ID клиента GitHub",
|
||||||
"GitHub Client Secret": "Секрет клиента GitHub",
|
"GitHub Client Secret": "Секрет клиента GitHub",
|
||||||
|
|||||||
@@ -67,6 +67,8 @@
|
|||||||
"Gemini思考适配设置": "Gemini思考适配设置",
|
"Gemini思考适配设置": "Gemini思考适配设置",
|
||||||
"Gemini版本设置": "Gemini版本设置",
|
"Gemini版本设置": "Gemini版本设置",
|
||||||
"Gemini设置": "Gemini设置",
|
"Gemini设置": "Gemini设置",
|
||||||
|
"启用FunctionCall思维签名填充": "启用FunctionCall思维签名填充",
|
||||||
|
"仅为使用OpenAI格式的Gemini/Vertex渠道填充thoughtSignature": "仅为使用OpenAI格式的Gemini/Vertex渠道填充thoughtSignature",
|
||||||
"GitHub": "GitHub",
|
"GitHub": "GitHub",
|
||||||
"GitHub Client ID": "GitHub Client ID",
|
"GitHub Client ID": "GitHub Client ID",
|
||||||
"GitHub Client Secret": "GitHub Client Secret",
|
"GitHub Client Secret": "GitHub Client Secret",
|
||||||
|
|||||||
@@ -39,19 +39,22 @@ const GEMINI_VERSION_EXAMPLE = {
|
|||||||
default: 'v1beta',
|
default: 'v1beta',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const DEFAULT_GEMINI_INPUTS = {
|
||||||
|
'gemini.safety_settings': '',
|
||||||
|
'gemini.version_settings': '',
|
||||||
|
'gemini.supported_imagine_models': '',
|
||||||
|
'gemini.thinking_adapter_enabled': false,
|
||||||
|
'gemini.thinking_adapter_budget_tokens_percentage': 0.6,
|
||||||
|
'gemini.function_call_thought_signature_enabled': true,
|
||||||
|
};
|
||||||
|
|
||||||
export default function SettingGeminiModel(props) {
|
export default function SettingGeminiModel(props) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [inputs, setInputs] = useState({
|
const [inputs, setInputs] = useState(DEFAULT_GEMINI_INPUTS);
|
||||||
'gemini.safety_settings': '',
|
|
||||||
'gemini.version_settings': '',
|
|
||||||
'gemini.supported_imagine_models': '',
|
|
||||||
'gemini.thinking_adapter_enabled': false,
|
|
||||||
'gemini.thinking_adapter_budget_tokens_percentage': 0.6,
|
|
||||||
});
|
|
||||||
const refForm = useRef();
|
const refForm = useRef();
|
||||||
const [inputsRow, setInputsRow] = useState(inputs);
|
const [inputsRow, setInputsRow] = useState(DEFAULT_GEMINI_INPUTS);
|
||||||
|
|
||||||
async function onSubmit() {
|
async function onSubmit() {
|
||||||
await refForm.current
|
await refForm.current
|
||||||
@@ -92,9 +95,9 @@ export default function SettingGeminiModel(props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const currentInputs = {};
|
const currentInputs = { ...DEFAULT_GEMINI_INPUTS };
|
||||||
for (let key in props.options) {
|
for (let key in props.options) {
|
||||||
if (Object.keys(inputs).includes(key)) {
|
if (Object.prototype.hasOwnProperty.call(DEFAULT_GEMINI_INPUTS, key)) {
|
||||||
currentInputs[key] = props.options[key];
|
currentInputs[key] = props.options[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -166,6 +169,23 @@ export default function SettingGeminiModel(props) {
|
|||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Col span={16}>
|
||||||
|
<Form.Switch
|
||||||
|
label={t('启用FunctionCall思维签名填充')}
|
||||||
|
field={'gemini.function_call_thought_signature_enabled'}
|
||||||
|
extraText={t(
|
||||||
|
'仅为使用OpenAI格式的Gemini/Vertex渠道填充thoughtSignature',
|
||||||
|
)}
|
||||||
|
onChange={(value) =>
|
||||||
|
setInputs({
|
||||||
|
...inputs,
|
||||||
|
'gemini.function_call_thought_signature_enabled': value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
|
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
|
||||||
<Form.TextArea
|
<Form.TextArea
|
||||||
|
|||||||
Reference in New Issue
Block a user