Rewrite README with SVG diagrams and Dynamic node documentation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
428
README.md
428
README.md
@@ -1,121 +1,347 @@
|
||||
# 🎛️ AI Settings Manager for ComfyUI
|
||||
<p align="center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="480" height="100" viewBox="0 0 480 100">
|
||||
<defs>
|
||||
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#1a1a2e;stop-opacity:1" />
|
||||
<stop offset="100%" style="stop-color:#16213e;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient id="accent" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
<stop offset="0%" style="stop-color:#e94560" />
|
||||
<stop offset="100%" style="stop-color:#0f3460" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect width="480" height="100" rx="16" fill="url(#bg)" />
|
||||
<rect x="20" y="72" width="440" height="3" rx="1.5" fill="url(#accent)" opacity="0.6" />
|
||||
<text x="240" y="36" text-anchor="middle" fill="#e94560" font-family="monospace" font-size="13" font-weight="bold">{ JSON }</text>
|
||||
<text x="240" y="60" text-anchor="middle" fill="#eee" font-family="sans-serif" font-size="22" font-weight="bold">ComfyUI JSON Manager</text>
|
||||
<text x="240" y="90" text-anchor="middle" fill="#888" font-family="sans-serif" font-size="11">Visual dashboard & dynamic nodes for AI video workflows</text>
|
||||
</svg>
|
||||
</p>
|
||||
|
||||
A 100% vibecoded, visual dashboard for managing, versioning, and batch-processing JSON configuration files used in AI video generation workflows (I2V, VACE).
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/badge/License-Apache_2.0-blue.svg" alt="License" />
|
||||
<img src="https://img.shields.io/badge/Python-3.10%2B-green" alt="Python" />
|
||||
<img src="https://img.shields.io/badge/Built%20with-Streamlit-red" alt="Streamlit" />
|
||||
<img src="https://img.shields.io/badge/ComfyUI-Custom%20Nodes-purple" alt="ComfyUI" />
|
||||
</p>
|
||||
|
||||
This tool consists of two parts:
|
||||
1. **Streamlit Web Interface:** A Dockerized editor to manage prompts, LoRAs, settings, and **branching history**.
|
||||
2. **ComfyUI Custom Nodes:** A set of nodes to read these JSON files (including custom keys) directly into your workflows.
|
||||
A visual dashboard for managing, versioning, and batch-processing JSON configuration files used in AI video generation workflows (I2V, VACE). Two parts:
|
||||
|
||||
  
|
||||
---
|
||||
|
||||
## ✨ Features
|
||||
|
||||
### 📝 Single File Editor
|
||||
* **Visual Interface:** Edit Prompts, Negative Prompts, Seeds, LoRAs, and advanced settings (Camera, FLF, VACE params) without touching raw JSON.
|
||||
* **🔧 Custom Parameters:** Add arbitrary key-value pairs (e.g., `controlnet_strength`, `my_custom_value`) that persist and can be read by ComfyUI.
|
||||
* **Conflict Protection:** Prevents accidental overwrites if the file is modified by another tab or process.
|
||||
* **Snippet Library:** Save reusable prompt fragments (e.g., "Cinematic Lighting", "Anime Style") and append them with one click.
|
||||
|
||||
### 🚀 Batch Processor
|
||||
* **Sequence Management:** Create unlimited sequences within a single JSON file.
|
||||
* **Smart Import:** Copy settings from **any other file** or **history entry** into your current batch sequence.
|
||||
* **Custom Keys per Shot:** Define unique parameters for specific shots in a batch (e.g., Shot 1 has `fog: 0.5`, Shot 2 has `fog: 0.0`).
|
||||
* **Promote to Single:** One-click convert a specific batch sequence back into a standalone Single File.
|
||||
|
||||
### 🕒 Visual Timeline (New!)
|
||||
* **Git-Style Branching:** A dedicated tab visualizes your edit history as a **horizontal node graph**.
|
||||
* **Non-Destructive:** If you jump back to an old version and make changes, the system automatically **forks a new branch** so you never lose history.
|
||||
* **Visual Diff:** Inspect any past version and see a "Delta View" highlighting exactly what changed (e.g., `Seed: 100 -> 555`) compared to your current state.
|
||||
* **Interactive Mode (WIP):** A zoomed-out, interactive canvas to explore complex history trees.
|
||||
1. **Streamlit Web Interface** — Dockerized editor for prompts, LoRAs, settings, and branching history
|
||||
2. **ComfyUI Custom Nodes** — Read JSON files directly into workflows, including a dynamic node that auto-discovers keys
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Installation
|
||||
## Features
|
||||
|
||||
### 1. Unraid / Docker Setup (The Manager)
|
||||
This tool is designed to run as a lightweight container on Unraid.
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%">
|
||||
|
||||
1. **Prepare a Folder:** Create a folder on your server (e.g., `/mnt/user/appdata/ai-manager/`) and place the following files inside:
|
||||
* `app.py`
|
||||
* `utils.py`
|
||||
* `history_tree.py` (New logic engine)
|
||||
* `tab_single.py`
|
||||
* `tab_batch.py`
|
||||
* `tab_timeline.py`
|
||||
* `tab_timeline_wip.py`
|
||||
2. **Add Container in Unraid:**
|
||||
* **Repository:** `python:3.12-slim`
|
||||
* **Network:** `Bridge`
|
||||
* **WebUI:** `http://[IP]:[PORT:8501]`
|
||||
3. **Path Mappings:**
|
||||
* **App Location:** Container `/app` ↔ Host `/mnt/user/appdata/ai-manager/`
|
||||
* **Project Data:** Container `/mnt/user/` ↔ Host `/mnt/user/` (Your media/JSON location)
|
||||
4. **Post Arguments (Crucial):**
|
||||
Enable "Advanced View" and paste this command to install the required graph engines:
|
||||
```bash
|
||||
/bin/sh -c "apt-get update && apt-get install -y graphviz && pip install streamlit opencv-python-headless graphviz streamlit-agraph && cd /app && streamlit run app.py --server.headless true --server.port 8501"
|
||||
```
|
||||
<h3>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><rect width="20" height="20" rx="4" fill="#0f3460"/><text x="10" y="14" text-anchor="middle" fill="#fff" font-size="11">E</text></svg>
|
||||
Single File Editor
|
||||
</h3>
|
||||
|
||||
### 2. ComfyUI Setup (The Nodes)
|
||||
1. Navigate to your ComfyUI installation: `ComfyUI/custom_nodes/`
|
||||
2. Create a folder named `ComfyUI-JSON-Loader`.
|
||||
3. Place the `json_loader.py` file inside.
|
||||
4. Restart ComfyUI.
|
||||
- Visual editing of Prompts, Seeds, LoRAs, Camera, FLF, VACE params
|
||||
- Custom key-value parameters that persist and flow to ComfyUI
|
||||
- Conflict protection against external file modifications
|
||||
- Snippet library for reusable prompt fragments
|
||||
|
||||
</td>
|
||||
<td width="50%">
|
||||
|
||||
<h3>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><rect width="20" height="20" rx="4" fill="#e94560"/><text x="10" y="14" text-anchor="middle" fill="#fff" font-size="11">B</text></svg>
|
||||
Batch Processor
|
||||
</h3>
|
||||
|
||||
- Unlimited sequences within a single JSON file
|
||||
- Import settings from any file or history entry
|
||||
- Per-shot custom keys (e.g. Shot 1: `fog: 0.5`, Shot 2: `fog: 0.0`)
|
||||
- Clone, reorder, and manage sequences visually
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%">
|
||||
|
||||
<h3>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><rect width="20" height="20" rx="4" fill="#533483"/><text x="10" y="14" text-anchor="middle" fill="#fff" font-size="11">T</text></svg>
|
||||
Visual Timeline
|
||||
</h3>
|
||||
|
||||
- Git-style branching with horizontal node graph
|
||||
- Non-destructive: forking on old-version edits preserves all history
|
||||
- Visual diff highlighting changes between any two versions
|
||||
- Restore any past state with one click
|
||||
|
||||
</td>
|
||||
<td width="50%">
|
||||
|
||||
<h3>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><rect width="20" height="20" rx="4" fill="#2b9348"/><text x="10" y="14" text-anchor="middle" fill="#fff" font-size="11">D</text></svg>
|
||||
Dynamic Node (New)
|
||||
</h3>
|
||||
|
||||
- Auto-discovers all JSON keys and exposes them as outputs
|
||||
- No code changes needed when JSON structure evolves
|
||||
- Preserves connections when keys are added on refresh
|
||||
- Native type handling: `int`, `float`, `string`
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
---
|
||||
|
||||
## 🖥️ Usage Guide
|
||||
## Installation
|
||||
|
||||
### 1. Unraid / Docker (Streamlit Manager)
|
||||
|
||||
```bash
|
||||
# Repository: python:3.12-slim
|
||||
# Network: Bridge
|
||||
# WebUI: http://[IP]:[PORT:8501]
|
||||
```
|
||||
|
||||
**Path Mappings:**
|
||||
| Container | Host | Purpose |
|
||||
|:---|:---|:---|
|
||||
| `/app` | `/mnt/user/appdata/ai-manager/` | App files |
|
||||
| `/mnt/user/` | `/mnt/user/` | Project data / JSON location |
|
||||
|
||||
**Post Arguments:**
|
||||
```bash
|
||||
/bin/sh -c "apt-get update && apt-get install -y graphviz && \
|
||||
pip install streamlit opencv-python-headless graphviz streamlit-agraph && \
|
||||
cd /app && streamlit run app.py --server.headless true --server.port 8501"
|
||||
```
|
||||
|
||||
### 2. ComfyUI (Custom Nodes)
|
||||
|
||||
```bash
|
||||
cd ComfyUI/custom_nodes/
|
||||
git clone <this-repo> ComfyUI-JSON-Manager
|
||||
# Restart ComfyUI
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ComfyUI Nodes
|
||||
|
||||
### Node Overview
|
||||
|
||||
<!--
|
||||
Diagram: shows JSON file flowing into different node types
|
||||
-->
|
||||
<p align="center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="720" height="280" viewBox="0 0 720 280">
|
||||
<defs>
|
||||
<linearGradient id="nodeBg" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#2d2d3d" />
|
||||
<stop offset="100%" style="stop-color:#1e1e2e" />
|
||||
</linearGradient>
|
||||
<filter id="shadow">
|
||||
<feDropShadow dx="1" dy="2" stdDeviation="3" flood-opacity="0.3"/>
|
||||
</filter>
|
||||
</defs>
|
||||
|
||||
<!-- JSON File -->
|
||||
<rect x="10" y="100" width="120" height="60" rx="8" fill="#0f3460" filter="url(#shadow)" />
|
||||
<text x="70" y="125" text-anchor="middle" fill="#aaa" font-family="monospace" font-size="10">batch_prompt</text>
|
||||
<text x="70" y="142" text-anchor="middle" fill="#fff" font-family="monospace" font-size="13" font-weight="bold">.json</text>
|
||||
|
||||
<!-- Arrow -->
|
||||
<line x1="130" y1="130" x2="170" y2="130" stroke="#555" stroke-width="2" marker-end="url(#arrowhead)"/>
|
||||
<defs><marker id="arrowhead" markerWidth="8" markerHeight="6" refX="8" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#555"/></marker></defs>
|
||||
|
||||
<!-- Dynamic Node -->
|
||||
<rect x="180" y="20" width="200" height="70" rx="10" fill="url(#nodeBg)" stroke="#2b9348" stroke-width="2" filter="url(#shadow)" />
|
||||
<text x="280" y="44" text-anchor="middle" fill="#2b9348" font-family="sans-serif" font-size="12" font-weight="bold">JSON Loader (Dynamic)</text>
|
||||
<text x="280" y="62" text-anchor="middle" fill="#888" font-family="monospace" font-size="10">auto-discovers keys</text>
|
||||
<text x="280" y="78" text-anchor="middle" fill="#666" font-family="monospace" font-size="9">click Refresh to populate</text>
|
||||
|
||||
<!-- Batch I2V Node -->
|
||||
<rect x="180" y="105" width="200" height="50" rx="10" fill="url(#nodeBg)" stroke="#e94560" stroke-width="2" filter="url(#shadow)" />
|
||||
<text x="280" y="127" text-anchor="middle" fill="#e94560" font-family="sans-serif" font-size="12" font-weight="bold">JSON Batch Loader (I2V)</text>
|
||||
<text x="280" y="144" text-anchor="middle" fill="#888" font-family="monospace" font-size="10">prompts, flf, seed, paths</text>
|
||||
|
||||
<!-- Batch VACE Node -->
|
||||
<rect x="180" y="170" width="200" height="50" rx="10" fill="url(#nodeBg)" stroke="#533483" stroke-width="2" filter="url(#shadow)" />
|
||||
<text x="280" y="192" text-anchor="middle" fill="#533483" font-family="sans-serif" font-size="12" font-weight="bold">JSON Batch Loader (VACE)</text>
|
||||
<text x="280" y="209" text-anchor="middle" fill="#888" font-family="monospace" font-size="10">+ vace frames, schedule</text>
|
||||
|
||||
<!-- Custom Nodes -->
|
||||
<rect x="180" y="235" width="200" height="40" rx="10" fill="url(#nodeBg)" stroke="#0f3460" stroke-width="2" filter="url(#shadow)" />
|
||||
<text x="280" y="260" text-anchor="middle" fill="#0f3460" font-family="sans-serif" font-size="12" font-weight="bold">JSON Loader (Custom 1/3/6)</text>
|
||||
|
||||
<!-- Output labels -->
|
||||
<line x1="380" y1="55" x2="420" y2="55" stroke="#2b9348" stroke-width="1.5"/>
|
||||
<text x="430" y="47" fill="#aaa" font-family="monospace" font-size="9">general_prompt</text>
|
||||
<text x="430" y="59" fill="#aaa" font-family="monospace" font-size="9">seed (int)</text>
|
||||
<text x="430" y="71" fill="#aaa" font-family="monospace" font-size="9">my_custom_key ...</text>
|
||||
|
||||
<line x1="380" y1="130" x2="420" y2="130" stroke="#e94560" stroke-width="1.5"/>
|
||||
<text x="430" y="127" fill="#aaa" font-family="monospace" font-size="9">general_prompt, camera,</text>
|
||||
<text x="430" y="139" fill="#aaa" font-family="monospace" font-size="9">flf, seed, paths ...</text>
|
||||
|
||||
<line x1="380" y1="195" x2="420" y2="195" stroke="#533483" stroke-width="1.5"/>
|
||||
<text x="430" y="192" fill="#aaa" font-family="monospace" font-size="9">+ frame_to_skip, vace_schedule,</text>
|
||||
<text x="430" y="204" fill="#aaa" font-family="monospace" font-size="9">input_a_frames ...</text>
|
||||
|
||||
<line x1="380" y1="255" x2="420" y2="255" stroke="#0f3460" stroke-width="1.5"/>
|
||||
<text x="430" y="259" fill="#aaa" font-family="monospace" font-size="9">manual key lookup (1-6 slots)</text>
|
||||
</svg>
|
||||
</p>
|
||||
|
||||
### Dynamic Node
|
||||
|
||||
The **JSON Loader (Dynamic)** node reads your JSON file and automatically creates output slots for every key it finds. No code changes needed when your JSON structure evolves.
|
||||
|
||||
**How it works:**
|
||||
1. Enter a `json_path` and `sequence_number`
|
||||
2. Click **Refresh Outputs**
|
||||
3. Outputs appear named after JSON keys, with native types preserved
|
||||
|
||||
<p align="center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="240" viewBox="0 0 500 240">
|
||||
<defs>
|
||||
<linearGradient id="dynBg" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#353545" />
|
||||
<stop offset="100%" style="stop-color:#252535" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<!-- Node body -->
|
||||
<rect x="20" y="10" width="240" height="220" rx="10" fill="url(#dynBg)" stroke="#2b9348" stroke-width="2" />
|
||||
<rect x="20" y="10" width="240" height="28" rx="10" fill="#2b9348" />
|
||||
<rect x="20" y="28" width="240" height="10" fill="#2b9348" />
|
||||
<text x="140" y="31" text-anchor="middle" fill="#fff" font-family="sans-serif" font-size="13" font-weight="bold">JSON Loader (Dynamic)</text>
|
||||
|
||||
<!-- Inputs -->
|
||||
<text x="35" y="60" fill="#ccc" font-family="monospace" font-size="10">json_path: /data/prompt.json</text>
|
||||
<text x="35" y="78" fill="#ccc" font-family="monospace" font-size="10">sequence_number: 1</text>
|
||||
|
||||
<!-- Refresh button -->
|
||||
<rect x="45" y="88" width="190" height="24" rx="5" fill="#2b9348" opacity="0.3" stroke="#2b9348" stroke-width="1"/>
|
||||
<text x="140" y="104" text-anchor="middle" fill="#2b9348" font-family="sans-serif" font-size="11" font-weight="bold">Refresh Outputs</text>
|
||||
|
||||
<!-- Output slots -->
|
||||
<circle cx="260" cy="130" r="5" fill="#6bcb77"/>
|
||||
<text x="245" y="134" text-anchor="end" fill="#ccc" font-family="monospace" font-size="10">general_prompt</text>
|
||||
|
||||
<circle cx="260" cy="150" r="5" fill="#6bcb77"/>
|
||||
<text x="245" y="154" text-anchor="end" fill="#ccc" font-family="monospace" font-size="10">negative</text>
|
||||
|
||||
<circle cx="260" cy="170" r="5" fill="#4d96ff"/>
|
||||
<text x="245" y="174" text-anchor="end" fill="#ccc" font-family="monospace" font-size="10">seed</text>
|
||||
|
||||
<circle cx="260" cy="190" r="5" fill="#ff6b6b"/>
|
||||
<text x="245" y="194" text-anchor="end" fill="#ccc" font-family="monospace" font-size="10">flf</text>
|
||||
|
||||
<circle cx="260" cy="210" r="5" fill="#6bcb77"/>
|
||||
<text x="245" y="214" text-anchor="end" fill="#ccc" font-family="monospace" font-size="10">camera</text>
|
||||
|
||||
<!-- Connection lines to downstream -->
|
||||
<line x1="265" y1="130" x2="340" y2="130" stroke="#6bcb77" stroke-width="1.5"/>
|
||||
<line x1="265" y1="170" x2="340" y2="165" stroke="#4d96ff" stroke-width="1.5"/>
|
||||
|
||||
<!-- Downstream node -->
|
||||
<rect x="340" y="115" width="140" height="65" rx="8" fill="url(#dynBg)" stroke="#555" stroke-width="1.5" />
|
||||
<text x="410" y="137" text-anchor="middle" fill="#aaa" font-family="sans-serif" font-size="11">KSampler</text>
|
||||
<circle cx="340" cy="130" r="4" fill="#6bcb77"/>
|
||||
<text x="350" y="150" fill="#777" font-family="monospace" font-size="9">positive</text>
|
||||
<circle cx="340" cy="165" r="4" fill="#4d96ff"/>
|
||||
<text x="350" y="170" fill="#777" font-family="monospace" font-size="9">seed</text>
|
||||
|
||||
<!-- Legend -->
|
||||
<circle cx="30" y="248" r="4" fill="#6bcb77"/>
|
||||
<text x="40" y="252" fill="#888" font-family="monospace" font-size="9">STRING</text>
|
||||
<circle cx="100" y="248" r="4" fill="#4d96ff"/>
|
||||
<text x="110" y="252" fill="#888" font-family="monospace" font-size="9">INT</text>
|
||||
<circle cx="155" y="248" r="4" fill="#ff6b6b"/>
|
||||
<text x="165" y="252" fill="#888" font-family="monospace" font-size="9">FLOAT</text>
|
||||
</svg>
|
||||
</p>
|
||||
|
||||
**Type handling:** Values keep their native Python type — `int` stays `int`, `float` stays `float`, booleans become `"true"`/`"false"` strings, everything else becomes `string`. The `*` (any) output type allows connecting to any input.
|
||||
|
||||
**Refreshing is safe:** Clicking Refresh after adding new keys to your JSON preserves all existing connections. Only removed keys get disconnected.
|
||||
|
||||
### Standard & Batch Nodes
|
||||
|
||||
| Node | Outputs | Use Case |
|
||||
|:---|:---|:---|
|
||||
| **JSON Loader (Standard/I2V)** | prompts, flf, seed, paths | Single-file I2V workflows |
|
||||
| **JSON Loader (VACE Full)** | above + VACE integers | Single-file VACE workflows |
|
||||
| **JSON Loader (LoRAs Only)** | 6 LoRA strings | Single-file LoRA loading |
|
||||
| **JSON Batch Loader (I2V)** | prompts, flf, seed, paths | Batch I2V with sequence_number |
|
||||
| **JSON Batch Loader (VACE)** | above + VACE integers | Batch VACE with sequence_number |
|
||||
| **JSON Batch Loader (LoRAs)** | 6 LoRA strings | Batch LoRA loading |
|
||||
| **JSON Loader (Custom 1/3/6)** | 1, 3, or 6 string values | Manual key lookup by name |
|
||||
|
||||
---
|
||||
|
||||
## Web Interface Usage
|
||||
|
||||
### The Web Interface
|
||||
Navigate to your container's IP (e.g., `http://192.168.1.100:8501`).
|
||||
|
||||
* **Custom Parameters:** Scroll to the bottom of the editor (Single or Batch) to find the "🔧 Custom Parameters" section. Type a Key (e.g., `strength`) and Value (e.g., `0.8`) and click "Add".
|
||||
* **Timeline:** Switch to the **Timeline Tab** to see your version history.
|
||||
* **Restore:** Select a node from the list or click on the graph (WIP tab) to view details. Click "Restore" to revert settings to that point.
|
||||
* **Branching:** If you restore an old node and click "Save/Snap", a new branch is created automatically.
|
||||
**Path navigation** supports case-insensitive matching — typing `/media/P5/myFolder` will resolve to `/media/p5/MyFolder` automatically.
|
||||
|
||||
### ComfyUI Workflow
|
||||
Search for "JSON" in ComfyUI to find the new nodes.
|
||||
|
||||
<img width="1251" height="921" alt="image" src="https://github.com/user-attachments/assets/06d567f8-15ee-4011-9b86-d0b43ce1ba74" />
|
||||
|
||||
#### Standard Nodes
|
||||
| Node Name | Description |
|
||||
| :--- | :--- |
|
||||
| **JSON Loader (Standard/I2V)** | Outputs prompts, FLF, Seed, and paths for I2V. |
|
||||
| **JSON Loader (VACE Full)** | Outputs everything above plus VACE integers (frames to skip, schedule, etc.). |
|
||||
| **JSON Loader (LoRAs Only)** | Outputs the 6 LoRA strings. |
|
||||
|
||||
#### Universal Custom Nodes (New!)
|
||||
These nodes read *any* key you added in the "Custom Parameters" section. They work for both Single files (ignores sequence input) and Batch files (reads specific sequence).
|
||||
|
||||
| Node Name | Description |
|
||||
| :--- | :--- |
|
||||
| **JSON Loader (Custom 1)** | Reads 1 custom key. Input the key name (e.g., "strength"), outputs the value string. |
|
||||
| **JSON Loader (Custom 3)** | Reads 3 custom keys. |
|
||||
| **JSON Loader (Custom 6)** | Reads 6 custom keys. |
|
||||
|
||||
#### Batch Nodes
|
||||
These nodes require an integer input (Primitive or Batch Indexer) for `sequence_number`.
|
||||
|
||||
| Node Name | Description |
|
||||
| :--- | :--- |
|
||||
| **JSON Batch Loader (I2V)** | Loads specific sequence data for I2V. |
|
||||
| **JSON Batch Loader (VACE)** | Loads specific sequence data for VACE. |
|
||||
| **JSON Batch Loader (LoRAs)** | Loads specific LoRAs for that sequence. |
|
||||
- **Custom Parameters:** Scroll to "Custom Parameters" in any editor tab. Type a key and value, click Add.
|
||||
- **Timeline:** Switch to the Timeline tab to see version history as a graph. Restore any version, and new edits fork a branch automatically.
|
||||
- **Snippets:** Save reusable prompt fragments and append them with one click.
|
||||
|
||||
---
|
||||
|
||||
## 📂 File Structure
|
||||
## JSON Format
|
||||
|
||||
```text
|
||||
/ai-manager
|
||||
├── app.py # Main entry point & Tab controller
|
||||
├── utils.py # I/O logic, Config, and Defaults
|
||||
├── history_tree.py # Graph logic, Branching engine, Graphviz generator
|
||||
├── tab_single.py # Single Editor UI
|
||||
├── tab_batch.py # Batch Processor UI
|
||||
├── tab_timeline.py # Stable Timeline UI (Compact Graphviz + Diff Inspector)
|
||||
├── tab_timeline_wip.py # Interactive Timeline UI (Streamlit Agraph)
|
||||
└── json_loader.py # ComfyUI Custom Node script
|
||||
```jsonc
|
||||
{
|
||||
"batch_data": [
|
||||
{
|
||||
"sequence_number": 1,
|
||||
"general_prompt": "A cinematic scene...",
|
||||
"negative": "blurry, low quality",
|
||||
"seed": 42,
|
||||
"flf": 0.5,
|
||||
"camera": "pan_left",
|
||||
"video file path": "/data/input.mp4",
|
||||
"reference image path": "/data/ref.png",
|
||||
"my_custom_key": "any value"
|
||||
// ... any additional keys are auto-discovered by the Dynamic node
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
ComfyUI-JSON-Manager/
|
||||
├── __init__.py # ComfyUI entry point, exports nodes + WEB_DIRECTORY
|
||||
├── json_loader.py # All ComfyUI node classes + /json_manager/get_keys API
|
||||
├── web/
|
||||
│ └── json_dynamic.js # Frontend extension for Dynamic node (refresh, show/hide)
|
||||
├── app.py # Streamlit main entry point & navigator
|
||||
├── utils.py # I/O, config, defaults, case-insensitive path resolver
|
||||
├── history_tree.py # Git-style branching engine
|
||||
├── tab_single.py # Single file editor UI
|
||||
├── tab_batch.py # Batch processor UI
|
||||
├── tab_timeline.py # Visual timeline UI
|
||||
├── tab_comfy.py # ComfyUI server monitor
|
||||
├── tab_raw.py # Raw JSON editor
|
||||
└── tests/
|
||||
├── test_json_loader.py
|
||||
├── test_utils.py
|
||||
└── test_history_tree.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
[Apache 2.0](LICENSE)
|
||||
|
||||
Reference in New Issue
Block a user