summaryrefslogtreecommitdiff
path: root/internal/video
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-04-08 09:53:17 +0300
committerPaul Buetow <paul@buetow.org>2026-04-08 09:53:17 +0300
commitcd4265b8f87811db758c89bab5e62daa6c39337a (patch)
tree94c0a129b4b6ee9132baaa81eb3fbc96b083cbd4 /internal/video
parent7e7d34bfc0aec2aa8dff4cefa720e4a9b42d95d8 (diff)
feat(httpctx): add timeouts for OpenAI, Gemini, and HTTP downloads
Introduce internal/httpctx with non-zero http.Client timeouts for go-openai and google.golang.org/genai, shared image download client, and WithTimeoutUnlessSet for operation-level deadlines when callers use Background. Wire NewOpenAIClient/NewGenAIClient everywhere clients are constructed. Apply Search timeouts for DALL-E and Nano Banana, provider audio timeouts, model-list timeouts, Veo operation timeouts, story page download context, and single-word CLI processing cap. Made-with: Cursor
Diffstat (limited to 'internal/video')
-rw-r--r--internal/video/veo.go10
1 files changed, 9 insertions, 1 deletions
diff --git a/internal/video/veo.go b/internal/video/veo.go
index 018c06a..05fd0f3 100644
--- a/internal/video/veo.go
+++ b/internal/video/veo.go
@@ -13,6 +13,8 @@ import (
"time"
"google.golang.org/genai"
+
+ "codeberg.org/snonux/totalrecall/internal/httpctx"
)
const (
@@ -48,7 +50,7 @@ type VeoGenerator struct {
// newGenaiClient is the constructor used in production and can be replaced in
// unit tests to inject a mock transport.
-var newGenaiClient = genai.NewClient
+var newGenaiClient = httpctx.NewGenAIClient
// NewVeoGenerator creates a new VeoGenerator backed by the Gemini API.
// It returns an error if the API key is empty or the SDK client cannot be
@@ -82,6 +84,9 @@ func NewVeoGenerator(apiKey string) (*VeoGenerator, error) {
// outputDir is where the output MP4 will be written.
// pageNum selects which gallery page to animate (1-based).
func (g *VeoGenerator) GenerateVideoFromGallery(ctx context.Context, galleryPath string, outputDir string, pageNum int) (string, error) {
+ ctx, cancel := httpctx.WithTimeoutUnlessSet(ctx, httpctx.VeoCLIPerVideoTimeout)
+ defer cancel()
+
imgPath, imgBytes, err := loadGalleryImage(galleryPath, pageNum)
if err != nil {
return "", err
@@ -109,6 +114,9 @@ func (g *VeoGenerator) GenerateVideoFromGallery(ctx context.Context, galleryPath
// because it avoids a second glob search and always writes the video next to
// its source image.
func (g *VeoGenerator) GenerateVideoFromPath(ctx context.Context, imgPath string) (string, error) {
+ ctx, cancel := httpctx.WithTimeoutUnlessSet(ctx, httpctx.VeoCLIPerVideoTimeout)
+ defer cancel()
+
imgBytes, err := os.ReadFile(imgPath)
if err != nil {
return "", fmt.Errorf("veo: reading gallery image %s: %w", imgPath, err)