Thugshake54323's picture
download
raw
4.37 kB
#!/usr/bin/env python3
"""Quality gate for SFT message rows — reject bad assistant targets."""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from sft_pipeline_utils import (
asks_for_code,
assistant_repeats_user_prompt,
has_code,
verification_is_vague,
)
ROOT = Path(__file__).resolve().parent.parent
DEFAULT_INPUT = ROOT / "data" / "train" / "mythos_sft_messages.jsonl"
DEFAULT_CLEAN = ROOT / "data" / "train" / "mythos_sft_messages_clean.jsonl"
DEFAULT_REJECTED = ROOT / "data" / "rejected" / "sft_rejected.jsonl"
def reject_reasons(user: str, assistant: str) -> list[str]:
reasons: list[str] = []
a = str(assistant or "")
u = str(user or "")
if asks_for_code(u) and not has_code(a):
reasons.append("code_request_no_code")
if assistant_repeats_user_prompt(u, a):
reasons.append("repeats_user_prompt")
if "additional targeted edits" in a.lower():
reasons.append("additional_targeted_edits")
if a.startswith("Diagnosis:") and asks_for_code(u):
reasons.append("code_request_starts_with_diagnosis")
if "Diagnosis:" in a and "Implementation:" in a:
impl = a.split("Implementation:", 1)[1].split("Verification:", 1)[0].strip()
if not impl or (not has_code(impl) and len(impl) < 40):
reasons.append("diagnosis_without_implementation")
elif a.startswith("Here is the complete code:"):
code_block = a.split("Here is the complete code:", 1)[1].split("Verification:", 1)[0].strip()
if not code_block or not has_code(code_block):
reasons.append("code_header_without_code")
elif not has_code(a) and asks_for_code(u):
reasons.append("code_request_no_code")
ver_section = ""
if "Verification:" in a:
ver_section = a.split("Verification:", 1)[1].strip()
if asks_for_code(u) and verification_is_vague(ver_section) and has_code(a):
# soft — only reject if verification completely empty
if not ver_section:
reasons.append("missing_verification")
return reasons
def main() -> int:
parser = argparse.ArgumentParser(description="Filter low-quality SFT rows.")
parser.add_argument("--input", default=str(DEFAULT_INPUT))
parser.add_argument("--clean-output", default=str(DEFAULT_CLEAN))
parser.add_argument("--rejected-output", default=str(DEFAULT_REJECTED))
args = parser.parse_args()
input_path = Path(args.input)
clean_path = Path(args.clean_output)
rejected_path = Path(args.rejected_output)
clean_path.parent.mkdir(parents=True, exist_ok=True)
rejected_path.parent.mkdir(parents=True, exist_ok=True)
if not input_path.exists():
print(f"Error: input not found: {input_path}", file=sys.stderr)
return 1
clean: list[dict] = []
rejected: list[dict] = []
with input_path.open("r", encoding="utf-8") as f:
for line_num, line in enumerate(f, 1):
if not line.strip():
continue
row = json.loads(line)
user = row["messages"][1]["content"]
assistant = row["messages"][2]["content"]
reasons = reject_reasons(user, assistant)
if reasons:
rejected.append({
"line": line_num,
"reasons": reasons,
"user_prompt": user,
"assistant_preview": assistant[:600],
"row": row,
})
else:
clean.append(row)
with clean_path.open("w", encoding="utf-8") as f:
for row in clean:
f.write(json.dumps(row, ensure_ascii=False) + "\n")
with rejected_path.open("w", encoding="utf-8") as f:
for item in rejected:
f.write(json.dumps(item, ensure_ascii=False) + "\n")
print(f"Input: {sum(1 for _ in input_path.open(encoding='utf-8') if _.strip())}")
print(f"Clean: {len(clean)} -> {clean_path}")
print(f"Rejected: {len(rejected)} -> {rejected_path}")
if rejected:
from collections import Counter
c = Counter(r for item in rejected for r in item["reasons"])
print("Rejection reasons:", dict(c))
return 0
if __name__ == "__main__":
raise SystemExit(main())

Xet Storage Details

Size:
4.37 kB
·
Xet hash:
4b3b7eaed8beb4d99ef132a92ee695b0d46a13c8a6e775b2bc41b3eb2e8d7f0b

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.