mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-27 00:17:31 +00:00
4.6.4 (#588)
This commit is contained in:
@@ -21,3 +21,5 @@ MONGODB_URI=mongodb://username:password@0.0.0.0:27017/fastgpt?authSource=admin
|
||||
PG_URL=postgresql://username:password@host:port/postgres
|
||||
# 首页路径
|
||||
HOME_URL=/
|
||||
# Loki Log Path
|
||||
# LOKI_LOG_URL=
|
@@ -1,11 +1,18 @@
|
||||
### Fast GPT V4.6.3
|
||||
### Fast GPT V4.6.4
|
||||
|
||||
1. 商业版新增 - web站点同步
|
||||
2. 新增 - 集合元数据记录
|
||||
3. 优化 - url 读取内容
|
||||
4. 优化 - 流读取文件,防止内存溢出
|
||||
5. [知识库结构详解](https://doc.fastgpt.in/docs/use-cases/datasetengine/)
|
||||
6. [知识库提示词详解](https://doc.fastgpt.in/docs/use-cases/ai_settings/#引用模板--引用提示词)
|
||||
7. [使用文档](https://doc.fastgpt.in/docs/intro/)
|
||||
8. [点击查看高级编排介绍文档](https://doc.fastgpt.in/docs/workflow)
|
||||
9. [点击查看商业版](https://doc.fastgpt.in/docs/commercial/)
|
||||
1. 重写 - 分享链接身份逻辑,采用 localID 记录用户的ID。
|
||||
2. 商业版新增 - 分享链接 SSO 方案,通过`身份鉴权`地址,仅需`3个接口`即可完全接入已有用户系统。具体参考[分享链接身份鉴权](https://doc.fastgpt.in/docs/development/openapi/share/)
|
||||
3. 调整 - 知识库搜索模块 topk 逻辑,采用 MaxToken 计算,兼容不同长度的文本块
|
||||
4. 调整鉴权顺序,提高 apikey 的优先级,避免cookie抢占 apikey 的鉴权。
|
||||
5. 链接读取支持多选择器。参考[Web 站点同步用法](https://doc.fastgpt.in/docs/course/webSync)
|
||||
6. 修复 - 分享链接图片上传鉴权问题
|
||||
7. 修复 - Mongo 连接池未释放问题。
|
||||
8. 修复 - Dataset Intro 无法更新
|
||||
9. 修复 - md 代码块问题
|
||||
10. 修复 - root 权限问题
|
||||
11. 优化 docker file
|
||||
12. [知识库结构详解](https://doc.fastgpt.in/docs/use-cases/datasetengine/)
|
||||
13. [知识库提示词详解](https://doc.fastgpt.in/docs/use-cases/ai_settings/#引用模板--引用提示词)
|
||||
14. [使用文档](https://doc.fastgpt.in/docs/intro/)
|
||||
15. [点击查看高级编排介绍文档](https://doc.fastgpt.in/docs/workflow)
|
||||
16. [点击查看商业版](https://doc.fastgpt.in/docs/commercial/)
|
||||
|
@@ -65,7 +65,6 @@
|
||||
"Confirm to clear share chat history": " Are you sure to delete all chats?",
|
||||
"Converting to text": "Converting to text...",
|
||||
"Exit Chat": "Exit",
|
||||
"Feedback Close": "Close Feedback",
|
||||
"Feedback Failed": "Feedback Failed",
|
||||
"Feedback Mark": "Mark",
|
||||
"Feedback Modal": "Feedback",
|
||||
@@ -81,7 +80,6 @@
|
||||
"Question Guide Tips": "I guess what you're asking is",
|
||||
"Quote": "Quote",
|
||||
"Read Mark Description": "Read mark description",
|
||||
"Read User Feedback": "Read user feedback",
|
||||
"Select Mark Kb": "Select Dataset",
|
||||
"Select Mark Kb Desc": "Select a dataset to store the expected answers",
|
||||
"You need to a chat app": "You need to a chat app",
|
||||
@@ -201,6 +199,9 @@
|
||||
"confirm": {
|
||||
"Common Tip": "Operational Confirm"
|
||||
},
|
||||
"course": {
|
||||
"Read Course": "Read Course"
|
||||
},
|
||||
"empty": {
|
||||
"Common Tip": "No data"
|
||||
},
|
||||
@@ -234,6 +235,10 @@
|
||||
},
|
||||
"speech": {
|
||||
"error tip": "Speech Failed"
|
||||
},
|
||||
"system": {
|
||||
"Help Chatbot": "Chatbot Helper",
|
||||
"Use Helper": "UsingHelp"
|
||||
}
|
||||
},
|
||||
"core": {
|
||||
@@ -257,6 +262,9 @@
|
||||
"TTS Tip": "After this function is enabled, the voice playback function can be used after each conversation. Use of this feature may incur additional charges.",
|
||||
"Welcome Text": "Welcome Text",
|
||||
"create app": "Create App",
|
||||
"logs": {
|
||||
"Source And Time": "Source & Time"
|
||||
},
|
||||
"setting": "App Setting",
|
||||
"simple": {
|
||||
"mode template select": "Template"
|
||||
@@ -283,6 +291,16 @@
|
||||
"Speaking": "I'm listening...",
|
||||
"Stop Speak": "Stop Speak",
|
||||
"Type a message": "Input problem",
|
||||
"error": {
|
||||
"Messages empty": "Interface content is empty, maybe the text is too long ~"
|
||||
},
|
||||
"feedback": {
|
||||
"Close User Good Feedback": "",
|
||||
"Close User Like": "The user like\nClick to close the tag",
|
||||
"No Content": "The user did not fill in the specific feedback content",
|
||||
"Read User dislike": "User dislike\nClick to view content",
|
||||
"Feedback Close": "Close Feedback"
|
||||
},
|
||||
"markdown": {
|
||||
"Edit Question": "Edit Question",
|
||||
"Quick Question": "Ask the question immediately",
|
||||
@@ -295,9 +313,6 @@
|
||||
},
|
||||
"tts": {
|
||||
"Stop Speech": "Stop"
|
||||
},
|
||||
"error": {
|
||||
"Messages empty": "Interface content is empty, maybe the text is too long ~"
|
||||
}
|
||||
},
|
||||
"dataset": {
|
||||
@@ -379,13 +394,13 @@
|
||||
"id": "Data ID"
|
||||
},
|
||||
"error": {
|
||||
"Start Sync Failed": "Start Sync Failed",
|
||||
"unAuthDataset": "No access to this knowledge base ",
|
||||
"unAuthDatasetCollection": "Not authorized to manipulate this data set ",
|
||||
"unAuthDatasetData": "Not authorized to manipulate this data ",
|
||||
"unAuthDatasetFile": "No permission to manipulate this file ",
|
||||
"unCreateCollection": "No permission to manipulate this data ",
|
||||
"unLinkCollection": "not a network link collection ",
|
||||
"Start Sync Failed": "Start Sync Failed"
|
||||
"unLinkCollection": "not a network link collection "
|
||||
},
|
||||
"file": "File",
|
||||
"folder": "Folder",
|
||||
@@ -462,6 +477,7 @@
|
||||
"Confirm Create Tips": "Confirm to synchronize the site, the synchronization task will start later, please confirm!",
|
||||
"Confirm Update Tips": "Are you sure to update the site configuration? The synchronization starts immediately with the new configuration. Please confirm",
|
||||
"Selector": "Selector",
|
||||
"Selector Course": "Selector using tutorial",
|
||||
"Start Sync": "Start Sync",
|
||||
"UnValid Website Tip": "Your site may not be static and cannot be synchronized"
|
||||
}
|
||||
@@ -669,6 +685,10 @@
|
||||
"Visual AI orchestration": "Visual AI orchestration",
|
||||
"Why FastGPT": "Why {{title}}",
|
||||
"desc": "AI knowledge base question and answer platform based on LLM large model",
|
||||
"navbar": {
|
||||
"Use guidance": "Use Guidance",
|
||||
"chatbot": "Chatbot"
|
||||
},
|
||||
"slogan": "Let the AI know more about you"
|
||||
},
|
||||
"module": {
|
||||
|
@@ -65,7 +65,6 @@
|
||||
"Confirm to clear share chat history": "确认删除所有聊天记录?",
|
||||
"Converting to text": "正在转换为文本...",
|
||||
"Exit Chat": "退出聊天",
|
||||
"Feedback Close": "关闭反馈",
|
||||
"Feedback Failed": "提交反馈异常",
|
||||
"Feedback Mark": "标注",
|
||||
"Feedback Modal": "结果反馈",
|
||||
@@ -81,7 +80,6 @@
|
||||
"Question Guide Tips": "猜你想问",
|
||||
"Quote": "引用",
|
||||
"Read Mark Description": "查看标注功能介绍",
|
||||
"Read User Feedback": "查看用户反馈",
|
||||
"Select Mark Kb": "选择知识库",
|
||||
"Select Mark Kb Desc": "选择一个知识库存储预期答案",
|
||||
"You need to a chat app": "你需要创建一个应用",
|
||||
@@ -201,6 +199,9 @@
|
||||
"confirm": {
|
||||
"Common Tip": "操作确认"
|
||||
},
|
||||
"course": {
|
||||
"Read Course": "查看教程"
|
||||
},
|
||||
"empty": {
|
||||
"Common Tip": "没有什么数据噢~"
|
||||
},
|
||||
@@ -234,6 +235,10 @@
|
||||
},
|
||||
"speech": {
|
||||
"error tip": "语音转文字失败"
|
||||
},
|
||||
"system": {
|
||||
"Help Chatbot": "机器人助手",
|
||||
"Use Helper": "使用帮助"
|
||||
}
|
||||
},
|
||||
"core": {
|
||||
@@ -257,6 +262,9 @@
|
||||
"TTS Tip": "开启后,每次对话后可使用语音播放功能。使用该功能可能产生额外费用。",
|
||||
"Welcome Text": "对话开场白",
|
||||
"create app": "创建属于你的 AI 应用",
|
||||
"logs": {
|
||||
"Source And Time": "来源 & 时间"
|
||||
},
|
||||
"setting": "应用信息设置",
|
||||
"simple": {
|
||||
"mode template select": "简易模板"
|
||||
@@ -283,6 +291,16 @@
|
||||
"Speaking": "我在听,请说...",
|
||||
"Stop Speak": "停止录音",
|
||||
"Type a message": "输入问题",
|
||||
"error": {
|
||||
"Messages empty": "接口内容为空,可能文本超长了~"
|
||||
},
|
||||
"feedback": {
|
||||
"Close User Good Feedback": "",
|
||||
"Close User Like": "用户表示赞同\n点击关闭该标记",
|
||||
"No Content": "用户没有填写具体反馈内容",
|
||||
"Read User dislike": "用户表示反对\n点击查看内容",
|
||||
"Feedback Close": "关闭反馈"
|
||||
},
|
||||
"markdown": {
|
||||
"Edit Question": "编辑问题",
|
||||
"Quick Question": "点我立即提问",
|
||||
@@ -295,9 +313,6 @@
|
||||
},
|
||||
"tts": {
|
||||
"Stop Speech": "停止"
|
||||
},
|
||||
"error": {
|
||||
"Messages empty": "接口内容为空,可能文本超长了~"
|
||||
}
|
||||
},
|
||||
"dataset": {
|
||||
@@ -462,6 +477,7 @@
|
||||
"Confirm Create Tips": "确认同步该站点,同步任务将随后开启,请确认!",
|
||||
"Confirm Update Tips": "确认更新站点配置?会立即按新的配置开始同步,请确认!",
|
||||
"Selector": "选择器",
|
||||
"Selector Course": "选择器使用教程",
|
||||
"Start Sync": "开始同步",
|
||||
"UnValid Website Tip": "您的站点可能非静态站点,无法同步"
|
||||
}
|
||||
@@ -669,6 +685,10 @@
|
||||
"Visual AI orchestration": "可视化 AI 编排",
|
||||
"Why FastGPT": "为什么选择 {{title}}",
|
||||
"desc": "基于 LLM 大模型的 AI 知识库问答平台",
|
||||
"navbar": {
|
||||
"Use guidance": "使用引导",
|
||||
"chatbot": "问答机器人"
|
||||
},
|
||||
"slogan": "让 AI 更懂你的知识"
|
||||
},
|
||||
"module": {
|
||||
|
@@ -14,7 +14,7 @@
|
||||
"datasets": true,
|
||||
"similarity": false,
|
||||
"limit": false,
|
||||
"searchMode": "embedding",
|
||||
"searchMode": false,
|
||||
"searchEmptyText": false
|
||||
},
|
||||
"userGuide": {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { Image } from '@chakra-ui/react';
|
||||
import type { ImageProps } from '@chakra-ui/react';
|
||||
import { LOGO_ICON } from '@fastgpt/global/core/chat/constants';
|
||||
import { LOGO_ICON } from '@fastgpt/global/common/system/constants';
|
||||
|
||||
const Avatar = ({ w = '30px', src, ...props }: ImageProps) => {
|
||||
return (
|
||||
|
@@ -3,13 +3,15 @@ import { ModalBody, Textarea, ModalFooter, Button } from '@chakra-ui/react';
|
||||
import MyModal from '../MyModal';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { userUpdateChatFeedback } from '@/web/core/chat/api';
|
||||
import { updateChatUserFeedback } from '@/web/core/chat/api';
|
||||
|
||||
const FeedbackModal = ({
|
||||
chatId,
|
||||
chatItemId,
|
||||
onSuccess,
|
||||
onClose
|
||||
}: {
|
||||
chatId: string;
|
||||
chatItemId: string;
|
||||
onSuccess: (e: string) => void;
|
||||
onClose: () => void;
|
||||
@@ -19,14 +21,15 @@ const FeedbackModal = ({
|
||||
|
||||
const { mutate, isLoading } = useRequest({
|
||||
mutationFn: async () => {
|
||||
const val = ref.current?.value || 'N/A';
|
||||
return userUpdateChatFeedback({
|
||||
const val = ref.current?.value || t('core.chat.feedback.No Content');
|
||||
return updateChatUserFeedback({
|
||||
chatId,
|
||||
chatItemId,
|
||||
userFeedback: val
|
||||
userBadFeedback: val
|
||||
});
|
||||
},
|
||||
onSuccess() {
|
||||
onSuccess(ref.current?.value || 'N/A');
|
||||
onSuccess(ref.current?.value || t('core.chat.feedback.No Content'));
|
||||
},
|
||||
successToast: t('chat.Feedback Success'),
|
||||
errorToast: t('chat.Feedback Failed')
|
||||
@@ -40,11 +43,7 @@ const FeedbackModal = ({
|
||||
title={t('chat.Feedback Modal')}
|
||||
>
|
||||
<ModalBody>
|
||||
<Textarea
|
||||
ref={ref}
|
||||
rows={10}
|
||||
placeholder={t('chat.Feedback Modal Tip') || 'chat.Feedback Modal Tip'}
|
||||
/>
|
||||
<Textarea ref={ref} rows={10} placeholder={t('chat.Feedback Modal Tip')} />
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button variant={'base'} mr={2} onClick={onClose}>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import { ModalBody, Box, useTheme, Flex, Progress, Link, Image } from '@chakra-ui/react';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { ModalBody, Box, useTheme, Flex, Progress, Link } from '@chakra-ui/react';
|
||||
import { getDatasetDataItemById } from '@/web/core/dataset/api';
|
||||
import { useLoading } from '@/web/common/hooks/useLoading';
|
||||
import { useToast } from '@/web/common/hooks/useToast';
|
||||
@@ -11,7 +11,6 @@ import InputDataModal, {
|
||||
} from '@/pages/dataset/detail/components/InputDataModal';
|
||||
import MyModal from '../MyModal';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useRouter } from 'next/router';
|
||||
import type { SearchDataResponseItemType } from '@fastgpt/global/core/dataset/type';
|
||||
import MyTooltip from '../MyTooltip';
|
||||
import NextLink from 'next/link';
|
||||
@@ -19,21 +18,20 @@ import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
|
||||
const QuoteModal = ({
|
||||
rawSearch = [],
|
||||
onClose
|
||||
onClose,
|
||||
isShare
|
||||
}: {
|
||||
rawSearch: SearchDataResponseItemType[];
|
||||
onClose: () => void;
|
||||
isShare: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { isPc } = useSystemStore();
|
||||
const theme = useTheme();
|
||||
const router = useRouter();
|
||||
const { toast } = useToast();
|
||||
const { setIsLoading, Loading } = useLoading();
|
||||
const [editInputData, setEditInputData] = useState<InputDataType & { collectionId: string }>();
|
||||
|
||||
const isShare = useMemo(() => router.pathname === '/chat/share', [router.pathname]);
|
||||
|
||||
/**
|
||||
* click edit, get new DataItem
|
||||
*/
|
||||
|
@@ -1,40 +1,19 @@
|
||||
import React from 'react';
|
||||
import { ModalBody, ModalFooter, Button } from '@chakra-ui/react';
|
||||
import MyModal from '../MyModal';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { userUpdateChatFeedback } from '@/web/core/chat/api';
|
||||
|
||||
const ReadFeedbackModal = ({
|
||||
chatItemId,
|
||||
content,
|
||||
isMarked,
|
||||
onMark,
|
||||
onSuccess,
|
||||
onCloseFeedback,
|
||||
onClose
|
||||
}: {
|
||||
chatItemId: string;
|
||||
content: string;
|
||||
isMarked: boolean;
|
||||
onMark: () => void;
|
||||
onSuccess: () => void;
|
||||
onCloseFeedback: () => void;
|
||||
onClose: () => void;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { mutate, isLoading } = useRequest({
|
||||
mutationFn: async () => {
|
||||
return userUpdateChatFeedback({
|
||||
chatItemId,
|
||||
userFeedback: undefined
|
||||
});
|
||||
},
|
||||
onSuccess() {
|
||||
onSuccess();
|
||||
},
|
||||
errorToast: t('chat.Feedback Update Failed')
|
||||
});
|
||||
|
||||
return (
|
||||
<MyModal
|
||||
isOpen={true}
|
||||
@@ -44,14 +23,9 @@ const ReadFeedbackModal = ({
|
||||
>
|
||||
<ModalBody>{content}</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button mr={2} isLoading={isLoading} variant={'base'} onClick={mutate}>
|
||||
{t('chat.Feedback Close')}
|
||||
<Button mr={2} onClick={onCloseFeedback}>
|
||||
{t('core.chat.feedback.Feedback Close')}
|
||||
</Button>
|
||||
{!isMarked && (
|
||||
<Button mr={2} onClick={onMark}>
|
||||
{t('chat.Feedback Mark')}
|
||||
</Button>
|
||||
)}
|
||||
</ModalFooter>
|
||||
</MyModal>
|
||||
);
|
||||
|
@@ -13,12 +13,19 @@ import { getSourceNameIcon } from '@fastgpt/global/core/dataset/utils';
|
||||
import ChatBoxDivider from '@/components/core/chat/Divider';
|
||||
import MyIcon from '../Icon';
|
||||
import { getFileAndOpen } from '@/web/core/dataset/utils';
|
||||
import { strIsLink } from '@fastgpt/global/common/string/tools';
|
||||
|
||||
const QuoteModal = dynamic(() => import('./QuoteModal'), { ssr: false });
|
||||
const ContextModal = dynamic(() => import('./ContextModal'), { ssr: false });
|
||||
const WholeResponseModal = dynamic(() => import('./WholeResponseModal'), { ssr: false });
|
||||
|
||||
const ResponseTags = ({ responseData = [] }: { responseData?: ChatHistoryItemResType[] }) => {
|
||||
const ResponseTags = ({
|
||||
responseData = [],
|
||||
isShare
|
||||
}: {
|
||||
responseData?: ChatHistoryItemResType[];
|
||||
isShare: boolean;
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const { isPc } = useSystemStore();
|
||||
const { t } = useTranslation();
|
||||
@@ -62,12 +69,13 @@ const ResponseTags = ({ responseData = [] }: { responseData?: ChatHistoryItemRes
|
||||
.map((item) => ({
|
||||
sourceName: item.sourceName,
|
||||
sourceId: item.sourceId,
|
||||
icon: getSourceNameIcon({ sourceId: item.sourceId, sourceName: item.sourceName })
|
||||
icon: getSourceNameIcon({ sourceId: item.sourceId, sourceName: item.sourceName }),
|
||||
canReadQuote: !isShare || strIsLink(item.sourceId)
|
||||
})),
|
||||
historyPreview: chatData?.historyPreview,
|
||||
runningTime: +responseData.reduce((sum, item) => sum + (item.runningTime || 0), 0).toFixed(2)
|
||||
};
|
||||
}, [responseData]);
|
||||
}, [isShare, responseData]);
|
||||
|
||||
const TagStyles: BoxProps = {
|
||||
mr: 2,
|
||||
@@ -97,7 +105,6 @@ const ResponseTags = ({ responseData = [] }: { responseData?: ChatHistoryItemRes
|
||||
}}
|
||||
overflow={'hidden'}
|
||||
position={'relative'}
|
||||
onClick={() => setQuoteModalData(quoteList)}
|
||||
>
|
||||
<Image src={item.icon} alt={''} mr={1} w={'12px'} />
|
||||
<Box className="textEllipsis" flex={'1 0 0'}>
|
||||
@@ -106,7 +113,7 @@ const ResponseTags = ({ responseData = [] }: { responseData?: ChatHistoryItemRes
|
||||
|
||||
<Box
|
||||
className="controller"
|
||||
display={['flex', 'none']}
|
||||
display={'none'}
|
||||
pr={2}
|
||||
position={'absolute'}
|
||||
right={0}
|
||||
@@ -127,9 +134,13 @@ const ResponseTags = ({ responseData = [] }: { responseData?: ChatHistoryItemRes
|
||||
_hover={{
|
||||
color: 'green.600'
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setQuoteModalData(quoteList);
|
||||
}}
|
||||
/>
|
||||
</MyTooltip>
|
||||
{item.sourceId && (
|
||||
{item.sourceId && item.canReadQuote && (
|
||||
<MyTooltip label={t('core.chat.quote.Read Source')}>
|
||||
<MyIcon
|
||||
ml={4}
|
||||
@@ -201,7 +212,11 @@ const ResponseTags = ({ responseData = [] }: { responseData?: ChatHistoryItemRes
|
||||
</MyTooltip>
|
||||
|
||||
{!!quoteModalData && (
|
||||
<QuoteModal rawSearch={quoteModalData} onClose={() => setQuoteModalData(undefined)} />
|
||||
<QuoteModal
|
||||
rawSearch={quoteModalData}
|
||||
isShare={isShare}
|
||||
onClose={() => setQuoteModalData(undefined)}
|
||||
/>
|
||||
)}
|
||||
{!!contextModalData && (
|
||||
<ContextModal context={contextModalData} onClose={() => setContextModalData(undefined)} />
|
||||
|
@@ -43,7 +43,7 @@ import { useRouter } from 'next/router';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
import { adminUpdateChatFeedback, userUpdateChatFeedback } from '@/web/core/chat/api';
|
||||
import { updateChatAdminFeedback, updateChatUserFeedback } from '@/web/core/chat/api';
|
||||
import type { AdminMarkType } from './SelectMarkCollection';
|
||||
|
||||
import MyIcon from '@/components/Icon';
|
||||
@@ -51,7 +51,6 @@ import Avatar from '@/components/Avatar';
|
||||
import Markdown, { CodeClassName } from '@/components/Markdown';
|
||||
import MySelect from '@/components/Select';
|
||||
import MyTooltip from '../MyTooltip';
|
||||
import ChatBoxDivider from '@/components/core/chat/Divider';
|
||||
import dynamic from 'next/dynamic';
|
||||
const ResponseTags = dynamic(() => import('./ResponseTags'));
|
||||
const FeedbackModal = dynamic(() => import('./FeedbackModal'));
|
||||
@@ -64,7 +63,6 @@ import { splitGuideModule } from '@fastgpt/global/core/module/utils';
|
||||
import type { AppTTSConfigType } from '@fastgpt/global/core/module/type.d';
|
||||
import MessageInput from './MessageInput';
|
||||
import { ModuleOutputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/module/node/constant';
|
||||
|
||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 24);
|
||||
|
||||
@@ -104,6 +102,9 @@ type Props = {
|
||||
userGuideModule?: ModuleItemType;
|
||||
showFileSelector?: boolean;
|
||||
active?: boolean; // can use
|
||||
chatId?: string;
|
||||
shareId?: string;
|
||||
outLinkUid?: string;
|
||||
onUpdateVariable?: (e: Record<string, any>) => void;
|
||||
onStartChat?: (e: StartChatFnProps) => Promise<{
|
||||
responseText: string;
|
||||
@@ -124,6 +125,9 @@ const ChatBox = (
|
||||
userGuideModule,
|
||||
showFileSelector,
|
||||
active = true,
|
||||
chatId,
|
||||
shareId,
|
||||
outLinkUid,
|
||||
onUpdateVariable,
|
||||
onStartChat,
|
||||
onDelMessage
|
||||
@@ -133,7 +137,6 @@ const ChatBox = (
|
||||
const ChatBoxRef = useRef<HTMLDivElement>(null);
|
||||
const theme = useTheme();
|
||||
const router = useRouter();
|
||||
const { shareId } = router.query as { shareId?: string };
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToast();
|
||||
const { isPc, setLoading } = useSystemStore();
|
||||
@@ -147,10 +150,8 @@ const ChatBox = (
|
||||
const [chatHistory, setChatHistory] = useState<ChatSiteItemType[]>([]);
|
||||
const [feedbackId, setFeedbackId] = useState<string>();
|
||||
const [readFeedbackData, setReadFeedbackData] = useState<{
|
||||
// read feedback modal data
|
||||
chatItemId: string;
|
||||
content: string;
|
||||
isMarked: boolean;
|
||||
}>();
|
||||
const [adminMarkData, setAdminMarkData] = useState<AdminMarkType & { chatItemId: string }>();
|
||||
const [questionGuides, setQuestionGuide] = useState<string[]>([]);
|
||||
@@ -653,7 +654,6 @@ const ChatBox = (
|
||||
<Box mt={['6px', 2]} textAlign={'right'}>
|
||||
<Card
|
||||
className="markdown"
|
||||
whiteSpace={'pre-wrap'}
|
||||
{...MessageCardStyle}
|
||||
bg={'myBlue.300'}
|
||||
borderRadius={'8px 0 8px 8px'}
|
||||
@@ -706,33 +706,90 @@ const ChatBox = (
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
onReadFeedback={
|
||||
onAddUserLike={(() => {
|
||||
if (feedbackType !== FeedbackTypeEnum.user || item.userBadFeedback) {
|
||||
return;
|
||||
}
|
||||
return () => {
|
||||
if (!item.dataId || !chatId) return;
|
||||
|
||||
const isGoodFeedback = !!item.userGoodFeedback;
|
||||
setChatHistory((state) =>
|
||||
state.map((chatItem) =>
|
||||
chatItem.dataId === item.dataId
|
||||
? {
|
||||
...chatItem,
|
||||
userGoodFeedback: isGoodFeedback ? undefined : 'yes'
|
||||
}
|
||||
: chatItem
|
||||
)
|
||||
);
|
||||
try {
|
||||
updateChatUserFeedback({
|
||||
chatId,
|
||||
chatItemId: item.dataId,
|
||||
shareId,
|
||||
outLinkUid,
|
||||
userGoodFeedback: isGoodFeedback ? undefined : 'yes'
|
||||
});
|
||||
} catch (error) {}
|
||||
};
|
||||
})()}
|
||||
onCloseUserLike={
|
||||
feedbackType === FeedbackTypeEnum.admin
|
||||
? () =>
|
||||
setReadFeedbackData({
|
||||
chatItemId: item.dataId || '',
|
||||
content: item.userFeedback || '',
|
||||
isMarked: !!item.adminFeedback
|
||||
})
|
||||
? () => {
|
||||
if (!item.dataId || !chatId) return;
|
||||
setChatHistory((state) =>
|
||||
state.map((chatItem) =>
|
||||
chatItem.dataId === item.dataId
|
||||
? { ...chatItem, userGoodFeedback: undefined }
|
||||
: chatItem
|
||||
)
|
||||
);
|
||||
updateChatUserFeedback({
|
||||
chatId,
|
||||
chatItemId: item.dataId,
|
||||
userGoodFeedback: undefined
|
||||
});
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
onFeedback={
|
||||
feedbackType === FeedbackTypeEnum.user
|
||||
? item.userFeedback
|
||||
? () => {
|
||||
if (!item.dataId) return;
|
||||
setChatHistory((state) =>
|
||||
state.map((chatItem) =>
|
||||
chatItem.dataId === item.dataId
|
||||
? { ...chatItem, userFeedback: undefined }
|
||||
: chatItem
|
||||
)
|
||||
);
|
||||
try {
|
||||
userUpdateChatFeedback({ chatItemId: item.dataId });
|
||||
} catch (error) {}
|
||||
}
|
||||
: () => setFeedbackId(item.dataId)
|
||||
onAddUserDislike={(() => {
|
||||
if (feedbackType !== FeedbackTypeEnum.user || item.userGoodFeedback) {
|
||||
return;
|
||||
}
|
||||
if (item.userBadFeedback) {
|
||||
return () => {
|
||||
if (!item.dataId || !chatId) return;
|
||||
setChatHistory((state) =>
|
||||
state.map((chatItem) =>
|
||||
chatItem.dataId === item.dataId
|
||||
? { ...chatItem, userBadFeedback: undefined }
|
||||
: chatItem
|
||||
)
|
||||
);
|
||||
try {
|
||||
updateChatUserFeedback({
|
||||
chatId,
|
||||
chatItemId: item.dataId,
|
||||
shareId,
|
||||
outLinkUid
|
||||
});
|
||||
} catch (error) {}
|
||||
};
|
||||
} else {
|
||||
return () => setFeedbackId(item.dataId);
|
||||
}
|
||||
})()}
|
||||
onReadUserDislike={
|
||||
feedbackType === FeedbackTypeEnum.admin
|
||||
? () => {
|
||||
if (!item.dataId) return;
|
||||
setReadFeedbackData({
|
||||
chatItemId: item.dataId || '',
|
||||
content: item.userBadFeedback || ''
|
||||
});
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
@@ -786,7 +843,7 @@ const ChatBox = (
|
||||
isChatting={index === chatHistory.length - 1 && isChatting}
|
||||
/>
|
||||
|
||||
<ResponseTags responseData={item.responseData} />
|
||||
<ResponseTags responseData={item.responseData} isShare={!!shareId} />
|
||||
|
||||
{/* admin mark content */}
|
||||
{showMarkIcon && item.adminFeedback && (
|
||||
@@ -828,16 +885,16 @@ const ChatBox = (
|
||||
showFileSelector={showFileSelector}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{/* user feedback modal */}
|
||||
{!!feedbackId && (
|
||||
{!!feedbackId && chatId && (
|
||||
<FeedbackModal
|
||||
chatId={chatId}
|
||||
chatItemId={feedbackId}
|
||||
onClose={() => setFeedbackId(undefined)}
|
||||
onSuccess={(content: string) => {
|
||||
setChatHistory((state) =>
|
||||
state.map((item) =>
|
||||
item.dataId === feedbackId ? { ...item, userFeedback: content } : item
|
||||
item.dataId === feedbackId ? { ...item, userBadFeedback: content } : item
|
||||
)
|
||||
);
|
||||
setFeedbackId(undefined);
|
||||
@@ -847,27 +904,23 @@ const ChatBox = (
|
||||
{/* admin read feedback modal */}
|
||||
{!!readFeedbackData && (
|
||||
<ReadFeedbackModal
|
||||
{...readFeedbackData}
|
||||
content={readFeedbackData.content}
|
||||
onClose={() => setReadFeedbackData(undefined)}
|
||||
onMark={() => {
|
||||
const index = chatHistory.findIndex(
|
||||
(item) => item.dataId === readFeedbackData.chatItemId
|
||||
);
|
||||
if (index === -1) return setReadFeedbackData(undefined);
|
||||
setAdminMarkData({
|
||||
chatItemId: readFeedbackData.chatItemId,
|
||||
q: chatHistory[index - 1]?.value || '',
|
||||
a: chatHistory[index]?.value || ''
|
||||
});
|
||||
}}
|
||||
onSuccess={() => {
|
||||
onCloseFeedback={() => {
|
||||
setChatHistory((state) =>
|
||||
state.map((chatItem) =>
|
||||
chatItem.dataId === readFeedbackData.chatItemId
|
||||
? { ...chatItem, userFeedback: undefined }
|
||||
? { ...chatItem, userBadFeedback: undefined }
|
||||
: chatItem
|
||||
)
|
||||
);
|
||||
try {
|
||||
if (!chatId) return;
|
||||
updateChatUserFeedback({
|
||||
chatId,
|
||||
chatItemId: readFeedbackData.chatItemId
|
||||
});
|
||||
} catch (error) {}
|
||||
setReadFeedbackData(undefined);
|
||||
}}
|
||||
/>
|
||||
@@ -879,7 +932,7 @@ const ChatBox = (
|
||||
setAdminMarkData={(e) => setAdminMarkData({ ...e, chatItemId: adminMarkData.chatItemId })}
|
||||
onClose={() => setAdminMarkData(undefined)}
|
||||
onSuccess={(adminFeedback) => {
|
||||
adminUpdateChatFeedback({
|
||||
updateChatAdminFeedback({
|
||||
chatItemId: adminMarkData.chatItemId,
|
||||
...adminFeedback
|
||||
});
|
||||
@@ -895,15 +948,16 @@ const ChatBox = (
|
||||
)
|
||||
);
|
||||
|
||||
if (readFeedbackData) {
|
||||
userUpdateChatFeedback({
|
||||
if (readFeedbackData && chatId) {
|
||||
updateChatUserFeedback({
|
||||
chatId,
|
||||
chatItemId: readFeedbackData.chatItemId,
|
||||
userFeedback: undefined
|
||||
userBadFeedback: undefined
|
||||
});
|
||||
setChatHistory((state) =>
|
||||
state.map((chatItem) =>
|
||||
chatItem.dataId === readFeedbackData.chatItemId
|
||||
? { ...chatItem, userFeedback: undefined }
|
||||
? { ...chatItem, userBadFeedback: undefined }
|
||||
: chatItem
|
||||
)
|
||||
);
|
||||
@@ -1054,11 +1108,13 @@ function ChatController({
|
||||
display,
|
||||
showVoiceIcon,
|
||||
ttsConfig,
|
||||
onReadFeedback,
|
||||
onReadUserDislike,
|
||||
onCloseUserLike,
|
||||
onMark,
|
||||
onRetry,
|
||||
onDelete,
|
||||
onFeedback,
|
||||
onAddUserDislike,
|
||||
onAddUserLike,
|
||||
ml,
|
||||
mr
|
||||
}: {
|
||||
@@ -1069,8 +1125,10 @@ function ChatController({
|
||||
onRetry?: () => void;
|
||||
onDelete?: () => void;
|
||||
onMark?: () => void;
|
||||
onReadFeedback?: () => void;
|
||||
onFeedback?: () => void;
|
||||
onReadUserDislike?: () => void;
|
||||
onCloseUserLike?: () => void;
|
||||
onAddUserLike?: () => void;
|
||||
onAddUserDislike?: () => void;
|
||||
} & FlexProps) {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
@@ -1184,39 +1242,62 @@ function ChatController({
|
||||
/>
|
||||
</MyTooltip>
|
||||
)}
|
||||
{!!onReadFeedback && (
|
||||
<MyTooltip label={t('chat.Read User Feedback')}>
|
||||
{!!onCloseUserLike && chat.userGoodFeedback && (
|
||||
<MyTooltip label={t('core.chat.feedback.Close User Like')}>
|
||||
<MyIcon
|
||||
{...controlIconStyle}
|
||||
color={'white'}
|
||||
bg={'green.500'}
|
||||
fontWeight={'bold'}
|
||||
name={'core/chat/feedback/goodLight'}
|
||||
onClick={onCloseUserLike}
|
||||
/>
|
||||
</MyTooltip>
|
||||
)}
|
||||
{!!onReadUserDislike && chat.userBadFeedback && (
|
||||
<MyTooltip label={t('core.chat.feedback.Read User dislike')}>
|
||||
<MyIcon
|
||||
display={chat.userFeedback ? 'block' : 'none'}
|
||||
{...controlIconStyle}
|
||||
color={'white'}
|
||||
bg={'#FC9663'}
|
||||
fontWeight={'bold'}
|
||||
name={'core/chat/feedback/badLight'}
|
||||
onClick={onReadFeedback}
|
||||
onClick={onReadUserDislike}
|
||||
/>
|
||||
</MyTooltip>
|
||||
)}
|
||||
{!!onFeedback && (
|
||||
<MyTooltip
|
||||
label={chat.userFeedback ? `取消反馈。\n您当前反馈内容为:\n${chat.userFeedback}` : '反馈'}
|
||||
>
|
||||
<MyIcon
|
||||
{...controlIconStyle}
|
||||
{...(!!chat.userFeedback
|
||||
? {
|
||||
color: 'white',
|
||||
bg: '#FC9663',
|
||||
fontWeight: 'bold',
|
||||
onClick: onFeedback
|
||||
}
|
||||
: {
|
||||
_hover: { color: '#FB7C3C' },
|
||||
onClick: onFeedback
|
||||
})}
|
||||
name={'core/chat/feedback/badLight'}
|
||||
/>
|
||||
</MyTooltip>
|
||||
{!!onAddUserLike && (
|
||||
<MyIcon
|
||||
{...controlIconStyle}
|
||||
{...(!!chat.userGoodFeedback
|
||||
? {
|
||||
color: 'white',
|
||||
bg: 'green.500',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
: {
|
||||
_hover: { color: 'green.600' }
|
||||
})}
|
||||
name={'core/chat/feedback/goodLight'}
|
||||
onClick={onAddUserLike}
|
||||
/>
|
||||
)}
|
||||
{!!onAddUserDislike && (
|
||||
<MyIcon
|
||||
{...controlIconStyle}
|
||||
{...(!!chat.userBadFeedback
|
||||
? {
|
||||
color: 'white',
|
||||
bg: '#FC9663',
|
||||
fontWeight: 'bold',
|
||||
onClick: onAddUserDislike
|
||||
}
|
||||
: {
|
||||
_hover: { color: '#FB7C3C' },
|
||||
onClick: onAddUserDislike
|
||||
})}
|
||||
name={'core/chat/feedback/badLight'}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1702264142648"
|
||||
class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2973"
|
||||
data-spm-anchor-id="a313x.manage_type_myprojects.0.i0.65e73a81QqWlcB" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="128" height="128">
|
||||
<path
|
||||
d="M743.328 985.536l-316.704 0c-12.896 0-23.392-10.368-23.392-23.104s10.496-23.072 23.392-23.072l316.704 0c67.296 0 99.808-36.512 115.168-67.136 0.768-1.856 1.024-3.552 1.408-5.568 2.912-14.624 7.84-39.168 40.192-77.92 23.328-27.968 19.328-57.664 14.624-92.032-1.472-10.912-2.944-21.76-3.552-32.512-2.688-45.856 9.344-65.664 26.048-93.12 3.04-4.928 6.304-10.304 9.792-16.32 15.328-26.432 14.464-59.232-2.304-87.712-20.48-34.816-59.008-55.648-103.008-55.648-77.952 0-167.808 2.656-168.672 2.656-7.776 0.288-13.888-2.72-18.464-8-4.64-5.28-6.528-12.352-5.28-19.2 0.32-1.6 29.664-160.48 29.664-230.304 0-71.616-54.336-79.328-77.632-79.328-36.832 0-66.784 39.2-66.784 87.424 0 59.936 0 80.16-31.68 123.904-43.712 60.352-126.24 161.632-188.416 161.632L275.04 450.176l0 512.224c0 12.768-10.496 23.104-23.392 23.104L117.76 985.504c-49.056 0-88.992-39.392-88.992-87.808L28.768 491.808c0-48.384 39.904-87.776 88.992-87.776l196.704 0c27.84 0 89.696-58.496 150.304-142.272 22.976-31.712 22.976-39.168 22.976-97.088 0-74.944 49.856-133.6 113.536-133.6 57.408 0 124.448 32.896 124.448 125.504 0 56.128-16.8 160.576-25.44 210.656 33.184-0.8 89.856-1.952 141.408-1.952 60.864 0 114.56 29.376 143.488 78.624 25.216 42.88 26.144 92.928 2.464 133.792-3.68 6.336-7.104 11.968-10.272 17.184-15.52 25.472-21.344 35.008-19.488 66.656 0.576 9.568 1.952 19.296 3.232 29.024 5.088 37.408 11.424 83.968-24.896 127.488-24.832 29.792-28.192 46.496-30.432 57.536-1.056 5.28-2.176 10.752-4.928 16.256C870.336 952.544 814.56 985.536 743.328 985.536L743.328 985.536zM117.76 450.208c-23.232 0-42.176 18.656-42.176 41.6l0 405.952c0 22.976 18.944 41.632 42.176 41.632l110.496 0L228.256 450.208 117.76 450.208 117.76 450.208zM117.76 450.208"
|
||||
p-id="2974"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
@@ -78,6 +78,7 @@ const iconPaths = {
|
||||
'support/account/promotionLight': () => import('./icons/support/account/promotionLight.svg'),
|
||||
'core/app/logsLight': () => import('./icons/core/app/logsLight.svg'),
|
||||
'core/chat/feedback/badLight': () => import('./icons/core/chat/feedback/badLight.svg'),
|
||||
'core/chat/feedback/goodLight': () => import('./icons/core/chat/feedback/goodLight.svg'),
|
||||
'core/app/markLight': () => import('./icons/core/app/markLight.svg'),
|
||||
'common/retryLight': () => import('./icons/common/retryLight.svg'),
|
||||
'common/rightArrowLight': () => import('./icons/common/rightArrowLight.svg'),
|
||||
|
@@ -3,7 +3,7 @@ import { Box, Flex, Link } from '@chakra-ui/react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import { useChatStore } from '@/web/core/chat/storeChat';
|
||||
import { HUMAN_ICON } from '@fastgpt/global/core/chat/constants';
|
||||
import { HUMAN_ICON } from '@fastgpt/global/common/system/constants';
|
||||
import { feConfigs } from '@/web/common/system/staticData';
|
||||
import NextLink from 'next/link';
|
||||
import Badge from '../Badge';
|
||||
@@ -175,18 +175,17 @@ const Navbar = ({ unread }: { unread: number }) => {
|
||||
</Link>
|
||||
</Box>
|
||||
)}
|
||||
{feConfigs?.docUrl && (
|
||||
<MyTooltip label={t('home.Docs')} placement={'right-end'}>
|
||||
<Box
|
||||
{(feConfigs?.docUrl || feConfigs?.chatbotUrl) && (
|
||||
<MyTooltip label={t('common.system.Use Helper')} placement={'right-end'}>
|
||||
<Link
|
||||
{...itemStyles}
|
||||
href={feConfigs?.chatbotUrl || getDocPath('/docs/intro')}
|
||||
target="_blank"
|
||||
mb={0}
|
||||
color={'#9096a5'}
|
||||
onClick={() => {
|
||||
window.open(getDocPath('/docs/intro'));
|
||||
}}
|
||||
>
|
||||
<MyIcon name={'common/courseLight'} width={'26px'} height={'26px'} />
|
||||
</Box>
|
||||
</Link>
|
||||
</MyTooltip>
|
||||
)}
|
||||
{feConfigs?.show_git && (
|
||||
|
@@ -49,7 +49,7 @@ const QuestionGuide = ({ text }: { text: string }) => {
|
||||
</Box>
|
||||
<Box
|
||||
className="controller"
|
||||
display={['flex', 'none']}
|
||||
display={'none'}
|
||||
pr={2}
|
||||
position={'absolute'}
|
||||
right={0}
|
||||
|
@@ -173,7 +173,6 @@
|
||||
}
|
||||
.markdown ul,
|
||||
.markdown ol {
|
||||
margin-bottom: 0;
|
||||
padding-left: 14px;
|
||||
}
|
||||
.markdown dl {
|
||||
|
@@ -15,7 +15,7 @@ import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { getPreviewPluginModule } from '@/web/core/plugin/api';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { LOGO_ICON } from '@fastgpt/global/core/chat/constants';
|
||||
import { LOGO_ICON } from '@fastgpt/global/common/system/constants';
|
||||
|
||||
type Props = FlowModuleItemType & {
|
||||
children?: React.ReactNode | React.ReactNode[] | string;
|
||||
|
@@ -82,7 +82,7 @@ const InviteModal = ({
|
||||
>
|
||||
<ModalCloseButton onClick={onClose} />
|
||||
<ModalBody>
|
||||
<Box mb={2}>{t('common.Username')}</Box>
|
||||
<Box mb={2}>{t('user.Account')}</Box>
|
||||
<TagTextarea defaultValues={inviteUsernames} onUpdate={setInviteUsernames} />
|
||||
<Box mt={4}>
|
||||
<MySelect list={inviteTypes} value={selectedInviteType} onchange={setSelectInviteType} />
|
||||
|
@@ -1,8 +1,3 @@
|
||||
export enum UserAuthTypeEnum {
|
||||
register = 'register',
|
||||
findPassword = 'findPassword'
|
||||
}
|
||||
|
||||
export enum TrackEventName {
|
||||
windowError = 'windowError',
|
||||
pageError = 'pageError',
|
||||
|
@@ -1,9 +1,8 @@
|
||||
export const Prompt_AgentQA = {
|
||||
description: `<context></context> 标记中是一段文本,学习它们,并整理学习成果。
|
||||
|
||||
学习要求:
|
||||
description: `<context></context> 标记中是一段文本,学习和分析它,并整理学习成果:
|
||||
- 提出问题并给出每个问题的答案。
|
||||
- 答案需详细完整,给出相关原文描述。答案可以包含普通文字、链接、代码、表格、公示、媒体链接等 markdown 元素。
|
||||
- 答案需详细完整,给出相关原文描述。
|
||||
- 答案可以包含普通文字、链接、代码、表格、公示、媒体链接等 markdown 元素。
|
||||
- 最多提出 30 个问题。
|
||||
`,
|
||||
fixedText: `最后,你需要按下面的格式返回多个问题和答案:
|
||||
|
@@ -7,7 +7,8 @@ import {
|
||||
useTheme,
|
||||
Divider,
|
||||
Select,
|
||||
Input
|
||||
Input,
|
||||
Link
|
||||
} from '@chakra-ui/react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { UserUpdateParams } from '@/types/user';
|
||||
@@ -249,32 +250,52 @@ const UserInfo = () => {
|
||||
</Flex>
|
||||
</Box>
|
||||
{feConfigs?.docUrl && (
|
||||
<>
|
||||
<Flex
|
||||
mt={4}
|
||||
w={['85%', '300px']}
|
||||
py={3}
|
||||
px={6}
|
||||
border={theme.borders.sm}
|
||||
borderWidth={'1.5px'}
|
||||
borderRadius={'md'}
|
||||
alignItems={'center'}
|
||||
cursor={'pointer'}
|
||||
userSelect={'none'}
|
||||
onClick={() => {
|
||||
window.open(getDocPath('/docs/intro'));
|
||||
}}
|
||||
>
|
||||
<MyIcon name={'common/courseLight'} w={'18px'} />
|
||||
<Box ml={2} flex={1}>
|
||||
{t('system.Help Document')}
|
||||
</Box>
|
||||
<Box w={'8px'} h={'8px'} borderRadius={'50%'} bg={'#67c13b'} />
|
||||
<Box fontSize={'md'} ml={2}>
|
||||
V{systemVersion}
|
||||
</Box>
|
||||
</Flex>
|
||||
</>
|
||||
<Link
|
||||
href={getDocPath('/docs/intro')}
|
||||
target="_blank"
|
||||
display={'flex'}
|
||||
mt={4}
|
||||
w={['85%', '300px']}
|
||||
py={3}
|
||||
px={6}
|
||||
border={theme.borders.sm}
|
||||
borderWidth={'1.5px'}
|
||||
borderRadius={'md'}
|
||||
alignItems={'center'}
|
||||
userSelect={'none'}
|
||||
textDecoration={'none !important'}
|
||||
>
|
||||
<MyIcon name={'common/courseLight'} w={'18px'} />
|
||||
<Box ml={2} flex={1}>
|
||||
{t('system.Help Document')}
|
||||
</Box>
|
||||
<Box w={'8px'} h={'8px'} borderRadius={'50%'} bg={'#67c13b'} />
|
||||
<Box fontSize={'md'} ml={2}>
|
||||
V{systemVersion}
|
||||
</Box>
|
||||
</Link>
|
||||
)}
|
||||
{feConfigs?.chatbotUrl && (
|
||||
<Link
|
||||
href={feConfigs.chatbotUrl}
|
||||
target="_blank"
|
||||
display={'flex'}
|
||||
mt={4}
|
||||
w={['85%', '300px']}
|
||||
py={3}
|
||||
px={6}
|
||||
border={theme.borders.sm}
|
||||
borderWidth={'1.5px'}
|
||||
borderRadius={'md'}
|
||||
alignItems={'center'}
|
||||
userSelect={'none'}
|
||||
textDecoration={'none !important'}
|
||||
>
|
||||
<MyIcon name={'core/app/aiLight'} w={'18px'} />
|
||||
<Box ml={2} flex={1}>
|
||||
{t('common.system.Help Chatbot')}
|
||||
</Box>
|
||||
</Link>
|
||||
)}
|
||||
{feConfigs?.show_openai_account && (
|
||||
<>
|
||||
@@ -283,7 +304,7 @@ const UserInfo = () => {
|
||||
<MyTooltip label={'点击配置账号'}>
|
||||
<Flex
|
||||
w={['85%', '300px']}
|
||||
py={3}
|
||||
py={4}
|
||||
px={6}
|
||||
border={theme.borders.sm}
|
||||
borderWidth={'1.5px'}
|
||||
|
45
projects/app/src/pages/api/admin/init464.ts
Normal file
45
projects/app/src/pages/api/admin/init464.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
|
||||
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
||||
import { PgClient } from '@fastgpt/service/common/pg';
|
||||
import { PgDatasetTableName } from '@fastgpt/global/core/dataset/constant';
|
||||
import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
const { limit = 50, maxSize = 3 } = req.body as { limit: number; maxSize: number };
|
||||
await authCert({ req, authRoot: true });
|
||||
await connectToDatabase();
|
||||
|
||||
try {
|
||||
await PgClient.query(
|
||||
`ALTER TABLE ${PgDatasetTableName} ADD COLUMN createTime TIMESTAMP DEFAULT CURRENT_TIMESTAMP;`
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await MongoChatItem.updateMany(
|
||||
{ userFeedback: { $exists: true } },
|
||||
{ $rename: { userFeedback: 'userBadFeedback' } }
|
||||
);
|
||||
console.log(result);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
jsonRes(res, {
|
||||
data: {}
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
jsonRes(res, {
|
||||
code: 500,
|
||||
error
|
||||
});
|
||||
}
|
||||
}
|
@@ -6,7 +6,7 @@ import {
|
||||
delFileByFileIdList,
|
||||
getGFSCollection
|
||||
} from '@fastgpt/service/common/file/gridfs/controller';
|
||||
import { addLog } from '@fastgpt/service/common/mongo/controller';
|
||||
import { addLog } from '@fastgpt/service/common/system/log';
|
||||
import { MongoDatasetCollection } from '@fastgpt/service/core/dataset/collection/schema';
|
||||
import { delay } from '@fastgpt/global/common/system/utils';
|
||||
|
||||
|
@@ -379,14 +379,14 @@ function datasetTemplate({
|
||||
},
|
||||
{
|
||||
key: 'similarity',
|
||||
value: 0.4,
|
||||
value: 0.1,
|
||||
type: FlowNodeInputTypeEnum.slider,
|
||||
label: '相关度',
|
||||
connected: true
|
||||
},
|
||||
{
|
||||
key: 'limit',
|
||||
value: 8,
|
||||
value: 2000,
|
||||
type: FlowNodeInputTypeEnum.slider,
|
||||
label: '单次搜索上限',
|
||||
connected: true
|
||||
|
@@ -60,12 +60,30 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
},
|
||||
{
|
||||
$addFields: {
|
||||
feedbackCount: {
|
||||
userGoodFeedbackCount: {
|
||||
$size: {
|
||||
$filter: {
|
||||
input: '$chatitems',
|
||||
as: 'item',
|
||||
cond: { $ifNull: ['$$item.userFeedback', false] }
|
||||
cond: { $ifNull: ['$$item.userGoodFeedback', false] }
|
||||
}
|
||||
}
|
||||
},
|
||||
userBadFeedbackCount: {
|
||||
$size: {
|
||||
$filter: {
|
||||
input: '$chatitems',
|
||||
as: 'item',
|
||||
cond: { $ifNull: ['$$item.userBadFeedback', false] }
|
||||
}
|
||||
}
|
||||
},
|
||||
robotBadFeedbackCount: {
|
||||
$size: {
|
||||
$filter: {
|
||||
input: '$chatitems',
|
||||
as: 'item',
|
||||
cond: { $ifNull: ['$$item.robotBadFeedback', false] }
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -80,7 +98,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
}
|
||||
}
|
||||
},
|
||||
{ $sort: { feedbackCount: -1, updateTime: -1 } },
|
||||
{
|
||||
$sort: {
|
||||
userBadFeedbackCount: -1,
|
||||
userGoodFeedbackCount: -1,
|
||||
robotBadFeedbackCount: -1,
|
||||
updateTime: -1
|
||||
}
|
||||
},
|
||||
{ $skip: (pageNum - 1) * pageSize },
|
||||
{ $limit: pageSize },
|
||||
{
|
||||
@@ -91,7 +116,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
source: 1,
|
||||
time: '$updateTime',
|
||||
messageCount: { $size: '$chatitems' },
|
||||
feedbackCount: 1,
|
||||
userGoodFeedbackCount: 1,
|
||||
userBadFeedbackCount: 1,
|
||||
robotBadFeedbackCount: 1,
|
||||
markCount: 1
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,52 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema';
|
||||
import { UpdateChatFeedbackProps } from '@fastgpt/global/core/chat/api';
|
||||
import { autChatCrud } from '@/service/support/permission/auth/chat';
|
||||
|
||||
/* 初始化我的聊天框,需要身份验证 */
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { chatId, chatItemId, shareId, outLinkUid, userBadFeedback, userGoodFeedback } =
|
||||
req.body as UpdateChatFeedbackProps;
|
||||
|
||||
try {
|
||||
await connectToDatabase();
|
||||
|
||||
await autChatCrud({
|
||||
req,
|
||||
authToken: true,
|
||||
chatId,
|
||||
shareId,
|
||||
outLinkUid,
|
||||
per: 'r'
|
||||
});
|
||||
|
||||
if (!chatItemId) {
|
||||
throw new Error('chatItemId is required');
|
||||
}
|
||||
|
||||
await MongoChatItem.findOneAndUpdate(
|
||||
{
|
||||
dataId: chatItemId
|
||||
},
|
||||
{
|
||||
$unset: {
|
||||
...(userBadFeedback === undefined && { userBadFeedback: '' }),
|
||||
...(userGoodFeedback === undefined && { userGoodFeedback: '' })
|
||||
},
|
||||
$set: {
|
||||
...(userBadFeedback !== undefined && { userBadFeedback }),
|
||||
...(userGoodFeedback !== undefined && { userGoodFeedback })
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
jsonRes(res);
|
||||
} catch (err) {
|
||||
jsonRes(res, {
|
||||
code: 500,
|
||||
error: err
|
||||
});
|
||||
}
|
||||
}
|
@@ -1,35 +0,0 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema';
|
||||
|
||||
/* 初始化我的聊天框,需要身份验证 */
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
await connectToDatabase();
|
||||
const { chatItemId, userFeedback = undefined } = req.body as {
|
||||
chatItemId: string;
|
||||
userFeedback?: string;
|
||||
};
|
||||
|
||||
if (!chatItemId) {
|
||||
throw new Error('chatItemId is required');
|
||||
}
|
||||
|
||||
await MongoChatItem.findOneAndUpdate(
|
||||
{
|
||||
dataId: chatItemId
|
||||
},
|
||||
{
|
||||
...(userFeedback ? { userFeedback } : { $unset: { userFeedback: '' } })
|
||||
}
|
||||
);
|
||||
|
||||
jsonRes(res);
|
||||
} catch (err) {
|
||||
jsonRes(res, {
|
||||
code: 500,
|
||||
error: err
|
||||
});
|
||||
}
|
||||
}
|
@@ -43,7 +43,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
const { history } = await getChatItems({
|
||||
chatId,
|
||||
limit: 30,
|
||||
field: `dataId obj value adminFeedback userFeedback ${ModuleOutputKeyEnum.responseData}`
|
||||
field: `dataId obj value adminFeedback userBadFeedback userGoodFeedback robotBadFeedback ${ModuleOutputKeyEnum.responseData}`
|
||||
});
|
||||
|
||||
jsonRes<InitChatResponse>(res, {
|
||||
|
@@ -42,7 +42,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
const { history } = await getChatItems({
|
||||
chatId,
|
||||
limit: 30,
|
||||
field: `dataId obj value userFeedback ${
|
||||
field: `dataId obj value userGoodFeedback userBadFeedback ${
|
||||
shareChat.responseDetail ? `adminFeedback ${ModuleOutputKeyEnum.responseData}` : ''
|
||||
} `
|
||||
});
|
||||
|
@@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { MongoUser } from '@fastgpt/service/support/user/schema';
|
||||
import { addLog } from '@fastgpt/service/common/mongo/controller';
|
||||
import { addLog } from '@fastgpt/service/common/system/log';
|
||||
import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
|
||||
import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';
|
||||
import { findDatasetIdTreeByTopDatasetId } from '@fastgpt/service/core/dataset/controller';
|
||||
|
@@ -33,11 +33,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
fileIds: collections.map((item) => item?.fileId || '').filter(Boolean)
|
||||
});
|
||||
|
||||
// delete collection
|
||||
await MongoDatasetCollection.deleteMany({
|
||||
_id: { $in: delIdList }
|
||||
});
|
||||
|
||||
jsonRes(res);
|
||||
} catch (err) {
|
||||
jsonRes(res, {
|
||||
|
@@ -68,13 +68,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
});
|
||||
|
||||
// delete old collection
|
||||
await Promise.all([
|
||||
delCollectionRelevantData({
|
||||
collectionIds: [collection._id],
|
||||
fileIds: collection.fileId ? [collection.fileId] : []
|
||||
}),
|
||||
MongoDatasetCollection.findByIdAndRemove(collection._id)
|
||||
]);
|
||||
await delCollectionRelevantData({
|
||||
collectionIds: [collection._id],
|
||||
fileIds: collection.fileId ? [collection.fileId] : []
|
||||
});
|
||||
|
||||
jsonRes(res);
|
||||
} catch (err) {
|
||||
|
@@ -136,7 +136,7 @@ export async function pushDataToDatasetCollection({
|
||||
model,
|
||||
q: item.q,
|
||||
a: item.a,
|
||||
chunkIndex: i,
|
||||
chunkIndex: item.chunkIndex ?? i,
|
||||
indexes: item.indexes
|
||||
}))
|
||||
);
|
||||
|
@@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes, responseWriteController } from '@fastgpt/service/common/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { MongoUser } from '@fastgpt/service/support/user/schema';
|
||||
import { addLog } from '@fastgpt/service/common/mongo/controller';
|
||||
import { addLog } from '@fastgpt/service/common/system/log';
|
||||
import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
|
||||
import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';
|
||||
import { findDatasetIdTreeByTopDatasetId } from '@fastgpt/service/core/dataset/controller';
|
||||
|
@@ -6,10 +6,8 @@ import { connectToDatabase } from '@/service/mongo';
|
||||
import { authDataset } from '@fastgpt/service/support/permission/auth/dataset';
|
||||
import { authTeamBalance } from '@/service/support/permission/auth/bill';
|
||||
import { pushGenerateVectorBill } from '@/service/support/wallet/bill/push';
|
||||
import { countModelPrice } from '@/service/support/wallet/bill/utils';
|
||||
import { searchDatasetData } from '@/service/core/dataset/data/pg';
|
||||
import { updateApiKeyUsage } from '@fastgpt/service/support/openapi/tools';
|
||||
import { ModelTypeEnum } from '@/service/core/ai/model';
|
||||
import { BillSourceEnum } from '@fastgpt/global/support/wallet/bill/constants';
|
||||
|
||||
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
@@ -38,7 +36,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
const { searchRes, tokenLen } = await searchDatasetData({
|
||||
text,
|
||||
model: dataset.vectorModel,
|
||||
limit: Math.min(limit, 50),
|
||||
limit: Math.min(limit * 800, 30000),
|
||||
datasetIds: [datasetId],
|
||||
searchMode
|
||||
});
|
||||
|
@@ -20,6 +20,7 @@ import {
|
||||
import { SimpleModeTemplate_FastGPT_Universal } from '@/global/core/app/constants';
|
||||
import { getSimpleTemplatesFromPlus } from '@/service/core/app/utils';
|
||||
import { PluginTypeEnum } from '@fastgpt/global/core/plugin/constants';
|
||||
import { getFastGPTFeConfig } from '@fastgpt/service/common/system/config/controller';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
await getInitConfig();
|
||||
@@ -73,7 +74,17 @@ export async function getInitConfig() {
|
||||
process.env.NODE_ENV === 'development' ? 'data/config.local.json' : '/app/data/config.json';
|
||||
const res = JSON.parse(readFileSync(filename, 'utf-8')) as ConfigFileType;
|
||||
|
||||
setDefaultData(res);
|
||||
// get config from database
|
||||
const dbFeConfig = await getFastGPTFeConfig();
|
||||
const concatConfig: ConfigFileType = {
|
||||
...res,
|
||||
FeConfig: {
|
||||
...res.FeConfig,
|
||||
...dbFeConfig
|
||||
}
|
||||
};
|
||||
|
||||
setDefaultData(concatConfig);
|
||||
} catch (error) {
|
||||
setDefaultData();
|
||||
console.log('get init config error, set default', error);
|
||||
@@ -83,6 +94,23 @@ export async function getInitConfig() {
|
||||
getSystemVersion();
|
||||
getModelPrice();
|
||||
getSystemPlugin();
|
||||
|
||||
console.log({
|
||||
FeConfig: global.feConfigs,
|
||||
SystemParams: global.systemEnv,
|
||||
ChatModels: global.chatModels,
|
||||
QAModels: global.qaModels,
|
||||
CQModels: global.cqModels,
|
||||
ExtractModels: global.extractModels,
|
||||
QGModels: global.qgModels,
|
||||
VectorModels: global.vectorModels,
|
||||
ReRankModels: global.reRankModels,
|
||||
AudioSpeechModels: global.reRankModels,
|
||||
WhisperModel: global.whisperModel,
|
||||
price: global.priceMd,
|
||||
simpleModeTemplates: global.simpleModeTemplates,
|
||||
communityPlugins: global.communityPlugins
|
||||
});
|
||||
}
|
||||
|
||||
export function initGlobal() {
|
||||
@@ -125,8 +153,6 @@ export function setDefaultData(res?: ConfigFileType) {
|
||||
global.whisperModel = res?.WhisperModel || defaultWhisperModel;
|
||||
|
||||
global.priceMd = '';
|
||||
|
||||
console.log(res);
|
||||
}
|
||||
|
||||
export function getSystemVersion() {
|
||||
@@ -173,7 +199,6 @@ ${global.audioSpeechModels
|
||||
.join('\n')}
|
||||
${`| 语音输入-${global.whisperModel.name} | ${global.whisperModel.price}/分钟 |`}
|
||||
`;
|
||||
console.log(global.priceMd);
|
||||
}
|
||||
|
||||
async function getSimpleModeTemplates() {
|
||||
@@ -209,8 +234,6 @@ async function getSimpleModeTemplates() {
|
||||
} catch (error) {
|
||||
global.simpleModeTemplates = [SimpleModeTemplate_FastGPT_Universal];
|
||||
}
|
||||
console.log('simple mode templates: ');
|
||||
console.log(global.simpleModeTemplates);
|
||||
}
|
||||
|
||||
function getSystemPlugin() {
|
||||
@@ -236,6 +259,4 @@ function getSystemPlugin() {
|
||||
});
|
||||
|
||||
global.communityPlugins = fileTemplates;
|
||||
console.log('community plugins: ');
|
||||
console.log(fileTemplates);
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ import { createJWT, setCookie } from '@fastgpt/service/support/permission/contro
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { getUserDetail } from '@fastgpt/service/support/user/controller';
|
||||
import type { PostLoginProps } from '@fastgpt/global/support/user/api.d';
|
||||
import { UserStatusEnum } from '@fastgpt/global/support/user/constant';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
@@ -16,13 +17,20 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
}
|
||||
|
||||
// 检测用户是否存在
|
||||
const authCert = await MongoUser.findOne({
|
||||
username
|
||||
});
|
||||
const authCert = await MongoUser.findOne(
|
||||
{
|
||||
username
|
||||
},
|
||||
'status'
|
||||
);
|
||||
if (!authCert) {
|
||||
throw new Error('用户未注册');
|
||||
}
|
||||
|
||||
if (authCert.status === UserStatusEnum.forbidden) {
|
||||
throw new Error('账号已停用,无法登录');
|
||||
}
|
||||
|
||||
const user = await MongoUser.findOne({
|
||||
username,
|
||||
password
|
||||
|
@@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { authApp } from '@fastgpt/service/support/permission/auth/app';
|
||||
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
||||
import { sseErrRes, jsonRes } from '@fastgpt/service/common/response';
|
||||
import { addLog } from '@fastgpt/service/common/mongo/controller';
|
||||
import { addLog } from '@fastgpt/service/common/system/log';
|
||||
import { withNextCors } from '@fastgpt/service/common/middle/cors';
|
||||
import { ChatRoleEnum, ChatSourceEnum } from '@fastgpt/global/core/chat/constants';
|
||||
import { sseResponseEventEnum } from '@fastgpt/service/common/response/constant';
|
||||
|
@@ -18,7 +18,8 @@ import { useTranslation } from 'next-i18next';
|
||||
import { usePagination } from '@/web/common/hooks/usePagination';
|
||||
import { getAppChatLogs } from '@/web/core/app/api';
|
||||
import dayjs from 'dayjs';
|
||||
import { ChatSourceMap, HUMAN_ICON } from '@fastgpt/global/core/chat/constants';
|
||||
import { ChatSourceMap } from '@fastgpt/global/core/chat/constants';
|
||||
import { HUMAN_ICON } from '@fastgpt/global/common/system/constants';
|
||||
import { AppLogsListItemType } from '@/types/app';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import ChatBox, { type ComponentRef } from '@/components/ChatBox';
|
||||
@@ -48,7 +49,8 @@ const Logs = ({ appId }: { appId: string }) => {
|
||||
data: logs,
|
||||
isLoading,
|
||||
Pagination,
|
||||
getData
|
||||
getData,
|
||||
pageNum
|
||||
} = usePagination<AppLogsListItemType>({
|
||||
api: getAppChatLogs,
|
||||
pageSize: 20,
|
||||
@@ -90,8 +92,7 @@ const Logs = ({ appId }: { appId: string }) => {
|
||||
<Table variant={'simple'} fontSize={'sm'}>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th>{t('app.Logs Source')}</Th>
|
||||
<Th>{t('app.Logs Time')}</Th>
|
||||
<Th>{t('core.app.logs.Source And Time')}</Th>
|
||||
<Th>{t('app.Logs Title')}</Th>
|
||||
<Th>{t('app.Logs Message Total')}</Th>
|
||||
<Th>{t('app.Feedback Count')}</Th>
|
||||
@@ -107,35 +108,55 @@ const Logs = ({ appId }: { appId: string }) => {
|
||||
title={'点击查看对话详情'}
|
||||
onClick={() => setDetailLogsId(item.id)}
|
||||
>
|
||||
<Td>{t(ChatSourceMap[item.source]?.name || 'UnKnow')}</Td>
|
||||
<Td>{dayjs(item.time).format('YYYY/MM/DD HH:mm')}</Td>
|
||||
<Td>
|
||||
<Box>{t(ChatSourceMap[item.source]?.name || 'UnKnow')}</Box>
|
||||
<Box color={'myGray.500'}>{dayjs(item.time).format('YYYY/MM/DD HH:mm')}</Box>
|
||||
</Td>
|
||||
<Td className="textEllipsis" maxW={'250px'}>
|
||||
{item.title}
|
||||
</Td>
|
||||
<Td>{item.messageCount}</Td>
|
||||
<Td w={'100px'}>
|
||||
{!!item?.feedbackCount ? (
|
||||
<Box display={'inline-block'}>
|
||||
<Flex
|
||||
bg={'#FFF2EC'}
|
||||
{!!item?.userGoodFeedbackCount && (
|
||||
<Flex
|
||||
mb={item?.userGoodFeedbackCount ? 1 : 0}
|
||||
bg={'green.100'}
|
||||
color={'green.600'}
|
||||
px={3}
|
||||
py={1}
|
||||
alignItems={'center'}
|
||||
justifyContent={'center'}
|
||||
borderRadius={'lg'}
|
||||
fontWeight={'bold'}
|
||||
>
|
||||
<MyIcon
|
||||
mr={1}
|
||||
name={'core/chat/feedback/goodLight'}
|
||||
color={'green.600'}
|
||||
w={'14px'}
|
||||
/>
|
||||
{item.userGoodFeedbackCount}
|
||||
</Flex>
|
||||
)}
|
||||
{!!item?.userBadFeedbackCount && (
|
||||
<Flex
|
||||
bg={'#FFF2EC'}
|
||||
color={'#C96330'}
|
||||
px={3}
|
||||
py={1}
|
||||
alignItems={'center'}
|
||||
justifyContent={'center'}
|
||||
borderRadius={'lg'}
|
||||
fontWeight={'bold'}
|
||||
>
|
||||
<MyIcon
|
||||
mr={1}
|
||||
name={'core/chat/feedback/badLight'}
|
||||
color={'#C96330'}
|
||||
px={3}
|
||||
py={1}
|
||||
alignItems={'center'}
|
||||
borderRadius={'lg'}
|
||||
fontWeight={'bold'}
|
||||
>
|
||||
<MyIcon
|
||||
mr={1}
|
||||
name={'core/chat/feedback/badLight'}
|
||||
color={'#C96330'}
|
||||
w={'14px'}
|
||||
/>
|
||||
{item.feedbackCount}
|
||||
</Flex>
|
||||
</Box>
|
||||
) : (
|
||||
<>-</>
|
||||
w={'14px'}
|
||||
/>
|
||||
{item.userBadFeedbackCount}
|
||||
</Flex>
|
||||
)}
|
||||
</Td>
|
||||
<Td>{item.markCount}</Td>
|
||||
@@ -168,7 +189,10 @@ const Logs = ({ appId }: { appId: string }) => {
|
||||
<DetailLogsModal
|
||||
appId={appId}
|
||||
chatId={detailLogsId}
|
||||
onClose={() => setDetailLogsId(undefined)}
|
||||
onClose={() => {
|
||||
setDetailLogsId(undefined);
|
||||
getData(pageNum);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<MyModal
|
||||
@@ -297,6 +321,7 @@ function DetailLogsModal({
|
||||
showMarkIcon
|
||||
showVoiceIcon={false}
|
||||
userGuideModule={chat?.app?.userGuideModule}
|
||||
chatId={chatId}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
|
@@ -0,0 +1,9 @@
|
||||
import { OutLinkSchema } from '@fastgpt/global/support/outLink/type';
|
||||
import React from 'react';
|
||||
import MyModal from '@/components/MyModal';
|
||||
|
||||
const EmbModal = ({ share }: { share: OutLinkSchema }) => {
|
||||
return <MyModal isOpen>EmbModal</MyModal>;
|
||||
};
|
||||
|
||||
export default EmbModal;
|
@@ -91,11 +91,10 @@ const Share = ({ appId }: { appId: string }) => {
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th>名称</Th>
|
||||
<Th>金额消耗(¥)</Th>
|
||||
<Th>金额消耗</Th>
|
||||
<Th>返回详情</Th>
|
||||
{feConfigs?.isPlus && (
|
||||
<>
|
||||
<Th>金额限制(¥)</Th>
|
||||
<Th>IP限流(人/分钟)</Th>
|
||||
<Th>过期时间</Th>
|
||||
<Th>身份校验</Th>
|
||||
@@ -109,13 +108,19 @@ const Share = ({ appId }: { appId: string }) => {
|
||||
{shareChatList.map((item) => (
|
||||
<Tr key={item._id}>
|
||||
<Td>{item.name}</Td>
|
||||
<Td>{formatPrice(item.total)}</Td>
|
||||
<Td>
|
||||
{formatPrice(item.total)}
|
||||
{feConfigs?.isPlus
|
||||
? `${
|
||||
item.limit && item.limit.credit > -1
|
||||
? ` / ${item.limit.credit}元`
|
||||
: ' / 无限制'
|
||||
}`
|
||||
: ''}
|
||||
</Td>
|
||||
<Td>{item.responseDetail ? '✔' : '✖'}</Td>
|
||||
{feConfigs?.isPlus && (
|
||||
<>
|
||||
<Td>
|
||||
{item.limit && item.limit.credit > -1 ? `${item.limit.credit}元` : '无限制'}
|
||||
</Td>
|
||||
<Td>{item?.limit?.QPM || '-'}</Td>
|
||||
<Td>
|
||||
{item?.limit?.expiredTime
|
||||
|
@@ -349,6 +349,7 @@ const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
|
||||
onUpdateVariable={(e) => {}}
|
||||
onStartChat={startChat}
|
||||
onDelMessage={(e) => delOneHistoryItem({ ...e, chatId })}
|
||||
chatId={chatId}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
|
@@ -358,6 +358,9 @@ const OutLink = ({
|
||||
onUpdateVariable={(e) => {}}
|
||||
onStartChat={startChat}
|
||||
onDelMessage={(e) => delOneHistoryItem({ ...e, chatId, shareId, outLinkUid })}
|
||||
chatId={chatId}
|
||||
shareId={shareId}
|
||||
outLinkUid={outLinkUid}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
|
@@ -35,7 +35,7 @@ export type FileItemType = {
|
||||
id: string; // fileId / raw Link
|
||||
filename: string;
|
||||
chunks: PushDatasetDataChunkProps[];
|
||||
text: string; // raw text
|
||||
rawText: string; // raw text
|
||||
icon: string;
|
||||
tokens: number; // total tokens
|
||||
type: DatasetCollectionTypeEnum.file | DatasetCollectionTypeEnum.link;
|
||||
@@ -152,7 +152,7 @@ const FileSelect = ({
|
||||
filename: file.name,
|
||||
icon,
|
||||
tokens: filterData.reduce((sum, item) => sum + countPromptTokens(item.q), 0),
|
||||
text: `${header.join(',')}\n${data
|
||||
rawText: `${header.join(',')}\n${data
|
||||
.map((item) => `"${item[0]}","${item[1]}"`)
|
||||
.join('\n')}`,
|
||||
chunks: filterData,
|
||||
@@ -192,7 +192,7 @@ const FileSelect = ({
|
||||
id: nanoid(),
|
||||
filename: file.name,
|
||||
icon,
|
||||
text,
|
||||
rawText: text,
|
||||
tokens: splitRes.tokens,
|
||||
type: DatasetCollectionTypeEnum.file,
|
||||
fileId,
|
||||
@@ -228,7 +228,7 @@ const FileSelect = ({
|
||||
id: nanoid(),
|
||||
filename: url,
|
||||
icon: '/imgs/files/link.svg',
|
||||
text: content,
|
||||
rawText: content,
|
||||
tokens: splitRes.tokens,
|
||||
type: DatasetCollectionTypeEnum.link,
|
||||
rawLink: url,
|
||||
@@ -270,7 +270,7 @@ const FileSelect = ({
|
||||
id: nanoid(),
|
||||
filename,
|
||||
icon: '/imgs/files/txt.svg',
|
||||
text: content,
|
||||
rawText: content,
|
||||
tokens: splitRes.tokens,
|
||||
type: DatasetCollectionTypeEnum.file,
|
||||
fileId: fileIds[0],
|
||||
|
@@ -49,7 +49,7 @@ const ImportData = ({
|
||||
collectionTrainingType: DatasetCollectionTrainingModeEnum.chunk
|
||||
},
|
||||
[ImportTypeEnum.qa]: {
|
||||
defaultChunkLen: agentModel?.maxContext * 0.6 || 8000,
|
||||
defaultChunkLen: agentModel?.maxContext * 0.55 || 8000,
|
||||
chunkOverlapRatio: 0,
|
||||
unitPrice: agentModel?.price || 3,
|
||||
mode: TrainingModeEnum.qa,
|
||||
|
@@ -13,6 +13,7 @@ import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { postDatasetCollection } from '@/web/core/dataset/api';
|
||||
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
|
||||
import { splitText2Chunks } from '@fastgpt/global/common/string/textSplitter';
|
||||
import { hashStr } from '@fastgpt/global/common/string/tools';
|
||||
import { useToast } from '@/web/common/hooks/useToast';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import {
|
||||
@@ -158,7 +159,9 @@ const Provider = ({
|
||||
fileId: file.fileId,
|
||||
rawLink: file.rawLink,
|
||||
chunkSize: chunkLen,
|
||||
trainingType: collectionTrainingType
|
||||
trainingType: collectionTrainingType,
|
||||
qaPrompt: mode === TrainingModeEnum.qa ? prompt : '',
|
||||
hashRawText: hashStr(file.rawText)
|
||||
});
|
||||
|
||||
// upload data
|
||||
@@ -193,7 +196,7 @@ const Provider = ({
|
||||
setFiles((state) =>
|
||||
state.map((file) => {
|
||||
const splitRes = splitText2Chunks({
|
||||
text: file.text,
|
||||
text: file.rawText,
|
||||
chunkLen,
|
||||
overlapRatio: chunkOverlapRatio
|
||||
});
|
||||
@@ -287,7 +290,7 @@ export const PreviewFileOrChunk = () => {
|
||||
px={[4, 8]}
|
||||
my={4}
|
||||
contentEditable
|
||||
dangerouslySetInnerHTML={{ __html: previewFile.text }}
|
||||
dangerouslySetInnerHTML={{ __html: previewFile.rawText }}
|
||||
fontSize={'sm'}
|
||||
whiteSpace={'pre-wrap'}
|
||||
wordBreak={'break-all'}
|
||||
|
@@ -1,11 +1,13 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import { Box, Button, Input, ModalBody, ModalFooter, Textarea } from '@chakra-ui/react';
|
||||
import { Box, Button, Input, Link, ModalBody, ModalFooter, Textarea } from '@chakra-ui/react';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { postFetchUrls } from '@/web/common/tools/api';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { UrlFetchResponse } from '@fastgpt/global/common/file/api.d';
|
||||
import { getDocPath } from '@/web/common/system/doc';
|
||||
import { feConfigs } from '@/web/common/system/staticData';
|
||||
|
||||
const UrlFetchModal = ({
|
||||
onClose,
|
||||
@@ -68,7 +70,12 @@ const UrlFetchModal = ({
|
||||
<Box mt={4}>
|
||||
<Box fontWeight={'bold'}>
|
||||
{t('core.dataset.website.Selector')}({t('common.choosable')})
|
||||
</Box>{' '}
|
||||
</Box>
|
||||
{feConfigs?.docUrl && (
|
||||
<Link href={getDocPath('/docs/course/websync/#选择器如何使用')} target="_blank">
|
||||
{t('core.dataset.website.Selector Course')}
|
||||
</Link>
|
||||
)}
|
||||
<Input {...register('selector')} placeholder="body .content #document" />
|
||||
</Box>
|
||||
</ModalBody>
|
||||
|
@@ -1,11 +1,13 @@
|
||||
import React from 'react';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { Box, Button, Input, ModalBody, ModalFooter } from '@chakra-ui/react';
|
||||
import { Box, Button, Input, Link, ModalBody, ModalFooter } from '@chakra-ui/react';
|
||||
import { strIsLink } from '@fastgpt/global/common/string/tools';
|
||||
import { useToast } from '@/web/common/hooks/useToast';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useConfirm } from '@/web/common/hooks/useConfirm';
|
||||
import { getDocPath } from '@/web/common/system/doc';
|
||||
import { feConfigs } from '@/web/common/system/staticData';
|
||||
|
||||
type FormType = {
|
||||
url?: string | undefined;
|
||||
@@ -49,6 +51,16 @@ const WebsiteConfigModal = ({
|
||||
<ModalBody>
|
||||
<Box fontSize={'sm'} color={'myGray.600'}>
|
||||
{t('core.dataset.website.Config Description')}
|
||||
{feConfigs?.docUrl && (
|
||||
<Link
|
||||
href={getDocPath('/docs/course/websync')}
|
||||
target="_blank"
|
||||
textDecoration={'underline'}
|
||||
fontWeight={'bold'}
|
||||
>
|
||||
{t('common.course.Read Course')}
|
||||
</Link>
|
||||
)}
|
||||
</Box>
|
||||
<Box mt={2}>
|
||||
<Box>{t('core.dataset.website.Base Url')}</Box>
|
||||
|
@@ -13,15 +13,7 @@ import { jiebaSplit } from '../utils';
|
||||
import { reRankRecall } from '../../ai/rerank';
|
||||
import { countPromptTokens } from '@fastgpt/global/common/string/tiktoken';
|
||||
|
||||
export async function insertData2Pg({
|
||||
mongoDataId,
|
||||
input,
|
||||
model,
|
||||
teamId,
|
||||
tmbId,
|
||||
datasetId,
|
||||
collectionId
|
||||
}: {
|
||||
export async function insertData2Pg(props: {
|
||||
mongoDataId: string;
|
||||
input: string;
|
||||
model: string;
|
||||
@@ -29,42 +21,42 @@ export async function insertData2Pg({
|
||||
tmbId: string;
|
||||
datasetId: string;
|
||||
collectionId: string;
|
||||
}) {
|
||||
let retry = 2;
|
||||
async function insertPg(): Promise<{ insertId: string; vectors: number[][]; tokenLen: number }> {
|
||||
try {
|
||||
// get vector
|
||||
const { vectors, tokenLen } = await getVectorsByText({
|
||||
model,
|
||||
input: [input]
|
||||
});
|
||||
const { rows } = await PgClient.insert(PgDatasetTableName, {
|
||||
values: [
|
||||
[
|
||||
{ key: 'vector', value: `[${vectors[0]}]` },
|
||||
{ key: 'team_id', value: String(teamId) },
|
||||
{ key: 'tmb_id', value: String(tmbId) },
|
||||
{ key: 'dataset_id', value: datasetId },
|
||||
{ key: 'collection_id', value: collectionId },
|
||||
{ key: 'data_id', value: String(mongoDataId) }
|
||||
]
|
||||
retry?: number;
|
||||
}): Promise<{ insertId: string; vectors: number[][]; tokenLen: number }> {
|
||||
const { mongoDataId, input, model, teamId, tmbId, datasetId, collectionId, retry = 3 } = props;
|
||||
try {
|
||||
// get vector
|
||||
const { vectors, tokenLen } = await getVectorsByText({
|
||||
model,
|
||||
input: [input]
|
||||
});
|
||||
const { rows } = await PgClient.insert(PgDatasetTableName, {
|
||||
values: [
|
||||
[
|
||||
{ key: 'vector', value: `[${vectors[0]}]` },
|
||||
{ key: 'team_id', value: String(teamId) },
|
||||
{ key: 'tmb_id', value: String(tmbId) },
|
||||
{ key: 'dataset_id', value: datasetId },
|
||||
{ key: 'collection_id', value: collectionId },
|
||||
{ key: 'data_id', value: String(mongoDataId) }
|
||||
]
|
||||
});
|
||||
return {
|
||||
insertId: rows[0].id,
|
||||
vectors,
|
||||
tokenLen
|
||||
};
|
||||
} catch (error) {
|
||||
if (--retry < 0) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
await delay(500);
|
||||
return insertPg();
|
||||
]
|
||||
});
|
||||
return {
|
||||
insertId: rows[0].id,
|
||||
vectors,
|
||||
tokenLen
|
||||
};
|
||||
} catch (error) {
|
||||
if (retry <= 0) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
await delay(500);
|
||||
return insertData2Pg({
|
||||
...props,
|
||||
retry: retry - 1
|
||||
});
|
||||
}
|
||||
|
||||
return insertPg();
|
||||
}
|
||||
|
||||
export async function updatePgDataById({
|
||||
@@ -128,8 +120,9 @@ export async function searchDatasetData(props: SearchProps) {
|
||||
}
|
||||
|
||||
const rerank =
|
||||
searchMode === DatasetSearchModeEnum.embeddingReRank ||
|
||||
searchMode === DatasetSearchModeEnum.embFullTextReRank;
|
||||
global.reRankModels?.[0] &&
|
||||
(searchMode === DatasetSearchModeEnum.embeddingReRank ||
|
||||
searchMode === DatasetSearchModeEnum.embFullTextReRank);
|
||||
|
||||
const oneChunkToken = 50;
|
||||
const { embeddingLimit, fullTextLimit } = (() => {
|
||||
@@ -188,8 +181,6 @@ export async function searchDatasetData(props: SearchProps) {
|
||||
return true;
|
||||
});
|
||||
|
||||
// token slice
|
||||
|
||||
if (!rerank) {
|
||||
return {
|
||||
searchRes: filterResultsByMaxTokens(
|
||||
@@ -264,7 +255,7 @@ export async function embeddingRecall({
|
||||
{
|
||||
_id: { $in: filterRows.map((item) => item.data_id?.trim()) }
|
||||
},
|
||||
'datasetId collectionId q a indexes'
|
||||
'datasetId collectionId q a chunkIndex indexes'
|
||||
).lean()
|
||||
]);
|
||||
const formatResult = filterRows
|
||||
@@ -281,6 +272,7 @@ export async function embeddingRecall({
|
||||
id: String(data._id),
|
||||
q: data.q,
|
||||
a: data.a,
|
||||
chunkIndex: data.chunkIndex,
|
||||
indexes: data.indexes,
|
||||
datasetId: String(data.datasetId),
|
||||
collectionId: String(data.collectionId),
|
||||
@@ -322,7 +314,8 @@ export async function fullTextRecall({ text, limit, datasetIds = [] }: SearchPro
|
||||
collectionId: 1,
|
||||
q: 1,
|
||||
a: 1,
|
||||
indexes: 1
|
||||
indexes: 1,
|
||||
chunkIndex: 1
|
||||
}
|
||||
)
|
||||
.sort({ score: { $meta: 'textScore' } })
|
||||
@@ -354,6 +347,7 @@ export async function fullTextRecall({ text, limit, datasetIds = [] }: SearchPro
|
||||
sourceId: collection?.fileId || collection?.rawLink,
|
||||
q: item.q,
|
||||
a: item.a,
|
||||
chunkIndex: item.chunkIndex,
|
||||
indexes: item.indexes,
|
||||
// @ts-ignore
|
||||
score: item.score
|
||||
@@ -395,8 +389,6 @@ export async function reRankSearchResult({
|
||||
|
||||
return mergeResult;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
@@ -4,7 +4,7 @@ import { DatasetDataIndexTypeEnum, TrainingModeEnum } from '@fastgpt/global/core
|
||||
import { sendOneInform } from '../support/user/inform/api';
|
||||
import { getAIApi } from '@fastgpt/service/core/ai/config';
|
||||
import type { ChatMessageItemType } from '@fastgpt/global/core/ai/type.d';
|
||||
import { addLog } from '@fastgpt/service/common/mongo/controller';
|
||||
import { addLog } from '@fastgpt/service/common/system/log';
|
||||
import { splitText2Chunks } from '@fastgpt/global/common/string/textSplitter';
|
||||
import { replaceVariable } from '@fastgpt/global/common/string/tools';
|
||||
import { Prompt_AgentQA } from '@/global/core/prompt/agent';
|
||||
@@ -56,6 +56,7 @@ export async function generateQA(): Promise<any> {
|
||||
collectionId: 1,
|
||||
q: 1,
|
||||
model: 1,
|
||||
chunkIndex: 1,
|
||||
billId: 1,
|
||||
prompt: 1
|
||||
})
|
||||
@@ -130,7 +131,7 @@ ${replaceVariable(Prompt_AgentQA.fixedText, { text })}`;
|
||||
const ai = getAIApi(undefined, 600000);
|
||||
const chatResponse = await ai.chat.completions.create({
|
||||
model,
|
||||
temperature: 0.01,
|
||||
temperature: 0.3,
|
||||
messages,
|
||||
stream: false
|
||||
});
|
||||
@@ -144,7 +145,10 @@ ${replaceVariable(Prompt_AgentQA.fixedText, { text })}`;
|
||||
teamId: data.teamId,
|
||||
tmbId: data.tmbId,
|
||||
collectionId: data.collectionId,
|
||||
data: qaArr,
|
||||
data: qaArr.map((item) => ({
|
||||
...item,
|
||||
chunkIndex: data.chunkIndex
|
||||
})),
|
||||
mode: TrainingModeEnum.chunk,
|
||||
billId: data.billId
|
||||
});
|
||||
|
@@ -2,7 +2,7 @@ import { insertData2Dataset } from '@/service/core/dataset/data/controller';
|
||||
import { MongoDatasetTraining } from '@fastgpt/service/core/dataset/training/schema';
|
||||
import { TrainingModeEnum } from '@fastgpt/global/core/dataset/constant';
|
||||
import { sendOneInform } from '../support/user/inform/api';
|
||||
import { addLog } from '@fastgpt/service/common/mongo/controller';
|
||||
import { addLog } from '@fastgpt/service/common/system/log';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { authTeamBalance } from '@/service/support/permission/auth/bill';
|
||||
import { pushGenerateVectorBill } from '@/service/support/wallet/bill/push';
|
||||
|
@@ -223,6 +223,7 @@ function filterQuote({
|
||||
score: item.score?.toFixed(4)
|
||||
});
|
||||
}
|
||||
|
||||
const sliceResult = sliceMessagesTB({
|
||||
maxTokens: model.quoteMaxToken,
|
||||
messages: quoteQA.map((item, index) => ({
|
||||
@@ -234,13 +235,30 @@ function filterQuote({
|
||||
// slice filterSearch
|
||||
const filterQuoteQA = quoteQA.slice(0, sliceResult.length);
|
||||
|
||||
// filterQuoteQA按collectionId聚合在一起后,再按chunkIndex从小到大排序
|
||||
const sortQuoteQAMap: Record<string, SearchDataResponseItemType[]> = {};
|
||||
filterQuoteQA.forEach((item) => {
|
||||
if (sortQuoteQAMap[item.collectionId]) {
|
||||
sortQuoteQAMap[item.collectionId].push(item);
|
||||
} else {
|
||||
sortQuoteQAMap[item.collectionId] = [item];
|
||||
}
|
||||
});
|
||||
const sortQuoteQAList = Object.values(sortQuoteQAMap).flat();
|
||||
sortQuoteQAList.sort((a, b) => {
|
||||
if (a.collectionId === b.collectionId) {
|
||||
return a.chunkIndex - b.chunkIndex;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
const quoteText =
|
||||
filterQuoteQA.length > 0
|
||||
? `${filterQuoteQA.map((item, index) => getValue(item, index)).join('\n')}`
|
||||
: '';
|
||||
|
||||
return {
|
||||
filterQuoteQA,
|
||||
filterQuoteQA: sortQuoteQAList,
|
||||
quoteText
|
||||
};
|
||||
}
|
||||
|
@@ -45,9 +45,16 @@ export async function autChatCrud({
|
||||
}
|
||||
|
||||
// req auth
|
||||
const { tmbId, role } = await authUserRole(props);
|
||||
const { teamId, tmbId, role } = await authUserRole(props);
|
||||
|
||||
if (String(teamId) !== String(chat.teamId)) return Promise.reject(ChatErrEnum.unAuthChat);
|
||||
|
||||
if (role === TeamMemberRoleEnum.owner) return { uid: outLinkUid };
|
||||
if (String(tmbId) === String(chat.tmbId)) return { uid: outLinkUid };
|
||||
|
||||
// admin
|
||||
if (per === 'r' && role === TeamMemberRoleEnum.admin) return { uid: outLinkUid };
|
||||
|
||||
return Promise.reject(ChatErrEnum.unAuthChat);
|
||||
})();
|
||||
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { DatasetDataItemType, DatasetDataSchemaType } from '@fastgpt/global/core/dataset/type';
|
||||
import { AuthResponseType } from '@fastgpt/global/support/permission/type';
|
||||
import { DatasetDataItemType } from '@fastgpt/global/core/dataset/type';
|
||||
import { MongoDatasetData } from '@fastgpt/service/core/dataset/data/schema';
|
||||
import { authDatasetCollection } from '@fastgpt/service/support/permission/auth/dataset';
|
||||
import { AuthModeType } from '@fastgpt/service/support/permission/type';
|
||||
@@ -27,6 +26,7 @@ export async function authDatasetData({
|
||||
id: String(datasetData._id),
|
||||
q: datasetData.q,
|
||||
a: datasetData.a,
|
||||
chunkIndex: datasetData.chunkIndex,
|
||||
indexes: datasetData.indexes,
|
||||
datasetId: String(datasetData.datasetId),
|
||||
collectionId: String(datasetData.collectionId),
|
||||
|
@@ -2,7 +2,7 @@ import { BillSourceEnum, PRICE_SCALE } from '@fastgpt/global/support/wallet/bill
|
||||
import { getAudioSpeechModel, getQAModel } from '@/service/core/ai/model';
|
||||
import type { ChatHistoryItemResType } from '@fastgpt/global/core/chat/type.d';
|
||||
import { formatPrice } from '@fastgpt/global/support/wallet/bill/tools';
|
||||
import { addLog } from '@fastgpt/service/common/mongo/controller';
|
||||
import { addLog } from '@fastgpt/service/common/system/log';
|
||||
import type { ConcatBillProps, CreateBillProps } from '@fastgpt/global/support/wallet/bill/api.d';
|
||||
import { defaultQGModels } from '@fastgpt/global/core/ai/model';
|
||||
import { POST } from '@fastgpt/service/common/api/plusRequest';
|
||||
|
@@ -3,7 +3,7 @@ import { MongoApp } from '@fastgpt/service/core/app/schema';
|
||||
import { ChatSourceEnum } from '@fastgpt/global/core/chat/constants';
|
||||
import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema';
|
||||
import { MongoChat } from '@fastgpt/service/core/chat/chatSchema';
|
||||
import { addLog } from '@fastgpt/service/common/mongo/controller';
|
||||
import { addLog } from '@fastgpt/service/common/system/log';
|
||||
import { chatContentReplaceBlock } from '@fastgpt/global/core/chat/utils';
|
||||
|
||||
type Props = {
|
||||
|
4
projects/app/src/types/app.d.ts
vendored
4
projects/app/src/types/app.d.ts
vendored
@@ -59,6 +59,8 @@ export type AppLogsListItemType = {
|
||||
time: Date;
|
||||
title: string;
|
||||
messageCount: number;
|
||||
feedbackCount: number;
|
||||
userGoodFeedbackCount: number;
|
||||
userBadFeedbackCount: number;
|
||||
robotBadFeedbackCount: number;
|
||||
markCount: number;
|
||||
};
|
||||
|
@@ -99,10 +99,14 @@ function responseError(err: any) {
|
||||
// 有报错响应
|
||||
if (err?.code in TOKEN_ERROR_CODE) {
|
||||
clearToken();
|
||||
window.location.replace(
|
||||
`/login?lastRoute=${encodeURIComponent(location.pathname + location.search)}`
|
||||
);
|
||||
return Promise.reject({ message: 'token过期,重新登录' });
|
||||
|
||||
if (window.location.pathname !== '/chat/share') {
|
||||
window.location.replace(
|
||||
`/login?lastRoute=${encodeURIComponent(location.pathname + location.search)}`
|
||||
);
|
||||
}
|
||||
|
||||
return Promise.reject({ message: '无权操作' });
|
||||
}
|
||||
if (err?.response?.data) {
|
||||
return Promise.reject(err?.response?.data);
|
||||
|
@@ -13,6 +13,7 @@ import type {
|
||||
DeleteChatItemProps,
|
||||
UpdateHistoryProps
|
||||
} from '@/global/core/chat/api.d';
|
||||
import { UpdateChatFeedbackProps } from '@fastgpt/global/core/chat/api';
|
||||
|
||||
/**
|
||||
* 获取初始化聊天内容
|
||||
@@ -49,8 +50,8 @@ export const delChatRecordById = (data: DeleteChatItemProps) =>
|
||||
*/
|
||||
export const putChatHistory = (data: UpdateHistoryProps) => PUT('/core/chat/updateHistory', data);
|
||||
|
||||
export const userUpdateChatFeedback = (data: { chatItemId: string; userFeedback?: string }) =>
|
||||
POST('/core/chat/feedback/userUpdate', data);
|
||||
export const updateChatUserFeedback = (data: UpdateChatFeedbackProps) =>
|
||||
POST('/core/chat/feedback/updateUserFeedback', data);
|
||||
|
||||
export const adminUpdateChatFeedback = (data: AdminUpdateFeedbackParams) =>
|
||||
export const updateChatAdminFeedback = (data: AdminUpdateFeedbackParams) =>
|
||||
POST('/core/chat/feedback/adminUpdate', data);
|
||||
|
@@ -31,6 +31,12 @@ export async function chunksUpload({
|
||||
});
|
||||
}
|
||||
|
||||
// add chunk index
|
||||
chunks = chunks.map((chunk, i) => ({
|
||||
...chunk,
|
||||
chunkIndex: i
|
||||
}));
|
||||
|
||||
let successInsert = 0;
|
||||
let retryTimes = 10;
|
||||
for (let i = 0; i < chunks.length; i += rate) {
|
||||
|
@@ -49,7 +49,7 @@ export const FlowValueTypeMap = {
|
||||
example: `{
|
||||
obj: System | Human | AI;
|
||||
value: string;
|
||||
}`
|
||||
}[]`
|
||||
},
|
||||
[ModuleDataTypeEnum.datasetQuote]: {
|
||||
label: 'core.module.valueType.datasetQuote',
|
||||
@@ -62,7 +62,7 @@ export const FlowValueTypeMap = {
|
||||
sourceId?: string;
|
||||
q: string;
|
||||
a: string
|
||||
}`
|
||||
}[]`
|
||||
},
|
||||
[ModuleDataTypeEnum.any]: {
|
||||
label: 'core.module.valueType.any',
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { GET, POST, PUT } from '@/web/common/api/request';
|
||||
import { hashStr } from '@fastgpt/global/common/string/tools';
|
||||
import type { ResLogin } from '@/global/support/api/userRes.d';
|
||||
import { UserAuthTypeEnum } from '@/constants/common';
|
||||
import { UserAuthTypeEnum } from '@fastgpt/global/support/user/constant';
|
||||
import { UserUpdateParams } from '@/types/user';
|
||||
import { UserType } from '@fastgpt/global/support/user/type.d';
|
||||
import type {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { useState, useMemo, useCallback } from 'react';
|
||||
import { sendAuthCode } from '@/web/support/user/api';
|
||||
import { UserAuthTypeEnum } from '@/constants/common';
|
||||
import { UserAuthTypeEnum } from '@fastgpt/global/support/user/constant';
|
||||
import { useToast } from '@/web/common/hooks/useToast';
|
||||
import { feConfigs } from '@/web/common/system/staticData';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
|
Reference in New Issue
Block a user