RJ3vans commited on
Commit
d22063a
·
verified ·
1 Parent(s): 4e01283

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +30 -164
app.py CHANGED
@@ -1685,8 +1685,9 @@ def subject_is_singular(subj_token) -> bool:
1685
 
1686
  def fix_subject_verb_agreement(sent: str) -> str:
1687
  """
1688
- Repair singular subject + plural/base present verb after CMN1/SSCCV splits.
1689
- Handles: John are moving → John is moving; John live → John lives.
 
1690
  """
1691
  if not sent or not sent.strip():
1692
  return sent
@@ -1696,47 +1697,25 @@ def fix_subject_verb_agreement(sent: str) -> str:
1696
  if not doc:
1697
  return sent
1698
 
1699
- # ----- identify subject head (prefer nsubj of ROOT) -----
1700
- root = next((t for t in doc if t.dep_ == "ROOT"), doc[0])
1701
- subj = None
1702
- for t in doc:
1703
- if t.dep_ in ("nsubj", "nsubjpass") and (
1704
- t.head == root or t.head.head == root
1705
- ):
1706
- subj = t
1707
- break
1708
- if subj is None:
1709
- for t in doc:
1710
- if t.dep_ in ("nsubj", "nsubjpass"):
1711
- subj = t
1712
- break
1713
-
1714
- # Fallback: first proper/common noun or pronoun
1715
  if subj is None:
1716
- for t in doc:
1717
- if t.tag_ in ("NNP", "NN", "PRP") and t.dep_ not in ("punct",):
1718
- subj = t
1719
- break
1720
  if subj is None:
1721
  return sent
1722
 
1723
- # Coordinated subject → keep plural verb
1724
  if any(t.dep_ == "cc" for t in subj.subtree):
1725
  return sent
1726
-
1727
- plural_pronouns = {"i", "you", "we", "they"}
1728
- if subj.lower_ in plural_pronouns:
1729
  return sent
1730
  if subj.tag_ in ("NNS", "NNPS"):
1731
  return sent
1732
-
1733
- # NNP / NN / singular PRP → singular
1734
- singular = subj.tag_ in ("NNP", "NN", "PRP")
1735
- if not singular:
1736
  return sent
1737
 
1738
  def to_3sg(word: str) -> str:
1739
- lower = word.lower()
1740
  irregular = {
1741
  "are": "is",
1742
  "were": "was",
@@ -1744,80 +1723,39 @@ def fix_subject_verb_agreement(sent: str) -> str:
1744
  "do": "does",
1745
  "go": "goes",
1746
  "live": "lives",
1747
- "move": "moves",
1748
- "am": "is",
1749
  }
1750
- if lower in irregular:
1751
- new = irregular[lower]
1752
- elif lower.endswith(("s", "sh", "ch", "x", "z", "o")):
1753
- new = lower + "es"
1754
- elif lower.endswith("y") and len(lower) > 1 and lower[-2] not in "aeiou":
1755
- new = lower[:-1] + "ies"
1756
  else:
1757
- new = lower + "s"
1758
- if word[0].isupper():
1759
  new = new[0].upper() + new[1:]
1760
  return new
1761
 
1762
- # ----- finite aux or main verb that should agree -----
1763
  target = None
1764
  for t in doc:
1765
- if t.dep_ in ("aux", "auxpass") and t.tag_ in ("VBP", "VB", "VBD"):
1766
- # prefer aux of the main clause
1767
- if t.head == root or t.head.dep_ == "ROOT":
1768
- target = t
1769
- break
1770
  if target is None:
1771
  for t in doc:
1772
- if t.dep_ in ("aux", "auxpass") and t.lower_ in (
1773
- "are", "were", "have", "do", "am"
1774
- ):
1775
  target = t
1776
  break
1777
- if target is None and root.tag_ in ("VBP", "VB"):
1778
- target = root
1779
  if target is None:
1780
- for t in doc:
1781
- if t.tag_ in ("VBP", "VB") and t.lower_ in (
1782
- "are", "were", "have", "do", "live", "go", "move"
1783
- ):
1784
- target = t
1785
- break
1786
-
1787
- if target is not None and target.tag_ != "VBZ":
1788
- if target.lower_ in ("is", "was", "has", "does"):
1789
- pass
1790
- else:
1791
- new = to_3sg(target.text)
1792
- sent = sent[: target.idx] + new + sent[target.idx + len(target.text) :]
1793
- # re-parse if you chain multiple fixes; for one shot this is enough
1794
- return sent
1795
-
1796
- # ----- surface fallback (ungrammatical strings spaCy mis-parses) -----
1797
- # "John are …" / "Mary live …"
1798
- m = re.match(
1799
- r"^((?:The|A|An|His|Her|Their)\s+\w+|[A-Z][\w']*)\s+"
1800
- r"(are|were|have|do|live|move|go|want|need)\b",
1801
- sent,
1802
- flags=re.I,
1803
- )
1804
- if m:
1805
- subj_s, verb = m.group(1), m.group(2)
1806
- # skip if subject looks plural
1807
- if re.search(r"\b(and|&)\b", subj_s, re.I):
1808
- return sent
1809
- if re.search(r"s\s*$", subj_s) and not re.match(
1810
- r"^(His|Her|Their|The|A|An)\s", subj_s, re.I
1811
- ):
1812
- # weak; proper names end without s more often
1813
- pass
1814
- new_verb = to_3sg(verb)
1815
- if verb[0].isupper():
1816
- new_verb = new_verb[0].upper() + new_verb[1:]
1817
- sent = sent[: m.start(2)] + new_verb + sent[m.end(2) :]
1818
 
1819
- return sent
1820
-
1821
  ###############################################################################
1822
 
1823
  ###############################################################################
@@ -2376,78 +2314,6 @@ def build_single_sign_bracketed(tagged_list, mode="ccv"):
2376
 
2377
  ###############################################################################
2378
 
2379
- ###############################################################################
2380
- def fix_subject_verb_agreement(sent: str) -> str:
2381
- """
2382
- If the finite verb is present plural (VBP) but the subject is singular,
2383
- rewrite the verb to singular present (lives, is, has, …).
2384
- """
2385
- doc = nlp(sent)
2386
- if not doc:
2387
- return sent
2388
-
2389
- # Find root verb
2390
- root = None
2391
- for t in doc:
2392
- if t.dep_ == "ROOT" and t.pos_ in ("VERB", "AUX"):
2393
- root = t
2394
- break
2395
- if root is None:
2396
- return sent
2397
-
2398
- # Only repair present non-3sg forms that look plural/base
2399
- if root.tag_ not in ("VBP", "VB"):
2400
- return sent
2401
-
2402
- # Collect nsubj / nsubjpass text
2403
- subj_tokens = [t for t in root.lefts if t.dep_ in ("nsubj", "nsubjpass")]
2404
- if not subj_tokens:
2405
- return sent
2406
-
2407
- subj = subj_tokens[0]
2408
- # Coordinated subject still plural → leave alone
2409
- if any(t.dep_ == "cc" for t in subj.subtree):
2410
- return sent
2411
-
2412
- singular = subj.tag_ in ("NN", "NNP", "PRP") and subj.lower_ not in (
2413
- "i", "you", "we", "they",
2414
- )
2415
- # "I/you" take VBP; don't force -s
2416
- if subj.lower_ in ("i", "you", "we", "they"):
2417
- return sent
2418
- if not singular and subj.tag_ not in ("NN", "NNP"):
2419
- # Heuristic: plural NNS / NNPS → keep verb
2420
- if subj.tag_ in ("NNS", "NNPS"):
2421
- return sent
2422
-
2423
- if not singular and subj.tag_ not in ("NN", "NNP", "PRP"):
2424
- return sent
2425
-
2426
- # Map verb → 3sg present
2427
- irregular = {
2428
- "are": "is", "were": "was", "have": "has", "do": "does",
2429
- "go": "goes", "do": "does",
2430
- }
2431
- lemma = root.lemma_.lower()
2432
- form = root.text
2433
- lower = form.lower()
2434
-
2435
- if lower in irregular:
2436
- new = irregular[lower]
2437
- elif lower.endswith(("s", "sh", "ch", "x", "z", "o")):
2438
- new = lower + "es"
2439
- elif lower.endswith("y") and len(lower) > 1 and lower[-2] not in "aeiou":
2440
- new = lower[:-1] + "ies"
2441
- else:
2442
- new = lower + "s"
2443
-
2444
- if form[0].isupper():
2445
- new = new[0].upper() + new[1:]
2446
-
2447
- # Splice back into the sentence using character offsets
2448
- return sent[: root.idx] + new + sent[root.idx + len(root.text) :]
2449
- ###############################################################################
2450
-
2451
  ###############################################################################
2452
  @spaces.GPU(duration=120)
2453
  def process_text(input_text):
 
1685
 
1686
  def fix_subject_verb_agreement(sent: str) -> str:
1687
  """
1688
+ After CMN1 splits a plural subject, repair the finite verb / aux.
1689
+ The man live … → The man lives …
1690
+ The man are going … → The man is going …
1691
  """
1692
  if not sent or not sent.strip():
1693
  return sent
 
1697
  if not doc:
1698
  return sent
1699
 
1700
+ # --- subject: first nsubj, else first noun ---
1701
+ subj = next((t for t in doc if t.dep_ in ("nsubj", "nsubjpass")), None)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1702
  if subj is None:
1703
+ subj = next((t for t in doc if t.tag_ in ("NN", "NNP", "PRP")), None)
 
 
 
1704
  if subj is None:
1705
  return sent
1706
 
1707
+ # Coordinated subject still plural
1708
  if any(t.dep_ == "cc" for t in subj.subtree):
1709
  return sent
1710
+ if subj.lower_ in {"i", "you", "we", "they"}:
 
 
1711
  return sent
1712
  if subj.tag_ in ("NNS", "NNPS"):
1713
  return sent
1714
+ if subj.tag_ not in ("NN", "NNP", "PRP"):
 
 
 
1715
  return sent
1716
 
1717
  def to_3sg(word: str) -> str:
1718
+ low = word.lower()
1719
  irregular = {
1720
  "are": "is",
1721
  "were": "was",
 
1723
  "do": "does",
1724
  "go": "goes",
1725
  "live": "lives",
 
 
1726
  }
1727
+ if low in irregular:
1728
+ new = irregular[low]
1729
+ elif low.endswith(("s", "sh", "ch", "x", "z", "o")):
1730
+ new = low + "es"
1731
+ elif low.endswith("y") and len(low) > 1 and low[-2] not in "aeiou":
1732
+ new = low[:-1] + "ies"
1733
  else:
1734
+ new = low + "s"
1735
+ if word[:1].isupper():
1736
  new = new[0].upper() + new[1:]
1737
  return new
1738
 
1739
+ # Prefer agreeing AUX (are going, have gone, …)
1740
  target = None
1741
  for t in doc:
1742
+ if t.dep_ in ("aux", "auxpass") and t.lower_ in {
1743
+ "are", "were", "have", "do", "am"
1744
+ }:
1745
+ target = t
1746
+ break
1747
  if target is None:
1748
  for t in doc:
1749
+ if t.tag_ in ("VBP", "VB") and t.lower_ not in {"to"}:
 
 
1750
  target = t
1751
  break
 
 
1752
  if target is None:
1753
+ return sent
1754
+ if target.lower_ in {"is", "was", "has", "does"}:
1755
+ return sent
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1756
 
1757
+ new = to_3sg(target.text)
1758
+ return sent[: target.idx] + new + sent[target.idx + len(target.text) :]
1759
  ###############################################################################
1760
 
1761
  ###############################################################################
 
2314
 
2315
  ###############################################################################
2316
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2317
  ###############################################################################
2318
  @spaces.GPU(duration=120)
2319
  def process_text(input_text):