File size: 3,597 Bytes
138e09d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
export const MODEL_ID = "Xenova/all-MiniLM-L6-v2";

export const CONDITION_CARDS = [
  {
    label: "common cold",
    description:
      "runny or stuffy nose, sneezing, sore throat, cough, mild headache, and usually little or no fever",
  },
  {
    label: "influenza",
    description:
      "sudden fever, dry cough, fatigue, body aches, headache, chills, and sometimes sore throat",
  },
  {
    label: "COVID-19",
    description:
      "fever, cough, fatigue, sore throat, congestion, headache, body aches, and possible loss of taste or smell",
  },
  {
    label: "seasonal allergies",
    description:
      "sneezing, itchy or watery eyes, clear runny nose, nasal congestion, and usually no fever",
  },
  {
    label: "strep throat",
    description:
      "sudden sore throat, pain when swallowing, fever, red swollen tonsils, and usually no cough",
  },
  {
    label: "migraine",
    description:
      "moderate or severe throbbing headache, often one-sided, nausea, and sensitivity to light or sound",
  },
  {
    label: "tension headache",
    description:
      "mild or moderate pressure or tightness around the head, scalp tenderness, and no nausea",
  },
  {
    label: "gastroenteritis",
    description:
      "watery diarrhea, abdominal cramps, nausea or vomiting, and sometimes fever",
  },
  {
    label: "urinary tract infection",
    description:
      "burning or pain during urination, frequent urination, urgent urination, and pelvic pressure",
  },
  {
    label: "pneumonia",
    description:
      "cough, fever, chills, difficulty breathing, chest pain with breathing or coughing, and fatigue",
  },
];

export const RED_FLAG_PHRASES = [
  "chest pain",
  "difficulty breathing",
  "trouble breathing",
  "shortness of breath",
  "fainting",
  "confusion",
  "blue lips",
  "one-sided weakness",
  "stiff neck",
  "coughing blood",
];

export function normalizeInput(text) {
  return text.trim().replace(/\s+/g, " ");
}

export function splitSymptoms(text) {
  return text
    .split(/\n|,|;|\.(?:\s|$)/)
    .map(normalizeInput)
    .filter(Boolean);
}

export function reorderSymptoms(text) {
  return splitSymptoms(text).reverse().join(", ");
}

export function findRedFlags(text) {
  const normalized = normalizeInput(text).toLowerCase();
  return RED_FLAG_PHRASES.filter((phrase) => normalized.includes(phrase));
}

export function rankRows(result, limit = 5) {
  return result.labels.slice(0, limit).map((label, index) => ({
    rank: index + 1,
    label,
    score: result.scores[index],
  }));
}

export function compareRankings(first, second) {
  const secondRanks = new Map(second.map((row) => [row.label, row.rank]));
  return first.map((row) => ({
    label: row.label,
    originalRank: row.rank,
    reorderedRank: secondRanks.get(row.label) ?? null,
    shift:
      secondRanks.has(row.label) ? row.rank - secondRanks.get(row.label) : null,
  }));
}

export function csvEscape(value) {
  const text = String(value ?? "");
  return `"${text.replaceAll('"', '""')}"`;
}

export function runsToCsv(runs) {
  const header = [
    "timestamp",
    "input",
    "variant",
    "rank",
    "condition",
    "model_score",
    "model_id",
    "device",
    "dtype",
    "inference_ms",
  ];
  const rows = runs.flatMap((run) =>
    run.results.map((result) => [
      run.timestamp,
      run.input,
      run.variant,
      result.rank,
      result.label,
      result.score,
      run.modelId,
      run.device,
      run.dtype,
      run.inferenceMs,
    ]),
  );
  return [header, ...rows].map((row) => row.map(csvEscape).join(",")).join("\n");
}