feat(models): memory-aware whisper.cpp ladder with conditional backend order

Free memory picks the load-time rung (large-v3-turbo-q8_0 default,
q5_0 under 1086 MiB free, small/small.en floor) for unpinned default
configs; thresholds derive from catalog sizes plus the protocol's
512 MiB headroom. A manual pin is never overridden, and a failed load
steps one rung down and retries exactly once before surfacing.

CUDA ranks before Vulkan only with a complete architecture-matching
toolkit (nvidia-smi GPU, nvcc, compute capability >= 7.0); otherwise
Vulkan, then CPU. The driver-only CUDA recommendation now demotes to
CPU logic instead of naming an unreachable VRAM ladder.

Refs #20
This commit is contained in:
soubarnak
2026-11-06 01:48:20 +05:30
parent 426f524145
commit df771d8fb1
9 changed files with 746 additions and 34 deletions
+84 -20
View File
@@ -999,9 +999,13 @@ class TestGetRecommendedModel(unittest.TestCase):
) as mock_backend:
mock_backend.return_value = ("vulkan", "Intel Arc A770")
from vocalinux.utils.whispercpp_model_info import get_recommended_model
with patch(
"vocalinux.speech_recognition.model_ladder.cuda_toolkit_ready",
return_value=True,
):
from vocalinux.utils.whispercpp_model_info import get_recommended_model
model, reason = get_recommended_model()
model, reason = get_recommended_model()
self.assertEqual(model, "small")
@@ -1018,13 +1022,41 @@ class TestGetRecommendedModel(unittest.TestCase):
) as mock_backend:
mock_backend.return_value = ("cuda", "NVIDIA RTX 4090 (24GB)")
from vocalinux.utils.whispercpp_model_info import get_recommended_model
with patch(
"vocalinux.speech_recognition.model_ladder.cuda_toolkit_ready",
return_value=True,
):
from vocalinux.utils.whispercpp_model_info import get_recommended_model
model, reason = get_recommended_model()
model, reason = get_recommended_model()
# High VRAM should recommend medium or higher
self.assertIn(model, ["medium", "large", "small"])
def test_get_recommended_model_with_driver_only_cuda_demotes(self):
"""A CUDA driver without the toolkit cannot run the build: CPU logic."""
import sys
mock_psutil = MagicMock()
mock_psutil.virtual_memory.return_value = MagicMock(total=16 * (1024**3))
with patch.dict("sys.modules", {"psutil": mock_psutil}):
with patch(
"vocalinux.utils.whispercpp_model_info.detect_compute_backend"
) as mock_backend:
mock_backend.return_value = ("cuda", "NVIDIA RTX 4090 (24GB)")
with patch(
"vocalinux.speech_recognition.model_ladder.cuda_toolkit_ready",
return_value=False,
):
from vocalinux.utils.whispercpp_model_info import get_recommended_model
model, _reason = get_recommended_model()
# 16 GB system RAM under CPU logic recommends base.
self.assertEqual(model, "base")
def test_get_recommended_model_with_cpu_high_ram(self):
"""Test model recommendation with CPU and 16GB+ RAM."""
import sys
@@ -1038,9 +1070,13 @@ class TestGetRecommendedModel(unittest.TestCase):
) as mock_backend:
mock_backend.return_value = ("cpu", "Intel Core i7")
from vocalinux.utils.whispercpp_model_info import get_recommended_model
with patch(
"vocalinux.speech_recognition.model_ladder.cuda_toolkit_ready",
return_value=True,
):
from vocalinux.utils.whispercpp_model_info import get_recommended_model
model, reason = get_recommended_model()
model, reason = get_recommended_model()
self.assertEqual(model, "base")
@@ -1057,9 +1093,13 @@ class TestGetRecommendedModel(unittest.TestCase):
) as mock_backend:
mock_backend.return_value = ("cpu", "AMD Ryzen 5")
from vocalinux.utils.whispercpp_model_info import get_recommended_model
with patch(
"vocalinux.speech_recognition.model_ladder.cuda_toolkit_ready",
return_value=True,
):
from vocalinux.utils.whispercpp_model_info import get_recommended_model
model, reason = get_recommended_model()
model, reason = get_recommended_model()
self.assertEqual(model, "tiny")
@@ -1076,9 +1116,13 @@ class TestGetRecommendedModel(unittest.TestCase):
) as mock_backend:
mock_backend.return_value = ("cpu", "Intel Atom")
from vocalinux.utils.whispercpp_model_info import get_recommended_model
with patch(
"vocalinux.speech_recognition.model_ladder.cuda_toolkit_ready",
return_value=True,
):
from vocalinux.utils.whispercpp_model_info import get_recommended_model
model, reason = get_recommended_model()
model, reason = get_recommended_model()
self.assertEqual(model, "tiny")
@@ -1141,9 +1185,13 @@ class TestGetRecommendedModel(unittest.TestCase):
) as mock_backend:
mock_backend.return_value = ("cuda", "NVIDIA GeForce RTX 3070 (8192 MiB)")
from vocalinux.utils.whispercpp_model_info import get_recommended_model
with patch(
"vocalinux.speech_recognition.model_ladder.cuda_toolkit_ready",
return_value=True,
):
from vocalinux.utils.whispercpp_model_info import get_recommended_model
model, reason = get_recommended_model()
model, reason = get_recommended_model()
self.assertEqual(model, "medium")
self.assertIn("VRAM", reason)
@@ -1159,9 +1207,13 @@ class TestGetRecommendedModel(unittest.TestCase):
) as mock_backend:
mock_backend.return_value = ("cuda", "NVIDIA GeForce RTX 3060 (6144 MiB)")
from vocalinux.utils.whispercpp_model_info import get_recommended_model
with patch(
"vocalinux.speech_recognition.model_ladder.cuda_toolkit_ready",
return_value=True,
):
from vocalinux.utils.whispercpp_model_info import get_recommended_model
model, reason = get_recommended_model()
model, reason = get_recommended_model()
self.assertEqual(model, "small")
@@ -1176,9 +1228,13 @@ class TestGetRecommendedModel(unittest.TestCase):
) as mock_backend:
mock_backend.return_value = ("cuda", "NVIDIA GeForce GTX 1050 (2048 MiB)")
from vocalinux.utils.whispercpp_model_info import get_recommended_model
with patch(
"vocalinux.speech_recognition.model_ladder.cuda_toolkit_ready",
return_value=True,
):
from vocalinux.utils.whispercpp_model_info import get_recommended_model
model, reason = get_recommended_model()
model, reason = get_recommended_model()
self.assertEqual(model, "base")
@@ -1192,9 +1248,13 @@ class TestGetRecommendedModel(unittest.TestCase):
) as mock_backend:
mock_backend.return_value = ("cuda", "NVIDIA GPU")
from vocalinux.utils.whispercpp_model_info import get_recommended_model
with patch(
"vocalinux.speech_recognition.model_ladder.cuda_toolkit_ready",
return_value=True,
):
from vocalinux.utils.whispercpp_model_info import get_recommended_model
model, reason = get_recommended_model()
model, reason = get_recommended_model()
self.assertEqual(model, "small")
self.assertIn("CUDA GPU detected", reason)
@@ -1210,9 +1270,13 @@ class TestGetRecommendedModel(unittest.TestCase):
) as mock_backend:
mock_backend.return_value = ("vulkan", "Intel Arc A770")
from vocalinux.utils.whispercpp_model_info import get_recommended_model
with patch(
"vocalinux.speech_recognition.model_ladder.cuda_toolkit_ready",
return_value=True,
):
from vocalinux.utils.whispercpp_model_info import get_recommended_model
model, reason = get_recommended_model()
model, reason = get_recommended_model()
self.assertEqual(model, "small")
self.assertIn("8GB", reason)