From f3e0d0d771f201d699d4a2c08e7e175b2955f313 Mon Sep 17 00:00:00 2001 From: puke <1129090915@qq.com> Date: Wed, 17 Dec 2025 10:58:27 +0800 Subject: [PATCH] =?UTF-8?q?API=E6=8E=A5=E5=8F=A3=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E8=87=AA=E5=AE=9A=E4=B9=89=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/routers/frame.py | 79 +++++++++++++++++++++++++++++++++++++++++++- api/routers/video.py | 8 +++++ api/schemas/frame.py | 22 +++++++++++- api/schemas/video.py | 15 +++++++-- 4 files changed, 120 insertions(+), 4 deletions(-) diff --git a/api/routers/frame.py b/api/routers/frame.py index e345f87..1aff672 100644 --- a/api/routers/frame.py +++ b/api/routers/frame.py @@ -18,7 +18,7 @@ from fastapi import APIRouter, HTTPException from loguru import logger from api.dependencies import PixelleVideoDep -from api.schemas.frame import FrameRenderRequest, FrameRenderResponse +from api.schemas.frame import FrameRenderRequest, FrameRenderResponse, TemplateParamsResponse from pixelle_video.services.frame_html import HTMLFrameGenerator from pixelle_video.utils.template_util import parse_template_size, resolve_template_path @@ -82,3 +82,80 @@ async def render_frame( logger.error(f"Frame render error: {e}") raise HTTPException(status_code=500, detail=str(e)) + +@router.get("/template/params", response_model=TemplateParamsResponse) +async def get_template_params( + template: str +): + """ + Get custom parameters for a template + + Returns the custom parameters defined in the template HTML file. + These parameters can be passed via `template_params` in video generation requests. + + Template parameters are defined using syntax: `{{param_name:type=default}}` + + Supported types: + - `text`: String input + - `number`: Numeric input + - `color`: Color picker (hex format) + - `bool`: Boolean checkbox + + Example template syntax: + ```html +
+ {{custom_text:text=Hello World}} +
+ ``` + + Args: + template: Template path (e.g., '1080x1920/image_default.html') + + Returns: + Template parameters with their types, defaults, and labels + + Example response: + ```json + { + "template": "1080x1920/image_default.html", + "media_width": 1080, + "media_height": 1440, + "params": { + "accent_color": { + "type": "color", + "default": "#ff0000", + "label": "accent_color" + }, + "background": { + "type": "text", + "default": "https://example.com/bg.jpg", + "label": "background" + } + } + } + ``` + """ + try: + logger.info(f"Get template params: {template}") + + # Resolve template path + template_path = resolve_template_path(template) + + # Create generator and parse parameters + generator = HTMLFrameGenerator(template_path) + params = generator.parse_template_parameters() + media_width, media_height = generator.get_media_size() + + return TemplateParamsResponse( + template=template, + media_width=media_width, + media_height=media_height, + params=params + ) + + except FileNotFoundError: + raise HTTPException(status_code=404, detail=f"Template not found: {template}") + except Exception as e: + logger.error(f"Get template params error: {e}") + raise HTTPException(status_code=500, detail=str(e)) + diff --git a/api/routers/video.py b/api/routers/video.py index 952d1b5..d033006 100644 --- a/api/routers/video.py +++ b/api/routers/video.py @@ -151,6 +151,10 @@ async def generate_video_sync( logger.warning("voice_id parameter is deprecated, please use tts_workflow instead") video_params["voice_id"] = request_body.voice_id + # Add custom template parameters if specified + if request_body.template_params: + video_params["template_params"] = request_body.template_params + # Call video generator service result = await pixelle_video.generate_video(**video_params) @@ -252,6 +256,10 @@ async def generate_video_async( logger.warning("voice_id parameter is deprecated, please use tts_workflow instead") video_params["voice_id"] = request_body.voice_id + # Add custom template parameters if specified + if request_body.template_params: + video_params["template_params"] = request_body.template_params + result = await pixelle_video.generate_video(**video_params) # Get file size diff --git a/api/schemas/frame.py b/api/schemas/frame.py index d4f72d6..cf0e771 100644 --- a/api/schemas/frame.py +++ b/api/schemas/frame.py @@ -14,7 +14,7 @@ Frame/Template rendering API schemas """ -from typing import Optional +from typing import Optional, Dict, Any, List from pydantic import BaseModel, Field @@ -47,3 +47,23 @@ class FrameRenderResponse(BaseModel): width: int = Field(..., description="Frame width in pixels") height: int = Field(..., description="Frame height in pixels") + +class TemplateParamConfig(BaseModel): + """Single template parameter configuration""" + type: str = Field(..., description="Parameter type: 'text', 'number', 'color', 'bool'") + default: Any = Field(..., description="Default value") + label: str = Field(..., description="Display label for the parameter") + + +class TemplateParamsResponse(BaseModel): + """Template parameters response""" + success: bool = True + message: str = "Success" + template: str = Field(..., description="Template path") + media_width: int = Field(..., description="Media width from template meta tags") + media_height: int = Field(..., description="Media height from template meta tags") + params: Dict[str, TemplateParamConfig] = Field( + default_factory=dict, + description="Custom parameters defined in template. Key is parameter name, value is config." + ) + diff --git a/api/schemas/video.py b/api/schemas/video.py index 483fd16..426b654 100644 --- a/api/schemas/video.py +++ b/api/schemas/video.py @@ -14,7 +14,7 @@ Video generation API schemas """ -from typing import Optional, Literal +from typing import Optional, Literal, Dict, Any from pydantic import BaseModel, Field @@ -69,6 +69,13 @@ class VideoGenerateRequest(BaseModel): description="HTML template path with size (e.g., '1080x1920/default.html'). Video size is auto-determined from template." ) + # === Template Custom Parameters === + template_params: Optional[Dict[str, Any]] = Field( + None, + description="Custom template parameters (e.g., {'accent_color': '#ff0000', 'background': 'url'}). " + "Available parameters depend on the template. Use GET /api/templates/{template_path}/params to discover them." + ) + # === Image Style === prompt_prefix: Optional[str] = Field(None, description="Image style prefix") @@ -82,7 +89,11 @@ class VideoGenerateRequest(BaseModel): "text": "Atomic Habits teaches us that small changes compound over time to produce remarkable results.", "mode": "generate", "n_scenes": 5, - "voice_id": "[Chinese] zh-CN Yunjian", + "frame_template": "1080x1920/image_default.html", + "template_params": { + "accent_color": "#3498db", + "background": "https://example.com/custom-bg.jpg" + }, "title": "The Power of Atomic Habits" } }