@9000ai/cli 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,183 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import argparse
4
- import json
5
- import sys
6
- from pathlib import Path
7
- from typing import Any
8
-
9
- import requests
10
-
11
- REPO_ROOT = Path(__file__).resolve().parents[2]
12
- HUB_ROOT = REPO_ROOT / "9000AI-hub-9000AI"
13
- if str(HUB_ROOT) not in sys.path:
14
- sys.path.insert(0, str(HUB_ROOT))
15
-
16
- from shared.runner import ( # noqa: E402
17
- ModuleSpec,
18
- configure_stdout_encoding,
19
- load_json_file,
20
- print_json,
21
- request_json,
22
- resolve_api_key,
23
- resolve_base_url,
24
- save_local_config,
25
- )
26
-
27
- SKILL_ROOT = Path(__file__).resolve().parents[1]
28
- MODULE_SPEC = ModuleSpec(
29
- module="video-transcription",
30
- skill_root=SKILL_ROOT,
31
- )
32
-
33
-
34
- def build_parser() -> argparse.ArgumentParser:
35
- parser = argparse.ArgumentParser(description="Video transcription API client")
36
- parser.add_argument("--base-url", default=None)
37
- parser.add_argument("--api-key", default=None)
38
- subparsers = parser.add_subparsers(dest="command", required=True)
39
-
40
- subparsers.add_parser("configure", help="写入本地配置文件")
41
- subparsers.add_parser("whoami", help="查看当前 key 对应的调用方")
42
- subparsers.add_parser("capabilities", help="查看当前 key 已开通的能力")
43
-
44
- submit = subparsers.add_parser("submit", help="提交批量视频转文字任务")
45
- submit.add_argument("--json-file", required=True)
46
-
47
- task = subparsers.add_parser("task", help="查询任务状态")
48
- task.add_argument("--task-id", required=True)
49
-
50
- results = subparsers.add_parser("results", help="查询任务结果")
51
- results.add_argument("--task-id", required=True)
52
-
53
- text = subparsers.add_parser("text", help="只提取转写原文文案")
54
- text.add_argument("--task-id", required=True)
55
-
56
- return parser
57
-
58
-
59
- def _normalize_output(output: object) -> dict[str, Any]:
60
- if isinstance(output, dict):
61
- return output
62
- if isinstance(output, str):
63
- try:
64
- parsed = json.loads(output)
65
- if isinstance(parsed, dict):
66
- return parsed
67
- except json.JSONDecodeError:
68
- return {}
69
- return {}
70
-
71
-
72
- def _fetch_transcription_payload(json_url: str) -> dict[str, Any]:
73
- response = requests.get(json_url, timeout=60)
74
- response.raise_for_status()
75
- payload = response.json()
76
- if not isinstance(payload, dict):
77
- raise SystemExit("转写 JSON 返回格式不是 object")
78
- return payload
79
-
80
-
81
- def main() -> None:
82
- configure_stdout_encoding()
83
- parser = build_parser()
84
- args = parser.parse_args()
85
-
86
- if args.command == "configure":
87
- if not args.base_url or not args.api_key:
88
- raise SystemExit("configure 需要同时传 --base-url 和 --api-key")
89
- save_local_config(MODULE_SPEC, base_url=args.base_url, api_key=args.api_key)
90
- print_json({"message": "配置已写入", "config_path": str(MODULE_SPEC.config_path)})
91
- return
92
-
93
- base_url = resolve_base_url(MODULE_SPEC, args.base_url)
94
- api_key = resolve_api_key(MODULE_SPEC, args.api_key)
95
-
96
- if args.command == "whoami":
97
- print_json(
98
- request_json(MODULE_SPEC, method="GET", base_url=base_url, api_key=api_key, path="/api/v1/auth/me")
99
- )
100
- return
101
-
102
- if args.command == "capabilities":
103
- print_json(
104
- request_json(
105
- MODULE_SPEC,
106
- method="GET",
107
- base_url=base_url,
108
- api_key=api_key,
109
- path="/api/v1/auth/capability-permissions",
110
- )
111
- )
112
- return
113
-
114
- if args.command == "submit":
115
- print_json(
116
- request_json(
117
- MODULE_SPEC,
118
- method="POST",
119
- base_url=base_url,
120
- api_key=api_key,
121
- path="/api/v1/media/batch-video-to-text",
122
- payload=load_json_file(args.json_file),
123
- )
124
- )
125
- return
126
-
127
- if args.command == "task":
128
- print_json(
129
- request_json(
130
- MODULE_SPEC,
131
- method="GET",
132
- base_url=base_url,
133
- api_key=api_key,
134
- path=f"/api/v1/tasks/{args.task_id}",
135
- )
136
- )
137
- return
138
-
139
- if args.command == "results":
140
- print_json(
141
- request_json(
142
- MODULE_SPEC,
143
- method="GET",
144
- base_url=base_url,
145
- api_key=api_key,
146
- path=f"/api/v1/tasks/{args.task_id}/results",
147
- )
148
- )
149
- return
150
-
151
- if args.command == "text":
152
- task_response = request_json(
153
- MODULE_SPEC,
154
- method="GET",
155
- base_url=base_url,
156
- api_key=api_key,
157
- path=f"/api/v1/tasks/{args.task_id}",
158
- )
159
- task_data = task_response.get("data", {}) if isinstance(task_response, dict) else {}
160
- output = _normalize_output(task_data.get("output"))
161
- json_url = output.get("json_url")
162
- if not json_url:
163
- raise SystemExit("当前 task 还没有可用的 json_url,请先确认任务已完成")
164
-
165
- payload = _fetch_transcription_payload(str(json_url))
166
- sentences = ((payload.get("timecodes") or {}).get("sentences") or [])
167
- print_json(
168
- {
169
- "task_id": args.task_id,
170
- "status": task_data.get("status"),
171
- "json_url": json_url,
172
- "text_field": "text",
173
- "sentence_field": "timecodes.sentences[*].text",
174
- "duration_ms": payload.get("duration_ms"),
175
- "sentence_count": len(sentences) if isinstance(sentences, list) else None,
176
- "text": payload.get("text", ""),
177
- }
178
- )
179
- return
180
-
181
-
182
- if __name__ == "__main__":
183
- main()