omniai 1.2.2 → 1.3.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: 239eb058ae53afd3f28fe00a18af282a856ca842a4f81bcdf22413a02d8d44fc
4
- data.tar.gz: e74ac69ab6435fd9da3d1602c9cce5e052f53bebf609d8815868b58be0897884
3
+ metadata.gz: 341ce12cf0950b167a43c298f3ccb1df821bbdc469bc6824b14219bef4e38ab5
4
+ data.tar.gz: 9badfe7e48d20fe84054d9206e8572a333f382407c3236a3715e1d85cf6b6a84
5
5
  SHA512:
6
- metadata.gz: a6b18cae8b5aab610bf255860ccd514b794eda3021b2f9b3aa86020968e0f449b683b4db74291e71583698b61d7612a7e49b3ee0310c806a826f7b27c50c7d92
7
- data.tar.gz: bd12b38f3c9a150fe09644aaf187aa05aa1063ee136196e11fcaa356f4fe5bdc2c93f6292a79025f301c6d35a1202186f6ad787787828dfd5af91f229a34b550
6
+ metadata.gz: f81164e402f5e1e4b2ccc2e627675d42631cfda985bf91469eb32735a789eecbe69c7f10bd9d2d5b4959f2d0f2484ae1bf7ced58f607a7cae822846c831ce96c
7
+ data.tar.gz: '0182828dad6fb6f6d98550608c3bd57ee980ff4acbcc6dfb3ee7d61a16200566f1c8965424537583d0b73225298ca5eba6ddafd3c51791ca847f53264a7654fd'
data/Gemfile CHANGED
@@ -4,8 +4,8 @@ source 'https://rubygems.org'
4
4
 
5
5
  gemspec
6
6
 
7
+ gem 'logger'
7
8
  gem 'rake'
8
-
9
9
  gem 'rspec'
10
10
  gem 'rspec_junit_formatter'
11
11
  gem 'rubocop'
data/README.md CHANGED
@@ -2,13 +2,15 @@
2
2
 
3
3
  [![CircleCI](https://circleci.com/gh/ksylvest/omniai.svg?style=svg)](https://circleci.com/gh/ksylvest/omniai)
4
4
 
5
- OmniAI is a flexible AI library that standardizes the APIs for multiple AI providers:
5
+ OmniAI is a flexible AI library that standardizes the APIs of many different AIs:
6
6
 
7
7
  - [OmniAI::Anthropic](https://github.com/ksylvest/omniai-anthropic)
8
8
  - [OmniAI::Google](https://github.com/ksylvest/omniai-google)
9
9
  - [OmniAI::Mistral](https://github.com/ksylvest/omniai-mistral)
10
10
  - [OmniAI::OpenAI](https://github.com/ksylvest/omniai-openai)
11
11
 
12
+ All libraries are community maintained.
13
+
12
14
  ## Installation
13
15
 
14
16
  ```sh
@@ -72,6 +74,79 @@ Ollama support is offered through [OmniAI::OpenAI](https://github.com/ksylvest/o
72
74
 
73
75
  [Usage with Ollama](https://github.com/ksylvest/omniai-openai#usage-with-ollama)
74
76
 
77
+ #### Logging
78
+
79
+ Logging the **request** / **response** is configurable by passing a logger into any client:
80
+
81
+ ```ruby
82
+ require 'omniai/openai'
83
+ require 'logger'
84
+
85
+ logger = Logger.new(STDOUT)
86
+ client = OmniAI::Example::Client.new(logger:)
87
+ ```
88
+
89
+ ```
90
+ I, [...] INFO -- : > POST https://...
91
+ D, [...] DEBUG -- : Authorization: Bearer ...
92
+ ...
93
+ {"messages":[{"role":"user","content":"Tell me a joke!"}],"model":"..."}
94
+ I, [...] INFO -- : < 200 OK
95
+ D, [...] DEBUG -- : Date: ...
96
+ ...
97
+ {
98
+ "id": "...",
99
+ "object": "...",
100
+ ...
101
+ }
102
+ ```
103
+
104
+ The level of the logger can be configured to either `INFO` and `DEBUG`:
105
+
106
+ **INFO**:
107
+
108
+ ```ruby
109
+ logger.level = Logger::INFO
110
+ ```
111
+
112
+ - Request: verb / URI
113
+ - Response: status
114
+
115
+ **DEBUG**:
116
+
117
+ ```ruby
118
+ logger.level = Logger::DEBUG
119
+ ```
120
+
121
+ - Request: verb / URI / headers / body
122
+ - Response: status / headers / body
123
+
124
+ #### Timeouts
125
+
126
+ Timeouts are configurable by passing a `timeout` an integer duration for the request / response of any APIs using:
127
+
128
+ ```ruby
129
+ require 'omniai/openai'
130
+ require 'logger'
131
+
132
+ logger = Logger.new(STDOUT)
133
+ client = OmniAI::OpenAI::Client.new(timeout: 8) # i.e. 8 seconds
134
+ ```
135
+
136
+ Timeouts are also be configurable by passing a `timeout` hash with `timeout` / `read` / `write` / `keys using:
137
+
138
+ ```ruby
139
+ require 'omniai/openai'
140
+ require 'logger'
141
+
142
+ logger = Logger.new(STDOUT)
143
+ client = OmniAI::OpenAI::Client.new(timeout: {
144
+ read: 2, # i.e. 2 seconds
145
+ write: 3, # i.e. 3 seconds
146
+ connect: 4, # i.e. 4 seconds
147
+ })
148
+ ```
149
+
75
150
  ### Chat
76
151
 
77
152
  Clients that support chat (e.g. Anthropic w/ "Claude", Google w/ "Gemini", Mistral w/ "LeChat", OpenAI w/ "ChatGPT", etc) generate completions using the following calls:
@@ -31,9 +31,9 @@ module OmniAI
31
31
  @data['model']
32
32
  end
33
33
 
34
- # @return [Array<OmniAI::Chat::Choice>]
34
+ # @return [Array<OmniAI::Chat::DeltaChoice>]
35
35
  def choices
36
- @choices ||= @data['choices'].map { |data| Choice.for(data:) }
36
+ @choices ||= @data['choices'].map { |data| DeltaChoice.for(data:) }
37
37
  end
38
38
 
39
39
  # @param index [Integer]
@@ -38,13 +38,13 @@ module OmniAI
38
38
  @usage ||= Usage.for(data: @data['usage'])
39
39
  end
40
40
 
41
- # @return [Array<OmniAI::Chat::Choice>]
41
+ # @return [Array<OmniAI::Chat::MessageChoice>]
42
42
  def choices
43
- @choices ||= @data['choices'].map { |data| Choice.for(data:) }
43
+ @choices ||= @data['choices'].map { |data| MessageChoice.for(data:) }
44
44
  end
45
45
 
46
46
  # @param index [Integer] optional - default is 0
47
- # @return [OmniAI::Chat::Choice]
47
+ # @return [OmniAI::Chat::MessageChoice]
48
48
  def choice(index: 0)
49
49
  choices[index]
50
50
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OmniAI
4
+ class Chat
5
+ # A delta choice returned by the API.
6
+ class DeltaChoice
7
+ attr_accessor :index, :delta
8
+
9
+ # @param data [Hash]
10
+ # @return [OmniAI::Chat::Choice]
11
+ def self.for(data:)
12
+ index = data['index']
13
+ delta = Delta.for(data: data['delta'])
14
+
15
+ new(index:, delta:)
16
+ end
17
+
18
+ # @param index [Integer]
19
+ # @param delta [Delta]
20
+ def initialize(index:, delta:)
21
+ @index = index
22
+ @delta = delta
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OmniAI
4
+ class Chat
5
+ # A choice returned by the API.
6
+ class MessageChoice
7
+ attr_accessor :index, :message
8
+
9
+ # @param data [Hash]
10
+ # @return [OmniAI::Chat::Choice]
11
+ def self.for(data:)
12
+ index = data['index']
13
+ message = Message.for(data: data['message'])
14
+
15
+ new(index:, message:)
16
+ end
17
+
18
+ # @param index [Integer]
19
+ # @param message [OmniAI::Chat::Message]
20
+ def initialize(index:, message:)
21
+ @index = index
22
+ @message = message
23
+ end
24
+ end
25
+ end
26
+ end
data/lib/omniai/client.rb CHANGED
@@ -9,19 +9,36 @@ module OmniAI
9
9
  # def initialize(api_key: ENV.fetch('OPENAI_API_KEY'), logger: nil)
10
10
  # super
11
11
  # end
12
+ #
13
+ # # @return [HTTP::Client]
14
+ # def connection
15
+ # @connection ||= super.auth("Bearer: #{@api_key}")
16
+ # end
12
17
  # end
13
18
  class Client
14
19
  class Error < StandardError; end
15
20
 
16
- attr_accessor :api_key, :logger, :host
21
+ # @return [String, nil]
22
+ attr_accessor :api_key
23
+
24
+ # @return [Logger, nil]
25
+ attr_accessor :logger
26
+
27
+ # @return [String, nil]
28
+ attr_accessor :host
29
+
30
+ # @return [Integer, nil]
31
+ attr_accessor :timeout
17
32
 
18
- # @param api_key [String] optional
19
- # @param host [String] optional - supports for customzing the host of the client (e.g. 'http://localhost:8080')
20
- # @param logger [Logger] optional
21
- def initialize(api_key: nil, logger: nil, host: nil)
33
+ # @param api_key [String, nil] optional
34
+ # @param host [String, nil] optional - supports for customzing the host of the client (e.g. 'http://localhost:8080')
35
+ # @param logger [Logger, nil] optional
36
+ # @param timeout [Integer, nil] optional
37
+ def initialize(api_key: nil, logger: nil, host: nil, timeout: nil)
22
38
  @api_key = api_key
23
39
  @host = host
24
40
  @logger = logger
41
+ @timeout = timeout
25
42
  end
26
43
 
27
44
  # @return [String]
@@ -39,7 +56,10 @@ module OmniAI
39
56
 
40
57
  # @return [HTTP::Client]
41
58
  def connection
42
- raise NotImplementedError, "#{self.class.name}#connection undefined"
59
+ http = HTTP.persistent(@host)
60
+ http = http.use(logging: { logger: @logger }) if @logger
61
+ http = http.timeout(@timeout) if @timeout
62
+ http
43
63
  end
44
64
 
45
65
  # @raise [OmniAI::Error]
data/lib/omniai/config.rb CHANGED
@@ -1,9 +1,56 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OmniAI
4
- # A configuration for each agent w/ `api_key` / `host` / `logger`.
4
+ # A configuration for each agent w/ `api_key` / `host` / `logger`. Usage:
5
+ #
6
+ # OmniAI::OpenAI.config do |config|
7
+ # config.api_key = '...'
8
+ # config.host = 'http://localhost:8080'
9
+ # config.logger = Logger.new(STDOUT)
10
+ # config.timeout = 15
11
+ # config.chat_options = { ... }
12
+ # config.transcribe_options = { ... }
13
+ # config.speak_options = { ... }
14
+ # end
5
15
  class Config
6
- attr_accessor :api_key, :host, :logger
16
+ # @return [String, nil]
17
+ attr_accessor :api_key
18
+
19
+ # @return [String, nil]
20
+ attr_accessor :host
21
+
22
+ # @return [Logger, nil]
23
+ attr_accessor :logger
24
+
25
+ # @return [Integer, Hash{Symbol => Integer}, nil]
26
+ # @option timeout [Integer] :read
27
+ # @option timeout [Integer] :write
28
+ # @option timeout [Integer] :connect
29
+ attr_accessor :timeout
30
+
31
+ # @return [Hash]
32
+ attr_accessor :chat_options
33
+
34
+ # @return [Hash]
35
+ attr_accessor :transcribe_options
36
+
37
+ # @return [Hash]
38
+ attr_accessor :speak_options
39
+
40
+ # @param api_key [String] optional
41
+ # @param host [String] optional
42
+ # @param logger [Logger] optional
43
+ # @param timeout [Integer] optional
44
+ def initialize(api_key: nil, host: nil, logger: nil, timeout: nil)
45
+ @api_key = api_key
46
+ @host = host
47
+ @logger = logger
48
+ @timeout = timeout
49
+
50
+ @chat_options = {}
51
+ @transcribe_options = {}
52
+ @speak_options = {}
53
+ end
7
54
 
8
55
  # @return [String]
9
56
  def inspect
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OmniAI
4
- VERSION = '1.2.2'
4
+ VERSION = '1.3.0'
5
5
  end
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.2.2
4
+ version: 1.3.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-20 00:00:00.000000000 Z
11
+ date: 2024-06-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: event_stream_parser
@@ -66,7 +66,6 @@ files:
66
66
  - bin/setup
67
67
  - lib/omniai.rb
68
68
  - lib/omniai/chat.rb
69
- - lib/omniai/chat/choice.rb
70
69
  - lib/omniai/chat/chunk.rb
71
70
  - lib/omniai/chat/completion.rb
72
71
  - lib/omniai/chat/content/file.rb
@@ -74,7 +73,9 @@ files:
74
73
  - lib/omniai/chat/content/text.rb
75
74
  - lib/omniai/chat/content/url.rb
76
75
  - lib/omniai/chat/delta.rb
76
+ - lib/omniai/chat/delta_choice.rb
77
77
  - lib/omniai/chat/message.rb
78
+ - lib/omniai/chat/message_choice.rb
78
79
  - lib/omniai/chat/stream.rb
79
80
  - lib/omniai/chat/usage.rb
80
81
  - lib/omniai/client.rb
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OmniAI
4
- class Chat
5
- # A choice returned by the API.
6
- class Choice
7
- attr_accessor :index, :delta, :message
8
-
9
- # @param data [Hash]
10
- # @return [OmniAI::Chat::Choice]
11
- def self.for(data:)
12
- index = data['index']
13
- delta = Delta.for(data: data['delta']) if data['delta']
14
- message = Message.for(data: data['message']) if data['message']
15
-
16
- new(index:, delta:, message:)
17
- end
18
-
19
- # @param index [Integer]
20
- # @param delta [OmniAI::Chat::Delta] optional
21
- # @param message [OmniAI::Chat::Message] optional
22
- def initialize(index:, delta:, message:)
23
- @index = index
24
- @delta = delta
25
- @message = message
26
- end
27
- end
28
- end
29
- end