Skip to content

Added overview pages for guides and examples, and improved examples #1314

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions docs/examples/dall-e3-generate-image.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ export const generateContent = task({
maxAttempts: 3, // Retry up to 3 times
},
run: async ({ theme, description }: Payload) => {

// Generate text
const textResult = await openai.chat.completions.create({
model: "gpt-4o",
Expand Down Expand Up @@ -64,4 +63,15 @@ function generateTextPrompt(theme: string, description: string): any {
function generateImagePrompt(theme: string, description: string): any {
return `Theme: ${theme}\n\nDescription: ${description}`;
}
```
```

## Testing your task

To test this task in the dashboard, you can use the following payload:

```json
{
"theme": "A beautiful sunset",
"description": "A sunset over the ocean with a tiny yacht in the distance."
}
```
115 changes: 73 additions & 42 deletions docs/examples/ffmpeg-video-processing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,13 @@ export const ffmpegCompressVideo = task({

// Read the compressed video
const compressedVideo = await fs.readFile(outputPath);

const compressedSize = compressedVideo.length;

// Log compression results
logger.log(`Compressed video size: ${compressedSize} bytes`);
logger.log(`Compressed video saved at: ${outputPath}`);
logger.log(`Temporary compressed video file created`, { outputPath });

// Upload the compressed video to S3, replacing slashes with underscores
// Create the r2Key for the extracted audio, using the base name of the output path
const r2Key = `processed-videos/${path.basename(outputPath)}`;

const uploadParams = {
Expand All @@ -116,22 +115,31 @@ export const ffmpegCompressVideo = task({

// Upload the video to R2 and get the URL
await s3Client.send(new PutObjectCommand(uploadParams));
const r2Url = `https://${process.env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com/${process.env.R2_BUCKET}/${r2Key}`;
logger.log("Compressed video uploaded to R2", { url: r2Url });
logger.log(`Compressed video saved to your r2 bucket`, { r2Key });

// Delete the temporary compressed video file
await fs.unlink(outputPath);
logger.log(`Temporary compressed video file deleted`, { outputPath });

// Return the compressed video file path, compressed size, and S3 URL
// Return the compressed video buffer and r2 key
return {
compressedVideoPath: outputPath,
compressedSize,
r2Url,
Bucket: process.env.R2_BUCKET,
r2Key,
};
},
});
```

### Testing:

To test this task, use this payload structure:

```json
{
"videoUrl": "<video-url>"
}
```

## Extract audio from a video using FFmpeg

This task demonstrates how to use FFmpeg to extract audio from a video, convert it to WAV format, and upload it to R2 storage.
Expand All @@ -145,11 +153,6 @@ This task demonstrates how to use FFmpeg to extract audio from a video, convert

### Task code

<Warning>
When testing, make sure to provide a video URL that contains audio. If the video does not have
audio, the task will fail.
</Warning>

```ts trigger/ffmpeg-extract-audio.ts
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
import { logger, task } from "@trigger.dev/sdk/v3";
Expand All @@ -176,63 +179,81 @@ export const ffmpegExtractAudio = task({
run: async (payload: { videoUrl: string }) => {
const { videoUrl } = payload;

// Generate temporary and output file names
// Generate temporary file names
const tempDirectory = os.tmpdir();
const outputPath = path.join(tempDirectory, `output_${Date.now()}.wav`);
const outputPath = path.join(tempDirectory, `audio_${Date.now()}.wav`);

// Fetch the video
const response = await fetch(videoUrl);

// Convert the video to WAV
// Extract the audio
await new Promise((resolve, reject) => {
if (!response.body) {
return reject(new Error("Failed to fetch video"));
}

ffmpeg(Readable.from(response.body))
.toFormat("wav")
.save(outputPath)
.on("end", () => {
logger.log(`WAV file saved to ${outputPath}`);
resolve(outputPath);
})
.on("error", (err) => {
reject(err);
});
.outputOptions([
"-vn", // Disable video output
"-acodec pcm_s16le", // Use PCM 16-bit little-endian encoding
"-ar 44100", // Set audio sample rate to 44.1 kHz
"-ac 2", // Set audio channels to stereo
])
.output(outputPath)
.on("end", resolve)
.on("error", reject)
.run();
});

// Read the WAV file
const wavBuffer = await fs.readFile(outputPath);
// Read the extracted audio
const audioBuffer = await fs.readFile(outputPath);
const audioSize = audioBuffer.length;

// Log the output file path
logger.log(`Converted video saved at: ${outputPath}`);
// Log audio extraction results
logger.log(`Extracted audio size: ${audioSize} bytes`);
logger.log(`Temporary audio file created`, { outputPath });

// Upload the compressed video to S3, replacing slashes with underscores
const r2Key = `processed-audio/${path.basename(outputPath)}`;
// Create the r2Key for the extracted audio, using the base name of the output path
const r2Key = `extracted-audio/${path.basename(outputPath)}`;

const uploadParams = {
Bucket: process.env.R2_BUCKET,
Key: r2Key,
Body: wavBuffer,
Body: audioBuffer,
};

// Upload the audio to R2 and get the URL
await s3Client.send(new PutObjectCommand(uploadParams));
const r2Url = `https://${process.env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com/${process.env.R2_BUCKET}/${r2Key}`;
logger.log("Extracted audio uploaded to R2", { url: r2Url });
logger.log(`Extracted audio saved to your R2 bucket`, { r2Key });

// Delete the temporary file
// Delete the temporary audio file
await fs.unlink(outputPath);
logger.log(`Temporary audio file deleted`, { outputPath });

// Return the WAV buffer and file path
// Return the audio file path, size, and R2 URL
return {
wavBuffer,
wavFilePath: outputPath,
r2Url,
Bucket: process.env.R2_BUCKET,
r2Key,
};
},
});
```

### Testing:

To test this task, use this payload structure:

<Warning>
Make sure to provide a video URL that contains audio. If the video does not have audio, the task
will fail.
</Warning>

```json
{
"videoUrl": "<video-url>"
}
```

## Generate a thumbnail from a video using FFmpeg

This task demonstrates how to use FFmpeg to generate a thumbnail from a video at a specific time and upload the generated thumbnail to R2 storage.
Expand Down Expand Up @@ -298,7 +319,7 @@ export const ffmpegGenerateThumbnail = task({
// Read the generated thumbnail
const thumbnail = await fs.readFile(outputPath);

// Upload the compressed video to S3, replacing slashes with underscores
// Create the r2Key for the extracted audio, using the base name of the output path
const r2Key = `thumbnails/${path.basename(outputPath)}`;

const uploadParams = {
Expand All @@ -318,7 +339,7 @@ export const ffmpegGenerateThumbnail = task({
// Log thumbnail generation results
logger.log(`Thumbnail uploaded to S3: ${r2Url}`);

// Return the thumbnail buffer, file path, sizes, and S3 URL
// Return the thumbnail buffer, path, and R2 URL
return {
thumbnailBuffer: thumbnail,
thumbnailPath: outputPath,
Expand All @@ -327,3 +348,13 @@ export const ffmpegGenerateThumbnail = task({
},
});
```

## Testing your task

To test this task in the dashboard, you can use the following payload:

```json
{
"videoUrl": "<video-url>"
}
```
15 changes: 15 additions & 0 deletions docs/examples/intro.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
title: "Introduction"
sidebarTitle: "Introduction"
description: "Learn how to use Trigger.dev with these practical task examples."
---

| Example task | Description |
| :------------------------------------------------------------ | :-------------------------------------------------------------------------- |
| [DALL·E 3 image generation](/examples/dall-e3-generate-image) | Use OpenAI's GPT-4o and DALL·E 3 to generate an image and text. |
| [FFmpeg video processing](/examples/ffmpeg-video-processing) | Use FFmpeg to process a video in various ways and save it to Cloudflare R2. |
| [OpenAI with retrying](/examples/open-ai-with-retrying) | Create a reusable OpenAI task with custom retry options. |
| [React to PDF](/examples/react-pdf) | Use `react-pdf` to generate a PDF and save it to Cloudflare R2. |
| [Resend email sequence](/examples/resend-email-sequence) | Send a sequence of emails over several days using Resend with Trigger.dev. |
| [Sharp image processing](/examples/sharp-image-processing) | Use Sharp to process an image and save it to Cloudflare R2. |
| [Vercel AI SDK](/examples/vercel-ai-sdk) | Use Vercel AI SDK to generate text using OpenAI. |
11 changes: 10 additions & 1 deletion docs/examples/open-ai-with-retrying.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,14 @@ export const openaiTask = task({
return chatCompletion.choices[0].message.content;
},
});
```

```
## Testing your task

To test this task in the dashboard, you can use the following payload:

```json
{
"prompt": "What is the meaning of life?"
}
```
56 changes: 36 additions & 20 deletions docs/examples/react-pdf.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,18 @@ This example demonstrates how to use Trigger.dev to generate a PDF using `react-

## Task code

```ts trigger/generateResumePDF.ts
<Info> This example must be a .tsx file to use React components. </Info>

```ts trigger/generateResumePDF.tsx
import { logger, task } from "@trigger.dev/sdk/v3";
import { Document, Page, Text, View } from "@react-pdf/renderer";
import { renderToBuffer } from "@react-pdf/renderer";
import { renderToBuffer, Document, Page, Text, View } from "@react-pdf/renderer";
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";

// Initialize S3 client
const s3Client = new S3Client({
// Initialize R2 client
const r2Client = new S3Client({
// How to authenticate to R2: https://developers.cloudflare.com/r2/api/s3/tokens/
region: "auto",
endpoint: process.env.S3_ENDPOINT,
endpoint: process.env.R2_ENDPOINT,
credentials: {
accessKeyId: process.env.R2_ACCESS_KEY_ID ?? "",
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY ?? "",
Expand All @@ -29,6 +31,7 @@ const s3Client = new S3Client({
export const generateResumePDF = task({
id: "generate-resume-pdf",
run: async (payload: { text: string }) => {
// Log the payload
logger.log("Generating PDF resume", payload);

// Render the ResumeDocument component to a PDF buffer
Expand All @@ -42,28 +45,41 @@ export const generateResumePDF = task({
</Document>
);

// Generate a unique filename
const filename = `${payload.text
.replace(/\s+/g, "-")
.toLowerCase()}-${Date.now()}.pdf`;
// Generate a unique filename based on the text and current timestamp
const filename = `${payload.text.replace(/\s+/g, "-").toLowerCase()}-${Date.now()}.pdf`;

// Set the R2 key for the PDF file
const r2Key = `resumes/${filename}`;

// Upload to R2
const s3Key = `resumes/${filename}`;
// Set the upload parameters for R2
const uploadParams = {
Bucket: process.env.S3_BUCKET,
Key: s3Key,
Bucket: process.env.R2_BUCKET,
Key: r2Key,
Body: pdfBuffer,
ContentType: "application/pdf",
};

// Log the upload parameters
logger.log("Uploading to R2 with params", uploadParams);

// Upload the PDF to R2 and return the URL.
await s3Client.send(new PutObjectCommand(uploadParams));
const s3Url = `https://${process.env.S3_BUCKET}.s3.amazonaws.com/${s3Key}`;
logger.log("PDF uploaded to R2", { url: s3Url });
return { pdfUrl: s3Url };
// Upload the PDF to R2
await r2Client.send(new PutObjectCommand(uploadParams));

// Return the Bucket and R2 key for the uploaded PDF
return {
Bucket: process.env.R2_BUCKET,
Key: r2Key,
};
},
});
```

## Testing your task

To test this task in the dashboard, you can use the following payload:

```
```json
{
"text": "Hello, world!"
}
```
Loading
Loading