contentoh-components-library 21.5.78 → 21.5.81

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 (34) hide show
  1. package/dist/ai/utils/compare-strings.js +43 -0
  2. package/dist/components/atoms/GeneralInput/index.js +64 -36
  3. package/dist/components/atoms/GeneralInput/styles.js +1 -1
  4. package/dist/components/atoms/InputFormatter/index.js +45 -21
  5. package/dist/components/atoms/InputFormatter/styles.js +1 -1
  6. package/dist/components/molecules/StatusAsignationInfo/index.js +11 -1
  7. package/dist/components/molecules/TagAndInput/index.js +110 -29
  8. package/dist/components/molecules/TagAndInput/styles.js +2 -2
  9. package/dist/components/organisms/InputGroup/index.js +22 -18
  10. package/dist/components/pages/RetailerProductEdition/RetailerProductEdition.stories.js +92 -785
  11. package/dist/components/pages/RetailerProductEdition/context/provider-product-edition.context.js +59 -260
  12. package/dist/components/pages/RetailerProductEdition/context/reducers/product.js +3 -41
  13. package/dist/components/pages/RetailerProductEdition/index.js +191 -123
  14. package/dist/contexts/AiProductEdition.js +179 -155
  15. package/package.json +1 -1
  16. package/src/ai/utils/compare-strings.js +43 -0
  17. package/src/components/atoms/GeneralInput/index.js +63 -42
  18. package/src/components/atoms/GeneralInput/styles.js +7 -0
  19. package/src/components/atoms/InputFormatter/index.js +51 -23
  20. package/src/components/atoms/InputFormatter/styles.js +62 -10
  21. package/src/components/molecules/StatusAsignationInfo/index.js +9 -1
  22. package/src/components/molecules/TagAndInput/index.js +113 -28
  23. package/src/components/molecules/TagAndInput/styles.js +48 -17
  24. package/src/components/organisms/FullTabsMenu/index.js +1 -1
  25. package/src/components/organisms/InputGroup/index.js +4 -0
  26. package/src/components/pages/RetailerProductEdition/RetailerProductEdition.stories.js +111 -832
  27. package/src/components/pages/RetailerProductEdition/context/provider-product-edition.context.jsx +3 -221
  28. package/src/components/pages/RetailerProductEdition/context/reducers/product.js +3 -43
  29. package/src/components/pages/RetailerProductEdition/index.js +17 -15
  30. package/src/contexts/AiProductEdition.jsx +138 -96
  31. package/src/ai/prompts/attribute.prompt.js +0 -46
  32. package/src/ai/prompts/description.prompt.js +0 -52
  33. package/src/ai/schemas/attribute.schema.js +0 -23
  34. package/src/ai/schemas/description.schema.js +0 -19
@@ -2,14 +2,7 @@ import { useContext, useEffect, useState } from "react";
2
2
  import { createContext } from "react";
3
3
  import axios from "axios";
4
4
 
5
- import AttributeSchema from "../ai/schemas/attribute.schema.js";
6
- import DescriptionSchema from "../ai/schemas/description.schema.js";
7
-
8
- import { GoogleGenAI } from "@google/genai";
9
- import { generateDescriptionPrompt } from "../ai/prompts/description.prompt";
10
- import { generateAttributePrompt } from "../ai/prompts/attribute.prompt";
11
-
12
- const GeminiApiKey = process.env.REACT_APP_GEMINI_API_KEY;
5
+ import { useProviderProductEdition } from "../components/pages/RetailerProductEdition/context/provider-product-edition.context.jsx";
13
6
 
14
7
  export const AiProductEdition = createContext();
15
8
 
@@ -23,22 +16,36 @@ export const useAiProductEdition = () => {
23
16
 
24
17
  export const AiProductEditionProvider = ({
25
18
  children,
26
- isCreatorsEdition = true,
27
- productSelected = null,
28
- activeRetailer
19
+ isCreatorsEdition = false,
20
+ user = {},
21
+ token = ""
29
22
  }) => {
30
23
 
31
24
  const isCreators = isCreatorsEdition;
32
25
 
26
+ const {
27
+ state,
28
+ } = useProviderProductEdition();
29
+
30
+ const productSelected = state.product;
31
+ const activeRetailer = state.active_retailer;
32
+ const datasheetInputs = state.datasheets_inputs?.[1];
33
+ const imagesData = state.images_values;
34
+
33
35
  const [product, setProduct] = useState(null);
34
36
 
35
- const [suggestions, setSuggestions] = useState({});
37
+ const [parsedDatasheet, setParsedDatasheet] = useState([]);
38
+ const [parsedImages, setParsedImages] = useState([]);
36
39
 
40
+ const [suggestions, setSuggestions] = useState({});
37
41
  const [currentSuggestion, setCurrentSuggestion] = useState({});
38
42
 
39
- const ai = new GoogleGenAI({ apiKey: GeminiApiKey });
43
+ const [isAiAvailable, setIsAiAvailable] = useState(false);
44
+
45
+ const [inputsGeneratedWithAi, setInputsGeneratedWithAi] = useState({});
46
+ const [inputsUsingAi, setInputsUsingAi] = useState({});
47
+
40
48
 
41
- const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
42
49
 
43
50
  function setCurrentSuggestionValue({
44
51
  inputId,
@@ -59,22 +66,31 @@ export const AiProductEditionProvider = ({
59
66
  }
60
67
 
61
68
  async function regenerateProductSuggestions ({
62
- inputId,
63
69
  inputName,
64
70
  currentValue,
65
71
  description,
66
72
  maxChar,
67
- type
73
+ type,
74
+
75
+ articleId,
76
+ versionId,
77
+ descriptionId,
78
+ attributeId
68
79
  }) {
69
80
 
70
- if(!inputId || !description || !maxChar || !type) return console.log("Error: No se obtuvieron los parametros obligatorios");
81
+ if(!description || !maxChar || !type) return console.log("Error: No se obtuvieron los parametros obligatorios");
71
82
 
72
83
  const newSuggestions = await generateProductSuggestions({
73
84
  inputName,
74
85
  currentValue,
75
86
  description,
76
87
  maxChar,
77
- type
88
+ type,
89
+
90
+ articleId,
91
+ versionId,
92
+ descriptionId,
93
+ attributeId
78
94
  });
79
95
 
80
96
  if(!Array.isArray(newSuggestions) || newSuggestions.length === 0)
@@ -91,22 +107,26 @@ export const AiProductEditionProvider = ({
91
107
  currentValue = "",
92
108
  description = "",
93
109
  maxChar = 100,
94
- type = "description"
110
+ type = 'description',
111
+
112
+ articleId,
113
+ versionId,
114
+ descriptionId,
115
+ attributeId
95
116
  }) {
96
117
 
97
118
  try {
98
119
 
99
- if(!product) {
120
+ if(!isAiAvailable) return;
121
+
122
+ if(!product)
100
123
  throw new Error("El producto no está definido");
101
- }
102
124
 
103
- console.log({
104
- inputName,
105
- currentValue,
106
- description,
107
- maxChar,
108
- type
109
- });
125
+ if(!Array.isArray(parsedDatasheet) || parsedDatasheet.length === 0)
126
+ throw new Error("No es encontró la ficha técnica");
127
+
128
+ if(!Array.isArray(parsedImages) || parsedImages.length === 0)
129
+ throw new Error("No se encontraron imágenes para la cadena seleccionada");
110
130
 
111
131
  const {
112
132
  upc,
@@ -115,50 +135,37 @@ export const AiProductEditionProvider = ({
115
135
  category
116
136
  } = product;
117
137
 
118
- if (!upc || !description || !productName || !category || !retailer) {
138
+ if (!upc || !description || !productName || !category || !retailer || !articleId || !versionId || (!descriptionId && !attributeId))
119
139
  throw new Error("Faltan parámetros obligatorios para generar sugerencias de IA");
120
- }
121
140
 
122
- const prompt = type === "description" ? generateDescriptionPrompt({
141
+ const payload = {
123
142
  upc,
124
- inputName,
125
- description,
126
- name: productName,
127
- category,
128
- currentValue,
129
- retailer,
130
- maxChar
131
- }) : generateAttributePrompt({
132
- upc,
133
- inputName,
134
- description,
135
- name: productName,
136
- category,
143
+ attributeTitle: inputName,
144
+ attributeDescription: description,
145
+ productName,
137
146
  currentValue,
138
- retailer,
139
- maxChar
140
- })
141
-
142
- const schema = type === "description" ? DescriptionSchema : AttributeSchema;
143
-
144
- const response = await generateContentWithRetry({
145
- model: "gemini-2.5-flash",
146
- contents: [
147
- {
148
- role: "user",
149
- parts: [{ text: prompt }]
150
- }
151
- ],
152
- config: {
153
- responseMimeType: "application/json",
154
- responseSchema : schema,
155
- temperature: 0.1
147
+ categoryName: category,
148
+ retailerName: retailer,
149
+ datasheet: parsedDatasheet,
150
+ images: parsedImages,
151
+ maxChar: maxChar,
152
+
153
+ articleId,
154
+ retailerId: activeRetailer?.id_retailer,
155
+ versionId,
156
+ descriptionId,
157
+ attributeId
158
+ }
159
+
160
+ const { data } = await axios.post(process.env.REACT_APP_GENERATE_AI_ATTRIBUTES, payload, {
161
+ headers: {
162
+ Authorization: token
156
163
  }
157
164
  });
158
165
 
159
- const normalizedResponse = JSON.parse(response.text);
166
+ const results = JSON.parse(data?.body)?.data ?? [];
160
167
 
161
- const results = normalizedResponse?.["results"];
168
+ console.log({results});
162
169
 
163
170
  if(!results)
164
171
  throw new Error("No se encontraron resultados");
@@ -174,34 +181,7 @@ export const AiProductEditionProvider = ({
174
181
 
175
182
  }
176
183
 
177
- async function generateContentWithRetry(modelParams, retries = 5, backoff = 1000) {
178
- try {
179
-
180
- const failoverModel = "gemini-2.5-flash";
181
-
182
- const model = retries > 3 ? "gemini-2.5-flash-lite" : failoverModel;
183
-
184
- return await ai.models.generateContent({
185
- ...modelParams,
186
- model: model
187
- });
188
- } catch (error) {
189
-
190
- const isOverloaded = error.status === 503 || error.message?.includes("overloaded");
191
-
192
- if (retries > 0 && isOverloaded) {
193
- console.warn(`⚠️ Modelo saturado (503). Reintentando en ${backoff}ms... (Quedan ${retries} intentos)`);
194
-
195
- await delay(backoff);
196
-
197
- return generateContentWithRetry(modelParams, retries - 1, backoff * 2);
198
- }
199
-
200
- // Si no es error de sobrecarga o se acabaron los intentos, lanzamos el error real
201
- throw error;
202
- }
203
- }
204
-
184
+ // Verificamos si los servicios de ficha técnica e imágenes estan completos
205
185
  useEffect(() => {
206
186
 
207
187
  if (!productSelected) return;
@@ -223,6 +203,23 @@ export const AiProductEditionProvider = ({
223
203
  category
224
204
  } = currentCategory;
225
205
 
206
+ //Checamos si el servicio de ficha técnica e imagenes esta completo
207
+ const currentRetailerPercentages = productSelected?.percentages?.find(retailer => retailer?.id_retailer === activeRetailer?.id_retailer);
208
+
209
+ if(!currentRetailerPercentages) return console.log("Error: No hay porcentajes disponibles");
210
+
211
+ const {
212
+ required: datasheetRequiredPercent,
213
+ } = currentRetailerPercentages?.datasheet;
214
+
215
+ const {
216
+ required: imagesRequiredPercent,
217
+ } = currentRetailerPercentages?.images;
218
+
219
+ const aiServiceAvailable = (datasheetRequiredPercent >= 100) && (imagesRequiredPercent >= 100) && user?.id_role === 7;
220
+
221
+ setIsAiAvailable(aiServiceAvailable);
222
+
226
223
  setProduct({
227
224
  upc,
228
225
  productName,
@@ -232,19 +229,64 @@ export const AiProductEditionProvider = ({
232
229
 
233
230
  }, [productSelected]);
234
231
 
232
+ // Inicializamos la ficha técnica con el objetivo de posteriormente pasarlo a la generación con IA
233
+ useEffect(() => {
234
+
235
+ if (!datasheetInputs) return;
236
+
237
+ const datasheetToArray = Object.values(datasheetInputs);
238
+
239
+ const normalizedDatasheet = datasheetToArray.map(attribute => ({
240
+ description: attribute?.description,
241
+ name: attribute?.name,
242
+ type: attribute?.type,
243
+ value: attribute?.value
244
+ }));
245
+
246
+ setParsedDatasheet(normalizedDatasheet);
247
+
248
+ }, [datasheetInputs]);
249
+
250
+ // Inicializamos las imágenes con el objetivo de posteriormente pasarlo a la generación con IA
251
+ useEffect(() => {
252
+
253
+ const currentRetailerImageInputs = imagesData?.inputsByRetailer?.[0]?.filter(input => input?.id_retailer === activeRetailer?.id_retailer);
254
+
255
+ if(!Array.isArray(currentRetailerImageInputs) || currentRetailerImageInputs.length === 0) return console.log('No existen imágenes para la cadena seleccionada')
256
+
257
+ const allProductImages = imagesData?.values;
258
+
259
+ if(!Array.isArray(allProductImages) || allProductImages.length === 0) return console.log("No existen imágenes para el producto");
260
+
261
+ //Obtenemos las imágenes para el retailer seleccionado
262
+ const currentParsedImages = allProductImages.filter(image => {
263
+
264
+ const imageId = image?.image_id;
265
+ const foundedImage = currentRetailerImageInputs.some(retailerImage => retailerImage?.id_image === imageId);
266
+
267
+ return foundedImage;
268
+ });
269
+
270
+ setParsedImages(currentParsedImages);
271
+
272
+ }, [imagesData]);
273
+
235
274
  return (
236
275
  <AiProductEdition.Provider
237
276
  value={{
238
277
  isCreators: isCreators,
239
278
  suggestions,
240
279
  currentSuggestion,
280
+ isAiAvailable,
281
+ inputsGeneratedWithAi,
282
+ inputsUsingAi,
241
283
 
242
-
243
-
244
- generateProductSuggestions,
245
- regenerateProductSuggestions,
284
+ setInputsUsingAi,
285
+ setInputsGeneratedWithAi,
246
286
  setSuggestions,
247
287
  setCurrentSuggestionValue,
288
+ generateProductSuggestions,
289
+ regenerateProductSuggestions,
248
290
  clearCurrentSuggestions,
249
291
 
250
292
  }}
@@ -1,46 +0,0 @@
1
- export const generateAttributePrompt = ({
2
- upc = 0,
3
- inputName = "",
4
- description = "",
5
- currentValue = "",
6
- name = "",
7
- category = "",
8
- retailer = "",
9
- maxChar = 100,
10
- }) => {
11
-
12
- return `
13
- Eres un especialista en la generación, optimización, mejora y captura de atributos de la ficha técnica de productos para catálogos en línea.
14
- Tu tarea es crear atributos claros, concisos y relevantes que resalten las características y beneficios del producto, utilizando un lenguaje preciso y adaptado al público objetivo.
15
-
16
- Datos del producto:
17
- - UPC: ${upc}
18
- - Nombre del producto: ${name}
19
- - Categoría: ${category}
20
- - Nombre del atributo: ${inputName}
21
- - Requerimiento del atributo: ${description}
22
- - Valor actual del atributo: ${currentValue}
23
- - Cadena comercial dirigida: ${retailer}
24
-
25
- Instrucciones:
26
- 1. Analiza el nombre del producto y la categoría para entender su contexto.
27
- 2. Analiza la descripción del atributo actual del producto.
28
- 3. Identifica la información clave del atributo que sean relevantes y útiles para los clientes potenciales.
29
- 4. Genera una lista de atributos que:
30
- - Cumplan con la descripcion del atributo proporcionada, no inventes datos o cambies el contexto de lo que pide la descripción del atributo.
31
- - Sean claros y fáciles de entender.
32
- - Destaquen las características y beneficios clave del producto.
33
- - Utilicen un lenguaje preciso y adaptado al público objetivo.
34
- - Mantengan un tono profesional y coherente con la marca.
35
- - Aumenten la probabilidad de compra del producto.
36
- - No excedan los ${maxChar} caracteres en total.
37
- - Si existe ejemplo en la descripción del atributo, sigue el mismo formato para generar los atributos.
38
- 5. No incluyas emojis ni signos especiales (*/+´!¡?¿)
39
- 6. No repitas el encabezado: ${inputName}
40
- 7. No incluyas call to action, ejemplo: "!Compra ya!" "!Da click!" "!Apurate!"
41
-
42
- Asegúrate de que los atributos generados cumplan con todas las instrucciones proporcionadas.
43
-
44
- No lo olvides, el objetivo principal es mejorar la captura de atributos para la ficha técnica del producto para atraer, convencer y dar la información completa a los clientes potenciales que puedan realizar una compra.
45
- `
46
- }
@@ -1,52 +0,0 @@
1
- // Cadena y Proveedor
2
-
3
- /**
4
- * La cadena ${cadena} tiene estas reglas ${reglas} para el tipo de descripcion que es: ${descripcion}
5
- */
6
-
7
- export const generateDescriptionPrompt = ({
8
- upc = 0,
9
- inputName = "",
10
- description = "",
11
- currentValue = "",
12
- name = "",
13
- category = "",
14
- retailer = "",
15
- maxChar = 100,
16
- }) => {
17
-
18
- return `
19
- Eres un especialista en la generación, optimización y mejora de descripciones de productos para catálogos en línea.
20
- Tu tarea es crear descripciones claras, concisas y atractivas que resalten las características y beneficios del producto, utilizando un lenguaje persuasivo y adaptado al público objetivo.
21
-
22
- Datos del producto:
23
- - UPC: ${upc}
24
- - Nombre del producto: ${name}
25
- - Categoría: ${category}
26
- - Encabezado de la descripción: ${inputName}
27
- - Requerimiento de la descripcion: ${description}
28
- - Descripcion actual del producto: ${currentValue}
29
- - Cadena comercial dirigida: ${retailer}
30
-
31
- Instrucciones:
32
- 1. Analiza la descripción actual del producto en caso de tenerla.
33
- 2. Identifica áreas de mejora, como claridad, concisión, atractivo y relevancia.
34
- 3. Genera una descripción que:
35
- - Sea clara y fácil de entender.
36
- - Destaque las características y beneficios clave del producto.
37
- - Utilice un lenguaje persuasivo y adaptado al público objetivo.
38
- - Mantenga un tono profesional y coherente con la marca.
39
- - No exceda los ${maxChar} caracteres.
40
- - Aumente la probabilidad de compra del producto, utilizando persuasión en la necesidad de compra del producto.
41
- 4. No incluyas emojis ni signos especiales (*/+´!¡?¿)
42
- 5. No repitas el encabezado: ${inputName}
43
- 6. No incluyas call to action, ejemplo: "!Compra ya!" "!Da click!" "!Apurate!"
44
-
45
-
46
- Asegúrate de que la descripción generada cumpla con todas las instrucciones proporcionadas.
47
-
48
- No lo olvides, el objetivo principal es mejorar la descripción del producto para atraer y convencer a los clientes potenciales de realizar una compra. Eres un experto en marketing y redacción persuasiva.
49
-
50
- Nota: No estas hablando con los clientes, estas descripciones irán en la tienda de E-commerce de la cadena comercial. No realices saludos, despedidas, sugerencias
51
- `
52
- }
@@ -1,23 +0,0 @@
1
- const schema = {
2
- type: "object",
3
- properties: {
4
- results: {
5
- type: "array",
6
- items: {
7
- type: "object",
8
- properties: {
9
- label: { type: "string" },
10
- value: { type: "string" }
11
- }
12
- },
13
- maxItems: 3
14
- },
15
- compliance_warnings: {
16
- type: "array",
17
- items: { type: "string" }
18
- }
19
- },
20
- required: ["results"]
21
- }
22
-
23
- export default schema;
@@ -1,19 +0,0 @@
1
- const schema = {
2
- type: "object",
3
- properties: {
4
- results: {
5
- type: "array",
6
- items: {
7
- type: "object",
8
- properties: {
9
- value: { type: "string" }
10
- }
11
- },
12
- minItems: 1,
13
- maxItems: 3
14
- }
15
- },
16
- required: ["results"]
17
- }
18
-
19
- export default schema;