cue-ai 0.9.2 → 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -3
- package/README.md +148 -170
- package/bin/cue-learnings +30 -4
- package/bin/cue-review-progress +0 -0
- package/bin/cue-review-watch +0 -0
- package/dist/cue.js +4328 -3108
- package/package.json +1 -1
- package/plugins/cue/commands/cue-switch.md +1 -1
- package/plugins/cue/commands/cue.md +1 -1
- package/profiles/backend/profile.yaml +4 -0
- package/profiles/browser/profile.yaml +4 -0
- package/profiles/career/profile.yaml +2 -13
- package/profiles/commerce/profile.yaml +0 -2
- package/profiles/coolify/profile.yaml +0 -1
- package/profiles/core/profile.yaml +78 -11
- package/profiles/dash-merge-test/profile.yaml +6 -1
- package/profiles/designer/profile.yaml +9 -1
- package/profiles/dropshipping/profile.yaml +69 -0
- package/profiles/frontend/profile.yaml +4 -0
- package/profiles/google-ads/profile.yaml +34 -0
- package/profiles/google-analytics/profile.yaml +34 -0
- package/profiles/google-drive/profile.yaml +34 -0
- package/profiles/gstack/profile.yaml +117 -29
- package/profiles/marketing/profile.yaml +0 -1
- package/profiles/media/README.md +70 -0
- package/profiles/media/profile.yaml +104 -0
- package/profiles/nano-banana/profile.yaml +52 -0
- package/profiles/ops/profile.yaml +1 -2
- package/profiles/secops/profile.yaml +3 -0
- package/profiles/skill-writer/profile.yaml +15 -0
- package/profiles/video/profile.yaml +3 -0
- package/profiles/web-frontend-base/profile.yaml +6 -0
- package/profiles/webshop/profile.yaml +0 -1
- package/profiles/webshop-google/profile.yaml +1 -0
- package/profiles/x-growth-bot/profile.yaml +2 -0
- package/resources/icons/generate-icons.py +2 -128
- package/resources/mcps/configs/claude.sanitized.json +88 -20
- package/resources/mcps/configs/claude_runtime.sanitized.json +40 -1
- package/resources/mcps/configs/codex.sanitized.json +29 -0
- package/resources/skills/skills/career/job-hunter/LICENSE +21 -0
- package/resources/skills/skills/career/job-hunter/README.md +323 -0
- package/resources/skills/skills/career/job-hunter/SKILL.md +91 -0
- package/resources/skills/skills/career/job-hunter/agents/README.md +96 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-assessment-prep.md +195 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-ats-scan.md +155 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-bias-audit.md +224 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-cover-letter.md +69 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-decode-jd.md +117 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-fit-score.md +183 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-linkedin-audit.md +74 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-linkedin-scrape.md +255 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-portfolio-brief.md +123 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-reality-check.md +164 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-reference-prep.md +150 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-rejection-analysis.md +172 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-resume.md +70 -0
- package/resources/skills/skills/career/job-hunter/agents/apply-skills-gap-filler.md +109 -0
- package/resources/skills/skills/career/job-hunter/agents/career-internal.md +94 -0
- package/resources/skills/skills/career/job-hunter/agents/career-linkedin-content.md +173 -0
- package/resources/skills/skills/career/job-hunter/agents/career-linkedin-scanner.md +262 -0
- package/resources/skills/skills/career/job-hunter/agents/career-network-message.md +108 -0
- package/resources/skills/skills/career/job-hunter/agents/career-promote.md +102 -0
- package/resources/skills/skills/career/job-hunter/agents/career-review.md +71 -0
- package/resources/skills/skills/career/job-hunter/agents/interview-debrief.md +117 -0
- package/resources/skills/skills/career/job-hunter/agents/interview-mock.md +171 -0
- package/resources/skills/skills/career/job-hunter/agents/interview-panel-decoder.md +152 -0
- package/resources/skills/skills/career/job-hunter/agents/interview-prep.md +184 -0
- package/resources/skills/skills/career/job-hunter/agents/interview-question-bank.md +133 -0
- package/resources/skills/skills/career/job-hunter/agents/interview-research.md +148 -0
- package/resources/skills/skills/career/job-hunter/agents/offer-compare.md +117 -0
- package/resources/skills/skills/career/job-hunter/agents/offer-counteroffer.md +144 -0
- package/resources/skills/skills/career/job-hunter/agents/offer-deadline-manager.md +148 -0
- package/resources/skills/skills/career/job-hunter/agents/offer-negotiate.md +126 -0
- package/resources/skills/skills/career/job-hunter/agents/offer-schedule.md +99 -0
- package/resources/skills/skills/career/job-hunter/agents/offer-thankyou.md +80 -0
- package/resources/skills/skills/career/job-hunter/agents/search-company-research.md +146 -0
- package/resources/skills/skills/career/job-hunter/agents/search-follow-up.md +129 -0
- package/resources/skills/skills/career/job-hunter/agents/search-ghost-job-detector.md +152 -0
- package/resources/skills/skills/career/job-hunter/agents/search-inbox-scan.md +193 -0
- package/resources/skills/skills/career/job-hunter/agents/search-interview-scorecard.md +164 -0
- package/resources/skills/skills/career/job-hunter/agents/search-jobs.md +149 -0
- package/resources/skills/skills/career/job-hunter/agents/search-momentum-check.md +194 -0
- package/resources/skills/skills/career/job-hunter/agents/search-outreach.md +85 -0
- package/resources/skills/skills/career/job-hunter/agents/search-referral-finder.md +124 -0
- package/resources/skills/skills/career/job-hunter/agents/search-salary.md +96 -0
- package/resources/skills/skills/career/job-hunter/agents/search-send-email.md +109 -0
- package/resources/skills/skills/career/job-hunter/agents/search-tracker-update.md +127 -0
- package/resources/skills/skills/career/job-hunter/inputs/README.md +26 -0
- package/resources/skills/skills/career/job-hunter/inputs/apply-linkedin-url.txt +8 -0
- package/resources/skills/skills/career/job-hunter/inputs/interview-context.md +24 -0
- package/resources/skills/skills/career/job-hunter/inputs/job-description.md +20 -0
- package/resources/skills/skills/career/job-hunter/inputs/job-search-criteria.md +36 -0
- package/resources/skills/skills/career/job-hunter/inputs/my-linkedin.md +24 -0
- package/resources/skills/skills/career/job-hunter/inputs/my-resume.md +28 -0
- package/resources/skills/skills/career/job-hunter/inputs/search-outreach-target.md +24 -0
- package/resources/skills/skills/career/job-hunter/rules/README.md +37 -0
- package/resources/skills/skills/career/job-hunter/rules/writing-rules.md +81 -0
- package/resources/skills/skills/design/banana/SKILL.md +375 -0
- package/resources/skills/skills/design/banana/references/cost-tracking.md +47 -0
- package/resources/skills/skills/design/banana/references/gemini-models.md +236 -0
- package/resources/skills/skills/design/banana/references/mcp-tools.md +145 -0
- package/resources/skills/skills/design/banana/references/post-processing.md +192 -0
- package/resources/skills/skills/design/banana/references/presets.md +69 -0
- package/resources/skills/skills/design/banana/references/prompt-engineering.md +481 -0
- package/resources/skills/skills/design/banana/scripts/batch.py +97 -0
- package/resources/skills/skills/design/banana/scripts/cost_tracker.py +191 -0
- package/resources/skills/skills/design/banana/scripts/edit.py +159 -0
- package/resources/skills/skills/design/banana/scripts/generate.py +168 -0
- package/resources/skills/skills/design/banana/scripts/presets.py +154 -0
- package/resources/skills/skills/design/banana/scripts/setup_mcp.py +151 -0
- package/resources/skills/skills/design/banana/scripts/validate_setup.py +133 -0
- package/resources/skills/skills/gstack/ship/SKILL.md +13 -0
- package/resources/skills/skills/media/3d-logo-animation/SKILL.md +59 -0
- package/resources/skills/skills/media/action-figure-generator/SKILL.md +48 -0
- package/resources/skills/skills/media/ad-creative/SKILL.md +79 -0
- package/resources/skills/skills/media/ai-clipping/SKILL.md +194 -0
- package/resources/skills/skills/media/ai-clipping/scripts/run-ai-clipping.sh +200 -0
- package/resources/skills/skills/media/ai-fight-scene/SKILL.md +132 -0
- package/resources/skills/skills/media/amazon-product-listing/SKILL.md +68 -0
- package/resources/skills/skills/media/animal-video-generator/SKILL.md +59 -0
- package/resources/skills/skills/media/award-ceremony-video/SKILL.md +87 -0
- package/resources/skills/skills/media/blog-header/SKILL.md +61 -0
- package/resources/skills/skills/media/brand-kit/SKILL.md +72 -0
- package/resources/skills/skills/media/brochures/SKILL.md +65 -0
- package/resources/skills/skills/media/cartoon-dance-animation/SKILL.md +62 -0
- package/resources/skills/skills/media/character-story-video/SKILL.md +84 -0
- package/resources/skills/skills/media/chibi-collage-effect/SKILL.md +63 -0
- package/resources/skills/skills/media/cinema-director/SKILL.md +93 -0
- package/resources/skills/skills/media/cinema-director/scripts/generate-film.sh +78 -0
- package/resources/skills/skills/media/color-analysis-board/SKILL.md +71 -0
- package/resources/skills/skills/media/core-edit/SKILL.md +48 -0
- package/resources/skills/skills/media/core-edit/edit-image.sh +54 -0
- package/resources/skills/skills/media/core-edit/enhance-image.sh +191 -0
- package/resources/skills/skills/media/core-edit/lipsync.sh +144 -0
- package/resources/skills/skills/media/core-edit/video-effects.sh +193 -0
- package/resources/skills/skills/media/core-media/SKILL.md +49 -0
- package/resources/skills/skills/media/core-media/create-music.sh +169 -0
- package/resources/skills/skills/media/core-media/generate-image.sh +161 -0
- package/resources/skills/skills/media/core-media/generate-video.sh +137 -0
- package/resources/skills/skills/media/core-media/image-to-video.sh +228 -0
- package/resources/skills/skills/media/core-media/schema_data.json +18708 -0
- package/resources/skills/skills/media/core-media/upload.sh +41 -0
- package/resources/skills/skills/media/core-platform/SKILL.md +41 -0
- package/resources/skills/skills/media/core-platform/check-result.sh +37 -0
- package/resources/skills/skills/media/core-platform/setup.sh +31 -0
- package/resources/skills/skills/media/couple-grid-creator/SKILL.md +47 -0
- package/resources/skills/skills/media/design-guide/SKILL.md +73 -0
- package/resources/skills/skills/media/drone-style-video/SKILL.md +61 -0
- package/resources/skills/skills/media/fashion-try-on/SKILL.md +61 -0
- package/resources/skills/skills/media/floor-plan-rendering/SKILL.md +56 -0
- package/resources/skills/skills/media/freeze-effect-video/SKILL.md +100 -0
- package/resources/skills/skills/media/giant-product-showcase/SKILL.md +61 -0
- package/resources/skills/skills/media/instagram-post/SKILL.md +58 -0
- package/resources/skills/skills/media/interior-design/SKILL.md +61 -0
- package/resources/skills/skills/media/interior-design-visualizer/SKILL.md +57 -0
- package/resources/skills/skills/media/jewelry-product-video/SKILL.md +61 -0
- package/resources/skills/skills/media/kdenlive/SKILL.md +106 -0
- package/resources/skills/skills/media/kdenlive/scripts/assemble.sh +57 -0
- package/resources/skills/skills/media/kdenlive/scripts/common.sh +30 -0
- package/resources/skills/skills/media/kdenlive/scripts/inspect.sh +19 -0
- package/resources/skills/skills/media/kdenlive/scripts/reframe.sh +22 -0
- package/resources/skills/skills/media/kdenlive/scripts/render.sh +16 -0
- package/resources/skills/skills/media/kdenlive/scripts/title-card.sh +25 -0
- package/resources/skills/skills/media/keyboard-art-maker/SKILL.md +44 -0
- package/resources/skills/skills/media/logo-branding/SKILL.md +70 -0
- package/resources/skills/skills/media/logo-creator/SKILL.md +80 -0
- package/resources/skills/skills/media/logo-creator/scripts/create-logo.sh +38 -0
- package/resources/skills/skills/media/logo-generator/SKILL.md +56 -0
- package/resources/skills/skills/media/multi-angle-reshoot/SKILL.md +70 -0
- package/resources/skills/skills/media/multi-angle-shots/SKILL.md +73 -0
- package/resources/skills/skills/media/music-video/SKILL.md +61 -0
- package/resources/skills/skills/media/nano-banana/SKILL.md +80 -0
- package/resources/skills/skills/media/nano-banana/scripts/generate-nano-art.sh +54 -0
- package/resources/skills/skills/media/one-shot-video/SKILL.md +56 -0
- package/resources/skills/skills/media/photo-pack-generator/SKILL.md +205 -0
- package/resources/skills/skills/media/photo-pack-generator/scripts/generate-pack.sh +241 -0
- package/resources/skills/skills/media/product-ad-cinematic/SKILL.md +78 -0
- package/resources/skills/skills/media/product-campaign/SKILL.md +76 -0
- package/resources/skills/skills/media/product-showcase-video/SKILL.md +60 -0
- package/resources/skills/skills/media/product-video-ad-maker/SKILL.md +59 -0
- package/resources/skills/skills/media/rednote-cover/SKILL.md +57 -0
- package/resources/skills/skills/media/seedance-2/SKILL.md +632 -0
- package/resources/skills/skills/media/seedance-2/scripts/generate-seedance.sh +701 -0
- package/resources/skills/skills/media/selfie-with-celebrities/SKILL.md +64 -0
- package/resources/skills/skills/media/social-media-video/SKILL.md +277 -0
- package/resources/skills/skills/media/social-media-video/scripts/run-social-video.sh +316 -0
- package/resources/skills/skills/media/social-pack/SKILL.md +58 -0
- package/resources/skills/skills/media/storyboard/SKILL.md +57 -0
- package/resources/skills/skills/media/storyboard-to-cooking-video/SKILL.md +143 -0
- package/resources/skills/skills/media/talking-baby-video/SKILL.md +57 -0
- package/resources/skills/skills/media/ugc-ads-workflow/SKILL.md +70 -0
- package/resources/skills/skills/media/ugc-lifestyle-try-on/SKILL.md +65 -0
- package/resources/skills/skills/media/ugc-video-factory/SKILL.md +134 -0
- package/resources/skills/skills/media/ui-design/SKILL.md +81 -0
- package/resources/skills/skills/media/ui-design/scripts/generate-mockup.sh +49 -0
- package/resources/skills/skills/media/url-to-design/SKILL.md +61 -0
- package/resources/skills/skills/media/workflow/SKILL.md +197 -0
- package/resources/skills/skills/media/workflow/scripts/discover-workflow.sh +18 -0
- package/resources/skills/skills/media/workflow/scripts/generate-workflow.sh +33 -0
- package/resources/skills/skills/media/workflow/scripts/interactive-run.sh +16 -0
- package/resources/skills/skills/media/workflow/scripts/list-workflows.sh +20 -0
- package/resources/skills/skills/media/workflow/scripts/run-workflow.sh +34 -0
- package/resources/skills/skills/media/youtube-shorts/SKILL.md +173 -0
- package/resources/skills/skills/media/youtube-shorts/scripts/run-youtube-shorts.sh +141 -0
- package/resources/skills/skills/media/youtube-thumbnail/SKILL.md +66 -0
- package/resources/skills/skills/meta/cue-developer/references/architecture.md +2 -2
- package/resources/skills/skills/meta/cue-usage/SKILL.md +1 -1
- package/resources/skills/skills/meta/profile-fit-monitor/SKILL.md +2 -2
- package/resources/skills/skills/meta/profile-optimizer/SKILL.md +1 -1
- package/resources/skills/skills/meta/profile-suggest/SKILL.md +7 -7
- package/resources/skills/skills/meta/profile-summon/SKILL.md +159 -0
- package/resources/skills/skills/meta/profile-summon/evals/evals.json +53 -0
- package/resources/skills/skills/meta/save-profile/SKILL.md +1 -1
- package/resources/skills/skills/meta/skill-reviewer/SKILL.md +3 -0
- package/resources/skills/skills/meta/skill-reviewer/references/tdd-for-skills.md +55 -0
- package/resources/skills/skills/research/find-skills/SKILL.md +1 -1
- package/resources/skills/skills/review/code-review-deep/SKILL.md +20 -0
- package/resources/skills/skills/security/trivy-scan/SKILL.md +139 -0
- package/resources/skills/skills/security/trivy-scan/scripts/ensure-trivy.sh +21 -0
- package/resources/skills/skills/tools/ccusage/SKILL.md +142 -0
- package/src/commands/_index.ts +8 -0
- package/src/commands/ai.ts +2 -2
- package/src/commands/auto-detect.test.ts +74 -0
- package/src/commands/auto-detect.ts +9 -7
- package/src/commands/cli.test.ts +20 -4
- package/src/commands/cli.ts +36 -20
- package/src/commands/create-profile.ts +2 -2
- package/src/commands/debug.ts +2 -2
- package/src/commands/discover.ts +14 -4
- package/src/commands/export-docker.ts +1 -1
- package/src/commands/features-batch1.test.ts +1 -1
- package/src/commands/gates.ts +1 -1
- package/src/commands/import-profile.ts +1 -1
- package/src/commands/init.ts +15 -11
- package/src/commands/install.test.ts +192 -0
- package/src/commands/install.ts +610 -0
- package/src/commands/launch-handoff.e2e.test.ts +33 -1
- package/src/commands/launch.e2e.test.ts +15 -10
- package/src/commands/launch.ts +73 -116
- package/src/commands/materialize.ts +2 -2
- package/src/commands/prune.ts +1 -1
- package/src/commands/security-audit.ts +1 -1
- package/src/commands/shell.ts +7 -7
- package/src/commands/skill-report.ts +1 -1
- package/src/commands/skills.ts +3 -3
- package/src/commands/snapshot.ts +2 -2
- package/src/commands/summon.test.ts +116 -0
- package/src/commands/summon.ts +338 -0
- package/src/commands/trigger-gaps.ts +1 -1
- package/src/commands/use.ts +47 -3
- package/src/commands/watch-live.ts +5 -5
- package/src/commands/watch.ts +8 -8
- package/src/index.ts +2 -0
- package/src/lib/active-sessions.test.ts +3 -3
- package/src/lib/active-sessions.ts +4 -4
- package/src/lib/auto-detect.test.ts +172 -8
- package/src/lib/auto-detect.ts +191 -136
- package/src/lib/codex-persona-parity.test.ts +58 -0
- package/src/lib/companion-detect.test.ts +43 -1
- package/src/lib/companion-detect.ts +35 -0
- package/src/lib/credentials-sync.test.ts +121 -1
- package/src/lib/credentials-sync.ts +95 -1
- package/src/lib/cwd-resolver.test.ts +8 -8
- package/src/lib/cwd-resolver.ts +2 -2
- package/src/lib/dashboard-merge.test.ts +9 -4
- package/src/lib/dashboard-server.ts +1 -1
- package/src/lib/picker.test.ts +1 -1
- package/src/lib/picker.ts +5 -5
- package/src/lib/profile-merge.test.ts +8 -0
- package/src/lib/profile-names.test.ts +3 -3
- package/src/lib/runtime-install.ts +166 -0
- package/src/lib/runtime-materializer.test.ts +137 -0
- package/src/lib/runtime-materializer.ts +105 -2
- package/src/lib/skill-router.test.ts +38 -0
- package/src/lib/skill-router.ts +65 -4
- package/profiles/eu-tender-research/README.md +0 -48
- package/profiles/eu-tender-research/logo.png +0 -0
- package/profiles/eu-tender-research/profile.yaml +0 -108
|
@@ -0,0 +1,701 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Expert Skill: Seedance 2 Cinema Expert
|
|
3
|
+
# Translates creative intent into 'Director-Level' technical directives for Seedance 2.0.
|
|
4
|
+
#
|
|
5
|
+
# Modes: t2v | i2v | extend | first-last | omni | omni-train | character | video-edit | watermark-remove
|
|
6
|
+
# Tiers: chinese (default) | global | vip
|
|
7
|
+
# Options: --fast for fast-queue variants (global/vip only)
|
|
8
|
+
#
|
|
9
|
+
# Requires: bash 3.2+, curl, jq, python3
|
|
10
|
+
|
|
11
|
+
set -euo pipefail
|
|
12
|
+
|
|
13
|
+
SUBJECT=""
|
|
14
|
+
INTENT="cinematic"
|
|
15
|
+
ASPECT="16:9"
|
|
16
|
+
DURATION=5
|
|
17
|
+
QUALITY="basic"
|
|
18
|
+
AUDIO_FLAG=""
|
|
19
|
+
VIEW=false
|
|
20
|
+
MODE="t2v"
|
|
21
|
+
TIER="chinese"
|
|
22
|
+
FAST=false
|
|
23
|
+
IMAGE_URLS=()
|
|
24
|
+
IMAGE_FILES=()
|
|
25
|
+
VIDEO_URLS=()
|
|
26
|
+
VIDEO_FILES=()
|
|
27
|
+
AUDIO_URLS=()
|
|
28
|
+
AUDIO_FILES=()
|
|
29
|
+
EXTEND_REQUEST_ID=""
|
|
30
|
+
CHARACTER_NAME=""
|
|
31
|
+
CHARACTER_DESC=""
|
|
32
|
+
REMOVE_WATERMARK=false
|
|
33
|
+
PRO_WATERMARK=false
|
|
34
|
+
ASYNC=false
|
|
35
|
+
JSON_ONLY=false
|
|
36
|
+
MAX_WAIT=600
|
|
37
|
+
POLL_INTERVAL=5
|
|
38
|
+
|
|
39
|
+
MUAPI_BASE="https://api.muapi.ai/api/v1"
|
|
40
|
+
|
|
41
|
+
# Load .env if present (suppress errors, disable nounset temporarily)
|
|
42
|
+
if [ -f ".env" ]; then
|
|
43
|
+
set +u; source .env 2>/dev/null || true; set -u
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# ============================================================
|
|
47
|
+
# Argument parsing
|
|
48
|
+
# ============================================================
|
|
49
|
+
while [[ $# -gt 0 ]]; do
|
|
50
|
+
case $1 in
|
|
51
|
+
--mode) MODE="$2"; shift 2 ;;
|
|
52
|
+
--tier) TIER="$2"; shift 2 ;;
|
|
53
|
+
--fast) FAST=true; shift ;;
|
|
54
|
+
--subject) SUBJECT="$2"; shift 2 ;;
|
|
55
|
+
--intent) INTENT="$2"; shift 2 ;;
|
|
56
|
+
--aspect) ASPECT="$2"; shift 2 ;;
|
|
57
|
+
--duration) DURATION="$2"; shift 2 ;;
|
|
58
|
+
--quality) QUALITY="$2"; shift 2 ;;
|
|
59
|
+
--no-audio) AUDIO_FLAG="--no-audio"; shift ;;
|
|
60
|
+
--view) VIEW=true; shift ;;
|
|
61
|
+
--image|--image-url) IMAGE_URLS+=("$2"); shift 2 ;;
|
|
62
|
+
--file|--image-file) IMAGE_FILES+=("$2"); shift 2 ;;
|
|
63
|
+
--video-url) VIDEO_URLS+=("$2"); shift 2 ;;
|
|
64
|
+
--video-file) VIDEO_FILES+=("$2"); shift 2 ;;
|
|
65
|
+
--audio-url) AUDIO_URLS+=("$2"); shift 2 ;;
|
|
66
|
+
--audio-file) AUDIO_FILES+=("$2"); shift 2 ;;
|
|
67
|
+
--request-id) EXTEND_REQUEST_ID="$2"; shift 2 ;;
|
|
68
|
+
--character-name) CHARACTER_NAME="$2"; shift 2 ;;
|
|
69
|
+
--character-desc) CHARACTER_DESC="$2"; shift 2 ;;
|
|
70
|
+
--remove-watermark) REMOVE_WATERMARK=true; shift ;;
|
|
71
|
+
--pro) PRO_WATERMARK=true; shift ;;
|
|
72
|
+
--async) ASYNC=true; shift ;;
|
|
73
|
+
--json) JSON_ONLY=true; shift ;;
|
|
74
|
+
--help|-h)
|
|
75
|
+
cat <<'HELP'
|
|
76
|
+
Seedance 2 Cinema Expert
|
|
77
|
+
Usage: bash generate-seedance.sh --mode MODE [options]
|
|
78
|
+
|
|
79
|
+
MODES
|
|
80
|
+
t2v Text-to-Video
|
|
81
|
+
i2v Image-to-Video (1–9 images)
|
|
82
|
+
extend Extend an existing Seedance 2.0 video (Chinese tier only)
|
|
83
|
+
first-last First & Last Frame interpolation (Global/VIP; 1–2 images)
|
|
84
|
+
omni Omni Reference — images + audio + optional @character refs
|
|
85
|
+
omni-train Train a custom Omni Reference character (one reference image)
|
|
86
|
+
character Build a character sheet from 1–3 images
|
|
87
|
+
video-edit Edit a video with prompt + optional reference images (Chinese tier)
|
|
88
|
+
watermark-remove Remove watermark from a Seedance 2.0 video
|
|
89
|
+
|
|
90
|
+
TIERS (default: chinese)
|
|
91
|
+
chinese seedance-v2.0-* endpoints — lower cost, low censorship
|
|
92
|
+
global seedance-2-* endpoints — 21:9/1:1 aspect ratios, flexible 4–15s duration
|
|
93
|
+
vip seedance-2-vip-* endpoints — fast queue + low censorship
|
|
94
|
+
|
|
95
|
+
OPTIONS
|
|
96
|
+
--fast Use fast-queue variant (global/vip tiers only)
|
|
97
|
+
--subject TEXT Scene description / prompt (required for most modes)
|
|
98
|
+
--intent TYPE reveal|tense|epic|narrative|product|educational|comedy|fpv|drone|flythrough (default: cinematic)
|
|
99
|
+
--aspect RATIO 16:9|9:16|4:3|3:4 — global/vip also support: 21:9|1:1 (default: 16:9)
|
|
100
|
+
--duration N Chinese: 5|10|15 s — global/vip: any integer 4–15 s (default: 5)
|
|
101
|
+
--quality Q basic|high (Chinese tier only; default: basic)
|
|
102
|
+
--view Download and open the output file (macOS)
|
|
103
|
+
--async Return request_id immediately without polling
|
|
104
|
+
--json Raw JSON output only
|
|
105
|
+
|
|
106
|
+
INPUTS
|
|
107
|
+
--image URL Image URL (repeatable, up to 9)
|
|
108
|
+
--file PATH Local image file — auto-uploaded (repeatable)
|
|
109
|
+
--video-url URL Reference video URL (repeatable, up to 3; Chinese i2v/omni only)
|
|
110
|
+
--video-file PATH Local video file — auto-uploaded (repeatable)
|
|
111
|
+
--audio-url URL Reference audio URL (repeatable, up to 3)
|
|
112
|
+
--audio-file PATH Local audio file — auto-uploaded (repeatable)
|
|
113
|
+
|
|
114
|
+
MODE-SPECIFIC OPTIONS
|
|
115
|
+
extend: --request-id ID request_id of the original Seedance 2.0 video
|
|
116
|
+
character: --character-name NAME optional character label
|
|
117
|
+
--subject TEXT optional outfit/costume description
|
|
118
|
+
omni-train: --character-name NAME character name for @omni-character ref
|
|
119
|
+
--character-desc TEXT optional character description
|
|
120
|
+
video-edit: --video-url/--video-file source video (1 max, 10MB, 15s)
|
|
121
|
+
--remove-watermark strip watermark from edited output
|
|
122
|
+
watermark-remove: --video-url/--video-file Seedance 2.0 video URL
|
|
123
|
+
--pro use Pro remover (100MB limit)
|
|
124
|
+
|
|
125
|
+
EXAMPLES
|
|
126
|
+
# Chinese T2V (default)
|
|
127
|
+
bash generate-seedance.sh --subject "hidden Andes temple at dawn" --intent epic --view
|
|
128
|
+
|
|
129
|
+
# Global T2V — 21:9, 12s, fast queue
|
|
130
|
+
bash generate-seedance.sh --tier global --fast --subject "neon cyberpunk alley" --aspect "21:9" --duration 12
|
|
131
|
+
|
|
132
|
+
# VIP I2V
|
|
133
|
+
bash generate-seedance.sh --mode i2v --tier vip --fast --file hero.jpg --subject "hero strides forward"
|
|
134
|
+
|
|
135
|
+
# First & Last Frame (global)
|
|
136
|
+
bash generate-seedance.sh --mode first-last --tier global --file start.jpg --file end.jpg \
|
|
137
|
+
--subject "smooth cinematic transition"
|
|
138
|
+
|
|
139
|
+
# Omni Reference (global, with character ref)
|
|
140
|
+
bash generate-seedance.sh --mode omni --tier global --file portrait.jpg \
|
|
141
|
+
--subject "@image1 walks through a neon-lit city at night"
|
|
142
|
+
|
|
143
|
+
# Train Omni Reference character
|
|
144
|
+
bash generate-seedance.sh --mode omni-train --file portrait.jpg \
|
|
145
|
+
--character-name "Alex" --character-desc "A brave explorer"
|
|
146
|
+
|
|
147
|
+
# Chinese character sheet
|
|
148
|
+
bash generate-seedance.sh --mode character --file ref1.jpg --file ref2.jpg \
|
|
149
|
+
--character-name "Hero" --subject "red leather jacket"
|
|
150
|
+
|
|
151
|
+
# Video Edit
|
|
152
|
+
bash generate-seedance.sh --mode video-edit \
|
|
153
|
+
--video-url "https://example.com/input.mp4" --file replacement.jpg \
|
|
154
|
+
--subject "Replace the runner with @image1, preserve exact motion and camera"
|
|
155
|
+
|
|
156
|
+
# Watermark Remove (Pro)
|
|
157
|
+
bash generate-seedance.sh --mode watermark-remove --video-url "https://example.com/v.mp4" --pro
|
|
158
|
+
HELP
|
|
159
|
+
exit 0 ;;
|
|
160
|
+
*)
|
|
161
|
+
echo "Warning: Unknown argument '$1' — skipping." >&2
|
|
162
|
+
shift ;;
|
|
163
|
+
esac
|
|
164
|
+
done
|
|
165
|
+
|
|
166
|
+
# ============================================================
|
|
167
|
+
# Validate API key
|
|
168
|
+
# ============================================================
|
|
169
|
+
if [ -z "${MUAPI_KEY:-}" ]; then
|
|
170
|
+
echo "Error: MUAPI_KEY is not set. Export it or add to .env" >&2
|
|
171
|
+
exit 1
|
|
172
|
+
fi
|
|
173
|
+
|
|
174
|
+
HEADERS=(-H "x-api-key: $MUAPI_KEY" -H "Content-Type: application/json")
|
|
175
|
+
|
|
176
|
+
# ============================================================
|
|
177
|
+
# Director's Cinematography Grammar
|
|
178
|
+
# ============================================================
|
|
179
|
+
case "$INTENT" in
|
|
180
|
+
reveal)
|
|
181
|
+
MOVEMENT="Slow crane up and tilt down, wide establishing shot."
|
|
182
|
+
LIGHTING="Volumetric god rays, golden hour atmosphere, warm bloom."
|
|
183
|
+
OPTICS="Deep focus, anamorphic widescreen, ultra-high clarity."
|
|
184
|
+
;;
|
|
185
|
+
tense)
|
|
186
|
+
MOVEMENT="Handheld jittery movement, dutch angle close-up, unstable framing."
|
|
187
|
+
LIGHTING="Low key, harsh shadows, flickering magenta neon, split lighting."
|
|
188
|
+
OPTICS="Shallow depth of field, anamorphic lens flare, slight motion blur."
|
|
189
|
+
;;
|
|
190
|
+
epic)
|
|
191
|
+
MOVEMENT="Dolly in with circular orbit, low hero angle, sweeping arc."
|
|
192
|
+
LIGHTING="Dramatic rim lighting, high contrast cinematic grade, specular highlights."
|
|
193
|
+
OPTICS="Anamorphic 35mm, sharp focus on subject, chromatic aberration edges."
|
|
194
|
+
;;
|
|
195
|
+
narrative)
|
|
196
|
+
MOVEMENT="Smooth tracking shot following subject, natural Steadicam motion."
|
|
197
|
+
LIGHTING="Natural soft light, blue hour tones, practical light sources."
|
|
198
|
+
OPTICS="Standard 50mm, realistic bokeh, minimal distortion."
|
|
199
|
+
;;
|
|
200
|
+
product)
|
|
201
|
+
MOVEMENT="Static camera with slow macro orbit, precision product reveal."
|
|
202
|
+
LIGHTING="Perfect even exposure, specular highlights on product surface."
|
|
203
|
+
OPTICS="Macro lens, zero distortion, commercial grade clarity."
|
|
204
|
+
;;
|
|
205
|
+
educational)
|
|
206
|
+
MOVEMENT="Slow push in, clinical camera movements, no handheld jitter."
|
|
207
|
+
LIGHTING="Even neutral lighting, high clarity, no dramatic shadows."
|
|
208
|
+
OPTICS="Standard lens, deep focus, semi-transparent CGI visualization."
|
|
209
|
+
;;
|
|
210
|
+
comedy)
|
|
211
|
+
MOVEMENT="Reactive handheld, punchy cuts, exaggerated zooms."
|
|
212
|
+
LIGHTING="Bright even lighting, warm comedic tone, no harsh shadows."
|
|
213
|
+
OPTICS="Slight wide angle, expressive framing, snappy focus pulls."
|
|
214
|
+
;;
|
|
215
|
+
fpv)
|
|
216
|
+
MOVEMENT="Immersive first-person POV, continuous forward motion at eye level, slight natural stabilization with GoPro-style wide angle. No cuts throughout."
|
|
217
|
+
LIGHTING="Natural ambient light matching environment, subtle lens flare, peripheral depth-of-field blur."
|
|
218
|
+
OPTICS="Ultra-wide fisheye-adjacent lens, slight barrel distortion, high motion clarity, natural vignette edges."
|
|
219
|
+
;;
|
|
220
|
+
drone)
|
|
221
|
+
MOVEMENT="Cinematic aerial drone shot, smooth gimbal-stabilized descent from high altitude, sweeping lateral arc resolving into establishing medium shot. DJI Inspire aesthetic."
|
|
222
|
+
LIGHTING="Golden hour atmosphere, long directional shadows across terrain, volumetric haze on horizon."
|
|
223
|
+
OPTICS="Wide-angle aerial lens, deep focus across entire frame, high altitude clarity, natural atmospheric haze."
|
|
224
|
+
;;
|
|
225
|
+
flythrough)
|
|
226
|
+
MOVEMENT="Continuous ground-level architectural dolly-through, seamless forward movement through connected spaces. One-take no-cut trajectory."
|
|
227
|
+
LIGHTING="Practical interior lighting with natural window light spill, soft even exposure transitions between zones."
|
|
228
|
+
OPTICS="Wide-angle rectilinear lens, deep focus, minimal distortion, smooth exposure transitions."
|
|
229
|
+
;;
|
|
230
|
+
*)
|
|
231
|
+
MOVEMENT="Smooth cinematic pan, balanced stable framing."
|
|
232
|
+
LIGHTING="Natural studio lighting, balanced highlights and shadows."
|
|
233
|
+
OPTICS="Standard cinematic lens, high-fidelity optics."
|
|
234
|
+
;;
|
|
235
|
+
esac
|
|
236
|
+
|
|
237
|
+
# ============================================================
|
|
238
|
+
# Helper: upload a local file — prints CDN URL to stdout, errors to stderr
|
|
239
|
+
# Returns 1 on failure (caller should handle with || exit 1)
|
|
240
|
+
# ============================================================
|
|
241
|
+
upload_file() {
|
|
242
|
+
local FPATH="$1"
|
|
243
|
+
if [ ! -f "$FPATH" ]; then
|
|
244
|
+
echo "Error: File not found: $FPATH" >&2
|
|
245
|
+
return 1
|
|
246
|
+
fi
|
|
247
|
+
[ "$JSON_ONLY" = false ] && echo "Uploading $(basename "$FPATH")..." >&2
|
|
248
|
+
local RESP URL
|
|
249
|
+
RESP=$(curl -s -X POST "${MUAPI_BASE}/upload_file" \
|
|
250
|
+
-H "x-api-key: $MUAPI_KEY" \
|
|
251
|
+
-F "file=@${FPATH}")
|
|
252
|
+
URL=$(echo "$RESP" | jq -r '.url // empty')
|
|
253
|
+
if [ -z "$URL" ]; then
|
|
254
|
+
echo "Error: Upload failed for $(basename "$FPATH"): $(echo "$RESP" | jq -r '.error // .detail // "unknown"')" >&2
|
|
255
|
+
return 1
|
|
256
|
+
fi
|
|
257
|
+
echo "$URL"
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
# ============================================================
|
|
261
|
+
# Helper: build a JSON array string from positional args
|
|
262
|
+
# Usage: build_json_array "${MY_ARRAY[@]}" — empty array safe
|
|
263
|
+
# ============================================================
|
|
264
|
+
build_json_array() {
|
|
265
|
+
local JSON="[" i=0 elem
|
|
266
|
+
for elem in "$@"; do
|
|
267
|
+
[ "$i" -gt 0 ] && JSON="${JSON},"
|
|
268
|
+
JSON="${JSON}\"${elem}\""
|
|
269
|
+
i=$(( i + 1 ))
|
|
270
|
+
done
|
|
271
|
+
echo "${JSON}]"
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
# ============================================================
|
|
275
|
+
# Helper: JSON-encode a string (handles quotes, backslashes, newlines)
|
|
276
|
+
# Usage: echo "text" | json_string
|
|
277
|
+
# ============================================================
|
|
278
|
+
json_string() {
|
|
279
|
+
python3 -c 'import json,sys; print(json.dumps(sys.stdin.read().rstrip()))'
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
# ============================================================
|
|
283
|
+
# Helper: poll predictions/<id>/result until completed or failed
|
|
284
|
+
# Prints final JSON to stdout; status lines go to stderr.
|
|
285
|
+
# ============================================================
|
|
286
|
+
poll_result() {
|
|
287
|
+
local REQ_ID="$1"
|
|
288
|
+
local ELAPSED=0 LAST_STATUS="" RESULT STATUS URL EXT OUTPUT_DIR TEMP_FILE
|
|
289
|
+
|
|
290
|
+
while [ "$ELAPSED" -lt "$MAX_WAIT" ]; do
|
|
291
|
+
sleep "$POLL_INTERVAL"
|
|
292
|
+
ELAPSED=$(( ELAPSED + POLL_INTERVAL ))
|
|
293
|
+
|
|
294
|
+
RESULT=$(curl -s -X GET "${MUAPI_BASE}/predictions/${REQ_ID}/result" \
|
|
295
|
+
-H "x-api-key: $MUAPI_KEY" \
|
|
296
|
+
-H "Content-Type: application/json")
|
|
297
|
+
|
|
298
|
+
STATUS=$(echo "$RESULT" | jq -r '.status // "unknown"')
|
|
299
|
+
|
|
300
|
+
if [ "$STATUS" != "$LAST_STATUS" ] && [ "$JSON_ONLY" = false ]; then
|
|
301
|
+
echo "Status: $STATUS (${ELAPSED}s elapsed)" >&2
|
|
302
|
+
LAST_STATUS="$STATUS"
|
|
303
|
+
fi
|
|
304
|
+
|
|
305
|
+
if [ "$STATUS" = "completed" ]; then
|
|
306
|
+
URL=$(echo "$RESULT" | jq -r '.outputs[0] // empty')
|
|
307
|
+
[ "$JSON_ONLY" = false ] && echo "Done! Output: $URL" >&2
|
|
308
|
+
if [ "$VIEW" = true ] && [ -n "$URL" ]; then
|
|
309
|
+
EXT="${URL##*.}"
|
|
310
|
+
# Detect non-extension fragment (query strings, etc.) → default mp4
|
|
311
|
+
case "$EXT" in
|
|
312
|
+
mp4|mov|webm|jpg|jpeg|png|gif|webp) ;;
|
|
313
|
+
*) EXT="mp4" ;;
|
|
314
|
+
esac
|
|
315
|
+
OUTPUT_DIR="${PWD}/media_outputs"
|
|
316
|
+
mkdir -p "$OUTPUT_DIR"
|
|
317
|
+
TEMP_FILE="$OUTPUT_DIR/muapi_$(date +%s).$EXT"
|
|
318
|
+
[ "$JSON_ONLY" = false ] && echo "Downloading → $TEMP_FILE" >&2
|
|
319
|
+
curl -s -o "$TEMP_FILE" "$URL"
|
|
320
|
+
[[ "$OSTYPE" == "darwin"* ]] && open "$TEMP_FILE"
|
|
321
|
+
fi
|
|
322
|
+
echo "$RESULT"
|
|
323
|
+
return 0
|
|
324
|
+
|
|
325
|
+
elif [ "$STATUS" = "failed" ]; then
|
|
326
|
+
echo "Error: Job failed — $(echo "$RESULT" | jq -r '.output.error // .error // "unknown"')" >&2
|
|
327
|
+
echo "$RESULT"
|
|
328
|
+
return 1
|
|
329
|
+
fi
|
|
330
|
+
done
|
|
331
|
+
|
|
332
|
+
echo "Error: Timeout after ${MAX_WAIT}s for request_id=$REQ_ID" >&2
|
|
333
|
+
return 1
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
# ============================================================
|
|
337
|
+
# Helper: submit JSON payload to endpoint, then poll (or return async)
|
|
338
|
+
# Usage: submit_and_poll ENDPOINT PAYLOAD [LABEL]
|
|
339
|
+
# ============================================================
|
|
340
|
+
submit_and_poll() {
|
|
341
|
+
local ENDPOINT="$1"
|
|
342
|
+
local PAYLOAD="$2"
|
|
343
|
+
local LABEL="${3:-$1}"
|
|
344
|
+
local SUBMIT API_ERROR REQUEST_ID
|
|
345
|
+
|
|
346
|
+
[ "$JSON_ONLY" = false ] && echo "Submitting to $LABEL..." >&2
|
|
347
|
+
|
|
348
|
+
SUBMIT=$(curl -s -X POST "${MUAPI_BASE}/${ENDPOINT}" "${HEADERS[@]}" -d "$PAYLOAD")
|
|
349
|
+
|
|
350
|
+
API_ERROR=$(echo "$SUBMIT" | jq -r '.error // .detail // empty')
|
|
351
|
+
if [ -n "$API_ERROR" ]; then
|
|
352
|
+
echo "Error: $API_ERROR" >&2
|
|
353
|
+
echo "$SUBMIT" >&2
|
|
354
|
+
exit 1
|
|
355
|
+
fi
|
|
356
|
+
|
|
357
|
+
REQUEST_ID=$(echo "$SUBMIT" | jq -r '.request_id // empty')
|
|
358
|
+
if [ -z "$REQUEST_ID" ]; then
|
|
359
|
+
echo "Error: No request_id returned from $ENDPOINT" >&2
|
|
360
|
+
echo "$SUBMIT" >&2
|
|
361
|
+
exit 1
|
|
362
|
+
fi
|
|
363
|
+
|
|
364
|
+
[ "$JSON_ONLY" = false ] && echo "Request ID: $REQUEST_ID" >&2
|
|
365
|
+
|
|
366
|
+
if [ "$ASYNC" = true ]; then
|
|
367
|
+
echo "$SUBMIT"
|
|
368
|
+
exit 0
|
|
369
|
+
fi
|
|
370
|
+
|
|
371
|
+
[ "$JSON_ONLY" = false ] && echo "Waiting for completion..." >&2
|
|
372
|
+
poll_result "$REQUEST_ID"
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
# ============================================================
|
|
376
|
+
# MODE: t2v — Text-to-Video
|
|
377
|
+
#
|
|
378
|
+
# Chinese: seedance-v2.0-t2v (16:9/9:16/4:3/3:4, quality, duration 5|10|15)
|
|
379
|
+
# Global: seedance-2-text-to-video{-fast} (+ 21:9/1:1, any 4–15s, no quality)
|
|
380
|
+
# VIP: seedance-2-vip-text-to-video{-fast}
|
|
381
|
+
# ============================================================
|
|
382
|
+
if [ "$MODE" = "t2v" ]; then
|
|
383
|
+
[ -z "$SUBJECT" ] && { echo "Error: --subject is required for t2v." >&2; exit 1; }
|
|
384
|
+
|
|
385
|
+
DIRECTOR_PROMPT="[SCENE] $SUBJECT. [LIGHTING] $LIGHTING [ACTION] Fluid continuous motion. [CAMERA] $MOVEMENT [STYLE] $OPTICS High-fidelity production grade, 24fps. Maintain high character consistency, zero flicker."
|
|
386
|
+
|
|
387
|
+
if [ "$TIER" = "chinese" ]; then
|
|
388
|
+
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
389
|
+
CORE_SCRIPT="$SCRIPT_DIR/../../core-media/generate-video.sh"
|
|
390
|
+
[ ! -f "$CORE_SCRIPT" ] && { echo "Error: Core script not found at $CORE_SCRIPT" >&2; exit 1; }
|
|
391
|
+
|
|
392
|
+
VIEW_FLAG=""; [ "$VIEW" = true ] && VIEW_FLAG="--view"
|
|
393
|
+
ASYNC_FLAG=""; [ "$ASYNC" = true ] && ASYNC_FLAG="--async"
|
|
394
|
+
JSON_FLAG=""; [ "$JSON_ONLY" = true ] && JSON_FLAG="--json"
|
|
395
|
+
|
|
396
|
+
# shellcheck disable=SC2086
|
|
397
|
+
bash "$CORE_SCRIPT" \
|
|
398
|
+
--prompt "$DIRECTOR_PROMPT" \
|
|
399
|
+
--model "seedance-v2.0-t2v" \
|
|
400
|
+
--aspect-ratio "$ASPECT" \
|
|
401
|
+
--duration "$DURATION" \
|
|
402
|
+
$AUDIO_FLAG $VIEW_FLAG $ASYNC_FLAG $JSON_FLAG
|
|
403
|
+
else
|
|
404
|
+
PROMPT_JSON=$(echo "$DIRECTOR_PROMPT" | json_string)
|
|
405
|
+
[ "$TIER" = "vip" ] && ENDPOINT="seedance-2-vip-text-to-video" || ENDPOINT="seedance-2-text-to-video"
|
|
406
|
+
[ "$FAST" = true ] && ENDPOINT="${ENDPOINT}-fast"
|
|
407
|
+
PAYLOAD="{\"prompt\": $PROMPT_JSON, \"aspect_ratio\": \"$ASPECT\", \"duration\": $DURATION}"
|
|
408
|
+
submit_and_poll "$ENDPOINT" "$PAYLOAD"
|
|
409
|
+
fi
|
|
410
|
+
|
|
411
|
+
# ============================================================
|
|
412
|
+
# MODE: i2v — Image-to-Video
|
|
413
|
+
#
|
|
414
|
+
# Chinese: seedance-v2.0-i2v (images_list + videos_list + audios_list, quality)
|
|
415
|
+
# Global: seedance-2-image-to-video{-fast} (1 img=first frame, 2-9=omni ref; no quality)
|
|
416
|
+
# VIP: seedance-2-vip-image-to-video{-fast}
|
|
417
|
+
# ============================================================
|
|
418
|
+
elif [ "$MODE" = "i2v" ]; then
|
|
419
|
+
for FPATH in "${IMAGE_FILES[@]+"${IMAGE_FILES[@]}"}"; do
|
|
420
|
+
URL=$(upload_file "$FPATH") || exit 1; IMAGE_URLS+=("$URL")
|
|
421
|
+
done
|
|
422
|
+
for FPATH in "${VIDEO_FILES[@]+"${VIDEO_FILES[@]}"}"; do
|
|
423
|
+
URL=$(upload_file "$FPATH") || exit 1; VIDEO_URLS+=("$URL")
|
|
424
|
+
done
|
|
425
|
+
for FPATH in "${AUDIO_FILES[@]+"${AUDIO_FILES[@]}"}"; do
|
|
426
|
+
URL=$(upload_file "$FPATH") || exit 1; AUDIO_URLS+=("$URL")
|
|
427
|
+
done
|
|
428
|
+
|
|
429
|
+
[ ${#IMAGE_URLS[@]} -eq 0 ] && { echo "Error: At least one --image or --file is required for i2v." >&2; exit 1; }
|
|
430
|
+
[ ${#IMAGE_URLS[@]} -gt 9 ] && { echo "Error: Maximum 9 images allowed." >&2; exit 1; }
|
|
431
|
+
|
|
432
|
+
if [ -n "$SUBJECT" ]; then
|
|
433
|
+
DIRECTOR_PROMPT="[ACTION] $SUBJECT. [CAMERA] $MOVEMENT [STYLE] $OPTICS Fluid continuous motion. Maintain high character consistency, zero flicker."
|
|
434
|
+
else
|
|
435
|
+
DIRECTOR_PROMPT="[CAMERA] $MOVEMENT [STYLE] $OPTICS Fluid continuous motion. Animate the provided image with cinematic realism."
|
|
436
|
+
fi
|
|
437
|
+
PROMPT_JSON=$(echo "$DIRECTOR_PROMPT" | json_string)
|
|
438
|
+
IMAGES_JSON=$(build_json_array "${IMAGE_URLS[@]}")
|
|
439
|
+
|
|
440
|
+
if [ "$TIER" = "chinese" ]; then
|
|
441
|
+
[ ${#VIDEO_URLS[@]} -gt 3 ] && { echo "Error: Maximum 3 reference videos allowed." >&2; exit 1; }
|
|
442
|
+
[ ${#AUDIO_URLS[@]} -gt 3 ] && { echo "Error: Maximum 3 reference audio files allowed." >&2; exit 1; }
|
|
443
|
+
|
|
444
|
+
PAYLOAD="{\"prompt\": $PROMPT_JSON, \"images_list\": $IMAGES_JSON, \"aspect_ratio\": \"$ASPECT\", \"duration\": $DURATION, \"quality\": \"$QUALITY\""
|
|
445
|
+
[ ${#VIDEO_URLS[@]} -gt 0 ] && PAYLOAD="${PAYLOAD}, \"videos_list\": $(build_json_array "${VIDEO_URLS[@]}")"
|
|
446
|
+
[ ${#AUDIO_URLS[@]} -gt 0 ] && PAYLOAD="${PAYLOAD}, \"audios_list\": $(build_json_array "${AUDIO_URLS[@]}")"
|
|
447
|
+
PAYLOAD="${PAYLOAD}}"
|
|
448
|
+
submit_and_poll "seedance-v2.0-i2v" "$PAYLOAD" "seedance-v2.0-i2v (${#IMAGE_URLS[@]} image(s))"
|
|
449
|
+
else
|
|
450
|
+
[ "$TIER" = "vip" ] && ENDPOINT="seedance-2-vip-image-to-video" || ENDPOINT="seedance-2-image-to-video"
|
|
451
|
+
[ "$FAST" = true ] && ENDPOINT="${ENDPOINT}-fast"
|
|
452
|
+
PAYLOAD="{\"prompt\": $PROMPT_JSON, \"images_list\": $IMAGES_JSON, \"duration\": $DURATION}"
|
|
453
|
+
submit_and_poll "$ENDPOINT" "$PAYLOAD" "$ENDPOINT (${#IMAGE_URLS[@]} image(s))"
|
|
454
|
+
fi
|
|
455
|
+
|
|
456
|
+
# ============================================================
|
|
457
|
+
# MODE: extend — Extend a Seedance 2.0 video (Chinese tier)
|
|
458
|
+
# Endpoint: seedance-v2.0-extend
|
|
459
|
+
# ============================================================
|
|
460
|
+
elif [ "$MODE" = "extend" ]; then
|
|
461
|
+
[ -z "$EXTEND_REQUEST_ID" ] && { echo "Error: --request-id is required for extend." >&2; exit 1; }
|
|
462
|
+
|
|
463
|
+
if [ -n "$SUBJECT" ]; then
|
|
464
|
+
EXT_PROMPT="[CONTINUATION] $SUBJECT. [CAMERA] $MOVEMENT [STYLE] $OPTICS Seamless continuation of previous scene."
|
|
465
|
+
PROMPT_JSON=$(echo "$EXT_PROMPT" | json_string)
|
|
466
|
+
PAYLOAD="{\"request_id\": \"$EXTEND_REQUEST_ID\", \"prompt\": $PROMPT_JSON, \"duration\": $DURATION, \"quality\": \"$QUALITY\"}"
|
|
467
|
+
else
|
|
468
|
+
PAYLOAD="{\"request_id\": \"$EXTEND_REQUEST_ID\", \"duration\": $DURATION, \"quality\": \"$QUALITY\"}"
|
|
469
|
+
fi
|
|
470
|
+
|
|
471
|
+
submit_and_poll "seedance-v2.0-extend" "$PAYLOAD"
|
|
472
|
+
|
|
473
|
+
# ============================================================
|
|
474
|
+
# MODE: first-last — First & Last Frame interpolation (Global/VIP only)
|
|
475
|
+
#
|
|
476
|
+
# Global: seedance-2-first-last-frame{-fast} (1 img=anchor, 2 imgs=first+last)
|
|
477
|
+
# VIP: seedance-2-vip-first-last-frame{-fast}
|
|
478
|
+
# Note: Aspect ratio is inferred from the reference image.
|
|
479
|
+
# ============================================================
|
|
480
|
+
elif [ "$MODE" = "first-last" ]; then
|
|
481
|
+
[ "$TIER" = "chinese" ] && { echo "Error: --mode first-last requires --tier global or --tier vip." >&2; exit 1; }
|
|
482
|
+
|
|
483
|
+
for FPATH in "${IMAGE_FILES[@]+"${IMAGE_FILES[@]}"}"; do
|
|
484
|
+
URL=$(upload_file "$FPATH") || exit 1; IMAGE_URLS+=("$URL")
|
|
485
|
+
done
|
|
486
|
+
|
|
487
|
+
[ ${#IMAGE_URLS[@]} -eq 0 ] && { echo "Error: At least 1 --image or --file required for first-last." >&2; exit 1; }
|
|
488
|
+
[ ${#IMAGE_URLS[@]} -gt 2 ] && { echo "Error: first-last accepts 1 (anchor) or 2 (first+last) images." >&2; exit 1; }
|
|
489
|
+
|
|
490
|
+
IMAGES_JSON=$(build_json_array "${IMAGE_URLS[@]}")
|
|
491
|
+
PROMPT_JSON=$(echo "$SUBJECT" | json_string)
|
|
492
|
+
|
|
493
|
+
[ "$TIER" = "vip" ] && ENDPOINT="seedance-2-vip-first-last-frame" || ENDPOINT="seedance-2-first-last-frame"
|
|
494
|
+
[ "$FAST" = true ] && ENDPOINT="${ENDPOINT}-fast"
|
|
495
|
+
|
|
496
|
+
PAYLOAD="{\"prompt\": $PROMPT_JSON, \"images_list\": $IMAGES_JSON, \"duration\": $DURATION}"
|
|
497
|
+
submit_and_poll "$ENDPOINT" "$PAYLOAD" "$ENDPOINT (${#IMAGE_URLS[@]} frame(s))"
|
|
498
|
+
|
|
499
|
+
# ============================================================
|
|
500
|
+
# MODE: omni — Omni Reference (full multimodal)
|
|
501
|
+
#
|
|
502
|
+
# Chinese: seedance-2.0-omni-reference
|
|
503
|
+
# params: images_list, video_files, audio_files, aspect_ratio, duration, quality
|
|
504
|
+
# tags: @image1…@image9, @video1…@video3, @audio1…@audio3
|
|
505
|
+
# also: @character:<request_id>, @omni-character:<character_id>
|
|
506
|
+
#
|
|
507
|
+
# Global: seedance-2-omni-reference-no-video{-fast}
|
|
508
|
+
# params: images_list, audio_files, aspect_ratio, duration (no video, no quality)
|
|
509
|
+
#
|
|
510
|
+
# VIP: seedance-2-vip-omni-reference{-fast}
|
|
511
|
+
# params: images_list, audio_files, aspect_ratio, duration (no video, no quality)
|
|
512
|
+
# ============================================================
|
|
513
|
+
elif [ "$MODE" = "omni" ]; then
|
|
514
|
+
for FPATH in "${IMAGE_FILES[@]+"${IMAGE_FILES[@]}"}"; do
|
|
515
|
+
URL=$(upload_file "$FPATH") || exit 1; IMAGE_URLS+=("$URL")
|
|
516
|
+
done
|
|
517
|
+
for FPATH in "${VIDEO_FILES[@]+"${VIDEO_FILES[@]}"}"; do
|
|
518
|
+
URL=$(upload_file "$FPATH") || exit 1; VIDEO_URLS+=("$URL")
|
|
519
|
+
done
|
|
520
|
+
for FPATH in "${AUDIO_FILES[@]+"${AUDIO_FILES[@]}"}"; do
|
|
521
|
+
URL=$(upload_file "$FPATH") || exit 1; AUDIO_URLS+=("$URL")
|
|
522
|
+
done
|
|
523
|
+
|
|
524
|
+
[ -z "$SUBJECT" ] && { echo "Error: --subject is required for omni." >&2; exit 1; }
|
|
525
|
+
[ ${#IMAGE_URLS[@]} -gt 9 ] && { echo "Error: Maximum 9 images allowed." >&2; exit 1; }
|
|
526
|
+
[ ${#VIDEO_URLS[@]} -gt 3 ] && { echo "Error: Maximum 3 reference videos allowed." >&2; exit 1; }
|
|
527
|
+
[ ${#AUDIO_URLS[@]} -gt 3 ] && { echo "Error: Maximum 3 reference audio files allowed." >&2; exit 1; }
|
|
528
|
+
|
|
529
|
+
PROMPT_JSON=$(echo "$SUBJECT" | json_string)
|
|
530
|
+
|
|
531
|
+
if [ "$TIER" = "chinese" ]; then
|
|
532
|
+
PAYLOAD="{\"prompt\": $PROMPT_JSON, \"aspect_ratio\": \"$ASPECT\", \"duration\": $DURATION, \"quality\": \"$QUALITY\""
|
|
533
|
+
[ ${#IMAGE_URLS[@]} -gt 0 ] && PAYLOAD="${PAYLOAD}, \"images_list\": $(build_json_array "${IMAGE_URLS[@]}")"
|
|
534
|
+
[ ${#VIDEO_URLS[@]} -gt 0 ] && PAYLOAD="${PAYLOAD}, \"video_files\": $(build_json_array "${VIDEO_URLS[@]}")"
|
|
535
|
+
[ ${#AUDIO_URLS[@]} -gt 0 ] && PAYLOAD="${PAYLOAD}, \"audio_files\": $(build_json_array "${AUDIO_URLS[@]}")"
|
|
536
|
+
PAYLOAD="${PAYLOAD}}"
|
|
537
|
+
submit_and_poll "seedance-2.0-omni-reference" "$PAYLOAD" "seedance-v2.0-omni-reference"
|
|
538
|
+
else
|
|
539
|
+
if [ ${#VIDEO_URLS[@]} -gt 0 ]; then
|
|
540
|
+
echo "Warning: $TIER omni does not support video references — ignoring --video-url/--video-file." >&2
|
|
541
|
+
fi
|
|
542
|
+
[ "$TIER" = "vip" ] && ENDPOINT="seedance-2-vip-omni-reference" || ENDPOINT="seedance-2-omni-reference-no-video"
|
|
543
|
+
[ "$FAST" = true ] && ENDPOINT="${ENDPOINT}-fast"
|
|
544
|
+
PAYLOAD="{\"prompt\": $PROMPT_JSON, \"aspect_ratio\": \"$ASPECT\", \"duration\": $DURATION"
|
|
545
|
+
[ ${#IMAGE_URLS[@]} -gt 0 ] && PAYLOAD="${PAYLOAD}, \"images_list\": $(build_json_array "${IMAGE_URLS[@]}")"
|
|
546
|
+
[ ${#AUDIO_URLS[@]} -gt 0 ] && PAYLOAD="${PAYLOAD}, \"audio_files\": $(build_json_array "${AUDIO_URLS[@]}")"
|
|
547
|
+
PAYLOAD="${PAYLOAD}}"
|
|
548
|
+
submit_and_poll "$ENDPOINT" "$PAYLOAD"
|
|
549
|
+
fi
|
|
550
|
+
|
|
551
|
+
# ============================================================
|
|
552
|
+
# MODE: omni-train — Train a custom Omni Reference character
|
|
553
|
+
# Endpoint: seedance-2-omni-reference-train
|
|
554
|
+
# Params: image_url (single portrait), character_name, description
|
|
555
|
+
# Output: character_id — reference as @omni-character:<character_id>
|
|
556
|
+
# ============================================================
|
|
557
|
+
elif [ "$MODE" = "omni-train" ]; then
|
|
558
|
+
for FPATH in "${IMAGE_FILES[@]+"${IMAGE_FILES[@]}"}"; do
|
|
559
|
+
URL=$(upload_file "$FPATH") || exit 1; IMAGE_URLS+=("$URL")
|
|
560
|
+
done
|
|
561
|
+
|
|
562
|
+
[ ${#IMAGE_URLS[@]} -eq 0 ] && { echo "Error: Exactly 1 --image or --file required for omni-train." >&2; exit 1; }
|
|
563
|
+
[ ${#IMAGE_URLS[@]} -gt 1 ] && { echo "Error: omni-train accepts only 1 reference image." >&2; exit 1; }
|
|
564
|
+
|
|
565
|
+
PAYLOAD="{\"image_url\": \"${IMAGE_URLS[0]}\""
|
|
566
|
+
if [ -n "$CHARACTER_NAME" ]; then
|
|
567
|
+
NAME_JSON=$(echo "$CHARACTER_NAME" | json_string)
|
|
568
|
+
PAYLOAD="${PAYLOAD}, \"character_name\": $NAME_JSON"
|
|
569
|
+
fi
|
|
570
|
+
if [ -n "$CHARACTER_DESC" ]; then
|
|
571
|
+
DESC_JSON=$(echo "$CHARACTER_DESC" | json_string)
|
|
572
|
+
PAYLOAD="${PAYLOAD}, \"description\": $DESC_JSON"
|
|
573
|
+
fi
|
|
574
|
+
PAYLOAD="${PAYLOAD}}"
|
|
575
|
+
|
|
576
|
+
[ "$JSON_ONLY" = false ] && echo "Submitting omni-reference-train..." >&2
|
|
577
|
+
SUBMIT=$(curl -s -X POST "${MUAPI_BASE}/seedance-2-omni-reference-train" "${HEADERS[@]}" -d "$PAYLOAD")
|
|
578
|
+
|
|
579
|
+
API_ERROR=$(echo "$SUBMIT" | jq -r '.error // .detail // empty')
|
|
580
|
+
if [ -n "$API_ERROR" ]; then
|
|
581
|
+
echo "Error: $API_ERROR" >&2; echo "$SUBMIT" >&2; exit 1
|
|
582
|
+
fi
|
|
583
|
+
|
|
584
|
+
REQUEST_ID=$(echo "$SUBMIT" | jq -r '.request_id // empty')
|
|
585
|
+
if [ -z "$REQUEST_ID" ]; then
|
|
586
|
+
echo "Error: No request_id in response" >&2; echo "$SUBMIT" >&2; exit 1
|
|
587
|
+
fi
|
|
588
|
+
|
|
589
|
+
[ "$JSON_ONLY" = false ] && echo "Request ID: $REQUEST_ID" >&2
|
|
590
|
+
[ "$JSON_ONLY" = false ] && echo "Training started — use @omni-character:<character_id> once complete." >&2
|
|
591
|
+
|
|
592
|
+
if [ "$ASYNC" = true ]; then echo "$SUBMIT"; exit 0; fi
|
|
593
|
+
|
|
594
|
+
[ "$JSON_ONLY" = false ] && echo "Waiting for training to complete..." >&2
|
|
595
|
+
RESULT=$(poll_result "$REQUEST_ID")
|
|
596
|
+
echo "$RESULT"
|
|
597
|
+
CHAR_ID=$(echo "$RESULT" | jq -r '.outputs[0] // empty')
|
|
598
|
+
if [ "$JSON_ONLY" = false ] && [ -n "$CHAR_ID" ]; then
|
|
599
|
+
echo "Character trained! Reference as: @omni-character:$CHAR_ID" >&2
|
|
600
|
+
fi
|
|
601
|
+
|
|
602
|
+
# ============================================================
|
|
603
|
+
# MODE: character — Build a reusable character sheet from 1–3 images
|
|
604
|
+
# Endpoint: seedance-2-character
|
|
605
|
+
# Params: images_list (1–3), prompt (outfit description), character_name
|
|
606
|
+
# Output: request_id — reference as @character:<request_id>
|
|
607
|
+
# ============================================================
|
|
608
|
+
elif [ "$MODE" = "character" ]; then
|
|
609
|
+
for FPATH in "${IMAGE_FILES[@]+"${IMAGE_FILES[@]}"}"; do
|
|
610
|
+
URL=$(upload_file "$FPATH") || exit 1; IMAGE_URLS+=("$URL")
|
|
611
|
+
done
|
|
612
|
+
|
|
613
|
+
[ ${#IMAGE_URLS[@]} -eq 0 ] && { echo "Error: At least 1 --image or --file required for character." >&2; exit 1; }
|
|
614
|
+
[ ${#IMAGE_URLS[@]} -gt 3 ] && { echo "Error: Maximum 3 reference images for character training." >&2; exit 1; }
|
|
615
|
+
|
|
616
|
+
IMAGES_JSON=$(build_json_array "${IMAGE_URLS[@]}")
|
|
617
|
+
PAYLOAD="{\"images_list\": $IMAGES_JSON"
|
|
618
|
+
if [ -n "$SUBJECT" ]; then
|
|
619
|
+
OUTFIT_JSON=$(echo "$SUBJECT" | json_string)
|
|
620
|
+
PAYLOAD="${PAYLOAD}, \"prompt\": $OUTFIT_JSON"
|
|
621
|
+
fi
|
|
622
|
+
if [ -n "$CHARACTER_NAME" ]; then
|
|
623
|
+
NAME_JSON=$(echo "$CHARACTER_NAME" | json_string)
|
|
624
|
+
PAYLOAD="${PAYLOAD}, \"character_name\": $NAME_JSON"
|
|
625
|
+
fi
|
|
626
|
+
PAYLOAD="${PAYLOAD}}"
|
|
627
|
+
|
|
628
|
+
[ "$JSON_ONLY" = false ] && echo "Submitting character training (${#IMAGE_URLS[@]} image(s))..." >&2
|
|
629
|
+
SUBMIT=$(curl -s -X POST "${MUAPI_BASE}/seedance-2-character" "${HEADERS[@]}" -d "$PAYLOAD")
|
|
630
|
+
|
|
631
|
+
API_ERROR=$(echo "$SUBMIT" | jq -r '.error // .detail // empty')
|
|
632
|
+
if [ -n "$API_ERROR" ]; then
|
|
633
|
+
echo "Error: $API_ERROR" >&2; echo "$SUBMIT" >&2; exit 1
|
|
634
|
+
fi
|
|
635
|
+
|
|
636
|
+
REQUEST_ID=$(echo "$SUBMIT" | jq -r '.request_id // empty')
|
|
637
|
+
if [ -z "$REQUEST_ID" ]; then
|
|
638
|
+
echo "Error: No request_id in response" >&2; echo "$SUBMIT" >&2; exit 1
|
|
639
|
+
fi
|
|
640
|
+
|
|
641
|
+
[ "$JSON_ONLY" = false ] && echo "Request ID: $REQUEST_ID" >&2
|
|
642
|
+
[ "$JSON_ONLY" = false ] && echo "Use in prompts as: @character:$REQUEST_ID" >&2
|
|
643
|
+
|
|
644
|
+
if [ "$ASYNC" = true ]; then echo "$SUBMIT"; exit 0; fi
|
|
645
|
+
|
|
646
|
+
[ "$JSON_ONLY" = false ] && echo "Waiting for character sheet to complete..." >&2
|
|
647
|
+
poll_result "$REQUEST_ID"
|
|
648
|
+
|
|
649
|
+
# ============================================================
|
|
650
|
+
# MODE: video-edit — Edit a video with a prompt + optional reference images
|
|
651
|
+
# Endpoint: seedance-v2.0-video-edit
|
|
652
|
+
# Params: prompt, video_urls (1 max, 10MB/15s), images_list (up to 9),
|
|
653
|
+
# aspect_ratio, quality, remove_watermark
|
|
654
|
+
# ============================================================
|
|
655
|
+
elif [ "$MODE" = "video-edit" ]; then
|
|
656
|
+
for FPATH in "${IMAGE_FILES[@]+"${IMAGE_FILES[@]}"}"; do
|
|
657
|
+
URL=$(upload_file "$FPATH") || exit 1; IMAGE_URLS+=("$URL")
|
|
658
|
+
done
|
|
659
|
+
for FPATH in "${VIDEO_FILES[@]+"${VIDEO_FILES[@]}"}"; do
|
|
660
|
+
URL=$(upload_file "$FPATH") || exit 1; VIDEO_URLS+=("$URL")
|
|
661
|
+
done
|
|
662
|
+
|
|
663
|
+
[ -z "$SUBJECT" ] && { echo "Error: --subject (edit prompt) is required for video-edit." >&2; exit 1; }
|
|
664
|
+
[ ${#VIDEO_URLS[@]} -eq 0 ] && { echo "Error: --video-url or --video-file is required for video-edit." >&2; exit 1; }
|
|
665
|
+
[ ${#VIDEO_URLS[@]} -gt 1 ] && { echo "Error: video-edit supports 1 source video only (max 10MB, 15s)." >&2; exit 1; }
|
|
666
|
+
[ ${#IMAGE_URLS[@]} -gt 9 ] && { echo "Error: Maximum 9 reference images allowed." >&2; exit 1; }
|
|
667
|
+
|
|
668
|
+
PROMPT_JSON=$(echo "$SUBJECT" | json_string)
|
|
669
|
+
PAYLOAD="{\"prompt\": $PROMPT_JSON, \"video_urls\": [\"${VIDEO_URLS[0]}\"], \"aspect_ratio\": \"$ASPECT\", \"quality\": \"$QUALITY\""
|
|
670
|
+
[ ${#IMAGE_URLS[@]} -gt 0 ] && PAYLOAD="${PAYLOAD}, \"images_list\": $(build_json_array "${IMAGE_URLS[@]}")"
|
|
671
|
+
[ "$REMOVE_WATERMARK" = true ] && PAYLOAD="${PAYLOAD}, \"remove_watermark\": true"
|
|
672
|
+
PAYLOAD="${PAYLOAD}}"
|
|
673
|
+
|
|
674
|
+
submit_and_poll "seedance-v2.0-video-edit" "$PAYLOAD"
|
|
675
|
+
|
|
676
|
+
# ============================================================
|
|
677
|
+
# MODE: watermark-remove — Strip watermark from a Seedance 2.0 video
|
|
678
|
+
#
|
|
679
|
+
# Basic: seedance-2.0-watermark-remover
|
|
680
|
+
# Pro: seedance-2-video-watermark-remover-pro (--pro flag; up to 100MB)
|
|
681
|
+
# ============================================================
|
|
682
|
+
elif [ "$MODE" = "watermark-remove" ]; then
|
|
683
|
+
for FPATH in "${VIDEO_FILES[@]+"${VIDEO_FILES[@]}"}"; do
|
|
684
|
+
URL=$(upload_file "$FPATH") || exit 1; VIDEO_URLS+=("$URL")
|
|
685
|
+
done
|
|
686
|
+
|
|
687
|
+
[ ${#VIDEO_URLS[@]} -eq 0 ] && { echo "Error: --video-url or --video-file is required for watermark-remove." >&2; exit 1; }
|
|
688
|
+
|
|
689
|
+
PAYLOAD="{\"video_url\": \"${VIDEO_URLS[0]}\"}"
|
|
690
|
+
|
|
691
|
+
if [ "$PRO_WATERMARK" = true ]; then
|
|
692
|
+
submit_and_poll "seedance-2-video-watermark-remover-pro" "$PAYLOAD"
|
|
693
|
+
else
|
|
694
|
+
submit_and_poll "seedance-2.0-watermark-remover" "$PAYLOAD"
|
|
695
|
+
fi
|
|
696
|
+
|
|
697
|
+
else
|
|
698
|
+
echo "Error: Unknown mode '$MODE'." >&2
|
|
699
|
+
echo "Valid: t2v | i2v | extend | first-last | omni | omni-train | character | video-edit | watermark-remove" >&2
|
|
700
|
+
exit 1
|
|
701
|
+
fi
|