← Cloudflare Workflows / workflows / examples
Разметка изображений с участием человека через waitForEvent
Этот пример показывает, как использовать waitForEvent() API в Cloudflare Workflows для добавления шага с участием человека. Workflow запускается загрузкой изображения, во время которой метаданные сохраняются в базе данных D1. Затем Workflow ожидает подтверждения от пользователя и после подтверждения использует Workers AI для генерации тегов изображения, которые сохраняются в базе данных. Прилагаемое фронтенд-приложение на Next.js обеспечивает процесс загрузки изображения и подтверждения.
Обзор Workflow
В этом Workflow мы моделируем сценарий, в котором загруженное изображение требует одобрения человеком перед обработкой с помощью ИИ. Изображение загружается в R2, после чего Workflow выполняет следующие шаги:
- Сохраняет метаданные изображений в базе данных D1.
- Приостанавливает выполнение с помощью
waitForEvent()и ожидает внешнего события, отправленного с фронтенда Next.js, которое указывает на одобрение или отклонение. - В случае одобрения Workflow использует Workers AI для генерации тегов изображения и сохраняет их в базе данных D1.
- В случае отклонения Workflow завершается без дальнейших действий.
Этот паттерн полезен в сценариях, где определённые операции не должны выполняться без явного согласия человека, что добавляет дополнительный уровень контроля и безопасности.
Интеграция фронтенда
Этот пример включает фронтенд-приложение на Next.js, которое обеспечивает процесс загрузки и подтверждения изображений. Фронтенд предоставляет интерфейс для загрузки изображений, их просмотра, а также одобрения или отклонения. При загрузке изображения приложение запускает Cloudflare Workflow, который затем управляет следующими шагами, включая ожидание подтверждения от пользователя и тегирование изображений на основе ИИ после одобрения.
См. /nextjs-workflow-frontend папка в репозиторий GitHub ↗ с полным описанием реализации клиентской части и развёртывания.
Workflow index.ts
index.ts файл определяет основную логику Cloudflare Workflow, отвечающего за обработку загрузки изображений, ожидание одобрения человеком и выполнение тегирования изображений на основе ИИ после одобрения. Он расширяет WorkflowEntrypoint класс и реализует run() метод.
Полную реализацию index.ts файл, обратитесь к репозиторий 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
Конфигурация Workflow задаётся в wrangler.jsonc файл. Этот файл включает привязки для R2-бакета, базы данных D1, Workers AI и самого Workflow. Убедитесь, что все необходимые привязки и переменные окружения настроены правильно и соответствуют вашему аккаунту Cloudflare и используемым сервисам.
{
"$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"Чтобы получить доступ к исходному коду, инструкциям по развертыванию и эталонной архитектуре, посетите репозиторий GitHub ↗. Этот ресурс содержит все инструменты и сведения, необходимые для эффективной реализации Workflow и клиентского приложения на Next.js.