Skip to content

Commit f4d5e94

Browse files
authored
Relax resource requirements for audio analysis providers (#4249)
1 parent cf8407c commit f4d5e94

7 files changed

Lines changed: 97 additions & 22 deletions

File tree

music_assistant/helpers/util.py

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -147,23 +147,50 @@ def verify_system_meets_requirements(
147147
torch inference (AVX2 on x86). Checked last, as it imports torch.
148148
:raises UnsupportedSystemError: If the system does not meet the requirements.
149149
"""
150-
cpu_cores = os.process_cpu_count() or os.cpu_count() or 1
151-
if min_cpu_cores and cpu_cores < min_cpu_cores:
150+
if shortfall := _resource_shortfall(min_memory_gb=min_memory_gb, min_cpu_cores=min_cpu_cores):
152151
raise UnsupportedSystemError(
153-
f"This system does not meet the minimal requirements for {feature_name}: "
154-
f"at least {min_cpu_cores} CPU cores are required ({cpu_cores} detected)."
152+
f"This system does not meet the minimal requirements for {feature_name}: {shortfall}"
155153
)
154+
if require_ml_inference:
155+
verify_cpu_supports_ml_inference()
156+
157+
158+
def system_meets_requirements(
159+
*,
160+
min_memory_gb: float = 0.0,
161+
min_cpu_cores: int = 0,
162+
) -> bool:
163+
"""
164+
Return whether the host meets the given RAM/CPU thresholds.
165+
166+
A non-raising companion to verify_system_meets_requirements for soft UI hints
167+
(e.g. hiding a recommended-hardware notice) rather than gating setup. The
168+
ML-inference capability is not considered here.
169+
170+
:param min_memory_gb: Minimum total system RAM in GB (0 disables the check).
171+
:param min_cpu_cores: Minimum CPU core count (0 disables the check).
172+
"""
173+
return _resource_shortfall(min_memory_gb=min_memory_gb, min_cpu_cores=min_cpu_cores) is None
174+
175+
176+
def _resource_shortfall(*, min_memory_gb: float, min_cpu_cores: int) -> str | None:
177+
"""
178+
Return why the host falls short of the RAM/CPU thresholds, or None if it meets them.
179+
180+
:param min_memory_gb: Minimum total system RAM in GB (0 disables the check).
181+
:param min_cpu_cores: Minimum CPU core count (0 disables the check).
182+
"""
183+
cpu_cores = os.process_cpu_count() or os.cpu_count() or 1
184+
if min_cpu_cores and cpu_cores < min_cpu_cores:
185+
return f"at least {min_cpu_cores} CPU cores are required ({cpu_cores} detected)."
156186
total_memory_gb = get_total_system_memory()
157187
# get_total_system_memory() returns 0.0 when the platform cannot report memory
158-
# (e.g. Windows); treat that as unknown and fail open rather than block setup.
188+
# (e.g. Windows); treat that as unknown and pass rather than block on a guess.
159189
if min_memory_gb and total_memory_gb and total_memory_gb < min_memory_gb:
160-
raise UnsupportedSystemError(
161-
f"This system does not meet the minimal requirements for {feature_name}: "
162-
f"at least {min_memory_gb:.0f}GB of RAM is required "
163-
f"({total_memory_gb:.1f}GB detected)."
190+
return (
191+
f"at least {min_memory_gb:.0f}GB of RAM is required ({total_memory_gb:.1f}GB detected)."
164192
)
165-
if require_ml_inference:
166-
verify_cpu_supports_ml_inference()
193+
return None
167194

168195

169196
def verify_cpu_supports_ml_inference() -> None:

music_assistant/providers/smart_fades/__init__.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
from __future__ import annotations
44

5-
import os
65
from typing import TYPE_CHECKING
76

87
from music_assistant_models.config_entries import ConfigEntry, ConfigValueType
98
from music_assistant_models.enums import ConfigEntryType
109

11-
from music_assistant.helpers.util import verify_system_meets_requirements
10+
from music_assistant.helpers.util import (
11+
system_meets_requirements,
12+
verify_system_meets_requirements,
13+
)
1214

1315
if TYPE_CHECKING:
1416
from music_assistant_models.config_entries import ProviderConfig
@@ -24,7 +26,11 @@
2426
# Smart Fades runs on-device ML (torch) inference; gate it to capable hardware.
2527
# 4GB matches the Balanced buffer threshold, the minimum buffer smart crossfade needs.
2628
MIN_RAM_GB = 4.0
27-
MIN_CPU_CORES = 4
29+
MIN_CPU_CORES = 2
30+
# Below the recommended thresholds the provider still runs, but we surface an
31+
# informational notice (see get_config_entries) as it may be tight under load.
32+
RECOMMENDED_RAM_GB = 6.0
33+
RECOMMENDED_CPU_CORES = 4
2834

2935

3036
async def setup(
@@ -56,9 +62,12 @@ async def get_config_entries(
5662
# ruff: noqa: ARG001
5763
return (
5864
ConfigEntry(
59-
key="single_cpu_warning",
65+
key="resource_warning",
6066
type=ConfigEntryType.ALERT,
6167
required=False,
62-
hidden=(os.cpu_count() or 1) > 1,
68+
hidden=system_meets_requirements(
69+
min_memory_gb=RECOMMENDED_RAM_GB,
70+
min_cpu_cores=RECOMMENDED_CPU_CORES,
71+
),
6372
),
6473
)

music_assistant/providers/smart_fades/strings.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"config_entries": {
3-
"single_cpu_warning": {
4-
"label": "Only 1 CPU core detected on this system. Smart Fades analysis typically takes some CPU time during model inference. Enabling it on single-CPU hosts may cause performance issues and block normal playback. Enable at your own risk."
3+
"resource_warning": {
4+
"label": "Smart Fades is powerful but resource-intensive: it loads a machine-learning model into memory to analyze your music. The minimum requirements are 4 GB of RAM, 2 CPU cores and (on Intel/AMD CPUs) AVX2 support. For the best experience we recommend 6 GB or more of RAM and 4 CPU cores. On systems near the minimum, or under heavy load, you may still run into out-of-memory situations."
55
}
66
},
77
"manifest": {

music_assistant/providers/sonic_analysis/__init__.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313
from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption
1414
from music_assistant_models.enums import ConfigEntryType, ContentType
1515

16-
from music_assistant.helpers.util import verify_system_meets_requirements
16+
from music_assistant.helpers.util import (
17+
system_meets_requirements,
18+
verify_system_meets_requirements,
19+
)
1720
from music_assistant.models.audio_analysis import AudioAnalysisData
1821
from music_assistant.models.audio_analysis_provider import (
1922
AnalysisSessionData,
@@ -67,8 +70,12 @@
6770
CONF_CLAP_SAMPLING: str = "clap_sampling"
6871

6972
# Sonic Analysis runs on-device CLAP inference; gate it to capable hardware.
70-
MIN_RAM_GB: float = 8.0
71-
MIN_CPU_CORES: int = 4
73+
MIN_RAM_GB: float = 4.0
74+
MIN_CPU_CORES: int = 2
75+
# Below the recommended thresholds the provider still runs, but we surface an
76+
# informational notice (see get_config_entries) as it may be tight under load.
77+
RECOMMENDED_RAM_GB: float = 6.0
78+
RECOMMENDED_CPU_CORES: int = 4
7279

7380

7481
@dataclass
@@ -118,6 +125,15 @@ async def get_config_entries(
118125
:param values: the (intermediate) raw values for config entries sent with the action.
119126
"""
120127
return (
128+
ConfigEntry(
129+
key="resource_warning",
130+
type=ConfigEntryType.ALERT,
131+
required=False,
132+
hidden=system_meets_requirements(
133+
min_memory_gb=RECOMMENDED_RAM_GB,
134+
min_cpu_cores=RECOMMENDED_CPU_CORES,
135+
),
136+
),
121137
ConfigEntry(
122138
key=CONF_CLAP_SAMPLING,
123139
type=ConfigEntryType.STRING,

music_assistant/providers/sonic_analysis/strings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
{
22
"config_entries": {
3+
"resource_warning": {
4+
"label": "Sonic Analysis is powerful but resource-intensive: it loads a machine-learning model (CLAP) into memory to analyze how your music sounds. The minimum requirements are 4 GB of RAM, 2 CPU cores and (on Intel/AMD CPUs) AVX2 support. For the best experience we recommend 6 GB or more of RAM and 4 CPU cores. On systems near the minimum, or under heavy load, you may still run into out-of-memory situations."
5+
},
36
"clap_sampling": {
47
"label": "CLAP quality (windows per track)",
58
"description": "Number of 7-second windows CLAP analyzes per track. More windows produce more representative scalars at linear CPU cost. Thorough is most useful for instrumentalness, where vocals can be missed by a single window.",

music_assistant/translations/en.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1179,7 +1179,7 @@
11791179
"provider.siriusxm.config_entries.sxm_region.options.CA": "Canada",
11801180
"provider.siriusxm.config_entries.sxm_region.options.US": "United States",
11811181
"provider.siriusxm.manifest.description": "Stream SiriusXM’s radio, talk, and curated music channels.",
1182-
"provider.smart_fades.config_entries.single_cpu_warning.label": "Only 1 CPU core detected on this system. Smart Fades analysis typically takes some CPU time during model inference. Enabling it on single-CPU hosts may cause performance issues and block normal playback. Enable at your own risk.",
1182+
"provider.smart_fades.config_entries.resource_warning.label": "Smart Fades is powerful but resource-intensive: it loads a machine-learning model into memory to analyze your music. The minimum requirements are 4 GB of RAM, 2 CPU cores and (on Intel/AMD CPUs) AVX2 support. For the best experience we recommend 6 GB or more of RAM and 4 CPU cores. On systems near the minimum, or under heavy load, you may still run into out-of-memory situations.",
11831183
"provider.smart_fades.manifest.description": "Smart fades analyzes beat and downbeat detection, energy and musical key for smart crossfades.",
11841184
"provider.smart_playlist.config_entries.ai_descriptions.description": "When a provider with AI support is available, use it to write a natural-language description for each smart playlist. Falls back to a plain rules summary when no AI provider is available.",
11851185
"provider.smart_playlist.config_entries.ai_descriptions.label": "Generate descriptions with AI",
@@ -1208,6 +1208,7 @@
12081208
"provider.sonic_analysis.config_entries.clap_sampling.options.balanced": "Balanced (3 windows, 2.4x CPU)",
12091209
"provider.sonic_analysis.config_entries.clap_sampling.options.fast": "Fast (1 window)",
12101210
"provider.sonic_analysis.config_entries.clap_sampling.options.thorough": "Thorough (8 windows, 6.6x CPU)",
1211+
"provider.sonic_analysis.config_entries.resource_warning.label": "Sonic Analysis is powerful but resource-intensive: it loads a machine-learning model (CLAP) into memory to analyze how your music sounds. The minimum requirements are 4 GB of RAM, 2 CPU cores and (on Intel/AMD CPUs) AVX2 support. For the best experience we recommend 6 GB or more of RAM and 4 CPU cores. On systems near the minimum, or under heavy load, you may still run into out-of-memory situations.",
12111212
"provider.sonic_analysis.manifest.description": "Analyses how each track sounds to power similarity, mood-based playlists, and other audio-aware features.",
12121213
"provider.sonic_similarity.config_entries.discover_diversity.description": "0 keeps results closest to the seeds; 10 maximises variety via MMR (some results may be less similar but more distinct from each other). Traits engine only.",
12131214
"provider.sonic_similarity.config_entries.discover_diversity.label": "Discover row diversity",

tests/core/test_helpers.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,3 +508,22 @@ def test_verify_system_meets_requirements_ml_inference() -> None:
508508
feature_name="X", min_cpu_cores=4, min_memory_gb=8.0, require_ml_inference=True
509509
)
510510
util.verify_system_meets_requirements(feature_name="X", min_cpu_cores=4, min_memory_gb=8.0)
511+
512+
513+
@pytest.mark.parametrize(
514+
("cpu_cores", "total_gb", "expected"),
515+
[
516+
(4, 6.0, True), # meets both recommended thresholds
517+
(8, 16.0, True),
518+
(2, 6.0, False), # below recommended cores
519+
(4, 4.0, False), # below recommended RAM
520+
(4, 0.0, True), # unknown memory -> fail open, same as the gate
521+
],
522+
)
523+
def test_system_meets_requirements(cpu_cores: int, total_gb: float, expected: bool) -> None:
524+
"""The non-raising predicate mirrors the gate's RAM/CPU checks, failing open on unknown RAM."""
525+
with (
526+
patch("music_assistant.helpers.util.os.process_cpu_count", return_value=cpu_cores),
527+
patch("music_assistant.helpers.util.get_total_system_memory", return_value=total_gb),
528+
):
529+
assert util.system_meets_requirements(min_memory_gb=6.0, min_cpu_cores=4) is expected

0 commit comments

Comments
 (0)