aigen-google 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3ed459cd7a272b27030c5256b234e5ae7c8275673fed7f97515e70b6017dff86
4
+ data.tar.gz: 827d4b335dba5251b636f22647c3f8c8efd9fa0bedd228b8171e9b3da975929c
5
+ SHA512:
6
+ metadata.gz: 99d6ddbd100fb2760a1a0c27e3472e72691fae5c862b43dd025bb0c76ec57bbedccc7ac3bf3adca900775cca48b771910d19bc22f287f83fbd1d6121ac5cd66f
7
+ data.tar.gz: 9db2f4e1aeb91496b9042e55e49d7112b63d47809b479d753f57ac4dce6a0773efd2ad18ade956eecda652eeff42e8f12e2a111e1847062788c9c521bd3bf510
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.standard.yml ADDED
@@ -0,0 +1,3 @@
1
+ # For available configuration options, see:
2
+ # https://github.com/standardrb/standard
3
+ ruby_version: 3.1
data/CHANGELOG.md ADDED
@@ -0,0 +1,82 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0] - 2025-11-23
11
+
12
+ ### Added
13
+
14
+ **Core Features:**
15
+ - Text generation with Gemini API (`Client#generate_content`)
16
+ - Multi-turn chat with conversation history (`Client#start_chat`, `Chat#send_message`)
17
+ - Streaming responses with progressive chunk delivery (`Client#generate_content_stream`, `Chat#send_message_stream`)
18
+ - Multimodal content support (text + images via `Content` class)
19
+ - Generation configuration (`GenerationConfig` with temperature, top_p, top_k, max_output_tokens)
20
+ - Safety settings with sensible defaults (`SafetySettings` with harm categories and thresholds)
21
+
22
+ **Configuration:**
23
+ - Global configuration via `Aigen::Google.configure` block
24
+ - Instance-level configuration via client initialization
25
+ - Environment variable fallback for API key (`GOOGLE_API_KEY`)
26
+ - Configurable timeout and retry count
27
+
28
+ **Error Handling:**
29
+ - Comprehensive exception hierarchy (`AuthenticationError`, `InvalidRequestError`, `RateLimitError`, `ServerError`, `TimeoutError`, `ApiError`)
30
+ - Automatic retry logic with exponential backoff (1s, 2s, 4s) for rate limits (429) and server errors (500-599)
31
+ - Client-side validation for generation config parameters (fail-fast approach)
32
+ - Helpful error messages with context and actionable suggestions
33
+
34
+ **Developer Experience:**
35
+ - YARD documentation for all public APIs with `@param`, `@return`, `@raise`, `@example` tags
36
+ - Frozen string literals for memory efficiency
37
+ - StandardRB compliance (0 offenses)
38
+ - Ruby 3.1+ support with modern idioms
39
+ - Comprehensive test suite (137 examples, >= 90% coverage)
40
+
41
+ **Testing & Quality:**
42
+ - RSpec test suite with 137 passing examples
43
+ - SimpleCov integration for coverage tracking
44
+ - WebMock for HTTP stubbing in tests
45
+ - StandardRB linter configuration
46
+ - Continuous integration ready
47
+
48
+ ### Technical Details
49
+
50
+ **Architecture:**
51
+ - Clean separation of concerns: `Client` (orchestration), `Chat` (state), `HttpClient` (transport), `Content` (data), `GenerationConfig` (validation), `SafetySettings` (configuration)
52
+ - Builder pattern for Content creation (`.text()`, `.image()`)
53
+ - Fail-fast validation in GenerationConfig
54
+ - Enumerator pattern for lazy streaming evaluation
55
+ - History management with frozen copies to prevent external mutation
56
+
57
+ **API Compatibility:**
58
+ - Gemini API v1beta support
59
+ - Backward compatible prompt API alongside new contents API
60
+ - camelCase conversion for API parameters (maxOutputTokens, topP, topK)
61
+ - Newline-delimited JSON streaming (not traditional SSE)
62
+
63
+ ### Dependencies
64
+
65
+ - `faraday` ~> 2.0 - HTTP client
66
+ - `rspec` ~> 3.0 - Testing framework (development)
67
+ - `webmock` ~> 3.0 - HTTP mocking (development)
68
+ - `standard` ~> 1.3 - Ruby linter (development)
69
+ - `simplecov` ~> 0.22 - Code coverage (development)
70
+
71
+ ### Breaking Changes
72
+
73
+ None - this is the initial release.
74
+
75
+ ### Known Issues
76
+
77
+ None
78
+
79
+ ---
80
+
81
+ [Unreleased]: https://github.com/neuralmux/aigen-google/compare/v0.1.0...HEAD
82
+ [0.1.0]: https://github.com/neuralmux/aigen-google/releases/tag/v0.1.0
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 TODO: Write your name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,383 @@
1
+ # Aigen::Google
2
+
3
+ Ruby SDK for Google's Gemini API - build AI-powered applications with text generation, chat, streaming, and multimodal content support.
4
+
5
+ [![Gem Version](https://badge.fury.io/rb/aigen-google.svg)](https://badge.fury.io/rb/aigen-google)
6
+ [![Build Status](https://github.com/neuralmux/aigen-google/workflows/CI/badge.svg)](https://github.com/neuralmux/aigen-google/actions)
7
+
8
+ ## Features
9
+
10
+ - **Text Generation:** Generate content from text prompts
11
+ - **Chat with History:** Multi-turn conversations with context preservation
12
+ - **Streaming:** Real-time response delivery with progressive chunks
13
+ - **Multimodal Content:** Combine text and images in requests
14
+ - **Generation Config:** Control output with temperature, top_p, top_k, max_output_tokens
15
+ - **Safety Settings:** Configure content filtering for harm categories
16
+ - **Comprehensive Error Handling:** Automatic retries with exponential backoff for rate limits and server errors
17
+ - **Ruby 3.1+ Support:** Modern Ruby idioms with frozen string literals
18
+
19
+ ## Installation
20
+
21
+ Add this line to your application's Gemfile:
22
+
23
+ ```ruby
24
+ gem 'aigen-google'
25
+ ```
26
+
27
+ And then execute:
28
+
29
+ ```bash
30
+ bundle install
31
+ ```
32
+
33
+ Or install it yourself as:
34
+
35
+ ```bash
36
+ gem install aigen-google
37
+ ```
38
+
39
+ ## Quick Start
40
+
41
+ ```ruby
42
+ require 'aigen/google'
43
+
44
+ # Configure with your API key
45
+ Aigen::Google.configure do |config|
46
+ config.api_key = ENV['GOOGLE_API_KEY']
47
+ end
48
+
49
+ # Generate content
50
+ client = Aigen::Google::Client.new
51
+ response = client.generate_content(prompt: "Explain quantum computing in simple terms")
52
+ puts response["candidates"][0]["content"]["parts"][0]["text"]
53
+ ```
54
+
55
+ ## Configuration
56
+
57
+ ### Block-based Configuration (Recommended)
58
+
59
+ ```ruby
60
+ Aigen::Google.configure do |config|
61
+ config.api_key = ENV['GOOGLE_API_KEY']
62
+ config.default_model = "gemini-pro"
63
+ config.timeout = 60
64
+ end
65
+
66
+ client = Aigen::Google::Client.new
67
+ ```
68
+
69
+ ### Instance-based Configuration
70
+
71
+ ```ruby
72
+ client = Aigen::Google::Client.new(
73
+ api_key: "your-api-key",
74
+ model: "gemini-pro",
75
+ timeout: 60
76
+ )
77
+ ```
78
+
79
+ ### Available Configuration Options
80
+
81
+ | Option | Type | Default | Description |
82
+ |--------|------|---------|-------------|
83
+ | `api_key` | String | `ENV['GOOGLE_API_KEY']` | Your Google AI API key ([Get one here](https://makersuite.google.com/app/apikey)) |
84
+ | `default_model` | String | `"gemini-pro"` | Default model to use for requests |
85
+ | `timeout` | Integer | `30` | HTTP request timeout in seconds |
86
+ | `retry_count` | Integer | `3` | Number of retry attempts for rate limits/server errors |
87
+
88
+ ## Usage Examples
89
+
90
+ ### Basic Text Generation
91
+
92
+ ```ruby
93
+ client = Aigen::Google::Client.new
94
+
95
+ response = client.generate_content(prompt: "Write a haiku about Ruby programming")
96
+ text = response["candidates"][0]["content"]["parts"][0]["text"]
97
+ puts text
98
+ ```
99
+
100
+ ### Chat with History
101
+
102
+ ```ruby
103
+ chat = client.start_chat
104
+
105
+ # First message
106
+ chat.send_message("What is Ruby?")
107
+
108
+ # Follow-up with context
109
+ response = chat.send_message("What are its main features?")
110
+ text = response["candidates"][0]["content"]["parts"][0]["text"]
111
+ puts text
112
+
113
+ # View conversation history
114
+ puts chat.history
115
+ ```
116
+
117
+ ### Streaming Responses
118
+
119
+ Stream responses as they're generated for real-time feedback:
120
+
121
+ ```ruby
122
+ # With block (immediate processing)
123
+ client.generate_content_stream(prompt: "Tell me a story") do |chunk|
124
+ text = chunk["candidates"][0]["content"]["parts"][0]["text"]
125
+ print text
126
+ end
127
+
128
+ # With Enumerator (lazy evaluation)
129
+ stream = client.generate_content_stream(prompt: "Count to 10")
130
+ stream.each do |chunk|
131
+ text = chunk["candidates"][0]["content"]["parts"][0]["text"]
132
+ print text
133
+ end
134
+ ```
135
+
136
+ ### Chat Streaming
137
+
138
+ ```ruby
139
+ chat = client.start_chat
140
+
141
+ chat.send_message_stream("Tell me a joke") do |chunk|
142
+ text = chunk["candidates"][0]["content"]["parts"][0]["text"]
143
+ print text
144
+ end
145
+ # History is updated after streaming completes
146
+ ```
147
+
148
+ ### Multimodal Content (Text + Images)
149
+
150
+ ```ruby
151
+ require 'base64'
152
+
153
+ # Prepare image data
154
+ image_data = Base64.strict_encode64(File.read("photo.jpg"))
155
+
156
+ # Create multimodal content
157
+ text_content = Aigen::Google::Content.text("What is in this image?")
158
+ image_content = Aigen::Google::Content.image(
159
+ data: image_data,
160
+ mime_type: "image/jpeg"
161
+ )
162
+
163
+ # Generate content with both
164
+ response = client.generate_content(contents: [text_content.to_h, image_content.to_h])
165
+ text = response["candidates"][0]["content"]["parts"][0]["text"]
166
+ puts text
167
+ ```
168
+
169
+ ### Configuring Generation Parameters
170
+
171
+ Control output quality and randomness:
172
+
173
+ ```ruby
174
+ response = client.generate_content(
175
+ prompt: "Write a creative story",
176
+ temperature: 0.9, # Higher = more creative (0.0-1.0)
177
+ top_p: 0.95, # Nucleus sampling (0.0-1.0)
178
+ top_k: 40, # Top-k sampling
179
+ max_output_tokens: 1024 # Maximum response length
180
+ )
181
+ ```
182
+
183
+ ### Safety Settings
184
+
185
+ Configure content filtering:
186
+
187
+ ```ruby
188
+ # Use default settings (BLOCK_MEDIUM_AND_ABOVE for all categories)
189
+ settings = Aigen::Google::SafetySettings.default
190
+
191
+ # Or customize
192
+ settings = Aigen::Google::SafetySettings.new([
193
+ {
194
+ category: Aigen::Google::SafetySettings::HARM_CATEGORY_HATE_SPEECH,
195
+ threshold: Aigen::Google::SafetySettings::BLOCK_LOW_AND_ABOVE
196
+ },
197
+ {
198
+ category: Aigen::Google::SafetySettings::HARM_CATEGORY_DANGEROUS_CONTENT,
199
+ threshold: Aigen::Google::SafetySettings::BLOCK_MEDIUM_AND_ABOVE
200
+ }
201
+ ])
202
+
203
+ response = client.generate_content(
204
+ prompt: "Hello",
205
+ safety_settings: settings.to_h
206
+ )
207
+ ```
208
+
209
+ ### Image Generation (Nano Banana 🍌)
210
+
211
+ Generate images using Gemini's image generation models (nicknamed "Nano Banana"):
212
+
213
+ ```ruby
214
+ # Use an image generation model
215
+ client = Aigen::Google::Client.new(model: 'gemini-2.5-flash-image')
216
+
217
+ # Simple image generation
218
+ response = client.generate_image("A serene mountain landscape at sunset")
219
+
220
+ if response.success?
221
+ response.save("landscape.png")
222
+ puts "Image saved!"
223
+ puts "Description: #{response.text}"
224
+ else
225
+ puts "Generation failed: #{response.failure_message}"
226
+ end
227
+ ```
228
+
229
+ #### With Size and Aspect Ratio
230
+
231
+ ```ruby
232
+ response = client.generate_image(
233
+ "A futuristic cityscape with flying cars",
234
+ aspect_ratio: "16:9", # Options: "1:1", "16:9", "9:16", "4:3", "3:4", "5:4", "4:5"
235
+ size: "2K" # Options: "1K", "2K", "4K"
236
+ )
237
+
238
+ response.save("city.png") if response.success?
239
+ ```
240
+
241
+ #### ImageResponse Helper Methods
242
+
243
+ The `generate_image` method returns an `ImageResponse` object with convenient helpers:
244
+
245
+ ```ruby
246
+ response = client.generate_image("A cute puppy")
247
+
248
+ # Check success
249
+ response.success? # => true/false
250
+ response.has_image? # => true/false
251
+
252
+ # Access image data
253
+ response.image_data # => Binary image data
254
+ response.mime_type # => "image/png"
255
+ response.text # => Text description
256
+
257
+ # Save image
258
+ response.save("output.png")
259
+
260
+ # Handle failures
261
+ unless response.success?
262
+ puts response.failure_reason # => "IMAGE_OTHER", "SAFETY", etc.
263
+ puts response.failure_message # => Detailed error message
264
+ end
265
+
266
+ # Access raw response
267
+ response.raw_response # => Full API response hash
268
+ ```
269
+
270
+ #### Available Models
271
+
272
+ - `gemini-2.5-flash-image` - Standard image generation (up to 2K)
273
+ - `gemini-2.0-flash-exp` - Experimental with native image generation
274
+ - `gemini-3-pro-image-preview` - Preview with 4K support
275
+
276
+ ## Error Handling
277
+
278
+ The SDK provides comprehensive error handling with automatic retries:
279
+
280
+ ### Exception Types
281
+
282
+ | Exception | When Raised | Retry Behavior |
283
+ |-----------|-------------|----------------|
284
+ | `Aigen::Google::AuthenticationError` | Invalid API key (401/403) | No retry |
285
+ | `Aigen::Google::InvalidRequestError` | Malformed request (400/404) | No retry |
286
+ | `Aigen::Google::RateLimitError` | Rate limit exceeded (429) | Automatic retry with backoff |
287
+ | `Aigen::Google::ServerError` | Server error (500-599) | Automatic retry with backoff |
288
+ | `Aigen::Google::TimeoutError` | Request timeout | Automatic retry with backoff |
289
+ | `Aigen::Google::ApiError` | Other API errors | No retry |
290
+
291
+ ### Retry Behavior
292
+
293
+ The SDK automatically retries rate limit (429) and server errors (500-599) with exponential backoff:
294
+ - **Attempt 1:** Wait 1 second, retry
295
+ - **Attempt 2:** Wait 2 seconds, retry
296
+ - **Attempt 3:** Wait 4 seconds, raise error if fails
297
+
298
+ Maximum retry attempts: 3 (configurable via `retry_count`)
299
+
300
+ ### Handling Errors
301
+
302
+ ```ruby
303
+ begin
304
+ response = client.generate_content(prompt: "Hello")
305
+ rescue Aigen::Google::AuthenticationError => e
306
+ puts "Invalid API key: #{e.message}"
307
+ puts "Get your API key at: https://makersuite.google.com/app/apikey"
308
+ rescue Aigen::Google::RateLimitError => e
309
+ puts "Rate limit exceeded: #{e.message}"
310
+ puts "Try reducing request rate or increasing quota"
311
+ rescue Aigen::Google::ServerError => e
312
+ puts "Server error (#{e.status_code}): #{e.message}"
313
+ puts "Try again later - the API may be experiencing issues"
314
+ rescue Aigen::Google::TimeoutError => e
315
+ puts "Request timed out: #{e.message}"
316
+ rescue Aigen::Google::ApiError => e
317
+ puts "API error (#{e.status_code}): #{e.message}"
318
+ end
319
+ ```
320
+
321
+ ## API Reference
322
+
323
+ Full API documentation is available at [https://rubydoc.info/gems/aigen-google](https://rubydoc.info/gems/aigen-google) (YARD documentation).
324
+
325
+ ### Key Classes
326
+
327
+ - `Aigen::Google::Client` - Main client for API requests
328
+ - `Aigen::Google::Chat` - Multi-turn conversation management
329
+ - `Aigen::Google::Content` - Multimodal content builder
330
+ - `Aigen::Google::GenerationConfig` - Generation parameter configuration
331
+ - `Aigen::Google::SafetySettings` - Content filtering configuration
332
+ - `Aigen::Google::Configuration` - Global configuration
333
+
334
+ ## Development
335
+
336
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
337
+
338
+ ### Running Tests
339
+
340
+ ```bash
341
+ # Run all tests
342
+ bundle exec rspec
343
+
344
+ # Run with coverage report
345
+ COVERAGE=true bundle exec rspec
346
+
347
+ # Run linter
348
+ bundle exec rake standard
349
+
350
+ # Run both tests and linter
351
+ bundle exec rake
352
+ ```
353
+
354
+ ### Code Quality
355
+
356
+ - **Test Coverage:** >= 90% (enforced with SimpleCov)
357
+ - **Code Style:** StandardRB (0 offenses required)
358
+ - **Ruby Version:** >= 3.1.0
359
+
360
+ ## Contributing
361
+
362
+ Bug reports and pull requests are welcome on GitHub at https://github.com/neuralmux/aigen-google.
363
+
364
+ 1. Fork the repository
365
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
366
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
367
+ 4. Push to the branch (`git push origin my-new-feature`)
368
+ 5. Create a new Pull Request
369
+
370
+ ## License
371
+
372
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
373
+
374
+ ## Changelog
375
+
376
+ See [CHANGELOG.md](CHANGELOG.md) for version history and release notes.
377
+
378
+ ## Resources
379
+
380
+ - [Gemini API Documentation](https://ai.google.dev/docs)
381
+ - [Get your API Key](https://makersuite.google.com/app/apikey)
382
+ - [Ruby Style Guide](https://rubystyle.guide/)
383
+ - [YARD Documentation Guide](https://rubydoc.info/gems/yard/file/docs/GettingStarted.md)
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "standard/rake"
9
+
10
+ task default: %i[spec standard]