| } = useContext(ConfigContext) | } = useContext(ConfigContext) | ||||
| const isChatApp = mode === AppType.chat | const isChatApp = mode === AppType.chat | ||||
| const { data: userInfo } = useSWR({ url: '/info' }, fetchTenantInfo) | const { data: userInfo } = useSWR({ url: '/info' }, fetchTenantInfo) | ||||
| const targetProvider = userInfo?.providers?.find(({ token_is_set, is_valid }) => token_is_set && is_valid) | |||||
| const openaiProvider = userInfo?.providers?.find(({ token_is_set, is_valid, provider_name }) => token_is_set && is_valid && provider_name === 'openai') | |||||
| const promptTemplate = modelConfig.configs.prompt_template | const promptTemplate = modelConfig.configs.prompt_template | ||||
| const promptVariables = modelConfig.configs.prompt_variables | const promptVariables = modelConfig.configs.prompt_variables | ||||
| }, | }, | ||||
| }) | }) | ||||
| const hasChatConfig = isChatApp && (featureConfig.openingStatement || featureConfig.suggestedQuestionsAfterAnswer || (featureConfig.speechToText && targetProvider?.provider_name === 'openai')) | |||||
| const hasChatConfig = isChatApp && (featureConfig.openingStatement || featureConfig.suggestedQuestionsAfterAnswer || (featureConfig.speechToText && openaiProvider)) | |||||
| const hasToolbox = false | const hasToolbox = false | ||||
| const [showAutomatic, { setTrue: showAutomaticTrue, setFalse: showAutomaticFalse }] = useBoolean(false) | const [showAutomatic, { setTrue: showAutomaticTrue, setFalse: showAutomaticFalse }] = useBoolean(false) | ||||
| isChatApp={isChatApp} | isChatApp={isChatApp} | ||||
| config={featureConfig} | config={featureConfig} | ||||
| onChange={handleFeatureChange} | onChange={handleFeatureChange} | ||||
| showSpeechToTextItem={targetProvider?.provider_name === 'openai'} | |||||
| showSpeechToTextItem={!!openaiProvider} | |||||
| /> | /> | ||||
| )} | )} | ||||
| {showAutomatic && ( | {showAutomatic && ( | 
| } | } | ||||
| const checkCanSend = () => { | const checkCanSend = () => { | ||||
| let hasEmptyInput = false | |||||
| let hasEmptyInput = '' | |||||
| const requiredVars = modelConfig.configs.prompt_variables.filter(({ key, name, required }) => { | const requiredVars = modelConfig.configs.prompt_variables.filter(({ key, name, required }) => { | ||||
| const res = (!key || !key.trim()) || (!name || !name.trim()) || (required || required === undefined || required === null) | const res = (!key || !key.trim()) || (!name || !name.trim()) || (required || required === undefined || required === null) | ||||
| return res | return res | ||||
| }) // compatible with old version | }) // compatible with old version | ||||
| // debugger | // debugger | ||||
| requiredVars.forEach(({ key }) => { | |||||
| requiredVars.forEach(({ key, name }) => { | |||||
| if (hasEmptyInput) | if (hasEmptyInput) | ||||
| return | return | ||||
| if (!inputs[key]) | if (!inputs[key]) | ||||
| hasEmptyInput = true | |||||
| hasEmptyInput = name | |||||
| }) | }) | ||||
| if (hasEmptyInput) { | if (hasEmptyInput) { | ||||
| logError(t('appDebug.errorMessage.valueOfVarRequired')) | |||||
| logError(t('appDebug.errorMessage.valueOfVarRequired', { key: hasEmptyInput })) | |||||
| return false | return false | ||||
| } | } | ||||
| return !hasEmptyInput | return !hasEmptyInput | 
| items={(options || []).map(i => ({ name: i, value: i }))} | items={(options || []).map(i => ({ name: i, value: i }))} | ||||
| allowSearch={false} | allowSearch={false} | ||||
| bgClassName='bg-gray-50' | bgClassName='bg-gray-50' | ||||
| overlayClassName='z-[11]' | |||||
| /> | /> | ||||
| ) | ) | ||||
| : ( | : ( | 
| allowSearch?: boolean | allowSearch?: boolean | ||||
| bgClassName?: string | bgClassName?: string | ||||
| placeholder?: string | placeholder?: string | ||||
| overlayClassName?: string | |||||
| } | } | ||||
| const Select: FC<ISelectProps> = ({ | const Select: FC<ISelectProps> = ({ | ||||
| className, | className, | ||||
| onSelect, | onSelect, | ||||
| allowSearch = true, | allowSearch = true, | ||||
| bgClassName = 'bg-gray-100', | bgClassName = 'bg-gray-100', | ||||
| overlayClassName, | |||||
| }) => { | }) => { | ||||
| const [query, setQuery] = useState('') | const [query, setQuery] = useState('') | ||||
| const [open, setOpen] = useState(false) | const [open, setOpen] = useState(false) | ||||
| useEffect(() => { | useEffect(() => { | ||||
| let defaultSelect = null | let defaultSelect = null | ||||
| const existed = items.find((item: Item) => item.value === defaultValue) | const existed = items.find((item: Item) => item.value === defaultValue) | ||||
| if (existed) { | |||||
| if (existed) | |||||
| defaultSelect = existed | defaultSelect = existed | ||||
| } | |||||
| setSelectedItem(defaultSelect) | setSelectedItem(defaultSelect) | ||||
| }, [defaultValue]) | }, [defaultValue]) | ||||
| </div> | </div> | ||||
| {filteredItems.length > 0 && ( | {filteredItems.length > 0 && ( | ||||
| <Combobox.Options className="absolute z-10 mt-1 px-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg border-gray-200 border-[0.5px] focus:outline-none sm:text-sm"> | |||||
| <Combobox.Options className={`absolute z-10 mt-1 px-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg border-gray-200 border-[0.5px] focus:outline-none sm:text-sm ${overlayClassName}`}> | |||||
| {filteredItems.map((item: Item) => ( | {filteredItems.map((item: Item) => ( | ||||
| <Combobox.Option | <Combobox.Option | ||||
| key={item.value} | key={item.value} | ||||
| useEffect(() => { | useEffect(() => { | ||||
| let defaultSelect = null | let defaultSelect = null | ||||
| const existed = items.find((item: Item) => item.value === defaultValue) | const existed = items.find((item: Item) => item.value === defaultValue) | ||||
| if (existed) { | |||||
| if (existed) | |||||
| defaultSelect = existed | defaultSelect = existed | ||||
| } | |||||
| setSelectedItem(defaultSelect) | setSelectedItem(defaultSelect) | ||||
| }, [defaultValue]) | }, [defaultValue]) | ||||
| > | > | ||||
| <div className={`relative h-9 ${wrapperClassName}`}> | <div className={`relative h-9 ${wrapperClassName}`}> | ||||
| <Listbox.Button className={`w-full h-full rounded-lg border-0 bg-gray-100 py-1.5 pl-3 pr-10 shadow-sm sm:text-sm sm:leading-6 focus-visible:outline-none focus-visible:bg-gray-200 group-hover:bg-gray-200 cursor-pointer ${className}`}> | <Listbox.Button className={`w-full h-full rounded-lg border-0 bg-gray-100 py-1.5 pl-3 pr-10 shadow-sm sm:text-sm sm:leading-6 focus-visible:outline-none focus-visible:bg-gray-200 group-hover:bg-gray-200 cursor-pointer ${className}`}> | ||||
| <span className={classNames("block truncate text-left", !selectedItem?.name && 'text-gray-400')}>{selectedItem?.name ?? localPlaceholder}</span> | |||||
| <span className={classNames('block truncate text-left', !selectedItem?.name && 'text-gray-400')}>{selectedItem?.name ?? localPlaceholder}</span> | |||||
| <span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2"> | <span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2"> | ||||
| <ChevronDownIcon | <ChevronDownIcon | ||||
| className="h-5 w-5 text-gray-400" | className="h-5 w-5 text-gray-400" | 
| if (!inputs || !prompt_variables || prompt_variables?.length === 0) | if (!inputs || !prompt_variables || prompt_variables?.length === 0) | ||||
| return true | return true | ||||
| let hasEmptyInput = false | |||||
| let hasEmptyInput = '' | |||||
| const requiredVars = prompt_variables?.filter(({ key, name, required }) => { | const requiredVars = prompt_variables?.filter(({ key, name, required }) => { | ||||
| const res = (!key || !key.trim()) || (!name || !name.trim()) || (required || required === undefined || required === null) | const res = (!key || !key.trim()) || (!name || !name.trim()) || (required || required === undefined || required === null) | ||||
| return res | return res | ||||
| }) || [] // compatible with old version | }) || [] // compatible with old version | ||||
| requiredVars.forEach(({ key }) => { | |||||
| requiredVars.forEach(({ key, name }) => { | |||||
| if (hasEmptyInput) | if (hasEmptyInput) | ||||
| return | return | ||||
| if (!inputs?.[key]) | if (!inputs?.[key]) | ||||
| hasEmptyInput = true | |||||
| hasEmptyInput = name | |||||
| }) | }) | ||||
| if (hasEmptyInput) { | if (hasEmptyInput) { | ||||
| logError(t('appDebug.errorMessage.valueOfVarRequired')) | |||||
| logError(t('appDebug.errorMessage.valueOfVarRequired', { key: hasEmptyInput })) | |||||
| return false | return false | ||||
| } | } | ||||
| return !hasEmptyInput | return !hasEmptyInput | 
| 'use client' | 'use client' | ||||
| import type { FC } from 'react' | import type { FC } from 'react' | ||||
| import React, { useState, useEffect } from 'react' | |||||
| import React, { useEffect, useState } from 'react' | |||||
| import { useTranslation } from 'react-i18next' | import { useTranslation } from 'react-i18next' | ||||
| import { useContext } from 'use-context-selector' | import { useContext } from 'use-context-selector' | ||||
| import TemplateVarPanel, { PanelTitle, VarOpBtnGroup } from '../value-panel' | |||||
| import s from './style.module.css' | import s from './style.module.css' | ||||
| import { AppInfo, ChatBtn, EditBtn, FootLogo, PromptTemplate } from './massive-component' | |||||
| import type { SiteInfo } from '@/models/share' | import type { SiteInfo } from '@/models/share' | ||||
| import type { PromptConfig } from '@/models/debug' | import type { PromptConfig } from '@/models/debug' | ||||
| import { ToastContext } from '@/app/components/base/toast' | import { ToastContext } from '@/app/components/base/toast' | ||||
| import Select from '@/app/components/base/select' | import Select from '@/app/components/base/select' | ||||
| import { DEFAULT_VALUE_MAX_LEN } from '@/config' | import { DEFAULT_VALUE_MAX_LEN } from '@/config' | ||||
| import TemplateVarPanel, { PanelTitle, VarOpBtnGroup } from '../value-panel' | |||||
| import { AppInfo, PromptTemplate, ChatBtn, EditBtn, FootLogo } from './massive-component' | |||||
| // regex to match the {{}} and replace it with a span | // regex to match the {{}} and replace it with a span | ||||
| const regex = /\{\{([^}]+)\}\}/g | const regex = /\{\{([^}]+)\}\}/g | ||||
| onStartChat, | onStartChat, | ||||
| canEidtInpus, | canEidtInpus, | ||||
| savedInputs, | savedInputs, | ||||
| onInputsChange | |||||
| onInputsChange, | |||||
| }) => { | }) => { | ||||
| const { t } = useTranslation() | const { t } = useTranslation() | ||||
| const hasVar = promptConfig.prompt_variables.length > 0 | const hasVar = promptConfig.prompt_variables.length > 0 | ||||
| const [isFold, setIsFold] = useState<boolean>(true) | const [isFold, setIsFold] = useState<boolean>(true) | ||||
| const [inputs, setInputs] = useState<Record<string, any>>((() => { | const [inputs, setInputs] = useState<Record<string, any>>((() => { | ||||
| if (hasSetInputs) { | |||||
| if (hasSetInputs) | |||||
| return savedInputs | return savedInputs | ||||
| } | |||||
| const res: Record<string, any> = {} | const res: Record<string, any> = {} | ||||
| if (promptConfig) { | if (promptConfig) { | ||||
| promptConfig.prompt_variables.forEach((item) => { | promptConfig.prompt_variables.forEach((item) => { | ||||
| }) | }) | ||||
| } | } | ||||
| setInputs(res) | setInputs(res) | ||||
| } else { | |||||
| } | |||||
| else { | |||||
| setInputs(savedInputs) | setInputs(savedInputs) | ||||
| } | } | ||||
| }, [savedInputs]) | }, [savedInputs]) | ||||
| {promptConfig.prompt_variables.map(item => ( | {promptConfig.prompt_variables.map(item => ( | ||||
| <div className='tablet:flex tablet:!h-9 mobile:space-y-2 tablet:space-y-0 mobile:text-xs tablet:text-sm' key={item.key}> | <div className='tablet:flex tablet:!h-9 mobile:space-y-2 tablet:space-y-0 mobile:text-xs tablet:text-sm' key={item.key}> | ||||
| <label className={`flex-shrink-0 flex items-center mobile:text-gray-700 tablet:text-gray-900 mobile:font-medium pc:font-normal ${s.formLabel}`}>{item.name}</label> | <label className={`flex-shrink-0 flex items-center mobile:text-gray-700 tablet:text-gray-900 mobile:font-medium pc:font-normal ${s.formLabel}`}>{item.name}</label> | ||||
| {item.type === 'select' ? ( | |||||
| <Select | |||||
| className='w-full' | |||||
| defaultValue={inputs?.[item.key]} | |||||
| onSelect={(i) => { setInputs({ ...inputs, [item.key]: i.value }) }} | |||||
| items={(item.options || []).map(i => ({ name: i, value: i }))} | |||||
| allowSearch={false} | |||||
| bgClassName='bg-gray-50' | |||||
| /> | |||||
| ) : ( | |||||
| <input | |||||
| placeholder={`${item.name}${!item.required ? `(${t('appDebug.variableTable.optional')})` : ''}`} | |||||
| value={inputs?.[item.key] || ''} | |||||
| onChange={(e) => { setInputs({ ...inputs, [item.key]: e.target.value }) }} | |||||
| className={`w-full flex-grow py-2 pl-3 pr-3 box-border rounded-lg bg-gray-50`} | |||||
| maxLength={item.max_length || DEFAULT_VALUE_MAX_LEN} | |||||
| /> | |||||
| )} | |||||
| {item.type === 'select' | |||||
| ? ( | |||||
| <Select | |||||
| className='w-full' | |||||
| defaultValue={inputs?.[item.key]} | |||||
| onSelect={(i) => { setInputs({ ...inputs, [item.key]: i.value }) }} | |||||
| items={(item.options || []).map(i => ({ name: i, value: i }))} | |||||
| allowSearch={false} | |||||
| bgClassName='bg-gray-50' | |||||
| /> | |||||
| ) | |||||
| : ( | |||||
| <input | |||||
| placeholder={`${item.name}${!item.required ? `(${t('appDebug.variableTable.optional')})` : ''}`} | |||||
| value={inputs?.[item.key] || ''} | |||||
| onChange={(e) => { setInputs({ ...inputs, [item.key]: e.target.value }) }} | |||||
| className={'w-full flex-grow py-2 pl-3 pr-3 box-border rounded-lg bg-gray-50'} | |||||
| maxLength={item.max_length || DEFAULT_VALUE_MAX_LEN} | |||||
| /> | |||||
| )} | |||||
| </div> | </div> | ||||
| ))} | ))} | ||||
| </div> | </div> | ||||
| const canChat = () => { | const canChat = () => { | ||||
| const prompt_variables = promptConfig?.prompt_variables | const prompt_variables = promptConfig?.prompt_variables | ||||
| if (!inputs || !prompt_variables || prompt_variables?.length === 0) { | |||||
| if (!inputs || !prompt_variables || prompt_variables?.length === 0) | |||||
| return true | return true | ||||
| } | |||||
| let hasEmptyInput = false | |||||
| let hasEmptyInput = '' | |||||
| const requiredVars = prompt_variables?.filter(({ key, name, required }) => { | const requiredVars = prompt_variables?.filter(({ key, name, required }) => { | ||||
| const res = (!key || !key.trim()) || (!name || !name.trim()) || (required || required === undefined || required === null) | const res = (!key || !key.trim()) || (!name || !name.trim()) || (required || required === undefined || required === null) | ||||
| return res | return res | ||||
| }) || [] // compatible with old version | }) || [] // compatible with old version | ||||
| requiredVars.forEach(({ key }) => { | |||||
| if (hasEmptyInput) { | |||||
| requiredVars.forEach(({ key, name }) => { | |||||
| if (hasEmptyInput) | |||||
| return | return | ||||
| } | |||||
| if (!inputs?.[key]) { | |||||
| hasEmptyInput = true | |||||
| } | |||||
| if (!inputs?.[key]) | |||||
| hasEmptyInput = name | |||||
| }) | }) | ||||
| if (hasEmptyInput) { | if (hasEmptyInput) { | ||||
| logError(t('appDebug.errorMessage.valueOfVarRequired')) | |||||
| logError(t('appDebug.errorMessage.valueOfVarRequired', { key: hasEmptyInput })) | |||||
| return false | return false | ||||
| } | } | ||||
| return !hasEmptyInput | return !hasEmptyInput | ||||
| } | } | ||||
| const handleChat = () => { | const handleChat = () => { | ||||
| if (!canChat()) { | |||||
| if (!canChat()) | |||||
| return | return | ||||
| } | |||||
| onStartChat(inputs) | onStartChat(inputs) | ||||
| } | } | ||||
| return ( | return ( | ||||
| <VarOpBtnGroup | <VarOpBtnGroup | ||||
| onConfirm={() => { | onConfirm={() => { | ||||
| if (!canChat()) { | |||||
| if (!canChat()) | |||||
| return | return | ||||
| } | |||||
| onInputsChange(inputs) | onInputsChange(inputs) | ||||
| setIsFold(true) | setIsFold(true) | ||||
| }} | }} | ||||
| } | } | ||||
| const renderHasSetInputsPrivate = () => { | const renderHasSetInputsPrivate = () => { | ||||
| if (!canEidtInpus || !hasVar) { | |||||
| if (!canEidtInpus || !hasVar) | |||||
| return null | return null | ||||
| } | |||||
| return ( | return ( | ||||
| <TemplateVarPanel | <TemplateVarPanel | ||||
| isFold={isFold} | isFold={isFold} | ||||
| } | } | ||||
| const renderHasSetInputs = () => { | const renderHasSetInputs = () => { | ||||
| if (!isPublicVersion && !canEidtInpus || !hasVar) { | |||||
| if ((!isPublicVersion && !canEidtInpus) || !hasVar) | |||||
| return null | return null | ||||
| } | |||||
| return ( | return ( | ||||
| <div | <div | ||||
| className='pt-[88px] mb-5' | className='pt-[88px] mb-5' | ||||
| { | { | ||||
| !hasSetInputs && ( | !hasSetInputs && ( | ||||
| <div className='mobile:pt-[72px] tablet:pt-[128px] pc:pt-[200px]'> | <div className='mobile:pt-[72px] tablet:pt-[128px] pc:pt-[200px]'> | ||||
| {hasVar ? ( | |||||
| renderVarPanel() | |||||
| ) : ( | |||||
| renderNoVarPanel() | |||||
| )} | |||||
| {hasVar | |||||
| ? ( | |||||
| renderVarPanel() | |||||
| ) | |||||
| : ( | |||||
| renderNoVarPanel() | |||||
| )} | |||||
| </div> | </div> | ||||
| ) | ) | ||||
| } | } | 
| if (!inputs || !prompt_variables || prompt_variables?.length === 0) | if (!inputs || !prompt_variables || prompt_variables?.length === 0) | ||||
| return true | return true | ||||
| let hasEmptyInput = false | |||||
| let hasEmptyInput = '' | |||||
| const requiredVars = prompt_variables?.filter(({ key, name, required }) => { | const requiredVars = prompt_variables?.filter(({ key, name, required }) => { | ||||
| const res = (!key || !key.trim()) || (!name || !name.trim()) || (required || required === undefined || required === null) | const res = (!key || !key.trim()) || (!name || !name.trim()) || (required || required === undefined || required === null) | ||||
| return res | return res | ||||
| }) || [] // compatible with old version | }) || [] // compatible with old version | ||||
| requiredVars.forEach(({ key }) => { | |||||
| requiredVars.forEach(({ key, name }) => { | |||||
| if (hasEmptyInput) | if (hasEmptyInput) | ||||
| return | return | ||||
| if (!inputs?.[key]) | if (!inputs?.[key]) | ||||
| hasEmptyInput = true | |||||
| hasEmptyInput = name | |||||
| }) | }) | ||||
| if (hasEmptyInput) { | if (hasEmptyInput) { | ||||
| logError(t('appDebug.errorMessage.valueOfVarRequired')) | |||||
| logError(t('appDebug.errorMessage.valueOfVarRequired', { key: hasEmptyInput })) | |||||
| return false | return false | ||||
| } | } | ||||
| return !hasEmptyInput | return !hasEmptyInput | 
| if (!inputs || !prompt_variables || prompt_variables?.length === 0) | if (!inputs || !prompt_variables || prompt_variables?.length === 0) | ||||
| return true | return true | ||||
| let hasEmptyInput = false | |||||
| let hasEmptyInput = '' | |||||
| const requiredVars = prompt_variables?.filter(({ key, name, required }) => { | const requiredVars = prompt_variables?.filter(({ key, name, required }) => { | ||||
| const res = (!key || !key.trim()) || (!name || !name.trim()) || (required || required === undefined || required === null) | const res = (!key || !key.trim()) || (!name || !name.trim()) || (required || required === undefined || required === null) | ||||
| return res | return res | ||||
| }) || [] // compatible with old version | }) || [] // compatible with old version | ||||
| requiredVars.forEach(({ key }) => { | |||||
| requiredVars.forEach(({ key, name }) => { | |||||
| if (hasEmptyInput) | if (hasEmptyInput) | ||||
| return | return | ||||
| if (!inputs?.[key]) | if (!inputs?.[key]) | ||||
| hasEmptyInput = true | |||||
| hasEmptyInput = name | |||||
| }) | }) | ||||
| if (hasEmptyInput) { | if (hasEmptyInput) { | ||||
| logError(t('appDebug.errorMessage.valueOfVarRequired')) | |||||
| logError(t('appDebug.errorMessage.valueOfVarRequired', { key: hasEmptyInput })) | |||||
| return false | return false | ||||
| } | } | ||||
| return !hasEmptyInput | return !hasEmptyInput | 
| if (!prompt_variables || prompt_variables?.length === 0) | if (!prompt_variables || prompt_variables?.length === 0) | ||||
| return true | return true | ||||
| let hasEmptyInput = false | |||||
| let hasEmptyInput = '' | |||||
| const requiredVars = prompt_variables?.filter(({ key, name, required }) => { | const requiredVars = prompt_variables?.filter(({ key, name, required }) => { | ||||
| const res = (!key || !key.trim()) || (!name || !name.trim()) || (required || required === undefined || required === null) | const res = (!key || !key.trim()) || (!name || !name.trim()) || (required || required === undefined || required === null) | ||||
| return res | return res | ||||
| }) || [] // compatible with old version | }) || [] // compatible with old version | ||||
| requiredVars.forEach(({ key }) => { | |||||
| requiredVars.forEach(({ key, name }) => { | |||||
| if (hasEmptyInput) | if (hasEmptyInput) | ||||
| return | return | ||||
| if (!inputs[key]) | if (!inputs[key]) | ||||
| hasEmptyInput = true | |||||
| hasEmptyInput = name | |||||
| }) | }) | ||||
| if (hasEmptyInput) { | if (hasEmptyInput) { | ||||
| logError(t('appDebug.errorMessage.valueOfVarRequired')) | |||||
| logError(t('appDebug.errorMessage.valueOfVarRequired', { key: hasEmptyInput })) | |||||
| return false | return false | ||||
| } | } | ||||
| return !hasEmptyInput | return !hasEmptyInput | 
| }, | }, | ||||
| errorMessage: { | errorMessage: { | ||||
| nameOfKeyRequired: 'name of the key: {{key}} required', | nameOfKeyRequired: 'name of the key: {{key}} required', | ||||
| valueOfVarRequired: 'Variables value can not be empty', | |||||
| valueOfVarRequired: '{{key}} value can not be empty', | |||||
| queryRequired: 'Request text is required.', | queryRequired: 'Request text is required.', | ||||
| waitForResponse: | waitForResponse: | ||||
| 'Please wait for the response to the previous message to complete.', | 'Please wait for the response to the previous message to complete.', | 
| }, | }, | ||||
| errorMessage: { | errorMessage: { | ||||
| nameOfKeyRequired: '变量 {{key}} 对应的名称必填', | nameOfKeyRequired: '变量 {{key}} 对应的名称必填', | ||||
| valueOfVarRequired: '变量值必填', | |||||
| valueOfVarRequired: '{{key}}必填', | |||||
| queryRequired: '主要文本必填', | queryRequired: '主要文本必填', | ||||
| waitForResponse: '请等待上条信息响应完成', | waitForResponse: '请等待上条信息响应完成', | ||||
| waitForBatchResponse: '请等待批量任务完成', | waitForBatchResponse: '请等待批量任务完成', |