joycecast commited on
Commit
c3ea20a
·
verified ·
1 Parent(s): 819c364

Upload 3 files

Browse files
Files changed (3) hide show
  1. HTS_list.py +8 -0
  2. app.py +17 -6
  3. hts_validator.py +24 -3
HTS_list.py CHANGED
@@ -320,3 +320,11 @@ Auto_parts_HTS_list = [
320
 
321
  # Auto Parts additional tariff codes
322
  AUTO_PARTS_301_CODES = [99039405, 99039406]
 
 
 
 
 
 
 
 
 
320
 
321
  # Auto Parts additional tariff codes
322
  AUTO_PARTS_301_CODES = [99039405, 99039406]
323
+
324
+ # Semiconductor primary HTS List (6-digit prefix match)
325
+ # Note: These overlap with Computer Parts and Aluminum HTS - requires manual review
326
+ Semiconductor_HTS_list = [
327
+ 847150, # 8471.50 - Processing units (may contain semiconductors)
328
+ 847180, # 8471.80 - Other units of ADP machines
329
+ 847330, # 8473.30 - Parts and accessories of machines of heading 84.71
330
+ ]
app.py CHANGED
@@ -9,7 +9,7 @@ from io import BytesIO
9
  import hashlib
10
  import os
11
  from hts_validator import HTSValidator, validate_dataframe, SCENARIO_SUMMARIES
12
- from HTS_list import Steel_primary_HTS_list, Aluminum_primary_HTS_list, Copper_primary_HTS_list
13
 
14
 
15
  # Page configuration
@@ -194,7 +194,7 @@ def color_indicator(val):
194
 
195
  # Indicator columns for styling
196
  INDICATOR_COLUMNS = [
197
- "Steel HTS", "Alum HTS", "Copper HTS", "Computer HTS", "Auto HTS",
198
  "Metal KW", "Alum KW", "Copper KW", "Zinc KW", "Plastics KW"
199
  ]
200
 
@@ -221,6 +221,7 @@ def results_to_dataframe(results):
221
  "Copper HTS": bool_to_symbol(r.in_copper_hts),
222
  "Computer HTS": bool_to_symbol(r.in_computer_hts),
223
  "Auto HTS": bool_to_symbol(r.in_auto_hts),
 
224
  # Keyword indicators
225
  "Metal KW": bool_to_symbol(r.has_metal_keyword),
226
  "Alum KW": bool_to_symbol(r.has_aluminum_keyword),
@@ -468,7 +469,7 @@ with tab2:
468
  "Entry Number", "Description", "Primary HTS",
469
  "Additional HTS",
470
  # HTS indicators
471
- "Steel HTS", "Alum HTS", "Copper HTS", "Computer HTS", "Auto HTS",
472
  # Keyword indicators
473
  "Metal KW", "Alum KW", "Copper KW", "Zinc KW", "Plastics KW",
474
  # Validation
@@ -670,6 +671,7 @@ with tab2b:
670
  "Copper HTS": "first",
671
  "Computer HTS": "first",
672
  "Auto HTS": "first",
 
673
  # Keyword indicators
674
  "Metal KW": "first",
675
  "Alum KW": "first",
@@ -739,7 +741,7 @@ with tab2b:
739
  display_cols = [
740
  "Primary HTS", "Description", "Additional HTS",
741
  # HTS indicators
742
- "Steel HTS", "Alum HTS", "Copper HTS", "Computer HTS", "Auto HTS",
743
  # Keyword indicators
744
  "Metal KW", "Alum KW", "Copper KW", "Zinc KW", "Plastics KW",
745
  # Validation
@@ -958,7 +960,7 @@ with tab4:
958
  # Tab 5: HTS Reference
959
  with tab5:
960
  st.header("HTS Reference Lists")
961
- st.markdown("Reference lists of Steel, Aluminum, and Copper HTS codes used for validation")
962
 
963
  # Search filter
964
  hts_search = st.text_input(
@@ -967,7 +969,7 @@ with tab5:
967
  key="hts_reference_search"
968
  )
969
 
970
- col1, col2, col3 = st.columns(3)
971
 
972
  with col1:
973
  st.subheader(f"Steel HTS ({len(Steel_primary_HTS_list)})")
@@ -993,6 +995,15 @@ with tab5:
993
  copper_df = pd.DataFrame({"Copper HTS": copper_list})
994
  st.dataframe(copper_df, use_container_width=True, height=400)
995
 
 
 
 
 
 
 
 
 
 
996
  # Show overlap info
997
  st.subheader("HTS Overlap Analysis")
998
  steel_set = set(str(h) for h in Steel_primary_HTS_list)
 
9
  import hashlib
10
  import os
11
  from hts_validator import HTSValidator, validate_dataframe, SCENARIO_SUMMARIES
12
+ from HTS_list import Steel_primary_HTS_list, Aluminum_primary_HTS_list, Copper_primary_HTS_list, Semiconductor_HTS_list
13
 
14
 
15
  # Page configuration
 
194
 
195
  # Indicator columns for styling
196
  INDICATOR_COLUMNS = [
197
+ "Steel HTS", "Alum HTS", "Copper HTS", "Computer HTS", "Auto HTS", "Semi HTS",
198
  "Metal KW", "Alum KW", "Copper KW", "Zinc KW", "Plastics KW"
199
  ]
200
 
 
221
  "Copper HTS": bool_to_symbol(r.in_copper_hts),
222
  "Computer HTS": bool_to_symbol(r.in_computer_hts),
223
  "Auto HTS": bool_to_symbol(r.in_auto_hts),
224
+ "Semi HTS": bool_to_symbol(r.in_semiconductor_hts),
225
  # Keyword indicators
226
  "Metal KW": bool_to_symbol(r.has_metal_keyword),
227
  "Alum KW": bool_to_symbol(r.has_aluminum_keyword),
 
469
  "Entry Number", "Description", "Primary HTS",
470
  "Additional HTS",
471
  # HTS indicators
472
+ "Steel HTS", "Alum HTS", "Copper HTS", "Computer HTS", "Auto HTS", "Semi HTS",
473
  # Keyword indicators
474
  "Metal KW", "Alum KW", "Copper KW", "Zinc KW", "Plastics KW",
475
  # Validation
 
671
  "Copper HTS": "first",
672
  "Computer HTS": "first",
673
  "Auto HTS": "first",
674
+ "Semi HTS": "first",
675
  # Keyword indicators
676
  "Metal KW": "first",
677
  "Alum KW": "first",
 
741
  display_cols = [
742
  "Primary HTS", "Description", "Additional HTS",
743
  # HTS indicators
744
+ "Steel HTS", "Alum HTS", "Copper HTS", "Computer HTS", "Auto HTS", "Semi HTS",
745
  # Keyword indicators
746
  "Metal KW", "Alum KW", "Copper KW", "Zinc KW", "Plastics KW",
747
  # Validation
 
960
  # Tab 5: HTS Reference
961
  with tab5:
962
  st.header("HTS Reference Lists")
963
+ st.markdown("Reference lists of Steel, Aluminum, Copper, and Semiconductor HTS codes used for validation")
964
 
965
  # Search filter
966
  hts_search = st.text_input(
 
969
  key="hts_reference_search"
970
  )
971
 
972
+ col1, col2, col3, col4 = st.columns(4)
973
 
974
  with col1:
975
  st.subheader(f"Steel HTS ({len(Steel_primary_HTS_list)})")
 
995
  copper_df = pd.DataFrame({"Copper HTS": copper_list})
996
  st.dataframe(copper_df, use_container_width=True, height=400)
997
 
998
+ with col4:
999
+ st.subheader(f"Semiconductor HTS ({len(Semiconductor_HTS_list)})")
1000
+ semi_list = [str(h) for h in Semiconductor_HTS_list]
1001
+ if hts_search:
1002
+ semi_list = [h for h in semi_list if hts_search in h]
1003
+ semi_df = pd.DataFrame({"Semiconductor HTS": semi_list})
1004
+ st.dataframe(semi_df, use_container_width=True, height=400)
1005
+ st.caption("Note: Overlaps with Computer Parts and Aluminum HTS")
1006
+
1007
  # Show overlap info
1008
  st.subheader("HTS Overlap Analysis")
1009
  steel_set = set(str(h) for h in Steel_primary_HTS_list)
hts_validator.py CHANGED
@@ -16,7 +16,7 @@ import re
16
  from typing import Dict, List, Optional, Tuple, Set
17
  from dataclasses import dataclass
18
  from HTS_list import (Steel_primary_HTS_list, Aluminum_primary_HTS_list, Copper_primary_HTS_list,
19
- Computer_parts_HTS_list, Auto_parts_HTS_list)
20
 
21
 
22
  # Key Additional HTS codes
@@ -42,6 +42,7 @@ SCENARIO_SUMMARIES = {
42
  # Level 1: Special HTS
43
  "C1": "Computer Parts HTS - FLAG for manual review",
44
  "A1": "Auto Parts HTS - FLAG for manual review",
 
45
  # Level 2: Dual HTS - Steel + Aluminum
46
  "D1": "Steel+Alum HTS, no keyword - FLAG",
47
  "D2": "Steel+Alum HTS + metal keyword - Steel 232 + 99030133",
@@ -130,6 +131,7 @@ class ValidationResult:
130
  in_copper_hts: bool = False
131
  in_computer_hts: bool = False
132
  in_auto_hts: bool = False
 
133
  # Keyword indicators
134
  has_metal_keyword: bool = False
135
  has_aluminum_keyword: bool = False
@@ -172,6 +174,7 @@ class HTSValidator:
172
  self.copper_hts_set = self._convert_hts_list(Copper_primary_HTS_list)
173
  self.computer_parts_hts_set = self._convert_hts_list(Computer_parts_HTS_list)
174
  self.auto_parts_hts_set = self._convert_hts_list(Auto_parts_HTS_list)
 
175
 
176
  def _convert_hts_list(self, hts_list: List) -> Set[str]:
177
  """Convert HTS list to set of strings"""
@@ -266,6 +269,7 @@ class HTSValidator:
266
  in_copper = self._hts_matches_list(primary_str, self.copper_hts_set)
267
  in_computer_parts = self._hts_matches_list(primary_str, self.computer_parts_hts_set)
268
  in_auto_parts = self._hts_matches_list(primary_str, self.auto_parts_hts_set)
 
269
 
270
  # Check description keywords
271
  has_metal_kw = self._contains_keywords(desc, self.metal_keywords)
@@ -295,6 +299,7 @@ class HTSValidator:
295
  in_copper=in_copper,
296
  in_computer_parts=in_computer_parts,
297
  in_auto_parts=in_auto_parts,
 
298
  has_metal_kw=has_metal_kw,
299
  has_aluminum_kw=has_aluminum_kw,
300
  has_copper_kw=has_copper_kw,
@@ -316,7 +321,7 @@ class HTSValidator:
316
  flag_reason: str = "",
317
  # Indicators
318
  in_steel: bool = False, in_aluminum: bool = False, in_copper: bool = False,
319
- in_computer: bool = False, in_auto: bool = False,
320
  has_metal_kw: bool = False, has_aluminum_kw: bool = False,
321
  has_copper_kw: bool = False, has_zinc_kw: bool = False,
322
  has_plastics_kw: bool = False) -> ValidationResult:
@@ -344,6 +349,7 @@ class HTSValidator:
344
  in_copper_hts=in_copper,
345
  in_computer_hts=in_computer,
346
  in_auto_hts=in_auto,
 
347
  has_metal_keyword=has_metal_kw,
348
  has_aluminum_keyword=has_aluminum_kw,
349
  has_copper_keyword=has_copper_kw,
@@ -417,6 +423,7 @@ class HTSValidator:
417
  in_copper_hts=in_copper,
418
  in_computer_hts=in_computer,
419
  in_auto_hts=in_auto,
 
420
  has_metal_keyword=has_metal_kw,
421
  has_aluminum_keyword=has_aluminum_kw,
422
  has_copper_keyword=has_copper_kw,
@@ -427,7 +434,7 @@ class HTSValidator:
427
  def _apply_validation_rules(self, entry_number: str, description: str,
428
  primary_hts: str, additional_hts: List[str],
429
  in_steel: bool, in_aluminum: bool, in_copper: bool,
430
- in_computer_parts: bool, in_auto_parts: bool,
431
  has_metal_kw: bool, has_aluminum_kw: bool,
432
  has_copper_kw: bool, has_zinc_kw: bool,
433
  has_plastics_kw: bool, has_steel_232: bool,
@@ -443,6 +450,7 @@ class HTSValidator:
443
  "in_copper": in_copper,
444
  "in_computer": in_computer_parts,
445
  "in_auto": in_auto_parts,
 
446
  "has_metal_kw": has_metal_kw,
447
  "has_aluminum_kw": has_aluminum_kw,
448
  "has_copper_kw": has_copper_kw,
@@ -556,6 +564,18 @@ class HTSValidator:
556
  flag_reason="Auto parts HTS - manual review required"
557
  )
558
 
 
 
 
 
 
 
 
 
 
 
 
 
559
  # =====================================================================
560
  # LEVEL 2: Dual HTS Categories
561
  # =====================================================================
@@ -1122,6 +1142,7 @@ class HTSValidator:
1122
  in_copper_hts=in_copper,
1123
  in_computer_hts=in_computer_parts,
1124
  in_auto_hts=in_auto_parts,
 
1125
  has_metal_keyword=has_metal_kw,
1126
  has_aluminum_keyword=has_aluminum_kw,
1127
  has_copper_keyword=has_copper_kw,
 
16
  from typing import Dict, List, Optional, Tuple, Set
17
  from dataclasses import dataclass
18
  from HTS_list import (Steel_primary_HTS_list, Aluminum_primary_HTS_list, Copper_primary_HTS_list,
19
+ Computer_parts_HTS_list, Auto_parts_HTS_list, Semiconductor_HTS_list)
20
 
21
 
22
  # Key Additional HTS codes
 
42
  # Level 1: Special HTS
43
  "C1": "Computer Parts HTS - FLAG for manual review",
44
  "A1": "Auto Parts HTS - FLAG for manual review",
45
+ "SC1": "Semiconductor HTS - FLAG for manual review (overlaps Computer/Aluminum)",
46
  # Level 2: Dual HTS - Steel + Aluminum
47
  "D1": "Steel+Alum HTS, no keyword - FLAG",
48
  "D2": "Steel+Alum HTS + metal keyword - Steel 232 + 99030133",
 
131
  in_copper_hts: bool = False
132
  in_computer_hts: bool = False
133
  in_auto_hts: bool = False
134
+ in_semiconductor_hts: bool = False
135
  # Keyword indicators
136
  has_metal_keyword: bool = False
137
  has_aluminum_keyword: bool = False
 
174
  self.copper_hts_set = self._convert_hts_list(Copper_primary_HTS_list)
175
  self.computer_parts_hts_set = self._convert_hts_list(Computer_parts_HTS_list)
176
  self.auto_parts_hts_set = self._convert_hts_list(Auto_parts_HTS_list)
177
+ self.semiconductor_hts_set = self._convert_hts_list(Semiconductor_HTS_list)
178
 
179
  def _convert_hts_list(self, hts_list: List) -> Set[str]:
180
  """Convert HTS list to set of strings"""
 
269
  in_copper = self._hts_matches_list(primary_str, self.copper_hts_set)
270
  in_computer_parts = self._hts_matches_list(primary_str, self.computer_parts_hts_set)
271
  in_auto_parts = self._hts_matches_list(primary_str, self.auto_parts_hts_set)
272
+ in_semiconductor = self._hts_matches_list(primary_str, self.semiconductor_hts_set)
273
 
274
  # Check description keywords
275
  has_metal_kw = self._contains_keywords(desc, self.metal_keywords)
 
299
  in_copper=in_copper,
300
  in_computer_parts=in_computer_parts,
301
  in_auto_parts=in_auto_parts,
302
+ in_semiconductor=in_semiconductor,
303
  has_metal_kw=has_metal_kw,
304
  has_aluminum_kw=has_aluminum_kw,
305
  has_copper_kw=has_copper_kw,
 
321
  flag_reason: str = "",
322
  # Indicators
323
  in_steel: bool = False, in_aluminum: bool = False, in_copper: bool = False,
324
+ in_computer: bool = False, in_auto: bool = False, in_semiconductor: bool = False,
325
  has_metal_kw: bool = False, has_aluminum_kw: bool = False,
326
  has_copper_kw: bool = False, has_zinc_kw: bool = False,
327
  has_plastics_kw: bool = False) -> ValidationResult:
 
349
  in_copper_hts=in_copper,
350
  in_computer_hts=in_computer,
351
  in_auto_hts=in_auto,
352
+ in_semiconductor_hts=in_semiconductor,
353
  has_metal_keyword=has_metal_kw,
354
  has_aluminum_keyword=has_aluminum_kw,
355
  has_copper_keyword=has_copper_kw,
 
423
  in_copper_hts=in_copper,
424
  in_computer_hts=in_computer,
425
  in_auto_hts=in_auto,
426
+ in_semiconductor_hts=in_semiconductor,
427
  has_metal_keyword=has_metal_kw,
428
  has_aluminum_keyword=has_aluminum_kw,
429
  has_copper_keyword=has_copper_kw,
 
434
  def _apply_validation_rules(self, entry_number: str, description: str,
435
  primary_hts: str, additional_hts: List[str],
436
  in_steel: bool, in_aluminum: bool, in_copper: bool,
437
+ in_computer_parts: bool, in_auto_parts: bool, in_semiconductor: bool,
438
  has_metal_kw: bool, has_aluminum_kw: bool,
439
  has_copper_kw: bool, has_zinc_kw: bool,
440
  has_plastics_kw: bool, has_steel_232: bool,
 
450
  "in_copper": in_copper,
451
  "in_computer": in_computer_parts,
452
  "in_auto": in_auto_parts,
453
+ "in_semiconductor": in_semiconductor,
454
  "has_metal_kw": has_metal_kw,
455
  "has_aluminum_kw": has_aluminum_kw,
456
  "has_copper_kw": has_copper_kw,
 
564
  flag_reason="Auto parts HTS - manual review required"
565
  )
566
 
567
+ # SC1: Semiconductor HTS - always FLAG (overlaps with Computer Parts and Aluminum)
568
+ if in_semiconductor:
569
+ return self._create_result(
570
+ entry_number, description, primary_hts, additional_hts,
571
+ scenario_id="SC1",
572
+ expected_codes=[], forbidden_codes=set(),
573
+ additional_set=additional_set,
574
+ **indicators,
575
+ always_flag=True,
576
+ flag_reason="Semiconductor HTS - manual review required (overlaps Computer/Aluminum)"
577
+ )
578
+
579
  # =====================================================================
580
  # LEVEL 2: Dual HTS Categories
581
  # =====================================================================
 
1142
  in_copper_hts=in_copper,
1143
  in_computer_hts=in_computer_parts,
1144
  in_auto_hts=in_auto_parts,
1145
+ in_semiconductor_hts=in_semiconductor,
1146
  has_metal_keyword=has_metal_kw,
1147
  has_aluminum_keyword=has_aluminum_kw,
1148
  has_copper_keyword=has_copper_kw,