fix: restore windows asr gpu runtime
Some checks failed
StoryForge CI / Baseline checks (push) Has been cancelled
StoryForge CI / Backend tests (push) Has been cancelled
StoryForge CI / Web tests (push) Has been cancelled

This commit is contained in:
kris
2026-04-06 12:04:25 +08:00
parent aa3aa9170f
commit 4acde19ffe
4 changed files with 69 additions and 0 deletions

View File

@@ -9,6 +9,7 @@
- Windows `ASR HTTP` 现在在 `auto` 模式下仍会优先尝试 `cuda + int8_float16`,但如果在真正推理阶段命中 `cublas/cudnn/cuda` 运行库缺失,会自动切回 `cpu + int8` 重试,不再把整次转写卡死在 GPU 路径。
- 这让“默认优先用 GPU、但当前机器 CUDA 运行库不完整”的场景也能稳定返回结果,同时保留混合中英文自动识别。
- `smoke_public_storyforge.sh``smoke_fnos_storyforge_lan.sh` 现在会覆盖 ASR 转写链路,公网 smoke 在遇到 `127.0.0.1` 这类服务器内网地址时会自动跳过真实转写,避免在开发机上误判。
- Windows ASR 运行时现在会自动发现 venv 里的 `nvidia-cublas-cu12 / nvidia-cuda-runtime-cu12 / nvidia-cudnn-cu12` DLL 目录并注入搜索路径;实机验证后 `active_device` 已经恢复为 `cuda`,不再长期回退到 CPU。
### Windows ASR 默认改成 GPU 优先与自动语言识别

View File

@@ -1,6 +1,8 @@
from __future__ import annotations
import os
import sys
import sysconfig
import tempfile
import time
from functools import lru_cache
@@ -15,6 +17,7 @@ VAD_FILTER = os.getenv("WHISPER_VAD_FILTER", "1").strip().lower() not in {"0", "
DOWNLOAD_ROOT = Path(os.getenv("WHISPER_DOWNLOAD_ROOT", str(Path(__file__).resolve().parent / "models-cache")))
app = FastAPI(title="storyforge-windows-asr", version="1.0.0")
_dll_handles: list[object] = []
def describe_language_mode() -> str:
@@ -66,8 +69,44 @@ def activate_cpu_fallback() -> None:
get_model.cache_clear()
def find_windows_cuda_runtime_dirs(site_packages_root: Path | None = None) -> list[Path]:
root = site_packages_root or Path(sysconfig.get_paths()["purelib"])
dirs = []
for rel in (
"nvidia/cublas/bin",
"nvidia/cuda_runtime/bin",
"nvidia/cuda_nvrtc/bin",
"nvidia/cudnn/bin",
):
path = root / rel
if path.exists():
dirs.append(path)
return dirs
def configure_windows_cuda_runtime() -> None:
if sys.platform != "win32":
return
configured = getattr(app.state, "windows_cuda_runtime_dirs", None)
if configured is not None:
return
runtime_dirs = find_windows_cuda_runtime_dirs()
app.state.windows_cuda_runtime_dirs = [str(path) for path in runtime_dirs]
if not runtime_dirs:
return
path_parts = os.environ.get("PATH", "").split(os.pathsep)
for runtime_dir in runtime_dirs:
runtime_dir_str = str(runtime_dir)
if runtime_dir_str not in path_parts:
path_parts.insert(0, runtime_dir_str)
if hasattr(os, "add_dll_directory"):
_dll_handles.append(os.add_dll_directory(runtime_dir_str))
os.environ["PATH"] = os.pathsep.join(path_parts)
@lru_cache(maxsize=1)
def get_model():
configure_windows_cuda_runtime()
from faster_whisper import WhisperModel
DOWNLOAD_ROOT.mkdir(parents=True, exist_ok=True)
@@ -91,6 +130,7 @@ def get_model():
@app.get("/health")
def health() -> dict[str, object]:
configure_windows_cuda_runtime()
return {
"status": "ok",
"service": "storyforge-windows-asr",
@@ -102,6 +142,7 @@ def health() -> dict[str, object]:
"active_compute_type": getattr(app.state, "runtime_compute_type", ""),
"download_root": str(DOWNLOAD_ROOT),
"model_loaded": get_model.cache_info().currsize > 0,
"windows_cuda_runtime_dirs": getattr(app.state, "windows_cuda_runtime_dirs", []),
}

View File

@@ -2,3 +2,6 @@ fastapi==0.116.1
uvicorn[standard]==0.35.0
python-multipart==0.0.20
faster-whisper>=1.1,<2
nvidia-cublas-cu12; platform_system == "Windows"
nvidia-cuda-runtime-cu12; platform_system == "Windows"
nvidia-cudnn-cu12; platform_system == "Windows"

View File

@@ -71,6 +71,30 @@ class WindowsAsrHttpTests(unittest.TestCase):
self.assertEqual(module.describe_language_mode(), "zh")
self.assertEqual(module.build_runtime_profiles(), [("cpu", "int8")])
def test_windows_cuda_runtime_discovery_finds_nvidia_wheel_bins(self) -> None:
module = load_windows_asr_app()
with tempfile.TemporaryDirectory() as tempdir:
root = Path(tempdir)
for rel in [
"nvidia/cublas/bin",
"nvidia/cuda_runtime/bin",
"nvidia/cuda_nvrtc/bin",
"nvidia/cudnn/bin",
]:
(root / rel).mkdir(parents=True, exist_ok=True)
dirs = module.find_windows_cuda_runtime_dirs(root)
self.assertEqual(
[path.as_posix() for path in dirs],
[
(root / "nvidia/cublas/bin").as_posix(),
(root / "nvidia/cuda_runtime/bin").as_posix(),
(root / "nvidia/cuda_nvrtc/bin").as_posix(),
(root / "nvidia/cudnn/bin").as_posix(),
],
)
def test_auto_runtime_falls_back_to_cpu_when_cuda_runtime_is_missing(self) -> None:
os.environ.pop("WHISPER_LANGUAGE", None)
os.environ.pop("WHISPER_DEVICE", None)