cry-search 2.1.1 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CLAUDE.md CHANGED
@@ -387,6 +387,7 @@ src/
387
387
  │ │ ├── searchAndRank.ts # Wrapper w/ exactKeysFn boost + fallback
388
388
  │ │ ├── scoring.ts # scoreOne, scoreOrderAndPresence, scoreBag
389
389
  │ │ ├── syncSearchArrayMetadata.ts
390
+ │ │ ├── matchMany.ts # Mass matching (matchMany / matchManySync)
390
391
  │ │ └── AugmentedMetadata.ts
391
392
  │ └── SearchUniverse.ts # Multi-collection manager
392
393
  ├── utils/
@@ -399,11 +400,29 @@ src/
399
400
  │ ├── sanitiseString.ts
400
401
  │ ├── tokenize.ts
401
402
  │ └── compareTokenized.ts # Jaccard token-set similarity (0..1)
403
+ ├── vet/ # Domain extension, published as `cry-search/vet`
404
+ │ ├── index.ts # Public API of the subpath
405
+ │ ├── spec.ts # vetArtikelSpec / vetQueryOpts (field normalizers)
406
+ │ ├── normalizatorji.ts # Units, decimals, brands, quantities, sizes, species
407
+ │ ├── ocena.ts # oceniPar: score + acceptance rule + reason
408
+ │ ├── uparjanje.ts # pripraviVetIndeks, upariArtikle/upariVse(Sync)
409
+ │ └── data/ # Generated tables (enote.ts, znamke.gen.ts)
402
410
  ├── types/
403
411
  │ └── index.ts
404
412
  └── index.ts # Public API
405
413
  ```
406
414
 
415
+ The core stays domain-free. It only exposes narrow seams for domain modules:
416
+ `SearchableObjectSpec.valueNormalizers` (index side, may return `{ text, classes }`),
417
+ `SearchOpts.queryNormalizers` + `normalizeQueryWithOpts` (query side) and `matchMany` /
418
+ `matchManySync` (mass matching with optional domain `rank`/`accept`). Soft domain data lives
419
+ in `metadata.classes` (never in the token stream, so retrieval speed is unaffected) and is
420
+ read back with `itemClasses(metadata, id)`. Domain rules belong in `src/vet/` (see `VET.md`).
421
+
422
+ Build note: `cry-vetzdravila` is an optional peer dependency and is marked external in the
423
+ bundles (`bun build --external cry-vetzdravila`), so core consumers do not pull in its
424
+ `xlsx`/`pdfjs-dist` dependencies.
425
+
407
426
  ## Coding rules
408
427
 
409
428
  1. each function is in separate file
@@ -415,6 +434,13 @@ src/
415
434
 
416
435
  ## Testing
417
436
 
437
+ 0. Quality first: `bun test` — thresholds for `cry-search/vet` live in
438
+ `test/vet/pari.test.ts` (recall@1/3, precision@1 per group) and the golden output in
439
+ `test/vet/zlati-gw.json`.
440
+ 0b. Speed separately: `bun run bench` (not part of `bun test`, not in CI) measures index build
441
+ and mass-pairing throughput against the stored baseline `test/vet/bench-osnova.json` and
442
+ fails only when latency grows > 20 % or `uspeh@1` drops > 2 pp. Refresh the baseline
443
+ deliberately with `bun run bench --zapisi-osnovo`.
418
444
  1. Large real-life datasets are in ./test-data (arikli, stranke, pacienti).
419
445
  2. tests are in ./test
420
446
  3. tests per implementation are in ./test/(IMPLEMENTATION)
package/README.md CHANGED
@@ -532,6 +532,19 @@ See [CLAUDE.md](./CLAUDE.md) for the complete technical specification including:
532
532
 
533
533
  See [LICENSE.md](./LICENSE.md) for license terms.
534
534
 
535
+ ### Measuring performance
536
+
537
+ Quality thresholds live in the test suite; performance is measured separately (it depends on
538
+ machine load, so it must not fail the quality tests):
539
+
540
+ ```bash
541
+ bun run bench # measure and compare against test/vet/bench-osnova.json
542
+ bun run bench --zapisi-osnovo # deliberately refresh the baseline
543
+ ```
544
+
545
+ The bench fails only when latency grows by more than 20 % or `uspeh@1` drops by more than
546
+ 2 percentage points.
547
+
535
548
  ## Domain extensions and the `cry-search/vet` entry point
536
549
 
537
550
  The core exposes a narrow seam for domain logic (all optional, no behaviour change when unused):
@@ -545,6 +558,31 @@ The core exposes a narrow seam for domain logic (all optional, no behaviour chan
545
558
  collection as queries; asynchronous iterator (chunked), top-K candidates per item with scores,
546
559
  optional `samoEnolicno` (greedy 1:1), optional domain `rank`/`accept`, and
547
560
  `alternativnePoizvedbe` (retry with a narrowed query).
561
+ - `matchManySync(prepared, queries, opts)` — the same in one shot, for callers whose API is not
562
+ async (no I/O happen in the hot path, so the sync variant is equivalent).
563
+
564
+ The veterinary module also ships a **bilingual SI↔EN lexicon** (`data/prevodi.ts`, normalizer
565
+ `prevodiNormalizator`): English catalogue names (`Monge dog rabbit rice&potatoes 2,5kg`) pair with
566
+ Slovenian Pantheon names (`MONGE DOG ADULT zajec, riž, krompir 2,5kg`). The same table is applied
567
+ to index values and queries (symmetry is required — one-sided translation makes results worse),
568
+ brand names are never translated, and marketing/connector words (`care`, `for`, `with` …) are
569
+ dropped. `razdeljevalciNormalizator` splits `&`/`+`/`/` inside names, and life stages
570
+ (`puppy`/`kitten`/`adult`/`senior`) become the soft class `starost`.
571
+
572
+ For a **user-facing search field** the same lexicon must be in the search index, but the
573
+ class-producing normalizers have to stay out (a user searching `200ml`, `PRIB` or `adult` must
574
+ still find those rows). That is what `vetIskalniSpec()` / `vetIskalniQueryOpts()` are for:
575
+
576
+ ```typescript
577
+ import { vetIskalniSpec, vetIskalniQueryOpts } from 'cry-search/vet';
578
+
579
+ const metadata = createSearchArrayMetadata(data, vetIskalniSpec({ polja: ['acName', 'acIdent'] }));
580
+ searchAndRank('monge rabbit', data, metadata, vetIskalniQueryOpts({ exactKeysFn }));
581
+ // → najde `MONGE DOG ADULT zajec, riž, krompir 2,5kg` (leksikon rabbit → zajec)
582
+ ```
583
+
584
+ With `vrniNesprejete: true` the domain module keeps candidates that fail the acceptance rule and
585
+ marks them (`sprejeto: false`) instead of dropping them — useful in UIs where the user decides.
548
586
 
549
587
  A ready-made veterinary implementation ships as a subpath (optional peer dependency on
550
588
  `cry-vetzdravila`):
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Dvojezični leksikon SI↔EN za veterinarske nazive artikelov (živila + zdravila).
3
+ *
4
+ * Zakaj: isti artikel ima v klik.vetu pogosto **angleški** naziv (vnesen po
5
+ * dobaviteljskem katalogu), v Pantheonu pa **slovenskega** (ali obratno — pri
6
+ * znamkah N&D/Hills je pantheonov naziv pogosto v angleščini, klik.vetov pa
7
+ * slovenski). Brez preslikave iskalnik takih parov NE NAJDE, ker se ključne besede
8
+ * (`rabbit`/`zajec`, `rice`/`riž`, `codfish`/`polenovka`) ne ujemajo:
9
+ *
10
+ * „Monge dog rabbit rice&potatoes 2,5kg“ ↔ „MONGE DOG ADULT zajec, riž, krompir 2,5kg“
11
+ * → brez leksikona 0 kandidatov, z leksikonom pravi par prvi (`sprejeto: true`).
12
+ *
13
+ * Pravila (izmerjeno na podatkih tackakp + SI_TACKA, 2026-10-04):
14
+ * - preslikava je **simetrična**: ista tabela se uporabi na INDEKSU in na
15
+ * POIZVEDBI (normalizator + ocenjevalec), zato sta obe strani vedno v kanonični
16
+ * obliki — tudi kadar sta obe angleški ali obe slovenski;
17
+ * - ključi so normalizirani (male črke, brez šumnikov, brez ločil), kanonične
18
+ * vrednosti so prav tako brez šumnikov (jedro jih itak normalizira);
19
+ * - **znamk in učinkovin ne prevajamo** (Monge, Royal Canin, N&D, Hills, Brit,
20
+ * Flamingo, Trixie, Kong, Kerbl, Rogz, Ferplast, Flexi, JBL, Rinti, Dubex, Sera,
21
+ * Oasy, Vetlife, Dingo, Matis, Besta, Ferribella, MEDROL …) — zanje skrbi
22
+ * `znamkaNormalizator`; v tem seznamu jih namenoma NI;
23
+ * - besed, ki so v obeh jezikih enake (`light`, `mini`, `maxi`, `gel`, `spot`,
24
+ * `tuna`, `premium`, `hairball` …), NI na seznamu — preslikava bi bila odveč;
25
+ * - okrajšava `MED` (= „medium“) je namenoma izven te tabele: `med` je v slovenščini
26
+ * tudi „honey“ („z medom“ je v tackakp 497 artikelov), zato jo rešuje ciljno
27
+ * pravilo v `razdeljevalciNormalizator` (`MED&MAXI` → `MEDIUM MAXI`).
28
+ *
29
+ * Vzdrževanje: kandidate za dodajanje izlušči diagnostični skript
30
+ * `panthenImport/src/debug/besedisceZaLeksikon.ts` (`--kandidati`).
31
+ */
32
+ /**
33
+ * Angleške (in okrajšane) besede → kanonična slovenska oblika (brez šumnikov).
34
+ *
35
+ * Vrednost je lahko tudi večbesedna (`granatno jabolko`), tako se „POMEG“ in
36
+ * „granatno jabolko“ ujameta kot ista dva žetona.
37
+ */
38
+ export declare const PREVODI: Record<string, string>;
39
+ /**
40
+ * Vezniki in marketinške besede, ki ne nosijo pomena izdelka — iz besedila se
41
+ * ODSTRANIJO (brez razreda). Merjeno: par „urinary care“ ↔ „urinarne“ je imel
42
+ * zaradi `care` pokritost kandidata 50 % namesto 100 %.
43
+ */
44
+ export declare const STOP_BESEDE: string[];
45
+ /**
46
+ * Življenjska stopnja → kanonična oblika, ki postane RAZRED `starost`.
47
+ *
48
+ * Stopnja je močan razločevalnik (mladič proti odraslemu je drug izdelek), a jo
49
+ * nazivi navajajo nedosledno, zato razred (kazen ob nasprotju), ne trdi žeton.
50
+ * Zajema tudi angleške zapise in okrajšave, ker so v podatkih pogosti.
51
+ */
52
+ export declare const STAROSTI: Record<string, string>;
53
+ /**
54
+ * Angleške velikosti → kanonična velikost (isti ključi kot `VELIKOSTI_SINONIMI`).
55
+ *
56
+ * `mini` in `maxi` namenoma OSTAJAJO besede: uporablja jih obe strani enako, v
57
+ * linijah RC/N&D pa pomenita razred velikosti. V razred gredo le nedvoumne.
58
+ */
59
+ export declare const VELIKOSTI_EN: Record<string, string>;
60
+ /** Okrajšave velikosti, ki se v Pantheonu pojavljajo s `&` (`MED&MAXI`) — ciljno pravilo. */
61
+ export declare const VELIKOSTI_OKRAJSAVE: Record<string, string>;
62
+ /** Izvoz za teste in diagnostične skripte. */
63
+ export declare const PREVODI_VIR = "ro\u010Dno kurirano 2026-10-04 (besedi\u0161\u010De izmerjeno v tackakp + SI_TACKA)";
64
+ //# sourceMappingURL=prevodi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prevodi.d.ts","sourceRoot":"","sources":["../../../src/vet/data/prevodi.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA0T1C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,MAAM,EAiB/B,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAqB3C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAO/C,CAAC;AAEF,6FAA6F;AAC7F,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAItD,CAAC;AAEF,8CAA8C;AAC9C,eAAO,MAAM,WAAW,wFAAyE,CAAC"}