Showing
7 changed files
with
80 additions
and
197 deletions
| 1 | -import React, {useState, useEffect, useMemo, memo} from "react"; | |
| 1 | +import React, {useState, useMemo, memo, useEffect} from "react"; | |
| 2 | 2 | import './base.less' |
| 3 | 3 | import './style.less' |
| 4 | 4 | import ReactMarkdown from 'react-markdown' |
| ... | ... | @@ -18,8 +18,7 @@ import ThinkBlock from './markdown-block' |
| 18 | 18 | import VideoGallery from './videoGallery' |
| 19 | 19 | |
| 20 | 20 | interface MarkdownProps { |
| 21 | - content: any | |
| 22 | - customDisallowedElements?: any | |
| 21 | + content: string | |
| 23 | 22 | } |
| 24 | 23 | |
| 25 | 24 | const capitalizationLanguageNameMap: Record<string, string> = { |
| ... | ... | @@ -77,7 +76,7 @@ const preprocessLaTeX = (content: string) => { |
| 77 | 76 | |
| 78 | 77 | |
| 79 | 78 | const CodeBlock: any = memo(({ inline, className, children, ...props }: any) => { |
| 80 | - const [isSVG, setIsSVG] = useState(true) | |
| 79 | + const [isSVG, setIsSVG] = useState<boolean>() | |
| 81 | 80 | const match = /language-(\w+)/.exec(className || '') |
| 82 | 81 | const language = match?.[1] |
| 83 | 82 | const languageShowName = getCorrectCapitalizationLanguageName(language || '') |
| ... | ... | @@ -91,26 +90,33 @@ const CodeBlock: any = memo(({ inline, className, children, ...props }: any) => |
| 91 | 90 | return JSON.parse('{"title":{"text":"ECharts error - Wrong JSON format."}}') |
| 92 | 91 | }, [language, children]) |
| 93 | 92 | |
| 93 | + useEffect(() => { | |
| 94 | + setIsSVG(true) | |
| 95 | + }, []) | |
| 96 | + | |
| 94 | 97 | const renderCodeContent = useMemo(() => { |
| 95 | 98 | const content = String(children).replace(/\n$/, '') |
| 96 | 99 | if (language === 'mermaid' && isSVG) { |
| 97 | - return <Flowchart PrimitiveCode={content} /> | |
| 100 | + // return <Flowchart PrimitiveCode={content} /> | |
| 101 | + return '' | |
| 98 | 102 | } |
| 99 | 103 | else if (language === 'echarts') { |
| 100 | - return ( | |
| 101 | - <div style={{ minHeight: '350px', minWidth: '100%', overflowX: 'scroll' }}> | |
| 102 | - <ErrorBoundary> | |
| 103 | - <ReactEcharts option={chartData} style={{ minWidth: '700px' }} /> | |
| 104 | - </ErrorBoundary> | |
| 105 | - </div> | |
| 106 | - ) | |
| 104 | + // return ( | |
| 105 | + // <div style={{ minHeight: '350px', minWidth: '100%', overflowX: 'scroll' }}> | |
| 106 | + // <ErrorBoundary> | |
| 107 | + // <ReactEcharts option={chartData} style={{ minWidth: '700px' }} /> | |
| 108 | + // </ErrorBoundary> | |
| 109 | + // </div> | |
| 110 | + // ) | |
| 111 | + return '' | |
| 107 | 112 | } |
| 108 | 113 | else if (language === 'svg' && isSVG) { |
| 109 | - return ( | |
| 110 | - <ErrorBoundary> | |
| 111 | - <SVGRenderer content={content} /> | |
| 112 | - </ErrorBoundary> | |
| 113 | - ) | |
| 114 | + // return ( | |
| 115 | + // <ErrorBoundary> | |
| 116 | + // <SVGRenderer content={content} /> | |
| 117 | + // </ErrorBoundary> | |
| 118 | + // ) | |
| 119 | + return '' | |
| 114 | 120 | } |
| 115 | 121 | else { |
| 116 | 122 | return ( |
| ... | ... | @@ -166,7 +172,8 @@ const AudioBlock: any = memo(({ node }: any) => { |
| 166 | 172 | const srcs = node.children.filter((child: any) => 'properties' in child).map((child: any) => (child as any).properties.src) |
| 167 | 173 | if (srcs.length === 0) |
| 168 | 174 | return null |
| 169 | - return <AudioGallery key={srcs.join()} srcs={srcs} /> | |
| 175 | + // return <AudioGallery key={srcs.join()} srcs={srcs} /> | |
| 176 | + return '' | |
| 170 | 177 | }) |
| 171 | 178 | AudioBlock.displayName = 'AudioBlock' |
| 172 | 179 | |
| ... | ... | @@ -179,28 +186,26 @@ ScriptBlock.displayName = 'ScriptBlock' |
| 179 | 186 | const Paragraph = (paragraph: any) => { |
| 180 | 187 | const children_node = paragraph?.node?.children |
| 181 | 188 | if (children_node && children_node?.[0] && 'tagName' in children_node?.[0] && children_node?.[0]?.tagName === 'img') { |
| 182 | - return ( | |
| 183 | - <> | |
| 184 | - <ImageGallery srcs={[children_node?.[0].properties?.src]} /> | |
| 185 | - { | |
| 186 | - Array.isArray(paragraph?.children) ? <p>{paragraph?.children?.slice(1)}</p> : null | |
| 187 | - } | |
| 188 | - </> | |
| 189 | - ) | |
| 189 | + // return ( | |
| 190 | + // <> | |
| 191 | + // <ImageGallery srcs={[children_node?.[0].properties?.src]} /> | |
| 192 | + // { | |
| 193 | + // Array.isArray(paragraph?.children) ? <p>{paragraph?.children?.slice(1)}</p> : null | |
| 194 | + // } | |
| 195 | + // </> | |
| 196 | + // ) | |
| 197 | + return '' | |
| 190 | 198 | } |
| 191 | 199 | return <p>{paragraph?.children}</p> |
| 192 | 200 | } |
| 193 | 201 | |
| 194 | 202 | const Img = ({ src }: any) => { |
| 195 | - return (<ImageGallery srcs={[src]} />) | |
| 203 | + return (<img src={src} />) | |
| 196 | 204 | } |
| 197 | 205 | |
| 198 | 206 | const Link = ({ node, ...props }: any) => { |
| 199 | 207 | if (node.properties?.href && node.properties.href?.toString().startsWith('abbr')) { |
| 200 | - // eslint-disable-next-line react-hooks/rules-of-hooks | |
| 201 | - // const { onSend } = useChatContext() | |
| 202 | - const hidden_text = decodeURIComponent(node.properties.href.toString().split('abbr:')[1]) | |
| 203 | - | |
| 208 | + // const hidden_text = decodeURIComponent(node.properties.href.toString().split('abbr:')[1]) | |
| 204 | 209 | return <abbr className="cursor-pointer underline !decoration-primary-700 decoration-dashed" title={node.children[0]?.value}>{node.children[0]?.value}</abbr> |
| 205 | 210 | } |
| 206 | 211 | else { |
| ... | ... | @@ -208,7 +213,9 @@ const Link = ({ node, ...props }: any) => { |
| 208 | 213 | } |
| 209 | 214 | } |
| 210 | 215 | |
| 211 | -const Markdown: React.FC = (props: MarkdownProps) => { | |
| 216 | + | |
| 217 | + | |
| 218 | +const Markdown: React.FC<MarkdownProps> = (props) => { | |
| 212 | 219 | |
| 213 | 220 | const latexContent = flow([ |
| 214 | 221 | preprocessThinkTag, |
| ... | ... | @@ -245,7 +252,7 @@ const Markdown: React.FC = (props: MarkdownProps) => { |
| 245 | 252 | } |
| 246 | 253 | }, |
| 247 | 254 | ]} |
| 248 | - disallowedElements={['iframe', 'head', 'html', 'meta', 'link', 'style', 'body', ...(props?.customDisallowedElements || [])]} | |
| 255 | + disallowedElements={['iframe', 'head', 'html', 'meta', 'link', 'style', 'body']} | |
| 249 | 256 | components={{ |
| 250 | 257 | code: CodeBlock, |
| 251 | 258 | img: Img, | ... | ... |
| 1 | +// @ts-ignore | |
| 1 | 2 | import React, { useEffect, useState } from 'react' |
| 2 | 3 | import './base.less' |
| 3 | 4 | import './style.less' |
| ... | ... | @@ -5,7 +6,6 @@ import { |
| 5 | 6 | Button, |
| 6 | 7 | Input, |
| 7 | 8 | DatePicker, |
| 8 | - TimePicker, | |
| 9 | 9 | Checkbox, |
| 10 | 10 | Select |
| 11 | 11 | } from 'antd'; |
| ... | ... | @@ -95,39 +95,12 @@ const MarkdownForm = ({ node }: any) => { |
| 95 | 95 | <DatePicker |
| 96 | 96 | key={index} |
| 97 | 97 | value={formValues[child.properties.name]} |
| 98 | - needTimePicker={child.properties.type === SUPPORTED_TYPES.DATETIME} | |
| 99 | 98 | onChange={(date) => { |
| 100 | 99 | setFormValues(prevValues => ({ |
| 101 | 100 | ...prevValues, |
| 102 | 101 | [child.properties.name]: date, |
| 103 | 102 | })) |
| 104 | 103 | }} |
| 105 | - onClear={() => { | |
| 106 | - setFormValues(prevValues => ({ | |
| 107 | - ...prevValues, | |
| 108 | - [child.properties.name]: undefined, | |
| 109 | - })) | |
| 110 | - }} | |
| 111 | - /> | |
| 112 | - ) | |
| 113 | - } | |
| 114 | - if (child.properties.type === SUPPORTED_TYPES.TIME) { | |
| 115 | - return ( | |
| 116 | - <TimePicker | |
| 117 | - key={index} | |
| 118 | - value={formValues[child.properties.name]} | |
| 119 | - onChange={(time) => { | |
| 120 | - setFormValues(prevValues => ({ | |
| 121 | - ...prevValues, | |
| 122 | - [child.properties.name]: time, | |
| 123 | - })) | |
| 124 | - }} | |
| 125 | - onClear={() => { | |
| 126 | - setFormValues(prevValues => ({ | |
| 127 | - ...prevValues, | |
| 128 | - [child.properties.name]: undefined, | |
| 129 | - })) | |
| 130 | - }} | |
| 131 | 104 | /> |
| 132 | 105 | ) |
| 133 | 106 | } |
| ... | ... | @@ -137,7 +110,7 @@ const MarkdownForm = ({ node }: any) => { |
| 137 | 110 | <Checkbox |
| 138 | 111 | key={index} |
| 139 | 112 | checked={formValues[child.properties.name]} |
| 140 | - onCheck={() => { | |
| 113 | + onChange={() => { | |
| 141 | 114 | setFormValues(prevValues => ({ |
| 142 | 115 | ...prevValues, |
| 143 | 116 | [child.properties.name]: !prevValues[child.properties.name], |
| ... | ... | @@ -152,24 +125,23 @@ const MarkdownForm = ({ node }: any) => { |
| 152 | 125 | return ( |
| 153 | 126 | <Select |
| 154 | 127 | key={index} |
| 155 | - allowSearch={false} | |
| 156 | 128 | className="w-full" |
| 157 | - items={(() => { | |
| 158 | - let options = child.properties.dataOptions || child.properties['data-options'] || [] | |
| 159 | - if (typeof options === 'string') { | |
| 160 | - try { | |
| 161 | - options = JSON.parse(options) | |
| 162 | - } | |
| 163 | - catch (e) { | |
| 164 | - console.error('Failed to parse options:', e) | |
| 165 | - options = [] | |
| 166 | - } | |
| 167 | - } | |
| 168 | - return options.map((option: string) => ({ | |
| 169 | - name: option, | |
| 170 | - value: option, | |
| 171 | - })) | |
| 172 | - })()} | |
| 129 | + // items={(() => { | |
| 130 | + // let options = child.properties.dataOptions || child.properties['data-options'] || [] | |
| 131 | + // if (typeof options === 'string') { | |
| 132 | + // try { | |
| 133 | + // options = JSON.parse(options) | |
| 134 | + // } | |
| 135 | + // catch (e) { | |
| 136 | + // console.error('Failed to parse options:', e) | |
| 137 | + // options = [] | |
| 138 | + // } | |
| 139 | + // } | |
| 140 | + // return options.map((option: string) => ({ | |
| 141 | + // name: option, | |
| 142 | + // value: option, | |
| 143 | + // })) | |
| 144 | + // })()} | |
| 173 | 145 | defaultValue={formValues[child.properties.name]} |
| 174 | 146 | onSelect={(item) => { |
| 175 | 147 | setFormValues(prevValues => ({ | ... | ... |
| ... | ... | @@ -61,7 +61,7 @@ const DeepSeekIndex: React.FC = () => { |
| 61 | 61 | const [disabled, setDisabled] = useState<boolean>(false); |
| 62 | 62 | const [exampleFlag, setExampleFlag] = useState<string>('1') |
| 63 | 63 | |
| 64 | - const [chatHistory, setChatHistory] = useState<any[]>([]); | |
| 64 | + const [chatHistory, setChatHistory] = useState<{role: string, answer: string, info?: any[]}[]>([]); | |
| 65 | 65 | const [currentResponse, setCurrentResponse] = useState<string>(''); |
| 66 | 66 | |
| 67 | 67 | const chatRef = useRef(null); |
| ... | ... | @@ -72,7 +72,8 @@ const DeepSeekIndex: React.FC = () => { |
| 72 | 72 | {role: 'time', answer: _time}, |
| 73 | 73 | { |
| 74 | 74 | role: 'example', |
| 75 | - answer: example_1 | |
| 75 | + answer: '', | |
| 76 | + info: example_1 | |
| 76 | 77 | } |
| 77 | 78 | ]; |
| 78 | 79 | console.log('newHistory', newHistory) |
| ... | ... | @@ -85,7 +86,7 @@ const DeepSeekIndex: React.FC = () => { |
| 85 | 86 | const _chatHistory = _.cloneDeep(chatHistory); |
| 86 | 87 | _chatHistory?.forEach((item: any) => { |
| 87 | 88 | if (item?.role === 'example') { |
| 88 | - item.answer = _example | |
| 89 | + item.info = _example | |
| 89 | 90 | } |
| 90 | 91 | }) |
| 91 | 92 | setChatHistory(_chatHistory); |
| ... | ... | @@ -133,17 +134,17 @@ const DeepSeekIndex: React.FC = () => { |
| 133 | 134 | throw new Error(`HTTP error! status: ${response.status}`); |
| 134 | 135 | } |
| 135 | 136 | |
| 136 | - const reader = response.body.getReader(); | |
| 137 | + const reader: any = response?.body?.getReader(); | |
| 137 | 138 | const decoder = new TextDecoder(); |
| 138 | - let buffer = ''; | |
| 139 | + let buffer: string = ''; | |
| 139 | 140 | |
| 140 | 141 | while (true) { |
| 141 | - const {done, value} = await reader.read(); | |
| 142 | + const {done, value} = await reader?.read(); | |
| 142 | 143 | if (done) break; |
| 143 | 144 | buffer += decoder?.decode(value, {stream: true}); |
| 144 | - const lines = buffer?.split('\n'); | |
| 145 | - buffer = lines.pop(); | |
| 146 | - lines.forEach(line => { | |
| 145 | + const lines: any[] = buffer?.split('\n'); | |
| 146 | + buffer = lines?.pop(); | |
| 147 | + lines?.forEach(line => { | |
| 147 | 148 | if (line.startsWith('data:')) { |
| 148 | 149 | const data = JSON.parse(line?.slice(5)?.trim()); |
| 149 | 150 | setCurrentResponse(prev => prev + (data?.answer || '')); |
| ... | ... | @@ -168,6 +169,7 @@ const DeepSeekIndex: React.FC = () => { |
| 168 | 169 | // 让会话一直展示最新 |
| 169 | 170 | useEffect(() => { |
| 170 | 171 | if (chatRef.current) { |
| 172 | + // @ts-ignore | |
| 171 | 173 | chatRef.current.scrollTop = chatRef.current.scrollHeight; |
| 172 | 174 | } |
| 173 | 175 | }, [currentResponse]); |
| ... | ... | @@ -177,7 +179,7 @@ const DeepSeekIndex: React.FC = () => { |
| 177 | 179 | console.log('chatHistory', chatHistory) |
| 178 | 180 | }, [chatHistory]) |
| 179 | 181 | |
| 180 | - const handleKeyDown = (e) => { | |
| 182 | + const handleKeyDown = (e: any) => { | |
| 181 | 183 | if (e.key === 'Enter' && !e.shiftKey) { |
| 182 | 184 | e.preventDefault(); // 阻止默认换行 |
| 183 | 185 | send(); |
| ... | ... | @@ -205,7 +207,7 @@ const DeepSeekIndex: React.FC = () => { |
| 205 | 207 | <img src={refresh} className={'refresh'} alt="" onClick={refreshFun}/> |
| 206 | 208 | </div> |
| 207 | 209 | { |
| 208 | - msg?.answer?.map((item:any) => { | |
| 210 | + msg?.info?.map((item:any) => { | |
| 209 | 211 | return <div |
| 210 | 212 | className={'omit1 current-example_title'} |
| 211 | 213 | key={item?.id} |
| ... | ... | @@ -215,16 +217,16 @@ const DeepSeekIndex: React.FC = () => { |
| 215 | 217 | } |
| 216 | 218 | </div> : |
| 217 | 219 | msg.role === 'user' ? <p className={'current-ask'}>{msg?.answer}</p> : |
| 218 | - <Markdown content={msg?.answer}/> | |
| 220 | + <Markdown content={msg?.answer || ''}/> | |
| 219 | 221 | } |
| 220 | 222 | |
| 221 | 223 | </div> |
| 222 | 224 | ))} |
| 223 | - {currentResponse && ( | |
| 225 | + {currentResponse ? ( | |
| 224 | 226 | <div className="content-left"> |
| 225 | - <Markdown content={currentResponse}/> | |
| 227 | + <Markdown content={currentResponse || ''}/> | |
| 226 | 228 | </div> |
| 227 | - )} | |
| 229 | + ) : ''} | |
| 228 | 230 | </div> |
| 229 | 231 | <div className={'deep-seek_footer'}> |
| 230 | 232 | <Input |
| ... | ... | @@ -235,7 +237,7 @@ const DeepSeekIndex: React.FC = () => { |
| 235 | 237 | onChange={(val: string) => setSearchValue(val)} |
| 236 | 238 | onKeyDown={handleKeyDown} |
| 237 | 239 | /> |
| 238 | - <Button className={`deep-seek_footer-send ${disabled ? 'disabled' : ''}`} color={'primary'} onClick={send}>发送</Button> | |
| 240 | + <Button className={`deep-seek_footer-send ${disabled ? 'disabled' : ''}`} color={'primary'} onClick={() =>send}>发送</Button> | |
| 239 | 241 | </div> |
| 240 | 242 | |
| 241 | 243 | </div> | ... | ... |
| ... | ... | @@ -40,7 +40,7 @@ const Test: React.FC = () => { |
| 40 | 40 | // 消息列表 |
| 41 | 41 | const { messages, appendMsg, setTyping } = useMessages(initialMessages); |
| 42 | 42 | // 发送回调 |
| 43 | - function handleSend(type, val) { | |
| 43 | + function handleSend(type: any, val: any) { | |
| 44 | 44 | if (type === 'text' && val.trim()) { |
| 45 | 45 | // TODO: 发送请求 |
| 46 | 46 | appendMsg({ |
| ... | ... | @@ -62,11 +62,11 @@ const Test: React.FC = () => { |
| 62 | 62 | } |
| 63 | 63 | |
| 64 | 64 | // 快捷短语回调,可根据 item 数据做出不同的操作,这里以发送文本消息为例 |
| 65 | - function handleQuickReplyClick(item) { | |
| 65 | + function handleQuickReplyClick(item: any) { | |
| 66 | 66 | handleSend('text', item.name); |
| 67 | 67 | } |
| 68 | 68 | |
| 69 | - function renderMessageContent(msg) { | |
| 69 | + function renderMessageContent(msg: any) { | |
| 70 | 70 | const { type, content } = msg; |
| 71 | 71 | |
| 72 | 72 | // 根据消息类型来渲染 | ... | ... |
src/utils/request.tsx
deleted
100644 → 0
| 1 | -import axios from 'axios'; | |
| 2 | -import {currentCorpCode, _baseUrl} from "@/utils/common" | |
| 3 | - | |
| 4 | -// 创建axios实例 | |
| 5 | -const service = axios.create({ | |
| 6 | - baseURL: _baseUrl, // 你可以通过.env文件设置API的基础URL | |
| 7 | - timeout: 5000 // 请求超时时间 | |
| 8 | -}); | |
| 9 | - | |
| 10 | -// 请求拦截器 | |
| 11 | -service.interceptors.request.use( | |
| 12 | - config => { | |
| 13 | - // 在发送请求之前做些什么,例如设置请求头 | |
| 14 | - // if (store.getters.token) { | |
| 15 | - // config.headers['X-Token'] = getToken(); | |
| 16 | - // } | |
| 17 | - console.log('config---2', config) | |
| 18 | - return config; | |
| 19 | - }, | |
| 20 | - error => { | |
| 21 | - // 对请求错误做些什么 | |
| 22 | - console.error('请求拦截器错误:', error); // for debug | |
| 23 | - Promise.reject(error); | |
| 24 | - } | |
| 25 | -); | |
| 26 | - | |
| 27 | -// 响应拦截器 | |
| 28 | -service.interceptors.response.use( | |
| 29 | - response => { | |
| 30 | - /** | |
| 31 | - * 可以在这里对响应数据做点什么 | |
| 32 | - */ | |
| 33 | - const res = response.data; | |
| 34 | - if (res?.success || res?.code === 200) { | |
| 35 | - return res.data; | |
| 36 | - } else { | |
| 37 | - // 如果后端有统一的错误码处理,可以在这里统一处理 | |
| 38 | - console.error('接口错误:', res.message); | |
| 39 | - // 你可以抛出一个错误,或者返回一个错误对象 | |
| 40 | - // throw new Error(res.message || 'Error'); | |
| 41 | - return Promise.reject(new Error(res.message || 'Error')); | |
| 42 | - } | |
| 43 | - }, | |
| 44 | - error => { | |
| 45 | - console.error('响应拦截器错误:', error); | |
| 46 | - // 对响应错误做点什么 | |
| 47 | - return Promise.reject(error); | |
| 48 | - } | |
| 49 | -); | |
| 50 | - | |
| 51 | -// 封装get请求 | |
| 52 | -export function get(url: string, params = {}, customHeaders?: any, notCorpCode?: boolean) { | |
| 53 | - | |
| 54 | - const _params = notCorpCode ? { | |
| 55 | - ...params, | |
| 56 | - } : { | |
| 57 | - corpCode: currentCorpCode(), | |
| 58 | - ...params, | |
| 59 | - } | |
| 60 | - return service.get(url, {params: _params, headers: customHeaders}) | |
| 61 | - | |
| 62 | -} | |
| 63 | - | |
| 64 | -// 封装post请求 | |
| 65 | -export function post(url: string, params = {}, data = {}, customHeaders?: any, notCorpCode?: boolean) { | |
| 66 | - const _params = notCorpCode ? { | |
| 67 | - ...params, | |
| 68 | - } : { | |
| 69 | - corpCode: currentCorpCode(), | |
| 70 | - ...params, | |
| 71 | - } | |
| 72 | - return service.post(url, data, {params: _params, headers: customHeaders}) | |
| 73 | -} | |
| \ No newline at end of file |
src/utils/util.ts
deleted
100644 → 0
| 1 | -import Cookie from "js-cookie"; | |
| 2 | -import {get} from "@/utils/request"; | |
| 3 | - | |
| 4 | -// 1.行业大脑集成页/行业大脑明细页 | |
| 5 | -// 1.判断缓存token | |
| 6 | -// 无 直接404 --empty | |
| 7 | -// 有 | |
| 8 | -// 1.调用getUserInfo接口 | |
| 9 | -// 失败 404 --empty | |
| 10 | -// 成功 | |
| 11 | -// 1.管理员角色才能看行业大脑 | |
| 12 | -// 2.其他 404 --empty | |
| 13 | - | |
| 14 | -// 处理权限相关 --- 前端 | |
| 15 | -export const judgePermission = async (navigate: any) => { | |
| 16 | - let _hasPermission = true; | |
| 17 | - return { | |
| 18 | - _hasPermission | |
| 19 | - } | |
| 20 | -} | |
| 21 | - | |
| 22 | -const toEmpty = (navigate: any) => { | |
| 23 | - // 去往没有权限的页面 -- 前端处理 | |
| 24 | - const _url = '/empty'; | |
| 25 | - navigate(_url, { replace: true }); | |
| 26 | -} | |
| \ No newline at end of file |