omniai-google 1.9.1 → 1.9.3
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/Gemfile +1 -0
- data/README.md +34 -0
- data/lib/omniai/google/chat/media_serializer.rb +33 -2
- data/lib/omniai/google/client.rb +26 -0
- data/lib/omniai/google/embed.rb +64 -0
- data/lib/omniai/google/upload/file.rb +63 -0
- data/lib/omniai/google/upload.rb +74 -0
- data/lib/omniai/google/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 80e08395bc3710a72cc59b7c110cc50b1ba4a1dc64e15c622fcacb39448c1265
|
4
|
+
data.tar.gz: cccb64b57c0430caf449ebb1de2620e597409de0179379ef0cb26588d41418a2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf8a4e78c06a9808930300c1aa05b45211ab0f733a79bddc22bd5ac3ca2bfff1a00d075ca596122295c82aeb909372d2a9c7a66bc27566386d529428209beda7
|
7
|
+
data.tar.gz: 7324a4d99c3ce3a890129eb5a3091459facbd0acf5818b7ff0624d168d2fee94613656db1fe1c1091f8f001c6c34cc34c66a835b69fb7d90191075bde455de5b
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -94,4 +94,38 @@ end
|
|
94
94
|
client.chat('Be poetic.', stream:)
|
95
95
|
```
|
96
96
|
|
97
|
+
### Upload
|
98
|
+
|
99
|
+
An upload is especially useful when processing audio / image / video / text files. To use:
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
CAT_URL = 'https://images.unsplash.com/photo-1472491235688-bdc81a63246e?fm=jpg'
|
103
|
+
DOG_URL = 'https://images.unsplash.com/photo-1517849845537-4d257902454a?fm=jpg'
|
104
|
+
|
105
|
+
begin
|
106
|
+
cat_upload = client.upload(CAT_URL)
|
107
|
+
dog_upload = client.upload(DOG_URL)
|
108
|
+
|
109
|
+
completion = client.chat(stream: $stdout) do |prompt|
|
110
|
+
prompt.user do |message|
|
111
|
+
message.text 'What are these photos of?'
|
112
|
+
message.url(cat_upload.uri, cat_upload.mime_type)
|
113
|
+
message.url(dog_upload.uri, dog_upload.mime_type)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
ensure
|
117
|
+
cat_upload.delete!
|
118
|
+
dog_upload.delete!
|
119
|
+
end
|
120
|
+
```
|
121
|
+
|
97
122
|
[Google API Reference `stream`](https://ai.google.dev/gemini-api/docs/api-overview#stream)
|
123
|
+
|
124
|
+
### Embed
|
125
|
+
|
126
|
+
Text can be converted into a vector embedding for similarity comparison usage via:
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
response = client.embed('The quick brown fox jumps over a lazy dog.')
|
130
|
+
response.embedding # [0.0, ...]
|
131
|
+
```
|
@@ -6,8 +6,21 @@ module OmniAI
|
|
6
6
|
# Overrides media serialize / deserialize.
|
7
7
|
module MediaSerializer
|
8
8
|
# @param media [OmniAI::Chat::Media]
|
9
|
-
#
|
10
|
-
|
9
|
+
#
|
10
|
+
# @return [hash]
|
11
|
+
def self.serialize_as_file_data(media)
|
12
|
+
{
|
13
|
+
fileData: {
|
14
|
+
mimeType: media.type,
|
15
|
+
fileUri: media.uri,
|
16
|
+
},
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param media [OmniAI::Chat::Media]
|
21
|
+
#
|
22
|
+
# @return [hash]
|
23
|
+
def self.serialize_as_inline_data(media)
|
11
24
|
{
|
12
25
|
inlineData: {
|
13
26
|
mimeType: media.type,
|
@@ -15,6 +28,24 @@ module OmniAI
|
|
15
28
|
},
|
16
29
|
}
|
17
30
|
end
|
31
|
+
|
32
|
+
# @param media [OmniAI::Chat::Media]
|
33
|
+
#
|
34
|
+
# @return [Hash]
|
35
|
+
def self.serialize(media, *)
|
36
|
+
if media.is_a?(OmniAI::Chat::URL) && use_file_data?(URI.parse(media.uri))
|
37
|
+
serialize_as_file_data(media)
|
38
|
+
else
|
39
|
+
serialize_as_inline_data(media)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# @param uri [URI]
|
44
|
+
#
|
45
|
+
# @return [Boolean]
|
46
|
+
def self.use_file_data?(uri)
|
47
|
+
uri.host.eql?('generativelanguage.googleapis.com') || uri.scheme.eql?('gs')
|
48
|
+
end
|
18
49
|
end
|
19
50
|
end
|
20
51
|
end
|
data/lib/omniai/google/client.rb
CHANGED
@@ -59,6 +59,32 @@ module OmniAI
|
|
59
59
|
def chat(messages = nil, model: Chat::DEFAULT_MODEL, temperature: nil, format: nil, stream: nil, tools: nil, &)
|
60
60
|
Chat.process!(messages, model:, temperature:, format:, stream:, tools:, client: self, &)
|
61
61
|
end
|
62
|
+
|
63
|
+
# @param io [File, String] required - a file or URL
|
64
|
+
#
|
65
|
+
# @raise [OmniAI::Google::Upload::FetchError]
|
66
|
+
#
|
67
|
+
# @return [OmniAI::Google::Upload::File]
|
68
|
+
def upload(io)
|
69
|
+
Upload.process!(client: self, io:)
|
70
|
+
end
|
71
|
+
|
72
|
+
# @raise [OmniAI::Error]
|
73
|
+
#
|
74
|
+
# @param input [String, Array<String>, Array<Integer>] required
|
75
|
+
# @param model [String] optional
|
76
|
+
def embed(input, model: Embed::DEFAULT_MODEL)
|
77
|
+
Embed.process!(input, model:, client: self)
|
78
|
+
end
|
79
|
+
|
80
|
+
# @return [String]
|
81
|
+
def path
|
82
|
+
if @project_id
|
83
|
+
"/#{@version}/projects/#{@project_id}/locations/#{@location}/publishers/google"
|
84
|
+
else
|
85
|
+
"/#{@version}"
|
86
|
+
end
|
87
|
+
end
|
62
88
|
end
|
63
89
|
end
|
64
90
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OmniAI
|
4
|
+
module Google
|
5
|
+
# An Google embed implementation.
|
6
|
+
#
|
7
|
+
# Usage:
|
8
|
+
#
|
9
|
+
# input = "..."
|
10
|
+
# response = OmniAI::Google::Embed.process!(input, client: client)
|
11
|
+
# response.embedding [0.0, ...]
|
12
|
+
class Embed < OmniAI::Embed
|
13
|
+
module Model
|
14
|
+
TEXT_EMBEDDING_004 = 'text-embedding-004'
|
15
|
+
TEXT_MULTILINGUAL_EMBEDDING_002 = 'text-multilingual-embedding-002'
|
16
|
+
EMBEDDING = TEXT_EMBEDDING_004
|
17
|
+
MULTILINGUAL_EMBEDDING = TEXT_MULTILINGUAL_EMBEDDING_002
|
18
|
+
end
|
19
|
+
|
20
|
+
DEFAULT_MODEL = Model::EMBEDDING
|
21
|
+
|
22
|
+
EMBEDDINGS_DESERIALIZER = proc do |data, *|
|
23
|
+
data['embeddings'].map { |embedding| embedding['values'] }
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [Context]
|
27
|
+
CONTEXT = Context.build do |context|
|
28
|
+
context.deserializers[:embeddings] = EMBEDDINGS_DESERIALIZER
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
# @param response [HTTP::Response]
|
34
|
+
# @return [Response]
|
35
|
+
def parse!(response:)
|
36
|
+
Response.new(data: response.parse, context: CONTEXT)
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [Array<Hash<{ text: String }>]
|
40
|
+
def requests
|
41
|
+
arrayify(@input).map do |text|
|
42
|
+
{
|
43
|
+
model: "models/#{@model}",
|
44
|
+
content: { parts: [{ text: text }] },
|
45
|
+
}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [Hash]
|
50
|
+
def payload
|
51
|
+
{ requests: }
|
52
|
+
end
|
53
|
+
|
54
|
+
# @return [String]
|
55
|
+
def path
|
56
|
+
"/#{@client.path}/models/#{@model}:batchEmbedContents?key=#{@client.api_key}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def arrayify(input)
|
60
|
+
input.is_a?(Array) ? input : [input]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OmniAI
|
4
|
+
module Google
|
5
|
+
class Upload
|
6
|
+
# A file that can be used for generating chat completions.
|
7
|
+
class File
|
8
|
+
class DeleteError < HTTPError; end
|
9
|
+
|
10
|
+
# @!attribute [rw] name
|
11
|
+
# @return [String]
|
12
|
+
attr_accessor :name
|
13
|
+
|
14
|
+
# @attribute [rw] uri
|
15
|
+
# @return [String]
|
16
|
+
attr_accessor :uri
|
17
|
+
|
18
|
+
# @attribute [rw] state
|
19
|
+
# @return [String]
|
20
|
+
attr_accessor :state
|
21
|
+
|
22
|
+
# @attribute [rw] mime_type
|
23
|
+
# @return [String]
|
24
|
+
attr_accessor :mime_type
|
25
|
+
|
26
|
+
# @param client [Client]
|
27
|
+
# @param data [Hash]
|
28
|
+
#
|
29
|
+
# @return [File]
|
30
|
+
def self.parse(client:, data:)
|
31
|
+
new(
|
32
|
+
client: client,
|
33
|
+
name: data['name'],
|
34
|
+
uri: data['uri'],
|
35
|
+
state: data['state'],
|
36
|
+
mime_type: data['mimeType']
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param client [Client]
|
41
|
+
# @param name [String]
|
42
|
+
# @param uri [String]
|
43
|
+
# @param state [String]
|
44
|
+
# @param mime_type [String]
|
45
|
+
def initialize(client:, name:, uri:, state:, mime_type:)
|
46
|
+
@client = client
|
47
|
+
@name = name
|
48
|
+
@uri = uri
|
49
|
+
@state = state
|
50
|
+
@mime_type = mime_type
|
51
|
+
end
|
52
|
+
|
53
|
+
# @raise [DeleteError]
|
54
|
+
def delete!
|
55
|
+
response = @client.connection
|
56
|
+
.delete("/#{@client.version}/#{@name}", params: { key: @client.api_key })
|
57
|
+
|
58
|
+
raise DeleteError, response unless response.status.success?
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OmniAI
|
4
|
+
module Google
|
5
|
+
# Uploads a file to Google to be used when generating completions.
|
6
|
+
class Upload
|
7
|
+
class FetchError < HTTPError; end
|
8
|
+
|
9
|
+
# @param client [Client]
|
10
|
+
# @param io [IO]
|
11
|
+
# @param mime_type [String]
|
12
|
+
def self.process!(client:, io:)
|
13
|
+
new(client:, io:).process!
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param client [Client]
|
17
|
+
# @param file [File]
|
18
|
+
# @param mime_type [String]
|
19
|
+
def initialize(client:, io:)
|
20
|
+
@client = client
|
21
|
+
@io = io
|
22
|
+
end
|
23
|
+
|
24
|
+
# @raise [HTTPError]
|
25
|
+
#
|
26
|
+
# @return [Upload::File]
|
27
|
+
def process!
|
28
|
+
response = io! do |io|
|
29
|
+
response = @client
|
30
|
+
.connection
|
31
|
+
.headers({ 'X-Goog-Upload-Protocol' => 'raw' })
|
32
|
+
.post("/upload/#{@client.version}/files?key=#{@client.api_key}", body: HTTP::FormData::File.new(io))
|
33
|
+
end
|
34
|
+
|
35
|
+
raise OmniAI::HTTPError, response.flush unless response.status.ok?
|
36
|
+
|
37
|
+
File.parse(client: @client, data: response.parse['file'])
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
# @raise [FetchError]
|
43
|
+
#
|
44
|
+
# @yield [io]
|
45
|
+
# @yieldparam io [IO]
|
46
|
+
def io!(&block)
|
47
|
+
case @io
|
48
|
+
when File, IO then block.call(@io)
|
49
|
+
else fetch!(&block)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# @raise [FetchError]
|
54
|
+
#
|
55
|
+
# @yield [tempfile]
|
56
|
+
# @yieldparam tempfile [Tempfile]
|
57
|
+
def fetch!
|
58
|
+
tempfile = Tempfile.new
|
59
|
+
tempfile.binmode
|
60
|
+
|
61
|
+
response = HTTP.follow.get(@io)
|
62
|
+
raise FetchError, response.flush unless response.status.success?
|
63
|
+
|
64
|
+
response.body.each { |chunk| tempfile.write(chunk) }
|
65
|
+
tempfile.rewind
|
66
|
+
|
67
|
+
yield(tempfile)
|
68
|
+
ensure
|
69
|
+
tempfile.close
|
70
|
+
tempfile.unlink
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: omniai-google
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.9.
|
4
|
+
version: 1.9.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Sylvestre
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-11-
|
11
|
+
date: 2024-11-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: event_stream_parser
|
@@ -76,6 +76,9 @@ files:
|
|
76
76
|
- lib/omniai/google/chat/usage_serializer.rb
|
77
77
|
- lib/omniai/google/client.rb
|
78
78
|
- lib/omniai/google/config.rb
|
79
|
+
- lib/omniai/google/embed.rb
|
80
|
+
- lib/omniai/google/upload.rb
|
81
|
+
- lib/omniai/google/upload/file.rb
|
79
82
|
- lib/omniai/google/version.rb
|
80
83
|
homepage: https://github.com/ksylvest/omniai-google
|
81
84
|
licenses:
|