Chat.tsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import {Input, Button, Spin, Select} from "antd";
  2. import React, {useEffect, useRef, useState} from "react";
  3. import Markdown from 'react-markdown'
  4. import remarkGfm from "remark-gfm"
  5. import {Prism as SyntaxHighlighter} from "react-syntax-highlighter"
  6. import {oneDark as dark} from "react-syntax-highlighter/dist/esm/styles/prism"
  7. import {CopyToClipboard} from 'react-copy-to-clipboard';
  8. import {getChat, getTags} from '@/services/chat-service'
  9. import styles from './Chat.module.less'
  10. import {CopyOutlined} from "@ant-design/icons";
  11. const {TextArea} = Input;
  12. const {Option} = Select
  13. export default function Chat() {
  14. const textAreaRef = useRef(null);
  15. const [inputText, setInputText] = useState('')
  16. const [assistantMsg, setAssistantMsg] = useState<any>({})
  17. const [messages, setMessages] = useState<any>([])
  18. const [loading, setLoading] = useState(false)
  19. const [spinTip, setSpinTip] = useState('')
  20. const [models, setModels] = useState([])
  21. const [useModels, setUseModels] = useState('')
  22. useEffect(() => {
  23. getLocalModels()
  24. }, [])
  25. function InputChange(e: any) {
  26. setInputText(e.target.value)
  27. }
  28. async function getLocalModels() {
  29. const res = await getTags()
  30. console.log(2424, res)
  31. const models = res.data.models.map((elm: any) => elm.model)
  32. console.log(31, models)
  33. setModels(models)
  34. setUseModels(models[0])
  35. }
  36. async function getText() {
  37. setLoading(true)
  38. const _messages = [...messages]
  39. const res = await getChat({
  40. "model": useModels,
  41. "messages": [
  42. ...messages,
  43. {
  44. "role": "user",
  45. "content": `翻译这段文字 ${inputText}`
  46. }
  47. ],
  48. "stream": false
  49. })
  50. _messages.push(
  51. {
  52. "role": "user",
  53. "content": `${inputText}`
  54. }
  55. )
  56. setAssistantMsg(res.data.message);
  57. _messages.push(res.data.message)
  58. setMessages(_messages)
  59. setInputText('')
  60. setLoading(false)
  61. /*if (res && res?.data) {
  62. const messageData = qs.parse(res.data)
  63. Object.keys(messageData).forEach(key => {
  64. console.log(24, qs.parse(key));
  65. })
  66. }*/
  67. }
  68. function clearText() {
  69. setInputText('')
  70. setMessages([])
  71. }
  72. function modelChange(e: any) {
  73. setUseModels(e)
  74. }
  75. return <Spin spinning={loading} tip={spinTip}>
  76. <div className={styles.ChatPage} style={{
  77. padding: '24px'
  78. }}>
  79. <div>
  80. <Select style={{
  81. width: '140px',
  82. marginRight: '12px'
  83. }}
  84. value={useModels}
  85. onChange={modelChange}>
  86. {models.map(model => <Option key={model}
  87. value={model}>{`${model}`.replace(/:latest/, '')}</Option>)}
  88. </Select>
  89. {useModels ? `${useModels}`.replace(/:latest/, '') : '选择模型:'}
  90. </div>
  91. <div>
  92. {/*value={inputText}*/}
  93. <div style={{
  94. padding: '24px 0'
  95. }}>
  96. {
  97. messages.length > 0 && messages.map((item: any, index: number) => (
  98. <div key={index} className={item.role === 'user' ? styles.userBox : styles.robotBox}>
  99. {item.role !== 'user' && <div className={styles.avatar}>{item.role}:</div>}
  100. <div className={styles.content}>
  101. <Markdown
  102. children={item.content}
  103. components={{
  104. code(props) {
  105. const {children, className, node, ...rest} = props
  106. const match = /language-(\w+)/.exec(className || '')
  107. return match ? (
  108. <div style={{position: 'relative'}}>
  109. <CopyToClipboard text={String(children).replace(/\n$/, '')}>
  110. {/*<Button
  111. style={{
  112. position: 'absolute',
  113. top: '10px',
  114. right: '10px',
  115. backgroundColor: 'transparent',
  116. color: '#fff',
  117. border: 'none',
  118. cursor: 'pointer',
  119. padding: '5px 10px',
  120. borderRadius: '5px',
  121. }}
  122. >
  123. <CopyOutlined/>
  124. </Button>*/}
  125. <CopyOutlined style={{
  126. position: 'absolute',
  127. top: '10px',
  128. right: '10px',
  129. backgroundColor: 'transparent',
  130. color: '#fff',
  131. border: 'none',
  132. cursor: 'pointer',
  133. }}/>
  134. </CopyToClipboard>
  135. {/*// @ts-ignore*/}
  136. <SyntaxHighlighter
  137. {...rest}
  138. PreTag="div"
  139. language={match[1]}
  140. style={dark}
  141. >
  142. {String(children).replace(/\n$/, '')}
  143. </SyntaxHighlighter>
  144. </div>
  145. ) : (
  146. <code {...rest} className={className}>
  147. {children}
  148. </code>
  149. )
  150. }
  151. }}
  152. />
  153. </div>
  154. </div>
  155. ))
  156. }
  157. </div>
  158. <TextArea value={inputText} ref={textAreaRef} onChange={InputChange} allowClear={true}
  159. showCount={true}></TextArea>
  160. <Button onClick={() => getText()}>获取</Button>
  161. <Button onClick={() => clearText()}>清空</Button>
  162. </div>
  163. </div>
  164. </Spin>
  165. }