| import argparse |
| import csv |
| import json |
| import sys |
| from pathlib import Path |
|
|
| from deployment import load_bundle, load_networks, predict_text |
|
|
|
|
| def read_records(path, text_column): |
| suffix = path.suffix.lower() |
|
|
| if suffix == ".txt": |
| records = [] |
| with path.open(encoding="utf-8") as input_file: |
| for line_number, line in enumerate(input_file, start=1): |
| text = line.strip() |
| if text: |
| records.append({"id": line_number, text_column: text}) |
| return records |
|
|
| if suffix == ".csv": |
| with path.open(encoding="utf-8-sig", newline="") as input_file: |
| records = list(csv.DictReader(input_file)) |
| if records and text_column not in records[0]: |
| raise ValueError( |
| f"CSV does not contain a '{text_column}' column. " |
| f"Available columns: {list(records[0])}" |
| ) |
| return records |
|
|
| if suffix in {".jsonl", ".ndjson"}: |
| records = [] |
| with path.open(encoding="utf-8") as input_file: |
| for line_number, line in enumerate(input_file, start=1): |
| if not line.strip(): |
| continue |
| record = json.loads(line) |
| if not isinstance(record, dict): |
| raise ValueError( |
| f"JSONL line {line_number} must contain an object." |
| ) |
| if text_column not in record: |
| raise ValueError( |
| f"JSONL line {line_number} does not contain " |
| f"'{text_column}'." |
| ) |
| records.append(record) |
| return records |
|
|
| raise ValueError("Input file must be .txt, .csv, .jsonl, or .ndjson.") |
|
|
|
|
| def add_predictions(record, predictions): |
| result = dict(record) |
| for dimension, values in predictions.items(): |
| result[f"{dimension}_probability"] = values["probability"] |
| result[f"{dimension}_prediction"] = values["prediction"] |
| return result |
|
|
|
|
| def write_records(path, records): |
| path.parent.mkdir(parents=True, exist_ok=True) |
| suffix = path.suffix.lower() |
|
|
| if suffix == ".csv": |
| if not records: |
| path.write_text("", encoding="utf-8") |
| return |
| with path.open("w", encoding="utf-8", newline="") as output_file: |
| writer = csv.DictWriter(output_file, fieldnames=list(records[0])) |
| writer.writeheader() |
| writer.writerows(records) |
| return |
|
|
| if suffix in {".jsonl", ".ndjson"}: |
| with path.open("w", encoding="utf-8") as output_file: |
| for record in records: |
| output_file.write(json.dumps(record) + "\n") |
| return |
|
|
| if suffix == ".json": |
| path.write_text(json.dumps(records, indent=2), encoding="utf-8") |
| return |
|
|
| raise ValueError("Output file must be .csv, .json, .jsonl, or .ndjson.") |
|
|
|
|
| def main(): |
| parser = argparse.ArgumentParser( |
| description="Predict personality dimensions from new text." |
| ) |
| parser.add_argument("bundle", help="Path to a saved .pt model bundle.") |
| parser.add_argument( |
| "--text", |
| help="A single text to classify.", |
| ) |
| parser.add_argument( |
| "--input", |
| type=Path, |
| help="Batch input file: .txt, .csv, .jsonl, or .ndjson.", |
| ) |
| parser.add_argument( |
| "--output", |
| type=Path, |
| help="Batch output file: .csv, .json, .jsonl, or .ndjson.", |
| ) |
| parser.add_argument( |
| "--text-column", |
| default="text", |
| help="Text field for CSV/JSONL input (default: text).", |
| ) |
| args = parser.parse_args() |
|
|
| bundle = load_bundle(args.bundle) |
| networks = load_networks(bundle) |
|
|
| if args.input: |
| if args.text is not None: |
| parser.error("--text and --input cannot be used together") |
| if not args.output: |
| parser.error("--output is required with --input") |
| if not args.input.is_file(): |
| parser.error(f"input file does not exist: {args.input}") |
|
|
| try: |
| records = read_records(args.input, args.text_column) |
| results = [] |
| for row_number, record in enumerate(records, start=1): |
| text = record.get(args.text_column) |
| if not isinstance(text, str) or not text.strip(): |
| raise ValueError( |
| f"Row {row_number} has an empty or invalid " |
| f"'{args.text_column}' value." |
| ) |
| results.append( |
| add_predictions( |
| record, |
| predict_text(text, bundle, networks=networks), |
| ) |
| ) |
| write_records(args.output, results) |
| except (OSError, ValueError, json.JSONDecodeError) as error: |
| parser.error(str(error)) |
|
|
| print(f"Wrote {len(results)} prediction(s) to {args.output}") |
| return |
|
|
| if args.output: |
| parser.error("--output can only be used with --input") |
|
|
| text = args.text if args.text is not None else sys.stdin.read() |
| if not text.strip(): |
| parser.error("prediction text cannot be empty") |
|
|
| result = { |
| "dataset": bundle["dataset"], |
| "predictions": predict_text(text, bundle, networks=networks), |
| } |
| print(json.dumps(result, indent=2)) |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|