eubottura commited on
Commit
2b59679
·
verified ·
1 Parent(s): 8549f24

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +114 -260
index.html CHANGED
@@ -1,14 +1,13 @@
1
  <!DOCTYPE html>
2
- <html lang="pt-BR">
3
 
4
  <head>
5
  <meta charset="UTF-8">
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>AI Prompt Gen | E-Commerce Specialist</title>
8
  <link rel="preconnect" href="https://fonts.googleapis.com">
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
- <link
11
- href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
12
  rel="stylesheet">
13
  <style>
14
  :root {
@@ -90,7 +89,7 @@
90
  width: 100%;
91
  padding: 2rem;
92
  display: grid;
93
- grid-template-columns: 400px 1fr;
94
  gap: 2rem;
95
  }
96
 
@@ -143,7 +142,7 @@
143
 
144
  textarea {
145
  resize: vertical;
146
- min-height: 120px;
147
  }
148
 
149
  input:focus,
@@ -185,7 +184,7 @@
185
  .output-container {
186
  display: flex;
187
  flex-direction: column;
188
- gap: 2rem;
189
  }
190
 
191
  .results-header {
@@ -207,7 +206,7 @@
207
 
208
  .grid {
209
  display: grid;
210
- grid-template-columns: repeat(auto-fill, minmax(450px, 1fr));
211
  gap: 1.5rem;
212
  }
213
 
@@ -408,7 +407,7 @@
408
  <path d="M12 12l-2-2"></path>
409
  <path d="M12 16l-2-2"></path>
410
  </svg>
411
- PromptGen AI
412
  </div>
413
  <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link">Built with
414
  anycoder</a>
@@ -423,52 +422,51 @@
423
  <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path>
424
  <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>
425
  </svg>
426
- Dados de Entrada
427
  </h2>
428
 
429
  <div class="form-group">
430
- <label for="productName">Nome do Produto (INPUT_PRODUCT_NAME)</label>
431
- <textarea id="productName" placeholder="e.g. Bermuda Viena Feminina em Algodão High-Waisted Pague 3 Leve 5"></textarea>
432
- <p class="helper-text">Inclua material, gênero, recursos estruturais e oferta promocional.</p>
433
  </div>
434
 
435
  <div class="form-group">
436
- <label for="colorList">Lista de Cores (INPUT_COLORS)</label>
437
  <input type="text" id="colorList" placeholder="e.g. Black/Grey/Blue/Green">
438
- <p class="helper-text">Use vírgulas, barras ou + para separar (ex: Green, Khaki, White).</p>
439
  </div>
440
 
441
- <button class="btn-primary" id="generateBtn">Gerar Prompts</button>
442
  </aside>
443
 
444
  <!-- Output Section -->
445
  <section class="output-container">
446
  <div class="results-header">
447
- <h2>Resultados Gerados</h2>
448
- <span class="status-badge" id="statusBadge">Aguardando entrada...</span>
449
  </div>
450
 
451
  <div id="resultsGrid" class="grid">
452
  <div class="empty-state">
453
  <div class="empty-icon">⚡</div>
454
- <h3>Pronto para Gerar</h3>
455
- <p>Insira os detalhes do produto e clique no botão para criar seu conjunto de prompts.</p>
456
  </div>
457
  </div>
458
  </section>
459
  </main>
460
 
461
- <div id="toast" class="toast">Copiado para a área de transferência!</div>
462
 
463
  <script>
464
- // --- Constants & Templates ---
465
-
466
  const TEMPLATES = [
467
  {
468
  id: "detail_1",
469
  title: "DETALHE DO PRODUTO",
470
  type: "SINGLE",
471
- content: `STRICT VISUAL MATCH TAKEN WITH IPHONE. 1:1 Square format. The subject is the EXACT "Bermuda Viena Feminina" in Linen and Cotton. The design must be IDENTICAL to the reference: high-waisted structure with precise vertical front seams (nervuras). A feminine hand is gently pinching the fabric on the front seam to display the exact ribbing detail and texture. Extreme close-up focus on the material weave and seam construction. Natural sunlight, casual Brazilian atmosphere, amateur raw photo style, natural beige color. DO NOT ALTER THE SILHOUETTE OR DETAILS. --ar 1:1 --style raw --v 6.0`
472
  },
473
  {
474
  id: "detail_2",
@@ -492,13 +490,13 @@
492
  id: "mirror",
493
  title: "AVALIAÇÃO ESPELHO",
494
  type: "SINGLE",
495
- content: `Authentic Shopee-style customer review photo, raw vertical mirror selfie, 9:18 aspect ratio. A female model is standing in front of a bathroom mirror, framed from the neck up (no face visible, hiding face). She is wearing the EXACT "Bermuda Viena" high-waisted shorts. STRICT VISUAL FIDELITY: The shorts must feature the specific vertical front ribs/nervuras seams, linen and cotton fabric texture, natural beige color. The setting is a typical Brazilian home bathroom with natural ambient light. The image must look like a real amateur photo taken by a customer, realistic phone camera grain, showing the fit of the high waist and the straight leg cut. Candid, unposed, honest product demonstration. --ar 9:16 --style raw --v 6.0`
496
  },
497
  {
498
  id: "bed",
499
  title: "AVALIAÇÃO CAMA",
500
  type: "GLOBAL",
501
- content: `Authentic Brazilian Shopee customer review photo, raw vertical mobile shot, 9:16 aspect ratio. THE SCENE: A messy, unorganized pile of exactly 5 pairs of 'Bermuda Viena' shorts thrown casually across a bedroom bed. The shorts are fully unfolded and lying in a heap. COLOR CRITICAL: The pile must display the specific 5 colors from the product listing: Green, Khaki, White, Black, and Beige. STRICT FIDELITY: Exact 'Bermuda Viena' model, high-waisted, vertical front ribs/nervuras, linen texture. LOGO: Brand tag visible. VIBE: Honest amateur photo, natural daylight, typical home setting, showing the variety of the purchase. --ar 9:16 --style raw --v 6.0`
502
  },
503
  {
504
  id: "main",
@@ -520,51 +518,32 @@
520
  }
521
  ];
522
 
523
- // --- Logic Functions ---
524
-
525
- /**
526
- * Step 1: Advanced Variable Extraction
527
- */
528
  function extractData(productNameInput, colorsInput) {
529
- // 1. PRODUCT_NAME: Clean input
530
  let rawName = productNameInput.trim();
531
- let promoOffer = null;
532
- let totalQuantity = 0;
533
-
534
- // Extract Promotional Offer (e.g., "Pague 3, Leve 5")
535
  const promoRegex = /pague\s*\d+\s*(?:,|e)?\s*leve\s*\d+/i;
536
  const promoMatch = rawName.match(promoRegex);
 
537
 
538
- if (promoMatch) {
539
- promoOffer = promoMatch[0];
540
- // Extract Quantity from offer
541
- const qtyMatch = promoOffer.match(/leve\s*(\d+)/i);
542
- if (qtyMatch) {
543
- totalQuantity = parseInt(qtyMatch[1], 10);
544
- }
545
- }
546
-
547
- // Clean Product Name (Remove promo text)
548
  let productName = rawName.replace(promoRegex, '').trim();
549
- // Remove trailing commas or artifacts
550
  productName = productName.replace(/,\s*$/, '').trim();
551
 
552
- // 2. MATERIAL: Identify and translate
553
  const materialMap = {
554
- 'algodão': 'Cotton',
555
- 'algodon': 'Cotton',
556
  'linho': 'Linen',
557
- 'poliéster': 'Polyester',
558
- 'poliester': 'Polyester',
559
  'seda': 'Silk',
560
- 'jeans': 'Denim',
561
- 'denim': 'Denim',
562
  'couro': 'Leather'
563
  };
564
-
565
  let material = 'Cotton'; // Default
566
  const lowerInput = rawName.toLowerCase();
567
-
568
  for (const [key, value] of Object.entries(materialMap)) {
569
  if (lowerInput.includes(key)) {
570
  material = value;
@@ -578,41 +557,31 @@
578
  gender = 'Male';
579
  }
580
 
581
- // 4. HAS_GIFTS
582
- const hasGifts = /brinde|bônus|presente|bonus/i.test(rawName);
583
-
584
- // 5. TOTAL_QUANTITY (Fallback if no promo offer)
585
- if (totalQuantity === 0) {
586
- // Will be calculated from color array later if 0
 
 
587
  }
588
 
589
- // 6. STRUCTURAL_FEATURES
 
 
 
590
  const hasHighWaisted = /(?:high-waisted|alta cintura|cintura alta)/i.test(rawName);
591
  const hasRibs = /(?:nervuras|ribs|costuras)/i.test(rawName);
592
 
593
- // 7. COLORS
594
- // Split delimiters (/, ,, or +)
595
  const rawColors = colorsInput.split(/[\/,+]/).map(c => c.trim()).filter(c => c.length > 0);
596
 
597
- // Color Translation Map
598
  const colorMap = {
599
- 'verde': 'Green',
600
- 'vermelho': 'Red',
601
- 'azul': 'Blue',
602
- 'amarelo': 'Yellow',
603
- 'laranja': 'Orange',
604
- 'roxo': 'Purple',
605
- 'rosa': 'Pink',
606
- 'marrom': 'Brown',
607
- 'preto': 'Black',
608
- 'branco': 'White',
609
- 'cinza': 'Grey',
610
- 'grey': 'Grey',
611
- 'bege': 'Beige',
612
- 'khaki': 'Khaki',
613
- 'cáqui': 'Khaki',
614
- 'dourado': 'Gold',
615
- 'prata': 'Silver'
616
  };
617
 
618
  const colorArray = rawColors.map(c => {
@@ -620,12 +589,12 @@
620
  return colorMap[lowerC] || c;
621
  });
622
 
623
- // Calculate Total Quantity from colors if not set by promo
624
  if (totalQuantity === 0) {
625
  totalQuantity = colorArray.length > 0 ? colorArray.length : 1;
626
  }
627
 
628
- // Format List String (e.g., "Green, Khaki, White, Black, and Beige")
629
  let colorListString = '';
630
  if (colorArray.length === 0) {
631
  colorListString = 'Assorted Colors';
@@ -653,202 +622,87 @@
653
  };
654
  }
655
 
656
- /**
657
- * Step 2, 3, & 4: Logic, Substitution & Output Generation
658
- */
659
- function generateFinalPrompts(data) {
660
  let singleColorIndex = 0;
661
 
662
  return TEMPLATES.map(template => {
663
  let text = template.content;
664
 
665
- // --- Step 3: Color Distribution Logic ---
666
  let assignedColor = '';
667
  if (template.type === "GLOBAL") {
668
- // Use Color List String
669
  assignedColor = data.colorListString;
670
  } else {
671
- // Use Unique Color Rotation
672
  assignedColor = data.colorArray[singleColorIndex % data.colorArray.length] || 'Assorted';
673
  singleColorIndex++;
674
  }
675
 
676
- // --- Step 3: Template Substitution (Global Replacements) ---
677
-
678
- // 1. Replace Product Name
679
- // Replace "Bermuda Viena Feminina", "'Bermuda Viena'", "Bermuda Viena"
680
- const nameVariations = [
681
- /Bermuda Viena Feminina/g,
682
- /'Bermuda Viena'/g,
683
- /Bermuda Viena/g
684
- ];
685
- nameVariations.forEach(regex => {
686
- text = text.replace(regex, data.productName);
687
- });
688
-
689
- // 2. Replace Material
690
- // "Linen and Cotton", "linen and cotton", "Linen", "Cotton"
691
- // We replace the specific blend mention first, then individual if needed
692
- const matRegex = /linen and cotton/gi;
693
- text = text.replace(matRegex, data.material);
694
-
695
- // Also catch standalone "linen" or "cotton" if the input is just one
696
- if (data.material === 'Linen') {
697
- text = text.replace(/\bcotton\b/gi, 'Linen');
698
- } else if (data.material === 'Cotton') {
699
- text = text.replace(/\blinen\b/gi, 'Cotton');
700
  }
701
 
702
- // 3. Replace Quantity
703
- // "5 pairs", "5 identical copies", "exactly 5 pairs"
704
- const qStr = data.totalQuantity.toString();
705
- text = text.replace(/5 pairs/g, `${qStr} pairs`);
706
- text = text.replace(/exactly 5 copies/g, `exactly ${qStr} copies`);
707
- text = text.replace(/exactly 5 pairs/g, `exactly ${qStr} pairs`);
708
- text = text.replace(/specific 5 colors/g, `specific ${qStr} colors`);
709
- text = text.replace(/5 identical copies/g, `${qStr} identical copies`);
710
- text = text.replace(/display the following distinct colors: Green \(Verde\), Khaki \(Cáki\), White \(Branco\), Black \(Preto\), and Beige/g, `display the distinct colors: ${data.colorListString}`);
711
-
712
- // 4. Replace Gender
713
- // Replace "female model", "women's", "feminine hand"
714
- if (data.gender === 'Male') {
715
- text = text.replace(/female model/gi, 'male model');
716
- text = text.replace(/women's/gi, "men's");
717
- text = text.replace(/feminine hand/gi, 'masculine hand');
718
  }
719
 
720
- // 5. Replace Colors
721
- // Replace specific color lists
722
- const oldColorList = /Green, Khaki, White, Black, and Beige/g;
723
- text = text.replace(oldColorList, data.colorListString);
724
-
725
- const oldColorList2 = /Green, Khaki, White, Black, and Bege/g;
726
- text = text.replace(oldColorList2, data.colorListString);
727
-
728
- const oldColorList3 = /Verde \(Green\), Cáqui \(Khaki\), Branco \(White\), Preto \(Black\), Beige/g;
729
- // Create a mapped string for the Portuguese/English mix in the template
730
- const mappedColorString = data.colorArray.map(c => {
731
- // Simple mapping back for the specific template format or just use the list
732
- return c;
733
- }).join(', ');
734
- text = text.replace(oldColorList3, mappedColorString);
735
-
736
- // Replace single color mentions for single items
737
- if (template.type !== 'GLOBAL') {
738
- text = text.replace(/natural beige color/g, `${assignedColor.toLowerCase()} color`);
739
- text = text.replace(/beige color/g, `${assignedColor.toLowerCase()} color`);
740
- // Replace standalone "beige" at end of sentence or description
741
- text = text.replace(/, beige\./g, `, ${assignedColor}.`);
742
- text = text.replace(/ is beige\./g, ` is ${assignedColor}.`);
743
  }
744
 
745
- return { ...template, content: text, generatedColor: assignedColor };
746
- });
747
- }
748
-
749
- /**
750
- * UI Functions
751
- */
752
- function renderResults(prompts) {
753
- const grid = document.getElementById('resultsGrid');
754
- const statusBadge = document.getElementById('statusBadge');
755
-
756
- // Clear previous results
757
- grid.innerHTML = '';
758
-
759
- if (prompts.length === 0) {
760
- grid.innerHTML = `
761
- <div class="empty-state" style="grid-column: 1 / -1;">
762
- <div class="empty-icon">⚡</div>
763
- <h3>Sem resultados</h3>
764
- <p>Não foi possível gerar prompts com os dados fornecidos.</p>
765
- </div>`;
766
- statusBadge.textContent = 'Erro';
767
- return;
768
- }
769
-
770
- statusBadge.textContent = `${prompts.length} Prompts Gerados`;
771
-
772
- prompts.forEach((prompt, index) => {
773
- const card = document.createElement('div');
774
- card.className = 'card';
775
- card.style.animationDelay = `${index * 0.05}s`;
776
-
777
- card.innerHTML = `
778
- <div class="card-header">
779
- <div class="card-title">
780
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline></svg>
781
- ${prompt.title}
782
- </div>
783
- <span class="card-type">${prompt.type}</span>
784
- </div>
785
- <div class="card-content">${prompt.content}</div>
786
- <div class="card-actions">
787
- <button class="btn-copy" onclick="copyToClipboard(this)">
788
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2-2"></path></svg>
789
- Copiar
790
- </button>
791
- </div>
792
- `;
793
- grid.appendChild(card);
794
- });
795
- }
796
-
797
- // Copy functionality
798
- window.copyToClipboard = function(button) {
799
- const card = button.closest('.card');
800
- const content = card.querySelector('.card-content').innerText;
801
-
802
- navigator.clipboard.writeText(content).then(() => {
803
- showToast();
804
- const originalHTML = button.innerHTML;
805
- button.innerHTML = `
806
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>
807
- Copiado!
808
- `;
809
- button.classList.add('copied');
810
-
811
- setTimeout(() => {
812
- button.innerHTML = originalHTML;
813
- button.classList.remove('copied');
814
- }, 2000);
815
- }).catch(err => {
816
- console.error('Erro ao copiar: ', err);
817
- alert('Não foi possível copiar o texto automaticamente.');
818
- });
819
- };
820
-
821
- function showToast() {
822
- const toast = document.getElementById('toast');
823
- toast.classList.add('show');
824
- setTimeout(() => {
825
- toast.classList.remove('show');
826
- }, 3000);
827
- }
828
-
829
- // --- Initialization ---
830
- document.addEventListener('DOMContentLoaded', () => {
831
- const generateBtn = document.getElementById('generateBtn');
832
-
833
- generateBtn.addEventListener('click', () => {
834
- const productNameInput = document.getElementById('productName').value;
835
- const colorsInput = document.getElementById('colorList').value;
836
 
837
- if (!productNameInput.trim()) {
838
- alert('Por favor, insira pelo menos o nome do produto.');
839
- return;
 
 
 
 
 
840
  }
841
 
842
- // Execute Logic
843
- const extractedData = extractData(productNameInput, colorsInput);
844
- const finalPrompts = generateFinalPrompts(extractedData);
845
-
846
- // Update UI
847
- renderResults(finalPrompts);
848
- });
849
- });
850
 
851
- </script>
852
- </body>
 
 
 
 
853
 
854
- </html
 
 
1
  <!DOCTYPE html>
2
+ <html lang="en">
3
 
4
  <head>
5
  <meta charset="UTF-8">
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>AI Prompt Gen | E-Commerce Asset System v4.7</title>
8
  <link rel="preconnect" href="https://fonts.googleapis.com">
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
 
11
  rel="stylesheet">
12
  <style>
13
  :root {
 
89
  width: 100%;
90
  padding: 2rem;
91
  display: grid;
92
+ grid-template-columns: 380px 1fr;
93
  gap: 2rem;
94
  }
95
 
 
142
 
143
  textarea {
144
  resize: vertical;
145
+ min-height: 100px;
146
  }
147
 
148
  input:focus,
 
184
  .output-container {
185
  display: flex;
186
  flex-direction: column;
187
+ gap: 1rem;
188
  }
189
 
190
  .results-header {
 
206
 
207
  .grid {
208
  display: grid;
209
+ grid-template-columns: repeat(auto-fill, minmax(500px, 1fr));
210
  gap: 1.5rem;
211
  }
212
 
 
407
  <path d="M12 12l-2-2"></path>
408
  <path d="M12 16l-2-2"></path>
409
  </svg>
410
+ PromptGen AI v4.7
411
  </div>
412
  <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link">Built with
413
  anycoder</a>
 
422
  <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path>
423
  <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>
424
  </svg>
425
+ Input Data
426
  </h2>
427
 
428
  <div class="form-group">
429
+ <label for="productName">INPUT_PRODUCT_NAME</label>
430
+ <textarea id="productName" placeholder="e.g. Bermuda Viena Feminina Algodão Pague 3 Leve 5"></textarea>
431
+ <p class="helper-text">Include material, gender, features (High-waisted, Nervuras), and offer.</p>
432
  </div>
433
 
434
  <div class="form-group">
435
+ <label for="colorList">INPUT_COLORS</label>
436
  <input type="text" id="colorList" placeholder="e.g. Black/Grey/Blue/Green">
437
+ <p class="helper-text">Use commas, slashes, or + to separate (e.g., Verde, Cáqui, White).</p>
438
  </div>
439
 
440
+ <button class="btn-primary" id="generateBtn">Generate Prompts</button>
441
  </aside>
442
 
443
  <!-- Output Section -->
444
  <section class="output-container">
445
  <div class="results-header">
446
+ <h2>Generated Results</h2>
447
+ <span class="status-badge" id="statusBadge">Waiting for input...</span>
448
  </div>
449
 
450
  <div id="resultsGrid" class="grid">
451
  <div class="empty-state">
452
  <div class="empty-icon">⚡</div>
453
+ <h3>Ready to Generate</h3>
454
+ <p>Enter product details and click the button to execute the logic engine.</p>
455
  </div>
456
  </div>
457
  </section>
458
  </main>
459
 
460
+ <div id="toast" class="toast">Copied to clipboard!</div>
461
 
462
  <script>
463
+ // --- TEMPLATES (BLOCKS 1-9) ---
 
464
  const TEMPLATES = [
465
  {
466
  id: "detail_1",
467
  title: "DETALHE DO PRODUTO",
468
  type: "SINGLE",
469
+ content: `STRICT VISUAL MATCH TAKEN WITH IPHONE. 1:1 Square format. The subject is the EXACT "Bermuda Viena Feminina" in Linen and Cotton. The design must be IDENTICAL to the reference: high-waisted structure with precise vertical front seams (nervuras). A feminine hand is gently pinching the fabric on the front seam to display the exact ribbing detail and texture. Extreme close-up focus on the material weave and seam construction. Natural sunlight, casual Brazilian atmosphere, amateur raw photo style, beige color. DO NOT ALTER THE SILHOUETTE OR DETAILS. --ar 1:1 --style raw --v 6.0`
470
  },
471
  {
472
  id: "detail_2",
 
490
  id: "mirror",
491
  title: "AVALIAÇÃO ESPELHO",
492
  type: "SINGLE",
493
+ content: `Authentic Shopee-style customer review photo, raw vertical mirror selfie, 9:18 aspect ratio. A female model is standing in front of a bathroom mirror, framed from the neck up (no face visible, hiding face). She is wearing the EXACT "Bermuda Viena" high-waisted shorts. STRICT VISUAL FIDELITY: The shorts must feature the specific vertical front ribs/nervuras seams, linen and cotton fabric texture, beige color. The setting is a typical Brazilian home bathroom with natural ambient light. The image must look like a real amateur photo taken by a customer, realistic phone camera grain, showing the fit of the high waist and the straight leg cut. Candid, unposed, honest product demonstration. --ar 9:16 --style raw --v 6.0`
494
  },
495
  {
496
  id: "bed",
497
  title: "AVALIAÇÃO CAMA",
498
  type: "GLOBAL",
499
+ content: `Authentic Brazilian Shopee customer review photo, raw vertical mobile shot, 9:16 aspect ratio. THE SCENE: A messy, unorganized pile of exactly 5 pairs of 'Bermuda Viena' shorts thrown casually across a bedroom bed. The shorts are fully unfolded and lying in a heap. COLOR CRITICAL: The pile must display the specific 5 colors from the product listing: Green, Khaki, White, Black, and Bege. STRICT FIDELITY: Exact 'Bermuda Viena' model, high-waisted, vertical front ribs/nervuras, linen texture. LOGO: Brand tag visible. VIBE: Honest amateur photo, natural daylight, typical home setting, showing the variety of the purchase. --ar 9:16 --style raw --v 6.0`
500
  },
501
  {
502
  id: "main",
 
518
  }
519
  ];
520
 
521
+ // --- STEP 1: VARIABLE EXTRACTION & PARSING ---
 
 
 
 
522
  function extractData(productNameInput, colorsInput) {
 
523
  let rawName = productNameInput.trim();
524
+
525
+ // 1. PRODUCT_NAME (Cleaned)
526
+ // Remove promo text for the clean name, but keep it for PROMOTIONAL_OFFER extraction
 
527
  const promoRegex = /pague\s*\d+\s*(?:,|e)?\s*leve\s*\d+/i;
528
  const promoMatch = rawName.match(promoRegex);
529
+ let promoOffer = promoMatch ? promoMatch[0] : null;
530
 
531
+ // Clean Name: Remove promo offer
 
 
 
 
 
 
 
 
 
532
  let productName = rawName.replace(promoRegex, '').trim();
533
+ // Remove trailing punctuation artifacts
534
  productName = productName.replace(/,\s*$/, '').trim();
535
 
536
+ // 2. MATERIAL (Extract & Translate)
537
  const materialMap = {
538
+ 'algodão': 'Cotton', 'algodon': 'Cotton',
 
539
  'linho': 'Linen',
540
+ 'poliéster': 'Polyester', 'poliester': 'Polyester',
 
541
  'seda': 'Silk',
542
+ 'jeans': 'Denim', 'denim': 'Denim',
 
543
  'couro': 'Leather'
544
  };
 
545
  let material = 'Cotton'; // Default
546
  const lowerInput = rawName.toLowerCase();
 
547
  for (const [key, value] of Object.entries(materialMap)) {
548
  if (lowerInput.includes(key)) {
549
  material = value;
 
557
  gender = 'Male';
558
  }
559
 
560
+ // 4. PROMOTIONAL_OFFER (Already extracted above)
561
+
562
+ // 5. TOTAL_QUANTITY
563
+ let totalQuantity = 0;
564
+ // Priority A: Extract from "Leve [X]"
565
+ if (promoOffer) {
566
+ const qtyMatch = promoOffer.match(/leve\s*(\d+)/i);
567
+ if (qtyMatch) totalQuantity = parseInt(qtyMatch[1], 10);
568
  }
569
 
570
+ // 6. HAS_GIFTS
571
+ const hasGifts = /brinde|bônus|presente|bonus/i.test(rawName);
572
+
573
+ // 7. STRUCTURAL_FEATURES
574
  const hasHighWaisted = /(?:high-waisted|alta cintura|cintura alta)/i.test(rawName);
575
  const hasRibs = /(?:nervuras|ribs|costuras)/i.test(rawName);
576
 
577
+ // 8. COLORS (Split & Translate)
 
578
  const rawColors = colorsInput.split(/[\/,+]/).map(c => c.trim()).filter(c => c.length > 0);
579
 
 
580
  const colorMap = {
581
+ 'verde': 'Green', 'vermelho': 'Red', 'azul': 'Blue', 'amarelo': 'Yellow',
582
+ 'laranja': 'Orange', 'roxo': 'Purple', 'rosa': 'Pink', 'marrom': 'Brown',
583
+ 'preto': 'Black', 'branco': 'White', 'cinza': 'Grey', 'grey': 'Grey',
584
+ 'bege': 'Beige', 'khaki': 'Khaki', 'cáqui': 'Khaki', 'dourado': 'Gold', 'prata': 'Silver'
 
 
 
 
 
 
 
 
 
 
 
 
 
585
  };
586
 
587
  const colorArray = rawColors.map(c => {
 
589
  return colorMap[lowerC] || c;
590
  });
591
 
592
+ // Priority B: Count from colors if quantity is 0
593
  if (totalQuantity === 0) {
594
  totalQuantity = colorArray.length > 0 ? colorArray.length : 1;
595
  }
596
 
597
+ // Format Color List String (e.g., "Green, Khaki, White, Black, and Beige")
598
  let colorListString = '';
599
  if (colorArray.length === 0) {
600
  colorListString = 'Assorted Colors';
 
622
  };
623
  }
624
 
625
+ // --- STEP 2, 3, & 4: LOGIC, DISTRIBUTION & INJECTION ---
626
+ function processTemplates(data) {
 
 
627
  let singleColorIndex = 0;
628
 
629
  return TEMPLATES.map(template => {
630
  let text = template.content;
631
 
632
+ // --- STEP 3: COLOR DISTRIBUTION ---
633
  let assignedColor = '';
634
  if (template.type === "GLOBAL") {
 
635
  assignedColor = data.colorListString;
636
  } else {
637
+ // Single Display Rotation
638
  assignedColor = data.colorArray[singleColorIndex % data.colorArray.length] || 'Assorted';
639
  singleColorIndex++;
640
  }
641
 
642
+ // --- STEP 2: CONDITIONAL LOGIC ENGINE ---
643
+
644
+ // Rule A: Feature Adaptation (Deletion)
645
+ if (!data.hasHighWaisted) {
646
+ // Remove "high-waisted", "high waist", "alta cintura"
647
+ // Using regex to handle word boundaries and spacing roughly
648
+ text = text.replace(/\bhigh-waisted\b/gi, '');
649
+ text = text.replace(/\bhigh waist\b/gi, 'waist');
650
+ text = text.replace(/\balta cintura\b/gi, '');
651
+
652
+ // Cleanup double spaces resulting from removal
653
+ text = text.replace(/\s+/g, ' ').trim();
 
 
 
 
 
 
 
 
 
 
 
 
654
  }
655
 
656
+ if (!data.hasRibs) {
657
+ // Remove "vertical front seams", "nervuras", "ribs"
658
+ text = text.replace(/vertical front seams/gi, '');
659
+ text = text.replace(/nervuras/gi, '');
660
+ text = text.replace(/ribs/gi, '');
661
+ text = text.replace(/\s+/g, ' ').trim();
 
 
 
 
 
 
 
 
 
 
662
  }
663
 
664
+ // Rule B: Gender Adaptation
665
+ if (data.gender === 'Male') {
666
+ text = text.replace(/female model/gi, 'male model');
667
+ text = text.replace(/woman/gi, 'man');
668
+ text = text.replace(/women's/gi, "men's");
669
+ text = text.replace(/feminine hand/gi, 'masculine hand');
670
+ text = text.replace(/Brazilian woman/gi, 'Brazilian man');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
671
  }
672
 
673
+ // Rule C: Text Overlay & Gift Logic
674
+ if (template.id === 'text_overlay') {
675
+ if (data.promoOffer) {
676
+ text = `Ensure the promotional text "${data.promoOffer}". Preserve exact original image position. Maintain flat lighting, no visible JPEG artifacts, Ultra-realistic, 8k resolution, photographic clarity, sharp focus, high fidelity textures, crisp details. Simple composition, use of symmetry, shallow depth of field, background blurred, leading lines created by clothes rack, no other objects, minimalist style. Add bold, sharp graphic text overlays seamlessly integrated without altering the photography subject.`;
677
+ } else {
678
+ // If no promo, display Product Name
679
+ text = `Ensure the product name "${data.productName}" is clearly visible. Preserve exact original image position. Maintain flat lighting, no visible JPEG artifacts, Ultra-realistic, 8k resolution, photographic clarity, sharp focus, high fidelity textures, crisp details. Simple composition, use of symmetry, shallow depth of field, background blurred, leading lines created by clothes rack, no other objects, minimalist style. Add bold, sharp graphic text overlays seamlessly integrated without altering the photography subject.`;
680
+ }
681
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
682
 
683
+ if (template.id === 'detail_2' && data.hasGifts) {
684
+ // Logic: DELETE PROMOTIONAL_OFFER logic (use Product Name)
685
+ // Since Block 2 is a macro shot, it doesn't inherently have text.
686
+ // We ensure the prompt focuses purely on the product material/name context.
687
+ // The prompt instruction says "Display only Product Name".
688
+ // We will append a clarification to ensure no promo text is implied if it were.
689
+ // (Since the base template doesn't have promo text, we leave it mostly as is,
690
+ // but we ensure we don't inject promo text later).
691
  }
692
 
693
+ // --- STEP 4: TEMPLATE INJECTION ---
694
+
695
+ // 1. Product Name
696
+ text = text.replace(/Bermuda Viena Feminina/g, data.productName);
697
+ text = text.replace(/'Bermuda Viena'/g, `'${data.productName}'`);
698
+ text = text.replace(/Bermuda Viena/g, data.productName);
 
 
699
 
700
+ // 2. Material
701
+ // Replace "Linen and Cotton" first
702
+ text = text.replace(/Linen and Cotton/gi, data.material);
703
+ // Handle individual fallbacks if material is singular
704
+ if (data.material === 'Linen') text = text.replace(/\bCotton\b/gi, 'Linen');
705
+ if (data.material === 'Cotton') text = text.replace(/\bLinen\b/gi, 'Cotton');
706
 
707
+ // 3. Quantity
708
+ const