feat(backend): read a spoken tooth number as its FDI code

The prompt had this backwards. "Never output an FDI tooth code unless the
speaker used FDI notation. Prefer arch + side + position" pushed the model
to decompose speech into "upper / patient_right / six", so the clinician
effectively had to *describe* every tooth. Saying "دندون بیست و شش" — the
way a dentist actually dictates — was the unsupported path.

FDI is what clinicians speak, so the prompt now teaches the notation
instead of forbidding it: first digit = quadrant from the patient's own
point of view, second digit = position from the midline. arch/side/position
stays as the reading of a *described* tooth, where a single digit is a
position and the quadrant comes from words.

Two guards come with it, because bare numbers are now teeth: a single digit
alone still refuses to guess a quadrant, and dates, counts and quantities
are explicitly not teeth.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-21 04:43:19 +08:00
parent 17d3c5ca25
commit 215aa1fd87
2 changed files with 35 additions and 22 deletions

View File

@@ -21,7 +21,7 @@ import { WEEKDAYS } from './voice.types';
export type WireToothIntent = {
spoken: string;
/** Two-digit FDI code, only when the speaker genuinely used FDI notation. */
/** The two-digit FDI code the clinician spoke; null when the tooth was described. */
fdi: string | null;
arch: 'upper' | 'lower' | null;
side: 'patient_right' | 'patient_left' | null;
@@ -66,7 +66,8 @@ const TOOTH_SCHEMA = {
fdi: {
type: ['string', 'null'],
description:
'Two-digit FDI code ONLY if the speaker used FDI notation. Otherwise null.',
'The two-digit FDI code the clinician said for this tooth, e.g. "26". Null only ' +
'when the tooth was described in words instead of numbered.',
},
arch: { type: ['string', 'null'], enum: ['upper', 'lower', null] },
side: {
@@ -76,7 +77,8 @@ const TOOTH_SCHEMA = {
},
position: {
type: ['integer', 'null'],
description: '1 = central incisor … 8 = third molar.',
description:
'Position from the midline: 1 = central incisor … 8 = third molar. Never an FDI code.',
},
},
} as const;