File size: 4,384 Bytes
222e211
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/**
 * 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 };
}