Files
Comfyui-JSON-Manager/tab_comfy.py
2026-01-05 14:49:11 +01:00

186 lines
7.5 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 requests
from PIL import Image
from io import BytesIO
import urllib.parse
from utils import save_config
# Constants for Neko/Browser instance
NEKO_IP = "192.168.1.51"
NEKO_PORT = "8080"
NEKO_BASE = f"http://{NEKO_IP}:{NEKO_PORT}"
def render_single_instance(instance_config, index, all_instances):
url = instance_config.get("url", "http://127.0.0.1:8188")
name = instance_config.get("name", f"Server {index+1}")
COMFY_URL = url.rstrip("/")
c_head, c_set = st.columns([3, 1])
c_head.markdown(f"### 🔌 {name}")
with c_set.popover("⚙️ Settings"):
st.caption("Press Update to apply changes!")
new_name = st.text_input("Name", value=name, key=f"name_{index}")
new_url = st.text_input("URL", value=url, key=f"url_{index}")
if new_url != url:
st.warning("⚠️ Unsaved URL! Click Update below.")
if st.button("💾 Update & Save", key=f"save_{index}", type="primary"):
all_instances[index]["name"] = new_name
all_instances[index]["url"] = new_url
st.session_state.config["comfy_instances"] = all_instances
save_config(
st.session_state.current_dir,
st.session_state.config['favorites'],
{"comfy_instances": all_instances}
)
st.toast("Server config saved!", icon="💾")
st.rerun()
st.divider()
if st.button("🗑️ Remove Server", key=f"del_{index}"):
all_instances.pop(index)
st.session_state.config["comfy_instances"] = all_instances
save_config(
st.session_state.current_dir,
st.session_state.config['favorites'],
{"comfy_instances": all_instances}
)
st.rerun()
# --- 1. STATUS DASHBOARD (Still uses direct API fetch) ---
with st.expander("📊 Server Status", expanded=True):
col1, col2, col3, col4 = st.columns([1, 1, 1, 1])
try:
res = requests.get(f"{COMFY_URL}/queue", timeout=1.5)
queue_data = res.json()
running_cnt = len(queue_data.get("queue_running", []))
pending_cnt = len(queue_data.get("queue_pending", []))
col1.metric("Status", "🟢 Online" if running_cnt > 0 else "💤 Idle")
col2.metric("Pending", pending_cnt)
col3.metric("Running", running_cnt)
if col4.button("🔄 Check Img", key=f"refresh_{index}", use_container_width=True):
st.session_state[f"force_img_refresh_{index}"] = True
except Exception:
col1.metric("Status", "🔴 Offline")
col2.metric("Pending", "-")
col3.metric("Running", "-")
st.error(f"Could not connect to API at {COMFY_URL}")
# If API fails, we still show the browser because the user might be able to debug via Neko
# --- 2. LIVE VIEW (VIA NEKO) ---
st.write("")
c_label, c_ctrl = st.columns([1, 2])
c_label.subheader("📺 Live View (Neko)")
# LIVE PREVIEW TOGGLE
enable_preview = c_ctrl.checkbox("Enable Live Preview", value=True, key=f"live_toggle_{index}")
if enable_preview:
# Height Slider
iframe_h = st.slider(
"Height (px)",
min_value=600, max_value=2500, value=1000, step=50,
key=f"h_slider_{index}"
)
# Construct Neko URL
# Neko usually takes a url parameter.
# Adjust query logic if your specific Neko docker uses a different format (e.g. ?url=...)
encoded_url = urllib.parse.quote(COMFY_URL)
neko_target = f"{NEKO_BASE}/?url={encoded_url}"
# If your neko setup just opens a browser session where you type the URL manually,
# just use NEKO_BASE.
# Assuming typical "browser-in-browser" behavior here:
final_src = NEKO_BASE
st.info(f"Viewing via Neko at: `{final_src}` targeting `{COMFY_URL}`")
st.markdown(
f"""
<iframe src="{final_src}" width="100%" height="{iframe_h}px"
style="border: 2px solid #666; border-radius: 8px; box-shadow: 0 4px 6px rgba(0,0,0,0.3);">
</iframe>
""",
unsafe_allow_html=True
)
st.caption("💡 Note: You may need to type the ComfyUI IP into the Neko browser address bar manually if it doesn't auto-load.")
else:
st.info("Live Preview is disabled.")
st.markdown("---")
# --- 3. LATEST OUTPUT ---
if st.session_state.get(f"force_img_refresh_{index}", False):
st.caption("🖼️ Most Recent Output")
try:
hist_res = requests.get(f"{COMFY_URL}/history", timeout=2)
history = hist_res.json()
if history:
last_prompt_id = list(history.keys())[-1]
outputs = history[last_prompt_id].get("outputs", {})
found_img = None
for node_id, node_output in outputs.items():
if "images" in node_output:
for img_info in node_output["images"]:
if img_info["type"] == "output":
found_img = img_info
break
if found_img: break
if found_img:
img_name = found_img['filename']
folder = found_img['subfolder']
img_type = found_img['type']
img_url = f"{COMFY_URL}/view?filename={img_name}&subfolder={folder}&type={img_type}"
img_res = requests.get(img_url)
image = Image.open(BytesIO(img_res.content))
st.image(image, caption=f"Last Output: {img_name}")
else:
st.warning("Last run had no image output.")
else:
st.info("No history found.")
st.session_state[f"force_img_refresh_{index}"] = False
except Exception as e:
st.error(f"Error fetching image: {e}")
def render_comfy_monitor():
if "comfy_instances" not in st.session_state.config:
st.session_state.config["comfy_instances"] = [
{"name": "Main Server", "url": "http://192.168.1.100:8188"}
]
instances = st.session_state.config["comfy_instances"]
tab_names = [i["name"] for i in instances] + [" Add Server"]
tabs = st.tabs(tab_names)
for i, tab in enumerate(tabs[:-1]):
with tab:
render_single_instance(instances[i], i, instances)
with tabs[-1]:
st.header("Add New ComfyUI Instance")
with st.form("add_server_form"):
new_name = st.text_input("Server Name", placeholder="e.g. Render Node 2")
new_url = st.text_input("URL", placeholder="http://192.168.1.50:8188")
if st.form_submit_button("Add Instance"):
if new_name and new_url:
instances.append({"name": new_name, "url": new_url})
st.session_state.config["comfy_instances"] = instances
save_config(
st.session_state.current_dir,
st.session_state.config['favorites'],
{"comfy_instances": instances}
)
st.success("Server Added!")
st.rerun()
else:
st.error("Please fill in both Name and URL.")