Files
Comfyui-JSON-Manager/tab_single.py
2026-01-02 19:15:05 +01:00

146 lines
6.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import streamlit as st
import random
import json
from utils import DEFAULTS, save_json, get_file_mtime
from history_tree import HistoryTree
def render_single_editor(data, file_path):
is_batch_file = "batch_data" in data or isinstance(data, list)
if is_batch_file:
st.warning("⚠️ This file looks like a Batch file. Please switch to the 'Batch Processor' tab.")
return
# Check external modification
current_mtime = get_file_mtime(file_path)
if st.session_state.last_mtime != 0 and current_mtime > st.session_state.last_mtime:
st.error("⚠️ File has been modified externally! Save will overwrite.")
# --- TOP ROW: MODELS ---
st.subheader("🤖 Models")
c1, c2 = st.columns(2)
with c1:
data["model_name"] = st.text_input("Checkpoint", value=data.get("model_name", ""))
with c2:
data["vae_name"] = st.text_input("VAE", value=data.get("vae_name", ""))
# --- PROMPTS ---
st.markdown("---")
st.subheader("📝 Prompts")
if 'append_prompt' in st.session_state:
current_p = data.get("positive_prompt", "")
if current_p: current_p += "\n"
data["positive_prompt"] = current_p + st.session_state.append_prompt
del st.session_state.append_prompt
data["positive_prompt"] = st.text_area("Positive Prompt", value=data.get("positive_prompt", ""), height=150)
data["negative_prompt"] = st.text_area("Negative Prompt", value=data.get("negative_prompt", ""), height=100)
# --- MAIN SETTINGS ---
st.markdown("---")
st.subheader("⚙️ Settings")
col1, col2, col3 = st.columns(3)
with col1:
data["steps"] = st.number_input("Steps", value=int(data.get("steps", 20)))
data["cfg"] = st.number_input("CFG", value=float(data.get("cfg", 7.0)))
with col2:
data["denoise"] = st.number_input("Denoise", value=float(data.get("denoise", 1.0)))
data["sampler_name"] = st.text_input("Sampler", value=data.get("sampler_name", "euler"))
with col3:
data["scheduler"] = st.text_input("Scheduler", value=data.get("scheduler", "normal"))
# Seed Logic
s_row1, s_row2 = st.columns([3, 1])
with s_row2:
st.write("")
st.write("")
if st.button("🎲"):
st.session_state.rand_seed = random.randint(0, 999999999999)
st.rerun()
with s_row1:
current_seed = st.session_state.get('rand_seed', int(data.get("seed", -1)))
val = st.number_input("Seed", value=current_seed)
data["seed"] = val
# --- ADVANCED SECTIONS ---
with st.expander("🎥 Camera & FLF Settings"):
data["camera"] = st.text_input("Camera Motion", value=data.get("camera", "static"))
data["flf"] = st.number_input("FLF", value=float(data.get("flf", 0.0)))
data["frame_to_skip"] = st.number_input("Frames to Skip (VACE)", value=int(data.get("frame_to_skip", 81)))
data["vace schedule"] = st.number_input("VACE Schedule", value=int(data.get("vace schedule", 1)))
with st.expander("📂 File Paths"):
data["video file path"] = st.text_input("Video Input Path", value=data.get("video file path", ""))
data["reference image path"] = st.text_input("Reference Image Path", value=data.get("reference image path", ""))
# --- LORAS (Reverted to plain text to avoid float/string crashes) ---
st.subheader("💊 LoRAs")
l1, l2, l3 = st.columns(3)
with l1:
data["lora 1 high"] = st.text_input("LoRA 1 Name", value=data.get("lora 1 high", ""))
data["lora 1 low"] = st.text_input("LoRA 1 Strength", value=str(data.get("lora 1 low", "")))
with l2:
data["lora 2 high"] = st.text_input("LoRA 2 Name", value=data.get("lora 2 high", ""))
data["lora 2 low"] = st.text_input("LoRA 2 Strength", value=str(data.get("lora 2 low", "")))
with l3:
data["lora 3 high"] = st.text_input("LoRA 3 Name", value=data.get("lora 3 high", ""))
data["lora 3 low"] = st.text_input("LoRA 3 Strength", value=str(data.get("lora 3 low", "")))
# --- CUSTOM PARAMETERS ---
st.markdown("---")
st.caption("🔧 Custom Parameters")
standard_keys = list(DEFAULTS.keys()) + ["history_tree", "prompt_history"]
custom_keys = [k for k in data.keys() if k not in standard_keys]
if custom_keys:
keys_to_remove = []
for k in custom_keys:
ck1, ck2, ck3 = st.columns([1, 2, 0.5])
ck1.text_input("Key", value=k, disabled=True, key=f"ck_lbl_{k}", label_visibility="collapsed")
data[k] = ck2.text_input("Value", value=str(data[k]), key=f"cv_{k}", label_visibility="collapsed")
if ck3.button("🗑️", key=f"cdel_{k}"):
keys_to_remove.append(k)
if keys_to_remove:
for k in keys_to_remove: del data[k]
save_json(file_path, data)
st.rerun()
with st.expander(" Add Parameter"):
nk, nv = st.columns(2)
new_k = nk.text_input("New Key")
new_v = nv.text_input("New Value")
if st.button("Add Parameter"):
if new_k and new_k not in data:
data[new_k] = new_v
save_json(file_path, data)
st.rerun()
# --- SAVE ACTIONS ---
st.markdown("---")
c_save, c_snap = st.columns([1, 2])
with c_save:
if st.button("💾 Save Changes", use_container_width=True):
save_json(file_path, data)
st.toast("Saved!", icon="")
with c_snap:
with st.popover("📸 Save Snapshot (History)", use_container_width=True):
note = st.text_input("Snapshot Note", placeholder="e.g. Changed lighting")
if st.button("Confirm Snapshot"):
tree_data = data.get("history_tree", {})
htree = HistoryTree(tree_data)
snapshot = data.copy()
if "history_tree" in snapshot: del snapshot["history_tree"]
htree.commit(snapshot, note=note if note else "Manual Snapshot")
data["history_tree"] = htree.to_dict()
save_json(file_path, data)
st.toast("Snapshot Saved!", icon="📸")