vignette/scripts/start-local-whisper-stt.ps1
Yun Chan 16e791e044 G0~G8 성과·동맹 측정 OS 작업 일괄 고정
8월 7일까지 워킹트리에만 남아 있던 미커밋 작업을 커밋한다. 여러 사본
폴더(worktree·clone)에 흩어져 있던 중간 스냅샷을 정리하기 전에 원본을
git 이력으로 고정하는 것이 목적이다.

- contracts/routes/services: measurement, outcome_trajectory, rupture_repair,
  deliberate_practice, calibration_transfer, supervision_research,
  multimodal_alliance, continuous_improvement 계열 신규 모듈과 테스트
- infra/db/init: 07~16 마이그레이션(측정 기반~calibration transfer 실행)
- apps/web: 세션 리뷰 카드·관리 화면·E2E 스펙 추가
- docs/ops: G0~G8 라이브 통합·배포·롤백 증거 문서와 evidence JSON/PNG
- scripts: smoke·ledger·릴리스 에이전트·NAS 프리뷰 운영 스크립트

engine.public 로그 .bak과 apps/web/test-results 산출물은 커밋에서 제외했다.
2026-08-08 01:30:53 +09:00

89 lines
3 KiB
PowerShell

param(
[int]$Port = 9882,
[ValidateSet('large-v3', 'large-v3-turbo', 'medium', 'small', 'base')]
[string]$Model = 'large-v3',
[ValidateSet('auto', 'cuda', 'cpu')]
[string]$Device = 'auto',
[int]$WaitReadySeconds = 180
)
# 노트북 상주 faster-whisper 스트리밍 STT 사이드카를 띄운다.
# 오디오는 호스트를 벗어나지 않고 외부 STT 키도 필요 없다.
$ErrorActionPreference = 'Stop'
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)
$OutputEncoding = [System.Text.UTF8Encoding]::new($false)
$repoRoot = Split-Path -Parent $PSScriptRoot
$serverScript = Join-Path $PSScriptRoot 'local-whisper-stt-server.py'
$runtimeLogDir = Join-Path $env:TEMP 'Vignette\local-whisper-stt'
$stdoutLog = Join-Path $runtimeLogDir 'server.out.log'
$stderrLog = Join-Path $runtimeLogDir 'server.err.log'
if (!(Test-Path -LiteralPath $serverScript)) {
throw "로컬 whisper 서버 스크립트를 찾지 못했습니다: $serverScript"
}
# faster-whisper 가 설치된 인터프리터를 고른다.
$pyCandidates = @(
(Join-Path $env:LOCALAPPDATA 'Programs\Python\Python311\python.exe'),
(Join-Path $env:LOCALAPPDATA 'Programs\Python\Python312\python.exe'),
'python'
)
$python = $null
foreach ($candidate in $pyCandidates) {
try {
& $candidate -c 'import faster_whisper, websockets' 2>$null
if ($LASTEXITCODE -eq 0) { $python = $candidate; break }
} catch { }
}
if (-not $python) {
throw 'faster_whisper 와 websockets 가 설치된 python 을 찾지 못했습니다.'
}
Write-Output "python: $python"
$listener = Get-NetTCPConnection -State Listen -LocalPort $Port -ErrorAction SilentlyContinue
if ($null -ne $listener) {
Write-Output "포트 $Port 에 이미 리스너가 있습니다. 임의 종료하지 않았습니다."
return
}
New-Item -ItemType Directory -Path $runtimeLogDir -Force | Out-Null
$serverArgs = @(
'-X', 'utf8', $serverScript,
'--host', '127.0.0.1',
'--port', "$Port",
'--model', $Model,
'--device', $Device,
'--enable'
)
$process = Start-Process -WindowStyle Hidden -FilePath $python `
-ArgumentList $serverArgs `
-WorkingDirectory $repoRoot `
-RedirectStandardOutput $stdoutLog `
-RedirectStandardError $stderrLog `
-PassThru
Write-Output "로컬 whisper STT 로드를 시작했습니다. PID=$($process.Id) model=$Model device=$Device"
Write-Output "로그: $stdoutLog"
if ($WaitReadySeconds -le 0) {
return
}
$deadline = (Get-Date).AddSeconds($WaitReadySeconds)
while ((Get-Date) -lt $deadline) {
if ($process.HasExited) {
throw "로컬 whisper STT가 준비되기 전에 종료됐습니다. stderr=$stderrLog"
}
$ready = Get-NetTCPConnection -State Listen -LocalPort $Port -ErrorAction SilentlyContinue
if ($null -ne $ready) {
Write-Output "로컬 whisper STT 준비 완료: ws://127.0.0.1:$Port/v1/listen"
if (Test-Path -LiteralPath $stdoutLog) {
Get-Content -LiteralPath $stdoutLog -Tail 1
}
return
}
Start-Sleep -Seconds 2
}
throw "로컬 whisper STT 준비 시간이 ${WaitReadySeconds}초를 넘었습니다. 로그: $stdoutLog"