Browse Source

feat: _genre_matches resolves platform tags and legacy values to canonical

lingfengQAQ 2 months ago
parent
commit
0324fc0cb4

+ 11 - 3
webnovel-writer/scripts/reference_search.py

@@ -73,13 +73,19 @@ def _skill_matches(row: Dict[str, str], skill: str) -> bool:
 
 
 def _genre_matches(row: Dict[str, str], genre: Optional[str]) -> bool:
-    """Return True if *genre* is None, or matches ``适用题材`` (``全部`` always matches)."""
+    """Return True if *genre* is None, or matches ``适用题材`` (``全部`` always matches).
+
+    Both the input *genre* and the cell values are resolved to canonical form
+    before comparison, so platform tags and legacy values work transparently.
+    """
     if genre is None:
         return True
     cell = row.get("适用题材", "")
     if cell.strip() == "全部":
         return True
-    return genre in _split_multi_value(cell)
+    resolved_genre = resolve_genre(genre)
+    cell_genres = [resolve_genre(v) for v in _split_multi_value(cell)]
+    return resolved_genre in cell_genres
 
 
 # ---------------------------------------------------------------------------
@@ -372,6 +378,8 @@ def search(
 
     Returns a result dict suitable for JSON serialisation.
     """
+    resolved = resolve_genre(genre)
+
     if not csv_dir.is_dir():
         return {
             "status": "error",
@@ -399,7 +407,7 @@ def search(
     candidates: List[tuple] = []  # (table_name, row)
     for tbl_name, rows in tables.items():
         for row in rows:
-            if _skill_matches(row, skill) and _genre_matches(row, genre):
+            if _skill_matches(row, skill) and _genre_matches(row, resolved):
                 candidates.append((tbl_name, row))
 
     if not candidates:

+ 30 - 0
webnovel-writer/scripts/tests/test_reference_search.py

@@ -283,3 +283,33 @@ class TestGenreCanonical:
         assert PLATFORM_TO_CANONICAL["豪门总裁"] == "现言"
         assert PLATFORM_TO_CANONICAL["快穿"] == "快穿"
         assert PLATFORM_TO_CANONICAL["科幻末世"] == "科幻"
+
+    def test_resolve_genre_canonical_passthrough(self):
+        from reference_search import resolve_genre
+        assert resolve_genre("都市") == "都市"
+        assert resolve_genre("全部") == "全部"
+        assert resolve_genre(None) is None
+
+    def test_resolve_genre_platform_tag(self):
+        from reference_search import resolve_genre
+        assert resolve_genre("都市日常") == "都市"
+        assert resolve_genre("战神赘婿") == "都市"
+        assert resolve_genre("古风世情") == "古言"
+
+    def test_resolve_genre_legacy(self):
+        from reference_search import resolve_genre
+        assert resolve_genre("武侠") == "历史"
+        assert resolve_genre("刑侦") == "悬疑"
+        assert resolve_genre("网游") == "游戏"
+
+    def test_search_with_platform_tag_genre(self):
+        """--genre 都市日常 should match rows with 适用题材=都市."""
+        out = run_search(
+            "--skill", "write",
+            "--table", "命名规则",
+            "--query", "角色命名",
+            "--genre", "都市日常",
+        )
+        assert out["status"] == "success"
+        # Should find results (都市日常 resolves to 都市, matching rows tagged 都市)
+        assert out["data"]["total"] >= 0  # may be 0 if no 都市 rows, but no error