@neta-art/generation 0.1.2 → 0.1.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 +33 -0
- package/dist/{builtins-BE6FhnwP.d.ts → builtins-BJ2_TVlr.d.ts} +24 -3
- package/dist/builtins-BJ2_TVlr.d.ts.map +1 -0
- package/dist/{builtins-B1AheaEa.js → builtins-FumzmWvj.js} +248 -1
- package/dist/builtins-FumzmWvj.js.map +1 -0
- package/dist/builtins.d.ts +1 -1
- package/dist/builtins.js +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/{export-config-BPnZYpmN.js → export-config-D8By2_r7.js} +428 -49
- package/dist/export-config-D8By2_r7.js.map +1 -0
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/models/suno_music.yaml +265 -0
- package/package.json +2 -1
- package/dist/builtins-B1AheaEa.js.map +0 -1
- package/dist/builtins-BE6FhnwP.d.ts.map +0 -1
- package/dist/export-config-BPnZYpmN.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as compactArray, c as slugifyFileName, i as cloneJson, l as MODEL_SCHEMA, n as getBuiltinGenerationModel, o as compactObject, r as listBuiltinGenerationModels, s as getBlockMeta, t as builtinGenerationModels } from "./builtins-
|
|
1
|
+
import { a as compactArray, c as slugifyFileName, i as cloneJson, l as MODEL_SCHEMA, n as getBuiltinGenerationModel, o as compactObject, r as listBuiltinGenerationModels, s as getBlockMeta, t as builtinGenerationModels } from "./builtins-FumzmWvj.js";
|
|
2
2
|
import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
|
|
3
3
|
import { extname, join } from "node:path";
|
|
4
4
|
import { parse, stringify } from "yaml";
|
|
@@ -161,7 +161,12 @@ function validateGenerationContent(declaration, content) {
|
|
|
161
161
|
function resolveGenerationParameters(declaration, parameters) {
|
|
162
162
|
const specs = declaration.parameters ?? {};
|
|
163
163
|
const resolved = {};
|
|
164
|
-
|
|
164
|
+
const allowUnknownParameters = declaration.allowUnknownParameters ?? false;
|
|
165
|
+
for (const key of Object.keys(parameters ?? {})) if (!specs[key]) {
|
|
166
|
+
if (!allowUnknownParameters) throw new GenerationValidationError(`Unknown parameter: ${key}`);
|
|
167
|
+
const value = parameters?.[key];
|
|
168
|
+
if (value !== void 0) resolved[key] = value;
|
|
169
|
+
}
|
|
165
170
|
for (const [key, spec] of Object.entries(specs)) {
|
|
166
171
|
const value = parameters?.[key];
|
|
167
172
|
if (value === void 0) {
|
|
@@ -169,27 +174,73 @@ function resolveGenerationParameters(declaration, parameters) {
|
|
|
169
174
|
else if (!spec.optional) throw new GenerationValidationError(`Missing required parameter: ${key}`);
|
|
170
175
|
continue;
|
|
171
176
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
177
|
+
validateSpecValue(`Parameter ${key}`, spec, value);
|
|
178
|
+
resolved[key] = value;
|
|
179
|
+
}
|
|
180
|
+
return resolved;
|
|
181
|
+
}
|
|
182
|
+
function mergeGenerationMeta(requestMeta, content) {
|
|
183
|
+
const merged = {};
|
|
184
|
+
mergeMetaFields(merged, requestMeta);
|
|
185
|
+
for (const block of content) mergeMetaFields(merged, block.meta);
|
|
186
|
+
return merged;
|
|
187
|
+
}
|
|
188
|
+
function normalizeMetaKey(key) {
|
|
189
|
+
return key === "metadataParams" ? "metadata_params" : key;
|
|
190
|
+
}
|
|
191
|
+
function mergeMetaFields(target, meta) {
|
|
192
|
+
for (const [key, value] of Object.entries(meta ?? {})) {
|
|
193
|
+
const normalizedKey = normalizeMetaKey(key);
|
|
194
|
+
if (value !== void 0 && target[normalizedKey] === void 0) target[normalizedKey] = value;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function validateSpecValue(label, spec, value) {
|
|
198
|
+
switch (spec.type) {
|
|
199
|
+
case "string":
|
|
200
|
+
if (typeof value !== "string") throw new GenerationValidationError(`${label} must be a string`);
|
|
201
|
+
if (spec.enum && !spec.enum.includes(value)) throw new GenerationValidationError(`${label} must be one of: ${spec.enum.join(", ")}`);
|
|
202
|
+
break;
|
|
203
|
+
case "number":
|
|
204
|
+
if (typeof value !== "number" || !Number.isFinite(value)) throw new GenerationValidationError(`${label} must be a number`);
|
|
205
|
+
if (spec.min !== void 0 && value < spec.min) throw new GenerationValidationError(`${label} must be >= ${spec.min}`);
|
|
206
|
+
if (spec.max !== void 0 && value > spec.max) throw new GenerationValidationError(`${label} must be <= ${spec.max}`);
|
|
207
|
+
break;
|
|
208
|
+
case "integer":
|
|
209
|
+
if (typeof value !== "number" || !Number.isInteger(value)) throw new GenerationValidationError(`${label} must be an integer`);
|
|
210
|
+
if (spec.min !== void 0 && value < spec.min) throw new GenerationValidationError(`${label} must be >= ${spec.min}`);
|
|
211
|
+
if (spec.max !== void 0 && value > spec.max) throw new GenerationValidationError(`${label} must be <= ${spec.max}`);
|
|
212
|
+
break;
|
|
213
|
+
case "boolean":
|
|
214
|
+
if (typeof value !== "boolean") throw new GenerationValidationError(`${label} must be a boolean`);
|
|
215
|
+
break;
|
|
216
|
+
case "object":
|
|
217
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new GenerationValidationError(`${label} must be an object`);
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
function resolveGenerationMeta(declaration, meta, content) {
|
|
222
|
+
const specs = declaration.meta?.fields ?? {};
|
|
223
|
+
const resolved = {};
|
|
224
|
+
for (const key of Object.keys(meta ?? {})) if (!specs[key]) {
|
|
225
|
+
const value = meta?.[key];
|
|
226
|
+
if (value !== void 0) resolved[key] = value;
|
|
227
|
+
}
|
|
228
|
+
for (const [key, spec] of Object.entries(specs)) {
|
|
229
|
+
const value = meta?.[key];
|
|
230
|
+
if (value === void 0) {
|
|
231
|
+
if (!spec.optional) throw new GenerationValidationError(`Missing required meta: ${key}`);
|
|
232
|
+
continue;
|
|
190
233
|
}
|
|
234
|
+
validateSpecValue(`meta.${key}`, spec, value);
|
|
191
235
|
resolved[key] = value;
|
|
192
236
|
}
|
|
237
|
+
const taskField = declaration.meta?.taskField;
|
|
238
|
+
const task = taskField && typeof resolved[taskField] === "string" ? resolved[taskField] : void 0;
|
|
239
|
+
if (!task) return resolved;
|
|
240
|
+
const variant = declaration.meta?.taskVariants?.[task];
|
|
241
|
+
if (!variant) throw new GenerationValidationError(`Unsupported meta.${taskField}: ${task}`);
|
|
242
|
+
for (const key of variant.required ?? []) if (resolved[key] === void 0 || resolved[key] === null || resolved[key] === "") throw new GenerationValidationError(`meta.${taskField} ${task} requires meta.${key}`);
|
|
243
|
+
for (const type of variant.requiredContent ?? []) if (!content.some((block) => block.type === type)) throw new GenerationValidationError(`meta.${taskField} ${task} requires ${type} content`);
|
|
193
244
|
return resolved;
|
|
194
245
|
}
|
|
195
246
|
function mergeTextBlocks(declaration, content) {
|
|
@@ -200,9 +251,9 @@ function mergeTextBlocks(declaration, content) {
|
|
|
200
251
|
|
|
201
252
|
//#endregion
|
|
202
253
|
//#region src/adapters/ark-video-generations.ts
|
|
203
|
-
const REQUEST_TIMEOUT_MS$
|
|
204
|
-
const DEFAULT_POLL_INTERVAL_SEC = 2;
|
|
205
|
-
const DEFAULT_MAX_WAIT_SEC = 600;
|
|
254
|
+
const REQUEST_TIMEOUT_MS$3 = 6e4;
|
|
255
|
+
const DEFAULT_POLL_INTERVAL_SEC$1 = 2;
|
|
256
|
+
const DEFAULT_MAX_WAIT_SEC$1 = 600;
|
|
206
257
|
const RESOLUTION_SHORT_EDGE = {
|
|
207
258
|
"480p": 480,
|
|
208
259
|
"720p": 720,
|
|
@@ -220,10 +271,10 @@ const ASPECT_RATIOS = {
|
|
|
220
271
|
"21:9": [21, 9],
|
|
221
272
|
adaptive: null
|
|
222
273
|
};
|
|
223
|
-
function sleep(ms) {
|
|
274
|
+
function sleep$1(ms) {
|
|
224
275
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
225
276
|
}
|
|
226
|
-
function asString(value) {
|
|
277
|
+
function asString$1(value) {
|
|
227
278
|
return typeof value === "string" && value ? value : void 0;
|
|
228
279
|
}
|
|
229
280
|
function asNumber(value) {
|
|
@@ -232,7 +283,7 @@ function asNumber(value) {
|
|
|
232
283
|
function asBoolean(value) {
|
|
233
284
|
return typeof value === "boolean" ? value : void 0;
|
|
234
285
|
}
|
|
235
|
-
function normalizeStatus(value) {
|
|
286
|
+
function normalizeStatus$1(value) {
|
|
236
287
|
const status = value.toLowerCase();
|
|
237
288
|
return status === "success" ? "succeeded" : status;
|
|
238
289
|
}
|
|
@@ -286,8 +337,8 @@ function buildMetadataContent(prompt, images, mode) {
|
|
|
286
337
|
}
|
|
287
338
|
return content;
|
|
288
339
|
}
|
|
289
|
-
function extractTaskId(response) {
|
|
290
|
-
const taskId = asString(response.task_id) ?? asString(response.id);
|
|
340
|
+
function extractTaskId$1(response) {
|
|
341
|
+
const taskId = asString$1(response.task_id) ?? asString$1(response.id);
|
|
291
342
|
if (!taskId) throw new GenerationProviderError("Video generation provider did not return a task id", { details: { response } });
|
|
292
343
|
return taskId;
|
|
293
344
|
}
|
|
@@ -295,9 +346,9 @@ function normalizeTaskStatus(response) {
|
|
|
295
346
|
if (response.data) {
|
|
296
347
|
const wrapper = response.data;
|
|
297
348
|
const native = wrapper.data;
|
|
298
|
-
const status = normalizeStatus(asString(native?.status) ?? asString(wrapper.status) ?? "unknown");
|
|
299
|
-
const videoUrl = asString(wrapper.result_url) ?? asString(native?.content?.video_url);
|
|
300
|
-
const lastFrameUrl = asString(wrapper.first_frame) ?? asString(native?.content?.first_frame);
|
|
349
|
+
const status = normalizeStatus$1(asString$1(native?.status) ?? asString$1(wrapper.status) ?? "unknown");
|
|
350
|
+
const videoUrl = asString$1(wrapper.result_url) ?? asString$1(native?.content?.video_url);
|
|
351
|
+
const lastFrameUrl = asString$1(wrapper.first_frame) ?? asString$1(native?.content?.first_frame);
|
|
301
352
|
const metadata = {
|
|
302
353
|
progress: wrapper.progress,
|
|
303
354
|
resolution: native?.resolution,
|
|
@@ -324,7 +375,7 @@ function normalizeTaskStatus(response) {
|
|
|
324
375
|
metadata: {}
|
|
325
376
|
};
|
|
326
377
|
}
|
|
327
|
-
async function requestJson(input, path, init) {
|
|
378
|
+
async function requestJson$1(input, path, init) {
|
|
328
379
|
const response = await fetchWithTimeout(input.context.fetch, joinUrl(input.context.baseUrl, path), {
|
|
329
380
|
...init,
|
|
330
381
|
headers: {
|
|
@@ -332,7 +383,7 @@ async function requestJson(input, path, init) {
|
|
|
332
383
|
"Content-Type": "application/json",
|
|
333
384
|
...init.headers
|
|
334
385
|
}
|
|
335
|
-
}, REQUEST_TIMEOUT_MS$
|
|
386
|
+
}, REQUEST_TIMEOUT_MS$3);
|
|
336
387
|
if (!response.ok) {
|
|
337
388
|
const body = await response.text().catch(() => response.statusText);
|
|
338
389
|
throw new GenerationProviderError("Video generation provider request failed", {
|
|
@@ -351,12 +402,12 @@ async function arkVideoGenerationsAdapter(input) {
|
|
|
351
402
|
role: getImageRole(block)
|
|
352
403
|
})));
|
|
353
404
|
const mode = classifyImages(images);
|
|
354
|
-
const resolution = asString(input.parameters.resolution) ?? "720p";
|
|
355
|
-
const aspectRatio = asString(input.parameters.aspect_ratio) ?? "16:9";
|
|
405
|
+
const resolution = asString$1(input.parameters.resolution) ?? "720p";
|
|
406
|
+
const aspectRatio = asString$1(input.parameters.aspect_ratio) ?? "16:9";
|
|
356
407
|
const duration = getIntegerParameter(input.parameters, "duration", 5);
|
|
357
408
|
const fps = getIntegerParameter(input.parameters, "fps", 30);
|
|
358
|
-
const pollIntervalSec = getIntegerParameter(input.parameters, "poll_interval", DEFAULT_POLL_INTERVAL_SEC);
|
|
359
|
-
const maxWaitSec = getIntegerParameter(input.parameters, "max_wait", DEFAULT_MAX_WAIT_SEC);
|
|
409
|
+
const pollIntervalSec = getIntegerParameter(input.parameters, "poll_interval", DEFAULT_POLL_INTERVAL_SEC$1);
|
|
410
|
+
const maxWaitSec = getIntegerParameter(input.parameters, "max_wait", DEFAULT_MAX_WAIT_SEC$1);
|
|
360
411
|
const generateAudio = asBoolean(input.parameters.generate_audio) ?? true;
|
|
361
412
|
const returnLastFrame = asBoolean(input.parameters.return_last_frame) ?? true;
|
|
362
413
|
const cameraFixed = asBoolean(input.parameters.camera_fixed) ?? false;
|
|
@@ -388,14 +439,14 @@ async function arkVideoGenerationsAdapter(input) {
|
|
|
388
439
|
if (images[0]) payload.image = images[0].url;
|
|
389
440
|
}
|
|
390
441
|
payload.metadata = metadata;
|
|
391
|
-
const taskId = extractTaskId(await requestJson(input, "/v1/video/generations", {
|
|
442
|
+
const taskId = extractTaskId$1(await requestJson$1(input, "/v1/video/generations", {
|
|
392
443
|
method: "POST",
|
|
393
444
|
body: JSON.stringify(payload)
|
|
394
445
|
}));
|
|
395
446
|
const startedAt = Date.now();
|
|
396
447
|
while (Date.now() - startedAt <= maxWaitSec * 1e3) {
|
|
397
|
-
await sleep(pollIntervalSec * 1e3);
|
|
398
|
-
const rawStatus = await requestJson(input, `/v1/video/generations/${encodeURIComponent(taskId)}`, { method: "GET" });
|
|
448
|
+
await sleep$1(pollIntervalSec * 1e3);
|
|
449
|
+
const rawStatus = await requestJson$1(input, `/v1/video/generations/${encodeURIComponent(taskId)}`, { method: "GET" });
|
|
399
450
|
const status = normalizeTaskStatus(rawStatus);
|
|
400
451
|
if (status.status === "succeeded") {
|
|
401
452
|
if (!status.videoUrl) throw new GenerationProviderError("Video generation succeeded but returned no video URL", { details: compactObject({
|
|
@@ -442,7 +493,7 @@ async function arkVideoGenerationsAdapter(input) {
|
|
|
442
493
|
|
|
443
494
|
//#endregion
|
|
444
495
|
//#region src/adapters/gemini-generate-content.ts
|
|
445
|
-
const REQUEST_TIMEOUT_MS$
|
|
496
|
+
const REQUEST_TIMEOUT_MS$2 = 3e5;
|
|
446
497
|
const IMAGE_FETCH_TIMEOUT_MS = 6e4;
|
|
447
498
|
const MAX_REFERENCE_IMAGE_BYTES = 10 * 1024 * 1024;
|
|
448
499
|
const DATA_URI_PATTERN = /^data:([^;]+);base64,(.+)$/s;
|
|
@@ -580,7 +631,7 @@ async function geminiGenerateContentAdapter(input) {
|
|
|
580
631
|
"Content-Type": "application/json"
|
|
581
632
|
},
|
|
582
633
|
body: JSON.stringify(payload)
|
|
583
|
-
}, REQUEST_TIMEOUT_MS$
|
|
634
|
+
}, REQUEST_TIMEOUT_MS$2);
|
|
584
635
|
if (!response.ok) {
|
|
585
636
|
const body = await response.text().catch(() => response.statusText);
|
|
586
637
|
throw new GenerationProviderError("Gemini generation provider request failed", {
|
|
@@ -597,7 +648,7 @@ async function geminiGenerateContentAdapter(input) {
|
|
|
597
648
|
|
|
598
649
|
//#endregion
|
|
599
650
|
//#region src/adapters/openai-images.ts
|
|
600
|
-
const REQUEST_TIMEOUT_MS = 3e5;
|
|
651
|
+
const REQUEST_TIMEOUT_MS$1 = 3e5;
|
|
601
652
|
function collectOpenAiImagesNoOutputDetails(raw) {
|
|
602
653
|
const data = raw.data ?? [];
|
|
603
654
|
return compactObject({
|
|
@@ -632,7 +683,7 @@ async function openAiImagesAdapter(input) {
|
|
|
632
683
|
"Content-Type": "application/json"
|
|
633
684
|
},
|
|
634
685
|
body: JSON.stringify(payload)
|
|
635
|
-
}, REQUEST_TIMEOUT_MS);
|
|
686
|
+
}, REQUEST_TIMEOUT_MS$1);
|
|
636
687
|
if (!response.ok) {
|
|
637
688
|
const body = await response.text().catch(() => response.statusText);
|
|
638
689
|
throw new GenerationProviderError("Image generation provider request failed", {
|
|
@@ -668,12 +719,322 @@ async function openAiImagesAdapter(input) {
|
|
|
668
719
|
return output;
|
|
669
720
|
}
|
|
670
721
|
|
|
722
|
+
//#endregion
|
|
723
|
+
//#region src/adapters/suno-tasks.ts
|
|
724
|
+
const REQUEST_TIMEOUT_MS = 6e4;
|
|
725
|
+
const DEFAULT_POLL_INTERVAL_SEC = 5;
|
|
726
|
+
const DEFAULT_MAX_WAIT_SEC = 600;
|
|
727
|
+
const DEFAULT_MUSIC_VERSION = "chirp-v5-5";
|
|
728
|
+
const OPERATION_PATHS = {
|
|
729
|
+
music: {
|
|
730
|
+
path: "/suno/submit/music",
|
|
731
|
+
poll: true,
|
|
732
|
+
defaultMusicVersion: true,
|
|
733
|
+
textField: "prompt"
|
|
734
|
+
},
|
|
735
|
+
lyrics: {
|
|
736
|
+
path: "/suno/submit/lyrics",
|
|
737
|
+
poll: true,
|
|
738
|
+
textField: "prompt",
|
|
739
|
+
requireText: true
|
|
740
|
+
},
|
|
741
|
+
concat: {
|
|
742
|
+
path: "/suno/submit/concat",
|
|
743
|
+
poll: true
|
|
744
|
+
},
|
|
745
|
+
upsample_tags: {
|
|
746
|
+
path: "/suno/submit/upsample-tags",
|
|
747
|
+
poll: false,
|
|
748
|
+
textField: "original_tags",
|
|
749
|
+
requireText: true
|
|
750
|
+
},
|
|
751
|
+
upload_audio: {
|
|
752
|
+
path: "/suno/uploads/audio",
|
|
753
|
+
poll: true
|
|
754
|
+
}
|
|
755
|
+
};
|
|
756
|
+
const FINAL_SUCCESS_STATUSES = new Set([
|
|
757
|
+
"success",
|
|
758
|
+
"succeeded",
|
|
759
|
+
"completed"
|
|
760
|
+
]);
|
|
761
|
+
const FINAL_FAILURE_STATUSES = new Set([
|
|
762
|
+
"failure",
|
|
763
|
+
"failed",
|
|
764
|
+
"error",
|
|
765
|
+
"cancelled",
|
|
766
|
+
"canceled",
|
|
767
|
+
"expired"
|
|
768
|
+
]);
|
|
769
|
+
function sleep(ms) {
|
|
770
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
771
|
+
}
|
|
772
|
+
function isRecord$1(value) {
|
|
773
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
774
|
+
}
|
|
775
|
+
function asString(value) {
|
|
776
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
777
|
+
}
|
|
778
|
+
function asInteger(value, fallback) {
|
|
779
|
+
return typeof value === "number" && Number.isInteger(value) ? value : fallback;
|
|
780
|
+
}
|
|
781
|
+
function successCode(value) {
|
|
782
|
+
const code = String(value ?? "").trim().toLowerCase();
|
|
783
|
+
return code === "success" || code === "200" || code === "0";
|
|
784
|
+
}
|
|
785
|
+
function requireSuccess(response, fallbackMessage) {
|
|
786
|
+
if (!successCode(response.code)) throw new GenerationProviderError(fallbackMessage, { details: {
|
|
787
|
+
code: response.code,
|
|
788
|
+
message: response.message,
|
|
789
|
+
data: response.data
|
|
790
|
+
} });
|
|
791
|
+
return response.data;
|
|
792
|
+
}
|
|
793
|
+
function extractTaskId(value) {
|
|
794
|
+
if (typeof value === "string" && value.trim()) return value.trim();
|
|
795
|
+
if (!isRecord$1(value)) return void 0;
|
|
796
|
+
for (const key of [
|
|
797
|
+
"task_id",
|
|
798
|
+
"id",
|
|
799
|
+
"taskBatchId"
|
|
800
|
+
]) {
|
|
801
|
+
const taskId = asString(value[key]);
|
|
802
|
+
if (taskId) return taskId;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
function normalizeStatus(value) {
|
|
806
|
+
return String(value ?? "").trim().toLowerCase();
|
|
807
|
+
}
|
|
808
|
+
function normalizeTask(operation, data) {
|
|
809
|
+
if (Array.isArray(data)) return data.length > 0 ? normalizeTask(operation, data[0]) : null;
|
|
810
|
+
if (!isRecord$1(data)) return null;
|
|
811
|
+
if ("status" in data || "task_id" in data) return data;
|
|
812
|
+
if (Array.isArray(data.data) && data.data.length > 0) return normalizeTask(operation, data.data[0]);
|
|
813
|
+
return {
|
|
814
|
+
action: operation,
|
|
815
|
+
status: "SUCCESS",
|
|
816
|
+
data
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
function getOperation(input) {
|
|
820
|
+
const operation = asString(input.parameters.operation) ?? "music";
|
|
821
|
+
if (!OPERATION_PATHS[operation]) throw new GenerationValidationError(`Unsupported Suno operation: ${operation}`);
|
|
822
|
+
return operation;
|
|
823
|
+
}
|
|
824
|
+
async function buildPayload(input, operation) {
|
|
825
|
+
const payload = { ...input.meta };
|
|
826
|
+
const config = OPERATION_PATHS[operation];
|
|
827
|
+
const prompt = mergeTextBlocks(input.declaration, input.request.content);
|
|
828
|
+
if (prompt && config?.textField && payload[config.textField] === void 0) payload[config.textField] = prompt;
|
|
829
|
+
if (config?.textField && config.textField !== "prompt" && payload[config.textField] === void 0 && payload.prompt !== void 0) payload[config.textField] = payload.prompt;
|
|
830
|
+
const audioBlock = input.request.content.find((block) => block.type === "audio");
|
|
831
|
+
if (audioBlock && payload.url === void 0) payload.url = await input.context.resolveSource(audioBlock.source);
|
|
832
|
+
const imageBlock = input.request.content.find((block) => block.type === "image");
|
|
833
|
+
if (imageBlock && payload.image_url === void 0) payload.image_url = await input.context.resolveSource(imageBlock.source);
|
|
834
|
+
const videoBlock = input.request.content.find((block) => block.type === "video");
|
|
835
|
+
if (videoBlock && payload.video_url === void 0) payload.video_url = await input.context.resolveSource(videoBlock.source);
|
|
836
|
+
normalizeMusicTaskPayload(input, operation, payload);
|
|
837
|
+
if (config?.defaultMusicVersion && payload.mv === void 0 && payload.model_name === void 0) payload.mv = DEFAULT_MUSIC_VERSION;
|
|
838
|
+
validateSunoPayload(operation, payload);
|
|
839
|
+
return payload;
|
|
840
|
+
}
|
|
841
|
+
function contentCount(content, type) {
|
|
842
|
+
return content.filter((block) => block.type === type).length;
|
|
843
|
+
}
|
|
844
|
+
function normalizeMusicTaskPayload(input, operation, payload) {
|
|
845
|
+
if (operation !== "music") return;
|
|
846
|
+
const taskField = input.declaration.meta?.taskField ?? "task";
|
|
847
|
+
const task = asString(payload[taskField]);
|
|
848
|
+
if (!task) return;
|
|
849
|
+
const taskVariant = input.declaration.meta?.taskVariants?.[task];
|
|
850
|
+
if (!taskVariant) throw new GenerationValidationError(`Unsupported Suno music task: ${task}`);
|
|
851
|
+
for (const key of taskVariant.required ?? []) if (payload[key] === void 0 || payload[key] === null || payload[key] === "") throw new GenerationValidationError(`Suno task ${task} requires meta.${key}`);
|
|
852
|
+
for (const type of taskVariant.requiredContent ?? []) if (contentCount(input.request.content, type) === 0) throw new GenerationValidationError(`Suno task ${task} requires ${type} content`);
|
|
853
|
+
if (taskVariant.sendTask === false) delete payload[taskField];
|
|
854
|
+
}
|
|
855
|
+
function validateSunoPayload(operation, payload) {
|
|
856
|
+
const config = OPERATION_PATHS[operation];
|
|
857
|
+
const task = asString(payload.task);
|
|
858
|
+
if (operation === "music" && task) {
|
|
859
|
+
if (task === "lyrics") throw new GenerationValidationError("Use operation=lyrics instead of task=lyrics");
|
|
860
|
+
}
|
|
861
|
+
if (config?.requireText && !asString(payload[config.textField ?? "prompt"])) throw new GenerationValidationError(`${config.textField ?? "prompt"} text is required`);
|
|
862
|
+
if (operation === "upload_audio" && !asString(payload.url)) throw new GenerationValidationError("Audio url is required for Suno upload_audio");
|
|
863
|
+
if (operation === "concat" && !asString(payload.clip_id)) throw new GenerationValidationError("clip_id is required for Suno concat");
|
|
864
|
+
}
|
|
865
|
+
async function requestJson(input, path, init) {
|
|
866
|
+
const response = await fetchWithTimeout(input.context.fetch, joinUrl(input.context.baseUrl, path), {
|
|
867
|
+
...init,
|
|
868
|
+
headers: {
|
|
869
|
+
Authorization: `Bearer ${input.context.apiKey}`,
|
|
870
|
+
"Content-Type": "application/json",
|
|
871
|
+
...init.headers
|
|
872
|
+
}
|
|
873
|
+
}, REQUEST_TIMEOUT_MS);
|
|
874
|
+
const body = await response.text();
|
|
875
|
+
let parsed;
|
|
876
|
+
try {
|
|
877
|
+
parsed = body ? JSON.parse(body) : {};
|
|
878
|
+
} catch {
|
|
879
|
+
throw new GenerationProviderError("Suno provider returned invalid JSON", {
|
|
880
|
+
status: response.status,
|
|
881
|
+
body
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
if (!response.ok) throw new GenerationProviderError("Suno provider request failed", {
|
|
885
|
+
status: response.status,
|
|
886
|
+
details: { body: parsed }
|
|
887
|
+
});
|
|
888
|
+
return parsed;
|
|
889
|
+
}
|
|
890
|
+
function appendUrlBlock(output, type, url, meta) {
|
|
891
|
+
const value = asString(url);
|
|
892
|
+
if (!value) return;
|
|
893
|
+
output.push({
|
|
894
|
+
type,
|
|
895
|
+
source: {
|
|
896
|
+
type: "url",
|
|
897
|
+
url: value
|
|
898
|
+
},
|
|
899
|
+
meta: compactObject(meta)
|
|
900
|
+
});
|
|
901
|
+
}
|
|
902
|
+
function appendSunoContent(output, value, meta = {}) {
|
|
903
|
+
if (Array.isArray(value)) {
|
|
904
|
+
for (const item of value) appendSunoContent(output, item, meta);
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
if (!isRecord$1(value)) return;
|
|
908
|
+
if (isRecord$1(value.clips)) for (const clip of Object.values(value.clips)) appendSunoContent(output, clip, meta);
|
|
909
|
+
if (Array.isArray(value.items)) for (const item of value.items) appendSunoContent(output, item, meta);
|
|
910
|
+
const itemMeta = compactObject({
|
|
911
|
+
...meta,
|
|
912
|
+
id: value.id,
|
|
913
|
+
clip_id: value.clipId ?? value.clip_id ?? meta.clip_id,
|
|
914
|
+
task_id: value.task_id ?? value.taskId ?? meta.task_id,
|
|
915
|
+
title: value.title,
|
|
916
|
+
status: value.status ?? meta.status,
|
|
917
|
+
model: value.model_name ?? value.modelName,
|
|
918
|
+
duration: value.duration ?? (isRecord$1(value.metadata) ? value.metadata.duration : void 0),
|
|
919
|
+
tags: value.tags ?? (isRecord$1(value.metadata) ? value.metadata.tags : void 0),
|
|
920
|
+
prompt: value.prompt ?? (isRecord$1(value.metadata) ? value.metadata.prompt : void 0),
|
|
921
|
+
progress: value.progress ?? meta.progress,
|
|
922
|
+
progress_message: value.progressMsg ?? value.progress_msg,
|
|
923
|
+
task_batch_id: value.taskBatchId ?? value.task_batch_id,
|
|
924
|
+
continue_clip_id: value.continueClipId ?? value.continue_clip_id,
|
|
925
|
+
input_type: value.inputType ?? value.input_type,
|
|
926
|
+
make_instrumental: value.makeInstrumental ?? value.make_instrumental,
|
|
927
|
+
created_at: value.createTime ?? value.created_at
|
|
928
|
+
});
|
|
929
|
+
appendUrlBlock(output, "audio", value.audio_url ?? value.audioUrl ?? value.cld2AudioUrl ?? value.cld2_audio_url, itemMeta);
|
|
930
|
+
appendUrlBlock(output, "audio", value.vocal_audio_url ?? value.vocalAudioUrl, itemMeta);
|
|
931
|
+
appendUrlBlock(output, "audio", value.instrumental_audio_url ?? value.instrumentalAudioUrl, itemMeta);
|
|
932
|
+
appendUrlBlock(output, "audio", value.source_audio_url ?? value.sourceAudioUrl, itemMeta);
|
|
933
|
+
appendUrlBlock(output, "video", value.video_url ?? value.videoUrl ?? value.cld2VideoUrl ?? value.cld2_video_url, itemMeta);
|
|
934
|
+
appendUrlBlock(output, "image", value.image_large_url ?? value.image_url ?? value.imageUrl ?? value.cld2ImageUrl ?? value.cld2_image_url, itemMeta);
|
|
935
|
+
const text = asString(value.upsampled_tags) ?? asString(value.text) ?? asString(value.lyrics);
|
|
936
|
+
if (text) output.push({
|
|
937
|
+
type: "text",
|
|
938
|
+
text,
|
|
939
|
+
meta: itemMeta
|
|
940
|
+
});
|
|
941
|
+
if (isRecord$1(value.data)) appendSunoContent(output, value.data, itemMeta);
|
|
942
|
+
}
|
|
943
|
+
function buildImmediateResult(operation, data, raw) {
|
|
944
|
+
const output = [];
|
|
945
|
+
const metadata = compactObject({
|
|
946
|
+
operation,
|
|
947
|
+
raw
|
|
948
|
+
});
|
|
949
|
+
appendSunoContent(output, data, metadata);
|
|
950
|
+
if (output.length > 0) return output;
|
|
951
|
+
const value = extractTaskId(data) ?? asString(data);
|
|
952
|
+
if (value) output.push({
|
|
953
|
+
type: "text",
|
|
954
|
+
text: value,
|
|
955
|
+
meta: metadata
|
|
956
|
+
});
|
|
957
|
+
return requireSunoOutput(output, "Suno provider returned no output", {
|
|
958
|
+
operation,
|
|
959
|
+
raw
|
|
960
|
+
});
|
|
961
|
+
}
|
|
962
|
+
function requireSunoOutput(output, message, details) {
|
|
963
|
+
if (output.length === 0) throw new GenerationProviderError(message, { details });
|
|
964
|
+
return output;
|
|
965
|
+
}
|
|
966
|
+
function buildResult(operation, task, raw) {
|
|
967
|
+
const output = [];
|
|
968
|
+
const metadata = compactObject({
|
|
969
|
+
operation,
|
|
970
|
+
task_id: task.task_id,
|
|
971
|
+
action: task.action,
|
|
972
|
+
status: task.status,
|
|
973
|
+
fail_reason: task.fail_reason,
|
|
974
|
+
progress: task.progress,
|
|
975
|
+
submit_time: task.submit_time,
|
|
976
|
+
start_time: task.start_time,
|
|
977
|
+
finish_time: task.finish_time,
|
|
978
|
+
raw
|
|
979
|
+
});
|
|
980
|
+
appendSunoContent(output, task.data, metadata);
|
|
981
|
+
appendUrlBlock(output, "audio", task.result_url, metadata);
|
|
982
|
+
return requireSunoOutput(output, "Suno task succeeded but returned no output", {
|
|
983
|
+
operation,
|
|
984
|
+
task,
|
|
985
|
+
raw
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
async function pollSunoTask(input, operation, taskId, pollIntervalSec, maxWaitSec) {
|
|
989
|
+
const startedAt = Date.now();
|
|
990
|
+
while (Date.now() - startedAt <= maxWaitSec * 1e3) {
|
|
991
|
+
await sleep(pollIntervalSec * 1e3);
|
|
992
|
+
let raw;
|
|
993
|
+
try {
|
|
994
|
+
raw = await requestJson(input, `/suno/fetch/${encodeURIComponent(taskId)}`, { method: "GET" });
|
|
995
|
+
} catch (error) {
|
|
996
|
+
if (error instanceof GenerationProviderError) throw error;
|
|
997
|
+
continue;
|
|
998
|
+
}
|
|
999
|
+
const data = requireSuccess(raw, "Suno task fetch failed");
|
|
1000
|
+
const task = normalizeTask(operation, data);
|
|
1001
|
+
if (!task) throw new GenerationProviderError("Suno task fetch returned invalid task data", { details: { data } });
|
|
1002
|
+
const status = normalizeStatus(task.status);
|
|
1003
|
+
if (FINAL_SUCCESS_STATUSES.has(status)) return buildResult(operation, task, data);
|
|
1004
|
+
if (FINAL_FAILURE_STATUSES.has(status)) throw new GenerationProviderError("Suno task failed", { details: {
|
|
1005
|
+
task_id: taskId,
|
|
1006
|
+
status: task.status,
|
|
1007
|
+
fail_reason: task.fail_reason
|
|
1008
|
+
} });
|
|
1009
|
+
}
|
|
1010
|
+
throw new GenerationTimeoutError("Timed out waiting for Suno task", {
|
|
1011
|
+
task_id: taskId,
|
|
1012
|
+
operation
|
|
1013
|
+
});
|
|
1014
|
+
}
|
|
1015
|
+
async function sunoTasksAdapter(input) {
|
|
1016
|
+
const operation = getOperation(input);
|
|
1017
|
+
const payload = await buildPayload(input, operation);
|
|
1018
|
+
const config = OPERATION_PATHS[operation];
|
|
1019
|
+
if (!config) throw new GenerationValidationError(`Unsupported Suno operation: ${operation}`);
|
|
1020
|
+
const raw = await requestJson(input, config.path, {
|
|
1021
|
+
method: "POST",
|
|
1022
|
+
body: JSON.stringify(payload)
|
|
1023
|
+
});
|
|
1024
|
+
const data = requireSuccess(raw, "Suno task submit failed");
|
|
1025
|
+
if (!config.poll) return buildImmediateResult(operation, data, raw);
|
|
1026
|
+
const taskId = extractTaskId(data);
|
|
1027
|
+
if (!taskId) return buildImmediateResult(operation, data, raw);
|
|
1028
|
+
return pollSunoTask(input, operation, taskId, asInteger(input.parameters.poll_interval, DEFAULT_POLL_INTERVAL_SEC), asInteger(input.parameters.max_wait, DEFAULT_MAX_WAIT_SEC));
|
|
1029
|
+
}
|
|
1030
|
+
|
|
671
1031
|
//#endregion
|
|
672
1032
|
//#region src/adapters/index.ts
|
|
673
1033
|
const builtinGenerationAdapters = {
|
|
674
1034
|
"ark.videoGenerations": arkVideoGenerationsAdapter,
|
|
675
1035
|
"gemini.generateContent": geminiGenerateContentAdapter,
|
|
676
|
-
"openai.images": openAiImagesAdapter
|
|
1036
|
+
"openai.images": openAiImagesAdapter,
|
|
1037
|
+
"suno.tasks": sunoTasksAdapter
|
|
677
1038
|
};
|
|
678
1039
|
function getGenerationAdapter(type, adapters = {}) {
|
|
679
1040
|
const adapter = adapters[type] ?? builtinGenerationAdapters[type];
|
|
@@ -700,13 +1061,26 @@ function isParameterSpec(value) {
|
|
|
700
1061
|
"boolean"
|
|
701
1062
|
].includes(String(value.type));
|
|
702
1063
|
}
|
|
1064
|
+
function isMetaFieldSpec(value) {
|
|
1065
|
+
if (!isRecord(value)) return false;
|
|
1066
|
+
return isParameterSpec(value) || String(value.type) === "object";
|
|
1067
|
+
}
|
|
1068
|
+
function isMetaTaskVariantSpec(value) {
|
|
1069
|
+
if (!isRecord(value)) return false;
|
|
1070
|
+
return (value.description === void 0 || typeof value.description === "string") && (value.required === void 0 || Array.isArray(value.required) && value.required.every((item) => typeof item === "string")) && (value.requiredContent === void 0 || Array.isArray(value.requiredContent) && value.requiredContent.every((item) => typeof item === "string")) && (value.sendTask === void 0 || typeof value.sendTask === "boolean");
|
|
1071
|
+
}
|
|
1072
|
+
function isMetaSpec(value) {
|
|
1073
|
+
if (!isRecord(value)) return false;
|
|
1074
|
+
return (value.fields === void 0 || isRecord(value.fields) && Object.values(value.fields).every((field) => isMetaFieldSpec(field))) && (value.taskField === void 0 || typeof value.taskField === "string") && (value.taskVariants === void 0 || isRecord(value.taskVariants) && Object.values(value.taskVariants).every((variant) => isMetaTaskVariantSpec(variant)));
|
|
1075
|
+
}
|
|
703
1076
|
function isGenerationModelDeclaration(value) {
|
|
704
1077
|
if (!isRecord(value)) return false;
|
|
705
1078
|
const adapter = value.adapter;
|
|
706
1079
|
const content = value.content;
|
|
707
1080
|
const parameters = value.parameters;
|
|
1081
|
+
const meta = value.meta;
|
|
708
1082
|
const examples = value.examples;
|
|
709
|
-
return value.schema === MODEL_SCHEMA && typeof value.model === "string" && value.model.trim().length > 0 && isRecord(adapter) && typeof adapter.type === "string" && isRecord(content) && Array.isArray(content.input) && (parameters === void 0 || isRecord(parameters) && Object.values(parameters).every(isParameterSpec)) && (examples === void 0 || Array.isArray(examples));
|
|
1083
|
+
return value.schema === MODEL_SCHEMA && typeof value.model === "string" && value.model.trim().length > 0 && (value.allowUnknownParameters === void 0 || typeof value.allowUnknownParameters === "boolean") && isRecord(adapter) && typeof adapter.type === "string" && isRecord(content) && Array.isArray(content.input) && (parameters === void 0 || isRecord(parameters) && Object.values(parameters).every(isParameterSpec)) && (meta === void 0 || isMetaSpec(meta)) && (examples === void 0 || Array.isArray(examples));
|
|
710
1084
|
}
|
|
711
1085
|
function parseGenerationModelDeclaration(rawText, filePath = "model.yaml") {
|
|
712
1086
|
const parsed = extname(filePath) === ".json" ? JSON.parse(rawText) : parse(rawText);
|
|
@@ -805,10 +1179,15 @@ function createGenerationClient(options = {}) {
|
|
|
805
1179
|
const declaration = requireModel(request.model);
|
|
806
1180
|
validateGenerationContent(declaration, request.content);
|
|
807
1181
|
const parameters = resolveGenerationParameters(declaration, request.parameters);
|
|
1182
|
+
const meta = resolveGenerationMeta(declaration, mergeGenerationMeta({
|
|
1183
|
+
...request.metadata ?? {},
|
|
1184
|
+
...request.meta ?? {}
|
|
1185
|
+
}, request.content), request.content);
|
|
808
1186
|
return {
|
|
809
1187
|
declaration: cloneJson(declaration),
|
|
810
1188
|
request: cloneJson(request),
|
|
811
|
-
parameters
|
|
1189
|
+
parameters,
|
|
1190
|
+
meta
|
|
812
1191
|
};
|
|
813
1192
|
},
|
|
814
1193
|
async generate(request) {
|
|
@@ -880,5 +1259,5 @@ async function exportBuiltinModelConfigs(directory) {
|
|
|
880
1259
|
}
|
|
881
1260
|
|
|
882
1261
|
//#endregion
|
|
883
|
-
export {
|
|
884
|
-
//# sourceMappingURL=export-config-
|
|
1262
|
+
export { GenerationError as A, arkVideoGenerationsAdapter as C, resolveGenerationParameters as D, resolveGenerationMeta as E, GenerationTimeoutError as M, GenerationUnsupportedAdapterError as N, validateGenerationContent as O, GenerationValidationError as P, geminiGenerateContentAdapter as S, mergeTextBlocks as T, writeGenerationModelDeclarations as _, createGenerationClientFromDirectory as a, sunoTasksAdapter as b, defaultGenerationSourceResolver as c, parseGenerationModelDeclaration as d, readGenerationModelDeclaration as f, writeGenerationModelDeclaration as g, stringifyGenerationModelDeclaration as h, createGenerationClient as i, GenerationProviderError as j, GenerationConfigError as k, isGenerationModelDeclaration as l, readGenerationModelDeclarationsFromFiles as m, exportBuiltinModelConfigs as n, createGenerationClientFromFile as o, readGenerationModelDeclarationsFromDirectory as p, stringifyBuiltinModelConfig as r, createGenerationClientFromFiles as s, exportBuiltinModelConfig as t, mergeGenerationModelDeclarations as u, builtinGenerationAdapters as v, mergeGenerationMeta as w, openAiImagesAdapter as x, getGenerationAdapter as y };
|
|
1263
|
+
//# sourceMappingURL=export-config-D8By2_r7.js.map
|