Files
Qwen3.5-9B-ToolHub-Enhanced…/start_8080_toolhub_stack.ps1
2026-03-11 16:49:00 +08:00

293 lines
9.0 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
param(
[string]$Command = 'status'
)
$ErrorActionPreference = 'Stop'
$ProgressPreference = 'SilentlyContinue'
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$RootDir = (Resolve-Path $ScriptDir).Path
$EnvConfig = Join-Path $RootDir 'env_config.ps1'
if (Test-Path $EnvConfig) {
. $EnvConfig
Import-EnvFile -Path (Join-Path $RootDir '.env')
}
$PythonBin = Join-Path $RootDir '.venv-qwen35\Scripts\python.exe'
$GatewayRun = Join-Path $RootDir 'run_8080_toolhub_gateway.py'
$RuntimeDir = Join-Path $RootDir '.tmp\toolhub_gateway'
$PidFile = Join-Path $RuntimeDir 'gateway.pid'
$LogFile = Join-Path $RuntimeDir 'gateway.log'
$ErrLogFile = Join-Path $RuntimeDir 'gateway.err.log'
$ModelSwitch = Join-Path $RootDir 'switch_qwen35_webui.ps1'
$GatewayHost = if ($env:GATEWAY_HOST) { $env:GATEWAY_HOST } else { '127.0.0.1' }
$GatewayPort = if ($env:GATEWAY_PORT) { $env:GATEWAY_PORT } else { '8080' }
$BackendHost = if ($env:BACKEND_HOST) { $env:BACKEND_HOST } else { '127.0.0.1' }
$BackendPort = if ($env:BACKEND_PORT) { $env:BACKEND_PORT } else { '8081' }
$ThinkMode = if ($env:THINK_MODE) { $env:THINK_MODE } else { 'think-on' }
$BackendWaitHint = '.\start_8080_toolhub_stack.cmd logs'
$SpinnerFrameIntervalMs = 120
$SpinnerProbeIntervalMs = 1000
function Ensure-Dir {
param([string]$Path)
if (-not (Test-Path $Path)) {
New-Item -Path $Path -ItemType Directory -Force | Out-Null
}
}
function Test-GatewayRunning {
if (-not (Test-Path $PidFile)) {
return $false
}
$raw = Get-Content -Path $PidFile -ErrorAction SilentlyContinue | Select-Object -First 1
$gatewayPid = 0
if (-not [int]::TryParse([string]$raw, [ref]$gatewayPid)) {
return $false
}
$proc = Get-Process -Id $gatewayPid -ErrorAction SilentlyContinue
return $null -ne $proc
}
function Test-GatewayReady {
try {
$null = Invoke-RestMethod -Uri "http://$GatewayHost`:$GatewayPort/gateway/health" -Method Get -TimeoutSec 2
return $true
} catch {
return $false
}
}
function Show-GatewayFailureLogs {
Write-Host '网关启动失败,最近日志如下:'
if (Test-Path $LogFile) {
Write-Host '=== 网关标准输出 ==='
Get-Content -Path $LogFile -Tail 120 -ErrorAction SilentlyContinue
}
if (Test-Path $ErrLogFile) {
Write-Host '=== 网关标准错误 ==='
Get-Content -Path $ErrLogFile -Tail 120 -ErrorAction SilentlyContinue
}
}
function Write-SpinnerLine {
param(
[string]$Label,
[double]$Current,
[int]$Total,
[int]$Tick
)
$frames = @('|', '/', '-', '\')
$frame = $frames[$Tick % $frames.Count]
$currentText = [string][int][Math]::Floor($Current)
Write-Host -NoNewline "`r$Label $frame $currentText/$Total"
}
function Complete-SpinnerLine {
Write-Host ''
}
function Stop-OrphanGatewayProcesses {
try {
$rootPattern = [regex]::Escape($RootDir)
$targets = Get-CimInstance Win32_Process -Filter "Name='python.exe'" -ErrorAction SilentlyContinue | Where-Object {
$cmd = [string]$_.CommandLine
$cmd -match 'run_8080_toolhub_gateway\.py' -and $cmd -match $rootPattern
}
foreach ($proc in $targets) {
if ($proc.ProcessId) {
Stop-Process -Id ([int]$proc.ProcessId) -Force -ErrorAction SilentlyContinue
}
}
} catch {}
}
function Start-Backend {
if ($env:MODEL_KEY -and $env:MODEL_KEY -ne '9b') {
throw "当前交付包仅支持 MODEL_KEY=9b收到: $($env:MODEL_KEY)"
}
$oldHost = $env:HOST
$oldPort = $env:PORT
try {
$env:HOST = $BackendHost
$env:PORT = $BackendPort
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $ModelSwitch '9b' $ThinkMode
if ($LASTEXITCODE -ne 0) {
throw '后端启动失败,请先查看上面的直接原因'
}
} finally {
$env:HOST = $oldHost
$env:PORT = $oldPort
}
}
function Start-Gateway {
Ensure-Dir $RuntimeDir
Stop-OrphanGatewayProcesses
if (Test-GatewayRunning) {
Write-Host '网关状态: 已运行'
Write-Host "PID: $(Get-Content -Path $PidFile)"
return
}
if (-not (Test-Path $PythonBin)) {
throw "Python 环境不存在: $PythonBin"
}
$args = @(
$GatewayRun,
'--host', $GatewayHost,
'--port', $GatewayPort,
'--backend-base', "http://$BackendHost`:$BackendPort",
'--model-server', "http://$BackendHost`:$BackendPort/v1"
)
if (Test-Path $ErrLogFile) {
Remove-Item -Path $ErrLogFile -Force -ErrorAction SilentlyContinue
}
$oldWaitHint = $env:BACKEND_WAIT_HINT
try {
$env:BACKEND_WAIT_HINT = $BackendWaitHint
$proc = Start-Process -FilePath $PythonBin -ArgumentList $args -WindowStyle Hidden -RedirectStandardOutput $LogFile -RedirectStandardError $ErrLogFile -PassThru
} finally {
$env:BACKEND_WAIT_HINT = $oldWaitHint
}
Set-Content -Path $PidFile -Value $proc.Id -Encoding ascii
$timeoutSec = 60
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
$nextProbeMs = 0
$tick = 0
while ($stopwatch.Elapsed.TotalSeconds -lt $timeoutSec) {
Write-SpinnerLine -Label '网关启动中...' -Current $stopwatch.Elapsed.TotalSeconds -Total $timeoutSec -Tick $tick
if ($stopwatch.ElapsedMilliseconds -ge $nextProbeMs) {
if (-not (Test-GatewayRunning)) {
break
}
if (Test-GatewayReady) {
Complete-SpinnerLine
return
}
$nextProbeMs += $SpinnerProbeIntervalMs
}
Start-Sleep -Milliseconds $SpinnerFrameIntervalMs
$tick++
}
Complete-SpinnerLine
Show-GatewayFailureLogs
throw '网关启动失败。'
}
function Stop-Gateway {
Stop-OrphanGatewayProcesses
if (-not (Test-GatewayRunning)) {
if (Test-Path $PidFile) {
Remove-Item -Path $PidFile -Force -ErrorAction SilentlyContinue
}
Write-Host '网关状态: 未运行'
return
}
$gatewayPid = [int](Get-Content -Path $PidFile | Select-Object -First 1)
Stop-Process -Id $gatewayPid -Force -ErrorAction SilentlyContinue
Start-Sleep -Seconds 1
if (Test-Path $PidFile) {
Remove-Item -Path $PidFile -Force -ErrorAction SilentlyContinue
}
Write-Host '网关状态: 已停止'
}
function Show-Status {
Write-Host '=== 网关 ==='
if (Test-GatewayRunning) {
$state = if (Test-GatewayReady) { '可访问' } else { '初始化中' }
Write-Host '状态: 运行中'
Write-Host "PID: $(Get-Content -Path $PidFile)"
Write-Host "地址: http://$GatewayHost`:$GatewayPort"
Write-Host "健康: $state"
Write-Host "日志: $LogFile"
Write-Host "错误日志: $ErrLogFile"
} else {
Write-Host '状态: 未运行'
}
Write-Host ''
Write-Host '=== 模型后端 ==='
$oldHost = $env:HOST
$oldPort = $env:PORT
try {
$env:HOST = $BackendHost
$env:PORT = $BackendPort
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $ModelSwitch 'status'
} finally {
$env:HOST = $oldHost
$env:PORT = $oldPort
}
}
function Show-Logs {
Write-Host '=== 网关日志 ==='
if (Test-Path $LogFile) {
Get-Content -Path $LogFile -Tail 120
}
if (Test-Path $ErrLogFile) {
Write-Host '=== 网关错误日志 ==='
Get-Content -Path $ErrLogFile -Tail 120
return
}
Write-Host '暂无日志'
}
function Stop-Backend {
$oldHost = $env:HOST
$oldPort = $env:PORT
try {
$env:HOST = $BackendHost
$env:PORT = $BackendPort
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $ModelSwitch 'stop'
} finally {
$env:HOST = $oldHost
$env:PORT = $oldPort
}
}
function Start-Stack {
try {
Write-Host '步骤 1/2: 启动模型后端'
Start-Backend
Write-Host '步骤 2/2: 启动网关服务'
Start-Gateway
Write-Host '栈已启动'
Write-Host "网页入口: http://$GatewayHost`:$GatewayPort"
Write-Host '可用状态检查命令: .\start_8080_toolhub_stack.cmd status'
Write-Host '停止命令: .\start_8080_toolhub_stack.cmd stop'
} catch {
Write-Host $_.Exception.Message
exit 1
}
}
function Stop-Stack {
Stop-Gateway
Stop-Backend
}
switch ($Command) {
'start' { Start-Stack; break }
'stop' { Stop-Stack; break }
'restart' { Stop-Stack; Start-Stack; break }
'status' { Show-Status; break }
'logs' { Show-Logs; break }
default {
Write-Host '用法:'
Write-Host ' .\\start_8080_toolhub_stack.cmd {start|stop|restart|status|logs}'
Write-Host ''
Write-Host '可选环境变量:'
Write-Host ' GATEWAY_HOST=127.0.0.1'
Write-Host ' GATEWAY_PORT=8080'
Write-Host ' BACKEND_HOST=127.0.0.1'
Write-Host ' BACKEND_PORT=8081'
Write-Host ' THINK_MODE=think-on'
exit 1
}
}