Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
0089157
✨ feat(channel): enhance AddChannel functionality with structured req…
Calcium-Ion Jun 15, 2025
aa79308
✨ fix(playground): send selected group in API payload
zeraturing Jun 15, 2025
617c8e8
✨ feat(channel-ui): support multi-JSON batch creation for Vertex AI &…
zeraturing Jun 15, 2025
7403df7
✨ feat(channel): enhance channel handling with multi-key support
Calcium-Ion Jun 15, 2025
4a8b7bf
temp
Calcium-Ion Jun 16, 2025
fa2cd85
Merge branch 'alpha' into mutil_key_channel
Calcium-Ion Jul 6, 2025
b695e67
🔧 refactor(channel): replace common.ChannelTypeVertexAi with constant…
Calcium-Ion Jul 6, 2025
f0f277d
🔧 refactor(auth, channel, context): improve context setup and validat…
Calcium-Ion Jul 6, 2025
870cdd5
✨ feat(channel): Robust Vertex AI batch-key upload & stable multi-key…
t0ng7u Jul 6, 2025
f1856fe
🔧 **fix(model, controller): robust serialization for `ChannelInfo` & …
t0ng7u Jul 6, 2025
0e6b608
🎨 feat(ui): dynamic multi-key controls in Channel editor
t0ng7u Jul 6, 2025
9895219
refactor: Introduce standardized API error
Calcium-Ion Jul 10, 2025
cb16bf5
Merge branch 'alpha' into refactor_error
Calcium-Ion Jul 10, 2025
a9e03e6
🔧 refactor(user_cache): remove unused JSON import
Calcium-Ion Jul 10, 2025
cd8c23c
✨ feat(channel): enhance channel status management
Calcium-Ion Jul 10, 2025
85efea3
✨ feat(channel): implement multi-key mode handling and improve channe…
Calcium-Ion Jul 11, 2025
23e4e25
✨ feat(channel): implement thread-safe polling
Calcium-Ion Jul 12, 2025
50b76f4
✨ feat(channel): improve channel cache handling and add error checks …
Calcium-Ion Jul 12, 2025
20607b0
✨ feat(logs): add multi-key support in LogsTable and enhance log info…
Calcium-Ion Jul 12, 2025
52a5e58
✨ feat(adaptor): refactor response handlers to return usage first and…
Calcium-Ion Jul 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion common/gin.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func UnmarshalBodyReusable(c *gin.Context, v any) error {
}
contentType := c.Request.Header.Get("Content-Type")
if strings.HasPrefix(contentType, "application/json") {
err = UnmarshalJson(requestBody, &v)
err = Unmarshal(requestBody, &v)
} else {
// skip for now
// TODO: someday non json request have variant model, we will need to implementation this
Expand Down
4 changes: 2 additions & 2 deletions common/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"encoding/json"
)

func UnmarshalJson(data []byte, v any) error {
func Unmarshal(data []byte, v any) error {
return json.Unmarshal(data, v)
}

Expand All @@ -17,6 +17,6 @@ func DecodeJson(reader *bytes.Reader, v any) error {
return json.NewDecoder(reader).Decode(v)
}

func EncodeJson(v any) ([]byte, error) {
func Marshal(v any) ([]byte, error) {
return json.Marshal(v)
}
24 changes: 19 additions & 5 deletions common/str.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,30 @@ func MapToJsonStr(m map[string]interface{}) string {
return string(bytes)
}

func StrToMap(str string) map[string]interface{} {
func StrToMap(str string) (map[string]interface{}, error) {
m := make(map[string]interface{})
err := json.Unmarshal([]byte(str), &m)
err := Unmarshal([]byte(str), &m)
if err != nil {
return nil
return nil, err
}
return m
return m, nil
}

func IsJsonStr(str string) bool {
func StrToJsonArray(str string) ([]interface{}, error) {
var js []interface{}
err := json.Unmarshal([]byte(str), &js)
if err != nil {
return nil, err
}
return js, nil
}

func IsJsonArray(str string) bool {
var js []interface{}
return json.Unmarshal([]byte(str), &js) == nil
}

func IsJsonObject(str string) bool {
var js map[string]interface{}
return json.Unmarshal([]byte(str), &js) == nil
}
Expand Down
19 changes: 14 additions & 5 deletions constant/context_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,20 @@ const (
ContextKeyTokenModelLimit ContextKey = "token_model_limit"

/* channel related keys */
ContextKeyBaseUrl ContextKey = "base_url"
ContextKeyChannelType ContextKey = "channel_type"
ContextKeyChannelId ContextKey = "channel_id"
ContextKeyChannelSetting ContextKey = "channel_setting"
ContextKeyParamOverride ContextKey = "param_override"
ContextKeyChannelId ContextKey = "channel_id"
ContextKeyChannelName ContextKey = "channel_name"
ContextKeyChannelCreateTime ContextKey = "channel_create_time"
ContextKeyChannelBaseUrl ContextKey = "base_url"
ContextKeyChannelType ContextKey = "channel_type"
ContextKeyChannelSetting ContextKey = "channel_setting"
ContextKeyChannelParamOverride ContextKey = "param_override"
ContextKeyChannelOrganization ContextKey = "channel_organization"
ContextKeyChannelAutoBan ContextKey = "auto_ban"
ContextKeyChannelModelMapping ContextKey = "model_mapping"
ContextKeyChannelStatusCodeMapping ContextKey = "status_code_mapping"
ContextKeyChannelIsMultiKey ContextKey = "channel_is_multi_key"
ContextKeyChannelMultiKeyIndex ContextKey = "channel_multi_key_index"
ContextKeyChannelKey ContextKey = "channel_key"

/* user related keys */
ContextKeyUserId ContextKey = "id"
Expand Down
8 changes: 8 additions & 0 deletions constant/multi_key_mode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package constant

type MultiKeyMode string

const (
MultiKeyModeRandom MultiKeyMode = "random" // 随机
MultiKeyModePolling MultiKeyMode = "polling" // 轮询
)
16 changes: 13 additions & 3 deletions controller/channel-billing.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"one-api/model"
"one-api/service"
"one-api/setting"
"one-api/types"
"strconv"
"time"

Expand Down Expand Up @@ -415,14 +416,21 @@ func UpdateChannelBalance(c *gin.Context) {
})
return
}
channel, err := model.GetChannelById(id, true)
channel, err := model.CacheGetChannel(id)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": err.Error(),
})
return
}
if channel.ChannelInfo.IsMultiKey {
c.JSON(http.StatusOK, gin.H{
"success": false,
"message": "多密钥渠道不支持余额查询",
})
return
}
balance, err := updateChannelBalance(channel)
if err != nil {
c.JSON(http.StatusOK, gin.H{
Expand All @@ -436,7 +444,6 @@ func UpdateChannelBalance(c *gin.Context) {
"message": "",
"balance": balance,
})
return
}

func updateAllChannelsBalance() error {
Expand All @@ -448,6 +455,9 @@ func updateAllChannelsBalance() error {
if channel.Status != common.ChannelStatusEnabled {
continue
}
if channel.ChannelInfo.IsMultiKey {
continue // skip multi-key channels
}
// TODO: support Azure
//if channel.Type != common.ChannelTypeOpenAI && channel.Type != common.ChannelTypeCustom {
// continue
Expand All @@ -458,7 +468,7 @@ func updateAllChannelsBalance() error {
} else {
// err is nil & balance <= 0 means quota is used up
if balance <= 0 {
service.DisableChannel(channel.Id, channel.Name, "余额不足")
service.DisableChannel(*types.NewChannelError(channel.Id, channel.Type, channel.Name, channel.ChannelInfo.IsMultiKey, "", channel.GetAutoBan()), "余额不足")
}
}
time.Sleep(common.RequestInterval)
Expand Down
Loading