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
a37f91fb
Commit
a37f91fb
authored
May 10, 2025
by
nick zheng
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'beta' into 'master'
Beta See merge request
!224
parents
b423f4db
edafe38c
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
1748 additions
and
119 deletions
+1748
-119
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
message-item.vue
src/views/home/components/message-item.vue
+1
-1
types.d.ts
src/views/home/components/smart-forms/types.d.ts
+26
-0
smart-forms.ts
src/views/home/utils/smart-forms.ts
+40
-0
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 @
a37f91fb
...
@@ -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 @
a37f91fb
...
@@ -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"
>
<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 gap-[6px] overflow-hidden"
>
<div
class=
"flex flex-1 items-center gap-[6px] overflow-hidden"
>
<div
<div
v-show=
"pluginLoading"
v-show=
"pluginLoading"
...
@@ -91,53 +92,55 @@ const parsedMarkdownPluginContent = computed(() => {
...
@@ -91,53 +92,55 @@ const parsedMarkdownPluginContent = computed(() => {
/>
/>
<
/div
>
<
/div
>
<
div
<
n
-
scrollbar
style
=
"max-height: 500px"
:
class
=
"{ 'mt-[10px]': !isFolding
}
"
>
class
=
"flex transform flex-col overflow-x-auto duration-200 ease-in-out"
<
div
:
class
=
"isFolding ? 'h-0 overflow-hidden' : 'h-fit'"
class
=
"flex transform flex-col overflow-x-auto duration-200 ease-in-out"
>
:
class
=
"[isFolding ? 'h-0 overflow-hidden' : 'h-fit', isMobile ? 'px-[3.2vw]' : 'px-[12px]']"
<!--
json
格式
-->
>
<
div
v
-
if
=
"displayFormat === 'json'"
>
<!--
json
格式
-->
<
div
class
=
"mt-[10px]"
>
<
div
v
-
if
=
"displayFormat === 'json'"
>
<
span
<
div
>
class
=
"rounded-theme inline-block bg-[#E8EAFF] text-[#0072FF]"
<
span
:
class
=
"
class
=
"rounded-theme inline-block bg-[#E8EAFF] text-[#0072FF]"
isMobile
:
class
=
"
? 'h-[7.2vw] px-[3.2vw] text-[2.93333vw] leading-[7.2vw]'
isMobile
: 'h-[29px] px-[12px] text-[12px] leading-[29px]'
? 'h-[7.2vw] px-[3.2vw] text-[2.93333vw] leading-[7.2vw]'
"
: 'h-[29px] px-[12px] text-[12px] leading-[29px]'
>
"
{{
t
(
'common_module.input_parameter'
)
}}
>
<
/span
>
{{
t
(
'common_module.input_parameter'
)
}}
<
JsonViewer
:
value
=
"parsedPluginArguments"
:
expand
-
depth
=
"3"
/>
<
/span
>
<
JsonViewer
:
value
=
"parsedPluginArguments"
:
expand
-
depth
=
"3"
/>
<
/div
>
<
div
class
=
"mt-[10px]"
>
<
span
class
=
"rounded-theme inline-block bg-[#E8EAFF] text-[#0072FF]"
:
class
=
"
isMobile
? 'h-[7.2vw] px-[3.2vw] text-[2.93333vw] leading-[7.2vw]'
: 'h-[29px] px-[12px] text-[12px] leading-[29px]'
"
>
{{
t
(
'common_module.output_parameter'
)
}}
<
/span
>
<
JsonViewer
:
value
=
"parsedPluginContent"
:
expand
-
depth
=
"3"
/>
<
/div
>
<
/div
>
<
/div
>
<
div
class
=
"mt-[10px]"
>
<!--
markdown
格式
-->
<
span
<
div
v
-
else
-
if
=
"displayFormat === 'markdown'"
>
class
=
"rounded-theme inline-block bg-[#E8EAFF] text-[#0072FF]"
<
div
>
:
class
=
"
<
MarkdownRender
:
raw
-
text
-
content
=
"parsedMarkdownPluginContent"
:
font
-
size
=
"isMobile ? '3.2vw' : '14px'"
/>
isMobile
<
/div
>
? 'h-[7.2vw] px-[3.2vw] text-[2.93333vw] leading-[7.2vw]'
: 'h-[29px] px-[12px] text-[12px] leading-[29px]'
"
>
{{
t
(
'common_module.output_parameter'
)
}}
<
/span
>
<
JsonViewer
:
value
=
"parsedPluginContent"
:
expand
-
depth
=
"3"
/>
<
/div
>
<
/div
>
<
/div
>
<!--
markdown
格式
-->
<!--
none
格式
-->
<
div
v
-
else
-
if
=
"displayFormat === 'markdown'"
>
<
div
v
-
else
-
if
=
"displayFormat === 'none'"
>
<
div
class
=
"mt-[10px]"
>
<
span
class
=
"text-font-color break-all"
>
{{
content
}}
<
/span
>
<
MarkdownRender
:
raw
-
text
-
content
=
"parsedMarkdownPluginContent"
:
font
-
size
=
"isMobile ? '3.2vw' : '14px'"
/>
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
/n-scrollbar
>
<!--
其他格式
-->
<
div
v
-
else
>
<
span
class
=
"mt-[10px] break-all"
>
{{
content
}}
<
/span
>
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
/template
>
<
/template
>
...
...
src/composables/useEventSource.ts
View file @
a37f91fb
...
@@ -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/home/components/message-item.vue
View file @
a37f91fb
...
@@ -75,7 +75,7 @@ const handleContentEdit = throttle(
...
@@ -75,7 +75,7 @@ const handleContentEdit = throttle(
<div
class=
"flex"
>
<div
class=
"flex"
>
<img
class=
"h-[36px] w-[36px] rounded-[6px] object-cover"
:src=
"avatarUrl"
alt=
"Avatar"
/>
<img
class=
"h-[36px] w-[36px] rounded-[6px] object-cover"
:src=
"avatarUrl"
alt=
"Avatar"
/>
<div
v-if=
"
tru
e"
class=
"ml-[11px] overflow-hidden"
>
<div
v-if=
"
fals
e"
class=
"ml-[11px] overflow-hidden"
>
<AuthorInfo
:is-agent-message=
"isAgentMessage"
:message-item=
"messageItem"
:message-author=
"messageAuthor"
/>
<AuthorInfo
:is-agent-message=
"isAgentMessage"
:message-item=
"messageItem"
:message-author=
"messageAuthor"
/>
<div
<div
...
...
src/views/home/components/smart-forms/types.d.ts
0 → 100644
View file @
a37f91fb
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
}
src/views/home/utils/smart-forms.ts
0 → 100644
View file @
a37f91fb
import
type
{
SmartFormTypes
}
from
'../types'
import
{
ResponseBusinessTripForm
,
BusinessTripForm
}
from
'@/views/home/components/smart-forms/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
,
}
}
src/views/multi-model-dialogue/components/footer-operation.vue
View file @
a37f91fb
...
@@ -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 @
a37f91fb
<
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 @
a37f91fb
<
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 @
a37f91fb
...
@@ -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 @
a37f91fb
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 @
a37f91fb
<
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 @
a37f91fb
<
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 @
a37f91fb
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 @
a37f91fb
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 @
a37f91fb
...
@@ -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 @
a37f91fb
...
@@ -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 @
a37f91fb
...
@@ -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 @
a37f91fb
...
@@ -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 @
a37f91fb
...
@@ -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 @
a37f91fb
<
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 @
a37f91fb
<
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 @
a37f91fb
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 @
a37f91fb
<
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 @
a37f91fb
<
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 @
a37f91fb
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 @
a37f91fb
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 @
a37f91fb
...
@@ -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 @
a37f91fb
...
@@ -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 @
a37f91fb
<
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 @
a37f91fb
<
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 @
a37f91fb
...
@@ -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 @
a37f91fb
...
@@ -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