149 lines
4.6 KiB
JavaScript
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,
|
|
}
|