// Package adapters provides mediagen provider adapters for various AI services. package adapters import ( "context" "fmt" "git.threesix.ai/jordan/persona-community-5/pkg/gemini" "git.threesix.ai/jordan/persona-community-5/pkg/mediagen" ) // GeminiProvider adapts pkg/gemini to the mediagen interfaces. type GeminiProvider struct { client *gemini.Client } // NewGeminiProvider creates a new Gemini provider adapter. func NewGeminiProvider(client *gemini.Client) *GeminiProvider { return &GeminiProvider{client: client} } // Name implements mediagen.ImageGenerator and mediagen.VideoGenerator. func (p *GeminiProvider) Name() string { return "gemini" } // Health implements mediagen.ImageGenerator and mediagen.VideoGenerator. func (p *GeminiProvider) Health(ctx context.Context) error { if err := p.client.Health(ctx); err != nil { return mediagen.NewProviderError("gemini", "Health", err) } return nil } // validImageMIMETypes lists MIME types supported for reference images var geminiValidImageMIMETypes = map[string]bool{ "image/png": true, "image/jpeg": true, "image/webp": true, } // GenerateImage implements mediagen.ImageGenerator. // Note: Gemini's native image generation currently supports only 1 image per request. // The Count field is ignored. func (p *GeminiProvider) GenerateImage(ctx context.Context, req mediagen.ImageRequest) (*mediagen.ImageResponse, error) { // Validate reference image MIME type if provided if len(req.ReferenceImage) > 0 && req.ReferenceMime != "" { if !geminiValidImageMIMETypes[req.ReferenceMime] { return nil, fmt.Errorf("unsupported reference image MIME type: %s (supported: image/png, image/jpeg, image/webp)", req.ReferenceMime) } } // Map unified request to Gemini-specific request gemReq := gemini.ImageRequest{ Prompt: req.Prompt, Model: req.Model, Size: req.Size, AspectRatio: req.AspectRatio, ReferenceImage: req.ReferenceImage, ReferenceMime: req.ReferenceMime, Seed: req.Seed, } // Call Gemini client gemResp, err := p.client.GenerateImage(ctx, gemReq) if err != nil { return nil, mediagen.NewProviderError("gemini", "GenerateImage", err) } // Convert response to unified format images := make([]mediagen.Image, 0, len(gemResp.Images)) for _, img := range gemResp.Images { images = append(images, mediagen.Image{ Data: img.Data, MimeType: img.MimeType, }) } return &mediagen.ImageResponse{ Images: images, Seed: gemResp.Seed, }, nil } // GenerateVideo implements mediagen.VideoGenerator. func (p *GeminiProvider) GenerateVideo(ctx context.Context, req mediagen.VideoRequest) (*mediagen.VideoResponse, error) { // Map unified request to Gemini-specific request gemReq := gemini.VideoRequest{ Prompt: req.Prompt, Model: req.Model, AspectRatio: req.AspectRatio, Duration: req.Duration, } // Convert first reference image if provided if len(req.ReferenceImages) > 0 { img := req.ReferenceImages[0] gemReq.Image = img.Data gemReq.ImageMimeType = img.MimeType } // Call Gemini client gemResp, err := p.client.GenerateVideo(ctx, gemReq) if err != nil { return nil, mediagen.NewProviderError("gemini", "GenerateVideo", err) } // If video was returned as URI, download it var videoData []byte var mimeType string var url string if len(gemResp.Video.Data) > 0 { videoData = gemResp.Video.Data mimeType = gemResp.Video.MimeType } if gemResp.Video.URI != "" { url = gemResp.Video.URI // If we don't have data yet, download from URI if len(videoData) == 0 { downloaded, downloadErr := downloadVideo(ctx, gemResp.Video.URI) if downloadErr != nil { // Return URI-only response if download fails (caller can retry download) return &mediagen.VideoResponse{ Videos: []mediagen.Video{ { URL: url, MimeType: "video/mp4", }, }, }, nil } videoData = downloaded mimeType = "video/mp4" } } if mimeType == "" { mimeType = "video/mp4" } return &mediagen.VideoResponse{ Videos: []mediagen.Video{ { Data: videoData, MimeType: mimeType, URL: url, }, }, }, nil } // Compile-time interface check var ( _ mediagen.ImageGenerator = (*GeminiProvider)(nil) _ mediagen.VideoGenerator = (*GeminiProvider)(nil) )