@interware/content-generator 0.2.1 → 0.3.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 (26) hide show
  1. package/README.md +42 -0
  2. package/dist/_chunks/{App-Cbkccs2K.mjs → App-ClgJldBv.mjs} +539 -14
  3. package/dist/_chunks/{App-DCuBRwX8.js → App-CwkLhm0x.js} +538 -13
  4. package/dist/_chunks/{Settings-DuGbtyWC.js → Settings-BEtewXxk.js} +2 -2
  5. package/dist/_chunks/{Settings-B60QGKK4.mjs → Settings-Bc5rcMRs.mjs} +2 -2
  6. package/dist/_chunks/{getTranslation-CacX7ZX5.js → getTranslation-C1jZiBcc.js} +1 -1
  7. package/dist/_chunks/{getTranslation-B97xbmEl.mjs → getTranslation-D3pA_57E.mjs} +1 -1
  8. package/dist/_chunks/{index-BVGbP3E-.js → index-D4lanCw0.js} +2 -2
  9. package/dist/_chunks/{index-B2RuvYul.mjs → index-K1A2opOE.mjs} +2 -2
  10. package/dist/admin/index.js +1 -1
  11. package/dist/admin/index.mjs +1 -1
  12. package/dist/admin/src/components/generate-image/Form.d.ts +15 -0
  13. package/dist/admin/src/components/generate-video/Form.d.ts +36 -0
  14. package/dist/admin/src/containers/generate-image/index.d.ts +2 -0
  15. package/dist/admin/src/containers/generate-video/index.d.ts +2 -0
  16. package/dist/admin/src/lib/use-cases/images/index.d.ts +2 -0
  17. package/dist/admin/src/pages/GenerateImage.d.ts +2 -0
  18. package/dist/admin/src/pages/GenerateVideo.d.ts +2 -0
  19. package/dist/server/index.js +369 -172
  20. package/dist/server/index.mjs +352 -173
  21. package/dist/server/src/controllers/controller.d.ts +2 -0
  22. package/dist/server/src/controllers/index.d.ts +2 -0
  23. package/dist/server/src/index.d.ts +21 -0
  24. package/dist/server/src/services/index.d.ts +19 -0
  25. package/dist/server/src/services/service.d.ts +20 -4
  26. package/package.json +1 -1
@@ -4,12 +4,12 @@ const jsxRuntime = require("react/jsx-runtime");
4
4
  const admin = require("@strapi/strapi/admin");
5
5
  const designSystem = require("@strapi/design-system");
6
6
  const reactRouterDom = require("react-router-dom");
7
- const index = require("./index-BVGbP3E-.js");
7
+ const index = require("./index-D4lanCw0.js");
8
8
  const reactIntl = require("react-intl");
9
9
  const react = require("react");
10
10
  const reactRedux = require("react-redux");
11
11
  const icons = require("@strapi/icons");
12
- const getTranslation = require("./getTranslation-CacX7ZX5.js");
12
+ const getTranslation = require("./getTranslation-C1jZiBcc.js");
13
13
  const formik = require("formik");
14
14
  const Yup = require("yup");
15
15
  function _interopNamespace(e) {
@@ -588,24 +588,24 @@ const useUsers = () => {
588
588
  getUsers
589
589
  };
590
590
  };
591
- const validationSchema = Yup__namespace.object().shape({
591
+ const validationSchema$2 = Yup__namespace.object().shape({
592
592
  titulo: Yup__namespace.string().notRequired(),
593
593
  autor: Yup__namespace.string().required("Este campo es obligatorio"),
594
594
  categoria: Yup__namespace.string().required("Este campo es obligatorio"),
595
595
  temperatura: Yup__namespace.string().notRequired(),
596
596
  instrucciones: Yup__namespace.string().notRequired()
597
597
  });
598
- const initialValues = {
598
+ const initialValues$1 = {
599
599
  titulo: "",
600
600
  autor: "",
601
601
  categoria: "",
602
- temperatura: "0.2",
602
+ temperatura: "0.5",
603
603
  instrucciones: ""
604
604
  };
605
- const Form = ({ onSubmit, categorias, users }) => {
605
+ const Form$2 = ({ onSubmit, categorias, users }) => {
606
606
  const formik$1 = formik.useFormik({
607
- initialValues,
608
- validationSchema,
607
+ initialValues: initialValues$1,
608
+ validationSchema: validationSchema$2,
609
609
  onSubmit
610
610
  });
611
611
  const { values, errors, touched, isValid, dirty, isSubmitting, handleChange, setFieldValue, handleSubmit } = formik$1;
@@ -863,7 +863,7 @@ const GenerateContentContainer = () => {
863
863
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: "Para uso exclusivo de InterWare de México" })
864
864
  ] }) }),
865
865
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { m: 12, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { alignItems: "end", width: "100%", justifyContent: "end", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.LinkButton, { href: "/admin/plugins/strapi-content-generator-gemini", children: "Regresar" }) }) }),
866
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form, { categorias, users, onSubmit }) })
866
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2, { categorias, users, onSubmit }) })
867
867
  ] })
868
868
  ] });
869
869
  };
@@ -874,7 +874,7 @@ const GenerateContent = () => {
874
874
  ] });
875
875
  };
876
876
  const useImages$1 = () => {
877
- const { get, del } = admin.useFetchClient();
877
+ const { get, del, post } = admin.useFetchClient();
878
878
  const getImages = react.useCallback(
879
879
  async () => {
880
880
  return await get("/strapi-content-generator-gemini/images");
@@ -887,9 +887,23 @@ const useImages$1 = () => {
887
887
  },
888
888
  [del]
889
889
  );
890
+ const generateImageWithConfig = react.useCallback(
891
+ async (data, config) => {
892
+ return await post("/strapi-content-generator-gemini/generate-image-with-config", data, config);
893
+ },
894
+ [post]
895
+ );
896
+ const generateVideoWithScenes = react.useCallback(
897
+ async (data, config) => {
898
+ return await post("/strapi-content-generator-gemini/generate-video-with-scenes", data, config);
899
+ },
900
+ [post]
901
+ );
890
902
  return {
891
903
  getImages,
892
- deleteImage
904
+ deleteImage,
905
+ generateImageWithConfig,
906
+ generateVideoWithScenes
893
907
  };
894
908
  };
895
909
  const PRINCIPAL_KEY = "principal";
@@ -1192,9 +1206,10 @@ const Images = () => {
1192
1206
  const GenerateImagesContainer = () => {
1193
1207
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(ImagesProvider, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { padding: 6, children: [
1194
1208
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "start", children: [
1195
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", children: "Generar imagenes con IA" }),
1209
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", children: "Generar imagenes y videos con IA" }),
1196
1210
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: "Para uso exclusivo de InterWare de México" })
1197
1211
  ] }) }),
1212
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { m: 12, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "end", alignItems: "end", gap: 3, width: "100%", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.LinkButton, { href: "/admin/plugins/strapi-content-generator-gemini/generate-image", children: "Generar nueva imagen" }) }) }),
1198
1213
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Images, {}) })
1199
1214
  ] }) }) });
1200
1215
  };
@@ -1204,6 +1219,512 @@ const GenerateImages = () => {
1204
1219
  /* @__PURE__ */ jsxRuntime.jsx(GenerateImagesContainer, {})
1205
1220
  ] });
1206
1221
  };
1222
+ const aspectRatioOptions = [
1223
+ { value: "1:1", label: "1:1 (Cuadrado)" },
1224
+ { value: "2:3", label: "2:3 Rectangular (vertical)" },
1225
+ { value: "3:2", label: "3:2 Rectangular (horizontal)" },
1226
+ { value: "3:4", label: "3:4 Rectangular (vertical)" },
1227
+ { value: "4:3", label: "4:3 Rectangular (horizontal)" },
1228
+ { value: "9:16", label: "9:16 Rectangular (vertical)" },
1229
+ { value: "16:9", label: "16:9 Rectangular (horizontal)" },
1230
+ { value: "21:9", label: "21:9 Rectangular (horizontal)" }
1231
+ ];
1232
+ const validationSchema$1 = Yup__namespace.object({
1233
+ prompt: Yup__namespace.string().required("El prompt es requerido"),
1234
+ aspectRatio: Yup__namespace.string().required("La relación de aspecto es requerida"),
1235
+ imageSize: Yup__namespace.string().required("El tamaño de la imagen es requerido")
1236
+ });
1237
+ const Form$1 = ({ onSubmit }) => {
1238
+ const [referenceImages, setReferenceImages] = react.useState([]);
1239
+ const individualFileInputRefs = react.useRef({});
1240
+ const newImageFileInputRef = react.useRef(null);
1241
+ const formik$1 = formik.useFormik({
1242
+ initialValues: {
1243
+ prompt: "",
1244
+ aspectRatio: "16:9",
1245
+ imageSize: "1K"
1246
+ },
1247
+ validationSchema: validationSchema$1,
1248
+ onSubmit: (values, formikHelpers) => onSubmit({ ...values }, formikHelpers, referenceImages)
1249
+ });
1250
+ const handleAddImage = () => {
1251
+ newImageFileInputRef.current?.click();
1252
+ };
1253
+ const handleRemoveImage = (id) => {
1254
+ const imageToRemove = referenceImages.find((img) => img.id === id);
1255
+ if (imageToRemove?.previewUrl) {
1256
+ URL.revokeObjectURL(imageToRemove.previewUrl);
1257
+ }
1258
+ setReferenceImages(referenceImages.filter((image) => image.id !== id));
1259
+ };
1260
+ const handleNewImageFileChange = (e) => {
1261
+ const selectedFile = e.target.files?.[0];
1262
+ if (selectedFile) {
1263
+ setReferenceImages((prevImages) => [
1264
+ ...prevImages,
1265
+ { id: Date.now(), file: selectedFile, previewUrl: URL.createObjectURL(selectedFile) }
1266
+ ]);
1267
+ }
1268
+ e.target.value = "";
1269
+ };
1270
+ const handleIndividualFileChange = (id, selectedFile) => {
1271
+ setReferenceImages((prevImages) => prevImages.map((image) => {
1272
+ if (image.id === id) {
1273
+ if (image.previewUrl) {
1274
+ URL.revokeObjectURL(image.previewUrl);
1275
+ }
1276
+ if (selectedFile) {
1277
+ return { ...image, file: selectedFile, previewUrl: URL.createObjectURL(selectedFile) };
1278
+ } else {
1279
+ const { file, previewUrl, ...rest } = image;
1280
+ return rest;
1281
+ }
1282
+ }
1283
+ return image;
1284
+ }));
1285
+ };
1286
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { background: "neutral0", padding: 6, hasRadius: true, width: "100%", children: /* @__PURE__ */ jsxRuntime.jsx("form", { onSubmit: formik$1.handleSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { gap: 4, children: [
1287
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { m: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(
1288
+ designSystem.Field.Root,
1289
+ {
1290
+ id: "prompt",
1291
+ width: "100%",
1292
+ required: true,
1293
+ children: [
1294
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Prompt de la imagen" }),
1295
+ /* @__PURE__ */ jsxRuntime.jsx(
1296
+ designSystem.Textarea,
1297
+ {
1298
+ name: "prompt",
1299
+ placeholder: "Ej: Un paisaje futurista de la Ciudad de México con neones.",
1300
+ onChange: formik$1.handleChange,
1301
+ onBlur: formik$1.handleBlur,
1302
+ value: formik$1.values.prompt,
1303
+ rows: 12
1304
+ }
1305
+ )
1306
+ ]
1307
+ }
1308
+ ) }),
1309
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { m: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(
1310
+ designSystem.Field.Root,
1311
+ {
1312
+ id: "imagen-referencia",
1313
+ width: "100%",
1314
+ children: [
1315
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Imagen(es) de referencia" }),
1316
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 3, width: "100%", children: [
1317
+ referenceImages.map((image) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { background: "neutral100", padding: 3, hasRadius: true, width: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", gap: 3, width: "100%", children: [
1318
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { background: "primary100", padding: 1, children: image.previewUrl ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: image.previewUrl, alt: "preview", style: { width: "50px", height: "50px", objectFit: "cover" } }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: { width: "50px", height: "50px", backgroundColor: "#ccc" } }) }),
1319
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { flexGrow: 2 }, children: [
1320
+ /* @__PURE__ */ jsxRuntime.jsx(
1321
+ "input",
1322
+ {
1323
+ type: "file",
1324
+ accept: "image/*",
1325
+ ref: (el) => individualFileInputRefs.current[image.id] = el,
1326
+ style: { display: "none" },
1327
+ onChange: (e) => handleIndividualFileChange(image.id, e.target.files?.[0])
1328
+ }
1329
+ ),
1330
+ /* @__PURE__ */ jsxRuntime.jsx(
1331
+ designSystem.Button,
1332
+ {
1333
+ onClick: () => individualFileInputRefs.current[image.id]?.click(),
1334
+ startIcon: image.file ? void 0 : /* @__PURE__ */ jsxRuntime.jsx(icons.PlusCircle, {}),
1335
+ variant: "secondary",
1336
+ fullWidth: true,
1337
+ children: image.file ? image.file.name : "Seleccionar archivo"
1338
+ }
1339
+ )
1340
+ ] }),
1341
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.IconButton, { onClick: () => handleRemoveImage(image.id), label: "Eliminar imagen", children: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {}) })
1342
+ ] }) }, image.id)),
1343
+ /* @__PURE__ */ jsxRuntime.jsx(
1344
+ "input",
1345
+ {
1346
+ type: "file",
1347
+ accept: "image/*",
1348
+ ref: newImageFileInputRef,
1349
+ style: { display: "none" },
1350
+ onChange: handleNewImageFileChange
1351
+ }
1352
+ ),
1353
+ /* @__PURE__ */ jsxRuntime.jsx(
1354
+ designSystem.Button,
1355
+ {
1356
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.PlusCircle, {}),
1357
+ variant: "secondary",
1358
+ fullWidth: true,
1359
+ onClick: handleAddImage,
1360
+ disabled: referenceImages.length >= 5,
1361
+ children: "Añadir imagen de referencia"
1362
+ }
1363
+ )
1364
+ ] }),
1365
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, {}),
1366
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
1367
+ ]
1368
+ }
1369
+ ) }),
1370
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { m: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(
1371
+ designSystem.Field.Root,
1372
+ {
1373
+ id: "aspectRatio",
1374
+ width: "100%",
1375
+ required: true,
1376
+ children: [
1377
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Relación de aspecto" }),
1378
+ /* @__PURE__ */ jsxRuntime.jsx(
1379
+ designSystem.Combobox,
1380
+ {
1381
+ name: "aspectRatio",
1382
+ onChange: (value) => formik$1.setFieldValue("aspectRatio", value),
1383
+ onBlur: () => formik$1.setFieldTouched("aspectRatio", true),
1384
+ value: formik$1.values.aspectRatio,
1385
+ onClear: () => formik$1.setFieldValue("aspectRatio", ""),
1386
+ children: aspectRatioOptions.map((option) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.ComboboxOption, { value: option.value, children: option.label }, option.value))
1387
+ }
1388
+ )
1389
+ ]
1390
+ }
1391
+ ) }),
1392
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { m: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(
1393
+ designSystem.Field.Root,
1394
+ {
1395
+ id: "imageSize",
1396
+ error: formik$1.touched.imageSize && formik$1.errors.imageSize ? formik$1.errors.imageSize : void 0,
1397
+ width: "100%",
1398
+ required: true,
1399
+ children: [
1400
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Tamaño de la imagen" }),
1401
+ /* @__PURE__ */ jsxRuntime.jsxs(
1402
+ designSystem.Combobox,
1403
+ {
1404
+ name: "imageSize",
1405
+ onChange: (value) => formik$1.setFieldValue("imageSize", value),
1406
+ onBlur: () => formik$1.setFieldTouched("imageSize", true),
1407
+ value: formik$1.values.imageSize,
1408
+ onClear: () => formik$1.setFieldValue("imageSize", ""),
1409
+ children: [
1410
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.ComboboxOption, { value: "1K", children: "1K" }),
1411
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.ComboboxOption, { value: "2K", children: "2K" }),
1412
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.ComboboxOption, { value: "4K", children: "4K" })
1413
+ ]
1414
+ }
1415
+ ),
1416
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, { children: formik$1.errors.imageSize })
1417
+ ]
1418
+ }
1419
+ ) }),
1420
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 12, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { width: "100%", justifyContent: "end", alignItems: "end", children: /* @__PURE__ */ jsxRuntime.jsx(
1421
+ designSystem.Button,
1422
+ {
1423
+ type: "submit",
1424
+ fullWidth: true,
1425
+ disabled: !(formik$1.isValid && formik$1.dirty) || formik$1.isSubmitting,
1426
+ loading: formik$1.isSubmitting,
1427
+ children: "Generar imagen"
1428
+ }
1429
+ ) }) })
1430
+ ] }) }) });
1431
+ };
1432
+ const GenerateImageContainer = () => {
1433
+ const { toggleNotification } = admin.useNotification();
1434
+ const { generateImageWithConfig } = useImages$1();
1435
+ const { formatMessage } = reactIntl.useIntl();
1436
+ const handleSubmit = async (values, { setSubmitting }, referenceImages) => {
1437
+ try {
1438
+ const formData = new FormData();
1439
+ formData.append("prompt", values.prompt);
1440
+ formData.append("aspectRatio", values.aspectRatio);
1441
+ formData.append("imageSize", values.imageSize);
1442
+ referenceImages.forEach((img, index2) => {
1443
+ if (img.file) {
1444
+ formData.append(`referenceImages[${index2}]`, img.file);
1445
+ }
1446
+ });
1447
+ const response = await generateImageWithConfig(formData);
1448
+ toggleNotification({
1449
+ type: "success",
1450
+ message: formatMessage({
1451
+ id: `${index.PLUGIN_ID}.config.load.success`,
1452
+ defaultMessage: "Imagen generada con éxito"
1453
+ })
1454
+ });
1455
+ } catch (error) {
1456
+ toggleNotification({
1457
+ type: "danger",
1458
+ message: formatMessage({
1459
+ id: `${index.PLUGIN_ID}.config.load.error`,
1460
+ defaultMessage: "Ocurrió un error al generar la imagen"
1461
+ })
1462
+ });
1463
+ } finally {
1464
+ setSubmitting(false);
1465
+ }
1466
+ };
1467
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1468
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Root, { padding: 6, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "start", children: [
1469
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", children: "Generar imagen con IA" }),
1470
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: "Para uso exclusivo de InterWare de México" })
1471
+ ] }) }) }),
1472
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { padding: 6, children: [
1473
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { m: 2 }),
1474
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { m: 8, children: /* @__PURE__ */ jsxRuntime.jsx(Form$1, { onSubmit: handleSubmit }) })
1475
+ ] })
1476
+ ] });
1477
+ };
1478
+ const GenerateImage = () => {
1479
+ return /* @__PURE__ */ jsxRuntime.jsxs(admin.Page.Main, { children: [
1480
+ /* @__PURE__ */ jsxRuntime.jsx(admin.Page.Title, { children: "Generar imagen con IA" }),
1481
+ /* @__PURE__ */ jsxRuntime.jsx(GenerateImageContainer, {})
1482
+ ] });
1483
+ };
1484
+ const sceneSchema = Yup__namespace.object().shape({
1485
+ prompt: Yup__namespace.string().trim().required("El prompt es obligatorio para esta escena"),
1486
+ durationSeconds: Yup__namespace.number().min(1, "La duración mínima es 1 segundo").max(90, "La duración máxima es 90 segundos").required("La duración es obligatoria"),
1487
+ referenceImages: Yup__namespace.array().of(
1488
+ Yup__namespace.object().shape({
1489
+ id: Yup__namespace.number().required(),
1490
+ file: Yup__namespace.mixed().optional(),
1491
+ previewUrl: Yup__namespace.string().optional()
1492
+ })
1493
+ ).max(3, "Se permiten máximo 3 imágenes de referencia por escena").optional()
1494
+ });
1495
+ const validationSchema = Yup__namespace.object().shape({
1496
+ aspectRatio: Yup__namespace.string().oneOf(["16:9", "9:16", "1:1"], "Aspect ratio no válido").required("El aspect ratio es obligatorio"),
1497
+ scenes: Yup__namespace.array().of(sceneSchema).min(1, "Debe haber al menos una escena").max(20, "No se permiten más de 20 escenas")
1498
+ });
1499
+ const initialValues = {
1500
+ aspectRatio: "16:9",
1501
+ scenes: [
1502
+ {
1503
+ prompt: ``,
1504
+ durationSeconds: 8,
1505
+ narrationText: ``,
1506
+ referenceImages: []
1507
+ }
1508
+ ]
1509
+ };
1510
+ const Form = ({ onSubmit }) => {
1511
+ const formik$1 = formik.useFormik({
1512
+ initialValues,
1513
+ validationSchema,
1514
+ validateOnMount: true,
1515
+ onSubmit
1516
+ });
1517
+ console.log("🚀 ~ Form ~ formik:", formik$1.errors);
1518
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { background: "neutral0", padding: 6, hasRadius: true, width: "100%", children: /* @__PURE__ */ jsxRuntime.jsx("form", { onSubmit: formik$1.handleSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { gap: 4, children: [
1519
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { m: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { id: "aspectRatio", width: "100%", required: true, children: [
1520
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Relación de aspecto" }),
1521
+ /* @__PURE__ */ jsxRuntime.jsxs(
1522
+ designSystem.Combobox,
1523
+ {
1524
+ name: "aspectRatio",
1525
+ onChange: (value) => formik$1.setFieldValue("aspectRatio", value),
1526
+ onBlur: () => formik$1.setFieldTouched("aspectRatio", true),
1527
+ value: formik$1.values.aspectRatio,
1528
+ onClear: () => formik$1.setFieldValue("aspectRatio", ""),
1529
+ children: [
1530
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.ComboboxOption, { value: "16:9", children: "16:9" }),
1531
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.ComboboxOption, { value: "9:16", children: "9:16" }),
1532
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.ComboboxOption, { value: "1:1", children: "1:1" })
1533
+ ]
1534
+ }
1535
+ ),
1536
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, { children: formik$1.errors.aspectRatio })
1537
+ ] }) }),
1538
+ formik$1.values.scenes.map((scene, index2) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { background: "neutral100", padding: 4, hasRadius: true, width: "100%", children: [
1539
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 3, children: [
1540
+ /* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
1541
+ "Escena ",
1542
+ index2 + 1
1543
+ ] }),
1544
+ formik$1.values.scenes.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
1545
+ designSystem.Button,
1546
+ {
1547
+ variant: "danger-light",
1548
+ onClick: () => {
1549
+ const updatedScenes = [...formik$1.values.scenes];
1550
+ updatedScenes.splice(index2, 1);
1551
+ formik$1.setFieldValue("scenes", updatedScenes);
1552
+ },
1553
+ children: "Eliminar Escena"
1554
+ }
1555
+ )
1556
+ ] }),
1557
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 3, children: [
1558
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { id: `scenes.${index2}.prompt`, width: "100%", required: true, children: [
1559
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Prompt de la escena" }),
1560
+ /* @__PURE__ */ jsxRuntime.jsx(
1561
+ designSystem.Textarea,
1562
+ {
1563
+ name: `scenes.${index2}.prompt`,
1564
+ placeholder: "Describe visualmente esta escena",
1565
+ onChange: formik$1.handleChange,
1566
+ onBlur: formik$1.handleBlur,
1567
+ value: formik$1.values.scenes[index2].prompt,
1568
+ rows: 6
1569
+ }
1570
+ )
1571
+ ] }),
1572
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { id: `scenes.${index2}.durationSeconds`, width: "100%", required: true, children: [
1573
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Duración (segundos)" }),
1574
+ /* @__PURE__ */ jsxRuntime.jsxs(
1575
+ designSystem.Combobox,
1576
+ {
1577
+ name: `scenes.${index2}.durationSeconds`,
1578
+ onChange: (value) => formik$1.setFieldValue(`scenes.${index2}.durationSeconds`, value),
1579
+ onBlur: formik$1.handleBlur,
1580
+ value: formik$1.values.scenes[index2].durationSeconds,
1581
+ onClear: () => formik$1.setFieldValue(`scenes.${index2}.durationSeconds`, ""),
1582
+ children: [
1583
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.ComboboxOption, { value: 4, children: "4" }),
1584
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.ComboboxOption, { value: 6, children: "6" }),
1585
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.ComboboxOption, { value: 8, children: "8" })
1586
+ ]
1587
+ }
1588
+ )
1589
+ ] }),
1590
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { id: `scenes.${index2}.referenceImages`, width: "100%", children: [
1591
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Imagen(es) de referencia" }),
1592
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 3, width: "100%", children: [
1593
+ scene.referenceImages.map((image, imgIndex) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { background: "neutral200", padding: 2, hasRadius: true, width: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", children: [
1594
+ image.previewUrl ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: image.previewUrl, alt: "preview", style: { width: 50, height: 50, objectFit: "cover" } }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: { width: 50, height: 50, backgroundColor: "#ccc" } }),
1595
+ /* @__PURE__ */ jsxRuntime.jsx(
1596
+ designSystem.IconButton,
1597
+ {
1598
+ onClick: () => {
1599
+ const imageToRemove = scene.referenceImages[imgIndex];
1600
+ if (imageToRemove.previewUrl) {
1601
+ URL.revokeObjectURL(imageToRemove.previewUrl);
1602
+ }
1603
+ const updatedImages = [...scene.referenceImages];
1604
+ updatedImages.splice(imgIndex, 1);
1605
+ formik$1.setFieldValue(`scenes.${index2}.referenceImages`, updatedImages);
1606
+ },
1607
+ label: "Eliminar imagen",
1608
+ children: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {})
1609
+ }
1610
+ )
1611
+ ] }) }, image.id)),
1612
+ /* @__PURE__ */ jsxRuntime.jsx(
1613
+ designSystem.Button,
1614
+ {
1615
+ type: "button",
1616
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.PlusCircle, {}),
1617
+ variant: "secondary",
1618
+ fullWidth: true,
1619
+ onClick: () => {
1620
+ const input = document.createElement("input");
1621
+ input.type = "file";
1622
+ input.accept = "image/*";
1623
+ input.onchange = (e) => {
1624
+ const selectedFile = e.target.files?.[0];
1625
+ if (!selectedFile) return;
1626
+ const newImage = {
1627
+ id: Date.now(),
1628
+ file: selectedFile,
1629
+ previewUrl: URL.createObjectURL(selectedFile)
1630
+ };
1631
+ const newImages = [...scene.referenceImages, newImage];
1632
+ formik$1.setFieldValue(`scenes.${index2}.referenceImages`, newImages.slice(0, 5));
1633
+ };
1634
+ input.click();
1635
+ },
1636
+ disabled: scene.referenceImages.length >= 5,
1637
+ children: "Añadir imagen de referencia"
1638
+ }
1639
+ )
1640
+ ] })
1641
+ ] })
1642
+ ] })
1643
+ ] }, index2) }, `scene-${index2}`)),
1644
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { m: 12, children: /* @__PURE__ */ jsxRuntime.jsx(
1645
+ designSystem.Button,
1646
+ {
1647
+ type: "button",
1648
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.PlusCircle, {}),
1649
+ variant: "secondary",
1650
+ onClick: () => {
1651
+ formik$1.setFieldValue("scenes", [
1652
+ ...formik$1.values.scenes,
1653
+ { prompt: "", durationSeconds: 6, narrationText: "", referenceImages: [] }
1654
+ ]);
1655
+ },
1656
+ fullWidth: true,
1657
+ children: "Añadir Escena"
1658
+ }
1659
+ ) }),
1660
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 12, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { width: "100%", justifyContent: "end", alignItems: "end", children: /* @__PURE__ */ jsxRuntime.jsx(
1661
+ designSystem.Button,
1662
+ {
1663
+ type: "submit",
1664
+ fullWidth: true,
1665
+ disabled: !(formik$1.isValid && formik$1.dirty) || formik$1.isSubmitting,
1666
+ loading: formik$1.isSubmitting,
1667
+ children: "Generar Video"
1668
+ }
1669
+ ) }) })
1670
+ ] }) }) });
1671
+ };
1672
+ const GenerateVideoContainer = () => {
1673
+ const { toggleNotification } = admin.useNotification();
1674
+ const { generateVideoWithScenes } = useImages$1();
1675
+ const { formatMessage } = reactIntl.useIntl();
1676
+ const handleSubmit = async (values, { setSubmitting }) => {
1677
+ try {
1678
+ const formData = new FormData();
1679
+ formData.append("aspectRatio", values.aspectRatio);
1680
+ values.scenes.forEach((scene, index2) => {
1681
+ formData.append(`scenes[${index2}][prompt]`, scene.prompt);
1682
+ formData.append(`scenes[${index2}][durationSeconds]`, scene.durationSeconds.toString());
1683
+ formData.append(`scenes[${index2}][narrationText]`, scene.narrationText || "");
1684
+ scene.referenceImages.forEach((image, imgIndex) => {
1685
+ if (image.file) {
1686
+ formData.append(`scenes[${index2}][referenceImages][${imgIndex}]`, image.file);
1687
+ }
1688
+ });
1689
+ });
1690
+ const response = await generateVideoWithScenes(formData);
1691
+ console.log("🚀 ~ handleSubmit ~ response:", response);
1692
+ toggleNotification({
1693
+ type: "success",
1694
+ message: formatMessage({
1695
+ id: `${index.PLUGIN_ID}.config.load.success`,
1696
+ defaultMessage: "Video generado con éxito"
1697
+ })
1698
+ });
1699
+ } catch (error) {
1700
+ toggleNotification({
1701
+ type: "danger",
1702
+ message: formatMessage({
1703
+ id: `${index.PLUGIN_ID}.config.load.error`,
1704
+ defaultMessage: "Ocurrió un error al generar el video"
1705
+ })
1706
+ });
1707
+ } finally {
1708
+ setSubmitting(false);
1709
+ }
1710
+ };
1711
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1712
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Root, { padding: 6, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "start", children: [
1713
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", children: "Generar video con IA" }),
1714
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: "Para uso exclusivo de InterWare de México" })
1715
+ ] }) }) }),
1716
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { padding: 6, children: [
1717
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { m: 2 }),
1718
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { m: 8, children: /* @__PURE__ */ jsxRuntime.jsx(Form, { onSubmit: handleSubmit }) })
1719
+ ] })
1720
+ ] });
1721
+ };
1722
+ const GenerateVideo = () => {
1723
+ return /* @__PURE__ */ jsxRuntime.jsxs(admin.Page.Main, { children: [
1724
+ /* @__PURE__ */ jsxRuntime.jsx(admin.Page.Title, { children: "Generar video con IA" }),
1725
+ /* @__PURE__ */ jsxRuntime.jsx(GenerateVideoContainer, {})
1726
+ ] });
1727
+ };
1207
1728
  const App = () => {
1208
1729
  const { allowedActions, isLoading } = admin.useRBAC(index.pluginPermissions);
1209
1730
  if (isLoading) {
@@ -1223,7 +1744,11 @@ const App = () => {
1223
1744
  /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Routes, { children: [
1224
1745
  allowedActions.canAccess && /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { index: true, element: /* @__PURE__ */ jsxRuntime.jsx(HomePage, {}) }),
1225
1746
  allowedActions.canAccess && /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "/generate-content", element: /* @__PURE__ */ jsxRuntime.jsx(GenerateContent, {}) }),
1226
- allowedActions.canAccess && /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "/generate-images", element: /* @__PURE__ */ jsxRuntime.jsx(GenerateImages, {}) }),
1747
+ allowedActions.canAccess && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1748
+ /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "/generate-images", element: /* @__PURE__ */ jsxRuntime.jsx(GenerateImages, {}) }),
1749
+ /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "/generate-image", element: /* @__PURE__ */ jsxRuntime.jsx(GenerateImage, {}) }),
1750
+ /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "/generate-video", element: /* @__PURE__ */ jsxRuntime.jsx(GenerateVideo, {}) })
1751
+ ] }),
1227
1752
  /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "*", element: /* @__PURE__ */ jsxRuntime.jsx(admin.Page.Error, {}) })
1228
1753
  ] })
1229
1754
  ] })
@@ -7,8 +7,8 @@ const react = require("react");
7
7
  const designSystem = require("@strapi/design-system");
8
8
  const formik = require("formik");
9
9
  const Yup = require("yup");
10
- const index = require("./index-BVGbP3E-.js");
11
- const getTranslation = require("./getTranslation-CacX7ZX5.js");
10
+ const index = require("./index-D4lanCw0.js");
11
+ const getTranslation = require("./getTranslation-C1jZiBcc.js");
12
12
  function _interopNamespace(e) {
13
13
  if (e && e.__esModule) return e;
14
14
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -5,8 +5,8 @@ import { useCallback, useState, useEffect } from "react";
5
5
  import { Box, Grid, Field, Flex, Button, DesignSystemProvider, Typography } from "@strapi/design-system";
6
6
  import { Formik } from "formik";
7
7
  import * as Yup from "yup";
8
- import { P as PLUGIN_ID } from "./index-B2RuvYul.mjs";
9
- import { g as getTranslation } from "./getTranslation-B97xbmEl.mjs";
8
+ import { P as PLUGIN_ID } from "./index-K1A2opOE.mjs";
9
+ import { g as getTranslation } from "./getTranslation-D3pA_57E.mjs";
10
10
  const useSettings = () => {
11
11
  const { get, post } = useFetchClient();
12
12
  const getSettings = useCallback(
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
- const index = require("./index-BVGbP3E-.js");
2
+ const index = require("./index-D4lanCw0.js");
3
3
  const getTranslation = (id) => `${index.PLUGIN_ID}.${id}`;
4
4
  exports.getTranslation = getTranslation;
@@ -1,4 +1,4 @@
1
- import { P as PLUGIN_ID } from "./index-B2RuvYul.mjs";
1
+ import { P as PLUGIN_ID } from "./index-K1A2opOE.mjs";
2
2
  const getTranslation = (id) => `${PLUGIN_ID}.${id}`;
3
3
  export {
4
4
  getTranslation as g