@gentbajko/slopify 3.25.9 → 4.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/dist/adapters/account-limits.js +30 -0
- package/dist/adapters/alignment/cache.js +3 -5
- package/dist/adapters/alignment/ctc.js +1 -2
- package/dist/adapters/alignment/lock.js +4 -3
- package/dist/adapters/alignment/multilingual.js +0 -3
- package/dist/adapters/alignment/prefetch.js +2 -1
- package/dist/adapters/alignment/worker.js +2 -1
- package/dist/adapters/explain.js +0 -3
- package/dist/adapters/ffmpeg.js +19 -1
- package/dist/adapters/host-cli/index.js +19 -3
- package/dist/adapters/http-failure.js +53 -0
- package/dist/adapters/image/codex.js +36 -4
- package/dist/adapters/image/fal.js +17 -50
- package/dist/adapters/image/google.js +31 -55
- package/dist/adapters/image/openai.js +20 -47
- package/dist/adapters/image/reference.js +36 -0
- package/dist/adapters/image/replicate.js +18 -47
- package/dist/adapters/interest/search-interest.js +113 -0
- package/dist/adapters/key-probes.js +53 -2
- package/dist/adapters/llm/antigravity.js +4 -0
- package/dist/adapters/llm/assistant-cli.js +388 -0
- package/dist/adapters/llm/child-session.js +83 -0
- package/dist/adapters/llm/claude-code-models.js +51 -98
- package/dist/adapters/llm/claude-code.js +13 -2
- package/dist/adapters/llm/codex-limits.js +27 -68
- package/dist/adapters/llm/codex-server-models.js +61 -109
- package/dist/adapters/llm/codex.js +12 -1
- package/dist/adapters/llm/openrouter.js +10 -47
- package/dist/adapters/llm/run-cli.js +6 -22
- package/dist/adapters/llm/sse-lines.js +5 -1
- package/dist/adapters/model-access.js +37 -0
- package/dist/adapters/tts/cartesia.js +15 -46
- package/dist/adapters/tts/elevenlabs.js +20 -52
- package/dist/adapters/tts/gemini.js +19 -40
- package/dist/adapters/tts/inworld-async.js +4 -1
- package/dist/adapters/tts/inworld.js +3 -0
- package/dist/adapters/tts/openai.js +20 -50
- package/dist/assets/models-lifecycle.yaml +6 -0
- package/dist/assistant-wiring.js +60 -0
- package/dist/autopilot-timers.js +59 -0
- package/dist/catalog/lifecycle.js +52 -0
- package/dist/catalog/propose.js +204 -0
- package/dist/catalog/registry.js +3 -1
- package/dist/catalog/schema.js +2 -0
- package/dist/catalog/store.js +39 -0
- package/dist/edge/autostart/native.js +3 -5
- package/dist/edge/autostart/prompt.js +2 -1
- package/dist/edge/autostart/service.js +3 -4
- package/dist/edge/cli-args.js +3 -4
- package/dist/edge/cli.js +2 -1
- package/dist/edge/docker-install/apply.js +11 -11
- package/dist/edge/docker-install/run.js +2 -1
- package/dist/edge/docker-install/state.js +4 -3
- package/dist/edge/docker-install/tree.js +2 -4
- package/dist/edge/docker-install/volume.js +3 -2
- package/dist/edge/docker.js +5 -4
- package/dist/edge/events/hub.js +5 -5
- package/dist/edge/http/actions.js +4 -25
- package/dist/edge/http/actor.js +5 -3
- package/dist/edge/http/app.js +85 -10
- package/dist/edge/http/assistant.js +127 -0
- package/dist/edge/http/audio-preview.js +4 -11
- package/dist/edge/http/auditions.js +1 -1
- package/dist/edge/http/autostart.js +5 -5
- package/dist/edge/http/backups.js +1 -3
- package/dist/edge/http/channel-memory.js +7 -20
- package/dist/edge/http/channels.js +13 -26
- package/dist/edge/http/checkpoints.js +33 -17
- package/dist/edge/http/design-templates.js +167 -0
- package/dist/edge/http/designs.js +178 -0
- package/dist/edge/http/diagnostics.js +5 -1
- package/dist/edge/http/document-themes.js +2 -11
- package/dist/edge/http/draft-files.js +1 -3
- package/dist/edge/http/draft-problem.js +4 -9
- package/dist/edge/http/drafts.js +3 -3
- package/dist/edge/http/entries.js +6 -9
- package/dist/edge/http/extension-auth.js +27 -0
- package/dist/edge/http/external-reviews.js +12 -11
- package/dist/edge/http/files.js +5 -11
- package/dist/edge/http/folder-location.js +1 -4
- package/dist/edge/http/fonts.js +0 -7
- package/dist/edge/http/home.js +38 -13
- package/dist/edge/http/host-cli.js +18 -8
- package/dist/edge/http/ids.js +8 -0
- package/dist/edge/http/keywords.js +35 -0
- package/dist/edge/http/model-checks.js +132 -0
- package/dist/edge/http/narration-peaks.js +5 -13
- package/dist/edge/http/onboarding.js +1 -14
- package/dist/edge/http/open-folder.js +5 -10
- package/dist/edge/http/outputs.js +4 -12
- package/dist/edge/http/patch-notes.js +4 -10
- package/dist/edge/http/planning.js +2 -6
- package/dist/edge/http/problem.js +2 -4
- package/dist/edge/http/project-create.js +1 -0
- package/dist/edge/http/project-templates.js +29 -17
- package/dist/edge/http/projects.js +2 -12
- package/dist/edge/http/prompts.js +7 -14
- package/dist/edge/http/pronunciations.js +1 -2
- package/dist/edge/http/providers.js +39 -24
- package/dist/edge/http/refusal.js +29 -0
- package/dist/edge/http/remote-access.js +40 -0
- package/dist/edge/http/remote-guard.js +71 -0
- package/dist/edge/http/request-guard.js +91 -0
- package/dist/edge/http/reviews.js +11 -24
- package/dist/edge/http/revision-files.js +5 -10
- package/dist/edge/http/revisions.js +10 -15
- package/dist/edge/http/run-cost.js +1 -2
- package/dist/edge/http/same-page.js +80 -0
- package/dist/edge/http/schedules.js +59 -32
- package/dist/edge/http/settings.js +22 -13
- package/dist/edge/http/social.js +282 -0
- package/dist/edge/http/staging.js +2 -4
- package/dist/edge/http/storage-files.js +5 -7
- package/dist/edge/http/storage.js +23 -23
- package/dist/edge/http/studio.js +23 -50
- package/dist/edge/http/style-preview.js +1 -4
- package/dist/edge/http/subtitles.js +3 -17
- package/dist/edge/http/template-studio.js +433 -0
- package/dist/edge/http/trash.js +10 -11
- package/dist/edge/http/tutorial.js +1 -2
- package/dist/edge/http/tutorials.js +5 -11
- package/dist/edge/http/update.js +7 -13
- package/dist/edge/http/waveform.js +3 -6
- package/dist/edge/http/youtube-edits.js +2 -3
- package/dist/edge/mcp/assistant.js +279 -0
- package/dist/edge/mcp/attribution.js +8 -2
- package/dist/edge/mcp/call-route.js +11 -2
- package/dist/edge/mcp/excluded-routes.js +25 -0
- package/dist/edge/mcp/http.js +11 -2
- package/dist/edge/mcp/instructions.js +5 -3
- package/dist/edge/mcp/library-tools.js +1 -0
- package/dist/edge/mcp/route-tool.js +35 -15
- package/dist/edge/mcp/server.js +13 -8
- package/dist/edge/mcp/tools-channels.js +2 -0
- package/dist/edge/mcp/tools-designs.js +165 -0
- package/dist/edge/mcp/tools-library.js +14 -2
- package/dist/edge/mcp/tools-planning.js +23 -4
- package/dist/edge/mcp/tools-projects.js +28 -1
- package/dist/edge/mcp/tools-runs.js +14 -1
- package/dist/edge/mcp/tools-schedules.js +28 -4
- package/dist/edge/mcp/tools-setup.js +61 -3
- package/dist/edge/mcp/tools-social.js +46 -0
- package/dist/edge/mcp/tools-storage.js +8 -0
- package/dist/edge/mcp/tools-template-studio.js +166 -0
- package/dist/edge/mcp/tools.js +6 -0
- package/dist/edge/remote-access/cli.js +71 -0
- package/dist/edge/remote-access/model.js +32 -0
- package/dist/edge/remote-access/rules.js +207 -0
- package/dist/edge/remote-access/service.js +203 -0
- package/dist/edge/remote-access/store.js +44 -0
- package/dist/edge/remote-access/views.js +43 -0
- package/dist/extension/slopify-studio-chrome.zip +0 -0
- package/dist/extension/slopify-studio-firefox.zip +0 -0
- package/dist/host-cli/install.js +2 -2
- package/dist/host-cli/open-folder.js +2 -2
- package/dist/host-cli/paths.js +2 -4
- package/dist/host-cli/server.js +4 -4
- package/dist/host-cli/service.js +3 -3
- package/dist/host-cli/status.js +7 -7
- package/dist/kernel/db/migrations/0063-model-checks.sql +20 -0
- package/dist/kernel/db/migrations/0064-template-studio.sql +46 -0
- package/dist/kernel/db/migrations/0065-promise-and-assistant-reviews.sql +58 -0
- package/dist/kernel/db/migrations/0066-assistant.sql +44 -0
- package/dist/kernel/db/migrations/0067-autopilot.sql +6 -0
- package/dist/kernel/db/migrations/0068-topic-scores.sql +17 -0
- package/dist/kernel/db/migrations/0070-designs.sql +53 -0
- package/dist/kernel/db/migrations/0071-design-usage.sql +33 -0
- package/dist/kernel/db/migrations/0072-design-templates.sql +33 -0
- package/dist/kernel/db/migrations/0073-schedule-design-kind.sql +5 -0
- package/dist/kernel/db/migrations/0074-template-bakeoffs.sql +44 -0
- package/dist/kernel/db/migrations/0075-social-posts.sql +25 -0
- package/dist/kernel/db/migrations/0076-channel-social.sql +5 -0
- package/dist/kernel/db/migrations/0077-post-prompts.sql +17 -0
- package/dist/kernel/db/tx.js +2 -4
- package/dist/kernel/errors.js +27 -1
- package/dist/kernel/json-answer.js +15 -0
- package/dist/kernel/lock.js +4 -9
- package/dist/kernel/paths.js +8 -0
- package/dist/kernel/ports/assistant-cli.js +4 -0
- package/dist/kernel/ports/host-cli.js +3 -0
- package/dist/kernel/ports/interest.js +4 -0
- package/dist/kernel/ports/languages.js +0 -3
- package/dist/kernel/ports/model.js +2 -0
- package/dist/kernel/runner/attempt.js +3 -1
- package/dist/kernel/runner/audition.js +3 -1
- package/dist/kernel/runner/checkpoint-authority.js +2 -1
- package/dist/kernel/runner/index.js +8 -10
- package/dist/kernel/runner/model-access.js +40 -0
- package/dist/kernel/runner/model-check.js +153 -0
- package/dist/kernel/runner/providers.js +15 -10
- package/dist/kernel/runner/standalone.js +9 -5
- package/dist/main.js +334 -19
- package/dist/model-checks.js +166 -0
- package/dist/patch-notes/4.0.0.md +51 -0
- package/dist/patch-notes/index.json +6 -0
- package/dist/slices/admission/heads.js +2 -1
- package/dist/slices/admission/repo.js +2 -1
- package/dist/slices/admission/rules.js +43 -8
- package/dist/slices/admission/schema.js +8 -0
- package/dist/slices/admission/stage-writes.js +0 -3
- package/dist/slices/admission/start.js +48 -31
- package/dist/slices/admission/substitute.js +7 -4
- package/dist/slices/agents/attention-posts.js +31 -0
- package/dist/slices/agents/attention-templates.js +33 -0
- package/dist/slices/agents/attention.js +10 -1
- package/dist/slices/agents/connection.js +2 -6
- package/dist/slices/agents/model.js +6 -3
- package/dist/slices/agents/repo.js +15 -7
- package/dist/slices/article/continuation.js +0 -63
- package/dist/slices/article/plain.js +3 -2
- package/dist/slices/article/segments.js +2 -62
- package/dist/slices/assistant/access.js +1 -0
- package/dist/slices/assistant/asks.js +80 -0
- package/dist/slices/assistant/cost.js +54 -0
- package/dist/slices/assistant/gate.js +222 -0
- package/dist/slices/assistant/model.js +79 -0
- package/dist/slices/assistant/names.js +23 -0
- package/dist/slices/assistant/prompt.js +74 -0
- package/dist/slices/assistant/repo.js +74 -0
- package/dist/slices/assistant/tokens.js +18 -0
- package/dist/slices/assistant/turn.js +342 -0
- package/dist/slices/autopilot/buffer.js +76 -0
- package/dist/slices/autopilot/model.js +14 -0
- package/dist/slices/autopilot/notify.js +27 -0
- package/dist/slices/autopilot/repo.js +34 -0
- package/dist/slices/autopilot/signals.js +194 -0
- package/dist/slices/autopilot/warnings.js +85 -0
- package/dist/slices/autopilot/weekly.js +100 -0
- package/dist/slices/backups/files.js +2 -6
- package/dist/slices/backups/repo.js +3 -15
- package/dist/slices/backups/service.js +4 -3
- package/dist/slices/channels/cast-images.js +2 -1
- package/dist/slices/channels/model.js +0 -1
- package/dist/slices/channels/rebrand.js +0 -3
- package/dist/slices/channels/repo.js +4 -0
- package/dist/slices/channels/schema.js +6 -0
- package/dist/slices/channels/service.js +10 -0
- package/dist/slices/channels/videos.js +2 -14
- package/dist/slices/checkpoints/index.js +0 -1
- package/dist/slices/control/providers.js +0 -26
- package/dist/slices/designs/artwork.js +66 -0
- package/dist/slices/designs/budget.js +23 -0
- package/dist/slices/designs/calls.js +124 -0
- package/dist/slices/designs/check-context.js +38 -0
- package/dist/slices/designs/check-text.js +43 -0
- package/dist/slices/designs/fields.js +88 -0
- package/dist/slices/designs/frames.js +34 -0
- package/dist/slices/designs/gate.js +128 -0
- package/dist/slices/designs/layout.js +293 -0
- package/dist/slices/designs/model.js +35 -0
- package/dist/slices/designs/pdf-job.js +23 -0
- package/dist/slices/designs/pdf-pages.js +30 -0
- package/dist/slices/designs/pdf-runner.js +68 -0
- package/dist/slices/designs/pdf-worker.js +24 -0
- package/dist/slices/designs/picture-size.js +79 -0
- package/dist/slices/designs/pictures.js +55 -0
- package/dist/slices/designs/quote.js +24 -0
- package/dist/slices/designs/render-args.js +36 -0
- package/dist/slices/designs/render-input.js +59 -0
- package/dist/slices/designs/render.js +215 -0
- package/dist/slices/designs/repo.js +101 -0
- package/dist/slices/designs/requests.js +80 -0
- package/dist/slices/designs/runner.js +239 -0
- package/dist/slices/designs/sample-repo.js +91 -0
- package/dist/slices/designs/sample.js +222 -0
- package/dist/slices/designs/schema.js +87 -0
- package/dist/slices/designs/sections.js +44 -0
- package/dist/slices/designs/service.js +233 -0
- package/dist/slices/designs/steps-repo.js +102 -0
- package/dist/slices/designs/studio-kind.js +39 -0
- package/dist/slices/designs/template-checks.js +44 -0
- package/dist/slices/designs/template-make.js +118 -0
- package/dist/slices/designs/templates.js +218 -0
- package/dist/slices/document/fonts.js +2 -1
- package/dist/slices/episodes/summarize.js +5 -1
- package/dist/slices/estimate/index.js +45 -7
- package/dist/slices/fonts/catalog.js +3 -2
- package/dist/slices/fonts/discovery.js +3 -2
- package/dist/slices/fonts/files.js +2 -6
- package/dist/slices/fonts/index.js +0 -1
- package/dist/slices/fonts/sfnt.js +45 -10
- package/dist/slices/images/appearance.js +6 -15
- package/dist/slices/images/scenes.js +100 -27
- package/dist/slices/keywords/digest.js +84 -0
- package/dist/slices/keywords/facts.js +92 -0
- package/dist/slices/keywords/fill.js +80 -0
- package/dist/slices/keywords/model.js +75 -0
- package/dist/slices/keywords/rules.js +187 -0
- package/dist/slices/keywords/schema.js +28 -0
- package/dist/slices/keywords/specs.js +260 -0
- package/dist/slices/keywords/values.js +74 -0
- package/dist/slices/library/lint.js +29 -12
- package/dist/slices/library/model.js +2 -0
- package/dist/slices/library/photorealistic.js +4 -12
- package/dist/slices/library/rename.js +9 -7
- package/dist/slices/library/save.js +14 -10
- package/dist/slices/library/slots.js +37 -11
- package/dist/slices/library/transfer.js +2 -1
- package/dist/slices/library/used-by.js +25 -10
- package/dist/slices/loudness/loudnorm.js +51 -11
- package/dist/slices/model-checks/cost.js +61 -0
- package/dist/slices/model-checks/listing.js +124 -0
- package/dist/slices/model-checks/model.js +20 -0
- package/dist/slices/model-checks/record.js +32 -0
- package/dist/slices/model-checks/repo.js +120 -0
- package/dist/slices/model-checks/rules.js +112 -0
- package/dist/slices/model-checks/run.js +143 -0
- package/dist/slices/model-checks/service.js +198 -0
- package/dist/slices/model-upkeep/switch.js +70 -25
- package/dist/slices/model-upkeep/usage.js +26 -11
- package/dist/slices/narration/breaths.js +2 -1
- package/dist/slices/narration/clean-pieces.js +2 -1
- package/dist/slices/narration/concat.js +2 -1
- package/dist/slices/narration/peaks.js +3 -4
- package/dist/slices/narration/pronunciation-chunks.js +4 -3
- package/dist/slices/narration/pronunciation.js +3 -2
- package/dist/slices/narration/steering.js +4 -3
- package/dist/slices/notifications/notifier.js +4 -3
- package/dist/slices/notifications/rules.js +5 -2
- package/dist/slices/notifications/settings.js +4 -12
- package/dist/slices/notifications/subject.js +2 -1
- package/dist/slices/onboarding/copy.js +2 -1
- package/dist/slices/onboarding/first-run.js +3 -2
- package/dist/slices/onboarding/full-video.js +3 -2
- package/dist/slices/onboarding/install.js +4 -3
- package/dist/slices/onboarding/model.js +0 -16
- package/dist/slices/onboarding/packs.js +22 -22
- package/dist/slices/onboarding/quick-short.js +2 -1
- package/dist/slices/onboarding/sample.js +0 -1
- package/dist/slices/onboarding/state.js +2 -11
- package/dist/slices/onboarding/template.js +2 -1
- package/dist/slices/patch-notes/library.js +3 -2
- package/dist/slices/play-drafts/convert.js +4 -0
- package/dist/slices/play-drafts/review-inputs.js +8 -2
- package/dist/slices/play-drafts/review.js +5 -4
- package/dist/slices/play-drafts/schema.js +4 -0
- package/dist/slices/project-templates/from-project.js +9 -2
- package/dist/slices/project-templates/repo.js +6 -1
- package/dist/slices/project-templates/setup.js +8 -0
- package/dist/slices/project-templates/stand-ins.js +22 -0
- package/dist/slices/rebuild/activity.js +2 -0
- package/dist/slices/rebuild/admission-repo.js +3 -2
- package/dist/slices/rebuild/narration-history.js +4 -5
- package/dist/slices/rebuild/narration-retry.js +2 -1
- package/dist/slices/rebuild/preview-details.js +27 -9
- package/dist/slices/rebuild/preview-plan.js +3 -8
- package/dist/slices/rebuild/recipe-build.js +8 -3
- package/dist/slices/rebuild/recipe-describe.js +3 -3
- package/dist/slices/rebuild/recipe-digest.js +58 -0
- package/dist/slices/rebuild/recipe-input-schema.js +10 -0
- package/dist/slices/rebuild/recipe-keywords.js +71 -0
- package/dist/slices/rebuild/recipe-legacy.js +5 -1
- package/dist/slices/rebuild/recipe-model.js +4 -0
- package/dist/slices/rebuild/recipe-narration-text.js +2 -1
- package/dist/slices/rebuild/recipe-preparation.js +3 -3
- package/dist/slices/rebuild/recipe-reference.js +8 -4
- package/dist/slices/rebuild/recipe-reviews.js +27 -7
- package/dist/slices/rebuild/recipe-save.js +6 -3
- package/dist/slices/rebuild/recipe-scenes.js +40 -11
- package/dist/slices/rebuild/recipe-shorts.js +8 -8
- package/dist/slices/rebuild/recipe-social.js +46 -0
- package/dist/slices/rebuild/recipe-text.js +64 -20
- package/dist/slices/rebuild/recipe-validation.js +98 -28
- package/dist/slices/rebuild/recipe-visual.js +55 -16
- package/dist/slices/rebuild/recipe-work.js +15 -3
- package/dist/slices/rebuild/recipe-youtube.js +4 -3
- package/dist/slices/rebuild/recovery-selection.js +3 -1
- package/dist/slices/rebuild/recovery.js +3 -2
- package/dist/slices/rebuild/repo.js +4 -3
- package/dist/slices/rebuild/review-promise.js +25 -0
- package/dist/slices/rebuild/review-redo.js +2 -1
- package/dist/slices/rebuild/runtime-admission.js +4 -3
- package/dist/slices/rebuild/runtime-agent-review.js +11 -5
- package/dist/slices/rebuild/runtime-animate.js +9 -8
- package/dist/slices/rebuild/runtime-article.js +3 -2
- package/dist/slices/rebuild/runtime-checkpoints.js +5 -4
- package/dist/slices/rebuild/runtime-document.js +8 -11
- package/dist/slices/rebuild/runtime-export-bed.js +6 -11
- package/dist/slices/rebuild/runtime-export-edit.js +6 -15
- package/dist/slices/rebuild/runtime-export-inputs.js +7 -7
- package/dist/slices/rebuild/runtime-export-short.js +8 -4
- package/dist/slices/rebuild/runtime-export.js +34 -12
- package/dist/slices/rebuild/runtime-figure-card.js +2 -1
- package/dist/slices/rebuild/runtime-image.js +4 -9
- package/dist/slices/rebuild/runtime-instructions.js +2 -0
- package/dist/slices/rebuild/runtime-keywords.js +59 -0
- package/dist/slices/rebuild/runtime-lines.js +2 -11
- package/dist/slices/rebuild/runtime-local.js +14 -20
- package/dist/slices/rebuild/runtime-narration-publication.js +2 -5
- package/dist/slices/rebuild/runtime-narration-reuse.js +9 -13
- package/dist/slices/rebuild/runtime-narration-text.js +10 -15
- package/dist/slices/rebuild/runtime-pictures.js +2 -4
- package/dist/slices/rebuild/runtime-piece-label.js +10 -6
- package/dist/slices/rebuild/runtime-plan.js +31 -5
- package/dist/slices/rebuild/runtime-provider.js +60 -19
- package/dist/slices/rebuild/runtime-publication.js +10 -9
- package/dist/slices/rebuild/runtime-review.js +33 -28
- package/dist/slices/rebuild/runtime-run.js +4 -1
- package/dist/slices/rebuild/runtime-shorts.js +25 -45
- package/dist/slices/rebuild/runtime-store.js +3 -8
- package/dist/slices/rebuild/runtime-subtitles.js +16 -14
- package/dist/slices/rebuild/runtime-voices.js +8 -15
- package/dist/slices/rebuild/runtime-youtube.js +11 -29
- package/dist/slices/rebuild/transition-repo.js +6 -5
- package/dist/slices/rebuild/work-records.js +6 -0
- package/dist/slices/reruns/cascade.js +1 -2
- package/dist/slices/reruns/index.js +6 -9
- package/dist/slices/reviews/external-model.js +3 -0
- package/dist/slices/reviews/external-repo.js +2 -1
- package/dist/slices/reviews/external-rows.js +2 -3
- package/dist/slices/reviews/model.js +26 -8
- package/dist/slices/reviews/repo.js +2 -1
- package/dist/slices/reviews/rules.js +1 -0
- package/dist/slices/reviews/view.js +5 -2
- package/dist/slices/revisions/downloads.js +4 -5
- package/dist/slices/revisions/mutation-assets.js +7 -4
- package/dist/slices/revisions/mutation-cues.js +2 -5
- package/dist/slices/revisions/mutations.js +0 -1
- package/dist/slices/revisions/repo.js +3 -1
- package/dist/slices/revisions/schema.js +1 -0
- package/dist/slices/revisions/view.js +20 -0
- package/dist/slices/run-cost/limits.js +5 -2
- package/dist/slices/run-cost/meter.js +12 -5
- package/dist/slices/run-cost/panel.js +8 -74
- package/dist/slices/run-cost/plan-readings.js +127 -0
- package/dist/slices/run-cost/plan-use.js +169 -0
- package/dist/slices/run-cost/pricing.js +3 -3
- package/dist/slices/run-cost/week.js +32 -4
- package/dist/slices/schedules/agenda.js +11 -2
- package/dist/slices/schedules/by-date.js +42 -0
- package/dist/slices/schedules/calendar.js +5 -0
- package/dist/slices/schedules/design-agenda.js +36 -0
- package/dist/slices/schedules/design-check.js +41 -0
- package/dist/slices/schedules/design-run.js +126 -0
- package/dist/slices/schedules/next-run.js +62 -0
- package/dist/slices/schedules/prepare.js +18 -2
- package/dist/slices/schedules/repo.js +24 -16
- package/dist/slices/schedules/rescore.js +35 -0
- package/dist/slices/schedules/scheduler.js +13 -3
- package/dist/slices/schedules/schema.js +54 -3
- package/dist/slices/schedules/score.js +107 -0
- package/dist/slices/schedules/service.js +57 -24
- package/dist/slices/schedules/topic-list.js +15 -0
- package/dist/slices/schedules/topic-scores.js +104 -0
- package/dist/slices/schedules/topics.js +48 -36
- package/dist/slices/settings/cli-paths.js +4 -6
- package/dist/slices/settings/first-run.js +2 -11
- package/dist/slices/settings/model-reach.js +3 -17
- package/dist/slices/settings/model.js +10 -0
- package/dist/slices/settings/playback.js +33 -22
- package/dist/slices/settings/probe-read.js +16 -0
- package/dist/slices/settings/repo.js +33 -0
- package/dist/slices/settings/tutorial.js +2 -2
- package/dist/slices/settings/voices.js +4 -12
- package/dist/slices/shorts/pick.js +2 -15
- package/dist/slices/shorts/prompts.js +2 -13
- package/dist/slices/shorts/render.js +3 -0
- package/dist/slices/social/channel.js +44 -0
- package/dist/slices/social/defaults.js +17 -0
- package/dist/slices/social/due.js +36 -0
- package/dist/slices/social/extension.js +18 -0
- package/dist/slices/social/fit.js +115 -0
- package/dist/slices/social/limits.js +186 -0
- package/dist/slices/social/links.js +21 -0
- package/dist/slices/social/media.js +131 -0
- package/dist/slices/social/model.js +75 -0
- package/dist/slices/social/notice.js +19 -0
- package/dist/slices/social/pack.js +176 -0
- package/dist/slices/social/post-prompt.js +55 -0
- package/dist/slices/social/queue.js +31 -0
- package/dist/slices/social/repo.js +133 -0
- package/dist/slices/social/reshape.js +97 -0
- package/dist/slices/social/rules.js +5 -0
- package/dist/slices/social/schema.js +70 -0
- package/dist/slices/social/serve.js +51 -0
- package/dist/slices/social/service.js +128 -0
- package/dist/slices/social/settings.js +21 -0
- package/dist/slices/social/sources.js +114 -0
- package/dist/slices/social/state.js +110 -0
- package/dist/slices/social/text.js +149 -0
- package/dist/slices/storage/arrange.js +3 -1
- package/dist/slices/storage/assets.js +8 -10
- package/dist/slices/storage/backup-designs.js +74 -0
- package/dist/slices/storage/backup-export.js +8 -3
- package/dist/slices/storage/backup-format.js +10 -0
- package/dist/slices/storage/backup-import.js +20 -2
- package/dist/slices/storage/delete-project.js +6 -5
- package/dist/slices/storage/files-location.js +6 -8
- package/dist/slices/storage/layout.js +13 -2
- package/dist/slices/storage/model.js +3 -0
- package/dist/slices/storage/portable.js +16 -11
- package/dist/slices/storage/schema.js +2 -0
- package/dist/slices/storage/staging-refs.js +2 -1
- package/dist/slices/storage/staging.js +6 -9
- package/dist/slices/storage/trim.js +10 -3
- package/dist/slices/studio/calendar.js +4 -1
- package/dist/slices/studio/pick.js +2 -11
- package/dist/slices/studio/plan.js +6 -15
- package/dist/slices/studio/queue.js +3 -14
- package/dist/slices/studio/releases.js +26 -0
- package/dist/slices/studio/settings.js +14 -51
- package/dist/slices/studio/videos.js +12 -0
- package/dist/slices/style-preview/render.js +34 -13
- package/dist/slices/style-preview/schema.js +13 -0
- package/dist/slices/style-preview/service.js +2 -1
- package/dist/slices/style-preview/settings.js +33 -5
- package/dist/slices/telemetry/collector-client.js +2 -4
- package/dist/slices/telemetry/flush.js +2 -4
- package/dist/slices/telemetry/model.js +0 -7
- package/dist/slices/telemetry/record.js +10 -3
- package/dist/slices/template-studio/anatomy-view.js +118 -0
- package/dist/slices/template-studio/anatomy.js +73 -0
- package/dist/slices/template-studio/bakeoff-make.js +225 -0
- package/dist/slices/template-studio/bakeoff-repo.js +83 -0
- package/dist/slices/template-studio/bakeoff.js +333 -0
- package/dist/slices/template-studio/budget.js +103 -0
- package/dist/slices/template-studio/checks.js +273 -0
- package/dist/slices/template-studio/document-sample.js +56 -0
- package/dist/slices/template-studio/edit.js +15 -0
- package/dist/slices/template-studio/for-all.js +161 -0
- package/dist/slices/template-studio/free-video.js +31 -0
- package/dist/slices/template-studio/free.js +176 -0
- package/dist/slices/template-studio/gate.js +40 -0
- package/dist/slices/template-studio/hidden.js +20 -0
- package/dist/slices/template-studio/jobs.js +79 -0
- package/dist/slices/template-studio/loudness.js +111 -0
- package/dist/slices/template-studio/make.js +40 -0
- package/dist/slices/template-studio/model.js +54 -0
- package/dist/slices/template-studio/pack-import.js +253 -0
- package/dist/slices/template-studio/pack-samples.js +60 -0
- package/dist/slices/template-studio/pack.js +205 -0
- package/dist/slices/template-studio/paid-view.js +66 -0
- package/dist/slices/template-studio/paid.js +348 -0
- package/dist/slices/template-studio/quote.js +148 -0
- package/dist/slices/template-studio/ready.js +104 -0
- package/dist/slices/template-studio/repo.js +134 -0
- package/dist/slices/template-studio/reviews-path.js +58 -0
- package/dist/slices/template-studio/runner.js +84 -0
- package/dist/slices/template-studio/save.js +236 -0
- package/dist/slices/template-studio/say-it-as.js +248 -0
- package/dist/slices/template-studio/schedule-gate.js +34 -0
- package/dist/slices/template-studio/schedule-price.js +30 -0
- package/dist/slices/template-studio/schedule-sample.js +87 -0
- package/dist/slices/template-studio/schema.js +218 -0
- package/dist/slices/template-studio/scope.js +124 -0
- package/dist/slices/template-studio/sections.js +176 -0
- package/dist/slices/template-studio/service.js +173 -0
- package/dist/slices/template-studio/status.js +174 -0
- package/dist/slices/template-studio/topic.js +223 -0
- package/dist/slices/trash/designs.js +76 -0
- package/dist/slices/trash/model.js +13 -4
- package/dist/slices/trash/service.js +52 -2
- package/dist/slices/tutorials/library.js +3 -2
- package/dist/slices/video/ass-text.js +17 -0
- package/dist/slices/video/audio-export.js +2 -64
- package/dist/slices/video/encoding.js +160 -0
- package/dist/slices/video/ffmpeg.js +23 -21
- package/dist/slices/video/figure-card.js +1 -15
- package/dist/slices/video/slideshow.js +43 -18
- package/dist/slices/voices/palette.js +0 -3
- package/dist/slices/youtube/answer.js +2 -15
- package/dist/slices/youtube/edits-repo.js +2 -11
- package/dist/tutorials/Agents-MCP.md +2 -1
- package/dist/tutorials/Assistant.md +42 -0
- package/dist/tutorials/Channels.md +2 -0
- package/dist/tutorials/Home-and-Projects.md +19 -0
- package/dist/tutorials/Install.md +1 -0
- package/dist/tutorials/Keywords-Slopify-Fills.md +87 -0
- package/dist/tutorials/Models.md +33 -1
- package/dist/tutorials/Notifications.md +6 -0
- package/dist/tutorials/Play-Images.md +4 -0
- package/dist/tutorials/Posting-to-Social-Sites.md +121 -0
- package/dist/tutorials/Prompts.md +10 -6
- package/dist/tutorials/Remote-Access.md +63 -0
- package/dist/tutorials/Reviews-and-Checkpoints.md +13 -2
- package/dist/tutorials/Schedules.md +21 -1
- package/dist/tutorials/Settings-Reference.md +50 -8
- package/dist/tutorials/Template-Studio.md +125 -0
- package/dist/tutorials/Templates.md +3 -0
- package/dist/tutorials/_Sidebar.md +5 -0
- package/dist/updater/work-in-progress.js +42 -12
- package/dist/web/assets/index-CkAI_2E7.css +1 -0
- package/dist/web/assets/index-DcD0cdfo.js +334 -0
- package/dist/web/assets/{pdf-T7MCwjIv.js → pdf-TODRwF31.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +5 -1
- package/dist/slices/article/provided-entries.js +0 -66
- package/dist/slices/article/run.js +0 -145
- package/dist/slices/images/run.js +0 -234
- package/dist/slices/narration/legacy-plan.js +0 -58
- package/dist/slices/narration/run.js +0 -270
- package/dist/slices/rebuild/runtime-actions.js +0 -90
- package/dist/slices/research/run.js +0 -224
- package/dist/slices/subtitles/prepare.js +0 -194
- package/dist/slices/subtitles/transcript.js +0 -34
- package/dist/slices/thumbnail/run.js +0 -219
- package/dist/slices/video/audio-inputs.js +0 -33
- package/dist/slices/video/reuse-audio.js +0 -62
- package/dist/slices/video/run.js +0 -78
- package/dist/slices/video/write-export.js +0 -158
- package/dist/slices/video/write-subtitles.js +0 -59
- package/dist/web/assets/index-BadsoORk.css +0 -1
- package/dist/web/assets/index-D8LqNsCl.js +0 -326
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { copyFileSync, mkdirSync, mkdtempSync, rmSync } from "node:fs";
|
|
2
2
|
import { extname, join, relative, sep } from "node:path";
|
|
3
|
+
import { internalError } from "../../kernel/errors.js";
|
|
3
4
|
import { usesShortMode } from "../admission/short-mode.js";
|
|
4
5
|
import { masterFile, masterReport } from "../loudness/loudnorm.js";
|
|
5
6
|
import { masterGoal } from "../loudness/model.js";
|
|
7
|
+
import { isReadyOutput, readyOutput } from "../revisions/view.js";
|
|
6
8
|
import { allocateAsset, discardPreparedAssets, sealAsset } from "../storage/assets.js";
|
|
7
9
|
import { outputPath, projectDir, renderCacheDir } from "../storage/layout.js";
|
|
8
10
|
import { audioExportArgs } from "../video/audio-export.js";
|
|
@@ -18,10 +20,21 @@ import { exportSnapshot, retainedOutput, revisionAudio, } from "./runtime-export
|
|
|
18
20
|
import { executeShortExport } from "./runtime-export-short.js";
|
|
19
21
|
import { lineLevelledAudio } from "./runtime-lines.js";
|
|
20
22
|
import { preparedResult, preparedText, publishResult } from "./runtime-publication.js";
|
|
23
|
+
import { pieceAlreadyDone } from "./work-records.js";
|
|
24
|
+
// The machine settings for one render, and the notices it gathers for the project page.
|
|
25
|
+
export async function exportMachine(deps, projectId) {
|
|
26
|
+
const chosen = await deps.renderMachine?.(projectId);
|
|
27
|
+
const notices = chosen?.notice === undefined ? [] : [chosen.notice];
|
|
28
|
+
return {
|
|
29
|
+
machine: chosen?.machine,
|
|
30
|
+
notices,
|
|
31
|
+
notice: (sentence) => {
|
|
32
|
+
notices.push(sentence);
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
21
36
|
export async function executeExportRecipe(deps, context, piece) {
|
|
22
|
-
if (deps.db
|
|
23
|
-
.prepare("SELECT state FROM revision_work_pieces WHERE id=? AND work_id=?")
|
|
24
|
-
.get(piece.id, context.work.workId)?.state === "done")
|
|
37
|
+
if (pieceAlreadyDone(deps.db, context.work.workId, piece.id))
|
|
25
38
|
return "done";
|
|
26
39
|
if (!context.maySubmit(piece.id))
|
|
27
40
|
return "held";
|
|
@@ -31,7 +44,7 @@ export async function executeExportRecipe(deps, context, piece) {
|
|
|
31
44
|
const audio = await revisionAudio(deps, context, view, { levelled: true });
|
|
32
45
|
const wav = piece.key === "export:wav";
|
|
33
46
|
if (!wav && piece.key !== "export:video")
|
|
34
|
-
throw new Error("
|
|
47
|
+
throw new Error(internalError("unknown kind of export"));
|
|
35
48
|
if (wav && audio.length === 0)
|
|
36
49
|
throw new Error("The audio export has nothing to export because narration is turned off for this project. Turn narration on in Edit project, then Try again.");
|
|
37
50
|
if (!wav && usesShortMode(view.revision.config))
|
|
@@ -49,7 +62,7 @@ export async function executeExportRecipe(deps, context, piece) {
|
|
|
49
62
|
const sound = linesDirectory === undefined
|
|
50
63
|
? audio
|
|
51
64
|
: await lineLevelledAudio(deps, context, view, audio, linesDirectory);
|
|
52
|
-
const captions = snapshot.view.outputs.filter((row) => row
|
|
65
|
+
const captions = snapshot.view.outputs.filter((row) => isReadyOutput(row) && row.workKey === "subtitles:files");
|
|
53
66
|
const burn = !wav && view.revision.config.subtitles?.mode === "burn-in";
|
|
54
67
|
if (burn)
|
|
55
68
|
directory = captionDirectory(deps, context, snapshot);
|
|
@@ -119,6 +132,8 @@ export async function executeExportRecipe(deps, context, piece) {
|
|
|
119
132
|
};
|
|
120
133
|
if (!context.maySubmit(piece.id))
|
|
121
134
|
return "held";
|
|
135
|
+
const machine = await exportMachine(deps, context.work.projectId);
|
|
136
|
+
const priority = machine.machine?.priority;
|
|
122
137
|
const onProgress = (elapsedMs) => context.emit({
|
|
123
138
|
type: "stage.progress",
|
|
124
139
|
projectId: context.work.projectId,
|
|
@@ -139,10 +154,11 @@ export async function executeExportRecipe(deps, context, piece) {
|
|
|
139
154
|
args: audioExportArgs(sound, mixed),
|
|
140
155
|
signal: context.signal,
|
|
141
156
|
log: deps.log,
|
|
157
|
+
priority,
|
|
142
158
|
onProgress,
|
|
143
159
|
});
|
|
144
160
|
if (goal !== undefined) {
|
|
145
|
-
const run = { bin: deps.ffmpeg, log: deps.log, signal: context.signal };
|
|
161
|
+
const run = { bin: deps.ffmpeg, log: deps.log, signal: context.signal, priority };
|
|
146
162
|
await masterFile(run, mixed, `${pending.absolutePath}.master.wav`, goal, {
|
|
147
163
|
sampleRate: 48000,
|
|
148
164
|
channels: 2,
|
|
@@ -167,6 +183,7 @@ export async function executeExportRecipe(deps, context, piece) {
|
|
|
167
183
|
],
|
|
168
184
|
signal: context.signal,
|
|
169
185
|
log: deps.log,
|
|
186
|
+
priority,
|
|
170
187
|
onProgress: () => { },
|
|
171
188
|
});
|
|
172
189
|
master = await masterReport(run, pending.absolutePath, goal);
|
|
@@ -193,20 +210,21 @@ export async function executeExportRecipe(deps, context, piece) {
|
|
|
193
210
|
log: deps.log,
|
|
194
211
|
onProgress,
|
|
195
212
|
...(goal === undefined ? {} : { master: goal }),
|
|
213
|
+
machine: machine.machine,
|
|
214
|
+
notice: machine.notice,
|
|
196
215
|
});
|
|
197
216
|
context.signal.throwIfAborted();
|
|
198
217
|
const asset = sealAsset(deps, pending);
|
|
199
218
|
prepared.push(preparedResult(deps, context, piece, wav ? "audio_export" : "video", asset, Math.round(totalSeconds * 1000), {
|
|
200
219
|
subtitlesMode: mode,
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
: { warnings: edited.warnings }),
|
|
220
|
+
// An audio export encodes no picture, so the encoder's notice is not its to show.
|
|
221
|
+
...warningsOf([...(edited?.warnings ?? []), ...(wav ? [] : machine.notices)]),
|
|
204
222
|
...(master === undefined ? {} : { master }),
|
|
205
223
|
}));
|
|
206
224
|
prepared.push(preparedText(deps, context, piece, "render_params", "render.json", JSON.stringify(record)));
|
|
207
225
|
prepared.push(...captions.map((row) => retainedOutput(deps, view, row)));
|
|
208
226
|
await publishResult(deps, context, piece, prepared, { totalSeconds }, asset);
|
|
209
|
-
deps.count?.("stage.completed", { stage: "video" });
|
|
227
|
+
deps.count?.("stage.completed", { stage: "video" }, context.work.projectId);
|
|
210
228
|
return "done";
|
|
211
229
|
}
|
|
212
230
|
finally {
|
|
@@ -220,14 +238,14 @@ export async function executeExportRecipe(deps, context, piece) {
|
|
|
220
238
|
// The project's images in slideshow order, as files.
|
|
221
239
|
export function slideshowImages(deps, context, view) {
|
|
222
240
|
return view.revision.content.imageOrder.map((key) => {
|
|
223
|
-
const row = view
|
|
241
|
+
const row = readyOutput(view, { workKey: `image:${key}` });
|
|
224
242
|
if (row === undefined)
|
|
225
243
|
throw new Error("The video export can't find one of the slideshow images. Use More → make it again in its section on Images (or regenerate that image in Edit project → Images), then Try again.");
|
|
226
244
|
return outputPath(deps.paths, context.work.projectId, row.output.path);
|
|
227
245
|
});
|
|
228
246
|
}
|
|
229
247
|
function captionDirectory(deps, context, snapshot) {
|
|
230
|
-
const find = (role) => snapshot.view
|
|
248
|
+
const find = (role) => readyOutput(snapshot.view, { role });
|
|
231
249
|
const ass = find("subtitle_ass");
|
|
232
250
|
const font = find("subtitle_font");
|
|
233
251
|
if (ass === undefined || font === undefined)
|
|
@@ -244,3 +262,7 @@ function captionDirectory(deps, context, snapshot) {
|
|
|
244
262
|
throw error;
|
|
245
263
|
}
|
|
246
264
|
}
|
|
265
|
+
// What the video could not do as asked, for the project page; nothing when it did it all.
|
|
266
|
+
export function warningsOf(warnings) {
|
|
267
|
+
return warnings.length === 0 ? {} : { warnings };
|
|
268
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { copyFileSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
+
import { internalError } from "../../kernel/errors.js";
|
|
4
5
|
import { captionFont, captionFontDeps } from "../fonts/coverage.js";
|
|
5
6
|
import { describedKinds } from "../narration/blocks.js";
|
|
6
7
|
import { allocateAsset, discardPreparedAssets, sealAsset } from "../storage/assets.js";
|
|
@@ -25,7 +26,7 @@ const values = z.object({
|
|
|
25
26
|
const frames = { "16:9": [1920, 1080], "9:16": [1080, 1920], "1:1": [1080, 1080] };
|
|
26
27
|
export async function executeFigureCard(deps, context, piece) {
|
|
27
28
|
if (piece.input.kind !== "local")
|
|
28
|
-
throw new Error("
|
|
29
|
+
throw new Error(internalError("a figure card step was set up wrongly"));
|
|
29
30
|
const card = values.parse(piece.input.values);
|
|
30
31
|
const view = executionView(deps, context.work.projectId, context.work.revisionId);
|
|
31
32
|
// The article's own picture for a figure, when the project has it as an upload.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
|
-
import { z } from "zod";
|
|
3
2
|
import { imageBlob } from "../channels/repo.js";
|
|
3
|
+
import { assetPathOrUndefined } from "../revisions/mutation-assets.js";
|
|
4
4
|
import { outputPath } from "../storage/layout.js";
|
|
5
5
|
// The provider call an image step makes: its request, the effort when one is chosen and, while
|
|
6
6
|
// the project's Establishing image is on, that image's bytes as the visual reference.
|
|
@@ -25,17 +25,12 @@ function referenceImage(deps, projectId, input) {
|
|
|
25
25
|
const missing = "The establishing image this image is drawn from is missing. Use Regenerate on the establishing image in the Images section (or upload it again in Edit project → Images), then use Try again.";
|
|
26
26
|
if (input.reference.assetId === null)
|
|
27
27
|
throw new Error(missing);
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
.optional()
|
|
31
|
-
.parse(deps.db
|
|
32
|
-
.prepare("SELECT path FROM project_assets WHERE id=? AND project_id=?")
|
|
33
|
-
.get(input.reference.assetId, projectId));
|
|
34
|
-
if (row === undefined)
|
|
28
|
+
const saved = assetPathOrUndefined(deps, projectId, input.reference.assetId);
|
|
29
|
+
if (saved === undefined)
|
|
35
30
|
throw new Error(missing);
|
|
36
31
|
let bytes;
|
|
37
32
|
try {
|
|
38
|
-
bytes = new Uint8Array(readFileSync(outputPath(deps.paths, projectId,
|
|
33
|
+
bytes = new Uint8Array(readFileSync(outputPath(deps.paths, projectId, saved)));
|
|
39
34
|
}
|
|
40
35
|
catch {
|
|
41
36
|
throw new Error(missing);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { errorText } from "../../kernel/errors.js";
|
|
2
|
+
import { fillLateKeywords, mentionsLateKeyword } from "../keywords/fill.js";
|
|
3
|
+
import { durationText, releaseDateText } from "../keywords/values.js";
|
|
4
|
+
import { releasesOf } from "../studio/releases.js";
|
|
5
|
+
import { revisionAudio } from "./runtime-export-inputs.js";
|
|
6
|
+
import { executionView } from "./runtime-plan.js";
|
|
7
|
+
// The release date and the video's length are filled into a request only as it is sent: the
|
|
8
|
+
// planned request keeps `{{Slopify_Release_Date}}` and `{{Slopify_Duration}}`, so moving the
|
|
9
|
+
// date later, or a new length, never makes anything outdated. Every other call goes through as
|
|
10
|
+
// it was.
|
|
11
|
+
export function lateKeywordProviders(providers, values) {
|
|
12
|
+
let once;
|
|
13
|
+
const late = () => {
|
|
14
|
+
once ??= values();
|
|
15
|
+
return once;
|
|
16
|
+
};
|
|
17
|
+
const wrap = (inner) => ({
|
|
18
|
+
...inner,
|
|
19
|
+
llm: async (call, onEvent) => {
|
|
20
|
+
if (!call.messages.some((message) => mentionsLateKeyword(message.content)))
|
|
21
|
+
return inner.llm(call, onEvent);
|
|
22
|
+
const filled = await late();
|
|
23
|
+
return inner.llm({
|
|
24
|
+
...call,
|
|
25
|
+
messages: call.messages.map((message) => ({
|
|
26
|
+
...message,
|
|
27
|
+
content: fillLateKeywords(message.content, filled),
|
|
28
|
+
})),
|
|
29
|
+
}, onEvent);
|
|
30
|
+
},
|
|
31
|
+
image: async (call) => mentionsLateKeyword(call.prompt)
|
|
32
|
+
? inner.image({ ...call, prompt: fillLateKeywords(call.prompt, await late()) })
|
|
33
|
+
: inner.image(call),
|
|
34
|
+
forPiece: (pieceId) => wrap(inner.forPiece(pieceId)),
|
|
35
|
+
});
|
|
36
|
+
return wrap(providers);
|
|
37
|
+
}
|
|
38
|
+
// The long video's release time from the posting plan, and the narration's length once it is
|
|
39
|
+
// there. A length that can't be read yet (an article review runs before the narration) is
|
|
40
|
+
// blank, so its line is left out, and the reason is logged.
|
|
41
|
+
export async function lateValuesOf(deps, context) {
|
|
42
|
+
const releaseDate = releaseDateText(releasesOf(deps.db, context.work.projectId).find((release) => release.short === 0)?.at);
|
|
43
|
+
const view = executionView(deps, context.work.projectId, context.work.revisionId);
|
|
44
|
+
let duration;
|
|
45
|
+
if (view !== undefined && view.revision.config.sources.audio !== "off")
|
|
46
|
+
try {
|
|
47
|
+
const audio = await revisionAudio(deps, context, view);
|
|
48
|
+
const seconds = audio.reduce((sum, segment) => sum + segment.seconds, 0);
|
|
49
|
+
duration = seconds > 0 ? durationText(seconds) : undefined;
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
deps.log.write("warn", "keywords.duration", {
|
|
53
|
+
projectId: context.work.projectId,
|
|
54
|
+
stage: context.work.kind,
|
|
55
|
+
detail: errorText(error),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return { releaseDate, duration };
|
|
59
|
+
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
1
|
import { join } from "node:path";
|
|
3
2
|
import { levelLines } from "../loudness/line-level.js";
|
|
4
|
-
import { outputPath } from "../storage/layout.js";
|
|
5
3
|
import { linesLevelled } from "./recipe-lines.js";
|
|
6
|
-
import {
|
|
4
|
+
import { readTimingWords } from "./runtime-subtitles.js";
|
|
7
5
|
// The sound a multi-voice run plays, with its body narration levelled line by line
|
|
8
6
|
// (`loudness/line-level.ts`) into `directory`, for the video, the audio export and the audio
|
|
9
7
|
// files alike. The words are timed on the timeline these segments lay out, so the body starts
|
|
@@ -11,14 +9,7 @@ import { wordsSchema } from "./runtime-subtitles.js";
|
|
|
11
9
|
export async function lineLevelledAudio(deps, context, view, audio, directory) {
|
|
12
10
|
if (!linesLevelled(view.revision.config))
|
|
13
11
|
return audio;
|
|
14
|
-
const
|
|
15
|
-
row.available &&
|
|
16
|
-
row.state === "ready" &&
|
|
17
|
-
row.workKey === "subtitles:timing" &&
|
|
18
|
-
row.output.role === "subtitle_words");
|
|
19
|
-
if (timing === undefined)
|
|
20
|
-
throw new Error("The narration's word timing, which evens out the speakers' volume, is missing. Use More → Render the video again in the Video section, then Try again.");
|
|
21
|
-
const { words } = wordsSchema.parse(JSON.parse(readFileSync(outputPath(deps.paths, context.work.projectId, timing.output.path), "utf8")));
|
|
12
|
+
const { words } = readTimingWords(deps, context, view, "evens out the speakers' volume");
|
|
22
13
|
const run = { bin: deps.ffmpeg, log: deps.log, signal: context.signal };
|
|
23
14
|
const levelled = [];
|
|
24
15
|
let offset = 0;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { rmSync, statSync } from "node:fs";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
+
import { internalError } from "../../kernel/errors.js";
|
|
4
5
|
import { referenceKey, thumbnailVariant } from "../admission/model.js";
|
|
5
6
|
import { plainText } from "../article/plain.js";
|
|
6
7
|
import { splitEndMatter } from "../article/split.js";
|
|
@@ -9,6 +10,8 @@ import { levelSentences } from "../loudness/sentence-level.js";
|
|
|
9
10
|
import { cleanPieces } from "../narration/clean-pieces.js";
|
|
10
11
|
import { joinNarration } from "../narration/concat.js";
|
|
11
12
|
import { applyPauses, planPieces } from "../narration/pauses.js";
|
|
13
|
+
import { assetPath } from "../revisions/mutation-assets.js";
|
|
14
|
+
import { isDonePiece } from "../revisions/view.js";
|
|
12
15
|
import { allocateAsset, discardPreparedAssets, sealAsset } from "../storage/assets.js";
|
|
13
16
|
import { outputPath } from "../storage/layout.js";
|
|
14
17
|
import { probeDurationMs, runFfmpeg } from "../video/ffmpeg.js";
|
|
@@ -17,12 +20,11 @@ import { breathsAsked, deEssAsked } from "./recipe-breaths.js";
|
|
|
17
20
|
import { levelOperation, sentencesAsked } from "./recipe-loudness.js";
|
|
18
21
|
import { executeFigureCard } from "./runtime-figure-card.js";
|
|
19
22
|
import { publishNarrationText } from "./runtime-narration-text.js";
|
|
20
|
-
import { executionPlan, executionView,
|
|
23
|
+
import { executionPlan, executionView, workCatalogue } from "./runtime-plan.js";
|
|
21
24
|
import { preparedResult, preparedText, preparedTexts, publishResult, } from "./runtime-publication.js";
|
|
25
|
+
import { pieceAlreadyDone } from "./work-records.js";
|
|
22
26
|
export async function executeLocalRecipe(deps, context, piece) {
|
|
23
|
-
if (deps.db
|
|
24
|
-
.prepare("SELECT state FROM revision_work_pieces WHERE id=? AND work_id=?")
|
|
25
|
-
.get(piece.id, context.work.workId)?.state === "done")
|
|
27
|
+
if (pieceAlreadyDone(deps.db, context.work.workId, piece.id))
|
|
26
28
|
return "done";
|
|
27
29
|
if (!context.maySubmit(piece.id))
|
|
28
30
|
return "held";
|
|
@@ -62,7 +64,7 @@ export async function executeLocalRecipe(deps, context, piece) {
|
|
|
62
64
|
return "done";
|
|
63
65
|
}
|
|
64
66
|
if (input.kind !== "local")
|
|
65
|
-
throw new Error("
|
|
67
|
+
throw new Error(internalError("a local step was set up wrongly"));
|
|
66
68
|
if (input.operation === "figure-card-v1")
|
|
67
69
|
return executeFigureCard(deps, context, piece);
|
|
68
70
|
if (input.operation === "narration-files-v1") {
|
|
@@ -98,31 +100,23 @@ export async function executeLocalRecipe(deps, context, piece) {
|
|
|
98
100
|
});
|
|
99
101
|
return "done";
|
|
100
102
|
}
|
|
101
|
-
throw new Error(`
|
|
103
|
+
throw new Error(internalError(`no handler for the step "${input.operation}"`));
|
|
102
104
|
}
|
|
103
105
|
async function concatenate(deps, context, piece) {
|
|
104
106
|
const view = executionView(deps, context.work.projectId, context.work.revisionId);
|
|
105
107
|
if (view === undefined)
|
|
106
|
-
throw new Error("
|
|
107
|
-
const
|
|
108
|
-
.prepare("SELECT recipe_context FROM revision_work WHERE id=?")
|
|
109
|
-
.get(context.work.workId);
|
|
110
|
-
const plan = executionPlan(deps, view, savedCatalogue(row?.recipe_context));
|
|
108
|
+
throw new Error(internalError("the project version being built is missing"));
|
|
109
|
+
const plan = executionPlan(deps, view, workCatalogue(deps.db, context.work.workId));
|
|
111
110
|
const recipe = plan.recipes.find((candidate) => candidate.key === piece.key && candidate.fingerprint === piece.fingerprint);
|
|
112
111
|
if (recipe === undefined)
|
|
113
|
-
throw new Error("
|
|
112
|
+
throw new Error(internalError("the narration chunks to join no longer match the project's saved inputs"));
|
|
114
113
|
const files = recipe.dependsOn.map((key) => {
|
|
115
114
|
const input = view.pieces.find((candidate) => candidate.key === key &&
|
|
116
|
-
candidate
|
|
117
|
-
candidate.available &&
|
|
118
|
-
candidate.piece.state === "done" &&
|
|
115
|
+
isDonePiece(candidate) &&
|
|
119
116
|
candidate.fingerprint === plan.recipes.find((value) => value.key === key)?.fingerprint);
|
|
120
117
|
if (input?.assetId === null || input === undefined)
|
|
121
118
|
throw new Error("One narration chunk has no saved audio, so the narration can't be joined together. Regenerate the missing chunk in Edit project → Narration, then Try again.");
|
|
122
|
-
|
|
123
|
-
.prepare("SELECT path FROM project_assets WHERE id=? AND project_id=?")
|
|
124
|
-
.get(input.assetId, context.work.projectId);
|
|
125
|
-
return outputPath(deps.paths, context.work.projectId, z.string().parse(asset?.path));
|
|
119
|
+
return outputPath(deps.paths, context.work.projectId, assetPath(deps, context.work.projectId, input.assetId));
|
|
126
120
|
});
|
|
127
121
|
// Level the volume repeats the join its recipe names, from the same pieces, each levelled
|
|
128
122
|
// first (`recipe-loudness.ts`).
|
|
@@ -295,7 +289,7 @@ export async function joinTurns(run, files, values, output) {
|
|
|
295
289
|
.rest(z.unknown())
|
|
296
290
|
.parse(values)[1];
|
|
297
291
|
if (layout.length !== files.length || files.length === 0)
|
|
298
|
-
throw new Error("
|
|
292
|
+
throw new Error(internalError("the speaker turns to join don't match their audio"));
|
|
299
293
|
await runFfmpeg({
|
|
300
294
|
bin: run.bin,
|
|
301
295
|
args: turnJoinArgs(files.map((path, index) => ({
|
|
@@ -2,7 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
import { projectSelected } from "../revisions/projection.js";
|
|
3
3
|
import { getRevisionView } from "../revisions/view.js";
|
|
4
4
|
import { bindNarrationReuse, narrationOrdinal } from "./runtime-narration-reuse.js";
|
|
5
|
-
import { executionPlan,
|
|
5
|
+
import { executionPlan, workCatalogue } from "./runtime-plan.js";
|
|
6
6
|
export function rebindPublishedNarration(deps, work, piece) {
|
|
7
7
|
if (piece.input.kind !== "tts")
|
|
8
8
|
return;
|
|
@@ -11,10 +11,7 @@ export function rebindPublishedNarration(deps, work, piece) {
|
|
|
11
11
|
.all(work.projectId, piece.id, piece.key, work.revisionId);
|
|
12
12
|
if (targets.length === 0)
|
|
13
13
|
return;
|
|
14
|
-
const
|
|
15
|
-
.prepare("SELECT recipe_context FROM revision_work WHERE id=?")
|
|
16
|
-
.get(work.workId);
|
|
17
|
-
const catalogue = savedCatalogue(row?.recipe_context);
|
|
14
|
+
const catalogue = workCatalogue(deps.db, work.workId);
|
|
18
15
|
for (const target of targets) {
|
|
19
16
|
const view = getRevisionView(deps, work.projectId, z.string().parse(target.revision_id));
|
|
20
17
|
if (view === undefined)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { insertManifestOutput, insertManifestPiece, selectOutputRecord, selectPieceRecord, } from "../revisions/manifest-repo.js";
|
|
3
|
+
import { assetPathOrUndefined } from "../revisions/mutation-assets.js";
|
|
4
|
+
import { isDonePiece } from "../revisions/view.js";
|
|
3
5
|
import { retainedNarrationPieces } from "./narration-history.js";
|
|
4
6
|
import { matchingNarrationPiece } from "./narration-reuse.js";
|
|
5
7
|
export function bindNarrationReuse(deps, view, recipe, ordinal) {
|
|
@@ -30,17 +32,14 @@ export function bindNarrationReuse(deps, view, recipe, ordinal) {
|
|
|
30
32
|
return;
|
|
31
33
|
}
|
|
32
34
|
if (recipe.input.kind === "provided" && /^audio:(body:.+|intro|outro):[0-9]+$/.test(recipe.key)) {
|
|
33
|
-
if (view.pieces.some((one) => one.
|
|
34
|
-
one.available &&
|
|
35
|
-
one.key === recipe.key &&
|
|
35
|
+
if (view.pieces.some((one) => isDonePiece(one, recipe.key) &&
|
|
36
36
|
one.fingerprint === recipe.fingerprint &&
|
|
37
|
-
one.piece.state === "done" &&
|
|
38
37
|
one.piece.idx === ordinal))
|
|
39
38
|
return;
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (
|
|
39
|
+
const file = recipe.input.assetId === null
|
|
40
|
+
? undefined
|
|
41
|
+
: assetPathOrUndefined(deps, view.revision.projectId, recipe.input.assetId);
|
|
42
|
+
if (file === undefined)
|
|
44
43
|
return;
|
|
45
44
|
const semantic = z
|
|
46
45
|
.tuple([z.string(), z.array(z.string().nullable())])
|
|
@@ -67,7 +66,7 @@ export function bindNarrationReuse(deps, view, recipe, ordinal) {
|
|
|
67
66
|
state: "done",
|
|
68
67
|
payload: JSON.stringify({
|
|
69
68
|
provided: true,
|
|
70
|
-
file
|
|
69
|
+
file,
|
|
71
70
|
logicalKey: recipe.key.slice(0, recipe.key.lastIndexOf(":")),
|
|
72
71
|
logicalText: semantic[0],
|
|
73
72
|
text: semantic[0],
|
|
@@ -85,11 +84,8 @@ export function bindNarrationReuse(deps, view, recipe, ordinal) {
|
|
|
85
84
|
if (recipe.input.kind !== "tts")
|
|
86
85
|
return;
|
|
87
86
|
const input = recipe.input;
|
|
88
|
-
if (view.pieces.some((one) => one.
|
|
89
|
-
one.available &&
|
|
90
|
-
one.key === recipe.key &&
|
|
87
|
+
if (view.pieces.some((one) => isDonePiece(one, recipe.key) &&
|
|
91
88
|
one.fingerprint === recipe.fingerprint &&
|
|
92
|
-
one.piece.state === "done" &&
|
|
93
89
|
one.piece.idx === ordinal &&
|
|
94
90
|
narrationMetadataMatches(one.piece.payload, input)))
|
|
95
91
|
return;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { internalError } from "../../kernel/errors.js";
|
|
3
|
+
import { isDonePiece } from "../revisions/view.js";
|
|
4
|
+
import { executionPlan, executionView, savedCatalogue, workCatalogue } from "./runtime-plan.js";
|
|
3
5
|
import { preparedTexts, publishResult } from "./runtime-publication.js";
|
|
4
6
|
export function joinedNarration(parts) {
|
|
5
7
|
return parts
|
|
@@ -9,14 +11,10 @@ export function joinedNarration(parts) {
|
|
|
9
11
|
export function narrationTextParts(view, plan, segment) {
|
|
10
12
|
const concat = plan.recipes.find((row) => row.key === (segment === "body" ? "audio:body:concat" : `audio:${segment}`));
|
|
11
13
|
if (concat === undefined)
|
|
12
|
-
throw new Error(`
|
|
14
|
+
throw new Error(internalError(`the ${segment} narration is missing from the project plan`));
|
|
13
15
|
return concat.dependsOn.map((key) => {
|
|
14
16
|
const recipe = plan.recipes.find((row) => row.key === key);
|
|
15
|
-
const selected = view.pieces.find((row) => row.key === key &&
|
|
16
|
-
row.selected &&
|
|
17
|
-
row.available &&
|
|
18
|
-
row.piece.state === "done" &&
|
|
19
|
-
row.fingerprint === recipe?.fingerprint);
|
|
17
|
+
const selected = view.pieces.find((row) => row.key === key && isDonePiece(row) && row.fingerprint === recipe?.fingerprint);
|
|
20
18
|
if (selected === undefined || recipe === undefined)
|
|
21
19
|
throw new Error("Some narration chunks aren't finished, so the full narration text isn't available. Let the Narration stage finish (Resume, or Try again on it), or regenerate the missing chunk in Edit project → Narration.");
|
|
22
20
|
const input = recipe.input;
|
|
@@ -29,7 +27,7 @@ export function narrationTextParts(view, plan, segment) {
|
|
|
29
27
|
requestText: null,
|
|
30
28
|
};
|
|
31
29
|
if (input.kind !== "tts")
|
|
32
|
-
throw new Error("
|
|
30
|
+
throw new Error(internalError("a narration chunk's text was never worked out"));
|
|
33
31
|
const payload = z
|
|
34
32
|
.object({ text: z.string().optional(), spokenText: z.string().optional() })
|
|
35
33
|
.parse(JSON.parse(selected.piece.payload ?? "{}"));
|
|
@@ -45,19 +43,16 @@ export function narrationTextParts(view, plan, segment) {
|
|
|
45
43
|
}
|
|
46
44
|
export async function publishNarrationText(deps, context, piece) {
|
|
47
45
|
if (piece.input.kind !== "local")
|
|
48
|
-
throw new Error("
|
|
46
|
+
throw new Error(internalError("the narration text file step was set up wrongly"));
|
|
49
47
|
const { segment } = z
|
|
50
48
|
.object({ segment: z.enum(["body", "intro", "outro"]) })
|
|
51
49
|
.parse(piece.input.values);
|
|
52
50
|
const view = executionView(deps, context.work.projectId, context.work.revisionId);
|
|
53
|
-
const row = deps.db
|
|
54
|
-
.prepare("SELECT recipe_context FROM revision_work WHERE id=?")
|
|
55
|
-
.get(context.work.workId);
|
|
56
51
|
if (view === undefined)
|
|
57
|
-
throw new Error("
|
|
58
|
-
const plan = executionPlan(deps, view,
|
|
52
|
+
throw new Error(internalError("the project version being narrated is missing"));
|
|
53
|
+
const plan = executionPlan(deps, view, workCatalogue(deps.db, context.work.workId));
|
|
59
54
|
if (!plan.recipes.some((recipe) => recipe.key === piece.key && recipe.fingerprint === piece.fingerprint))
|
|
60
|
-
throw new Error("
|
|
55
|
+
throw new Error(internalError("the narration text no longer matches the project's saved inputs"));
|
|
61
56
|
const parts = narrationTextParts(view, plan, segment);
|
|
62
57
|
const outputs = preparedTexts(deps, context, piece, [
|
|
63
58
|
["narration_txt", `${segment}-narration.txt`, joinedNarration(parts)],
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { basename } from "node:path";
|
|
3
|
+
import { assetPathOrUndefined } from "../revisions/mutation-assets.js";
|
|
3
4
|
import { outputPath } from "../storage/layout.js";
|
|
4
5
|
// The file behind a picture the article names (``): an image uploaded
|
|
5
6
|
// to the project under that file name. An article's pictures are otherwise web addresses
|
|
@@ -14,10 +15,7 @@ export function articlePicture(deps, view, named) {
|
|
|
14
15
|
for (const image of Object.values(view.revision.content.imageDefinitions)) {
|
|
15
16
|
if (image.source !== "provide" || image.assetId === null)
|
|
16
17
|
continue;
|
|
17
|
-
const
|
|
18
|
-
.prepare("SELECT path FROM project_assets WHERE id=? AND project_id=?")
|
|
19
|
-
.get(image.assetId, view.revision.projectId);
|
|
20
|
-
const path = typeof row?.path === "string" ? row.path : undefined;
|
|
18
|
+
const path = assetPathOrUndefined(deps, view.revision.projectId, image.assetId);
|
|
21
19
|
if (path === undefined || basename(path).toLowerCase() !== name)
|
|
22
20
|
continue;
|
|
23
21
|
const file = outputPath(deps.paths, view.revision.projectId, path);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { platformLabels, socialPlatforms } from "../social/model.js";
|
|
2
|
+
import { executionPlan, executionView, workCatalogueIfSaved } from "./runtime-plan.js";
|
|
2
3
|
// What a failed step is called on screen, so its error says which image, chunk or topic to
|
|
3
4
|
// fix. Worked out only after a failure: numbering a narration chunk means building the plan.
|
|
4
5
|
// Undefined for steps that name their own place (captions, export) or have no single one.
|
|
@@ -17,6 +18,9 @@ export function pieceLabel(deps, context, piece) {
|
|
|
17
18
|
return "Document";
|
|
18
19
|
if (key === "youtube:description")
|
|
19
20
|
return "YouTube description";
|
|
21
|
+
const post = /^social:post:([a-z]+)$/.exec(key);
|
|
22
|
+
if (post !== null)
|
|
23
|
+
return `${platformLabels[socialPlatforms.find((one) => one === post[1]) ?? "x"]} post`;
|
|
20
24
|
if (key.startsWith("review:")) {
|
|
21
25
|
const item = key.slice("review:".length);
|
|
22
26
|
const itemLabel = item === "narration"
|
|
@@ -47,6 +51,8 @@ export function pieceLabel(deps, context, piece) {
|
|
|
47
51
|
return "Animated images";
|
|
48
52
|
if (key === "images:scenes")
|
|
49
53
|
return "Image scenes";
|
|
54
|
+
if (key === "article:digest")
|
|
55
|
+
return "Keyword digest";
|
|
50
56
|
const short = /^shorts:(\d+):(prompts|image:(\d+)|render)$/.exec(key);
|
|
51
57
|
if (short !== null)
|
|
52
58
|
return short[2] === "prompts"
|
|
@@ -84,13 +90,11 @@ export function pieceLabel(deps, context, piece) {
|
|
|
84
90
|
return narrationChunk(deps, context, segment, key, prefix) ?? prefix;
|
|
85
91
|
}
|
|
86
92
|
function narrationChunk(deps, context, segment, key, prefix) {
|
|
87
|
-
const
|
|
88
|
-
.prepare("SELECT recipe_context FROM revision_work WHERE id=?")
|
|
89
|
-
.get(context.work.workId);
|
|
93
|
+
const catalogue = workCatalogueIfSaved(deps.db, context.work.workId);
|
|
90
94
|
const view = executionView(deps, context.work.projectId, context.work.revisionId);
|
|
91
|
-
if (
|
|
95
|
+
if (catalogue === undefined || view === undefined)
|
|
92
96
|
return undefined;
|
|
93
|
-
const plan = executionPlan(deps, view,
|
|
97
|
+
const plan = executionPlan(deps, view, catalogue);
|
|
94
98
|
const concat = plan.recipes.find((recipe) => recipe.key === (segment === "body" ? "audio:body:concat" : `audio:${segment}`));
|
|
95
99
|
if (concat === undefined)
|
|
96
100
|
return undefined;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { catalogueSchema } from "../../catalog/schema.js";
|
|
4
|
-
import { getRevisionView, withEarlierJoins } from "../revisions/view.js";
|
|
4
|
+
import { getRevisionView, readyOutput, withEarlierJoins } from "../revisions/view.js";
|
|
5
5
|
import { outputPath } from "../storage/layout.js";
|
|
6
6
|
import { referencedAssetsAvailable, retainedNarrationPieces } from "./narration-history.js";
|
|
7
7
|
import { applyProvidedReviews } from "./provided-review.js";
|
|
@@ -22,12 +22,38 @@ export function executionCatalogue(catalogue, config) {
|
|
|
22
22
|
export function savedCatalogue(value) {
|
|
23
23
|
return catalogueSchema.parse(JSON.parse(z.string().parse(value)));
|
|
24
24
|
}
|
|
25
|
+
function savedContext(db, workId) {
|
|
26
|
+
return db.prepare("SELECT recipe_context FROM revision_work WHERE id=?").get(workId)
|
|
27
|
+
?.recipe_context;
|
|
28
|
+
}
|
|
29
|
+
// The catalogue a work was admitted with, saved beside it; a work without one is a bug.
|
|
30
|
+
export function workCatalogue(db, workId) {
|
|
31
|
+
return savedCatalogue(savedContext(db, workId));
|
|
32
|
+
}
|
|
33
|
+
// The same, or undefined for a work (or a missing one) that has no catalogue saved.
|
|
34
|
+
export function workCatalogueIfSaved(db, workId) {
|
|
35
|
+
const context = savedContext(db, workId);
|
|
36
|
+
return context === null || context === undefined ? undefined : savedCatalogue(context);
|
|
37
|
+
}
|
|
38
|
+
// A step's LLM call on its work's saved catalogue: the chosen model with the thinking settings
|
|
39
|
+
// the catalogue holds for its level, no web search, labelled with the step. The catalogue is
|
|
40
|
+
// read once, as the builder is made.
|
|
41
|
+
export function workLlm(db, workId, choice, label) {
|
|
42
|
+
const catalogued = workCatalogue(db, workId).llm.find((one) => one.provider === choice.provider && one.id === choice.model);
|
|
43
|
+
const { thinking } = choice;
|
|
44
|
+
return (call) => ({
|
|
45
|
+
provider: choice.provider,
|
|
46
|
+
model: choice.model,
|
|
47
|
+
...(thinking === undefined ? {} : { thinking }),
|
|
48
|
+
thinkingConfig: thinking === undefined ? null : (catalogued?.llm.thinking?.[thinking] ?? null),
|
|
49
|
+
webSearch: false,
|
|
50
|
+
previewLabel: label,
|
|
51
|
+
...call,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
25
54
|
export function executionPlan(deps, view, catalogue) {
|
|
26
55
|
const textOutput = (role) => {
|
|
27
|
-
const row = view
|
|
28
|
-
output.available &&
|
|
29
|
-
output.state === "ready" &&
|
|
30
|
-
output.output.role === role);
|
|
56
|
+
const row = readyOutput(view, { role });
|
|
31
57
|
return row === undefined
|
|
32
58
|
? null
|
|
33
59
|
: readFileSync(outputPath(deps.paths, view.revision.projectId, row.output.path), "utf8");
|