@contractspec/lib.image-gen 0.2.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 (86) hide show
  1. package/dist/browser/docs/generators.docblock.js +36 -0
  2. package/dist/browser/docs/image-gen.docblock.js +47 -0
  3. package/dist/browser/generators/image-generator.js +525 -0
  4. package/dist/browser/generators/index.js +527 -0
  5. package/dist/browser/generators/prompt-builder.js +93 -0
  6. package/dist/browser/generators/style-resolver.js +90 -0
  7. package/dist/browser/i18n/catalogs/en.js +85 -0
  8. package/dist/browser/i18n/catalogs/es.js +85 -0
  9. package/dist/browser/i18n/catalogs/fr.js +85 -0
  10. package/dist/browser/i18n/catalogs/index.js +253 -0
  11. package/dist/browser/i18n/index.js +309 -0
  12. package/dist/browser/i18n/keys.js +33 -0
  13. package/dist/browser/i18n/locale.js +13 -0
  14. package/dist/browser/i18n/messages.js +265 -0
  15. package/dist/browser/index.js +623 -0
  16. package/dist/browser/presets/index.js +99 -0
  17. package/dist/browser/presets/marketing.js +35 -0
  18. package/dist/browser/presets/social.js +45 -0
  19. package/dist/browser/presets/video.js +25 -0
  20. package/dist/browser/types.js +5 -0
  21. package/dist/docs/generators.docblock.d.ts +1 -0
  22. package/dist/docs/generators.docblock.js +37 -0
  23. package/dist/docs/image-gen.docblock.d.ts +1 -0
  24. package/dist/docs/image-gen.docblock.js +48 -0
  25. package/dist/generators/image-generator.d.ts +12 -0
  26. package/dist/generators/image-generator.js +526 -0
  27. package/dist/generators/image-generator.test.d.ts +1 -0
  28. package/dist/generators/index.d.ts +4 -0
  29. package/dist/generators/index.js +528 -0
  30. package/dist/generators/prompt-builder.d.ts +21 -0
  31. package/dist/generators/prompt-builder.js +94 -0
  32. package/dist/generators/prompt-builder.test.d.ts +1 -0
  33. package/dist/generators/style-resolver.d.ts +9 -0
  34. package/dist/generators/style-resolver.js +91 -0
  35. package/dist/generators/style-resolver.test.d.ts +1 -0
  36. package/dist/i18n/catalogs/en.d.ts +8 -0
  37. package/dist/i18n/catalogs/en.js +86 -0
  38. package/dist/i18n/catalogs/es.d.ts +6 -0
  39. package/dist/i18n/catalogs/es.js +86 -0
  40. package/dist/i18n/catalogs/fr.d.ts +6 -0
  41. package/dist/i18n/catalogs/fr.js +86 -0
  42. package/dist/i18n/catalogs/index.d.ts +3 -0
  43. package/dist/i18n/catalogs/index.js +254 -0
  44. package/dist/i18n/i18n.test.d.ts +1 -0
  45. package/dist/i18n/index.d.ts +6 -0
  46. package/dist/i18n/index.js +310 -0
  47. package/dist/i18n/keys.d.ts +78 -0
  48. package/dist/i18n/keys.js +34 -0
  49. package/dist/i18n/locale.d.ts +8 -0
  50. package/dist/i18n/locale.js +14 -0
  51. package/dist/i18n/messages.d.ts +14 -0
  52. package/dist/i18n/messages.js +266 -0
  53. package/dist/index.d.ts +3 -0
  54. package/dist/index.js +624 -0
  55. package/dist/node/docs/generators.docblock.js +36 -0
  56. package/dist/node/docs/image-gen.docblock.js +47 -0
  57. package/dist/node/generators/image-generator.js +525 -0
  58. package/dist/node/generators/index.js +527 -0
  59. package/dist/node/generators/prompt-builder.js +93 -0
  60. package/dist/node/generators/style-resolver.js +90 -0
  61. package/dist/node/i18n/catalogs/en.js +85 -0
  62. package/dist/node/i18n/catalogs/es.js +85 -0
  63. package/dist/node/i18n/catalogs/fr.js +85 -0
  64. package/dist/node/i18n/catalogs/index.js +253 -0
  65. package/dist/node/i18n/index.js +309 -0
  66. package/dist/node/i18n/keys.js +33 -0
  67. package/dist/node/i18n/locale.js +13 -0
  68. package/dist/node/i18n/messages.js +265 -0
  69. package/dist/node/index.js +623 -0
  70. package/dist/node/presets/index.js +99 -0
  71. package/dist/node/presets/marketing.js +35 -0
  72. package/dist/node/presets/social.js +45 -0
  73. package/dist/node/presets/video.js +25 -0
  74. package/dist/node/types.js +5 -0
  75. package/dist/presets/index.d.ts +3 -0
  76. package/dist/presets/index.js +100 -0
  77. package/dist/presets/marketing.d.ts +8 -0
  78. package/dist/presets/marketing.js +36 -0
  79. package/dist/presets/presets.test.d.ts +1 -0
  80. package/dist/presets/social.d.ts +10 -0
  81. package/dist/presets/social.js +46 -0
  82. package/dist/presets/video.d.ts +6 -0
  83. package/dist/presets/video.js +26 -0
  84. package/dist/types.d.ts +56 -0
  85. package/dist/types.js +6 -0
  86. package/package.json +394 -0
@@ -0,0 +1,623 @@
1
+ // src/i18n/catalogs/en.ts
2
+ import { defineTranslation } from "@contractspec/lib.contracts-spec/translations";
3
+ var enMessages = defineTranslation({
4
+ meta: {
5
+ key: "image-gen.messages",
6
+ version: "1.0.0",
7
+ domain: "image-gen",
8
+ description: "All user-facing, LLM-facing, and developer-facing strings for the image-gen package",
9
+ owners: ["platform"],
10
+ stability: "experimental"
11
+ },
12
+ locale: "en",
13
+ fallback: "en",
14
+ messages: {
15
+ "prompt.system.imagePromptEngineer": {
16
+ value: "You are an expert image prompt engineer. Given a JSON brief containing title, summary, problems, solutions, purpose, style, and style tokens, produce a single detailed image generation prompt. The prompt should be vivid, specific, and optimized for AI image generation models. Focus on composition, lighting, color palette, and subject matter. Output only the prompt text, no JSON.",
17
+ description: "System prompt for LLM-based image prompt engineering"
18
+ },
19
+ "image.generate.description": {
20
+ value: "Generate a {style} image for {purpose}",
21
+ description: "Description template for image generation tasks",
22
+ placeholders: [
23
+ { name: "style", type: "string" },
24
+ { name: "purpose", type: "string" }
25
+ ]
26
+ },
27
+ "image.prompt.featuring": {
28
+ value: "featuring {solutions}",
29
+ description: "Prompt fragment for featured solutions",
30
+ placeholders: [{ name: "solutions", type: "string" }]
31
+ },
32
+ "image.prompt.industryContext": {
33
+ value: "{industry} context",
34
+ description: "Prompt fragment for industry context",
35
+ placeholders: [{ name: "industry", type: "string" }]
36
+ },
37
+ "image.error.noProvider": {
38
+ value: "No image provider configured",
39
+ description: "Error message when no ImageProvider is available"
40
+ },
41
+ "image.error.generationFailed": {
42
+ value: "Image generation failed",
43
+ description: "Error message when image generation fails"
44
+ },
45
+ "purpose.blogHero": {
46
+ value: "Blog hero image",
47
+ description: "Label for blog hero image purpose"
48
+ },
49
+ "purpose.socialOg": {
50
+ value: "Social media OG image",
51
+ description: "Label for Open Graph image purpose"
52
+ },
53
+ "purpose.socialTwitter": {
54
+ value: "Twitter card image",
55
+ description: "Label for Twitter card image purpose"
56
+ },
57
+ "purpose.socialInstagram": {
58
+ value: "Instagram image",
59
+ description: "Label for Instagram image purpose"
60
+ },
61
+ "purpose.landingHero": {
62
+ value: "Landing page hero",
63
+ description: "Label for landing page hero image purpose"
64
+ },
65
+ "purpose.videoThumbnail": {
66
+ value: "Video thumbnail",
67
+ description: "Label for video thumbnail purpose"
68
+ },
69
+ "purpose.emailHeader": {
70
+ value: "Email header",
71
+ description: "Label for email header image purpose"
72
+ },
73
+ "purpose.illustration": {
74
+ value: "Illustration",
75
+ description: "Label for illustration purpose"
76
+ },
77
+ "purpose.icon": {
78
+ value: "Icon",
79
+ description: "Label for icon purpose"
80
+ }
81
+ }
82
+ });
83
+
84
+ // src/i18n/catalogs/fr.ts
85
+ import { defineTranslation as defineTranslation2 } from "@contractspec/lib.contracts-spec/translations";
86
+ var frMessages = defineTranslation2({
87
+ meta: {
88
+ key: "image-gen.messages",
89
+ version: "1.0.0",
90
+ domain: "image-gen",
91
+ description: "French translations for the image-gen package",
92
+ owners: ["platform"],
93
+ stability: "experimental"
94
+ },
95
+ locale: "fr",
96
+ fallback: "en",
97
+ messages: {
98
+ "prompt.system.imagePromptEngineer": {
99
+ value: "Vous êtes un expert en ingénierie de prompts d'images. À partir d'un brief JSON contenant titre, résumé, problèmes, solutions, objectif, style et tokens de style, produisez un prompt détaillé de génération d'image. Le prompt doit être vivant, spécifique et optimisé pour les modèles de génération d'images IA. Concentrez-vous sur la composition, l'éclairage, la palette de couleurs et le sujet. Produisez uniquement le texte du prompt, pas de JSON.",
100
+ description: "Prompt système pour l'ingénierie de prompts d'images par LLM"
101
+ },
102
+ "image.generate.description": {
103
+ value: "Générer une image {style} pour {purpose}",
104
+ description: "Modèle de description pour les tâches de génération d'images",
105
+ placeholders: [
106
+ { name: "style", type: "string" },
107
+ { name: "purpose", type: "string" }
108
+ ]
109
+ },
110
+ "image.prompt.featuring": {
111
+ value: "mettant en avant {solutions}",
112
+ description: "Fragment de prompt pour les solutions mises en avant",
113
+ placeholders: [{ name: "solutions", type: "string" }]
114
+ },
115
+ "image.prompt.industryContext": {
116
+ value: "contexte {industry}",
117
+ description: "Fragment de prompt pour le contexte industriel",
118
+ placeholders: [{ name: "industry", type: "string" }]
119
+ },
120
+ "image.error.noProvider": {
121
+ value: "Aucun fournisseur d'images configuré",
122
+ description: "Message d'erreur quand aucun ImageProvider n'est disponible"
123
+ },
124
+ "image.error.generationFailed": {
125
+ value: "La génération d'image a échoué",
126
+ description: "Message d'erreur quand la génération d'image échoue"
127
+ },
128
+ "purpose.blogHero": {
129
+ value: "Image hero de blog",
130
+ description: "Libellé pour l'objectif image hero de blog"
131
+ },
132
+ "purpose.socialOg": {
133
+ value: "Image OG pour réseaux sociaux",
134
+ description: "Libellé pour l'objectif image Open Graph"
135
+ },
136
+ "purpose.socialTwitter": {
137
+ value: "Image carte Twitter",
138
+ description: "Libellé pour l'objectif image carte Twitter"
139
+ },
140
+ "purpose.socialInstagram": {
141
+ value: "Image Instagram",
142
+ description: "Libellé pour l'objectif image Instagram"
143
+ },
144
+ "purpose.landingHero": {
145
+ value: "Hero de page d'atterrissage",
146
+ description: "Libellé pour l'objectif image hero de page d'atterrissage"
147
+ },
148
+ "purpose.videoThumbnail": {
149
+ value: "Miniature vidéo",
150
+ description: "Libellé pour l'objectif miniature vidéo"
151
+ },
152
+ "purpose.emailHeader": {
153
+ value: "En-tête d'email",
154
+ description: "Libellé pour l'objectif image en-tête d'email"
155
+ },
156
+ "purpose.illustration": {
157
+ value: "Illustration",
158
+ description: "Libellé pour l'objectif illustration"
159
+ },
160
+ "purpose.icon": {
161
+ value: "Icône",
162
+ description: "Libellé pour l'objectif icône"
163
+ }
164
+ }
165
+ });
166
+
167
+ // src/i18n/catalogs/es.ts
168
+ import { defineTranslation as defineTranslation3 } from "@contractspec/lib.contracts-spec/translations";
169
+ var esMessages = defineTranslation3({
170
+ meta: {
171
+ key: "image-gen.messages",
172
+ version: "1.0.0",
173
+ domain: "image-gen",
174
+ description: "Spanish translations for the image-gen package",
175
+ owners: ["platform"],
176
+ stability: "experimental"
177
+ },
178
+ locale: "es",
179
+ fallback: "en",
180
+ messages: {
181
+ "prompt.system.imagePromptEngineer": {
182
+ value: "Eres un experto en ingeniería de prompts de imágenes. Dado un brief JSON que contiene título, resumen, problemas, soluciones, propósito, estilo y tokens de estilo, produce un prompt detallado de generación de imágenes. El prompt debe ser vívido, específico y optimizado para modelos de generación de imágenes con IA. Concéntrate en la composición, iluminación, paleta de colores y tema. Produce solo el texto del prompt, sin JSON.",
183
+ description: "Prompt del sistema para ingeniería de prompts de imágenes por LLM"
184
+ },
185
+ "image.generate.description": {
186
+ value: "Generar una imagen {style} para {purpose}",
187
+ description: "Plantilla de descripción para tareas de generación de imágenes",
188
+ placeholders: [
189
+ { name: "style", type: "string" },
190
+ { name: "purpose", type: "string" }
191
+ ]
192
+ },
193
+ "image.prompt.featuring": {
194
+ value: "presentando {solutions}",
195
+ description: "Fragmento de prompt para soluciones destacadas",
196
+ placeholders: [{ name: "solutions", type: "string" }]
197
+ },
198
+ "image.prompt.industryContext": {
199
+ value: "contexto de {industry}",
200
+ description: "Fragmento de prompt para contexto de industria",
201
+ placeholders: [{ name: "industry", type: "string" }]
202
+ },
203
+ "image.error.noProvider": {
204
+ value: "No hay proveedor de imágenes configurado",
205
+ description: "Mensaje de error cuando no hay ImageProvider disponible"
206
+ },
207
+ "image.error.generationFailed": {
208
+ value: "La generación de imagen falló",
209
+ description: "Mensaje de error cuando la generación de imagen falla"
210
+ },
211
+ "purpose.blogHero": {
212
+ value: "Imagen hero de blog",
213
+ description: "Etiqueta para el propósito imagen hero de blog"
214
+ },
215
+ "purpose.socialOg": {
216
+ value: "Imagen OG para redes sociales",
217
+ description: "Etiqueta para el propósito imagen Open Graph"
218
+ },
219
+ "purpose.socialTwitter": {
220
+ value: "Imagen de tarjeta Twitter",
221
+ description: "Etiqueta para el propósito imagen tarjeta Twitter"
222
+ },
223
+ "purpose.socialInstagram": {
224
+ value: "Imagen de Instagram",
225
+ description: "Etiqueta para el propósito imagen Instagram"
226
+ },
227
+ "purpose.landingHero": {
228
+ value: "Hero de página de aterrizaje",
229
+ description: "Etiqueta para el propósito imagen hero de página de aterrizaje"
230
+ },
231
+ "purpose.videoThumbnail": {
232
+ value: "Miniatura de video",
233
+ description: "Etiqueta para el propósito miniatura de video"
234
+ },
235
+ "purpose.emailHeader": {
236
+ value: "Encabezado de email",
237
+ description: "Etiqueta para el propósito imagen encabezado de email"
238
+ },
239
+ "purpose.illustration": {
240
+ value: "Ilustración",
241
+ description: "Etiqueta para el propósito ilustración"
242
+ },
243
+ "purpose.icon": {
244
+ value: "Icono",
245
+ description: "Etiqueta para el propósito icono"
246
+ }
247
+ }
248
+ });
249
+
250
+ // src/i18n/messages.ts
251
+ import {
252
+ createI18nFactory
253
+ } from "@contractspec/lib.contracts-spec/translations";
254
+ var factory = createI18nFactory({
255
+ specKey: "image-gen.messages",
256
+ catalogs: [enMessages, frMessages, esMessages]
257
+ });
258
+ var createImageGenI18n = factory.create;
259
+ var getDefaultI18n = factory.getDefault;
260
+ var resetI18nRegistry = factory.resetRegistry;
261
+
262
+ // src/generators/prompt-builder.ts
263
+ class PromptBuilder {
264
+ llm;
265
+ model;
266
+ temperature;
267
+ i18n;
268
+ constructor(options) {
269
+ this.llm = options.llm;
270
+ this.model = options.model;
271
+ this.temperature = options.temperature ?? 0.4;
272
+ this.i18n = options.i18n;
273
+ }
274
+ async build(brief, resolvedStyle) {
275
+ const style = brief.style ?? "photorealistic";
276
+ const format = brief.format ?? "png";
277
+ if (this.llm) {
278
+ try {
279
+ return await this.buildWithLlm(brief, resolvedStyle, style, format);
280
+ } catch {
281
+ return this.buildDeterministic(brief, resolvedStyle, style, format);
282
+ }
283
+ }
284
+ return this.buildDeterministic(brief, resolvedStyle, style, format);
285
+ }
286
+ async buildWithLlm(brief, resolvedStyle, style, format) {
287
+ const systemPrompt = this.i18n.t("prompt.system.imagePromptEngineer");
288
+ const briefJson = JSON.stringify({
289
+ title: brief.content.title,
290
+ summary: brief.content.summary,
291
+ problems: brief.content.problems,
292
+ solutions: brief.content.solutions,
293
+ purpose: brief.purpose,
294
+ style,
295
+ styleTokens: resolvedStyle.styleTokens
296
+ });
297
+ const messages = [
298
+ {
299
+ role: "system",
300
+ content: [{ type: "text", text: systemPrompt }]
301
+ },
302
+ {
303
+ role: "user",
304
+ content: [{ type: "text", text: briefJson }]
305
+ }
306
+ ];
307
+ const llm = this.llm;
308
+ if (!llm) {
309
+ throw new Error("LLM provider is required for buildWithLlm");
310
+ }
311
+ const response = await llm.chat(messages, {
312
+ model: this.model,
313
+ temperature: this.temperature
314
+ });
315
+ const text = response.message.content.filter((block) => block.type === "text").map((block) => ("text" in block) ? block.text : "").join("");
316
+ return {
317
+ text: text.trim(),
318
+ negativeText: resolvedStyle.negativeTokens.join(", "),
319
+ style,
320
+ dimensions: resolvedStyle.dimensions,
321
+ format
322
+ };
323
+ }
324
+ buildDeterministic(brief, resolvedStyle, style, format) {
325
+ const parts = [
326
+ brief.content.title,
327
+ this.i18n.t("image.generate.description", {
328
+ style,
329
+ purpose: brief.purpose
330
+ })
331
+ ];
332
+ if (brief.content.solutions.length > 0) {
333
+ parts.push(this.i18n.t("image.prompt.featuring", {
334
+ solutions: brief.content.solutions.slice(0, 3).join(", ")
335
+ }));
336
+ }
337
+ if (brief.content.audience?.industry) {
338
+ parts.push(this.i18n.t("image.prompt.industryContext", {
339
+ industry: brief.content.audience.industry
340
+ }));
341
+ }
342
+ parts.push(...resolvedStyle.styleTokens);
343
+ return {
344
+ text: parts.join(", "),
345
+ negativeText: resolvedStyle.negativeTokens.join(", "),
346
+ style,
347
+ dimensions: resolvedStyle.dimensions,
348
+ format
349
+ };
350
+ }
351
+ }
352
+
353
+ // src/types.ts
354
+ import { IMAGE_PRESETS } from "@contractspec/lib.contracts-integrations/integrations/providers/image";
355
+ // src/generators/style-resolver.ts
356
+ var PURPOSE_DIMENSIONS = {
357
+ "blog-hero": IMAGE_PRESETS.blogHero,
358
+ "social-og": IMAGE_PRESETS.ogImage,
359
+ "social-twitter": IMAGE_PRESETS.twitterCard,
360
+ "social-instagram": IMAGE_PRESETS.instagramSquare,
361
+ "landing-hero": IMAGE_PRESETS.blogHero,
362
+ "video-thumbnail": IMAGE_PRESETS.thumbnail,
363
+ "email-header": IMAGE_PRESETS.emailHeader,
364
+ illustration: IMAGE_PRESETS.illustration,
365
+ icon: IMAGE_PRESETS.favicon
366
+ };
367
+ var STYLE_TOKENS = {
368
+ photorealistic: [
369
+ "professional photography",
370
+ "high resolution",
371
+ "natural lighting",
372
+ "detailed textures"
373
+ ],
374
+ illustration: [
375
+ "digital illustration",
376
+ "clean lines",
377
+ "vibrant colors",
378
+ "artistic composition"
379
+ ],
380
+ "3d-render": [
381
+ "3D render",
382
+ "volumetric lighting",
383
+ "glossy materials",
384
+ "depth of field"
385
+ ],
386
+ "flat-design": [
387
+ "clean flat vector",
388
+ "geometric shapes",
389
+ "solid colors",
390
+ "minimal shadows"
391
+ ],
392
+ abstract: [
393
+ "abstract composition",
394
+ "bold shapes",
395
+ "dynamic colors",
396
+ "artistic interpretation"
397
+ ],
398
+ minimalist: [
399
+ "minimalist design",
400
+ "clean whitespace",
401
+ "simple elements",
402
+ "restrained palette"
403
+ ],
404
+ branded: [
405
+ "brand-consistent design",
406
+ "professional layout",
407
+ "corporate aesthetic",
408
+ "clean composition"
409
+ ]
410
+ };
411
+ var BASE_NEGATIVE_TOKENS = [
412
+ "blurry",
413
+ "low quality",
414
+ "text overlay",
415
+ "watermark",
416
+ "distorted",
417
+ "pixelated"
418
+ ];
419
+
420
+ class StyleResolver {
421
+ resolve(purpose, style, brand) {
422
+ const resolvedStyle = style ?? "photorealistic";
423
+ const dimensions = PURPOSE_DIMENSIONS[purpose];
424
+ const styleTokens = [...STYLE_TOKENS[resolvedStyle]];
425
+ const negativeTokens = [...BASE_NEGATIVE_TOKENS];
426
+ if (brand) {
427
+ if (brand.primary) {
428
+ styleTokens.push(`primary color ${brand.primary} palette`);
429
+ }
430
+ if (brand.accent) {
431
+ styleTokens.push(`accent color ${brand.accent}`);
432
+ }
433
+ if (brand.background) {
434
+ styleTokens.push(`background color ${brand.background}`);
435
+ }
436
+ }
437
+ return { styleTokens, negativeTokens, dimensions };
438
+ }
439
+ }
440
+
441
+ // src/generators/image-generator.ts
442
+ var DEFAULT_CLOCK = {
443
+ now: () => Date.now(),
444
+ toISOString: () => new Date().toISOString()
445
+ };
446
+
447
+ class ImageGenerator {
448
+ promptBuilder;
449
+ styleResolver;
450
+ options;
451
+ i18n;
452
+ clock;
453
+ constructor(options) {
454
+ this.options = options ?? {};
455
+ this.i18n = createImageGenI18n(options?.locale);
456
+ this.clock = options?.clock ?? DEFAULT_CLOCK;
457
+ this.styleResolver = new StyleResolver;
458
+ this.promptBuilder = new PromptBuilder({
459
+ llm: options?.llm,
460
+ model: options?.model,
461
+ temperature: options?.temperature,
462
+ i18n: this.i18n
463
+ });
464
+ }
465
+ async generate(brief) {
466
+ const resolvedStyle = this.styleResolver.resolve(brief.purpose, brief.style ?? this.options.defaultStyle, brief.brandColors);
467
+ const prompt = await this.promptBuilder.build(brief, resolvedStyle);
468
+ if (brief.dimensions) {
469
+ prompt.dimensions = brief.dimensions;
470
+ }
471
+ const id = this.generateId(brief);
472
+ const project = {
473
+ id,
474
+ prompt,
475
+ metadata: {
476
+ purpose: brief.purpose,
477
+ title: brief.content.title,
478
+ createdAt: this.clock.toISOString(),
479
+ locale: brief.locale ?? this.options.locale ?? "en"
480
+ }
481
+ };
482
+ if (this.options.image) {
483
+ try {
484
+ const results = await this.options.image.generate({
485
+ prompt: prompt.text,
486
+ negativePrompt: prompt.negativeText,
487
+ dimensions: prompt.dimensions,
488
+ format: prompt.format,
489
+ style: this.mapStyleToProviderStyle(prompt.style),
490
+ numVariants: brief.variants,
491
+ seed: brief.seed
492
+ });
493
+ project.results = results;
494
+ } catch (error) {
495
+ const message = this.i18n.t("image.error.generationFailed");
496
+ throw new Error(message, error instanceof Error ? { cause: error } : undefined);
497
+ }
498
+ }
499
+ return project;
500
+ }
501
+ generateId(brief) {
502
+ const slug = brief.content.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
503
+ const ts = this.clock.now().toString(36);
504
+ return `img-${slug}-${ts}`;
505
+ }
506
+ mapStyleToProviderStyle(style) {
507
+ const providerStyles = [
508
+ "photorealistic",
509
+ "illustration",
510
+ "3d-render",
511
+ "flat-design",
512
+ "abstract"
513
+ ];
514
+ if (providerStyles.includes(style)) {
515
+ return style;
516
+ }
517
+ if (style === "minimalist" || style === "branded") {
518
+ return "flat-design";
519
+ }
520
+ return;
521
+ }
522
+ }
523
+ // src/presets/social.ts
524
+ function ogImageBrief(content) {
525
+ return {
526
+ content,
527
+ purpose: "social-og",
528
+ dimensions: IMAGE_PRESETS.ogImage,
529
+ format: "png",
530
+ style: "photorealistic"
531
+ };
532
+ }
533
+ function twitterCardBrief(content) {
534
+ return {
535
+ content,
536
+ purpose: "social-twitter",
537
+ dimensions: IMAGE_PRESETS.twitterCard,
538
+ format: "png",
539
+ style: "photorealistic"
540
+ };
541
+ }
542
+ function instagramSquareBrief(content) {
543
+ return {
544
+ content,
545
+ purpose: "social-instagram",
546
+ dimensions: IMAGE_PRESETS.instagramSquare,
547
+ format: "jpg",
548
+ style: "photorealistic"
549
+ };
550
+ }
551
+ function instagramStoryBrief(content) {
552
+ return {
553
+ content,
554
+ purpose: "social-instagram",
555
+ dimensions: IMAGE_PRESETS.instagramStory,
556
+ format: "jpg",
557
+ style: "photorealistic"
558
+ };
559
+ }
560
+
561
+ // src/presets/marketing.ts
562
+ function blogHeroBrief(content) {
563
+ return {
564
+ content,
565
+ purpose: "blog-hero",
566
+ dimensions: IMAGE_PRESETS.blogHero,
567
+ format: "webp",
568
+ style: "photorealistic"
569
+ };
570
+ }
571
+ function landingHeroBrief(content) {
572
+ return {
573
+ content,
574
+ purpose: "landing-hero",
575
+ dimensions: IMAGE_PRESETS.blogHero,
576
+ format: "webp",
577
+ style: "photorealistic"
578
+ };
579
+ }
580
+ function emailHeaderBrief(content) {
581
+ return {
582
+ content,
583
+ purpose: "email-header",
584
+ dimensions: IMAGE_PRESETS.emailHeader,
585
+ format: "png",
586
+ style: "flat-design"
587
+ };
588
+ }
589
+
590
+ // src/presets/video.ts
591
+ function videoThumbnailBrief(content) {
592
+ return {
593
+ content,
594
+ purpose: "video-thumbnail",
595
+ dimensions: IMAGE_PRESETS.thumbnail,
596
+ format: "png",
597
+ style: "photorealistic"
598
+ };
599
+ }
600
+ function videoThumbnailWideBrief(content) {
601
+ return {
602
+ content,
603
+ purpose: "video-thumbnail",
604
+ dimensions: { width: 1280, height: 720 },
605
+ format: "png",
606
+ style: "photorealistic"
607
+ };
608
+ }
609
+ export {
610
+ videoThumbnailWideBrief,
611
+ videoThumbnailBrief,
612
+ twitterCardBrief,
613
+ ogImageBrief,
614
+ landingHeroBrief,
615
+ instagramStoryBrief,
616
+ instagramSquareBrief,
617
+ emailHeaderBrief,
618
+ blogHeroBrief,
619
+ StyleResolver,
620
+ PromptBuilder,
621
+ ImageGenerator,
622
+ IMAGE_PRESETS
623
+ };