RJ3vans commited on
Commit
3be238e
·
verified ·
1 Parent(s): 9544498

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +122 -56
app.py CHANGED
@@ -357,6 +357,11 @@ required_sign_tags = [
357
  # Helper functions (refactored from notebook)
358
  ###############################################################################
359
 
 
 
 
 
 
360
  ###############################################################################
361
  # Third-person (and similar) pronouns that usually need an antecedent.
362
  # Omit I/you/me — deictic, not anaphoric in the same way.
@@ -794,8 +799,8 @@ def highlight_tokens_html(tokens, labels):
794
  ###############################################################################
795
  def highlight_sentence_if_ssccv(sentence):
796
  """
797
- SignTagger -> bracket leftmost SSCCV sign -> SSCCVspanTagger
798
- -> HTML with cognitive/communicative VP spans coloured.
799
  """
800
  sentence = (sentence or "").strip()
801
  if not sentence:
@@ -806,9 +811,10 @@ def highlight_sentence_if_ssccv(sentence):
806
  return html.escape(sentence)
807
 
808
  bracketed = build_single_sign_bracketed(tagged_list, mode="ssccv")
809
- tokens, pos, lemmas, preds = tag_SSCCV_span(bracketed)
 
810
 
811
- # Predictions are already spaCy-aligned by tag_SSCCV_span
812
  return highlight_tokens_html(tokens, preds)
813
  ###############################################################################
814
 
@@ -1883,6 +1889,9 @@ def fix_subject_verb_agreement(sent: str) -> str:
1883
  if not sent or not sent.strip():
1884
  return sent
1885
 
 
 
 
1886
  sent = sent.strip()
1887
  doc = nlp(sent)
1888
  if not doc:
@@ -2393,21 +2402,26 @@ def drop_bracket_tokens(tokens, pos, lemmas, preds):
2393
  ###############################################################################
2394
 
2395
  ###############################################################################
2396
- def build_single_sign_bracketed(tagged_list, mode="ccv"):
2397
  """
2398
  mode = "ccv" → bracket only the rightmost CCV sign
2399
  mode = "cmv1" → bracket only the rightmost CMV1 sign
2400
  mode = "cmn1" → bracket only the rightmost CMN1 sign
2401
- mode = "cln" → bracket only the rightmost CLN sign
2402
  mode = "ssccv" → bracket one relative SSCCV trigger:
2403
  - nested relatives (2+ opens before next ESCCV): innermost
2404
- (rightmost preferred trigger before that ESCCV)
2405
  - coordinated relatives (CCV between opens): leftmost
2406
  - otherwise: leftmost relative trigger
2407
  - fallback: leftmost SSCCV/ESCCV (e.g. bare "that")
2408
  mode = "ssmn" → bracket only the leftmost SSMN sign
 
 
 
 
2409
  """
2410
 
 
 
2411
  def surface_of(item):
2412
  if item.startswith("<M:Y_") and ">" in item:
2413
  start = item.find(">") + 1
@@ -2425,6 +2439,8 @@ def build_single_sign_bracketed(tagged_list, mode="ccv"):
2425
  ssmn_indices = []
2426
 
2427
  for i, item in enumerate(tagged_list):
 
 
2428
  s = str(item)
2429
  if "<M:Y_CCV>" in s or "M:Y_CCV" in s:
2430
  ccv_indices.append(i)
@@ -2442,7 +2458,7 @@ def build_single_sign_bracketed(tagged_list, mode="ccv"):
2442
  ssccv_indices.append(i)
2443
  if "M:Y_SSMN" in s:
2444
  ssmn_indices.append(i)
2445
-
2446
  target = set()
2447
 
2448
  if mode == "ccv" and ccv_indices:
@@ -2458,8 +2474,8 @@ def build_single_sign_bracketed(tagged_list, mode="ccv"):
2458
  target.add(cln_indices[-1])
2459
 
2460
  elif mode == "ssmn" and ssmn_indices:
2461
- target.add(ssmn_indices[0]) # leftmost appositive boundary
2462
-
2463
  elif mode == "ssccv" and ssccv_indices:
2464
  relative_pronouns = {"who", "which", "whom", "whose"}
2465
  preferred = []
@@ -2467,12 +2483,10 @@ def build_single_sign_bracketed(tagged_list, mode="ccv"):
2467
  for i in ssccv_indices:
2468
  surface = surface_of(tagged_list[i]).strip().lower()
2469
 
2470
- # Direct relative pronoun as the tagged sign
2471
  if surface in relative_pronouns:
2472
  preferred.append(i)
2473
  continue
2474
 
2475
- # Punctuation that introduces a relative (e.g. "," before "who")
2476
  if surface in {",", ";", ":"} and i + 1 < len(tagged_list):
2477
  nxt = surface_of(tagged_list[i + 1]).strip().lower()
2478
  if nxt in relative_pronouns or nxt == "that":
@@ -2490,25 +2504,30 @@ def build_single_sign_bracketed(tagged_list, mode="ccv"):
2490
  if len(opens_before_close) >= 2:
2491
  first_open = opens_before_close[0]
2492
  last_open = opens_before_close[-1]
2493
- # CCV between relative openers → coordinated relatives, not nesting
2494
  ccv_between = any(
2495
  first_open < j < last_open for j in ccv_indices
2496
  )
2497
  if ccv_between:
2498
  coordinated = True
2499
- target.add(opens_before_close[0]) # leftmost / whole relative
2500
  else:
2501
  nested = True
2502
- target.add(opens_before_close[-1]) # innermost
2503
 
2504
  if not nested and not coordinated:
2505
- target.add(preferred[0]) # single relative or siblings
2506
  else:
2507
  pure_ssccv = [
2508
- i for i, item in enumerate(tagged_list)
2509
- if "M:Y_SSCCV" in str(item)
 
2510
  ]
2511
- target.add((pure_ssccv or ssccv_indices)[0])
 
 
 
 
 
2512
 
2513
  parts = []
2514
  for i, item in enumerate(tagged_list):
@@ -2525,14 +2544,12 @@ def build_single_sign_bracketed(tagged_list, mode="ccv"):
2525
 
2526
  text = " ".join(parts)
2527
 
2528
- # spacing
2529
  text = re.sub(r"\s+\[([,;:])", r"[\1", text)
2530
  text = re.sub(r"(?<!\[)\[([A-Za-z])", r" [\1", text)
2531
  text = re.sub(r"\[\s+", "[", text)
2532
  text = re.sub(r"\s+\]", "]", text)
2533
  text = re.sub(r"\s+", " ", text).strip()
2534
 
2535
- # merge [, who] / [, which] style
2536
  text = re.sub(
2537
  r"\[([,;:])\]\s+(who|which|that|whom|whose)\b",
2538
  r"[\1 \2]",
@@ -2541,7 +2558,6 @@ def build_single_sign_bracketed(tagged_list, mode="ccv"):
2541
  )
2542
 
2543
  return text
2544
-
2545
  ###############################################################################
2546
 
2547
  ###############################################################################
@@ -2581,11 +2597,9 @@ def process_text(input_text):
2581
  para = re.sub(r"\s+", " ", para).strip()
2582
 
2583
  sents = split_into_sentences(para)
2584
-
2585
  if not sents:
2586
- # continue
2587
- return "No input text.", "No input text."
2588
-
2589
  print(f"Paragraph → {len(sents)} sentence(s):")
2590
  for i, s in enumerate(sents, 1):
2591
  print(f" [{i}] {s}")
@@ -2606,7 +2620,7 @@ def process_text(input_text):
2606
  f"ABORT: exceeded {MAX_ITERS} iterations; "
2607
  f"draining {len(working_set)} item(s) to final"
2608
  )
2609
- while working_set:
2610
  sentence_final.append(
2611
  clean_output(working_set.popleft())
2612
  )
@@ -2655,53 +2669,104 @@ def process_text(input_text):
2655
  "<M:Y_CLN>" in t or "M:Y_CLN" in t for t in tagged_list
2656
  )
2657
 
 
 
 
 
 
 
2658
  if has_ssccv:
2659
- mode = "ssccv"
2660
- xml_tag = "M:Y_SSCCV"
2661
- simplifier = SSCCVsimplify
2662
- span_fn = tag_SSCCV_span
2663
- elif has_ssmn:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2664
  mode = "ssmn"
2665
  xml_tag = "M:Y_SSMN"
2666
  simplifier = SSMNsimplify
2667
  span_fn = tag_SSMN_span
2668
- elif has_ccv:
2669
  mode = "ccv"
2670
  xml_tag = "M:Y_CCV"
2671
  simplifier = CompoundSimplify
2672
  span_fn = tag_CCV_span
2673
- elif has_cmv1:
2674
  mode = "cmv1"
2675
  xml_tag = "M:Y_CMV1"
2676
  simplifier = CompoundSimplify
2677
  span_fn = tag_CMV1_span
2678
- elif has_cmn1:
2679
  mode = "cmn1"
2680
  xml_tag = "M:Y_CMN1"
2681
  simplifier = CompoundSimplify
2682
  span_fn = tag_CMN1_span
2683
- elif has_cln:
2684
  mode = "cln"
2685
  xml_tag = "M:Y_CLN"
2686
  simplifier = CompoundSimplify
2687
  span_fn = tag_CLN_span
2688
- else:
2689
  sentence_final.append(current)
2690
  continue
2691
 
2692
- bracketed_version = build_single_sign_bracketed(
2693
- tagged_list, mode=mode
2694
- )
2695
-
2696
- print(f"\nProcessing: {current}")
2697
- print(f"Bracketed version ({mode}): {bracketed_version}")
2698
-
2699
- cleaned = clean_for_spaCy(bracketed_version)
2700
- tokens, pos, lemmas, preds = span_fn(cleaned)
2701
-
2702
- tokens, pos, lemmas, preds = drop_bracket_tokens(
2703
- tokens, pos, lemmas, preds
2704
- )
 
 
 
2705
 
2706
  cleaned_tokens, clean_pos, clean_lemmas, cleaned_preds = (
2707
  sign_cleaning(tokens, pos, lemmas, preds)
@@ -2721,7 +2786,6 @@ def process_text(input_text):
2721
  if simps:
2722
  simps = [fix_subject_verb_agreement(s) for s in simps]
2723
 
2724
- # Residual comma → same conjunction (CCV / CMV1 / CMN1 / CLN only)
2725
  if (
2726
  simps
2727
  and simplifier is CompoundSimplify
@@ -2741,10 +2805,8 @@ def process_text(input_text):
2741
  rewritten.append(s2)
2742
  simps = rewritten
2743
 
2744
- # Subject–verb agreement after coordinated-NP (CMN1) splits
2745
  if simps and xml_tag == "M:Y_CMN1":
2746
  simps = [fix_subject_verb_agreement(s) for s in simps]
2747
-
2748
 
2749
  if not simps:
2750
  print(
@@ -2793,13 +2855,17 @@ def process_text(input_text):
2793
 
2794
  final_output = "\n\n".join(output_paragraphs)
2795
  print(f"\n=== FINAL OUTPUT ===\n{final_output}")
2796
- highlighted = highlight_final_output(final_output)
2797
- return highlighted
2798
 
2799
  except Exception as e:
2800
  import traceback
 
2801
  print(traceback.format_exc())
2802
- return f'<div class="simp-out">{html.escape("ERROR: " + str(e))}</div>'
 
 
 
 
2803
 
2804
  ###########################################################################
2805
 
 
357
  # Helper functions (refactored from notebook)
358
  ###############################################################################
359
 
360
+ ###############################################################################
361
+ def is_cognitive_communicative_vp(preds):
362
+ return any("COGNITIVE_COMMUNICATIVE_VP" in str(p) for p in (preds or []))
363
+ ###############################################################################
364
+
365
  ###############################################################################
366
  # Third-person (and similar) pronouns that usually need an antecedent.
367
  # Omit I/you/me — deictic, not anaphoric in the same way.
 
799
  ###############################################################################
800
  def highlight_sentence_if_ssccv(sentence):
801
  """
802
+ SignTagger -> bracket one SSCCV sign -> SSCCVspanTagger
803
+ -> HTML with cognitive/communicative VP underlined.
804
  """
805
  sentence = (sentence or "").strip()
806
  if not sentence:
 
811
  return html.escape(sentence)
812
 
813
  bracketed = build_single_sign_bracketed(tagged_list, mode="ssccv")
814
+ if not bracketed:
815
+ return html.escape(sentence)
816
 
817
+ tokens, pos, lemmas, preds = tag_SSCCV_span(bracketed)
818
  return highlight_tokens_html(tokens, preds)
819
  ###############################################################################
820
 
 
1889
  if not sent or not sent.strip():
1890
  return sent
1891
 
1892
+ if re.search(r"\bdo(?:es|ing)?\s+so\b", sentence, flags=re.I):
1893
+ return sentence
1894
+
1895
  sent = sent.strip()
1896
  doc = nlp(sent)
1897
  if not doc:
 
2402
  ###############################################################################
2403
 
2404
  ###############################################################################
2405
+ def build_single_sign_bracketed(tagged_list, mode="ccv", skip_indices=None):
2406
  """
2407
  mode = "ccv" → bracket only the rightmost CCV sign
2408
  mode = "cmv1" → bracket only the rightmost CMV1 sign
2409
  mode = "cmn1" → bracket only the rightmost CMN1 sign
2410
+ mode = "cln" → bracket only the rightmost CLN sign
2411
  mode = "ssccv" → bracket one relative SSCCV trigger:
2412
  - nested relatives (2+ opens before next ESCCV): innermost
 
2413
  - coordinated relatives (CCV between opens): leftmost
2414
  - otherwise: leftmost relative trigger
2415
  - fallback: leftmost SSCCV/ESCCV (e.g. bare "that")
2416
  mode = "ssmn" → bracket only the leftmost SSMN sign
2417
+
2418
+ skip_indices: token offsets already tried and rejected
2419
+ (e.g. SSCCV signs whose span is a cognitive/communicative VP).
2420
+ Returns None if nothing remains to bracket for this mode.
2421
  """
2422
 
2423
+ skip_indices = set(skip_indices or [])
2424
+
2425
  def surface_of(item):
2426
  if item.startswith("<M:Y_") and ">" in item:
2427
  start = item.find(">") + 1
 
2439
  ssmn_indices = []
2440
 
2441
  for i, item in enumerate(tagged_list):
2442
+ if i in skip_indices:
2443
+ continue
2444
  s = str(item)
2445
  if "<M:Y_CCV>" in s or "M:Y_CCV" in s:
2446
  ccv_indices.append(i)
 
2458
  ssccv_indices.append(i)
2459
  if "M:Y_SSMN" in s:
2460
  ssmn_indices.append(i)
2461
+
2462
  target = set()
2463
 
2464
  if mode == "ccv" and ccv_indices:
 
2474
  target.add(cln_indices[-1])
2475
 
2476
  elif mode == "ssmn" and ssmn_indices:
2477
+ target.add(ssmn_indices[0])
2478
+
2479
  elif mode == "ssccv" and ssccv_indices:
2480
  relative_pronouns = {"who", "which", "whom", "whose"}
2481
  preferred = []
 
2483
  for i in ssccv_indices:
2484
  surface = surface_of(tagged_list[i]).strip().lower()
2485
 
 
2486
  if surface in relative_pronouns:
2487
  preferred.append(i)
2488
  continue
2489
 
 
2490
  if surface in {",", ";", ":"} and i + 1 < len(tagged_list):
2491
  nxt = surface_of(tagged_list[i + 1]).strip().lower()
2492
  if nxt in relative_pronouns or nxt == "that":
 
2504
  if len(opens_before_close) >= 2:
2505
  first_open = opens_before_close[0]
2506
  last_open = opens_before_close[-1]
 
2507
  ccv_between = any(
2508
  first_open < j < last_open for j in ccv_indices
2509
  )
2510
  if ccv_between:
2511
  coordinated = True
2512
+ target.add(opens_before_close[0])
2513
  else:
2514
  nested = True
2515
+ target.add(opens_before_close[-1])
2516
 
2517
  if not nested and not coordinated:
2518
+ target.add(preferred[0])
2519
  else:
2520
  pure_ssccv = [
2521
+ i
2522
+ for i, item in enumerate(tagged_list)
2523
+ if i not in skip_indices and "M:Y_SSCCV" in str(item)
2524
  ]
2525
+ pool = pure_ssccv or ssccv_indices
2526
+ if pool:
2527
+ target.add(pool[0])
2528
+
2529
+ if not target:
2530
+ return None
2531
 
2532
  parts = []
2533
  for i, item in enumerate(tagged_list):
 
2544
 
2545
  text = " ".join(parts)
2546
 
 
2547
  text = re.sub(r"\s+\[([,;:])", r"[\1", text)
2548
  text = re.sub(r"(?<!\[)\[([A-Za-z])", r" [\1", text)
2549
  text = re.sub(r"\[\s+", "[", text)
2550
  text = re.sub(r"\s+\]", "]", text)
2551
  text = re.sub(r"\s+", " ", text).strip()
2552
 
 
2553
  text = re.sub(
2554
  r"\[([,;:])\]\s+(who|which|that|whom|whose)\b",
2555
  r"[\1 \2]",
 
2558
  )
2559
 
2560
  return text
 
2561
  ###############################################################################
2562
 
2563
  ###############################################################################
 
2597
  para = re.sub(r"\s+", " ", para).strip()
2598
 
2599
  sents = split_into_sentences(para)
 
2600
  if not sents:
2601
+ continue
2602
+
 
2603
  print(f"Paragraph → {len(sents)} sentence(s):")
2604
  for i, s in enumerate(sents, 1):
2605
  print(f" [{i}] {s}")
 
2620
  f"ABORT: exceeded {MAX_ITERS} iterations; "
2621
  f"draining {len(working_set)} item(s) to final"
2622
  )
2623
+ while working_set:
2624
  sentence_final.append(
2625
  clean_output(working_set.popleft())
2626
  )
 
2669
  "<M:Y_CLN>" in t or "M:Y_CLN" in t for t in tagged_list
2670
  )
2671
 
2672
+ skipped_ssccv = set()
2673
+ mode = xml_tag = None
2674
+ simplifier = span_fn = None
2675
+ bracketed_version = None
2676
+
2677
+ # SSCCV first, but skip cognitive/communicative VPs
2678
  if has_ssccv:
2679
+ while True:
2680
+ bracketed_version = build_single_sign_bracketed(
2681
+ tagged_list,
2682
+ mode="ssccv",
2683
+ skip_indices=skipped_ssccv,
2684
+ )
2685
+ if not bracketed_version:
2686
+ break
2687
+
2688
+ print(f"\nProcessing: {current}")
2689
+ print(
2690
+ f"Bracketed version (ssccv): {bracketed_version}"
2691
+ )
2692
+
2693
+ cleaned = clean_for_spaCy(bracketed_version)
2694
+ tokens, pos, lemmas, preds = tag_SSCCV_span(cleaned)
2695
+ tokens, pos, lemmas, preds = drop_bracket_tokens(
2696
+ tokens, pos, lemmas, preds
2697
+ )
2698
+
2699
+ if is_cognitive_communicative_vp(preds):
2700
+ ssccv_idxs = [
2701
+ i
2702
+ for i, t in enumerate(tagged_list)
2703
+ if "M:Y_SSCCV" in str(t)
2704
+ or "M:Y_ESCCV" in str(t)
2705
+ ]
2706
+ remaining = [
2707
+ i
2708
+ for i in ssccv_idxs
2709
+ if i not in skipped_ssccv
2710
+ ]
2711
+ if remaining:
2712
+ skipped_ssccv.add(remaining[0])
2713
+ print(
2714
+ " Skip SSCCV "
2715
+ "(cognitive/communicative VP)"
2716
+ )
2717
+ continue
2718
+
2719
+ mode = "ssccv"
2720
+ xml_tag = "M:Y_SSCCV"
2721
+ simplifier = SSCCVsimplify
2722
+ span_fn = tag_SSCCV_span
2723
+ break
2724
+
2725
+ if mode is None and has_ssmn:
2726
  mode = "ssmn"
2727
  xml_tag = "M:Y_SSMN"
2728
  simplifier = SSMNsimplify
2729
  span_fn = tag_SSMN_span
2730
+ elif mode is None and has_ccv:
2731
  mode = "ccv"
2732
  xml_tag = "M:Y_CCV"
2733
  simplifier = CompoundSimplify
2734
  span_fn = tag_CCV_span
2735
+ elif mode is None and has_cmv1:
2736
  mode = "cmv1"
2737
  xml_tag = "M:Y_CMV1"
2738
  simplifier = CompoundSimplify
2739
  span_fn = tag_CMV1_span
2740
+ elif mode is None and has_cmn1:
2741
  mode = "cmn1"
2742
  xml_tag = "M:Y_CMN1"
2743
  simplifier = CompoundSimplify
2744
  span_fn = tag_CMN1_span
2745
+ elif mode is None and has_cln:
2746
  mode = "cln"
2747
  xml_tag = "M:Y_CLN"
2748
  simplifier = CompoundSimplify
2749
  span_fn = tag_CLN_span
2750
+ elif mode is None:
2751
  sentence_final.append(current)
2752
  continue
2753
 
2754
+ if mode != "ssccv":
2755
+ bracketed_version = build_single_sign_bracketed(
2756
+ tagged_list, mode=mode
2757
+ )
2758
+ if not bracketed_version:
2759
+ sentence_final.append(current)
2760
+ continue
2761
+ print(f"\nProcessing: {current}")
2762
+ print(
2763
+ f"Bracketed version ({mode}): {bracketed_version}"
2764
+ )
2765
+ cleaned = clean_for_spaCy(bracketed_version)
2766
+ tokens, pos, lemmas, preds = span_fn(cleaned)
2767
+ tokens, pos, lemmas, preds = drop_bracket_tokens(
2768
+ tokens, pos, lemmas, preds
2769
+ )
2770
 
2771
  cleaned_tokens, clean_pos, clean_lemmas, cleaned_preds = (
2772
  sign_cleaning(tokens, pos, lemmas, preds)
 
2786
  if simps:
2787
  simps = [fix_subject_verb_agreement(s) for s in simps]
2788
 
 
2789
  if (
2790
  simps
2791
  and simplifier is CompoundSimplify
 
2805
  rewritten.append(s2)
2806
  simps = rewritten
2807
 
 
2808
  if simps and xml_tag == "M:Y_CMN1":
2809
  simps = [fix_subject_verb_agreement(s) for s in simps]
 
2810
 
2811
  if not simps:
2812
  print(
 
2855
 
2856
  final_output = "\n\n".join(output_paragraphs)
2857
  print(f"\n=== FINAL OUTPUT ===\n{final_output}")
2858
+ return highlight_final_output(final_output)
 
2859
 
2860
  except Exception as e:
2861
  import traceback
2862
+
2863
  print(traceback.format_exc())
2864
+ return (
2865
+ f'<div class="simp-out">'
2866
+ f"{html.escape('ERROR: ' + str(e))}"
2867
+ f"</div>"
2868
+ )
2869
 
2870
  ###########################################################################
2871