#!/usr/bin/env python3
"""batch_and_sdk_template.py — Message Batches 请求构建 + SDK 调用模板（需 key，静态校验通过）

【需 key】真实调用部分需要 ANTHROPIC_API_KEY；无 key 时输出请求体并做本地校验。

官方约束（截至 2026-08-30，访问于 2026-08-30）:
- 批上限: 100,000 请求 / 256MB；24 小时未完成则过期；结果保留 29 天
- custom_id 规则: ^[a-zA-Z0-9_-]{1,64}$
- 不支持: stream / speed / max_tokens:0 / store 等
来源: https://platform.claude.com/docs/en/build-with-claude/batch-processing

运行: python3 batch_and_sdk_template.py
"""

import json
import re
import sys

CUSTOM_ID_RE = re.compile(r"^[a-zA-Z0-9_-]{1,64}$")

UNSUPPORTED_IN_BATCH = ("stream", "speed", "store", "previous_thread_event_id",
                        "cache_hint", "context_hint")


def validate_batch(requests: list[dict]) -> list[str]:
    """批请求的本地校验（发送前跑）。"""
    problems = []
    if len(requests) > 100_000:
        problems.append(f"批内请求数 {len(requests)} 超过 100,000 上限")
    seen_ids = set()
    for i, r in enumerate(requests):
        cid = r.get("custom_id", "")
        if not CUSTOM_ID_RE.match(cid):
            problems.append(f"[{i}] custom_id {cid!r} 不符合 ^[a-zA-Z0-9_-]{{1,64}}$")
        if cid in seen_ids:
            problems.append(f"[{i}] custom_id {cid!r} 重复（对账会混）")
        seen_ids.add(cid)
        params = r.get("params", {})
        for k in UNSUPPORTED_IN_BATCH:
            if k in params:
                problems.append(f"[{i}] 参数 {k!r} 不支持出现在批请求中")
        mt = params.get("max_tokens")
        if mt is not None and mt < 1:
            problems.append(f"[{i}] 批内 max_tokens 必须 >= 1（max_tokens:0 预热不支持）")
        if "model" not in params or "messages" not in params:
            problems.append(f"[{i}] params 缺 model/messages")
    return problems


def build_batch(items: list[tuple[str, str]], model="claude-sonnet-5") -> dict:
    return {
        "requests": [
            {"custom_id": cid, "params": {
                "model": model, "max_tokens": 512,
                "messages": [{"role": "user", "content": prompt}]}}
            for cid, prompt in items
        ]
    }


if __name__ == "__main__":
    items = [(f"eval-{i:04d}", f"请判断以下客户反馈的情感（第 {i} 条）：产品很好用但物流慢")
             for i in range(3)]
    batch = build_batch(items)

    print("== 批请求体（前 1 条示意）==")
    print(json.dumps({"requests": batch["requests"][:1]}, ensure_ascii=False, indent=2))

    problems = validate_batch(batch["requests"])
    print("\n本地校验:", "通过" if not problems else problems)
    assert not problems

    # 反例：stream 与 max_tokens:0 混入 + 坏 custom_id
    bad = {"requests": [
        {"custom_id": "bad id!", "params": {"model": "claude-sonnet-5", "max_tokens": 0,
                                            "messages": [], "stream": True}},
    ]}
    bad_problems = validate_batch(bad["requests"])
    assert len(bad_problems) >= 3, bad_problems
    print(f"反例拦截: {len(bad_problems)} 个问题被本地校验捕获 ->", bad_problems[:2], "...")

    # --- 以下为需 key 的真实调用模板（静态展示；运行前 pip install anthropic） ---
    print(
        "\n== 真实调用模板（需 ANTHROPIC_API_KEY；此处静态校验，不执行）==\n"
        "import anthropic\n"
        "client = anthropic.Anthropic()\n"
        "b = client.messages.batches.create(requests=batch['requests'])\n"
        "print(b.id, b.status)          # in_progress\n"
        "# 轮询: b = client.messages.batches.retrieve(b.id)；ended 后取结果\n"
        "for r in client.messages.batches.results(b.id):\n"
        "    if r.result.type == 'succeeded':\n"
        "        print(r.custom_id, r.result.message.content)\n"
        "    else:\n"
        "        print(r.custom_id, 'errored/submitterside')\n"
        "\n注: 结果按 custom_id 对账；个别请求可能 errored/expired，批整体 ended 不代表全成功。"
    )
    sys.exit(0)
