| 1299 | }; |
| 1300 | |
| 1301 | const watchJob = (jobId, options = {}) => { |
| 1302 | const numericJobId = Number(jobId || 0); |
| 1303 | if (!Number.isFinite(numericJobId) || numericJobId <= 0) return; |
| 1304 | if (watchedJobs.has(numericJobId)) return; |
| 1305 | |
| 1306 | const state = { |
| 1307 | done: false, |
| 1308 | timer: 0, |
| 1309 | lastProgressKey: '', |
| 1310 | lastStatus: '', |
| 1311 | messageHandle: options.messageHandle || null, |
| 1312 | workflow: (options.workflow && typeof options.workflow === 'object') ? { ...options.workflow } : null |
| 1313 | }; |
| 1314 | watchedJobs.set(numericJobId, state); |
| 1315 | |
| 1316 | const poll = async () => { |
| 1317 | if (state.done) return; |
| 1318 | try { |
| 1319 | const detail = await apiGet(`/api/pro/automation/jobs/get.php?id=${encodeURIComponent(numericJobId)}`); |
| 1320 | const job = (detail && typeof detail === 'object' && detail.job && typeof detail.job === 'object') ? detail.job : null; |
| 1321 | const status = String(job?.status || '').toLowerCase(); |
| 1322 | const payload = (job && job.payload && typeof job.payload === 'object') ? job.payload : null; |
| 1323 | const progress = (payload && payload.aiProgress && typeof payload.aiProgress === 'object') ? payload.aiProgress : null; |
| 1324 | const progressKey = progress |
| 1325 | ? `${Number(progress.processedCount || 0)}|${Number(progress.filteredOutCount || 0)}|${Number(progress.failedCount || 0)}|${String(progress.lastFile || '')}` |
| 1326 | : ''; |
| 1327 | const workflowDetail = buildAutomationWorkflowFromDetail(state.workflow, detail); |
| 1328 | |
| 1329 | if ((status === 'queued' || status === 'running') && progress && progressKey !== '' && progressKey !== state.lastProgressKey) { |
| 1330 | state.lastProgressKey = progressKey; |
| 1331 | if (state.messageHandle) { |
| 1332 | state.messageHandle.setWorkflow(workflowDetail); |
| 1333 | state.messageHandle.setText(`Job #${numericJobId} is running.`); |
| 1334 | } else { |
| 1335 | appendMessage( |
| 1336 | 'assistant', |
| 1337 | `Job #${numericJobId} running: processed ${Number(progress.processedCount || 0)}, filtered ${Number(progress.filteredOutCount || 0)}, failed ${Number(progress.failedCount || 0)}${progress.lastFile ? `, last file ${String(progress.lastFile)}` : ''}.`, |
| 1338 | { workflow: workflowDetail } |
| 1339 | ); |
| 1340 | } |
| 1341 | } else if ((status === 'queued' || status === 'running') && state.lastStatus !== status) { |
| 1342 | state.lastStatus = status; |
| 1343 | if (state.messageHandle) { |
| 1344 | state.messageHandle.setWorkflow(workflowDetail); |
| 1345 | state.messageHandle.setText(`Job #${numericJobId} ${status}.`); |
| 1346 | } else { |
| 1347 | appendMessage('assistant', `Job #${numericJobId} ${status}.`, { workflow: workflowDetail }); |
| 1348 | } |
| 1349 | } |
| 1350 | |
| 1351 | if (status === 'succeeded' || status === 'failed' || status === 'dead' || status === 'canceled') { |
| 1352 | state.done = true; |
| 1353 | watchedJobs.delete(numericJobId); |
| 1354 | const result = (payload && payload.aiResult && typeof payload.aiResult === 'object') ? payload.aiResult : null; |
| 1355 | const saved = (result?.savedOutputFile && typeof result.savedOutputFile === 'object') ? result.savedOutputFile : null; |
| 1356 | const summary = describeJobCompletion(detail); |
| 1357 | if (state.messageHandle) { |
| 1358 | state.messageHandle.setWorkflow(workflowDetail); |