chore: gofmt 对齐(远端提交带入的未格式化文件)
This commit is contained in:
1 parent
dfe31b5b4f
commit
263bfb7845
6 files changed
+49
-49
No files matched your search
@@ -104,7 +104,7 @@ func (h *Handler) AdminChannelAddModel(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
var req struct {
|
var req struct {
|
||||||
UpstreamModel string `json:"upstream_model" binding:"required"` // 渠道侧真实模型名
|
UpstreamModel string `json:"upstream_model" binding:"required"` // 渠道侧真实模型名
|
||||||
CustomName string `json:"custom_name"` // 客户端调用名,空=用上游名
|
CustomName string `json:"custom_name"` // 客户端调用名,空=用上游名
|
||||||
Weight *int `json:"weight"`
|
Weight *int `json:"weight"`
|
||||||
}
|
}
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
|||||||
@@ -56,9 +56,9 @@ func (h *Handler) channelRuntime(id uint64) (fails int, cooldownSeconds int64) {
|
|||||||
|
|
||||||
type channelBody struct {
|
type channelBody struct {
|
||||||
Name string `json:"name" binding:"required,min=1,max=64"`
|
Name string `json:"name" binding:"required,min=1,max=64"`
|
||||||
Provider string `json:"provider"` // 可选:为空时按 formats 推断(兼容旧数据)
|
Provider string `json:"provider"` // 可选:为空时按 formats 推断(兼容旧数据)
|
||||||
Formats []string `json:"formats"` // 原生支持的协议 chat|responses|messages(主配置)
|
Formats []string `json:"formats"` // 原生支持的协议 chat|responses|messages(主配置)
|
||||||
BaseURL string `json:"base_url"` // 可选:留空按供应商默认;支持前缀或完整端点
|
BaseURL string `json:"base_url"` // 可选:留空按供应商默认;支持前缀或完整端点
|
||||||
BaseURLs map[string]string `json:"base_urls"` // 分协议 base_url 覆盖(chat/responses/messages)
|
BaseURLs map[string]string `json:"base_urls"` // 分协议 base_url 覆盖(chat/responses/messages)
|
||||||
APIKey string `json:"api_key"`
|
APIKey string `json:"api_key"`
|
||||||
Weight *int `json:"weight"`
|
Weight *int `json:"weight"`
|
||||||
@@ -194,7 +194,7 @@ func (h *Handler) AdminCreateChannel(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
ch := store.Channel{
|
ch := store.Channel{
|
||||||
Name: req.Name, Provider: req.Provider, Formats: formats, BaseURL: baseURL,
|
Name: req.Name, Provider: req.Provider, Formats: formats, BaseURL: baseURL,
|
||||||
BaseURLs: normalizeBaseURLs(req.BaseURLs),
|
BaseURLs: normalizeBaseURLs(req.BaseURLs),
|
||||||
APIKeyEnc: enc, Weight: intOr(req.Weight, 1), Priority: intOr(req.Priority, 0),
|
APIKeyEnc: enc, Weight: intOr(req.Weight, 1), Priority: intOr(req.Priority, 0),
|
||||||
TimeoutMS: intOr(req.TimeoutMS, 300000), MaxConcurrency: intOr(req.MaxConcurrency, 16),
|
TimeoutMS: intOr(req.TimeoutMS, 300000), MaxConcurrency: intOr(req.MaxConcurrency, 16),
|
||||||
HealthStatus: store.ChannelHealthHealthy, Enabled: boolOr(req.Enabled, true),
|
HealthStatus: store.ChannelHealthHealthy, Enabled: boolOr(req.Enabled, true),
|
||||||
|
|||||||
+13
-13
@@ -118,27 +118,27 @@ func (a *App) Seed() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ch := store.Channel{
|
ch := store.Channel{
|
||||||
Name: a.Cfg.Proxy.DefaultChannelName,
|
Name: a.Cfg.Proxy.DefaultChannelName,
|
||||||
Provider: store.ChannelProviderOpenAI,
|
Provider: store.ChannelProviderOpenAI,
|
||||||
Formats: []string{store.FormatChat, store.FormatResponses},
|
Formats: []string{store.FormatChat, store.FormatResponses},
|
||||||
BaseURL: a.Cfg.Proxy.UpstreamBaseURL,
|
BaseURL: a.Cfg.Proxy.UpstreamBaseURL,
|
||||||
APIKeyEnc: enc,
|
APIKeyEnc: enc,
|
||||||
Weight: 1,
|
Weight: 1,
|
||||||
Priority: 0,
|
Priority: 0,
|
||||||
TimeoutMS: int(a.Cfg.Proxy.Timeout / time.Millisecond),
|
TimeoutMS: int(a.Cfg.Proxy.Timeout / time.Millisecond),
|
||||||
MaxConcurrency: 16,
|
MaxConcurrency: 16,
|
||||||
HealthStatus: store.ChannelHealthHealthy,
|
HealthStatus: store.ChannelHealthHealthy,
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
}
|
}
|
||||||
if err := a.DB.Create(&ch).Error; err != nil {
|
if err := a.DB.Create(&ch).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// 默认模型 + 绑定
|
// 默认模型 + 绑定
|
||||||
m := store.Model{
|
m := store.Model{
|
||||||
Name: a.Cfg.Proxy.DefaultModel,
|
Name: a.Cfg.Proxy.DefaultModel,
|
||||||
InputPrice: 0.15, // 每百万 token,示例价
|
InputPrice: 0.15, // 每百万 token,示例价
|
||||||
OutputPrice: 0.60,
|
OutputPrice: 0.60,
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
}
|
}
|
||||||
if err := a.DB.Create(&m).Error; err == nil {
|
if err := a.DB.Create(&m).Error; err == nil {
|
||||||
a.DB.Create(&store.ChannelModelBinding{ChannelID: ch.ID, ModelID: m.ID, UpstreamModel: m.Name})
|
a.DB.Create(&store.ChannelModelBinding{ChannelID: ch.ID, ModelID: m.ID, UpstreamModel: m.Name})
|
||||||
|
|||||||
@@ -61,10 +61,10 @@ type webUser struct {
|
|||||||
credentials []webauthn.Credential
|
credentials []webauthn.Credential
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *webUser) WebAuthnID() []byte { return []byte(strconv.FormatUint(u.id, 10)) }
|
func (u *webUser) WebAuthnID() []byte { return []byte(strconv.FormatUint(u.id, 10)) }
|
||||||
func (u *webUser) WebAuthnName() string { return u.name }
|
func (u *webUser) WebAuthnName() string { return u.name }
|
||||||
func (u *webUser) WebAuthnDisplayName() string { return u.displayName }
|
func (u *webUser) WebAuthnDisplayName() string { return u.displayName }
|
||||||
func (u *webUser) WebAuthnIcon() string { return "" }
|
func (u *webUser) WebAuthnIcon() string { return "" }
|
||||||
func (u *webUser) WebAuthnCredentials() []webauthn.Credential { return u.credentials }
|
func (u *webUser) WebAuthnCredentials() []webauthn.Credential { return u.credentials }
|
||||||
|
|
||||||
func (s *Service) loadWebUser(u *store.User) (*webUser, error) {
|
func (s *Service) loadWebUser(u *store.User) (*webUser, error) {
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ type User struct {
|
|||||||
Role string `gorm:"size:16;not null;default:user" json:"role"`
|
Role string `gorm:"size:16;not null;default:user" json:"role"`
|
||||||
Balance float64 `gorm:"type:numeric(20,8);not null;default:0" json:"balance"`
|
Balance float64 `gorm:"type:numeric(20,8);not null;default:0" json:"balance"`
|
||||||
Status string `gorm:"size:16;not null;default:active" json:"status"`
|
Status string `gorm:"size:16;not null;default:active" json:"status"`
|
||||||
TokenVersion int `gorm:"not null;default:0" json:"-"` // 会话版本:改密/登出递增,低于当前版本的 token 全部失效
|
TokenVersion int `gorm:"not null;default:0" json:"-"` // 会话版本:改密/登出递增,低于当前版本的 token 全部失效
|
||||||
AllowedModels []string `gorm:"type:jsonb;serializer:json" json:"allowed_models,omitempty"` // 用户级模型白名单(空=不限制)
|
AllowedModels []string `gorm:"type:jsonb;serializer:json" json:"allowed_models,omitempty"` // 用户级模型白名单(空=不限制)
|
||||||
DeniedModels []string `gorm:"type:jsonb;serializer:json" json:"denied_models,omitempty"` // 用户级模型黑名单
|
DeniedModels []string `gorm:"type:jsonb;serializer:json" json:"denied_models,omitempty"` // 用户级模型黑名单
|
||||||
InviteCode *string `json:"invite_code,omitempty"`
|
InviteCode *string `json:"invite_code,omitempty"`
|
||||||
@@ -183,30 +183,30 @@ type ChannelModelBinding struct {
|
|||||||
|
|
||||||
// UsageLog 请求级用量明细(PLANNING §6.5)
|
// UsageLog 请求级用量明细(PLANNING §6.5)
|
||||||
type UsageLog struct {
|
type UsageLog struct {
|
||||||
ID uint64 `gorm:"primaryKey;autoIncrement" json:"id"`
|
ID uint64 `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||||
RequestID string `gorm:"size:128" json:"request_id"` // 上游 request id
|
RequestID string `gorm:"size:128" json:"request_id"` // 上游 request id
|
||||||
TraceID string `gorm:"size:64;index" json:"trace_id"`
|
TraceID string `gorm:"size:64;index" json:"trace_id"`
|
||||||
UserID uint64 `gorm:"index:idx_user_created,priority:1;not null" json:"user_id"`
|
UserID uint64 `gorm:"index:idx_user_created,priority:1;not null" json:"user_id"`
|
||||||
KeyID uint64 `gorm:"index" json:"key_id"`
|
KeyID uint64 `gorm:"index" json:"key_id"`
|
||||||
ChannelID uint64 `gorm:"index:idx_channel_created,priority:1" json:"channel_id"`
|
ChannelID uint64 `gorm:"index:idx_channel_created,priority:1" json:"channel_id"`
|
||||||
ModelID uint64 `json:"model_id"`
|
ModelID uint64 `json:"model_id"`
|
||||||
ModelName string `gorm:"size:128" json:"model_name"`
|
ModelName string `gorm:"size:128" json:"model_name"`
|
||||||
Protocol string `gorm:"size:32" json:"protocol"` // responses|chat|messages
|
Protocol string `gorm:"size:32" json:"protocol"` // responses|chat|messages
|
||||||
InputTokens int64 `json:"input_tokens"`
|
InputTokens int64 `json:"input_tokens"`
|
||||||
OutputTokens int64 `json:"output_tokens"`
|
OutputTokens int64 `json:"output_tokens"`
|
||||||
CacheReadTokens int64 `json:"cache_read_tokens"`
|
CacheReadTokens int64 `json:"cache_read_tokens"`
|
||||||
CacheCreationTokens int64 `json:"cache_creation_tokens"`
|
CacheCreationTokens int64 `json:"cache_creation_tokens"`
|
||||||
InputPrice float64 `gorm:"type:numeric(20,8)" json:"input_price"` // 快照
|
InputPrice float64 `gorm:"type:numeric(20,8)" json:"input_price"` // 快照
|
||||||
OutputPrice float64 `gorm:"type:numeric(20,8)" json:"output_price"` // 快照
|
OutputPrice float64 `gorm:"type:numeric(20,8)" json:"output_price"` // 快照
|
||||||
CacheReadPrice float64 `gorm:"type:numeric(20,8)" json:"cache_read_price"` // 快照
|
CacheReadPrice float64 `gorm:"type:numeric(20,8)" json:"cache_read_price"` // 快照
|
||||||
Cost float64 `gorm:"type:numeric(20,8)" json:"cost"`
|
Cost float64 `gorm:"type:numeric(20,8)" json:"cost"`
|
||||||
LatencyMS int `json:"latency_ms"`
|
LatencyMS int `json:"latency_ms"`
|
||||||
Status string `gorm:"size:16;not null" json:"status"`
|
Status string `gorm:"size:16;not null" json:"status"`
|
||||||
ErrorCode *string `json:"error_code,omitempty"`
|
ErrorCode *string `json:"error_code,omitempty"`
|
||||||
RawRequest string `gorm:"type:text" json:"raw_request"` // 客户端原始请求体(未转换)
|
RawRequest string `gorm:"type:text" json:"raw_request"` // 客户端原始请求体(未转换)
|
||||||
RawResponse string `gorm:"type:text" json:"raw_response"` // 上游原始响应(未转换;流式为全部 SSE 事件)
|
RawResponse string `gorm:"type:text" json:"raw_response"` // 上游原始响应(未转换;流式为全部 SSE 事件)
|
||||||
// CreatedAt 同时参与 user/channel 两个复合索引(时间窗过滤),自身单列索引保留给全表时间扫
|
// CreatedAt 同时参与 user/channel 两个复合索引(时间窗过滤),自身单列索引保留给全表时间扫
|
||||||
CreatedAt time.Time `gorm:"index;index:idx_user_created,priority:2;index:idx_channel_created,priority:2" json:"created_at"`
|
CreatedAt time.Time `gorm:"index;index:idx_user_created,priority:2;index:idx_channel_created,priority:2" json:"created_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UsageDaily 日粒度预聚合(PLANNING §6.6)
|
// UsageDaily 日粒度预聚合(PLANNING §6.6)
|
||||||
|
|||||||
@@ -37,9 +37,9 @@ func TestChannelUpstreamURL(t *testing.T) {
|
|||||||
}
|
}
|
||||||
cases2 := []struct{ proto, path, want string }{
|
cases2 := []struct{ proto, path, want string }{
|
||||||
{"chat", "/chat/completions", "https://open.bigmodel.cn/api/paas/v4/chat/completions"}, // 用主 base
|
{"chat", "/chat/completions", "https://open.bigmodel.cn/api/paas/v4/chat/completions"}, // 用主 base
|
||||||
{"responses", "/responses", "https://resp.example.com/v4/responses"}, // 用覆盖 base
|
{"responses", "/responses", "https://resp.example.com/v4/responses"}, // 用覆盖 base
|
||||||
{"messages", "/messages", "https://msg.example.com/v1/messages"}, // 用覆盖 base
|
{"messages", "/messages", "https://msg.example.com/v1/messages"}, // 用覆盖 base
|
||||||
{"", "/models", "https://open.bigmodel.cn/api/paas/v4/models"}, // 空协议用主 base
|
{"", "/models", "https://open.bigmodel.cn/api/paas/v4/models"}, // 空协议用主 base
|
||||||
}
|
}
|
||||||
for _, c := range cases2 {
|
for _, c := range cases2 {
|
||||||
got := ch.UpstreamURL(c.proto, c.path)
|
got := ch.UpstreamURL(c.proto, c.path)
|
||||||
|
|||||||
Reference in new issue
Block a user