$npx -y skills add calesthio/OpenMontage --skill dashscopeDashScope (Alibaba Cloud Bailian / 阿里云百炼) integration — image generation (qwen-image-2.0-pro), text-to-speech (qwen3-tts-flash), and ASR with word-level timestamps (qwen3-asr-flash-filetrans). Use when generating images via Qwen-Image, narrating via Qwen-TTS, or transcribing with
| 1 | # DashScope |
| 2 | |
| 3 | Requires `DASHSCOPE_API_KEY` in `.env`. Get one at https://dashscope.aliyun.com/. |
| 4 | |
| 5 | ## Current API |
| 6 | |
| 7 | **CRITICAL:** DashScope's `/compatible-mode/v1/` only supports `/chat/completions` and `/embeddings`. Image generation, TTS, and ASR all use **DashScope-native endpoints** — not OpenAI-compatible paths. |
| 8 | |
| 9 | All three tools use `Authorization: Bearer $DASHSCOPE_API_KEY`. |
| 10 | |
| 11 | ### Image Generation |
| 12 | |
| 13 | ```text |
| 14 | POST https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation |
| 15 | ``` |
| 16 | |
| 17 | - Model: `qwen-image-2.0-pro` (default), `qwen-image-max`, `wan2.7-image`, `z-image-turbo` |
| 18 | - Body: `{model, input: {messages: [{role: "user", content: [{text: "prompt"}]}]}, parameters: {size: "W*H", n, prompt_extend, watermark}}` |
| 19 | - **Size format uses asterisk:** `"1024*1024"` not `"1024x1024"` |
| 20 | - Response: `output.choices[0].message.content[0].image` (URL, valid ~24h) — must download separately |
| 21 | |
| 22 | ### Text-to-Speech |
| 23 | |
| 24 | ```text |
| 25 | POST https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation |
| 26 | ``` |
| 27 | |
| 28 | Same endpoint as image gen, different body. |
| 29 | |
| 30 | - Model: `qwen3-tts-flash` (default), `qwen3-tts-instruct-flash`, `qwen-tts-2025-05-22` |
| 31 | - Body: `{model, input: {text, voice: "Cherry", language_type: "Auto"}}` |
| 32 | - Response: `output.audio.url` (WAV, valid ~24h) — must download separately |
| 33 | |
| 34 | ### ASR with Word-Level Timestamps |
| 35 | |
| 36 | ```text |
| 37 | POST https://dashscope.aliyuncs.com/api/v1/services/audio/asr/transcription |
| 38 | Header: X-DashScope-Async: enable |
| 39 | ``` |
| 40 | |
| 41 | - Model: `qwen3-asr-flash-filetrans` (NOT `qwen3-asr-flash` — the sync version has no word timestamps) |
| 42 | - Body: `{model, input: {file_url: "https://public-url/audio.mp3"}, parameters: {enable_words: true, language_hints: ["zh","en"]}}` |
| 43 | - Returns `task_id` → poll `GET /api/v1/tasks/{task_id}` until `SUCCEEDED` → download `output.result.transcription_url` → JSON with `transcripts[].sentences[].words[]` |
| 44 | - Timestamps in `begin_time`/`end_time` are in **milliseconds** — the tool normalizes to seconds |
| 45 | |
| 46 | ## OpenMontage Usage |
| 47 | |
| 48 | ### Image via selector |
| 49 | |
| 50 | ```python |
| 51 | from tools.graphics.image_selector import ImageSelector |
| 52 | |
| 53 | result = ImageSelector().execute({ |
| 54 | "preferred_provider": "dashscope", |
| 55 | "prompt": "一只猫坐在沙发上", |
| 56 | "output_path": "projects/my-video/assets/images/cat.png", |
| 57 | }) |
| 58 | ``` |
| 59 | |
| 60 | ### TTS via selector |
| 61 | |
| 62 | ```python |
| 63 | from tools.audio.tts_selector import TTSSelector |
| 64 | |
| 65 | result = TTSSelector().execute({ |
| 66 | "preferred_provider": "dashscope", |
| 67 | "text": "如果 AI 真的会改变未来,普通人到底该怎么参与?", |
| 68 | "voice": "Cherry", |
| 69 | "output_path": "projects/my-video/assets/audio/narration.wav", |
| 70 | }) |
| 71 | ``` |
| 72 | |
| 73 | ### ASR directly (word timestamps for subtitles) |
| 74 | |
| 75 | ```python |
| 76 | from tools.analysis.dashscope_asr import DashscopeAsr |
| 77 | |
| 78 | result = DashscopeAsr().execute({ |
| 79 | "audio_url": "https://example.com/narration.wav", |
| 80 | "output_path": "projects/my-video/assets/audio/transcription.json", |
| 81 | }) |
| 82 | |
| 83 | # result.data["words"] is a flat list of {text, begin_time_seconds, end_time_seconds} |
| 84 | ``` |
| 85 | |
| 86 | ## Recommended Workflow |
| 87 | |
| 88 | 1. **Image:** Generate a sample first. Check `prompt_extend: true` (default) — DashScope rewrites your prompt for better results. Disable if you need literal prompt adherence. |
| 89 | 2. **TTS:** Generate a 10-15 second sample before full narration. Approve voice and pacing before committing to full generation. |
| 90 | 3. **ASR:** Audio must be at a **publicly accessible URL**. Upload to any public host (S3, etc.) first. Local paths are rejected with a clear error. |
| 91 | 4. **Subtitles:** Build from `result.data["words"]` — each word has `begin_time_seconds` and `end_time_seconds`. Group words into caption phrases by language semantics, not fixed character count. |
| 92 | |
| 93 | ## Parameters |
| 94 | |
| 95 | ### Image (`dashscope_image`) |
| 96 | - `prompt` (required): text prompt |
| 97 | - `model`: default `qwen-image-2.0-pro` |
| 98 | - `size`: default `"1024*1024"` — **asterisk separator, not "x"** |
| 99 | - `n`: 1-6 images |
| 100 | - `negative_prompt`: things to avoid (max 500 chars) |
| 101 | - `prompt_extend`: default `true` — auto-rewrite prompt for better results |
| 102 | - `watermark`: default `false` |
| 103 | - `seed`: for reproducibility |
| 104 | |
| 105 | ### TTS (`dashscope_tts`) |
| 106 | - `text` (required): text to synthesize (max 600 chars for qwen3-tts-flash) |
| 107 | - `model`: default `qwen3-tts-flash` |
| 108 | - `voice`: default `"Cherry"` — other voices: `"Ethan"`, `"Chelsie"`, etc. |
| 109 | - `language_type`: default `"Auto"` — `"Chinese"`, `"English"`, `"Japanese"`, `"Korean"` |
| 110 | - `instructions`: natural language delivery instructions (only for `qwen3-tts-instruct-flash`) |
| 111 | |
| 112 | ### ASR (`dashscope_asr`) |
| 113 | - `audio_url` (required): **must be publicly accessible URL** |
| 114 | - `model`: `qwen3-asr-flash-filetrans` (only model that supports word timestamps) |
| 115 | - `language_hints`: default `["zh", "en"]` |
| 116 | - `enable_words`: default `true` — required fo |