Files
AI-Video/web/components/settings.py

220 lines
10 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)"
)
# ====================================================================
# 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:
# Save LLM configuration
if llm_api_key and llm_base_url and llm_model:
config_manager.set_llm_config(llm_api_key, llm_base_url, llm_model)
# Save ComfyUI configuration
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
)
# Save to file
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()