threenative-asset-mcp 0.9.1 → 0.9.3
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.
- package/README.md +88 -0
- package/dist/audio/fsutil.d.ts +7 -0
- package/dist/audio/fsutil.d.ts.map +1 -0
- package/dist/audio/fsutil.js +37 -0
- package/dist/audio/fsutil.js.map +1 -0
- package/dist/audio/generate.d.ts +95 -0
- package/dist/audio/generate.d.ts.map +1 -0
- package/dist/audio/generate.js +405 -0
- package/dist/audio/generate.js.map +1 -0
- package/dist/audio/inspect.d.ts +123 -0
- package/dist/audio/inspect.d.ts.map +1 -0
- package/dist/audio/inspect.js +464 -0
- package/dist/audio/inspect.js.map +1 -0
- package/dist/audio/semantic.d.ts +66 -0
- package/dist/audio/semantic.d.ts.map +1 -0
- package/dist/audio/semantic.js +197 -0
- package/dist/audio/semantic.js.map +1 -0
- package/dist/fab/api-download.d.ts.map +1 -1
- package/dist/fab/api-download.js +18 -2
- package/dist/fab/api-download.js.map +1 -1
- package/dist/fab/fabcli.d.ts.map +1 -1
- package/dist/fab/fabcli.js +8 -1
- package/dist/fab/fabcli.js.map +1 -1
- package/dist/fab/normalize.d.ts.map +1 -1
- package/dist/fab/normalize.js +4 -0
- package/dist/fab/normalize.js.map +1 -1
- package/dist/polyhaven/pack.d.ts +53 -0
- package/dist/polyhaven/pack.d.ts.map +1 -0
- package/dist/polyhaven/pack.js +104 -0
- package/dist/polyhaven/pack.js.map +1 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +33 -1
- package/dist/server.js.map +1 -1
- package/dist/tools/audio.d.ts +622 -0
- package/dist/tools/audio.d.ts.map +1 -1
- package/dist/tools/audio.js +217 -1
- package/dist/tools/audio.js.map +1 -1
- package/dist/tools/polyhaven-import.d.ts +58 -0
- package/dist/tools/polyhaven-import.d.ts.map +1 -0
- package/dist/tools/polyhaven-import.js +121 -0
- package/dist/tools/polyhaven-import.js.map +1 -0
- package/dist/unreal/importer.d.ts +6 -1
- package/dist/unreal/importer.d.ts.map +1 -1
- package/dist/unreal/importer.js +61 -20
- package/dist/unreal/importer.js.map +1 -1
- package/dist/unreal/materials.d.ts.map +1 -1
- package/dist/unreal/materials.js +39 -7
- package/dist/unreal/materials.js.map +1 -1
- package/dist/unreal/provision.d.ts +6 -1
- package/dist/unreal/provision.d.ts.map +1 -1
- package/dist/unreal/provision.js +23 -6
- package/dist/unreal/provision.js.map +1 -1
- package/dist/unreal/psa.d.ts.map +1 -1
- package/dist/unreal/psa.js +27 -9
- package/dist/unreal/psa.js.map +1 -1
- package/package.json +3 -1
- package/scripts/audio-semantic.py +168 -0
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { mkdir, open, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
4
|
+
import { join, resolve } from "node:path";
|
|
5
|
+
import { sha256Bytes, sha256File, sha256Json } from "./fsutil.js";
|
|
6
|
+
import { AudioInspector, } from "./inspect.js";
|
|
7
|
+
import { semanticAvailable } from "./semantic.js";
|
|
8
|
+
export class AudioGenerateError extends Error {
|
|
9
|
+
code;
|
|
10
|
+
retryable;
|
|
11
|
+
constructor(code, message, retryable = false) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.code = code;
|
|
14
|
+
this.retryable = retryable;
|
|
15
|
+
this.name = "AudioGenerateError";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const ENDPOINT = "https://api.elevenlabs.io/v1/sound-generation";
|
|
19
|
+
const MODEL_ID = "eleven_text_to_sound_v2";
|
|
20
|
+
const OUTPUT_FORMAT = "mp3_44100_128";
|
|
21
|
+
const PROVIDER_TERMS_URL = "https://help.elevenlabs.io/hc/en-us/articles/13313564601361-Can-I-publish-the-content-I-generate-on-the-platform";
|
|
22
|
+
export const GENERATE_LIMITS = {
|
|
23
|
+
/** Our policy cap, not a claimed provider maximum. */
|
|
24
|
+
maxPromptChars: 2_000,
|
|
25
|
+
minDurationSeconds: 0.5,
|
|
26
|
+
maxDurationSeconds: 30,
|
|
27
|
+
maxResponseBytes: 32 * 1024 * 1024,
|
|
28
|
+
timeoutMs: 120_000,
|
|
29
|
+
};
|
|
30
|
+
export class AudioGenerator {
|
|
31
|
+
fetch;
|
|
32
|
+
audioDir;
|
|
33
|
+
apiKeyOverride;
|
|
34
|
+
ffmpegPath;
|
|
35
|
+
inspector;
|
|
36
|
+
constructor(options = {}) {
|
|
37
|
+
this.fetch = options.fetch ?? globalThis.fetch;
|
|
38
|
+
this.audioDir = resolve(options.audioDir ??
|
|
39
|
+
process.env.AUDIO_DOWNLOAD_DIR ??
|
|
40
|
+
join(homedir(), "Downloads", "threenative-asset-mcp", "audio"));
|
|
41
|
+
this.apiKeyOverride = options.apiKey;
|
|
42
|
+
this.ffmpegPath = options.ffmpegPath ?? "ffmpeg";
|
|
43
|
+
this.inspector = new AudioInspector({ ...options, audioDir: this.audioDir });
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The key is the operator's, read from their environment at call time. It is never defaulted,
|
|
47
|
+
* never written to a receipt, never logged and never returned — a missing one is an error the
|
|
48
|
+
* agent is expected to relay to the person running the server.
|
|
49
|
+
*/
|
|
50
|
+
apiKey() {
|
|
51
|
+
const key = this.apiKeyOverride ?? process.env.ELEVENLABS_API_KEY;
|
|
52
|
+
if (!key || key.trim().length === 0) {
|
|
53
|
+
throw new AudioGenerateError("AUDIO_GENERATE_NO_CREDENTIALS", "ELEVENLABS_API_KEY is not set, so no audio can be generated and nothing was charged. " +
|
|
54
|
+
"Ask the user to set their own ElevenLabs API key in the MCP server's environment; " +
|
|
55
|
+
"the catalog and local inspection tools keep working without it.");
|
|
56
|
+
}
|
|
57
|
+
return key.trim();
|
|
58
|
+
}
|
|
59
|
+
async generate(request) {
|
|
60
|
+
const normalized = normalize(request);
|
|
61
|
+
const normalizedHash = sha256Json(normalized);
|
|
62
|
+
const dir = join(this.audioDir, "generated", request.requestId);
|
|
63
|
+
const receiptPath = join(dir, "receipt.json");
|
|
64
|
+
// Preflight: everything that could fail locally fails before a paid request is made.
|
|
65
|
+
this.apiKey();
|
|
66
|
+
await this.preflight(dir, request);
|
|
67
|
+
const existing = await readReceipt(receiptPath);
|
|
68
|
+
if (existing) {
|
|
69
|
+
if (existing.normalizedHash !== normalizedHash) {
|
|
70
|
+
throw new AudioGenerateError("AUDIO_GENERATE_REQUEST_CONFLICT", "That requestId was already used with different options. Use a new requestId for a new attempt.");
|
|
71
|
+
}
|
|
72
|
+
if (existing.state === "outcome_unknown") {
|
|
73
|
+
throw new AudioGenerateError("AUDIO_GENERATE_OUTCOME_UNKNOWN", "A previous submission of this requestId never reported its outcome; it may already have been " +
|
|
74
|
+
"billed, so this id will never be resubmitted. Use a new requestId to deliberately try again.");
|
|
75
|
+
}
|
|
76
|
+
// Everything from here is local work on bytes already paid for.
|
|
77
|
+
return await this.resume(existing, dir, receiptPath, request);
|
|
78
|
+
}
|
|
79
|
+
await this.reserve(dir, receiptPath, {
|
|
80
|
+
requestId: request.requestId,
|
|
81
|
+
state: "submitted",
|
|
82
|
+
normalizedHash,
|
|
83
|
+
normalized,
|
|
84
|
+
provider: "elevenlabs",
|
|
85
|
+
model: MODEL_ID,
|
|
86
|
+
commercialUse: "unverified",
|
|
87
|
+
providerTermsUrl: PROVIDER_TERMS_URL,
|
|
88
|
+
});
|
|
89
|
+
const response = await this.submit(normalized, receiptPath);
|
|
90
|
+
const receipt = {
|
|
91
|
+
requestId: request.requestId,
|
|
92
|
+
state: "source_saved",
|
|
93
|
+
normalizedHash,
|
|
94
|
+
normalized,
|
|
95
|
+
provider: "elevenlabs",
|
|
96
|
+
model: MODEL_ID,
|
|
97
|
+
generatedAt: new Date().toISOString(),
|
|
98
|
+
...(response.providerRequestId === undefined
|
|
99
|
+
? {}
|
|
100
|
+
: { providerRequestId: response.providerRequestId }),
|
|
101
|
+
...(response.billingUnits === undefined ? {} : { billingUnits: response.billingUnits }),
|
|
102
|
+
commercialUse: "unverified",
|
|
103
|
+
providerTermsUrl: PROVIDER_TERMS_URL,
|
|
104
|
+
};
|
|
105
|
+
const sourcePath = join(dir, "source.mp3");
|
|
106
|
+
await writeExclusive(sourcePath, response.body);
|
|
107
|
+
receipt.source = {
|
|
108
|
+
path: sourcePath,
|
|
109
|
+
sha256: sha256Bytes(response.body),
|
|
110
|
+
sizeBytes: response.body.byteLength,
|
|
111
|
+
};
|
|
112
|
+
await writeReceipt(receiptPath, receipt);
|
|
113
|
+
return await this.resume(receipt, dir, receiptPath, request);
|
|
114
|
+
}
|
|
115
|
+
/** Local-only completion: convert, inspect, finish. Never reaches the provider, never charges. */
|
|
116
|
+
async resume(receipt, dir, receiptPath, request) {
|
|
117
|
+
if (!receipt.source) {
|
|
118
|
+
// `submitted` with nothing saved yet means another caller is mid-flight with this id. That is
|
|
119
|
+
// a conflict to wait on, not an unknown outcome to condemn the id for.
|
|
120
|
+
throw receipt.state === "submitted"
|
|
121
|
+
? new AudioGenerateError("AUDIO_GENERATE_REQUEST_CONFLICT", "That requestId is already in flight. Wait for it, or use a new requestId.")
|
|
122
|
+
: new AudioGenerateError("AUDIO_GENERATE_OUTCOME_UNKNOWN", "This request has no durable source audio, so it cannot be completed locally.");
|
|
123
|
+
}
|
|
124
|
+
// Recorded before this call finishes it: a replay is one that arrived already complete.
|
|
125
|
+
const replayed = receipt.state === "complete";
|
|
126
|
+
// A saved file that no longer matches its recorded hash fails; it is never re-fetched.
|
|
127
|
+
if ((await sha256File(receipt.source.path)) !== receipt.source.sha256) {
|
|
128
|
+
throw new AudioGenerateError("AUDIO_GENERATE_HASH_MISMATCH", "The saved source audio no longer matches the hash recorded when it was written.");
|
|
129
|
+
}
|
|
130
|
+
const wavPath = join(dir, "sound.wav");
|
|
131
|
+
if (!receipt.wav || !(await exists(wavPath))) {
|
|
132
|
+
await this.toWav(receipt.source.path, wavPath);
|
|
133
|
+
receipt.wav = {
|
|
134
|
+
path: wavPath,
|
|
135
|
+
sha256: await sha256File(wavPath),
|
|
136
|
+
sizeBytes: (await stat(wavPath)).size,
|
|
137
|
+
};
|
|
138
|
+
receipt.state = "wav_saved";
|
|
139
|
+
await writeReceipt(receiptPath, receipt);
|
|
140
|
+
}
|
|
141
|
+
else if ((await sha256File(wavPath)) !== receipt.wav.sha256) {
|
|
142
|
+
throw new AudioGenerateError("AUDIO_GENERATE_HASH_MISMATCH", "The saved WAV no longer matches the hash recorded when it was written.");
|
|
143
|
+
}
|
|
144
|
+
const inspection = await this.inspector.inspect({
|
|
145
|
+
...(request.inspection ?? {}),
|
|
146
|
+
path: wavPath,
|
|
147
|
+
loop: receipt.normalized.loop,
|
|
148
|
+
expectedDurationSeconds: receipt.normalized.duration_seconds,
|
|
149
|
+
expectedPrompt: receipt.normalized.text,
|
|
150
|
+
});
|
|
151
|
+
receipt.state = "complete";
|
|
152
|
+
receipt.inspectionCacheKey = inspection.cacheKey;
|
|
153
|
+
await writeReceipt(receiptPath, receipt);
|
|
154
|
+
return {
|
|
155
|
+
requestId: receipt.requestId,
|
|
156
|
+
provider: "elevenlabs",
|
|
157
|
+
model: receipt.model,
|
|
158
|
+
normalizedRequest: receipt.normalized,
|
|
159
|
+
generatedAt: receipt.generatedAt ?? new Date().toISOString(),
|
|
160
|
+
generation: "saved",
|
|
161
|
+
sourcePath: receipt.source.path,
|
|
162
|
+
sourceSha256: receipt.source.sha256,
|
|
163
|
+
sourceSizeBytes: receipt.source.sizeBytes,
|
|
164
|
+
wavPath: receipt.wav.path,
|
|
165
|
+
wavSha256: receipt.wav.sha256,
|
|
166
|
+
wavSizeBytes: receipt.wav.sizeBytes,
|
|
167
|
+
...(receipt.providerRequestId === undefined
|
|
168
|
+
? {}
|
|
169
|
+
: { providerRequestId: receipt.providerRequestId }),
|
|
170
|
+
...(receipt.billingUnits === undefined ? {} : { billingUnits: receipt.billingUnits }),
|
|
171
|
+
commercialUse: "unverified",
|
|
172
|
+
providerTermsUrl: PROVIDER_TERMS_URL,
|
|
173
|
+
receiptPath,
|
|
174
|
+
replayed,
|
|
175
|
+
inspection,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
async preflight(dir, request) {
|
|
179
|
+
try {
|
|
180
|
+
await mkdir(dir, { recursive: true, mode: 0o700 });
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
throw new AudioGenerateError("AUDIO_GENERATE_STORAGE", "The audio output directory could not be created, so nothing was requested.");
|
|
184
|
+
}
|
|
185
|
+
await new Promise((done, fail) => {
|
|
186
|
+
execFile(this.ffmpegPath, ["-hide_banner", "-version"], { timeout: 20_000 }, (error) => error
|
|
187
|
+
? fail(new AudioGenerateError("AUDIO_GENERATE_PREREQUISITE_MISSING", "FFmpeg is not available, so the response could not be decoded. Nothing was requested."))
|
|
188
|
+
: done());
|
|
189
|
+
});
|
|
190
|
+
this.inspector.resolveInspectorBin();
|
|
191
|
+
// An explicitly requested semantic model that is not provisioned is refused before spending.
|
|
192
|
+
if (request.inspection?.semantic === "clap" && !(await semanticAvailable())) {
|
|
193
|
+
throw new AudioGenerateError("AUDIO_GENERATE_PREREQUISITE_MISSING", "Semantic inspection was requested but local CLAP is not provisioned. Nothing was requested or charged.");
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/** Exclusive reservation: two concurrent duplicates cannot both get past this. */
|
|
197
|
+
async reserve(dir, receiptPath, receipt) {
|
|
198
|
+
let handle;
|
|
199
|
+
try {
|
|
200
|
+
handle = await open(receiptPath, "wx", 0o600);
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
throw new AudioGenerateError("AUDIO_GENERATE_REQUEST_CONFLICT", "That requestId is already in flight. Wait for it, or use a new requestId.");
|
|
204
|
+
}
|
|
205
|
+
try {
|
|
206
|
+
await handle.writeFile(JSON.stringify(receipt, null, 2));
|
|
207
|
+
await handle.sync();
|
|
208
|
+
}
|
|
209
|
+
finally {
|
|
210
|
+
await handle.close();
|
|
211
|
+
}
|
|
212
|
+
void dir;
|
|
213
|
+
}
|
|
214
|
+
async submit(normalized, receiptPath) {
|
|
215
|
+
const url = new URL(ENDPOINT);
|
|
216
|
+
url.searchParams.set("output_format", normalized.output_format);
|
|
217
|
+
let response;
|
|
218
|
+
try {
|
|
219
|
+
response = await this.fetch(url, {
|
|
220
|
+
method: "POST",
|
|
221
|
+
// An authenticated request must never be replayed against a redirect target.
|
|
222
|
+
redirect: "error",
|
|
223
|
+
signal: AbortSignal.timeout(GENERATE_LIMITS.timeoutMs),
|
|
224
|
+
headers: {
|
|
225
|
+
"xi-api-key": this.apiKey(),
|
|
226
|
+
"content-type": "application/json",
|
|
227
|
+
accept: "audio/mpeg",
|
|
228
|
+
"user-agent": "threenative-asset-mcp",
|
|
229
|
+
},
|
|
230
|
+
body: JSON.stringify({
|
|
231
|
+
text: normalized.text,
|
|
232
|
+
duration_seconds: normalized.duration_seconds,
|
|
233
|
+
loop: normalized.loop,
|
|
234
|
+
prompt_influence: normalized.prompt_influence,
|
|
235
|
+
model_id: normalized.model_id,
|
|
236
|
+
}),
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
// We asked and never learned the answer, so we must assume it may have been billed.
|
|
241
|
+
await markUnknown(receiptPath);
|
|
242
|
+
throw new AudioGenerateError(isTimeout(error) ? "AUDIO_GENERATE_TIMEOUT" : "AUDIO_GENERATE_UPSTREAM", "The generation request did not complete and its outcome is unknown; this requestId will not be retried.");
|
|
243
|
+
}
|
|
244
|
+
if (!response.ok) {
|
|
245
|
+
// A refusal is a definite non-charge answer, so the reservation can simply be cleared.
|
|
246
|
+
await rm(receiptPath, { force: true });
|
|
247
|
+
throw sanitizedUpstream(response.status);
|
|
248
|
+
}
|
|
249
|
+
const providerRequestId = response.headers.get("request-id") ?? undefined;
|
|
250
|
+
const billingUnits = response.headers.get("character-cost") ?? undefined;
|
|
251
|
+
let body;
|
|
252
|
+
try {
|
|
253
|
+
body = await readCapped(response, GENERATE_LIMITS.maxResponseBytes);
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
if (error instanceof AudioGenerateError) {
|
|
257
|
+
await rm(receiptPath, { force: true });
|
|
258
|
+
throw error;
|
|
259
|
+
}
|
|
260
|
+
await markUnknown(receiptPath);
|
|
261
|
+
throw new AudioGenerateError("AUDIO_GENERATE_UPSTREAM", "The generated audio could not be read completely and its outcome is unknown.");
|
|
262
|
+
}
|
|
263
|
+
if (body.byteLength === 0) {
|
|
264
|
+
await markUnknown(receiptPath);
|
|
265
|
+
throw new AudioGenerateError("AUDIO_GENERATE_UPSTREAM", "The provider returned no audio; the outcome of this request is unknown.");
|
|
266
|
+
}
|
|
267
|
+
return {
|
|
268
|
+
body,
|
|
269
|
+
...(providerRequestId === undefined ? {} : { providerRequestId }),
|
|
270
|
+
...(billingUnits === undefined ? {} : { billingUnits }),
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Decode to PCM16 WAV with no resampling, no downmix, no normalization and no trimming. Turning
|
|
275
|
+
* MP3 into WAV does not restore what the encoder threw away, and pretending otherwise by
|
|
276
|
+
* "cleaning up" here would hide the defect the inspection exists to find.
|
|
277
|
+
*/
|
|
278
|
+
async toWav(sourcePath, wavPath) {
|
|
279
|
+
const temporary = `${wavPath}.partial`;
|
|
280
|
+
await new Promise((done, fail) => {
|
|
281
|
+
execFile(this.ffmpegPath, ["-v", "error", "-y", "-i", sourcePath, "-c:a", "pcm_s16le", "-f", "wav", temporary], { timeout: GENERATE_LIMITS.timeoutMs, maxBuffer: 1024 * 1024 }, (error) => error
|
|
282
|
+
? fail(new AudioGenerateError("AUDIO_GENERATE_CONVERT_FAILED", "The saved audio could not be decoded to WAV. The original response is kept.", true))
|
|
283
|
+
: done());
|
|
284
|
+
});
|
|
285
|
+
await rename(temporary, wavPath);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
function normalize(request) {
|
|
289
|
+
const text = typeof request.prompt === "string" ? request.prompt.trim() : "";
|
|
290
|
+
if (text.length === 0 || text.length > GENERATE_LIMITS.maxPromptChars) {
|
|
291
|
+
throw new AudioGenerateError("AUDIO_GENERATE_INVALID_INPUT", `The prompt must be between 1 and ${String(GENERATE_LIMITS.maxPromptChars)} characters.`);
|
|
292
|
+
}
|
|
293
|
+
const duration = request.durationSeconds ?? 5;
|
|
294
|
+
if (!Number.isFinite(duration) ||
|
|
295
|
+
duration < GENERATE_LIMITS.minDurationSeconds ||
|
|
296
|
+
duration > GENERATE_LIMITS.maxDurationSeconds) {
|
|
297
|
+
throw new AudioGenerateError("AUDIO_GENERATE_INVALID_INPUT", `durationSeconds must be between ${String(GENERATE_LIMITS.minDurationSeconds)} and ${String(GENERATE_LIMITS.maxDurationSeconds)}.`);
|
|
298
|
+
}
|
|
299
|
+
const influence = request.promptInfluence ?? 0.3;
|
|
300
|
+
if (!Number.isFinite(influence) || influence < 0 || influence > 1) {
|
|
301
|
+
throw new AudioGenerateError("AUDIO_GENERATE_INVALID_INPUT", "promptInfluence must be between 0 and 1.");
|
|
302
|
+
}
|
|
303
|
+
// Generation owns these three; a caller who also sets them in `inspection` is contradicting itself.
|
|
304
|
+
const conflicting = request.inspection;
|
|
305
|
+
for (const key of ["loop", "expectedDurationSeconds", "expectedPrompt", "path"]) {
|
|
306
|
+
if (conflicting && key in conflicting) {
|
|
307
|
+
throw new AudioGenerateError("AUDIO_GENERATE_INVALID_INPUT", `inspection.${key} is supplied by generation itself and must not be set.`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return {
|
|
311
|
+
text,
|
|
312
|
+
duration_seconds: duration,
|
|
313
|
+
loop: request.loop ?? false,
|
|
314
|
+
prompt_influence: influence,
|
|
315
|
+
model_id: MODEL_ID,
|
|
316
|
+
output_format: OUTPUT_FORMAT,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
/** Provider error bodies and headers never reach the caller; only a category does. */
|
|
320
|
+
function sanitizedUpstream(status) {
|
|
321
|
+
if (status === 401 || status === 403) {
|
|
322
|
+
return new AudioGenerateError("AUDIO_GENERATE_AUTH_FAILED", "ElevenLabs rejected the API key. Ask the user to check their own ELEVENLABS_API_KEY; nothing was saved.");
|
|
323
|
+
}
|
|
324
|
+
if (status === 429) {
|
|
325
|
+
return new AudioGenerateError("AUDIO_GENERATE_RATE_LIMITED", "ElevenLabs rate-limited or refused the request for quota reasons; nothing was saved.", true);
|
|
326
|
+
}
|
|
327
|
+
if (status === 422 || status === 400) {
|
|
328
|
+
return new AudioGenerateError("AUDIO_GENERATE_REJECTED", "ElevenLabs rejected the request parameters; nothing was saved.");
|
|
329
|
+
}
|
|
330
|
+
return new AudioGenerateError("AUDIO_GENERATE_UPSTREAM", `ElevenLabs returned an error (HTTP ${String(status)}); nothing was saved.`, status >= 500);
|
|
331
|
+
}
|
|
332
|
+
async function readCapped(response, cap) {
|
|
333
|
+
const declared = Number(response.headers.get("content-length") ?? "0");
|
|
334
|
+
if (Number.isFinite(declared) && declared > cap) {
|
|
335
|
+
throw new AudioGenerateError("AUDIO_GENERATE_TOO_LARGE", "The provider's audio response exceeds the size cap; nothing was saved.");
|
|
336
|
+
}
|
|
337
|
+
const reader = response.body?.getReader();
|
|
338
|
+
if (!reader)
|
|
339
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
340
|
+
const chunks = [];
|
|
341
|
+
let total = 0;
|
|
342
|
+
for (;;) {
|
|
343
|
+
const { done, value } = await reader.read();
|
|
344
|
+
if (done)
|
|
345
|
+
break;
|
|
346
|
+
if (value) {
|
|
347
|
+
total += value.byteLength;
|
|
348
|
+
if (total > cap) {
|
|
349
|
+
// Stop pulling bytes we have already decided to refuse.
|
|
350
|
+
await reader.cancel();
|
|
351
|
+
throw new AudioGenerateError("AUDIO_GENERATE_TOO_LARGE", "The provider's audio response exceeds the size cap; nothing was saved.");
|
|
352
|
+
}
|
|
353
|
+
chunks.push(value);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
const body = new Uint8Array(total);
|
|
357
|
+
let offset = 0;
|
|
358
|
+
for (const chunk of chunks) {
|
|
359
|
+
body.set(chunk, offset);
|
|
360
|
+
offset += chunk.byteLength;
|
|
361
|
+
}
|
|
362
|
+
return body;
|
|
363
|
+
}
|
|
364
|
+
function isTimeout(error) {
|
|
365
|
+
return error instanceof Error && (error.name === "TimeoutError" || error.name === "AbortError");
|
|
366
|
+
}
|
|
367
|
+
async function markUnknown(receiptPath) {
|
|
368
|
+
const receipt = await readReceipt(receiptPath);
|
|
369
|
+
if (!receipt)
|
|
370
|
+
return;
|
|
371
|
+
await writeReceipt(receiptPath, { ...receipt, state: "outcome_unknown" });
|
|
372
|
+
}
|
|
373
|
+
async function readReceipt(path) {
|
|
374
|
+
try {
|
|
375
|
+
return JSON.parse(await readFile(path, "utf8"));
|
|
376
|
+
}
|
|
377
|
+
catch {
|
|
378
|
+
return undefined;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
async function writeReceipt(path, receipt) {
|
|
382
|
+
const temporary = `${path}.partial`;
|
|
383
|
+
await writeFile(temporary, JSON.stringify(receipt, null, 2), { mode: 0o600 });
|
|
384
|
+
await rename(temporary, path);
|
|
385
|
+
}
|
|
386
|
+
async function writeExclusive(path, bytes) {
|
|
387
|
+
const handle = await open(path, "wx", 0o600);
|
|
388
|
+
try {
|
|
389
|
+
await handle.writeFile(bytes);
|
|
390
|
+
await handle.sync();
|
|
391
|
+
}
|
|
392
|
+
finally {
|
|
393
|
+
await handle.close();
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
async function exists(path) {
|
|
397
|
+
try {
|
|
398
|
+
await stat(path);
|
|
399
|
+
return true;
|
|
400
|
+
}
|
|
401
|
+
catch {
|
|
402
|
+
return false;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
//# sourceMappingURL=generate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/audio/generate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { type SemanticResult } from "./semantic.js";
|
|
2
|
+
/**
|
|
3
|
+
* Wrap the existing `threenative-playtest audio` inspector.
|
|
4
|
+
*
|
|
5
|
+
* Every measurement and every judgement about peaks, silence, bands and loop seams belongs to that
|
|
6
|
+
* package. This module only decides which bytes get inspected, translates the caller's expectations
|
|
7
|
+
* into its manifest, and turns its report into an agent-facing result that never overstates what was
|
|
8
|
+
* actually checked. It does not re-implement a single DSP routine, and it never repairs the input.
|
|
9
|
+
*/
|
|
10
|
+
export type AudioInspectErrorCode = "AUDIO_INSPECT_INVALID_INPUT" | "AUDIO_INSPECT_NOT_FOUND" | "AUDIO_INSPECT_OUTSIDE_ROOT" | "AUDIO_INSPECT_TOO_LARGE" | "AUDIO_INSPECT_UNSUPPORTED" | "AUDIO_INSPECT_TOOL_MISSING" | "AUDIO_INSPECT_FAILED";
|
|
11
|
+
export declare class AudioInspectError extends Error {
|
|
12
|
+
readonly code: AudioInspectErrorCode;
|
|
13
|
+
readonly retryable: boolean;
|
|
14
|
+
constructor(code: AudioInspectErrorCode, message: string, retryable?: boolean);
|
|
15
|
+
}
|
|
16
|
+
/** v1 limits, reported in every result so a caller never has to guess why something was refused. */
|
|
17
|
+
export declare const INSPECT_LIMITS: {
|
|
18
|
+
readonly maxBytes: number;
|
|
19
|
+
readonly maxSeconds: 60;
|
|
20
|
+
readonly maxChannels: 2;
|
|
21
|
+
readonly maxSampleRate: 96000;
|
|
22
|
+
/** Wall clock for the inspector subprocess itself. */
|
|
23
|
+
readonly timeoutMs: 120000;
|
|
24
|
+
/** stdout is a JSON report, not a stream; a runaway one is a failure, not something to buffer. */
|
|
25
|
+
readonly maxOutputBytes: number;
|
|
26
|
+
};
|
|
27
|
+
export declare const AUDIO_BAND_NAMES: readonly ["sub", "low", "mid", "high", "air"];
|
|
28
|
+
export type AudioBandName = (typeof AUDIO_BAND_NAMES)[number];
|
|
29
|
+
export interface AudioBandBound {
|
|
30
|
+
min?: number | undefined;
|
|
31
|
+
max?: number | undefined;
|
|
32
|
+
}
|
|
33
|
+
export interface AudioEmotionRequest {
|
|
34
|
+
sourceDescription: string;
|
|
35
|
+
targetMood: string;
|
|
36
|
+
alternativeMoods: string[];
|
|
37
|
+
}
|
|
38
|
+
type PartialBands = {
|
|
39
|
+
[K in AudioBandName]?: AudioBandBound | undefined;
|
|
40
|
+
};
|
|
41
|
+
export interface AudioInspectRequest {
|
|
42
|
+
path: string;
|
|
43
|
+
loop: boolean;
|
|
44
|
+
expectedDurationSeconds?: number | undefined;
|
|
45
|
+
expectedPrompt?: string | undefined;
|
|
46
|
+
alternativePrompts?: string[] | undefined;
|
|
47
|
+
emotion?: AudioEmotionRequest | undefined;
|
|
48
|
+
bands?: PartialBands | undefined;
|
|
49
|
+
peakMax?: number | undefined;
|
|
50
|
+
silenceRms?: number | undefined;
|
|
51
|
+
seamMaxRatio?: number | undefined;
|
|
52
|
+
semantic?: "off" | "clap" | undefined;
|
|
53
|
+
}
|
|
54
|
+
export interface AudioFinding {
|
|
55
|
+
name: string;
|
|
56
|
+
severity: "error" | "warning";
|
|
57
|
+
reason: string;
|
|
58
|
+
remedy?: string;
|
|
59
|
+
}
|
|
60
|
+
export interface AudioMeasured {
|
|
61
|
+
durationSeconds: number;
|
|
62
|
+
sampleRate: number;
|
|
63
|
+
channels: number;
|
|
64
|
+
peak: number;
|
|
65
|
+
rms: number;
|
|
66
|
+
dc: number;
|
|
67
|
+
bands: Record<AudioBandName, number>;
|
|
68
|
+
seam?: {
|
|
69
|
+
wrap: number;
|
|
70
|
+
nearP99: number;
|
|
71
|
+
ratio: number;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export interface AudioInspectResult {
|
|
75
|
+
inputPath: string;
|
|
76
|
+
inputSha256: string;
|
|
77
|
+
inputSizeBytes: number;
|
|
78
|
+
analysis: {
|
|
79
|
+
inspector: string;
|
|
80
|
+
inspectorVersion: string;
|
|
81
|
+
adapterVersion: string;
|
|
82
|
+
};
|
|
83
|
+
limits: typeof INSPECT_LIMITS;
|
|
84
|
+
effectiveExpectations: Record<string, unknown>;
|
|
85
|
+
measured?: AudioMeasured;
|
|
86
|
+
findings: AudioFinding[];
|
|
87
|
+
spectrogramPath?: string;
|
|
88
|
+
technicalStatus: "pass" | "warn" | "fail" | "unverified";
|
|
89
|
+
promptFit: "consistent" | "possible_mismatch" | "unverified";
|
|
90
|
+
emotionFit: SemanticResult["emotionFit"];
|
|
91
|
+
semantic: SemanticResult["content"];
|
|
92
|
+
artisticQuality: "unverified";
|
|
93
|
+
recommendation: "reject" | "review" | "audition";
|
|
94
|
+
notes: string[];
|
|
95
|
+
cacheKey: string;
|
|
96
|
+
cached: boolean;
|
|
97
|
+
}
|
|
98
|
+
export interface AudioInspectorOptions {
|
|
99
|
+
/** Extra roots a caller may inspect, beyond the canonical audio download directory. */
|
|
100
|
+
inspectRoots?: string[];
|
|
101
|
+
audioDir?: string;
|
|
102
|
+
/** Overridden only by tests that need a fake inspector; production resolves the pinned package. */
|
|
103
|
+
inspectorBin?: string;
|
|
104
|
+
}
|
|
105
|
+
export declare class AudioInspector {
|
|
106
|
+
private readonly audioDir;
|
|
107
|
+
private readonly extraRoots;
|
|
108
|
+
private readonly inspectorBinOverride;
|
|
109
|
+
constructor(options?: AudioInspectorOptions);
|
|
110
|
+
/** Absolute path of the pinned inspector's declared binary. Never `npx`, never a shell lookup. */
|
|
111
|
+
resolveInspectorBin(): string;
|
|
112
|
+
private inspectorVersion;
|
|
113
|
+
inspect(request: AudioInspectRequest): Promise<AudioInspectResult>;
|
|
114
|
+
private resolveInput;
|
|
115
|
+
private allowedRoots;
|
|
116
|
+
private runInspection;
|
|
117
|
+
private semantics;
|
|
118
|
+
private keepSpectrogram;
|
|
119
|
+
private runInspector;
|
|
120
|
+
private assemble;
|
|
121
|
+
}
|
|
122
|
+
export {};
|
|
123
|
+
//# sourceMappingURL=inspect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspect.d.ts","sourceRoot":"","sources":["../../src/audio/inspect.ts"],"names":[],"mappings":"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"}
|