summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-04-19 23:16:14 +0300
committerPaul Buetow <paul@buetow.org>2026-04-19 23:16:14 +0300
commit6130cae3fa396cff94653225e47326b642e270f3 (patch)
tree8a8ca46bd320682b984a7aca45531b451b2ceeaf
parentd97741966a6c97b5db7df62873bd2ee9d99f0565 (diff)
y4: make narration TTS optional in CLI
-rw-r--r--cmd/comicforge/cli.go9
-rw-r--r--cmd/comicforge/cli_test.go67
2 files changed, 73 insertions, 3 deletions
diff --git a/cmd/comicforge/cli.go b/cmd/comicforge/cli.go
index b0c539b..270ed72 100644
--- a/cmd/comicforge/cli.go
+++ b/cmd/comicforge/cli.go
@@ -134,9 +134,12 @@ func runCommand(ctx context.Context, cmd *cobra.Command, deps commandDeps, flags
if err != nil {
return fmt.Errorf("build image provider: %w", err)
}
- mainTTSProvider, err := deps.newTTSProvider(cfg, voice)
- if err != nil {
- return fmt.Errorf("build TTS provider: %w", err)
+ var mainTTSProvider provider.TTSProvider
+ if flags.narrateEnabled {
+ mainTTSProvider, err = deps.newTTSProvider(cfg, voice)
+ if err != nil {
+ return fmt.Errorf("build TTS provider: %w", err)
+ }
}
runner := deps.newRunner(&comic.RunnerConfig{
diff --git a/cmd/comicforge/cli_test.go b/cmd/comicforge/cli_test.go
index 19a2f19..809a839 100644
--- a/cmd/comicforge/cli_test.go
+++ b/cmd/comicforge/cli_test.go
@@ -3,6 +3,7 @@ package main
import (
"bytes"
"context"
+ "fmt"
"os"
"path/filepath"
"strings"
@@ -250,6 +251,72 @@ func TestRootCommandRejectsConflictingUltraFlags(t *testing.T) {
}
}
+func TestRootCommandProviderFlagsDefaultToGemini(t *testing.T) {
+ cmd := newRootCommand()
+ for _, flagName := range []string{"text-provider", "image-provider", "tts-provider"} {
+ flag := cmd.Flags().Lookup(flagName)
+ if flag == nil {
+ t.Fatalf("flag %q not found", flagName)
+ }
+ if got, want := flag.DefValue, provider.Gemini; got != want {
+ t.Fatalf("%s default = %q, want %q", flagName, got, want)
+ }
+ }
+}
+
+func TestRootCommandSkipsTTSProviderWhenNarrationDisabled(t *testing.T) {
+ tmpDir := t.TempDir()
+ vocabPath := filepath.Join(tmpDir, "vocab.txt")
+ if err := os.WriteFile(vocabPath, []byte("ябълка = apple\n"), 0o644); err != nil {
+ t.Fatalf("write vocab: %v", err)
+ }
+
+ var ttsCalled bool
+ var gotRunnerCfg *comic.RunnerConfig
+ runner := &recordingRunner{}
+
+ cmd := newRootCommandWithDeps(commandDeps{
+ loadConfig: func(string) (*config.Config, error) {
+ return config.DefaultConfig(), nil
+ },
+ newTextProvider: func(cfg *config.Config) (provider.TextProvider, error) {
+ return noopProvider{}, nil
+ },
+ newImageProvider: func(cfg *config.Config) (provider.ImageProvider, error) {
+ return noopProvider{}, nil
+ },
+ newTTSProvider: func(*config.Config, string) (provider.TTSProvider, error) {
+ ttsCalled = true
+ return nil, fmt.Errorf("tts provider should not be resolved when narration is disabled")
+ },
+ newRunner: func(cfg *comic.RunnerConfig) comic.StoryRunner {
+ gotRunnerCfg = cfg
+ runner.cfg = cfg
+ return runner
+ },
+ })
+ buf := &bytes.Buffer{}
+ cmd.SetOut(buf)
+ cmd.SetErr(buf)
+ cmd.SetArgs([]string{"--vocab", vocabPath})
+
+ if err := cmd.ExecuteContext(context.Background()); err != nil {
+ t.Fatalf("ExecuteContext() error = %v\noutput:\n%s", err, buf.String())
+ }
+ if ttsCalled {
+ t.Fatal("newTTSProvider was called, want narration-disabled path to skip TTS setup")
+ }
+ if gotRunnerCfg == nil {
+ t.Fatal("runner config was not captured")
+ }
+ if gotRunnerCfg.MainTTSProvider != nil || gotRunnerCfg.ConclusionTTSProvider != nil {
+ t.Fatalf("runner TTS providers = %#v / %#v, want nil / nil", gotRunnerCfg.MainTTSProvider, gotRunnerCfg.ConclusionTTSProvider)
+ }
+ if runner.runs != 1 {
+ t.Fatalf("runner.runs = %d, want 1", runner.runs)
+ }
+}
+
type recordingRunner struct {
cfg *comic.RunnerConfig
batchFile string