omniai 1.3.1 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 28e6e2a736d78cbc0135308eb28320a85a319b78a888cd96fa3320456c3c0222
4
- data.tar.gz: '044786d21ba8f2316599836af153c6dec80d055a0cbcf1e843c000296d1df350'
3
+ metadata.gz: 8b3d66712c9a2fd460abf00c29b056b87ff8cdd08c8b38d69ece0755d8c76578
4
+ data.tar.gz: f0fdf7b20e3f3cc3c4e2bee6d21b68bd917d9267c9f1297dec91f2f8bccc71e9
5
5
  SHA512:
6
- metadata.gz: c260f1b52fe5ffec70dc5c6755426c9798062bb234da303d76ec21319d450433e95f03ca787fcfa8cd966899235416d5a83580ffd11c24615d8a58df8d64efbc
7
- data.tar.gz: 0acc9d0556d0bf8de430ca3a52977c88c6a43edfe017226d1831b4ccc034d2ba3bcde38fad112d61d8910bfc9a9ee440999354919a8d4c3cb614a0d0fc3e2314
6
+ metadata.gz: 98c6c3380181aaf7ad858968b998adab49f8cd200d94755ff6cf79423378dd401c4c538147aeb416b023c47fe7f1806a8742a9486429e90bcc487eb8944cba52
7
+ data.tar.gz: f251bb7436e9536275a285508f63964693a067378f55a72b3cf01fb9cb801f55ef96fd8a64c9b4e5790c6c400ee6adcee64f6dc5dc413e92b42d5f869afce45f
data/README.md CHANGED
@@ -193,3 +193,38 @@ tempfile = client.speak('The quick brown fox jumps over a lazy dog.', voice: 'HA
193
193
  tempfile.close
194
194
  tempfile.unlink
195
195
  ```
196
+
197
+ ## CLI
198
+
199
+ OmniAI packages a basic command line interface (CLI) to allow for exploration of various APIs. A detailed CLI documentation can be found via help:
200
+
201
+ ```bash
202
+ omniai --help
203
+ ```
204
+
205
+ ### Chat
206
+
207
+ #### w/ a Prompt
208
+
209
+ ```bash
210
+ omniai chat "What is the coldest place on earth?"
211
+ ```
212
+
213
+ ```
214
+ The coldest place on earth is Antarctica.
215
+ ```
216
+
217
+ #### w/o a Prompt
218
+
219
+ ```bash
220
+ omniai chat --provider="openai" --model="gpt-4" --temperature="0.5"
221
+ ```
222
+
223
+ ```
224
+ Type 'exit' or 'quit' to abort.
225
+ # What is the warmet place on earth?
226
+ ```
227
+
228
+ ```
229
+ The warmest place on earth is Africa.
230
+ ```
data/exe/omniai ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'omniai'
5
+
6
+ cli = OmniAI::CLI.new
7
+ cli.parse
data/lib/omniai/chat.rb CHANGED
@@ -45,7 +45,7 @@ module OmniAI
45
45
  # @param client [OmniAI::Client] the client
46
46
  # @param model [String] required
47
47
  # @param temperature [Float, nil] optional
48
- # @param stream [Proc, nil] optional
48
+ # @param stream [Proc, IO, nil] optional
49
49
  # @param format [Symbol, nil] optional - :json
50
50
  def initialize(messages, client:, model:, temperature: nil, stream: nil, format: nil)
51
51
  @messages = messages
@@ -97,7 +97,14 @@ module OmniAI
97
97
  def stream!(response:)
98
98
  raise Error, "#{self.class.name}#stream! unstreamable" unless @stream
99
99
 
100
- Stream.new(response:).stream! { |chunk| @stream.call(chunk) }
100
+ Stream.new(response:).stream! do |chunk|
101
+ case @stream
102
+ when IO then @stream << chunk
103
+ else @stream.call(chunk)
104
+ end
105
+ end
106
+
107
+ @stream.flush if @stream.is_a?(IO)
101
108
  end
102
109
 
103
110
  # @return [Array<Hash>]
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OmniAI
4
+ class CLI
5
+ # A generic handler for CLI commands (e.g. 'omnia chat').
6
+ class BaseHandler
7
+ # @param stdin [IO] an optional stream for stdin
8
+ # @param stdout [IO] an optional stream for stdout
9
+ # @param provider [String] an optional provider (defaults to 'openai')
10
+ # @param argv [Array<String>]
11
+ def self.handle!(argv:, stdin: $stdin, stdout: $stdout, provider: 'openai')
12
+ new(stdin:, stdout:, provider:).handle!(argv:)
13
+ end
14
+
15
+ # @param stdin [IO] an optional stream for stdin
16
+ # @param stdout [IO] an optional stream for stdout
17
+ # @param provider [String] an optional provider (defaults to 'openai')
18
+ def initialize(stdin: $stdin, stdout: $stdout, provider: 'openai')
19
+ @stdin = stdin
20
+ @stdout = stdout
21
+ @provider = provider
22
+ @args = {}
23
+ end
24
+
25
+ # @param argv [Array<String>]
26
+ def handle!(argv:)
27
+ raise NotImplementedError, "#{self.class}#handle! undefined"
28
+ end
29
+
30
+ private
31
+
32
+ # @return [OmniAI::Client]
33
+ def client
34
+ @client ||= OmniAI::Client.find(provider: @provider)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OmniAI
4
+ class CLI
5
+ # Used for CLI usage of 'omnia chat'.
6
+ class ChatHandler < BaseHandler
7
+ def handle!(argv:)
8
+ parser.parse!(argv)
9
+
10
+ if argv.empty?
11
+ listen!
12
+ else
13
+ chat(prompt: argv.join(' '))
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def listen!
20
+ @stdout.puts('Type "exit" or "quit" to leave.')
21
+
22
+ loop do
23
+ @stdout.print('# ')
24
+ prompt = @stdin.gets&.chomp
25
+
26
+ break if prompt.nil? || prompt.match?(/\A(exit|quit)\z/i)
27
+
28
+ chat(prompt:)
29
+ rescue Interrupt
30
+ break
31
+ end
32
+ end
33
+
34
+ # @param prompt [String]
35
+ def chat(prompt:)
36
+ client.chat(prompt, **@args, stream: @stdout)
37
+ end
38
+
39
+ # @return [OptionParser]
40
+ def parser
41
+ OptionParser.new do |options|
42
+ options.banner = 'usage: omniai chat [options] "<prompt>"'
43
+
44
+ options.on('-h', '--help', 'help') do
45
+ @stdout.puts(options)
46
+ exit
47
+ end
48
+
49
+ options.on('-p', '--provider=PROVIDER', 'provider') { |provider| @provider = provider }
50
+ options.on('-m', '--model=MODEL', 'model') { |model| @args[:model] = model }
51
+ options.on('-t', '--temperature=TEMPERATURE', Float, 'temperature') do |temperature|
52
+ @args[:temperature] = temperature
53
+ end
54
+ options.on('-f', '--format=FORMAT', 'format') { |format| @args[:format] = format.intern }
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
data/lib/omniai/cli.rb ADDED
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'optparse'
4
+
5
+ module OmniAI
6
+ # Used when interacting with the suite from the command line interface (CLI).
7
+ #
8
+ # Usage:
9
+ #
10
+ # cli = OmniAI::CLI.new
11
+ # cli.parse
12
+ class CLI
13
+ ChatArgs = Struct.new(:provider, :model, :temperature)
14
+
15
+ # @param in [IO] a stream
16
+ # @param out [IO] a stream
17
+ # @param provider [String] a provider
18
+ def initialize(stdin: $stdin, stdout: $stdout, provider: 'openai')
19
+ @stdin = stdin
20
+ @stdout = stdout
21
+ @provider = provider
22
+ @args = {}
23
+ end
24
+
25
+ def parse(argv = ARGV)
26
+ parser.order!(argv)
27
+ command = argv.shift
28
+ return if command.nil?
29
+
30
+ case command
31
+ when 'chat' then ChatHandler.handle!(stdin: @stdin, stdout: @stdout, provider: @provider, argv:)
32
+ else raise Error, "unsupported command=#{command.inspect}"
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ # @return [OptionParser]
39
+ def parser
40
+ OptionParser.new do |options|
41
+ options.banner = 'usage: omniai [options] <command> [<args>]'
42
+
43
+ options.on('-h', '--help', 'help') do
44
+ @stdout.puts(options)
45
+ exit
46
+ end
47
+
48
+ options.on('-v', '--version', 'version') do
49
+ @stdout.puts(VERSION)
50
+ exit
51
+ end
52
+
53
+ options.on('-p', '--provider=PROVIDER', 'provider (default="openai")') do |provider|
54
+ @provider = provider
55
+ end
56
+
57
+ options.separator <<~COMMANDS
58
+ commands:
59
+ chat
60
+ COMMANDS
61
+ end
62
+ end
63
+ end
64
+ end
data/lib/omniai/client.rb CHANGED
@@ -16,8 +16,6 @@ module OmniAI
16
16
  # end
17
17
  # end
18
18
  class Client
19
- class Error < StandardError; end
20
-
21
19
  # @return [String, nil]
22
20
  attr_accessor :api_key
23
21
 
@@ -30,6 +28,68 @@ module OmniAI
30
28
  # @return [Integer, nil]
31
29
  attr_accessor :timeout
32
30
 
31
+ # Initialize a client for Anthropic. This method requires the provider if it is undefined.
32
+ #
33
+ # @raise [OmniAI::Error] if the provider is not defined and the gem is not installed
34
+ # @return [Class<OmniAI::Client>]
35
+ def self.anthropic
36
+ require 'omniai/anthropic' unless defined?(OmniAI::Anthropic::Client)
37
+ OmniAI::Anthropic::Client
38
+ rescue LoadError
39
+ raise Error, "requires 'omniai-anthropic': `gem install omniai-anthropic`"
40
+ end
41
+
42
+ # Lookup the `OmniAI::Google::Client``. This method requires the provider if it is undefined.
43
+ #
44
+ # @raise [OmniAI::Error] if the provider is not defined and the gem is not installed
45
+ # @return [Class<OmniAI::Client>]
46
+ def self.google
47
+ require 'omniai/google' unless defined?(OmniAI::Google::Client)
48
+ OmniAI::Google::Client
49
+ rescue LoadError
50
+ raise Error, "requires 'omniai-google': `gem install omniai-google`"
51
+ end
52
+
53
+ # Initialize a client for Mistral. This method requires the provider if it is undefined.
54
+ #
55
+ # @raise [OmniAI::Error] if the provider is not defined and the gem is not installed
56
+ # @return [Class<OmniAI::Client>]
57
+ def self.mistral
58
+ require 'omniai/mistral' unless defined?(OmniAI::Mistral::Client)
59
+ OmniAI::Mistral::Client
60
+ rescue LoadError
61
+ raise Error, "requires 'omniai-mistral': `gem install omniai-mistral`"
62
+ end
63
+
64
+ # Initialize a client for OpenAI. This method requires the provider if it is undefined.
65
+ #
66
+ # @raise [OmniAI::Error] if the provider is not defined and the gem is not installed
67
+ # @return [Class<OmniAI::Client>]
68
+ def self.openai
69
+ require 'omniai/openai' unless defined?(OmniAI::OpenAI::Client)
70
+ OmniAI::OpenAI::Client
71
+ rescue LoadError
72
+ raise Error, "requires 'omniai-openai': `gem install omniai-openai`"
73
+ end
74
+
75
+ # Initialize a client by provider (e.g. 'openai'). This method attempts to require the provider.
76
+ #
77
+ # @raise [OmniAI::Error] if the provider is not defined and the gem is not installed
78
+ # @param provider [String] required (e.g. 'anthropic', 'google', 'mistral', 'openai', etc)
79
+ # @return [OmniAI::Client]
80
+ def self.find(provider:, **)
81
+ klass =
82
+ case provider
83
+ when 'anthropic' then anthropic
84
+ when 'google' then google
85
+ when 'mistral' then mistral
86
+ when 'openai' then openai
87
+ else raise Error, "unknown provider=#{provider.inspect}"
88
+ end
89
+
90
+ klass.new(**)
91
+ end
92
+
33
93
  # @param api_key [String, nil] optional
34
94
  # @param host [String, nil] optional - supports for customzing the host of the client (e.g. 'http://localhost:8080')
35
95
  # @param logger [Logger, nil] optional
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OmniAI
4
- VERSION = '1.3.1'
4
+ VERSION = '1.4.0'
5
5
  end
data/lib/omniai.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'logger'
3
4
  require 'event_stream_parser'
4
5
  require 'http'
5
6
  require 'uri'
@@ -8,6 +9,7 @@ require 'zeitwerk'
8
9
  loader = Zeitwerk::Loader.for_gem
9
10
  loader.inflector.inflect 'omniai' => 'OmniAI'
10
11
  loader.inflector.inflect 'url' => 'URL'
12
+ loader.inflector.inflect 'cli' => 'CLI'
11
13
  loader.setup
12
14
 
13
15
  module OmniAI
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omniai
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.4.0
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-06-21 00:00:00.000000000 Z
11
+ date: 2024-07-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: event_stream_parser
@@ -56,7 +56,8 @@ description: An interface for OpenAI's ChatGPT, Google's Gemini, Anthropic's Cla
56
56
  Mistral's LeChat, etc.
57
57
  email:
58
58
  - kevin@ksylvest.com
59
- executables: []
59
+ executables:
60
+ - omniai
60
61
  extensions: []
61
62
  extra_rdoc_files: []
62
63
  files:
@@ -64,6 +65,7 @@ files:
64
65
  - README.md
65
66
  - bin/console
66
67
  - bin/setup
68
+ - exe/omniai
67
69
  - lib/omniai.rb
68
70
  - lib/omniai/chat.rb
69
71
  - lib/omniai/chat/chunk.rb
@@ -78,6 +80,9 @@ files:
78
80
  - lib/omniai/chat/message_choice.rb
79
81
  - lib/omniai/chat/stream.rb
80
82
  - lib/omniai/chat/usage.rb
83
+ - lib/omniai/cli.rb
84
+ - lib/omniai/cli/base_handler.rb
85
+ - lib/omniai/cli/chat_handler.rb
81
86
  - lib/omniai/client.rb
82
87
  - lib/omniai/config.rb
83
88
  - lib/omniai/instrumentation.rb