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
edafe38c
Commit
edafe38c
authored
May 10, 2025
by
nick zheng
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: agent应用智能表单(出差表单)
parent
f36f9815
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
30 changed files
with
1681 additions
and
118 deletions
+1681
-118
eslint.config.js
eslint.config.js
+1
-0
execute-plugin-render.vue
...omponents/execute-plugin-render/execute-plugin-render.vue
+49
-46
useEventSource.ts
src/composables/useEventSource.ts
+6
-1
footer-operation.vue
...iews/multi-model-dialogue/components/footer-operation.vue
+33
-1
message-item.vue
src/views/multi-model-dialogue/components/message-item.vue
+45
-15
message-list.vue
src/views/multi-model-dialogue/components/message-list.vue
+9
-1
model-dialogue-item.vue
...s/multi-model-dialogue/components/model-dialogue-item.vue
+8
-1
business-trip-form.vue
.../components/smart-forms/components/business-trip-form.vue
+360
-0
business-trip-reimbursement-form.vue
...art-forms/components/business-trip-reimbursement-form.vue
+188
-0
index.vue
...ews/multi-model-dialogue/components/smart-forms/index.vue
+29
-0
types.d.ts
...ti-model-dialogue/components/smart-forms/types/types.d.ts
+28
-0
smart-forms.ts
...odel-dialogue/components/smart-forms/utils/smart-forms.ts
+41
-0
multi-model-dialogue.vue
src/views/multi-model-dialogue/multi-model-dialogue.vue
+16
-4
types.d.ts
src/views/multi-model-dialogue/types.d.ts
+8
-1
fetch-event-stream-source.ts
...s/multi-model-dialogue/utils/fetch-event-stream-source.ts
+1
-1
agent-preview.vue
...g/components/agent-config/agent-preview/agent-preview.vue
+15
-3
footer-input.vue
...ts/agent-config/agent-preview/components/footer-input.vue
+32
-1
message-item.vue
...ts/agent-config/agent-preview/components/message-item.vue
+47
-15
message-list.vue
...ts/agent-config/agent-preview/components/message-list.vue
+10
-3
business-trip-form.vue
.../components/smart-forms/components/business-trip-form.vue
+357
-0
business-trip-reimbursement-form.vue
...art-forms/components/business-trip-reimbursement-form.vue
+187
-0
index.vue
...ent-config/agent-preview/components/smart-forms/index.vue
+28
-0
types.d.ts
...fig/agent-preview/components/smart-forms/types/types.d.ts
+28
-0
smart-forms.ts
...agent-preview/components/smart-forms/utils/smart-forms.ts
+41
-0
types.d.ts
...e/personal-app-setting/components/agent-config/types.d.ts
+2
-0
footer-input.vue
src/views/share/components/footer-input.vue
+32
-1
message-item.vue
src/views/share/components/message-item.vue
+47
-17
message-list.vue
src/views/share/components/message-list.vue
+10
-3
share-application-web.vue
src/views/share/share-application-web.vue
+15
-3
conversation.d.ts
types/conversation.d.ts
+8
-1
No files found.
eslint.config.js
View file @
edafe38c
...
@@ -24,6 +24,7 @@ export default [
...
@@ -24,6 +24,7 @@ export default [
AnyObject
:
'readonly'
,
AnyObject
:
'readonly'
,
KnowledgeContentResultItem
:
'readonly'
,
KnowledgeContentResultItem
:
'readonly'
,
DBChainResultItem
:
'readonly'
,
DBChainResultItem
:
'readonly'
,
PluginDisplayFormatType
:
'readonly'
,
ConversationMessageItem
:
'readonly'
,
ConversationMessageItem
:
'readonly'
,
ConversationMessageItemInfo
:
'readonly'
,
ConversationMessageItemInfo
:
'readonly'
,
MittEvents
:
'readonly'
,
MittEvents
:
'readonly'
,
...
...
src/components/execute-plugin-render/execute-plugin-render.vue
View file @
edafe38c
...
@@ -7,7 +7,7 @@ import MarkdownRender from '@/components/markdown-render/markdown-render.vue'
...
@@ -7,7 +7,7 @@ import MarkdownRender from '@/components/markdown-render/markdown-render.vue'
import
{
useLayoutConfig
}
from
'@/composables/useLayoutConfig'
import
{
useLayoutConfig
}
from
'@/composables/useLayoutConfig'
interface
Props
{
interface
Props
{
displayFormat
:
'json'
|
'markdown'
|
'none'
displayFormat
:
PluginDisplayFormatType
name
:
string
name
:
string
arguments
:
string
arguments
:
string
content
:
string
content
:
string
...
@@ -59,11 +59,12 @@ const parsedMarkdownPluginContent = computed(() => {
...
@@ -59,11 +59,12 @@ const parsedMarkdownPluginContent = computed(() => {
<
template
>
<
template
>
<div
<div
class=
"flex w-full flex-col bg-[#f3f5f9]"
class=
"flex w-full flex-col bg-[#f3f5f9]"
:class=
"
:class=
"isMobile ? 'rounded-[2.66667vw] py-[2.66667vw] text-[3.2vw]' : 'rounded-[10px] py-[10px]'"
isMobile ? 'rounded-[2.66667vw] px-[3.2vw] py-[2.66667vw] text-[3.2vw]' : 'rounded-[10px] px-[12px] py-[10px]'
>
"
<div
class=
"flex flex-1 items-center justify-between gap-[10px] overflow-hidden"
:class=
"isMobile ? 'px-[3.2vw]' : 'px-[12px]'"
>
>
<div
class=
"flex flex-1 items-center justify-between gap-[10px] overflow-hidden"
>
<div
class=
"flex flex-1 items-center gap-[6px] overflow-hidden"
>
<div
class=
"flex flex-1 items-center gap-[6px] overflow-hidden"
>
<div
<div
v-show=
"pluginLoading"
v-show=
"pluginLoading"
...
@@ -91,13 +92,14 @@ const parsedMarkdownPluginContent = computed(() => {
...
@@ -91,13 +92,14 @@ const parsedMarkdownPluginContent = computed(() => {
/>
/>
<
/div
>
<
/div
>
<
n
-
scrollbar
style
=
"max-height: 500px"
:
class
=
"{ 'mt-[10px]': !isFolding
}
"
>
<
div
<
div
class
=
"flex transform flex-col overflow-x-auto duration-200 ease-in-out"
class
=
"flex transform flex-col overflow-x-auto duration-200 ease-in-out"
:
class
=
"isFolding ? 'h-0 overflow-hidden' : 'h-fit'
"
:
class
=
"[isFolding ? 'h-0 overflow-hidden' : 'h-fit', isMobile ? 'px-[3.2vw]' : 'px-[12px]']
"
>
>
<!--
json
格式
-->
<!--
json
格式
-->
<
div
v
-
if
=
"displayFormat === 'json'"
>
<
div
v
-
if
=
"displayFormat === 'json'"
>
<
div
class
=
"mt-[10px]"
>
<
div
>
<
span
<
span
class
=
"rounded-theme inline-block bg-[#E8EAFF] text-[#0072FF]"
class
=
"rounded-theme inline-block bg-[#E8EAFF] text-[#0072FF]"
:
class
=
"
:
class
=
"
...
@@ -128,16 +130,17 @@ const parsedMarkdownPluginContent = computed(() => {
...
@@ -128,16 +130,17 @@ const parsedMarkdownPluginContent = computed(() => {
<!--
markdown
格式
-->
<!--
markdown
格式
-->
<
div
v
-
else
-
if
=
"displayFormat === 'markdown'"
>
<
div
v
-
else
-
if
=
"displayFormat === 'markdown'"
>
<
div
class
=
"mt-[10px]"
>
<
div
>
<
MarkdownRender
:
raw
-
text
-
content
=
"parsedMarkdownPluginContent"
:
font
-
size
=
"isMobile ? '3.2vw' : '14px'"
/>
<
MarkdownRender
:
raw
-
text
-
content
=
"parsedMarkdownPluginContent"
:
font
-
size
=
"isMobile ? '3.2vw' : '14px'"
/>
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<!--
其他
格式
-->
<!--
none
格式
-->
<
div
v
-
else
>
<
div
v
-
else
-
if
=
"displayFormat === 'none'"
>
<
span
class
=
"mt-[10px]
break-all"
>
{{
content
}}
<
/span
>
<
span
class
=
"text-font-color
break-all"
>
{{
content
}}
<
/span
>
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
/n-scrollbar
>
<
/div
>
<
/div
>
<
/template
>
<
/template
>
...
...
src/composables/useEventSource.ts
View file @
edafe38c
...
@@ -8,7 +8,12 @@ import { languageKeyTransform } from '@/utils/language-key-transform'
...
@@ -8,7 +8,12 @@ import { languageKeyTransform } from '@/utils/language-key-transform'
interface
ResponseData
{
interface
ResponseData
{
message
:
string
message
:
string
reasoningContent
:
string
reasoningContent
:
string
function
:
{
displayFormat
:
'json'
|
'markdown'
|
'none'
;
name
:
string
;
result
:
string
;
arguments
:
string
}
function
:
{
displayFormat
:
PluginDisplayFormatType
name
:
string
result
:
string
arguments
:
string
}
knowledgeContentResult
:
KnowledgeContentResultItem
[]
knowledgeContentResult
:
KnowledgeContentResultItem
[]
dbChainResult
:
DBChainResultItem
[]
dbChainResult
:
DBChainResultItem
[]
}
}
...
...
src/views/multi-model-dialogue/components/footer-operation.vue
View file @
edafe38c
...
@@ -5,12 +5,14 @@ import { nanoid } from 'nanoid'
...
@@ -5,12 +5,14 @@ import { nanoid } from 'nanoid'
import
{
throttle
}
from
'lodash-es'
import
{
throttle
}
from
'lodash-es'
import
{
CloseSmall
}
from
'@icon-park/vue-next'
import
{
CloseSmall
}
from
'@icon-park/vue-next'
import
CMessage
from
'./c-message'
import
CMessage
from
'./c-message'
import
{
MessageItemInterface
,
MultiModelDialogueItem
,
QuestionMessageItem
}
from
'../types'
import
{
MessageItemInterface
,
MultiModelDialogueItem
,
QuestionMessageItem
,
SmartFormTypes
}
from
'../types'
import
{
fetchEventStreamSource
}
from
'../utils/fetch-event-stream-source'
import
{
fetchEventStreamSource
}
from
'../utils/fetch-event-stream-source'
import
{
UploadStatus
}
from
'@/enums/upload-status'
import
{
UploadStatus
}
from
'@/enums/upload-status'
import
{
ChannelType
}
from
'@/enums/channel'
import
{
ChannelType
}
from
'@/enums/channel'
import
{
useDialogueFile
}
from
'@/composables/useDialogueFile'
import
{
useDialogueFile
}
from
'@/composables/useDialogueFile'
import
{
useUserStore
}
from
'@/store/modules/user'
import
{
useUserStore
}
from
'@/store/modules/user'
import
{
smartFormTypeConverter
}
from
'./smart-forms/utils/smart-forms'
import
{
SmartFormDisplayFormat
}
from
'./smart-forms/types/types'
const
{
t
}
=
useI18n
()
const
{
t
}
=
useI18n
()
...
@@ -29,6 +31,7 @@ const emit = defineEmits<{
...
@@ -29,6 +31,7 @@ const emit = defineEmits<{
deleteMessageItem
:
[
messageId
:
string
,
index
:
number
]
deleteMessageItem
:
[
messageId
:
string
,
index
:
number
]
messageListScrollToBottom
:
[
autoScrollBottom
?:
boolean
]
messageListScrollToBottom
:
[
autoScrollBottom
?:
boolean
]
clearAllMessage
:
[]
clearAllMessage
:
[]
smartFormsStatusFreezeCheck
:
[
value
:
SmartFormTypes
,
index
:
number
]
}
>
()
}
>
()
const
userStore
=
useUserStore
()
const
userStore
=
useUserStore
()
...
@@ -205,6 +208,35 @@ function handleQuestionSubmit() {
...
@@ -205,6 +208,35 @@ function handleQuestionSubmit() {
// 插件
// 插件
if
(
data
.
function
&&
data
.
function
.
name
)
{
if
(
data
.
function
&&
data
.
function
.
name
)
{
// 表单插件,展示表单内容
if
([
'travelForm'
].
includes
(
data
.
function
.
displayFormat
))
{
emit
(
'smartFormsStatusFreezeCheck'
,
smartFormTypeConverter
(
data
.
function
.
displayFormat
as
SmartFormDisplayFormat
),
modelIndex
,
)
emit
(
'updateMessageItem'
,
answerMessageId
,
{
pluginResult
:
{
displayFormat
:
data
.
function
.
displayFormat
,
pluginName
:
data
.
function
.
name
,
arguments
:
data
.
function
.
arguments
,
pluginContent
:
data
.
function
.
result
,
},
smartFormInfo
:
{
type
:
smartFormTypeConverter
(
data
.
function
.
displayFormat
as
SmartFormDisplayFormat
),
isDisabled
:
false
,
params
:
data
.
function
.
result
,
},
},
modelIndex
,
)
emit
(
'messageListScrollToBottom'
)
return
}
emit
(
emit
(
'updateMessageItem'
,
'updateMessageItem'
,
answerMessageId
,
answerMessageId
,
...
...
src/views/multi-model-dialogue/components/message-item.vue
View file @
edafe38c
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
computed
,
readonly
,
ref
}
from
'vue'
import
{
computed
,
provide
,
readonly
,
ref
}
from
'vue'
import
{
useI18n
}
from
'vue-i18n'
import
{
useI18n
}
from
'vue-i18n'
import
{
Down
}
from
'@icon-park/vue-next'
import
{
Down
}
from
'@icon-park/vue-next'
import
type
{
MessageItemInterface
}
from
'../types'
import
type
{
MessageItemInterface
}
from
'../types'
...
@@ -7,9 +7,11 @@ import MarkdownRender from '@/components/markdown-render/markdown-render.vue'
...
@@ -7,9 +7,11 @@ import MarkdownRender from '@/components/markdown-render/markdown-render.vue'
import
ExecuteCodeRender
from
'@/components/execute-code-render/execute-code-render.vue'
import
ExecuteCodeRender
from
'@/components/execute-code-render/execute-code-render.vue'
import
ExecutePluginRender
from
'@/components/execute-plugin-render/execute-plugin-render.vue'
import
ExecutePluginRender
from
'@/components/execute-plugin-render/execute-plugin-render.vue'
import
MessageBubbleLoading
from
'./message-bubble-loading.vue'
import
MessageBubbleLoading
from
'./message-bubble-loading.vue'
import
SmartForms
from
'./smart-forms/index.vue'
interface
Props
{
interface
Props
{
messageItem
:
MessageItemInterface
messageItem
:
MessageItemInterface
messageItemId
:
string
}
}
const
props
=
defineProps
<
Props
>
()
const
props
=
defineProps
<
Props
>
()
...
@@ -20,14 +22,33 @@ const emit = defineEmits<{
...
@@ -20,14 +22,33 @@ const emit = defineEmits<{
const
{
t
}
=
useI18n
()
const
{
t
}
=
useI18n
()
provide
(
'messageItemId'
,
props
.
messageItemId
)
const
isShowReasoningContent
=
ref
(
true
)
const
isShowReasoningContent
=
ref
(
true
)
const
agentAvatarUrl
=
readonly
({
url
:
'https://gsst-poe-sit.gz.bcebos.com/icon/agent-avatar.png'
})
const
agentAvatarUrl
=
readonly
({
url
:
'https://gsst-poe-sit.gz.bcebos.com/icon/agent-avatar.png'
})
const
isAssistant
=
computed
(()
=>
{
const
displaySmartFormsList
=
readonly
([
'travelForm'
])
const
isAgentMessage
=
computed
(()
=>
{
return
props
.
messageItem
.
role
===
'assistant'
return
props
.
messageItem
.
role
===
'assistant'
})
})
const
currentBubbleTextColor
=
computed
(()
=>
{
return
isAgentMessage
.
value
?
'#192338'
:
'#fff'
})
const
messageAuthor
=
computed
(()
=>
{
return
props
.
messageItem
.
nickName
})
const
isShowSmartForms
=
computed
(()
=>
{
if
(
props
.
messageItem
?.
pluginResult
?.
displayFormat
)
{
return
displaySmartFormsList
.
includes
(
props
.
messageItem
?.
pluginResult
?.
displayFormat
)
}
return
false
})
const
assistantAvatarUrl
=
computed
(()
=>
{
const
assistantAvatarUrl
=
computed
(()
=>
{
return
props
.
messageItem
.
avatar
||
agentAvatarUrl
.
url
return
props
.
messageItem
.
avatar
||
agentAvatarUrl
.
url
})
})
...
@@ -42,12 +63,13 @@ function handleShowReasoningContentSwitch() {
...
@@ -42,12 +63,13 @@ function handleShowReasoningContentSwitch() {
<div
class=
"flex"
>
<div
class=
"flex"
>
<img
<img
class=
"h-[36px] w-[36px] flex-shrink-0 rounded-full object-cover"
class=
"h-[36px] w-[36px] flex-shrink-0 rounded-full object-cover"
:src=
"isA
ssistant
? assistantAvatarUrl : props.messageItem.avatar"
:src=
"isA
gentMessage
? assistantAvatarUrl : props.messageItem.avatar"
alt=
"Avatar"
alt=
"Avatar"
/>
/>
<div
class=
"ml-[11px] flex flex-col items-start overflow-hidden"
>
<div
v-if=
"!isShowSmartForms"
class=
"ml-[11px] flex flex-col items-start overflow-hidden"
>
<template
v-if=
"isAssistant && messageItem.nickName === 'DeepSeek'"
>
<!-- DeepSeek深度思考 -->
<template
v-if=
"isAgentMessage && messageItem.nickName === 'DeepSeek'"
>
<div
class=
"mb-[7px] select-none text-[14px]"
>
<div
class=
"mb-[7px] select-none text-[14px]"
>
<div
class=
"inline-flex cursor-pointer"
@
click=
"handleShowReasoningContentSwitch"
>
<div
class=
"inline-flex cursor-pointer"
@
click=
"handleShowReasoningContentSwitch"
>
<span
v-if=
"messageItem.isTextContentLoading"
class=
"mr-[6px]"
>
<span
v-if=
"messageItem.isTextContentLoading"
class=
"mr-[6px]"
>
...
@@ -89,19 +111,19 @@ function handleShowReasoningContentSwitch() {
...
@@ -89,19 +111,19 @@ function handleShowReasoningContentSwitch() {
<
div
<
div
class
=
"min-h-[21px] w-full flex-wrap rounded-[10px] border border-[#9EA3FF] px-[15px] py-[12px] text-justify"
class
=
"min-h-[21px] w-full flex-wrap rounded-[10px] border border-[#9EA3FF] px-[15px] py-[12px] text-justify"
:
class
=
"{
:
class
=
"{
'bg-[#777EF9]':
isAssistant
,
'bg-[#777EF9]':
!isAgentMessage
,
'text-[#fff]':
isAssistant
,
'text-[#fff]':
!isAgentMessage
,
'!min-w-[80px]': messageItem.isTextContentLoading,
'!min-w-[80px]': messageItem.isTextContentLoading,
}
"
}
"
>
>
<
img
<
img
v
-
show
=
"!isA
ssistant
&& messageItem.imageUrl"
v
-
show
=
"!isA
gentMessage
&& messageItem.imageUrl"
:
src
=
"messageItem.imageUrl"
:
src
=
"messageItem.imageUrl"
class
=
"max-h-[120px]! mb-[12px] rounded-[10px] object-contain"
class
=
"max-h-[120px]! mb-[12px] rounded-[10px] object-contain"
/>
/>
<!--
插件返回结果
-->
<!--
插件返回结果
-->
<
div
v
-
show
=
"isA
ssistant
&& messageItem?.pluginResult?.pluginName"
class
=
"mb-[11px] w-full"
>
<
div
v
-
show
=
"isA
gentMessage
&& messageItem?.pluginResult?.pluginName"
class
=
"mb-[11px] w-full"
>
<
ExecutePluginRender
<
ExecutePluginRender
:
display
-
format
=
"messageItem.pluginResult?.displayFormat || 'none'"
:
display
-
format
=
"messageItem.pluginResult?.displayFormat || 'none'"
:
name
=
"messageItem.pluginResult?.pluginName!"
:
name
=
"messageItem.pluginResult?.pluginName!"
...
@@ -111,8 +133,8 @@ function handleShowReasoningContentSwitch() {
...
@@ -111,8 +133,8 @@ function handleShowReasoningContentSwitch() {
/>
/>
<
/div
>
<
/div
>
<
div
v
-
if
=
"messageItem.isTextContentLoading"
class
=
"flex px-4 py-
1.5
"
>
<
div
v
-
if
=
"messageItem.isTextContentLoading"
class
=
"flex px-4 py-
[7.5px]
"
>
<
MessageBubbleLoading
:
active
-
color
=
"
isAssistant ? '#fff' : '#192338'
"
/>
<
MessageBubbleLoading
:
active
-
color
=
"
currentBubbleTextColor
"
/>
<
/div
>
<
/div
>
<
div
v
-
else
>
<
div
v
-
else
>
...
@@ -128,21 +150,21 @@ function handleShowReasoningContentSwitch() {
...
@@ -128,21 +150,21 @@ function handleShowReasoningContentSwitch() {
:
raw
-
text
-
content
=
"
:
raw
-
text
-
content
=
"
messageItem.content ? messageItem.content : t('common_module.dialogue_module.empty_message_content')
messageItem.content ? messageItem.content : t('common_module.dialogue_module.empty_message_content')
"
"
:
color
=
"
isAssistant ? '#fff' : '#192338'
"
:
color
=
"
currentBubbleTextColor
"
/>
/>
<
div
<
div
v
-
show
=
"isA
ssistant
&& messageItem.isAnswerResponseLoading"
v
-
show
=
"isA
gentMessage
&& messageItem.isAnswerResponseLoading"
class
=
"mt-2.5 flex h-[21px] w-[30px] items-center justify-center"
class
=
"mt-2.5 flex h-[21px] w-[30px] items-center justify-center"
>
>
<
MessageBubbleLoading
:
active
-
color
=
"
isAssistant ? '#fff' : '#192338'
"
/>
<
MessageBubbleLoading
:
active
-
color
=
"
currentBubbleTextColor
"
/>
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
div
class
=
"flex justify-between py-[2px]"
>
<
div
class
=
"flex justify-between py-[2px]"
>
<
div
<
div
v
-
show
=
"isA
ssistant
&& messageItem.knowledgeContentResult.length"
v
-
show
=
"isA
gentMessage
&& messageItem.knowledgeContentResult.length"
class
=
"flex-center rounded-theme h-8 cursor-pointer gap-[5px] px-[14px] font-['Microsoft_YaHei_UI'] text-[#0B7DFF] hover:opacity-80"
class
=
"flex-center rounded-theme h-8 cursor-pointer gap-[5px] px-[14px] font-['Microsoft_YaHei_UI'] text-[#0B7DFF] hover:opacity-80"
@
click
=
"emit('showKnowledgeResult')"
@
click
=
"emit('showKnowledgeResult')"
>
>
...
@@ -152,6 +174,14 @@ function handleShowReasoningContentSwitch() {
...
@@ -152,6 +174,14 @@ function handleShowReasoningContentSwitch() {
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
SmartForms
v
-
else
:
message
-
item
=
"messageItem"
:
message
-
author
=
"messageAuthor"
:
is
-
agent
-
message
=
"isAgentMessage"
:
current
-
bubble
-
text
-
color
=
"currentBubbleTextColor"
/>
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
/template
>
<
/template
>
...
...
src/views/multi-model-dialogue/components/message-list.vue
View file @
edafe38c
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
useTemplateRef
}
from
'vue'
import
{
provide
,
useTemplateRef
}
from
'vue'
import
{
ScrollbarInst
}
from
'naive-ui'
import
{
ScrollbarInst
}
from
'naive-ui'
import
{
useElementVisibility
}
from
'@vueuse/core'
import
{
useElementVisibility
}
from
'@vueuse/core'
import
MessageItem
from
'./message-item.vue'
import
MessageItem
from
'./message-item.vue'
...
@@ -13,6 +13,7 @@ defineProps<Props>()
...
@@ -13,6 +13,7 @@ defineProps<Props>()
const
emit
=
defineEmits
<
{
const
emit
=
defineEmits
<
{
showKnowledgeResult
:
[
knowledgeContentResult
:
KnowledgeContentResultItem
[]]
showKnowledgeResult
:
[
knowledgeContentResult
:
KnowledgeContentResultItem
[]]
updateSpecifyMessageItem
:
[
messageId
:
string
,
newMessageItem
:
Partial
<
MessageItemInterface
>
]
}
>
()
}
>
()
const
scrollbarRef
=
useTemplateRef
<
ScrollbarInst
|
null
>
(
'scrollbarRef'
)
const
scrollbarRef
=
useTemplateRef
<
ScrollbarInst
|
null
>
(
'scrollbarRef'
)
...
@@ -21,6 +22,12 @@ const backBottomBtnFlagRef = useTemplateRef<HTMLDivElement | null>('backBottomBt
...
@@ -21,6 +22,12 @@ const backBottomBtnFlagRef = useTemplateRef<HTMLDivElement | null>('backBottomBt
const
isNotShowBackBottomBtn
=
useElementVisibility
(
backBottomBtnFlagRef
)
const
isNotShowBackBottomBtn
=
useElementVisibility
(
backBottomBtnFlagRef
)
provide
(
'updateSpecifyMessageItem'
,
{
updateSpecifyMessageItem
:
(
messageId
:
string
,
newMessageItem
:
Partial
<
MessageItemInterface
>
)
=>
{
emit
(
'updateSpecifyMessageItem'
,
messageId
,
newMessageItem
)
},
})
function
scrollToBottom
()
{
function
scrollToBottom
()
{
if
(
scrollbarRef
.
value
)
{
if
(
scrollbarRef
.
value
)
{
scrollbarRef
.
value
.
scrollTo
({
top
:
999999999
,
behavior
:
'smooth'
})
scrollbarRef
.
value
.
scrollTo
({
top
:
999999999
,
behavior
:
'smooth'
})
...
@@ -41,6 +48,7 @@ defineExpose({
...
@@ -41,6 +48,7 @@ defineExpose({
<MessageItem
<MessageItem
v-for=
"[key, messageItem] in messageList"
v-for=
"[key, messageItem] in messageList"
:key=
"key"
:key=
"key"
:message-item-id=
"key"
:message-item=
"messageItem"
:message-item=
"messageItem"
@
show-knowledge-result=
"emit('showKnowledgeResult', messageItem.knowledgeContentResult)"
@
show-knowledge-result=
"emit('showKnowledgeResult', messageItem.knowledgeContentResult)"
/>
/>
...
...
src/views/multi-model-dialogue/components/model-dialogue-item.vue
View file @
edafe38c
...
@@ -5,7 +5,7 @@ import { SelectOption } from 'naive-ui'
...
@@ -5,7 +5,7 @@ import { SelectOption } from 'naive-ui'
import
{
useVModel
}
from
'@vueuse/core'
import
{
useVModel
}
from
'@vueuse/core'
import
{
useElementSize
}
from
'@vueuse/core'
import
{
useElementSize
}
from
'@vueuse/core'
import
{
useSystemLanguageStore
}
from
'@/store/modules/system-language'
import
{
useSystemLanguageStore
}
from
'@/store/modules/system-language'
import
{
MultiModelDialogueItem
}
from
'../types'
import
{
MultiModelDialogueItem
,
MessageItemInterface
}
from
'../types'
import
ModelSetting
from
'./model-setting.vue'
import
ModelSetting
from
'./model-setting.vue'
import
MessageList
from
'./message-list.vue'
import
MessageList
from
'./message-list.vue'
import
HitKnowledgeContent
from
'./hit-knowledge-content.vue'
import
HitKnowledgeContent
from
'./hit-knowledge-content.vue'
...
@@ -15,6 +15,7 @@ interface Props {
...
@@ -15,6 +15,7 @@ interface Props {
modelListOptions
:
SelectOption
[]
modelListOptions
:
SelectOption
[]
totalNum
:
number
totalNum
:
number
isCurrent
:
boolean
isCurrent
:
boolean
modelDialogueId
:
number
}
}
const
{
t
}
=
useI18n
()
const
{
t
}
=
useI18n
()
...
@@ -26,6 +27,7 @@ const emit = defineEmits<{
...
@@ -26,6 +27,7 @@ const emit = defineEmits<{
updateConfig
:
[
modelDialogueItem
:
MultiModelDialogueItem
]
updateConfig
:
[
modelDialogueItem
:
MultiModelDialogueItem
]
replaceConfig
:
[
modelDialogueItem
:
MultiModelDialogueItem
]
replaceConfig
:
[
modelDialogueItem
:
MultiModelDialogueItem
]
resetConversation
:
[]
resetConversation
:
[]
updateMessageItem
:
[
messageId
:
string
,
messageItem
:
Partial
<
MessageItemInterface
>
,
index
:
number
]
}
>
()
}
>
()
const
systemLanguageStore
=
useSystemLanguageStore
()
const
systemLanguageStore
=
useSystemLanguageStore
()
...
@@ -118,6 +120,10 @@ function handleShowKnowledgeResult(knowledgeContentResult: KnowledgeContentResul
...
@@ -118,6 +120,10 @@ function handleShowKnowledgeResult(knowledgeContentResult: KnowledgeContentResul
isShowKnowledgeContentResult
.
value
=
true
isShowKnowledgeContentResult
.
value
=
true
currentKnowledgeContentResult
.
value
=
knowledgeContentResult
currentKnowledgeContentResult
.
value
=
knowledgeContentResult
}
}
function
handleUpdateSpecifyMessageItem
(
messageId
:
string
,
messageItem
:
Partial
<
MessageItemInterface
>
)
{
emit
(
'updateMessageItem'
,
messageId
,
messageItem
,
props
.
modelDialogueId
)
}
</
script
>
</
script
>
<
template
>
<
template
>
...
@@ -205,6 +211,7 @@ function handleShowKnowledgeResult(knowledgeContentResult: KnowledgeContentResul
...
@@ -205,6 +211,7 @@ function handleShowKnowledgeResult(knowledgeContentResult: KnowledgeContentResul
ref=
"messageListRef"
ref=
"messageListRef"
:message-list=
"modelDialogueItem.messageList"
:message-list=
"modelDialogueItem.messageList"
@
show-knowledge-result=
"handleShowKnowledgeResult"
@
show-knowledge-result=
"handleShowKnowledgeResult"
@
update-specify-message-item=
"handleUpdateSpecifyMessageItem"
/>
/>
<HitKnowledgeContent
<HitKnowledgeContent
...
...
src/views/multi-model-dialogue/components/smart-forms/components/business-trip-form.vue
0 → 100644
View file @
edafe38c
This diff is collapsed.
Click to expand it.
src/views/multi-model-dialogue/components/smart-forms/components/business-trip-reimbursement-form.vue
0 → 100644
View file @
edafe38c
<
script
setup
lang=
"ts"
>
import
{
readonly
,
ref
}
from
'vue'
import
type
{
MessageItemInterface
}
from
'../../../types'
import
MarkdownRender
from
'@/components/markdown-render/markdown-render.vue'
import
type
{
FormRules
}
from
'naive-ui'
import
MessageBubbleLoading
from
'../../message-bubble-loading.vue'
interface
Props
{
isAgentMessage
:
boolean
messageItem
:
MessageItemInterface
currentBubbleTextColor
:
string
}
defineProps
<
Props
>
()
const
formRules
=
readonly
<
FormRules
>
({
objective
:
{
required
:
true
,
trigger
:
[
'blur'
,
'input'
],
message
:
''
,
},
travelLocation
:
{
required
:
true
,
trigger
:
[
'blur'
,
'input'
],
message
:
''
,
},
departureTime
:
{
required
:
true
,
trigger
:
[
'blur'
,
'input'
],
message
:
''
,
},
returnTime
:
{
required
:
true
,
trigger
:
[
'blur'
,
'input'
],
message
:
''
,
},
email
:
{
required
:
true
,
trigger
:
[
'blur'
,
'input'
],
message
:
''
,
},
})
const
formModel
=
ref
({
objective
:
'khbf'
,
travelLocation
:
''
,
departureTime
:
null
,
returnTime
:
null
,
vehicle
:
''
,
vehicleEstimatedCost
:
''
,
residence
:
''
,
residenceEstimatedCost
:
''
,
estimatedAmount
:
''
,
generalBudget
:
''
,
email
:
''
,
})
const
objectiveOptions
=
readonly
([
{
label
:
'客户拜访'
,
value
:
'khbf'
,
},
{
label
:
'会议'
,
value
:
'hy'
,
},
{
label
:
'培训'
,
value
:
'px'
,
},
])
</
script
>
<
template
>
<div
class=
"ml-[11px] overflow-hidden"
>
<div
class=
"mb-[7px] text-[12px] text-[#999]"
>
作者信息
</div>
<div
class=
"min-w-[420px]"
>
<div
class=
"box-content min-h-[21px] min-w-[10px] max-w-full rounded-[10px] border border-[#9EA3FF] bg-[#777EF9] px-[15px] py-[14px] text-justify"
:class=
"
{
'!bg-[#fff]': isAgentMessage,
'!min-w-[80px]': messageItem.isAnswerResponseLoading,
}"
>
<div
v-if=
"messageItem.isAnswerResponseLoading && !messageItem.content"
class=
"flex h-[21px] items-center justify-center"
>
<MessageBubbleLoading
:active-color=
"currentBubbleTextColor"
/>
</div>
<template
v-else
>
<div
class=
"mb-[10px]"
>
<i
class=
"iconfont icon-tongyi font-600 text-[14px] text-[#6ccb59]"
></i>
<span
class=
"ml-[5px] text-[14px] text-[#999]"
>
出差表单插件执行成功
</span>
</div>
<MarkdownRender
ref=
"markdownRenderRef"
raw-text-content=
"好的,我将为您自动生成出差表单,表单如下"
:color=
"currentBubbleTextColor"
/>
<!--
<div
v-if=
"messageItem.isAnswerLoading"
class=
"ml-[15px] pt-[12px]"
>
<MessageBubbleLoading
active-color=
"#fff"
width=
"5px"
/>
</div>
-->
</
template
>
</div>
<div
class=
"mt-[10px] box-content min-h-[21px] min-w-[10px] max-w-full rounded-[10px] border border-[#9EA3FF] bg-[#777EF9] px-[15px] py-[14px] text-justify"
:class=
"{
'!bg-[#fff]': isAgentMessage,
}"
>
<h2
class=
"font-600 text-[15px] text-[#0B7DFF]"
>
出差表单
</h2>
<div
class=
"mt-[12px]"
>
<n-form
:model=
"formModel"
:rules=
"formRules"
label-width=
"90"
label-placement=
"left"
:show-feedback=
"false"
>
<n-form-item
class=
"mb-[10px]"
label=
"出差目的"
path=
"objective"
>
<n-select
v-model:value=
"formModel.objective"
placeholder=
"Select"
:options=
"objectiveOptions"
/>
</n-form-item>
<n-form-item
class=
"mb-[10px]"
label=
"出差地点"
path=
"travelLocation"
>
<n-input
v-model:value=
"formModel.travelLocation"
placeholder=
"Input"
/>
</n-form-item>
<n-form-item
class=
"mb-[10px]"
label=
"出发时间"
path=
"departureTime"
>
<n-date-picker
v-model:value=
"formModel.departureTime"
type=
"datetime"
/>
</n-form-item>
<n-form-item
label=
"返回时间"
path=
"returnTime"
>
<n-date-picker
v-model:value=
"formModel.returnTime"
type=
"datetime"
/>
</n-form-item>
<n-form-item
label=
""
>
<div
class=
"h-[1px] w-full bg-[#B1B1B1] opacity-45"
></div>
</n-form-item>
<n-form-item
class=
"mb-[10px]"
label=
"交通工具"
path=
"vehicle"
>
<n-input
v-model:value=
"formModel.vehicle"
placeholder=
"Input"
/>
</n-form-item>
<n-form-item
label=
"预计费用"
path=
"vehicleEstimatedCost"
>
<n-input
v-model:value=
"formModel.vehicleEstimatedCost"
placeholder=
"Input"
/>
</n-form-item>
<n-form-item
label=
""
>
<div
class=
"h-[1px] w-full bg-[#B1B1B1] opacity-45"
></div>
</n-form-item>
<n-form-item
class=
"mb-[10px]"
label=
"住宿地点"
path=
"residence"
>
<n-input
v-model:value=
"formModel.residence"
placeholder=
"Input"
/>
</n-form-item>
<n-form-item
label=
"预计费用"
path=
"residenceEstimatedCost"
>
<n-input
v-model:value=
"formModel.residenceEstimatedCost"
placeholder=
"Input"
/>
</n-form-item>
<n-form-item
label=
""
>
<div
class=
"h-[1px] w-full bg-[#B1B1B1] opacity-45"
></div>
</n-form-item>
<n-form-item
class=
"mb-[10px]"
label=
"预计金额"
path=
"residence"
>
<n-input
v-model:value=
"formModel.estimatedAmount"
placeholder=
"Input"
/>
</n-form-item>
<n-form-item
label=
"总预算"
path=
"generalBudget"
>
<n-input
v-model:value=
"formModel.generalBudget"
placeholder=
"Input"
/>
</n-form-item>
<n-form-item
label=
""
>
<div
class=
"h-[1px] w-full bg-[#B1B1B1] opacity-45"
></div>
</n-form-item>
<n-form-item
class=
"mb-[10px]"
label=
"邮箱信息"
path=
"email"
>
<n-input
v-model:value=
"formModel.email"
placeholder=
"Input"
/>
</n-form-item>
<div
class=
"mt-[30px] text-end"
>
<n-button
type=
"primary"
>
确认提交
</n-button>
</div>
</n-form>
</div>
</div>
</div>
</div>
</template>
src/views/multi-model-dialogue/components/smart-forms/index.vue
0 → 100644
View file @
edafe38c
<
script
setup
lang=
"ts"
>
import
type
{
MessageItemInterface
}
from
'../../types'
import
BusinessTripForm
from
'./components/business-trip-form.vue'
// import BusinessTripReimbursementForm from './business-trip-reimbursement-form.vue'
interface
Props
{
isAgentMessage
:
boolean
messageAuthor
:
string
messageItem
:
MessageItemInterface
currentBubbleTextColor
:
string
}
defineProps
<
Props
>
()
</
script
>
<
template
>
<BusinessTripForm
:message-item=
"messageItem"
:is-agent-message=
"isAgentMessage"
:message-author=
"messageAuthor"
:current-bubble-text-color=
"currentBubbleTextColor"
/>
<!--
<BusinessTripReimbursementForm
:is-agent-message=
"isAgentMessage"
:message-item=
"messageItem"
:current-bubble-text-color=
"currentBubbleTextColor"
/>
-->
</
template
>
src/views/multi-model-dialogue/components/smart-forms/types/types.d.ts
0 → 100644
View file @
edafe38c
export
interface
ResponseBusinessTripForm
{
purpose
:
string
place
:
string
departureDate
:
string
returnDate
:
string
vehicle
:
string
transportationFee
:
string
accommodation
:
string
accommodationCost
:
string
advancePaymentAmount
:
string
totalBudget
:
string
}
export
interface
BusinessTripForm
{
objective
:
string
travelLocation
:
string
departureTime
:
number
|
null
returnTime
:
number
|
null
vehicle
:
string
vehicleEstimatedCost
:
number
|
null
residence
:
string
residenceEstimatedCost
:
number
|
null
advancePaymentAmount
:
number
|
null
generalBudget
:
string
email
:
string
}
export
type
SmartFormDisplayFormat
=
'travelForm'
src/views/multi-model-dialogue/components/smart-forms/utils/smart-forms.ts
0 → 100644
View file @
edafe38c
import
{
BusinessTripForm
,
ResponseBusinessTripForm
}
from
'../types/types'
import
type
{
SmartFormTypes
}
from
'../../../types'
export
function
smartFormTypeConverter
(
type
:
'travelForm'
):
SmartFormTypes
{
switch
(
type
)
{
case
'travelForm'
:
return
'BusinessTripForm'
}
}
export
function
businessTripFormParser
(
resForm
:
Partial
<
ResponseBusinessTripForm
>
)
{
return
{
objective
:
resForm
.
purpose
||
'CustomerVisits'
,
travelLocation
:
resForm
.
place
||
''
,
departureTime
:
resForm
.
departureDate
?
Date
.
parse
(
resForm
.
departureDate
)
:
null
,
returnTime
:
resForm
.
returnDate
?
Date
.
parse
(
resForm
.
returnDate
)
:
null
,
vehicle
:
resForm
.
vehicle
||
''
,
vehicleEstimatedCost
:
resForm
.
transportationFee
?
Number
.
parseInt
(
resForm
.
transportationFee
)
:
null
,
residence
:
resForm
.
accommodation
||
''
,
residenceEstimatedCost
:
resForm
.
accommodationCost
?
Number
.
parseInt
(
resForm
.
accommodationCost
)
:
null
,
advancePaymentAmount
:
resForm
.
advancePaymentAmount
?
Number
.
parseInt
(
resForm
.
advancePaymentAmount
)
:
null
,
generalBudget
:
resForm
.
totalBudget
||
''
,
email
:
''
,
}
}
export
function
businessTripFormReturner
(
form
:
BusinessTripForm
)
{
return
{
purpose
:
form
.
objective
,
place
:
form
.
travelLocation
,
departureDate
:
form
.
departureTime
?
new
Date
(
form
.
departureTime
).
toISOString
()
:
''
,
returnDate
:
form
.
returnTime
?
new
Date
(
form
.
returnTime
).
toISOString
()
:
''
,
vehicle
:
form
.
vehicle
,
transportationFee
:
form
.
vehicleEstimatedCost
,
accommodation
:
form
.
residence
,
accommodationCost
:
form
.
residenceEstimatedCost
,
advancePaymentAmount
:
form
.
advancePaymentAmount
,
totalBudget
:
form
.
generalBudget
,
email
:
form
.
email
,
}
}
src/views/multi-model-dialogue/multi-model-dialogue.vue
View file @
edafe38c
...
@@ -9,7 +9,7 @@ import type { ValueOf } from 'type-fest'
...
@@ -9,7 +9,7 @@ import type { ValueOf } from 'type-fest'
import
PageHeader
from
'./components/page-header.vue'
import
PageHeader
from
'./components/page-header.vue'
import
ModelDialogueItem
from
'./components/model-dialogue-item.vue'
import
ModelDialogueItem
from
'./components/model-dialogue-item.vue'
import
FooterOperation
from
'./components/footer-operation.vue'
import
FooterOperation
from
'./components/footer-operation.vue'
import
{
MessageItemInterface
,
MultiModelDialogueItem
,
LargeModelItem
}
from
'./types'
import
{
MessageItemInterface
,
MultiModelDialogueItem
,
LargeModelItem
,
SmartFormTypes
}
from
'./types'
import
{
import
{
fetchGetDebugApplicationInfo
,
fetchGetDebugApplicationInfo
,
fetchGetLargeModelInfo
,
fetchGetLargeModelInfo
,
...
@@ -254,9 +254,7 @@ function handleUpdateSpecifyMessageItem(messageId: string, newObj: Partial<Messa
...
@@ -254,9 +254,7 @@ function handleUpdateSpecifyMessageItem(messageId: string, newObj: Partial<Messa
if
(
currentMessageItemInfo
)
{
if
(
currentMessageItemInfo
)
{
Object
.
entries
<
ValueOf
<
typeof
newObj
>>
(
newObj
).
forEach
(([
key
,
value
])
=>
{
Object
.
entries
<
ValueOf
<
typeof
newObj
>>
(
newObj
).
forEach
(([
key
,
value
])
=>
{
if
(
Object
.
prototype
.
hasOwnProperty
.
call
(
currentMessageItemInfo
,
key
))
{
;(
currentMessageItemInfo
as
any
)[
key
as
keyof
MessageItemInterface
]
=
value
;(
currentMessageItemInfo
as
any
)[
key
as
keyof
MessageItemInterface
]
=
value
}
})
})
}
}
}
}
...
@@ -300,6 +298,17 @@ function handleBlockMessageResponse() {
...
@@ -300,6 +298,17 @@ function handleBlockMessageResponse() {
modelDialogueItem
.
messageList
.
clear
()
modelDialogueItem
.
messageList
.
clear
()
})
})
}
}
function
onSmartFormsStatusFreezeCheck
(
smartFormType
:
SmartFormTypes
,
index
:
number
)
{
/* 重置智能表单项目 */
if
(
smartFormType
)
{
multiModelDialogueList
.
value
[
index
].
messageList
.
forEach
((
item
)
=>
{
if
(
item
.
smartFormInfo
&&
item
.
smartFormInfo
.
type
===
smartFormType
)
{
item
.
smartFormInfo
.
isDisabled
=
true
}
})
}
}
</
script
>
</
script
>
<
template
>
<
template
>
...
@@ -328,6 +337,7 @@ function handleBlockMessageResponse() {
...
@@ -328,6 +337,7 @@ function handleBlockMessageResponse() {
v-for=
"(modelDialogueItem, index) in multiModelDialogueList"
v-for=
"(modelDialogueItem, index) in multiModelDialogueList"
:ref=
"(el) => (modelDialogueListRef[index] = el as InstanceType
<typeof
ModelDialogueItem
>
)"
:ref=
"(el) => (modelDialogueListRef[index] = el as InstanceType
<typeof
ModelDialogueItem
>
)"
:key="modelDialogueItem.id"
:key="modelDialogueItem.id"
:model-dialogue-id="index"
:model-dialogue-item="modelDialogueItem"
:model-dialogue-item="modelDialogueItem"
:is-current="modelDialogueItem.id === multiModelDialogueList[0].id"
:is-current="modelDialogueItem.id === multiModelDialogueList[0].id"
:model-list-options="modelListOptions"
:model-list-options="modelListOptions"
...
@@ -336,6 +346,7 @@ function handleBlockMessageResponse() {
...
@@ -336,6 +346,7 @@ function handleBlockMessageResponse() {
@remove-model-dialogue-item="handleRemoveModelDialogueItem"
@remove-model-dialogue-item="handleRemoveModelDialogueItem"
@replace-config="handleReplaceAgentConfig"
@replace-config="handleReplaceAgentConfig"
@reset-conversation="handleResetConversation"
@reset-conversation="handleResetConversation"
@update-message-item="handleUpdateSpecifyMessageItem"
/>
/>
</div>
</div>
</main>
</main>
...
@@ -352,6 +363,7 @@ function handleBlockMessageResponse() {
...
@@ -352,6 +363,7 @@ function handleBlockMessageResponse() {
@
delete-message-item=
"handleDeleteMessageItem"
@
delete-message-item=
"handleDeleteMessageItem"
@
clear-all-message=
"handleClearAllMessage"
@
clear-all-message=
"handleClearAllMessage"
@
message-list-scroll-to-bottom=
"handleMessageListScrollToBottom"
@
message-list-scroll-to-bottom=
"handleMessageListScrollToBottom"
@
smart-forms-status-freeze-check=
"onSmartFormsStatusFreezeCheck"
/>
/>
<Transition
name=
"mask"
mode=
"out-in"
>
<Transition
name=
"mask"
mode=
"out-in"
>
...
...
src/views/multi-model-dialogue/types.d.ts
View file @
edafe38c
...
@@ -25,6 +25,8 @@ export interface MultiModelDialogueItem {
...
@@ -25,6 +25,8 @@ export interface MultiModelDialogueItem {
messageList
:
Map
<
string
,
MessageItemInterface
>
messageList
:
Map
<
string
,
MessageItemInterface
>
}
}
export
type
SmartFormTypes
=
'BusinessTripForm'
export
interface
MessageItemInterface
{
export
interface
MessageItemInterface
{
role
:
'user'
|
'assistant'
role
:
'user'
|
'assistant'
avatar
:
string
avatar
:
string
...
@@ -38,11 +40,16 @@ export interface MessageItemInterface {
...
@@ -38,11 +40,16 @@ export interface MessageItemInterface {
knowledgeContentResult
:
KnowledgeContentResultItem
[]
knowledgeContentResult
:
KnowledgeContentResultItem
[]
dbChainSQLContent
:
string
dbChainSQLContent
:
string
pluginResult
?:
{
pluginResult
?:
{
displayFormat
:
'json'
|
'markdown'
|
'none'
displayFormat
:
PluginDisplayFormatType
pluginName
:
string
pluginName
:
string
arguments
:
string
arguments
:
string
pluginContent
:
string
pluginContent
:
string
}
}
smartFormInfo
?:
{
type
:
SmartFormTypes
isDisabled
:
boolean
params
:
string
}
}
}
export
interface
LargeModelItem
{
export
interface
LargeModelItem
{
...
...
src/views/multi-model-dialogue/utils/fetch-event-stream-source.ts
View file @
edafe38c
...
@@ -8,7 +8,7 @@ import { languageKeyTransform } from '@/utils/language-key-transform'
...
@@ -8,7 +8,7 @@ import { languageKeyTransform } from '@/utils/language-key-transform'
interface
ResponseData
{
interface
ResponseData
{
message
:
string
message
:
string
reasoningContent
:
string
reasoningContent
:
string
function
:
{
displayFormat
:
'json'
|
'markdown'
|
'none'
;
name
:
string
;
result
:
string
;
arguments
:
string
}
function
:
{
displayFormat
:
PluginDisplayFormatType
;
name
:
string
;
result
:
string
;
arguments
:
string
}
knowledgeContentResult
:
KnowledgeContentResultItem
[]
knowledgeContentResult
:
KnowledgeContentResultItem
[]
dbChainResult
:
DBChainResultItem
[]
dbChainResult
:
DBChainResultItem
[]
}
}
...
...
src/views/personal-space/personal-app-setting/components/agent-config/agent-preview/agent-preview.vue
View file @
edafe38c
...
@@ -14,6 +14,7 @@ import { usePersonalAppConfigStore } from '@/store/modules/personal-app-config'
...
@@ -14,6 +14,7 @@ import { usePersonalAppConfigStore } from '@/store/modules/personal-app-config'
import
{
useSystemLanguageStore
}
from
'@/store/modules/system-language'
import
{
useSystemLanguageStore
}
from
'@/store/modules/system-language'
import
{
Brain
,
Down
}
from
'@icon-park/vue-next'
import
{
Brain
,
Down
}
from
'@icon-park/vue-next'
import
{
validBrowser
}
from
'@/utils/browser-detection'
import
{
validBrowser
}
from
'@/utils/browser-detection'
import
{
SmartFormTypes
}
from
'../types'
const
{
t
}
=
useI18n
()
const
{
t
}
=
useI18n
()
...
@@ -78,9 +79,7 @@ function handleUpdateSpecifyMessageItem(messageId: string, newMessageItem: Parti
...
@@ -78,9 +79,7 @@ function handleUpdateSpecifyMessageItem(messageId: string, newMessageItem: Parti
}
}
Object
.
entries
<
ValueOf
<
typeof
newMessageItem
>>
(
newMessageItem
).
forEach
(([
key
,
value
])
=>
{
Object
.
entries
<
ValueOf
<
typeof
newMessageItem
>>
(
newMessageItem
).
forEach
(([
key
,
value
])
=>
{
if
(
Object
.
prototype
.
hasOwnProperty
.
call
(
currentMessageItemInfo
,
key
))
{
;(
currentMessageItemInfo
as
any
)[
key
as
keyof
ConversationMessageItem
]
=
value
;(
currentMessageItemInfo
as
any
)[
key
as
keyof
ConversationMessageItem
]
=
value
}
})
})
}
}
}
}
...
@@ -235,6 +234,17 @@ function handleAudioPause(isClearMessageList = false) {
...
@@ -235,6 +234,17 @@ function handleAudioPause(isClearMessageList = false) {
footerInputRef
.
value
?.
blockMessageResponse
()
footerInputRef
.
value
?.
blockMessageResponse
()
}
}
}
}
function
onSmartFormsStatusFreezeCheck
(
smartFormType
:
SmartFormTypes
)
{
/* 重置智能表单项目 */
if
(
smartFormType
)
{
messageList
.
value
.
forEach
((
item
)
=>
{
if
(
item
.
smartFormInfo
&&
item
.
smartFormInfo
.
type
===
smartFormType
)
{
item
.
smartFormInfo
.
isDisabled
=
true
}
})
}
}
</
script
>
</
script
>
<
template
>
<
template
>
...
@@ -328,6 +338,7 @@ function handleAudioPause(isClearMessageList = false) {
...
@@ -328,6 +338,7 @@ function handleAudioPause(isClearMessageList = false) {
:create-continue-questions-exception=
"createContinueQuestionsException"
:create-continue-questions-exception=
"createContinueQuestionsException"
@
audio-play=
"handleAudioPlay"
@
audio-play=
"handleAudioPlay"
@
audio-pause=
"handleAudioPause"
@
audio-pause=
"handleAudioPause"
@
update-specify-message-item=
"handleUpdateSpecifyMessageItem"
/>
/>
</div>
</div>
</div>
</div>
...
@@ -348,6 +359,7 @@ function handleAudioPause(isClearMessageList = false) {
...
@@ -348,6 +359,7 @@ function handleAudioPause(isClearMessageList = false) {
@
update-continuous-question-status=
"handleUpdateContinueQuestionStatus"
@
update-continuous-question-status=
"handleUpdateContinueQuestionStatus"
@
audio-play=
"handleAudioPlay"
@
audio-play=
"handleAudioPlay"
@
audio-pause=
"handleAudioPause"
@
audio-pause=
"handleAudioPause"
@
smart-forms-status-freeze-check=
"onSmartFormsStatusFreezeCheck"
/>
/>
<MemoryPreviewModal
v-model=
"isShowMemoryPreviewModal"
:data=
"selectedMemoryTabName"
/>
<MemoryPreviewModal
v-model=
"isShowMemoryPreviewModal"
:data=
"selectedMemoryTabName"
/>
...
...
src/views/personal-space/personal-app-setting/components/agent-config/agent-preview/components/footer-input.vue
View file @
edafe38c
...
@@ -13,6 +13,9 @@ import { TEXTTOSPEECH_WS_URL } from '@/config/base-url'
...
@@ -13,6 +13,9 @@ import { TEXTTOSPEECH_WS_URL } from '@/config/base-url'
import
WebSocketCtr
from
'@/utils/web-socket-ctr'
import
WebSocketCtr
from
'@/utils/web-socket-ctr'
import
{
ChannelType
}
from
'@/enums/channel'
import
{
ChannelType
}
from
'@/enums/channel'
import
{
useUserStore
}
from
'@/store/modules/user'
import
{
useUserStore
}
from
'@/store/modules/user'
import
{
smartFormTypeConverter
}
from
'../components/smart-forms/utils/smart-forms'
import
{
SmartFormTypes
}
from
'../../types'
import
{
SmartFormDisplayFormat
}
from
'./smart-forms/types/types'
interface
Props
{
interface
Props
{
messageList
:
Map
<
string
,
ConversationMessageItem
>
messageList
:
Map
<
string
,
ConversationMessageItem
>
...
@@ -35,6 +38,7 @@ const emit = defineEmits<{
...
@@ -35,6 +38,7 @@ const emit = defineEmits<{
updateContinuousQuestionStatus
:
[
value
:
'default'
|
'close'
]
updateContinuousQuestionStatus
:
[
value
:
'default'
|
'close'
]
audioPlay
:
[
messageItem
:
ConversationMessageItem
,
requestId
?:
string
]
audioPlay
:
[
messageItem
:
ConversationMessageItem
,
requestId
?:
string
]
audioPause
:
[]
audioPause
:
[]
smartFormsStatusFreezeCheck
:
[
value
:
SmartFormTypes
]
}
>
()
}
>
()
const
personalAppConfigStore
=
usePersonalAppConfigStore
()
const
personalAppConfigStore
=
usePersonalAppConfigStore
()
...
@@ -61,6 +65,7 @@ const assistantFullAnswerContent = ref('')
...
@@ -61,6 +65,7 @@ const assistantFullAnswerContent = ref('')
const
currentAgentTimberId
=
ref
(
''
)
const
currentAgentTimberId
=
ref
(
''
)
const
sentenceSpeechException
=
ref
(
false
)
const
sentenceSpeechException
=
ref
(
false
)
const
messageAudioLoading
=
ref
(
false
)
const
messageAudioLoading
=
ref
(
false
)
const
isSmartFormPlugins
=
ref
(
false
)
// 是否智能表单插件
const
currentLatestMessageItemKeyMap
=
ref
(
new
Map
<
'assistant'
|
'user'
,
string
>
())
const
currentLatestMessageItemKeyMap
=
ref
(
new
Map
<
'assistant'
|
'user'
,
string
>
())
let
controller
:
AbortController
|
null
=
null
let
controller
:
AbortController
|
null
=
null
...
@@ -233,6 +238,7 @@ function handleMessageSend() {
...
@@ -233,6 +238,7 @@ function handleMessageSend() {
currentAgentTimberId
.
value
=
personalAppConfigStore
.
voiceConfig
.
timbreId
currentAgentTimberId
.
value
=
personalAppConfigStore
.
voiceConfig
.
timbreId
sentenceSpeechException
.
value
=
false
sentenceSpeechException
.
value
=
false
messageAudioLoading
.
value
=
false
messageAudioLoading
.
value
=
false
isSmartFormPlugins
.
value
=
false
const
isVoiceEnabled
=
!!
personalAppConfigStore
.
voiceConfig
.
timbreId
const
isVoiceEnabled
=
!!
personalAppConfigStore
.
voiceConfig
.
timbreId
...
@@ -271,6 +277,31 @@ function handleMessageSend() {
...
@@ -271,6 +277,31 @@ function handleMessageSend() {
// 插件
// 插件
if
(
data
.
function
&&
data
.
function
.
name
)
{
if
(
data
.
function
&&
data
.
function
.
name
)
{
// 表单插件,展示表单内容
if
([
'travelForm'
].
includes
(
data
.
function
.
displayFormat
))
{
emit
(
'smartFormsStatusFreezeCheck'
,
smartFormTypeConverter
(
data
.
function
.
displayFormat
as
SmartFormDisplayFormat
),
)
emit
(
'updateSpecifyMessageItem'
,
latestAssistantMessageKey
,
{
pluginResult
:
{
displayFormat
:
data
.
function
.
displayFormat
,
pluginName
:
data
.
function
.
name
,
arguments
:
data
.
function
.
arguments
,
pluginContent
:
data
.
function
.
result
,
},
smartFormInfo
:
{
type
:
smartFormTypeConverter
(
data
.
function
.
displayFormat
as
SmartFormDisplayFormat
),
isDisabled
:
false
,
params
:
data
.
function
.
result
,
},
})
emit
(
'updatePageScroll'
)
isSmartFormPlugins
.
value
=
true
return
}
emit
(
'updateSpecifyMessageItem'
,
latestAssistantMessageKey
,
{
emit
(
'updateSpecifyMessageItem'
,
latestAssistantMessageKey
,
{
pluginResult
:
{
pluginResult
:
{
displayFormat
:
data
.
function
.
displayFormat
,
displayFormat
:
data
.
function
.
displayFormat
,
...
@@ -313,7 +344,7 @@ function handleMessageSend() {
...
@@ -313,7 +344,7 @@ function handleMessageSend() {
''
,
''
,
)
)
if
(
!
sentenceExtractCheckEnabled
.
value
&&
isVoiceEnabled
)
{
if
(
!
sentenceExtractCheckEnabled
.
value
&&
isVoiceEnabled
&&
!
isSmartFormPlugins
.
value
)
{
sentenceExtract
(
latestAssistantMessageKey
)
sentenceExtract
(
latestAssistantMessageKey
)
sentenceExtractCheckEnabled
.
value
=
true
sentenceExtractCheckEnabled
.
value
=
true
messageAudioLoading
.
value
=
true
messageAudioLoading
.
value
=
true
...
...
src/views/personal-space/personal-app-setting/components/agent-config/agent-preview/components/message-item.vue
View file @
edafe38c
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
computed
,
ref
,
useTemplateRef
}
from
'vue'
import
{
computed
,
ref
,
useTemplateRef
,
readonly
,
provide
}
from
'vue'
import
{
useI18n
}
from
'vue-i18n'
import
{
useI18n
}
from
'vue-i18n'
import
{
throttle
}
from
'lodash-es'
import
{
throttle
}
from
'lodash-es'
import
{
Down
}
from
'@icon-park/vue-next'
import
{
Down
}
from
'@icon-park/vue-next'
import
CustomLoading
from
'./custom-loading.vue'
import
CustomLoading
from
'./custom-loading.vue'
import
SmartForms
from
'./smart-forms/index.vue'
import
{
usePersonalAppConfigStore
}
from
'@/store/modules/personal-app-config'
import
{
usePersonalAppConfigStore
}
from
'@/store/modules/personal-app-config'
import
MarkdownRender
from
'@/components/markdown-render/markdown-render.vue'
import
MarkdownRender
from
'@/components/markdown-render/markdown-render.vue'
import
ExecuteCodeRender
from
'@/components/execute-code-render/execute-code-render.vue'
import
ExecuteCodeRender
from
'@/components/execute-code-render/execute-code-render.vue'
...
@@ -14,7 +15,7 @@ import { downloadFile } from '@/utils/download-file'
...
@@ -14,7 +15,7 @@ import { downloadFile } from '@/utils/download-file'
import
{
copyToClip
}
from
'@/utils/copy'
import
{
copyToClip
}
from
'@/utils/copy'
interface
Props
{
interface
Props
{
role
:
'user'
|
'assistant'
messageItemId
:
string
messageItem
:
ConversationMessageItem
messageItem
:
ConversationMessageItem
}
}
...
@@ -33,8 +34,12 @@ const personalAppConfigStore = usePersonalAppConfigStore()
...
@@ -33,8 +34,12 @@ const personalAppConfigStore = usePersonalAppConfigStore()
const
markdownRenderRef
=
useTemplateRef
<
InstanceType
<
typeof
MarkdownRender
>>
(
'markdownRenderRef'
)
const
markdownRenderRef
=
useTemplateRef
<
InstanceType
<
typeof
MarkdownRender
>>
(
'markdownRenderRef'
)
provide
(
'messageItemId'
,
props
.
messageItemId
)
const
isShowReasoningContent
=
ref
(
true
)
const
isShowReasoningContent
=
ref
(
true
)
const
displaySmartFormsList
=
readonly
([
'travelForm'
])
const
useAvatar
=
computed
(()
=>
{
const
useAvatar
=
computed
(()
=>
{
return
userStore
.
userInfo
.
avatarUrl
||
'https://gsst-poe-sit.gz.bcebos.com/data/20240910/1725952917468.png'
return
userStore
.
userInfo
.
avatarUrl
||
'https://gsst-poe-sit.gz.bcebos.com/data/20240910/1725952917468.png'
})
})
...
@@ -43,8 +48,27 @@ const assistantAvatar = computed(() => {
...
@@ -43,8 +48,27 @@ const assistantAvatar = computed(() => {
return
personalAppConfigStore
.
baseInfo
.
agentAvatar
return
personalAppConfigStore
.
baseInfo
.
agentAvatar
})
})
const
isAgentMessage
=
computed
(()
=>
{
return
props
.
messageItem
.
role
===
'assistant'
})
const
currentBubbleTextColor
=
computed
(()
=>
{
return
isAgentMessage
.
value
?
'#192338'
:
'#fff'
})
const
isShowSmartForms
=
computed
(()
=>
{
if
(
props
.
messageItem
?.
pluginResult
?.
displayFormat
)
{
return
displaySmartFormsList
.
includes
(
props
.
messageItem
?.
pluginResult
?.
displayFormat
)
}
return
false
})
const
messageAuthor
=
computed
(()
=>
{
return
isAgentMessage
.
value
?
props
.
messageItem
.
modelName
||
'AI'
:
userStore
.
userInfo
.
nickName
})
const
isShowAudioControl
=
computed
(()
=>
{
const
isShowAudioControl
=
computed
(()
=>
{
return
props
.
role
===
'assistant'
&&
!
props
.
messageItem
.
isVoiceLoading
return
isAgentMessage
.
value
&&
!
props
.
messageItem
.
isVoiceLoading
})
})
const
isPlayableAudio
=
computed
(()
=>
{
const
isPlayableAudio
=
computed
(()
=>
{
...
@@ -52,7 +76,7 @@ const isPlayableAudio = computed(() => {
...
@@ -52,7 +76,7 @@ const isPlayableAudio = computed(() => {
})
})
const
isShowVoiceLoading
=
computed
(()
=>
{
const
isShowVoiceLoading
=
computed
(()
=>
{
return
props
.
role
===
'assistant'
&&
props
.
messageItem
.
isVoiceLoading
&&
props
.
messageItem
.
isVoiceEnabled
return
isAgentMessage
.
value
&&
props
.
messageItem
.
isVoiceLoading
&&
props
.
messageItem
.
isVoiceEnabled
})
})
const
isDeepSeekR1
=
computed
(()
=>
{
const
isDeepSeekR1
=
computed
(()
=>
{
...
@@ -105,7 +129,7 @@ const handleContentCopy = throttle(
...
@@ -105,7 +129,7 @@ const handleContentCopy = throttle(
<
template
>
<
template
>
<div
class=
"mb-5 flex last:mb-0"
>
<div
class=
"mb-5 flex last:mb-0"
>
<NImage
<NImage
:src=
"
role === 'user' ? useAvatar : assistant
Avatar"
:src=
"
isAgentMessage ? assistantAvatar : use
Avatar"
preview-disabled
preview-disabled
:width=
"32"
:width=
"32"
:height=
"32"
:height=
"32"
...
@@ -113,9 +137,9 @@ const handleContentCopy = throttle(
...
@@ -113,9 +137,9 @@ const handleContentCopy = throttle(
class=
"mr-2 mt-1.5 h-8 w-8 flex-shrink-0 rounded-full"
class=
"mr-2 mt-1.5 h-8 w-8 flex-shrink-0 rounded-full"
/>
/>
<div
class=
"flex flex-col items-start overflow-x-auto"
>
<div
v-if=
"!isShowSmartForms"
class=
"flex flex-col items-start overflow-x-auto"
>
<!-- DeepSeek大模型思考 -->
<!-- DeepSeek大模型思考 -->
<template
v-if=
"
role === 'assistant'
&& isDeepSeekR1"
>
<template
v-if=
"
isAgentMessage
&& isDeepSeekR1"
>
<div
class=
"my-[7px] select-none text-[14px]"
>
<div
class=
"my-[7px] select-none text-[14px]"
>
<div
class=
"inline-flex cursor-pointer"
@
click=
"handleShowReasoningContentSwitch"
>
<div
class=
"inline-flex cursor-pointer"
@
click=
"handleShowReasoningContentSwitch"
>
<span
v-if=
"messageItem.isTextContentLoading"
class=
"mr-[6px]"
>
<span
v-if=
"messageItem.isTextContentLoading"
class=
"mr-[6px]"
>
...
@@ -156,17 +180,17 @@ const handleContentCopy = throttle(
...
@@ -156,17 +180,17 @@ const handleContentCopy = throttle(
<!--
大模型内容
-->
<!--
大模型内容
-->
<
div
class
=
"flex min-w-[80px] max-w-full flex-col items-start overflow-x-auto"
>
<
div
class
=
"flex min-w-[80px] max-w-full flex-col items-start overflow-x-auto"
>
<
div
<
div
class
=
"w-full flex-wrap rounded-xl border border-[#
e8e9eb
] px-4 py-[11px]"
class
=
"w-full flex-wrap rounded-xl border border-[#
9EA3FF
] px-4 py-[11px]"
:
class
=
"
role === 'user' ? 'user-content-container bg-[#777EF9] text-white' : 'bg-white text-[#333]
'"
:
class
=
"
isAgentMessage ? 'bg-white text-[#333]' : 'user-content-container bg-[#777EF9] text-white
'"
>
>
<
img
<
img
v
-
show
=
"
role === 'user'
&& messageItem.imageUrl"
v
-
show
=
"
!isAgentMessage
&& messageItem.imageUrl"
:
src
=
"messageItem.imageUrl"
:
src
=
"messageItem.imageUrl"
class
=
"max-h-[120px]! mb-[11px] rounded-[10px] object-contain"
class
=
"max-h-[120px]! mb-[11px] rounded-[10px] object-contain"
/>
/>
<!--
插件返回结果
-->
<!--
插件返回结果
-->
<
div
v
-
show
=
"
role === 'assistant'
&& messageItem?.pluginResult?.pluginName"
class
=
"mb-[11px] w-full"
>
<
div
v
-
show
=
"
isAgentMessage
&& messageItem?.pluginResult?.pluginName"
class
=
"mb-[11px] w-full"
>
<
ExecutePluginRender
<
ExecutePluginRender
:
display
-
format
=
"messageItem.pluginResult?.displayFormat || 'none'"
:
display
-
format
=
"messageItem.pluginResult?.displayFormat || 'none'"
:
name
=
"messageItem.pluginResult?.pluginName!"
:
name
=
"messageItem.pluginResult?.pluginName!"
...
@@ -197,12 +221,12 @@ const handleContentCopy = throttle(
...
@@ -197,12 +221,12 @@ const handleContentCopy = throttle(
? t('common_module.dialogue_module.empty_message_content')
? t('common_module.dialogue_module.empty_message_content')
: messageItem.textContent
: messageItem.textContent
"
"
:
color
=
"
role === 'user' ? '#fff' : '#192338'
"
:
color
=
"
currentBubbleTextColor
"
/>
/>
<
/p
>
<
/p
>
<
div
<
div
v
-
show
=
"(
role === 'assistant'
&& messageItem.isAnswerResponseLoading) || isShowVoiceLoading"
v
-
show
=
"(
isAgentMessage
&& messageItem.isAnswerResponseLoading) || isShowVoiceLoading"
class
=
"mt-4 px-4"
class
=
"mt-4 px-4"
:
class
=
"isShowAudioControl ? 'mb-2.5' : 'mb-[5px]'"
:
class
=
"isShowAudioControl ? 'mb-2.5' : 'mb-[5px]'"
>
>
...
@@ -242,7 +266,7 @@ const handleContentCopy = throttle(
...
@@ -242,7 +266,7 @@ const handleContentCopy = throttle(
<
div
class
=
"flex w-full items-center justify-between py-[5px]"
>
<
div
class
=
"flex w-full items-center justify-between py-[5px]"
>
<
div
>
<
div
>
<
div
<
div
v
-
show
=
"
role === 'assistant'
&& messageItem.knowledgeContentResult.length"
v
-
show
=
"
isAgentMessage
&& messageItem.knowledgeContentResult.length"
class
=
"flex-center rounded-theme h-8 cursor-pointer gap-[5px] px-[13px] font-['Microsoft_YaHei_UI'] text-[#0B7DFF] hover:opacity-80"
class
=
"flex-center rounded-theme h-8 cursor-pointer gap-[5px] px-[13px] font-['Microsoft_YaHei_UI'] text-[#0B7DFF] hover:opacity-80"
@
click
=
"emit('showKnowledgeResult')"
@
click
=
"emit('showKnowledgeResult')"
>
>
...
@@ -252,7 +276,7 @@ const handleContentCopy = throttle(
...
@@ -252,7 +276,7 @@ const handleContentCopy = throttle(
<
/div
>
<
/div
>
<
div
<
div
v
-
show
=
"
role === 'assistant'
&& messageItem.textContent && !messageItem.isAnswerResponseLoading"
v
-
show
=
"
isAgentMessage
&& messageItem.textContent && !messageItem.isAnswerResponseLoading"
class
=
"pr-[13px] text-end"
class
=
"pr-[13px] text-end"
>
>
<
i
<
i
...
@@ -267,6 +291,14 @@ const handleContentCopy = throttle(
...
@@ -267,6 +291,14 @@ const handleContentCopy = throttle(
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
SmartForms
v
-
else
:
message
-
author
=
"messageAuthor"
:
is
-
agent
-
message
=
"isAgentMessage"
:
message
-
item
=
"messageItem"
:
current
-
bubble
-
text
-
color
=
"currentBubbleTextColor"
/>
<
/div
>
<
/div
>
<
/template
>
<
/template
>
...
...
src/views/personal-space/personal-app-setting/components/agent-config/agent-preview/components/message-list.vue
View file @
edafe38c
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
computed
,
nextTick
,
ref
,
useTemplateRef
,
watch
}
from
'vue'
import
{
computed
,
nextTick
,
provide
,
ref
,
useTemplateRef
,
watch
}
from
'vue'
import
{
useElementVisibility
}
from
'@vueuse/core'
import
{
useElementVisibility
}
from
'@vueuse/core'
import
MessageItem
from
'./message-item.vue'
import
MessageItem
from
'./message-item.vue'
import
ContinueQuestion
from
'./continue-question.vue'
import
ContinueQuestion
from
'./continue-question.vue'
...
@@ -16,15 +16,22 @@ interface Props {
...
@@ -16,15 +16,22 @@ interface Props {
const
props
=
defineProps
<
Props
>
()
const
props
=
defineProps
<
Props
>
()
defineEmits
<
{
const
emit
=
defineEmits
<
{
audioPlay
:
[
messageItem
:
ConversationMessageItem
]
audioPlay
:
[
messageItem
:
ConversationMessageItem
]
audioPause
:
[]
audioPause
:
[]
updateSpecifyMessageItem
:
[
messageId
:
string
,
newMessageItem
:
Partial
<
ConversationMessageItem
>
]
}
>
()
}
>
()
const
{
scrollRef
,
scrollToBottom
}
=
useScroll
()
const
{
scrollRef
,
scrollToBottom
}
=
useScroll
()
const
backBottomBtnFlagRef
=
useTemplateRef
<
HTMLDivElement
|
null
>
(
'backBottomBtnFlagRef'
)
const
backBottomBtnFlagRef
=
useTemplateRef
<
HTMLDivElement
|
null
>
(
'backBottomBtnFlagRef'
)
const
isNotShowBackBottomBtn
=
useElementVisibility
(
backBottomBtnFlagRef
)
const
isNotShowBackBottomBtn
=
useElementVisibility
(
backBottomBtnFlagRef
)
provide
(
'updateSpecifyMessageItem'
,
{
updateSpecifyMessageItem
:
(
messageId
:
string
,
newMessageItem
:
Partial
<
ConversationMessageItem
>
)
=>
{
emit
(
'updateSpecifyMessageItem'
,
messageId
,
newMessageItem
)
},
})
const
isShowKnowledgeContent
=
ref
(
false
)
const
isShowKnowledgeContent
=
ref
(
false
)
const
currentKnowledgeContentResult
=
ref
<
KnowledgeContentResultItem
[]
>
([])
const
currentKnowledgeContentResult
=
ref
<
KnowledgeContentResultItem
[]
>
([])
...
@@ -70,7 +77,7 @@ function handleShowKnowledgeResult(knowledgeContentResult: KnowledgeContentResul
...
@@ -70,7 +77,7 @@ function handleShowKnowledgeResult(knowledgeContentResult: KnowledgeContentResul
<MessageItem
<MessageItem
v-for=
"[key, messageItem] in messageList"
v-for=
"[key, messageItem] in messageList"
:key=
"key"
:key=
"key"
:
role=
"messageItem.role
"
:
message-item-id=
"key
"
:message-item=
"messageItem"
:message-item=
"messageItem"
@
audio-play=
"() => $emit('audioPlay', messageItem)"
@
audio-play=
"() => $emit('audioPlay', messageItem)"
@
audio-pause=
"() => $emit('audioPause')"
@
audio-pause=
"() => $emit('audioPause')"
...
...
src/views/personal-space/personal-app-setting/components/agent-config/agent-preview/components/smart-forms/components/business-trip-form.vue
0 → 100644
View file @
edafe38c
This diff is collapsed.
Click to expand it.
src/views/personal-space/personal-app-setting/components/agent-config/agent-preview/components/smart-forms/components/business-trip-reimbursement-form.vue
0 → 100644
View file @
edafe38c
<
script
setup
lang=
"ts"
>
import
{
readonly
,
ref
}
from
'vue'
import
MarkdownRender
from
'@/components/markdown-render/markdown-render.vue'
import
type
{
FormRules
}
from
'naive-ui'
import
CustomLoading
from
'../../custom-loading.vue'
interface
Props
{
isAgentMessage
:
boolean
messageItem
:
ConversationMessageItem
currentBubbleTextColor
:
string
}
defineProps
<
Props
>
()
const
formRules
=
readonly
<
FormRules
>
({
objective
:
{
required
:
true
,
trigger
:
[
'blur'
,
'input'
],
message
:
''
,
},
travelLocation
:
{
required
:
true
,
trigger
:
[
'blur'
,
'input'
],
message
:
''
,
},
departureTime
:
{
required
:
true
,
trigger
:
[
'blur'
,
'input'
],
message
:
''
,
},
returnTime
:
{
required
:
true
,
trigger
:
[
'blur'
,
'input'
],
message
:
''
,
},
email
:
{
required
:
true
,
trigger
:
[
'blur'
,
'input'
],
message
:
''
,
},
})
const
formModel
=
ref
({
objective
:
'khbf'
,
travelLocation
:
''
,
departureTime
:
null
,
returnTime
:
null
,
vehicle
:
''
,
vehicleEstimatedCost
:
''
,
residence
:
''
,
residenceEstimatedCost
:
''
,
estimatedAmount
:
''
,
generalBudget
:
''
,
email
:
''
,
})
const
objectiveOptions
=
readonly
([
{
label
:
'客户拜访'
,
value
:
'khbf'
,
},
{
label
:
'会议'
,
value
:
'hy'
,
},
{
label
:
'培训'
,
value
:
'px'
,
},
])
</
script
>
<
template
>
<div
class=
"ml-[11px] overflow-hidden"
>
<div
class=
"mb-[7px] text-[12px] text-[#999]"
>
作者信息
</div>
<div
class=
"min-w-[420px]"
>
<div
class=
"box-content min-h-[21px] min-w-[10px] max-w-full rounded-[10px] border border-[#9EA3FF] bg-[#777EF9] px-[15px] py-[14px] text-justify"
:class=
"
{
'!bg-[#fff]': isAgentMessage,
'!min-w-[80px]': messageItem.isAnswerResponseLoading,
}"
>
<div
v-if=
"messageItem.isAnswerResponseLoading && !messageItem.textContent"
class=
"flex h-[21px] items-center justify-center"
>
<CustomLoading
:active-color=
"currentBubbleTextColor"
/>
</div>
<template
v-else
>
<div
class=
"mb-[10px]"
>
<i
class=
"iconfont icon-tongyi font-600 text-[14px] text-[#6ccb59]"
></i>
<span
class=
"ml-[5px] text-[14px] text-[#999]"
>
出差表单插件执行成功
</span>
</div>
<MarkdownRender
ref=
"markdownRenderRef"
raw-text-content=
"好的,我将为您自动生成出差表单,表单如下"
:color=
"currentBubbleTextColor"
/>
<!--
<div
v-if=
"messageItem.isAnswerLoading"
class=
"ml-[15px] pt-[12px]"
>
<CustomLoading
active-color=
"#fff"
width=
"5px"
/>
</div>
-->
</
template
>
</div>
<div
class=
"mt-[10px] box-content min-h-[21px] min-w-[10px] max-w-full rounded-[10px] border border-[#9EA3FF] bg-[#777EF9] px-[15px] py-[14px] text-justify"
:class=
"{
'!bg-[#fff]': isAgentMessage,
}"
>
<h2
class=
"font-600 text-[15px] text-[#0B7DFF]"
>
出差表单
</h2>
<div
class=
"mt-[12px]"
>
<n-form
:model=
"formModel"
:rules=
"formRules"
label-width=
"90"
label-placement=
"left"
:show-feedback=
"false"
>
<n-form-item
class=
"mb-[10px]"
label=
"出差目的"
path=
"objective"
>
<n-select
v-model:value=
"formModel.objective"
placeholder=
"Select"
:options=
"objectiveOptions"
/>
</n-form-item>
<n-form-item
class=
"mb-[10px]"
label=
"出差地点"
path=
"travelLocation"
>
<n-input
v-model:value=
"formModel.travelLocation"
placeholder=
"Input"
/>
</n-form-item>
<n-form-item
class=
"mb-[10px]"
label=
"出发时间"
path=
"departureTime"
>
<n-date-picker
v-model:value=
"formModel.departureTime"
type=
"datetime"
/>
</n-form-item>
<n-form-item
label=
"返回时间"
path=
"returnTime"
>
<n-date-picker
v-model:value=
"formModel.returnTime"
type=
"datetime"
/>
</n-form-item>
<n-form-item
label=
""
>
<div
class=
"h-[1px] w-full bg-[#B1B1B1] opacity-45"
></div>
</n-form-item>
<n-form-item
class=
"mb-[10px]"
label=
"交通工具"
path=
"vehicle"
>
<n-input
v-model:value=
"formModel.vehicle"
placeholder=
"Input"
/>
</n-form-item>
<n-form-item
label=
"预计费用"
path=
"vehicleEstimatedCost"
>
<n-input
v-model:value=
"formModel.vehicleEstimatedCost"
placeholder=
"Input"
/>
</n-form-item>
<n-form-item
label=
""
>
<div
class=
"h-[1px] w-full bg-[#B1B1B1] opacity-45"
></div>
</n-form-item>
<n-form-item
class=
"mb-[10px]"
label=
"住宿地点"
path=
"residence"
>
<n-input
v-model:value=
"formModel.residence"
placeholder=
"Input"
/>
</n-form-item>
<n-form-item
label=
"预计费用"
path=
"residenceEstimatedCost"
>
<n-input
v-model:value=
"formModel.residenceEstimatedCost"
placeholder=
"Input"
/>
</n-form-item>
<n-form-item
label=
""
>
<div
class=
"h-[1px] w-full bg-[#B1B1B1] opacity-45"
></div>
</n-form-item>
<n-form-item
class=
"mb-[10px]"
label=
"预计金额"
path=
"residence"
>
<n-input
v-model:value=
"formModel.estimatedAmount"
placeholder=
"Input"
/>
</n-form-item>
<n-form-item
label=
"总预算"
path=
"generalBudget"
>
<n-input
v-model:value=
"formModel.generalBudget"
placeholder=
"Input"
/>
</n-form-item>
<n-form-item
label=
""
>
<div
class=
"h-[1px] w-full bg-[#B1B1B1] opacity-45"
></div>
</n-form-item>
<n-form-item
class=
"mb-[10px]"
label=
"邮箱信息"
path=
"email"
>
<n-input
v-model:value=
"formModel.email"
placeholder=
"Input"
/>
</n-form-item>
<div
class=
"mt-[30px] text-end"
>
<n-button
type=
"primary"
>
确认提交
</n-button>
</div>
</n-form>
</div>
</div>
</div>
</div>
</template>
src/views/personal-space/personal-app-setting/components/agent-config/agent-preview/components/smart-forms/index.vue
0 → 100644
View file @
edafe38c
<
script
setup
lang=
"ts"
>
import
BusinessTripForm
from
'./components/business-trip-form.vue'
// import BusinessTripReimbursementForm from './business-trip-reimbursement-form.vue'
interface
Props
{
isAgentMessage
:
boolean
messageAuthor
:
string
messageItem
:
ConversationMessageItem
currentBubbleTextColor
:
string
}
defineProps
<
Props
>
()
</
script
>
<
template
>
<BusinessTripForm
:message-item=
"messageItem"
:is-agent-message=
"isAgentMessage"
:message-author=
"messageAuthor"
:current-bubble-text-color=
"currentBubbleTextColor"
/>
<!--
<BusinessTripReimbursementForm
:is-agent-message=
"isAgentMessage"
:message-item=
"messageItem"
:current-bubble-text-color=
"currentBubbleTextColor"
/>
-->
</
template
>
src/views/personal-space/personal-app-setting/components/agent-config/agent-preview/components/smart-forms/types/types.d.ts
0 → 100644
View file @
edafe38c
export
interface
ResponseBusinessTripForm
{
purpose
:
string
place
:
string
departureDate
:
string
returnDate
:
string
vehicle
:
string
transportationFee
:
string
accommodation
:
string
accommodationCost
:
string
advancePaymentAmount
:
string
totalBudget
:
string
}
export
interface
BusinessTripForm
{
objective
:
string
travelLocation
:
string
departureTime
:
number
|
null
returnTime
:
number
|
null
vehicle
:
string
vehicleEstimatedCost
:
number
|
null
residence
:
string
residenceEstimatedCost
:
number
|
null
advancePaymentAmount
:
number
|
null
generalBudget
:
string
email
:
string
}
export
type
SmartFormDisplayFormat
=
'travelForm'
src/views/personal-space/personal-app-setting/components/agent-config/agent-preview/components/smart-forms/utils/smart-forms.ts
0 → 100644
View file @
edafe38c
import
type
{
SmartFormTypes
}
from
'../../../../types'
import
{
BusinessTripForm
,
ResponseBusinessTripForm
}
from
'../types/types'
export
function
smartFormTypeConverter
(
type
:
'travelForm'
):
SmartFormTypes
{
switch
(
type
)
{
case
'travelForm'
:
return
'BusinessTripForm'
}
}
export
function
businessTripFormParser
(
resForm
:
Partial
<
ResponseBusinessTripForm
>
)
{
return
{
objective
:
resForm
.
purpose
||
'CustomerVisits'
,
travelLocation
:
resForm
.
place
||
''
,
departureTime
:
resForm
.
departureDate
?
Date
.
parse
(
resForm
.
departureDate
)
:
null
,
returnTime
:
resForm
.
returnDate
?
Date
.
parse
(
resForm
.
returnDate
)
:
null
,
vehicle
:
resForm
.
vehicle
||
''
,
vehicleEstimatedCost
:
resForm
.
transportationFee
?
Number
.
parseInt
(
resForm
.
transportationFee
)
:
null
,
residence
:
resForm
.
accommodation
||
''
,
residenceEstimatedCost
:
resForm
.
accommodationCost
?
Number
.
parseInt
(
resForm
.
accommodationCost
)
:
null
,
advancePaymentAmount
:
resForm
.
advancePaymentAmount
?
Number
.
parseInt
(
resForm
.
advancePaymentAmount
)
:
null
,
generalBudget
:
resForm
.
totalBudget
||
''
,
email
:
''
,
}
}
export
function
businessTripFormReturner
(
form
:
BusinessTripForm
)
{
return
{
purpose
:
form
.
objective
,
place
:
form
.
travelLocation
,
departureDate
:
form
.
departureTime
?
new
Date
(
form
.
departureTime
).
toISOString
()
:
''
,
returnDate
:
form
.
returnTime
?
new
Date
(
form
.
returnTime
).
toISOString
()
:
''
,
vehicle
:
form
.
vehicle
,
transportationFee
:
form
.
vehicleEstimatedCost
,
accommodation
:
form
.
residence
,
accommodationCost
:
form
.
residenceEstimatedCost
,
advancePaymentAmount
:
form
.
advancePaymentAmount
,
totalBudget
:
form
.
generalBudget
,
email
:
form
.
email
,
}
}
src/views/personal-space/personal-app-setting/components/agent-config/types.d.ts
View file @
edafe38c
...
@@ -10,3 +10,5 @@ export interface TimbreLanguageInfoItem {
...
@@ -10,3 +10,5 @@ export interface TimbreLanguageInfoItem {
matchLang
:
string
matchLang
:
string
timbreInfo
:
TimbreInfoItem
[]
timbreInfo
:
TimbreInfoItem
[]
}
}
export
type
SmartFormTypes
=
'BusinessTripForm'
src/views/share/components/footer-input.vue
View file @
edafe38c
...
@@ -13,6 +13,9 @@ import { useLayoutConfig } from '@/composables/useLayoutConfig'
...
@@ -13,6 +13,9 @@ import { useLayoutConfig } from '@/composables/useLayoutConfig'
import
{
TEXTTOSPEECH_WS_URL
}
from
'@/config/base-url'
import
{
TEXTTOSPEECH_WS_URL
}
from
'@/config/base-url'
import
WebSocketCtr
from
'@/utils/web-socket-ctr'
import
WebSocketCtr
from
'@/utils/web-socket-ctr'
import
{
ChannelType
}
from
'@/enums/channel'
import
{
ChannelType
}
from
'@/enums/channel'
import
{
smartFormTypeConverter
}
from
'@/views/personal-space/personal-app-setting/components/agent-config/agent-preview/components/smart-forms/utils/smart-forms'
import
{
SmartFormTypes
}
from
'@/views/personal-space/personal-app-setting/components/agent-config/types'
import
{
SmartFormDisplayFormat
}
from
'@/views/personal-space/personal-app-setting/components/agent-config/agent-preview/components/smart-forms/types/types'
interface
Props
{
interface
Props
{
agentId
:
string
agentId
:
string
...
@@ -43,6 +46,7 @@ const emit = defineEmits<{
...
@@ -43,6 +46,7 @@ const emit = defineEmits<{
resetContinueQuestionList
:
[]
resetContinueQuestionList
:
[]
audioPlay
:
[
messageItem
:
ConversationMessageItem
,
requestId
?:
string
]
audioPlay
:
[
messageItem
:
ConversationMessageItem
,
requestId
?:
string
]
audioPause
:
[]
audioPause
:
[]
smartFormsStatusFreezeCheck
:
[
value
:
SmartFormTypes
]
}
>
()
}
>
()
const
{
isMobile
}
=
useLayoutConfig
()
const
{
isMobile
}
=
useLayoutConfig
()
...
@@ -63,6 +67,7 @@ const sentenceExtractCheckEnabled = ref(false)
...
@@ -63,6 +67,7 @@ const sentenceExtractCheckEnabled = ref(false)
const
assistantFullAnswerContent
=
ref
(
''
)
const
assistantFullAnswerContent
=
ref
(
''
)
const
sentenceSpeechException
=
ref
(
false
)
const
sentenceSpeechException
=
ref
(
false
)
const
messageAudioLoading
=
ref
(
false
)
const
messageAudioLoading
=
ref
(
false
)
const
isSmartFormPlugins
=
ref
(
false
)
const
currentLatestMessageItemKeyMap
=
ref
(
new
Map
<
'assistant'
|
'user'
,
string
>
())
const
currentLatestMessageItemKeyMap
=
ref
(
new
Map
<
'assistant'
|
'user'
,
string
>
())
let
controller
:
AbortController
|
null
=
null
let
controller
:
AbortController
|
null
=
null
...
@@ -221,6 +226,7 @@ function handleMessageSend(lastQuestionContent?: string) {
...
@@ -221,6 +226,7 @@ function handleMessageSend(lastQuestionContent?: string) {
assistantFullAnswerContent
.
value
=
''
assistantFullAnswerContent
.
value
=
''
sentenceSpeechException
.
value
=
false
sentenceSpeechException
.
value
=
false
messageAudioLoading
.
value
=
false
messageAudioLoading
.
value
=
false
isSmartFormPlugins
.
value
=
false
controller
=
new
AbortController
()
controller
=
new
AbortController
()
...
@@ -246,6 +252,31 @@ function handleMessageSend(lastQuestionContent?: string) {
...
@@ -246,6 +252,31 @@ function handleMessageSend(lastQuestionContent?: string) {
// 插件
// 插件
if
(
data
.
function
&&
data
.
function
.
name
)
{
if
(
data
.
function
&&
data
.
function
.
name
)
{
// 表单插件,展示表单内容
if
([
'travelForm'
].
includes
(
data
.
function
.
displayFormat
))
{
emit
(
'smartFormsStatusFreezeCheck'
,
smartFormTypeConverter
(
data
.
function
.
displayFormat
as
SmartFormDisplayFormat
),
)
emit
(
'updateSpecifyMessageItem'
,
latestAssistantMessageKey
,
{
pluginResult
:
{
displayFormat
:
data
.
function
.
displayFormat
,
pluginName
:
data
.
function
.
name
,
arguments
:
data
.
function
.
arguments
,
pluginContent
:
data
.
function
.
result
,
},
smartFormInfo
:
{
type
:
smartFormTypeConverter
(
data
.
function
.
displayFormat
as
SmartFormDisplayFormat
),
isDisabled
:
false
,
params
:
data
.
function
.
result
,
},
})
emit
(
'updatePageScroll'
)
isSmartFormPlugins
.
value
=
true
return
}
emit
(
'updateSpecifyMessageItem'
,
latestAssistantMessageKey
,
{
emit
(
'updateSpecifyMessageItem'
,
latestAssistantMessageKey
,
{
pluginResult
:
{
pluginResult
:
{
displayFormat
:
data
.
function
.
displayFormat
,
displayFormat
:
data
.
function
.
displayFormat
,
...
@@ -280,7 +311,7 @@ function handleMessageSend(lastQuestionContent?: string) {
...
@@ -280,7 +311,7 @@ function handleMessageSend(lastQuestionContent?: string) {
''
,
''
,
)
)
if
(
!
sentenceExtractCheckEnabled
.
value
&&
props
.
isEnableVoice
)
{
if
(
!
sentenceExtractCheckEnabled
.
value
&&
props
.
isEnableVoice
&&
!
isSmartFormPlugins
.
value
)
{
sentenceExtract
(
latestAssistantMessageKey
)
sentenceExtract
(
latestAssistantMessageKey
)
sentenceExtractCheckEnabled
.
value
=
true
sentenceExtractCheckEnabled
.
value
=
true
messageAudioLoading
.
value
=
true
messageAudioLoading
.
value
=
true
...
...
src/views/share/components/message-item.vue
View file @
edafe38c
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
computed
,
ref
,
useTemplateRef
}
from
'vue'
import
{
computed
,
provide
,
readonly
,
ref
,
useTemplateRef
}
from
'vue'
import
{
useI18n
}
from
'vue-i18n'
import
{
useI18n
}
from
'vue-i18n'
import
{
throttle
}
from
'lodash-es'
import
{
throttle
}
from
'lodash-es'
import
{
Down
}
from
'@icon-park/vue-next'
import
{
Down
}
from
'@icon-park/vue-next'
...
@@ -13,9 +13,10 @@ import { PersonalAppConfigState } from '@/store/types/personal-app-config'
...
@@ -13,9 +13,10 @@ import { PersonalAppConfigState } from '@/store/types/personal-app-config'
import
{
useLayoutConfig
}
from
'@/composables/useLayoutConfig'
import
{
useLayoutConfig
}
from
'@/composables/useLayoutConfig'
import
{
useUserStore
}
from
'@/store/modules/user'
import
{
useUserStore
}
from
'@/store/modules/user'
import
{
copyToClip
}
from
'@/utils/copy'
import
{
copyToClip
}
from
'@/utils/copy'
import
SmartForms
from
'@/views/personal-space/personal-app-setting/components/agent-config/agent-preview/components/smart-forms/index.vue'
interface
Props
{
interface
Props
{
role
:
'user'
|
'assistant'
messageItemId
:
string
messageItem
:
ConversationMessageItem
messageItem
:
ConversationMessageItem
agentApplicationConfig
:
PersonalAppConfigState
agentApplicationConfig
:
PersonalAppConfigState
}
}
...
@@ -35,10 +36,14 @@ const { isMobile } = useLayoutConfig()
...
@@ -35,10 +36,14 @@ const { isMobile } = useLayoutConfig()
const
markdownRenderRef
=
useTemplateRef
<
InstanceType
<
typeof
MarkdownRender
>>
(
'markdownRenderRef'
)
const
markdownRenderRef
=
useTemplateRef
<
InstanceType
<
typeof
MarkdownRender
>>
(
'markdownRenderRef'
)
provide
(
'messageItemId'
,
props
.
messageItemId
)
const
isShowReasoningContent
=
ref
(
true
)
const
isShowReasoningContent
=
ref
(
true
)
const
isShowEditorDrawer
=
ref
(
false
)
const
isShowEditorDrawer
=
ref
(
false
)
const
editorDrawerContent
=
ref
(
''
)
const
editorDrawerContent
=
ref
(
''
)
const
displaySmartFormsList
=
readonly
([
'travelForm'
])
const
useAvatar
=
computed
(()
=>
{
const
useAvatar
=
computed
(()
=>
{
return
userStore
.
userInfo
.
avatarUrl
||
'https://gsst-poe-sit.gz.bcebos.com/data/20240910/1725952917468.png'
return
userStore
.
userInfo
.
avatarUrl
||
'https://gsst-poe-sit.gz.bcebos.com/data/20240910/1725952917468.png'
})
})
...
@@ -50,12 +55,31 @@ const assistantAvatar = computed(() => {
...
@@ -50,12 +55,31 @@ const assistantAvatar = computed(() => {
)
)
})
})
const
isAgentMessage
=
computed
(()
=>
{
return
props
.
messageItem
.
role
===
'assistant'
})
const
currentBubbleTextColor
=
computed
(()
=>
{
return
isAgentMessage
.
value
?
'#192338'
:
'#fff'
})
const
isShowSmartForms
=
computed
(()
=>
{
if
(
props
.
messageItem
?.
pluginResult
?.
displayFormat
)
{
return
displaySmartFormsList
.
includes
(
props
.
messageItem
?.
pluginResult
?.
displayFormat
)
}
return
false
})
const
messageAuthor
=
computed
(()
=>
{
return
isAgentMessage
.
value
?
props
.
messageItem
.
modelName
||
'AI'
:
userStore
.
userInfo
.
nickName
})
const
timbreEnabled
=
computed
(()
=>
{
const
timbreEnabled
=
computed
(()
=>
{
return
!!
props
.
agentApplicationConfig
.
voiceConfig
.
timbreId
return
!!
props
.
agentApplicationConfig
.
voiceConfig
.
timbreId
})
})
const
isShowAudioControl
=
computed
(()
=>
{
const
isShowAudioControl
=
computed
(()
=>
{
return
props
.
role
===
'assistant'
&&
!
props
.
messageItem
.
isVoiceLoading
&&
timbreEnabled
.
value
return
isAgentMessage
.
value
&&
!
props
.
messageItem
.
isVoiceLoading
&&
timbreEnabled
.
value
})
})
const
isPlayableAudio
=
computed
(()
=>
{
const
isPlayableAudio
=
computed
(()
=>
{
...
@@ -64,7 +88,7 @@ const isPlayableAudio = computed(() => {
...
@@ -64,7 +88,7 @@ const isPlayableAudio = computed(() => {
const
isShowVoiceLoading
=
computed
(()
=>
{
const
isShowVoiceLoading
=
computed
(()
=>
{
return
(
return
(
props
.
role
===
'assistant'
&&
isAgentMessage
.
value
&&
(
props
.
messageItem
.
isAnswerResponseLoading
||
(
props
.
messageItem
.
isVoiceLoading
&&
timbreEnabled
.
value
))
(
props
.
messageItem
.
isAnswerResponseLoading
||
(
props
.
messageItem
.
isVoiceLoading
&&
timbreEnabled
.
value
))
)
)
})
})
...
@@ -113,14 +137,11 @@ const handleContentCopy = throttle(
...
@@ -113,14 +137,11 @@ const handleContentCopy = throttle(
<
template
>
<
template
>
<div
<div
class=
"mb-5 flex last:mb-0"
class=
"mb-5 flex last:mb-0"
:class=
"[
:class=
"[isMobile ? 'flex-row-reverse' : 'flex-row', isAgentMessage && isMobile ? 'justify-end' : 'justify-start']"
isMobile ? 'flex-row-reverse' : 'flex-row',
role === 'assistant' && isMobile ? 'justify-end' : 'justify-start',
]"
>
>
<NImage
<NImage
v-show=
"!isMobile"
v-show=
"!isMobile"
:src=
"
role === 'user' ? useAvatar : assistant
Avatar"
:src=
"
isAgentMessage ? assistantAvatar : use
Avatar"
preview-disabled
preview-disabled
:width=
"32"
:width=
"32"
:height=
"32"
:height=
"32"
...
@@ -129,11 +150,12 @@ const handleContentCopy = throttle(
...
@@ -129,11 +150,12 @@ const handleContentCopy = throttle(
/>
/>
<div
<div
v-if=
"!isShowSmartForms"
class=
"flex flex-col overflow-x-auto"
class=
"flex flex-col overflow-x-auto"
:class=
"[isMobile &&
role === 'user'
? 'items-end' : 'items-start', isMobile ? 'w-full' : '']"
:class=
"[isMobile &&
!isAgentMessage
? 'items-end' : 'items-start', isMobile ? 'w-full' : '']"
>
>
<!-- 大模型深度思考 -->
<!-- 大模型深度思考 -->
<template
v-if=
"
role === 'assistant'
&& isDeepSeekR1"
>
<template
v-if=
"
isAgentMessage
&& isDeepSeekR1"
>
<div
class=
"my-[7px] select-none text-[14px]"
>
<div
class=
"my-[7px] select-none text-[14px]"
>
<div
class=
"inline-flex cursor-pointer"
@
click=
"handleShowReasoningContentSwitch"
>
<div
class=
"inline-flex cursor-pointer"
@
click=
"handleShowReasoningContentSwitch"
>
<span
v-if=
"messageItem.isTextContentLoading"
class=
"mr-[6px]"
>
<span
v-if=
"messageItem.isTextContentLoading"
class=
"mr-[6px]"
>
...
@@ -174,17 +196,17 @@ const handleContentCopy = throttle(
...
@@ -174,17 +196,17 @@ const handleContentCopy = throttle(
<!--
模型内容
-->
<!--
模型内容
-->
<
div
class
=
"flex min-w-[80px] flex-col"
:
class
=
"[isMobile ? 'max-w-[calc(100%-20px)]' : 'max-w-full']"
>
<
div
class
=
"flex min-w-[80px] flex-col"
:
class
=
"[isMobile ? 'max-w-[calc(100%-20px)]' : 'max-w-full']"
>
<
div
<
div
class
=
"w-full flex-wrap rounded-xl border border-[#
e8e9eb
] px-4 py-[11px]"
class
=
"w-full flex-wrap rounded-xl border border-[#
9EA3FF
] px-4 py-[11px]"
:
class
=
"[
role === 'user' ? 'user-content-container bg-[#777EF9] text-white' : 'bg-white text-[#333]
']"
:
class
=
"[
isAgentMessage ? 'bg-white text-[#333]' : 'user-content-container bg-[#777EF9] text-white
']"
>
>
<
img
<
img
v
-
show
=
"
role === 'user'
&& messageItem.imageUrl"
v
-
show
=
"
!isAgentMessage
&& messageItem.imageUrl"
:
src
=
"messageItem.imageUrl"
:
src
=
"messageItem.imageUrl"
class
=
"max-h-[120px]! mb-[11px] rounded-[10px] object-contain"
class
=
"max-h-[120px]! mb-[11px] rounded-[10px] object-contain"
/>
/>
<!--
插件返回结果
-->
<!--
插件返回结果
-->
<
div
v
-
show
=
"
role === 'assistant'
&& messageItem?.pluginResult?.pluginName"
class
=
"mb-[11px] w-full"
>
<
div
v
-
show
=
"
isAgentMessage
&& messageItem?.pluginResult?.pluginName"
class
=
"mb-[11px] w-full"
>
<
ExecutePluginRender
<
ExecutePluginRender
:
display
-
format
=
"messageItem.pluginResult?.displayFormat || 'none'"
:
display
-
format
=
"messageItem.pluginResult?.displayFormat || 'none'"
:
name
=
"messageItem.pluginResult?.pluginName!"
:
name
=
"messageItem.pluginResult?.pluginName!"
...
@@ -215,7 +237,7 @@ const handleContentCopy = throttle(
...
@@ -215,7 +237,7 @@ const handleContentCopy = throttle(
? t('common_module.dialogue_module.empty_message_content')
? t('common_module.dialogue_module.empty_message_content')
: messageItem.textContent
: messageItem.textContent
"
"
:
color
=
"
role === 'user' ? '#fff' : '#192338'
"
:
color
=
"
currentBubbleTextColor
"
/>
/>
<
/p
>
<
/p
>
...
@@ -280,7 +302,7 @@ const handleContentCopy = throttle(
...
@@ -280,7 +302,7 @@ const handleContentCopy = throttle(
<
div
><
/div
>
<
div
><
/div
>
<
div
<
div
v
-
show
=
"
role === 'assistant'
&& messageItem.textContent && !messageItem.isAnswerResponseLoading"
v
-
show
=
"
isAgentMessage
&& messageItem.textContent && !messageItem.isAnswerResponseLoading"
class
=
"py-[10px] pr-[14px] text-end"
class
=
"py-[10px] pr-[14px] text-end"
>
>
<
i
<
i
...
@@ -295,6 +317,14 @@ const handleContentCopy = throttle(
...
@@ -295,6 +317,14 @@ const handleContentCopy = throttle(
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
SmartForms
v
-
else
:
message
-
author
=
"messageAuthor"
:
is
-
agent
-
message
=
"isAgentMessage"
:
message
-
item
=
"messageItem"
:
current
-
bubble
-
text
-
color
=
"currentBubbleTextColor"
/>
<
/div
>
<
/div
>
<
EditorDrawer
v
-
model
:
is
-
show
-
editor
-
drawer
=
"isShowEditorDrawer"
v
-
model
:
content
-
edit
=
"editorDrawerContent"
/>
<
EditorDrawer
v
-
model
:
is
-
show
-
editor
-
drawer
=
"isShowEditorDrawer"
v
-
model
:
content
-
edit
=
"editorDrawerContent"
/>
...
...
src/views/share/components/message-list.vue
View file @
edafe38c
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
computed
,
nextTick
,
useTemplateRef
,
watch
}
from
'vue'
import
{
computed
,
nextTick
,
provide
,
useTemplateRef
,
watch
}
from
'vue'
import
{
useI18n
}
from
'vue-i18n'
import
{
useI18n
}
from
'vue-i18n'
import
{
useElementVisibility
}
from
'@vueuse/core'
import
{
useElementVisibility
}
from
'@vueuse/core'
import
MessageItem
from
'./message-item.vue'
import
MessageItem
from
'./message-item.vue'
...
@@ -20,9 +20,10 @@ interface Props {
...
@@ -20,9 +20,10 @@ interface Props {
const
props
=
defineProps
<
Props
>
()
const
props
=
defineProps
<
Props
>
()
defineEmits
<
{
const
emit
=
defineEmits
<
{
audioPlay
:
[
messageItem
:
ConversationMessageItem
]
audioPlay
:
[
messageItem
:
ConversationMessageItem
]
audioPause
:
[]
audioPause
:
[]
updateSpecifyMessageItem
:
[
messageId
:
string
,
newMessageItem
:
Partial
<
ConversationMessageItem
>
]
}
>
()
}
>
()
const
{
t
}
=
useI18n
()
const
{
t
}
=
useI18n
()
...
@@ -33,6 +34,12 @@ const { scrollRef, scrollToBottom } = useScroll()
...
@@ -33,6 +34,12 @@ const { scrollRef, scrollToBottom } = useScroll()
const
backBottomBtnFlagRef
=
useTemplateRef
<
HTMLDivElement
|
null
>
(
'backBottomBtnFlagRef'
)
const
backBottomBtnFlagRef
=
useTemplateRef
<
HTMLDivElement
|
null
>
(
'backBottomBtnFlagRef'
)
const
isNotShowBackBottomBtn
=
useElementVisibility
(
backBottomBtnFlagRef
)
const
isNotShowBackBottomBtn
=
useElementVisibility
(
backBottomBtnFlagRef
)
provide
(
'updateSpecifyMessageItem'
,
{
updateSpecifyMessageItem
:
(
messageId
:
string
,
newMessageItem
:
Partial
<
ConversationMessageItem
>
)
=>
{
emit
(
'updateSpecifyMessageItem'
,
messageId
,
newMessageItem
)
},
})
const
isShowContinueQuestion
=
computed
(()
=>
{
const
isShowContinueQuestion
=
computed
(()
=>
{
return
(
return
(
props
.
continuousQuestionStatus
===
'default'
&&
props
.
continuousQuestionStatus
===
'default'
&&
...
@@ -71,7 +78,7 @@ function handleScrollToBottom() {
...
@@ -71,7 +78,7 @@ function handleScrollToBottom() {
<MessageItem
<MessageItem
v-for=
"[key, messageItem] in messageList"
v-for=
"[key, messageItem] in messageList"
:key=
"key"
:key=
"key"
:
role=
"messageItem.role
"
:
message-item-id=
"key
"
:message-item=
"messageItem"
:message-item=
"messageItem"
:agent-application-config=
"agentApplicationConfig"
:agent-application-config=
"agentApplicationConfig"
@
audio-play=
"() => $emit('audioPlay', messageItem)"
@
audio-play=
"() => $emit('audioPlay', messageItem)"
...
...
src/views/share/share-application-web.vue
View file @
edafe38c
...
@@ -22,6 +22,7 @@ import { useLayoutConfig } from '@/composables/useLayoutConfig'
...
@@ -22,6 +22,7 @@ import { useLayoutConfig } from '@/composables/useLayoutConfig'
import
{
fetchGetMemberInfoById
}
from
'@/apis/user'
import
{
fetchGetMemberInfoById
}
from
'@/apis/user'
import
{
UserInfo
}
from
'@/store/types/user'
import
{
UserInfo
}
from
'@/store/types/user'
import
{
validBrowser
}
from
'@/utils/browser-detection'
import
{
validBrowser
}
from
'@/utils/browser-detection'
import
{
SmartFormTypes
}
from
'../personal-space/personal-app-setting/components/agent-config/types'
const
{
t
}
=
useI18n
()
const
{
t
}
=
useI18n
()
...
@@ -177,9 +178,7 @@ function handleUpdateSpecifyMessageItem(messageId: string, newMessageItem: Parti
...
@@ -177,9 +178,7 @@ function handleUpdateSpecifyMessageItem(messageId: string, newMessageItem: Parti
}
}
Object
.
entries
<
ValueOf
<
typeof
newMessageItem
>>
(
newMessageItem
).
forEach
(([
key
,
value
])
=>
{
Object
.
entries
<
ValueOf
<
typeof
newMessageItem
>>
(
newMessageItem
).
forEach
(([
key
,
value
])
=>
{
if
(
Object
.
prototype
.
hasOwnProperty
.
call
(
currentMessageItemInfo
,
key
))
{
;(
currentMessageItemInfo
as
any
)[
key
as
keyof
ConversationMessageItem
]
=
value
;(
currentMessageItemInfo
as
any
)[
key
as
keyof
ConversationMessageItem
]
=
value
}
})
})
}
}
}
}
...
@@ -313,6 +312,17 @@ function handleAudioPause(isClearMessageList = false) {
...
@@ -313,6 +312,17 @@ function handleAudioPause(isClearMessageList = false) {
footerInputRef
.
value
?.
blockMessageResponse
()
footerInputRef
.
value
?.
blockMessageResponse
()
}
}
}
}
function
onSmartFormsStatusFreezeCheck
(
smartFormType
:
SmartFormTypes
)
{
/* 重置智能表单项目 */
if
(
smartFormType
)
{
messageList
.
value
.
forEach
((
item
)
=>
{
if
(
item
.
smartFormInfo
&&
item
.
smartFormInfo
.
type
===
smartFormType
)
{
item
.
smartFormInfo
.
isDisabled
=
true
}
})
}
}
</
script
>
</
script
>
<
template
>
<
template
>
...
@@ -352,6 +362,7 @@ function handleAudioPause(isClearMessageList = false) {
...
@@ -352,6 +362,7 @@ function handleAudioPause(isClearMessageList = false) {
:create-continue-questions-exception=
"createContinueQuestionsException"
:create-continue-questions-exception=
"createContinueQuestionsException"
@
audio-play=
"handleAudioPlay"
@
audio-play=
"handleAudioPlay"
@
audio-pause=
"handleAudioPause"
@
audio-pause=
"handleAudioPause"
@
update-specify-message-item=
"handleUpdateSpecifyMessageItem"
/>
/>
</div>
</div>
</div>
</div>
...
@@ -380,6 +391,7 @@ function handleAudioPause(isClearMessageList = false) {
...
@@ -380,6 +391,7 @@ function handleAudioPause(isClearMessageList = false) {
@
reset-continue-question-list=
"handleResetContinueQuestionList"
@
reset-continue-question-list=
"handleResetContinueQuestionList"
@
audio-play=
"handleAudioPlay"
@
audio-play=
"handleAudioPlay"
@
audio-pause=
"handleAudioPause"
@
audio-pause=
"handleAudioPause"
@
smart-forms-status-freeze-check=
"onSmartFormsStatusFreezeCheck"
/>
/>
</div>
</div>
</div>
</div>
...
...
types/conversation.d.ts
View file @
edafe38c
...
@@ -12,6 +12,8 @@ declare interface DBChainResultItem {
...
@@ -12,6 +12,8 @@ declare interface DBChainResultItem {
status
:
string
status
:
string
}
}
declare
type
PluginDisplayFormatType
=
'json'
|
'markdown'
|
'none'
|
'travelForm'
declare
interface
ConversationMessageItem
{
declare
interface
ConversationMessageItem
{
timestamp
:
number
timestamp
:
number
role
:
'user'
|
'assistant'
role
:
'user'
|
'assistant'
...
@@ -29,9 +31,14 @@ declare interface ConversationMessageItem {
...
@@ -29,9 +31,14 @@ declare interface ConversationMessageItem {
knowledgeContentResult
:
KnowledgeContentResultItem
[]
knowledgeContentResult
:
KnowledgeContentResultItem
[]
dbChainSQLContent
:
string
dbChainSQLContent
:
string
pluginResult
?:
{
pluginResult
?:
{
displayFormat
:
'json'
|
'markdown'
|
'none'
displayFormat
:
PluginDisplayFormatType
pluginName
:
string
pluginName
:
string
arguments
:
string
arguments
:
string
pluginContent
:
string
pluginContent
:
string
}
}
smartFormInfo
?:
{
type
:
'BusinessTripForm'
|
''
isDisabled
:
boolean
params
:
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