{"id":111186,"date":"2024-05-09T09:05:00","date_gmt":"2024-05-09T16:05:00","guid":{"rendered":"https:\/\/backblaze.com\/blog\/?p=111186"},"modified":"2024-08-23T16:41:16","modified_gmt":"2024-08-23T23:41:16","slug":"ai-video-understanding-in-your-apps-with-twelve-labs-and-backblaze","status":"publish","type":"post","link":"https:\/\/www.backblaze.com\/blog\/ai-video-understanding-in-your-apps-with-twelve-labs-and-backblaze\/","title":{"rendered":"AI Video Understanding in Your Apps with Twelve Labs and Backblaze"},"content":{"rendered":"<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1440\" height=\"820\" src=\"https:\/\/www.backblaze.com\/blog\/wp-content\/uploads\/2024\/05\/bb-bh-Twelve-Labs.png\" alt=\"A decorative header depicting several screens with video editing tasks and a cloud with the Backblaze logo on it. \" class=\"wp-image-111187\" srcset=\"https:\/\/backblazeprod.wpenginepowered.com\/wp-content\/uploads\/2024\/05\/bb-bh-Twelve-Labs.png 1440w, https:\/\/backblazeprod.wpenginepowered.com\/wp-content\/uploads\/2024\/05\/bb-bh-Twelve-Labs-300x171.png 300w, https:\/\/backblazeprod.wpenginepowered.com\/wp-content\/uploads\/2024\/05\/bb-bh-Twelve-Labs-1024x583.png 1024w, https:\/\/backblazeprod.wpenginepowered.com\/wp-content\/uploads\/2024\/05\/bb-bh-Twelve-Labs-768x437.png 768w\" sizes=\"auto, (max-width: 1440px) 100vw, 1440px\" \/><\/figure>\n<\/div>\n\n\n<div style=\"height:15px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Over the past few years, since long before the recent <a href=\"https:\/\/www.backblaze.com\/blog\/ai-101-how-cognitive-science-and-computer-processors-create-artificial-intelligence\/\" target=\"_blank\" rel=\"noreferrer noopener\">large language model (LLM) revolution<\/a>, we\u2019ve benefited not only from the ability of AI models to transcribe audio to text, but also to automatically tag video files according to their content. Media asset management (MAM) software\u2014such as <a href=\"https:\/\/www.backblaze.com\/blog\/managing-the-media-tidal-wave-backlight-iconiks-2024-media-report\/\" target=\"_blank\" rel=\"noreferrer noopener\">Backlight iconik<\/a> and <a href=\"https:\/\/axle.ai\/cloud-backblaze\/\" target=\"_blank\" rel=\"noreferrer noopener\">Axle.ai<\/a> (both Backblaze Partners, by the way)\u2014allows media professionals to quickly locate footage by searching for combinations of tags. For example, \u201cred car\u201d, will return not only a list of video files containing red cars, but also the timecodes pinpointing the appearance of the red car in each clip.<\/p>\n\n\n\n<p>San Francisco startup <a href=\"https:\/\/www.twelvelabs.io\/\" target=\"_blank\" rel=\"noreferrer noopener\">Twelve Labs<\/a> has created a video understanding platform that allows any developer to build this kind of functionality, and more, into their app via a straightforward RESTful API.&nbsp;<\/p>\n\n\n\n<p>In preparation for <a href=\"https:\/\/www.brighttalk.com\/webcast\/14807\/611588\" target=\"_blank\" rel=\"noreferrer noopener\">our webinar with Twelve Labs last month<\/a>, I created a web app to show how to integrate Twelve Labs with Backblaze B2 for storing video. The <a href=\"https:\/\/github.com\/backblaze-b2-samples\/b2-twelvelabs-example\" target=\"_blank\" rel=\"noreferrer noopener\">complete sample app is available as open source at GitHub<\/a>; in this blog post, I\u2019ll provide a brief description of the Twelve Labs platform, explain how presigned URLs allow temporary access to files in a private bucket, and then share the key elements of the sample app. If you just want a high level understanding of the integration, read on, and feel free to skip the technical details!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Twelve Labs Video Understanding Platform<\/h2>\n\n\n\n<p>The core of the Twelve Labs platform is a foundation model that operates across the visual, audio, and text modes of video content, allowing multimodal video understanding. When you submit a video using the Twelve Labs Task API, the platform generates a compact numerical representation of the video content, termed an <strong>embedding<\/strong>, that identifies entities, actions, patterns, movements, objects, scenes, other elements of the video, and their interrelationships. The embedding contains everything the Twelve Labs platform needs to do its work\u2014after the initial scan, the platform no longer needs access to the original video content. As each video is scanned into the platform, its embedding is added to an <strong>index<\/strong>, so this scanning process is often referred to as <strong>indexing<\/strong>.<\/p>\n\n\n\n<p>As part of the indexing process, the platform extracts a standard set of data from each video: a thumbnail image, a transcript of any spoken content, any text that appears on screen, and a list of brand logos, all annotated with timecodes locating them on the video\u2019s timeline, and all accessible via the Twelve Labs Index API.<\/p>\n\n\n\n<p>You can have the platform create a title and summary, and even prompt the model to describe the video, via Twelve Labs\u2019 Generate API. For example, I indexed an <a href=\"https:\/\/www.youtube.com\/watch?v=kwK2XnsSlLI\" target=\"_blank\" rel=\"noreferrer noopener\">eight-minute video that explains how to back up a Synology NAS to Backblaze B2<\/a>, then prompted the Generate API, \u201cWhat are the two Synology applications mentioned in the video?\u201d This was the first sentence of the resulting text:<\/p>\n\n\n\n<p class=\"has-background\" style=\"background-color:#f5f4ff\">The two Synology applications mentioned throughout the video are \u201cSynology Hyper Backup\u201d and \u201cSynology Cloud Sync.\u201d<\/p>\n\n\n\n<p>The remainder of the response is a brief summary of the two applications and how they differ; <a href=\"https:\/\/f004.backblazeb2.com\/file\/blze-ev-share\/TwelveLabsResponse.txt\" target=\"_blank\" rel=\"noreferrer noopener\">here\u2019s the full text<\/a>. Although it does have that \u201cAI flavor\u201d as you read it, it\u2019s clear and accurate. I must admit, I was quite impressed!<\/p>\n\n\n\n<p>You can define a taxonomy for your videos via the Classify API. Submit a one- or two-level classification schema and a set of video IDs, and the platform will assign each video to a category.<\/p>\n\n\n\n<p>Rounding up this quick tour of the Twelve Labs platform, the Search API, as its name suggests, allows you to search the indexed videos. As well as a search query, you must specify a set of content sources: any combination of visual, conversation, text in video, or logos. Each search result includes timecodes for its start and end.<\/p>\n\n\n\n<p>Now you understand the basic capabilities of the Twelve Labs platform, let\u2019s look at how you can integrate it with Backblaze B2.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Allowing Temporary Access to Files in a Private Backblaze B2 Bucket<\/h2>\n\n\n\n<p>A key feature of the sample app is that it uploads videos to a private Backblaze B2 Bucket, where they are only accessible to authorized users. Twelve Labs\u2019 API allows you to submit a video for indexing by POSTing a JSON payload including the video\u2019s URL to its Task API. This is straightforward for video files in a public bucket, but how do we allow the Twelve Labs platform to read files from a private bucket?<\/p>\n\n\n\n<p>One way would be to create an application key with capabilities to read files from the private bucket and share it with the Twelve Labs platform. The main drawback to this approach is that the platform currently lacks the ability to sign requests for files from a private bucket.<\/p>\n\n\n\n<p>Since Twelve Labs only needs to read the video file when we submit it for indexing, we can send it a presigned URL for the video file. As well as the usual Backblaze B2 endpoint, bucket name, and object key (path and filename), a presigned URL includes query parameters containing data such as the time when the URL was created, its validity period in seconds, an application key ID (or access key ID, in S3 terminology), and a signature created with the corresponding application key (secret access key). Here\u2019s an example, with line breaks added for clarity:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">https:\/\/s3.us-west-004.backblazeb2.com\/mybucket\/image.jpeg\n?X-Amz-Algorithm=AWS4-HMAC-SHA256\n&amp;X-Amz-Credential=00415f935c00000000aa%2F20240423%2Fus-west-004%2Fs3%2Faws4_request\n&amp;X-Amz-Date=20240423T222652Z\n&amp;X-Amz-Expires=3600\n&amp;X-Amz-SignedHeaders=host\n&amp;X-Amz-Signature=23ade1...3ca1eb<\/pre>\n\n\n\n<p>This URL was created at 22:26:52 UTC on 04\/23\/2024, and was valid for one hour (3600 seconds). The signature is 64 hex characters. Changing <em>any<\/em> part of the URL, for example, the <code>X-Amz-Date <\/code>parameter, invalidates the signature, resulting in an <code>HTTP 403 Forbidden<\/code> error when you try to use it, with a corresponding message in the response payload:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?&gt;\n&lt;Error&gt;\n    &lt;Code&gt;SignatureDoesNotMatch&lt;\/Code&gt;\n    &lt;Message&gt;Signature validation failed&lt;\/Message&gt;\n&lt;\/Error&gt;<\/pre>\n\n\n\n<p>Attempting to use the presigned URL after it expires yields <code>HTTP 401 Unauthorized<\/code> with a message such as:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?&gt;\n&lt;Error&gt;\n    &lt;Code&gt;UnauthorizedAccess&lt;\/Code&gt;\n    &lt;Message&gt;Request has expired given timestamp: '20240423T222652Z' and expiration: 3600&lt;\/Message&gt;\n&lt;\/Error&gt;<\/pre>\n\n\n\n<p>You can create presigned URLs with any of the AWS SDKs or the AWS CLI. For example, with the CLI:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">% aws s3 presign s3:\/\/mybucket\/image.jpeg --expires-in 600 \nhttps:\/\/s3.us-west-004.backblazeb2.com\/mybucket\/image.jpeg?X-Amz...<\/pre>\n\n\n\n<p>Presigned URLs are useful whenever you want to provide temporary access to a file in a private bucket without having to share an application key for a client app to sign the request itself. The sample app also uses them when rendering HTML web pages. For example, all of the thumbnail images are retrieved by the user\u2019s browser via presigned URLs.<\/p>\n\n\n\n<p>Note that presigned URLs are a feature of <a href=\"https:\/\/www.backblaze.com\/docs-s3-compatible-api\" target=\"_blank\" rel=\"noreferrer noopener\">Backblaze B2\u2019s S3 Compatible API<\/a>. Creating a presigned URL is an offline operation and does not consume any API calls. We recommend you use presigned URLs rather than the <a href=\"https:\/\/www.backblaze.com\/apidocs\/b2-get-download-authorization\" target=\"_blank\" rel=\"noreferrer noopener\"><code>b2_get_download_authorization<\/code><\/a> B2 Native API operation, since the latter is a <a href=\"https:\/\/www.backblaze.com\/cloud-storage\/transaction-pricing\" target=\"_blank\" rel=\"noreferrer noopener\">class C API call<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Inside the Backblaze B2 + Twelve Labs Media Asset Management Example<\/h2>\n\n\n\n<p>The sample app is written in Python, using JavaScript for its front end, the <a href=\"https:\/\/www.djangoproject.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Django web framework<\/a> for its backend, the <a href=\"https:\/\/huey.readthedocs.io\/en\/latest\/\" target=\"_blank\" rel=\"noreferrer noopener\">Huey task queue<\/a> for managing long-running tasks, and the <a href=\"https:\/\/github.com\/twelvelabs-io\/twelvelabs-python\" target=\"_blank\" rel=\"noreferrer noopener\">Twelve Labs Python SDK<\/a> to interact with the Twelve Labs platform. A simple web UI allows the user to upload videos to the private bucket, browse uploaded videos, submit them for indexing, view the resulting transcription, logos, etc., and search the indexed videos.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;6a3aa4dc9231b&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"6a3aa4dc9231b\" class=\"aligncenter size-full wp-lightbox-container\"><img loading=\"lazy\" decoding=\"async\" width=\"936\" height=\"720\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/www.backblaze.com\/blog\/wp-content\/uploads\/2024\/05\/Backblaze-12-Labs_1_Index-Videos.png\" alt=\"A screenshot of an app showing several videos that have been indexed using 12 Labs' tools. \" class=\"wp-image-111189\" srcset=\"https:\/\/backblazeprod.wpenginepowered.com\/wp-content\/uploads\/2024\/05\/Backblaze-12-Labs_1_Index-Videos.png 936w, https:\/\/backblazeprod.wpenginepowered.com\/wp-content\/uploads\/2024\/05\/Backblaze-12-Labs_1_Index-Videos-300x231.png 300w, https:\/\/backblazeprod.wpenginepowered.com\/wp-content\/uploads\/2024\/05\/Backblaze-12-Labs_1_Index-Videos-768x591.png 768w\" sizes=\"auto, (max-width: 936px) 100vw, 936px\" \/><button\n\t\t\tclass=\"lightbox-trigger\"\n\t\t\ttype=\"button\"\n\t\t\taria-haspopup=\"dialog\"\n\t\t\taria-label=\"Enlarge\"\n\t\t\tdata-wp-init=\"callbacks.initTriggerButton\"\n\t\t\tdata-wp-on--click=\"actions.showLightbox\"\n\t\t\tdata-wp-style--right=\"state.imageButtonRight\"\n\t\t\tdata-wp-style--top=\"state.imageButtonTop\"\n\t\t>\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewBox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\" \/>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure>\n<\/div>\n\n\n<div style=\"height:10px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Most of the application code is concerned with rendering the web UI; very little code is required to interact with Twelve Labs.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Configuration<\/h3>\n\n\n\n<p>The Django <a href=\"https:\/\/github.com\/backblaze-b2-samples\/b2-twelvelabs-example\/blob\/main\/cattube\/settings.py\" target=\"_blank\" rel=\"noreferrer noopener\"><code>settings.py<\/code><\/a> file defines a constant for the Twelve Labs index ID and creates an SDK client object using the Twelve Labs API key. Note that the app reads the index ID and API key from environment variables, rather than including the values in the source code. Externalizing the index ID as an environment variable allows more flexibility in deployment while, of course, you should <em>never<\/em> include secrets such as passwords or API keys in source code!<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">TWELVE_LABS_INDEX_ID = os.environ['TWELVE_LABS_INDEX_ID']\nTWELVE_LABS_CLIENT = TwelveLabs(api_key=os.environ['TWELVE_LABS_API_KEY'])<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Startup<\/h3>\n\n\n\n<p>When the web application starts, it validates the index ID and API key by retrieving details of the index. This is the relevant code, in <a href=\"https:\/\/github.com\/backblaze-b2-samples\/b2-twelvelabs-example\/blob\/main\/cattube\/core\/apps.py\"><code>apps.py<\/code><\/a>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">index = TWELVE_LABS_CLIENT.index.retrieve(TWELVE_LABS_INDEX_ID)<\/pre>\n\n\n\n<p>If this API call fails, then the app prints a suitable diagnostic message identifying the issue.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Indexing<\/h3>\n\n\n\n<p>When a web application needs to perform an action that takes more than a few seconds to complete\u2014for example\u2014indexing a set of videos, it typically starts a background task to do the work, and returns an appropriate response to the user. The sample app follows this pattern: when the user selects one or more videos and hits the <strong>Index<\/strong> button, the web app starts a Huey task, <code>do_video_indexing()<\/code>, passing the IDs of the selected videos, and returns the IDs to the JavaScript front end. The front end can then show that the indexing tasks have started, and poll for their current status.<\/p>\n\n\n\n<p>Here\u2019s the code, in <a href=\"https:\/\/github.com\/backblaze-b2-samples\/b2-twelvelabs-example\/blob\/main\/cattube\/core\/tasks.py\"><code>tasks.py<\/code><\/a>, for submitting the videos for indexing.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># Create a task for each video we want to index\nfor video_task in video_tasks:\n    task = TWELVE_LABS_CLIENT.task.create(\n        TWELVE_LABS_INDEX_ID,\n        url=default_storage.url(video_task['video']),\n        disable_video_stream=True\n    )\n    print(f'Created task: {task}')\n    video_task['task_id'] = task.id<\/pre>\n\n\n\n<p>Notice the call to <code>default_storage.url()<\/code>. This function, implemented by the <a href=\"https:\/\/django-storages.readthedocs.io\/\" target=\"_blank\" rel=\"noreferrer noopener\"><code>django-storages<\/code><\/a> library, takes as its argument the path to the video file, returning the presigned URL. The default expiry period is one hour.<\/p>\n\n\n\n<p>Once the videos have been submitted, <code>do_video_indexing()<\/code> polls for the status of each indexing task until all are complete. Most of the code is concerned with minimizing the number of calls to the API, and saving status to the app\u2019s database; getting the status of a task is simple:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">task = TWELVE_LABS_CLIENT.task.retrieve(video_task['task_id'])<\/pre>\n\n\n\n<p>The task object\u2019s status attribute is a string with a value such as <code>validating<\/code>, <code>indexing<\/code>, or <code>ready<\/code>. When the task reaches the <code>ready<\/code> status, the task object also includes a <code>video_id<\/code> attribute, uniquely identifying the video within the Twelve Labs platform. At this point, <code>do_video_indexing()<\/code> calls a helper function that retrieves the thumbnail, transcript, text, and logos and stores them in Backblaze B2.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Retrieving Video Data<\/h3>\n\n\n\n<p>Here\u2019s the call to retrieve the thumbnail:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">thumbnail_url = TWELVE_LABS_CLIENT.index.video.thumbnail(TWELVE_LABS_INDEX_ID, video.video_id)<\/pre>\n\n\n\n<p>The helper function creates a path for the thumbnail file from the video ID and the file extension in the returned URL, and saves the thumbnail to Backblaze B2:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">default_storage.save(thumbnail_path, urlopen(thumbnail_url))<\/pre>\n\n\n\n<p>Again, <code>django-storages<\/code> is doing the heavy lifting. We use <a href=\"https:\/\/docs.python.org\/3\/library\/urllib.request.html#urllib.request.urlopen\" target=\"_blank\" rel=\"noreferrer noopener\"><code>urlopen()<\/code><\/a>, from the <code>urllib.request<\/code> module, to open the thumbnail URL, providing <code>default_storage.save()<\/code> with a file-like object from which it can read the thumbnail data.<\/p>\n\n\n\n<p>The calls to retrieve transcript, text, and logo data have a slightly different form, for example:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">video_data = TWELVE_LABS_CLIENT.index.video.transcription(TWELVE_LABS_INDEX_ID, video.video_id)<\/pre>\n\n\n\n<p>Each call returns a list of <code>VideoValue<\/code> objects, each <code>VideoValue<\/code> object comprising a <code>start<\/code> and <code>end<\/code> timecode (in seconds) and a <code>value<\/code> specific to the type of data; for example, a fragment of the transcription. We serialize each list to JSON and save it as a file in Backblaze B2.<\/p>\n\n\n\n<p>When the user navigates to the detail page for a video, JavaScript reads each dataset from Backblaze B2 and renders it into the page, allowing the user to easily navigate to any of the data items.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;6a3aa4dc92eda&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"6a3aa4dc92eda\" class=\"aligncenter size-full wp-lightbox-container\"><img loading=\"lazy\" decoding=\"async\" width=\"936\" height=\"564\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/www.backblaze.com\/blog\/wp-content\/uploads\/2024\/05\/Backblaze-12-Labs_2_Transcription.png\" alt=\"A screenshot showing a video that's used 12 Labs AI technology to create a transcript. \" class=\"wp-image-111190\" srcset=\"https:\/\/backblazeprod.wpenginepowered.com\/wp-content\/uploads\/2024\/05\/Backblaze-12-Labs_2_Transcription.png 936w, https:\/\/backblazeprod.wpenginepowered.com\/wp-content\/uploads\/2024\/05\/Backblaze-12-Labs_2_Transcription-300x181.png 300w, https:\/\/backblazeprod.wpenginepowered.com\/wp-content\/uploads\/2024\/05\/Backblaze-12-Labs_2_Transcription-768x463.png 768w\" sizes=\"auto, (max-width: 936px) 100vw, 936px\" \/><button\n\t\t\tclass=\"lightbox-trigger\"\n\t\t\ttype=\"button\"\n\t\t\taria-haspopup=\"dialog\"\n\t\t\taria-label=\"Enlarge\"\n\t\t\tdata-wp-init=\"callbacks.initTriggerButton\"\n\t\t\tdata-wp-on--click=\"actions.showLightbox\"\n\t\t\tdata-wp-style--right=\"state.imageButtonRight\"\n\t\t\tdata-wp-style--top=\"state.imageButtonTop\"\n\t\t>\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewBox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\" \/>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure>\n<\/div>\n\n\n<div style=\"height:10px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Searching the Index<\/h3>\n\n\n\n<p>When the user enters a query and hits the search button, the backend calls the Twelve Labs Search API, passing the query text, and requesting results for all four sources of information. We set <code>group_by<\/code> to video since we want to show the results by video, and set the confidence threshold to medium to improve the relevance of the results. From <code>VideoSearchView<\/code> in <a href=\"https:\/\/github.com\/backblaze-b2-samples\/b2-twelvelabs-example\/blob\/main\/cattube\/core\/views.py\" target=\"_blank\" rel=\"noreferrer noopener\"><code>views.py<\/code><\/a>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">results = TWELVE_LABS_CLIENT.search.query(\n    TWELVE_LABS_INDEX_ID,\n    query,\n    [\"visual\", \"conversation\", \"text_in_video\", \"logo\"],\n    group_by=\"video\",\n    threshold=\"medium\"\n)<\/pre>\n\n\n\n<p>By default, the <code>query()<\/code> call returns a page of 10 results in <code>result.data<\/code>, so we loop through the pages using <code>next(result)<\/code> to fetch pages of search results as necessary. Each individual search result includes start and end timecodes, confidence, and the type of match (visual, conversation, text, or logo).<\/p>\n\n\n\n<p>In the web UI, the user can click through to the results for a given video, then click an individual search result to view the matching video clip.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;6a3aa4dc93525&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"6a3aa4dc93525\" class=\"aligncenter size-full wp-lightbox-container\"><img loading=\"lazy\" decoding=\"async\" width=\"936\" height=\"662\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/www.backblaze.com\/blog\/wp-content\/uploads\/2024\/05\/Backblaze-12-Labs_3_Video-Search.png\" alt=\"A screenshot showing how to search using a 12 Labs and Backblaze video tool. \" class=\"wp-image-111191\" srcset=\"https:\/\/backblazeprod.wpenginepowered.com\/wp-content\/uploads\/2024\/05\/Backblaze-12-Labs_3_Video-Search.png 936w, https:\/\/backblazeprod.wpenginepowered.com\/wp-content\/uploads\/2024\/05\/Backblaze-12-Labs_3_Video-Search-300x212.png 300w, https:\/\/backblazeprod.wpenginepowered.com\/wp-content\/uploads\/2024\/05\/Backblaze-12-Labs_3_Video-Search-768x543.png 768w\" sizes=\"auto, (max-width: 936px) 100vw, 936px\" \/><button\n\t\t\tclass=\"lightbox-trigger\"\n\t\t\ttype=\"button\"\n\t\t\taria-haspopup=\"dialog\"\n\t\t\taria-label=\"Enlarge\"\n\t\t\tdata-wp-init=\"callbacks.initTriggerButton\"\n\t\t\tdata-wp-on--click=\"actions.showLightbox\"\n\t\t\tdata-wp-style--right=\"state.imageButtonRight\"\n\t\t\tdata-wp-style--top=\"state.imageButtonTop\"\n\t\t>\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewBox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\" \/>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure>\n<\/div>\n\n\n<div style=\"height:10px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Getting Started with Backblaze B2 and Twelve Labs<\/h2>\n\n\n\n<p>Backblaze B2 Cloud Storage is a great choice for storing video to index with Twelve Labs; free egress each month for up to three times the amount of data you\u2019re storing means that you can submit your entire video library to the Twelve Labs platform without worrying about data transfer charges, and unlimited free egress to our CDN partners reduces the costs of distributing video content to end users.<\/p>\n\n\n\n<p><a href=\"https:\/\/www.backblaze.com\/sign-up\/cloud-storage?referrer=no_pref\" target=\"_blank\" rel=\"noreferrer noopener\">Click here<\/a> to create a Backblaze B2 account, if you don\u2019t already have one. Your first 10GB of storage is free, no credit card required. If you\u2019re an enterprise that wants to run a larger proof of concept, you can always <a href=\"https:\/\/www.backblaze.com\/contact-sales\/cloud-storage\" target=\"_blank\" rel=\"noreferrer noopener\">reach out to our Sales Team<\/a>. You don\u2019t need to write any code to upload video files or create presigned URLs, and you can use the Backblaze web UI to upload files up to 500MB, or any of a wide variety of tools to upload files up to 10TB, including the <a href=\"https:\/\/rclone.org\/\" target=\"_blank\" rel=\"noreferrer noopener\">AWS CLI<\/a>, <a href=\"https:\/\/www.backblaze.com\/cloud-storage\/integrations\/rclone\">rclone<\/a> and <a href=\"https:\/\/cyberduck.io\/\" target=\"_blank\" rel=\"noreferrer noopener\">Cyberduck<\/a>. Select S3 as the protocol to be able to create presigned URLs.<\/p>\n\n\n\n<p>Similarly, <a href=\"https:\/\/playground.twelvelabs.io\/\" target=\"_blank\" rel=\"noreferrer noopener\">click here<\/a> to sign up for Twelve Labs\u2019 Free plan. With it, you can index up to 600 minutes of video, again, no credit card required. Python and Node.js developers can use one of the <a href=\"https:\/\/docs.twelvelabs.io\/docs\/twelve-labs-sdks\" target=\"_blank\" rel=\"noreferrer noopener\">Twelve Labs SDKs<\/a>, while the <a href=\"https:\/\/docs.twelvelabs.io\/reference\" target=\"_blank\" rel=\"noreferrer noopener\">Twelve Labs API documentation<\/a> includes code examples for a wide range of other programming languages.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to use AI video understanding platform Twelve Labs, with Backblaze B2 Cloud Storage. <\/p>\n","protected":false},"author":174,"featured_media":111187,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"content-type":"","footnotes":"","jetpack_post_was_ever_published":false},"categories":[7,434,438,476,484,483],"tags":[],"class_list":["post-111186","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cloud-storage","category-featured-1","category-featured-cloud-storage","category-media-workflow","category-partner-news","category-tech-lab","entry"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.8 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>AI Video Understanding in Your Apps with Twelve Labs and Backblaze<\/title>\n<meta name=\"description\" content=\"Unlock the power of AI in media management! Learn how to integrate Twelve Labs with Backblaze B2 for efficient video indexing and retrieval.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.backblaze.com\/blog\/ai-video-understanding-in-your-apps-with-twelve-labs-and-backblaze\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"AI Video Understanding in Your Apps with Twelve Labs and Backblaze\" \/>\n<meta property=\"og:description\" content=\"Unlock the power of AI in media management! Learn how to integrate Twelve Labs with Backblaze B2 for efficient video indexing and retrieval.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.backblaze.com\/blog\/ai-video-understanding-in-your-apps-with-twelve-labs-and-backblaze\/\" \/>\n<meta property=\"og:site_name\" content=\"Backblaze Blog | Cloud Storage &amp; Cloud Backup\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/backblaze\" \/>\n<meta property=\"article:published_time\" content=\"2024-05-09T16:05:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-08-23T23:41:16+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.backblaze.com\/blog\/wp-content\/uploads\/2024\/05\/bb-bh-Twelve-Labs.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1440\" \/>\n\t<meta property=\"og:image:height\" content=\"820\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Pat Patterson\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@backblaze\" \/>\n<meta name=\"twitter:site\" content=\"@backblaze\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Pat Patterson\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"12 minutes\" \/>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"AI Video Understanding in Your Apps with Twelve Labs and Backblaze","description":"Unlock the power of AI in media management! Learn how to integrate Twelve Labs with Backblaze B2 for efficient video indexing and retrieval.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.backblaze.com\/blog\/ai-video-understanding-in-your-apps-with-twelve-labs-and-backblaze\/","og_locale":"en_US","og_type":"article","og_title":"AI Video Understanding in Your Apps with Twelve Labs and Backblaze","og_description":"Unlock the power of AI in media management! Learn how to integrate Twelve Labs with Backblaze B2 for efficient video indexing and retrieval.","og_url":"https:\/\/www.backblaze.com\/blog\/ai-video-understanding-in-your-apps-with-twelve-labs-and-backblaze\/","og_site_name":"Backblaze Blog | Cloud Storage &amp; Cloud Backup","article_publisher":"https:\/\/www.facebook.com\/backblaze","article_published_time":"2024-05-09T16:05:00+00:00","article_modified_time":"2024-08-23T23:41:16+00:00","og_image":[{"width":1440,"height":820,"url":"https:\/\/www.backblaze.com\/blog\/wp-content\/uploads\/2024\/05\/bb-bh-Twelve-Labs.png","type":"image\/png"}],"author":"Pat Patterson","twitter_card":"summary_large_image","twitter_creator":"@backblaze","twitter_site":"@backblaze","twitter_misc":{"Written by":"Pat Patterson","Est. reading time":"12 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.backblaze.com\/blog\/ai-video-understanding-in-your-apps-with-twelve-labs-and-backblaze\/#article","isPartOf":{"@id":"https:\/\/www.backblaze.com\/blog\/ai-video-understanding-in-your-apps-with-twelve-labs-and-backblaze\/"},"author":{"name":"Pat Patterson","@id":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/#\/schema\/person\/a724a8aee97b6451107442747cd101a4"},"headline":"AI Video Understanding in Your Apps with Twelve Labs and Backblaze","datePublished":"2024-05-09T16:05:00+00:00","dateModified":"2024-08-23T23:41:16+00:00","mainEntityOfPage":{"@id":"https:\/\/www.backblaze.com\/blog\/ai-video-understanding-in-your-apps-with-twelve-labs-and-backblaze\/"},"wordCount":2133,"commentCount":0,"publisher":{"@id":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.backblaze.com\/blog\/ai-video-understanding-in-your-apps-with-twelve-labs-and-backblaze\/#primaryimage"},"thumbnailUrl":"https:\/\/backblazeprod.wpenginepowered.com\/wp-content\/uploads\/2024\/05\/bb-bh-Twelve-Labs.png","articleSection":["Cloud Storage","Featured","Featured-Cloud Storage","Media Workflow","Partner News","Tech Lab"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.backblaze.com\/blog\/ai-video-understanding-in-your-apps-with-twelve-labs-and-backblaze\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.backblaze.com\/blog\/ai-video-understanding-in-your-apps-with-twelve-labs-and-backblaze\/","url":"https:\/\/www.backblaze.com\/blog\/ai-video-understanding-in-your-apps-with-twelve-labs-and-backblaze\/","name":"AI Video Understanding in Your Apps with Twelve Labs and Backblaze","isPartOf":{"@id":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.backblaze.com\/blog\/ai-video-understanding-in-your-apps-with-twelve-labs-and-backblaze\/#primaryimage"},"image":{"@id":"https:\/\/www.backblaze.com\/blog\/ai-video-understanding-in-your-apps-with-twelve-labs-and-backblaze\/#primaryimage"},"thumbnailUrl":"https:\/\/backblazeprod.wpenginepowered.com\/wp-content\/uploads\/2024\/05\/bb-bh-Twelve-Labs.png","datePublished":"2024-05-09T16:05:00+00:00","dateModified":"2024-08-23T23:41:16+00:00","description":"Unlock the power of AI in media management! Learn how to integrate Twelve Labs with Backblaze B2 for efficient video indexing and retrieval.","breadcrumb":{"@id":"https:\/\/www.backblaze.com\/blog\/ai-video-understanding-in-your-apps-with-twelve-labs-and-backblaze\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.backblaze.com\/blog\/ai-video-understanding-in-your-apps-with-twelve-labs-and-backblaze\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.backblaze.com\/blog\/ai-video-understanding-in-your-apps-with-twelve-labs-and-backblaze\/#primaryimage","url":"https:\/\/backblazeprod.wpenginepowered.com\/wp-content\/uploads\/2024\/05\/bb-bh-Twelve-Labs.png","contentUrl":"https:\/\/backblazeprod.wpenginepowered.com\/wp-content\/uploads\/2024\/05\/bb-bh-Twelve-Labs.png","width":1440,"height":820,"caption":"A decorative header depicting several screens with video editing tasks and a cloud with the Backblaze logo on it."},{"@type":"BreadcrumbList","@id":"https:\/\/www.backblaze.com\/blog\/ai-video-understanding-in-your-apps-with-twelve-labs-and-backblaze\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/"},{"@type":"ListItem","position":2,"name":"AI Video Understanding in Your Apps with Twelve Labs and Backblaze"}]},{"@type":"WebSite","@id":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/#website","url":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/","name":"Backblaze Cloud Solutions Blog","description":"Cloud Storage &amp; Cloud Backup","publisher":{"@id":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/#organization","name":"Backblaze","url":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/i0.wp.com\/www.backblaze.com\/blog\/wp-content\/uploads\/2017\/12\/backblaze_icon_transparent.png?fit=512%2C512&ssl=1","contentUrl":"https:\/\/i0.wp.com\/www.backblaze.com\/blog\/wp-content\/uploads\/2017\/12\/backblaze_icon_transparent.png?fit=512%2C512&ssl=1","width":512,"height":512,"caption":"Backblaze"},"image":{"@id":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/backblaze","https:\/\/x.com\/backblaze","https:\/\/www.youtube.com\/user\/Backblaze","https:\/\/en.wikipedia.org\/wiki\/Backblaze"]},{"@type":"Person","@id":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/#\/schema\/person\/a724a8aee97b6451107442747cd101a4","name":"Pat Patterson","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/backblazeprod.wpenginepowered.com\/wp-content\/uploads\/2022\/01\/PatPatterson1920px-150x150.png","url":"https:\/\/backblazeprod.wpenginepowered.com\/wp-content\/uploads\/2022\/01\/PatPatterson1920px-150x150.png","contentUrl":"https:\/\/backblazeprod.wpenginepowered.com\/wp-content\/uploads\/2022\/01\/PatPatterson1920px-150x150.png","caption":"Pat Patterson"},"description":"Pat Patterson is the former chief technical evangelist at Backblaze. Over his three decades in the industry, Pat has built software and communities at Sun Microsystems, Salesforce, StreamSets, and Citrix. In his role at Backblaze, he creates and delivers content tailored to the needs of the hands-on technical professional, acts as the \u201cvoice of the developer\u201d on the Product team, and actively participates in the wider technical community. Outside the office, Pat runs far, having completed ultramarathons up to the 50 mile distance. Catch up with Pat via Bluesky or LinkedIn.","url":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/author\/pat\/"}]}},"jetpack_featured_media_url":"https:\/\/backblazeprod.wpenginepowered.com\/wp-content\/uploads\/2024\/05\/bb-bh-Twelve-Labs.png","_links":{"self":[{"href":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/wp-json\/wp\/v2\/posts\/111186","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/wp-json\/wp\/v2\/users\/174"}],"replies":[{"embeddable":true,"href":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/wp-json\/wp\/v2\/comments?post=111186"}],"version-history":[{"count":0,"href":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/wp-json\/wp\/v2\/posts\/111186\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/wp-json\/wp\/v2\/media\/111187"}],"wp:attachment":[{"href":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/wp-json\/wp\/v2\/media?parent=111186"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/wp-json\/wp\/v2\/categories?post=111186"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/backblazeprod.wpenginepowered.com\/blog\/wp-json\/wp\/v2\/tags?post=111186"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}