This commit is contained in:
Archer
2023-12-18 16:24:50 +08:00
committed by GitHub
parent d33c99f564
commit 703583fff7
130 changed files with 3418 additions and 2579 deletions

View File

@@ -6,10 +6,10 @@
module.exports = {
i18n: {
defaultLocale: 'zh',
locales: ['en', 'zh', 'zh-Hans', 'zh-CN'],
localeDetection: false
locales: ['en', 'zh'],
localeDetection: true
},
localePath:
typeof window === 'undefined' ? require('path').resolve('./public/locales') : '/locales',
typeof window === 'undefined' ? require('path').resolve('./public/locales') : '/public/locales',
reloadOnPrerender: process.env.NODE_ENV === 'development'
};

View File

@@ -45,7 +45,7 @@ const nextConfig = {
},
transpilePackages: ['@fastgpt/*'],
experimental: {
serverComponentsExternalPackages: ['mongoose', 'winston', 'winston-mongodb', 'pg'],
serverComponentsExternalPackages: ['mongoose', 'pg'],
outputFileTracingRoot: path.join(__dirname, '../../')
}
};

View File

@@ -10,12 +10,13 @@
},
"dependencies": {
"@chakra-ui/anatomy": "^2.2.1",
"@chakra-ui/icons": "^2.0.17",
"@chakra-ui/react": "^2.7.0",
"@chakra-ui/icons": "^2.1.1",
"@chakra-ui/next-js": "^2.1.5",
"@chakra-ui/react": "^2.8.1",
"@chakra-ui/styled-system": "^2.9.1",
"@chakra-ui/system": "^2.5.8",
"@emotion/react": "^11.10.6",
"@emotion/styled": "^11.10.6",
"@chakra-ui/system": "^2.6.1",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@fastgpt/plugins": "workspace:*",
"@fastgpt/global": "workspace:*",
"@fastgpt/service": "workspace:*",
@@ -23,33 +24,25 @@
"@node-rs/jieba": "^1.7.2",
"@tanstack/react-query": "^4.24.10",
"@types/nprogress": "^0.2.0",
"axios": "^1.5.1",
"date-fns": "^2.30.0",
"dayjs": "^1.11.7",
"downloadjs": "^1.4.7",
"echarts": "^5.4.1",
"next": "13.5.2",
"echarts-gl": "^2.0.9",
"formidable": "^2.1.1",
"framer-motion": "^9.0.6",
"hyperdown": "^2.4.29",
"i18next": "^22.5.1",
"immer": "^9.0.19",
"jschardet": "^3.0.0",
"jsonwebtoken": "^9.0.2",
"lodash": "^4.17.21",
"mammoth": "^1.6.0",
"mermaid": "^10.2.3",
"multer": "1.4.5-lts.1",
"nanoid": "^4.0.1",
"next": "13.5.2",
"next-i18next": "^13.3.0",
"nprogress": "^0.2.0",
"papaparse": "^5.4.1",
"react": "18.2.0",
"react-day-picker": "^8.7.1",
"react-dom": "18.2.0",
"react-hook-form": "^7.43.1",
"react-i18next": "^12.3.1",
"react-markdown": "^8.0.7",
"react-syntax-highlighter": "^15.5.0",
"reactflow": "^11.7.4",
@@ -59,28 +52,28 @@
"remark-math": "^5.1.1",
"request-ip": "^3.3.0",
"sass": "^1.58.3",
"zustand": "^4.3.5"
"zustand": "^4.3.5",
"i18next": "^22.5.1",
"next-i18next": "^13.3.0",
"react-i18next": "^12.3.1",
"axios": "^1.5.1",
"nanoid": "^4.0.1",
"dayjs": "^1.11.7"
},
"devDependencies": {
"@svgr/webpack": "^6.5.1",
"@types/downloadjs": "^1.4.3",
"@types/formidable": "^2.0.5",
"@types/js-cookie": "^3.0.3",
"@types/jsonwebtoken": "^9.0.3",
"@types/lodash": "^4.14.191",
"@types/multer": "^1.4.10",
"@types/node": "^20.8.5",
"@types/papaparse": "^5.3.7",
"@types/react": "18.0.28",
"@types/react-dom": "18.0.11",
"@types/react": "18.2.0",
"@types/react-dom": "18.2.0",
"@types/react-syntax-highlighter": "^15.5.6",
"@types/request-ip": "^0.0.37",
"eslint": "8.34.0",
"eslint-config-next": "13.1.6",
"typescript": "4.9.5"
},
"engines": {
"node": ">=18.0.0",
"pnpm": ">=8.6.0"
}
}

View File

@@ -0,0 +1 @@
<?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="1702637232008" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6146" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M261.688889 194.218667A67.470222 67.470222 0 1 1 194.218667 261.688889 67.584 67.584 0 0 1 261.688889 194.218667M261.688889 136.533333a125.155556 125.155556 0 1 0 125.155555 125.155556 125.155556 125.155556 0 0 0-125.155555-125.155556zM614.4 444.529778A67.470222 67.470222 0 1 1 547.271111 512a67.584 67.584 0 0 1 67.128889-67.470222M614.4 386.844444a125.155556 125.155556 0 1 0 125.155556 125.155556 125.155556 125.155556 0 0 0-125.155556-125.155556zM408.120889 694.840889A67.470222 67.470222 0 1 1 340.650667 762.311111a67.470222 67.470222 0 0 1 67.470222-67.470222m0-57.685333a125.155556 125.155556 0 1 0 125.155555 125.155555 125.155556 125.155556 0 0 0-125.155555-125.155555z" fill="#1DCCA1" p-id="6147"></path><path d="M489.016889 736.142222h375.011555v52.337778H489.016889zM325.632 788.48h-42.894222C171.804444 788.48 113.777778 711.452444 113.777778 635.335111a143.36 143.36 0 0 1 43.235555-103.651555c30.833778-30.037333 74.296889-45.511111 125.724445-45.511112h242.119111v52.337778H282.737778c-80.554667 0-116.622222 48.810667-116.622222 97.166222s36.522667 100.807111 116.622222 100.807112h42.894222zM743.537778 538.168889h-40.618667v-52.337778h40.618667c78.620444 0 114.346667-51.541333 114.346666-99.555555s-35.384889-98.417778-114.346666-98.417778H337.123556v-52.337778h406.414222C853.333333 235.52 910.222222 311.409778 910.222222 386.844444a147.911111 147.911111 0 0 1-42.780444 104.903112 168.732444 168.732444 0 0 1-123.904 46.421333z" fill="#1DCCA1" p-id="6148"></path><path d="M910.222222 762.311111l-136.533333 102.4V659.911111l136.533333 102.4z" fill="#1DCCA1" p-id="6149"></path></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -247,6 +247,10 @@
"Save and out": "Save out",
"UnSave": "UnSave"
},
"feedback": {
"Custom feedback": "Custom feedback",
"close custom feedback": "Close Feedback"
},
"logs": {
"Source And Time": "Source & Time"
},

View File

@@ -247,6 +247,10 @@
"Save and out": "保存并退出",
"UnSave": "不保存"
},
"feedback": {
"Custom feedback": "自定义反馈",
"close custom feedback": "关闭反馈"
},
"logs": {
"Source And Time": "来源 & 时间"
},

View File

@@ -18,7 +18,8 @@ type pluginType = {
name: string;
avatar: string;
intro: string;
modules: 直接从高级编排导出配置复制过来;
showStatus?: boolean; // 是否需要展示组件运行状态
modules: []; //直接从高级编排导出配置复制过来;
};
```

View File

@@ -0,0 +1,319 @@
{
"author": "FastGPT Team",
"templateType": "other",
"name": "自定义反馈",
"avatar": "/imgs/module/customFeedback.svg",
"intro": "该模块被触发时,会给当前的对话记录增加一条反馈。可用于自动记录对话效果等。",
"showStatus": false,
"modules": [
{
"moduleId": "w90mfp",
"name": "定义插件输入",
"avatar": "/imgs/module/input.png",
"flowType": "pluginInput",
"showStatus": false,
"position": {
"x": 515.1887815471657,
"y": -169.04905809653783
},
"inputs": [
{
"key": "defaultFeedback",
"valueType": "string",
"label": "默认反馈内容",
"type": "textarea",
"required": false,
"description": "",
"edit": true,
"editField": {
"key": true,
"name": true,
"description": true,
"required": true,
"dataType": true,
"inputType": true
},
"connected": true
},
{
"key": "customFeedback",
"valueType": "string",
"label": "自定义反馈内容",
"type": "target",
"required": false,
"description": "",
"edit": true,
"editField": {
"key": true,
"name": true,
"description": true,
"required": true,
"dataType": true,
"inputType": true
},
"connected": true
}
],
"outputs": [
{
"key": "defaultFeedback",
"valueType": "string",
"label": "默认反馈内容",
"type": "source",
"edit": true,
"targets": [
{
"moduleId": "49de3g",
"key": "defaultFeedback"
}
]
},
{
"key": "customFeedback",
"valueType": "string",
"label": "自定义反馈内容",
"type": "source",
"edit": true,
"targets": [
{
"moduleId": "49de3g",
"key": "customFeedback"
}
]
}
]
},
{
"moduleId": "49de3g",
"name": "HTTP模块",
"avatar": "/imgs/module/http.png",
"flowType": "httpRequest",
"showStatus": true,
"position": {
"x": 1086.8929621216014,
"y": -451.7550009773506
},
"inputs": [
{
"key": "switch",
"type": "target",
"label": "core.module.input.label.switch",
"valueType": "any",
"showTargetInApp": true,
"showTargetInPlugin": true,
"connected": false
},
{
"key": "system_httpMethod",
"type": "select",
"valueType": "string",
"label": "core.module.input.label.Http Request Method",
"value": "POST",
"list": [
{
"label": "GET",
"value": "GET"
},
{
"label": "POST",
"value": "POST"
}
],
"required": true,
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false
},
{
"key": "system_httpReqUrl",
"type": "input",
"valueType": "string",
"label": "core.module.input.label.Http Request Url",
"description": "core.module.input.description.Http Request Url",
"placeholder": "https://api.ai.com/getInventory",
"required": false,
"showTargetInApp": false,
"showTargetInPlugin": false,
"value": "/api/plugins/customFeedback",
"connected": false
},
{
"key": "system_httpHeader",
"type": "textarea",
"valueType": "string",
"label": "core.module.input.label.Http Request Header",
"description": "core.module.input.description.Http Request Header",
"placeholder": "core.module.input.description.Http Request Header",
"required": false,
"showTargetInApp": false,
"showTargetInPlugin": false,
"value": "",
"connected": false
},
{
"key": "DYNAMIC_INPUT_KEY",
"type": "target",
"valueType": "any",
"label": "core.module.inputType.dynamicTargetInput",
"description": "core.module.input.description.dynamic input",
"required": false,
"showTargetInApp": false,
"showTargetInPlugin": true,
"hideInApp": true,
"connected": false
},
{
"valueType": "string",
"label": "defaultFeedback",
"type": "target",
"required": true,
"description": "",
"edit": true,
"editField": {
"key": true,
"name": true,
"description": true,
"required": true,
"dataType": true
},
"connected": true,
"key": "defaultFeedback"
},
{
"key": "customFeedback",
"valueType": "string",
"label": "customFeedback",
"type": "target",
"required": true,
"description": "",
"edit": true,
"editField": {
"key": true,
"name": true,
"description": true,
"required": true,
"dataType": true
},
"connected": true
},
{
"key": "system_addInputParam",
"type": "addInputParam",
"valueType": "any",
"label": "",
"required": false,
"showTargetInApp": false,
"showTargetInPlugin": false,
"editField": {
"key": true,
"name": true,
"description": true,
"required": true,
"dataType": true
},
"defaultEditField": {
"label": "",
"key": "",
"description": "",
"inputType": "target",
"valueType": "string",
"required": true
},
"connected": false
}
],
"outputs": [
{
"key": "finish",
"label": "core.module.output.label.running done",
"description": "core.module.output.description.running done",
"valueType": "boolean",
"type": "source",
"targets": []
},
{
"key": "system_addOutputParam",
"type": "addOutputParam",
"valueType": "any",
"label": "",
"targets": [],
"editField": {
"key": true,
"name": true,
"description": true,
"dataType": true
},
"defaultEditField": {
"label": "",
"key": "",
"description": "",
"outputType": "source",
"valueType": "string"
}
},
{
"type": "source",
"valueType": "string",
"label": "response",
"description": "",
"edit": true,
"editField": {
"key": true,
"name": true,
"description": true,
"dataType": true
},
"targets": [
{
"moduleId": "s15f3v",
"key": "text"
}
],
"key": "response"
}
]
},
{
"moduleId": "s15f3v",
"name": "指定回复",
"avatar": "/imgs/module/reply.png",
"flowType": "answerNode",
"position": {
"x": 1705.6337348182756,
"y": -37.53826066726282
},
"inputs": [
{
"key": "switch",
"type": "target",
"label": "core.module.input.label.switch",
"valueType": "any",
"showTargetInApp": true,
"showTargetInPlugin": true,
"connected": false
},
{
"key": "text",
"type": "textarea",
"valueType": "any",
"label": "回复的内容",
"description": "可以使用 \\n 来实现连续换行。\n可以通过外部模块输入实现回复外部模块输入时会覆盖当前填写的内容。\n如传入非字符串类型数据将会自动转成字符串",
"placeholder": "可以使用 \\n 来实现连续换行。\n可以通过外部模块输入实现回复外部模块输入时会覆盖当前填写的内容。\n如传入非字符串类型数据将会自动转成字符串",
"showTargetInApp": true,
"showTargetInPlugin": true,
"connected": true
}
],
"outputs": [
{
"key": "finish",
"label": "core.module.output.label.running done",
"description": "core.module.output.description.running done",
"valueType": "boolean",
"type": "source",
"targets": []
}
]
}
]
}

View File

@@ -4,6 +4,7 @@
"name": "core.module.template.textEditor",
"avatar": "/imgs/module/textEditor.svg",
"intro": "core.module.template.textEditor intro",
"showStatus": false,
"modules": [
{
"moduleId": "w90mfp",

View File

@@ -4,6 +4,7 @@
"name": "core.module.template.TFSwitch",
"avatar": "/imgs/module/tfSwitch.svg",
"intro": "core.module.template.TFSwitch intro",
"showStatus": false,
"modules": [
{
"moduleId": "w90mfp",

View File

@@ -2,7 +2,7 @@ import { useSpeech } from '@/web/common/hooks/useSpeech';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { Box, Flex, Image, Spinner, Textarea } from '@chakra-ui/react';
import React, { useRef, useEffect, useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useTranslation } from 'next-i18next';
import MyTooltip from '../MyTooltip';
import MyIcon from '../Icon';
import styles from './index.module.scss';
@@ -216,7 +216,7 @@ ${images.map((img) => JSON.stringify({ src: img.src })).join('\n')}
pl={5}
alignItems={'center'}
bg={'white'}
color={'myBlue.600'}
color={'blue.500'}
visibility={isSpeaking && isTransCription ? 'visible' : 'hidden'}
>
<Spinner size={'sm'} mr={4} />
@@ -244,7 +244,7 @@ ${images.map((img) => JSON.stringify({ src: img.src })).join('\n')}
alignItems={'center'}
justifyContent={'center'}
rounded={'md'}
color={'myBlue.600'}
color={'blue.500'}
top={0}
left={0}
bottom={0}
@@ -260,7 +260,7 @@ ${images.map((img) => JSON.stringify({ src: img.src })).join('\n')}
h={'16px'}
color={'myGray.700'}
cursor={'pointer'}
_hover={{ color: 'myBlue.600' }}
_hover={{ color: 'blue.500' }}
position={'absolute'}
bg={'white'}
right={'-8px'}
@@ -396,7 +396,7 @@ ${images.map((img) => JSON.stringify({ src: img.src })).join('\n')}
name={isSpeaking ? 'core/chat/stopSpeechFill' : 'core/chat/recordFill'}
width={['20px', '22px']}
height={['20px', '22px']}
color={'myBlue.600'}
color={'blue.500'}
/>
</MyTooltip>
</Flex>
@@ -415,7 +415,7 @@ ${images.map((img) => JSON.stringify({ src: img.src })).join('\n')}
h={['28px', '32px']}
w={['28px', '32px']}
borderRadius={'md'}
bg={isSpeaking || isChatting ? '' : !havInput ? '#E5E5E5' : 'myBlue.600'}
bg={isSpeaking || isChatting ? '' : !havInput ? '#E5E5E5' : 'blue.500'}
cursor={havInput ? 'pointer' : 'not-allowed'}
lineHeight={1}
onClick={() => {

View File

@@ -105,7 +105,7 @@ const QuoteModal = ({
className="hover-data"
display={'none'}
alignItems={'center'}
color={'myBlue.600'}
color={'blue.500'}
href={`/dataset/detail?datasetId=${item.datasetId}&currentTab=dataCard&collectionId=${item.collectionId}`}
>
{t('core.dataset.Go Dataset')}
@@ -164,7 +164,7 @@ const QuoteModal = ({
cursor={'pointer'}
color={'myGray.600'}
_hover={{
color: 'myBlue.700'
color: 'blue.600'
}}
onClick={() => onclickEdit(item)}
/>

View File

@@ -147,7 +147,7 @@ const ResponseTags = ({
name="common/routePushLight"
w={'14px'}
cursor={'pointer'}
_hover={{ color: 'myBlue.600' }}
_hover={{ color: 'blue.500' }}
onClick={async (e) => {
e.stopPropagation();

View File

@@ -35,7 +35,7 @@ const SelectMarkCollection = ({
const theme = useTheme();
const [selectedDatasetId, setSelectedDatasetId] = useState<string>();
const [selectedDatasetCollectionIds, setSelectedDatasetCollectionIds] = useState<string[]>([]);
const { paths, parentId, setParentId, datasets, isFetching } = useDatasetSelect();
const { paths, setParentId, datasets, isFetching } = useDatasetSelect();
return (
<>
@@ -70,7 +70,7 @@ const SelectMarkCollection = ({
}}
{...(selected
? {
bg: 'myBlue.300'
bg: 'blue.200'
}
: {})}
onClick={() => {

View File

@@ -27,7 +27,8 @@ import {
BoxProps,
FlexProps,
Image,
Textarea
Textarea,
Checkbox
} from '@chakra-ui/react';
import { feConfigs } from '@/web/common/system/staticData';
import { EventNameEnum, eventBus } from '@/web/common/utils/eventbus';
@@ -43,7 +44,11 @@ import { useRouter } from 'next/router';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useTranslation } from 'next-i18next';
import { customAlphabet } from 'nanoid';
import { updateChatAdminFeedback, updateChatUserFeedback } from '@/web/core/chat/api';
import {
closeCustomFeedback,
updateChatAdminFeedback,
updateChatUserFeedback
} from '@/web/core/chat/api';
import type { AdminMarkType } from './SelectMarkCollection';
import MyIcon from '@/components/Icon';
@@ -63,6 +68,7 @@ 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 ChatBoxDivider from '../core/chat/Divider';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 24);
@@ -492,7 +498,7 @@ const ChatBox = (
const colorMap = {
loading: 'myGray.700',
running: '#67c13b',
finish: 'myBlue.600'
finish: 'blue.500'
};
if (!isChatting) return;
const chatContent = chatHistory[chatHistory.length - 1];
@@ -660,7 +666,7 @@ const ChatBox = (
<Card
className="markdown"
{...MessageCardStyle}
bg={'myBlue.300'}
bg={'blue.200'}
borderRadius={'8px 0 8px 8px'}
textAlign={'left'}
>
@@ -853,16 +859,56 @@ const ChatBox = (
<ResponseTags responseData={item.responseData} isShare={!!shareId} />
{/* custom feedback */}
{item.customFeedbacks && item.customFeedbacks.length > 0 && (
<Box>
<ChatBoxDivider
icon={'core/app/customFeedback'}
text={t('core.app.feedback.Custom feedback')}
/>
{item.customFeedbacks.map((text, i) => (
<Box key={`${text}${i}`}>
<MyTooltip label={t('core.app.feedback.close custom feedback')}>
<Checkbox
onChange={(e) => {
if (e.target.checked && appId && chatId && item.dataId) {
closeCustomFeedback({
appId,
chatId,
chatItemId: item.dataId,
index: i
});
// update dom
setChatHistory((state) =>
state.map((chatItem) =>
chatItem.dataId === item.dataId
? {
...chatItem,
customFeedbacks: chatItem.customFeedbacks?.filter(
(item, index) => index !== i
)
}
: chatItem
)
);
}
console.log(e);
}}
>
{text}
</Checkbox>
</MyTooltip>
</Box>
))}
</Box>
)}
{/* admin mark content */}
{showMarkIcon && item.adminFeedback && (
<Box>
<Flex alignItems={'center'} py={2}>
<MyIcon name={'core/app/markLight'} w={'14px'} color={'myGray.900'} />
<Box ml={2} color={'myGray.500'}>
{t('chat.Admin Mark Content')}
</Box>
<Box h={'1px'} bg={'myGray.300'} flex={'1'} />
</Flex>
<ChatBoxDivider
icon="core/app/markLight"
text={t('chat.Admin Mark Content')}
/>
<Box whiteSpace={'pre'}>{`${item.adminFeedback.q || ''}${
item.adminFeedback.a ? `\n${item.adminFeedback.a}` : ''
}`}</Box>
@@ -942,7 +988,10 @@ const ChatBox = (
setAdminMarkData={(e) => setAdminMarkData({ ...e, chatItemId: adminMarkData.chatItemId })}
onClose={() => setAdminMarkData(undefined)}
onSuccess={(adminFeedback) => {
if (!appId || !chatId || !adminMarkData.chatItemId) return;
updateChatAdminFeedback({
appId,
chatId,
chatItemId: adminMarkData.chatItemId,
...adminFeedback
});
@@ -1089,7 +1138,7 @@ function ChatAvatar({ src, type }: { src?: string; type: 'Human' | 'AI' }) {
borderRadius={'lg'}
border={theme.borders.base}
boxShadow={'0 0 5px rgba(0,0,0,0.1)'}
bg={type === 'Human' ? 'white' : 'myBlue.100'}
bg={type === 'Human' ? 'white' : 'blue.50'}
>
<Avatar src={src} w={'100%'} h={'100%'} />
</Box>
@@ -1170,7 +1219,7 @@ function ChatController({
<MyIcon
{...controlIconStyle}
name={'copy'}
_hover={{ color: 'myBlue.700' }}
_hover={{ color: 'blue.600' }}
onClick={() => copyData(chat.value)}
/>
</MyTooltip>

View File

@@ -0,0 +1,12 @@
<?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="1702637232008"
class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6146"
xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128">
<path
d="M261.688889 194.218667A67.470222 67.470222 0 1 1 194.218667 261.688889 67.584 67.584 0 0 1 261.688889 194.218667M261.688889 136.533333a125.155556 125.155556 0 1 0 125.155555 125.155556 125.155556 125.155556 0 0 0-125.155555-125.155556zM614.4 444.529778A67.470222 67.470222 0 1 1 547.271111 512a67.584 67.584 0 0 1 67.128889-67.470222M614.4 386.844444a125.155556 125.155556 0 1 0 125.155556 125.155556 125.155556 125.155556 0 0 0-125.155556-125.155556zM408.120889 694.840889A67.470222 67.470222 0 1 1 340.650667 762.311111a67.470222 67.470222 0 0 1 67.470222-67.470222m0-57.685333a125.155556 125.155556 0 1 0 125.155555 125.155555 125.155556 125.155556 0 0 0-125.155555-125.155555z"
fill="#1DCCA1" p-id="6147"></path>
<path
d="M489.016889 736.142222h375.011555v52.337778H489.016889zM325.632 788.48h-42.894222C171.804444 788.48 113.777778 711.452444 113.777778 635.335111a143.36 143.36 0 0 1 43.235555-103.651555c30.833778-30.037333 74.296889-45.511111 125.724445-45.511112h242.119111v52.337778H282.737778c-80.554667 0-116.622222 48.810667-116.622222 97.166222s36.522667 100.807111 116.622222 100.807112h42.894222zM743.537778 538.168889h-40.618667v-52.337778h40.618667c78.620444 0 114.346667-51.541333 114.346666-99.555555s-35.384889-98.417778-114.346666-98.417778H337.123556v-52.337778h406.414222C853.333333 235.52 910.222222 311.409778 910.222222 386.844444a147.911111 147.911111 0 0 1-42.780444 104.903112 168.732444 168.732444 0 0 1-123.904 46.421333z"
fill="#1DCCA1" p-id="6148"></path>
<path d="M910.222222 762.311111l-136.533333 102.4V659.911111l136.533333 102.4z" fill="#1DCCA1" p-id="6149"></path>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -124,7 +124,8 @@ const iconPaths = {
'common/confirm/deleteTip': () => import('./icons/common/confirm/deleteTip.svg'),
'common/confirm/commonTip': () => import('./icons/common/confirm/commonTip.svg'),
'common/routePushLight': () => import('./icons/common/routePushLight.svg'),
'common/viewLight': () => import('./icons/common/viewLight.svg')
'common/viewLight': () => import('./icons/common/viewLight.svg'),
'core/app/customFeedback': () => import('./icons/core/app/customFeedback.svg')
};
export type IconName = keyof typeof iconPaths;

View File

@@ -129,7 +129,7 @@ const Navbar = ({ unread }: { unread: number }) => {
{...itemStyles}
{...(item.activeLink.includes(router.pathname)
? {
color: 'myBlue.700',
color: 'blue.600',
bg: 'white !important',
boxShadow: '1px 1px 10px rgba(0,0,0,0.2)'
}

View File

@@ -25,9 +25,9 @@ const Loading = ({
justifyContent={'center'}
flexDirection={'column'}
>
<Spinner thickness="4px" speed="0.65s" emptyColor="myGray.100" color="myBlue.600" size="xl" />
<Spinner thickness="4px" speed="0.65s" emptyColor="myGray.100" color="blue.500" size="xl" />
{text && (
<Box mt={2} color="myBlue.700" fontWeight={'bold'}>
<Box mt={2} color="blue.600" fontWeight={'bold'}>
{text}
</Box>
)}

View File

@@ -23,7 +23,7 @@ function MyLink(e: any) {
<Box as={'li'} mb={1}>
<Box
as={'span'}
color={'blue.600'}
color={'blue.500'}
textDecoration={'underline'}
cursor={'pointer'}
onClick={() => {

View File

@@ -77,7 +77,7 @@ const QuestionGuide = ({ text }: { text: string }) => {
name={'core/chat/sendLight'}
w={'14px'}
cursor={'pointer'}
_hover={{ color: 'myBlue.600' }}
_hover={{ color: 'blue.500' }}
onClick={() => eventBus.emit(EventNameEnum.sendQuestion, { text })}
/>
</MyTooltip>

View File

@@ -123,7 +123,7 @@ const MermaidBlock = ({ code }: { code: string }) => {
position={'absolute'}
color={'myGray.600'}
_hover={{
color: 'myBlue.700'
color: 'blue.600'
}}
right={0}
top={0}

View File

@@ -1,20 +1,23 @@
.waitingAnimation::after {
.waitingAnimation > :last-child::after {
display: inline-block;
content: '';
width: 4px;
width: 3px;
height: 14px;
transform: translate(4px, 2px) scaleY(1.3);
background-color: var(--chakra-colors-chakra-body-text);
background-color: var(--chakra-colors-blue-700);
animation: blink 0.6s infinite;
}
.animation {
> :last-child::after {
height: 20px;
&::after {
display: inline-block;
content: '';
width: 4px;
width: 3px;
height: 14px;
transform: translate(4px, 2px) scaleY(1.3);
background-color: var(--chakra-colors-chakra-body-text);
background-color: var(--chakra-colors-blue-700);
animation: blink 0.6s infinite;
}
}

View File

@@ -96,10 +96,10 @@ function A({ children, ...props }: any) {
name={'core/chat/quoteSign'}
transform={'translateY(-2px)'}
w={'18px'}
color={'myBlue.600'}
color={'blue.500'}
cursor={'pointer'}
_hover={{
color: 'myBlue.800'
color: 'blue.700'
}}
onClick={() => getFileAndOpen(props.href)}
/>
@@ -131,7 +131,7 @@ const Markdown = ({ source, isChatting = false }: { source: string; isChatting?:
return (
<ReactMarkdown
className={`markdown ${styles.markdown}
${isChatting ? (source === '' ? styles.waitingAnimation : styles.animation) : ''}
${isChatting ? `${formatSource ? styles.waitingAnimation : styles.animation}` : ''}
`}
remarkPlugins={[RemarkGfm, RemarkMath, RemarkBreaks]}
rehypePlugins={[RehypeKatex]}

View File

@@ -41,7 +41,7 @@ const MyMenu = ({ width, offset = [0, 10], Button, menuList }: Props) => {
e.stopPropagation();
item.onClick && item.onClick();
}}
color={item.isActive ? 'myBlue.600' : ''}
color={item.isActive ? 'blue.500' : ''}
whiteSpace={'pre-wrap'}
>
{item.child}

View File

@@ -32,7 +32,7 @@ const PromptTemplate = ({
cursor={'pointer'}
{...(item.title === selectTemplateTitle?.title
? {
bg: 'myBlue.100'
bg: 'blue.50'
}
: {})}
onClick={() => setSelectTemplateTitle(item)}

View File

@@ -62,7 +62,7 @@ const MySelect = (
{...(isOpen
? {
boxShadow: '0px 0px 4px #A8DBFF',
borderColor: 'myBlue.600'
borderColor: 'blue.500'
}
: {})}
{...props}
@@ -93,7 +93,7 @@ const MySelect = (
{...menuItemStyles}
{...(value === item.value
? {
color: 'myBlue.600',
color: 'blue.500',
bg: 'myWhite.300'
}
: {})}

View File

@@ -44,9 +44,9 @@ const SideTabs = ({ list, size = 'md', activeId, onChange, ...props }: Props) =>
alignItems={'center'}
{...(activeId === item.id
? {
bg: ' myBlue.300 !important',
bg: ' blue.200 !important',
fontWeight: 'bold',
color: 'myBlue.700 ',
color: 'blue.600 ',
cursor: 'default'
}
: {

View File

@@ -69,7 +69,7 @@ const MySlider = ({
<SliderMark
value={value}
textAlign="center"
bg="myBlue.600"
bg="blue.500"
color="white"
px={1}
minW={'18px'}
@@ -95,9 +95,9 @@ const MySlider = ({
right: '-3px'
}}
>
<SliderFilledTrack bg={'myBlue.600'} />
<SliderFilledTrack bg={'blue.500'} />
</SliderTrack>
<SliderThumb border={'3px solid'} borderColor={'myBlue.600'}></SliderThumb>
<SliderThumb border={'3px solid'} borderColor={'blue.500'}></SliderThumb>
</Slider>
);
};

View File

@@ -55,10 +55,10 @@ const Tabs = ({ list, size = 'md', activeId, onChange, ...props }: Props) => {
whiteSpace={'nowrap'}
{...(activeId === item.id
? {
color: 'myBlue.700',
color: 'blue.600',
cursor: 'default',
fontWeight: 'bold',
borderBottomColor: 'myBlue.700'
borderBottomColor: 'blue.600'
}
: {
cursor: 'pointer'

View File

@@ -10,9 +10,9 @@ const Tag = ({ children, colorSchema = 'blue', ...props }: Props) => {
const theme = useMemo(() => {
const map = {
blue: {
borderColor: 'myBlue.600',
borderColor: 'blue.500',
bg: '#F2FBFF',
color: 'myBlue.700'
color: 'blue.600'
},
green: {
borderColor: '#67c13b',

View File

@@ -43,13 +43,13 @@ const MyRadio = ({
position={'relative'}
{...(value === item.value
? {
borderColor: 'myBlue.500',
bg: 'myBlue.100'
borderColor: 'blue.400',
bg: 'blue.50'
}
: {
bg: 'myWhite.300',
_hover: {
borderColor: 'myBlue.500'
borderColor: 'blue.400'
}
})}
_after={{
@@ -66,7 +66,7 @@ const MyRadio = ({
...(value === item.value
? {
border: '5px solid',
borderColor: 'myBlue.700'
borderColor: 'blue.600'
}
: {
border: '2px solid',

View File

@@ -52,7 +52,7 @@ const TagTextarea = ({ defaultValues, onUpdate, ...props }: Props) => {
bg={'myWhite.600'}
{...(focus && {
boxShadow: '0px 0px 4px #A8DBFF',
borderColor: 'myBlue.600'
borderColor: 'blue.500'
})}
{...props}
onClick={() => {

View File

@@ -3,8 +3,7 @@ import MyModal from '@/components/MyModal';
import { useQuery } from '@tanstack/react-query';
import React, { Dispatch, useMemo, useState } from 'react';
import { useTranslation } from 'next-i18next';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { Box, Flex } from '@chakra-ui/react';
import { Box } from '@chakra-ui/react';
import ParentPaths from '@/components/common/ParentPaths';
type PathItemType = {
@@ -53,13 +52,12 @@ const DatasetSelectContainer = ({
}
isOpen={isOpen}
onClose={onClose}
h={'80vh'}
w={'100%'}
maxW={['90vw', '900px']}
isCentered
>
<Flex flexDirection={'column'} h={'90vh'}>
<Box flex={'1 0 0'}>{children}</Box>
</Flex>
{children}
</MyModal>
);
};

View File

@@ -66,7 +66,7 @@ const AIChatSettingsModal = ({
fontSize: ['sm', 'md']
};
const selectTemplateBtn: BoxProps = {
color: 'myBlue.600',
color: 'blue.500',
cursor: 'pointer'
};

View File

@@ -82,7 +82,7 @@ export const DatasetSelectModal = ({
p={3}
border={theme.borders.base}
boxShadow={'sm'}
bg={'myBlue.300'}
bg={'blue.200'}
>
<Flex alignItems={'center'} h={'38px'}>
<Avatar src={item.avatar} w={['24px', '28px']}></Avatar>

View File

@@ -12,10 +12,7 @@ import type {
FlowModuleItemType,
FlowModuleTemplateType
} from '@fastgpt/global/core/module/type.d';
import type {
FlowNodeOutputTargetItemType,
FlowNodeChangeProps
} from '@fastgpt/global/core/module/node/type';
import type { FlowNodeChangeProps } from '@fastgpt/global/core/module/node/type';
import React, {
type SetStateAction,
type Dispatch,

View File

@@ -60,7 +60,7 @@ const SelectAppModal = ({
cursor={'pointer'}
{...(selectedApps.includes(app._id)
? {
bg: 'myBlue.200',
bg: 'blue.100',
onClick: () => {
setSelectedApps(selectedApps.filter((e) => e !== app._id));
}

View File

@@ -36,7 +36,7 @@ const ButtonEdge = (
targetPosition
});
const edgeStyle = {
const edgeStyle: React.CSSProperties = {
...style,
...(selected
? {
@@ -63,6 +63,7 @@ const ButtonEdge = (
color={'black'}
cursor={'pointer'}
border={'1px solid #fff'}
zIndex={selected ? 1000 : 0}
_hover={{
boxShadow: '0 0 6px 2px rgba(0, 0, 0, 0.08)'
}}
@@ -71,7 +72,7 @@ const ButtonEdge = (
<MyIcon
name="closeSolid"
w={'100%'}
color={selected ? 'myBlue.800' : 'myGray.500'}
color={selected ? 'blue.700' : 'myGray.500'}
></MyIcon>
</Flex>
</EdgeLabelRenderer>

View File

@@ -65,7 +65,7 @@ const NodePluginInput = ({ data }: NodeProps<FlowModuleItemType>) => {
w={'14px'}
cursor={'pointer'}
mr={3}
_hover={{ color: 'myBlue.600' }}
_hover={{ color: 'blue.500' }}
onClick={() =>
setEditField({
inputType: item.type,

View File

@@ -84,7 +84,7 @@ const NodePluginOutput = ({ data }: NodeProps<FlowModuleItemType>) => {
w={'14px'}
cursor={'pointer'}
ml={3}
_hover={{ color: 'myBlue.600' }}
_hover={{ color: 'blue.500' }}
onClick={() =>
setEditField({
inputType: item.type,

View File

@@ -1,6 +1,6 @@
import { EditNodeFieldType, FlowNodeInputItemType } from '@fastgpt/global/core/module/node/type';
import React, { useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useTranslation } from 'next-i18next';
import {
onChangeNode,
useFlowProviderStore,
@@ -81,7 +81,7 @@ const InputLabel = ({
w={'14px'}
cursor={'pointer'}
ml={3}
_hover={{ color: 'myBlue.600' }}
_hover={{ color: 'blue.500' }}
onClick={() =>
setEditField({
inputType: type,

View File

@@ -41,7 +41,7 @@ const OutputLabel = ({
w={'14px'}
cursor={'pointer'}
mr={3}
_hover={{ color: 'myBlue.600' }}
_hover={{ color: 'blue.500' }}
onClick={() =>
setEditField({
key: outputKey,

View File

@@ -96,8 +96,10 @@ const Container = React.memo(function Container(props: Props) {
minZoom={0.1}
maxZoom={1.5}
defaultEdgeOptions={{
animated: true
animated: true,
zIndex: 0
}}
elevateEdgesOnSelect
connectionLineStyle={{ strokeWidth: 2, stroke: '#5A646Es' }}
nodeTypes={nodeTypes}
edgeTypes={edgeTypes}

View File

@@ -88,7 +88,7 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => {
href={feConfigs.openAPIDocUrl || getDocPath('/docs/development/openapi')}
target={'_blank'}
ml={1}
color={'myBlue.600'}
color={'blue.500'}
>
</Link>

View File

@@ -156,7 +156,7 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
<MyIcon
name={'common/addCircleLight'}
w={['16px', '18px']}
color={'myBlue.600'}
color={'blue.500'}
cursor={'pointer'}
/>
}
@@ -177,7 +177,7 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
gap={3}
{...(userInfo?.team?.teamId === team.teamId
? {
bg: 'myBlue.300'
bg: 'blue.200'
}
: {
_hover: {
@@ -198,7 +198,7 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
{team.teamName}
</Box>
{userInfo?.team?.teamId === team.teamId ? (
<MyIcon name={'common/tickFill'} w={'16px'} color={'myBlue.600'} />
<MyIcon name={'common/tickFill'} w={'16px'} color={'blue.500'} />
) : (
<Button size={'xs'} variant={'base'} onClick={() => onSwitchTeam(team.teamId)}>
{t('user.team.Check Team')}
@@ -235,7 +235,7 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
ml={2}
cursor={'pointer'}
_hover={{
color: 'myBlue.600'
color: 'blue.500'
}}
onClick={() => {
if (!userInfo?.team) return;
@@ -260,7 +260,7 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
size="sm"
borderRadius={'md'}
ml={3}
leftIcon={<MyIcon name={'common/inviteLight'} w={'14px'} color={'myBlue.600'} />}
leftIcon={<MyIcon name={'common/inviteLight'} w={'14px'} color={'blue.500'} />}
onClick={() => {
if (userInfo.team.maxSize <= members.length) {
toast({
@@ -283,11 +283,7 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
borderRadius={'md'}
ml={3}
leftIcon={
<MyIcon
name={'support/account/loginoutLight'}
w={'14px'}
color={'myBlue.600'}
/>
<MyIcon name={'support/account/loginoutLight'} w={'14px'} color={'blue.500'} />
}
onClick={() => {
openLeaveConfirm(() => onLeaveTeam(userInfo?.team?.teamId))();
@@ -339,7 +335,7 @@ const TeamManageModal = ({ onClose }: { onClose: () => void }) => {
name={'edit'}
cursor={'pointer'}
w="14px"
_hover={{ color: 'myBlue.600' }}
_hover={{ color: 'blue.500' }}
/>
</MenuButton>
}

View File

@@ -12,6 +12,7 @@ export type GetChatSpeechProps = {
export type InitChatProps = {
appId?: string;
chatId?: string;
loadCustomFeedbacks?: boolean;
};
export type InitOutLinkChatProps = {
chatId?: string;
@@ -74,5 +75,14 @@ export type DeleteChatItemProps = {
};
export type AdminUpdateFeedbackParams = AdminFbkType & {
appId: string;
chatId: string;
chatItemId: string;
};
export type CloseCustomFeedbackParams = {
appId: string;
chatId: string;
chatItemId: string;
index: number;
};

View File

@@ -288,7 +288,7 @@ async function initPgData() {
const limit = 10;
// add column
try {
await Promise.all([
await Promise.allSettled([
PgClient.query(`ALTER TABLE ${PgDatasetTableName} ADD COLUMN team_id VARCHAR(50);`),
PgClient.query(`ALTER TABLE ${PgDatasetTableName} ADD COLUMN tmb_id VARCHAR(50);`),
PgClient.query(`ALTER TABLE ${PgDatasetTableName} ALTER COLUMN user_id DROP NOT NULL;`)

View File

@@ -2,79 +2,15 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { customAlphabet } from 'nanoid';
import multer from 'multer';
import path from 'path';
import { uploadFile } from '@fastgpt/service/common/file/gridfs/controller';
import { BucketNameEnum } from '@fastgpt/global/common/file/constants';
const nanoid = customAlphabet('1234567890abcdef', 12);
type FileType = {
fieldname: string;
originalname: string;
encoding: string;
mimetype: string;
filename: string;
path: string;
size: number;
};
import { getUploadModel } from '@fastgpt/service/common/file/upload/multer';
/**
* Creates the multer uploader
*/
const maxSize = 500 * 1024 * 1024;
class UploadModel {
uploader = multer({
limits: {
fieldSize: maxSize
},
preservePath: true,
storage: multer.diskStorage({
filename: (_req, file, cb) => {
const { ext } = path.parse(decodeURIComponent(file.originalname));
cb(null, nanoid() + ext);
}
})
}).any();
async doUpload(req: NextApiRequest, res: NextApiResponse) {
return new Promise<{
files: FileType[];
bucketName: `${BucketNameEnum}`;
metadata: Record<string, any>;
}>((resolve, reject) => {
// @ts-ignore
this.uploader(req, res, (error) => {
if (error) {
return reject(error);
}
resolve({
...req.body,
files:
// @ts-ignore
req.files?.map((file) => ({
...file,
originalname: decodeURIComponent(file.originalname)
})) || [],
metadata: (() => {
if (!req.body?.metadata) return {};
try {
return JSON.parse(req.body.metadata);
} catch (error) {
console.log(error);
return {};
}
})()
});
});
});
}
}
const upload = new UploadModel();
const upload = getUploadModel({
maxSize: 500 * 1024 * 1024
});
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
@@ -82,6 +18,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
const { userId, teamId, tmbId } = await authCert({ req, authToken: true });
const { files, bucketName, metadata } = await upload.doUpload(req, res);
if (!bucketName) {
throw new Error('bucketName is empty');
}
const upLoadResults = await Promise.all(
files.map((file) =>
uploadFile({

View File

@@ -4,7 +4,7 @@ import { jsonRes } from '@fastgpt/service/common/response';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { connectToDatabase } from '@/service/mongo';
import { UrlFetchParams, UrlFetchResponse } from '@fastgpt/global/common/file/api.d';
import { urlsFetch } from '@fastgpt/global/common/file/tools';
import { urlsFetch } from '@fastgpt/service/common/string/cheerio';
const fetchContent = async (req: NextApiRequest, res: NextApiResponse) => {
try {

View File

@@ -53,7 +53,7 @@ function simpleChatTemplate({
key: 'userChatInput',
type: 'systemInput',
label: '用户问题',
connected: true
connected: false
}
],
outputs: [
@@ -95,7 +95,7 @@ function simpleChatTemplate({
label: '对话模型',
required: true,
value: formData.aiSettings.model,
connected: true
connected: false
},
{
key: 'temperature',
@@ -115,7 +115,7 @@ function simpleChatTemplate({
value: 10
}
],
connected: true
connected: false
},
{
key: 'maxToken',
@@ -135,7 +135,7 @@ function simpleChatTemplate({
value: 4000
}
],
connected: true
connected: false
},
{
key: 'isResponseAnswerText',
@@ -143,21 +143,21 @@ function simpleChatTemplate({
label: '返回AI内容',
valueType: 'boolean',
value: true,
connected: true
connected: false
},
{
key: 'quoteTemplate',
type: 'hidden',
label: '引用内容模板',
valueType: 'string',
connected: true
connected: false
},
{
key: 'quotePrompt',
type: 'hidden',
label: '引用内容提示词',
valueType: 'string',
connected: true
connected: false
},
{
key: 'aiSettings',
@@ -176,7 +176,7 @@ function simpleChatTemplate({
placeholder:
'模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。可使用变量,例如 {{language}}',
value: formData.aiSettings.systemPrompt,
connected: true
connected: false
},
{
key: 'quoteQA',
@@ -191,7 +191,7 @@ function simpleChatTemplate({
type: 'target',
label: 'core.module.input.label.chat history',
valueType: 'chatHistory',
connected: true,
connected: false,
value: 8
},
{
@@ -292,21 +292,21 @@ function datasetTemplate({
value: formData.dataset.datasets,
type: FlowNodeInputTypeEnum.custom,
label: '关联的知识库',
connected: true
connected: false
},
{
key: 'similarity',
value: 0.1,
type: FlowNodeInputTypeEnum.slider,
label: '相关度',
connected: true
connected: false
},
{
key: 'limit',
value: 2000,
type: FlowNodeInputTypeEnum.slider,
label: '单次搜索上限',
connected: true
connected: false
},
{
key: 'switch',
@@ -403,7 +403,7 @@ function datasetTemplate({
label: '对话模型',
required: true,
value: formData.aiSettings.model,
connected: true
connected: false
},
{
key: 'temperature',
@@ -423,7 +423,7 @@ function datasetTemplate({
value: 10
}
],
connected: true
connected: false
},
{
key: 'maxToken',
@@ -443,7 +443,7 @@ function datasetTemplate({
value: 4000
}
],
connected: true
connected: false
},
{
key: 'isResponseAnswerText',
@@ -451,21 +451,21 @@ function datasetTemplate({
label: '返回AI内容',
valueType: 'boolean',
value: true,
connected: true
connected: false
},
{
key: 'quoteTemplate',
type: 'hidden',
label: '引用内容模板',
valueType: 'string',
connected: true
connected: false
},
{
key: 'quotePrompt',
type: 'hidden',
label: '引用内容提示词',
valueType: 'string',
connected: true
connected: false
},
{
key: 'aiSettings',
@@ -484,7 +484,7 @@ function datasetTemplate({
placeholder:
'模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。可使用变量,例如 {{language}}',
value: formData.aiSettings.systemPrompt,
connected: true
connected: false
},
{
key: 'quoteQA',
@@ -499,7 +499,7 @@ function datasetTemplate({
type: 'target',
label: 'core.module.input.label.chat history',
valueType: 'chatHistory',
connected: true,
connected: false,
value: 8
},
{

View File

@@ -39,49 +39,49 @@ function chatModelInput(formData: AppSimpleEditFormType): FlowNodeInputItemType[
value: formData.aiSettings.model,
type: 'custom',
label: '对话模型',
connected: true
connected: false
},
{
key: 'temperature',
value: formData.aiSettings.temperature,
type: 'slider',
label: '温度',
connected: true
connected: false
},
{
key: 'maxToken',
value: formData.aiSettings.maxToken,
type: 'custom',
label: '回复上限',
connected: true
connected: false
},
{
key: 'systemPrompt',
value: formData.aiSettings.systemPrompt || '',
type: 'textarea',
label: '系统提示词',
connected: true
connected: false
},
{
key: ModuleInputKeyEnum.aiChatIsResponseText,
value: true,
type: 'hidden',
label: '返回AI内容',
connected: true
connected: false
},
{
key: 'quoteTemplate',
value: formData.aiSettings.quoteTemplate || '',
type: 'hidden',
label: '引用内容模板',
connected: true
connected: false
},
{
key: 'quotePrompt',
value: formData.aiSettings.quotePrompt || '',
type: 'hidden',
label: '引用内容提示词',
connected: true
connected: false
},
{
key: 'switch',
@@ -93,7 +93,7 @@ function chatModelInput(formData: AppSimpleEditFormType): FlowNodeInputItemType[
key: 'history',
type: 'target',
label: 'core.module.input.label.chat history',
connected: true,
connected: false,
value: 6
},
{
@@ -118,9 +118,9 @@ function simpleChatTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
inputs: [
{
key: 'userChatInput',
connected: true,
connected: false,
label: '用户问题',
type: 'target'
type: 'systemInput'
}
],
outputs: [
@@ -179,8 +179,8 @@ function datasetTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
{
key: 'userChatInput',
label: '用户问题',
type: 'target',
connected: true
type: 'systemInput',
connected: false
}
],
outputs: [
@@ -319,7 +319,7 @@ function datasetTemplate(formData: AppSimpleEditFormType): ModuleItemType[] {
type: FlowNodeInputTypeEnum.textarea,
valueType: ModuleIOValueTypeEnum.string,
label: '回复的内容',
connected: true
connected: false
}
],
outputs: [],

View File

@@ -78,12 +78,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
}
}
},
robotBadFeedbackCount: {
customFeedbacksCount: {
$size: {
$filter: {
input: '$chatitems',
as: 'item',
cond: { $ifNull: ['$$item.robotBadFeedback', false] }
cond: { $gt: [{ $size: { $ifNull: ['$$item.customFeedbacks', []] } }, 0] }
}
}
},
@@ -102,7 +102,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
$sort: {
userBadFeedbackCount: -1,
userGoodFeedbackCount: -1,
robotBadFeedbackCount: -1,
customFeedbacksCount: -1,
updateTime: -1
}
},
@@ -118,7 +118,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
messageCount: { $size: '$chatitems' },
userGoodFeedbackCount: 1,
userBadFeedbackCount: 1,
robotBadFeedbackCount: 1,
customFeedbacksCount: 1,
markCount: 1
}
}

View File

@@ -4,22 +4,29 @@ import { connectToDatabase } from '@/service/mongo';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import type { AdminUpdateFeedbackParams } from '@/global/core/chat/api.d';
import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema';
import { autChatCrud } from '@/service/support/permission/auth/chat';
/* 初始化我的聊天框,需要身份验证 */
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
await connectToDatabase();
const { chatItemId, datasetId, dataId, q, a } = req.body as AdminUpdateFeedbackParams;
const { appId, chatId, chatItemId, datasetId, dataId, q, a } =
req.body as AdminUpdateFeedbackParams;
if (!chatItemId || !datasetId || !dataId || !q) {
throw new Error('missing parameter');
}
const { userId } = await authCert({ req, authToken: true });
await autChatCrud({
req,
authToken: true,
appId,
chatId,
per: 'r'
});
await MongoChatItem.findOneAndUpdate(
{
userId,
dataId: chatItemId
},
{

View File

@@ -0,0 +1,47 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import type {
AdminUpdateFeedbackParams,
CloseCustomFeedbackParams
} from '@/global/core/chat/api.d';
import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema';
import { autChatCrud } from '@/service/support/permission/auth/chat';
/* 初始化我的聊天框,需要身份验证 */
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
await connectToDatabase();
const { appId, chatId, chatItemId, index } = req.body as CloseCustomFeedbackParams;
if (!chatItemId || !appId || !chatId || !chatItemId) {
throw new Error('missing parameter');
}
await autChatCrud({
req,
authToken: true,
appId,
chatId,
per: 'r'
});
await authCert({ req, authToken: true });
await MongoChatItem.findOneAndUpdate(
{ dataId: chatItemId },
{ $unset: { [`customFeedbacks.${index}`]: 1 } }
);
await MongoChatItem.findOneAndUpdate(
{ dataId: chatItemId },
{ $pull: { customFeedbacks: null } }
);
jsonRes(res);
} catch (err) {
jsonRes(res, {
code: 500,
error: err
});
}
}

View File

@@ -14,7 +14,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
try {
await connectToDatabase();
let { appId, chatId } = req.query as InitChatProps;
let { appId, chatId, loadCustomFeedbacks } = req.query as InitChatProps;
if (!appId) {
return jsonRes(res, {
@@ -43,7 +43,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const { history } = await getChatItems({
chatId,
limit: 30,
field: `dataId obj value adminFeedback userBadFeedback userGoodFeedback robotBadFeedback ${ModuleOutputKeyEnum.responseData}`
field: `dataId obj value adminFeedback userBadFeedback userGoodFeedback ${
ModuleOutputKeyEnum.responseData
} ${loadCustomFeedbacks ? 'customFeedbacks' : ''}`
});
jsonRes<InitChatResponse>(res, {

View File

@@ -1,6 +1,7 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import type { HttpBodyType } from '@fastgpt/global/core/module/api.d';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { authRequestFromLocal } from '@fastgpt/service/support/permission/auth/common';
type Props = HttpBodyType<{
input: string;
@@ -13,6 +14,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
data: { input, rule = '' }
} = req.body as Props;
await authRequestFromLocal({ req });
const result = (() => {
if (typeof input === 'string') {
const defaultReg: any[] = [

View File

@@ -0,0 +1,52 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import type { HttpBodyType } from '@fastgpt/global/core/module/api.d';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { addCustomFeedbacks } from '@fastgpt/service/core/chat/controller';
import { authRequestFromLocal } from '@fastgpt/service/support/permission/auth/common';
type Props = HttpBodyType<{
defaultFeedback: string;
customFeedback: string;
}>;
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try {
const {
chatId,
responseChatItemId: chatItemId,
data: { defaultFeedback, customFeedback }
} = req.body as Props;
await authRequestFromLocal({ req });
const feedback = customFeedback || defaultFeedback;
if (!feedback) {
return res.json({
response: ''
});
}
// wait the chat finish
setTimeout(() => {
addCustomFeedbacks({
chatId,
chatItemId,
feedbacks: [feedback]
});
}, 60000);
if (!chatId || !chatItemId) {
return res.json({
response: `\\n\\n**自动反馈调试**: ${feedback}\\n\\n`
});
}
return res.json({
response: ''
});
} catch (err) {
console.log(err);
res.status(500).send(getErrText(err));
}
}

View File

@@ -2,6 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import type { HttpBodyType } from '@fastgpt/global/core/module/api.d';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { replaceVariable } from '@fastgpt/global/common/string/tools';
import { authRequestFromLocal } from '@fastgpt/service/support/permission/auth/common';
type Props = HttpBodyType<{
text: string;
@@ -14,6 +15,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
data: { text, ...obj }
} = req.body as Props;
await authRequestFromLocal({ req });
const textResult = replaceVariable(text, obj);
res.json({

View File

@@ -195,12 +195,14 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
// get and concat history
const { history } = await getChatItems({ chatId, limit: 30, field: `dataId obj value` });
const concatHistories = history.concat(chatMessages);
const responseChatItemId: string | undefined = messages[messages.length - 1].dataId;
/* start flow controller */
const { responseData, answerText } = await dispatchModules({
res,
appId: String(app._id),
chatId,
responseChatItemId,
modules: app.modules,
user,
teamId: user.team.teamId,
@@ -237,7 +239,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
content: [
question,
{
dataId: messages[messages.length - 1].dataId,
dataId: responseChatItemId,
obj: ChatRoleEnum.AI,
value: answerText,
responseData

View File

@@ -29,6 +29,7 @@ import Tag from '@/components/Tag';
import MyModal from '@/components/MyModal';
import DateRangePicker, { type DateRangeType } from '@/components/DateRangePicker';
import { addDays } from 'date-fns';
import MyBox from '@/components/common/MyBox';
const Logs = ({ appId }: { appId: string }) => {
const { t } = useTranslation();
@@ -96,6 +97,7 @@ const Logs = ({ appId }: { appId: string }) => {
<Th>{t('app.Logs Title')}</Th>
<Th>{t('app.Logs Message Total')}</Th>
<Th>{t('app.Feedback Count')}</Th>
<Th>{t('core.app.feedback.Custom feedback')}</Th>
<Th>{t('app.Mark Count')}</Th>
</Tr>
</Thead>
@@ -158,7 +160,9 @@ const Logs = ({ appId }: { appId: string }) => {
{item.userBadFeedbackCount}
</Flex>
)}
{!item?.userGoodFeedbackCount && !item?.userBadFeedbackCount && <>-</>}
</Td>
<Td>{item.customFeedbacksCount || '-'}</Td>
<Td>{item.markCount}</Td>
</Tr>
))}
@@ -208,7 +212,7 @@ const Logs = ({ appId }: { appId: string }) => {
export default React.memo(Logs);
function DetailLogsModal({
const DetailLogsModal = ({
appId,
chatId,
onClose
@@ -216,14 +220,14 @@ function DetailLogsModal({
appId: string;
chatId: string;
onClose: () => void;
}) {
}) => {
const ChatBoxRef = useRef<ComponentRef>(null);
const { isPc } = useSystemStore();
const theme = useTheme();
const { data: chat } = useQuery(
const { data: chat, isFetching } = useQuery(
['getChatDetail', chatId],
() => getInitChatInfo({ appId, chatId }),
() => getInitChatInfo({ appId, chatId, loadCustomFeedbacks: true }),
{
onSuccess(res) {
const history = res.history.map((item) => ({
@@ -249,9 +253,11 @@ function DetailLogsModal({
return (
<>
<Flex
zIndex={3}
<MyBox
isLoading={isFetching}
display={'flex'}
flexDirection={'column'}
zIndex={3}
position={['fixed', 'absolute']}
top={[0, '2%']}
right={0}
@@ -325,8 +331,8 @@ function DetailLogsModal({
chatId={chatId}
/>
</Box>
</Flex>
</MyBox>
<Box zIndex={2} position={'fixed'} top={0} left={0} bottom={0} right={0} onClick={onClose} />
</>
);
}
};

View File

@@ -189,7 +189,7 @@ const SelectUsingWayModal = ({ share, onClose }: { share: OutLinkSchema; onClose
w={'16px'}
color={'myGray.600'}
cursor={'pointer'}
_hover={{ color: 'myBlue.600' }}
_hover={{ color: 'blue.500' }}
onClick={() => {
copyData(wayMap[getValues('usingWay')].code);
}}

View File

@@ -77,7 +77,7 @@ const Share = ({ appId }: { appId: string }) => {
</Box>
<Button
variant={'base'}
colorScheme={'myBlue'}
colorScheme={'blue'}
size={['sm', 'md']}
{...(shareChatList.length >= 10
? {

View File

@@ -548,7 +548,7 @@ function Settings({ appId }: { appId: string }) {
mt={2}
px={5}
py={4}
bg={'myBlue.100'}
bg={'blue.50'}
position={'relative'}
>
<Flex alignItems={'center'} py={2}>

View File

@@ -139,7 +139,7 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
>
<IconButton
mr={3}
icon={<MyIcon name={'backFill'} w={'18px'} color={'myBlue.600'} />}
icon={<MyIcon name={'backFill'} w={'18px'} color={'blue.500'} />}
bg={'white'}
boxShadow={'1px 1px 9px rgba(0,0,0,0.15)'}
h={'28px'}

View File

@@ -61,7 +61,7 @@ const ShareModelList = ({
<Flex
alignItems={'center'}
cursor={'pointer'}
color={model.isCollection ? 'myBlue.700' : 'blackAlpha.700'}
color={model.isCollection ? 'blue.600' : 'blackAlpha.700'}
onClick={() => onclickCollection(model._id)}
>
<MyIcon

View File

@@ -154,7 +154,7 @@ const ChatHistorySlider = ({
variant={'base'}
flex={1}
h={'100%'}
color={'myBlue.700'}
color={'blue.600'}
borderRadius={'xl'}
leftIcon={<MyIcon name={'chat'} w={'16px'} />}
overflow={'hidden'}
@@ -201,8 +201,8 @@ const ChatHistorySlider = ({
bg={item.top ? '#E6F6F6 !important' : ''}
{...(item.id === activeChatId
? {
backgroundColor: 'myBlue.100 !important',
color: 'myBlue.700'
backgroundColor: 'blue.50 !important',
color: 'blue.600'
}
: {
onClick: () => {
@@ -290,8 +290,8 @@ const ChatHistorySlider = ({
alignItems={'center'}
{...(item._id === appId
? {
backgroundColor: 'myBlue.100 !important',
color: 'myBlue.700'
backgroundColor: 'blue.50 !important',
color: 'blue.600'
}
: {
onClick: () => {
@@ -325,7 +325,7 @@ const ChatHistorySlider = ({
>
<IconButton
mr={3}
icon={<MyIcon name={'backFill'} w={'18px'} color={'myBlue.600'} />}
icon={<MyIcon name={'backFill'} w={'18px'} color={'blue.500'} />}
bg={'white'}
boxShadow={'1px 1px 9px rgba(0,0,0,0.15)'}
h={'28px'}

View File

@@ -28,7 +28,7 @@ const SliderApps = ({ appId }: { appId: string }) => {
>
<IconButton
mr={3}
icon={<MyIcon name={'backFill'} w={'18px'} color={'myBlue.600'} />}
icon={<MyIcon name={'backFill'} w={'18px'} color={'blue.500'} />}
bg={'white'}
boxShadow={'1px 1px 9px rgba(0,0,0,0.15)'}
h={'28px'}

View File

@@ -311,7 +311,7 @@ const CollectionCard = () => {
target="_blank"
mr={2}
textDecoration={'underline'}
color={'myBlue.700'}
color={'blue.600'}
>
{datasetDetail.websiteConfig.url}
</Link>
@@ -371,7 +371,7 @@ const CollectionCard = () => {
Button={
<MenuButton
_hover={{
color: 'myBlue.600'
color: 'blue.500'
}}
fontSize={['sm', 'md']}
>
@@ -381,7 +381,7 @@ const CollectionCard = () => {
py={2}
borderRadius={'md'}
cursor={'pointer'}
bg={'myBlue.600'}
bg={'blue.500'}
overflow={'hidden'}
color={'white'}
h={['28px', '35px']}
@@ -489,7 +489,7 @@ const CollectionCard = () => {
data-drag-id={
collection.type === DatasetCollectionTypeEnum.folder ? collection._id : undefined
}
bg={dragTargetId === collection._id ? 'myBlue.200' : ''}
bg={dragTargetId === collection._id ? 'blue.100' : ''}
userSelect={'none'}
onDragStart={(e) => {
setDragStartId(collection._id);
@@ -579,7 +579,7 @@ const CollectionCard = () => {
h={'22px'}
borderRadius={'md'}
_hover={{
color: 'myBlue.600',
color: 'blue.500',
'& .icon': {
bg: 'myGray.100'
}

View File

@@ -163,7 +163,7 @@ const DataCard = () => {
<Flex alignItems={'center'}>
<IconButton
mr={3}
icon={<MyIcon name={'backFill'} w={['14px', '18px']} color={'myBlue.600'} />}
icon={<MyIcon name={'backFill'} w={['14px', '18px']} color={'blue.500'} />}
bg={'white'}
boxShadow={'1px 1px 9px rgba(0,0,0,0.15)'}
size={'sm'}

View File

@@ -182,7 +182,7 @@ const FileSelect = ({
if (text) {
text = simpleText(text);
const splitRes = splitText2Chunks({
const { chunks, tokens } = splitText2Chunks({
text,
chunkLen,
overlapRatio
@@ -193,10 +193,10 @@ const FileSelect = ({
filename: file.name,
icon,
rawText: text,
tokens: splitRes.tokens,
tokens,
type: DatasetCollectionTypeEnum.file,
fileId,
chunks: splitRes.chunks.map((chunk) => ({
chunks: chunks.map((chunk) => ({
q: chunk,
a: ''
}))
@@ -219,7 +219,7 @@ const FileSelect = ({
const onUrlFetch = useCallback(
(e: UrlFetchResponse) => {
const result: FileItemType[] = e.map<FileItemType>(({ url, content }) => {
const splitRes = splitText2Chunks({
const { chunks, tokens } = splitText2Chunks({
text: content,
chunkLen,
overlapRatio
@@ -229,10 +229,10 @@ const FileSelect = ({
filename: url,
icon: '/imgs/files/link.svg',
rawText: content,
tokens: splitRes.tokens,
tokens,
type: DatasetCollectionTypeEnum.link,
rawLink: url,
chunks: splitRes.chunks.map((chunk) => ({
chunks: chunks.map((chunk) => ({
q: chunk,
a: ''
}))
@@ -259,7 +259,7 @@ const FileSelect = ({
metadata: { datasetId: datasetDetail._id }
});
const splitRes = splitText2Chunks({
const { chunks, tokens } = splitText2Chunks({
text: content,
chunkLen,
overlapRatio
@@ -271,10 +271,10 @@ const FileSelect = ({
filename,
icon: '/imgs/files/txt.svg',
rawText: content,
tokens: splitRes.tokens,
tokens,
type: DatasetCollectionTypeEnum.file,
fileId: fileIds[0],
chunks: splitRes.chunks.map((chunk) => ({
chunks: chunks.map((chunk) => ({
q: chunk,
a: ''
}))
@@ -352,7 +352,7 @@ const FileSelect = ({
ml: 1,
as: 'span',
cursor: 'pointer',
color: 'myBlue.700',
color: 'blue.600',
_hover: {
textDecoration: 'underline'
}
@@ -417,7 +417,7 @@ const FileSelect = ({
mt={1}
cursor={'pointer'}
textDecoration={'underline'}
color={'myBlue.600'}
color={'blue.500'}
fontSize={'12px'}
onClick={() =>
fileDownload({

View File

@@ -195,7 +195,7 @@ const Provider = ({
setFiles((state) =>
state.map((file) => {
const splitRes = splitText2Chunks({
const { chunks, tokens } = splitText2Chunks({
text: file.rawText,
chunkLen,
overlapRatio: chunkOverlapRatio
@@ -203,8 +203,8 @@ const Provider = ({
return {
...file,
tokens: splitRes.tokens,
chunks: splitRes.chunks.map((chunk) => ({
tokens,
chunks: chunks.map((chunk) => ({
q: chunk,
a: ''
}))
@@ -475,7 +475,7 @@ export const SelectorContainer = ({
position={'relative'}
alignItems={'center'}
_hover={{
bg: 'myBlue.100',
bg: 'blue.50',
'& .delete': {
display: 'block'
}

View File

@@ -313,7 +313,7 @@ const InputDataModal = ({
borderColor={'transparent'}
px={0}
_focus={{
borderColor: 'myBlue.400',
borderColor: 'blue.400',
px: 3
}}
placeholder={t('dataset.data.Index Placeholder')}
@@ -332,7 +332,7 @@ const InputDataModal = ({
border={theme.borders.base}
cursor={'pointer'}
_hover={{
bg: 'myBlue.100'
bg: 'blue.50'
}}
minH={'100px'}
onClick={() =>

View File

@@ -102,10 +102,10 @@ const Test = ({ datasetId }: { datasetId: string }) => {
py={4}
borderRight={['none', theme.borders.base]}
>
<Box border={'2px solid'} borderColor={'myBlue.600'} p={3} mx={4} borderRadius={'md'}>
<Box border={'2px solid'} borderColor={'blue.500'} p={3} mx={4} borderRadius={'md'}>
<Flex alignItems={'center'}>
<Box fontSize={'sm'} fontWeight={'bold'} flex={1}>
<MyIcon mr={2} name={'text'} w={'18px'} h={'18px'} color={'myBlue.700'} />
<MyIcon mr={2} name={'text'} w={'18px'} h={'18px'} color={'blue.600'} />
{t('core.dataset.test.Test Text')}
</Box>
<Button

View File

@@ -181,7 +181,7 @@ const Detail = ({ datasetId, currentTab }: { datasetId: string; currentTab: `${T
>
<IconButton
mr={3}
icon={<MyIcon name={'backFill'} w={'18px'} color={'myBlue.600'} />}
icon={<MyIcon name={'backFill'} w={'18px'} color={'blue.500'} />}
bg={'white'}
boxShadow={'1px 1px 9px rgba(0,0,0,0.15)'}
h={'28px'}

View File

@@ -79,7 +79,7 @@ const MoveModal = ({
: {
cursor: 'pointer',
_hover: {
color: 'myBlue.600'
color: 'blue.500'
},
onClick: () => {
setParentId(item.parentId);

View File

@@ -163,7 +163,7 @@ const Kb = () => {
Button={
<MenuButton
_hover={{
color: 'myBlue.600'
color: 'blue.500'
}}
>
<Flex
@@ -221,7 +221,7 @@ const Kb = () => {
boxShadow={'none'}
position={'relative'}
data-drag-id={dataset.type === DatasetTypeEnum.folder ? dataset._id : undefined}
borderColor={dragTargetId === dataset._id ? 'myBlue.600' : ''}
borderColor={dragTargetId === dataset._id ? 'blue.500' : ''}
draggable
onDragStart={(e) => {
setDragStartId(dataset._id);
@@ -287,7 +287,7 @@ const Kb = () => {
h={'22px'}
borderRadius={'md'}
_hover={{
color: 'myBlue.600',
color: 'blue.500',
'& .icon': {
bg: 'myGray.100'
}

View File

@@ -158,7 +158,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
float={'right'}
fontSize="sm"
mt={2}
color={'myBlue.600'}
color={'blue.500'}
cursor={'pointer'}
_hover={{ textDecoration: 'underline' }}
onClick={() => setPageType('login')}

View File

@@ -125,7 +125,7 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
</FormControl>
{feConfigs?.show_register && (
<>
<Flex align={'center'} justifyContent={'space-between'} mt={3} color={'myBlue.600'}>
<Flex align={'center'} justifyContent={'space-between'} mt={3} color={'blue.500'}>
<Box
cursor={'pointer'}
_hover={{ textDecoration: 'underline' }}
@@ -149,7 +149,7 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
<Link
href={getDocPath('/docs/agreement/disclaimer/')}
target={'_blank'}
color={'myBlue.600'}
color={'blue.500'}
>
</Link>

View File

@@ -172,7 +172,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
float={'right'}
fontSize="sm"
mt={2}
color={'myBlue.600'}
color={'blue.500'}
cursor={'pointer'}
_hover={{ textDecoration: 'underline' }}
onClick={() => setPageType('login')}

View File

@@ -116,7 +116,7 @@ const Login = () => {
{feConfigs?.concatMd && (
<Box
fontWeight={'bold'}
color={'myBlue.700'}
color={'blue.600'}
cursor={'pointer'}
position={'absolute'}
right={5}

View File

@@ -88,7 +88,7 @@ const MyModules = () => {
aria-label={'delete'}
display={['', 'none']}
_hover={{
bg: 'myBlue.200'
bg: 'blue.100'
}}
onClick={(e) => {
e.stopPropagation();

View File

@@ -78,12 +78,12 @@ export function request(url: string, data: any, config: ConfigType, method: Meth
return instance
.request({
baseURL: `http://localhost:${process.env.PORT || 3000}`,
baseURL: `http://${process.env.HOSTNAME || 'localhost'}:${process.env.PORT || 3000}`,
url,
method,
data: ['POST', 'PUT'].includes(method) ? data : null,
params: !['POST', 'PUT'].includes(method) ? data : null,
...config // 用户自定义配置,可以覆盖前面的配置
...config // custom config
})
.then((res) => checkRes(res.data))
.catch((err) => responseError(err));

View File

@@ -243,8 +243,8 @@ function formatSplitText(text: string, rawText: string) {
// empty result. direct split chunk
if (result.length === 0) {
const splitRes = splitText2Chunks({ text: rawText, chunkLen: 512 });
splitRes.chunks.forEach((chunk) => {
const { chunks } = splitText2Chunks({ text: rawText, chunkLen: 512, countTokens: false });
chunks.forEach((chunk) => {
result.push({
q: chunk,
a: '',

View File

@@ -40,7 +40,7 @@ export async function dispatchContentExtract(props: Props): Promise<Response> {
const extractModel = global.extractModels[0];
const chatHistories = getHistories(history, histories);
const { arg, tokens } = await (async () => {
const { arg, tokens, rawResponse } = await (async () => {
if (extractModel.functionCall) {
return functionCall({
...props,
@@ -176,6 +176,7 @@ ${content}
const tokens = response.usage?.total_tokens || 0;
return {
rawResponse: response?.choices?.[0]?.message?.tool_calls?.[0]?.function?.arguments || '',
tokens,
arg
};
@@ -195,7 +196,7 @@ async function completions({
json: extractKeys
.map(
(item) =>
`{"key":"${item.key}", "description":"${item.required}", "required":${item.required}${
`{"key":"${item.key}", "description":"${item.desc}", "required":${item.required}${
item.enum ? `, "enum":"[${item.enum.split('\n')}]"` : ''
}}`
)
@@ -223,6 +224,7 @@ Human: ${content}`
if (start === -1 || end === -1)
return {
rawResponse: answer,
tokens: totalTokens,
arg: {}
};
@@ -234,11 +236,13 @@ Human: ${content}`
try {
return {
rawResponse: answer,
tokens: totalTokens,
arg: JSON.parse(jsonStr) as Record<string, any>
};
} catch (error) {
return {
rawResponse: answer,
tokens: totalTokens,
arg: {}
};

View File

@@ -50,6 +50,7 @@ export async function dispatchModules({
appId,
modules,
chatId,
responseChatItemId,
histories = [],
startParams = {},
variables = {},
@@ -63,6 +64,7 @@ export async function dispatchModules({
appId: string;
modules: ModuleItemType[];
chatId?: string;
responseChatItemId?: string;
histories: ChatItemType[];
startParams?: Record<string, any>;
variables?: Record<string, any>;
@@ -201,6 +203,7 @@ export async function dispatchModules({
user,
appId,
chatId,
responseChatItemId,
stream,
detail,
variables,

View File

@@ -21,6 +21,7 @@ export const dispatchHttpRequest = async (props: HttpRequestProps): Promise<Http
let {
appId,
chatId,
responseChatItemId,
variables,
inputs: {
system_httpMethod: httpMethod,
@@ -57,6 +58,7 @@ export const dispatchHttpRequest = async (props: HttpRequestProps): Promise<Http
requestBody: {
appId,
chatId,
responseChatItemId,
variables,
data: body
},

View File

@@ -4,7 +4,6 @@ import { initPg } from '@fastgpt/service/common/pg';
import { MongoUser } from '@fastgpt/service/support/user/schema';
import { connectMongo } from '@fastgpt/service/common/mongo/init';
import { hashStr } from '@fastgpt/global/common/string/tools';
import { getInitConfig } from '@/pages/api/system/getInitData';
import { createDefaultTeam } from '@fastgpt/service/support/user/team/controller';
import { exit } from 'process';
@@ -13,9 +12,7 @@ import { exit } from 'process';
*/
export function connectToDatabase(): Promise<void> {
return connectMongo({
beforeHook: () => {
getInitConfig();
},
beforeHook: () => {},
afterHook: () => {
initPg();
// start queue

View File

@@ -61,6 +61,6 @@ export type AppLogsListItemType = {
messageCount: number;
userGoodFeedbackCount: number;
userBadFeedbackCount: number;
robotBadFeedbackCount: number;
customFeedbacksCount: number;
markCount: number;
};

View File

@@ -12,6 +12,7 @@ export type ModuleDispatchProps<T> = {
user: UserType;
appId: string;
chatId?: string;
responseChatItemId?: string;
stream: boolean;
detail: boolean; // response detail
variables: Record<string, any>;

View File

@@ -2,4 +2,6 @@ import { GET, POST, PUT, DELETE } from '@/web/common/api/request';
import { UrlFetchParams, UrlFetchResponse } from '@fastgpt/global/common/file/api.d';
export const postFetchUrls = (data: UrlFetchParams) =>
POST<UrlFetchResponse>(`/common/tools/urlFetch`, data);
POST<UrlFetchResponse>(`/common/tools/urlFetch`, data, {
timeout: 300000
});

View File

@@ -1,6 +1,7 @@
import { GET, POST, DELETE, PUT } from '@/web/common/api/request';
import type { ChatHistoryItemType } from '@fastgpt/global/core/chat/type.d';
import type {
CloseCustomFeedbackParams,
InitChatProps,
InitChatResponse,
InitOutLinkChatProps,
@@ -50,8 +51,12 @@ export const delChatRecordById = (data: DeleteChatItemProps) =>
*/
export const putChatHistory = (data: UpdateHistoryProps) => PUT('/core/chat/updateHistory', data);
/* -------------- feedback ------------ */
export const updateChatUserFeedback = (data: UpdateChatFeedbackProps) =>
POST('/core/chat/feedback/updateUserFeedback', data);
export const updateChatAdminFeedback = (data: AdminUpdateFeedbackParams) =>
POST('/core/chat/feedback/adminUpdate', data);
export const closeCustomFeedback = (data: CloseCustomFeedbackParams) =>
POST('/core/chat/feedback/closeCustom', data).catch();

View File

@@ -5,7 +5,17 @@ import { useLoading } from '@/web/common/hooks/useLoading';
import { useRequest } from '@/web/common/hooks/useRequest';
import { getDatasetCollectionPathById, getDatasetCollections } from '@/web/core/dataset/api';
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
import { Box, Flex, ModalFooter, Button, useTheme, Grid, Card, Image } from '@chakra-ui/react';
import {
Box,
Flex,
ModalFooter,
Button,
useTheme,
Grid,
Card,
Image,
ModalBody
} from '@chakra-ui/react';
import { DatasetCollectionTypeEnum } from '@fastgpt/global/core/dataset/constant';
import { getCollectionIcon } from '@fastgpt/global/core/dataset/utils';
import { useQuery } from '@tanstack/react-query';
@@ -115,7 +125,9 @@ const SelectCollections = ({
FirstPathDom={
<>
<Box fontWeight={'bold'} fontSize={['sm', 'lg']}>
{title || type === 'folder'
{title
? title
: type === 'folder'
? t('common.Select One Folder')
: t('dataset.collections.Select Collection')}
</Box>
@@ -133,85 +145,83 @@ const SelectCollections = ({
</Box>
}
>
<Flex flexDirection={'column'} flex={'1 0 0'}>
<Box flex={'1 0 0'} px={4} py={2} position={'relative'}>
<Grid
gridTemplateColumns={['repeat(1,1fr)', 'repeat(2,1fr)', 'repeat(3,1fr)']}
gridGap={3}
userSelect={'none'}
overflowY={'auto'}
mt={2}
>
{collections.map((item) =>
(() => {
const selected = selectedDatasetCollectionIds.includes(item._id);
return (
<Card
key={item._id}
p={3}
border={theme.borders.base}
boxShadow={'sm'}
cursor={'pointer'}
_hover={{
boxShadow: 'md'
}}
{...(selected
? {
bg: 'myBlue.300'
}
: {})}
onClick={() => {
if (item.type === DatasetCollectionTypeEnum.folder) {
setParentId(item._id);
} else {
let result: string[] = [];
if (max === 1) {
result = [item._id];
} else if (selected) {
result = selectedDatasetCollectionIds.filter((id) => id !== item._id);
} else if (selectedDatasetCollectionIds.length < max) {
result = [...selectedDatasetCollectionIds, item._id];
}
setSelectedDatasetCollectionIds(result);
onChange && onChange({ parentId, collectionIds: result });
<ModalBody flex={'1 0 0'} overflow={'auto'}>
<Grid
gridTemplateColumns={['repeat(1,1fr)', 'repeat(2,1fr)']}
gridGap={3}
userSelect={'none'}
overflowY={'auto'}
mt={2}
>
{collections.map((item) =>
(() => {
const selected = selectedDatasetCollectionIds.includes(item._id);
return (
<Card
key={item._id}
p={3}
border={theme.borders.base}
boxShadow={'sm'}
cursor={'pointer'}
_hover={{
boxShadow: 'md'
}}
{...(selected
? {
bg: 'blue.200'
}
}}
>
<Flex alignItems={'center'} h={'38px'}>
<Image src={item.icon} w={'18px'} alt={''} />
<Box ml={3} fontSize={'sm'}>
{item.name}
</Box>
</Flex>
</Card>
);
})()
)}
</Grid>
{collections.length === 0 && (
<Flex mt={'20vh'} flexDirection={'column'} alignItems={'center'}>
<MyIcon name="empty" w={'48px'} h={'48px'} color={'transparent'} />
<Box mt={2} color={'myGray.500'}>
{t('common.folder.No Folder')}
</Box>
</Flex>
: {})}
onClick={() => {
if (item.type === DatasetCollectionTypeEnum.folder) {
setParentId(item._id);
} else {
let result: string[] = [];
if (max === 1) {
result = [item._id];
} else if (selected) {
result = selectedDatasetCollectionIds.filter((id) => id !== item._id);
} else if (selectedDatasetCollectionIds.length < max) {
result = [...selectedDatasetCollectionIds, item._id];
}
setSelectedDatasetCollectionIds(result);
onChange && onChange({ parentId, collectionIds: result });
}
}}
>
<Flex alignItems={'center'} h={'38px'}>
<Image src={item.icon} w={'18px'} alt={''} />
<Box ml={3} fontSize={'sm'} className="textEllipsis">
{item.name}
</Box>
</Flex>
</Card>
);
})()
)}
<Loading loading={isLoading} fixed={false} />
</Box>
{CustomFooter ? (
<>{CustomFooter}</>
) : (
<ModalFooter>
<Button
isLoading={isResponding}
isDisabled={type === 'collection' && selectedDatasetCollectionIds.length === 0}
onClick={mutate}
>
{type === 'folder' ? t('common.Confirm Move') : t('Confirm')}
</Button>
</ModalFooter>
</Grid>
{collections.length === 0 && (
<Flex mt={'20vh'} flexDirection={'column'} alignItems={'center'}>
<MyIcon name="empty" w={'48px'} h={'48px'} color={'transparent'} />
<Box mt={2} color={'myGray.500'}>
{t('common.folder.No Folder')}
</Box>
</Flex>
)}
</Flex>
<Loading loading={isLoading} fixed={false} />
</ModalBody>
{CustomFooter ? (
<>{CustomFooter}</>
) : (
<ModalFooter>
<Button
isLoading={isResponding}
isDisabled={type === 'collection' && selectedDatasetCollectionIds.length === 0}
onClick={mutate}
>
{type === 'folder' ? t('common.Confirm Move') : t('Confirm')}
</Button>
</ModalFooter>
)}
</MyModal>
);
};

View File

@@ -1,5 +1,11 @@
import { extendTheme, defineStyleConfig, ComponentStyleConfig } from '@chakra-ui/react';
import { modalAnatomy, switchAnatomy, selectAnatomy, numberInputAnatomy } from '@chakra-ui/anatomy';
import {
modalAnatomy,
switchAnatomy,
selectAnatomy,
numberInputAnatomy,
checkboxAnatomy
} from '@chakra-ui/anatomy';
import { createMultiStyleConfigHelpers } from '@chakra-ui/styled-system';
const { definePartsStyle, defineMultiStyleConfig } = createMultiStyleConfigHelpers(
@@ -11,6 +17,8 @@ const { definePartsStyle: selectPart, defineMultiStyleConfig: selectMultiStyle }
createMultiStyleConfigHelpers(selectAnatomy.keys);
const { definePartsStyle: numInputPart, defineMultiStyleConfig: numInputMultiStyle } =
createMultiStyleConfigHelpers(numberInputAnatomy.keys);
const { definePartsStyle: checkBoxPart, defineMultiStyleConfig: checkBoxMultiStyle } =
createMultiStyleConfigHelpers(checkboxAnatomy.keys);
// 按键
const Button = defineStyleConfig({
@@ -68,7 +76,7 @@ const Button = defineStyleConfig({
},
gray: {
bg: '#F5F5F8',
color: 'myBlue.700',
color: 'blue.600',
border: '1px solid #EFF0F1',
_hover: {
background: '#3370FF1A'
@@ -81,12 +89,12 @@ const Button = defineStyleConfig({
bg: 'transparent',
transition: 'background 0.3s',
_hover: {
color: 'myBlue.600',
color: 'blue.500',
background: 'myWhite.400',
boxShadow: '0 0 5px rgba(0,0,0,0.1)'
},
_active: {
color: 'myBlue.700'
color: 'blue.600'
},
_disabled: {
bg: 'myGray.100 !important',
@@ -127,7 +135,7 @@ const Input: ComponentStyleConfig = {
borderRadius: 'base',
borderColor: 'myGray.200',
_focus: {
borderColor: 'myBlue.600',
borderColor: 'blue.500',
boxShadow: '0px 0px 4px #A8DBFF',
bg: 'white'
},
@@ -153,7 +161,7 @@ const NumberInput = numInputMultiStyle({
borderRadius: 'base',
borderColor: 'myGray.200',
_focus: {
borderColor: 'myBlue.600 !important',
borderColor: 'blue.500 !important',
boxShadow: '0px 0px 4px #A8DBFF !important',
bg: 'transparent'
},
@@ -167,7 +175,7 @@ const NumberInput = numInputMultiStyle({
border: 'none',
color: 'myGray.600',
_active: {
color: 'myBlue.600'
color: 'blue.500'
}
}
})
@@ -187,7 +195,7 @@ const Textarea: ComponentStyleConfig = {
borderColor: ''
},
_focus: {
borderColor: 'myBlue.600',
borderColor: 'blue.500',
boxShadow: '0px 0px 4px #A8DBFF',
bg: 'white'
}
@@ -205,7 +213,7 @@ const Switch = switchMultiStyle({
track: {
bg: 'myGray.100',
_checked: {
bg: 'myBlue.700'
bg: 'blue.600'
}
}
})
@@ -218,13 +226,21 @@ const Select = selectMultiStyle({
borderColor: 'myGray.200',
_focusWithin: {
boxShadow: '0px 0px 4px #A8DBFF',
borderColor: 'myBlue.600'
borderColor: 'blue.500'
}
}
})
}
});
const Checkbox = checkBoxMultiStyle({
baseStyle: checkBoxPart({
label: {
fontFamily: 'mono' // change the font family of the label
}
})
});
// 全局主题
export const theme = extendTheme({
styles: {
@@ -238,7 +254,7 @@ export const theme = extendTheme({
// lineHeight: 'unset'
},
a: {
color: 'myBlue.700'
color: 'blue.600'
}
}
},
@@ -267,17 +283,17 @@ export const theme = extendTheme({
900: '#24282C',
1000: '#121416'
},
myBlue: {
100: '#f0f7ff',
200: '#EBF7FD',
300: '#d6e8ff',
400: '#adceff',
500: '#85b1ff',
600: '#4e83fd',
700: '#3370ff',
800: '#2152d9',
900: '#1237b3',
1000: '#07228c'
blue: {
50: '#f0f7ff',
100: '#EBF7FD',
200: '#d6e8ff',
300: '#adceff',
400: '#85b1ff',
500: '#4e83fd',
600: '#3370ff',
700: '#2152d9',
800: '#1237b3',
900: '#07228c'
},
myRead: {
600: '#ff4d4f'
@@ -326,6 +342,7 @@ export const theme = extendTheme({
Textarea,
Switch,
Select,
NumberInput
NumberInput,
Checkbox
}
});