Ecommerce Template
Next.js·React 등으로 만든 최신 전자상거래 템플릿
무료 HS 코드 조회. 모든 분류는 해당 CBP 판결에 근거하며, 판결이 없을 경우 답변을 보류합니다
Free HS code lookup. Every classification is traced to the published CBP rulings that support it, and withheld when the rulings do not support an answer.
커머스Python · CSSGitHub @ShantanuTaro접속 불안정운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기HS Code Lookup for Customs - classification traced to published CBP rulings, behind a confidence gate that withholds rather than guesses. 176,972 rulings, 1989-2026.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Find your HS code. See the rulings behind it.
Every classification traced to the published CBP rulings that support it -
and withheld outright when they don't. Free, no account.
176,972 CBP classification rulings, 1989-2026, behind one text box. Describe your goods and get
a 6-digit HS subheading with every ruling it leaned on named and linked - or a straight refusal when
the rulings don't support one. Seven dependencies, no framework, no build step, no JavaScript
framework, and a corpus you can rebuild yourself from public records.README 전문 보기 ↗Every classification traced to the published CBP rulings that support it - and withheld outright when they don't. Free, no account.
176,972 CBP classification rulings, 1989-2026, behind one text box. Describe your goods and get a 6-digit HS subheading with every ruling it leaned on named and linked - or a straight refusal when the rulings don't support one. Seven dependencies, no framework, no build step, no JavaScript framework, and a corpus you can rebuild yourself from public records.
| Answered - the code, the confidence, and neighbouring products one click away | Withheld - below threshold, and it says so |
| 176,972 ruling pages, each linked to its nearest neighbours | Live retrieval as you type - no model call, so it's free |
Every theme value is a CSS custom property with a light and a dark pair, so dark mode is a token swap that follows the OS - no toggle, no JavaScript, nothing stored.
A wrong HS code on an entry is a false statement to CBP under 19 U.S.C. §1592. Competitors publish 92-96% accuracy at the 6-digit level and stop there. Nobody sells a classification that is legally defensible: reasoning traced to specific published rulings, with a calibrated gate that declines to answer rather than guessing. The gate is the product, not a safety feature bolted onto it.
The wedge is CBP CROSS: 200,000+ public rulings, free, deep, owned by nobody, and usable as both the retrieval corpus and the eval ground truth. Being able to measure is the moat.
Transferred node-for-node from the freight exception agent, pointed at a problem where being wrong has a statutory citation attached.
| Freight agent | Here |
|---|---|
classify_exception | classify.classify |
retrieve_playbook | retrieve.search over CROSS rulings |
decide_authorization | classify.gate - answer vs. escalate |
Same machinery: a deterministic gate the model cannot talk its way past, one auto-answer threshold in one place, a labelled fallback instead of a silent one, and a threshold calibrated against measured accuracy rather than taste.
| File | Does |
|---|---|
cross.py | Crawl rulings.cbp.gov; split each ruling into description + HTS label |
retrieve.py | Hybrid dense+sparse retrieval over the corpus, RRF-fused and reranked |
classify.py | Classify against retrieved rulings, then apply the gate |
backtest.py | Held-out accuracy and the threshold calibration sweep |
app.py | Lookup page, 177k indexable ruling pages, sitemap, JSON endpoint |
test_hs.py | Leakage, gate, retrieval, seeding and sitemap checks |
static/ | The whole front end: two HTML templates, one CSS file, self-hosted fonts |
The backtest is worthless if the eval input contains its own answer. cross.extract_description
cuts each ruling at the first conclusion marker and at the first HTS code, which also removes
subheadings the importer proposed and CBP rejected. backtest.split removes the held-out rulings
from the index before anything is classified. Both are asserted in test_hs.py.
python -m venv .venv && .venv/bin/pip install -r requirements.txt
cp .env.example .env # add GROQ_API_KEY and/or MISTRAL_API_KEY
.venv/bin/python cross.py --from-year 1989 --to-year 2026 # ~177k rulings, ~2h, resumable
.venv/bin/python backtest.py --cases 500 # the kill switch
.venv/bin/python backtest.py --cases 500 --no-model # retrieval-only floor
.venv/bin/python -m pytest test_hs.py -q
.venv/bin/python -m uvicorn app:app --port 8099 # the free lookup page
The hosted instance runs on Vercel with the index in Qdrant Cloud: the embedded index is 1.1GB and
the corpus 790MB, and neither fits in a 250MB function on a read-only disk. Nothing is deployed but
the code and static/, and the app skips seeding entirely when QDRANT_URL names a populated
collection.
python seed_cloud.py # one-off: 177k points into the cluster, ~20 minutes
vercel env add QDRANT_URL production # and QDRANT_API_KEY, GROQ_API_KEY, MISTRAL_API_KEY, BASE_URL
vercel deploy --prod
Live at hs-code-lookup-dusky.vercel.app. Sitemaps are the one thing a hosted instance does not serve - they are written next to the corpus, which is not deployed.
The lookup page is one URL competing against Flexport and Avalara. The corpus is 176,972 URLs
competing against nothing: /ruling/N352926 is a real page about a real product, titled with the
long-tail phrase someone actually searches ("tariff classification of a hat, a headband and a
blanket from China"). Each one links to the six rulings nearest it in retrieval space, so the corpus
is a connected graph rather than 176,972 orphans, and each links into the lookup tool.
/sitemap.xml is an index over /sitemap-N.xml parts, because one sitemap is capped at
50,000 URLs and the corpus is well past that; robots.txt points at it and keeps /?q= lookups out of the
index, since a separate indexable page per query is how a tool becomes thin content. Set BASE_URL
in the deployment or every canonical tag will claim the pages live on localhost.
Both Groq and Mistral speak the OpenAI chat-completions dialect, so one client covers them and the
only difference is a base URL. Every key configured in .env becomes a link in a fallback chain:
all but the last give up after two retries, so a rate-limited provider costs seconds rather than the
run. Which model answered is stamped on every result and reported per-provider, because a chain is
two different models and one blended accuracy number would hide which is doing the work.
backtest.py prints ungated HS6/HS4 accuracy, retrieval recall@k (the ceiling on everything else),
and a coverage-vs-precision table across candidate thresholds. Pick the lowest threshold whose
precision clears what an entry filing needs; that number goes in classify.ANSWER_CONFIDENCE_THRESHOLD.
The corpus is indexed once and cached: data/qdrant.seed fingerprints rulings.jsonl, so a restart
re-reads neither the 790MB corpus nor the vectoriser. Only a changed corpus triggers a rebuild
(~2-5 minutes for 177k rulings).
Embedded Qdrant warns above roughly 20,000 points and this corpus is nine times that. Point it at a server when search gets slow:
docker run -d -p 6333:6333 -v "$PWD/data/qdrant-server:/qdrant/storage" qdrant/qdrant
echo 'QDRANT_URL=http://localhost:6333' >> .env
MIT - see LICENSE.
The CBP rulings themselves are US Government public records and are not covered by that licence;
rulings.jsonl is not distributed with this repository because it is 790MB and you can rebuild it
from source with cross.py. Bundled fonts (Inter, IBM Plex Mono) are SIL OFL 1.1 - see
static/fonts/.