Commit 39905505 authored by nick zheng's avatar nick zheng

chore: 没有应用名称时不可发布及补充优化角色指令

parent e1a430eb
...@@ -9,6 +9,9 @@ interface Props { ...@@ -9,6 +9,9 @@ interface Props {
width?: number // 宽度 width?: number // 宽度
borderRadius?: number // 圆角 borderRadius?: number // 圆角
btnLoading?: boolean // 按钮是否加载中 btnLoading?: boolean // 按钮是否加载中
btnDisabled?: boolean // 按钮是否禁用
cancelBtnText?: string // 取消按钮文字
confirmBtnText?: string // 取消按钮文字
labelWidth?: number // 标签的宽度 labelWidth?: number // 标签的宽度
labelPlacement?: 'left' | 'top' // 标签显示的位置 labelPlacement?: 'left' | 'top' // 标签显示的位置
} }
...@@ -23,6 +26,10 @@ const props = withDefaults(defineProps<Props>(), { ...@@ -23,6 +26,10 @@ const props = withDefaults(defineProps<Props>(), {
height: 240, height: 240,
width: 500, width: 500,
borderRadius: 6, borderRadius: 6,
btnLoading: false,
btnDisabled: false,
cancelBtnText: '取 消',
confirmBtnText: '确认',
labelWidth: 80, labelWidth: 80,
labelPlacement: 'left', labelPlacement: 'left',
}) })
...@@ -79,14 +86,15 @@ function handleDetele() { ...@@ -79,14 +86,15 @@ function handleDetele() {
<template #footer> <template #footer>
<div class="flex w-full items-center justify-end"> <div class="flex w-full items-center justify-end">
<NButton class="h-[32px]! w-[80px]! rounded-md!" @click="handleCloseModal"> 取 消 </NButton> <NButton class="h-[32px]! rounded-md! px-6!" @click="handleCloseModal"> {{ cancelBtnText }} </NButton>
<NButton <NButton
:loading="btnLoading" :loading="btnLoading"
type="primary" type="primary"
class="h-[32px]! w-[80px]! rounded-md! ml-4!" :disabled="btnDisabled"
class="h-[32px]! px-6! rounded-md! ml-4!"
@click="handleDetele" @click="handleDetele"
> >
确 定 {{ confirmBtnText }}
</NButton> </NButton>
</div> </div>
</template> </template>
......
<script setup lang="ts">
import { computed, ref, watchEffect } from 'vue'
import CustomModal from '@/components/custom-modal/custom-modal.vue'
interface Props {
modalTitle: string
isShowModal: boolean
btnLoading: boolean
questionSystem: string
}
interface Emits {
(e: 'update:isShowModal', value: boolean): void
(e: 'comfirm', value: string): void
}
const props = defineProps<Props>()
const emit = defineEmits<Emits>()
const continuousQuestionSystem = ref('')
watchEffect(() => {
continuousQuestionSystem.value = props.questionSystem
})
const showModal = computed({
get() {
return props.isShowModal
},
set(value: boolean) {
emit('update:isShowModal', value)
},
})
function handleAdditionalPrompt() {
emit('comfirm', continuousQuestionSystem.value)
}
</script>
<template>
<CustomModal
v-model:is-show="showModal"
:title="modalTitle"
:btn-loading="btnLoading"
:height="636"
:width="520"
@confirm="handleAdditionalPrompt"
>
<template #content>
<p class="mb-3 select-none text-[#84868c]">可在追问prompt中指引追问的字数、风格和内容范围。</p>
<NInput
v-model:value="continuousQuestionSystem"
type="textarea"
:rows="19"
maxlength="1000"
show-count
placeholder="请输入追问prompt"
class="rounded-lg!"
/>
</template>
</CustomModal>
</template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, onMounted, reactive, ref, watch } from 'vue' import { computed, onMounted, reactive, ref, watch } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { SelectOption, UploadFileInfo } from 'naive-ui' import { FormInst, SelectOption, UploadFileInfo } from 'naive-ui'
import { useThrottleFn } from '@vueuse/core' import { useThrottleFn } from '@vueuse/core'
import CustomIcon from '@/components/custom-icon/custom-icon.vue' import CustomIcon from '@/components/custom-icon/custom-icon.vue'
import UploadPhoto from '@/components/upload-photo/upload-photo.vue' import UploadPhoto from '@/components/upload-photo/upload-photo.vue'
import OptimizeSystemModal from './optimize-system-modal.vue'
import { usePersonalAppConfigStore } from '@/store/modules/personal-app-config' import { usePersonalAppConfigStore } from '@/store/modules/personal-app-config'
import { PersonalAppConfigState } from '@/store/types/personal-app-config' import { PersonalAppConfigState } from '@/store/types/personal-app-config'
import { import {
...@@ -51,10 +52,20 @@ const commConfigExpandedNames = ref<string[]>(['continuousQuestion']) ...@@ -51,10 +52,20 @@ const commConfigExpandedNames = ref<string[]>(['continuousQuestion'])
const isInitGetAgentAppDetail = ref(false) const isInitGetAgentAppDetail = ref(false)
const isShowOptimizeAgentSystemModal = ref(false) // 是否显示优化角色指令对话框
const generateAgentAvatarLoading = ref(false) // 是否正在生成图片 const generateAgentAvatarLoading = ref(false) // 是否正在生成图片
const generatePreambleLoading = ref(false) // 是否正在生成开场白 const generatePreambleLoading = ref(false) // 是否正在生成开场白
const generateFeaturedQuestionsLoading = ref(false) // 是否正在生成推荐词 const generateFeaturedQuestionsLoading = ref(false) // 是否正在生成推荐词
const personalAppFormRef = ref<FormInst | null>(null)
const personalAppRules = {
baseInfo: {
agentTitle: [{ required: true, message: '请输入应用名称', trigger: 'blur' }],
},
}
const personalAppConfig = computed(() => { const personalAppConfig = computed(() => {
return personalAppConfigStore.$state return personalAppConfigStore.$state
}) })
...@@ -108,6 +119,11 @@ async function handleGetAgentApplicationDetail(agentId: string) { ...@@ -108,6 +119,11 @@ async function handleGetAgentApplicationDetail(agentId: string) {
res.data.baseInfo.agentAvatar || 'https://gsst-poe-sit.gz.bcebos.com/data/20240911/1726041369632.webp', res.data.baseInfo.agentAvatar || 'https://gsst-poe-sit.gz.bcebos.com/data/20240911/1726041369632.webp',
}, },
}) })
;['preamble', 'featuredQuestions']
.filter((property) => personalAppConfig.value.commConfig[property as keyof PersonalAppConfigState['commConfig']])
.forEach((property) => {
commConfigExpandedNames.value.push(property)
})
} }
} }
...@@ -139,6 +155,12 @@ async function handleUpdatePersonalAppId() { ...@@ -139,6 +155,12 @@ async function handleUpdatePersonalAppId() {
} }
} }
function handleShowOptimizeAgentSystemModal() {
if (!personalAppConfig.value.baseInfo.agentSystem) return
isShowOptimizeAgentSystemModal.value = true
}
function handleSettingDefaultPrompt() { function handleSettingDefaultPrompt() {
personalAppConfig.value.baseInfo.agentSystem = defaultPrompt personalAppConfig.value.baseInfo.agentSystem = defaultPrompt
} }
...@@ -173,13 +195,19 @@ async function handleAIGeneratePreamble() { ...@@ -173,13 +195,19 @@ async function handleAIGeneratePreamble() {
generatePreambleLoading.value = true generatePreambleLoading.value = true
const res = await fetchCreatePreamble({ const res = await fetchCreatePreamble<string>({
agentTitle: personalAppConfig.value.baseInfo.agentTitle, agentTitle: personalAppConfig.value.baseInfo.agentTitle,
agentDesc: personalAppConfig.value.baseInfo.agentDesc, agentDesc: personalAppConfig.value.baseInfo.agentDesc,
}).finally(() => (generatePreambleLoading.value = false)) }).finally(() => (generatePreambleLoading.value = false))
if (res.code === 0) { if (res.code === 0) {
personalAppConfig.value.commConfig.preamble = res.data as string try {
const content = res.data.replace(/^```json|```$/g, '')
const preamble = JSON.parse(content)['output']
personalAppConfig.value.commConfig.preamble = preamble
} catch (error) {
window.$message.error('生成内容格式出错啦')
}
} }
} }
...@@ -198,6 +226,11 @@ async function handleAIGenerateFeaturedQuestions() { ...@@ -198,6 +226,11 @@ async function handleAIGenerateFeaturedQuestions() {
personalAppConfig.value.commConfig.featuredQuestions = res.data personalAppConfig.value.commConfig.featuredQuestions = res.data
} }
} }
function handleSettingAgentSystem(agentSystem: string) {
personalAppConfig.value.baseInfo.agentSystem = agentSystem
isShowOptimizeAgentSystemModal.value = false
}
</script> </script>
<template> <template>
...@@ -351,8 +384,14 @@ async function handleAIGenerateFeaturedQuestions() { ...@@ -351,8 +384,14 @@ async function handleAIGenerateFeaturedQuestions() {
</div> </div>
</div> </div>
<div class="flex flex-1"> <div class="flex flex-1">
<NForm label-placement="left" class="flex-1"> <NForm
<NFormItem feedback-style="height: 14px"> ref="personalAppFormRef"
:model="personalAppConfig"
:rules="personalAppRules"
label-placement="left"
class="flex-1"
>
<NFormItem feedback-class="p-0.5! text-xs!" path="baseInfo.agentTitle">
<NInput <NInput
v-model:value="personalAppConfig.baseInfo.agentTitle" v-model:value="personalAppConfig.baseInfo.agentTitle"
:maxlength="50" :maxlength="50"
...@@ -396,18 +435,40 @@ async function handleAIGenerateFeaturedQuestions() { ...@@ -396,18 +435,40 @@ async function handleAIGenerateFeaturedQuestions() {
</NPopover> </NPopover>
</div> </div>
<NPopover style="width: 200px" content-style="padding: 10px 0;" trigger="hover"> <div class="flex items-center justify-center">
<template #trigger> <NPopover trigger="hover">
<div <template #trigger>
class="text-theme-color flex cursor-pointer items-center hover:opacity-80" <div
@click="handleSettingDefaultPrompt" class="text-theme-color flex items-center border-r border-[#e8e9eb] pr-[9px]"
> :class="
<CustomIcon icon="solar:book-2-broken" class="mr-3 text-base" /> personalAppConfig.baseInfo.agentSystem
<span class="text-xs">模板</span> ? 'cursor-pointer hover:opacity-80'
</div> : 'cursor-not-allowed opacity-50'
</template> "
<p class="text-xs" style="white-space: pre-wrap">{{ defaultPrompt }}</p> @click="handleShowOptimizeAgentSystemModal"
</NPopover> >
<div
class="mr-3 mt-[-2px] h-[16px] w-[16px] bg-[url(@/assets/svgs/star.svg)] bg-[length:100%_100%]"
/>
<span class="text-xs">优化</span>
</div>
</template>
<p class="text-xs">AI优化</p>
</NPopover>
<NPopover style="width: 200px" content-style="padding: 10px 0;" trigger="hover">
<template #trigger>
<div
class="text-theme-color flex cursor-pointer items-center pl-[9px] hover:opacity-80"
@click="handleSettingDefaultPrompt"
>
<CustomIcon icon="solar:book-2-broken" class="mr-3 text-base" />
<span class="text-xs">模板</span>
</div>
</template>
<p class="text-xs" style="white-space: pre-wrap">{{ defaultPrompt }}</p>
</NPopover>
</div>
</div> </div>
<div class="flex flex-1 p-1 pl-6"> <div class="flex flex-1 p-1 pl-6">
...@@ -563,6 +624,13 @@ async function handleAIGenerateFeaturedQuestions() { ...@@ -563,6 +624,13 @@ async function handleAIGenerateFeaturedQuestions() {
</div> </div>
</div> </div>
</div> </div>
<OptimizeSystemModal
v-model:is-show-modal="isShowOptimizeAgentSystemModal"
:btn-loading="false"
modal-title="角色指令优化"
@comfirm="handleSettingAgentSystem"
/>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
......
<script setup lang="ts">
import { computed, ref, watch, nextTick } from 'vue'
import CustomModal from '@/components/custom-modal/custom-modal.vue'
import { fetchCustomEventSource } from '@/composables/useEventSource'
import { usePersonalAppConfigStore } from '@/store/modules/personal-app-config'
import { InputInst } from 'naive-ui'
import { useThrottleFn } from '@vueuse/core'
interface Props {
modalTitle: string
isShowModal: boolean
btnLoading: boolean
}
interface Emits {
(e: 'update:isShowModal', value: boolean): void
(e: 'comfirm', value: string): void
}
const props = defineProps<Props>()
const emit = defineEmits<Emits>()
const personalAppConfigStore = usePersonalAppConfigStore()
const agentSystemInputRef = ref<InputInst | null>(null)
const agentSystem = ref('')
const generateAgentSystemLoading = ref(false)
let controller: AbortController | null = null
const showModal = computed({
get() {
return props.isShowModal
},
set(value: boolean) {
emit('update:isShowModal', value)
},
})
watch(
() => showModal.value,
() => {
showModal.value && handleGenerateAgentSystem()
},
)
const isDisabledBtn = computed(() => {
return !agentSystem.value || generateAgentSystemLoading.value
})
function handleGenerateAgentSystem() {
agentSystem.value = ''
generateAgentSystemLoading.value = true
controller = new AbortController()
fetchCustomEventSource({
path: '/api/rest/agentApplicationInfoRest/createAgentSystem.json',
payload: {
input: personalAppConfigStore.baseInfo.agentSystem,
},
controller,
onMessage: (data: any) => {
if (data === '[DONE]') {
blockMessageResponse()
return
}
if (data) {
agentSystem.value += data
useThrottleFn(
() => {
nextTick(() => {
agentSystemInputRef.value!.textareaElRef!.scrollTop =
agentSystemInputRef.value?.textareaElRef?.scrollHeight || 0
})
},
200,
true,
)()
}
},
onRequestError: () => {
blockMessageResponse()
},
onError: () => {
blockMessageResponse()
},
onFinally: () => {
controller = null
},
})
}
function blockMessageResponse() {
controller?.abort()
generateAgentSystemLoading.value = false
}
function handleCloseModal() {
blockMessageResponse()
}
function handleAdditionalPrompt() {
emit('comfirm', agentSystem.value)
}
</script>
<template>
<CustomModal
v-model:is-show="showModal"
:title="modalTitle"
:btn-loading="btnLoading"
:btn-disabled="isDisabledBtn"
:width="640"
:height="610"
confirm-btn-text="使 用"
@close="handleCloseModal"
@confirm="handleAdditionalPrompt"
>
<template #content>
<div>
<NInput
ref="agentSystemInputRef"
v-model:value="agentSystem"
type="textarea"
:rows="18"
:disabled="generateAgentSystemLoading"
placeholder=""
class="rounded-lg!"
/>
<div class="mt-2.5">
<NButton :disabled="generateAgentSystemLoading" class="rounded-md!" @click="handleGenerateAgentSystem">
重新生成
</NButton>
</div>
</div>
</template>
</CustomModal>
</template>
...@@ -135,6 +135,11 @@ function handleSwtichAgentAppOption(currentTabKey: string) { ...@@ -135,6 +135,11 @@ function handleSwtichAgentAppOption(currentTabKey: string) {
} }
async function handlePublishApplication() { async function handlePublishApplication() {
if (!personalAppConfig.value.baseInfo.agentTitle) {
window.$message.warning('应用名称不能为空')
return
}
publishBtnloading.value = true publishBtnloading.value = true
const res = await fetchPublishApplication(personalAppConfig.value).finally(() => (publishBtnloading.value = false)) const res = await fetchPublishApplication(personalAppConfig.value).finally(() => (publishBtnloading.value = false))
......
...@@ -59,8 +59,8 @@ export function createPersonalAppColumn(handlePersonalAppTableAction: (actionTyp ...@@ -59,8 +59,8 @@ export function createPersonalAppColumn(handlePersonalAppTableAction: (actionTyp
props: { placement: 'top' }, props: { placement: 'top' },
}, },
{ {
trigger: () => h('span', {}, row.baseInfo.agentTitle || '我的Agent应用'), trigger: () => h('span', {}, row.baseInfo.agentTitle || '--'),
default: () => h('span', {}, row.baseInfo.agentTitle || '我的Agent应用'), default: () => h('span', {}, row.baseInfo.agentTitle || '--'),
}, },
), ),
], ],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment