mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-03-30 11:13:40 +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")
|
||||
}
|
||||
|
||||
geminiRequest, err := CovertGemini2OpenAI(c, *request, info)
|
||||
geminiRequest, err := CovertOpenAI2Gemini(c, *request, info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ var geminiSupportedMimeTypes = map[string]bool{
|
||||
"video/flv": true,
|
||||
}
|
||||
|
||||
const thoughtSignatureBypassValue = "context_engineering_is_the_way_to_go"
|
||||
|
||||
// Gemini 允许的思考预算范围
|
||||
const (
|
||||
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
|
||||
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{
|
||||
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) {
|
||||
geminiRequest.GenerationConfig.ResponseModalities = []string{
|
||||
"TEXT",
|
||||
@@ -371,6 +377,8 @@ func CovertGemini2OpenAI(c *gin.Context, textRequest dto.GeneralOpenAIRequest, i
|
||||
content := dto.GeminiChatContent{
|
||||
Role: message.Role,
|
||||
}
|
||||
shouldAttachThoughtSignature := attachThoughtSignature && (message.Role == "assistant" || message.Role == "model")
|
||||
signatureAttached := false
|
||||
// isToolCall := false
|
||||
if message.ToolCalls != nil {
|
||||
// message.Role = "model"
|
||||
@@ -388,6 +396,10 @@ func CovertGemini2OpenAI(c *gin.Context, textRequest dto.GeneralOpenAIRequest, i
|
||||
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)
|
||||
tool_call_ids[call.ID] = call.Function.Name
|
||||
}
|
||||
@@ -496,6 +508,28 @@ func CovertGemini2OpenAI(c *gin.Context, textRequest dto.GeneralOpenAIRequest, i
|
||||
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
|
||||
func getSupportedMimeTypesList() []string {
|
||||
keys := make([]string, 0, len(geminiSupportedMimeTypes))
|
||||
|
||||
@@ -296,7 +296,7 @@ func (a *Adaptor) ConvertOpenAIRequest(c *gin.Context, info *relaycommon.RelayIn
|
||||
info.UpstreamModelName = claudeReq.Model
|
||||
return vertexClaudeReq, nil
|
||||
} else if a.RequestMode == RequestModeGemini {
|
||||
geminiRequest, err := gemini.CovertGemini2OpenAI(c, *request, info)
|
||||
geminiRequest, err := gemini.CovertOpenAI2Gemini(c, *request, info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ type GeminiSettings struct {
|
||||
SupportedImagineModels []string `json:"supported_imagine_models"`
|
||||
ThinkingAdapterEnabled bool `json:"thinking_adapter_enabled"`
|
||||
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,
|
||||
ThinkingAdapterBudgetTokensPercentage: 0.6,
|
||||
FunctionCallThoughtSignatureEnabled: true,
|
||||
}
|
||||
|
||||
// 全局实例
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"configVersion": 0,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "react-template",
|
||||
|
||||
@@ -69,6 +69,8 @@
|
||||
"Gemini思考适配设置": "Gemini thinking adaptation settings",
|
||||
"Gemini版本设置": "Gemini version 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 Client ID": "GitHub Client ID",
|
||||
"GitHub Client Secret": "GitHub Client Secret",
|
||||
|
||||
@@ -71,6 +71,8 @@
|
||||
"Gemini思考适配设置": "Paramètres d'adaptation de la pensée Gemini",
|
||||
"Gemini版本设置": "Paramètres de version 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 Client ID": "ID client GitHub",
|
||||
"GitHub Client Secret": "Secret client GitHub",
|
||||
|
||||
@@ -69,6 +69,8 @@
|
||||
"Gemini思考适配设置": "Gemini思考モード設定",
|
||||
"Gemini版本设置": "Geminiバージョン設定",
|
||||
"Gemini设置": "Gemini設定",
|
||||
"启用FunctionCall思维签名填充": "FunctionCall用のthoughtSignature自動付与を有効化",
|
||||
"仅为使用OpenAI格式的Gemini/Vertex渠道填充thoughtSignature": "OpenAI形式を利用するGemini/VertexチャネルにのみthoughtSignatureを付与します",
|
||||
"GitHub": "GitHub",
|
||||
"GitHub Client ID": "GitHub Client ID",
|
||||
"GitHub Client Secret": "GitHub Client Secret",
|
||||
|
||||
@@ -73,6 +73,8 @@
|
||||
"Gemini思考适配设置": "Настройки адаптации мышления Gemini",
|
||||
"Gemini版本设置": "Настройки версии Gemini",
|
||||
"Gemini设置": "Настройки Gemini",
|
||||
"启用FunctionCall思维签名填充": "Включить автозаполнение thoughtSignature для FunctionCall",
|
||||
"仅为使用OpenAI格式的Gemini/Vertex渠道填充thoughtSignature": "Заполнять thoughtSignature только для каналов Gemini/Vertex, использующих формат OpenAI",
|
||||
"GitHub": "GitHub",
|
||||
"GitHub Client ID": "ID клиента GitHub",
|
||||
"GitHub Client Secret": "Секрет клиента GitHub",
|
||||
|
||||
@@ -67,6 +67,8 @@
|
||||
"Gemini思考适配设置": "Gemini思考适配设置",
|
||||
"Gemini版本设置": "Gemini版本设置",
|
||||
"Gemini设置": "Gemini设置",
|
||||
"启用FunctionCall思维签名填充": "启用FunctionCall思维签名填充",
|
||||
"仅为使用OpenAI格式的Gemini/Vertex渠道填充thoughtSignature": "仅为使用OpenAI格式的Gemini/Vertex渠道填充thoughtSignature",
|
||||
"GitHub": "GitHub",
|
||||
"GitHub Client ID": "GitHub Client ID",
|
||||
"GitHub Client Secret": "GitHub Client Secret",
|
||||
|
||||
@@ -39,19 +39,22 @@ const GEMINI_VERSION_EXAMPLE = {
|
||||
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) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [inputs, setInputs] = useState({
|
||||
'gemini.safety_settings': '',
|
||||
'gemini.version_settings': '',
|
||||
'gemini.supported_imagine_models': '',
|
||||
'gemini.thinking_adapter_enabled': false,
|
||||
'gemini.thinking_adapter_budget_tokens_percentage': 0.6,
|
||||
});
|
||||
const [inputs, setInputs] = useState(DEFAULT_GEMINI_INPUTS);
|
||||
const refForm = useRef();
|
||||
const [inputsRow, setInputsRow] = useState(inputs);
|
||||
const [inputsRow, setInputsRow] = useState(DEFAULT_GEMINI_INPUTS);
|
||||
|
||||
async function onSubmit() {
|
||||
await refForm.current
|
||||
@@ -92,9 +95,9 @@ export default function SettingGeminiModel(props) {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const currentInputs = {};
|
||||
const currentInputs = { ...DEFAULT_GEMINI_INPUTS };
|
||||
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];
|
||||
}
|
||||
}
|
||||
@@ -166,6 +169,23 @@ export default function SettingGeminiModel(props) {
|
||||
/>
|
||||
</Col>
|
||||
</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>
|
||||
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
|
||||
<Form.TextArea
|
||||
|
||||
Reference in New Issue
Block a user