mirror of
https://github.com/calesthio/OpenMontage.git
synced 2026-08-05 15:20:40 +08:00
Merge pull request #317 from ziyu4huang/fix/music-gen-force-instrumental
fix(music_gen): send force_instrumental per music-gen-usage mandate (§8 #8)
This commit is contained in:
87
tests/tools/test_music_gen_force_instrumental.py
Normal file
87
tests/tools/test_music_gen_force_instrumental.py
Normal file
@@ -0,0 +1,87 @@
|
||||
"""Regression for the force_instrumental mandate (REVIEW §8 #8).
|
||||
|
||||
``skills/creative/music-gen-usage.md`` mandates that video background music
|
||||
ALWAYS be generated instrumental-only (vocals collide with narration).
|
||||
``music_gen`` historically never sent the kwarg, so ElevenLabs could return
|
||||
vocal tracks. This test pins the payload to include ``force_instrumental=True``
|
||||
by default and to honor an explicit opt-out.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import types
|
||||
|
||||
import pytest
|
||||
|
||||
from tools.audio.music_gen import MusicGen
|
||||
|
||||
|
||||
class _FakeResponse:
|
||||
def __init__(self, content: bytes = b"audio") -> None:
|
||||
self.content = content
|
||||
|
||||
def raise_for_status(self) -> None: # noqa: D401 - stub
|
||||
return None
|
||||
|
||||
|
||||
def _install_fake_requests(captured: dict) -> types.ModuleType:
|
||||
"""Install a stub ``requests`` module that records the JSON payload."""
|
||||
fake = types.ModuleType("requests")
|
||||
|
||||
def fake_post(url, headers=None, json=None, timeout=None): # noqa: ANN001
|
||||
captured["url"] = url
|
||||
captured["headers"] = headers
|
||||
captured["payload"] = json
|
||||
return _FakeResponse()
|
||||
|
||||
fake.post = fake_post
|
||||
sys.modules["requests"] = fake
|
||||
return fake
|
||||
|
||||
|
||||
def test_force_instrumental_is_sent_true_by_default(monkeypatch, tmp_path):
|
||||
monkeypatch.setenv("ELEVENLABS_API_KEY", "test-key")
|
||||
captured: dict = {}
|
||||
_install_fake_requests(captured)
|
||||
# Route the output to tmp_path so the test never writes music_output.mp3
|
||||
# into the repo root (the default output_path).
|
||||
out = tmp_path / "bg.mp3"
|
||||
try:
|
||||
MusicGen()._generate(
|
||||
{"prompt": "gentle ambient", "duration_seconds": 10, "output_path": str(out)},
|
||||
"test-key",
|
||||
)
|
||||
finally:
|
||||
sys.modules.pop("requests", None)
|
||||
|
||||
assert "force_instrumental" in captured["payload"], "force_instrumental kwarg was never sent"
|
||||
assert captured["payload"]["force_instrumental"] is True
|
||||
assert captured["payload"]["music_length_ms"] == 10_000
|
||||
|
||||
|
||||
def test_explicit_vocal_opt_out_is_respected(monkeypatch, tmp_path):
|
||||
monkeypatch.setenv("ELEVENLABS_API_KEY", "test-key")
|
||||
captured: dict = {}
|
||||
_install_fake_requests(captured)
|
||||
out = tmp_path / "vocals.mp3"
|
||||
try:
|
||||
MusicGen()._generate(
|
||||
{
|
||||
"prompt": "lead vocal pop",
|
||||
"duration_seconds": 10,
|
||||
"force_instrumental": False,
|
||||
"output_path": str(out),
|
||||
},
|
||||
"test-key",
|
||||
)
|
||||
finally:
|
||||
sys.modules.pop("requests", None)
|
||||
|
||||
assert captured["payload"]["force_instrumental"] is False
|
||||
|
||||
|
||||
def test_schema_defaults_force_instrumental_to_true():
|
||||
props = MusicGen().input_schema["properties"]["force_instrumental"]
|
||||
assert props["type"] == "boolean"
|
||||
assert props["default"] is True
|
||||
@@ -69,6 +69,17 @@ class MusicGen(BaseTool):
|
||||
),
|
||||
},
|
||||
"output_path": {"type": "string"},
|
||||
"force_instrumental": {
|
||||
"type": "boolean",
|
||||
"default": True,
|
||||
"description": (
|
||||
"Whether to generate instrumental-only music (no vocals). "
|
||||
"Defaults to True — the music-gen-usage mandate is to always "
|
||||
"set force_instrumental=true for video background music, since "
|
||||
"vocals collide with narration/dialogue. Set False only for "
|
||||
"explicitly vocal-led pieces."
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -147,6 +158,11 @@ class MusicGen(BaseTool):
|
||||
payload = {
|
||||
"prompt": prompt,
|
||||
"music_length_ms": int(duration * 1000),
|
||||
# music-gen-usage mandate: always set force_instrumental=true for
|
||||
# video background music (vocals collide with narration). The input
|
||||
# schema defaults this to True, so callers get the mandate by
|
||||
# default; they may opt out only by passing force_instrumental=False.
|
||||
"force_instrumental": bool(inputs.get("force_instrumental", True)),
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
|
||||
Reference in New Issue
Block a user