Spaces:
Sleeping
Sleeping
| """ | |
| Prepare dataset for fine-tuning: read cleaned JSONL, optionally apply prompt formatting, | |
| create train/val/test splits (stratified if labels exist), and write HF-compatible JSON/JSONL. | |
| Usage (bash): | |
| python scripts/prepare_dataset.py --cleaned data/cleaned/cleaned_extracted_text.jsonl --out_dir data/prepared_run | |
| """ | |
| import argparse | |
| import json | |
| import os | |
| from collections import Counter | |
| from sklearn.model_selection import train_test_split | |
| # Compact prompt template for training (IDs + short names) | |
| COMPACT_PROMPT = ( | |
| "CATEGORIES: 1:MaliciousData 2:Ransomware 3:Marketplace 4:MalwareTools 5:ThreatActor " | |
| "6:VulnIntel 7:InfraOps 8:Credentials 9:SocialEng 10:General\n\nPOST:\n{txt}\n\nCATEGORY_ID:" | |
| ) | |
| def format_prompt(text): | |
| return COMPACT_PROMPT.format(txt=text) | |
| def read_jsonl(path): | |
| with open(path, 'r', encoding='utf-8') as f: | |
| for line in f: | |
| yield json.loads(line) | |
| def main(): | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument('--cleaned', required=True) | |
| parser.add_argument('--out_dir', default='data/prepared_run') | |
| parser.add_argument('--use_prompt', action='store_true') | |
| args = parser.parse_args() | |
| os.makedirs(args.out_dir, exist_ok=True) | |
| samples = list(read_jsonl(args.cleaned)) | |
| print(f"Loaded {len(samples)} cleaned samples") | |
| # If labels exist, create stratified splits | |
| labels = [s.get('label') for s in samples] | |
| has_labels = all([l is not None for l in labels]) | |
| if has_labels: | |
| # map label names to numeric ids | |
| unique = sorted(list(set(labels))) | |
| label2id = {name: i for i, name in enumerate(unique)} | |
| for s in samples: | |
| s['label_id'] = label2id[s['label']] | |
| # stratified split | |
| train, temp = train_test_split(samples, test_size=0.3, stratify=[s['label_id'] for s in samples], random_state=42) | |
| val, test = train_test_split(temp, test_size=0.5, stratify=[s['label_id'] for s in temp], random_state=42) | |
| else: | |
| # no labels: split randomly | |
| train, val_test = train_test_split(samples, test_size=0.3, random_state=42) | |
| val, test = train_test_split(val_test, test_size=0.5, random_state=42) | |
| label2id = {} | |
| # Optionally apply prompt formatting | |
| def maybe_prompt(s): | |
| txt = s['text'] | |
| return format_prompt(txt) if args.use_prompt else txt | |
| def write_jsonl(l, path): | |
| with open(path, 'w', encoding='utf-8') as f: | |
| for s in l: | |
| out = { | |
| 'text': maybe_prompt(s), | |
| } | |
| if 'label_id' in s: | |
| out['label'] = s['label_id'] | |
| f.write(json.dumps(out, ensure_ascii=False) + '\n') | |
| write_jsonl(train, os.path.join(args.out_dir, 'train.jsonl')) | |
| write_jsonl(val, os.path.join(args.out_dir, 'val.jsonl')) | |
| write_jsonl(test, os.path.join(args.out_dir, 'test.jsonl')) | |
| # Write labels mapping | |
| with open(os.path.join(args.out_dir, 'labels.json'), 'w', encoding='utf-8') as f: | |
| json.dump({'label2id': label2id}, f, ensure_ascii=False, indent=2) | |
| print(f"Prepared splits -> train:{len(train)} val:{len(val)} test:{len(test)}") | |
| if __name__ == '__main__': | |
| main() | |