package model
import (
"time"
"github.com/bestruirui/octopus/internal/transformer/outbound"
)
type AutoGroupType int
const (
AutoGroupTypeNone AutoGroupType = 0
AutoGroupTypeFuzzy AutoGroupType = 1
AutoGroupTypeExact AutoGroupType = 2
AutoGroupTypeRegex AutoGroupType = 3
)
type Channel struct {
ID int `json:"id" gorm:"primaryKey"`
Name string `json:"name" gorm:"unique;not null"`
Type outbound.OutboundType `json:"type"`
Enabled bool `json:"enabled" gorm:"default:true"`
BaseUrls []BaseUrl `json:"base_urls" gorm:"serializer:json"`
Keys []ChannelKey `json:"keys" gorm:"foreignKey:ChannelID"`
Model string `json:"model"`
CustomModel string `json:"custom_model"`
Proxy bool `json:"proxy" gorm:"default:false"`
AutoSync bool `json:"auto_sync" gorm:"default:false"`
AutoGroup AutoGroupType `json:"auto_group" gorm:"default:0"`
CustomHeader []CustomHeader `json:"custom_header" gorm:"serializer:json"`
ParamOverride *string `json:"param_override"`
ChannelProxy *string `json:"channel_proxy"`
Stats *StatsChannel `json:"stats,omitempty" gorm:"foreignKey:ChannelID"`
MatchRegex *string `json:"match_regex"`
}
type BaseUrl struct {
URL string `json:"url"`
Delay int `json:"delay"`
}
type CustomHeader struct {
HeaderKey string `json:"header_key"`
HeaderValue string `json:"header_value"`
}
type ChannelKey struct {
ID int `json:"id" gorm:"primaryKey"`
ChannelID int `json:"channel_id"`
Enabled bool `json:"enabled" gorm:"default:true"`
ChannelKey string `json:"channel_key"`
StatusCode int `json:"status_code"`
LastUseTimeStamp int64 `json:"last_use_time_stamp"`
TotalCost float64 `json:"total_cost"`
Remark string `json:"remark"`
}
type ChannelUpdateRequest struct {
ID int `json:"id" binding:"required"`
Name *string `json:"name,omitempty"`
Type *outbound.OutboundType `json:"type,omitempty"`
Enabled *bool `json:"enabled,omitempty"`
BaseUrls *[]BaseUrl `json:"base_urls,omitempty"`
Model *string `json:"model,omitempty"`
CustomModel *string `json:"custom_model,omitempty"`
Proxy *bool `json:"proxy,omitempty"`
AutoSync *bool `json:"auto_sync,omitempty"`
AutoGroup *AutoGroupType `json:"auto_group,omitempty"`
CustomHeader *[]CustomHeader `json:"custom_header,omitempty"`
ChannelProxy *string `json:"channel_proxy,omitempty"`
ParamOverride *string `json:"param_override,omitempty"`
MatchRegex *string `json:"match_regex,omitempty"`
KeysToAdd []ChannelKeyAddRequest `json:"keys_to_add,omitempty"`
KeysToUpdate []ChannelKeyUpdateRequest `json:"keys_to_update,omitempty"`
KeysToDelete []int `json:"keys_to_delete,omitempty"`
}
type ChannelKeyAddRequest struct {
Enabled bool `json:"enabled"`
ChannelKey string `json:"channel_key" binding:"required"`
Remark string `json:"remark"`
}
type ChannelKeyUpdateRequest struct {
ID int `json:"id" binding:"required"`
Enabled *bool `json:"enabled,omitempty"`
ChannelKey *string `json:"channel_key,omitempty"`
Remark *string `json:"remark,omitempty"`
}
type ChannelFetchModelRequest struct {
Type outbound.OutboundType `json:"type" binding:"required"`
BaseURL string `json:"base_url" binding:"required"`
Key string `json:"key" binding:"required"`
Proxy bool `json:"proxy"`
}
func (c *Channel) GetBaseUrl() string {
if c == nil || len(c.BaseUrls) == 0 {
return ""
}
bestURL := ""
bestDelay := 0
bestSet := false
for _, bu := range c.BaseUrls {
if bu.URL == "" {
continue
}
if !bestSet || bu.Delay < bestDelay {
bestURL = bu.URL
bestDelay = bu.Delay
bestSet = true
}
}
return bestURL
}
func (c *Channel) GetChannelKey() ChannelKey {
if c == nil || len(c.Keys) == 0 {
return ChannelKey{}
}
nowSec := time.Now().Unix()
best := ChannelKey{}
bestCost := 0.0
bestSet := false
for _, k := range c.Keys {
if !k.Enabled || k.ChannelKey == "" {
continue
}
if k.StatusCode == 429 && k.LastUseTimeStamp > 0 {
if nowSec-k.LastUseTimeStamp < int64(5*time.Minute/time.Second) {
continue
}
}
if !bestSet || k.TotalCost < bestCost {
best = k
bestCost = k.TotalCost
bestSet = true
}
}
if !bestSet {
return ChannelKey{}
}
return best
}