omniai 2.4.0 → 2.4.1
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 +43 -4
- data/lib/omniai/chat/response.rb +1 -1
- data/lib/omniai/cli/base_handler.rb +1 -1
- data/lib/omniai/cli/chat_handler.rb +24 -7
- data/lib/omniai/cli/embed_handler.rb +3 -1
- data/lib/omniai/client.rb +33 -10
- data/lib/omniai/config.rb +17 -10
- data/lib/omniai/speak.rb +1 -1
- data/lib/omniai/tool.rb +4 -2
- data/lib/omniai/version.rb +1 -1
- data/lib/omniai.rb +2 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab754f5c048f4d0e4c76e75f142f4e3d511e81a4f2a0585dd466e4b325ccdeb2
|
4
|
+
data.tar.gz: 815d97caf42308a0bfaf183383522c5e34ce08ecab30835390d4c22034b32779
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3497bf2f884a273896d42271170a513462f180bf86ca561f9120a3b8d464485b42400828901ada0bfd3c47ff2f374eb57242149a3664b3b6208b42fcf4227425
|
7
|
+
data.tar.gz: d714671acf5e5c8dcfd3834bfbc529d2fede0967e8e7a3ddda4710588375eb65366c1067e1bcd00220764a6e9d30f583e7478e6e85881762fe005e43f8da3851
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -119,7 +119,46 @@ end
|
|
119
119
|
The weather is 24° Celsius in London and 42° Fahrenheit in Madrid.
|
120
120
|
```
|
121
121
|
|
122
|
-
### Example #5: [Chat w/
|
122
|
+
### Example #5: [Chat w/ History](https://github.com/ksylvest/omniai/blob/main/examples/chat_with_history)
|
123
|
+
|
124
|
+
Building a conversation history (e.g. multiple user and assistant messages) is especially helpful when building an agent like conversation experience. A prompt can be used to track this back and forth conversation:
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
require "omniai/openai"
|
128
|
+
|
129
|
+
puts("Type 'exit' or 'quit' to leave.")
|
130
|
+
|
131
|
+
client = OmniAI::OpenAI::Client.new
|
132
|
+
|
133
|
+
conversation = OmniAI::Chat::Prompt.build do |prompt|
|
134
|
+
prompt.system "You are a helpful assistant. Respond in both English and French."
|
135
|
+
end
|
136
|
+
|
137
|
+
loop do
|
138
|
+
print "> "
|
139
|
+
text = gets.chomp.strip
|
140
|
+
next if text.empty?
|
141
|
+
break if text.eql?("exit") || text.eql?("quit")
|
142
|
+
|
143
|
+
conversation.user(text)
|
144
|
+
response = client.chat(conversation, stream: $stdout)
|
145
|
+
conversation.assistant(response.text)
|
146
|
+
end
|
147
|
+
```
|
148
|
+
|
149
|
+
```
|
150
|
+
Type 'exit' or 'quit' to leave.
|
151
|
+
|
152
|
+
> What is the capital of France?
|
153
|
+
The capital of France is Paris.
|
154
|
+
La capitale de la France est Paris.
|
155
|
+
|
156
|
+
> How many people live there?
|
157
|
+
The population of Paris is approximately 2.1 million.
|
158
|
+
La population de Paris est d’environ 2,1 million.
|
159
|
+
```
|
160
|
+
|
161
|
+
### Example #6: [Chat w/ CLI](https://github.com/ksylvest/omniai/blob/main/examples/chat_with_cli)
|
123
162
|
|
124
163
|
The `OmniAI` gem also ships with a CLI to simplify quick tests.
|
125
164
|
|
@@ -139,7 +178,7 @@ omniai chat --provider="google" --model="gemini-2.0-flash" "Who are you?"
|
|
139
178
|
I am a large language model, trained by Google.
|
140
179
|
```
|
141
180
|
|
142
|
-
### Example #
|
181
|
+
### Example #7: [Text-to-Speech](https://github.com/ksylvest/omniai/blob/main/examples/text_to_speech)
|
143
182
|
|
144
183
|
This example demonstrates using `OmniAI` with **OpenAI** to convert text to speech and save it to a file.
|
145
184
|
|
@@ -155,7 +194,7 @@ File.open(File.join(__dir__, 'audio.wav'), 'wb') do |file|
|
|
155
194
|
end
|
156
195
|
```
|
157
196
|
|
158
|
-
### Example #
|
197
|
+
### Example #8: [Speech-to-Text](https://github.com/ksylvest/omniai/blob/main/examples/speech_to_text)
|
159
198
|
|
160
199
|
This example demonstrates using `OmniAI` with **OpenAI** to convert speech to text.
|
161
200
|
|
@@ -170,7 +209,7 @@ File.open(File.join(__dir__, 'audio.wav'), 'rb') do |file|
|
|
170
209
|
end
|
171
210
|
```
|
172
211
|
|
173
|
-
### Example #
|
212
|
+
### Example #9: [Embeddings](https://github.com/ksylvest/omniai/blob/main/examples/embeddings)
|
174
213
|
|
175
214
|
This example demonstrates using `OmniAI` with **Mistral** to generate embeddings for a dataset. It defines a set of entries (e.g. "George is a teacher." or "Ringo is a doctor.") and then compares the embeddings generated from a query (e.g. "What does George do?" or "Who is a doctor?") to rank the entries by relevance.
|
176
215
|
|
data/lib/omniai/chat/response.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module OmniAI
|
4
4
|
class CLI
|
5
|
-
# A generic handler for CLI commands (e.g. '
|
5
|
+
# A generic handler for CLI commands (e.g. 'omniai chat').
|
6
6
|
class BaseHandler
|
7
7
|
# @param stdin [IO] an optional stream for stdin
|
8
8
|
# @param stdout [IO] an optional stream for stdout
|
@@ -2,7 +2,11 @@
|
|
2
2
|
|
3
3
|
module OmniAI
|
4
4
|
class CLI
|
5
|
-
# Used
|
5
|
+
# Used by CLI to process commands like:
|
6
|
+
#
|
7
|
+
# omniai chat
|
8
|
+
# omniai chat "What is the capital of France?"
|
9
|
+
# omniai chat --provider="google" --model="gemini-2.0-flash" "Who are you?"
|
6
10
|
class ChatHandler < BaseHandler
|
7
11
|
# @param argv [Array<String>]
|
8
12
|
def handle!(argv:)
|
@@ -20,14 +24,18 @@ module OmniAI
|
|
20
24
|
def listen!
|
21
25
|
@stdout.puts('Type "exit" or "quit" to leave.')
|
22
26
|
|
27
|
+
prompt = OmniAI::Chat::Prompt.new
|
28
|
+
|
23
29
|
loop do
|
24
30
|
@stdout.print("# ")
|
25
31
|
@stdout.flush
|
26
|
-
|
32
|
+
text = @stdin.gets&.strip
|
27
33
|
|
28
|
-
break if
|
34
|
+
break if text.nil? || text.match?(/\A(exit|quit)\z/i)
|
29
35
|
|
30
|
-
|
36
|
+
prompt.user(text)
|
37
|
+
response = chat(prompt:)
|
38
|
+
prompt.assistant(response.text)
|
31
39
|
rescue Interrupt
|
32
40
|
break
|
33
41
|
end
|
@@ -48,12 +56,21 @@ module OmniAI
|
|
48
56
|
exit
|
49
57
|
end
|
50
58
|
|
51
|
-
options.on("-p", "--provider=PROVIDER", "provider")
|
52
|
-
|
59
|
+
options.on("-p", "--provider=PROVIDER", "provider") do |provider|
|
60
|
+
@provider = provider
|
61
|
+
end
|
62
|
+
|
63
|
+
options.on("-m", "--model=MODEL", "model") do |model|
|
64
|
+
@args[:model] = model
|
65
|
+
end
|
66
|
+
|
53
67
|
options.on("-t", "--temperature=TEMPERATURE", Float, "temperature") do |temperature|
|
54
68
|
@args[:temperature] = temperature
|
55
69
|
end
|
56
|
-
|
70
|
+
|
71
|
+
options.on("-f", "--format=FORMAT", "format") do |format|
|
72
|
+
@args[:format] = format.intern
|
73
|
+
end
|
57
74
|
end
|
58
75
|
end
|
59
76
|
end
|
data/lib/omniai/client.rb
CHANGED
@@ -16,71 +16,94 @@ module OmniAI
|
|
16
16
|
# end
|
17
17
|
# end
|
18
18
|
class Client
|
19
|
-
#
|
19
|
+
# @!attribute [rw] api_key
|
20
|
+
# @return [String, nil]
|
20
21
|
attr_accessor :api_key
|
21
22
|
|
22
|
-
#
|
23
|
+
# @!attribute [rw] logger
|
24
|
+
# @return [Logger, nil]
|
23
25
|
attr_accessor :logger
|
24
26
|
|
25
|
-
#
|
27
|
+
# @!attribute [rw] host
|
28
|
+
# @return [String, nil]
|
26
29
|
attr_accessor :host
|
27
30
|
|
28
|
-
#
|
31
|
+
# @!attribute [rw] timeout
|
32
|
+
# @return [Integer, nil]
|
29
33
|
attr_accessor :timeout
|
30
34
|
|
31
35
|
# Initialize a client for Anthropic. This method requires the provider if it is undefined.
|
32
36
|
#
|
33
37
|
# @raise [OmniAI::Error] if the provider is not defined and the gem is not installed
|
38
|
+
#
|
34
39
|
# @return [Class<OmniAI::Client>]
|
35
40
|
def self.anthropic
|
36
41
|
require "omniai/anthropic" unless defined?(OmniAI::Anthropic::Client)
|
37
42
|
OmniAI::Anthropic::Client
|
38
|
-
rescue LoadError
|
43
|
+
rescue ::LoadError
|
39
44
|
raise Error, "requires 'omniai-anthropic': `gem install omniai-anthropic`"
|
40
45
|
end
|
41
46
|
|
47
|
+
# Initialize a client for DeepSeek. This method requires the provider if it is undefined.
|
48
|
+
#
|
49
|
+
# @raise [OmniAI::Error] if the provider is not defined and the gem is not installed
|
50
|
+
#
|
51
|
+
# @return [Class<OmniAI::Client>]
|
52
|
+
def self.deepseek
|
53
|
+
require "omniai/deepseek" unless defined?(OmniAI::DeepSeek::Client)
|
54
|
+
OmniAI::DeepSeek::Client
|
55
|
+
rescue ::LoadError
|
56
|
+
raise Error, "requires 'omniai-deepseek': `gem install omniai-deepseek`"
|
57
|
+
end
|
58
|
+
|
42
59
|
# Lookup the `OmniAI::Google::Client``. This method requires the provider if it is undefined.
|
43
60
|
#
|
44
61
|
# @raise [OmniAI::Error] if the provider is not defined and the gem is not installed
|
62
|
+
#
|
45
63
|
# @return [Class<OmniAI::Client>]
|
46
64
|
def self.google
|
47
65
|
require "omniai/google" unless defined?(OmniAI::Google::Client)
|
48
66
|
OmniAI::Google::Client
|
49
|
-
rescue LoadError
|
67
|
+
rescue ::LoadError
|
50
68
|
raise Error, "requires 'omniai-google': `gem install omniai-google`"
|
51
69
|
end
|
52
70
|
|
53
71
|
# Initialize a client for Mistral. This method requires the provider if it is undefined.
|
54
72
|
#
|
55
73
|
# @raise [OmniAI::Error] if the provider is not defined and the gem is not installed
|
74
|
+
#
|
56
75
|
# @return [Class<OmniAI::Client>]
|
57
76
|
def self.mistral
|
58
77
|
require "omniai/mistral" unless defined?(OmniAI::Mistral::Client)
|
59
78
|
OmniAI::Mistral::Client
|
60
|
-
rescue LoadError
|
79
|
+
rescue ::LoadError
|
61
80
|
raise Error, "requires 'omniai-mistral': `gem install omniai-mistral`"
|
62
81
|
end
|
63
82
|
|
64
83
|
# Initialize a client for OpenAI. This method requires the provider if it is undefined.
|
65
84
|
#
|
66
85
|
# @raise [OmniAI::Error] if the provider is not defined and the gem is not installed
|
86
|
+
#
|
67
87
|
# @return [Class<OmniAI::Client>]
|
68
88
|
def self.openai
|
69
89
|
require "omniai/openai" unless defined?(OmniAI::OpenAI::Client)
|
70
90
|
OmniAI::OpenAI::Client
|
71
|
-
rescue LoadError
|
91
|
+
rescue ::LoadError
|
72
92
|
raise Error, "requires 'omniai-openai': `gem install omniai-openai`"
|
73
93
|
end
|
74
94
|
|
75
95
|
# Initialize a client by provider (e.g. 'openai'). This method attempts to require the provider.
|
76
96
|
#
|
97
|
+
# @param provider [String, Symbol] required (e.g. 'anthropic', 'deepsek', 'google', 'mistral', 'openai', etc)
|
98
|
+
#
|
77
99
|
# @raise [OmniAI::Error] if the provider is not defined and the gem is not installed
|
78
|
-
#
|
100
|
+
#
|
79
101
|
# @return [OmniAI::Client]
|
80
102
|
def self.find(provider:, **)
|
81
103
|
klass =
|
82
104
|
case provider
|
83
105
|
when :anthropic, "anthropic" then anthropic
|
106
|
+
when :deepseek, "deepseek" then deepseek
|
84
107
|
when :google, "google" then google
|
85
108
|
when :mistral, "mistral" then mistral
|
86
109
|
when :openai, "openai" then openai
|
@@ -169,7 +192,7 @@ module OmniAI
|
|
169
192
|
#
|
170
193
|
# @yield [output] optional
|
171
194
|
#
|
172
|
-
# @return [Tempfile
|
195
|
+
# @return [Tempfile]
|
173
196
|
def speak(input, model:, voice:, speed: nil, format: nil, &stream)
|
174
197
|
raise NotImplementedError, "#{self.class.name}#speak undefined"
|
175
198
|
end
|
data/lib/omniai/config.rb
CHANGED
@@ -15,28 +15,35 @@ module OmniAI
|
|
15
15
|
# config.speak_options = { ... }
|
16
16
|
# end
|
17
17
|
class Config
|
18
|
-
#
|
18
|
+
# @!attribute [rw] api_key
|
19
|
+
# @return [String, nil]
|
19
20
|
attr_accessor :api_key
|
20
21
|
|
21
|
-
#
|
22
|
+
# @!attribute [rw] host
|
23
|
+
# @return [String, nil]
|
22
24
|
attr_accessor :host
|
23
25
|
|
24
|
-
#
|
26
|
+
# @!attribute [rw] logger
|
27
|
+
# @return [Logger, nil]
|
25
28
|
attr_accessor :logger
|
26
29
|
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
30
|
+
# @!attribute [rw] timeout
|
31
|
+
# @return [Integer, Hash{Symbol => Integer}, nil]
|
32
|
+
# @option timeout [Integer] :read
|
33
|
+
# @option timeout [Integer] :write
|
34
|
+
# @option timeout [Integer] :connect
|
31
35
|
attr_accessor :timeout
|
32
36
|
|
33
|
-
#
|
37
|
+
# @!attribute [rw] chat_options
|
38
|
+
# @return [Hash]
|
34
39
|
attr_accessor :chat_options
|
35
40
|
|
36
|
-
#
|
41
|
+
# @!attribute [rw] transcribe_options
|
42
|
+
# @return [Hash]
|
37
43
|
attr_accessor :transcribe_options
|
38
44
|
|
39
|
-
#
|
45
|
+
# @!attribute [rw] speak_options
|
46
|
+
# @return [Hash]
|
40
47
|
attr_accessor :speak_options
|
41
48
|
|
42
49
|
# @param api_key [String] optional
|
data/lib/omniai/speak.rb
CHANGED
data/lib/omniai/tool.rb
CHANGED
@@ -17,6 +17,8 @@ module OmniAI
|
|
17
17
|
class Tool
|
18
18
|
class << self
|
19
19
|
# @param description [String]
|
20
|
+
#
|
21
|
+
# @return [String]
|
20
22
|
def description(description = nil)
|
21
23
|
return @description if description.nil?
|
22
24
|
|
@@ -61,11 +63,11 @@ module OmniAI
|
|
61
63
|
# @return [String]
|
62
64
|
attr_accessor :name
|
63
65
|
|
64
|
-
# @!attribute [description
|
66
|
+
# @!attribute [rw] description
|
65
67
|
# @return [String, nil]
|
66
68
|
attr_accessor :description
|
67
69
|
|
68
|
-
# @!attribute[parameters
|
70
|
+
# @!attribute [rw] parameters
|
69
71
|
# @return [Hash, nil]
|
70
72
|
attr_accessor :parameters
|
71
73
|
|
data/lib/omniai/version.rb
CHANGED
data/lib/omniai.rb
CHANGED
@@ -19,7 +19,8 @@ module OmniAI
|
|
19
19
|
|
20
20
|
# An error that wraps an HTTP::Response for non-OK requests.
|
21
21
|
class HTTPError < Error
|
22
|
-
#
|
22
|
+
# @!attribute [rw] response
|
23
|
+
# @return [HTTP::Response]
|
23
24
|
attr_accessor :response
|
24
25
|
|
25
26
|
# @param response [HTTP::Response]
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: omniai
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.4.
|
4
|
+
version: 2.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Sylvestre
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-04-
|
10
|
+
date: 2025-04-23 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: event_stream_parser
|