Build a Video Processing Pipeline with AssemblyAI on Koyeb
24 minIntroduction
In the digital era, video is the king, demanding innovative solutions for efficient processing and distribution.
This guide introduces a powerful approach using Koyeb's cloud services to build a scalable video processing pipeline. We will rely on secure protocols for video uploads, employ AI-driven tagging and classification via AssemblyAI, and leverage Koyeb's built-in CDN technology for global content distribution. Embrace the power of serverless architecture to meet the growing demand for video content, ensuring optimal performance and viewer satisfaction.
You can follow along with this guide by viewing the GitHub repositories for the video web app and the video worker service.
Requirements
Before diving into building your video processing pipeline with Koyeb, it's important to ensure that you have the necessary tools and knowledge. This section outlines the prerequisites needed to follow the upcoming guide successfully.
- A Koyeb account will be required for deploying. It will be helpful to have a foundational understanding of its service offerings (web service and database, in this case).
- An AssemblyAI API key to integrate AI-driven video tagging and classification capabilities. Note: You will need to add credit to your account to use the LLM features implemented in this guide.
- Knowledge of Python programming for scripting and automation within the serverless architecture.
- Experience with Django for developing robust, scalable web applications that interfaces effectively with back-end services.
Steps
- Set up the database: This step involves setting up a database service on Koyeb to store and manage video metadata. This database will be used by the web application to store and access data.
- Build the web application: This section guides you through developing a simple web application for video uploads along with features to view and search videos. The application is built with Django.
- Build the worker service: This step covers implementing a service API that processes the video uploads. The API will incorporate AI technologies from AssemblyAI for tagging, classifying, and potentially transcoding videos. Additionally, the API will utilize Koyeb's autoscaling features to efficiently manage varying video processing loads.
- Integrate with Koyeb's edge network: This section details how to integrate the web application with Koyeb's edge network to enhance the distribution of video content globally.
Set up the database
Setting up the database is an important part of this process. This database will be used to keep and organize video metadata, such as video titles, descriptions, lengths, file types, and other important information.
For this article you are going to setup a PostgreSQL database using Koyeb's recent fully-managed serverless PostgreSQL databases feature.
Here's a step-by-step guide on how to set up the database on Koyeb:
- In the Koyeb control panel, click Create Database Service.
- Choose alternatives to or confirm the provided defaults for the name and role fields.
- Choose the region closest to you or your users.
- Select the database size. If you are not already using it, you can deploy the Free tire as the Instance type.
- Click Create Database Service.
Once the database is created, access the database's detail page and there you can check the connection details.
Since you will be using Django later, select Django and copy the database connection details. Store this locally somewhere so that you can reference it later. It will look like something like this:
Once you've completed these steps, your database will be ready to store and manage video metadata for your application.
Build the web application
This part of the guide will show you how to make a simple web application using Django and deploy it to Koyeb. This app will let users upload videos and also provide features to watch for these uploaded videos.
The focus of this article is the end-to-end process, so in this section we will only highlight the code relevant to this process. You can check the full source code in the project's GitHub repository.
Create a virtual environment and initialize a new project
To get started, create a project directory and then initialize a new virtual environment inside by typing:
Activate the new virtual environment by typing:
Install Django within the virtual environment. We'll also install some additional libraries and packages that we'll use in the application while we're here:
Save the project's dependencies to a requirements.txt
file by typing:
With Django installed, create a new Django project called VideoApp rooted in the existing project directory (be sure to include the trailing dot to avoid creating an extra directory hierarchy):
Next, create a new Django application called App that the project will incorporate:
This will create a new App
directory alongside the existing VideoApp
directory.
Set up the app models
In the App/models.py
file, you can now define the Django models for the video metadata. Replace the current contents with the following:
Here you are defining three database models: Video
, Tag
, and Category
.
The Video
model is used to store video metadata, including the title, description, video file, upload date and time, duration, and size.
The Tag
model is used to store video-related tags. It has a many-to-many relationship with the Video
model, meaning that a video can have multiple tags and a tag can be associated with multiple videos. The related_name
attribute specifies the name of the reverse relation from the Video
model back to the Tag
model.
The Category
model is used to store video classifications. It also has a many-to-many relationship with the Video
model, meaning that a video can belong to multiple categories and a category can contain multiple videos. The related_name
attribute specifies the name of the reverse relation from the Video
model back to the Category
model.
Create a video upload form
In order to be able to upload any videos, you need to have a form defined in Django, let's now create that in App/forms.py
:
The VideoForm
is a ModelForm
, a special form created from a Django model. In this case, the Video
model is used.
The Meta
class inside VideoForm
is used to specify additional metadata for the form. The model
attribute indicates which Django model this form is associated with, and the fields
attribute is a list of model fields that should be included in the form. In this case, the form includes fields for title
, description
, video_file
.
The tags
and categories
, as well as duration
and size
will be filled in later on with the results from the worker service API.
This form will allow users to input data for these fields, which will then be saved as a new Video
object in the database when the form is submitted.
Configure the App views
With the form in place, next you can create the view that will handle the form submission. Replace the contents of App/views.py
with the following:
The upload_video
view function handles the video upload process. When a user submits the video upload form, this function is called to process the form data. It starts by creating an instance of the VideoForm
with the form data and files. If the form is valid, it saves the video, processes the video file with a worker service, and saves the video metadata (tags, categories, duration, and resolution) returned by the worker service API. If the form is not valid, it returns the form with errors. If the request method is not POST, it simply renders the video upload form.
The list_videos
view function retrieves all videos from the database and renders them in a template.
Create the application templates
In order for this view to work, you will need to create the HTML template. Create a new directory for HTML templates:
Inside, create a new file at App/templates/upload_video.html
with the following content:
This HTML markup creates a simple web page for uploading videos.
The video upload form is created using the HTML <form>
tag. The method
attribute is set to post
, which means the form data will be sent to the server using the HTTP POST
method. The enctype
attribute is set to "multipart/form-data", which is necessary for forms that allow file uploads. The {% csrf_token %}
template tag is used to protect against cross-site request forgery attacks.
When the form is submitted, the data is sent to the server and handled by the upload_video
view function in the views.py
file. As mentioned earlier, if the form is valid, the video is saved and processed by the worker service, and a success message is displayed. If the form is not valid, an error message is displayed.
You will also need an HTML template to list the videos. Add the following to a App/templates/list_videos.html
file:
The {% for video in videos %}
template tag is used to loop through the list of videos passed from the list_videos
view function in the views.py
file. For each video, it displays the video player, title, description, tags, categories, duration, and resolution.
The <video>
element embeds a video player in the web page. The controls
attribute is used to display the video controls, such as play, pause, and volume. The width
and height
attributes are used to set the size of the video player. The <source>
element is used to specify the video file and its MIME type.
The {{ video.title }}
, {{ video.description }}
, {{ video.duration }}
, and {{ video.size }}
template tags are used to display the video metadata.
The {% for tag in video.tags.all %}
and {% for category in video.categories.all %}
template tags are used to loop through the list of tags and categories associated with the video. The {{ tag.name }}
and {{ category.name }}
template tags are used to display the name of each tag and category.
When the web page is loaded, the list_videos
view function in the views.py
file is called to retrieve the list of videos from the database and pass it to the template. The template then loops through the list of videos and displays them on the web page.
Define the URL routing
To access the views and HTML templates, you need to define the URLs, which you can add to App/urls.py
:
The urlpatterns
list contains two path
objects that map URLs to view functions. The first path
object maps the root URL ('') to the list_videos
view function and assigns it the name 'list_videos'. This means that when a user navigates to the /
URL of the application, the list_videos
view function will be called to handle the request and render the appropriate response.
The second path
object maps the 'upload' URL to the upload_video
view function and assigns it the name 'upload_video'. This means that when a user navigates to the /upload
URL, the upload_video
view function will be called to handle the request and render the appropriate response.
Hook the new App/urls.py
file in to the project URL processing by editing the VideoApp/urls.py
file as follows:
Adjust the project configuration
Hook the application up with the project by editing the VideoApp/settings.py
file and adding the AppConfig
instance declared in the App/apps.py
file to the list of INSTALLED_APPS
:
You also need to make sure that we connect the Django project to the PostgreSQL database defined earlier. Also in the VideoApp/settings.py
file, edit the DATABASES
dictionary to take parameterized values from environment variables:
We'll finish the configuration by setting some required variables and configuring static files. First, add some new imports to the top of the file:
Next, create or set the following variables:
The ALLOWED_HOSTS
variable is used to set a list of allowed host names for the application. This is a security feature that prevents host header attacks.
The DOMAIN
variable is used to set the domain name of the application. This is used in the upload_video
view function to construct the URL for the worker service.
The CSRF_TRUSTED_ORIGINS
variable is used to set a list of trusted origins for the Cross-Site Request Forgery (CSRF) protection in Django. This is a security feature that prevents malicious websites from making unauthorized requests to the application.
Finally, configure the static file configuration by adding the following:
Now, you can create and run the migrations, with:
The main page and the video upload form are now complete and should render if you run the test server with the expected environment variables configured. To actually upload videos, however, you need to create the associated worker service.
To finish up with the web app, create a new repository on GitHub. Afterwards, initialize a git repository in the project root, download a basic Python .gitignore
file, and push the changes:
Build the worker service
You will build a second application with FastAPI that will be responsible for processing uploads.
Outside of the Django project directory, create a new project directory for the worker API service. Deactivate any existing virtual environments and create a new virtual environment:
Activate the new virtual environment by typing:
Create a requirements.txt
file with the service's dependencies:
Install the dependencies by typing:
The important packages installed here are assemblyai
, which is a speech recognition and natural language processing API, and moviepy
, which is a library for video editing and processing.
Create a .env
file to define your AssemblyAI API key as an environment variable:
You will need an API key from AssemblyAI, which you can get [here](AssemblyAI | Dashboard). You will need to sign up for an account if you don't have one. To use the AI features (like LEMUR) you will need to add credits to the account.
Then you can create your main.py
file inside the FastAPI project:
This script first sets up an API key for the AssemblyAI service, which is used for transcribing audio. It then defines several functions for downloading a video file from a URL, extracting audio from a video file, and getting the resolution and duration of a video file.
Afterwards, it creates a FastAPI instance and defines two route handlers. The first route handler is for the default route (/
) and simply returns the version number of the service.
The second route handler is for the /process_video
route and performs the following steps:
- Downloads the video file from the provided URL and saves it locally.
- Extracts audio from the video file using MoviePy.
- Gets the resolution and duration of the video file.
- Transcribes the audio using AssemblyAI.
- Generates tags and categories for the video using AssemblyAI's LEMUR model.
- Deletes the video and audio files from local storage.
- Returns the generated tags, categories, resolution, and duration as a JSON object.
The assemblyai
library is used for transcribing audio and generating tags and categories and the moviepy
library is used for extracting audio from a video file and getting the resolution and duration of a video file.
To finish up with the worker service, create a new repository on GitHub. Afterwards, initialize a git repository in the project root, download a basic Python .gitignore
file, and push the changes:
Integrate with Koyeb's edge network
Integrating with Koyeb's edge network requires nothing more than deploying the applications to Koyeb. All CDN features are enabled by default and all services are part of the service mesh network and edge network.
Let's now see how you can deploy the applications to Koyeb to build the pipeline.
Deploy the web application
You can start by first deploying the web application. For that go the Koyeb control panel and click Create Web Service:
-
Select GitHub as your deployment method and select your GitHub project for the web application.
-
In the Builder section, override the Run command with
python manage.py runserver 0.0.0.0:8000
. -
In the App and Service names section, configure the App name. This will impact the environment variable values you define next.
-
In the Environment variables section, click Bulk edit and configure the following variables:
Fill in the variables as follows:
DJANGO_DB_HOST
: The hostname of the PostgreSQL database.DJANGO_DB_USER
: The PostgreSQL username to authenticate with.DJANGO_DB_PASSWORD
: The PostgreSQL password to authenticate with.DJANGO_DB_NAME
: The name of the PostgreSQL database to connect to.ALLOWED_HOSTS
: The bare hostname where this application will be deployed. It will begin with your App name followed by your Koyeb org name, a hash, and end with.koyeb.app
.CSRF_TRUSTED_ORIGINS
: The domain where this application will be deployed. It will begin withhttps://
and include your App name, Koyeb org name, a hash, and end with.koyeb.app
.DOMAIN
: The domain where this application will be deployed. It will begin withhttps://
and include your App name, Koyeb org name, a hash, and end with.koyeb.app
.DJANGO_SECRET_KEY
: A secret key used for encryption by Django. You can follow the procedure in generate a secure Django secret key locally to generate a secure Django key.WORKER_URL
: The internal URL where your service worker will be deployed. This should take the following format:http://<WORKER_SERVICE_NAME>.<YOUR_KOYEB_ORG>.koyeb:8080
. Use the name you plan to deploy your service worker under.
-
Click Deploy.
After a couple of minutes the application should be deployed and accessible at the application's URL.
Deploy the worker service API
Next, deploy the worker API service. Navigate to the previous created application in the Koyeb control panel and click Create Service:
- Select GitHub as your deployment method and select your GitHub project for the worker service API.
- In the Builder section, override the Run command with
uvicorn main:app --port 8080 --host 0.0.0.0
. - In the Environment variables section, configure the following environment variable:
ASSEMBLYAI_API_KEY=<YOUR_ASSEMBLYAI_API_KEY>
. - In the Scaling section, select Autoscaling from 1 to 3 Instances. Set the number of requests per second to your desired threshold.
- In the Exposed ports section, deselect the Public toggle to make it only accessible from the service mesh and set the port to 8080.
- In the App and Service names section, set the Service name to the value you chose in the
WORKER_URL
variable when you deployed the Django application. - Click Deploy.
After a couple of minutes the Worker Web API should be deployed.
Test the application
You can now test the web application and the worker API pipeline by accessing the web application URL and uploading a video file.
In this example, first we upload a file and fill in the title and description:
We can observe the different steps of the video worker API in the Koyeb logs:
And finally, returning to the web application, we can see the categories and tags as well as the additional information filled in:
You now have a full functional working video pipeline which can automatically scale when the number of requests for the video worker API crosses the threshold.
Conclusion
This article described how to build a video processing app using FastAPI, AssemblyAI, and Django on Koyeb. We've covered everything from setting up the app and creating the FastAPI service to implementing video processing features using AssemblyAI and MoviePy.
Throughout the article, we've seen how to build a reliable and scalable app that can process videos and extract valuable metadata, such as transcriptions, tags, and categories. You can customize and extend the app to meet your specific needs and use cases.
With the skills and knowledge you've gained from this article, you can confidently create your own video processing apps and use Koyeb to deploy innovative solutions for video processing and analysis. The demand for video content and video processing is growing rapidly, so the abilities you've learned here will be extremely valuable if you want to develop advanced video processing apps.