summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-04-06 15:43:04 +0300
committerPaul Buetow <paul@buetow.org>2026-04-06 15:43:04 +0300
commitcdb5951fa25cc9352128ee8c0d76027cf2f6aa92 (patch)
treea6adec2155464831d61be27cea00ac2a53a6b99c
parent7193ec765f0b51093a203f8f3d00e69008be1cce (diff)
chore: bump version to 0.21.0, add maxPollAttempts constant and comments to veo.go
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
-rw-r--r--internal/version.go2
-rw-r--r--internal/video/veo.go20
2 files changed, 18 insertions, 4 deletions
diff --git a/internal/version.go b/internal/version.go
index 4c6daf1..ea3a538 100644
--- a/internal/version.go
+++ b/internal/version.go
@@ -1,3 +1,3 @@
package internal
-const Version = "0.20.0"
+const Version = "0.21.0"
diff --git a/internal/video/veo.go b/internal/video/veo.go
index ba23c74..c3be521 100644
--- a/internal/video/veo.go
+++ b/internal/video/veo.go
@@ -21,14 +21,23 @@ const (
DefaultVeoModel = "veo-2.0-generate-001"
// videoDurationSeconds is the clip length requested from Veo.
+ // 8 seconds is the minimum duration supported by the Veo API and produces
+ // clips long enough to convey the flashcard content without excess.
videoDurationSeconds = int32(8)
// videoAspectRatio is the target aspect ratio for generated clips.
+ // 16:9 matches the landscape orientation of the comic-style gallery panels.
videoAspectRatio = "16:9"
// pollInterval is the time to wait between operation status checks.
// Veo generation typically takes 1–3 minutes; 15 s keeps polling overhead low.
pollInterval = 15 * time.Second
+
+ // maxPollAttempts caps the number of polling iterations so that a hung or
+ // stalled Veo operation does not block the process indefinitely.
+ // At 15 s per attempt, 40 attempts ≈ 10 minutes — well above the observed
+ // worst-case generation time of ~3 minutes.
+ maxPollAttempts = 40
)
// VeoGenerator wraps the Google GenAI client for Veo video generation.
@@ -219,10 +228,15 @@ func (g *VeoGenerator) startOperation(ctx context.Context, imgBytes []byte, prom
}
// pollUntilDone repeatedly calls GetVideosOperation until the operation reports
-// completion or the context is cancelled. It sleeps pollInterval between checks.
+// completion, the context is cancelled, or maxPollAttempts is reached.
+// It sleeps pollInterval between checks to avoid hammering the API.
func (g *VeoGenerator) pollUntilDone(ctx context.Context, op *genai.GenerateVideosOperation) (*genai.GenerateVideosOperation, error) {
- for !op.Done {
- log.Printf("veo: operation in progress, waiting %s...", pollInterval)
+ for attempt := 0; !op.Done; attempt++ {
+ if attempt >= maxPollAttempts {
+ return nil, fmt.Errorf("veo: operation did not complete after %d attempts (%s each)", maxPollAttempts, pollInterval)
+ }
+
+ log.Printf("veo: operation in progress, waiting %s (attempt %d/%d)...", pollInterval, attempt+1, maxPollAttempts)
select {
case <-ctx.Done():