perf: ai proxy log remove retry log;perf: workflow type auto parse;add chunk spliter test (#4296)

* sync collection

* remove lock

* perf: workflow type auto parse

* add chunk spliter test

* perf: ai proxy log remove retry log

* udpate ai proxy field
This commit is contained in:
Archer 2025-03-24 17:16:49 +08:00 committed by archer
parent 2fcf421672
commit 6ea57e4609
No known key found for this signature in database
GPG Key ID: 4446499B846D4A9E
12 changed files with 475 additions and 18 deletions

View File

@ -26,6 +26,9 @@ weight: 799
3. 无 SSL 证书时复制失败,会提示弹窗用于手动复制。
4. FastGPT 未内置 ai proxy 渠道时,也能正常展示其名称。
5. 升级 nextjs 版本至 14.2.25。
6. 工作流节点数组字符串类型,自动适配 string 输入。
7. 工作流节点数组类型,自动进行 JSON parse 解析 string 输入。
8. AI proxy 日志优化,去除重试失败的日志,仅保留最后一份错误日志。
## 🐛 修复

View File

@ -20,6 +20,7 @@ export enum WorkflowIOValueTypeEnum {
number = 'number',
boolean = 'boolean',
object = 'object',
arrayString = 'arrayString',
arrayNumber = 'arrayNumber',
arrayBoolean = 'arrayBoolean',

View File

@ -78,7 +78,7 @@ export const Input_Template_Text_Quote: FlowNodeInputItemType = {
export const Input_Template_File_Link: FlowNodeInputItemType = {
key: NodeInputKeyEnum.fileUrlList,
renderTypeList: [FlowNodeInputTypeEnum.reference],
renderTypeList: [FlowNodeInputTypeEnum.reference, FlowNodeInputTypeEnum.input],
label: i18nT('app:workflow.user_file_input'),
debugLabel: i18nT('app:workflow.user_file_input'),
description: i18nT('app:workflow.user_file_input_desc'),

View File

@ -117,6 +117,9 @@ export const valueTypeFormat = (value: any, type?: WorkflowIOValueTypeEnum) => {
return Boolean(value);
}
try {
if (WorkflowIOValueTypeEnum.arrayString && typeof value === 'string') {
return [value];
}
if (
type &&
[
@ -124,7 +127,12 @@ export const valueTypeFormat = (value: any, type?: WorkflowIOValueTypeEnum) => {
WorkflowIOValueTypeEnum.chatHistory,
WorkflowIOValueTypeEnum.datasetQuote,
WorkflowIOValueTypeEnum.selectApp,
WorkflowIOValueTypeEnum.selectDataset
WorkflowIOValueTypeEnum.selectDataset,
WorkflowIOValueTypeEnum.arrayString,
WorkflowIOValueTypeEnum.arrayNumber,
WorkflowIOValueTypeEnum.arrayBoolean,
WorkflowIOValueTypeEnum.arrayObject,
WorkflowIOValueTypeEnum.arrayAny
].includes(type) &&
typeof value !== 'object'
) {

View File

@ -37,6 +37,7 @@
"model_tokens": "Input/Output tokens",
"request_at": "Request time",
"request_duration": "Request duration: {{duration}}s",
"retry_times": "Number of retry times",
"running_test": "In testing",
"search_model": "Search for models",
"select_channel": "Select a channel name",

View File

@ -37,6 +37,7 @@
"model_tokens": "输入/输出 Tokens",
"request_at": "请求时间",
"request_duration": "请求时长: {{duration}}s",
"retry_times": "重试次数",
"running_test": "测试中",
"search_model": "搜索模型",
"select_channel": "选择渠道名",

View File

@ -35,6 +35,7 @@
"model_tokens": "輸入/輸出 Tokens",
"request_at": "請求時間",
"request_duration": "請求時長: {{duration}}s",
"retry_times": "重試次數",
"running_test": "測試中",
"search_model": "搜索模型",
"select_channel": "選擇渠道名",

View File

@ -30,6 +30,13 @@ export type CreateChannelProps = {
};
// Log
export type ChannelLogUsageType = {
cache_creation_tokens?: number;
cached_tokens?: number;
input_tokens?: number;
output_tokens?: number;
total_tokens?: number;
};
export type ChannelLogListItemType = {
token_name: string;
model: string;
@ -40,8 +47,8 @@ export type ChannelLogListItemType = {
created_at: number;
request_at: number;
code: number;
prompt_tokens: number;
completion_tokens: number;
usage?: ChannelLogUsageType;
endpoint: string;
content?: string;
retry_times?: number;
};

View File

@ -33,6 +33,7 @@ import { formatTime2YMDHMS } from '@fastgpt/global/common/string/time';
import MyModal from '@fastgpt/web/components/common/MyModal';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
import SearchInput from '@fastgpt/web/components/common/Input/SearchInput';
import { ChannelLogUsageType } from '@/global/aiproxy/type';
type LogDetailType = {
id: number;
@ -42,10 +43,10 @@ type LogDetailType = {
duration: number;
request_at: string;
code: number;
prompt_tokens: number;
completion_tokens: number;
usage?: ChannelLogUsageType;
endpoint: string;
retry_times?: number;
content?: string;
request_body?: string;
response_body?: string;
@ -159,8 +160,7 @@ const ChannelLog = ({ Tab }: { Tab: React.ReactNode }) => {
duration: durationSecond,
request_at: formatTime2YMDHMS(item.request_at),
code: item.code,
prompt_tokens: item.prompt_tokens,
completion_tokens: item.completion_tokens,
usage: item.usage,
request_id: item.request_id,
endpoint: item.endpoint,
content: item.content
@ -260,7 +260,7 @@ const ChannelLog = ({ Tab }: { Tab: React.ReactNode }) => {
<Td>{item.channelName}</Td>
<Td>{item.model}</Td>
<Td>
{item.prompt_tokens} / {item.completion_tokens}
{item.usage?.input_tokens} / {item.usage?.output_tokens}
</Td>
<Td color={item.duration > 10 ? 'red.600' : ''}>{item.duration.toFixed(2)}s</Td>
<Td color={item.code === 200 ? 'green.600' : 'red.600'}>
@ -297,6 +297,7 @@ const LogDetail = ({ data, onClose }: { data: LogDetailType; onClose: () => void
const { t } = useTranslation();
const { data: detailData } = useRequest2(
async () => {
console.log(data);
if (data.code === 200) return data;
try {
const res = await getLogDetail(data.id);
@ -363,7 +364,7 @@ const LogDetail = ({ data, onClose }: { data: LogDetailType; onClose: () => void
<Title>RequestID</Title>
<Container>{detailData?.request_id}</Container>
</GridItem>
<GridItem display={'flex'} borderBottomWidth="1px" borderRightWidth="1px">
<GridItem display={'flex'} borderBottomWidth="1px">
<Title>{t('account_model:channel_status')}</Title>
<Container color={detailData.code === 200 ? 'green.600' : 'red.600'}>
{detailData?.code}
@ -373,7 +374,7 @@ const LogDetail = ({ data, onClose }: { data: LogDetailType; onClose: () => void
<Title>Endpoint</Title>
<Container>{detailData?.endpoint}</Container>
</GridItem>
<GridItem display={'flex'} borderBottomWidth="1px" borderRightWidth="1px">
<GridItem display={'flex'} borderBottomWidth="1px">
<Title>{t('account_model:channel_name')}</Title>
<Container>{detailData?.channelName}</Container>
</GridItem>
@ -381,7 +382,7 @@ const LogDetail = ({ data, onClose }: { data: LogDetailType; onClose: () => void
<Title>{t('account_model:request_at')}</Title>
<Container>{detailData?.request_at}</Container>
</GridItem>
<GridItem display={'flex'} borderBottomWidth="1px" borderRightWidth="1px">
<GridItem display={'flex'} borderBottomWidth="1px">
<Title>{t('account_model:duration')}</Title>
<Container>{detailData?.duration.toFixed(2)}s</Container>
</GridItem>
@ -389,20 +390,26 @@ const LogDetail = ({ data, onClose }: { data: LogDetailType; onClose: () => void
<Title>{t('account_model:model')}</Title>
<Container>{detailData?.model}</Container>
</GridItem>
<GridItem display={'flex'} borderBottomWidth="1px" borderRightWidth="1px">
<GridItem display={'flex'} borderBottomWidth="1px">
<Title flex={'0 0 150px'}>{t('account_model:model_tokens')}</Title>
<Container>
{detailData?.prompt_tokens} / {detailData?.completion_tokens}
{detailData?.usage?.input_tokens} / {detailData?.usage?.output_tokens}
</Container>
</GridItem>
{detailData?.retry_times !== undefined && (
<GridItem display={'flex'} borderBottomWidth="1px" colSpan={2}>
<Title>{t('account_model:retry_times')}</Title>
<Container>{detailData?.retry_times}</Container>
</GridItem>
)}
{detailData?.content && (
<GridItem display={'flex'} borderBottomWidth="1px" borderRightWidth="1px" colSpan={2}>
<GridItem display={'flex'} borderBottomWidth="1px" colSpan={2}>
<Title>Content</Title>
<Container>{detailData?.content}</Container>
</GridItem>
)}
{detailData?.request_body && (
<GridItem display={'flex'} borderBottomWidth="1px" borderRightWidth="1px" colSpan={2}>
<GridItem display={'flex'} borderBottomWidth="1px" colSpan={2}>
<Title>Request Body</Title>
<Container userSelect={'all'}>{detailData?.request_body}</Container>
</GridItem>

View File

@ -247,9 +247,9 @@ const MultipleReferenceSelector = ({
// Get valid item and remove invalid item
const formatList = useMemo(() => {
if (!value) return [];
if (!value || !Array.isArray(value)) return [];
return value?.map((item) => {
return value.map((item) => {
const [nodeName, outputName] = getSelectValue(item);
return {
rawValue: item,

View File

@ -166,6 +166,7 @@ export const getChannelLog = (params: {
logs: ChannelLogListItemType[];
total: number;
}>(`/logs/search`, {
result_only: true,
request_id: params.request_id,
channel: params.channel,
model_name: params.model_name,

File diff suppressed because one or more lines are too long