videobook 0.0.0-stage → 0.2.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 +54 -0
- package/LICENSE +21 -0
- package/README.md +195 -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 +242 -0
- package/dist/cli/config-command.js +103 -0
- package/dist/cli/doctor-command.js +289 -0
- package/dist/cli/entry.js +2 -0
- package/dist/cli/key-report.js +16 -0
- package/dist/cli/main.js +104 -0
- package/dist/cli/mcp-command.js +88 -0
- package/dist/cli/mcp-relay.js +51 -0
- package/dist/cli/open-browser.js +14 -0
- package/dist/cli/run-command.js +231 -0
- package/dist/cli/serve-command.js +62 -0
- package/dist/cli/setup-command.js +60 -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 +447 -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-file.js +91 -0
- package/dist/env-secrets.js +148 -0
- package/dist/ffmpeg-binary.js +12 -0
- package/dist/ffmpeg.js +425 -0
- package/dist/ffprobe-binary.js +77 -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/hydration.js +56 -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 +458 -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 +427 -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 +12 -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/one-password.js +200 -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 +810 -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 +125 -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 +2021 -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/ytdlp-binary.js +65 -0
- package/dist/zod-slots.js +334 -0
- package/package.json +84 -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,216 @@
|
|
|
1
|
+
import { markDescendantsStale } from "./notebook-action-catalog.js";
|
|
2
|
+
import { mutateNotebook } from "./notebook-mutations.js";
|
|
3
|
+
import { removeArtifactFromTimeline } from "./tools/delete-asset.js";
|
|
4
|
+
const CELL_INPUT_ARTIFACT_KEYS = [
|
|
5
|
+
"firstFrameArtifactId",
|
|
6
|
+
"lastFrameArtifactId",
|
|
7
|
+
"providerArtifactId",
|
|
8
|
+
];
|
|
9
|
+
function isString(value) {
|
|
10
|
+
return typeof value === "string" && value.length > 0;
|
|
11
|
+
}
|
|
12
|
+
function inputVersionIds(inputs) {
|
|
13
|
+
return Array.isArray(inputs.outputVersionArtifactIds)
|
|
14
|
+
? inputs.outputVersionArtifactIds.filter(isString)
|
|
15
|
+
: [];
|
|
16
|
+
}
|
|
17
|
+
function cellHoldsArtifact(cell, artifactId) {
|
|
18
|
+
const inputs = cell.inputs ?? {};
|
|
19
|
+
return cell.outputArtifactId === artifactId
|
|
20
|
+
|| (cell.references ?? []).some((reference) => reference.targetId === artifactId)
|
|
21
|
+
|| (cell.pinnedResults ?? []).some((pinned) => pinned.artifactId === artifactId)
|
|
22
|
+
|| CELL_INPUT_ARTIFACT_KEYS.some((key) => inputs[key] === artifactId)
|
|
23
|
+
|| inputVersionIds(inputs).includes(artifactId);
|
|
24
|
+
}
|
|
25
|
+
function detachedInputs(cell, artifactId) {
|
|
26
|
+
const inputs = { ...(cell.inputs ?? {}) };
|
|
27
|
+
for (const key of CELL_INPUT_ARTIFACT_KEYS) {
|
|
28
|
+
if (inputs[key] === artifactId)
|
|
29
|
+
delete inputs[key];
|
|
30
|
+
}
|
|
31
|
+
if (Array.isArray(inputs.outputVersionArtifactIds)) {
|
|
32
|
+
inputs.outputVersionArtifactIds = inputVersionIds(inputs)
|
|
33
|
+
.filter((id) => id !== artifactId);
|
|
34
|
+
}
|
|
35
|
+
if (cell.outputArtifactId === artifactId)
|
|
36
|
+
inputs.state = "ready";
|
|
37
|
+
return inputs;
|
|
38
|
+
}
|
|
39
|
+
function detachedCell(cell, artifactId) {
|
|
40
|
+
const references = (cell.references ?? [])
|
|
41
|
+
.filter((reference) => reference.targetId !== artifactId);
|
|
42
|
+
const pinnedResults = (cell.pinnedResults ?? [])
|
|
43
|
+
.filter((pinned) => pinned.artifactId !== artifactId);
|
|
44
|
+
return {
|
|
45
|
+
...cell,
|
|
46
|
+
...(cell.outputArtifactId === artifactId ? { outputArtifactId: undefined } : {}),
|
|
47
|
+
inputs: detachedInputs(cell, artifactId),
|
|
48
|
+
...(cell.references ? { references } : {}),
|
|
49
|
+
...(cell.pinnedResults ? { pinnedResults } : {}),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** A cleared cell reads as never run, so a re-run refills it. */
|
|
53
|
+
function detachedExecution(document, cellIds) {
|
|
54
|
+
const execution = { ...(document.execution ?? {}) };
|
|
55
|
+
for (const cellId of cellIds) {
|
|
56
|
+
const current = execution[cellId];
|
|
57
|
+
if (!current || typeof current !== "object")
|
|
58
|
+
continue;
|
|
59
|
+
execution[cellId] = {
|
|
60
|
+
...current,
|
|
61
|
+
status: "ready",
|
|
62
|
+
stale: false,
|
|
63
|
+
outputArtifactId: undefined,
|
|
64
|
+
providerArtifactId: undefined,
|
|
65
|
+
error: undefined,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return execution;
|
|
69
|
+
}
|
|
70
|
+
function detachedDocument(document, artifactId) {
|
|
71
|
+
const cellIds = document.cells
|
|
72
|
+
.filter((cell) => cellHoldsArtifact(cell, artifactId))
|
|
73
|
+
.map((cell) => cell.id);
|
|
74
|
+
if (cellIds.length === 0)
|
|
75
|
+
return { document, cellIds };
|
|
76
|
+
const detached = {
|
|
77
|
+
...document,
|
|
78
|
+
cells: document.cells.map((cell) => cellIds.includes(cell.id) ? detachedCell(cell, artifactId) : cell),
|
|
79
|
+
execution: detachedExecution(document, cellIds),
|
|
80
|
+
};
|
|
81
|
+
return {
|
|
82
|
+
document: cellIds.reduce((next, cellId) => markDescendantsStale(next, cellId), detached),
|
|
83
|
+
cellIds,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
async function detachFromNotebooks(engine, artifactId) {
|
|
87
|
+
let cleared = 0;
|
|
88
|
+
for (const notebook of engine.notebooks.list()) {
|
|
89
|
+
if (!notebook.cells.some((cell) => cellHoldsArtifact(cell, artifactId))) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
let cellIds = [];
|
|
93
|
+
const result = await mutateNotebook(engine, notebook.id, "forget_asset", (document) => {
|
|
94
|
+
const detached = detachedDocument(document, artifactId);
|
|
95
|
+
cellIds = detached.cellIds;
|
|
96
|
+
return detached.document;
|
|
97
|
+
}, { artifactId }, { artifactId });
|
|
98
|
+
if (!result.ok)
|
|
99
|
+
throw new Error(result.error.message);
|
|
100
|
+
cleared += cellIds.length;
|
|
101
|
+
}
|
|
102
|
+
return cleared;
|
|
103
|
+
}
|
|
104
|
+
function referencesOf(details) {
|
|
105
|
+
const references = details?.references;
|
|
106
|
+
if (!Array.isArray(references))
|
|
107
|
+
return [];
|
|
108
|
+
return references.flatMap((entry) => {
|
|
109
|
+
if (typeof entry !== "object" || entry === null)
|
|
110
|
+
return [];
|
|
111
|
+
const row = entry;
|
|
112
|
+
return isString(row.kind) && isString(row.id)
|
|
113
|
+
? [{ kind: row.kind, id: row.id }]
|
|
114
|
+
: [];
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
function remainingForgetReferences(engine, artifactId) {
|
|
118
|
+
const references = engine.artifacts.deletionReferences(artifactId, { deleteOwnedMedia: true });
|
|
119
|
+
if (!references.ok)
|
|
120
|
+
throw new Error(references.error.message);
|
|
121
|
+
const clearable = new Set(engine.sequences.getPrimary().clips
|
|
122
|
+
.filter((clip) => clip.source.artifactId === artifactId).map((clip) => `sequenceClip:${clip.clipId}`));
|
|
123
|
+
for (const notebook of engine.notebooks.list()) {
|
|
124
|
+
for (const cell of notebook.cells) {
|
|
125
|
+
const cellId = `${notebook.id}/${cell.id}`;
|
|
126
|
+
if (cell.outputArtifactId === artifactId)
|
|
127
|
+
clearable.add(`cell.outputArtifact:${cellId}`);
|
|
128
|
+
for (const reference of cell.references ?? []) {
|
|
129
|
+
if (reference.targetId === artifactId)
|
|
130
|
+
clearable.add(`cell.reference:${cellId}/${reference.id}`);
|
|
131
|
+
}
|
|
132
|
+
for (const result of cell.pinnedResults ?? []) {
|
|
133
|
+
if (result.artifactId === artifactId)
|
|
134
|
+
clearable.add(`pinnedSearchResult:${cellId}/${result.id}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return references.value.filter((reference) => !clearable.has(`${reference.kind}:${reference.id}`));
|
|
139
|
+
}
|
|
140
|
+
function inUseOutcome(artifactId, label, references, clearedCells = 0) {
|
|
141
|
+
return { status: "in_use", artifactId, label, references, clearedCells,
|
|
142
|
+
forgottenObjects: 0, sharedObjects: 0, reclaimedBytes: 0 };
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Deletes an artifact and destroys the bytes behind it.
|
|
146
|
+
*
|
|
147
|
+
* `engine.artifacts.delete` clears the catalog rows and the workspace copy,
|
|
148
|
+
* but the content objects survive — that is what makes a duplicate import
|
|
149
|
+
* free and an old revision restorable. Forgetting finishes the job through
|
|
150
|
+
* `storage.deleteObject`, which is left unforced on purpose: an object another
|
|
151
|
+
* artifact still references is kept, so forgetting one copy of shared bytes
|
|
152
|
+
* never blanks the other.
|
|
153
|
+
*/
|
|
154
|
+
export async function forgetAsset(engine, input) {
|
|
155
|
+
const artifact = engine.artifacts.get(input.assetId);
|
|
156
|
+
if (!artifact.ok)
|
|
157
|
+
throw new Error(artifact.error.message);
|
|
158
|
+
const artifactId = artifact.value.artifactId;
|
|
159
|
+
const label = artifact.value.label ?? null;
|
|
160
|
+
if (input.clearReferences) {
|
|
161
|
+
const blockers = remainingForgetReferences(engine, artifactId);
|
|
162
|
+
if (blockers.length > 0)
|
|
163
|
+
return inUseOutcome(artifactId, label, blockers);
|
|
164
|
+
const timeline = await removeArtifactFromTimeline(engine, artifactId, { dryRun: true });
|
|
165
|
+
if (timeline.error)
|
|
166
|
+
throw new Error(timeline.error);
|
|
167
|
+
}
|
|
168
|
+
const manifest = await engine.files.manifest(artifactId, { includeDotfiles: true });
|
|
169
|
+
const hashes = [...new Set(manifest.ok ? manifest.value.files.map((file) => file.objectHash) : [])];
|
|
170
|
+
const clearedCells = input.clearReferences
|
|
171
|
+
? await detachFromNotebooks(engine, artifactId)
|
|
172
|
+
: 0;
|
|
173
|
+
if (input.clearReferences) {
|
|
174
|
+
const timeline = await removeArtifactFromTimeline(engine, artifactId);
|
|
175
|
+
if (timeline.error)
|
|
176
|
+
throw new Error(timeline.error);
|
|
177
|
+
}
|
|
178
|
+
const deleted = await engine.artifacts.delete(artifactId, {
|
|
179
|
+
deleteOwnedMedia: true,
|
|
180
|
+
});
|
|
181
|
+
if (!deleted.ok) {
|
|
182
|
+
if (deleted.error.code !== "IN_USE")
|
|
183
|
+
throw new Error(deleted.error.message);
|
|
184
|
+
return inUseOutcome(artifactId, label, referencesOf(deleted.error.details), clearedCells);
|
|
185
|
+
}
|
|
186
|
+
let forgottenObjects = 0;
|
|
187
|
+
let sharedObjects = 0;
|
|
188
|
+
let reclaimedBytes = 0;
|
|
189
|
+
for (const hash of hashes) {
|
|
190
|
+
const result = await engine.storage.deleteObject(hash);
|
|
191
|
+
if (result.ok) {
|
|
192
|
+
forgottenObjects += 1;
|
|
193
|
+
if (result.value.deletedLocal)
|
|
194
|
+
reclaimedBytes += result.value.sizeBytes;
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
// Bytes another artifact stores, or an object row that never existed.
|
|
198
|
+
if (result.error.code === "IN_USE") {
|
|
199
|
+
sharedObjects += 1;
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
if (result.error.code === "NOT_FOUND")
|
|
203
|
+
continue;
|
|
204
|
+
throw new Error(result.error.message);
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
status: "forgotten",
|
|
208
|
+
artifactId,
|
|
209
|
+
label,
|
|
210
|
+
references: [],
|
|
211
|
+
clearedCells,
|
|
212
|
+
forgottenObjects,
|
|
213
|
+
sharedObjects,
|
|
214
|
+
reclaimedBytes,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
@@ -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
|
+
}
|