gemini_craft 0.1.2 → 0.2.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 +4 -4
- data/CHANGELOG.md +292 -4
- data/README.md +652 -38
- data/lib/gemini_craft/cache.rb +102 -18
- data/lib/gemini_craft/client.rb +280 -75
- data/lib/gemini_craft/configuration.rb +24 -1
- data/lib/gemini_craft/error.rb +27 -0
- data/lib/gemini_craft/version.rb +1 -1
- data/lib/gemini_craft.rb +37 -11
- metadata +8 -8
data/README.md
CHANGED
@@ -1,8 +1,24 @@
|
|
1
|
-
# GeminiCraft
|
1
|
+
# GeminiCraft 🚀
|
2
2
|
|
3
|
-
|
3
|
+
[](https://badge.fury.io/rb/gemini_craft)
|
4
|
+
[](https://github.com/shobhits7/gemini_craft/actions)
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
4
6
|
|
5
|
-
|
7
|
+
A powerful Ruby gem for generating content using Google's Gemini AI with advanced features like streaming, function calling, intelligent caching, and Rails integration.
|
8
|
+
|
9
|
+
## ✨ Features
|
10
|
+
|
11
|
+
- 🤖 **Simple Content Generation** - Easy-to-use interface for Gemini AI
|
12
|
+
- 🌊 **Streaming Support** - Real-time content generation for better UX
|
13
|
+
- 🔧 **Function Calling** - Enable AI to call your Ruby functions/APIs
|
14
|
+
- 🚀 **Enhanced Caching** - Intelligent caching with automatic cleanup
|
15
|
+
- 📊 **Comprehensive Error Handling** - Specific error types for better debugging
|
16
|
+
- 📝 **Rails Integration** - Built-in Rails logger support
|
17
|
+
- ⚡ **Connection Pooling** - Optimized for high-throughput applications
|
18
|
+
- 🔄 **Automatic Retries** - Smart retry logic for failed requests
|
19
|
+
- 🛡️ **Thread Safe** - Safe for concurrent usage
|
20
|
+
|
21
|
+
## 📦 Installation
|
6
22
|
|
7
23
|
Add this line to your application's Gemfile:
|
8
24
|
|
@@ -22,87 +38,685 @@ Or install it yourself as:
|
|
22
38
|
$ gem install gemini_craft
|
23
39
|
```
|
24
40
|
|
25
|
-
##
|
41
|
+
## 🔑 Getting Started
|
26
42
|
|
27
|
-
###
|
43
|
+
### 1. Get Your API Key
|
28
44
|
|
29
|
-
|
45
|
+
Get your Gemini API key from [Google AI Studio](https://makersuite.google.com/app/apikey).
|
46
|
+
|
47
|
+
### 2. Basic Configuration
|
30
48
|
|
31
49
|
```ruby
|
32
50
|
require 'gemini_craft'
|
33
51
|
|
34
52
|
GeminiCraft.configure do |config|
|
35
53
|
config.api_key = 'your-gemini-api-key'
|
36
|
-
|
37
|
-
config.cache_enabled = true # Optional, defaults to false
|
38
|
-
config.cache_ttl = 3600 # Optional, cache TTL in seconds (default: 1 hour)
|
39
|
-
config.timeout = 30 # Optional, request timeout in seconds
|
40
|
-
config.max_retries = 3 # Optional, number of retry attempts for failed requests
|
54
|
+
# Or set the GEMINI_API_KEY environment variable
|
41
55
|
end
|
42
56
|
```
|
43
57
|
|
44
|
-
|
58
|
+
### 3. Generate Your First Content
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
response = GeminiCraft.generate_content("Write a haiku about Ruby programming")
|
62
|
+
puts response
|
63
|
+
```
|
45
64
|
|
46
|
-
|
65
|
+
## 🔧 Configuration
|
47
66
|
|
48
|
-
|
67
|
+
### Basic Configuration
|
49
68
|
|
50
69
|
```ruby
|
51
|
-
|
52
|
-
|
70
|
+
GeminiCraft.configure do |config|
|
71
|
+
config.api_key = 'your-gemini-api-key'
|
72
|
+
config.model = 'gemini-2.0-flash' # Default model
|
73
|
+
config.timeout = 30 # Request timeout in seconds
|
74
|
+
config.max_retries = 3 # Number of retry attempts
|
75
|
+
end
|
53
76
|
```
|
54
77
|
|
55
|
-
|
78
|
+
### Advanced Configuration
|
56
79
|
|
57
80
|
```ruby
|
58
|
-
|
59
|
-
|
60
|
-
|
81
|
+
GeminiCraft.configure do |config|
|
82
|
+
# Authentication
|
83
|
+
config.api_key = 'your-gemini-api-key'
|
84
|
+
|
85
|
+
# Model Configuration
|
86
|
+
config.model = 'gemini-2.0-flash'
|
87
|
+
config.api_base_url = 'https://generativelanguage.googleapis.com/v1beta'
|
88
|
+
|
89
|
+
# Performance & Reliability
|
90
|
+
config.timeout = 45
|
91
|
+
config.max_retries = 5
|
92
|
+
config.connection_pool_size = 10
|
93
|
+
config.keep_alive_timeout = 60
|
94
|
+
|
95
|
+
# Caching
|
96
|
+
config.cache_enabled = true
|
97
|
+
config.cache_ttl = 3600 # 1 hour
|
98
|
+
|
99
|
+
# Logging (Rails integration)
|
100
|
+
config.logger = Rails.logger
|
101
|
+
config.log_level = :info
|
102
|
+
|
103
|
+
# Features
|
104
|
+
config.streaming_enabled = true
|
105
|
+
end
|
106
|
+
```
|
107
|
+
|
108
|
+
### Environment Variables
|
109
|
+
|
110
|
+
```bash
|
111
|
+
# Set your API key
|
112
|
+
export GEMINI_API_KEY="your-api-key-here"
|
61
113
|
```
|
62
114
|
|
63
|
-
|
115
|
+
## 🚀 Usage Examples
|
64
116
|
|
65
|
-
|
117
|
+
### Basic Content Generation
|
66
118
|
|
67
119
|
```ruby
|
120
|
+
# Simple text generation
|
121
|
+
response = GeminiCraft.generate_content("Explain quantum computing in simple terms")
|
122
|
+
puts response
|
123
|
+
|
124
|
+
# With system instruction
|
125
|
+
system_instruction = "You are a helpful coding assistant. Be concise and practical."
|
126
|
+
response = GeminiCraft.generate_content(
|
127
|
+
"How do I sort an array in Ruby?",
|
128
|
+
system_instruction
|
129
|
+
)
|
130
|
+
puts response
|
131
|
+
|
132
|
+
# With custom options
|
68
133
|
options = {
|
69
|
-
temperature: 0.7,
|
70
|
-
topK: 40,
|
71
|
-
topP: 0.95,
|
72
|
-
maxOutputTokens: 1024
|
134
|
+
temperature: 0.7, # Creativity level (0.0 - 1.0)
|
135
|
+
topK: 40, # Consider top K tokens
|
136
|
+
topP: 0.95, # Nucleus sampling
|
137
|
+
maxOutputTokens: 1024 # Maximum response length
|
73
138
|
}
|
74
139
|
|
75
140
|
response = GeminiCraft.generate_content(
|
76
|
-
"
|
77
|
-
"You are a
|
141
|
+
"Write a creative story about AI",
|
142
|
+
"You are a creative writer",
|
78
143
|
options
|
79
144
|
)
|
80
|
-
|
81
145
|
puts response
|
82
146
|
```
|
83
147
|
|
84
|
-
|
148
|
+
### 🌊 Streaming Content
|
149
|
+
|
150
|
+
Perfect for real-time applications like chatbots or live content generation:
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
# Method 1: Using stream_content
|
154
|
+
puts "Generating story (streaming):"
|
155
|
+
stream = GeminiCraft.stream_content("Tell me an adventure story")
|
156
|
+
|
157
|
+
stream.each do |chunk|
|
158
|
+
print chunk
|
159
|
+
$stdout.flush
|
160
|
+
sleep(0.02) # Optional: Add slight delay for visual effect
|
161
|
+
end
|
162
|
+
puts "\n"
|
163
|
+
|
164
|
+
# Method 2: Using generate_content with stream option
|
165
|
+
GeminiCraft.generate_content(
|
166
|
+
"Explain machine learning",
|
167
|
+
stream: true
|
168
|
+
).each do |chunk|
|
169
|
+
print chunk
|
170
|
+
$stdout.flush
|
171
|
+
end
|
172
|
+
|
173
|
+
# Method 3: Collect all chunks
|
174
|
+
chunks = []
|
175
|
+
GeminiCraft.stream_content("Write a poem").each { |chunk| chunks << chunk }
|
176
|
+
full_response = chunks.join
|
177
|
+
puts full_response
|
178
|
+
```
|
179
|
+
|
180
|
+
### 🔧 Function Calling
|
181
|
+
|
182
|
+
Enable AI to call your Ruby functions/APIs:
|
183
|
+
|
184
|
+
```ruby
|
185
|
+
# Define available functions
|
186
|
+
functions = [
|
187
|
+
{
|
188
|
+
name: "get_current_weather",
|
189
|
+
description: "Get the current weather in a given location",
|
190
|
+
parameters: {
|
191
|
+
type: "object",
|
192
|
+
properties: {
|
193
|
+
location: {
|
194
|
+
type: "string",
|
195
|
+
description: "The city and state, e.g. San Francisco, CA"
|
196
|
+
},
|
197
|
+
unit: {
|
198
|
+
type: "string",
|
199
|
+
enum: ["celsius", "fahrenheit"],
|
200
|
+
description: "Temperature unit"
|
201
|
+
}
|
202
|
+
},
|
203
|
+
required: ["location"]
|
204
|
+
}
|
205
|
+
},
|
206
|
+
{
|
207
|
+
name: "calculate_tip",
|
208
|
+
description: "Calculate tip amount for a bill",
|
209
|
+
parameters: {
|
210
|
+
type: "object",
|
211
|
+
properties: {
|
212
|
+
bill_amount: {
|
213
|
+
type: "number",
|
214
|
+
description: "The total bill amount"
|
215
|
+
},
|
216
|
+
tip_percentage: {
|
217
|
+
type: "number",
|
218
|
+
description: "Tip percentage (default: 18)"
|
219
|
+
}
|
220
|
+
},
|
221
|
+
required: ["bill_amount"]
|
222
|
+
}
|
223
|
+
}
|
224
|
+
]
|
225
|
+
|
226
|
+
# Generate content with function calling
|
227
|
+
result = GeminiCraft.generate_with_functions(
|
228
|
+
"What's the weather like in Tokyo? Also calculate 18% tip for a $50 bill.",
|
229
|
+
functions,
|
230
|
+
"You are a helpful assistant that can check weather and calculate tips."
|
231
|
+
)
|
232
|
+
|
233
|
+
puts "AI Response: #{result[:content]}"
|
234
|
+
|
235
|
+
# Handle function calls
|
236
|
+
result[:function_calls].each do |call|
|
237
|
+
case call[:name]
|
238
|
+
when "get_current_weather"
|
239
|
+
location = call[:args]["location"]
|
240
|
+
unit = call[:args]["unit"] || "celsius"
|
241
|
+
# Call your weather API here
|
242
|
+
puts "🌤️ Would call weather API for #{location} in #{unit}"
|
243
|
+
|
244
|
+
when "calculate_tip"
|
245
|
+
bill = call[:args]["bill_amount"]
|
246
|
+
tip_pct = call[:args]["tip_percentage"] || 18
|
247
|
+
tip = (bill * tip_pct / 100).round(2)
|
248
|
+
puts "💰 Tip calculation: $#{bill} * #{tip_pct}% = $#{tip}"
|
249
|
+
end
|
250
|
+
end
|
251
|
+
```
|
252
|
+
|
253
|
+
### 🔄 Using the Client Directly
|
254
|
+
|
255
|
+
For more control over the client instance:
|
85
256
|
|
86
257
|
```ruby
|
87
258
|
client = GeminiCraft.client
|
88
|
-
|
259
|
+
|
260
|
+
# Standard generation
|
261
|
+
response = client.generate_content("Hello, how are you?")
|
89
262
|
puts response
|
263
|
+
|
264
|
+
# With system instruction and options
|
265
|
+
response = client.generate_content(
|
266
|
+
"Explain Ruby blocks",
|
267
|
+
"You are a Ruby expert who teaches with examples",
|
268
|
+
{ temperature: 0.3, maxOutputTokens: 500 }
|
269
|
+
)
|
270
|
+
puts response
|
271
|
+
|
272
|
+
# Function calling with client
|
273
|
+
result = client.generate_with_functions(
|
274
|
+
"What's 15% tip on $80?",
|
275
|
+
[tip_function],
|
276
|
+
"You are a helpful calculator"
|
277
|
+
)
|
278
|
+
```
|
279
|
+
|
280
|
+
### 📊 Cache Management
|
281
|
+
|
282
|
+
Intelligent caching for improved performance:
|
283
|
+
|
284
|
+
```ruby
|
285
|
+
# Enable caching in configuration
|
286
|
+
GeminiCraft.configure do |config|
|
287
|
+
config.cache_enabled = true
|
288
|
+
config.cache_ttl = 1800 # 30 minutes
|
289
|
+
end
|
290
|
+
|
291
|
+
# Same requests will be cached
|
292
|
+
response1 = GeminiCraft.generate_content("What is Ruby?")
|
293
|
+
response2 = GeminiCraft.generate_content("What is Ruby?") # Served from cache
|
294
|
+
|
295
|
+
# Check cache statistics
|
296
|
+
stats = GeminiCraft.cache_stats
|
297
|
+
puts "Cache entries: #{stats[:size]}"
|
298
|
+
puts "Oldest entry: #{Time.at(stats[:oldest_entry]) if stats[:oldest_entry]}"
|
299
|
+
puts "Newest entry: #{Time.at(stats[:newest_entry]) if stats[:newest_entry]}"
|
300
|
+
|
301
|
+
# Clear cache manually
|
302
|
+
GeminiCraft.clear_cache
|
303
|
+
puts "Cache cleared!"
|
304
|
+
```
|
305
|
+
|
306
|
+
### 🛡️ Error Handling
|
307
|
+
|
308
|
+
Comprehensive error handling with specific error types:
|
309
|
+
|
310
|
+
```ruby
|
311
|
+
begin
|
312
|
+
response = GeminiCraft.generate_content("Hello there!")
|
313
|
+
puts response
|
314
|
+
rescue GeminiCraft::AuthenticationError => e
|
315
|
+
puts "❌ Authentication failed: #{e.message}"
|
316
|
+
puts "Please check your API key"
|
317
|
+
rescue GeminiCraft::RateLimitError => e
|
318
|
+
puts "⏰ Rate limit exceeded: #{e.message}"
|
319
|
+
puts "Please wait before making more requests"
|
320
|
+
rescue GeminiCraft::TimeoutError => e
|
321
|
+
puts "⏱️ Request timed out: #{e.message}"
|
322
|
+
puts "Try increasing the timeout or check your connection"
|
323
|
+
rescue GeminiCraft::ConnectionError => e
|
324
|
+
puts "🌐 Connection failed: #{e.message}"
|
325
|
+
puts "Please check your internet connection"
|
326
|
+
rescue GeminiCraft::ServerError => e
|
327
|
+
puts "🔧 Server error: #{e.message}"
|
328
|
+
puts "The API service may be temporarily unavailable"
|
329
|
+
rescue GeminiCraft::APIError => e
|
330
|
+
puts "🚨 API error: #{e.message}"
|
331
|
+
rescue StandardError => e
|
332
|
+
puts "💥 Unexpected error: #{e.message}"
|
333
|
+
end
|
334
|
+
```
|
335
|
+
|
336
|
+
### 🔧 Rails Integration
|
337
|
+
|
338
|
+
Perfect integration with Ruby on Rails applications:
|
339
|
+
|
340
|
+
```ruby
|
341
|
+
# config/initializers/gemini_craft.rb
|
342
|
+
GeminiCraft.configure do |config|
|
343
|
+
config.api_key = Rails.application.credentials.gemini_api_key
|
344
|
+
config.logger = Rails.logger
|
345
|
+
config.log_level = Rails.env.production? ? :warn : :info
|
346
|
+
config.cache_enabled = Rails.env.production?
|
347
|
+
config.cache_ttl = 30.minutes
|
348
|
+
config.timeout = 45
|
349
|
+
config.max_retries = 5
|
350
|
+
end
|
351
|
+
|
352
|
+
# In your controllers
|
353
|
+
class ContentController < ApplicationController
|
354
|
+
def generate
|
355
|
+
begin
|
356
|
+
@content = GeminiCraft.generate_content(
|
357
|
+
params[:prompt],
|
358
|
+
"You are a helpful assistant for #{current_user.name}",
|
359
|
+
{ temperature: 0.7 }
|
360
|
+
)
|
361
|
+
render json: { content: @content }
|
362
|
+
rescue GeminiCraft::RateLimitError
|
363
|
+
render json: { error: "Rate limit exceeded" }, status: 429
|
364
|
+
rescue GeminiCraft::APIError => e
|
365
|
+
Rails.logger.error "Gemini API error: #{e.message}"
|
366
|
+
render json: { error: "Content generation failed" }, status: 500
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
def stream_generate
|
371
|
+
response.headers['Content-Type'] = 'text/event-stream'
|
372
|
+
response.headers['Cache-Control'] = 'no-cache'
|
373
|
+
|
374
|
+
begin
|
375
|
+
GeminiCraft.stream_content(params[:prompt]).each do |chunk|
|
376
|
+
response.stream.write("data: #{chunk}\n\n")
|
377
|
+
end
|
378
|
+
ensure
|
379
|
+
response.stream.close
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
# In your models
|
385
|
+
class Article < ApplicationRecord
|
386
|
+
def generate_summary
|
387
|
+
return if content.blank?
|
388
|
+
|
389
|
+
self.summary = GeminiCraft.generate_content(
|
390
|
+
"Summarize this article in 2-3 sentences: #{content}",
|
391
|
+
"You are a professional editor creating concise summaries"
|
392
|
+
)
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
# Background jobs
|
397
|
+
class ContentGenerationJob < ApplicationJob
|
398
|
+
def perform(user_id, prompt)
|
399
|
+
user = User.find(user_id)
|
400
|
+
|
401
|
+
content = GeminiCraft.generate_content(
|
402
|
+
prompt,
|
403
|
+
"Generate content for #{user.name}",
|
404
|
+
{ temperature: 0.8, maxOutputTokens: 2000 }
|
405
|
+
)
|
406
|
+
|
407
|
+
user.generated_contents.create!(prompt: prompt, content: content)
|
408
|
+
rescue GeminiCraft::APIError => e
|
409
|
+
Rails.logger.error "Content generation failed for user #{user_id}: #{e.message}"
|
410
|
+
# Handle error (retry, notify user, etc.)
|
411
|
+
end
|
412
|
+
end
|
413
|
+
```
|
414
|
+
|
415
|
+
## ⚙️ Configuration Options
|
416
|
+
|
417
|
+
| Option | Default | Description |
|
418
|
+
|--------|---------|-------------|
|
419
|
+
| `api_key` | `ENV['GEMINI_API_KEY']` | Your Gemini API key |
|
420
|
+
| `model` | `'gemini-2.0-flash'` | The Gemini model to use |
|
421
|
+
| `api_base_url` | `'https://generativelanguage.googleapis.com/v1beta'` | Base URL for the API |
|
422
|
+
| `timeout` | `30` | Request timeout in seconds |
|
423
|
+
| `cache_enabled` | `false` | Enable response caching |
|
424
|
+
| `cache_ttl` | `3600` | Cache time-to-live in seconds |
|
425
|
+
| `max_retries` | `3` | Number of retry attempts |
|
426
|
+
| `logger` | `nil` | Logger instance for debugging |
|
427
|
+
| `log_level` | `:info` | Logging level (`:debug`, `:info`, `:warn`, `:error`, `:fatal`) |
|
428
|
+
| `streaming_enabled` | `false` | Enable streaming support |
|
429
|
+
| `connection_pool_size` | `5` | HTTP connection pool size |
|
430
|
+
| `keep_alive_timeout` | `30` | Keep-alive timeout for connections |
|
431
|
+
|
432
|
+
## 🏗️ Available Models
|
433
|
+
|
434
|
+
| Model | Description | Best For |
|
435
|
+
|-------|-------------|----------|
|
436
|
+
| `gemini-2.0-flash` | Fast, efficient model | General content generation, chatbots |
|
437
|
+
| `gemini-1.5-pro` | Most capable model | Complex reasoning, analysis |
|
438
|
+
| `gemini-1.5-flash` | Balanced speed and capability | Most applications |
|
439
|
+
|
440
|
+
## 🚨 Error Types
|
441
|
+
|
442
|
+
The gem provides specific error types for better error handling:
|
443
|
+
|
444
|
+
- `GeminiCraft::Error` - Base error class
|
445
|
+
- `GeminiCraft::APIError` - General API errors
|
446
|
+
- `GeminiCraft::AuthenticationError` - Invalid API key or authentication failures
|
447
|
+
- `GeminiCraft::AuthorizationError` - Access forbidden or permission issues
|
448
|
+
- `GeminiCraft::NotFoundError` - Model or endpoint not found
|
449
|
+
- `GeminiCraft::RateLimitError` - Rate limit exceeded
|
450
|
+
- `GeminiCraft::ClientError` - Client-side errors (4xx)
|
451
|
+
- `GeminiCraft::ServerError` - Server-side errors (5xx)
|
452
|
+
- `GeminiCraft::TimeoutError` - Request timeouts
|
453
|
+
- `GeminiCraft::ConnectionError` - Connection failures
|
454
|
+
- `GeminiCraft::StreamingError` - Streaming-specific errors
|
455
|
+
- `GeminiCraft::ResponseError` - Response parsing errors
|
456
|
+
- `GeminiCraft::ConfigurationError` - Configuration errors
|
457
|
+
|
458
|
+
## 🎯 Best Practices
|
459
|
+
|
460
|
+
### 1. API Key Security
|
461
|
+
```ruby
|
462
|
+
# ✅ Good: Use environment variables
|
463
|
+
config.api_key = ENV['GEMINI_API_KEY']
|
464
|
+
|
465
|
+
# ✅ Good: Use Rails credentials
|
466
|
+
config.api_key = Rails.application.credentials.gemini_api_key
|
467
|
+
|
468
|
+
# ❌ Bad: Hard-code in source
|
469
|
+
config.api_key = "your-actual-api-key"
|
470
|
+
```
|
471
|
+
|
472
|
+
### 2. Error Handling
|
473
|
+
```ruby
|
474
|
+
# ✅ Good: Specific error handling
|
475
|
+
rescue GeminiCraft::RateLimitError
|
476
|
+
# Implement backoff strategy
|
477
|
+
rescue GeminiCraft::AuthenticationError
|
478
|
+
# Log and alert about API key issues
|
479
|
+
|
480
|
+
# ❌ Bad: Generic error handling
|
481
|
+
rescue StandardError
|
482
|
+
# Too broad, might hide important errors
|
483
|
+
```
|
484
|
+
|
485
|
+
### 3. Caching Strategy
|
486
|
+
```ruby
|
487
|
+
# ✅ Good: Enable caching for production
|
488
|
+
GeminiCraft.configure do |config|
|
489
|
+
config.cache_enabled = Rails.env.production?
|
490
|
+
config.cache_ttl = 1.hour
|
491
|
+
end
|
492
|
+
|
493
|
+
# ✅ Good: Cache expensive operations
|
494
|
+
def generate_analysis(data)
|
495
|
+
cache_key = "analysis_#{Digest::SHA256.hexdigest(data)}"
|
496
|
+
Rails.cache.fetch(cache_key, expires_in: 30.minutes) do
|
497
|
+
GeminiCraft.generate_content("Analyze: #{data}")
|
498
|
+
end
|
499
|
+
end
|
500
|
+
```
|
501
|
+
|
502
|
+
### 4. Streaming for Better UX
|
503
|
+
```ruby
|
504
|
+
# ✅ Good: Use streaming for long content
|
505
|
+
def stream_story
|
506
|
+
GeminiCraft.stream_content("Write a long story").each do |chunk|
|
507
|
+
ActionCable.server.broadcast("story_channel", { chunk: chunk })
|
508
|
+
end
|
509
|
+
end
|
510
|
+
```
|
511
|
+
|
512
|
+
### 5. Function Calling
|
513
|
+
```ruby
|
514
|
+
# ✅ Good: Validate function parameters
|
515
|
+
def execute_function_call(call)
|
516
|
+
case call[:name]
|
517
|
+
when "get_weather"
|
518
|
+
location = call[:args]["location"]
|
519
|
+
return "Location required" if location.blank?
|
520
|
+
|
521
|
+
WeatherService.new.get_weather(location)
|
522
|
+
end
|
523
|
+
end
|
524
|
+
```
|
525
|
+
|
526
|
+
## 🧪 Testing
|
527
|
+
|
528
|
+
### RSpec Integration
|
529
|
+
|
530
|
+
```ruby
|
531
|
+
# spec/support/gemini_craft.rb
|
532
|
+
RSpec.configure do |config|
|
533
|
+
config.before(:suite) do
|
534
|
+
GeminiCraft.configure do |config|
|
535
|
+
config.api_key = "test-api-key"
|
536
|
+
config.cache_enabled = false
|
537
|
+
config.logger = Logger.new(IO::NULL)
|
538
|
+
end
|
539
|
+
end
|
540
|
+
end
|
541
|
+
|
542
|
+
# In your specs
|
543
|
+
RSpec.describe ContentGenerator do
|
544
|
+
before do
|
545
|
+
allow(GeminiCraft).to receive(:generate_content)
|
546
|
+
.and_return("Generated content")
|
547
|
+
end
|
548
|
+
|
549
|
+
it "generates content" do
|
550
|
+
result = subject.generate_summary("test input")
|
551
|
+
expect(result).to eq("Generated content")
|
552
|
+
end
|
553
|
+
end
|
554
|
+
```
|
555
|
+
|
556
|
+
### WebMock for Testing
|
557
|
+
|
558
|
+
```ruby
|
559
|
+
# Gemfile (test group)
|
560
|
+
gem 'webmock'
|
561
|
+
|
562
|
+
# In your test
|
563
|
+
require 'webmock/rspec'
|
564
|
+
|
565
|
+
RSpec.describe "Gemini integration" do
|
566
|
+
before do
|
567
|
+
stub_request(:post, /generativelanguage\.googleapis\.com/)
|
568
|
+
.to_return(
|
569
|
+
status: 200,
|
570
|
+
body: {
|
571
|
+
candidates: [{
|
572
|
+
content: {
|
573
|
+
parts: [{ text: "Test response" }]
|
574
|
+
}
|
575
|
+
}]
|
576
|
+
}.to_json
|
577
|
+
)
|
578
|
+
end
|
579
|
+
|
580
|
+
it "generates content" do
|
581
|
+
result = GeminiCraft.generate_content("test")
|
582
|
+
expect(result).to eq("Test response")
|
583
|
+
end
|
584
|
+
end
|
585
|
+
```
|
586
|
+
|
587
|
+
## 🔄 Migration from v0.1.x
|
588
|
+
|
589
|
+
The v0.2.0 release maintains backward compatibility. However, to use new features:
|
590
|
+
|
591
|
+
```ruby
|
592
|
+
# Old way (still works)
|
593
|
+
response = GeminiCraft.generate_content("Hello")
|
594
|
+
|
595
|
+
# New way with streaming
|
596
|
+
stream = GeminiCraft.stream_content("Hello")
|
597
|
+
|
598
|
+
# New way with function calling
|
599
|
+
result = GeminiCraft.generate_with_functions("Hello", functions)
|
600
|
+
|
601
|
+
# Enhanced error handling
|
602
|
+
rescue GeminiCraft::RateLimitError # New specific error type
|
603
|
+
```
|
604
|
+
|
605
|
+
## 🚀 Performance Tips
|
606
|
+
|
607
|
+
1. **Enable Caching**: For production applications to reduce API calls
|
608
|
+
2. **Use Streaming**: For better user experience with long responses
|
609
|
+
3. **Implement Proper Retry Logic**: Handle transient failures gracefully
|
610
|
+
4. **Monitor Rate Limits**: Implement backoff strategies for sustained usage
|
611
|
+
5. **Optimize Prompts**: Shorter, clearer prompts often work better
|
612
|
+
6. **Batch Operations**: Group related requests when possible
|
613
|
+
|
614
|
+
## 📋 Troubleshooting
|
615
|
+
|
616
|
+
### Common Issues
|
617
|
+
|
618
|
+
**Authentication Error**
|
619
|
+
```ruby
|
620
|
+
# Check your API key
|
621
|
+
puts ENV['GEMINI_API_KEY'] # Should not be nil
|
622
|
+
```
|
623
|
+
|
624
|
+
**Rate Limiting**
|
625
|
+
```ruby
|
626
|
+
# Implement exponential backoff
|
627
|
+
rescue GeminiCraft::RateLimitError
|
628
|
+
sleep(2 ** retry_count)
|
629
|
+
retry if (retry_count += 1) < 3
|
630
|
+
```
|
631
|
+
|
632
|
+
**Timeout Issues**
|
633
|
+
```ruby
|
634
|
+
# Increase timeout for complex requests
|
635
|
+
GeminiCraft.configure { |c| c.timeout = 120 }
|
636
|
+
```
|
637
|
+
|
638
|
+
**Caching Problems**
|
639
|
+
```ruby
|
640
|
+
# Clear cache if responses seem stale
|
641
|
+
GeminiCraft.clear_cache
|
642
|
+
```
|
643
|
+
|
644
|
+
## 🤝 Contributing
|
645
|
+
|
646
|
+
We welcome contributions! Here's how to get started:
|
647
|
+
|
648
|
+
1. Fork the repository
|
649
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
650
|
+
3. Make your changes
|
651
|
+
4. Add tests for your changes
|
652
|
+
5. Ensure all tests pass (`bundle exec rake spec`)
|
653
|
+
6. Ensure code style is correct (`bundle exec rake rubocop`)
|
654
|
+
7. Commit your changes (`git commit -am 'Add amazing feature'`)
|
655
|
+
8. Push to the branch (`git push origin feature/amazing-feature`)
|
656
|
+
9. Create a Pull Request
|
657
|
+
|
658
|
+
### Development Setup
|
659
|
+
|
660
|
+
```bash
|
661
|
+
git clone https://github.com/shobhits7/gemini_craft.git
|
662
|
+
cd gemini_craft
|
663
|
+
bin/setup
|
664
|
+
bundle exec rake spec
|
90
665
|
```
|
91
666
|
|
92
|
-
|
667
|
+
### Running Tests
|
668
|
+
|
669
|
+
```bash
|
670
|
+
# Run all tests
|
671
|
+
bundle exec rake spec
|
93
672
|
|
94
|
-
|
673
|
+
# Run specific test file
|
674
|
+
bundle exec rspec spec/gemini_craft/client_spec.rb
|
675
|
+
|
676
|
+
# Run with coverage
|
677
|
+
COVERAGE=true bundle exec rake spec
|
678
|
+
```
|
95
679
|
|
96
|
-
|
680
|
+
### Code Style
|
97
681
|
|
98
|
-
|
682
|
+
```bash
|
683
|
+
# Check code style
|
684
|
+
bundle exec rake rubocop
|
99
685
|
|
100
|
-
|
686
|
+
# Auto-fix issues
|
687
|
+
bundle exec rubocop -a
|
688
|
+
```
|
101
689
|
|
102
|
-
## License
|
690
|
+
## 📄 License
|
103
691
|
|
104
692
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
105
693
|
|
106
|
-
## Code of Conduct
|
694
|
+
## 🏆 Code of Conduct
|
107
695
|
|
108
696
|
Everyone interacting in the GeminiCraft project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/shobhits7/gemini_craft/blob/main/CODE_OF_CONDUCT.md).
|
697
|
+
|
698
|
+
## 🔗 Links
|
699
|
+
|
700
|
+
- [GitHub Repository](https://github.com/shobhits7/gemini_craft)
|
701
|
+
- [RubyGems Page](https://rubygems.org/gems/gemini_craft)
|
702
|
+
- [Documentation](https://rubydoc.info/gems/gemini_craft)
|
703
|
+
- [Issues & Bug Reports](https://github.com/shobhits7/gemini_craft/issues)
|
704
|
+
- [Google AI Studio](https://makersuite.google.com/app/apikey) (Get API Key)
|
705
|
+
- [Gemini API Documentation](https://ai.google.dev/docs)
|
706
|
+
|
707
|
+
## 📈 Changelog
|
708
|
+
|
709
|
+
See [CHANGELOG.md](CHANGELOG.md) for a detailed history of changes.
|
710
|
+
|
711
|
+
## ❤️ Support
|
712
|
+
|
713
|
+
If you find this gem helpful, please:
|
714
|
+
- ⭐ Star the repository
|
715
|
+
- 🐛 Report bugs
|
716
|
+
- 💡 Suggest new features
|
717
|
+
- 📝 Contribute to documentation
|
718
|
+
- 📢 Share with others
|
719
|
+
|
720
|
+
---
|
721
|
+
|
722
|
+
Made with ❤️ by [Shobhit Jain](https://github.com/shobhits7) and [contributors](https://github.com/shobhits7/gemini_craft/contributors)
|