Tutorial Tutorial Developer Platform Developer Platform ~88 phút ~88 min Đồng bộ 2026-06-10 Synced 2026-06-10

Sử dụng event notification to summarize PDF files on upload Use event notification to summarize PDF files on upload

Hướng dẫn chi tiết đồng bộ từ docs Cloudflare — mỗi section có backlink tới đúng vị trí trên trang gốc. Detailed guide synced from Cloudflare docs — each section links to the matching anchor on the official page.

← Danh mục ← Catalog

Giải thích nhanh Quick context

Thuộc Developer Platform — thực hành triển khai code, API và dữ liệu trên edge/serverless. Tutorial «Sử dụng event notification to summarize PDF files on upload» giúp bạn làm quen luồng triển khai thật — phù hợp đọc trước khi mở tài liệu gốc tiếng Anh. Docs gốc chia khoảng 11 bước chính; bản tóm tắt dưới đây giúp bạn nắm khung trước khi làm theo từng lệnh.

Use event notification to summarize PDF files on upload. Use Workers AI to summarize the PDF and store the summary as a text file.

Lưu ý trước khi làm Notes before you start

  • Đây là bản tóm tắt trên Orange Cloud Learning Hub — không thay thế tài liệu chính thức. This is a summary on Orange Cloud Learning Hub — it does not replace the official documentation.
  • Luôn mở liên kết «Tài liệu gốc» bên dưới khi cần lệnh CLI, snippet code và ảnh minh họa đầy đủ. Open the Official docs link below for CLI commands, code snippets, and full screenshots.
  • Cần tài khoản Cloudflare, Wrangler CLI và (thường) hoàn thành hướng dẫn Get started của Workers/Pages. Requires a Cloudflare account, Wrangler CLI, and (typically) completing the Workers/Pages Get started guide.
  • Docs Cloudflare cập nhật thường xuyên — đối chiếu ngày «Rà soát lần cuối» trên trang gốc khi triển khai production. Cloudflare docs change frequently — verify the Last reviewed date on the official page before production use.

Tài liệu gốc — rà soát lần cuối: over 1 year ago Official docs — last reviewed: over 1 year ago

Tổng quan Overview

Trong tutorial này, bạn sẽ use event notifications to process a PDF file when it is uploaded to an R2 bucket. You will use Workers AI to summarize the PDF and store the summary as a text file in the same bucket.

Read the "Overview" section below — open the official docs link for full screenshots and configuration tabs.

Mở section docs gốc ↗ Open source section ↗

In this tutorial, you will learn how to use event notifications to process a PDF file when it is uploaded to an R2 bucket. You will use Workers AI to summarize the PDF and store the summary as a text file in the same bucket.

Liên kết liên quan (docs Cloudflare) Related links (Cloudflare docs)

Yêu cầu trước Prerequisites

Phần «Yêu cầu trước» — đọc hướng dẫn bên dưới, dùng liên kết docs gốc để xem ảnh minh họa và tab cấu hình đầy đủ.

Read the "Prerequisites" section below — open the official docs link for full screenshots and configuration tabs.

Mở section docs gốc ↗ Open source section ↗

To continue, you will need:

Node.js version manager

Use a Node version manager like Volta ↗ ornvm ↗ to avoid permission issues and change Node.js versions. Wrangler, discussed later in this guide, requires a Node version of 16.17.0 or later.

Liên kết liên quan (docs Cloudflare) Related links (Cloudflare docs)

1. Tạo dự án mới 1. Create a new project

Bạn sẽ create a new Worker project that will use Static Assets to serve the front-end of your application. A user can upload a PDF file using this front-end, which will then be processed by your Worker.

Read the "1. Create a new project" section below — open the official docs link for full screenshots and configuration tabs.

Mở section docs gốc ↗ Open source section ↗

You will create a new Worker project that will use Static Assets to serve the front-end of your application. A user can upload a PDF file using this front-end, which will then be processed by your Worker.

Create a new Worker project by running the following commands:

npm yarn pnpm

text
npm create cloudflare@latest -- pdf-summarizer
text
yarn create cloudflare pdf-summarizer
text
pnpm create cloudflare@latest pdf-summarizer

For setup, select the following options:

  • For What would you like to start with?, choose Hello World example.
  • For Which template would you like to use?, choose Worker only.
  • For Which language do you want to use?, choose TypeScript.
  • For Do you want to use git for version control?, choose Yes.
  • For Do you want to deploy your application?, choose No (we will be making some changes before deploying).

Navigate to the pdf-summarizer directory:

text
cd pdf-summarizer

Liên kết liên quan (docs Cloudflare) Related links (Cloudflare docs)

2. Tạo front-end 2. Create the front-end

Phần «Tạo front-end» — đọc hướng dẫn bên dưới, dùng liên kết docs gốc để xem ảnh minh họa và tab cấu hình đầy đủ.

Read the "2. Create the front-end" section below — open the official docs link for full screenshots and configuration tabs.

Mở section docs gốc ↗ Open source section ↗

Using Static Assets, you can serve the front-end of your application from your Worker. To use Static Assets, you need to add the required bindings to your Wrangler file.

JSONC

text
{

  "assets": {

    "directory": "public"

  }

}

TOML

text
[assets]

directory = "public"

Next, create a public directory and add an index.html file. The index.html file should contain the following HTML code:

Select to view the HTML code

text
<!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>

To view the front-end of your application, run the following command and navigate to the URL displayed in the terminal:

Terminal window

text
npm run dev
text
⛅️ 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              │

╰───────────────────────────╯

When you open the URL in your browser, you will see that there is a file upload form. If you try uploading a file, you will notice that the file is not uploaded to the server. This is because the front-end is not connected to the back-end. In the next step, you will update your Worker that will handle the file upload.

3. Xử lý file upload 3. Handle file upload

Phần «Xử lý file upload» — đọc hướng dẫn bên dưới, dùng liên kết docs gốc để xem ảnh minh họa và tab cấu hình đầy đủ.

Read the "3. Handle file upload" section below — open the official docs link for full screenshots and configuration tabs.

Mở section docs gốc ↗ Open source section ↗

To handle the file upload, you will first need to add the R2 binding. In the Wrangler file, add the following code:

JSONC

text
{

  "r2_buckets": [

    {

      "binding": "MY_BUCKET",

      "bucket_name": "<R2_BUCKET_NAME>"

    }

  ]

}

TOML

text
[[r2_buckets]]

binding = "MY_BUCKET"

bucket_name = "<R2_BUCKET_NAME>"

Replace <R2BUCKETNAME> with the name of your R2 bucket.

Next, update the src/index.ts file. The src/index.ts file should contain the following code:

src/index.ts

text
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>;

The above code does the following:

  • Check if the request is a POST request to the /api/upload endpoint. If it is, it gets the file from the request and uploads it to Cloudflare R2 using the Workers API.
  • If the request is not a POST request to the /api/upload endpoint, it returns a 404 response.

Since the Worker code is written in TypeScript, you should run the following command to add the necessary type definitions. While this is not required, it will help you avoid errors.

Prevent potential errors when accessing request.body

The body of a Request ↗ can only be accessed once. If you previously used request.formData() in the same request, you may encounter a TypeError when attempting to access request.body.

To avoid errors, create a clone of the Request object with request.clone() for each subsequent attempt to access a Request's body. Keep in mind that Workers have a memory limit of 128 MB per Worker and loading particularly large files into a Worker's memory multiple times may reach this limit. To ensure memory usage does not reach this limit, consider using Streams.

Terminal window

text
npm run cf-typegen

You can restart the developer server to test the changes:

Terminal window

text
npm run dev

Liên kết liên quan (docs Cloudflare) Related links (Cloudflare docs)

4. Tạo queue 4. Create a queue

Phần «Tạo queue» — đọc hướng dẫn bên dưới, dùng liên kết docs gốc để xem ảnh minh họa và tab cấu hình đầy đủ.

Read the "4. Create a queue" section below — open the official docs link for full screenshots and configuration tabs.

Mở section docs gốc ↗ Open source section ↗

Event notifications capture changes to data in your R2 bucket. You will need to create a new queue pdf-summarize to receive notifications:

Terminal window

text
npx wrangler queues create pdf-summarizer

Add the binding to the Wrangler file:

JSONC

text
{

  "queues": {

    "consumers": [

      {

        "queue": "pdf-summarizer"

      }

    ]

  }

}

TOML

text
[[queues.consumers]]

queue = "pdf-summarizer"

5. Xử lý event notifications 5. Handle event notifications

Phần «Xử lý event notifications» — đọc hướng dẫn bên dưới, dùng liên kết docs gốc để xem ảnh minh họa và tab cấu hình đầy đủ.

Read the "5. Handle event notifications" section below — open the official docs link for full screenshots and configuration tabs.

Mở section docs gốc ↗ Open source section ↗

Now that you have a queue to receive event notifications, you need to update the Worker to handle the event notifications. You will need to add a Queue handler that will extract the textual content from the PDF, use Workers AI to summarize the content, and then save it in the R2 bucket.

Update the src/index.ts file to add the Queue handler:

src/index.ts

text
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>;

The above code does the following:

  • The queue handler is called when a new message is added to the queue. It loops through the messages in the batch and logs the name of the file.

For now the queue handler is not doing anything. In the next steps, you will update the queue handler to extract the textual content from the PDF, use Workers AI to summarize the content, and then add it to the bucket.

6. Extract textual content từ PDF 6. Extract the textual content from the PDF

Phần «Extract textual content từ PDF» — đọc hướng dẫn bên dưới, dùng liên kết docs gốc để xem ảnh minh họa và tab cấu hình đầy đủ.

Read the "6. Extract the textual content from the PDF" section below — open the official docs link for full screenshots and configuration tabs.

Mở section docs gốc ↗ Open source section ↗

To extract the textual content from the PDF, the Worker will use the unpdf ↗ library. The unpdf library provides utilities to work with PDF files.

Install the unpdf library by running the following command:

npm yarn pnpm bun

text
npm i unpdf
text
yarn add unpdf
text
pnpm add unpdf
text
bun add unpdf

Update the src/index.ts file to import the required modules from the unpdf library:

src/index.ts

text
import { extractText, getDocumentProxy } from "unpdf";

Next, update the queue handler to extract the textual content from the PDF:

src/index.ts

text
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)}...`);

    }

}

The above code does the following:

  • The queue handler gets the file from the R2 bucket.
  • The queue handler extracts the textual content from the PDF using the unpdf library.
  • The queue handler logs the textual content.

7. Sử dụng Workers AI to summarize content 7. Use Workers AI to summarize the content

Phần «Sử dụng Workers AI to summarize content» — đọc hướng dẫn bên dưới, dùng liên kết docs gốc để xem ảnh minh họa và tab cấu hình đầy đủ.

Read the "7. Use Workers AI to summarize the content" section below — open the official docs link for full screenshots and configuration tabs.

Mở section docs gốc ↗ Open source section ↗

To use Workers AI, you will need to add the Workers AI binding to the Wrangler file. The Wrangler file should contain the following code:

JSONC

text
{

  "ai": {

    "binding": "AI"

  }

}

TOML

text
[ai]

binding = "AI"

Execute the following command to add the AI type definition:

Terminal window

text
npm run cf-typegen

Update the src/index.ts file to use Workers AI to summarize the content:

src/index.ts

text
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)}...`);

  }

}

The queue handler now uses Workers AI to summarize the content.

8. Thêm summary to R2 bucket 8. Add the summary to the R2 bucket

Phần «Thêm summary to R2 bucket» — đọc hướng dẫn bên dưới, dùng liên kết docs gốc để xem ảnh minh họa và tab cấu hình đầy đủ.

Read the "8. Add the summary to the R2 bucket" section below — open the official docs link for full screenshots and configuration tabs.

Mở section docs gốc ↗ Open source section ↗

Now that you have the summary, you need to add it to the R2 bucket. Update the src/index.ts file to add the summary to the R2 bucket:

src/index.ts

text
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}`);

  }

}

The queue handler now adds the summary to the R2 bucket as a text file.

9. Enable event notifications 9. Enable event notifications

Phần «Enable event notifications» — đọc hướng dẫn bên dưới, dùng liên kết docs gốc để xem ảnh minh họa và tab cấu hình đầy đủ.

Read the "9. Enable event notifications" section below — open the official docs link for full screenshots and configuration tabs.

Mở section docs gốc ↗ Open source section ↗

Your queue handler is ready to handle incoming event notification messages. You need to enable event notifications with the wrangler r2 bucket notification create command for your bucket. The following command creates an event notification for the object-create event type for the pdf suffix:

Terminal window

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

Replace <R2BUCKETNAME> with the name of your R2 bucket.

An event notification is created for the pdf suffix. When a new file with the pdf suffix is uploaded to the R2 bucket, the pdf-summarizer queue is triggered.

Liên kết liên quan (docs Cloudflare) Related links (Cloudflare docs)

10. Triển khai your Worker 10. Deploy your Worker

Phần «Triển khai your Worker» — đọc hướng dẫn bên dưới, dùng liên kết docs gốc để xem ảnh minh họa và tab cấu hình đầy đủ.

Read the "10. Deploy your Worker" section below — open the official docs link for full screenshots and configuration tabs.

Mở section docs gốc ↗ Open source section ↗

To deploy your Worker, run the wrangler deploy command:

Terminal window

text
npx wrangler deploy

In the output of the wrangler deploy command, copy the URL. This is the URL of your deployed application.

Liên kết liên quan (docs Cloudflare) Related links (Cloudflare docs)

11. Test 11. Test

Phần «Test» — đọc hướng dẫn bên dưới, dùng liên kết docs gốc để xem ảnh minh họa và tab cấu hình đầy đủ.

Read the "11. Test" section below — open the official docs link for full screenshots and configuration tabs.

Mở section docs gốc ↗ Open source section ↗

To test the application, navigate to the URL of your deployed application and upload a PDF file. Alternatively, you can use the Cloudflare dashboard ↗ to upload a PDF file.

To view the logs, you can use the wrangler tail command.

Terminal window

text
npx wrangler tail

You will see the logs in your terminal. You can also navigate to the Cloudflare dashboard and view the logs in the Workers Logs section.

If you check your R2 bucket, you will see the summary file.

Liên kết liên quan (docs Cloudflare) Related links (Cloudflare docs)

Kết luận Conclusion

Phần «Kết luận» — đọc hướng dẫn bên dưới, dùng liên kết docs gốc để xem ảnh minh họa và tab cấu hình đầy đủ.

Read the "Conclusion" section below — open the official docs link for full screenshots and configuration tabs.

Mở section docs gốc ↗ Open source section ↗

In this tutorial, you learned how to use R2 event notifications to process an object on upload. You created an application to upload a PDF file, and created a consumer Worker that creates a summary of the PDF file. You also learned how to use Workers AI to summarize the content of the PDF file, and upload the summary to the R2 bucket.

You can use the same approach to process other types of files, such as images, videos, and audio files. You can also use the same approach to process other types of events, such as object deletion, and object update.

If you want to view the code for this tutorial, you can find it on GitHub ↗.

json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/r2/","name":"R2"}},{"@type":"ListItem","position":3,"item":{"@id":"/r2/tutorials/","name":"Tutorials"}},{"@type":"ListItem","position":4,"item":{"@id":"/r2/tutorials/summarize-pdf/","name":"Use event notification to summarize PDF files on upload"}}]}

Xem bản đầy đủ trên developers.cloudflare.com (ảnh, tab cấu hình). View the full guide on developers.cloudflare.com (images, config tabs).

Tài liệu gốc ↗ Official docs ↗