feat: workflow application debug chat (#3245)

This commit is contained in:
shaohuzhang1 2025-06-12 21:10:10 +08:00 committed by GitHub
parent c7e30bb098
commit bf630b9d07
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 145 additions and 118 deletions

View File

@ -82,7 +82,7 @@ class WorkFlowPostHandler:
index=0) index=0)
self.chat_info.append_chat_record(chat_record) self.chat_info.append_chat_record(chat_record)
self.chat_info.set_cahce() self.chat_info.set_cache()
if [ChatUserType.ANONYMOUS_USER.value, ChatUserType.CHAT_USER.value].__contains__( if [ChatUserType.ANONYMOUS_USER.value, ChatUserType.CHAT_USER.value].__contains__(
workflow_body.get('chat_user_type')): workflow_body.get('chat_user_type')):
application_public_access_client = (QuerySet(ApplicationChatUserStats) application_public_access_client = (QuerySet(ApplicationChatUserStats)

View File

@ -219,12 +219,17 @@ class ChatSerializers(serializers.Serializer):
other_list = instance.get('other_list') other_list = instance.get('other_list')
workspace_id = chat_info.application.workspace_id workspace_id = chat_info.application.workspace_id
chat_record_id = instance.get('chat_record_id') chat_record_id = instance.get('chat_record_id')
debug = self.data.get('debug', False)
chat_record = None chat_record = None
history_chat_record = chat_info.chat_record_list history_chat_record = chat_info.chat_record_list
if chat_record_id is not None: if chat_record_id is not None:
chat_record = self.get_chat_record(chat_info, chat_record_id) chat_record = self.get_chat_record(chat_info, chat_record_id)
history_chat_record = [r for r in chat_info.chat_record_list if str(r.id) != chat_record_id] history_chat_record = [r for r in chat_info.chat_record_list if str(r.id) != chat_record_id]
work_flow_manage = WorkflowManage(Flow.new_instance(chat_info.work_flow_version.work_flow), if not debug:
work_flow = chat_info.work_flow_version.work_flow
else:
work_flow = chat_info.application.work_flow
work_flow_manage = WorkflowManage(Flow.new_instance(work_flow),
{'history_chat_record': history_chat_record, 'question': message, {'history_chat_record': history_chat_record, 'question': message,
'chat_id': chat_info.chat_id, 'chat_record_id': str( 'chat_id': chat_info.chat_id, 'chat_record_id': str(
uuid.uuid1()) if chat_record is None else chat_record.id, uuid.uuid1()) if chat_record is None else chat_record.id,
@ -233,7 +238,7 @@ class ChatSerializers(serializers.Serializer):
'chat_user_id': chat_user_id, 'chat_user_id': chat_user_id,
'chat_user_type': chat_user_type, 'chat_user_type': chat_user_type,
'workspace_id': workspace_id, 'workspace_id': workspace_id,
'debug': self.data.get('debug', False)}, 'debug': debug},
WorkFlowPostHandler(chat_info), WorkFlowPostHandler(chat_info),
base_to_response, form_data, image_list, document_list, audio_list, base_to_response, form_data, image_list, document_list, audio_list,
other_list, other_list,
@ -339,12 +344,14 @@ class OpenChatSerializers(serializers.Serializer):
chat_user_type = self.data.get("chat_user_type") chat_user_type = self.data.get("chat_user_type")
debug = self.data.get("debug") debug = self.data.get("debug")
chat_id = str(uuid.uuid7()) chat_id = str(uuid.uuid7())
work_flow_version = QuerySet(WorkFlowVersion).filter(application_id=application_id).order_by( work_flow_version = None
'-create_time')[0:1].first() if not debug:
if work_flow_version is None: work_flow_version = QuerySet(WorkFlowVersion).filter(application_id=application_id).order_by(
raise AppApiException(500, '-create_time')[0:1].first()
gettext( if work_flow_version is None:
"The application has not been published. Please use it after publishing.")) raise AppApiException(500,
gettext(
"The application has not been published. Please use it after publishing."))
ChatInfo(chat_id, chat_user_id, chat_user_type, [], ChatInfo(chat_id, chat_user_id, chat_user_type, [],
[], [],
application_id, application_id,

View File

@ -17,8 +17,8 @@
"@codemirror/lang-json": "^6.0.1", "@codemirror/lang-json": "^6.0.1",
"@codemirror/lang-python": "^6.2.1", "@codemirror/lang-python": "^6.2.1",
"@codemirror/theme-one-dark": "^6.1.2", "@codemirror/theme-one-dark": "^6.1.2",
"@logicflow/core": "^2.0.15", "@logicflow/core": "^1.2.27",
"@logicflow/extension": "^2.0.20", "@logicflow/extension": "^1.2.27",
"@vavt/cm-extension": "^1.9.1", "@vavt/cm-extension": "^1.9.1",
"@vueuse/core": "^13.3.0", "@vueuse/core": "^13.3.0",
"@wecom/jssdk": "^2.3.1", "@wecom/jssdk": "^2.3.1",

View File

@ -22,60 +22,55 @@ const getModel: (
return get(`${prefix}/model`, data, loading) return get(`${prefix}/model`, data, loading)
} }
/** /**
* 使 *
* @param application_id * @param loading
* @param loading * @returns
* @query { query_text: string, top_number: number, similarity: number }
* @returns
*/ */
const getApplicationRerankerModel: ( const getRerankerModel: (loading?: Ref<boolean>) => Promise<Result<Array<any>>> = (loading) => {
application_id: string,
loading?: Ref<boolean>,
) => Promise<Result<Array<any>>> = (application_id, loading) => {
return get(`${prefix}/model`, { model_type: 'RERANKER' }, loading) return get(`${prefix}/model`, { model_type: 'RERANKER' }, loading)
} }
/** /**
* 使 *
* @param application_id
* @param loading * @param loading
* @query { query_text: string, top_number: number, similarity: number } * @returns
* @returns
*/ */
const getApplicationSTTModel: ( const getSTTModel: (loading?: Ref<boolean>) => Promise<Result<Array<any>>> = (loading) => {
application_id: string,
loading?: Ref<boolean>,
) => Promise<Result<Array<any>>> = (application_id, loading) => {
return get(`${prefix}/model`, { model_type: 'STT' }, loading) return get(`${prefix}/model`, { model_type: 'STT' }, loading)
} }
/** /**
* 使 *
* @param application_id
* @param loading * @param loading
* @query { query_text: string, top_number: number, similarity: number }
* @returns * @returns
*/ */
const getApplicationTTSModel: ( const getTTSModel: (loading?: Ref<boolean>) => Promise<Result<Array<any>>> = (loading) => {
application_id: string,
loading?: Ref<boolean>,
) => Promise<Result<Array<any>>> = (application_id, loading) => {
return get(`${prefix}/model`, { model_type: 'TTS' }, loading) return get(`${prefix}/model`, { model_type: 'TTS' }, loading)
} }
/**
const getApplicationImageModel: ( *
application_id: string, * @param loading
loading?: Ref<boolean>, * @returns
) => Promise<Result<Array<any>>> = (application_id, loading) => { */
const getImageModel: (loading?: Ref<boolean>) => Promise<Result<Array<any>>> = (loading) => {
return get(`${prefix}/model`, { model_type: 'IMAGE' }, loading) return get(`${prefix}/model`, { model_type: 'IMAGE' }, loading)
} }
/**
const getApplicationTTIModel: ( *
application_id: string, * @param loading
loading?: Ref<boolean>, * @returns
) => Promise<Result<Array<any>>> = (application_id, loading) => { */
const getTTIModel: (loading?: Ref<boolean>) => Promise<Result<Array<any>>> = (loading) => {
return get(`${prefix}/model`, { model_type: 'TTI' }, loading) return get(`${prefix}/model`, { model_type: 'TTI' }, loading)
} }
/**
*
* @param loading
* @returns
*/
const getLLMModel: (loading?: Ref<boolean>) => Promise<Result<Array<any>>> = (loading) => {
return get(`${prefix}/model`, { model_type: 'LLM' }, loading)
}
/** /**
* *
* @param model_id id * @param model_id id
@ -182,9 +177,10 @@ export default {
pauseDownload, pauseDownload,
getModelParamsForm, getModelParamsForm,
updateModelParamsForm, updateModelParamsForm,
getApplicationRerankerModel, getRerankerModel,
getApplicationSTTModel, getSTTModel,
getApplicationTTSModel, getTTSModel,
getApplicationImageModel, getImageModel,
getApplicationTTIModel, getTTIModel,
getLLMModel,
} }

View File

@ -0,0 +1,31 @@
import type { App } from 'vue'
export default {
install: (app: App) => {
app.directive('resize', {
created(el: any, binding: any) {
// 记录长宽
let width = ''
let height = ''
function getSize() {
const style = (document.defaultView as any).getComputedStyle(el)
// 如果当前长宽和历史长宽不同
if (width !== style.width || height !== style.height) {
// binding.value在这里就是下面的resizeChart函数
binding.value({
width: parseFloat(style.width),
height: parseFloat(style.height)
})
}
width = style.width
height = style.height
}
;(el as any).__vueDomResize__ = setInterval(getSize, 500)
},
unmounted(el: any, binding: any) {
clearInterval((el as any).__vueDomResize__)
}
})
}
}

View File

@ -673,7 +673,7 @@ function getKnowledge() {
function getModel() { function getModel() {
loading.value = true loading.value = true
modelAPI modelAPI
.getModel({}) .getLLMModel()
.then((res: any) => { .then((res: any) => {
modelOptions.value = groupBy(res?.data, 'provider') modelOptions.value = groupBy(res?.data, 'provider')
loading.value = false loading.value = false
@ -686,7 +686,7 @@ function getModel() {
function getSTTModel() { function getSTTModel() {
loading.value = true loading.value = true
modelAPI modelAPI
.getApplicationSTTModel(id) .getSTTModel()
.then((res: any) => { .then((res: any) => {
sttModelOptions.value = groupBy(res?.data, 'provider') sttModelOptions.value = groupBy(res?.data, 'provider')
loading.value = false loading.value = false
@ -699,7 +699,7 @@ function getSTTModel() {
function getTTSModel() { function getTTSModel() {
loading.value = true loading.value = true
modelAPI modelAPI
.getApplicationTTSModel(id) .getTTSModel()
.then((res: any) => { .then((res: any) => {
ttsModelOptions.value = groupBy(res?.data, 'provider') ttsModelOptions.value = groupBy(res?.data, 'provider')
loading.value = false loading.value = false

View File

@ -144,8 +144,8 @@
{ {
required: true, required: true,
message: $t('common.inputPlaceholder'), message: $t('common.inputPlaceholder'),
trigger: 'blur' trigger: 'blur',
} },
]" ]"
> >
<el-input v-model="form.title" @blur="form.title = form.title.trim()" /> <el-input v-model="form.title" @blur="form.title = form.title.trim()" />
@ -176,7 +176,7 @@ import { MsgError, MsgConfirm } from '@/utils/message'
import type { FormInstance } from 'element-plus' import type { FormInstance } from 'element-plus'
import { t } from '@/locales' import { t } from '@/locales'
const { const {
params: { id } params: { id },
} = app.config.globalProperties.$route as any } = app.config.globalProperties.$route as any
const height = ref<{ const height = ref<{
@ -186,14 +186,14 @@ const height = ref<{
}>({ }>({
stepContainerHeight: 0, stepContainerHeight: 0,
inputContainerHeight: 0, inputContainerHeight: 0,
outputContainerHeight: 0 outputContainerHeight: 0,
}) })
const showAnchor = ref<boolean>(false) const showAnchor = ref<boolean>(false)
const anchorData = ref<any>() const anchorData = ref<any>()
const titleFormRef = ref() const titleFormRef = ref()
const nodeNameDialogVisible = ref<boolean>(false) const nodeNameDialogVisible = ref<boolean>(false)
const form = ref<any>({ const form = ref<any>({
title: '' title: '',
}) })
const condition = computed({ const condition = computed({
@ -206,7 +206,7 @@ const condition = computed({
} }
set(props.nodeModel.properties, 'condition', 'AND') set(props.nodeModel.properties, 'condition', 'AND')
return true return true
} },
}) })
const showNode = computed({ const showNode = computed({
set: (v) => { set: (v) => {
@ -218,7 +218,7 @@ const showNode = computed({
} }
set(props.nodeModel.properties, 'showNode', true) set(props.nodeModel.properties, 'showNode', true)
return true return true
} },
}) })
const handleWheel = (event: any) => { const handleWheel = (event: any) => {
@ -244,7 +244,7 @@ const editName = async (formEl: FormInstance | undefined) => {
if (valid) { if (valid) {
if ( if (
!props.nodeModel.graphModel.nodes?.some( !props.nodeModel.graphModel.nodes?.some(
(node: any) => node.properties.stepName === form.value.title (node: any) => node.properties.stepName === form.value.title,
) )
) { ) {
set(props.nodeModel.properties, 'stepName', form.value.title) set(props.nodeModel.properties, 'stepName', form.value.title)
@ -274,7 +274,7 @@ const copyNode = () => {
const deleteNode = () => { const deleteNode = () => {
MsgConfirm(t('common.tip'), t('views.applicationWorkflow.delete.confirmTitle'), { MsgConfirm(t('common.tip'), t('views.applicationWorkflow.delete.confirmTitle'), {
confirmButtonText: t('common.confirm'), confirmButtonText: t('common.confirm'),
confirmButtonClass: 'danger' confirmButtonClass: 'danger',
}).then(() => { }).then(() => {
props.nodeModel.graphModel.deleteNode(props.nodeModel.id) props.nodeModel.graphModel.deleteNode(props.nodeModel.id)
}) })
@ -295,13 +295,13 @@ function clickNodes(item: any) {
type: item.type, type: item.type,
properties: item.properties, properties: item.properties,
x: anchorData.value?.x + width / 2 + 200, x: anchorData.value?.x + width / 2 + 200,
y: anchorData.value?.y - item.height y: anchorData.value?.y - item.height,
}) })
props.nodeModel.graphModel.addEdge({ props.nodeModel.graphModel.addEdge({
type: 'app-edge', type: 'app-edge',
sourceNodeId: props.nodeModel.id, sourceNodeId: props.nodeModel.id,
sourceAnchorId: anchorData.value?.id, sourceAnchorId: anchorData.value?.id,
targetNodeId: nodeModel.id targetNodeId: nodeModel.id,
}) })
closeNodeMenu() closeNodeMenu()
@ -317,7 +317,7 @@ const nodeFields = computed(() => {
label: field.label, label: field.label,
value: field.value, value: field.value,
globeLabel: `{{${props.nodeModel.properties.stepName}.${field.value}}}`, globeLabel: `{{${props.nodeModel.properties.stepName}.${field.value}}}`,
globeValue: `{{context['${props.nodeModel.id}'].${field.value}}}` globeValue: `{{context['${props.nodeModel.id}'].${field.value}}}`,
} }
}) })
return fields return fields
@ -364,4 +364,9 @@ onMounted(() => {
:deep(.el-card) { :deep(.el-card) {
overflow: visible; overflow: visible;
} }
.app-card {
background: #fff;
border-radius: 8px;
box-shadow: 0px 2px 4px 0px rgba(31, 35, 41, 0.12);
}
</style> </style>

View File

@ -11,7 +11,7 @@ import AppEdge from './common/edge'
import Control from './common/NodeControl.vue' import Control from './common/NodeControl.vue'
import { baseNodes } from '@/workflow/common/data' import { baseNodes } from '@/workflow/common/data'
import '@logicflow/extension/lib/style/index.css' import '@logicflow/extension/lib/style/index.css'
import '@logicflow/core/dist/index.css' import '@logicflow/core/dist/style/index.css'
import { initDefaultShortcut } from '@/workflow/common/shortcut' import { initDefaultShortcut } from '@/workflow/common/shortcut'
import Dagre from '@/workflow/plugins/dagre' import Dagre from '@/workflow/plugins/dagre'
import { getTeleport } from '@/workflow/common/teleport' import { getTeleport } from '@/workflow/common/teleport'
@ -32,11 +32,11 @@ type ShapeItem = {
} }
const props = defineProps({ const props = defineProps({
data: Object || null data: Object || null,
}) })
const defaultData = { const defaultData = {
nodes: [...baseNodes] nodes: [...baseNodes],
} }
const graphData = computed({ const graphData = computed({
get: () => { get: () => {
@ -48,7 +48,7 @@ const graphData = computed({
}, },
set: (value) => { set: (value) => {
return value return value
} },
}) })
const lf = ref() const lf = ref()
@ -67,27 +67,27 @@ const renderGraphData = (data?: any) => {
adjustEdge: false, adjustEdge: false,
adjustEdgeStartAndEnd: false, adjustEdgeStartAndEnd: false,
background: { background: {
backgroundColor: '#f5f6f7' backgroundColor: '#f5f6f7',
}, },
grid: { grid: {
size: 10, size: 10,
type: 'dot', type: 'dot',
config: { config: {
color: '#DEE0E3', color: '#DEE0E3',
thickness: 1 thickness: 1,
} },
}, },
keyboard: { keyboard: {
enabled: true enabled: true,
}, },
isSilentMode: false, isSilentMode: false,
container: container container: container,
}) })
lf.value.setTheme({ lf.value.setTheme({
bezier: { bezier: {
stroke: '#afafaf', stroke: '#afafaf',
strokeWidth: 1 strokeWidth: 1,
} },
}) })
lf.value.on('graph:rendered', () => { lf.value.on('graph:rendered', () => {
flowId.value = lf.value.graphModel.flowId flowId.value = lf.value.graphModel.flowId
@ -124,7 +124,7 @@ const onmousedown = (shapeItem: ShapeItem) => {
if (shapeItem.type) { if (shapeItem.type) {
lf.value.dnd.startDrag({ lf.value.dnd.startDrag({
type: shapeItem.type, type: shapeItem.type,
properties: { ...shapeItem.properties } properties: { ...shapeItem.properties },
}) })
} }
if (shapeItem.callback) { if (shapeItem.callback) {
@ -139,7 +139,7 @@ const addNode = (shapeItem: ShapeItem) => {
type: shapeItem.type, type: shapeItem.type,
properties: shapeItem.properties, properties: shapeItem.properties,
x: virtualRectCenterPositionX, x: virtualRectCenterPositionX,
y: virtualRectCenterPositionY - lf.value.graphModel.height / 2 y: virtualRectCenterPositionY - lf.value.graphModel.height / 2,
}) })
newNode.isSelected = true newNode.isSelected = true
newNode.isHovered = true newNode.isHovered = true
@ -157,7 +157,7 @@ defineExpose({
addNode, addNode,
clearGraphData, clearGraphData,
renderGraphData, renderGraphData,
render render,
}) })
</script> </script>
<style lang="scss"> <style lang="scss">

View File

@ -17,7 +17,7 @@
:rules="{ :rules="{
required: true, required: true,
message: $t('views.application.form.aiModel.placeholder'), message: $t('views.application.form.aiModel.placeholder'),
trigger: 'change' trigger: 'change',
}" }"
> >
<template #label> <template #label>
@ -68,7 +68,7 @@
:rules="{ :rules="{
required: true, required: true,
message: $t('views.application.form.prompt.requiredMessage'), message: $t('views.application.form.prompt.requiredMessage'),
trigger: 'blur' trigger: 'blur',
}" }"
> >
<template #label> <template #label>
@ -80,9 +80,7 @@
> >
</div> </div>
<el-tooltip effect="dark" placement="right" popper-class="max-w-200"> <el-tooltip effect="dark" placement="right" popper-class="max-w-200">
<template #content <template #content>{{ $t('views.application.form.prompt.tooltip') }} </template>
>{{ $t('views.application.form.prompt.tooltip') }}
</template>
<AppIcon iconName="app-warning" class="app-warning-icon"></AppIcon> <AppIcon iconName="app-warning" class="app-warning-icon"></AppIcon>
</el-tooltip> </el-tooltip>
</div> </div>
@ -127,9 +125,7 @@
<template #label> <template #label>
<div class="flex-between w-full"> <div class="flex-between w-full">
<div> <div>
<span>{{ <span>{{ $t('views.application.form.reasoningContent.label') }}</span>
$t('views.application.form.reasoningContent.label')
}}</span>
</div> </div>
<el-button <el-button
type="primary" type="primary"
@ -179,6 +175,7 @@ import NodeContainer from '@/workflow/common/NodeContainer.vue'
import type { FormInstance } from 'element-plus' import type { FormInstance } from 'element-plus'
import { ref, computed, onMounted } from 'vue' import { ref, computed, onMounted } from 'vue'
import applicationApi from '@/api/application/application' import applicationApi from '@/api/application/application'
import modelAPI from '@/api/model/model.ts'
import useStore from '@/stores' import useStore from '@/stores'
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'
@ -213,7 +210,7 @@ const model_change = (model_id?: string) => {
} }
} }
const { const {
params: { id } params: { id },
} = app.config.globalProperties.$route as any } = app.config.globalProperties.$route as any
// @ts-ignore // @ts-ignore
@ -234,8 +231,8 @@ const form = {
model_setting: { model_setting: {
reasoning_content_start: '<think>', reasoning_content_start: '<think>',
reasoning_content_end: '</think>', reasoning_content_end: '</think>',
reasoning_content_enable: false reasoning_content_enable: false,
} },
} }
const chat_data = computed({ const chat_data = computed({
@ -245,7 +242,7 @@ const chat_data = computed({
set(props.nodeModel.properties.node_data, 'model_setting', { set(props.nodeModel.properties.node_data, 'model_setting', {
reasoning_content_start: '<think>', reasoning_content_start: '<think>',
reasoning_content_end: '</think>', reasoning_content_end: '</think>',
reasoning_content_enable: false reasoning_content_enable: false,
}) })
} }
return props.nodeModel.properties.node_data return props.nodeModel.properties.node_data
@ -257,7 +254,7 @@ const chat_data = computed({
}, },
set: (value) => { set: (value) => {
set(props.nodeModel.properties, 'node_data', value) set(props.nodeModel.properties, 'node_data', value)
} },
}) })
const props = defineProps<{ nodeModel: any }>() const props = defineProps<{ nodeModel: any }>()
@ -274,7 +271,7 @@ const validate = () => {
function getModel() { function getModel() {
if (id) { if (id) {
applicationApi.getApplicationModel(id).then((res: any) => { modelAPI.getLLMModel().then((res: any) => {
modelOptions.value = groupBy(res?.data, 'provider') modelOptions.value = groupBy(res?.data, 'provider')
}) })
} else { } else {
@ -302,7 +299,7 @@ function submitReasoningDialog(val: any) {
let model_setting = cloneDeep(props.nodeModel.properties.node_data.model_setting) let model_setting = cloneDeep(props.nodeModel.properties.node_data.model_setting)
model_setting = { model_setting = {
...model_setting, ...model_setting,
...val ...val,
} }
set(props.nodeModel.properties.node_data, 'model_setting', model_setting) set(props.nodeModel.properties.node_data, 'model_setting', model_setting)
@ -312,7 +309,7 @@ const mcpServersDialogRef = ref()
function openMcpServersDialog() { function openMcpServersDialog() {
const config = { const config = {
mcp_servers: chat_data.value.mcp_servers, mcp_servers: chat_data.value.mcp_servers,
mcp_enable: chat_data.value.mcp_enable mcp_enable: chat_data.value.mcp_enable,
} }
mcpServersDialogRef.value.open(config) mcpServersDialogRef.value.open(config)
} }

View File

@ -15,7 +15,7 @@
:rules="{ :rules="{
message: t('views.application.form.appName.requiredMessage'), message: t('views.application.form.appName.requiredMessage'),
trigger: 'blur', trigger: 'blur',
required: true required: true,
}" }"
> >
<el-input <el-input
@ -86,9 +86,7 @@
<el-form-item> <el-form-item>
<template #label> <template #label>
<div class="flex-between"> <div class="flex-between">
<span class="mr-4">{{ <span class="mr-4">{{ $t('views.application.form.voiceInput.label') }}</span>
$t('views.application.form.voiceInput.label')
}}</span>
<div class="flex"> <div class="flex">
<el-checkbox v-if="form_data.stt_model_enable" v-model="form_data.stt_autosend">{{ <el-checkbox v-if="form_data.stt_model_enable" v-model="form_data.stt_autosend">{{
$t('views.application.form.voiceInput.autoSend') $t('views.application.form.voiceInput.autoSend')
@ -115,9 +113,7 @@
<el-form-item> <el-form-item>
<template #label> <template #label>
<div class="flex-between"> <div class="flex-between">
<span class="mr-4">{{ <span class="mr-4">{{ $t('views.application.form.voicePlay.label') }}</span>
$t('views.application.form.voicePlay.label')
}}</span>
<div class="flex"> <div class="flex">
<el-checkbox v-if="form_data.tts_model_enable" v-model="form_data.tts_autoplay">{{ <el-checkbox v-if="form_data.tts_model_enable" v-model="form_data.tts_autoplay">{{
$t('views.application.form.voicePlay.autoPlay') $t('views.application.form.voicePlay.autoPlay')
@ -133,14 +129,8 @@
</template> </template>
<div class="w-full"> <div class="w-full">
<el-radio-group v-model="form_data.tts_type" v-show="form_data.tts_model_enable"> <el-radio-group v-model="form_data.tts_type" v-show="form_data.tts_model_enable">
<el-radio <el-radio :label="$t('views.application.form.voicePlay.browser')" value="BROWSER" />
:label="$t('views.application.form.voicePlay.browser')" <el-radio :label="$t('views.application.form.voicePlay.tts')" value="TTS" />
value="BROWSER"
/>
<el-radio
:label="$t('views.application.form.voicePlay.tts')"
value="TTS"
/>
</el-radio-group> </el-radio-group>
</div> </div>
<div class="flex-between w-full"> <div class="flex-between w-full">
@ -183,6 +173,7 @@ import NodeContainer from '@/workflow/common/NodeContainer.vue'
import type { FormInstance } from 'element-plus' import type { FormInstance } from 'element-plus'
import { ref, computed, onMounted } from 'vue' import { ref, computed, onMounted } from 'vue'
import applicationApi from '@/api/application/application' import applicationApi from '@/api/application/application'
import modelAPI from '@/api/model/model.ts'
import { MsgError, MsgSuccess, MsgWarning } from '@/utils/message' import { MsgError, MsgSuccess, MsgWarning } from '@/utils/message'
import { t } from '@/locales' import { t } from '@/locales'
import TTSModeParamSettingDialog from '@/views/application/component/TTSModeParamSettingDialog.vue' import TTSModeParamSettingDialog from '@/views/application/component/TTSModeParamSettingDialog.vue'
@ -191,7 +182,7 @@ import UserInputFieldTable from './component/UserInputFieldTable.vue'
import FileUploadSettingDialog from '@/workflow/nodes/base-node/component/FileUploadSettingDialog.vue' import FileUploadSettingDialog from '@/workflow/nodes/base-node/component/FileUploadSettingDialog.vue'
const { const {
params: { id } params: { id },
} = app.config.globalProperties.$route as any } = app.config.globalProperties.$route as any
const props = defineProps<{ nodeModel: any }>() const props = defineProps<{ nodeModel: any }>()
@ -206,7 +197,7 @@ const FileUploadSettingDialogRef = ref<InstanceType<typeof FileUploadSettingDial
const form = { const form = {
name: '', name: '',
desc: '', desc: '',
prologue: t('views.application.form.defaultPrologue') prologue: t('views.application.form.defaultPrologue'),
} }
const wheel = (e: any) => { const wheel = (e: any) => {
@ -234,7 +225,7 @@ const form_data = computed({
}, },
set: (value) => { set: (value) => {
set(props.nodeModel.properties, 'node_data', value) set(props.nodeModel.properties, 'node_data', value)
} },
}) })
const baseNodeFormRef = ref<FormInstance>() const baseNodeFormRef = ref<FormInstance>()
@ -247,13 +238,13 @@ const validate = () => {
) { ) {
return Promise.reject({ return Promise.reject({
node: props.nodeModel, node: props.nodeModel,
errMessage: t('views.application.form.voicePlay.requiredMessage') errMessage: t('views.application.form.voicePlay.requiredMessage'),
}) })
} }
if (form_data.value.stt_model_enable && !form_data.value.stt_model_id) { if (form_data.value.stt_model_enable && !form_data.value.stt_model_id) {
return Promise.reject({ return Promise.reject({
node: props.nodeModel, node: props.nodeModel,
errMessage: t('views.application.form.voiceInput.requiredMessage') errMessage: t('views.application.form.voiceInput.requiredMessage'),
}) })
} }
return baseNodeFormRef.value?.validate().catch((err) => { return baseNodeFormRef.value?.validate().catch((err) => {
@ -262,13 +253,13 @@ const validate = () => {
} }
function getSTTModel() { function getSTTModel() {
applicationApi.getApplicationSTTModel(id).then((res: any) => { modelAPI.getSTTModel().then((res: any) => {
sttModelOptions.value = groupBy(res?.data, 'provider') sttModelOptions.value = groupBy(res?.data, 'provider')
}) })
} }
function getTTSModel() { function getTTSModel() {
applicationApi.getApplicationTTSModel(id).then((res: any) => { modelAPI.getTTSModel().then((res: any) => {
ttsModelOptions.value = groupBy(res?.data, 'provider') ttsModelOptions.value = groupBy(res?.data, 'provider')
}) })
} }
@ -316,7 +307,7 @@ const switchFileUpload = () => {
audio: false, audio: false,
video: false, video: false,
other: false, other: false,
otherExtensions: ['ppt', 'doc'] otherExtensions: ['ppt', 'doc'],
} }
if (form_data.value.file_upload_enable) { if (form_data.value.file_upload_enable) {