@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
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { pieceLufs, pieceTruePeak, truePeakOf, usesLoudness, } from "../loudness/model.js";
|
|
2
|
+
import { recipe, resourceIdentity, } from "./recipe-model.js";
|
|
3
|
+
// Level the volume (`loudness/model.ts`): beside each narration join, a step that joins the
|
|
4
|
+
// same pieces again, each brought to one loudness first. The plain join stays what it was, and
|
|
5
|
+
// the word timing keeps reading it, so turning the setting on never makes the timing, or the
|
|
6
|
+
// description, shorts and reviews written from it, again: only these steps and the exports that
|
|
7
|
+
// play their files. The keys are outside `audio:` on purpose, where the narration's own pieces
|
|
8
|
+
// and joins are recognised by their keys.
|
|
9
|
+
export const levelOperation = "level-narration-v1";
|
|
10
|
+
export function levelKey(segment) {
|
|
11
|
+
return `level:${segment}`;
|
|
12
|
+
}
|
|
13
|
+
export function levelRecipe(context, join, segment) {
|
|
14
|
+
if (!usesLoudness(context.config) || join.input.kind !== "local")
|
|
15
|
+
return undefined;
|
|
16
|
+
return recipe(context, levelKey(segment), "audio", {
|
|
17
|
+
kind: "local",
|
|
18
|
+
version: 1,
|
|
19
|
+
operation: levelOperation,
|
|
20
|
+
// The join it repeats, as that join's own recipe has it: the pieces and their layout.
|
|
21
|
+
values: [
|
|
22
|
+
join.input.operation,
|
|
23
|
+
join.input.values,
|
|
24
|
+
["piece-level-v1", pieceLufs, pieceTruePeak],
|
|
25
|
+
],
|
|
26
|
+
}, join.dependsOn, { unresolved: join.unresolved });
|
|
27
|
+
}
|
|
28
|
+
export const noMaster = { values: [], keys: [] };
|
|
29
|
+
export function masterPlan(context, levels, target) {
|
|
30
|
+
const settings = context.config.loudness;
|
|
31
|
+
if (!usesLoudness(context.config) || settings === undefined)
|
|
32
|
+
return noMaster;
|
|
33
|
+
const lufs = target === "video" ? settings.videoLufs : settings.audioFilesLufs;
|
|
34
|
+
return {
|
|
35
|
+
values: [
|
|
36
|
+
[
|
|
37
|
+
"loudness-v1",
|
|
38
|
+
levels.map((level) => resourceIdentity(context, level)),
|
|
39
|
+
lufs,
|
|
40
|
+
truePeakOf(target),
|
|
41
|
+
],
|
|
42
|
+
],
|
|
43
|
+
keys: levels.map((level) => level.key),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -4,6 +4,8 @@ import { narrationRegenerationToken, narrationRequestFingerprint } from "../narr
|
|
|
4
4
|
export const localOperations = [
|
|
5
5
|
"export-wav",
|
|
6
6
|
"wav2vec2-en-a19f851-v2-omissions",
|
|
7
|
+
"wav2vec2-xlsr56-2d48b01-v1",
|
|
8
|
+
"sentence-timing-v1",
|
|
7
9
|
"automatic-cues-v1",
|
|
8
10
|
"manual-cues-v1",
|
|
9
11
|
"subtitle-files-v1",
|
|
@@ -19,9 +21,16 @@ export const localOperations = [
|
|
|
19
21
|
"youtube-description-v1",
|
|
20
22
|
"shorts-pick-v1",
|
|
21
23
|
"short-render-v1",
|
|
24
|
+
"review-v1",
|
|
25
|
+
"concat-turns-v1",
|
|
26
|
+
"voice-captions-v1",
|
|
27
|
+
"audio-files-v1",
|
|
28
|
+
"level-narration-v1",
|
|
29
|
+
"figure-card-v1",
|
|
22
30
|
];
|
|
23
31
|
export const deferredOperations = [
|
|
24
32
|
"narration-preparation",
|
|
33
|
+
"narration-description",
|
|
25
34
|
"research-synthesis",
|
|
26
35
|
"article",
|
|
27
36
|
"entry:intro:text",
|
|
@@ -34,14 +43,24 @@ export const deferredOperations = [
|
|
|
34
43
|
"resolve-revision-recipe",
|
|
35
44
|
"shorts",
|
|
36
45
|
"animate",
|
|
46
|
+
"script-attribution",
|
|
37
47
|
];
|
|
38
48
|
export function recipe(context, key, stage, input, dependsOn = [], options = {}) {
|
|
39
|
-
const requestFingerprint = input.kind === "tts"
|
|
40
|
-
?
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
const requestFingerprint = input.kind === "tts" && input.dialogue !== undefined
|
|
50
|
+
? // One request, several voices: every line's voice and words are what was sent.
|
|
51
|
+
fingerprint([
|
|
52
|
+
"narration-dialogue-v1",
|
|
53
|
+
input.provider,
|
|
54
|
+
input.model,
|
|
55
|
+
input.dialogue.map((line) => [line.voice, line.text]),
|
|
56
|
+
input.segment,
|
|
57
|
+
])
|
|
58
|
+
: input.kind === "tts"
|
|
59
|
+
? narrationRequestFingerprint({
|
|
60
|
+
...input,
|
|
61
|
+
wholeText: input.wholeRequest === true ? input.logicalText : null,
|
|
62
|
+
})
|
|
63
|
+
: fingerprint(JSON.parse(JSON.stringify(input, (_key, value) => typeof value === "number" ? z.number().finite().parse(value) : value)));
|
|
45
64
|
const token = input.kind === "tts"
|
|
46
65
|
? narrationRegenerationToken(context.content.regenerationTokens, input.logicalKey, input.segment)
|
|
47
66
|
: options.token !== undefined
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { pausesOf } from "../narration/pauses-model.js";
|
|
2
|
+
export function pauseValues(config, next) {
|
|
3
|
+
const pauses = pausesOf(config);
|
|
4
|
+
if (pauses === undefined)
|
|
5
|
+
return [];
|
|
6
|
+
return [["pauses-v1", pauses.sentenceSeconds, pauses.paragraphSeconds, [...next]]];
|
|
7
|
+
}
|
|
@@ -4,7 +4,7 @@ import { prepareRequests } from "../narration/steering.js";
|
|
|
4
4
|
import { recipe, selectedReference, } from "./recipe-model.js";
|
|
5
5
|
import { llmInput, renderedPrompt } from "./recipe-text.js";
|
|
6
6
|
export function preparationTemplate(context) {
|
|
7
|
-
const input = llmInput(context, preparationMessages(renderedPrompt(context, "narration"), ""));
|
|
7
|
+
const input = llmInput(context, preparationMessages(renderedPrompt(context, "narration"), "", [], context.config.language));
|
|
8
8
|
return [
|
|
9
9
|
"inworld-tts-2",
|
|
10
10
|
1,
|
|
@@ -25,9 +25,9 @@ export function preparationFuture(context, segment, dependency, additionalDepend
|
|
|
25
25
|
],
|
|
26
26
|
}, [...new Set([dependency.key, ...additionalDependencies.map((row) => row.key)])]);
|
|
27
27
|
}
|
|
28
|
-
export function preparationForGroup(context, logicalKey, source, segment, dependsOn, maxCharacters, spans = []) {
|
|
28
|
+
export function preparationForGroup(context, logicalKey, source, segment, dependsOn, maxCharacters, spans = [], aliases = [], speaker) {
|
|
29
29
|
const preparation = recipe(context, `narration:prepare:${segment}:${logicalKey}`, "audio", {
|
|
30
|
-
...llmInput(context, preparationMessages(renderedPrompt(context, "narration"), source)),
|
|
30
|
+
...llmInput(context, preparationMessages(renderedPrompt(context, "narration"), source, aliases, context.config.language, speaker)),
|
|
31
31
|
preparation: { format: "inworld-tts-2", version: 1, source, logicalKey, segment },
|
|
32
32
|
}, dependsOn, { unresolved: source.trim() === "" });
|
|
33
33
|
if (source.trim() === "")
|
|
@@ -5,6 +5,16 @@ export function recipeProviderChoice(recipe, config) {
|
|
|
5
5
|
// The YouTube description's request is built when it runs, from the project's LLM row.
|
|
6
6
|
if (input.kind === "local" && input.operation === "youtube-description-v1")
|
|
7
7
|
return config.llm === undefined ? undefined : { ...config.llm, family: "llm" };
|
|
8
|
+
// A review's request is built when it runs, from the reviewer the project chose.
|
|
9
|
+
if (input.kind === "local" && input.operation === "review-v1")
|
|
10
|
+
return config.reviews === undefined
|
|
11
|
+
? undefined
|
|
12
|
+
: {
|
|
13
|
+
provider: config.reviews.provider,
|
|
14
|
+
model: config.reviews.model,
|
|
15
|
+
...(config.reviews.thinking === undefined ? {} : { thinking: config.reviews.thinking }),
|
|
16
|
+
family: "llm",
|
|
17
|
+
};
|
|
8
18
|
// So is the shorts' pick; what stands in for the rest of the step until it lands is
|
|
9
19
|
// mostly images, which are its cost.
|
|
10
20
|
if (input.kind === "local" && input.operation === "shorts-pick-v1")
|
|
@@ -22,7 +32,7 @@ export function recipeProviderChoice(recipe, config) {
|
|
|
22
32
|
};
|
|
23
33
|
if (input.kind !== "deferred")
|
|
24
34
|
return undefined;
|
|
25
|
-
const family = input.operation === "narration-preparation"
|
|
35
|
+
const family = input.operation === "narration-preparation" || input.operation === "narration-description"
|
|
26
36
|
? "llm"
|
|
27
37
|
: recipe.stage === "audio"
|
|
28
38
|
? "tts"
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { referenceKey } from "../admission/model.js";
|
|
2
|
+
import { usesReference } from "../admission/rules.js";
|
|
3
|
+
import { castFor } from "./recipe-cast.js";
|
|
4
|
+
import { recipe, selectedAsset, } from "./recipe-model.js";
|
|
5
|
+
import { renderedPrompt } from "./recipe-text.js";
|
|
6
|
+
// The establishing image (`RunDraft.reference`): one step of the Images stage, made before
|
|
7
|
+
// every other image of the run and never part of the video. Made from its library prompt, whose
|
|
8
|
+
// keywords are filled like every other image prompt's, or the file the user uploaded.
|
|
9
|
+
export const referencePromptKey = "referencePrompt";
|
|
10
|
+
// The image provider's choice as an image request carries it: the effort only when one is set,
|
|
11
|
+
// so a request made without one keeps the fingerprint it always had.
|
|
12
|
+
export function imageChoice(config) {
|
|
13
|
+
return {
|
|
14
|
+
provider: config.images?.provider ?? "",
|
|
15
|
+
model: config.images?.model ?? "",
|
|
16
|
+
...(config.images?.thinking === undefined ? {} : { thinking: config.images.thinking }),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export function referenceRecipe(context) {
|
|
20
|
+
const { config, content } = context;
|
|
21
|
+
if (!usesReference(config) || config.reference === undefined)
|
|
22
|
+
return undefined;
|
|
23
|
+
if (config.reference.source === "provide")
|
|
24
|
+
return recipe(context, referenceKey, "images", {
|
|
25
|
+
kind: "provided",
|
|
26
|
+
version: 1,
|
|
27
|
+
assetId: content.provided.reference ?? null,
|
|
28
|
+
semantic: "reference",
|
|
29
|
+
}, [], { unresolved: content.provided.reference === undefined });
|
|
30
|
+
const prompt = renderedPrompt(context, referencePromptKey);
|
|
31
|
+
return recipe(context, referenceKey, "images", {
|
|
32
|
+
kind: "image",
|
|
33
|
+
version: 1,
|
|
34
|
+
...imageChoice(config),
|
|
35
|
+
aspect: config.format,
|
|
36
|
+
prompt,
|
|
37
|
+
// The establishing image sets the look for the whole video, so it is drawn with every
|
|
38
|
+
// member the title mentions as well as the ones its own brief does.
|
|
39
|
+
...castField(castFor(config, config.title, prompt)),
|
|
40
|
+
}, [], { unresolved: prompt.trim() === "" });
|
|
41
|
+
}
|
|
42
|
+
// Which image the others are drawn from: the step's fingerprint, so making it again or
|
|
43
|
+
// changing it marks every image drawn from it outdated, and the asset it made.
|
|
44
|
+
export function imageReference(context, reference) {
|
|
45
|
+
return reference === undefined
|
|
46
|
+
? undefined
|
|
47
|
+
: {
|
|
48
|
+
key: reference.key,
|
|
49
|
+
input: {
|
|
50
|
+
fingerprint: reference.fingerprint,
|
|
51
|
+
assetId: selectedAsset(context, reference.key, reference.fingerprint),
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
// The request's `cast`, only when some member is mentioned.
|
|
56
|
+
export function castField(cast) {
|
|
57
|
+
return cast === undefined ? {} : { cast };
|
|
58
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { narrationItemKey, reviewKey, reviewModeOf, reviewPromptKey, reviewRetriesOf, } from "../reviews/model.js";
|
|
2
|
+
import { activeReviewStages } from "../reviews/rules.js";
|
|
3
|
+
import { recipe, resourceIdentity, } from "./recipe-model.js";
|
|
4
|
+
import { renderedPrompt } from "./recipe-text.js";
|
|
5
|
+
// A review is a step of its own, `review:<item>`, planned like any other: it waits for the
|
|
6
|
+
// item, its fingerprint follows the item's output, the reviewer and the prompt, and it is
|
|
7
|
+
// kept and reused while those stay the same. What depends on a reviewed item waits for its
|
|
8
|
+
// review too, so the run moves on only once the reviewer has answered - the automatic twin
|
|
9
|
+
// of a review checkpoint. With every review Off nothing here is added and no step changes.
|
|
10
|
+
export function withReviews(context, recipes) {
|
|
11
|
+
const settings = context.config.reviews;
|
|
12
|
+
const stages = activeReviewStages(context.config);
|
|
13
|
+
if (settings === undefined || stages.length === 0)
|
|
14
|
+
return recipes;
|
|
15
|
+
const byKey = new Map(recipes.map((row) => [row.key, row]));
|
|
16
|
+
const items = stages.flatMap((stage) => reviewedItems(stage, recipes, byKey));
|
|
17
|
+
const reviews = items.map((item) => recipe(context, reviewKey(item.itemKey), stageOf(item.stage), {
|
|
18
|
+
kind: "local",
|
|
19
|
+
version: 1,
|
|
20
|
+
operation: "review-v1",
|
|
21
|
+
values: [
|
|
22
|
+
item.stage,
|
|
23
|
+
item.itemKey,
|
|
24
|
+
item.inputs.map((input) => [input.key, resourceIdentity(context, input)]),
|
|
25
|
+
settings.provider,
|
|
26
|
+
settings.model,
|
|
27
|
+
settings.thinking ?? null,
|
|
28
|
+
// Blank means the stage's built-in prompt; the step fills it in, so a new built-in
|
|
29
|
+
// wording ships as a new operation version rather than a silent change here.
|
|
30
|
+
settings.stages[item.stage]?.prompt?.trim()
|
|
31
|
+
? renderedPrompt(context, reviewPromptKey(item.stage))
|
|
32
|
+
: "",
|
|
33
|
+
reviewModeOf(settings, item.stage),
|
|
34
|
+
reviewRetriesOf(settings),
|
|
35
|
+
],
|
|
36
|
+
}, item.inputs.map((input) => input.key),
|
|
37
|
+
// A paid LLM call: readiness, the charge warning and the estimate treat it like one.
|
|
38
|
+
{ kind: "provider" }));
|
|
39
|
+
const gated = recipes.map((row) => {
|
|
40
|
+
const waits = items.flatMap((item, index) => {
|
|
41
|
+
const review = reviews[index];
|
|
42
|
+
if (review === undefined || !row.dependsOn.some((key) => item.gates.includes(key)))
|
|
43
|
+
return [];
|
|
44
|
+
// A step the review itself reads (the word timing the narration review hears) must not
|
|
45
|
+
// wait for it.
|
|
46
|
+
return upstream(review, byKey).has(row.key) ? [] : [review.key];
|
|
47
|
+
});
|
|
48
|
+
return waits.length === 0 ? row : { ...row, dependsOn: [...row.dependsOn, ...waits] };
|
|
49
|
+
});
|
|
50
|
+
return [...gated, ...reviews];
|
|
51
|
+
}
|
|
52
|
+
function reviewedItems(stage, recipes, byKey) {
|
|
53
|
+
const one = (itemKey, inputs, gates) => ({ stage, itemKey, inputs, gates });
|
|
54
|
+
switch (stage) {
|
|
55
|
+
case "article": {
|
|
56
|
+
const article = byKey.get("article:body");
|
|
57
|
+
return article === undefined || article.kind !== "provider"
|
|
58
|
+
? []
|
|
59
|
+
: [one(article.key, [article], [article.key])];
|
|
60
|
+
}
|
|
61
|
+
case "images": {
|
|
62
|
+
const reference = byKey.get("reference:image");
|
|
63
|
+
return recipes
|
|
64
|
+
.filter((row) => row.key.startsWith("image:") && row.input.kind === "image")
|
|
65
|
+
.map((row) => one(row.key, reference === undefined ? [row] : [row, reference], [row.key]));
|
|
66
|
+
}
|
|
67
|
+
// One thumbnail, or each of three when the project makes three to compare.
|
|
68
|
+
case "thumbnail":
|
|
69
|
+
return recipes
|
|
70
|
+
.filter((row) => /^thumbnail:image(?::\d+)?$/.test(row.key) && row.kind === "provider")
|
|
71
|
+
.map((row) => one(row.key, [row], [row.key]));
|
|
72
|
+
case "narration": {
|
|
73
|
+
const timing = byKey.get("subtitles:timing");
|
|
74
|
+
if (timing === undefined)
|
|
75
|
+
return [];
|
|
76
|
+
const article = byKey.get("article:body");
|
|
77
|
+
return [
|
|
78
|
+
one(narrationItemKey, article === undefined ? [timing] : [timing, article], [
|
|
79
|
+
timing.key,
|
|
80
|
+
...timing.dependsOn,
|
|
81
|
+
]),
|
|
82
|
+
];
|
|
83
|
+
}
|
|
84
|
+
case "shorts":
|
|
85
|
+
return recipes.flatMap((row) => {
|
|
86
|
+
const match = /^(shorts:\d+):render$/.exec(row.key);
|
|
87
|
+
return match?.[1] === undefined ? [] : [one(match[1], [row], [row.key])];
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// The Images stage runs the image reviews and the Video stage the shorts'; the others run in
|
|
92
|
+
// the stage that made the item.
|
|
93
|
+
function stageOf(stage) {
|
|
94
|
+
switch (stage) {
|
|
95
|
+
case "article":
|
|
96
|
+
return "article";
|
|
97
|
+
case "images":
|
|
98
|
+
return "images";
|
|
99
|
+
case "narration":
|
|
100
|
+
return "audio";
|
|
101
|
+
case "thumbnail":
|
|
102
|
+
return "thumbnail";
|
|
103
|
+
case "shorts":
|
|
104
|
+
return "video";
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function upstream(review, byKey) {
|
|
108
|
+
const seen = new Set();
|
|
109
|
+
const queue = [...review.dependsOn];
|
|
110
|
+
for (let key = queue.pop(); key !== undefined; key = queue.pop()) {
|
|
111
|
+
if (seen.has(key))
|
|
112
|
+
continue;
|
|
113
|
+
seen.add(key);
|
|
114
|
+
queue.push(...(byKey.get(key)?.dependsOn ?? []));
|
|
115
|
+
}
|
|
116
|
+
return seen;
|
|
117
|
+
}
|
|
@@ -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,7 +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";
|
|
10
|
+
import { castField, imageChoice } from "./recipe-reference.js";
|
|
8
11
|
import { llmInput, renderedPrompt } from "./recipe-text.js";
|
|
9
12
|
// The Shorts step unfolds as its answers land, the way research's chapters unfold from the
|
|
10
13
|
// plan. `shorts:pick` reads the word timing, so it waits for `subtitles:timing` and runs
|
|
@@ -19,7 +22,13 @@ import { llmInput, renderedPrompt } from "./recipe-text.js";
|
|
|
19
22
|
// can be made again alone.
|
|
20
23
|
export const shortsPickKey = "shorts:pick";
|
|
21
24
|
export const shortsFutureKey = "shorts:future";
|
|
22
|
-
export function shortsRecipes(context, exports
|
|
25
|
+
export function shortsRecipes(context, exports,
|
|
26
|
+
// The establishing image the shorts' images are drawn from, when it is on.
|
|
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) {
|
|
23
32
|
const { config } = context;
|
|
24
33
|
const shorts = config.shorts;
|
|
25
34
|
const timing = exports.find((value) => value.key === "subtitles:timing");
|
|
@@ -41,6 +50,8 @@ export function shortsRecipes(context, exports) {
|
|
|
41
50
|
shorts.minSeconds,
|
|
42
51
|
shorts.maxSeconds,
|
|
43
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]),
|
|
44
55
|
],
|
|
45
56
|
}, [timing.key],
|
|
46
57
|
// A paid LLM call: readiness, the charge warning and the estimate treat it like one.
|
|
@@ -67,6 +78,10 @@ export function shortsRecipes(context, exports) {
|
|
|
67
78
|
shorts.maxSeconds,
|
|
68
79
|
config.llm?.provider ?? "",
|
|
69
80
|
config.llm?.model ?? "",
|
|
81
|
+
// Only what is in use, so shorts planned before these existed keep their
|
|
82
|
+
// fingerprint; the estimate reads the fields above by position.
|
|
83
|
+
...(config.images?.thinking === undefined ? [] : [config.images.thinking]),
|
|
84
|
+
...(reference === undefined ? [] : [reference.input.fingerprint]),
|
|
70
85
|
],
|
|
71
86
|
}, [pick.key], { tokenKey: shortsPickKey }),
|
|
72
87
|
];
|
|
@@ -94,11 +109,12 @@ export function shortsRecipes(context, exports) {
|
|
|
94
109
|
const stills = written.map((prompt, index) => recipe(context, `${prefix}:image:${String(index + 1)}`, "video", {
|
|
95
110
|
kind: "image",
|
|
96
111
|
version: 1,
|
|
97
|
-
|
|
98
|
-
model: images.model,
|
|
112
|
+
...imageChoice(config),
|
|
99
113
|
prompt,
|
|
100
114
|
aspect: "9:16",
|
|
101
|
-
|
|
115
|
+
...(reference === undefined ? {} : { reference: reference.input }),
|
|
116
|
+
...castField(castFor(config, prompt)),
|
|
117
|
+
}, [prompts.key, ...(reference === undefined ? [] : [reference.key])], { token }));
|
|
102
118
|
recipes.push(...stills);
|
|
103
119
|
const extras = renderExtras(context, clip);
|
|
104
120
|
recipes.push(recipe(context, `${prefix}:render`, "video", {
|
|
@@ -118,8 +134,19 @@ export function shortsRecipes(context, exports) {
|
|
|
118
134
|
// Only when one of the later settings is in use, so a short rendered before
|
|
119
135
|
// they existed keeps its fingerprint.
|
|
120
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,
|
|
121
143
|
],
|
|
122
|
-
}, [
|
|
144
|
+
}, [
|
|
145
|
+
pick.key,
|
|
146
|
+
...stills.map((still) => still.key),
|
|
147
|
+
...cards.map((card) => card.key),
|
|
148
|
+
...master.keys,
|
|
149
|
+
], { token }));
|
|
123
150
|
}
|
|
124
151
|
return recipes;
|
|
125
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
|
}
|