Processing a Large Media Library
Run extraction over tens of thousands of files without paying for the same object twice. Price the job before you submit it, keep new uploads flowing in on their own, and move cold collections out of the vector store while they stay searchable.
Why This Matters
Extraction is the expensive part, and the bill is set by how many objects reach a GPU. A library that grows every day will re-pay for everything it already holds unless the pipeline knows what it has seen.
import os, json, urllib.requestfrom mixpeek import Mixpeekclient = Mixpeek(api_key=os.environ["MIXPEEK_API_KEY"], namespace="media-library")BUCKET_ID = "bkt_your_library"BATCH_ID = "bat_the_draft_you_just_created"COLLECTION_ID = "col_enriched_media"ARCHIVE_COLLECTION_ID = "col_2019_archive"CONNECTION_ID = "con_your_s3_connection"BASE = "https://api.mixpeek.com/v1"HEADERS = {"Authorization": f"Bearer {os.environ['MIXPEEK_API_KEY']}","X-Namespace": "media-library","Content-Type": "application/json",}def api(method, path, body=None):"""The facade covers buckets, collections, retrievers, documents,evaluations, tasks and namespaces. Batch cost, bucket syncs and collectionlifecycle have no resource on it yet, so those three go over HTTP."""req = urllib.request.Request(f"{BASE}{path}",method=method,data=json.dumps(body).encode() if body is not None else None,headers=HEADERS,)with urllib.request.urlopen(req) as r:return json.load(r)# 1. Price the run before you spend anything. estimate-cost consumes no credits# and changes nothing about the batch. already_extracted_count is the number# you care about: under 'force' or 'replace' those objects go back through a# GPU and estimated_repay_credits is what that costs.est = api("POST", f"/buckets/{BUCKET_ID}/batches/{BATCH_ID}/estimate-cost")print(est["object_count"], "objects,", est["already_extracted_count"], "already done")print(est["estimated_credits"], "credits")if est.get("estimated_usd") is not None:print("approx USD:", round(est["estimated_usd"], 2))for w in est.get("warnings", []):print("warning:", w)# 2. Run it. dedup_strategy defaults to 'skip' and is scoped to# (bucket, collection), so re-triggering after the bucket grows pays only for# the new objects. Reach for 'replace' when the extractor itself changed and# the old documents are wrong; 'force' allows duplicates and is rarely what# you want.client.collections.trigger(COLLECTION_ID, dedup_strategy="skip")# 3. Stop triggering by hand. A sync watches the bucket's storage connection and# submits what lands. skip_duplicates is on by default and does the same job# as dedup_strategy for objects arriving continuously.sync = api("POST", f"/buckets/{BUCKET_ID}/syncs", {"connection_id": CONNECTION_ID,"source_path": "incoming/","sync_mode": "continuous","polling_interval_seconds": 300,"batch_size": 50,"skip_duplicates": True,})# 4. Keep the hot set small. 'cold' evicts a collection's vectors from the vector# store and they stay searchable from object storage; 'active' rehydrates.# Search latency is set by what is resident, so an archive that nobody queries# should not be.api("PATCH", f"/collections/{ARCHIVE_COLLECTION_ID}/lifecycle",{"lifecycle_state": "cold"})
Feature Extractors
Multimodal Extractor
Unified embeddings for video, audio, image, and text: scene/silence chunking, Whisper transcription, thumbnails, and Gemini vision.
Retriever Stages
feature search
Search and filter documents by vector similarity using feature embeddings
Documentation
Frequently asked questions
How do I process thousands of videos without re-paying for the ones already done?
Leave dedup_strategy on its default of 'skip'. It is scoped to (bucket, collection), so an object counts as done if the target collection already holds documents produced from it, whichever batch made them. Re-trigger after the bucket grows and only the new objects reach a GPU. Before submitting anything, POST to the batch's estimate-cost endpoint: it returns object_count, already_extracted_count and estimated_credits without consuming credits or changing the batch.
What actually drives the cost of processing a large library?
How many objects reach an extractor, and which features you ask for. The cost estimate breaks this out as content_summary (file types and how much of each, including video minutes) and features (what the batch will let you search by). If you are using replace or force, estimated_repay_credits is the part of the bill that buys you nothing new.
How do I process new uploads automatically as they arrive?
Create a sync on the bucket. With sync_mode "continuous" it polls the storage connection every polling_interval_seconds (300 by default) and submits what it finds in batches of batch_size (50 by default). skip_duplicates defaults to true. max_objects_per_run caps a single run if you want a hard ceiling while you are still tuning it.
How do I keep search fast once the library is large?
Shrink what is resident. PATCH a collection's lifecycle to "cold" and its vectors leave the vector store while staying searchable through object storage; "active" brings them back. Latency tracks the size of the hot set, so a five-year archive that nobody queries should not be sitting in it.
Can I do all of this from the Python SDK?
Partly. client.collections.trigger(collection_id, dedup_strategy=...) is on the client. Batch cost estimation, bucket syncs and collection lifecycle have no resource manager on it yet, so those three are plain HTTP calls against the same API key.
Related Recipes & Resources
Pages on the same stages, extractors and patterns.
Multimodal Extractor
Unified embeddings for video, audio, image, and text: scene/silence chunking, Whisper transcription, thumbnails, and Gemini vision.
Feature Extraction
Multi-tier feature extraction that decomposes content into searchable components: embeddings, transcripts, detected objects, OCR text, scene boundaries, and more. The foundation for all downstream retrieval and analysis.
Video Transcription & Indexing Pipeline
Automatically transcribe video content with speaker identification, timestamps, and full-text indexing for downstream search and analytics.
Dataset Versioning
Treat versioned object storage as your dataset's source of truth. Capture complete snapshots-raw assets, embeddings, and cluster assignments-for deterministic reconstruction at any point in time.
Semantic Multimodal Search
Unified semantic search across all content types. Query by natural language and retrieve relevant video clips, images, audio segments, and documents based on meaning-not keywords or manual tags.
Clustering & Theme Discovery
Unsupervised clustering that groups content into semantic themes using HDBSCAN. Surfaces hidden patterns, content variants, and outliers without requiring predefined labels.