mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-30 02:12:38 +00:00
v4.4.6 (#377)
This commit is contained in:
@@ -3,71 +3,39 @@ import { jsonRes } from '@/service/response';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { authUser } from '@/service/utils/auth';
|
||||
import { CreateQuestionGuideProps } from '@/api/core/ai/agent/type';
|
||||
import { getAIChatApi } from '@fastgpt/core/aiApi/config';
|
||||
import { Prompt_QuestionGuide } from '@/prompts/core/agent';
|
||||
import { pushQuestionGuideBill } from '@/service/common/bill/push';
|
||||
import { defaultQGModel } from '@/pages/api/system/getInitData';
|
||||
import { createQuestionGuide } from '@fastgpt/core/ai/functions/createQuestionGuide';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
await connectToDatabase();
|
||||
const { messages } = req.body as CreateQuestionGuideProps;
|
||||
const { user } = await authUser({ req, authToken: true, authApiKey: true, authBalance: true });
|
||||
const { user } = await authUser({
|
||||
req,
|
||||
authOutLink: true,
|
||||
authToken: true,
|
||||
authApiKey: true,
|
||||
authBalance: true
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
throw new Error('user not found');
|
||||
}
|
||||
const qgModel = global.qgModel || defaultQGModel;
|
||||
|
||||
const chatAPI = getAIChatApi(user.openaiAccount);
|
||||
|
||||
const { data } = await chatAPI.createChatCompletion({
|
||||
model: qgModel.model,
|
||||
temperature: 0,
|
||||
max_tokens: 200,
|
||||
messages: [
|
||||
...messages,
|
||||
{
|
||||
role: 'user',
|
||||
content: Prompt_QuestionGuide
|
||||
}
|
||||
],
|
||||
stream: false
|
||||
const { result, tokens } = await createQuestionGuide({
|
||||
messages,
|
||||
model: (global.qgModel || defaultQGModel).model
|
||||
});
|
||||
|
||||
const answer = data.choices?.[0].message?.content || '';
|
||||
const totalTokens = data.usage?.total_tokens || 0;
|
||||
jsonRes(res, {
|
||||
data: result
|
||||
});
|
||||
|
||||
const start = answer.indexOf('[');
|
||||
const end = answer.lastIndexOf(']');
|
||||
|
||||
if (start === -1 || end === -1) {
|
||||
return jsonRes(res, {
|
||||
data: []
|
||||
});
|
||||
}
|
||||
|
||||
const jsonStr = answer
|
||||
.substring(start, end + 1)
|
||||
.replace(/(\\n|\\)/g, '')
|
||||
.replace(/ /g, '');
|
||||
|
||||
try {
|
||||
jsonRes(res, {
|
||||
data: JSON.parse(jsonStr)
|
||||
});
|
||||
|
||||
pushQuestionGuideBill({
|
||||
tokens: totalTokens,
|
||||
userId: user._id
|
||||
});
|
||||
|
||||
return;
|
||||
} catch (error) {
|
||||
return jsonRes(res, {
|
||||
data: []
|
||||
});
|
||||
}
|
||||
pushQuestionGuideBill({
|
||||
tokens: tokens,
|
||||
userId: user._id
|
||||
});
|
||||
} catch (err) {
|
||||
jsonRes(res, {
|
||||
code: 500,
|
||||
|
@@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/service/response';
|
||||
import { authBalanceByUid, authUser } from '@/service/utils/auth';
|
||||
import { withNextCors } from '@/service/utils/tools';
|
||||
import { getAIChatApi, axiosConfig } from '@fastgpt/core/aiApi/config';
|
||||
import { getAIChatApi, axiosConfig } from '@fastgpt/core/ai/config';
|
||||
import { pushGenerateVectorBill } from '@/service/common/bill/push';
|
||||
|
||||
type Props = {
|
||||
|
@@ -5,7 +5,7 @@ import { User } from '@/service/models/user';
|
||||
import { connectToDatabase } from '@/service/mongo';
|
||||
import { authUser } from '@/service/utils/auth';
|
||||
import { UserUpdateParams } from '@/types/user';
|
||||
import { axiosConfig, getAIChatApi, openaiBaseUrl } from '@fastgpt/core/aiApi/config';
|
||||
import { axiosConfig, getAIChatApi, openaiBaseUrl } from '@fastgpt/core/ai/config';
|
||||
|
||||
/* update user info */
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
|
@@ -12,9 +12,10 @@ import {
|
||||
dispatchAnswer,
|
||||
dispatchClassifyQuestion,
|
||||
dispatchContentExtract,
|
||||
dispatchHttpRequest
|
||||
dispatchHttpRequest,
|
||||
dispatchAppRequest
|
||||
} from '@/service/moduleDispatch';
|
||||
import type { CreateChatCompletionRequest } from '@fastgpt/core/aiApi/type';
|
||||
import type { CreateChatCompletionRequest } from '@fastgpt/core/ai/type';
|
||||
import type { MessageItemType } from '@/types/core/chat/type';
|
||||
import { gptMessage2ChatType, textAdaptGptResponse } from '@/utils/adapt';
|
||||
import { getChatHistory } from './getHistory';
|
||||
@@ -325,14 +326,19 @@ export async function dispatchModules({
|
||||
responseData
|
||||
}: {
|
||||
answerText?: string;
|
||||
responseData?: ChatHistoryItemResType;
|
||||
responseData?: ChatHistoryItemResType | ChatHistoryItemResType[];
|
||||
}) {
|
||||
const time = Date.now();
|
||||
responseData &&
|
||||
chatResponse.push({
|
||||
...responseData,
|
||||
runningTime: +((time - runningTime) / 1000).toFixed(2)
|
||||
});
|
||||
if (responseData) {
|
||||
if (Array.isArray(responseData)) {
|
||||
chatResponse = chatResponse.concat(responseData);
|
||||
} else {
|
||||
chatResponse.push({
|
||||
...responseData,
|
||||
runningTime: +((time - runningTime) / 1000).toFixed(2)
|
||||
});
|
||||
}
|
||||
}
|
||||
runningTime = time;
|
||||
chatAnswerText += answerText;
|
||||
}
|
||||
@@ -411,7 +417,7 @@ export async function dispatchModules({
|
||||
variables,
|
||||
moduleName: module.name,
|
||||
outputs: module.outputs,
|
||||
userOpenaiAccount: user?.openaiAccount,
|
||||
user,
|
||||
inputs: params
|
||||
};
|
||||
|
||||
@@ -424,7 +430,8 @@ export async function dispatchModules({
|
||||
[FlowModuleTypeEnum.kbSearchNode]: dispatchKBSearch,
|
||||
[FlowModuleTypeEnum.classifyQuestion]: dispatchClassifyQuestion,
|
||||
[FlowModuleTypeEnum.contentExtract]: dispatchContentExtract,
|
||||
[FlowModuleTypeEnum.httpRequest]: dispatchHttpRequest
|
||||
[FlowModuleTypeEnum.httpRequest]: dispatchHttpRequest,
|
||||
[FlowModuleTypeEnum.app]: dispatchAppRequest
|
||||
};
|
||||
if (callbackMap[module.flowType]) {
|
||||
return callbackMap[module.flowType](props);
|
||||
|
@@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import NodeCard from '../modules/NodeCard';
|
||||
import { FlowModuleItemType } from '@/types/core/app/flow';
|
||||
import Divider from '../modules/Divider';
|
||||
import Container from '../modules/Container';
|
||||
import RenderInput from '../render/RenderInput';
|
||||
import RenderOutput from '../render/RenderOutput';
|
||||
|
||||
const NodeAPP = ({ data }: NodeProps<FlowModuleItemType>) => {
|
||||
const { moduleId, inputs, outputs } = data;
|
||||
|
||||
return (
|
||||
<NodeCard minW={'350px'} {...data}>
|
||||
<Container borderTop={'2px solid'} borderTopColor={'myGray.200'}>
|
||||
<RenderInput moduleId={moduleId} flowInputList={inputs} />
|
||||
</Container>
|
||||
<Divider text="Output" />
|
||||
<Container>
|
||||
<RenderOutput moduleId={moduleId} flowOutputList={outputs} />
|
||||
</Container>
|
||||
</NodeCard>
|
||||
);
|
||||
};
|
||||
export default React.memo(NodeAPP);
|
@@ -35,6 +35,7 @@ const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
|
||||
|
||||
type OnChange<ChangesType> = (changes: ChangesType[]) => void;
|
||||
export type useFlowStoreType = {
|
||||
appId: string;
|
||||
reactFlowWrapper: null | React.RefObject<HTMLDivElement>;
|
||||
nodes: Node<FlowModuleItemType, string | undefined>[];
|
||||
setNodes: Dispatch<SetStateAction<Node<FlowModuleItemType, string | undefined>[]>>;
|
||||
@@ -58,6 +59,7 @@ export type useFlowStoreType = {
|
||||
};
|
||||
|
||||
const StateContext = createContext<useFlowStoreType>({
|
||||
appId: '',
|
||||
reactFlowWrapper: null,
|
||||
nodes: [],
|
||||
setNodes: function (
|
||||
@@ -109,7 +111,7 @@ const StateContext = createContext<useFlowStoreType>({
|
||||
});
|
||||
export const useFlowStore = () => useContext(StateContext);
|
||||
|
||||
export const FlowProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
export const FlowProvider = ({ appId, children }: { appId: string; children: React.ReactNode }) => {
|
||||
const reactFlowWrapper = useRef<HTMLDivElement>(null);
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToast();
|
||||
@@ -209,7 +211,6 @@ export const FlowProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
const reactFlowBounds = reactFlowWrapper.current.getBoundingClientRect();
|
||||
const mouseX = (position.x - reactFlowBounds.left - x) / zoom - 100;
|
||||
const mouseY = (position.y - reactFlowBounds.top - y) / zoom;
|
||||
console.log(template);
|
||||
setNodes((state) =>
|
||||
state.concat(
|
||||
appModule2FlowNode({
|
||||
@@ -328,6 +329,7 @@ export const FlowProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
);
|
||||
|
||||
const value = {
|
||||
appId,
|
||||
reactFlowWrapper,
|
||||
nodes,
|
||||
setNodes,
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import React, { useState } from 'react';
|
||||
import type { FlowInputItemType } from '@/types/core/app/flow';
|
||||
import type { FlowInputItemType, SelectAppItemType } from '@/types/core/app/flow';
|
||||
import {
|
||||
Box,
|
||||
Textarea,
|
||||
@@ -9,7 +9,10 @@ import {
|
||||
NumberInputStepper,
|
||||
NumberIncrementStepper,
|
||||
NumberDecrementStepper,
|
||||
Flex
|
||||
Flex,
|
||||
useDisclosure,
|
||||
Button,
|
||||
useTheme
|
||||
} from '@chakra-ui/react';
|
||||
import { FlowInputItemTypeEnum } from '@/constants/flow';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
@@ -20,7 +23,9 @@ import MyTooltip from '@/components/MyTooltip';
|
||||
import TargetHandle from './TargetHandle';
|
||||
import MyIcon from '@/components/Icon';
|
||||
const SetInputFieldModal = dynamic(() => import('../modules/SetInputFieldModal'));
|
||||
const SelectAppModal = dynamic(() => import('../../../SelectAppModal'));
|
||||
import { useFlowStore } from '../Provider';
|
||||
import Avatar from '@/components/Avatar';
|
||||
|
||||
export const Label = ({
|
||||
moduleId,
|
||||
@@ -141,6 +146,7 @@ const RenderInput = ({
|
||||
CustomComponent?: Record<string, (e: FlowInputItemType) => React.ReactNode>;
|
||||
}) => {
|
||||
const { onChangeNode } = useFlowStore();
|
||||
|
||||
return (
|
||||
<>
|
||||
{flowInputList.map(
|
||||
@@ -253,6 +259,9 @@ const RenderInput = ({
|
||||
{item.type === FlowInputItemTypeEnum.custom && CustomComponent[item.key] && (
|
||||
<>{CustomComponent[item.key]({ ...item })}</>
|
||||
)}
|
||||
{item.type === FlowInputItemTypeEnum.selectApp && (
|
||||
<RenderSelectApp app={item} moduleId={moduleId} />
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
@@ -262,3 +271,54 @@ const RenderInput = ({
|
||||
};
|
||||
|
||||
export default React.memo(RenderInput);
|
||||
|
||||
function RenderSelectApp({ app, moduleId }: { app: FlowInputItemType; moduleId: string }) {
|
||||
const { onChangeNode, appId } = useFlowStore();
|
||||
const theme = useTheme();
|
||||
|
||||
const {
|
||||
isOpen: isOpenSelectApp,
|
||||
onOpen: onOpenSelectApp,
|
||||
onClose: onCloseSelectApp
|
||||
} = useDisclosure();
|
||||
|
||||
const value = app.value as SelectAppItemType | undefined;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box onClick={onOpenSelectApp}>
|
||||
{!value ? (
|
||||
<Button variant={'base'} w={'100%'}>
|
||||
选择应用
|
||||
</Button>
|
||||
) : (
|
||||
<Flex alignItems={'center'} border={theme.borders.base} borderRadius={'md'} px={3} py={2}>
|
||||
<Avatar src={value?.logo} />
|
||||
<Box fontWeight={'bold'} ml={1}>
|
||||
{value?.name}
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
{isOpenSelectApp && (
|
||||
<SelectAppModal
|
||||
defaultApps={app.value?.id ? [app.value.id] : []}
|
||||
filterApps={[appId]}
|
||||
onClose={onCloseSelectApp}
|
||||
onSuccess={(e) => {
|
||||
onChangeNode({
|
||||
moduleId,
|
||||
type: 'inputs',
|
||||
key: 'app',
|
||||
value: {
|
||||
...app,
|
||||
value: e[0]
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@@ -38,6 +38,7 @@ const NodeVariable = dynamic(() => import('./components/Nodes/NodeVariable'));
|
||||
const NodeUserGuide = dynamic(() => import('./components/Nodes/NodeUserGuide'));
|
||||
const NodeExtract = dynamic(() => import('./components/Nodes/NodeExtract'));
|
||||
const NodeHttp = dynamic(() => import('./components/Nodes/NodeHttp'));
|
||||
const NodeAPP = dynamic(() => import('./components/Nodes/NodeAPP'));
|
||||
|
||||
import 'reactflow/dist/style.css';
|
||||
|
||||
@@ -52,7 +53,8 @@ const nodeTypes = {
|
||||
[FlowModuleTypeEnum.answerNode]: NodeAnswer,
|
||||
[FlowModuleTypeEnum.classifyQuestion]: NodeCQNode,
|
||||
[FlowModuleTypeEnum.contentExtract]: NodeExtract,
|
||||
[FlowModuleTypeEnum.httpRequest]: NodeHttp
|
||||
[FlowModuleTypeEnum.httpRequest]: NodeHttp,
|
||||
[FlowModuleTypeEnum.app]: NodeAPP
|
||||
// [FlowModuleTypeEnum.empty]: EmptyModule
|
||||
};
|
||||
const edgeTypes = {
|
||||
@@ -116,8 +118,17 @@ function FlowHeader({ app, onCloseSettings }: Props & {}) {
|
||||
|
||||
const { mutate: onclickSave, isLoading } = useRequest({
|
||||
mutationFn: () => {
|
||||
const modules = flow2AppModules();
|
||||
// check required connect
|
||||
for (let i = 0; i < modules.length; i++) {
|
||||
const item = modules[i];
|
||||
if (item.inputs.find((input) => input.required && !input.connected)) {
|
||||
return Promise.reject(`【${item.name}】存在未连接的必填输入`);
|
||||
}
|
||||
}
|
||||
|
||||
return updateAppDetail(app._id, {
|
||||
modules: flow2AppModules(),
|
||||
modules: modules,
|
||||
type: AppTypeEnum.advanced
|
||||
});
|
||||
},
|
||||
@@ -314,7 +325,7 @@ const Flow = (data: Props) => {
|
||||
return (
|
||||
<Box h={'100%'} position={'fixed'} zIndex={999} top={0} left={0} right={0} bottom={0}>
|
||||
<ReactFlowProvider>
|
||||
<FlowProvider>
|
||||
<FlowProvider appId={data?.app?._id}>
|
||||
<Flex h={'100%'} flexDirection={'column'} bg={'#fff'}>
|
||||
{!!data.app._id && <AppEdit {...data} />}
|
||||
</Flex>
|
||||
|
@@ -69,7 +69,12 @@ export const DatasetSelectModal = ({
|
||||
tips={'仅能选择同一个索引模型的知识库'}
|
||||
onClose={onClose}
|
||||
>
|
||||
<ModalBody flex={['1 0 0', '0 0 auto']} maxH={'80vh'} overflowY={'auto'} userSelect={'none'}>
|
||||
<ModalBody
|
||||
flex={['1 0 0', '1 0 auto']}
|
||||
maxH={'80vh'}
|
||||
overflowY={['auto', 'unset']}
|
||||
userSelect={'none'}
|
||||
>
|
||||
<Grid gridTemplateColumns={['repeat(1,1fr)', 'repeat(2,1fr)', 'repeat(3,1fr)']} gridGap={3}>
|
||||
{filterKbList.selected.map((item) =>
|
||||
(() => {
|
||||
|
@@ -287,7 +287,6 @@ function DetailLogsModal({
|
||||
<Box pt={2} flex={'1 0 0'}>
|
||||
<ChatBox
|
||||
ref={ChatBoxRef}
|
||||
chatId={chatId}
|
||||
appAvatar={chat?.app.avatar}
|
||||
userAvatar={HUMAN_ICON}
|
||||
feedbackType={'admin'}
|
||||
|
110
projects/app/src/pages/app/detail/components/SelectAppModal.tsx
Normal file
110
projects/app/src/pages/app/detail/components/SelectAppModal.tsx
Normal file
@@ -0,0 +1,110 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { ModalBody, Flex, Box, useTheme, ModalFooter, Button } from '@chakra-ui/react';
|
||||
import MyModal from '@/components/MyModal';
|
||||
import { getMyModels } from '@/api/app';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import type { SelectAppItemType } from '@/types/core/app/flow';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useLoading } from '@/hooks/useLoading';
|
||||
|
||||
const SelectAppModal = ({
|
||||
defaultApps = [],
|
||||
filterApps = [],
|
||||
max = 1,
|
||||
onClose,
|
||||
onSuccess
|
||||
}: {
|
||||
defaultApps: string[];
|
||||
filterApps?: string[];
|
||||
max?: number;
|
||||
onClose: () => void;
|
||||
onSuccess: (e: SelectAppItemType[]) => void;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { Loading } = useLoading();
|
||||
const theme = useTheme();
|
||||
const [selectedApps, setSelectedApps] = React.useState<string[]>(defaultApps);
|
||||
/* 加载模型 */
|
||||
const { data = [], isLoading } = useQuery(['loadMyApos'], () => getMyModels());
|
||||
|
||||
const apps = useMemo(
|
||||
() => data.filter((app) => !filterApps.includes(app._id)),
|
||||
[data, filterApps]
|
||||
);
|
||||
|
||||
return (
|
||||
<MyModal
|
||||
isOpen
|
||||
title={`选择应用${max > 1 ? `(${selectedApps.length}/${max})` : ''}`}
|
||||
onClose={onClose}
|
||||
w={'700px'}
|
||||
position={'relative'}
|
||||
>
|
||||
<ModalBody
|
||||
minH={'300px'}
|
||||
display={'grid'}
|
||||
gridTemplateColumns={['1fr', 'repeat(3,1fr)']}
|
||||
gridGap={4}
|
||||
>
|
||||
{apps.map((app) => (
|
||||
<Flex
|
||||
key={app._id}
|
||||
alignItems={'center'}
|
||||
border={theme.borders.base}
|
||||
borderRadius={'md'}
|
||||
px={1}
|
||||
py={2}
|
||||
cursor={'pointer'}
|
||||
{...(selectedApps.includes(app._id)
|
||||
? {
|
||||
bg: 'myBlue.200',
|
||||
onClick: () => {
|
||||
setSelectedApps(selectedApps.filter((e) => e !== app._id));
|
||||
}
|
||||
}
|
||||
: {
|
||||
onClick: () => {
|
||||
if (max === 1) {
|
||||
setSelectedApps([app._id]);
|
||||
} else if (selectedApps.length < max) {
|
||||
setSelectedApps([...selectedApps, app._id]);
|
||||
}
|
||||
}
|
||||
})}
|
||||
>
|
||||
<Avatar src={app.avatar} w={['16px', '22px']} />
|
||||
<Box fontWeight={'bold'} ml={1}>
|
||||
{app.name}
|
||||
</Box>
|
||||
</Flex>
|
||||
))}
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button variant={'base'} onClick={onClose}>
|
||||
{t('Cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
ml={2}
|
||||
onClick={() => {
|
||||
onSuccess(
|
||||
apps
|
||||
.filter((app) => selectedApps.includes(app._id))
|
||||
.map((app) => ({
|
||||
id: app._id,
|
||||
name: app.name,
|
||||
logo: app.avatar
|
||||
}))
|
||||
);
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
{t('Confirm')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
<Loading loading={isLoading} fixed={false} />
|
||||
</MyModal>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(SelectAppModal);
|
@@ -64,7 +64,7 @@ const MyApps = () => {
|
||||
);
|
||||
|
||||
/* 加载模型 */
|
||||
useQuery(['loadModels'], () => loadMyApps(true), {
|
||||
useQuery(['loadApps'], () => loadMyApps(true), {
|
||||
refetchOnMount: true
|
||||
});
|
||||
|
||||
|
@@ -8,7 +8,6 @@ import { useRouter } from 'next/router';
|
||||
const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
|
||||
const { onExportChat } = useChatBox();
|
||||
const router = useRouter();
|
||||
const { appId, shareId } = router.query;
|
||||
|
||||
const menuList = useMemo(
|
||||
() => [
|
||||
@@ -18,8 +17,8 @@ const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
|
||||
onClick: () => {
|
||||
router.replace({
|
||||
query: {
|
||||
appId,
|
||||
shareId
|
||||
...router.query,
|
||||
chatId: ''
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -36,7 +35,7 @@ const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
|
||||
},
|
||||
{ icon: 'pdf', label: 'PDF导出', onClick: () => onExportChat({ type: 'pdf', history }) }
|
||||
],
|
||||
[appId, history, onExportChat, router, shareId]
|
||||
[history, onExportChat, router]
|
||||
);
|
||||
|
||||
return history.length > 0 ? (
|
||||
|
@@ -358,7 +358,6 @@ const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
|
||||
<ChatBox
|
||||
ref={ChatBoxRef}
|
||||
showEmptyIntro
|
||||
chatId={chatId}
|
||||
appAvatar={chatData.app.avatar}
|
||||
userAvatar={userInfo?.avatar}
|
||||
userGuideModule={chatData.app?.userGuideModule}
|
||||
|
@@ -24,10 +24,12 @@ import { serviceSideProps } from '@/utils/web/i18n';
|
||||
const OutLink = ({
|
||||
shareId,
|
||||
chatId,
|
||||
showHistory,
|
||||
authToken
|
||||
}: {
|
||||
shareId: string;
|
||||
chatId: string;
|
||||
showHistory: '0' | '1';
|
||||
authToken?: string;
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
@@ -89,9 +91,8 @@ const OutLink = ({
|
||||
forbidRefresh.current = true;
|
||||
router.replace({
|
||||
query: {
|
||||
shareId,
|
||||
chatId: completionChatId,
|
||||
authToken
|
||||
...router.query,
|
||||
chatId: completionChatId
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -174,59 +175,58 @@ const OutLink = ({
|
||||
<title>{shareChatData.app.name}</title>
|
||||
</Head>
|
||||
<Flex h={'100%'} flexDirection={['column', 'row']}>
|
||||
{((children: React.ReactNode) => {
|
||||
return isPc ? (
|
||||
<SideBar>{children}</SideBar>
|
||||
) : (
|
||||
<Drawer
|
||||
isOpen={isOpenSlider}
|
||||
placement="left"
|
||||
autoFocus={false}
|
||||
size={'xs'}
|
||||
onClose={onCloseSlider}
|
||||
>
|
||||
<DrawerOverlay backgroundColor={'rgba(255,255,255,0.5)'} />
|
||||
<DrawerContent maxWidth={'250px'} boxShadow={'2px 0 10px rgba(0,0,0,0.15)'}>
|
||||
{children}
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
);
|
||||
})(
|
||||
<ChatHistorySlider
|
||||
appName={shareChatData.app.name}
|
||||
appAvatar={shareChatData.app.avatar}
|
||||
activeChatId={chatId}
|
||||
history={history.map((item) => ({
|
||||
id: item.chatId,
|
||||
title: item.title
|
||||
}))}
|
||||
onClose={onCloseSlider}
|
||||
onChangeChat={(chatId) => {
|
||||
console.log(chatId);
|
||||
|
||||
router.replace({
|
||||
query: {
|
||||
chatId: chatId || '',
|
||||
shareId,
|
||||
authToken
|
||||
}
|
||||
});
|
||||
if (!isPc) {
|
||||
onCloseSlider();
|
||||
}
|
||||
}}
|
||||
onDelHistory={delOneShareHistoryByChatId}
|
||||
onClearHistory={() => {
|
||||
delManyShareChatHistoryByShareId(shareId);
|
||||
router.replace({
|
||||
query: {
|
||||
shareId,
|
||||
authToken
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{showHistory === '1'
|
||||
? ((children: React.ReactNode) => {
|
||||
return isPc ? (
|
||||
<SideBar>{children}</SideBar>
|
||||
) : (
|
||||
<Drawer
|
||||
isOpen={isOpenSlider}
|
||||
placement="left"
|
||||
autoFocus={false}
|
||||
size={'xs'}
|
||||
onClose={onCloseSlider}
|
||||
>
|
||||
<DrawerOverlay backgroundColor={'rgba(255,255,255,0.5)'} />
|
||||
<DrawerContent maxWidth={'250px'} boxShadow={'2px 0 10px rgba(0,0,0,0.15)'}>
|
||||
{children}
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
);
|
||||
})(
|
||||
<ChatHistorySlider
|
||||
appName={shareChatData.app.name}
|
||||
appAvatar={shareChatData.app.avatar}
|
||||
activeChatId={chatId}
|
||||
history={history.map((item) => ({
|
||||
id: item.chatId,
|
||||
title: item.title
|
||||
}))}
|
||||
onClose={onCloseSlider}
|
||||
onChangeChat={(chatId) => {
|
||||
router.replace({
|
||||
query: {
|
||||
...router.query,
|
||||
chatId: chatId || ''
|
||||
}
|
||||
});
|
||||
if (!isPc) {
|
||||
onCloseSlider();
|
||||
}
|
||||
}}
|
||||
onDelHistory={delOneShareHistoryByChatId}
|
||||
onClearHistory={() => {
|
||||
delManyShareChatHistoryByShareId(shareId);
|
||||
router.replace({
|
||||
query: {
|
||||
...router.query,
|
||||
chatId: ''
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)
|
||||
: null}
|
||||
|
||||
{/* chat container */}
|
||||
<Flex
|
||||
@@ -276,10 +276,11 @@ const OutLink = ({
|
||||
export async function getServerSideProps(context: any) {
|
||||
const shareId = context?.query?.shareId || '';
|
||||
const chatId = context?.query?.chatId || '';
|
||||
const showHistory = context?.query?.showHistory || '1';
|
||||
const authToken = context?.query?.authToken || '';
|
||||
|
||||
return {
|
||||
props: { shareId, chatId, authToken, ...(await serviceSideProps(context)) }
|
||||
props: { shareId, chatId, showHistory, authToken, ...(await serviceSideProps(context)) }
|
||||
};
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user