king
2025-03-12 b0e4770969816dd4799aefdb710b76595101a629
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}">复制代码</span>
  //     </div>
  //   `
  //   //代码部分
  //   if (code) {
  //     try {
  //     // 使用 highlight.js 对代码进行高亮显示
  //       const preCode = hljs.highlightAuto(code).value;
  //       // 将代码包裹在 textarea 中,由于防止textarea渲染出现问题,这里将 "<" 用 "&lt;" 代替,不影响复制功能
  //       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,"&lt;/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>