omniai 1.0.0 → 1.0.2

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: a227888b197b576509bec7208b79f125e2c55baac317ce32b3fed8e2101f11cc
4
- data.tar.gz: 16fe842b15ef266556c9887b1625c32a62edbbdba21dea0a8b21e418d76cd435
3
+ metadata.gz: ffc27287a50c39e3aab00622ea1e389f2e2da0828e5ec5b01f0e62bf7ec63c58
4
+ data.tar.gz: 3979a4a92abd12706cc36ff66d4befab252a48a2deb7d5b3db3a81162af41b50
5
5
  SHA512:
6
- metadata.gz: a4bc067e862d142036dcc15721fb7f3cf5084112145676b3884977e5d3e7025f34637eab3520ad2a1f2d524909f5e8a55b7a2bee35c139062cb481ffc64b3071
7
- data.tar.gz: c95602154261e59d7e42fbc94d7afb42f836f54287c4842c0c982a82ced52271ac8c41afbb6cb620865ca948d55971c789c94967f5f18e2af8305271e1c2885b
6
+ metadata.gz: 32f6f70655128b1eb60bcc1add45eb53cd312550a521fd3a7a7663f09f4084809d139ecb2a617464266b12199f590db26bfa240be9c5fb90b6d1e264b1bd57c9
7
+ data.tar.gz: d7b170ae465c6e72e4faa5fde86a216bd8317205c9c1630753f527424aa9e59b60f6f1dca32fcecd242824485f7fc328368d9fd8bcff92658fdfd078a5d4080f
data/README.md CHANGED
@@ -65,7 +65,7 @@ Clients that support chat (e.g. Anthropic w/ "Claude", Google w/ "Gemini", Mistr
65
65
  #### w/ a Simple Prompt
66
66
 
67
67
  ```ruby
68
- completion = client.chat.completion('Tell me a joke.')
68
+ completion = client.chat('Tell me a joke.')
69
69
  puts(completion.choice.message.content) # '...'
70
70
  ```
71
71
 
@@ -82,7 +82,7 @@ messages = [
82
82
  content: 'What is the capital of Canada?',
83
83
  },
84
84
  ]
85
- completion = client.chat.completion(messages, model: '...', temperature: 0.7, format: :json)
85
+ completion = client.chat(messages, model: '...', temperature: 0.7, format: :json)
86
86
  puts(completion.choice.message.content) # '...'
87
87
  ```
88
88
 
@@ -102,7 +102,7 @@ message = {
102
102
  ]
103
103
  }
104
104
 
105
- completion = client.chat.completion(message)
105
+ completion = client.chat(message)
106
106
  puts(completion.choice.message.content) # '...'
107
107
  ```
108
108
 
@@ -112,5 +112,5 @@ puts(completion.choice.message.content) # '...'
112
112
  stream = proc do |chunk|
113
113
  print(chunk.choice.delta.content) # '...'
114
114
  end
115
- client.chat.completion('Tell me a joke.', stream:)
115
+ client.chat('Tell me a joke.', stream:)
116
116
  ```
data/lib/omniai/chat.rb CHANGED
@@ -1,21 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OmniAI
4
- # An abstract class that provides an interface for chatting for various vendors (e.g. OpenAI’s ChatGPT).
4
+ # An abstract class that provides a consistent interface for processing chat requests.
5
5
  #
6
6
  # Usage:
7
7
  #
8
8
  # class OmniAI::OpenAI::Chat < OmniAI::Chat
9
- # def completion(messages, model:, temperature: 0.0, format: :text)
10
- # # TODO: implement
9
+ # module Model
10
+ # GPT_4O = "gpt-4o"
11
11
  # end
12
- # end
13
12
  #
14
- # Once defined, it can be used to interface with the vendor's chat API as follows:
13
+ # protected
15
14
  #
16
- # client.chat.completion("...", model: "...", temperature: 0.0, format: :text)
15
+ # # @return [Hash]
16
+ # def payload
17
+ # raise NotImplementedError, "#{self.class.name}#payload undefined"
18
+ # end
17
19
  #
18
- # @param client [OmniAI::Client] the client
20
+ # # @return [String]
21
+ # def path
22
+ # raise NotImplementedError, "#{self.class.name}#path undefined"
23
+ # end
24
+ # end
25
+ #
26
+ # client.chat(messages, model: "...", temperature: 0.0, format: :text)
19
27
  class Chat
20
28
  JSON_PROMPT = 'Respond with valid JSON. Do not include any non-JSON in the response.'
21
29
 
@@ -25,21 +33,91 @@ module OmniAI
25
33
  SYSTEM = 'system'
26
34
  end
27
35
 
28
- def initialize(client:)
29
- @client = client
36
+ def self.process!(...)
37
+ new(...).process!
30
38
  end
31
39
 
32
- # @raise [OmniAI::Error]
33
- #
34
- # @param messages [String, Array, Hash, OmnniAI::Chat::Message]
35
- # @param model [String] optional
36
- # @param format [Symbol] optional :text or :json
40
+ # @param messages [String] required
41
+ # @param client [OmniAI::Client] the client
42
+ # @param model [String] required
37
43
  # @param temperature [Float, nil] optional
38
44
  # @param stream [Proc, nil] optional
39
- #
40
- # @return [OmniAI::Chat::Request]
41
- def completion(messages, model:, temperature: nil, format: nil, stream: nil)
42
- raise NotImplementedError, "#{self.class.name}#completion undefined"
45
+ # @param format [Symbol, nil] optional - :json
46
+ def initialize(messages, client:, model:, temperature: nil, stream: nil, format: nil)
47
+ @messages = messages
48
+ @client = client
49
+ @model = model
50
+ @temperature = temperature
51
+ @stream = stream
52
+ @format = format
53
+ end
54
+
55
+ # @raise [ExecutionError]
56
+ def process!
57
+ response = request!
58
+ raise HTTPError, response unless response.status.ok?
59
+
60
+ parse!(response:)
61
+ end
62
+
63
+ protected
64
+
65
+ # @return [Hash]
66
+ def payload
67
+ raise NotImplementedError, "#{self.class.name}#payload undefined"
68
+ end
69
+
70
+ # @return [String]
71
+ def path
72
+ raise NotImplementedError, "#{self.class.name}#path undefined"
73
+ end
74
+
75
+ # @param response [HTTP::Response]
76
+ # @return [OmniAI::Chat::Completion]
77
+ def parse!(response:)
78
+ if @stream
79
+ stream!(response:)
80
+ else
81
+ complete!(response:)
82
+ end
83
+ end
84
+
85
+ # @param response [OmniAI::Chat::Completion]
86
+ def complete!(response:)
87
+ Completion.new(data: response.parse)
88
+ end
89
+
90
+ # @param response [HTTP::Response]
91
+ # @return [OmniAI::Chat::Stream]
92
+ def stream!(response:)
93
+ raise Error, "#{self.class.name}#stream! unstreamable" unless @stream
94
+
95
+ Stream.new(response:).stream! { |chunk| @stream.call(chunk) }
96
+ end
97
+
98
+ # @return [Array<Hash>]
99
+ def messages
100
+ arrayify(@messages).map do |content|
101
+ case content
102
+ when String then { role: OmniAI::Chat::Role::USER, content: }
103
+ when Hash then content
104
+ else raise Error, "Unsupported content=#{content.inspect}"
105
+ end
106
+ end
107
+ end
108
+
109
+ # @param value [Object, Array<Object>]
110
+ # @return [Array<Object>]
111
+ def arrayify(value)
112
+ value.is_a?(Array) ? value : [value]
113
+ end
114
+
115
+ # @return [HTTP::Response]
116
+ def request!
117
+ @client
118
+ .connection
119
+ .accept(:json)
120
+ .post(path, json: payload)
43
121
  end
44
122
  end
45
123
  end
data/lib/omniai/client.rb CHANGED
@@ -9,11 +9,6 @@ module OmniAI
9
9
  # def initialize(api_key: ENV.fetch('OPENAI_API_KEY'), logger: nil)
10
10
  # super
11
11
  # end
12
- #
13
- # @return [OmniAI::OpenAI::Chat]
14
- # def chat
15
- # # TODO: implement
16
- # end
17
12
  # end
18
13
  class Client
19
14
  class Error < StandardError; end
@@ -38,8 +33,16 @@ module OmniAI
38
33
  raise NotImplementedError, "#{self.class.name}#connection undefined"
39
34
  end
40
35
 
41
- # @return [OmniAI::Chat] an instance of OmniAI::Chat
42
- def chat
36
+ # @raise [OmniAI::Error]
37
+ #
38
+ # @param messages [String, Array, Hash]
39
+ # @param model [String] optional
40
+ # @param format [Symbol] optional :text or :json
41
+ # @param temperature [Float, nil] optional
42
+ # @param stream [Proc, nil] optional
43
+ #
44
+ # @return [OmniAI::Chat::Completion]
45
+ def chat(messages, model:, temperature: nil, format: nil, stream: nil)
43
46
  raise NotImplementedError, "#{self.class.name}#chat undefined"
44
47
  end
45
48
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OmniAI
4
- VERSION = '1.0.0'
4
+ VERSION = '1.0.2'
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.0.0
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Sylvestre
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-06-14 00:00:00.000000000 Z
11
+ date: 2024-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: event_stream_parser
@@ -72,7 +72,6 @@ files:
72
72
  - lib/omniai/chat/content.rb
73
73
  - lib/omniai/chat/delta.rb
74
74
  - lib/omniai/chat/message.rb
75
- - lib/omniai/chat/request.rb
76
75
  - lib/omniai/chat/stream.rb
77
76
  - lib/omniai/chat/usage.rb
78
77
  - lib/omniai/client.rb
@@ -84,7 +83,7 @@ metadata:
84
83
  homepage_uri: https://github.com/ksylvest/omniai
85
84
  changelog_uri: https://github.com/ksylvest/omniai/releases
86
85
  rubygems_mfa_required: 'true'
87
- post_install_message:
86
+ post_install_message:
88
87
  rdoc_options: []
89
88
  require_paths:
90
89
  - lib
@@ -99,8 +98,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
99
98
  - !ruby/object:Gem::Version
100
99
  version: '0'
101
100
  requirements: []
102
- rubygems_version: 3.5.11
103
- signing_key:
101
+ rubygems_version: 3.5.3
102
+ signing_key:
104
103
  specification_version: 4
105
104
  summary: A generalized framework for interacting with many AI services
106
105
  test_files: []
@@ -1,105 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OmniAI
4
- class Chat
5
- # An abstract class that provides a consistent interface for processing chat requests.
6
- #
7
- # Usage:
8
- #
9
- # class OmniAI::OpenAI::ChatGPT::Request < OmniAI::Chat::Request
10
- # module Model
11
- # CHAT = "davinci"
12
- # end
13
- # def completion(messages, model:, temperature: 0.0, format: :text)
14
- # end
15
- # end
16
- #
17
- # Once defined, the subclass can be used to interface with the vendor's chat API as follows:
18
- #
19
- # client.chat.completion(messages, model: "...", temperature: 0.0, format: :text)
20
- class Request
21
- # @param client [OmniAI::Client] the client
22
- # @param messages [String] required
23
- # @param model [String] required
24
- # @param temperature [Float, nil] optional
25
- # @param stream [Proc, nil] optional
26
- # @param format [Symbol, nil] optional - :json
27
- def initialize(client:, messages:, model:, temperature: nil, stream: nil, format: nil)
28
- @client = client
29
- @messages = messages
30
- @model = model
31
- @temperature = temperature
32
- @stream = stream
33
- @format = format
34
- end
35
-
36
- # @raise [ExecutionError]
37
- def process!
38
- response = request!
39
- raise HTTPError, response unless response.status.ok?
40
-
41
- parse!(response:)
42
- end
43
-
44
- protected
45
-
46
- # @return [Hash]
47
- def payload
48
- raise NotImplementedError, "#{self.class.name}#payload undefined"
49
- end
50
-
51
- # @return [String]
52
- def path
53
- raise NotImplementedError, "#{self.class.name}#path undefined"
54
- end
55
-
56
- # @param response [HTTP::Response]
57
- # @return [OmniAI::Chat::Completion]
58
- def parse!(response:)
59
- if @stream
60
- stream!(response:)
61
- else
62
- complete!(response:)
63
- end
64
- end
65
-
66
- # @param response [OmniAI::Chat::Completion]
67
- def complete!(response:)
68
- Completion.new(data: response.parse)
69
- end
70
-
71
- # @param response [HTTP::Response]
72
- # @return [OmniAI::Chat::Stream]
73
- def stream!(response:)
74
- raise Error, "#{self.class.name}#stream! unstreamable" unless @stream
75
-
76
- Stream.new(response:).stream! { |chunk| @stream.call(chunk) }
77
- end
78
-
79
- # @return [Array<Hash>]
80
- def messages
81
- arrayify(@messages).map do |content|
82
- case content
83
- when String then { role: OmniAI::Chat::Role::USER, content: }
84
- when Hash then content
85
- else raise Error, "Unsupported content=#{content.inspect}"
86
- end
87
- end
88
- end
89
-
90
- # @param value [Object, Array<Object>]
91
- # @return [Array<Object>]
92
- def arrayify(value)
93
- value.is_a?(Array) ? value : [value]
94
- end
95
-
96
- # @return [HTTP::Response]
97
- def request!
98
- @client
99
- .connection
100
- .accept(:json)
101
- .post(path, json: payload)
102
- end
103
- end
104
- end
105
- end