idnameraj commited on
Commit
6f1b052
·
verified ·
1 Parent(s): 8fc6d4f

Upload 107 files

Browse files
app/pipeline/__pycache__/candidate_validator.cpython-311.pyc CHANGED
Binary files a/app/pipeline/__pycache__/candidate_validator.cpython-311.pyc and b/app/pipeline/__pycache__/candidate_validator.cpython-311.pyc differ
 
app/pipeline/__pycache__/generative.cpython-311.pyc CHANGED
Binary files a/app/pipeline/__pycache__/generative.cpython-311.pyc and b/app/pipeline/__pycache__/generative.cpython-311.pyc differ
 
app/pipeline/__pycache__/orchestrator.cpython-311.pyc CHANGED
Binary files a/app/pipeline/__pycache__/orchestrator.cpython-311.pyc and b/app/pipeline/__pycache__/orchestrator.cpython-311.pyc differ
 
app/pipeline/generative.py CHANGED
@@ -37,7 +37,7 @@ _backend: str | None = None
37
  _backend_kind: str | None = None # seq2seq | causal
38
 
39
  _SYSTEM_REWRITE = (
40
- "You rewrite ONE English sentence with clearly different wording and structure. "
41
  "Output exactly one sentence — no second sentence, no preamble. "
42
  "Keep EVERY claim and the same polarity. "
43
  "Do not flip negatives or antonyms. "
@@ -46,7 +46,8 @@ _SYSTEM_REWRITE = (
46
  "Do not add reasons, examples, education, awareness, routines, "
47
  "workouts, diets, or new facts. "
48
  "Do not summarize or drop content. "
49
- "Do NOT copy the input almost verbatim change words and word order. "
 
50
  "Return only the rewritten sentence."
51
  )
52
 
@@ -56,7 +57,7 @@ _SHARED_RULES = (
56
  "Do not add reasons, education, awareness, routines, workouts, diets, "
57
  "or extra clauses.\n"
58
  "Keep multiword terms intact (e.g. fast food, junk food, physical activity).\n"
59
- "MUST use different wording and structure — never return a near-copy.\n"
60
  "Keep polarity. Preserve names, numbers, dates, and quotations. Correct grammar.\n"
61
  "Return only the rewritten text."
62
  )
@@ -81,22 +82,22 @@ _TONE_PROMPTS: dict[str, str] = {
81
  "Paraphrase:"
82
  ),
83
  "Neutral": (
84
- "Paraphrase this text in clear natural English with clearly different wording.\n"
85
  f"{_SHARED_RULES}\n"
86
  "Keep polarity (e.g. unhealthy stays unhealthy; "
87
  "don't realize stays a lack of awareness — without adding 'education').\n"
88
- "Do not return a grammar-only edit of the same sentence.\n\n"
89
  "Text:\n{text}\n\n"
90
  "Paraphrase:"
91
  ),
92
  }
93
 
94
  _RETRY_PROMPT = (
95
- "Rewrite this as ONE sentence with clearly different wording and structure "
96
  "but the exact same meaning and polarity. Do not add or remove facts. "
97
  "Keep fixed phrases like 'fast food'. "
98
  "Do not invent workouts, diets, or routines. Do not add a second sentence. "
99
- "Do not return a near-copy or grammar-only edit. "
100
  "Tone: {tone}.\n\n"
101
  "Text:\n{text}\n\n"
102
  "Rewrite:"
 
37
  _backend_kind: str | None = None # seq2seq | causal
38
 
39
  _SYSTEM_REWRITE = (
40
+ "You rewrite ONE English sentence with clearly DIFFERENT WORDS. "
41
  "Output exactly one sentence — no second sentence, no preamble. "
42
  "Keep EVERY claim and the same polarity. "
43
  "Do not flip negatives or antonyms. "
 
46
  "Do not add reasons, examples, education, awareness, routines, "
47
  "workouts, diets, or new facts. "
48
  "Do not summarize or drop content. "
49
+ "Do NOT rearrange the same words. Do NOT copy almost verbatim. "
50
+ "Replace verbs, adverbs, and phrases with natural synonyms. "
51
  "Return only the rewritten sentence."
52
  )
53
 
 
57
  "Do not add reasons, education, awareness, routines, workouts, diets, "
58
  "or extra clauses.\n"
59
  "Keep multiword terms intact (e.g. fast food, junk food, physical activity).\n"
60
+ "MUST use different wording — never rearrange the same words only.\n"
61
  "Keep polarity. Preserve names, numbers, dates, and quotations. Correct grammar.\n"
62
  "Return only the rewritten text."
63
  )
 
82
  "Paraphrase:"
83
  ),
84
  "Neutral": (
85
+ "Paraphrase this text in clear natural English using different words.\n"
86
  f"{_SHARED_RULES}\n"
87
  "Keep polarity (e.g. unhealthy stays unhealthy; "
88
  "don't realize stays a lack of awareness — without adding 'education').\n"
89
+ "Do not return a grammar-only edit or a shuffle of the same words.\n\n"
90
  "Text:\n{text}\n\n"
91
  "Paraphrase:"
92
  ),
93
  }
94
 
95
  _RETRY_PROMPT = (
96
+ "Rewrite this as ONE sentence using DIFFERENT WORDS (not a word shuffle) "
97
  "but the exact same meaning and polarity. Do not add or remove facts. "
98
  "Keep fixed phrases like 'fast food'. "
99
  "Do not invent workouts, diets, or routines. Do not add a second sentence. "
100
+ "Do not return a near-copy, grammar-only edit, or rearranged same words. "
101
  "Tone: {tone}.\n\n"
102
  "Text:\n{text}\n\n"
103
  "Rewrite:"
app/pipeline/orchestrator.py CHANGED
@@ -177,7 +177,7 @@ def _paraphrase_hard_ok(source_unit: str, trial: str) -> bool:
177
  def _is_true_rewrite(source_unit: str, candidate: str) -> bool:
178
  """True rewrite = different wording, not grammar-fix or clause shuffle.
179
 
180
- Pure reorder / template edits keep almost the same content stems and must fail.
181
  """
182
  src = (source_unit or "").strip()
183
  cand = (candidate or "").strip()
@@ -185,18 +185,32 @@ def _is_true_rewrite(source_unit: str, candidate: str) -> bool:
185
  return False
186
  if cand.lower().rstrip(".!?") == src.lower().rstrip(".!?"):
187
  return False
 
 
 
 
 
188
  if not _paraphrase_hard_ok(src, cand):
189
  return False
190
  sim = _similarity_ratio(src, cand)
191
  jacc = _stem_jaccard(src, cand)
192
- # Same bag of content words reorder/template only (user complaint)
193
- if jacc >= 0.92:
194
  return False
195
- if sim > 0.90:
196
  return False
197
  return True
198
 
199
 
 
 
 
 
 
 
 
 
 
200
  def _safe_paraphrase_trial(source_unit: str, trial: str) -> tuple[bool, float]:
201
  """Return (is_true_rewrite, surface_sim)."""
202
  t = (trial or "").strip()
@@ -212,7 +226,12 @@ def _rewrite_score(source_unit: str, candidate: str) -> float:
212
  """Higher = more different while still usable (lower sim + lower stem overlap)."""
213
  sim = _similarity_ratio(source_unit, candidate)
214
  jacc = _stem_jaccard(source_unit, candidate)
215
- return (1.0 - sim) + 0.75 * (1.0 - jacc)
 
 
 
 
 
216
 
217
 
218
  # Phrase-level meaning-preserving rewrites (change wording, not just order).
@@ -254,6 +273,18 @@ _PHRASE_REWRITES: tuple[tuple[re.Pattern[str], str], ...] = (
254
  (re.compile(r"\bkeeps our body fit\b", re.I), "helps the body stay fit"),
255
  (re.compile(r"\bfind it harder to\b", re.I), "struggle more to"),
256
  (re.compile(r"\binstead of\b", re.I), "rather than"),
 
 
 
 
 
 
 
 
 
 
 
 
257
  )
258
 
259
 
@@ -303,9 +334,10 @@ def _esl_structural_variants(text: str) -> list[str]:
303
  if m:
304
  topic = m.group(1).strip().rstrip(".!?")
305
  if topic:
306
- out.append(f"{_cap_first(topic)} also matters a lot{end}")
307
- out.append(f"Getting {_lower_first(topic)} is also important{end}")
308
- out.append(f"{_cap_first(topic)} deserves attention too{end}")
 
309
 
310
  m = re.match(r"^Without enough\s+(\w+),\s*(.+)$", core, flags=re.I)
311
  if m:
@@ -382,8 +414,8 @@ _SAFE_SURFACE_SWAPS: tuple[tuple[re.Pattern[str], str], ...] = (
382
  (re.compile(r"\bhelp communities\b", re.I), "support communities"),
383
  )
384
 
385
- _VISIBLE_TARGET_SIM = 0.85
386
- _LM_SHIP_MAX_SIM = 0.88
387
 
388
 
389
  def _surface_humanize_variants(text: str, rng: random.Random) -> list[str]:
@@ -891,7 +923,11 @@ def _hybrid_rewrite(
891
  by_para.setdefault(unit.paragraph_index, []).append(cand_u)
892
  continue
893
  safe = _safe_classical_unit(src_u, cand_u)
894
- if safe == src_u:
 
 
 
 
895
  stats.reverted_source += 1
896
  else:
897
  stats.classical_kept += 1
 
177
  def _is_true_rewrite(source_unit: str, candidate: str) -> bool:
178
  """True rewrite = different wording, not grammar-fix or clause shuffle.
179
 
180
+ Pure reorder of the same words must fail (e.g. Ram/school shuffle example).
181
  """
182
  src = (source_unit or "").strip()
183
  cand = (candidate or "").strip()
 
185
  return False
186
  if cand.lower().rstrip(".!?") == src.lower().rstrip(".!?"):
187
  return False
188
+ # Same content-word bag → reorder only (not a complete rewrite)
189
+ src_bag = _content_word_bag(src)
190
+ cand_bag = _content_word_bag(cand)
191
+ if src_bag and src_bag == cand_bag:
192
+ return False
193
  if not _paraphrase_hard_ok(src, cand):
194
  return False
195
  sim = _similarity_ratio(src, cand)
196
  jacc = _stem_jaccard(src, cand)
197
+ # Near-identical stem setnot enough wording change
198
+ if jacc >= 0.88:
199
  return False
200
+ if sim > 0.88:
201
  return False
202
  return True
203
 
204
 
205
+ def _content_word_bag(text: str) -> frozenset[str]:
206
+ """Lowercased content words (len≥4), for detecting same-word shuffles."""
207
+ return frozenset(
208
+ w.strip("'")
209
+ for w in re.findall(r"[a-zA-Z']+", (text or "").lower())
210
+ if len(w.strip("'")) >= 4
211
+ )
212
+
213
+
214
  def _safe_paraphrase_trial(source_unit: str, trial: str) -> tuple[bool, float]:
215
  """Return (is_true_rewrite, surface_sim)."""
216
  t = (trial or "").strip()
 
226
  """Higher = more different while still usable (lower sim + lower stem overlap)."""
227
  sim = _similarity_ratio(source_unit, candidate)
228
  jacc = _stem_jaccard(source_unit, candidate)
229
+ bag_bonus = (
230
+ 0.15
231
+ if _content_word_bag(source_unit) != _content_word_bag(candidate)
232
+ else 0.0
233
+ )
234
+ return (1.0 - sim) + 0.85 * (1.0 - jacc) + bag_bonus
235
 
236
 
237
  # Phrase-level meaning-preserving rewrites (change wording, not just order).
 
273
  (re.compile(r"\bkeeps our body fit\b", re.I), "helps the body stay fit"),
274
  (re.compile(r"\bfind it harder to\b", re.I), "struggle more to"),
275
  (re.compile(r"\binstead of\b", re.I), "rather than"),
276
+ # General complete-rewrite lexical swaps (not reorder)
277
+ (re.compile(r"\bwent to\b", re.I), "headed to"),
278
+ (re.compile(r"\bgo to\b", re.I), "head to"),
279
+ (re.compile(r"\bgoes to\b", re.I), "heads to"),
280
+ (re.compile(r"\bhappily\b", re.I), "cheerfully"),
281
+ (re.compile(r"\bquickly\b", re.I), "in a hurry"),
282
+ (re.compile(r"\bslowly\b", re.I), "at a slow pace"),
283
+ (re.compile(r"\byesterday\b", re.I), "the day before"),
284
+ (re.compile(r"\btomorrow\b", re.I), "the next day"),
285
+ (re.compile(r"\bstarted\b", re.I), "began"),
286
+ (re.compile(r"\bfinished\b", re.I), "completed"),
287
+ (re.compile(r"\bhelped\b", re.I), "assisted"),
288
  )
289
 
290
 
 
334
  if m:
335
  topic = m.group(1).strip().rstrip(".!?")
336
  if topic:
337
+ # Keep topic head "thing" so topic_anchor passes; change other wording
338
+ out.append(f"{_cap_first(topic)} remains an important thing{end}")
339
+ out.append(f"{_cap_first(topic)} is still an important thing{end}")
340
+ out.append(f"A further important thing is {_lower_first(topic)}{end}")
341
 
342
  m = re.match(r"^Without enough\s+(\w+),\s*(.+)$", core, flags=re.I)
343
  if m:
 
414
  (re.compile(r"\bhelp communities\b", re.I), "support communities"),
415
  )
416
 
417
+ _VISIBLE_TARGET_SIM = 0.82
418
+ _LM_SHIP_MAX_SIM = 0.85
419
 
420
 
421
  def _surface_humanize_variants(text: str, rng: random.Random) -> list[str]:
 
923
  by_para.setdefault(unit.paragraph_index, []).append(cand_u)
924
  continue
925
  safe = _safe_classical_unit(src_u, cand_u)
926
+ if strength >= 1 and len(src_u.split()) >= 4:
927
+ safe = _require_visible_rewrite(
928
+ src_u, safe, tone, rng, target_sim=_VISIBLE_TARGET_SIM
929
+ )
930
+ if _similarity_ratio(src_u, safe) > 0.92:
931
  stats.reverted_source += 1
932
  else:
933
  stats.classical_kept += 1
scripts/test_phase_a_guards.py CHANGED
@@ -152,6 +152,35 @@ def test_exercise_tv_must_not_be_reorder_only() -> None:
152
  print(" stats", stats)
153
 
154
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  def test_rejects_hollow_ons_bills() -> None:
156
  src = (
157
  "People should save money for emergencies instead of spending every paycheck."
@@ -464,6 +493,7 @@ if __name__ == "__main__":
464
  test_skip_short_and_light()
465
  test_sleep_style_must_visibly_rewrite()
466
  test_exercise_tv_must_not_be_reorder_only()
 
467
  test_rejects_hollow_ons_bills()
468
  test_assembly_preserves_unit_count()
469
  test_live_bug_patterns_rejected()
 
152
  print(" stats", stats)
153
 
154
 
155
+ def test_complete_wording_rewrite_not_shuffle() -> None:
156
+ """Complete rewrite = new words; same-word shuffle must not count."""
157
+ import random
158
+
159
+ from app.pipeline.orchestrator import (
160
+ _content_word_bag,
161
+ _is_true_rewrite,
162
+ _require_visible_rewrite,
163
+ _similarity_ratio,
164
+ )
165
+
166
+ src = "Ram went to school yesterday happily."
167
+ shuffle = "Yesterday, Ram happily went to school."
168
+ assert not _is_true_rewrite(src, shuffle), "word shuffle must fail"
169
+ assert _content_word_bag(src) == _content_word_bag(shuffle)
170
+
171
+ out = _require_visible_rewrite(
172
+ src, src, "Neutral", random.Random(5), target_sim=0.82
173
+ )
174
+ assert _is_true_rewrite(src, out), out
175
+ assert _content_word_bag(src) != _content_word_bag(out)
176
+ assert "ram" in out.lower()
177
+ assert "school" in out.lower()
178
+ # Should use different wording (headed/cheerfully/day before), not shuffle
179
+ assert "yesterday, ram happily went" not in out.lower()
180
+ assert _similarity_ratio(src, out) < 0.90
181
+ print("Ram complete wording rewrite OK:", out)
182
+
183
+
184
  def test_rejects_hollow_ons_bills() -> None:
185
  src = (
186
  "People should save money for emergencies instead of spending every paycheck."
 
493
  test_skip_short_and_light()
494
  test_sleep_style_must_visibly_rewrite()
495
  test_exercise_tv_must_not_be_reorder_only()
496
+ test_complete_wording_rewrite_not_shuffle()
497
  test_rejects_hollow_ons_bills()
498
  test_assembly_preserves_unit_count()
499
  test_live_bug_patterns_rejected()