146 lines
6.2 KiB
Python
146 lines
6.2 KiB
Python
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="📸")
|