渠道支持多 API 格式 + 协议全名展示
- Channel 新增 formats(jsonb: chat|responses|messages), 一个渠道可同时声明 支持 OpenAI Chat Completions / OpenAI Responses API / Anthropic Messages - 路由改为按渠道声明的 formats 决定直通/转换: 客户端协议在 formats 内直通, 否则转换为其首选支持格式(chat > messages > responses) - 兼容旧数据: formats 为空时按 provider 推断(openai→chat+responses, anthropic→messages, compatible→chat) - 前端: 渠道表/表单展示 API 格式(支持多选), usage 明细显示协议全名 (OpenAI Chat Completions / OpenAI Responses API / Anthropic Messages) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ package proxy
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -175,21 +176,6 @@ func (g *Gateway) checkBalance(c *gin.Context, u *store.User) bool {
|
||||
// ---------------------------------------------------------------------------
|
||||
// 协议分派
|
||||
|
||||
// upstreamProtoFor 根据渠道 provider 与客户端协议确定上游协议与路径。
|
||||
func upstreamProtoFor(provider, clientProto string) string {
|
||||
switch provider {
|
||||
case store.ChannelProviderAnthropic:
|
||||
return convert.ProtoMessages
|
||||
case store.ChannelProviderOpenAI:
|
||||
if clientProto == convert.ProtoMessages {
|
||||
return convert.ProtoChat
|
||||
}
|
||||
return clientProto
|
||||
default: // compatible:假定 OpenAI Chat 形状
|
||||
return convert.ProtoChat
|
||||
}
|
||||
}
|
||||
|
||||
func upstreamPath(proto string) string {
|
||||
switch proto {
|
||||
case convert.ProtoMessages:
|
||||
@@ -209,18 +195,39 @@ type upstreamPlan struct {
|
||||
bodyConv func([]byte) ([]byte, error) // 非流式响应体转换(nil=直通)
|
||||
}
|
||||
|
||||
// prepareUpstream 计算上游访问计划:协议匹配直通,否则转换。
|
||||
func prepareUpstream(provider, clientProto string, body []byte) (*upstreamPlan, error) {
|
||||
up := upstreamProtoFor(provider, clientProto)
|
||||
plan := &upstreamPlan{path: upstreamPath(up), body: body}
|
||||
if up != clientProto {
|
||||
converted, err := convert.ConvertRequest(body, clientProto, up)
|
||||
// conversionTarget 决定客户端协议在渠道上的处理方式:
|
||||
// 渠道声明支持该协议则直通(返回原协议);否则转为其首选支持协议(chat > messages > responses)。
|
||||
func conversionTarget(formats []string, clientProto string) string {
|
||||
for _, f := range formats {
|
||||
if f == clientProto {
|
||||
return clientProto
|
||||
}
|
||||
}
|
||||
for _, p := range []string{convert.ProtoChat, convert.ProtoMessages, convert.ProtoResponses} {
|
||||
for _, f := range formats {
|
||||
if f == p {
|
||||
return p
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// prepareUpstream 计算上游访问计划:渠道声明支持客户端协议则直通,否则转换。
|
||||
func prepareUpstream(ch *store.Channel, clientProto string, body []byte) (*upstreamPlan, error) {
|
||||
target := conversionTarget(ch.FormatsEffective(), clientProto)
|
||||
if target == "" {
|
||||
return nil, fmt.Errorf("channel %q declares no supported protocol format", ch.Name)
|
||||
}
|
||||
plan := &upstreamPlan{path: upstreamPath(target), body: body}
|
||||
if target != clientProto {
|
||||
converted, err := convert.ConvertRequest(body, clientProto, target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
plan.body = converted
|
||||
plan.lineConv = convert.NewStreamTransformer(up, clientProto)
|
||||
plan.bodyConv = func(b []byte) ([]byte, error) { return convert.ConvertResponse(b, up, clientProto) }
|
||||
plan.lineConv = convert.NewStreamTransformer(target, clientProto)
|
||||
plan.bodyConv = func(b []byte) ([]byte, error) { return convert.ConvertResponse(b, target, clientProto) }
|
||||
}
|
||||
return plan, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user