fix:优化服务

This commit is contained in:
Daniel
2026-04-07 01:00:56 +08:00
parent 8d0b729f2f
commit e606b3dcd6
19 changed files with 899 additions and 7 deletions

View File

@@ -0,0 +1,88 @@
import asyncio
import json
import os
import sys
import time
import requests
import websockets
DISPATCH_WS_URL = os.getenv("DISPATCH_WS_URL", "ws://127.0.0.1:8020/ws/edge/edge-a4000-01")
WORKER_BASE_URL = os.getenv("WORKER_BASE_URL", "http://127.0.0.1:8000")
POLL_INTERVAL = float(os.getenv("EDGE_POLL_INTERVAL_SEC", "1.0"))
if len(sys.argv) > 1:
DISPATCH_WS_URL = sys.argv[1]
def worker_post(path: str, payload: dict):
r = requests.post(f"{WORKER_BASE_URL}{path}", json=payload, timeout=30)
r.raise_for_status()
return r.json()
def worker_get(path: str):
r = requests.get(f"{WORKER_BASE_URL}{path}", timeout=20)
r.raise_for_status()
return r.json()
async def handle_generate(ws, data: dict):
dispatch_id = data["dispatch_id"]
req = data["request"]
created = await asyncio.to_thread(worker_post, "/generate", req)
task_id = created["task_id"]
await ws.send(json.dumps({"event": "accepted", "dispatch_id": dispatch_id, "task_id": task_id}, ensure_ascii=False))
while True:
status = await asyncio.to_thread(worker_get, f"/tasks/{task_id}")
await ws.send(
json.dumps(
{
"event": "status",
"dispatch_id": dispatch_id,
"task_id": task_id,
"status": status["status"],
"progress": status.get("progress", 0.0),
},
ensure_ascii=False,
)
)
if status["status"] in {"SUCCEEDED", "FAILED"}:
result = await asyncio.to_thread(worker_get, f"/tasks/{task_id}/result")
await ws.send(
json.dumps(
{
"event": "result",
"dispatch_id": dispatch_id,
"task_id": task_id,
**result,
},
ensure_ascii=False,
)
)
return
await asyncio.sleep(POLL_INTERVAL)
async def main() -> None:
while True:
try:
async with websockets.connect(DISPATCH_WS_URL, max_size=2**22) as ws:
print(f"connected: {DISPATCH_WS_URL}")
while True:
raw = await ws.recv()
data = json.loads(raw)
event = data.get("event")
if event == "generate":
await handle_generate(ws, data)
elif event == "registered":
print("registered", data)
except Exception as exc:
print("connection error, retry in 3s:", exc)
time.sleep(3)
if __name__ == "__main__":
asyncio.run(main())

View File

@@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT_DIR"
if ! command -v python3 >/dev/null 2>&1; then
echo "[ERROR] python3 not found in WSL environment"
exit 1
fi
if [ ! -d .venv ]; then
echo "[INFO] .venv not found, running install_wsl_env.sh"
bash scripts/install_wsl_env.sh
fi
if [ ! -f .env ]; then
echo "[INFO] .env not found, copying from .env.example"
cp .env.example .env
fi
echo "[INFO] launching server in WSL"
exec bash scripts/run_server.sh

View File

@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT_DIR"
if [ ! -f .env ]; then
cp .env.example .env
fi
docker compose -f docker-compose.edge-dispatch.yml up -d --build
echo "[OK] edge dispatch service started"
echo "health: curl http://127.0.0.1:${EDGE_DISPATCH_PORT:-8020}/health"

View File

@@ -0,0 +1,18 @@
@echo off
setlocal
cd /d %~dp0\..
if not exist .venv (
echo [ERROR] .venv not found, run install script first
exit /b 1
)
if not exist .env (
echo [ERROR] .env not found, copy from .env.example
exit /b 1
)
call .venv\Scripts\activate.bat
for /f "usebackq tokens=1,* delims==" %%A in (".env") do (
if not "%%A"=="" set "%%A=%%B"
)
if "%WS_GATEWAY_HOST%"=="" set WS_GATEWAY_HOST=0.0.0.0
if "%WS_GATEWAY_PORT%"=="" set WS_GATEWAY_PORT=8010
python -m uvicorn app.ws_service:app --host %WS_GATEWAY_HOST% --port %WS_GATEWAY_PORT%

View File

@@ -0,0 +1,20 @@
$ErrorActionPreference = "Stop"
$Root = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path)
Set-Location $Root
if (!(Test-Path .venv)) { throw ".venv not found, run install script first" }
if (!(Test-Path .env)) { throw ".env not found, copy from .env.example" }
.\.venv\Scripts\Activate.ps1
Get-Content .env | ForEach-Object {
if ($_ -match "^\s*#") { return }
if ($_ -match "^\s*$") { return }
$parts = $_ -split "=", 2
if ($parts.Length -eq 2) {
[System.Environment]::SetEnvironmentVariable($parts[0], $parts[1], "Process")
}
}
$hostValue = if ($env:WS_GATEWAY_HOST) { $env:WS_GATEWAY_HOST } else { "0.0.0.0" }
$portValue = if ($env:WS_GATEWAY_PORT) { $env:WS_GATEWAY_PORT } else { "8010" }
python -m uvicorn app.ws_service:app --host $hostValue --port $portValue

View File

@@ -0,0 +1,21 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT_DIR"
if [ ! -d .venv ]; then
echo "[ERROR] .venv not found, run install script first"
exit 1
fi
if [ ! -f .env ]; then
echo "[ERROR] .env not found, copy from .env.example"
exit 1
fi
source .venv/bin/activate
set -a
source .env
set +a
python -m uvicorn app.ws_service:app --host "${WS_GATEWAY_HOST:-0.0.0.0}" --port "${WS_GATEWAY_PORT:-8010}"

View File

@@ -0,0 +1,31 @@
param(
[string]$Distro = ""
)
$ErrorActionPreference = "Stop"
$Root = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path)
Set-Location $Root
if (!(Get-Command wsl -ErrorAction SilentlyContinue)) {
throw "WSL command not found. Please install WSL first."
}
# Resolve Windows project path to the same distro that will run the server (mounts differ per distro).
if ([string]::IsNullOrWhiteSpace($Distro)) {
$linuxPath = (wsl -- wslpath -a "$Root").Trim()
} else {
$linuxPath = (wsl -d $Distro -- wslpath -a "$Root").Trim()
}
if ([string]::IsNullOrWhiteSpace($linuxPath)) {
throw "Failed to resolve WSL path for project root: $Root"
}
# Single argument to bash -lc; quote the whole string so spaces in path are safe.
$bashCommand = "cd '$linuxPath' && chmod +x scripts/one_click_wsl.sh scripts/install_wsl_env.sh scripts/run_server.sh && exec bash scripts/one_click_wsl.sh"
if ([string]::IsNullOrWhiteSpace($Distro)) {
wsl -- bash -lc "$bashCommand"
} else {
wsl -d $Distro -- bash -lc "$bashCommand"
}

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT_DIR"
docker compose -f docker-compose.edge-dispatch.yml down

View File

@@ -0,0 +1,37 @@
import asyncio
import json
import sys
import websockets
WS_URL = sys.argv[1] if len(sys.argv) > 1 else "ws://127.0.0.1:8010/ws/generate"
async def main() -> None:
payload = {
"action": "generate",
"payload": {
"prompt": "a lonely man walking in a rainy neon street, cinematic, handheld camera",
"negative_prompt": "blurry, deformed face, extra limbs, flicker",
"quality_mode": "preview",
"duration_sec": 1,
"width": 320,
"height": 240,
"fps": 8,
"steps": 8,
"seed": 123456,
},
}
async with websockets.connect(WS_URL, max_size=2**22) as ws:
await ws.send(json.dumps(payload, ensure_ascii=False))
while True:
msg = await ws.recv()
data = json.loads(msg)
print(json.dumps(data, ensure_ascii=False))
if data.get("event") == "result":
break
if __name__ == "__main__":
asyncio.run(main())