import "server-only"; import { getActiveAccountId } from "@/lib/account-context"; import { prisma } from "@/lib/db"; import type { JobProgressDetail } from "./types"; import { isJobCancelled, JobCancelledError } from "./cancel"; export async function trackAiTask(label: string, task: () => Promise): Promise { const accountId = await getActiveAccountId(); if (!accountId) return task(); const detail: JobProgressDetail = { summary: `${label}執行中…`, phase: "ai-work", tasks: [{ id: "ai-work", label, status: "running", startedAt: Date.now() }], }; const job = await prisma.backgroundJob.create({ data: { accountId, type: "ai-task", label, status: "running", progress: detail.summary, progressDetail: JSON.stringify(detail), }, }); try { const result = await task(); if (await isJobCancelled(job.id)) { throw new JobCancelledError(); } detail.summary = `${label}完成`; if (detail.tasks?.[0]) detail.tasks[0].status = "done"; await prisma.backgroundJob.update({ where: { id: job.id }, data: { status: "completed", progress: detail.summary, progressDetail: JSON.stringify(detail), completedAt: new Date(), }, }); return result; } catch (error) { if (error instanceof JobCancelledError || await isJobCancelled(job.id)) { await prisma.backgroundJob.update({ where: { id: job.id }, data: { status: "cancelled", progress: "已停止", completedAt: new Date() }, }); throw new JobCancelledError("任務已由使用者停止"); } const message = error instanceof Error ? error.message : `${label}失敗`; detail.summary = `${label}失敗`; if (detail.tasks?.[0]) { detail.tasks[0].status = "failed"; detail.tasks[0].error = message; } await prisma.backgroundJob.update({ where: { id: job.id }, data: { status: "failed", progress: detail.summary, progressDetail: JSON.stringify(detail), error: message, completedAt: new Date(), }, }); throw error; } }