Files
app-cli/vision/vision.ps1
toom1996 e366ee7498 chore: 初始化 app-cli,本地开发环境脚本
- dev/dev.ps1: 一键启动后端(编译后运行)+前端(4321),校验 CORS 与 astro dev 单实例锁
- dev/stop.ps1: 按 PID 登记停止,-Force 清残留
- dev/status.ps1: 端口/PID/健康检查一览
- dev/doctor.ps1: 工具链/路径/依赖/数据库/端口/CORS 体检
- vision/vision.ps1: CLIP 向量服务起停
- lib/common.ps1: 路径探测、端口、进程登记、HTTP 探测
- config/local.env.example: 路径与端口覆盖模板
2026-10-22 10:37:59 +08:00

122 lines
4.1 KiB
PowerShell
Raw Permalink 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.

<#
.SYNOPSIS
CLIP 向量服务(fashion-siglip)的独立起停脚本。
.DESCRIPTION
该服务把图片编码成归一化向量,供后台「疑似同款」提示使用。
- 只监听 127.0.0.1,不对外暴露
- --workers 必须为 1(模型常驻进程内,多 worker 会重复加载模型)
- 后端需要 VISION_ENABLED=true 才会调用它;服务不可用时后端自动降级,不影响入库
.EXAMPLE
.\vision\vision.ps1 start
.\vision\vision.ps1 status
.\vision\vision.ps1 logs
.\vision\vision.ps1 stop
#>
param(
[Parameter(Position = 0)]
[ValidateSet('start', 'stop', 'restart', 'status', 'logs')]
[string]$Action = 'start',
[switch]$Force
)
$ErrorActionPreference = 'Stop'
$CliRoot = Split-Path -Parent $PSScriptRoot
. (Join-Path $CliRoot 'lib\common.ps1')
$envMap = Import-LocalEnv (Join-Path $CliRoot 'config\local.env')
$svc = Resolve-Services -EnvMap $envMap -Root $CliRoot
$port = [int](Get-Setting $envMap 'VISION_PORT' '8900')
$healthUrl = "http://127.0.0.1:$port/health"
function Start-CLIP {
if (Test-PortInUse $port) {
$owner = Get-PortOwnerPid $port
$saved = Get-ServicePid 'vision'
if ($saved -gt 0 -and $saved -eq $owner) {
Write-Note "视觉服务已在运行(PID $owner)"
return $true
}
if (-not $Force) {
Write-Fail "端口 $port 被 PID $owner 占用"
Write-Note '加 -Force 强制释放:.\vision\vision.ps1 start -Force'
return $false
}
Stop-PidTree $owner | Out-Null
}
if (-not $svc.Vision.IsValid) {
Write-Fail "视觉服务目录无效:$($svc.Vision.Path)"
return $false
}
$uvicorn = Join-Path $svc.Vision.Path '.venv\Scripts\uvicorn.exe'
if (-not (Test-Path $uvicorn)) {
Write-Fail "找不到 $uvicorn"
Write-Note "在 $($svc.Vision.Path) 建虚拟环境:python -m venv .venv && .venv\Scripts\pip install -r requirements.txt"
return $false
}
Write-Step "启动视觉服务(端口 $port,首次加载模型较慢)"
Start-LoggedProcess -Name 'vision' -FilePath $uvicorn `
-ArgumentList @('app:app', '--host', '127.0.0.1', '--port', "$port", '--workers', '1') `
-WorkingDirectory $svc.Vision.Path | Out-Null
if (Wait-HttpOk -Url $healthUrl -TimeoutSec 180) {
Write-Ok '视觉服务就绪'
Show-Health
return $true
}
Write-Fail '视觉服务 180 秒内未就绪'
Show-LogTail -Name 'vision' -Lines 25
return $false
}
function Show-Health {
try {
$r = Invoke-WebRequest -Uri $healthUrl -UseBasicParsing -TimeoutSec 5 -ErrorAction Stop
Write-Note ("health: " + $r.Content.Trim())
} catch { }
}
Write-Host ''
Write-Host ' app-cli / CLIP 视觉服务' -ForegroundColor White
Write-Host ' ----------------------------------------' -ForegroundColor DarkGray
switch ($Action) {
'start' {
if (-not (Start-CLIP)) { exit 1 }
}
'stop' {
if (Stop-NamedService 'vision') { Write-Ok '视觉服务已停止' }
else { Write-Note '视觉服务未在本脚本登记(可能没启动过)' }
if (Test-PortInUse $port) {
$owner = Get-PortOwnerPid $port
Write-Warn "端口 $port 仍被 PID $owner 占用"
if ($Force) { Stop-PidTree $owner | Out-Null; Write-Ok "已终止 PID $owner" }
else { Write-Note '加 -Force 强制终止:.\vision\vision.ps1 stop -Force' }
}
}
'restart' {
Stop-NamedService 'vision' | Out-Null
Start-Sleep -Milliseconds 500
if (-not (Start-CLIP)) { exit 1 }
}
'status' {
$st = Get-ServiceStatus -Name 'vision' -Port $port -HealthUrl $healthUrl
if ($st.Healthy) {
Write-Ok "运行中(PID $($st.OwnerPid),端口 $port)"
Show-Health
} elseif ($st.Listening) {
Write-Warn "端口 $port 已监听但 /health 未通过(模型可能仍在加载)"
Show-LogTail -Name 'vision' -Lines 10
} else {
Write-Note '未运行'
}
}
'logs' {
Show-LogTail -Name 'vision' -Lines 40
}
}