feat(console): add formatting utils and VIN API client
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
93
console/utils/vin_api.py
Normal file
93
console/utils/vin_api.py
Normal file
@@ -0,0 +1,93 @@
|
||||
"""
|
||||
NHTSA VIN Decoder API client for the AUTOPARTES console application.
|
||||
|
||||
Wraps the National Highway Traffic Safety Administration (NHTSA) Vehicle
|
||||
Product Information Catalog (vPIC) DecodeVin endpoint to retrieve vehicle
|
||||
specifications from a 17-character VIN.
|
||||
"""
|
||||
|
||||
import requests
|
||||
|
||||
from console.config import NHTSA_API_URL
|
||||
|
||||
|
||||
# NHTSA result variables we care about, mapped to our internal keys.
|
||||
_FIELD_MAP = {
|
||||
"Make": "make",
|
||||
"Model": "model",
|
||||
"Model Year": "year",
|
||||
"Body Class": "body_class",
|
||||
"Drive Type": "drive_type",
|
||||
"Displacement (L)": "displacement_l",
|
||||
"Engine Number of Cylinders": "cylinders",
|
||||
"Fuel Type - Primary": "fuel_type",
|
||||
"Engine Brake (hp) From": "power_hp",
|
||||
}
|
||||
|
||||
|
||||
def decode_vin_nhtsa(vin: str) -> dict:
|
||||
"""Decode a VIN using the NHTSA vPIC API.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
vin : str
|
||||
A 17-character Vehicle Identification Number.
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
On success::
|
||||
|
||||
{
|
||||
"make": "TOYOTA",
|
||||
"model": "Corolla",
|
||||
"year": "2020",
|
||||
"body_class": "Sedan/Saloon",
|
||||
"drive_type": "FWD",
|
||||
"engine_info": {
|
||||
"displacement_l": "2.0",
|
||||
"cylinders": "4",
|
||||
"fuel_type": "Gasoline",
|
||||
"power_hp": "169",
|
||||
"raw": { ... full variable->value mapping ... },
|
||||
},
|
||||
}
|
||||
|
||||
On error::
|
||||
|
||||
{"error": "<description>"}
|
||||
"""
|
||||
try:
|
||||
url = f"{NHTSA_API_URL}/{vin}"
|
||||
response = requests.get(url, params={"format": "json"}, timeout=15)
|
||||
response.raise_for_status()
|
||||
|
||||
data = response.json()
|
||||
results = data.get("Results", [])
|
||||
|
||||
# Build a flat lookup: variable name -> value (skip empty/None)
|
||||
raw: dict[str, str] = {}
|
||||
for item in results:
|
||||
var = item.get("Variable", "")
|
||||
val = item.get("Value")
|
||||
if val and str(val).strip():
|
||||
raw[var] = str(val).strip()
|
||||
|
||||
# Extract top-level vehicle fields
|
||||
vehicle: dict = {}
|
||||
engine_info: dict = {"raw": raw}
|
||||
|
||||
engine_keys = {"displacement_l", "cylinders", "fuel_type", "power_hp"}
|
||||
|
||||
for nhtsa_var, our_key in _FIELD_MAP.items():
|
||||
value = raw.get(nhtsa_var, "")
|
||||
if our_key in engine_keys:
|
||||
engine_info[our_key] = value
|
||||
else:
|
||||
vehicle[our_key] = value
|
||||
|
||||
vehicle["engine_info"] = engine_info
|
||||
return vehicle
|
||||
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
Reference in New Issue
Block a user