deer-flow/tests/skills/test_video_generation_cli.py
VicFei a3d21e5e4d
feat(skills): expose MiniMax resolution/duration in video-generation (#7912)
* feat(skills): expose MiniMax resolution/duration in video-generation

Hailuo 2.3 accepts explicit resolution (768P/1080P) and duration (6/10s)
in the /v1/video_generation body, but the skill sent neither — and its
SKILL.md told the caller --aspect-ratio is ignored for MiniMax without
offering any alternative, leaving cost/quality/length uncontrollable.
Read MINIMAX_VIDEO_RESOLUTION and MINIMAX_VIDEO_DURATION from the
environment and pass them through when set (unset keeps the API defaults
byte-for-byte); values are passed through unvalidated beyond the integer
check so newer tiers (H3 per-second 4-15s) need no script change. Document
both knobs in SKILL.md with a draft/final example. Fixes #7911.

* fix(skills): address MiniMax video override review

---------

Co-authored-by: vicfei <4058491+vicfei@users.noreply.github.com>
Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-11-07 15:52:35 +08:00

111 lines
4.0 KiB
Python

"""The video CLI must expose generation failures to its shell caller."""
import json
import runpy
import subprocess
import sys
from pathlib import Path
import pytest
import requests
SCRIPT = Path(__file__).resolve().parents[2] / "skills/public/video-generation/scripts/generate.py"
@pytest.fixture(autouse=True)
def clean_env(monkeypatch):
for key in (
"GEMINI_API_KEY",
"MINIMAX_API_KEY",
"VIDEO_GENERATION_PROVIDER",
"MINIMAX_VIDEO_RESOLUTION",
"MINIMAX_VIDEO_DURATION",
):
monkeypatch.delenv(key, raising=False)
@pytest.mark.parametrize(
("case", "error"),
[
("missing-prompt", "Error while generating video:"),
("no-credentials", "No credentials found"),
("gemini", "GEMINI_API_KEY is not set"),
("google", "GEMINI_API_KEY is not set"),
("minimax", "MINIMAX_API_KEY is not set"),
("unknown", "Unknown video provider"),
],
)
def test_cli_generation_failure_is_nonzero(monkeypatch, tmp_path, case, error):
prompt = tmp_path / "prompt.json"
if case != "missing-prompt":
prompt.write_text('{"prompt": "A cat runs"}', encoding="utf-8")
if case not in ("missing-prompt", "no-credentials"):
monkeypatch.setenv("VIDEO_GENERATION_PROVIDER", case)
output = tmp_path / "video.mp4"
result = subprocess.run(
[sys.executable, str(SCRIPT), "--prompt-file", str(prompt), "--output-file", str(output)],
capture_output=True,
text=True,
check=False,
timeout=10,
)
assert result.returncode == 1
assert error in result.stderr
assert result.stdout == ""
assert not output.exists()
@pytest.mark.parametrize("provider", ["gemini", "minimax"])
@pytest.mark.parametrize("http_error", [False, True], ids=["success", "http-error"])
def test_cli_provider_result(monkeypatch, tmp_path, capsys, provider, http_error):
monkeypatch.setenv("VIDEO_GENERATION_PROVIDER", provider)
monkeypatch.setenv("GEMINI_API_KEY", "test-key")
monkeypatch.setenv("MINIMAX_API_KEY", "test-key")
prompt = tmp_path / "prompt.json"
prompt.write_text('{"prompt": "A cat runs"}', encoding="utf-8")
output = tmp_path / "video.mp4"
original = b"existing video"
output.write_bytes(original)
monkeypatch.setattr(sys, "argv", [str(SCRIPT), "--prompt-file", str(prompt), "--output-file", str(output)])
def response(payload=None, *, status=200, content=b""):
result = requests.Response()
result.status_code = status
result._content = json.dumps(payload).encode("utf-8") if payload is not None else content
return result
def post(*args, **kwargs):
if http_error:
return response(status=500)
return response({"task_id": "task-1"} if provider == "minimax" else {"name": "operations/test"})
def get(url, **kwargs):
if url.endswith("/query/video_generation"):
return response({"status": "Success", "file_id": "file-1"})
if url.endswith("/files/retrieve"):
return response({"file": {"download_url": "https://example.test/video.mp4"}})
if url.endswith("/operations/test"):
return response({"done": True, "response": {"generateVideoResponse": {"generatedSamples": [{"video": {"uri": "https://example.test/video.mp4"}}]}}})
assert url == "https://example.test/video.mp4"
return response(content=b"test video")
monkeypatch.setattr(requests, "post", post)
monkeypatch.setattr(requests, "get", get)
if http_error:
with pytest.raises(SystemExit) as exc:
runpy.run_path(str(SCRIPT), run_name="__main__")
assert exc.value.code == 1
assert output.read_bytes() == original
captured = capsys.readouterr()
assert "Error while generating video:" in captured.err
assert captured.out == ""
else:
runpy.run_path(str(SCRIPT), run_name="__main__")
assert output.read_bytes() == b"test video"
captured = capsys.readouterr()
assert "generated successfully" in captured.out
assert captured.err == ""