This commit is contained in:
Archer
2023-09-26 21:17:13 +08:00
committed by GitHub
parent a11e0bd9c3
commit 11848b8f44
34 changed files with 395 additions and 62 deletions

View File

@@ -24,7 +24,7 @@ import { feConfigs } from '@/store/static';
import { event } from '@/utils/plugin/eventbus';
import { adaptChat2GptMessages } from '@/utils/common/adapt/message';
import { useMarkdown } from '@/hooks/useMarkdown';
import { VariableItemType } from '@/types/app';
import { AppModuleItemType, VariableItemType } from '@/types/app';
import { VariableInputEnum } from '@/constants/app';
import { useForm } from 'react-hook-form';
import { MessageItemType } from '@/pages/api/openapi/v1/chat/completions';
@@ -51,6 +51,8 @@ const InputDataModal = dynamic(() => import('@/pages/kb/detail/components/InputD
import styles from './index.module.scss';
import Script from 'next/script';
import { postQuestionGuide } from '@/api/core/ai/agent/api';
import { splitGuideModule } from './utils';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 24);
@@ -137,8 +139,7 @@ const ChatBox = (
chatId,
appAvatar,
userAvatar,
variableModules,
welcomeText,
userGuideModule,
active = true,
onUpdateVariable,
onStartChat,
@@ -151,8 +152,7 @@ const ChatBox = (
chatId?: string;
appAvatar?: string;
userAvatar?: string;
variableModules?: VariableItemType[];
welcomeText?: string;
userGuideModule?: AppModuleItemType;
active?: boolean;
onUpdateVariable?: (e: Record<string, any>) => void;
onStartChat?: (e: StartChatFnProps) => Promise<{
@@ -171,24 +171,28 @@ const ChatBox = (
const { toast } = useToast();
const { isPc } = useGlobalStore();
const TextareaDom = useRef<HTMLTextAreaElement>(null);
const controller = useRef(new AbortController());
const chatController = useRef(new AbortController());
const questionGuideController = useRef(new AbortController());
const [refresh, setRefresh] = useState(false);
const [variables, setVariables] = useState<Record<string, any>>({});
const [variables, setVariables] = useState<Record<string, any>>({}); // settings variable
const [chatHistory, setChatHistory] = useState<ChatSiteItemType[]>([]);
const [feedbackId, setFeedbackId] = useState<string>();
const [readFeedbackData, setReadFeedbackData] = useState<{
// read feedback modal data
chatItemId: string;
content: string;
isMarked: boolean;
}>();
const [adminMarkData, setAdminMarkData] = useState<{
// mark modal data
kbId?: string;
chatItemId: string;
dataId?: string;
q: string;
a: string;
}>();
const [questionGuides, setQuestionGuide] = useState<string[]>([]);
const isChatting = useMemo(
() =>
@@ -196,6 +200,12 @@ const ChatBox = (
chatHistory[chatHistory.length - 1]?.status !== 'finish',
[chatHistory]
);
const { welcomeText, variableModules, questionGuide } = useMemo(
() => splitGuideModule(userGuideModule),
[userGuideModule]
);
// compute variable input is finish.
const [variableInputFinish, setVariableInputFinish] = useState(false);
const variableIsFinish = useMemo(() => {
@@ -287,6 +297,32 @@ const ChatBox = (
}, 100);
}, []);
// create question guide
const createQuestionGuide = useCallback(
async ({ history }: { history: ChatSiteItemType[] }) => {
if (!questionGuide || chatController.current?.signal?.aborted) return;
try {
const abortSignal = new AbortController();
questionGuideController.current = abortSignal;
const result = await postQuestionGuide(
{
messages: adaptChat2GptMessages({ messages: history, reserveId: false }).slice(-6)
},
abortSignal
);
if (Array.isArray(result)) {
setQuestionGuide(result);
setTimeout(() => {
scrollToBottom();
}, 100);
}
} catch (error) {}
},
[questionGuide, scrollToBottom]
);
/**
* user confirm send prompt
*/
@@ -300,6 +336,7 @@ const ChatBox = (
});
return;
}
questionGuideController.current?.abort('stop');
// get input value
const val = inputVal.trim();
@@ -332,6 +369,7 @@ const ChatBox = (
// 清空输入内容
resetInputVal('');
setQuestionGuide([]);
setTimeout(() => {
scrollToBottom();
}, 100);
@@ -339,11 +377,11 @@ const ChatBox = (
try {
// create abort obj
const abortSignal = new AbortController();
controller.current = abortSignal;
chatController.current = abortSignal;
const messages = adaptChat2GptMessages({ messages: newChatList, reserveId: true });
const { responseData } = await onStartChat({
const { responseData, responseText } = await onStartChat({
chatList: newChatList,
messages,
controller: abortSignal,
@@ -364,6 +402,16 @@ const ChatBox = (
);
setTimeout(() => {
createQuestionGuide({
history: newChatList.map((item, i) =>
i === newChatList.length - 1
? {
...item,
value: responseText
}
: item
)
});
generatingScroll();
isPc && TextareaDom.current?.focus();
}, 100);
@@ -393,13 +441,14 @@ const ChatBox = (
}
},
[
isChatting,
chatHistory,
onStartChat,
isChatting,
resetInputVal,
toast,
scrollToBottom,
onStartChat,
generatingMessage,
createQuestionGuide,
generatingScroll,
isPc
]
@@ -494,7 +543,8 @@ const ChatBox = (
// page change and abort request
useEffect(() => {
return () => {
controller.current?.abort('leave');
chatController.current?.abort('leave');
questionGuideController.current?.abort('leave');
// close voice
cancelBroadcast();
};
@@ -528,6 +578,7 @@ const ChatBox = (
<Flex flexDirection={'column'} h={'100%'}>
<Script src="/js/html2pdf.bundle.min.js" strategy="lazyOnload"></Script>
{/* chat box container */}
<Box ref={ChatBoxRef} flex={'1 0 0'} h={0} w={'100%'} overflow={'overlay'} px={[4, 0]} pb={3}>
<Box id="chat-container" maxW={['100%', '92%']} h={'100%'} mx={'auto'}>
{showEmpty && <Empty />}
@@ -839,6 +890,43 @@ const ChatBox = (
contentId={item.dataId}
responseData={item.responseData}
/>
{/* question guide */}
{index === chatHistory.length - 1 &&
!isChatting &&
questionGuides.length > 0 && (
<Flex
mt={2}
borderTop={theme.borders.sm}
alignItems={'center'}
flexWrap={'wrap'}
>
<Box
color={'myGray.500'}
mt={2}
mr={2}
fontSize={'sm'}
fontStyle={'italic'}
>
{t('chat.Question Guide Tips')}
</Box>
{questionGuides.map((item) => (
<Button
mt={2}
key={item}
mr="2"
borderRadius={'md'}
variant={'outline'}
colorScheme={'gray'}
size={'xs'}
onClick={() => {
resetInputVal(item);
}}
>
{item}
</Button>
))}
</Flex>
)}
{/* admin mark content */}
{showMarkIcon && item.adminFeedback && (
<Box>
@@ -928,7 +1016,7 @@ const ChatBox = (
cursor={'pointer'}
name={'stop'}
color={'gray.500'}
onClick={() => controller.current?.abort('stop')}
onClick={() => chatController.current?.abort('stop')}
/>
) : (
<MyIcon

View File

@@ -3,18 +3,24 @@ import { FlowModuleTypeEnum } from '@/constants/flow';
import { getChatModel } from '@/service/utils/data';
import { AppModuleItemType, VariableItemType } from '@/types/app';
export const getGuideModules = (modules: AppModuleItemType[]) => {
const guideModules = modules.find((item) => item.flowType === FlowModuleTypeEnum.userGuide);
export const getGuideModule = (modules: AppModuleItemType[]) =>
modules.find((item) => item.flowType === FlowModuleTypeEnum.userGuide);
export const splitGuideModule = (guideModules?: AppModuleItemType) => {
const welcomeText: string =
guideModules?.inputs?.find((item) => item.key === SystemInputEnum.welcomeText)?.value || '';
const variableModules: VariableItemType[] =
guideModules?.inputs.find((item) => item.key === SystemInputEnum.variables)?.value || [];
const questionGuide: boolean =
guideModules?.inputs?.find((item) => item.key === SystemInputEnum.questionGuide)?.value ||
false;
return {
welcomeText,
variableModules
variableModules,
questionGuide
};
};
export const getChatModelNameList = (modules: AppModuleItemType[]): string[] => {

View File

@@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd"
d="M10.8275 1.33325H5.17245C4.63581 1.33324 4.19289 1.33324 3.8321 1.36272C3.45737 1.39333 3.1129 1.45904 2.78934 1.6239C2.28758 1.87956 1.87963 2.28751 1.62397 2.78928C1.45911 3.11284 1.3934 3.4573 1.36278 3.83204C1.3333 4.19283 1.33331 4.63574 1.33332 5.17239L1.33328 9.42497C1.333 9.95523 1.33278 10.349 1.42418 10.6901C1.67076 11.6103 2.38955 12.3291 3.3098 12.5757C3.51478 12.6306 3.73878 12.6525 3.99998 12.6611L3.99998 13.5806C3.99995 13.7374 3.99992 13.8973 4.01182 14.0283C4.0232 14.1536 4.05333 14.3901 4.21844 14.5969C4.40843 14.8349 4.69652 14.9734 5.00106 14.973C5.26572 14.9728 5.46921 14.8486 5.57416 14.7792C5.6839 14.7066 5.80872 14.6067 5.93117 14.5087L7.53992 13.2217C7.88564 12.9451 7.98829 12.8671 8.09494 12.8126C8.20192 12.7579 8.3158 12.718 8.43349 12.6938C8.55081 12.6697 8.67974 12.6666 9.12248 12.6666H10.8275C11.3642 12.6666 11.8071 12.6666 12.1679 12.6371C12.5426 12.6065 12.8871 12.5408 13.2106 12.3759C13.7124 12.1203 14.1203 11.7123 14.376 11.2106C14.5409 10.887 14.6066 10.5425 14.6372 10.1678C14.6667 9.80701 14.6667 9.36411 14.6667 8.82747V5.17237C14.6667 4.63573 14.6667 4.19283 14.6372 3.83204C14.6066 3.4573 14.5409 3.11284 14.376 2.78928C14.1203 2.28751 13.7124 1.87956 13.2106 1.6239C12.8871 1.45904 12.5426 1.39333 12.1679 1.36272C11.8071 1.33324 11.3642 1.33324 10.8275 1.33325ZM8.99504 4.99992C8.99504 4.44763 9.44275 3.99992 9.99504 3.99992C10.5473 3.99992 10.995 4.44763 10.995 4.99992C10.995 5.5522 10.5473 5.99992 9.99504 5.99992C9.44275 5.99992 8.99504 5.5522 8.99504 4.99992ZM4.92837 7.79996C5.222 7.57974 5.63816 7.63837 5.85961 7.93051C5.90071 7.98295 5.94593 8.03229 5.99199 8.08035C6.09019 8.18282 6.23775 8.32184 6.42882 8.4608C6.81353 8.74059 7.3454 8.99996 7.99504 8.99996C8.64469 8.99996 9.17655 8.74059 9.56126 8.4608C9.75233 8.32184 9.89989 8.18282 9.99809 8.08035C10.0441 8.0323 10.0894 7.98294 10.1305 7.93051C10.3519 7.63837 10.7681 7.57974 11.0617 7.79996C11.3563 8.02087 11.416 8.43874 11.195 8.73329C11.1967 8.73112 11.1928 8.7361 11.186 8.74466C11.1697 8.7651 11.1372 8.80597 11.1261 8.81916C11.087 8.86575 11.0317 8.92884 10.9607 9.00289C10.8194 9.15043 10.6128 9.34474 10.3455 9.53912C9.81353 9.92599 9.01206 10.3333 7.99504 10.3333C6.97802 10.3333 6.17655 9.92599 5.64459 9.53912C5.37733 9.34474 5.17072 9.15043 5.02934 9.00289C4.95837 8.92884 4.90305 8.86575 4.86395 8.81916C4.84438 8.79585 4.82881 8.77659 4.81731 8.76207C4.58702 8.46455 4.61798 8.03275 4.92837 7.79996ZM5.99504 3.99992C5.44275 3.99992 4.99504 4.44763 4.99504 4.99992C4.99504 5.5522 5.44275 5.99992 5.99504 5.99992C6.54732 5.99992 6.99504 5.5522 6.99504 4.99992C6.99504 4.44763 6.54732 3.99992 5.99504 3.99992Z"
fill="#06AED4"></path>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -86,7 +86,8 @@ const iconPaths = {
rightArrowLight: () => import('./icons/light/rightArrow.svg'),
searchLight: () => import('./icons/light/search.svg'),
plusFill: () => import('./icons/fill/plus.svg'),
moveLight: () => import('./icons/light/move.svg')
moveLight: () => import('./icons/light/move.svg'),
questionGuide: () => import('./icons/app/questionGuide.svg')
};
export type IconName = keyof typeof iconPaths;