233 lines
11 KiB
Python
233 lines
11 KiB
Python
# Copyright (C) 2025 AIDC-AI
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""
|
|
System settings component for web UI
|
|
"""
|
|
|
|
import streamlit as st
|
|
|
|
from web.i18n import tr, get_language
|
|
from web.utils.streamlit_helpers import safe_rerun
|
|
from pixelle_video.config import config_manager
|
|
|
|
|
|
def render_advanced_settings():
|
|
"""Render system configuration (required) with 2-column layout"""
|
|
# Check if system is configured
|
|
is_configured = config_manager.validate()
|
|
|
|
# Expand if not configured, collapse if configured
|
|
with st.expander(tr("settings.title"), expanded=not is_configured):
|
|
# 2-column layout: LLM | ComfyUI
|
|
llm_col, comfyui_col = st.columns(2)
|
|
|
|
# ====================================================================
|
|
# Column 1: LLM Settings
|
|
# ====================================================================
|
|
with llm_col:
|
|
with st.container(border=True):
|
|
st.markdown(f"**{tr('settings.llm.title')}**")
|
|
|
|
# Quick preset selection
|
|
from pixelle_video.llm_presets import get_preset_names, get_preset, find_preset_by_base_url_and_model
|
|
|
|
# Custom at the end
|
|
preset_names = get_preset_names() + ["Custom"]
|
|
|
|
# Get current config
|
|
current_llm = config_manager.get_llm_config()
|
|
|
|
# Auto-detect which preset matches current config
|
|
current_preset = find_preset_by_base_url_and_model(
|
|
current_llm["base_url"],
|
|
current_llm["model"]
|
|
)
|
|
|
|
# Determine default index based on current config
|
|
if current_preset:
|
|
# Current config matches a preset
|
|
default_index = preset_names.index(current_preset)
|
|
else:
|
|
# Current config doesn't match any preset -> Custom
|
|
default_index = len(preset_names) - 1
|
|
|
|
selected_preset = st.selectbox(
|
|
tr("settings.llm.quick_select"),
|
|
options=preset_names,
|
|
index=default_index,
|
|
help=tr("settings.llm.quick_select_help"),
|
|
key="llm_preset_select"
|
|
)
|
|
|
|
# Auto-fill based on selected preset
|
|
if selected_preset != "Custom":
|
|
# Preset selected
|
|
preset_config = get_preset(selected_preset)
|
|
|
|
# If user switched to a different preset (not current one), clear API key
|
|
# If it's the same as current config, keep API key
|
|
if selected_preset == current_preset:
|
|
# Same preset as saved config: keep API key
|
|
default_api_key = current_llm["api_key"]
|
|
else:
|
|
# Different preset: use default_api_key if provided (e.g., Ollama), otherwise clear
|
|
default_api_key = preset_config.get("default_api_key", "")
|
|
|
|
default_base_url = preset_config.get("base_url", "")
|
|
default_model = preset_config.get("model", "")
|
|
|
|
# Show API key URL if available
|
|
if preset_config.get("api_key_url"):
|
|
st.markdown(f"🔑 [{tr('settings.llm.get_api_key')}]({preset_config['api_key_url']})")
|
|
else:
|
|
# Custom: show current saved config (if any)
|
|
default_api_key = current_llm["api_key"]
|
|
default_base_url = current_llm["base_url"]
|
|
default_model = current_llm["model"]
|
|
|
|
st.markdown("---")
|
|
|
|
# API Key (use unique key to force refresh when switching preset)
|
|
llm_api_key = st.text_input(
|
|
f"{tr('settings.llm.api_key')} *",
|
|
value=default_api_key,
|
|
type="password",
|
|
help=tr("settings.llm.api_key_help"),
|
|
key=f"llm_api_key_input_{selected_preset}"
|
|
)
|
|
|
|
# Base URL (use unique key based on preset to force refresh)
|
|
llm_base_url = st.text_input(
|
|
f"{tr('settings.llm.base_url')} *",
|
|
value=default_base_url,
|
|
help=tr("settings.llm.base_url_help"),
|
|
key=f"llm_base_url_input_{selected_preset}"
|
|
)
|
|
|
|
# Model (use unique key based on preset to force refresh)
|
|
llm_model = st.text_input(
|
|
f"{tr('settings.llm.model')} *",
|
|
value=default_model,
|
|
help=tr("settings.llm.model_help"),
|
|
key=f"llm_model_input_{selected_preset}"
|
|
)
|
|
|
|
# ====================================================================
|
|
# Column 2: ComfyUI Settings
|
|
# ====================================================================
|
|
with comfyui_col:
|
|
with st.container(border=True):
|
|
st.markdown(f"**{tr('settings.comfyui.title')}**")
|
|
|
|
# Get current configuration
|
|
comfyui_config = config_manager.get_comfyui_config()
|
|
|
|
# Local/Self-hosted ComfyUI configuration
|
|
st.markdown(f"**{tr('settings.comfyui.local_title')}**")
|
|
url_col, key_col = st.columns(2)
|
|
with url_col:
|
|
comfyui_url = st.text_input(
|
|
tr("settings.comfyui.comfyui_url"),
|
|
value=comfyui_config.get("comfyui_url", "http://127.0.0.1:8188"),
|
|
help=tr("settings.comfyui.comfyui_url_help"),
|
|
key="comfyui_url_input"
|
|
)
|
|
with key_col:
|
|
comfyui_api_key = st.text_input(
|
|
tr("settings.comfyui.comfyui_api_key"),
|
|
value=comfyui_config.get("comfyui_api_key", ""),
|
|
type="password",
|
|
help=tr("settings.comfyui.comfyui_api_key_help"),
|
|
key="comfyui_api_key_input"
|
|
)
|
|
|
|
# Test connection button
|
|
if st.button(tr("btn.test_connection"), key="test_comfyui", use_container_width=True):
|
|
try:
|
|
import requests
|
|
response = requests.get(f"{comfyui_url}/system_stats", timeout=5)
|
|
if response.status_code == 200:
|
|
st.success(tr("status.connection_success"))
|
|
else:
|
|
st.error(tr("status.connection_failed"))
|
|
except Exception as e:
|
|
st.error(f"{tr('status.connection_failed')}: {str(e)}")
|
|
|
|
st.markdown("---")
|
|
|
|
# RunningHub cloud configuration
|
|
st.markdown(f"**{tr('settings.comfyui.cloud_title')}**")
|
|
runninghub_api_key = st.text_input(
|
|
tr("settings.comfyui.runninghub_api_key"),
|
|
value=comfyui_config.get("runninghub_api_key", ""),
|
|
type="password",
|
|
help=tr("settings.comfyui.runninghub_api_key_help"),
|
|
key="runninghub_api_key_input"
|
|
)
|
|
st.caption(
|
|
f"{tr('settings.comfyui.runninghub_hint')} "
|
|
f"[{tr('settings.comfyui.runninghub_get_api_key')}]"
|
|
f"(https://www.runninghub{'.cn' if get_language() == 'zh_CN' else '.ai'}/?inviteCode=bozpdlbj)"
|
|
)
|
|
|
|
# RunningHub concurrent limit
|
|
runninghub_concurrent_limit = st.number_input(
|
|
tr("settings.comfyui.runninghub_concurrent_limit"),
|
|
min_value=1,
|
|
max_value=10,
|
|
value=comfyui_config.get("runninghub_concurrent_limit", 1),
|
|
help=tr("settings.comfyui.runninghub_concurrent_limit_help"),
|
|
key="runninghub_concurrent_limit_input"
|
|
)
|
|
|
|
# ====================================================================
|
|
# Action Buttons (full width at bottom)
|
|
# ====================================================================
|
|
st.markdown("---")
|
|
|
|
col1, col2 = st.columns(2)
|
|
with col1:
|
|
if st.button(tr("btn.save_config"), use_container_width=True, key="save_config_btn"):
|
|
try:
|
|
# Validate and save LLM configuration
|
|
if not (llm_api_key and llm_base_url and llm_model):
|
|
st.error(tr("status.llm_config_incomplete"))
|
|
else:
|
|
config_manager.set_llm_config(llm_api_key, llm_base_url, llm_model)
|
|
|
|
# Save ComfyUI configuration (optional fields, always save what's provided)
|
|
config_manager.set_comfyui_config(
|
|
comfyui_url=comfyui_url if comfyui_url 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_concurrent_limit=int(runninghub_concurrent_limit)
|
|
)
|
|
|
|
# Only save to file if LLM config is valid
|
|
if llm_api_key and llm_base_url and llm_model:
|
|
config_manager.save()
|
|
st.success(tr("status.config_saved"))
|
|
safe_rerun()
|
|
except Exception as e:
|
|
st.error(f"{tr('status.save_failed')}: {str(e)}")
|
|
|
|
with col2:
|
|
if st.button(tr("btn.reset_config"), use_container_width=True, key="reset_config_btn"):
|
|
# Reset to default
|
|
from pixelle_video.config.schema import PixelleVideoConfig
|
|
config_manager.config = PixelleVideoConfig()
|
|
config_manager.save()
|
|
st.success(tr("status.config_reset"))
|
|
safe_rerun()
|
|
|