chore: Merge upstream/main with RunningHub 48G support and FAQ improvements

This commit is contained in:
empty
2026-01-06 17:48:02 +08:00
12 changed files with 1828 additions and 2138 deletions

View File

@@ -31,22 +31,17 @@ https://github.com/user-attachments/assets/a42e7457-fcc8-40da-83fc-784c45a8b95d
![Web UI界面](resources/webui.png) ![Web UI界面](resources/webui.png)
## 📋 更新日志 ## 📋 最近更新
### 2025-12-04 -**2026-01-06**: 新增 RunningHub 48G 显存机器调用支持
-**2025-12-28**: 支持 RunningHub 并发限制可配置,优化 LLM 返回结构化数据的逻辑
- 🎨 **新增「自定义素材」功能** - 支持用户上传自己的照片和视频: - **2025-12-17**: 支持 ComfyUI API Key 配置,支持 Nano Banana 模型调用API 接口支持模板自定义参数
- 📸 **智能图片分析**: AI 自动识别图片内容,生成精准描述 - **2025-12-10**: 侧边栏内置 FAQ锁定 edge-tts 版本修复 TTS 服务不稳定问题
- 🎥 **视频理解能力**: 支持视频素材分析,理解视频中的场景和内容 - **2025-12-08**: 支持固定脚本多种分割方式(段落/行/句子),优化模板选择交互逻辑支持直接预览选择
- ✍️ **智能脚本生成**: 基于素材内容和用户意图,自动生成视频文案和旁白 - **2025-12-06**: 修复视频生成 API 返回 URL 路径处理,支持跨平台兼容
- 🎬 **一键成片**: 将你的照片/视频素材,快速制作成带文案和配音的完整视频 - **2025-12-05**: 新增 Windows 整合包下载,优化图片与视频反推工作流
- 💡 降低创作门槛,让没有素材的用户也能轻松制作专业视频 - **2025-12-04**: 新增「自定义素材」功能支持用户上传自己的照片和视频AI 智能分析生成脚本
-**2025-11-18**: 优化 RunningHub 服务调用支持并行处理,新增历史记录页面,支持批量创建视频任务
### 2025-11-18
- 优化 RunningHub 服务调用,支持并行处理,大幅提升生成速度
- 新增历史记录页面,可查看和管理所有生成过的视频
- 支持一次性创建多个视频任务,提高批量创作效率
## ✨ 功能亮点 ## ✨ 功能亮点

View File

@@ -30,22 +30,17 @@ Just input a **topic**, and Pixelle-Video will automatically:
![Web UI Interface](resources/webui_en.png) ![Web UI Interface](resources/webui_en.png)
## 📋 Changelog ## 📋 Recent Updates
### 2025-12-04 -**2026-01-06**: Added RunningHub 48G VRAM machine support
-**2025-12-28**: Configurable RunningHub concurrency limit, improved LLM structured data response handling
- 🎨 **New "Custom Media" Feature** - Support uploading your own photos and videos: - **2025-12-17**: Added ComfyUI API Key configuration, Nano Banana model support, API template custom parameters
- 📸 **Smart Image Analysis**: AI automatically recognizes image content and generates accurate descriptions - **2025-12-10**: Built-in FAQ in sidebar, fixed edge-tts version to resolve TTS service instability
- 🎥 **Video Understanding**: Supports video asset analysis to understand scenes and content - **2025-12-08**: Support multiple script split modes (paragraph/line/sentence), improved template selection with direct preview
- ✍️ **Intelligent Script Generation**: Auto-generates video scripts and narration based on asset content and user intent - **2025-12-06**: Fixed video generation API URL path handling with cross-platform compatibility
- 🎬 **One-Click Production**: Transform your photos/videos into complete videos with scripts and voiceover - **2025-12-05**: Added Windows all-in-one package download, optimized image and video analysis workflows
- 💡 Lower the creative barrier for users without existing media assets - **2025-12-04**: New "Custom Media" feature - upload your photos/videos with AI-powered analysis and script generation
-**2025-11-18**: Parallel processing for RunningHub, added history page, batch video task creation support
### 2025-11-18
- Optimized RunningHub service calls with parallel processing for significantly faster speed
- Added history page to view and manage all generated videos
- Support creating multiple video tasks at once for efficient batch production
## ✨ Key Features ## ✨ Key Features

View File

@@ -131,6 +131,7 @@ class ConfigManager:
"comfyui_api_key": self.config.comfyui.comfyui_api_key, "comfyui_api_key": self.config.comfyui.comfyui_api_key,
"runninghub_api_key": self.config.comfyui.runninghub_api_key, "runninghub_api_key": self.config.comfyui.runninghub_api_key,
"runninghub_concurrent_limit": self.config.comfyui.runninghub_concurrent_limit, "runninghub_concurrent_limit": self.config.comfyui.runninghub_concurrent_limit,
"runninghub_instance_type": self.config.comfyui.runninghub_instance_type,
"tts": { "tts": {
"default_workflow": self.config.comfyui.tts.default_workflow, "default_workflow": self.config.comfyui.tts.default_workflow,
}, },
@@ -149,7 +150,8 @@ class ConfigManager:
comfyui_url: Optional[str] = None, comfyui_url: Optional[str] = None,
comfyui_api_key: Optional[str] = None, comfyui_api_key: Optional[str] = None,
runninghub_api_key: Optional[str] = None, runninghub_api_key: Optional[str] = None,
runninghub_concurrent_limit: Optional[int] = None runninghub_concurrent_limit: Optional[int] = None,
runninghub_instance_type: Optional[str] = None
): ):
"""Set ComfyUI global configuration""" """Set ComfyUI global configuration"""
updates = {} updates = {}
@@ -161,6 +163,9 @@ class ConfigManager:
updates["runninghub_api_key"] = runninghub_api_key updates["runninghub_api_key"] = runninghub_api_key
if runninghub_concurrent_limit is not None: if runninghub_concurrent_limit is not None:
updates["runninghub_concurrent_limit"] = runninghub_concurrent_limit updates["runninghub_concurrent_limit"] = runninghub_concurrent_limit
if runninghub_instance_type is not None:
# Empty string means disable (treat as None for storage)
updates["runninghub_instance_type"] = runninghub_instance_type if runninghub_instance_type else None
if updates: if updates:
self.update({"comfyui": updates}) self.update({"comfyui": updates})

View File

@@ -74,6 +74,7 @@ class ComfyUIConfig(BaseModel):
comfyui_api_key: Optional[str] = Field(default=None, description="ComfyUI API Key (optional)") comfyui_api_key: Optional[str] = Field(default=None, description="ComfyUI API Key (optional)")
runninghub_api_key: Optional[str] = Field(default=None, description="RunningHub API Key (optional)") runninghub_api_key: Optional[str] = Field(default=None, description="RunningHub API Key (optional)")
runninghub_concurrent_limit: int = Field(default=1, ge=1, le=10, description="RunningHub concurrent execution limit (1-10)") runninghub_concurrent_limit: int = Field(default=1, ge=1, le=10, description="RunningHub concurrent execution limit (1-10)")
runninghub_instance_type: Optional[str] = Field(default=None, description="RunningHub instance type (optional, set to 'plus' for 48GB VRAM)")
tts: TTSSubConfig = Field(default_factory=TTSSubConfig, description="TTS-specific configuration") tts: TTSSubConfig = Field(default_factory=TTSSubConfig, description="TTS-specific configuration")
image: ImageSubConfig = Field(default_factory=ImageSubConfig, description="Image-specific configuration") image: ImageSubConfig = Field(default_factory=ImageSubConfig, description="Image-specific configuration")
video: VideoSubConfig = Field(default_factory=VideoSubConfig, description="Video-specific configuration") video: VideoSubConfig = Field(default_factory=VideoSubConfig, description="Video-specific configuration")

View File

@@ -120,6 +120,10 @@ class PixelleVideoCore:
kit_config["api_key"] = comfyui_config["comfyui_api_key"] kit_config["api_key"] = comfyui_config["comfyui_api_key"]
if comfyui_config.get("runninghub_api_key"): if comfyui_config.get("runninghub_api_key"):
kit_config["runninghub_api_key"] = comfyui_config["runninghub_api_key"] kit_config["runninghub_api_key"] = comfyui_config["runninghub_api_key"]
# Only pass instance_type if it has a non-empty value
instance_type = comfyui_config.get("runninghub_instance_type")
if instance_type and instance_type.strip():
kit_config["runninghub_instance_type"] = instance_type
return kit_config return kit_config

View File

@@ -231,6 +231,7 @@ class ComfyBaseService:
self, self,
comfyui_url: Optional[str] = None, comfyui_url: Optional[str] = None,
runninghub_api_key: Optional[str] = None, runninghub_api_key: Optional[str] = None,
runninghub_instance_type: Optional[str] = None,
) -> Dict[str, Any]: ) -> Dict[str, Any]:
""" """
Prepare ComfyKit configuration Prepare ComfyKit configuration
@@ -238,6 +239,7 @@ class ComfyBaseService:
Args: Args:
comfyui_url: ComfyUI URL (optional, overrides config) comfyui_url: ComfyUI URL (optional, overrides config)
runninghub_api_key: RunningHub API key (optional, overrides config) runninghub_api_key: RunningHub API key (optional, overrides config)
runninghub_instance_type: RunningHub instance type (optional, overrides config)
Returns: Returns:
ComfyKit configuration dict ComfyKit configuration dict
@@ -262,6 +264,16 @@ class ComfyBaseService:
if final_rh_key: if final_rh_key:
kit_config["runninghub_api_key"] = final_rh_key kit_config["runninghub_api_key"] = final_rh_key
# RunningHub instance type (priority: param > global config > env)
# Only pass if non-empty value
final_instance_type = (
runninghub_instance_type
or self.global_config.get("runninghub_instance_type")
or os.getenv("RUNNINGHUB_INSTANCE_TYPE")
)
if final_instance_type and final_instance_type.strip():
kit_config["runninghub_instance_type"] = final_instance_type
logger.debug(f"ComfyKit config: {kit_config}") logger.debug(f"ComfyKit config: {kit_config}")
return kit_config return kit_config

View File

@@ -24,7 +24,7 @@ dependencies = [
"fastapi>=0.115.0", "fastapi>=0.115.0",
"uvicorn[standard]>=0.32.0", "uvicorn[standard]>=0.32.0",
"python-multipart>=0.0.12", "python-multipart>=0.0.12",
"comfykit>=0.1.11", "comfykit>=0.1.12",
"beautifulsoup4>=4.14.2", "beautifulsoup4>=4.14.2",
] ]

3781
uv.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -14,6 +14,7 @@
FAQ component for displaying frequently asked questions FAQ component for displaying frequently asked questions
""" """
import re
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Optional
@@ -57,6 +58,50 @@ def load_faq_content(language: str) -> Optional[str]:
return None return None
def parse_faq_sections(content: str) -> list[tuple[str, str]]:
"""
Parse FAQ content into sections by ### headings
Args:
content: Raw markdown content
Returns:
List of (question, answer) tuples
"""
# Remove the first main heading (starts with #, not ###)
lines = content.split('\n')
if lines and lines[0].startswith('#') and not lines[0].startswith('##'):
content = '\n'.join(lines[1:])
# Split by ### headings (top-level questions)
# Pattern matches ### at start of line followed by question text
pattern = r'^###\s+(.+?)$'
sections = []
current_question = None
current_answer_lines = []
for line in content.split('\n'):
match = re.match(pattern, line)
if match:
# Save previous section if exists
if current_question is not None:
answer = '\n'.join(current_answer_lines).strip()
sections.append((current_question, answer))
# Start new section
current_question = match.group(1).strip()
current_answer_lines = []
else:
current_answer_lines.append(line)
# Save last section
if current_question is not None:
answer = '\n'.join(current_answer_lines).strip()
sections.append((current_question, answer))
return sections
def render_faq_sidebar(): def render_faq_sidebar():
""" """
Render FAQ in the sidebar Render FAQ in the sidebar
@@ -77,14 +122,13 @@ def render_faq_sidebar():
if faq_content: if faq_content:
# Display FAQ in an expander, expanded by default # Display FAQ in an expander, expanded by default
with st.expander(tr('faq.expand_to_view', fallback='FAQ'), expanded=True): with st.expander(tr('faq.expand_to_view', fallback='FAQ'), expanded=True):
# Remove the first heading from FAQ content since we already show it above # Parse FAQ into sections
lines = faq_content.split('\n') sections = parse_faq_sections(faq_content)
# Skip the first line if it's a heading
if lines and lines[0].startswith('#'):
faq_content = '\n'.join(lines[1:])
# Display FAQ content # Display each question in its own collapsible expander
st.markdown(faq_content, unsafe_allow_html=True) for question, answer in sections:
with st.expander(question, expanded=False):
st.markdown(answer, unsafe_allow_html=True)
# Add a link to GitHub issues for more help # Add a link to GitHub issues for more help
st.markdown( st.markdown(

View File

@@ -180,15 +180,35 @@ def render_advanced_settings():
f"(https://www.runninghub{'.cn' if get_language() == 'zh_CN' else '.ai'}/?inviteCode=bozpdlbj)" f"(https://www.runninghub{'.cn' if get_language() == 'zh_CN' else '.ai'}/?inviteCode=bozpdlbj)"
) )
# RunningHub concurrent limit # RunningHub concurrent limit and instance type (in one row)
runninghub_concurrent_limit = st.number_input( limit_col, instance_col = st.columns(2)
tr("settings.comfyui.runninghub_concurrent_limit"), with limit_col:
min_value=1, runninghub_concurrent_limit = st.number_input(
max_value=10, tr("settings.comfyui.runninghub_concurrent_limit"),
value=comfyui_config.get("runninghub_concurrent_limit", 1), min_value=1,
help=tr("settings.comfyui.runninghub_concurrent_limit_help"), max_value=10,
key="runninghub_concurrent_limit_input" value=comfyui_config.get("runninghub_concurrent_limit", 1),
) help=tr("settings.comfyui.runninghub_concurrent_limit_help"),
key="runninghub_concurrent_limit_input"
)
with instance_col:
# Check if instance type is "plus" (48G VRAM enabled)
current_instance_type = comfyui_config.get("runninghub_instance_type") or ""
is_plus_enabled = current_instance_type == "plus"
# Instance type options with i18n
instance_options = [
tr("settings.comfyui.runninghub_instance_24g"),
tr("settings.comfyui.runninghub_instance_48g"),
]
runninghub_instance_type_display = st.selectbox(
tr("settings.comfyui.runninghub_instance_type"),
options=instance_options,
index=1 if is_plus_enabled else 0,
help=tr("settings.comfyui.runninghub_instance_type_help"),
key="runninghub_instance_type_input"
)
# Convert display value back to actual value
runninghub_48g_enabled = runninghub_instance_type_display == tr("settings.comfyui.runninghub_instance_48g")
# ==================================================================== # ====================================================================
# Action Buttons (full width at bottom) # Action Buttons (full width at bottom)
@@ -206,11 +226,14 @@ def render_advanced_settings():
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 ComfyUI configuration (optional fields, always save what's provided) # Save ComfyUI configuration (optional fields, always save what's provided)
# Convert checkbox to instance type: True -> "plus", False -> ""
instance_type = "plus" if runninghub_48g_enabled else ""
config_manager.set_comfyui_config( config_manager.set_comfyui_config(
comfyui_url=comfyui_url if comfyui_url else None, comfyui_url=comfyui_url if comfyui_url else None,
comfyui_api_key=comfyui_api_key if comfyui_api_key else None, comfyui_api_key=comfyui_api_key if comfyui_api_key else None,
runninghub_api_key=runninghub_api_key if runninghub_api_key else None, runninghub_api_key=runninghub_api_key if runninghub_api_key else None,
runninghub_concurrent_limit=int(runninghub_concurrent_limit) runninghub_concurrent_limit=int(runninghub_concurrent_limit),
runninghub_instance_type=instance_type
) )
# Only save to file if LLM config is valid # Only save to file if LLM config is valid

View File

@@ -197,6 +197,10 @@
"settings.comfyui.runninghub_get_api_key": "Get RunningHub API Key", "settings.comfyui.runninghub_get_api_key": "Get RunningHub API Key",
"settings.comfyui.runninghub_concurrent_limit": "Concurrent Limit", "settings.comfyui.runninghub_concurrent_limit": "Concurrent Limit",
"settings.comfyui.runninghub_concurrent_limit_help": "RunningHub concurrent execution limit (1-10), default is 1 for regular members, adjust based on your membership level", "settings.comfyui.runninghub_concurrent_limit_help": "RunningHub concurrent execution limit (1-10), default is 1 for regular members, adjust based on your membership level",
"settings.comfyui.runninghub_instance_type": "Machine Spec",
"settings.comfyui.runninghub_instance_type_help": "Select RunningHub machine spec, 48G VRAM is suitable for large models or high-resolution generation (requires membership support)",
"settings.comfyui.runninghub_instance_24g": "24G VRAM",
"settings.comfyui.runninghub_instance_48g": "48G VRAM",
"tts.inference_mode": "Synthesis Mode", "tts.inference_mode": "Synthesis Mode",
"tts.mode.local": "Local Synthesis", "tts.mode.local": "Local Synthesis",
"tts.mode.comfyui": "ComfyUI Synthesis", "tts.mode.comfyui": "ComfyUI Synthesis",

View File

@@ -197,6 +197,10 @@
"settings.comfyui.runninghub_get_api_key": "点此获取 RunningHub API Key", "settings.comfyui.runninghub_get_api_key": "点此获取 RunningHub API Key",
"settings.comfyui.runninghub_concurrent_limit": "并发限制", "settings.comfyui.runninghub_concurrent_limit": "并发限制",
"settings.comfyui.runninghub_concurrent_limit_help": "RunningHub 并发执行数量1-10普通会员默认为1请根据您的会员等级调整", "settings.comfyui.runninghub_concurrent_limit_help": "RunningHub 并发执行数量1-10普通会员默认为1请根据您的会员等级调整",
"settings.comfyui.runninghub_instance_type": "机器规格",
"settings.comfyui.runninghub_instance_type_help": "选择 RunningHub 机器规格48G 显存适用于大模型或高分辨率生成(需要会员支持)",
"settings.comfyui.runninghub_instance_24g": "24G 显存",
"settings.comfyui.runninghub_instance_48g": "48G 显存",
"tts.inference_mode": "合成方式", "tts.inference_mode": "合成方式",
"tts.mode.local": "本地合成", "tts.mode.local": "本地合成",
"tts.mode.comfyui": "ComfyUI 合成", "tts.mode.comfyui": "ComfyUI 合成",