INTEGRITY Dokumentace

Značení obrázků s lidským dohledem pomocí waitForEvent

Tento příklad ukazuje, jak použít waitForEvent() API v Cloudflare Workflows, kterým se do procesu zavede krok human-in-the-loop. Workflow se spustí nahráním obrázku, při kterém se metadata uloží do databáze D1. Workflow poté čeká na schválení uživatelem a po schválení pomocí Workers AI vygeneruje tagy obrázku, které se uloží do databáze. Přiložená frontendová aplikace Next.js usnadňuje nahrávání obrázků a proces schvalování.

Přehled Workflow

V tomto Workflow simulujeme scénář, kdy nahraný obrázek vyžaduje před zpracováním pomocí AI schválení člověkem. Obrázek se nahraje do R2 a Workflow poté provede následující kroky:

  1. Ukládá metadata obrázků do databáze D1.
  2. Pozastaví spuštění pomocí waitForEvent() a čeká na externí událost odeslanou z frontendu Next.js, která signalizuje schválení nebo zamítnutí.
  3. Pokud je schváleno, Workflow pomocí Workers AI vygeneruje štítky obrázku a uloží je do databáze D1.
  4. Pokud je zamítnuto, Workflow skončí bez dalšího zásahu.

Tento vzor se hodí ve scénářích, kdy určité operace nemají pokračovat bez výslovného souhlasu člověka, což přidává další vrstvu kontroly a bezpečnosti.

Frontendová integrace

Tento příklad obsahuje frontendovou aplikaci v Next.js, která zajišťuje nahrávání a schvalování obrázků. Frontend nabízí rozhraní pro nahrávání obrázků, jejich kontrolu a jejich schválení nebo zamítnutí. Po nahrání obrázku aplikace spustí Cloudflare Workflow, který následně řídí další kroky: čeká na schválení uživatelem a po schválení provede AI tagování obrázku.

Viz /nextjs-workflow-frontend složku v Repozitář GitHub ↗ pro úplnou implementaci frontendu a podrobnosti nasazení.

Workflow index.ts

index.ts soubor definuje základní logiku Cloudflare Workflow, který zajišťuje zpracování nahraných obrázků, čekání na schválení člověkem a po schválení provedení označení obrázku pomocí AI. Rozšiřuje WorkflowEntrypoint třídu a implementuje run() metoda.

Úplnou implementaci index.ts souboru se podívejte na Repozitář GitHub ↗.

export class MyWorkflow extends WorkflowEntrypoint {
	db;

	async run(event, step) {
		this.db = new DatabaseService(this.env.DB);
		const { imageKey } = event.payload;

		await step.do("Insert image name into database", async () => {
			await this.db.insertImage(imageKey, event.instanceId);
		});

		const waitForApproval = await step.waitForEvent(
			"Wait for AI Image tagging approval",
			{
				type: "approval-for-ai-tagging",
				timeout: "5 minute",
			},
		);

		const approvalPayload = waitForApproval.payload;
		if (approvalPayload?.approved) {
			const aiTags = await step.do("Generate AI tags", async () => {
				const image = await this.env.workflow_demo_bucket.get(imageKey);
				if (!image) throw new Error("Image not found");

				const arrayBuffer = await image.arrayBuffer();
				const uint8Array = new Uint8Array(arrayBuffer);

				const input = {
					image: Array.from(uint8Array),
					prompt: AI_CONFIG.PROMPT,
					max_tokens: AI_CONFIG.MAX_TOKENS,
				};

				const response = await this.env.AI.run(AI_CONFIG.MODEL, input);
				return response.description;
			});

			await step.do("Update DB with AI tags", async () => {
				await this.db.updateImageTags(event.instanceId, aiTags);
			});
		}
	}
}
export class MyWorkflow extends WorkflowEntrypoint<Env, WorkflowParams> {
	private db!: DatabaseService;

	async run(event: WorkflowEvent<WorkflowParams>, step: WorkflowStep) {
		this.db = new DatabaseService(this.env.DB);
		const { imageKey } = event.payload;

		await step.do('Insert image name into database', async () => {
			await this.db.insertImage(imageKey, event.instanceId);
		});

		const waitForApproval = await step.waitForEvent('Wait for AI Image tagging approval', {
			type: 'approval-for-ai-tagging',
			timeout: '5 minute',
		});

		const approvalPayload = waitForApproval.payload as ApprovalRequest;
		if (approvalPayload?.approved) {
			const aiTags = await step.do('Generate AI tags', async () => {
				const image = await this.env.workflow_demo_bucket.get(imageKey);
				if (!image) throw new Error('Image not found');

				const arrayBuffer = await image.arrayBuffer();
				const uint8Array = new Uint8Array(arrayBuffer);

				const input = {
					image: Array.from(uint8Array),
					prompt: AI_CONFIG.PROMPT,
					max_tokens: AI_CONFIG.MAX_TOKENS,
				};

				const response = await this.env.AI.run(AI_CONFIG.MODEL, input);
				return response.description;
			});

			await step.do('Update DB with AI tags', async () => {
				await this.db.updateImageTags(event.instanceId, aiTags);
			});
		}
	}
}

Workflow wrangler.jsonc

Konfigurace Workflow je definována v wrangler.jsonc soubor. Tento soubor obsahuje vazby pro R2 bucket, databázi D1, Workers AI a samotný Workflow. Zajistěte, aby všechny potřebné vazby a proměnné prostředí byly správně nastaveny tak, aby odpovídaly vašemu účtu Cloudflare a používaným službám.

{
	"$schema": "node_modules/wrangler/config-schema.json",
	"name": "workflows-waitforevent",
	"main": "src/index.ts",
	// Set this to today's date
	"compatibility_date": "2026-08-28",
	"observability": {
		"enabled": true,
		"head_sampling_rate": 1,
	},
	"ai": {
		"binding": "AI"
	},
	"workflows": [
		{
			"name": "workflows-starter",
			"binding": "MY_WORKFLOW",
			"class_name": "MyWorkflow"
		}
	],
	"r2_buckets": [
		{
			"bucket_name": "workflow-demo",
			"binding": "workflow_demo_bucket"
		}
	],
	"d1_databases": [
		{
			"binding": "DB",
			"database_name": "workflows-demo-d1",
			"database_id": "66e4fbe9-06ac-4548-abba-2dc42088e13a"
		}
	]
}
"$schema" = "node_modules/wrangler/config-schema.json"
name = "workflows-waitforevent"
main = "src/index.ts"
# Set this to today's date
compatibility_date = "2026-08-28"

[observability]
enabled = true
head_sampling_rate = 1

[ai]
binding = "AI"

[[workflows]]
name = "workflows-starter"
binding = "MY_WORKFLOW"
class_name = "MyWorkflow"

[[r2_buckets]]
bucket_name = "workflow-demo"
binding = "workflow_demo_bucket"

[[d1_databases]]
binding = "DB"
database_name = "workflows-demo-d1"
database_id = "66e4fbe9-06ac-4548-abba-2dc42088e13a"

Zdrojový kód, pokyny k nasazení a referenční architekturu najdete na Repozitář GitHub ↗. Tento zdroj poskytuje všechny nástroje a informace potřebné k efektivní implementaci Workflow a frontendové aplikace Next.js.