/** * Extraction d'entités métier spécialisées pour les actes notariés * Biens immobiliers, clauses contractuelles, signatures, héritiers, etc. */ const fs = require('fs') const path = require('path') /** * Extraction des biens immobiliers * @param {string} text - Texte à analyser * @returns {Array} Liste des biens immobiliers */ function extractBiensImmobiliers(text) { const biens = [] // Patterns pour les biens immobiliers const patterns = [ // Maison, appartement, terrain /(maison|appartement|terrain|villa|studio|loft|duplex|triplex|pavillon|chalet|château|manoir|hôtel particulier|immeuble|bâtiment|construction|édifice)\s+(?:situé[e]?\s+)?(?:au\s+)?(?:n°\s*)?(\d+[a-z]?)?\s*(?:rue|avenue|boulevard|place|chemin|route|impasse|allée|square|quai|cours|passage)\s+([^,]+)/gi, // Adresse complète /(?:situé[e]?\s+)?(?:au\s+)?(?:n°\s*)?(\d+[a-z]?)\s*(?:rue|avenue|boulevard|place|chemin|route|impasse|allée|square|quai|cours|passage)\s+([^,]+),\s*(\d{5})\s+([^,]+)/gi, // Surface et caractéristiques /(?:d'une\s+)?(?:surface\s+de\s+)?(\d+(?:\.\d+)?)\s*(?:m²|m2|mètres?\s+carrés?)/gi, // Nombre de pièces /(?:composé[e]?\s+de\s+)?(\d+)\s*(?:pièces?|chambres?|salles?)/gi, // Type de bien /(?:un\s+)?(maison|appartement|terrain|villa|studio|loft|duplex|triplex|pavillon|chalet|château|manoir|hôtel particulier|immeuble|bâtiment|construction|édifice)/gi ] // Extraction des adresses const adresseMatches = text.match(patterns[1]) || [] for (const match of adresseMatches) { const parts = match.match(/(\d+[a-z]?)\s*(?:rue|avenue|boulevard|place|chemin|route|impasse|allée|square|quai|cours|passage)\s+([^,]+),\s*(\d{5})\s+([^,]+)/i) if (parts) { biens.push({ type: 'bien_immobilier', adresse: { numero: parts[1], rue: parts[2].trim(), codePostal: parts[3], ville: parts[4].trim() }, surface: null, pieces: null, description: match.trim() }) } } // Extraction des surfaces const surfaceMatches = text.match(patterns[2]) || [] for (const match of surfaceMatches) { const surface = parseFloat(match.match(/(\d+(?:\.\d+)?)/)[1]) if (biens.length > 0) { biens[biens.length - 1].surface = surface } } // Extraction du nombre de pièces const piecesMatches = text.match(patterns[3]) || [] for (const match of piecesMatches) { const pieces = parseInt(match.match(/(\d+)/)[1]) if (biens.length > 0) { biens[biens.length - 1].pieces = pieces } } return biens } /** * Extraction des clauses contractuelles * @param {string} text - Texte à analyser * @returns {Array} Liste des clauses */ function extractClauses(text) { const clauses = [] // Patterns pour les clauses const patterns = [ // Clauses de prix /(?:prix|montant|somme)\s+(?:de\s+)?(?:vente\s+)?(?:fixé[e]?\s+à\s+)?(\d+(?:\s+\d+)*(?:\.\d+)?)\s*(?:euros?|€|EUR)/gi, // Clauses suspensives /(?:clause\s+)?(?:suspensive|condition)\s+(?:de\s+)?([^.]{10,100})/gi, // Clauses de garantie /(?:garantie|garanties?)\s+(?:de\s+)?([^.]{10,100})/gi, // Clauses de délai /(?:délai|échéance|terme)\s+(?:de\s+)?(\d+)\s*(?:jours?|mois|années?)/gi, // Clauses de résolution /(?:résolution|annulation)\s+(?:du\s+)?(?:contrat|acte)\s+(?:en\s+cas\s+de\s+)?([^.]{10,100})/gi ] // Extraction des prix const prixMatches = text.match(patterns[0]) || [] for (const match of prixMatches) { const prix = match.match(/(\d+(?:\s+\d+)*(?:\.\d+)?)/)[1].replace(/\s+/g, '') clauses.push({ type: 'prix', valeur: parseFloat(prix), devise: 'EUR', description: match.trim() }) } // Extraction des clauses suspensives const suspensivesMatches = text.match(patterns[1]) || [] for (const match of suspensivesMatches) { clauses.push({ type: 'clause_suspensive', description: match.trim(), condition: match.replace(/(?:clause\s+)?(?:suspensive|condition)\s+(?:de\s+)?/i, '').trim() }) } // Extraction des garanties const garantiesMatches = text.match(patterns[2]) || [] for (const match of garantiesMatches) { clauses.push({ type: 'garantie', description: match.trim(), garantie: match.replace(/(?:garantie|garanties?)\s+(?:de\s+)?/i, '').trim() }) } return clauses } /** * Extraction des signatures * @param {string} text - Texte à analyser * @returns {Array} Liste des signatures */ function extractSignatures(text) { const signatures = [] // Patterns pour les signatures const patterns = [ // Signature simple /(?:signé|signature)\s+(?:par\s+)?([A-Z][a-z]+\s+[A-Z][a-z]+)/gi, // Signature avec date /(?:signé|signature)\s+(?:par\s+)?([A-Z][a-z]+\s+[A-Z][a-z]+)\s+(?:le\s+)?(\d{1,2}[\/\-\.]\d{1,2}[\/\-\.]\d{2,4})/gi, // Signature avec lieu /(?:signé|signature)\s+(?:par\s+)?([A-Z][a-z]+\s+[A-Z][a-z]+)\s+(?:à\s+)?([A-Z][a-z]+)/gi, // Signature notariale /(?:notaire|maître)\s+([A-Z][a-z]+\s+[A-Z][a-z]+)/gi ] // Extraction des signatures simples const signatureMatches = text.match(patterns[0]) || [] for (const match of signatureMatches) { const nom = match.match(/([A-Z][a-z]+\s+[A-Z][a-z]+)/)[1] signatures.push({ type: 'signature', nom: nom, date: null, lieu: null, description: match.trim() }) } // Extraction des signatures avec date const signatureDateMatches = text.match(patterns[1]) || [] for (const match of signatureDateMatches) { const parts = match.match(/([A-Z][a-z]+\s+[A-Z][a-z]+)\s+(?:le\s+)?(\d{1,2}[\/\-\.]\d{1,2}[\/\-\.]\d{2,4})/) if (parts) { signatures.push({ type: 'signature', nom: parts[1], date: parts[2], lieu: null, description: match.trim() }) } } // Extraction des signatures notariales const notaireMatches = text.match(patterns[3]) || [] for (const match of notaireMatches) { const nom = match.match(/([A-Z][a-z]+\s+[A-Z][a-z]+)/)[1] signatures.push({ type: 'signature_notariale', nom: nom, date: null, lieu: null, description: match.trim() }) } return signatures } /** * Extraction des héritiers * @param {string} text - Texte à analyser * @returns {Array} Liste des héritiers */ function extractHeritiers(text) { const heritiers = [] // Patterns pour les héritiers const patterns = [ // Héritier simple /(?:héritier|héritière|successeur|successeure|bénéficiaire)\s+(?:de\s+)?([A-Z][a-z]+\s+[A-Z][a-z]+)/gi, // Héritier avec degré de parenté /(?:fils|fille|père|mère|frère|sœur|époux|épouse|mari|femme|conjoint|conjointe|enfant|parent|grand-père|grand-mère|oncle|tante|neveu|nièce|cousin|cousine)\s+(?:de\s+)?([A-Z][a-z]+\s+[A-Z][a-z]+)/gi, // Héritier avec part /([A-Z][a-z]+\s+[A-Z][a-z]+)\s+(?:hérite|bénéficie)\s+(?:de\s+)?(?:la\s+)?(?:part\s+de\s+)?(\d+(?:\/\d+)?|tout|totalité)/gi ] // Extraction des héritiers simples const heritierMatches = text.match(patterns[0]) || [] for (const match of heritierMatches) { const nom = match.match(/([A-Z][a-z]+\s+[A-Z][a-z]+)/)[1] heritiers.push({ type: 'heritier', nom: nom, parente: null, part: null, description: match.trim() }) } // Extraction des héritiers avec parenté const parenteMatches = text.match(patterns[1]) || [] for (const match of parenteMatches) { const parts = match.match(/(fils|fille|père|mère|frère|sœur|époux|épouse|mari|femme|conjoint|conjointe|enfant|parent|grand-père|grand-mère|oncle|tante|neveu|nièce|cousin|cousine)\s+(?:de\s+)?([A-Z][a-z]+\s+[A-Z][a-z]+)/i) if (parts) { heritiers.push({ type: 'heritier', nom: parts[2], parente: parts[1], part: null, description: match.trim() }) } } return heritiers } /** * Extraction des vendeurs et acheteurs * @param {string} text - Texte à analyser * @returns {Object} Vendeurs et acheteurs */ function extractVendeursAcheteurs(text) { const result = { vendeurs: [], acheteurs: [] } // Patterns pour vendeurs et acheteurs const patterns = [ // Vendeur /(?:vendeur|vendeuse|vendant|vendant)\s+(?:M\.|Mme|Mademoiselle|Monsieur|Madame)?\s*([A-Z][a-z]+\s+[A-Z][a-z]+)/gi, // Acheteur /(?:acheteur|acheteuse|achetant|achetant)\s+(?:M\.|Mme|Mademoiselle|Monsieur|Madame)?\s*([A-Z][a-z]+\s+[A-Z][a-z]+)/gi, // Vente entre /(?:vente\s+)?(?:entre\s+)?(?:M\.|Mme|Mademoiselle|Monsieur|Madame)?\s*([A-Z][a-z]+\s+[A-Z][a-z]+)\s+(?:et\s+)?(?:M\.|Mme|Mademoiselle|Monsieur|Madame)?\s*([A-Z][a-z]+\s+[A-Z][a-z]+)/gi ] // Extraction des vendeurs const vendeurMatches = text.match(patterns[0]) || [] for (const match of vendeurMatches) { const nom = match.match(/([A-Z][a-z]+\s+[A-Z][a-z]+)/)[1] result.vendeurs.push({ type: 'vendeur', nom: nom, description: match.trim() }) } // Extraction des acheteurs const acheteurMatches = text.match(patterns[1]) || [] for (const match of acheteurMatches) { const nom = match.match(/([A-Z][a-z]+\s+[A-Z][a-z]+)/)[1] result.acheteurs.push({ type: 'acheteur', nom: nom, description: match.trim() }) } // Extraction des ventes entre const venteMatches = text.match(patterns[2]) || [] for (const match of venteMatches) { const parts = match.match(/([A-Z][a-z]+\s+[A-Z][a-z]+)\s+(?:et\s+)?([A-Z][a-z]+\s+[A-Z][a-z]+)/) if (parts) { result.vendeurs.push({ type: 'vendeur', nom: parts[1], description: match.trim() }) result.acheteurs.push({ type: 'acheteur', nom: parts[2], description: match.trim() }) } } return result } /** * Classification du type de document * @param {string} text - Texte à analyser * @returns {string} Type de document */ function classifyDocumentType(text) { const textLower = text.toLowerCase() // Types de documents notariés const types = { 'acte_vente': ['vente', 'achat', 'acquisition', 'cession', 'transfert'], 'acte_succession': ['succession', 'héritage', 'héritier', 'défunt', 'décès'], 'acte_donation': ['donation', 'donner', 'donné', 'donateur', 'donataire'], 'acte_mariage': ['mariage', 'époux', 'épouse', 'conjoint', 'conjointe'], 'acte_divorce': ['divorce', 'séparation', 'liquidation'], 'acte_pacs': ['pacs', 'pacte civil', 'solidarité'], 'acte_testament': ['testament', 'testateur', 'testatrice', 'legs', 'léguer'], 'acte_promesse': ['promesse', 'compromis', 'avant-contrat'], 'acte_authentification': ['authentification', 'authentifier', 'certifier'], 'acte_pouvoir': ['pouvoir', 'procuration', 'mandat'], 'acte_societe': ['société', 'entreprise', 'sarl', 'sas', 'eurl', 'snc'] } // Calcul des scores const scores = {} for (const [type, keywords] of Object.entries(types)) { scores[type] = keywords.reduce((score, keyword) => { const matches = (textLower.match(new RegExp(keyword, 'g')) || []).length return score + matches }, 0) } // Retourner le type avec le score le plus élevé const bestType = Object.entries(scores).reduce((a, b) => scores[a[0]] > scores[b[0]] ? a : b) return bestType[1] > 0 ? bestType[0] : 'document_inconnu' } /** * Extraction complète des entités métier * @param {string} text - Texte à analyser * @returns {Object} Toutes les entités extraites */ function extractMetierEntities(text) { return { biensImmobiliers: extractBiensImmobiliers(text), clauses: extractClauses(text), signatures: extractSignatures(text), heritiers: extractHeritiers(text), vendeursAcheteurs: extractVendeursAcheteurs(text), documentType: classifyDocumentType(text), timestamp: new Date().toISOString() } } module.exports = { extractBiensImmobiliers, extractClauses, extractSignatures, extractHeritiers, extractVendeursAcheteurs, classifyDocumentType, extractMetierEntities }