|
@@ -1,106 +1,152 @@
|
|
|
-# 观澜·如东样板 v2 — Windows 离线安装
|
|
|
|
|
-# 用法: powershell -ExecutionPolicy Bypass -File install.ps1
|
|
|
|
|
-# ... -File install.ps1 -Python "C:\Python312\python.exe" # 多版本机器指定
|
|
|
|
|
-# ... -File install.ps1 -UseBundledPython # 强制用包内便携运行时
|
|
|
|
|
-#
|
|
|
|
|
-# 编码约定 (2026-09-10, 同事 xzy 实机报 ParserError 后定): 本文件必须存成 **UTF-8 带 BOM + CRLF**。
|
|
|
|
|
-# Windows PowerShell 5.1 对没有 BOM 的 .ps1 按 ANSI 代码页 (中文机 = GBK) 解码, 文件里的中文会被
|
|
|
|
|
-# 错读, 相邻的转义反引号可能被一起吞掉 → 引号不配对 → 级联 ParserError (报在看起来没问题的行上)。
|
|
|
|
|
-# install.bat 里的 chcp 65001 管不了这件事 (它改的是控制台代码页, 不是脚本文件的解码方式)。
|
|
|
|
|
-# 另: 本文件**不再使用** 形如 & cmd /c "\"$exe\" -m pip ..." 的嵌套引号写法 —— 一旦有字节被吃掉就崩; 改用
|
|
|
|
|
-# PowerShell 原生调用 & $exe arg1 arg2, 不需要任何引号转义。
|
|
|
|
|
-param([string]$Python = "", [switch]$UseBundledPython, [switch]$SkipOllama)
|
|
|
|
|
-$ErrorActionPreference = "Stop"; $env:PYTHONUTF8 = "1"
|
|
|
|
|
-# 机器上若全局设了 PYTHONPATH (例如指向 D:\Program Files\Python\Lib\site-packages), pip 会把那里的包
|
|
|
|
|
-# 当成 "已满足", 于是不装进 .venv —— venv 里就缺 urllib3 / polars / pyyaml / jinja2 等传递依赖,
|
|
|
|
|
-# 换个没设 PYTHONPATH 的 shell 立刻 import 失败; 且 PYTHONPATH 排在 venv 之前会顶掉 pin 住的版本。
|
|
|
|
|
-# 先把环境变量摘掉, 让下面 pip 老老实实按 requirements.txt 装进 .venv。
|
|
|
|
|
-Remove-Item Env:PYTHONPATH -ErrorAction SilentlyContinue
|
|
|
|
|
-Set-Location $PSScriptRoot
|
|
|
|
|
-function Say($m){ Write-Host $m }
|
|
|
|
|
-
|
|
|
|
|
-Say "== 1/5 选 Python (需 3.11+; 本项目依赖 pandas 3, 3.10 及以下没有轮子)"
|
|
|
|
|
-$py = $null
|
|
|
|
|
-if ($Python) { $py = $Python }
|
|
|
|
|
-elseif (-not $UseBundledPython) {
|
|
|
|
|
- # 列出机器上所有 Python, 选第一个 >=3.11 (多版本共存时不猜, 打印出来让人看见)
|
|
|
|
|
- $cands = @()
|
|
|
|
|
- foreach ($c in @("py -3.13","py -3.12","py -3.11","python","python3")) {
|
|
|
|
|
- $exe, $arg = $c.Split(" ", 2)
|
|
|
|
|
- try {
|
|
|
|
|
- $v = if ($arg) { & $exe $arg -c "import sys;print('%d.%d'%sys.version_info[:2])" 2>$null }
|
|
|
|
|
- else { & $exe -c "import sys;print('%d.%d'%sys.version_info[:2])" 2>$null }
|
|
|
|
|
- if ($LASTEXITCODE -eq 0 -and $v) { $cands += [pscustomobject]@{cmd=$c; exe=$exe; arg=$arg; ver=$v} }
|
|
|
|
|
- } catch {}
|
|
|
|
|
- }
|
|
|
|
|
- if ($cands) { Say (" 机器上的 Python: " + (($cands | ForEach-Object { "$($_.cmd)=$($_.ver)" }) -join ", ")) }
|
|
|
|
|
- $ok = $cands | Where-Object { [version]$_.ver -ge [version]"3.11" } | Select-Object -First 1
|
|
|
|
|
- if ($ok) { $py = $ok }
|
|
|
|
|
-}
|
|
|
|
|
-if (-not $py) {
|
|
|
|
|
- $rt = Get-ChildItem "vendor\python\cpython-3.12*windows*.tar.gz" -ErrorAction SilentlyContinue | Select-Object -First 1
|
|
|
|
|
- if ($rt) {
|
|
|
|
|
- Say " 系统无 3.11+, 解包内便携运行时: $($rt.Name)"
|
|
|
|
|
- if (Test-Path runtime) { Remove-Item runtime -Recurse -Force }
|
|
|
|
|
- New-Item -ItemType Directory runtime | Out-Null
|
|
|
|
|
- tar -xzf $rt.FullName -C runtime # Windows 10 1803+ 自带 tar
|
|
|
|
|
- $py = [pscustomobject]@{ exe = (Resolve-Path "runtime\python\python.exe").Path; arg = "" }
|
|
|
|
|
- } else {
|
|
|
|
|
- Say " X 没有 3.11+ 的 Python, 包内也没有便携运行时。"
|
|
|
|
|
- Say " 办法一: 装 https://www.python.org/downloads/windows/ 的 3.12.x (勾 Add to PATH)"
|
|
|
|
|
- Say " 办法二: -Python <python.exe 的完整路径> 指定"
|
|
|
|
|
- exit 2
|
|
|
|
|
- }
|
|
|
|
|
-} elseif ($py -is [string]) {
|
|
|
|
|
- $py = [pscustomobject]@{ exe = $py; arg = "" }
|
|
|
|
|
-}
|
|
|
|
|
-Say " 使用: $($py.exe) $($py.arg)"
|
|
|
|
|
-
|
|
|
|
|
-Say "== 2/5 建虚拟环境 .venv"
|
|
|
|
|
-if ($py.arg) { & $py.exe $py.arg -m venv .venv } else { & $py.exe -m venv .venv }
|
|
|
|
|
-$vpy = (Resolve-Path ".\.venv\Scripts\python.exe").Path
|
|
|
|
|
-& $vpy -m pip install --upgrade pip --quiet
|
|
|
|
|
-
|
|
|
|
|
-Say "== 3/5 装依赖 (优先包内离线轮子 wheels\win_amd64)"
|
|
|
|
|
-if (Test-Path ".\wheels\win_amd64") { & $vpy -m pip install --no-index --find-links .\wheels\win_amd64 -r requirements.txt }
|
|
|
|
|
-else { Say " 包内无轮子, 改为联网安装"; & $vpy -m pip install -r requirements.txt }
|
|
|
|
|
-if ($LASTEXITCODE -ne 0) { Say " X 依赖安装失败 (上面有 pip 的报错) —— 先解决它, 别接着跑 start.bat"; exit 3 }
|
|
|
|
|
-
|
|
|
|
|
-Say "== 4/5 写配置"
|
|
|
|
|
-# 别改回 Get-Content / Set-Content -Encoding UTF8 (2026-09-10 实机踩过):
|
|
|
|
|
-# PS 5.1 的 Get-Content 把无 BOM 的 UTF-8 当 ANSI(GBK) 解码 -> 中文注释变乱码;
|
|
|
|
|
-# Set-Content -Encoding UTF8 又写出 BOM -> Python 侧用裸 utf-8 json.loads 直接 JSONDecodeError。
|
|
|
|
|
-# 交给 venv 里的 Python 读写: 读 utf-8-sig (有 BOM 也认), 写无 BOM 的 UTF-8。
|
|
|
|
|
-# 下面 Python 代码故意只用单引号, 避开 PS 5.1 传参时的引号转义坑。
|
|
|
|
|
-$cfgFix = @'
|
|
|
|
|
-import json, pathlib, sys
|
|
|
|
|
-p = pathlib.Path('configs/serve.json') # portability-allow: 安装脚本已 Set-Location 到安装根
|
|
|
|
|
-c = json.loads(p.read_text(encoding='utf-8-sig'))
|
|
|
|
|
-# 写**相对**路径 (相对安装根): 整个目录拷到别的电脑/别的盘后仍然有效 (绝对路径会在换机后失效)
|
|
|
|
|
-exe = pathlib.Path(sys.executable).resolve()
|
|
|
|
|
-root = pathlib.Path('.').resolve()
|
|
|
|
|
-try:
|
|
|
|
|
- c['python'] = exe.relative_to(root).as_posix()
|
|
|
|
|
-except ValueError:
|
|
|
|
|
- c['python'] = exe.as_posix()
|
|
|
|
|
-p.write_text(json.dumps(c, ensure_ascii=False, indent=2) + '\n', encoding='utf-8')
|
|
|
|
|
-print(' configs/serve.json -> ' + c['python'] + ' (相对安装根)')
|
|
|
|
|
-'@
|
|
|
|
|
-& $vpy -c $cfgFix
|
|
|
|
|
-if ($LASTEXITCODE -ne 0) { Say " X 写 configs\serve.json 失败"; exit 4 }
|
|
|
|
|
-
|
|
|
|
|
-Say "== 5/5 Ollama (只影响问答与本地审核; 其余页面不受影响)"
|
|
|
|
|
-if (-not $SkipOllama) {
|
|
|
|
|
- $has = Get-Command ollama -ErrorAction SilentlyContinue
|
|
|
|
|
- if ($has) { Say " 已安装: $(& ollama -v 2>&1 | Select-Object -First 1)" }
|
|
|
|
|
- elseif (Test-Path "vendor\ollama\OllamaSetup.exe") {
|
|
|
|
|
- Say " 包内有离线安装包, 现在静默安装 (约 1.5 GB, 需几分钟)…"
|
|
|
|
|
- Start-Process -FilePath "vendor\ollama\OllamaSetup.exe" -ArgumentList "/SILENT" -Wait
|
|
|
|
|
- Say " 安装完成; 模型请把有网机器的 %USERPROFILE%\.ollama\models 整个目录拷到本机同位置"
|
|
|
|
|
- } else { Say " 未装且包内无离线包: 问答不可用。装法见 说明书 §5" }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-Say ""
|
|
|
|
|
-& $vpy guanlan.py check
|
|
|
|
|
-Say ""
|
|
|
|
|
-Say "安装完成. 启动: start.bat 停止: stop.bat 自检: check.bat 入口: http://127.0.0.1:28084/"
|
|
|
|
|
|
|
+# 观澜·如东样板 v2 — Windows 离线安装
|
|
|
|
|
+# 用法: powershell -ExecutionPolicy Bypass -File install.ps1
|
|
|
|
|
+# ... -File install.ps1 -Python "C:\Python312\python.exe" # 多版本机器指定
|
|
|
|
|
+# ... -File install.ps1 -UseBundledPython # 强制用包内便携运行时
|
|
|
|
|
+#
|
|
|
|
|
+# 编码约定 (2026-09-10, 同事 xzy 实机报 ParserError 后定): 本文件必须存成 **UTF-8 带 BOM + CRLF**。
|
|
|
|
|
+# Windows PowerShell 5.1 对没有 BOM 的 .ps1 按 ANSI 代码页 (中文机 = GBK) 解码, 文件里的中文会被
|
|
|
|
|
+# 错读, 相邻的转义反引号可能被一起吞掉 → 引号不配对 → 级联 ParserError (报在看起来没问题的行上)。
|
|
|
|
|
+# install.bat 里的 chcp 65001 管不了这件事 (它改的是控制台代码页, 不是脚本文件的解码方式)。
|
|
|
|
|
+# 另: 本文件**不再使用** 形如 & cmd /c "\"$exe\" -m pip ..." 的嵌套引号写法 —— 一旦有字节被吃掉就崩; 改用
|
|
|
|
|
+# PowerShell 原生调用 & $exe arg1 arg2, 不需要任何引号转义。
|
|
|
|
|
+param([string]$Python = "", [switch]$UseBundledPython, [switch]$SkipOllama, [switch]$NoDesktopShortcut)
|
|
|
|
|
+$ErrorActionPreference = "Stop"; $env:PYTHONUTF8 = "1"
|
|
|
|
|
+# 机器上若全局设了 PYTHONPATH (例如指向 D:\Program Files\Python\Lib\site-packages), pip 会把那里的包
|
|
|
|
|
+# 当成 "已满足", 于是不装进 .venv —— venv 里就缺 urllib3 / polars / pyyaml / jinja2 等传递依赖,
|
|
|
|
|
+# 换个没设 PYTHONPATH 的 shell 立刻 import 失败; 且 PYTHONPATH 排在 venv 之前会顶掉 pin 住的版本。
|
|
|
|
|
+# 先把环境变量摘掉, 让下面 pip 老老实实按 requirements.txt 装进 .venv。
|
|
|
|
|
+Remove-Item Env:PYTHONPATH -ErrorAction SilentlyContinue
|
|
|
|
|
+Set-Location $PSScriptRoot
|
|
|
|
|
+function Say($m){ Write-Host $m }
|
|
|
|
|
+
|
|
|
|
|
+Say "== 1/6 选 Python (需 3.11+; 本项目依赖 pandas 3, 3.10 及以下没有轮子)"
|
|
|
|
|
+$py = $null
|
|
|
|
|
+if ($Python) { $py = $Python }
|
|
|
|
|
+elseif (-not $UseBundledPython) {
|
|
|
|
|
+ # 列出机器上所有 Python, 选第一个 >=3.11 (多版本共存时不猜, 打印出来让人看见)
|
|
|
|
|
+ $cands = @()
|
|
|
|
|
+ foreach ($c in @("py -3.13","py -3.12","py -3.11","python","python3")) {
|
|
|
|
|
+ $exe, $arg = $c.Split(" ", 2)
|
|
|
|
|
+ try {
|
|
|
|
|
+ $v = if ($arg) { & $exe $arg -c "import sys;print('%d.%d'%sys.version_info[:2])" 2>$null }
|
|
|
|
|
+ else { & $exe -c "import sys;print('%d.%d'%sys.version_info[:2])" 2>$null }
|
|
|
|
|
+ if ($LASTEXITCODE -eq 0 -and $v) { $cands += [pscustomobject]@{cmd=$c; exe=$exe; arg=$arg; ver=$v} }
|
|
|
|
|
+ } catch {}
|
|
|
|
|
+ }
|
|
|
|
|
+ if ($cands) { Say (" 机器上的 Python: " + (($cands | ForEach-Object { "$($_.cmd)=$($_.ver)" }) -join ", ")) }
|
|
|
|
|
+ $ok = $cands | Where-Object { [version]$_.ver -ge [version]"3.11" } | Select-Object -First 1
|
|
|
|
|
+ if ($ok) { $py = $ok }
|
|
|
|
|
+}
|
|
|
|
|
+if (-not $py) {
|
|
|
|
|
+ $rt = Get-ChildItem "vendor\python\cpython-3.12*windows*.tar.gz" -ErrorAction SilentlyContinue | Select-Object -First 1
|
|
|
|
|
+ if ($rt) {
|
|
|
|
|
+ Say " 系统无 3.11+, 解包内便携运行时: $($rt.Name)"
|
|
|
|
|
+ if (Test-Path runtime) { Remove-Item runtime -Recurse -Force }
|
|
|
|
|
+ New-Item -ItemType Directory runtime | Out-Null
|
|
|
|
|
+ tar -xzf $rt.FullName -C runtime # Windows 10 1803+ 自带 tar
|
|
|
|
|
+ $py = [pscustomobject]@{ exe = (Resolve-Path "runtime\python\python.exe").Path; arg = "" }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ Say " X 没有 3.11+ 的 Python, 包内也没有便携运行时。"
|
|
|
|
|
+ Say " 办法一: 装 https://www.python.org/downloads/windows/ 的 3.12.x (勾 Add to PATH)"
|
|
|
|
|
+ Say " 办法二: -Python <python.exe 的完整路径> 指定"
|
|
|
|
|
+ exit 2
|
|
|
|
|
+ }
|
|
|
|
|
+} elseif ($py -is [string]) {
|
|
|
|
|
+ $py = [pscustomobject]@{ exe = $py; arg = "" }
|
|
|
|
|
+}
|
|
|
|
|
+Say " 使用: $($py.exe) $($py.arg)"
|
|
|
|
|
+
|
|
|
|
|
+Say "== 2/6 建虚拟环境 .venv"
|
|
|
|
|
+if ($py.arg) { & $py.exe $py.arg -m venv .venv } else { & $py.exe -m venv .venv }
|
|
|
|
|
+$vpy = (Resolve-Path ".\.venv\Scripts\python.exe").Path
|
|
|
|
|
+& $vpy -m pip install --upgrade pip --quiet
|
|
|
|
|
+
|
|
|
|
|
+Say "== 3/6 装依赖 (优先包内离线轮子 wheels\win_amd64)"
|
|
|
|
|
+if (Test-Path ".\wheels\win_amd64") { & $vpy -m pip install --no-index --find-links .\wheels\win_amd64 -r requirements.txt }
|
|
|
|
|
+else { Say " 包内无轮子, 改为联网安装"; & $vpy -m pip install -r requirements.txt }
|
|
|
|
|
+if ($LASTEXITCODE -ne 0) { Say " X 依赖安装失败 (上面有 pip 的报错) —— 先解决它, 别接着跑 start.bat"; exit 3 }
|
|
|
|
|
+
|
|
|
|
|
+Say "== 4/6 写配置"
|
|
|
|
|
+# 别改回 Get-Content / Set-Content -Encoding UTF8 (2026-09-10 实机踩过):
|
|
|
|
|
+# PS 5.1 的 Get-Content 把无 BOM 的 UTF-8 当 ANSI(GBK) 解码 -> 中文注释变乱码;
|
|
|
|
|
+# Set-Content -Encoding UTF8 又写出 BOM -> Python 侧用裸 utf-8 json.loads 直接 JSONDecodeError。
|
|
|
|
|
+# 交给 venv 里的 Python 读写: 读 utf-8-sig (有 BOM 也认), 写无 BOM 的 UTF-8。
|
|
|
|
|
+# 下面 Python 代码故意只用单引号, 避开 PS 5.1 传参时的引号转义坑。
|
|
|
|
|
+$cfgFix = @'
|
|
|
|
|
+import json, pathlib, sys
|
|
|
|
|
+p = pathlib.Path('configs/serve.json') # portability-allow: 安装脚本已 Set-Location 到安装根
|
|
|
|
|
+c = json.loads(p.read_text(encoding='utf-8-sig'))
|
|
|
|
|
+# 写**相对**路径 (相对安装根): 整个目录拷到别的电脑/别的盘后仍然有效 (绝对路径会在换机后失效)
|
|
|
|
|
+exe = pathlib.Path(sys.executable).resolve()
|
|
|
|
|
+root = pathlib.Path('.').resolve()
|
|
|
|
|
+try:
|
|
|
|
|
+ c['python'] = exe.relative_to(root).as_posix()
|
|
|
|
|
+except ValueError:
|
|
|
|
|
+ c['python'] = exe.as_posix()
|
|
|
|
|
+p.write_text(json.dumps(c, ensure_ascii=False, indent=2) + '\n', encoding='utf-8')
|
|
|
|
|
+print(' configs/serve.json -> ' + c['python'] + ' (相对安装根)')
|
|
|
|
|
+'@
|
|
|
|
|
+& $vpy -c $cfgFix
|
|
|
|
|
+if ($LASTEXITCODE -ne 0) { Say " X 写 configs\serve.json 失败"; exit 4 }
|
|
|
|
|
+
|
|
|
|
|
+Say "== 5/6 建启动快捷方式 (无窗口; 不依赖 Windows 脚本宿主)"
|
|
|
|
|
+# 2026-09-16 用户令二 "把 VBScript 替换掉": 原先无窗口启动靠 start_hidden.vbs (WScript.Shell.Run 窗口样式 0),
|
|
|
|
|
+# 现在快捷方式直接指向 **pythonw.exe**(无控制台子系统的解释器) + 启动器脚本 —— 运行期一个窗口都没有,
|
|
|
|
|
+# 且不经过 wscript/cscript: WSH 被组策略禁用、或系统未安装 WSH 功能的机器上同样可用。
|
|
|
|
|
+# 注意: 这里是 PowerShell 自己的 COM 调用, 不是 .vbs 文件; 建不出来也不让安装失败 (提示手工建/用 start.bat)。
|
|
|
|
|
+$rootDir = (Get-Location).Path
|
|
|
|
|
+$pywPath = (Resolve-Path ".\.venv\Scripts\pythonw.exe").Path
|
|
|
|
|
+$launcher = Join-Path $rootDir "scripts\guanlan_start_hidden.py"
|
|
|
|
|
+function New-GuanlanShortcut([string]$Path) {
|
|
|
|
|
+ $sh = New-Object -ComObject WScript.Shell
|
|
|
|
|
+ $lnk = $sh.CreateShortcut($Path)
|
|
|
|
|
+ $lnk.TargetPath = $pywPath
|
|
|
|
|
+ $lnk.Arguments = '"' + $launcher + '"'
|
|
|
|
|
+ $lnk.WorkingDirectory = $rootDir
|
|
|
|
|
+ $lnk.WindowStyle = 7 # 最小化; pythonw 本身无窗口, 这里是双保险
|
|
|
|
|
+ $lnk.Description = "观澜·如东样板 v2 - 无窗口启动 (pythonw.exe)"
|
|
|
|
|
+ $ico = Join-Path $rootDir "resources\guanlan.ico"
|
|
|
|
|
+ if (Test-Path $ico) { $lnk.IconLocation = $ico }
|
|
|
|
|
+ $lnk.Save()
|
|
|
|
|
+}
|
|
|
|
|
+$made = @()
|
|
|
|
|
+try {
|
|
|
|
|
+ $lnkRoot = Join-Path $rootDir "启动观澜.lnk"
|
|
|
|
|
+ New-GuanlanShortcut $lnkRoot
|
|
|
|
|
+ $made += $lnkRoot
|
|
|
|
|
+ try {
|
|
|
|
|
+ if ($NoDesktopShortcut) {
|
|
|
|
|
+ Say " (-NoDesktopShortcut: 跳过桌面快捷方式 —— 自动核验用, 免得在别人桌面上留一个指向临时目录的死链)"
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $desk = [Environment]::GetFolderPath('Desktop')
|
|
|
|
|
+ if ($desk) {
|
|
|
|
|
+ $lnkDesk = Join-Path $desk "观澜·如东样板 v2.lnk"
|
|
|
|
|
+ New-GuanlanShortcut $lnkDesk
|
|
|
|
|
+ $made += $lnkDesk
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch { Say " (桌面快捷方式没建成, 不影响使用: $($_.Exception.Message))" }
|
|
|
|
|
+} catch {
|
|
|
|
|
+ Say " [!] 快捷方式没建成: $($_.Exception.Message)"
|
|
|
|
|
+ Say " 不影响使用: 双击 start.bat 一样起得来(会有一次极短的窗口闪烁);"
|
|
|
|
|
+ Say " 或手工建: 目标填 $pywPath 参数填 `"$launcher`""
|
|
|
|
|
+}
|
|
|
|
|
+foreach ($m in $made) { Say " 已建: $m" }
|
|
|
|
|
+if ($made.Count -gt 0) { Say " * 双击这个快捷方式 = 完全不出现命令窗口 (start.bat 会有一次极短闪烁)" }
|
|
|
|
|
+
|
|
|
|
|
+Say "== 6/6 Ollama (只影响问答与本地审核; 其余页面不受影响)"
|
|
|
|
|
+if (-not $SkipOllama) {
|
|
|
|
|
+ $has = Get-Command ollama -ErrorAction SilentlyContinue
|
|
|
|
|
+ if ($has) { Say " 已安装: $(& ollama -v 2>&1 | Select-Object -First 1)" }
|
|
|
|
|
+ elseif (Test-Path "vendor\ollama\OllamaSetup.exe") {
|
|
|
|
|
+ Say " 包内有离线安装包, 现在静默安装 (约 1.5 GB, 需几分钟)…"
|
|
|
|
|
+ Start-Process -FilePath "vendor\ollama\OllamaSetup.exe" -ArgumentList "/SILENT" -Wait
|
|
|
|
|
+ Say " 安装完成; 模型请把有网机器的 %USERPROFILE%\.ollama\models 整个目录拷到本机同位置"
|
|
|
|
|
+ } else { Say " 未装且包内无离线包: 问答不可用。装法见 说明书 §5" }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+Say ""
|
|
|
|
|
+& $vpy guanlan.py check
|
|
|
|
|
+Say ""
|
|
|
|
|
+Say "安装完成. 启动: 双击「启动观澜」快捷方式 (无窗口) 或 start.bat; 停止: stop.bat; 自检: check.bat"
|
|
|
|
|
+Say " 入口: http://127.0.0.1:28084/"
|