| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192 |
- import argparse
- import json
- from pathlib import Path
- from zhifu.app import create_app
- from zhifu.modules.knowledge.inference import app as inference_app
- from zhifu.monitoring.api import app as operations_app
- from zhifu.oms.api import create_app as create_oms
- ROOT = Path(__file__).resolve().parents[1]
- OUTPUT = ROOT / "docs" / "api"
- METHODS = {"get", "post", "put", "patch", "delete", "head", "options"}
- def specifications():
- # 只创建应用与 OpenAPI 定义,不启动 lifespan,也不连接数据库或加载模型权重。
- return {
- "openapi.json": create_app().openapi(),
- "oms-openapi.json": create_oms().openapi(),
- "inference-openapi.json": inference_app.openapi(),
- "operations-openapi.json": operations_app.openapi(),
- }
- def catalog(documents):
- lines = [
- "# 接口目录",
- "",
- "由接口定义生成,更新命令:`uv run python scripts/export_openapi.py`。",
- "",
- ]
- for filename, document in documents.items():
- lines.extend(
- [
- f"## {document['info']['title']}",
- "",
- f"字段、参数、响应及错误说明见 [{filename}]({filename})。",
- "",
- "| 方法 | 路径 | 用途 | 认证 | 成功状态 |",
- "|---|---|---|---|---|",
- ]
- )
- for path, methods in document["paths"].items():
- for method, operation in methods.items():
- if method not in METHODS:
- continue
- success = ", ".join(code for code in operation["responses"] if code.startswith("2"))
- schemes = {
- scheme
- for requirement in operation.get("security", [])
- for scheme in requirement
- }
- # 渠道使用各自签名协议,目录与 OpenAPI security 保持一致。
- security = (
- "Standard Webhooks" if "StandardWebhooks" in schemes
- else "HMAC" if "ChannelHMAC" in schemes
- else "Bearer" if schemes else "无"
- )
- lines.append(
- f"| {method.upper()} | `{path}` | {operation['summary']} "
- f"| {security} | {success} |"
- )
- lines.append("")
- return "\n".join(lines)
- def main(check=False):
- documents = specifications()
- artifacts = {
- name: json.dumps(document, ensure_ascii=False, indent=2) + "\n"
- for name, document in documents.items()
- }
- artifacts["routes.md"] = catalog(documents)
- for name, content in artifacts.items():
- destination = OUTPUT / name
- if check:
- if destination.read_text(encoding="utf-8") != content:
- raise RuntimeError(f"接口文档需要更新:{name}")
- else:
- destination.write_text(content, encoding="utf-8")
- print(f"{'checked' if check else 'exported'}: {name}")
- counts = {
- name: sum(method in METHODS for methods in document["paths"].values() for method in methods)
- for name, document in documents.items()
- }
- print(json.dumps(counts))
- if __name__ == "__main__":
- parser = argparse.ArgumentParser(description="导出或核对四类服务的接口文档")
- parser.add_argument("--check", action="store_true")
- main(parser.parse_args().check)
|