适配webui

This commit is contained in:
puke
2025-10-27 20:21:30 +08:00
committed by puke
parent 9937c0fffd
commit f37964507f
5 changed files with 145 additions and 27 deletions

View File

@@ -27,7 +27,7 @@ class StoryboardConfig:
# Image parameters # Image parameters
image_width: int = 1024 image_width: int = 1024
image_height: int = 1024 image_height: int = 1024
image_preset: Optional[str] = None # Image workflow preset (None = use default) image_workflow: Optional[str] = None # Image workflow filename (None = use default)
# Frame template # Frame template
frame_template: Optional[str] = None # HTML template name or path (None = use PIL) frame_template: Optional[str] = None # HTML template name or path (None = use PIL)

View File

@@ -145,7 +145,7 @@ class StoryboardProcessorService:
# Call Image generation (with optional preset) # Call Image generation (with optional preset)
image_url = await self.core.image( image_url = await self.core.image(
prompt=frame.image_prompt, prompt=frame.image_prompt,
preset=config.image_preset, # Pass preset from config (None = use default) workflow=config.image_workflow, # Pass workflow from config (None = use default)
width=config.image_width, width=config.image_width,
height=config.image_height height=config.image_height
) )

View File

@@ -66,7 +66,7 @@ class VideoGeneratorService:
# === Image Parameters === # === Image Parameters ===
image_width: int = 1024, image_width: int = 1024,
image_height: int = 1024, image_height: int = 1024,
image_preset: Optional[str] = None, image_workflow: Optional[str] = None,
# === Video Parameters === # === Video Parameters ===
video_width: int = 1080, video_width: int = 1080,
@@ -121,7 +121,7 @@ class VideoGeneratorService:
image_width: Generated image width (default 1024) image_width: Generated image width (default 1024)
image_height: Generated image height (default 1024) image_height: Generated image height (default 1024)
image_preset: Image workflow preset (e.g., "flux", "sdxl", None = use default) image_workflow: Image workflow filename (e.g., "image_flux.json", None = use default)
video_width: Final video width (default 1080) video_width: Final video width (default 1080)
video_height: Final video height (default 1920) video_height: Final video height (default 1920)
@@ -215,7 +215,7 @@ class VideoGeneratorService:
voice_id=voice_id, voice_id=voice_id,
image_width=image_width, image_width=image_width,
image_height=image_height, image_height=image_height,
image_preset=image_preset, image_workflow=image_workflow,
frame_template=frame_template frame_template=frame_template
) )

View File

@@ -0,0 +1,114 @@
"""
Lightweight configuration utility for Web UI
Simple wrapper around config.yaml without heavy dependencies.
"""
from pathlib import Path
from typing import Dict, Any, Optional
import yaml
from loguru import logger
class WebConfig:
"""Lightweight configuration manager for Web UI"""
def __init__(self, config_path: str = "config.yaml"):
self.config_path = Path(config_path)
self.config: Dict[str, Any] = {}
self.load()
def load(self):
"""Load configuration from file"""
if not self.config_path.exists():
logger.warning(f"Config file not found: {self.config_path}, using default")
self.config = self._create_default_config()
self.save()
else:
try:
with open(self.config_path, "r", encoding="utf-8") as f:
self.config = yaml.safe_load(f) or {}
logger.info(f"Configuration loaded from {self.config_path}")
except Exception as e:
logger.error(f"Failed to load config: {e}")
self.config = self._create_default_config()
def save(self):
"""Save configuration to file"""
try:
with open(self.config_path, "w", encoding="utf-8") as f:
yaml.dump(self.config, f, allow_unicode=True, default_flow_style=False, sort_keys=False)
logger.info(f"Configuration saved to {self.config_path}")
except Exception as e:
logger.error(f"Failed to save config: {e}")
def validate(self) -> bool:
"""
Validate configuration completeness
Returns:
True if required fields are present
"""
# Check LLM configuration (required)
llm_config = self.config.get("llm", {})
if not all([
llm_config.get("api_key"),
llm_config.get("base_url"),
llm_config.get("model")
]):
return False
return True
def get_llm_config(self) -> Dict[str, str]:
"""Get LLM configuration"""
llm = self.config.get("llm", {})
return {
"api_key": llm.get("api_key", ""),
"base_url": llm.get("base_url", ""),
"model": llm.get("model", "")
}
def set_llm_config(self, api_key: str, base_url: str, model: str):
"""Set LLM configuration"""
if "llm" not in self.config:
self.config["llm"] = {}
self.config["llm"]["api_key"] = api_key
self.config["llm"]["base_url"] = base_url
self.config["llm"]["model"] = model
def get_image_config(self) -> Dict[str, Any]:
"""Get image generation configuration"""
return self.config.get("image", {})
def set_image_config(self, comfyui_url: Optional[str] = None, runninghub_api_key: Optional[str] = None):
"""Set image generation configuration"""
if "image" not in self.config:
self.config["image"] = {}
if comfyui_url is not None:
self.config["image"]["comfyui_url"] = comfyui_url
if runninghub_api_key is not None:
self.config["image"]["runninghub_api_key"] = runninghub_api_key
def _create_default_config(self) -> Dict[str, Any]:
"""Create default configuration"""
return {
"project_name": "ReelForge",
"llm": {
"api_key": "",
"base_url": "",
"model": ""
},
"tts": {
"default_workflow": "edge"
},
"image": {
"comfyui_url": "http://127.0.0.1:8188",
"runninghub_api_key": "",
"prompt_prefix": "Pure white background, minimalist illustration, matchstick figure style, black and white line drawing, simple clean lines"
}
}

48
web.py
View File

@@ -14,7 +14,7 @@ from loguru import logger
# Import i18n and config manager # Import i18n and config manager
from reelforge.i18n import load_locales, set_language, tr, get_available_languages from reelforge.i18n import load_locales, set_language, tr, get_available_languages
from reelforge.config_manager import ConfigManager from reelforge.utils.web_config import WebConfig
from reelforge.models.progress import ProgressEvent from reelforge.models.progress import ProgressEvent
# Setup page config (must be first) # Setup page config (must be first)
@@ -48,10 +48,8 @@ def safe_rerun():
# ============================================================================ # ============================================================================
def get_config_manager(): def get_config_manager():
"""Get ConfigManager instance (no caching - always fresh)""" """Get WebConfig instance (no caching - always fresh)"""
manager = ConfigManager() return WebConfig()
manager.load_or_create_default()
return manager
def init_i18n(): def init_i18n():
@@ -129,7 +127,7 @@ def init_session_state():
# System Configuration (Required) # System Configuration (Required)
# ============================================================================ # ============================================================================
def render_advanced_settings(config_manager: ConfigManager): def render_advanced_settings(config_manager: WebConfig):
"""Render system configuration (required) with 2-column layout""" """Render system configuration (required) with 2-column layout"""
# Check if system is configured # Check if system is configured
is_configured = config_manager.validate() is_configured = config_manager.validate()
@@ -237,8 +235,8 @@ def render_advanced_settings(config_manager: ConfigManager):
with st.container(border=True): with st.container(border=True):
st.markdown(f"**{tr('settings.image.title')}**") st.markdown(f"**{tr('settings.image.title')}**")
# Get current configuration (flat structure) # Get current configuration
image_config = config_manager.config.get("image", {}) image_config = config_manager.get_image_config()
# Local/Self-hosted ComfyUI configuration # Local/Self-hosted ComfyUI configuration
st.markdown(f"**{tr('settings.image.local_title')}**") st.markdown(f"**{tr('settings.image.local_title')}**")
@@ -282,16 +280,15 @@ def render_advanced_settings(config_manager: ConfigManager):
with col1: with col1:
if st.button(tr("btn.save_config"), use_container_width=True, key="save_config_btn"): if st.button(tr("btn.save_config"), use_container_width=True, key="save_config_btn"):
try: try:
# Save LLM configuration (simple 3-field format) # Save LLM configuration
if llm_api_key and llm_base_url and llm_model: if llm_api_key and llm_base_url and llm_model:
config_manager.set_llm_config(llm_api_key, llm_base_url, llm_model) config_manager.set_llm_config(llm_api_key, llm_base_url, llm_model)
# Save Image configuration (flat structure) # Save Image configuration
config_manager.config["image"]["default"] = "default" config_manager.set_image_config(
if comfyui_url: comfyui_url=comfyui_url if comfyui_url else None,
config_manager.config["image"]["comfyui_url"] = comfyui_url runninghub_api_key=runninghub_api_key if runninghub_api_key else None
if runninghub_api_key: )
config_manager.config["image"]["runninghub_api_key"] = runninghub_api_key
# Save to file # Save to file
config_manager.save() config_manager.save()
@@ -303,7 +300,17 @@ def render_advanced_settings(config_manager: ConfigManager):
with col2: with col2:
if st.button(tr("btn.reset_config"), use_container_width=True, key="reset_config_btn"): if st.button(tr("btn.reset_config"), use_container_width=True, key="reset_config_btn"):
config_manager.config = config_manager._create_default_config() # Reset to default by creating new config
config_manager.config = {
"project_name": "ReelForge",
"llm": {"api_key": "", "base_url": "", "model": ""},
"tts": {"default_workflow": "edge"},
"image": {
"comfyui_url": "http://127.0.0.1:8188",
"runninghub_api_key": "",
"prompt_prefix": "Pure white background, minimalist illustration, matchstick figure style, black and white line drawing, simple clean lines"
}
}
config_manager.save() config_manager.save()
st.success(tr("status.config_reset")) st.success(tr("status.config_reset"))
safe_rerun() safe_rerun()
@@ -539,18 +546,15 @@ def main():
workflow_files if workflow_files else ["image_default.json"], workflow_files if workflow_files else ["image_default.json"],
index=default_workflow_index, index=default_workflow_index,
label_visibility="collapsed", label_visibility="collapsed",
key="image_preset_select" key="image_workflow_select"
) )
# Extract preset name from filename: "image_default.json" -> "default"
image_preset = workflow_filename.replace("image_", "").replace(".json", "") if workflow_filename else None
# 2. Prompt prefix input # 2. Prompt prefix input
st.caption(tr("style.prompt_prefix")) st.caption(tr("style.prompt_prefix"))
# Get current prompt_prefix from config # Get current prompt_prefix from config
image_config = config_manager.config.get("image", {}) image_config = config_manager.get_image_config()
current_prefix = image_config.get("prompt_prefix", "") current_prefix = image_config.get("prompt_prefix", "")
# Prompt prefix input (temporary, not saved to config) # Prompt prefix input (temporary, not saved to config)
@@ -687,7 +691,7 @@ def main():
title=title if title else None, title=title if title else None,
n_scenes=n_scenes, n_scenes=n_scenes,
voice_id=voice_id, voice_id=voice_id,
image_preset=image_preset, # Pass image_preset image_workflow=workflow_filename, # Pass image workflow filename
frame_template=frame_template, frame_template=frame_template,
prompt_prefix=prompt_prefix, # Pass prompt_prefix prompt_prefix=prompt_prefix, # Pass prompt_prefix
bgm_path=bgm_path, bgm_path=bgm_path,