{
  "schemaVersion": "1.0",
  "item": {
    "slug": "ima-voice-ai",
    "name": "AI Music Generation",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/allenfancy-gan/ima-voice-ai",
    "canonicalUrl": "https://clawhub.ai/allenfancy-gan/ima-voice-ai",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/ima-voice-ai",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=ima-voice-ai",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "_meta.json",
      "requirements.txt",
      "clawhub.json",
      "SKILL.md",
      "scripts/ima_logger.py",
      "scripts/ima_voice_create.py"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "slug": "ima-voice-ai",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-29T03:31:08.814Z",
      "expiresAt": "2026-05-06T03:31:08.814Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=ima-voice-ai",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=ima-voice-ai",
        "contentDisposition": "attachment; filename=\"ima-voice-ai-1.0.14.zip\"",
        "redirectLocation": null,
        "bodySnippet": null,
        "slug": "ima-voice-ai"
      },
      "scope": "item",
      "summary": "Item download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this item.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/ima-voice-ai"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/ima-voice-ai",
    "agentPageUrl": "https://openagent3.xyz/skills/ima-voice-ai/agent",
    "manifestUrl": "https://openagent3.xyz/skills/ima-voice-ai/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/ima-voice-ai/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Scope & Dependencies (Declared for Transparency)",
        "body": "Credentials: This skill requires an IMA API key at runtime (IMA_API_KEY or --api-key). The key is sent only to api.imastudio.com. Obtain keys at https://imastudio.com. Declared in registry as required.\nOptional dependency: When ima-knowledge-ai is installed, this skill may instruct the agent to read that skill's reference files (~/.openclaw/skills/ima-knowledge-ai/references/*) for workflow and model-selection guidance. This skill is self-contained — it works fully without ima-knowledge-ai. Reading another skill's files is optional and only for complex or multi-step tasks; users who do not have or trust ima-knowledge-ai can ignore those steps and use this skill's built-in defaults and 📥 User Input Parsing tables.\nLocal paths: This skill reads/writes ~/.openclaw/memory/ima_prefs.json (preferences) and ~/.openclaw/logs/ima_skills/ (logs; auto-deleted after 7 days). User can delete these anytime."
      },
      {
        "title": "Optional: Read Knowledge Base (When ima-knowledge-ai Is Installed)",
        "body": "If ima-knowledge-ai is not installed: Skip this section. Use only this SKILL's default models and the 📥 User Input Parsing tables for model_id and parameters.\n\nWhen ima-knowledge-ai is installed and the task is complex, you may optionally read its reference files for better workflow and model choice:\n\nWorkflow complexity — Read ima-knowledge-ai/references/workflow-design.md if:\n\nUser mentions: \"MV\"、\"配乐\"、\"完整作品\"、\"多步骤\"、\"soundtrack\"\nTask involves: video + music coordination, multi-track production, integrated workflows\nComplex requirements that need task decomposition\n\n\n\nModel selection — Read ima-knowledge-ai/references/model-selection.md if:\n\nUnsure which model to use (Suno vs DouBao BGM vs DouBao Song)\nNeed cost/quality trade-off guidance\nUser specifies budget or quality requirements\n\nWhy this is optional:\n\nMusic generation is often part of a larger workflow (video + music, story + soundtrack)\nFor simple single-track requests, proceed directly with this skill's defaults\nFor complex workflows, reading the knowledge base can improve task decomposition and model choice\n\nExample workflow case (when using optional knowledge base):\n\nUser: \"帮我做个产品宣传MV，有背景音乐\"\n\n❌ Wrong: 直接生成音乐 (music alone, no coordination with video)\n\n✅ Right (if ima-knowledge-ai available): \n  1. Read workflow-design.md\n  2. Decompose: Script → Video shots → Background music (matching video duration/mood)\n  3. Generate video first (get duration)\n  4. Generate BGM with matching duration and style\n\nHow to check (optional):\n\n# Only if ima-knowledge-ai is installed and task is complex\nif ima_knowledge_ai_installed and (complex_workflow or multi_step):\n    read(\"~/.openclaw/skills/ima-knowledge-ai/references/workflow-design.md\")\n\nif ima_knowledge_ai_installed and unsure_model_choice:\n    read(\"~/.openclaw/skills/ima-knowledge-ai/references/model-selection.md\")\n\n# Choose model (this skill's logic works with or without knowledge base)\nif \"background music\" or \"BGM\" or \"instrumental\":\n    use_doubao_bgm()  # 30pts, pure instrumental\nelif \"song\" or \"lyrics\" or \"vocals\":\n    use_suno_sonic()  # 25pts, full-featured with lyrics\nelse:\n    use_suno_sonic()  # Default: most versatile\n\nFor simple requests: Proceed directly with this skill's defaults. No need to read other skills' files."
      },
      {
        "title": "📥 User Input Parsing (Model & Parameter Recognition)",
        "body": "Purpose: So that any agent (Claude or other models) parses user intent consistently, follow these rules when deriving model_id and task type from natural language. Normalize first, then map."
      },
      {
        "title": "1. User phrasing → model selection (model_id)",
        "body": "User intent / phrasingmodel_idNotesBGM / 背景音乐 / 纯音乐 / 无人声 / instrumental / 配乐GenBGMDouBao BGM, 30 pts, ~30s歌 / 歌曲 / 带歌词 / 人声 / song / lyrics / 有唱sonic or GenSongSuno (25 pts, ~2min) or DouBao Song (30 pts, ~30s)Suno / 苏诺 / sonicsonicFull-featured, lyrics, vocal_gender, 25 pts豆包 BGM / DouBao BGM / BGMGenBGM30 pts豆包 歌曲 / DouBao Song / 豆包歌GenSong30 pts最便宜 / 最省钱 / cheapest / budgetGenBGM or GenSong (6 pts 档 if available)Only if user explicitly asks for cheapest最好 / 最全功能 / best / 带歌词可调sonicSuno default\n\nIf the user does not specify, default to Suno (sonic) for versatility. For \"背景音乐\"/\"BGM\"/\"配乐\" only → use DouBao BGM (GenBGM)."
      },
      {
        "title": "2. Music-specific parameters (Suno)",
        "body": "User says (examples)ParameterAction无人声 / 纯音乐 / no vocals / instrumentalmake_instrumentaltrue女声 / 女声演唱 / female vocalsvocal_gender\"female\" (custom_mode true)男声 / 男声演唱 / male vocalsvocal_gender\"male\" (custom_mode true)我写歌词 / 自定义歌词 / custom lyricscustom_mode + lyricsProvide lyrics in request\n\nWhen using Suno with lyrics or vocal control, set custom_mode: true and pass lyrics / vocal_gender per API docs."
      },
      {
        "title": "⚙️ How This Skill Works",
        "body": "For transparency: This skill uses a bundled Python script (scripts/ima_voice_create.py) to call the IMA Open API. The script:\n\nSends your prompt to https://api.imastudio.com (IMA's servers)\nUses --user-id only locally as a key for storing your model preferences\nReturns a music URL when generation is complete\nNEW (v1.1.0): Automatic reflection mechanism — if generation fails, the script automatically retries up to 3 times with smart parameter adjustments"
      },
      {
        "title": "🧠 Reflection Mechanism (Automatic Error Recovery)",
        "body": "This skill now includes an intelligent reflection system that automatically recovers from common errors:\n\n3-Layer Retry Strategy:\n\nAttempt 1: Original Parameters\n\nUses your provided parameters with smart credit_rule selection\nMost tasks succeed on first try\n\n\n\nAttempt 2: Strict Match (Error 6009 Fix)\n\nAutomatically removes unsupported parameters\nOnly keeps parameters in credit_rules.attributes\nExample: Removes unsupported Suno parameters if not in model config\n\n\n\nAttempt 3: Fallback to Default (Error 6010 Fix)\n\nUses model's default configuration\nUses credit_rules[0] (first rule = safest default)\nGuarantees maximum compatibility\n\nCommon Errors Fixed Automatically:\n\nError 6009: \"No exact rule match found for parameters\" → removes unsupported params\nError 6010: \"Attribute ID does not match\" → corrects attribute_id to match params\nInvalid product attribute: Uses default rule configuration\n\nUser Experience:\n\n✅ Transparent: Shows reflection log when retries happen\n✅ Fast: Most tasks succeed on first attempt (no delay)\n✅ Smart: Learns from errors and adjusts automatically\n✅ User-friendly: Provides helpful suggestions if all 3 attempts fail\n\nExample Output (with reflection):\n\n🚀 Creating music generation task…\n\n🧠 反省日志 (2 次尝试):\n   ❌ [尝试 1] Invalid product attribute → 移除不支持的参数: ['unsupported_param']\n   ✅ [尝试 2] ✅ 成功（尝试 2）\n\n✅ Task created: task_abc123xyz\n\nWhat gets sent to IMA servers:\n\n✅ Your music prompt/description\n✅ Model selection (Suno/DouBao)\n❌ NO API key in prompts (key is used for authentication only)\n❌ NO user_id (it's only used locally)\n\nWhat's stored locally:\n\n~/.openclaw/memory/ima_prefs.json - Your model preferences (< 1 KB)\n~/.openclaw/logs/ima_skills/ - Generation logs (auto-deleted after 7 days)"
      },
      {
        "title": "Agent Execution (Internal Reference)",
        "body": "Note for users: You can review the script source at scripts/ima_voice_create.py anytime.\nThis skill uses only api.imastudio.com (no image upload needed for music generation, unlike image/video skills which also use imapi.liveme.com).\n\nUse the bundled script internally:\n\n# Generate music — Suno sonic-v5\npython3 {baseDir}/scripts/ima_voice_create.py \\\n  --api-key  $IMA_API_KEY \\\n  --task-type text_to_music \\\n  --model-id  sonic \\\n  --prompt   \"upbeat lo-fi hip hop, 90 BPM, no vocals\" \\\n  --user-id  {user_id} \\\n  --output-json\n\n# DouBao BGM\npython3 {baseDir}/scripts/ima_voice_create.py \\\n  --api-key  $IMA_API_KEY \\\n  --model-id  GenBGM \\\n  --prompt   \"calm ambient piano background\" \\\n  --user-id  {user_id} \\\n  --output-json\n\nThe script outputs JSON — parse it to get the result URL and pass it to the user via the UX protocol messages below."
      },
      {
        "title": "Overview",
        "body": "Call IMA Open API to create AI-generated music/audio. All endpoints require an ima_* API key. The core flow is: query products → create task → poll until done."
      },
      {
        "title": "🔒 Security & Transparency Policy",
        "body": "This skill is community-maintained and open for inspection."
      },
      {
        "title": "🌐 Network Architecture",
        "body": "This skill uses a simpler network architecture than image/video skills:\n\nSkill TypeDomains UsedWhyima-voice-ai (this skill)✅ api.imastudio.com onlyMusic generation doesn't require image uploadsima-image-ai, ima-video-aiapi.imastudio.com + imapi.liveme.comImage/video tasks need image upload service\n\nWhy the difference?\n\nMusic generation (text_to_music) only needs text prompts → single API endpoint\nImage/video generation (i2i, i2v tasks) needs image file uploads → requires separate upload service\n\nSecurity verification:\n\n# Verify this skill only uses api.imastudio.com:\ngrep -n \"https://\" scripts/ima_voice_create.py\n\n# Expected output:\n# Only https://api.imastudio.com (no imapi.liveme.com)"
      },
      {
        "title": "✅ What Users CAN Do",
        "body": "Full transparency:\n\n✅ Review all source code: Check scripts/ima_voice_create.py and ima_logger.py anytime\n✅ Verify network calls: This skill uses only api.imastudio.com (music generation doesn't require image uploads). Verify by running: grep -n \"https://\" scripts/ima_voice_create.py\n✅ Inspect local data: View ~/.openclaw/memory/ima_prefs.json and log files\n✅ Control privacy: Delete preferences/logs anytime, or disable file writes (see below)\n\nConfiguration allowed:\n\n✅ Set API key in environment or agent config:\n\nEnvironment variable: export IMA_API_KEY=ima_your_key_here\nOpenClaw/MCP config: Add IMA_API_KEY to agent's environment configuration\nGet your key at: https://imastudio.com\n\n\n✅ Use scoped/test keys: Test with limited API keys, rotate after testing\n✅ Disable file writes: Make prefs/logs read-only or symlink to /dev/null\n\nData control:\n\n✅ View stored data: cat ~/.openclaw/memory/ima_prefs.json\n✅ Delete preferences: rm ~/.openclaw/memory/ima_prefs.json (resets to defaults)\n✅ Delete logs: rm -rf ~/.openclaw/logs/ima_skills/ (auto-cleanup after 7 days anyway)"
      },
      {
        "title": "⚠️ Advanced Users: Fork & Modify",
        "body": "If you need to modify this skill for your use case:\n\nFork the repository (don't modify the original)\nUpdate your fork with your changes\nTest thoroughly with limited API keys\nDocument your changes for troubleshooting\n\nNote: Modified skills may break API compatibility or introduce security issues. Official support only covers the unmodified version."
      },
      {
        "title": "❌ What to AVOID (Security Risks)",
        "body": "Actions that could compromise security:\n\n❌ Sharing API keys publicly or in skill files\n❌ Modifying API endpoints to unknown servers\n❌ Disabling SSL/TLS certificate verification\n❌ Logging sensitive user data (prompts, IDs, etc.)\n❌ Bypassing authentication or billing mechanisms\n\nWhy this matters:\n\nAPI Compatibility: Skill logic aligns with IMA Open API schema\nSecurity: Malicious modifications could leak credentials or bypass billing\nSupport: Modified skills may not be supported\nCommunity: Breaking changes affect all users"
      },
      {
        "title": "📁 File System Access (Declared)",
        "body": "This skill reads/writes the following files:\n\nPathPurposeSizeAuto-cleanupUser Control~/.openclaw/memory/ima_prefs.jsonUser model preferences< 1 KBNoDelete anytime~/.openclaw/logs/ima_skills/Generation logs~10-50 KB/day7 daysDelete anytime\n\nWhat's stored:\n\n✅ Model preferences (e.g., \"last used: Suno sonic-v5\")\n✅ Timestamps (e.g., \"2026-02-27 12:34:56\")\n✅ Task IDs and HTTP status codes\n❌ NO API keys\n❌ NO personal data\n❌ NO prompts or generated content\n\nFull transparency: See the complete data flow and privacy policy in the skill documentation above."
      },
      {
        "title": "📋 Privacy & Data Handling Summary",
        "body": "What this skill does with your data:\n\nData TypeSent to IMA?Stored Locally?User ControlMusic prompts✅ Yes (required for generation)❌ NoNone (required)API key✅ Yes (authentication header)❌ NoSet via env varuser_id (optional CLI arg)❌ Never (local preference key only)✅ Yes (as prefs file key)Change --user-id valueModel preferences❌ No✅ Yes (~/.openclaw)Delete anytimeGeneration logs❌ No✅ Yes (~/.openclaw)Auto-cleanup 7 days\n\nPrivacy recommendations:\n\nUse test/scoped API keys for initial testing\nNote: --user-id is never sent to IMA servers - it's only used locally as a key for storing preferences in ~/.openclaw/memory/ima_prefs.json\nReview source code at scripts/ima_voice_create.py to verify network calls (search for create_task function)\nRotate API keys after testing or if compromised\n\nGet your IMA API key: Visit https://imastudio.com to register and get started."
      },
      {
        "title": "🔧 For Skill Maintainers Only",
        "body": "Version control:\n\nAll changes must go through Git with proper version bumps (semver)\nCHANGELOG.md must document all changes\nProduction deployments require code review\n\nFile checksums (optional):\n\n# Verify skill integrity\nsha256sum SKILL.md scripts/ima_voice_create.py\n\nIf users report issues, verify file integrity first."
      },
      {
        "title": "🧠 User Preference Memory",
        "body": "User preferences override recommended defaults. If a user has generated before, use their preferred model — not the system default."
      },
      {
        "title": "Storage: ~/.openclaw/memory/ima_prefs.json",
        "body": "{\n  \"user_{user_id}\": {\n    \"text_to_music\": { \"model_id\": \"sonic\", \"model_name\": \"Suno\", \"credit\": 25, \"last_used\": \"...\" }\n  }\n}\n\nIf the file or key doesn't exist, fall back to the ⭐ Recommended Defaults below."
      },
      {
        "title": "When to Read (Before Every Generation)",
        "body": "Load ~/.openclaw/memory/ima_prefs.json (silently, no error if missing)\nLook up user_{user_id}.text_to_music\nIf found → use that model; mention it:\n🎵 根据你的使用习惯，将用 [Model Name] 帮你生成音乐…\n• 模型：[Model Name]（你的常用模型）\n• 预计耗时：[X ~ Y 秒]\n• 消耗积分：[N pts]\n\n\nIf not found → use the ⭐ Recommended Default (Suno sonic-v5)"
      },
      {
        "title": "When to Write (After Every Successful Generation)",
        "body": "Save the used model to ~/.openclaw/memory/ima_prefs.json under user_{user_id}.text_to_music.\nSee ima-image-ai/SKILL.md → \"User Preference Memory\" for the full Python write snippet."
      },
      {
        "title": "When to Update (User Explicitly Changes Model)",
        "body": "TriggerAction用XXX / 换成XXXSwitch + save as new preference以后都用XXX / always use XXXSave + confirm: ✅ 已记住！以后音乐生成默认用 [XXX]用便宜的 / cheapestUse DouBao BGM/Song; do NOT save unless user says \"以后都用\""
      },
      {
        "title": "⭐ Recommended Defaults",
        "body": "These are fallback defaults — only used when no user preference exists.\nAlways default to the newest and most popular model. Do NOT default to the cheapest.\n\nTaskDefault Modelmodel_idmodel_versionCostWhytext_to_musicSuno (sonic-v5)sonicsonic25 ptsLatest Suno engine, best qualitytext_to_music (BGM only)DouBao BGMGenBGMGenBGM30 ptsBackground musictext_to_music (song)DouBao SongGenSongGenSong30 ptsSong generation\n\nSelection guide by use case:\n\nCustom song with lyrics, vocals, style → Suno sonic-v5 (default)\nBackground music / ambient loop → DouBao BGM\nSimple song generation → DouBao Song\nUser explicitly asks for cheapest → DouBao BGM/Song (6pts each) — only if explicitly requested\n\n⚠️ For Suno: model_version inside parameters (e.g. sonic-v5) is different from the outer model_version field (which is sonic). Always set both."
      },
      {
        "title": "💬 User Experience Protocol (IM / Feishu / Discord) v1.1 🆕",
        "body": "v1.1 Update: Added Step 0 to ensure correct message ordering in group chats (learned from ima-image-ai v1.2).\nMusic generation completes in 10~45 seconds. Never let users wait in silence.\nAlways follow all 5 steps below, every single time."
      },
      {
        "title": "🚫 Never Say to Users",
        "body": "❌ Never say✅ What users care aboutima_voice_create.py / 脚本 / script—自动化脚本 / automation—自动处理产品列表 / 查询接口—自动解析参数 / 智能轮询—attribute_id / model_version / form_config—API 调用 / HTTP 请求 / 任何技术参数名—\n\nOnly tell users: model name · estimated time · credits · result (audio file/player) · plain-language status."
      },
      {
        "title": "Estimated Generation Time per Model",
        "body": "ModelEstimated TimePoll EverySend Progress EveryDouBao BGM10~25s5s10sDouBao Song10~25s5s10sSuno (sonic-v5)20~45s5s15s\n\nestimated_max_seconds = upper bound (e.g. 45 for Suno, 25 for DouBao BGM/Song)."
      },
      {
        "title": "Step 0 — Initial Acknowledgment Reply (Normal Reply) 🆕",
        "body": "⚠️ CRITICAL: This step ensures correct message ordering in group chats.\n\nBefore doing anything else, reply to the user with a friendly acknowledgment message using your normal reply (not message tool). This reply will automatically appear FIRST in the conversation.\n\nExample acknowledgment messages:\n\n好的！马上帮你生成轻松的背景音乐 🎵\n\n收到！用 Suno 为你创作一首歌 🎶\n\nOK! Starting music generation with DouBao BGM 🎵\n\nRules:\n\nKeep it short and warm (< 15 words)\nMatch the user's language (Chinese/English)\nInclude relevant emoji (🎵/🎶/🎸/🎹)\nThis is your ONLY normal reply — all subsequent updates use message tool\n\nWhy this matters:\n\nNormal replies automatically appear FIRST in the conversation thread\nmessage tool pushes appear in chronological order AFTER your initial reply\nThis ensures users see: \"好的！\" → \"🎵 开始生成...\" → \"✅ 成功!\" (correct order)"
      },
      {
        "title": "Step 1 — Pre-Generation Notification (Push via message tool)",
        "body": "After Step 0 reply, use the message tool to push a notification immediately to the group/channel:\n\n# Agent implementation\nmessage(\n    action=\"send\",\n    target=group_id,  # or channel_id for Discord\n    message=\"\"\"🎵 开始生成音乐，请稍候…\n• 模型：[Model Name]\n• 预计耗时：[X ~ Y 秒]\n• 消耗积分：[N pts]\"\"\"\n)\n\nUser-facing message template:\n\n🎵 开始生成音乐，请稍候…\n• 模型：[Model Name]\n• 预计耗时：[X ~ Y 秒]\n• 消耗积分：[N pts]\n\nCost transparency:\n\nBalanced (Suno 25 pts): \"使用 Suno（25 积分，功能最全）\"\nDouBao alternatives (30 pts each): \"使用 DouBao BGM（30 积分）\" — only if user explicitly requests DouBao or background music type\n\nAdapt language to match the user. English → 🎵 Starting music generation, please wait [X~Y] seconds…"
      },
      {
        "title": "Step 2 — Progress Updates",
        "body": "Poll the task detail API every 5s.\nSend a progress update every [Send Progress Every] seconds per the table above.\n\n⏳ 音乐生成中… [P]%\n已等待 [elapsed]s，预计最长 [max]s\n\nProgress formula:\n\nP = min(95, floor(elapsed_seconds / estimated_max_seconds * 100))\n\nCap at 95% — never show 100% until the API returns success\nIf elapsed > estimated_max: keep P at 95% and append 「快好了，稍等…」"
      },
      {
        "title": "Step 3 — Success Notification (Push audio via message tool)",
        "body": "When task status = success, use the message tool to send the generated audio directly (not as a text URL):\n\nAgent implementation:\n\n# Get result URL from script output or task detail API\nresult = get_task_result(task_id)\naudio_url = result[\"medias\"][0][\"url\"]\n\n# Push audio + caption to group/channel\nmessage(\n    action=\"send\",\n    target=group_id,\n    media=audio_url,  # Feishu/Discord will render the audio\n    caption=f\"\"\"✅ 音乐生成成功！\n• 模型：[Model Name]\n• 耗时：预计 [X~Y]s，实际 [actual]s\n• 消耗积分：[N pts]\n\n🔗 原始链接：{audio_url}\"\"\"\n)\n\nUser-facing message:\n\n✅ 音乐生成成功！\n• 模型：[Model Name]\n• 耗时：预计 [X~Y]s，实际 [actual]s\n• 消耗积分：[N pts]\n\n🔗 原始链接：https://ws.esxscloud.com/.../audio.wav\n\n[音频直接显示为文件卡片，可点击播放]\n\nPlatform-specific notes:\n\nFeishu: message(action=send, media=url, caption=\"...\") — caption appears with audio file card\nDiscord: Audio embeds automatically from URL; caption can be in message text\nTelegram: Use message(action=send, media=url, caption=\"...\")\n\n⚠️ Important:\n\nAlways send audio via media parameter (file card/player) + include URL in caption text\nDo NOT use local file paths like /tmp/audio.wav — use HTTP URL from API\nUsers expect: (1) clickable audio file card + (2) raw URL link for sharing/downloading\nFormat: media=audio_url + caption=\"...🔗 原始链接：{audio_url}\""
      },
      {
        "title": "Step 4 — Failure Notification (Push via message tool)",
        "body": "When task status = failed or any API/network error, push a failure message with alternative suggestions:\n\nAgent implementation:\n\nmessage(\n    action=\"send\",\n    target=group_id,\n    message=\"\"\"❌ 音乐生成失败\n• 原因：[natural_language_error_message]\n• 建议改用：\n  - [Alt Model 1]（[特点]，[N pts]）\n  - [Alt Model 2]（[特点]，[N pts]）\n\n需要我帮你用其他模型重试吗？\"\"\"\n)\n\n⚠️ CRITICAL: Error Message Translation\n\nNEVER show technical error messages to users. Always translate API errors into natural language.\nAPI key & credits: 密钥与积分管理入口为 imaclaw.ai（与 imastudio.com 同属 IMA 平台）。Key and subscription management: imaclaw.ai (same IMA platform as imastudio.com).\n\nTechnical Error❌ Never Say✅ Say Instead (Chinese)✅ Say Instead (English)401 Unauthorized 🆕Invalid API key / 401 Unauthorized❌ API密钥无效或未授权<br>💡 生成新密钥: https://www.imaclaw.ai/imaclaw/apikey❌ API key is invalid or unauthorized<br>💡 Generate API Key: https://www.imaclaw.ai/imaclaw/apikey4008 Insufficient points 🆕Insufficient points / Error 4008❌ 积分不足，无法创建任务<br>💡 购买积分: https://www.imaclaw.ai/imaclaw/subscription❌ Insufficient points to create this task<br>💡 Buy Credits: https://www.imaclaw.ai/imaclaw/subscription\"Invalid product attribute\" / \"Insufficient points\"Invalid product attribute生成参数配置异常，请稍后重试Configuration error, please try again laterError 6006 (credit mismatch)Error 6006积分计算异常，系统正在修复Points calculation error, system is fixingError 6010 (attribute_id mismatch)Attribute ID does not match模型参数不匹配，请尝试其他模型Model parameters incompatible, try another modelerror 400 (bad request)error 400 / Bad request音乐参数设置有误，请调整描述后重试Music parameter error, adjust description and retryresource_status == 2Resource status 2 / Failed音乐生成遇到问题，建议换个模型试试Music generation failed, try another modelstatus == \"failed\" (no details)Task failed这次生成没成功，要不换个模型试试？Generation unsuccessful, try a different model?timeoutTask timed out / Timeout error音乐生成时间过长已超时，建议用更快的模型Music generation took too long, try a faster modelNetwork error / Connection refusedConnection refused / Network error网络连接不稳定，请检查网络后重试Network connection unstable, check network and retryRate limit exceeded429 Too Many Requests / Rate limit请求过于频繁，请稍等片刻再试Too many requests, please wait a momentModel unavailableModel not available / 503 Service Unavailable当前模型暂时不可用，建议换个模型Model temporarily unavailable, try another modelLyrics format error (Suno only)Invalid lyrics format歌词格式有误，请调整后重试Lyrics format error, adjust and retryPrompt too short/longPrompt length invalid音乐描述过短或过长，请调整到合适长度Music description too short or long, adjust length\n\nGeneric fallback (when error is unknown):\n\nChinese: 音乐生成遇到问题，请稍后重试或换个模型试试\nEnglish: Music generation encountered an issue, please try again or use another model\n\nBest Practices:\n\nFocus on user action: Tell users what to do next, not what went wrong technically\nBe reassuring: Use phrases like \"建议换个模型试试\" instead of \"生成失败了\"\nAvoid blame: Never say \"你的描述有问题\" → say \"描述需要调整一下\"\nProvide alternatives: Always suggest 1-2 alternative models in the failure message\nMusic-specific:\n\nFor Suno lyrics errors, suggest simplifying lyrics or using auto-generated lyrics\nFor prompt length errors, give example length (e.g., \"建议20-100字\")\nFor BGM requests, recommend DouBao BGM over Suno\n\n\n🆕 Include actionable links (v1.0.8+): For 401/4008 errors, provide clickable links to API key generation or credit purchase pages\n\n🆕 Enhanced Error Handling (v1.0.8):\n\nMusic generation uses direct error handling (no Reflection mechanism due to simpler parameters):\n\n401 Unauthorized: System provides clickable link to API key generation page\n4008 Insufficient Points: System provides clickable link to credit purchase page\nOther errors: Clear natural language explanations with alternative model suggestions\n\nError messages are user-friendly and actionable — users receive clear next steps for resolution.\n\nFailure fallback table:\n\nFailed ModelFirst AltSecond AltSunoDouBao BGM（30pts，背景音乐）DouBao Song（30pts，歌曲生成）DouBao BGMDouBao Song（30pts）Suno（25pts，功能最强）DouBao SongDouBao BGM（30pts）Suno（25pts，功能最强）"
      },
      {
        "title": "Step 5 — Done (No Further Action Needed) 🆕",
        "body": "v1.1 Note: After completing Steps 0-4:\n\n✅ Step 0 already sent your normal reply (appears FIRST in chat)\n✅ Steps 1-4 pushed all updates via message tool (appear in order)\n✅ No further action needed — conversation is complete\n\nDo NOT:\n\n❌ Reply again with NO_REPLY (you already replied in Step 0)\n❌ Send duplicate confirmation messages\n❌ Use message tool to send the same content twice\n\nWhy this works:\n\nUser: \"帮我生成一段轻松的背景音乐\"\n  ↓\n[Step 0] Your normal reply:  \"好的！马上帮你生成轻松的背景音乐 🎵\"  ← Appears FIRST\n  ↓\n[Step 1] message tool push:  \"🎵 开始生成音乐...\"  ← Appears SECOND\n  ↓\n[Step 2] message tool push:  \"⏳ 正在生成中… 45%\"  ← (if task takes >15s)\n  ↓\n[Step 3] message tool push:  \"✅ 音乐生成成功! [Audio File]\"  ← Appears LAST\n  ↓\n[Step 5] Done. No further replies."
      },
      {
        "title": "text_to_music (3 models)",
        "body": "Namemodel_idversion_idCostKey form_configSunosonicsonic25 ptsmodel_version=sonic-v5 (latest), custom_mode=true, make_instrumental, auto_lyrics, tags, negative_tags, vocal_gender, titleDouBao BGMGenBGMGenBGM30 pts—DouBao SongGenSongGenSong30 pts—\n\nModel guidance:\n\nSuno: Most powerful option. Supports full custom mode with genre tags, explicit instrumental toggle, vocal gender selection, and negative tags to exclude unwanted styles.\nDouBao BGM: Lightweight background music generation. Ideal for ambient / background tracks.\nDouBao Song: Song generation. Good for structured vocal compositions.\n\nWhat you can generate:\n\nBackground music (lo-fi, ambient, cinematic, electronic, jazz, classical…)\nCustom jingles or theme songs with specific BPM and key\nVocal or instrumental tracks with mood direction\nShort loops or full-length compositions\n\nPrompt writing tips (for Suno gpt_description_prompt):\n\nGenre: \"lo-fi hip hop\", \"orchestral cinematic\", \"upbeat pop\", \"dark ambient\"\nTempo: \"80 BPM\", \"fast tempo\", \"slow ballad\"\nVocals: \"no vocals\" → set make_instrumental=true; \"female vocals\" → vocal_gender=\"female\"\nMood: \"happy and energetic\", \"melancholic\", \"tense and dramatic\"\nNegative: negative_tags=\"heavy metal, distortion\" to exclude styles\nDuration hint: \"60 seconds\", \"30 second loop\""
      },
      {
        "title": "Environment",
        "body": "Base URL: https://api.imastudio.com\n\nRequired/recommended headers for all /open/v1/ endpoints:\n\nHeaderRequiredValueNotesAuthorization✅Bearer ima_your_api_key_hereAPI key authenticationx-app-source✅ima_skillsFixed value — identifies skill-originated requestsx_app_languagerecommendeden / zhProduct label language; defaults to en if omitted\n\nAuthorization: Bearer ima_your_api_key_here\nx-app-source: ima_skills\nx_app_language: en"
      },
      {
        "title": "⚠️ MANDATORY: Always Query Product List First",
        "body": "CRITICAL: You MUST call /open/v1/product/list BEFORE creating any task.\nThe attribute_id field is REQUIRED in the create request. If it is 0 or missing, you get:\n\"Invalid product attribute\" → \"Insufficient points\" → task fails completely.\nNEVER construct a create request from the model table alone. Always fetch the product first."
      },
      {
        "title": "How to get attribute_id",
        "body": "# Step 1: Query product list\nGET /open/v1/product/list?app=ima&platform=web&category=text_to_music\n\n# Step 2: Walk the tree to find your model\nfor group in response[\"data\"]:\n    for version in group.get(\"children\", []):\n        if version[\"type\"] == \"3\" and version[\"model_id\"] == target_model_id:\n            attribute_id  = version[\"credit_rules\"][0][\"attribute_id\"]\n            credit        = version[\"credit_rules\"][0][\"points\"]\n            model_version = version[\"id\"]\n            model_name    = version[\"name\"]"
      },
      {
        "title": "Quick Reference: Known attribute_ids",
        "body": "⚠️ Production warning: attribute_id and credit values change frequently. Always call /open/v1/product/list at runtime; table below is pre-queried reference (2026-02-27).\n\nModelmodel_idattribute_idcreditNotesSuno (sonic-v4)sonic237025 ptsDefaultDouBao BGMGenBGM439930 ptsBGM专用DouBao SongGenSong439830 pts歌曲专用All others—→ query /open/v1/product/list—Always runtime query"
      },
      {
        "title": "Common Mistakes (and resulting errors)",
        "body": "MistakeErrorattribute_id is 0 or missing\"Invalid product attribute\" → Insufficient pointsattribute_id outdated (production changed)Same errors; always query product list firstprompt at outer levelPrompt ignoredcast missing from inner parametersBilling failureSuno: model_version in parameters not set to sonic-v5Wrong engine used"
      },
      {
        "title": "Core Flow",
        "body": "1. GET /open/v1/product/list?app=ima&platform=web&category=text_to_music\n   → REQUIRED: Get attribute_id, credit, model_version, form_config defaults\n\n2. POST /open/v1/tasks/create\n   → Must include: attribute_id, model_name, model_version, credit, cast, prompt (nested!)\n\n3. POST /open/v1/tasks/detail  {task_id: \"...\"}\n   → Poll every 3–5s until medias[].resource_status == 1\n   → Extract url from completed media (mp3)"
      },
      {
        "title": "Supported Task Types",
        "body": "categoryCapabilityInputtext_to_musicText → Musicprompt"
      },
      {
        "title": "Detail API status values",
        "body": "FieldTypeValuesresource_statusint or null0=处理中, 1=可用, 2=失败, 3=已删除；null 当作 0statusstring\"pending\", \"processing\", \"success\", \"failed\"\n\nresource_statusstatusAction0 or nullpending / processingKeep polling1success (or completed)Stop when all medias are 1; read url1failedStop, handle error2 / 3anyStop, handle error\n\nImportant: Treat resource_status: null as 0. Stop only when all medias have resource_status == 1. Check status != \"failed\" when rs=1."
      },
      {
        "title": "API 1: Product List",
        "body": "GET /open/v1/product/list?app=ima&platform=web&category=text_to_music\n\nReturns a V2 tree structure: type=2 nodes are model groups, type=3 nodes are versions (leaves). Only type=3 nodes contain credit_rules and form_config.\n\nHow to pick a version:\n\nTraverse nodes to find type=3 leaves\nUse model_id and id (= model_version) from the leaf\nPick credit_rules[].attribute_id\nUse form_config[].value as default parameters values"
      },
      {
        "title": "API 2: Create Task",
        "body": "POST /open/v1/tasks/create"
      },
      {
        "title": "text_to_music",
        "body": "No image input. src_img_url: [], input_images: [].\n\n{\n  \"task_type\": \"text_to_music\",\n  \"enable_multi_model\": false,\n  \"src_img_url\": [],\n  \"parameters\": [{\n    \"attribute_id\":  \"<from credit_rules>\",\n    \"model_id\":      \"<model_id>\",\n    \"model_name\":    \"<model_name>\",\n    \"model_version\": \"<version_id>\",\n    \"app\":           \"ima\",\n    \"platform\":      \"web\",\n    \"category\":      \"text_to_music\",\n    \"credit\":        \"<points>\",\n    \"parameters\": {\n      \"prompt\":       \"upbeat electronic, 120 BPM, no vocals\",\n      \"n\":            1,\n      \"input_images\": [],\n      \"cast\":         {\"points\": \"<points>\", \"attribute_id\": \"<attribute_id>\"}\n    }\n  }]\n}\n\nPrompt tips for music generation:\n\nGenre: \"upbeat electronic\", \"classical piano\", \"ambient chill\"\nTempo: \"120 BPM\", \"slow tempo\"\nVocals: \"no vocals\", \"male vocals\", \"female vocals\"\nMood: \"happy\", \"melancholic\", \"energetic\"\nDuration hint: \"60 seconds\", \"short loop\"\n\nKey fields:\n\nFieldRequiredDescriptionparameters[].credit✅Must equal credit_rules[].points. Error 6006 if wrong.parameters[].parameters.prompt✅Prompt must be nested here, NOT at top level.parameters[].parameters.cast✅{\"points\": N, \"attribute_id\": N} — mirror of credit.parameters[].parameters.n✅Number of outputs (usually 1).\n\nResponse: data.id = task ID for polling."
      },
      {
        "title": "API 3: Task Detail (Poll)",
        "body": "POST /open/v1/tasks/detail\n{\"task_id\": \"<id from create response>\"}\n\nPoll every 3–5s. Completed response:\n\n{\n  \"id\": \"task_abc\",\n  \"medias\": [{\n    \"resource_status\": 1,\n    \"url\":          \"https://cdn.../output.mp3\",\n    \"duration_str\": \"60s\",\n    \"format\":       \"mp3\"\n  }]\n}\n\nOutput fields: url (mp3), duration_str, format."
      },
      {
        "title": "Common Mistakes",
        "body": "MistakeFixPlacing prompt at param top-levelprompt must be inside parameters[].parametersWrong credit valueMust exactly match credit_rules[].points (error 6006)Missing app / platform in parametersRequired — use ima / webSingle-poll instead of loopPoll until resource_status == 1 for ALL mediasNot checking status != \"failed\"resource_status=1 + status=\"failed\" = actual failure"
      },
      {
        "title": "Python Example",
        "body": "import time\nimport requests\n\nBASE_URL = \"https://api.imastudio.com\"\nAPI_KEY  = \"ima_your_key_here\"\nHEADERS  = {\n    \"Authorization\":  f\"Bearer {API_KEY}\",\n    \"Content-Type\":   \"application/json\",\n    \"x-app-source\":   \"ima_skills\",\n    \"x_app_language\": \"en\",\n}\n\n\ndef get_products(category: str) -> list:\n    \"\"\"Returns flat list of type=3 version nodes from V2 tree.\"\"\"\n    r = requests.get(\n        f\"{BASE_URL}/open/v1/product/list\",\n        headers=HEADERS,\n        params={\"app\": \"ima\", \"platform\": \"web\", \"category\": category},\n    )\n    r.raise_for_status()\n    nodes = r.json()[\"data\"]\n    versions = []\n    for node in nodes:\n        for child in node.get(\"children\") or []:\n            if child.get(\"type\") == \"3\":\n                versions.append(child)\n            for gc in child.get(\"children\") or []:\n                if gc.get(\"type\") == \"3\":\n                    versions.append(gc)\n    return versions\n\n\ndef create_music_task(prompt: str, product: dict) -> str:\n    \"\"\"Returns task_id.\"\"\"\n    rule = product[\"credit_rules\"][0]\n    form_defaults = {f[\"field\"]: f[\"value\"] for f in product.get(\"form_config\", []) if f.get(\"value\") is not None}\n\n    nested_params = {\n        \"prompt\": prompt,\n        \"n\":      1,\n        \"input_images\": [],\n        \"cast\":   {\"points\": rule[\"points\"], \"attribute_id\": rule[\"attribute_id\"]},\n        **form_defaults,\n    }\n\n    body = {\n        \"task_type\":          \"text_to_music\",\n        \"enable_multi_model\": False,\n        \"src_img_url\":        [],\n        \"parameters\": [{\n            \"attribute_id\":  rule[\"attribute_id\"],\n            \"model_id\":      product[\"model_id\"],\n            \"model_name\":    product[\"name\"],\n            \"model_version\": product[\"id\"],\n            \"app\":           \"ima\",\n            \"platform\":      \"web\",\n            \"category\":      \"text_to_music\",\n            \"credit\":        rule[\"points\"],\n            \"parameters\":    nested_params,\n        }],\n    }\n    r = requests.post(f\"{BASE_URL}/open/v1/tasks/create\", headers=HEADERS, json=body)\n    r.raise_for_status()\n    return r.json()[\"data\"][\"id\"]\n\n\ndef poll(task_id: str, interval: int = 3, timeout: int = 300) -> dict:\n    deadline = time.time() + timeout\n    while time.time() < deadline:\n        r = requests.post(f\"{BASE_URL}/open/v1/tasks/detail\", headers=HEADERS, json={\"task_id\": task_id})\n        r.raise_for_status()\n        task   = r.json()[\"data\"]\n        medias = task.get(\"medias\", [])\n        if medias:\n            if any(m.get(\"status\") == \"failed\" for m in medias):\n                raise RuntimeError(f\"Task failed: {task_id}\")\n            rs = lambda m: m.get(\"resource_status\") if m.get(\"resource_status\") is not None else 0\n            if any(rs(m) == 2 for m in medias):\n                raise RuntimeError(f\"Task failed: {task_id}\")\n            if all(rs(m) == 1 for m in medias):\n                return task\n        time.sleep(interval)\n    raise TimeoutError(f\"Task timed out: {task_id}\")\n\n\n# text_to_music\nproducts = get_products(\"text_to_music\")\ntask_id  = create_music_task(\"upbeat electronic, 120 BPM, no vocals\", products[0])\nresult   = poll(task_id)\nprint(result[\"medias\"][0][\"url\"])          # mp3 URL\nprint(result[\"medias\"][0][\"duration_str\"]) # e.g. \"60s\""
      },
      {
        "title": "Supported Models & Search Terms",
        "body": "Models: Suno sonic v4, Suno sonic v5, DouBao BGM (GenBGM), DouBao Song (GenSong)\n\nCapabilities: music generation, text-to-music, AI music, background music, BGM, soundtrack, jingle, song with lyrics, vocal, instrumental, ambient music, audio generation"
      }
    ],
    "body": "IMA Voice AI Creation\nScope & Dependencies (Declared for Transparency)\nCredentials: This skill requires an IMA API key at runtime (IMA_API_KEY or --api-key). The key is sent only to api.imastudio.com. Obtain keys at https://imastudio.com. Declared in registry as required.\nOptional dependency: When ima-knowledge-ai is installed, this skill may instruct the agent to read that skill's reference files (~/.openclaw/skills/ima-knowledge-ai/references/*) for workflow and model-selection guidance. This skill is self-contained — it works fully without ima-knowledge-ai. Reading another skill's files is optional and only for complex or multi-step tasks; users who do not have or trust ima-knowledge-ai can ignore those steps and use this skill's built-in defaults and 📥 User Input Parsing tables.\nLocal paths: This skill reads/writes ~/.openclaw/memory/ima_prefs.json (preferences) and ~/.openclaw/logs/ima_skills/ (logs; auto-deleted after 7 days). User can delete these anytime.\nOptional: Read Knowledge Base (When ima-knowledge-ai Is Installed)\n\nIf ima-knowledge-ai is not installed: Skip this section. Use only this SKILL's default models and the 📥 User Input Parsing tables for model_id and parameters.\n\nWhen ima-knowledge-ai is installed and the task is complex, you may optionally read its reference files for better workflow and model choice:\n\nWorkflow complexity — Read ima-knowledge-ai/references/workflow-design.md if:\n\nUser mentions: \"MV\"、\"配乐\"、\"完整作品\"、\"多步骤\"、\"soundtrack\"\nTask involves: video + music coordination, multi-track production, integrated workflows\nComplex requirements that need task decomposition\n\nModel selection — Read ima-knowledge-ai/references/model-selection.md if:\n\nUnsure which model to use (Suno vs DouBao BGM vs DouBao Song)\nNeed cost/quality trade-off guidance\nUser specifies budget or quality requirements\n\nWhy this is optional:\n\nMusic generation is often part of a larger workflow (video + music, story + soundtrack)\nFor simple single-track requests, proceed directly with this skill's defaults\nFor complex workflows, reading the knowledge base can improve task decomposition and model choice\n\nExample workflow case (when using optional knowledge base):\n\nUser: \"帮我做个产品宣传MV，有背景音乐\"\n\n❌ Wrong: 直接生成音乐 (music alone, no coordination with video)\n\n✅ Right (if ima-knowledge-ai available): \n  1. Read workflow-design.md\n  2. Decompose: Script → Video shots → Background music (matching video duration/mood)\n  3. Generate video first (get duration)\n  4. Generate BGM with matching duration and style\n\n\nHow to check (optional):\n\n# Only if ima-knowledge-ai is installed and task is complex\nif ima_knowledge_ai_installed and (complex_workflow or multi_step):\n    read(\"~/.openclaw/skills/ima-knowledge-ai/references/workflow-design.md\")\n\nif ima_knowledge_ai_installed and unsure_model_choice:\n    read(\"~/.openclaw/skills/ima-knowledge-ai/references/model-selection.md\")\n\n# Choose model (this skill's logic works with or without knowledge base)\nif \"background music\" or \"BGM\" or \"instrumental\":\n    use_doubao_bgm()  # 30pts, pure instrumental\nelif \"song\" or \"lyrics\" or \"vocals\":\n    use_suno_sonic()  # 25pts, full-featured with lyrics\nelse:\n    use_suno_sonic()  # Default: most versatile\n\n\nFor simple requests: Proceed directly with this skill's defaults. No need to read other skills' files.\n\n📥 User Input Parsing (Model & Parameter Recognition)\n\nPurpose: So that any agent (Claude or other models) parses user intent consistently, follow these rules when deriving model_id and task type from natural language. Normalize first, then map.\n\n1. User phrasing → model selection (model_id)\nUser intent / phrasing\tmodel_id\tNotes\nBGM / 背景音乐 / 纯音乐 / 无人声 / instrumental / 配乐\tGenBGM\tDouBao BGM, 30 pts, ~30s\n歌 / 歌曲 / 带歌词 / 人声 / song / lyrics / 有唱\tsonic or GenSong\tSuno (25 pts, ~2min) or DouBao Song (30 pts, ~30s)\nSuno / 苏诺 / sonic\tsonic\tFull-featured, lyrics, vocal_gender, 25 pts\n豆包 BGM / DouBao BGM / BGM\tGenBGM\t30 pts\n豆包 歌曲 / DouBao Song / 豆包歌\tGenSong\t30 pts\n最便宜 / 最省钱 / cheapest / budget\tGenBGM or GenSong (6 pts 档 if available)\tOnly if user explicitly asks for cheapest\n最好 / 最全功能 / best / 带歌词可调\tsonic\tSuno default\n\nIf the user does not specify, default to Suno (sonic) for versatility. For \"背景音乐\"/\"BGM\"/\"配乐\" only → use DouBao BGM (GenBGM).\n\n2. Music-specific parameters (Suno)\nUser says (examples)\tParameter\tAction\n无人声 / 纯音乐 / no vocals / instrumental\tmake_instrumental\ttrue\n女声 / 女声演唱 / female vocals\tvocal_gender\t\"female\" (custom_mode true)\n男声 / 男声演唱 / male vocals\tvocal_gender\t\"male\" (custom_mode true)\n我写歌词 / 自定义歌词 / custom lyrics\tcustom_mode + lyrics\tProvide lyrics in request\n\nWhen using Suno with lyrics or vocal control, set custom_mode: true and pass lyrics / vocal_gender per API docs.\n\n⚙️ How This Skill Works\n\nFor transparency: This skill uses a bundled Python script (scripts/ima_voice_create.py) to call the IMA Open API. The script:\n\nSends your prompt to https://api.imastudio.com (IMA's servers)\nUses --user-id only locally as a key for storing your model preferences\nReturns a music URL when generation is complete\nNEW (v1.1.0): Automatic reflection mechanism — if generation fails, the script automatically retries up to 3 times with smart parameter adjustments\n🧠 Reflection Mechanism (Automatic Error Recovery)\n\nThis skill now includes an intelligent reflection system that automatically recovers from common errors:\n\n3-Layer Retry Strategy:\n\nAttempt 1: Original Parameters\n\nUses your provided parameters with smart credit_rule selection\nMost tasks succeed on first try\n\nAttempt 2: Strict Match (Error 6009 Fix)\n\nAutomatically removes unsupported parameters\nOnly keeps parameters in credit_rules.attributes\nExample: Removes unsupported Suno parameters if not in model config\n\nAttempt 3: Fallback to Default (Error 6010 Fix)\n\nUses model's default configuration\nUses credit_rules[0] (first rule = safest default)\nGuarantees maximum compatibility\n\nCommon Errors Fixed Automatically:\n\nError 6009: \"No exact rule match found for parameters\" → removes unsupported params\nError 6010: \"Attribute ID does not match\" → corrects attribute_id to match params\nInvalid product attribute: Uses default rule configuration\n\nUser Experience:\n\n✅ Transparent: Shows reflection log when retries happen\n✅ Fast: Most tasks succeed on first attempt (no delay)\n✅ Smart: Learns from errors and adjusts automatically\n✅ User-friendly: Provides helpful suggestions if all 3 attempts fail\n\nExample Output (with reflection):\n\n🚀 Creating music generation task…\n\n🧠 反省日志 (2 次尝试):\n   ❌ [尝试 1] Invalid product attribute → 移除不支持的参数: ['unsupported_param']\n   ✅ [尝试 2] ✅ 成功（尝试 2）\n\n✅ Task created: task_abc123xyz\n\n\nWhat gets sent to IMA servers:\n\n✅ Your music prompt/description\n✅ Model selection (Suno/DouBao)\n❌ NO API key in prompts (key is used for authentication only)\n❌ NO user_id (it's only used locally)\n\nWhat's stored locally:\n\n~/.openclaw/memory/ima_prefs.json - Your model preferences (< 1 KB)\n~/.openclaw/logs/ima_skills/ - Generation logs (auto-deleted after 7 days)\nAgent Execution (Internal Reference)\n\nNote for users: You can review the script source at scripts/ima_voice_create.py anytime.\nThis skill uses only api.imastudio.com (no image upload needed for music generation, unlike image/video skills which also use imapi.liveme.com).\n\nUse the bundled script internally:\n\n# Generate music — Suno sonic-v5\npython3 {baseDir}/scripts/ima_voice_create.py \\\n  --api-key  $IMA_API_KEY \\\n  --task-type text_to_music \\\n  --model-id  sonic \\\n  --prompt   \"upbeat lo-fi hip hop, 90 BPM, no vocals\" \\\n  --user-id  {user_id} \\\n  --output-json\n\n# DouBao BGM\npython3 {baseDir}/scripts/ima_voice_create.py \\\n  --api-key  $IMA_API_KEY \\\n  --model-id  GenBGM \\\n  --prompt   \"calm ambient piano background\" \\\n  --user-id  {user_id} \\\n  --output-json\n\n\nThe script outputs JSON — parse it to get the result URL and pass it to the user via the UX protocol messages below.\n\nOverview\n\nCall IMA Open API to create AI-generated music/audio. All endpoints require an ima_* API key. The core flow is: query products → create task → poll until done.\n\n🔒 Security & Transparency Policy\n\nThis skill is community-maintained and open for inspection.\n\n🌐 Network Architecture\n\nThis skill uses a simpler network architecture than image/video skills:\n\nSkill Type\tDomains Used\tWhy\nima-voice-ai (this skill)\t✅ api.imastudio.com only\tMusic generation doesn't require image uploads\nima-image-ai, ima-video-ai\tapi.imastudio.com + imapi.liveme.com\tImage/video tasks need image upload service\n\nWhy the difference?\n\nMusic generation (text_to_music) only needs text prompts → single API endpoint\nImage/video generation (i2i, i2v tasks) needs image file uploads → requires separate upload service\n\nSecurity verification:\n\n# Verify this skill only uses api.imastudio.com:\ngrep -n \"https://\" scripts/ima_voice_create.py\n\n# Expected output:\n# Only https://api.imastudio.com (no imapi.liveme.com)\n\n✅ What Users CAN Do\n\nFull transparency:\n\n✅ Review all source code: Check scripts/ima_voice_create.py and ima_logger.py anytime\n✅ Verify network calls: This skill uses only api.imastudio.com (music generation doesn't require image uploads). Verify by running: grep -n \"https://\" scripts/ima_voice_create.py\n✅ Inspect local data: View ~/.openclaw/memory/ima_prefs.json and log files\n✅ Control privacy: Delete preferences/logs anytime, or disable file writes (see below)\n\nConfiguration allowed:\n\n✅ Set API key in environment or agent config:\nEnvironment variable: export IMA_API_KEY=ima_your_key_here\nOpenClaw/MCP config: Add IMA_API_KEY to agent's environment configuration\nGet your key at: https://imastudio.com\n✅ Use scoped/test keys: Test with limited API keys, rotate after testing\n✅ Disable file writes: Make prefs/logs read-only or symlink to /dev/null\n\nData control:\n\n✅ View stored data: cat ~/.openclaw/memory/ima_prefs.json\n✅ Delete preferences: rm ~/.openclaw/memory/ima_prefs.json (resets to defaults)\n✅ Delete logs: rm -rf ~/.openclaw/logs/ima_skills/ (auto-cleanup after 7 days anyway)\n⚠️ Advanced Users: Fork & Modify\n\nIf you need to modify this skill for your use case:\n\nFork the repository (don't modify the original)\nUpdate your fork with your changes\nTest thoroughly with limited API keys\nDocument your changes for troubleshooting\n\nNote: Modified skills may break API compatibility or introduce security issues. Official support only covers the unmodified version.\n\n❌ What to AVOID (Security Risks)\n\nActions that could compromise security:\n\n❌ Sharing API keys publicly or in skill files\n❌ Modifying API endpoints to unknown servers\n❌ Disabling SSL/TLS certificate verification\n❌ Logging sensitive user data (prompts, IDs, etc.)\n❌ Bypassing authentication or billing mechanisms\n\nWhy this matters:\n\nAPI Compatibility: Skill logic aligns with IMA Open API schema\nSecurity: Malicious modifications could leak credentials or bypass billing\nSupport: Modified skills may not be supported\nCommunity: Breaking changes affect all users\n📁 File System Access (Declared)\n\nThis skill reads/writes the following files:\n\nPath\tPurpose\tSize\tAuto-cleanup\tUser Control\n~/.openclaw/memory/ima_prefs.json\tUser model preferences\t< 1 KB\tNo\tDelete anytime\n~/.openclaw/logs/ima_skills/\tGeneration logs\t~10-50 KB/day\t7 days\tDelete anytime\n\nWhat's stored:\n\n✅ Model preferences (e.g., \"last used: Suno sonic-v5\")\n✅ Timestamps (e.g., \"2026-02-27 12:34:56\")\n✅ Task IDs and HTTP status codes\n❌ NO API keys\n❌ NO personal data\n❌ NO prompts or generated content\n\nFull transparency: See the complete data flow and privacy policy in the skill documentation above.\n\n📋 Privacy & Data Handling Summary\n\nWhat this skill does with your data:\n\nData Type\tSent to IMA?\tStored Locally?\tUser Control\nMusic prompts\t✅ Yes (required for generation)\t❌ No\tNone (required)\nAPI key\t✅ Yes (authentication header)\t❌ No\tSet via env var\nuser_id (optional CLI arg)\t❌ Never (local preference key only)\t✅ Yes (as prefs file key)\tChange --user-id value\nModel preferences\t❌ No\t✅ Yes (~/.openclaw)\tDelete anytime\nGeneration logs\t❌ No\t✅ Yes (~/.openclaw)\tAuto-cleanup 7 days\n\nPrivacy recommendations:\n\nUse test/scoped API keys for initial testing\nNote: --user-id is never sent to IMA servers - it's only used locally as a key for storing preferences in ~/.openclaw/memory/ima_prefs.json\nReview source code at scripts/ima_voice_create.py to verify network calls (search for create_task function)\nRotate API keys after testing or if compromised\n\nGet your IMA API key: Visit https://imastudio.com to register and get started.\n\n🔧 For Skill Maintainers Only\n\nVersion control:\n\nAll changes must go through Git with proper version bumps (semver)\nCHANGELOG.md must document all changes\nProduction deployments require code review\n\nFile checksums (optional):\n\n# Verify skill integrity\nsha256sum SKILL.md scripts/ima_voice_create.py\n\n\nIf users report issues, verify file integrity first.\n\n🧠 User Preference Memory\n\nUser preferences override recommended defaults. If a user has generated before, use their preferred model — not the system default.\n\nStorage: ~/.openclaw/memory/ima_prefs.json\n{\n  \"user_{user_id}\": {\n    \"text_to_music\": { \"model_id\": \"sonic\", \"model_name\": \"Suno\", \"credit\": 25, \"last_used\": \"...\" }\n  }\n}\n\n\nIf the file or key doesn't exist, fall back to the ⭐ Recommended Defaults below.\n\nWhen to Read (Before Every Generation)\nLoad ~/.openclaw/memory/ima_prefs.json (silently, no error if missing)\nLook up user_{user_id}.text_to_music\nIf found → use that model; mention it:\n🎵 根据你的使用习惯，将用 [Model Name] 帮你生成音乐…\n• 模型：[Model Name]（你的常用模型）\n• 预计耗时：[X ~ Y 秒]\n• 消耗积分：[N pts]\n\nIf not found → use the ⭐ Recommended Default (Suno sonic-v5)\nWhen to Write (After Every Successful Generation)\n\nSave the used model to ~/.openclaw/memory/ima_prefs.json under user_{user_id}.text_to_music.\nSee ima-image-ai/SKILL.md → \"User Preference Memory\" for the full Python write snippet.\n\nWhen to Update (User Explicitly Changes Model)\nTrigger\tAction\n用XXX / 换成XXX\tSwitch + save as new preference\n以后都用XXX / always use XXX\tSave + confirm: ✅ 已记住！以后音乐生成默认用 [XXX]\n用便宜的 / cheapest\tUse DouBao BGM/Song; do NOT save unless user says \"以后都用\"\n⭐ Recommended Defaults\n\nThese are fallback defaults — only used when no user preference exists.\nAlways default to the newest and most popular model. Do NOT default to the cheapest.\n\nTask\tDefault Model\tmodel_id\tmodel_version\tCost\tWhy\ntext_to_music\tSuno (sonic-v5)\tsonic\tsonic\t25 pts\tLatest Suno engine, best quality\ntext_to_music (BGM only)\tDouBao BGM\tGenBGM\tGenBGM\t30 pts\tBackground music\ntext_to_music (song)\tDouBao Song\tGenSong\tGenSong\t30 pts\tSong generation\n\nSelection guide by use case:\n\nCustom song with lyrics, vocals, style → Suno sonic-v5 (default)\nBackground music / ambient loop → DouBao BGM\nSimple song generation → DouBao Song\nUser explicitly asks for cheapest → DouBao BGM/Song (6pts each) — only if explicitly requested\n\n⚠️ For Suno: model_version inside parameters (e.g. sonic-v5) is different from the outer model_version field (which is sonic). Always set both.\n\n💬 User Experience Protocol (IM / Feishu / Discord) v1.1 🆕\n\nv1.1 Update: Added Step 0 to ensure correct message ordering in group chats (learned from ima-image-ai v1.2).\n\nMusic generation completes in 10~45 seconds. Never let users wait in silence.\nAlways follow all 5 steps below, every single time.\n\n🚫 Never Say to Users\n❌ Never say\t✅ What users care about\nima_voice_create.py / 脚本 / script\t—\n自动化脚本 / automation\t—\n自动处理产品列表 / 查询接口\t—\n自动解析参数 / 智能轮询\t—\nattribute_id / model_version / form_config\t—\nAPI 调用 / HTTP 请求 / 任何技术参数名\t—\n\nOnly tell users: model name · estimated time · credits · result (audio file/player) · plain-language status.\n\nEstimated Generation Time per Model\nModel\tEstimated Time\tPoll Every\tSend Progress Every\nDouBao BGM\t10~25s\t5s\t10s\nDouBao Song\t10~25s\t5s\t10s\nSuno (sonic-v5)\t20~45s\t5s\t15s\n\nestimated_max_seconds = upper bound (e.g. 45 for Suno, 25 for DouBao BGM/Song).\n\nStep 0 — Initial Acknowledgment Reply (Normal Reply) 🆕\n\n⚠️ CRITICAL: This step ensures correct message ordering in group chats.\n\nBefore doing anything else, reply to the user with a friendly acknowledgment message using your normal reply (not message tool). This reply will automatically appear FIRST in the conversation.\n\nExample acknowledgment messages:\n\n好的！马上帮你生成轻松的背景音乐 🎵\n\n收到！用 Suno 为你创作一首歌 🎶\n\nOK! Starting music generation with DouBao BGM 🎵\n\n\nRules:\n\nKeep it short and warm (< 15 words)\nMatch the user's language (Chinese/English)\nInclude relevant emoji (🎵/🎶/🎸/🎹)\nThis is your ONLY normal reply — all subsequent updates use message tool\n\nWhy this matters:\n\nNormal replies automatically appear FIRST in the conversation thread\nmessage tool pushes appear in chronological order AFTER your initial reply\nThis ensures users see: \"好的！\" → \"🎵 开始生成...\" → \"✅ 成功!\" (correct order)\nStep 1 — Pre-Generation Notification (Push via message tool)\n\nAfter Step 0 reply, use the message tool to push a notification immediately to the group/channel:\n\n# Agent implementation\nmessage(\n    action=\"send\",\n    target=group_id,  # or channel_id for Discord\n    message=\"\"\"🎵 开始生成音乐，请稍候…\n• 模型：[Model Name]\n• 预计耗时：[X ~ Y 秒]\n• 消耗积分：[N pts]\"\"\"\n)\n\n\nUser-facing message template:\n\n🎵 开始生成音乐，请稍候…\n• 模型：[Model Name]\n• 预计耗时：[X ~ Y 秒]\n• 消耗积分：[N pts]\n\n\nCost transparency:\n\nBalanced (Suno 25 pts): \"使用 Suno（25 积分，功能最全）\"\nDouBao alternatives (30 pts each): \"使用 DouBao BGM（30 积分）\" — only if user explicitly requests DouBao or background music type\n\nAdapt language to match the user. English → 🎵 Starting music generation, please wait [X~Y] seconds…\n\nStep 2 — Progress Updates\n\nPoll the task detail API every 5s.\nSend a progress update every [Send Progress Every] seconds per the table above.\n\n⏳ 音乐生成中… [P]%\n已等待 [elapsed]s，预计最长 [max]s\n\n\nProgress formula:\n\nP = min(95, floor(elapsed_seconds / estimated_max_seconds * 100))\n\nCap at 95% — never show 100% until the API returns success\nIf elapsed > estimated_max: keep P at 95% and append 「快好了，稍等…」\nStep 3 — Success Notification (Push audio via message tool)\n\nWhen task status = success, use the message tool to send the generated audio directly (not as a text URL):\n\nAgent implementation:\n\n# Get result URL from script output or task detail API\nresult = get_task_result(task_id)\naudio_url = result[\"medias\"][0][\"url\"]\n\n# Push audio + caption to group/channel\nmessage(\n    action=\"send\",\n    target=group_id,\n    media=audio_url,  # Feishu/Discord will render the audio\n    caption=f\"\"\"✅ 音乐生成成功！\n• 模型：[Model Name]\n• 耗时：预计 [X~Y]s，实际 [actual]s\n• 消耗积分：[N pts]\n\n🔗 原始链接：{audio_url}\"\"\"\n)\n\n\nUser-facing message:\n\n✅ 音乐生成成功！\n• 模型：[Model Name]\n• 耗时：预计 [X~Y]s，实际 [actual]s\n• 消耗积分：[N pts]\n\n🔗 原始链接：https://ws.esxscloud.com/.../audio.wav\n\n[音频直接显示为文件卡片，可点击播放]\n\n\nPlatform-specific notes:\n\nFeishu: message(action=send, media=url, caption=\"...\") — caption appears with audio file card\nDiscord: Audio embeds automatically from URL; caption can be in message text\nTelegram: Use message(action=send, media=url, caption=\"...\")\n\n⚠️ Important:\n\nAlways send audio via media parameter (file card/player) + include URL in caption text\nDo NOT use local file paths like /tmp/audio.wav — use HTTP URL from API\nUsers expect: (1) clickable audio file card + (2) raw URL link for sharing/downloading\nFormat: media=audio_url + caption=\"...🔗 原始链接：{audio_url}\"\nStep 4 — Failure Notification (Push via message tool)\n\nWhen task status = failed or any API/network error, push a failure message with alternative suggestions:\n\nAgent implementation:\n\nmessage(\n    action=\"send\",\n    target=group_id,\n    message=\"\"\"❌ 音乐生成失败\n• 原因：[natural_language_error_message]\n• 建议改用：\n  - [Alt Model 1]（[特点]，[N pts]）\n  - [Alt Model 2]（[特点]，[N pts]）\n\n需要我帮你用其他模型重试吗？\"\"\"\n)\n\n\n⚠️ CRITICAL: Error Message Translation\n\nNEVER show technical error messages to users. Always translate API errors into natural language.\nAPI key & credits: 密钥与积分管理入口为 imaclaw.ai（与 imastudio.com 同属 IMA 平台）。Key and subscription management: imaclaw.ai (same IMA platform as imastudio.com).\n\nTechnical Error\t❌ Never Say\t✅ Say Instead (Chinese)\t✅ Say Instead (English)\n401 Unauthorized 🆕\tInvalid API key / 401 Unauthorized\t❌ API密钥无效或未授权<br>💡 生成新密钥: https://www.imaclaw.ai/imaclaw/apikey\t❌ API key is invalid or unauthorized<br>💡 Generate API Key: https://www.imaclaw.ai/imaclaw/apikey\n4008 Insufficient points 🆕\tInsufficient points / Error 4008\t❌ 积分不足，无法创建任务<br>💡 购买积分: https://www.imaclaw.ai/imaclaw/subscription\t❌ Insufficient points to create this task<br>💡 Buy Credits: https://www.imaclaw.ai/imaclaw/subscription\n\"Invalid product attribute\" / \"Insufficient points\"\tInvalid product attribute\t生成参数配置异常，请稍后重试\tConfiguration error, please try again later\nError 6006 (credit mismatch)\tError 6006\t积分计算异常，系统正在修复\tPoints calculation error, system is fixing\nError 6010 (attribute_id mismatch)\tAttribute ID does not match\t模型参数不匹配，请尝试其他模型\tModel parameters incompatible, try another model\nerror 400 (bad request)\terror 400 / Bad request\t音乐参数设置有误，请调整描述后重试\tMusic parameter error, adjust description and retry\nresource_status == 2\tResource status 2 / Failed\t音乐生成遇到问题，建议换个模型试试\tMusic generation failed, try another model\nstatus == \"failed\" (no details)\tTask failed\t这次生成没成功，要不换个模型试试？\tGeneration unsuccessful, try a different model?\ntimeout\tTask timed out / Timeout error\t音乐生成时间过长已超时，建议用更快的模型\tMusic generation took too long, try a faster model\nNetwork error / Connection refused\tConnection refused / Network error\t网络连接不稳定，请检查网络后重试\tNetwork connection unstable, check network and retry\nRate limit exceeded\t429 Too Many Requests / Rate limit\t请求过于频繁，请稍等片刻再试\tToo many requests, please wait a moment\nModel unavailable\tModel not available / 503 Service Unavailable\t当前模型暂时不可用，建议换个模型\tModel temporarily unavailable, try another model\nLyrics format error (Suno only)\tInvalid lyrics format\t歌词格式有误，请调整后重试\tLyrics format error, adjust and retry\nPrompt too short/long\tPrompt length invalid\t音乐描述过短或过长，请调整到合适长度\tMusic description too short or long, adjust length\n\nGeneric fallback (when error is unknown):\n\nChinese: 音乐生成遇到问题，请稍后重试或换个模型试试\nEnglish: Music generation encountered an issue, please try again or use another model\n\nBest Practices:\n\nFocus on user action: Tell users what to do next, not what went wrong technically\nBe reassuring: Use phrases like \"建议换个模型试试\" instead of \"生成失败了\"\nAvoid blame: Never say \"你的描述有问题\" → say \"描述需要调整一下\"\nProvide alternatives: Always suggest 1-2 alternative models in the failure message\nMusic-specific:\nFor Suno lyrics errors, suggest simplifying lyrics or using auto-generated lyrics\nFor prompt length errors, give example length (e.g., \"建议20-100字\")\nFor BGM requests, recommend DouBao BGM over Suno\n🆕 Include actionable links (v1.0.8+): For 401/4008 errors, provide clickable links to API key generation or credit purchase pages\n\n🆕 Enhanced Error Handling (v1.0.8):\n\nMusic generation uses direct error handling (no Reflection mechanism due to simpler parameters):\n\n401 Unauthorized: System provides clickable link to API key generation page\n4008 Insufficient Points: System provides clickable link to credit purchase page\nOther errors: Clear natural language explanations with alternative model suggestions\n\nError messages are user-friendly and actionable — users receive clear next steps for resolution.\n\nFailure fallback table:\n\nFailed Model\tFirst Alt\tSecond Alt\nSuno\tDouBao BGM（30pts，背景音乐）\tDouBao Song（30pts，歌曲生成）\nDouBao BGM\tDouBao Song（30pts）\tSuno（25pts，功能最强）\nDouBao Song\tDouBao BGM（30pts）\tSuno（25pts，功能最强）\nStep 5 — Done (No Further Action Needed) 🆕\n\nv1.1 Note: After completing Steps 0-4:\n\n✅ Step 0 already sent your normal reply (appears FIRST in chat)\n✅ Steps 1-4 pushed all updates via message tool (appear in order)\n✅ No further action needed — conversation is complete\n\nDo NOT:\n\n❌ Reply again with NO_REPLY (you already replied in Step 0)\n❌ Send duplicate confirmation messages\n❌ Use message tool to send the same content twice\n\nWhy this works:\n\nUser: \"帮我生成一段轻松的背景音乐\"\n  ↓\n[Step 0] Your normal reply:  \"好的！马上帮你生成轻松的背景音乐 🎵\"  ← Appears FIRST\n  ↓\n[Step 1] message tool push:  \"🎵 开始生成音乐...\"  ← Appears SECOND\n  ↓\n[Step 2] message tool push:  \"⏳ 正在生成中… 45%\"  ← (if task takes >15s)\n  ↓\n[Step 3] message tool push:  \"✅ 音乐生成成功! [Audio File]\"  ← Appears LAST\n  ↓\n[Step 5] Done. No further replies.\n\nSupported Models\ntext_to_music (3 models)\nName\tmodel_id\tversion_id\tCost\tKey form_config\nSuno\tsonic\tsonic\t25 pts\tmodel_version=sonic-v5 (latest), custom_mode=true, make_instrumental, auto_lyrics, tags, negative_tags, vocal_gender, title\nDouBao BGM\tGenBGM\tGenBGM\t30 pts\t—\nDouBao Song\tGenSong\tGenSong\t30 pts\t—\n\nModel guidance:\n\nSuno: Most powerful option. Supports full custom mode with genre tags, explicit instrumental toggle, vocal gender selection, and negative tags to exclude unwanted styles.\nDouBao BGM: Lightweight background music generation. Ideal for ambient / background tracks.\nDouBao Song: Song generation. Good for structured vocal compositions.\n\nWhat you can generate:\n\nBackground music (lo-fi, ambient, cinematic, electronic, jazz, classical…)\nCustom jingles or theme songs with specific BPM and key\nVocal or instrumental tracks with mood direction\nShort loops or full-length compositions\n\nPrompt writing tips (for Suno gpt_description_prompt):\n\nGenre: \"lo-fi hip hop\", \"orchestral cinematic\", \"upbeat pop\", \"dark ambient\"\nTempo: \"80 BPM\", \"fast tempo\", \"slow ballad\"\nVocals: \"no vocals\" → set make_instrumental=true; \"female vocals\" → vocal_gender=\"female\"\nMood: \"happy and energetic\", \"melancholic\", \"tense and dramatic\"\nNegative: negative_tags=\"heavy metal, distortion\" to exclude styles\nDuration hint: \"60 seconds\", \"30 second loop\"\nEnvironment\n\nBase URL: https://api.imastudio.com\n\nRequired/recommended headers for all /open/v1/ endpoints:\n\nHeader\tRequired\tValue\tNotes\nAuthorization\t✅\tBearer ima_your_api_key_here\tAPI key authentication\nx-app-source\t✅\tima_skills\tFixed value — identifies skill-originated requests\nx_app_language\trecommended\ten / zh\tProduct label language; defaults to en if omitted\nAuthorization: Bearer ima_your_api_key_here\nx-app-source: ima_skills\nx_app_language: en\n\n⚠️ MANDATORY: Always Query Product List First\n\nCRITICAL: You MUST call /open/v1/product/list BEFORE creating any task.\nThe attribute_id field is REQUIRED in the create request. If it is 0 or missing, you get:\n\"Invalid product attribute\" → \"Insufficient points\" → task fails completely.\nNEVER construct a create request from the model table alone. Always fetch the product first.\n\nHow to get attribute_id\n# Step 1: Query product list\nGET /open/v1/product/list?app=ima&platform=web&category=text_to_music\n\n# Step 2: Walk the tree to find your model\nfor group in response[\"data\"]:\n    for version in group.get(\"children\", []):\n        if version[\"type\"] == \"3\" and version[\"model_id\"] == target_model_id:\n            attribute_id  = version[\"credit_rules\"][0][\"attribute_id\"]\n            credit        = version[\"credit_rules\"][0][\"points\"]\n            model_version = version[\"id\"]\n            model_name    = version[\"name\"]\n\nQuick Reference: Known attribute_ids\n\n⚠️ Production warning: attribute_id and credit values change frequently. Always call /open/v1/product/list at runtime; table below is pre-queried reference (2026-02-27).\n\nModel\tmodel_id\tattribute_id\tcredit\tNotes\nSuno (sonic-v4)\tsonic\t2370\t25 pts\tDefault\nDouBao BGM\tGenBGM\t4399\t30 pts\tBGM专用\nDouBao Song\tGenSong\t4398\t30 pts\t歌曲专用\nAll others\t—\t→ query /open/v1/product/list\t—\tAlways runtime query\nCommon Mistakes (and resulting errors)\nMistake\tError\nattribute_id is 0 or missing\t\"Invalid product attribute\" → Insufficient points\nattribute_id outdated (production changed)\tSame errors; always query product list first\nprompt at outer level\tPrompt ignored\ncast missing from inner parameters\tBilling failure\nSuno: model_version in parameters not set to sonic-v5\tWrong engine used\nCore Flow\n1. GET /open/v1/product/list?app=ima&platform=web&category=text_to_music\n   → REQUIRED: Get attribute_id, credit, model_version, form_config defaults\n\n2. POST /open/v1/tasks/create\n   → Must include: attribute_id, model_name, model_version, credit, cast, prompt (nested!)\n\n3. POST /open/v1/tasks/detail  {task_id: \"...\"}\n   → Poll every 3–5s until medias[].resource_status == 1\n   → Extract url from completed media (mp3)\n\nSupported Task Types\ncategory\tCapability\tInput\ntext_to_music\tText → Music\tprompt\nDetail API status values\nField\tType\tValues\nresource_status\tint or null\t0=处理中, 1=可用, 2=失败, 3=已删除；null 当作 0\nstatus\tstring\t\"pending\", \"processing\", \"success\", \"failed\"\nresource_status\tstatus\tAction\n0 or null\tpending / processing\tKeep polling\n1\tsuccess (or completed)\tStop when all medias are 1; read url\n1\tfailed\tStop, handle error\n2 / 3\tany\tStop, handle error\n\nImportant: Treat resource_status: null as 0. Stop only when all medias have resource_status == 1. Check status != \"failed\" when rs=1.\n\nAPI 1: Product List\nGET /open/v1/product/list?app=ima&platform=web&category=text_to_music\n\n\nReturns a V2 tree structure: type=2 nodes are model groups, type=3 nodes are versions (leaves). Only type=3 nodes contain credit_rules and form_config.\n\nHow to pick a version:\n\nTraverse nodes to find type=3 leaves\nUse model_id and id (= model_version) from the leaf\nPick credit_rules[].attribute_id\nUse form_config[].value as default parameters values\nAPI 2: Create Task\nPOST /open/v1/tasks/create\n\ntext_to_music\n\nNo image input. src_img_url: [], input_images: [].\n\n{\n  \"task_type\": \"text_to_music\",\n  \"enable_multi_model\": false,\n  \"src_img_url\": [],\n  \"parameters\": [{\n    \"attribute_id\":  \"<from credit_rules>\",\n    \"model_id\":      \"<model_id>\",\n    \"model_name\":    \"<model_name>\",\n    \"model_version\": \"<version_id>\",\n    \"app\":           \"ima\",\n    \"platform\":      \"web\",\n    \"category\":      \"text_to_music\",\n    \"credit\":        \"<points>\",\n    \"parameters\": {\n      \"prompt\":       \"upbeat electronic, 120 BPM, no vocals\",\n      \"n\":            1,\n      \"input_images\": [],\n      \"cast\":         {\"points\": \"<points>\", \"attribute_id\": \"<attribute_id>\"}\n    }\n  }]\n}\n\n\nPrompt tips for music generation:\n\nGenre: \"upbeat electronic\", \"classical piano\", \"ambient chill\"\nTempo: \"120 BPM\", \"slow tempo\"\nVocals: \"no vocals\", \"male vocals\", \"female vocals\"\nMood: \"happy\", \"melancholic\", \"energetic\"\nDuration hint: \"60 seconds\", \"short loop\"\n\nKey fields:\n\nField\tRequired\tDescription\nparameters[].credit\t✅\tMust equal credit_rules[].points. Error 6006 if wrong.\nparameters[].parameters.prompt\t✅\tPrompt must be nested here, NOT at top level.\nparameters[].parameters.cast\t✅\t{\"points\": N, \"attribute_id\": N} — mirror of credit.\nparameters[].parameters.n\t✅\tNumber of outputs (usually 1).\n\nResponse: data.id = task ID for polling.\n\nAPI 3: Task Detail (Poll)\nPOST /open/v1/tasks/detail\n{\"task_id\": \"<id from create response>\"}\n\n\nPoll every 3–5s. Completed response:\n\n{\n  \"id\": \"task_abc\",\n  \"medias\": [{\n    \"resource_status\": 1,\n    \"url\":          \"https://cdn.../output.mp3\",\n    \"duration_str\": \"60s\",\n    \"format\":       \"mp3\"\n  }]\n}\n\n\nOutput fields: url (mp3), duration_str, format.\n\nCommon Mistakes\nMistake\tFix\nPlacing prompt at param top-level\tprompt must be inside parameters[].parameters\nWrong credit value\tMust exactly match credit_rules[].points (error 6006)\nMissing app / platform in parameters\tRequired — use ima / web\nSingle-poll instead of loop\tPoll until resource_status == 1 for ALL medias\nNot checking status != \"failed\"\tresource_status=1 + status=\"failed\" = actual failure\nPython Example\nimport time\nimport requests\n\nBASE_URL = \"https://api.imastudio.com\"\nAPI_KEY  = \"ima_your_key_here\"\nHEADERS  = {\n    \"Authorization\":  f\"Bearer {API_KEY}\",\n    \"Content-Type\":   \"application/json\",\n    \"x-app-source\":   \"ima_skills\",\n    \"x_app_language\": \"en\",\n}\n\n\ndef get_products(category: str) -> list:\n    \"\"\"Returns flat list of type=3 version nodes from V2 tree.\"\"\"\n    r = requests.get(\n        f\"{BASE_URL}/open/v1/product/list\",\n        headers=HEADERS,\n        params={\"app\": \"ima\", \"platform\": \"web\", \"category\": category},\n    )\n    r.raise_for_status()\n    nodes = r.json()[\"data\"]\n    versions = []\n    for node in nodes:\n        for child in node.get(\"children\") or []:\n            if child.get(\"type\") == \"3\":\n                versions.append(child)\n            for gc in child.get(\"children\") or []:\n                if gc.get(\"type\") == \"3\":\n                    versions.append(gc)\n    return versions\n\n\ndef create_music_task(prompt: str, product: dict) -> str:\n    \"\"\"Returns task_id.\"\"\"\n    rule = product[\"credit_rules\"][0]\n    form_defaults = {f[\"field\"]: f[\"value\"] for f in product.get(\"form_config\", []) if f.get(\"value\") is not None}\n\n    nested_params = {\n        \"prompt\": prompt,\n        \"n\":      1,\n        \"input_images\": [],\n        \"cast\":   {\"points\": rule[\"points\"], \"attribute_id\": rule[\"attribute_id\"]},\n        **form_defaults,\n    }\n\n    body = {\n        \"task_type\":          \"text_to_music\",\n        \"enable_multi_model\": False,\n        \"src_img_url\":        [],\n        \"parameters\": [{\n            \"attribute_id\":  rule[\"attribute_id\"],\n            \"model_id\":      product[\"model_id\"],\n            \"model_name\":    product[\"name\"],\n            \"model_version\": product[\"id\"],\n            \"app\":           \"ima\",\n            \"platform\":      \"web\",\n            \"category\":      \"text_to_music\",\n            \"credit\":        rule[\"points\"],\n            \"parameters\":    nested_params,\n        }],\n    }\n    r = requests.post(f\"{BASE_URL}/open/v1/tasks/create\", headers=HEADERS, json=body)\n    r.raise_for_status()\n    return r.json()[\"data\"][\"id\"]\n\n\ndef poll(task_id: str, interval: int = 3, timeout: int = 300) -> dict:\n    deadline = time.time() + timeout\n    while time.time() < deadline:\n        r = requests.post(f\"{BASE_URL}/open/v1/tasks/detail\", headers=HEADERS, json={\"task_id\": task_id})\n        r.raise_for_status()\n        task   = r.json()[\"data\"]\n        medias = task.get(\"medias\", [])\n        if medias:\n            if any(m.get(\"status\") == \"failed\" for m in medias):\n                raise RuntimeError(f\"Task failed: {task_id}\")\n            rs = lambda m: m.get(\"resource_status\") if m.get(\"resource_status\") is not None else 0\n            if any(rs(m) == 2 for m in medias):\n                raise RuntimeError(f\"Task failed: {task_id}\")\n            if all(rs(m) == 1 for m in medias):\n                return task\n        time.sleep(interval)\n    raise TimeoutError(f\"Task timed out: {task_id}\")\n\n\n# text_to_music\nproducts = get_products(\"text_to_music\")\ntask_id  = create_music_task(\"upbeat electronic, 120 BPM, no vocals\", products[0])\nresult   = poll(task_id)\nprint(result[\"medias\"][0][\"url\"])          # mp3 URL\nprint(result[\"medias\"][0][\"duration_str\"]) # e.g. \"60s\"\n\nSupported Models & Search Terms\n\nModels: Suno sonic v4, Suno sonic v5, DouBao BGM (GenBGM), DouBao Song (GenSong)\n\nCapabilities: music generation, text-to-music, AI music, background music, BGM, soundtrack, jingle, song with lyrics, vocal, instrumental, ambient music, audio generation"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/allenfancy-gan/ima-voice-ai",
    "publisherUrl": "https://clawhub.ai/allenfancy-gan/ima-voice-ai",
    "owner": "allenfancy-gan",
    "version": "1.0.7",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/ima-voice-ai",
    "downloadUrl": "https://openagent3.xyz/downloads/ima-voice-ai",
    "agentUrl": "https://openagent3.xyz/skills/ima-voice-ai/agent",
    "manifestUrl": "https://openagent3.xyz/skills/ima-voice-ai/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/ima-voice-ai/agent.md"
  }
}