@gentbajko/slopify 4.0.0 → 4.2.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 +5 -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/pronunciation-check.js +133 -0
- package/dist/edge/http/pronunciations.js +26 -0
- 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 +31 -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/4.2.0.md +28 -0
- package/dist/patch-notes/index.json +12 -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/schema.js +2 -0
- package/dist/slices/admission/start.js +7 -0
- package/dist/slices/admission/state-words.js +34 -5
- package/dist/slices/assistant/cost.js +1 -1
- package/dist/slices/assistant/gate.js +1 -0
- 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-check.js +226 -0
- package/dist/slices/narration/pronunciation.js +7 -2
- package/dist/slices/narration/pronunciations-library.js +94 -0
- 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-text.js +16 -4
- 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 +95 -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 +101 -19
- 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 +183 -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-CQASqwjT.js +460 -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
|
@@ -11,7 +11,7 @@ import { findRevisionDownload } from "../revisions/downloads.js";
|
|
|
11
11
|
import { currentRevisionId } from "../revisions/repo.js";
|
|
12
12
|
import { getRevisionView } from "../revisions/view.js";
|
|
13
13
|
import { listVoices } from "../settings/repo.js";
|
|
14
|
-
import {
|
|
14
|
+
import { runnableVersion } from "./gate.js";
|
|
15
15
|
import { gatesOf, sampleOf } from "./repo.js";
|
|
16
16
|
// A template pack: a template set up in the studio, as one zip someone else imports and looks
|
|
17
17
|
// at before using it. It carries the version marked ready (its prompts' and intros' text, the
|
|
@@ -146,22 +146,24 @@ export async function exportPack(deps, templateId, samples = (id) => sampleFiles
|
|
|
146
146
|
return {
|
|
147
147
|
ok: false,
|
|
148
148
|
reason: "not-found",
|
|
149
|
-
message: "This template no longer exists; it may have been deleted. Go to
|
|
149
|
+
message: "This template no longer exists; it may have been deleted. Go to Templates to see your templates.",
|
|
150
150
|
};
|
|
151
|
-
|
|
151
|
+
// What its schedules run: the newest version, or once it was first approved for schedules,
|
|
152
|
+
// the newest approved one.
|
|
153
|
+
const runs = runnableVersion(gatesOf(deps.db, templateId), head.version);
|
|
152
154
|
const template = runs === undefined ? undefined : templateById(deps.db, templateId, runs);
|
|
153
155
|
if (template === undefined)
|
|
154
156
|
return {
|
|
155
157
|
ok: false,
|
|
156
158
|
reason: "not-ready",
|
|
157
|
-
message: "No version of this template is
|
|
159
|
+
message: "No version of this template is approved for schedules, so there is nothing to put in the file: it carries what its schedules run. Approve a version in Edit template, then export it again.",
|
|
158
160
|
};
|
|
159
161
|
const setup = templateSetup(deps, template.document);
|
|
160
162
|
if (!setup.ok)
|
|
161
163
|
return {
|
|
162
164
|
ok: false,
|
|
163
165
|
reason: "invalid-input",
|
|
164
|
-
message: `Version ${String(template.version)} names a prompt or intro/outro that was deleted, so its text can't go into the
|
|
166
|
+
message: `Version ${String(template.version)} names a prompt or intro/outro that was deleted, so its text can't go into the file. Choose another in Edit template, Save, then export it again.`,
|
|
165
167
|
};
|
|
166
168
|
const document = setup.value;
|
|
167
169
|
const { audio } = document.form;
|
|
@@ -187,7 +189,7 @@ export async function exportPack(deps, templateId, samples = (id) => sampleFiles
|
|
|
187
189
|
return {
|
|
188
190
|
ok: false,
|
|
189
191
|
reason: "invalid-input",
|
|
190
|
-
message: "Something in this template looks like an API key or a login token (a keyword's value or a prompt's text), so no
|
|
192
|
+
message: "Something in this template looks like an API key or a login token (a keyword's value or a prompt's text), so no file was made: it is meant to be shared. Remove it in Edit template, Save, then export it again.",
|
|
191
193
|
};
|
|
192
194
|
const entries = { "manifest.json": [strToU8(json), { level: 6 }] };
|
|
193
195
|
for (const file of named) {
|
|
@@ -197,7 +199,7 @@ export async function exportPack(deps, templateId, samples = (id) => sampleFiles
|
|
|
197
199
|
return {
|
|
198
200
|
ok: true,
|
|
199
201
|
value: {
|
|
200
|
-
filename: `${slug(template.name)}.slopify-
|
|
202
|
+
filename: `${slug(template.name)}.slopify-template.zip`,
|
|
201
203
|
bytes: zipSync(entries),
|
|
202
204
|
version: template.version,
|
|
203
205
|
},
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
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 { derive } from "../../kernel/runner/graph.js";
|
|
5
6
|
import { pendingAdmitted } from "../admission/admitted-work.js";
|
|
6
7
|
import { projectExists, projectPaused, stagesOf } from "../admission/repo.js";
|
|
@@ -31,8 +32,11 @@ export function holdReason(deps, job, cost) {
|
|
|
31
32
|
if (cost.unknown > 0 && !deps.acks.accepted(job.templateId, job.templateVersion))
|
|
32
33
|
return `Waiting: ${String(cost.unknown)} ${cost.unknown === 1 ? "step of this sample has" : "steps of this sample have"} no known price. Press Make sample to accept that and make it.`;
|
|
33
34
|
const room = budgetRoom(deps.db, deps.now, deps.timeZone);
|
|
35
|
+
// Tomorrow brings a new budget, never the plan setting.
|
|
34
36
|
if (!fitsBudget(room, cost.high, cost.usesPlan))
|
|
35
|
-
return
|
|
37
|
+
return cost.usesPlan && !room.plans
|
|
38
|
+
? `Waiting: ${budgetWords(room, cost, "this sample")}.`
|
|
39
|
+
: `Waiting: ${budgetWords(room, cost, "this sample")}, or press Make sample tomorrow.`;
|
|
36
40
|
return undefined;
|
|
37
41
|
}
|
|
38
42
|
// Whether the sample project still has work going: a stage running or waiting, or work admitted
|
|
@@ -88,13 +92,16 @@ function outcome(db, projectId) {
|
|
|
88
92
|
return { failed: "The sample stopped before it finished. Press Make sample to make it again." };
|
|
89
93
|
return { failed: null };
|
|
90
94
|
}
|
|
95
|
+
// A step's sentence sends a project to its settings for another model; a template's section
|
|
96
|
+
// changes its model with Change on its "Made with …" line.
|
|
97
|
+
const modelPlaces = new RegExp(`choose another (model|image model) in (?:${[editSettings.writer, editSettings.narration, editSettings.images].join("|")})`, "g");
|
|
91
98
|
// A step's sentence names a project's Try again (on its stage); a studio's own button for it
|
|
92
99
|
// is another: Make sample for a sample, Compare again for a model comparison. `then` is what
|
|
93
100
|
// follows the button's name in the sentence.
|
|
94
101
|
export function studioWords(reason, button = "Make sample", then = " to try again") {
|
|
95
102
|
return reason
|
|
96
|
-
.replace(
|
|
97
|
-
.replace(/(\b[UuPp](?:se|ress) )?Try again(?: on [A-Z][
|
|
103
|
+
.replace(modelPlaces, "choose another $1 with Change on that section's “Made with …” line")
|
|
104
|
+
.replace(/(\b[UuPp](?:se|ress) )?Try again(?: on [A-Z][A-Za-z]+)?/g, (_, verb, at) => {
|
|
98
105
|
const opens = verb === undefined ? /(^|[.;:!?]\s+)$/.test(reason.slice(0, at)) : /^[UP]/.test(verb);
|
|
99
106
|
return `${opens ? "Press" : "press"} ${button}${then}`;
|
|
100
107
|
});
|
|
@@ -102,7 +109,7 @@ export function studioWords(reason, button = "Make sample", then = " to try agai
|
|
|
102
109
|
const refusedSentence = {
|
|
103
110
|
conflict: "The sample project changed while the sample was being set up. Press Make sample again.",
|
|
104
111
|
"stale-preview": "What the sample needed changed while it was being set up. Press Make sample again.",
|
|
105
|
-
readiness: "A provider this template uses isn't set up, so the sample can't start. Set it up in Settings →
|
|
112
|
+
readiness: "A provider this template uses isn't set up, so the sample can't start. Set it up in Settings → Keys & services, then press Make sample.",
|
|
106
113
|
"cost-ack-required": "Some steps of this sample have no known price. Press Make sample to accept that and make it.",
|
|
107
114
|
};
|
|
108
115
|
export function refused(reason, fields) {
|
|
@@ -127,7 +134,7 @@ export async function makePaidSample(deps, job, signal) {
|
|
|
127
134
|
if (!resolved.ok) {
|
|
128
135
|
mark({
|
|
129
136
|
state: "failed",
|
|
130
|
-
heldReason: `${resolved.problem} Change it
|
|
137
|
+
heldReason: `${resolved.problem} Change it, press Save, then Make sample.`,
|
|
131
138
|
});
|
|
132
139
|
return;
|
|
133
140
|
}
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
import { projectExists } from "../admission/repo.js";
|
|
2
2
|
import { estimateRun } from "../estimate/index.js";
|
|
3
3
|
import { resolvePlayReview } from "../play-drafts/review.js";
|
|
4
|
+
import { withProviderDefaults } from "../project-templates/provider-defaults.js";
|
|
4
5
|
import { templateById } from "../project-templates/repo.js";
|
|
6
|
+
import { readProviderDefaults } from "../settings/first-run.js";
|
|
5
7
|
import { budgetRoom, fitsBudget } from "./budget.js";
|
|
8
|
+
import { sectionLabel } from "./model.js";
|
|
6
9
|
import { sampleOf } from "./repo.js";
|
|
7
10
|
import { sampleDocument } from "./scope.js";
|
|
8
11
|
import { affectedSections } from "./sections.js";
|
|
9
12
|
import { defaultSampleTopic } from "./service.js";
|
|
10
|
-
// The sample's single run as Play's review resolves it, on a draft that is never saved.
|
|
11
|
-
|
|
13
|
+
// The sample's single run as Play's review resolves it, on a draft that is never saved. Like a
|
|
14
|
+
// video made from the template, it uses this computer's writer and image service where the
|
|
15
|
+
// template chose none.
|
|
16
|
+
export async function resolveSampleRun(review, scoped, fullScript) {
|
|
17
|
+
const document = withProviderDefaults(scoped, readProviderDefaults(review.db));
|
|
12
18
|
const at = review.clock.now().toISOString();
|
|
13
19
|
const view = {
|
|
14
20
|
draft: { id: review.uuid(), version: 1, createdAt: at, updatedAt: at, document },
|
|
@@ -22,14 +28,14 @@ export async function resolveSampleRun(review, document, fullScript) {
|
|
|
22
28
|
return {
|
|
23
29
|
ok: false,
|
|
24
30
|
problem: resolved.fields.length === 0
|
|
25
|
-
? "
|
|
31
|
+
? "Create's review refused this setup, so no sample can be made. Press Make a video to see why on Create."
|
|
26
32
|
: `No sample can be made of this setup: ${[...new Set(resolved.fields.map(fieldSentence))].join(" ")}`,
|
|
27
33
|
};
|
|
28
34
|
const run = resolved.value.runs[0];
|
|
29
35
|
if (run === undefined)
|
|
30
36
|
return {
|
|
31
37
|
ok: false,
|
|
32
|
-
problem: "
|
|
38
|
+
problem: "Create's review found no video to make, so no sample can be made.",
|
|
33
39
|
};
|
|
34
40
|
return {
|
|
35
41
|
ok: true,
|
|
@@ -40,16 +46,16 @@ export async function resolveSampleRun(review, document, fullScript) {
|
|
|
40
46
|
// A refused field in the studio's words: an empty keyword is named, with where it is filled.
|
|
41
47
|
export function fieldSentence(field) {
|
|
42
48
|
if (field.field.startsWith("values."))
|
|
43
|
-
return `The keyword {{${field.field.slice("values.".length)}}} is empty. Fill it in
|
|
49
|
+
return `The keyword {{${field.field.slice("values.".length)}}} is empty. Fill it in ${sectionLabel.subject}.`;
|
|
44
50
|
return field.message;
|
|
45
51
|
}
|
|
46
52
|
const sectionOfRow = {
|
|
47
53
|
Research: "subject",
|
|
48
54
|
Article: "script",
|
|
49
55
|
"Intro / outro text": "script",
|
|
50
|
-
"
|
|
51
|
-
"Narration
|
|
52
|
-
"Delivery
|
|
56
|
+
"Describing tables and figures": "voice",
|
|
57
|
+
"Narration preparation": "voice",
|
|
58
|
+
"Delivery cues": "voice",
|
|
53
59
|
Narration: "voice",
|
|
54
60
|
"Speaker split": "voice",
|
|
55
61
|
"Conversation script": "voice",
|
|
@@ -58,13 +64,14 @@ const sectionOfRow = {
|
|
|
58
64
|
"Establishing image": "pictures",
|
|
59
65
|
Thumbnail: "thumbnail",
|
|
60
66
|
"Thumbnail prompt": "thumbnail",
|
|
61
|
-
|
|
67
|
+
Video: "video",
|
|
68
|
+
"Audio export": "video",
|
|
62
69
|
"Animated images": "video",
|
|
63
70
|
"YouTube description": "upload",
|
|
64
71
|
Posts: "upload",
|
|
65
72
|
Shorts: "shorts",
|
|
66
73
|
Reviews: "reviews",
|
|
67
|
-
|
|
74
|
+
PDF: "document",
|
|
68
75
|
};
|
|
69
76
|
export function totals(rows) {
|
|
70
77
|
const priced = rows.filter((row) => row.high !== null && row.high > 0);
|
|
@@ -87,7 +94,7 @@ export async function quoteSample(deps, templateId, ask) {
|
|
|
87
94
|
return {
|
|
88
95
|
ok: false,
|
|
89
96
|
reason: "not-found",
|
|
90
|
-
message: "This template no longer exists; it may have been deleted. Go to
|
|
97
|
+
message: "This template no longer exists; it may have been deleted. Go to Templates to see your templates.",
|
|
91
98
|
};
|
|
92
99
|
const document = ask.document ?? template.document;
|
|
93
100
|
const sample = sampleOf(deps.db, templateId);
|
|
@@ -13,11 +13,11 @@ export const markReadySchema = z
|
|
|
13
13
|
.readonly();
|
|
14
14
|
const checkLabel = {
|
|
15
15
|
keywords: "Keywords",
|
|
16
|
-
providers: "
|
|
16
|
+
providers: "Services",
|
|
17
17
|
voice: "Voice",
|
|
18
|
-
"release-slots": "Release
|
|
18
|
+
"release-slots": "Release times",
|
|
19
19
|
"monthly-cost": "Monthly cost",
|
|
20
|
-
answerers: "
|
|
20
|
+
answerers: "Pauses answered",
|
|
21
21
|
};
|
|
22
22
|
// The section states Mark ready accepts: nothing about them is left to look at.
|
|
23
23
|
const settled = new Set(["current", "off", "provided"]);
|
|
@@ -43,12 +43,12 @@ function sentenceOf(problem) {
|
|
|
43
43
|
const fix = problem.fix === undefined ? "" : ` ${problem.fix.label}.`;
|
|
44
44
|
return `${problem.label}: ${problem.sentence}${fix}`;
|
|
45
45
|
}
|
|
46
|
-
const missingTemplate = "This template no longer exists; it may have been deleted. Go to
|
|
46
|
+
const missingTemplate = "This template no longer exists; it may have been deleted. Go to Templates to see your templates.";
|
|
47
47
|
function notNewest(version, head) {
|
|
48
48
|
return {
|
|
49
49
|
ok: false,
|
|
50
50
|
reason: "conflict",
|
|
51
|
-
message: `Version ${String(version)} is no longer the newest: the template is at version ${String(head)}. Look over version ${String(head)}'s samples, then
|
|
51
|
+
message: `Version ${String(version)} is no longer the newest: the template is at version ${String(head)}. Look over version ${String(head)}'s samples, then approve it for schedules.`,
|
|
52
52
|
problems: [],
|
|
53
53
|
};
|
|
54
54
|
}
|
|
@@ -58,7 +58,7 @@ export async function markReady(deps, templateId, raw) {
|
|
|
58
58
|
return {
|
|
59
59
|
ok: false,
|
|
60
60
|
reason: "invalid-input",
|
|
61
|
-
message: "
|
|
61
|
+
message: "Edit template sent a request Slopify couldn't read. Reload the page and try again.",
|
|
62
62
|
problems: [],
|
|
63
63
|
};
|
|
64
64
|
const { version } = parsed.data;
|
|
@@ -83,7 +83,7 @@ export async function markReady(deps, templateId, raw) {
|
|
|
83
83
|
return {
|
|
84
84
|
ok: false,
|
|
85
85
|
reason: "not-ready",
|
|
86
|
-
message: `Version ${String(version)} can't be
|
|
86
|
+
message: `Version ${String(version)} can't be approved for schedules yet. ${problems.map(sentenceOf).join(" ")}`,
|
|
87
87
|
problems,
|
|
88
88
|
};
|
|
89
89
|
return transact(deps.db, () => {
|
|
@@ -56,7 +56,7 @@ export function createSampleRunner(deps) {
|
|
|
56
56
|
recoverJobs(deps.db);
|
|
57
57
|
loop = run().catch((error) => {
|
|
58
58
|
deps.log.write("error", "template-studio.runner", {
|
|
59
|
-
detail: `The template
|
|
59
|
+
detail: `The loop that makes Edit template's samples stopped: ${errorText(error)}. Restart Slopify to make samples again.`,
|
|
60
60
|
});
|
|
61
61
|
});
|
|
62
62
|
},
|
|
@@ -64,7 +64,7 @@ export async function saveStudio(deps, id, raw) {
|
|
|
64
64
|
return {
|
|
65
65
|
ok: false,
|
|
66
66
|
reason: "invalid-input",
|
|
67
|
-
message: "
|
|
67
|
+
message: "Edit template sent a Save Slopify couldn't read. Reload the page and press Save again.",
|
|
68
68
|
};
|
|
69
69
|
const input = parsed.data;
|
|
70
70
|
const head = templateById(deps.db, id);
|
|
@@ -72,7 +72,7 @@ export async function saveStudio(deps, id, raw) {
|
|
|
72
72
|
return {
|
|
73
73
|
ok: false,
|
|
74
74
|
reason: "not-found",
|
|
75
|
-
message: "This template no longer exists; it may have been deleted. Go to
|
|
75
|
+
message: "This template no longer exists; it may have been deleted. Go to Templates to see your templates.",
|
|
76
76
|
};
|
|
77
77
|
const update = {
|
|
78
78
|
id,
|
|
@@ -89,7 +89,7 @@ export async function saveStudio(deps, id, raw) {
|
|
|
89
89
|
return {
|
|
90
90
|
ok: false,
|
|
91
91
|
reason: "conflict",
|
|
92
|
-
message: "This Save was already sent with different settings. Reload the
|
|
92
|
+
message: "This Save was already sent with different settings. Reload the page to see what was saved.",
|
|
93
93
|
};
|
|
94
94
|
return {
|
|
95
95
|
ok: true,
|
|
@@ -105,7 +105,7 @@ export async function saveStudio(deps, id, raw) {
|
|
|
105
105
|
return {
|
|
106
106
|
ok: false,
|
|
107
107
|
reason: "conflict",
|
|
108
|
-
message: `This template changed since you opened it: it is now version ${String(head.version)}. Reload the
|
|
108
|
+
message: `This template changed since you opened it: it is now version ${String(head.version)}. Reload the page to see the change, then make yours again.`,
|
|
109
109
|
};
|
|
110
110
|
let quote = null;
|
|
111
111
|
if (input.sample === "make") {
|
|
@@ -117,28 +117,28 @@ export async function saveStudio(deps, id, raw) {
|
|
|
117
117
|
return {
|
|
118
118
|
ok: false,
|
|
119
119
|
reason: "invalid-input",
|
|
120
|
-
message: `${quote.problem}
|
|
120
|
+
message: `${quote.problem} Save keeps the change without a sample.`,
|
|
121
121
|
quote,
|
|
122
122
|
};
|
|
123
123
|
if (exceedsAcknowledged(quote.high, input.acknowledgedHigh))
|
|
124
124
|
return {
|
|
125
125
|
ok: false,
|
|
126
126
|
reason: "cost-changed",
|
|
127
|
-
message: `The sample now costs about ${money(quote.high)}, more than the ${money(input.acknowledgedHigh)} you saw. Press
|
|
127
|
+
message: `The sample now costs about ${money(quote.high)}, more than the ${money(input.acknowledgedHigh)} you saw. Press Make sample again to accept the new price.`,
|
|
128
128
|
quote,
|
|
129
129
|
};
|
|
130
130
|
if (quote.unknown > 0 && input.acknowledgedUnknown !== true)
|
|
131
131
|
return {
|
|
132
132
|
ok: false,
|
|
133
133
|
reason: "cost-changed",
|
|
134
|
-
message: `${String(quote.unknown)} ${quote.unknown === 1 ? "step of this sample has" : "steps of this sample have"} no known price. Tick that you accept unknown costs, then press
|
|
134
|
+
message: `${String(quote.unknown)} ${quote.unknown === 1 ? "step of this sample has" : "steps of this sample have"} no known price. Tick that you accept unknown costs, then press Make sample again.`,
|
|
135
135
|
quote,
|
|
136
136
|
};
|
|
137
137
|
if (!quote.fits)
|
|
138
138
|
return {
|
|
139
139
|
ok: false,
|
|
140
140
|
reason: "over-budget",
|
|
141
|
-
message: `${budgetWords(quote.budget, quote, "This sample")}
|
|
141
|
+
message: `${budgetWords(quote.budget, quote, "This sample")}.`,
|
|
142
142
|
quote,
|
|
143
143
|
};
|
|
144
144
|
}
|
|
@@ -154,7 +154,7 @@ export async function saveStudio(deps, id, raw) {
|
|
|
154
154
|
message: saved.reason === "missing-prompt"
|
|
155
155
|
? "A prompt or intro/outro entry this template uses was deleted. Choose another in the template, then press Save again."
|
|
156
156
|
: saved.reason === "conflict"
|
|
157
|
-
? "This template changed while you were editing. Reload the
|
|
157
|
+
? "This template changed while you were editing. Reload the page to see the latest, then make your change again."
|
|
158
158
|
: "Some template settings are not valid, for example an image you supplied yourself. Check the template's settings and press Save again.",
|
|
159
159
|
};
|
|
160
160
|
const template = saved.value;
|
|
@@ -201,20 +201,20 @@ export function requestSample(deps, id, raw) {
|
|
|
201
201
|
return {
|
|
202
202
|
ok: false,
|
|
203
203
|
reason: "invalid-input",
|
|
204
|
-
message: "
|
|
204
|
+
message: "Edit template sent a request Slopify couldn't read. Reload the page and press Make sample again.",
|
|
205
205
|
};
|
|
206
206
|
const head = templateById(deps.db, id);
|
|
207
207
|
if (head === undefined)
|
|
208
208
|
return {
|
|
209
209
|
ok: false,
|
|
210
210
|
reason: "not-found",
|
|
211
|
-
message: "This template no longer exists; it may have been deleted. Go to
|
|
211
|
+
message: "This template no longer exists; it may have been deleted. Go to Templates to see your templates.",
|
|
212
212
|
};
|
|
213
213
|
if (head.version !== parsed.data.version)
|
|
214
214
|
return {
|
|
215
215
|
ok: false,
|
|
216
216
|
reason: "conflict",
|
|
217
|
-
message: `This template is now version ${String(head.version)}, not the version ${String(parsed.data.version)} you saw. Reload the
|
|
217
|
+
message: `This template is now version ${String(head.version)}, not the version ${String(parsed.data.version)} you saw. Reload the page, then press Make sample.`,
|
|
218
218
|
};
|
|
219
219
|
const at = deps.clock.now().toISOString();
|
|
220
220
|
if (parsed.data.acknowledgedUnknown === true)
|
|
@@ -87,7 +87,7 @@ function sampleTexts(deps, templateId) {
|
|
|
87
87
|
glossary: textOf(deps, sample.projectId, "glossary"),
|
|
88
88
|
};
|
|
89
89
|
}
|
|
90
|
-
const missingTemplate = "This template no longer exists; it may have been deleted. Go to
|
|
90
|
+
const missingTemplate = "This template no longer exists; it may have been deleted. Go to Templates to see your templates.";
|
|
91
91
|
export function pronunciationsOf(deps, templateId) {
|
|
92
92
|
const head = templateById(deps.db, templateId);
|
|
93
93
|
if (head === undefined)
|
|
@@ -125,7 +125,7 @@ export const sayItAsSchema = z
|
|
|
125
125
|
})
|
|
126
126
|
.strict()
|
|
127
127
|
.readonly();
|
|
128
|
-
const aliasesOff = "This template's voice doesn't use
|
|
128
|
+
const aliasesOff = "This template's voice doesn't use your pronunciations (Settings → Voices → Pronunciation), so “Say it as” would change nothing. Turn on Use your pronunciation list under All Narration settings → More narration settings, press Save, then try again.";
|
|
129
129
|
export function quoteSayItAs(deps, templateId, ask) {
|
|
130
130
|
const head = templateById(deps.db, templateId);
|
|
131
131
|
if (head === undefined)
|
|
@@ -222,7 +222,7 @@ export async function sayItAs(deps, templateId, raw) {
|
|
|
222
222
|
return {
|
|
223
223
|
ok: false,
|
|
224
224
|
reason: "invalid-input",
|
|
225
|
-
message: `The alias wasn't saved: ${saved.fields.map((field) => field.message).join(" ")} Fix it in
|
|
225
|
+
message: `The alias wasn't saved: ${saved.fields.map((field) => field.message).join(" ")} Fix it in Settings → Voices → Pronunciation, then try again.`,
|
|
226
226
|
};
|
|
227
227
|
if (quote.lines === 0)
|
|
228
228
|
return { ok: true, value: { alias, queued: false, quote } };
|
|
@@ -30,5 +30,5 @@ export function notReadySentence(db, templateId) {
|
|
|
30
30
|
if (gate === undefined || gate.runs !== null)
|
|
31
31
|
return undefined;
|
|
32
32
|
const name = templateById(db, templateId)?.name ?? "This schedule's template";
|
|
33
|
-
return `Not started: ${name} has no version
|
|
33
|
+
return `Not started: ${name} has no version approved for schedules. Open it in Templates → Edit template and choose More → Approve for schedules.`;
|
|
34
34
|
}
|
|
@@ -21,10 +21,12 @@ export async function priceDocument(deps, document) {
|
|
|
21
21
|
const review = await resolvePlayReview(deps, view, { unsaved: true });
|
|
22
22
|
if (!review.ok)
|
|
23
23
|
return review.fields.length === 0
|
|
24
|
-
? "
|
|
24
|
+
? "Create's review refused this setup. Press Make a video on the template to see why on Create."
|
|
25
25
|
: [...new Set(review.fields.map((field) => field.message))].join(" ");
|
|
26
|
+
const rows = review.value.estimates.flatMap((estimate) => estimate.rows);
|
|
26
27
|
return {
|
|
27
28
|
high: review.value.estimates.reduce((sum, estimate) => sum + estimate.high, 0),
|
|
28
29
|
unknown: review.value.estimates.reduce((sum, estimate) => sum + estimate.unknown, 0),
|
|
30
|
+
unpriced: [...new Set(rows.filter((row) => row.low === null).map((row) => row.stage))],
|
|
29
31
|
};
|
|
30
32
|
}
|
|
@@ -61,6 +61,7 @@ export function monthlyCost(schedules, prices, now) {
|
|
|
61
61
|
let runs = 0;
|
|
62
62
|
let high = 0;
|
|
63
63
|
let unknown = 0;
|
|
64
|
+
const unpriced = new Set();
|
|
64
65
|
let problem = null;
|
|
65
66
|
for (const schedule of active) {
|
|
66
67
|
const perMonth = runsPerMonth(schedule, now);
|
|
@@ -71,16 +72,19 @@ export function monthlyCost(schedules, prices, now) {
|
|
|
71
72
|
problem ??=
|
|
72
73
|
price === undefined
|
|
73
74
|
? `The cost of the runs of ${schedule.name} isn't worked out yet: it is, with the free samples.`
|
|
74
|
-
: `The runs of ${schedule.name} couldn't be priced: ${price} Fix it
|
|
75
|
+
: `The runs of ${schedule.name} couldn't be priced: ${price} Fix it here, then press Save.`;
|
|
75
76
|
continue;
|
|
76
77
|
}
|
|
77
78
|
high += price.high * perMonth;
|
|
78
79
|
unknown += price.unknown;
|
|
80
|
+
for (const stage of price.unpriced ?? [])
|
|
81
|
+
unpriced.add(stage);
|
|
79
82
|
}
|
|
80
83
|
return {
|
|
81
84
|
runs: Math.round(runs * 10) / 10,
|
|
82
85
|
high: Math.round(high * 100) / 100,
|
|
83
86
|
unknown,
|
|
87
|
+
unpriced: [...unpriced],
|
|
84
88
|
problem,
|
|
85
89
|
paused,
|
|
86
90
|
};
|
|
@@ -68,6 +68,7 @@ export const scheduleSampleSchema = z
|
|
|
68
68
|
runs: z.number(),
|
|
69
69
|
high: z.number(),
|
|
70
70
|
unknown: z.number(),
|
|
71
|
+
unpriced: z.array(z.string()).readonly(),
|
|
71
72
|
problem: z.string().nullable(),
|
|
72
73
|
paused: z
|
|
73
74
|
.object({ schedules: z.number(), runs: z.number(), high: z.number() })
|
|
@@ -216,3 +217,27 @@ export const anatomyViewSchema = z
|
|
|
216
217
|
})
|
|
217
218
|
.strict()
|
|
218
219
|
.readonly();
|
|
220
|
+
// GET /api/template-studio/cards: what each template makes, for the Templates page (`cards.ts`).
|
|
221
|
+
export const templateCardSchema = z
|
|
222
|
+
.object({
|
|
223
|
+
id: z.string(),
|
|
224
|
+
// A picture of what it makes, served by the app, or null when there is none yet.
|
|
225
|
+
still: z.string().nullable(),
|
|
226
|
+
format: z.enum(["16:9", "9:16", "1:1"]),
|
|
227
|
+
// Whether it makes a video at all (a narration-only setup does not).
|
|
228
|
+
video: z.boolean(),
|
|
229
|
+
words: z.number().int().nonnegative().nullable(),
|
|
230
|
+
voice: z
|
|
231
|
+
.object({ provider: z.string(), voiceId: z.string(), name: z.string() })
|
|
232
|
+
.strict()
|
|
233
|
+
.nullable(),
|
|
234
|
+
captions: z.enum(["off", "burn-in", "files"]),
|
|
235
|
+
shorts: z.number().int().nonnegative(),
|
|
236
|
+
pdf: z.boolean(),
|
|
237
|
+
// The keywords each video asks for: the topic keywords of its title ("Topic").
|
|
238
|
+
asks: z.array(z.string()),
|
|
239
|
+
// The schedules that run it now (paused ones too).
|
|
240
|
+
schedules: z.number().int().nonnegative(),
|
|
241
|
+
})
|
|
242
|
+
.strict();
|
|
243
|
+
export const templateCardsSchema = z.object({ cards: z.array(templateCardSchema) }).strict();
|
|
@@ -5,6 +5,7 @@ import { snapshotEntry, snapshotPrompt } from "../library/snapshot.js";
|
|
|
5
5
|
import { readNotificationUrl } from "../notifications/settings.js";
|
|
6
6
|
import { templateById } from "../project-templates/repo.js";
|
|
7
7
|
import { scheduleRows } from "../schedules/repo.js";
|
|
8
|
+
import { readProviderDefaults } from "../settings/first-run.js";
|
|
8
9
|
import { listVoices, readJsonSetting } from "../settings/repo.js";
|
|
9
10
|
import { freeChecks } from "./checks.js";
|
|
10
11
|
import { checkedVersion, gateOf, isGated, runnableVersion } from "./gate.js";
|
|
@@ -82,7 +83,7 @@ export function createReadinessCache(load, now = Date.now, ttlMs = 30_000) {
|
|
|
82
83
|
return value;
|
|
83
84
|
};
|
|
84
85
|
}
|
|
85
|
-
const missingTemplate = "This template no longer exists; it may have been deleted. Go to
|
|
86
|
+
const missingTemplate = "This template no longer exists; it may have been deleted. Go to Templates to see your templates.";
|
|
86
87
|
// The studio page's content, answered without waiting for the providers' readiness: the
|
|
87
88
|
// checks that need it are read on their own (`getStudioChecks`).
|
|
88
89
|
export async function getStudio(deps, id) {
|
|
@@ -161,6 +162,7 @@ export async function getStudioChecks(deps, id) {
|
|
|
161
162
|
status.id,
|
|
162
163
|
{ name: status.displayName, ready: readinessIsUsable(status.readiness) },
|
|
163
164
|
])),
|
|
165
|
+
defaults: readProviderDefaults(deps.db),
|
|
164
166
|
schedules: schedules.map(fitOf),
|
|
165
167
|
voices: listVoices(deps.db),
|
|
166
168
|
monthlyCost: cost,
|
|
@@ -36,17 +36,32 @@ function sourceOf(document, section) {
|
|
|
36
36
|
function heldText(source, text) {
|
|
37
37
|
return source === "provide" && text.trim() !== "" ? "held" : source;
|
|
38
38
|
}
|
|
39
|
+
// One press of Make sample makes every paid section's sample at once, so its sentence names
|
|
40
|
+
// them: "Make sample makes the samples of Title and keywords, Article and Narration together,
|
|
41
|
+
// about the sample topic."
|
|
42
|
+
export function makeSampleSentence(document) {
|
|
43
|
+
const made = paidSections
|
|
44
|
+
.filter((id) => {
|
|
45
|
+
const source = sourceOf(document, id);
|
|
46
|
+
return source !== "off" && source !== "provide";
|
|
47
|
+
})
|
|
48
|
+
.map((id) => sectionLabel[id]);
|
|
49
|
+
if (made.length <= 1)
|
|
50
|
+
return "Make sample shows what this section makes, about the sample topic.";
|
|
51
|
+
const names = `${made.slice(0, -1).join(", ")} and ${made.at(-1) ?? ""}`;
|
|
52
|
+
return `Make sample makes the samples of ${names} together, about the sample topic.`;
|
|
53
|
+
}
|
|
39
54
|
const offSentence = {
|
|
40
55
|
subject: "Research is off: the script is written from the topic alone.",
|
|
41
|
-
script: "The
|
|
56
|
+
script: "The article is off.",
|
|
42
57
|
voice: "The narration is off.",
|
|
43
|
-
pictures: "
|
|
58
|
+
pictures: "Images are off.",
|
|
44
59
|
thumbnail: "The thumbnail is off.",
|
|
45
60
|
video: "The video is off.",
|
|
46
61
|
shorts: "Shorts are off.",
|
|
47
|
-
document: "The PDF
|
|
48
|
-
reviews: "No
|
|
49
|
-
upload: "No video, so there is no
|
|
62
|
+
document: "The PDF is off.",
|
|
63
|
+
reviews: "No pause or AI check is on.",
|
|
64
|
+
upload: "No video, so there is no YouTube description or post.",
|
|
50
65
|
schedule: "",
|
|
51
66
|
};
|
|
52
67
|
// Each section's state before any sample: off, provided at run time (no sample, never blocks
|
|
@@ -69,7 +84,9 @@ export function baseStatuses(document, made = {}) {
|
|
|
69
84
|
id,
|
|
70
85
|
label,
|
|
71
86
|
state: "stale",
|
|
72
|
-
sentence:
|
|
87
|
+
sentence: paidSections.includes(id)
|
|
88
|
+
? makeSampleSentence(document)
|
|
89
|
+
: "Make sample shows what this section makes, about the sample topic.",
|
|
73
90
|
});
|
|
74
91
|
});
|
|
75
92
|
}
|
|
@@ -93,7 +110,7 @@ export function madeStatuses(free, schedules, cost) {
|
|
|
93
110
|
id: "reviews",
|
|
94
111
|
label: sectionLabel.reviews,
|
|
95
112
|
state: "current",
|
|
96
|
-
sentence: "Where a run
|
|
113
|
+
sentence: "Where a run pauses for you, and which AI checks run.",
|
|
97
114
|
};
|
|
98
115
|
made.schedule =
|
|
99
116
|
schedules === 0
|
|
@@ -101,7 +118,7 @@ export function madeStatuses(free, schedules, cost) {
|
|
|
101
118
|
id: "schedule",
|
|
102
119
|
label: sectionLabel.schedule,
|
|
103
120
|
state: "off",
|
|
104
|
-
sentence: "No schedule runs this template yet.
|
|
121
|
+
sentence: "No schedule runs this template yet.",
|
|
105
122
|
}
|
|
106
123
|
: {
|
|
107
124
|
id: "schedule",
|
|
@@ -167,7 +184,7 @@ export function paidStatuses(input) {
|
|
|
167
184
|
made[id] = status(id, "needs-fix", row.heldReason ?? "The sample failed. Press Make sample to try again.");
|
|
168
185
|
else
|
|
169
186
|
made[id] = status(id, "stale", done === undefined
|
|
170
|
-
?
|
|
187
|
+
? makeSampleSentence(input.headDocument)
|
|
171
188
|
: `Changed since the sample of version ${String(done.templateVersion)}. Press Make sample to see it again.`);
|
|
172
189
|
}
|
|
173
190
|
return made;
|
|
@@ -57,7 +57,7 @@ async function change(deps, id, next, sections, ack, kind) {
|
|
|
57
57
|
return {
|
|
58
58
|
ok: false,
|
|
59
59
|
reason: "not-found",
|
|
60
|
-
message: "This template no longer exists; it may have been deleted. Go to
|
|
60
|
+
message: "This template no longer exists; it may have been deleted. Go to Templates to see your templates.",
|
|
61
61
|
};
|
|
62
62
|
const quoted = await quoteSample(deps, id, {
|
|
63
63
|
topic: next.topic,
|
|
@@ -159,7 +159,7 @@ export async function setSampleTopic(deps, id, raw) {
|
|
|
159
159
|
return {
|
|
160
160
|
ok: false,
|
|
161
161
|
reason: "conflict",
|
|
162
|
-
message: "This topic change was already sent with another topic or price. Reload the
|
|
162
|
+
message: "This topic change was already sent with another topic or price. Reload the page to see the sample's topic, then change it again.",
|
|
163
163
|
};
|
|
164
164
|
const replayed = await quoteSample(deps, id, {
|
|
165
165
|
topic: last.topic,
|
|
@@ -212,7 +212,7 @@ export async function setFullScript(deps, id, raw) {
|
|
|
212
212
|
return {
|
|
213
213
|
ok: false,
|
|
214
214
|
reason: "invalid-input",
|
|
215
|
-
message: "
|
|
215
|
+
message: "Edit template sent a request Slopify couldn't read. Reload the page and try again.",
|
|
216
216
|
};
|
|
217
217
|
const record = sampleOf(deps.db, id);
|
|
218
218
|
return change(deps, id, {
|
|
@@ -27,5 +27,5 @@ export function thumbnailMessages(brief) {
|
|
|
27
27
|
// Empty output is a failed attempt. Returned as the sentence the stage would show rather than
|
|
28
28
|
// thrown, because the wrapper's `check` hook is what makes it a retry.
|
|
29
29
|
export function writtenPrompt(text) {
|
|
30
|
-
return text.trim() === "" ? "the
|
|
30
|
+
return text.trim() === "" ? "the AI model wrote no thumbnail prompt" : undefined;
|
|
31
31
|
}
|