1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
package image
import (
"context"
"io"
)
// SearchResult represents a single image search result
type SearchResult struct {
ID string // Unique identifier
URL string // Direct URL to the image
ThumbnailURL string // URL to thumbnail version
Width int // Image width in pixels
Height int // Image height in pixels
Description string // Image description or tags
Attribution string // Attribution text if required
Source string // Source provider (e.g., "pixabay", "unsplash")
}
// SearchOptions configures the image search
type SearchOptions struct {
Query string // Search query (Bulgarian word)
Translation string // English translation (if already available)
Language string // Language code (default: "bg")
SafeSearch bool // Enable safe search filtering
PerPage int // Number of results per page
Page int // Page number (1-based)
ImageType string // Type: "photo", "illustration", "vector", "all"
Orientation string // Orientation: "horizontal", "vertical", "all"
CustomPrompt string // Custom prompt for AI image generation
AspectRatio string // Override aspect ratio (e.g. "9:16"); empty = provider default
// ReferenceImages holds raw PNG bytes of previously generated images.
// When non-empty, the NanoBanana client sends them as multimodal content
// alongside the text prompt so the model can match character appearance
// across pages (iterative chaining technique).
ReferenceImages [][]byte
}
// DefaultSearchOptions returns sensible defaults for Bulgarian word searches
func DefaultSearchOptions(query string) *SearchOptions {
return &SearchOptions{
Query: query,
Language: "bg",
SafeSearch: true,
PerPage: 10,
Page: 1,
ImageType: "photo",
Orientation: "all",
}
}
// AttributionProvider returns required attribution text for a search result.
// Kept separate from ImageSearcher so callers that only need attribution
// do not depend on Search/Download/Name.
type AttributionProvider interface {
GetAttribution(result *SearchResult) string
}
// ImageSearcher defines the interface for image search providers.
// Providers that also carry attribution text implement AttributionProvider
// in addition to this interface.
type ImageSearcher interface {
// Search performs an image search with the given options.
Search(ctx context.Context, opts *SearchOptions) ([]SearchResult, error)
// Download downloads an image from the given URL.
Download(ctx context.Context, url string) (io.ReadCloser, error)
// Name returns the name of the search provider.
Name() string
}
// ImageClient combines ImageSearcher and AttributionProvider for callers
// that need full provider capabilities (search, download, attribution).
type ImageClient interface {
ImageSearcher
AttributionProvider
}
// SearchError represents an error from an image search provider
type SearchError struct {
Provider string
Code string
Message string
}
func (e *SearchError) Error() string {
return e.Provider + ": " + e.Message
}
// RateLimitError indicates that the API rate limit has been exceeded
type RateLimitError struct {
Provider string
RetryAfter int // Seconds to wait before retry
LimitPerHour int
LimitPerDay int
}
func (e *RateLimitError) Error() string {
return e.Provider + ": rate limit exceeded"
}
|