fix:优化服务
This commit is contained in:
88
video_worker/scripts/edge_device_client.py
Normal file
88
video_worker/scripts/edge_device_client.py
Normal 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())
|
||||
23
video_worker/scripts/one_click_wsl.sh
Normal file
23
video_worker/scripts/one_click_wsl.sh
Normal 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
|
||||
14
video_worker/scripts/run_edge_dispatch_docker.sh
Executable file
14
video_worker/scripts/run_edge_dispatch_docker.sh
Executable 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"
|
||||
18
video_worker/scripts/run_ws_service.bat
Normal file
18
video_worker/scripts/run_ws_service.bat
Normal 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%
|
||||
20
video_worker/scripts/run_ws_service.ps1
Normal file
20
video_worker/scripts/run_ws_service.ps1
Normal 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
|
||||
21
video_worker/scripts/run_ws_service.sh
Executable file
21
video_worker/scripts/run_ws_service.sh
Executable 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}"
|
||||
31
video_worker/scripts/run_wsl_one_click.ps1
Normal file
31
video_worker/scripts/run_wsl_one_click.ps1
Normal 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"
|
||||
}
|
||||
7
video_worker/scripts/stop_edge_dispatch_docker.sh
Executable file
7
video_worker/scripts/stop_edge_dispatch_docker.sh
Executable 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
|
||||
37
video_worker/scripts/ws_smoke_test.py
Normal file
37
video_worker/scripts/ws_smoke_test.py
Normal 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())
|
||||
Reference in New Issue
Block a user