4NK_IA_front/backend/collectors/addressCollector.js

149 lines
4.6 KiB
JavaScript

/**
* Collecteur Adresses
* Géocodage via BAN (api-adresse.data.gouv.fr) et scaffold pour risques
*/
const fetch = require('node-fetch')
const USER_AGENT = '4NK-IA-Front/1.0 (Document Analysis Tool)'
const REQUEST_TIMEOUT_MS = 12000
// URLs des services publics
const GEORISQUE_BASE_URL = 'https://www.georisques.gouv.fr'
const CADASTRE_BASE_URL = 'https://cadastre.data.gouv.fr'
async function geocodeBAN(address) {
const q = [address.street, address.postalCode, address.city, address.country]
.filter(Boolean)
.join(' ')
const url = `https://api-adresse.data.gouv.fr/search/?q=${encodeURIComponent(q)}&limit=1`
const start = Date.now()
try {
const res = await fetch(url, {
headers: { 'User-Agent': USER_AGENT, 'Accept': 'application/json' },
timeout: REQUEST_TIMEOUT_MS,
})
if (!res.ok) throw new Error(`HTTP ${res.status}`)
const json = await res.json()
const f = json.features && json.features[0]
if (!f) {
return { success: true, duration: Date.now() - start, score: 0, lat: null, lon: null, label: null }
}
return {
success: true,
duration: Date.now() - start,
score: f.properties && typeof f.properties.score === 'number' ? f.properties.score : null,
lat: f.geometry?.coordinates ? f.geometry.coordinates[1] : null,
lon: f.geometry?.coordinates ? f.geometry.coordinates[0] : null,
label: f.properties?.label || null,
}
} catch (e) {
return { success: false, duration: Date.now() - start, error: e.message }
}
}
async function collectGéoRisque(lat, lon) {
if (!lat || !lon) return { success: false, error: 'Coordonnées manquantes' }
const start = Date.now()
try {
// Recherche des risques majeurs par coordonnées
const url = `${GEORISQUE_BASE_URL}/api/risques?lat=${lat}&lon=${lon}&rayon=1000`
const res = await fetch(url, {
headers: { 'User-Agent': USER_AGENT, 'Accept': 'application/json' },
timeout: REQUEST_TIMEOUT_MS,
})
if (!res.ok) throw new Error(`HTTP ${res.status}`)
const data = await res.json()
const risks = (data.risques || []).map(risk => ({
type: risk.type || 'Risque majeur',
level: risk.niveau || 'Non spécifié',
description: risk.description || '',
sourceUrl: `${GEORISQUE_BASE_URL}/risques/${risk.id || ''}`,
distance: risk.distance || null
}))
return {
success: true,
duration: Date.now() - start,
risks,
count: risks.length
}
} catch (e) {
return { success: false, duration: Date.now() - start, error: e.message, risks: [] }
}
}
async function collectCadastre(lat, lon) {
if (!lat || !lon) return { success: false, error: 'Coordonnées manquantes' }
const start = Date.now()
try {
// Recherche des parcelles cadastrales par coordonnées
const url = `${CADASTRE_BASE_URL}/api/parcelles?lat=${lat}&lon=${lon}&distance=100`
const res = await fetch(url, {
headers: { 'User-Agent': USER_AGENT, 'Accept': 'application/json' },
timeout: REQUEST_TIMEOUT_MS,
})
if (!res.ok) throw new Error(`HTTP ${res.status}`)
const data = await res.json()
const parcelles = (data.parcelles || []).map(parcelle => ({
section: parcelle.section || '',
numero: parcelle.numero || '',
commune: parcelle.commune || '',
surface: parcelle.surface || null,
sourceUrl: `${CADASTRE_BASE_URL}/parcelles/${parcelle.id || ''}`
}))
return {
success: true,
duration: Date.now() - start,
parcelles,
count: parcelles.length
}
} catch (e) {
return { success: false, duration: Date.now() - start, error: e.message, parcelles: [] }
}
}
async function collectAddressData(address) {
// Étape 1: Géocodage BAN
const geocode = await geocodeBAN(address)
let risks = []
let cadastre = []
// Étape 2: Si géocodage réussi, collecter risques et cadastre
if (geocode.success && geocode.lat && geocode.lon) {
console.log(`[Address] Géocodage réussi: ${geocode.lat}, ${geocode.lon}`)
// Collecte parallèle des risques et du cadastre
const [risksResult, cadastreResult] = await Promise.all([
collectGéoRisque(geocode.lat, geocode.lon),
collectCadastre(geocode.lat, geocode.lon)
])
risks = risksResult.risks || []
cadastre = cadastreResult.parcelles || []
console.log(`[Address] Risques: ${risks.length}, Parcelles: ${cadastre.length}`)
}
return {
success: geocode.success,
geocode,
risks,
cadastre,
timestamp: new Date().toISOString(),
sources: ['ban', 'georisque', 'cadastre']
}
}
module.exports = {
collectAddressData,
}