playlist-data-engine 1.5.8 → 1.5.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -40781,76 +40781,91 @@ class I0 {
|
|
|
40781
40781
|
/**
|
|
40782
40782
|
* Analyzes audio to extract genre, mood, and vibe data.
|
|
40783
40783
|
*/
|
|
40784
|
+
/**
|
|
40785
|
+
* Analyze a track. Accepts either:
|
|
40786
|
+
* - a `string` URL: the engine fetches + decodes + downsamples via Web
|
|
40787
|
+
* Audio (main-thread path). Backward-compatible with all existing callers.
|
|
40788
|
+
* - an `{ audioSignal, sampleRate? }` object: caller has already fetched,
|
|
40789
|
+
* decoded, AND downsampled to mono PCM. Used when running inside a Web
|
|
40790
|
+
* Worker (no Web Audio available there). `sampleRate` defaults to 16000
|
|
40791
|
+
* (essentia.js's required rate); the engine skips fetch + decode +
|
|
40792
|
+
* downsample and runs only the slice + ML inference on the provided signal.
|
|
40793
|
+
*/
|
|
40784
40794
|
async analyze(e) {
|
|
40785
40795
|
try {
|
|
40786
40796
|
await this.initializeEssentia();
|
|
40787
|
-
|
|
40788
|
-
|
|
40789
|
-
|
|
40790
|
-
|
|
40797
|
+
let t;
|
|
40798
|
+
if (typeof e == "string") {
|
|
40799
|
+
const l = await (await fetch(e)).arrayBuffer(), u = typeof self < "u" ? self : typeof globalThis < "u" ? globalThis : {}, d = u.AudioContext || u.webkitAudioContext, h = u.OfflineAudioContext || u.webkitOfflineAudioContext, m = d ? new d() : h ? new h(1, 44100, 44100) : (() => {
|
|
40800
|
+
throw new Error("No Web Audio API available in this context");
|
|
40801
|
+
})(), f = await m.decodeAudioData(l);
|
|
40802
|
+
t = await this.extractor.downsampleAudioBuffer(f, m.sampleRate);
|
|
40803
|
+
} else
|
|
40804
|
+
t = e.audioSignal;
|
|
40805
|
+
const i = this.sliceAudioSignal(t, 16e3), n = Math.max(0, Math.floor((i.length - 512) / 256) + 1), a = [], r = {
|
|
40791
40806
|
genres: [],
|
|
40792
40807
|
moods: [],
|
|
40793
40808
|
mood_tags: [],
|
|
40794
40809
|
vibe_metrics: {}
|
|
40795
40810
|
};
|
|
40796
40811
|
if (this.options.models?.genre) {
|
|
40797
|
-
const
|
|
40798
|
-
let
|
|
40799
|
-
Ai(
|
|
40800
|
-
const
|
|
40801
|
-
|
|
40802
|
-
d,
|
|
40812
|
+
const o = this.options.models.genre, c = Ai(o) ? o.classifier : o.modelUrl;
|
|
40813
|
+
let l;
|
|
40814
|
+
Ai(o) && o.classifierType ? l = o.classifierType : fr(o) && o.genreType ? l = o.genreType : l = dv(c);
|
|
40815
|
+
const u = hv(l);
|
|
40816
|
+
r.genres = await this.runModelPrediction(
|
|
40803
40817
|
o,
|
|
40804
|
-
|
|
40805
|
-
|
|
40818
|
+
i,
|
|
40819
|
+
u
|
|
40820
|
+
), r.primary_genre = r.genres.length > 0 ? r.genres[0].name : "Unknown", a.push(Ot(o));
|
|
40806
40821
|
}
|
|
40807
40822
|
if (this.options.models?.mood) {
|
|
40808
|
-
const
|
|
40809
|
-
|
|
40810
|
-
d,
|
|
40823
|
+
const o = this.options.models.mood, c = fr(o) ? rv : ov;
|
|
40824
|
+
r.moods = await this.runModelPrediction(
|
|
40811
40825
|
o,
|
|
40812
|
-
|
|
40813
|
-
|
|
40826
|
+
i,
|
|
40827
|
+
c
|
|
40828
|
+
), r.mood_tags = r.moods.slice(0, 3).map((l) => l.name), a.push(Ot(o));
|
|
40814
40829
|
}
|
|
40815
40830
|
if (this.options.models?.danceability) {
|
|
40816
|
-
const
|
|
40817
|
-
d,
|
|
40831
|
+
const o = this.options.models.danceability, l = (await this.runModelPrediction(
|
|
40818
40832
|
o,
|
|
40833
|
+
i,
|
|
40819
40834
|
cv
|
|
40820
|
-
)).find((
|
|
40821
|
-
|
|
40835
|
+
)).find((u) => u.name === "danceable");
|
|
40836
|
+
r.vibe_metrics.danceability = l?.confidence ?? 0, a.push(Ot(o));
|
|
40822
40837
|
}
|
|
40823
40838
|
if (this.options.models?.voice) {
|
|
40824
|
-
const
|
|
40825
|
-
d,
|
|
40839
|
+
const o = this.options.models.voice, l = (await this.runModelPrediction(
|
|
40826
40840
|
o,
|
|
40841
|
+
i,
|
|
40827
40842
|
lv
|
|
40828
|
-
)).find((
|
|
40829
|
-
|
|
40843
|
+
)).find((u) => u.name === "instrumental");
|
|
40844
|
+
r.vibe_metrics.instrumental_probability = l?.confidence ?? 0, a.push(Ot(o));
|
|
40830
40845
|
}
|
|
40831
40846
|
if (this.options.models?.acoustic) {
|
|
40832
|
-
const
|
|
40833
|
-
d,
|
|
40847
|
+
const o = this.options.models.acoustic, l = (await this.runModelPrediction(
|
|
40834
40848
|
o,
|
|
40849
|
+
i,
|
|
40835
40850
|
uv
|
|
40836
|
-
)).find((
|
|
40837
|
-
|
|
40851
|
+
)).find((u) => u.name === "electronic");
|
|
40852
|
+
r.vibe_metrics.electronic_probability = l?.confidence ?? 0, a.push(Ot(o));
|
|
40838
40853
|
}
|
|
40839
|
-
if (
|
|
40840
|
-
const
|
|
40841
|
-
|
|
40854
|
+
if (r.moods) {
|
|
40855
|
+
const o = r.moods.find((l) => l.name === "energetic" || l.name === "upbeat" || l.name === "epic"), c = r.moods.find((l) => l.name === "happy" || l.name === "positive" || l.name === "uplifting");
|
|
40856
|
+
o && (r.vibe_metrics.energy = o.confidence), c && (r.vibe_metrics.valence = c.confidence);
|
|
40842
40857
|
}
|
|
40843
40858
|
return {
|
|
40844
|
-
genres:
|
|
40845
|
-
moods:
|
|
40846
|
-
primary_genre:
|
|
40847
|
-
mood_tags:
|
|
40848
|
-
vibe_metrics:
|
|
40859
|
+
genres: r.genres || [],
|
|
40860
|
+
moods: r.moods || [],
|
|
40861
|
+
primary_genre: r.primary_genre || "Unknown",
|
|
40862
|
+
mood_tags: r.mood_tags || [],
|
|
40863
|
+
vibe_metrics: r.vibe_metrics,
|
|
40849
40864
|
analysis_metadata: {
|
|
40850
|
-
models_used:
|
|
40851
|
-
model_used:
|
|
40852
|
-
frames_analyzed:
|
|
40853
|
-
duration_analyzed:
|
|
40865
|
+
models_used: a,
|
|
40866
|
+
model_used: a.length > 0 ? a[0] : void 0,
|
|
40867
|
+
frames_analyzed: n,
|
|
40868
|
+
duration_analyzed: i.length / 16e3,
|
|
40854
40869
|
analyzed_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
40855
40870
|
}
|
|
40856
40871
|
};
|
package/package.json
CHANGED