@gentbajko/slopify 4.0.0 → 4.1.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 +1 -1
- package/dist/adapters/alignment/audio.js +1 -1
- package/dist/adapters/alignment/cache.js +1 -1
- package/dist/adapters/alignment/multilingual.js +2 -1
- package/dist/adapters/alignment/runner.js +1 -1
- package/dist/adapters/alignment/worker.js +1 -1
- package/dist/adapters/explain.js +10 -9
- package/dist/adapters/host-cli/index.js +2 -1
- package/dist/adapters/host-cli/transport.js +2 -1
- package/dist/adapters/image/bytes.js +2 -1
- package/dist/adapters/image/codex.js +6 -5
- package/dist/adapters/image/fal.js +4 -3
- package/dist/adapters/image/google.js +3 -2
- package/dist/adapters/image/models.js +2 -2
- package/dist/adapters/image/openai.js +2 -1
- package/dist/adapters/image/replicate.js +3 -2
- package/dist/adapters/image/video.js +2 -1
- package/dist/adapters/key-probes.js +1 -1
- package/dist/adapters/llm/antigravity-models.js +1 -1
- package/dist/adapters/llm/antigravity.js +7 -6
- package/dist/adapters/llm/assistant-cli.js +1 -1
- package/dist/adapters/llm/claude-code-models.js +1 -1
- package/dist/adapters/llm/claude-code.js +3 -2
- package/dist/adapters/llm/codex-models.js +1 -1
- package/dist/adapters/llm/document-workspace.js +3 -2
- package/dist/adapters/llm/image-workspace.js +3 -2
- package/dist/adapters/llm/openrouter.js +2 -1
- package/dist/adapters/llm/run-cli.js +3 -2
- package/dist/adapters/tts/gemini.js +2 -1
- package/dist/adapters/tts/inworld-async.js +2 -1
- package/dist/adapters/tts/inworld.js +3 -2
- package/dist/adapters/tts/system.js +2 -1
- package/dist/catalog/registry.js +20 -13
- package/dist/catalog/schema.js +2 -1
- package/dist/catalog/validate.js +5 -2
- package/dist/edge/http/actions.js +7 -7
- package/dist/edge/http/app.js +3 -3
- package/dist/edge/http/assistant.js +3 -1
- package/dist/edge/http/backups.js +1 -1
- package/dist/edge/http/channel-memory.js +2 -2
- package/dist/edge/http/channels.js +1 -1
- package/dist/edge/http/checkpoints.js +7 -5
- package/dist/edge/http/design-templates.js +3 -3
- package/dist/edge/http/designs.js +1 -1
- package/dist/edge/http/document-themes.js +3 -3
- package/dist/edge/http/draft-problem.js +1 -1
- package/dist/edge/http/extension-auth.js +1 -1
- package/dist/edge/http/home.js +9 -1
- package/dist/edge/http/model-checks.js +4 -4
- package/dist/edge/http/onboarding.js +29 -12
- package/dist/edge/http/outputs.js +3 -2
- package/dist/edge/http/patch-notes.js +2 -2
- package/dist/edge/http/planning.js +1 -1
- package/dist/edge/http/project-create.js +1 -1
- package/dist/edge/http/project-templates.js +2 -2
- package/dist/edge/http/projects.js +22 -4
- package/dist/edge/http/prompts.js +2 -2
- package/dist/edge/http/providers.js +9 -10
- package/dist/edge/http/refusal.js +1 -1
- package/dist/edge/http/remote-access.js +4 -4
- package/dist/edge/http/remote-guard.js +2 -2
- package/dist/edge/http/reviews.js +1 -1
- package/dist/edge/http/revision-files.js +1 -1
- package/dist/edge/http/revisions.js +4 -4
- package/dist/edge/http/schedules.js +13 -11
- package/dist/edge/http/settings.js +6 -2
- package/dist/edge/http/social.js +5 -4
- package/dist/edge/http/staging.js +1 -1
- package/dist/edge/http/storage.js +12 -4
- package/dist/edge/http/studio.js +71 -19
- package/dist/edge/http/style-preview.js +2 -2
- package/dist/edge/http/template-studio.js +12 -9
- package/dist/edge/http/trash.js +1 -1
- package/dist/edge/http/youtube-edits.js +1 -1
- package/dist/edge/mcp/excluded-routes.js +4 -3
- package/dist/edge/mcp/instructions.js +3 -3
- package/dist/edge/mcp/library-tools.js +8 -5
- package/dist/edge/mcp/remake-tools.js +7 -4
- package/dist/edge/mcp/server.js +1 -1
- package/dist/edge/mcp/tools-channels.js +9 -9
- package/dist/edge/mcp/tools-designs.js +9 -9
- package/dist/edge/mcp/tools-library.js +7 -7
- package/dist/edge/mcp/tools-planning.js +18 -18
- package/dist/edge/mcp/tools-projects.js +10 -10
- package/dist/edge/mcp/tools-publishing.js +9 -9
- package/dist/edge/mcp/tools-runs.js +9 -9
- package/dist/edge/mcp/tools-schedules.js +6 -6
- package/dist/edge/mcp/tools-setup.js +20 -14
- package/dist/edge/mcp/tools-social.js +5 -4
- package/dist/edge/mcp/tools-storage.js +3 -3
- package/dist/edge/mcp/tools-template-studio.js +18 -18
- package/dist/edge/remote-access/model.js +1 -1
- package/dist/extension/slopify-studio-chrome.zip +0 -0
- package/dist/extension/slopify-studio-firefox.zip +0 -0
- package/dist/kernel/db/migrations/0078-uploaded-from-links.sql +7 -0
- package/dist/kernel/pipeline.js +12 -0
- package/dist/kernel/ports/settings-places.js +31 -0
- package/dist/kernel/ports/system-speech.js +31 -3
- package/dist/kernel/runner/attempt.js +11 -3
- package/dist/kernel/runner/providers.js +3 -2
- package/dist/kernel/runner/standalone.js +2 -2
- package/dist/main.js +5 -3
- package/dist/model-catalog.js +20 -0
- package/dist/patch-notes/4.0.0.md +13 -13
- package/dist/patch-notes/4.1.0.md +42 -0
- package/dist/patch-notes/index.json +6 -0
- package/dist/slices/admission/listing-facts.js +95 -0
- package/dist/slices/admission/repo.js +9 -6
- package/dist/slices/admission/rules.js +7 -7
- package/dist/slices/admission/state-words.js +34 -5
- package/dist/slices/assistant/cost.js +1 -1
- package/dist/slices/assistant/model.js +10 -3
- package/dist/slices/assistant/turn.js +5 -3
- package/dist/slices/autopilot/warnings.js +1 -1
- package/dist/slices/backups/service.js +5 -5
- package/dist/slices/channels/cast-images.js +1 -1
- package/dist/slices/channels/schema.js +1 -1
- package/dist/slices/channels/videos.js +1 -1
- package/dist/slices/control/providers.js +2 -2
- package/dist/slices/designs/budget.js +1 -1
- package/dist/slices/designs/calls.js +2 -2
- package/dist/slices/designs/check-context.js +4 -4
- package/dist/slices/designs/fields.js +4 -4
- package/dist/slices/designs/gate.js +7 -5
- package/dist/slices/designs/render-input.js +1 -1
- package/dist/slices/designs/requests.js +1 -1
- package/dist/slices/designs/runner.js +1 -1
- package/dist/slices/designs/sample.js +2 -1
- package/dist/slices/designs/service.js +1 -1
- package/dist/slices/designs/template-checks.js +2 -2
- package/dist/slices/designs/template-make.js +3 -3
- package/dist/slices/designs/templates.js +3 -3
- package/dist/slices/document/fonts.js +1 -1
- package/dist/slices/document/model.js +7 -4
- package/dist/slices/document/render.js +2 -1
- package/dist/slices/document/theme-schema.js +1 -1
- package/dist/slices/document/theme.js +49 -3
- package/dist/slices/episodes/summarize.js +2 -2
- package/dist/slices/estimate/index.js +28 -22
- package/dist/slices/estimate/requests.js +4 -4
- package/dist/slices/fixes/rules.js +3 -1
- package/dist/slices/fonts/catalog.js +2 -1
- package/dist/slices/fonts/coverage.js +2 -1
- package/dist/slices/images/appearance.js +2 -1
- package/dist/slices/images/scenes.js +2 -1
- package/dist/slices/keywords/digest.js +2 -1
- package/dist/slices/keywords/rules.js +2 -2
- package/dist/slices/keywords/specs.js +5 -5
- package/dist/slices/keywords/values.js +1 -1
- package/dist/slices/library/transfer.js +3 -3
- package/dist/slices/loudness/loudnorm.js +2 -1
- package/dist/slices/loudness/model.js +3 -2
- package/dist/slices/loudness/sentence-level.js +2 -1
- package/dist/slices/model-checks/rules.js +13 -0
- package/dist/slices/model-upkeep/model.js +1 -1
- package/dist/slices/model-upkeep/switch.js +3 -3
- package/dist/slices/model-upkeep/usage.js +13 -2
- package/dist/slices/narration/breaths.js +2 -1
- package/dist/slices/narration/clean-pieces.js +2 -1
- package/dist/slices/narration/pauses-model.js +3 -2
- package/dist/slices/narration/pronunciation.js +3 -2
- package/dist/slices/notifications/subject.js +2 -2
- package/dist/slices/onboarding/copy.js +19 -2
- package/dist/slices/onboarding/first-run.js +13 -38
- package/dist/slices/onboarding/install.js +2 -1
- package/dist/slices/onboarding/model.js +26 -21
- package/dist/slices/onboarding/preferred-model.js +14 -0
- package/dist/slices/onboarding/quick-short.js +103 -64
- package/dist/slices/onboarding/sample.js +4 -1
- package/dist/slices/onboarding/state.js +7 -0
- package/dist/slices/onboarding/template.js +6 -5
- package/dist/slices/outputs/add.js +3 -2
- package/dist/slices/outputs/service.js +2 -2
- package/dist/slices/patch-notes/library.js +1 -1
- package/dist/slices/play-drafts/readiness.js +3 -3
- package/dist/slices/play-drafts/review-inputs.js +1 -1
- package/dist/slices/play-drafts/service.js +17 -7
- package/dist/slices/project-templates/next-chapter.js +2 -1
- package/dist/slices/project-templates/provider-defaults.js +22 -0
- package/dist/slices/project-templates/setup-sections.js +26 -0
- package/dist/slices/project-templates/setup.js +6 -1
- package/dist/slices/rebuild/preview-details.js +5 -5
- package/dist/slices/rebuild/recipe-preparation.js +1 -1
- package/dist/slices/rebuild/recipe-save.js +2 -2
- package/dist/slices/rebuild/recipe-validation.js +5 -4
- package/dist/slices/rebuild/recipe-voices.js +3 -2
- package/dist/slices/rebuild/recipe-work.js +4 -4
- package/dist/slices/rebuild/recovery.js +6 -6
- package/dist/slices/rebuild/remake-outdated.js +5 -5
- package/dist/slices/rebuild/review-redo.js +1 -1
- package/dist/slices/rebuild/runtime-animate.js +2 -2
- package/dist/slices/rebuild/runtime-article.js +4 -3
- package/dist/slices/rebuild/runtime-document.js +5 -4
- package/dist/slices/rebuild/runtime-export-bed.js +2 -1
- package/dist/slices/rebuild/runtime-export-edit.js +2 -1
- package/dist/slices/rebuild/runtime-export-inputs.js +5 -4
- package/dist/slices/rebuild/runtime-export-short.js +1 -1
- package/dist/slices/rebuild/runtime-export.js +4 -3
- package/dist/slices/rebuild/runtime-image.js +4 -3
- package/dist/slices/rebuild/runtime-local.js +3 -2
- package/dist/slices/rebuild/runtime-narration-text.js +3 -2
- package/dist/slices/rebuild/runtime-provider.js +7 -6
- package/dist/slices/rebuild/runtime-review.js +6 -5
- package/dist/slices/rebuild/runtime-shorts.js +6 -5
- package/dist/slices/rebuild/runtime-store.js +17 -2
- package/dist/slices/rebuild/runtime-subtitles.js +13 -12
- package/dist/slices/rebuild/runtime-voices.js +2 -1
- package/dist/slices/rebuild/runtime-youtube.js +3 -2
- package/dist/slices/rebuild/service-readiness.js +11 -3
- package/dist/slices/research/synthesis.js +3 -2
- package/dist/slices/reviews/external-model.js +1 -1
- package/dist/slices/reviews/holds.js +5 -4
- package/dist/slices/reviews/model.js +8 -5
- package/dist/slices/reviews/rules.js +3 -3
- package/dist/slices/reviews/verdict.js +2 -1
- package/dist/slices/revisions/image-plan.js +1 -1
- package/dist/slices/revisions/mutation-assets.js +2 -1
- package/dist/slices/revisions/mutations.js +3 -2
- package/dist/slices/schedules/agenda.js +7 -5
- package/dist/slices/schedules/design-check.js +4 -4
- package/dist/slices/schedules/design-run.js +3 -3
- package/dist/slices/schedules/repo.js +6 -5
- package/dist/slices/schedules/schema.js +3 -0
- package/dist/slices/schedules/topics.js +5 -5
- package/dist/slices/settings/first-run.js +6 -32
- package/dist/slices/settings/health.js +30 -15
- package/dist/slices/settings/key-test.js +1 -1
- package/dist/slices/settings/model.js +4 -2
- package/dist/slices/settings/playback.js +2 -2
- package/dist/slices/shorts/keep.js +2 -1
- package/dist/slices/shorts/pick.js +4 -3
- package/dist/slices/shorts/prompts.js +2 -1
- package/dist/slices/shorts/render.js +3 -2
- package/dist/slices/social/media.js +5 -4
- package/dist/slices/social/pack.js +1 -1
- package/dist/slices/social/post-prompt.js +2 -1
- package/dist/slices/social/reshape.js +2 -2
- package/dist/slices/social/serve.js +1 -1
- package/dist/slices/social/service.js +3 -2
- package/dist/slices/social/state.js +1 -1
- package/dist/slices/storage/backup-import.js +2 -2
- package/dist/slices/storage/portable.js +1 -1
- package/dist/slices/storage/trim.js +23 -13
- package/dist/slices/studio/calendar.js +3 -1
- package/dist/slices/studio/disclosure.js +4 -4
- package/dist/slices/studio/model.js +1 -1
- package/dist/slices/studio/pack.js +9 -8
- package/dist/slices/studio/plan.js +1 -1
- package/dist/slices/studio/settings.js +6 -6
- package/dist/slices/studio/videos.js +23 -4
- package/dist/slices/style-preview/render.js +3 -3
- package/dist/slices/style-preview/schema.js +1 -1
- package/dist/slices/subtitles/captions.js +1 -1
- package/dist/slices/template-studio/anatomy-view.js +46 -3
- package/dist/slices/template-studio/bakeoff.js +3 -3
- package/dist/slices/template-studio/budget.js +6 -3
- package/dist/slices/template-studio/cards.js +78 -0
- package/dist/slices/template-studio/checks.js +99 -50
- package/dist/slices/template-studio/for-all.js +5 -5
- package/dist/slices/template-studio/free-video.js +1 -1
- package/dist/slices/template-studio/free.js +5 -5
- package/dist/slices/template-studio/model.js +19 -15
- package/dist/slices/template-studio/pack-import.js +14 -14
- package/dist/slices/template-studio/pack.js +9 -7
- package/dist/slices/template-studio/paid.js +12 -5
- package/dist/slices/template-studio/quote.js +18 -11
- package/dist/slices/template-studio/ready.js +7 -7
- package/dist/slices/template-studio/runner.js +1 -1
- package/dist/slices/template-studio/save.js +12 -12
- package/dist/slices/template-studio/say-it-as.js +3 -3
- package/dist/slices/template-studio/schedule-gate.js +1 -1
- package/dist/slices/template-studio/schedule-price.js +3 -1
- package/dist/slices/template-studio/schedule-sample.js +5 -1
- package/dist/slices/template-studio/schema.js +25 -0
- package/dist/slices/template-studio/service.js +3 -1
- package/dist/slices/template-studio/status.js +26 -9
- package/dist/slices/template-studio/topic.js +3 -3
- package/dist/slices/thumbnail/by-llm.js +1 -1
- package/dist/slices/uploads/repo.js +37 -1
- package/dist/slices/uploads/rules.js +3 -2
- package/dist/slices/video/edit-list.js +2 -2
- package/dist/slices/video/edit-settings.js +1 -1
- package/dist/slices/video/encoding.js +14 -5
- package/dist/slices/video/ffmpeg.js +2 -2
- package/dist/slices/video/plan.js +2 -1
- package/dist/slices/video/slideshow.js +1 -1
- package/dist/slices/voices/attribution.js +3 -2
- package/dist/slices/voices/model.js +9 -8
- package/dist/slices/voices/script.js +2 -1
- package/dist/slices/youtube/answer.js +2 -1
- package/dist/slices/youtube/edits-repo.js +1 -1
- package/dist/tutorials/AI-CLIs.md +25 -25
- package/dist/tutorials/Agents-MCP.md +32 -32
- package/dist/tutorials/Assistant.md +5 -5
- package/dist/tutorials/Backups.md +7 -7
- package/dist/tutorials/Calendar.md +17 -25
- package/dist/tutorials/Cast-Library.md +19 -19
- package/dist/tutorials/Channels.md +40 -35
- package/dist/tutorials/Costs-and-Run-Cost.md +38 -40
- package/dist/tutorials/Create-Article.md +114 -0
- package/dist/tutorials/Create-Extras.md +112 -0
- package/dist/tutorials/Create-Images.md +165 -0
- package/dist/tutorials/Create-Narration.md +178 -0
- package/dist/tutorials/Create-Overview.md +244 -0
- package/dist/tutorials/Create-Video-and-Style.md +144 -0
- package/dist/tutorials/Docker.md +3 -3
- package/dist/tutorials/Document-Themes.md +32 -32
- package/dist/tutorials/Editing-a-Project.md +94 -94
- package/dist/tutorials/FAQ.md +18 -18
- package/dist/tutorials/First-Launch-and-Welcome.md +50 -64
- package/dist/tutorials/Home-and-Projects.md +101 -76
- package/dist/tutorials/Home.md +33 -33
- package/dist/tutorials/Install.md +13 -13
- package/dist/tutorials/Intros-and-Outros.md +33 -34
- package/dist/tutorials/Keyboard-Shortcuts-and-Command-Palette.md +62 -58
- package/dist/tutorials/Keywords-Slopify-Fills.md +21 -21
- package/dist/tutorials/Models.md +27 -27
- package/dist/tutorials/Multiple-Voices.md +41 -40
- package/dist/tutorials/Narration-Aliases-and-Glossary.md +14 -14
- package/dist/tutorials/Notifications.md +21 -17
- package/dist/tutorials/Other-Languages.md +15 -15
- package/dist/tutorials/PDF-Documents.md +38 -29
- package/dist/tutorials/Posting-to-Social-Sites.md +12 -12
- package/dist/tutorials/Project-Page.md +118 -120
- package/dist/tutorials/Prompts-and-Templates.md +84 -0
- package/dist/tutorials/Prompts.md +45 -45
- package/dist/tutorials/Providers-and-Keys.md +105 -98
- package/dist/tutorials/Publishing-to-YouTube.md +31 -31
- package/dist/tutorials/Recovery-and-Retries.md +31 -31
- package/dist/tutorials/Remote-Access.md +2 -2
- package/dist/tutorials/Reviews-and-Checkpoints.md +90 -93
- package/dist/tutorials/Schedules.md +27 -28
- package/dist/tutorials/Settings-Reference.md +182 -204
- package/dist/tutorials/Shorts.md +34 -33
- package/dist/tutorials/Start-at-Login.md +3 -3
- package/dist/tutorials/Studio-Extension.md +22 -24
- package/dist/tutorials/Template-Studio.md +45 -42
- package/dist/tutorials/Templates.md +50 -79
- package/dist/tutorials/Trash.md +4 -4
- package/dist/tutorials/Troubleshooting.md +44 -44
- package/dist/tutorials/Uninstalling-and-Moving.md +5 -5
- package/dist/tutorials/Updating-and-Patch-Notes.md +18 -18
- package/dist/tutorials/Video-Editing.md +34 -34
- package/dist/tutorials/Where-Your-Files-Live.md +10 -10
- package/dist/tutorials/YouTube-Description.md +26 -26
- package/dist/tutorials/Your-First-Short.md +35 -35
- package/dist/tutorials/_Sidebar.md +15 -15
- package/dist/web/assets/index-BNftKQrA.css +1 -0
- package/dist/web/assets/index-Cpa58woP.js +459 -0
- package/dist/web/assets/pdf-BKh8f7R6.js +56 -0
- package/dist/web/assets/pdf.worker.min-BmVo14Nb.mjs +28 -0
- package/dist/web/assets/pdf.worker.min-D7i8o3wR.js +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +2 -2
- package/dist/tutorials/Library-Overview.md +0 -76
- package/dist/tutorials/Play-Images.md +0 -165
- package/dist/tutorials/Play-Narration.md +0 -167
- package/dist/tutorials/Play-Outputs.md +0 -109
- package/dist/tutorials/Play-Overview.md +0 -227
- package/dist/tutorials/Play-Title-and-Article.md +0 -136
- package/dist/tutorials/Play-Video-and-Style.md +0 -143
- package/dist/web/assets/index-CkAI_2E7.css +0 -1
- package/dist/web/assets/index-DcD0cdfo.js +0 -334
- package/dist/web/assets/pdf-TODRwF31.js +0 -54
- package/dist/web/assets/pdf.worker.min-Dswkl-cV.mjs +0 -29
- package/dist/web/assets/pdf.worker.min-zC6nfbxG.js +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { stageKinds } from "../../kernel/pipeline.js";
|
|
2
|
+
import { editSettings } from "../../kernel/ports/settings-places.js";
|
|
2
3
|
import { sourceOf } from "../admission/model.js";
|
|
3
4
|
import { defaultVoicesSettings } from "../voices/model.js";
|
|
4
5
|
// Another output made from a project that already exists: the same brief, sources and
|
|
@@ -53,7 +54,7 @@ export function planAddedOutput(config, kind) {
|
|
|
53
54
|
return {
|
|
54
55
|
ok: false,
|
|
55
56
|
reason: "narration-taken",
|
|
56
|
-
message: `This project already has narration, and a project has one: ${kind === "podcast" ? "a podcast" : "an audiobook"} would replace it. Keep it, or change its format under Speakers in
|
|
57
|
+
message: `This project already has narration, and a project has one: ${kind === "podcast" ? "a podcast" : "an audiobook"} would replace it. Keep it, or change its format under Speakers in ${editSettings.narration}.`,
|
|
57
58
|
};
|
|
58
59
|
const sources = switchedOn(config, kind);
|
|
59
60
|
const next = {
|
|
@@ -78,7 +79,7 @@ export function planAddedOutput(config, kind) {
|
|
|
78
79
|
reused: ["Brief: title, prompts and keywords", ...kept.map((stage) => stageResults[stage])],
|
|
79
80
|
created: createdWords(kind, stages),
|
|
80
81
|
textUse: kind === "podcast"
|
|
81
|
-
? "Adapted: the
|
|
82
|
+
? "Adapted: the AI model rewrites your article as a conversation between two hosts for the narration. The article stays as written; the conversation is kept beside it as the script."
|
|
82
83
|
: kind === "images"
|
|
83
84
|
? "Your text is not changed."
|
|
84
85
|
: "Your text is used as written: nothing is rewritten.",
|
|
@@ -117,9 +117,9 @@ function newProblems(before, after) {
|
|
|
117
117
|
.map((one) => ({ field: one.field, message: settingsHint(one) }));
|
|
118
118
|
}
|
|
119
119
|
function settingsHint(problem) {
|
|
120
|
-
return /Settings|Edit
|
|
120
|
+
return /Settings|Edit settings/.test(problem.message)
|
|
121
121
|
? problem.message
|
|
122
|
-
: `${problem.message} Set it in
|
|
122
|
+
: `${problem.message} Set it in Edit settings, save, then add the output again.`;
|
|
123
123
|
}
|
|
124
124
|
function catalogueOf(deps) {
|
|
125
125
|
return (deps.catalogue?.read() ?? {
|
|
@@ -4,7 +4,7 @@ import { join } from "node:path";
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import { hasErrnoCode } from "../../kernel/errors.js";
|
|
7
|
-
// The patch notes the app shows in Settings →
|
|
7
|
+
// The patch notes the app shows in Settings → What's new: Markdown files kept in the
|
|
8
8
|
// repository's docs/patch-notes/ and copied into the build beside the compiled code
|
|
9
9
|
// (scripts/copy-assets.mjs). index.json lists them with a title and a date; each note is
|
|
10
10
|
// `<id>.md` beside it. Nothing here writes: the notes are part of the release.
|
|
@@ -63,7 +63,7 @@ export async function checkDraftReadiness(deps, runs) {
|
|
|
63
63
|
field: c.field,
|
|
64
64
|
message: provider !== undefined && provider.readiness.kind !== "keyed" && provider.readiness.issue
|
|
65
65
|
? provider.readiness.issue
|
|
66
|
-
: "Set up this provider in Settings →
|
|
66
|
+
: "Set up this provider in Settings → Keys & services before starting.",
|
|
67
67
|
});
|
|
68
68
|
continue;
|
|
69
69
|
}
|
|
@@ -88,12 +88,12 @@ export function localDraftReadiness(deps, runs, providers) {
|
|
|
88
88
|
if (cliPathChanged(deps.db, provider))
|
|
89
89
|
fields.push({
|
|
90
90
|
field: `${c.field}.cliPath`,
|
|
91
|
-
message: "This provider's command-line tool changed in Settings →
|
|
91
|
+
message: "This provider's command-line tool changed in Settings → Keys & services. Choose Review and start again.",
|
|
92
92
|
});
|
|
93
93
|
if (provider?.readiness.kind === "keyed" && !hasKey(deps.db, provider.id))
|
|
94
94
|
fields.push({
|
|
95
95
|
field: c.field,
|
|
96
|
-
message: "Add this provider's API key in Settings →
|
|
96
|
+
message: "Add this provider's API key in Settings → Keys & services before starting.",
|
|
97
97
|
});
|
|
98
98
|
}
|
|
99
99
|
for (const { draft } of runs)
|
|
@@ -161,7 +161,7 @@ unsaved = false) {
|
|
|
161
161
|
: run.draft.sources[stage] !== "generate")
|
|
162
162
|
fields.push({
|
|
163
163
|
field: `checkpoints.${stage}`,
|
|
164
|
-
message: "
|
|
164
|
+
message: "A pause can only go before a step Slopify makes, or before the video. Untick this pause or turn that step on.",
|
|
165
165
|
});
|
|
166
166
|
if (fields.length)
|
|
167
167
|
return reviewRefusal(view, fields);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { statSync } from "node:fs";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { transact } from "../../kernel/db/tx.js";
|
|
4
|
+
import { render } from "../admission/substitute.js";
|
|
4
5
|
import { stagingPath } from "../storage/layout.js";
|
|
5
6
|
import { stagedFileById } from "../storage/repo.js";
|
|
6
7
|
import { releaseStagedFile } from "../storage/staging-refs.js";
|
|
@@ -114,14 +115,23 @@ export function readDraft(deps, id) {
|
|
|
114
115
|
}),
|
|
115
116
|
};
|
|
116
117
|
}
|
|
118
|
+
// A draft is listed by its title as the run would have it, with the topic typed in ("Lore:
|
|
119
|
+
// Cleopatra", not "Lore: {{Topic}}"); a keyword still empty stays in braces.
|
|
117
120
|
export function listDrafts(deps) {
|
|
118
|
-
return draftRows(deps.db).map((row) =>
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
121
|
+
return draftRows(deps.db).map((row) => {
|
|
122
|
+
const document = documentOf(row);
|
|
123
|
+
return {
|
|
124
|
+
id: row.id,
|
|
125
|
+
title: document === null ? row.title : filledTitle(document),
|
|
126
|
+
version: row.version,
|
|
127
|
+
updatedAt: row.updated_at,
|
|
128
|
+
readable: document !== null,
|
|
129
|
+
};
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
function filledTitle(document) {
|
|
133
|
+
const { title, values } = document.form;
|
|
134
|
+
return render(title, Object.fromEntries(Object.entries(values).filter(([, value]) => value.trim() !== "")));
|
|
125
135
|
}
|
|
126
136
|
export function createDraft(deps, input) {
|
|
127
137
|
const parsed = createDraftInputSchema.safeParse(input);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { transact } from "../../kernel/db/tx.js";
|
|
3
|
+
import { createRows } from "../../kernel/ports/settings-places.js";
|
|
3
4
|
import { projectById } from "../admission/repo.js";
|
|
4
5
|
import { projectChannelId } from "../channels/repo.js";
|
|
5
6
|
import { draftRow } from "../play-drafts/repo.js";
|
|
@@ -55,7 +56,7 @@ export function makeNextChapter(deps, input) {
|
|
|
55
56
|
return {
|
|
56
57
|
ok: false,
|
|
57
58
|
reason: "not-an-audiobook",
|
|
58
|
-
message:
|
|
59
|
+
message: `Only an audiobook has chapters. Pick Audiobook as the Format under Speakers (${createRows.narration}) to start a book.`,
|
|
59
60
|
};
|
|
60
61
|
const book = nextBook(revision.config.title, voices.book);
|
|
61
62
|
const document = documentFromProject(deps, revision);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// A template nobody picked a writer or an image service in runs on this computer's defaults,
|
|
2
|
+
// kind by kind, by the same rule Create applies to a draft (web `play/draft-state.ts`
|
|
3
|
+
// withProviderDefaults): a writer nobody picked takes the default writer even where the images
|
|
4
|
+
// were picked, and the other way round; a choice someone made is never changed. Every place a
|
|
5
|
+
// template runs or is checked reads it through here (a draft made from it, a schedule's run, a
|
|
6
|
+
// sample, Edit template's checks and editors), so none of them can disagree about whether it
|
|
7
|
+
// can start.
|
|
8
|
+
export function withProviderDefaults(document, defaults) {
|
|
9
|
+
const { form } = document;
|
|
10
|
+
const llm = form.llm.provider === "" ? defaults.llm : undefined;
|
|
11
|
+
const images = form.images.provider === "" ? defaults.images : undefined;
|
|
12
|
+
if (llm === undefined && images === undefined)
|
|
13
|
+
return document;
|
|
14
|
+
return {
|
|
15
|
+
...document,
|
|
16
|
+
form: {
|
|
17
|
+
...form,
|
|
18
|
+
...(llm === undefined ? {} : { llm: { ...llm } }),
|
|
19
|
+
...(images === undefined ? {} : { images: { ...images } }),
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// One setup, three editors: Create, Edit template and a project's Edit settings show the same
|
|
2
|
+
// setup, so they name its sections alike and list them in this order, the order a run makes
|
|
3
|
+
// them. Each editor keeps its own data model and its own ids; only the names and the order
|
|
4
|
+
// come from here. Browser-safe: the web app imports it too.
|
|
5
|
+
export const setupSectionNames = {
|
|
6
|
+
topic: "Title and keywords",
|
|
7
|
+
article: "Article",
|
|
8
|
+
narration: "Narration",
|
|
9
|
+
images: "Images",
|
|
10
|
+
video: "Video and style",
|
|
11
|
+
thumbnail: "Thumbnail",
|
|
12
|
+
shorts: "Shorts",
|
|
13
|
+
pdf: "PDF",
|
|
14
|
+
checks: "Pauses and checks",
|
|
15
|
+
youtube: "YouTube description and posts",
|
|
16
|
+
schedule: "Schedule",
|
|
17
|
+
};
|
|
18
|
+
// In run order.
|
|
19
|
+
export const setupSections = Object.keys(setupSectionNames);
|
|
20
|
+
// Create and a project's Edit settings keep the optional outputs together in one section, where
|
|
21
|
+
// Edit template gives each its own: the thumbnail, the shorts, the PDF and the YouTube
|
|
22
|
+
// description and posts.
|
|
23
|
+
export const extrasName = "Extras";
|
|
24
|
+
// Last in Create and a project's Edit settings: the channel the video is for. A template has no
|
|
25
|
+
// section for it; its schedules and Create pick the channel.
|
|
26
|
+
export const channelName = "Channel";
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { templateChannelId } from "../channels/repo.js";
|
|
2
2
|
import { snapshotEntry, snapshotPrompt } from "../library/snapshot.js";
|
|
3
|
+
import { readProviderDefaults } from "../settings/first-run.js";
|
|
3
4
|
import { socialPlatforms } from "../social/model.js";
|
|
4
5
|
import { templateDocument } from "./one-off.js";
|
|
6
|
+
import { withProviderDefaults } from "./provider-defaults.js";
|
|
5
7
|
export function templateSetup(deps, input) {
|
|
6
8
|
const prompts = [];
|
|
7
9
|
const entries = [];
|
|
@@ -58,7 +60,10 @@ export function templateSetup(deps, input) {
|
|
|
58
60
|
value: { ...document, fontUpload: null, librarySnapshot: { prompts, entries } },
|
|
59
61
|
};
|
|
60
62
|
}
|
|
61
|
-
|
|
63
|
+
// A draft made from a template, for Create or a schedule's run. A template nobody picked a writer
|
|
64
|
+
// or image service in gets this computer's defaults, as Edit template's checks expect.
|
|
65
|
+
export function freshTemplateDraft(deps, saved, source) {
|
|
66
|
+
const document = withProviderDefaults(saved, readProviderDefaults(deps.db));
|
|
62
67
|
const provided = document.form.provided;
|
|
63
68
|
const fresh = (file) => ({
|
|
64
69
|
attachmentId: deps.uuid(),
|
|
@@ -72,7 +72,7 @@ export function previewDetails(deps, view, allRecipes, selected) {
|
|
|
72
72
|
if (input.kind === "llm") {
|
|
73
73
|
const peers = allRecipes.filter((one) => one.stage === row.stage && one.input.kind === "llm");
|
|
74
74
|
const category = input.preparation !== undefined
|
|
75
|
-
? "Narration
|
|
75
|
+
? "Narration preparation"
|
|
76
76
|
: row.key.startsWith("entry:intro")
|
|
77
77
|
? "Intro text"
|
|
78
78
|
: row.key.startsWith("entry:outro")
|
|
@@ -154,9 +154,9 @@ function inputChanges(parent, view) {
|
|
|
154
154
|
}
|
|
155
155
|
add("Language", languageInfo(before.language).name, languageInfo(after.language).name);
|
|
156
156
|
add("Narration voice", before.audio?.voice, after.audio?.voice);
|
|
157
|
-
add("Narration
|
|
157
|
+
add("Narration preparation", before.narrationPrompt, after.narrationPrompt);
|
|
158
158
|
add("Narration chunking", before.chunking, after.chunking);
|
|
159
|
-
add("
|
|
159
|
+
add("Pronunciation list", before.audio?.useNarrationAliases === true ? aliasLines(before.narrationAliases) : "Off", after.audio?.useNarrationAliases === true ? aliasLines(after.narrationAliases) : "Off");
|
|
160
160
|
const described = (audio) => audio?.describeFigures !== true ? "Off" : audio.skipCode === true ? "On, code left out" : "On";
|
|
161
161
|
add("Describe tables and figures", described(before.audio), described(after.audio));
|
|
162
162
|
add("Show tables and figures on screen", before.showFigures === true ? "On" : "Off", after.showFigures === true ? "On" : "Off");
|
|
@@ -215,11 +215,11 @@ function inputChanges(parent, view) {
|
|
|
215
215
|
add(label, value, editAfter.get(label));
|
|
216
216
|
add("Intro", before.intro, after.intro);
|
|
217
217
|
add("Outro", before.outro, after.outro);
|
|
218
|
-
add("
|
|
218
|
+
add("Caption settings", before.subtitles, after.subtitles);
|
|
219
219
|
const themeBefore = documentThemeLabel(before.document);
|
|
220
220
|
const themeAfter = documentThemeLabel(after.document);
|
|
221
221
|
// A Library theme saved again under the same name still changes the document.
|
|
222
|
-
add("
|
|
222
|
+
add("PDF look", themeBefore, themeBefore === themeAfter &&
|
|
223
223
|
JSON.stringify(before.document?.custom?.values) !==
|
|
224
224
|
JSON.stringify(after.document?.custom?.values)
|
|
225
225
|
? `${themeAfter} (updated settings)`
|
|
@@ -38,7 +38,7 @@ export function preparationForGroup(context, logicalKey, source, segment, depend
|
|
|
38
38
|
return {
|
|
39
39
|
preparation,
|
|
40
40
|
requests: null,
|
|
41
|
-
refusal: "Narration
|
|
41
|
+
refusal: "Narration preparation needs narration text to work from.",
|
|
42
42
|
};
|
|
43
43
|
const logical = recipe(context, preparation.key, "audio", preparation.input.kind === "llm"
|
|
44
44
|
? { ...preparation.input, thinkingConfig: null }
|
|
@@ -286,7 +286,7 @@ export function validateRevisionEdit(config, content) {
|
|
|
286
286
|
if (config.sources.images !== "off" && content.imageOrder.length === 0)
|
|
287
287
|
fields.push({
|
|
288
288
|
field: "content.imageOrder",
|
|
289
|
-
message: "Every image is deleted, so the video has nothing to show. Press Discard changes to get them back, then press
|
|
289
|
+
message: "Every image is deleted, so the video has nothing to show. Press Discard changes to get them back, then press Make all images again in the project's Images section. To make the project without pictures, set Images source and Video source to Off in Edit settings instead.",
|
|
290
290
|
});
|
|
291
291
|
if (config.sources.images === "off" && config.sources.video !== "off")
|
|
292
292
|
fields.push({ field: "sources.video", message: "Turn Video off when Images is off." });
|
|
@@ -328,7 +328,7 @@ export function validateRevisionEdit(config, content) {
|
|
|
328
328
|
if (config.sources.audio === "off" &&
|
|
329
329
|
config.subtitles !== undefined &&
|
|
330
330
|
config.subtitles.mode !== "off")
|
|
331
|
-
fields.push({ field: "subtitles.mode", message: "
|
|
331
|
+
fields.push({ field: "subtitles.mode", message: "Captions need narration audio." });
|
|
332
332
|
fields.push(...voicesFields(config));
|
|
333
333
|
return fields;
|
|
334
334
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { editSettings } from "../../kernel/ports/settings-places.js";
|
|
1
2
|
import { narrationPreparationFields, shortsFields, usesNarrationPreparation, usesReference, usesShorts, usesYoutubeDescription, videoEditFields, youtubeDescriptionFields, } from "../admission/rules.js";
|
|
2
3
|
import { detectSlots, filledKeywords, render } from "../admission/substitute.js";
|
|
3
4
|
import { imagesPerVideoMax } from "../images/scale.js";
|
|
@@ -33,10 +34,10 @@ export function validateRecipeInputs(config, content) {
|
|
|
33
34
|
// The keyword digest and the scene keywords are written by the text model too.
|
|
34
35
|
Object.keys(keywordUsesOf(keywordBodies(config, content))).some((cost) => cost === "digest" || cost === "scenes");
|
|
35
36
|
if (llm && (!config.llm?.provider.trim() || !config.llm.model.trim()))
|
|
36
|
-
fields.push({ field: "llm", message: "
|
|
37
|
+
fields.push({ field: "llm", message: "Choose a Service and a Model under Written by." });
|
|
37
38
|
if (config.sources.audio === "generate") {
|
|
38
39
|
if (!config.audio?.provider.trim() || !config.audio.model.trim())
|
|
39
|
-
fields.push({ field: "audio", message: "
|
|
40
|
+
fields.push({ field: "audio", message: "Choose a Service and a Model under Read by." });
|
|
40
41
|
else if (!config.audio.voice.trim())
|
|
41
42
|
fields.push({ field: "audio.voice", message: "Pick a narration voice." });
|
|
42
43
|
}
|
|
@@ -48,7 +49,7 @@ export function validateRecipeInputs(config, content) {
|
|
|
48
49
|
usesShorts(config) ||
|
|
49
50
|
usesAnimation(config)) &&
|
|
50
51
|
(!config.images?.provider.trim() || !config.images.model.trim()))
|
|
51
|
-
fields.push({ field: "images", message: "
|
|
52
|
+
fields.push({ field: "images", message: "Choose a Service and a Model under Images by." });
|
|
52
53
|
// 60, or more for a project that scales its images with the narration (`images/scale.ts`).
|
|
53
54
|
const imagesMax = imagesPerVideoMax(config);
|
|
54
55
|
if (content.imageOrder.length > imagesMax)
|
|
@@ -91,7 +92,7 @@ export function validateRecipeInputs(config, content) {
|
|
|
91
92
|
if (config.keywordFacts === undefined && usesFacts([text]))
|
|
92
93
|
fields.push({
|
|
93
94
|
field: prompt.field,
|
|
94
|
-
message:
|
|
95
|
+
message: `This prompt uses a keyword Slopify fills from the channel and its videos, but this project has no keyword facts yet. Use Refresh keyword facts in ${editSettings.title}, then save again.`,
|
|
95
96
|
});
|
|
96
97
|
if (prompt.raw === null)
|
|
97
98
|
continue;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { aliasMatches, applyAliases } from "../../kernel/ports/narration-aliases.js";
|
|
2
|
+
import { createRows, editSettings } from "../../kernel/ports/settings-places.js";
|
|
2
3
|
import { splitText } from "../../kernel/ports/text.js";
|
|
3
4
|
import { narrationAliasesOf, usesNarrationPreparation } from "../admission/rules.js";
|
|
4
5
|
import { aliasSpans, withAliasSpans } from "../narration/aliases.js";
|
|
@@ -83,7 +84,7 @@ export function voiceBodyRecipes(context, voices, script, glossary) {
|
|
|
83
84
|
parts.push(future());
|
|
84
85
|
}
|
|
85
86
|
else if (parsed !== undefined && !parsed.ok) {
|
|
86
|
-
parts.push(refused(context, "audio:body:turn:1", script.dependsOn, `The script can't be narrated: ${parsed.reason} Fix it in
|
|
87
|
+
parts.push(refused(context, "audio:body:turn:1", script.dependsOn, `The script can't be narrated: ${parsed.reason} Fix it in ${editSettings.article}, then Try again.`));
|
|
87
88
|
}
|
|
88
89
|
else if (pending) {
|
|
89
90
|
parts.push(future());
|
|
@@ -251,7 +252,7 @@ function speakerGlossary(context, speaker, glossary) {
|
|
|
251
252
|
if (!own.ok)
|
|
252
253
|
return {
|
|
253
254
|
ok: false,
|
|
254
|
-
reason: `${speaker.name.trim()}'s pronunciations can't be used: ${own.reason.replace("Edit the glossary or turn off Use Pronunciation Glossary.",
|
|
255
|
+
reason: `${speaker.name.trim()}'s pronunciations can't be used: ${own.reason.replace("Edit the glossary or turn off Use Pronunciation Glossary.", `Fix them under Speakers (${createRows.narration}, or ${editSettings.narration}).`)}`,
|
|
255
256
|
};
|
|
256
257
|
const run = context.config.audio?.usePronunciationGlossary === true && glossary?.ok === true
|
|
257
258
|
? glossary.entries
|
|
@@ -255,7 +255,7 @@ config) {
|
|
|
255
255
|
model: typeof llmModel === "string" ? llmModel : "",
|
|
256
256
|
inputCharacters: (typeof style === "string" ? style.length : 0) + 3000,
|
|
257
257
|
outputCharacters: 2400,
|
|
258
|
-
detail: "One
|
|
258
|
+
detail: "One AI call per short writes its image prompts; its length is estimated.",
|
|
259
259
|
})),
|
|
260
260
|
...Array.from({ length: images }, () => ({
|
|
261
261
|
kind: "image",
|
|
@@ -312,13 +312,13 @@ export function priceRecipe(work, value, config) {
|
|
|
312
312
|
return {
|
|
313
313
|
kind: "unknown",
|
|
314
314
|
stage: work.key,
|
|
315
|
-
detail: "Narration
|
|
315
|
+
detail: "Narration preparation: one AI call per narration piece or intro or outro; how many is known once the text is written.",
|
|
316
316
|
};
|
|
317
317
|
if (input.kind === "deferred" && input.operation === "narration-description")
|
|
318
318
|
return {
|
|
319
319
|
kind: "unknown",
|
|
320
320
|
stage: work.key,
|
|
321
|
-
detail: "Narration descriptions: one
|
|
321
|
+
detail: "Narration descriptions: one AI call per table, figure, equation or code block in the article; how many is known once the article is written.",
|
|
322
322
|
};
|
|
323
323
|
if (input.kind === "llm")
|
|
324
324
|
return {
|
|
@@ -421,7 +421,7 @@ function cliRequest(work, value, config) {
|
|
|
421
421
|
detail: preparation
|
|
422
422
|
? value.input.operation === "narration-description"
|
|
423
423
|
? "Runs on your CLI plan, so it adds no charge. Narration descriptions make one call per table, figure, equation or code block; how many is known once the article is written, so no API figure is given."
|
|
424
|
-
: "Runs on your CLI plan, so it adds no charge. Narration
|
|
424
|
+
: "Runs on your CLI plan, so it adds no charge. Narration preparation makes one call per narration piece or intro or outro; how many is known when the step runs, so no API figure is given."
|
|
425
425
|
: "Runs on your CLI plan, so it adds no charge. The request is built when the step runs, so its API figure uses an estimated length.",
|
|
426
426
|
};
|
|
427
427
|
}
|
|
@@ -79,7 +79,7 @@ options = {}) {
|
|
|
79
79
|
field: "stage",
|
|
80
80
|
message: input.action.kind === "redo"
|
|
81
81
|
? "This item is no longer made by the project (it was removed, or its source changed), so it can't be made again. Reload the project page."
|
|
82
|
-
: "This section has
|
|
82
|
+
: "This section has nothing made by AI to make again. Change its source in Edit settings.",
|
|
83
83
|
},
|
|
84
84
|
],
|
|
85
85
|
};
|
|
@@ -121,7 +121,7 @@ options = {}) {
|
|
|
121
121
|
{
|
|
122
122
|
field: "stage",
|
|
123
123
|
message: late === "running"
|
|
124
|
-
? "Wait for this section to finish, or Pause the project before
|
|
124
|
+
? "Wait for this section to finish, or Pause the project before making it again."
|
|
125
125
|
: acceptedJobMessage,
|
|
126
126
|
},
|
|
127
127
|
],
|
|
@@ -154,7 +154,7 @@ options = {}) {
|
|
|
154
154
|
fields: [
|
|
155
155
|
{
|
|
156
156
|
field: "stage",
|
|
157
|
-
message: "This section
|
|
157
|
+
message: "This section is switched off. Change its source in Edit settings.",
|
|
158
158
|
},
|
|
159
159
|
],
|
|
160
160
|
});
|
|
@@ -167,7 +167,7 @@ options = {}) {
|
|
|
167
167
|
reason: "review-required",
|
|
168
168
|
fields: preview.value.preview.providedReuseRequired.map((key) => ({
|
|
169
169
|
field: key,
|
|
170
|
-
message: "
|
|
170
|
+
message: "Look over the changed content you supplied, or the captions you edited, in Edit settings or in Choose what to make again.",
|
|
171
171
|
})),
|
|
172
172
|
});
|
|
173
173
|
const blocked = preview.value.preview.work.filter((row) => row.disposition === "blocked");
|
|
@@ -187,11 +187,11 @@ options = {}) {
|
|
|
187
187
|
input.action.stage === "video"
|
|
188
188
|
? {
|
|
189
189
|
field: "video",
|
|
190
|
-
message: "
|
|
190
|
+
message: "Some of what the video is made from isn't finished. Use Continue the run to finish it before making the video again.",
|
|
191
191
|
}
|
|
192
192
|
: {
|
|
193
193
|
field: "document",
|
|
194
|
-
message: "The article or thumbnail the document is made from isn't finished. Use Continue the run to finish it, then
|
|
194
|
+
message: "The article or thumbnail the document is made from isn't finished. Use Continue the run to finish it, then press Make the PDF again in the project's PDF section.",
|
|
195
195
|
},
|
|
196
196
|
],
|
|
197
197
|
});
|
|
@@ -3,19 +3,19 @@ export function remadeWork(work) {
|
|
|
3
3
|
}
|
|
4
4
|
export function remakeBlocker(status, sample) {
|
|
5
5
|
if (status === "running")
|
|
6
|
-
return "It is running now.
|
|
6
|
+
return "It is running now. Make its outdated parts again once the run has finished.";
|
|
7
7
|
if (sample)
|
|
8
|
-
return "It is a sample project, which stays as it came with Slopify. Open it, press Make my own copy at the top of its page, then
|
|
8
|
+
return "It is a sample project, which stays as it came with Slopify. Open it, press Make my own copy at the top of its page, then change the copy.";
|
|
9
9
|
return undefined;
|
|
10
10
|
}
|
|
11
11
|
export function previewBlocker(preview, label) {
|
|
12
12
|
if (remadeWork(preview.work).length === 0)
|
|
13
|
-
return "Nothing in it is outdated, so there is nothing to
|
|
13
|
+
return "Nothing in it is outdated, so there is nothing to make again.";
|
|
14
14
|
const blocked = preview.work.find((work) => work.disposition === "blocked");
|
|
15
15
|
if (blocked !== undefined)
|
|
16
|
-
return `${label(blocked.key)} can't run: ${blocked.reason.trim() || "no reason was given."} Open the project and press Choose what to
|
|
16
|
+
return `${label(blocked.key)} can't run: ${blocked.reason.trim() || "no reason was given."} Open the project and press Choose what to make again to see what to fix.`;
|
|
17
17
|
if (preview.providedReuseRequired.length > 0)
|
|
18
|
-
return "It uses content you supplied, which you confirm on the project itself: open it and press Choose what to
|
|
18
|
+
return "It uses content you supplied, which you confirm on the project itself: open it and press Choose what to make again.";
|
|
19
19
|
return undefined;
|
|
20
20
|
}
|
|
21
21
|
export function remakeTotal(costs) {
|
|
@@ -128,7 +128,7 @@ export function redoRefusal(result) {
|
|
|
128
128
|
case "running":
|
|
129
129
|
return "Slopify couldn't make this item again automatically because work that depends on it was already running. Use Redo beside it once the run has finished.";
|
|
130
130
|
case "readiness":
|
|
131
|
-
return `Slopify couldn't make this item again automatically: ${detail ?? "a provider isn't ready"}. Fix that in Settings →
|
|
131
|
+
return `Slopify couldn't make this item again automatically: ${detail ?? "a provider isn't ready"}. Fix that in Settings → Keys & services, then use Redo beside it.`;
|
|
132
132
|
case "conflict":
|
|
133
133
|
case "control-changed":
|
|
134
134
|
return "Slopify couldn't make this item again automatically because the project changed at the same moment (an edit, Pause or Cancel). Use Redo beside it.";
|
|
@@ -36,7 +36,7 @@ export async function executeAnimateRecipe(deps, context, providers, piece) {
|
|
|
36
36
|
return "done";
|
|
37
37
|
};
|
|
38
38
|
if (still === undefined)
|
|
39
|
-
return fallback("its image wasn't ready to animate.
|
|
39
|
+
return fallback("its image wasn't ready to animate. Press Make the video again in the project's Video section after the image is made.");
|
|
40
40
|
const animate = providers.forPiece(piece.id).animate;
|
|
41
41
|
if (animate === undefined)
|
|
42
42
|
throw new Error(internalError("animating images isn't wired up in this build"));
|
|
@@ -56,7 +56,7 @@ export async function executeAnimateRecipe(deps, context, providers, piece) {
|
|
|
56
56
|
catch (error) {
|
|
57
57
|
if (context.signal.aborted)
|
|
58
58
|
throw error;
|
|
59
|
-
return fallback(`${errorText(error)} To try again,
|
|
59
|
+
return fallback(`${errorText(error)} To try again, press Make the video again in the project's Video section.`);
|
|
60
60
|
}
|
|
61
61
|
if (!made.ok)
|
|
62
62
|
return "held";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { transact } from "../../kernel/db/tx.js";
|
|
3
3
|
import { internalError } from "../../kernel/errors.js";
|
|
4
|
+
import { editSettings } from "../../kernel/ports/settings-places.js";
|
|
4
5
|
import { continuationLimit, continuationMessages } from "../article/continuation.js";
|
|
5
6
|
import { currentRevisionId, revisionById } from "../revisions/repo.js";
|
|
6
7
|
import { recipe } from "./recipe-model.js";
|
|
@@ -39,9 +40,9 @@ export async function executeArticleRequests(deps, context, providers, initial)
|
|
|
39
40
|
webSearch: input.webSearch,
|
|
40
41
|
previewLabel: part === 0 ? "Article" : `Continuation ${part}`,
|
|
41
42
|
check: (value) => value.text.trim() === ""
|
|
42
|
-
?
|
|
43
|
+
? `The AI model returned an empty article. Try again; if it keeps happening, choose a different model in ${editSettings.writer}.`
|
|
43
44
|
: part === continuationLimit && value.finishReason === "length"
|
|
44
|
-
? `The article was still unfinished after ${continuationLimit} continuations because the AI model kept stopping at its length limit. Ask for a shorter article in
|
|
45
|
+
? `The article was still unfinished after ${continuationLimit} continuations because the AI model kept stopping at its length limit. Ask for a shorter article in the article prompt in ${editSettings.article}, or choose a model with a larger output limit under Written by there, then Try again.`
|
|
45
46
|
: undefined,
|
|
46
47
|
}, (event) => {
|
|
47
48
|
if (event.type === "delta")
|
|
@@ -73,7 +74,7 @@ export async function executeArticleRequests(deps, context, providers, initial)
|
|
|
73
74
|
return { ok: false, reason: "held" };
|
|
74
75
|
piece = next;
|
|
75
76
|
}
|
|
76
|
-
throw new Error(`The article was still unfinished after ${continuationLimit} continuations because the AI model kept stopping at its length limit. Ask for a shorter article in
|
|
77
|
+
throw new Error(`The article was still unfinished after ${continuationLimit} continuations because the AI model kept stopping at its length limit. Ask for a shorter article in the article prompt in ${editSettings.article}, or choose a model with a larger output limit under Written by there, then Try again.`);
|
|
77
78
|
}
|
|
78
79
|
function continuationPiece(deps, context, initial, part, text) {
|
|
79
80
|
return transact(deps.db, () => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import { errorText, internalError } from "../../kernel/errors.js";
|
|
3
|
+
import { editSettings } from "../../kernel/ports/settings-places.js";
|
|
3
4
|
import { readDocumentAssets } from "../document/fonts.js";
|
|
4
5
|
import { renderDocument } from "../document/render.js";
|
|
5
6
|
import { resolvedDocumentTheme } from "../document/theme.js";
|
|
@@ -29,7 +30,7 @@ export async function executeDocumentRecipe(deps, context, piece) {
|
|
|
29
30
|
? view.articleMarkdown
|
|
30
31
|
: text("article_md", "article:body");
|
|
31
32
|
if (article === null)
|
|
32
|
-
throw new Error("The article isn't finished yet, so there's nothing to make the document from. Let the Article stage finish (
|
|
33
|
+
throw new Error("The article isn't finished yet, so there's nothing to make the document from. Let the Article stage finish (Continue the run, or Try again on Article), then use Try again on PDF.");
|
|
33
34
|
const thumbnail = ready(view, "thumbnail", "thumbnail:image");
|
|
34
35
|
let cover = null;
|
|
35
36
|
if (config.sources.thumbnail !== "off" && thumbnail !== undefined) {
|
|
@@ -37,7 +38,7 @@ export async function executeDocumentRecipe(deps, context, piece) {
|
|
|
37
38
|
cover = new Uint8Array(readFileSync(outputPath(deps.paths, projectId, thumbnail.output.path)));
|
|
38
39
|
}
|
|
39
40
|
catch (error) {
|
|
40
|
-
throw new Error(`The document's cover is the project's thumbnail, and its file can't be read (${errorText(error)}).
|
|
41
|
+
throw new Error(`The document's cover is the project's thumbnail, and its file can't be read (${errorText(error)}). Make the thumbnail again in the project's Images section, or upload it again in ${editSettings.extras}, then use Try again on PDF.`, { cause: error });
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
const rendered = renderDocument({
|
|
@@ -70,10 +71,10 @@ function documentView(deps, context, piece) {
|
|
|
70
71
|
.prepare("SELECT recipe_context FROM revision_work WHERE id=?")
|
|
71
72
|
.get(context.work.workId);
|
|
72
73
|
if (view === undefined || row === undefined)
|
|
73
|
-
throw new Error(internalError("the project version the document belongs to is missing", "Use Try again on
|
|
74
|
+
throw new Error(internalError("the project version the document belongs to is missing", "Use Try again on PDF"));
|
|
74
75
|
const recipe = executionPlan(deps, view, savedCatalogue(row.recipe_context)).recipes.find((one) => one.key === piece.key && one.fingerprint === piece.fingerprint);
|
|
75
76
|
if (recipe === undefined || recipe.unresolved)
|
|
76
|
-
throw new Error("The project changed after this document was queued, so it no longer matches the saved article. Use Choose what to
|
|
77
|
+
throw new Error("The project changed after this document was queued, so it no longer matches the saved article. Use Choose what to make again (in the project's More menu) (or Try again on PDF) to make it from the current version.");
|
|
77
78
|
return view;
|
|
78
79
|
}
|
|
79
80
|
function ready(view, role, workKey) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { errorText } from "../../kernel/errors.js";
|
|
2
|
+
import { editSettings } from "../../kernel/ports/settings-places.js";
|
|
2
3
|
import { assetPathOrUndefined } from "../revisions/mutation-assets.js";
|
|
3
4
|
import { outputPath } from "../storage/layout.js";
|
|
4
5
|
import { usesAmbientBed } from "../video/ambient-bed.js";
|
|
@@ -18,7 +19,7 @@ export async function exportBed(deps, context, view) {
|
|
|
18
19
|
};
|
|
19
20
|
if (bed.source !== "upload")
|
|
20
21
|
return { source: { kind: "noise", preset: bed.source }, ...settings };
|
|
21
|
-
const fix =
|
|
22
|
+
const fix = `Choose another file under Ambient sound in ${editSettings.sound}, or pick Rain, Fireplace or Wind there instead.`;
|
|
22
23
|
const assetId = view.revision.content.ambientBed;
|
|
23
24
|
const saved = assetId === undefined ? undefined : assetPathOrUndefined(deps, context.work.projectId, assetId);
|
|
24
25
|
if (saved === undefined)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { extname } from "node:path";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
import { editSettings } from "../../kernel/ports/settings-places.js";
|
|
3
4
|
import { usesFigureCards, usesYoutubeDescription } from "../admission/rules.js";
|
|
4
5
|
import { captionFont, captionFontDeps } from "../fonts/coverage.js";
|
|
5
6
|
import { resolveFont } from "../fonts/index.js";
|
|
@@ -135,7 +136,7 @@ async function clipSeconds(deps, context, path, place) {
|
|
|
135
136
|
ms = 0;
|
|
136
137
|
}
|
|
137
138
|
if (!(ms > 0))
|
|
138
|
-
throw new Error(`Image ${String(place)} is a video clip Slopify can't read, so the video can't show it. Replace it with another clip or an image in
|
|
139
|
+
throw new Error(`Image ${String(place)} is a video clip Slopify can't read, so the video can't show it. Replace it with another clip or an image in ${editSettings.images}, then Try again.`);
|
|
139
140
|
return ms / 1000;
|
|
140
141
|
}
|
|
141
142
|
// Each card in the video's frame, shown where its description is spoken: the description's
|