Matching and confidence API
Every text lookup in the Rules document library is a distance calculation and every extracted value carries a score. This page is the symbol reference for that surface: the distance functions and their cost models, the confidence types and their fields, the calibration functions, the special-region detector, and the phrase / snippet / table query APIs.
For how these are used in a task — thresholds, tuning, worked examples — read
Matching and confidence and
Tables and repeating structures. The rule-language
spellings are on Document functions. Both documented
surfaces reach this API: the kis CLI over local .bbox files and
rules.svc over a document sent with the request.
Distance functions
Section titled “Distance functions”| Symbol | Signature | Cost model |
|---|---|---|
Distance | Distance(a, b string) int | Levenshtein over runes; insert, delete and substitute each cost 1 |
DamerauDistance | DamerauDistance(a, b string) int | Levenshtein plus adjacent transposition at cost 1 |
OCRAwareDistance | OCRAwareDistance(a, b string) float64 | Levenshtein with fractional substitution cost for known OCR confusions; insert and delete still cost 1.0 |
Similarity | Similarity(a, b string) float64 | 1 - Distance(a,b) / max(runeLen(a), runeLen(b)) |
OCRAwareSimilarity | OCRAwareSimilarity(a, b string) float64 | Same ratio computed over OCRAwareDistance |
func Distance(a, b string) intfunc DamerauDistance(a, b string) intfunc OCRAwareDistance(a, b string) float64func Similarity(a, b string) float64func OCRAwareSimilarity(a, b string) float64All five operate on runes, so a multi-byte character is one edit: Distance("café", "cafe") is 1.
Identical strings short-circuit — Distance returns 0, the similarity functions return 1.0. Two
empty strings return a similarity of 1.0.
Both similarity ratios divide by the longer string, so a short query compared against a long block scores low even when the query is fully contained in it. Range is 0.0 to 1.0.
OCR confusion costs
Section titled “OCR confusion costs”OCRAwareDistance charges a reduced substitution cost for these pairs. The table is a compiled-in
package variable — there is no config key, flag or environment variable that extends or overrides it.
| Cost | Pairs (both directions unless noted) |
|---|---|
| 0.3 | l/1, O/0, o/0, I/1, I/l |
| 0.4 | S/5, s/5, B/8, $/S, space/_, ,/. |
| 0.5 | G/6, Z/2, c/e, n/h, u/v |
| 0.6 | % → 9 (one direction only) |
Every other substitution costs 1.0.
Match configuration
Section titled “Match configuration”type MatchConfig struct { MaxDistance int CaseSensitive bool OCRAware bool MinSimilarity float64}
func DefaultConfig() MatchConfig| Field | Type | Default | Meaning |
|---|---|---|---|
MaxDistance | int | 2 | Maximum edit distance accepted. Read only on the non-OCR-aware branch of Match |
CaseSensitive | bool | false | When false both strings are lowercased before comparison |
OCRAware | bool | true | Compare with OCRAwareSimilarity instead of Distance |
MinSimilarity | float64 | 0.8 | Similarity floor for an accepted match |
Matching helpers
Section titled “Matching helpers”func Match(target, candidate string, cfg MatchConfig) boolfunc BestMatch(target string, candidates []string, cfg MatchConfig) (int, float64)func NormalizeForMatch(s string) stringfunc GenerateOCRVariants(s string) []string| Symbol | Returns | Behaviour |
|---|---|---|
Match | bool | Exact hit returns true. With OCRAware it gates on MinSimilarity; otherwise on MaxDistance |
BestMatch | index, similarity | Index of the highest-similarity candidate, or -1 and the best similarity found when that best is below MinSimilarity. Comparison is strictly greater-than, so the first of several equal-similarity candidates wins |
NormalizeForMatch | string | Lowercases, trims, and collapses each run of whitespace to a single space |
GenerateOCRVariants | []string | The input plus every single-character substitution drawn from the confusion table |
GenerateOCRVariants builds its result from a map, so the returned order varies between runs.
Sort it if order matters.
Confidence score and factors
Section titled “Confidence score and factors”type Score struct { Value float64 // Overall score 0.0 - 1.0 Factors []Factor // Contributing factors}
type Factor struct { Name string // Descriptive name (e.g., "ocr", "alignment", "pattern_match") Value float64 // Factor score 0.0 - 1.0 Weight float64 // Weight in overall calculation (default 1.0) Detail string // Optional detail about this factor}Every confidence number in the block is a Score. Value is the weight-normalised mean of the
factors, clamped to [0,1]. Detail is what makes an extraction explainable in a review queue.
Constructing a score
Section titled “Constructing a score”func New(value float64) Scorefunc FromFactors(factors ...Factor) Scorefunc (s Score) WithFactor(f Factor) Score| Symbol | Returns | Behaviour |
|---|---|---|
New | Score | Bare value, clamped to [0,1], no factors |
FromFactors | Score | Weighted mean of the factors, clamped. A factor with Weight <= 0 is coerced to 1.0. No factors returns Value: 0 |
WithFactor | Score | Appends one factor and recomputes through FromFactors |
Reading a score
Section titled “Reading a score”func (s Score) String() string // "%.2f"func (s Score) Percent() float64 // Value * 100func (s Score) IsHigh() bool // >= 0.8func (s Score) IsMedium() bool // >= 0.5 and < 0.8func (s Score) IsLow() bool // < 0.5func (s Score) Level() Leveltype Level int
const ( LevelVeryLow Level = iota LevelLow LevelMedium LevelHigh LevelVeryHigh)
func (l Level) String() string // "VeryLow" | "Low" | "Medium" | "High" | "VeryHigh"Level | Band |
|---|---|
LevelVeryHigh | Value >= 0.9 |
LevelHigh | Value >= 0.8 |
LevelMedium | Value >= 0.6 |
LevelLow | Value >= 0.4 |
LevelVeryLow | below 0.4 |
Factor constructors
Section titled “Factor constructors”Each constructor fixes the factor name and weight. The weights are compiled in, not configuration.
| Constructor | Name | Weight | Value |
|---|---|---|---|
OCRFactor(ocrConfidence float64) | ocr | 1.0 | the OCR confidence, clamped |
ValidationFactor(isValid bool, validatorName string) | validation | 1.0 | 1.0 when valid, else 0.0 |
PatternMatchFactor(matchScore float64, pattern string) | pattern_match | 0.9 | the match score, clamped |
AlignmentFactor(alignmentScore float64) | alignment | 0.8 | the alignment score, clamped |
ConsistencyFactor(isConsistent bool, detail string) | consistency | 0.8 | 1.0 when consistent, else 0.0 |
FuzzyMatchFactor(similarity float64, editDistance int) | fuzzy_match | 0.7 | the similarity, clamped |
ProximityFactor(distance, maxDistance float64) | proximity | 0.6 | 1 - distance/maxDistance, clamped; 1.0 when either argument is <= 0 |
CountFactor(found, expected int) | count | 0.5 | found/expected, clamped; 0 when expected <= 0 |
func OCRFactor(ocrConfidence float64) Factorfunc AlignmentFactor(alignmentScore float64) Factorfunc PatternMatchFactor(matchScore float64, pattern string) Factorfunc FuzzyMatchFactor(similarity float64, editDistance int) Factorfunc ProximityFactor(distance, maxDistance float64) Factorfunc CountFactor(found, expected int) Factorfunc ConsistencyFactor(isConsistent bool, detail string) Factorfunc ValidationFactor(isValid bool, validatorName string) FactorAggregating scores
Section titled “Aggregating scores”func Average(scores ...Score) Scorefunc WeightedAverage(scores []Score, weights []float64) Scorefunc Min(scores ...Score) Scorefunc Max(scores ...Score) Scorefunc Geometric(scores ...Score) Scorefunc Harmonic(scores ...Score) Score| Symbol | Result | Notes |
|---|---|---|
Average | arithmetic mean | Concatenates every input’s factors onto the result |
WeightedAverage | weight-normalised mean | Returns Value: 0 when the slice lengths differ; negative weights are treated as 0 |
Min / Max | the extreme input Score | Returns the whole score, factors included |
Geometric | geometric mean | Returns Value: 0 and no factors if any input is <= 0 |
Harmonic | harmonic mean | Same zero collapse; penalises low scores hardest |
Average and WeightedAverage do not clamp — they are safe only because factor-built inputs are
already clamped. Geometric and Harmonic discard all factors.
Shaping scores
Section titled “Shaping scores”func (s Score) Penalize(penalty float64) Scorefunc (s Score) PenalizeIf(condition bool, penalty float64) Scorefunc (s Score) Boost(boost float64) Scorefunc (s Score) BoostIf(condition bool, boost float64) Scorefunc (s Score) AtLeast(threshold float64) Scorefunc (s Score) Cap(maxValue float64) Scorefunc (s Score) Floor(minValue float64) Score| Symbol | Result |
|---|---|
Penalize(p) | Value * (1 - p), clamped |
PenalizeIf(cond, p) | Penalize(p) when cond, otherwise unchanged |
Boost(b) | Value + (1 - Value) * b, with b clamped to [0,1] |
BoostIf(cond, b) | Boost(b) when cond, otherwise unchanged |
AtLeast(t) | the score when Value >= t, otherwise Value: 0 keeping the factors |
Cap(max) | Value lowered to max when above it |
Floor(min) | Value raised to min when below it |
All seven preserve the factor slice, so the audit trail survives shaping.
Geometry to confidence
Section titled “Geometry to confidence”func FromEditDistance(editDist, maxLen int) float64func FromOverlap(overlapArea, box1Area, box2Area float64) float64func FromAlignment(offset, tolerance float64) float64| Symbol | Result | Range |
|---|---|---|
FromEditDistance | 1 - editDist/maxLen; 0 when maxLen <= 0 | goes negative if editDist > maxLen — clamp before use |
FromOverlap | intersection over union of the two box areas; 0 when either area or the union is <= 0 | 0.0 to 1.0 |
FromAlignment | 1 - abs(offset)/tolerance, 0 at or beyond tolerance; with tolerance <= 0 returns 1.0 only for an exact 0 offset | 0.0 to 1.0 |
Confidence report
Section titled “Confidence report”type Report struct { Overall Score Components map[string]Score Issues []string Suggestions []string}
func NewReport() *Reportfunc (r *Report) Add(name string, score Score)func (r *Report) AddIssue(format string, args ...any)func (r *Report) AddSuggestion(format string, args ...any)func (r *Report) Compute()func (r *Report) Summary() stringCompute sets Overall to the unweighted Average of every component. Summary renders the
overall percentage and level, then components, issues and suggestions as a text block. Components
are iterated from a map, so Summary lists them in arbitrary order.
Calibration
Section titled “Calibration”A raw score of 0.8 is a heuristic weighted average, not a probability. Calibration is what turns it into one, and what answers the operating-point question: if you auto-accept everything at or above a threshold and review the rest, what precision do you get and how much did you cover?
type Sample struct { Predicted float64 // confidence the extractor reported, 0.0 - 1.0 Correct bool // whether the extracted value matched ground truth}
type Calibration struct{ /* opaque */ }
func Fit(samples []Sample) *Calibrationfunc (c *Calibration) Apply(raw float64) float64func (c *Calibration) SampleCount() int64| Symbol | Behaviour |
|---|---|
Fit | Isotonic regression by Pool-Adjacent-Violators. Samples are aggregated by identical raw score first, so the fit is insensitive to the order of equal-score samples. Returns nil for empty input |
Apply | Linear interpolation between fitted knots; holds the end value outside the fitted range. A nil receiver is the identity map, still clamped to [0,1]. Safe for concurrent use after Fit |
SampleCount | Number of labelled samples the fit used; 0 on a nil receiver |
// scores that violate monotonicity are pooled to the same calibrated valuec := confidence.Fit(samples)c.Apply(0.50) // == c.Apply(0.70) when raw 0.50 outperformed raw 0.70
var uncalibrated *confidence.Calibrationuncalibrated.Apply(0.37) // 0.37uncalibrated.Apply(1.5) // 1.0Reliability and calibration error
Section titled “Reliability and calibration error”type ReliabilityBin struct { Low float64 High float64 Count int64 MeanPredicted float64 Empirical float64}
func Reliability(samples []Sample, bins int) []ReliabilityBinfunc ECE(samples []Sample, bins int) float64Reliability buckets samples into bins equal-width bands over [0,1] — bins <= 0 means 10 —
and omits empty bands. A well-calibrated scorer has MeanPredicted close to Empirical in every
band.
ECE is the Expected Calibration Error: the sample-weighted mean absolute gap between
MeanPredicted and Empirical. Range 0.0 to 1.0; 0 is perfect. It is the single headline number
for whether the confidences are honest. With no samples it returns 0 — indistinguishable from a
perfectly calibrated scorer, so check the sample count before reading it.
Precision and coverage
Section titled “Precision and coverage”type ThresholdStat struct { Threshold float64 Coverage float64 // fraction of all values auto-accepted Precision float64 // fraction correct among auto-accepted Accepted int64 AcceptedWrong int64 // auto-accepted but actually wrong ReviewedCount int64 // routed to human review}
func PrecisionCoverageCurve(samples []Sample, steps int) []ThresholdStatfunc ThresholdForPrecision(samples []Sample, targetPrecision float64, minAccepted int64) (stat ThresholdStat, ok bool)func CurveReport(curve []ThresholdStat) string| Symbol | Behaviour |
|---|---|
PrecisionCoverageCurve | Sweeps the accept threshold from 0 to 1 in steps increments and returns steps+1 points. steps <= 0 means 20 |
ThresholdForPrecision | The lowest threshold meeting targetPrecision, maximising coverage. Candidates are the distinct predicted scores plus a 0.01 sweep. Thresholds with fewer than minAccepted accepted samples are skipped. ok is false when no threshold reaches the target |
CurveReport | Text table with the header threshold coverage precision accepted wrong reviewed |
With nothing accepted, Precision is defined as 1.0 — vacuously precise. Read Accepted alongside
it before believing a precision figure.
Special-region detection
Section titled “Special-region detection”type RegionType int
const ( RegionUnknown RegionType = iota RegionSignature RegionHandwriting RegionBarcode1D RegionBarcodeQR RegionBarcode2D // DataMatrix, PDF417, etc.)
func (rt RegionType) String() string // "Unknown" | "Signature" | "Handwriting" | "Barcode1D" | "QRCode" | "Barcode2D"type Region struct { Type RegionType Box geometry.Box Page int Confidence confidence.Score
NearLabel string // Nearby label text (e.g., "Signature:", "Sign here") OCRText string // Any OCR text detected in region (often garbage for signatures) OCRConfidence float64 // Average OCR confidence in region
AspectRatio float64 // Width / Height WordDensity float64 // Words per unit area IsIsolated bool // True if not part of main text flow}
func (r Region) GetPage() intDetection is inference over OCR geometry and confidence. No image is read, and nothing is decoded —
OCRText on a barcode region is whatever the OCR engine emitted there, never a barcode payload.
GetPage returns Page; it exists so a Region satisfies the page-filter interface shared with
the other extracted shapes.
Detector
Section titled “Detector”type Detector struct{ /* config DetectorConfig, unexported */ }
func NewDetector() *Detectorfunc NewDetectorWithConfig(cfg DetectorConfig) *Detector
func (d *Detector) DetectAll(pages []ocr.Page, blocks []text.Block) []Regionfunc (d *Detector) DetectSignatures(pages []ocr.Page, blocks []text.Block) []Regionfunc (d *Detector) DetectHandwriting(pages []ocr.Page, blocks []text.Block) []Regionfunc (d *Detector) DetectBarcodes(pages []ocr.Page) []RegionNewDetector uses DefaultDetectorConfig; the config is unexported afterwards, so every threshold
is fixed at construction. DetectAll is DetectSignatures then DetectHandwriting then
DetectBarcodes, concatenated. DetectBarcodes takes pages only — it reads no text blocks.
type DetectorConfig struct { SignatureMinWidth float64 SignatureMaxHeight float64 SignatureOCRThreshold float64 SignatureLabelDistance float64
HandwritingOCRMin float64 HandwritingOCRMax float64 HandwritingVarianceMin float64
BarcodeMinAspectRatio float64 BarcodeMaxAspectRatio float64 QRCodeAspectTolerance float64 BarcodeMinWidth float64 BarcodeMinHeight float64}
func DefaultDetectorConfig() DetectorConfig| Field | Default | Meaning |
|---|---|---|
SignatureMinWidth | 100 | Minimum width for a signature region |
SignatureMaxHeight | 80 | Maximum height — signatures are typically short |
SignatureOCRThreshold | 0.3 | OCR confidence below this suggests a signature |
SignatureLabelDistance | 150 | Maximum distance from a signature label |
HandwritingOCRMin | 0.3 | Below this the region reads as a signature instead |
HandwritingOCRMax | 0.75 | Above this the region reads as printed text |
HandwritingVarianceMin | 0.15 | Minimum character-size variance to consider handwriting |
BarcodeMinAspectRatio | 3.0 | 1D barcodes are at least 3× wider than tall |
BarcodeMaxAspectRatio | 20.0 | Upper bound for 1D |
QRCodeAspectTolerance | 0.3 | QR aspect ratio must fall within 0.7–1.3 |
BarcodeMinWidth | 50 | Minimum barcode width |
BarcodeMinHeight | 20 | Minimum barcode height |
A signature found next to a label emits at whatever it scores; an isolated low-confidence candidate in the bottom third of the page emits only at ≥ 0.4. Handwriting emits at ≥ 0.5 and merges same-type regions within 50px on a page. Barcodes emit at ≥ 0.4.
Filtering regions
Section titled “Filtering regions”func FilterByConfidence(regions []Region, minConfidence float64) []Regionfunc FilterByType(regions []Region, regionType RegionType) []Regionfunc GetSignatures(regions []Region) []Regionfunc GetHandwriting(regions []Region) []Regionfunc GetBarcodes(regions []Region) []RegionGetBarcodes returns all three barcode types. All five return nil when nothing matches.
Signature anchor registry
Section titled “Signature anchor registry”var DefaultSignatureAnchors = []string{ "signature", "sign here", "sign:", "signed:", "authorized signature", "x_", "x:", "sign below", "your signature",}
func AddSignatureAnchors(anchors ...string)func RegisteredSignatureAnchors() []stringfunc ResetSignatureAnchors()| Symbol | Behaviour |
|---|---|
DefaultSignatureAnchors | The domain-neutral anchor set. Matching is case-insensitive substring |
AddSignatureAnchors | Appends domain anchors; never replaces the defaults. Mutex-protected, typically called from init() |
RegisteredSignatureAnchors | Defaults followed by registered anchors in registration order, as a fresh copy |
ResetSignatureAnchors | Clears registered anchors, leaving the defaults. Tests only |
special.AddSignatureAnchors( "borrower signature", "co-borrower signature", "coborrower signature", "applicant signature", "co-applicant signature", "seller signature", "witness signature", "notary signature",)Phrase query API
Section titled “Phrase query API”type PhraseMatch struct { Phrase string // The matched phrase text Page int // Page number where found Box geometry.Box // Bounding box of the phrase LineIndex int // Index of the line containing the phrase MatchedLine string // Full text of the line containing the match LinesBefore []string // Lines before the match (context) LinesAfter []string // Lines after the match (context) Blocks []text.Block // The blocks that form this phrase}
type FuzzyPhraseMatch struct { PhraseMatch TotalDistance int // Total Levenshtein distance across all words MatchedWords []string // The actual words that matched (from document)}func (d *Document) FindPhrase(phrase string, linesBefore, linesAfter int64) []PhraseMatchfunc (d *Document) FindIPhrase(phrase string, linesBefore, linesAfter int64) []PhraseMatchfunc (d *Document) FindPhraseFuzzy(phrase string, maxDistancePerWord, maxTotalDistance, linesBefore, linesAfter int64) []FuzzyPhraseMatchfunc (d *Document) FindIPhraseFuzzy(phrase string, maxDistancePerWord, maxTotalDistance, linesBefore, linesAfter int64) []FuzzyPhraseMatchThe I variants are case-insensitive. Box is the union of the matched blocks. The fuzzy walk
finds candidates for the first word within maxDistancePerWord, then extends across the same page,
ranking candidates by editDistance*100 + spatialDistance.
Boolean and count helpers
Section titled “Boolean and count helpers”All are case-insensitive and built on FindIPhrase / FindIPhraseFuzzy. The fuzzy forms derive
the total budget as maxDistancePerWord × wordCount; there is no separate total argument.
| Signature | Returns |
|---|---|
HasPhrase(phrase string) bool | phrase present anywhere |
HasPhraseFuzzy(phrase string, maxDistancePerWord int64) bool | as above, fuzzy |
HasPhraseOnPage(phrase string, page int64) bool | phrase present on one page |
HasPhraseOnPageFuzzy(phrase string, page int64, maxDistancePerWord int64) bool | as above, fuzzy |
HasPhraseInBox(phrase string, box geometry.Box) bool | phrase present inside a box |
HasPhraseInBoxFuzzy(phrase string, box geometry.Box, maxDistancePerWord int64) bool | as above, fuzzy |
HasAnyPhrase(phrases ...string) bool | any of the phrases present |
HasAnyPhraseFuzzy(maxDistancePerWord int64, phrases ...string) bool | as above, fuzzy |
HasAllPhrases(phrases ...string) bool | every phrase present |
HasAllPhrasesFuzzy(maxDistancePerWord int64, phrases ...string) bool | as above, fuzzy |
HasAnyPhraseInBox(box geometry.Box, phrases ...string) bool | any phrase inside a box |
HasAnyPhraseOnPage(page int64, phrases ...string) bool | any phrase on one page |
CountPhrase(phrase string) int64 | occurrence count |
CountPhraseFuzzy(phrase string, maxDistancePerWord int64) int64 | fuzzy occurrence count |
CountPhraseOnPage(phrase string, page int64) int64 | occurrence count on one page |
PhraseNear(a, b string, maxPixels float64) bool | both phrases present within maxPixels |
PhraseBetween(startAnchor, endAnchor string) string | text between two anchors |
Note the argument order on the variadic fuzzy forms: the distance budget comes first, before the phrases.
Region-scoped phrase matching
Section titled “Region-scoped phrase matching”func (q QueryResult) ContainingPhraseFuzzy(phrase string, maxDistPerWord, maxTotalDist int64) QueryResultfunc (q QueryResult) ContainingIPhraseFuzzy(phrase string, maxDistPerWord, maxTotalDist int64) QueryResultfunc (q QueryResult) ContainingAnyPhraseFuzzy(phrases string, maxDistPerWord, maxTotalDist int64) QueryResultfunc (q QueryResult) ContainingAnyIPhraseFuzzy(phrases string, maxDistPerWord, maxTotalDist int64) QueryResultThese flatten the region’s blocks into a word stream, normalise quotes and dashes, then slide the
phrase over the stream comparing with OCRAwareDistance. A match requires every word within
maxDistPerWord and the running total within maxTotalDist. The result carries the blocks
that participated in the match, or is empty.
The Any forms split phrases on | and return the first phrase that matches.
doc.InRegionPct(0, 0, 100, 20).ContainingAnyIPhraseFuzzy( "ANTI-COERCION INSURANCE|Anti-Coercion Statement|STATEMENT OF ANTI-COERCION", 2, 4)Snippet API
Section titled “Snippet API”type Snippet struct { StartPhrase string // The starting phrase that was matched EndPhrase string // The ending phrase that was matched StartPage int // Page where the start phrase was found EndPage int // Page where the end phrase was found (or last page if not found) Lines []string // The extracted lines of text}
func (d *Document) ExtractSnippet(startPhrase, endPhrase string, caseInsensitive, includeEnd bool) *Snippetfunc (d *Document) ExtractSnippetFuzzy(startPhrase, endPhrase string, caseInsensitive, includeEnd bool, maxDist int64) *Snippet| Behaviour | Detail |
|---|---|
| Start line | always included |
| End line | excluded unless includeEnd is true |
| Page boundaries | extraction spans them |
| Not found | returns nil, and only when the start phrase is missing |
| No end match | EndPage is the page count and extraction runs to the end of the document |
| Fuzzy budget | total is maxDist × max(startWordCount, endWordCount), applied to both phrases |
Table query API
Section titled “Table query API”func (d *Document) TableCount() int64func (d *Document) TableAt(index int64) *table.Tablefunc (d *Document) TableNear(anchorText string) *table.Tablefunc (d *Document) TableNearPhrase(anchorPhrase string) *table.TableTableNear delegates to TableNearPhrase when the anchor contains a space, and otherwise finds the
first block containing the text. TableNearPhrase uses the case-sensitive FindPhrase and falls
back to a single-block contains search. Both then return the table with the smallest box-to-box
distance.
Spatial table lookups
Section titled “Spatial table lookups”func (d *Document) TableBelow(anchor string) *TableResultfunc (d *Document) TableAbove(anchor string) *TableResultfunc (d *Document) TableBetween(startAnchor, endAnchor string) *TableResultfunc (d *Document) TablesBetween(startAnchor, endAnchor string) []*TableResult
func (d *Document) TableBelowFuzzy(anchor string, maxDistPerWord, maxTotalDist int64) *TableResultfunc (d *Document) TableAboveFuzzy(anchor string, maxDistPerWord, maxTotalDist int64) *TableResultfunc (d *Document) TableBetweenFuzzy(startAnchor, endAnchor string, maxDistPerWord, maxTotalDist int64) *TableResultNil-safe wrappers return a zero-valued result instead of nil, so a rule cannot fault on a missing
table:
func (d *Document) SafeTable(index int64) *SafeTableResultfunc (d *Document) SafeTableBelow(anchor string) *SafeTableResultfunc (d *Document) SafeTableAbove(anchor string) *SafeTableResultfunc (d *Document) SafeTableBetween(startAnchor, endAnchor string) *SafeTableResultfunc (d *Document) SafeTablesBetween(startAnchor, endAnchor string) []*TableResultfunc (d *Document) SafeTableBelowFuzzy(anchor string, maxDistPerWord, maxTotalDist int64) *SafeTableResultfunc (d *Document) SafeTableAboveFuzzy(anchor string, maxDistPerWord, maxTotalDist int64) *SafeTableResultfunc (d *Document) SafeTableBetweenFuzzy(startAnchor, endAnchor string, maxDistPerWord, maxTotalDist int64) *SafeTableResultDetected table shape
Section titled “Detected table shape”type Table struct { Rows []Row Columns []Column Box geometry.Box HeaderRows int Page int Confidence float64 // Overall (backward compatibility) TableScore confidence.Score // Detailed table confidence}
func NewDetector() *Detectorfunc (d *Detector) WithMinDimensions(rows, cols int) *Detectorfunc (d *Detector) DetectTables(lines []text.Line, docStats text.DocStats) []TableThis Detector is the table detector, distinct from the special-region Detector above — the two
NewDetector constructors live in different packages. Table detector defaults: minimum 2 rows,
minimum 2 columns, alignment tolerance 0.1, gap multiplier 2.0.
Table.Confidence is (consistencyScore + sizeScore) / 2, where consistencyScore is
1 / (1 + variance(cellsPerRow) * 0.1) and sizeScore is 0.5 by default, 0.8 at ≥ 3 rows and
≥ 2 columns, and 1.0 at ≥ 5 rows and ≥ 3 columns. It is a shape score: it says nothing about
whether the cell text is right, and it is not comparable with field-extraction confidence.
Header detection yields at most one header row, from either of two signals: the first row contains no digits and no cell longer than 50 characters, or the gap after the first row exceeds 1.2× the average row gap. Multi-row headers are never detected.
The full Table, TableResult and SafeTableResult accessor surface is on
Tables and repeating structures.
What each score means
Section titled “What each score means”| Score | Range | Meaning |
|---|---|---|
fuzzy.Similarity, fuzzy.OCRAwareSimilarity | 0.0 – 1.0 | 1.0 is identical; the denominator is the longer string |
confidence.Score.Value | 0.0 – 1.0 | Weighted mean of the factors. A raw heuristic belief, not a probability |
confidence.Factor.Value | 0.0 – 1.0 | One signal’s contribution, clamped by its constructor |
Calibration.Apply | 0.0 – 1.0 | Empirical probability of correctness, once fitted against labelled outcomes |
ECE | 0.0 – 1.0 | Mean gap between claimed and actual accuracy; 0 is perfect |
ThresholdStat.Coverage | 0.0 – 1.0 | Fraction of values auto-accepted at that threshold |
ThresholdStat.Precision | 0.0 – 1.0 | Fraction correct among the accepted; 1.0 when nothing is accepted |
special.Region.Confidence | 0.0 – 1.0 | Heuristic detection belief over OCR geometry; not comparable with extraction confidence |
table.Table.Confidence | 0.0 – 1.0 | Table shape consistency and size only |