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:
Archer
2024-03-26 12:09:31 +08:00
committed by GitHub
parent ef15ca894e
commit 911512b36d
180 changed files with 2179 additions and 1361 deletions

View File

@@ -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,

View File

@@ -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]
)
};
};

View File

@@ -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 = () => {

View File

@@ -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,

View File

@@ -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: []
}
]
}

View File

@@ -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';

View File

@@ -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');

View File

@@ -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`);

View File

@@ -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
})
}
)
)