Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
P
poc-fe
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
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
poc
poc-fe
Commits
852687d7
Commit
852687d7
authored
Mar 04, 2025
by
nick zheng
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 应用预览调试及发布支持推理内容展示
parent
1a700198
Show whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
418 additions
and
113 deletions
+418
-113
useBackBottom.ts
src/composables/useBackBottom.ts
+34
-0
useEventSource.ts
src/composables/useEventSource.ts
+8
-9
en.yaml
src/locales/langs/en.yaml
+2
-0
zh-cn.yaml
src/locales/langs/zh-cn.yaml
+2
-0
zh-hk.yaml
src/locales/langs/zh-hk.yaml
+2
-0
footer-operation.vue
...iews/multi-model-dialogue/components/footer-operation.vue
+16
-10
message-item.vue
src/views/multi-model-dialogue/components/message-item.vue
+52
-5
message-list.vue
src/views/multi-model-dialogue/components/message-list.vue
+32
-7
types.d.ts
src/views/multi-model-dialogue/types.d.ts
+1
-0
fetch-event-stream-source.ts
...s/multi-model-dialogue/utils/fetch-event-stream-source.ts
+8
-9
agent-preview.vue
...g/components/agent-config/agent-preview/agent-preview.vue
+1
-1
footer-input.vue
...ts/agent-config/agent-preview/components/footer-input.vue
+41
-22
message-item.vue
...ts/agent-config/agent-preview/components/message-item.vue
+55
-2
message-list.vue
...ts/agent-config/agent-preview/components/message-list.vue
+27
-3
agent-setting.vue
...g/components/agent-config/agent-setting/agent-setting.vue
+5
-9
optimize-system-modal.vue
...config/agent-setting/components/optimize-system-modal.vue
+4
-8
footer-input.vue
src/views/share/components/footer-input.vue
+42
-21
message-item.vue
src/views/share/components/message-item.vue
+54
-2
message-list.vue
src/views/share/components/message-list.vue
+27
-3
share-application-mobile.vue
src/views/share/share-application-mobile.vue
+1
-1
share-application-web.vue
src/views/share/share-application-web.vue
+1
-1
conversation.d.ts
types/conversation.d.ts
+1
-0
locales.d.ts
types/locales.d.ts
+2
-0
No files found.
src/composables/useBackBottom.ts
0 → 100644
View file @
852687d7
import
{
ref
}
from
'vue'
import
{
throttle
}
from
'lodash-es'
export
function
useBackBottom
(
cb
:
()
=>
void
)
{
const
visible
=
ref
(
false
)
const
lastScrollTop
=
ref
(
0
)
function
clickBackBottom
()
{
visible
.
value
=
false
cb
()
}
function
handleScrollMessageContainer
(
e
:
Event
)
{
const
target
=
e
.
target
as
HTMLElement
const
currentScrollTop
=
target
.
scrollTop
// 向上滚动,显示返回底部图标
if
(
currentScrollTop
<
lastScrollTop
.
value
)
{
visible
.
value
=
true
}
// 是否滚动触底
if
(
currentScrollTop
+
target
.
clientHeight
>=
target
.
scrollHeight
-
5
)
{
visible
.
value
=
false
}
lastScrollTop
.
value
=
currentScrollTop
}
const
throttleScrollMessageContainer
=
throttle
(
handleScrollMessageContainer
,
100
,
{
leading
:
true
})
return
{
visible
,
clickBackBottom
,
throttleScrollMessageContainer
}
}
src/composables/useEventSource.ts
View file @
852687d7
...
...
@@ -5,6 +5,12 @@ import { useUserStore } from '@/store/modules/user'
import
{
useSystemLanguageStore
}
from
'@/store/modules/system-language'
import
{
languageKeyTransform
}
from
'@/utils/language-key-transform'
interface
ResponseData
{
message
:
string
reasoningContent
:
string
function
:
{
name
:
string
}
}
const
{
t
}
=
i18n
.
global
const
ENV
=
import
.
meta
.
env
.
VITE_APP_ENV
...
...
@@ -15,7 +21,7 @@ export function fetchCustomEventSource(config: {
path
:
string
payload
:
any
controller
:
AbortController
on
Message
:
(
data
:
string
)
=>
void
on
Response
:
(
_data
:
ResponseData
)
=>
void
onRequestError
:
(
err
:
any
)
=>
void
onError
?:
(
err
:
any
)
=>
void
onFinally
?:
()
=>
void
...
...
@@ -36,7 +42,6 @@ export function fetchCustomEventSource(config: {
openWhenHidden
:
true
,
onmessage
:
(
e
)
=>
{
if
(
e
.
data
===
'[DONE]'
&&
!
responseError
)
{
config
.
onMessage
(
e
.
data
)
config
.
onFinally
&&
config
.
onFinally
()
return
...
...
@@ -66,13 +71,7 @@ export function fetchCustomEventSource(config: {
return
}
// 插件调用
if
(
data
.
function
&&
data
.
function
.
name
)
{
config
.
onMessage
(
data
.
function
)
return
}
config
.
onMessage
(
data
.
message
)
config
.
onResponse
(
data
)
}
catch
(
err
)
{
config
.
onRequestError
(
err
)
...
...
src/locales/langs/en.yaml
View file @
852687d7
...
...
@@ -140,6 +140,8 @@ common_module:
plugin_in_progress
:
'
{pluginName}
Plugin
in
Progress'
plugin_executed_successfully
:
'
{pluginName}
Plugin
Executed
Successfully'
upload_image
:
'
Upload
Image'
deep_thinking
:
'
{modelName}
deep
thinking'
have_thought_deeply
:
'
Have
thought
deeply'
dialogue_module
:
continue_question_message
:
'
You
can
keep
asking
questions'
...
...
src/locales/langs/zh-cn.yaml
View file @
852687d7
...
...
@@ -139,6 +139,8 @@ common_module:
plugin_in_progress
:
'
{pluginName}插件执行中...'
plugin_executed_successfully
:
'
{pluginName}插件执行成功'
upload_image
:
'
上传图片'
deep_thinking
:
'
{modelName}深度思考中...'
have_thought_deeply
:
'
已深度思考'
dialogue_module
:
continue_question_message
:
'
你可以继续提问'
...
...
src/locales/langs/zh-hk.yaml
View file @
852687d7
...
...
@@ -139,6 +139,8 @@ common_module:
plugin_in_progress
:
'
{pluginName}插件執行中...'
plugin_executed_successfully
:
'
{pluginName}插件執行成功'
upload_image
:
'
上傳圖片'
deep_thinking
:
'
{modelName}深度思考中...'
have_thought_deeply
:
'
已深度思考'
dialogue_module
:
continue_question_message
:
'
你可以繼續提問'
...
...
src/views/multi-model-dialogue/components/footer-operation.vue
View file @
852687d7
...
...
@@ -95,6 +95,7 @@ function messageItemFactory() {
isAnswerResponseLoading
:
false
,
pluginName
:
''
,
imageUrl
:
''
,
reasoningContent
:
''
,
}
as
MessageItemInterface
}
...
...
@@ -147,6 +148,7 @@ function handleQuestionSubmit() {
const
answerMessageId
=
nanoid
()
let
messageContent
=
''
let
reasoningContent
=
''
let
isFirstClip
=
true
emit
(
...
...
@@ -173,22 +175,25 @@ function handleQuestionSubmit() {
channel
:
ChannelType
.
multi_preview
,
},
controller
:
modelItem
.
controller
,
onMessage
:
(
data
:
any
)
=>
{
if
(
data
===
'[DONE]'
)
{
emit
(
'updateMessageItem'
,
answerMessageId
,
{
isAnswerResponseLoading
:
false
},
modelIndex
)
emit
(
'messageListScrollToBottom'
)
modelItem
.
isAnswerResponseWait
=
false
return
onResponse
:
(
data
)
=>
{
// 推理内容
if
(
data
.
reasoningContent
)
{
reasoningContent
+=
data
.
reasoningContent
emit
(
'updateMessageItem'
,
answerMessageId
,
{
reasoningContent
},
modelIndex
)
messageListScrollToBottomThrottle
()
}
if
(
data
&&
data
.
name
)
{
emit
(
'updateMessageItem'
,
answerMessageId
,
{
pluginName
:
data
.
name
},
modelIndex
)
// 插件
if
(
data
.
function
&&
data
.
function
.
name
)
{
emit
(
'updateMessageItem'
,
answerMessageId
,
{
pluginName
:
data
.
function
.
name
},
modelIndex
)
emit
(
'messageListScrollToBottom'
)
return
}
if
(
data
)
{
messageContent
+=
data
// 回复内容
if
(
data
.
message
)
{
messageContent
+=
data
.
message
if
(
isFirstClip
)
{
emit
(
...
...
@@ -215,6 +220,7 @@ function handleQuestionSubmit() {
modelItem
.
controller
=
null
modelItem
.
isAnswerResponseWait
=
false
userStore
.
fetchUpdateEquityInfo
()
emit
(
'updateMessageItem'
,
answerMessageId
,
{
isAnswerResponseLoading
:
false
},
modelIndex
)
emit
(
'messageListScrollToBottom'
)
},
})
...
...
src/views/multi-model-dialogue/components/message-item.vue
View file @
852687d7
<
script
setup
lang=
"ts"
>
import
{
computed
,
readonly
}
from
'vue'
import
{
computed
,
readonly
,
ref
}
from
'vue'
import
{
useI18n
}
from
'vue-i18n'
import
{
CheckOne
}
from
'@icon-park/vue-next'
import
{
CheckOne
,
Down
}
from
'@icon-park/vue-next'
import
type
{
MessageItemInterface
}
from
'../types'
import
MarkdownRender
from
'@/components/markdown-render/markdown-render.vue'
import
MessageBubbleLoading
from
'./message-bubble-loading.vue'
...
...
@@ -14,6 +14,8 @@ const props = defineProps<Props>()
const
{
t
}
=
useI18n
()
const
isShowReasoningContent
=
ref
(
true
)
const
agentAvatarUrl
=
readonly
({
url
:
'https://gsst-poe-sit.gz.bcebos.com/icon/agent-avatar.png'
})
const
isAssistant
=
computed
(()
=>
{
...
...
@@ -23,6 +25,10 @@ const isAssistant = computed(() => {
const
assistantAvatarUrl
=
computed
(()
=>
{
return
props
.
messageItem
.
avatar
||
agentAvatarUrl
.
url
})
function
handleShowReasoningContentSwitch
()
{
isShowReasoningContent
.
value
=
!
isShowReasoningContent
.
value
}
</
script
>
<
template
>
...
...
@@ -34,12 +40,53 @@ const assistantAvatarUrl = computed(() => {
alt=
"Avatar"
/>
<div
class=
"ml-[11px] overflow-auto"
>
<div
class=
"mb-[7px] line-clamp-1 break-all text-[12px] text-[#999]"
>
<div
class=
"ml-[11px] flex flex-col items-start overflow-hidden"
>
<template
v-if=
"isAssistant && messageItem.nickName === 'DeepSeek'"
>
<div
class=
"mb-[7px] select-none text-[14px]"
>
<div
class=
"inline-flex cursor-pointer"
@
click=
"handleShowReasoningContentSwitch"
>
<span
v-if=
"messageItem.isTextContentLoading"
class=
"mr-[6px]"
>
{{
t
(
'common_module.deep_thinking'
,
{
modelName
:
messageItem
.
nickName
}
)
}}
<
/span
>
<
span
v
-
else
class
=
"mr-[6px]"
>
{{
t
(
'common_module.have_thought_deeply'
)
}}
<
/span
>
<
Down
theme
=
"outline"
size
=
"21"
fill
=
"#333"
:
stroke
-
width
=
"3"
class
=
"transition-[rotate] duration-100 ease-linear"
:
class
=
"{ '-rotate-180': isShowReasoningContent
}
"
/>
<
/div
>
<
/div
>
<
n
-
collapse
-
transition
:
show
=
"isShowReasoningContent"
>
<
div
class
=
"my-[14px] border-l-[1px] border-solid border-l-[#ccc] p-[13px]"
>
<
div
>
<
img
v
-
if
=
"!messageItem.reasoningContent && !messageItem.content"
src
=
"@/assets/images/home/bubble-loading.gif"
alt
=
"bubble-loading"
/>
<
template
v
-
else
>
<
MarkdownRender
:
raw
-
text
-
content
=
"
messageItem.reasoningContent
? messageItem.reasoningContent
: t('common_module.dialogue_module.empty_message_content')
"
color
=
"#999"
/>
<
/template
>
<
/div
>
<
/div
>
<
/n-collapse-transition
>
<
/template
>
<
div
v
-
else
class
=
"mb-[7px] line-clamp-1 break-all text-[12px] text-[#999]"
>
{{
props
.
messageItem
.
nickName
}}
<
/div
>
<
div
class=
"
box-content min-h-[21px] min-w-[10px]
rounded-[10px] border border-[#9EA3FF] px-[15px] py-[12px] text-justify"
class
=
"
min-h-[21px] min-w-[10px] max-w-full flex-wrap
rounded-[10px] border border-[#9EA3FF] px-[15px] py-[12px] text-justify"
:
class
=
"{
'bg-[#777EF9]': isAssistant,
'text-[#fff]': isAssistant,
...
...
src/views/multi-model-dialogue/components/message-list.vue
View file @
852687d7
<
script
setup
lang=
"ts"
>
import
{
useTemplateRef
}
from
'vue'
import
{
nextTick
,
useTemplateRef
,
watch
}
from
'vue'
import
{
ScrollbarInst
}
from
'naive-ui'
import
MessageItem
from
'./message-item.vue'
import
type
{
MessageItemInterface
}
from
'../types'
import
{
useBackBottom
}
from
'@/composables/useBackBottom'
interface
Props
{
messageList
:
Map
<
string
,
MessageItemInterface
>
}
defineProps
<
Props
>
()
const
props
=
defineProps
<
Props
>
()
defineExpose
({
scrollToBottom
,
...
...
@@ -16,21 +17,45 @@ defineExpose({
const
scrollbarRef
=
useTemplateRef
<
ScrollbarInst
|
null
>
(
'scrollbarRef'
)
const
{
visible
,
clickBackBottom
,
throttleScrollMessageContainer
}
=
useBackBottom
(
scrollToBottom
)
function
scrollToBottom
()
{
nextTick
(()
=>
{
if
(
scrollbarRef
.
value
)
{
scrollbarRef
.
value
.
scrollTo
({
top
:
999999999
,
behavior
:
'smooth'
})
!
visible
.
value
&&
scrollbarRef
.
value
.
scrollTo
({
top
:
999999999
,
behavior
:
'smooth'
})
}
})
}
watch
(
()
=>
props
.
messageList
.
size
,
()
=>
{
clickBackBottom
()
},
)
</
script
>
<
template
>
<div
class=
"flex-1 overflow-hidden overflow-y-auto py-[20px]"
>
<n-scrollbar
ref=
"scrollbarRef"
class=
"min-h-full"
content-class=
"min-h-full flex"
>
<div
class=
"relative flex-1 overflow-hidden overflow-y-auto py-[20px]"
>
<n-scrollbar
ref=
"scrollbarRef"
class=
"min-h-full"
content-class=
"min-h-full flex"
@
scroll=
"throttleScrollMessageContainer"
>
<div
class=
"flex flex-col-reverse overflow-hidden"
>
<div
class=
"pr-[10px]"
>
<MessageItem
v-for=
"[key, messageItem] in messageList"
:key=
"key"
:message-item=
"messageItem"
/>
</div>
</div>
<div
v-show=
"visible"
class=
"flex-center hover:text-theme-color absolute bottom-5 right-5 h-6 w-6 cursor-pointer rounded-full bg-white shadow-[0_0_0_1px_#ededed]"
@
click
.
stop=
"clickBackBottom"
>
<i
class=
"iconfont icon-decrease text-sm"
/>
</div>
</n-scrollbar>
</div>
</
template
>
src/views/multi-model-dialogue/types.d.ts
View file @
852687d7
...
...
@@ -35,6 +35,7 @@ export interface MessageItemInterface {
isAnswerResponseLoading
:
boolean
pluginName
?:
string
imageUrl
?:
string
reasoningContent
:
string
}
export
interface
LargeModelItem
{
...
...
src/views/multi-model-dialogue/utils/fetch-event-stream-source.ts
View file @
852687d7
...
...
@@ -5,6 +5,12 @@ import { useUserStore } from '@/store/modules/user'
import
{
useSystemLanguageStore
}
from
'@/store/modules/system-language'
import
{
languageKeyTransform
}
from
'@/utils/language-key-transform'
interface
ResponseData
{
message
:
string
reasoningContent
:
string
function
:
{
name
:
string
}
}
const
{
t
}
=
i18n
.
global
const
ENV
=
import
.
meta
.
env
.
VITE_APP_ENV
...
...
@@ -15,7 +21,7 @@ export function fetchEventStreamSource(config: {
path
:
string
payload
:
any
controller
:
AbortController
on
Message
:
(
data
:
string
)
=>
void
on
Response
:
(
data
:
ResponseData
)
=>
void
onRequestError
:
(
err
:
any
)
=>
void
onError
?:
(
err
:
any
)
=>
void
onFinally
?:
()
=>
void
...
...
@@ -36,7 +42,6 @@ export function fetchEventStreamSource(config: {
openWhenHidden
:
true
,
onmessage
:
(
e
)
=>
{
if
(
e
.
data
===
'[DONE]'
&&
!
responseError
)
{
config
.
onMessage
(
e
.
data
)
config
.
onFinally
&&
config
.
onFinally
()
return
...
...
@@ -65,13 +70,7 @@ export function fetchEventStreamSource(config: {
return
}
// 插件调用
if
(
data
.
function
&&
data
.
function
.
name
)
{
config
.
onMessage
(
data
.
function
)
return
}
config
.
onMessage
(
data
.
message
)
config
.
onResponse
(
data
)
}
catch
(
err
)
{
config
.
onRequestError
(
err
)
...
...
src/views/personal-space/personal-app-setting/components/agent-config/agent-preview/agent-preview.vue
View file @
852687d7
...
...
@@ -318,7 +318,7 @@ function handleAudioPause(isClearMessageList = false) {
<Preamble
/>
</div>
<div
v-show=
"messageList.size > 0"
class=
"w-full"
>
<div
v-show=
"messageList.size > 0"
class=
"
relative
w-full"
>
<MessageList
ref=
"messageListRef"
:message-list=
"messageList"
...
...
src/views/personal-space/personal-app-setting/components/agent-config/agent-preview/components/footer-input.vue
View file @
852687d7
...
...
@@ -148,6 +148,7 @@ function messageItemFactory(): ConversationMessageItem {
isVoiceEnabled
:
false
,
pluginName
:
''
,
imageUrl
:
''
,
reasoningContent
:
''
,
}
}
...
...
@@ -236,6 +237,7 @@ function handleMessageSend() {
emit
(
'updatePageScroll'
)
let
replyTextContent
=
''
let
reasoningContent
=
''
controller
=
new
AbortController
()
...
...
@@ -248,31 +250,45 @@ function handleMessageSend() {
messages
,
},
controller
,
onMessage
:
(
data
:
any
)
=>
{
if
(
data
===
'[DONE]'
)
{
emit
(
'updateSpecifyMessageItem'
,
latestAssistantMessageKey
,
{
isEmptyContent
:
!
replyTextContent
,
isTextContentLoading
:
false
,
isAnswerResponseLoading
:
false
,
})
isAnswerResponseLoading
.
value
=
false
isCreateContinueQuestions
.
value
&&
emit
(
'createContinueQuestions'
,
replyTextContent
)
onResponse
:
(
data
)
=>
{
// 推理内容
if
(
data
.
reasoningContent
)
{
reasoningContent
+=
data
.
reasoningContent
emit
(
'updateSpecifyMessageItem'
,
latestAssistantMessageKey
,
{
reasoningContent
:
reasoningContent
})
emit
(
'updatePageScroll'
)
blockMessageResponse
()
assistantFullAnswerContent
.
value
=
(
assistantFullAnswerContent
.
value
+
data
.
reasoningContent
).
replace
(
/
\^\[[\d\\
[
\]
-
]
+
?\]\^
/g
,
''
,
)
if
(
!
sentenceExtractCheckEnabled
.
value
&&
isVoiceEnabled
)
{
sentenceExtract
(
latestAssistantMessageKey
)
sentenceExtractCheckEnabled
.
value
=
true
messageAudioLoading
.
value
=
true
}
return
}
if
(
data
&&
data
.
name
)
{
emit
(
'updateSpecifyMessageItem'
,
latestAssistantMessageKey
,
{
pluginName
:
data
.
name
})
// 插件
if
(
data
.
function
&&
data
.
function
.
name
)
{
emit
(
'updateSpecifyMessageItem'
,
latestAssistantMessageKey
,
{
pluginName
:
data
.
function
.
name
})
emit
(
'updatePageScroll'
)
return
}
if
(
data
)
{
replyTextContent
+=
data
// 回复消息
if
(
data
.
message
)
{
replyTextContent
+=
data
.
message
assistantFullAnswerContent
.
value
=
(
assistantFullAnswerContent
.
value
+
data
).
replace
(
emit
(
'updateSpecifyMessageItem'
,
latestAssistantMessageKey
,
{
textContent
:
replyTextContent
,
isTextContentLoading
:
false
,
})
emit
(
'updatePageScroll'
)
assistantFullAnswerContent
.
value
=
(
assistantFullAnswerContent
.
value
+
data
.
message
).
replace
(
/
\^\[[\d\\
[
\]
-
]
+
?\]\^
/g
,
''
,
)
...
...
@@ -282,12 +298,6 @@ function handleMessageSend() {
sentenceExtractCheckEnabled
.
value
=
true
messageAudioLoading
.
value
=
true
}
emit
(
'updateSpecifyMessageItem'
,
latestAssistantMessageKey
,
{
textContent
:
replyTextContent
,
isTextContentLoading
:
false
,
})
emit
(
'updatePageScroll'
)
}
},
onRequestError
:
()
=>
{
...
...
@@ -297,6 +307,15 @@ function handleMessageSend() {
errorMessageResponse
()
},
onFinally
:
()
=>
{
emit
(
'updateSpecifyMessageItem'
,
latestAssistantMessageKey
,
{
isEmptyContent
:
!
replyTextContent
,
isTextContentLoading
:
false
,
isAnswerResponseLoading
:
false
,
})
isAnswerResponseLoading
.
value
=
false
isCreateContinueQuestions
.
value
&&
emit
(
'createContinueQuestions'
,
replyTextContent
)
emit
(
'updatePageScroll'
)
blockMessageResponse
()
controller
=
null
userStore
.
fetchUpdateEquityInfo
()
},
...
...
src/views/personal-space/personal-app-setting/components/agent-config/agent-preview/components/message-item.vue
View file @
852687d7
<
script
setup
lang=
"ts"
>
import
{
computed
}
from
'vue'
import
{
computed
,
ref
}
from
'vue'
import
{
useI18n
}
from
'vue-i18n'
import
{
CheckOne
}
from
'@icon-park/vue-next'
import
{
CheckOne
,
Down
}
from
'@icon-park/vue-next'
import
CustomLoading
from
'./custom-loading.vue'
import
{
usePersonalAppConfigStore
}
from
'@/store/modules/personal-app-config'
import
MarkdownRender
from
'@/components/markdown-render/markdown-render.vue'
...
...
@@ -24,6 +24,8 @@ const { t } = useI18n()
const
userStore
=
useUserStore
()
const
personalAppConfigStore
=
usePersonalAppConfigStore
()
const
isShowReasoningContent
=
ref
(
true
)
const
useAvatar
=
computed
(()
=>
{
return
userStore
.
userInfo
.
avatarUrl
||
'https://gsst-poe-sit.gz.bcebos.com/data/20240910/1725952917468.png'
})
...
...
@@ -44,6 +46,10 @@ const isShowVoiceLoading = computed(() => {
return
props
.
role
===
'assistant'
&&
props
.
messageItem
.
isVoiceLoading
&&
props
.
messageItem
.
isVoiceEnabled
})
const
isDeepSeekR1
=
computed
(()
=>
{
return
personalAppConfigStore
.
commModelConfig
.
largeModel
===
'DeepSeek'
})
function
handleAudioControl
()
{
if
(
!
isPlayableAudio
.
value
)
{
return
...
...
@@ -55,6 +61,10 @@ function handleAudioControl() {
emit
(
'audioPlay'
)
}
}
function
handleShowReasoningContentSwitch
()
{
isShowReasoningContent
.
value
=
!
isShowReasoningContent
.
value
}
</
script
>
<
template
>
...
...
@@ -69,6 +79,49 @@ function handleAudioControl() {
/>
<div
class=
"flex flex-col items-start overflow-x-auto"
>
<template
v-if=
"role === 'assistant' && isDeepSeekR1"
>
<div
class=
"my-[7px] select-none text-[14px]"
>
<div
class=
"inline-flex cursor-pointer"
@
click=
"handleShowReasoningContentSwitch"
>
<span
v-if=
"messageItem.isTextContentLoading"
class=
"mr-[6px]"
>
{{
t
(
'common_module.deep_thinking'
,
{
modelName
:
personalAppConfigStore
.
commModelConfig
.
largeModel
}
)
}}
<
/span
>
<
span
v
-
else
class
=
"mr-[6px]"
>
{{
t
(
'common_module.have_thought_deeply'
)
}}
<
/span
>
<
Down
theme
=
"outline"
size
=
"21"
fill
=
"#333"
:
stroke
-
width
=
"3"
class
=
"transition-[rotate] duration-100 ease-linear"
:
class
=
"{ '-rotate-180': isShowReasoningContent
}
"
/>
<
/div
>
<
/div
>
<
n
-
collapse
-
transition
:
show
=
"isShowReasoningContent"
>
<
div
class
=
"my-[14px] border-l-[1px] border-solid border-l-[#ccc] p-[13px]"
>
<
div
>
<
img
v
-
if
=
"!messageItem.reasoningContent && !messageItem.textContent"
src
=
"@/assets/images/home/bubble-loading.gif"
alt
=
"bubble-loading"
/>
<
template
v
-
else
>
<
MarkdownRender
:
raw
-
text
-
content
=
"
messageItem.reasoningContent
? messageItem.reasoningContent
: t('common_module.dialogue_module.empty_message_content')
"
color
=
"#999"
/>
<
/template
>
<
/div
>
<
/div
>
<
/n-collapse-transition
>
<
/template
>
<
div
class
=
"min-w-[80px] max-w-full flex-wrap rounded-xl border border-[#e8e9eb] px-4 py-[11px]"
:
class
=
"role === 'user' ? 'bg-[#4b87ff] text-white' : 'bg-white text-[#333]'"
...
...
src/views/personal-space/personal-app-setting/components/agent-config/agent-preview/components/message-list.vue
View file @
852687d7
<
script
setup
lang=
"ts"
>
import
{
computed
}
from
'vue'
import
{
computed
,
nextTick
,
watch
}
from
'vue'
import
MessageItem
from
'./message-item.vue'
import
ContinueQuestion
from
'./continue-question.vue'
import
{
useScroll
}
from
'@/composables/useScroll'
import
{
useBackBottom
}
from
'@/composables/useBackBottom'
interface
Props
{
messageList
:
Map
<
string
,
ConversationMessageItem
>
...
...
@@ -21,6 +22,8 @@ defineEmits<{
const
{
scrollRef
,
scrollToBottom
}
=
useScroll
()
const
{
visible
,
clickBackBottom
,
throttleScrollMessageContainer
}
=
useBackBottom
(
scrollToBottom
)
const
isShowContinueQuestion
=
computed
(()
=>
{
return
(
props
.
continuousQuestionStatus
===
'default'
&&
...
...
@@ -30,13 +33,26 @@ const isShowContinueQuestion = computed(() => {
)
})
watch
(
()
=>
props
.
messageList
.
size
,
()
=>
{
clickBackBottom
()
},
)
defineExpose
({
scrollToBottom
,
scrollToBottom
:
handleScrollToBottom
,
})
function
handleScrollToBottom
()
{
nextTick
(()
=>
{
!
visible
.
value
&&
scrollToBottom
()
})
}
</
script
>
<
template
>
<main
ref=
"scrollRef"
class=
"h-full overflow-y-auto overflow-x-hidden px-5"
>
<main
ref=
"scrollRef"
class=
"h-full overflow-y-auto overflow-x-hidden px-5"
@
scroll=
"throttleScrollMessageContainer"
>
<div>
<MessageItem
v-for=
"[key, messageItem] in messageList"
...
...
@@ -51,5 +67,13 @@ defineExpose({
<div
v-show=
"isShowContinueQuestion"
>
<ContinueQuestion
:continuous-question-list=
"continuousQuestionList"
/>
</div>
<div
v-show=
"visible"
class=
"flex-center hover:text-theme-color absolute bottom-5 right-5 h-6 w-6 cursor-pointer rounded-full bg-white shadow-[0_0_0_1px_#ededed]"
@
click
.
stop=
"clickBackBottom"
>
<i
class=
"iconfont icon-decrease text-sm"
/>
</div>
</main>
</
template
>
src/views/personal-space/personal-app-setting/components/agent-config/agent-setting/agent-setting.vue
View file @
852687d7
...
...
@@ -301,18 +301,12 @@ function handleAIGenerateAgentSystem() {
input
:
personalAppConfigStore
.
baseInfo
.
agentTitle
||
personalAppConfigStore
.
baseInfo
.
agentSystem
,
},
controller
:
generateAgentSystemController
,
onMessage
:
(
data
:
any
)
=>
{
if
(
data
===
'[DONE]'
)
{
blockAnswerResponse
()
resolve
(
data
)
return
}
if
(
data
)
{
onResponse
:
(
data
)
=>
{
if
(
data
&&
data
.
message
)
{
useThrottleFn
(
()
=>
{
nextTick
(()
=>
{
baseInfo
.
value
.
agentSystem
+=
data
baseInfo
.
value
.
agentSystem
+=
data
.
message
agentSystemInputRef
.
value
!
.
textareaElRef
!
.
scrollTop
=
agentSystemInputRef
.
value
?.
textareaElRef
?.
scrollHeight
||
0
})
...
...
@@ -331,6 +325,8 @@ function handleAIGenerateAgentSystem() {
blockAnswerResponse
()
},
onFinally
:
()
=>
{
blockAnswerResponse
()
resolve
(
''
)
generateAgentSystemController
=
null
},
})
...
...
src/views/personal-space/personal-app-setting/components/agent-config/agent-setting/components/optimize-system-modal.vue
View file @
852687d7
...
...
@@ -65,14 +65,9 @@ function handleGenerateAgentSystem() {
input
:
personalAppConfigStore
.
baseInfo
.
agentSystem
,
},
controller
,
onMessage
:
(
data
:
any
)
=>
{
if
(
data
===
'[DONE]'
)
{
blockMessageResponse
()
return
}
if
(
data
)
{
agentSystem
.
value
+=
data
onResponse
:
(
data
)
=>
{
if
(
data
&&
data
.
message
)
{
agentSystem
.
value
+=
data
.
message
useThrottleFn
(
()
=>
{
...
...
@@ -94,6 +89,7 @@ function handleGenerateAgentSystem() {
},
onFinally
:
()
=>
{
controller
=
null
blockMessageResponse
()
},
})
}
...
...
src/views/share/components/footer-input.vue
View file @
852687d7
...
...
@@ -142,6 +142,7 @@ function messageItemFactory(): ConversationMessageItem {
voiceFragmentUrlList
:
[],
pluginName
:
''
,
imageUrl
:
''
,
reasoningContent
:
''
,
}
}
...
...
@@ -195,6 +196,7 @@ function handleMessageSend() {
emit
(
'updatePageScroll'
)
let
replyTextContent
=
''
let
reasoningContent
=
''
isAnswerResponseLoading
.
value
=
true
isAnswerResponseWait
.
value
=
true
currentReplyContentSentenceExtractIndex
.
value
=
0
...
...
@@ -217,31 +219,46 @@ function handleMessageSend() {
imageUrl
:
uploadImageList
.
value
?.[
0
]?.
url
||
''
,
},
controller
,
onMessage
:
(
data
:
any
)
=>
{
if
(
data
===
'[DONE]'
)
{
emit
(
'updateSpecifyMessageItem'
,
latestAssistantMessageKey
,
{
isEmptyContent
:
!
replyTextContent
,
isTextContentLoading
:
false
,
isAnswerResponseLoading
:
false
,
})
onResponse
:
(
data
)
=>
{
// 推理内容
if
(
data
.
reasoningContent
)
{
reasoningContent
+=
data
.
reasoningContent
isAnswerResponseLoading
.
value
=
false
isCreateContinueQuestions
.
value
&&
emit
(
'createContinueQuestions'
,
replyTextContent
)
emit
(
'updateSpecifyMessageItem'
,
latestAssistantMessageKey
,
{
reasoningContent
})
emit
(
'updatePageScroll'
)
blockMessageResponse
()
assistantFullAnswerContent
.
value
=
(
assistantFullAnswerContent
.
value
+
data
.
reasoningContent
).
replace
(
/
\^\[[\d\\
[
\]
-
]
+
?\]\^
/g
,
''
,
)
if
(
!
sentenceExtractCheckEnabled
.
value
&&
props
.
isEnableVoice
)
{
sentenceExtract
(
latestAssistantMessageKey
)
sentenceExtractCheckEnabled
.
value
=
true
messageAudioLoading
.
value
=
true
}
return
}
if
(
data
&&
data
.
name
)
{
emit
(
'updateSpecifyMessageItem'
,
latestAssistantMessageKey
,
{
pluginName
:
data
.
name
})
// 插件
if
(
data
.
function
&&
data
.
function
.
name
)
{
emit
(
'updateSpecifyMessageItem'
,
latestAssistantMessageKey
,
{
pluginName
:
data
.
function
.
name
})
emit
(
'updatePageScroll'
)
return
}
if
(
data
)
{
replyTextContent
+=
data
// 回复内容
if
(
data
.
message
)
{
replyTextContent
+=
data
.
message
assistantFullAnswerContent
.
value
=
(
assistantFullAnswerContent
.
value
+
data
).
replace
(
emit
(
'updateSpecifyMessageItem'
,
latestAssistantMessageKey
,
{
textContent
:
replyTextContent
,
isTextContentLoading
:
false
,
})
emit
(
'updatePageScroll'
)
assistantFullAnswerContent
.
value
=
(
assistantFullAnswerContent
.
value
+
data
.
message
).
replace
(
/
\^\[[\d\\
[
\]
-
]
+
?\]\^
/g
,
''
,
)
...
...
@@ -251,12 +268,6 @@ function handleMessageSend() {
sentenceExtractCheckEnabled
.
value
=
true
messageAudioLoading
.
value
=
true
}
emit
(
'updateSpecifyMessageItem'
,
latestAssistantMessageKey
,
{
textContent
:
replyTextContent
,
isTextContentLoading
:
false
,
})
emit
(
'updatePageScroll'
)
}
},
onRequestError
:
()
=>
{
...
...
@@ -266,6 +277,16 @@ function handleMessageSend() {
errorMessageResponse
()
},
onFinally
:
()
=>
{
emit
(
'updateSpecifyMessageItem'
,
latestAssistantMessageKey
,
{
isEmptyContent
:
!
replyTextContent
,
isTextContentLoading
:
false
,
isAnswerResponseLoading
:
false
,
})
isAnswerResponseLoading
.
value
=
false
isCreateContinueQuestions
.
value
&&
emit
(
'createContinueQuestions'
,
replyTextContent
)
emit
(
'updatePageScroll'
)
blockMessageResponse
()
controller
=
null
userStore
.
isLogin
&&
userStore
.
fetchUpdateEquityInfo
()
},
...
...
src/views/share/components/message-item.vue
View file @
852687d7
<
script
setup
lang=
"ts"
>
import
{
computed
}
from
'vue'
import
{
computed
,
ref
}
from
'vue'
import
{
useI18n
}
from
'vue-i18n'
import
{
CheckOne
}
from
'@icon-park/vue-next'
import
{
CheckOne
,
Down
}
from
'@icon-park/vue-next'
import
CustomLoading
from
'./custom-loading.vue'
import
MusicWavesLoading
from
'./music-waves-loading.vue'
import
MarkdownRender
from
'@/components/markdown-render/markdown-render.vue'
...
...
@@ -28,6 +28,8 @@ const userStore = useUserStore()
const
{
isMobile
}
=
useLayoutConfig
()
const
isShowReasoningContent
=
ref
(
true
)
const
useAvatar
=
computed
(()
=>
{
return
userStore
.
userInfo
.
avatarUrl
||
'https://gsst-poe-sit.gz.bcebos.com/data/20240910/1725952917468.png'
})
...
...
@@ -63,6 +65,10 @@ const isShowMobileLoading = computed(() => {
)
})
const
isDeepSeekR1
=
computed
(()
=>
{
return
props
.
agentApplicationConfig
.
commModelConfig
.
largeModel
===
'DeepSeek'
})
function
handleAudioControl
()
{
if
(
!
isPlayableAudio
.
value
)
{
return
...
...
@@ -74,6 +80,10 @@ function handleAudioControl() {
emit
(
'audioPlay'
)
}
}
function
handleShowReasoningContentSwitch
()
{
isShowReasoningContent
.
value
=
!
isShowReasoningContent
.
value
}
</
script
>
<
template
>
...
...
@@ -98,6 +108,48 @@ function handleAudioControl() {
class=
"flex w-full flex-col overflow-x-auto"
:class=
"isMobile && role === 'user' ? 'items-end' : 'items-start'"
>
<template
v-if=
"role === 'assistant' && isDeepSeekR1"
>
<div
class=
"my-[7px] select-none text-[14px]"
>
<div
class=
"inline-flex cursor-pointer"
@
click=
"handleShowReasoningContentSwitch"
>
<span
v-if=
"messageItem.isTextContentLoading"
class=
"mr-[6px]"
>
{{
t
(
'common_module.deep_thinking'
,
{
modelName
:
agentApplicationConfig
.
commModelConfig
.
largeModel
}
)
}}
<
/span
>
<
span
v
-
else
class
=
"mr-[6px]"
>
{{
t
(
'common_module.have_thought_deeply'
)
}}
<
/span
>
<
Down
theme
=
"outline"
size
=
"21"
fill
=
"#333"
:
stroke
-
width
=
"3"
class
=
"transition-[rotate] duration-100 ease-linear"
:
class
=
"{ '-rotate-180': isShowReasoningContent
}
"
/>
<
/div
>
<
/div
>
<
n
-
collapse
-
transition
:
show
=
"isShowReasoningContent"
>
<
div
class
=
"my-[14px] border-l-[1px] border-solid border-l-[#ccc] p-[13px]"
>
<
div
>
<
img
v
-
if
=
"!messageItem.reasoningContent && !messageItem.textContent"
src
=
"@/assets/images/home/bubble-loading.gif"
alt
=
"bubble-loading"
/>
<
template
v
-
else
>
<
MarkdownRender
:
raw
-
text
-
content
=
"
messageItem.reasoningContent
? messageItem.reasoningContent
: t('common_module.dialogue_module.empty_message_content')
"
color
=
"#999"
/>
<
/template
>
<
/div
>
<
/div
>
<
/n-collapse-transition
>
<
/template
>
<
div
class
=
"min-w-[80px] flex-wrap rounded-xl border border-[#e8e9eb] px-4 py-[11px]"
:
class
=
"[
...
...
src/views/share/components/message-list.vue
View file @
852687d7
...
...
@@ -3,7 +3,8 @@ import MessageItem from './message-item.vue'
import
ContinueQuestion
from
'./continue-question.vue'
import
{
useScroll
}
from
'@/composables/useScroll'
import
{
PersonalAppConfigState
}
from
'@/store/types/personal-app-config'
import
{
computed
}
from
'vue'
import
{
computed
,
nextTick
,
watch
}
from
'vue'
import
{
useBackBottom
}
from
'@/composables/useBackBottom'
interface
Props
{
messageList
:
Map
<
string
,
ConversationMessageItem
>
...
...
@@ -23,6 +24,8 @@ defineEmits<{
const
{
scrollRef
,
scrollToBottom
}
=
useScroll
()
const
{
visible
,
clickBackBottom
,
throttleScrollMessageContainer
}
=
useBackBottom
(
scrollToBottom
)
const
isShowContinueQuestion
=
computed
(()
=>
{
return
(
props
.
continuousQuestionStatus
===
'default'
&&
...
...
@@ -32,13 +35,26 @@ const isShowContinueQuestion = computed(() => {
)
})
watch
(
()
=>
props
.
messageList
.
size
,
()
=>
{
clickBackBottom
()
},
)
defineExpose
({
scrollToBottom
,
scrollToBottom
:
handleScrollToBottom
,
})
function
handleScrollToBottom
()
{
nextTick
(()
=>
{
!
visible
.
value
&&
scrollToBottom
()
})
}
</
script
>
<
template
>
<main
ref=
"scrollRef"
class=
"h-full overflow-y-auto overflow-x-hidden px-5"
>
<main
ref=
"scrollRef"
class=
"h-full overflow-y-auto overflow-x-hidden px-5"
@
scroll=
"throttleScrollMessageContainer"
>
<div>
<MessageItem
v-for=
"[key, messageItem] in messageList"
...
...
@@ -54,5 +70,13 @@ defineExpose({
<div
v-show=
"isShowContinueQuestion"
>
<ContinueQuestion
:continuous-question-list=
"continuousQuestionList"
/>
</div>
<div
v-show=
"visible"
class=
"flex-center hover:text-theme-color absolute bottom-5 right-5 h-6 w-6 cursor-pointer rounded-full bg-white shadow-[0_0_0_1px_#ededed]"
@
click
.
stop=
"clickBackBottom"
>
<i
class=
"iconfont icon-decrease text-sm"
/>
</div>
</main>
</
template
>
src/views/share/share-application-mobile.vue
View file @
852687d7
...
...
@@ -322,7 +322,7 @@ function handleAudioPause(isClearMessageList = false) {
</div>
<div
v-if=
"messageList.size > 0"
class=
"flex w-full flex-1 flex-col overflow-hidden pt-5"
>
<div
class=
"flex-1 overflow-auto"
>
<div
class=
"
relative
flex-1 overflow-auto"
>
<MessageList
ref=
"messageListRef"
:agent-application-config=
"agentApplicationConfig"
...
...
src/views/share/share-application-web.vue
View file @
852687d7
...
...
@@ -345,7 +345,7 @@ function handleAudioPause(isClearMessageList = false) {
</div>
<div
v-if=
"messageList.size > 0"
class=
"flex w-full flex-1 flex-col overflow-hidden"
>
<div
class=
"mt-20 flex-1 overflow-auto"
>
<div
class=
"
relative
mt-20 flex-1 overflow-auto"
>
<MessageList
ref=
"messageListRef"
:agent-application-config=
"agentApplicationConfig"
...
...
types/conversation.d.ts
View file @
852687d7
...
...
@@ -11,4 +11,5 @@ declare interface ConversationMessageItem {
isVoiceEnabled
?:
boolean
pluginName
?:
string
imageUrl
?:
string
reasoningContent
:
string
}
types/locales.d.ts
View file @
852687d7
...
...
@@ -139,6 +139,8 @@ declare namespace I18n {
plugin_in_progress
:
string
plugin_executed_successfully
:
string
upload_image
:
string
deep_thinking
:
string
have_thought_deeply
:
string
dialogue_module
:
{
continue_question_message
:
string
...
...
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