显示具体的模板尺寸
This commit is contained in:
@@ -4,7 +4,8 @@ Template utility functions for size parsing and template management
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import List, Tuple, Optional
|
||||
from typing import List, Tuple, Optional, Literal
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
def parse_template_size(template_path: str) -> Tuple[int, int]:
|
||||
@@ -154,6 +155,113 @@ def get_template_full_path(size: str, template_name: str) -> str:
|
||||
return str(template_path)
|
||||
|
||||
|
||||
class TemplateDisplayInfo(BaseModel):
|
||||
"""Template display information for UI layer"""
|
||||
|
||||
name: str = Field(..., description="Template name without extension")
|
||||
size: str = Field(..., description="Size string like '1080x1920'")
|
||||
width: int = Field(..., description="Width in pixels")
|
||||
height: int = Field(..., description="Height in pixels")
|
||||
orientation: Literal['portrait', 'landscape', 'square'] = Field(
|
||||
...,
|
||||
description="Video orientation"
|
||||
)
|
||||
is_standard: bool = Field(
|
||||
...,
|
||||
description="True only for standard sizes: 1080x1920, 1920x1080, 1080x1080"
|
||||
)
|
||||
|
||||
|
||||
class TemplateInfo(BaseModel):
|
||||
"""Complete template information with path and display info"""
|
||||
|
||||
template_path: str = Field(..., description="Full template path like '1080x1920/default.html'")
|
||||
display_info: TemplateDisplayInfo = Field(..., description="Display information")
|
||||
|
||||
|
||||
def format_template_display_info(template_name: str, size: str) -> TemplateDisplayInfo:
|
||||
"""
|
||||
Format template display information for UI
|
||||
|
||||
Returns structured data for UI layer to handle display and i18n.
|
||||
|
||||
Args:
|
||||
template_name: Template filename like "default.html"
|
||||
size: Size string like "1080x1920"
|
||||
|
||||
Returns:
|
||||
TemplateDisplayInfo object with name, size, dimensions, orientation, and standard flag
|
||||
|
||||
Examples:
|
||||
>>> info = format_template_display_info("default.html", "1080x1920")
|
||||
>>> info.name
|
||||
'default'
|
||||
>>> info.is_standard
|
||||
True
|
||||
|
||||
>>> info = format_template_display_info("custom.html", "1080x1921")
|
||||
>>> info.orientation
|
||||
'portrait'
|
||||
>>> info.is_standard
|
||||
False
|
||||
"""
|
||||
# Keep full template name with .html extension
|
||||
name = template_name
|
||||
|
||||
# Parse size
|
||||
width, height = map(int, size.split('x'))
|
||||
|
||||
# Detect orientation
|
||||
if height > width:
|
||||
orientation = 'portrait'
|
||||
elif width > height:
|
||||
orientation = 'landscape'
|
||||
else:
|
||||
orientation = 'square'
|
||||
|
||||
# Check if it's a standard size (only these three)
|
||||
is_standard = (width, height) in [(1080, 1920), (1920, 1080), (1080, 1080)]
|
||||
|
||||
return TemplateDisplayInfo(
|
||||
name=name,
|
||||
size=size,
|
||||
width=width,
|
||||
height=height,
|
||||
orientation=orientation,
|
||||
is_standard=is_standard
|
||||
)
|
||||
|
||||
|
||||
def get_all_templates_with_info() -> List[TemplateInfo]:
|
||||
"""
|
||||
Get all templates with their display information
|
||||
|
||||
Returns:
|
||||
List of TemplateInfo objects
|
||||
|
||||
Example:
|
||||
>>> templates = get_all_templates_with_info()
|
||||
>>> for t in templates:
|
||||
... print(f"{t.display_info.name} - {t.display_info.orientation}")
|
||||
... print(f" Path: {t.template_path}")
|
||||
... print(f" Standard: {t.display_info.is_standard}")
|
||||
"""
|
||||
result = []
|
||||
sizes = list_available_sizes()
|
||||
|
||||
for size in sizes:
|
||||
templates = list_templates_for_size(size)
|
||||
for template in templates:
|
||||
display_info = format_template_display_info(template, size)
|
||||
full_path = f"{size}/{template}"
|
||||
result.append(TemplateInfo(
|
||||
template_path=full_path,
|
||||
display_info=display_info
|
||||
))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def resolve_template_path(template_input: Optional[str]) -> str:
|
||||
"""
|
||||
Resolve template input to full path with validation
|
||||
|
||||
69
web/app.py
69
web/app.py
@@ -667,47 +667,52 @@ def main():
|
||||
st.markdown(tr("template.how"))
|
||||
|
||||
# Import template utilities
|
||||
from pixelle_video.utils.template_util import list_available_sizes, list_templates_for_size
|
||||
from pixelle_video.utils.template_util import get_all_templates_with_info
|
||||
|
||||
# Step 1: Select video size
|
||||
VIDEO_SIZE_OPTIONS = {
|
||||
"📱 竖屏视频 (1080×1920)": "1080x1920",
|
||||
"🖥 横屏视频 (1920×1080)": "1920x1080",
|
||||
"⬜ 方形视频 (1080×1080)": "1080x1080",
|
||||
}
|
||||
# Get all templates with their info
|
||||
all_templates = get_all_templates_with_info()
|
||||
|
||||
# Filter available sizes (only show sizes that exist)
|
||||
available_sizes = list_available_sizes()
|
||||
available_size_options = {k: v for k, v in VIDEO_SIZE_OPTIONS.items() if v in available_sizes}
|
||||
|
||||
if not available_size_options:
|
||||
st.error("No template sizes found. Please ensure templates are in correct directory structure.")
|
||||
if not all_templates:
|
||||
st.error("No templates found. Please ensure templates are in templates/ directory with proper structure (e.g., templates/1080x1920/default.html).")
|
||||
st.stop()
|
||||
|
||||
selected_size_label = st.selectbox(
|
||||
tr("template.video_size"),
|
||||
list(available_size_options.keys()),
|
||||
label_visibility="collapsed"
|
||||
)
|
||||
selected_size = available_size_options[selected_size_label]
|
||||
# Build display names with i18n
|
||||
ORIENTATION_I18N = {
|
||||
'portrait': tr('orientation.portrait'),
|
||||
'landscape': tr('orientation.landscape'),
|
||||
'square': tr('orientation.square')
|
||||
}
|
||||
|
||||
# Step 2: Select template for the chosen size
|
||||
template_files = list_templates_for_size(selected_size)
|
||||
display_options = {}
|
||||
for item in all_templates:
|
||||
info = item.display_info
|
||||
name = info.name
|
||||
orientation = ORIENTATION_I18N.get(info.orientation, info.orientation)
|
||||
|
||||
# Always show dimensions for standardization
|
||||
display_name = f"{name} - {orientation}({info.width}×{info.height})"
|
||||
|
||||
display_options[display_name] = item.template_path
|
||||
|
||||
# Default to default.html if exists, otherwise first option
|
||||
default_template_index = 0
|
||||
if "default.html" in template_files:
|
||||
default_template_index = template_files.index("default.html")
|
||||
# Default to "default" portrait if exists
|
||||
display_names = list(display_options.keys())
|
||||
default_index = 0
|
||||
for idx, name in enumerate(display_names):
|
||||
if "default" in name.lower() and tr('orientation.portrait') in name:
|
||||
default_index = idx
|
||||
break
|
||||
|
||||
template_name = st.selectbox(
|
||||
tr("template.style"),
|
||||
template_files if template_files else ["default.html"],
|
||||
index=default_template_index,
|
||||
label_visibility="collapsed"
|
||||
# Single dropdown with formatted names
|
||||
selected_display_name = st.selectbox(
|
||||
tr("template.select"),
|
||||
display_names,
|
||||
index=default_index,
|
||||
label_visibility="collapsed",
|
||||
help=tr("template.select_help")
|
||||
)
|
||||
|
||||
# Combine size and template name to get full path
|
||||
frame_template = f"{selected_size}/{template_name}"
|
||||
# Get full template path
|
||||
frame_template = display_options[selected_display_name]
|
||||
|
||||
# Template preview expander
|
||||
with st.expander(tr("template.preview_title"), expanded=False):
|
||||
|
||||
@@ -66,11 +66,18 @@
|
||||
"style.generated_prompt": "Generated prompt: {prompt}",
|
||||
|
||||
"template.selector": "Template Selection",
|
||||
"template.select": "Select Template",
|
||||
"template.select_help": "Select template and video size",
|
||||
"template.default": "Default",
|
||||
"template.modern": "Modern",
|
||||
"template.neon": "Neon",
|
||||
"template.what": "Controls the visual layout and design style of each frame (title, text, image arrangement)",
|
||||
"template.how": "Place .html template files in the templates/ folder for automatic detection. Supports custom CSS styles",
|
||||
"template.size_info": "Template Size",
|
||||
|
||||
"orientation.portrait": "Portrait",
|
||||
"orientation.landscape": "Landscape",
|
||||
"orientation.square": "Square",
|
||||
"template.preview_title": "Preview Template",
|
||||
"template.preview_param_title": "Title",
|
||||
"template.preview_param_text": "Text",
|
||||
|
||||
@@ -66,11 +66,18 @@
|
||||
"style.generated_prompt": "生成的提示词:{prompt}",
|
||||
|
||||
"template.selector": "模板选择",
|
||||
"template.select": "选择模板",
|
||||
"template.select_help": "选择模板和视频尺寸",
|
||||
"template.default": "默认",
|
||||
"template.modern": "现代",
|
||||
"template.neon": "霓虹",
|
||||
"template.what": "控制视频每一帧的视觉布局和设计风格(标题、文本、图片的排版样式)",
|
||||
"template.how": "将 .html 模板文件放入 templates/ 文件夹即可自动识别。支持自定义 CSS 样式",
|
||||
"template.size_info": "模板尺寸",
|
||||
|
||||
"orientation.portrait": "竖屏",
|
||||
"orientation.landscape": "横屏",
|
||||
"orientation.square": "方形",
|
||||
"template.preview_title": "预览模板",
|
||||
"template.preview_param_title": "标题",
|
||||
"template.preview_param_text": "文本",
|
||||
|
||||
Reference in New Issue
Block a user