feat: The model directly generates optimized prompt words

v3.2
wangdan-fit2cloud 2025-09-11 17:17:13 +08:00
parent 94d3bf3125
commit fad4ce9cd0
16 changed files with 271 additions and 220 deletions

View File

@ -3,8 +3,7 @@
<div class="text-center mb-8" v-if="loading"> <div class="text-center mb-8" v-if="loading">
<el-button class="border-primary video-stop-button" @click="stopChat"> <el-button class="border-primary video-stop-button" @click="stopChat">
<app-icon iconName="app-video-stop" class="mr-8"></app-icon> <app-icon iconName="app-video-stop" class="mr-8"></app-icon>
{{ $t('chat.operation.stopChat') }}</el-button {{ $t('chat.operation.stopChat') }}</el-button>
>
</div> </div>
<div class="operate-textarea"> <div class="operate-textarea">
<el-scrollbar max-height="136"> <el-scrollbar max-height="136">

View File

@ -718,4 +718,26 @@ export default {
]) ])
}, },
}, },
'app-generate-star': {
iconReader: () => {
return h('i', [
h(
'svg',
{
style: { height: '100%', width: '100%' },
viewBox: '0 0 1024 1024',
version: '1.1',
xmlns: 'http://www.w3.org/2000/svg',
},
[
h('path', {
d: 'M384 832c-12.8 0-25.6-8.533333-29.866667-21.333333l-34.133333-119.466667c-17.066667-55.466667-55.466667-93.866667-110.933333-110.933333L85.333333 541.866667c-12.8-4.266667-21.333333-17.066667-21.333333-29.866667 0-12.8 8.533333-25.6 21.333333-29.866667l119.466667-34.133333c55.466667-17.066667 93.866667-55.466667 110.933333-110.933333L354.133333 213.333333c4.266667-12.8 17.066667-21.333333 29.866667-21.333333 12.8 0 25.6 8.533333 29.866667 21.333333l34.133333 119.466667c17.066667 55.466667 55.466667 93.866667 110.933333 110.933333l119.466667 34.133334c12.8 4.266667 21.333333 17.066667 21.333333 29.866666 0 12.8-8.533333 25.6-21.333333 29.866667l-119.466667 34.133333c-55.466667 17.066667-93.866667 55.466667-110.933333 110.933334l-34.133333 128c-4.266667 12.8-17.066667 21.333333-29.866667 21.333333z m384-384c-12.8 0-25.6-8.533333-29.866667-25.6l-12.8-42.666667c-8.533333-38.4-42.666667-72.533333-81.066666-81.066666l-42.666667-12.8c-12.8-4.266667-25.6-17.066667-25.6-29.866667 0-12.8 8.533333-25.6 25.6-29.866667l42.666667-12.8c38.4-8.533333 72.533333-42.666667 81.066666-81.066666l12.8-42.666667c4.266667-12.8 17.066667-25.6 29.866667-25.6 12.8 0 25.6 8.533333 29.866667 25.6l12.8 42.666667c8.533333 38.4 42.666667 72.533333 81.066666 81.066666l42.666667 12.8c12.8 4.266667 25.6 17.066667 25.6 29.866667 0 12.8-8.533333 25.6-25.6 29.866667l-42.666667 12.8c-38.4 8.533333-72.533333 42.666667-81.066666 81.066666l-12.8 42.666667c-4.266667 17.066667-17.066667 25.6-29.866667 25.6z m-64 512c-12.8 0-25.6-8.533333-29.866667-21.333333l-17.066666-51.2c-4.266667-17.066667-21.333333-34.133333-38.4-38.4l-51.2-17.066667c-12.8-4.266667-21.333333-17.066667-21.333334-29.866667 0-12.8 8.533333-25.6 21.333334-29.866666l51.2-17.066667c17.066667-4.266667 34.133333-21.333333 38.4-38.4l17.066666-51.2c4.266667-12.8 17.066667-21.333333 29.866667-21.333333 12.8 0 25.6 8.533333 29.866667 21.333333l17.066666 51.2c4.266667 17.066667 21.333333 34.133333 38.4 38.4l51.2 17.066667c12.8 4.266667 21.333333 17.066667 21.333334 29.866666 0 12.8-8.533333 25.6-21.333334 29.866667l-51.2 17.066667c-17.066667 4.266667-34.133333 21.333333-38.4 38.4l-17.066666 51.2c-4.266667 12.8-17.066667 21.333333-29.866667 21.333333z',
fill: 'currentColor',
}),
],
),
])
},
},
} }

View File

@ -79,7 +79,7 @@ defineExpose({
line-height: 24px; line-height: 24px;
&.active { &.active {
background: var(--el-color-primary-light-9); background: var(--el-color-primary-light-9);
border-radius: var(--app-border-radius-base); border-radius: var();
color: var(--el-color-primary); color: var(--el-color-primary);
font-weight: 500; font-weight: 500;
&:hover { &:hover {
@ -87,7 +87,7 @@ defineExpose({
} }
} }
&:hover { &:hover {
border-radius: var(--app-border-radius-base); border-radius: var();
background: var(--app-text-color-light-1); background: var(--app-text-color-light-1);
} }
&.is-active { &.is-active {

View File

@ -277,7 +277,7 @@ onUnmounted(() => {
margin-bottom: 4px; margin-bottom: 4px;
&.active { &.active {
background: var(--el-color-primary-light-9); background: var(--el-color-primary-light-9);
border-radius: var(--app-border-radius-base); border-radius: var();
color: var(--el-color-primary); color: var(--el-color-primary);
font-weight: 500; font-weight: 500;
&:hover { &:hover {
@ -285,7 +285,7 @@ onUnmounted(() => {
} }
} }
&:hover { &:hover {
border-radius: var(--app-border-radius-base); border-radius: var();
background: var(--app-text-color-light-1); background: var(--app-text-color-light-1);
} }
&.is-active { &.is-active {

View File

@ -131,7 +131,11 @@ export default {
}, },
mcp_output_enable: 'Output MCP/Tool Execution Process', mcp_output_enable: 'Output MCP/Tool Execution Process',
}, },
buttons: {}, generateDialog: {
label: 'Generate',
generatePrompt: 'Generate Prompt',
placeholder: 'Please enter the prompt topic',
},
dialog: { dialog: {
addKnowledge: 'Add Related Knowledge', addKnowledge: 'Add Related Knowledge',
addKnowledgePlaceholder: 'The selected knowledge must use the same embedding model', addKnowledgePlaceholder: 'The selected knowledge must use the same embedding model',

View File

@ -65,6 +65,7 @@ export default {
label: '系统角色', label: '系统角色',
placeholder: '你是 xxx 小助手', placeholder: '你是 xxx 小助手',
}, },
prompt: { prompt: {
label: '提示词', label: '提示词',
noReferences: ' (无引用知识库)', noReferences: ' (无引用知识库)',
@ -120,9 +121,13 @@ export default {
start: '开始', start: '开始',
end: '结束', end: '结束',
}, },
mcp_output_enable: '输出MCP/工具执行过程' mcp_output_enable: '输出MCP/工具执行过程',
},
generateDialog: {
label: '生成',
generatePrompt: '生成提示词',
placeholder: '请输入提示词主题',
}, },
dialog: { dialog: {
addKnowledge: '添加关联知识库', addKnowledge: '添加关联知识库',
addKnowledgePlaceholder: '所选知识库必须使用相同的 Embedding 模型', addKnowledgePlaceholder: '所选知识库必须使用相同的 Embedding 模型',

View File

@ -122,7 +122,11 @@ export default {
}, },
mcp_output_enable: '輸出MCP/工具執行過程', mcp_output_enable: '輸出MCP/工具執行過程',
}, },
generateDialog: {
label: '生成',
generatePrompt: '生成提示詞',
placeholder: '請輸入提示詞主題',
},
dialog: { dialog: {
addKnowledge: '新增關聯知識庫', addKnowledge: '新增關聯知識庫',
addKnowledgePlaceholder: '所選知識庫必須使用相同的 Embedding 模型', addKnowledgePlaceholder: '所選知識庫必須使用相同的 Embedding 模型',

View File

@ -315,14 +315,12 @@ h5 {
.border-b-light { .border-b-light {
border-bottom: 1px solid var(--el-border-color-lighter); border-bottom: 1px solid var(--el-border-color-lighter);
} }
.border-r-4 {
border-radius: var(--app-border-radius-small);
}
.border-r-6 { .border-r-6 {
border-radius: var(--app-border-radius-base); border-radius: var();
} }
.border-r-8 { .border-r-8 {
border-radius: var(--app-border-radius-large); border-radius: var(--app-border-radius-base);
} }
.border-t-dashed { .border-t-dashed {

View File

@ -111,6 +111,9 @@
} }
.el-dialog__header { .el-dialog__header {
padding: 16px 24px; padding: 16px 24px;
.el-dialog__headerbtn {
top: 8px;
}
} }
.el-dialog__body { .el-dialog__body {
border-top: 1px solid var(--el-border-color); border-top: 1px solid var(--el-border-color);

View File

@ -209,12 +209,13 @@
.el-dialog { .el-dialog {
--el-dialog-padding-primary: 24px; --el-dialog-padding-primary: 24px;
--el-dialog-border-radius: 8px; --el-dialog-border-radius: 8px;
--el-dialog-title-font-size: 16px;
.el-dialog__body { .el-dialog__body {
color: var(--el-text-color-primary); color: var(--el-text-color-primary);
} }
} }
.el-dialog__headerbtn { .el-dialog__headerbtn {
top: 8px; top: 12px;
right: 8px; right: 8px;
.el-dialog__close { .el-dialog__close {
font-size: 20px; font-size: 20px;

View File

@ -8,9 +8,9 @@
--app-view-padding: 24px; --app-view-padding: 24px;
--app-view-bg-color: #ffffff; --app-view-bg-color: #ffffff;
--app-border-color-dark: #bbbfc4; --app-border-color-dark: #bbbfc4;
--app-border-radius-small: 4px; --app-border-radius-small: 6px;
--app-border-radius-base: 6px; --app-border-radius-base: 8px;
--app-border-radius-large: 8px; --app-border-radius-large: 16px;
--md-bk-hover-color: var(--el-border-color-hover); --md-bk-hover-color: var(--el-border-color-hover);
/** header 组件 */ /** header 组件 */
--app-header-height: 56px; --app-header-height: 56px;

View File

@ -104,12 +104,13 @@
<div class="flex-between"> <div class="flex-between">
<span>{{ $t('views.application.form.roleSettings.label') }}</span> <span>{{ $t('views.application.form.roleSettings.label') }}</span>
<el-button <el-button
type="primary" type="primary"
link link
@click="handleGeneratePromptClick(applicationForm.model_id as string)" @click="openGeneratePromptDialog"
:disabled="!applicationForm.model_id" :disabled="!applicationForm.model_id"
> >
生成 <AppIcon iconName="app-generate-star" class="mr-4"></AppIcon>
{{ $t('views.application.generateDialog.label') }}
</el-button> </el-button>
</div> </div>
</template> </template>
@ -308,12 +309,15 @@
</el-form-item> </el-form-item>
<div <div
class="w-full mb-16" class="w-full mb-16"
v-if="applicationForm.mcp_tool_ids && v-if="
applicationForm.mcp_tool_ids.length > 0 || (applicationForm.mcp_servers && applicationForm.mcp_servers.length > 0) (applicationForm.mcp_tool_ids && applicationForm.mcp_tool_ids.length > 0) ||
(applicationForm.mcp_servers && applicationForm.mcp_servers.length > 0)
" "
> >
<template v-for="(item, index) in applicationForm.mcp_tool_ids" :key="index"> <template v-for="(item, index) in applicationForm.mcp_tool_ids" :key="index">
<div class="flex-between border border-r-6 white-bg mb-4" style="padding: 5px 8px" <div
class="flex-between border border-r-6 white-bg mb-4"
style="padding: 5px 8px"
v-if="relatedObject(mcpToolSelectOptions, item, 'id')" v-if="relatedObject(mcpToolSelectOptions, item, 'id')"
> >
<div class="flex align-center" style="line-height: 20px"> <div class="flex align-center" style="line-height: 20px">
@ -324,7 +328,10 @@
style="background: none" style="background: none"
class="mr-8" class="mr-8"
> >
<img :src="resetUrl(relatedObject(mcpToolSelectOptions, item, 'id')?.icon)" alt="" /> <img
:src="resetUrl(relatedObject(mcpToolSelectOptions, item, 'id')?.icon)"
alt=""
/>
</el-avatar> </el-avatar>
<ToolIcon v-else type="MCP" class="mr-8" :size="20" /> <ToolIcon v-else type="MCP" class="mr-8" :size="20" />
@ -361,14 +368,24 @@
> >
<AppIcon iconName="app-setting"></AppIcon> <AppIcon iconName="app-setting"></AppIcon>
</el-button> </el-button>
<el-switch class="ml-8" size="small" v-model="applicationForm.tool_enable" /> <el-switch
class="ml-8"
size="small"
v-model="applicationForm.tool_enable"
/>
</div>
</div> </div>
</div>
</template> </template>
</el-form-item> </el-form-item>
<div class="w-full mb-16" v-if="applicationForm.tool_ids && applicationForm.tool_ids.length > 0"> <div
class="w-full mb-16"
v-if="applicationForm.tool_ids && applicationForm.tool_ids.length > 0"
>
<template v-for="(item, index) in applicationForm.tool_ids" :key="index"> <template v-for="(item, index) in applicationForm.tool_ids" :key="index">
<div class="flex-between border border-r-6 white-bg mb-4" style="padding: 5px 8px"> <div
class="flex-between border border-r-6 white-bg mb-4"
style="padding: 5px 8px"
>
<div class="flex align-center" style="line-height: 20px"> <div class="flex align-center" style="line-height: 20px">
<el-avatar <el-avatar
v-if="relatedObject(toolSelectOptions, item, 'id')?.icon" v-if="relatedObject(toolSelectOptions, item, 'id')?.icon"
@ -377,11 +394,17 @@
style="background: none" style="background: none"
class="mr-8" class="mr-8"
> >
<img :src="resetUrl(relatedObject(toolSelectOptions, item, 'id')?.icon)" alt="" /> <img
:src="resetUrl(relatedObject(toolSelectOptions, item, 'id')?.icon)"
alt=""
/>
</el-avatar> </el-avatar>
<ToolIcon v-else class="mr-8" :size="20" /> <ToolIcon v-else class="mr-8" :size="20" />
<div class="ellipsis" :title="relatedObject(toolSelectOptions, item, 'id')?.name"> <div
class="ellipsis"
:title="relatedObject(toolSelectOptions, item, 'id')?.name"
>
{{ relatedObject(toolSelectOptions, item, 'id')?.name }} {{ relatedObject(toolSelectOptions, item, 'id')?.name }}
</div> </div>
</div> </div>
@ -558,7 +581,7 @@
</el-card> </el-card>
<AIModeParamSettingDialog ref="AIModeParamSettingDialogRef" @refresh="refreshForm" /> <AIModeParamSettingDialog ref="AIModeParamSettingDialogRef" @refresh="refreshForm" />
<GeneratePromptDialog @replace="replace " ref="GeneratePromptDialogRef" /> <GeneratePromptDialog @replace="replace" ref="GeneratePromptDialogRef" />
<TTSModeParamSettingDialog ref="TTSModeParamSettingDialogRef" @refresh="refreshTTSForm" /> <TTSModeParamSettingDialog ref="TTSModeParamSettingDialogRef" @refresh="refreshTTSForm" />
<ParamSettingDialog ref="ParamSettingDialogRef" @refresh="refreshParam" /> <ParamSettingDialog ref="ParamSettingDialogRef" @refresh="refreshParam" />
<AddKnowledgeDialog <AddKnowledgeDialog
@ -580,7 +603,7 @@ import { reactive, ref, onMounted, computed, onBeforeMount } from 'vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { groupBy, set } from 'lodash' import { groupBy, set } from 'lodash'
import AIModeParamSettingDialog from './component/AIModeParamSettingDialog.vue' import AIModeParamSettingDialog from './component/AIModeParamSettingDialog.vue'
import GeneratePromptDialog from './component/GeneratePrompt.vue' import GeneratePromptDialog from './component/GeneratePromptDialog.vue'
import ParamSettingDialog from './component/ParamSettingDialog.vue' import ParamSettingDialog from './component/ParamSettingDialog.vue'
import AddKnowledgeDialog from './component/AddKnowledgeDialog.vue' import AddKnowledgeDialog from './component/AddKnowledgeDialog.vue'
import type { FormInstance, FormRules } from 'element-plus' import type { FormInstance, FormRules } from 'element-plus'
@ -594,17 +617,15 @@ import permissionMap from '@/permission'
import { EditionConst } from '@/utils/permission/data' import { EditionConst } from '@/utils/permission/data'
import { hasPermission } from '@/utils/permission/index' import { hasPermission } from '@/utils/permission/index'
import { loadSharedApi } from '@/utils/dynamics-api/shared-api' import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
import { resetUrl } from "@/utils/common.ts"; import { resetUrl } from '@/utils/common.ts'
import McpServersDialog from "@/views/application/component/McpServersDialog.vue"; import McpServersDialog from '@/views/application/component/McpServersDialog.vue'
import ToolDialog from "@/views/application/component/ToolDialog.vue"; import ToolDialog from '@/views/application/component/ToolDialog.vue'
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const { const {
params: { id }, params: { id },
} = route as any } = route as any
const replace = (v: any) => {
applicationForm.value.model_setting.system=v
}
const apiType = computed(() => { const apiType = computed(() => {
if (route.path.includes('resource-management')) { if (route.path.includes('resource-management')) {
return 'systemManage' return 'systemManage'
@ -761,15 +782,16 @@ const openAIParamSettingDialog = () => {
} }
} }
const openGeneratePromptDialog = (modelId: string) => { const openGeneratePromptDialog = () => {
GeneratePromptDialogRef.value?.open(modelId) if (applicationForm.value.model_id) {
GeneratePromptDialogRef.value?.open(applicationForm.value.model_id)
}
} }
const handleGeneratePromptClick = (model_id:string) => { const replace = (v: any) => {
openGeneratePromptDialog(model_id) applicationForm.value.model_setting.system = v
} }
const openReasoningParamSettingDialog = () => { const openReasoningParamSettingDialog = () => {
ReasoningParamSettingDialogRef.value?.open(applicationForm.value.model_setting) ReasoningParamSettingDialogRef.value?.open(applicationForm.value.model_setting)
} }

View File

@ -1,72 +1,82 @@
<template> <template>
<el-dialog align-center :title="$t('生成提示词')" v-model="dialogVisible" <el-dialog
style="width: 600px"> align-center
:title="$t('views.application.generateDialog.generatePrompt')"
<div> v-model="dialogVisible"
<div class="dialog-bg"> style="width: 600px"
<div class="scrollbar-height"> append-to-body
<!-- 生成内容 --> >
<div style="height: 600px;"> <div class="generate-prompt-dialog-bg border-r-8">
<el-card shadow="always" class="mb-8 border-r-8" :style="{ <div class="scrollbar-height">
'--el-card-padding': '6px 16px', <!-- 生成内容 -->
'min-height': answer ? 'auto' : '120px' <div class="p-16 pb-0 lighter">
}"> <el-scrollbar>
<div> <div v-if="answer" class="pre-wrap lighter" style="max-height: calc(100vh - 400px)">
{{ answer }} {{ answer }}
</div>
</el-card>
<div>
<el-button type="primary" @click="() => emit('replace', answer)">
替换
</el-button>
<el-button type="primary" @click="reAnswerClick" :disabled="!answer || loading" :loading="loading">
重新生成
</el-button>
</div> </div>
<p v-else-if="loading" shadow="always" style="margin: 0.5rem 0">
<el-icon class="is-loading color-primary mr-4"><Loading /></el-icon>
{{ $t('chat.tip.answerLoading') }}
<span class="dotting"></span>
</p>
<p v-else class="flex align-center">
<AppIcon iconName="app-generate-star" class="color-primary mr-4"></AppIcon>
提示词显示在这里
</p>
</el-scrollbar>
<div v-if="answer && !loading">
<el-button type="primary" @click="() => emit('replace', answer)"> 替换 </el-button>
<el-button @click="reAnswerClick" :disabled="!answer || loading" :loading="loading">
重新生成
</el-button>
</div>
</div>
<!-- 文本输入框 -->
<div class="generate-prompt-operate p-16">
<div class="text-center mb-8" v-if="loading">
<el-button class="border-primary video-stop-button" @click="stopChat">
<app-icon iconName="app-video-stop" class="mr-8"></app-icon>
{{ $t('chat.operation.stopChat') }}
</el-button>
</div> </div>
<!-- 文本输入框 --> <div class="operate-textarea">
<div> <el-input
<div class="ai-chat__operate p-16"> ref="quickInputRef"
<div class="text-center mb-8" v-if="loading"> v-model="inputValue"
<el-button class="border-primary video-stop-button" @click="stopChat"> :autosize="{ minRows: 1, maxRows: 10 }"
<app-icon iconName="app-video-stop" class="mr-8"></app-icon> type="textarea"
停止对话 :placeholder="$t('views.application.generateDialog.placeholder')"
:maxlength="100000"
class="chat-operate-textarea"
/>
<div class="operate">
<div class="text-right">
<el-button
text
class="sent-button"
:disabled="!inputValue.trim() || loading"
@click="handleSubmit"
>
<img v-show="!inputValue.trim() || loading" src="@/assets/icon_send.svg" alt="" />
<SendIcon v-show="inputValue.trim() && !loading" />
</el-button> </el-button>
</div> </div>
<div class="operate-textarea">
<el-input ref="quickInputRef" v-model="inputValue" :autosize="{ minRows: 1, maxRows: 10 }"
type="textarea" placeholder="请输入您的问题..." :maxlength="100000"
class="chat-operate-textarea" />
<div class="operate flex-between">
<div>
<slot name="userInput" />
</div>
<div class="flex align-center">
<el-button text class="sent-button" :disabled="!inputValue.trim() || loading" @click="handleSubmit">
<img v-show="!inputValue.trim() || loading" src="@/assets/icon_send.svg" alt="" />
<SendIcon v-show="inputValue.trim() && !loading" />
</el-button>
</div>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</el-dialog> </el-dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, reactive, ref } from 'vue' import { computed, reactive, ref } from 'vue'
import generatePromptAPI from '@/api/application/application' import generatePromptAPI from '@/api/application/application'
import useStore from '@/stores'; import useStore from '@/stores'
const emit = defineEmits(['replace']) const emit = defineEmits(['replace'])
const { user } = useStore() const { user } = useStore()
@ -111,11 +121,9 @@ const promptTemplates = {
描述角色在互动过程中需要遵循的限制条件1 描述角色在互动过程中需要遵循的限制条件1
描述角色在互动过程中需要遵循的限制条件2 描述角色在互动过程中需要遵循的限制条件2
描述角色在互动过程中需要遵循的限制条件3 描述角色在互动过程中需要遵循的限制条件3
` `,
} }
/** /**
* 获取一个递归函数,处理流式数据 * 获取一个递归函数,处理流式数据
* @param chat 每一条对话记录 * @param chat 每一条对话记录
@ -124,7 +132,7 @@ const promptTemplates = {
*/ */
const getWrite = (reader: any) => { const getWrite = (reader: any) => {
let tempResult = '' let tempResult = ''
const answer = reactive({ content: '', 'role': 'ai' }) const answer = reactive({ content: '', role: 'ai' })
chatMessages.value.push(answer) chatMessages.value.push(answer)
/** /**
* *
@ -184,21 +192,18 @@ const answer = computed(() => {
return '' return ''
}) })
function generatePrompt(inputValue: any) { function generatePrompt(inputValue: any) {
loading.value = true loading.value = true
const workspaceId = user.getWorkspaceId() || 'default' const workspaceId = user.getWorkspaceId() || 'default'
chatMessages.value.push({ content: inputValue, role: 'user' }) chatMessages.value.push({ content: inputValue, role: 'user' })
const requestData = { const requestData = {
messages: chatMessages.value, messages: chatMessages.value,
prompt: promptTemplates.INIT_TEMPLATE prompt: promptTemplates.INIT_TEMPLATE,
} }
generatePromptAPI.generate_prompt( generatePromptAPI.generate_prompt(workspaceId, modelID.value, requestData).then((response) => {
workspaceId, modelID.value, requestData).then(response => { const reader = response.body.getReader()
const reader = response.body.getReader() reader.read().then(getWrite(reader))
reader.read().then(getWrite(reader)) })
})
} }
// //
@ -206,7 +211,6 @@ const reAnswerClick = () => {
if (originalUserInput.value) { if (originalUserInput.value) {
generatePrompt('结果不满意,请按照格式,重新生成') generatePrompt('结果不满意,请按照格式,重新生成')
} }
} }
const handleSubmit = () => { const handleSubmit = () => {
@ -217,14 +221,11 @@ const handleSubmit = () => {
inputValue.value = '' inputValue.value = ''
} }
const stopChat = () => { const stopChat = () => {
loading.value = false loading.value = false
chatMessages.value = [] chatMessages.value = []
} }
const open = (modelId: string) => { const open = (modelId: string) => {
modelID.value = modelId modelID.value = modelId
dialogVisible.value = true dialogVisible.value = true
@ -233,111 +234,75 @@ const open = (modelId: string) => {
} }
defineExpose({ defineExpose({
open open,
}) })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.dialog-bg { .generate-prompt-dialog-bg {
border-radius: 8px;
background: var(--dialog-bg-gradient-color); background: var(--dialog-bg-gradient-color);
overflow: hidden; overflow: hidden;
box-sizing: border-box; box-sizing: border-box;
} }
.ai-chat { .generate-prompt-operate {
&__operate { position: relative;
position: relative; width: 100%;
width: 100%; box-sizing: border-box;
z-index: 10;
:deep(.operate-textarea) {
box-shadow: 0px 6px 24px 0px rgba(31, 35, 41, 0.08);
background-color: #ffffff;
border-radius: var(--app-border-radius-large);
border: 1px solid #ffffff;
box-sizing: border-box; box-sizing: border-box;
z-index: 10;
:deep(.operate-textarea) { &:has(.el-textarea__inner:focus) {
box-shadow: 0px 6px 24px 0px rgba(31, 35, 41, 0.08); border: 1px solid var(--el-color-primary);
background-color: #ffffff; }
border-radius: 8px;
border: 1px solid #ffffff; .el-textarea__inner {
border-radius: var(--app-border-radius-large) !important;
box-shadow: none;
resize: none;
padding: 13px 16px;
box-sizing: border-box; box-sizing: border-box;
min-height: 47px !important;
&:has(.el-textarea__inner:focus) { height: 0;
border: 1px solid var(--el-color-primary);
}
.el-textarea__inner {
border-radius: 8px !important;
box-shadow: none;
resize: none;
padding: 13px 16px;
box-sizing: border-box;
min-height: 47px !important;
height: 0;
}
.operate {
padding: 6px 10px;
.el-icon {
font-size: 20px;
}
.sent-button {
max-height: none;
.el-icon {
font-size: 24px;
}
}
.el-loading-spinner {
margin-top: -15px;
.circular {
width: 31px;
height: 31px;
}
}
}
} }
.file-image { .operate {
position: relative; padding: 6px 10px;
overflow: inherit;
.delete-icon {
position: absolute;
right: -5px;
top: -5px;
z-index: 1;
}
}
.upload-tooltip-width {
width: 300px;
}
}
}
@media only screen and (max-width: 768px) {
.ai-chat {
&__operate {
position: fixed;
bottom: 0;
font-size: 1rem;
.el-icon { .el-icon {
font-size: 1.4rem !important; font-size: 20px;
}
.sent-button {
max-height: none;
.el-icon {
font-size: 24px;
}
}
.el-loading-spinner {
margin-top: -15px;
.circular {
width: 31px;
height: 31px;
}
} }
} }
} }
} .video-stop-button {
box-shadow: 0px 6px 24px 0px rgba(31, 35, 41, 0.08);
.popperUserInput { &:hover {
position: absolute; background: #ffffff;
z-index: 999; }
left: 0; }
bottom: 50px;
width: calc(100% - 50px);
max-width: 400px;
} }
</style> </style>

View File

@ -160,12 +160,12 @@ const handleSharedNodeClick = () => {
padding: 10px 8px; padding: 10px 8px;
font-weight: 400; font-weight: 400;
&:hover { &:hover {
border-radius: var(--app-border-radius-base); border-radius: var();
background: var(--app-text-color-light-1); background: var(--app-text-color-light-1);
} }
} }
.all-mode-active { .all-mode-active {
border-radius: var(--app-border-radius-base); border-radius: var();
color: var(--el-color-primary); color: var(--el-color-primary);
font-weight: 500 !important; font-weight: 500 !important;
background: var(--el-color-primary-light-9); background: var(--el-color-primary-light-9);
@ -185,7 +185,7 @@ const handleSharedNodeClick = () => {
background: none; background: none;
&:hover { &:hover {
background: var(--app-text-color-light-1); background: var(--app-text-color-light-1);
border-radius: var(--app-border-radius-base); border-radius: var();
} }
} }
:deep(.el-collapse-item) { :deep(.el-collapse-item) {
@ -211,7 +211,7 @@ const handleSharedNodeClick = () => {
margin-bottom: 4px; margin-bottom: 4px;
&.active { &.active {
background: var(--el-color-primary-light-9); background: var(--el-color-primary-light-9);
border-radius: var(--app-border-radius-base); border-radius: var();
color: var(--el-color-primary); color: var(--el-color-primary);
font-weight: 500; font-weight: 500;
&:hover { &:hover {
@ -219,7 +219,7 @@ const handleSharedNodeClick = () => {
} }
} }
&:hover { &:hover {
border-radius: var(--app-border-radius-base); border-radius: var();
background: var(--app-text-color-light-1); background: var(--app-text-color-light-1);
} }
&.is-active { &.is-active {

View File

@ -94,7 +94,7 @@
</el-space> </el-space>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="$t('common.operation')" align="left"> <el-table-column :label="$t('views.model.modelForm.permissionType.label')" align="left">
<template #default="{ row }"> <template #default="{ row }">
<el-radio-group <el-radio-group
v-model="row.permission" v-model="row.permission"
@ -154,7 +154,7 @@ const props = defineProps<{
}>() }>()
const emit = defineEmits(['submitPermissions']) const emit = defineEmits(['submitPermissions'])
const permissionOptions = computed(() => { const permissionOptions = computed(() => {
return getPermissionOptions() return getPermissionOptions()
}) })
const permissionObj = ref<any>({ const permissionObj = ref<any>({

View File

@ -54,6 +54,19 @@
</el-form-item> </el-form-item>
<el-form-item :label="$t('views.application.form.roleSettings.label')"> <el-form-item :label="$t('views.application.form.roleSettings.label')">
<template #label>
<div class="flex-between">
<span>{{ $t('views.application.form.roleSettings.label') }}</span>
<el-button
type="primary"
link
@click="openGeneratePromptDialog(chat_data.model_id)"
:disabled="!chat_data.model_id"
>
<AppIcon iconName="app-generate-star"></AppIcon>
</el-button>
</div>
</template>
<MdEditorMagnify <MdEditorMagnify
:title="$t('views.application.form.roleSettings.label')" :title="$t('views.application.form.roleSettings.label')"
v-model="chat_data.system" v-model="chat_data.system"
@ -134,11 +147,14 @@
<div <div
class="w-full mb-16" class="w-full mb-16"
v-if=" v-if="
chat_data.mcp_tool_ids?.length > 0 || (chat_data.mcp_servers && chat_data.mcp_servers.length > 0) chat_data.mcp_tool_ids?.length > 0 ||
(chat_data.mcp_servers && chat_data.mcp_servers.length > 0)
" "
> >
<template v-for="(item, index) in chat_data.mcp_tool_ids" :key="index"> <template v-for="(item, index) in chat_data.mcp_tool_ids" :key="index">
<div class="flex-between border border-r-6 white-bg mb-4" style="padding: 5px 8px" <div
class="flex-between border border-r-6 white-bg mb-4"
style="padding: 5px 8px"
v-if="relatedObject(mcpToolSelectOptions, item, 'id')" v-if="relatedObject(mcpToolSelectOptions, item, 'id')"
> >
<div class="flex align-center" style="line-height: 20px"> <div class="flex align-center" style="line-height: 20px">
@ -149,7 +165,10 @@
style="background: none" style="background: none"
class="mr-8" class="mr-8"
> >
<img :src="resetUrl(relatedObject(mcpToolSelectOptions, item, 'id')?.icon)" alt="" /> <img
:src="resetUrl(relatedObject(mcpToolSelectOptions, item, 'id')?.icon)"
alt=""
/>
</el-avatar> </el-avatar>
<ToolIcon v-else type="MCP" class="mr-8" :size="20" /> <ToolIcon v-else type="MCP" class="mr-8" :size="20" />
@ -218,11 +237,7 @@
{{ $t('views.application.form.mcp_output_enable') }} {{ $t('views.application.form.mcp_output_enable') }}
</span> </span>
<div class="flex"> <div class="flex">
<el-switch <el-switch class="ml-8" size="small" v-model="chat_data.mcp_output_enable" />
class="ml-8"
size="small"
v-model="chat_data.mcp_output_enable"
/>
</div> </div>
</div> </div>
</template> </template>
@ -274,6 +289,7 @@
</el-card> </el-card>
<AIModeParamSettingDialog ref="AIModeParamSettingDialogRef" @refresh="refreshParam" /> <AIModeParamSettingDialog ref="AIModeParamSettingDialogRef" @refresh="refreshParam" />
<GeneratePromptDialog @replace="replace" ref="GeneratePromptDialogRef" />
<ReasoningParamSettingDialog <ReasoningParamSettingDialog
ref="ReasoningParamSettingDialogRef" ref="ReasoningParamSettingDialogRef"
@refresh="submitReasoningDialog" @refresh="submitReasoningDialog"
@ -289,6 +305,7 @@ import type { FormInstance } from 'element-plus'
import { ref, computed, onMounted, inject } from 'vue' import { ref, computed, onMounted, inject } from 'vue'
import { isLastNode } from '@/workflow/common/data' import { isLastNode } from '@/workflow/common/data'
import AIModeParamSettingDialog from '@/views/application/component/AIModeParamSettingDialog.vue' import AIModeParamSettingDialog from '@/views/application/component/AIModeParamSettingDialog.vue'
import GeneratePromptDialog from '@/views/application/component/GeneratePromptDialog.vue'
import { t } from '@/locales' import { t } from '@/locales'
import ReasoningParamSettingDialog from '@/views/application/component/ReasoningParamSettingDialog.vue' import ReasoningParamSettingDialog from '@/views/application/component/ReasoningParamSettingDialog.vue'
import ToolDialog from '@/views/application/component/ToolDialog.vue' import ToolDialog from '@/views/application/component/ToolDialog.vue'
@ -419,6 +436,15 @@ const openAIParamSettingDialog = (modelId: string) => {
} }
} }
const GeneratePromptDialogRef = ref<InstanceType<typeof GeneratePromptDialog>>()
const openGeneratePromptDialog = (modelId: string) => {
if (modelId) {
GeneratePromptDialogRef.value?.open(modelId)
}
}
const replace = (v: any) => {
set(props.nodeModel.properties.node_data.model_setting, 'system', v)
}
const openReasoningParamSettingDialog = () => { const openReasoningParamSettingDialog = () => {
ReasoningParamSettingDialogRef.value?.open(chat_data.value.model_setting) ReasoningParamSettingDialogRef.value?.open(chat_data.value.model_setting)
} }
@ -528,11 +554,13 @@ onMounted(() => {
} }
if (props.nodeModel.properties.node_data?.mcp_tool_id) { if (props.nodeModel.properties.node_data?.mcp_tool_id) {
set(props.nodeModel.properties.node_data, 'mcp_tool_ids', [props.nodeModel.properties.node_data?.mcp_tool_id]) set(props.nodeModel.properties.node_data, 'mcp_tool_ids', [
set(props.nodeModel.properties.node_data, 'mcp_tool_id', undefined) props.nodeModel.properties.node_data?.mcp_tool_id,
])
set(props.nodeModel.properties.node_data, 'mcp_tool_id', undefined)
} }
if (props.nodeModel.properties.node_data?.mcp_output_enable === undefined) { if (props.nodeModel.properties.node_data?.mcp_output_enable === undefined) {
set(props.nodeModel.properties.node_data, 'mcp_output_enable', true) set(props.nodeModel.properties.node_data, 'mcp_output_enable', true)
} }
getToolSelectOptions() getToolSelectOptions()