logs good, replacement good
This commit is contained in:
@@ -252,57 +252,32 @@ export async function POST(req: NextRequest) {
|
|||||||
) => {
|
) => {
|
||||||
const replacementMap: Record<string, string> = {};
|
const replacementMap: Record<string, string> = {};
|
||||||
|
|
||||||
// Approche simple : comparer caractère par caractère
|
// Extraire tous les remplacements [XXX] du texte anonymisé
|
||||||
let originalIndex = 0;
|
const replacementPattern = /\[[^\]]+\]/g;
|
||||||
let anonymizedIndex = 0;
|
const foundReplacements = anonymizedText.match(replacementPattern) || [];
|
||||||
|
|
||||||
// Trier les résultats par position
|
console.log("🔍 Remplacements trouvés dans le texte anonymisé:", foundReplacements);
|
||||||
const sortedResults = [...analyzerResults].sort(
|
|
||||||
(a, b) => a.start - b.start
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const result of sortedResults) {
|
// Trier les entités par position
|
||||||
const originalValue = originalText.substring(
|
const sortedResults = [...analyzerResults].sort((a, b) => a.start - b.start);
|
||||||
result.start,
|
|
||||||
result.end
|
|
||||||
);
|
|
||||||
|
|
||||||
// Avancer jusqu'à la position de l'entité dans le texte original
|
// Associer chaque entité avec son remplacement correspondant
|
||||||
while (originalIndex < result.start) {
|
sortedResults.forEach((result, index) => {
|
||||||
originalIndex++;
|
const originalValue = originalText.substring(result.start, result.end);
|
||||||
anonymizedIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Maintenant on est au début de l'entité
|
if (index < foundReplacements.length) {
|
||||||
// Dans le texte anonymisé, on doit avoir un remplacement qui commence par '['
|
// Utiliser le remplacement correspondant par ordre d'apparition
|
||||||
if (anonymizedText[anonymizedIndex] === "[") {
|
replacementMap[originalValue] = foundReplacements[index];
|
||||||
// Trouver la fin du remplacement (le ']')
|
console.log(`✅ Mapping ordonné: "${originalValue}" -> "${foundReplacements[index]}"`);
|
||||||
let endBracket = anonymizedIndex;
|
|
||||||
while (
|
|
||||||
endBracket < anonymizedText.length &&
|
|
||||||
anonymizedText[endBracket] !== "]"
|
|
||||||
) {
|
|
||||||
endBracket++;
|
|
||||||
}
|
|
||||||
endBracket++; // Inclure le ']'
|
|
||||||
|
|
||||||
const replacementValue = anonymizedText.substring(
|
|
||||||
anonymizedIndex,
|
|
||||||
endBracket
|
|
||||||
);
|
|
||||||
replacementMap[originalValue] = replacementValue;
|
|
||||||
|
|
||||||
// Avancer les index
|
|
||||||
originalIndex = result.end;
|
|
||||||
anonymizedIndex = endBracket;
|
|
||||||
} else {
|
} else {
|
||||||
// Si pas de '[', avancer normalement
|
// Fallback si pas assez de remplacements trouvés
|
||||||
originalIndex = result.end;
|
const fallbackValue = `[${result.entity_type.toUpperCase()}]`;
|
||||||
anonymizedIndex += result.end - result.start;
|
replacementMap[originalValue] = fallbackValue;
|
||||||
|
console.log(`⚠️ Fallback: "${originalValue}" -> "${fallbackValue}"`);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
console.log("🔧 Valeurs de remplacement extraites:", replacementMap);
|
console.log("🔧 Mapping final:", replacementMap);
|
||||||
return replacementMap;
|
return replacementMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ export const useAnonymization = ({
|
|||||||
end: end,
|
end: end,
|
||||||
text: detectedText,
|
text: detectedText,
|
||||||
replacementValue: replacementValues[detectedText] || `[${entity_type}]`,
|
replacementValue: replacementValues[detectedText] || `[${entity_type}]`,
|
||||||
displayName: replacementValues[detectedText] || `[${entity_type}]`, // Ajouter cette ligne
|
displayName: replacementValues[detectedText], // CORRECTION: Supprimer le fallback
|
||||||
customColor: undefined,
|
customColor: undefined,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useState, useCallback, useEffect } from "react";
|
import { useState, useCallback, useEffect, useMemo, useRef } from "react";
|
||||||
import { EntityMapping } from "@/app/config/entityLabels";
|
import { EntityMapping } from "@/app/config/entityLabels";
|
||||||
import { Word } from "./useTextParsing"; // AJOUTER cet import
|
import { Word } from "./useTextParsing";
|
||||||
|
|
||||||
interface ContextMenuState {
|
interface ContextMenuState {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
@@ -12,7 +12,7 @@ interface ContextMenuState {
|
|||||||
|
|
||||||
interface UseContextMenuProps {
|
interface UseContextMenuProps {
|
||||||
entityMappings: EntityMapping[];
|
entityMappings: EntityMapping[];
|
||||||
words: Word[]; // Maintenant le type Word est reconnu
|
words: Word[];
|
||||||
onUpdateMapping: (
|
onUpdateMapping: (
|
||||||
originalValue: string,
|
originalValue: string,
|
||||||
newLabel: string,
|
newLabel: string,
|
||||||
@@ -29,7 +29,7 @@ interface UseContextMenuProps {
|
|||||||
|
|
||||||
export const useContextMenu = ({
|
export const useContextMenu = ({
|
||||||
entityMappings,
|
entityMappings,
|
||||||
words, // Paramètre ajouté
|
words,
|
||||||
onUpdateMapping,
|
onUpdateMapping,
|
||||||
onRemoveMapping,
|
onRemoveMapping,
|
||||||
getCurrentColor,
|
getCurrentColor,
|
||||||
@@ -43,6 +43,10 @@ export const useContextMenu = ({
|
|||||||
wordIndices: [],
|
wordIndices: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Référence pour tracker les mappings précédents
|
||||||
|
const previousMappingsRef = useRef<EntityMapping[]>([]);
|
||||||
|
const previousLabelsRef = useRef<string[]>([]);
|
||||||
|
|
||||||
const closeContextMenu = useCallback(() => {
|
const closeContextMenu = useCallback(() => {
|
||||||
setContextMenu((prev) => ({ ...prev, visible: false }));
|
setContextMenu((prev) => ({ ...prev, visible: false }));
|
||||||
}, []);
|
}, []);
|
||||||
@@ -54,15 +58,105 @@ export const useContextMenu = ({
|
|||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
const getExistingLabels = useCallback(() => {
|
// OPTIMISATION INTELLIGENTE: Ne log que les changements
|
||||||
|
const existingLabels = useMemo(() => {
|
||||||
const uniqueLabels = new Set<string>();
|
const uniqueLabels = new Set<string>();
|
||||||
entityMappings.forEach((mapping) => {
|
const newMappings: EntityMapping[] = [];
|
||||||
uniqueLabels.add(mapping.displayName || mapping.entity_type); // Utiliser displayName
|
const changedMappings: EntityMapping[] = [];
|
||||||
|
const removedMappings: EntityMapping[] = [];
|
||||||
|
|
||||||
|
// Détecter les changements
|
||||||
|
const previousMap = new Map(previousMappingsRef.current.map(m => [m.text, m]));
|
||||||
|
const currentMap = new Map(entityMappings.map(m => [m.text, m]));
|
||||||
|
|
||||||
|
// Nouveaux mappings
|
||||||
|
entityMappings.forEach(mapping => {
|
||||||
|
if (!previousMap.has(mapping.text)) {
|
||||||
|
newMappings.push(mapping);
|
||||||
|
} else {
|
||||||
|
const previous = previousMap.get(mapping.text)!;
|
||||||
|
if (JSON.stringify(previous) !== JSON.stringify(mapping)) {
|
||||||
|
changedMappings.push(mapping);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return Array.from(uniqueLabels).sort();
|
|
||||||
|
// Mappings supprimés
|
||||||
|
previousMappingsRef.current.forEach(mapping => {
|
||||||
|
if (!currentMap.has(mapping.text)) {
|
||||||
|
removedMappings.push(mapping);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Logger seulement les changements
|
||||||
|
if (newMappings.length > 0) {
|
||||||
|
console.log("🆕 Nouveaux mappings détectés:", newMappings.length);
|
||||||
|
newMappings.forEach(mapping => {
|
||||||
|
console.log("📋 Nouveau mapping:", {
|
||||||
|
text: mapping.text,
|
||||||
|
displayName: mapping.displayName,
|
||||||
|
entity_type: mapping.entity_type,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changedMappings.length > 0) {
|
||||||
|
console.log("🔄 Mappings modifiés:", changedMappings.length);
|
||||||
|
changedMappings.forEach(mapping => {
|
||||||
|
console.log("📝 Mapping modifié:", {
|
||||||
|
text: mapping.text,
|
||||||
|
displayName: mapping.displayName,
|
||||||
|
entity_type: mapping.entity_type,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removedMappings.length > 0) {
|
||||||
|
console.log("🗑️ Mappings supprimés:", removedMappings.length);
|
||||||
|
removedMappings.forEach(mapping => {
|
||||||
|
console.log("❌ Mapping supprimé:", {
|
||||||
|
text: mapping.text,
|
||||||
|
displayName: mapping.displayName,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Traitement de tous les mappings pour les labels
|
||||||
|
entityMappings.forEach((mapping) => {
|
||||||
|
if (
|
||||||
|
mapping.displayName &&
|
||||||
|
typeof mapping.displayName === "string" &&
|
||||||
|
mapping.displayName.startsWith("[") &&
|
||||||
|
mapping.displayName.endsWith("]") &&
|
||||||
|
mapping.displayName.length > 2
|
||||||
|
) {
|
||||||
|
uniqueLabels.add(mapping.displayName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = Array.from(uniqueLabels).sort();
|
||||||
|
|
||||||
|
// Logger seulement si les labels ont changé
|
||||||
|
const previousLabels = previousLabelsRef.current;
|
||||||
|
if (JSON.stringify(previousLabels) !== JSON.stringify(result)) {
|
||||||
|
console.log("🎯 Labels mis à jour:", {
|
||||||
|
ajoutés: result.filter(l => !previousLabels.includes(l)),
|
||||||
|
supprimés: previousLabels.filter(l => !result.includes(l)),
|
||||||
|
total: result.length
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mettre à jour les références
|
||||||
|
previousMappingsRef.current = [...entityMappings];
|
||||||
|
previousLabelsRef.current = [...result];
|
||||||
|
|
||||||
|
return result;
|
||||||
}, [entityMappings]);
|
}, [entityMappings]);
|
||||||
|
|
||||||
// CORRECTION: Accepter displayName comme premier paramètre
|
const getExistingLabels = useCallback(() => {
|
||||||
|
return existingLabels;
|
||||||
|
}, [existingLabels]);
|
||||||
|
|
||||||
const applyLabel = useCallback(
|
const applyLabel = useCallback(
|
||||||
(displayName: string, applyToAll?: boolean) => {
|
(displayName: string, applyToAll?: boolean) => {
|
||||||
if (!contextMenu.selectedText) return;
|
if (!contextMenu.selectedText) return;
|
||||||
@@ -70,7 +164,6 @@ export const useContextMenu = ({
|
|||||||
const originalText = contextMenu.selectedText;
|
const originalText = contextMenu.selectedText;
|
||||||
const firstWordIndex = contextMenu.wordIndices[0];
|
const firstWordIndex = contextMenu.wordIndices[0];
|
||||||
|
|
||||||
// Calculer les vraies coordonnées start/end du mot cliqué
|
|
||||||
const clickedWord = words[firstWordIndex];
|
const clickedWord = words[firstWordIndex];
|
||||||
const wordStart = clickedWord?.start;
|
const wordStart = clickedWord?.start;
|
||||||
const wordEnd = clickedWord?.end;
|
const wordEnd = clickedWord?.end;
|
||||||
@@ -82,14 +175,21 @@ export const useContextMenu = ({
|
|||||||
existingMapping?.entity_type ||
|
existingMapping?.entity_type ||
|
||||||
displayName.replace(/[\[\]]/g, "").toUpperCase();
|
displayName.replace(/[\[\]]/g, "").toUpperCase();
|
||||||
|
|
||||||
|
console.log("🏷️ Application de label:", {
|
||||||
|
text: originalText,
|
||||||
|
label: displayName,
|
||||||
|
entityType,
|
||||||
|
applyToAll
|
||||||
|
});
|
||||||
|
|
||||||
onUpdateMapping(
|
onUpdateMapping(
|
||||||
originalText,
|
originalText,
|
||||||
displayName,
|
displayName,
|
||||||
entityType,
|
entityType,
|
||||||
applyToAll,
|
applyToAll,
|
||||||
undefined, // customColor
|
undefined,
|
||||||
wordStart, // vraies coordonnées start
|
wordStart,
|
||||||
wordEnd // vraies coordonnées end
|
wordEnd
|
||||||
);
|
);
|
||||||
|
|
||||||
setSelectedWords(new Set());
|
setSelectedWords(new Set());
|
||||||
@@ -97,7 +197,7 @@ export const useContextMenu = ({
|
|||||||
},
|
},
|
||||||
[
|
[
|
||||||
contextMenu,
|
contextMenu,
|
||||||
words, // NOUVEAU
|
words,
|
||||||
entityMappings,
|
entityMappings,
|
||||||
onUpdateMapping,
|
onUpdateMapping,
|
||||||
closeContextMenu,
|
closeContextMenu,
|
||||||
@@ -105,7 +205,6 @@ export const useContextMenu = ({
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
// CORRECTION: Accepter applyToAll comme paramètre
|
|
||||||
const applyColorDirectly = useCallback(
|
const applyColorDirectly = useCallback(
|
||||||
(color: string, colorName: string, applyToAll?: boolean) => {
|
(color: string, colorName: string, applyToAll?: boolean) => {
|
||||||
if (!contextMenu.selectedText) return;
|
if (!contextMenu.selectedText) return;
|
||||||
@@ -114,17 +213,18 @@ export const useContextMenu = ({
|
|||||||
(mapping) => mapping.text === contextMenu.selectedText
|
(mapping) => mapping.text === contextMenu.selectedText
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log("useContextMenu - applyColorDirectly:", {
|
console.log("🎨 Application de couleur:", {
|
||||||
|
text: contextMenu.selectedText,
|
||||||
color,
|
color,
|
||||||
colorName,
|
colorName,
|
||||||
applyToAll,
|
applyToAll,
|
||||||
existingMapping,
|
existingMapping: !!existingMapping,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (existingMapping) {
|
if (existingMapping) {
|
||||||
onUpdateMapping(
|
onUpdateMapping(
|
||||||
contextMenu.selectedText,
|
contextMenu.selectedText,
|
||||||
existingMapping.displayName || existingMapping.entity_type, // Utiliser displayName
|
existingMapping.displayName || existingMapping.entity_type,
|
||||||
existingMapping.entity_type,
|
existingMapping.entity_type,
|
||||||
applyToAll,
|
applyToAll,
|
||||||
color
|
color
|
||||||
@@ -144,20 +244,19 @@ export const useContextMenu = ({
|
|||||||
},
|
},
|
||||||
[
|
[
|
||||||
contextMenu.selectedText,
|
contextMenu.selectedText,
|
||||||
entityMappings, // Ajouter cette dépendance
|
entityMappings,
|
||||||
onUpdateMapping,
|
onUpdateMapping,
|
||||||
closeContextMenu,
|
closeContextMenu,
|
||||||
setSelectedWords,
|
setSelectedWords,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
// CORRECTION: Accepter applyToAll comme paramètre
|
|
||||||
const removeLabel = useCallback(
|
const removeLabel = useCallback(
|
||||||
(applyToAll?: boolean) => {
|
(applyToAll?: boolean) => {
|
||||||
if (!contextMenu.selectedText || !onRemoveMapping) return;
|
if (!contextMenu.selectedText || !onRemoveMapping) return;
|
||||||
|
|
||||||
console.log("useContextMenu - removeLabel:", {
|
console.log("🗑️ Suppression de label:", {
|
||||||
selectedText: contextMenu.selectedText,
|
text: contextMenu.selectedText,
|
||||||
applyToAll,
|
applyToAll,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -173,7 +272,6 @@ export const useContextMenu = ({
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Gestion des clics en dehors du menu
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleClickOutside = (event: MouseEvent) => {
|
const handleClickOutside = (event: MouseEvent) => {
|
||||||
if (contextMenu.visible) {
|
if (contextMenu.visible) {
|
||||||
|
|||||||
Reference in New Issue
Block a user