Final final updates to app.py
Browse files
app.py
CHANGED
|
@@ -207,20 +207,6 @@ def read_input(file, text):
|
|
| 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)
|
|
@@ -274,15 +260,14 @@ def analyse(file, text):
|
|
| 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 |
-
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
|
| 284 |
-
f"<
|
| 285 |
-
f"
|
| 286 |
|
| 287 |
order = np.argsort(-b.max(axis=1)) #strongest segments first for shap
|
| 288 |
choices = [f"#{k + 1} (BERT max {b[k].max():.2f}) {segs[k][:60]}..." for k in order]
|
|
@@ -311,21 +296,37 @@ def explain(state, choice, category):
|
|
| 311 |
f"<div class='seg' style='line-height:1.9'>{spans}</div>")
|
| 312 |
|
| 313 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 314 |
# the page
|
| 315 |
|
| 316 |
CSS = """
|
| 317 |
.gradio-container {background: radial-gradient(ellipse at top, #141b33 0%, #05070f 70%) !important;}
|
| 318 |
* {box-shadow: none !important;}
|
| 319 |
.seg {border: 1px solid #ffffff44; border-radius: 12px; padding: 8px 12px; margin: 6px 0; color: #e6ebff;}
|
| 320 |
-
table {width: 100%; border-collapse: collapse;
|
| 321 |
-
th, td {border
|
| 322 |
.small {color: #9aa4c4; font-size: 13px;}
|
| 323 |
-
.cell {display: flex; align-items: center; gap: 8px;}
|
| 324 |
-
.bar {flex: 1; min-width: 40px; height: 6px; background: #ffffff14; border-radius: 3px; overflow: hidden;}
|
| 325 |
-
.bar span {display: block; height: 100%;}
|
| 326 |
-
.meter {position: relative; flex: 1; min-width: 80px; height: 8px; background: #ffffff14; border-radius: 4px;}
|
| 327 |
-
.meter .fill {position: absolute; left: 0; top: 0; bottom: 0; border-radius: 4px;}
|
| 328 |
-
.meter .tick {position: absolute; top: -4px; bottom: -4px; width: 2px; background: #fff;}
|
| 329 |
"""
|
| 330 |
|
| 331 |
with gr.Blocks(title="SPACEMIND") as demo:
|
|
@@ -340,6 +341,16 @@ with gr.Blocks(title="SPACEMIND") as demo:
|
|
| 340 |
clearButton = gr.ClearButton()
|
| 341 |
runButton = gr.Button("Run the pipeline", variant="primary")
|
| 342 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 343 |
#right side: the stages
|
| 344 |
with gr.Column():
|
| 345 |
out1 = gr.Textbox(label="1. Input (word count)")
|
|
|
|
| 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)
|
|
|
|
| 260 |
v = np.array([vader_flags(s) for s in segs])
|
| 261 |
t = tfidf_probs(segs)
|
| 262 |
b = bert_probs(segs)
|
|
|
|
| 263 |
rows = ""
|
| 264 |
for i, c in enumerate(CATEGORIES):
|
| 265 |
+
rows += (f"<tr><td>{NAMES[c]}</td><td>{int(v[:, i].sum())}</td><td>{int((t[:, i] >= 0.5).sum())}</td>"
|
| 266 |
+
f"<td><b>{int((b[:, i] >= BERT_THRESHOLDS[c]).sum())}</b></td><td>{b[:, i].max():.2f} / {BERT_THRESHOLDS[c]:.2f}</td></tr>")
|
| 267 |
+
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>"
|
| 268 |
+
f"<th>BERT top prob / threshold</th></tr>{rows}</table>"
|
| 269 |
+
f"<p class='small'>Numbers are segments flagged out of {len(segs)}. BERT is my final model. "
|
| 270 |
+
f"A research prototype, it flags passages for a person to read and does not diagnose anyone.</p>")
|
| 271 |
|
| 272 |
order = np.argsort(-b.max(axis=1)) #strongest segments first for shap
|
| 273 |
choices = [f"#{k + 1} (BERT max {b[k].max():.2f}) {segs[k][:60]}..." for k in order]
|
|
|
|
| 296 |
f"<div class='seg' style='line-height:1.9'>{spans}</div>")
|
| 297 |
|
| 298 |
|
| 299 |
+
#files for the examiners to try (loose in the space or inside a test_set folder)
|
| 300 |
+
TEST_SET = [("ridesk-12-6-02.txt", "Sally Ride, Shuttle"), ("crippenrl-10-16-12.txt", "Robert Crippen, Shuttle"),
|
| 301 |
+
("whitsonpa-9-6-12.txt", "Peggy Whitson, ISS"), ("pettitdr-8-17-15.pdf", "Donald Pettit, ISS (PDF)"),
|
| 302 |
+
("harttj-4-10-03.txt", "Terry Hart, Shuttle"), ("rossjl-12-4-03.txt", "Jerry Ross, Shuttle"),
|
| 303 |
+
("mullanerm-1-24-03.txt", "Mike Mullane, Shuttle"), ("armstrongna-9-19-01.txt", "Neil Armstrong, Apollo")]
|
| 304 |
+
PIPELINE_TESTS = [("1_WORKS_cover_page_transcript.txt", "Works: transcript with cover page"),
|
| 305 |
+
("2_TEST_one_short_sentence.txt", "Test: one short sentence"),
|
| 306 |
+
("3_TEST_speaker_names_not_in_capitals.txt", "Test: speaker names not in capitals"),
|
| 307 |
+
("4_TEST_curly_apostrophe_in_name.txt", "Test: curly apostrophe in a name"),
|
| 308 |
+
("5_TEST_technical_no_strain.txt", "Test: technical, no strain")]
|
| 309 |
+
|
| 310 |
+
|
| 311 |
+
def find_files(pairs):
|
| 312 |
+
found = []
|
| 313 |
+
for name, label in pairs:
|
| 314 |
+
for folder in [os.path.join(HERE, "test_set"), HERE]:
|
| 315 |
+
if os.path.exists(os.path.join(folder, name)):
|
| 316 |
+
found.append((os.path.join(folder, name), label))
|
| 317 |
+
break
|
| 318 |
+
return found
|
| 319 |
+
|
| 320 |
+
|
| 321 |
# the page
|
| 322 |
|
| 323 |
CSS = """
|
| 324 |
.gradio-container {background: radial-gradient(ellipse at top, #141b33 0%, #05070f 70%) !important;}
|
| 325 |
* {box-shadow: none !important;}
|
| 326 |
.seg {border: 1px solid #ffffff44; border-radius: 12px; padding: 8px 12px; margin: 6px 0; color: #e6ebff;}
|
| 327 |
+
table {width: 100%; border-collapse: collapse; color: #e6ebff;}
|
| 328 |
+
th, td {border-bottom: 1px solid #ffffff33; padding: 6px 8px; text-align: left;}
|
| 329 |
.small {color: #9aa4c4; font-size: 13px;}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 330 |
"""
|
| 331 |
|
| 332 |
with gr.Blocks(title="SPACEMIND") as demo:
|
|
|
|
| 341 |
clearButton = gr.ClearButton()
|
| 342 |
runButton = gr.Button("Run the pipeline", variant="primary")
|
| 343 |
|
| 344 |
+
#held out test astronauts --> the model never saw them in training
|
| 345 |
+
heldOut = find_files(TEST_SET)
|
| 346 |
+
if heldOut:
|
| 347 |
+
gr.Examples([[p] for p, _ in heldOut], inputs=fileInput, example_labels=[l for _, l in heldOut],
|
| 348 |
+
label="Load a transcript from my held-out test set")
|
| 349 |
+
tests = find_files(PIPELINE_TESTS)
|
| 350 |
+
if tests:
|
| 351 |
+
gr.Examples([[p] for p, _ in tests], inputs=fileInput, example_labels=[l for _, l in tests],
|
| 352 |
+
label="Pipeline tests (where it works and where it breaks)")
|
| 353 |
+
|
| 354 |
#right side: the stages
|
| 355 |
with gr.Column():
|
| 356 |
out1 = gr.Textbox(label="1. Input (word count)")
|