Files
vendoo/scripts/runtime-start-local-flux.ps1
T
Masterluke77andGitHub 6f48827f4d Vendoo 1.41.2 – Git Ignore Boundary & Module Tracking Hotfix (#18)
* docs: prepare Vendoo 1.41.2 git-ignore boundary hotfix

* fix: track native source modules with root-anchored runtime ignores
2026-07-09 17:09:00 +02:00

211 lines
8.2 KiB
PowerShell

param(
[int]$StartupTimeoutSeconds = 180,
[ValidateSet('auto','fast','balanced','lowvram')]
[string]$Profile = 'auto'
)
$ErrorActionPreference = 'Stop'
Set-StrictMode -Version 2.0
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
if ((Split-Path -Leaf $ScriptDir) -eq 'local-ai') {
$VendooDir = Split-Path -Parent $ScriptDir
} else {
$VendooDir = Split-Path -Parent $ScriptDir
}
$LocalAiDir = Join-Path $VendooDir 'local-ai'
$PortableRoot = Join-Path $LocalAiDir 'comfyui\ComfyUI_windows_portable'
$Python = Join-Path $PortableRoot 'python_embeded\python.exe'
$Main = Join-Path $PortableRoot 'ComfyUI\main.py'
$LogDir = Join-Path $VendooDir 'logs'
$StdoutLog = Join-Path $LogDir 'local-flux-runtime.log'
$StderrLog = Join-Path $LogDir 'local-flux-runtime-error.log'
$StateFile = Join-Path $LogDir 'local-flux-runtime-state.json'
$PidFile = Join-Path $LogDir 'local-flux-runtime.pid'
$ComfyUrl = 'http://127.0.0.1:8188'
$ComfyPort = 8188
New-Item -ItemType Directory -Force -Path $LogDir | Out-Null
$env:PYTHONUTF8 = '1'
$env:PYTHONIOENCODING = 'utf-8'
$env:NO_COLOR = '1'
function Write-Utf8NoBom([string]$Path, [string]$Content) {
$encoding = New-Object System.Text.UTF8Encoding($false)
[System.IO.File]::WriteAllText($Path, $Content, $encoding)
}
function Remove-Ansi([string]$Text) {
if ([string]::IsNullOrEmpty($Text)) { return '' }
$pattern = ([string][char]27) + '\\[[0-?]*[ -/]*[@-~]'
return [regex]::Replace($Text, $pattern, '')
}
function Read-Tail([string]$Path, [int]$Count = 16) {
if (-not (Test-Path -LiteralPath $Path)) { return @() }
try {
return @(Get-Content -LiteralPath $Path -Tail $Count -ErrorAction SilentlyContinue | ForEach-Object { Remove-Ansi ([string]$_) })
} catch { return @() }
}
function Save-RuntimeState([string]$Status, [string]$Message, [int]$ProcessId = 0, [int]$Elapsed = 0, [string]$ErrorMessage = '') {
$state = [ordered]@{
status = $Status
message = $Message
pid = if ($ProcessId -gt 0) { $ProcessId } else { $null }
port = $ComfyPort
url = $ComfyUrl
elapsed_seconds = $Elapsed
updated_at = (Get-Date).ToString('o')
stdout_log = $StdoutLog
stderr_log = $StderrLog
error = $ErrorMessage
stdout_tail = @(Read-Tail $StdoutLog 12)
stderr_tail = @(Read-Tail $StderrLog 16)
}
Write-Utf8NoBom -Path $StateFile -Content ($state | ConvertTo-Json -Depth 5)
if ($ProcessId -gt 0) { Write-Utf8NoBom -Path $PidFile -Content ([string]$ProcessId) }
}
function Test-ComfyFlag([string]$Flag) {
try {
$help = & $Python -s $Main --help 2>&1 | Out-String
return $help -match [regex]::Escape($Flag)
} catch { return $false }
}
function Get-NvidiaVramGb {
try {
$line = & nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits 2>$null | Select-Object -First 1
if ($line -match '^\s*(\d+)') { return [math]::Round(([double]$Matches[1] / 1024), 1) }
} catch {}
return 0
}
function Get-PerformanceArguments([string]$RequestedProfile) {
$effective = $RequestedProfile
$vramGb = Get-NvidiaVramGb
if ($effective -eq 'auto') {
if ($vramGb -ge 12) { $effective = 'fast' }
elseif ($vramGb -gt 0 -and $vramGb -lt 8) { $effective = 'lowvram' }
else { $effective = 'balanced' }
}
$flags = New-Object System.Collections.Generic.List[string]
if ($effective -eq 'fast') {
$flags.Add('--highvram')
$flags.Add('--cache-classic')
if (Test-ComfyFlag '--fast') {
$flags.Add('--fast'); $flags.Add('fp16_accumulation'); $flags.Add('cublas_ops')
}
} elseif ($effective -eq 'lowvram') {
$flags.Add('--lowvram')
$flags.Add('--cache-none')
} else {
$flags.Add('--cache-classic')
}
return [pscustomobject]@{ profile = $effective; requested = $RequestedProfile; vram_gb = $vramGb; flags = @($flags) }
}
function Test-ComfyReady {
try {
$response = Invoke-WebRequest -UseBasicParsing -Uri "$ComfyUrl/system_stats" -TimeoutSec 4
return $response.StatusCode -ge 200 -and $response.StatusCode -lt 300
} catch { return $false }
}
function Get-ComfyProcess {
try {
$items = @(Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
$_.CommandLine -and
$_.CommandLine -match 'ComfyUI[\\/]main\.py' -and
$_.CommandLine -match "--port\s+$ComfyPort"
} | Select-Object -First 1)
if ($items.Count -gt 0) { return $items[0] }
return $null
} catch { return $null }
}
try {
if (-not (Test-Path -LiteralPath $Python)) { throw "Embedded Python wurde nicht gefunden: $Python" }
if (-not (Test-Path -LiteralPath $Main)) { throw "ComfyUI main.py wurde nicht gefunden: $Main" }
if (Test-ComfyReady) {
$existingReady = Get-ComfyProcess
$readyPid = if ($existingReady) { [int]$existingReady.ProcessId } else { 0 }
Save-RuntimeState 'ready' 'FLUX / ComfyUI ist bereits aktiv und erreichbar.' $readyPid 0
exit 0
}
$existing = Get-ComfyProcess
$comfyPid = 0
$process = $null
if ($existing) {
$comfyPid = [int]$existing.ProcessId
Save-RuntimeState 'starting' 'Ein vorhandener ComfyUI-Prozess initialisiert noch.' $comfyPid 0
} else {
Remove-Item -LiteralPath $StdoutLog,$StderrLog -Force -ErrorAction SilentlyContinue
$performance = Get-PerformanceArguments $Profile
$arguments = @(
'-s', $Main,
'--listen', '127.0.0.1',
'--port', [string]$ComfyPort,
'--disable-auto-launch',
'--preview-method', 'none',
'--windows-standalone-build',
'--disable-all-custom-nodes',
'--log-stdout',
'--verbose', 'INFO'
)
foreach ($flag in $performance.flags) { $arguments += $flag }
$process = Start-Process -FilePath $Python -ArgumentList $arguments -WorkingDirectory $PortableRoot -WindowStyle Hidden -RedirectStandardOutput $StdoutLog -RedirectStandardError $StderrLog -PassThru
if (-not $process) { throw 'Der ComfyUI-Prozess konnte nicht gestartet werden.' }
$comfyPid = [int]$process.Id
Save-RuntimeState 'starting' ("FLUX / ComfyUI wird initialisiert · Profil: {0} · VRAM: {1} GB." -f $performance.profile, $performance.vram_gb) $comfyPid 0
}
$startedAt = Get-Date
while (((Get-Date) - $startedAt).TotalSeconds -lt $StartupTimeoutSeconds) {
Start-Sleep -Seconds 2
$elapsed = [int][math]::Round(((Get-Date) - $startedAt).TotalSeconds)
if (Test-ComfyReady) {
Save-RuntimeState 'ready' "FLUX / ComfyUI ist nach ${elapsed}s erreichbar." $comfyPid $elapsed
exit 0
}
$alive = $false
try { $alive = $null -ne (Get-Process -Id $comfyPid -ErrorAction SilentlyContinue) } catch {}
if (-not $alive) {
$stderrTail = (Read-Tail $StderrLog 24) -join "`n"
$stdoutTail = (Read-Tail $StdoutLog 24) -join "`n"
$detail = if ($stderrTail) { $stderrTail } elseif ($stdoutTail) { $stdoutTail } else { 'Der Prozess wurde ohne verwertbare Ausgabe beendet.' }
Save-RuntimeState 'failed' 'ComfyUI wurde während des Starts beendet.' $comfyPid $elapsed $detail
throw "ComfyUI wurde während des Starts beendet. $detail"
}
$tail = @((Read-Tail $StdoutLog 3) + (Read-Tail $StderrLog 3)) | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
$lastLine = if ($tail.Count -gt 0) { [string]$tail[-1] } else { 'ComfyUI initialisiert Python, Datenbank und Modelle.' }
Save-RuntimeState 'starting' "Start läuft seit ${elapsed}s: $lastLine" $comfyPid $elapsed
}
$timeoutDetail = @((Read-Tail $StderrLog 24) + (Read-Tail $StdoutLog 24)) -join "`n"
Stop-Process -Id $comfyPid -Force -ErrorAction SilentlyContinue
Save-RuntimeState 'failed' "ComfyUI war nach ${StartupTimeoutSeconds}s noch nicht erreichbar und wurde beendet." $comfyPid $StartupTimeoutSeconds $timeoutDetail
throw "ComfyUI war nach ${StartupTimeoutSeconds}s noch nicht erreichbar und wurde beendet. Prüfe $StderrLog und $StdoutLog."
} catch {
$message = Remove-Ansi ([string]$_.Exception.Message)
$currentPid = 0
try { if (Test-Path -LiteralPath $PidFile) { $currentPid = [int](Get-Content -LiteralPath $PidFile -Raw).Trim() } } catch {}
$elapsed = 0
try {
if (Test-Path -LiteralPath $StateFile) {
$oldState = Get-Content -LiteralPath $StateFile -Raw | ConvertFrom-Json
$elapsed = [int]$oldState.elapsed_seconds
}
} catch {}
Save-RuntimeState 'failed' 'FLUX / ComfyUI konnte nicht gestartet werden.' $currentPid $elapsed $message
Write-Error $message
exit 1
}