Cleanup
This commit is contained in:
parent
f808f4d599
commit
ca33869007
16
README.md
16
README.md
@ -1,6 +1,6 @@
|
|||||||
# MooseCP Image Server
|
# MooseCP Image Server
|
||||||
|
|
||||||
A Model Context Protocol (MCP) server designed to provide LLMs with efficient, token-optimized visual access to image directories. Instead of dumping full-resolution images (which waste tokens and cause context overflow), MooseCP provides a hierarchical workflow: **List $\rightarrow$ Scan $\rightarrow$ Preview $\rightarrow$ Inspect**.
|
A Model Context Protocol (MCP) server designed to provide LLMs with efficient, token-optimized visual access to image directories and AI generation capabilities. Instead of dumping full-resolution images (which waste tokens and cause context overflow), MooseCP provides a hierarchical workflow: **List $\rightarrow$ Scan $\rightarrow$ Preview $\rightarrow$ Inspect**.
|
||||||
|
|
||||||
## ⚠️ AI SLOP DISCLAIMER
|
## ⚠️ AI SLOP DISCLAIMER
|
||||||
This entire project was vibe-coded by an AI. It is 100% slop code. Use it at your own risk.
|
This entire project was vibe-coded by an AI. It is 100% slop code. Use it at your own risk.
|
||||||
@ -32,6 +32,17 @@ Extracts AI generation parameters from PNG files.
|
|||||||
Returns the full-resolution image.
|
Returns the full-resolution image.
|
||||||
* **Best for**: Final confirmation or deep visual analysis where every pixel counts.
|
* **Best for**: Final confirmation or deep visual analysis where every pixel counts.
|
||||||
|
|
||||||
|
### 🎨 `generate_image`
|
||||||
|
Triggers an image generation on a local Stable Diffusion WebUI Forge instance.
|
||||||
|
* **Workflow**: Always call `get_model_info` first to determine the correct prompting style (e.g., tag-based vs. natural language).
|
||||||
|
* **Features**: Supports model-specific presets, resolution presets, and standard parameter overrides.
|
||||||
|
* **Output**: Returns a Base64 image for AI analysis and a proxy URL for direct embedding in the chat.
|
||||||
|
|
||||||
|
### ℹ️ `get_model_info`
|
||||||
|
Provides the "manual" for available generation models.
|
||||||
|
* **Best for**: Learning the prompting style, recommended settings, and available resolution presets for a specific model.
|
||||||
|
* **Workflow**: Call without arguments to see the catalog; call with `model_name` for the detailed guide.
|
||||||
|
|
||||||
### 🌐 `browse_wikipedia`
|
### 🌐 `browse_wikipedia`
|
||||||
Allows the model to browse Wikipedia using its API.
|
Allows the model to browse Wikipedia using its API.
|
||||||
* **Best for**: Quickly retrieving summaries, structural maps (ToC), or specific section content from Wikipedia without dumping the entire page.
|
* **Best for**: Quickly retrieving summaries, structural maps (ToC), or specific section content from Wikipedia without dumping the entire page.
|
||||||
@ -47,9 +58,10 @@ This server requires Python 3.10+ and the following packages:
|
|||||||
* `uvicorn`: ASGI server for the SSE transport.
|
* `uvicorn`: ASGI server for the SSE transport.
|
||||||
* `starlette`: Lightweight ASGI framework.
|
* `starlette`: Lightweight ASGI framework.
|
||||||
* `Pillow`: Image processing and thumbnail generation.
|
* `Pillow`: Image processing and thumbnail generation.
|
||||||
|
* `requests`: For communicating with the Stable Diffusion API.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install uvicorn starlette Pillow
|
pip install uvicorn starlette Pillow requests
|
||||||
```
|
```
|
||||||
|
|
||||||
### Setup
|
### Setup
|
||||||
|
|||||||
12
config.py
12
config.py
@ -1,12 +1,22 @@
|
|||||||
import logging
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# --- Project Root ---
|
||||||
|
# Get the directory where config.py is located
|
||||||
|
ROOT_DIR = Path(__file__).parent.resolve()
|
||||||
|
|
||||||
# --- Server & Logs ---
|
# --- Server & Logs ---
|
||||||
HOST = "127.0.0.1"
|
HOST = "127.0.0.1"
|
||||||
PORT = 8000
|
PORT = 8000
|
||||||
LOG_LEVEL = "WARNING" # Options: "DEBUG", "INFO", "WARNING", "ERROR"
|
LOG_LEVEL = "WARNING" # Options: "DEBUG", "INFO", "WARNING", "ERROR"
|
||||||
LOG_FILE = "debug.log"
|
LOG_FILE = str(ROOT_DIR / "debug.log")
|
||||||
USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64; rv:151.0) Gecko/20100101 Firefox/151.0" # Stealth User-Agent to bypass Wikipedia's bot detection
|
USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64; rv:151.0) Gecko/20100101 Firefox/151.0" # Stealth User-Agent to bypass Wikipedia's bot detection
|
||||||
|
|
||||||
|
# --- Stable Diffusion Config ---
|
||||||
|
SD_URL = "http://127.0.0.1:7860"
|
||||||
|
MODEL_PRESETS_PATH = str(ROOT_DIR / "model_presets.toml")
|
||||||
|
RES_PRESETS_PATH = str(ROOT_DIR / "resolution_presets.toml")
|
||||||
|
|
||||||
# --- Model Specific Token Tuning (Tuned for Gemma 4) ---
|
# --- Model Specific Token Tuning (Tuned for Gemma 4) ---
|
||||||
# Patch size is typically (clip.vision.patch_size * n_merge)
|
# Patch size is typically (clip.vision.patch_size * n_merge)
|
||||||
# For Gemma 4, this is 48px.
|
# For Gemma 4, this is 48px.
|
||||||
|
|||||||
@ -1,23 +1,8 @@
|
|||||||
import requests
|
import requests
|
||||||
import tomllib
|
|
||||||
import os
|
|
||||||
import base64
|
import base64
|
||||||
import config
|
import config
|
||||||
from typing import Any, Dict, List
|
from typing import Any, Dict, List
|
||||||
from tools.utils import ToolError
|
from tools.utils import ToolError, load_toml
|
||||||
|
|
||||||
# Paths to config files
|
|
||||||
MODEL_PRESETS_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), "model_presets.toml")
|
|
||||||
RES_PRESETS_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), "resolution_presets.toml")
|
|
||||||
|
|
||||||
SD_URL = "http://127.0.0.1:7860"
|
|
||||||
|
|
||||||
def load_toml(path: str) -> Dict[str, Any]:
|
|
||||||
try:
|
|
||||||
with open(path, "rb") as f:
|
|
||||||
return tomllib.load(f)
|
|
||||||
except Exception as e:
|
|
||||||
raise ToolError(f"Failed to load config file {path}: {str(e)}")
|
|
||||||
|
|
||||||
async def handle(args: Dict[str, Any]) -> List[Dict[str, Any]]:
|
async def handle(args: Dict[str, Any]) -> List[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
@ -34,7 +19,7 @@ async def handle(args: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|||||||
|
|
||||||
# 2. FETCH CURRENT SERVER DEFAULTS & MAP LABELS
|
# 2. FETCH CURRENT SERVER DEFAULTS & MAP LABELS
|
||||||
try:
|
try:
|
||||||
info_resp = requests.get(f"{SD_URL}/info", timeout=10)
|
info_resp = requests.get(f"{config.SD_URL}/info", timeout=10)
|
||||||
info_resp.raise_for_status()
|
info_resp.raise_for_status()
|
||||||
info_data = info_resp.json()
|
info_data = info_resp.json()
|
||||||
params_info = info_data["named_endpoints"]["/txt2img"]["parameters"]
|
params_info = info_data["named_endpoints"]["/txt2img"]["parameters"]
|
||||||
@ -62,8 +47,8 @@ async def handle(args: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|||||||
label_map[mapped_label] = idx
|
label_map[mapped_label] = idx
|
||||||
|
|
||||||
# 3. LOAD CONFIGS
|
# 3. LOAD CONFIGS
|
||||||
models_cfg = load_toml(MODEL_PRESETS_PATH)
|
models_cfg = load_toml(config.MODEL_PRESETS_PATH)
|
||||||
res_cfg = load_toml(RES_PRESETS_PATH)
|
res_cfg = load_toml(config.RES_PRESETS_PATH)
|
||||||
|
|
||||||
if model_name not in models_cfg:
|
if model_name not in models_cfg:
|
||||||
raise ToolError(f"Model '{model_name}' not found in presets. Available: {', '.join(models_cfg.keys())}")
|
raise ToolError(f"Model '{model_name}' not found in presets. Available: {', '.join(models_cfg.keys())}")
|
||||||
|
|||||||
@ -1,18 +1,7 @@
|
|||||||
import tomllib
|
import requests
|
||||||
import os
|
from typing import Any, Dict, List
|
||||||
from typing import Any, Dict, Union, List
|
import config
|
||||||
from tools.utils import ToolError
|
from tools.utils import ToolError, load_toml
|
||||||
|
|
||||||
# Paths to config files
|
|
||||||
MODEL_PRESETS_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), "model_presets.toml")
|
|
||||||
RES_PRESETS_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), "resolution_presets.toml")
|
|
||||||
|
|
||||||
def load_toml(path: str) -> Dict[str, Any]:
|
|
||||||
try:
|
|
||||||
with open(path, "rb") as f:
|
|
||||||
return tomllib.load(f)
|
|
||||||
except Exception as e:
|
|
||||||
raise ToolError(f"Failed to load config file {path}: {str(e)}")
|
|
||||||
|
|
||||||
async def handle(args: Dict[str, Any]) -> Dict[str, Any]:
|
async def handle(args: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
@ -20,8 +9,8 @@ async def handle(args: Dict[str, Any]) -> Dict[str, Any]:
|
|||||||
"""
|
"""
|
||||||
model_name = args.get("model_name")
|
model_name = args.get("model_name")
|
||||||
|
|
||||||
models = load_toml(MODEL_PRESETS_PATH)
|
models = load_toml(config.MODEL_PRESETS_PATH)
|
||||||
res_presets = load_toml(RES_PRESETS_PATH)
|
res_presets = load_toml(config.RES_PRESETS_PATH)
|
||||||
|
|
||||||
if not model_name:
|
if not model_name:
|
||||||
# Return a catalog of all models
|
# Return a catalog of all models
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import time
|
import time
|
||||||
import datetime
|
import datetime
|
||||||
|
import tomllib
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Dict, Any, Optional
|
from typing import List, Dict, Any, Optional
|
||||||
|
|
||||||
@ -8,6 +9,14 @@ class ToolError(Exception):
|
|||||||
"""Custom exception for tool-related errors to be caught by the MCP server."""
|
"""Custom exception for tool-related errors to be caught by the MCP server."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def load_toml(path: str) -> Dict[str, Any]:
|
||||||
|
"""Loads a TOML file into a dictionary."""
|
||||||
|
try:
|
||||||
|
with open(path, "rb") as f:
|
||||||
|
return tomllib.load(f)
|
||||||
|
except Exception as e:
|
||||||
|
raise ToolError(f"Failed to load config file {path}: {str(e)}")
|
||||||
|
|
||||||
def format_relative_time(timestamp: float) -> str:
|
def format_relative_time(timestamp: float) -> str:
|
||||||
"""Converts a timestamp to a human-readable relative format."""
|
"""Converts a timestamp to a human-readable relative format."""
|
||||||
now = time.time()
|
now = time.time()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user