Harbor Radio Signals
Harbor radio signal media pipeline: audio normalize/fade, vision box overlays, and StringSplitter sentence views
One app.py with 2 tables, 13 computed columns. Needs pixeltable>=0.7.16. Updated 2026-10-11.
app.py
"""Harbor Signals media pipeline built with Pixeltable.Ingest short VHF/MF/HF radio clips with a cover still and a transcript. Pixeltablederives audio metadata, peak-normalized / faded / volume-scaled copies, drawsannotated cover boxes via vision helpers, and fans the transcript into asentence view with StringSplitter. UDFs tag band lane, callsign, and duration.Layout: UDFs live in udfs.py; this file holds table models and @pxt.query functions.No HTTP router — drive the pipeline with `python run.py`.Run locally:pxt schema update app.py harborpython run.py"""from __future__ import annotationsimport pixeltable as pxtimport pixeltable.functions as pxtffrom udfs import band_lane, callsign_tag, duration_bucket, transcript_word_countTableModel = pxt.model_base()class Signals(TableModel, name='signals', has_default_idxs=False):"""One harbor radio transmission: clip + cover still + transcript."""signal_id = pxt.Column(value=pxtf.uuid.uuid7(), primary_key=True)callsign: pxt.Stringharbor: pxt.Stringband: pxt.String # vhf / mf / hftranscript: pxt.Stringclip: pxt.Audiocover: pxt.Image# ground-truth and predicted boxes on the cover (xyxy ints)gt_boxes: pxt.Json # list[list[int]]pred_boxes: pxt.Jsonbox_labels: pxt.Json # list[str]# --- fn.audio primary ---meta = pxtf.audio.get_metadata(clip)normalized = pxtf.audio.normalize(clip)faded_in = pxtf.audio.fade_in(normalized, duration=0.25)faded = pxtf.audio.fade_out(faded_in, duration=0.25)quiet = pxtf.audio.multiply_volume(clip, factor=0.4)# duration from metadata (seconds); nested json path is best-effortduration_s: pxt.Float | None# --- fn.vision secondary ---annotated = pxtf.vision.bboxes_draw(cover,pred_boxes,labels=box_labels,color='lime',width=2,)padded_pred = pxtf.vision.bboxes_pad(pred_boxes, 'xyxy', x=4, y=4)# UDF chainlane = band_lane(band)tag = callsign_tag(callsign, harbor, band)words = transcript_word_count(transcript)dur_bucket = duration_bucket(duration_s)__indexes__ = [pxt.BtreeIndex(harbor),pxt.BtreeIndex(band),pxt.BtreeIndex(lane),]class Sentences(TableModel,name='sentences',base=Signals,iterator=pxtf.string.string_splitter(Signals.transcript, separators='sentence'),):"""Component view: one row per sentence from each signal transcript."""# 'text' is an output column of string_splitterlength = pxtf.string.len(text) # type: ignore[name-defined] # noqa: F821upper = pxtf.string.upper(text) # type: ignore[name-defined] # noqa: F821@pxt.querydef by_harbor(harbor: str):"""Signals for one harbor (harbor index)."""return (Signals.where(Signals.harbor == harbor).select(Signals.signal_id,Signals.callsign,Signals.band,Signals.tag,Signals.lane,Signals.words,Signals.dur_bucket,).order_by(Signals.callsign))@pxt.querydef by_lane(lane: str):"""Signals in an ops lane (lane index)."""return (Signals.where(Signals.lane == lane).select(Signals.signal_id, Signals.callsign, Signals.harbor, Signals.band, Signals.tag).order_by(Signals.harbor))@pxt.querydef long_sentences(min_len: int):"""Sentences at least min_len characters (StringSplitter view)."""return (Sentences.where(Sentences.length >= min_len).select(Sentences.callsign, Sentences.harbor, Sentences.text, Sentences.length).order_by(Sentences.length, asc=False))
What app.py declares
Each row links to its line.
- runs on insert
- stored
- index
- route
- signal_idcallsignharborbandtranscriptclipcovergt_boxespred_boxesbox_labelsduration_s
- meta = pxtf.audio.get_metadata(clip)L41
- normalized = pxtf.audio.normalize(clip)L42
- faded_in = pxtf.audio.fade_in(normalized, duration=0.25)L43
- faded = pxtf.audio.fade_out(faded_in, duration=0.25)L44
- quiet = pxtf.audio.multiply_volume(clip, factor=0.4)L45
- annotated = pxtf.vision.bboxes_draw(cover, pred_boxes, labels=box_labels, color='lime', width=2)L51
- padded_pred = pxtf.vision.bboxes_pad(pred_boxes, 'xyxy', x=4, y=4)L58
- lane = band_lane(band)L61
- tag = callsign_tag(callsign, harbor, band)L62
- words = transcript_word_count(transcript)L63
- dur_bucket = duration_bucket(duration_s)L64
- B-tree index on harborL67
- B-tree index on bandL68
- B-tree index on laneL69
No HTTP routes: a pipeline you insert into and query from Python.
Run it
Needs uv.
terminal
git clone https://github.com/pierrebrunelle/pixeltable-harbor-signalscd pixeltable-harbor-signalsuv syncuv run pxt schema update app.py harbor
Related apps
- Research Agent MemoryDurable, searchable long-term memory for an AI research assistant: per-user semantic recall, retrieval_udf lookups, tool calling and memory consolidation with custom aggregatesShares: B-tree indexes, Images, video and audio, UDFs
- Apiary AdvisorRAG + tool-calling beekeeping advisor: custom embedding index, table-as-UDF agent pipeline, expr_udf mite mathShares: B-tree indexes, Views and iterators, UDFs
- Archery RangeMigrate archery-range scoring sessions from legacy JSON into Pixeltable, score with date-aware computed columns, and run as an incremental scheduled pipelineShares: B-tree indexes, UDFs