From ba8844e798c0453021e9f7b1f816f8f76270f3f6 Mon Sep 17 00:00:00 2001 From: "changhuiping.chp" <392752049@qq.com> Date: Wed, 19 Jul 2023 18:14:16 +0800 Subject: [PATCH 1/7] fix: update code from db-gpt --- app/agents/layout.tsx | 13 - app/agents/page.tsx | 214 ----------- app/chat/page.tsx | 216 ++++++++++- app/datastores/documents/page.tsx | 588 +++++++++++++++--------------- app/datastores/page.tsx | 1 - hooks/useAgentChat.ts | 304 ++++++++------- 6 files changed, 650 insertions(+), 686 deletions(-) delete mode 100644 app/agents/layout.tsx delete mode 100644 app/agents/page.tsx diff --git a/app/agents/layout.tsx b/app/agents/layout.tsx deleted file mode 100644 index 8c94ab3..0000000 --- a/app/agents/layout.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { Box } from '@/lib/mui'; - -export default function RootLayout({ - children, -}: { - children: React.ReactNode -}) { - return ( - <> - {children} - - ) -} diff --git a/app/agents/page.tsx b/app/agents/page.tsx deleted file mode 100644 index 3dcd846..0000000 --- a/app/agents/page.tsx +++ /dev/null @@ -1,214 +0,0 @@ -"use client" -import ChatBoxComp from '@/components/chatBox'; -import { Chart, LineAdvance, Interval, Tooltip, getTheme } from 'bizcharts'; -import { Card, CardContent, Typography, Grid, styled, Sheet } from '@/lib/mui'; -import { Stack } from '@mui/material'; -import useAgentChat from '@/hooks/useAgentChat'; - - -const Item = styled(Sheet)(({ theme }) => ({ - ...theme.typography.body2, - padding: theme.spacing(1), - textAlign: 'center', - borderRadius: 4, - color: theme.vars.palette.text.secondary, -})); - -const Agents = () => { - const { handleChatSubmit, history } = useAgentChat({ - queryAgentURL: `/v1/chat/completions`, - }); - - const data = [ - { - month: "Jan", - city: "Tokyo", - temperature: 7 - }, - { - month: "Feb", - city: "Tokyo", - temperature: 13 - }, - { - month: "Mar", - city: "Tokyo", - temperature: 16.5 - }, - { - month: "Apr", - city: "Tokyo", - temperature: 14.5 - }, - { - month: "May", - city: "Tokyo", - temperature: 10 - }, - { - month: "Jun", - city: "Tokyo", - temperature: 7.5 - }, - { - month: "Jul", - city: "Tokyo", - temperature: 9.2 - }, - { - month: "Aug", - city: "Tokyo", - temperature: 14.5 - }, - { - month: "Sep", - city: "Tokyo", - temperature: 9.3 - }, - { - month: "Oct", - city: "Tokyo", - temperature: 8.3 - }, - { - month: "Nov", - city: "Tokyo", - temperature: 8.9 - }, - { - month: "Dec", - city: "Tokyo", - temperature: 5.6 - }, - ]; - - const d1 = [ - { year: '1951 年', sales: 0 }, - { year: '1952 年', sales: 52 }, - { year: '1956 年', sales: 61 }, - { year: '1957 年', sales: 45 }, - { year: '1958 年', sales: 48 }, - { year: '1959 年', sales: 38 }, - { year: '1960 年', sales: 38 }, - { year: '1962 年', sales: 38 }, - ]; - - const topCard = [{ - label: 'Revenue Won', - value: '$7,811,851' - }, { - label: 'Close %', - value: '37.7%' - }, { - label: 'AVG Days to Close', - value: '121' - }, { - label: 'Opportunities Won', - value: '526' - }]; - - return ( -
-
- - - - - - {topCard.map((item) => ( - - - - - {item.label} - - - {item.value} - - - - - ))} - - - - - - - Revenue Won by Month - -
- - - -
-
-
-
- - - - - - - Close % by Month - -
- - - - -
-
-
-
- - - - - Close % by Month - -
- - - - -
-
-
-
- - - - - Close % by Month - -
- - - - -
-
-
-
-
-
-
-
- - - -
-
-
- ) -} - -export default Agents; \ No newline at end of file diff --git a/app/chat/page.tsx b/app/chat/page.tsx index 529b56e..4141230 100644 --- a/app/chat/page.tsx +++ b/app/chat/page.tsx @@ -1,10 +1,14 @@ "use client" import { useRequest } from 'ahooks'; import { sendGetRequest, sendPostRequest } from '@/utils/request'; +import { Card, CardContent, Typography, Grid, Table } from "@/lib/mui"; import useAgentChat from '@/hooks/useAgentChat'; import ChatBoxComp from '@/components/chatBoxTemp'; import { useDialogueContext } from '@/app/context/dialogue'; import { useSearchParams } from 'next/navigation'; +import { useMemo } from 'react'; +import { Chart, LineAdvance, Interval, Tooltip, getTheme } from "bizcharts"; +import lodash from 'lodash'; const AgentPage = () => { const searchParams = useSearchParams(); @@ -33,17 +37,209 @@ const AgentPage = () => { initHistory: historyList?.data }); + const chartsData = useMemo(() => { + try { + const contextTemp = history?.[history.length - 1]?.context; + const contextObj = JSON.parse(contextTemp); + return contextObj?.template_name === 'sales_report' ? contextObj?.charts : undefined; + } catch (e) { + return undefined; + } + }, [history]); + + const chartRows = useMemo(() => { + if (chartsData) { + let res = []; + // 若是有类型为 IndicatorValue 的,提出去,独占一行 + const chartCalc = chartsData?.filter( + (item) => item.chart_type === "IndicatorValue" + ); + if (chartCalc.length > 0) { + res.push({ + rowIndex: res.length, + cols: chartCalc, + type: "IndicatorValue", + }); + } + let otherCharts = chartsData?.filter( + (item) => item.chart_type !== "IndicatorValue" + ); + let otherLength = otherCharts.length; + let curIndex = 0; + // charts 数量 3~8个,暂定每行排序 + let chartLengthMap = [ + [0], + [1], + [2], + [1, 2], + [1, 3], + [2, 1, 2], + [2, 1, 3], + [3, 1, 3], + [3, 2, 3], + ]; + let currentRowsSort = chartLengthMap[otherLength]; + currentRowsSort.forEach((item) => { + if (item > 0) { + const rowsItem = otherCharts.slice(curIndex, curIndex + item); + curIndex = curIndex + item; + res.push({ + rowIndex: res.length, + cols: rowsItem, + }); + } + }); + return res; + } + return undefined; + }, [chartsData]); + return ( - <> - { - await refreshDialogList(); - }} - messages={history || []} - onSubmit={handleChatSubmit} - paramsList={paramsList?.data} - /> - + + {chartsData && ( + +
+ {chartRows?.map((chartRow) => ( +
+ {chartRow.cols.map((col) => { + if (col.chart_type === "IndicatorValue") { + return ( +
+ {col.values.map((item) => ( +
+ + + + {item.name} + + {item.value} + + +
+ ))} +
+ ); + } else if (col.chart_type === "LineChart") { + return ( +
+ + + + {col.chart_name} + +
+ + + +
+
+
+
+ ); + } else if (col.chart_type === "BarChart") { + return ( +
+ + + + {col.chart_name} + +
+ + + + +
+
+
+
+ ); + } else if (col.chart_type === 'Table') { + const data = lodash.groupBy(col.values, 'type'); + return ( +
+ + + + + {col.chart_name} + +
+ + + + {Object.keys(data).map(key => ( + + ))} + + + + {Object.values(data)?.[0]?.map((value, i) => ( + + {Object.keys(data)?.map(k => ( + + ))} + + ))} + +
{key}
{data?.[k]?.[i].value || ''}
+
+
+
+
+ ) + } + })} +
+ ))} +
+
+ )} + +
+ { + await refreshDialogList(); + }} + messages={history || []} + onSubmit={handleChatSubmit} + paramsList={paramsList?.data} + /> +
+
+ +
) } diff --git a/app/datastores/documents/page.tsx b/app/datastores/documents/page.tsx index 3749145..acf10be 100644 --- a/app/datastores/documents/page.tsx +++ b/app/datastores/documents/page.tsx @@ -1,38 +1,34 @@ 'use client' -import { useRouter, useSearchParams } from 'next/navigation' +import { useRouter } from 'next/navigation' import React, { useState, useEffect } from 'react' +import { InboxOutlined } from '@ant-design/icons' +import CheckCircleOutlinedIcon from '@mui/icons-material/CheckCircleOutlined' +import ContentPasteSearchOutlinedIcon from '@mui/icons-material/ContentPasteSearchOutlined' +import type { UploadProps } from 'antd' +import { message, Upload } from 'antd' import { useColorScheme, + Modal, Button, - Table, Sheet, - Modal, - Box, Stack, + Box, Input, Textarea, - Chip, Switch, Typography, - Breadcrumbs, - Link, styled } from '@/lib/mui' -import moment from 'moment' -import { InboxOutlined } from '@ant-design/icons' -import CheckCircleOutlinedIcon from '@mui/icons-material/CheckCircleOutlined' -import CachedIcon from '@mui/icons-material/Cached' -import type { UploadProps } from 'antd' -import { Upload, Pagination, Popover, message } from 'antd' import { sendSpacePostRequest, sendSpaceUploadPostRequest } from '@/utils/request' const { Dragger } = Upload + const Item = styled(Sheet)(({ theme }) => ({ - width: '50%', + width: '33%', backgroundColor: theme.palette.mode === 'dark' ? theme.palette.background.level1 : '#fff', ...theme.typography.body2, @@ -41,7 +37,9 @@ const Item = styled(Sheet)(({ theme }) => ({ borderRadius: 4, color: theme.vars.palette.text.secondary })) -const stepsOfAddingDocument = [ + +const stepsOfAddingSpace = [ + 'Knowledge Space Config', 'Choose a Datasource type', 'Setup the Datasource' ] @@ -63,24 +61,22 @@ const documentTypeList = [ 'Upload a document, document type can be PDF, CSV, Text, PowerPoint, Word, Markdown' } ] -const page_size = 20 -const Documents = () => { +const Index = () => { const router = useRouter() - const spaceName = useSearchParams().get('name') - const { mode } = useColorScheme() - const [isAddDocumentModalShow, setIsAddDocumentModalShow] = - useState(false) const [activeStep, setActiveStep] = useState(0) const [documentType, setDocumentType] = useState('') - const [documents, setDocuments] = useState([]) + const [knowledgeSpaceList, setKnowledgeSpaceList] = useState([]) + const [isAddKnowledgeSpaceModalShow, setIsAddKnowledgeSpaceModalShow] = + useState(false) + const [knowledgeSpaceName, setKnowledgeSpaceName] = useState('') + const [owner, setOwner] = useState('') + const [description, setDescription] = useState('') const [webPageUrl, setWebPageUrl] = useState('') const [documentName, setDocumentName] = useState('') const [textSource, setTextSource] = useState('') const [text, setText] = useState('') const [originFileObj, setOriginFileObj] = useState(null) - const [total, setTotal] = useState(0) - const [current, setCurrent] = useState(0) const [synchChecked, setSynchChecked] = useState(true) const props: UploadProps = { name: 'file', @@ -97,217 +93,193 @@ const Documents = () => { } } useEffect(() => { - async function fetchDocuments() { - const data = await sendSpacePostRequest( - `/knowledge/${spaceName}/document/list`, - { - page: 1, - page_size - } - ) + async function fetchData() { + const data = await sendSpacePostRequest('/knowledge/space/list', {}) if (data.success) { - setDocuments(data.data.data) - setTotal(data.data.total) - setCurrent(data.data.page) + setKnowledgeSpaceList(data.data) } } - fetchDocuments() + fetchData() }, []) return ( -
- + - - { - router.push('/datastores') - }} - key="Knowledge Space" - underline="hover" - color="neutral" - fontSize="inherit" - > - Knowledge Space - - Documents - - - - {documents.length ? ( - <> - setIsAddKnowledgeSpaceModalShow(true)} + className="bg-[#E9EBEE] dark:bg-[#484848]" > - - - - - - - - - - - - - {documents.map((row: any) => ( - - - - - - - - - - ))} - -
NameTypeSizeLast SynchStatusResultOperation
{row.doc_name} - - {row.doc_type} - - {row.chunk_size} chunks{moment(row.last_sync).format('YYYY-MM-DD HH:MM:SS')} - - {row.status} - - - {(function () { - if (row.status === 'TODO' || row.status === 'RUNNING') { - return '' - } else if (row.status === 'FINISHED') { - return ( - - - SUCCESS - - - ) - } else { - return ( - - - FAILED - - - ) - } - })()} - - { - <> - - - - } -
- - { - const data = await sendSpacePostRequest( - `/knowledge/${spaceName}/document/list`, - { - page, - page_size - } - ) - if (data.success) { - setDocuments(data.data.data) - setTotal(data.data.total) - setCurrent(data.data.page) + + + + + + space + + + {knowledgeSpaceList.map((item: any, index: number) => ( + - - - ) : ( - <> - )} + onClick={() => { + router.push(`/datastores/documents?name=${item.name}`) + }} + className="bg-[#FFFFFF] dark:bg-[#484848]" + > + + + {item.name} + + + + + {item.vector_type} + + Vector + + + + {item.owner} + + Owner + + + + {item.docs || 0} + + Docs + + + + ))} + + + + + + + { alignItems: 'center', 'z-index': 1000 }} - open={isAddDocumentModalShow} - onClose={() => setIsAddDocumentModalShow(false)} + open={isAddKnowledgeSpaceModalShow} + onClose={() => setIsAddKnowledgeSpaceModalShow(false)} > { > - {stepsOfAddingDocument.map((item: any, index: number) => ( + {stepsOfAddingSpace.map((item: any, index: number) => ( { {activeStep === 0 ? ( + <> + + Knowledge Space Name: + setKnowledgeSpaceName(e.target.value)} + sx={{ marginBottom: '20px' }} + /> + Owner: + setOwner(e.target.value)} + sx={{ marginBottom: '20px' }} + /> + Description: + setDescription(e.target.value)} + sx={{ marginBottom: '20px' }} + /> + + + + ) : activeStep === 1 ? ( <> {documentTypeList.map((item: any) => ( @@ -367,7 +403,7 @@ const Documents = () => { }} onClick={() => { setDocumentType(item.type) - setActiveStep(1) + setActiveStep(2) }} > @@ -456,7 +492,7 @@ const Documents = () => { @@ -473,36 +509,23 @@ const Documents = () => { return } const data = await sendSpacePostRequest( - `/knowledge/${spaceName}/document/add`, + `/knowledge/${knowledgeSpaceName}/document/add`, { doc_name: documentName, content: webPageUrl, doc_type: 'URL' } ) - data.success && - synchChecked && - sendSpacePostRequest( - `/knowledge/${spaceName}/document/sync`, - { - doc_ids: [data.data] - } - ) if (data.success) { message.success('success') - setIsAddDocumentModalShow(false) - const data = await sendSpacePostRequest( - `/knowledge/${spaceName}/document/list`, - { - page: current, - page_size - } - ) - if (data.success) { - setDocuments(data.data.data) - setTotal(data.data.total) - setCurrent(data.data.page) - } + setIsAddKnowledgeSpaceModalShow(false) + synchChecked && + sendSpacePostRequest( + `/knowledge/${knowledgeSpaceName}/document/sync`, + { + doc_ids: [data.data] + } + ) } else { message.error(data.err_msg || 'failed') } @@ -515,33 +538,21 @@ const Documents = () => { formData.append('doc_name', documentName) formData.append('doc_file', originFileObj) formData.append('doc_type', 'DOCUMENT') + const data = await sendSpaceUploadPostRequest( - `/knowledge/${spaceName}/document/upload`, + `/knowledge/${knowledgeSpaceName}/document/upload`, formData ) - data.success && - synchChecked && - sendSpacePostRequest( - `/knowledge/${spaceName}/document/sync`, - { - doc_ids: [data.data] - } - ) if (data.success) { message.success('success') - setIsAddDocumentModalShow(false) - const data = await sendSpacePostRequest( - `/knowledge/${spaceName}/document/list`, - { - page: current, - page_size - } - ) - if (data.success) { - setDocuments(data.data.data) - setTotal(data.data.total) - setCurrent(data.data.page) - } + setIsAddKnowledgeSpaceModalShow(false) + synchChecked && + sendSpacePostRequest( + `/knowledge/${knowledgeSpaceName}/document/sync`, + { + doc_ids: [data.data] + } + ) } else { message.error(data.err_msg || 'failed') } @@ -551,7 +562,7 @@ const Documents = () => { return } const data = await sendSpacePostRequest( - `/knowledge/${spaceName}/document/add`, + `/knowledge/${knowledgeSpaceName}/document/add`, { doc_name: documentName, source: textSource, @@ -559,29 +570,16 @@ const Documents = () => { doc_type: 'TEXT' } ) - data.success && - synchChecked && - sendSpacePostRequest( - `/knowledge/${spaceName}/document/sync`, - { - doc_ids: [data.data] - } - ) if (data.success) { message.success('success') - setIsAddDocumentModalShow(false) - const data = await sendSpacePostRequest( - `/knowledge/${spaceName}/document/list`, - { - page: current, - page_size - } - ) - if (data.success) { - setDocuments(data.data.data) - setTotal(data.data.total) - setCurrent(data.data.page) - } + setIsAddKnowledgeSpaceModalShow(false) + synchChecked && + sendSpacePostRequest( + `/knowledge/${knowledgeSpaceName}/document/sync`, + { + doc_ids: [data.data] + } + ) } else { message.error(data.err_msg || 'failed') } @@ -595,8 +593,8 @@ const Documents = () => { )} -
+ ) } -export default Documents +export default Index diff --git a/app/datastores/page.tsx b/app/datastores/page.tsx index 3abf025..acf10be 100644 --- a/app/datastores/page.tsx +++ b/app/datastores/page.tsx @@ -64,7 +64,6 @@ const documentTypeList = [ const Index = () => { const router = useRouter() - const { mode } = useColorScheme() const [activeStep, setActiveStep] = useState(0) const [documentType, setDocumentType] = useState('') const [knowledgeSpaceList, setKnowledgeSpaceList] = useState([]) diff --git a/hooks/useAgentChat.ts b/hooks/useAgentChat.ts index f14f72b..c45d4fe 100644 --- a/hooks/useAgentChat.ts +++ b/hooks/useAgentChat.ts @@ -1,170 +1,168 @@ import { - EventStreamContentType, - fetchEventSource, - } from '@microsoft/fetch-event-source'; - import useStateReducer from './useStateReducer'; + EventStreamContentType, + fetchEventSource, +} from '@microsoft/fetch-event-source'; +import useStateReducer from './useStateReducer'; import { Message } from '@/types'; import { useEffect } from 'react'; import { useDialogueContext } from '@/app/context/dialogue'; - type Props = { - queryAgentURL: string; - channel?: "dashboard" | "website" | "slack" | "crisp"; - queryBody?: any; - initHistory?: Message[]; - }; +type Props = { + queryAgentURL: string; + channel?: "dashboard" | "website" | "slack" | "crisp"; + queryBody?: any; + initHistory?: Message[]; +}; + +const useAgentChat = ({ + queryAgentURL, + channel, + queryBody, + initHistory +}: Props) => { + const [state, setState] = useStateReducer({ + history: (initHistory || []) as { role: 'human' | 'view'; context: string; id?: string }[], + }); + + const { refreshDialogList } = useDialogueContext(); + + useEffect(() => { + if (initHistory) setState({ history: initHistory }); + }, [initHistory]); + + const handleChatSubmit = async (context: string, otherQueryBody?: any) => { + if (!context) { + return; + } - const useAgentChat = ({ - queryAgentURL, - channel, - queryBody, - initHistory - }: Props) => { - const [state, setState] = useStateReducer({ - history: (initHistory || []) as { role: 'human' | 'view'; context: string; id?: string }[], + const history = [...state.history, { role: 'human', context }]; + const nextIndex = history.length; + + setState({ + history: history as any, }); - const { refreshDialogList } = useDialogueContext(); + let answer = ''; + let error = ''; - useEffect(() => { - if (initHistory) setState({ history: initHistory }); - }, [initHistory]); + try { + const ctrl = new AbortController(); + let buffer = ''; - const handleChatSubmit = async (context: string, otherQueryBody?: any) => { - if (!context) { - return; - } - - const history = [...state.history, { role: 'human', context }]; - const nextIndex = history.length; - - setState({ - history: history as any, - }); - - let answer = ''; - let error = ''; - - try { - const ctrl = new AbortController(); - let buffer = ''; - - await fetchEventSource(`${process.env.API_BASE_URL ? process.env.API_BASE_URL : ''}${"/api" + queryAgentURL}`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - ...otherQueryBody, - ...queryBody, - user_input: context, - channel, - }), - signal: ctrl.signal, - - async onopen(response) { - if (history.length <= 1) { - refreshDialogList(); - const searchParams = new URLSearchParams(window.location.search); - searchParams.delete('initMessage'); - window.history.replaceState(null, null, `?${searchParams.toString()}`); + await fetchEventSource(`${process.env.API_BASE_URL ? process.env.API_BASE_URL : ''}${"/api" + queryAgentURL}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + ...otherQueryBody, + ...queryBody, + user_input: context, + channel, + }), + signal: ctrl.signal, + + async onopen(response) { + if (history.length <= 1) { + refreshDialogList(); + const searchParams = new URLSearchParams(window.location.search); + searchParams.delete('initMessage'); + window.history.replaceState(null, null, `?${searchParams.toString()}`); + } + if ( + response.ok && + response.headers.get('content-type') === EventStreamContentType + ) { + return; // everything's good + } else if ( + response.status >= 400 && + response.status < 500 && + response.status !== 429 + ) { + if (response.status === 402) { + //throw new ApiError(ApiErrorType.USAGE_LIMIT); } - if ( - response.ok && - response.headers.get('content-type') === EventStreamContentType - ) { - return; // everything's good - } else if ( - response.status >= 400 && - response.status < 500 && - response.status !== 429 - ) { - if (response.status === 402) { - //throw new ApiError(ApiErrorType.USAGE_LIMIT); + // client-side errors are usually non-retriable: + //throw new FatalError(); + } else { + //throw new RetriableError(); + } + }, + onclose() { + // if the server closes the connection unexpectedly, retry: + console.log('onclose'); + }, + onerror(err) { + throw new Error(err); + }, + onmessage: (event) => { + event.data = event.data.replaceAll('\\n', '\n'); + + if (event.data === '[DONE]') { + ctrl.abort(); + } else if (event.data?.startsWith('[ERROR]')) { + ctrl.abort(); + setState({ + history: [ + ...history, + { + role: 'view', + context: event.data.replace('[ERROR]', ''), + } as any, + ], + }); + } else { + const h = [...history]; + if (event.data) { + if (h?.[nextIndex]) { + h[nextIndex].context = `${event.data}`; + } else { + h.push({ role: 'view', context: event.data }); } - // client-side errors are usually non-retriable: - //throw new FatalError(); - } else { - //throw new RetriableError(); - } - }, - onclose() { - // if the server closes the connection unexpectedly, retry: - console.log('onclose'); - }, - onerror(err) { - throw new Error(err); - }, - onmessage: (event) => { - console.log(event, 'e'); - event.data = event.data.replaceAll('\\n', '\n'); - - if (event.data === '[DONE]') { - ctrl.abort(); - } else if (event.data?.startsWith('[ERROR]')) { - ctrl.abort(); setState({ - history: [ - ...history, - { - role: 'view', - context: event.data.replace('[ERROR]', ''), - } as any, - ], + history: h as any, }); - } else { - const h = [...history]; - if (event.data) { - if (h?.[nextIndex]) { - h[nextIndex].context = `${event.data}`; - } else { - h.push({ role: 'view', context: event.data }); - } - setState({ - history: h as any, - }); - } - } - }, - }); - } catch (err) { - console.log('---e', err); + + } + }, + }); + } catch (err) { + console.log(err); + + setState({ + history: [ + ...history, + { role: 'view', context: answer || '请求出错' as string }, + ] as any, + }); + // if (err instanceof ApiError) { + // if (err?.message) { + // error = err?.message; + + // if (error === ApiErrorType.USAGE_LIMIT) { + // answer = + // 'Usage limit reached. Please upgrade your plan to get higher usage.'; + // } else { + // answer = `Error: ${error}`; + // } + // } else { + // answer = `Error: ${error}`; + // } - setState({ - history: [ - ...history, - { role: 'view', context: answer || '请求出错' as string }, - ] as any, - }); - // if (err instanceof ApiError) { - // if (err?.message) { - // error = err?.message; - - // if (error === ApiErrorType.USAGE_LIMIT) { - // answer = - // 'Usage limit reached. Please upgrade your plan to get higher usage.'; - // } else { - // answer = `Error: ${error}`; - // } - // } else { - // answer = `Error: ${error}`; - // } - - // setState({ - // history: [ - // ...history, - // { from: 'ai', message: answer as string }, - // ] as any, - // }); - // } - } - }; - return { - handleChatSubmit, - history: state.history, - }; + // setState({ + // history: [ + // ...history, + // { from: 'ai', message: answer as string }, + // ] as any, + // }); + // } + } }; - - export default useAgentChat; - \ No newline at end of file + return { + handleChatSubmit, + history: state.history, + }; +}; + +export default useAgentChat; From 18cef2495975ee245dcd872fd5fa4c8d9c478aa8 Mon Sep 17 00:00:00 2001 From: "changhuiping.chp" <392752049@qq.com> Date: Fri, 21 Jul 2023 10:04:52 +0800 Subject: [PATCH 2/7] fix: add Skeleton&tab change duplicate request --- app/chat/page.tsx | 93 ++++++++++++--- components/chatBoxTemp.tsx | 131 ++++++++++++++++++-- hooks/useAgentChat.ts | 52 ++++---- package-lock.json | 236 ++++++++++++++++++++++++------------- package.json | 4 +- 5 files changed, 380 insertions(+), 136 deletions(-) diff --git a/app/chat/page.tsx b/app/chat/page.tsx index 4141230..e62c1a1 100644 --- a/app/chat/page.tsx +++ b/app/chat/page.tsx @@ -1,22 +1,52 @@ "use client" +import { useEffect, useMemo, useState } from 'react'; +import { Chart, LineAdvance, Interval, Tooltip, getTheme } from "bizcharts"; +import { Card, CardContent, Typography, Grid, Table, Skeleton, AspectRatio, Box, aspectRatioClasses } from "@/lib/mui"; import { useRequest } from 'ahooks'; import { sendGetRequest, sendPostRequest } from '@/utils/request'; -import { Card, CardContent, Typography, Grid, Table } from "@/lib/mui"; import useAgentChat from '@/hooks/useAgentChat'; import ChatBoxComp from '@/components/chatBoxTemp'; import { useDialogueContext } from '@/app/context/dialogue'; import { useSearchParams } from 'next/navigation'; -import { useMemo } from 'react'; -import { Chart, LineAdvance, Interval, Tooltip, getTheme } from "bizcharts"; + import lodash from 'lodash'; +const ChartSkeleton = () => { + return ( + + + + + + + + ) +}; + const AgentPage = () => { + const [chartsData, setChartsData] = useState(); const searchParams = useSearchParams(); const { refreshDialogList } = useDialogueContext(); const id = searchParams.get('id'); const scene = searchParams.get('scene'); - const { data: historyList } = useRequest(async () => await sendGetRequest('/v1/chat/dialogue/messages/history', { + const { data: historyList, run: runHistoryList } = useRequest(async () => await sendGetRequest('/v1/chat/dialogue/messages/history', { con_uid: id }), { ready: !!id, @@ -34,16 +64,17 @@ const AgentPage = () => { conv_uid: id, chat_mode: scene || 'chat_normal', }, - initHistory: historyList?.data + initHistory: historyList?.data, + runHistoryList }); - const chartsData = useMemo(() => { + useEffect(() => { try { const contextTemp = history?.[history.length - 1]?.context; const contextObj = JSON.parse(contextTemp); - return contextObj?.template_name === 'sales_report' ? contextObj?.charts : undefined; + setChartsData(contextObj?.template_name === 'sales_report' ? contextObj?.charts : undefined); } catch (e) { - return undefined; + setChartsData(undefined); } }, [history]); @@ -117,7 +148,7 @@ const AgentPage = () => { > {col.values.map((item) => (
- + {item.name} @@ -132,11 +163,14 @@ const AgentPage = () => { } else if (col.chart_type === "LineChart") { return (
- + {col.chart_name} + + {col.chart_desc} +
{ } else if (col.chart_type === "BarChart") { return (
- + {col.chart_name} + + {col.chart_desc} +
{ const data = lodash.groupBy(col.values, 'type'); return (
- - + {col.chart_name} + + {col.chart_desc} +
{ )} - -
+ {!chartsData && scene === 'chat_dashboard' && ( + +
+ + + + + + + + + + + + + + + + +
+
+ )} + +
{ await refreshDialogList(); }} + isChartChat={scene === 'chat_dashboard'} messages={history || []} onSubmit={handleChatSubmit} paramsList={paramsList?.data} + setChartsData={setChartsData} />
diff --git a/components/chatBoxTemp.tsx b/components/chatBoxTemp.tsx index a4a1473..68db9d7 100644 --- a/components/chatBoxTemp.tsx +++ b/components/chatBoxTemp.tsx @@ -1,7 +1,7 @@ import { zodResolver } from '@hookform/resolvers/zod'; import SendRoundedIcon from '@mui/icons-material/SendRounded'; -import { Card, CircularProgress, IconButton, Input, Stack, Select, Option, Tooltip, Box, useColorScheme } from '@/lib/mui'; -import React, { useState } from 'react'; +import { Card, CircularProgress, IconButton, Input, Stack, Select, Option, Box, Modal, ModalDialog, ModalClose, Button, Link } from '@/lib/mui'; +import React, { useState, useRef } from 'react'; import { useForm } from 'react-hook-form'; import { z } from 'zod'; import { Message } from '@/types'; @@ -11,13 +11,20 @@ import Markdown from 'markdown-to-jsx'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { okaidia } from 'react-syntax-highlighter/dist/esm/styles/prism'; import { useSearchParams } from 'next/navigation'; +import lodash from 'lodash'; +import AceEditor from 'react-ace'; +import 'ace-builds/src-noconflict/mode-json'; +import 'ace-builds/src-noconflict/ext-language_tools'; +import { message } from 'antd'; type Props = { messages: Message[]; onSubmit: (message: string, otherQueryBody?: any) => Promise; readOnly?: boolean; paramsList?: { [key: string]: string }; + isChartChat: boolean; clearIntialMessage?: () => void; + setChartsData?: (chartsData: any) => void; }; const Schema = z.object({ query: z.string().min(1) }); @@ -27,13 +34,19 @@ const ChatBoxComp = ({ onSubmit, readOnly, paramsList, - clearIntialMessage + isChartChat = false, + clearIntialMessage, + setChartsData }: Props) => { const searchParams = useSearchParams(); const initMessage = searchParams.get('initMessage'); - const scrollableRef = React.useRef(null); + const scrollableRef = useRef(null); const [isLoading, setIsLoading] = useState(false); const [currentParam, setCurrentParam] = useState(); + const [jsonModalOpen, setJsonModalOpen] = useState(false); + const [currentJsonIndex, setCurrentJsonIndex] = useState(); + const [showMessages, setShowMessages] = useState(messages); + const [jsonValue, setJsonValue] = useState(''); const methods = useForm>({ resolver: zodResolver(Schema), @@ -42,7 +55,6 @@ const ChatBoxComp = ({ const submit = async ({ query }: z.infer) => { try { - console.log('submit'); setIsLoading(true); methods.reset(); await onSubmit(query, { @@ -79,11 +91,20 @@ const ChatBoxComp = ({ wrapper: React.Fragment, }; + const handleJson2Obj = (jsonStr: string) => { + let res = jsonStr; + try { + res = JSON.parse(jsonStr); + } catch (e) { + console.log(e); + } + return res; + }; + React.useEffect(() => { if (!scrollableRef.current) { return; } - scrollableRef.current.scrollTo(0, scrollableRef.current.scrollHeight); }, [messages?.length]); @@ -99,6 +120,20 @@ const ChatBoxComp = ({ } }, [paramsList]); + React.useEffect(() => { + if (isChartChat) { + let temp = lodash.cloneDeep(messages); + temp.forEach(item => { + if (item?.role === 'view' && typeof item?.context === 'string') { + item.context = handleJson2Obj(item?.context); + } + }) + setShowMessages(temp.filter(item => ['view', 'human'].includes(item.role))); + } else { + setShowMessages(messages.filter(item => ['view', 'human'].includes(item.role))); + } + }, [isChartChat, messages]); + return (
- {messages.filter(item => ['view', 'human'].includes(item.role))?.map((each, index) => { + {showMessages.map((each, index) => { return (
- - {each.context?.replaceAll('\\n', '\n')} - + { + (isChartChat && each.role === 'view' && typeof each?.context === 'object') ? ( + <> + {`[${each.context.template_name}]: `} + { + setJsonModalOpen(true); + setCurrentJsonIndex(index); + setJsonValue(JSON.stringify(each?.context, null, 2)); + }} + > + {each.context.template_introduce || '暂无介绍'} + + + ) : ( + + {each.context?.replaceAll?.('\\n', '\n')} + + ) + }
@@ -246,6 +302,61 @@ const ChatBoxComp = ({ )}
+ setJsonModalOpen(false)} + > + + + + + + + +
); } diff --git a/hooks/useAgentChat.ts b/hooks/useAgentChat.ts index c45d4fe..5e7733a 100644 --- a/hooks/useAgentChat.ts +++ b/hooks/useAgentChat.ts @@ -12,24 +12,42 @@ type Props = { channel?: "dashboard" | "website" | "slack" | "crisp"; queryBody?: any; initHistory?: Message[]; + runHistoryList?: () => void; }; const useAgentChat = ({ queryAgentURL, channel, queryBody, - initHistory + initHistory, + runHistoryList }: Props) => { const [state, setState] = useStateReducer({ history: (initHistory || []) as { role: 'human' | 'view'; context: string; id?: string }[], }); const { refreshDialogList } = useDialogueContext(); + const ctrl = new AbortController(); useEffect(() => { if (initHistory) setState({ history: initHistory }); }, [initHistory]); + const handleVisibleChange = async () => { + if (document.visibilityState === 'hidden') { + ctrl.abort(); + } else { + await runHistoryList?.(); + document.removeEventListener('visibilitychange', handleVisibleChange); + } + } + + useEffect(() => { + return () => { + document.removeEventListener('visibilitychange', handleVisibleChange); + } + }, []); + const handleChatSubmit = async (context: string, otherQueryBody?: any) => { if (!context) { return; @@ -43,12 +61,8 @@ const useAgentChat = ({ }); let answer = ''; - let error = ''; try { - const ctrl = new AbortController(); - let buffer = ''; - await fetchEventSource(`${process.env.API_BASE_URL ? process.env.API_BASE_URL : ''}${"/api" + queryAgentURL}`, { method: 'POST', headers: { @@ -91,15 +105,19 @@ const useAgentChat = ({ onclose() { // if the server closes the connection unexpectedly, retry: console.log('onclose'); + document.removeEventListener('visibilitychange', handleVisibleChange); }, - onerror(err) { + onerror(err) { + console.log('onerror'); throw new Error(err); }, onmessage: (event) => { + document.addEventListener('visibilitychange', handleVisibleChange); event.data = event.data.replaceAll('\\n', '\n'); if (event.data === '[DONE]') { ctrl.abort(); + document.removeEventListener('visibilitychange', handleVisibleChange); } else if (event.data?.startsWith('[ERROR]')) { ctrl.abort(); setState({ @@ -136,29 +154,9 @@ const useAgentChat = ({ { role: 'view', context: answer || '请求出错' as string }, ] as any, }); - // if (err instanceof ApiError) { - // if (err?.message) { - // error = err?.message; - - // if (error === ApiErrorType.USAGE_LIMIT) { - // answer = - // 'Usage limit reached. Please upgrade your plan to get higher usage.'; - // } else { - // answer = `Error: ${error}`; - // } - // } else { - // answer = `Error: ${error}`; - // } - - // setState({ - // history: [ - // ...history, - // { from: 'ai', message: answer as string }, - // ] as any, - // }); - // } } }; + return { handleChatSubmit, history: state.history, diff --git a/package-lock.json b/package-lock.json index 727e944..2aedc4f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "@hookform/resolvers": "^3.0.0", "@microsoft/fetch-event-source": "^2.0.1", "@mui/icons-material": "^5.11.16", - "@mui/joy": "5.0.0-alpha.72", + "@mui/joy": "5.0.0-alpha.88", "@mui/lab": "5.0.0-alpha.124", "@mui/material": "^5.13.6", "@mui/styled-engine-sc": "^5.12.0", @@ -25,6 +25,7 @@ "@types/node": "20.3.1", "@types/react": "18.2.14", "@types/react-dom": "18.2.6", + "ace-builds": "^1.12.5", "ahooks": "^3.7.8", "antd": "^5.6.2", "autoprefixer": "10.4.14", @@ -41,6 +42,7 @@ "nprogress": "^0.2.0", "postcss": "8.4.24", "react": "18.2.0", + "react-ace": "^10.1.0", "react-dom": "18.2.0", "react-hook-form": "^7.43.8", "react-syntax-highlighter": "^15.5.0", @@ -1066,9 +1068,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.22.5", - "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.22.5.tgz", - "integrity": "sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==", + "version": "7.22.6", + "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.22.6.tgz", + "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", "dependencies": { "regenerator-runtime": "^0.13.11" }, @@ -1512,9 +1514,9 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.13.4", - "resolved": "https://registry.npmmirror.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.13.4.tgz", - "integrity": "sha512-yFrMWcrlI0TqRN5jpb6Ma9iI7sGTHpytdzzL33oskFHNQ8UgrtPas33Y1K7sWAMwCrr1qbWDrOHLAQG4tAzuSw==" + "version": "5.14.1", + "resolved": "https://registry.npmmirror.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.1.tgz", + "integrity": "sha512-mIa1WmDmNr1LoupV1Rbxt9bTFKMbIn10RHG1bnZ/FJCkAYpuU/D4n+R+ttiycgcZNngU++zyh/OQeJblzbQPzg==" }, "node_modules/@mui/icons-material": { "version": "5.11.16", @@ -1538,18 +1540,18 @@ } }, "node_modules/@mui/joy": { - "version": "5.0.0-alpha.72", - "resolved": "https://registry.npmmirror.com/@mui/joy/-/joy-5.0.0-alpha.72.tgz", - "integrity": "sha512-Tlf5HkRUpYMuVAjLWZY/k1mqF8fGHH5l3OL4Q8SZIiYZF+k6loMrapCI2L70qDVDbb6C42G0/9qrOczJNMIF4A==", - "dependencies": { - "@babel/runtime": "^7.21.0", - "@mui/base": "5.0.0-alpha.122", - "@mui/core-downloads-tracker": "^5.11.14", - "@mui/system": "^5.11.14", - "@mui/types": "^7.2.3", - "@mui/utils": "^5.11.13", + "version": "5.0.0-alpha.88", + "resolved": "https://registry.npmmirror.com/@mui/joy/-/joy-5.0.0-alpha.88.tgz", + "integrity": "sha512-zG+kYy7JV07nQWHXtZP7+78pf3erv+X07aHetbwb9etx7pqGhxTxeBeT2WltH3hAUEUEr9GqfChcBe2MWy2ziQ==", + "dependencies": { + "@babel/runtime": "^7.22.6", + "@mui/base": "5.0.0-beta.8", + "@mui/core-downloads-tracker": "^5.14.1", + "@mui/system": "^5.14.1", + "@mui/types": "^7.2.4", + "@mui/utils": "^5.14.1", "clsx": "^1.2.1", - "csstype": "^3.1.1", + "csstype": "^3.1.2", "prop-types": "^15.8.1", "react-is": "^18.2.0" }, @@ -1576,15 +1578,15 @@ } }, "node_modules/@mui/joy/node_modules/@mui/base": { - "version": "5.0.0-alpha.122", - "resolved": "https://registry.npmmirror.com/@mui/base/-/base-5.0.0-alpha.122.tgz", - "integrity": "sha512-IgZEFQyHa39J1+Q3tekVdhPuUm1fr3icddaNLmiAIeYTVXmR7KR5FhBAIL0P+4shlPq0liUPGlXryoTm0iCeFg==", + "version": "5.0.0-beta.8", + "resolved": "https://registry.npmmirror.com/@mui/base/-/base-5.0.0-beta.8.tgz", + "integrity": "sha512-b4vVjMZx5KzzEMf4arXKoeV5ZegAMOoPwoy1vfUBwhvXc2QtaaAyBp50U7OA2L06Leubc1A+lEp3eqwZoFn87g==", "dependencies": { - "@babel/runtime": "^7.21.0", - "@emotion/is-prop-valid": "^1.2.0", - "@mui/types": "^7.2.3", - "@mui/utils": "^5.11.13", - "@popperjs/core": "^2.11.6", + "@babel/runtime": "^7.22.6", + "@emotion/is-prop-valid": "^1.2.1", + "@mui/types": "^7.2.4", + "@mui/utils": "^5.14.1", + "@popperjs/core": "^2.11.8", "clsx": "^1.2.1", "prop-types": "^15.8.1", "react-is": "^18.2.0" @@ -1728,12 +1730,12 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, "node_modules/@mui/private-theming": { - "version": "5.13.1", - "resolved": "https://registry.npmmirror.com/@mui/private-theming/-/private-theming-5.13.1.tgz", - "integrity": "sha512-HW4npLUD9BAkVppOUZHeO1FOKUJWAwbpy0VQoGe3McUYTlck1HezGHQCfBQ5S/Nszi7EViqiimECVl9xi+/WjQ==", + "version": "5.13.7", + "resolved": "https://registry.npmmirror.com/@mui/private-theming/-/private-theming-5.13.7.tgz", + "integrity": "sha512-qbSr+udcij5F9dKhGX7fEdx2drXchq7htLNr2Qg2Ma+WJ6q0ERlEqGSBiPiVDJkptcjeVL4DGmcf1wl5+vD4EA==", "dependencies": { - "@babel/runtime": "^7.21.0", - "@mui/utils": "^5.13.1", + "@babel/runtime": "^7.22.5", + "@mui/utils": "^5.13.7", "prop-types": "^15.8.1" }, "engines": { @@ -1802,15 +1804,15 @@ } }, "node_modules/@mui/system": { - "version": "5.13.6", - "resolved": "https://registry.npmmirror.com/@mui/system/-/system-5.13.6.tgz", - "integrity": "sha512-G3Xr28uLqU3DyF6r2LQkHGw/ku4P0AHzlKVe7FGXOPl7X1u+hoe2xxj8Vdiq/69II/mh9OP21i38yBWgWb7WgQ==", + "version": "5.14.1", + "resolved": "https://registry.npmmirror.com/@mui/system/-/system-5.14.1.tgz", + "integrity": "sha512-u+xlsU34Jdkgx1CxmBnIC4Y08uPdVX5iEd3S/1dggDFtOGp+Lj8xmKRJAQ8PJOOJLOh8pDwaZx4AwXikL4l1QA==", "dependencies": { - "@babel/runtime": "^7.22.5", - "@mui/private-theming": "^5.13.1", + "@babel/runtime": "^7.22.6", + "@mui/private-theming": "^5.13.7", "@mui/styled-engine": "^5.13.2", "@mui/types": "^7.2.4", - "@mui/utils": "^5.13.6", + "@mui/utils": "^5.14.1", "clsx": "^1.2.1", "csstype": "^3.1.2", "prop-types": "^15.8.1" @@ -1850,13 +1852,13 @@ } }, "node_modules/@mui/utils": { - "version": "5.13.6", - "resolved": "https://registry.npmmirror.com/@mui/utils/-/utils-5.13.6.tgz", - "integrity": "sha512-ggNlxl5NPSbp+kNcQLmSig6WVB0Id+4gOxhx644987v4fsji+CSXc+MFYLocFB/x4oHtzCUlSzbVHlJfP/fXoQ==", + "version": "5.14.1", + "resolved": "https://registry.npmmirror.com/@mui/utils/-/utils-5.14.1.tgz", + "integrity": "sha512-39KHKK2JeqRmuUcLDLwM+c2XfVC136C5/yUyQXmO2PVbOb2Bol4KxtkssEqCbTwg87PSCG3f1Tb0keRsK7cVGw==", "dependencies": { - "@babel/runtime": "^7.22.5", + "@babel/runtime": "^7.22.6", "@types/prop-types": "^15.7.5", - "@types/react-is": "^18.2.0", + "@types/react-is": "^18.2.1", "prop-types": "^15.8.1", "react-is": "^18.2.0" }, @@ -2442,6 +2444,11 @@ "react": "*" } }, + "node_modules/ace-builds": { + "version": "1.12.5", + "resolved": "https://registry.npmmirror.com/ace-builds/-/ace-builds-1.12.5.tgz", + "integrity": "sha512-2OTOZZdXVqWHfsV63n/bWLJ4uGnGNm9uwEQSECbEzMpKF2RKxD04lWu7s+eRBTZoEbqPXziyI1qamJH2OAwdwA==" + }, "node_modules/acorn": { "version": "8.9.0", "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.9.0.tgz", @@ -3521,6 +3528,11 @@ "node": ">=0.3.1" } }, + "node_modules/diff-match-patch": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/diff-match-patch/-/diff-match-patch-1.0.5.tgz", + "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==" + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmmirror.com/dir-glob/-/dir-glob-3.0.1.tgz", @@ -5168,6 +5180,16 @@ "resolved": "https://registry.npmmirror.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmmirror.com/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -7020,6 +7042,22 @@ "node": ">=0.10.0" } }, + "node_modules/react-ace": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/react-ace/-/react-ace-10.1.0.tgz", + "integrity": "sha512-VkvUjZNhdYTuKOKQpMIZi7uzZZVgzCjM7cLYu6F64V0mejY8a2XTyPUIMszC6A4trbeMIHbK5fYFcT/wkP/8VA==", + "dependencies": { + "ace-builds": "^1.4.14", + "diff-match-patch": "^1.0.5", + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "react": "^0.13.0 || ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^0.13.0 || ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-dom": { "version": "18.2.0", "resolved": "https://registry.npmmirror.com/react-dom/-/react-dom-18.2.0.tgz", @@ -9241,9 +9279,9 @@ } }, "@babel/runtime": { - "version": "7.22.5", - "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.22.5.tgz", - "integrity": "sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==", + "version": "7.22.6", + "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.22.6.tgz", + "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", "requires": { "regenerator-runtime": "^0.13.11" } @@ -9594,9 +9632,9 @@ } }, "@mui/core-downloads-tracker": { - "version": "5.13.4", - "resolved": "https://registry.npmmirror.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.13.4.tgz", - "integrity": "sha512-yFrMWcrlI0TqRN5jpb6Ma9iI7sGTHpytdzzL33oskFHNQ8UgrtPas33Y1K7sWAMwCrr1qbWDrOHLAQG4tAzuSw==" + "version": "5.14.1", + "resolved": "https://registry.npmmirror.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.1.tgz", + "integrity": "sha512-mIa1WmDmNr1LoupV1Rbxt9bTFKMbIn10RHG1bnZ/FJCkAYpuU/D4n+R+ttiycgcZNngU++zyh/OQeJblzbQPzg==" }, "@mui/icons-material": { "version": "5.11.16", @@ -9607,32 +9645,32 @@ } }, "@mui/joy": { - "version": "5.0.0-alpha.72", - "resolved": "https://registry.npmmirror.com/@mui/joy/-/joy-5.0.0-alpha.72.tgz", - "integrity": "sha512-Tlf5HkRUpYMuVAjLWZY/k1mqF8fGHH5l3OL4Q8SZIiYZF+k6loMrapCI2L70qDVDbb6C42G0/9qrOczJNMIF4A==", - "requires": { - "@babel/runtime": "^7.21.0", - "@mui/base": "5.0.0-alpha.122", - "@mui/core-downloads-tracker": "^5.11.14", - "@mui/system": "^5.11.14", - "@mui/types": "^7.2.3", - "@mui/utils": "^5.11.13", + "version": "5.0.0-alpha.88", + "resolved": "https://registry.npmmirror.com/@mui/joy/-/joy-5.0.0-alpha.88.tgz", + "integrity": "sha512-zG+kYy7JV07nQWHXtZP7+78pf3erv+X07aHetbwb9etx7pqGhxTxeBeT2WltH3hAUEUEr9GqfChcBe2MWy2ziQ==", + "requires": { + "@babel/runtime": "^7.22.6", + "@mui/base": "5.0.0-beta.8", + "@mui/core-downloads-tracker": "^5.14.1", + "@mui/system": "^5.14.1", + "@mui/types": "^7.2.4", + "@mui/utils": "^5.14.1", "clsx": "^1.2.1", - "csstype": "^3.1.1", + "csstype": "^3.1.2", "prop-types": "^15.8.1", "react-is": "^18.2.0" }, "dependencies": { "@mui/base": { - "version": "5.0.0-alpha.122", - "resolved": "https://registry.npmmirror.com/@mui/base/-/base-5.0.0-alpha.122.tgz", - "integrity": "sha512-IgZEFQyHa39J1+Q3tekVdhPuUm1fr3icddaNLmiAIeYTVXmR7KR5FhBAIL0P+4shlPq0liUPGlXryoTm0iCeFg==", + "version": "5.0.0-beta.8", + "resolved": "https://registry.npmmirror.com/@mui/base/-/base-5.0.0-beta.8.tgz", + "integrity": "sha512-b4vVjMZx5KzzEMf4arXKoeV5ZegAMOoPwoy1vfUBwhvXc2QtaaAyBp50U7OA2L06Leubc1A+lEp3eqwZoFn87g==", "requires": { - "@babel/runtime": "^7.21.0", - "@emotion/is-prop-valid": "^1.2.0", - "@mui/types": "^7.2.3", - "@mui/utils": "^5.11.13", - "@popperjs/core": "^2.11.6", + "@babel/runtime": "^7.22.6", + "@emotion/is-prop-valid": "^1.2.1", + "@mui/types": "^7.2.4", + "@mui/utils": "^5.14.1", + "@popperjs/core": "^2.11.8", "clsx": "^1.2.1", "prop-types": "^15.8.1", "react-is": "^18.2.0" @@ -9709,12 +9747,12 @@ } }, "@mui/private-theming": { - "version": "5.13.1", - "resolved": "https://registry.npmmirror.com/@mui/private-theming/-/private-theming-5.13.1.tgz", - "integrity": "sha512-HW4npLUD9BAkVppOUZHeO1FOKUJWAwbpy0VQoGe3McUYTlck1HezGHQCfBQ5S/Nszi7EViqiimECVl9xi+/WjQ==", + "version": "5.13.7", + "resolved": "https://registry.npmmirror.com/@mui/private-theming/-/private-theming-5.13.7.tgz", + "integrity": "sha512-qbSr+udcij5F9dKhGX7fEdx2drXchq7htLNr2Qg2Ma+WJ6q0ERlEqGSBiPiVDJkptcjeVL4DGmcf1wl5+vD4EA==", "requires": { - "@babel/runtime": "^7.21.0", - "@mui/utils": "^5.13.1", + "@babel/runtime": "^7.22.5", + "@mui/utils": "^5.13.7", "prop-types": "^15.8.1" } }, @@ -9739,15 +9777,15 @@ } }, "@mui/system": { - "version": "5.13.6", - "resolved": "https://registry.npmmirror.com/@mui/system/-/system-5.13.6.tgz", - "integrity": "sha512-G3Xr28uLqU3DyF6r2LQkHGw/ku4P0AHzlKVe7FGXOPl7X1u+hoe2xxj8Vdiq/69II/mh9OP21i38yBWgWb7WgQ==", + "version": "5.14.1", + "resolved": "https://registry.npmmirror.com/@mui/system/-/system-5.14.1.tgz", + "integrity": "sha512-u+xlsU34Jdkgx1CxmBnIC4Y08uPdVX5iEd3S/1dggDFtOGp+Lj8xmKRJAQ8PJOOJLOh8pDwaZx4AwXikL4l1QA==", "requires": { - "@babel/runtime": "^7.22.5", - "@mui/private-theming": "^5.13.1", + "@babel/runtime": "^7.22.6", + "@mui/private-theming": "^5.13.7", "@mui/styled-engine": "^5.13.2", "@mui/types": "^7.2.4", - "@mui/utils": "^5.13.6", + "@mui/utils": "^5.14.1", "clsx": "^1.2.1", "csstype": "^3.1.2", "prop-types": "^15.8.1" @@ -9760,13 +9798,13 @@ "requires": {} }, "@mui/utils": { - "version": "5.13.6", - "resolved": "https://registry.npmmirror.com/@mui/utils/-/utils-5.13.6.tgz", - "integrity": "sha512-ggNlxl5NPSbp+kNcQLmSig6WVB0Id+4gOxhx644987v4fsji+CSXc+MFYLocFB/x4oHtzCUlSzbVHlJfP/fXoQ==", + "version": "5.14.1", + "resolved": "https://registry.npmmirror.com/@mui/utils/-/utils-5.14.1.tgz", + "integrity": "sha512-39KHKK2JeqRmuUcLDLwM+c2XfVC136C5/yUyQXmO2PVbOb2Bol4KxtkssEqCbTwg87PSCG3f1Tb0keRsK7cVGw==", "requires": { - "@babel/runtime": "^7.22.5", + "@babel/runtime": "^7.22.6", "@types/prop-types": "^15.7.5", - "@types/react-is": "^18.2.0", + "@types/react-is": "^18.2.1", "prop-types": "^15.8.1", "react-is": "^18.2.0" }, @@ -10174,6 +10212,11 @@ "integrity": "sha512-QlN0RJSBVQBwLRNxbxjQ5qzqYIGn+K7USppMoIOVlf7fxXHsnQZ2bEsa6Pm74bt6DVQxpUE8HqvdStn6Y9FV1w==", "requires": {} }, + "ace-builds": { + "version": "1.12.5", + "resolved": "https://registry.npmmirror.com/ace-builds/-/ace-builds-1.12.5.tgz", + "integrity": "sha512-2OTOZZdXVqWHfsV63n/bWLJ4uGnGNm9uwEQSECbEzMpKF2RKxD04lWu7s+eRBTZoEbqPXziyI1qamJH2OAwdwA==" + }, "acorn": { "version": "8.9.0", "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.9.0.tgz", @@ -11044,6 +11087,11 @@ "resolved": "https://registry.npmmirror.com/diff/-/diff-5.1.0.tgz", "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==" }, + "diff-match-patch": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/diff-match-patch/-/diff-match-patch-1.0.5.tgz", + "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==" + }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmmirror.com/dir-glob/-/dir-glob-3.0.1.tgz", @@ -12364,6 +12412,16 @@ "resolved": "https://registry.npmmirror.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmmirror.com/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -13808,6 +13866,18 @@ "loose-envify": "^1.1.0" } }, + "react-ace": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/react-ace/-/react-ace-10.1.0.tgz", + "integrity": "sha512-VkvUjZNhdYTuKOKQpMIZi7uzZZVgzCjM7cLYu6F64V0mejY8a2XTyPUIMszC6A4trbeMIHbK5fYFcT/wkP/8VA==", + "requires": { + "ace-builds": "^1.4.14", + "diff-match-patch": "^1.0.5", + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "prop-types": "^15.7.2" + } + }, "react-dom": { "version": "18.2.0", "resolved": "https://registry.npmmirror.com/react-dom/-/react-dom-18.2.0.tgz", diff --git a/package.json b/package.json index 47cde7c..42a03d1 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "@hookform/resolvers": "^3.0.0", "@microsoft/fetch-event-source": "^2.0.1", "@mui/icons-material": "^5.11.16", - "@mui/joy": "5.0.0-alpha.72", + "@mui/joy": "5.0.0-alpha.88", "@mui/lab": "5.0.0-alpha.124", "@mui/material": "^5.13.6", "@mui/styled-engine-sc": "^5.12.0", @@ -28,6 +28,7 @@ "@types/node": "20.3.1", "@types/react": "18.2.14", "@types/react-dom": "18.2.6", + "ace-builds": "^1.12.5", "ahooks": "^3.7.8", "antd": "^5.6.2", "autoprefixer": "10.4.14", @@ -44,6 +45,7 @@ "nprogress": "^0.2.0", "postcss": "8.4.24", "react": "18.2.0", + "react-ace": "^10.1.0", "react-dom": "18.2.0", "react-hook-form": "^7.43.8", "react-syntax-highlighter": "^15.5.0", From 7b6c4be95e4b4432865ec0e247bc0dee1e0a2b1b Mon Sep 17 00:00:00 2001 From: "changhuiping.chp" <392752049@qq.com> Date: Fri, 21 Jul 2023 11:26:12 +0800 Subject: [PATCH 3/7] fix: npm run compile 'window is not defined' error --- components/chatBoxTemp.tsx | 53 +++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/components/chatBoxTemp.tsx b/components/chatBoxTemp.tsx index 68db9d7..a86169a 100644 --- a/components/chatBoxTemp.tsx +++ b/components/chatBoxTemp.tsx @@ -12,9 +12,6 @@ import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { okaidia } from 'react-syntax-highlighter/dist/esm/styles/prism'; import { useSearchParams } from 'next/navigation'; import lodash from 'lodash'; -import AceEditor from 'react-ace'; -import 'ace-builds/src-noconflict/mode-json'; -import 'ace-builds/src-noconflict/ext-language_tools'; import { message } from 'antd'; type Props = { @@ -101,6 +98,17 @@ const ChatBoxComp = ({ return res; }; + const MyAceEditor = React.useMemo(() => { + // fix npm run compile 'window is not defined' error + if (typeof window !== 'undefined' && typeof window?.fetch === 'function') { + const AceEditor = require('react-ace'); + require('ace-builds/src-noconflict/mode-json'); + require('ace-builds/src-noconflict/ext-language_tools'); + return AceEditor.default; + } + return undefined; + }, []); + React.useEffect(() => { if (!scrollableRef.current) { return; @@ -312,24 +320,27 @@ const ChatBoxComp = ({ > - + {!!MyAceEditor && ( + + )} +