chore: initial commit of ai site platform

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
whm
2026-07-31 10:19:22 +08:00
commit 6366859bb3
222 changed files with 47313 additions and 0 deletions

120
scripts/restart_ai_only.py Normal file
View File

@@ -0,0 +1,120 @@
"""Kill port 8001 holders, then start ai-service."""
from __future__ import annotations
import os
import subprocess
import sys
import time
import urllib.request
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
LOG = ROOT / ".runtime" / "logs"
LOG.mkdir(parents=True, exist_ok=True)
def pids_on_port(port: int) -> list[int]:
out = subprocess.check_output(["netstat", "-ano"], text=True, errors="replace")
pids: set[int] = set()
needle = f":{port}"
for line in out.splitlines():
if needle not in line:
continue
if "LISTENING" not in line.upper():
continue
parts = line.split()
try:
pids.add(int(parts[-1]))
except ValueError:
pass
return sorted(pids)
def kill_pid(pid: int) -> None:
if pid <= 0:
return
subprocess.run(["taskkill", "/F", "/T", "/PID", str(pid)], check=False, capture_output=True)
def main() -> None:
print("stopping old ai...")
# stop watchdog first if present
wd = LOG / "watchdog.pid"
if wd.is_file():
try:
kill_pid(int(wd.read_text(encoding="ascii").strip()))
except ValueError:
pass
wd.unlink(missing_ok=True)
for name in ("ai-service.pid",):
pf = LOG / name
if pf.is_file():
try:
kill_pid(int(pf.read_text(encoding="ascii").strip()))
except ValueError:
pass
for pid in pids_on_port(8001):
print(f" free 8001 pid={pid}")
kill_pid(pid)
time.sleep(2)
env = os.environ.copy()
env["WEB_BASE"] = "http://127.0.0.1:5173"
env["PLATFORM_BASE"] = "http://127.0.0.1:8888"
env["GATEWAY_BASE"] = "http://127.0.0.1:8180"
env["GENERATE_LOG_DIR"] = str(LOG / "generate")
env["FIDELITY_SHOT_DIR"] = str(ROOT / ".runtime" / "fidelity_shots")
stamp = time.strftime("%H%M%S")
out_path = LOG / f"ai-service.{stamp}.out.log"
err_path = LOG / f"ai-service.{stamp}.err.log"
out_f = out_path.open("w", encoding="utf-8")
err_f = err_path.open("w", encoding="utf-8")
# also point stable names via copies later; use unique to avoid locks
(LOG / "ai-service.out.log.path").write_text(str(out_path), encoding="utf-8")
flags = getattr(subprocess, "CREATE_NO_WINDOW", 0)
p = subprocess.Popen(
[
sys.executable,
"-m",
"uvicorn",
"app:app",
"--host",
"127.0.0.1",
"--port",
"8001",
"--reload",
],
cwd=str(ROOT / "ai-service"),
env=env,
stdout=out_f,
stderr=err_f,
creationflags=flags,
)
(LOG / "ai-service.pid").write_text(str(p.pid), encoding="ascii")
print(f"started ai-service pid={p.pid}")
print(f" logs: {out_path.name} / {err_path.name}")
for i in range(45):
time.sleep(1)
try:
with urllib.request.urlopen("http://127.0.0.1:8001/docs", timeout=2) as r:
if r.status == 200:
print("OK AI http://127.0.0.1:8001")
return
except Exception as e:
if i % 5 == 4:
print(f" waiting... ({type(e).__name__})")
# show err log snippet
try:
print(err_path.read_text(encoding="utf-8", errors="replace")[-400:])
except Exception:
pass
raise SystemExit("AI failed to become ready on :8001")
if __name__ == "__main__":
main()