<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://vane.astrovela.ai/blog</id>
    <title>Vane Blog</title>
    <updated>2026-08-31T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://vane.astrovela.ai/blog"/>
    <subtitle>Vane Blog</subtitle>
    <icon>https://vane.astrovela.ai/favicon.svg</icon>
    <entry>
        <title type="html"><![CDATA[Vane Data: From Multimodal Files to Queryable Data]]></title>
        <id>https://vane.astrovela.ai/blog/from-files-to-queryable-data</id>
        <link href="https://vane.astrovela.ai/blog/from-files-to-queryable-data"/>
        <updated>2026-08-31T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[How Vane Data turns PDFs, images, audio, and video into queryable Relations with SQL, Python UDFs, AI Functions, and GPU Actors.]]></summary>
        <content type="html"><![CDATA[<p class="blog-body-lead">AI applications often need to process PDFs, images, audio, and video. Before they enter a data pipeline, PDFs must be split into pages, images decoded, audio resampled, and video expanded along its timeline, while filenames, page numbers, and frame indices remain attached as location metadata. Using these four file types, this article shows how Vane Data centers the workflow on a Relation—a multimodal dataset—to connect file expansion, batch processing, model inference, queries, and writes, turning raw files into queryable data.</p>
<div class="callout"><span class="cb">Reading note<!-- -->.</span><p>This article uses conceptual pseudocode to show how Vane Data organizes multimodal processing workflows. It omits the implementation details of tools such as PyMuPDF, image decoders, Whisper, and YOLO. Related runnable examples appear at the end.</p></div>
<img class="dimg" style="width:100%;height:auto" src="https://vane.astrovela.ai/img/blog/from-files-to-queryable-data/vane-data-multimodal-pipeline-en.png" alt="Vane Data processing PDFs, images, audio, and video into queryable data" width="1800" height="766" loading="lazy" decoding="async">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq ds" id="sql-and-python-two-apis-one-data-pipeline">SQL and Python: Two APIs, One Data Pipeline</h2>
<p>In Vane Data, file contents, business fields, and processing results all live in a <strong>Relation</strong>. SQL is well suited to column expressions, filtering, and AI Function calls. The Python API is better suited to integrating existing processing libraries, performing one-to-many expansion, and configuring runtime resources such as Actors and GPUs.</p>
<p>Parsing, decoding, and format conversion can be implemented with <strong>stateless UDFs</strong>. Models such as Whisper and YOLO, which should not be loaded repeatedly, can be wrapped in <strong>stateful UDFs</strong>: an Actor initializes the model once and then processes multiple batches. <strong>AI Functions</strong> handle Prompts and Embeddings.</p>
<p>The following four examples show how PDFs, images, audio, and video become queryable Relations. The table summarizes each pipeline, its main outputs, and how the code is organized.</p>
<table class="dt"><thead><tr><th>Example</th><th>Typical pipeline</th><th>Main output</th><th>Code structure</th></tr></thead><tbody><tr><td>PDF</td><td>PDF → text chunks → Embedding / semantic fields</td><td>One text chunk per row, retaining its source, page number, chunk index, and text while adding <span class="link">embedding</span>, <span class="link">topics</span>, and <span class="link">chunk_summary</span></td><td>SQL reads files and generates vectors and semantic fields;  <br>Python <span class="link">flat_map</span> expands pages and text chunks</td></tr><tr><td>Image</td><td>Image BLOB → batch decoding and inspection → usable images → vision Prompt → STRUCT fields</td><td>One image that passed inspection per row, including file information, dimensions, an English summary, and model-reported confidence</td><td>SQL calls <span class="link">inspect_image</span> to inspect and filter images, then uses <span class="link">AI_PROMPT</span> to generate structured descriptions;  <br>Python registers the UDF</td></tr><tr><td>Audio</td><td>Audio bytes → decoding and 16 kHz resampling → Whisper input features → model inference → transcript</td><td>One audio item per row, retaining its path, language, and business fields while adding a Chinese <span class="link">transcription</span></td><td>SQL CTEs connect the batch UDFs;  <br>Python registers stateless UDFs and an Actor that reuses the Whisper model</td></tr><tr><td>Video</td><td>Video file → frames → per-frame detections → objects → cropped images</td><td>One detected object per row, including video and frame location, class, confidence, bounding box, and a cropped PNG BLOB</td><td>Python uses <span class="link">VideoFrameSource</span>, <span class="link">map_batches</span>, and a GPU Actor for frame reading, detection, object expansion, and cropping</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq ds" id="pdf-split-documents-into-text-chunks-and-generate-retrieval-and-semantic-fields">PDF: Split Documents into Text Chunks and Generate Retrieval and Semantic Fields</h2>
<p><strong>Typical pipeline:</strong> <span class="link">PDF → pages → text chunks → Embedding / semantic fields</span></p>
<p>The PDF example processes a collection of text-based documents to produce searchable text chunks. Each chunk carries its file source, page number, and chunk index, so a retrieval result can lead directly back to the original text. Vectors support similarity search, while topics and summaries support filtering and result presentation.</p>
<p>The example uses <span class="link">read_blob</span> to read the files and PyMuPDF to extract text page by page. Two Python <span class="link">flat_map</span> calls expand the PDFs first into pages and then into text chunks. The chunk size is aligned with the Embedding model's tokenizer and retains a moderate overlap. SQL then uses <span class="link">AI_EMBED</span> to generate the vector field.</p>
<p>Embedding and Prompt can process the same text-chunk Relation. The <span class="link">embedding</span> field supports similarity search, while <span class="link">topics</span> and <span class="link">chunk_summary</span> support filtering and result presentation.</p>
<div class="term"><div class="term-bar"><span class="sq sq1"></span><span class="sq sq2"></span><span class="sq sq3"></span><span class="fn">example.py</span><button type="button" class="term-copy" aria-label="Copy code">Copy</button></div><pre class="code"><span class="token-line" style="color:#15171E"><span class="token keyword" style="color:#8E3DA8;font-weight:bold">import</span><span class="token plain"> vane</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># These placeholders represent PyMuPDF and tokenizer-based helpers.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># See the related runnable example linked at the end for a complete PDF pipeline.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">EMBEDDING_MODEL </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> </span><span class="token string" style="color:#3F8A3C">"sentence-transformers/all-MiniLM-L6-v2"</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">MAX_CHUNK_TOKENS </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> </span><span class="token number" style="color:#A86420">240</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">CHUNK_TOKEN_OVERLAP </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> </span><span class="token number" style="color:#A86420">32</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># flat_map callable: take one PDF row and yield one row per page.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">def</span><span class="token plain"> </span><span class="token function" style="color:#2E66C4">extract_pages</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">row</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">for</span><span class="token plain"> page_number</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> text </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">in</span><span class="token plain"> parse_pdf</span><span class="token punctuation" style="color:#595D67">(</span><span class="token builtin" style="color:#1A7E7B">bytes</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">row</span><span class="token punctuation" style="color:#595D67">[</span><span class="token string" style="color:#3F8A3C">"content"</span><span class="token punctuation" style="color:#595D67">]</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">yield</span><span class="token plain"> </span><span class="token punctuation" style="color:#595D67">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            </span><span class="token string" style="color:#3F8A3C">"source"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> row</span><span class="token punctuation" style="color:#595D67">[</span><span class="token string" style="color:#3F8A3C">"source"</span><span class="token punctuation" style="color:#595D67">]</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            </span><span class="token string" style="color:#3F8A3C">"size"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> row</span><span class="token punctuation" style="color:#595D67">[</span><span class="token string" style="color:#3F8A3C">"size"</span><span class="token punctuation" style="color:#595D67">]</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            </span><span class="token string" style="color:#3F8A3C">"page_number"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> page_number</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            </span><span class="token string" style="color:#3F8A3C">"text"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> text</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token punctuation" style="color:#595D67">}</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># flat_map callable: take one page row and split it into overlapping tokenizer-aligned chunks.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">def</span><span class="token plain"> </span><span class="token function" style="color:#2E66C4">split_chunks</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">row</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">for</span><span class="token plain"> chunk_index</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> text </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">in</span><span class="token plain"> </span><span class="token builtin" style="color:#1A7E7B">enumerate</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        split_text_by_tokens</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            row</span><span class="token punctuation" style="color:#595D67">[</span><span class="token string" style="color:#3F8A3C">"text"</span><span class="token punctuation" style="color:#595D67">]</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            model</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">EMBEDDING_MODEL</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            max_tokens</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">MAX_CHUNK_TOKENS</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            overlap_tokens</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">CHUNK_TOKEN_OVERLAP</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">yield</span><span class="token plain"> </span><span class="token punctuation" style="color:#595D67">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            </span><span class="token string" style="color:#3F8A3C">"source"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> row</span><span class="token punctuation" style="color:#595D67">[</span><span class="token string" style="color:#3F8A3C">"source"</span><span class="token punctuation" style="color:#595D67">]</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            </span><span class="token string" style="color:#3F8A3C">"size"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> row</span><span class="token punctuation" style="color:#595D67">[</span><span class="token string" style="color:#3F8A3C">"size"</span><span class="token punctuation" style="color:#595D67">]</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            </span><span class="token string" style="color:#3F8A3C">"page_number"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> row</span><span class="token punctuation" style="color:#595D67">[</span><span class="token string" style="color:#3F8A3C">"page_number"</span><span class="token punctuation" style="color:#595D67">]</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            </span><span class="token string" style="color:#3F8A3C">"chunk_index"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> chunk_index</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            </span><span class="token string" style="color:#3F8A3C">"text"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> text</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token punctuation" style="color:#595D67">}</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># flat_map changes the row count, so declare the output schema for each stage.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">PAGE_SCHEMA </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#595D67">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token string" style="color:#3F8A3C">"source"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">sqltypes</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">VARCHAR</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token string" style="color:#3F8A3C">"size"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">sqltypes</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">BIGINT</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token string" style="color:#3F8A3C">"page_number"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">sqltypes</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">INTEGER</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token string" style="color:#3F8A3C">"text"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">sqltypes</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">VARCHAR</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token punctuation" style="color:#595D67">}</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">CHUNK_SCHEMA </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#595D67">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token operator" style="color:#595D67">**</span><span class="token plain">PAGE_SCHEMA</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token string" style="color:#3F8A3C">"chunk_index"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">sqltypes</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">INTEGER</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token punctuation" style="color:#595D67">}</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># The same connection carries both SQL queries and subsequent Python Relation operations.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">con </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">connect</span><span class="token punctuation" style="color:#595D67">(</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># read_blob loads file metadata and binary content into one Relation.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">pdfs </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> con</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">sql</span><span class="token punctuation" style="color:#595D67">(</span><span class="token triple-quoted-string string" style="color:#3F8A3C">"""</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    SELECT filename AS source, size, content</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    FROM read_blob('/data/pdfs/*.pdf')</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">"""</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># The first flat_map call expands one PDF row into multiple page rows.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">pages </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> pdfs</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">flat_map</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">extract_pages</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> schema</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">PAGE_SCHEMA</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># The second flat_map call expands one page row into multiple text-chunk rows.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">chunks </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> pages</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">flat_map</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">split_chunks</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> schema</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">CHUNK_SCHEMA</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Once the chunks form a Relation, switch back to SQL and append a vector field with AI_EMBED.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">embedded </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> chunks</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">query</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token string" style="color:#3F8A3C">"chunks"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:#3F8A3C">"""</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    SELECT</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        *,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        -- Generate a vector for each text chunk while retaining its location fields.</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        AI_EMBED(</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            text,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            provider := 'transformers',</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            model := 'sentence-transformers/all-MiniLM-L6-v2',</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            options := struct_pack(</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                device := 'cpu',</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                batch_size := 32</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            )</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        ) AS embedding</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    FROM chunks</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    """</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Continue on the same Relation with AI_PROMPT to generate queryable semantic fields.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">result </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> embedded</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">query</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token string" style="color:#3F8A3C">"embedded"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:#3F8A3C">"""</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    WITH enriched AS (</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        SELECT</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            *,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            -- AI_PROMPT returns STRUCT(topics, summary), or NULL on failure.</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            AI_PROMPT(</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                text,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                return_format := json '{</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                    "type": "object",</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                    "properties": {</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                        "topics": {</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                            "type": "array",</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                            "items": {"type": "string"}</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                        },</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                        "summary": {"type": "string"}</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                    },</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                    "required": ["topics", "summary"],</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                    "additionalProperties": false</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                }',</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                system_message :=</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                    'Extract the main topics from the text chunk and summarize it in one sentence.',</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                provider := 'vllm',</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                model := 'Qwen/Qwen2.5-7B-Instruct',</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                on_error := 'ignore',</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                options := struct_pack(</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                    max_tokens := 128,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                    temperature := 0.0</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                )</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            ) AS metadata</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        FROM embedded</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    )</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    SELECT</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        source,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        size,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        page_number,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        chunk_index,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        text,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        embedding,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        -- Expand the STRUCT directly for downstream SQL filtering and presentation.</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        metadata.topics AS topics,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        metadata.summary AS chunk_summary</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    FROM enriched</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    """</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># write_parquet materializes the entire Relation pipeline.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">result</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">write_parquet</span><span class="token punctuation" style="color:#595D67">(</span><span class="token string" style="color:#3F8A3C">"/tmp/pdf_chunks_enriched.parquet"</span><span class="token punctuation" style="color:#595D67">)</span></span></pre></div>
<p><span class="link">write_parquet</span> materializes the entire Relation pipeline. This example covers only text-based PDFs; scanned, password-protected, or corrupted files need separate handling.</p>
<p>Each output row represents one text chunk with the following fields:</p>
<table class="dt"><thead><tr><th>Field</th><th>Type</th><th>Purpose</th></tr></thead><tbody><tr><td><span class="link">source</span></td><td><span class="link">VARCHAR</span></td><td>Locate the original PDF</td></tr><tr><td><span class="link">size</span></td><td><span class="link">BIGINT</span></td><td>Retain the original file size</td></tr><tr><td><span class="link">page_number</span></td><td><span class="link">INTEGER</span></td><td>Locate the original page</td></tr><tr><td><span class="link">chunk_index</span></td><td><span class="link">INTEGER</span></td><td>Record the chunk's position within the page</td></tr><tr><td><span class="link">text</span></td><td><span class="link">VARCHAR</span></td><td>Store the text sent to the model</td></tr><tr><td><span class="link">embedding</span></td><td><span class="link">FLOAT[384]</span></td><td>Support downstream vector indexes and similarity queries</td></tr><tr><td><span class="link">topics</span></td><td><span class="link">VARCHAR[]</span></td><td>Provide a topic list for filtering text chunks</td></tr><tr><td><span class="link">chunk_summary</span></td><td><span class="link">VARCHAR</span></td><td>Provide a text-chunk summary for result presentation</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq ds" id="images-filter-usable-images-and-generate-structured-descriptions">Images: Filter Usable Images and Generate Structured Descriptions</h2>
<p><strong>Typical pipeline:</strong> <span class="link">Image BLOB → batch decoding and inspection → usable images → vision Prompt → STRUCT fields</span></p>
<p>The image example focuses on structured descriptions. Image inspection is implemented in Python and registered in advance as a SQL UDF. SQL calls the function to obtain a <span class="link">STRUCT</span> containing the width, height, and <span class="link">is_usable</span> flag, then routes images through a <span class="link">WHERE</span> clause. Records that fail inspection can form a separate Relation, while images that pass continue to the vision model. <span class="link">AI_PROMPT</span> generates a <span class="link">STRUCT(summary, model_confidence)</span> that follows the supplied schema, and SQL constrains the fields and their types.</p>
<p>The example processes five images and calls <span class="link">gpt-4o-mini</span> through the OpenAI Provider. The <span class="link">inspect_image</span> function defines the input and output contract of the batch UDF, while <span class="link">inspect_image_blobs</span> implements the underlying image-decoding logic.</p>
<div class="term"><div class="term-bar"><span class="sq sq1"></span><span class="sq sq2"></span><span class="sq sq3"></span><span class="fn">example.py</span><button type="button" class="term-copy" aria-label="Copy code">Copy</button></div><pre class="code"><span class="token-line" style="color:#15171E"><span class="token keyword" style="color:#8E3DA8;font-weight:bold">import</span><span class="token plain"> pyarrow </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">as</span><span class="token plain"> pa</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">import</span><span class="token plain"> vane</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># The UDF returns one STRUCT per image, with all three fields directly accessible from SQL.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">INSPECTION_TYPE </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> pa</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">struct</span><span class="token punctuation" style="color:#595D67">(</span><span class="token punctuation" style="color:#595D67">[</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    pa</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">field</span><span class="token punctuation" style="color:#595D67">(</span><span class="token string" style="color:#3F8A3C">"width"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> pa</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">int32</span><span class="token punctuation" style="color:#595D67">(</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    pa</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">field</span><span class="token punctuation" style="color:#595D67">(</span><span class="token string" style="color:#3F8A3C">"height"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> pa</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">int32</span><span class="token punctuation" style="color:#595D67">(</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    pa</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">field</span><span class="token punctuation" style="color:#595D67">(</span><span class="token string" style="color:#3F8A3C">"is_usable"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> pa</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">bool_</span><span class="token punctuation" style="color:#595D67">(</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token punctuation" style="color:#595D67">]</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Define a stateless batch UDF. Vane passes two Arrow arrays per batch.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># The function returns a StructArray of the same length, and batch_size controls each batch.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:#595D67">@vane</span><span class="token decorator annotation punctuation" style="color:#595D67">.</span><span class="token decorator annotation punctuation" style="color:#595D67">func</span><span class="token decorator annotation punctuation" style="color:#595D67">.</span><span class="token decorator annotation punctuation" style="color:#595D67">batch</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">return_dtype</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">INSPECTION_TYPE</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> batch_size</span><span class="token operator" style="color:#595D67">=</span><span class="token number" style="color:#A86420">32</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">def</span><span class="token plain"> </span><span class="token function" style="color:#2E66C4">inspect_image</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">image</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> minimum_side</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">return</span><span class="token plain"> inspect_image_blobs</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">image</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> minimum_side</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">con </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">connect</span><span class="token punctuation" style="color:#595D67">(</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Register the Python UDF on the current connection under the SQL name inspect_image.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># parameters declares its input signature as (BLOB, INTEGER).</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">attach_function</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    inspect_image</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    alias</span><span class="token operator" style="color:#595D67">=</span><span class="token string" style="color:#3F8A3C">"inspect_image"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    connection</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">con</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    parameters</span><span class="token operator" style="color:#595D67">=</span><span class="token punctuation" style="color:#595D67">[</span><span class="token string" style="color:#3F8A3C">"BLOB"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> </span><span class="token string" style="color:#3F8A3C">"INTEGER"</span><span class="token punctuation" style="color:#595D67">]</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Read image files into a Relation containing metadata and BLOB values.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">images </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> con</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">sql</span><span class="token punctuation" style="color:#595D67">(</span><span class="token triple-quoted-string string" style="color:#3F8A3C">"""</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    SELECT filename, size, content AS image</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    FROM read_blob('/data/images/*')</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">"""</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Call the registered Python UDF in a SQL projection. The value 64 is the minimum short side.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">inspected </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> images</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">query</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token string" style="color:#3F8A3C">"images"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:#3F8A3C">"""</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    SELECT</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        *,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        -- Each row receives a STRUCT(width, height, is_usable).</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        inspect_image(image, 64) AS inspection</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    FROM images</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    """</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Route on the UDF's is_usable field in SQL and send only usable images to the model.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">result </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> inspected</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">query</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token string" style="color:#3F8A3C">"inspected"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:#3F8A3C">"""</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    WITH described AS (</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        SELECT</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            filename,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            size,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            inspection.width AS width,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            inspection.height AS height,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            -- Call a vision Prompt for each image that passed inspection and require a fixed STRUCT.</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            AI_PROMPT(</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                'Describe the main subject in the image and provide a confidence score from 0 to 1.',</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                image,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                return_format := json '{</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                    "type": "object",</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                    "properties": {</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                        "summary": {"type": "string"},</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                        "model_confidence": {"type": "number"}</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                    },</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                    "required": ["summary", "model_confidence"],</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                    "additionalProperties": false</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                }',</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                system_message := 'Return only an English-language result that matches the requested structure.',</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                provider := 'openai',</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                model := 'gpt-4o-mini',</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                on_error := 'ignore',</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                options := struct_pack(</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                    use_chat_completions := true,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                    max_output_tokens := 128,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                    temperature := 0.0</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                )</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            ) AS answer</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        FROM inspected</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        WHERE inspection.is_usable</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    )</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    SELECT</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        filename,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        size,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        width,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        height,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        -- Expand the model-returned STRUCT into regular queryable columns.</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        answer.summary AS summary,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        answer.model_confidence AS model_confidence</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    FROM described</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    """</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Materialize the preceding UDF inspection and model calls.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">result</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">write_parquet</span><span class="token punctuation" style="color:#595D67">(</span><span class="token string" style="color:#3F8A3C">"/tmp/image_descriptions.parquet"</span><span class="token punctuation" style="color:#595D67">)</span></span></pre></div>
<p>The results for the five images are:</p>
<table class="dt"><thead><tr><th>Filename (<span class="link">filename</span>)</th><th>Content summary (<span class="link">summary</span>)</th><th>Model-reported confidence (<span class="link">model_confidence</span>)</th></tr></thead><tbody><tr><td><span class="link">n02094114_4707.JPEG</span></td><td>A fluffy puppy is running across the grass</td><td>0.95</td></tr><tr><td><span class="link">n02398521_13903.JPEG</span></td><td><span class="link">NULL</span></td><td><span class="link">NULL</span></td></tr><tr><td><span class="link">n01784675_1352.JPEG</span></td><td>A close-up of a centipede, showing its segmented body and long, slender legs</td><td>0.95</td></tr><tr><td><span class="link">n02790996_10925.JPEG</span></td><td>A man is bench-pressing in a gym</td><td>0.95</td></tr><tr><td><span class="link">n02018207_15713.JPEG</span></td><td><span class="link">NULL</span></td><td><span class="link">NULL</span></td></tr></tbody></table>
<p><span class="link">NULL</span> means the image passed decoding and dimension checks, but the Prompt stage did not produce a valid structured result. The cause may be a Provider error or an output validation failure; it does not mean that the image itself is unusable. <span class="link">model_confidence</span> can assist with ranking.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq ds" id="audio-transcribe-in-stages-and-reuse-the-whisper-model">Audio: Transcribe in Stages and Reuse the Whisper Model</h2>
<p><strong>Typical pipeline:</strong> <span class="link">audio bytes → decoding and 16 kHz resampling → Whisper input features → model inference → transcript</span></p>
<p>This example uses Mandarin audio. The samples vary in encoding, sampling rate, and duration, so they must be decoded and resampled to 16 kHz before being sent to Whisper. The query uses a sequence of SQL CTEs and a final projection to make each stage explicit: extract the audio bytes, decode and resample them, generate input features, run Whisper, and decode the output tokens into Chinese text. The final four stages call registered batch UDFs. Model inference explicitly sets <span class="link">language="zh"</span> and <span class="link">task="transcribe"</span> so short clips do not depend on automatic language detection.</p>
<p>Stateless batch UDFs provide decoding, feature generation, and token decoding. The <span class="link">WhisperTranscriber</span> Actor backs the <span class="link">whisper_transcribe_zh</span> SQL UDF and reuses one model instance throughout its lifetime. SQL organizes these stages.</p>
<div class="term"><div class="term-bar"><span class="sq sq1"></span><span class="sq sq2"></span><span class="sq sq3"></span><span class="fn">example.py</span><button type="button" class="term-copy" aria-label="Copy code">Copy</button></div><pre class="code"><span class="token-line" style="color:#15171E"><span class="token keyword" style="color:#8E3DA8;font-weight:bold">import</span><span class="token plain"> vane</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">MODEL_ID </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> </span><span class="token string" style="color:#3F8A3C">"openai/whisper-tiny"</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">SAMPLING_RATE </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> </span><span class="token number" style="color:#A86420">16000</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">BATCH_SIZE </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> </span><span class="token number" style="color:#A86420">128</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">NUM_GPU_ACTORS </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> </span><span class="token number" style="color:#A86420">1</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Declare the types of the three intermediate results for both UDF returns and SQL parameters.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">FEATURE_MELS </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> </span><span class="token number" style="color:#A86420">80</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">FEATURE_FRAMES </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> </span><span class="token number" style="color:#A86420">3000</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">RESAMPLED_AUDIO_TYPE </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">list_type</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">sqltypes</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">FLOAT</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">INPUT_FEATURES_TYPE </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">tensor_type</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">sqltypes</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">FLOAT</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">FEATURE_MELS</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> FEATURE_FRAMES</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">TOKEN_IDS_TYPE </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">list_type</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">sqltypes</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">INTEGER</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># These placeholders represent audio decoding, feature construction, and token decoding.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># See the related runnable example linked at the end for a complete audio pipeline.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># First stateless batch UDF: decode audio BLOBs in different formats into 16 kHz waveforms.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:#595D67">@vane</span><span class="token decorator annotation punctuation" style="color:#595D67">.</span><span class="token decorator annotation punctuation" style="color:#595D67">func</span><span class="token decorator annotation punctuation" style="color:#595D67">.</span><span class="token decorator annotation punctuation" style="color:#595D67">batch</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">return_dtype</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">RESAMPLED_AUDIO_TYPE</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> batch_size</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">BATCH_SIZE</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">def</span><span class="token plain"> </span><span class="token function" style="color:#2E66C4">decode_resample_16k</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">audio_bytes</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">return</span><span class="token plain"> decode_and_resample</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">audio_bytes</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> sample_rate</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">SAMPLING_RATE</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Second stateless batch UDF: convert waveforms into the fixed-shape features Whisper expects.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:#595D67">@vane</span><span class="token decorator annotation punctuation" style="color:#595D67">.</span><span class="token decorator annotation punctuation" style="color:#595D67">func</span><span class="token decorator annotation punctuation" style="color:#595D67">.</span><span class="token decorator annotation punctuation" style="color:#595D67">batch</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">return_dtype</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">INPUT_FEATURES_TYPE</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> batch_size</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">BATCH_SIZE</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">def</span><span class="token plain"> </span><span class="token function" style="color:#2E66C4">prepare_whisper_features</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">waveform</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">return</span><span class="token plain"> build_whisper_features</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        waveform</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        model</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">MODEL_ID</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        sample_rate</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">SAMPLING_RATE</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Define a stateful Actor UDF. Each Actor uses one GPU and processes multiple batches.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:#595D67">@vane</span><span class="token decorator annotation punctuation" style="color:#595D67">.</span><span class="token decorator annotation punctuation" style="color:#595D67">cls</span><span class="token decorator annotation punctuation" style="color:#595D67">.</span><span class="token decorator annotation punctuation" style="color:#595D67">batch</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    actor_number</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">NUM_GPU_ACTORS</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    gpus</span><span class="token operator" style="color:#595D67">=</span><span class="token number" style="color:#A86420">1.0</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    return_dtype</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">TOKEN_IDS_TYPE</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    batch_size</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">BATCH_SIZE</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">class</span><span class="token plain"> </span><span class="token class-name" style="color:#1A7E7B">WhisperTranscriber</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">def</span><span class="token plain"> </span><span class="token function" style="color:#2E66C4">__init__</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token comment" style="color:#9A9DA6;font-style:italic"># __init__ runs once when the Actor is created, avoiding a model load for every batch.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        self</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">model </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> load_whisper</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">MODEL_ID</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> device</span><span class="token operator" style="color:#595D67">=</span><span class="token string" style="color:#3F8A3C">"cuda"</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">def</span><span class="token plain"> </span><span class="token function" style="color:#2E66C4">__call__</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> input_features</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token comment" style="color:#9A9DA6;font-style:italic"># __call__ processes one feature batch and explicitly selects Chinese transcription.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">return</span><span class="token plain"> transcribe_to_token_ids</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            input_features</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            model</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">self</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">model</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            language</span><span class="token operator" style="color:#595D67">=</span><span class="token string" style="color:#3F8A3C">"zh"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            task</span><span class="token operator" style="color:#595D67">=</span><span class="token string" style="color:#3F8A3C">"transcribe"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Third stateless batch UDF: decode the model's token IDs into Chinese strings.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:#595D67">@vane</span><span class="token decorator annotation punctuation" style="color:#595D67">.</span><span class="token decorator annotation punctuation" style="color:#595D67">func</span><span class="token decorator annotation punctuation" style="color:#595D67">.</span><span class="token decorator annotation punctuation" style="color:#595D67">batch</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">return_dtype</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">sqltypes</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">VARCHAR</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> batch_size</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">BATCH_SIZE</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">def</span><span class="token plain"> </span><span class="token function" style="color:#2E66C4">decode_whisper_tokens</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">token_ids</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">return</span><span class="token plain"> decode_token_ids</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">token_ids</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> model</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">MODEL_ID</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">con </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">connect</span><span class="token punctuation" style="color:#595D67">(</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Register the decoding and resampling UDF with the SQL signature decode_resample_16k(BLOB).</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">attach_function</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    decode_resample_16k</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    alias</span><span class="token operator" style="color:#595D67">=</span><span class="token string" style="color:#3F8A3C">"decode_resample_16k"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    connection</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">con</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    parameters</span><span class="token operator" style="color:#595D67">=</span><span class="token punctuation" style="color:#595D67">[</span><span class="token string" style="color:#3F8A3C">"BLOB"</span><span class="token punctuation" style="color:#595D67">]</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Register the feature-generation UDF, matching its input type to the previous stage's return.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">attach_function</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    prepare_whisper_features</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    alias</span><span class="token operator" style="color:#595D67">=</span><span class="token string" style="color:#3F8A3C">"prepare_whisper_features"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    connection</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">con</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    parameters</span><span class="token operator" style="color:#595D67">=</span><span class="token punctuation" style="color:#595D67">[</span><span class="token plain">RESAMPLED_AUDIO_TYPE</span><span class="token punctuation" style="color:#595D67">]</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Register the Actor instance. Every SQL call reuses the model already loaded in the Actor.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">attach_function</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    WhisperTranscriber</span><span class="token punctuation" style="color:#595D67">(</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    alias</span><span class="token operator" style="color:#595D67">=</span><span class="token string" style="color:#3F8A3C">"whisper_transcribe_zh"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    connection</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">con</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    parameters</span><span class="token operator" style="color:#595D67">=</span><span class="token punctuation" style="color:#595D67">[</span><span class="token plain">INPUT_FEATURES_TYPE</span><span class="token punctuation" style="color:#595D67">]</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Register the token-decoding UDF, converting INTEGER[] into VARCHAR.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">attach_function</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    decode_whisper_tokens</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    alias</span><span class="token operator" style="color:#595D67">=</span><span class="token string" style="color:#3F8A3C">"decode_whisper_tokens"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    connection</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">con</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    parameters</span><span class="token operator" style="color:#595D67">=</span><span class="token punctuation" style="color:#595D67">[</span><span class="token plain">TOKEN_IDS_TYPE</span><span class="token punctuation" style="color:#595D67">]</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Read a Parquet Relation containing the audio STRUCT and sample metadata.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">source </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> con</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">sql</span><span class="token punctuation" style="color:#595D67">(</span><span class="token triple-quoted-string string" style="color:#3F8A3C">"""</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    SELECT *</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    FROM read_parquet('/data/chinese-speech/*.parquet')</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">"""</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Connect the registered UDFs through staged SQL CTEs and the final projection.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">result </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> source</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">query</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token string" style="color:#3F8A3C">"source"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:#3F8A3C">"""</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    WITH audio AS (</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        SELECT</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            * EXCLUDE (audio),</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            -- Extract the raw audio BLOB from the audio STRUCT.</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            audio.bytes AS audio_bytes</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        FROM source</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    ),</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    resampled AS (</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        SELECT</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            * EXCLUDE (audio_bytes),</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            -- Stage 1: call a Python UDF to decode and resample the audio to 16 kHz.</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            decode_resample_16k(audio_bytes) AS waveform</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        FROM audio</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    ),</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    featured AS (</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        SELECT</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            * EXCLUDE (waveform),</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            -- Stage 2: call a Python UDF to generate Whisper input tensors.</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            prepare_whisper_features(waveform) AS input_features</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        FROM resampled</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    ),</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    tokens AS (</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        SELECT</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            * EXCLUDE (input_features),</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            -- Stage 3: call an Actor UDF to run model inference on the GPU.</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            whisper_transcribe_zh(input_features) AS token_ids</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        FROM featured</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    )</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    SELECT</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        * EXCLUDE (token_ids),</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        -- Stage 4: call a Python UDF to decode token IDs into the final text.</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        decode_whisper_tokens(token_ids) AS transcription</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    FROM tokens</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    """</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Write only the business fields and transcript. The write materializes the entire UDF chain.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">result</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">write_parquet</span><span class="token punctuation" style="color:#595D67">(</span><span class="token string" style="color:#3F8A3C">"/tmp/chinese_audio_transcriptions.parquet"</span><span class="token punctuation" style="color:#595D67">)</span></span></pre></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq ds" id="video-detect-frame-by-frame-and-extract-objects">Video: Detect Frame by Frame and Extract Objects</h2>
<p><strong>Typical pipeline:</strong> <span class="link">video file → frame Relation → per-frame detections → object-level Relation → cropped images</span></p>
<p>Video processing involves a custom data source, contiguous frame tensors, GPU Actor configuration, and batched object cropping. These steps are more direct to express through the Python API, so this section takes a Python-first approach.</p>
<p>The video pipeline changes row granularity twice. <span class="link">VideoFrameSource</span> first expands a video along its timeline into multiple frames, and object detection then expands the objects in each frame into multiple records. <span class="link">source_id</span>, <span class="link">video_path</span>, and <span class="link">frame_index</span> stay attached to every record, so detections can be queried by object fields and traced back to the source video.</p>
<p>An Actor lets <span class="link">Detector</span> reuse the YOLO model. <span class="link">crop_object_batch</span> expands the detection list and crops each bounding box into a PNG.</p>
<div class="term"><div class="term-bar"><span class="sq sq1"></span><span class="sq sq2"></span><span class="sq sq3"></span><span class="fn">example.py</span><button type="button" class="term-copy" aria-label="Copy code">Copy</button></div><pre class="code"><span class="token-line" style="color:#15171E"><span class="token keyword" style="color:#8E3DA8;font-weight:bold">import</span><span class="token plain"> vane</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">from</span><span class="token plain"> vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">datasource </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">import</span><span class="token plain"> read_datasource</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">from</span><span class="token plain"> vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">datasource</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">video_reader </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">import</span><span class="token plain"> VideoFrameSource</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Stateful batch callable: Vane creates and manages the Actor after it is passed to map_batches.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">class</span><span class="token plain"> </span><span class="token class-name" style="color:#1A7E7B">Detector</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">def</span><span class="token plain"> </span><span class="token function" style="color:#2E66C4">__init__</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Each Actor loads the YOLO model only once during its lifetime.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        self</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">model </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> load_yolo</span><span class="token punctuation" style="color:#595D67">(</span><span class="token string" style="color:#3F8A3C">"yolo11n.pt"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> device</span><span class="token operator" style="color:#595D67">=</span><span class="token string" style="color:#3F8A3C">"cuda"</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">def</span><span class="token plain"> </span><span class="token function" style="color:#2E66C4">__call__</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> table</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token comment" style="color:#9A9DA6;font-style:italic"># __call__ receives one Arrow Table batch and detects objects in all of its video frames.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">return</span><span class="token plain"> run_object_detection</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            table</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            model</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">self</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">model</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            frame_column</span><span class="token operator" style="color:#595D67">=</span><span class="token string" style="color:#3F8A3C">"frame"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            fields</span><span class="token operator" style="color:#595D67">=</span><span class="token punctuation" style="color:#595D67">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">                </span><span class="token string" style="color:#3F8A3C">"label"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> </span><span class="token string" style="color:#3F8A3C">"boxes.cls"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">                </span><span class="token string" style="color:#3F8A3C">"confidence"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> </span><span class="token string" style="color:#3F8A3C">"boxes.conf"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">                </span><span class="token string" style="color:#3F8A3C">"bbox"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> </span><span class="token string" style="color:#3F8A3C">"boxes.xyxy"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            </span><span class="token punctuation" style="color:#595D67">}</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            </span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Retain source fields and frame indices with the detection results.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            pass_through</span><span class="token operator" style="color:#595D67">=</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">                </span><span class="token string" style="color:#3F8A3C">"source_id"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">                </span><span class="token string" style="color:#3F8A3C">"video_path"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">                </span><span class="token string" style="color:#3F8A3C">"frame_index"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">                </span><span class="token string" style="color:#3F8A3C">"frame"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            </span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Stateless batch callable: expand each frame's object list into multiple cropped-result rows.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">def</span><span class="token plain"> </span><span class="token function" style="color:#2E66C4">crop_object_batch</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">table</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token comment" style="color:#9A9DA6;font-style:italic"># A frame may contain multiple objects, so expand it into rows and crop each object.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">return</span><span class="token plain"> crop_detected_objects</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        table</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        frame_column</span><span class="token operator" style="color:#595D67">=</span><span class="token string" style="color:#3F8A3C">"frame"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        features_column</span><span class="token operator" style="color:#595D67">=</span><span class="token string" style="color:#3F8A3C">"features"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        pass_through</span><span class="token operator" style="color:#595D67">=</span><span class="token punctuation" style="color:#595D67">(</span><span class="token string" style="color:#3F8A3C">"source_id"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> </span><span class="token string" style="color:#3F8A3C">"video_path"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> </span><span class="token string" style="color:#3F8A3C">"frame_index"</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        object_column</span><span class="token operator" style="color:#595D67">=</span><span class="token string" style="color:#3F8A3C">"object"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">con </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">connect</span><span class="token punctuation" style="color:#595D67">(</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># VideoFrameSource decodes the videos, and read_datasource organizes the output as a frame Relation.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Each row represents one frame and carries its source, path, frame index, and frame tensor.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">frames </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> read_datasource</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    VideoFrameSource</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        video_paths</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        height</span><span class="token operator" style="color:#595D67">=</span><span class="token number" style="color:#A86420">640</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        width</span><span class="token operator" style="color:#595D67">=</span><span class="token number" style="color:#A86420">640</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    con</span><span class="token operator" style="color:#595D67">=</span><span class="token plain">con</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># The first map_batches call runs Detector. Vane creates a GPU Actor and reuses its model.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">detected </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> frames</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">map_batches</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    Detector</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token comment" style="color:#9A9DA6;font-style:italic"># schema describes every column in the Relation produced by the detection stage.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    schema</span><span class="token operator" style="color:#595D67">=</span><span class="token punctuation" style="color:#595D67">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token string" style="color:#3F8A3C">"source_id"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">sqltypes</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">VARCHAR</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token string" style="color:#3F8A3C">"video_path"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">sqltypes</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">VARCHAR</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token string" style="color:#3F8A3C">"frame_index"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">sqltypes</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">BIGINT</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token string" style="color:#3F8A3C">"frame"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> FRAME_TYPE</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token string" style="color:#3F8A3C">"features"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> FEATURE_LIST_TYPE</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token punctuation" style="color:#595D67">}</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    batch_size</span><span class="token operator" style="color:#595D67">=</span><span class="token number" style="color:#A86420">16</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    actor_number</span><span class="token operator" style="color:#595D67">=</span><span class="token number" style="color:#A86420">1</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    gpus</span><span class="token operator" style="color:#595D67">=</span><span class="token number" style="color:#A86420">1.0</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># The second map_batches call runs a stateless function to expand and crop objects on the CPU.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">objects </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> detected</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">map_batches</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    crop_object_batch</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token comment" style="color:#9A9DA6;font-style:italic"># After expansion, each row represents one object and adds a cropped PNG BLOB.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    schema</span><span class="token operator" style="color:#595D67">=</span><span class="token punctuation" style="color:#595D67">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token string" style="color:#3F8A3C">"source_id"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">sqltypes</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">VARCHAR</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token string" style="color:#3F8A3C">"video_path"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">sqltypes</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">VARCHAR</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token string" style="color:#3F8A3C">"frame_index"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">sqltypes</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">BIGINT</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token string" style="color:#3F8A3C">"features"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> FEATURE_TYPE</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token string" style="color:#3F8A3C">"object"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">sqltypes</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">BLOB</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token punctuation" style="color:#595D67">}</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># Select the final output columns explicitly; the crop stage has already dropped the frame tensor.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">result </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> objects</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">project</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token string" style="color:#3F8A3C">"source_id, video_path, frame_index, features, object"</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token comment" style="color:#9A9DA6;font-style:italic"># write_parquet materializes the preceding read, detection, and crop stages.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">result</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">write_parquet</span><span class="token punctuation" style="color:#595D67">(</span><span class="token string" style="color:#3F8A3C">"/tmp/video_objects.parquet"</span><span class="token punctuation" style="color:#595D67">)</span></span></pre></div>
<p>Each output row represents one detected object:</p>
<table class="dt"><thead><tr><th>Field</th><th>Purpose</th></tr></thead><tbody><tr><td><span class="link">source_id</span>, <span class="link">video_path</span></td><td>Identify the source video</td></tr><tr><td><span class="link">frame_index</span></td><td>Locate the decoded frame containing the object</td></tr><tr><td><span class="link">features.label</span></td><td>Store the numeric class produced by the model</td></tr><tr><td><span class="link">features.confidence</span></td><td>Store the object-detection confidence</td></tr><tr><td><span class="link">features.bbox</span></td><td>Store the bounding box in the model input frame's coordinate system</td></tr><tr><td><span class="link">object</span></td><td>Store the PNG BLOB cropped from the bounding box</td></tr></tbody></table>
<p><span class="link">features.label</span> can be mapped to a class name through YOLO's <span class="link">names</span>. The <span class="link">bbox</span> coordinates refer to the 640×640 model input frame. Mapping them back to the original video also requires the original dimensions and scaling parameters. <span class="link">frame_index</span> is only the decoded frame number; precise playback positioning also requires a timestamp, or PTS and time base.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq ds" id="conclusion">Conclusion</h2>
<p>If summaries, transcripts, and detection results are to support later queries, review, and writes, they cannot become detached from their source files. Filenames, page numbers, frame indices, and business fields stay with the results, so every returned record still reveals where it came from. Vane Data uses Relations to preserve this correspondence, while existing Python tools and models continue to handle parsing and inference. When a model changes or a business rule is added, downstream systems still receive data with a clear schema and explicit provenance instead of having to reconstruct results scattered across scripts and intermediate files. Multimodal files thus become part of routine data processing rather than stopping at a one-off model call.</p>
<p>Get started:</p>
<ul class="dl">
<li class=""><a class="dlink" href="https://github.com/AstroVela/demo-scene/tree/main/claims-disposition">Build an end-to-end multimodal claims audit</a></li>
<li class=""><a class="dlink" href="https://github.com/AstroVela/vane/blob/main/multimodal_inference_benchmarks/document_embedding/vane_main.py">PDF document Embedding example</a></li>
<li class=""><a class="dlink" href="https://github.com/AstroVela/vane/blob/main/examples/basic_prompt.py">Image structured Prompt example</a></li>
<li class=""><a class="dlink" href="https://github.com/AstroVela/vane/blob/main/multimodal_inference_benchmarks/audio_transcription/vane_main.py">Audio transcription example</a></li>
<li class=""><a class="dlink" href="https://github.com/AstroVela/vane/blob/main/multimodal_inference_benchmarks/video_object_detection/vane_main.py">Video object-detection example</a></li>
<li class=""><a class="dlink" href="https://github.com/AstroVela/vane">Vane Data GitHub repository</a></li>
<li class=""><a class="dlink" href="https://vane.astrovela.ai/docs/data/quickstart/quickstart">Vane Data quickstart</a></li>
</ul>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Vane Data: How to Turn DuckDB into an AI Multimodal Data Engine]]></title>
        <id>https://vane.astrovela.ai/blog/ai-workloads-need-a-new-data-engine</id>
        <link href="https://vane.astrovela.ai/blog/ai-workloads-need-a-new-data-engine"/>
        <updated>2026-08-23T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Why multimodal AI workloads need a data engine that coordinates relational processing, model inference, and heterogeneous resources.]]></summary>
        <content type="html"><![CDATA[<p class="blog-body-lead">Vane Data is a multimodal-native data engine built on DuckDB that brings data processing, model inference, and heterogeneous resource scheduling into a single Relation pipeline. This article explains how it combines AI Functions, Python UDFs, and vLLM; uses dynamic batching, pipeline parallelism, backpressure, and fault tolerance to run workloads reliably; and applies them to an auto-insurance workflow from image preprocessing to claims review routing.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq ds" id="ai-workloads-need-a-new-data-engine">AI workloads need a new data engine</h2>
<p>AI workloads are moving beyond querying tables toward understanding and acting on multimodal inputs. Agents depend on text, images, audio, video, and documents that must be parsed, filtered, and organized into queryable structures before their workflows can run reliably.</p>
<ul class="dl">
<li class=""><strong>Traditional data stacks struggle with multimodal workflows</strong></li>
</ul>
<p>Multimodal objects vary wildly in size: one row may be a few bytes or hundreds of megabytes. Model inference also requires CPU, GPU, network, and storage resources with mismatched throughput. A traditional stack combines a warehouse, Python preprocessing scripts, object storage, and a model service: the table engine handles structured data, scripts preprocess media, and another system runs inference. Data moves between systems, while batching, concurrency, retries, and memory limits are configured independently; the pipeline can spend its time queueing, idling, or hitting memory peaks.</p>
<ul class="dl">
<li class=""><strong>Vane Data brings multimodal processing back to the data engine</strong></li>
</ul>
<p>Vane Data is a multimodal-native data engine built on DuckDB. It keeps DuckDB's Relation API, treats text, images, and audio as columns, composes AI Functions and Python UDFs in the same relational query, and lets Providers such as vLLM execute inference. The results remain columns that can be filtered, joined, aggregated, and written out.</p>
<hr class="dr">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq ds" id="start-with-duckdb-then-build-an-ai-data-engine">Start with DuckDB, then build an AI data engine</h2>
<p><a class="dlink" href="https://duckdb.org/">DuckDB</a> is an embedded analytical database for querying local files, in-memory data, and object storage directly from an application or Python process. It is used for exploration, ETL, notebooks, and lightweight analytics.</p>
<ul class="dl">
<li class=""><strong>Lightweight embedding: start with one process.</strong> DuckDB runs in-process with no external service dependencies. A single installation command gets you up and running locally for instant analytics. It works particularly well with local files and in-memory data, making it ideal for embedding data processing directly into applications, notebooks, and task scripts. It’s the SQLite of OLAP.</li>
<li class=""><strong>Extreme performance for analytical workloads.</strong> DuckDB combines columnar storage, vectorized execution, SIMD instruction-level parallelism, and multi-threaded scheduling into a highly efficient data pipeline, delivering analytical throughput of hundreds of millions of rows per second on a single machine. Its outstanding analytical performance is validated by <a class="dlink" href="https://duckdb.org/2025/10/09/benchmark-results-14-lts">public ClickBench results</a>.</li>
<li class=""><strong>A rich, extensible ecosystem with on-demand loading.</strong> DuckDB offers a flexible <a class="dlink" href="https://duckdb.org/docs/stable/extensions/overview">extension mechanism</a> that allows users to define new data types, functions, file formats, and even custom SQL syntax. Data processing often involves multiple sources, and DuckDB can query Parquet, Iceberg, CSV, JSON, Arrow, and more; it can also read Python objects like Pandas and Polars DataFrames. Through its extension system, it connects to object storage, lakehouse formats, and external databases. Business records, files, and in-memory tables can be combined within a single query, reducing the need for intermediate files and format conversions.</li>
<li class=""><strong>SQL and Python: expressive interfaces.</strong> SQL is a compact way to express filtering, joins, and aggregations. The Python Relation API lets users compose the same plans step by step. Both are entry points into the same execution model.</li>
</ul>
<p>We are deeply impressed by DuckDB’s outstanding performance in the single-machine analytics space and sincerely appreciate its elegant design. Building an AI-native multimodal data engine on top of it offers inherent, compelling advantages. That is why we have built Vane Data, an AI-native multimodal data engine on DuckDB, designed to help users effortlessly build multimodal AI pipelines.</p>
<hr class="dr">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq ds" id="vane-data-the-multimodal-native-engine-coordinating-data-models-and-compute-resources">Vane Data, the multimodal-native engine: coordinating data, models, and compute resources</h2>
<img class="dimg" style="width:100%;height:auto" src="https://vane.astrovela.ai/img/blog/ai-workloads-need-a-new-data-engine/vane-data-architecture-en.png" alt="Vane Data multimodal-native data engine architecture" width="1880" height="837" loading="lazy" decoding="async">
<p>On top of DuckDB, Vane Data connects multimodal operators, AI calls, and resource scheduling into one Relation-based multimodal data pipeline. Familiar read, filter, aggregate, and export operations remain available. The next sections show how Prompt, Embedding, UDF, and vLLM stages fit into a Relation, then how those stages coordinate CPU, GPU, and I/O on one machine or across a cluster.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq dss" id="ai-functions-udfs-and-vllm-building-a-multimodal-data-pipeline-with-relation">AI Functions, UDFs, and vLLM: building a multimodal data pipeline with Relation</h3>
<p>The key is to turn multimodal data such as images and audio into Relation columns that are as composable as text and tabular fields, allowing them to flow through a lazy execution plan. Vane Data provides three complementary pieces:</p>
<ul class="dl">
<li class=""><strong>AI Functions make model calls feel like column expressions.</strong> <span class="link">ai_prompt</span> and <span class="link">ai_embed</span> work in SQL and through the Python API. <span class="link">ai_prompt</span> accepts text or images and can return a <span class="link">STRUCT</span>; <span class="link">ai_embed</span> turns text into fixed-dimensional vectors. The results remain columns that can be filtered, joined, and aggregated, with <span class="link">on_error</span>, retries, and Provider options available for control.</li>
<li class=""><strong>Python UDFs bring custom logic into the plan.</strong> <span class="link">@vane.func</span> allows stateless processing logic to be defined as functions that can be called directly in SQL. <span class="link">@vane.cls</span> defines stateful processing logic as functions, or callable classes, that can reuse resources such as models, clients, or decoders within an Actor. Both types of functions also provide a batch mode for processing data in bulk, which significantly improves performance.</li>
<li class=""><strong>Vane's native vLLM Provider adds dataflow-oriented, prefix-aware routing to improve KV/prefix-cache reuse.</strong> It places requests with shared prefixes into bounded buckets and tries to send them to the same vLLM Actor. When one Actor's in-flight load is materially higher, it rebalances without letting affinity block the entire pipeline.</li>
</ul>
<p>Prompt calls, embedding generation, and result filtering can be composed through the Relation API and executed as one complete plan when the result is finally read or written.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq dss" id="from-one-machine-to-a-cluster-schedule-cpu-gpu-and-io-together">From one machine to a cluster: schedule CPU, GPU, and I/O together</h3>
<p>Writing multimodal operations into a data pipeline is only the first step. To make it run to completion reliably, the runtime must decide where work runs, how resources are allocated, and what happens when conditions fluctuate. Vane Data delegates these concerns to a unified runtime:</p>
<ul class="dl">
<li class=""><strong>Two Runners, one business pipeline.</strong> Before creating the connection, use <span class="link">vane.configure(runner="local")</span> to select the Local Runner. It fits development and small jobs; switch to <span class="link">vane.configure(runner="ray")</span> to let the Ray Runner schedule multiple processes or nodes with CPU and GPU resources. The Relation and business logic stay the same; only runtime configuration and resource declarations change.</li>
<li class=""><strong>Dynamic batching follows data size and compute cost.</strong> The runtime considers both row counts and bytes instead of forcing objects of very different sizes into a fixed row count. Oversized inputs are split, output buffers flush at row or byte thresholds, and the partition allocator adjusts its target as it observes split sizes.</li>
<li class=""><strong>Pipeline parallelism keeps heterogeneous resources busy.</strong> Reading and decoding, CPU preprocessing, GPU inference, and I/O writes are separate stages with their own resources, concurrency, and batch sizes. An asynchronous execution graph overlaps adjacent stages so one resource can prepare the next batch while another is still running.</li>
<li class=""><strong>Backpressure trades unbounded queues for stable throughput.</strong> When a GPU, model service, or storage system slows down, bounded in-flight tasks, output windows, and resource admission prevent the upstream from submitting indefinitely. Queue bytes and pending work stay visible, keeping memory and object-store peaks under control.</li>
<li class=""><strong>Fault tolerance makes failures retryable, isolatable, and recoverable.</strong> Transient Provider errors, task failures, and Worker failures can be retried according to policy. Actors can reload their model or client after reconstruction. An AI Function can use <span class="link">on_error="ignore"</span> to produce <span class="link">NULL</span> while preserving error details, or <span class="link">raise</span> to fail the task explicitly.</li>
</ul>
<p>Together these mechanisms turn an individual model call into a continuously running data pipeline: upstream stages prepare data, middle stages infer, downstream stages reconcile results, and resource and error boundaries remain explicit.</p>
<hr class="dr">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq ds" id="case-study-one-sql-pipeline-for-image-preprocessing-ai-recognition-and-claims-disposition">Case study: one SQL pipeline for image preprocessing, AI recognition, and claims disposition</h2>
<p>Consider an auto-insurance claim. Claim records live in a business table while incident photos live in an image table. The pipeline filters pending claims, joins their photos, uses a Python UDF to correct image orientation, validate image dimensions, and normalize the image format, calls an AI Function for a structured damage assessment, and applies claim amount and business rules to decide the next step. Apart from defining and registering the UDF, the workflow is expressed as one SQL plan.</p>
<p>The JSON Schema in the example constrains the model output to a damaged part, severity, and confidence. Downstream SQL can read those structured fields directly.</p>
<div class="term"><div class="term-bar"><span class="sq sq1"></span><span class="sq sq2"></span><span class="sq sq3"></span><span class="fn">example.py</span><button type="button" class="term-copy" aria-label="Copy code">Copy</button></div><pre class="code"><span class="token-line" style="color:#15171E"><span class="token keyword" style="color:#8E3DA8;font-weight:bold">from</span><span class="token plain"> io </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">import</span><span class="token plain"> BytesIO</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">from</span><span class="token plain"> PIL </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">import</span><span class="token plain"> Image</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> ImageOps</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">import</span><span class="token plain"> vane</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">damage_schema </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> </span><span class="token triple-quoted-string string" style="color:#3F8A3C">"""{</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">  "type": "object",</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">  "properties": {</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    "damage_part": {"type": "string"},</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    "severity": {"type": "string", "enum": ["low", "medium", "high"]},</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    "confidence": {"type": "number"}</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">  },</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">  "required": ["damage_part", "severity", "confidence"],</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">  "additionalProperties": false</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">}"""</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:#595D67">@vane</span><span class="token decorator annotation punctuation" style="color:#595D67">.</span><span class="token decorator annotation punctuation" style="color:#595D67">func</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">return_dtype</span><span class="token operator" style="color:#595D67">=</span><span class="token string" style="color:#3F8A3C">"BLOB"</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">def</span><span class="token plain"> </span><span class="token function" style="color:#2E66C4">prepare_image</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">raw</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> </span><span class="token builtin" style="color:#1A7E7B">bytes</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"> </span><span class="token operator" style="color:#595D67">-</span><span class="token operator" style="color:#595D67">&gt;</span><span class="token plain"> </span><span class="token builtin" style="color:#1A7E7B">bytes</span><span class="token plain"> </span><span class="token operator" style="color:#595D67">|</span><span class="token plain"> </span><span class="token boolean" style="color:#8E3DA8;font-weight:bold">None</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">try</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">with</span><span class="token plain"> Image</span><span class="token punctuation" style="color:#595D67">.</span><span class="token builtin" style="color:#1A7E7B">open</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">BytesIO</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">raw</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"> </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">as</span><span class="token plain"> image</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            image </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> ImageOps</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">exif_transpose</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">image</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">convert</span><span class="token punctuation" style="color:#595D67">(</span><span class="token string" style="color:#3F8A3C">"RGB"</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">if</span><span class="token plain"> </span><span class="token builtin" style="color:#1A7E7B">min</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">image</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">size</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"> </span><span class="token operator" style="color:#595D67">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#A86420">480</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">                </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">return</span><span class="token plain"> </span><span class="token boolean" style="color:#8E3DA8;font-weight:bold">None</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            image</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">thumbnail</span><span class="token punctuation" style="color:#595D67">(</span><span class="token punctuation" style="color:#595D67">(</span><span class="token number" style="color:#A86420">1024</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> </span><span class="token number" style="color:#A86420">1024</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            output </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> BytesIO</span><span class="token punctuation" style="color:#595D67">(</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            image</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">save</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">output</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> </span><span class="token string" style="color:#3F8A3C">"JPEG"</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> quality</span><span class="token operator" style="color:#595D67">=</span><span class="token number" style="color:#A86420">85</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">            </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">return</span><span class="token plain"> output</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">getvalue</span><span class="token punctuation" style="color:#595D67">(</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">except</span><span class="token plain"> </span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain">OSError</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"> TypeError</span><span class="token punctuation" style="color:#595D67">)</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">        </span><span class="token keyword" style="color:#8E3DA8;font-weight:bold">return</span><span class="token plain"> </span><span class="token boolean" style="color:#8E3DA8;font-weight:bold">None</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">connection </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> vane</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">connect</span><span class="token punctuation" style="color:#595D67">(</span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">routes </span><span class="token operator" style="color:#595D67">=</span><span class="token plain"> connection</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">sql</span><span class="token punctuation" style="color:#595D67">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:#3F8A3C">"""</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    WITH prepared AS (</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        SELECT c.claim_id, c.claim_amount,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">               prepare_image(i.content) AS image</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        FROM pending_claims AS c</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        LEFT JOIN claim_images AS i USING (claim_id)</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        WHERE c.status = 'pending'</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    )</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    SELECT</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        claim_id,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        assessment.*,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        CASE</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            WHEN image IS NULL THEN 'Request more photos'</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            WHEN assessment IS NULL OR assessment.confidence &lt; 0.65 THEN 'Manual review'</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            WHEN assessment.severity = 'high' OR claim_amount &gt;= 50000 THEN 'Claims review'</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">            ELSE 'Automatic routing'</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        END AS next_step</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    FROM (</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        SELECT *,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">               CASE WHEN image IS NOT NULL THEN ai_prompt(</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                   'Identify the damaged vehicle part and severity.',</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                   image,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                   return_format := $damage_schema,</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                   system_message := 'Use only visual evidence; lower confidence when uncertain.',</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                   provider := 'openai',</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                   model := 'gpt-4o-mini',</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">                   on_error := 'ignore'</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">               ) END AS assessment</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">        FROM prepared</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    ) AS assessed</span>
</span><span class="token-line" style="color:#15171E"><span class="token triple-quoted-string string" style="color:#3F8A3C">    """</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">    params</span><span class="token operator" style="color:#595D67">=</span><span class="token punctuation" style="color:#595D67">{</span><span class="token string" style="color:#3F8A3C">"damage_schema"</span><span class="token punctuation" style="color:#595D67">:</span><span class="token plain"> damage_schema</span><span class="token punctuation" style="color:#595D67">}</span><span class="token punctuation" style="color:#595D67">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain"></span><span class="token punctuation" style="color:#595D67">)</span><span class="token plain"></span>
</span><span class="token-line" style="color:#15171E"><span class="token plain" style="display:inline-block">
</span>
</span><span class="token-line" style="color:#15171E"><span class="token plain">routes</span><span class="token punctuation" style="color:#595D67">.</span><span class="token plain">write_parquet</span><span class="token punctuation" style="color:#595D67">(</span><span class="token string" style="color:#3F8A3C">"claim_routes.parquet"</span><span class="token punctuation" style="color:#595D67">)</span></span></pre></div>
<p>Python handles image decoding and preprocessing, SQL handles joins, filtering, and claims disposition, and <span class="link">ai_prompt</span> turns each preprocessed image into a structured assessment. The assessment remains a column that can participate in conditions and later writes. Calling <span class="link">write_parquet</span> materializes the complete plan.</p>
<hr class="dr">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq ds" id="from-duckdb-to-multimodal-ai-data-processing">From DuckDB to multimodal AI data processing</h2>
<p>Vane Data gives DuckDB users a lower-friction path into multimodal and intelligent data processing: use SQL and Python to express relations, AI Functions and UDFs to process multimodal data, and one runtime to coordinate CPU, GPU, and distributed resources.</p>
<p>Start exploring:</p>
<ul class="dl">
<li class=""><a class="dlink" href="https://github.com/AstroVela/vane">GitHub repository</a></li>
<li class=""><a class="dlink" href="https://vane.astrovela.ai/docs/data/quickstart/quickstart">Quickstart</a></li>
<li class=""><a class="dlink" href="https://github.com/AstroVela/demo-scene/tree/main/claims-disposition">Complete demo: auditable multimodal claims disposition</a></li>
<li class=""><a class="dlink" href="https://vane.astrovela.ai/benchmarks">Benchmarks</a></li>
</ul>]]></content>
    </entry>
</feed>