From f80a9746c73cc984bd6eb0975d7c1aa7302a3e82 Mon Sep 17 00:00:00 2001 From: ethanfel Date: Fri, 2 Jan 2026 18:02:15 +0100 Subject: [PATCH] Update app.py --- app.py | 50 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/app.py b/app.py index 5942058..3187bd1 100644 --- a/app.py +++ b/app.py @@ -10,7 +10,8 @@ from utils import ( from tab_single import render_single_editor from tab_batch import render_batch_processor from tab_timeline import render_timeline_tab -from tab_timeline_wip import render_timeline_wip # <--- New Interactive Tab +from tab_timeline_wip import render_timeline_wip +from tab_comfy import render_comfy_monitor # ========================================== # 1. PAGE CONFIGURATION @@ -20,13 +21,17 @@ st.set_page_config(layout="wide", page_title="AI Settings Manager") # ========================================== # 2. SESSION STATE INITIALIZATION # ========================================== +# Core Configuration if 'config' not in st.session_state: st.session_state.config = load_config() + # Default to current working dir if last_dir is missing st.session_state.current_dir = Path(st.session_state.config.get("last_dir", Path.cwd())) +# Snippet Library if 'snippets' not in st.session_state: st.session_state.snippets = load_snippets() +# File Loading & Caching if 'loaded_file' not in st.session_state: st.session_state.loaded_file = None @@ -39,7 +44,7 @@ if 'edit_history_idx' not in st.session_state: if 'single_editor_cache' not in st.session_state: st.session_state.single_editor_cache = DEFAULTS.copy() -# CRITICAL: Token to force UI widgets to refresh when history is restored +# CRITICAL: Token to force UI widgets to refresh when history/batch actions occur if 'ui_reset_token' not in st.session_state: st.session_state.ui_reset_token = 0 @@ -50,6 +55,7 @@ with st.sidebar: st.header("๐Ÿ“‚ Navigator") # --- Path Navigator --- + # Input field to manually change directory new_path = st.text_input("Current Path", value=str(st.session_state.current_dir)) if new_path != str(st.session_state.current_dir): p = Path(new_path) @@ -66,6 +72,7 @@ with st.sidebar: save_config(st.session_state.current_dir, st.session_state.config['favorites']) st.rerun() + # Quick Jump Dropdown fav_selection = st.radio( "Jump to:", ["Select..."] + st.session_state.config['favorites'], @@ -90,13 +97,16 @@ with st.sidebar: st.success(f"Saved '{snip_name}'") st.rerun() + # Snippet List if st.session_state.snippets: st.caption("Click to Append to Prompt:") for name, content in st.session_state.snippets.items(): col_s1, col_s2 = st.columns([4, 1]) + # Append Button if col_s1.button(f"โž• {name}", use_container_width=True): st.session_state.append_prompt = content st.rerun() + # Delete Button if col_s2.button("๐Ÿ—‘๏ธ", key=f"del_snip_{name}"): del st.session_state.snippets[name] save_snippets(st.session_state.snippets) @@ -105,7 +115,9 @@ with st.sidebar: st.markdown("---") # --- File List & Creation --- + # Scan directory for JSONs json_files = sorted(list(st.session_state.current_dir.glob("*.json"))) + # Exclude internal config files json_files = [f for f in json_files if f.name != ".editor_config.json" and f.name != ".editor_snippets.json"] if not json_files: @@ -113,22 +125,30 @@ with st.sidebar: generate_templates(st.session_state.current_dir) st.rerun() + # Creator Form with st.expander("Create New JSON"): new_filename = st.text_input("Filename", placeholder="my_prompt_vace") is_batch = st.checkbox("Is Batch File?") if st.button("Create"): if not new_filename.endswith(".json"): new_filename += ".json" path = st.session_state.current_dir / new_filename + + # Initialize appropriate structure if is_batch: data = {"batch_data": []} else: data = DEFAULTS.copy() - if "vace" in new_filename: data.update({"frame_to_skip": 81, "vace schedule": 1, "video file path": ""}) - elif "i2v" in new_filename: data.update({"reference image path": "", "flf image path": ""}) + # Auto-fill defaults based on name hint + if "vace" in new_filename: + data.update({"frame_to_skip": 81, "vace schedule": 1, "video file path": ""}) + elif "i2v" in new_filename: + data.update({"reference image path": "", "flf image path": ""}) + save_json(path, data) st.rerun() - # --- File Selector --- + # --- File Selector Logic --- + # Ensure selector state is valid if 'file_selector' not in st.session_state: st.session_state.file_selector = json_files[0].name if json_files else None if st.session_state.file_selector not in [f.name for f in json_files] and json_files: @@ -143,15 +163,15 @@ if selected_file_name: file_path = st.session_state.current_dir / selected_file_name # --- Load & Cache Logic --- - # We only reload from disk if the filename changed or mtime changed. - # Otherwise, we use the session state cache to preserve unsaved edits. + # We only reload from disk if the filename changed or file mtime changed externally. + # Otherwise, we use the session state cache to preserve unsaved edits during interactions. if st.session_state.loaded_file != str(file_path): data, mtime = load_json(file_path) st.session_state.data_cache = data st.session_state.last_mtime = mtime st.session_state.loaded_file = str(file_path) - # Clear transient states + # Clear transient states on file switch if 'append_prompt' in st.session_state: del st.session_state.append_prompt if 'rand_seed' in st.session_state: del st.session_state.rand_seed if 'restored_indicator' in st.session_state: del st.session_state.restored_indicator @@ -162,21 +182,31 @@ if selected_file_name: st.title(f"Editing: {selected_file_name}") # --- TABS --- - tab_single, tab_batch, tab_timeline, tab_wip = st.tabs([ + # The heart of the application + tab_single, tab_batch, tab_timeline, tab_wip, tab_comfy = st.tabs([ "๐Ÿ“ Single Editor", "๐Ÿš€ Batch Processor", "๐Ÿ•’ Timeline", - "๐Ÿงช WIP Timeline" + "๐Ÿงช WIP Timeline", + "๐Ÿ”Œ Comfy Monitor" ]) + # 1. Single Editor (Form-based editing) with tab_single: render_single_editor(data, file_path) + # 2. Batch Processor (Sequence list management) with tab_batch: render_batch_processor(data, file_path, json_files, st.session_state.current_dir, selected_file_name) + # 3. Stable Timeline (Clean Graphviz + Diff Inspector) with tab_timeline: render_timeline_tab(data, file_path) + # 4. WIP Timeline (Interactive Agraph - Experimental) with tab_wip: render_timeline_wip(data, file_path) + + # 5. Comfy Monitor (Multi-server dashboard + Live View) + with tab_comfy: + render_comfy_monitor()