# 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: clear API key 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')}**") 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" ) # 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, 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()