build.yml 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. name: CI
  2. on:
  3. push:
  4. branches: [main, master]
  5. paths:
  6. - '**/*.cpp'
  7. - '**/*.h'
  8. - '**/*.hpp'
  9. - '**/CMakeLists.txt'
  10. - '.github/workflows/**'
  11. pull_request:
  12. types: [opened, synchronize, reopened]
  13. workflow_dispatch:
  14. concurrency:
  15. group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
  16. cancel-in-progress: true
  17. env:
  18. # HuggingFace model info
  19. HF_MODEL_REPO: GaboxR67/MelBandRoformers
  20. HF_CHECKPOINT_PATH: melbandroformers/vocals/voc_fv6.ckpt
  21. HF_CONFIG_PATH: melbandroformers/vocals/voc_gabox.yaml
  22. # Music-Source-Separation-Training repo
  23. MSST_REPO: https://github.com/ZFTurbo/Music-Source-Separation-Training.git
  24. jobs:
  25. # ===========================================================================
  26. # Prepare: Generate test data (runs once, shared via artifacts)
  27. # ===========================================================================
  28. prepare-test-data:
  29. runs-on: ubuntu-latest
  30. steps:
  31. - name: Checkout
  32. uses: actions/checkout@v4
  33. - name: Setup Python
  34. uses: actions/setup-python@v5
  35. with:
  36. python-version: '3.11'
  37. - name: Clone MSST Repository
  38. run: git clone --depth 1 ${{ env.MSST_REPO }} msst
  39. - name: Install Dependencies
  40. run: |
  41. pip install torch torchaudio --index-url https://download.pytorch.org/whl/cpu
  42. pip install huggingface_hub scipy soundfile gguf librosa ml_collections einops pyyaml numpy tqdm beartype rotary_embedding_torch
  43. - name: Download Model from HuggingFace
  44. env:
  45. HF_TOKEN: ${{ secrets.HF_TOKEN }}
  46. run: |
  47. python -c "
  48. from huggingface_hub import hf_hub_download
  49. import os
  50. token = os.environ.get('HF_TOKEN') or None
  51. hf_hub_download('${{ env.HF_MODEL_REPO }}', '${{ env.HF_CHECKPOINT_PATH }}',
  52. local_dir='./model', token=token)
  53. hf_hub_download('${{ env.HF_MODEL_REPO }}', '${{ env.HF_CONFIG_PATH }}',
  54. local_dir='./model', token=token)
  55. "
  56. - name: Generate Test Audio
  57. run: |
  58. python scripts/generate_test_audio.py --output test_audio.wav --duration 5.0 --sample-rate 44100
  59. - name: Generate Test Data
  60. run: |
  61. python scripts/generate_test_data.py \
  62. --model-repo msst \
  63. --audio test_audio.wav \
  64. --checkpoint model/${{ env.HF_CHECKPOINT_PATH }} \
  65. --config model/${{ env.HF_CONFIG_PATH }} \
  66. --output test_data
  67. - name: Convert Model to GGUF
  68. run: |
  69. python scripts/convert_to_gguf.py \
  70. --ckpt model/${{ env.HF_CHECKPOINT_PATH }} \
  71. --config model/${{ env.HF_CONFIG_PATH }} \
  72. --out model.gguf \
  73. --dtype fp32
  74. - name: Upload Test Data Artifact
  75. uses: actions/upload-artifact@v4
  76. with:
  77. name: test-data
  78. path: |
  79. test_data/
  80. model.gguf
  81. test_audio.wav
  82. retention-days: 1
  83. # ===========================================================================
  84. # Build Matrix: Core Platforms + Vulkan
  85. # ===========================================================================
  86. build:
  87. needs: prepare-test-data
  88. strategy:
  89. fail-fast: false
  90. matrix:
  91. include:
  92. # Tier 1: Core Platforms (CPU)
  93. - { name: linux-x64-cpu, os: ubuntu-22.04, backend: cpu, test: true }
  94. - { name: linux-arm64-cpu, os: ubuntu-22.04-arm, backend: cpu, test: true }
  95. - { name: macos-arm64, os: macos-latest, backend: cpu, test: true }
  96. - { name: macos-x64, os: macos-15-intel, backend: cpu, test: true }
  97. - { name: windows-x64-msvc, os: windows-2025, backend: cpu, test: true }
  98. # Tier 2: Vulkan Backend
  99. - { name: linux-vulkan, os: ubuntu-24.04, backend: vulkan, test: true }
  100. - { name: windows-vulkan, os: windows-2025, backend: vulkan, test: true }
  101. runs-on: ${{ matrix.os }}
  102. steps:
  103. - name: Checkout
  104. uses: actions/checkout@v4
  105. - name: Clone GGML
  106. run: git clone --depth 1 https://github.com/ggerganov/ggml.git ggml
  107. - name: Download Test Data
  108. uses: actions/download-artifact@v4
  109. with:
  110. name: test-data
  111. - name: Setup Python
  112. uses: actions/setup-python@v5
  113. with:
  114. python-version: '3.11'
  115. - name: Setup MSVC
  116. if: runner.os == 'Windows'
  117. uses: ilammy/msvc-dev-cmd@v1
  118. - name: Install Python Dependencies
  119. run: pip install numpy scipy
  120. # ----- Linux Dependencies -----
  121. - name: Install Dependencies (Linux)
  122. if: runner.os == 'Linux'
  123. run: |
  124. sudo apt-get update
  125. sudo apt-get install -y build-essential cmake
  126. - name: Install Vulkan SDK (Linux)
  127. if: matrix.backend == 'vulkan' && runner.os == 'Linux'
  128. run: |
  129. sudo apt-get install -y libvulkan-dev glslc mesa-vulkan-drivers
  130. # ----- macOS Dependencies -----
  131. - name: Install Dependencies (macOS)
  132. if: runner.os == 'macOS'
  133. run: brew install cmake
  134. # ----- Windows Dependencies -----
  135. - name: Install Dependencies (Windows)
  136. if: runner.os == 'Windows'
  137. run: choco install ninja -y
  138. - name: Install Vulkan SDK (Windows)
  139. if: matrix.backend == 'vulkan' && runner.os == 'Windows'
  140. run: |
  141. $VK_VERSION = "1.4.313.2"
  142. curl.exe -o VulkanSDK.exe -L "https://sdk.lunarg.com/sdk/download/${VK_VERSION}/windows/vulkansdk-windows-X64-${VK_VERSION}.exe"
  143. Start-Process -FilePath .\VulkanSDK.exe -ArgumentList "--accept-licenses --default-answer --confirm-command install" -Wait
  144. Add-Content $env:GITHUB_ENV "VULKAN_SDK=C:\VulkanSDK\${VK_VERSION}"
  145. Add-Content $env:GITHUB_PATH "C:\VulkanSDK\${VK_VERSION}\bin"
  146. # ----- Configure -----
  147. - name: Configure (Unix)
  148. if: runner.os != 'Windows'
  149. run: |
  150. cmake -B build \
  151. -DCMAKE_BUILD_TYPE=Release \
  152. -DGGML_DIR=ggml \
  153. -DGGML_CUDA=OFF \
  154. -DGGML_VULKAN=${{ matrix.backend == 'vulkan' && 'ON' || 'OFF' }} \
  155. -DMBR_BUILD_TESTS=ON \
  156. -DMBR_BUILD_CLI=ON
  157. - name: Configure (Windows)
  158. if: runner.os == 'Windows'
  159. run: |
  160. cmake -B build -G "Ninja Multi-Config" `
  161. -DGGML_DIR=ggml `
  162. -DGGML_CUDA=OFF `
  163. -DGGML_VULKAN=${{ matrix.backend == 'vulkan' && 'ON' || 'OFF' }} `
  164. -DMBR_BUILD_TESTS=ON `
  165. -DMBR_BUILD_CLI=ON
  166. # ----- Build -----
  167. - name: Build (Unix)
  168. if: runner.os != 'Windows'
  169. run: cmake --build build --config Release -j $(nproc 2>/dev/null || sysctl -n hw.logicalcpu)
  170. - name: Build (Windows)
  171. if: runner.os == 'Windows'
  172. run: cmake --build build --config Release -j $env:NUMBER_OF_PROCESSORS
  173. # ----- Unit Tests -----
  174. - name: Run Unit Tests
  175. if: matrix.test
  176. env:
  177. MBR_MODEL_PATH: ${{ github.workspace }}/model.gguf
  178. MBR_TEST_DATA_DIR: ${{ github.workspace }}/test_data
  179. MBR_FORCE_CPU: ${{ runner.os == 'macOS' && '1' || '' }}
  180. run: ctest --test-dir build -C Release -V --output-on-failure --timeout 300
  181. # ----- CLI Tests -----
  182. - name: Test CLI
  183. if: matrix.test
  184. shell: bash
  185. env:
  186. MBR_MODEL_PATH: ${{ github.workspace }}/model.gguf
  187. MBR_FORCE_CPU: ${{ runner.os == 'macOS' && '1' || '' }}
  188. run: |
  189. echo "=== CLI Test Suite ==="
  190. # Dynamically find CLI executable
  191. CLI_NAME="mel_band_roformer-cli"
  192. if [[ "$RUNNER_OS" == "Windows" ]]; then CLI_NAME="mel_band_roformer-cli.exe"; fi
  193. echo "Searching for $CLI_NAME..."
  194. CLI_PATH=$(find build -name "$CLI_NAME" | head -n 1)
  195. if [[ -z "$CLI_PATH" ]]; then
  196. echo "Error: CLI executable not found!"
  197. find build
  198. exit 1
  199. fi
  200. echo "Found CLI at: $CLI_PATH"
  201. chmod +x "$CLI_PATH"
  202. # Setup execution variables
  203. CLI_DIR=$(dirname "$CLI_PATH")
  204. CLI_EXE="./$CLI_NAME"
  205. # Debug Info
  206. echo "Debug: Listing directory $CLI_DIR"
  207. ls -l "$CLI_DIR"
  208. echo "Debug: Checking dependencies"
  209. if command -v ldd >/dev/null; then
  210. ldd "$CLI_PATH" || echo "ldd returned error"
  211. fi
  212. # Define runner helper
  213. run_cli() {
  214. echo "Executing: ./$CLI_NAME $@"
  215. (cd "$CLI_DIR" && ./$CLI_NAME "$@")
  216. }
  217. # Debug PATH
  218. echo "PATH: $PATH"
  219. # 1. Test --help
  220. echo "[1/4] Testing --help..."
  221. run_cli --help
  222. # 2. Test with missing arguments (should fail)
  223. echo "[2/4] Testing error handling..."
  224. if run_cli 2>/dev/null; then
  225. echo "ERROR: CLI should fail without arguments"
  226. exit 1
  227. fi
  228. # 3. Use existing test audio
  229. echo "[3/4] Using generated test audio..."
  230. cp test_audio.wav cli_test_input.wav
  231. # 4. Run full inference
  232. echo "[4/4] Running inference..."
  233. # Use absolute paths for input/output to avoid directory issues
  234. ABS_MODEL=$(readlink -f "$MBR_MODEL_PATH" || echo "$(pwd)/model.gguf")
  235. ABS_INPUT=$(readlink -f cli_test_input.wav || echo "$(pwd)/cli_test_input.wav")
  236. ABS_OUTPUT=$(readlink -f cli_test_output.wav || echo "$(pwd)/cli_test_output.wav")
  237. # Convert paths for Windows MSVC executables
  238. if [[ "$RUNNER_OS" == "Windows" ]]; then
  239. ABS_MODEL=$(cygpath -w "$ABS_MODEL")
  240. ABS_INPUT=$(cygpath -w "$ABS_INPUT")
  241. ABS_OUTPUT=$(cygpath -w "$ABS_OUTPUT")
  242. fi
  243. echo "Running with model: $ABS_MODEL"
  244. run_cli "$ABS_MODEL" "$ABS_INPUT" "$ABS_OUTPUT" --chunk-size 88200 --overlap 2
  245. # Verify output exists and has reasonable size
  246. if [[ ! -f cli_test_output.wav ]]; then
  247. echo "ERROR: Output file not created"
  248. exit 1
  249. fi
  250. OUTPUT_SIZE=$(stat -c%s cli_test_output.wav 2>/dev/null || stat -f%z cli_test_output.wav)
  251. if [[ $OUTPUT_SIZE -lt 1000 ]]; then
  252. echo "ERROR: Output file too small: $OUTPUT_SIZE bytes"
  253. exit 1
  254. fi
  255. echo "=== CLI Tests Passed ==="
  256. # ----- Upload Artifacts -----
  257. - name: Upload Build Artifacts
  258. uses: actions/upload-artifact@v4
  259. with:
  260. name: build-${{ matrix.name }}
  261. path: |
  262. build/bin/
  263. build/lib*/
  264. build/*.dll
  265. build/*.so
  266. build/*.dylib
  267. build/mel_band_roformer-cli*
  268. build/Release/
  269. retention-days: 7
  270. # ----- Prepare Release Artifact -----
  271. - name: Prepare Release Artifact (Unix)
  272. if: runner.os != 'Windows'
  273. shell: bash
  274. run: |
  275. # Create release directory
  276. mkdir -p release/mel-band-roformer
  277. # Find and copy CLI executable
  278. CLI_PATH=$(find build -name "mel_band_roformer-cli" -type f | head -n 1)
  279. if [[ -n "$CLI_PATH" ]]; then
  280. cp "$CLI_PATH" release/mel-band-roformer/
  281. chmod +x release/mel-band-roformer/mel_band_roformer-cli
  282. fi
  283. # Copy shared libraries if exist (only real files, not symlinks)
  284. find build \( -name "*.so*" -o -name "*.dylib" \) -type f ! -type l | while read lib; do
  285. cp "$lib" release/mel-band-roformer/ 2>/dev/null || true
  286. done
  287. # List contents
  288. echo "Release artifact contents:"
  289. ls -lh release/mel-band-roformer/
  290. - name: Prepare Release Artifact (Windows)
  291. if: runner.os == 'Windows'
  292. shell: pwsh
  293. run: |
  294. # Create release directory
  295. New-Item -ItemType Directory -Force -Path "release\mel-band-roformer"
  296. # Find and copy CLI executable
  297. $CliPath = Get-ChildItem -Path build -Filter "mel_band_roformer-cli.exe" -Recurse -File | Select-Object -First 1
  298. if ($CliPath) {
  299. Copy-Item $CliPath.FullName "release\mel-band-roformer\"
  300. }
  301. # Copy DLL files
  302. Get-ChildItem -Path build -Filter "*.dll" -Recurse -File | ForEach-Object {
  303. Copy-Item $_.FullName "release\mel-band-roformer\" -ErrorAction SilentlyContinue
  304. }
  305. # List contents
  306. Write-Host "Release artifact contents:"
  307. Get-ChildItem "release\mel-band-roformer" | Format-Table Name, Length
  308. - name: Upload Release Artifact
  309. uses: actions/upload-artifact@v4
  310. with:
  311. name: MelBandRoformer-${{ matrix.name }}
  312. path: release/mel-band-roformer/
  313. retention-days: 30
  314. # ===========================================================================
  315. # CUDA Build: Linux (Verification Only - Not for Release)
  316. # ===========================================================================
  317. # Note: We do not provide precompiled CUDA binaries for Linux.
  318. # This build exists solely to verify the code compiles with CUDA on Linux.
  319. # Linux users should build from source for optimal performance.
  320. build-cuda-linux:
  321. name: build-cuda-linux-verify
  322. runs-on: ubuntu-latest
  323. steps:
  324. - name: Checkout
  325. uses: actions/checkout@v4
  326. - name: Clone GGML
  327. run: git clone --depth 1 https://github.com/ggerganov/ggml.git ggml
  328. - name: Install CUDA Toolkit
  329. uses: Jimver/cuda-toolkit@master
  330. with:
  331. cuda: "12.9.1"
  332. method: network
  333. sub-packages: '["nvcc", "cudart", "thrust"]'
  334. non-cuda-sub-packages: '["libcublas", "libcublas-dev"]'
  335. - name: Install Dependencies
  336. run: |
  337. sudo apt-get install -y cmake build-essential ninja-build
  338. - name: Configure
  339. run: |
  340. ls -ld ggml
  341. cmake -B build -G Ninja \
  342. -DCMAKE_BUILD_TYPE=Release \
  343. -DGGML_DIR=ggml \
  344. -DGGML_CUDA=ON \
  345. -DGGML_CUDA_FORCE_MMQ=ON \
  346. -DCMAKE_CUDA_RUNTIME_LIBRARY=Static \
  347. -DCMAKE_CUDA_ARCHITECTURES="61;75;80;86;89;120" \
  348. -DMBR_BUILD_TESTS=OFF \
  349. -DMBR_BUILD_CLI=ON
  350. - name: Build
  351. run: cmake --build build --config Release -j $(nproc)
  352. - name: Upload Build Artifacts (Debug Only)
  353. uses: actions/upload-artifact@v4
  354. with:
  355. name: build-linux-cuda-verify
  356. path: |
  357. build/bin/
  358. build/lib*/
  359. build/*.so
  360. retention-days: 7
  361. # CUDA Build: Windows (Single-Architecture Distribution)
  362. # ===========================================================================
  363. # Strategy: Each architecture built separately for minimal file size
  364. # - CUDA 11.8: GTX 10 / RTX 20 / RTX 30 / RTX 40 (Driver >= 520)
  365. # - CUDA 12.9: RTX 50 only (Driver >= 575)
  366. build-cuda-windows:
  367. name: build-cuda-windows-${{ matrix.arch_name }}
  368. runs-on: windows-2022
  369. strategy:
  370. fail-fast: false
  371. matrix:
  372. include:
  373. # CUDA 11.8 builds (Driver >= 520)
  374. - { cuda_version: "11.8.0", arch: "61", arch_name: "gtx10-pascal" }
  375. - { cuda_version: "11.8.0", arch: "75", arch_name: "rtx20-turing" }
  376. - { cuda_version: "11.8.0", arch: "80", arch_name: "rtx30-desktop" }
  377. - { cuda_version: "11.8.0", arch: "86", arch_name: "rtx30-mobile" }
  378. - { cuda_version: "11.8.0", arch: "89", arch_name: "rtx40-ada" }
  379. # CUDA 12.9 build (Driver >= 575)
  380. - { cuda_version: "12.9.1", arch: "120", arch_name: "rtx50-blackwell" }
  381. steps:
  382. - name: Checkout
  383. uses: actions/checkout@v4
  384. - name: Setup MSVC
  385. uses: ilammy/msvc-dev-cmd@v1
  386. - name: Clone GGML
  387. run: git clone --depth 1 https://github.com/ggerganov/ggml.git ggml
  388. - name: Install CUDA Toolkit
  389. uses: Jimver/cuda-toolkit@master
  390. with:
  391. cuda: ${{ matrix.cuda_version }}
  392. method: network
  393. sub-packages: '["nvcc", "cudart", "cublas", "cublas_dev", "thrust", "visual_studio_integration"]'
  394. - name: Install Ninja
  395. run: choco install ninja -y
  396. - name: Configure and Build
  397. shell: cmd
  398. run: |
  399. REM CUDA 11.8 requires compatibility flags for newer MSVC
  400. if "${{ matrix.cuda_version }}" == "11.8.0" (
  401. set CUDAFLAGS=-allow-unsupported-compiler -D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH -D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR
  402. ) else (
  403. set CUDAFLAGS=
  404. )
  405. cmake -B build -G "Ninja Multi-Config" ^
  406. -DGGML_DIR=ggml ^
  407. -DGGML_CUDA=ON ^
  408. -DGGML_CUDA_FORCE_MMQ=ON ^
  409. -DCMAKE_CUDA_RUNTIME_LIBRARY=Static ^
  410. -DCMAKE_CUDA_ARCHITECTURES="${{ matrix.arch }}" ^
  411. -DMBR_BUILD_TESTS=OFF ^
  412. -DMBR_BUILD_CLI=ON
  413. cmake --build build --config Release -j %NUMBER_OF_PROCESSORS%
  414. - name: Verify Binary Dependencies
  415. shell: pwsh
  416. run: |
  417. Write-Host "=== Verifying Binary Dependencies ===" -ForegroundColor Cyan
  418. # Find all DLLs and EXEs
  419. $binaries = Get-ChildItem -Path build -Include *.dll,*.exe -Recurse -File
  420. if ($binaries.Count -eq 0) {
  421. Write-Host "WARNING: No binaries found!" -ForegroundColor Yellow
  422. exit 0
  423. }
  424. $hasProblems = $false
  425. $forbiddenDeps = @("cudart64", "cudart32", "cublas64", "cublas32", "cublasLt64")
  426. foreach ($binary in $binaries) {
  427. Write-Host "`n--- $($binary.Name) ---" -ForegroundColor Green
  428. # Use dumpbin to get dependencies
  429. $deps = & dumpbin /dependents $binary.FullName 2>&1
  430. # Extract DLL names
  431. $dllDeps = $deps | Select-String -Pattern "^\s+(\S+\.dll)" | ForEach-Object { $_.Matches.Groups[1].Value }
  432. if ($dllDeps) {
  433. Write-Host "Dependencies:"
  434. foreach ($dep in $dllDeps) {
  435. # Check for forbidden dependencies
  436. $isForbidden = $false
  437. foreach ($forbidden in $forbiddenDeps) {
  438. if ($dep -like "$forbidden*") {
  439. Write-Host " [FAIL] $dep" -ForegroundColor Red
  440. $isForbidden = $true
  441. $hasProblems = $true
  442. }
  443. }
  444. if (-not $isForbidden) {
  445. Write-Host " [OK] $dep" -ForegroundColor Gray
  446. }
  447. }
  448. } else {
  449. Write-Host " No DLL dependencies found (static build)" -ForegroundColor Gray
  450. }
  451. }
  452. Write-Host "`n=== Summary ===" -ForegroundColor Cyan
  453. if ($hasProblems) {
  454. Write-Host "FAILED: Found forbidden CUDA runtime dependencies!" -ForegroundColor Red
  455. Write-Host "The build should use static CUDA runtime linking." -ForegroundColor Red
  456. exit 1
  457. } else {
  458. Write-Host "PASSED: No forbidden CUDA dependencies found." -ForegroundColor Green
  459. }
  460. - name: Upload Build Artifacts
  461. uses: actions/upload-artifact@v4
  462. with:
  463. name: build-windows-cuda-${{ matrix.arch_name }}
  464. path: |
  465. build/bin/
  466. build/Release/
  467. build/*.dll
  468. retention-days: 7
  469. # ----- Prepare Release Artifact -----
  470. - name: Prepare Release Artifact
  471. shell: pwsh
  472. run: |
  473. # Create release directory
  474. New-Item -ItemType Directory -Force -Path "release\mel-band-roformer"
  475. # Find and copy CLI executable
  476. $CliPath = Get-ChildItem -Path build -Filter "mel_band_roformer-cli.exe" -Recurse -File | Select-Object -First 1
  477. if ($CliPath) {
  478. Copy-Item $CliPath.FullName "release\mel-band-roformer\"
  479. }
  480. # Copy DLL files
  481. Get-ChildItem -Path build -Filter "*.dll" -Recurse -File | ForEach-Object {
  482. Copy-Item $_.FullName "release\mel-band-roformer\" -ErrorAction SilentlyContinue
  483. }
  484. # List contents
  485. Write-Host "Release artifact contents:"
  486. Get-ChildItem "release\mel-band-roformer" | Format-Table Name, Length
  487. - name: Upload Release Artifact
  488. uses: actions/upload-artifact@v4
  489. with:
  490. name: MelBandRoformer-windows-cuda-${{ matrix.arch_name }}
  491. path: release\mel-band-roformer\
  492. retention-days: 30