feat(web): 用markdown显示思考过程

This commit is contained in:
v-zhangjc9
2025-06-03 16:12:23 +08:00
parent 602a337923
commit c9a1ea2be5
4 changed files with 106 additions and 22 deletions

View File

@@ -1,7 +1,9 @@
import {ClearOutlined, FileOutlined, UserOutlined} from '@ant-design/icons'
import {Bubble, Sender, useXAgent, useXChat, Welcome} from '@ant-design/x'
import {fetchEventSource} from '@echofly/fetch-event-source'
import {useMount} from 'ahooks'
import {Button, Divider, Flex, Popover, Radio, Switch, Tooltip, Typography} from 'antd'
import {isEqual, isStrBlank, trim} from 'licia'
import markdownIt from 'markdown-it'
import {useRef, useState} from 'react'
import styled from 'styled-components'
@@ -32,7 +34,6 @@ const ConversationDiv = styled.div`
border-left: 3px solid;
padding-left: 5px;
margin-bottom: 10px;
white-space: pre-line;
}
}
@@ -43,23 +44,35 @@ const ConversationDiv = styled.div`
}
`
type ChatMessage = { role: string, content?: string, reason?: string }
function Conversation() {
const abortController = useRef<AbortController | null>(null)
const [input, setInput] = useState<string>('')
const [think, setThink] = useState<boolean>(true)
const [knowledge, setKnowledge] = useState<string>('0')
const [knowledgeList, setKnowledgeList] = useState<{ id: string, name: string }[]>([])
const [agent] = useXAgent<{ role: string, content: string }>({
useMount(async () => {
let response = await fetch(`${commonInfo.baseAiKnowledgeUrl}/knowledge/list`, {
headers: commonInfo.authorizationHeaders,
})
let items = (await response.json()).data.items
setKnowledgeList(items.map((item: { id: string, name: string }) => ({id: item.id, name: item.name})))
})
const [agent] = useXAgent<ChatMessage>({
request: async (info, callbacks) => {
await fetchEventSource(`${commonInfo.baseAiChatUrl}/chat/async`, {
let requestUrl = `${commonInfo.baseAiChatUrl}/chat/async`
if (!isEqual('0', knowledge)) {
requestUrl = `${requestUrl}?knowledge=${knowledge}`
}
await fetchEventSource(requestUrl, {
method: 'POST',
headers: {
'Authorization': 'Basic QXhoRWJzY3dzSkRiWU1IMjpjWXhnM2I0UHRXb1ZENVNqRmF5V3h0blNWc2p6UnNnNA==',
'Content-Type': 'application/json',
},
headers: commonInfo.authorizationHeaders,
body: JSON.stringify(info.messages),
signal: abortController.current?.signal,
onmessage: ev => {
console.log(ev)
callbacks.onUpdate({
id: ev.id,
event: 'delta',
@@ -73,17 +86,22 @@ function Conversation() {
const {onRequest, messages, setMessages} = useXChat({
agent,
transformMessage: ({originMessage, chunk}) => {
let text = ''
let content = '', reason = ''
try {
if (chunk?.data) {
text = chunk.data
let map = JSON.parse(chunk.data)
if (map['content'])
content = map['content']
if (map['reason'])
reason = map['reason']
}
} catch (error) {
console.error(error)
}
return {
content: (originMessage?.content || '') + text,
role: 'assistant',
content: (originMessage?.content || '') + content,
reason: (originMessage?.reason || '') + reason,
}
},
resolveAbortController: controller => {
@@ -105,10 +123,17 @@ function Conversation() {
background: 'transparent',
},
},
messageRender: content => {
messageRender: item => {
let content = ''
if (!isStrBlank(item['reason'])) {
content = `<think>${trim(md.render(item['reason']))}</think>${trim(md.render(item['content']))}`
} else {
content = trim(md.render(item['content']))
}
console.log(content)
return (
<Typography>
<div dangerouslySetInnerHTML={{__html: md.render(content)}}/>
<div dangerouslySetInnerHTML={{__html: content}}/>
</Typography>
)
},
@@ -118,12 +143,20 @@ function Conversation() {
avatar: {
icon: <UserOutlined/>,
},
messageRender: item => {
return (
<Typography>{trim(item['content'])}</Typography>
)
},
},
}}
items={messages.map(({id, message}) => ({
key: id,
...message,
}))}
items={messages.map(({id, message}) => {
return {
key: id,
role: message.role,
content: message,
}
})}
/>)
: (<div className="conversation-welcome">
<Welcome
@@ -170,10 +203,12 @@ function Conversation() {
flexDirection: 'column',
gap: 10,
}}
disabled={agent.isRequesting()}
value={knowledge}
onChange={event => setKnowledge(event.target.value)}
options={[
{value: 1, label: '测试'},
{value: 2, label: 'Hudi'},
{value: 3, label: 'Apache Hudi'},
{value: '0', label: ''},
...knowledgeList.map(k => ({label: k.name, value: k.id})),
]}
/>}
>

View File

@@ -13,6 +13,10 @@ export const commonInfo = {
baseAiChatUrl: 'http://132.126.207.130:35690/hudi_services/ai_chat',
baseAiKnowledgeUrl: 'http://132.126.207.130:35690/hudi_services/ai_knowledge',
// baseUrl: '/hudi_services/service_web',
authorizationHeaders: {
'Authorization': 'Basic QXhoRWJzY3dzSkRiWU1IMjpjWXhnM2I0UHRXb1ZENVNqRmF5V3h0blNWc2p6UnNnNA==',
'Content-Type': 'application/json',
},
clusters: {
// hudi同步运行集群和yarn队列名称
sync: {