浏览代码

feat preapplied package filters

n2749 1 周之前
父节点
当前提交
133bcf7c0a
共有 3 个文件被更改,包括 28 次插入1 次删除
  1. 12 0
      bom_assistant/scouting/orchestrator.py
  2. 14 0
      bom_assistant/suppliers/lcsc/category_cache.json
  3. 2 1
      docs/backlog.md

+ 12 - 0
bom_assistant/scouting/orchestrator.py

@@ -36,6 +36,17 @@ def _refresh_filtering(row: BomRow) -> None:
     }
 
 
+def _preseed_package_filter(session: BomSession, row_id: str) -> None:
+    row = get_row(session, row_id)
+    package = row.normalized_params.package
+    if not package:
+        return
+    options = [opt.get("name") for opt in row.facet_groups.get("Package", [])]
+    match = next((opt for opt in options if opt and opt.lower() == package.lower()), None)
+    if match:
+        apply_filter(session, row_id, "Package", match)
+
+
 def confirm_category(session: BomSession, row_id: str, category_id: int, category_name: str) -> BomRow:
     row = get_row(session, row_id)
     row.resolved_category_id = category_id
@@ -44,6 +55,7 @@ def confirm_category(session: BomSession, row_id: str, category_id: int, categor
     row.confirmed_pick = None
     row.state = RowState.filtering
     _refresh_filtering(row)
+    _preseed_package_filter(session, row_id)
     return row
 
 

+ 14 - 0
bom_assistant/suppliers/lcsc/category_cache.json

@@ -1054,5 +1054,19 @@
       "name": "Special Purpose Regulators",
       "id": 1024
     }
+  ],
+  "resistor||ERJ-8GEY0R00V": [
+    {
+      "name": "Chip Resistor - Surface Mount",
+      "id": 1199
+    },
+    {
+      "name": "Current Sense Resistors",
+      "id": 1336
+    },
+    {
+      "name": "Through Hole Resistors",
+      "id": 1203
+    }
   ]
 }

+ 2 - 1
docs/backlog.md

@@ -33,7 +33,7 @@
 - [x] `api/main.py` — FastAPI app entry point + exception handlers (404 for not-found, 400 for `ScoutingValidationError`)
 - [x] `POST /upload` — ingest file, return BomSession (HTMX-rendered row table)
 - [x] `GET /session/{id}/row/{row_id}/scout` — LLM category inference, HTMX-rendered candidate list (now with confirm buttons)
-- [x] `POST /session/{id}/row/{row_id}/confirm-category` — locks `resolved_category_id`/`resolved_category_name`, resets `applied_filters`, state → filtering, eagerly populates `facet_groups` + `search_results` via live LCSC calls
+- [x] `POST /session/{id}/row/{row_id}/confirm-category` — locks `resolved_category_id`/`resolved_category_name`, resets `applied_filters`, state → filtering, eagerly populates `facet_groups` + `search_results` via live LCSC calls; pre-seeds `encapValueList` from `normalized_params.package` when it exactly matches a live facet `Package` name (no match → left unfiltered, never guessed)
 - [x] `POST /session/{id}/row/{row_id}/apply-filter` — applies a Package/Manufacturer facet value to `applied_filters`, re-runs facets + search — verified live: narrows `search_results` items to the selected package/manufacturer
 - [x] `POST /session/{id}/row/{row_id}/confirm` — locks `confirmed_pick` from `search_results` by `productCode`, state → confirmed
 - [x] `bom_assistant/scouting/` — framework-agnostic orchestrator (`build_session`, `scout_row`, `confirm_category`, `apply_filter`, `confirm_pick`) backing the above
@@ -64,6 +64,7 @@
 
 ### Scouting Loop
 - [ ] Per-component param filters (Capacitance, Tolerance, Voltage Rating, ...) — facet response (`paramNameValueMap`) describes available values, but the exact request shape LCSC expects to *select* one was never captured live; wiring it blind risks a silently-broken filter. Needs another live traffic capture.
+- [ ] `Packaging` facet group (bulk/reel/tape) — same problem as param filters: `query_facets()` returns it, but no request field for *selecting* a value was ever captured (`_FILTER_DEFAULTS` in `lcsc.py` has no packaging-type key). User decision (2026-07-27): skip rather than guess a field name; revisit after a live traffic capture.
 - [ ] Pagination past page 1 of search results
 - [ ] Remove/toggle off an already-applied filter (currently additive-only within a session)
 - [ ] Retry / re-scout flow when user rejects results or picks a different category