Linaya commited on
Commit
e700b5a
·
verified ·
1 Parent(s): cf60df2

Final final updates to app.py

Browse files
Files changed (1) hide show
  1. app.py +39 -8
app.py CHANGED
@@ -207,6 +207,20 @@ def read_input(file, text):
207
  return open(path, encoding="utf-8", errors="replace").read()
208
 
209
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210
  @GPU
211
  def analyse(file, text):
212
  raw = read_input(file, text)
@@ -232,6 +246,9 @@ def analyse(file, text):
232
  s3 = (f"FAILED: interviewer found ({', '.join(removed)}) but nothing was left after removing them, "
233
  f"because the astronaut's name tag was not recognised.")
234
  s3 += f" Words left: {len(narrative.split()):,}."
 
 
 
235
 
236
  #step 4
237
  segs = segment(narrative)
@@ -243,6 +260,11 @@ def analyse(file, text):
243
  return s1, s2, s3, "<h4>4. Segmenting</h4>FAILED: no text left to segment.", "", None, empty
244
  segs = segs[:300] #keeps a free cpu quick
245
  wc = [len(s.split()) for s in segs]
 
 
 
 
 
246
  s4 = (f"<h4>4. Segmenting</h4><b>{len(segs)} segment{"s" if len(segs) != 1 else ""}</b>, {min(wc)} to {max(wc)} words each{note}<br><br>" +
247
  "".join(f"<div class='seg'><b>#{i + 1}</b> ({wc[i]} words) {html.escape(s[:220])}{'...' if len(s) > 220 else ''}</div>"
248
  for i, s in enumerate(segs[:3])) +
@@ -252,14 +274,17 @@ def analyse(file, text):
252
  v = np.array([vader_flags(s) for s in segs])
253
  t = tfidf_probs(segs)
254
  b = bert_probs(segs)
 
255
  rows = ""
256
  for i, c in enumerate(CATEGORIES):
257
- rows += (f"<tr><td>{NAMES[c]}</td><td>{int(v[:, i].sum())}</td><td>{int((t[:, i] >= 0.5).sum())}</td>"
258
- f"<td><b>{int((b[:, i] >= BERT_THRESHOLDS[c]).sum())}</b></td><td>{b[:, i].max():.2f} / {BERT_THRESHOLDS[c]:.2f}</td></tr>")
259
- s5 = (f"<h4>5. Classification: all three models</h4><table><tr><th>Category</th><th>VADER</th><th>TF-IDF</th><th>BERT + LoRA</th>"
260
- f"<th>BERT top prob / threshold</th></tr>{rows}</table>"
261
- f"<p class='small'>Numbers are segments flagged out of {len(segs)}. BERT is my final model. "
262
- f"A research prototype, it flags passages for a person to read and does not diagnose anyone.</p>")
 
 
263
 
264
  order = np.argsort(-b.max(axis=1)) #strongest segments first for shap
265
  choices = [f"#{k + 1} (BERT max {b[k].max():.2f}) {segs[k][:60]}..." for k in order]
@@ -294,9 +319,15 @@ CSS = """
294
  .gradio-container {background: radial-gradient(ellipse at top, #141b33 0%, #05070f 70%) !important;}
295
  * {box-shadow: none !important;}
296
  .seg {border: 1px solid #ffffff44; border-radius: 12px; padding: 8px 12px; margin: 6px 0; color: #e6ebff;}
297
- table {width: 100%; border-collapse: collapse; color: #e6ebff;}
298
- th, td {border-bottom: 1px solid #ffffff33; padding: 6px 8px; text-align: left;}
299
  .small {color: #9aa4c4; font-size: 13px;}
 
 
 
 
 
 
300
  """
301
 
302
  with gr.Blocks(title="SPACEMIND") as demo:
 
207
  return open(path, encoding="utf-8", errors="replace").read()
208
 
209
 
210
+ def bar(k, n, colour):
211
+ #count + a thin bar showing what share of the segments got flagged
212
+ return (f"<td><div class='cell'><b>{k}</b><span class='bar'>"
213
+ f"<span style='width:{k / n * 100:.0f}%;background:{colour}'></span></span></div></td>")
214
+
215
+
216
+ def meter(p, thr):
217
+ #track from 0 to 1, fill = top bert score, white tick = threshold
218
+ colour = "#818cf8" if p >= thr else "#4b5370"
219
+ return (f"<div class='cell'><span class='meter'><span class='fill' style='width:{p * 100:.0f}%;background:{colour}'></span>"
220
+ f"<span class='tick' style='left:{thr * 100:.0f}%'></span></span>"
221
+ f"<span class='small'>{p:.2f} / {thr:.2f}</span></div>")
222
+
223
+
224
  @GPU
225
  def analyse(file, text):
226
  raw = read_input(file, text)
 
246
  s3 = (f"FAILED: interviewer found ({', '.join(removed)}) but nothing was left after removing them, "
247
  f"because the astronaut's name tag was not recognised.")
248
  s3 += f" Words left: {len(narrative.split()):,}."
249
+ if method == "no_tags":
250
+ #no cover page and no NAME: tags --> probably not an oral history, the models still run but read with care
251
+ s3 += " Note: this does not look like a NASA oral history transcript, so the scores below are less meaningful."
252
 
253
  #step 4
254
  segs = segment(narrative)
 
260
  return s1, s2, s3, "<h4>4. Segmenting</h4>FAILED: no text left to segment.", "", None, empty
261
  segs = segs[:300] #keeps a free cpu quick
262
  wc = [len(s.split()) for s in segs]
263
+ long = sum(w > MAX_WORDS for w in wc)
264
+ if long:
265
+ #one "sentence" over 300 words (tables, references, no full stops) can't be split, bert only reads the first 512 tokens
266
+ note += (f"<br><span class='small'>{long} segment{'s are' if long != 1 else ' is'} over {MAX_WORDS} words because the text "
267
+ f"has very long runs with no full stop, BERT only reads the first 512 tokens of those.</span>")
268
  s4 = (f"<h4>4. Segmenting</h4><b>{len(segs)} segment{"s" if len(segs) != 1 else ""}</b>, {min(wc)} to {max(wc)} words each{note}<br><br>" +
269
  "".join(f"<div class='seg'><b>#{i + 1}</b> ({wc[i]} words) {html.escape(s[:220])}{'...' if len(s) > 220 else ''}</div>"
270
  for i, s in enumerate(segs[:3])) +
 
274
  v = np.array([vader_flags(s) for s in segs])
275
  t = tfidf_probs(segs)
276
  b = bert_probs(segs)
277
+ n = len(segs)
278
  rows = ""
279
  for i, c in enumerate(CATEGORIES):
280
+ counts = [int(v[:, i].sum()), int((t[:, i] >= 0.5).sum()), int((b[:, i] >= BERT_THRESHOLDS[c]).sum())]
281
+ cells = "".join(bar(k, n, col) for k, col in zip(counts, ["#7c86a8", "#38bdf8", "#818cf8"]))
282
+ rows += f"<tr><td>{NAMES[c]}</td>{cells}<td>{meter(b[:, i].max(), BERT_THRESHOLDS[c])}</td></tr>"
283
+ s5 = (f"<h4>5. Classification: all three models</h4>"
284
+ f"<table><tr><th>Category</th><th>VADER</th><th>TF-IDF</th><th>BERT + LoRA</th><th>BERT top score vs threshold</th></tr>{rows}</table>"
285
+ f"<p class='small'>Segments flagged out of {n}. White line = BERT threshold, the bar fills to the top segment score "
286
+ f"(indigo if it passes). BERT is my final model. A research prototype, it flags passages for a person to read "
287
+ f"and does not diagnose anyone.</p>")
288
 
289
  order = np.argsort(-b.max(axis=1)) #strongest segments first for shap
290
  choices = [f"#{k + 1} (BERT max {b[k].max():.2f}) {segs[k][:60]}..." for k in order]
 
319
  .gradio-container {background: radial-gradient(ellipse at top, #141b33 0%, #05070f 70%) !important;}
320
  * {box-shadow: none !important;}
321
  .seg {border: 1px solid #ffffff44; border-radius: 12px; padding: 8px 12px; margin: 6px 0; color: #e6ebff;}
322
+ table {width: 100%; border-collapse: collapse; border: none !important; color: #e6ebff;}
323
+ th, td {border: none !important; border-bottom: 1px solid #ffffff33 !important; padding: 6px 8px; text-align: left;}
324
  .small {color: #9aa4c4; font-size: 13px;}
325
+ .cell {display: flex; align-items: center; gap: 8px;}
326
+ .bar {flex: 1; min-width: 40px; height: 6px; background: #ffffff14; border-radius: 3px; overflow: hidden;}
327
+ .bar span {display: block; height: 100%;}
328
+ .meter {position: relative; flex: 1; min-width: 80px; height: 8px; background: #ffffff14; border-radius: 4px;}
329
+ .meter .fill {position: absolute; left: 0; top: 0; bottom: 0; border-radius: 4px;}
330
+ .meter .tick {position: absolute; top: -4px; bottom: -4px; width: 2px; background: #fff;}
331
  """
332
 
333
  with gr.Blocks(title="SPACEMIND") as demo: