渠道: 分协议 Base URL + 模型抽屉/远程拉取/操作图标

- 渠道支持分协议 base_url(chat/responses/messages 各一), 网关按协议选 base 直通
  (如智谱三种格式不同 base, 一个渠道即可), UpstreamURL 按 proto 拼接
- 渠道模型改为下方抽屉: 当前绑定列表(内联改上游/解除)、从接口拉取(remote 预览+勾选添加)、手动添加
- 新增 /channels/:id/models/remote 预览接口; 操作按钮加 Phosphor 图标
- 修复 formats jsonb 更新未序列化问题; 手机端渠道卡片化

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Sakurasan
2026-08-16 04:31:28 +08:00
co-authored by Claude
parent 7c4e80afac
commit db83972b6f
11 changed files with 484 additions and 246 deletions
+5 -4
View File
@@ -251,16 +251,17 @@ func (g *Gateway) checkBalance(c *gin.Context, u *store.User) bool {
func upstreamPath(proto string) string {
switch proto {
case convert.ProtoMessages:
return "/v1/messages"
return "/messages"
case convert.ProtoResponses:
return "/v1/responses"
return "/responses"
default:
return "/v1/chat/completions"
return "/chat/completions"
}
}
// upstreamPlan 描述一次代理请求的上游访问方式。
type upstreamPlan struct {
proto string // 上游协议(用于分协议 base_url)
path string // 上游路径
body []byte // 已转换的请求体
lineConv func([]byte) []byte // 流式逐行转换(nil=直通)
@@ -292,7 +293,7 @@ func prepareUpstream(ch *store.Channel, clientProto string, body []byte, upstrea
if target == "" {
return nil, fmt.Errorf("channel %q declares no supported protocol format", ch.Name)
}
plan := &upstreamPlan{path: upstreamPath(target), body: body}
plan := &upstreamPlan{proto: target, path: upstreamPath(target), body: body}
if target != clientProto {
converted, err := convert.ConvertRequest(body, clientProto, target)
if err != nil {