feat: ship self-hosted KOC LOOP workflows
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import { env } from "cloudflare:workers";
|
||||
import { getRequestExecutionContext } from "vinext/shims/request-context";
|
||||
import { getRuntimeEnv } from "../../../lib/runtime-env";
|
||||
import { runInBackground } from "../../../lib/background";
|
||||
|
||||
const env = getRuntimeEnv();
|
||||
import { backfillAccountProfiles } from "../../../lib/account-enrichment-service";
|
||||
import {
|
||||
ensureSchema,
|
||||
@@ -24,9 +26,10 @@ import {
|
||||
readFeishuSource,
|
||||
type FeishuBindings,
|
||||
} from "../../../lib/feishu-client";
|
||||
import { createDistributionTask } from "../../../lib/task-service";
|
||||
|
||||
export const runtime = "edge";
|
||||
import {
|
||||
createDistributionTask,
|
||||
createScreenshotTask,
|
||||
} from "../../../lib/task-service";
|
||||
|
||||
type ActionBody = {
|
||||
action?: string;
|
||||
@@ -79,6 +82,16 @@ export async function POST(request: Request) {
|
||||
},
|
||||
env as unknown as FeishuBindings,
|
||||
);
|
||||
} else if (body.action === "create_screenshot_task") {
|
||||
await createScreenshotTask({
|
||||
name: String(body.name ?? "").trim(),
|
||||
brand: String(body.brand ?? "").trim(),
|
||||
dueAt: String(body.dueAt ?? "").trim(),
|
||||
keyword: String(body.keyword ?? "").trim(),
|
||||
instructions: String(body.instructions ?? "").trim(),
|
||||
quantity: numberValue(body.quantity),
|
||||
exampleImageKey: String(body.exampleImageKey ?? "").trim(),
|
||||
});
|
||||
} else if (body.action === "claim") {
|
||||
const partnerId = String(body.partnerId ?? "");
|
||||
const taskId = String(body.taskId ?? "");
|
||||
@@ -88,9 +101,9 @@ export async function POST(request: Request) {
|
||||
`SELECT id FROM contents
|
||||
WHERE task_id = ? AND status = 'available'
|
||||
ORDER BY created_at, id
|
||||
LIMIT ?`,
|
||||
LIMIT ${quantity}`,
|
||||
)
|
||||
.bind(taskId, quantity)
|
||||
.bind(taskId)
|
||||
.all<{ id: string }>();
|
||||
if (available.results.length === 0) {
|
||||
return Response.json({ error: "当前没有可领取内容" }, { status: 409 });
|
||||
@@ -146,12 +159,18 @@ export async function POST(request: Request) {
|
||||
);
|
||||
}
|
||||
const task = await db
|
||||
.prepare("SELECT id FROM tasks WHERE id = ?")
|
||||
.prepare("SELECT id, task_type FROM tasks WHERE id = ?")
|
||||
.bind(taskId)
|
||||
.first<{ id: string }>();
|
||||
.first<{ id: string; task_type?: string | null }>();
|
||||
if (!task) {
|
||||
return Response.json({ error: "任务不存在" }, { status: 404 });
|
||||
}
|
||||
if (task.task_type === "screenshot_collect") {
|
||||
return Response.json(
|
||||
{ error: "截图回收任务不需要设置数据采集计划" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
await db.batch([
|
||||
db
|
||||
.prepare(
|
||||
@@ -193,12 +212,7 @@ export async function POST(request: Request) {
|
||||
"catchup",
|
||||
taskId,
|
||||
).catch(() => undefined);
|
||||
const executionContext = getRequestExecutionContext();
|
||||
if (executionContext) {
|
||||
executionContext.waitUntil(catchup);
|
||||
} else {
|
||||
await catchup;
|
||||
}
|
||||
runInBackground(catchup, "collection catchup");
|
||||
} else if (body.action === "run_due_collections") {
|
||||
await runDueScheduledCollections(
|
||||
db,
|
||||
@@ -224,6 +238,24 @@ export async function POST(request: Request) {
|
||||
if (body.action === "collect" && day === null) {
|
||||
return Response.json({ error: "采集周期无效" }, { status: 400 });
|
||||
}
|
||||
const distribution = await db
|
||||
.prepare(
|
||||
`SELECT t.task_type
|
||||
FROM distributions d
|
||||
JOIN tasks t ON t.id = d.task_id
|
||||
WHERE d.id = ?`,
|
||||
)
|
||||
.bind(distributionId)
|
||||
.first<{ task_type?: string | null }>();
|
||||
if (!distribution) {
|
||||
return Response.json({ error: "笔记记录不存在" }, { status: 404 });
|
||||
}
|
||||
if (distribution.task_type === "screenshot_collect") {
|
||||
return Response.json(
|
||||
{ error: "截图回收任务不支持公开数据采集" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
await collectDistributionMetrics(
|
||||
db,
|
||||
distributionId,
|
||||
@@ -239,6 +271,19 @@ export async function POST(request: Request) {
|
||||
if (!taskId) {
|
||||
return Response.json({ error: "请选择需要补采的任务" }, { status: 400 });
|
||||
}
|
||||
const task = await db
|
||||
.prepare("SELECT task_type FROM tasks WHERE id = ?")
|
||||
.bind(taskId)
|
||||
.first<{ task_type?: string | null }>();
|
||||
if (!task) {
|
||||
return Response.json({ error: "任务不存在" }, { status: 404 });
|
||||
}
|
||||
if (task.task_type === "screenshot_collect") {
|
||||
return Response.json(
|
||||
{ error: "截图回收任务没有需要补采的公开数据" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
await retryFailedCollections(
|
||||
db,
|
||||
taskId,
|
||||
@@ -254,12 +299,7 @@ export async function POST(request: Request) {
|
||||
),
|
||||
Math.max(1, Math.min(25, numberValue(body.limit, 10))),
|
||||
).catch(() => undefined);
|
||||
const executionContext = getRequestExecutionContext();
|
||||
if (executionContext) {
|
||||
executionContext.waitUntil(backfill);
|
||||
} else {
|
||||
await backfill;
|
||||
}
|
||||
runInBackground(backfill, "account profile backfill");
|
||||
} else if (body.action === "set_public_account_ids") {
|
||||
const items = Array.isArray(body.items) ? body.items.slice(0, 50) : [];
|
||||
const normalized = items
|
||||
|
||||
Reference in New Issue
Block a user