最近天天都在学习claude code,Skills == 工具箱(技能库)
我们可以把skills看成是一个个的小程序,这些程序有入口,有参数,有限制。
那通过一篇md文件,来引导claude来智能的传参调用你的程序,这样技能箱就越来越丰富。
一、我们首先准备这个可执行 python 脚本 这个是通过CLIProxyAPI的反代,把antigravity的gemini3模型给抽出来,然后生图
看最下面,有一堆参数
#!/usr/bin/env python3 # ============================================================ # Configuration - Edit these values before use # 配置项 - 使用前请修改以下值 # ============================================================ API_BASE_URL = "http://127.0.0.1:8317" # API server address / API 服务器地址 API_KEY = "key" # Your API key / 你的 API 密钥 MODEL = "gemini-3-pro-image-preview" # Model name / 模型名称 # ============================================================ import argparse import base64 import json import os import sys from datetime import datetime from pathlib import Path from urllib import request from mimetypes import guess_type try: from google import genai from google.genai import types except ImportError: genai = None types = None VALID_ASPECT_RATIOS = ["1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9"] VALID_RESOLUTIONS = ["1K", "2K", "4K"] def _resolve_output_dir(output_dir: str, mkdir: bool) -> str: if os.path.isdir(output_dir): return output_dir if mkdir: os.makedirs(output_dir, exist_ok=True) return output_dir print(f"Warning: Output directory not found: {output_dir}. Saving to current directory.") return "." def _build_filename(output_name: str | None, timestamp: str, index: int, default_ext: str) -> str: if output_name: root, ext = os.path.splitext(output_name) if not ext: ext = default_ext suffix = f"_{index}" if index > 0 else "" return f"{root}{suffix}{ext}" return f"generated_{timestamp}_{index}{default_ext}" def _load_image_inline(image_path: str) -> dict: mime_type, _ = guess_type(image_path) if mime_type is None: mime_type = "image/png" data = Path(image_path).read_bytes() return {"inlineData": {"mimeType": mime_type, "data": base64.b64encode(data).decode("ascii")}} def _post_json(url: str, body: dict) -> dict: data = json.dumps(body).encode("utf-8") req = request.Request( url, data=data, headers={"Content-Type": "application/json", "x-goog-api-key": API_KEY}, ) resp = request.urlopen(req).read() return json.loads(resp) def _save_images(parts, output_dir: str, select: str, output_name: str | None, mkdir: bool) -> list[str]: imgs = [p["inlineData"] for p in parts if "inlineData" in p] if not imgs: return [] if select == "first": imgs = imgs[:1] elif select == "last": imgs = imgs[-1:] elif select == "max_res": imgs = imgs[-1:] ts = datetime.now().strftime("%Y%m%d_%H%M%S") output_dir = _resolve_output_dir(output_dir, mkdir) saved = [] for i, img in enumerate(imgs): data = base64.b64decode(img["data"]) ext = "jpg" if img.get("mimeType", "").endswith("jpeg") else "png" filename = _build_filename(output_name, ts, i, f".{ext}") path = Path(output_dir) / filename path.write_bytes(data) saved.append(str(path)) return saved def _sdk_generate(prompt: str, output_dir: str, aspect_ratio: str, resolution: str, input_image: str | None, output_name: str | None, mkdir: bool, select: str) -> list[str]: if genai is None or types is None: print("Error: google-genai is not installed.") return [] client_kwargs = {"api_key": API_KEY} if API_BASE_URL: client_kwargs["http_options"] = {"base_url": API_BASE_URL} client = genai.Client(**client_kwargs) if input_image: if not Path(input_image).exists(): print(f"Error: Input image not found: {input_image}") return [] with open(input_image, "rb") as f: image_bytes = f.read() mime_type, _ = guess_type(input_image) if mime_type is None: mime_type = "image/png" image_part = types.Part.from_bytes(data=image_bytes, mime_type=mime_type) contents = [prompt, image_part] else: contents = prompt try: response = client.models.generate_content( model=MODEL, contents=contents, config=types.GenerateContentConfig( image_config=types.ImageConfig( aspectRatio=aspect_ratio, imageSize=resolution, ) ), ) except Exception as exc: print(f"API Error: {exc}") return [] saved = [] ts = datetime.now().strftime("%Y%m%d_%H%M%S") output_dir = _resolve_output_dir(output_dir, mkdir) image_parts = [] for part in response.parts: if part.text is not None: print(f"Response text: {part.text}") elif image := part.as_image(): image_parts.append(image) if not image_parts: return [] if select == "first": image_parts = image_parts[:1] elif select == "last": image_parts = image_parts[-1:] elif select == "max_res": image_parts = [max(image_parts, key=lambda x: len(x.image_bytes))] for i, image in enumerate(image_parts): filename = _build_filename(output_name, ts, i, ".png") path = Path(output_dir) / filename image.save(path) saved.append(str(path)) return saved def _http_generate(prompt: str, output_dir: str, aspect_ratio: str, resolution: str, input_image: str | None, select: str, output_name: str | None, mkdir: bool) -> list[str]: if input_image and not Path(input_image).exists(): print(f"Error: Input image not found: {input_image}") return [] url = f"{API_BASE_URL.rstrip('/')}/v1beta/models/{MODEL}:generateContent" parts = [{"text": prompt}] if input_image: parts.append(_load_image_inline(input_image)) body = { "contents": [{"parts": parts}], "generationConfig": { "responseModalities": ["TEXT", "IMAGE"], "imageConfig": {"aspectRatio": aspect_ratio, "imageSize": resolution}, }, } try: resp = _post_json(url, body) except Exception as exc: print(f"API Error: {exc}") return [] if "candidates" not in resp: print(f"Unexpected response: {resp}") return [] parts_out = resp["candidates"][0]["content"]["parts"] return _save_images(parts_out, output_dir, select, output_name, mkdir) def main(): parser = argparse.ArgumentParser(description="Generate images via SDK or HTTP") parser.add_argument("prompt", nargs="*", help="Image description prompt") parser.add_argument("--mode", default="sdk", choices=["sdk", "http"]) parser.add_argument("--aspect-ratio", "-a", default="16:9", choices=VALID_ASPECT_RATIOS) parser.add_argument("--resolution", "-r", default="4K", choices=VALID_RESOLUTIONS) parser.add_argument("--output-dir", "-o", default=".") parser.add_argument("--output-name", default=None) parser.add_argument("--mkdir", action="store_true") parser.add_argument("--input-image", "-i", default=None) parser.add_argument("--select", default="all", choices=["all", "first", "last", "max_res"]) args = parser.parse_args() if not args.prompt: parser.print_help() sys.exit(1) prompt = " ".join(args.prompt) if args.mode == "sdk": saved = _sdk_generate( prompt=prompt, output_dir=args.output_dir, aspect_ratio=args.aspect_ratio, resolution=args.resolution, input_image=args.input_image, output_name=args.output_name, mkdir=args.mkdir, select=args.select, ) else: saved = _http_generate( prompt=prompt, output_dir=args.output_dir, aspect_ratio=args.aspect_ratio, resolution=args.resolution, input_image=args.input_image, select=args.select, output_name=args.output_name, mkdir=args.mkdir, ) if saved: print(f"Generated {len(saved)} image(s):") for f in saved: print(f" - {Path(f).resolve()}") else: print("No images were generated.") sys.exit(1) if __name__ == "__main__": main() 基本用法:
...