@vibeframe/cli 0.27.0
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/.turbo/turbo-build.log +4 -0
- package/.turbo/turbo-lint.log +21 -0
- package/.turbo/turbo-test.log +689 -0
- package/dist/agent/adapters/claude.d.ts +15 -0
- package/dist/agent/adapters/claude.d.ts.map +1 -0
- package/dist/agent/adapters/claude.js +119 -0
- package/dist/agent/adapters/claude.js.map +1 -0
- package/dist/agent/adapters/gemini.d.ts +15 -0
- package/dist/agent/adapters/gemini.d.ts.map +1 -0
- package/dist/agent/adapters/gemini.js +132 -0
- package/dist/agent/adapters/gemini.js.map +1 -0
- package/dist/agent/adapters/index.d.ts +27 -0
- package/dist/agent/adapters/index.d.ts.map +1 -0
- package/dist/agent/adapters/index.js +38 -0
- package/dist/agent/adapters/index.js.map +1 -0
- package/dist/agent/adapters/ollama.d.ts +20 -0
- package/dist/agent/adapters/ollama.d.ts.map +1 -0
- package/dist/agent/adapters/ollama.js +186 -0
- package/dist/agent/adapters/ollama.js.map +1 -0
- package/dist/agent/adapters/openai.d.ts +15 -0
- package/dist/agent/adapters/openai.d.ts.map +1 -0
- package/dist/agent/adapters/openai.js +92 -0
- package/dist/agent/adapters/openai.js.map +1 -0
- package/dist/agent/adapters/xai.d.ts +15 -0
- package/dist/agent/adapters/xai.d.ts.map +1 -0
- package/dist/agent/adapters/xai.js +95 -0
- package/dist/agent/adapters/xai.js.map +1 -0
- package/dist/agent/index.d.ts +69 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +180 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/memory/index.d.ts +70 -0
- package/dist/agent/memory/index.d.ts.map +1 -0
- package/dist/agent/memory/index.js +132 -0
- package/dist/agent/memory/index.js.map +1 -0
- package/dist/agent/prompts/system.d.ts +6 -0
- package/dist/agent/prompts/system.d.ts.map +1 -0
- package/dist/agent/prompts/system.js +103 -0
- package/dist/agent/prompts/system.js.map +1 -0
- package/dist/agent/tools/ai-editing.d.ts +15 -0
- package/dist/agent/tools/ai-editing.d.ts.map +1 -0
- package/dist/agent/tools/ai-editing.js +763 -0
- package/dist/agent/tools/ai-editing.js.map +1 -0
- package/dist/agent/tools/ai-generation.d.ts +13 -0
- package/dist/agent/tools/ai-generation.d.ts.map +1 -0
- package/dist/agent/tools/ai-generation.js +973 -0
- package/dist/agent/tools/ai-generation.js.map +1 -0
- package/dist/agent/tools/ai-pipeline.d.ts +14 -0
- package/dist/agent/tools/ai-pipeline.d.ts.map +1 -0
- package/dist/agent/tools/ai-pipeline.js +961 -0
- package/dist/agent/tools/ai-pipeline.js.map +1 -0
- package/dist/agent/tools/ai.d.ts +13 -0
- package/dist/agent/tools/ai.d.ts.map +1 -0
- package/dist/agent/tools/ai.js +19 -0
- package/dist/agent/tools/ai.js.map +1 -0
- package/dist/agent/tools/batch.d.ts +6 -0
- package/dist/agent/tools/batch.d.ts.map +1 -0
- package/dist/agent/tools/batch.js +383 -0
- package/dist/agent/tools/batch.js.map +1 -0
- package/dist/agent/tools/e2e.test.d.ts +26 -0
- package/dist/agent/tools/e2e.test.d.ts.map +1 -0
- package/dist/agent/tools/e2e.test.js +397 -0
- package/dist/agent/tools/e2e.test.js.map +1 -0
- package/dist/agent/tools/export.d.ts +6 -0
- package/dist/agent/tools/export.d.ts.map +1 -0
- package/dist/agent/tools/export.js +171 -0
- package/dist/agent/tools/export.js.map +1 -0
- package/dist/agent/tools/filesystem.d.ts +6 -0
- package/dist/agent/tools/filesystem.d.ts.map +1 -0
- package/dist/agent/tools/filesystem.js +212 -0
- package/dist/agent/tools/filesystem.js.map +1 -0
- package/dist/agent/tools/index.d.ts +65 -0
- package/dist/agent/tools/index.d.ts.map +1 -0
- package/dist/agent/tools/index.js +120 -0
- package/dist/agent/tools/index.js.map +1 -0
- package/dist/agent/tools/integration.test.d.ts +11 -0
- package/dist/agent/tools/integration.test.d.ts.map +1 -0
- package/dist/agent/tools/integration.test.js +659 -0
- package/dist/agent/tools/integration.test.js.map +1 -0
- package/dist/agent/tools/media.d.ts +6 -0
- package/dist/agent/tools/media.d.ts.map +1 -0
- package/dist/agent/tools/media.js +616 -0
- package/dist/agent/tools/media.js.map +1 -0
- package/dist/agent/tools/project.d.ts +6 -0
- package/dist/agent/tools/project.d.ts.map +1 -0
- package/dist/agent/tools/project.js +284 -0
- package/dist/agent/tools/project.js.map +1 -0
- package/dist/agent/tools/timeline.d.ts +6 -0
- package/dist/agent/tools/timeline.d.ts.map +1 -0
- package/dist/agent/tools/timeline.js +873 -0
- package/dist/agent/tools/timeline.js.map +1 -0
- package/dist/agent/types.d.ts +59 -0
- package/dist/agent/types.d.ts.map +1 -0
- package/dist/agent/types.js +5 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/commands/agent.d.ts +21 -0
- package/dist/commands/agent.d.ts.map +1 -0
- package/dist/commands/agent.js +290 -0
- package/dist/commands/agent.js.map +1 -0
- package/dist/commands/ai-analyze.d.ts +106 -0
- package/dist/commands/ai-analyze.d.ts.map +1 -0
- package/dist/commands/ai-analyze.js +327 -0
- package/dist/commands/ai-analyze.js.map +1 -0
- package/dist/commands/ai-animated-caption.d.ts +64 -0
- package/dist/commands/ai-animated-caption.d.ts.map +1 -0
- package/dist/commands/ai-animated-caption.js +272 -0
- package/dist/commands/ai-animated-caption.js.map +1 -0
- package/dist/commands/ai-audio.d.ts +20 -0
- package/dist/commands/ai-audio.d.ts.map +1 -0
- package/dist/commands/ai-audio.js +808 -0
- package/dist/commands/ai-audio.js.map +1 -0
- package/dist/commands/ai-broll.d.ts +15 -0
- package/dist/commands/ai-broll.d.ts.map +1 -0
- package/dist/commands/ai-broll.js +406 -0
- package/dist/commands/ai-broll.js.map +1 -0
- package/dist/commands/ai-edit-cli.d.ts +14 -0
- package/dist/commands/ai-edit-cli.d.ts.map +1 -0
- package/dist/commands/ai-edit-cli.js +579 -0
- package/dist/commands/ai-edit-cli.js.map +1 -0
- package/dist/commands/ai-edit.d.ts +398 -0
- package/dist/commands/ai-edit.d.ts.map +1 -0
- package/dist/commands/ai-edit.js +1019 -0
- package/dist/commands/ai-edit.js.map +1 -0
- package/dist/commands/ai-fill-gaps.d.ts +14 -0
- package/dist/commands/ai-fill-gaps.d.ts.map +1 -0
- package/dist/commands/ai-fill-gaps.js +451 -0
- package/dist/commands/ai-fill-gaps.js.map +1 -0
- package/dist/commands/ai-helpers.d.ts +20 -0
- package/dist/commands/ai-helpers.d.ts.map +1 -0
- package/dist/commands/ai-helpers.js +59 -0
- package/dist/commands/ai-helpers.js.map +1 -0
- package/dist/commands/ai-highlights.d.ts +127 -0
- package/dist/commands/ai-highlights.d.ts.map +1 -0
- package/dist/commands/ai-highlights.js +1026 -0
- package/dist/commands/ai-highlights.js.map +1 -0
- package/dist/commands/ai-image.d.ts +34 -0
- package/dist/commands/ai-image.d.ts.map +1 -0
- package/dist/commands/ai-image.js +653 -0
- package/dist/commands/ai-image.js.map +1 -0
- package/dist/commands/ai-motion.d.ts +50 -0
- package/dist/commands/ai-motion.d.ts.map +1 -0
- package/dist/commands/ai-motion.js +271 -0
- package/dist/commands/ai-motion.js.map +1 -0
- package/dist/commands/ai-narrate.d.ts +66 -0
- package/dist/commands/ai-narrate.d.ts.map +1 -0
- package/dist/commands/ai-narrate.js +329 -0
- package/dist/commands/ai-narrate.js.map +1 -0
- package/dist/commands/ai-review.d.ts +57 -0
- package/dist/commands/ai-review.d.ts.map +1 -0
- package/dist/commands/ai-review.js +251 -0
- package/dist/commands/ai-review.js.map +1 -0
- package/dist/commands/ai-script-pipeline-cli.d.ts +9 -0
- package/dist/commands/ai-script-pipeline-cli.d.ts.map +1 -0
- package/dist/commands/ai-script-pipeline-cli.js +1494 -0
- package/dist/commands/ai-script-pipeline-cli.js.map +1 -0
- package/dist/commands/ai-script-pipeline.d.ts +259 -0
- package/dist/commands/ai-script-pipeline.d.ts.map +1 -0
- package/dist/commands/ai-script-pipeline.js +1027 -0
- package/dist/commands/ai-script-pipeline.js.map +1 -0
- package/dist/commands/ai-suggest-edit.d.ts +14 -0
- package/dist/commands/ai-suggest-edit.d.ts.map +1 -0
- package/dist/commands/ai-suggest-edit.js +220 -0
- package/dist/commands/ai-suggest-edit.js.map +1 -0
- package/dist/commands/ai-video-fx.d.ts +14 -0
- package/dist/commands/ai-video-fx.d.ts.map +1 -0
- package/dist/commands/ai-video-fx.js +395 -0
- package/dist/commands/ai-video-fx.js.map +1 -0
- package/dist/commands/ai-video.d.ts +15 -0
- package/dist/commands/ai-video.d.ts.map +1 -0
- package/dist/commands/ai-video.js +785 -0
- package/dist/commands/ai-video.js.map +1 -0
- package/dist/commands/ai-viral.d.ts +15 -0
- package/dist/commands/ai-viral.d.ts.map +1 -0
- package/dist/commands/ai-viral.js +519 -0
- package/dist/commands/ai-viral.js.map +1 -0
- package/dist/commands/ai-visual-fx.d.ts +14 -0
- package/dist/commands/ai-visual-fx.d.ts.map +1 -0
- package/dist/commands/ai-visual-fx.js +505 -0
- package/dist/commands/ai-visual-fx.js.map +1 -0
- package/dist/commands/ai.d.ts +38 -0
- package/dist/commands/ai.d.ts.map +1 -0
- package/dist/commands/ai.js +225 -0
- package/dist/commands/ai.js.map +1 -0
- package/dist/commands/ai.test.d.ts +2 -0
- package/dist/commands/ai.test.d.ts.map +1 -0
- package/dist/commands/ai.test.js +554 -0
- package/dist/commands/ai.test.js.map +1 -0
- package/dist/commands/analyze.d.ts +16 -0
- package/dist/commands/analyze.d.ts.map +1 -0
- package/dist/commands/analyze.js +247 -0
- package/dist/commands/analyze.js.map +1 -0
- package/dist/commands/audio.d.ts +18 -0
- package/dist/commands/audio.d.ts.map +1 -0
- package/dist/commands/audio.js +539 -0
- package/dist/commands/audio.js.map +1 -0
- package/dist/commands/batch.d.ts +3 -0
- package/dist/commands/batch.d.ts.map +1 -0
- package/dist/commands/batch.js +366 -0
- package/dist/commands/batch.js.map +1 -0
- package/dist/commands/batch.test.d.ts +2 -0
- package/dist/commands/batch.test.d.ts.map +1 -0
- package/dist/commands/batch.test.js +203 -0
- package/dist/commands/batch.test.js.map +1 -0
- package/dist/commands/detect.d.ts +3 -0
- package/dist/commands/detect.d.ts.map +1 -0
- package/dist/commands/detect.js +273 -0
- package/dist/commands/detect.js.map +1 -0
- package/dist/commands/doctor.d.ts +6 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +191 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/edit-cmd.d.ts +26 -0
- package/dist/commands/edit-cmd.d.ts.map +1 -0
- package/dist/commands/edit-cmd.js +870 -0
- package/dist/commands/edit-cmd.js.map +1 -0
- package/dist/commands/export.d.ts +39 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +730 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/generate.d.ts +25 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +1885 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/media.d.ts +3 -0
- package/dist/commands/media.d.ts.map +1 -0
- package/dist/commands/media.js +165 -0
- package/dist/commands/media.js.map +1 -0
- package/dist/commands/output.d.ts +45 -0
- package/dist/commands/output.d.ts.map +1 -0
- package/dist/commands/output.js +122 -0
- package/dist/commands/output.js.map +1 -0
- package/dist/commands/pipeline.d.ts +19 -0
- package/dist/commands/pipeline.d.ts.map +1 -0
- package/dist/commands/pipeline.js +345 -0
- package/dist/commands/pipeline.js.map +1 -0
- package/dist/commands/project.d.ts +3 -0
- package/dist/commands/project.d.ts.map +1 -0
- package/dist/commands/project.js +139 -0
- package/dist/commands/project.js.map +1 -0
- package/dist/commands/project.test.d.ts +2 -0
- package/dist/commands/project.test.d.ts.map +1 -0
- package/dist/commands/project.test.js +105 -0
- package/dist/commands/project.test.js.map +1 -0
- package/dist/commands/sanitize.d.ts +21 -0
- package/dist/commands/sanitize.d.ts.map +1 -0
- package/dist/commands/sanitize.js +56 -0
- package/dist/commands/sanitize.js.map +1 -0
- package/dist/commands/schema.d.ts +11 -0
- package/dist/commands/schema.d.ts.map +1 -0
- package/dist/commands/schema.js +101 -0
- package/dist/commands/schema.js.map +1 -0
- package/dist/commands/setup.d.ts +6 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +440 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/timeline.d.ts +3 -0
- package/dist/commands/timeline.d.ts.map +1 -0
- package/dist/commands/timeline.js +469 -0
- package/dist/commands/timeline.js.map +1 -0
- package/dist/commands/timeline.test.d.ts +2 -0
- package/dist/commands/timeline.test.d.ts.map +1 -0
- package/dist/commands/timeline.test.js +320 -0
- package/dist/commands/timeline.test.js.map +1 -0
- package/dist/commands/validate.d.ts +32 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +63 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/config/config.test.d.ts +2 -0
- package/dist/config/config.test.d.ts.map +1 -0
- package/dist/config/config.test.js +164 -0
- package/dist/config/config.test.js.map +1 -0
- package/dist/config/index.d.ts +35 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +101 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/schema.d.ts +43 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +42 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/engine/index.d.ts +3 -0
- package/dist/engine/index.d.ts.map +1 -0
- package/dist/engine/index.js +2 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/engine/project.d.ts +84 -0
- package/dist/engine/project.d.ts.map +1 -0
- package/dist/engine/project.js +355 -0
- package/dist/engine/project.js.map +1 -0
- package/dist/engine/project.test.d.ts +2 -0
- package/dist/engine/project.test.d.ts.map +1 -0
- package/dist/engine/project.test.js +599 -0
- package/dist/engine/project.test.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +131 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/api-key.d.ts +36 -0
- package/dist/utils/api-key.d.ts.map +1 -0
- package/dist/utils/api-key.js +211 -0
- package/dist/utils/api-key.js.map +1 -0
- package/dist/utils/api-key.test.d.ts +2 -0
- package/dist/utils/api-key.test.d.ts.map +1 -0
- package/dist/utils/api-key.test.js +35 -0
- package/dist/utils/api-key.test.js.map +1 -0
- package/dist/utils/audio.d.ts +23 -0
- package/dist/utils/audio.d.ts.map +1 -0
- package/dist/utils/audio.js +79 -0
- package/dist/utils/audio.js.map +1 -0
- package/dist/utils/exec-safe.d.ts +22 -0
- package/dist/utils/exec-safe.d.ts.map +1 -0
- package/dist/utils/exec-safe.js +62 -0
- package/dist/utils/exec-safe.js.map +1 -0
- package/dist/utils/first-run.d.ts +13 -0
- package/dist/utils/first-run.d.ts.map +1 -0
- package/dist/utils/first-run.js +48 -0
- package/dist/utils/first-run.js.map +1 -0
- package/dist/utils/provider-resolver.d.ts +15 -0
- package/dist/utils/provider-resolver.d.ts.map +1 -0
- package/dist/utils/provider-resolver.js +42 -0
- package/dist/utils/provider-resolver.js.map +1 -0
- package/dist/utils/remotion.d.ts +210 -0
- package/dist/utils/remotion.d.ts.map +1 -0
- package/dist/utils/remotion.js +731 -0
- package/dist/utils/remotion.js.map +1 -0
- package/dist/utils/subtitle.d.ts +65 -0
- package/dist/utils/subtitle.d.ts.map +1 -0
- package/dist/utils/subtitle.js +135 -0
- package/dist/utils/subtitle.js.map +1 -0
- package/dist/utils/subtitle.test.d.ts +2 -0
- package/dist/utils/subtitle.test.d.ts.map +1 -0
- package/dist/utils/subtitle.test.js +175 -0
- package/dist/utils/subtitle.test.js.map +1 -0
- package/dist/utils/tty.d.ts +45 -0
- package/dist/utils/tty.d.ts.map +1 -0
- package/dist/utils/tty.js +172 -0
- package/dist/utils/tty.js.map +1 -0
- package/package.json +102 -0
- package/src/agent/adapters/claude.ts +143 -0
- package/src/agent/adapters/gemini.ts +159 -0
- package/src/agent/adapters/index.ts +61 -0
- package/src/agent/adapters/ollama.ts +231 -0
- package/src/agent/adapters/openai.ts +116 -0
- package/src/agent/adapters/xai.ts +119 -0
- package/src/agent/index.ts +251 -0
- package/src/agent/memory/index.ts +151 -0
- package/src/agent/prompts/system.ts +106 -0
- package/src/agent/tools/ai-editing.ts +845 -0
- package/src/agent/tools/ai-generation.ts +1073 -0
- package/src/agent/tools/ai-pipeline.ts +1055 -0
- package/src/agent/tools/ai.ts +21 -0
- package/src/agent/tools/batch.ts +429 -0
- package/src/agent/tools/e2e.test.ts +545 -0
- package/src/agent/tools/export.ts +184 -0
- package/src/agent/tools/filesystem.ts +237 -0
- package/src/agent/tools/index.ts +150 -0
- package/src/agent/tools/integration.test.ts +775 -0
- package/src/agent/tools/media.ts +697 -0
- package/src/agent/tools/project.ts +313 -0
- package/src/agent/tools/timeline.ts +951 -0
- package/src/agent/types.ts +68 -0
- package/src/commands/agent.ts +340 -0
- package/src/commands/ai-analyze.ts +429 -0
- package/src/commands/ai-animated-caption.ts +390 -0
- package/src/commands/ai-audio.ts +941 -0
- package/src/commands/ai-broll.ts +490 -0
- package/src/commands/ai-edit-cli.ts +658 -0
- package/src/commands/ai-edit.ts +1542 -0
- package/src/commands/ai-fill-gaps.ts +566 -0
- package/src/commands/ai-helpers.ts +65 -0
- package/src/commands/ai-highlights.ts +1303 -0
- package/src/commands/ai-image.ts +761 -0
- package/src/commands/ai-motion.ts +347 -0
- package/src/commands/ai-narrate.ts +451 -0
- package/src/commands/ai-review.ts +309 -0
- package/src/commands/ai-script-pipeline-cli.ts +1710 -0
- package/src/commands/ai-script-pipeline.ts +1365 -0
- package/src/commands/ai-suggest-edit.ts +264 -0
- package/src/commands/ai-video-fx.ts +445 -0
- package/src/commands/ai-video.ts +915 -0
- package/src/commands/ai-viral.ts +595 -0
- package/src/commands/ai-visual-fx.ts +601 -0
- package/src/commands/ai.test.ts +627 -0
- package/src/commands/ai.ts +307 -0
- package/src/commands/analyze.ts +282 -0
- package/src/commands/audio.ts +644 -0
- package/src/commands/batch.test.ts +279 -0
- package/src/commands/batch.ts +440 -0
- package/src/commands/detect.ts +329 -0
- package/src/commands/doctor.ts +237 -0
- package/src/commands/edit-cmd.ts +1014 -0
- package/src/commands/export.ts +918 -0
- package/src/commands/generate.ts +2146 -0
- package/src/commands/media.ts +177 -0
- package/src/commands/output.ts +142 -0
- package/src/commands/pipeline.ts +398 -0
- package/src/commands/project.test.ts +127 -0
- package/src/commands/project.ts +149 -0
- package/src/commands/sanitize.ts +60 -0
- package/src/commands/schema.ts +130 -0
- package/src/commands/setup.ts +509 -0
- package/src/commands/timeline.test.ts +499 -0
- package/src/commands/timeline.ts +529 -0
- package/src/commands/validate.ts +77 -0
- package/src/config/config.test.ts +197 -0
- package/src/config/index.ts +125 -0
- package/src/config/schema.ts +82 -0
- package/src/engine/index.ts +2 -0
- package/src/engine/project.test.ts +702 -0
- package/src/engine/project.ts +439 -0
- package/src/index.ts +146 -0
- package/src/utils/api-key.test.ts +41 -0
- package/src/utils/api-key.ts +247 -0
- package/src/utils/audio.ts +83 -0
- package/src/utils/exec-safe.ts +75 -0
- package/src/utils/first-run.ts +52 -0
- package/src/utils/provider-resolver.ts +56 -0
- package/src/utils/remotion.ts +951 -0
- package/src/utils/subtitle.test.ts +227 -0
- package/src/utils/subtitle.ts +169 -0
- package/src/utils/tty.ts +196 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module ai-video-fx
|
|
3
|
+
* @description Video FX commands (upscale, interpolate, inpaint, track-object).
|
|
4
|
+
*
|
|
5
|
+
* ## Commands: vibe ai upscale, vibe ai interpolate, vibe ai inpaint, vibe ai track-object
|
|
6
|
+
* ## Dependencies: Replicate
|
|
7
|
+
*
|
|
8
|
+
* Extracted from ai.ts as part of modularisation.
|
|
9
|
+
* ai.ts re-exports all public types and functions from this module.
|
|
10
|
+
* @see MODELS.md for AI model configuration
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { type Command } from "commander";
|
|
14
|
+
import { writeFile } from "node:fs/promises";
|
|
15
|
+
import { resolve } from "node:path";
|
|
16
|
+
import chalk from "chalk";
|
|
17
|
+
import ora from "ora";
|
|
18
|
+
import { ReplicateProvider } from "@vibeframe/ai-providers";
|
|
19
|
+
import { getApiKey } from "../utils/api-key.js";
|
|
20
|
+
import { execSafe } from "../utils/exec-safe.js";
|
|
21
|
+
import { downloadVideo } from "./ai-helpers.js";
|
|
22
|
+
|
|
23
|
+
// ── Register all video FX commands ───────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
export function registerVideoFxCommands(ai: Command): void {
|
|
26
|
+
// Video Upscale command
|
|
27
|
+
ai.command("video-upscale")
|
|
28
|
+
.description("Upscale video resolution using AI or FFmpeg")
|
|
29
|
+
.argument("<video>", "Video file path")
|
|
30
|
+
.option("-o, --output <path>", "Output file path")
|
|
31
|
+
.option("-s, --scale <factor>", "Scale factor: 2 or 4", "2")
|
|
32
|
+
.option("-m, --model <model>", "Model: real-esrgan, topaz", "real-esrgan")
|
|
33
|
+
.option("--ffmpeg", "Use FFmpeg lanczos (free, no API)")
|
|
34
|
+
.option("-k, --api-key <key>", "Replicate API token (or set REPLICATE_API_TOKEN env)")
|
|
35
|
+
.option("--no-wait", "Start processing and return task ID without waiting")
|
|
36
|
+
.action(async (videoPath: string, options) => {
|
|
37
|
+
try {
|
|
38
|
+
const absPath = resolve(process.cwd(), videoPath);
|
|
39
|
+
const scale = parseInt(options.scale);
|
|
40
|
+
|
|
41
|
+
if (scale !== 2 && scale !== 4) {
|
|
42
|
+
console.error(chalk.red("Scale must be 2 or 4"));
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Use FFmpeg if requested (free fallback)
|
|
47
|
+
if (options.ffmpeg) {
|
|
48
|
+
const outputPath = options.output
|
|
49
|
+
? resolve(process.cwd(), options.output)
|
|
50
|
+
: absPath.replace(/(\.[^.]+)$/, `-upscaled-${scale}x$1`);
|
|
51
|
+
|
|
52
|
+
const spinner = ora(`Upscaling video with FFmpeg (${scale}x)...`).start();
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
// Get original dimensions
|
|
56
|
+
const { stdout: probeOut } = await execSafe("ffprobe", [
|
|
57
|
+
"-v", "error", "-select_streams", "v:0", "-show_entries", "stream=width,height", "-of", "csv=p=0", absPath,
|
|
58
|
+
]);
|
|
59
|
+
const [width, height] = probeOut.trim().split(",").map(Number);
|
|
60
|
+
const newWidth = width * scale;
|
|
61
|
+
const newHeight = height * scale;
|
|
62
|
+
|
|
63
|
+
// Use lanczos scaling
|
|
64
|
+
await execSafe("ffmpeg", ["-i", absPath, "-vf", `scale=${newWidth}:${newHeight}:flags=lanczos`, "-c:a", "copy", outputPath, "-y"]);
|
|
65
|
+
|
|
66
|
+
spinner.succeed(chalk.green(`Upscaled to ${newWidth}x${newHeight}`));
|
|
67
|
+
console.log(`Output: ${outputPath}`);
|
|
68
|
+
} catch (err) {
|
|
69
|
+
spinner.fail(chalk.red("FFmpeg upscaling failed"));
|
|
70
|
+
console.error(err);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Use Replicate API
|
|
77
|
+
const apiKey = await getApiKey("REPLICATE_API_TOKEN", "Replicate", options.apiKey);
|
|
78
|
+
if (!apiKey) {
|
|
79
|
+
console.error(chalk.red("Replicate API token required for AI upscaling."));
|
|
80
|
+
console.error(chalk.dim("Use --api-key or set REPLICATE_API_TOKEN"));
|
|
81
|
+
console.error(chalk.dim("Or use --ffmpeg for free FFmpeg upscaling"));
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const spinner = ora("Initializing Replicate...").start();
|
|
86
|
+
|
|
87
|
+
const { ReplicateProvider } = await import("@vibeframe/ai-providers");
|
|
88
|
+
const replicate = new ReplicateProvider();
|
|
89
|
+
await replicate.initialize({ apiKey });
|
|
90
|
+
|
|
91
|
+
// For Replicate, we need a URL. Upload to temporary hosting or require URL
|
|
92
|
+
spinner.text = "Note: Replicate requires video URL. Reading file...";
|
|
93
|
+
|
|
94
|
+
// For now, we'll show an error suggesting URL or ffmpeg
|
|
95
|
+
spinner.fail(chalk.yellow("Replicate requires a video URL"));
|
|
96
|
+
console.log();
|
|
97
|
+
console.log(chalk.dim("Options:"));
|
|
98
|
+
console.log(chalk.dim(" 1. Use --ffmpeg for local processing"));
|
|
99
|
+
console.log(chalk.dim(" 2. Upload video to a URL and run:"));
|
|
100
|
+
console.log(chalk.dim(` pnpm vibe ai video-upscale https://example.com/video.mp4 -s ${scale}`));
|
|
101
|
+
console.log();
|
|
102
|
+
process.exit(1);
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error(chalk.red("Video upscaling failed"));
|
|
105
|
+
console.error(error);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Frame Interpolation (Slow Motion)
|
|
111
|
+
ai.command("video-interpolate")
|
|
112
|
+
.description("Create slow motion with frame interpolation (FFmpeg)")
|
|
113
|
+
.argument("<video>", "Video file path")
|
|
114
|
+
.option("-o, --output <path>", "Output file path")
|
|
115
|
+
.option("-f, --factor <number>", "Slow motion factor: 2, 4, or 8", "2")
|
|
116
|
+
.option("--fps <number>", "Target output FPS")
|
|
117
|
+
.option("-q, --quality <mode>", "Quality: fast or quality", "quality")
|
|
118
|
+
.action(async (videoPath: string, options) => {
|
|
119
|
+
try {
|
|
120
|
+
const absPath = resolve(process.cwd(), videoPath);
|
|
121
|
+
const factor = parseInt(options.factor);
|
|
122
|
+
|
|
123
|
+
if (![2, 4, 8].includes(factor)) {
|
|
124
|
+
console.error(chalk.red("Factor must be 2, 4, or 8"));
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const outputPath = options.output
|
|
129
|
+
? resolve(process.cwd(), options.output)
|
|
130
|
+
: absPath.replace(/(\.[^.]+)$/, `-slow${factor}x$1`);
|
|
131
|
+
|
|
132
|
+
const spinner = ora(`Creating ${factor}x slow motion...`).start();
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
// Get original FPS
|
|
136
|
+
const { stdout: fpsOut } = await execSafe("ffprobe", [
|
|
137
|
+
"-v", "error", "-select_streams", "v:0", "-show_entries", "stream=r_frame_rate", "-of", "default=noprint_wrappers=1:nokey=1", absPath,
|
|
138
|
+
]);
|
|
139
|
+
const [num, den] = fpsOut.trim().split("/").map(Number);
|
|
140
|
+
const originalFps = num / (den || 1);
|
|
141
|
+
|
|
142
|
+
// Calculate target FPS
|
|
143
|
+
const targetFps = options.fps ? parseInt(options.fps) : originalFps * factor;
|
|
144
|
+
|
|
145
|
+
// Use minterpolate for frame interpolation
|
|
146
|
+
const mi = options.quality === "fast" ? "mi_mode=mci" : "mi_mode=mci:mc_mode=aobmc:me_mode=bidir:vsbmc=1";
|
|
147
|
+
|
|
148
|
+
spinner.text = `Interpolating frames (${originalFps.toFixed(1)} → ${targetFps}fps)...`;
|
|
149
|
+
|
|
150
|
+
// First interpolate frames, then slow down
|
|
151
|
+
await execSafe("ffmpeg", ["-i", absPath, "-filter:v", `minterpolate='${mi}:fps=${targetFps}',setpts=${factor}*PTS`, "-an", outputPath, "-y"], { timeout: 600000 });
|
|
152
|
+
|
|
153
|
+
spinner.succeed(chalk.green(`Created ${factor}x slow motion`));
|
|
154
|
+
console.log();
|
|
155
|
+
console.log(chalk.dim("─".repeat(60)));
|
|
156
|
+
console.log(`Original FPS: ${originalFps.toFixed(1)}`);
|
|
157
|
+
console.log(`Interpolated FPS: ${targetFps}`);
|
|
158
|
+
console.log(`Slow factor: ${factor}x`);
|
|
159
|
+
console.log(`Output: ${outputPath}`);
|
|
160
|
+
console.log();
|
|
161
|
+
} catch (err: unknown) {
|
|
162
|
+
spinner.fail(chalk.red("Frame interpolation failed"));
|
|
163
|
+
if (err instanceof Error && err.message.includes("timeout")) {
|
|
164
|
+
console.error(chalk.yellow("Processing timed out. Try with a shorter video or --quality fast"));
|
|
165
|
+
} else {
|
|
166
|
+
console.error(err);
|
|
167
|
+
}
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
} catch (error) {
|
|
171
|
+
console.error(chalk.red("Frame interpolation failed"));
|
|
172
|
+
console.error(error);
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// Video Inpainting (Object Removal)
|
|
178
|
+
ai.command("video-inpaint")
|
|
179
|
+
.description("Remove objects from video using AI inpainting")
|
|
180
|
+
.argument("<video>", "Video file path or URL")
|
|
181
|
+
.option("-o, --output <path>", "Output file path")
|
|
182
|
+
.option("-t, --target <description>", "Object to remove (text description)")
|
|
183
|
+
.option("-m, --mask <path>", "Mask video file path (white = remove)")
|
|
184
|
+
.option("-k, --api-key <key>", "Replicate API token (or set REPLICATE_API_TOKEN env)")
|
|
185
|
+
.option("--provider <name>", "Provider: replicate", "replicate")
|
|
186
|
+
.option("--no-wait", "Start processing and return task ID without waiting")
|
|
187
|
+
.action(async (videoPath: string, options) => {
|
|
188
|
+
try {
|
|
189
|
+
if (!options.target && !options.mask) {
|
|
190
|
+
console.error(chalk.red("Either --target or --mask is required"));
|
|
191
|
+
console.error(chalk.dim("Examples:"));
|
|
192
|
+
console.error(chalk.dim(' pnpm vibe ai video-inpaint video.mp4 --target "watermark"'));
|
|
193
|
+
console.error(chalk.dim(" pnpm vibe ai video-inpaint video.mp4 --mask mask.mp4"));
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const apiKey = await getApiKey("REPLICATE_API_TOKEN", "Replicate", options.apiKey);
|
|
198
|
+
if (!apiKey) {
|
|
199
|
+
console.error(chalk.red("Replicate API token required for video inpainting."));
|
|
200
|
+
console.error(chalk.dim("Use --api-key or set REPLICATE_API_TOKEN"));
|
|
201
|
+
process.exit(1);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const spinner = ora("Initializing Replicate...").start();
|
|
205
|
+
|
|
206
|
+
const { ReplicateProvider } = await import("@vibeframe/ai-providers");
|
|
207
|
+
const replicate = new ReplicateProvider();
|
|
208
|
+
await replicate.initialize({ apiKey });
|
|
209
|
+
|
|
210
|
+
// Check if video is URL or file
|
|
211
|
+
let videoUrl: string;
|
|
212
|
+
if (videoPath.startsWith("http://") || videoPath.startsWith("https://")) {
|
|
213
|
+
videoUrl = videoPath;
|
|
214
|
+
} else {
|
|
215
|
+
spinner.fail(chalk.yellow("Video inpainting requires a video URL"));
|
|
216
|
+
console.log();
|
|
217
|
+
console.log(chalk.dim("Upload your video to a URL and run:"));
|
|
218
|
+
console.log(chalk.dim(` pnpm vibe ai video-inpaint https://example.com/video.mp4 --mask https://example.com/mask.mp4`));
|
|
219
|
+
console.log();
|
|
220
|
+
process.exit(1);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
let maskVideo: string | undefined;
|
|
224
|
+
if (options.mask) {
|
|
225
|
+
if (options.mask.startsWith("http://") || options.mask.startsWith("https://")) {
|
|
226
|
+
maskVideo = options.mask;
|
|
227
|
+
} else {
|
|
228
|
+
spinner.fail(chalk.yellow("Mask must also be a URL"));
|
|
229
|
+
process.exit(1);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
spinner.text = "Starting video inpainting...";
|
|
234
|
+
|
|
235
|
+
const result = await replicate.inpaintVideo(videoUrl, {
|
|
236
|
+
target: options.target,
|
|
237
|
+
maskVideo,
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
if (result.status === "failed") {
|
|
241
|
+
spinner.fail(chalk.red(result.error || "Failed to start inpainting"));
|
|
242
|
+
process.exit(1);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
console.log();
|
|
246
|
+
console.log(chalk.bold.cyan("Video Inpainting Started"));
|
|
247
|
+
console.log(chalk.dim("─".repeat(60)));
|
|
248
|
+
console.log(`Task ID: ${chalk.bold(result.id)}`);
|
|
249
|
+
|
|
250
|
+
if (!options.wait) {
|
|
251
|
+
spinner.succeed(chalk.green("Inpainting started"));
|
|
252
|
+
console.log();
|
|
253
|
+
console.log(chalk.dim("Check status with:"));
|
|
254
|
+
console.log(chalk.dim(` curl -s -H "Authorization: Bearer $REPLICATE_API_TOKEN" https://api.replicate.com/v1/predictions/${result.id}`));
|
|
255
|
+
console.log();
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
spinner.text = "Processing video (this may take several minutes)...";
|
|
260
|
+
|
|
261
|
+
const finalResult = await replicate.waitForCompletion(
|
|
262
|
+
result.id,
|
|
263
|
+
(status) => {
|
|
264
|
+
spinner.text = `Processing... ${status.status}`;
|
|
265
|
+
},
|
|
266
|
+
600000
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
if (finalResult.status !== "completed") {
|
|
270
|
+
spinner.fail(chalk.red(finalResult.error || "Inpainting failed"));
|
|
271
|
+
process.exit(1);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
spinner.succeed(chalk.green("Video inpainting complete"));
|
|
275
|
+
|
|
276
|
+
console.log();
|
|
277
|
+
if (finalResult.videoUrl) {
|
|
278
|
+
console.log(`Video URL: ${finalResult.videoUrl}`);
|
|
279
|
+
|
|
280
|
+
// Download if output specified
|
|
281
|
+
if (options.output) {
|
|
282
|
+
const downloadSpinner = ora("Downloading video...").start();
|
|
283
|
+
try {
|
|
284
|
+
const buffer = await downloadVideo(finalResult.videoUrl);
|
|
285
|
+
const outputPath = resolve(process.cwd(), options.output);
|
|
286
|
+
await writeFile(outputPath, buffer);
|
|
287
|
+
downloadSpinner.succeed(chalk.green(`Saved to: ${outputPath}`));
|
|
288
|
+
} catch (err) {
|
|
289
|
+
downloadSpinner.fail(chalk.red("Failed to download video"));
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
console.log();
|
|
294
|
+
} catch (error) {
|
|
295
|
+
console.error(chalk.red("Video inpainting failed"));
|
|
296
|
+
console.error(error);
|
|
297
|
+
process.exit(1);
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
// Object Tracking
|
|
302
|
+
ai.command("track-object")
|
|
303
|
+
.description("Track objects in video (Replicate SAM-2)")
|
|
304
|
+
.argument("<video>", "Video file path or URL")
|
|
305
|
+
.option("-p, --point <x,y>", "Point to track (x,y coordinates)")
|
|
306
|
+
.option("-b, --box <x,y,w,h>", "Bounding box to track (x,y,width,height)")
|
|
307
|
+
.option("--prompt <text>", "Object description to track")
|
|
308
|
+
.option("-o, --output <path>", "Output JSON or MP4 file path", "track.json")
|
|
309
|
+
.option("-v, --visualize", "Output video with tracking overlay")
|
|
310
|
+
.option("--no-wait", "Start processing without waiting")
|
|
311
|
+
.option("-k, --api-key <key>", "Replicate API token (or set REPLICATE_API_TOKEN env)")
|
|
312
|
+
.action(async (videoPath: string, options) => {
|
|
313
|
+
try {
|
|
314
|
+
if (!options.point && !options.box && !options.prompt) {
|
|
315
|
+
console.error(chalk.red("Tracking target required. Use --point, --box, or --prompt"));
|
|
316
|
+
console.log(chalk.dim("Examples:"));
|
|
317
|
+
console.log(chalk.dim(" pnpm vibe ai track-object video.mp4 --point 500,300"));
|
|
318
|
+
console.log(chalk.dim(" pnpm vibe ai track-object video.mp4 --box 100,100,200,200"));
|
|
319
|
+
console.log(chalk.dim(' pnpm vibe ai track-object video.mp4 --prompt "the person"'));
|
|
320
|
+
process.exit(1);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const apiKey = await getApiKey("REPLICATE_API_TOKEN", "Replicate", options.apiKey);
|
|
324
|
+
if (!apiKey) {
|
|
325
|
+
console.error(chalk.red("Replicate API token required."));
|
|
326
|
+
console.error(chalk.dim("Set REPLICATE_API_TOKEN environment variable"));
|
|
327
|
+
process.exit(1);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const spinner = ora("Initializing object tracking...").start();
|
|
331
|
+
|
|
332
|
+
const replicate = new ReplicateProvider();
|
|
333
|
+
await replicate.initialize({ apiKey });
|
|
334
|
+
|
|
335
|
+
// Video must be URL
|
|
336
|
+
let videoUrl: string;
|
|
337
|
+
if (videoPath.startsWith("http://") || videoPath.startsWith("https://")) {
|
|
338
|
+
videoUrl = videoPath;
|
|
339
|
+
} else {
|
|
340
|
+
spinner.fail(chalk.yellow("Video must be a URL for Replicate processing."));
|
|
341
|
+
console.log(chalk.dim("Upload your video to a URL and try again."));
|
|
342
|
+
process.exit(1);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Parse tracking target
|
|
346
|
+
let point: [number, number] | undefined;
|
|
347
|
+
let box: [number, number, number, number] | undefined;
|
|
348
|
+
|
|
349
|
+
if (options.point) {
|
|
350
|
+
const [x, y] = options.point.split(",").map(Number);
|
|
351
|
+
point = [x, y];
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (options.box) {
|
|
355
|
+
const [x, y, w, h] = options.box.split(",").map(Number);
|
|
356
|
+
box = [x, y, w, h];
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
spinner.text = "Starting object tracking...";
|
|
360
|
+
|
|
361
|
+
const result = await replicate.trackObject({
|
|
362
|
+
videoUrl,
|
|
363
|
+
point,
|
|
364
|
+
box,
|
|
365
|
+
prompt: options.prompt,
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
if (result.status === "failed") {
|
|
369
|
+
spinner.fail(chalk.red(result.error || "Object tracking failed"));
|
|
370
|
+
process.exit(1);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
console.log();
|
|
374
|
+
console.log(chalk.bold.cyan("Object Tracking Started"));
|
|
375
|
+
console.log(chalk.dim("─".repeat(60)));
|
|
376
|
+
console.log(`Task ID: ${chalk.bold(result.id)}`);
|
|
377
|
+
if (point) console.log(`Point: ${point[0]}, ${point[1]}`);
|
|
378
|
+
if (box) console.log(`Box: ${box[0]}, ${box[1]}, ${box[2]}, ${box[3]}`);
|
|
379
|
+
if (options.prompt) console.log(`Prompt: ${options.prompt}`);
|
|
380
|
+
|
|
381
|
+
if (!options.wait) {
|
|
382
|
+
spinner.succeed(chalk.green("Tracking started"));
|
|
383
|
+
console.log();
|
|
384
|
+
console.log(chalk.dim("Check status with:"));
|
|
385
|
+
console.log(chalk.dim(` curl -s -H "Authorization: Bearer $REPLICATE_API_TOKEN" https://api.replicate.com/v1/predictions/${result.id}`));
|
|
386
|
+
console.log();
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
spinner.text = "Processing tracking (this may take several minutes)...";
|
|
391
|
+
|
|
392
|
+
const finalResult = await replicate.getTrackingResult(result.id);
|
|
393
|
+
|
|
394
|
+
// Poll for completion
|
|
395
|
+
let pollResult = finalResult;
|
|
396
|
+
const startTime = Date.now();
|
|
397
|
+
const maxWait = 600000;
|
|
398
|
+
|
|
399
|
+
while (pollResult.status !== "completed" && pollResult.status !== "failed" && Date.now() - startTime < maxWait) {
|
|
400
|
+
await new Promise((r) => setTimeout(r, 3000));
|
|
401
|
+
pollResult = await replicate.getTrackingResult(result.id);
|
|
402
|
+
spinner.text = `Processing... ${pollResult.status}`;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (pollResult.status !== "completed") {
|
|
406
|
+
spinner.fail(chalk.red(pollResult.error || "Tracking failed or timed out"));
|
|
407
|
+
process.exit(1);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
spinner.succeed(chalk.green("Object tracking complete"));
|
|
411
|
+
|
|
412
|
+
console.log();
|
|
413
|
+
if (pollResult.maskUrl) {
|
|
414
|
+
console.log(`Mask URL: ${pollResult.maskUrl}`);
|
|
415
|
+
|
|
416
|
+
const outputPath = resolve(process.cwd(), options.output);
|
|
417
|
+
if (options.visualize || options.output.endsWith(".mp4")) {
|
|
418
|
+
const downloadSpinner = ora("Downloading tracking mask...").start();
|
|
419
|
+
try {
|
|
420
|
+
const response = await fetch(pollResult.maskUrl);
|
|
421
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
422
|
+
await writeFile(outputPath, buffer);
|
|
423
|
+
downloadSpinner.succeed(chalk.green(`Saved to: ${outputPath}`));
|
|
424
|
+
} catch (err) {
|
|
425
|
+
downloadSpinner.fail(chalk.red("Failed to download mask"));
|
|
426
|
+
}
|
|
427
|
+
} else {
|
|
428
|
+
// Save tracking data as JSON
|
|
429
|
+
const trackData = {
|
|
430
|
+
taskId: result.id,
|
|
431
|
+
maskUrl: pollResult.maskUrl,
|
|
432
|
+
trackingData: pollResult.trackingData,
|
|
433
|
+
};
|
|
434
|
+
await writeFile(outputPath, JSON.stringify(trackData, null, 2));
|
|
435
|
+
console.log(chalk.green(`Tracking data saved to: ${outputPath}`));
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
console.log();
|
|
439
|
+
} catch (error) {
|
|
440
|
+
console.error(chalk.red("Object tracking failed"));
|
|
441
|
+
console.error(error);
|
|
442
|
+
process.exit(1);
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
}
|