chore: sync derniers changements code/docs/tests avant restart services

This commit is contained in:
4NK IA 2025-09-18 16:39:25 +00:00
parent 9712d9f375
commit 3519b948f8
11 changed files with 93 additions and 100 deletions

View File

@ -44,7 +44,7 @@ async function geocodeBAN(address) {
async function collectGéoRisque(lat, lon) { async function collectGéoRisque(lat, lon) {
if (!lat || !lon) return { success: false, error: 'Coordonnées manquantes' } if (!lat || !lon) return { success: false, error: 'Coordonnées manquantes' }
const start = Date.now() const start = Date.now()
try { try {
// Recherche des risques majeurs par coordonnées // Recherche des risques majeurs par coordonnées
@ -53,10 +53,10 @@ async function collectGéoRisque(lat, lon) {
headers: { 'User-Agent': USER_AGENT, 'Accept': 'application/json' }, headers: { 'User-Agent': USER_AGENT, 'Accept': 'application/json' },
timeout: REQUEST_TIMEOUT_MS, timeout: REQUEST_TIMEOUT_MS,
}) })
if (!res.ok) throw new Error(`HTTP ${res.status}`) if (!res.ok) throw new Error(`HTTP ${res.status}`)
const data = await res.json() const data = await res.json()
const risks = (data.risques || []).map(risk => ({ const risks = (data.risques || []).map(risk => ({
type: risk.type || 'Risque majeur', type: risk.type || 'Risque majeur',
level: risk.niveau || 'Non spécifié', level: risk.niveau || 'Non spécifié',
@ -64,7 +64,7 @@ async function collectGéoRisque(lat, lon) {
sourceUrl: `${GEORISQUE_BASE_URL}/risques/${risk.id || ''}`, sourceUrl: `${GEORISQUE_BASE_URL}/risques/${risk.id || ''}`,
distance: risk.distance || null distance: risk.distance || null
})) }))
return { return {
success: true, success: true,
duration: Date.now() - start, duration: Date.now() - start,
@ -78,7 +78,7 @@ async function collectGéoRisque(lat, lon) {
async function collectCadastre(lat, lon) { async function collectCadastre(lat, lon) {
if (!lat || !lon) return { success: false, error: 'Coordonnées manquantes' } if (!lat || !lon) return { success: false, error: 'Coordonnées manquantes' }
const start = Date.now() const start = Date.now()
try { try {
// Recherche des parcelles cadastrales par coordonnées // Recherche des parcelles cadastrales par coordonnées
@ -87,10 +87,10 @@ async function collectCadastre(lat, lon) {
headers: { 'User-Agent': USER_AGENT, 'Accept': 'application/json' }, headers: { 'User-Agent': USER_AGENT, 'Accept': 'application/json' },
timeout: REQUEST_TIMEOUT_MS, timeout: REQUEST_TIMEOUT_MS,
}) })
if (!res.ok) throw new Error(`HTTP ${res.status}`) if (!res.ok) throw new Error(`HTTP ${res.status}`)
const data = await res.json() const data = await res.json()
const parcelles = (data.parcelles || []).map(parcelle => ({ const parcelles = (data.parcelles || []).map(parcelle => ({
section: parcelle.section || '', section: parcelle.section || '',
numero: parcelle.numero || '', numero: parcelle.numero || '',
@ -98,7 +98,7 @@ async function collectCadastre(lat, lon) {
surface: parcelle.surface || null, surface: parcelle.surface || null,
sourceUrl: `${CADASTRE_BASE_URL}/parcelles/${parcelle.id || ''}` sourceUrl: `${CADASTRE_BASE_URL}/parcelles/${parcelle.id || ''}`
})) }))
return { return {
success: true, success: true,
duration: Date.now() - start, duration: Date.now() - start,
@ -113,23 +113,23 @@ async function collectCadastre(lat, lon) {
async function collectAddressData(address) { async function collectAddressData(address) {
// Étape 1: Géocodage BAN // Étape 1: Géocodage BAN
const geocode = await geocodeBAN(address) const geocode = await geocodeBAN(address)
let risks = [] let risks = []
let cadastre = [] let cadastre = []
// Étape 2: Si géocodage réussi, collecter risques et cadastre // Étape 2: Si géocodage réussi, collecter risques et cadastre
if (geocode.success && geocode.lat && geocode.lon) { if (geocode.success && geocode.lat && geocode.lon) {
console.log(`[Address] Géocodage réussi: ${geocode.lat}, ${geocode.lon}`) console.log(`[Address] Géocodage réussi: ${geocode.lat}, ${geocode.lon}`)
// Collecte parallèle des risques et du cadastre // Collecte parallèle des risques et du cadastre
const [risksResult, cadastreResult] = await Promise.all([ const [risksResult, cadastreResult] = await Promise.all([
collectGéoRisque(geocode.lat, geocode.lon), collectGéoRisque(geocode.lat, geocode.lon),
collectCadastre(geocode.lat, geocode.lon) collectCadastre(geocode.lat, geocode.lon)
]) ])
risks = risksResult.risks || [] risks = risksResult.risks || []
cadastre = cadastreResult.parcelles || [] cadastre = cadastreResult.parcelles || []
console.log(`[Address] Risques: ${risks.length}, Parcelles: ${cadastre.length}`) console.log(`[Address] Risques: ${risks.length}, Parcelles: ${cadastre.length}`)
} }

View File

@ -19,10 +19,10 @@ const REQUEST_TIMEOUT_MS = 10000; // 10 secondes timeout
*/ */
async function searchBodaccGelAvoirs(lastName, firstName = '') { async function searchBodaccGelAvoirs(lastName, firstName = '') {
const startTime = Date.now(); const startTime = Date.now();
try { try {
console.log(`[Bodacc] Recherche gel des avoirs pour: ${lastName} ${firstName}`); console.log(`[Bodacc] Recherche gel des avoirs pour: ${lastName} ${firstName}`);
// Construction de la requête de recherche // Construction de la requête de recherche
const searchParams = new URLSearchParams({ const searchParams = new URLSearchParams({
'q': `${lastName} ${firstName}`.trim(), 'q': `${lastName} ${firstName}`.trim(),
@ -30,9 +30,9 @@ async function searchBodaccGelAvoirs(lastName, firstName = '') {
'date_debut': '2020-01-01', // Recherche sur les 4 dernières années 'date_debut': '2020-01-01', // Recherche sur les 4 dernières années
'date_fin': new Date().toISOString().split('T')[0] 'date_fin': new Date().toISOString().split('T')[0]
}); });
const searchUrl = `${BODACC_BASE_URL}/recherche?${searchParams.toString()}`; const searchUrl = `${BODACC_BASE_URL}/recherche?${searchParams.toString()}`;
// Requête avec politesse // Requête avec politesse
const response = await fetch(searchUrl, { const response = await fetch(searchUrl, {
method: 'GET', method: 'GET',
@ -46,24 +46,24 @@ async function searchBodaccGelAvoirs(lastName, firstName = '') {
}, },
timeout: REQUEST_TIMEOUT_MS timeout: REQUEST_TIMEOUT_MS
}); });
if (!response.ok) { if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`); throw new Error(`HTTP ${response.status}: ${response.statusText}`);
} }
const html = await response.text(); const html = await response.text();
const dom = new JSDOM(html); const dom = new JSDOM(html);
const document = dom.window.document; const document = dom.window.document;
// Extraction des résultats // Extraction des résultats
const results = extractBodaccResults(document, lastName, firstName); const results = extractBodaccResults(document, lastName, firstName);
// Délai de politesse avant la prochaine requête // Délai de politesse avant la prochaine requête
await new Promise(resolve => setTimeout(resolve, REQUEST_DELAY_MS)); await new Promise(resolve => setTimeout(resolve, REQUEST_DELAY_MS));
const duration = Date.now() - startTime; const duration = Date.now() - startTime;
console.log(`[Bodacc] Recherche terminée en ${duration}ms, ${results.length} résultats`); console.log(`[Bodacc] Recherche terminée en ${duration}ms, ${results.length} résultats`);
return { return {
success: true, success: true,
duration, duration,
@ -72,11 +72,11 @@ async function searchBodaccGelAvoirs(lastName, firstName = '') {
searchUrl, searchUrl,
timestamp: new Date().toISOString() timestamp: new Date().toISOString()
}; };
} catch (error) { } catch (error) {
const duration = Date.now() - startTime; const duration = Date.now() - startTime;
console.error(`[Bodacc] Erreur recherche:`, error.message); console.error(`[Bodacc] Erreur recherche:`, error.message);
return { return {
success: false, success: false,
duration, duration,
@ -97,7 +97,7 @@ async function searchBodaccGelAvoirs(lastName, firstName = '') {
*/ */
function extractBodaccResults(document, lastName, firstName) { function extractBodaccResults(document, lastName, firstName) {
const results = []; const results = [];
try { try {
// Sélecteurs pour les résultats de gel des avoirs // Sélecteurs pour les résultats de gel des avoirs
const resultSelectors = [ const resultSelectors = [
@ -106,13 +106,13 @@ function extractBodaccResults(document, lastName, firstName) {
'.bodacc-result', '.bodacc-result',
'[data-type="gel-avoirs"]' '[data-type="gel-avoirs"]'
]; ];
let resultElements = []; let resultElements = [];
for (const selector of resultSelectors) { for (const selector of resultSelectors) {
resultElements = document.querySelectorAll(selector); resultElements = document.querySelectorAll(selector);
if (resultElements.length > 0) break; if (resultElements.length > 0) break;
} }
// Si pas de sélecteur spécifique, chercher dans le contenu général // Si pas de sélecteur spécifique, chercher dans le contenu général
if (resultElements.length === 0) { if (resultElements.length === 0) {
const content = document.body.textContent || ''; const content = document.body.textContent || '';
@ -134,14 +134,14 @@ function extractBodaccResults(document, lastName, firstName) {
const nameElement = element.querySelector('.name, .nom, .person-name, h3, h4'); const nameElement = element.querySelector('.name, .nom, .person-name, h3, h4');
const dateElement = element.querySelector('.date, .publication-date, .date-publication'); const dateElement = element.querySelector('.date, .publication-date, .date-publication');
const linkElement = element.querySelector('a[href]'); const linkElement = element.querySelector('a[href]');
const name = nameElement ? nameElement.textContent.trim() : `${firstName} ${lastName}`.trim(); const name = nameElement ? nameElement.textContent.trim() : `${firstName} ${lastName}`.trim();
const date = dateElement ? dateElement.textContent.trim() : new Date().toISOString().split('T')[0]; const date = dateElement ? dateElement.textContent.trim() : new Date().toISOString().split('T')[0];
const sourceUrl = linkElement ? new URL(linkElement.href, BODACC_BASE_URL).href : BODACC_BASE_URL; const sourceUrl = linkElement ? new URL(linkElement.href, BODACC_BASE_URL).href : BODACC_BASE_URL;
// Calcul du score de correspondance basique // Calcul du score de correspondance basique
const matchScore = calculateMatchScore(name, lastName, firstName); const matchScore = calculateMatchScore(name, lastName, firstName);
if (matchScore > 0.3) { // Seuil minimum de correspondance if (matchScore > 0.3) { // Seuil minimum de correspondance
results.push({ results.push({
name, name,
@ -157,11 +157,11 @@ function extractBodaccResults(document, lastName, firstName) {
} }
}); });
} }
} catch (error) { } catch (error) {
console.warn(`[Bodacc] Erreur extraction résultats:`, error.message); console.warn(`[Bodacc] Erreur extraction résultats:`, error.message);
} }
return results; return results;
} }
@ -176,24 +176,24 @@ function calculateMatchScore(foundName, lastName, firstName) {
const found = foundName.toLowerCase(); const found = foundName.toLowerCase();
const last = lastName.toLowerCase(); const last = lastName.toLowerCase();
const first = firstName.toLowerCase(); const first = firstName.toLowerCase();
let score = 0; let score = 0;
// Correspondance exacte du nom de famille // Correspondance exacte du nom de famille
if (found.includes(last)) { if (found.includes(last)) {
score += 0.6; score += 0.6;
} }
// Correspondance du prénom si fourni // Correspondance du prénom si fourni
if (first && found.includes(first)) { if (first && found.includes(first)) {
score += 0.4; score += 0.4;
} }
// Bonus pour correspondance exacte // Bonus pour correspondance exacte
if (found === `${first} ${last}`.trim().toLowerCase()) { if (found === `${first} ${last}`.trim().toLowerCase()) {
score = 1.0; score = 1.0;
} }
return Math.min(score, 1.0); return Math.min(score, 1.0);
} }
@ -218,17 +218,17 @@ function generateBodaccSummary(results, lastName, firstName) {
oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1); oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1);
return resultDate > oneYearAgo; return resultDate > oneYearAgo;
}); });
return { return {
searchTarget: `${firstName} ${lastName}`.trim(), searchTarget: `${firstName} ${lastName}`.trim(),
totalResults, totalResults,
highConfidenceResults: highConfidenceResults.length, highConfidenceResults: highConfidenceResults.length,
recentResults: recentResults.length, recentResults: recentResults.length,
hasGelAvoirs: totalResults > 0, hasGelAvoirs: totalResults > 0,
riskLevel: totalResults === 0 ? 'Aucun' : riskLevel: totalResults === 0 ? 'Aucun' :
highConfidenceResults.length > 0 ? 'Élevé' : highConfidenceResults.length > 0 ? 'Élevé' :
totalResults > 0 ? 'Moyen' : 'Faible', totalResults > 0 ? 'Moyen' : 'Faible',
summary: totalResults === 0 ? summary: totalResults === 0 ?
'Aucune mention de gel des avoirs trouvée sur Bodacc' : 'Aucune mention de gel des avoirs trouvée sur Bodacc' :
`${totalResults} mention(s) trouvée(s), ${highConfidenceResults.length} avec haute confiance` `${totalResults} mention(s) trouvée(s), ${highConfidenceResults.length} avec haute confiance`
}; };

View File

@ -20,29 +20,29 @@ const REQUEST_TIMEOUT_MS = 12000; // 12 secondes timeout
*/ */
async function searchCompanyInfo(companyName, siren = '') { async function searchCompanyInfo(companyName, siren = '') {
const startTime = Date.now(); const startTime = Date.now();
try { try {
console.log(`[Inforgreffe] Recherche entreprise: ${companyName} ${siren ? `(SIREN: ${siren})` : ''}`); console.log(`[Inforgreffe] Recherche entreprise: ${companyName} ${siren ? `(SIREN: ${siren})` : ''}`);
// Recherche sur Societe.com d'abord (plus accessible) // Recherche sur Societe.com d'abord (plus accessible)
const societeComResult = await searchSocieteCom(companyName, siren); const societeComResult = await searchSocieteCom(companyName, siren);
// Délai de politesse // Délai de politesse
await new Promise(resolve => setTimeout(resolve, REQUEST_DELAY_MS)); await new Promise(resolve => setTimeout(resolve, REQUEST_DELAY_MS));
// Recherche sur Inforgreffe si SIREN disponible // Recherche sur Inforgreffe si SIREN disponible
let inforgreffeResult = null; let inforgreffeResult = null;
if (siren) { if (siren) {
inforgreffeResult = await searchInforgreffe(siren); inforgreffeResult = await searchInforgreffe(siren);
await new Promise(resolve => setTimeout(resolve, REQUEST_DELAY_MS)); await new Promise(resolve => setTimeout(resolve, REQUEST_DELAY_MS));
} }
// Fusion des résultats // Fusion des résultats
const mergedResult = mergeCompanyResults(societeComResult, inforgreffeResult, companyName); const mergedResult = mergeCompanyResults(societeComResult, inforgreffeResult, companyName);
const duration = Date.now() - startTime; const duration = Date.now() - startTime;
console.log(`[Inforgreffe] Recherche terminée en ${duration}ms`); console.log(`[Inforgreffe] Recherche terminée en ${duration}ms`);
return { return {
success: true, success: true,
duration, duration,
@ -53,11 +53,11 @@ async function searchCompanyInfo(companyName, siren = '') {
}, },
timestamp: new Date().toISOString() timestamp: new Date().toISOString()
}; };
} catch (error) { } catch (error) {
const duration = Date.now() - startTime; const duration = Date.now() - startTime;
console.error(`[Inforgreffe] Erreur recherche:`, error.message); console.error(`[Inforgreffe] Erreur recherche:`, error.message);
return { return {
success: false, success: false,
duration, duration,
@ -80,7 +80,7 @@ async function searchSocieteCom(companyName, siren = '') {
// Construction de l'URL de recherche // Construction de l'URL de recherche
const searchQuery = siren || companyName; const searchQuery = siren || companyName;
const searchUrl = `${SOCIETE_COM_BASE_URL}/search?q=${encodeURIComponent(searchQuery)}`; const searchUrl = `${SOCIETE_COM_BASE_URL}/search?q=${encodeURIComponent(searchQuery)}`;
const response = await fetch(searchUrl, { const response = await fetch(searchUrl, {
method: 'GET', method: 'GET',
headers: { headers: {
@ -93,17 +93,17 @@ async function searchSocieteCom(companyName, siren = '') {
}, },
timeout: REQUEST_TIMEOUT_MS timeout: REQUEST_TIMEOUT_MS
}); });
if (!response.ok) { if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`); throw new Error(`HTTP ${response.status}: ${response.statusText}`);
} }
const html = await response.text(); const html = await response.text();
const dom = new JSDOM(html); const dom = new JSDOM(html);
const document = dom.window.document; const document = dom.window.document;
return extractSocieteComData(document, companyName, siren); return extractSocieteComData(document, companyName, siren);
} catch (error) { } catch (error) {
console.warn(`[Societe.com] Erreur:`, error.message); console.warn(`[Societe.com] Erreur:`, error.message);
return { return {
@ -123,7 +123,7 @@ async function searchInforgreffe(siren) {
try { try {
// URL de recherche par SIREN // URL de recherche par SIREN
const searchUrl = `${INFORGREFFE_BASE_URL}/entreprise/${siren}`; const searchUrl = `${INFORGREFFE_BASE_URL}/entreprise/${siren}`;
const response = await fetch(searchUrl, { const response = await fetch(searchUrl, {
method: 'GET', method: 'GET',
headers: { headers: {
@ -136,17 +136,17 @@ async function searchInforgreffe(siren) {
}, },
timeout: REQUEST_TIMEOUT_MS timeout: REQUEST_TIMEOUT_MS
}); });
if (!response.ok) { if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`); throw new Error(`HTTP ${response.status}: ${response.statusText}`);
} }
const html = await response.text(); const html = await response.text();
const dom = new JSDOM(html); const dom = new JSDOM(html);
const document = dom.window.document; const document = dom.window.document;
return extractInforgreffeData(document, siren); return extractInforgreffeData(document, siren);
} catch (error) { } catch (error) {
console.warn(`[Inforgreffe] Erreur:`, error.message); console.warn(`[Inforgreffe] Erreur:`, error.message);
return { return {
@ -178,38 +178,38 @@ function extractSocieteComData(document, companyName, siren) {
dateCreation: '', dateCreation: '',
sourceUrl: SOCIETE_COM_BASE_URL sourceUrl: SOCIETE_COM_BASE_URL
}; };
// Extraction du nom de l'entreprise // Extraction du nom de l'entreprise
const nameElement = document.querySelector('.company-name, .nom-entreprise, h1, .title'); const nameElement = document.querySelector('.company-name, .nom-entreprise, h1, .title');
if (nameElement) { if (nameElement) {
data.name = nameElement.textContent.trim(); data.name = nameElement.textContent.trim();
} }
// Extraction du SIREN/SIRET // Extraction du SIREN/SIRET
const sirenElement = document.querySelector('.siren, .num-siren, [data-siren]'); const sirenElement = document.querySelector('.siren, .num-siren, [data-siren]');
if (sirenElement) { if (sirenElement) {
const sirenText = sirenElement.textContent || sirenElement.getAttribute('data-siren'); const sirenText = sirenElement.textContent || sirenElement.getAttribute('data-siren');
data.siren = extractSiren(sirenText); data.siren = extractSiren(sirenText);
} }
// Extraction de la forme juridique // Extraction de la forme juridique
const formeElement = document.querySelector('.forme, .forme-juridique, .legal-form'); const formeElement = document.querySelector('.forme, .forme-juridique, .legal-form');
if (formeElement) { if (formeElement) {
data.forme = formeElement.textContent.trim(); data.forme = formeElement.textContent.trim();
} }
// Extraction du capital // Extraction du capital
const capitalElement = document.querySelector('.capital, .capital-social, .share-capital'); const capitalElement = document.querySelector('.capital, .capital-social, .share-capital');
if (capitalElement) { if (capitalElement) {
data.capital = capitalElement.textContent.trim(); data.capital = capitalElement.textContent.trim();
} }
// Extraction de l'adresse // Extraction de l'adresse
const adresseElement = document.querySelector('.adresse, .address, .company-address'); const adresseElement = document.querySelector('.adresse, .address, .company-address');
if (adresseElement) { if (adresseElement) {
data.adresse = adresseElement.textContent.trim(); data.adresse = adresseElement.textContent.trim();
} }
// Extraction des dirigeants // Extraction des dirigeants
const dirigeantsElements = document.querySelectorAll('.dirigeant, .manager, .president, .gérant'); const dirigeantsElements = document.querySelectorAll('.dirigeant, .manager, .president, .gérant');
dirigeantsElements.forEach(element => { dirigeantsElements.forEach(element => {
@ -222,24 +222,24 @@ function extractSocieteComData(document, companyName, siren) {
}); });
} }
}); });
// Extraction de l'activité // Extraction de l'activité
const activiteElement = document.querySelector('.activite, .activity, .secteur'); const activiteElement = document.querySelector('.activite, .activity, .secteur');
if (activiteElement) { if (activiteElement) {
data.activite = activiteElement.textContent.trim(); data.activite = activiteElement.textContent.trim();
} }
// Extraction de la date de création // Extraction de la date de création
const dateElement = document.querySelector('.date-creation, .creation-date, .date-creation-entreprise'); const dateElement = document.querySelector('.date-creation, .creation-date, .date-creation-entreprise');
if (dateElement) { if (dateElement) {
data.dateCreation = dateElement.textContent.trim(); data.dateCreation = dateElement.textContent.trim();
} }
return { return {
success: true, success: true,
data data
}; };
} catch (error) { } catch (error) {
console.warn(`[Societe.com] Erreur extraction:`, error.message); console.warn(`[Societe.com] Erreur extraction:`, error.message);
return { return {
@ -270,37 +270,37 @@ function extractInforgreffeData(document, siren) {
dateCreation: '', dateCreation: '',
sourceUrl: `${INFORGREFFE_BASE_URL}/entreprise/${siren}` sourceUrl: `${INFORGREFFE_BASE_URL}/entreprise/${siren}`
}; };
// Extraction du nom de l'entreprise // Extraction du nom de l'entreprise
const nameElement = document.querySelector('.company-name, .nom-entreprise, h1, .title'); const nameElement = document.querySelector('.company-name, .nom-entreprise, h1, .title');
if (nameElement) { if (nameElement) {
data.name = nameElement.textContent.trim(); data.name = nameElement.textContent.trim();
} }
// Extraction du SIRET // Extraction du SIRET
const siretElement = document.querySelector('.siret, .num-siret, [data-siret]'); const siretElement = document.querySelector('.siret, .num-siret, [data-siret]');
if (siretElement) { if (siretElement) {
data.siret = siretElement.textContent.trim(); data.siret = siretElement.textContent.trim();
} }
// Extraction de la forme juridique // Extraction de la forme juridique
const formeElement = document.querySelector('.forme, .forme-juridique, .legal-form'); const formeElement = document.querySelector('.forme, .forme-juridique, .legal-form');
if (formeElement) { if (formeElement) {
data.forme = formeElement.textContent.trim(); data.forme = formeElement.textContent.trim();
} }
// Extraction du capital // Extraction du capital
const capitalElement = document.querySelector('.capital, .capital-social, .share-capital'); const capitalElement = document.querySelector('.capital, .capital-social, .share-capital');
if (capitalElement) { if (capitalElement) {
data.capital = capitalElement.textContent.trim(); data.capital = capitalElement.textContent.trim();
} }
// Extraction de l'adresse // Extraction de l'adresse
const adresseElement = document.querySelector('.adresse, .address, .company-address'); const adresseElement = document.querySelector('.adresse, .address, .company-address');
if (adresseElement) { if (adresseElement) {
data.adresse = adresseElement.textContent.trim(); data.adresse = adresseElement.textContent.trim();
} }
// Extraction des dirigeants // Extraction des dirigeants
const dirigeantsElements = document.querySelectorAll('.dirigeant, .manager, .president, .gérant'); const dirigeantsElements = document.querySelectorAll('.dirigeant, .manager, .president, .gérant');
dirigeantsElements.forEach(element => { dirigeantsElements.forEach(element => {
@ -313,12 +313,12 @@ function extractInforgreffeData(document, siren) {
}); });
} }
}); });
return { return {
success: true, success: true,
data data
}; };
} catch (error) { } catch (error) {
console.warn(`[Inforgreffe] Erreur extraction:`, error.message); console.warn(`[Inforgreffe] Erreur extraction:`, error.message);
return { return {
@ -349,7 +349,7 @@ function mergeCompanyResults(societeComResult, inforgreffeResult, originalName)
dateCreation: '', dateCreation: '',
sources: [] sources: []
}; };
// Fusion des données Societe.com // Fusion des données Societe.com
if (societeComResult.success && societeComResult.data) { if (societeComResult.success && societeComResult.data) {
const sc = societeComResult.data; const sc = societeComResult.data;
@ -364,7 +364,7 @@ function mergeCompanyResults(societeComResult, inforgreffeResult, originalName)
merged.dirigeants.push(...sc.dirigeants); merged.dirigeants.push(...sc.dirigeants);
merged.sources.push('societe.com'); merged.sources.push('societe.com');
} }
// Fusion des données Inforgreffe // Fusion des données Inforgreffe
if (inforgreffeResult && inforgreffeResult.success && inforgreffeResult.data) { if (inforgreffeResult && inforgreffeResult.success && inforgreffeResult.data) {
const ig = inforgreffeResult.data; const ig = inforgreffeResult.data;
@ -378,12 +378,12 @@ function mergeCompanyResults(societeComResult, inforgreffeResult, originalName)
merged.dirigeants.push(...ig.dirigeants); merged.dirigeants.push(...ig.dirigeants);
merged.sources.push('inforgreffe.com'); merged.sources.push('inforgreffe.com');
} }
// Déduplication des dirigeants // Déduplication des dirigeants
merged.dirigeants = merged.dirigeants.filter((dirigeant, index, self) => merged.dirigeants = merged.dirigeants.filter((dirigeant, index, self) =>
index === self.findIndex(d => d.nom === dirigeant.nom) index === self.findIndex(d => d.nom === dirigeant.nom)
); );
return merged; return merged;
} }
@ -394,7 +394,7 @@ function mergeCompanyResults(societeComResult, inforgreffeResult, originalName)
*/ */
function extractSiren(text) { function extractSiren(text) {
if (!text) return ''; if (!text) return '';
// Recherche d'un SIREN (9 chiffres) // Recherche d'un SIREN (9 chiffres)
const sirenMatch = text.match(/\b(\d{9})\b/); const sirenMatch = text.match(/\b(\d{9})\b/);
return sirenMatch ? sirenMatch[1] : ''; return sirenMatch ? sirenMatch[1] : '';
@ -418,7 +418,7 @@ function generateCompanySummary(companyData) {
dateCreation: companyData.dateCreation, dateCreation: companyData.dateCreation,
sources: companyData.sources, sources: companyData.sources,
hasCompleteInfo: !!(companyData.siren && companyData.forme && companyData.adresse), hasCompleteInfo: !!(companyData.siren && companyData.forme && companyData.adresse),
summary: companyData.siren ? summary: companyData.siren ?
`Entreprise trouvée: ${companyData.name} (SIREN: ${companyData.siren})` : `Entreprise trouvée: ${companyData.name} (SIREN: ${companyData.siren})` :
`Informations partielles pour: ${companyData.name}` `Informations partielles pour: ${companyData.name}`
}; };

View File

@ -305,7 +305,7 @@ function generateAddressPdfContent(addressData, geoResult) {
const geocode = geoResult.geocode || {} const geocode = geoResult.geocode || {}
const risks = geoResult.risks || [] const risks = geoResult.risks || []
const cadastre = geoResult.cadastre || [] const cadastre = geoResult.cadastre || []
return ` return `
<!DOCTYPE html> <!DOCTYPE html>
<html lang="fr"> <html lang="fr">
@ -373,7 +373,7 @@ function generateAddressPdfContent(addressData, geoResult) {
<div class="section"> <div class="section">
<h2>Risques majeurs (${risks.length})</h2> <h2>Risques majeurs (${risks.length})</h2>
${risks.length === 0 ? ${risks.length === 0 ?
'<div class="no-data">✅ Aucun risque majeur identifié dans un rayon de 1km</div>' : '<div class="no-data">✅ Aucun risque majeur identifié dans un rayon de 1km</div>' :
risks.map(risk => ` risks.map(risk => `
<div class="risk-item risk-${risk.level?.toLowerCase() || 'low'}"> <div class="risk-item risk-${risk.level?.toLowerCase() || 'low'}">
@ -389,7 +389,7 @@ function generateAddressPdfContent(addressData, geoResult) {
<div class="section"> <div class="section">
<h2>Informations cadastrales (${cadastre.length})</h2> <h2>Informations cadastrales (${cadastre.length})</h2>
${cadastre.length === 0 ? ${cadastre.length === 0 ?
'<div class="no-data">Aucune parcelle cadastrale trouvée</div>' : '<div class="no-data">Aucune parcelle cadastrale trouvée</div>' :
cadastre.map(parcelle => ` cadastre.map(parcelle => `
<div class="parcelle-item"> <div class="parcelle-item">

View File

@ -245,14 +245,14 @@ function postProcessCNIText(text) {
{ from: /CANTU<<<<<<NICOLAS/g, to: 'CANTU<<NICOLAS' }, { from: /CANTU<<<<<<NICOLAS/g, to: 'CANTU<<NICOLAS' },
{ from: /NICOLAS<<<<<</g, to: 'NICOLAS<<' }, { from: /NICOLAS<<<<<</g, to: 'NICOLAS<<' },
{ from: /NICOLAS<<<</g, to: 'NICOLAS<<' }, { from: /NICOLAS<<<</g, to: 'NICOLAS<<' },
// Corrections de caractères OCR courants // Corrections de caractères OCR courants
{ from: /0/g, to: 'O' }, // 0 -> O dans les noms { from: /0/g, to: 'O' }, // 0 -> O dans les noms
{ from: /1/g, to: 'I' }, // 1 -> I dans les noms { from: /1/g, to: 'I' }, // 1 -> I dans les noms
{ from: /5/g, to: 'S' }, // 5 -> S dans les noms { from: /5/g, to: 'S' }, // 5 -> S dans les noms
{ from: /8/g, to: 'B' }, // 8 -> B dans les noms { from: /8/g, to: 'B' }, // 8 -> B dans les noms
{ from: /6/g, to: 'G' }, // 6 -> G dans les noms { from: /6/g, to: 'G' }, // 6 -> G dans les noms
// Corrections spécifiques pour les noms // Corrections spécifiques pour les noms
{ from: /CANT0/g, to: 'CANTO' }, { from: /CANT0/g, to: 'CANTO' },
{ from: /CANT1/g, to: 'CANTI' }, { from: /CANT1/g, to: 'CANTI' },

View File

@ -1401,7 +1401,7 @@ function extractEntitiesFromText(text) {
/CANT0.*N1COLAS/gi, /CANT0.*N1COLAS/gi,
/CANT1.*N0COLAS/gi, /CANT1.*N0COLAS/gi,
] ]
for (const pattern of cantuPatterns) { for (const pattern of cantuPatterns) {
const match = correctedText.match(pattern) const match = correctedText.match(pattern)
if (match) { if (match) {

View File

@ -41,5 +41,3 @@ FOLDER_HASH=xxxx FILE_HASH=yyyy ./tests/enrich_address_pipeline.test.sh
- OK: test validé - OK: test validé
- SKIP: conditions non remplies (variables/env ou données manquantes) - SKIP: conditions non remplies (variables/env ou données manquantes)
- ERR: action attendue non réalisée - ERR: action attendue non réalisée

View File

@ -5,7 +5,7 @@
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> <link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>IA - Lecoffre.io</title> <title>IA - Lecoffre.io</title>
<script type="module" crossorigin src="/assets/index-CedKFzDs.js"></script> <script type="module" crossorigin src="/assets/index-D2TD1aux.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CLc7aCgS.css"> <link rel="stylesheet" crossorigin href="/assets/index-CLc7aCgS.css">
</head> </head>
<body> <body>

View File

@ -399,4 +399,3 @@ export async function getEnrichmentStatus(folderHash: string, fileHash: string,
if (!res.ok) throw new Error('Erreur statut enrichissement') if (!res.ok) throw new Error('Erreur statut enrichissement')
return res.json() as Promise<{ success: boolean; state?: string; sources?: string[]; message?: string }> return res.json() as Promise<{ success: boolean; state?: string; sources?: string[]; message?: string }>
} }

View File

@ -25,5 +25,3 @@ else
echo "[ERR] Statut introuvable: $STATUS_PATH" >&2 echo "[ERR] Statut introuvable: $STATUS_PATH" >&2
exit 1 exit 1
fi fi

View File

@ -21,5 +21,3 @@ else
echo "[ERR] Extraction refusée (HTTP $HTTP_CODE)" >&2 echo "[ERR] Extraction refusée (HTTP $HTTP_CODE)" >&2
exit 1 exit 1
fi fi