⚡️ improve: Allows selection of test models (#121)
This commit is contained in:
parent
376d54f56a
commit
646cb74154
@ -18,7 +18,7 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testChannel(channel *model.Channel, request types.ChatCompletionRequest) (err error, openaiErr *types.OpenAIError) {
|
func testChannel(channel *model.Channel, testModel string) (err error, openaiErr *types.OpenAIError) {
|
||||||
if channel.TestModel == "" {
|
if channel.TestModel == "" {
|
||||||
return errors.New("请填写测速模型后再试"), nil
|
return errors.New("请填写测速模型后再试"), nil
|
||||||
}
|
}
|
||||||
@ -33,7 +33,13 @@ func testChannel(channel *model.Channel, request types.ChatCompletionRequest) (e
|
|||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
c, _ := gin.CreateTestContext(w)
|
c, _ := gin.CreateTestContext(w)
|
||||||
c.Request = req
|
c.Request = req
|
||||||
request.Model = channel.TestModel
|
request := buildTestRequest()
|
||||||
|
|
||||||
|
if testModel != "" {
|
||||||
|
request.Model = testModel
|
||||||
|
} else {
|
||||||
|
request.Model = channel.TestModel
|
||||||
|
}
|
||||||
|
|
||||||
provider := providers.GetProvider(channel, c)
|
provider := providers.GetProvider(channel, c)
|
||||||
if provider == nil {
|
if provider == nil {
|
||||||
@ -54,21 +60,15 @@ func testChannel(channel *model.Channel, request types.ChatCompletionRequest) (e
|
|||||||
|
|
||||||
chatProvider.SetUsage(&types.Usage{})
|
chatProvider.SetUsage(&types.Usage{})
|
||||||
|
|
||||||
response, openAIErrorWithStatusCode := chatProvider.CreateChatCompletion(&request)
|
response, openAIErrorWithStatusCode := chatProvider.CreateChatCompletion(request)
|
||||||
|
|
||||||
if openAIErrorWithStatusCode != nil {
|
if openAIErrorWithStatusCode != nil {
|
||||||
return errors.New(openAIErrorWithStatusCode.Message), &openAIErrorWithStatusCode.OpenAIError
|
return errors.New(openAIErrorWithStatusCode.Message), &openAIErrorWithStatusCode.OpenAIError
|
||||||
}
|
}
|
||||||
|
|
||||||
usage := chatProvider.GetUsage()
|
|
||||||
|
|
||||||
if usage.CompletionTokens == 0 {
|
|
||||||
return fmt.Errorf("channel %s, message 补全 tokens 非预期返回 0", channel.Name), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 转换为JSON字符串
|
// 转换为JSON字符串
|
||||||
jsonBytes, _ := json.Marshal(response)
|
jsonBytes, _ := json.Marshal(response)
|
||||||
common.SysLog(fmt.Sprintf("测试模型 %s 返回内容为:%s", channel.Name, string(jsonBytes)))
|
common.SysLog(fmt.Sprintf("测试渠道 %s : %s 返回内容为:%s", channel.Name, request.Model, string(jsonBytes)))
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@ -81,9 +81,9 @@ func buildTestRequest() *types.ChatCompletionRequest {
|
|||||||
Content: "You just need to output 'hi' next.",
|
Content: "You just need to output 'hi' next.",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Model: "",
|
Model: "",
|
||||||
// MaxTokens: 1,
|
MaxTokens: 2,
|
||||||
Stream: false,
|
Stream: false,
|
||||||
}
|
}
|
||||||
return testRequest
|
return testRequest
|
||||||
}
|
}
|
||||||
@ -105,9 +105,9 @@ func TestChannel(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
testRequest := buildTestRequest()
|
testModel := c.Query("model")
|
||||||
tik := time.Now()
|
tik := time.Now()
|
||||||
err, _ = testChannel(channel, *testRequest)
|
err, _ = testChannel(channel, testModel)
|
||||||
tok := time.Now()
|
tok := time.Now()
|
||||||
milliseconds := tok.Sub(tik).Milliseconds()
|
milliseconds := tok.Sub(tik).Milliseconds()
|
||||||
go channel.UpdateResponseTime(milliseconds)
|
go channel.UpdateResponseTime(milliseconds)
|
||||||
@ -163,7 +163,6 @@ func testAllChannels(notify bool) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
testRequest := buildTestRequest()
|
|
||||||
var disableThreshold = int64(common.ChannelDisableThreshold * 1000)
|
var disableThreshold = int64(common.ChannelDisableThreshold * 1000)
|
||||||
if disableThreshold == 0 {
|
if disableThreshold == 0 {
|
||||||
disableThreshold = 10000000 // a impossible value
|
disableThreshold = 10000000 // a impossible value
|
||||||
@ -172,7 +171,7 @@ func testAllChannels(notify bool) error {
|
|||||||
for _, channel := range channels {
|
for _, channel := range channels {
|
||||||
isChannelEnabled := channel.Status == common.ChannelStatusEnabled
|
isChannelEnabled := channel.Status == common.ChannelStatusEnabled
|
||||||
tik := time.Now()
|
tik := time.Now()
|
||||||
err, openaiErr := testChannel(channel, *testRequest)
|
err, openaiErr := testChannel(channel, "")
|
||||||
tok := time.Now()
|
tok := time.Now()
|
||||||
milliseconds := tok.Sub(tik).Milliseconds()
|
milliseconds := tok.Sub(tik).Milliseconds()
|
||||||
if milliseconds > disableThreshold {
|
if milliseconds > disableThreshold {
|
||||||
|
@ -22,6 +22,8 @@ import {
|
|||||||
Collapse,
|
Collapse,
|
||||||
Typography,
|
Typography,
|
||||||
TextField,
|
TextField,
|
||||||
|
Stack,
|
||||||
|
Menu,
|
||||||
Box
|
Box
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
|
|
||||||
@ -32,12 +34,51 @@ import ResponseTimeLabel from './ResponseTimeLabel';
|
|||||||
import GroupLabel from './GroupLabel';
|
import GroupLabel from './GroupLabel';
|
||||||
|
|
||||||
import { IconDotsVertical, IconEdit, IconTrash, IconCopy, IconWorldWww } from '@tabler/icons-react';
|
import { IconDotsVertical, IconEdit, IconTrash, IconCopy, IconWorldWww } from '@tabler/icons-react';
|
||||||
|
import { styled, alpha } from '@mui/material/styles';
|
||||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||||
import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp';
|
import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp';
|
||||||
import { copy } from 'utils/common';
|
import { copy } from 'utils/common';
|
||||||
|
|
||||||
|
const StyledMenu = styled((props) => (
|
||||||
|
<Menu
|
||||||
|
elevation={0}
|
||||||
|
anchorOrigin={{
|
||||||
|
vertical: 'bottom',
|
||||||
|
horizontal: 'right'
|
||||||
|
}}
|
||||||
|
transformOrigin={{
|
||||||
|
vertical: 'top',
|
||||||
|
horizontal: 'right'
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))(({ theme }) => ({
|
||||||
|
'& .MuiPaper-root': {
|
||||||
|
borderRadius: 6,
|
||||||
|
marginTop: theme.spacing(1),
|
||||||
|
minWidth: 180,
|
||||||
|
color: theme.palette.mode === 'light' ? 'rgb(55, 65, 81)' : theme.palette.grey[300],
|
||||||
|
boxShadow:
|
||||||
|
'rgb(255, 255, 255) 0px 0px 0px 0px, rgba(0, 0, 0, 0.05) 0px 0px 0px 1px, rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.05) 0px 4px 6px -2px',
|
||||||
|
'& .MuiMenu-list': {
|
||||||
|
padding: '4px 0'
|
||||||
|
},
|
||||||
|
'& .MuiMenuItem-root': {
|
||||||
|
'& .MuiSvgIcon-root': {
|
||||||
|
fontSize: 18,
|
||||||
|
color: theme.palette.text.secondary,
|
||||||
|
marginRight: theme.spacing(1.5)
|
||||||
|
},
|
||||||
|
'&:active': {
|
||||||
|
backgroundColor: alpha(theme.palette.primary.main, theme.palette.action.selectedOpacity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
export default function ChannelTableRow({ item, manageChannel, handleOpenModal, setModalChannelId }) {
|
export default function ChannelTableRow({ item, manageChannel, handleOpenModal, setModalChannelId }) {
|
||||||
const [open, setOpen] = useState(null);
|
const [open, setOpen] = useState(null);
|
||||||
|
const [openTest, setOpenTest] = useState(false);
|
||||||
const [openDelete, setOpenDelete] = useState(false);
|
const [openDelete, setOpenDelete] = useState(false);
|
||||||
const [statusSwitch, setStatusSwitch] = useState(item.status);
|
const [statusSwitch, setStatusSwitch] = useState(item.status);
|
||||||
const [priorityValve, setPriority] = useState(item.priority);
|
const [priorityValve, setPriority] = useState(item.priority);
|
||||||
@ -63,6 +104,10 @@ export default function ChannelTableRow({ item, manageChannel, handleOpenModal,
|
|||||||
setOpen(event.currentTarget);
|
setOpen(event.currentTarget);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleTestModel = (event) => {
|
||||||
|
setOpenTest(event.currentTarget);
|
||||||
|
};
|
||||||
|
|
||||||
const handleCloseMenu = () => {
|
const handleCloseMenu = () => {
|
||||||
setOpen(null);
|
setOpen(null);
|
||||||
};
|
};
|
||||||
@ -105,11 +150,21 @@ export default function ChannelTableRow({ item, manageChannel, handleOpenModal,
|
|||||||
setWeight(currentValue);
|
setWeight(currentValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleResponseTime = async () => {
|
const handleResponseTime = async (modelName) => {
|
||||||
const { success, time } = await manageChannel(item.id, 'test', '');
|
setOpenTest(null);
|
||||||
|
|
||||||
|
if (typeof modelName !== 'string') {
|
||||||
|
modelName = item.test_model;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modelName == '') {
|
||||||
|
showError('请先设置测试模型');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { success, time } = await manageChannel(item.id, 'test', modelName);
|
||||||
if (success) {
|
if (success) {
|
||||||
setResponseTimeData({ test_time: Date.now() / 1000, response_time: time * 1000 });
|
setResponseTimeData({ test_time: Date.now() / 1000, response_time: time * 1000 });
|
||||||
showInfo(`通道 ${item.name} 测试成功,耗时 ${time.toFixed(2)} 秒。`);
|
showInfo(`通道 ${item.name}: ${modelName} 测试成功,耗时 ${time.toFixed(2)} 秒。`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -202,9 +257,24 @@ export default function ChannelTableRow({ item, manageChannel, handleOpenModal,
|
|||||||
</TableCell>
|
</TableCell>
|
||||||
|
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<IconButton onClick={handleOpenMenu} sx={{ color: 'rgb(99, 115, 129)' }}>
|
<Stack direction="row" spacing={1}>
|
||||||
<IconDotsVertical />
|
<Button
|
||||||
</IconButton>
|
id="test-model-button"
|
||||||
|
aria-controls={openTest ? 'test-model-menu' : undefined}
|
||||||
|
aria-haspopup="true"
|
||||||
|
aria-expanded={openTest ? 'true' : undefined}
|
||||||
|
variant="outlined"
|
||||||
|
disableElevation
|
||||||
|
onClick={handleTestModel}
|
||||||
|
endIcon={<KeyboardArrowDownIcon />}
|
||||||
|
>
|
||||||
|
测试
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<IconButton onClick={handleOpenMenu} sx={{ color: 'rgb(99, 115, 129)' }}>
|
||||||
|
<IconDotsVertical />
|
||||||
|
</IconButton>
|
||||||
|
</Stack>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|
||||||
@ -256,6 +326,28 @@ export default function ChannelTableRow({ item, manageChannel, handleOpenModal,
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|
||||||
|
<StyledMenu
|
||||||
|
id="test-model-menu"
|
||||||
|
MenuListProps={{
|
||||||
|
'aria-labelledby': 'test-model-button'
|
||||||
|
}}
|
||||||
|
anchorEl={openTest}
|
||||||
|
open={!!openTest}
|
||||||
|
onClose={() => {
|
||||||
|
setOpenTest(null);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{modelMap.map((model) => (
|
||||||
|
<MenuItem
|
||||||
|
key={'test_model-' + model}
|
||||||
|
onClick={() => {
|
||||||
|
handleResponseTime(model);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{model}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</StyledMenu>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell style={{ paddingBottom: 0, paddingTop: 0, textAlign: 'left' }} colSpan={10}>
|
<TableCell style={{ paddingBottom: 0, paddingTop: 0, textAlign: 'left' }} colSpan={10}>
|
||||||
<Collapse in={openRow} timeout="auto" unmountOnExit>
|
<Collapse in={openRow} timeout="auto" unmountOnExit>
|
||||||
|
@ -158,7 +158,9 @@ export default function ChannelPage() {
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'test':
|
case 'test':
|
||||||
res = await API.get(url + `test/${id}`);
|
res = await API.get(url + `test/${id}`, {
|
||||||
|
params: { model: value }
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const { success, message } = res.data;
|
const { success, message } = res.data;
|
||||||
@ -377,16 +379,16 @@ export default function ChannelPage() {
|
|||||||
orderBy={orderBy}
|
orderBy={orderBy}
|
||||||
onRequestSort={handleSort}
|
onRequestSort={handleSort}
|
||||||
headLabel={[
|
headLabel={[
|
||||||
{ id: 'collapse', label: '', disableSort: true },
|
{ id: 'collapse', label: '', disableSort: true, width: '50px' },
|
||||||
{ id: 'id', label: 'ID', disableSort: false },
|
{ id: 'id', label: 'ID', disableSort: false, width: '80px' },
|
||||||
{ id: 'name', label: '名称', disableSort: false },
|
{ id: 'name', label: '名称', disableSort: false },
|
||||||
{ id: 'group', label: '分组', disableSort: true },
|
{ id: 'group', label: '分组', disableSort: true },
|
||||||
{ id: 'type', label: '类型', disableSort: false },
|
{ id: 'type', label: '类型', disableSort: false },
|
||||||
{ id: 'status', label: '状态', disableSort: false },
|
{ id: 'status', label: '状态', disableSort: false },
|
||||||
{ id: 'response_time', label: '响应时间', disableSort: false },
|
{ id: 'response_time', label: '响应时间', disableSort: false },
|
||||||
{ id: 'balance', label: '余额', disableSort: false },
|
{ id: 'balance', label: '余额', disableSort: false },
|
||||||
{ id: 'priority', label: '优先级', disableSort: false },
|
{ id: 'priority', label: '优先级', disableSort: false, width: '80px' },
|
||||||
{ id: 'weight', label: '权重', disableSort: false },
|
{ id: 'weight', label: '权重', disableSort: false, width: '80px' },
|
||||||
{ id: 'action', label: '操作', disableSort: true }
|
{ id: 'action', label: '操作', disableSort: true }
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
Loading…
Reference in New Issue
Block a user