From ed6f781fbe1dd5297a54d61ba50b5d609bb1b639 Mon Sep 17 00:00:00 2001 From: king <18310653075@163.com> Date: 星期四, 20 三月 2025 10:31:59 +0800 Subject: [PATCH] Merge branch 'positec' into dms --- src/views/mkai/index.jsx | 312 +++++++++++++++++++++++++++------------------------ 1 files changed, 167 insertions(+), 145 deletions(-) diff --git a/src/views/mkai/index.jsx b/src/views/mkai/index.jsx index 05fddfb..aff559b 100644 --- a/src/views/mkai/index.jsx +++ b/src/views/mkai/index.jsx @@ -4,6 +4,7 @@ import { LoadingOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons' // import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter' // import { dark } from 'react-syntax-highlighter/dist/esm/styles/prism' +import { fetchEventSource } from '@microsoft/fetch-event-source' import moment from 'moment' import Api from '@/api' @@ -180,46 +181,13 @@ message.success('澶嶅埗鎴愬姛銆�') } - // eslint-disable-next-line - // let html = marked(item.content, { - // highlight: (code, language) => { - // // 閫氳繃鏃堕棿鎴崇敓鎴愬敮涓�鏍囪瘑 - // const codeIndex = parseInt(Date.now() + "") + Math.floor(Math.random() * 10000000) - // // 鏍煎紡鍖栫涓�琛屾槸鍙充晶language鍜� 鈥滃鍒垛�� 鎸夐挳锛� - // let html = ` - // <div class=${styles["code-block-header"]}> - // <span>${language}</span> - // <span id='copy-btn'data-clipboard-action="copy" data-clipboard-target="#copy${codeIndex}">澶嶅埗浠g爜</span> - // </div> - // ` - - // //浠g爜閮ㄥ垎 - // if (code) { - // try { - // // 浣跨敤 highlight.js 瀵逛唬鐮佽繘琛岄珮浜樉绀� - // const preCode = hljs.highlightAuto(code).value; - // // 灏嗕唬鐮佸寘瑁瑰湪 textarea 涓紝鐢变簬闃叉textarea娓叉煋鍑虹幇闂锛岃繖閲屽皢 "<" 鐢� "<" 浠f浛锛屼笉褰卞搷澶嶅埗鍔熻兘 - // return `<pre class='${styles["hljs-customer"]} hljs'> - // <code>${preCode}</code> - // </pre> - // <textarea style="position: absolute;top: -9999px;left: -9999px;z-index: -9999;" id="copy${codeIndex}">${code.replace(/<\/textarea>/g,"</textarea>")}</textarea>`; - // } catch (error) { - - // } - // } - // } - // }) - // <SyntaxHighlighter language="javascript" style={dark}> - // {item.content} - // </SyntaxHighlighter> - return ( <div className="assist-wrap" {...restProps}> <DeepSeekLogo/> - {item.type === 'deepseek-reasoner' ? <div className="top-level"> + <div className="top-level"> <DeepSeekIcon /> {item.loading ? '鎬濊�冧腑...' : '宸叉繁搴︽�濊��'} - </div> : null} + </div> {item.loading ? <LoadingOutlined /> : null} <div dangerouslySetInnerHTML={{ __html: item.content }}></div> {item.oriText ? <MkCopy onClick={copy}/> : null} @@ -233,8 +201,9 @@ UserID: '', LoginUID: '', textInput: '', - type: 'deepseek-reasoner', // deepseek-chat deepseek-reasoner + type: 'DeepSeek-R1-Distill-Qwen-32B', // deepseek-chat deepseek-reasoner currentChat: {id: '', list: [], title: ''}, + dpChat: null, chats: [] } @@ -380,7 +349,7 @@ id: cell.id, content: _content, oriText: content, - type: cell.typecharone || '', + type: 'deepseek-reasoner', role } }) @@ -390,14 +359,14 @@ }) } - changeType = () => { - const { type } = this.state + // changeType = () => { + // const { type } = this.state - this.setState({type: type === 'deepseek-reasoner' ? 'deepseek-chat' : 'deepseek-reasoner'}) - } + // this.setState({type: type === 'deepseek-reasoner' ? 'deepseek-chat' : 'deepseek-reasoner'}) + // } submit = () => { - const { textInput, currentChat, UserID, LoginUID, loading, type } = this.state + const { textInput, currentChat, loading, type /*, UserID, LoginUID*/ } = this.state let val = textInput.replace(/\t+|\v+/g, '').replace(/^\s+|\s+$/g, '') @@ -406,122 +375,174 @@ let node = document.getElementById('mk-input') node && node.blur() - let isNew = false + // let isNew = false + const that = this let chat = fromJS(currentChat).toJS() - if (!chat.id) { - chat.id = Utils.getuuid() - isNew = true - } - chat.list.push({ role: 'user', content: val, id: Utils.getuuid() }) - chat.list.push({ role: 'assistant', content: '', type: type, loading: true, id: Utils.getuuid() }) if (!chat.title) { chat.title = val.substr(0, 32) } chat.loading = true - this.setState({textInput: '', currentChat: chat}) + let reschat = { role: 'assistant', content: '', type: type, loading: true, id: Utils.getuuid() } - let list = [] - chat.list.forEach(item => { - if (!item.loading) { - list.push({ - role: item.role, - content: item.oriText || item.content - }) - } - }) + this.setState({textInput: '', currentChat: fromJS(chat).toJS(), dpChat: reschat}) - Api.directRequest({ - url: burl + '/chat/completions', - method: 'post', - headers: { 'Content-Type': 'application/json' }, - data: { - model: type, - messages: list, - stream: false - } - }).then(res => { - let _chat = fromJS(chat).toJS() + // let list = [] + // chat.list.forEach(item => { + // if (!item.loading) { + // list.push({ + // role: item.role, + // content: item.oriText || item.content + // }) + // } + // }) - delete _chat.loading - _chat.list.pop() + // const ctrlAbout = new AbortController() + // const { signal } = ctrlAbout + let contents = [] + let timer = setInterval(() => { + if (contents.length) { + let _cont = contents.shift() - let _val = '鏈嶅姟鍣ㄧ箒蹇欙紝璇风◢鍚庡啀璇曘��' - let _html = _val - let tokens_count = 0 - if (res.success && res.choices && res.choices[0]) { - _val = res.choices[0].message.content - _html = this.getAssistVal(_val) - } else if (!res.success && res.rawStatusCode === 400 && res.message && /This\s*model's\s*maximum\s*context\s*length/.test(res.message)) { - _html = `褰撳墠瀵硅瘽宸茶秴鍑�${type === 'deepseek-reasoner' ? '娣卞害鎬濊�冪殑' : ''}鏈�澶ч暱搴﹂檺鍒讹紝寮�鍚竴涓柊瀵硅瘽缁х画鎬濊�冨惂~` - _val = _html - } - - if (res.usage && res.usage.total_tokens) { - tokens_count = res.usage.total_tokens - } - - _chat.list = _chat.list.map(item => { - delete item.loading - delete item.step - return item - }) - - _chat.list.push({ role: 'assistant', content: _html, oriText: _val, type: type, step: true, id: Utils.getuuid() }) - - this.setState({currentChat: _chat}) - - Api.genericInterface({ - func: 's_deepseek_ai', - rduri: burl + '/webapi/dostars', - file_url: '', - userid: UserID, - LoginUID: LoginUID, - u_id: sessionStorage.getItem('UserID'), - content: window.btoa(window.encodeURIComponent(_val)), - title: window.btoa(window.encodeURIComponent(chat.title)), - data_type: 'reply', - tokens_count: tokens_count, - version: type, - ID: chat.id - }).then(r => { - if (!r.status) { - notification.error({ - top: 92, - message: r.message, - duration: 10 - }) - } else if (isNew) { - this.getList() + if (_cont === '[CLOSE]') { + clearInterval(timer) + chat.list.push(reschat) + that.setState({dpChat: null, currentChat: chat, loading: false}) + } else { + reschat.content += _cont + + if (_cont === '</think>') { + delete reschat.loading + } + + that.setState({dpChat: reschat}) } - }) - }) + } + }, 30) - Api.genericInterface({ - func: 's_deepseek_ai', - rduri: burl + '/webapi/dostars', - file_url: '', - userid: UserID, - LoginUID: LoginUID, - u_id: sessionStorage.getItem('UserID'), - content: window.btoa(window.encodeURIComponent(val)), - title: window.btoa(window.encodeURIComponent(chat.title)), - data_type: 'request', - version: type, - tokens_count: 0, - ID: chat.id - }).then(result => { - if (!result.status) { - notification.error({ - top: 92, - message: result.message, - duration: 10 - }) + fetchEventSource(burl + '/chat', { + mode: 'cors', + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'text/event-stream' + }, + body: JSON.stringify({ + chat_session_id: chat.id || '', + model: type, + prompt: val, + stream: true + }), + onmessage(event) { + if (event.data) { + if (event.data === '[CLOSE]') { + contents.push(event.data) + } else { + let data = JSON.parse(event.data) + if (!chat.id && data.id) { + chat.id = data.id + } + contents.push(data.content) + } + } + }, + onclose() {}, + onerror(error) { + console.info(error) } }) + + // Api.directRequest({ + // url: burl + '/chat/completions', + // method: 'post', + // headers: { 'Content-Type': 'application/json' }, + // data: { + // model: type, + // messages: list, + // stream: false + // } + // }).then(res => { + // let _chat = fromJS(chat).toJS() + + // delete _chat.loading + // _chat.list.pop() + + // let _val = '鏈嶅姟鍣ㄧ箒蹇欙紝璇风◢鍚庡啀璇曘��' + // let _html = _val + // let tokens_count = 0 + // if (res.success && res.choices && res.choices[0]) { + // _val = res.choices[0].message.content + // _html = this.getAssistVal(_val) + // } else if (!res.success && res.rawStatusCode === 400 && res.message && /This\s*model's\s*maximum\s*context\s*length/.test(res.message)) { + // _html = `褰撳墠瀵硅瘽宸茶秴鍑�${type === 'deepseek-reasoner' ? '娣卞害鎬濊�冪殑' : ''}鏈�澶ч暱搴﹂檺鍒讹紝寮�鍚竴涓柊瀵硅瘽缁х画鎬濊�冨惂~` + // _val = _html + // } + + // if (res.usage && res.usage.total_tokens) { + // tokens_count = res.usage.total_tokens + // } + + // _chat.list = _chat.list.map(item => { + // delete item.loading + // delete item.step + // return item + // }) + + // _chat.list.push({ role: 'assistant', content: _html, oriText: _val, type: type, step: true, id: Utils.getuuid() }) + + // this.setState({currentChat: _chat}) + + // Api.genericInterface({ + // func: 's_deepseek_ai', + // rduri: burl + '/webapi/dostars', + // file_url: '', + // userid: UserID, + // LoginUID: LoginUID, + // u_id: sessionStorage.getItem('UserID'), + // content: window.btoa(window.encodeURIComponent(_val)), + // title: window.btoa(window.encodeURIComponent(chat.title)), + // data_type: 'reply', + // tokens_count: tokens_count, + // version: type, + // ID: chat.id + // }).then(r => { + // if (!r.status) { + // notification.error({ + // top: 92, + // message: r.message, + // duration: 10 + // }) + // } else if (isNew) { + // this.getList() + // } + // }) + // }) + + // Api.genericInterface({ + // func: 's_deepseek_ai', + // rduri: burl + '/webapi/dostars', + // file_url: '', + // userid: UserID, + // LoginUID: LoginUID, + // u_id: sessionStorage.getItem('UserID'), + // content: window.btoa(window.encodeURIComponent(val)), + // title: window.btoa(window.encodeURIComponent(chat.title)), + // data_type: 'request', + // version: type, + // tokens_count: 0, + // ID: chat.id + // }).then(result => { + // if (!result.status) { + // notification.error({ + // top: 92, + // message: result.message, + // duration: 10 + // }) + // } + // }) } getAssistVal = (val) => { @@ -595,10 +616,10 @@ } render () { - const { loading, textInput, type, currentChat, chats } = this.state + const { loading, textInput, currentChat, chats, dpChat } = this.state let able = textInput && !/^\s+$/.test(textInput) - let empty = !currentChat.id + let empty = currentChat.list.length === 0 return ( <div className="mk-deepseek-wrap"> @@ -643,6 +664,7 @@ return <UserChat key={item.id} item={item}/> } })} + {dpChat ? <DpChat key='chat' item={dpChat}/> : null} </div> : null} {!empty ? <div className="chat-reset"> <div className="wrap" onClick={this.newContent}> @@ -657,7 +679,7 @@ <TextArea id="mk-input" value={textInput} autoSize={{minRows: 2, maxRows: 12}} placeholder="缁� DeepSeek 鍙戦�佹秷鎭� " onChange={this.changeVal} onPressEnter={this.submit}/> </div> <div className="ec4f5d61"> - {type === 'deepseek-chat' ? <Tooltip placement="left" title="璋冪敤鏂版ā鍨� DeekSeek-R1锛岃В鍐虫帹鐞嗛棶棰�"> + {/* {type === 'deepseek-chat' ? <Tooltip placement="left" title="璋冪敤鏂版ā鍨� DeekSeek-R1锛岃В鍐虫帹鐞嗛棶棰�"> <div className="ds-button" onClick={this.changeType}> <DeepSeekIcon/> <span className="text">娣卞害鎬濊�� (R1)</span> @@ -665,7 +687,7 @@ </Tooltip> : <div className="ds-button active" onClick={this.changeType}> <DeepSeekIcon/> <span className="text">娣卞害鎬濊�� (R1)</span> - </div>} + </div>} */} {/* <div className="ds-button"> <span className="ds-icon"> <svg width="20" height="20" viewBox="0 0 20 20" fill="none"><circle cx="10" cy="10" r="9" stroke="currentColor" strokeWidth="1.8"></circle><path d="M10 1c1.657 0 3 4.03 3 9s-1.343 9-3 9M10 19c-1.657 0-3-4.03-3-9s1.343-9 3-9M1 10h18" stroke="currentColor" strokeWidth="1.8"></path></svg> -- Gitblit v1.8.0