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 === '
|
|
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: '
|
|
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: '
|
|
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:
|
|
615
|
-
displayOptions: {
|
|
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: '
|
|
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: '
|
|
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:
|
|
638
|
-
displayOptions: {
|
|
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: '
|
|
667
|
-
{ name: '
|
|
668
|
-
{ name: '
|
|
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: '
|
|
753
|
+
default: 'firstDocx',
|
|
671
754
|
},
|
|
672
755
|
{
|
|
673
756
|
displayName: 'Document',
|
|
674
757
|
name: 'extractDocument',
|
|
675
758
|
type: 'string',
|
|
676
759
|
default: '',
|
|
677
|
-
required:
|
|
678
|
-
displayOptions: {
|
|
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
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
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.
|
|
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
|
},
|