@picsart/ai-sdk 6.15.1 → 6.17.0

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.
Files changed (3) hide show
  1. package/index.d.ts +61 -4
  2. package/index.js +352 -43
  3. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -349,14 +349,30 @@ type ModelInputById = {
349
349
  "gemini-2.5-flash-tts": {
350
350
  language?: string;
351
351
  accent?: string;
352
- prompt: string;
352
+ prompt?: string;
353
353
  voiceId?: string;
354
+ parts?: Array<{
355
+ text: string;
356
+ speaker?: string;
357
+ }>;
358
+ multiSpeakerVoiceConfigs?: Array<{
359
+ speaker: string;
360
+ voiceName: string;
361
+ }>;
354
362
  };
355
363
  "gemini-2.5-pro-tts": {
356
364
  language?: string;
357
365
  accent?: string;
358
- prompt: string;
366
+ prompt?: string;
359
367
  voiceId?: string;
368
+ parts?: Array<{
369
+ text: string;
370
+ speaker?: string;
371
+ }>;
372
+ multiSpeakerVoiceConfigs?: Array<{
373
+ speaker: string;
374
+ voiceName: string;
375
+ }>;
360
376
  };
361
377
  "gemini-3-pro": {
362
378
  prompt: string;
@@ -412,14 +428,34 @@ type ModelInputById = {
412
428
  "gemini-3.8-flash-lite-tts": {
413
429
  language?: string;
414
430
  accent?: string;
415
- prompt: string;
431
+ prompt?: string;
416
432
  voiceId?: string;
433
+ style?: string;
434
+ parts?: Array<{
435
+ text: string;
436
+ speaker?: string;
437
+ style?: string;
438
+ }>;
439
+ multiSpeakerVoiceConfigs?: Array<{
440
+ speaker: string;
441
+ voiceName: string;
442
+ }>;
417
443
  };
418
444
  "gemini-3.8-flash-tts": {
419
445
  language?: string;
420
446
  accent?: string;
421
- prompt: string;
447
+ prompt?: string;
422
448
  voiceId?: string;
449
+ style?: string;
450
+ parts?: Array<{
451
+ text: string;
452
+ speaker?: string;
453
+ style?: string;
454
+ }>;
455
+ multiSpeakerVoiceConfigs?: Array<{
456
+ speaker: string;
457
+ voiceName: string;
458
+ }>;
423
459
  };
424
460
  "gemini-omni-1.1-flash-preview": {
425
461
  prompt: string;
@@ -689,6 +725,25 @@ type ModelInputById = {
689
725
  negativePrompt?: string;
690
726
  cfgScale?: number;
691
727
  };
728
+ "ideogram-4-5": {
729
+ prompt: string;
730
+ imageUrls?: string[];
731
+ mask?: string;
732
+ size?: "auto" | "source" | "2048x2048" | "1440x2880" | "2880x1440" | "1664x2496" | "2496x1664" | "1792x2240" | "2240x1792" | "1440x2560" | "2560x1440" | "1600x2560" | "2560x1600" | "1728x2304" | "2304x1728" | "1296x3168" | "3168x1296" | "1152x2944" | "2944x1152" | "1248x3328" | "3328x1248" | "1280x3072" | "3072x1280" | "1024x3072" | "3072x1024" | "1024x1024" | "896x1120" | "1120x896" | "864x1152" | "1152x864" | "832x1248" | "1248x832" | "800x1280" | "1280x800" | "720x1280" | "1280x720" | "720x1440" | "1440x720" | "512x1536" | "1536x512";
733
+ magicPrompt?: "auto" | "on" | "off";
734
+ quality?: "low" | "medium" | "high";
735
+ count?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
736
+ seed?: number;
737
+ };
738
+ "ideogram-4-5-precise-edit": {
739
+ prompt: string;
740
+ startFrame: string;
741
+ mask?: string;
742
+ imageUrls?: string[];
743
+ quality?: "low" | "medium" | "high" | "very_high";
744
+ count?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
745
+ seed?: number;
746
+ };
692
747
  "ideogram-character": {
693
748
  prompt: string;
694
749
  resolution?: "1024x1024" | "1344x768" | "768x1344" | "1152x864" | "864x1152" | "832x1248" | "1280x800";
@@ -3249,6 +3304,8 @@ declare const Models: {
3249
3304
  readonly HeygenTalkingPhoto: "heygen-talking-photo";
3250
3305
  readonly HeygenVideoAvatar: "heygen-video-avatar";
3251
3306
  readonly HunyuanV3: "hunyuan-v3";
3307
+ readonly Ideogram45: "ideogram-4-5";
3308
+ readonly Ideogram45PreciseEdit: "ideogram-4-5-precise-edit";
3252
3309
  readonly IdeogramCharacter: "ideogram-character";
3253
3310
  readonly IdeogramPImage: "ideogram-p-image";
3254
3311
  readonly IdeogramV3: "ideogram-v3";
package/index.js CHANGED
@@ -6453,11 +6453,6 @@ var buildGemini31FlashLiteImagePayload = (ctx) => ({
6453
6453
  imageSize: ctx.resolution ?? "1K",
6454
6454
  ...buildThinkingConfig(ctx)
6455
6455
  });
6456
- var buildGeminiTTSPayload = (model) => (ctx) => ({
6457
- text: ctx.prompt,
6458
- model,
6459
- voiceName: ctx.voiceId ?? "Kore"
6460
- });
6461
6456
  function inferMimeType2(url) {
6462
6457
  return url.match(/\.png(\?|$)/i) ? "image/png" : "image/jpeg";
6463
6458
  }
@@ -6469,6 +6464,52 @@ var buildGeminiOmniVideoPayload = (ctx) => ({
6469
6464
  ...ctx.imageUrls?.[0] ? { image: { url: ctx.imageUrls[0], mimeType: inferMimeType2(ctx.imageUrls[0]) } } : {},
6470
6465
  ...ctx.videoUrl ? { video: { url: ctx.videoUrl } } : {}
6471
6466
  });
6467
+ var GEMINI_TTS_TEXT_MAX = 6e3;
6468
+ var GEMINI_TTS_STYLE_MAX = 500;
6469
+ var geminiTtsParams = (directable) => ({
6470
+ ...params.language(true),
6471
+ // 6,000 boundary-verified against the live gemini/v1/audios worker
6472
+ // (accepts >5,000; see scripts/api-tests/audio-charlimit-boundary-probe.mjs).
6473
+ ...params.prompt({ required: false, maxLength: GEMINI_TTS_TEXT_MAX }),
6474
+ ...params.voiceId([], GEMINI_DEFAULT_VOICE_ID, { catalog: { workflow: "gemini/v1/catalog/voices" } }),
6475
+ ...directable ? {
6476
+ style: {
6477
+ label: "Style",
6478
+ descriptor: {
6479
+ kind: "text",
6480
+ maxLength: GEMINI_TTS_STYLE_MAX,
6481
+ placeholder: "e.g. warm, unhurried; a bedtime story"
6482
+ }
6483
+ }
6484
+ } : {},
6485
+ // Worker `SpeechPartDto[]`, same names. Used instead of `prompt`.
6486
+ parts: {
6487
+ label: "Spoken Parts",
6488
+ descriptor: {
6489
+ kind: "object",
6490
+ array: { min: 1, max: 200 },
6491
+ fields: {
6492
+ text: { label: "Text", kind: "text", maxLength: GEMINI_TTS_TEXT_MAX },
6493
+ speaker: { label: "Speaker", kind: "text", required: false },
6494
+ ...directable ? { style: { label: "Style", kind: "text", maxLength: GEMINI_TTS_STYLE_MAX, required: false } } : {}
6495
+ }
6496
+ }
6497
+ },
6498
+ // Worker `SpeakerVoiceConfigDto[]`, max 2. Replaces `voiceId`. The voice is
6499
+ // a plain id, not a catalog picker: catalog loading resolves top-level params
6500
+ // only, so a caller lists voices with `ai.catalogs.voices(<model>)`.
6501
+ multiSpeakerVoiceConfigs: {
6502
+ label: "Speakers",
6503
+ descriptor: {
6504
+ kind: "object",
6505
+ array: { min: 1, max: 2 },
6506
+ fields: {
6507
+ speaker: { label: "Speaker", kind: "text", placeholder: "Speaker 1" },
6508
+ voiceName: { label: "Voice", kind: "text", placeholder: GEMINI_DEFAULT_VOICE_ID }
6509
+ }
6510
+ }
6511
+ }
6512
+ });
6472
6513
  var GEMINI_AR_WIDE = ["1:1", "16:9", "9:16", "3:4", "4:3", "2:3", "21:9", "auto"];
6473
6514
  var thinkingLevelParam = {
6474
6515
  thinkingLevel: {
@@ -6586,32 +6627,35 @@ var { MODELS: MODELS22 } = defineModels("google", [
6586
6627
  }
6587
6628
  },
6588
6629
  // ── Audio ─────────────────────────────────────────────────────────
6630
+ // Payload builders live in gemini.payloads.ts (typed against ModelInput).
6631
+ // The wire `model` is fixed per entry there: `modelId` is the pricing key and
6632
+ // never reaches the builder.
6633
+ //
6634
+ // 2.5 and 3.8 take direction and speakers differently, so the builders
6635
+ // resolve them per generation. 3.8 reads `style` and per-part speakers from
6636
+ // `speechMetadata` and speaks a natural-language prefix in the text aloud:
6637
+ // `parts` go through and `language` / `accent` fold into `style`. 2.5
6638
+ // ignores `speechMetadata`: it reads speakers from "Speaker: line" labels
6639
+ // and direction from a "Say …:" prefix, so the builder writes both into
6640
+ // one text.
6589
6641
  {
6590
6642
  id: "gemini-2.5-flash-tts",
6591
6643
  name: "Gemini 2.5 Flash TTS",
6592
6644
  addedAt: "2026-02-15",
6593
6645
  workflow: "gemini/v1/audios",
6594
- buildPayload: buildGeminiTTSPayload("gemini-2.5-flash-tts"),
6595
6646
  estimatedTime: 15,
6596
6647
  mode: "audio",
6597
6648
  inputType: "tts",
6598
6649
  modelId: "gemini-2.5-flash-tts",
6599
6650
  description: "Google Gemini native text-to-speech with expressive multilingual voices.",
6600
- features: [feat("Multilingual", "characteristic"), feat("30 Voices", "characteristic")],
6601
- paramConfig: {
6602
- ...params.language(true),
6603
- // 6,000 boundary-verified against the live gemini/v1/audios worker
6604
- // (accepts >5,000; see scripts/api-tests/audio-charlimit-boundary-probe.mjs).
6605
- ...params.prompt({ maxLength: 6e3 }),
6606
- ...params.voiceId([], GEMINI_DEFAULT_VOICE_ID, { catalog: { workflow: "gemini/v1/catalog/voices" } })
6607
- }
6651
+ features: [feat("Multilingual", "characteristic"), feat("30 Voices", "characteristic"), feat("Multi-Speaker", "characteristic")],
6652
+ paramConfig: geminiTtsParams(false)
6608
6653
  },
6609
6654
  {
6610
6655
  id: "gemini-2.5-pro-tts",
6611
6656
  name: "Gemini 2.5 Pro TTS",
6612
6657
  addedAt: "2026-03-18",
6613
6658
  workflow: "gemini/v1/audios",
6614
- buildPayload: buildGeminiTTSPayload("gemini-2.5-pro-tts"),
6615
6659
  estimatedTime: 20,
6616
6660
  mode: "audio",
6617
6661
  inputType: "tts",
@@ -6619,54 +6663,34 @@ var { MODELS: MODELS22 } = defineModels("google", [
6619
6663
  badge: ["premium"],
6620
6664
  description: "Premium Gemini TTS with richer expressiveness and multi-speaker support.",
6621
6665
  features: [feat("Multilingual", "characteristic"), feat("30 Voices", "characteristic"), feat("Multi-Speaker", "characteristic")],
6622
- paramConfig: {
6623
- ...params.language(true),
6624
- // 6,000 boundary-verified against the live gemini/v1/audios worker
6625
- // (accepts >5,000; see scripts/api-tests/audio-charlimit-boundary-probe.mjs).
6626
- ...params.prompt({ maxLength: 6e3 }),
6627
- ...params.voiceId([], GEMINI_DEFAULT_VOICE_ID, { catalog: { workflow: "gemini/v1/catalog/voices" } })
6628
- }
6666
+ paramConfig: geminiTtsParams(false)
6629
6667
  },
6630
6668
  {
6631
6669
  id: "gemini-3.8-flash-tts",
6632
6670
  name: "Gemini 3.8 Flash TTS",
6633
6671
  addedAt: "2026-09-24",
6634
6672
  workflow: "gemini/v1/audios",
6635
- buildPayload: buildGeminiTTSPayload("gemini-3.8-flash-tts"),
6636
6673
  estimatedTime: 15,
6637
6674
  mode: "audio",
6638
6675
  inputType: "tts",
6639
6676
  modelId: "gemini-3.8-flash-tts",
6640
- description: "Latest Gemini native text-to-speech with expressive multilingual voices.",
6641
- features: [feat("Multilingual", "characteristic"), feat("30 Voices", "characteristic")],
6642
- paramConfig: {
6643
- ...params.language(true),
6644
- // 6,000 boundary-verified against the live gemini/v1/audios worker
6645
- // (accepts >5,000; see scripts/api-tests/audio-charlimit-boundary-probe.mjs).
6646
- ...params.prompt({ maxLength: 6e3 }),
6647
- ...params.voiceId([], GEMINI_DEFAULT_VOICE_ID, { catalog: { workflow: "gemini/v1/catalog/voices" } })
6648
- }
6677
+ description: "Latest Gemini native text-to-speech with directable delivery and inline vocal events like <laugh> and <sigh>.",
6678
+ features: [feat("Multilingual", "characteristic"), feat("30 Voices", "characteristic"), feat("Multi-Speaker", "characteristic"), feat("Style Direction", "characteristic")],
6679
+ paramConfig: geminiTtsParams(true)
6649
6680
  },
6650
6681
  {
6651
6682
  id: "gemini-3.8-flash-lite-tts",
6652
6683
  name: "Gemini 3.8 Flash Lite TTS",
6653
6684
  addedAt: "2026-09-24",
6654
6685
  workflow: "gemini/v1/audios",
6655
- buildPayload: buildGeminiTTSPayload("gemini-3.8-flash-lite-tts"),
6656
6686
  estimatedTime: 12,
6657
6687
  mode: "audio",
6658
6688
  inputType: "tts",
6659
6689
  modelId: "gemini-3.8-flash-lite-tts",
6660
6690
  badge: ["fast"],
6661
- description: "Lightweight Gemini 3.8 TTS variant for faster, high-volume speech synthesis.",
6662
- features: [feat("Multilingual", "characteristic"), feat("30 Voices", "characteristic")],
6663
- paramConfig: {
6664
- ...params.language(true),
6665
- // 6,000 boundary-verified against the live gemini/v1/audios worker
6666
- // (accepts >5,000; see scripts/api-tests/audio-charlimit-boundary-probe.mjs).
6667
- ...params.prompt({ maxLength: 6e3 }),
6668
- ...params.voiceId([], GEMINI_DEFAULT_VOICE_ID, { catalog: { workflow: "gemini/v1/catalog/voices" } })
6669
- }
6691
+ description: "Lightweight Gemini 3.8 TTS with directable delivery for faster, high-volume speech synthesis.",
6692
+ features: [feat("Multilingual", "characteristic"), feat("30 Voices", "characteristic"), feat("Multi-Speaker", "characteristic"), feat("Style Direction", "characteristic")],
6693
+ paramConfig: geminiTtsParams(true)
6670
6694
  },
6671
6695
  // ── Video ─────────────────────────────────────────────────────────
6672
6696
  {
@@ -6733,8 +6757,95 @@ var buildOmniFlash11Payload = (input) => ({
6733
6757
  ...input.videoUrl ? { video: { url: input.videoUrl } } : {},
6734
6758
  ...input.videoUrls?.length ? { referenceVideos: input.videoUrls.map((url) => ({ url })) } : {}
6735
6759
  });
6760
+ var STYLE_MAX = 500;
6761
+ var TEXT_MAX = 6e3;
6762
+ var invalid = (message) => new ApiError(message, { status: 400, code: "validation_error" });
6763
+ var blank = (value) => !value?.trim();
6764
+ function checkInput(input) {
6765
+ const configs = input.multiSpeakerVoiceConfigs ?? [];
6766
+ for (const [i, config] of configs.entries()) {
6767
+ if (blank(config.speaker)) throw invalid(`Gemini TTS: speaker config ${i + 1} has no speaker.`);
6768
+ if (blank(config.voiceName)) throw invalid(`Gemini TTS: speaker config ${i + 1} has no voiceName.`);
6769
+ }
6770
+ const speakers = configs.map((config) => config.speaker);
6771
+ if (new Set(speakers).size !== speakers.length) {
6772
+ throw invalid("Gemini TTS: multiSpeakerVoiceConfigs names the same speaker twice.");
6773
+ }
6774
+ const parts = input.parts?.length ? input.parts : void 0;
6775
+ if (!parts) {
6776
+ if (blank(input.prompt)) throw invalid("Gemini TTS: provide a prompt or parts.");
6777
+ return { speakers };
6778
+ }
6779
+ for (const [i, part] of parts.entries()) {
6780
+ if (blank(part.text)) throw invalid(`Gemini TTS: part ${i + 1} has no text.`);
6781
+ if (speakers.length && (!part.speaker || !speakers.includes(part.speaker))) {
6782
+ throw invalid(
6783
+ `Gemini TTS: part ${i + 1} needs a speaker from multiSpeakerVoiceConfigs (${speakers.join(", ")}).`
6784
+ );
6785
+ }
6786
+ if (!speakers.length && part.speaker) {
6787
+ throw invalid(`Gemini TTS: part ${i + 1} names a speaker but no multiSpeakerVoiceConfigs are set.`);
6788
+ }
6789
+ }
6790
+ return { parts, speakers };
6791
+ }
6792
+ function assertLength(spoken) {
6793
+ if (spoken.length > TEXT_MAX) {
6794
+ throw invalid(`Gemini TTS: the text totals ${spoken.length} characters; the limit is ${TEXT_MAX}.`);
6795
+ }
6796
+ }
6797
+ var voiceFields = (input) => input.multiSpeakerVoiceConfigs?.length ? { multiSpeakerVoiceConfigs: input.multiSpeakerVoiceConfigs } : { voiceName: input.voiceId ?? GEMINI_DEFAULT_VOICE_ID };
6798
+ function composeStyle(input) {
6799
+ const language = input.language?.trim();
6800
+ const accent = input.accent?.trim();
6801
+ const voice = language || accent ? `speak${language ? ` in ${language}` : ""}${accent ? ` with a ${accent} accent` : ""}` : void 0;
6802
+ const composed = [...input.styles.map((style) => style?.trim()), voice].filter(Boolean).join("; ") || void 0;
6803
+ if (composed && composed.length > STYLE_MAX) {
6804
+ throw invalid(`Gemini TTS: style with language/accent exceeds ${STYLE_MAX} characters.`);
6805
+ }
6806
+ return composed;
6807
+ }
6808
+ function directionPrefix(input) {
6809
+ const language = input.language?.trim();
6810
+ const accent = input.accent?.trim();
6811
+ if (!language && !accent) return "";
6812
+ return `Say${language ? ` in ${language}` : ""}${accent ? ` with a ${accent} accent` : ""}: `;
6813
+ }
6814
+ var buildTts25Payload = (model) => (input) => {
6815
+ const { parts, speakers } = checkInput(input);
6816
+ const body = parts ? parts.map((part) => speakers.length ? `${part.speaker}: ${part.text}` : part.text).join("\n") : input.prompt;
6817
+ const text = `${directionPrefix(input)}${body}`;
6818
+ assertLength(text);
6819
+ return { text, model, ...voiceFields(input) };
6820
+ };
6821
+ var buildTts38Payload = (model) => (input) => {
6822
+ const { parts } = checkInput(input);
6823
+ const direction = { language: input.language, accent: input.accent };
6824
+ if (!parts) {
6825
+ assertLength(input.prompt);
6826
+ const style = composeStyle({ styles: [input.style], ...direction });
6827
+ return { text: input.prompt, model, ...voiceFields(input), ...style ? { style } : {} };
6828
+ }
6829
+ assertLength(parts.map((part) => part.text).join("\n"));
6830
+ return {
6831
+ parts: parts.map((part) => {
6832
+ const style = composeStyle({ styles: [input.style, part.style], ...direction });
6833
+ return {
6834
+ text: part.text,
6835
+ ...part.speaker ? { speaker: part.speaker } : {},
6836
+ ...style ? { style } : {}
6837
+ };
6838
+ }),
6839
+ model,
6840
+ ...voiceFields(input)
6841
+ };
6842
+ };
6736
6843
  registerPayloads(MODELS22, {
6737
- "gemini-omni-1.1-flash-preview": buildOmniFlash11Payload
6844
+ "gemini-omni-1.1-flash-preview": buildOmniFlash11Payload,
6845
+ "gemini-2.5-flash-tts": buildTts25Payload("gemini-2.5-flash-tts"),
6846
+ "gemini-2.5-pro-tts": buildTts25Payload("gemini-2.5-pro-tts"),
6847
+ "gemini-3.8-flash-tts": buildTts38Payload("gemini-3.8-flash-tts"),
6848
+ "gemini-3.8-flash-lite-tts": buildTts38Payload("gemini-3.8-flash-lite-tts")
6738
6849
  });
6739
6850
 
6740
6851
  // src/vendors/catalog/openai.ts
@@ -7691,7 +7802,138 @@ var buildIdeogramPImagePayload = (ctx) => ({
7691
7802
  resolution: ctx.resolution ?? "1024x1024",
7692
7803
  rendering_speed: ctx.renderingSpeed ?? "medium"
7693
7804
  });
7805
+ var IDEOGRAM_45_IMAGE_BOUNDS = {
7806
+ maxBytes: 25 * 1024 * 1024,
7807
+ minAspectRatio: 1 / 6,
7808
+ maxAspectRatio: 6
7809
+ };
7810
+ var IDEOGRAM_45_T2I_SIZES = [
7811
+ "2048x2048",
7812
+ "1440x2880",
7813
+ "2880x1440",
7814
+ "1664x2496",
7815
+ "2496x1664",
7816
+ "1792x2240",
7817
+ "2240x1792",
7818
+ "1440x2560",
7819
+ "2560x1440",
7820
+ "1600x2560",
7821
+ "2560x1600",
7822
+ "1728x2304",
7823
+ "2304x1728",
7824
+ "1296x3168",
7825
+ "3168x1296",
7826
+ "1152x2944",
7827
+ "2944x1152",
7828
+ "1248x3328",
7829
+ "3328x1248",
7830
+ "1280x3072",
7831
+ "3072x1280",
7832
+ "1024x3072",
7833
+ "3072x1024",
7834
+ "1024x1024",
7835
+ "896x1120",
7836
+ "1120x896",
7837
+ "864x1152",
7838
+ "1152x864",
7839
+ "832x1248",
7840
+ "1248x832",
7841
+ "800x1280",
7842
+ "1280x800",
7843
+ "720x1280",
7844
+ "1280x720",
7845
+ "720x1440",
7846
+ "1440x720",
7847
+ "512x1536",
7848
+ "1536x512"
7849
+ ];
7850
+ var ideogram45MaskParam = p.file("mask", "image", {
7851
+ label: "Mask",
7852
+ category: "asset",
7853
+ ...IDEOGRAM_45_IMAGE_BOUNDS
7854
+ });
7855
+ var ideogram45MagicPromptParam = {
7856
+ magicPrompt: {
7857
+ label: "Magic Prompt",
7858
+ descriptor: {
7859
+ kind: "enum",
7860
+ valueType: "string",
7861
+ options: [
7862
+ { id: "auto", label: "Auto" },
7863
+ { id: "on", label: "On" },
7864
+ { id: "off", label: "Off (verbatim)" }
7865
+ ],
7866
+ default: "auto"
7867
+ }
7868
+ }
7869
+ };
7870
+ var IDEOGRAM_45_COUNTS = [1, 2, 3, 4, 5, 6, 7, 8];
7871
+ var ideogram45Constraints = [
7872
+ { when: { imageUrls: { exists: false } }, then: {
7873
+ size: { allowed: ["auto", ...IDEOGRAM_45_T2I_SIZES] },
7874
+ mask: { disabled: true, reason: "A mask needs a source image." }
7875
+ } },
7876
+ { when: { imageUrls: { exists: true } }, then: {
7877
+ size: { allowed: ["auto", "source"], reason: 'With input images the size is "auto" or the source image size.' }
7878
+ } },
7879
+ { when: { mask: { exists: true } }, then: {
7880
+ size: { disabled: true, reason: "A masked edit keeps the source image size." }
7881
+ } }
7882
+ ];
7883
+ var ideogram45PreciseEditConstraints = [
7884
+ { when: { quality: { is: "very_high" } }, then: {
7885
+ count: { allowed: [1, 2, 3, 4], reason: "Very high quality returns at most 4 images." }
7886
+ } }
7887
+ ];
7694
7888
  var { MODELS: MODELS26 } = defineModels("ideogram", [
7889
+ {
7890
+ id: "ideogram-4-5",
7891
+ name: "Ideogram 4.5",
7892
+ addedAt: "2026-09-28",
7893
+ release: "preview",
7894
+ workflow: "ideogram/v4.5/generate",
7895
+ estimatedTime: 30,
7896
+ mode: "image",
7897
+ inputType: "t2i",
7898
+ description: "Ideogram 4.5 \u2014 text-to-image and drift-free iterative editing with up to 4 reference images and an optional mask.",
7899
+ features: [feat("Reference Images", "input"), feat("Masked Edit", "input"), feat("2K", "resolution")],
7900
+ constraints: ideogram45Constraints,
7901
+ paramConfig: {
7902
+ ...params.prompt({ maxLength: 1e4 }),
7903
+ // imageUrls[0] is the source image to edit; the rest are references ("image 2", "image 3"…).
7904
+ // With a mask the vendor allows at most 4 images.
7905
+ ...params.imageInput(5, "Images", false, "reference", IDEOGRAM_45_IMAGE_BOUNDS),
7906
+ ...ideogram45MaskParam,
7907
+ ...p.size(["auto", "source", ...IDEOGRAM_45_T2I_SIZES], "auto"),
7908
+ ...ideogram45MagicPromptParam,
7909
+ ...p.quality(["low", "medium", "high"], "high"),
7910
+ ...params.count(IDEOGRAM_45_COUNTS, 1),
7911
+ ...params.seed()
7912
+ }
7913
+ },
7914
+ {
7915
+ id: "ideogram-4-5-precise-edit",
7916
+ name: "Ideogram 4.5 Precise Edit",
7917
+ addedAt: "2026-09-28",
7918
+ release: "preview",
7919
+ workflow: "ideogram/v4.5/precise-edit",
7920
+ estimatedTime: 40,
7921
+ mode: "image",
7922
+ inputType: "i2i",
7923
+ description: "Ideogram 4.5 precise edit \u2014 change one area and keep the rest of the image pixel-intact, optionally with a mask and reference images.",
7924
+ features: [feat("Precise Edit", "input"), feat("Masked Edit", "input"), feat("Reference Images", "input")],
7925
+ constraints: ideogram45PreciseEditConstraints,
7926
+ paramConfig: {
7927
+ ...params.prompt({ maxLength: 1e4 }),
7928
+ ...params.startFrame("Source Image", true, IDEOGRAM_45_IMAGE_BOUNDS),
7929
+ ...ideogram45MaskParam,
7930
+ // With a mask the vendor allows at most 3 references.
7931
+ ...params.imageInput(4, "Reference Images", false, "reference", IDEOGRAM_45_IMAGE_BOUNDS),
7932
+ ...p.quality(["low", "medium", "high", "very_high"], "high"),
7933
+ ...params.count(IDEOGRAM_45_COUNTS, 1),
7934
+ ...params.seed()
7935
+ }
7936
+ },
7695
7937
  {
7696
7938
  id: "ideogram-v4",
7697
7939
  name: "Ideogram 4.0",
@@ -7888,6 +8130,69 @@ var { MODELS: MODELS26 } = defineModels("ideogram", [
7888
8130
  }
7889
8131
  ]);
7890
8132
 
8133
+ // src/vendors/catalog/ideogram.payloads.ts
8134
+ var GENERATE_MAX_IMAGES_WITH_MASK = 4;
8135
+ var PRECISE_EDIT_MAX_REFERENCES_WITH_MASK = 3;
8136
+ var VERY_HIGH_MAX_COUNT = 4;
8137
+ function assertMaskedImageLimit(model, count, max, what) {
8138
+ if (count > max) {
8139
+ throw new ApiError(`${model}: with a mask, use at most ${max} ${what} (got ${count}).`, {
8140
+ status: 400,
8141
+ code: "validation_error"
8142
+ });
8143
+ }
8144
+ }
8145
+ function ideogram45Size(size, hasImages, hasMask) {
8146
+ if (!size || hasMask) return void 0;
8147
+ if (hasImages) return size === "auto" || size === "source" ? size : void 0;
8148
+ return size === "source" ? void 0 : size;
8149
+ }
8150
+ var buildIdeogram45Payload = (input) => {
8151
+ const images = input.imageUrls?.length ? input.imageUrls : void 0;
8152
+ const mask = images && input.mask ? input.mask : void 0;
8153
+ if (mask) assertMaskedImageLimit("Ideogram 4.5", images.length, GENERATE_MAX_IMAGES_WITH_MASK, "images");
8154
+ const size = ideogram45Size(input.size, !!images, !!mask);
8155
+ return {
8156
+ prompt: input.prompt,
8157
+ ...images ? { images } : {},
8158
+ ...mask ? { mask } : {},
8159
+ ...size ? { size } : {},
8160
+ ...input.magicPrompt ? { magic_prompt: input.magicPrompt } : {},
8161
+ quality: input.quality ?? "high",
8162
+ num_images: input.count ?? 1,
8163
+ ...input.seed != null ? { seed: input.seed } : {}
8164
+ };
8165
+ };
8166
+ var buildIdeogram45PreciseEditPayload = (input) => {
8167
+ if (input.mask) {
8168
+ assertMaskedImageLimit(
8169
+ "Ideogram 4.5 Precise Edit",
8170
+ input.imageUrls?.length ?? 0,
8171
+ PRECISE_EDIT_MAX_REFERENCES_WITH_MASK,
8172
+ "reference images"
8173
+ );
8174
+ }
8175
+ if (input.quality === "very_high" && (input.count ?? 1) > VERY_HIGH_MAX_COUNT) {
8176
+ throw new ApiError(
8177
+ `Ideogram 4.5 Precise Edit: very_high quality returns at most ${VERY_HIGH_MAX_COUNT} images (got ${input.count}).`,
8178
+ { status: 400, code: "validation_error" }
8179
+ );
8180
+ }
8181
+ return {
8182
+ image: input.startFrame,
8183
+ prompt: input.prompt,
8184
+ ...input.mask ? { mask: input.mask } : {},
8185
+ ...input.imageUrls?.length ? { reference_images: input.imageUrls } : {},
8186
+ quality: input.quality ?? "high",
8187
+ num_images: input.count ?? 1,
8188
+ ...input.seed != null ? { seed: input.seed } : {}
8189
+ };
8190
+ };
8191
+ registerPayloads(MODELS26, {
8192
+ "ideogram-4-5": buildIdeogram45Payload,
8193
+ "ideogram-4-5-precise-edit": buildIdeogram45PreciseEditPayload
8194
+ });
8195
+
7891
8196
  // src/vendors/catalog/qwen.ts
7892
8197
  var QWEN_V1_SIZES = [
7893
8198
  "2048x2048",
@@ -13002,6 +13307,8 @@ var Happyhorse11T2v = "happyhorse-1.1-t2v";
13002
13307
  var HeygenTalkingPhoto = "heygen-talking-photo";
13003
13308
  var HeygenVideoAvatar = "heygen-video-avatar";
13004
13309
  var HunyuanV3 = "hunyuan-v3";
13310
+ var Ideogram45 = "ideogram-4-5";
13311
+ var Ideogram45PreciseEdit = "ideogram-4-5-precise-edit";
13005
13312
  var IdeogramCharacter = "ideogram-character";
13006
13313
  var IdeogramPImage = "ideogram-p-image";
13007
13314
  var IdeogramV3 = "ideogram-v3";
@@ -13255,6 +13562,8 @@ var Models = {
13255
13562
  HeygenTalkingPhoto,
13256
13563
  HeygenVideoAvatar,
13257
13564
  HunyuanV3,
13565
+ Ideogram45,
13566
+ Ideogram45PreciseEdit,
13258
13567
  IdeogramCharacter,
13259
13568
  IdeogramPImage,
13260
13569
  IdeogramV3,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@picsart/ai-sdk",
3
- "version": "6.15.1",
3
+ "version": "6.17.0",
4
4
  "type": "module",
5
5
  "description": "Type-safe SDK for 100+ AI models — image, video, audio, and text generation with Picsart",
6
6
  "license": "MIT",