/** * Intent parser: maps natural language to task types. * Ported from hf_space/intent_parser.py. */ import { DEFAULT_DETECT_CLASSES, KEYWORD_FALLBACK, ROUTING_GROUP_MAP } from "./constants.js"; const INTERPRET_KW = ["interpret","analyze","analyse","describe","assessment","what do you see","what is this","clinical interpretation","examine","evaluate","tell me about"]; const DETECT_KW = ["detect","find","locate","where is","where are","bounding box","identify","show me","mark","highlight"]; const SEGMENT_KW = ["segment","outline","contour","mask","delineate","boundary","trace","polygon"]; const CLASSIFY_KW = ["classify","what type","what view","which plane","what kind","categorize","classification"]; const GREETING_KW = ["hello","hi ","hey","good morning","good afternoon","thanks","thank you"]; const ANATOMY_TO_GROUP = new Map([ ["nt keypoint","nt_kp"],["nt kp","nt_kp"],["nuchal keypoint","nt_kp"],["ntkpoint","nt_kp"], ["brain keypoint","brain"],["cardiac keypoint","cardiac"], ["fetal head","pelvimetry"],["fetal_head","pelvimetry"],["angle of progression","pelvimetry"], ["keypoint","crl_kp"],["kpoint","crl_kp"],["scalebar","crl_kp"],["scale bar","crl_kp"], ["crl_kp","crl_kp"],["scalebarpoint","crl_kp"], ["brain","brain"],["cerebral","brain"],["cerebellum","brain"],["ventricle","brain"], ["thalami","brain"],["bpd","brain"],["head circumference","brain"],["csp","brain"], ["cavum","brain"],["septum pellucidum","brain"],["lv","brain"],["lateral ventricle","brain"], ["choroid plexus","brain"],["falx","brain"], ["heart","cardiac"],["cardiac","cardiac"],["thorax","cardiac"],["thoracic","cardiac"], ["aorta","cardiac"],["four chamber","cardiac"],["cardic","cardiac"],["cariac","cardiac"], ["nuchal","nt_nasal"],["nasal","nt_nasal"],["translucency","nt_nasal"],["nasal bone","nt_nasal"], ["nasal tip","nt_nasal"],["nasal skin","nt_nasal"],["nuchel","nt_nasal"],["translucen","nt_nasal"], ["crown-rump","crl"],["crown rump","crl"],["crl","crl"], ["doppler","doppler"],["flow","doppler"],["vessel","doppler"],["artery","doppler"], ["vein","doppler"],["umbilical","doppler"], ["cervix","pelvimetry"],["pelvimetry","pelvimetry"],["symphysis","pelvimetry"], ["pubic","pelvimetry"],["symphsis","pelvimetry"],["symphis","pelvimetry"],["pelvimtry","pelvimetry"], ["body","body_pose"],["abdomen","body_pose"],["arm","body_pose"],["legs","body_pose"], ["pose","body_pose"],["abdomin","body_pose"], ["femur","femur"],["thigh","femur"],["femor","femur"], ]); export function parseIntent(userText, hasImage = false, hasInterpretation = false) { const text = userText.trim().toLowerCase(); if (!text && hasImage) return { task: "interpret" }; for (const kw of GREETING_KW) { if (text.startsWith(kw) || text.includes(` ${kw}`)) { if (hasImage && !hasInterpretation) return { task: "interpret" }; return { task: "greeting" }; } } for (const kw of SEGMENT_KW) { if (text.includes(kw)) { const { det, seg } = extractClasses(text); return { task: "segment", classes: det || seg, segClasses: seg }; } } for (const kw of DETECT_KW) { if (text.includes(kw)) { const { det } = extractClasses(text); return { task: "detect", classes: det }; } } for (const kw of CLASSIFY_KW) { if (text.includes(kw)) return { task: "classify" }; } for (const kw of INTERPRET_KW) { if (text.includes(kw)) return { task: "interpret" }; } if (hasImage && !hasInterpretation) return { task: "interpret" }; if (hasInterpretation) { const { det } = extractClasses(text); if (det) return { task: "detect", classes: det }; } return { task: "general" }; } function extractClasses(text) { const lower = text.toLowerCase(); for (const [name, groupKey] of ANATOMY_TO_GROUP) { if (lower.includes(name) && ROUTING_GROUP_MAP[groupKey]) { const [det, seg] = ROUTING_GROUP_MAP[groupKey]; return { det, seg }; } } for (const [keywords, det, seg] of KEYWORD_FALLBACK) { for (const kw of keywords) { if (lower.includes(kw)) return { det, seg }; } } if (/\bnt\b/.test(lower) && ROUTING_GROUP_MAP.nt_nasal) { const [det, seg] = ROUTING_GROUP_MAP.nt_nasal; return { det, seg }; } if (/\b(all|every|everything)\b/.test(lower)) return { det: DEFAULT_DETECT_CLASSES, seg: null }; return { det: null, seg: null }; }