feat: MusicBrainz BPM enrichment + improved AI prompts

- lookupRecordingWithTags, extractBpmFromTags, extractTimeSigFromTags, getMusicBrainzRecording added to MB client
- upsertSong preserves existing BPM via COALESCE on conflict
- updateSongBpm helper for async enrichment writes
- AnalysisInput gains confirmedBpm / confirmedTimeSigNum fields
- POST /api/analyze fetches confirmed BPM from DB then MB tags before generation
- All three AI providers use confirmedBpm as authoritative and build enriched userMessage
- POST /api/tracks auto-registration now fetches tags via getMusicBrainzRecording
- Updated User-Agent and MB client fallback URL to Gitea

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
AJ Avezzano
2026-04-03 19:25:04 -04:00
parent 7ba4381bff
commit 5e686fc9c4
8 changed files with 223 additions and 26 deletions

View File

@@ -81,7 +81,9 @@ export const CTP_SCHEMA = {
export const SYSTEM_PROMPT = `\
You are an expert music producer and session musician assisting cover bands with click tracks.
You will receive automated BPM detection results for a song and must generate a CTP (Click Track Protocol) document describing the song's full tempo map.
You will receive information about a song and must generate a CTP (Click Track Protocol) document describing the song's full tempo map.
**Use your training knowledge of the specific song.** If you recognise the title and artist, use what you know about its actual structure: section names, bar counts, time signature, and any tempo changes (ritardando, double-time, key change with tempo shift). Your training data is a valuable source — do not ignore it in favour of generic guesses.
CTP rules:
- "version" must be "1.0"
@@ -96,10 +98,15 @@ CTP rules:
Guidelines for section layout:
- Use typical pop/rock section names: Intro, Verse, Pre-Chorus, Chorus, Bridge, Outro
- Estimate bar counts based on song duration and BPM (bars = duration_seconds × BPM / 60 / beats_per_bar)
- Most songs are 4/4; note any unusual meters if you know the song
- If you know the song has a tempo change (ritardando, double-time feel, key change with tempo shift), model it with a ramp or step section
- Most songs are 4/4; use 3/4, 6/8, etc. if you know the song uses that meter
- If the song has a tempo change (ritardando, double-time feel, key change with tempo shift), model it with a ramp or step section
- If unsure about sections, use a single constant-tempo section covering the whole song
- Use the detected BPM as the primary tempo — do not invent a different BPM unless the song is well-known to have a different tempo
**BPM authority:** When a "Confirmed BPM" is provided in the user message, it comes from
MusicBrainz community tags or a reliable reference — treat it as ground truth and use it
for all sections unless you know the song has a significant tempo change. Do not average it
with the detected BPM or discard it. When only a "Detected BPM" is provided, use it as a
starting point but apply your knowledge of the song if you recognise it.
The output is a draft for human review. Add reasonable section structure based on the song's typical arrangement.`;
@@ -118,9 +125,18 @@ export const anthropicProvider: AnalysisProvider = {
},
async generateCTP(input: AnalysisInput): Promise<CTPDocument> {
const { bpm, duration, title, artist, mbid, contributed_by } = input;
const { bpm, duration, title, artist, mbid, contributed_by, confirmedBpm, confirmedTimeSigNum } = input;
const model = process.env.ANTHROPIC_MODEL ?? "claude-opus-4-6";
const approxBars = Math.round((duration * bpm) / 60 / 4);
const effectiveBpm = confirmedBpm ?? bpm;
const approxBars = Math.round((duration * effectiveBpm) / 60 / 4);
const bpmLine = confirmedBpm
? `Confirmed BPM (from MusicBrainz community tags — treat as authoritative): ${confirmedBpm}\nDetected BPM (audio analysis): ${bpm}`
: `Detected BPM (audio analysis): ${bpm}`;
const timeSigHint = confirmedTimeSigNum
? `\nConfirmed time signature numerator: ${confirmedTimeSigNum}`
: "";
const userMessage = `\
Generate a CTP document for the following song:
@@ -128,11 +144,11 @@ Generate a CTP document for the following song:
Title: ${title ?? "Unknown Title"}
Artist: ${artist ?? "Unknown Artist"}
MusicBrainz ID: ${mbid ?? "unknown"}
Detected BPM: ${bpm}
${bpmLine}${timeSigHint}
Duration: ${duration.toFixed(1)} seconds (~${approxBars} bars at 4/4)
Contributed by: ${contributed_by}
Create a plausible section layout for this song. If this is a well-known song, use your knowledge of its actual arrangement. If not, use a sensible generic structure.`;
If you recognise this song, use your training knowledge of its actual arrangement — section names, bar counts, time signature, and any tempo changes. If you do not recognise it, use a sensible generic structure based on the BPM and duration above.`;
// thinking and output_config are not yet in the SDK type definitions;
// cast through the base param type to avoid type errors.