vgtc-api / src /hermes /api /routers /classify.py
vora-sonnet's picture
Upload folder using huggingface_hub
0d3f7cc verified
Raw
History Blame Contribute Delete
45.8 kB
"""Classification router — HS code lookup and duty calculation."""
from __future__ import annotations
import logging
from datetime import datetime, timezone
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel, Field
from hermes.api.middleware import sanitize_input
from hermes.core.auth import get_api_key_dependency
logger = logging.getLogger(__name__)
router = APIRouter(dependencies=[Depends(get_api_key_dependency)])
# ── Request/Response Models ──────────────────────────────────────────
class ItemInput(BaseModel):
description: str = Field(..., max_length=500, description="Item description")
quantity: int = Field(default=1, ge=1, description="Quantity")
unit_price_usd: float = Field(default=0.0, ge=0, description="Unit price in USD")
origin_country: str = Field(..., min_length=2, max_length=2, description="ISO country code")
class ClassifyRequest(BaseModel):
items: list[ItemInput] = Field(..., min_length=1, max_length=50, description="Items to classify")
destination_country: str = Field(..., min_length=2, max_length=2, description="Destination ISO country code")
class ItemClassification(BaseModel):
description: str
hs_code: str
taric_description: str
origin: str
customs_value: float
duty_rate: float
duty_amount: float
vat_rate: float
vat_amount: float
total_landed_cost: float
notes: str
class DutySummary(BaseModel):
customs_value: float
total_duty: float
total_vat: float
shipping_cost: float
total_taxes_fees: float
total_landed_cost: float
effective_rate: float
class ClassifyResponse(BaseModel):
status: str
classified_at: str
destination_country: str
items: list[ItemClassification]
summary: DutySummary
# ── TARIC API Helpers ────────────────────────────────────────────────
TARIC_BASE_URL = "https://ec.europa.eu/taxation_customs/dds2/taric"
TARIC_DESCRIPTION_URL = f"{TARIC_BASE_URL}/goodsDescrForWs"
# Default duty rate for unknown products (15% is conservative EU average)
DEFAULT_DUTY_RATE = 0.15
DEFAULT_VAT_RATE = 0.19 # German VAT
async def fetch_taric_description(taric_code: str) -> dict:
"""Fetch TARIC code description from EU database."""
import httpx
params = {
"Goods_code": taric_code.replace(".", ""),
"Country_code": "en",
}
try:
async with httpx.AsyncClient(timeout=15.0) as client:
resp = await client.get(TARIC_DESCRIPTION_URL, params=params)
resp.raise_for_status()
import xml.etree.ElementTree as ET
root = ET.fromstring(resp.text)
result = {}
goods_code = root.find(".//Goods_code")
if goods_code is not None:
result["taric_code"] = goods_code.text or ""
description = root.find(".//Description")
if description is not None:
result["description"] = description.text or ""
return result
except Exception as e:
return {"taric_code": taric_code, "description": f"Lookup failed: {e}"}
# ── Classification Logic ─────────────────────────────────────────────
# Comprehensive HS code lookup table: keywords → (hs_code, description, duty_rate, notes)
# Covers 100+ common import product categories
HS_CODE_DATABASE: dict[str, tuple[str, str, float, str]] = {
# ── Electronics & IT (Chapter 84-85) ──────────────────────────
"earbuds": ("8518.30", "Headphones and earphones", 0.0, "ITA zero duty"),
"headphones": ("8518.30", "Headphones and earphones", 0.0, "ITA zero duty"),
"earphones": ("8518.30", "Headphones and earphones", 0.0, "ITA zero duty"),
"airpods": ("8518.30", "Headphones and earphones", 0.0, "ITA zero duty"),
"charger": ("8504.40", "Static converters (chargers)", 0.0, "ITA zero duty"),
"charging": ("8504.40", "Static converters (chargers)", 0.0, "ITA zero duty"),
"power adapter": ("8504.40", "Static converters (chargers)", 0.0, "ITA zero duty"),
"power supply": ("8504.40", "Static converters (power supplies)", 0.0, "ITA zero duty"),
"usb-c": ("8504.40", "USB-C chargers/adapters", 0.0, "ITA zero duty"),
"laptop": ("8471.30", "Portable digital computers", 0.0, "ITA zero duty"),
"computer": ("8471.30", "Digital computers", 0.0, "ITA zero duty"),
"notebook": ("8471.30", "Portable computers", 0.0, "ITA zero duty"),
"macbook": ("8471.30", "Portable computers", 0.0, "ITA zero duty"),
"desktop": ("8471.30", "Desktop computers", 0.0, "ITA zero duty"),
"monitor": ("8528.52", "Monitors and displays", 0.0, "ITA zero duty"),
"display": ("8528.52", "Monitors and displays", 0.0, "ITA zero duty"),
"tv ": ("8528.72", "Television receivers", 0.14, "Standard rate"),
"television": ("8528.72", "Television receivers", 0.14, "Standard rate"),
"chip": ("8542.31", "Electronic integrated circuits", 0.0, "ITA zero duty"),
"processor": ("8542.31", "Electronic integrated circuits", 0.0, "ITA zero duty"),
"circuit": ("8542.31", "Electronic integrated circuits", 0.0, "ITA zero duty"),
"semiconductor": ("8542.31", "Semiconductor devices", 0.0, "ITA zero duty"),
"memory": ("8542.32", "Electronic integrated circuits (memory)", 0.0, "ITA zero duty"),
"ssd": ("8523.51", "Solid-state non-volatile storage", 0.0, "ITA zero duty"),
"hdd": ("8524.99", "Magnetic storage devices", 0.0, "ITA zero duty"),
"hard drive": ("8524.99", "Magnetic storage devices", 0.0, "ITA zero duty"),
"usb drive": ("8523.51", "Solid-state non-volatile storage", 0.0, "ITA zero duty"),
"flash drive": ("8523.51", "Solid-state non-volatile storage", 0.0, "ITA zero duty"),
"keyboard": ("8471.60", "Input/output units (keyboards)", 0.0, "ITA zero duty"),
"mouse": ("8471.60", "Input/output units (mice)", 0.0, "ITA zero duty"),
"printer": ("8443.32", "Printers, copying machines", 0.0, "ITA zero duty"),
"scanner": ("8443.32", "Scanners", 0.0, "ITA zero duty"),
"camera": ("8525.89", "Television cameras, digital cameras", 0.0, "ITA zero duty"),
"webcam": ("8525.89", "Digital cameras", 0.0, "ITA zero duty"),
"speaker": ("8518.22", "Loudspeakers", 0.0, "ITA zero duty"),
"bluetooth speaker": ("8518.22", "Loudspeakers", 0.0, "ITA zero duty"),
"router": ("8517.62", "Routers and switches", 0.0, "ITA zero duty"),
"switch ": ("8517.62", "Network switches", 0.0, "ITA zero duty"),
"modem": ("8517.62", "Modems", 0.0, "ITA zero duty"),
"wifi": ("8517.62", "Wireless network equipment", 0.0, "ITA zero duty"),
"antenna": ("8517.71", "Antenna and parts", 0.0, "ITA zero duty"),
"battery": ("8507.60", "Lithium-ion accumulators", 0.0, "ITA zero duty"),
"power bank": ("8507.60", "Portable battery packs", 0.0, "ITA zero duty"),
"solar panel": ("8541.40", "Photovoltaic cells", 0.0, "ITA zero duty"),
"led": ("9405.42", "LED light sources", 0.0, "ITA zero duty"),
"light bulb": ("9405.42", "LED light sources", 0.0, "Standard rate"),
"cable": ("8544.42", "Electric conductors, fitted with connectors", 0.0, "ITA zero duty"),
"wire": ("8544.49", "Electric conductors", 0.0, "ITA zero duty"),
"cable tie": ("3926.90", "Plastic articles", 0.065, "Standard rate"),
"connector": ("8536.90", "Electrical connectors", 0.0, "ITA zero duty"),
"plug": ("8536.90", "Electrical plugs and sockets", 0.0, "ITA zero duty"),
"socket": ("8536.90", "Electrical plugs and sockets", 0.0, "ITA zero duty"),
"extension cord": ("8544.42", "Extension cords", 0.0, "ITA zero duty"),
"surge protector": ("8536.30", "Surge protectors", 0.0, "ITA zero duty"),
"ups ": ("8504.40", "Uninterruptible power supplies", 0.0, "ITA zero duty"),
"server": ("8471.50", "Processing units (servers)", 0.0, "ITA zero duty"),
"workstation": ("8471.50", "Processing units", 0.0, "ITA zero duty"),
"graphics card": ("8473.30", "Parts for computers", 0.0, "ITA zero duty"),
"gpu ": ("8473.30", "Parts for computers", 0.0, "ITA zero duty"),
"motherboard": ("8473.30", "Parts for computers", 0.0, "ITA zero duty"),
"ram ": ("8542.32", "Memory modules", 0.0, "ITA zero duty"),
"smartphone": ("8517.13", "Smartphones", 0.0, "ITA zero duty"),
"mobile phone": ("8517.13", "Mobile phones", 0.0, "ITA zero duty"),
"tablet": ("8471.30", "Tablet computers", 0.0, "ITA zero duty"),
"ipad": ("8471.30", "Tablet computers", 0.0, "ITA zero duty"),
"smartwatch": ("9102.12", "Smartwatches", 0.045, "Standard rate"),
"drone": ("8802.20", "Unmanned aircraft", 0.0, "ITA zero duty"),
"drone parts": ("8803.90", "Parts of aircraft", 0.0, "ITA zero duty"),
"vr headset": ("9013.80", "Liquid crystal devices", 0.0, "ITA zero duty"),
"headset": ("8518.30", "Headphones and headsets", 0.0, "ITA zero duty"),
"microphone": ("8518.10", "Microphones", 0.0, "ITA zero duty"),
"amplifier": ("8518.50", "Audio amplifiers", 0.0, "ITA zero duty"),
"projector": ("9006.59", "Photographic projectors", 0.0, "ITA zero duty"),
"external hard drive": ("8524.99", "Magnetic storage devices", 0.0, "ITA zero duty"),
"smart home": ("8543.70", "Electrical machines with individual functions", 0.0, "ITA zero duty"),
"thermostat": ("9032.10", "Thermostats", 0.0, "ITA zero duty"),
"security camera": ("8525.83", "Television cameras", 0.0, "ITA zero duty"),
"cctv": ("8525.83", "Television cameras", 0.0, "ITA zero duty"),
"doorbell": ("8536.30", "Electric doorbells", 0.0, "ITA zero duty"),
# ── Food & Beverages (Chapter 01-24) ─────────────────────────
"coffee": ("0901.11", "Coffee, not roasted, not decaffeinated", 0.075, "Standard rate"),
"coffee beans": ("0901.11", "Coffee beans, not roasted", 0.075, "Standard rate"),
"arabica": ("0901.11", "Coffee beans, not roasted", 0.075, "Standard rate"),
"robusta": ("0901.11", "Coffee beans, not roasted", 0.075, "Standard rate"),
"roasted coffee": ("0901.21", "Coffee, roasted, not decaffeinated", 0.075, "Standard rate"),
"tea": ("0902.10", "Green tea, in packages ≤ 3kg", 0.0, "Standard rate"),
"black tea": ("0902.30", "Black tea, fermented, in packages ≤ 3kg", 0.0, "Standard rate"),
"spice": ("0910.99", "Spices and mixes", 0.0, "Standard rate"),
"pepper": ("0904.11", "Pepper, neither crushed nor ground", 0.0, "Standard rate"),
"chili": ("0904.21", "Chili peppers, dried", 0.0, "Standard rate"),
"cinnamon": ("0906.11", "Cinnamon, not crushed", 0.0, "Standard rate"),
"rice": ("1006.30", "Semi-milled or milled rice", 0.0, "Standard rate"),
"wheat": ("1001.19", "Wheat and meslin", 0.0, "Standard rate"),
"flour": ("1101.00", "Wheat or meslin flour", 0.0, "Standard rate"),
"sugar": ("1701.14", "Raw cane sugar", 0.0, "Standard rate"),
"chocolate": ("1806.32", "Chocolate, not filled", 0.08, "Standard rate"),
"cocoa": ("1801.00", "Cocoa beans", 0.0, "Standard rate"),
"honey": ("0409.00", "Natural honey", 0.17, "Standard rate"),
"olive oil": ("1509.10", "Virgin olive oil", 0.0, "Standard rate"),
"vegetable oil": ("1507.10", "Soybean oil, crude", 0.0, "Standard rate"),
"pasta": ("1902.19", "Pasta, not stuffed", 0.0, "Standard rate"),
"noodles": ("1902.30", "Other pasta", 0.0, "Standard rate"),
"biscuit": ("1905.31", "Sweet biscuits", 0.08, "Standard rate"),
"cookie": ("1905.31", "Sweet biscuits", 0.08, "Standard rate"),
"snack": ("1905.90", "Bakery products", 0.08, "Standard rate"),
"chips": ("2008.19", "Roasted nuts and snacks", 0.0, "Standard rate"),
"nuts": ("0802.11", "Almonds, fresh", 0.0, "Standard rate"),
"almond": ("0802.11", "Almonds, fresh", 0.0, "Standard rate"),
"cashew": ("0803.90", "Bananas and plantains", 0.0, "Standard rate"),
"peanut": ("1202.41", "Groundnuts, not roasted", 0.0, "Standard rate"),
"wine": ("2204.21", "Wine of fresh grapes, in containers ≤ 2L", 0.032, "Standard rate"),
"beer": ("2203.00", "Beer made from malt", 0.0, "Standard rate"),
"whisky": ("2208.30", "Whiskies", 0.0, "Standard rate"),
"vodka": ("2208.90", "Spirits and liqueurs", 0.0, "Standard rate"),
"juice": ("2009.12", "Orange juice, frozen", 0.0, "Standard rate"),
"water bottle": ("2201.10", "Waters, mineral and aerated", 0.0, "Standard rate"),
"milk": ("0401.20", "Milk and cream, not concentrated", 0.0, "Standard rate"),
"cheese": ("0406.90", "Cheese and curd", 0.0, "Standard rate"),
"butter": ("0405.10", "Butter", 0.0, "Standard rate"),
"egg": ("0407.11", "Fresh eggs of chickens", 0.0, "Standard rate"),
"frozen meat": ("0202.30", "Meat of bovine animals, boneless, frozen", 0.125, "Standard rate"),
"chicken": ("0207.14", "Frozen chicken cuts", 0.0, "Standard rate"),
"fish": ("0303.89", "Frozen fish", 0.0, "Standard rate"),
"shrimp": ("0306.17", "Frozen shrimps and prawns", 0.0, "Standard rate"),
"canned food": ("2023.90", "Prepared or preserved meat", 0.25, "Standard rate"),
"sauce": ("2103.90", "Sauces and preparations", 0.0, "Standard rate"),
"condiment": ("2103.90", "Sauces and condiments", 0.0, "Standard rate"),
"vinegar": ("2209.00", "Vinegar", 0.0, "Standard rate"),
"salt": ("2501.00", "Sodium chloride", 0.0, "Standard rate"),
# ── Textiles & Clothing (Chapter 50-63) ──────────────────────
"shirt": ("6105.10", "Men's shirts, cotton, knitted", 0.12, "Textile rate"),
"t-shirt": ("6109.10", "T-shirts, cotton, knitted", 0.12, "Textile rate"),
"polo": ("6105.10", "Men's shirts, cotton, knitted", 0.12, "Textile rate"),
"jersey": ("6110.30", "Jerseys and pullovers", 0.12, "Textile rate"),
"pullover": ("6110.30", "Pullovers and sweatshirts", 0.12, "Textile rate"),
"sweater": ("6110.30", "Sweaters and pullovers", 0.12, "Textile rate"),
"hoodie": ("6110.30", "Hoodies and sweatshirts", 0.12, "Textile rate"),
"jacket": ("6201.93", "Men's jackets, man-made fibres", 0.12, "Textile rate"),
"coat": ("6201.10", "Overcoats, raincoats", 0.12, "Textile rate"),
"vest": ("6110.30", "Vests and waistcoats", 0.12, "Textile rate"),
"pants": ("6203.42", "Men's trousers, cotton", 0.12, "Textile rate"),
"trousers": ("6203.42", "Men's trousers, cotton", 0.12, "Textile rate"),
"jeans": ("6203.42", "Men's jeans, cotton", 0.12, "Textile rate"),
"shorts": ("6203.59", "Men's shorts", 0.12, "Textile rate"),
"skirt": ("6204.53", "Women's skirts, man-made fibres", 0.12, "Textile rate"),
"dress": ("6204.43", "Women's dresses, synthetic fibres", 0.12, "Textile rate"),
"leggings": ("6115.95", "Stockings and leggings", 0.12, "Textile rate"),
"socks": ("6115.95", "Stockings and socks", 0.12, "Textile rate"),
"underwear": ("6107.11", "Men's underpants, cotton, knitted", 0.12, "Textile rate"),
"bra": ("6212.10", "Brassieres", 0.12, "Textile rate"),
"swimsuit": ("6112.41", "Women's swimwear, synthetic fibres", 0.12, "Textile rate"),
"uniform": ("6110.30", "Uniforms and workwear", 0.12, "Textile rate"),
"workwear": ("6211.33", "Men's clothing, man-made fibres", 0.12, "Textile rate"),
"scarf": ("6117.10", "Shawls, scarves", 0.12, "Textile rate"),
"tie ": ("6215.20", "Ties and bow ties", 0.12, "Textile rate"),
"glove": ("6116.93", "Gloves, knitted", 0.12, "Textile rate"),
"hat ": ("6505.00", "Hats and headgear, knitted", 0.12, "Textile rate"),
"cap ": ("6505.00", "Caps and headgear", 0.12, "Textile rate"),
"beanie": ("6505.00", "Headgear, knitted", 0.12, "Textile rate"),
"blanket": ("6302.21", "Bed linen, cotton, printed", 0.12, "Textile rate"),
"towel": ("6302.60", "Toilet and kitchen linen", 0.12, "Textile rate"),
"curtain": ("6303.91", "Curtains, cotton", 0.12, "Textile rate"),
"fabric": ("5208.12", "Woven cotton fabrics", 0.08, "Textile rate"),
"yarn": ("5204.19", "Cotton sewing thread", 0.0, "Standard rate"),
# ── Footwear (Chapter 64) ────────────────────────────────────
"shoes": ("6403.99", "Footwear with leather uppers", 0.169, "Footwear rate"),
"boots": ("6403.99", "Boots with leather uppers", 0.169, "Footwear rate"),
"sneakers": ("6404.11", "Sports footwear, rubber/plastic soles", 0.169, "Footwear rate"),
"running shoes": ("6404.11", "Sports footwear, rubber/plastic soles", 0.169, "Footwear rate"),
"sandals": ("6403.99", "Sandals with leather uppers", 0.169, "Footwear rate"),
"slippers": ("6404.19", "Slippers, textile uppers", 0.169, "Footwear rate"),
"flip flops": ("6404.19", "Flip flops, rubber soles", 0.169, "Footwear rate"),
"heels": ("6403.99", "High-heeled shoes", 0.169, "Footwear rate"),
"loafers": ("6403.99", "Leather loafers", 0.169, "Footwear rate"),
"football boots": ("6404.11", "Football boots", 0.169, "Footwear rate"),
"hiking boots": ("6403.99", "Hiking boots, leather uppers", 0.169, "Footwear rate"),
"work boots": ("6403.99", "Safety boots", 0.169, "Footwear rate"),
# ── Bags & Leather (Chapter 42) ──────────────────────────────
"bag": ("4202.21", "Handbags, leather", 0.08, "Standard rate"),
"handbag": ("4202.21", "Handbags, leather", 0.08, "Standard rate"),
"backpack": ("4202.92", "Backpacks, textile", 0.08, "Standard rate"),
"luggage": ("4202.12", "Trunks and suitcases, hard shell", 0.08, "Standard rate"),
"suitcase": ("4202.12", "Suitcases, hard shell", 0.08, "Standard rate"),
"wallet": ("4202.31", "Wallets, leather", 0.08, "Standard rate"),
"purse": ("4202.31", "Purses, leather", 0.08, "Standard rate"),
"briefcase": ("4202.12", "Briefcases", 0.08, "Standard rate"),
"laptop bag": ("4202.92", "Laptop bags", 0.08, "Standard rate"),
"belt ": ("4203.30", "Belts and bandoliers, leather", 0.08, "Standard rate"),
# ── Toys & Games (Chapter 95) ────────────────────────────────
"toy": ("9503.00", "Toys and models", 0.047, "Standard rate"),
"doll": ("9503.00", "Dolls and toy figures", 0.047, "Standard rate"),
"puzzle": ("9503.00", "Puzzles and jigsaws", 0.047, "Standard rate"),
"lego": ("9503.00", "Construction toys", 0.047, "Standard rate"),
"board game": ("9504.90", "Board games", 0.0, "Standard rate"),
"card game": ("9504.90", "Card games", 0.0, "Standard rate"),
"playing cards": ("9504.40", "Playing cards", 0.0, "Standard rate"),
"action figure": ("9503.00", "Toy figures", 0.047, "Standard rate"),
"stuffed animal": ("9503.00", "Stuffed toys", 0.047, "Standard rate"),
"plush": ("9503.00", "Stuffed toys", 0.047, "Standard rate"),
"remote control car": ("9503.00", "Radio-controlled toys", 0.047, "Standard rate"),
"rc car": ("9503.00", "Radio-controlled toys", 0.047, "Standard rate"),
"balloon": ("9503.00", "Toy balloons", 0.047, "Standard rate"),
"kite": ("9503.00", "Kites and similar toys", 0.047, "Standard rate"),
"video game": ("9504.50", "Video game consoles and machines", 0.0, "Standard rate"),
"console": ("9504.50", "Game consoles", 0.0, "Standard rate"),
"controller": ("9504.50", "Game controllers", 0.0, "Standard rate"),
# ── Furniture (Chapter 94) ───────────────────────────────────
"chair": ("9401.30", "Swivel chairs with adjustable height", 0.0, "Standard rate"),
"desk": ("9403.30", "Office furniture, wood", 0.0, "Standard rate"),
"table": ("9403.40", "Kitchen furniture, wood", 0.0, "Standard rate"),
"sofa": ("9401.61", "Upholstered seats, wooden frame", 0.0, "Standard rate"),
"couch": ("9401.61", "Upholstered seats, wooden frame", 0.0, "Standard rate"),
"bed ": ("9403.50", "Wooden furniture for bedrooms", 0.0, "Standard rate"),
"mattress": ("9404.21", "Mattresses of cellular rubber", 0.0, "Standard rate"),
"bookshelf": ("9403.40", "Shelving, wood", 0.0, "Standard rate"),
"cabinet": ("9403.40", "Cabinets, wood", 0.0, "Standard rate"),
"wardrobe": ("9403.50", "Wooden furniture for bedrooms", 0.0, "Standard rate"),
"filing cabinet": ("9403.10", "Metal furniture for offices", 0.0, "Standard rate"),
"shoe rack": ("9403.40", "Shelving, wood", 0.0, "Standard rate"),
"tv stand": ("9403.40", "TV stands, wood", 0.0, "Standard rate"),
# ── Home & Kitchen (Chapter 69-73, 82-83) ────────────────────
"mug": ("6912.00", "Ceramic tableware", 0.0, "Standard rate"),
"cup": ("6912.00", "Ceramic cups", 0.0, "Standard rate"),
"plate": ("6911.10", "Tableware, porcelain", 0.0, "Standard rate"),
"bowl": ("6911.10", "Ceramic bowls", 0.0, "Standard rate"),
"glass": ("7013.37", "Drinking glasses", 0.0, "Standard rate"),
"bottle": ("7010.90", "Glass bottles", 0.0, "Standard rate"),
"vase": ("7013.99", "Ceramic or glass vases", 0.0, "Standard rate"),
"pan ": ("7323.93", "Steel cooking articles", 0.0, "Standard rate"),
"pot ": ("7323.93", "Steel pots and pans", 0.0, "Standard rate"),
"frying pan": ("7323.93", "Frying pans, steel", 0.0, "Standard rate"),
"cooking pot": ("7323.93", "Cooking pots, steel", 0.0, "Standard rate"),
"knife": ("8211.91", "Kitchen knives with fixed blades", 0.0, "Standard rate"),
"kitchen knife": ("8211.91", "Kitchen knives with fixed blades", 0.0, "Standard rate"),
"fork": ("8215.99", "Forks and spoons, steel", 0.0, "Standard rate"),
"spoon": ("8215.99", "Spoons, steel", 0.0, "Standard rate"),
"cutlery": ("8215.99", "Cutlery sets, steel", 0.0, "Standard rate"),
"blender": ("8509.40", "Food grinders and blenders", 0.0, "ITA zero duty"),
"toaster": ("8516.72", "Toasters", 0.0, "ITA zero duty"),
"kettle": ("8516.10", "Electric water heaters", 0.0, "ITA zero duty"),
"microwave": ("8516.50", "Microwave ovens", 0.0, "ITA zero duty"),
"oven": ("8516.60", "Electric ovens", 0.0, "ITA zero duty"),
"refrigerator": ("8418.10", "Refrigerators, combined", 0.0, "ITA zero duty"),
"freezer": ("8418.30", "Freezers", 0.0, "ITA zero duty"),
"washing machine": ("8450.11", "Fully-automatic washing machines", 0.0, "ITA zero duty"),
"dryer": ("8451.29", "Drying machines", 0.0, "ITA zero duty"),
"vacuum cleaner": ("8508.11", "Vacuum cleaners, power < 1500W", 0.0, "ITA zero duty"),
"air conditioner": ("8415.10", "Window or wall type air conditioning machines", 0.0, "ITA zero duty"),
"fan ": ("8414.51", "Table, floor or wall fans", 0.0, "ITA zero duty"),
"heater": ("8516.29", "Electric space and soil heaters", 0.0, "ITA zero duty"),
"iron ": ("8516.40", "Electric irons", 0.0, "ITA zero duty"),
"hair dryer": ("8516.31", "Hair dryers", 0.0, "ITA zero duty"),
"sewing machine": ("8452.21", "Sewing machines", 0.0, "ITA zero duty"),
"luggage tag": ("4821.10", "Luggage labels, paper", 0.0, "Standard rate"),
# ── Rubber & Plastics (Chapter 39-40) ────────────────────────
"rubber": ("4015.90", "Articles of vulcanised rubber", 0.065, "Standard rate"),
"silicone": ("3926.90", "Plastic articles", 0.065, "Standard rate"),
"plastic": ("3926.90", "Plastic articles", 0.065, "Standard rate"),
"foam": ("3921.13", "Foam plastic articles", 0.065, "Standard rate"),
"styrofoam": ("3921.13", "Polystyrene foam", 0.065, "Standard rate"),
"pvc": ("3917.23", "PVC tubes and pipes", 0.065, "Standard rate"),
"polyethylene": ("3917.23", "Plastic tubes and pipes", 0.065, "Standard rate"),
"nitrile gloves": ("4015.90", "Rubber gloves", 0.065, "Standard rate"),
"rubber band": ("4015.90", "Rubber bands", 0.065, "Standard rate"),
"eraser": ("4015.90", "Rubber erasers", 0.065, "Standard rate"),
"seal ": ("4016.93", "Rubber gaskets and seals", 0.065, "Standard rate"),
"o-ring": ("4016.93", "O-rings, rubber", 0.065, "Standard rate"),
# ── Paper & Stationery (Chapter 47-49) ───────────────────────
"paper": ("4819.10", "Cartons and boxes of paper", 0.0, "Standard rate"),
"notebook": ("4820.10", "Notebooks and pads", 0.0, "Standard rate"),
"pen ": ("9608.10", "Ball point pens", 0.0, "Standard rate"),
"pencil": ("9609.10", "Pencils and crayons", 0.0, "Standard rate"),
"marker": ("9608.20", "Felt-tipped and porous pens", 0.0, "Standard rate"),
"stapler": ("8472.90", "Stapling machines", 0.0, "ITA zero duty"),
"tape": ("3919.10", "Self-adhesive plastic tape", 0.065, "Standard rate"),
"envelope": ("4817.10", "Envelopes, paper", 0.0, "Standard rate"),
"calendar": ("4910.00", "Printed calendars", 0.0, "Standard rate"),
"book ": ("4901.99", "Printed books, brochures", 0.0, "Standard rate"),
"textbook": ("4901.99", "Textbooks and educational books", 0.0, "Standard rate"),
"magazine": ("4902.10", "Newspapers and magazines", 0.0, "Standard rate"),
"newspaper": ("4902.10", "Newspapers", 0.0, "Standard rate"),
"brochure": ("4911.99", "Printed matter", 0.0, "Standard rate"),
"poster": ("4911.99", "Printed posters", 0.0, "Standard rate"),
"sticker": ("4911.91", "Printed stickers and labels", 0.0, "Standard rate"),
"label": ("4821.10", "Printed labels", 0.0, "Standard rate"),
# ── Beauty & Personal Care (Chapter 33-34) ───────────────────
"perfume": ("3303.00", "Perfumes and toilet waters", 0.0, "Standard rate"),
"cologne": ("3303.00", "Perfumes", 0.0, "Standard rate"),
"shampoo": ("3305.10", "Shampoos", 0.0, "Standard rate"),
"conditioner": ("3305.90", "Hair preparations", 0.0, "Standard rate"),
"soap": ("3401.11", "Toilet soap", 0.0, "Standard rate"),
"lotion": ("3304.99", "Beauty preparations", 0.0, "Standard rate"),
"moisturizer": ("3304.99", "Skin moisturizers", 0.0, "Standard rate"),
"sunscreen": ("3304.99", "Sunscreen preparations", 0.0, "Standard rate"),
"makeup": ("3304.91", "Lip and eye makeup", 0.0, "Standard rate"),
"cosmetics": ("3304.99", "Cosmetic preparations", 0.0, "Standard rate"),
"toothpaste": ("3306.10", "Toothpaste", 0.0, "Standard rate"),
"toothbrush": ("9603.21", "Toothbrushes", 0.0, "Standard rate"),
"razor": ("9615.11", "Razor blades", 0.0, "Standard rate"),
"deodorant": ("3307.20", "Deodorants", 0.0, "Standard rate"),
"candle": ("3406.00", "Candles and tapers", 0.0, "Standard rate"),
"essential oil": ("3301.90", "Essential oils", 0.0, "Standard rate"),
# ── Sports & Outdoor (Chapter 95) ────────────────────────────
"football": ("9506.62", "Inflatable balls", 0.0, "Standard rate"),
"soccer ball": ("9506.62", "Inflatable balls", 0.0, "Standard rate"),
"basketball": ("9506.62", "Basketballs", 0.0, "Standard rate"),
"tennis": ("9506.40", "Tennis rackets", 0.0, "Standard rate"),
"golf": ("9506.39", "Golf clubs and equipment", 0.0, "Standard rate"),
"yoga mat": ("9506.99", "Sports equipment", 0.0, "Standard rate"),
"gym equipment": ("9506.91", "Articles for gymnasium", 0.0, "Standard rate"),
"dumbbell": ("9506.91", "Articles for gymnasium", 0.0, "Standard rate"),
"bicycle": ("8712.00", "Bicycles", 0.14, "Standard rate"),
"bike": ("8712.00", "Bicycles", 0.14, "Standard rate"),
"helmet": ("6506.10", "Helmets for riders", 0.0, "Standard rate"),
"fishing rod": ("9507.10", "Fishing rods", 0.0, "Standard rate"),
"camping tent": ("6307.90", "Tent articles", 0.0, "Standard rate"),
"sleeping bag": ("9404.30", "Sleeping bags", 0.0, "Standard rate"),
"backpack outdoor": ("4202.92", "Backpacks", 0.08, "Standard rate"),
"ski": ("9506.11", "Skis for snow", 0.0, "Standard rate"),
"surfboard": ("9506.99", "Surf boards", 0.0, "Standard rate"),
"swimming goggles": ("9506.99", "Swimming goggles", 0.0, "Standard rate"),
"boxing gloves": ("9506.99", "Boxing gloves", 0.0, "Standard rate"),
"badminton": ("9506.59", "Badminton rackets", 0.0, "Standard rate"),
"ping pong": ("9506.40", "Table tennis equipment", 0.0, "Standard rate"),
"billiard": ("9504.90", "Billiard equipment", 0.0, "Standard rate"),
"pool cue": ("9504.90", "Billiard cues", 0.0, "Standard rate"),
# ── Automotive Parts (Chapter 85-87) ─────────────────────────
"brake pad": ("8708.30", "Brakes and servo-brakes", 0.025, "Standard rate"),
"oil filter": ("8421.23", "Oil or fuel filters", 0.0, "ITA zero duty"),
"air filter": ("8421.23", "Air filters", 0.0, "ITA zero duty"),
"spark plug": ("8511.10", "Spark plugs", 0.0, "ITA zero duty"),
"alternator": ("8511.20", "Alternators", 0.0, "ITA zero duty"),
"starter motor": ("8511.40", "Starter motors", 0.0, "ITA zero duty"),
"headlight": ("8512.20", "Lighting equipment for vehicles", 0.0, "ITA zero duty"),
"taillight": ("8512.20", "Vehicle lighting equipment", 0.0, "ITA zero duty"),
"wing mirror": ("8708.29", "Parts for vehicles", 0.025, "Standard rate"),
"bumper": ("8708.10", "Bumpers and parts", 0.025, "Standard rate"),
"windshield": ("7007.21", "Laminated safety glass", 0.0, "ITA zero duty"),
"tyre": ("4011.10", "New pneumatic rubber tyres, cars", 0.045, "Standard rate"),
"tire ": ("4011.10", "New pneumatic rubber tyres, cars", 0.045, "Standard rate"),
"wheel": ("8708.70", "Wheels and parts", 0.025, "Standard rate"),
"car battery": ("8507.10", "Lead-acid accumulators for vehicles", 0.0, "ITA zero duty"),
"car seat cover": ("8708.99", "Parts for motor vehicles", 0.025, "Standard rate"),
"floor mat car": ("8708.99", "Vehicle interior fittings", 0.025, "Standard rate"),
# ── Jewelry & Watches (Chapter 71) ───────────────────────────
"ring ": ("7113.11", "Rings, silver", 0.025, "Standard rate"),
"necklace": ("7113.19", "Necklaces, other precious metal", 0.025, "Standard rate"),
"bracelet": ("7113.19", "Bracelets, precious metal", 0.025, "Standard rate"),
"earring": ("7113.19", "Earrings, precious metal", 0.025, "Standard rate"),
"watch": ("9101.19", "Wrist-watches with case of precious metal", 0.045, "Standard rate"),
"pendant": ("7113.19", "Pendants, precious metal", 0.025, "Standard rate"),
"brooch": ("7113.19", "Brooches, precious metal", 0.025, "Standard rate"),
"anklet": ("7117.19", "Imitation jewellery, base metal", 0.04, "Standard rate"),
"jewelry": ("7113.19", "Jewellery, precious metal", 0.025, "Standard rate"),
# ── Building Materials (Chapter 68-73) ────────────────────────
"tile": ("6907.21", "Ceramic tiles", 0.0, "Standard rate"),
"marble": ("6802.93", "Marble and articles", 0.0, "Standard rate"),
"granite": ("6802.93", "Granite and articles", 0.0, "Standard rate"),
"ceramic": ("6907.21", "Ceramic tiles", 0.0, "Standard rate"),
"steel pipe": ("7304.31", "Seamless pipes, iron or steel", 0.0, "Standard rate"),
"steel tube": ("7304.31", "Seamless tubes, iron or steel", 0.0, "Standard rate"),
"aluminium": ("7604.21", "Aluminium tubes and pipes", 0.0, "Standard rate"),
"cement": ("2523.29", "Portland cement", 0.0, "Standard rate"),
"sand": ("2505.90", "Natural sands", 0.0, "Standard rate"),
"gravel": ("2517.10", "Pebbles and gravel", 0.0, "Standard rate"),
"brick": ("6904.10", "Ceramic building bricks", 0.0, "Standard rate"),
"insulation": ("6808.00", "Panels of fibres and cement", 0.0, "Standard rate"),
"paint": ("3208.90", "Paints and varnishes", 0.065, "Standard rate"),
"varnish": ("3208.90", "Varnishes", 0.065, "Standard rate"),
"adhesive": ("3506.99", "Prepared glues and adhesives", 0.0, "Standard rate"),
"glue": ("3506.99", "Glues and adhesives", 0.0, "Standard rate"),
"nail": ("7317.00", "Nails and tacks, iron or steel", 0.0, "Standard rate"),
"screw": ("7318.15", "Screws and bolts, iron or steel", 0.0, "Standard rate"),
"bolt": ("7318.15", "Bolts and screws, iron or steel", 0.0, "Standard rate"),
"nut ": ("7318.16", "Nuts, iron or steel", 0.0, "Standard rate"),
"washer": ("7318.22", "Washers, iron or steel", 0.0, "Standard rate"),
"spring": ("7320.20", "Helical springs, iron or steel", 0.0, "Standard rate"),
# ── Medical & Pharmaceutical (Chapter 30, 90) ────────────────
"mask": ("6307.90", "Face masks, textile", 0.0, "Standard rate"),
"surgical mask": ("6307.90", "Surgical masks", 0.0, "Standard rate"),
"glove medical": ("4015.90", "Medical examination gloves", 0.065, "Standard rate"),
"bandage": ("3005.90", "Bandages and dressings", 0.0, "Standard rate"),
"syringe": ("9018.31", "Syringes and needles", 0.0, "Standard rate"),
" thermometer": ("9025.80", "Thermometers", 0.0, "ITA zero duty"),
"stethoscope": ("9018.19", "Electro-diagnostic apparatus", 0.0, "ITA zero duty"),
"hearing aid": ("9021.40", "Hearing aids", 0.0, "ITA zero duty"),
"prosthetic": ("9021.39", "Artificial joints and other", 0.0, "ITA zero duty"),
"wheelchair": ("8713.10", "Wheelchairs not mechanically propelled", 0.0, "ITA zero duty"),
# ── Musical Instruments (Chapter 92) ──────────────────────────
"guitar": ("9202.10", "String musical instruments (guitars)", 0.0, "Standard rate"),
"piano": ("9201.10", "Grand pianos", 0.0, "Standard rate"),
"keyboard musical": ("9207.10", "Keyboard instruments (electronic)", 0.0, "ITA zero duty"),
"drum ": ("9206.00", "Percussion musical instruments", 0.0, "Standard rate"),
"violin": ("9202.10", "Violins and string instruments", 0.0, "Standard rate"),
"flute": ("9205.10", "Wind musical instruments", 0.0, "Standard rate"),
"saxophone": ("9205.10", "Saxophones", 0.0, "Standard rate"),
"trumpet": ("9205.10", "Trumpets", 0.0, "Standard rate"),
"ukulele": ("9202.10", "Ukuleles", 0.0, "Standard rate"),
"harmonica": ("9204.10", "Harmonicas", 0.0, "Standard rate"),
"amplifier musical": ("8518.50", "Audio frequency amplifiers", 0.0, "ITA zero duty"),
"guitar amp": ("8518.50", "Guitar amplifiers", 0.0, "ITA zero duty"),
# ── Office Supplies ──────────────────────────────────────────
"whiteboard": ("9504.90", "Board games and equipment", 0.0, "Standard rate"),
"projector stand": ("9403.30", "Office furniture", 0.0, "Standard rate"),
"laptop stand": ("8473.30", "Computer parts and accessories", 0.0, "ITA zero duty"),
"monitor arm": ("7326.90", "Articles of iron or steel", 0.0, "Standard rate"),
"desk lamp": ("9405.20", "Desk lamps", 0.0, "ITA zero duty"),
"ergonomic chair": ("9401.30", "Swivel chairs", 0.0, "Standard rate"),
"file holder": ("4821.10", "Labels and file holders", 0.0, "Standard rate"),
"cable management": ("3926.90", "Plastic articles for cable management", 0.065, "Standard rate"),
"wireless charger": ("8504.40", "Wireless chargers", 0.0, "ITA zero duty"),
"magsafe": ("8504.40", "MagSafe chargers", 0.0, "ITA zero duty"),
"dock": ("8473.30", "Computer docking stations", 0.0, "ITA zero duty"),
"hub usb": ("8471.60", "USB hubs", 0.0, "ITA zero duty"),
"ethernet cable": ("8544.42", "Electric conductors with connectors", 0.0, "ITA zero duty"),
"hdmi cable": ("8544.42", "HDMI cables", 0.0, "ITA zero duty"),
"power strip": ("8536.90", "Power strips and extension leads", 0.0, "ITA zero duty"),
# ── Miscellaneous ────────────────────────────────────────────
"umbrella": ("6601.10", "Garden umbrellas and similar", 0.08, "Standard rate"),
"decoration": ("9701.10", "Paintings, drawings and pastels", 0.0, "Standard rate"),
"artwork": ("9701.10", "Original artworks", 0.0, "Standard rate"),
"flower": ("0603.11", "Fresh cut roses", 0.0, "Standard rate"),
"plant": ("0602.90", "Live plants", 0.0, "Standard rate"),
"seed": ("1209.99", "Seeds for sowing", 0.0, "Standard rate"),
"fertilizer": ("3105.20", "Mineral or chemical fertilizers", 0.0, "Standard rate"),
"pet food": ("2309.10", "Dog or cat food", 0.0, "Standard rate"),
"litter": ("2530.10", "Expanded minerals (cat litter)", 0.0, "Standard rate"),
"aquarium": ("9306.90", "Other articles for aquariums", 0.0, "Standard rate"),
"incense": ("3307.41", "Incense and宗教 articles", 0.0, "Standard rate"),
"candle scented": ("3406.00", "Scented candles", 0.0, "Standard rate"),
"photo frame": ("4414.90", "Frames for photographs", 0.0, "Standard rate"),
"mirror": ("7009.92", "Glass mirrors, framed", 0.0, "Standard rate"),
"binoculars": ("9005.80", "Binoculars", 0.0, "ITA zero duty"),
"telescope": ("9005.80", "Telescopes", 0.0, "ITA zero duty"),
"compass": ("9014.10", "Direction-finding compasses", 0.0, "ITA zero duty"),
"scale": ("8423.10", "Weighing scales", 0.0, "ITA zero duty"),
"thermos": ("9617.00", "Vacuum flasks", 0.0, "Standard rate"),
"ice cream maker": ("8210.00", "Hand-operated food grinders", 0.0, "Standard rate"),
"popcorn maker": ("8516.72", "Coffee or tea makers", 0.0, "ITA zero duty"),
"pet bed": ("9404.21", "Mattress supports", 0.0, "Standard rate"),
"dog house": ("4418.60", "Doors and windows, wood", 0.0, "Standard rate"),
"bird cage": ("7326.20", "Articles of wire, iron or steel", 0.0, "Standard rate"),
"smoke detector": ("8531.10", "Fire or smoke detectors", 0.0, "ITA zero duty"),
"carbon monoxide detector": ("8531.10", "Gas detectors", 0.0, "ITA zero duty"),
"flashlight": ("8513.10", "Hand-held electric torches", 0.0, "ITA zero duty"),
"lantern": ("8513.10", "Electric lanterns", 0.0, "ITA zero duty"),
"power tool": ("8467.21", "Electric drills", 0.0, "ITA zero duty"),
"drill": ("8467.21", "Electric drills", 0.0, "ITA zero duty"),
"saw": ("8467.22", "Electric saws", 0.0, "ITA zero duty"),
"grinder": ("8467.81", "Grinding machines", 0.0, "ITA zero duty"),
"sandpaper": ("6805.30", "Articles of paper with abrasive coating", 0.0, "Standard rate"),
"paint brush": ("9603.30", "Artists' brushes and writing brushes", 0.0, "Standard rate"),
"roller paint": ("9603.30", "Paint rollers", 0.0, "Standard rate"),
"caulking gun": ("8467.81", "Hand tools, pneumatic", 0.0, "ITA zero duty"),
"wrench": ("8204.11", "Hand-operated spanners and wrenches", 0.0, "Standard rate"),
"screwdriver": ("8205.40", "Screwdrivers", 0.0, "Standard rate"),
"pliers": ("8203.20", "Pliers, including cutting pliers", 0.0, "Standard rate"),
"hammer": ("8205.20", "Hand hammers and sledge hammers", 0.0, "Standard rate"),
"tape measure": ("9017.80", "Measuring tapes", 0.0, "ITA zero duty"),
"level": ("9017.20", "Drawing and measuring instruments", 0.0, "ITA zero duty"),
"multimeter": ("9030.33", "Multimeters", 0.0, "ITA zero duty"),
"soldering iron": ("8515.11", "Soldering irons and guns", 0.0, "ITA zero duty"),
"cable tester": ("9030.33", "Electrical measuring instruments", 0.0, "ITA zero duty"),
"network tester": ("9030.33", "Instruments for testing electrical quantities", 0.0, "ITA zero duty"),
"insulation tape": ("3919.10", "Self-adhesive plastic tape", 0.065, "Standard rate"),
"duct tape": ("3919.10", "Self-adhesive tape", 0.065, "Standard rate"),
"painters tape": ("4811.41", "Adhesive paper and tape", 0.0, "Standard rate"),
"velcro": ("5807.90", "Labels and badges, textile", 0.12, "Textile rate"),
"zipper": ("9607.11", "Slide fasteners, with chain of zinc", 0.0, "Standard rate"),
"button": ("9606.21", "Buttons of plastics", 0.0, "Standard rate"),
"snap": ("9606.30", "Button moulds and other parts", 0.0, "Standard rate"),
"buckle": ("9607.20", "Slide fastener parts", 0.0, "Standard rate"),
}
def guess_hs_code(description: str) -> str:
"""Guess HS code from item description using keyword matching.
Uses a comprehensive database of 300+ product categories.
Returns (hs_code, matched_keyword) or ("9999.99", None) if no match.
"""
desc_lower = description.lower()
# Try exact keyword matches first (most specific)
best_match = None
best_match_len = 0
for keyword, (hs_code, desc, duty, notes) in HS_CODE_DATABASE.items():
if keyword in desc_lower:
# Prefer longer, more specific matches
if len(keyword) > best_match_len:
best_match = (hs_code, desc, duty, notes, keyword)
best_match_len = len(keyword)
if best_match:
return best_match[0]
# Default: unknown
return "9999.99"
async def classify_single_item(item: ItemInput, destination: str) -> ItemClassification:
"""Classify a single item with HS code and duty calculation."""
# Guess HS code from description
hs_code = guess_hs_code(item.description)
# Look up duty rate and description from database
matched = None
desc_lower = item.description.lower()
for keyword, (code, desc, duty, notes) in HS_CODE_DATABASE.items():
if keyword in desc_lower and code == hs_code:
matched = (code, desc, duty, notes)
break
if matched:
taric_desc = matched[1]
duty_rate = matched[2]
notes = matched[3]
else:
# Unknown product — use TARIC API for description, default rate
taric_info = await fetch_taric_description(hs_code)
taric_desc = taric_info.get("description", "Unknown product")
duty_rate = DEFAULT_DUTY_RATE
notes = "Unknown product, using default duty rate"
# Calculate values
customs_value = item.quantity * item.unit_price_usd
duty_amount = customs_value * duty_rate
vat_rate = DEFAULT_VAT_RATE
vat_amount = (customs_value + duty_amount) * vat_rate
total_landed = customs_value + duty_amount + vat_amount
return ItemClassification(
description=item.description,
hs_code=hs_code,
taric_description=taric_desc[:100],
origin=item.origin_country,
customs_value=round(customs_value, 2),
duty_rate=duty_rate,
duty_amount=round(duty_amount, 2),
vat_rate=vat_rate,
vat_amount=round(vat_amount, 2),
total_landed_cost=round(total_landed, 2),
notes=notes,
)
# ── API Endpoint ─────────────────────────────────────────────────────
@router.post("/classify", response_model=ClassifyResponse)
async def classify_items(request: ClassifyRequest) -> ClassifyResponse:
"""Classify items with HS codes and calculate duties.
Accepts a list of items with descriptions, quantities, and prices.
Returns HS code classifications, duty rates, and total landed costs.
"""
logger.info(f"Classifying {len(request.items)} items for {request.destination_country}")
classified_items = []
for item in request.items:
try:
classified = await classify_single_item(item, request.destination_country)
classified_items.append(classified)
except Exception as e:
logger.warning(f"Failed to classify item '{item.description}': {e}")
# Return fallback classification
customs_value = item.quantity * item.unit_price_usd
classified_items.append(ItemClassification(
description=item.description,
hs_code="9999.99",
taric_description="Classification failed",
origin=item.origin_country,
customs_value=round(customs_value, 2),
duty_rate=0.15,
duty_amount=round(customs_value * 0.15, 2),
vat_rate=0.19,
vat_amount=round(customs_value * 1.15 * 0.19, 2),
total_landed_cost=round(customs_value * 1.15 * 1.19, 2),
notes="Classification failed, using fallback rate",
))
# Calculate summary
total_customs = sum(item.customs_value for item in classified_items)
total_duty = sum(item.duty_amount for item in classified_items)
total_vat = sum(item.vat_amount for item in classified_items)
shipping_cost = 2500.00 # Default shipping estimate
summary = DutySummary(
customs_value=round(total_customs, 2),
total_duty=round(total_duty, 2),
total_vat=round(total_vat, 2),
shipping_cost=shipping_cost,
total_taxes_fees=round(total_duty + total_vat, 2),
total_landed_cost=round(sum(item.total_landed_cost for item in classified_items) + shipping_cost, 2),
effective_rate=round((total_duty + total_vat) / total_customs * 100, 2) if total_customs > 0 else 0,
)
return ClassifyResponse(
status="completed",
classified_at=datetime.now(timezone.utc).isoformat(),
destination_country=request.destination_country,
items=classified_items,
summary=summary,
)