Full source for the-third-rev: Discord bot (discord.py), FastAPI web UI (React/TS/Vite/Tailwind), ComfyUI integration, generation history DB, preset manager, workflow inspector, and all supporting modules. Excluded from tracking: .env, invite_tokens.json, *.db (SQLite), current-workflow-changes.json, user_settings/, presets/, logs/, web-static/ (build output), frontend/node_modules/. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
195 lines
9.0 KiB
Markdown
195 lines
9.0 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Project Overview
|
|
|
|
This is a Discord bot that integrates with ComfyUI to generate AI images and videos. Users interact via Discord commands, which queue generation requests that execute on a ComfyUI server.
|
|
|
|
## Architecture
|
|
|
|
### File Structure
|
|
|
|
The codebase is organized into focused modules for maintainability:
|
|
|
|
```
|
|
the-third-rev/
|
|
├── config.py # Configuration and constants
|
|
├── job_queue.py # Job queue system (SerialJobQueue)
|
|
├── workflow_manager.py # Workflow manipulation logic
|
|
├── workflow_state.py # Runtime workflow state management
|
|
├── discord_utils.py # Discord helpers and decorators
|
|
├── commands/ # Command handlers (organized by functionality)
|
|
│ ├── __init__.py # Command registration
|
|
│ ├── generation.py # generate, workflow-gen commands
|
|
│ ├── workflow.py # workflow-load command
|
|
│ ├── upload.py # upload command
|
|
│ ├── history.py # history, get-history commands
|
|
│ └── workflow_changes.py # get/set workflow changes commands
|
|
├── bot.py # Main bot entry point (~150 lines)
|
|
└── comfy_client.py # ComfyUI API client (~650 lines)
|
|
```
|
|
|
|
### Core Components
|
|
|
|
- **bot.py**: Minimal Discord bot entry point. Loads configuration, creates dependencies, and registers commands. No command logic here.
|
|
- **comfy_client.py**: Async client wrapping ComfyUI's REST and WebSocket APIs. Dependencies (WorkflowManager, WorkflowStateManager) are injected via constructor.
|
|
- **config.py**: Centralized configuration with `BotConfig.from_env()` for loading environment variables and constants.
|
|
- **job_queue.py**: `SerialJobQueue` ensuring generation requests execute sequentially, preventing ComfyUI server overload.
|
|
- **workflow_manager.py**: `WorkflowManager` class handling workflow template storage and node manipulation (finding/replacing prompts, seeds, etc).
|
|
- **workflow_state.py**: `WorkflowStateManager` class managing runtime workflow changes (prompt, negative_prompt, input_image) in memory with optional file persistence.
|
|
- **discord_utils.py**: Reusable Discord utilities including `@require_comfy_client` decorator, argument parsing, and the `UploadView` component.
|
|
- **commands/**: Command handlers organized by functionality. Each module exports a `setup_*_commands(bot, config)` function.
|
|
|
|
### Key Architectural Patterns
|
|
|
|
1. **Dependency Injection**: ComfyClient receives WorkflowManager and WorkflowStateManager as constructor parameters, eliminating tight coupling to file-based state.
|
|
|
|
2. **Job Queue System**: All generation requests are queued through `SerialJobQueue` in job_queue.py. Jobs execute serially with a worker loop that catches and logs exceptions without crashing the bot.
|
|
|
|
3. **Workflow System**: The bot uses two modes:
|
|
- **Prompt mode**: Simple prompt + negative_prompt (requires workflow template with KSampler node)
|
|
- **Workflow mode**: Full workflow JSON with dynamic modifications from WorkflowStateManager
|
|
|
|
4. **Workflow Modification Flow**:
|
|
- Load workflow template via `bot.comfy.set_workflow()` or `bot.comfy.load_workflow_from_file()`
|
|
- Runtime changes (prompt, negative_prompt, input_image) stored in WorkflowStateManager
|
|
- At generation time, WorkflowManager methods locate nodes by class_type and title metadata, then inject values
|
|
- Seeds are randomized automatically via `workflow_manager.find_and_replace_seed()`
|
|
|
|
5. **Command Registration**: Commands are registered via `commands.register_all_commands(bot, config)` which calls individual `setup_*_commands()` functions from each command module.
|
|
|
|
6. **Configuration Management**: All configuration loaded via `BotConfig.from_env()` in config.py. Constants (command prefixes, error messages, limits) centralized in config.py.
|
|
|
|
7. **History Management**: ComfyClient maintains a bounded deque of recent generations (configurable via `history_limit`) for retrieval via `ttr!get-history`.
|
|
|
|
## Environment Variables
|
|
|
|
Required in `.env`:
|
|
- `DISCORD_BOT_TOKEN`: Discord bot authentication token
|
|
- `COMFY_SERVER`: ComfyUI server address (e.g., `localhost:8188` or `example.com:8188`)
|
|
|
|
Optional:
|
|
- `WORKFLOW_FILE`: Path to JSON workflow file to load at startup
|
|
- `COMFY_HISTORY_LIMIT`: Number of generations to keep in history (default: 10)
|
|
- `COMFY_OUTPUT_PATH`: Path to ComfyUI output directory (default: `C:\Users\ktrangia\Documents\ComfyUI\output`)
|
|
|
|
## Running the Bot
|
|
|
|
```bash
|
|
python bot.py
|
|
```
|
|
|
|
The bot will:
|
|
1. Load configuration from environment variables via `BotConfig.from_env()`
|
|
2. Create WorkflowStateManager and WorkflowManager instances
|
|
3. Initialize ComfyClient with injected dependencies
|
|
4. Load workflow from `WORKFLOW_FILE` if specified
|
|
5. Register all commands via `commands.register_all_commands()`
|
|
6. Start Discord bot and job queue
|
|
7. Listen for commands with prefix `ttr!`
|
|
|
|
## Development Commands
|
|
|
|
No build/test/lint commands exist. This is a standalone Python application.
|
|
|
|
To run: `python bot.py`
|
|
|
|
## Key Implementation Details
|
|
|
|
### ComfyUI Workflow Node Injection
|
|
|
|
When generating with workflows, WorkflowManager searches for specific node patterns:
|
|
- **Prompt**: Finds `CLIPTextEncode` nodes with `_meta.title` containing "Positive Prompt"
|
|
- **Negative Prompt**: Finds `CLIPTextEncode` nodes with `_meta.title` containing "Negative Prompt"
|
|
- **Input Image**: Finds `LoadImage` nodes and replaces the `image` input
|
|
- **Seeds**: Finds any node with `inputs.seed` or `inputs.noise_seed` and randomizes
|
|
|
|
This pattern-matching approach means workflows must follow naming conventions in their node titles for dynamic updates to work.
|
|
|
|
### Discord Command Pattern
|
|
|
|
Commands use a labelled parameter syntax: `ttr!generate prompt:<text> negative_prompt:<text>`
|
|
|
|
Parsing is handled by helpers in discord_utils.py (e.g., `parse_labeled_args()`). The bot splits on keyword markers (`prompt:`, `negative_prompt:`, `type:`, etc.) rather than traditional argparse. Case is preserved for prompts.
|
|
|
|
### Job Queue Mechanics
|
|
|
|
Jobs are dataclasses with `run: Callable[[], Awaitable[None]]` and a `label` for logging. The queue returns position on submit. Jobs capture their context (ctx, prompts) via lambda closures when submitted.
|
|
|
|
### Image/Video Output Handling
|
|
|
|
The `_general_generate` method in ComfyClient returns both images and videos. Videos are identified by file extension (mp4, webm, avi) in the history response. For videos, the bot reads the file from disk at the path specified by `COMFY_OUTPUT_PATH` rather than downloading via the API.
|
|
|
|
### Command Validation
|
|
|
|
The `@require_comfy_client` decorator (from discord_utils.py) validates that `bot.comfy` exists before executing commands. This eliminates repetitive validation code in every command handler.
|
|
|
|
### State Management
|
|
|
|
WorkflowStateManager maintains runtime workflow changes in memory with optional persistence to `current-workflow-changes.json`. The file is loaded on initialization if it exists, and saved automatically when changes are made.
|
|
|
|
## Configuration System
|
|
|
|
Configuration is managed via the `BotConfig` dataclass in config.py:
|
|
|
|
```python
|
|
from config import BotConfig
|
|
|
|
# Load from environment
|
|
config = BotConfig.from_env()
|
|
|
|
# Access configuration
|
|
server = config.comfy_server
|
|
history_limit = config.comfy_history_limit
|
|
output_path = config.comfy_output_path
|
|
```
|
|
|
|
All constants (command prefixes, error messages, defaults) are defined in config.py and imported where needed.
|
|
|
|
## Adding New Commands
|
|
|
|
To add a new command:
|
|
|
|
1. Create a new module in `commands/` (e.g., `commands/my_feature.py`)
|
|
2. Define a `setup_my_feature_commands(bot, config=None)` function
|
|
3. Use `@bot.command(name="...")` decorators to define commands
|
|
4. Use `@require_comfy_client` decorator if command needs ComfyClient
|
|
5. Import and call your setup function in `commands/__init__.py`'s `register_all_commands()`
|
|
|
|
Example:
|
|
|
|
```python
|
|
# commands/my_feature.py
|
|
from discord.ext import commands
|
|
from discord_utils import require_comfy_client
|
|
|
|
def setup_my_feature_commands(bot):
|
|
@bot.command(name="my-command")
|
|
@require_comfy_client
|
|
async def my_command(ctx: commands.Context):
|
|
await ctx.reply("Hello from my command!")
|
|
```
|
|
|
|
## Dependencies
|
|
|
|
From imports:
|
|
- discord.py
|
|
- aiohttp
|
|
- websockets
|
|
- python-dotenv (optional, for .env loading)
|
|
|
|
No requirements.txt exists. Install manually: `pip install discord.py aiohttp websockets python-dotenv`
|
|
|
|
## Code Organization Principles
|
|
|
|
The refactored codebase follows these principles:
|
|
|
|
1. **Single Responsibility**: Each module has one clear purpose
|
|
2. **Dependency Injection**: Dependencies passed via constructor, not created internally
|
|
3. **Configuration Centralization**: All configuration in config.py
|
|
4. **Command Separation**: Commands grouped by functionality in separate modules
|
|
5. **No Magic Strings**: Constants defined once in config.py
|
|
6. **Type Safety**: Modern Python type hints throughout (dict[str, Any] instead of Dict)
|
|
7. **Logging**: Using logger methods instead of print() statements
|