Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
A
ai-chat-xy
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
David Yang
ai-chat-xy
Commits
671bc70b
Commit
671bc70b
authored
Aug 04, 2026
by
drigle
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 接入在线 LLM 聊天能力
parent
c49ab07e
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
180 additions
and
16 deletions
+180
-16
.umirc.ts
.umirc.ts
+5
-0
index.jsx
src/pages/Chat/index.jsx
+0
-0
invoice.jsx
src/pages/Chat/invoice.jsx
+22
-6
index.jsx
src/pages/Home/index.jsx
+12
-2
DataService.js
src/services/DataService.js
+141
-8
No files found.
.umirc.ts
View file @
671bc70b
...
...
@@ -38,6 +38,11 @@ export default defineConfig({
changeOrigin
:
true
,
pathRewrite
:
{
'^/api'
:
''
},
},
'/llm-api'
:
{
target
:
'https://lingsuan.top'
,
changeOrigin
:
true
,
pathRewrite
:
{
'^/llm-api'
:
''
},
},
'/myapi/upload_invoices'
:
{
target
:
'http://1.94.111.115:5173'
,
changeOrigin
:
true
,
...
...
src/pages/Chat/index.jsx
View file @
671bc70b
This diff is collapsed.
Click to expand it.
src/pages/Chat/invoice.jsx
View file @
671bc70b
...
...
@@ -13,9 +13,9 @@ import {
Bubble
,
Prompts
,
Sender
,
XStream
,
useXAgent
,
useXChat
,
XStream
,
}
from
'@ant-design/x'
;
import
{
App
,
Button
,
Flex
,
Space
,
Spin
,
Steps
,
Tag
,
Typography
}
from
'antd'
;
import
{
createStyles
}
from
'antd-style'
;
...
...
@@ -34,8 +34,11 @@ import {
import
{
callMcpTool
,
createConversation
,
extractLlmChunkContent
,
extractLlmChunkReasoning
,
llmChat
,
queryMcps
,
resolveLlmModel
,
updateConversation
,
}
from
'../../services/DataService'
;
...
...
@@ -71,6 +74,14 @@ const SYSTEM_PROMPT = `你叫Mia,是一个有用的的发票智能助手。如
如果你不知道答案,请回答你只能根据上下文的内容回答问题。在识别完文件之后,需要调用mcp工具生成用户可能需要的问题选项。用户确认数量没问题之后,需要生成一个表单供用户填写。接收到的是html的时候,assistent角色回复的消息需要是html格式,只要用户发送了表单信息,那么无论表单信息内容是否为空,都需要调用mcp工具对表单信息进行标准化处理
`
;
const
INVOICE_TOOL_API_KEY
=
process
.
env
.
UMI_APP_INVOICE_TOOL_API_KEY
||
process
.
env
.
VITE_INVOICE_TOOL_API_KEY
;
const
INVOICE_TOOL_BASE_URL
=
process
.
env
.
UMI_APP_INVOICE_TOOL_BASE_URL
||
process
.
env
.
VITE_INVOICE_TOOL_BASE_URL
||
'https://api.deepseek.com'
;
const
useStyle
=
createStyles
(({
token
,
css
,
responsive
})
=>
{
return
{
chat
:
css
`
...
...
@@ -437,8 +448,8 @@ const InvoiceAssistant = forwardRef((props, ref) => {
return
originMessage
;
}
currentThink
=
messageData
?.
choices
?.[
0
]?.
delta
?.
reasoning_content
||
''
;
currentContent
=
messageData
?.
choices
?.[
0
]?.
delta
?.
content
||
''
;
currentThink
=
extractLlmChunkReasoning
(
messageData
)
;
currentContent
=
extractLlmChunkContent
(
messageData
)
;
messageData
?.
choices
?.[
0
]?.
delta
?.
tool_calls
?.
forEach
((
call
)
=>
{
const
index
=
call
.
index
;
const
toolCall
=
(
toolCalls
[
index
]
=
toolCalls
[
index
]
||
{
...
...
@@ -729,7 +740,10 @@ const InvoiceAssistant = forwardRef((props, ref) => {
}
const
content
=
JSON
.
stringify
(
requestMessages
);
const
long
=
content
.
length
>
900000
;
const
model
=
long
?
'qwen-long'
:
'qwen-plus'
;
const
model
=
await
resolveLlmModel
({
long
,
thinking
:
false
,
});
const
enable_search
=
false
;
const
enable_thinking
=
false
;
...
...
@@ -800,8 +814,10 @@ const InvoiceAssistant = forwardRef((props, ref) => {
)
{
mcpArguments
=
{
...
mcpArguments
,
apikey
:
'sk-bf3698390f3b40dd8435cb73169a7437'
,
baseurl
:
'https://api.deepseek.com'
,
...(
INVOICE_TOOL_API_KEY
?
{
apikey
:
INVOICE_TOOL_API_KEY
}
:
{}),
baseurl
:
INVOICE_TOOL_BASE_URL
,
};
}
...
...
src/pages/Home/index.jsx
View file @
671bc70b
...
...
@@ -535,7 +535,12 @@ function buildConversationItems(conversations = []) {
return
conversations
.
map
((
c
)
=>
({
key
:
c
.
name
,
label
:
c
.
metadata
.
label
||
'新会话'
,
icon
:
c
.
metadata
.
topic
?
<
BorderlessTableOutlined
/>
:
<
CommentOutlined
/>,
icon
:
c
.
metadata
.
topic
||
c
.
metadata
.
topicConfig
?
(
<
BorderlessTableOutlined
/>
)
:
(
<
CommentOutlined
/>
),
pinned
:
c
.
metadata
.
pinned
,
group
:
'历史会话'
,
}));
...
...
@@ -545,7 +550,12 @@ function buildCompactConversationItems(conversations = []) {
return
conversations
.
slice
(
0
,
6
).
map
((
c
)
=>
({
key
:
c
.
name
,
label
:
c
.
metadata
.
label
||
'新会话'
,
icon
:
c
.
metadata
.
topic
?
<
BorderlessTableOutlined
/>
:
<
CommentOutlined
/>,
icon
:
c
.
metadata
.
topic
||
c
.
metadata
.
topicConfig
?
(
<
BorderlessTableOutlined
/>
)
:
(
<
CommentOutlined
/>
),
pinned
:
c
.
metadata
.
pinned
,
}));
}
...
...
src/services/DataService.js
View file @
671bc70b
...
...
@@ -4,7 +4,117 @@ import { request } from '@umijs/max';
const
SUBJECT_CONVERSATION
=
'ai_conversation'
;
const
SUBJECT_TOPIC
=
'ai_topic'
;
const
SUBJECT_KNOWLEDGEBASE
=
'ai_knowledgebase'
;
const
LLM_API_BASE
=
process
.
env
.
UMI_APP_LLM_API_BASE
||
process
.
env
.
VITE_LLM_API_BASE
||
'/llm-api'
;
const
LLM_CHAT_PATH
=
process
.
env
.
UMI_APP_LLM_CHAT_PATH
||
process
.
env
.
VITE_LLM_CHAT_PATH
||
'/v1/chat/completions'
;
const
LLM_API_KEY
=
process
.
env
.
UMI_APP_LLM_API_KEY
||
process
.
env
.
VITE_LLM_API_KEY
;
const
LLM_MODEL
=
process
.
env
.
UMI_APP_LLM_MODEL
||
process
.
env
.
VITE_LLM_MODEL
||
'gpt-5.5'
;
function
joinUrl
(
baseUrl
,
path
)
{
return
`
${
baseUrl
.
replace
(
/
\/
+$/
,
''
)}
/
${
path
.
replace
(
/^
\/
+/
,
''
)}
`
;
}
export
function
extractLlmChunkContent
(
value
)
{
if
(
typeof
value
===
'string'
)
{
return
value
;
}
if
(
!
value
||
typeof
value
!==
'object'
)
{
return
''
;
}
if
(
typeof
value
.
content
===
'string'
)
{
return
value
.
content
;
}
if
(
typeof
value
.
text
===
'string'
)
{
return
value
.
text
;
}
const
delta
=
value
.
delta
;
if
(
delta
&&
typeof
delta
===
'object'
)
{
const
deltaContent
=
extractLlmChunkContent
(
delta
);
if
(
deltaContent
)
{
return
deltaContent
;
}
}
const
message
=
value
.
message
;
if
(
message
&&
typeof
message
===
'object'
)
{
const
messageContent
=
extractLlmChunkContent
(
message
);
if
(
messageContent
)
{
return
messageContent
;
}
}
const
data
=
value
.
data
;
if
(
data
&&
typeof
data
===
'object'
)
{
const
dataContent
=
extractLlmChunkContent
(
data
);
if
(
dataContent
)
{
return
dataContent
;
}
}
const
choices
=
value
.
choices
;
if
(
Array
.
isArray
(
choices
))
{
return
choices
.
map
((
choice
)
=>
extractLlmChunkContent
(
choice
)).
join
(
''
);
}
return
''
;
}
export
function
extractLlmChunkReasoning
(
value
)
{
if
(
!
value
||
typeof
value
!==
'object'
)
{
return
''
;
}
const
reasoning
=
value
.
reasoning_content
||
value
.
reasoning
||
value
.
thinking_content
||
value
.
thought
||
value
.
thoughts
;
if
(
typeof
reasoning
===
'string'
)
{
return
reasoning
;
}
const
delta
=
value
.
delta
;
if
(
delta
&&
typeof
delta
===
'object'
)
{
const
deltaReasoning
=
extractLlmChunkReasoning
(
delta
);
if
(
deltaReasoning
)
{
return
deltaReasoning
;
}
}
const
message
=
value
.
message
;
if
(
message
&&
typeof
message
===
'object'
)
{
const
messageReasoning
=
extractLlmChunkReasoning
(
message
);
if
(
messageReasoning
)
{
return
messageReasoning
;
}
}
const
data
=
value
.
data
;
if
(
data
&&
typeof
data
===
'object'
)
{
const
dataReasoning
=
extractLlmChunkReasoning
(
data
);
if
(
dataReasoning
)
{
return
dataReasoning
;
}
}
const
choices
=
value
.
choices
;
if
(
Array
.
isArray
(
choices
))
{
return
choices
.
map
((
choice
)
=>
extractLlmChunkReasoning
(
choice
)).
join
(
''
);
}
return
''
;
}
export
function
getApplication
(
name
)
{
return
request
(
`/api/application/
${
name
}
`
,
{
...
...
@@ -158,14 +268,37 @@ export async function callMcpTool(mcpName, toolName, data = {}) {
}
export
async
function
llmChat
(
data
,
signal
=
undefined
)
{
return
fetch
(
`/api/llm/chat`
,
{
method
:
'post'
,
headers
:
{
'Content-Type'
:
'application/json'
,
},
if
(
!
LLM_API_KEY
)
{
throw
new
Error
(
'缺少 UMI_APP_LLM_API_KEY,请配置线上模型服务 API Key。'
);
}
const
headers
=
new
Headers
({
Accept
:
'text/event-stream'
,
Authorization
:
`Bearer
${
LLM_API_KEY
}
`
,
'Content-Type'
:
'application/json'
,
});
const
response
=
await
fetch
(
joinUrl
(
LLM_API_BASE
,
LLM_CHAT_PATH
),
{
method
:
'POST'
,
headers
,
signal
,
body
:
JSON
.
stringify
(
data
),
body
:
JSON
.
stringify
({
...
data
,
model
:
LLM_MODEL
,
stream
:
true
,
}),
});
if
(
!
response
.
ok
)
{
const
message
=
await
response
.
text
();
throw
new
Error
(
message
||
`HTTP
${
response
.
status
}
`
);
}
return
response
;
}
export
async
function
resolveLlmModel
(
options
=
{})
{
return
LLM_MODEL
;
}
export
async
function
queryConversations
(
query
)
{
...
...
@@ -179,7 +312,7 @@ export async function queryConversations(query) {
page_size
:
20
,
mode
:
'basic'
,
select
:
'metadata.label metadata.pinned metadata.agent metadata.a
vatar metadata.topic
'
,
'metadata.label metadata.pinned metadata.agent metadata.a
gentConfig metadata.avatar metadata.topic metadata.topicConfig metadata.knowledgeBases
'
,
sort
:
'-metadata.pinned -created_at'
,
filter
:
{
'metadata.user'
:
userInfo
.
_id
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment