Commit 228ddb2d authored by Joel's avatar Joel

feat: valid batch input

parent 2ab7f80c
......@@ -10,8 +10,7 @@ import Button from '../../base/button'
import s from './style.module.css'
import RunBatch from './run-batch'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import ConfigScence from '@/app/components/share/text-generation/config-scence'
// import History from '@/app/components/share/text-generation/history'
import RunOnce from '@/app/components/share/text-generation/run-once'
import { fetchSavedMessage as doFetchSavedMessage, fetchAppInfo, fetchAppParams, removeMessage, saveMessage } from '@/service/share'
import type { SiteInfo } from '@/models/share'
import type { MoreLikeThisConfig, PromptConfig, SavedMessage } from '@/models/debug'
......@@ -102,16 +101,106 @@ const TextGeneration: FC<IMainProps> = ({
const pendingTaskList = allTaskList.filter(task => task.status === TaskStatus.pending)
const noPendingTask = pendingTaskList.length === 0
const showTaskList = allTaskList.filter(task => task.status !== TaskStatus.pending)
// console.log(showTaskList.map(item => ({ id: item.id, status: item.status })))
const allTaskFinished = allTaskList.every(task => task.status === TaskStatus.completed)
const checkBatchInputs = (data: string[][]) => {
if (!data || data.length === 0) {
notify({ type: 'error', message: t('share.generation.errorMsg.empty') })
return false
}
const headerData = data[0]
const varLen = promptConfig?.prompt_variables.length || 0
let isMapVarName = true
promptConfig?.prompt_variables.forEach((item, index) => {
if (!isMapVarName)
return
if (item.name !== headerData[index])
isMapVarName = false
})
if (headerData[varLen] !== t('share.generation.queryTitle'))
isMapVarName = false
if (!isMapVarName) {
notify({ type: 'error', message: t('share.generation.errorMsg.fileStructNotMatch') })
return false
}
let payloadData = data.slice(0)
if (payloadData.length === 0) {
notify({ type: 'error', message: t('share.generation.errorMsg.atLeastOne') })
return false
}
// check middle empty line
const allEmptyLineIndexes = payloadData.filter(item => item.every(i => i === '')).map(item => payloadData.indexOf(item))
if (allEmptyLineIndexes.length > 0) {
let hasMiddleEmptyLine = false
let startIndex = allEmptyLineIndexes[0] - 1
allEmptyLineIndexes.forEach((index) => {
if (hasMiddleEmptyLine)
return
if (startIndex + 1 !== index) {
hasMiddleEmptyLine = true
return
}
startIndex++
})
if (hasMiddleEmptyLine) {
notify({ type: 'error', message: t('share.generation.errorMsg.emptyLine', { rowIndex: startIndex }) })
return false
}
}
// check row format
payloadData = payloadData.filter(item => !item.every(i => i === '')) // remove empty rows in the end
let errorRowIndex = 0
let requiredVarName = ''
payloadData.forEach((item, index) => {
if (errorRowIndex !== 0)
return
promptConfig?.prompt_variables.forEach((varItem, varIndex) => {
if (errorRowIndex !== 0)
return
if (varItem.required === false)
return
if (item[varIndex].trim() === '') {
requiredVarName = varItem.name
errorRowIndex = index + 1
}
})
if (errorRowIndex !== 0)
return
if (item[varLen] === '') {
requiredVarName = t('share.generation.queryTitle')
errorRowIndex = index + 1
}
})
if (errorRowIndex !== 0) {
notify({ type: 'error', message: t('share.generation.errorMsg.invalidLine', { rowIndex: errorRowIndex, varName: requiredVarName }) })
return false
}
return true
}
const handleRunBatch = (data: string[][]) => {
if (!checkBatchInputs(data))
return
if (!allTaskFinished) {
notify({ type: 'info', message: t('appDebug.errorMessage.waitForBatchResponse') })
return
}
const payloadData = data.slice(0)
setIsCallBatchAPI(true)
const allTaskList: Task[] = data.map((item, i) => {
const allTaskList: Task[] = payloadData.map((item, i) => {
const inputs: Record<string, string> = {}
item.slice(0, -1).forEach((input, index) => {
inputs[promptConfig?.prompt_variables[index].key as string] = input
......@@ -314,7 +403,7 @@ const TextGeneration: FC<IMainProps> = ({
/>
<div className='grow h-20 overflow-y-auto'>
<div className={cn(currTab === 'create' ? 'block' : 'hidden')}>
<ConfigScence
<RunOnce
siteInfo={siteInfo}
inputs={inputs}
onInputsChange={setInputs}
......
......@@ -29,7 +29,7 @@ const RunBatch: FC<IRunBatchProps> = ({
}
const handleSend = () => {
onSend(csvData.slice(1))
onSend(csvData)
}
return (
<div className='pt-4'>
......
......@@ -10,7 +10,7 @@ import type { PromptConfig } from '@/models/debug'
import Button from '@/app/components/base/button'
import { DEFAULT_VALUE_MAX_LEN } from '@/config'
export type IConfigSenceProps = {
export type IRunOnceProps = {
siteInfo: SiteInfo
promptConfig: PromptConfig
inputs: Record<string, any>
......@@ -19,7 +19,7 @@ export type IConfigSenceProps = {
onQueryChange: (query: string) => void
onSend: () => void
}
const ConfigSence: FC<IConfigSenceProps> = ({
const RunOnce: FC<IRunOnceProps> = ({
promptConfig,
inputs,
onInputsChange,
......@@ -100,4 +100,4 @@ const ConfigSence: FC<IConfigSenceProps> = ({
</div>
)
}
export default React.memo(ConfigSence)
export default React.memo(RunOnce)
......@@ -51,6 +51,13 @@ const translation = {
csvStructureTitle: 'The CSV file must conform to the following structure:',
downloadTemplate: 'Download the template here',
field: 'Field',
errorMsg: {
empty: 'Please input content in the uploaded file.',
fileStructNotMatch: 'The uploaded CSV file not match the struct.',
emptyLine: 'Row {{rowIndex}} is empty',
invalidLine: 'Row {{rowIndex}}: {{varName}} is required',
atLeastOne: 'Please input at least one row in the uploaded file.',
},
},
}
......
......@@ -47,6 +47,13 @@ const translation = {
csvStructureTitle: 'CSV 文件必须符合以下结构:',
downloadTemplate: '下载模板',
field: '',
errorMsg: {
empty: '上传文件的内容不能为空',
fileStructNotMatch: '上传文件的内容与结构不匹配',
emptyLine: '第 {{rowIndex}} 行的内容为空',
invalidLine: '第 {{rowIndex}} 行: {{varName}} 的内容不能为空',
atLeastOne: '上传文件的内容不能少于一条',
},
},
}
......
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