מדריך קלאודפלייר בעברית

תיעוד 259

שימוש בהתראת אירוע כדי לסכם קובצי PDF בעת העלאה

במדריך זה תלמדו כיצד להשתמש בהתראות אירוע כדי לעבד קובץ PDF כאשר הוא מועלה ל-bucket של R2. תשתמשו בWorkers AI כדי לסכם את ה-PDF ולשמור את הסיכום כקובץ טקסט באותו bucket.

#דרישות מוקדמות

כדי להמשיך, תצטרכו:

#מנהל גרסאות של Node.js

השתמשו ב-Vite+ (vp env) ↗︎ כדי להתקין ולנהל גרסאות של Node.js.

לגרסאות נתמכות של Node.js, עיינו בדרישות המערכת של Wrangler.

#1. יצירת פרויקט חדש

תיצרו פרויקט Worker חדש שישתמש בStatic Assets כדי להגיש את ה-front-end של היישום. משתמש יכול להעלות קובץ PDF באמצעות ה-front-end הזה, ואז ה-Worker יעבד אותו.

צרו פרויקט Worker חדש על ידי הרצת הפקודות הבאות:

npm:

npm create cloudflare@latest -- pdf-summarizer

yarn:

yarn create cloudflare pdf-summarizer

pnpm:

pnpm create cloudflare@latest pdf-summarizer

להגדרה, בחרו את האפשרויות הבאות:

  • עבור What would you like to start with?, בחרו Hello World example.
  • עבור Which template would you like to use?, בחרו Worker only.
  • עבור Which language do you want to use?, בחרו TypeScript.
  • עבור Do you want to use git for version control?, בחרו Yes.
  • עבור Do you want to add an AGENTS.md file to help AI coding tools understand Cloudflare APIs?, בחרו Yes.
  • עבור Do you want to deploy your application?, בחרו No (נבצע כמה שינויים לפני הפריסה).

עברו לספרייה pdf-summarizer:

cd pdf-summarizer

#2. יצירת ה-front-end

באמצעות Static Assets אפשר להגיש את ה-front-end של היישום מה-Worker. כדי להשתמש ב-Static Assets, צריך להוסיף את ה-bindings הנדרשים לקובץ Wrangler.

{
	"assets": {
		"directory": "public"
	}
}
[assets]
directory = "public"

לאחר מכן, צרו ספרייה public והוסיפו קובץ index.html. הקובץ index.html צריך להכיל את קוד ה-HTML הבא:

#בחרו כדי להציג את קוד ה-HTML

<!doctype html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>PDF Summarizer</title>
		<style>
			body {
				font-family: Arial, sans-serif;
				display: flex;
				flex-direction: column;
				min-height: 100vh;
				margin: 0;
				background-color: #fefefe;
			}
			.content {
				flex: 1;
				display: flex;
				justify-content: center;
				align-items: center;
			}
			.upload-container {
				background-color: #f0f0f0;
				padding: 20px;
				border-radius: 8px;
				box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
			}
			.upload-button {
				background-color: #4caf50;
				color: white;
				padding: 10px 15px;
				border: none;
				border-radius: 4px;
				cursor: pointer;
				font-size: 16px;
			}
			.upload-button:hover {
				background-color: #45a049;
			}
			footer {
				background-color: #f0f0f0;
				color: white;
				text-align: center;
				padding: 10px;
				width: 100%;
			}
			footer a {
				color: #333;
				text-decoration: none;
				margin: 0 10px;
			}
			footer a:hover {
				text-decoration: underline;
			}
		</style>
	</head>
	<body>
		<div class="content">
			<div class="upload-container">
				<h2>Upload PDF File</h2>
				<form id="uploadForm" onsubmit="return handleSubmit(event)">
					<input
						type="file"
						id="pdfFile"
						name="pdfFile"
						accept=".pdf"
						required
					/>
					<button type="submit" id="uploadButton" class="upload-button">
						Upload
					</button>
				</form>
			</div>
		</div>

		<footer>
			<a
				href="https://developers.cloudflare.com/r2/buckets/event-notifications/"
				target="_blank"
				>R2 Event Notification</a
			>
			<a
				href="https://developers.cloudflare.com/queues/get-started/#3-create-a-queue"
				target="_blank"
				>Cloudflare Queues</a
			>
			<a href="https://developers.cloudflare.com/workers-ai/" target="_blank"
				>Workers AI</a
			>
			<a
				href="https://github.com/harshil1712/pdf-summarizer-r2-event-notification"
				target="_blank"
				>GitHub Repo</a
			>
		</footer>

		<script>
			handleSubmit = async (event) => {
				event.preventDefault();

				// Disable the upload button and show a loading message
				const uploadButton = document.getElementById("uploadButton");
				uploadButton.disabled = true;
				uploadButton.textContent = "Uploading...";

				// get form data
				const formData = new FormData(event.target);
				const file = formData.get("pdfFile");

				if (file) {
					// call /api/upload endpoint and send the file
					await fetch("/api/upload", {
						method: "POST",
						body: formData,
					});

					event.target.reset();
				} else {
					console.log("No file selected");
				}
				uploadButton.disabled = false;
				uploadButton.textContent = "Upload";
			};
		</script>
	</body>
</html>

כדי להציג את ה-front-end של היישום, הריצו את הפקודה הבאה ועברו לכתובת שמוצגת בטרמינל:

npm run dev
 ⛅️ wrangler 3.80.2
-------------------

⎔ Starting local server...
[wrangler:inf] Ready on http://localhost:8787
╭───────────────────────────╮
│  [b] open a browser       │
│  [d] open devtools        │
│  [l] turn off local mode  │
│  [c] clear console        │
│  [x] to exit              │
╰───────────────────────────╯

כאשר תפתחו את הכתובת בדפדפן, תראו שיש טופס להעלאת קובץ. אם תנסו להעלות קובץ, תשימו לב שהקובץ לא מועלה לשרת. הסיבה היא שה-front-end לא מחובר ל-back-end. בשלב הבא תעדכנו את ה-Worker שיטפל בהעלאת הקובץ.

#3. טיפול בהעלאת קובץ

כדי לטפל בהעלאת הקובץ, תחילה צריך להוסיף את ה-binding של R2. בקובץ Wrangler, הוסיפו את הקוד הבא:

{
	"r2_buckets": [
		{
			"binding": "MY_BUCKET",
			"bucket_name": "<R2_BUCKET_NAME>"
		}
	]
}
[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "<R2_BUCKET_NAME>"

החליפו את <R2_BUCKET_NAME> בשם של ה-bucket של R2.

לאחר מכן, עדכנו את הקובץ src/index.ts. הקובץ src/index.ts צריך להכיל את הקוד הבא:

src/index.ts:

export default {
	async fetch(request, env, ctx): Promise<Response> {
		// Get the pathname from the request
		const pathname = new URL(request.url).pathname;

		if (pathname === "/api/upload" && request.method === "POST") {
			// Get the file from the request
			const formData = await request.formData();
			const file = formData.get("pdfFile") as File;

			// Upload the file to Cloudflare R2
			const upload = await env.MY_BUCKET.put(file.name, file);
			return new Response("File uploaded successfully", { status: 200 });
		}

		return new Response("incorrect route", { status: 404 });
	},
} satisfies ExportedHandler<Env>;

הקוד שלמעלה עושה את הפעולות הבאות:

  • בודק אם הבקשה היא בקשת POST לנקודת הקצה /api/upload. אם כן, הוא מקבל את הקובץ מהבקשה ומעלה אותו ל-Cloudflare R2 באמצעות Workers API.
  • אם הבקשה אינה בקשת POST לנקודת הקצה /api/upload, הוא מחזיר תגובת 404.

מכיוון שקוד ה-Worker כתוב ב-TypeScript, כדאי להריץ את הפקודה הבאה כדי להוסיף את הגדרות הטיפוס הנדרשות. זה לא חובה, אבל זה יעזור להימנע משגיאות.

#מניעת שגיאות אפשריות בגישה ל-request.body

אפשר לגשת לגוף של Request ↗︎ רק פעם אחת. אם השתמשתם קודם ב-request.formData() באותה בקשה, ייתכן שתיתקלו ב-TypeError כאשר תנסו לגשת ל-request.body.

כדי להימנע משגיאות, צרו עותק של אובייקט ה-Request באמצעות request.clone() לכל ניסיון נוסף לגשת לגוף של Request. קחו בחשבון של-Workers יש מגבלת זיכרון של 128 MB לכל Worker, וטעינה של קבצים גדולים במיוחד לזיכרון של Worker כמה פעמים עלולה להגיע למגבלה הזו. כדי לוודא ששימוש הזיכרון לא מגיע למגבלה הזו, שקלו להשתמש ב-Streams.

npm run cf-typegen

אפשר להפעיל מחדש את שרת הפיתוח כדי לבדוק את השינויים:

npm run dev

#4. יצירת תור

התראות אירוע לוכדות שינויים בנתונים ב-bucket של R2. תצטרכו ליצור תור חדש pdf-summarize כדי לקבל התראות:

npx wrangler queues create pdf-summarizer

הוסיפו את ה-binding לקובץ Wrangler:

{
	"queues": {
		"consumers": [
			{
				"queue": "pdf-summarizer"
			}
		]
	}
}
[[queues.consumers]]
queue = "pdf-summarizer"

#5. טיפול בהתראות אירוע

עכשיו, כשיש תור לקבלת התראות אירוע, צריך לעדכן את ה-Worker כדי לטפל בהתראות האירוע. תצטרכו להוסיף Queue handler שיחלץ את התוכן הטקסטואלי מה-PDF, ישתמש ב-Workers AI כדי לסכם את התוכן, ואז ישמור אותו ב-bucket של R2.

עדכנו את הקובץ src/index.ts כדי להוסיף את ה-Queue handler:

src/index.ts:

export default {
	async fetch(request, env, ctx): Promise<Response> {
		// No changes in the fetch handler
	},
	async queue(batch, env) {
		for (let message of batch.messages) {
			console.log(`Processing the file: ${message.body.object.key}`);
		}
	},
} satisfies ExportedHandler<Env>;

הקוד שלמעלה עושה את הפעולות הבאות:

  • ה-handler של queue נקרא כאשר הודעה חדשה מתווספת לתור. הוא עובר על ההודעות ב-batch ורושם ביומן את שם הקובץ.

לעת עתה ה-handler של queue לא עושה דבר. בשלבים הבאים תעדכנו את ה-handler של queue כדי לחלץ את התוכן הטקסטואלי מה-PDF, להשתמש ב-Workers AI כדי לסכם את התוכן, ואז להוסיף אותו ל-bucket.

#6. חילוץ התוכן הטקסטואלי מה-PDF

כדי לחלץ את התוכן הטקסטואלי מה-PDF, ה-Worker ישתמש בספרייה unpdf ↗︎. הספרייה unpdf מספקת כלי עזר לעבודה עם קובצי PDF.

התקינו את הספרייה unpdf על ידי הרצת הפקודה הבאה:

npm:

npm i unpdf

yarn:

yarn add unpdf

pnpm:

pnpm add unpdf

bun:

bun add unpdf

עדכנו את הקובץ src/index.ts כדי לייבא את המודולים הנדרשים מספריית unpdf:

src/index.ts:

import { extractText, getDocumentProxy } from "unpdf";

לאחר מכן, עדכנו את ה-handler של queue כדי לחלץ את התוכן הטקסטואלי מה-PDF:

src/index.ts:

async queue(batch, env) {
  for(let message of batch.messages) {
    console.log(`Processing file: ${message.body.object.key}`);
    // Get the file from the R2 bucket
    const file = await env.MY_BUCKET.get(message.body.object.key);
    if (!file) {
				console.error(`File not found: ${message.body.object.key}`);
				continue;
			}
    // Extract the textual content from the PDF
    const buffer = await file.arrayBuffer();
    const document = await getDocumentProxy(new Uint8Array(buffer));

    const {text} = await extractText(document, {mergePages: true});
    console.log(`Extracted text: ${text.substring(0, 100)}...`);
    }
}

הקוד שלמעלה עושה את הפעולות הבאות:

  • ה-handler של queue מקבל את הקובץ מה-bucket של R2.
  • ה-handler של queue מחלץ את התוכן הטקסטואלי מה-PDF באמצעות הספרייה unpdf.
  • ה-handler של queue רושם ביומן את התוכן הטקסטואלי.

#7. שימוש ב-Workers AI כדי לסכם את התוכן

כדי להשתמש ב-Workers AI, תצטרכו להוסיף את ה-binding של Workers AI לקובץ Wrangler. קובץ Wrangler צריך להכיל את הקוד הבא:

{
	"ai": {
		"binding": "AI"
	}
}
[ai]
binding = "AI"

הריצו את הפקודה הבאה כדי להוסיף את הגדרת הטיפוס של AI:

npm run cf-typegen

עדכנו את הקובץ src/index.ts כדי להשתמש ב-Workers AI לסיכום התוכן:

src/index.ts:

async queue(batch, env) {
  for(let message of batch.messages) {
    // Extract the textual content from the PDF
    const {text} = await extractText(document, {mergePages: true});
    console.log(`Extracted text: ${text.substring(0, 100)}...`);

    // Use Workers AI to summarize the content
    const result: AiSummarizationOutput = await env.AI.run(
    "@cf/facebook/bart-large-cnn",
      {
        input_text: text,
      }
    );
    const summary = result.summary;
    console.log(`Summary: ${summary.substring(0, 100)}...`);
  }
}

ה-handler של queue משתמש עכשיו ב-Workers AI כדי לסכם את התוכן.

#8. הוספת הסיכום ל-bucket של R2

עכשיו, כשיש את הסיכום, צריך להוסיף אותו ל-bucket של R2. עדכנו את הקובץ src/index.ts כדי להוסיף את הסיכום ל-bucket של R2:

src/index.ts:

async queue(batch, env) {
  for(let message of batch.messages) {
    // Extract the textual content from the PDF
    // ...
    // Use Workers AI to summarize the content
    // ...

    // Add the summary to the R2 bucket
    const upload = await env.MY_BUCKET.put(`${message.body.object.key}-summary.txt`, summary, {
					httpMetadata: {
						contentType: 'text/plain',
					},
		});
		console.log(`Summary added to the R2 bucket: ${upload.key}`);
  }
}

ה-handler של התור מוסיף עכשיו את הסיכום ל-bucket של R2 כקובץ טקסט.

#9. הפעלת התראות אירוע

ה-handler של queue מוכן לטפל בהודעות התראת אירוע נכנסות. צריך להפעיל התראות אירוע באמצעות הפקודה wrangler r2 bucket notification create עבור ה-bucket. הפקודה הבאה יוצרת התראת אירוע עבור סוג האירוע object-create עבור הסיומת pdf:

npx wrangler r2 bucket notification create <R2_BUCKET_NAME> --event-type object-create --queue pdf-summarizer --suffix "pdf"

החליפו את <R2_BUCKET_NAME> בשם של ה-bucket של R2.

נוצרת התראת אירוע עבור הסיומת pdf. כאשר קובץ חדש עם הסיומת pdf מועלה ל-bucket של R2, התור pdf-summarizer מופעל.

#10. פריסת ה-Worker

כדי לפרוס את ה-Worker, הריצו את הפקודה wrangler deploy:

npx wrangler deploy

בפלט של הפקודה wrangler deploy, העתיקו את הכתובת. זו הכתובת של היישום הפרוס.

#11. בדיקה

כדי לבדוק את היישום, עברו לכתובת של היישום הפרוס והעלו קובץ PDF. לחלופין, אפשר להשתמש בלוח הבקרה של Cloudflare ↗︎ כדי להעלות קובץ PDF.

כדי להציג את היומנים, אפשר להשתמש בפקודה wrangler tail.

npx wrangler tail

תראו את היומנים בטרמינל. אפשר גם לעבור ללוח הבקרה של Cloudflare ולהציג את היומנים במקטע Workers Logs.

אם תבדקו את ה-bucket של R2, תראו את קובץ הסיכום.

#סיכום

במדריך זה למדתם כיצד להשתמש בהתראות אירוע של R2 כדי לעבד אובייקט בעת העלאה. יצרתם יישום להעלאת קובץ PDF, ויצרתם Worker צרכן שיוצר סיכום של קובץ ה-PDF. למדתם גם כיצד להשתמש ב-Workers AI כדי לסכם את התוכן של קובץ ה-PDF, ולהעלות את הסיכום ל-bucket של R2.

אפשר להשתמש באותה גישה כדי לעבד סוגים אחרים של קבצים, כמו תמונות, סרטונים וקובצי שמע. אפשר גם להשתמש באותה גישה כדי לעבד סוגים אחרים של אירועים, כמו מחיקת אובייקט ועדכון אובייקט.

אם תרצו להציג את הקוד של המדריך הזה, אפשר למצוא אותו ב-GitHub ↗︎.