Skill: danielchen59/gnano-ihogmn (version 1.0.4)

--- name: gnano-ihogmn description: GNano Ihogmn 图片生成技能 - 支持动态 API 配置，根据 Token 自动获取可用功能，支持文生图和图生图 --- # GNano Ihogmn 图片生成技能 V1 GNano Ihogmn 图片生成技能 - 第一版。支持动态 API 配置，根据用户提供的 Token 自动获取可用功能和参数。 ## 快速开始 ### 1. 安装依赖 ```bash pip install requests ``` ### 2. 验证安装 ```bash python scripts/get_config.py --token "YOUR_API_TOKEN" ``` ## 核心特性 - **动态配置**: 不内嵌 API Token，每个新任务需要用户提供 - **自动探测**: 根据 Token 获取该账户支持的模型、分辨率、参考图限制等 - **任务记忆**: 在同一任务会话内记住配置，后续对话快速出图 - **模型支持**: 自动适配 gemini-3-pro-image-preview 和 gemini-3.1-flash-image-preview - **路径处理**: 支持相对路径和绝对路径，自动转换 ## 使用流程 ### 1. 新建任务（首次对话） 用户首次使用或明确说"新建任务"时： **步骤 1: 请求 API Token** ``` "请提供您的 GNano API Token，我将根据您的账户配置获取可用功能。" "如果您没有 Token，请访问 https://gnano.ihogmn.top 获取。" ``` **步骤 2: 验证并获取配置** ```bash python scripts/get_config.py --token "用户提供的TOKEN" ``` 返回配置示例： ```json { "success": true, "api_token": "xxx", "api_url": "https://gnano.ihogmn.top", "models": ["gemini-3.1-flash-image-preview", "gemini-3-pro-image-preview"], "default_model": "gemini-3.1-flash-image-preview", "resolutions": ["1K", "2K", "4K"], "default_resolution": "2K", "max_reference_images": 2, "max_reference_size_mb": 2, "rate_limit_per_minute": 2 } ``` **步骤 3: 向用户展示配置** ``` "✅ 配置成功！您的账户支持以下功能： - 可用模型: gemini-3.1-flash-image-preview, gemini-3-pro-image-preview - 默认模型: gemini-3.1-flash-image-preview - 支持分辨率: 1K, 2K, 4K - 参考图限制: 最多2张，每张≤2MB - 速率限制: 每分钟2张 现在可以直接告诉我您想生成什么图片了！" ``` ### 2. 常规出图对话 在同一任务内，用户直接说： - "出图：一只可爱的猫咪" - "生成一张风景图" **执行命令：** ```bash python scripts/generate_image.py \ --token "YOUR_TOKEN" \ --prompt "一只可爱的猫咪" \ --model "gemini-3.1-flash-image-preview" \ --resolution "2K" \ --output "result.png" ``` #### 使用参考图（图生图） **使用方法：** 1. **将参考图放到工作区目录** - 把图片文件复制到工作区目录 - 或使用绝对路径 2. **使用参考图生成** ```bash python scripts/generate_image.py \ --token "YOUR_TOKEN" \ --prompt "将图中人物外套脱掉" \ --reference "woman.jpg" \ --output "result.png" ``` **注意：** - 参考图必须已保存到工作区目录 - 支持最多 2 张参考图，每张不超过 2MB - 支持格式：PNG, JPG, JPEG, WEBP, GIF - 支持相对路径和绝对路径 ### 3. 切换任务/重置配置 用户说： - "新建任务" - "切换 Token" - "重置配置" 清除当前保存的配置，然后返回步骤 1，重新请求 API Token。 ## 脚本说明 ### get_config.py - 获取配置 验证 API Token 并获取账户能力配置。 ```bash # 基本用法 python scripts/get_config.py --token "YOUR_API_TOKEN" # 指定自定义 API 地址 python scripts/get_config.py --token "YOUR_API_TOKEN" --api-url "https://custom.api.com" # 保存配置到文件 python scripts/get_config.py --token "YOUR_API_TOKEN" --output "config.json" ``` **返回字段：** - `success`: 是否成功 - `api_token`: API Token - `api_url`: API 地址 - `models`: 可用模型列表 - `default_model`: 默认模型 - `resolutions`: 支持的分辨率 - `default_resolution`: 默认分辨率 - `max_reference_images`: 最大参考图数量 - `max_reference_size_mb`: 参考图大小限制(MB) - `rate_limit_per_minute`: 每分钟出图限制 - `error`: 错误信息（如有） - `warning`: 警告信息（如有） ### generate_image.py - 生成图片 根据配置生成图片。 ```bash # 基本用法 python scripts/generate_image.py --token "TOKEN" --prompt "提示词" # 完整参数 python scripts/generate_image.py \ --token "TOKEN" \ --prompt "一只可爱的猫咪" \ --api-url "https://gnano.ihogmn.top" \ --model "gemini-3.1-flash-image-preview" \ --available-models "gemini-3.1-flash-image-preview,gemini-2.5-flash-image" \ --resolution "2K" \ --reference "ref1.png,ref2.png" \ --output "output.png" \ --max-ref 2 \ --max-ref-size 2 ``` **参数说明：** - `--token, -t`: API Token（必需） - `--prompt, -p`: 提示词（必需） - `--api-url, -u`: API 地址 - `--model, -m`: 模型名称（优先使用） - `--available-models`: 可用模型列表（逗号分隔，用于自动选择最佳模型） - `--resolution, -r`: 分辨率 (1K, 2K, 4K) - `--reference, -ref`: 参考图路径，多个用逗号分隔 - `--output, -o`: 输出图片路径 - `--max-ref`: 最大参考图数量 - `--max-ref-size`: 参考图大小限制(MB) - `--verbose, -v`: 输出详细日志 **返回字段：** - `success`: 是否成功 - `output_path`: 输出图片路径 - `model`: 使用的模型 - `mime_type`: 图片 MIME 类型 - `file_size`: 文件大小（字节） - `file_size_mb`: 文件大小（MB） - `references_used`: 使用的参考图数量 - `elapsed_time`: 生成耗时（秒） - `error`: 错误信息（如有） - `details`: 详细错误信息（如有） **进度输出（stderr）：** 脚本会输出 JSON 格式的进度信息到 stderr： ```json {"type": "progress", "message": "使用模型: gemini-3.1-flash-image-preview", "step": 1, "total": 5} {"type": "progress", "message": "正在生成图片，请稍候...", "step": 4, "total": 5} ``` ## 任务状态管理 任务状态可以保存在工作区的 `.workbuddy/gnano-tasks/` 目录下： ``` WORKSPACE/ └── .workbuddy/ └── gnano-tasks/ ├── {conversation_id}.json # 当前对话的任务状态 └── {other_conv_id}.json # 其他对话的任务状态 ``` 任务状态文件格式： ```json { "api_token": "your-token", "api_url": "https://gnano.ihogmn.top", "models": ["gemini-3.1-flash-image-preview"], "default_model": "gemini-3.1-flash-image-preview", "resolutions": ["1K", "2K", "4K"], "default_resolution": "2K", "max_reference_images": 2, "max_reference_size_mb": 2, "rate_limit_per_minute": 2, "supports_text_to_image": true, "supports_image_editing": true, "created_at": "2026-03-23T08:00:00", "updated_at": "2026-03-23T08:00:00", "last_accessed_at": "2026-03-23T08:00:00" } ``` 任务状态的读取和写入由 WorkBuddy 自动处理，无需额外脚本。 ## 完整对话示例 ### 示例 1: 新建任务并出图 **用户**: "我想用 GNano 出图" **助手**: "请提供您的 GNano API Token，我将根据您的账户配置获取可用功能。 如果您没有 Token，请访问 https://gnano.ihogmn.top 获取。" **用户**: "我的 Token 是 abc123" **助手**: ```bash python scripts/get_config.py --token "abc123" ``` "✅ 配置成功！您的账户支持以下功能： - 可用模型: gemini-3.1-flash-image-preview - 默认模型: gemini-3.1-flash-image-preview - 支持分辨率: 1K, 2K, 4K - 参考图限制: 最多2张，每张≤2MB - 速率限制: 每分钟2张 现在可以直接告诉我您想生成什么图片了！" **用户**: "出图：一只可爱的猫咪在草地上玩耍" **助手**: ```bash python scripts/generate_image.py --token "abc123" --prompt "一只可爱的猫咪在草地上玩耍" --model "gemini-3.1-flash-image-preview" --resolution "2K" --output "generated_cat.png" ``` [显示生成的图片] ### 示例 2: 使用参考图 **用户**: "参考图：woman.jpg，提示词：将外套脱掉" **助手**: ```bash python scripts/generate_image.py --token "abc123" --prompt "将外套脱掉" --reference "woman.jpg" --model "gemini-3.1-flash-image-preview" --resolution "2K" --output "result.png" ``` [显示生成的图片] ### 示例 3: 切换 Token **用户**: "我想换一个 Token" **助手**: "已清除当前配置。请提供新的 GNano API Token：" ## 依赖要求 ### 必需依赖 - **Python**: >= 3.8 - **requests**: >= 2.31.0 (用于 HTTP 请求) ### 安装方法 ```bash pip install requests ``` ## 安装 troubleshooting ### 问题：requests 模块找不到 **解决**: 安装依赖 ```bash pip install requests ``` ### 问题：Python 版本过低 **解决**: 升级 Python 到 3.8 或更高版本 ```bash # 检查版本 python --version ``` ## 注意事项 1. **所有回复使用中文** 2. **首次对话必须请求 API Token**，不能跳过 3. **同一任务内记住配置**，后续对话快速出图，无需重复输入 Token 4. **Token 仅保存在本地任务状态**，不对外传输 5. **支持相对路径和绝对路径**，自动转换 6. **严格遵守速率限制**，每分钟最多2张 7. **参考图限制**：最多2张，每张不超过2MB 8. **如果 Token 失效**，提示用户重新提供 ## 错误处理 ### Token 无效 ``` "❌ API Token 无效或已过期。请检查您的 Token 是否正确，或重新获取一个新的 Token。" ``` ### 请求过于频繁 ``` "⚠️ 请求过于频繁，请稍后再试。您的账户限制为每分钟2张图片。" ``` ### 参考图过大 ``` "⚠️ 参考图超过大小限制（2MB）。请压缩图片后重试。" ``` ### 网络错误 ``` "❌ 无法连接到 API 服务器。请检查网络连接后重试。" ```

path: pyproject.toml
content: [project]
name = "gnano-ihogmn"
version = "1.0.0"
description = "GNano Ihogmn 图片生成技能 - 支持动态 API 配置"
requires-python = ">=3.8"
dependencies = [
    "requests>=2.31.0",
]

[project.scripts]
gnano-generate = "scripts.generate_image:main"
gnano-config = "scripts.get_config:main"
gnano-task = "scripts.task_manager:main"

[tool.uv]
dev-dependencies = []


path: requirements.txt
content: requests>=2.31.0


path: scripts/generate_image.py
content: #!/usr/bin/env python3
"""
GNano Ihogmn 图片生成脚本
支持动态模型选择和参数配置
"""

import argparse
import base64
import json
import sys
import os
import time
from pathlib import Path
from typing import List, Optional, Tuple

try:
    import requests
except ImportError:
    print(json.dumps({
        "success": False,
        "error": "未找到 requests 模块。请安装: pip install requests"
    }, ensure_ascii=False))
    sys.exit(1)


DEFAULT_API_URL = "https://gnano.ihogmn.top"

RESOLUTION_MAP = {
    "1K": (1024, 1024),
    "2K": (2048, 2048),
    "4K": (4096, 4096)
}

MODEL_PERFORMANCE = {
    "gemini-3.1-flash-image-preview": 100,
    "gemini-2.5-flash-image": 90,
    "gemini-3-pro-image-preview": 70
}


def log_progress(message: str, step: int = None, total: int = None):
    """输出进度信息"""
    progress_data = {
        "type": "progress",
        "message": message,
        "timestamp": time.time()
    }
    if step is not None:
        progress_data["step"] = step
    if total is not None:
        progress_data["total"] = total
    
    print(json.dumps(progress_data, ensure_ascii=False), file=sys.stderr, flush=True)


def convert_to_absolute_path(image_path: str) -> str:
    """将路径转换为绝对路径"""
    if not image_path:
        return ""
    
    image_path = image_path.strip().strip('"').strip("'")
    path = Path(image_path)
    
    if not path.is_absolute():
        path = Path.cwd() / path
    
    abs_path = path.resolve()
    abs_path_str = str(abs_path)
    if os.name == 'nt':
        abs_path_str = abs_path_str.replace('\\', '/')
    
    return abs_path_str


def encode_image(image_path: str, max_size_mb: int = 2) -> Tuple[Optional[str], Optional[str]]:
    """将图片转换为 base64 编码"""
    abs_path = convert_to_absolute_path(image_path)
    path = Path(abs_path)
    
    if not path.exists():
        return None, f"参考图不存在: {abs_path}"
    
    file_size = path.stat().st_size
    max_size = max_size_mb * 1024 * 1024
    if file_size > max_size:
        return None, f"参考图超过{max_size_mb}MB限制"
    
    suffix = path.suffix.lower()
    if suffix in ['.png']:
        mime_type = "image/png"
    elif suffix in ['.jpg', '.jpeg']:
        mime_type = "image/jpeg"
    elif suffix in ['.webp']:
        mime_type = "image/webp"
    elif suffix in ['.gif']:
        mime_type = "image/gif"
    else:
        mime_type = "image/png"
    
    try:
        with open(path, "rb") as f:
            data = base64.b64encode(f.read()).decode("utf-8")
        return mime_type, data
    except Exception as e:
        return None, f"读取图片失败: {e}"


def build_api_url(api_url: str, model: str) -> str:
    """构建 API 请求 URL"""
    api_url = api_url.rstrip("/")
    return f"{api_url}/v1beta/models/{model}:generateContent"


def select_best_model(available_models: List[str], preferred_model: str = None) -> str:
    """选择最佳模型"""
    if preferred_model and preferred_model in available_models:
        return preferred_model
    
    scored_models = []
    for model in available_models:
        score = MODEL_PERFORMANCE.get(model, 50)
        scored_models.append((model, score))
    
    scored_models.sort(key=lambda x: x[1], reverse=True)
    return scored_models[0][0] if scored_models else "gemini-3.1-flash-image-preview"


def generate_image(
    token: str,
    prompt: str,
    api_url: str = None,
    model: str = None,
    available_models: List[str] = None,
    resolution: str = None,
    reference_paths: List[str] = None,
    output_path: str = None,
    max_reference_images: int = 2,
    max_reference_size_mb: int = 2,
    verbose: bool = False
) -> dict:
    """生成图片"""
    start_time = time.time()
    api_url = api_url or DEFAULT_API_URL
    
    if available_models:
        selected_model = select_best_model(available_models, model)
    else:
        selected_model = model or "gemini-3.1-flash-image-preview"
    
    log_progress(f"使用模型: {selected_model}", step=1, total=5)
    
    parts = [{"text": prompt}]
    
    loaded_references = []
    if reference_paths:
        log_progress(f"正在处理 {len(reference_paths)} 张参考图...", step=2, total=5)
        
        if len(reference_paths) > max_reference_images:
            log_progress(f"警告: 最多支持{max_reference_images}张参考图")
            reference_paths = reference_paths[:max_reference_images]
        
        for i, ref_path in enumerate(reference_paths, 1):
            abs_ref_path = convert_to_absolute_path(ref_path)
            mime_type, image_data = encode_image(abs_ref_path, max_reference_size_mb)
            
            if mime_type is None:
                log_progress(f"警告: 跳过参考图 {i}")
                continue
            
            parts.append({
                "inline_data": {
                    "mime_type": mime_type,
                    "data": image_data
                }
            })
            loaded_references.append(abs_ref_path)
            log_progress(f"已加载参考图 {i}/{len(reference_paths)}")
    
    generation_config = {
        "responseModalities": ["Text", "Image"]
    }
    
    if resolution and resolution in RESOLUTION_MAP:
        width, height = RESOLUTION_MAP[resolution]
        generation_config["imageConfig"] = {
            "width": width,
            "height": height
        }
        log_progress(f"设置分辨率: {resolution}", step=3, total=5)
    
    payload = {
        "contents": [{"parts": parts}],
        "generationConfig": generation_config
    }
    
    url = build_api_url(api_url, selected_model)
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {token}"
    }
    
    log_progress("正在生成图片，请稍候...", step=4, total=5)
    
    try:
        response = requests.post(url, headers=headers, json=payload, timeout=120)
    except requests.exceptions.Timeout:
        return {
            "success": False,
            "error": "请求超时，请稍后重试",
            "model": selected_model,
            "elapsed_time": time.time() - start_time
        }
    except requests.exceptions.RequestException as e:
        return {
            "success": False,
            "error": f"网络请求失败: {e}",
            "model": selected_model,
            "elapsed_time": time.time() - start_time
        }
    
    if response.status_code == 401:
        return {
            "success": False,
            "error": "API Token 无效或已过期",
            "model": selected_model,
            "elapsed_time": time.time() - start_time
        }
    elif response.status_code == 429:
        return {
            "success": False,
            "error": "请求过于频繁，请稍后再试",
            "model": selected_model,
            "elapsed_time": time.time() - start_time
        }
    elif response.status_code != 200:
        error_detail = ""
        try:
            error_json = response.json()
            if "error" in error_json:
                error_detail = error_json["error"].get("message", "")
        except:
            error_detail = response.text[:200]
        
        return {
            "success": False,
            "error": f"请求失败: {response.status_code}",
            "details": error_detail,
            "model": selected_model,
            "elapsed_time": time.time() - start_time
        }
    
    result = response.json()
    
    if "candidates" in result and len(result["candidates"]) > 0:
        candidate = result["candidates"][0]
        
        if "finishReason" in candidate:
            finish_reason = candidate["finishReason"]
            if finish_reason not in ["STOP", "MAX_TOKENS", "IMAGE"]:
                return {
                    "success": False,
                    "error": f"生成被中断: {finish_reason}",
                    "model": selected_model,
                    "elapsed_time": time.time() - start_time
                }
        
        if "content" in candidate and "parts" in candidate["content"]:
            for part in candidate["content"]["parts"]:
                if "inlineData" in part:
                    image_data = part["inlineData"]["data"]
                    mime_type = part["inlineData"].get("mimeType", "image/png")
                    
                    try:
                        image_bytes = base64.b64decode(image_data)
                    except Exception as e:
                        return {
                            "success": False,
                            "error": f"解码图片失败: {e}",
                            "model": selected_model,
                            "elapsed_time": time.time() - start_time
                        }
                    
                    if not output_path:
                        output_path = "generated_image.png"
                    
                    output_abs_path = convert_to_absolute_path(output_path)
                    
                    try:
                        output_dir = Path(output_abs_path).parent
                        if not output_dir.exists():
                            output_dir.mkdir(parents=True, exist_ok=True)
                        
                        with open(output_abs_path, "wb") as f:
                            f.write(image_bytes)
                        
                        elapsed = time.time() - start_time
                        log_progress(f"图片生成完成！耗时 {elapsed:.1f} 秒", step=5, total=5)
                        
                        return {
                            "success": True,
                            "output_path": output_abs_path,
                            "model": selected_model,
                            "mime_type": mime_type,
                            "file_size": len(image_bytes),
                            "file_size_mb": round(len(image_bytes) / 1024 / 1024, 2),
                            "references_used": len(loaded_references),
                            "elapsed_time": round(elapsed, 2)
                        }
                    except Exception as e:
                        return {
                            "success": False,
                            "error": f"保存图片失败: {e}",
                            "model": selected_model,
                            "elapsed_time": time.time() - start_time
                        }
                
                elif "text" in part:
                    text_content = part["text"]
                    log_progress(f"文本响应: {text_content}")
    
    return {
        "success": False,
        "error": "未找到生成的图片",
        "model": selected_model,
        "api_response": result,
        "elapsed_time": time.time() - start_time
    }


def main():
    parser = argparse.ArgumentParser(
        description="GNano Ihogmn 图片生成"
    )
    parser.add_argument("--token", "-t", required=True, help="API Token")
    parser.add_argument("--prompt", "-p", required=True, help="图片生成提示词")
    parser.add_argument("--api-url", "-u", default=DEFAULT_API_URL, help=f"API 地址")
    parser.add_argument("--model", "-m", help="模型名称")
    parser.add_argument("--available-models", help="可用模型列表，逗号分隔")
    parser.add_argument("--resolution", "-r", choices=["1K", "2K", "4K"], help="输出分辨率")
    parser.add_argument("--reference", "-ref", help="参考图路径，多个用逗号分隔")
    parser.add_argument("--output", "-o", default="generated_image.png", help="输出图片路径")
    parser.add_argument("--max-ref", type=int, default=2, help="最大参考图数量")
    parser.add_argument("--max-ref-size", type=int, default=2, help="参考图大小限制(MB)")
    parser.add_argument("--verbose", "-v", action="store_true", help="输出详细日志")
    
    args = parser.parse_args()
    
    reference_paths = None
    if args.reference:
        reference_paths = [p.strip() for p in args.reference.split(",") if p.strip()]
    
    available_models = None
    if args.available_models:
        available_models = [m.strip() for m in args.available_models.split(",") if m.strip()]
    
    result = generate_image(
        [REDACTED_SECRET],
        prompt=args.prompt,
        api_url=args.api_url,
        model=args.model,
        available_models=available_models,
        resolution=args.resolution,
        reference_paths=reference_paths,
        output_path=args.output,
        max_reference_images=args.max_ref,
        max_reference_size_mb=args.max_ref_size,
        verbose=args.verbose
    )
    
    print(json.dumps(result, ensure_ascii=False, indent=2))
    
    sys.exit(0 if result.get("success") else 1)


if __name__ == "__main__":
    main()


path: scripts/get_config.py
content: #!/usr/bin/env python3
"""
GNano Ihogmn 配置获取脚本
根据 API Token 获取账户可用功能和参数
"""

import argparse
import json
import sys
from pathlib import Path

try:
    import requests
except ImportError:
    print(json.dumps({
        "success": False,
        "error": "未找到 requests 模块。请安装: pip install requests"
    }, ensure_ascii=False))
    sys.exit(1)


DEFAULT_API_URL = "https://gnano.ihogmn.top"

KNOWN_MODELS = [
    "gemini-3-pro-image-preview",
    "gemini-3.1-flash-image-preview"
]


def detect_capabilities(api_url: str, token: str) -> dict:
    """探测 API 能力"""
    capabilities = {
        "api_url": api_url,
        "token_valid": False,
        "models": [],
        "default_model": None,
        "resolutions": ["1K", "2K", "4K"],
        "default_resolution": "2K",
        "max_reference_images": 2,
        "max_reference_size_mb": 2,
        "rate_limit_per_minute": 2,
        "supports_text_to_image": True,
        "supports_image_editing": True,
        "error": None
    }
    
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json"
    }
    
    models_url = f"{api_url}/v1beta/models"
    
    try:
        response = requests.get(models_url, headers=headers, timeout=30)
        
        if response.status_code == 200:
            result = response.json()
            capabilities["token_valid"] = True
            
            if "models" in result:
                for model in result["models"]:
                    model_name = model.get("name", "")
                    if "gemini" in model_name.lower() and "image" in model_name.lower():
                        model_id = model_name.split("/")[-1] if "/" in model_name else model_name
                        capabilities["models"].append(model_id)
            
            if not capabilities["models"]:
                capabilities["models"] = KNOWN_MODELS.copy()
                
        elif response.status_code == 401:
            capabilities["error"] = "API Token 无效或已过期"
            return capabilities
        elif response.status_code == 403:
            capabilities["error"] = "API Token 没有访问权限"
            return capabilities
        else:
            capabilities["token_valid"] = True
            capabilities["models"] = KNOWN_MODELS.copy()
            
    except requests.exceptions.RequestException as e:
        capabilities["token_valid"] = True
        capabilities["models"] = KNOWN_MODELS.copy()
        capabilities["error"] = f"无法连接到 API 服务器: {e}"
    
    if capabilities["models"]:
        if "gemini-3.1-flash-image-preview" in capabilities["models"]:
            capabilities["default_model"] = "gemini-3.1-flash-image-preview"
        else:
            capabilities["default_model"] = capabilities["models"][0]
    
    return capabilities


def get_full_config(token: str, api_url: str = None) -> dict:
    """获取完整的配置信息"""
    api_url = api_url or DEFAULT_API_URL
    api_url = api_url.rstrip("/")
    
    capabilities = detect_capabilities(api_url, token)
    
    if capabilities["error"] and not capabilities["token_valid"]:
        return {
            "success": False,
            "error": capabilities["error"],
            "api_url": api_url
        }
    
    return {
        "success": True,
        "api_token": token,
        "api_url": api_url,
        "models": capabilities["models"],
        "default_model": capabilities["default_model"],
        "resolutions": capabilities["resolutions"],
        "default_resolution": capabilities["default_resolution"],
        "max_reference_images": capabilities["max_reference_images"],
        "max_reference_size_mb": capabilities["max_reference_size_mb"],
        "rate_limit_per_minute": capabilities["rate_limit_per_minute"],
        "supports_text_to_image": capabilities["supports_text_to_image"],
        "supports_image_editing": capabilities["supports_image_editing"],
        "warning": capabilities.get("error")
    }


def main():
    parser = argparse.ArgumentParser(
        description="获取 GNano API 配置信息"
    )
    parser.add_argument("--token", "-t", required=True, help="API Token")
    parser.add_argument("--api-url", "-u", default=DEFAULT_API_URL, help="API 地址")
    
    args = parser.parse_args()
    
    config = get_full_config(args.token, args.api_url)
    
    print(json.dumps(config, ensure_ascii=False, indent=2))
    
    sys.exit(0 if config.get("success") else 1)


if __name__ == "__main__":
    main()


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)