Metadata-Version: 2.4
Name: omnidoc
Version: 0.1.2
Summary: OmniDoc 开放 API 的 Python 客户端
Project-URL: Homepage, https://omnidoc.top/
Project-URL: Documentation, https://docs.omnidoc.top/
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Operating System :: OS Independent
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: requests>=2.31
Provides-Extra: test
Requires-Dist: pytest>=8; extra == "test"

# omnidoc（Python）

OmniDoc 开放 API 的 Python 客户端：上传文件、创建翻译任务、等待结果、下载产物，并提供积分查询和 Webhook 验签。

- 官网：<https://omnidoc.top/>
- 接口文档：<https://docs.omnidoc.top/>

（注意：这个包直接调用上面的 API，需要 OmniDoc 账号和 API Key。）

## 安装

发布到 PyPI 之前，可以从源码安装：

```bash
pip install ./libs/omnidoc-python
```

发布后使用 `pip install omnidoc`。

依赖只有 `requests`，需要 Python 3.9 或更新版本。

## 快速开始

在环境变量里设置 API Key（以 `sk_` 开头，在 API 中心创建）：

```bash
export OMNIDOC_API_KEY="sk_your_key"
```

```python
from omnidoc import OmniDocClient

client = OmniDocClient()  # 读取 OMNIDOC_API_KEY
files = client.translate_file("report.docx", "en", output_dir="out")
print(files)
```

`translate_file` 会依次完成：上传（presign → 直传 → finalize）、创建翻译任务、轮询直到结束、下载全部产物。任务失败时抛出 `JobFailedError`，`quota_exceeded` 为 True 表示余额不足，未扣费。

## 分步调用

```python
doc_id = client.upload("report.docx")
job = client.create_job(doc_id, "en", output_mode="bilingual", engine="xr-397b")
job = client.wait_job(job["id"], poll_interval=3, timeout=1800)
for artifact in client.list_artifacts(job["id"]):
    client.download_artifact(artifact["id"], "out", fallback_name=f"{artifact['id']}.{artifact.get('format', 'bin')}")
```

`create_job` 每次调用会生成新的 `Idempotency-Key`；内部重试沿用同一个键，不会重复创建或扣费。需要自己重试同一次提交时，传入相同的 `idempotency_key`。

## 查询与其他接口

```python
client.get_job(job_id)           # 任务状态（不扣积分）
client.cancel_job(job_id)        # 取消任务
client.credit_balance()          # 积分余额（不扣积分）
client.credit_operations()       # 积分流水
client.usage_summary()           # 用量汇总

# 尚未封装的接口，按 docs.omnidoc.top 上的路径直接调用：
client.get_json("<路径>", params={...})
client.post_json("<路径>", json={...})
```

## 错误与重试

- API 错误统一抛出 `OmniDocError`，带有 `status_code`、`code`、`message` 与 `request_id`（对应响应头 `X-Request-Id`）。
- 429 与 5xx 会按 `Retry-After` 或指数退避重试，最多 `max_retries` 次（默认 4）。
- `AUTH_API_KEY_QUOTA_EXCEEDED` 不重试：该 Key 的预算已用尽，需要先调高预算。

## Webhook 验签

```python
from omnidoc import parse_webhook

event = parse_webhook(raw_body, request.headers["X-Webhook-Signature"], secret)
```

必须使用收到的原始请求体字节验签。签名或时间戳不符时抛出 `ValueError`。接收端还应按 `data.job_id` 与 `data.status` 去重。

## 安全

- Key 只在服务端或受控环境保存，不要写进源码、日志或公开仓库。
- Key 只发送给 API 地址，不会发送给直传的 `upload_url`。

## 开发

```bash
pip install -e ".[test]"
pytest
```

测试使用假的 HTTP 会话，不需要 API Key，也不会访问网络。
