mirror of
https://github.com/labring/FastGPT.git
synced 2025-08-01 03:48:24 +00:00
4.7-production (#1053)
* 4.7-alpha3 (#62) * doc * Optimize possible null Pointers and parts of Ux * fix: mulity index training error * feat: doc and rename question guide * fix ios speech input (#59) * fix: prompt editor variables nowrap (#61) * change openapi import in http module with curl import (#60) * chore(ui): dataset import modal ui (#58) * chore(ui): dataset import modal ui * use component * fix height * 4.7 (#63) * fix: claude3 image type verification failed (#1038) (#1040) * perf: curl import modal * doc img * perf: adapt cohere rerank * perf: code * perf: input style * doc --------- Co-authored-by: xiaotian <dimsky@163.com> * fix: ts * docker deploy * perf: prompt call * doc * ts * finish ui * perf: outlink detail ux * perf: user schema * fix: plugin update * feat: get current time plugin * fix: ts * perf: fetch anamation * perf: mark ux * doc * perf: select app ux * fix: split text custom string conflict * peref: inform readed * doc * memo flow component * perf: version * faq * feat: flow max runtimes * feat: similarity tip * feat: auto detect file encoding * Supports asymmetric vector model * fix: ts * perf: max w * move code * perf: hide whisper * fix: ts * feat: system msg modal * perf: catch error * perf: inform tip * fix: inform --------- Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com> Co-authored-by: xiaotian <dimsky@163.com>
This commit is contained in:
@@ -83,8 +83,7 @@ export const streamFetch = ({
|
||||
}
|
||||
|
||||
if (responseQueue.length > 0) {
|
||||
const fetchCount = Math.max(1, Math.round(responseQueue.length / 10));
|
||||
|
||||
const fetchCount = Math.max(1, Math.round(responseQueue.length / 30));
|
||||
for (let i = 0; i < fetchCount; i++) {
|
||||
const item = responseQueue[i];
|
||||
onMessage(item);
|
||||
@@ -167,7 +166,15 @@ export const streamFetch = ({
|
||||
}
|
||||
})();
|
||||
// console.log(parseJson, event);
|
||||
if (event === SseResponseEventEnum.answer || event === SseResponseEventEnum.fastAnswer) {
|
||||
if (event === SseResponseEventEnum.answer) {
|
||||
const text = parseJson.choices?.[0]?.delta?.content || '';
|
||||
for (const item of text) {
|
||||
responseQueue.push({
|
||||
event,
|
||||
text: item
|
||||
});
|
||||
}
|
||||
} else if (event === SseResponseEventEnum.fastAnswer) {
|
||||
const text = parseJson.choices?.[0]?.delta?.content || '';
|
||||
responseQueue.push({
|
||||
event,
|
||||
|
@@ -1,131 +0,0 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useDisclosure, Button, ModalBody, ModalFooter } from '@chakra-ui/react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
|
||||
export const useConfirm = (props?: {
|
||||
title?: string;
|
||||
iconSrc?: string | '';
|
||||
content?: string;
|
||||
showCancel?: boolean;
|
||||
type?: 'common' | 'delete';
|
||||
hideFooter?: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const map = useMemo(() => {
|
||||
const map = {
|
||||
common: {
|
||||
title: t('common.confirm.Common Tip'),
|
||||
bg: undefined,
|
||||
iconSrc: 'common/confirm/commonTip'
|
||||
},
|
||||
delete: {
|
||||
title: t('common.Delete Warning'),
|
||||
bg: 'red.600',
|
||||
iconSrc: 'common/confirm/deleteTip'
|
||||
}
|
||||
};
|
||||
if (props?.type && map[props.type]) return map[props.type];
|
||||
return map.common;
|
||||
}, [props?.type, t]);
|
||||
|
||||
const {
|
||||
title = map?.title || t('Warning'),
|
||||
iconSrc = map?.iconSrc,
|
||||
content,
|
||||
showCancel = true,
|
||||
hideFooter = false
|
||||
} = props || {};
|
||||
const [customContent, setCustomContent] = useState<string | React.ReactNode>(content);
|
||||
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
|
||||
const confirmCb = useRef<any>();
|
||||
const cancelCb = useRef<any>();
|
||||
|
||||
return {
|
||||
openConfirm: useCallback(
|
||||
(confirm?: any, cancel?: any, customContent?: string | React.ReactNode) => {
|
||||
confirmCb.current = confirm;
|
||||
cancelCb.current = cancel;
|
||||
|
||||
customContent && setCustomContent(customContent);
|
||||
|
||||
return onOpen;
|
||||
},
|
||||
[onOpen]
|
||||
),
|
||||
onClose,
|
||||
ConfirmModal: useCallback(
|
||||
({
|
||||
closeText = t('common.Close'),
|
||||
confirmText = t('common.Confirm'),
|
||||
isLoading,
|
||||
bg,
|
||||
countDown = 0
|
||||
}: {
|
||||
closeText?: string;
|
||||
confirmText?: string;
|
||||
isLoading?: boolean;
|
||||
bg?: string;
|
||||
countDown?: number;
|
||||
}) => {
|
||||
const timer = useRef<any>();
|
||||
const [countDownAmount, setCountDownAmount] = useState(countDown);
|
||||
|
||||
useEffect(() => {
|
||||
timer.current = setInterval(() => {
|
||||
setCountDownAmount((val) => {
|
||||
if (val <= 0) {
|
||||
clearInterval(timer.current);
|
||||
}
|
||||
return val - 1;
|
||||
});
|
||||
}, 1000);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<MyModal
|
||||
isOpen={isOpen}
|
||||
onClose={onClose}
|
||||
iconSrc={iconSrc}
|
||||
title={title}
|
||||
maxW={['90vw', '500px']}
|
||||
>
|
||||
<ModalBody pt={5}>{customContent}</ModalBody>
|
||||
{!hideFooter && (
|
||||
<ModalFooter>
|
||||
{showCancel && (
|
||||
<Button
|
||||
variant={'whiteBase'}
|
||||
onClick={() => {
|
||||
onClose();
|
||||
typeof cancelCb.current === 'function' && cancelCb.current();
|
||||
}}
|
||||
>
|
||||
{closeText}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<Button
|
||||
bg={bg ? bg : map.bg}
|
||||
isDisabled={countDownAmount > 0}
|
||||
ml={4}
|
||||
isLoading={isLoading}
|
||||
onClick={() => {
|
||||
onClose();
|
||||
typeof confirmCb.current === 'function' && confirmCb.current();
|
||||
}}
|
||||
>
|
||||
{countDownAmount > 0 ? `${countDownAmount}s` : confirmText}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
)}
|
||||
</MyModal>
|
||||
);
|
||||
},
|
||||
[customContent, hideFooter, iconSrc, isOpen, map.bg, onClose, showCancel, t, title]
|
||||
)
|
||||
};
|
||||
};
|
@@ -8,7 +8,6 @@ import { OutLinkChatAuthProps } from '@fastgpt/global/support/permission/chat';
|
||||
export const useSpeech = (props?: OutLinkChatAuthProps) => {
|
||||
const { t } = useTranslation();
|
||||
const mediaRecorder = useRef<MediaRecorder>();
|
||||
// const mediaStream = useRef<MediaStream>();
|
||||
const [mediaStream, setMediaStream] = useState<MediaStream>();
|
||||
const { toast } = useToast();
|
||||
const [isSpeaking, setIsSpeaking] = useState(false);
|
||||
@@ -54,6 +53,7 @@ export const useSpeech = (props?: OutLinkChatAuthProps) => {
|
||||
try {
|
||||
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
||||
setMediaStream(stream);
|
||||
|
||||
mediaRecorder.current = new MediaRecorder(stream);
|
||||
const chunks: Blob[] = [];
|
||||
setIsSpeaking(true);
|
||||
@@ -74,11 +74,18 @@ export const useSpeech = (props?: OutLinkChatAuthProps) => {
|
||||
|
||||
mediaRecorder.current.onstop = async () => {
|
||||
const formData = new FormData();
|
||||
const blob = new Blob(chunks, { type: 'audio/webm' });
|
||||
|
||||
let options = {};
|
||||
if (MediaRecorder.isTypeSupported('audio/webm')) {
|
||||
options = { type: 'audio/webm' };
|
||||
} else if (MediaRecorder.isTypeSupported('video/mp4')) {
|
||||
options = { type: 'video/mp4' };
|
||||
} else {
|
||||
console.error('no suitable mimetype found for this device');
|
||||
}
|
||||
const blob = new Blob(chunks, options);
|
||||
const duration = Math.round((Date.now() - startTimestamp.current) / 1000);
|
||||
|
||||
formData.append('file', blob, 'recording.webm');
|
||||
formData.append('file', blob, 'recording.mp4');
|
||||
formData.append(
|
||||
'data',
|
||||
JSON.stringify({
|
||||
@@ -112,7 +119,13 @@ export const useSpeech = (props?: OutLinkChatAuthProps) => {
|
||||
};
|
||||
|
||||
mediaRecorder.current.start();
|
||||
} catch (error) {}
|
||||
} catch (error) {
|
||||
toast({
|
||||
status: 'warning',
|
||||
title: getErrText(error, 'Whisper error')
|
||||
});
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
|
||||
const stopSpeak = () => {
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import { AppItemType } from '@/types/app';
|
||||
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
|
||||
import { Dataset_SEARCH_DESC } from '@fastgpt/global/core/module/template/system/datasetSearch';
|
||||
|
||||
// template
|
||||
export const appTemplates: (AppItemType & {
|
||||
@@ -876,7 +877,7 @@ export const appTemplates: (AppItemType & {
|
||||
{
|
||||
moduleId: '0voh5n',
|
||||
name: '知识库搜索',
|
||||
intro: '调用知识库搜索能力,查找“有可能”与问题相关的内容',
|
||||
intro: Dataset_SEARCH_DESC,
|
||||
avatar: '/imgs/module/db.png',
|
||||
flowType: 'datasetSearchNode',
|
||||
showStatus: true,
|
||||
|
@@ -4,7 +4,10 @@ import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '@fastgpt/global/core/mo
|
||||
import { ModuleIOValueTypeEnum, ModuleInputKeyEnum } from '@fastgpt/global/core/module/constants';
|
||||
import { UserInputModule } from '@fastgpt/global/core/module/template/system/userInput';
|
||||
import { ToolModule } from '@fastgpt/global/core/module/template/system/tools';
|
||||
import { DatasetSearchModule } from '@fastgpt/global/core/module/template/system/datasetSearch';
|
||||
import {
|
||||
DatasetSearchModule,
|
||||
Dataset_SEARCH_DESC
|
||||
} from '@fastgpt/global/core/module/template/system/datasetSearch';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
|
||||
export async function postForm2Modules(data: AppSimpleEditFormType) {
|
||||
@@ -489,7 +492,7 @@ export async function postForm2Modules(data: AppSimpleEditFormType) {
|
||||
{
|
||||
moduleId: '0voh5n',
|
||||
name: '知识库搜索',
|
||||
intro: '调用知识库搜索能力,查找“有可能”与问题相关的内容',
|
||||
intro: Dataset_SEARCH_DESC,
|
||||
avatar: '/imgs/module/db.png',
|
||||
flowType: 'datasetSearchNode',
|
||||
showStatus: true,
|
||||
@@ -640,14 +643,6 @@ export async function postForm2Modules(data: AppSimpleEditFormType) {
|
||||
key: 'quoteQA'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'finish',
|
||||
label: 'core.module.output.label.running done',
|
||||
description: 'core.module.output.description.running done',
|
||||
valueType: 'boolean',
|
||||
type: 'source',
|
||||
targets: []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -800,14 +795,6 @@ export async function postForm2Modules(data: AppSimpleEditFormType) {
|
||||
type: 'source',
|
||||
valueType: 'datasetQuote',
|
||||
targets: []
|
||||
},
|
||||
{
|
||||
key: 'finish',
|
||||
label: 'core.module.output.label.running done',
|
||||
description: 'core.module.output.description.running done',
|
||||
valueType: 'boolean',
|
||||
type: 'source',
|
||||
targets: []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import ParentPaths from '@/components/common/ParentPaths';
|
||||
import { useRequest } from '@/web/common/hooks/useRequest';
|
||||
import { useRequest } from '@fastgpt/web/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, ModalBody } from '@chakra-ui/react';
|
||||
|
@@ -17,7 +17,13 @@ export const getPluginPaths = (parentId?: string) =>
|
||||
|
||||
// http plugin
|
||||
export const getApiSchemaByUrl = (url: string) =>
|
||||
POST<Object>('/core/plugin/httpPlugin/getApiSchemaByUrl', { url });
|
||||
POST<Object>(
|
||||
'/core/plugin/httpPlugin/getApiSchemaByUrl',
|
||||
{ url },
|
||||
{
|
||||
timeout: 30000
|
||||
}
|
||||
);
|
||||
|
||||
/* work flow */
|
||||
export const getPlugTemplates = () => GET<FlowNodeTemplateType[]>('/core/plugin/templates');
|
||||
|
@@ -1,9 +1,17 @@
|
||||
import { GET, POST, PUT } from '@/web/common/api/request';
|
||||
import type { PagingData, RequestPaging } from '@/types';
|
||||
import type { UserInformSchema } from '@fastgpt/global/support/user/inform/type';
|
||||
import { SystemMsgModalValueType } from '@fastgpt/service/support/user/inform/type';
|
||||
|
||||
export const getInforms = (data: RequestPaging) =>
|
||||
POST<PagingData<UserInformSchema>>(`/proApi/support/user/inform/list`, data);
|
||||
|
||||
export const getUnreadCount = () => GET<number>(`/proApi/support/user/inform/countUnread`);
|
||||
export const getUnreadCount = () =>
|
||||
GET<{
|
||||
unReadCount: number;
|
||||
importantInforms: UserInformSchema[];
|
||||
}>(`/proApi/support/user/inform/countUnread`);
|
||||
export const readInform = (id: string) => GET(`/proApi/support/user/inform/read`, { id });
|
||||
|
||||
export const getSystemMsgModalData = () =>
|
||||
GET<SystemMsgModalValueType>(`/proApi/support/user/inform/getSystemMsgModal`);
|
||||
|
@@ -6,9 +6,11 @@ import type { UserType } from '@fastgpt/global/support/user/type.d';
|
||||
import { getTokenLogin, putUserInfo } from '@/web/support/user/api';
|
||||
import { FeTeamPlanStatusType } from '@fastgpt/global/support/wallet/sub/type';
|
||||
import { getTeamPlanStatus } from './team/api';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
|
||||
type State = {
|
||||
systemMsgReadId: string;
|
||||
setSysMsgReadId: (id: string) => void;
|
||||
|
||||
userInfo: UserType | null;
|
||||
initUserInfo: () => Promise<UserType>;
|
||||
setUserInfo: (user: UserType | null) => void;
|
||||
@@ -21,6 +23,13 @@ export const useUserStore = create<State>()(
|
||||
devtools(
|
||||
persist(
|
||||
immer((set, get) => ({
|
||||
systemMsgReadId: '',
|
||||
setSysMsgReadId(id: string) {
|
||||
set((state) => {
|
||||
state.systemMsgReadId = id;
|
||||
});
|
||||
},
|
||||
|
||||
userInfo: null,
|
||||
async initUserInfo() {
|
||||
get().initTeamPlanStatus();
|
||||
@@ -71,7 +80,9 @@ export const useUserStore = create<State>()(
|
||||
})),
|
||||
{
|
||||
name: 'userStore',
|
||||
partialize: (state) => ({})
|
||||
partialize: (state) => ({
|
||||
systemMsgReadId: state.systemMsgReadId
|
||||
})
|
||||
}
|
||||
)
|
||||
)
|
||||
|
Reference in New Issue
Block a user