omniai 1.0.0 → 1.0.2

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: 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