Skip to content

Commit f40957b

Browse files
authored
Merge pull request #23 from Pippit-dev/feat-remove-video-reference-count-limits
fix: remove video reference count limits (v1.0.26)
2 parents ae75590 + 9f1168f commit f40957b

7 files changed

Lines changed: 67 additions & 80 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ pippit-tool-cli generate-video \
227227
--resolution "720p"
228228
```
229229

230-
命令输出 `thread_id`、`run_id` 和 `web_thread_link`。提交生视频 HTTP 请求时,参考图、参考视频和参考音频会使用上传接口返回的 `pippit_asset_id`,并分别写入 `video_part_tool_param.images`、`video_part_tool_param.videos` 和 `video_part_tool_param.audios`。图片最多 9 张,支持 `.jpg`、`.jpeg`、`.png`、`.gif`、`.bmp`、`.webp`、`.svg`;视频最多 3 个,支持 `.mp4`、`.avi`、`.mov`、`.wmv`、`.flv`、`.webm`、`.mkv`、`.m4v`;音频最多 3 个,仅支持 `.mp3`、`.wav`。普通用户支持模型 `Seedance_2.0_mini_lite`;`seedance2.0_vision`、`seedance2.0_fast_vision`、`Seedance_2.0_mini` 和 `Seedance_2.5` 为 VIP 专属模型。CLI 会在提交前校验 prompt、素材数量和文件后缀;模型、比例、分辨率等语义校验由服务端处理。
230+
命令输出 `thread_id`、`run_id` 和 `web_thread_link`。提交生视频 HTTP 请求时,参考图、参考视频和参考音频会使用上传接口返回的 `pippit_asset_id`,并分别写入 `video_part_tool_param.images`、`video_part_tool_param.videos` 和 `video_part_tool_param.audios`。图片支持 `.jpg`、`.jpeg`、`.png`、`.gif`、`.bmp`、`.webp`、`.svg`;视频支持 `.mp4`、`.avi`、`.mov`、`.wmv`、`.flv`、`.webm`、`.mkv`、`.m4v`;音频仅支持 `.mp3`、`.wav`。普通用户支持模型 `Seedance_2.0_mini_lite`;`seedance2.0_vision`、`seedance2.0_fast_vision`、`Seedance_2.0_mini` 和 `Seedance_2.5` 为 VIP 专属模型。CLI 会在提交前校验 prompt 和文件后缀;模型、比例、分辨率等语义校验由服务端处理。
231231

232232
首尾帧生视频时,按首帧、尾帧的顺序传入两次 `--image`,并设置 `--generate-type 1`:
233233

‎cmd/generate_video/generate_video.go‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ func NewCommand(stdout, stderr io.Writer, runner *common.Runner) *cobra.Command
4343
cmd.SetErr(stderr)
4444
flags := cmd.Flags()
4545
flags.StringVar(&opts.Prompt, "prompt", "", "video generation prompt")
46-
flags.StringArrayVar(&opts.ImagePaths, "image", nil, "local reference image path; repeat for multiple images, up to 9")
47-
flags.StringArrayVar(&opts.VideoPaths, "video", nil, "local reference video path; repeat for multiple videos, up to 3")
48-
flags.StringArrayVar(&opts.AudioPaths, "audio", nil, "local reference audio path; repeat for multiple audios, up to 3")
46+
flags.StringArrayVar(&opts.ImagePaths, "image", nil, "local reference image path; repeat for multiple images")
47+
flags.StringArrayVar(&opts.VideoPaths, "video", nil, "local reference video path; repeat for multiple videos")
48+
flags.StringArrayVar(&opts.AudioPaths, "audio", nil, "local reference audio path; repeat for multiple audios")
4949
flags.IntVar(&durationSec, "duration", 0, "video duration in seconds")
5050
flags.StringVar(&opts.Ratio, "ratio", "", "video ratio, such as 9:16, 16:9, 3:4, 4:3")
5151
flags.StringVar(&opts.Model, "model", "", "video model; normal users: Seedance_2.0_mini_lite; VIP-only: seedance2.0_vision, seedance2.0_fast_vision, Seedance_2.0_mini, Seedance_2.5")

‎cmd/generate_video_test.go‎

Lines changed: 57 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -189,72 +189,74 @@ func TestGenerateVideoRequiresPrompt(t *testing.T) {
189189
}
190190
}
191191

192-
func TestGenerateVideoRejectsTooManyImages(t *testing.T) {
193-
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
194-
t.Fatal("server should not receive request when image count is invalid")
195-
}))
196-
defer server.Close()
197-
198-
var stdout, stderr bytes.Buffer
199-
root := newTestRootCommand(t, &stdout, &stderr, server.URL)
200-
args := []string{"generate-video", "--prompt", "x"}
201-
for _, path := range mediaPaths("image", ".jpg", 10) {
202-
args = append(args, "--image", path)
203-
}
204-
root.SetArgs(args)
205-
206-
err := root.Execute()
207-
if err == nil {
208-
t.Fatal("Execute() error = nil, want image count validation")
209-
}
210-
if !strings.Contains(err.Error(), "参考图片最多支持 9 个,当前传入 10 个") {
211-
t.Fatalf("error = %q, want image count validation", err)
212-
}
213-
}
214-
215-
func TestGenerateVideoRejectsTooManyVideos(t *testing.T) {
216-
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
217-
t.Fatal("server should not receive request when video count is invalid")
218-
}))
219-
defer server.Close()
220-
221-
var stdout, stderr bytes.Buffer
222-
root := newTestRootCommand(t, &stdout, &stderr, server.URL)
192+
func TestGenerateVideoAcceptsReferencesBeyondFormerLimits(t *testing.T) {
193+
cwd := chdirTemp(t)
223194
args := []string{"generate-video", "--prompt", "x"}
224-
for _, path := range mediaPaths("video", ".mp4", 4) {
225-
args = append(args, "--video", path)
226-
}
227-
root.SetArgs(args)
228-
229-
err := root.Execute()
230-
if err == nil {
231-
t.Fatal("Execute() error = nil, want video count validation")
232-
}
233-
if !strings.Contains(err.Error(), "参考视频最多支持 3 个,当前传入 4 个") {
234-
t.Fatalf("error = %q, want video count validation", err)
195+
var assetIDs []string
196+
for _, media := range []struct {
197+
flag string
198+
ext string
199+
count int
200+
}{
201+
{"image", ".jpg", 10},
202+
{"video", ".mp4", 4},
203+
{"audio", ".mp3", 4},
204+
} {
205+
for _, name := range mediaPaths(media.flag, media.ext, media.count) {
206+
path := filepath.Join(cwd, name)
207+
if err := os.WriteFile(path, []byte("media-data"), 0o644); err != nil {
208+
t.Fatalf("WriteFile(%s): %v", path, err)
209+
}
210+
args = append(args, "--"+media.flag, path)
211+
assetIDs = append(assetIDs, name)
212+
}
235213
}
236-
}
237214

238-
func TestGenerateVideoRejectsTooManyAudios(t *testing.T) {
215+
uploadIndex := 0
216+
submitted := false
239217
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
240-
t.Fatal("server should not receive request when audio count is invalid")
218+
switch r.URL.Path {
219+
case "/api/biz/v1/skill/upload_file":
220+
if uploadIndex >= len(assetIDs) {
221+
t.Fatalf("unexpected upload %d", uploadIndex)
222+
}
223+
_, _ = w.Write([]byte(`{"ret":"0","data":{"pippit_asset_id":"` + assetIDs[uploadIndex] + `"}}`))
224+
uploadIndex++
225+
case "/api/biz/v1/skill/submit_run":
226+
if uploadIndex != len(assetIDs) {
227+
t.Fatalf("uploaded %d references, want %d", uploadIndex, len(assetIDs))
228+
}
229+
data, err := io.ReadAll(r.Body)
230+
if err != nil {
231+
t.Fatalf("read body: %v", err)
232+
}
233+
var body map[string]any
234+
if err := sonic.Unmarshal(data, &body); err != nil {
235+
t.Fatalf("decode body: %v", err)
236+
}
237+
param, ok := body["video_part_tool_param"].(map[string]any)
238+
if !ok {
239+
t.Fatalf("video_part_tool_param = %#v, want object", body["video_part_tool_param"])
240+
}
241+
assertAssetRefs(t, param["images"], assetIDs[:10])
242+
assertAssetRefs(t, param["videos"], assetIDs[10:14])
243+
assertAssetRefs(t, param["audios"], assetIDs[14:])
244+
submitted = true
245+
_, _ = w.Write([]byte(`{"ret":"0","data":{"run":{"thread_id":"thread_123","run_id":"run_456"}}}`))
246+
default:
247+
t.Fatalf("unexpected path %s", r.URL.Path)
248+
}
241249
}))
242250
defer server.Close()
243251

244252
var stdout, stderr bytes.Buffer
245253
root := newTestRootCommand(t, &stdout, &stderr, server.URL)
246-
args := []string{"generate-video", "--prompt", "x"}
247-
for _, path := range mediaPaths("audio", ".mp3", 4) {
248-
args = append(args, "--audio", path)
249-
}
250254
root.SetArgs(args)
251-
252-
err := root.Execute()
253-
if err == nil {
254-
t.Fatal("Execute() error = nil, want audio count validation")
255+
if err := root.Execute(); err != nil {
256+
t.Fatalf("Execute() error = %v, stderr = %s", err, stderr.String())
255257
}
256-
if !strings.Contains(err.Error(), "参考音频最多支持 3 个,当前传入 4 个") {
257-
t.Fatalf("error = %q, want audio count validation", err)
258+
if !submitted {
259+
t.Fatal("generate-video did not submit references")
258260
}
259261
}
260262

‎internal/generate_video/generate_video.go‎

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,6 @@ import (
99
"github.com/Pippit-dev/pippit-cli/internal/common"
1010
)
1111

12-
const (
13-
maxReferenceImages = 9
14-
maxReferenceVideos = 3
15-
maxReferenceAudios = 3
16-
)
17-
1812
var (
1913
allowedImageExtensionList = []string{".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp", ".svg"}
2014
allowedAudioExtensionList = []string{".mp3", ".wav"}
@@ -70,15 +64,6 @@ func ValidateOptions(opts *Options) error {
7064
if strings.TrimSpace(opts.Prompt) == "" {
7165
return fmt.Errorf("缺少必填参数 --prompt")
7266
}
73-
if len(opts.ImagePaths) > maxReferenceImages {
74-
return fmt.Errorf("参考图片最多支持 %d 个,当前传入 %d 个", maxReferenceImages, len(opts.ImagePaths))
75-
}
76-
if len(opts.VideoPaths) > maxReferenceVideos {
77-
return fmt.Errorf("参考视频最多支持 %d 个,当前传入 %d 个", maxReferenceVideos, len(opts.VideoPaths))
78-
}
79-
if len(opts.AudioPaths) > maxReferenceAudios {
80-
return fmt.Errorf("参考音频最多支持 %d 个,当前传入 %d 个", maxReferenceAudios, len(opts.AudioPaths))
81-
}
8267
if err := validateMediaExtensions("图片", opts.ImagePaths, allowedImageExtensions, allowedImageExtensionList); err != nil {
8368
return err
8469
}

‎package-lock.json‎

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@pippit-dev/cli",
3-
"version": "1.0.25",
3+
"version": "1.0.26",
44
"description": "Pippit CLI",
55
"bin": {
66
"pippit-tool-cli": "scripts/run.js"

‎skills/xyq-nest-skill/commands/generate-video.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
| --- | --- | --- |
99
| `--prompt` | 是 | 用户原始描述,不能全为空白 |
1010
| `--model` | 否 | 用户指定的模型;未提供时省略,由服务端处理默认配置 |
11-
| `--image` | 否 | 本地图片路径,重复参数,最多 9 张 |
12-
| `--video` | 否 | 本地参考视频路径,重复参数,最多 3 个 |
13-
| `--audio` | 否 | 本地 `.mp3/.wav` 音频路径,重复参数,最多 3 个 |
11+
| `--image` | 否 | 本地图片路径,重复参数 |
12+
| `--video` | 否 | 本地参考视频路径,重复参数 |
13+
| `--audio` | 否 | 本地 `.mp3/.wav` 音频路径,重复参数 |
1414
| `--duration` | 否 | 整数秒;用户只给时长范围时先确认具体秒数 |
1515
| `--ratio` | 否 | 比例字符串,如 `9:16`、`16:9`、`3:4`、`4:3`;不转换为生图枚举 |
1616
| `--resolution` | 否 | 用户指定值,如 `720p`、`1080p` |

0 commit comments

Comments
 (0)