Add resolution parameter to video generation requests and implement video status polling endpoint
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
@@ -74,6 +74,7 @@ class VideoRequest(BaseModel):
|
|||||||
prompt: str
|
prompt: str
|
||||||
duration_seconds: int | None = None
|
duration_seconds: int | None = None
|
||||||
aspect_ratio: str = "16:9"
|
aspect_ratio: str = "16:9"
|
||||||
|
resolution: str | None = None # e.g. "480p", "720p", "1080p"
|
||||||
|
|
||||||
|
|
||||||
class VideoFromImageRequest(BaseModel):
|
class VideoFromImageRequest(BaseModel):
|
||||||
@@ -82,6 +83,7 @@ class VideoFromImageRequest(BaseModel):
|
|||||||
prompt: str
|
prompt: str
|
||||||
duration_seconds: int | None = None
|
duration_seconds: int | None = None
|
||||||
aspect_ratio: str = "16:9"
|
aspect_ratio: str = "16:9"
|
||||||
|
resolution: str | None = None # e.g. "480p", "720p", "1080p"
|
||||||
|
|
||||||
|
|
||||||
class VideoResponse(BaseModel):
|
class VideoResponse(BaseModel):
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ async def generate_video(
|
|||||||
prompt=body.prompt,
|
prompt=body.prompt,
|
||||||
duration_seconds=body.duration_seconds,
|
duration_seconds=body.duration_seconds,
|
||||||
aspect_ratio=body.aspect_ratio,
|
aspect_ratio=body.aspect_ratio,
|
||||||
|
resolution=body.resolution,
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
@@ -131,6 +132,7 @@ async def generate_video_from_image(
|
|||||||
prompt=body.prompt,
|
prompt=body.prompt,
|
||||||
duration_seconds=body.duration_seconds,
|
duration_seconds=body.duration_seconds,
|
||||||
aspect_ratio=body.aspect_ratio,
|
aspect_ratio=body.aspect_ratio,
|
||||||
|
resolution=body.resolution,
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ async def generate_video(
|
|||||||
prompt: str,
|
prompt: str,
|
||||||
duration_seconds: int | None = None,
|
duration_seconds: int | None = None,
|
||||||
aspect_ratio: str = "16:9",
|
aspect_ratio: str = "16:9",
|
||||||
|
resolution: str | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
"""Request text-to-video generation via OpenRouter."""
|
"""Request text-to-video generation via OpenRouter."""
|
||||||
base_url = os.getenv("OPENROUTER_BASE_URL", OPENROUTER_BASE_URL)
|
base_url = os.getenv("OPENROUTER_BASE_URL", OPENROUTER_BASE_URL)
|
||||||
@@ -91,6 +92,8 @@ async def generate_video(
|
|||||||
}
|
}
|
||||||
if duration_seconds is not None:
|
if duration_seconds is not None:
|
||||||
payload["duration_seconds"] = duration_seconds
|
payload["duration_seconds"] = duration_seconds
|
||||||
|
if resolution is not None:
|
||||||
|
payload["resolution"] = resolution
|
||||||
async with httpx.AsyncClient(timeout=120) as client:
|
async with httpx.AsyncClient(timeout=120) as client:
|
||||||
resp = client.build_request(
|
resp = client.build_request(
|
||||||
"POST", f"{base_url}/videos", headers=_headers(), json=payload
|
"POST", f"{base_url}/videos", headers=_headers(), json=payload
|
||||||
@@ -106,6 +109,7 @@ async def generate_video_from_image(
|
|||||||
prompt: str,
|
prompt: str,
|
||||||
duration_seconds: int | None = None,
|
duration_seconds: int | None = None,
|
||||||
aspect_ratio: str = "16:9",
|
aspect_ratio: str = "16:9",
|
||||||
|
resolution: str | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
"""Request image-to-video generation via OpenRouter."""
|
"""Request image-to-video generation via OpenRouter."""
|
||||||
base_url = os.getenv("OPENROUTER_BASE_URL", OPENROUTER_BASE_URL)
|
base_url = os.getenv("OPENROUTER_BASE_URL", OPENROUTER_BASE_URL)
|
||||||
@@ -117,6 +121,8 @@ async def generate_video_from_image(
|
|||||||
}
|
}
|
||||||
if duration_seconds is not None:
|
if duration_seconds is not None:
|
||||||
payload["duration_seconds"] = duration_seconds
|
payload["duration_seconds"] = duration_seconds
|
||||||
|
if resolution is not None:
|
||||||
|
payload["resolution"] = resolution
|
||||||
async with httpx.AsyncClient(timeout=120) as client:
|
async with httpx.AsyncClient(timeout=120) as client:
|
||||||
resp = client.build_request(
|
resp = client.build_request(
|
||||||
"POST", f"{base_url}/videos", headers=_headers(), json=payload
|
"POST", f"{base_url}/videos", headers=_headers(), json=payload
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import httpx
|
|||||||
from flask import (
|
from flask import (
|
||||||
Flask,
|
Flask,
|
||||||
flash,
|
flash,
|
||||||
|
jsonify,
|
||||||
redirect,
|
redirect,
|
||||||
render_template,
|
render_template,
|
||||||
request,
|
request,
|
||||||
@@ -172,18 +173,25 @@ def generate_video():
|
|||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
mode = request.form.get("mode", "text")
|
mode = request.form.get("mode", "text")
|
||||||
token = session["access_token"]
|
token = session["access_token"]
|
||||||
|
duration_raw = request.form.get("duration_seconds", "")
|
||||||
|
duration = int(duration_raw) if duration_raw.strip().isdigit() else None
|
||||||
|
resolution = request.form.get("resolution", "").strip() or None
|
||||||
if mode == "image":
|
if mode == "image":
|
||||||
resp = _api("POST", "/generate/video/from-image", token=token, json={
|
resp = _api("POST", "/generate/video/from-image", token=token, json={
|
||||||
"model": request.form.get("model", "").strip(),
|
"model": request.form.get("model", "").strip(),
|
||||||
"image_url": request.form.get("image_url", "").strip(),
|
"image_url": request.form.get("image_url", "").strip(),
|
||||||
"prompt": request.form.get("prompt", "").strip(),
|
"prompt": request.form.get("prompt", "").strip(),
|
||||||
"aspect_ratio": request.form.get("aspect_ratio", "16:9"),
|
"aspect_ratio": request.form.get("aspect_ratio", "16:9"),
|
||||||
|
"duration_seconds": duration,
|
||||||
|
"resolution": resolution,
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
resp = _api("POST", "/generate/video", token=token, json={
|
resp = _api("POST", "/generate/video", token=token, json={
|
||||||
"model": request.form.get("model", "").strip(),
|
"model": request.form.get("model", "").strip(),
|
||||||
"prompt": request.form.get("prompt", "").strip(),
|
"prompt": request.form.get("prompt", "").strip(),
|
||||||
"aspect_ratio": request.form.get("aspect_ratio", "16:9"),
|
"aspect_ratio": request.form.get("aspect_ratio", "16:9"),
|
||||||
|
"duration_seconds": duration,
|
||||||
|
"resolution": resolution,
|
||||||
})
|
})
|
||||||
if resp.status_code == 200:
|
if resp.status_code == 200:
|
||||||
result = resp.json()
|
result = resp.json()
|
||||||
@@ -192,6 +200,21 @@ def generate_video():
|
|||||||
return render_template("generate_video.html", result=result, error=error)
|
return render_template("generate_video.html", result=result, error=error)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/generate/video/status")
|
||||||
|
@login_required
|
||||||
|
def generate_video_status():
|
||||||
|
"""Proxy video status polling to the backend."""
|
||||||
|
polling_url = request.args.get("polling_url", "")
|
||||||
|
if not polling_url:
|
||||||
|
return jsonify({"error": "polling_url required"}), 400
|
||||||
|
resp = _api(
|
||||||
|
"GET", "/generate/video/status",
|
||||||
|
token=session["access_token"],
|
||||||
|
params={"polling_url": polling_url},
|
||||||
|
)
|
||||||
|
return jsonify(resp.json()), resp.status_code
|
||||||
|
|
||||||
|
|
||||||
# ── Admin ─────────────────────────────────────────────────────────────────
|
# ── Admin ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@app.get("/admin")
|
@app.get("/admin")
|
||||||
|
|||||||
Reference in New Issue
Block a user