geminai 0.1.1 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fd8310e9cec4ec0a99b4fd40b509475f4f4f444d60bc6ee25864ebbca6361192
4
- data.tar.gz: 9854c80f0e3e319ba6cbfd8c5cbdc14e4ae4b0a80609ada5e99423fdc2c1c75d
3
+ metadata.gz: 182008113410d8953e5d9dbb32d0b3d31e400f0b64dc6de753bd2b0a0ecd0e3b
4
+ data.tar.gz: 5e4f6e4c304a109ec19e1bb00e98d7c60cd27b3f9c36d88fd51721aef9f424a2
5
5
  SHA512:
6
- metadata.gz: 2c9cbf33c85d33bff8b5104a53817e77429c62ab9d0e873c1c8cf2a5a45d212441f6d6626efbb3814641a16bacd67e8a3e2f3cae2713f666c20f178ed8d746be
7
- data.tar.gz: 514038195a974de0cc62d953540f3ea370c5d03ab9c270a921bbed232b9e299ce63a43cdd1481b76f1504e286108c2aa5939ba077620a8e1fd4ab8f5e8b7ef1c
6
+ metadata.gz: f1c57d71925d784ff071a79f207b2f5fff3615774929b39a1dced79408c05dbb2bebbc561edc1a6b7b725d394bd9082c0590184ffe131b118d8d6c8edd02143d
7
+ data.tar.gz: bb3cf7288bfba9404ea343f75f931ba31b75154a17db76d435703d09acc989eaf7b586d39a8e22f7c5458ac2ebbcde3ad9144701e5a2074100366849b6001e29
data/README.md CHANGED
@@ -2,12 +2,6 @@
2
2
 
3
3
  A gem for gemini's interactions api
4
4
 
5
- * **Built-in Tools**: Native search grounding (`google_search`), mapping citations, and suggestions.
6
- * **Image Generation**: High-fidelity native image generation (`gemini-3.1-flash-image`) with direct config like `aspect_ratio` and `image_size`.
7
- * **Stateful Conversations**: Seamless multi-turn conversations managed server-side via `previous_interaction_id`.
8
- * **Stateless Conversations**: Client-managed conversation paths using `store: false`.
9
- * **Zero Dependencies**: Pure Ruby standard library (`net/http` and `json`)
10
-
11
5
  ## Install
12
6
 
13
7
  ```ruby
@@ -65,7 +59,7 @@ Geminai includes a helper method `generate_image` which calls the Interactions A
65
59
  ```ruby
66
60
  require 'base64'
67
61
 
68
- interaction = client.generate_image(
62
+ interaction = client.interact(
69
63
  "An image of a pelican riding a bicycle",
70
64
  model: 'gemini-3.1-flash-image',
71
65
  aspect_ratio: '1:1',
@@ -74,7 +68,7 @@ interaction = client.generate_image(
74
68
  )
75
69
 
76
70
  # Extract and save generated images
77
- interaction.output_images.each_with_index do |img, index|
71
+ interaction.output_files.each_with_index do |img, index|
78
72
  File.binwrite("pelican#{index}.png", Base64.decode64(img[:data]))
79
73
  puts "Saved pelican_#{index}.png"
80
74
  end
@@ -104,7 +98,29 @@ puts interaction_2.output_text
104
98
  # => "Your favorite jihad is a butlerian jihad."
105
99
  ```
106
100
 
107
- ---
101
+ ### 4. Video generation
102
+
103
+ ```ruby
104
+ # Generate a video
105
+ interaction = client.generate_video(
106
+ "A beautiful sunset over a calm ocean.",
107
+ model: "gemini-omni-flash-preview"
108
+ )
109
+
110
+ if interaction.output_video
111
+ # Access base64 data
112
+ video_data = interaction.output_video[:data]
113
+ # Or access the URI if delivery: "uri" was used
114
+ video_uri = interaction.output_video[:uri]
115
+ end
116
+
117
+ # Stateful video editing
118
+ edit_interaction = client.interact(
119
+ model: "gemini-omni-flash-preview",
120
+ input: "Make the sun more vibrant and red.",
121
+ previous_interaction_id: interaction.id
122
+ )
123
+ ```
108
124
 
109
125
  ## Running Tests
110
126
 
@@ -23,23 +23,36 @@ module Geminai
23
23
  input: input
24
24
  }
25
25
 
26
- # Forward all recognized interactions API request parameters
27
- [
28
- :system_instruction,
29
- :generation_config,
30
- :response_format,
31
- :tools,
32
- :previous_interaction_id,
33
- :stream,
34
- :store
35
- ].each do |opt|
36
- body[opt] = options[opt] if options.key?(opt)
26
+ # Infer output shortcut from model name if not explicitly provided
27
+ output = options.delete(:output)
28
+ unless output
29
+ if model.include?("-tts-") || model.include?("-audio")
30
+ output = :audio
31
+ elsif model.include?("-image")
32
+ output = :image
33
+ elsif model.include?("-video") || model.include?("-generate")
34
+ output = :video
35
+ end
37
36
  end
38
37
 
39
- # Handle any extra keys passed in options as well to be fully future-proof
38
+ # Handle output shortcut
39
+ if output
40
+ body[:response_format] = {type: output.to_s}
41
+ body[:response_format][:aspect_ratio] = options.delete(:aspect_ratio) if options.key?(:aspect_ratio)
42
+ body[:response_format][:image_size] = options.delete(:image_size) if options.key?(:image_size)
43
+ end
44
+
45
+ if (voice = options.delete(:voice))
46
+ body[:generation_config] = {speech_config: [{voice: voice}]}
47
+ end
48
+
49
+ # Merge other options, allowing them to override shortcuts if explicitly provided
40
50
  options.each do |k, v|
41
- next if body.key?(k)
42
- body[k] = v
51
+ if body[k].is_a?(Hash) && v.is_a?(Hash)
52
+ body[k] = body[k].merge(v)
53
+ else
54
+ body[k] = v
55
+ end
43
56
  end
44
57
 
45
58
  http = Net::HTTP.new(uri.host, uri.port)
@@ -65,20 +78,6 @@ module Geminai
65
78
  data = JSON.parse(response.body, symbolize_names: true)
66
79
  Interaction.new(data)
67
80
  end
68
-
69
- # Helper method for image generation using response_format
70
- def generate_image(prompt, model:, aspect_ratio: "1:1", image_size: "1K", **options)
71
- interact(
72
- model: model,
73
- input: prompt,
74
- response_format: {
75
- type: "image",
76
- aspect_ratio: aspect_ratio,
77
- image_size: image_size
78
- },
79
- **options
80
- )
81
- end
82
81
  end
83
82
 
84
83
  class ApiError < StandardError
@@ -26,29 +26,67 @@ module Geminai
26
26
  text_parts.join("")
27
27
  end
28
28
 
29
- def output_images
30
- images = []
29
+ def files
30
+ files = []
31
31
  @steps.each do |step|
32
32
  next unless step.model_output?
33
33
  (step.content || []).each do |part|
34
- if part[:type] == "image"
35
- images <<
36
- {
37
- data: part[:data],
38
- mime_type: part[:mime_type]
39
- }
40
- elsif part[:image]
41
- # Handle other possible image shapes in responses if applicable
42
- images <<
43
- {
44
- data: part[:image][:data] || part[:image][:image_bytes],
45
- mime_type: part[:image][:mime_type]
46
- }
47
- end
34
+ file_data = extract_file_data(part)
35
+ files << file_data if file_data
36
+ end
37
+ end
38
+
39
+ # Also include top-level outputs (like output_audio) if present in raw data
40
+ @raw_data.each do |key, value|
41
+ if key.to_s.start_with?("output_") && value.is_a?(Hash) && (value[:data] || value[:uri])
42
+ files << value.merge(type: key.to_s.sub("output_", ""))
48
43
  end
49
44
  end
50
45
 
51
- images
46
+ files
47
+ end
48
+
49
+ alias_method :output_files, :files
50
+
51
+ def base64(type = nil)
52
+ file = if type
53
+ files.find { |f| f[:type] == type.to_s && f[:data] }
54
+ else
55
+ files.find { |f| f[:data] }
56
+ end
57
+
58
+ file ? file[:data] : nil
59
+ end
60
+
61
+ alias_method :base64_file, :base64
62
+
63
+ def uri(type = nil)
64
+ file = if type
65
+ files.find { |f| f[:type] == type.to_s && f[:uri] }
66
+ else
67
+ files.find { |f| f[:uri] }
68
+ end
69
+
70
+ file ? file[:uri] : nil
71
+ end
72
+
73
+ alias_method :uri_file, :uri
74
+
75
+ # Deprecated specific helpers kept for compatibility but powered by generic methods
76
+ def output_images
77
+ files.select { |f| f[:type] == "image" }
78
+ end
79
+
80
+ def output_videos
81
+ files.select { |f| f[:type] == "video" }
82
+ end
83
+
84
+ def output_video
85
+ output_videos.first
86
+ end
87
+
88
+ def output_audio
89
+ files.select { |f| f[:type] == "audio" }.first
52
90
  end
53
91
 
54
92
  def grounding_metadata
@@ -93,5 +131,34 @@ module Geminai
93
131
  search_suggestions: suggestions
94
132
  )
95
133
  end
134
+
135
+ private
136
+
137
+ def extract_file_data(part)
138
+ # Check part[:type]
139
+ if %w[image video audio file].include?(part[:type])
140
+ return {
141
+ type: part[:type],
142
+ data: part[:data],
143
+ uri: part[:uri],
144
+ mime_type: part[:mime_type]
145
+ }
146
+ end
147
+
148
+ # Check for keys like :image, :video, :audio
149
+ [:image, :video, :audio].each do |key|
150
+ if part[key]
151
+ data = part[key]
152
+ return {
153
+ type: key.to_s,
154
+ data: data[:data] || data[:image_bytes] || data[:video_bytes] || data[:audio_bytes],
155
+ uri: data[:uri],
156
+ mime_type: data[:mime_type]
157
+ }
158
+ end
159
+ end
160
+
161
+ nil
162
+ end
96
163
  end
97
164
  end
@@ -1,3 +1,3 @@
1
1
  module Geminai
2
- VERSION = "0.1.1"
2
+ VERSION = "1.0.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: geminai
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - swlkr