Skip to content

Commit 22e490c

Browse files
author
kigner
committed
fix(release): validate portable v0.3 upgrades
1 parent 5e19a3c commit 22e490c

4 files changed

Lines changed: 157 additions & 11 deletions

File tree

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# audio.cpp Windows portable v0.3.0
2+
3+
This release brings the Windows portable package up to the current audio.cpp
4+
runtime and WebUI, with new TTS integrations, broader GGUF support, and fixes
5+
for local browser and dictation workflows.
6+
7+
## Highlights
8+
9+
- Added four TTS families to the runtime, model manager, and WebUI:
10+
- Fish Audio S2 Pro
11+
- Higgs Audio v3 TTS 4B
12+
- OuteTTS 1.0 1B
13+
- VieNeu-TTS v3 Turbo
14+
- Expanded model-spec and GGUF package support, including corrected WebUI GGUF
15+
model detection/loading and updated GGUF paths for supported packages.
16+
- Added OmniVoice pseudo-streaming and GGUF tokenizer support.
17+
- Added the bundled MarbleNet VAD model alongside Silero VAD.
18+
- Added optional local-demo CORS support to `audiocpp_server`.
19+
- Moved the default TTS server port to `8088` to avoid common local port
20+
conflicts while keeping ASR on `8081`.
21+
- Fixed SpeakType microphone capture on Windows by selecting the WASAPI default
22+
input, recording at the device's native sample rate, and continuously
23+
resampling to the ASR rate. This resolves cases where the UI showed a waveform
24+
but ASR returned an empty transcript.
25+
- Rebuilt the CPU and CUDA cores with the latest Windows build fixes and runtime
26+
updates.
27+
28+
## Updating
29+
30+
Run `update.bat` from an existing Windows portable installation.
31+
32+
- Supported source versions: `0.2.0`, `0.2.1`, and `0.2.2`
33+
- Updated components: `app`, `core-cpu`, and `core-cuda`
34+
- Python environment changes: none
35+
- CUDA runtime changes: none
36+
37+
The updater preserves downloaded models, custom voices, generated output, API
38+
keys, logs, UI language preferences, and SpeakType configuration. If validation
39+
fails, managed files are restored from `_update\backup\`.
40+
41+
## Validation
42+
43+
- Verified full apply updates from `0.2.0`, `0.2.1`, and `0.2.2` to `0.3.0`
44+
- Verified updater signature, hash, protected-path, rollback, self-update, and
45+
user-data preservation paths
46+
- Verified CPU and CUDA CLI/server/GGUF binaries
47+
- Passed WebUI and SpeakType automated tests

scripts/build_update_release.ps1

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ param(
55
[string]$OutputDir = "",
66
[string]$ReleaseTag = "",
77
[string]$Repository = "kigner/audio.cpp-webui",
8+
[string]$ReleaseNotesPath = "",
89
[Parameter(Mandatory = $true)][string]$MinisignSecretKey,
910
[Parameter(Mandatory = $true)][string]$MinisignPublicKey,
1011
[string]$MinisignPath = "minisign.exe",
@@ -29,6 +30,7 @@ $PortableRoot = [IO.Path]::GetFullPath($PortableRoot)
2930
$OutputDir = [IO.Path]::GetFullPath($OutputDir)
3031
$MinisignSecretKey = [IO.Path]::GetFullPath($MinisignSecretKey)
3132
$MinisignPublicKey = [IO.Path]::GetFullPath($MinisignPublicKey)
33+
if ($ReleaseNotesPath -ne "") { $ReleaseNotesPath = [IO.Path]::GetFullPath($ReleaseNotesPath) }
3234
$stageRoot = Join-Path $OutputDir ".staging"
3335

3436
$preserveRules = @(
@@ -152,6 +154,7 @@ function Get-AppInputs {
152154
SpeakType `
153155
tools/model_manager.py `
154156
assets/model_manager `
157+
assets/framework/models/marblenet_vad `
155158
model_specs)
156159
if ($LASTEXITCODE -ne 0) { throw "git ls-files failed." }
157160
foreach ($relative in $tracked) {
@@ -166,6 +169,7 @@ function Get-AppInputs {
166169
$normalized -notin @("SpeakType/config.json", "SpeakType/logs/.gitkeep")
167170
} elseif ($normalized -eq "tools/model_manager.py" -or
168171
$normalized.StartsWith("assets/model_manager/") -or
172+
$normalized.StartsWith("assets/framework/models/marblenet_vad/") -or
169173
$normalized.StartsWith("model_specs/")) {
170174
$include = $true
171175
}
@@ -261,6 +265,9 @@ if (-not (Test-Path -LiteralPath $MinisignSecretKey -PathType Leaf)) {
261265
if (-not (Test-Path -LiteralPath $MinisignPublicKey -PathType Leaf)) {
262266
throw "Minisign public key not found: $MinisignPublicKey"
263267
}
268+
if ($ReleaseNotesPath -ne "" -and -not (Test-Path -LiteralPath $ReleaseNotesPath -PathType Leaf)) {
269+
throw "Release notes file not found: $ReleaseNotesPath"
270+
}
264271
if ((Get-Content -LiteralPath $MinisignPublicKey -Raw -Encoding UTF8) -match 'REPLACE_WITH_') {
265272
throw "Refusing to use a placeholder minisign public key."
266273
}
@@ -339,7 +346,11 @@ if ($Stable) {
339346
$stablePointer | ConvertTo-Json -Depth 10 | Set-Content -LiteralPath $stablePath -Encoding UTF8
340347
}
341348

342-
$releaseNotes = @"
349+
$releaseNotesOutput = Join-Path $OutputDir "release-notes.md"
350+
if ($ReleaseNotesPath -ne "") {
351+
Copy-Item -LiteralPath $ReleaseNotesPath -Destination $releaseNotesOutput -Force
352+
} else {
353+
$releaseNotes = @"
343354
# audio.cpp Windows portable v$Version
344355
345356
## Update
@@ -355,7 +366,8 @@ The updater does not overwrite models, custom voices, output files, API keys,
355366
logs, or SpeakType user configuration. Failed updates roll back managed files
356367
from `_update\\backup\\`.
357368
"@
358-
Set-Content -LiteralPath (Join-Path $OutputDir "release-notes.md") -Value $releaseNotes -Encoding UTF8
369+
Set-Content -LiteralPath $releaseNotesOutput -Value $releaseNotes -Encoding UTF8
370+
}
359371

360372
$sumCandidates = @(Get-ChildItem -LiteralPath $OutputDir -File | Where-Object {
361373
$_.Name -notin @("SHA256SUMS.txt", "SHA256SUMS.txt.minisig")

tests/updater/run_tests.ps1

Lines changed: 95 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,13 @@ function Write-Json {
3131
}
3232

3333
function New-TestBundle {
34-
param([string]$Name)
34+
param(
35+
[string]$Name,
36+
[string]$BundleVersion = "0.2.0",
37+
[string]$AppVersion = $BundleVersion,
38+
[string]$CoreCpuVersion = $BundleVersion,
39+
[string]$CoreCudaVersion = $BundleVersion
40+
)
3541
$root = Join-Path $testRoot $Name
3642
New-Item -ItemType Directory -Path (Join-Path $root "updater") -Force | Out-Null
3743
Copy-Item -LiteralPath (Join-Path $repoRoot "update.bat") -Destination (Join-Path $root "update.bat")
@@ -48,11 +54,17 @@ function New-TestBundle {
4854
) | Set-Content -LiteralPath $verifier -Encoding ASCII
4955
$version = [ordered]@{
5056
product = "audiocpp-portable"
51-
version = "0.2.0"
57+
version = $BundleVersion
5258
channel = "stable"
5359
platform = "windows-x64"
5460
python = "3.11"
55-
components = [ordered]@{ app = "0.2.0"; core_cpu = "0.2.0"; core_cuda = "0.2.0"; python_env = "0.2.0"; updater = $testUpdaterVersion }
61+
components = [ordered]@{
62+
app = $AppVersion
63+
core_cpu = $CoreCpuVersion
64+
core_cuda = $CoreCudaVersion
65+
python_env = "0.2.0"
66+
updater = $testUpdaterVersion
67+
}
5668
}
5769
Write-Json $version (Join-Path $root "version.json")
5870
return $root
@@ -63,7 +75,8 @@ function New-TestArchive {
6375
[string]$Directory,
6476
[string]$FileName,
6577
[string]$ManagedPath,
66-
[string]$Content = "new managed content"
78+
[string]$Content = "new managed content",
79+
[string]$Component = "app"
6780
)
6881
$stage = Join-Path $Directory ("stage-" + [guid]::NewGuid().ToString("N"))
6982
$payload = Join-Path $stage "payload"
@@ -73,7 +86,7 @@ function New-TestArchive {
7386
$file = Get-Item -LiteralPath $filePath
7487
$index = [ordered]@{
7588
schema = 1
76-
component = "app"
89+
component = $Component
7790
files = @([ordered]@{
7891
path = $ManagedPath
7992
size = [int64]$file.Length
@@ -135,14 +148,16 @@ function New-CustomManifest {
135148
[string]$Directory,
136149
[object[]]$Components,
137150
[string]$MinimumUpdater = $testUpdaterVersion,
138-
[string[]]$HealthChecks = @()
151+
[string[]]$HealthChecks = @(),
152+
[string]$ManifestVersion = "0.2.1",
153+
[string]$SupportedFrom = ">=0.2.0 <0.3.0"
139154
)
140155
$value = [ordered]@{
141156
schema = 1
142157
product = "audiocpp-portable"
143158
platform = "windows-x64"
144-
version = "0.2.1"
145-
supported_from = ">=0.2.0 <0.3.0"
159+
version = $ManifestVersion
160+
supported_from = $SupportedFrom
146161
minimum_updater = $MinimumUpdater
147162
components = $Components
148163
preserve = $requiredPreserve
@@ -468,6 +483,62 @@ function Test-UpdaterSelfUpdate {
468483
Assert-True ((Read-JsonFile (Join-Path $root "version.json")).components.updater -eq "1.2.0") "version.json did not record the new updater version"
469484
}
470485

486+
function Test-UpgradeMatrixFromSupportedVersions {
487+
$cases = @(
488+
[pscustomobject]@{
489+
Version = "0.2.0"
490+
App = "0.2.0"
491+
CoreCpu = "0.2.0"
492+
CoreCuda = "0.2.0"
493+
},
494+
[pscustomobject]@{
495+
Version = "0.2.1"
496+
App = "0.2.1"
497+
CoreCpu = "0.2.1"
498+
CoreCuda = "0.2.1"
499+
},
500+
[pscustomobject]@{
501+
Version = "0.2.2"
502+
App = "0.2.1"
503+
CoreCpu = "0.2.1"
504+
CoreCuda = "0.2.2"
505+
}
506+
)
507+
508+
foreach ($case in $cases) {
509+
$root = New-TestBundle "upgrade-$($case.Version)" `
510+
-BundleVersion $case.Version `
511+
-AppVersion $case.App `
512+
-CoreCpuVersion $case.CoreCpu `
513+
-CoreCudaVersion $case.CoreCuda
514+
New-Item -ItemType Directory -Path (Join-Path $root "models") -Force | Out-Null
515+
Set-Content -LiteralPath (Join-Path $root "models\user-model.bin") -Value "preserve me" -Encoding ASCII
516+
517+
$assets = Join-Path $root "assets"
518+
New-Item -ItemType Directory -Path $assets -Force | Out-Null
519+
$appArchive = New-TestArchive $assets "app-v0.3.0.zip" "webui\upgrade-matrix.txt" "app 0.3.0" "app"
520+
$cpuArchive = New-TestArchive $assets "core-cpu-v0.3.0.zip" "cpu\audiocpp_cli.exe" "cpu 0.3.0" "core-cpu"
521+
$cudaArchive = New-TestArchive $assets "core-cuda-v0.3.0.zip" "gpu\audiocpp_cli.exe" "cuda 0.3.0" "core-cuda"
522+
$components = @(
523+
(New-ComponentDescriptor "app" "0.3.0" $appArchive),
524+
(New-ComponentDescriptor "core-cpu" "0.3.0" $cpuArchive),
525+
(New-ComponentDescriptor "core-cuda" "0.3.0" $cudaArchive)
526+
)
527+
$manifest = New-CustomManifest $assets $components `
528+
-ManifestVersion "0.3.0" `
529+
-SupportedFrom ">=0.2.0"
530+
531+
$result = Invoke-TestUpdater $root "--apply" $manifest
532+
Assert-True ($result.ExitCode -eq 0) "upgrade from $($case.Version) failed: $($result.Output)"
533+
$installed = Read-JsonFile (Join-Path $root "version.json")
534+
Assert-True ([string]$installed.version -eq "0.3.0") "upgrade from $($case.Version) did not commit target version"
535+
Assert-True ([string]$installed.components.app -eq "0.3.0") "upgrade from $($case.Version) did not update app"
536+
Assert-True ([string]$installed.components.core_cpu -eq "0.3.0") "upgrade from $($case.Version) did not update core-cpu"
537+
Assert-True ([string]$installed.components.core_cuda -eq "0.3.0") "upgrade from $($case.Version) did not update core-cuda"
538+
Assert-True ((Get-Content -LiteralPath (Join-Path $root "models\user-model.bin") -Raw) -match "preserve me") "upgrade from $($case.Version) changed preserved model data"
539+
}
540+
}
541+
471542
function Test-ReleaseBuilder {
472543
$root = Join-Path $testRoot "release-builder"
473544
$portable = Join-Path $root "portable"
@@ -499,13 +570,15 @@ function Test-ReleaseBuilder {
499570
Expand-Archive -LiteralPath $pythonDepsZip -DestinationPath $pythonDepsSource
500571
Remove-Item -LiteralPath (Join-Path $pythonDepsSource "files.json") -Force
501572
$output = Join-Path $root "output"
573+
$releaseNotes = Join-Path $root "custom-release-notes.md"
574+
Set-Content -LiteralPath $releaseNotes -Value "# Custom release notes" -Encoding UTF8
502575
$builder = Join-Path $repoRoot "scripts\build_update_release.ps1"
503576
$previousErrorAction = $ErrorActionPreference
504577
$ErrorActionPreference = "Continue"
505578
$builderOutput = @(& powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -File $builder `
506579
-Version "0.2.1" -PortableRoot $portable -OutputDir $output -MinisignSecretKey $secret `
507580
-MinisignPublicKey $publicKey -MinisignPath $signer -PythonDepsSource $pythonDepsSource `
508-
-IncludeUpdater -UpdaterMinisignBinary $signer -Stable -AllowDirty 2>&1)
581+
-IncludeUpdater -UpdaterMinisignBinary $signer -ReleaseNotesPath $releaseNotes -Stable -AllowDirty 2>&1)
509582
$exitCode = $LASTEXITCODE
510583
$ErrorActionPreference = $previousErrorAction
511584
Assert-True ($exitCode -eq 0) "release builder failed: $($builderOutput -join "`n")"
@@ -528,6 +601,18 @@ function Test-ReleaseBuilder {
528601
Assert-True (@($manifest.components).Count -eq 5) "release manifest does not contain all five component types"
529602
Assert-True (@($manifest.preserve) -contains "webui/voice/**") "release manifest omitted voice preservation"
530603
Assert-True ([string]$manifest.supported_from -eq ">=0.2.0") "release manifest does not keep bootstrap installs eligible for later versions"
604+
Assert-True ((Get-Content -LiteralPath (Join-Path $output "release-notes.md") -Raw) -match "Custom release notes") "release builder did not use custom release notes"
605+
$appExpanded = Join-Path $root "app-expanded"
606+
Expand-Archive -LiteralPath (Join-Path $output "audiocpp-app-v0.2.1.zip") -DestinationPath $appExpanded
607+
foreach ($relative in @(
608+
"payload\tools\model_manager.py",
609+
"payload\model_specs\qwen3_asr.json",
610+
"payload\assets\framework\models\marblenet_vad\marblenet_vad.safetensors",
611+
"payload\assets\framework\models\marblenet_vad\marblenet_vad_config.json",
612+
"payload\assets\framework\models\marblenet_vad\marblenet_vad_labels.txt"
613+
)) {
614+
Assert-True (Test-Path -LiteralPath (Join-Path $appExpanded $relative) -PathType Leaf) "app ZIP omitted $relative"
615+
}
531616
foreach ($directory in @("cpu", "gpu")) {
532617
$archive = Join-Path $output "audiocpp-core-$($directory -replace 'gpu', 'cuda')-win-x64-v0.2.1.zip"
533618
$expanded = Join-Path $root "core-$directory-expanded"
@@ -565,6 +650,7 @@ try {
565650
"Test-ProtectedPathAndLock",
566651
"Test-PythonDependencyUpdateAndRollback",
567652
"Test-UpdaterSelfUpdate",
653+
"Test-UpgradeMatrixFromSupportedVersions",
568654
"Test-ReleaseBuilder"
569655
)
570656
foreach ($test in $tests) {

tools/check_loader_catalog_sync.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
# Registered loaders that intentionally have no installable ModelPackage.
3434
BUNDLED_LOADERS_WITHOUT_PACKAGE: set[str] = {
35+
"marblenet_vad",
3536
"silero_vad",
3637
}
3738

0 commit comments

Comments
 (0)