Fix some bug (#5048)

* fix: chat log time range

* fix: repeat system prompt

* perf: nanoid random

* fix: get files from histories

* fix: ts

* ts config

* perf: search dataset collection
This commit is contained in:
Archer
2025-06-17 16:10:01 +08:00
committed by GitHub
parent 7981b61ca9
commit af3221fa47
21 changed files with 121 additions and 79 deletions

View File

@@ -1,5 +1,5 @@
---
title: 'V4.9.12(进行中)'
title: 'V4.9.12'
description: 'FastGPT V4.9.12 更新说明'
icon: 'upgrade'
draft: false
@@ -7,6 +7,16 @@ toc: true
weight: 788
---
## 更新指南
### 1. 更新镜像:
- 更新 FastGPT 镜像 tag: v4.9.12
- 更新 FastGPT 商业版镜像 tag: v4.9.12
- mcp_server 无需更新
- Sandbox 无需更新
- 更新 AIProxy 镜像 tag: v0.2.2
## 🚀 新增内容
1. AI proxy 监控完善,支持以图表/表格形式查看模型调用和性能情况。

View File

@@ -0,0 +1,23 @@
---
title: 'V4.9.13(进行中)'
description: 'FastGPT V4.9.13 更新说明'
icon: 'upgrade'
draft: false
toc: true
weight: 787
---
## 🚀 新增内容
## ⚙️ 优化
1. 所有 NodeId 调整随机值生成,避免首字母数字开头。
2. 知识库集合搜索,支持嵌套搜索。
## 🐛 修复
1. 对话日志,日期范围选择问题。
2. API 调用时,传入的 system 提示词可能会重复。
3. AI 对话/工具调用,未选择文件链接时,也会从历史记录读取文件。

View File

@@ -8,12 +8,12 @@ import {
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../workflow/node/constant';
import { nanoid } from 'nanoid';
import { type McpToolConfigType } from '../type';
import { i18nT } from '../../../../web/i18n/utils';
import { type RuntimeNodeItemType } from '../../workflow/runtime/type';
import { type StoreSecretValueType } from '../../../common/secret/type';
import { jsonSchema2NodeInput } from '../jsonschema';
import { getNanoid } from '../../../common/string/tools';
export const getMCPToolSetRuntimeNode = ({
url,
@@ -29,7 +29,7 @@ export const getMCPToolSetRuntimeNode = ({
avatar?: string;
}): RuntimeNodeItemType => {
return {
nodeId: nanoid(16),
nodeId: getNanoid(16),
flowNodeType: FlowNodeTypeEnum.toolSet,
avatar,
intro: 'MCP Tools',
@@ -64,7 +64,7 @@ export const getMCPToolRuntimeNode = ({
avatar?: string;
}): RuntimeNodeItemType => {
return {
nodeId: nanoid(16),
nodeId: getNanoid(16),
flowNodeType: FlowNodeTypeEnum.tool,
avatar,
intro: tool.description,

View File

@@ -1,10 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@fastgpt/global/*": ["./*"]
}
"baseUrl": "."
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.d.ts"]
}

View File

@@ -14,10 +14,7 @@
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"baseUrl": ".",
"paths": {
"@fastgpt/plugins/*": ["./*"]
}
"baseUrl": "."
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.d.ts", "../**/*.d.ts"],
"exclude": ["node_modules"]

View File

@@ -105,8 +105,9 @@ export const loadRequestMessages = async ({
const arrayContent = content
.filter((item) => item.text)
.map((item) => ({ ...item, text: addEndpointToImageUrl(item.text) }));
if (arrayContent.length === 0) return;
.map((item) => addEndpointToImageUrl(item.text))
.join('\n');
return arrayContent;
};
// Parse user content(text and img) Store history => api messages

View File

@@ -42,8 +42,8 @@ type Response = DispatchNodeResultType<{
}>;
export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<Response> => {
const {
node: { nodeId, name, isEntry, version },
let {
node: { nodeId, name, isEntry, version, inputs },
runtimeNodes,
runtimeEdges,
histories,
@@ -70,6 +70,11 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
props.params.aiChatVision = aiChatVision && toolModel.vision;
props.params.aiChatReasoning = aiChatReasoning && toolModel.reasoning;
const fileUrlInput = inputs.find((item) => item.key === NodeInputKeyEnum.fileUrlList);
if (!fileUrlInput || !fileUrlInput.value || fileUrlInput.value.length === 0) {
fileLinks = undefined;
}
console.log(fileLinks, 22);
const toolNodeIds = filterToolNodeIdByEdges({ nodeId, edges: runtimeEdges });

View File

@@ -13,7 +13,6 @@ import { createChatCompletion } from '../../../ai/config';
import type {
ChatCompletionMessageParam,
CompletionFinishReason,
CompletionUsage,
StreamChatType
} from '@fastgpt/global/core/ai/type.d';
import { formatModelChars2Points } from '../../../../support/wallet/usage/utils';
@@ -45,7 +44,8 @@ import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/
import { responseWriteController } from '../../../../common/response';
import { getLLMModel } from '../../../ai/model';
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
import type { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import type { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
import { checkQuoteQAValue, getHistories } from '../utils';
import { filterSearchResultsByMaxChars } from '../../utils';
@@ -82,7 +82,7 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
retainDatasetCite = true,
externalProvider,
histories,
node: { name, version },
node: { name, version, inputs },
query,
runningUserInfo,
workflowStreamResponse,
@@ -119,6 +119,11 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
aiChatVision = modelConstantsData.vision && aiChatVision;
aiChatReasoning = !!aiChatReasoning && !!modelConstantsData.reasoning;
// Check fileLinks is reference variable
const fileUrlInput = inputs.find((item) => item.key === NodeInputKeyEnum.fileUrlList);
if (!fileUrlInput || !fileUrlInput.value || fileUrlInput.value.length === 0) {
fileLinks = undefined;
}
const chatHistories = getHistories(history, histories);
quoteQA = checkQuoteQAValue(quoteQA);

View File

@@ -84,10 +84,12 @@ export const filterToolNodeIdByEdges = ({
export const getHistories = (history?: ChatItemType[] | number, histories: ChatItemType[] = []) => {
if (!history) return [];
const systemHistories = histories.filter((item) => item.obj === ChatRoleEnum.System);
const systemHistoryIndex = histories.findIndex((item) => item.obj !== ChatRoleEnum.System);
const systemHistories = histories.slice(0, systemHistoryIndex);
const chatHistories = histories.slice(systemHistoryIndex);
const filterHistories = (() => {
if (typeof history === 'number') return histories.slice(-(history * 2));
if (typeof history === 'number') return chatHistories.slice(-(history * 2));
if (Array.isArray(history)) return history;
return [];
})();

View File

@@ -1,10 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@fastgpt/servive/*": ["./*"]
}
"baseUrl": "."
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.d.ts", "../../**/*.d.ts"]
}

View File

@@ -1,12 +1,17 @@
import React, { useState, useMemo, useRef, useEffect } from 'react';
import { Box, Card, Flex, useTheme, useOutsideClick, Button } from '@chakra-ui/react';
import { addDays, format } from 'date-fns';
import { type DateRange, DayPicker } from 'react-day-picker';
import { DayPicker } from 'react-day-picker';
import 'react-day-picker/dist/style.css';
import zhCN from 'date-fns/locale/zh-CN';
import { useTranslation } from 'next-i18next';
import MyIcon from '../Icon';
export type DateRangeType = {
from: Date;
to: Date;
};
const DateRangePicker = ({
onChange,
onSuccess,
@@ -17,16 +22,16 @@ const DateRangePicker = ({
},
dateRange
}: {
onChange?: (date: DateRange) => void;
onSuccess?: (date: DateRange) => void;
onChange?: (date: DateRangeType) => void;
onSuccess?: (date: DateRangeType) => void;
position?: 'bottom' | 'top';
defaultDate?: DateRange;
dateRange?: DateRange;
defaultDate?: DateRangeType;
dateRange?: DateRangeType;
}) => {
const { t } = useTranslation();
const theme = useTheme();
const OutRangeRef = useRef(null);
const [range, setRange] = useState<DateRange | undefined>(defaultDate);
const [range, setRange] = useState<DateRangeType>(defaultDate);
const [showSelected, setShowSelected] = useState(false);
useEffect(() => {
@@ -87,28 +92,30 @@ const DateRangePicker = ({
defaultMonth={defaultDate.to}
selected={range}
disabled={[
{ from: new Date(2022, 3, 1), to: addDays(new Date(), -90) },
{ from: new Date(2022, 3, 1), to: addDays(new Date(), -180) },
{ from: addDays(new Date(), 1), to: new Date(2099, 1, 1) }
]}
onSelect={(date) => {
if (date?.from === undefined) {
date = {
let typeDate = date as DateRangeType;
if (!typeDate || typeDate?.from === undefined) {
typeDate = {
from: range?.from,
to: range?.from
};
}
if (date?.to === undefined) {
date.to = date.from;
if (typeDate?.to === undefined) {
typeDate.to = typeDate.from;
}
if (date?.from) {
date.from = new Date(date.from.setHours(0, 0, 0, 0));
if (typeDate?.from) {
typeDate.from = new Date(typeDate.from.setHours(0, 0, 0, 0));
}
if (date?.to) {
date.to = new Date(date.to.setHours(23, 59, 59, 999));
if (typeDate?.to) {
typeDate.to = new Date(typeDate.to.setHours(23, 59, 59, 999));
}
setRange(date);
onChange?.(date);
setRange(typeDate);
onChange?.(typeDate);
}}
footer={
<Flex justifyContent={'flex-end'}>
@@ -139,4 +146,3 @@ const DateRangePicker = ({
};
export default DateRangePicker;
export type DateRangeType = DateRange;

View File

@@ -258,6 +258,7 @@ export function usePagination<DataT, ResT = {}>(
return {
pageNum,
setPageNum,
pageSize,
total: totalDataLength,
data,

View File

@@ -1,10 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@fastgpt/web/*": ["./*"]
}
"baseUrl": "."
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.d.ts", "../**/*.d.ts"]
}

View File

@@ -21,7 +21,6 @@ import {
import type { VariableItemType } from '@fastgpt/global/core/app/type.d';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useForm, type UseFormReset } from 'react-hook-form';
import { customAlphabet } from 'nanoid';
import MyModal from '@fastgpt/web/components/common/MyModal';
import { useTranslation } from 'next-i18next';
import { useToast } from '@fastgpt/web/hooks/useToast';
@@ -36,11 +35,10 @@ import DndDrag, {
type DraggableProvided,
type DraggableStateSnapshot
} from '@fastgpt/web/components/common/DndDrag';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
import { getNanoid } from '@fastgpt/global/common/string/tools';
export const defaultVariable: VariableItemType = {
id: nanoid(),
id: getNanoid(6),
key: '',
label: '',
type: VariableInputEnum.input,
@@ -136,7 +134,7 @@ const VariableEdit = ({
} else {
onChangeVariable.push({
...data,
id: nanoid()
id: getNanoid(6)
});
}

View File

@@ -306,7 +306,7 @@ const ChatInput = ({
isChatting ? 'primary.50' : canSendMessage ? 'primary.500' : 'rgba(17, 24, 36, 0.1)'
}
borderRadius={['md', 'lg']}
cursor={canSendMessage ? 'pointer' : 'not-allowed'}
cursor={isChatting ? 'pointer' : canSendMessage ? 'pointer' : 'not-allowed'}
onClick={() => {
if (isChatting) {
return onStop();

View File

@@ -1,4 +1,4 @@
import React, { useMemo, useState } from 'react';
import React, { useEffect, useMemo, useState } from 'react';
import {
Flex,
Box,
@@ -46,8 +46,8 @@ const Logs = () => {
const appId = useContextSelector(AppContext, (v) => v.appId);
const [dateRange, setDateRange] = useState<DateRangeType>({
from: addDays(new Date(), -7),
to: new Date()
from: new Date(addDays(new Date(), -6).setHours(0, 0, 0, 0)),
to: new Date(new Date().setHours(23, 59, 59, 999))
});
const [detailLogsId, setDetailLogsId] = useState<string>();
@@ -69,6 +69,16 @@ const Logs = () => {
[t]
);
const params = useMemo(
() => ({
appId,
dateStart: dateRange.from!,
dateEnd: dateRange.to!,
sources: isSelectAllSource ? undefined : chatSources,
logTitle
}),
[appId, chatSources, dateRange.from, dateRange.to, isSelectAllSource, logTitle]
);
const {
data: logs,
isLoading,
@@ -78,14 +88,8 @@ const Logs = () => {
total
} = usePagination(getAppChatLogs, {
pageSize: 20,
params: {
appId,
dateStart: dateRange.from || new Date(),
dateEnd: addDays(dateRange.to || new Date(), 1),
sources: isSelectAllSource ? undefined : chatSources,
logTitle
},
refreshDeps: [chatSources, logTitle]
params,
refreshDeps: [params]
});
const { runAsync: exportLogs } = useRequest2(
@@ -116,7 +120,7 @@ const Logs = () => {
refreshDeps: [chatSources, logTitle]
}
);
console.log(dateRange, 111);
return (
<Flex
flexDirection={'column'}
@@ -153,8 +157,9 @@ const Logs = () => {
<DateRangePicker
defaultDate={dateRange}
position="bottom"
onChange={setDateRange}
onSuccess={() => getData(1)}
onSuccess={(date) => {
setDateRange(date);
}}
/>
</Flex>
<Flex alignItems={'center'} gap={2}>

View File

@@ -30,8 +30,7 @@ import { useContextSelector } from 'use-context-selector';
import { DatasetPageContext } from '@/web/core/dataset/context/datasetPageContext';
import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12);
import { getNanoid } from '@fastgpt/global/common/string/tools';
const DatasetParamsModal = dynamic(() => import('@/components/core/app/DatasetParamsModal'));
@@ -108,7 +107,7 @@ const Test = ({ datasetId }: { datasetId: string }) => {
}
const testItem: SearchTestStoreItemType = {
id: nanoid(),
id: getNanoid(),
datasetId,
text: getValues('inputText').trim(),
time: new Date(),

View File

@@ -38,13 +38,14 @@ async function handler(req: NextApiRequest) {
const match = {
teamId: new Types.ObjectId(teamId),
datasetId: new Types.ObjectId(datasetId),
parentId: parentId ? new Types.ObjectId(parentId) : null,
...(selectFolder ? { type: DatasetCollectionTypeEnum.folder } : {}),
...(searchText
? {
name: new RegExp(searchText, 'i')
}
: {}),
: {
parentId: parentId ? new Types.ObjectId(parentId) : null
}),
...(filterTags.length ? { tags: { $in: filterTags } } : {})
};

View File

@@ -43,13 +43,14 @@ async function handler(
const match = {
teamId: new Types.ObjectId(teamId),
datasetId: new Types.ObjectId(datasetId),
parentId: parentId ? new Types.ObjectId(parentId) : null,
...(selectFolder ? { type: DatasetCollectionTypeEnum.folder } : {}),
...(searchText
? {
name: new RegExp(searchText, 'i')
}
: {}),
: {
parentId: parentId ? new Types.ObjectId(parentId) : null
}),
...(filterTags.length ? { tags: { $in: filterTags } } : {})
};

View File

@@ -1,7 +1,6 @@
import { MongoOutLink } from '@fastgpt/service/support/outLink/schema';
import { authApp } from '@fastgpt/service/support/permission/app/auth';
import type { OutLinkEditType } from '@fastgpt/global/support/outLink/type.d';
import { customAlphabet } from 'nanoid';
import type { PublishChannelEnum } from '@fastgpt/global/support/outLink/constant';
import { ManagePermissionVal } from '@fastgpt/global/support/permission/constant';
import type { ApiRequestProps } from '@fastgpt/service/type/next';
@@ -9,8 +8,7 @@ import { NextAPI } from '@/service/middleware/entry';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nAppType } from '@fastgpt/service/support/operationLog/util';
/* create a shareChat */
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 24);
import { getNanoid } from '@fastgpt/global/common/string/tools';
export type OutLinkCreateQuery = {};
export type OutLinkCreateBody = OutLinkEditType &
@@ -32,7 +30,7 @@ async function handler(
per: ManagePermissionVal
});
const shareId = nanoid();
const shareId = getNanoid(24);
await MongoOutLink.create({
shareId,
teamId,

View File

@@ -16,7 +16,6 @@
"incremental": true,
"baseUrl": ".",
"paths": {
"@/*": ["projects/app/src/*"],
"@fastgpt/*": ["packages/*"],
"@test": ["test/*"]
}