Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
水玉婷
ai-wechat
Commits
7d91f005
Commit
7d91f005
authored
Dec 18, 2025
by
水玉婷
Browse files
feat:增加思考过程
parent
091c7fb9
Changes
3
Hide whitespace changes
Inline
Side-by-side
src/views/components/AiChat.vue
View file @
7d91f005
...
...
@@ -53,9 +53,9 @@
<div
v-else
v-html=
"item.content"
class=
"message-inner-box"
></div>
<!-- 思考过程框 -->
<div
v-if=
"item.hasThinkBox"
class=
"think-box-wrapper"
>
<div
class=
"think-box-toggle"
@
click=
"toggleThinkBox(index, i)"
>
{{
item.thinkBoxExpanded ? '▲
收起思考过程
' : '▼
展开思考过程
'
}}
</div>
<div
class=
"think-box-toggle"
@
click=
"toggleThinkBox(index, i)"
>
{{
item.thinkBoxExpanded ? '▲ ' : '▼ '
}}
<
span
v-if=
"item.thinkingTimeText"
class=
"thinking-text"
>
{{ item.thinkingTimeText }}
</span><
/div>
<div
v-if=
"item.thinkBoxExpanded"
class=
"think-box-content"
v-html=
"templateService.generateThinkingTemplate(item.thinkContent || '')"
></div>
</div>
...
...
src/views/components/style.less
View file @
7d91f005
...
...
@@ -312,15 +312,6 @@ li {
}
// 思考框样式
.think-box-wrapper {
margin: 12px 0;
padding: 10px 15px;
background-color: #f5f8f7;
border-radius: 12px;
border: 1px solid #e3ecea;
transition: all 0.3s ease;
}
:deep(.think-box-toggle) {
color: @primary-color;
cursor: pointer;
...
...
@@ -328,33 +319,23 @@ li {
text-decoration: none;
align-items: center;
gap: 4px;
font-weight: 500;
padding: 4px 8px;
border-radius: 4px;
transition: all 0.2s ease;
.thinking-text {
margin-left: 6px;
color: @gray-7;
font-size: 13px;
}
}
:deep(.think-box-content) {
margin-top: 8px;
background-color: @white;
padding: 12px 16px;
border-radius: 8px;
border: 1px solid #e9ecef;
font-size: 0px;
color: #495057;
white-space: pre-wrap;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
animation: fadeIn 0.3s ease-in-out;
.think-content {
font-size: 0;
.think-line {
font-size: 13px;
color: @gray-7;
font-style: italic;
}
.think-content {
font-size: 14px;
color: @gray-5;
}
}
...
...
src/views/components/utils/contentTemplateService.ts
View file @
7d91f005
...
...
@@ -25,6 +25,8 @@ export interface MessageBlock {
src
:
string
;
durationTime
:
string
;
};
thinkingTime
?:
number
;
thinkingTimeText
?:
string
;
}
// 消息类型定义
...
...
@@ -59,6 +61,49 @@ export interface TemplateProcessResult {
newDialogSessionId
:
string
;
}
// 检查最后一个块是否是普通文本块
function
isLastBlockText
(
blocks
:
MessageBlock
[]):
boolean
{
if
(
blocks
.
length
===
0
)
return
false
;
const
lastBlock
=
blocks
[
blocks
.
length
-
1
];
// 普通文本块的条件:有content且没有其他特殊类型数据
return
!!
lastBlock
.
content
&&
!
lastBlock
.
audioData
&&
!
lastBlock
.
chartData
&&
!
lastBlock
.
thinkContent
;
}
// 获取最后一个普通文本块的索引
function
getLastTextBlockIndex
(
blocks
:
MessageBlock
[]):
number
{
for
(
let
i
=
blocks
.
length
-
1
;
i
>=
0
;
i
--
)
{
const
block
=
blocks
[
i
];
if
(
!!
block
.
content
&&
!
block
.
audioData
&&
!
block
.
chartData
&&
!
block
.
thinkContent
)
{
return
i
;
}
}
return
-
1
;
}
// 合并普通文本内容
function
mergeTextContent
(
existingContent
:
string
,
newContent
:
string
):
string
{
// 从现有内容中提取纯文本(去掉HTML标签)
const
existingText
=
existingContent
.
replace
(
/<
[^
>
]
*>/g
,
''
).
trim
();
const
newText
=
newContent
.
trim
();
// 如果现有内容为空,直接返回新内容的模板
if
(
!
existingText
)
{
return
`<div class=\"message-text\">
${
newText
}
</div>`
;
}
// 合并文本内容
const
mergedText
=
existingText
+
'
\n
'
+
newText
;
// 返回合并后的HTML模板
return
`<div class=\"message-text\">
${
mergedText
}
</div>`
;
}
// 内容模板服务类
export
class
ContentTemplateService
{
private
templates
:
ContentTemplates
;
...
...
@@ -79,11 +124,7 @@ export class ContentTemplateService {
// 思考过程
thinking
:
(
content
:
string
)
=>
{
const
formattedContent
=
content
.
split
(
'
\n
'
)
.
map
((
line
)
=>
`<div class="think-line">
${
line
}
</div>`
)
.
join
(
''
);
return
`<div class="think-content">
${
formattedContent
}
</div>`
;
return
`<div class="think-content">
${
content
}
</div>`
;
},
// 错误信息
...
...
@@ -207,55 +248,12 @@ export class ContentTemplateService {
let
completionTokens
=
0
;
let
totalTokens
=
0
;
let
newDialogSessionId
=
''
;
// 删除局部变量 thinkingStartTime,使用类的实例变量
// 根据是否为历史数据设置默认展开状态
const
defaultThinkBoxExpanded
=
!
isHistoryData
;
// 检查是否是"正在思考中....."消息(仅当状态为0且类型为0时)
const
isThinkingMessage
=
contentStatus
===
0
&&
contentType
===
0
&&
typeof
messageContent
===
'
string
'
&&
messageContent
.
includes
(
'
正在思考中.....
'
);
// 跟踪思考状态的变量
let
isCurrentlyThinking
=
updatedResponse
&&
updatedResponse
.
contentBlocks
.
length
>
0
&&
updatedResponse
.
contentBlocks
.
some
(
block
=>
block
.
content
.
includes
(
'
think-message
'
));
// 处理思考开始时间(基于"正在思考中....."文本的出现)
if
(
isThinkingMessage
&&
!
this
.
thinkingStartTime
)
{
// 思考开始,记录开始时间
this
.
thinkingStartTime
=
Date
.
now
();
}
// 检查是否是思考完成的消息("正在思考中....."文本消失)
const
isThinkingComplete
=
contentStatus
===
0
&&
contentType
===
0
&&
!
isThinkingMessage
&&
this
.
thinkingStartTime
;
// 处理思考完成状态(在所有状态分支之前处理)
if
(
isThinkingComplete
)
{
// 如果思考完成,更新所有包含"正在思考中....."的消息
if
(
updatedResponse
&&
updatedResponse
.
contentBlocks
.
length
>
0
)
{
let
thinkingTimeText
=
''
;
// 计算思考用时
if
(
this
.
thinkingStartTime
)
{
const
thinkingEndTime
=
Date
.
now
();
const
thinkingTimeSeconds
=
Math
.
round
((
thinkingEndTime
-
this
.
thinkingStartTime
)
/
1000
);
thinkingTimeText
=
`(用时:
${
thinkingTimeSeconds
}
s)`
;
// 重置思考开始时间
this
.
thinkingStartTime
=
null
;
}
updatedResponse
.
contentBlocks
.
forEach
(
block
=>
{
// 只在包含"正在思考中....."文本的块中添加用时信息
if
(
block
.
content
&&
block
.
content
.
includes
(
'
正在思考中.....
'
))
{
block
.
content
=
block
.
content
.
replace
(
'
正在思考中.....
'
,
`已完成思考
${
thinkingTimeText
}
`
);
}
if
(
block
.
thinkContent
&&
block
.
thinkContent
.
includes
(
'
正在思考中.....
'
))
{
block
.
thinkContent
=
block
.
thinkContent
.
replace
(
'
正在思考中.....
'
,
`已完成思考
${
thinkingTimeText
}
`
);
}
});
}
}
switch
(
contentStatus
)
{
case
-
1
:
// 错误信息
if
(
updatedResponse
)
{
...
...
@@ -306,50 +304,12 @@ export class ContentTemplateService {
thinkBoxExpanded
:
false
,
});
}
else
{
// 走选项
updatedResponse
.
contentBlocks
.
push
({
content
:
this
.
templates
.
option
(
messageContent
),
hasThinkBox
:
false
,
thinkContent
:
''
,
thinkBoxExpanded
:
false
,
});
}
}
break
;
case
4
:
// MD格式
if
(
updatedResponse
)
{
// 对于SSE流式数据,使用流式处理
const
markdownContent
=
templateTools
?.
markdownTemplate
?
templateTools
.
markdownTemplate
(
messageContent
||
''
,
true
)
:
this
.
templates
.
markdown
(
messageContent
||
''
,
true
);
// 检查最后一个块是否是markdown块
const
isLastMarkdown
=
templateTools
?.
isLastBlockMarkdown
?
templateTools
.
isLastBlockMarkdown
(
updatedResponse
.
contentBlocks
)
:
isLastBlockMarkdown
(
updatedResponse
.
contentBlocks
);
if
(
isLastMarkdown
)
{
// 合并到现有的markdown块
const
lastMarkdownIndex
=
templateTools
?.
getLastMarkdownBlockIndex
?
templateTools
.
getLastMarkdownBlockIndex
(
updatedResponse
.
contentBlocks
)
:
getLastMarkdownBlockIndex
(
updatedResponse
.
contentBlocks
);
if
(
lastMarkdownIndex
!==
-
1
)
{
updatedResponse
.
contentBlocks
[
lastMarkdownIndex
].
content
=
templateTools
?.
mergeMarkdownContent
?
templateTools
.
mergeMarkdownContent
(
updatedResponse
.
contentBlocks
[
lastMarkdownIndex
].
content
,
markdownContent
)
:
mergeMarkdownContent
(
updatedResponse
.
contentBlocks
[
lastMarkdownIndex
].
content
,
markdownContent
);
}
}
else
{
// 创建新的markdown块
updatedResponse
.
contentBlocks
.
push
({
content
:
markdownContent
,
content
:
this
.
templates
.
option
({
tips
,
options
,
}),
hasThinkBox
:
false
,
thinkContent
:
''
,
thinkBoxExpanded
:
false
,
...
...
@@ -357,28 +317,24 @@ export class ContentTemplateService {
}
}
break
;
default
:
// 默认处理
updatedResponse
.
contentBlocks
.
push
({
content
:
this
.
templates
.
text
(
messageContent
||
''
),
hasThinkBox
:
false
,
thinkContent
:
''
,
thinkBoxExpanded
:
false
,
});
break
;
}
}
break
;
case
10
:
// 思考开始
updatedIsThinking
=
true
;
// 记录思考开始时间
this
.
thinkingStartTime
=
Date
.
now
();
if
(
updatedBlockIndex
===
-
1
&&
updatedResponse
)
{
updatedBlockIndex
=
updatedResponse
.
contentBlocks
.
length
;
updatedResponse
.
contentBlocks
.
push
({
content
:
''
,
thinkContent
:
`
${
messageContent
}
`
,
hasThinkBox
:
true
,
thinkBoxExpanded
:
defaultThinkBoxExpanded
,
thinkBoxExpanded
:
false
,
thinkingTime
:
0
,
thinkingTimeText
:
'
正在思考中……
'
,
});
}
else
if
(
updatedResponse
&&
updatedResponse
.
contentBlocks
[
updatedBlockIndex
])
{
updatedResponse
.
contentBlocks
[
updatedBlockIndex
].
thinkContent
+=
``
;
...
...
@@ -389,41 +345,27 @@ export class ContentTemplateService {
case
11
:
// 思考结束
if
(
updatedResponse
&&
updatedBlockIndex
!==
-
1
&&
updatedResponse
.
contentBlocks
[
updatedBlockIndex
])
{
updatedResponse
.
contentBlocks
[
updatedBlockIndex
].
thinkContent
+=
``
;
const
currentThinkContent
=
updatedResponse
.
contentBlocks
[
updatedBlockIndex
].
thinkContent
;
// 计算思考用时
const
thinkingTime
=
this
.
thinkingStartTime
?
Math
.
round
((
Date
.
now
()
-
this
.
thinkingStartTime
)
/
1000
)
:
0
;
const
thinkingTimeText
=
thinkingTime
>
0
?
`已完成思考 (用时:
${
thinkingTime
}
s)`
:
''
;
updatedResponse
.
contentBlocks
[
updatedBlockIndex
].
thinkContent
=
currentThinkContent
;
// 添加思考时长信息到内容块中,供前端模板使用
updatedResponse
.
contentBlocks
[
updatedBlockIndex
].
thinkingTime
=
thinkingTime
;
updatedResponse
.
contentBlocks
[
updatedBlockIndex
].
thinkingTimeText
=
thinkingTimeText
;
updatedResponse
.
contentBlocks
[
updatedBlockIndex
].
hasThinkBox
=
true
;
updatedResponse
.
contentBlocks
[
updatedBlockIndex
].
thinkBoxExpanded
=
defaultThinkBoxExpanded
;
// 思考结束后保持展开状态
updatedResponse
.
contentBlocks
[
updatedBlockIndex
].
thinkBoxExpanded
=
true
;
// 重置思考开始时间
this
.
thinkingStartTime
=
null
;
}
updatedIsThinking
=
false
;
break
;
case
0
:
// 普通内容状态
if
(
isThinkingMessage
||
isCurrentlyThinking
)
{
// 如果是思考中消息或当前处于思考状态,添加think类别
if
(
updatedResponse
)
{
updatedResponse
.
contentBlocks
.
push
({
content
:
`<div class="message-text think-message">
${
messageContent
}
</div>`
,
hasThinkBox
:
false
,
thinkContent
:
''
,
thinkBoxExpanded
:
false
,
});
// 标记为当前处于思考状态
isCurrentlyThinking
=
true
;
}
}
else
{
// 普通消息处理
if
(
updatedResponse
)
{
updatedResponse
.
contentBlocks
.
push
({
content
:
this
.
templates
.
text
(
messageContent
),
hasThinkBox
:
false
,
thinkContent
:
''
,
thinkBoxExpanded
:
false
,
});
// 普通消息结束思考状态
isCurrentlyThinking
=
false
;
}
}
break
;
case
20
:
// 初始连接回传信息
if
(
updatedResponse
)
{
updatedResponse
.
contentBlocks
.
push
({
...
...
@@ -446,35 +388,59 @@ export class ContentTemplateService {
completionTokens
=
messageContent
?.
completionTokens
||
0
;
totalTokens
=
messageContent
?.
totalTokens
||
0
;
// 只有实时对话才在29时折叠思考框,历史数据不受影响
if
(
!
isHistoryData
&&
updatedResponse
&&
updatedResponse
.
contentBlocks
.
length
>
0
)
{
updatedResponse
.
contentBlocks
.
forEach
((
block
)
=>
{
if
(
block
.
hasThinkBox
)
{
block
.
thinkBoxExpanded
=
false
;
}
});
}
// 修改:不再自动折叠思考框,保持用户当前的展开状态
// if (!isHistoryData && updatedResponse && updatedResponse.contentBlocks.length > 0) {
// updatedResponse.contentBlocks.forEach((block) => {
// if (block.hasThinkBox) {
// block.thinkBoxExpanded = false;
// }
// });
// }
updatedIsThinking
=
false
;
updatedBlockIndex
=
-
1
;
// 会话结束时重置思考开始时间
this
.
thinkingStartTime
=
null
;
break
;
default
:
// 普通内容
if
(
updatedIsThinking
&&
updatedResponse
)
{
if
(
updatedBlockIndex
!==
-
1
&&
updatedResponse
.
contentBlocks
[
updatedBlockIndex
])
{
updatedResponse
.
contentBlocks
[
updatedBlockIndex
].
thinkContent
+=
`\n
${
messageContent
}
`
;
// 获取当前思考内容
const
currentThinkContent
=
updatedResponse
.
contentBlocks
[
updatedBlockIndex
].
thinkContent
;
// 如果思考内容为空,直接设置新内容
if
(
!
currentThinkContent
)
{
updatedResponse
.
contentBlocks
[
updatedBlockIndex
].
thinkContent
=
messageContent
;
}
else
{
// 否则追加新内容(用换行符分隔)
updatedResponse
.
contentBlocks
[
updatedBlockIndex
].
thinkContent
=
currentThinkContent
+
messageContent
;
}
updatedResponse
.
contentBlocks
[
updatedBlockIndex
].
hasThinkBox
=
true
;
updatedResponse
.
contentBlocks
[
updatedBlockIndex
].
thinkBoxExpanded
=
defaultThinkBoxExpanded
;
}
}
else
if
(
updatedResponse
)
{
updatedBlockIndex
=
updatedResponse
.
contentBlocks
.
length
;
updatedResponse
.
contentBlocks
.
push
({
content
:
this
.
templates
.
text
(
messageContent
),
hasThinkBox
:
false
,
thinkContent
:
''
,
thinkBoxExpanded
:
false
,
});
// 检查最后一个块是否是普通文本块,如果是则合并,否则创建新块
const
isLastText
=
isLastBlockText
(
updatedResponse
.
contentBlocks
);
if
(
isLastText
)
{
// 合并到现有的普通文本块
const
lastTextIndex
=
getLastTextBlockIndex
(
updatedResponse
.
contentBlocks
);
if
(
lastTextIndex
!==
-
1
)
{
updatedResponse
.
contentBlocks
[
lastTextIndex
].
content
=
mergeTextContent
(
updatedResponse
.
contentBlocks
[
lastTextIndex
].
content
,
messageContent
);
}
}
else
{
// 创建新的内容块
updatedBlockIndex
=
updatedResponse
.
contentBlocks
.
length
;
updatedResponse
.
contentBlocks
.
push
({
content
:
this
.
templates
.
text
(
messageContent
),
hasThinkBox
:
false
,
thinkContent
:
''
,
thinkBoxExpanded
:
false
,
});
}
}
break
;
}
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new 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