支持视频生成时插图没必填,大幅提升视频生成速度
This commit is contained in:
302
web/app.py
302
web/app.py
@@ -636,145 +636,6 @@ def main():
|
||||
st.error(tr("tts.preview_failed", error=str(e)))
|
||||
logger.exception(e)
|
||||
|
||||
# ====================================================================
|
||||
# Image Generation Section
|
||||
# ====================================================================
|
||||
with st.container(border=True):
|
||||
st.markdown(f"**{tr('section.image')}**")
|
||||
|
||||
# 1. ComfyUI Workflow selection
|
||||
with st.expander(tr("help.feature_description"), expanded=False):
|
||||
st.markdown(f"**{tr('help.what')}**")
|
||||
st.markdown(tr("style.workflow_what"))
|
||||
st.markdown(f"**{tr('help.how')}**")
|
||||
st.markdown(tr("style.workflow_how"))
|
||||
st.markdown(f"**{tr('help.note')}**")
|
||||
st.markdown(tr("style.image_size_note"))
|
||||
|
||||
# Get available workflows from pixelle_video (with source info)
|
||||
workflows = pixelle_video.image.list_workflows()
|
||||
|
||||
# Build options for selectbox
|
||||
# Display: "image_flux.json - Runninghub"
|
||||
# Value: "runninghub/image_flux.json"
|
||||
workflow_options = [wf["display_name"] for wf in workflows]
|
||||
workflow_keys = [wf["key"] for wf in workflows]
|
||||
|
||||
# Default to first option (should be runninghub by sorting)
|
||||
default_workflow_index = 0
|
||||
|
||||
# If user has a saved preference in config, try to match it
|
||||
comfyui_config = config_manager.get_comfyui_config()
|
||||
saved_workflow = comfyui_config["image"]["default_workflow"]
|
||||
if saved_workflow and saved_workflow in workflow_keys:
|
||||
default_workflow_index = workflow_keys.index(saved_workflow)
|
||||
|
||||
workflow_display = st.selectbox(
|
||||
"Workflow",
|
||||
workflow_options if workflow_options else ["No workflows found"],
|
||||
index=default_workflow_index,
|
||||
label_visibility="collapsed",
|
||||
key="image_workflow_select"
|
||||
)
|
||||
|
||||
# Get the actual workflow key (e.g., "runninghub/image_flux.json")
|
||||
if workflow_options:
|
||||
workflow_selected_index = workflow_options.index(workflow_display)
|
||||
workflow_key = workflow_keys[workflow_selected_index]
|
||||
else:
|
||||
workflow_key = "runninghub/image_flux.json" # fallback
|
||||
|
||||
|
||||
# 2. Image size input
|
||||
col1, col2 = st.columns(2)
|
||||
with col1:
|
||||
image_width = st.number_input(
|
||||
tr('style.image_width'),
|
||||
min_value=128,
|
||||
value=1024,
|
||||
step=1,
|
||||
label_visibility="visible",
|
||||
help=tr('style.image_width_help')
|
||||
)
|
||||
with col2:
|
||||
image_height = st.number_input(
|
||||
tr('style.image_height'),
|
||||
min_value=128,
|
||||
value=1024,
|
||||
step=1,
|
||||
label_visibility="visible",
|
||||
help=tr('style.image_height_help')
|
||||
)
|
||||
|
||||
# 3. Prompt prefix input
|
||||
# Get current prompt_prefix from config
|
||||
current_prefix = comfyui_config["image"]["prompt_prefix"]
|
||||
|
||||
# Prompt prefix input (temporary, not saved to config)
|
||||
prompt_prefix = st.text_area(
|
||||
tr('style.prompt_prefix'),
|
||||
value=current_prefix,
|
||||
placeholder=tr("style.prompt_prefix_placeholder"),
|
||||
height=80,
|
||||
label_visibility="visible",
|
||||
help=tr("style.prompt_prefix_help")
|
||||
)
|
||||
|
||||
# Style preview expander (similar to template preview)
|
||||
with st.expander(tr("style.preview_title"), expanded=False):
|
||||
# Test prompt input
|
||||
test_prompt = st.text_input(
|
||||
tr("style.test_prompt"),
|
||||
value="a dog",
|
||||
help=tr("style.test_prompt_help"),
|
||||
key="style_test_prompt"
|
||||
)
|
||||
|
||||
# Preview button
|
||||
if st.button(tr("style.preview"), key="preview_style", use_container_width=True):
|
||||
with st.spinner(tr("style.previewing")):
|
||||
try:
|
||||
from pixelle_video.utils.prompt_helper import build_image_prompt
|
||||
|
||||
# Build final prompt with prefix
|
||||
final_prompt = build_image_prompt(test_prompt, prompt_prefix)
|
||||
|
||||
# Generate preview image (use user-specified size)
|
||||
preview_image_path = run_async(pixelle_video.image(
|
||||
prompt=final_prompt,
|
||||
workflow=workflow_key,
|
||||
width=int(image_width),
|
||||
height=int(image_height)
|
||||
))
|
||||
|
||||
# Display preview (support both URL and local path)
|
||||
if preview_image_path:
|
||||
st.success(tr("style.preview_success"))
|
||||
|
||||
# Read and encode image
|
||||
if preview_image_path.startswith('http'):
|
||||
# URL - use directly
|
||||
img_html = f'<div class="preview-image"><img src="{preview_image_path}" alt="Style Preview"/></div>'
|
||||
else:
|
||||
# Local file - encode as base64
|
||||
with open(preview_image_path, 'rb') as f:
|
||||
img_data = base64.b64encode(f.read()).decode()
|
||||
img_html = f'<div class="preview-image"><img src="data:image/png;base64,{img_data}" alt="Style Preview"/></div>'
|
||||
|
||||
st.markdown(img_html, unsafe_allow_html=True)
|
||||
|
||||
# Show the final prompt used
|
||||
st.info(f"**{tr('style.final_prompt_label')}**\n{final_prompt}")
|
||||
|
||||
# Show file path
|
||||
st.caption(f"📁 {preview_image_path}")
|
||||
else:
|
||||
st.error(tr("style.preview_failed_general"))
|
||||
except Exception as e:
|
||||
st.error(tr("style.preview_failed", error=str(e)))
|
||||
logger.exception(e)
|
||||
|
||||
|
||||
# ====================================================================
|
||||
# Storyboard Template Section
|
||||
# ====================================================================
|
||||
@@ -866,6 +727,11 @@ def main():
|
||||
generator_for_params = HTMLFrameGenerator(template_path_for_params)
|
||||
custom_params_for_video = generator_for_params.parse_template_parameters()
|
||||
|
||||
# Detect if template requires image generation
|
||||
template_requires_image = generator_for_params.requires_image()
|
||||
# Store in session state for Image Section to read
|
||||
st.session_state['template_requires_image'] = template_requires_image
|
||||
|
||||
custom_values_for_video = {}
|
||||
if custom_params_for_video:
|
||||
st.markdown("📝 " + tr("template.custom_parameters"))
|
||||
@@ -1004,7 +870,163 @@ def main():
|
||||
except Exception as e:
|
||||
st.error(tr("template.preview_failed", error=str(e)))
|
||||
logger.exception(e)
|
||||
|
||||
|
||||
# ====================================================================
|
||||
# Image Generation Section (conditional based on template)
|
||||
# ====================================================================
|
||||
# Check if current template requires image generation
|
||||
if st.session_state.get('template_requires_image', True):
|
||||
# Template requires images - show full Image Section
|
||||
with st.container(border=True):
|
||||
st.markdown(f"**{tr('section.image')}**")
|
||||
|
||||
# 1. ComfyUI Workflow selection
|
||||
with st.expander(tr("help.feature_description"), expanded=False):
|
||||
st.markdown(f"**{tr('help.what')}**")
|
||||
st.markdown(tr("style.workflow_what"))
|
||||
st.markdown(f"**{tr('help.how')}**")
|
||||
st.markdown(tr("style.workflow_how"))
|
||||
st.markdown(f"**{tr('help.note')}**")
|
||||
st.markdown(tr("style.image_size_note"))
|
||||
|
||||
# Get available workflows from pixelle_video (with source info)
|
||||
workflows = pixelle_video.image.list_workflows()
|
||||
|
||||
# Build options for selectbox
|
||||
# Display: "image_flux.json - Runninghub"
|
||||
# Value: "runninghub/image_flux.json"
|
||||
workflow_options = [wf["display_name"] for wf in workflows]
|
||||
workflow_keys = [wf["key"] for wf in workflows]
|
||||
|
||||
# Default to first option (should be runninghub by sorting)
|
||||
default_workflow_index = 0
|
||||
|
||||
# If user has a saved preference in config, try to match it
|
||||
comfyui_config = config_manager.get_comfyui_config()
|
||||
saved_workflow = comfyui_config["image"]["default_workflow"]
|
||||
if saved_workflow and saved_workflow in workflow_keys:
|
||||
default_workflow_index = workflow_keys.index(saved_workflow)
|
||||
|
||||
workflow_display = st.selectbox(
|
||||
"Workflow",
|
||||
workflow_options if workflow_options else ["No workflows found"],
|
||||
index=default_workflow_index,
|
||||
label_visibility="collapsed",
|
||||
key="image_workflow_select"
|
||||
)
|
||||
|
||||
# Get the actual workflow key (e.g., "runninghub/image_flux.json")
|
||||
if workflow_options:
|
||||
workflow_selected_index = workflow_options.index(workflow_display)
|
||||
workflow_key = workflow_keys[workflow_selected_index]
|
||||
else:
|
||||
workflow_key = "runninghub/image_flux.json" # fallback
|
||||
|
||||
|
||||
# 2. Image size input
|
||||
col1, col2 = st.columns(2)
|
||||
with col1:
|
||||
image_width = st.number_input(
|
||||
tr('style.image_width'),
|
||||
min_value=128,
|
||||
value=1024,
|
||||
step=1,
|
||||
label_visibility="visible",
|
||||
help=tr('style.image_width_help')
|
||||
)
|
||||
with col2:
|
||||
image_height = st.number_input(
|
||||
tr('style.image_height'),
|
||||
min_value=128,
|
||||
value=1024,
|
||||
step=1,
|
||||
label_visibility="visible",
|
||||
help=tr('style.image_height_help')
|
||||
)
|
||||
|
||||
# 3. Prompt prefix input
|
||||
# Get current prompt_prefix from config
|
||||
current_prefix = comfyui_config["image"]["prompt_prefix"]
|
||||
|
||||
# Prompt prefix input (temporary, not saved to config)
|
||||
prompt_prefix = st.text_area(
|
||||
tr('style.prompt_prefix'),
|
||||
value=current_prefix,
|
||||
placeholder=tr("style.prompt_prefix_placeholder"),
|
||||
height=80,
|
||||
label_visibility="visible",
|
||||
help=tr("style.prompt_prefix_help")
|
||||
)
|
||||
|
||||
# Style preview expander (similar to template preview)
|
||||
with st.expander(tr("style.preview_title"), expanded=False):
|
||||
# Test prompt input
|
||||
test_prompt = st.text_input(
|
||||
tr("style.test_prompt"),
|
||||
value="a dog",
|
||||
help=tr("style.test_prompt_help"),
|
||||
key="style_test_prompt"
|
||||
)
|
||||
|
||||
# Preview button
|
||||
if st.button(tr("style.preview"), key="preview_style", use_container_width=True):
|
||||
with st.spinner(tr("style.previewing")):
|
||||
try:
|
||||
from pixelle_video.utils.prompt_helper import build_image_prompt
|
||||
|
||||
# Build final prompt with prefix
|
||||
final_prompt = build_image_prompt(test_prompt, prompt_prefix)
|
||||
|
||||
# Generate preview image (use user-specified size)
|
||||
preview_image_path = run_async(pixelle_video.image(
|
||||
prompt=final_prompt,
|
||||
workflow=workflow_key,
|
||||
width=int(image_width),
|
||||
height=int(image_height)
|
||||
))
|
||||
|
||||
# Display preview (support both URL and local path)
|
||||
if preview_image_path:
|
||||
st.success(tr("style.preview_success"))
|
||||
|
||||
# Read and encode image
|
||||
if preview_image_path.startswith('http'):
|
||||
# URL - use directly
|
||||
img_html = f'<div class="preview-image"><img src="{preview_image_path}" alt="Style Preview"/></div>'
|
||||
else:
|
||||
# Local file - encode as base64
|
||||
with open(preview_image_path, 'rb') as f:
|
||||
img_data = base64.b64encode(f.read()).decode()
|
||||
img_html = f'<div class="preview-image"><img src="data:image/png;base64,{img_data}" alt="Style Preview"/></div>'
|
||||
|
||||
st.markdown(img_html, unsafe_allow_html=True)
|
||||
|
||||
# Show the final prompt used
|
||||
st.info(f"**{tr('style.final_prompt_label')}**\n{final_prompt}")
|
||||
|
||||
# Show file path
|
||||
st.caption(f"📁 {preview_image_path}")
|
||||
else:
|
||||
st.error(tr("style.preview_failed_general"))
|
||||
except Exception as e:
|
||||
st.error(tr("style.preview_failed", error=str(e)))
|
||||
logger.exception(e)
|
||||
|
||||
|
||||
else:
|
||||
# Template doesn't need images - show simplified message
|
||||
with st.container(border=True):
|
||||
st.markdown(f"**{tr('section.image')}**")
|
||||
st.info("ℹ️ " + tr("image.not_required"))
|
||||
st.caption(tr("image.not_required_hint"))
|
||||
|
||||
# Set default values for later use
|
||||
workflow_key = None
|
||||
image_width = 1024
|
||||
image_height = 1024
|
||||
prompt_prefix = ""
|
||||
|
||||
|
||||
# ========================================================================
|
||||
# Right Column: Generate Button + Progress + Video Preview
|
||||
# ========================================================================
|
||||
|
||||
@@ -102,6 +102,9 @@
|
||||
"template.preview_caption": "Template Preview: {template}",
|
||||
"template.custom_parameters": "Custom Parameters",
|
||||
|
||||
"image.not_required": "Current template does not require image generation",
|
||||
"image.not_required_hint": "The selected template is text-only and does not need images. Benefits: ⚡ Faster generation 💰 Lower cost",
|
||||
|
||||
"video.title": "🎬 Video Settings",
|
||||
"video.frames": "Scenes",
|
||||
"video.frames_help": "More scenes = longer video",
|
||||
|
||||
@@ -102,6 +102,9 @@
|
||||
"template.preview_caption": "模板预览:{template}",
|
||||
"template.custom_parameters": "自定义参数",
|
||||
|
||||
"image.not_required": "当前模板不需要插图生成",
|
||||
"image.not_required_hint": "您选择的模板是纯文本模板,无需生成图片。这将:⚡ 加快生成速度 💰 降低生成成本",
|
||||
|
||||
"video.title": "🎬 视频设置",
|
||||
"video.frames": "分镜数",
|
||||
"video.frames_help": "更多分镜 = 更长视频",
|
||||
|
||||
Reference in New Issue
Block a user