@gentbajko/slopify 2.4.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 +11 -1
- 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 +55 -5
- package/dist/adapters/host-cli/transport.js +13 -6
- package/dist/adapters/image/bytes.js +2 -2
- package/dist/adapters/image/codex-output.js +60 -18
- package/dist/adapters/image/codex.js +166 -25
- package/dist/adapters/image/fal.js +31 -3
- package/dist/adapters/image/google.js +17 -2
- package/dist/adapters/image/openai.js +45 -16
- package/dist/adapters/image/reference.js +41 -0
- package/dist/adapters/image/replicate.js +14 -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-models.js +2 -1
- package/dist/adapters/llm/codex-server-models.js +2 -1
- 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 +26 -9
- 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/models.yaml +7 -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 +33 -12
- package/dist/catalog/runtime-models.js +1 -1
- package/dist/catalog/schema.js +12 -1
- package/dist/catalog/store.js +147 -8
- package/dist/catalog/validate.js +17 -2
- 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/events/hub.js +11 -0
- package/dist/edge/host-cli.js +1 -1
- package/dist/edge/http/actions.js +32 -10
- package/dist/edge/http/app.js +60 -2
- package/dist/edge/http/auditions.js +70 -0
- package/dist/edge/http/autostart.js +37 -0
- package/dist/edge/http/backups.js +40 -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 +45 -6
- 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/problem.js +1 -0
- 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 +128 -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 +12 -3
- package/dist/kernel/db/migrations/0022-drop-duplicate-held-work.sql +56 -0
- package/dist/kernel/db/migrations/0024-reference-attachments.sql +18 -0
- 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 +139 -16
- package/dist/kernel/ports/image.js +3 -1
- package/dist/kernel/ports/key-probe.js +1 -0
- package/dist/kernel/ports/languages.js +157 -0
- package/dist/kernel/ports/llm.js +3 -1
- 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 +18 -9
- 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 +164 -9
- 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 +321 -20
- 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 +35 -0
- package/dist/slices/admission/repo.js +24 -4
- package/dist/slices/admission/rules.js +126 -1
- package/dist/slices/admission/schema.js +68 -1
- package/dist/slices/admission/short-mode.js +47 -0
- package/dist/slices/admission/start.js +90 -16
- 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/files.js +135 -0
- package/dist/slices/backups/folder.js +43 -0
- package/dist/slices/backups/model.js +65 -0
- package/dist/slices/backups/repo.js +28 -0
- package/dist/slices/backups/schedule.js +60 -0
- package/dist/slices/backups/service.js +311 -0
- package/dist/slices/batch/index.js +9 -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 +113 -24
- 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 +15 -3
- package/dist/slices/library/snapshot.js +8 -2
- 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 +94 -0
- package/dist/slices/notifications/rules.js +102 -0
- package/dist/slices/notifications/send.js +40 -0
- package/dist/slices/notifications/settings.js +34 -0
- 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 +160 -9
- package/dist/slices/play-drafts/readiness.js +3 -0
- package/dist/slices/play-drafts/repo.js +9 -1
- package/dist/slices/play-drafts/review-inputs.js +22 -3
- package/dist/slices/play-drafts/schema.js +109 -2
- package/dist/slices/play-drafts/service.js +10 -1
- package/dist/slices/play-drafts/start.js +43 -18
- package/dist/slices/play-drafts/uploads.js +2 -1
- package/dist/slices/project-templates/from-project.js +70 -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 +29 -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 +67 -2
- 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 +15 -5
- 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 +43 -1
- package/dist/slices/rebuild/recipe-legacy.js +12 -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 +58 -0
- 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 +32 -5
- package/dist/slices/rebuild/recipe-text.js +114 -19
- package/dist/slices/rebuild/recipe-validation.js +29 -3
- package/dist/slices/rebuild/recipe-visual.js +104 -29
- 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 +14 -2
- 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 +69 -0
- package/dist/slices/rebuild/runtime-local.js +154 -27
- 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 +29 -0
- package/dist/slices/rebuild/runtime-provider.js +134 -19
- 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 +48 -23
- 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/service-readiness.js +15 -1
- package/dist/slices/rebuild/soften.js +49 -0
- package/dist/slices/rebuild/transition-repo.js +10 -3
- 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 +12 -2
- package/dist/slices/revisions/adopt.js +9 -2
- package/dist/slices/revisions/downloads.js +7 -1
- package/dist/slices/revisions/image-plan.js +183 -0
- package/dist/slices/revisions/mutation-assets.js +43 -9
- package/dist/slices/revisions/mutation-cues.js +71 -0
- package/dist/slices/revisions/mutation-prepare.js +8 -10
- package/dist/slices/revisions/mutation-request.js +2 -1
- package/dist/slices/revisions/mutations.js +97 -3
- package/dist/slices/revisions/schema.js +16 -2
- 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 +48 -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 +11 -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 +20 -0
- package/dist/slices/storage/model.js +14 -0
- package/dist/slices/storage/portable.js +95 -12
- package/dist/slices/storage/reconcile.js +19 -2
- 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-CAJNT254.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-BGgYMm2u.css +0 -1
- package/dist/web/assets/index-BVVgtntL.js +0 -171
- package/scripts/docker-run.sh +0 -3
- /package/dist/edge/{docker-projects → docker-install}/tree.js +0 -0
|
@@ -4,25 +4,37 @@ import { defaultChunking } from "../narration/chunk.js";
|
|
|
4
4
|
import { concatArgs } from "../narration/concat.js";
|
|
5
5
|
import { normalizeNarrationText } from "../narration/plan.js";
|
|
6
6
|
import { pronunciationChunks } from "../narration/pronunciation-chunks.js";
|
|
7
|
-
import { narrationParts, pronunciationFutureValues, voiceValues } from "./recipe-audio-parts.js";
|
|
7
|
+
import { aliasFutureValues, narrationParts, pronunciationFutureValues, voiceValues, } from "./recipe-audio-parts.js";
|
|
8
|
+
import { levelRecipe } from "./recipe-loudness.js";
|
|
8
9
|
import { recipe, resourceIdentity, selectedReference, } from "./recipe-model.js";
|
|
9
10
|
import { narrationFileRecipe } from "./recipe-narration-text.js";
|
|
11
|
+
import { pauseValues } from "./recipe-pauses.js";
|
|
10
12
|
import { preparationFuture, preparationTemplate } from "./recipe-preparation.js";
|
|
13
|
+
import { voiceBodyRecipes } from "./recipe-voices.js";
|
|
11
14
|
export function bodyNarrationGroups(context, text) {
|
|
12
|
-
return text.
|
|
15
|
+
return text.narrationText === null
|
|
13
16
|
? []
|
|
14
|
-
: pronunciationChunks(normalizeNarrationText(text.
|
|
17
|
+
: pronunciationChunks(normalizeNarrationText(text.narrationText), context.config.chunking ?? defaultChunking, usesPronunciationGlossary(context.config) && text.glossary?.ok ? text.glossary.entries : [], new Set(Object.keys(context.content.narrationOverrides)), context.content.narrationSources);
|
|
15
18
|
}
|
|
16
19
|
export function audioRecipes(context, text) {
|
|
17
20
|
const { config, content } = context;
|
|
18
21
|
const recipes = [];
|
|
19
22
|
if (config.sources.audio === "off")
|
|
20
|
-
return { recipes, mediaFingerprint: null, timeline: [], keys: [] };
|
|
23
|
+
return { recipes, mediaFingerprint: null, timeline: [], keys: [], levels: [] };
|
|
21
24
|
const prepare = usesNarrationPreparation(config);
|
|
22
25
|
const pronounce = usesPronunciationGlossary(config);
|
|
23
26
|
const narrationFiles = prepare || pronounce;
|
|
24
27
|
let body;
|
|
25
|
-
let bodyTranscript = text.
|
|
28
|
+
let bodyTranscript = text.narrationText ??
|
|
29
|
+
(text.descriptions.length === 0
|
|
30
|
+
? text.article.fingerprint
|
|
31
|
+
: [
|
|
32
|
+
"described-v1",
|
|
33
|
+
text.article.fingerprint,
|
|
34
|
+
text.descriptions.map((row) => row.fingerprint),
|
|
35
|
+
]);
|
|
36
|
+
let sections;
|
|
37
|
+
let cards = [];
|
|
26
38
|
if (config.sources.audio === "provide") {
|
|
27
39
|
body = recipe(context, "audio:provided", "audio", {
|
|
28
40
|
kind: "provided",
|
|
@@ -32,18 +44,31 @@ export function audioRecipes(context, text) {
|
|
|
32
44
|
}, [text.article.key], { unresolved: content.provided.audio === undefined });
|
|
33
45
|
recipes.push(body);
|
|
34
46
|
}
|
|
47
|
+
else if (text.script !== undefined && config.voices !== undefined) {
|
|
48
|
+
const voiced = voiceBodyRecipes(context, config.voices, text.script, text.glossary);
|
|
49
|
+
recipes.push(...voiced.preparations, ...voiced.cards, ...voiced.parts);
|
|
50
|
+
cards = voiced.cards;
|
|
51
|
+
if (narrationFiles)
|
|
52
|
+
recipes.push(narrationFileRecipe(context, "body", voiced.parts));
|
|
53
|
+
recipes.push(voiced.body);
|
|
54
|
+
body = voiced.body;
|
|
55
|
+
bodyTranscript = voiced.transcript;
|
|
56
|
+
sections = voiced.sections;
|
|
57
|
+
}
|
|
35
58
|
else {
|
|
36
59
|
const groups = bodyNarrationGroups(context, text);
|
|
37
60
|
const parts = [];
|
|
38
61
|
const transcripts = [];
|
|
39
62
|
const futurePronunciation = [];
|
|
40
|
-
|
|
63
|
+
recipes.push(...text.descriptions, ...text.cards);
|
|
64
|
+
cards = text.cards;
|
|
65
|
+
let pending = text.narrationText === null;
|
|
41
66
|
for (const { key: logicalKey, text: logicalText } of groups) {
|
|
42
67
|
transcripts.push({
|
|
43
68
|
original: logicalText,
|
|
44
69
|
effective: effectiveText(context, logicalKey, logicalText),
|
|
45
70
|
});
|
|
46
|
-
futurePronunciation.push(...pronunciationFutureValues(context, text.glossary, text.article, logicalKey, logicalText));
|
|
71
|
+
futurePronunciation.push(...pronunciationFutureValues(context, text.glossary, text.article, logicalKey, logicalText), ...aliasFutureValues(context, logicalKey, logicalText));
|
|
47
72
|
const group = narrationParts(context, logicalKey, logicalText, "body", [text.article.key], recipes, text.glossary);
|
|
48
73
|
if (group.length === 0)
|
|
49
74
|
pending = true;
|
|
@@ -51,10 +76,10 @@ export function audioRecipes(context, text) {
|
|
|
51
76
|
}
|
|
52
77
|
if (transcripts.some((row) => row.effective !== row.original))
|
|
53
78
|
bodyTranscript = ["narration-transcript-v1", transcripts.map((row) => row.effective)];
|
|
54
|
-
if (text.
|
|
55
|
-
futurePronunciation.push(...pronunciationFutureValues(context, text.glossary, text.article, "audio:body:future", null));
|
|
79
|
+
if (text.narrationText === null) {
|
|
80
|
+
futurePronunciation.push(...pronunciationFutureValues(context, text.glossary, text.article, "audio:body:future", null), ...aliasFutureValues(context, "audio:body:future", null));
|
|
56
81
|
if (prepare)
|
|
57
|
-
recipes.push(preparationFuture(context, "body", text.article));
|
|
82
|
+
recipes.push(preparationFuture(context, "body", text.article, text.descriptions));
|
|
58
83
|
}
|
|
59
84
|
if (pending && prepare)
|
|
60
85
|
parts.length = 0;
|
|
@@ -69,8 +94,15 @@ export function audioRecipes(context, text) {
|
|
|
69
94
|
chunkingValues(context),
|
|
70
95
|
...(prepare ? [preparationTemplate(context)] : []),
|
|
71
96
|
...futurePronunciation,
|
|
97
|
+
...(text.descriptions.length === 0
|
|
98
|
+
? []
|
|
99
|
+
: [["described-v1", text.descriptions.map((row) => row.fingerprint)]]),
|
|
72
100
|
],
|
|
73
|
-
}, [
|
|
101
|
+
}, [
|
|
102
|
+
text.article.key,
|
|
103
|
+
...text.descriptions.map((row) => row.key),
|
|
104
|
+
...preparationKeys(recipes, "body"),
|
|
105
|
+
]));
|
|
74
106
|
recipes.push(...parts);
|
|
75
107
|
if (narrationFiles)
|
|
76
108
|
recipes.push(narrationFileRecipe(context, "body", parts));
|
|
@@ -81,14 +113,30 @@ export function audioRecipes(context, text) {
|
|
|
81
113
|
values: [
|
|
82
114
|
parts.map((part) => resourceIdentity(context, part)),
|
|
83
115
|
parts.length === 1 ? "copy-single-file" : concatArgs("$parts", "$output"),
|
|
116
|
+
// Pauses between sentences; a paragraph's between pieces cut at paragraphs.
|
|
117
|
+
...pauseValues(config, parts.map((_part, at) => at === parts.length - 1
|
|
118
|
+
? "end"
|
|
119
|
+
: (config.chunking ?? defaultChunking).mode === "paragraph"
|
|
120
|
+
? "paragraph"
|
|
121
|
+
: "sentence")),
|
|
84
122
|
],
|
|
85
|
-
}, parts.map((part) => part.key), { unresolved: text.
|
|
123
|
+
}, parts.map((part) => part.key), { unresolved: text.narrationText !== null && groups.length === 0 });
|
|
86
124
|
recipes.push(body);
|
|
87
125
|
}
|
|
88
126
|
const ordered = [];
|
|
127
|
+
const levels = [];
|
|
128
|
+
const level = (join, segment) => {
|
|
129
|
+
// An uploaded narration is the user's own file: only the exports' master reaches it.
|
|
130
|
+
const levelled = config.sources.audio === "generate" ? levelRecipe(context, join, segment) : undefined;
|
|
131
|
+
if (levelled === undefined)
|
|
132
|
+
return;
|
|
133
|
+
recipes.push(levelled);
|
|
134
|
+
levels.push(levelled);
|
|
135
|
+
};
|
|
89
136
|
for (const category of ["intro", "body", "outro"]) {
|
|
90
137
|
if (category === "body") {
|
|
91
138
|
ordered.push({ value: body, transcript: bodyTranscript });
|
|
139
|
+
level(body, "body");
|
|
92
140
|
continue;
|
|
93
141
|
}
|
|
94
142
|
const entry = text.entries[category];
|
|
@@ -116,6 +164,7 @@ export function audioRecipes(context, text) {
|
|
|
116
164
|
voiceValues(context),
|
|
117
165
|
...(prepare ? [preparationTemplate(context)] : []),
|
|
118
166
|
...pronunciationFutureValues(context, text.glossary, text.article, logicalKey, entry.text),
|
|
167
|
+
...aliasFutureValues(context, logicalKey, entry.text),
|
|
119
168
|
],
|
|
120
169
|
}, [...dependencies, ...preparationKeys(recipes, category)], invalidGlossary === undefined ? {} : { unresolved: true, refusal: invalidGlossary }));
|
|
121
170
|
recipes.push(...parts);
|
|
@@ -126,9 +175,11 @@ export function audioRecipes(context, text) {
|
|
|
126
175
|
values: [
|
|
127
176
|
parts.map((part) => resourceIdentity(context, part)),
|
|
128
177
|
parts.length === 1 ? "copy-single-file" : concatArgs("$parts", "$output"),
|
|
178
|
+
...pauseValues(config, parts.map((_part, at) => (at === parts.length - 1 ? "end" : "sentence"))),
|
|
129
179
|
],
|
|
130
180
|
}, parts.map((part) => part.key));
|
|
131
181
|
recipes.push(audio);
|
|
182
|
+
level(audio, category);
|
|
132
183
|
if (narrationFiles)
|
|
133
184
|
recipes.push(narrationFileRecipe(context, category, parts));
|
|
134
185
|
ordered.push({
|
|
@@ -158,6 +209,9 @@ export function audioRecipes(context, text) {
|
|
|
158
209
|
]),
|
|
159
210
|
timeline,
|
|
160
211
|
keys: ordered.map(({ value }) => value.key),
|
|
212
|
+
levels,
|
|
213
|
+
...(sections === undefined ? {} : { sections }),
|
|
214
|
+
...(cards.length === 0 ? {} : { cards }),
|
|
161
215
|
};
|
|
162
216
|
}
|
|
163
217
|
function effectiveText(context, key, original) {
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
import { referenceForThumbnail } from "../admission/rules.js";
|
|
1
2
|
import { audioRecipes } from "./recipe-audio.js";
|
|
2
3
|
import { documentRecipes } from "./recipe-document.js";
|
|
3
4
|
import { editPlan } from "./recipe-edit.js";
|
|
4
5
|
import { exportRecipes } from "./recipe-exports.js";
|
|
6
|
+
import { masterPlan } from "./recipe-loudness.js";
|
|
7
|
+
import { resourceIdentity } from "./recipe-model.js";
|
|
8
|
+
import { imageReference, referenceRecipe } from "./recipe-reference.js";
|
|
9
|
+
import { withReviews } from "./recipe-reviews.js";
|
|
5
10
|
import { shortsRecipes } from "./recipe-shorts.js";
|
|
6
11
|
import { textRecipes } from "./recipe-text.js";
|
|
7
12
|
import { thumbnailRecipes, visualAssets, visualRecipes } from "./recipe-visual.js";
|
|
@@ -11,16 +16,21 @@ export function buildRecipes(context) {
|
|
|
11
16
|
const audio = audioRecipes(context, text);
|
|
12
17
|
const exports = exportRecipes(context, audio);
|
|
13
18
|
const captions = exports.find((value) => value.key === "subtitles:files");
|
|
14
|
-
const
|
|
19
|
+
const timing = exports.find((value) => value.key === "subtitles:timing");
|
|
20
|
+
// The establishing image, when it is on: every other image is drawn from it.
|
|
21
|
+
const reference = referenceRecipe(context);
|
|
22
|
+
const drawnFrom = imageReference(context, reference);
|
|
23
|
+
const thumbnail = thumbnailRecipes(context, text.recipes, referenceForThumbnail(context.config) ? drawnFrom : undefined);
|
|
15
24
|
const youtube = youtubeRecipes(context, exports);
|
|
16
|
-
return [
|
|
25
|
+
return withReviews(context, [
|
|
17
26
|
...text.recipes,
|
|
18
27
|
...audio.recipes,
|
|
19
28
|
...exports,
|
|
20
29
|
...youtube,
|
|
21
|
-
...
|
|
30
|
+
...(reference === undefined ? [] : [reference]),
|
|
31
|
+
...shortsRecipes(context, exports, drawnFrom, audio.cards ?? [], masterPlan(context, audio.levels, "video")),
|
|
22
32
|
...thumbnail,
|
|
23
33
|
...documentRecipes(context, text, thumbnail),
|
|
24
|
-
...visualAssets(context, visualRecipes(context.config, context.content, audio.mediaFingerprint, captions?.fingerprint ?? null, (images) => editPlan(context, exports, youtube, images))),
|
|
25
|
-
];
|
|
34
|
+
...visualAssets(context, visualRecipes(context.config, context.content, audio.mediaFingerprint, captions?.fingerprint ?? null, (images) => editPlan(context, exports, youtube, images, audio.cards ?? []), drawnFrom, timing === undefined ? null : resourceIdentity(context, timing), masterPlan(context, audio.levels, "video"))),
|
|
35
|
+
]);
|
|
26
36
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { castMentions } from "../channels/cast-match.js";
|
|
2
|
+
// The cast members an image request is drawn with: the ones its texts mention, at most
|
|
3
|
+
// `castMembersPerImage` of them in the order they are first mentioned. Undefined when none is,
|
|
4
|
+
// so the request - and its fingerprint - is exactly what it was before the channel had a cast.
|
|
5
|
+
// A member's name and description go with its pictures, since the note that introduces each
|
|
6
|
+
// picture to the provider names them.
|
|
7
|
+
export const castMembersPerImage = 4;
|
|
8
|
+
export function castFor(config, ...texts) {
|
|
9
|
+
const text = texts.filter((value) => typeof value === "string" && value !== "").join("\n");
|
|
10
|
+
const mentioned = castMentions(text, config.cast).slice(0, castMembersPerImage);
|
|
11
|
+
return mentioned.length === 0
|
|
12
|
+
? undefined
|
|
13
|
+
: mentioned.map((member) => ({
|
|
14
|
+
name: member.name,
|
|
15
|
+
description: member.description,
|
|
16
|
+
images: member.images,
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { fingerprint } from "../../kernel/runner/work.js";
|
|
2
2
|
import { checkpointClosure, checkpointFingerprint } from "../checkpoints/fingerprint.js";
|
|
3
|
+
import { imageCountsOf } from "../images/scale.js";
|
|
3
4
|
import { buildRecipes } from "./recipe-build.js";
|
|
4
5
|
export function reviewCheckpointSet(runs, catalogue, attachments, fontHash) {
|
|
5
6
|
return runs.flatMap((run, runIndex) => {
|
|
@@ -11,15 +12,16 @@ export function reviewCheckpointSet(runs, catalogue, attachments, fontHash) {
|
|
|
11
12
|
id,
|
|
12
13
|
{ source: "provide", assetId: id, prompt: null, templateKey: null },
|
|
13
14
|
])
|
|
14
|
-
:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
: // The count the run's first revision plans (`revisions/adopt-content.ts`).
|
|
16
|
+
imageCountsOf(config).flatMap((count, index) => Array.from({ length: count }, (_, number) => [
|
|
17
|
+
`${index}:${number}`,
|
|
18
|
+
{
|
|
19
|
+
source: "generate",
|
|
20
|
+
assetId: null,
|
|
21
|
+
prompt: run.rendered[`imagePrompts.${index}`] ?? null,
|
|
22
|
+
templateKey: `imagePrompts.${index}`,
|
|
23
|
+
},
|
|
24
|
+
]));
|
|
23
25
|
const content = {
|
|
24
26
|
articleMarkdown: config.sources.article === "provide" ? config.provided.article : undefined,
|
|
25
27
|
provided: { audio: config.provided.audio, thumbnail: config.provided.thumbnail },
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { usesDescribedNarration, usesFigureCards, usesShorts } from "../admission/rules.js";
|
|
2
|
+
import { describedBlocks, narrationBlocks, spokenNarration, } from "../narration/blocks.js";
|
|
3
|
+
import { describeMessages, spokenPassage } from "../narration/describe.js";
|
|
4
|
+
import { recipe } from "./recipe-model.js";
|
|
5
|
+
import { llmInput, matchingText, renderedPrompt } from "./recipe-text.js";
|
|
6
|
+
// "Describe tables and figures in the narration": one text-model step per table, figure,
|
|
7
|
+
// diagram, equation or code block (`narration:describe:<n>`, in reading order), whose answer
|
|
8
|
+
// is said in the block's place. The narration is chunked, prepared and spoken from that
|
|
9
|
+
// spoken text, so the captions and the word timing follow what is said; the article, the
|
|
10
|
+
// PDF and the reading view keep the block itself.
|
|
11
|
+
//
|
|
12
|
+
// Off (or absent) plans nothing here and the narration is the flattened article, so a project
|
|
13
|
+
// saved before the setting keeps every fingerprint.
|
|
14
|
+
export const describeFutureKey = "narration:describe:future";
|
|
15
|
+
export function describing(context) {
|
|
16
|
+
return usesDescribedNarration(context.config);
|
|
17
|
+
}
|
|
18
|
+
// What a description request is made of before its block is known: the instruction family,
|
|
19
|
+
// the model and the style guidance. The future step's template, so a change to any of them
|
|
20
|
+
// reaches the narration still to be written.
|
|
21
|
+
export function describeTemplate(context) {
|
|
22
|
+
const input = llmInput(context, describeMessages({ kind: "table", index: 1, source: "", section: null }, renderedPrompt(context, "narration"), context.config.language));
|
|
23
|
+
return [
|
|
24
|
+
"narration-description-v1",
|
|
25
|
+
JSON.parse(JSON.stringify({ ...input, thinkingConfig: null })),
|
|
26
|
+
context.config.audio?.skipCode === true,
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
// The step that stands in for the descriptions while the text they describe is unwritten.
|
|
30
|
+
export function describeFuture(context, dependency) {
|
|
31
|
+
return recipe(context, describeFutureKey, "audio", {
|
|
32
|
+
kind: "deferred",
|
|
33
|
+
version: 1,
|
|
34
|
+
operation: "narration-description",
|
|
35
|
+
template: [dependency.fingerprint, describeTemplate(context)],
|
|
36
|
+
}, [dependency.key]);
|
|
37
|
+
}
|
|
38
|
+
// The Markdown's described blocks as steps, numbered from `offset + 1`, and the spoken text
|
|
39
|
+
// once every one of them has answered.
|
|
40
|
+
export function describedText(context, markdown, dependsOn, offset = 0) {
|
|
41
|
+
const { config } = context;
|
|
42
|
+
const blocks = narrationBlocks(markdown, {
|
|
43
|
+
code: config.audio?.skipCode === true ? "skip" : "describe",
|
|
44
|
+
language: config.language,
|
|
45
|
+
});
|
|
46
|
+
const style = renderedPrompt(context, "narration");
|
|
47
|
+
const passages = new Map();
|
|
48
|
+
const cards = [];
|
|
49
|
+
const recipes = describedBlocks(blocks).map((block) => {
|
|
50
|
+
const index = offset + block.index;
|
|
51
|
+
const value = recipe(context, `narration:describe:${String(index)}`, "audio", {
|
|
52
|
+
...llmInput(context, describeMessages(block, style, config.language)),
|
|
53
|
+
describe: {
|
|
54
|
+
kind: block.kind,
|
|
55
|
+
index,
|
|
56
|
+
...(block.image === undefined ? {} : { image: block.image }),
|
|
57
|
+
},
|
|
58
|
+
}, dependsOn);
|
|
59
|
+
const answer = matchingText(context, value, "text");
|
|
60
|
+
passages.set(block.index, answer === null ? null : spokenPassage(answer));
|
|
61
|
+
if (usesFigureCards(config))
|
|
62
|
+
cards.push(cardRecipe(context, block, index, dependsOn));
|
|
63
|
+
return value;
|
|
64
|
+
});
|
|
65
|
+
return {
|
|
66
|
+
recipes,
|
|
67
|
+
cards,
|
|
68
|
+
spoken: spokenNarration(blocks, (block) => passages.get(block.index) ?? null),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// The card the video shows while block `index` is described: drawn locally from the block in
|
|
72
|
+
// the brand kit's title font and colour (the 3.0 look otherwise), in the video's format, and
|
|
73
|
+
// upright too when a 16:9 project makes Shorts. Regenerated with its own token.
|
|
74
|
+
function cardRecipe(context, block, index, dependsOn) {
|
|
75
|
+
const { config } = context;
|
|
76
|
+
const formats = config.format === "16:9" && usesShorts(config) ? ["16:9", "9:16"] : [config.format];
|
|
77
|
+
return recipe(context, `figure:card:${String(index)}`, "images", {
|
|
78
|
+
kind: "local",
|
|
79
|
+
version: 1,
|
|
80
|
+
operation: "figure-card-v1",
|
|
81
|
+
values: {
|
|
82
|
+
kind: block.kind,
|
|
83
|
+
index,
|
|
84
|
+
source: block.source,
|
|
85
|
+
section: block.section,
|
|
86
|
+
image: block.image ?? null,
|
|
87
|
+
formats,
|
|
88
|
+
fontId: config.titleStyle?.fontId ?? config.subtitles?.fontId ?? "default",
|
|
89
|
+
color: config.titleStyle?.color ?? null,
|
|
90
|
+
language: config.language ?? "en",
|
|
91
|
+
},
|
|
92
|
+
}, dependsOn);
|
|
93
|
+
}
|
|
@@ -15,7 +15,7 @@ import { recipe, resourceIdentity, selectedReference, } from "./recipe-model.js"
|
|
|
15
15
|
// that step runs) has landed, so until then one deferred `animate:future` stands in for the
|
|
16
16
|
// requests and carries their cost, the way `shorts:future` does.
|
|
17
17
|
export const animateFutureKey = "animate:future";
|
|
18
|
-
export function editPlan(context, exports, youtube, images) {
|
|
18
|
+
export function editPlan(context, exports, youtube, images, cards = []) {
|
|
19
19
|
const { config } = context;
|
|
20
20
|
const edit = videoEditOf(config);
|
|
21
21
|
if (config.sources.video !== "generate")
|
|
@@ -38,6 +38,13 @@ export function editPlan(context, exports, youtube, images) {
|
|
|
38
38
|
values.push(["look-v1", edit.vignette, edit.grain, edit.grade, edit.atmosphere]);
|
|
39
39
|
if (usesChapterCards(config))
|
|
40
40
|
values.push(["cards-v1", config.subtitles?.fontId ?? "default"]);
|
|
41
|
+
// The brand kit's end screen and title style; nothing when unset, so a project without them
|
|
42
|
+
// keeps its export fingerprint.
|
|
43
|
+
const endScreen = config.endScreen?.text.trim() ?? "";
|
|
44
|
+
if (endScreen !== "")
|
|
45
|
+
values.push(["end-screen-v1", endScreen]);
|
|
46
|
+
if (config.titleStyle !== undefined && (usesChapterCards(config) || endScreen !== ""))
|
|
47
|
+
values.push(["title-style", config.titleStyle.fontId ?? null, config.titleStyle.color ?? null]);
|
|
41
48
|
if (timing !== undefined) {
|
|
42
49
|
values.push(["timing", resourceIdentity(context, timing)]);
|
|
43
50
|
dependsOn.push(timing.key);
|
|
@@ -48,6 +55,11 @@ export function editPlan(context, exports, youtube, images) {
|
|
|
48
55
|
else
|
|
49
56
|
values.push(["chapters", "headings", headingsIdentity(context)]);
|
|
50
57
|
}
|
|
58
|
+
// "Show tables and figures on screen": each card, placed where its description is spoken.
|
|
59
|
+
if (cards.length > 0) {
|
|
60
|
+
values.push(["figure-cards-v1", cards.map((value) => resourceIdentity(context, value))]);
|
|
61
|
+
dependsOn.push(...cards.map((value) => value.key));
|
|
62
|
+
}
|
|
51
63
|
const recipes = usesAnimation(config)
|
|
52
64
|
? animateRecipes(context, images, timing, fromDescription ? description : undefined)
|
|
53
65
|
: [];
|
|
@@ -1,12 +1,21 @@
|
|
|
1
|
+
import { projectLanguage } from "../../kernel/ports/languages.js";
|
|
1
2
|
import { usesShorts, usesYoutubeDescription } from "../admission/rules.js";
|
|
3
|
+
import { usesShortMode } from "../admission/short-mode.js";
|
|
4
|
+
import { reviewsNarration } from "../reviews/rules.js";
|
|
5
|
+
import { timingOperation } from "../subtitles/model.js";
|
|
2
6
|
import { audioExportArgs } from "../video/audio-export-args.js";
|
|
3
7
|
import { editNeedsTiming } from "../video/edit-settings.js";
|
|
8
|
+
import { usesVoices } from "../voices/model.js";
|
|
9
|
+
import { portraitValues } from "../voices/portraits.js";
|
|
10
|
+
import { masterPlan } from "./recipe-loudness.js";
|
|
4
11
|
import { recipe, resourceIdentity, } from "./recipe-model.js";
|
|
5
12
|
export function exportRecipes(context, audio) {
|
|
6
13
|
const { config, content } = context;
|
|
7
14
|
if (audio.mediaFingerprint === null)
|
|
8
15
|
return [];
|
|
9
16
|
const recipes = [];
|
|
17
|
+
// Level the volume: the listening files are mastered to the audio files' target.
|
|
18
|
+
const master = masterPlan(context, audio.levels, "audioFiles");
|
|
10
19
|
if (config.sources.video === "off")
|
|
11
20
|
recipes.push(recipe(context, "export:wav", "video", {
|
|
12
21
|
kind: "local",
|
|
@@ -15,30 +24,51 @@ export function exportRecipes(context, audio) {
|
|
|
15
24
|
values: [
|
|
16
25
|
audio.mediaFingerprint,
|
|
17
26
|
audioExportArgs([{ kind: "body", path: "$body", seconds: 0 }], "$output"),
|
|
27
|
+
...master.values,
|
|
18
28
|
],
|
|
19
|
-
}, audio.keys));
|
|
29
|
+
}, [...audio.keys, ...master.keys]));
|
|
20
30
|
const captions = config.subtitles !== undefined && config.subtitles.mode !== "off";
|
|
21
|
-
// The YouTube description's chapters, the shorts' clips and captions,
|
|
22
|
-
// chapter cards and chapter openers use the same word timing,
|
|
23
|
-
// captions off; only the caption files below wait for captions.
|
|
31
|
+
// The YouTube description's chapters, the shorts' clips and captions, a short's own
|
|
32
|
+
// captions, and the video's cuts, chapter cards and chapter openers use the same word timing,
|
|
33
|
+
// so it runs for them even with captions off; only the caption files below wait for captions.
|
|
34
|
+
const voices = usesVoices(config) ? config.voices : undefined;
|
|
24
35
|
if (!captions &&
|
|
25
36
|
!usesYoutubeDescription(config) &&
|
|
26
37
|
!usesShorts(config) &&
|
|
27
|
-
!
|
|
38
|
+
!usesShortMode(config) &&
|
|
39
|
+
!editNeedsTiming(config) &&
|
|
40
|
+
!reviewsNarration(config) &&
|
|
41
|
+
voices?.audioFiles !== true)
|
|
28
42
|
return recipes;
|
|
29
43
|
const timing = recipe(context, "subtitles:timing", "video", {
|
|
30
44
|
kind: "local",
|
|
31
45
|
version: 1,
|
|
32
|
-
operation:
|
|
46
|
+
operation: timingOperation(projectLanguage(config)),
|
|
33
47
|
// The lead-in moves every word, so the edge silence is part of the timing.
|
|
34
48
|
values: [
|
|
35
49
|
audio.timeline,
|
|
36
50
|
config.silenceGapSeconds,
|
|
37
|
-
|
|
51
|
+
// The project language; an English project reads "en" here as it always did.
|
|
52
|
+
config.language ?? config.subtitles?.language ?? "en",
|
|
38
53
|
config.edgeSilenceSeconds,
|
|
54
|
+
// Each word learns its speaker and turn on a multi-voice run.
|
|
55
|
+
...(voices === undefined ? [] : ["voice-words-v1"]),
|
|
39
56
|
],
|
|
40
57
|
}, audio.keys);
|
|
41
58
|
recipes.push(timing);
|
|
59
|
+
if (voices?.audioFiles === true)
|
|
60
|
+
recipes.push(recipe(context, "voices:files", "video", {
|
|
61
|
+
kind: "local",
|
|
62
|
+
version: 1,
|
|
63
|
+
operation: "audio-files-v1",
|
|
64
|
+
values: [
|
|
65
|
+
audio.mediaFingerprint,
|
|
66
|
+
resourceIdentity(context, timing),
|
|
67
|
+
(audio.sections ?? []).map((section) => [section.title, section.firstTurn]),
|
|
68
|
+
config.title,
|
|
69
|
+
...master.values,
|
|
70
|
+
],
|
|
71
|
+
}, [...audio.keys, timing.key, ...master.keys], { unresolved: audio.sections === undefined }));
|
|
42
72
|
if (config.subtitles === undefined || config.subtitles.mode === "off")
|
|
43
73
|
return recipes;
|
|
44
74
|
const cues = content.subtitleCues;
|
|
@@ -53,7 +83,12 @@ export function exportRecipes(context, audio) {
|
|
|
53
83
|
kind: "local",
|
|
54
84
|
version: 1,
|
|
55
85
|
operation: "manual-cues-v1",
|
|
56
|
-
|
|
86
|
+
// A cue's speaker only when it has one, so captions edited before speakers were
|
|
87
|
+
// kept (and every one-voice run's) keep their fingerprint.
|
|
88
|
+
values: [
|
|
89
|
+
cues.audioFingerprint,
|
|
90
|
+
cues.cues.map(({ speaker, ...cue }) => speaker === undefined ? { ...cue } : { ...cue, speaker }),
|
|
91
|
+
],
|
|
57
92
|
}, audio.keys);
|
|
58
93
|
recipes.push(cueRecipe);
|
|
59
94
|
recipes.push(recipe(context, "subtitles:files", "video", {
|
|
@@ -66,6 +101,11 @@ export function exportRecipes(context, audio) {
|
|
|
66
101
|
config.subtitles.fontId,
|
|
67
102
|
config.subtitles.fontSize,
|
|
68
103
|
config.subtitles.position,
|
|
104
|
+
// Only when the brand kit set them, so captions made before keep their fingerprint.
|
|
105
|
+
...(config.subtitles.color === undefined && config.subtitles.outlineColor === undefined
|
|
106
|
+
? []
|
|
107
|
+
: [["colours", config.subtitles.color ?? null, config.subtitles.outlineColor ?? null]]),
|
|
108
|
+
...(voices === undefined ? [] : [captionSpeakerValues(voices, audio.mediaFingerprint)]),
|
|
69
109
|
],
|
|
70
110
|
}, [cueRecipe.key]));
|
|
71
111
|
return recipes;
|
|
@@ -80,3 +120,17 @@ export function manualCuesNeedReview(context, recipes) {
|
|
|
80
120
|
cues.audioFingerprint !==
|
|
81
121
|
context.manifest.outputs.find((value) => value.workKey === timing.key && value.state === "ready")?.fingerprint);
|
|
82
122
|
}
|
|
123
|
+
// How the captions show the speakers: names, colours by place, name tags and, for a podcast or
|
|
124
|
+
// interview, the speaker panel, which runs to the end of the narration. The panel's portraits
|
|
125
|
+
// only when a speaker has one; the render reads the caption file's fingerprint, so it follows.
|
|
126
|
+
function captionSpeakerValues(voices, media) {
|
|
127
|
+
const portraits = portraitValues(voices);
|
|
128
|
+
return [
|
|
129
|
+
"voice-captions-v1",
|
|
130
|
+
voices.format,
|
|
131
|
+
voices.nameTags,
|
|
132
|
+
voices.speakers.map((speaker) => [speaker.id, speaker.name.trim()]),
|
|
133
|
+
media,
|
|
134
|
+
...(portraits === undefined ? [] : [["portraits", [...portraits]]]),
|
|
135
|
+
];
|
|
136
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { messageRoles, thinkingModes } from "../../kernel/ports/llm.js";
|
|
3
3
|
import { llmDocumentsSchema } from "../../kernel/ports/llm-documents.js";
|
|
4
|
+
import { describedKinds } from "../narration/blocks.js";
|
|
4
5
|
import { deferredOperations, localOperations } from "./recipe-model.js";
|
|
5
6
|
const value = z.lazy(() => z.union([
|
|
6
7
|
z.null(),
|
|
@@ -23,7 +24,9 @@ export const recipeInputSchema = z.discriminatedUnion("kind", [
|
|
|
23
24
|
.object({
|
|
24
25
|
budget: z.number().finite().optional(),
|
|
25
26
|
level: z.enum(["minimal", "low", "medium", "high"]).optional(),
|
|
26
|
-
effort: z
|
|
27
|
+
effort: z
|
|
28
|
+
.enum(["none", "minimal", "low", "medium", "high", "xhigh", "max", "ultra"])
|
|
29
|
+
.optional(),
|
|
27
30
|
})
|
|
28
31
|
.strict()
|
|
29
32
|
.nullable(),
|
|
@@ -40,6 +43,22 @@ export const recipeInputSchema = z.discriminatedUnion("kind", [
|
|
|
40
43
|
})
|
|
41
44
|
.strict()
|
|
42
45
|
.optional(),
|
|
46
|
+
// A multi-voice run's script or speaker split: the answer is checked as a script.
|
|
47
|
+
script: z
|
|
48
|
+
.object({
|
|
49
|
+
speakers: z.array(z.object({ id: z.string(), name: z.string() }).strict()),
|
|
50
|
+
attribute: z.boolean(),
|
|
51
|
+
})
|
|
52
|
+
.strict()
|
|
53
|
+
.optional(),
|
|
54
|
+
describe: z
|
|
55
|
+
.object({
|
|
56
|
+
kind: z.enum(describedKinds),
|
|
57
|
+
index: z.number().int().positive(),
|
|
58
|
+
image: z.string().optional(),
|
|
59
|
+
})
|
|
60
|
+
.strict()
|
|
61
|
+
.optional(),
|
|
43
62
|
})
|
|
44
63
|
.strict(),
|
|
45
64
|
z
|
|
@@ -56,6 +75,19 @@ export const recipeInputSchema = z.discriminatedUnion("kind", [
|
|
|
56
75
|
segment: z.enum(["body", "intro", "outro"]),
|
|
57
76
|
pronunciation: z.null(),
|
|
58
77
|
wholeRequest: z.boolean().optional(),
|
|
78
|
+
// A multi-voice run's turn requests; without them every such piece failed to store.
|
|
79
|
+
speaker: z.string().optional(),
|
|
80
|
+
turn: z.number().int().optional(),
|
|
81
|
+
dialogue: z
|
|
82
|
+
.array(z
|
|
83
|
+
.object({
|
|
84
|
+
speaker: z.string(),
|
|
85
|
+
turn: z.number().int(),
|
|
86
|
+
voice: z.string(),
|
|
87
|
+
text: z.string(),
|
|
88
|
+
})
|
|
89
|
+
.strict())
|
|
90
|
+
.optional(),
|
|
59
91
|
})
|
|
60
92
|
.strict(),
|
|
61
93
|
z
|
|
@@ -67,6 +99,16 @@ export const recipeInputSchema = z.discriminatedUnion("kind", [
|
|
|
67
99
|
prompt: z.string(),
|
|
68
100
|
aspect: z.enum(["16:9", "9:16"]),
|
|
69
101
|
animate: z.object({ image: z.string(), seconds: z.number() }).strict().optional(),
|
|
102
|
+
thinking: z.enum(thinkingModes).optional(),
|
|
103
|
+
reference: z
|
|
104
|
+
.object({ fingerprint: z.string(), assetId: z.string().nullable() })
|
|
105
|
+
.strict()
|
|
106
|
+
.optional(),
|
|
107
|
+
cast: z
|
|
108
|
+
.array(z
|
|
109
|
+
.object({ name: z.string(), description: z.string(), images: z.array(z.string()) })
|
|
110
|
+
.strict())
|
|
111
|
+
.optional(),
|
|
70
112
|
})
|
|
71
113
|
.strict(),
|
|
72
114
|
z
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { referenceKey } from "../admission/model.js";
|
|
2
3
|
import { buildRecipes } from "./recipe-build.js";
|
|
3
4
|
export function baselineFingerprints(project, outputs, pieces, content, stages = []) {
|
|
4
5
|
const recipes = buildRecipes({
|
|
@@ -34,6 +35,15 @@ export function legacyOutputWorkKey(output, config) {
|
|
|
34
35
|
return `image:${output.id}`;
|
|
35
36
|
case "thumbnail":
|
|
36
37
|
return "thumbnail:image";
|
|
38
|
+
case "script_md":
|
|
39
|
+
return "script:attribute";
|
|
40
|
+
case "audio_mp3":
|
|
41
|
+
case "audio_m4b":
|
|
42
|
+
return "voices:files";
|
|
43
|
+
case "audio_levelled":
|
|
44
|
+
return `level:${output.meta.segment ?? "body"}`;
|
|
45
|
+
case "reference":
|
|
46
|
+
return referenceKey;
|
|
37
47
|
case "notes":
|
|
38
48
|
return "research:notes";
|
|
39
49
|
case "article_md":
|
|
@@ -68,6 +78,8 @@ export function legacyOutputWorkKey(output, config) {
|
|
|
68
78
|
// Only ever made by a revision, never by the legacy stages.
|
|
69
79
|
case "animated_image":
|
|
70
80
|
return `animate:${String(output.meta.index ?? 1)}`;
|
|
81
|
+
case "figure_card":
|
|
82
|
+
return `figure:card:${String(output.meta.index ?? 1)}`;
|
|
71
83
|
case "subtitles_srt":
|
|
72
84
|
case "subtitles_vtt":
|
|
73
85
|
case "subtitle_ass":
|