@pippit-dev/cli 0.0.6 → 0.0.8
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/checksums.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
d403f987a5f3cf416d0d183d0b7f45c6cd13ac36da37ca29480e8c9b53af75ea pippit-cli-0.0.8-darwin-amd64.tar.gz
|
|
2
|
+
69aa116a8dd6086f00769ac71aca9cb83c5ffe058187c42c212d35aadb06d817 pippit-cli-0.0.8-darwin-arm64.tar.gz
|
|
3
|
+
cdb856501d5472f226bf061073aa2d2af2f61b28151ca908e48e1acc8d1261b4 pippit-cli-0.0.8-linux-amd64.tar.gz
|
|
4
|
+
6a8013ca271df7ddebba3ffcc4ed76ef79404ad6105893cda7db2969a5f51595 pippit-cli-0.0.8-linux-arm64.tar.gz
|
|
5
|
+
1fff575ecbef2d8ed5cc5c05b87d08dbad6f68b3aa1c5da13957cac9f887b4ce pippit-cli-0.0.8-windows-amd64.zip
|
|
6
|
+
bfe3160bad9d536a7510486233cbe4bada0581996b142812edcabb741cc5d2de pippit-cli-0.0.8-windows-arm64.zip
|
|
@@ -164,8 +164,8 @@ func newShortDramaListThreadFileCommand(stdout, stderr io.Writer, runner *common
|
|
|
164
164
|
if opts.ThreadID == "" {
|
|
165
165
|
return fmt.Errorf("--thread-id is required")
|
|
166
166
|
}
|
|
167
|
-
if opts.PageSize <= 0 || opts.PageSize >
|
|
168
|
-
return fmt.Errorf("--page-size must be between 1 and
|
|
167
|
+
if opts.PageSize <= 0 || opts.PageSize > common.MaxListThreadFilePageSize {
|
|
168
|
+
return fmt.Errorf("--page-size must be between 1 and %d", common.MaxListThreadFilePageSize)
|
|
169
169
|
}
|
|
170
170
|
if opts.PageNum <= 0 {
|
|
171
171
|
return fmt.Errorf("--page-num must be greater than 0")
|
|
@@ -182,7 +182,7 @@ func newShortDramaListThreadFileCommand(stdout, stderr io.Writer, runner *common
|
|
|
182
182
|
cmd.SetErr(stderr)
|
|
183
183
|
cmd.Flags().StringVar(&opts.ThreadID, "thread-id", "", "thread ID to list files for")
|
|
184
184
|
cmd.Flags().IntVar(&opts.PageNum, "page-num", 1, "page number (1-based)")
|
|
185
|
-
cmd.Flags().IntVar(&opts.PageSize, "page-size",
|
|
185
|
+
cmd.Flags().IntVar(&opts.PageSize, "page-size", common.MaxListThreadFilePageSize, fmt.Sprintf("number of files per page (between 1 and %d)", common.MaxListThreadFilePageSize))
|
|
186
186
|
return cmd
|
|
187
187
|
}
|
|
188
188
|
|
package/cmd/short_drama_test.go
CHANGED
|
@@ -194,8 +194,8 @@ func TestShortDramaDownloadResult(t *testing.T) {
|
|
|
194
194
|
if got["output_path"] != outputPath {
|
|
195
195
|
t.Fatalf("output_path = %v, want %s", got["output_path"], outputPath)
|
|
196
196
|
}
|
|
197
|
-
if got["total"]
|
|
198
|
-
t.Fatalf("total
|
|
197
|
+
if _, ok := got["total"]; ok {
|
|
198
|
+
t.Fatalf("total should not be returned: %#v", got)
|
|
199
199
|
}
|
|
200
200
|
downloaded, ok := got["downloaded"].([]any)
|
|
201
201
|
if !ok || len(downloaded) != 1 {
|
|
@@ -248,8 +248,8 @@ func TestShortDramaDownloadResultSkipsExistingFile(t *testing.T) {
|
|
|
248
248
|
if got["output_path"] != outputPath {
|
|
249
249
|
t.Fatalf("output_path = %v, want %s", got["output_path"], outputPath)
|
|
250
250
|
}
|
|
251
|
-
if got["total"]
|
|
252
|
-
t.Fatalf("total
|
|
251
|
+
if _, ok := got["total"]; ok {
|
|
252
|
+
t.Fatalf("total should not be returned: %#v", got)
|
|
253
253
|
}
|
|
254
254
|
alreadyExist, ok := got["already_exist"].([]any)
|
|
255
255
|
if !ok || len(alreadyExist) != 1 || alreadyExist[0] != outputPath {
|
|
@@ -258,6 +258,44 @@ func TestShortDramaDownloadResultSkipsExistingFile(t *testing.T) {
|
|
|
258
258
|
assertFileContent(t, outputPath, "existing-data")
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
+
func TestShortDramaDownloadResultDownloadsMetaJSON(t *testing.T) {
|
|
262
|
+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
263
|
+
if r.URL.Path != "/meta.json" {
|
|
264
|
+
t.Fatalf("path = %s, want meta.json", r.URL.Path)
|
|
265
|
+
}
|
|
266
|
+
_, _ = w.Write([]byte(`{"ok":true}`))
|
|
267
|
+
}))
|
|
268
|
+
defer server.Close()
|
|
269
|
+
|
|
270
|
+
chdirTemp(t)
|
|
271
|
+
outputPath := filepath.Join("results", "meta.json")
|
|
272
|
+
|
|
273
|
+
var stdout, stderr bytes.Buffer
|
|
274
|
+
root := NewRootCommand(&stdout, &stderr)
|
|
275
|
+
root.SetArgs([]string{
|
|
276
|
+
"short-drama", "+download-result",
|
|
277
|
+
"--output-path", outputPath,
|
|
278
|
+
"--url", server.URL + "/meta.json",
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
if err := root.Execute(); err != nil {
|
|
282
|
+
t.Fatalf("Execute() error = %v, stderr = %s", err, stderr.String())
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
got := decodeJSON(t, stdout.Bytes())
|
|
286
|
+
if got["output_path"] != outputPath {
|
|
287
|
+
t.Fatalf("output_path = %v, want %s", got["output_path"], outputPath)
|
|
288
|
+
}
|
|
289
|
+
if _, ok := got["total"]; ok {
|
|
290
|
+
t.Fatalf("total should not be returned: %#v", got)
|
|
291
|
+
}
|
|
292
|
+
downloaded, ok := got["downloaded"].([]any)
|
|
293
|
+
if !ok || len(downloaded) != 1 || downloaded[0] != outputPath {
|
|
294
|
+
t.Fatalf("downloaded = %#v, want meta.json output path", got["downloaded"])
|
|
295
|
+
}
|
|
296
|
+
assertFileContent(t, outputPath, `{"ok":true}`)
|
|
297
|
+
}
|
|
298
|
+
|
|
261
299
|
func TestShortDramaDownloadResultRequiresOutputPath(t *testing.T) {
|
|
262
300
|
var stdout, stderr bytes.Buffer
|
|
263
301
|
root := NewRootCommand(&stdout, &stderr)
|
|
@@ -515,6 +553,10 @@ func TestShortDramaListThreadFile(t *testing.T) {
|
|
|
515
553
|
if got["total"] != float64(1) {
|
|
516
554
|
t.Fatalf("total = %v, want 1", got["total"])
|
|
517
555
|
}
|
|
556
|
+
wantMessage := "<system-remind>\n- total is below 200; continue querying with current --page-num 2\n</system-remind>"
|
|
557
|
+
if got["message"] != wantMessage {
|
|
558
|
+
t.Fatalf("message = %v, want current page hint", got["message"])
|
|
559
|
+
}
|
|
518
560
|
files, ok := got["files"].([]any)
|
|
519
561
|
if !ok || len(files) != 1 {
|
|
520
562
|
t.Fatalf("files = %#v, want one file", got["files"])
|
|
@@ -535,6 +577,35 @@ func TestShortDramaListThreadFile(t *testing.T) {
|
|
|
535
577
|
}
|
|
536
578
|
}
|
|
537
579
|
|
|
580
|
+
func TestShortDramaListThreadFileMessageWhenPageFull(t *testing.T) {
|
|
581
|
+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
582
|
+
if !strings.Contains(r.URL.Path, "list_thread_file") {
|
|
583
|
+
t.Fatalf("path = %s, want list_thread_file path", r.URL.Path)
|
|
584
|
+
}
|
|
585
|
+
_, _ = w.Write([]byte(`{"ret":"0","errmsg":"","data":{"total":200,"files":[]}}`))
|
|
586
|
+
}))
|
|
587
|
+
defer server.Close()
|
|
588
|
+
|
|
589
|
+
var stdout, stderr bytes.Buffer
|
|
590
|
+
root := newTestRootCommand(t, &stdout, &stderr, server.URL)
|
|
591
|
+
root.SetArgs([]string{
|
|
592
|
+
"short-drama", "+list-thread-file",
|
|
593
|
+
"--thread-id", "thread_123",
|
|
594
|
+
"--page-num", "2",
|
|
595
|
+
"--page-size", "200",
|
|
596
|
+
})
|
|
597
|
+
|
|
598
|
+
if err := root.Execute(); err != nil {
|
|
599
|
+
t.Fatalf("Execute() error = %v, stderr = %s", err, stderr.String())
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
got := decodeJSON(t, stdout.Bytes())
|
|
603
|
+
wantMessage := "<system-remind>\n- total reached 200; query the next page with --page-num 3\n</system-remind>"
|
|
604
|
+
if got["message"] != wantMessage {
|
|
605
|
+
t.Fatalf("message = %v, want next page hint", got["message"])
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
538
609
|
func TestShortDramaListThreadFileRequiresThreadID(t *testing.T) {
|
|
539
610
|
var stdout, stderr bytes.Buffer
|
|
540
611
|
root := NewRootCommand(&stdout, &stderr)
|
|
@@ -549,6 +620,24 @@ func TestShortDramaListThreadFileRequiresThreadID(t *testing.T) {
|
|
|
549
620
|
}
|
|
550
621
|
}
|
|
551
622
|
|
|
623
|
+
func TestShortDramaListThreadFileRejectsPageSizeAboveMax(t *testing.T) {
|
|
624
|
+
var stdout, stderr bytes.Buffer
|
|
625
|
+
root := NewRootCommand(&stdout, &stderr)
|
|
626
|
+
root.SetArgs([]string{
|
|
627
|
+
"short-drama", "+list-thread-file",
|
|
628
|
+
"--thread-id", "thread_123",
|
|
629
|
+
"--page-size", "201",
|
|
630
|
+
})
|
|
631
|
+
|
|
632
|
+
err := root.Execute()
|
|
633
|
+
if err == nil {
|
|
634
|
+
t.Fatal("Execute() error = nil, want validation error")
|
|
635
|
+
}
|
|
636
|
+
if !strings.Contains(err.Error(), "--page-size must be between 1 and 200") {
|
|
637
|
+
t.Fatalf("error = %q, want page-size validation", err)
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
|
|
552
641
|
func newTestRootCommand(t *testing.T, stdout, stderr io.Writer, baseURL string) *cobra.Command {
|
|
553
642
|
t.Helper()
|
|
554
643
|
return newTestRootCommandWithAccessKey(t, stdout, stderr, baseURL, "test-token")
|
|
@@ -36,7 +36,6 @@ type DownloadResultResponse struct {
|
|
|
36
36
|
OutputPath string `json:"output_path"`
|
|
37
37
|
Downloaded []string `json:"downloaded"`
|
|
38
38
|
AlreadyExist []string `json:"already_exist,omitempty"`
|
|
39
|
-
Total int `json:"total"`
|
|
40
39
|
Errors []*DownloadResultError `json:"errors,omitempty"`
|
|
41
40
|
}
|
|
42
41
|
|
|
@@ -76,7 +75,6 @@ func DownloadResult(ctx context.Context, opts DownloadResultOptions, runner *Run
|
|
|
76
75
|
return &DownloadResultResponse{
|
|
77
76
|
OutputPath: outputPath,
|
|
78
77
|
AlreadyExist: []string{outputPath},
|
|
79
|
-
Total: 0,
|
|
80
78
|
}, nil
|
|
81
79
|
} else if !os.IsNotExist(err) {
|
|
82
80
|
return nil, fmt.Errorf("stat output path: %w", err)
|
|
@@ -161,7 +159,6 @@ func DownloadResult(ctx context.Context, opts DownloadResultOptions, runner *Run
|
|
|
161
159
|
result := &DownloadResultResponse{
|
|
162
160
|
OutputPath: outputPath,
|
|
163
161
|
Downloaded: downloaded,
|
|
164
|
-
Total: len(downloaded),
|
|
165
162
|
Errors: errorList,
|
|
166
163
|
}
|
|
167
164
|
if len(downloaded) == 0 && len(errorList) > 0 {
|
|
@@ -9,6 +9,8 @@ import (
|
|
|
9
9
|
"github.com/Pippit-dev/pippit-cli/internal/config"
|
|
10
10
|
)
|
|
11
11
|
|
|
12
|
+
const MaxListThreadFilePageSize = 200
|
|
13
|
+
|
|
12
14
|
// ListThreadFileOptions is the command-facing request shape for listing thread files.
|
|
13
15
|
type ListThreadFileOptions struct {
|
|
14
16
|
ThreadID string `json:"thread_id"`
|
|
@@ -24,8 +26,9 @@ type ThreadFile struct {
|
|
|
24
26
|
|
|
25
27
|
// ListThreadFileResult is the JSON envelope printed by `pippit-cli short-drama +list-thread-file`.
|
|
26
28
|
type ListThreadFileResult struct {
|
|
27
|
-
Files
|
|
28
|
-
Total
|
|
29
|
+
Files []*ThreadFile `json:"files"`
|
|
30
|
+
Total int64 `json:"total"`
|
|
31
|
+
Message string `json:"message"`
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
type listThreadFileResponse struct {
|
|
@@ -82,11 +85,26 @@ func ListThreadFile(ctx context.Context, opts *ListThreadFileOptions, runner *Ru
|
|
|
82
85
|
}
|
|
83
86
|
|
|
84
87
|
return &ListThreadFileResult{
|
|
85
|
-
Files:
|
|
86
|
-
Total:
|
|
88
|
+
Files: files,
|
|
89
|
+
Total: resp.Data.Total,
|
|
90
|
+
Message: listThreadFileMessage(resp.Data.Total, opts.PageNum),
|
|
87
91
|
}, nil
|
|
88
92
|
}
|
|
89
93
|
|
|
94
|
+
func listThreadFileMessage(total int64, pageNum int) string {
|
|
95
|
+
start, end := "<system-remind>", "</system-remind>"
|
|
96
|
+
if pageNum <= 0 {
|
|
97
|
+
pageNum = 1
|
|
98
|
+
}
|
|
99
|
+
var message string
|
|
100
|
+
if total >= MaxListThreadFilePageSize {
|
|
101
|
+
message = fmt.Sprintf("total reached %d; query the next page with --page-num %d", MaxListThreadFilePageSize, pageNum+1)
|
|
102
|
+
} else {
|
|
103
|
+
message = fmt.Sprintf("total is below %d; continue querying with current --page-num %d", MaxListThreadFilePageSize, pageNum)
|
|
104
|
+
}
|
|
105
|
+
return fmt.Sprintf("%s\n- %s\n%s", start, message, end)
|
|
106
|
+
}
|
|
107
|
+
|
|
90
108
|
func threadFilePath(threadID string, filePath string) string {
|
|
91
109
|
parts := []string{strings.TrimSpace(threadID)}
|
|
92
110
|
trimmedFilePath := strings.Trim(strings.TrimSpace(filePath), `/\`)
|
package/package.json
CHANGED
|
@@ -17,17 +17,19 @@ metadata:
|
|
|
17
17
|
|
|
18
18
|
# 小云雀短剧创作
|
|
19
19
|
|
|
20
|
-
通过 `pippit-cli short-drama`
|
|
20
|
+
通过 `pippit-cli short-drama` 命令提交短剧创作任务、上传参考文件,并行查询任务进展和会话产物文件,及时把重要资产下载到用户本地。
|
|
21
21
|
|
|
22
|
-
短剧场景面向剧情、人物、分集与画面化叙事创作,用户的原始需求通过 `--message` 发送给后端 Agent。后端 Agent 负责理解任务、编排流程和生成内容;用户侧 Agent
|
|
22
|
+
短剧场景面向剧情、人物、分集与画面化叙事创作,用户的原始需求通过 `--message` 发送给后端 Agent。后端 Agent 负责理解任务、编排流程和生成内容;用户侧 Agent 负责提交任务、并行查询进展与产物、主动下载重要资产并展示结果。
|
|
23
23
|
|
|
24
24
|
## 功能
|
|
25
25
|
|
|
26
26
|
1. **提交短剧 Run 任务** - 创建新会话或向已有会话发送短剧创作需求。
|
|
27
27
|
2. **查询会话进展** - 根据 `thread_id`、`run_id`、`after_seq` 拉取短剧任务消息列表。
|
|
28
28
|
3. **上传文件** - 上传短剧相关参考文件,得到文件 ID,供后续任务引用。
|
|
29
|
-
4. **获取会话文件** - 根据 `thread_id` 拉取会话文件列表,得到 `file_path`、`
|
|
30
|
-
5.
|
|
29
|
+
4. **获取会话文件** - 根据 `thread_id` 拉取会话文件列表,得到 `file_path`、`download_url`。这和查询会话进展同等重要。
|
|
30
|
+
5. **下载重要资产** - 使用文件列表中的 `download_url` 下载资源,并按 `file_path` 写入用户本地目标文件路径。
|
|
31
|
+
|
|
32
|
+
重要资产包括但不限于:剧本设计、场景设计、场景图、人物角色设计、人物图、分集草稿、故事板、最终视频产物。只要 `+list-thread-file` 返回了这些资产的 `download_url`,就要及时调用下载工具落盘,不要只展示文件元信息。
|
|
31
33
|
|
|
32
34
|
## 前置要求
|
|
33
35
|
|
|
@@ -73,7 +75,7 @@ pippit-cli short-drama +upload-file --path /path/to/outline.md
|
|
|
73
75
|
|
|
74
76
|
```bash
|
|
75
77
|
# 获取会话文件列表
|
|
76
|
-
pippit-cli short-drama +list-thread-file --thread-id THREAD_ID --page-num 1 --page-size
|
|
78
|
+
pippit-cli short-drama +list-thread-file --thread-id THREAD_ID --page-num 1 --page-size 200
|
|
77
79
|
```
|
|
78
80
|
|
|
79
81
|
`+list-thread-file` 返回的每个文件对象包含:
|
|
@@ -85,7 +87,7 @@ pippit-cli short-drama +list-thread-file --thread-id THREAD_ID --page-num 1 --pa
|
|
|
85
87
|
}
|
|
86
88
|
```
|
|
87
89
|
|
|
88
|
-
`+list-thread-file`
|
|
90
|
+
`+list-thread-file` 只负责获取会话文件列表,不负责下载文件,也不需要判断本地文件是否已存在。
|
|
89
91
|
|
|
90
92
|
### 5. 下载文件资源
|
|
91
93
|
|
|
@@ -104,20 +106,25 @@ pippit-cli short-drama +download-result --url DOWNLOAD_URL --output-path FILE_PA
|
|
|
104
106
|
1. pippit-cli short-drama +submit-run --message "用户的原始短剧需求"
|
|
105
107
|
→ 拿到 thread_id、run_id 和 web_thread_link
|
|
106
108
|
2. 立即将 web_thread_link 展示给用户
|
|
107
|
-
3.
|
|
109
|
+
3. 并行发起,二者同等重要:
|
|
108
110
|
a. pippit-cli short-drama +get-thread --thread-id THREAD_ID --run-id RUN_ID --after-seq SEQUENCE
|
|
109
|
-
b. pippit-cli short-drama +list-thread-file --thread-id THREAD_ID --page-num
|
|
111
|
+
b. pippit-cli short-drama +list-thread-file --thread-id THREAD_ID --page-num PAGE_NUM --page-size 200
|
|
110
112
|
4. 检查 `get-thread` 返回的 messages:
|
|
111
113
|
- 如果任务仍在进行中:展示过程消息,继续查询
|
|
112
114
|
- 如果后端 Agent 提出问题:展示问题,等待用户回复
|
|
113
|
-
5.
|
|
114
|
-
- 对每个文件取 file_path、
|
|
115
|
+
5. 检查 `list-thread-file` 返回的 files:
|
|
116
|
+
- 对每个文件取 file_path、download_url
|
|
115
117
|
- 将 file_path 作为本地目标文件路径,包含文件名
|
|
116
|
-
-
|
|
117
|
-
|
|
118
|
+
- 有 download_url 的重要资产:加入本轮下载队列
|
|
119
|
+
- 不判断 file_path 在本地是否已存在,是否跳过由 +download-result 内部处理
|
|
120
|
+
- 如果本轮 total 达到 200:下一轮将 PAGE_NUM 加 1,继续查询新一页文件
|
|
121
|
+
6. 对重要资产,立即调用 +download-result 并行下载资源:
|
|
118
122
|
- 使用第 5 步获取的 download_url 作为 --url
|
|
119
123
|
- 使用第 5 步获取的完整 file_path 作为 --output-path
|
|
120
|
-
|
|
124
|
+
- 剧本设计、场景设计、场景图、人物角色设计、人物图、最终视频产物都属于重要资产
|
|
125
|
+
7. 查询或下载失败时,不要直接放弃;记录失败项,并在后续轮询中主动重试
|
|
126
|
+
8. 只有会话进展已处理,且已发现的重要资产均已下载或明确重试失败后,才向用户汇总最终结果
|
|
127
|
+
9. 如用户继续追加需求,使用同一 thread_id 再次 submit-run
|
|
121
128
|
```
|
|
122
129
|
|
|
123
130
|
### 场景 2:用户提供参考文件要求创作
|
|
@@ -127,7 +134,7 @@ pippit-cli short-drama +download-result --url DOWNLOAD_URL --output-path FILE_PA
|
|
|
127
134
|
→ 拿到 file_id
|
|
128
135
|
2. pippit-cli short-drama +submit-run --message "用户的原始短剧需求" --asset-ids file_id
|
|
129
136
|
→ 拿到 thread_id、run_id 和 web_thread_link
|
|
130
|
-
3. 后续同场景 1
|
|
137
|
+
3. 后续同场景 1 的并行查询、重要资产发现和文件下载流程
|
|
131
138
|
```
|
|
132
139
|
|
|
133
140
|
### 场景 3:在已有短剧会话中续写或修改
|
|
@@ -135,18 +142,30 @@ pippit-cli short-drama +download-result --url DOWNLOAD_URL --output-path FILE_PA
|
|
|
135
142
|
```
|
|
136
143
|
1. pippit-cli short-drama +submit-run --message "用户的新需求" --thread-id THREAD_ID
|
|
137
144
|
→ 拿到新的 run_id 和 web_thread_link
|
|
138
|
-
2. 继续按场景 1
|
|
145
|
+
2. 继续按场景 1 展示进展、处理用户补充问题、获取新增会话文件列表,并及时下载新增重要资产
|
|
139
146
|
```
|
|
140
147
|
|
|
141
148
|
## 轮询策略
|
|
142
149
|
|
|
143
150
|
- **间隔**:每 10 秒查询一次。
|
|
144
151
|
- **增量拉取**:首次使用 `--after-seq 0`,后续根据已读消息进度调整 `after-seq`。
|
|
145
|
-
- **并行查询**:每次 `+submit-run` 返回 `thread_id` 后,同时发起 `+get-thread` 和 `+list-thread-file
|
|
146
|
-
-
|
|
152
|
+
- **并行查询**:每次 `+submit-run` 返回 `thread_id` 后,同时发起 `+get-thread` 和 `+list-thread-file`;二者同等重要,不能只查询会话进展而忽略会话文件。
|
|
153
|
+
- **文件分页**:`+list-thread-file` 使用 `--page-size 200`。如果本轮返回的 `total` 达到 200,下一轮使用 `--page-num` 加 1 查询新一页结果;如果未达到 200,保持当前页继续轮询新增产物。
|
|
154
|
+
- **重要资产识别**:每轮都检查 `+list-thread-file` 返回的文件。剧本设计、场景设计、场景图、人物角色设计、人物图、分集草稿、故事板、最终视频产物都是重要资产。
|
|
155
|
+
- **文件下载**:解析 `+list-thread-file` 的结果后,对带 `download_url` 的重要资产立即调用 `+download-result` 下载资源;不要在 `list-thread-file` 阶段检查文件是否已存在,存在性检查由下载工具内部处理。
|
|
156
|
+
- **下载完成标准**:不要把文件元信息展示当成下载完成;必须拿到本地 `file_path`,或明确记录该文件在重试后仍下载失败。
|
|
147
157
|
- **用户确认**:如果消息中出现需要用户确认、补充设定或回答问题的内容,先展示给用户,等待用户回复。
|
|
148
158
|
- **超时**:如果长时间无结果,告知用户任务仍在生成中,可稍后通过 `web_thread_link` 查看。
|
|
149
|
-
-
|
|
159
|
+
- **错误处理**:`+get-thread`、`+list-thread-file` 或 `+download-result` 任一调用失败时,记录失败原因和参数,在后续轮询中主动重试;重试期间继续处理其他成功返回的消息和文件。连续多轮失败后再向用户说明仍未完成的查询或下载项。
|
|
160
|
+
|
|
161
|
+
## 完成标准
|
|
162
|
+
|
|
163
|
+
一次短剧任务不能只以 `+get-thread` 返回完成消息作为结束条件。完成前必须同时检查:
|
|
164
|
+
|
|
165
|
+
1. 已处理 `+get-thread` 返回的最新会话进展、用户确认问题和最终消息。
|
|
166
|
+
2. 已用 `--page-size 200` 调用 `+list-thread-file` 获取会话文件列表;如果本轮 `total` 达到 200,已在后续轮询中递增 `page-num` 查询新一页。
|
|
167
|
+
3. 对所有带 `download_url` 的重要资产,已调用 `+download-result` 下载到本地 `file_path`。
|
|
168
|
+
4. 对查询失败或下载失败的资产,已在后续轮询中主动重试,并在最终回复中列出仍失败的文件或命令。
|
|
150
169
|
|
|
151
170
|
## 输出格式
|
|
152
171
|
|
|
@@ -204,51 +223,59 @@ pippit-cli short-drama +download-result --url DOWNLOAD_URL --output-path FILE_PA
|
|
|
204
223
|
"download_url": "https://..."
|
|
205
224
|
}
|
|
206
225
|
],
|
|
207
|
-
"total": 1
|
|
226
|
+
"total": 1,
|
|
227
|
+
"message": "<system-remind>\n- total reached 200; query the next page with --page-num {page-num} + 1\n</system-remind>"
|
|
208
228
|
}
|
|
209
229
|
```
|
|
210
230
|
|
|
231
|
+
当 `total` 达到 200 时,`message` 会用 `<system-remind>` 提示下一轮将 `page-num` 加 1 查询新一页。
|
|
232
|
+
|
|
211
233
|
**+download-result** 返回:
|
|
212
234
|
|
|
213
235
|
```json
|
|
214
236
|
{
|
|
215
237
|
"output_path": "./{thread-id}/{file_path}/{file_name}",
|
|
216
|
-
"downloaded": ["./{thread-id}/{file_path}/{file_name}"]
|
|
217
|
-
"total": 1
|
|
238
|
+
"downloaded": ["./{thread-id}/{file_path}/{file_name}"]
|
|
218
239
|
}
|
|
219
240
|
```
|
|
220
241
|
|
|
221
242
|
## 会话文件与资源下载
|
|
222
243
|
|
|
223
|
-
先用 `+list-thread-file`
|
|
244
|
+
先用 `+list-thread-file` 获取会话文件列表,再用 `+download-result` 并行下载重要资产。获取文件元信息不是最终目标,重要资产落盘才是核心目标。文件是否已存在由下载工具内部检查,`+list-thread-file` 阶段不要做本地存在性判断。
|
|
224
245
|
|
|
225
246
|
### 获取会话文件
|
|
226
247
|
|
|
227
|
-
从 `+list-thread-file` 的 `files` 中逐个读取文件元信息:`file_path`、`download_url
|
|
248
|
+
从 `+list-thread-file` 的 `files` 中逐个读取文件元信息:`file_path`、`file_name`、`download_url`。重点识别剧本设计、场景设计、场景图、人物角色设计、人物图、分集草稿、故事板、最终视频产物等重要资产。
|
|
228
249
|
|
|
229
250
|
```
|
|
230
|
-
1.
|
|
231
|
-
→ 跳过
|
|
232
|
-
2. file_path在本地不存在
|
|
251
|
+
1. 有download_url的重要资产
|
|
233
252
|
→ 记录该file_path和URL
|
|
234
253
|
→ 使用 +download-result 将URL资源下载到该file_path
|
|
254
|
+
2. 本轮total达到200
|
|
255
|
+
→ 下一轮page-num加1,继续查询新一页结果
|
|
256
|
+
3. 本轮total未达到200
|
|
257
|
+
→ 后续轮询保持当前页,继续发现新增产物
|
|
258
|
+
4. list-thread-file或download-result失败
|
|
259
|
+
→ 记录失败参数和错误
|
|
260
|
+
→ 后续轮询主动重试,不要直接结束任务
|
|
235
261
|
```
|
|
236
262
|
|
|
237
263
|
### 并行下载文件资源
|
|
238
264
|
|
|
239
|
-
|
|
265
|
+
对带 `download_url` 的重要资产调用下载工具,可并行。重要资产必须主动下载,不要等用户再次要求,也不要在调用下载工具前先检查本地文件是否存在。
|
|
240
266
|
|
|
241
267
|
1. 调用 `pippit-cli short-drama +download-result --url DOWNLOAD_URL --output-path FILE_PATH`。
|
|
242
|
-
2.
|
|
268
|
+
2. 下载完成后,向用户展示本地文件路径;如果某个文件下载失败,记录失败项并在后续轮询中重试,不阻塞已成功落盘的文件展示。
|
|
243
269
|
|
|
244
270
|
## 向用户展示内容
|
|
245
271
|
|
|
246
272
|
- 任务提交后:立即展示 `web_thread_link`。
|
|
247
273
|
- 任务进行中:展示后端 Agent 返回的过程消息。
|
|
248
274
|
- 需要用户补充信息时:原样展示后端 Agent 的问题,等待用户回复。
|
|
249
|
-
-
|
|
275
|
+
- 任务完成后:展示短剧内容、分集草稿、设定说明或其他结果信息,同时检查是否有未下载的重要资产。
|
|
250
276
|
- 获取会话文件后:展示或记录文件元信息,不把它当成已下载结果。
|
|
251
277
|
- 文件资源下载后:展示已落盘的本地文件路径;已存在而跳过下载的文件也要标明。
|
|
278
|
+
- 如果仍有重要资产下载失败:说明失败文件、失败命令和已进行的重试,不要把它描述为已完成下载。
|
|
252
279
|
|
|
253
280
|
## 核心原则:用户侧不做创作,只做传话
|
|
254
281
|
|
|
@@ -275,6 +302,6 @@ pippit-cli short-drama +download-result --url DOWNLOAD_URL --output-path FILE_PA
|
|
|
275
302
|
- 查询进展时优先使用 `+submit-run` 返回的 `thread_id` 和 `run_id`。
|
|
276
303
|
- `--after-seq` 用于增量拉取消息,首次查询可设置为 `0`。
|
|
277
304
|
- `+upload-file` 当前用于短剧场景文件上传链路,上传后将返回可传给 `+submit-run` 的文件 ID。
|
|
278
|
-
- `+list-thread-file` 只需要 `thread_id
|
|
305
|
+
- `+list-thread-file` 只需要 `thread_id`;分页参数使用 `--page-num 1 --page-size 200` 起步,`total` 达到 200 时下一轮递增 `page-num`。
|
|
279
306
|
- `+list-thread-file` 和 `+download-result` 是两个不同的 CLI 指令:前者获取会话文件元信息,后者下载 URL 资源并写入到本地目标文件路径。
|
|
280
307
|
- `+download-result` 接收 `--url`、`--output-path`、`--workers`;`--output-path` 必须是包含文件名的目标文件路径。
|