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:
Calesthio
2026-07-06 21:47:32 -07:00
committed by GitHub
2 changed files with 103 additions and 0 deletions

View 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

View File

@@ -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(