chat-container.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import { ChatContext } from '@/app/chat-context';
  2. import { apiInterceptors, getChatHistory } from '@/client/api';
  3. import useChat from '@/hooks/use-chat';
  4. import { ChartData, ChatHistoryResponse } from '@/types/chat';
  5. import { getInitMessage } from '@/utils';
  6. import { useAsyncEffect } from 'ahooks';
  7. import classNames from 'classnames';
  8. import { useSearchParams } from 'next/navigation';
  9. import { useCallback, useContext, useEffect, useState } from 'react';
  10. import Chart from '../chart';
  11. import MyEmpty from '../common/MyEmpty';
  12. import MuiLoading from '../common/loading';
  13. import Completion from './completion';
  14. import Header from './header';
  15. const ChatContainer = () => {
  16. const searchParams = useSearchParams();
  17. const { scene, chatId, model, agent, setModel, history, setHistory } = useContext(ChatContext);
  18. const { chat } = useChat({});
  19. const initMessage = (searchParams && searchParams.get('initMessage')) ?? '';
  20. const [loading, setLoading] = useState<boolean>(false);
  21. const [chartsData, setChartsData] = useState<Array<ChartData>>();
  22. const getHistory = async () => {
  23. setLoading(true);
  24. const [, res] = await apiInterceptors(getChatHistory(chatId));
  25. setHistory(res ?? []);
  26. setLoading(false);
  27. };
  28. const getChartsData = (list: ChatHistoryResponse) => {
  29. const contextTemp = list[list.length - 1]?.context;
  30. if (contextTemp) {
  31. try {
  32. const contextObj = typeof contextTemp === 'string' ? JSON.parse(contextTemp) : contextTemp;
  33. setChartsData(contextObj?.template_name === 'report' ? contextObj?.charts : undefined);
  34. } catch (e) {
  35. console.log(e);
  36. setChartsData([]);
  37. }
  38. }
  39. };
  40. useAsyncEffect(async () => {
  41. const initMessage = getInitMessage();
  42. if (initMessage && initMessage.id === chatId) return;
  43. await getHistory();
  44. }, [initMessage, chatId]);
  45. useEffect(() => {
  46. if (!history.length) return;
  47. /** use last view model_name as default model name */
  48. const lastView = history.filter(i => i.role === 'view')?.slice(-1)?.[0];
  49. lastView?.model_name && setModel(lastView.model_name);
  50. getChartsData(history);
  51. }, [history.length]);
  52. useEffect(() => {
  53. return () => {
  54. setHistory([]);
  55. };
  56. }, []);
  57. const handleChat = useCallback(
  58. (content: string, data?: Record<string, any>) => {
  59. return new Promise<void>(resolve => {
  60. const tempHistory: ChatHistoryResponse = [
  61. ...history,
  62. { role: 'human', context: content, model_name: model, order: 0, time_stamp: 0 },
  63. { role: 'view', context: '', model_name: model, order: 0, time_stamp: 0 },
  64. ];
  65. const index = tempHistory.length - 1;
  66. setHistory([...tempHistory]);
  67. chat({
  68. data: { ...data, chat_mode: scene || 'chat_normal', model_name: model, user_input: content },
  69. chatId,
  70. onMessage: message => {
  71. if (data?.incremental) {
  72. tempHistory[index].context += message;
  73. } else {
  74. tempHistory[index].context = message;
  75. }
  76. setHistory([...tempHistory]);
  77. },
  78. onDone: () => {
  79. getChartsData(tempHistory);
  80. resolve();
  81. },
  82. onClose: () => {
  83. getChartsData(tempHistory);
  84. resolve();
  85. },
  86. onError: message => {
  87. tempHistory[index].context = message;
  88. setHistory([...tempHistory]);
  89. resolve();
  90. },
  91. });
  92. });
  93. },
  94. [history, chat, chatId, model, agent, scene],
  95. );
  96. return (
  97. <>
  98. <MuiLoading visible={loading} />
  99. <Header
  100. refreshHistory={getHistory}
  101. modelChange={(newModel: string) => {
  102. setModel(newModel);
  103. }}
  104. />
  105. <div className='px-4 flex flex-1 flex-wrap overflow-hidden relative'>
  106. {!!chartsData?.length && (
  107. <div className='w-full pb-4 xl:w-3/4 h-1/2 xl:pr-4 xl:h-full overflow-y-auto'>
  108. <Chart chartsData={chartsData} />
  109. </div>
  110. )}
  111. {!chartsData?.length && scene === 'chat_dashboard' && <MyEmpty className='w-full xl:w-3/4 h-1/2 xl:h-full' />}
  112. {/** chat panel */}
  113. <div
  114. className={classNames('flex flex-1 flex-col overflow-hidden', {
  115. 'px-0 xl:pl-4 h-1/2 w-full xl:w-auto xl:h-full border-t xl:border-t-0 xl:border-l dark:border-gray-800':
  116. scene === 'chat_dashboard',
  117. 'h-full lg:px-8': scene !== 'chat_dashboard',
  118. })}
  119. >
  120. <Completion messages={history} onSubmit={handleChat} />
  121. </div>
  122. </div>
  123. </>
  124. );
  125. };
  126. export default ChatContainer;