param( [int]$Port = 9883, [string]$Language = 'KR', [ValidateSet('auto', 'cuda', 'cpu')] [string]$Device = 'auto', [int]$WaitReadySeconds = 300 ) # 노트북 상주 MeloTTS 한국어 TTS 사이드카를 띄운다. # MIT 라이선스 사전학습 다화자 모델이라 상업 사용 제약도, 실존 인물 reference 문제도 없다. # 그래서 Higgs 와 달리 dev 전용 가드나 P1 프리셋 한정이 필요 없다. $ErrorActionPreference = 'Stop' [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false) $OutputEncoding = [System.Text.UTF8Encoding]::new($false) $repoRoot = Split-Path -Parent $PSScriptRoot $serverScript = Join-Path $PSScriptRoot 'melotts-server.py' $venvPython = 'C:\Users\encep\.venvs\vignette-melotts\Scripts\python.exe' $healthUrl = "http://127.0.0.1:$Port/health" $runtimeLogDir = Join-Path $env:TEMP 'Vignette\melotts' $stdoutLog = Join-Path $runtimeLogDir 'server.out.log' $stderrLog = Join-Path $runtimeLogDir 'server.err.log' if (!(Test-Path -LiteralPath $serverScript)) { throw "MeloTTS 서버 스크립트를 찾지 못했습니다: $serverScript" } if (!(Test-Path -LiteralPath $venvPython)) { throw @" MeloTTS 전용 venv 를 찾지 못했습니다: $venvPython 설치 순서: python -m venv C:\Users\encep\.venvs\vignette-melotts & C:\Users\encep\.venvs\vignette-melotts\Scripts\python.exe -m pip install "git+https://github.com/myshell-ai/MeloTTS.git" & ... -m pip install "setuptools<81" eunjeon # librosa 0.9.1 의 pkg_resources, 한국어 g2p & ... -m unidic download # MeloTTS 가 무조건 임포트하는 일본어 사전 "@ } try { $currentHealth = Invoke-RestMethod -Uri $healthUrl -Method Get -TimeoutSec 3 if ($currentHealth.status -eq 'ok') { Write-Output "MeloTTS가 이미 준비됐습니다: $healthUrl" $currentHealth | ConvertTo-Json -Depth 4 -Compress return } } catch { # 아직 서버가 없으면 아래에서 시작한다. } $listener = Get-NetTCPConnection -State Listen -LocalPort $Port -ErrorAction SilentlyContinue if ($null -ne $listener) { throw "포트 $Port 를 다른 프로세스가 사용 중입니다. 임의 종료하지 않았습니다." } New-Item -ItemType Directory -Path $runtimeLogDir -Force | Out-Null $serverArgs = @( '-X', 'utf8', $serverScript, '--host', '127.0.0.1', '--port', "$Port", '--language', $Language, '--device', $Device ) $process = Start-Process -WindowStyle Hidden -FilePath $venvPython ` -ArgumentList $serverArgs ` -WorkingDirectory $repoRoot ` -RedirectStandardOutput $stdoutLog ` -RedirectStandardError $stderrLog ` -PassThru Write-Output "MeloTTS 로드를 시작했습니다. PID=$($process.Id) language=$Language device=$Device" Write-Output "로그: $stdoutLog" if ($WaitReadySeconds -le 0) { return } $deadline = (Get-Date).AddSeconds($WaitReadySeconds) while ((Get-Date) -lt $deadline) { if ($process.HasExited) { throw "MeloTTS가 준비되기 전에 종료됐습니다. stderr=$stderrLog" } try { $health = Invoke-RestMethod -Uri $healthUrl -Method Get -TimeoutSec 3 if ($health.status -eq 'ok') { Write-Output "MeloTTS 준비 완료: $healthUrl" $health | ConvertTo-Json -Depth 4 -Compress return } } catch { Start-Sleep -Seconds 3 } } throw "MeloTTS 준비 시간이 ${WaitReadySeconds}초를 넘었습니다. 로그: $stdoutLog"