n8n-nodes-docx-filler 2.0.0 → 2.1.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.
@@ -393,14 +393,78 @@ function validateDocxBuffer(buffer, source) {
393
393
  throw new Error(`Erreur lors de la lecture du fichier "${source}": ${zipError.message}`);
394
394
  }
395
395
  }
396
+ /**
397
+ * Trouve tous les binaires DOCX disponibles dans l'item
398
+ */
399
+ function findAllDocxBinaries(item) {
400
+ if (!item.binary)
401
+ return [];
402
+ const results = [];
403
+ for (const [key, binaryData] of Object.entries(item.binary)) {
404
+ // Vérifier le type MIME ou l'extension
405
+ const isDocx = (binaryData.mimeType && DOCX_MIME_TYPES.includes(binaryData.mimeType)) ||
406
+ (binaryData.fileName && binaryData.fileName.toLowerCase().endsWith('.docx'));
407
+ if (isDocx) {
408
+ results.push({ key, data: binaryData });
409
+ }
410
+ }
411
+ return results;
412
+ }
413
+ /**
414
+ * Trouve le premier binaire DOCX disponible dans l'item
415
+ */
416
+ function findFirstDocxBinary(item) {
417
+ const all = findAllDocxBinaries(item);
418
+ return all.length > 0 ? all[0] : null;
419
+ }
420
+ /**
421
+ * Trouve le deuxième binaire DOCX disponible dans l'item
422
+ */
423
+ function findSecondDocxBinary(item) {
424
+ const all = findAllDocxBinaries(item);
425
+ return all.length > 1 ? all[1] : null;
426
+ }
396
427
  /**
397
428
  * Charge un document DOCX depuis différentes sources
398
429
  */
399
430
  async function getDocumentBuffer(context, itemIndex, inputType, inputValue, items, documentName) {
400
431
  let buffer = null;
401
432
  let source = inputValue;
402
- // Mode binaire
403
- if (inputType === 'binary' || inputType === 'auto') {
433
+ // Mode "Premier DOCX" - trouve automatiquement le premier binaire DOCX
434
+ if (inputType === 'firstDocx') {
435
+ const found = findFirstDocxBinary(items[itemIndex]);
436
+ if (found) {
437
+ buffer = await context.helpers.getBinaryDataBuffer(itemIndex, found.key);
438
+ source = found.data.fileName || found.key;
439
+ }
440
+ else {
441
+ const availableBinaries = items[itemIndex].binary
442
+ ? Object.keys(items[itemIndex].binary)
443
+ : [];
444
+ throw new Error(`Aucun fichier DOCX trouvé dans les binaires pour ${documentName}. ` +
445
+ `Binaires disponibles: ${availableBinaries.length > 0 ? availableBinaries.join(', ') : 'aucun'}`);
446
+ }
447
+ }
448
+ // Mode "Second DOCX" - trouve le deuxième binaire DOCX
449
+ if (inputType === 'secondDocx') {
450
+ const found = findSecondDocxBinary(items[itemIndex]);
451
+ if (found) {
452
+ buffer = await context.helpers.getBinaryDataBuffer(itemIndex, found.key);
453
+ source = found.data.fileName || found.key;
454
+ }
455
+ else {
456
+ const allDocx = findAllDocxBinaries(items[itemIndex]);
457
+ if (allDocx.length === 0) {
458
+ throw new Error(`Aucun fichier DOCX trouvé pour ${documentName}.`);
459
+ }
460
+ else if (allDocx.length === 1) {
461
+ throw new Error(`Un seul fichier DOCX trouvé (${allDocx[0].data.fileName || allDocx[0].key}). ` +
462
+ `Le mode "Second DOCX" nécessite au moins 2 fichiers DOCX.`);
463
+ }
464
+ }
465
+ }
466
+ // Mode binaire (avec nom spécifique)
467
+ if (!buffer && (inputType === 'binary' || inputType === 'auto')) {
404
468
  if (items[itemIndex].binary && items[itemIndex].binary[inputValue]) {
405
469
  const binaryData = items[itemIndex].binary[inputValue];
406
470
  if (binaryData.mimeType && !DOCX_MIME_TYPES.includes(binaryData.mimeType)) {
@@ -600,19 +664,28 @@ class DocxFillerAI {
600
664
  type: 'options',
601
665
  displayOptions: { show: { operation: ['fill'] } },
602
666
  options: [
603
- { name: 'Binary', value: 'binary', description: 'Propriété binaire' },
667
+ { name: 'First DOCX Binary', value: 'firstDocx', description: 'Premier fichier DOCX trouvé (idéal après Merge)' },
668
+ { name: 'Second DOCX Binary', value: 'secondDocx', description: 'Deuxième fichier DOCX trouvé' },
669
+ { name: 'Binary Property', value: 'binary', description: 'Propriété binaire spécifique' },
604
670
  { name: 'File Path', value: 'path', description: 'Chemin fichier' },
605
- { name: 'Auto-Detect', value: 'auto', description: 'Détection auto' },
671
+ { name: 'Auto-Detect', value: 'auto', description: 'Détection auto (nom requis)' },
606
672
  ],
607
- default: 'auto',
673
+ default: 'firstDocx',
608
674
  },
609
675
  {
610
676
  displayName: 'Source Document',
611
677
  name: 'sourceDocument',
612
678
  type: 'string',
613
679
  default: '',
614
- required: true,
615
- displayOptions: { show: { operation: ['fill'] } },
680
+ required: false,
681
+ displayOptions: {
682
+ show: {
683
+ operation: ['fill'],
684
+ },
685
+ hide: {
686
+ sourceInputType: ['firstDocx', 'secondDocx'],
687
+ },
688
+ },
616
689
  description: 'Document source (propriété binaire, chemin, ou base64)',
617
690
  placeholder: 'sourceDoc ou /path/to/source.docx',
618
691
  },
@@ -623,19 +696,28 @@ class DocxFillerAI {
623
696
  type: 'options',
624
697
  displayOptions: { show: { operation: ['fill'] } },
625
698
  options: [
626
- { name: 'Binary', value: 'binary', description: 'Propriété binaire' },
699
+ { name: 'Second DOCX Binary', value: 'secondDocx', description: 'Deuxième fichier DOCX trouvé (idéal après Merge)' },
700
+ { name: 'First DOCX Binary', value: 'firstDocx', description: 'Premier fichier DOCX trouvé' },
701
+ { name: 'Binary Property', value: 'binary', description: 'Propriété binaire spécifique' },
627
702
  { name: 'File Path', value: 'path', description: 'Chemin fichier' },
628
- { name: 'Auto-Detect', value: 'auto', description: 'Détection auto' },
703
+ { name: 'Auto-Detect', value: 'auto', description: 'Détection auto (nom requis)' },
629
704
  ],
630
- default: 'auto',
705
+ default: 'secondDocx',
631
706
  },
632
707
  {
633
708
  displayName: 'Template Document',
634
709
  name: 'templateDocument',
635
710
  type: 'string',
636
711
  default: '',
637
- required: true,
638
- displayOptions: { show: { operation: ['fill'] } },
712
+ required: false,
713
+ displayOptions: {
714
+ show: {
715
+ operation: ['fill'],
716
+ },
717
+ hide: {
718
+ templateInputType: ['firstDocx', 'secondDocx'],
719
+ },
720
+ },
639
721
  description: 'Template à remplir (propriété binaire, chemin, ou base64)',
640
722
  placeholder: 'templateDoc ou /path/to/template.docx',
641
723
  },
@@ -663,19 +745,23 @@ class DocxFillerAI {
663
745
  type: 'options',
664
746
  displayOptions: { show: { operation: ['extract'] } },
665
747
  options: [
666
- { name: 'Binary', value: 'binary' },
667
- { name: 'File Path', value: 'path' },
668
- { name: 'Auto-Detect', value: 'auto' },
748
+ { name: 'First DOCX Binary', value: 'firstDocx', description: 'Premier fichier DOCX trouvé' },
749
+ { name: 'Binary Property', value: 'binary', description: 'Propriété binaire spécifique' },
750
+ { name: 'File Path', value: 'path', description: 'Chemin fichier' },
751
+ { name: 'Auto-Detect', value: 'auto', description: 'Détection auto' },
669
752
  ],
670
- default: 'auto',
753
+ default: 'firstDocx',
671
754
  },
672
755
  {
673
756
  displayName: 'Document',
674
757
  name: 'extractDocument',
675
758
  type: 'string',
676
759
  default: '',
677
- required: true,
678
- displayOptions: { show: { operation: ['extract'] } },
760
+ required: false,
761
+ displayOptions: {
762
+ show: { operation: ['extract'] },
763
+ hide: { extractInputType: ['firstDocx'] },
764
+ },
679
765
  description: 'Document à analyser',
680
766
  },
681
767
  ],
@@ -698,9 +784,9 @@ class DocxFillerAI {
698
784
  try {
699
785
  if (operation === 'fill') {
700
786
  const sourceInputType = this.getNodeParameter('sourceInputType', i);
701
- const sourceValue = this.getNodeParameter('sourceDocument', i);
787
+ const sourceValue = this.getNodeParameter('sourceDocument', i, '');
702
788
  const templateInputType = this.getNodeParameter('templateInputType', i);
703
- const templateValue = this.getNodeParameter('templateDocument', i);
789
+ const templateValue = this.getNodeParameter('templateDocument', i, '');
704
790
  const outputProperty = this.getNodeParameter('outputProperty', i);
705
791
  const useLLM = this.getNodeParameter('useLLM', i);
706
792
  // Charger les documents
@@ -739,17 +825,14 @@ class DocxFillerAI {
739
825
  // Fallback au mode sans LLM
740
826
  sourceData = extractSourceData(sourceParagraphs);
741
827
  }
742
- // Mapping avec LLM
828
+ // Mapping avec LLM (pour amélioration future)
743
829
  const fillPrompt = FILL_PROMPT
744
830
  .replace('{source_data}', JSON.stringify(sourceData, null, 2))
745
831
  .replace('{template_text}', templateStructured);
746
- const fillResponse = await llm.invoke(fillPrompt);
747
- const fillText = typeof fillResponse === 'string'
748
- ? fillResponse
749
- : fillResponse.content || fillResponse.text || JSON.stringify(fillResponse);
750
- // Parser les instructions et appliquer
751
- // ... (logique similaire à avant)
752
- // Pour simplifier, on utilise aussi la logique standard
832
+ // Note: LLM mapping response peut être utilisé pour un mapping plus intelligent
833
+ // Pour l'instant, on utilise la logique standard de mapping par patterns
834
+ await llm.invoke(fillPrompt);
835
+ // Utiliser la logique standard de mapping
753
836
  const fillPositions = findFillPositions(templateParagraphs);
754
837
  const result = fillTemplateXml(templateXml, templateParagraphs, sourceData, fillPositions);
755
838
  templateXml = result.xml;
@@ -795,7 +878,7 @@ class DocxFillerAI {
795
878
  }
796
879
  else if (operation === 'extract') {
797
880
  const inputType = this.getNodeParameter('extractInputType', i);
798
- const inputValue = this.getNodeParameter('extractDocument', i);
881
+ const inputValue = this.getNodeParameter('extractDocument', i, '');
799
882
  const docBuffer = await getDocumentBuffer(this, i, inputType, inputValue, items, 'document');
800
883
  const zip = new pizzip_1.default(docBuffer);
801
884
  const xml = ((_c = zip.file('word/document.xml')) === null || _c === void 0 ? void 0 : _c.asText()) || '';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-docx-filler",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "n8n node to automatically fill DOCX documents (French DC1, DC2, AE forms) using AI for semantic understanding and field mapping.",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",
@@ -47,7 +47,6 @@
47
47
  "n8n": {
48
48
  "n8nNodesApiVersion": 1,
49
49
  "nodes": [
50
- "dist/DocxFiller/DocxFiller.node.js",
51
50
  "dist/DocxFillerAI/DocxFillerAI.node.js"
52
51
  ]
53
52
  },