@pippit-dev/cli 1.0.0 → 1.0.2
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.
- package/README.md +37 -5
- package/checksums.txt +6 -6
- package/cmd/download_result.go +57 -0
- package/cmd/generate_video/generate_video.go +48 -0
- package/cmd/generate_video/query_result.go +58 -0
- package/cmd/generate_video_test.go +468 -0
- package/cmd/get_thread.go +59 -0
- package/cmd/list_thread_file.go +51 -0
- package/cmd/root.go +30 -1
- package/cmd/short_drama/short_drama.go +12 -133
- package/cmd/short_drama_test.go +76 -49
- package/cmd/update/update.go +8 -8
- package/internal/common/client.go +29 -21
- package/internal/common/download_results.go +21 -15
- package/internal/common/error_log.go +62 -1
- package/internal/common/error_log_test.go +33 -3
- package/internal/common/get_thread.go +29 -15
- package/internal/common/get_thread_test.go +74 -0
- package/internal/common/json.go +18 -0
- package/internal/common/list_thread_file.go +7 -7
- package/internal/common/submit_run.go +29 -0
- package/internal/common/upload_file.go +22 -18
- package/internal/config/config.go +1 -1
- package/internal/generate_video/generate_video.go +199 -0
- package/internal/generate_video/query_result.go +291 -0
- package/internal/generate_video/query_result_test.go +31 -0
- package/internal/short_drama/submit_run.go +8 -28
- package/package.json +1 -1
- package/skills/short-drama/SKILL.md +34 -34
- package/skills/xyq-nest-skill/scripts/download_results.py +3 -1
- package/skills/xyq-nest-skill/scripts/upload_file.py +2 -2
- package/skills/xyq-nest-skill/scripts/xyq_common.py +4 -3
|
@@ -5,7 +5,6 @@ import (
|
|
|
5
5
|
"fmt"
|
|
6
6
|
|
|
7
7
|
"github.com/Pippit-dev/pippit-cli/internal/common"
|
|
8
|
-
"github.com/Pippit-dev/pippit-cli/internal/config"
|
|
9
8
|
)
|
|
10
9
|
|
|
11
10
|
// SubmitRunOptions is the stable command-facing request shape for short drama run submission.
|
|
@@ -22,21 +21,9 @@ type SubmitRunResult struct {
|
|
|
22
21
|
WebThreadLink string `json:"web_thread_link"`
|
|
23
22
|
}
|
|
24
23
|
|
|
25
|
-
type submitRunResponse struct {
|
|
26
|
-
Ret string `json:"ret"`
|
|
27
|
-
Errmsg string `json:"errmsg"`
|
|
28
|
-
Data struct {
|
|
29
|
-
WebThreadLink string `json:"web_thread_link"`
|
|
30
|
-
Run struct {
|
|
31
|
-
ThreadID string `json:"thread_id"`
|
|
32
|
-
RunID string `json:"run_id"`
|
|
33
|
-
} `json:"run"`
|
|
34
|
-
} `json:"data"`
|
|
35
|
-
}
|
|
36
|
-
|
|
37
24
|
func SubmitRun(ctx context.Context, opts *SubmitRunOptions, runner *common.Runner) (*SubmitRunResult, error) {
|
|
38
25
|
if runner == nil || runner.Client == nil {
|
|
39
|
-
return nil, fmt.Errorf("submit_run
|
|
26
|
+
return nil, fmt.Errorf("submit_run 运行器客户端缺失")
|
|
40
27
|
}
|
|
41
28
|
|
|
42
29
|
body := map[string]any{
|
|
@@ -50,21 +37,21 @@ func SubmitRun(ctx context.Context, opts *SubmitRunOptions, runner *common.Runne
|
|
|
50
37
|
}
|
|
51
38
|
body["agent_name"] = "pippit_nest_novel_agent"
|
|
52
39
|
|
|
53
|
-
var resp
|
|
54
|
-
if err := runner.Client.SendRequest(ctx,
|
|
55
|
-
return nil, fmt.Errorf("
|
|
40
|
+
var resp common.SubmitRunResponse
|
|
41
|
+
if err := runner.Client.SendRequest(ctx, common.SubmitRunPath(runner), body, &resp); err != nil {
|
|
42
|
+
return nil, fmt.Errorf("提交 short_drama 请求失败: %w", err)
|
|
56
43
|
}
|
|
57
44
|
if resp.Ret != "0" {
|
|
58
45
|
if resp.Errmsg == "" {
|
|
59
|
-
resp.Errmsg = "
|
|
46
|
+
resp.Errmsg = "未知错误"
|
|
60
47
|
}
|
|
61
|
-
return nil, fmt.Errorf("
|
|
48
|
+
return nil, fmt.Errorf("short_drama 请求返回失败: ret=%s errmsg=%s", resp.Ret, resp.Errmsg)
|
|
62
49
|
}
|
|
63
50
|
if resp.Data.Run.ThreadID == "" {
|
|
64
|
-
return nil, fmt.Errorf("
|
|
51
|
+
return nil, fmt.Errorf("short_drama 响应缺少 data.run.thread_id")
|
|
65
52
|
}
|
|
66
53
|
if resp.Data.Run.RunID == "" {
|
|
67
|
-
return nil, fmt.Errorf("
|
|
54
|
+
return nil, fmt.Errorf("short_drama 响应缺少 data.run.run_id")
|
|
68
55
|
}
|
|
69
56
|
return &SubmitRunResult{
|
|
70
57
|
ThreadID: resp.Data.Run.ThreadID,
|
|
@@ -72,10 +59,3 @@ func SubmitRun(ctx context.Context, opts *SubmitRunOptions, runner *common.Runne
|
|
|
72
59
|
WebThreadLink: resp.Data.WebThreadLink,
|
|
73
60
|
}, nil
|
|
74
61
|
}
|
|
75
|
-
|
|
76
|
-
func submitRunPath(runner *common.Runner) string {
|
|
77
|
-
if runner != nil && runner.Config != nil && runner.Config.Paths != nil && runner.Config.Paths.SubmitRun != "" {
|
|
78
|
-
return runner.Config.Paths.SubmitRun
|
|
79
|
-
}
|
|
80
|
-
return config.SubmitRunPath
|
|
81
|
-
}
|
package/package.json
CHANGED
|
@@ -29,7 +29,7 @@ metadata:
|
|
|
29
29
|
4. **获取会话文件** - 根据 `thread_id` 拉取会话文件列表,得到 `file_path`、`download_url`。这和查询会话进展同等重要。
|
|
30
30
|
5. **下载重要资产** - 使用文件列表中的 `download_url` 下载资源,并按 `file_path` 写入用户本地目标文件路径。
|
|
31
31
|
|
|
32
|
-
重要资产包括但不限于:剧本设计、场景设计、场景图、人物角色设计、人物图、分集草稿、故事板、最终视频产物。只要
|
|
32
|
+
重要资产包括但不限于:剧本设计、场景设计、场景图、人物角色设计、人物图、分集草稿、故事板、最终视频产物。只要 `list-thread-file` 返回了这些资产的 `download_url`,就要及时调用下载工具落盘,不要只展示文件元信息。
|
|
33
33
|
|
|
34
34
|
## 短剧主流程顺序
|
|
35
35
|
|
|
@@ -94,7 +94,7 @@ pippit-tool-cli short-drama +submit-run --message "参考这个大纲写第一
|
|
|
94
94
|
|
|
95
95
|
```bash
|
|
96
96
|
# 查询会话可读进展
|
|
97
|
-
pippit-tool-cli
|
|
97
|
+
pippit-tool-cli get-thread --thread-id THREAD_ID --run-id RUN_ID
|
|
98
98
|
```
|
|
99
99
|
|
|
100
100
|
> `thread_id` 和 `run_id` 由 `+submit-run` 返回。`run_id` 可省略,省略时返回当前 `thread_id` 下的所有 Run;传入时只看指定 Run。
|
|
@@ -121,10 +121,10 @@ pippit-tool-cli short-drama +upload-file --path /path/to/outline.txt
|
|
|
121
121
|
|
|
122
122
|
```bash
|
|
123
123
|
# 获取会话文件列表
|
|
124
|
-
pippit-tool-cli
|
|
124
|
+
pippit-tool-cli list-thread-file --thread-id THREAD_ID --page-num 1 --page-size 200
|
|
125
125
|
```
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
`list-thread-file` 返回的每个文件对象包含:
|
|
128
128
|
|
|
129
129
|
```json
|
|
130
130
|
{
|
|
@@ -134,16 +134,16 @@ pippit-tool-cli short-drama +list-thread-file --thread-id THREAD_ID --page-num 1
|
|
|
134
134
|
}
|
|
135
135
|
```
|
|
136
136
|
|
|
137
|
-
|
|
137
|
+
`list-thread-file` 只负责获取会话文件列表,不负责下载文件,也不需要判断本地文件是否已存在。
|
|
138
138
|
|
|
139
139
|
### 5. 下载文件资源
|
|
140
140
|
|
|
141
141
|
```bash
|
|
142
142
|
# 下载文件资源到指定文件路径
|
|
143
|
-
pippit-tool-cli
|
|
143
|
+
pippit-tool-cli download-result --url DOWNLOAD_URL --output-path FILE_PATH --updated-at UPDATED_AT
|
|
144
144
|
```
|
|
145
145
|
|
|
146
|
-
`FILE_PATH` 必须直接使用
|
|
146
|
+
`FILE_PATH` 必须直接使用 `list-thread-file` 返回的完整 `file_path`,包含文件名,不要取父目录。`UPDATED_AT` 使用同一文件对象返回的 `updated_at`;如果没有 `updated_at`,可省略 `--updated-at`。`download-result` 负责把会话产生的文件通过 URL 下载到该目标文件路径;如果目标文件已存在且本地修改时间不早于 `updated_at`,跳过下载;如果本地文件早于 `updated_at`,覆盖更新。
|
|
147
147
|
|
|
148
148
|
## 典型工作流
|
|
149
149
|
|
|
@@ -154,8 +154,8 @@ pippit-tool-cli short-drama +download-result --url DOWNLOAD_URL --output-path FI
|
|
|
154
154
|
→ 拿到 thread_id、run_id 和 web_thread_link
|
|
155
155
|
2. 立即将 web_thread_link 展示给用户
|
|
156
156
|
3. 并行发起,二者同等重要:
|
|
157
|
-
a. pippit-tool-cli
|
|
158
|
-
b. pippit-tool-cli
|
|
157
|
+
a. pippit-tool-cli get-thread --thread-id THREAD_ID --run-id RUN_ID
|
|
158
|
+
b. pippit-tool-cli list-thread-file --thread-id THREAD_ID --page-num PAGE_NUM --page-size 200
|
|
159
159
|
4. 检查 `get-thread` 返回的 readable_text:
|
|
160
160
|
- 如果任务仍在进行中:展示可读进展,继续查询
|
|
161
161
|
- 如果后端 Agent 提出问题:从 readable_text 中提取问题并展示,等待用户回复
|
|
@@ -163,9 +163,9 @@ pippit-tool-cli short-drama +download-result --url DOWNLOAD_URL --output-path FI
|
|
|
163
163
|
- 对每个文件取 file_path、download_url、updated_at
|
|
164
164
|
- 将 file_path 作为本地目标文件路径,包含文件名
|
|
165
165
|
- 有 download_url 的重要资产:加入本轮下载队列
|
|
166
|
-
- 不判断 file_path 在本地是否已存在,是否跳过由
|
|
166
|
+
- 不判断 file_path 在本地是否已存在,是否跳过由 download-result 内部处理
|
|
167
167
|
- 如果本轮 total 达到 200:下一轮将 PAGE_NUM 加 1,继续查询新一页文件
|
|
168
|
-
6. 对重要资产,立即调用
|
|
168
|
+
6. 对重要资产,立即调用 download-result 并行下载资源:
|
|
169
169
|
- 使用第 5 步获取的 download_url 作为 --url
|
|
170
170
|
- 使用第 5 步获取的完整 file_path 作为 --output-path
|
|
171
171
|
- 如果第 5 步返回 updated_at,作为 --updated-at 传入
|
|
@@ -199,23 +199,23 @@ pippit-tool-cli short-drama +download-result --url DOWNLOAD_URL --output-path FI
|
|
|
199
199
|
## 轮询策略
|
|
200
200
|
|
|
201
201
|
- **间隔**:每 10 秒查询一次。
|
|
202
|
-
- **进展查询**:每轮调用
|
|
203
|
-
- **并行查询**:每次 `+submit-run` 返回 `thread_id` 后,同时发起
|
|
204
|
-
-
|
|
205
|
-
- **重要资产识别**:每轮都检查
|
|
206
|
-
- **文件下载**:解析
|
|
202
|
+
- **进展查询**:每轮调用 `get-thread` 查看 `readable_text`。优先带上本轮 `run_id` 聚焦当前任务;需要查看整个会话时可省略 `--run-id`。
|
|
203
|
+
- **并行查询**:每次 `+submit-run` 返回 `thread_id` 后,同时发起 `get-thread` 和 `list-thread-file`;二者同等重要,不能只查询会话进展而忽略会话文件。
|
|
204
|
+
- **文件分页**:`list-thread-file` 使用 `--page-size 200`。如果本轮返回的 `total` 达到 200,下一轮使用 `--page-num` 加 1 查询新一页结果;如果未达到 200,保持当前页继续轮询新增产物。
|
|
205
|
+
- **重要资产识别**:每轮都检查 `list-thread-file` 返回的文件。剧本设计、场景设计、场景图、人物角色设计、人物图、分集草稿、故事板、最终视频产物都是重要资产。
|
|
206
|
+
- **文件下载**:解析 `list-thread-file` 的结果后,对带 `download_url` 的重要资产立即调用 `download-result` 下载资源;不要在 `list-thread-file` 阶段检查文件是否已存在,存在性检查由下载工具内部处理。
|
|
207
207
|
- **下载完成标准**:不要把文件元信息展示当成下载完成;必须拿到本地 `file_path`,或明确记录该文件在重试后仍下载失败。
|
|
208
208
|
- **用户确认**:如果消息中出现需要用户确认、补充设定或回答问题的内容,先判断是否包含表单、问卷、选项或按钮;包含时按“短剧主流程顺序”和“表单与问卷选项处理原则”清洗选项,再展示给用户并等待回复。
|
|
209
209
|
- **超时**:如果长时间无结果,告知用户任务仍在生成中,可稍后通过 `web_thread_link` 查看。
|
|
210
|
-
-
|
|
210
|
+
- **错误处理**:`get-thread`、`list-thread-file` 或 `download-result` 任一调用失败时,记录失败原因和参数,在后续轮询中主动重试;重试期间继续处理其他成功返回的消息和文件。连续多轮失败后再向用户说明仍未完成的查询或下载项。
|
|
211
211
|
|
|
212
212
|
## 完成标准
|
|
213
213
|
|
|
214
|
-
一次短剧任务不能只以
|
|
214
|
+
一次短剧任务不能只以 `get-thread` 返回的 `readable_text` 作为结束条件。完成前必须同时检查:
|
|
215
215
|
|
|
216
|
-
1. 已处理
|
|
217
|
-
2. 已用 `--page-size 200` 调用
|
|
218
|
-
3. 对所有带 `download_url` 的重要资产,已调用
|
|
216
|
+
1. 已处理 `get-thread` 返回的最新 `readable_text`、用户确认问题和最终消息。
|
|
217
|
+
2. 已用 `--page-size 200` 调用 `list-thread-file` 获取会话文件列表;如果本轮 `total` 达到 200,已在后续轮询中递增 `page-num` 查询新一页。
|
|
218
|
+
3. 对所有带 `download_url` 的重要资产,已调用 `download-result` 下载到本地 `file_path`。
|
|
219
219
|
4. 已按短剧主流程顺序检查服务端表单、问卷和选项,没有把跳过必要阶段的选项直接呈现给用户;如果跳过 `剧本标准化`,已明确这是可选阶段。
|
|
220
220
|
5. 对查询失败或下载失败的资产,已在后续轮询中主动重试,并在最终回复中列出仍失败的文件或命令。
|
|
221
221
|
|
|
@@ -231,7 +231,7 @@ pippit-tool-cli short-drama +download-result --url DOWNLOAD_URL --output-path FI
|
|
|
231
231
|
}
|
|
232
232
|
```
|
|
233
233
|
|
|
234
|
-
|
|
234
|
+
**get-thread** 返回:
|
|
235
235
|
|
|
236
236
|
```text
|
|
237
237
|
Thread: thread_...
|
|
@@ -242,7 +242,7 @@ Thread: thread_...
|
|
|
242
242
|
[assistant] ...
|
|
243
243
|
```
|
|
244
244
|
|
|
245
|
-
|
|
245
|
+
**short-drama +upload-file** 返回:
|
|
246
246
|
|
|
247
247
|
```json
|
|
248
248
|
{
|
|
@@ -252,7 +252,7 @@ Thread: thread_...
|
|
|
252
252
|
|
|
253
253
|
`+upload-file` 通过 `multipart/form-data` 上传文件,表单文件字段名为 `file`。本地文件必须存在、不能是目录,后缀必须是 `.doc`、`.docx` 或 `.txt`;不支持的后缀会直接报错。返回的 `asset_id` 来自服务端 `pippit_asset_id`,如果没有该字段才回退到 `asset_id`。
|
|
254
254
|
|
|
255
|
-
|
|
255
|
+
**list-thread-file** 返回:
|
|
256
256
|
|
|
257
257
|
```json
|
|
258
258
|
{
|
|
@@ -270,7 +270,7 @@ Thread: thread_...
|
|
|
270
270
|
|
|
271
271
|
当 `total` 达到 200 时,`message` 会用 `<system-remind>` 提示下一轮将 `page-num` 加 1 查询新一页。
|
|
272
272
|
|
|
273
|
-
|
|
273
|
+
**download-result** 返回:
|
|
274
274
|
|
|
275
275
|
```json
|
|
276
276
|
{
|
|
@@ -281,16 +281,16 @@ Thread: thread_...
|
|
|
281
281
|
|
|
282
282
|
## 会话文件与资源下载
|
|
283
283
|
|
|
284
|
-
先用
|
|
284
|
+
先用 `list-thread-file` 获取会话文件列表,再用 `download-result` 并行下载重要资产。获取文件元信息不是最终目标,重要资产落盘才是核心目标。文件是否已存在由下载工具内部检查,`list-thread-file` 阶段不要做本地存在性判断。
|
|
285
285
|
|
|
286
286
|
### 获取会话文件
|
|
287
287
|
|
|
288
|
-
从
|
|
288
|
+
从 `list-thread-file` 的 `files` 中逐个读取文件元信息:`file_path`、`file_name`、`download_url`、`updated_at`。重点识别剧本设计、场景设计、场景图、人物角色设计、人物图、分集草稿、故事板、最终视频产物等重要资产。
|
|
289
289
|
|
|
290
290
|
```
|
|
291
291
|
1. 有download_url的重要资产
|
|
292
292
|
→ 记录该file_path、URL和updated_at
|
|
293
|
-
→ 使用
|
|
293
|
+
→ 使用 download-result 将URL资源下载到该file_path;有updated_at时传入--updated-at
|
|
294
294
|
2. 本轮total达到200
|
|
295
295
|
→ 下一轮page-num加1,继续查询新一页结果
|
|
296
296
|
3. 本轮total未达到200
|
|
@@ -304,7 +304,7 @@ Thread: thread_...
|
|
|
304
304
|
|
|
305
305
|
对带 `download_url` 的重要资产调用下载工具,可并行。重要资产必须主动下载,不要等用户再次要求,也不要在调用下载工具前先检查本地文件是否存在。
|
|
306
306
|
|
|
307
|
-
1. 调用 `pippit-tool-cli
|
|
307
|
+
1. 调用 `pippit-tool-cli download-result --url DOWNLOAD_URL --output-path FILE_PATH --updated-at UPDATED_AT`;如果文件对象没有 `updated_at`,省略 `--updated-at`。
|
|
308
308
|
2. 下载完成后,向用户展示本地文件路径;如果某个文件下载失败,记录失败项并在后续轮询中重试,不阻塞已成功落盘的文件展示。
|
|
309
309
|
|
|
310
310
|
## 向用户展示内容
|
|
@@ -325,7 +325,7 @@ Thread: thread_...
|
|
|
325
325
|
|
|
326
326
|
1. **上传**:如果用户给了本地 `.doc` / `.docx` / `.txt` 参考文件,先调用 `+upload-file`。
|
|
327
327
|
2. **提交任务**:首次创作时把用户原始短剧需求和唯一剧本 `asset_id` 通过 `+submit-run --asset-ids` 发给后端;同一 `thread_id` 后续续写或修改不再追加新的剧本文件。
|
|
328
|
-
3. **传话、取文件、下载资源**:根据
|
|
328
|
+
3. **传话、取文件、下载资源**:根据 `get-thread` 返回的 `readable_text` 展示进展、问题和结果;遇到表单、问卷、选项或按钮时,只做流程合理性清洗,不替用户决定创作内容;根据 `list-thread-file` 获取文件列表;再根据 `download_url` 调用 `download-result` 把缺失资源下载到用户本地。
|
|
329
329
|
|
|
330
330
|
**不要做的事:**
|
|
331
331
|
|
|
@@ -340,10 +340,10 @@ Thread: thread_...
|
|
|
340
340
|
|
|
341
341
|
- `--message` 是用户的原始短剧需求,不能为空。
|
|
342
342
|
- 查询进展时优先使用 `+submit-run` 返回的 `thread_id` 和 `run_id`;如果需要查看整个会话,可以省略 `--run-id`。
|
|
343
|
-
-
|
|
343
|
+
- `get-thread` 当前固定走服务端 v2 响应,输出字段是 `readable_text`;不要解析旧版 `messages` 数组。
|
|
344
344
|
- `+upload-file` 当前用于短剧场景文件上传链路,只支持本地 `.doc` / `.docx` / `.txt` 文件;`--path` 不能为空,路径必须指向真实文件,不能是目录。
|
|
345
345
|
- `+upload-file` 上传成功后只返回 `asset_id`;把该值原样作为 `+submit-run --asset-ids` 的参数。
|
|
346
346
|
- 单次创作会话中(相同 `thread_id`),`+submit-run` 只支持绑定一个剧本文件。不要在同一 `thread_id` 下重复上传并追加第二个剧本 `asset_id`;用户给多个剧本时,先让用户选择一个,或分别开启新的创作会话。
|
|
347
|
-
-
|
|
348
|
-
-
|
|
349
|
-
-
|
|
347
|
+
- `list-thread-file` 只需要 `thread_id`;分页参数使用 `--page-num 1 --page-size 200` 起步,`total` 达到 200 时下一轮递增 `page-num`。
|
|
348
|
+
- `list-thread-file` 和 `download-result` 是两个不同的 CLI 指令:前者获取会话文件元信息,后者下载 URL 资源并写入到本地目标文件路径。
|
|
349
|
+
- `download-result` 接收 `--url`、`--output-path`、`--updated-at`、`--workers`;`--output-path` 必须是包含文件名的目标文件路径。
|
|
@@ -11,6 +11,8 @@ from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
|
11
11
|
|
|
12
12
|
sys.path.insert(0, os.path.dirname(__file__))
|
|
13
13
|
|
|
14
|
+
HTTP_TIMEOUT_SECONDS = 30 * 60
|
|
15
|
+
|
|
14
16
|
|
|
15
17
|
def download_file(url, filepath):
|
|
16
18
|
"""下载单个文件"""
|
|
@@ -18,7 +20,7 @@ def download_file(url, filepath):
|
|
|
18
20
|
req = urllib.request.Request(url, headers={"User-Agent": "XYQ-Nest-Skill/1.0"})
|
|
19
21
|
tmp_path = filepath + ".tmp"
|
|
20
22
|
try:
|
|
21
|
-
with urllib.request.urlopen(req, timeout=
|
|
23
|
+
with urllib.request.urlopen(req, timeout=HTTP_TIMEOUT_SECONDS) as resp:
|
|
22
24
|
with open(tmp_path, "wb") as f:
|
|
23
25
|
shutil.copyfileobj(resp, f, length=1024 * 1024)
|
|
24
26
|
os.replace(tmp_path, filepath)
|
|
@@ -11,7 +11,7 @@ import urllib.request
|
|
|
11
11
|
import urllib.error
|
|
12
12
|
|
|
13
13
|
sys.path.insert(0, os.path.dirname(__file__))
|
|
14
|
-
from xyq_common import XYQ_BASE, ACCESS_KEY, UPLOAD_FILE_PATH, parse_response
|
|
14
|
+
from xyq_common import XYQ_BASE, ACCESS_KEY, UPLOAD_FILE_PATH, HTTP_TIMEOUT_SECONDS, parse_response
|
|
15
15
|
|
|
16
16
|
# 允许的 MIME 类型前缀
|
|
17
17
|
ALLOWED_PREFIXES = ("image/", "video/")
|
|
@@ -70,7 +70,7 @@ def upload_file(file_path: str) -> dict:
|
|
|
70
70
|
},
|
|
71
71
|
)
|
|
72
72
|
try:
|
|
73
|
-
with urllib.request.urlopen(req, timeout=
|
|
73
|
+
with urllib.request.urlopen(req, timeout=HTTP_TIMEOUT_SECONDS) as resp:
|
|
74
74
|
result = json.loads(resp.read().decode("utf-8"))
|
|
75
75
|
return parse_response(result)
|
|
76
76
|
except urllib.error.HTTPError as e:
|
|
@@ -13,6 +13,7 @@ ACCESS_KEY = os.environ.get("XYQ_ACCESS_KEY", "")
|
|
|
13
13
|
SUBMIT_RUN_PATH = "/api/biz/v1/skill/submit_run"
|
|
14
14
|
GET_THREAD_PATH = "/api/biz/v1/skill/get_thread"
|
|
15
15
|
UPLOAD_FILE_PATH = "/api/biz/v1/skill/upload_file"
|
|
16
|
+
HTTP_TIMEOUT_SECONDS = 30 * 60
|
|
16
17
|
|
|
17
18
|
if not ACCESS_KEY:
|
|
18
19
|
print("错误:请设置 XYQ_ACCESS_KEY 环境变量", file=sys.stderr)
|
|
@@ -22,7 +23,7 @@ if not ACCESS_KEY:
|
|
|
22
23
|
def _headers():
|
|
23
24
|
return {
|
|
24
25
|
"Authorization": f"Bearer {ACCESS_KEY}",
|
|
25
|
-
"Content-Type": "application/json"
|
|
26
|
+
"Content-Type": "application/json",
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
|
|
@@ -37,7 +38,7 @@ def api_post(path: str, body: dict) -> dict:
|
|
|
37
38
|
headers=_headers(),
|
|
38
39
|
)
|
|
39
40
|
try:
|
|
40
|
-
with urllib.request.urlopen(req, timeout=
|
|
41
|
+
with urllib.request.urlopen(req, timeout=HTTP_TIMEOUT_SECONDS) as resp:
|
|
41
42
|
return json.loads(resp.read().decode("utf-8"))
|
|
42
43
|
except urllib.error.HTTPError as e:
|
|
43
44
|
err_body = e.read().decode("utf-8") if e.fp else ""
|
|
@@ -53,7 +54,7 @@ def api_get(path: str) -> dict:
|
|
|
53
54
|
url = f"{XYQ_BASE.rstrip('/')}{path}"
|
|
54
55
|
req = urllib.request.Request(url, method="GET", headers=_headers())
|
|
55
56
|
try:
|
|
56
|
-
with urllib.request.urlopen(req, timeout=
|
|
57
|
+
with urllib.request.urlopen(req, timeout=HTTP_TIMEOUT_SECONDS) as resp:
|
|
57
58
|
return json.loads(resp.read().decode("utf-8"))
|
|
58
59
|
except urllib.error.HTTPError as e:
|
|
59
60
|
err_body = e.read().decode("utf-8") if e.fp else ""
|