Files
VacatureRadar/apps/jobs/services/distance.py
T
Jens a4eced8be5
deploy / deploy (push) Canceled after 0s
Fix release blockers and deployment build
2026-07-21 21:22:29 +02:00

66 lines
1.7 KiB
Python

from __future__ import annotations
from dataclasses import dataclass
from math import asin, cos, radians, sin, sqrt
from typing import Protocol
def haversine_km(lat1: float, lon1: float, lat2: float, lon2: float) -> float:
radius_km = 6371.0088
dlat = radians(lat2 - lat1)
dlon = radians(lon2 - lon1)
a = sin(dlat / 2) ** 2 + cos(radians(lat1)) * cos(radians(lat2)) * sin(dlon / 2) ** 2
return 2 * radius_km * asin(sqrt(a))
@dataclass(frozen=True)
class CommuteEstimate:
minutes: int
km: float
source: str
source_version: str
confidence: float = 0.55
is_estimate: bool = True
class CommuteEstimator(Protocol):
name: str
version: str
def estimate(self, distance_km: float) -> CommuteEstimate: ...
@dataclass(frozen=True)
class ConservativeRoadEstimator:
name: str = "road"
version: str = "offline-heuristic-1"
avg_kmh: float = 34.0
route_factor: float = 1.35
confidence: float = 0.55
def estimate(self, distance_km: float) -> CommuteEstimate:
if distance_km <= 0:
minutes = 0
else:
minutes = int(((distance_km / self.avg_kmh) * 60.0) * self.route_factor)
return CommuteEstimate(
minutes=max(minutes, 1),
km=distance_km,
source=self.name,
source_version=self.version,
confidence=self.confidence,
is_estimate=True,
)
def estimate_commute(
distance_km: float | None,
*,
estimator: CommuteEstimator | None = None,
) -> CommuteEstimate | None:
if distance_km is None:
return None
if estimator is None:
estimator = ConservativeRoadEstimator()
return estimator.estimate(float(distance_km))