foley.index
foley INDEX stage — make every sound findable by keyword and meaning.
The retrieval keystone (report 04 / report 10 §5): a CLAP joint embedding space,
a hybrid vector+keyword index with Reciprocal Rank Fusion, a dol-native
SoundLibrary façade composing the byte/metadata stores with the two
indexes, and the UCS/AudioSet taxonomy resolver — all behind small, swappable
protocols with zero-config defaults.
Everything heavy (torch/transformers/lancedb/sqlite_vec) is
lazy-imported inside the method that needs it, so import foley.index costs
only the stdlib; install the capability you use via the matching extra
(foley[clap], foley[index], foley[index-sqlite]).
- class foley.index.Captioner(*args, **kwargs)[source]
Produce one natural-language sentence describing a clip (report 03).
The caption feeds the BM25 keyword index and human display. Default is a dedicated AAC model (EnCLAP); Qwen2-Audio is a richer promptable upgrade. Both are
foley[caption]adapters plugged in behind this protocol.
- class foley.index.CatIdResolution(catid: str | None = None, category: str | None = None, subcategory: str | None = None, source: str | None = None, confidence: float = 0.0, matched_terms: list[str] = <factory>)[source]
The result of resolving free tags/caption/labels to a UCS CatID.
catidfeedsucs_categoryandsubcategoryfeedsucs_subcategoryon ingest, anducs_catidon the query side.
- class foley.index.ClapEmbedder(model_id: str = 'laion/larger_clap_general', *, device=None)[source]
LAION-CLAP text<->audio embedder (the default retrieval engine).
Returns L2-normalized
float32embeddings so a plain inner product is cosine similarity.embed_textalways returns a 2-D(n, dim)array;embed_audioreturns a 1-D(dim,)array for one clip.- model_id
The HF checkpoint id.
- dim
The embedding dimensionality.
- property device: str
The resolved torch device string (
'cuda'/'cpu').
- property dim: int
The embedding dimensionality (512 for the default; resolved for others).
For a non-default checkpoint this fetches only the model’s
config.json(viaAutoConfig) — never the ~1.7 GB weights — so building an index for it does not force a model download. Falls back to the loaded model’s config if the standalone config lacksprojection_dim.
- embed_audio(wav: ndarray, sr: int) ndarray[source]
Embed one audio clip ->
(dim,)L2-normalized.The clip is down-mixed to mono and resampled to 48 kHz (what CLAP expects) via
foley.audiobefore embedding.- Parameters:
wav – A working-array clip (
float32; mono or multichannel).sr – The clip’s sample rate in Hz.
- class foley.index.ClapZeroShotTagger(*, embedder=None, labels: Sequence[str] | None = None, prompt: str = 'this is a sound of {label}', threshold: float = 0.0)[source]
Zero-shot tagger: score a clip against a label set via CLAP cosine.
Reuses a
ClapEmbedder(the same model the Index uses), so the audio is embedded in the same joint space as the label prompts and no extra weights load. The default label set is the UCS subcategory names (foley’s own vocabulary), so tags land in-taxonomy.- property embedder
The CLAP embedder (injected or the process-wide default).
- property labels: list[str]
natural UCS
category subcategoryphrases).Natural multi-word phrases (
"weather rain","glass break") are far better CLAP prompts — and better BM25 tags / taxonomy-resolver input — than bare abstract subcategory words ("Break","Buzz"), which are a known zero-shot artifact (anomalously close to everything). Absolute tag-quality calibration (thresholds, label curation) is an eval-harness concern (#10).- Type:
The label vocabulary (default
- tag(wav: ndarray, sr: int, *, taxonomy: str = 'custom', top_k: int = 10) list[tuple[str, float]][source]
Return the top-
k(label, cosine)tags for the clip, best first.
- tag_vector(audio_vec: ndarray, *, top_k: int = 10) list[tuple[str, float]][source]
Score a precomputed (L2-normalized) audio vector against the labels.
The efficiency seam (report 03 Part 2): the Index already embeds every sound with this model, so on ingest the retrieval vector is reused here — no second CLAP forward pass.
- class foley.index.Embedder(*args, **kwargs)[source]
A joint text<->audio embedding space (CLAP by default).
One space serves both text->audio search (
embed_texta query) and audio<->audio similarity (embed_audioa clip). Implementations MUST return L2-normalizedfloat32arrays so a plain inner product is cosine similarity, and MUST stampmodel_id/dimso mixed-model libraries stay coherent (eachSoundRecordrecords theembedding_model/embedding_dimit was indexed under).- model_id
The checkpoint id (e.g.
'laion/larger_clap_general').- Type:
str
- dim
The embedding dimensionality (e.g.
512).- Type:
int
- class foley.index.FusedHit(id: str, rrf_score: float | None = None, clap_score: float | None = None, bm25_score: float | None = None)[source]
One fused retrieval hit: an id plus the scores that produced it.
The raw component scores are carried through (not just the fused rank score) so the façade can stamp them onto a
Candidate(clap_score/bm25_score/rrf_score) for display and debugging.- id
The sound id.
- Type:
str
- rrf_score
The fused RRF score (
Nonefor a pure-vector search).- Type:
float | None
- clap_score
Cosine similarity from the vector ranker (
Noneif the id appeared only in the keyword list).- Type:
float | None
- bm25_score
BM25 score from the keyword ranker (
Noneif the id appeared only in the vector list).- Type:
float | None
- class foley.index.IngestReport(root: str, results: list[IngestResult] = <factory>)[source]
The rolled-up outcome of a folder ingest (JSON-serializable).
- property errored: list[IngestResult]
Results that raised during ingest.
- property ingested: list[IngestResult]
Results that were added to the library (
passorwarn).
- property quarantined: list[IngestResult]
Results rejected by the QC gate.
- record(result: IngestResult) None[source]
Append one
IngestResult.
- property rights_blocked: list[IngestResult]
Results refused by the fail-closed AI-training/license rights gate.
- property skipped: list[IngestResult]
Results skipped as content-addressed duplicates.
- class foley.index.IngestResult(id: str, status: str, record: SoundRecord | None = None, qc: dict | None = None, notes: list = <factory>, error: str | None = None)[source]
The outcome of ingesting one clip.
status:'pass'/'warn'(ingested),'quarantined'(QC-rejected, not added),'skipped_dup'(content already in the library),'rights_blocked'(license forbids AI training / embedding, refused before embed — seeingest_one()),'skipped_license'(dropped by a bootstrap commercial-use / fail-closed license filter), or'error'.recordis present only when the clip was ingested.
- class foley.index.KeywordIndex(*args, **kwargs)[source]
BM25 / full-text index over each sound’s tags + caption.
The default is LanceDB’s Tantivy FTS (report 04 §3.4); SQLite FTS5 is the single-file fallback. Same
wherepush-down contract asVectorIndex.- bm25(query: str, k: int, *, where: dict | None = None) list[tuple[str, float]][source]
Return the top-
kBM25 matches forquery, best first.- Parameters:
query – A natural-language / keyword query.
k – Number of matches to return.
where – Optional metadata predicates for push-down filtering.
- Returns:
[(id, bm25_score), ...]in descending-score order.
- class foley.index.LanceIndex(*, uri, dim: int, table_name: str = 'sounds')[source]
LanceDB-backed index: one table with a vector column + a native FTS index.
Writes are staged per id and flushed on the next read (or explicit
commit()), so a sound’s vector (upsert()) and text (index()) — which arrive as two separate protocol calls — are merged into one row and written as an efficient batch. Vector search is exact cosine (no ANN index is built at this tier; adding one is a scale-time optimization). Fusion is done byfoley.index.search, not by LanceDB’s native hybrid reranker, so ranking matches every other backend.One-table constraint: the vector column is mandatory, so every indexed row needs a vector.
SoundLibrary.addenforces this (it raises without an embedding source), so the façade path is safe; a bareindex()with no matchingupsert()stages a text-only row that stays unflushed (never keyword-searchable). For a keyword-only library with no embeddings, useMemoryIndexorSqliteVecIndex(independent vector/text tables).- bm25(query: str, k: int, *, where: dict | None = None) list[tuple[str, float]][source]
Native full-text (BM25) search; returns
[(id, score), ...].
- property db
The lazily-connected LanceDB database handle.
- get_vector(id: str) ndarray | None[source]
Return the stored vector for
id(staged or persisted), elseNone.
- index(id: str, text: str, meta: dict) None[source]
Stage the searchable text for
id(flushed on the next read/commit).
- knn(vector: ndarray, k: int, *, where: dict | None = None) list[tuple[str, float]][source]
Exact cosine KNN; returns
[(id, cosine_similarity), ...].
- property table
The lazily-opened (or created-empty) LanceDB table.
- class foley.index.MemoryIndex(*, dim: int | None = None)[source]
In-memory vector + keyword index (numpy cosine + compact BM25).
Not persistent — everything lives in dicts, lost on process exit. It exists so the full hybrid + façade path is testable and usable with only
numpy(no LanceDB, no torch), and as a genuine zero-config tier for small or ephemeral libraries. The vector and text stores are independent dicts, soupsert()andindex()never contend.- bm25(query: str, k: int, *, where: dict | None = None) list[tuple[str, float]][source]
Return the top-
kBM25 matches forquery(best first).A compact Okapi BM25 (
k1=1.5,b=0.75) recomputed per query — O(N) in the corpus size, which is fine for the in-memory tier’s scale.
- index(id: str, text: str, meta: dict) None[source]
Insert or replace the searchable text (and light metadata) for
id.
- class foley.index.PannsTagger(*, device: str = 'cpu', threshold: float = 0.1)[source]
PANNs CNN14 supervised tagger over the 527 AudioSet classes (
foley[tag]).The checkpoint auto-downloads to
~/panns_data(~327 MB) on the firsttag(). PANNs expects 32 kHz mono; the clip is resampled viafoley.audio.to_working().
- class foley.index.SoundLibrary(*, sounds=None, meta=None, vindex=None, kindex=None, embedder=None, data_dir=None, candidate_k: int = 50, rrf_k: int = 60)[source]
A searchable, license-aware library of sounds (the foley INDEX façade).
Read it as a
MappingofSoundRecord`s; search it with :meth:`search(text) /search_clip()(a reference clip) /similar()(audio<->audio by id); browse it withfilter(); grow it withadd().- add(record: SoundRecord, *, data: bytes | None = None, vector: ndarray | None = None) SoundRecord[source]
Store a sound and index it (the ingest write path).
Persists bytes via
store_sound()(honouring the by-value/by-reference license gate), upserts the CLAP vector into the vector index, and indexescaption``+``tagsinto the keyword index.A sound is retrieval-first, so it MUST carry an embedding: supply either
data(bytes to embed — note a by-reference sound is embedded from its transient bytes even though they are not cached) or a precomputedvector. Adding with neither raises, rather than silently indexing a vectorless row (which the single-tableLanceIndexcannot persist, producing backend-dependent search results).- Parameters:
record – The record to add (mutated by
store_soundwith resolved storage fields, and stamped with the embedding model/dim).data – The archive bytes (required for by-value storage; also the source for computing
vectorwhen it is not supplied).vector – A precomputed CLAP embedding; when omitted and
datais given, it is computed via the library’s embedder.
- Returns:
The same (persisted, indexed)
record.- Raises:
ValueError – If neither
datanorvectoris provided (no way to obtain an embedding).
- array(sound_id: str, *, sr: int | None = None, mono: bool = True) ndarray[source]
Decode a sound to a working array (
float32).- Parameters:
sound_id – The record id.
sr – Target sample rate (default: the working rate, 48 kHz).
mono – Down-mix to mono (default
True).
- Returns:
The decoded working array.
- audio(sound_id: str) bytes[source]
Return a sound’s archive bytes (by-value from the store, or from a local by-reference path).
- Parameters:
sound_id – The record id.
- Returns:
The raw archive bytes.
- Raises:
LookupError – If the bytes are neither cached (by-value) nor readable from a local
uri— a remote by-reference sound needs its source adapter (subtask #5) to fetch.
- property data_dir: Path
The data root for default stores/index.
- property embedder
The text<->audio embedder (CLAP by default).
- filter(**facets) list[SoundRecord][source]
Browse the library by metadata facets (no ranking).
Accepts the same facet keywords as
search()’s filters (commercial_ok,ucs_category,min_snr,duration_range) plus anyrecord_attr=valueequality predicate.
- property kindex
The keyword index.
- property meta
The metadata store (
id -> SoundRecord).
- search(query: str, *, k: int = 10, filters: dict | None = None, commercial_ok: bool | None = None, ucs_category: str | None = None, min_snr: float | None = None, duration_range: tuple[float, float] | None = None, rerank: bool = False) list[Candidate][source]
Hybrid (CLAP vector ⊕ BM25) search for a text query.
- Parameters:
query – The natural-language query.
k – Number of results to return.
filters – Extra
{record_attr: value}equality predicates.commercial_ok – If
True, keep only commercially-usable sounds.ucs_category – Keep only sounds with this UCS CatID.
min_snr – Keep only sounds whose QC
snr_dbis at least this.duration_range – Keep only sounds whose
duration_sis in(min, max).rerank – Re-order the shortlist by direct query<->audio cosine (fills the CLAP score for keyword-only hits).
- Returns:
Up to
k:class:`~foley.base.Candidate`s, best first.
- search_clip(clip: AudioSource, *, sr: int | None = None, k: int = 10) list[Candidate][source]
Search by a reference audio clip (audio<->audio via CLAP).
- Parameters:
clip – A working array, or a path/bytes/file decodable by
foley.audio.load().sr – Sample rate when
clipis already a working array.k – Number of results.
- Returns:
Up to
k:class:`~foley.base.Candidate`s, most-similar first.
- similar(sound_id: str, *, k: int = 10) list[Candidate][source]
Return the
ksounds most similar tosound_id(audio<->audio).Uses the stored vector (no re-decoding); the query sound itself is excluded from the results.
- property sounds
The content-addressed byte store.
- property vindex
The vector index.
- class foley.index.SqliteVecIndex(*, path, dim: int)[source]
Single-file index: sqlite-vec
vec0KNN + stdlib FTS5 keyword search.The whole index is one SQLite file behind two virtual tables (independent, so
upsert()andindex()never contend). Requires an interpreter whose ``sqlite3`` permits loadable extensions — probe withsqlite_vec_loadable()before constructing; the constructor raises a clear error otherwise.- bm25(query: str, k: int, *, where: dict | None = None) list[tuple[str, float]][source]
FTS5 BM25 search; returns
[(id, score), ...]best-first.FTS5’s
rankis more-negative-is-better; it is negated so the returned score is larger-is-better (consistent with the other backends).
- index(id: str, text: str, meta: dict) None[source]
Insert or replace the searchable text for
idin the FTS5 table.
- class foley.index.Tagger(*args, **kwargs)[source]
Map a clip to
(label, score)pairs against a label vocabulary.Used on ingest to auto-fill
SoundRecord.audioset_labels(supervised) andtags(zero-shot). The default supervised tagger is PANNs CNN14 over AudioSet; the default zero-shot tagger scores a clip against a custom/UCS label set via CLAP (report 03). BEATs/AST are drop-in upgrades. Consumes the working array (float32, any sr — the impl resamples to its model’s rate).
- class foley.index.VectorIndex(*args, **kwargs)[source]
Approximate-nearest-neighbour store over embedding vectors.
The default is LanceDB (report 04 §2); Qdrant/pgvector/sqlite-vec bind the same protocol behind the scenes.
whereis an optional metadata push-down the façade may pass; a backend that cannot push filters down MAY ignore it (the façade over-fetches and post-filters to stay correct either way).- get_vector(id: str) ndarray | None[source]
Return the stored vector for
id(orNoneif absent).Needed by
SoundLibrary.similar(fetch a sound’s own vector, then runknn()) and by the optional CLAP rerank (score keyword-only hits).
- knn(vector: ndarray, k: int, *, where: dict | None = None) list[tuple[str, float]][source]
Return the
knearest ids tovector, most-similar first.- Parameters:
vector – A
(dim,)query vector (already L2-normalized).k – Number of neighbours to return.
where – Optional metadata predicates for push-down filtering.
- Returns:
[(id, cosine_similarity), ...]in descending-similarity order.
- foley.index.default_embedder() ClapEmbedder[source]
Return a process-wide default
ClapEmbedder(loaded once, reused).Cached so repeated
foley.search()calls share a single loaded model.
- foley.index.default_index(*, data_dir, dim: int)[source]
Build the best available persistent index for a library.
Degradation ladder: LanceDB (
foley[index]) → sqlite-vec (foley[index-sqlite], if loadable) → an informative error. The non-persistentMemoryIndexis never chosen automatically (a library must survive restarts); inject it explicitly for tests/ephemeral use.- Parameters:
data_dir – The library data root (a
pathlib.Path-like).dim – The embedding dimensionality from the active embedder.
- Returns:
A ready index object (both
VectorIndexandKeywordIndex).- Raises:
RuntimeError – If no persistent backend is installed/usable.
- foley.index.default_library() SoundLibrary[source]
The process-wide default library (local stores + CLAP + best index).
- foley.index.default_tagger() PannsTagger[source]
The default supervised tagger (PANNs CNN14;
foley[tag]).
- foley.index.default_zeroshot_tagger(embedder=None) ClapZeroShotTagger[source]
The default zero-shot tagger (CLAP vs UCS subcategories;
foley[clap]).Cached per embedder so the tagger is bound to the SAME embedder that produced the audio vector it scores — otherwise (report seam) the cosine would cross two unrelated embedding spaces.
embedder=Noneuses the process-wide default embedder.
- foley.index.fuse_hits(vector_hits: list[tuple[str, float]], keyword_hits: list[tuple[str, float]], *, k: int, rrf_k: int = 60) list[FusedHit][source]
RRF-fuse a vector ranker’s hits with a keyword ranker’s hits.
- foley.index.hybrid_search(query: str, *, embedder: Embedder, vindex: VectorIndex, kindex: KeywordIndex, k: int = 10, candidate_k: int = 50, rrf_k: int = 60, where: dict | None = None) list[FusedHit][source]
Embed
query, run the vector + keyword rankers, and RRF-fuse them.- Parameters:
query – The natural-language query.
embedder – Text<->audio embedder (its
embed_textproduces the query vector).vindex – The vector index (CLAP KNN).
kindex – The keyword index (BM25).
k – Number of fused results to return.
candidate_k – Shortlist depth pulled from each ranker before fusion.
rrf_k – The RRF damping constant.
where – Optional metadata push-down passed to both rankers.
- Returns:
The top-
kfused :class:`FusedHit`s.
- foley.index.ingest_folder(path, *, library=None, recursive: bool = True, exts: tuple[str, ...] = ('.wav', '.flac', '.aiff', '.aif', '.ogg', '.mp3', '.opus', '.m4a'), on_error: str = 'collect', **ingest_one_kw) IngestReport[source]
Ingest every audio file under
pathand return anIngestReport.- Parameters:
path – A folder (walked) or a single audio file.
library – Target library (default: the process-wide default).
recursive – Recurse into sub-folders.
exts – Audio extensions to ingest.
on_error –
'collect'records per-file errors and continues;'raise're-raises the first error.**ingest_one_kw – Forwarded to
ingest_one()(license, taggers, QC flags, …).
- Returns:
An
IngestReport(with.summary()counts and per-file results).
- foley.index.ingest_one(src: AudioSource, *, library=None, sound_id: str | None = None, source_uri: str | None = None, license: LicenseRecord | None = None, tagger=None, zeroshot_tagger=None, captioner=None, do_qc: bool = True, min_status: QCStatus = QCStatus.warn, do_supervised: bool = True, do_zeroshot: bool = True, do_caption: bool = True, thresholds: QCThresholds = QCThresholds(clip_full_scale=0.999, clip_min_run=3, clip_reject_ratio=0.0001, clip_reject_run=10, true_peak_max_dbtp=-1.0, true_peak_oversample=4, dc_offset_fail=0.01, dc_offset_warn=0.001, silence_rms_dbfs=-60.0, snr_clean_db=20.0, snr_quiet_percentile=10.0, snr_frame_s=0.025, snr_hop_s=0.01, edge_rel_peak_dbfs=-40.0, edge_fade_s=0.01, lufs_gate_floor=-70.0, lufs_outlier_lu=6.0, duration_min_s=0.1, deliver_min_sample_rate=44100), store: bool = True, allow_ai_training_forbidden: bool = False, seed_tags: list | None = None) IngestResult[source]
Ingest one clip into
libraryand return anIngestResult.Pipeline: probe + decode-once -> content-address dedup -> QC gate -> embed (once) -> supervised + zero-shot tags -> caption -> resolve UCS -> assemble
SoundRecord->SoundLibrary.add().- Parameters:
src – A path,
bytes, or file-like audio source.library – Target
SoundLibrary(default: the process-wide default library).sound_id – Optional canonical id override. Defaults to
None→ the content-hash of the decoded PCM (the local-ingest identity, used as the recordidand dedup key). A live source adapter passes a short, case-stable, source-native id (e.g.'freesound:12345') so dedup keys on the stable id rather than on re-fetched (lossy, byte-varying) preview bytes; when it does, the PCM hash is computed only for the (skipped) default and is not persisted. Separately,content_sha256records the hash of the stored FLAC archive bytes (set bystore_sound), which is a different byte source from this PCM hash.source_uri – Optional by-reference fetchable URI override. Defaults to
None→ the resolved local path whensrcis path-like. A live adapter passes the stable source page URL (e.g.'https://freesound.org/s/12345/') thatfoley.stores.store_sound()requires for a by-reference sound.license – Rights record (default: a user-owned, cacheable license).
tagger – Supervised
Tagger(default: PANNs viadefault_tagger()).zeroshot_tagger – Zero-shot tagger (default: CLAP via
default_zeroshot_tagger()).captioner – Optional
Captioner(default: none — the caption stage is off unless one is injected).do_qc – Run the Tier-0 QC gate.
min_status – Admission floor — a QC status worse than this is quarantined (default
warn: onlyfailclips are rejected).do_caption (do_supervised / do_zeroshot /) – Toggle each enrichment stage.
thresholds – QC thresholds.
store – If
False, assemble the record but do not add it to the library (probe/QC/enrich only).seed_tags – Optional caller-supplied tags (e.g. a corpus’s folder-path taxonomy) unioned into the record’s
tagsalongside the supervised/zero-shot tags — so they feed the BM25 keyword index.allow_ai_training_forbidden – The universal fail-closed rights gate. A sound whose license has
ai_training_ok=False(e.g. Sonniss, BBC RemArc) is refused with status'rights_blocked'before it is embedded or stored — CLAP-embedding-and-persisting is itself a form of AI training on the corpus. PassTrueto record explicit operator consent and admit it anyway (seefoley.bootstrap.bootstrap()’saccept_ai_restricted). Protects every ingest path, not just bootstrap.
- Returns:
An
IngestResult; itsrecordisNonewhen quarantined, a duplicate, or rights-blocked.
- foley.index.lancedb_available() bool[source]
True if
lancedbis importable (thefoley[index]extra is present).
- foley.index.parse_ucs_filename(filename, *, table: UcsTable | None = None) tuple[str | None, str | None][source]
Parse a UCS-conformant filename to
(ucs_category, ucs_subcategory).Fail-quiet: returns
(None, None)when the name is not UCS-conformant or its CatID token is unknown (so a wrong subcategory is never emitted).- Parameters:
filename – A path or filename (only the basename’s token 0 is used).
table – The UCS table to resolve against (defaults to
default_ucs_table()).
- foley.index.reciprocal_rank_fusion(ranked_id_lists: list[list[str]], *, k: int = 60) list[tuple[str, float]][source]
Fuse several ranked id lists into one, by reciprocal rank.
- Parameters:
ranked_id_lists – Each element is a list of ids in descending-relevance order (best first). Lists may overlap and may differ in length.
k – The RRF damping constant (default
RRF_K= 60).
- Returns:
[(id, fused_score), ...]sorted by fused score descending, ties broken byidascending (so the fusion is fully deterministic).
- foley.index.resolve_catid(*, tags: Sequence[str] = (), caption: str | None = None, audioset_labels: Sequence[str] = (), filename: str | None = None, table: UcsTable | None = None, audioset_map: AudioSetUcsMap | None = None) CatIdResolution[source]
Resolve inputs to a best UCS CatID by the staged precedence.
- Parameters:
tags – Free tags on the sound.
caption – Free-text caption/description.
audioset_labels – AudioSet MIDs or names (e.g. from PANNs).
filename – Optional UCS-style filename/path (its token-0 CatID wins if recognized).
table – UCS table (defaults to
default_ucs_table()).audioset_map – AudioSet->UCS map (defaults to
default_audioset_ucs_map()).
- Returns:
A
CatIdResolution(falsy when nothing resolved).
- foley.index.sqlite_vec_loadable() bool[source]
True if
sqlite_vecis installed AND this interpreter can load it.The macOS system / pyenv CPython builds frequently ship a
sqlite3without loadable-extension support (noenable_load_extension); on those, sqlite-vec cannot be used even when ``pip install``ed. This probes both.
- foley.index.vector_search(qvec: ndarray, *, vindex: VectorIndex, k: int = 10, where: dict | None = None) list[FusedHit][source]
Pure audio<->audio (or clip->library) vector search — no keyword leg.
Used by
SoundLibrary.similarand by searching with a reference clip. Hits keep their cosine similarity inclap_scoreand preserve the index’s own descending-similarity order (rrf_scoreis leftNone— there is no fusion).- Parameters:
qvec – An already-L2-normalized
(dim,)query vector.vindex – The vector index.
k – Number of neighbours to return.
where – Optional metadata push-down.
- Returns:
Up to
k:class:`FusedHit`s in descending-similarity order.