113 lines
3.5 KiB
Python
113 lines
3.5 KiB
Python
import time
|
|
import requests
|
|
import logging
|
|
from ..sso.sso_token import load_config, generate_sign_by_lux3d_code
|
|
|
|
logger = logging.getLogger("LuxRealEngine")
|
|
|
|
|
|
def render_and_poll(
|
|
base_url: str,
|
|
obs_render_design_id: str,
|
|
resolution=None,
|
|
ratio=None,
|
|
poll_interval: int = 2,
|
|
timeout: int = 600,
|
|
cookies: dict | None = None,
|
|
lux3d_api_key: str | None = None,
|
|
):
|
|
"""
|
|
:param base_url: e.g. http://localhost:9020
|
|
:param obs_render_design_id: Design ID
|
|
:param resolution: Resolution
|
|
:param ratio: Aspect ratio
|
|
:param poll_interval: Polling interval (seconds)
|
|
:param timeout: Timeout (seconds)
|
|
:param cookies: Optional cookies
|
|
:param lux3d_api_key: Invitation code (optional), used for OpenAPI signature
|
|
"""
|
|
# Get OpenAPI signature parameters
|
|
lux3d_code = load_config(lux3d_api_key=lux3d_api_key if lux3d_api_key else None)
|
|
if not lux3d_code.get("ak") or not lux3d_code.get("sk") or not lux3d_code.get("appuid"):
|
|
raise RuntimeError(
|
|
"Missing ak/sk/appuid configuration, please provide invitation code or configure config.txt file")
|
|
|
|
code_with_sign = generate_sign_by_lux3d_code(lux3d_code)
|
|
appuid = code_with_sign["appuid"]
|
|
appkey = code_with_sign["appkey"]
|
|
sign = code_with_sign["sign"]
|
|
timestamp = code_with_sign["timestamp"]
|
|
|
|
render_url = f"{base_url}/global/luxrealengine/render?appuid={appuid}&appkey={appkey}&sign={sign}×tamp={timestamp}"
|
|
poll_url = f"{base_url}/global/luxrealengine/render/status?appuid={appuid}&appkey={appkey}&sign={sign}×tamp={timestamp}"
|
|
|
|
headers = {
|
|
"Accept": "application/json",
|
|
"Content-Type": "application/json",
|
|
"User-Agent": "python-client",
|
|
}
|
|
|
|
payload = {
|
|
"baseObsRenderDesignId": obs_render_design_id,
|
|
}
|
|
|
|
if resolution is not None:
|
|
payload["resolution"] = resolution
|
|
if ratio is not None:
|
|
payload["ratio"] = ratio
|
|
|
|
# 1️⃣ Initiate rendering
|
|
resp = requests.post(
|
|
render_url,
|
|
json=payload,
|
|
headers=headers,
|
|
cookies=cookies,
|
|
timeout=10,
|
|
)
|
|
resp.raise_for_status()
|
|
data = resp.json()
|
|
|
|
if str(data.get("c")) != "0":
|
|
raise RuntimeError(f"Render request failed: {data}")
|
|
|
|
task_id = data["d"]
|
|
logger.info(f">>> Render task created, taskId: {task_id}")
|
|
start_time = time.time()
|
|
|
|
# 2️⃣ Polling
|
|
while True:
|
|
if time.time() - start_time > timeout:
|
|
raise TimeoutError(f"Render polling timeout: {task_id}")
|
|
|
|
time.sleep(poll_interval)
|
|
|
|
# Need to regenerate signature during polling (timestamp changes)
|
|
code_with_sign = generate_sign_by_lux3d_code(lux3d_code)
|
|
appuid = code_with_sign["appuid"]
|
|
appkey = code_with_sign["appkey"]
|
|
sign = code_with_sign["sign"]
|
|
timestamp = code_with_sign["timestamp"]
|
|
poll_url_with_sign = f"{base_url}/global/luxrealengine/render/status?taskId={task_id}&appuid={appuid}&appkey={appkey}&sign={sign}×tamp={timestamp}"
|
|
|
|
poll_resp = requests.get(
|
|
poll_url_with_sign,
|
|
headers=headers,
|
|
cookies=cookies,
|
|
timeout=10,
|
|
)
|
|
poll_resp.raise_for_status()
|
|
poll_data = poll_resp.json()
|
|
|
|
code = str(poll_data.get("c"))
|
|
|
|
if code == "0":
|
|
return poll_data["d"]
|
|
|
|
if code == "3001":
|
|
continue
|
|
|
|
if code == "3002":
|
|
raise RuntimeError(f"Render failed: {poll_data}")
|
|
|
|
raise RuntimeError(f"Unknown status code: {poll_data}")
|