# -*- coding: utf-8 -*- """WB feedback summary v1. Python 3, standard library, local files only. Usage: python3 summarize.py input.csv Columns: id,label,text. Labels must already be assigned; this does NOT classify text. Outputs JSON to stdout; invalid input produces stderr and exit status 2. """ import csv import io import json import re import sys from pathlib import Path LABELS = ("物流", "商品", "其他", "待确认") MAX_ROWS = 5000 def summarize(data): text = data.decode("utf-8-sig") reader = csv.reader(io.StringIO(text, newline=""), strict=True) if next(reader, None) != ["id", "label", "text"]: raise ValueError("expected header: id,label,text") seen = set() counts = dict.fromkeys(LABELS, 0) for row in reader: if len(row) != 3: raise ValueError("expected exactly three columns at line %s" % reader.line_num) record_id, label, _ = row if not re.fullmatch(r"[A-Za-z0-9_-]{1,40}", record_id): raise ValueError("invalid id at line %s" % reader.line_num) if record_id in seen: raise ValueError("duplicate id: %s" % record_id) if label not in counts: raise ValueError("unknown label at line %s" % reader.line_num) seen.add(record_id) if len(seen) > MAX_ROWS: raise ValueError("at most 5000 records supported") counts[label] += 1 if not seen: raise ValueError("at least one record required") return {"version": "WB-summary-v1", "total": len(seen), "counts": counts} def main(): if len(sys.argv) != 2: print("usage: python3 summarize.py input.csv", file=sys.stderr) return 2 try: result = summarize(Path(sys.argv[1]).read_bytes()) except (ValueError, UnicodeError, csv.Error, OSError) as exc: print("input rejected: %s" % exc, file=sys.stderr) return 2 print(json.dumps(result, ensure_ascii=False, indent=2)) return 0 if __name__ == "__main__": sys.exit(main())