@mailwoman/kind-classifier 7.1.0 → 7.2.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/out/classify.d.ts +15 -0
- package/out/classify.d.ts.map +1 -1
- package/out/classify.js +29 -0
- package/out/classify.js.map +1 -1
- package/out/index.d.ts +5 -2
- package/out/index.d.ts.map +1 -1
- package/out/index.js +3 -2
- package/out/index.js.map +1 -1
- package/out/poi.d.ts +41 -0
- package/out/poi.d.ts.map +1 -0
- package/out/poi.js +69 -0
- package/out/poi.js.map +1 -0
- package/package.json +5 -11
package/out/classify.d.ts
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* surfaces in `alternatives` — the caller decides whether to act on the top kind only or consider
|
|
13
13
|
* runner-ups.
|
|
14
14
|
*/
|
|
15
|
+
import { type POIPhraseLookup } from "./poi.ts";
|
|
15
16
|
import type { LocaleHint, NormalizedInputLite, QueryKindResult, QueryShapeLike } from "./types.ts";
|
|
16
17
|
/**
|
|
17
18
|
* Classify the query shape into a `QueryKind`. Synchronous + pure — produces the same result for the same `(input,
|
|
@@ -24,4 +25,18 @@ export declare function classifyKindSync(input: NormalizedInputLite, shape: Quer
|
|
|
24
25
|
* The locale parameter is accepted for future locale-aware rules (Japanese honorifics, etc.) but not currently used.
|
|
25
26
|
*/
|
|
26
27
|
export declare function classifyKind(input: NormalizedInputLite, shape: QueryShapeLike, _locale?: LocaleHint): Promise<QueryKindResult>;
|
|
28
|
+
/** Options for {@link createKindClassifier}. */
|
|
29
|
+
export interface KindClassifierOpts {
|
|
30
|
+
/**
|
|
31
|
+
* POI phrase lexicon (spec §3.1). When present, a `poi_query` scorer joins the rule set — injected, never imported,
|
|
32
|
+
* so this package stays dictionary-free. Absent → the returned classifier is behaviorally identical to
|
|
33
|
+
* {@link classifyKind}.
|
|
34
|
+
*/
|
|
35
|
+
poiLexicon?: POIPhraseLookup;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Build a kind classifier. Without opts this is exactly the default {@link classifyKind}; with a `poiLexicon` it
|
|
39
|
+
* additionally scores `poi_query` and merges it into the ranked result.
|
|
40
|
+
*/
|
|
41
|
+
export declare function createKindClassifier(opts?: KindClassifierOpts): (input: NormalizedInputLite, shape: QueryShapeLike, locale?: LocaleHint) => Promise<QueryKindResult>;
|
|
27
42
|
//# sourceMappingURL=classify.d.ts.map
|
package/out/classify.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../classify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;
|
|
1
|
+
{"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../classify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAuB,KAAK,eAAe,EAAE,MAAM,UAAU,CAAA;AAWpE,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAa,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAiB7G;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,cAAc,GAAG,eAAe,CAcnG;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CACjC,KAAK,EAAE,mBAAmB,EAC1B,KAAK,EAAE,cAAc,EACrB,OAAO,CAAC,EAAE,UAAU,GAClB,OAAO,CAAC,eAAe,CAAC,CAE1B;AAED,gDAAgD;AAChD,MAAM,WAAW,kBAAkB;IAClC;;;;OAIG;IACH,UAAU,CAAC,EAAE,eAAe,CAAA;CAC5B;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CACnC,IAAI,GAAE,kBAAuB,GAC3B,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,UAAU,KAAK,OAAO,CAAC,eAAe,CAAC,CA2BtG"}
|
package/out/classify.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* surfaces in `alternatives` — the caller decides whether to act on the top kind only or consider
|
|
13
13
|
* runner-ups.
|
|
14
14
|
*/
|
|
15
|
+
import { createScorePOIQuery } from "./poi.js";
|
|
15
16
|
import { scoreIntersection, scoreLandmark, scoreLocalityOnly, scorePoBox, scorePostcodeOnly, scoreStructuredAddress, scoreVague, scoreVenueLandmark, } from "./rules.js";
|
|
16
17
|
const SCORERS = [
|
|
17
18
|
{ kind: "po_box", score: scorePoBox },
|
|
@@ -45,4 +46,32 @@ export function classifyKindSync(input, shape) {
|
|
|
45
46
|
export async function classifyKind(input, shape, _locale) {
|
|
46
47
|
return classifyKindSync(input, shape);
|
|
47
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Build a kind classifier. Without opts this is exactly the default {@link classifyKind}; with a `poiLexicon` it
|
|
51
|
+
* additionally scores `poi_query` and merges it into the ranked result.
|
|
52
|
+
*/
|
|
53
|
+
export function createKindClassifier(opts = {}) {
|
|
54
|
+
const { poiLexicon } = opts;
|
|
55
|
+
if (!poiLexicon)
|
|
56
|
+
return classifyKind;
|
|
57
|
+
return async (input, shape, locale) => {
|
|
58
|
+
const base = classifyKindSync(input, shape);
|
|
59
|
+
const poiConfidence = createScorePOIQuery(poiLexicon, locale?.locale)(input, shape);
|
|
60
|
+
if (poiConfidence <= 0)
|
|
61
|
+
return base;
|
|
62
|
+
if (poiConfidence > base.confidence) {
|
|
63
|
+
return {
|
|
64
|
+
kind: "poi_query",
|
|
65
|
+
confidence: poiConfidence,
|
|
66
|
+
alternatives: [{ kind: base.kind, confidence: base.confidence }, ...base.alternatives],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
// The literal needs the contextual element type — a bare array literal widens `kind` to string.
|
|
70
|
+
const poiAlternative = { kind: "poi_query", confidence: poiConfidence };
|
|
71
|
+
return {
|
|
72
|
+
...base,
|
|
73
|
+
alternatives: [...base.alternatives, poiAlternative].sort((a, b) => b.confidence - a.confidence),
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
}
|
|
48
77
|
//# sourceMappingURL=classify.js.map
|
package/out/classify.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"classify.js","sourceRoot":"","sources":["../classify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACN,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,iBAAiB,EACjB,sBAAsB,EACtB,UAAU,EACV,kBAAkB,GAClB,MAAM,YAAY,CAAA;AAQnB,MAAM,OAAO,GAA8B;IAC1C,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE;IACrC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;IAC9F,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,iBAAiB,EAAE;IAClD,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,iBAAiB,EAAE;IACnD,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,iBAAiB,EAAE;IACnD,EAAE,IAAI,EAAE,oBAAoB,EAAE,KAAK,EAAE,sBAAsB,EAAE;IAC7D,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE;CACpC,CAAA;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAA0B,EAAE,KAAqB;IACjF,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAC9F,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CACvB,CAAA;IACD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC,CAAA;IAElD,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,OAAoB,EAAE,UAAU,EAAE,GAAG,EAAE,CAAA;IACxE,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAA;IAE7F,OAAO;QACN,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,YAAY;KACZ,CAAA;AACF,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CACjC,KAA0B,EAC1B,KAAqB,EACrB,OAAoB;IAEpB,OAAO,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;AACtC,CAAC"}
|
|
1
|
+
{"version":3,"file":"classify.js","sourceRoot":"","sources":["../classify.ts"],"names":[],"mappings":"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"}
|
package/out/index.d.ts
CHANGED
|
@@ -5,14 +5,17 @@
|
|
|
5
5
|
*
|
|
6
6
|
* `@mailwoman/kind-classifier` — Stage 2.5 of the runtime pipeline.
|
|
7
7
|
*
|
|
8
|
-
* Categorize inputs into one of
|
|
8
|
+
* Categorize inputs into one of eight `QueryKind`s by composing rule-based scorers over the
|
|
9
9
|
* QueryShape sub-system's output. Pure functions, no ML, no place-name dictionaries. Returns
|
|
10
10
|
* possibilities (alternatives) alongside the top pick so the coordinator can fall back when the
|
|
11
11
|
* winning kind isn't actionable.
|
|
12
12
|
*
|
|
13
13
|
* See `docs/articles/plan/reference/STAGES.md` § Stage 2.5 for the contract.
|
|
14
14
|
*/
|
|
15
|
-
export { classifyKind, classifyKindSync } from "./classify.ts";
|
|
15
|
+
export { classifyKind, classifyKindSync, createKindClassifier } from "./classify.ts";
|
|
16
|
+
export type { KindClassifierOpts } from "./classify.ts";
|
|
17
|
+
export { matchPOISubject } from "./poi.ts";
|
|
18
|
+
export type { POIPhraseMatch, POIPhraseLookup, POISubjectMatch } from "./poi.ts";
|
|
16
19
|
export { scoreIntersection, scoreLandmark, scoreLocalityOnly, scorePoBox, scorePostcodeOnly, scoreStructuredAddress, scoreVague, } from "./rules.ts";
|
|
17
20
|
export type { LocaleHint, NormalizedInputLite, QueryKind, QueryKindResult, QueryShapeLike } from "./types.ts";
|
|
18
21
|
//# sourceMappingURL=index.d.ts.map
|
package/out/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AACpF,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC1C,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAChF,OAAO,EACN,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,iBAAiB,EACjB,sBAAsB,EACtB,UAAU,GACV,MAAM,YAAY,CAAA;AACnB,YAAY,EAAE,UAAU,EAAE,mBAAmB,EAAE,SAAS,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA"}
|
package/out/index.js
CHANGED
|
@@ -5,13 +5,14 @@
|
|
|
5
5
|
*
|
|
6
6
|
* `@mailwoman/kind-classifier` — Stage 2.5 of the runtime pipeline.
|
|
7
7
|
*
|
|
8
|
-
* Categorize inputs into one of
|
|
8
|
+
* Categorize inputs into one of eight `QueryKind`s by composing rule-based scorers over the
|
|
9
9
|
* QueryShape sub-system's output. Pure functions, no ML, no place-name dictionaries. Returns
|
|
10
10
|
* possibilities (alternatives) alongside the top pick so the coordinator can fall back when the
|
|
11
11
|
* winning kind isn't actionable.
|
|
12
12
|
*
|
|
13
13
|
* See `docs/articles/plan/reference/STAGES.md` § Stage 2.5 for the contract.
|
|
14
14
|
*/
|
|
15
|
-
export { classifyKind, classifyKindSync } from "./classify.js";
|
|
15
|
+
export { classifyKind, classifyKindSync, createKindClassifier } from "./classify.js";
|
|
16
|
+
export { matchPOISubject } from "./poi.js";
|
|
16
17
|
export { scoreIntersection, scoreLandmark, scoreLocalityOnly, scorePoBox, scorePostcodeOnly, scoreStructuredAddress, scoreVague, } from "./rules.js";
|
|
17
18
|
//# sourceMappingURL=index.js.map
|
package/out/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AAEpF,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE1C,OAAO,EACN,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,iBAAiB,EACjB,sBAAsB,EACtB,UAAU,GACV,MAAM,YAAY,CAAA"}
|
package/out/poi.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* POI subject detection for the `poi_query` kind. The lexicon is INJECTED (`POIPhraseLookup`) —
|
|
7
|
+
* this package keeps its bitter-lesson invariant (no dictionaries in-tree); the phrase table
|
|
8
|
+
* lives in `@mailwoman/poi-taxonomy` and is wired in by `createRuntimePipeline` behind the
|
|
9
|
+
* default-OFF `poiQueryKind` flag. Spec §3.1.
|
|
10
|
+
*/
|
|
11
|
+
import type { NormalizedInputLite, QueryShapeLike } from "./types.ts";
|
|
12
|
+
/** One lexicon hit for a candidate subject phrase. */
|
|
13
|
+
export interface POIPhraseMatch {
|
|
14
|
+
categoryID: string;
|
|
15
|
+
matchedPhrase: string;
|
|
16
|
+
confidence: number;
|
|
17
|
+
}
|
|
18
|
+
/** Injected phrase→category lookup. Exact-phrase, locale-aware; returns [] on miss. */
|
|
19
|
+
export type POIPhraseLookup = (phrase: string, locale?: string) => ReadonlyArray<POIPhraseMatch>;
|
|
20
|
+
export interface POISubjectMatch {
|
|
21
|
+
match: POIPhraseMatch;
|
|
22
|
+
/** The matched subject text as it appeared in the query. */
|
|
23
|
+
subject: string;
|
|
24
|
+
/** The anchor remainder after the separator; `""` when the whole input matched. */
|
|
25
|
+
remainder: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Match a POI subject: the whole input, or the text before the FIRST anchor separator WHOSE PREFIX HITS THE LEXICON (≤
|
|
29
|
+
* 4 tokens). Scans separator occurrences left-to-right — a lexicon phrase may itself contain a bare separator word
|
|
30
|
+
* (e.g. "walk in clinic"), so the first separator isn't necessarily the right split point. Returns null when the
|
|
31
|
+
* lexicon never fires — including comma-ridden full addresses whose leading segment isn't a lexicon phrase.
|
|
32
|
+
*/
|
|
33
|
+
export declare function matchPOISubject(text: string, locale: string | undefined, lookup: POIPhraseLookup): POISubjectMatch | null;
|
|
34
|
+
/**
|
|
35
|
+
* `poi_query` scorer over an injected lexicon. Confidence bands: whole-input lexicon hit 0.92 (above venue-landmark's
|
|
36
|
+
* 0.88 ceiling — an exact lexicon phrase beats a shape heuristic); subject + anchor 0.9. Guards below keep venue-led
|
|
37
|
+
* FULL addresses (class 2) on the structured-address path: a remainder that leads with a house number, or a 4+-segment
|
|
38
|
+
* input, scores 0 here.
|
|
39
|
+
*/
|
|
40
|
+
export declare function createScorePOIQuery(lookup: POIPhraseLookup, locale?: string): (input: NormalizedInputLite, shape: QueryShapeLike) => number;
|
|
41
|
+
//# sourceMappingURL=poi.d.ts.map
|
package/out/poi.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"poi.d.ts","sourceRoot":"","sources":["../poi.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAErE,sDAAsD;AACtD,MAAM,WAAW,cAAc;IAC9B,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,MAAM,CAAA;CAClB;AAED,uFAAuF;AACvF,MAAM,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,aAAa,CAAC,cAAc,CAAC,CAAA;AAEhG,MAAM,WAAW,eAAe;IAC/B,KAAK,EAAE,cAAc,CAAA;IACrB,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAA;IACf,mFAAmF;IACnF,SAAS,EAAE,MAAM,CAAA;CACjB;AAWD;;;;;GAKG;AACH,wBAAgB,eAAe,CAC9B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,MAAM,EAAE,eAAe,GACrB,eAAe,GAAG,IAAI,CA6BxB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAClC,MAAM,EAAE,eAAe,EACvB,MAAM,CAAC,EAAE,MAAM,GACb,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,cAAc,KAAK,MAAM,CAiB/D"}
|
package/out/poi.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* POI subject detection for the `poi_query` kind. The lexicon is INJECTED (`POIPhraseLookup`) —
|
|
7
|
+
* this package keeps its bitter-lesson invariant (no dictionaries in-tree); the phrase table
|
|
8
|
+
* lives in `@mailwoman/poi-taxonomy` and is wired in by `createRuntimePipeline` behind the
|
|
9
|
+
* default-OFF `poiQueryKind` flag. Spec §3.1.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Anchor separator between subject and place: comma, or near/in/at/around — scanned left-to-right until a prefix hits
|
|
13
|
+
* the lexicon.
|
|
14
|
+
*/
|
|
15
|
+
const ANCHOR_SEPARATOR = /\s*,\s*|\s+(?:near|in|at|around)\s+/gi;
|
|
16
|
+
/** Longest subject we accept, in tokens. Lexicon phrases are short; 4 covers the table. */
|
|
17
|
+
const MAX_SUBJECT_TOKENS = 4;
|
|
18
|
+
/**
|
|
19
|
+
* Match a POI subject: the whole input, or the text before the FIRST anchor separator WHOSE PREFIX HITS THE LEXICON (≤
|
|
20
|
+
* 4 tokens). Scans separator occurrences left-to-right — a lexicon phrase may itself contain a bare separator word
|
|
21
|
+
* (e.g. "walk in clinic"), so the first separator isn't necessarily the right split point. Returns null when the
|
|
22
|
+
* lexicon never fires — including comma-ridden full addresses whose leading segment isn't a lexicon phrase.
|
|
23
|
+
*/
|
|
24
|
+
export function matchPOISubject(text, locale, lookup) {
|
|
25
|
+
const trimmed = text.trim();
|
|
26
|
+
if (!trimmed)
|
|
27
|
+
return null;
|
|
28
|
+
const whole = lookup(trimmed, locale);
|
|
29
|
+
if (whole.length > 0) {
|
|
30
|
+
return { match: whole[0], subject: trimmed, remainder: "" };
|
|
31
|
+
}
|
|
32
|
+
for (const separator of trimmed.matchAll(ANCHOR_SEPARATOR)) {
|
|
33
|
+
if (separator.index === 0)
|
|
34
|
+
continue;
|
|
35
|
+
const subject = trimmed.slice(0, separator.index).trim();
|
|
36
|
+
// Subjects only grow as the scan moves right — once over budget, later splits are too.
|
|
37
|
+
if (subject.split(/\s+/).length > MAX_SUBJECT_TOKENS)
|
|
38
|
+
break;
|
|
39
|
+
const hits = lookup(subject, locale);
|
|
40
|
+
if (hits.length === 0)
|
|
41
|
+
continue;
|
|
42
|
+
const remainder = trimmed.slice(separator.index + separator[0].length).trim();
|
|
43
|
+
return { match: hits[0], subject, remainder };
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* `poi_query` scorer over an injected lexicon. Confidence bands: whole-input lexicon hit 0.92 (above venue-landmark's
|
|
49
|
+
* 0.88 ceiling — an exact lexicon phrase beats a shape heuristic); subject + anchor 0.9. Guards below keep venue-led
|
|
50
|
+
* FULL addresses (class 2) on the structured-address path: a remainder that leads with a house number, or a 4+-segment
|
|
51
|
+
* input, scores 0 here.
|
|
52
|
+
*/
|
|
53
|
+
export function createScorePOIQuery(lookup, locale) {
|
|
54
|
+
return (input, shape) => {
|
|
55
|
+
const matched = matchPOISubject(input.normalized, locale ?? input.appliedLocale, lookup);
|
|
56
|
+
if (!matched)
|
|
57
|
+
return 0;
|
|
58
|
+
if (matched.remainder === "")
|
|
59
|
+
return 0.92 * matched.match.confidence;
|
|
60
|
+
// Venue-led full address: "X, 350 5th Ave, …" stays a structured_address parse.
|
|
61
|
+
if (/^\d+\s/.test(matched.remainder))
|
|
62
|
+
return 0;
|
|
63
|
+
const segCount = shape.segments?.length ?? 1;
|
|
64
|
+
if (segCount > 3)
|
|
65
|
+
return 0;
|
|
66
|
+
return 0.9 * matched.match.confidence;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=poi.js.map
|
package/out/poi.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"poi.js","sourceRoot":"","sources":["../poi.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAsBH;;;GAGG;AACH,MAAM,gBAAgB,GAAG,uCAAuC,CAAA;AAEhE,2FAA2F;AAC3F,MAAM,kBAAkB,GAAG,CAAC,CAAA;AAE5B;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAC9B,IAAY,EACZ,MAA0B,EAC1B,MAAuB;IAEvB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;IAE3B,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAA;IAEzB,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;IAErC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAE,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,CAAA;IAC7D,CAAC;IAED,KAAK,MAAM,SAAS,IAAI,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAC5D,IAAI,SAAS,CAAC,KAAK,KAAK,CAAC;YAAE,SAAQ;QAEnC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAA;QAExD,uFAAuF;QACvF,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,kBAAkB;YAAE,MAAK;QAE3D,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QAEpC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,SAAQ;QAE/B,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAA;QAE7E,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAE,EAAE,OAAO,EAAE,SAAS,EAAE,CAAA;IAC/C,CAAC;IAED,OAAO,IAAI,CAAA;AACZ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAClC,MAAuB,EACvB,MAAe;IAEf,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QACvB,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,CAAC,UAAU,EAAE,MAAM,IAAI,KAAK,CAAC,aAAa,EAAE,MAAM,CAAC,CAAA;QAExF,IAAI,CAAC,OAAO;YAAE,OAAO,CAAC,CAAA;QAEtB,IAAI,OAAO,CAAC,SAAS,KAAK,EAAE;YAAE,OAAO,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,UAAU,CAAA;QAEpE,gFAAgF;QAChF,IAAI,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;YAAE,OAAO,CAAC,CAAA;QAE9C,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC,CAAA;QAE5C,IAAI,QAAQ,GAAG,CAAC;YAAE,OAAO,CAAC,CAAA;QAE1B,OAAO,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,UAAU,CAAA;IACtC,CAAC,CAAA;AACF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mailwoman/kind-classifier",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.2.0",
|
|
4
4
|
"description": "Stage 2.5 of the runtime pipeline — categorize inputs by query shape (postcode_only / locality_only / structured_address / intersection / po_box / landmark / vague). Rule-based for v1.",
|
|
5
5
|
"license": "AGPL-3.0-only OR LicenseRef-Commercial",
|
|
6
6
|
"repository": {
|
|
@@ -18,21 +18,15 @@
|
|
|
18
18
|
"exports": {
|
|
19
19
|
"./package.json": "./package.json",
|
|
20
20
|
".": {
|
|
21
|
-
"
|
|
22
|
-
"default": "./out/index.js"
|
|
21
|
+
"node": "./index.ts",
|
|
22
|
+
"default": "./out/index.js",
|
|
23
|
+
"types": "./out/index.d.ts"
|
|
23
24
|
}
|
|
24
25
|
},
|
|
25
26
|
"publishConfig": {
|
|
26
|
-
"exports": {
|
|
27
|
-
"./package.json": "./package.json",
|
|
28
|
-
".": {
|
|
29
|
-
"types": "./out/index.d.ts",
|
|
30
|
-
"default": "./out/index.js"
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
27
|
"access": "public"
|
|
34
28
|
},
|
|
35
29
|
"dependencies": {
|
|
36
|
-
"@mailwoman/core": "7.
|
|
30
|
+
"@mailwoman/core": "7.2.0"
|
|
37
31
|
}
|
|
38
32
|
}
|