videobook 0.0.0-stage → 0.1.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/CHANGELOG.md +18 -0
- package/LICENSE +21 -0
- package/README.md +133 -2
- package/bin/videobook.js +7 -0
- package/dist/acestep/client.js +203 -0
- package/dist/acestep/config.js +62 -0
- package/dist/acestep/errors.js +8 -0
- package/dist/acestep/process.js +175 -0
- package/dist/alive-captions/analyze.js +117 -0
- package/dist/alive-captions/audio.js +179 -0
- package/dist/alive-captions/frames.js +59 -0
- package/dist/alive-captions/model.js +37 -0
- package/dist/alive-captions/schema.js +49 -0
- package/dist/alive-captions/track.js +9 -0
- package/dist/api-key.js +33 -0
- package/dist/app-state.js +56 -0
- package/dist/app.js +257 -0
- package/dist/archive-b2.js +332 -0
- package/dist/archive-store.js +169 -0
- package/dist/artifact-label.js +36 -0
- package/dist/artifact-refs.js +49 -0
- package/dist/asset-tag-extraction.js +169 -0
- package/dist/asset-tags.js +228 -0
- package/dist/asset-usage.js +23 -0
- package/dist/audio-cue.js +71 -0
- package/dist/audio-encoding.js +32 -0
- package/dist/audio-sync-request.js +1 -0
- package/dist/audio-sync.js +223 -0
- package/dist/audio-trim-range.js +31 -0
- package/dist/book-context.js +31 -0
- package/dist/book-manager.js +374 -0
- package/dist/catalog-gc.js +26 -0
- package/dist/chain-executor.js +815 -0
- package/dist/chain-generation.js +115 -0
- package/dist/chain-plan.js +746 -0
- package/dist/chain-step-review.js +60 -0
- package/dist/character-name.js +25 -0
- package/dist/chat-generation-routing.js +73 -0
- package/dist/chat-generation-settings.js +78 -0
- package/dist/chat-models.js +44 -0
- package/dist/chat-prompt-rewrite.js +67 -0
- package/dist/chat-router.js +628 -0
- package/dist/chat-view-actions.js +49 -0
- package/dist/cli/args.js +192 -0
- package/dist/cli/doctor-command.js +255 -0
- package/dist/cli/entry.js +2 -0
- package/dist/cli/main.js +91 -0
- package/dist/cli/mcp-command.js +82 -0
- package/dist/cli/mcp-relay.js +51 -0
- package/dist/cli/open-browser.js +14 -0
- package/dist/cli/run-command.js +187 -0
- package/dist/cli/serve-command.js +57 -0
- package/dist/cli/stdio-guard.js +8 -0
- package/dist/cold-open-model.js +7 -0
- package/dist/cold-open.js +79 -0
- package/dist/command-reference.js +95 -0
- package/dist/content-store.js +74 -0
- package/dist/cost.js +8 -0
- package/dist/crop-geometry.js +23 -0
- package/dist/dancing-workflow.js +446 -0
- package/dist/data-home.js +44 -0
- package/dist/diagnostics.js +109 -0
- package/dist/dialog-quality.js +34 -0
- package/dist/downloads-dest.js +56 -0
- package/dist/editing-moments.js +194 -0
- package/dist/elevenlabs-audio-extension.js +66 -0
- package/dist/engine.js +54 -0
- package/dist/env-secrets.js +184 -0
- package/dist/ffmpeg-binary.js +12 -0
- package/dist/ffmpeg.js +425 -0
- package/dist/ffprobe-binary.js +55 -0
- package/dist/forget-asset.js +216 -0
- package/dist/frame-utils.js +27 -0
- package/dist/generation-credit-error.js +11 -0
- package/dist/generation-input-mentions.js +117 -0
- package/dist/generation-input-policy.js +68 -0
- package/dist/generation-reference-mentions.js +97 -0
- package/dist/goal-characters.js +49 -0
- package/dist/goal-plan-v3.js +273 -0
- package/dist/goal-plan.js +220 -0
- package/dist/goal-planner-prompt.js +28 -0
- package/dist/goal-prompt-budget.js +4 -0
- package/dist/goal-reference-images.js +25 -0
- package/dist/goal-state.js +261 -0
- package/dist/goal-stills.js +153 -0
- package/dist/goal-store.js +144 -0
- package/dist/goal-styles.js +144 -0
- package/dist/goal-v3-runtime.js +157 -0
- package/dist/guides/character_schema_guide.md +70 -0
- package/dist/guides/gpt_image_2_5_prompting_guide.md +21 -0
- package/dist/guides/grok_imagine_prompting_guide.md +72 -0
- package/dist/guides/image_reproduction_guide.md +84 -0
- package/dist/guides/kling_3_0_prompting_guide.md +136 -0
- package/dist/guides/nano_banana_pro_prompting_guide.md +28 -0
- package/dist/guides/seedance_2_prompting_guide.md +172 -0
- package/dist/http-access.js +49 -0
- package/dist/http-byte-range.js +31 -0
- package/dist/image-compress.js +77 -0
- package/dist/image-edit-default.js +1 -0
- package/dist/image-edit-models.js +41 -0
- package/dist/image-edit-settings.js +11 -0
- package/dist/image-region-edit.js +32 -0
- package/dist/image-subject-map.js +523 -0
- package/dist/image.js +46 -0
- package/dist/index.js +12 -0
- package/dist/job-deadline.js +60 -0
- package/dist/jobs/_alibaba-upload.js +30 -0
- package/dist/jobs/_audio-chunks.js +31 -0
- package/dist/jobs/_download-into-asset.js +15 -0
- package/dist/jobs/_fal-shared.js +22 -0
- package/dist/jobs/_fal-upload.js +35 -0
- package/dist/jobs/_image-edit-adapter.js +213 -0
- package/dist/jobs/_kie-poll.js +119 -0
- package/dist/jobs/_kie-upload.js +32 -0
- package/dist/jobs/_lease.js +163 -0
- package/dist/jobs/_persist-output.js +19 -0
- package/dist/jobs/_storage-retry.js +21 -0
- package/dist/jobs/_transcribe.js +245 -0
- package/dist/jobs/_translate-transcript.js +270 -0
- package/dist/jobs/analyze-alive-captions.js +10 -0
- package/dist/jobs/analyze-editing-moments.js +104 -0
- package/dist/jobs/analyze-jokes.js +143 -0
- package/dist/jobs/analyze-keyword-placement.js +155 -0
- package/dist/jobs/analyze-music.js +14 -0
- package/dist/jobs/analyze-video.js +282 -0
- package/dist/jobs/apply-cuts.js +83 -0
- package/dist/jobs/apply-sfx.js +107 -0
- package/dist/jobs/archive-clip.js +457 -0
- package/dist/jobs/assemble-goal.js +98 -0
- package/dist/jobs/audio-boost.js +71 -0
- package/dist/jobs/audio-mix.js +161 -0
- package/dist/jobs/backfill-asset-tags.js +144 -0
- package/dist/jobs/burn-watermark.js +316 -0
- package/dist/jobs/change-video-speed.js +176 -0
- package/dist/jobs/clean-video-audio.js +207 -0
- package/dist/jobs/cold-open.js +166 -0
- package/dist/jobs/combine-goal.js +108 -0
- package/dist/jobs/complete-provider-task.js +185 -0
- package/dist/jobs/copy-library-asset.js +33 -0
- package/dist/jobs/cost-estimate-assessment.js +113 -0
- package/dist/jobs/crop-image.js +47 -0
- package/dist/jobs/crop-video.js +71 -0
- package/dist/jobs/describe-image.js +181 -0
- package/dist/jobs/detect-scenes.js +33 -0
- package/dist/jobs/doctor-fix.js +100 -0
- package/dist/jobs/download-video.js +426 -0
- package/dist/jobs/enqueue-search-index.js +24 -0
- package/dist/jobs/even-split.js +122 -0
- package/dist/jobs/export-sequence.js +365 -0
- package/dist/jobs/extend-audio.js +229 -0
- package/dist/jobs/extract-audio.js +72 -0
- package/dist/jobs/extract-frame.js +58 -0
- package/dist/jobs/extract-notebook-audio.js +82 -0
- package/dist/jobs/extract-notebook-frame.js +93 -0
- package/dist/jobs/extract-video-clip.js +8 -0
- package/dist/jobs/extract-video-poster.js +55 -0
- package/dist/jobs/extract-waveform.js +25 -0
- package/dist/jobs/finish-goal.js +255 -0
- package/dist/jobs/forget-asset.js +11 -0
- package/dist/jobs/generate-acestep-cover.js +219 -0
- package/dist/jobs/generate-media.js +70 -0
- package/dist/jobs/image-subjects.js +1059 -0
- package/dist/jobs/index.js +18 -0
- package/dist/jobs/inject-first-frame.js +175 -0
- package/dist/jobs/isolate-vocals.js +69 -0
- package/dist/jobs/kie-paygate.js +177 -0
- package/dist/jobs/label-music-sections.js +5 -0
- package/dist/jobs/osg-placement.js +135 -0
- package/dist/jobs/pad-video.js +72 -0
- package/dist/jobs/plan-goal.js +97 -0
- package/dist/jobs/post-record.js +21 -0
- package/dist/jobs/post-to-x.js +21 -0
- package/dist/jobs/prepare-search-reference.js +190 -0
- package/dist/jobs/prepare-temporal-search.js +16 -0
- package/dist/jobs/process-audio.js +67 -0
- package/dist/jobs/process-image.js +58 -0
- package/dist/jobs/process-upload.js +166 -0
- package/dist/jobs/process-video.js +438 -0
- package/dist/jobs/register-all.js +161 -0
- package/dist/jobs/relayout-notebook.js +78 -0
- package/dist/jobs/remove-sound.js +299 -0
- package/dist/jobs/render-project.js +380 -0
- package/dist/jobs/render-qr-outro.js +138 -0
- package/dist/jobs/render-timeline.js +283 -0
- package/dist/jobs/repair-search-indexes.js +42 -0
- package/dist/jobs/replace-video-audio.js +64 -0
- package/dist/jobs/restore-archive-clip.js +53 -0
- package/dist/jobs/reverse-video.js +53 -0
- package/dist/jobs/rewrite-script.js +173 -0
- package/dist/jobs/run-notebook.js +3335 -0
- package/dist/jobs/semantic-index.js +797 -0
- package/dist/jobs/smooth-scene-concat.js +257 -0
- package/dist/jobs/splice-video.js +280 -0
- package/dist/jobs/split-video.js +127 -0
- package/dist/jobs/suggest-cuts.js +149 -0
- package/dist/jobs/suggest-sfx.js +135 -0
- package/dist/jobs/sync-video-to-audio.js +329 -0
- package/dist/jobs/tag-asset.js +266 -0
- package/dist/jobs/task-failure.js +16 -0
- package/dist/jobs/timewarp-video.js +152 -0
- package/dist/jobs/transcribe-video-audio.js +117 -0
- package/dist/jobs/transcribe.js +35 -0
- package/dist/jobs/translate-transcript.js +55 -0
- package/dist/jobs/trim-audio.js +133 -0
- package/dist/jobs/trim-video.js +291 -0
- package/dist/jobs/xai-paygate.js +26 -0
- package/dist/keyword-placement-cache.js +74 -0
- package/dist/lazy-render.js +142 -0
- package/dist/library-browse.js +78 -0
- package/dist/lightning-defaults.js +206 -0
- package/dist/load-env.js +9 -0
- package/dist/local-search-models.js +206 -0
- package/dist/local-upload.js +318 -0
- package/dist/logger.js +69 -0
- package/dist/media/adapters/alibaba.js +20 -0
- package/dist/media/adapters/elevenlabs.js +58 -0
- package/dist/media/adapters/fal.js +45 -0
- package/dist/media/adapters/index.js +26 -0
- package/dist/media/adapters/kie.js +120 -0
- package/dist/media/adapters/pending.js +21 -0
- package/dist/media/adapters/types.js +5 -0
- package/dist/media/adapters/xai.js +18 -0
- package/dist/media/catalog.js +236 -0
- package/dist/media/complete.js +191 -0
- package/dist/media/cost.js +45 -0
- package/dist/media/descriptor.js +157 -0
- package/dist/media/endpoints.js +11 -0
- package/dist/media/frame-options.js +18 -0
- package/dist/media/insert-video-timing.js +17 -0
- package/dist/media/json-schema.js +75 -0
- package/dist/media/legacy-task-types.js +129 -0
- package/dist/media/listing.js +24 -0
- package/dist/media/model-id.js +14 -0
- package/dist/media/preview.js +86 -0
- package/dist/media/prompt-dialects.js +65 -0
- package/dist/media/ref-fields.js +106 -0
- package/dist/media/refs.js +131 -0
- package/dist/media/request.js +188 -0
- package/dist/media/types.js +6 -0
- package/dist/media/wire.js +161 -0
- package/dist/media-library.js +535 -0
- package/dist/media-output-path.js +33 -0
- package/dist/multyculty-workflow.js +757 -0
- package/dist/notebook-action-catalog.js +608 -0
- package/dist/notebook-cell-outputs.js +726 -0
- package/dist/notebook-credit-retry.js +45 -0
- package/dist/notebook-fixtures.js +8 -0
- package/dist/notebook-generation-contract.js +77 -0
- package/dist/notebook-generation-controls.js +145 -0
- package/dist/notebook-goal-layout.js +40 -0
- package/dist/notebook-graph.js +37 -0
- package/dist/notebook-image-edit.js +84 -0
- package/dist/notebook-initial-generation-prompt.js +222 -0
- package/dist/notebook-live-analysis.js +941 -0
- package/dist/notebook-media-ops.js +579 -0
- package/dist/notebook-mutations.js +20 -0
- package/dist/notebook-placement.js +41 -0
- package/dist/notebook-provider-failure.js +87 -0
- package/dist/notebook-published-post.js +26 -0
- package/dist/notebook-reference-resolver.js +227 -0
- package/dist/notebook-relayout.js +270 -0
- package/dist/notebook-run-plan.js +519 -0
- package/dist/notebook-shots.js +162 -0
- package/dist/notebook-workflow.js +856 -0
- package/dist/openai-intelligence.js +99 -0
- package/dist/original-media-file.js +12 -0
- package/dist/osg-assets.js +36 -0
- package/dist/osg-placement-cache.js +64 -0
- package/dist/osg-settings.js +27 -0
- package/dist/paid-tools.js +22 -0
- package/dist/platform-guidance.js +26 -0
- package/dist/posts/dropbox-auth.js +91 -0
- package/dist/posts/dropbox-upload.js +132 -0
- package/dist/posts/icloud-drive.js +134 -0
- package/dist/posts/icloud-status.js +64 -0
- package/dist/posts/post-contract.js +2 -0
- package/dist/posts/post-copy-format.js +43 -0
- package/dist/posts/post-copy.js +193 -0
- package/dist/posts/post-folder.js +18 -0
- package/dist/posts/post-metrics.js +119 -0
- package/dist/posts/post-store.js +340 -0
- package/dist/posts/x-post-target.js +43 -0
- package/dist/preview-payload.js +90 -0
- package/dist/prompt-surfaces.js +22 -0
- package/dist/provider-prompt-transform.js +77 -0
- package/dist/provider-status-link.js +21 -0
- package/dist/provider-task-record.js +78 -0
- package/dist/provider-task-status.js +47 -0
- package/dist/provider-usage.js +294 -0
- package/dist/queue.js +806 -0
- package/dist/reference-video-duration.js +17 -0
- package/dist/remotion/BlurFillVideo.js +51 -0
- package/dist/remotion/KeywordGraphicsOverlay.js +68 -0
- package/dist/remotion/OsgOverlay.js +30 -0
- package/dist/remotion/QrOutroComposition.js +47 -0
- package/dist/remotion/RenderComposition.js +11 -0
- package/dist/remotion/browser.js +59 -0
- package/dist/remotion/constants.js +35 -0
- package/dist/remotion/index.js +66 -0
- package/dist/remotion/keyword-graphics.js +151 -0
- package/dist/remotion/keyword-placement.js +182 -0
- package/dist/remotion/osg-spec.js +198 -0
- package/dist/remotion/public/qr-outro-impact.wav +0 -0
- package/dist/remotion/qr-outro-audio.js +1 -0
- package/dist/remotion/qr-outro-spec.js +211 -0
- package/dist/remotion/shared-bundle.js +37 -0
- package/dist/remotion/subtitles/AliveCaptions.js +83 -0
- package/dist/remotion/subtitles/Highlight.js +58 -0
- package/dist/remotion/subtitles/Impact.js +67 -0
- package/dist/remotion/subtitles/SubtitleOverlay.js +9 -0
- package/dist/remotion/subtitles/alive-layout.js +321 -0
- package/dist/remotion/subtitles/alive-types.js +17 -0
- package/dist/remotion/subtitles/chunker.js +68 -0
- package/dist/remotion/subtitles/segments.js +42 -0
- package/dist/remotion/subtitles/styles.js +4 -0
- package/dist/remotion/subtitles/types.js +1 -0
- package/dist/remotion/util.js +18 -0
- package/dist/remotion-cancellation.js +15 -0
- package/dist/rename-helpers.js +204 -0
- package/dist/rhythm/analyze.js +128 -0
- package/dist/rhythm/contract.js +14 -0
- package/dist/rhythm/draft-model.js +19 -0
- package/dist/rhythm/energy.js +133 -0
- package/dist/rhythm/fft.js +44 -0
- package/dist/rhythm/model.js +71 -0
- package/dist/rhythm/music-analysis.js +124 -0
- package/dist/rhythm/music-draft.js +261 -0
- package/dist/rhythm/onset.js +101 -0
- package/dist/rhythm/run-worker.js +51 -0
- package/dist/rhythm/score.js +47 -0
- package/dist/rhythm/section-labels.js +168 -0
- package/dist/rhythm/sequence-rhythm.js +67 -0
- package/dist/rhythm/synthesize.js +103 -0
- package/dist/rhythm/timing.js +98 -0
- package/dist/rhythm/track.js +320 -0
- package/dist/rhythm/visual-fit.js +4 -0
- package/dist/rhythm/worker.js +25 -0
- package/dist/scene-detect.js +200 -0
- package/dist/scene-transition.js +12 -0
- package/dist/scheduled-posts.js +200 -0
- package/dist/search-index-coverage.js +13 -0
- package/dist/search-index-media.js +71 -0
- package/dist/search-reference-store.js +60 -0
- package/dist/search-scoring.js +17 -0
- package/dist/serve.js +150 -0
- package/dist/server-lock.js +143 -0
- package/dist/server.js +42 -0
- package/dist/srt.js +16 -0
- package/dist/tag-backfill-state.js +121 -0
- package/dist/tag-settings.js +30 -0
- package/dist/tag-vocabulary.js +237 -0
- package/dist/test-queue-cleanup.js +1 -0
- package/dist/time-parse.js +50 -0
- package/dist/timeline-helpers.js +554 -0
- package/dist/timewarp.js +87 -0
- package/dist/tools/_image-inputs.js +9 -0
- package/dist/tools/_media-refs.js +84 -0
- package/dist/tools/_shared.js +59 -0
- package/dist/tools/_suggest-shared.js +279 -0
- package/dist/tools/add-timeline-audio.js +73 -0
- package/dist/tools/alive-captions.js +157 -0
- package/dist/tools/analyze-jokes.js +56 -0
- package/dist/tools/analyze-video.js +66 -0
- package/dist/tools/animate-keywords.js +217 -0
- package/dist/tools/api-status.js +42 -0
- package/dist/tools/application-commands.js +34 -0
- package/dist/tools/apply-cuts.js +112 -0
- package/dist/tools/apply-sfx.js +152 -0
- package/dist/tools/apply-watermark.js +670 -0
- package/dist/tools/archive-clip.js +74 -0
- package/dist/tools/asset-history.js +61 -0
- package/dist/tools/asset-manifest.js +24 -0
- package/dist/tools/asset-tags.js +151 -0
- package/dist/tools/assign-slot.js +97 -0
- package/dist/tools/audio-boost.js +107 -0
- package/dist/tools/audio-mix.js +121 -0
- package/dist/tools/book-usage.js +16 -0
- package/dist/tools/chain.js +136 -0
- package/dist/tools/change-video-speed.js +105 -0
- package/dist/tools/chat-history.js +5 -0
- package/dist/tools/chat.js +848 -0
- package/dist/tools/clean-video-audio.js +97 -0
- package/dist/tools/clear-failed-tasks.js +66 -0
- package/dist/tools/cold-open.js +114 -0
- package/dist/tools/command-plan.js +1680 -0
- package/dist/tools/commands.js +1666 -0
- package/dist/tools/concat-images.js +236 -0
- package/dist/tools/connect-service.js +55 -0
- package/dist/tools/copy-file-to-clipboard.js +58 -0
- package/dist/tools/create-character.js +114 -0
- package/dist/tools/create-qart.js +253 -0
- package/dist/tools/create-qr-outro.js +149 -0
- package/dist/tools/create-qrbtf.js +215 -0
- package/dist/tools/create-watermark.js +97 -0
- package/dist/tools/crop-asset.js +18 -0
- package/dist/tools/crop-image.js +120 -0
- package/dist/tools/crop-video.js +97 -0
- package/dist/tools/delete-asset.js +104 -0
- package/dist/tools/describe-image.js +69 -0
- package/dist/tools/detect-scenes.js +44 -0
- package/dist/tools/doctor.js +126 -0
- package/dist/tools/download-video.js +114 -0
- package/dist/tools/duplicate-asset.js +184 -0
- package/dist/tools/edit-timeline.js +59 -0
- package/dist/tools/editing-moments.js +105 -0
- package/dist/tools/estimate-cost.js +171 -0
- package/dist/tools/even-split.js +295 -0
- package/dist/tools/export-asset-file.js +22 -0
- package/dist/tools/export-asset.js +140 -0
- package/dist/tools/export-sequence.js +250 -0
- package/dist/tools/export-to-downloads.js +54 -0
- package/dist/tools/export-transcript-srt.js +79 -0
- package/dist/tools/extend-audio.js +100 -0
- package/dist/tools/extract-audio.js +174 -0
- package/dist/tools/extract-frame.js +108 -0
- package/dist/tools/extract-notebook-audio.js +173 -0
- package/dist/tools/extract-notebook-frame.js +160 -0
- package/dist/tools/extract-video-clip.js +101 -0
- package/dist/tools/generate-media.js +157 -0
- package/dist/tools/generation-payload.js +48 -0
- package/dist/tools/get-timeline.js +12 -0
- package/dist/tools/get-watermark-config.js +38 -0
- package/dist/tools/goal.js +644 -0
- package/dist/tools/image-subjects.js +711 -0
- package/dist/tools/index.js +323 -0
- package/dist/tools/inject-first-frame.js +154 -0
- package/dist/tools/invert-image.js +70 -0
- package/dist/tools/isolate-vocals.js +66 -0
- package/dist/tools/list-assets.js +98 -0
- package/dist/tools/list-cell-generations.js +225 -0
- package/dist/tools/list-elevenlabs-voices.js +163 -0
- package/dist/tools/log-wrapper.js +29 -0
- package/dist/tools/make-cover-song.js +95 -0
- package/dist/tools/mark-asset-seen.js +23 -0
- package/dist/tools/media-library.js +245 -0
- package/dist/tools/move-timeline-audio.js +35 -0
- package/dist/tools/music-analysis.js +60 -0
- package/dist/tools/music-draft.js +29 -0
- package/dist/tools/pad-video.js +87 -0
- package/dist/tools/post-record.js +83 -0
- package/dist/tools/post.js +168 -0
- package/dist/tools/prompt-history.js +164 -0
- package/dist/tools/provider-key-status.js +248 -0
- package/dist/tools/qrbtf-render.js +849 -0
- package/dist/tools/read-asset-metadata.js +26 -0
- package/dist/tools/read-file-at-commit.js +29 -0
- package/dist/tools/read-transcript.js +41 -0
- package/dist/tools/reconcile-project-work.js +1452 -0
- package/dist/tools/recover-asset.js +28 -0
- package/dist/tools/remove-sound.js +72 -0
- package/dist/tools/remove-timeline-audio.js +34 -0
- package/dist/tools/remove-timeline-slot.js +40 -0
- package/dist/tools/rename-all.js +434 -0
- package/dist/tools/rename-asset.js +34 -0
- package/dist/tools/render-settings.js +47 -0
- package/dist/tools/render-timeline.js +120 -0
- package/dist/tools/render.js +384 -0
- package/dist/tools/reorder-character-images.js +45 -0
- package/dist/tools/replace-video-audio.js +133 -0
- package/dist/tools/restore-archive-clips.js +209 -0
- package/dist/tools/restore-asset-version.js +37 -0
- package/dist/tools/retry-generation.js +54 -0
- package/dist/tools/reverse-video.js +74 -0
- package/dist/tools/rewrite-prompt.js +388 -0
- package/dist/tools/rewrite-script.js +67 -0
- package/dist/tools/schema-from-apicity.js +66 -0
- package/dist/tools/search-archive.js +150 -0
- package/dist/tools/semantic-search.js +1214 -0
- package/dist/tools/sequence-rhythm.js +43 -0
- package/dist/tools/set-character-metadata.js +84 -0
- package/dist/tools/set-env-secret.js +40 -0
- package/dist/tools/set-osg.js +143 -0
- package/dist/tools/show-folder.js +37 -0
- package/dist/tools/smooth-scene-concat.js +122 -0
- package/dist/tools/splice-video.js +149 -0
- package/dist/tools/split-video.js +202 -0
- package/dist/tools/suggest-cuts.js +45 -0
- package/dist/tools/suggest-sfx.js +43 -0
- package/dist/tools/sync-video-to-audio.js +115 -0
- package/dist/tools/tag-backfill.js +177 -0
- package/dist/tools/timewarp-video.js +85 -0
- package/dist/tools/tool-def.js +1 -0
- package/dist/tools/tool-json-schema.js +116 -0
- package/dist/tools/transcribe.js +90 -0
- package/dist/tools/translate-subtitles.js +59 -0
- package/dist/tools/trim-audio.js +139 -0
- package/dist/tools/trim-video.js +168 -0
- package/dist/tools/update-script.js +25 -0
- package/dist/tools/update-timeline-audio.js +40 -0
- package/dist/tools/upload-file.js +41 -0
- package/dist/tools/verify-x-mentions.js +141 -0
- package/dist/tools/video-editing-command-contract.js +291 -0
- package/dist/tools/video-source-reference.js +30 -0
- package/dist/tools/video-time-input.js +18 -0
- package/dist/tools/videobook-domain.js +2006 -0
- package/dist/tools/wait-for-asset-ready.js +143 -0
- package/dist/tools/workspace-actions.js +54 -0
- package/dist/transcript-projection.js +202 -0
- package/dist/transcript-srt.js +33 -0
- package/dist/upload.js +76 -0
- package/dist/usage-providers.js +25 -0
- package/dist/video-analysis-projection.js +46 -0
- package/dist/video-poster.js +33 -0
- package/dist/video-proxy.js +99 -0
- package/dist/vision-regions.js +111 -0
- package/dist/voice-actions.js +90 -0
- package/dist/voice-audio.js +55 -0
- package/dist/voice-config.js +122 -0
- package/dist/voice-continuation.js +54 -0
- package/dist/voice-contract.js +1 -0
- package/dist/voice-http.js +145 -0
- package/dist/voice-reply-progress.js +55 -0
- package/dist/voice-session.js +992 -0
- package/dist/watermark-badge.js +259 -0
- package/dist/watermark-config.js +111 -0
- package/dist/watermark-handle-position.js +55 -0
- package/dist/watermark-platform.js +15 -0
- package/dist/watermark-timing.js +16 -0
- package/dist/workspace-action-catalog.js +315 -0
- package/dist/workspace-action-contract.js +21 -0
- package/dist/workspace-action-groups.js +98 -0
- package/dist/workspace-action-surfaces.js +7 -0
- package/dist/x/account.js +88 -0
- package/dist/x/authenticated-handle.js +30 -0
- package/dist/x/oauth-flow.js +191 -0
- package/dist/x/post-contract.js +1 -0
- package/dist/x/post-metadata.js +44 -0
- package/dist/x/post-to-x.js +456 -0
- package/dist/x/published-post-cell.js +90 -0
- package/dist/x/x-tokens.js +69 -0
- package/dist/zod-slots.js +334 -0
- package/package.json +92 -4
- package/ui/assets/alive-captions-BWb5nLKj.css +1 -0
- package/ui/assets/alive-captions-DPEr1nKM.js +1 -0
- package/ui/assets/confirm-bodies-D8ouHXKy.js +1 -0
- package/ui/assets/confirm-bodies-DrMhaXC6.css +1 -0
- package/ui/assets/fullscreen-B7nw4YbE.js +1 -0
- package/ui/assets/goal-ui-DK-xTCK0.js +2 -0
- package/ui/assets/goal-ui-DXdUM2KF.css +1 -0
- package/ui/assets/index-DzPAnCUj.css +1 -0
- package/ui/assets/index-kS1905s5.js +37 -0
- package/ui/assets/inspector-MlzQbTVo.js +1 -0
- package/ui/assets/jobs-ui-CoinOWx0.js +1 -0
- package/ui/assets/music-video-Cbe80kmQ.js +1 -0
- package/ui/assets/music-video-DPaiKKEq.css +1 -0
- package/ui/assets/ui-Oirr9VOf.css +1 -0
- package/ui/assets/ui-xo_Y1yQg.js +2 -0
- package/ui/assets/vendor-D2rfiZ5j.css +1 -0
- package/ui/assets/vendor-DfTCWgKm.js +19 -0
- package/ui/assets/vendor-flow-BXbeWxW7.js +7 -0
- package/ui/assets/vendor-flow-BnuhLJ6X.css +1 -0
- package/ui/assets/vendor-icons-CGqhCIXV.js +1 -0
- package/ui/assets/vendor-mcp-BTlEJcHV.js +67 -0
- package/ui/assets/vendor-react-Dj7D1fD4.js +9 -0
- package/ui/assets/vendor-remotion-CH1HXrlc.js +95 -0
- package/ui/assets/videobook-Qlp9HQFu.js +20 -0
- package/ui/favicon.svg +8 -0
- package/ui/index.html +126 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export function sampleEvenly(items, maxSamples) {
|
|
2
|
+
if (maxSamples <= 0)
|
|
3
|
+
return [];
|
|
4
|
+
if (items.length <= maxSamples)
|
|
5
|
+
return items;
|
|
6
|
+
if (maxSamples === 1)
|
|
7
|
+
return [items[0]];
|
|
8
|
+
const sampleStep = (items.length - 1) / (maxSamples - 1);
|
|
9
|
+
return Array.from({ length: maxSamples }, (_, index) => items[Math.round(index * sampleStep)]);
|
|
10
|
+
}
|
|
11
|
+
function calculateFrameSampleCount(durationSeconds) {
|
|
12
|
+
const sampleIntervalSeconds = durationSeconds <= 10 ? 2 : 5;
|
|
13
|
+
const sampleCount = Math.floor(durationSeconds / sampleIntervalSeconds);
|
|
14
|
+
return Math.max(3, Math.min(30, sampleCount));
|
|
15
|
+
}
|
|
16
|
+
export function formatTimestamp(t) {
|
|
17
|
+
return t.toFixed(2);
|
|
18
|
+
}
|
|
19
|
+
export function generateTimestamps(durationSeconds) {
|
|
20
|
+
if (!Number.isFinite(durationSeconds) || durationSeconds <= 0)
|
|
21
|
+
return [];
|
|
22
|
+
const sampleCount = calculateFrameSampleCount(durationSeconds);
|
|
23
|
+
const endMarginSeconds = Math.min(0.1, durationSeconds / sampleCount);
|
|
24
|
+
const lastTimestampSeconds = durationSeconds - endMarginSeconds;
|
|
25
|
+
const sampleStepSeconds = lastTimestampSeconds / (sampleCount - 1);
|
|
26
|
+
return Array.from({ length: sampleCount }, (_, index) => sampleStepSeconds * index);
|
|
27
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function isGenerationCreditError(error) {
|
|
2
|
+
if (!error)
|
|
3
|
+
return false;
|
|
4
|
+
const message = error.toLowerCase().replaceAll(/[_-]+/g, " ");
|
|
5
|
+
return /\b(?:out of|insufficient|not enough|no(?: remaining| more| available)?) credits?\b/.test(message)
|
|
6
|
+
|| /\bcredits? (?:balance )?(?:is |are )?(?:insufficient|exhausted|depleted|too low)\b/.test(message)
|
|
7
|
+
|| /\b(?:insufficient|not enough|low|exhausted) (?:account |credit )?balance\b/.test(message)
|
|
8
|
+
|| /\b(?:account |credit )?balance (?:is )?(?:insufficient|too low|exhausted)\b/.test(message)
|
|
9
|
+
|| /\binsufficient quota\b/.test(message)
|
|
10
|
+
|| /\b(?:exceeds? (?:your|the) (?:remaining |available )?credits?|credits? (?:left|remaining).{0,100}(?:required|requested|needed))\b/.test(message);
|
|
11
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// Generation prompts name their media by input slot, never by grid square:
|
|
2
|
+
// "@image1" is the first connected image input, whatever square it sits in, so
|
|
3
|
+
// moving cells around the grid leaves the prompt untouched. The numbering is
|
|
4
|
+
// the order the server hands media to the provider (image_refs, video_refs,
|
|
5
|
+
// audio_refs), so "@image2" in the prompt and "reference image 2" in the
|
|
6
|
+
// payload always mean the same asset. Frame inputs ride their own params and
|
|
7
|
+
// get their own tokens.
|
|
8
|
+
//
|
|
9
|
+
// Pure and dependency-free: the client imports it for the autocomplete menu
|
|
10
|
+
// and the input cards, the server for prompt resolution.
|
|
11
|
+
const FRAME_TOKENS = {
|
|
12
|
+
first_frame: "firstframe",
|
|
13
|
+
last_frame: "lastframe",
|
|
14
|
+
};
|
|
15
|
+
// Inputs that feed a dedicated provider param and cannot be named inline.
|
|
16
|
+
const UNNAMED_TARGET_INPUTS = new Set(["replace_audio"]);
|
|
17
|
+
const KIND_ORDER = ["image", "video", "audio"];
|
|
18
|
+
function generationInputMediaKind(cellType) {
|
|
19
|
+
if (cellType === "image" || cellType === "generate_image")
|
|
20
|
+
return "image";
|
|
21
|
+
if (cellType === "audio"
|
|
22
|
+
|| cellType === "extract_audio"
|
|
23
|
+
|| cellType === "generate_audio")
|
|
24
|
+
return "audio";
|
|
25
|
+
if (cellType === "video"
|
|
26
|
+
|| cellType === "split_video"
|
|
27
|
+
|| cellType === "generate_video"
|
|
28
|
+
|| cellType === "concat"
|
|
29
|
+
|| cellType === "splice")
|
|
30
|
+
return "video";
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
function numberedKindSlotIndex(targetInput, kind) {
|
|
34
|
+
if (targetInput === kind)
|
|
35
|
+
return 1;
|
|
36
|
+
const prefix = `${kind}_`;
|
|
37
|
+
if (!targetInput.startsWith(prefix))
|
|
38
|
+
return null;
|
|
39
|
+
const suffix = targetInput.slice(prefix.length);
|
|
40
|
+
if (!/^\d+$/.test(suffix))
|
|
41
|
+
return null;
|
|
42
|
+
return Number(suffix);
|
|
43
|
+
}
|
|
44
|
+
/** Stable sort by numbered slot ("image", "image_2", …); unnumbered last. */
|
|
45
|
+
export function sortByKindSlot(entries, kind) {
|
|
46
|
+
return [...entries].sort((left, right) => {
|
|
47
|
+
const leftIndex = numberedKindSlotIndex(left.targetInput, kind)
|
|
48
|
+
?? Number.MAX_SAFE_INTEGER;
|
|
49
|
+
const rightIndex = numberedKindSlotIndex(right.targetInput, kind)
|
|
50
|
+
?? Number.MAX_SAFE_INTEGER;
|
|
51
|
+
return leftIndex - rightIndex;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function connectedInputs(cellId, cells, edges) {
|
|
55
|
+
const cellsById = new Map(cells.map((cell) => [cell.id, cell]));
|
|
56
|
+
return edges.flatMap((edge) => {
|
|
57
|
+
if (edge.target !== cellId)
|
|
58
|
+
return [];
|
|
59
|
+
const source = cellsById.get(edge.source);
|
|
60
|
+
const kind = source ? generationInputMediaKind(source.type) : null;
|
|
61
|
+
return kind
|
|
62
|
+
? [{ kind, sourceCellId: edge.source, targetInput: edge.targetInput }]
|
|
63
|
+
: [];
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function frameMentions(inputs) {
|
|
67
|
+
return Object.entries(FRAME_TOKENS).flatMap(([targetInput, token]) => {
|
|
68
|
+
const input = inputs.find((candidate) => candidate.kind === "image" && candidate.targetInput === targetInput);
|
|
69
|
+
return input ? [{ ...input, token }] : [];
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
function numberedMentions(inputs, kind, modeId) {
|
|
73
|
+
const named = inputs.filter((input) => input.kind === kind
|
|
74
|
+
&& !(modeId !== "r2v" && kind === "image" && input.targetInput in FRAME_TOKENS)
|
|
75
|
+
&& !UNNAMED_TARGET_INPUTS.has(input.targetInput));
|
|
76
|
+
return sortByKindSlot(named, kind).map((input, index) => ({
|
|
77
|
+
...input,
|
|
78
|
+
token: `${kind}${index + 1}`,
|
|
79
|
+
}));
|
|
80
|
+
}
|
|
81
|
+
/** Every prompt-nameable input of a generation cell, in provider order. */
|
|
82
|
+
export function generationInputMentions(cellId, cells, edges, modeId) {
|
|
83
|
+
const configuredMode = cells.find((cell) => cell.id === cellId)?.inputs?.generationMode;
|
|
84
|
+
const effectiveMode = modeId ?? configuredMode;
|
|
85
|
+
const inputs = connectedInputs(cellId, cells, edges);
|
|
86
|
+
return [
|
|
87
|
+
...(effectiveMode === "r2v" ? [] : frameMentions(inputs)),
|
|
88
|
+
...KIND_ORDER.flatMap((kind) => numberedMentions(inputs, kind, typeof effectiveMode === "string" ? effectiveMode : undefined)),
|
|
89
|
+
];
|
|
90
|
+
}
|
|
91
|
+
export function remapGenerationInputPrompt(prompt, previous, next) {
|
|
92
|
+
const used = new Set([...previous, ...next].map((mention) => mention.token));
|
|
93
|
+
const replacements = new Map(previous.map((before) => {
|
|
94
|
+
const after = next.find((candidate) => candidate.sourceCellId === before.sourceCellId
|
|
95
|
+
&& candidate.targetInput === before.targetInput)
|
|
96
|
+
?? next.find((candidate) => candidate.targetInput === before.targetInput);
|
|
97
|
+
if (after)
|
|
98
|
+
return [before.token, after.token];
|
|
99
|
+
if (!next.some((candidate) => candidate.token === before.token))
|
|
100
|
+
return [before.token, before.token];
|
|
101
|
+
let index = 1;
|
|
102
|
+
while (used.has(`${before.kind}${index}`))
|
|
103
|
+
index += 1;
|
|
104
|
+
const missing = `${before.kind}${index}`;
|
|
105
|
+
used.add(missing);
|
|
106
|
+
return [before.token, missing];
|
|
107
|
+
}));
|
|
108
|
+
return prompt.replace(/@((?:image|video|audio)\d+|firstframe|lastframe)(?![\w-])/giu, (match, token) => {
|
|
109
|
+
const replacement = replacements.get(token.toLowerCase());
|
|
110
|
+
return replacement && replacement !== token.toLowerCase() ? `@${replacement}` : match;
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/** "@image1"-style tokens in a prompt, lower-cased and without the "@". */
|
|
114
|
+
export function scanGenerationInputTokens(prompt) {
|
|
115
|
+
return [...prompt.matchAll(/@((?:image|video|audio)\d+|firstframe|lastframe)(?![\w-])/giu)]
|
|
116
|
+
.map((match) => match[1].toLowerCase());
|
|
117
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export function generationModeInputTarget(modeId, kind, target) {
|
|
2
|
+
return modeId === "r2v" && kind === "image"
|
|
3
|
+
&& (target === "first_frame" || target === "last_frame")
|
|
4
|
+
? "image"
|
|
5
|
+
: target;
|
|
6
|
+
}
|
|
7
|
+
function modeInputs(mode, inputs) {
|
|
8
|
+
const normalized = inputs.map((input) => ({
|
|
9
|
+
...input,
|
|
10
|
+
target: generationModeInputTarget(mode.id, input.kind, input.target),
|
|
11
|
+
}));
|
|
12
|
+
if (mode.id !== "i2v" || mode.slots.some((slot) => slot.targets.includes("image"))) {
|
|
13
|
+
return normalized;
|
|
14
|
+
}
|
|
15
|
+
const available = mode.slots.flatMap((slot) => slot.targets)
|
|
16
|
+
.filter((target) => target === "first_frame" || target === "last_frame")
|
|
17
|
+
.filter((target) => !inputs.some((input) => input.target === target));
|
|
18
|
+
let index = 0;
|
|
19
|
+
return normalized.map((input) => {
|
|
20
|
+
if (input.kind !== "image" || input.target !== "image")
|
|
21
|
+
return input;
|
|
22
|
+
const target = available[index++];
|
|
23
|
+
return target ? { ...input, target } : input;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
function inputLabel(target) {
|
|
27
|
+
if (target === "replace_audio")
|
|
28
|
+
return "replacement audio";
|
|
29
|
+
if (target === "first_frame")
|
|
30
|
+
return "first frame";
|
|
31
|
+
if (target === "last_frame")
|
|
32
|
+
return "last frame";
|
|
33
|
+
return `${target} reference`;
|
|
34
|
+
}
|
|
35
|
+
export function generationModeInputError(mode, inputs) {
|
|
36
|
+
const name = mode.id === "default" || mode.id === "text" ? "this model" : mode.id.toUpperCase();
|
|
37
|
+
const subject = name === "this model" ? "This model" : name;
|
|
38
|
+
const counts = new Map(mode.slots.map((slot) => [slot.field, 0]));
|
|
39
|
+
const sorted = modeInputs(mode, inputs).sort((left, right) => Number(right.target !== right.kind) - Number(left.target !== left.kind));
|
|
40
|
+
for (const input of sorted) {
|
|
41
|
+
const matching = mode.slots.filter((slot) => slot.kind === input.kind && slot.targets.includes(input.target));
|
|
42
|
+
if (matching.length === 0) {
|
|
43
|
+
return `${subject} does not accept ${inputLabel(input.target)} inputs. Change the type or remove that input.`;
|
|
44
|
+
}
|
|
45
|
+
const available = matching.filter((slot) => slot.max === null || (counts.get(slot.field) ?? 0) < slot.max)
|
|
46
|
+
.sort((left, right) => {
|
|
47
|
+
const leftRequired = Number((counts.get(left.field) ?? 0) < left.min);
|
|
48
|
+
const rightRequired = Number((counts.get(right.field) ?? 0) < right.min);
|
|
49
|
+
return rightRequired - leftRequired || left.targets.length - right.targets.length;
|
|
50
|
+
});
|
|
51
|
+
const slot = available[0];
|
|
52
|
+
if (!slot) {
|
|
53
|
+
const maximum = matching.reduce((total, candidate) => total + (candidate.max ?? 0), 0);
|
|
54
|
+
return `${subject} accepts at most ${maximum} ${inputLabel(input.target)} input${maximum === 1 ? "" : "s"}. Remove an input or change the model.`;
|
|
55
|
+
}
|
|
56
|
+
counts.set(slot.field, (counts.get(slot.field) ?? 0) + 1);
|
|
57
|
+
}
|
|
58
|
+
const missing = mode.slots.find((slot) => (counts.get(slot.field) ?? 0) < slot.min);
|
|
59
|
+
if (missing) {
|
|
60
|
+
return `Add at least ${missing.min} ${inputLabel(missing.targets[0] ?? missing.kind)} input${missing.min === 1 ? "" : "s"} for ${name}.`;
|
|
61
|
+
}
|
|
62
|
+
const group = mode.requiredGroups.find((fields) => !fields.some((field) => (counts.get(field) ?? 0) > 0));
|
|
63
|
+
if (!group)
|
|
64
|
+
return null;
|
|
65
|
+
const labels = [...new Set(mode.slots.filter((slot) => group.includes(slot.field))
|
|
66
|
+
.flatMap((slot) => slot.targets).map(inputLabel))];
|
|
67
|
+
return `Add at least one ${labels.join(" or ")} input for ${name}.`;
|
|
68
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { normalizeNotebookReference, replaceNotebookMentions, stripNotebookMentions, } from "videobook-engine/notebook-mentions";
|
|
2
|
+
function refMentionEntries(refs) {
|
|
3
|
+
return refs
|
|
4
|
+
.map((raw, index) => ({
|
|
5
|
+
ref: normalizeNotebookReference(raw),
|
|
6
|
+
index,
|
|
7
|
+
}))
|
|
8
|
+
.filter((e) => e.ref !== "")
|
|
9
|
+
.sort((a, b) => b.ref.length - a.ref.length);
|
|
10
|
+
}
|
|
11
|
+
/** Remove "@<ref>" mentions that have no inline marker form (reference video
|
|
12
|
+
* clips, first frames) — the asset still rides its body param. */
|
|
13
|
+
export function stripRefMentions(prompt, refs) {
|
|
14
|
+
return stripNotebookMentions(prompt, refMentionEntries(refs).map(({ ref }) => ref));
|
|
15
|
+
}
|
|
16
|
+
/** Replace "@<ref>" mentions with natural-language noun phrases for Kie
|
|
17
|
+
* happyhorse/video-edit and other free-form prompt models with no inline
|
|
18
|
+
* marker syntax (the "[Image N]" form belongs to happyhorse 1.1 t2v/i2v/ref
|
|
19
|
+
* only). The prompt is a free-form instruction; media rides separate URL
|
|
20
|
+
* fields. Rewrite confirmed @<video-ref> → "the source video", each
|
|
21
|
+
* @<image-ref> → "reference image N" (1-based in imageRefs), and each
|
|
22
|
+
* @<audio-ref> → "reference audio N". Unlisted mentions stay literal. */
|
|
23
|
+
export function replaceHappyHorseAssetMentions(prompt, videoRef, imageRefs, audioRefs = []) {
|
|
24
|
+
const replacements = [];
|
|
25
|
+
if (videoRef) {
|
|
26
|
+
const video = normalizeNotebookReference(videoRef);
|
|
27
|
+
if (video) {
|
|
28
|
+
replacements.push({ reference: video, replacement: "the source video" });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
for (const { ref, index } of refMentionEntries(imageRefs)) {
|
|
32
|
+
replacements.push({
|
|
33
|
+
reference: ref,
|
|
34
|
+
replacement: `reference image ${index + 1}`,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
for (const { ref, index } of refMentionEntries(audioRefs)) {
|
|
38
|
+
replacements.push({
|
|
39
|
+
reference: ref,
|
|
40
|
+
replacement: `reference audio ${index + 1}`,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return replaceNotebookMentions(prompt, replacements);
|
|
44
|
+
}
|
|
45
|
+
/** HappyHorse 1.1 reference-to-video: rewrite confirmed @<image-ref> mentions
|
|
46
|
+
* to positional `[Image N]` markers matching the reference_image[] order. */
|
|
47
|
+
export function rewriteImageRefMentionsToBrackets(prompt, imageRefs) {
|
|
48
|
+
return replaceNotebookMentions(prompt, refMentionEntries(imageRefs).map(({ ref, index }) => ({
|
|
49
|
+
reference: ref,
|
|
50
|
+
replacement: `[Image ${index + 1}]`,
|
|
51
|
+
})));
|
|
52
|
+
}
|
|
53
|
+
/** Seedance r2v: rewrite confirmed asset @refs to `@ImageN` / `@VideoN` /
|
|
54
|
+
* `@AudioN` (1-based, matching upload order in each modality array). */
|
|
55
|
+
export function rewriteSeedanceAssetMentions(prompt, refs) {
|
|
56
|
+
const replacements = [];
|
|
57
|
+
for (const { ref, index } of refMentionEntries(refs.imageRefs ?? [])) {
|
|
58
|
+
replacements.push({ reference: ref, replacement: `@Image${index + 1}` });
|
|
59
|
+
}
|
|
60
|
+
for (const { ref, index } of refMentionEntries(refs.videoRefs ?? [])) {
|
|
61
|
+
replacements.push({ reference: ref, replacement: `@Video${index + 1}` });
|
|
62
|
+
}
|
|
63
|
+
for (const { ref, index } of refMentionEntries(refs.audioRefs ?? [])) {
|
|
64
|
+
replacements.push({ reference: ref, replacement: `@Audio${index + 1}` });
|
|
65
|
+
}
|
|
66
|
+
return replaceNotebookMentions(prompt, replacements);
|
|
67
|
+
}
|
|
68
|
+
export function rewriteViduReferenceMentions(prompt, imageRefs, audioRefs) {
|
|
69
|
+
return replaceNotebookMentions(prompt, [
|
|
70
|
+
...refMentionEntries(imageRefs).map(({ ref, index }) => ({
|
|
71
|
+
reference: ref,
|
|
72
|
+
replacement: `[@reference_image_${index + 1}]`,
|
|
73
|
+
})),
|
|
74
|
+
...refMentionEntries(audioRefs).map(({ ref, index }) => ({
|
|
75
|
+
reference: ref,
|
|
76
|
+
replacement: `[reference_audio_${index + 1}]`,
|
|
77
|
+
})),
|
|
78
|
+
]);
|
|
79
|
+
}
|
|
80
|
+
/** Free-form multi-ref natural rewrite when the provider has no inline marker
|
|
81
|
+
* syntax: videos → "reference video N" (or "the source video" for a single
|
|
82
|
+
* source clip), images → "reference image N", audio → "reference audio N". */
|
|
83
|
+
export function replaceNaturalAssetMentions(prompt, refs) {
|
|
84
|
+
let out = prompt;
|
|
85
|
+
if (refs.sourceVideoRef) {
|
|
86
|
+
out = replaceHappyHorseAssetMentions(out, refs.sourceVideoRef, [], []);
|
|
87
|
+
}
|
|
88
|
+
const multiVideos = refs.videoRefs ?? [];
|
|
89
|
+
out = replaceNotebookMentions(out, refMentionEntries(multiVideos).map(({ ref, index }) => ({
|
|
90
|
+
reference: ref,
|
|
91
|
+
replacement: multiVideos.length === 1
|
|
92
|
+
? "the source video"
|
|
93
|
+
: `reference video ${index + 1}`,
|
|
94
|
+
})));
|
|
95
|
+
out = replaceHappyHorseAssetMentions(out, null, refs.imageRefs ?? [], refs.audioRefs ?? []);
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { resolveNotebookCellArtifactId } from "videobook-engine";
|
|
2
|
+
import { notebookGridTag } from "videobook-engine/notebook-grid";
|
|
3
|
+
import { replaceNotebookMentions, scanNotebookMentions } from "videobook-engine/notebook-mentions";
|
|
4
|
+
import { resolveNotebookPromptReferences } from "./notebook-reference-resolver.js";
|
|
5
|
+
const GOAL_CHARACTER_HELP = "Mention the reference images in the brief, for example /goal @a1 @a2 as ...";
|
|
6
|
+
export function resolveGoalCharacters(engine, document, brief) {
|
|
7
|
+
if (scanNotebookMentions(brief).length === 0)
|
|
8
|
+
throw new Error(GOAL_CHARACTER_HELP);
|
|
9
|
+
const resolved = resolveNotebookPromptReferences({ engine, document, prompt: brief, requireMedia: true });
|
|
10
|
+
if (resolved.unresolved.length > 0)
|
|
11
|
+
throw new Error(resolved.unresolved[0].message);
|
|
12
|
+
const characters = new Map();
|
|
13
|
+
for (const reference of resolved.resolved) {
|
|
14
|
+
const artifact = engine.artifacts.get(reference.artifactId);
|
|
15
|
+
const cell = document.cells.find(candidate => candidate.id === reference.cellId);
|
|
16
|
+
if (!artifact.ok || artifact.value.kind !== "image" || !cell || !["image", "generate_image"].includes(cell.type)) {
|
|
17
|
+
throw new Error(`${reference.mention} is not an image`);
|
|
18
|
+
}
|
|
19
|
+
if (!characters.has(reference.artifactId))
|
|
20
|
+
characters.set(reference.artifactId, {
|
|
21
|
+
artifactId: reference.artifactId, cellId: cell.id, address: notebookGridTag(cell.slot),
|
|
22
|
+
label: artifact.value.label || cell.label || `Character ${characters.size + 1}`,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
if (characters.size === 0)
|
|
26
|
+
throw new Error(GOAL_CHARACTER_HELP);
|
|
27
|
+
if (characters.size > 8)
|
|
28
|
+
throw new Error("A goal supports 1–8 reference images");
|
|
29
|
+
return [...characters.values()];
|
|
30
|
+
}
|
|
31
|
+
export function currentGoalCharacters(document, characters) {
|
|
32
|
+
return characters.map(character => {
|
|
33
|
+
const cell = document.cells.find(candidate => candidate.id === character.cellId);
|
|
34
|
+
if (!cell || resolveNotebookCellArtifactId(document, cell) !== character.artifactId) {
|
|
35
|
+
throw new Error(`Reference image ${character.address} changed or was removed. Start a new /goal.`);
|
|
36
|
+
}
|
|
37
|
+
return { ...character, address: notebookGridTag(cell.slot) };
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
export function goalPlannerBrief(brief, characters, document) {
|
|
41
|
+
const aliases = document?.cells.flatMap(cell => {
|
|
42
|
+
const index = characters.findIndex(character => character.artifactId === resolveNotebookCellArtifactId(document, cell));
|
|
43
|
+
return index < 0 ? [] : [{ reference: notebookGridTag(cell.slot), replacement: `Character ${index + 1}` }];
|
|
44
|
+
}) ?? [];
|
|
45
|
+
return replaceNotebookMentions(brief, [...characters.flatMap((character, index) => [
|
|
46
|
+
{ reference: character.address.slice(1), replacement: `Character ${index + 1}` },
|
|
47
|
+
{ reference: character.artifactId, replacement: `Character ${index + 1}` },
|
|
48
|
+
]), ...aliases]).replace(/(Character \d)(?=Character \d)/gu, "$1 ");
|
|
49
|
+
}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { notebookGridTag } from "videobook-engine/notebook-grid";
|
|
3
|
+
import { goalPromptWords } from "./goal-prompt-budget.js";
|
|
4
|
+
import { LIGHTNING_COLD_OPEN_SECONDS, LIGHTNING_SCENE_ASPECT_RATIO, LIGHTNING_SCENE_MODEL, LIGHTNING_SCENE_OUTPUT_FORMAT, LIGHTNING_SCENE_PROMPT_WORDS, LIGHTNING_SCENE_RESOLUTION, LIGHTNING_VIDEO_DURATION_SECONDS, LIGHTNING_VIDEO_GENERATE_AUDIO, LIGHTNING_VIDEO_OUTPUT_FORMAT, LIGHTNING_VIDEO_PROMPT_WORDS, LIGHTNING_VIDEO_RESOLUTION, LIGHTNING_VIDEO_MODEL, LIGHTNING_WATERMARK_PROFILE, preservedPrompt, } from "./lightning-defaults.js";
|
|
5
|
+
const IMAGE_LIMIT = 30;
|
|
6
|
+
const VIDEO_LIMIT = 10;
|
|
7
|
+
export const goalMediaRefSchema = z.object({
|
|
8
|
+
kind: z.enum(["image", "video"]),
|
|
9
|
+
artifactId: z.string().min(1),
|
|
10
|
+
cellId: z.string().min(1),
|
|
11
|
+
address: z.string().min(1),
|
|
12
|
+
label: z.string(),
|
|
13
|
+
objectHash: z.string().min(1),
|
|
14
|
+
slot: z.string().regex(/^@(?:image|video)\d+$/u),
|
|
15
|
+
}).strict();
|
|
16
|
+
export const goalPlanV3Schema = z.object({
|
|
17
|
+
version: z.literal(3),
|
|
18
|
+
title: z.string().trim().min(1).max(120),
|
|
19
|
+
aspectRatio: z.enum(["16:9", "9:16", "1:1"]),
|
|
20
|
+
scene: z.object({
|
|
21
|
+
prompt: z.string().trim().min(1).max(4000),
|
|
22
|
+
tool: z.literal("generate_image"),
|
|
23
|
+
model: z.literal(LIGHTNING_SCENE_MODEL),
|
|
24
|
+
aspectRatio: z.enum(["16:9", "9:16", "1:1"]),
|
|
25
|
+
resolution: z.literal(LIGHTNING_SCENE_RESOLUTION),
|
|
26
|
+
outputFormat: z.literal(LIGHTNING_SCENE_OUTPUT_FORMAT),
|
|
27
|
+
imageRefs: z.array(goalMediaRefSchema).max(IMAGE_LIMIT),
|
|
28
|
+
}).strict(),
|
|
29
|
+
video: z.object({
|
|
30
|
+
prompt: z.string().trim().min(1).max(4000),
|
|
31
|
+
tool: z.literal("generate_video"),
|
|
32
|
+
model: z.literal(LIGHTNING_VIDEO_MODEL),
|
|
33
|
+
aspectRatio: z.enum(["16:9", "9:16", "1:1", "adaptive"]),
|
|
34
|
+
resolution: z.literal(LIGHTNING_VIDEO_RESOLUTION),
|
|
35
|
+
durationSeconds: z.number().int().min(4).max(30),
|
|
36
|
+
generateAudio: z.literal(true),
|
|
37
|
+
outputFormat: z.literal(LIGHTNING_VIDEO_OUTPUT_FORMAT),
|
|
38
|
+
imageRefs: z.array(goalMediaRefSchema).max(IMAGE_LIMIT),
|
|
39
|
+
videoRefs: z.array(goalMediaRefSchema).max(VIDEO_LIMIT),
|
|
40
|
+
}).strict(),
|
|
41
|
+
references: z.array(goalMediaRefSchema).min(1),
|
|
42
|
+
sampledFrames: z.array(z.object({
|
|
43
|
+
artifactId: z.string().min(1),
|
|
44
|
+
objectHash: z.string().min(1),
|
|
45
|
+
seconds: z.number().nonnegative(),
|
|
46
|
+
}).strict()),
|
|
47
|
+
finish: z.object({
|
|
48
|
+
suggestedColdOpenSeconds: z.number().positive(),
|
|
49
|
+
watermark: z.object({
|
|
50
|
+
platform: z.literal("tiktok"),
|
|
51
|
+
handle: z.string().min(1),
|
|
52
|
+
profileUrl: z.string().min(1),
|
|
53
|
+
mode: z.literal("burn"),
|
|
54
|
+
handleEndSeconds: z.number().nullable(),
|
|
55
|
+
qrLeadSeconds: z.number().nullable(),
|
|
56
|
+
handleOpacity: z.number(),
|
|
57
|
+
qrOpacity: z.number(),
|
|
58
|
+
fadeSeconds: z.number(),
|
|
59
|
+
}).strict(),
|
|
60
|
+
}).strict(),
|
|
61
|
+
}).strict();
|
|
62
|
+
export function isGoalPlanV3(plan) {
|
|
63
|
+
return plan?.version === 3;
|
|
64
|
+
}
|
|
65
|
+
export function closestGoalAspectRatio(width, height) {
|
|
66
|
+
const ratio = Math.log(width / height);
|
|
67
|
+
const candidates = [["16:9", 16 / 9], ["9:16", 9 / 16], ["1:1", 1]];
|
|
68
|
+
return candidates.reduce((best, candidate) => Math.abs(ratio - Math.log(candidate[1])) < Math.abs(ratio - Math.log(best[1])) ? candidate : best)[0];
|
|
69
|
+
}
|
|
70
|
+
function goalV3Timing(brief, fallbackAspectRatio = LIGHTNING_SCENE_ASPECT_RATIO) {
|
|
71
|
+
const aspectRatio = /\b(?:9:16|portrait|vertical)\b/iu.test(brief) ? "9:16"
|
|
72
|
+
: /\b(?:1:1|square)\b/iu.test(brief) ? "1:1"
|
|
73
|
+
: /\b(?:16:9|landscape|horizontal)\b/iu.test(brief) ? "16:9"
|
|
74
|
+
: fallbackAspectRatio;
|
|
75
|
+
const match = /(?:^|\s)(\d+)[ -]*(?:s|secs?|seconds?)\b/iu.exec(brief);
|
|
76
|
+
const parsed = match ? Number(match[1]) : Number.NaN;
|
|
77
|
+
const durationSeconds = Number.isInteger(parsed) && parsed >= 4 && parsed <= 30
|
|
78
|
+
? parsed
|
|
79
|
+
: LIGHTNING_VIDEO_DURATION_SECONDS;
|
|
80
|
+
return { aspectRatio, durationSeconds };
|
|
81
|
+
}
|
|
82
|
+
function briefProse(brief) {
|
|
83
|
+
return brief.replace(/@[a-z0-9]+/giu, " ").replace(/\s+/gu, " ").trim();
|
|
84
|
+
}
|
|
85
|
+
function quoted(brief, label) {
|
|
86
|
+
const specific = new RegExp(`(?:^|\\s)${label}\\s*:\\s*["“]([^"”]+)["”]`, "iu").exec(brief);
|
|
87
|
+
return specific?.[1]?.trim() || null;
|
|
88
|
+
}
|
|
89
|
+
function authoredCopy(brief) {
|
|
90
|
+
const generic = /["“]([^"”]+)["”]/u.exec(brief)?.[1]?.trim() || null;
|
|
91
|
+
return {
|
|
92
|
+
scene: quoted(brief, "scene") ?? quoted(brief, "image") ?? generic,
|
|
93
|
+
video: quoted(brief, "video") ?? quoted(brief, "clip") ?? generic,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function limitedWords(value, maxWords, authored) {
|
|
97
|
+
if (authored)
|
|
98
|
+
return preservedPrompt(value, maxWords, true);
|
|
99
|
+
if (maxWords < 1)
|
|
100
|
+
return "";
|
|
101
|
+
return preservedPrompt(value, maxWords, false);
|
|
102
|
+
}
|
|
103
|
+
function promptWithSlots(body, slots, maxWords, authored) {
|
|
104
|
+
const kept = limitedWords(body, authored ? maxWords : Math.max(0, maxWords - slots.length), authored);
|
|
105
|
+
const prompt = [kept, ...slots].filter(part => part.length > 0).join(" ").trim();
|
|
106
|
+
if (!authored && goalPromptWords(prompt) > maxWords) {
|
|
107
|
+
return [...slots].join(" ");
|
|
108
|
+
}
|
|
109
|
+
return prompt.length > 0 ? prompt : slots.join(" ");
|
|
110
|
+
}
|
|
111
|
+
function framePrompt(body, characterSlots, authored) {
|
|
112
|
+
const instruction = characterSlots.length > 0
|
|
113
|
+
? `Place ${characterSlots.join(" and ")} into @image1, keeping its framing, setting and light.`
|
|
114
|
+
: "Edit @image1, keeping its framing, setting and light.";
|
|
115
|
+
const kept = limitedWords(body, LIGHTNING_SCENE_PROMPT_WORDS - goalPromptWords(instruction), authored);
|
|
116
|
+
return [instruction, kept].filter(part => part.length > 0).join(" ");
|
|
117
|
+
}
|
|
118
|
+
function sceneImageRefs(images, frame) {
|
|
119
|
+
if (!frame)
|
|
120
|
+
return images.slice(0, IMAGE_LIMIT);
|
|
121
|
+
return [frame.reference, ...images].slice(0, IMAGE_LIMIT).map((reference, index) => ({ ...reference, slot: `@image${index + 1}` }));
|
|
122
|
+
}
|
|
123
|
+
function titleFrom(body) {
|
|
124
|
+
const title = body.split(/\s+/u).filter(Boolean).slice(0, 6).join(" ").slice(0, 80).trim();
|
|
125
|
+
return title.length > 0 ? title : "Video";
|
|
126
|
+
}
|
|
127
|
+
function assignSlots(references) {
|
|
128
|
+
let images = 0;
|
|
129
|
+
let videos = 0;
|
|
130
|
+
return references.map(reference => {
|
|
131
|
+
const slot = reference.kind === "video" ? `@video${++videos}` : `@image${++images}`;
|
|
132
|
+
return { ...reference, slot };
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
export function buildGoalPlanV3(input) {
|
|
136
|
+
const references = assignSlots(input.references);
|
|
137
|
+
const images = references.filter(reference => reference.kind === "image");
|
|
138
|
+
const videos = references.filter(reference => reference.kind === "video");
|
|
139
|
+
const timing = goalV3Timing(input.brief, input.frame?.aspectRatio);
|
|
140
|
+
const copy = authoredCopy(input.brief);
|
|
141
|
+
const prose = briefProse(input.brief);
|
|
142
|
+
const sceneBody = copy.scene ?? prose;
|
|
143
|
+
const videoBody = copy.video ?? prose;
|
|
144
|
+
const sceneRefs = sceneImageRefs(images, input.frame);
|
|
145
|
+
const videoSlots = [...images.slice(0, IMAGE_LIMIT), ...videos.slice(0, VIDEO_LIMIT)].map(reference => reference.slot);
|
|
146
|
+
const scenePrompt = input.frame
|
|
147
|
+
? framePrompt(sceneBody, sceneRefs.slice(1).map(reference => reference.slot), copy.scene !== null)
|
|
148
|
+
: promptWithSlots(sceneBody, sceneRefs.map(reference => reference.slot), LIGHTNING_SCENE_PROMPT_WORDS, copy.scene !== null);
|
|
149
|
+
const videoPrompt = promptWithSlots(videoBody, videoSlots, LIGHTNING_VIDEO_PROMPT_WORDS, copy.video !== null);
|
|
150
|
+
const profile = LIGHTNING_WATERMARK_PROFILE;
|
|
151
|
+
return goalPlanV3Schema.parse({
|
|
152
|
+
version: 3,
|
|
153
|
+
title: titleFrom(sceneBody || videoBody),
|
|
154
|
+
aspectRatio: timing.aspectRatio,
|
|
155
|
+
scene: {
|
|
156
|
+
prompt: scenePrompt,
|
|
157
|
+
tool: "generate_image",
|
|
158
|
+
model: LIGHTNING_SCENE_MODEL,
|
|
159
|
+
aspectRatio: timing.aspectRatio,
|
|
160
|
+
resolution: LIGHTNING_SCENE_RESOLUTION,
|
|
161
|
+
outputFormat: LIGHTNING_SCENE_OUTPUT_FORMAT,
|
|
162
|
+
imageRefs: sceneRefs,
|
|
163
|
+
},
|
|
164
|
+
video: {
|
|
165
|
+
prompt: videoPrompt,
|
|
166
|
+
tool: "generate_video",
|
|
167
|
+
model: LIGHTNING_VIDEO_MODEL,
|
|
168
|
+
aspectRatio: timing.aspectRatio,
|
|
169
|
+
resolution: LIGHTNING_VIDEO_RESOLUTION,
|
|
170
|
+
durationSeconds: timing.durationSeconds,
|
|
171
|
+
generateAudio: LIGHTNING_VIDEO_GENERATE_AUDIO,
|
|
172
|
+
outputFormat: LIGHTNING_VIDEO_OUTPUT_FORMAT,
|
|
173
|
+
imageRefs: images.slice(0, IMAGE_LIMIT),
|
|
174
|
+
videoRefs: videos.slice(0, VIDEO_LIMIT),
|
|
175
|
+
},
|
|
176
|
+
references,
|
|
177
|
+
sampledFrames: input.frame
|
|
178
|
+
? [{ artifactId: input.frame.reference.artifactId, objectHash: input.frame.reference.objectHash, seconds: input.frame.seconds }]
|
|
179
|
+
: [],
|
|
180
|
+
finish: {
|
|
181
|
+
suggestedColdOpenSeconds: LIGHTNING_COLD_OPEN_SECONDS,
|
|
182
|
+
watermark: {
|
|
183
|
+
platform: "tiktok",
|
|
184
|
+
handle: profile.handle,
|
|
185
|
+
profileUrl: profile.profileUrl,
|
|
186
|
+
mode: "burn",
|
|
187
|
+
handleEndSeconds: profile.handleEndSeconds,
|
|
188
|
+
qrLeadSeconds: profile.qrLeadSeconds,
|
|
189
|
+
handleOpacity: profile.handleOpacity,
|
|
190
|
+
qrOpacity: profile.qrOpacity,
|
|
191
|
+
fadeSeconds: profile.fadeSeconds,
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
function liveAddress(document, reference) {
|
|
197
|
+
const cell = document.cells.find(candidate => candidate.id === reference.cellId);
|
|
198
|
+
return cell ? { ...reference, address: notebookGridTag(cell.slot) } : reference;
|
|
199
|
+
}
|
|
200
|
+
export function refreshGoalPlanV3(plan, document) {
|
|
201
|
+
const map = (reference) => liveAddress(document, reference);
|
|
202
|
+
return {
|
|
203
|
+
...plan,
|
|
204
|
+
references: plan.references.map(map),
|
|
205
|
+
scene: { ...plan.scene, imageRefs: plan.scene.imageRefs.map(map) },
|
|
206
|
+
video: {
|
|
207
|
+
...plan.video,
|
|
208
|
+
imageRefs: plan.video.imageRefs.map(map),
|
|
209
|
+
videoRefs: plan.video.videoRefs.map(map),
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
function refList(params, role) {
|
|
214
|
+
const refs = params.refs;
|
|
215
|
+
const list = refs?.[role];
|
|
216
|
+
return Array.isArray(list) ? list.filter((entry) => typeof entry === "string") : [];
|
|
217
|
+
}
|
|
218
|
+
function withRefs(params, images, videos) {
|
|
219
|
+
const refs = {
|
|
220
|
+
...(images.length > 0 ? { image: [...images] } : {}),
|
|
221
|
+
...(videos.length > 0 ? { video: [...videos] } : {}),
|
|
222
|
+
};
|
|
223
|
+
const { refs: _previous, mode: _mode, ...rest } = params;
|
|
224
|
+
return Object.keys(refs).length > 0 ? { ...rest, refs, ...(params.mode ? { mode: params.mode } : {}) } : rest;
|
|
225
|
+
}
|
|
226
|
+
export function compileGoalV3Approval(plan, stage, sceneAddress) {
|
|
227
|
+
const [scene, video] = compileGoalV3Steps(plan);
|
|
228
|
+
if (stage === "frame")
|
|
229
|
+
return { ...scene, params: withRefs(scene.params, refList(scene.params, "image"), []) };
|
|
230
|
+
const imageRefs = [...new Set([...(sceneAddress ? [sceneAddress] : []), ...refList(video.params, "image")])];
|
|
231
|
+
return { ...video, params: withRefs(video.params, imageRefs, refList(video.params, "video")) };
|
|
232
|
+
}
|
|
233
|
+
export function compileGoalV3Steps(plan) {
|
|
234
|
+
const sceneRefs = plan.scene.imageRefs.slice(0, IMAGE_LIMIT);
|
|
235
|
+
const videoImages = plan.video.imageRefs.slice(0, IMAGE_LIMIT);
|
|
236
|
+
const videoRefs = plan.video.videoRefs.slice(0, VIDEO_LIMIT);
|
|
237
|
+
return [
|
|
238
|
+
{
|
|
239
|
+
id: "scene",
|
|
240
|
+
tool: plan.scene.tool,
|
|
241
|
+
params: {
|
|
242
|
+
model: plan.scene.model,
|
|
243
|
+
prompt: plan.scene.prompt,
|
|
244
|
+
refs: { image: sceneRefs.map(reference => reference.address) },
|
|
245
|
+
options: {
|
|
246
|
+
aspect_ratio: plan.scene.aspectRatio,
|
|
247
|
+
resolution: plan.scene.resolution,
|
|
248
|
+
output_format: plan.scene.outputFormat,
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
id: "video",
|
|
254
|
+
tool: plan.video.tool,
|
|
255
|
+
params: {
|
|
256
|
+
model: plan.video.model,
|
|
257
|
+
prompt: plan.video.prompt,
|
|
258
|
+
refs: {
|
|
259
|
+
image: videoImages.map(reference => reference.address),
|
|
260
|
+
video: videoRefs.map(reference => reference.address),
|
|
261
|
+
},
|
|
262
|
+
...(videoImages.length + videoRefs.length > 0 ? { mode: "r2v" } : {}),
|
|
263
|
+
options: {
|
|
264
|
+
aspect_ratio: plan.video.aspectRatio,
|
|
265
|
+
resolution: plan.video.resolution,
|
|
266
|
+
duration: plan.video.durationSeconds,
|
|
267
|
+
generate_audio: plan.video.generateAudio,
|
|
268
|
+
output_format: plan.video.outputFormat,
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
];
|
|
273
|
+
}
|