feat: add TwelveLabs Marengo multimodal embedders (image/audio/video) - #3617
feat: add TwelveLabs Marengo multimodal embedders (image/audio/video)#3617mohit-twelvelabs wants to merge 1 commit into
Conversation
Marengo embeds text, images, audio, and video into one shared vector space, but the integration only exposed text embeddings. This adds two components, following the existing Text/Document embedder pairing: * TwelveLabsMultimodalEmbedder — embeds a single image, audio, or video (local path or URL) into the shared Marengo space; the cross-modal query companion to TwelveLabsTextEmbedder. * TwelveLabsDocumentMultimodalEmbedder — embeds the media referenced by each Document via meta["file_path"] (Cohere/Jina image-embedder convention), for indexing. Images and audio use the synchronous embed.create API; video uses the asynchronous embed.tasks workflow (submit, poll, retrieve). Modality is inferred from the file extension / MIME type and can be overridden. Adds unit + gated integration tests and wires the new modules into the pydoc config and README. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Heads-up for maintainers This PR is from a fork and touches integrations whose integration tests require API keys. Affected integrations:
Please run the integration tests locally ( |
Coverage report (twelvelabs)Click to see where and how coverage changed
This report was generated by python-coverage-comment-action |
||||||||||||||||||||||||||||||||||||
julian-risch
left a comment
There was a problem hiding this comment.
Hi @mohit-twelvelabs and thank you for extending the TwelveLabs integration!
I noticed an inconsistency between run and run_async that I would like you to have another look at and implement in a more consistent way:
- run_async resolves all sources and modalities up front before any embed_media_async call. Saves the user costs.
- run interleaves resolution with embedding inside the loop, so a bad modality/missing path on document only raises after other documents have already been embedded and billed.
My initial thinking is that run should also do sth like:
self._validate(documents)
key = self.api_key.resolve_value() or ""
sources = [self._resolve_source(d) for d in documents]
modalities = [self._resolve_modality(d, s) for d, s in zip(documents, sources, strict=True)]
# then loop embed_media(source, modality, ...) over the pre-resolved listsHowever, I realized that TwelveLabsVideoConverter takes a different approach than other components in the integration. It only has run (no run_async at all) and each source is wrapped in try/except that logs a warning and continues, which means no fail-fast one bad source doesn't fail the whole batch.
Description
Follow-up to #3480 (the initial TwelveLabs integration). That PR shipped text embeddings
via Marengo (
TwelveLabsTextEmbedder,TwelveLabsDocumentEmbedder) plus the PegasusTwelveLabsVideoConverter. But Marengo embeds text, images, audio, and video into one shared512-dimensional space, and only the text path was exposed. This PR adds the image/audio/video
embedding capabilities so the shared space can actually be used for cross-modal retrieval.
Modeled on the Voyage integration's multimodal embedder, and kept consistent with the existing
Text/Document embedder pairing in this integration.
Components added
TwelveLabsMultimodalEmbedderEmbeds a single image, audio, or video (a local file path or a public URL) into Marengo's
shared space and returns
{"embedding": [...], "meta": {...}}. This is the cross-modal querycompanion to
TwelveLabsTextEmbedder— e.g. embed a text query with the text embedder and searcha store of video/image embeddings, or vice-versa. Modality is inferred from the file
extension / MIME type and can be set explicitly via
modality=.TwelveLabsDocumentMultimodalEmbedderThe indexing counterpart to
TwelveLabsDocumentEmbedder(which embeds textcontent). It readseach Document's media path from
meta["file_path"](configurable viafile_path_meta_field/root_path), embeds the media, and writesDocument.embedding— following the same convention asthe existing
CohereDocumentImageEmbedder/JinaDocumentImageEmbedder. Modality is inferredper-Document (override with
meta["modality"]).Implementation notes
client.embed.create.polls
embed.tasks.statusuntil it isready, then retrieves the embedding (whole-video scope).runandrun_async.twelvelabsSDK already declared by the integration.Tests and quality
ruff check,ruff format --check, andmypyall clean.@pytest.mark.integration, skipped withoutTWELVELABS_API_KEY) covera live image embedding and a live video-Document embedding.
Notes for reviewers
TwelveLabsMultimodalEmbedder(query-side) +TwelveLabsDocumentMultimodalEmbedder(document-side) to mirror the existing
Text/Documentpairing and the repo's image-embedderconvention. Happy to rename or split further if you'd prefer.
I finalize.