Tutorial
Tutorial
Tutorial
Building a Video Content Quiz Generator with Twelve Labs


Hrishikesh Yadav
Hrishikesh Yadav
Hrishikesh Yadav
The Video Content MCQ Generator is an innovative application designed to transform video based learning experiences. The application is powered by Twelve Labs, this application automatically generates Multiple Choice Questions (MCQs) from video content, making learning and assessment more engaging and efficient.
The Video Content MCQ Generator is an innovative application designed to transform video based learning experiences. The application is powered by Twelve Labs, this application automatically generates Multiple Choice Questions (MCQs) from video content, making learning and assessment more engaging and efficient.


Join our newsletter
Receive the latest advancements, tutorials, and industry insights in video understanding
Oct 4, 2024
Oct 4, 2024
Oct 4, 2024
13 Min
13 Min
13 Min
Copy link to article
Copy link to article
Copy link to article
Introduction
Imagine a world where every video becomes an interactive quiz, effortlessly transforming passive viewing into active learning 🎓
In this tutorial, we'll explore the Video Content Quiz Generator, an application designed to revolutionize the learning experience associated with video content. Powered by Twelve Labs, this video-based tool automatically generates Multiple Choice Questions (MCQs) from video content, enhancing both learning and assessment.
Whether you're an educator seeking quick assessments or a content creator aiming to boost engagement, the Video Content MCQ Generator is your ally in fostering active learning.
You can explore the demo of the application here: Video Content MCQ Generator. You can play with it via this Replit template.
Prerequisites
Generate an API key by signing up at the Twelve Labs Playground.
Find the repository for the notebooks and this application on GitHub.
How the Application Works
This section outlines the application flow for developing the video content quiz (MCQ) generator using Twelve Labs.
The process begins when a user uploads video or educational content, which is then transformed into an active quiz assessment. After upload, the video is indexed on a specific index created during setup. Indexing is performed using Marengo 2.6 (Embedding Engine). Once indexed, the video content is converted into MCQs using the open-ended prompt functionality in Pegasus 1.1 (Generative Engine).
The prompt assigns the role of an educational video analyzer, tasked with generating quiz questions and correct answers. These are used to evaluate user responses based on the indexed video, following a specified format. After a user submits an answer, the application provides a score and the correct answer. A reset button allows users to start over.

Preparation Steps
There are two ways to create the index: through the Twelve Labs Playground or using provided code snippets. We'll discuss both methods. To prepare the index ID from the playground, follow these steps:
Sign up and create an Index on the Twelve Labs Playground.
Enable the following video understanding engines for your index: (these engines provide a robust foundation for video understanding)
Marengo 2.6 (Embedding Engine) for video search and classification
Pegasus 1.1 (Generative Engine) for video-to-text generation

Obtain your API Key from the Twelve Labs Playground.
Retrieve your INDEX_ID by opening the Index created in step 1. The ID is in the URL: https://playground.twelvelabs.io/indexes/{index_id}.
Set up the .env file with your API Key and INDEX_ID, along with the main file.
Twelvelabs_API=your_api_key_here API_URL=your_api_url_here
If you prefer the code-based approach, follow these steps:
Obtain your API Key from the Twelve Labs Playground and prepare the environment variable.
Import the Twelve Labs SDK and the environmental variables. Initiate the SDK client using the Twelve Labs API Key from the environment variable.
from twelvelabs import TwelveLabs from dotenv import load_dotenv load_dotenv() API_KEY = os.getenv("API_KEY") client = TwelveLabs(api_key=API_KEY)
Specifying the desired engine for the generation task:
engines = [ { "name": "marengo2.6", "options": ["visual", "conversation", "text_in_video", "logo"] }, { "name": "pegasus1.1", "options": ["visual", "conversation"] } ]
Create a new index by calling
client.index
with the Index name and engine configuration parameters. Use a unique and identifiable name for the Index.
index = client.index.create( name="<YOUR_INDEX_NAME>", engines=engines ) print(f"A new index has been created: Index id={index.id} name={index.name} engines={index.engines}")
The index.i
d field represents the unique identifier of your new index. This identifier is crucial for indexing videos in their correct location.
With these steps completed, you're now ready to develop the application!
Walkthrough for Video Content Quiz Generator
In this tutorial, we will build a Streamit application with a minimal frontend. Below is the directory structure to be followed:
. ├── app.py ├── requirements.txt ├── utils.py ├── .env └── .gitignore
After completing the previous steps, it's time to build the Streamlit application. This app offers a straightforward way to upload a video and convert it into a multiple-choice quiz assessment. The application comprises two files:
app.py: Contains the application flow with a minimal page layout
utils.py: Contains all the utility functions essential for the application's operation
1 - Setting up the utility function for the operation
In this section, we'll explore how to set up the utility function using the Twelve Labs SDK to transform video content into interactive learning experiences. This AI-powered system enables educators and content creators to craft engaging assessments based on visual content by automating video analysis and quiz generation. The code combines video indexing and custom prompt engineering to generate relevant multiple-choice questions from any uploaded video, making it a versatile tool for creating interactive learning materials.
# Import the necessary libraries import json import tempfile import os from twelvelabs import TwelveLabs from twelvelabs.models.task import Task import re from dotenv import load_dotenv load_dotenv() # Get the API Key from the Dashboard - https://playground.twelvelabs.io/dashboard/api-key API_KEY = os.getenv("API_KEY") # Create the INDEX ID as specified in the README.md and get the INDEX_ID INDEX_ID = os.getenv("INDEX_ID") # Initialize the Twelve Labs client client = TwelveLabs(api_key=API_KEY) # Create a temporary directory for uploaded files UPLOAD_DIR = tempfile.mkdtemp() def create_task(file_path): # Create a new task for video indexing return client.task.create( index_id=INDEX_ID, file=file_path, ) def on_task_update(task: Task): # Callback function to print task status updates print(f" Status={task.status}") def wait_for_task(task): # Wait for the indexing task to complete task.wait_for_done(sleep_interval=5, callback=on_task_update) if task.status != "ready": raise RuntimeError(f"Indexing failed with status {task.status}") return task.video_id def generate_mcq(video_id): # Prompt to generate the multiple choice questions based on video content prompt = """You're Educational Content Analyzer, and you are tasked to prepare the three Multiple Choice Questions based on the video content and the concept which is been discussed by the speaker or shown. The difficulty of the question should also gradually increase. The response should be in the json format where there is Q1, Q2, and Q3. Each section would contain the question with options in question and the correct_answer""" # Twelve Labs SDK to generate text based on the video content gist_r = client.generate.text( video_id=video_id, prompt=prompt ) return gist_r.data def parse_json_with_regex(text): # Extract and parse JSON content from the response match = re.search(r'\{[\s\S]*\}', text) if match: json_str = match.group(0) try: return json.loads(json_str) except json.JSONDecodeError: # Return None if JSON parsing fails return None else: # Return None if no JSON like content is found return None def save_uploaded_file(uploaded_file): # Save the uploaded file to the temporary directory file_path = os.path.join(UPLOAD_DIR, uploaded_file.name) with open(file_path, "wb") as f: f.write(uploaded_file.getbuffer()) return file_path # Calculate the user's score based on their answers def calculate_score(user_answers, questions): return sum(answer == questions[q_num]["correct_answer"] for q_num, answer in user_answers.items())
First, we import the necessary modules, including json, tempfile, os, and the Twelve Labs SDK, along with the API Key and Index ID environment variables.
The
create_task(file_path)
method initiates a new video indexing task using the Twelve Labs SDK. It returns the work object for the indexing application. A callback function,on_task_update(task: Task)
, prints status updates for the indexing task. Once the status becomes "ready" and returns the video_id, thegenerate_mcq(video_id)
function is triggered.The
generate_mcq(video_id)
function generates multiple-choice questions based on the indexed content using Pegasus 1.1. The prompt defines the model's role, objective, and output format. The result is then parsed usingparse_json_with_regex(text)
.The
calculate_score(user_answers, questions)
function computes the user's score based on their answers and returns the total score when the user clicks the submit button in the next section.
2. Instruction Flow of the Streamlit Application [app.py]
2.1 Quiz Assessment Instruction Flow
As mentioned earlier, app.py contains the proper flow of instructions for the Streamlit application, utilizing the utility functions from utils.py. This section focuses on the function and flow of the quiz assessment and scoring system.
# Import the necessary libraries and functions import streamlit as st from utils import create_task, wait_for_task, generate_mcq, parse_json_with_regex, save_uploaded_file, calculate_score def upload_and_index(): # Minimal custom HTML and CSS st.markdown(""" <h1 style='text-align: center; color: #2c3e50; font-size: 36px; font-weight: bold; margin-bottom: 30px;'> 📹 Video Content Quiz Generator </h1> """, unsafe_allow_html=True) st.write("Upload a video to start the quiz generation process and test yourself!") # # Check if a video has already been indexed if 'video_id' in st.session_state and st.session_state.video_id: st.info("Video already indexed. Next, Proceeding to quiz generation.") return generate_quiz() # File uploader for video files uploaded_file = st.file_uploader("Choose a video file", type=['mp4']) if uploaded_file is not None: # Save the uploaded file file_path = save_uploaded_file(uploaded_file) st.success("File uploaded successfully!") # To proceed witht the indexing of the video with st.spinner("Indexing video... Please wait"): task = create_task(file_path) video_id = wait_for_task(task) st.success("Video indexed successfully!") st.session_state.video_id = video_id return generate_quiz() # Utility function to generate the quiz questions based on the indexed video def generate_quiz(): with st.spinner("Generating quiz questions..."): raw_response = generate_mcq(st.session_state.video_id) questions = parse_json_with_regex(raw_response) if questions: st.session_state.questions = questions st.session_state.page = "quiz" st.experimental_rerun() else: st.error("Failed to generate quiz questions. Please try again.") def quiz(): st.title("🎓 Video Content Quiz") st.write("Answer the following questions based on the video content -") questions = st.session_state.questions # # Initialize user answers if not already done if 'user_answers' not in st.session_state: st.session_state.user_answers = {q_num: None for q_num in questions} if 'submitted' not in st.session_state: st.session_state.submitted = False # Display the questions and answer options for q_num, q_data in questions.items(): with st.container(): st.subheader(f"Question {q_num[-1]}") st.write(q_data["question"]) answer = st.radio( f"Select your answer for Question {q_num[-1]}:", options=q_data["options"], key=f"select_{q_num}", index=q_data["options"].index(st.session_state.user_answers[q_num]) if st.session_state.user_answers[q_num] else 0, on_change=update_answer, args=(q_num,) ) st.markdown("---") # Submit quiz button col1, col2, col3 = st.columns([1, 2, 1]) with col2: submit_button = st.button("Submit Quiz 📝", key="submit_quiz", use_container_width=True) if submit_button: submit_quiz() st.balloons() # Display results if quiz is submitted if st.session_state.submitted: display_results() start_over_button = st.button("Start Over 🔄", key="start_over", use_container_width=True) if start_over_button: reset_state() def update_answer(q_num): # Session state, to update the user's answer st.session_state.user_answers[q_num] = st.session_state[f"select_{q_num}"] def submit_quiz(): # On the submission button, mark quiz as submitted and calculate score st.session_state.submitted = True st.session_state.score = calculate_score(st.session_state.user_answers, st.session_state.questions) def display_results(): # To display the user's score st.success(f"🏆 Your score: {st.session_state.score} out of {len(st.session_state.questions)}") # Display the correct results for each question for q_num, q_data in st.session_state.questions.items(): with st.expander(f"Question {q_num[-1]} Details"): st.write(f"**Your answer:** {st.session_state.user_answers[q_num]}") st.write(f"**Correct answer:** {q_data['correct_answer']}") if st.session_state.user_answers[q_num] == q_data['correct_answer']: st.success("Correct! 🎉") else: st.error("Incorrect ❌") def reset_state(): # Clear all session state variables for key in list(st.session_state.keys()): del st.session_state[key] st.experimental_rerun()
This part of the Streamlit application focuses on generating quizzes from video content and managing quiz interactions.
The upload_and_index()
function utilizes the Twelve Labs SDK for video uploading and indexing. Once indexing is complete, the quiz generation process begins.
To generate quiz questions, the function uses the 'video_id' of the indexed video. It then calls generate_mcq()
followed by parse_json_with_regex()
, as previously discussed. This process creates the Quiz Questions and Answers. Upon successful generation, the quiz page is displayed.
The quiz()
function presents the generated quiz and handles user interactions, including answer selection and quiz submission. A "Start Over" option is provided after submission. Several utility functions manage quiz interactions:
update_answer()
updates the user's response for a specific question.submit_quiz()
processes quiz submission and calculates the score.display_results()
shows the quiz results, including the score and correct answers.reset_state()
clears all session state variables to restart the quiz.
2.2 Streamlit Session State and Custom CSS
The main function in the app.py package configures the Streamlit page and applies custom CSS. It sets the background image, styles buttons, and determines the overall look of the application. It also initializes the session state.
def main(): # Set up the Streamlit page configuration st.set_page_config(page_title="QnA Generator", page_icon="🎥", layout="wide") # Custom CSS st.markdown(""" <style> .stApp { background-color: #f0f2f6; } .stButton > button { background-color: #4CAF50; color: white; font-weight: bold; border-radius: 30px; padding: 15px 30px; font-size: 18px; transition: all 0.3s ease 0s; border: none; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); } .stButton > button:hover { background-color: #45a049; box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15); transform: translateY(-2px); } .stButton > button:active { transform: translateY(0px); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } .stRadio > label { background-color: #e1e5eb; padding: 12px; border-radius: 8px; margin-bottom: 12px; transition: all 0.2s ease 0s; cursor: pointer; } .stRadio > label:hover { background-color: #d0d4d9; transform: translateY(-2px); box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); } .stExpander { background-color: #ffffff; border-radius: 15px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); margin-bottom: 20px; } h1 { color: #2c3e50; font-size: 36px; font-weight: bold; margin-bottom: 20px; } h2, h3 { color: #34495e; } .stAlert { border-radius: 10px; font-weight: bold; } .stSpinner > div { border-color: #4CAF50 !important; } [data-testid="stAppViewContainer"] { background-image: url("https://img.freepik.com/free-photo/vivid-blurred-colorful-wallpaper-background_58702-3508.jpg?size=626&ext=jpg"); background-size: cover; } [data-testid="stHeader"] { background-color: rgba(0,0,0,0); } [data-testid="stToolbar"] { right: 2rem; background-image: url(""); background-size: cover; } </style> """, unsafe_allow_html=True) # Initialize the page state if not already set if 'page' not in st.session_state: st.session_state.page = "upload" # To show the appropriate page based on the current state if st.session_state.page == "upload": upload_and_index() elif st.session_state.page == "quiz": quiz() if __name__ == "__main__": main()
Serving as the entry point for launching the Streamlit application, the main()
function sets up a page with a title and uses a wide layout for better space utilization. Custom CSS enhances visual appeal by stylizing the background, buttons, radio buttons, and expanders, while reducing the opacity of headings.
To manage navigation between different sections of the app, a session state variable 'page' is initialized. It's set to "upload" by default if not already defined.
The application renders various pages based on its current state using conditional statements:
"upload" — Calls the
upload_and_index()
function for the video upload interface."quiz" — Calls the
quiz()
function to display the generated quiz.
Here's a demo quiz generated after uploading and indexing the video content on the PCA topic:

Explore further by experimenting with the open-ended prompt and Pegasus 1.1, powered by Twelve Labs.
More Ideas to Experiment with the Tutorial
Understanding how an application works and its development process empowers you to implement innovative ideas and create products that meet users' needs. Here are some use cases similar to the tutorial blog:
📚️ Self-Paced Learning: Students can generate questions to test their understanding of video lessons.
🎓 Educational Assessment: Teachers can quickly create quizzes based on lecture videos or educational content.
🏢️ Corporate Training: Organizations can enhance their video-based training programs with automated assessments tailored to different learners.
🎬 Content Engagement: Video content creators, including YouTubers, can increase engagement by providing interactive quizzes for their content.
🧠 Memory Retention: Users can reinforce their learning by answering questions generated from informational videos.
Conclusion
This blog post offers a comprehensive explanation of the working procedure and development of the video content quiz generator using Twelve Labs. We appreciate you following along with the tutorial and look forward to your ideas on improving the user experience and addressing various challenges.
Additional Resources
To deepen your understanding of the engines used for the generation task, check out Marengo 2.6 (Embedding Engine) and Pegasus 1.1 (Generator Engine). To further explore Twelve Labs and enhance your grasp of video content analysis, consider these valuable resources:
Discord Community: Join our vibrant community of developers and enthusiasts to discuss ideas, ask questions, and share your projects.
Sample Applications: Explore a variety of sample applications to inspire your next project or learn new implementation techniques.
Explore Tutorials: Dive deeper into Twelve Labs capabilities with our comprehensive tutorials.
We encourage you to leverage these resources to expand your knowledge and create innovative applications using Twelve Labs' video understanding technology.
Introduction
Imagine a world where every video becomes an interactive quiz, effortlessly transforming passive viewing into active learning 🎓
In this tutorial, we'll explore the Video Content Quiz Generator, an application designed to revolutionize the learning experience associated with video content. Powered by Twelve Labs, this video-based tool automatically generates Multiple Choice Questions (MCQs) from video content, enhancing both learning and assessment.
Whether you're an educator seeking quick assessments or a content creator aiming to boost engagement, the Video Content MCQ Generator is your ally in fostering active learning.
You can explore the demo of the application here: Video Content MCQ Generator. You can play with it via this Replit template.
Prerequisites
Generate an API key by signing up at the Twelve Labs Playground.
Find the repository for the notebooks and this application on GitHub.
How the Application Works
This section outlines the application flow for developing the video content quiz (MCQ) generator using Twelve Labs.
The process begins when a user uploads video or educational content, which is then transformed into an active quiz assessment. After upload, the video is indexed on a specific index created during setup. Indexing is performed using Marengo 2.6 (Embedding Engine). Once indexed, the video content is converted into MCQs using the open-ended prompt functionality in Pegasus 1.1 (Generative Engine).
The prompt assigns the role of an educational video analyzer, tasked with generating quiz questions and correct answers. These are used to evaluate user responses based on the indexed video, following a specified format. After a user submits an answer, the application provides a score and the correct answer. A reset button allows users to start over.

Preparation Steps
There are two ways to create the index: through the Twelve Labs Playground or using provided code snippets. We'll discuss both methods. To prepare the index ID from the playground, follow these steps:
Sign up and create an Index on the Twelve Labs Playground.
Enable the following video understanding engines for your index: (these engines provide a robust foundation for video understanding)
Marengo 2.6 (Embedding Engine) for video search and classification
Pegasus 1.1 (Generative Engine) for video-to-text generation

Obtain your API Key from the Twelve Labs Playground.
Retrieve your INDEX_ID by opening the Index created in step 1. The ID is in the URL: https://playground.twelvelabs.io/indexes/{index_id}.
Set up the .env file with your API Key and INDEX_ID, along with the main file.
Twelvelabs_API=your_api_key_here API_URL=your_api_url_here
If you prefer the code-based approach, follow these steps:
Obtain your API Key from the Twelve Labs Playground and prepare the environment variable.
Import the Twelve Labs SDK and the environmental variables. Initiate the SDK client using the Twelve Labs API Key from the environment variable.
from twelvelabs import TwelveLabs from dotenv import load_dotenv load_dotenv() API_KEY = os.getenv("API_KEY") client = TwelveLabs(api_key=API_KEY)
Specifying the desired engine for the generation task:
engines = [ { "name": "marengo2.6", "options": ["visual", "conversation", "text_in_video", "logo"] }, { "name": "pegasus1.1", "options": ["visual", "conversation"] } ]
Create a new index by calling
client.index
with the Index name and engine configuration parameters. Use a unique and identifiable name for the Index.
index = client.index.create( name="<YOUR_INDEX_NAME>", engines=engines ) print(f"A new index has been created: Index id={index.id} name={index.name} engines={index.engines}")
The index.i
d field represents the unique identifier of your new index. This identifier is crucial for indexing videos in their correct location.
With these steps completed, you're now ready to develop the application!
Walkthrough for Video Content Quiz Generator
In this tutorial, we will build a Streamit application with a minimal frontend. Below is the directory structure to be followed:
. ├── app.py ├── requirements.txt ├── utils.py ├── .env └── .gitignore
After completing the previous steps, it's time to build the Streamlit application. This app offers a straightforward way to upload a video and convert it into a multiple-choice quiz assessment. The application comprises two files:
app.py: Contains the application flow with a minimal page layout
utils.py: Contains all the utility functions essential for the application's operation
1 - Setting up the utility function for the operation
In this section, we'll explore how to set up the utility function using the Twelve Labs SDK to transform video content into interactive learning experiences. This AI-powered system enables educators and content creators to craft engaging assessments based on visual content by automating video analysis and quiz generation. The code combines video indexing and custom prompt engineering to generate relevant multiple-choice questions from any uploaded video, making it a versatile tool for creating interactive learning materials.
# Import the necessary libraries import json import tempfile import os from twelvelabs import TwelveLabs from twelvelabs.models.task import Task import re from dotenv import load_dotenv load_dotenv() # Get the API Key from the Dashboard - https://playground.twelvelabs.io/dashboard/api-key API_KEY = os.getenv("API_KEY") # Create the INDEX ID as specified in the README.md and get the INDEX_ID INDEX_ID = os.getenv("INDEX_ID") # Initialize the Twelve Labs client client = TwelveLabs(api_key=API_KEY) # Create a temporary directory for uploaded files UPLOAD_DIR = tempfile.mkdtemp() def create_task(file_path): # Create a new task for video indexing return client.task.create( index_id=INDEX_ID, file=file_path, ) def on_task_update(task: Task): # Callback function to print task status updates print(f" Status={task.status}") def wait_for_task(task): # Wait for the indexing task to complete task.wait_for_done(sleep_interval=5, callback=on_task_update) if task.status != "ready": raise RuntimeError(f"Indexing failed with status {task.status}") return task.video_id def generate_mcq(video_id): # Prompt to generate the multiple choice questions based on video content prompt = """You're Educational Content Analyzer, and you are tasked to prepare the three Multiple Choice Questions based on the video content and the concept which is been discussed by the speaker or shown. The difficulty of the question should also gradually increase. The response should be in the json format where there is Q1, Q2, and Q3. Each section would contain the question with options in question and the correct_answer""" # Twelve Labs SDK to generate text based on the video content gist_r = client.generate.text( video_id=video_id, prompt=prompt ) return gist_r.data def parse_json_with_regex(text): # Extract and parse JSON content from the response match = re.search(r'\{[\s\S]*\}', text) if match: json_str = match.group(0) try: return json.loads(json_str) except json.JSONDecodeError: # Return None if JSON parsing fails return None else: # Return None if no JSON like content is found return None def save_uploaded_file(uploaded_file): # Save the uploaded file to the temporary directory file_path = os.path.join(UPLOAD_DIR, uploaded_file.name) with open(file_path, "wb") as f: f.write(uploaded_file.getbuffer()) return file_path # Calculate the user's score based on their answers def calculate_score(user_answers, questions): return sum(answer == questions[q_num]["correct_answer"] for q_num, answer in user_answers.items())
First, we import the necessary modules, including json, tempfile, os, and the Twelve Labs SDK, along with the API Key and Index ID environment variables.
The
create_task(file_path)
method initiates a new video indexing task using the Twelve Labs SDK. It returns the work object for the indexing application. A callback function,on_task_update(task: Task)
, prints status updates for the indexing task. Once the status becomes "ready" and returns the video_id, thegenerate_mcq(video_id)
function is triggered.The
generate_mcq(video_id)
function generates multiple-choice questions based on the indexed content using Pegasus 1.1. The prompt defines the model's role, objective, and output format. The result is then parsed usingparse_json_with_regex(text)
.The
calculate_score(user_answers, questions)
function computes the user's score based on their answers and returns the total score when the user clicks the submit button in the next section.
2. Instruction Flow of the Streamlit Application [app.py]
2.1 Quiz Assessment Instruction Flow
As mentioned earlier, app.py contains the proper flow of instructions for the Streamlit application, utilizing the utility functions from utils.py. This section focuses on the function and flow of the quiz assessment and scoring system.
# Import the necessary libraries and functions import streamlit as st from utils import create_task, wait_for_task, generate_mcq, parse_json_with_regex, save_uploaded_file, calculate_score def upload_and_index(): # Minimal custom HTML and CSS st.markdown(""" <h1 style='text-align: center; color: #2c3e50; font-size: 36px; font-weight: bold; margin-bottom: 30px;'> 📹 Video Content Quiz Generator </h1> """, unsafe_allow_html=True) st.write("Upload a video to start the quiz generation process and test yourself!") # # Check if a video has already been indexed if 'video_id' in st.session_state and st.session_state.video_id: st.info("Video already indexed. Next, Proceeding to quiz generation.") return generate_quiz() # File uploader for video files uploaded_file = st.file_uploader("Choose a video file", type=['mp4']) if uploaded_file is not None: # Save the uploaded file file_path = save_uploaded_file(uploaded_file) st.success("File uploaded successfully!") # To proceed witht the indexing of the video with st.spinner("Indexing video... Please wait"): task = create_task(file_path) video_id = wait_for_task(task) st.success("Video indexed successfully!") st.session_state.video_id = video_id return generate_quiz() # Utility function to generate the quiz questions based on the indexed video def generate_quiz(): with st.spinner("Generating quiz questions..."): raw_response = generate_mcq(st.session_state.video_id) questions = parse_json_with_regex(raw_response) if questions: st.session_state.questions = questions st.session_state.page = "quiz" st.experimental_rerun() else: st.error("Failed to generate quiz questions. Please try again.") def quiz(): st.title("🎓 Video Content Quiz") st.write("Answer the following questions based on the video content -") questions = st.session_state.questions # # Initialize user answers if not already done if 'user_answers' not in st.session_state: st.session_state.user_answers = {q_num: None for q_num in questions} if 'submitted' not in st.session_state: st.session_state.submitted = False # Display the questions and answer options for q_num, q_data in questions.items(): with st.container(): st.subheader(f"Question {q_num[-1]}") st.write(q_data["question"]) answer = st.radio( f"Select your answer for Question {q_num[-1]}:", options=q_data["options"], key=f"select_{q_num}", index=q_data["options"].index(st.session_state.user_answers[q_num]) if st.session_state.user_answers[q_num] else 0, on_change=update_answer, args=(q_num,) ) st.markdown("---") # Submit quiz button col1, col2, col3 = st.columns([1, 2, 1]) with col2: submit_button = st.button("Submit Quiz 📝", key="submit_quiz", use_container_width=True) if submit_button: submit_quiz() st.balloons() # Display results if quiz is submitted if st.session_state.submitted: display_results() start_over_button = st.button("Start Over 🔄", key="start_over", use_container_width=True) if start_over_button: reset_state() def update_answer(q_num): # Session state, to update the user's answer st.session_state.user_answers[q_num] = st.session_state[f"select_{q_num}"] def submit_quiz(): # On the submission button, mark quiz as submitted and calculate score st.session_state.submitted = True st.session_state.score = calculate_score(st.session_state.user_answers, st.session_state.questions) def display_results(): # To display the user's score st.success(f"🏆 Your score: {st.session_state.score} out of {len(st.session_state.questions)}") # Display the correct results for each question for q_num, q_data in st.session_state.questions.items(): with st.expander(f"Question {q_num[-1]} Details"): st.write(f"**Your answer:** {st.session_state.user_answers[q_num]}") st.write(f"**Correct answer:** {q_data['correct_answer']}") if st.session_state.user_answers[q_num] == q_data['correct_answer']: st.success("Correct! 🎉") else: st.error("Incorrect ❌") def reset_state(): # Clear all session state variables for key in list(st.session_state.keys()): del st.session_state[key] st.experimental_rerun()
This part of the Streamlit application focuses on generating quizzes from video content and managing quiz interactions.
The upload_and_index()
function utilizes the Twelve Labs SDK for video uploading and indexing. Once indexing is complete, the quiz generation process begins.
To generate quiz questions, the function uses the 'video_id' of the indexed video. It then calls generate_mcq()
followed by parse_json_with_regex()
, as previously discussed. This process creates the Quiz Questions and Answers. Upon successful generation, the quiz page is displayed.
The quiz()
function presents the generated quiz and handles user interactions, including answer selection and quiz submission. A "Start Over" option is provided after submission. Several utility functions manage quiz interactions:
update_answer()
updates the user's response for a specific question.submit_quiz()
processes quiz submission and calculates the score.display_results()
shows the quiz results, including the score and correct answers.reset_state()
clears all session state variables to restart the quiz.
2.2 Streamlit Session State and Custom CSS
The main function in the app.py package configures the Streamlit page and applies custom CSS. It sets the background image, styles buttons, and determines the overall look of the application. It also initializes the session state.
def main(): # Set up the Streamlit page configuration st.set_page_config(page_title="QnA Generator", page_icon="🎥", layout="wide") # Custom CSS st.markdown(""" <style> .stApp { background-color: #f0f2f6; } .stButton > button { background-color: #4CAF50; color: white; font-weight: bold; border-radius: 30px; padding: 15px 30px; font-size: 18px; transition: all 0.3s ease 0s; border: none; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); } .stButton > button:hover { background-color: #45a049; box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15); transform: translateY(-2px); } .stButton > button:active { transform: translateY(0px); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } .stRadio > label { background-color: #e1e5eb; padding: 12px; border-radius: 8px; margin-bottom: 12px; transition: all 0.2s ease 0s; cursor: pointer; } .stRadio > label:hover { background-color: #d0d4d9; transform: translateY(-2px); box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); } .stExpander { background-color: #ffffff; border-radius: 15px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); margin-bottom: 20px; } h1 { color: #2c3e50; font-size: 36px; font-weight: bold; margin-bottom: 20px; } h2, h3 { color: #34495e; } .stAlert { border-radius: 10px; font-weight: bold; } .stSpinner > div { border-color: #4CAF50 !important; } [data-testid="stAppViewContainer"] { background-image: url("https://img.freepik.com/free-photo/vivid-blurred-colorful-wallpaper-background_58702-3508.jpg?size=626&ext=jpg"); background-size: cover; } [data-testid="stHeader"] { background-color: rgba(0,0,0,0); } [data-testid="stToolbar"] { right: 2rem; background-image: url(""); background-size: cover; } </style> """, unsafe_allow_html=True) # Initialize the page state if not already set if 'page' not in st.session_state: st.session_state.page = "upload" # To show the appropriate page based on the current state if st.session_state.page == "upload": upload_and_index() elif st.session_state.page == "quiz": quiz() if __name__ == "__main__": main()
Serving as the entry point for launching the Streamlit application, the main()
function sets up a page with a title and uses a wide layout for better space utilization. Custom CSS enhances visual appeal by stylizing the background, buttons, radio buttons, and expanders, while reducing the opacity of headings.
To manage navigation between different sections of the app, a session state variable 'page' is initialized. It's set to "upload" by default if not already defined.
The application renders various pages based on its current state using conditional statements:
"upload" — Calls the
upload_and_index()
function for the video upload interface."quiz" — Calls the
quiz()
function to display the generated quiz.
Here's a demo quiz generated after uploading and indexing the video content on the PCA topic:

Explore further by experimenting with the open-ended prompt and Pegasus 1.1, powered by Twelve Labs.
More Ideas to Experiment with the Tutorial
Understanding how an application works and its development process empowers you to implement innovative ideas and create products that meet users' needs. Here are some use cases similar to the tutorial blog:
📚️ Self-Paced Learning: Students can generate questions to test their understanding of video lessons.
🎓 Educational Assessment: Teachers can quickly create quizzes based on lecture videos or educational content.
🏢️ Corporate Training: Organizations can enhance their video-based training programs with automated assessments tailored to different learners.
🎬 Content Engagement: Video content creators, including YouTubers, can increase engagement by providing interactive quizzes for their content.
🧠 Memory Retention: Users can reinforce their learning by answering questions generated from informational videos.
Conclusion
This blog post offers a comprehensive explanation of the working procedure and development of the video content quiz generator using Twelve Labs. We appreciate you following along with the tutorial and look forward to your ideas on improving the user experience and addressing various challenges.
Additional Resources
To deepen your understanding of the engines used for the generation task, check out Marengo 2.6 (Embedding Engine) and Pegasus 1.1 (Generator Engine). To further explore Twelve Labs and enhance your grasp of video content analysis, consider these valuable resources:
Discord Community: Join our vibrant community of developers and enthusiasts to discuss ideas, ask questions, and share your projects.
Sample Applications: Explore a variety of sample applications to inspire your next project or learn new implementation techniques.
Explore Tutorials: Dive deeper into Twelve Labs capabilities with our comprehensive tutorials.
We encourage you to leverage these resources to expand your knowledge and create innovative applications using Twelve Labs' video understanding technology.
Introduction
Imagine a world where every video becomes an interactive quiz, effortlessly transforming passive viewing into active learning 🎓
In this tutorial, we'll explore the Video Content Quiz Generator, an application designed to revolutionize the learning experience associated with video content. Powered by Twelve Labs, this video-based tool automatically generates Multiple Choice Questions (MCQs) from video content, enhancing both learning and assessment.
Whether you're an educator seeking quick assessments or a content creator aiming to boost engagement, the Video Content MCQ Generator is your ally in fostering active learning.
You can explore the demo of the application here: Video Content MCQ Generator. You can play with it via this Replit template.
Prerequisites
Generate an API key by signing up at the Twelve Labs Playground.
Find the repository for the notebooks and this application on GitHub.
How the Application Works
This section outlines the application flow for developing the video content quiz (MCQ) generator using Twelve Labs.
The process begins when a user uploads video or educational content, which is then transformed into an active quiz assessment. After upload, the video is indexed on a specific index created during setup. Indexing is performed using Marengo 2.6 (Embedding Engine). Once indexed, the video content is converted into MCQs using the open-ended prompt functionality in Pegasus 1.1 (Generative Engine).
The prompt assigns the role of an educational video analyzer, tasked with generating quiz questions and correct answers. These are used to evaluate user responses based on the indexed video, following a specified format. After a user submits an answer, the application provides a score and the correct answer. A reset button allows users to start over.

Preparation Steps
There are two ways to create the index: through the Twelve Labs Playground or using provided code snippets. We'll discuss both methods. To prepare the index ID from the playground, follow these steps:
Sign up and create an Index on the Twelve Labs Playground.
Enable the following video understanding engines for your index: (these engines provide a robust foundation for video understanding)
Marengo 2.6 (Embedding Engine) for video search and classification
Pegasus 1.1 (Generative Engine) for video-to-text generation

Obtain your API Key from the Twelve Labs Playground.
Retrieve your INDEX_ID by opening the Index created in step 1. The ID is in the URL: https://playground.twelvelabs.io/indexes/{index_id}.
Set up the .env file with your API Key and INDEX_ID, along with the main file.
Twelvelabs_API=your_api_key_here API_URL=your_api_url_here
If you prefer the code-based approach, follow these steps:
Obtain your API Key from the Twelve Labs Playground and prepare the environment variable.
Import the Twelve Labs SDK and the environmental variables. Initiate the SDK client using the Twelve Labs API Key from the environment variable.
from twelvelabs import TwelveLabs from dotenv import load_dotenv load_dotenv() API_KEY = os.getenv("API_KEY") client = TwelveLabs(api_key=API_KEY)
Specifying the desired engine for the generation task:
engines = [ { "name": "marengo2.6", "options": ["visual", "conversation", "text_in_video", "logo"] }, { "name": "pegasus1.1", "options": ["visual", "conversation"] } ]
Create a new index by calling
client.index
with the Index name and engine configuration parameters. Use a unique and identifiable name for the Index.
index = client.index.create( name="<YOUR_INDEX_NAME>", engines=engines ) print(f"A new index has been created: Index id={index.id} name={index.name} engines={index.engines}")
The index.i
d field represents the unique identifier of your new index. This identifier is crucial for indexing videos in their correct location.
With these steps completed, you're now ready to develop the application!
Walkthrough for Video Content Quiz Generator
In this tutorial, we will build a Streamit application with a minimal frontend. Below is the directory structure to be followed:
. ├── app.py ├── requirements.txt ├── utils.py ├── .env └── .gitignore
After completing the previous steps, it's time to build the Streamlit application. This app offers a straightforward way to upload a video and convert it into a multiple-choice quiz assessment. The application comprises two files:
app.py: Contains the application flow with a minimal page layout
utils.py: Contains all the utility functions essential for the application's operation
1 - Setting up the utility function for the operation
In this section, we'll explore how to set up the utility function using the Twelve Labs SDK to transform video content into interactive learning experiences. This AI-powered system enables educators and content creators to craft engaging assessments based on visual content by automating video analysis and quiz generation. The code combines video indexing and custom prompt engineering to generate relevant multiple-choice questions from any uploaded video, making it a versatile tool for creating interactive learning materials.
# Import the necessary libraries import json import tempfile import os from twelvelabs import TwelveLabs from twelvelabs.models.task import Task import re from dotenv import load_dotenv load_dotenv() # Get the API Key from the Dashboard - https://playground.twelvelabs.io/dashboard/api-key API_KEY = os.getenv("API_KEY") # Create the INDEX ID as specified in the README.md and get the INDEX_ID INDEX_ID = os.getenv("INDEX_ID") # Initialize the Twelve Labs client client = TwelveLabs(api_key=API_KEY) # Create a temporary directory for uploaded files UPLOAD_DIR = tempfile.mkdtemp() def create_task(file_path): # Create a new task for video indexing return client.task.create( index_id=INDEX_ID, file=file_path, ) def on_task_update(task: Task): # Callback function to print task status updates print(f" Status={task.status}") def wait_for_task(task): # Wait for the indexing task to complete task.wait_for_done(sleep_interval=5, callback=on_task_update) if task.status != "ready": raise RuntimeError(f"Indexing failed with status {task.status}") return task.video_id def generate_mcq(video_id): # Prompt to generate the multiple choice questions based on video content prompt = """You're Educational Content Analyzer, and you are tasked to prepare the three Multiple Choice Questions based on the video content and the concept which is been discussed by the speaker or shown. The difficulty of the question should also gradually increase. The response should be in the json format where there is Q1, Q2, and Q3. Each section would contain the question with options in question and the correct_answer""" # Twelve Labs SDK to generate text based on the video content gist_r = client.generate.text( video_id=video_id, prompt=prompt ) return gist_r.data def parse_json_with_regex(text): # Extract and parse JSON content from the response match = re.search(r'\{[\s\S]*\}', text) if match: json_str = match.group(0) try: return json.loads(json_str) except json.JSONDecodeError: # Return None if JSON parsing fails return None else: # Return None if no JSON like content is found return None def save_uploaded_file(uploaded_file): # Save the uploaded file to the temporary directory file_path = os.path.join(UPLOAD_DIR, uploaded_file.name) with open(file_path, "wb") as f: f.write(uploaded_file.getbuffer()) return file_path # Calculate the user's score based on their answers def calculate_score(user_answers, questions): return sum(answer == questions[q_num]["correct_answer"] for q_num, answer in user_answers.items())
First, we import the necessary modules, including json, tempfile, os, and the Twelve Labs SDK, along with the API Key and Index ID environment variables.
The
create_task(file_path)
method initiates a new video indexing task using the Twelve Labs SDK. It returns the work object for the indexing application. A callback function,on_task_update(task: Task)
, prints status updates for the indexing task. Once the status becomes "ready" and returns the video_id, thegenerate_mcq(video_id)
function is triggered.The
generate_mcq(video_id)
function generates multiple-choice questions based on the indexed content using Pegasus 1.1. The prompt defines the model's role, objective, and output format. The result is then parsed usingparse_json_with_regex(text)
.The
calculate_score(user_answers, questions)
function computes the user's score based on their answers and returns the total score when the user clicks the submit button in the next section.
2. Instruction Flow of the Streamlit Application [app.py]
2.1 Quiz Assessment Instruction Flow
As mentioned earlier, app.py contains the proper flow of instructions for the Streamlit application, utilizing the utility functions from utils.py. This section focuses on the function and flow of the quiz assessment and scoring system.
# Import the necessary libraries and functions import streamlit as st from utils import create_task, wait_for_task, generate_mcq, parse_json_with_regex, save_uploaded_file, calculate_score def upload_and_index(): # Minimal custom HTML and CSS st.markdown(""" <h1 style='text-align: center; color: #2c3e50; font-size: 36px; font-weight: bold; margin-bottom: 30px;'> 📹 Video Content Quiz Generator </h1> """, unsafe_allow_html=True) st.write("Upload a video to start the quiz generation process and test yourself!") # # Check if a video has already been indexed if 'video_id' in st.session_state and st.session_state.video_id: st.info("Video already indexed. Next, Proceeding to quiz generation.") return generate_quiz() # File uploader for video files uploaded_file = st.file_uploader("Choose a video file", type=['mp4']) if uploaded_file is not None: # Save the uploaded file file_path = save_uploaded_file(uploaded_file) st.success("File uploaded successfully!") # To proceed witht the indexing of the video with st.spinner("Indexing video... Please wait"): task = create_task(file_path) video_id = wait_for_task(task) st.success("Video indexed successfully!") st.session_state.video_id = video_id return generate_quiz() # Utility function to generate the quiz questions based on the indexed video def generate_quiz(): with st.spinner("Generating quiz questions..."): raw_response = generate_mcq(st.session_state.video_id) questions = parse_json_with_regex(raw_response) if questions: st.session_state.questions = questions st.session_state.page = "quiz" st.experimental_rerun() else: st.error("Failed to generate quiz questions. Please try again.") def quiz(): st.title("🎓 Video Content Quiz") st.write("Answer the following questions based on the video content -") questions = st.session_state.questions # # Initialize user answers if not already done if 'user_answers' not in st.session_state: st.session_state.user_answers = {q_num: None for q_num in questions} if 'submitted' not in st.session_state: st.session_state.submitted = False # Display the questions and answer options for q_num, q_data in questions.items(): with st.container(): st.subheader(f"Question {q_num[-1]}") st.write(q_data["question"]) answer = st.radio( f"Select your answer for Question {q_num[-1]}:", options=q_data["options"], key=f"select_{q_num}", index=q_data["options"].index(st.session_state.user_answers[q_num]) if st.session_state.user_answers[q_num] else 0, on_change=update_answer, args=(q_num,) ) st.markdown("---") # Submit quiz button col1, col2, col3 = st.columns([1, 2, 1]) with col2: submit_button = st.button("Submit Quiz 📝", key="submit_quiz", use_container_width=True) if submit_button: submit_quiz() st.balloons() # Display results if quiz is submitted if st.session_state.submitted: display_results() start_over_button = st.button("Start Over 🔄", key="start_over", use_container_width=True) if start_over_button: reset_state() def update_answer(q_num): # Session state, to update the user's answer st.session_state.user_answers[q_num] = st.session_state[f"select_{q_num}"] def submit_quiz(): # On the submission button, mark quiz as submitted and calculate score st.session_state.submitted = True st.session_state.score = calculate_score(st.session_state.user_answers, st.session_state.questions) def display_results(): # To display the user's score st.success(f"🏆 Your score: {st.session_state.score} out of {len(st.session_state.questions)}") # Display the correct results for each question for q_num, q_data in st.session_state.questions.items(): with st.expander(f"Question {q_num[-1]} Details"): st.write(f"**Your answer:** {st.session_state.user_answers[q_num]}") st.write(f"**Correct answer:** {q_data['correct_answer']}") if st.session_state.user_answers[q_num] == q_data['correct_answer']: st.success("Correct! 🎉") else: st.error("Incorrect ❌") def reset_state(): # Clear all session state variables for key in list(st.session_state.keys()): del st.session_state[key] st.experimental_rerun()
This part of the Streamlit application focuses on generating quizzes from video content and managing quiz interactions.
The upload_and_index()
function utilizes the Twelve Labs SDK for video uploading and indexing. Once indexing is complete, the quiz generation process begins.
To generate quiz questions, the function uses the 'video_id' of the indexed video. It then calls generate_mcq()
followed by parse_json_with_regex()
, as previously discussed. This process creates the Quiz Questions and Answers. Upon successful generation, the quiz page is displayed.
The quiz()
function presents the generated quiz and handles user interactions, including answer selection and quiz submission. A "Start Over" option is provided after submission. Several utility functions manage quiz interactions:
update_answer()
updates the user's response for a specific question.submit_quiz()
processes quiz submission and calculates the score.display_results()
shows the quiz results, including the score and correct answers.reset_state()
clears all session state variables to restart the quiz.
2.2 Streamlit Session State and Custom CSS
The main function in the app.py package configures the Streamlit page and applies custom CSS. It sets the background image, styles buttons, and determines the overall look of the application. It also initializes the session state.
def main(): # Set up the Streamlit page configuration st.set_page_config(page_title="QnA Generator", page_icon="🎥", layout="wide") # Custom CSS st.markdown(""" <style> .stApp { background-color: #f0f2f6; } .stButton > button { background-color: #4CAF50; color: white; font-weight: bold; border-radius: 30px; padding: 15px 30px; font-size: 18px; transition: all 0.3s ease 0s; border: none; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); } .stButton > button:hover { background-color: #45a049; box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15); transform: translateY(-2px); } .stButton > button:active { transform: translateY(0px); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } .stRadio > label { background-color: #e1e5eb; padding: 12px; border-radius: 8px; margin-bottom: 12px; transition: all 0.2s ease 0s; cursor: pointer; } .stRadio > label:hover { background-color: #d0d4d9; transform: translateY(-2px); box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); } .stExpander { background-color: #ffffff; border-radius: 15px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); margin-bottom: 20px; } h1 { color: #2c3e50; font-size: 36px; font-weight: bold; margin-bottom: 20px; } h2, h3 { color: #34495e; } .stAlert { border-radius: 10px; font-weight: bold; } .stSpinner > div { border-color: #4CAF50 !important; } [data-testid="stAppViewContainer"] { background-image: url("https://img.freepik.com/free-photo/vivid-blurred-colorful-wallpaper-background_58702-3508.jpg?size=626&ext=jpg"); background-size: cover; } [data-testid="stHeader"] { background-color: rgba(0,0,0,0); } [data-testid="stToolbar"] { right: 2rem; background-image: url(""); background-size: cover; } </style> """, unsafe_allow_html=True) # Initialize the page state if not already set if 'page' not in st.session_state: st.session_state.page = "upload" # To show the appropriate page based on the current state if st.session_state.page == "upload": upload_and_index() elif st.session_state.page == "quiz": quiz() if __name__ == "__main__": main()
Serving as the entry point for launching the Streamlit application, the main()
function sets up a page with a title and uses a wide layout for better space utilization. Custom CSS enhances visual appeal by stylizing the background, buttons, radio buttons, and expanders, while reducing the opacity of headings.
To manage navigation between different sections of the app, a session state variable 'page' is initialized. It's set to "upload" by default if not already defined.
The application renders various pages based on its current state using conditional statements:
"upload" — Calls the
upload_and_index()
function for the video upload interface."quiz" — Calls the
quiz()
function to display the generated quiz.
Here's a demo quiz generated after uploading and indexing the video content on the PCA topic:

Explore further by experimenting with the open-ended prompt and Pegasus 1.1, powered by Twelve Labs.
More Ideas to Experiment with the Tutorial
Understanding how an application works and its development process empowers you to implement innovative ideas and create products that meet users' needs. Here are some use cases similar to the tutorial blog:
📚️ Self-Paced Learning: Students can generate questions to test their understanding of video lessons.
🎓 Educational Assessment: Teachers can quickly create quizzes based on lecture videos or educational content.
🏢️ Corporate Training: Organizations can enhance their video-based training programs with automated assessments tailored to different learners.
🎬 Content Engagement: Video content creators, including YouTubers, can increase engagement by providing interactive quizzes for their content.
🧠 Memory Retention: Users can reinforce their learning by answering questions generated from informational videos.
Conclusion
This blog post offers a comprehensive explanation of the working procedure and development of the video content quiz generator using Twelve Labs. We appreciate you following along with the tutorial and look forward to your ideas on improving the user experience and addressing various challenges.
Additional Resources
To deepen your understanding of the engines used for the generation task, check out Marengo 2.6 (Embedding Engine) and Pegasus 1.1 (Generator Engine). To further explore Twelve Labs and enhance your grasp of video content analysis, consider these valuable resources:
Discord Community: Join our vibrant community of developers and enthusiasts to discuss ideas, ask questions, and share your projects.
Sample Applications: Explore a variety of sample applications to inspire your next project or learn new implementation techniques.
Explore Tutorials: Dive deeper into Twelve Labs capabilities with our comprehensive tutorials.
We encourage you to leverage these resources to expand your knowledge and create innovative applications using Twelve Labs' video understanding technology.