Skip to main content

Qdrant retrieval and the remaining DJ-analysis gap

The platform now has a first-class offline Rust analyzer and a separate Rust retrieval crate. MongoDB database prochain_aidj is authoritative. Qdrant is a rebuildable index of already computed embeddings; indexing and searching never decode audio or call an LLM.

Implemented pipeline

Symphonia → canonical 48 kHz stereo PCM → native DSP measurements

Rubato → 16 kHz mono

ONNX Runtime / YAMNet

voice head + music heads + mean embedding

versioned Mongo report and two-second timeline

Qdrant payload filters + cosine retrieval (30)

current Mongo identity/review revalidation

similarity/tempo ordering → at most 10

compact DJ summaries, ready for an agent

prochain-music-retrieval uses Qdrant's HTTP API through the existing Rust reqwest dependency. The tested cluster runs Qdrant 1.12.4. No Python runs inside production analysis or retrieval. The optional Python scripts remain offline benchmark tools.

The dedicated collection is prochain_aidj_tracks_v1, with 1,024-dimensional cosine vectors and UUID track IDs. Payload indexes cover embedding space, review status, track kind, BPM, energy and exact key. This follows Qdrant's filtered retrieval and payload indexing APIs.

Embedding space includes model hash, analyzer code hash, sample rates, pooling, model identity and dimensions. Different spaces are never compared even if their vector dimensions match. The code hash is deliberately conservative: unrelated analyzer changes can require a new compatible cohort. A future separately versioned embedding extractor can reduce unnecessary separation. Structure-only refinements retain the original embedding provenance.

Commands and API

Set BOOTH_QDRANT_URL and optional BOOTH_QDRANT_API_KEY_FILE. The collection override must start with prochain_aidj_; credentials are not accepted in URLs. HTTP calls have timeouts, redirects are disabled and authentication is not logged.

analyzerd index-init
analyzerd index-tracks TRACK_ID...
analyzerd similar CURRENT_TRACK_ID filters.json

Example filters.json:

{
"bpm": 128,
"energy_min": 0.7,
"energy_max": 0.95,
"diagnostic_unreviewed": false
}

An optional key is an exact native key string such as A minor, not a Camelot-neighbour filter. Tempo filtering permits a target/source ratio of 0.85–1.15. The authenticated POST /api/v1/library/{id}/similar accepts the same body. The old shortlist BPM remains a separate tempo-only diagnostic. The library UI has not yet gained a similarity-results panel.

Indexing accepts explicit batches of 1–1,000 IDs and upserts the current report by stable track UUID. It returns failures separately; the CLI fails a partially rejected batch. Source read failures do not erase existing index entries. Re-index after native review, changed PCM or a new musical report. There is no continuous Mongo change-stream synchronizer yet.

Every returned hit is reloaded from Mongo and checked against an identity/review/feature snapshot hash, the embedding space and current filter eligibility. Deleted, missing, stale or newly unreviewed tracks are dropped. The snapshot hash avoids rejecting otherwise identical payloads because of JSON floating-point round trips. Compact context must still refer to the checked report. Stale entries can reduce results below ten; the query does not scan beyond its bounded 30 hits to fill the list.

Production retrieval requires reviewed tracks. diagnostic_unreviewed: true is an explicit research mode; its output is marked diagnostic. The 13 benchmark embeddings were indexed, but those recordings remain unreviewed, so a reviewed-only query correctly returns no benchmark candidates.

Ordering is an explicit heuristic: 0.75 × max(cosine, 0) + 0.25 × tempo_fit. It is not a DJ compatibility score. Responses include similarity and required tempo adjustment, and set recommendation_ready: false. No raw vector or frame array is passed into the compact candidate response.

Distance from the intended AI DJ

CapabilityCurrent implementationRemaining gate
Native measurementsDecoding/resampling, spectrum, band energy, flux, RMS/crest, LUFS/true peak, chroma/key, onset/tempo estimatesValidate difficult recordings; confidence calibration and metrical ambiguity
Beat/phrase timingProvisional beat grid, local tempo estimates, regular four-bar phrase candidatesReliable downbeats, meter, variable-tempo alignment and actual phrase boundaries
Musical structureIntro/groove/build/breakdown/outro and entry/drop hypothesesHuman-labelled section boundaries; verified verse/pre-chorus/chorus/bridge
VocalsMusic-specific two-second score timeline and benchmark evaluatorCalibrated presence, trustworthy vocal-free windows, separate dominance model
InstrumentsGeneric AudioSet group scoresMusic-specific instrument evidence or stems; bass-band power is not a bass stem
Genre/mood/danceabilityOptional research headsLibrary validation and suitable model licensing before wider deployment
RetrievalVersioned embeddings, filtered Qdrant search, Mongo revalidation, bounded summariesBetter music embeddings and learned/validated pair compatibility
Agent decisionExisting agent infrastructure and compact analysis contextWire this retrieval path into the live next-track planner and evaluate choices
TransitionsExisting reusable recipes/attempts/reviews and virtual controlsCompile region-aware plans into beat-aligned controls; measure rendered audio and human preference
AI-vs-AI / AI-vs-humanFour-player/mixer prototype and earlier LAN/audio testsReliable end-to-end autonomous sessions; physical audio routing, timing and ownership validation

We have the data and retrieval foundation. We cannot yet reliably answer “mix this pair over the next 32 bars without vocal collision and land the drop.” The next work is: annotate standalone benchmark passages; improve and measure beat/downbeat and vocal timing; score specific outgoing/incoming regions; render and rank reusable transition scripts; then connect that validated loop to the live agents. Qdrant improves candidate retrieval, not the accuracy of the measurements it filters.