{“content”:”---\nname: minimax-image-gen\ndescription: MiniMax image-01 text-to-image generation via REST API — correct endpoint, request format, and download workflow\ntriggers:\n - generate image via minimax\n - minimax image-01 api\n - minimax image generation endpoint\n---\n\n# MiniMax image-01 Image Generation API\n\n## Overview\nMiniMax provides an image generation model called image-01 accessible via a dedicated REST endpoint. This is separate from the chat completions API.\n\n## API Details\n\n| Item | Value |\n|------|-------|\n| Base URL | https://api.minimax.io/v1 |\n| Image Endpoint | POST /v1/image_generation |\n| Auth | Authorization: Bearer <API_KEY> |\n| Model name | image-01 |\n\n## Common Mistakes to Avoid\n\n❌ POST /v1/images/generations — This is OpenAI’s endpoint, not MiniMax’s\n❌ POST /v1/chat/completions with model image-01 — Returns unknown model error\n❌ POST /v1/image_generations (with ‘s’) — 404 not found\n\n✅ POST /v1/image_generation (no ‘s’)\n\n## Request Format\n\npython\nimport urllib.request, json\n\nAPI_KEY = \"sk-cp-...\" # Your MiniMax API key (OpenAI-compatible key format)\n\npayload = json.dumps({\n \"model\": \"image-01\",\n \"prompt\": \"A beautiful watercolor forest scene\",\n \"response_format\": \"url\", # \"url\" returns temp OSS download URLs\n \"n\": 1, # number of images to generate (1-4)\n \"prompt_optimizer\": False # MUST be False for precise asset generation\n}).encode()\n\nreq = urllib.request.Request(\n \"https://api.minimax.io/v1/image_generation\",\n data=payload,\n headers={\n \"Authorization\": f\"Bearer {API_KEY}\",\n \"Content-Type\": \"application/json\"\n },\n method=\"POST\"\n)\n\nwith urllib.request.urlopen(req, timeout=120) as resp:\n result = json.loads(resp.read())\n\n\n## Response Format — CORRECTED (2026-04-22 verified)\n\n❌ WRONG in older docs: result[\"data\"][\"images\"][0][\"url\"] → KeyError\n❌ WRONG in older docs: result[\"data\"][\"image_urls\"][0][\"url\"] → TypeError (string has no .url)\n\n✅ ACTUAL working response — image_urls is a list of string URLs directly:\n\njson\n{\n \"id\": \"0637c17ac9876db883d6a46c37cc6746\",\n \"data\": {\n \"image_urls\": [\n \"http://hailuo-image-algeng-data-us.oss-us-east-1.aliyuncs.com/image_inference_output/talkie/prod/img/2026-04-22/xxx_aigc.jpeg?Expires=1776934921&OSSAccessKeyId=LTAI5tRDTcyEYLLuBEpJRwCi&Signature=vXyTxt4...\"\n ]\n },\n \"base_resp\": {\n \"status_code\": 0,\n \"status_msg\": \"success\"\n }\n}\n\n\nKey extraction — it’s a string list, NOT an object list:\npython\nimg_url = result[\"data\"][\"image_urls\"][0] # returns string directly\n\n\n## Image Download\n\nThe URL returned is a temporary OSS (Aliyun) signed URL that expires quickly. Download immediately:\n\npython\nimg_url = result[\"data\"][\"image_urls\"][0]\nreq2 = urllib.request.Request(img_url)\nwith urllib.request.urlopen(req2, timeout=60) as r:\n img_data = r.read()\nwith open(\"output.png\", \"wb\") as f:\n f.write(img_data)\n\n\n## execute_code Sandbox — Files Are NOT Persistent ⚠️\n\nEach execute_code invocation runs in a different temp directory (/data/data/com.termux/files/usr/tmp/hermes_sandbox_XXXX/). Files written there are LOST after the call.\n\nAlways save to a persistent path:\npython\nOUT = '/data/data/com.termux/files/home/downloads'\nos.makedirs(OUT, exist_ok=True)\npath = f'{OUT}/filename.png'\nwith open(path, 'wb') as f:\n f.write(content)\n\n\n## SCP Upload to Windows PC — No Auto-Mkdir ⚠️\n\nSCP does NOT auto-create remote directories. Use PowerShell over SSH first:\n\nbash\nKEY=\"-i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=no\"\nPC=\"[email protected]\"\nssh $KEY $PC \"powershell -Command \\\"New-Item -ItemType Directory -Force -Path 'D:\\\\games\\\\path\\\\to\\\\dir' | Out-Null\\\"\" 2>&1 | grep -v Warning\nscp $KEY local.png \"$PC:D:/games/EchoesOfTheGreen/assets/items/\" 2>&1 | tail -1\n\n\nNote: SCP remote path uses $PC:D:/path/ syntax, forward slashes, and $PC: format (not user@host:/path).\n\n## MiniMax Vision API — IMPORTANT (2026-05-04)\n\nVision 是 Token Plan MCP 的付费专属功能,不是标准 API。\n\n### Termux DNS Issue\n- vision.minimax.chat 无法在 Termux 解析(DNS 失败)\n- api.minimax.io 可以连通(chat/image 都通)\n- 但 vision 端点在 api.minimax.io 上返回 404\n\n### 标准 API Key (sk-cp-xxx) 支持的能力\n| 能力 | 端点 | 状态 |\n|------|------|------|\n| 文字 chat | POST /v1/chat/completions | ✅ 可用(需确认 model 在 plan 内) |\n| 图片生成 | POST /v1/image_generation | ✅ 可用(model: image-01) |\n| 图片理解 | Token Plan MCP 专属 | ❌ 标准 API Key 不支持 |\n\n### Vision 替代方案\n如需图片理解,用以下免费 API:\n- Gemini: POST /v1beta/models/gemini-1.5-flash:generateContent + image\n- Claude: POST /v1/messages + image(免费 tier 有额度)\n\n### 当前 API Key 状态 (2026-05-04)\n- Key: sk-cp-Ghu-...(已在 memory)\n- Chat: ❌ MiniMax-Text-01 不在当前 plan 内(2061 error)\n- Image Gen: ✅ image-01 works\n\n## Troubleshooting\n\n| Error | Cause | Fix |\n|-------|-------|-----|\n| unknown model: image-01 via chat completions | Wrong endpoint | Use POST /v1/image_generation |\n| HTTP 404 on /v1/images/generations | Wrong endpoint name | Use /v1/image_generation (no ‘s’) |\n| HTTP 401 Incorrect API key | Key wrong or expired | Check your API key in MiniMax dashboard |\n| KeyError: 'images' on response | Wrong response key | Use image_urls[0] (list of strings, not objects) |\n| TypeError: string indices | Wrong nested path | Use result[\"data\"][\"image_urls\"][0] directly |\n| SCP upload fails “No such file or directory” | Remote dir doesn’t exist | Pre-create with PowerShell New-Item |\n| vision.minimax.chat DNS failure | Termux DNS 无法解析 | 用 Gemini/Claude vision 替代 |\n| vision HTTP 404 on api.minimax.io | vision 不是标准 API | vision 是 Token Plan MCP 专属功能 |\n\n## Verified Asset Prompts (2026-04-22, all succeeded)\n\nThese prompts generated working watercolor RPG assets:\n\n| Asset | Prompt (abbreviated) | Output |\n|-------|---------------------|--------|\n| Character | \"hand-painted watercolor RPG character sprite, young adventurer in green forest, gentle idle pose, warm earth tones, transparent background, top-down view\" | player_art.png (262KB) |\n| Background | \"hand-painted watercolor illustration of a lush green fantasy forest, soft brushstrokes, warm earth tones, misty atmosphere, seamless tileable background\" | forest_bg.png (445KB) |\n| Item potion | \"hand-painted watercolor RPG item sprite, elegant glass bottle with glowing red health potion, warm light rays, transparent background, top-down game asset\" | item_health_potion.png (195KB) |\n| Item mana | \"hand-painted watercolor RPG item sprite, crystal glass bottle filled with glowing blue mana potion, magical sparkles, transparent background, top-down game asset\" | item_mana_potion.png (200KB) |\n| Tile grass | \"seamless hand-painted watercolor game background tile, lush green grass with small wildflowers, soft natural tones, RPG fantasy forest floor, top-down view\" | tile_grass.png (552KB) |\n| Tile tree | \"hand-painted watercolor fantasy game tile, large ancient tree with thick trunk and lush green canopy, misty forest atmosphere, top-down view\" | tile_tree.png (638KB) |\n| Object rock | \"hand-painted watercolor RPG game object, ancient mossy stone boulder, fantasy forest setting, warm earth tones, transparent background, top-down view\" | obj_rock.png (379KB) |\n| UI frame | \"hand-painted watercolor RPG UI frame, ornate wooden dialog box border with golden trim, fantasy parchment interior, game interface element, transparent background\" | ui_dialog_frame.png (370KB) |\n| FX effect | \"hand-painted watercolor RPG magic effect, green energy slash with floating leaf particles, fantasy forest theme, transparent background, top-down action game\" | fx_attack_slash.png (351KB) |\n| Coin/item | \"hand-painted watercolor game asset, small glowing yellow star coins, magical warm golden light, transparent background, top-down RPG collectible item\" | item_coin.png (226KB) |\n| NPC | \"hand-painted watercolor RPG game character, wise elderly merchant with hat and wooden walking stick, friendly smile, warm earth tones, transparent background, top-down character sprite, friendly NPC\" | npc_merchant.png (302KB) |\n\n## MiniMax Music Generation (mmx CLI)\n\nMiniMax music generation is done via the mmx CLI tool (not REST API), available at /data/data/com.termux/files/usr/bin/mmx.\n\nbash\n# Basic music generation with lyrics\nmmx music generate \\\n --prompt \"Warm acoustic ballad, mandopop, male vocalist\" \\\n --lyrics-file song_lyrics.txt \\\n --vocals \"warm male vocal, gentle\" \\\n --genre \"folk ballad\" \\\n --mood \"warm, comforting\" \\\n --out output.mp3\n\n# Key flags:\n# --prompt Music style description (max 2000 chars)\n# --lyrics <text> Song lyrics with structure tags: [Verse], [Chorus], [Bridge], etc.\n# --lyrics-file Read lyrics from file\n# --vocals Vocal style description\n# --genre Music genre (folk, pop, jazz, etc.)\n# --mood Mood (warm, melancholic, uplifting, etc.)\n# --instruments Instruments to feature\n# --bpm <number> Exact tempo\n# --model Model: music-2.6 (recommended), music-2.6-free (default, unlimited), music-2.5+, music-2.5\n# --out Output file path\n# --output-format hex (default, saves to file) or url (24h expiry)\n\n# Models: music-2.6 is recommended; music-2.6-free is unlimited but lower quality\n# Lyrics structure tags: [Verse], [Pre-Chorus], [Chorus], [Bridge], [Interlude], [Outro]\n\n\n## YouTube Upload via OAuth2 + Data API v3\n\n### OAuth2 PKCE Flow (for YouTube scope)\n\nThe standard google_oauth_direct.py does NOT include YouTube scope. Use the custom script:\n\nbash\n# Step 1: Get auth URL (prints URL to visit)\npython3 ~/.hermes/youtube_oauth.py\n\n# Step 2: User visits URL, pastes redirect URL\npython3 ~/.hermes/youtube_oauth.py \"http://localhost:1/?code=xxx...\"\n\n# Token saved to: ~/.hermes/google_token_youtube.json\n\n\nKey lesson: authorization codes are single-use. If exchange fails, generate a new auth URL.\n\n### YouTube Resumable Upload (Python only, no google-api-python-client)\n\npython\nimport urllib.request, json\n\nwith open('~/.hermes/google_token_youtube.json') as f:\n token = json.load(f)\naccess_token = token[\"token\"]\n\n# 1. Initiate resumable upload\nmetadata = {\n \"snippet\": {\"title\": \"...\", \"description\": \"...\", \"tags\": [...], \"categoryId\": \"10\"},\n \"status\": {\"privacyStatus\": \"public\", \"selfDeclaredMadeForKids\": False}\n}\nmetadata_json = json.dumps(metadata).encode()\n\ninit_req = urllib.request.Request(\n \"https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=snippet,status\",\n data=metadata_json,\n headers={\n \"Authorization\": f\"Bearer {access_token}\",\n \"Content-Type\": \"application/json\",\n \"X-Upload-Content-Length\": str(len(video_data)),\n \"X-Upload-Content-Type\": \"video/mp4\",\n },\n method=\"POST\"\n)\nwith urllib.request.urlopen(init_req, timeout=30) as resp:\n upload_url = resp.headers.get(\"Location\")\n\n# 2. Upload video data\nwith open(\"video.mp4\", \"rb\") as f:\n video_data = f.read()\n\nreq = urllib.request.Request(upload_url, data=video_data, headers={\n \"Authorization\": f\"Bearer {access_token}\",\n \"Content-Type\": \"video/mp4\",\n \"Content-Length\": str(len(video_data)),\n}, method=\"PUT\")\nwith urllib.request.urlopen(req, timeout=300) as resp:\n result = json.loads(resp.read())\nvideo_id = result[\"id\"] # e.g. \"1gnVjNtfCE8\"\n\n\n## SRT Lyric Subtitles Timing\n\nMiniMax-generated music has unknown lyric timing — estimated SRT timestamps will NOT match. For precise sync:\n- Use Whisper to transcribe the audio and get word-level timestamps\n- Then generate SRT from Whisper output\n- Alternative: accept approximate sync with shorter display durations\n\n## See Also\n- GitHub: zients/minimax-sdk — Official Python/TS SDK supporting image, video, speech, music\n- Platform docs: https://platform.minimaxi.com/docs/api-reference/image-generation\n”}