Merge pull request #1179 from QuantumNous/alpha

merge alpha to main
This commit is contained in:
Calcium-Ion
2025-06-08 14:34:24 +08:00
committed by GitHub
10 changed files with 87 additions and 12 deletions

View File

@@ -92,12 +92,12 @@ func RedisDel(key string) error {
return RDB.Del(ctx, key).Err() return RDB.Del(ctx, key).Err()
} }
func RedisHDelObj(key string) error { func RedisDelKey(key string) error {
if DebugEnabled { if DebugEnabled {
SysLog(fmt.Sprintf("Redis HDEL: key=%s", key)) SysLog(fmt.Sprintf("Redis DEL Key: key=%s", key))
} }
ctx := context.Background() ctx := context.Background()
return RDB.HDel(ctx, key).Err() return RDB.Del(ctx, key).Err()
} }
func RedisHSetObj(key string, obj interface{}, expiration time.Duration) error { func RedisHSetObj(key string, obj interface{}, expiration time.Duration) error {

View File

@@ -623,3 +623,44 @@ func BatchSetChannelTag(c *gin.Context) {
}) })
return return
} }
func GetTagModels(c *gin.Context) {
tag := c.Query("tag")
if tag == "" {
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": "tag不能为空",
})
return
}
channels, err := model.GetChannelsByTag(tag, false) // Assuming false for idSort is fine here
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": err.Error(),
})
return
}
var longestModels string
maxLength := 0
// Find the longest models string among all channels with the given tag
for _, channel := range channels {
if channel.Models != "" {
currentModels := strings.Split(channel.Models, ",")
if len(currentModels) > maxLength {
maxLength = len(currentModels)
longestModels = channel.Models
}
}
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "",
"data": longestModels,
})
return
}

View File

@@ -19,7 +19,7 @@ func cacheSetToken(token Token) error {
func cacheDeleteToken(key string) error { func cacheDeleteToken(key string) error {
key = common.GenerateHMAC(key) key = common.GenerateHMAC(key)
err := common.RedisHDelObj(fmt.Sprintf("token:%s", key)) err := common.RedisDelKey(fmt.Sprintf("token:%s", key))
if err != nil { if err != nil {
return err return err
} }

View File

@@ -3,11 +3,12 @@ package model
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/gin-gonic/gin"
"one-api/common" "one-api/common"
"one-api/constant" "one-api/constant"
"time" "time"
"github.com/gin-gonic/gin"
"github.com/bytedance/gopkg/util/gopool" "github.com/bytedance/gopkg/util/gopool"
) )
@@ -57,7 +58,7 @@ func invalidateUserCache(userId int) error {
if !common.RedisEnabled { if !common.RedisEnabled {
return nil return nil
} }
return common.RedisHDelObj(getUserCacheKey(userId)) return common.RedisDelKey(getUserCacheKey(userId))
} }
// updateUserCache updates all user cache fields using hash // updateUserCache updates all user cache fields using hash

View File

@@ -105,6 +105,7 @@ func SetApiRouter(router *gin.Engine) {
channelRoute.GET("/fetch_models/:id", controller.FetchUpstreamModels) channelRoute.GET("/fetch_models/:id", controller.FetchUpstreamModels)
channelRoute.POST("/fetch_models", controller.FetchModels) channelRoute.POST("/fetch_models", controller.FetchModels)
channelRoute.POST("/batch/tag", controller.BatchSetChannelTag) channelRoute.POST("/batch/tag", controller.BatchSetChannelTag)
channelRoute.GET("/tag/models", controller.GetTagModels)
} }
tokenRoute := apiRouter.Group("/token") tokenRoute := apiRouter.Group("/token")
tokenRoute.Use(middleware.UserAuth()) tokenRoute.Use(middleware.UserAuth())

View File

@@ -462,7 +462,7 @@ const LogsTable = () => {
percent={text ? parseInt(text.replace('%', '')) : 0} percent={text ? parseInt(text.replace('%', '')) : 0}
showInfo={true} showInfo={true}
aria-label='drawing progress' aria-label='drawing progress'
style={{ minWidth: '200px' }} style={{ minWidth: '160px' }}
/> />
} }
</div> </div>
@@ -483,6 +483,7 @@ const LogsTable = () => {
setModalImageUrl(text); setModalImageUrl(text);
setIsModalOpenurl(true); setIsModalOpenurl(true);
}} }}
className="!rounded-full"
> >
{t('查看图片')} {t('查看图片')}
</Button> </Button>

View File

@@ -395,7 +395,7 @@ const LogsTable = () => {
percent={text ? parseInt(text.replace('%', '')) : 0} percent={text ? parseInt(text.replace('%', '')) : 0}
showInfo={true} showInfo={true}
aria-label='task progress' aria-label='task progress'
style={{ minWidth: '200px' }} style={{ minWidth: '160px' }}
/> />
) )
} }

View File

@@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom/client'; import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom'; import { BrowserRouter } from 'react-router-dom';
import '@douyinfe/semi-ui/dist/css/semi.css';
import { UserProvider } from './context/User'; import { UserProvider } from './context/User';
import 'react-toastify/dist/ReactToastify.css'; import 'react-toastify/dist/ReactToastify.css';
import { StatusProvider } from './context/Status'; import { StatusProvider } from './context/Status';

View File

@@ -194,6 +194,24 @@ const EditTagModal = (props) => {
}, [originModelOptions, inputs.models]); }, [originModelOptions, inputs.models]);
useEffect(() => { useEffect(() => {
const fetchTagModels = async () => {
if (!tag) return;
setLoading(true);
try {
const res = await API.get(`/api/channel/tag/models?tag=${tag}`);
if (res?.data?.success) {
const models = res.data.data ? res.data.data.split(',') : [];
setInputs((inputs) => ({ ...inputs, models: models }));
} else {
showError(res.data.message);
}
} catch (error) {
showError(error.message);
} finally {
setLoading(false);
}
};
setInputs({ setInputs({
...originInputs, ...originInputs,
tag: tag, tag: tag,
@@ -201,7 +219,8 @@ const EditTagModal = (props) => {
}); });
fetchModels().then(); fetchModels().then();
fetchGroups().then(); fetchGroups().then();
}, [visible]); fetchTagModels().then(); // Call the new function
}, [visible, tag]); // Add tag to dependency array
const addCustomModels = () => { const addCustomModels = () => {
if (customModel.trim() === '') return; if (customModel.trim() === '') return;
@@ -347,6 +366,11 @@ const EditTagModal = (props) => {
<div className="space-y-4"> <div className="space-y-4">
<div> <div>
<Text strong className="block mb-2">{t('模型')}</Text> <Text strong className="block mb-2">{t('模型')}</Text>
<Banner
type="info"
description={t('当前模型列表为该标签下所有渠道模型列表最长的一个,并非所有渠道的并集,请注意可能导致某些渠道模型丢失。')}
className="!rounded-lg mb-4"
/>
<Select <Select
placeholder={t('请选择该渠道所支持的模型,留空则不更改')} placeholder={t('请选择该渠道所支持的模型,留空则不更改')}
name='models' name='models'

View File

@@ -219,9 +219,15 @@ const EditToken = (props) => {
let successCount = 0; // 记录成功创建的令牌数量 let successCount = 0; // 记录成功创建的令牌数量
for (let i = 0; i < tokenCount; i++) { for (let i = 0; i < tokenCount; i++) {
let localInputs = { ...inputs }; let localInputs = { ...inputs };
if (i !== 0) {
// 如果用户想要创建多个令牌,则给每个令牌一个序号后缀 // 检查用户是否填写了令牌名称
localInputs.name = `${inputs.name}-${generateRandomSuffix()}`; const baseName = inputs.name.trim() === '' ? 'default' : inputs.name;
if (i !== 0 || inputs.name.trim() === '') {
// 如果创建多个令牌i !== 0或者用户没有填写名称则添加随机后缀
localInputs.name = `${baseName}-${generateRandomSuffix()}`;
} else {
localInputs.name = baseName;
} }
localInputs.remain_quota = parseInt(localInputs.remain_quota); localInputs.remain_quota = parseInt(localInputs.remain_quota);