适配webui
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
114
reelforge/utils/web_config.py
Normal file
114
reelforge/utils/web_config.py
Normal 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
48
web.py
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user