feat(merge): 以官方 main 为基底融合 PR#530 多维表格与本地定制
- 多维表格(canvas-batch-table-node/use-canvas-batch-table/canvas-batch-table 等)以 PR#530 实现为主 - 保留官方 main 全部新功能:banner/画布版本历史/提示词编辑/方舟 Agent Plan/支付导出 - 移植本地定制:ddcat 多参考图校验、万有引力 lxmone 连接错误提示、Description v20(v24)、自建插件(a6api/metaso-h3/antigravity-proxy/lxmone)、seccomp、Windows 脚本 - 迁移版本升至 v24(官方 v20-23 banner/版本历史 + 我们的 Description 列) - 修复官方缺失的 markdownPlainText import
This commit is contained in:
105
scripts/launch-canvas.ps1
Normal file
105
scripts/launch-canvas.ps1
Normal file
@@ -0,0 +1,105 @@
|
||||
# 影策画布一键启动器
|
||||
# 启动后端(8080) + 前端(3000) + cloudflared 隧道(公网 canvas.yingce.cc.cd),打开浏览器
|
||||
|
||||
[CmdletBinding()]
|
||||
param()
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$repoRoot = "D:\yingce\open-ai-canvas-main"
|
||||
$backendDir = Join-Path $repoRoot "backend"
|
||||
$webDir = Join-Path $repoRoot "web"
|
||||
$dataDir = Join-Path $repoRoot ".local\project-workbench-debug"
|
||||
$goBuildCache = Join-Path $repoRoot ".local\cache\go-build"
|
||||
$goModuleCache = Join-Path $repoRoot ".local\cache\go-mod"
|
||||
$cloudflaredExe = "C:\Program Files (x86)\cloudflared\cloudflared.exe"
|
||||
$bunExe = "C:\Users\Administrator\AppData\Roaming\npm\node_modules\bun\bin\bun.exe"
|
||||
if (-not (Test-Path -LiteralPath $bunExe)) { $bunExe = "bun" }
|
||||
$localUrl = "http://localhost:3000"
|
||||
$healthUrl = "http://127.0.0.1:3000/api/health"
|
||||
|
||||
function Test-PortListen([int]$Port) {
|
||||
try {
|
||||
return $null -ne (Get-NetTCPConnection -LocalPort $Port -State Listen -ErrorAction Stop | Select-Object -First 1)
|
||||
} catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Test-Http([string]$Url) {
|
||||
try {
|
||||
$r = Invoke-WebRequest -Uri $Url -UseBasicParsing -TimeoutSec 3
|
||||
return $r.StatusCode -ge 200 -and $r.StatusCode -lt 400
|
||||
} catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
# 0) 已全部就绪则直接打开
|
||||
if ((Test-PortListen 8080) -and (Test-PortListen 3000)) {
|
||||
Write-Host "影策画布已在运行,正在打开..." -ForegroundColor Green
|
||||
Start-Process $localUrl
|
||||
exit 0
|
||||
}
|
||||
|
||||
# 1) 后端:8080
|
||||
if (-not (Test-PortListen 8080)) {
|
||||
Write-Host "启动后端 (8080)..." -ForegroundColor Cyan
|
||||
New-Item -ItemType Directory -Force -Path $dataDir, $goBuildCache, $goModuleCache | Out-Null
|
||||
$env:CANVAS_BACKEND_ADDR = "127.0.0.1:8080"
|
||||
$env:CANVAS_BACKEND_DATA_DIR = $dataDir
|
||||
$env:CANVAS_PUBLIC_BASE_URL = "https://canvas.yingce.cc.cd"
|
||||
$env:GOPROXY = "https://goproxy.cn,direct"
|
||||
$env:GOCACHE = $goBuildCache
|
||||
$env:GOMODCACHE = $goModuleCache
|
||||
Start-Process -FilePath "go" -ArgumentList "run", "./cmd/server" `
|
||||
-WorkingDirectory $backendDir `
|
||||
-RedirectStandardOutput (Join-Path $repoRoot ".local\backend.stdout.log") `
|
||||
-RedirectStandardError (Join-Path $repoRoot ".local\backend.stderr.log") `
|
||||
-WindowStyle Hidden | Out-Null
|
||||
}
|
||||
|
||||
# 2) 前端:3000
|
||||
if (-not (Test-PortListen 3000)) {
|
||||
Write-Host "启动前端 (3000)..." -ForegroundColor Cyan
|
||||
$viteBinary = Join-Path $webDir "node_modules\.bin\vite"
|
||||
if (-not (Test-Path -LiteralPath $viteBinary)) {
|
||||
Write-Host "安装前端依赖..." -ForegroundColor Yellow
|
||||
Push-Location $webDir
|
||||
try { & bun install --frozen-lockfile } finally { Pop-Location }
|
||||
}
|
||||
$env:VITE_API_PROXY_TARGET = "http://127.0.0.1:8080"
|
||||
Start-Process -FilePath $bunExe -ArgumentList "run", "dev" `
|
||||
-WorkingDirectory $webDir `
|
||||
-RedirectStandardOutput (Join-Path $repoRoot ".local\web.stdout.log") `
|
||||
-RedirectStandardError (Join-Path $repoRoot ".local\web.stderr.log") `
|
||||
-WindowStyle Hidden | Out-Null
|
||||
}
|
||||
|
||||
# 3) cloudflared 隧道(公网 canvas.yingce.cc.cd)
|
||||
if (-not (Get-Process -Name cloudflared -ErrorAction SilentlyContinue)) {
|
||||
if (Test-Path -LiteralPath $cloudflaredExe) {
|
||||
Write-Host "启动公网隧道 cloudflared..." -ForegroundColor Cyan
|
||||
Start-Process -FilePath $cloudflaredExe -ArgumentList "--config", "C:\Users\Administrator\.cloudflared\config.yml", "tunnel", "run" -WindowStyle Hidden | Out-Null
|
||||
} else {
|
||||
Write-Host "未找到 cloudflared,跳过公网隧道(本地仍可访问)" -ForegroundColor Yellow
|
||||
}
|
||||
} else {
|
||||
Write-Host "公网隧道 cloudflared 已在运行" -ForegroundColor DarkGray
|
||||
}
|
||||
|
||||
# 4) 等待健康检查并打开浏览器
|
||||
$deadline = (Get-Date).AddMinutes(3)
|
||||
do {
|
||||
Start-Sleep -Seconds 2
|
||||
if (Test-Http $healthUrl) {
|
||||
Write-Host "影策画布已启动,正在打开浏览器..." -ForegroundColor Green
|
||||
Start-Sleep -Seconds 1
|
||||
Start-Process $localUrl
|
||||
Write-Host "本地: http://localhost:3000" -ForegroundColor Green
|
||||
Write-Host "公网: https://canvas.yingce.cc.cd" -ForegroundColor Green
|
||||
exit 0
|
||||
}
|
||||
} while ((Get-Date) -lt $deadline)
|
||||
|
||||
Write-Host "启动超时,请查看日志:.local\backend.stderr.log / .local\web.stderr.log" -ForegroundColor Red
|
||||
56
scripts/start-canvas.ps1
Normal file
56
scripts/start-canvas.ps1
Normal file
@@ -0,0 +1,56 @@
|
||||
[CmdletBinding()]
|
||||
param()
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
|
||||
$localStarter = Join-Path $PSScriptRoot "start-local.ps1"
|
||||
$healthUrl = "http://127.0.0.1:3000/api/health"
|
||||
$canvasUrl = "http://localhost:3000/canvas"
|
||||
|
||||
function Test-CanvasHttp([string]$Url) {
|
||||
try {
|
||||
$response = Invoke-WebRequest -Uri $Url -UseBasicParsing -TimeoutSec 3
|
||||
return $response.StatusCode -ge 200 -and $response.StatusCode -lt 400
|
||||
} catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Test-ListeningPort([int]$Port) {
|
||||
try {
|
||||
return $null -ne (Get-NetTCPConnection -LocalPort $Port -State Listen -ErrorAction Stop | Select-Object -First 1)
|
||||
} catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
if (Test-CanvasHttp $healthUrl) {
|
||||
Write-Host "影策画布已经在运行,正在打开..." -ForegroundColor Green
|
||||
Start-Process $canvasUrl
|
||||
exit 0
|
||||
}
|
||||
|
||||
$occupiedPorts = @(3000, 8080) | Where-Object { Test-ListeningPort $_ }
|
||||
if ($occupiedPorts.Count -gt 0) {
|
||||
throw "端口 $($occupiedPorts -join ', ') 已被其他程序占用,无法安全启动影策。"
|
||||
}
|
||||
|
||||
if (-not (Test-Path -LiteralPath $localStarter)) {
|
||||
throw "未找到项目启动脚本:$localStarter"
|
||||
}
|
||||
|
||||
Write-Host "正在启动影策前端和后端,请稍候..." -ForegroundColor Cyan
|
||||
& $localStarter
|
||||
|
||||
$deadline = (Get-Date).AddMinutes(3)
|
||||
do {
|
||||
Start-Sleep -Seconds 2
|
||||
if (Test-CanvasHttp $healthUrl) {
|
||||
Write-Host "影策画布已启动,正在打开浏览器..." -ForegroundColor Green
|
||||
Start-Process $canvasUrl
|
||||
exit 0
|
||||
}
|
||||
} while ((Get-Date) -lt $deadline)
|
||||
|
||||
throw "影策服务已拉起,但 3 分钟内未通过健康检查。请查看打开的前端、后端窗口。"
|
||||
@@ -3,6 +3,9 @@ param()
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
. (Join-Path $PSScriptRoot "windows-proxy.ps1")
|
||||
Import-CanvasWindowsProxy
|
||||
|
||||
$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
|
||||
$backendDir = Join-Path $repoRoot "backend"
|
||||
$webDir = Join-Path $repoRoot "web"
|
||||
|
||||
35
scripts/windows-proxy.ps1
Normal file
35
scripts/windows-proxy.ps1
Normal file
@@ -0,0 +1,35 @@
|
||||
# Go uses proxy environment variables, not Windows Internet Settings.
|
||||
# Inherit the user's enabled static proxy only when no explicit proxy was set.
|
||||
function Import-CanvasWindowsProxy {
|
||||
if ($env:HTTPS_PROXY -or $env:HTTP_PROXY -or $env:ALL_PROXY) { return }
|
||||
$settings = Get-ItemProperty -LiteralPath 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -ErrorAction SilentlyContinue
|
||||
if (-not $settings -or $settings.ProxyEnable -ne 1 -or -not $settings.ProxyServer) { return }
|
||||
$proxies = @{}
|
||||
foreach ($entry in ($settings.ProxyServer -split ';')) {
|
||||
if ($entry -match '^\s*(https?)=(.+)$') {
|
||||
$proxies[$Matches[1]] = $Matches[2].Trim()
|
||||
} elseif ($entry -notmatch '=') {
|
||||
$proxies['http'] = $entry.Trim()
|
||||
$proxies['https'] = $entry.Trim()
|
||||
}
|
||||
}
|
||||
foreach ($scheme in @('http', 'https')) {
|
||||
$address = $proxies[$scheme]
|
||||
if (-not $address) { continue }
|
||||
if ($address -notmatch '^[a-z]+://') { $address = "http://$address" }
|
||||
$parsed = $null
|
||||
if (-not [Uri]::TryCreate($address, [UriKind]::Absolute, [ref]$parsed) -or $parsed.Scheme -notin @('http', 'https')) {
|
||||
throw 'Windows proxy address is invalid. Check system proxy settings.'
|
||||
}
|
||||
[Environment]::SetEnvironmentVariable("$($scheme.ToUpper())_PROXY", $address, 'Process')
|
||||
}
|
||||
if ($env:HTTP_PROXY -or $env:HTTPS_PROXY) {
|
||||
$bypass = @($env:NO_PROXY, 'localhost', '127.0.0.1', '::1')
|
||||
foreach ($entry in ($settings.ProxyOverride -split ';')) {
|
||||
$entry = $entry.Trim()
|
||||
if ($entry -and $entry -ne '<local>') { $bypass += $entry }
|
||||
}
|
||||
$env:NO_PROXY = ($bypass | Where-Object { $_ } | Select-Object -Unique) -join ','
|
||||
Write-Host 'Backend network: using the enabled Windows proxy.' -ForegroundColor Cyan
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user