diff --git a/controller/channel-test.go b/controller/channel-test.go index f9657edb..2ae8b0ef 100644 --- a/controller/channel-test.go +++ b/controller/channel-test.go @@ -193,6 +193,7 @@ func testChannel(channel *model.Channel, testModel string, endpointType string) } } + info.IsChannelTest = true info.InitChannelMeta(c) err = helper.ModelMappedHelper(c, info, request) @@ -309,6 +310,27 @@ func testChannel(channel *model.Channel, testModel string, endpointType string) newAPIError: types.NewError(err, types.ErrorCodeJsonMarshalFailed), } } + + //jsonData, err = relaycommon.RemoveDisabledFields(jsonData, info.ChannelOtherSettings) + //if err != nil { + // return testResult{ + // context: c, + // localErr: err, + // newAPIError: types.NewError(err, types.ErrorCodeConvertRequestFailed), + // } + //} + + if len(info.ParamOverride) > 0 { + jsonData, err = relaycommon.ApplyParamOverride(jsonData, info.ParamOverride, relaycommon.BuildParamOverrideContext(info)) + if err != nil { + return testResult{ + context: c, + localErr: err, + newAPIError: types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid), + } + } + } + requestBody := bytes.NewBuffer(jsonData) c.Request.Body = io.NopCloser(requestBody) resp, err := adaptor.DoRequest(c, info, requestBody) diff --git a/relay/common/override.go b/relay/common/override.go index 872c960f..1a0c2478 100644 --- a/relay/common/override.go +++ b/relay/common/override.go @@ -570,18 +570,19 @@ func mergeObjects(jsonStr, path string, value interface{}, keepOrigin bool) (str // BuildParamOverrideContext 提供 ApplyParamOverride 可用的上下文信息。 // 目前内置以下字段: -// - model:优先使用上游模型名(UpstreamModelName),若不存在则回落到原始模型名(OriginModelName)。 -// - upstream_model:始终为通道映射后的上游模型名。 +// - upstream_model/model:始终为通道映射后的上游模型名。 // - original_model:请求最初指定的模型名。 +// - request_path:请求路径 +// - is_channel_test:是否为渠道测试请求(同 is_test)。 func BuildParamOverrideContext(info *RelayInfo) map[string]interface{} { - if info == nil || info.ChannelMeta == nil { + if info == nil { return nil } ctx := make(map[string]interface{}) - if info.UpstreamModelName != "" { - ctx["model"] = info.UpstreamModelName - ctx["upstream_model"] = info.UpstreamModelName + if info.ChannelMeta != nil && info.ChannelMeta.UpstreamModelName != "" { + ctx["model"] = info.ChannelMeta.UpstreamModelName + ctx["upstream_model"] = info.ChannelMeta.UpstreamModelName } if info.OriginModelName != "" { ctx["original_model"] = info.OriginModelName @@ -590,8 +591,13 @@ func BuildParamOverrideContext(info *RelayInfo) map[string]interface{} { } } - if len(ctx) == 0 { - return nil + if info.RequestURLPath != "" { + requestPath := info.RequestURLPath + if requestPath != "" { + ctx["request_path"] = requestPath + } } + + ctx["is_channel_test"] = info.IsChannelTest return ctx } diff --git a/relay/common/relay_info.go b/relay/common/relay_info.go index 1b9762fe..56f16fbf 100644 --- a/relay/common/relay_info.go +++ b/relay/common/relay_info.go @@ -115,6 +115,7 @@ type RelayInfo struct { SendResponseCount int FinalPreConsumedQuota int // 最终预消耗的配额 IsClaudeBetaQuery bool // /v1/messages?beta=true + IsChannelTest bool // channel test request PriceData types.PriceData diff --git a/web/src/components/table/channels/modals/EditChannelModal.jsx b/web/src/components/table/channels/modals/EditChannelModal.jsx index 0abd3fdf..722c1e8a 100644 --- a/web/src/components/table/channels/modals/EditChannelModal.jsx +++ b/web/src/components/table/channels/modals/EditChannelModal.jsx @@ -199,17 +199,11 @@ const EditChannelModal = (props) => { if (!trimmed) return []; try { const parsed = JSON.parse(trimmed); - if ( - !parsed || - typeof parsed !== 'object' || - Array.isArray(parsed) - ) { + if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) { return []; } const values = Object.values(parsed) - .map((value) => - typeof value === 'string' ? value.trim() : undefined, - ) + .map((value) => (typeof value === 'string' ? value.trim() : undefined)) .filter((value) => value); return Array.from(new Set(values)); } catch (error) { @@ -509,6 +503,18 @@ const EditChannelModal = (props) => { //setAutoBan }; + const formatJsonField = (fieldName) => { + const rawValue = (inputs?.[fieldName] ?? '').trim(); + if (!rawValue) return; + + try { + const parsed = JSON.parse(rawValue); + handleInputChange(fieldName, JSON.stringify(parsed, null, 2)); + } catch (error) { + showError(`${t('JSON格式错误')}: ${error.message}`); + } + }; + const loadChannel = async () => { setLoading(true); let res = await API.get(`/api/channel/${channelId}`); @@ -2812,6 +2818,12 @@ const EditChannelModal = (props) => { > {t('新格式模板')} + formatJsonField('param_override')} + > + {t('格式化')} + } showClear @@ -2852,6 +2864,12 @@ const EditChannelModal = (props) => { > {t('填入模板')} + formatJsonField('header_override')} + > + {t('格式化')} +
@@ -3181,7 +3199,9 @@ const EditChannelModal = (props) => { ? inputs.models.map(String) : []; const incoming = modelIds.map(String); - const nextModels = Array.from(new Set([...existingModels, ...incoming])); + const nextModels = Array.from( + new Set([...existingModels, ...incoming]), + ); handleInputChange('models', nextModels); if (formApiRef.current) {