@gentbajko/slopify 2.5.0 → 3.0.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/LICENSE +201 -21
- package/NOTICE +12 -0
- package/README.md +21 -40
- package/SUBTITLES.md +1 -1
- package/dist/adapter-registry.js +3 -0
- package/dist/adapters/alignment/cache.js +4 -1
- package/dist/adapters/alignment/ctc.js +25 -23
- package/dist/adapters/alignment/index.js +37 -6
- package/dist/adapters/alignment/multilingual.js +267 -0
- package/dist/adapters/alignment/protocol.js +11 -0
- package/dist/adapters/alignment/quality.js +4 -3
- package/dist/adapters/alignment/sentences.js +95 -0
- package/dist/adapters/alignment/spec.js +24 -0
- package/dist/adapters/alignment/spell.js +769 -0
- package/dist/adapters/alignment/text.js +56 -9
- package/dist/adapters/alignment/window.js +34 -30
- package/dist/adapters/alignment/worker.js +23 -21
- package/dist/adapters/explain.js +11 -11
- package/dist/adapters/host-cli/index.js +44 -5
- package/dist/adapters/host-cli/transport.js +7 -5
- package/dist/adapters/image/bytes.js +2 -2
- package/dist/adapters/image/codex-output.js +1 -1
- package/dist/adapters/image/codex.js +87 -22
- package/dist/adapters/image/fal.js +13 -5
- package/dist/adapters/image/google.js +11 -8
- package/dist/adapters/image/openai.js +14 -7
- package/dist/adapters/image/reference.js +34 -0
- package/dist/adapters/image/replicate.js +7 -2
- package/dist/adapters/image/video.js +2 -2
- package/dist/adapters/key-probes.js +36 -0
- package/dist/adapters/llm/claude-code.js +168 -32
- package/dist/adapters/llm/cli-login-error.js +1 -1
- package/dist/adapters/llm/codex-limits.js +157 -0
- package/dist/adapters/llm/codex.js +99 -12
- package/dist/adapters/llm/document-workspace.js +2 -2
- package/dist/adapters/llm/gemini-workspace.js +1 -1
- package/dist/adapters/llm/gemini.js +16 -3
- package/dist/adapters/llm/image-workspace.js +58 -0
- package/dist/adapters/llm/openrouter.js +11 -3
- package/dist/adapters/llm/run-cli.js +12 -7
- package/dist/adapters/tts/cartesia.js +10 -0
- package/dist/adapters/tts/elevenlabs.js +31 -9
- package/dist/adapters/tts/inworld-async.js +9 -5
- package/dist/adapters/tts/inworld.js +17 -3
- package/dist/adapters/tts/openai.js +3 -0
- package/dist/adapters/tts/voice-languages.js +80 -0
- package/dist/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
- package/dist/assets/fonts/noto/NotoSansArabic-Regular.ttf +0 -0
- package/dist/assets/fonts/noto/NotoSansDevanagari-Regular.ttf +0 -0
- package/dist/assets/fonts/noto/NotoSansHebrew-Regular.ttf +0 -0
- package/dist/assets/fonts/noto/NotoSansThai-Regular.ttf +0 -0
- package/dist/assets/fonts/noto/OFL.txt +93 -0
- package/dist/assets/fonts/noto/SOURCE.txt +18 -0
- package/dist/assets/sample/sample-audiobook.tar +0 -0
- package/dist/assets/sample/sample-podcast.tar +0 -0
- package/dist/assets/sample/sample-project.tar +0 -0
- package/dist/catalog/merge.js +132 -0
- package/dist/catalog/registry.js +13 -13
- package/dist/catalog/schema.js +2 -0
- package/dist/catalog/store.js +147 -8
- package/dist/compose.yaml +71 -0
- package/dist/edge/autostart/docker-record.js +32 -0
- package/dist/edge/autostart/docker.js +50 -0
- package/dist/edge/autostart/index.js +78 -0
- package/dist/edge/autostart/launcher.js +176 -0
- package/dist/edge/autostart/model.js +3 -0
- package/dist/edge/autostart/native.js +210 -0
- package/dist/edge/autostart/prompt.js +66 -0
- package/dist/edge/autostart/service.js +81 -0
- package/dist/edge/cli.js +57 -51
- package/dist/edge/docker-install/activation.js +56 -0
- package/dist/edge/docker-install/apply.js +458 -0
- package/dist/edge/docker-install/engine.js +362 -0
- package/dist/edge/docker-install/run.js +154 -0
- package/dist/edge/docker-install/state.js +146 -0
- package/dist/edge/{docker-projects → docker-install}/volume.js +1 -5
- package/dist/edge/docker.js +14 -22
- package/dist/edge/host-cli.js +1 -1
- package/dist/edge/http/actions.js +32 -10
- package/dist/edge/http/app.js +58 -2
- package/dist/edge/http/auditions.js +70 -0
- package/dist/edge/http/autostart.js +37 -0
- package/dist/edge/http/channel-memory.js +92 -0
- package/dist/edge/http/channels.js +128 -0
- package/dist/edge/http/entries.js +22 -3
- package/dist/edge/http/files.js +1 -1
- package/dist/edge/http/folder-location.js +1 -1
- package/dist/edge/http/home.js +39 -0
- package/dist/edge/http/host-cli.js +29 -5
- package/dist/edge/http/narration-peaks.js +76 -0
- package/dist/edge/http/onboarding.js +152 -0
- package/dist/edge/http/open-folder.js +1 -1
- package/dist/edge/http/patch-notes.js +45 -0
- package/dist/edge/http/planning.js +4 -2
- package/dist/edge/http/project-create.js +87 -0
- package/dist/edge/http/projects.js +31 -99
- package/dist/edge/http/prompts.js +40 -3
- package/dist/edge/http/pronunciations.js +23 -4
- package/dist/edge/http/providers.js +86 -0
- package/dist/edge/http/reviews.js +121 -0
- package/dist/edge/http/revision-files.js +1 -1
- package/dist/edge/http/revisions.js +1 -1
- package/dist/edge/http/run-cost.js +25 -0
- package/dist/edge/http/schedules.js +111 -6
- package/dist/edge/http/settings.js +84 -6
- package/dist/edge/http/storage-files.js +50 -0
- package/dist/edge/http/storage.js +29 -2
- package/dist/edge/http/studio.js +207 -0
- package/dist/edge/http/style-preview.js +100 -0
- package/dist/edge/http/subtitles.js +1 -1
- package/dist/edge/http/trash.js +69 -0
- package/dist/edge/http/update.js +24 -3
- package/dist/edge/http/whats-new.js +15 -0
- package/dist/edge/http/youtube-edits.js +83 -0
- package/dist/edge/native-update.js +62 -0
- package/dist/host-cli/open-folder.js +10 -10
- package/dist/host-cli/runtime.js +9 -1
- package/dist/kernel/db/migrations/0025-automatic-reviews.sql +40 -0
- package/dist/kernel/db/migrations/0026-schedule-topic-generation.sql +23 -0
- package/dist/kernel/db/migrations/0027-run-cost.sql +58 -0
- package/dist/kernel/db/migrations/0030-automatic-retries.sql +18 -0
- package/dist/kernel/db/migrations/0031-prompt-history-and-description-edits.sql +33 -0
- package/dist/kernel/db/migrations/0032-channels.sql +65 -0
- package/dist/kernel/db/migrations/0034-script-prompts.sql +23 -0
- package/dist/kernel/db/migrations/0035-narration-aliases.sql +13 -0
- package/dist/kernel/db/migrations/0037-project-uploads.sql +8 -0
- package/dist/kernel/db/migrations/0038-voice-languages.sql +7 -0
- package/dist/kernel/db/migrations/0039-channel-essentials.sql +64 -0
- package/dist/kernel/db/migrations/0040-standalone-usage.sql +35 -0
- package/dist/kernel/paths.js +27 -6
- package/dist/kernel/pipeline.js +4 -1
- package/dist/kernel/ports/host-cli.js +122 -14
- package/dist/kernel/ports/key-probe.js +1 -0
- package/dist/kernel/ports/languages.js +157 -0
- package/dist/kernel/ports/model.js +5 -2
- package/dist/kernel/ports/narration-aliases.js +60 -0
- package/dist/kernel/ports/plan-limits.js +36 -0
- package/dist/kernel/runner/attempt.js +17 -8
- package/dist/kernel/runner/audition.js +36 -0
- package/dist/kernel/runner/graph.js +24 -5
- package/dist/kernel/runner/index.js +35 -5
- package/dist/kernel/runner/meter.js +1 -0
- package/dist/kernel/runner/providers.js +142 -7
- package/dist/kernel/runner/retry-policy.js +43 -0
- package/dist/kernel/runner/standalone.js +134 -0
- package/dist/kernel/runner/work-authority.js +28 -2
- package/dist/main.js +272 -16
- package/dist/patch-notes/0.4.2-to-1.0.md +93 -0
- package/dist/patch-notes/1.0-to-2.0.md +74 -0
- package/dist/patch-notes/2.0-to-3.0.md +257 -0
- package/dist/patch-notes/3.0.0.md +70 -0
- package/dist/patch-notes/index.json +26 -0
- package/dist/slices/admission/model.js +27 -0
- package/dist/slices/admission/repo.js +24 -4
- package/dist/slices/admission/rules.js +79 -1
- package/dist/slices/admission/schema.js +58 -1
- package/dist/slices/admission/short-mode.js +47 -0
- package/dist/slices/admission/start.js +41 -5
- package/dist/slices/article/continuation.js +2 -2
- package/dist/slices/article/provided-entries.js +2 -2
- package/dist/slices/article/run.js +6 -2
- package/dist/slices/article/segments.js +3 -3
- package/dist/slices/backups/folder.js +14 -6
- package/dist/slices/batch/index.js +7 -2
- package/dist/slices/cancel/index.js +1 -1
- package/dist/slices/channels/cast-images.js +110 -0
- package/dist/slices/channels/cast-match.js +32 -0
- package/dist/slices/channels/images.js +19 -0
- package/dist/slices/channels/model.js +5 -0
- package/dist/slices/channels/rebrand.js +100 -0
- package/dist/slices/channels/repo.js +218 -0
- package/dist/slices/channels/runs.js +129 -0
- package/dist/slices/channels/schema.js +129 -0
- package/dist/slices/channels/service.js +180 -0
- package/dist/slices/channels/studio-csv.js +110 -0
- package/dist/slices/channels/videos.js +120 -0
- package/dist/slices/checkpoints/recovery.js +10 -0
- package/dist/slices/control/index.js +2 -1
- package/dist/slices/document/fonts.js +1 -1
- package/dist/slices/document/render.js +1 -1
- package/dist/slices/episodes/related.js +90 -0
- package/dist/slices/episodes/repo.js +60 -0
- package/dist/slices/episodes/service.js +58 -0
- package/dist/slices/episodes/summarize.js +170 -0
- package/dist/slices/estimate/index.js +109 -28
- package/dist/slices/estimate/requests.js +60 -2
- package/dist/slices/fixes/rules.js +73 -0
- package/dist/slices/fonts/coverage.js +82 -0
- package/dist/slices/fonts/sfnt.js +74 -0
- package/dist/slices/images/run.js +8 -5
- package/dist/slices/images/scale.js +84 -0
- package/dist/slices/library/diff.js +122 -0
- package/dist/slices/library/history.js +100 -0
- package/dist/slices/library/model.js +3 -0
- package/dist/slices/library/photorealistic.js +49 -0
- package/dist/slices/library/repo.js +19 -14
- package/dist/slices/library/save.js +62 -12
- package/dist/slices/library/slots.js +7 -1
- package/dist/slices/library/used-by.js +153 -0
- package/dist/slices/loudness/level-pieces.js +41 -0
- package/dist/slices/loudness/loudnorm.js +164 -0
- package/dist/slices/loudness/model.js +153 -0
- package/dist/slices/model-upkeep/model.js +10 -0
- package/dist/slices/model-upkeep/switch.js +217 -0
- package/dist/slices/model-upkeep/usage.js +183 -0
- package/dist/slices/narration/aliases-library.js +31 -0
- package/dist/slices/narration/aliases-schema.js +53 -0
- package/dist/slices/narration/aliases.js +49 -0
- package/dist/slices/narration/blocks.js +352 -0
- package/dist/slices/narration/chunk.js +19 -7
- package/dist/slices/narration/concat.js +2 -2
- package/dist/slices/narration/describe.js +45 -0
- package/dist/slices/narration/pauses-model.js +63 -0
- package/dist/slices/narration/pauses.js +269 -0
- package/dist/slices/narration/peaks-model.js +1 -0
- package/dist/slices/narration/peaks.js +94 -0
- package/dist/slices/narration/preparation.js +21 -3
- package/dist/slices/narration/pronunciation-chunks.js +3 -3
- package/dist/slices/narration/pronunciation.js +72 -25
- package/dist/slices/narration/run.js +6 -6
- package/dist/slices/narration/shared-glossary.js +1 -1
- package/dist/slices/narration/steering.js +15 -4
- package/dist/slices/notifications/notifier.js +21 -3
- package/dist/slices/notifications/rules.js +22 -1
- package/dist/slices/onboarding/copy.js +143 -0
- package/dist/slices/onboarding/first-run.js +46 -0
- package/dist/slices/onboarding/install.js +119 -0
- package/dist/slices/onboarding/model.js +64 -0
- package/dist/slices/onboarding/packs.js +491 -0
- package/dist/slices/onboarding/quick-short.js +129 -0
- package/dist/slices/onboarding/sample.js +132 -0
- package/dist/slices/onboarding/state.js +68 -0
- package/dist/slices/onboarding/template.js +73 -0
- package/dist/slices/patch-notes/library.js +73 -0
- package/dist/slices/patch-notes/seen.js +77 -0
- package/dist/slices/play-drafts/convert.js +125 -6
- package/dist/slices/play-drafts/readiness.js +3 -0
- package/dist/slices/play-drafts/repo.js +2 -0
- package/dist/slices/play-drafts/review-inputs.js +20 -3
- package/dist/slices/play-drafts/schema.js +89 -0
- package/dist/slices/play-drafts/service.js +4 -1
- package/dist/slices/play-drafts/start.js +43 -18
- package/dist/slices/project-templates/from-project.js +50 -4
- package/dist/slices/project-templates/one-off.js +26 -0
- package/dist/slices/project-templates/repo.js +2 -1
- package/dist/slices/project-templates/service.js +15 -4
- package/dist/slices/project-templates/setup.js +18 -2
- package/dist/slices/rebuild/admission-repo.js +1 -1
- package/dist/slices/rebuild/model.js +6 -0
- package/dist/slices/rebuild/preview-details.js +46 -3
- package/dist/slices/rebuild/preview-plan.js +13 -6
- package/dist/slices/rebuild/recipe-audio-parts.js +40 -7
- package/dist/slices/rebuild/recipe-audio.js +66 -12
- package/dist/slices/rebuild/recipe-build.js +8 -4
- package/dist/slices/rebuild/recipe-cast.js +18 -0
- package/dist/slices/rebuild/recipe-checkpoints.js +11 -9
- package/dist/slices/rebuild/recipe-describe.js +93 -0
- package/dist/slices/rebuild/recipe-edit.js +13 -1
- package/dist/slices/rebuild/recipe-exports.js +62 -8
- package/dist/slices/rebuild/recipe-input-schema.js +35 -0
- package/dist/slices/rebuild/recipe-legacy.js +9 -0
- package/dist/slices/rebuild/recipe-loudness.js +45 -0
- package/dist/slices/rebuild/recipe-model.js +25 -6
- package/dist/slices/rebuild/recipe-pauses.js +7 -0
- package/dist/slices/rebuild/recipe-preparation.js +3 -3
- package/dist/slices/rebuild/recipe-provider-choice.js +11 -1
- package/dist/slices/rebuild/recipe-reference.js +15 -1
- package/dist/slices/rebuild/recipe-reviews.js +117 -0
- package/dist/slices/rebuild/recipe-save.js +4 -1
- package/dist/slices/rebuild/recipe-shorts.js +23 -3
- package/dist/slices/rebuild/recipe-text.js +114 -19
- package/dist/slices/rebuild/recipe-validation.js +14 -2
- package/dist/slices/rebuild/recipe-visual.js +96 -33
- package/dist/slices/rebuild/recipe-voices.js +286 -0
- package/dist/slices/rebuild/recipe-work.js +77 -6
- package/dist/slices/rebuild/recipe-youtube.js +2 -0
- package/dist/slices/rebuild/recovery-conflict.js +7 -3
- package/dist/slices/rebuild/recovery-model.js +3 -0
- package/dist/slices/rebuild/recovery-selection.js +28 -2
- package/dist/slices/rebuild/recovery.js +35 -17
- package/dist/slices/rebuild/repo.js +3 -3
- package/dist/slices/rebuild/retry.js +18 -0
- package/dist/slices/rebuild/review-redo.js +110 -0
- package/dist/slices/rebuild/runtime-actions.js +5 -0
- package/dist/slices/rebuild/runtime-admission.js +4 -1
- package/dist/slices/rebuild/runtime-animate.js +4 -4
- package/dist/slices/rebuild/runtime-article.js +5 -5
- package/dist/slices/rebuild/runtime-document.js +4 -4
- package/dist/slices/rebuild/runtime-export-bed.js +43 -0
- package/dist/slices/rebuild/runtime-export-edit.js +70 -11
- package/dist/slices/rebuild/runtime-export-inputs.js +52 -10
- package/dist/slices/rebuild/runtime-export-short.js +85 -0
- package/dist/slices/rebuild/runtime-export.js +84 -19
- package/dist/slices/rebuild/runtime-figure-card.js +87 -0
- package/dist/slices/rebuild/runtime-image.js +21 -2
- package/dist/slices/rebuild/runtime-local.js +148 -24
- package/dist/slices/rebuild/runtime-materialize.js +8 -0
- package/dist/slices/rebuild/runtime-narration-reuse.js +2 -1
- package/dist/slices/rebuild/runtime-narration-text.js +7 -7
- package/dist/slices/rebuild/runtime-pictures.js +28 -0
- package/dist/slices/rebuild/runtime-piece-label.js +27 -0
- package/dist/slices/rebuild/runtime-provider.js +126 -18
- package/dist/slices/rebuild/runtime-publication.js +21 -5
- package/dist/slices/rebuild/runtime-review.js +237 -0
- package/dist/slices/rebuild/runtime-run.js +17 -11
- package/dist/slices/rebuild/runtime-shorts.js +44 -17
- package/dist/slices/rebuild/runtime-store.js +39 -10
- package/dist/slices/rebuild/runtime-subtitles.js +72 -19
- package/dist/slices/rebuild/runtime-voices.js +103 -0
- package/dist/slices/rebuild/runtime-youtube.js +7 -6
- package/dist/slices/rebuild/soften.js +49 -0
- package/dist/slices/rebuild/transition-repo.js +9 -2
- package/dist/slices/research/run.js +4 -4
- package/dist/slices/research/synthesis.js +2 -2
- package/dist/slices/reviews/model.js +105 -0
- package/dist/slices/reviews/outcome.js +22 -0
- package/dist/slices/reviews/repo.js +106 -0
- package/dist/slices/reviews/rules.js +63 -0
- package/dist/slices/reviews/verdict.js +71 -0
- package/dist/slices/reviews/view.js +30 -0
- package/dist/slices/revisions/adopt-content.js +5 -2
- package/dist/slices/revisions/adopt.js +3 -1
- package/dist/slices/revisions/downloads.js +7 -1
- package/dist/slices/revisions/image-plan.js +183 -0
- package/dist/slices/revisions/mutation-assets.js +10 -0
- package/dist/slices/revisions/mutation-cues.js +71 -0
- package/dist/slices/revisions/mutation-request.js +2 -1
- package/dist/slices/revisions/mutations.js +97 -3
- package/dist/slices/revisions/schema.js +11 -1
- package/dist/slices/run-cost/limits.js +128 -0
- package/dist/slices/run-cost/meter.js +47 -0
- package/dist/slices/run-cost/panel.js +234 -0
- package/dist/slices/run-cost/pricing.js +92 -0
- package/dist/slices/run-cost/week.js +108 -0
- package/dist/slices/schedules/agenda.js +158 -0
- package/dist/slices/schedules/repo.js +58 -18
- package/dist/slices/schedules/scheduler.js +67 -16
- package/dist/slices/schedules/schema.js +138 -1
- package/dist/slices/schedules/service.js +43 -4
- package/dist/slices/schedules/similar.js +90 -0
- package/dist/slices/schedules/topic-list.js +163 -0
- package/dist/slices/schedules/topics.js +422 -0
- package/dist/slices/settings/first-run.js +102 -0
- package/dist/slices/settings/health.js +190 -0
- package/dist/slices/settings/key-guides.js +128 -0
- package/dist/slices/settings/key-test.js +85 -0
- package/dist/slices/settings/model.js +6 -1
- package/dist/slices/settings/playback.js +15 -0
- package/dist/slices/settings/repo.js +17 -3
- package/dist/slices/settings/voices.js +64 -4
- package/dist/slices/settings/whats-new.js +64 -0
- package/dist/slices/shorts/captions.js +9 -0
- package/dist/slices/shorts/pick.js +3 -3
- package/dist/slices/shorts/prompts.js +1 -1
- package/dist/slices/shorts/render.js +54 -5
- package/dist/slices/storage/asset-name.js +3 -0
- package/dist/slices/storage/backup-export.js +48 -9
- package/dist/slices/storage/backup-format.js +38 -1
- package/dist/slices/storage/backup-import.js +191 -19
- package/dist/slices/storage/delete-project.js +7 -4
- package/dist/slices/storage/documents.js +79 -0
- package/dist/slices/storage/files-location.js +531 -0
- package/dist/slices/storage/layout.js +14 -4
- package/dist/slices/storage/model.js +11 -0
- package/dist/slices/storage/portable.js +92 -12
- package/dist/slices/storage/reconcile.js +14 -1
- package/dist/slices/storage/repo.js +4 -1
- package/dist/slices/storage/schema.js +11 -0
- package/dist/slices/storage/trim.js +146 -0
- package/dist/slices/studio/disclosure.js +74 -0
- package/dist/slices/studio/model.js +28 -0
- package/dist/slices/studio/pack.js +209 -0
- package/dist/slices/studio/settings.js +133 -0
- package/dist/slices/style-preview/images.js +61 -0
- package/dist/slices/style-preview/render.js +161 -0
- package/dist/slices/style-preview/schema.js +45 -0
- package/dist/slices/style-preview/service.js +93 -0
- package/dist/slices/style-preview/settings.js +89 -0
- package/dist/slices/subtitles/captions.js +42 -9
- package/dist/slices/subtitles/model.js +22 -0
- package/dist/slices/subtitles/prepare.js +27 -16
- package/dist/slices/subtitles/transcript.js +1 -1
- package/dist/slices/thumbnail/run.js +7 -7
- package/dist/slices/trash/model.js +25 -0
- package/dist/slices/trash/service.js +273 -0
- package/dist/slices/uploads/repo.js +20 -0
- package/dist/slices/video/ambient-bed-schema.js +15 -0
- package/dist/slices/video/ambient-bed.js +95 -0
- package/dist/slices/video/ambient-mix.js +72 -0
- package/dist/slices/video/audio-inputs.js +2 -2
- package/dist/slices/video/cards.js +5 -2
- package/dist/slices/video/edit-list.js +23 -2
- package/dist/slices/video/edit-settings.js +13 -3
- package/dist/slices/video/ffmpeg.js +63 -9
- package/dist/slices/video/figure-card.js +492 -0
- package/dist/slices/video/figure-spans.js +51 -0
- package/dist/slices/video/plan.js +125 -13
- package/dist/slices/video/run.js +14 -12
- package/dist/slices/video/slideshow.js +39 -4
- package/dist/slices/voices/attribution.js +69 -0
- package/dist/slices/voices/audio-files.js +82 -0
- package/dist/slices/voices/audition.js +25 -0
- package/dist/slices/voices/cast.js +56 -0
- package/dist/slices/voices/grouping.js +49 -0
- package/dist/slices/voices/join.js +35 -0
- package/dist/slices/voices/languages.js +25 -0
- package/dist/slices/voices/model.js +179 -0
- package/dist/slices/voices/palette.js +26 -0
- package/dist/slices/voices/panel.js +91 -0
- package/dist/slices/voices/portraits.js +55 -0
- package/dist/slices/voices/script.js +136 -0
- package/dist/slices/voices/timing.js +58 -0
- package/dist/slices/youtube/answer.js +1 -1
- package/dist/slices/youtube/chapters.js +126 -0
- package/dist/slices/youtube/edits-repo.js +69 -0
- package/dist/slices/youtube/edits.js +89 -0
- package/dist/slices/youtube/placeholders.js +98 -0
- package/dist/slices/youtube/transcript.js +11 -4
- package/dist/updater/service.js +66 -21
- package/dist/web/assets/index-CUA2sUxU.css +1 -0
- package/dist/web/assets/index-CX590kE-.js +303 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
- package/dist/web/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
- package/dist/web/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
- package/dist/web/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
- package/dist/web/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
- package/dist/web/assets/{pdf-BLF2i8c2.js → pdf-BG8n_uc5.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +4 -4
- package/dist/edge/docker-launch.js +0 -81
- package/dist/edge/docker-projects/activation.js +0 -35
- package/dist/edge/docker-projects/claims.js +0 -85
- package/dist/edge/docker-projects/committed.js +0 -40
- package/dist/edge/docker-projects/engine.js +0 -461
- package/dist/edge/docker-projects/install.js +0 -254
- package/dist/edge/docker-projects/prune.js +0 -66
- package/dist/edge/docker-projects/recover.js +0 -100
- package/dist/edge/docker-projects/state.js +0 -225
- package/dist/web/assets/index-CktpxlJd.js +0 -171
- package/dist/web/assets/index-DB-vOnGU.css +0 -1
- package/scripts/docker-run.sh +0 -3
- /package/dist/edge/{docker-projects → docker-install}/tree.js +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { stageKinds } from "../../kernel/pipeline.js";
|
|
2
2
|
import { sourceOf } from "../admission/model.js";
|
|
3
|
-
import { allowedSources, edgeSilenceSecondsProblem, imageSecondsProblem, normaliseDraft, silenceGapSecondsMax, zoomPercentProblem, } from "../admission/rules.js";
|
|
3
|
+
import { allowedSources, edgeSilenceSecondsProblem, imageSecondsProblem, normaliseDraft, silenceGapSecondsMax, voicesFields, zoomPercentProblem, } from "../admission/rules.js";
|
|
4
|
+
import { shortModeFields } from "../admission/short-mode.js";
|
|
4
5
|
import { render } from "../admission/substitute.js";
|
|
5
6
|
import { effectiveClips, pickedShortsOf, rangeProblem } from "../shorts/clips.js";
|
|
6
7
|
import { buildRecipes } from "./recipe-build.js";
|
|
@@ -44,6 +45,7 @@ export function planRevision(base, edit, prepared = { outputs: [], pieces: [] },
|
|
|
44
45
|
const content = normalizeImages(normalizeArticleIntent(base, edit));
|
|
45
46
|
const fields = [
|
|
46
47
|
...validateRevisionEdit(edit.config, content),
|
|
48
|
+
...shortModeFields(edit.config),
|
|
47
49
|
...validateCues(content),
|
|
48
50
|
...validateRecipeInputs(edit.config, content),
|
|
49
51
|
...shortRangeFields(base, edit.config, content),
|
|
@@ -234,6 +236,7 @@ export function validateRevisionEdit(config, content) {
|
|
|
234
236
|
config.subtitles !== undefined &&
|
|
235
237
|
config.subtitles.mode !== "off")
|
|
236
238
|
fields.push({ field: "subtitles.mode", message: "Subtitles need narration audio." });
|
|
239
|
+
fields.push(...voicesFields(config));
|
|
237
240
|
return fields;
|
|
238
241
|
}
|
|
239
242
|
function validateCues(content) {
|
|
@@ -4,8 +4,10 @@ import { usesShorts } from "../admission/rules.js";
|
|
|
4
4
|
import { effectiveClips, pickedShortsOf } from "../shorts/clips.js";
|
|
5
5
|
import { defaultShortsImagePrompt, musicVolumeOf, shortImageCount, shortsSpeedOf, } from "../shorts/model.js";
|
|
6
6
|
import { imagePromptMessages } from "../shorts/prompts.js";
|
|
7
|
+
import { castFor } from "./recipe-cast.js";
|
|
8
|
+
import { noMaster } from "./recipe-loudness.js";
|
|
7
9
|
import { recipe, resourceIdentity, selectedReference, } from "./recipe-model.js";
|
|
8
|
-
import { imageChoice } from "./recipe-reference.js";
|
|
10
|
+
import { castField, imageChoice } from "./recipe-reference.js";
|
|
9
11
|
import { llmInput, renderedPrompt } from "./recipe-text.js";
|
|
10
12
|
// The Shorts step unfolds as its answers land, the way research's chapters unfold from the
|
|
11
13
|
// plan. `shorts:pick` reads the word timing, so it waits for `subtitles:timing` and runs
|
|
@@ -22,7 +24,11 @@ export const shortsPickKey = "shorts:pick";
|
|
|
22
24
|
export const shortsFutureKey = "shorts:future";
|
|
23
25
|
export function shortsRecipes(context, exports,
|
|
24
26
|
// The establishing image the shorts' images are drawn from, when it is on.
|
|
25
|
-
reference
|
|
27
|
+
reference,
|
|
28
|
+
// "Show tables and figures on screen": the cards a short shows where it describes one.
|
|
29
|
+
cards = [],
|
|
30
|
+
// Level the volume: the levelled narration and the master (`recipe-loudness.ts`).
|
|
31
|
+
master = noMaster) {
|
|
26
32
|
const { config } = context;
|
|
27
33
|
const shorts = config.shorts;
|
|
28
34
|
const timing = exports.find((value) => value.key === "subtitles:timing");
|
|
@@ -44,6 +50,8 @@ reference) {
|
|
|
44
50
|
shorts.minSeconds,
|
|
45
51
|
shorts.maxSeconds,
|
|
46
52
|
config.title,
|
|
53
|
+
// The project language, only when it is not English, so English keeps its fingerprint.
|
|
54
|
+
...(config.language === undefined || config.language === "en" ? [] : [config.language]),
|
|
47
55
|
],
|
|
48
56
|
}, [timing.key],
|
|
49
57
|
// A paid LLM call: readiness, the charge warning and the estimate treat it like one.
|
|
@@ -105,6 +113,7 @@ reference) {
|
|
|
105
113
|
prompt,
|
|
106
114
|
aspect: "9:16",
|
|
107
115
|
...(reference === undefined ? {} : { reference: reference.input }),
|
|
116
|
+
...castField(castFor(config, prompt)),
|
|
108
117
|
}, [prompts.key, ...(reference === undefined ? [] : [reference.key])], { token }));
|
|
109
118
|
recipes.push(...stills);
|
|
110
119
|
const extras = renderExtras(context, clip);
|
|
@@ -125,8 +134,19 @@ reference) {
|
|
|
125
134
|
// Only when one of the later settings is in use, so a short rendered before
|
|
126
135
|
// they existed keeps its fingerprint.
|
|
127
136
|
...(extras === undefined ? [] : [extras]),
|
|
137
|
+
// Only with cards, so a short rendered before them keeps its fingerprint.
|
|
138
|
+
...(cards.length === 0
|
|
139
|
+
? []
|
|
140
|
+
: [["figure-cards-v1", cards.map((card) => resourceIdentity(context, card))]]),
|
|
141
|
+
// Only while the volume is levelled, so every short without it keeps its fingerprint.
|
|
142
|
+
...master.values,
|
|
128
143
|
],
|
|
129
|
-
}, [
|
|
144
|
+
}, [
|
|
145
|
+
pick.key,
|
|
146
|
+
...stills.map((still) => still.key),
|
|
147
|
+
...cards.map((card) => card.key),
|
|
148
|
+
...master.keys,
|
|
149
|
+
], { token }));
|
|
130
150
|
}
|
|
131
151
|
return recipes;
|
|
132
152
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { withLanguage } from "../../kernel/ports/languages.js";
|
|
2
3
|
import { documentIndex } from "../../kernel/ports/llm-documents.js";
|
|
3
4
|
import { fingerprint } from "../../kernel/runner/work.js";
|
|
4
5
|
import { usesPronunciationGlossary } from "../admission/rules.js";
|
|
@@ -7,12 +8,17 @@ import { articleMessages, continuationMessages } from "../article/continuation.j
|
|
|
7
8
|
import { plainText } from "../article/plain.js";
|
|
8
9
|
import { segmentMessages } from "../article/segments.js";
|
|
9
10
|
import { splitEndMatter } from "../article/split.js";
|
|
11
|
+
import { withEarlierEpisodes } from "../episodes/related.js";
|
|
10
12
|
import { parsePronunciationGlossary } from "../narration/pronunciation.js";
|
|
11
13
|
import { withSharedGlossary } from "../narration/shared-glossary.js";
|
|
12
14
|
import { researchDocuments } from "../research/documents.js";
|
|
13
15
|
import { plannerMessages, subAgentMessages } from "../research/planner.js";
|
|
14
16
|
import { synthesisMessages } from "../research/synthesis.js";
|
|
15
17
|
import { thumbnailMessages } from "../thumbnail/by-llm.js";
|
|
18
|
+
import { attributionMessages } from "../voices/attribution.js";
|
|
19
|
+
import { usesVoices } from "../voices/model.js";
|
|
20
|
+
import { scriptMessages } from "../voices/script.js";
|
|
21
|
+
import { describedText, describeFuture, describing } from "./recipe-describe.js";
|
|
16
22
|
import { recipe, selectedReference, } from "./recipe-model.js";
|
|
17
23
|
export function renderedPrompt(context, key) {
|
|
18
24
|
const raw = context.content.promptTemplates[key];
|
|
@@ -41,7 +47,12 @@ export function llmInput(context, messages, webSearch = false, documents) {
|
|
|
41
47
|
export function selectedText(context, key, field) {
|
|
42
48
|
const piece = context.manifest.pieces.find((row) => row.key === key &&
|
|
43
49
|
selectedReference(row) &&
|
|
44
|
-
row.stageKind ===
|
|
50
|
+
row.stageKind ===
|
|
51
|
+
(key.startsWith("entry:") || key.startsWith("script:")
|
|
52
|
+
? "article"
|
|
53
|
+
: key.startsWith("narration:describe:")
|
|
54
|
+
? "audio"
|
|
55
|
+
: "thumbnail") &&
|
|
45
56
|
row.piece.state === "done");
|
|
46
57
|
if (piece?.piece.payload === null || piece === undefined)
|
|
47
58
|
return null;
|
|
@@ -81,9 +92,7 @@ export function textRecipes(context) {
|
|
|
81
92
|
});
|
|
82
93
|
recipes.push(research);
|
|
83
94
|
}
|
|
84
|
-
const articleMarkdown =
|
|
85
|
-
? (content.articleMarkdown ?? config.provided.article ?? "")
|
|
86
|
-
: resolved.articleMarkdown;
|
|
95
|
+
const articleMarkdown = articleMarkdownOf(context);
|
|
87
96
|
const notes = config.sources.research === "off"
|
|
88
97
|
? null
|
|
89
98
|
: config.sources.research === "provide"
|
|
@@ -95,10 +104,26 @@ export function textRecipes(context) {
|
|
|
95
104
|
{ id: "editorial-notes", title: "Editorial notes", content: notes },
|
|
96
105
|
]
|
|
97
106
|
: [];
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
107
|
+
const voices = usesVoices(config) ? config.voices : undefined;
|
|
108
|
+
const writesScript = voices?.source === "script";
|
|
109
|
+
const articleNotes = documents.length ? documentIndex(documents) : (notes ?? undefined);
|
|
110
|
+
// A script run writes speaker turns in place of the article, from the same prompt and notes.
|
|
111
|
+
// The related earlier episodes go under the prompt only when the run carries them, so a
|
|
112
|
+
// project made without them keeps its fingerprint. Either is written in the project's
|
|
113
|
+
// language (`withLanguage`; English adds nothing).
|
|
114
|
+
const writtenPrompt = withEarlierEpisodes(brief.articlePrompt, config.earlierEpisodes);
|
|
115
|
+
const messages = withLanguage(voices !== undefined && writesScript
|
|
116
|
+
? scriptMessages(voices.format, voices.speakers, writtenPrompt, articleNotes)
|
|
117
|
+
: articleMessages({
|
|
118
|
+
articlePrompt: writtenPrompt,
|
|
119
|
+
...(articleNotes === undefined ? {} : { notes: articleNotes }),
|
|
120
|
+
}), config.language);
|
|
121
|
+
const scriptCheck = voices === undefined
|
|
122
|
+
? undefined
|
|
123
|
+
: {
|
|
124
|
+
speakers: voices.speakers.map((speaker) => ({ id: speaker.id, name: speaker.name })),
|
|
125
|
+
attribute: !writesScript,
|
|
126
|
+
};
|
|
102
127
|
const article = config.sources.article === "provide" || content.articleEdited === true
|
|
103
128
|
? recipe(context, "article:body", "article", {
|
|
104
129
|
kind: "local",
|
|
@@ -113,7 +138,10 @@ export function textRecipes(context) {
|
|
|
113
138
|
operation: "article",
|
|
114
139
|
template: [llmInputFingerprint(context, messages), research?.fingerprint ?? null],
|
|
115
140
|
}
|
|
116
|
-
:
|
|
141
|
+
: {
|
|
142
|
+
...llmInput(context, messages, false, documents),
|
|
143
|
+
...(writesScript && scriptCheck !== undefined ? { script: scriptCheck } : {}),
|
|
144
|
+
}, research === undefined ? [] : [research.key]);
|
|
117
145
|
recipes.push(article);
|
|
118
146
|
if (resolved.articleContinuation !== undefined &&
|
|
119
147
|
config.sources.article === "generate" &&
|
|
@@ -121,11 +149,50 @@ export function textRecipes(context) {
|
|
|
121
149
|
recipes.push(recipe(context, "article:continuation", "article", llmInput(context, continuationMessages(messages, resolved.articleContinuation), false, documents), [article.key]));
|
|
122
150
|
const endMatter = articleMarkdown === null ? null : splitEndMatter(articleMarkdown);
|
|
123
151
|
const articleText = endMatter === null ? null : plainText(endMatter.body);
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
152
|
+
let script;
|
|
153
|
+
if (voices !== undefined && scriptCheck !== undefined) {
|
|
154
|
+
if (writesScript)
|
|
155
|
+
script = { text: endMatter?.body ?? null, dependsOn: [article.key] };
|
|
156
|
+
else {
|
|
157
|
+
// An audiobook from a text: the text model hands the article's passages to speakers.
|
|
158
|
+
const attribute = recipe(context, "script:attribute", "article", endMatter === null
|
|
159
|
+
? {
|
|
160
|
+
kind: "deferred",
|
|
161
|
+
version: 1,
|
|
162
|
+
operation: "script-attribution",
|
|
163
|
+
template: [
|
|
164
|
+
article.fingerprint,
|
|
165
|
+
llmInputFingerprint(context, withLanguage(attributionMessages("", voices.speakers), config.language)),
|
|
166
|
+
],
|
|
167
|
+
}
|
|
168
|
+
: {
|
|
169
|
+
...llmInput(context, withLanguage(attributionMessages(endMatter.body, voices.speakers), config.language)),
|
|
170
|
+
script: scriptCheck,
|
|
171
|
+
}, [article.key]);
|
|
172
|
+
recipes.push(attribute);
|
|
173
|
+
script = {
|
|
174
|
+
text: endMatter === null ? null : matchingText(context, attribute, "text"),
|
|
175
|
+
dependsOn: [attribute.key],
|
|
176
|
+
fingerprint: attribute.fingerprint,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
let narrationText = articleText;
|
|
181
|
+
const descriptions = [];
|
|
182
|
+
const cards = [];
|
|
183
|
+
if (describing(context) && voices === undefined) {
|
|
184
|
+
if (endMatter === null) {
|
|
185
|
+
descriptions.push(describeFuture(context, article));
|
|
186
|
+
narrationText = null;
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
const described = describedText(context, endMatter.body, [article.key]);
|
|
190
|
+
descriptions.push(...described.recipes);
|
|
191
|
+
cards.push(...described.cards);
|
|
192
|
+
narrationText = described.spoken;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
const glossary = glossaryOf(context, endMatter);
|
|
129
196
|
const entries = {};
|
|
130
197
|
for (const category of ["intro", "outro"]) {
|
|
131
198
|
const choice = config[category];
|
|
@@ -141,11 +208,11 @@ export function textRecipes(context) {
|
|
|
141
208
|
version: 1,
|
|
142
209
|
operation: key,
|
|
143
210
|
template: [
|
|
144
|
-
llmInputFingerprint(context, segmentMessages(prompt, config, "")),
|
|
211
|
+
llmInputFingerprint(context, withLanguage(segmentMessages(prompt, config, ""), config.language)),
|
|
145
212
|
article.fingerprint,
|
|
146
213
|
],
|
|
147
214
|
}
|
|
148
|
-
: llmInput(context, segmentMessages(prompt, config, articleText));
|
|
215
|
+
: llmInput(context, withLanguage(segmentMessages(prompt, config, articleText), config.language));
|
|
149
216
|
const value = recipe(context, key, "article", input, choice.mode === "llm" ? [article.key] : []);
|
|
150
217
|
recipes.push(value);
|
|
151
218
|
entries[category] = {
|
|
@@ -171,7 +238,17 @@ export function textRecipes(context) {
|
|
|
171
238
|
}
|
|
172
239
|
: llmInput(context, messages), [article.key]));
|
|
173
240
|
}
|
|
174
|
-
return {
|
|
241
|
+
return {
|
|
242
|
+
recipes,
|
|
243
|
+
articleText,
|
|
244
|
+
narrationText,
|
|
245
|
+
descriptions,
|
|
246
|
+
cards,
|
|
247
|
+
glossary,
|
|
248
|
+
article,
|
|
249
|
+
entries,
|
|
250
|
+
...(script === undefined ? {} : { script }),
|
|
251
|
+
};
|
|
175
252
|
}
|
|
176
253
|
function llmInputFingerprint(context, messages) {
|
|
177
254
|
return fingerprint(JSON.parse(JSON.stringify(llmInput(context, messages))));
|
|
@@ -186,10 +263,28 @@ export function matchingText(context, value, field) {
|
|
|
186
263
|
return null;
|
|
187
264
|
return selectedText(context, value.key, field);
|
|
188
265
|
}
|
|
266
|
+
function articleMarkdownOf(context) {
|
|
267
|
+
const { config, content, resolved } = context;
|
|
268
|
+
return config.sources.article === "provide" || content.articleEdited === true
|
|
269
|
+
? (content.articleMarkdown ?? config.provided.article ?? "")
|
|
270
|
+
: resolved.articleMarkdown;
|
|
271
|
+
}
|
|
272
|
+
function glossaryOf(context, endMatter) {
|
|
273
|
+
if (!usesPronunciationGlossary(context.config))
|
|
274
|
+
return { ok: true, entries: [] };
|
|
275
|
+
if (endMatter === null)
|
|
276
|
+
return null;
|
|
277
|
+
return withShared(parsePronunciationGlossary(endMatter.glossary, context.config.language), context.config);
|
|
278
|
+
}
|
|
279
|
+
// The narration glossary this revision uses, or null while its article is still unwritten.
|
|
280
|
+
export function narrationGlossary(context) {
|
|
281
|
+
const markdown = articleMarkdownOf(context);
|
|
282
|
+
return glossaryOf(context, markdown === null ? null : splitEndMatter(markdown));
|
|
283
|
+
}
|
|
189
284
|
// The project's own glossary, then the other projects' pronunciations it copied, when it
|
|
190
|
-
// shares them.
|
|
285
|
+
// shares them. Rows the own glossary had to skip are still reported.
|
|
191
286
|
function withShared(own, config) {
|
|
192
287
|
if (!own.ok || config.audio?.shareGlossary !== true)
|
|
193
288
|
return own;
|
|
194
|
-
return {
|
|
289
|
+
return { ...own, entries: withSharedGlossary(own.entries, config.sharedGlossary) };
|
|
195
290
|
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { narrationPreparationFields, shortsFields, usesNarrationPreparation, usesReference, usesShorts, usesYoutubeDescription, videoEditFields, youtubeDescriptionFields, } from "../admission/rules.js";
|
|
2
2
|
import { detectSlots, render } from "../admission/substitute.js";
|
|
3
|
+
import { imagesPerVideoMax } from "../images/scale.js";
|
|
4
|
+
import { loudnessFields } from "../loudness/model.js";
|
|
5
|
+
import { pauseFields } from "../narration/pauses-model.js";
|
|
6
|
+
import { reviewFields } from "../reviews/rules.js";
|
|
3
7
|
import { usesAnimation } from "../video/edit-settings.js";
|
|
4
8
|
export function validateRecipeInputs(config, content) {
|
|
5
9
|
const fields = [
|
|
@@ -7,6 +11,9 @@ export function validateRecipeInputs(config, content) {
|
|
|
7
11
|
...youtubeDescriptionFields(config),
|
|
8
12
|
...shortsFields(config),
|
|
9
13
|
...videoEditFields(config),
|
|
14
|
+
...reviewFields(config),
|
|
15
|
+
...loudnessFields(config.loudness),
|
|
16
|
+
...pauseFields(config),
|
|
10
17
|
];
|
|
11
18
|
const llm = (config.sources.research === "generate" && config.sources.article !== "provide") ||
|
|
12
19
|
(config.sources.article === "generate" && !content.articleEdited) ||
|
|
@@ -33,8 +40,13 @@ export function validateRecipeInputs(config, content) {
|
|
|
33
40
|
usesAnimation(config)) &&
|
|
34
41
|
(!config.images?.provider.trim() || !config.images.model.trim()))
|
|
35
42
|
fields.push({ field: "images", message: "Pick an image provider and model." });
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
// 60, or more for a project that scales its images with the narration (`images/scale.ts`).
|
|
44
|
+
const imagesMax = imagesPerVideoMax(config);
|
|
45
|
+
if (content.imageOrder.length > imagesMax)
|
|
46
|
+
fields.push({
|
|
47
|
+
field: "content.imageOrder",
|
|
48
|
+
message: `Keep at most ${String(imagesMax)} images.`,
|
|
49
|
+
});
|
|
38
50
|
const chunking = config.chunking;
|
|
39
51
|
const size = chunking?.mode === "words"
|
|
40
52
|
? chunking.words
|
|
@@ -1,12 +1,21 @@
|
|
|
1
|
+
import { thumbnailCountOf, thumbnailKey } from "../admission/model.js";
|
|
2
|
+
import { usesShortMode } from "../admission/short-mode.js";
|
|
1
3
|
import { render } from "../admission/substitute.js";
|
|
4
|
+
import { usesAmbientBed } from "../video/ambient-bed.js";
|
|
5
|
+
import { castFor } from "./recipe-cast.js";
|
|
6
|
+
import { noMaster } from "./recipe-loudness.js";
|
|
2
7
|
import { recipe, resourceIdentity, } from "./recipe-model.js";
|
|
3
|
-
import { imageChoice } from "./recipe-reference.js";
|
|
8
|
+
import { castField, imageChoice } from "./recipe-reference.js";
|
|
4
9
|
import { matchingText, renderedPrompt } from "./recipe-text.js";
|
|
5
10
|
export function visualRecipes(config, content, audioFingerprint, captionFingerprint,
|
|
6
11
|
// What the Video stage's edit settings add (`recipe-edit.ts`), from the images planned here.
|
|
7
12
|
edit,
|
|
8
13
|
// The establishing image the generated images are drawn from, when it is on.
|
|
9
|
-
reference
|
|
14
|
+
reference,
|
|
15
|
+
// The word timing's identity, which a short's captions are drawn from.
|
|
16
|
+
timing = null,
|
|
17
|
+
// Level the volume: the levelled narration and the master (`recipe-loudness.ts`).
|
|
18
|
+
master = noMaster) {
|
|
10
19
|
const recipes = [];
|
|
11
20
|
const imageKeys = config.sources.images === "off" ? [] : content.imageOrder;
|
|
12
21
|
for (const key of imageKeys) {
|
|
@@ -26,10 +35,19 @@ reference) {
|
|
|
26
35
|
aspect: config.format,
|
|
27
36
|
prompt: prompt ?? "",
|
|
28
37
|
...(reference === undefined ? {} : { reference: reference.input }),
|
|
38
|
+
...castField(castFor(config, prompt)),
|
|
29
39
|
}, image.source === "provide" || reference === undefined ? [] : [reference.key], { unresolved: image.source === "provide" ? image.assetId === null : !prompt?.trim() }));
|
|
30
40
|
}
|
|
31
41
|
if (config.sources.video !== "off") {
|
|
32
|
-
const
|
|
42
|
+
const short = usesShortMode(config);
|
|
43
|
+
// A short is rendered by the Shorts renderer, which has no cuts, transitions or Look.
|
|
44
|
+
const edited = (short ? undefined : edit?.([...recipes])) ?? {
|
|
45
|
+
recipes: [],
|
|
46
|
+
values: [],
|
|
47
|
+
dependsOn: [],
|
|
48
|
+
};
|
|
49
|
+
// A short (rendered by the Shorts renderer) never has the bed.
|
|
50
|
+
const bed = short ? undefined : ambientBedValues(config, content);
|
|
33
51
|
const audioKeys = config.sources.audio === "off"
|
|
34
52
|
? []
|
|
35
53
|
: [
|
|
@@ -64,18 +82,48 @@ reference) {
|
|
|
64
82
|
// Only what the edit settings change; nothing at all for today's slideshow, so
|
|
65
83
|
// its fingerprint is the one it always had.
|
|
66
84
|
...(edited.values.length === 0 ? [] : [["video-edit", ...edited.values]]),
|
|
85
|
+
// Only for a short, so every long video keeps its fingerprint: the word-by-word
|
|
86
|
+
// captions are drawn from the word timing in the caption font, under the title.
|
|
87
|
+
...(short
|
|
88
|
+
? [["short-v1", config.subtitles?.fontId ?? "default", config.title, timing]]
|
|
89
|
+
: []),
|
|
90
|
+
// Only while the video has an ambient bed, so every video without one keeps the
|
|
91
|
+
// fingerprint it always had.
|
|
92
|
+
...(bed === undefined ? [] : [bed]),
|
|
93
|
+
// Only while the volume is levelled, so every video without it keeps its fingerprint.
|
|
94
|
+
...master.values,
|
|
67
95
|
],
|
|
68
96
|
}, [
|
|
69
97
|
...recipes.map((value) => value.key),
|
|
70
98
|
...audioKeys,
|
|
99
|
+
...master.keys,
|
|
71
100
|
...(config.subtitles?.mode === "burn-in" ? ["subtitles:files"] : []),
|
|
101
|
+
...(short ? ["subtitles:timing"] : []),
|
|
72
102
|
...edited.dependsOn,
|
|
73
|
-
], {
|
|
103
|
+
], {
|
|
104
|
+
unresolved: imageKeys.length === 0 ||
|
|
105
|
+
(config.ambientBed?.source === "upload" && content.ambientBed === undefined),
|
|
106
|
+
}));
|
|
74
107
|
// After the export, so the images' recipes above stay the only ones its first values list.
|
|
75
108
|
recipes.splice(recipes.length - 1, 0, ...edited.recipes);
|
|
76
109
|
}
|
|
77
110
|
return recipes;
|
|
78
111
|
}
|
|
112
|
+
// What the ambient bed adds to the render's fingerprint: its settings and, for the user's own
|
|
113
|
+
// file, the project asset it plays. Undefined without a bed.
|
|
114
|
+
export function ambientBedValues(config, content) {
|
|
115
|
+
const bed = config.ambientBed;
|
|
116
|
+
if (bed === undefined || !usesAmbientBed(config))
|
|
117
|
+
return undefined;
|
|
118
|
+
return [
|
|
119
|
+
"ambient-bed-v1",
|
|
120
|
+
bed.source,
|
|
121
|
+
bed.levelDb,
|
|
122
|
+
bed.fadeInSeconds,
|
|
123
|
+
bed.tailSeconds,
|
|
124
|
+
bed.source === "upload" ? (content.ambientBed ?? null) : null,
|
|
125
|
+
];
|
|
126
|
+
}
|
|
79
127
|
export function thumbnailRecipes(context, textRecipes,
|
|
80
128
|
// The establishing image, when it is on and the thumbnail is drawn from it too.
|
|
81
129
|
reference) {
|
|
@@ -95,35 +143,50 @@ reference) {
|
|
|
95
143
|
const prompt = config.sources.thumbnail === "prompt_by_llm" && promptRecipe !== undefined
|
|
96
144
|
? matchingText(context, promptRecipe, "prompt")
|
|
97
145
|
: renderedPrompt(context, "thumbnailPrompt");
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
],
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
},
|
|
123
|
-
|
|
124
|
-
...(
|
|
125
|
-
|
|
126
|
-
|
|
146
|
+
const variants = Array.from({ length: thumbnailCountOf(config) }, (_, index) => index + 1);
|
|
147
|
+
return variants.map((variant) => recipe(context, thumbnailKey(variant), "thumbnail", prompt === null
|
|
148
|
+
? {
|
|
149
|
+
kind: "deferred",
|
|
150
|
+
version: 1,
|
|
151
|
+
operation: "thumbnail-image",
|
|
152
|
+
template: [
|
|
153
|
+
promptRecipe?.fingerprint ?? null,
|
|
154
|
+
config.images?.provider ?? null,
|
|
155
|
+
config.images?.model ?? null,
|
|
156
|
+
config.format,
|
|
157
|
+
// Only what is in use, so a thumbnail made before these existed keeps its
|
|
158
|
+
// fingerprint.
|
|
159
|
+
...(config.images?.thinking === undefined ? [] : [config.images.thinking]),
|
|
160
|
+
...(reference === undefined ? [] : [reference.input.fingerprint]),
|
|
161
|
+
...(variant === 1 ? [] : [["thumbnail-variant", variant]]),
|
|
162
|
+
],
|
|
163
|
+
}
|
|
164
|
+
: {
|
|
165
|
+
kind: "image",
|
|
166
|
+
version: 1,
|
|
167
|
+
...imageChoice(config),
|
|
168
|
+
aspect: config.format,
|
|
169
|
+
prompt: thumbnailVariantPrompt(prompt, variant),
|
|
170
|
+
...(reference === undefined ? {} : { reference: reference.input }),
|
|
171
|
+
// The thumbnail stands for the whole video, like the establishing image.
|
|
172
|
+
...castField(castFor(config, config.title, prompt)),
|
|
173
|
+
}, [
|
|
174
|
+
...(promptRecipe === undefined ? [] : [promptRecipe.key]),
|
|
175
|
+
...(reference === undefined ? [] : [reference.key]),
|
|
176
|
+
]));
|
|
177
|
+
}
|
|
178
|
+
// The second and third thumbnails are the same prompt asked for another composition, so the
|
|
179
|
+
// three test one idea against itself rather than three ideas. The first is the prompt as it
|
|
180
|
+
// is, which keeps the thumbnail every project already has.
|
|
181
|
+
const variantFraming = {
|
|
182
|
+
2: "a tight close-up where the main subject fills most of the frame, seen from a different angle",
|
|
183
|
+
3: "a wider shot that shows the main subject in its setting, placed off-centre with room around it",
|
|
184
|
+
};
|
|
185
|
+
export function thumbnailVariantPrompt(prompt, variant) {
|
|
186
|
+
const framing = variantFraming[variant];
|
|
187
|
+
if (framing === undefined)
|
|
188
|
+
return prompt;
|
|
189
|
+
return `${prompt}\n\nThis is thumbnail ${String(variant)} of 3 for a YouTube thumbnail test. Keep the subject, style, colours and any text asked for above, but use a clearly different composition: ${framing}.`;
|
|
127
190
|
}
|
|
128
191
|
export function visualAssets(context, recipes) {
|
|
129
192
|
const images = recipes.filter((value) => value.stage === "images");
|