fix(aurora): harden Kling integration and surface config diagnostics
This commit is contained in:
11
.env.example
11
.env.example
@@ -59,6 +59,9 @@ DEEPSEEK_BASE_URL=https://api.deepseek.com
|
|||||||
# OpenAI API (optional)
|
# OpenAI API (optional)
|
||||||
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
|
||||||
|
# Anthropic Claude API (Sofiia agent)
|
||||||
|
ANTHROPIC_API_KEY=sk-ant-api03-xxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
|
||||||
# Notion integration (optional)
|
# Notion integration (optional)
|
||||||
NOTION_API_KEY=
|
NOTION_API_KEY=
|
||||||
NOTION_VERSION=2022-06-28
|
NOTION_VERSION=2022-06-28
|
||||||
@@ -139,6 +142,14 @@ ENVIRONMENT=development
|
|||||||
# Enable debug mode (true/false)
|
# Enable debug mode (true/false)
|
||||||
DEBUG=true
|
DEBUG=true
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Aurora / Kling Integration
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
KLING_ACCESS_KEY=
|
||||||
|
KLING_SECRET_KEY=
|
||||||
|
KLING_BASE_URL=https://api.klingai.com
|
||||||
|
KLING_TIMEOUT=60
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# SECRET GENERATION COMMANDS
|
# SECRET GENERATION COMMANDS
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|||||||
@@ -94,6 +94,10 @@ services:
|
|||||||
- AURORA_FORCE_CPU=false
|
- AURORA_FORCE_CPU=false
|
||||||
- AURORA_PREFER_MPS=true
|
- AURORA_PREFER_MPS=true
|
||||||
- AURORA_ENABLE_VIDEOTOOLBOX=true
|
- AURORA_ENABLE_VIDEOTOOLBOX=true
|
||||||
|
- KLING_ACCESS_KEY=${KLING_ACCESS_KEY:-}
|
||||||
|
- KLING_SECRET_KEY=${KLING_SECRET_KEY:-}
|
||||||
|
- KLING_BASE_URL=${KLING_BASE_URL:-https://api.klingai.com}
|
||||||
|
- KLING_TIMEOUT=${KLING_TIMEOUT:-60}
|
||||||
volumes:
|
volumes:
|
||||||
- sofiia-data:/data
|
- sofiia-data:/data
|
||||||
networks:
|
networks:
|
||||||
|
|||||||
74
services/aurora-service/README.md
Normal file
74
services/aurora-service/README.md
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
# Aurora Service
|
||||||
|
|
||||||
|
`aurora-service` is a FastAPI scaffold for AISTALK media forensics workflows.
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
- `POST /api/aurora/upload` (`multipart/form-data`)
|
||||||
|
- fields: `file`, `mode` (`tactical|forensic`)
|
||||||
|
- returns `job_id`
|
||||||
|
- `GET /api/aurora/status/{job_id}`
|
||||||
|
- `GET /api/aurora/jobs`
|
||||||
|
- `GET /api/aurora/result/{job_id}`
|
||||||
|
- `POST /api/aurora/cancel/{job_id}`
|
||||||
|
- `POST /api/aurora/delete/{job_id}`
|
||||||
|
- `GET /api/aurora/files/{job_id}/{file_name}`
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- Visual media (`video`, `photo`) run deterministic sequential enhancement with conservative defaults:
|
||||||
|
- `frame -> pre-denoise -> deblur -> face restore (GFPGAN / CodeFormer-style fallback) -> Real-ESRGAN`
|
||||||
|
- For `priority=faces`, pipeline can switch to ROI-only face processing (background preserved).
|
||||||
|
- Score-driven candidate selection is enabled for forensic face workflows.
|
||||||
|
- `audio` path remains scaffold (`Echo`) for now.
|
||||||
|
- Forensic mode adds chain-of-custody artifacts and signature metadata.
|
||||||
|
- Model weights are auto-downloaded to `AURORA_MODELS_DIR` on first run.
|
||||||
|
|
||||||
|
## Local run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd services/aurora-service
|
||||||
|
pip install -r requirements.txt
|
||||||
|
uvicorn app.main:app --host 0.0.0.0 --port 9401
|
||||||
|
```
|
||||||
|
|
||||||
|
## Native macOS run (Apple Silicon)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd services/aurora-service
|
||||||
|
./setup-native-macos.sh
|
||||||
|
./start-native-macos.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
This profile enables:
|
||||||
|
- `AURORA_FORCE_CPU=false`
|
||||||
|
- `AURORA_PREFER_MPS=true`
|
||||||
|
- `AURORA_ENABLE_VIDEOTOOLBOX=true`
|
||||||
|
|
||||||
|
### Runtime env vars
|
||||||
|
|
||||||
|
- `AURORA_DATA_DIR` (default: `/data/aurora`)
|
||||||
|
- `AURORA_MODELS_DIR` (default: `/data/aurora/models`)
|
||||||
|
- `AURORA_FORCE_CPU` (default: `true`)
|
||||||
|
- `AURORA_PREFER_MPS` (default: `true`)
|
||||||
|
- `AURORA_ENABLE_VIDEOTOOLBOX` (default: `true`)
|
||||||
|
- `AURORA_FFMPEG_VIDEO_ENCODER` (optional override, e.g. `h264_videotoolbox`)
|
||||||
|
- `KLING_ACCESS_KEY` / `KLING_SECRET_KEY` (required for Kling endpoints)
|
||||||
|
- `KLING_BASE_URL` (default: `https://api.klingai.com`)
|
||||||
|
- `KLING_TIMEOUT` (default: `60`)
|
||||||
|
|
||||||
|
## Autostart via launchd (macOS)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd services/aurora-service
|
||||||
|
./launchd/install-launchd.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Useful commands:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./launchd/status-launchd.sh
|
||||||
|
./launchd/uninstall-launchd.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
`install-launchd.sh` bootstraps the service immediately, so reboot is not required.
|
||||||
273
services/aurora-service/app/kling.py
Normal file
273
services/aurora-service/app/kling.py
Normal file
@@ -0,0 +1,273 @@
|
|||||||
|
"""Kling AI API client for video generation and enhancement."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
import hmac
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
|
import urllib.request
|
||||||
|
import urllib.error
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
KLING_ACCESS_KEY = os.getenv("KLING_ACCESS_KEY", "").strip()
|
||||||
|
KLING_SECRET_KEY = os.getenv("KLING_SECRET_KEY", "").strip()
|
||||||
|
KLING_BASE_URL = os.getenv("KLING_BASE_URL", "https://api.klingai.com")
|
||||||
|
KLING_TIMEOUT = int(os.getenv("KLING_TIMEOUT", "60"))
|
||||||
|
|
||||||
|
|
||||||
|
def _kling_sign(access_key: str, secret_key: str) -> str:
|
||||||
|
"""Generate Kling AI Bearer token via HMAC-SHA256 JWT-style signing."""
|
||||||
|
import base64
|
||||||
|
header = base64.urlsafe_b64encode(json.dumps({"alg": "HS256", "typ": "JWT"}).encode()).rstrip(b"=").decode()
|
||||||
|
now = int(time.time())
|
||||||
|
payload = base64.urlsafe_b64encode(json.dumps({
|
||||||
|
"iss": access_key,
|
||||||
|
"exp": now + 1800,
|
||||||
|
"nbf": now - 5,
|
||||||
|
}).encode()).rstrip(b"=").decode()
|
||||||
|
msg = f"{header}.{payload}"
|
||||||
|
sig = hmac.new(secret_key.encode(), msg.encode(), hashlib.sha256).digest()
|
||||||
|
sig_b64 = base64.urlsafe_b64encode(sig).rstrip(b"=").decode()
|
||||||
|
return f"{msg}.{sig_b64}"
|
||||||
|
|
||||||
|
|
||||||
|
def _kling_headers() -> Dict[str, str]:
|
||||||
|
if not KLING_ACCESS_KEY or not KLING_SECRET_KEY:
|
||||||
|
raise RuntimeError(
|
||||||
|
"Kling credentials are not configured. Set KLING_ACCESS_KEY and KLING_SECRET_KEY."
|
||||||
|
)
|
||||||
|
token = _kling_sign(KLING_ACCESS_KEY, KLING_SECRET_KEY)
|
||||||
|
return {
|
||||||
|
"Authorization": f"Bearer {token}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _kling_request(method: str, path: str, body: Optional[Dict] = None, timeout: int = KLING_TIMEOUT) -> Dict[str, Any]:
|
||||||
|
url = f"{KLING_BASE_URL}{path}"
|
||||||
|
data = json.dumps(body).encode() if body else None
|
||||||
|
req = urllib.request.Request(url, data=data, headers=_kling_headers(), method=method)
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen(req, timeout=timeout) as resp:
|
||||||
|
raw = resp.read().decode("utf-8")
|
||||||
|
return json.loads(raw)
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
err_body = e.read().decode("utf-8", errors="replace")
|
||||||
|
raise RuntimeError(f"Kling API {method} {path} → {e.code}: {err_body}") from e
|
||||||
|
|
||||||
|
|
||||||
|
def _kling_request_with_fallback(
|
||||||
|
method: str,
|
||||||
|
paths: List[str],
|
||||||
|
body: Optional[Dict] = None,
|
||||||
|
timeout: int = KLING_TIMEOUT,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
"""Try several endpoint variants to tolerate provider path drift/gateway prefixes."""
|
||||||
|
last_error: Optional[str] = None
|
||||||
|
tried: List[str] = []
|
||||||
|
for path in paths:
|
||||||
|
tried.append(path)
|
||||||
|
try:
|
||||||
|
return _kling_request(method, path, body=body, timeout=timeout)
|
||||||
|
except RuntimeError as e:
|
||||||
|
msg = str(e)
|
||||||
|
last_error = msg
|
||||||
|
# 404 likely means wrong endpoint path; try next candidate.
|
||||||
|
if "→ 404:" in msg:
|
||||||
|
continue
|
||||||
|
# Non-404 errors are usually actionable immediately.
|
||||||
|
raise
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Kling API endpoint mismatch for {method}. Tried: {tried}. Last error: {last_error or 'unknown'}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# ── Video Enhancement (Video-to-Video) ──────────────────────────────────────
|
||||||
|
|
||||||
|
def kling_video_enhance(
|
||||||
|
*,
|
||||||
|
video_url: Optional[str] = None,
|
||||||
|
video_id: Optional[str] = None,
|
||||||
|
prompt: str = "",
|
||||||
|
negative_prompt: str = "noise, blur, artifacts",
|
||||||
|
mode: str = "pro",
|
||||||
|
duration: str = "5",
|
||||||
|
cfg_scale: float = 0.5,
|
||||||
|
callback_url: Optional[str] = None,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
"""Submit a video-to-video enhancement task to Kling AI.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
video_url: Direct URL to input video.
|
||||||
|
video_id: Kling resource ID for previously uploaded video.
|
||||||
|
prompt: Text guidance for enhancement.
|
||||||
|
negative_prompt: Things to avoid.
|
||||||
|
mode: 'std' or 'pro'.
|
||||||
|
duration: '5' or '10' seconds.
|
||||||
|
cfg_scale: 0.0-1.0, how strongly to follow prompt.
|
||||||
|
callback_url: Webhook for completion notification.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Task response dict with task_id.
|
||||||
|
"""
|
||||||
|
if not video_url and not video_id:
|
||||||
|
raise ValueError("Either video_url or video_id must be provided")
|
||||||
|
|
||||||
|
payload: Dict[str, Any] = {
|
||||||
|
"model": f"kling-v1-5",
|
||||||
|
"mode": mode,
|
||||||
|
"duration": duration,
|
||||||
|
"cfg_scale": cfg_scale,
|
||||||
|
"prompt": prompt,
|
||||||
|
"negative_prompt": negative_prompt,
|
||||||
|
}
|
||||||
|
if video_url:
|
||||||
|
payload["video_url"] = video_url
|
||||||
|
if video_id:
|
||||||
|
payload["video_id"] = video_id
|
||||||
|
if callback_url:
|
||||||
|
payload["callback_url"] = callback_url
|
||||||
|
|
||||||
|
return _kling_request_with_fallback(
|
||||||
|
"POST",
|
||||||
|
["/v1/videos/video2video", "/kling/v1/videos/video2video"],
|
||||||
|
body=payload,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def kling_video_generate(
|
||||||
|
*,
|
||||||
|
image_url: Optional[str] = None,
|
||||||
|
image_id: Optional[str] = None,
|
||||||
|
prompt: str,
|
||||||
|
negative_prompt: str = "noise, blur, artifacts, distortion",
|
||||||
|
model: str = "kling-v1-5",
|
||||||
|
mode: str = "pro",
|
||||||
|
duration: str = "5",
|
||||||
|
cfg_scale: float = 0.5,
|
||||||
|
aspect_ratio: str = "16:9",
|
||||||
|
callback_url: Optional[str] = None,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
"""Generate video from image + prompt (image-to-video).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
image_url: Source still frame URL.
|
||||||
|
image_id: Kling resource ID for previously uploaded image.
|
||||||
|
prompt: Animation guidance.
|
||||||
|
model: 'kling-v1', 'kling-v1-5', 'kling-v1-6'.
|
||||||
|
mode: 'std' or 'pro'.
|
||||||
|
duration: '5' or '10'.
|
||||||
|
aspect_ratio: '16:9', '9:16', '1:1'.
|
||||||
|
"""
|
||||||
|
if not image_url and not image_id:
|
||||||
|
raise ValueError("Either image_url or image_id must be provided")
|
||||||
|
|
||||||
|
payload: Dict[str, Any] = {
|
||||||
|
"model": model,
|
||||||
|
"mode": mode,
|
||||||
|
"duration": duration,
|
||||||
|
"cfg_scale": cfg_scale,
|
||||||
|
"prompt": prompt,
|
||||||
|
"negative_prompt": negative_prompt,
|
||||||
|
"aspect_ratio": aspect_ratio,
|
||||||
|
}
|
||||||
|
if image_url:
|
||||||
|
payload["image"] = {"type": "url", "url": image_url}
|
||||||
|
if image_id:
|
||||||
|
payload["image"] = {"type": "id", "id": image_id}
|
||||||
|
if callback_url:
|
||||||
|
payload["callback_url"] = callback_url
|
||||||
|
|
||||||
|
return _kling_request_with_fallback(
|
||||||
|
"POST",
|
||||||
|
["/v1/videos/image2video", "/kling/v1/videos/image2video"],
|
||||||
|
body=payload,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def kling_task_status(task_id: str) -> Dict[str, Any]:
|
||||||
|
"""Get status of any Kling task by ID."""
|
||||||
|
return _kling_request_with_fallback(
|
||||||
|
"GET",
|
||||||
|
[f"/v1/tasks/{task_id}", f"/kling/v1/tasks/{task_id}"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def kling_video_task_status(task_id: str, endpoint: str = "video2video") -> Dict[str, Any]:
|
||||||
|
"""Get status of a video task."""
|
||||||
|
return _kling_request_with_fallback(
|
||||||
|
"GET",
|
||||||
|
[f"/v1/videos/{endpoint}/{task_id}", f"/kling/v1/videos/{endpoint}/{task_id}"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def kling_list_models() -> Dict[str, Any]:
|
||||||
|
"""List available Kling models."""
|
||||||
|
return _kling_request_with_fallback(
|
||||||
|
"GET",
|
||||||
|
["/v1/models", "/kling/v1/models"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def kling_upload_file(file_path: Path) -> Dict[str, Any]:
|
||||||
|
"""Upload a local file to Kling storage and return resource_id."""
|
||||||
|
import base64
|
||||||
|
with open(file_path, "rb") as f:
|
||||||
|
data = f.read()
|
||||||
|
b64 = base64.b64encode(data).decode()
|
||||||
|
suffix = file_path.suffix.lstrip(".").lower()
|
||||||
|
mime_map = {
|
||||||
|
"mp4": "video/mp4", "mov": "video/quicktime", "avi": "video/x-msvideo",
|
||||||
|
"jpg": "image/jpeg", "jpeg": "image/jpeg", "png": "image/png",
|
||||||
|
}
|
||||||
|
mime = mime_map.get(suffix, "application/octet-stream")
|
||||||
|
payload = {
|
||||||
|
"file": b64,
|
||||||
|
"file_name": file_path.name,
|
||||||
|
"content_type": mime,
|
||||||
|
}
|
||||||
|
return _kling_request_with_fallback(
|
||||||
|
"POST",
|
||||||
|
["/v1/files/upload", "/v1/files", "/kling/v1/files/upload", "/kling/v1/files"],
|
||||||
|
body=payload,
|
||||||
|
timeout=120,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def kling_poll_until_done(
|
||||||
|
task_id: str,
|
||||||
|
endpoint: str = "video2video",
|
||||||
|
max_wait_sec: int = 600,
|
||||||
|
poll_interval: int = 5,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
"""Poll Kling task until completed/failed or timeout."""
|
||||||
|
start = time.time()
|
||||||
|
while True:
|
||||||
|
status_resp = kling_video_task_status(task_id, endpoint)
|
||||||
|
task = status_resp.get("data", {})
|
||||||
|
state = task.get("task_status") or task.get("status") or "processing"
|
||||||
|
|
||||||
|
if state in ("succeed", "completed", "failed", "error"):
|
||||||
|
return status_resp
|
||||||
|
|
||||||
|
elapsed = time.time() - start
|
||||||
|
if elapsed >= max_wait_sec:
|
||||||
|
raise TimeoutError(f"Kling task {task_id} timed out after {max_wait_sec}s (last status: {state})")
|
||||||
|
|
||||||
|
logger.debug("Kling task %s status=%s elapsed=%.0fs", task_id, state, elapsed)
|
||||||
|
time.sleep(poll_interval)
|
||||||
|
|
||||||
|
|
||||||
|
def kling_health_check() -> Dict[str, Any]:
|
||||||
|
"""Quick connectivity check — returns status dict."""
|
||||||
|
try:
|
||||||
|
resp = _kling_request("GET", "/v1/models", timeout=10)
|
||||||
|
return {"ok": True, "models": resp}
|
||||||
|
except Exception as exc:
|
||||||
|
return {"ok": False, "error": str(exc)}
|
||||||
1327
services/aurora-service/app/main.py
Normal file
1327
services/aurora-service/app/main.py
Normal file
File diff suppressed because it is too large
Load Diff
113
services/aurora-service/launchd/install-launchd.sh
Executable file
113
services/aurora-service/launchd/install-launchd.sh
Executable file
@@ -0,0 +1,113 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
LABEL="${AURORA_LAUNCHD_LABEL:-com.daarion.aurora}"
|
||||||
|
DOMAIN="gui/$(id -u)"
|
||||||
|
LAUNCH_AGENTS_DIR="${HOME}/Library/LaunchAgents"
|
||||||
|
PLIST_PATH="${LAUNCH_AGENTS_DIR}/${LABEL}.plist"
|
||||||
|
START_SCRIPT="${ROOT_DIR}/start-native-macos.sh"
|
||||||
|
|
||||||
|
PORT_VALUE="${PORT:-9401}"
|
||||||
|
DATA_DIR_VALUE="${AURORA_DATA_DIR:-${HOME}/.sofiia/aurora-data}"
|
||||||
|
MODELS_DIR_VALUE="${AURORA_MODELS_DIR:-${DATA_DIR_VALUE}/models}"
|
||||||
|
PUBLIC_BASE_URL_VALUE="${AURORA_PUBLIC_BASE_URL:-http://127.0.0.1:${PORT_VALUE}}"
|
||||||
|
CORS_ORIGINS_VALUE="${AURORA_CORS_ORIGINS:-*}"
|
||||||
|
FORCE_CPU_VALUE="${AURORA_FORCE_CPU:-false}"
|
||||||
|
PREFER_MPS_VALUE="${AURORA_PREFER_MPS:-true}"
|
||||||
|
ENABLE_VTB_VALUE="${AURORA_ENABLE_VIDEOTOOLBOX:-true}"
|
||||||
|
KLING_ACCESS_KEY_VALUE="${KLING_ACCESS_KEY:-}"
|
||||||
|
KLING_SECRET_KEY_VALUE="${KLING_SECRET_KEY:-}"
|
||||||
|
KLING_BASE_URL_VALUE="${KLING_BASE_URL:-https://api.klingai.com}"
|
||||||
|
KLING_TIMEOUT_VALUE="${KLING_TIMEOUT:-60}"
|
||||||
|
|
||||||
|
LOG_DIR="${DATA_DIR_VALUE}/logs"
|
||||||
|
LOG_OUT="${LOG_DIR}/launchd.out.log"
|
||||||
|
LOG_ERR="${LOG_DIR}/launchd.err.log"
|
||||||
|
PATH_VALUE="${PATH:-/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin}"
|
||||||
|
|
||||||
|
if [ ! -x "${START_SCRIPT}" ]; then
|
||||||
|
echo "[aurora-launchd] missing start script: ${START_SCRIPT}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -x "${ROOT_DIR}/.venv-macos/bin/python" ]; then
|
||||||
|
echo "[aurora-launchd] .venv-macos is missing. Run ./setup-native-macos.sh first."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "${LAUNCH_AGENTS_DIR}" "${LOG_DIR}" "${DATA_DIR_VALUE}" "${MODELS_DIR_VALUE}"
|
||||||
|
|
||||||
|
cat > "${PLIST_PATH}" <<PLIST
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>Label</key>
|
||||||
|
<string>${LABEL}</string>
|
||||||
|
|
||||||
|
<key>ProgramArguments</key>
|
||||||
|
<array>
|
||||||
|
<string>${START_SCRIPT}</string>
|
||||||
|
</array>
|
||||||
|
|
||||||
|
<key>WorkingDirectory</key>
|
||||||
|
<string>${ROOT_DIR}</string>
|
||||||
|
|
||||||
|
<key>RunAtLoad</key>
|
||||||
|
<true/>
|
||||||
|
|
||||||
|
<key>KeepAlive</key>
|
||||||
|
<true/>
|
||||||
|
|
||||||
|
<key>StandardOutPath</key>
|
||||||
|
<string>${LOG_OUT}</string>
|
||||||
|
<key>StandardErrorPath</key>
|
||||||
|
<string>${LOG_ERR}</string>
|
||||||
|
|
||||||
|
<key>EnvironmentVariables</key>
|
||||||
|
<dict>
|
||||||
|
<key>PATH</key>
|
||||||
|
<string>${PATH_VALUE}</string>
|
||||||
|
<key>PYTHONUNBUFFERED</key>
|
||||||
|
<string>1</string>
|
||||||
|
<key>PORT</key>
|
||||||
|
<string>${PORT_VALUE}</string>
|
||||||
|
<key>AURORA_DATA_DIR</key>
|
||||||
|
<string>${DATA_DIR_VALUE}</string>
|
||||||
|
<key>AURORA_MODELS_DIR</key>
|
||||||
|
<string>${MODELS_DIR_VALUE}</string>
|
||||||
|
<key>AURORA_PUBLIC_BASE_URL</key>
|
||||||
|
<string>${PUBLIC_BASE_URL_VALUE}</string>
|
||||||
|
<key>AURORA_CORS_ORIGINS</key>
|
||||||
|
<string>${CORS_ORIGINS_VALUE}</string>
|
||||||
|
<key>AURORA_FORCE_CPU</key>
|
||||||
|
<string>${FORCE_CPU_VALUE}</string>
|
||||||
|
<key>AURORA_PREFER_MPS</key>
|
||||||
|
<string>${PREFER_MPS_VALUE}</string>
|
||||||
|
<key>AURORA_ENABLE_VIDEOTOOLBOX</key>
|
||||||
|
<string>${ENABLE_VTB_VALUE}</string>
|
||||||
|
<key>KLING_ACCESS_KEY</key>
|
||||||
|
<string>${KLING_ACCESS_KEY_VALUE}</string>
|
||||||
|
<key>KLING_SECRET_KEY</key>
|
||||||
|
<string>${KLING_SECRET_KEY_VALUE}</string>
|
||||||
|
<key>KLING_BASE_URL</key>
|
||||||
|
<string>${KLING_BASE_URL_VALUE}</string>
|
||||||
|
<key>KLING_TIMEOUT</key>
|
||||||
|
<string>${KLING_TIMEOUT_VALUE}</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
PLIST
|
||||||
|
|
||||||
|
chmod 644 "${PLIST_PATH}"
|
||||||
|
|
||||||
|
launchctl bootout "${DOMAIN}/${LABEL}" >/dev/null 2>&1 || true
|
||||||
|
launchctl bootstrap "${DOMAIN}" "${PLIST_PATH}"
|
||||||
|
launchctl enable "${DOMAIN}/${LABEL}" >/dev/null 2>&1 || true
|
||||||
|
launchctl kickstart -k "${DOMAIN}/${LABEL}"
|
||||||
|
|
||||||
|
echo "[aurora-launchd] installed: ${PLIST_PATH}"
|
||||||
|
echo "[aurora-launchd] active label: ${DOMAIN}/${LABEL}"
|
||||||
|
echo "[aurora-launchd] logs: ${LOG_OUT} | ${LOG_ERR}"
|
||||||
|
echo "[aurora-launchd] check: launchctl print ${DOMAIN}/${LABEL}"
|
||||||
Reference in New Issue
Block a user