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
f03284ec
Commit
f03284ec
authored
Sep 18, 2024
by
nick zheng
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: ai生成应用头像及追问问题
parent
e02481b6
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
319 additions
and
137 deletions
+319
-137
agent-application.ts
src/apis/agent-application.ts
+18
-0
upload-photo.vue
src/components/upload-photo/upload-photo.vue
+10
-13
personal-app-config.ts
src/store/types/personal-app-config.ts
+1
-1
app-preview.vue
...nal-space/personal-app-setting/components/app-preview.vue
+34
-1
app-setting.vue
...nal-space/personal-app-setting/components/app-setting.vue
+31
-92
continue-question.vue
...ace/personal-app-setting/components/continue-question.vue
+38
-0
footer-input.vue
...al-space/personal-app-setting/components/footer-input.vue
+15
-3
message-list.vue
...al-space/personal-app-setting/components/message-list.vue
+25
-7
preamble.vue
...rsonal-space/personal-app-setting/components/preamble.vue
+9
-5
continue-question.vue
src/views/share/components/continue-question.vue
+41
-0
footer-input.vue
src/views/share/components/footer-input.vue
+15
-3
message-list.vue
src/views/share/components/message-list.vue
+26
-8
preamble.vue
src/views/share/components/preamble.vue
+1
-1
share-application-mobile.vue
src/views/share/share-application-mobile.vue
+27
-1
share-application-web.vue
src/views/share/share-application-web.vue
+27
-1
mitt-events.d.ts
types/mitt-events.d.ts
+1
-1
No files found.
src/apis/agent-application.ts
View file @
f03284ec
...
...
@@ -69,6 +69,24 @@ export function fetchCreateDialogues<T>(agentId: string) {
return
request
.
post
<
T
>
(
`/agentApplicationRest/createDialogues.json?agentId=
${
agentId
}
`
)
}
/**
* * @param { input: AI回答内容 }
* @returns 生成追问问题
*/
export
function
fetchCreateContinueQuestions
<
T
>
(
payload
:
{
input
:
string
})
{
return
request
.
post
<
T
>
(
'/agentApplicationRest/createContinueQuestions.json'
,
payload
)
}
/**
* * @param { agentTitle: 标题 agentDesc: 描述 }
* @returns AI生成应用头像
*/
export
function
fetchCreateAgentAvatar
<
T
>
(
payload
:
{
agentTitle
:
string
;
agentDesc
:
string
})
{
return
request
.
post
<
T
>
(
'/agentApplicationInfoRest/createAgentApplicationAvatar.json'
,
payload
,
{
timeout
:
120000
,
})
}
/**
* * @param { agentTitle: 标题 agentDesc: 描述 }
* @returns AI生成开场白
...
...
src/components/upload-photo/upload-photo.vue
View file @
f03284ec
...
...
@@ -5,10 +5,11 @@ import { fetchUpload } from '@/apis/upload'
interface
Emit
{
(
e
:
'afterUpload'
,
data
:
UploadFileInfo
[]):
void
(
e
:
'remove'
,
data
:
number
):
void
}
const
props
=
defineProps
({
saveF
ileArr
:
{
f
ileArr
:
{
type
:
Array
,
default
:
()
=>
{
return
[]
...
...
@@ -34,10 +35,9 @@ const fileList = ref<UploadFileInfo[]>([])
const
previewImageUrl
=
ref
(
''
)
const
uploadPhotoRef
=
ref
()
const
imageRef
=
ref
()
const
showImage
=
false
watch
(
()
=>
props
.
saveF
ileArr
,
()
=>
props
.
f
ileArr
,
(
newValue
)
=>
{
fileList
.
value
=
[]
if
(
newValue
?.
length
)
{
...
...
@@ -99,6 +99,10 @@ function handlePreview(file: UploadFileInfo) {
imageRef
.
value
.
click
()
})
}
function
handleRemove
(
options
:
{
file
:
UploadFileInfo
;
fileList
:
UploadFileInfo
[];
index
:
number
})
{
emit
(
'remove'
,
options
.
index
)
}
</
script
>
<
template
>
...
...
@@ -109,14 +113,7 @@ function handlePreview(file: UploadFileInfo) {
:list-type=
"props.fileType"
@
change=
"handleUpload"
@
preview=
"handlePreview"
/>
<NImage
v-show=
"showImage"
ref=
"imageRef"
width=
"100"
:src=
"previewImageUrl"
:show-toolbar=
"false"
:preview-src=
"previewImageUrl"
/>
@
remove=
"handleRemove"
>
</NUpload>
</
template
>
src/store/types/personal-app-config.ts
View file @
f03284ec
...
...
@@ -10,7 +10,7 @@ export interface PersonalAppConfigState {
commConfig
:
{
preamble
:
string
//开场白
featuredQuestions
:
string
[]
//推荐问
continuousQuestionStatus
:
'default'
|
'c
ustomizable'
|
'c
lose'
//追问状态
continuousQuestionStatus
:
'default'
|
'close'
//追问状态
continuousQuestionSystem
:
string
// 追问提示词 customizable时必填
continuousQuestionTurn
:
number
// 追问轮次 1-5 customizable时必填
}
...
...
src/views/personal-space/personal-app-setting/components/app-preview.vue
View file @
f03284ec
...
...
@@ -3,11 +3,20 @@ import { ref } from 'vue'
import
Preamble
from
'./preamble.vue'
import
MessageList
from
'./message-list.vue'
import
FooterInput
from
'./footer-input.vue'
import
{
fetchCreateContinueQuestions
}
from
'@/apis/agent-application'
import
{
usePersonalAppConfigStore
}
from
'@/store/modules/personal-app-config'
const
personalAppConfigStore
=
usePersonalAppConfigStore
()
const
messageListRef
=
ref
<
InstanceType
<
typeof
MessageList
>
|
null
>
(
null
)
const
footerInputRef
=
ref
<
InstanceType
<
typeof
FooterInput
>
|
null
>
(
null
)
const
messageList
=
ref
<
ConversationMessageItem
[]
>
([])
const
continuousQuestionStatus
=
ref
<
'default'
|
'close'
>
(
personalAppConfigStore
.
commConfig
.
continuousQuestionStatus
)
const
continuousQuestionList
=
ref
<
string
[]
>
([])
function
handleAddMessageItem
(
messageItem
:
ConversationMessageItem
)
{
messageList
.
value
.
push
(
messageItem
)
}
...
...
@@ -35,11 +44,26 @@ function handleClearAllMessage() {
negativeText
:
'取消'
,
positiveText
:
'确定'
,
onPositiveClick
:
()
=>
{
footerInputRef
.
value
?.
blockMessageResponse
()
messageList
.
value
=
[]
window
.
$message
.
success
(
'清空成功'
)
},
})
}
async
function
handleCreateContinueQuestions
(
replyTextContent
:
string
)
{
const
res
=
await
fetchCreateContinueQuestions
<
string
[]
>
({
input
:
replyTextContent
})
if
(
res
.
code
===
0
)
{
continuousQuestionList
.
value
=
res
.
data
handleUpdatePageScroll
()
}
}
function
handleUpdateContinueQuestionStatus
(
status
:
'default'
|
'close'
)
{
continuousQuestionStatus
.
value
=
status
continuousQuestionList
.
value
=
[]
}
</
script
>
<
template
>
...
...
@@ -52,17 +76,26 @@ function handleClearAllMessage() {
</div>
<div
v-show=
"messageList.length > 0"
class=
"w-full"
>
<MessageList
ref=
"messageListRef"
:message-list=
"messageList"
/>
<MessageList
ref=
"messageListRef"
:message-list=
"messageList"
:continuous-question-status=
"continuousQuestionStatus"
:continuous-question-list=
"continuousQuestionList"
/>
</div>
</div>
<FooterInput
ref=
"footerInputRef"
:continuous-question-status=
"continuousQuestionStatus"
:message-list=
"messageList"
@
add-message-item=
"handleAddMessageItem"
@
update-specify-message-item=
"handleUpdateSpecifyMessageItem"
@
delete-last-message-item=
"handleDeleteLastMessageItem"
@
update-page-scroll=
"handleUpdatePageScroll"
@
clear-all-message=
"handleClearAllMessage"
@
create-continue-questions=
"handleCreateContinueQuestions"
@
update-continuous-question-status=
"handleUpdateContinueQuestionStatus"
/>
</div>
</
template
>
...
...
src/views/personal-space/personal-app-setting/components/app-setting.vue
View file @
f03284ec
...
...
@@ -3,12 +3,12 @@ import { computed, onMounted, reactive, ref, watch } from 'vue'
import
{
useRouter
}
from
'vue-router'
import
{
SelectOption
,
UploadFileInfo
}
from
'naive-ui'
import
{
useThrottleFn
}
from
'@vueuse/core'
import
AdditionalPromptModal
from
'./additional-prompt-modal.vue'
import
CustomIcon
from
'@/components/custom-icon/custom-icon.vue'
import
UploadPhoto
from
'@/components/upload-photo/upload-photo.vue'
import
{
usePersonalAppConfigStore
}
from
'@/store/modules/personal-app-config'
import
{
PersonalAppConfigState
}
from
'@/store/types/personal-app-config'
import
{
fetchCreateAgentAvatar
,
fetchCreateFeaturedQuestions
,
fetchCreatePreamble
,
fetchGetDebugApplicationInfo
,
...
...
@@ -38,11 +38,6 @@ const questionSettingOptions = [
value
:
'default'
,
style
:
{
fontSize
:
'12px'
},
},
{
label
:
'自定义'
,
value
:
'customizable'
,
style
:
{
fontSize
:
'12px'
},
},
{
label
:
'关闭'
,
value
:
'close'
,
...
...
@@ -54,10 +49,9 @@ const modalListOptions = reactive<SelectOption[]>([])
const
commConfigExpandedNames
=
ref
<
string
[]
>
([
'continuousQuestion'
])
const
showAdditionalPromptModal
=
ref
(
false
)
const
isInitGetAgentAppDetail
=
ref
(
false
)
const
generateAgentAvatarLoading
=
ref
(
false
)
// 是否正在生成图片
const
generatePreambleLoading
=
ref
(
false
)
// 是否正在生成开场白
const
generateFeaturedQuestionsLoading
=
ref
(
false
)
// 是否正在生成推荐词
...
...
@@ -66,11 +60,7 @@ const personalAppConfig = computed(() => {
})
const
continuousQuestionStatusText
=
computed
(()
=>
{
return
personalAppConfig
.
value
.
commConfig
.
continuousQuestionStatus
===
'default'
?
'默认'
:
personalAppConfig
.
value
.
commConfig
.
continuousQuestionStatus
===
'customizable'
?
'自定义'
:
'关闭'
return
personalAppConfig
.
value
.
commConfig
.
continuousQuestionStatus
===
'default'
?
'默认'
:
'关闭'
})
watch
(
...
...
@@ -157,24 +147,25 @@ function handleUploadAppAvatar(file: UploadFileInfo[]) {
personalAppConfig
.
value
.
baseInfo
.
agentAvatar
=
file
?.[
0
]?.
url
||
''
}
function
handleQuestionSettingChange
(
continuousQuestionStatus
:
string
)
{
if
(
continuousQuestionStatus
!==
'customizable'
)
{
personalAppConfig
.
value
.
commConfig
.
continuousQuestionSystem
=
''
personalAppConfig
.
value
.
commConfig
.
continuousQuestionTurn
=
3
}
function
handleRemoveAppAvatar
()
{
personalAppConfig
.
value
.
baseInfo
.
agentAvatar
=
''
}
function
handle
ShowAdditionalPromptModal
(
)
{
showAdditionalPromptModal
.
value
=
true
function
handle
UpdateCommConfigExpandedNames
(
expandedNames
:
string
[]
)
{
commConfigExpandedNames
.
value
=
expandedNames
}
function
handleAdditionalPrompt
(
continuousQuestionSystem
:
string
)
{
personalAppConfig
.
value
.
commConfig
.
continuousQuestionSystem
=
continuousQuestionSystem
showAdditionalPromptModal
.
value
=
false
}
async
function
handleAIGenerateAgentAvatar
()
{
generateAgentAvatarLoading
.
value
=
true
function
handleUpdateCommConfigExpandedNames
(
expandedNames
:
any
)
{
commConfigExpandedNames
.
value
=
expandedNames
const
res
=
await
fetchCreateAgentAvatar
({
agentTitle
:
personalAppConfig
.
value
.
baseInfo
.
agentTitle
,
agentDesc
:
personalAppConfig
.
value
.
baseInfo
.
agentDesc
,
}).
finally
(()
=>
(
generateAgentAvatarLoading
.
value
=
false
))
if
(
res
.
code
===
0
)
{
personalAppConfig
.
value
.
baseInfo
.
agentAvatar
=
res
.
data
as
string
}
}
async
function
handleAIGeneratePreamble
()
{
...
...
@@ -332,24 +323,32 @@ async function handleAIGenerateFeaturedQuestions() {
</
template
>
<NCollapseItem
title=
"基本信息"
name=
"1"
class=
"my-[13px]!"
>
<div
class=
"justify-left flex items-start pl-5"
>
<div
class=
"
mr-2 h-[72px]
w-[72px]"
>
<div
class=
"
relative mr-2
w-[72px]"
>
<UploadPhoto
:
save-
file-arr=
"[personalAppConfig.baseInfo.agentAvatar]"
:file-arr=
"[personalAppConfig.baseInfo.agentAvatar]"
@
after-upload=
"handleUploadAppAvatar"
@
remove=
"handleRemoveAppAvatar"
/>
<!-- <div
<div
v-show=
"generateAgentAvatarLoading"
class=
"absolute left-0 top-0 z-10 flex h-[72px] w-[72px] cursor-not-allowed items-center justify-center rounded-xl bg-[#151b2680]"
>
<CustomIcon
icon=
"eos-icons:bubble-loading"
class=
"text-xl text-white"
/>
</div>
<div
class=
"text-theme-color mt-3 flex h-[28px] items-center justify-between rounded-md border border-[#d4d6d9] px-2"
:class=
"
generateAgentAvatarLoading
? 'cursor-not-allowed opacity-50'
: 'cursor-pointer hover:border-[#d4e5ff] hover:bg-[#e6f0ff]'
"
@click="handleGenerateAgentAvatar"
@
click=
"handle
AI
GenerateAgentAvatar"
>
<div
class=
"mt-[-2px] h-[14px] w-[14px] bg-[url(@/assets/svgs/star.svg)] bg-[length:100%_100%]"
/>
<span
class=
"text-xs"
>
AI生成
</span>
</div>
-->
</div>
</div>
<div
class=
"flex flex-1"
>
<NForm
label-placement=
"left"
class=
"flex-1"
>
...
...
@@ -534,7 +533,6 @@ async function handleAIGenerateFeaturedQuestions() {
:options=
"questionSettingOptions"
trigger=
"click"
content-class=
"text-xs"
@
update:value=
"handleQuestionSettingChange"
>
<div
class=
"text-theme-color flex cursor-pointer items-center justify-between text-xs"
>
<span>
{{
continuousQuestionStatusText
}}
</span>
...
...
@@ -548,60 +546,9 @@ async function handleAIGenerateFeaturedQuestions() {
v-show=
"personalAppConfig.commConfig.continuousQuestionStatus === 'default'"
class=
"text-xs text-[#84868c]"
>
根据用户最近
3轮对话,在最后一轮
回复后自动提供3个提问建议。
根据用户最近
一轮对话,在
回复后自动提供3个提问建议。
</span>
<div
v-show=
"personalAppConfig.commConfig.continuousQuestionStatus === 'customizable'"
>
<span
class=
"text-xs text-[#84868c]"
>
根据最近轮次的参考对话,在最后一轮回复后自动提供3个提问建议。
</span>
<div
class=
"mt-4 text-xs"
>
<div
class=
"mb-2.5 flex h-[34px] items-center justify-between"
>
<span>
参考对话轮数:
</span>
<div
class=
"mx-5 flex flex-1"
>
<NSlider
v-model:value=
"personalAppConfig.commConfig.continuousQuestionTurn"
:default-value=
"3"
:step=
"1"
:min=
"1"
:max=
"5"
/>
<span
class=
"ml-4"
>
{{ personalAppConfig.commConfig.continuousQuestionTurn }}
</span>
</div>
<NPopover
trigger=
"hover"
>
<
template
#
trigger
>
<CustomIcon
icon=
"mingcute:question-line"
class=
"ml-1 cursor-pointer text-base text-[#999]"
/>
</
template
>
<span
class=
"text-xs"
>
大模型在追问生成过程中可参考1、3、5轮的对话轮数
</span>
</NPopover>
</div>
<div
class=
"mb-2.5 flex h-[34px] items-center justify-between"
>
<span>
追问prompt:
</span>
<div
class=
"mx-5 flex flex-1"
>
<span
class=
"text-theme-color cursor-pointer hover:opacity-80"
@
click=
"handleShowAdditionalPromptModal"
>
编辑
</span>
</div>
<NPopover
trigger=
"hover"
>
<
template
#
trigger
>
<CustomIcon
icon=
"mingcute:question-line"
class=
"ml-1 cursor-pointer text-base text-[#999]"
/>
</
template
>
<span
class=
"text-xs"
>
追问prompt可以控制追问的字数、风格和内容范围
</span>
</NPopover>
</div>
</div>
</div>
<span
v-show=
"personalAppConfig.commConfig.continuousQuestionStatus === 'close'"
class=
"text-xs text-[#84868c]"
...
...
@@ -616,14 +563,6 @@ async function handleAIGenerateFeaturedQuestions() {
</div>
</div>
</div>
<AdditionalPromptModal
v-model:isShowModal=
"showAdditionalPromptModal"
:question-system=
"personalAppConfig.commConfig.continuousQuestionSystem"
:btn-loading=
"false"
modal-title=
"追加Prompt"
@
comfirm=
"handleAdditionalPrompt"
/>
</template>
<
style
lang=
"scss"
scoped
>
...
...
src/views/personal-space/personal-app-setting/components/continue-question.vue
0 → 100644
View file @
f03284ec
<
script
lang=
"ts"
setup
>
import
{
inject
}
from
'vue'
import
{
Emitter
}
from
'mitt'
import
CustomLoading
from
'./custom-loading.vue'
interface
Props
{
continuousQuestionList
:
string
[]
}
defineProps
<
Props
>
()
const
emitter
=
inject
<
Emitter
<
MittEvents
>>
(
'emitter'
)
function
handleSelectContinueQuestion
(
continueQuestion
:
string
)
{
emitter
?.
emit
(
'selectQuestion'
,
continueQuestion
)
}
</
script
>
<
template
>
<div
class=
"pl-10 text-xs"
>
<p
class=
"mb-3 text-[#84868c]"
>
你可以继续提问
</p>
<div
v-if=
"continuousQuestionList.length === 0"
class=
"mt-4 px-4"
>
<CustomLoading
/>
</div>
<ul
v-else
class=
"flex max-w-full flex-col items-start justify-center gap-3 overflow-hidden"
>
<li
v-for=
"(continueQuestionItem, index) in continuousQuestionList"
:key=
"index"
>
<div
v-show=
"continueQuestionItem"
class=
"w-full cursor-pointer rounded-xl border border-[#d4d6d9] bg-[#ffffff80] px-[14px] py-[11px] text-[#5c5f66] hover:text-[#151b26]"
@
click=
"handleSelectContinueQuestion(continueQuestionItem)"
>
<span
class=
"break-all"
>
{{
continueQuestionItem
}}
</span>
</div>
</li>
</ul>
</div>
</
template
>
src/views/personal-space/personal-app-setting/components/footer-input.vue
View file @
f03284ec
...
...
@@ -7,6 +7,7 @@ import { usePersonalAppConfigStore } from '@/store/modules/personal-app-config'
interface
Props
{
messageList
:
ConversationMessageItem
[]
continuousQuestionStatus
:
'default'
|
'close'
}
const
props
=
defineProps
<
Props
>
()
...
...
@@ -17,6 +18,8 @@ const emit = defineEmits<{
deleteLastMessageItem
:
[]
updatePageScroll
:
[]
clearAllMessage
:
[]
createContinueQuestions
:
[
value
:
string
]
updateContinuousQuestionStatus
:
[
value
:
'default'
|
'close'
]
}
>
()
const
personalAppConfigStore
=
usePersonalAppConfigStore
()
...
...
@@ -33,6 +36,10 @@ const agentId = computed(() => {
return
personalAppConfigStore
.
baseInfo
.
agentId
})
const
isCreateContinueQuestions
=
computed
(()
=>
{
return
props
.
continuousQuestionStatus
===
'default'
})
const
isAllowClearMessage
=
computed
(()
=>
{
return
props
.
messageList
.
length
>
0
})
...
...
@@ -43,10 +50,10 @@ const isSendBtnDisabled = computed(() => {
onUnmounted
(()
=>
{
blockMessageResponse
()
emitter
?.
off
(
'select
Featured
Question'
)
emitter
?.
off
(
'selectQuestion'
)
})
emitter
?.
on
(
'select
Featured
Question'
,
(
featuredQuestion
)
=>
{
emitter
?.
on
(
'selectQuestion'
,
(
featuredQuestion
)
=>
{
inputeMessageContent
.
value
=
featuredQuestion
handleMessageSend
()
})
...
...
@@ -86,6 +93,7 @@ function handleMessageSend() {
role
:
string
}[]
=
[]
emit
(
'updateContinuousQuestionStatus'
,
personalAppConfigStore
.
commConfig
.
continuousQuestionStatus
)
emit
(
'addMessageItem'
,
{
...
messageItemFactory
(),
textContent
:
inputeMessageContent
.
value
})
emit
(
'updatePageScroll'
)
...
...
@@ -134,6 +142,7 @@ function handleMessageSend() {
isTextContentLoading
:
false
,
isAnswerResponseLoading
:
false
,
})
isCreateContinueQuestions
.
value
&&
emit
(
'createContinueQuestions'
,
replyTextContent
)
emit
(
'updatePageScroll'
)
blockMessageResponse
()
return
...
...
@@ -174,7 +183,6 @@ function errorMessageResponse() {
function
handleClearAllMessage
()
{
if
(
!
isAllowClearMessage
.
value
)
return
blockMessageResponse
()
emit
(
'clearAllMessage'
)
}
...
...
@@ -182,6 +190,10 @@ function blockMessageResponse() {
controller
?.
abort
()
isAnswerResponseWait
.
value
=
false
}
defineExpose
({
blockMessageResponse
,
})
</
script
>
<
template
>
...
...
src/views/personal-space/personal-app-setting/components/message-list.vue
View file @
f03284ec
<
script
setup
lang=
"ts"
>
import
{
computed
}
from
'vue'
import
MessageItem
from
'./message-item.vue'
import
ContinueQuestion
from
'./continue-question.vue'
import
{
useScroll
}
from
'@/composables/useScroll'
interface
Props
{
messageList
:
ConversationMessageItem
[]
continuousQuestionStatus
:
'default'
|
'close'
continuousQuestionList
:
string
[]
}
defineProps
<
Props
>
()
const
props
=
defineProps
<
Props
>
()
const
{
scrollRef
,
scrollToBottom
}
=
useScroll
()
const
isShowContinueQuestion
=
computed
(()
=>
{
return
(
props
.
continuousQuestionStatus
===
'default'
&&
props
.
messageList
.
length
>
1
&&
!
props
.
messageList
[
props
.
messageList
.
length
-
1
].
isAnswerResponseLoading
)
})
defineExpose
({
scrollToBottom
,
})
...
...
@@ -17,11 +29,17 @@ defineExpose({
<
template
>
<main
ref=
"scrollRef"
class=
"h-full overflow-y-auto px-5"
>
<MessageItem
v-for=
"messageItem in messageList"
:key=
"messageItem.timestamp"
:role=
"messageItem.role"
:message-item=
"messageItem"
/>
<div>
<MessageItem
v-for=
"messageItem in messageList"
:key=
"messageItem.timestamp"
:role=
"messageItem.role"
:message-item=
"messageItem"
/>
</div>
<div
v-show=
"isShowContinueQuestion"
>
<ContinueQuestion
:continuous-question-list=
"continuousQuestionList"
/>
</div>
</main>
</
template
>
src/views/personal-space/personal-app-setting/components/preamble.vue
View file @
f03284ec
...
...
@@ -8,20 +8,24 @@ const personalAppConfigStore = usePersonalAppConfigStore()
const
emitter
=
inject
<
Emitter
<
MittEvents
>>
(
'emitter'
)
const
agentAvatar
=
computed
(()
=>
{
return
(
personalAppConfigStore
.
baseInfo
.
agentAvatar
||
'https://gsst-poe-sit.gz.bcebos.com/data/20240911/1726041369632.webp'
)
return
personalAppConfigStore
.
baseInfo
.
agentAvatar
})
function
handleSelectFeaturedQuestion
(
featuredQuestion
:
string
)
{
emitter
?.
emit
(
'select
Featured
Question'
,
featuredQuestion
)
emitter
?.
emit
(
'selectQuestion'
,
featuredQuestion
)
}
</
script
>
<
template
>
<div
class=
"flex w-full flex-1 flex-col px-5"
>
<div
class=
"mb-5 flex w-full justify-center pt-[50px]"
>
<img
:src=
"agentAvatar"
class=
"h-[72px] w-[72px] rounded-xl border"
/>
<img
v-if=
"personalAppConfigStore.baseInfo.agentAvatar"
:src=
"agentAvatar"
class=
"h-[72px] w-[72px] rounded-xl border"
/>
<div
v-else
class=
"h-[72px] w-[72px] rounded-xl border"
/>
</div>
<div
class=
"flex flex-col items-center justify-center"
>
...
...
src/views/share/components/continue-question.vue
0 → 100644
View file @
f03284ec
<
script
lang=
"ts"
setup
>
import
{
inject
}
from
'vue'
import
{
Emitter
}
from
'mitt'
import
CustomLoading
from
'./custom-loading.vue'
import
{
useLayoutConfig
}
from
'@/composables/useLayoutConfig'
interface
Props
{
continuousQuestionList
:
string
[]
}
defineProps
<
Props
>
()
const
{
isMobile
}
=
useLayoutConfig
()
const
emitter
=
inject
<
Emitter
<
MittEvents
>>
(
'emitter'
)
function
handleSelectContinueQuestion
(
continueQuestion
:
string
)
{
emitter
?.
emit
(
'selectQuestion'
,
continueQuestion
)
}
</
script
>
<
template
>
<div
class=
"text-xs"
:class=
"isMobile ? 'pl-0' : 'pl-10'"
>
<p
class=
"mb-3 mt-5 text-[#84868c]"
>
你可以继续提问
</p>
<div
v-if=
"continuousQuestionList.length === 0"
class=
"mt-4 px-4"
>
<CustomLoading
/>
</div>
<ul
v-else
class=
"flex max-w-full flex-col items-start justify-center gap-3 overflow-hidden"
>
<li
v-for=
"(continueQuestionItem, index) in continuousQuestionList"
:key=
"index"
>
<div
v-show=
"continueQuestionItem"
class=
"w-full cursor-pointer rounded-xl border border-[#d4d6d9] bg-[#ffffff80] px-[14px] py-[11px] text-[#5c5f66] hover:text-[#151b26]"
@
click=
"handleSelectContinueQuestion(continueQuestionItem)"
>
<span
class=
"break-all"
>
{{
continueQuestionItem
}}
</span>
</div>
</li>
</ul>
</div>
</
template
>
src/views/share/components/footer-input.vue
View file @
f03284ec
...
...
@@ -10,6 +10,7 @@ interface Props {
agentId
:
string
dialogsId
:
string
messageList
:
ConversationMessageItem
[]
continuousQuestionStatus
:
'default'
|
'close'
}
const
props
=
defineProps
<
Props
>
()
...
...
@@ -21,6 +22,8 @@ const emit = defineEmits<{
updatePageScroll
:
[]
clearAllMessage
:
[]
toLogin
:
[]
createContinueQuestions
:
[
value
:
string
]
resetContinueQuestionList
:
[]
}
>
()
const
{
isMobile
}
=
useLayoutConfig
()
...
...
@@ -51,8 +54,12 @@ const inputPlaceholder = computed(() => {
return
isLogin
.
value
?
'请输入你的问题进行提问'
:
''
})
const
isCreateContinueQuestions
=
computed
(()
=>
{
return
props
.
continuousQuestionStatus
===
'default'
})
onMounted
(()
=>
{
emitter
?.
on
(
'select
Featured
Question'
,
(
featuredQuestion
)
=>
{
emitter
?.
on
(
'selectQuestion'
,
(
featuredQuestion
)
=>
{
if
(
!
isLogin
.
value
)
{
window
.
$message
.
warning
(
'请先登录'
)
return
...
...
@@ -65,7 +72,7 @@ onMounted(() => {
onUnmounted
(()
=>
{
blockMessageResponse
()
emitter
?.
off
(
'select
Featured
Question'
)
emitter
?.
off
(
'selectQuestion'
)
})
function
messageItemFactory
()
{
...
...
@@ -97,6 +104,7 @@ function handleMessageSend() {
if
(
!
inputeMessageContent
.
value
.
trim
()
||
isAnswerResponseWait
.
value
)
return
''
emit
(
'resetContinueQuestionList'
)
emit
(
'addMessageItem'
,
{
...
messageItemFactory
(),
textContent
:
inputeMessageContent
.
value
})
emit
(
'updatePageScroll'
)
...
...
@@ -131,6 +139,7 @@ function handleMessageSend() {
isTextContentLoading
:
false
,
isAnswerResponseLoading
:
false
,
})
isCreateContinueQuestions
.
value
&&
emit
(
'createContinueQuestions'
,
replyTextContent
)
emit
(
'updatePageScroll'
)
blockMessageResponse
()
return
...
...
@@ -171,7 +180,6 @@ function errorMessageResponse() {
function
handleClearAllMessage
()
{
if
(
!
isAllowClearMessage
.
value
)
return
blockMessageResponse
()
emit
(
'clearAllMessage'
)
}
...
...
@@ -183,6 +191,10 @@ function blockMessageResponse() {
function
handleToLogin
()
{
emit
(
'toLogin'
)
}
defineExpose
({
blockMessageResponse
,
})
</
script
>
<
template
>
...
...
src/views/share/components/message-list.vue
View file @
f03284ec
<
script
setup
lang=
"ts"
>
import
MessageItem
from
'./message-item.vue'
import
ContinueQuestion
from
'./continue-question.vue'
import
{
useScroll
}
from
'@/composables/useScroll'
import
{
PersonalAppConfigState
}
from
'@/store/types/personal-app-config'
import
{
computed
}
from
'vue'
interface
Props
{
messageList
:
ConversationMessageItem
[]
agentApplicationConfig
:
PersonalAppConfigState
continuousQuestionStatus
:
'default'
|
'close'
continuousQuestionList
:
string
[]
}
defineProps
<
Props
>
()
const
props
=
defineProps
<
Props
>
()
const
{
scrollRef
,
scrollToBottom
}
=
useScroll
()
const
isShowContinueQuestion
=
computed
(()
=>
{
return
(
props
.
continuousQuestionStatus
===
'default'
&&
props
.
messageList
.
length
>
1
&&
!
props
.
messageList
[
props
.
messageList
.
length
-
1
].
isAnswerResponseLoading
)
})
defineExpose
({
scrollToBottom
,
})
...
...
@@ -19,12 +31,18 @@ defineExpose({
<
template
>
<main
ref=
"scrollRef"
class=
"h-full overflow-y-auto px-5"
>
<MessageItem
v-for=
"messageItem in messageList"
:key=
"messageItem.timestamp"
:role=
"messageItem.role"
:message-item=
"messageItem"
:agent-application-config=
"agentApplicationConfig"
/>
<div>
<MessageItem
v-for=
"messageItem in messageList"
:key=
"messageItem.timestamp"
:role=
"messageItem.role"
:message-item=
"messageItem"
:agent-application-config=
"agentApplicationConfig"
/>
</div>
<div
v-show=
"isShowContinueQuestion"
>
<ContinueQuestion
:continuous-question-list=
"continuousQuestionList"
/>
</div>
</main>
</
template
>
src/views/share/components/preamble.vue
View file @
f03284ec
...
...
@@ -21,7 +21,7 @@ const agentAvatar = computed(() => {
})
function
handleSelectFeaturedQuestion
(
featuredQuestion
:
string
)
{
emitter
?.
emit
(
'select
Featured
Question'
,
featuredQuestion
)
emitter
?.
emit
(
'selectQuestion'
,
featuredQuestion
)
}
</
script
>
...
...
src/views/share/share-application-mobile.vue
View file @
f03284ec
...
...
@@ -8,7 +8,7 @@ import FooterInput from './components/footer-input.vue'
import
{
PersonalAppConfigState
}
from
'@/store/types/personal-app-config'
import
{
useUserStore
}
from
'@/store/modules/user'
import
{
defaultPersonalAppConfigState
}
from
'@/store/modules/personal-app-config'
import
{
fetchCreateDialogues
,
fetchGetApplicationInfo
}
from
'@/apis/agent-application'
import
{
fetchCreate
ContinueQuestions
,
fetchCreate
Dialogues
,
fetchGetApplicationInfo
}
from
'@/apis/agent-application'
import
{
useLayoutConfig
}
from
'@/composables/useLayoutConfig'
const
router
=
useRouter
()
...
...
@@ -24,8 +24,13 @@ const dialogsId = ref('')
const
agentApplicationConfig
=
ref
<
PersonalAppConfigState
>
(
defaultPersonalAppConfigState
())
const
messageListRef
=
ref
<
InstanceType
<
typeof
MessageList
>
|
null
>
(
null
)
const
footerInputRef
=
ref
<
InstanceType
<
typeof
FooterInput
>
|
null
>
(
null
)
const
messageList
=
ref
<
ConversationMessageItem
[]
>
([])
const
continuousQuestionStatus
=
ref
<
'default'
|
'close'
>
(
'default'
)
const
continueQuestionList
=
ref
<
string
[]
>
([])
onMounted
(
async
()
=>
{
if
(
router
.
currentRoute
.
value
.
params
.
agentId
)
{
agentId
.
value
=
router
.
currentRoute
.
value
.
params
.
agentId
as
string
...
...
@@ -53,6 +58,7 @@ async function handleGetApplicationDetail() {
fetchGetApplicationInfo
<
PersonalAppConfigState
>
(
agentId
.
value
)
.
then
((
res
)
=>
{
agentApplicationConfig
.
value
=
res
.
data
continuousQuestionStatus
.
value
=
res
.
data
.
commConfig
.
continuousQuestionStatus
document
.
title
=
agentApplicationConfig
.
value
.
baseInfo
.
agentTitle
})
.
catch
(()
=>
{
...
...
@@ -110,11 +116,25 @@ function handleClearAllMessage() {
negativeText
:
'取消'
,
positiveText
:
'确定'
,
onPositiveClick
:
()
=>
{
footerInputRef
.
value
?.
blockMessageResponse
()
messageList
.
value
=
[]
window
.
$message
.
success
(
'清空成功'
)
},
})
}
async
function
handleCreateContinueQuestions
(
replyTextContent
:
string
)
{
const
res
=
await
fetchCreateContinueQuestions
<
string
[]
>
({
input
:
replyTextContent
})
if
(
res
.
code
===
0
)
{
continueQuestionList
.
value
=
res
.
data
handleUpdatePageScroll
()
}
}
function
handleResetContinueQuestionList
()
{
continueQuestionList
.
value
=
[]
}
</
script
>
<
template
>
...
...
@@ -136,21 +156,27 @@ function handleClearAllMessage() {
ref=
"messageListRef"
:agent-application-config=
"agentApplicationConfig"
:message-list=
"messageList"
:continuous-question-status=
"continuousQuestionStatus"
:continuous-question-list=
"continueQuestionList"
/>
</div>
</div>
<div
class=
"footer-operation px-4"
>
<FooterInput
ref=
"footerInputRef"
:message-list=
"messageList"
:dialogs-id=
"dialogsId"
:agent-id=
"agentApplicationConfig.baseInfo.agentId"
:continuous-question-status=
"continuousQuestionStatus"
@
add-message-item=
"handleAddMessageItem"
@
update-specify-message-item=
"handleUpdateSpecifyMessageItem"
@
delete-last-message-item=
"handleDeleteLastMessageItem"
@
update-page-scroll=
"handleUpdatePageScroll"
@
clear-all-message=
"handleClearAllMessage"
@
to-login=
"handleToLoginPage"
@
create-continue-questions=
"handleCreateContinueQuestions"
@
reset-continue-question-list=
"handleResetContinueQuestionList"
/>
</div>
</div>
...
...
src/views/share/share-application-web.vue
View file @
f03284ec
...
...
@@ -5,7 +5,7 @@ import PageHeader from './components/web-page-header.vue'
import
Preamble
from
'./components/preamble.vue'
import
MessageList
from
'./components/message-list.vue'
import
FooterInput
from
'./components/footer-input.vue'
import
{
fetchCreateDialogues
,
fetchGetApplicationInfo
}
from
'@/apis/agent-application'
import
{
fetchCreate
ContinueQuestions
,
fetchCreate
Dialogues
,
fetchGetApplicationInfo
}
from
'@/apis/agent-application'
import
{
PersonalAppConfigState
}
from
'@/store/types/personal-app-config'
import
{
defaultPersonalAppConfigState
}
from
'@/store/modules/personal-app-config'
import
{
useUserStore
}
from
'@/store/modules/user'
...
...
@@ -24,8 +24,13 @@ const dialogsId = ref('')
const
agentApplicationConfig
=
ref
<
PersonalAppConfigState
>
(
defaultPersonalAppConfigState
())
const
messageListRef
=
ref
<
InstanceType
<
typeof
MessageList
>
|
null
>
(
null
)
const
footerInputRef
=
ref
<
InstanceType
<
typeof
FooterInput
>
|
null
>
(
null
)
const
messageList
=
ref
<
ConversationMessageItem
[]
>
([])
const
continuousQuestionStatus
=
ref
<
'default'
|
'close'
>
(
'default'
)
const
continueQuestionList
=
ref
<
string
[]
>
([])
onMounted
(
async
()
=>
{
if
(
router
.
currentRoute
.
value
.
params
.
agentId
)
{
agentId
.
value
=
router
.
currentRoute
.
value
.
params
.
agentId
as
string
...
...
@@ -53,6 +58,7 @@ async function handleGetApplicationDetail() {
fetchGetApplicationInfo
<
PersonalAppConfigState
>
(
agentId
.
value
)
.
then
((
res
)
=>
{
agentApplicationConfig
.
value
=
res
.
data
continuousQuestionStatus
.
value
=
res
.
data
.
commConfig
.
continuousQuestionStatus
document
.
title
=
agentApplicationConfig
.
value
.
baseInfo
.
agentTitle
})
.
catch
(()
=>
{
...
...
@@ -114,11 +120,25 @@ function handleClearAllMessage() {
negativeText
:
'取消'
,
positiveText
:
'确定'
,
onPositiveClick
:
()
=>
{
footerInputRef
.
value
?.
blockMessageResponse
()
messageList
.
value
=
[]
window
.
$message
.
success
(
'清空成功'
)
},
})
}
async
function
handleCreateContinueQuestions
(
replyTextContent
:
string
)
{
const
res
=
await
fetchCreateContinueQuestions
<
string
[]
>
({
input
:
replyTextContent
})
if
(
res
.
code
===
0
)
{
continueQuestionList
.
value
=
res
.
data
handleUpdatePageScroll
()
}
}
function
handleResetContinueQuestionList
()
{
continueQuestionList
.
value
=
[]
}
</
script
>
<
template
>
...
...
@@ -157,21 +177,27 @@ function handleClearAllMessage() {
ref=
"messageListRef"
:agent-application-config=
"agentApplicationConfig"
:message-list=
"messageList"
:continuous-question-status=
"continuousQuestionStatus"
:continuous-question-list=
"continueQuestionList"
/>
</div>
</div>
<div
class=
"px-5"
>
<FooterInput
ref=
"footerInputRef"
:message-list=
"messageList"
:dialogs-id=
"dialogsId"
:agent-id=
"agentApplicationConfig.baseInfo.agentId"
:continuous-question-status=
"continuousQuestionStatus"
@
add-message-item=
"handleAddMessageItem"
@
update-specify-message-item=
"handleUpdateSpecifyMessageItem"
@
delete-last-message-item=
"handleDeleteLastMessageItem"
@
update-page-scroll=
"handleUpdatePageScroll"
@
clear-all-message=
"handleClearAllMessage"
@
to-login=
"handleToLoginPage"
@
create-continue-questions=
"handleCreateContinueQuestions"
@
reset-continue-question-list=
"handleResetContinueQuestionList"
/>
</div>
</div>
...
...
types/mitt-events.d.ts
View file @
f03284ec
declare
type
MittEvents
=
{
select
Featured
Question
:
string
selectQuestion
:
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