mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 20:42:43 +00:00
fix(coach): narrow the pt-BR population-norm patterns
A sentence the grounding check reads as population guidance has its numbers exempted from the evidence check. Two of the pt-BR patterns matched sentences about the reader's own readings: "(entre|de) ... geralmente" fired on "Sua pressão de 158/97 geralmente fica...", and a singular "médico ... recomenda" with a 30-character gap fired on "Seu médico recomenda manter a pressão em 158/97". Either let an invented figure through unchecked. Every pt-BR entry now needs a population subject or a reference noun: plural guideline, doctor or specialist subjects next to their verb, plural adults needing something, and "a/o <metric> normal" without a possessive. Portuguese month names join the written-date pass so "21 de julho" is not graded as a figure, and quilos, por cento and passos join the unit words. Negative cases prove the reader's-own sentences are checked again; positive cases keep the reference sentences exempt.
This commit is contained in:
1 parent
68b428e3f5
commit
3577da6966
2 files changed
+56
-7
No files matched your search
@@ -600,6 +600,7 @@ describe("tokenizing prose written in the reader's language", () => {
|
||||
["es", "El 21 de julio, su tensión era de 128 mmHg."],
|
||||
["it", "Il 21 luglio la pressione era di 128 mmHg."],
|
||||
["pl", "21 lipca ciśnienie wynosiło 128 mmHg."],
|
||||
["pt-BR", "Em 21 de julho, sua pressão era de 128 mmHg."],
|
||||
] as const)("leaves a written %s date alone", (locale, prose) => {
|
||||
const findings = findUnverifiedCoachNumbers(
|
||||
prose,
|
||||
@@ -623,3 +624,38 @@ describe("tokenizing prose written in the reader's language", () => {
|
||||
expect(findings.map((f) => f.value)).not.toContain(21);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* A sentence framed as population guidance has its numbers exempted from the
|
||||
* check, so a framing pattern that also matches a sentence about the reader's
|
||||
* own readings lets an invented figure through unchecked. The Brazilian
|
||||
* Portuguese bank needs a population subject or a reference noun for that
|
||||
* reason; the first two cases here were exempted by the broader patterns it
|
||||
* started with.
|
||||
*/
|
||||
describe("Brazilian Portuguese population-norm framing", () => {
|
||||
const payloads = [{ metric: "bp", latest: 128 }];
|
||||
|
||||
it.each([
|
||||
"Sua pressão de 158/97 geralmente fica acima do seu padrão.",
|
||||
"Seu médico recomenda manter a pressão em 158/97.",
|
||||
"Entre as suas medições, a pressão normalmente fica em 158/97.",
|
||||
"Para um adulto como você, 158/97 geralmente precisa de atenção.",
|
||||
])("still checks the numbers in: %s", (prose) => {
|
||||
const values = findUnverifiedCoachNumbers(prose, payloads, "pt-BR").map(
|
||||
(f) => f.value,
|
||||
);
|
||||
expect(values).toContain(158);
|
||||
expect(values).toContain(97);
|
||||
});
|
||||
|
||||
it.each([
|
||||
"A faixa normal do pulso em repouso fica entre 60 e 100 bpm.",
|
||||
"Os médicos recomendam de 7 a 9 horas de sono por noite.",
|
||||
"A maioria dos adultos precisa de 7 a 9 horas de sono.",
|
||||
"A pressão arterial normal de um adulto fica abaixo de 120/80 mmHg.",
|
||||
"Os valores de referência da glicemia em jejum vão de 70 a 99 mg/dL.",
|
||||
])("exempts the reference figures in: %s", (prose) => {
|
||||
expect(findUnverifiedCoachNumbers(prose, payloads, "pt-BR")).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -156,6 +156,10 @@ const UNIT_WORDS: Readonly<Record<NumKind, readonly string[]>> = {
|
||||
"livres",
|
||||
"libra",
|
||||
"libras",
|
||||
"quilo",
|
||||
"quilos",
|
||||
"quilograma",
|
||||
"quilogramas",
|
||||
"funt",
|
||||
"funty",
|
||||
],
|
||||
@@ -170,6 +174,7 @@ const UNIT_WORDS: Readonly<Record<NumKind, readonly string[]>> = {
|
||||
"pour cent",
|
||||
"pourcent",
|
||||
"por ciento",
|
||||
"por cento",
|
||||
"porciento",
|
||||
"per cento",
|
||||
"procent",
|
||||
@@ -214,6 +219,7 @@ const UNIT_WORDS: Readonly<Record<NumKind, readonly string[]>> = {
|
||||
"pasos",
|
||||
"passo",
|
||||
"passi",
|
||||
"passos",
|
||||
"krok",
|
||||
"kroki",
|
||||
"krokow",
|
||||
@@ -626,6 +632,8 @@ const MONTHS = [
|
||||
"stycznia|lutego|marca|kwietnia|maja|czerwca|lipca|sierpnia|września|wrzesnia|października|pazdziernika|listopada|grudnia",
|
||||
// nl
|
||||
"januari|februari|maart|mei|augustus",
|
||||
// pt-BR
|
||||
"janeiro|fevereiro|março|marco|maio|junho|julho|setembro|outubro|novembro|dezembro",
|
||||
].join("|");
|
||||
|
||||
/** Parse a raw number token honouring the reply language's separators. */
|
||||
@@ -635,7 +643,7 @@ function parseLocaleNumber(raw: string, locale: Locale): number | null {
|
||||
// EN: "," groups thousands, "." is the decimal point.
|
||||
normalised = raw.replace(/,/g, "");
|
||||
} else {
|
||||
// DE / fr / es / it / pl / nl: "." groups thousands, "," is the decimal
|
||||
// DE / fr / es / it / pl / nl / pt-BR: "." groups thousands, "," is the decimal
|
||||
// point.
|
||||
normalised = raw.replace(/\./g, "").replace(/,/g, ".");
|
||||
}
|
||||
@@ -880,18 +888,23 @@ const POPULATION_NORM_PATTERNS: Record<Locale, readonly RegExp[]> = {
|
||||
/\b(?:volwassenen|mensen)\s+(?:hebben\s+)?(?:meestal|doorgaans|gewoonlijk|normaal\s+gesproken|over\s+het\s+algemeen)\s+(?:nodig|hebben)\b/i,
|
||||
/\b(?:referentie|normaal|aanbevolen)\w*\s*(?:bereik|waarden?)\b/i,
|
||||
/\bligt\s+(?:normaal\s+gesproken|meestal|doorgaans|gewoonlijk)\s+(?:tussen|rond|op)\b/i,
|
||||
], // No `\b` next to Hangul (it is an ASCII \w boundary), and the object sits
|
||||
// between subject and verb in Korean, so each entry allows a gap where the
|
||||
// Latin banks put \s+.
|
||||
],
|
||||
// pt-BR. Every entry needs a population subject or a reference noun: a
|
||||
// reading of the reader's own ("Sua pressão de 158/97 geralmente fica…",
|
||||
// "Seu médico recomenda…") is a claim about their data, and an exempted
|
||||
// sentence is one whose numbers are never checked.
|
||||
"pt-BR": [
|
||||
/\bfaixa\s+(?:de\s+refer[eê]ncia|normal)\b/i,
|
||||
/\bvalor(?:es)?\s+de\s+refer[eê]ncia\b/i,
|
||||
/\b(?:adultos?|pessoas?)\s+saud[áa]ve(?:l|is)\b/i,
|
||||
/\bmaioria\s+(?:dos\s+)?(?:adultos?|das\s+pessoas)\b/i,
|
||||
/\b(?:diretrizes|guias|m[eé]dicos?|especialistas?)\b[^.?!]{0,30}\b(?:recomend(?:am|a)|suger(?:em|e)|indic(?:am|a))\b/i,
|
||||
/\b(?:adultos?|pessoas?)\b[^.?!]{0,30}\b(?:geralmente|normalmente|em\s+geral)\b[^.?!]{0,30}\b(?:precis(?:am|a)|devem|necessit(?:am|a))\b/i,
|
||||
/\b(?:entre|de)\s+[^.?!]{0,30}\b(?:normalmente|geralmente|em\s+geral)\b/i,
|
||||
/\b(?:as\s+|os\s+)?(?:diretrizes|m[eé]dicos|especialistas)\s+(?:geralmente\s+|em\s+geral\s+)?(?:dizem|recomendam|aconselham|sugerem|indicam|consideram)\b/i,
|
||||
/\b(?:os\s+)?(?:adultos|as\s+pessoas)\s+(?:geralmente\s+|normalmente\s+|em\s+geral\s+)?(?:precisam|necessitam)\s+de\b/i,
|
||||
/\b(?:a|o)\s+(?:frequ[êe]ncia\s+card[íi]aca|pulso|press[ãa]o(?:\s+arterial)?|glicemia|glicose)(?:\s+de\s+repouso)?\s+(?:normal|saud[áa]vel|t[íi]pica|t[íi]pico)\b/i,
|
||||
],
|
||||
// No `\b` next to Hangul (it is an ASCII \w boundary), and the object sits
|
||||
// between subject and verb in Korean, so each entry allows a gap where the
|
||||
// Latin banks put \s+.
|
||||
ko: [
|
||||
/정상\s*범위(?:는|가|를|로|의)/,
|
||||
/(?:참고|기준|권장)\s*(?:범위|치|값)/,
|
||||
|
||||
Reference in new issue
Block a user