omniai 0.0.8 → 0.1.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: b478ff0decf827e07f67c3c85973ad576f546980417f82ff5f71949c99157e22
4
- data.tar.gz: edcd0f60037d10fca5aec3ecc6cbd08c0c9b1c42aa9353506c232821cbd0fe0f
3
+ metadata.gz: 7f87f1b50c279a434ef7c23fb84f66321450897a62c9db0eda70659e3ac024a6
4
+ data.tar.gz: 334d3055c491bb582107b62ff555bba9bd175d9a23d7492cbfb07bdae4a1b876
5
5
  SHA512:
6
- metadata.gz: 69d8116cf9313da66fc89857332d8efb9e2005f007474dd377ec8c34ffb5c18e22155740390acb793f255447399f176605f0306e94c99c0e160346581fd1e597
7
- data.tar.gz: 5c7975664071ff8158d5fd9e33fac37f7874b856d319edb0555deeefb78ac70e1dd7c13ffde015a5b0029c4b1ad26554d34ba0ca294bbf8acc81365adef1705c
6
+ metadata.gz: c6ed29f063e505bf58ad6ca19f8d4dace1627f73fb3bee8b52fb5f9756d550f3ff322e7ef00d286044eaa9a0b48a16811e62efb70c130948302834e9206a362d
7
+ data.tar.gz: 512fa19f0b5cb1c67a081d413bdf8e9b964716f08151fc20b048f5c2b46edc4eb8ec891563eb510c98e7ae5749c63afbbb661546718ec219f1287592c1f351da
data/README.md CHANGED
@@ -22,44 +22,57 @@ gem install omniai-openai
22
22
 
23
23
  ## Usage
24
24
 
25
- ### Chat
25
+ OmniAI implements APIs for a number of popular clients by default. A client can be initialized using the specific gem (e.g. `omniai-openai` for `OmniAI::OpenAI`). Vendor specific docs can be found within each repo.
26
+
27
+ ### Client
26
28
 
27
- #### Anthropic (Claude)
29
+ #### [OmniAI::Anthropic](https://github.com/ksylvest/omniai-anthropic)
28
30
 
29
31
  ```ruby
30
32
  require 'omniai-anthropic'
31
33
 
32
34
  client = OmniAI::Anthropic::Client.new
33
- completion = client.chat.completion('Tell me a joke.')
34
- completion.choice.message.content # '...'
35
35
  ```
36
36
 
37
- #### Google (Gemini)
37
+ #### [OmniAI::Google](https://github.com/ksylvest/omniai-google)
38
38
 
39
39
  ```ruby
40
40
  require 'omniai-google'
41
41
 
42
42
  client = OmniAI::Google::Client.new
43
- completion = client.chat.completion('Tell me a joke.')
44
- completion.choice.message.content # '...'
45
43
  ```
46
44
 
47
- #### Mistral (LeChat)
45
+ #### [OmniAI::Mistral](https://github.com/ksylvest/omniai-mistral)
48
46
 
49
47
  ```ruby
50
48
  require 'omniai-mistral'
51
49
 
52
50
  client = OmniAI::Mistral::Client.new
53
- completion = client.chat.completion('Tell me a joke.')
54
- completion.choice.message.content # '...'
55
51
  ```
56
52
 
57
- #### OpenAI (ChatGPT)
53
+ #### [OmniAI::OpenAI](https://github.com/ksylvest/omniai-openai)
58
54
 
59
55
  ```ruby
60
56
  require 'omniai-openai'
61
57
 
62
58
  client = OmniAI::OpenAI::Client.new
59
+ ```
60
+
61
+ ### Chat
62
+
63
+ Clients that support chat (e.g. Anthropic w/ "Claude", Google w/ "Gemini", Mistral w/ "LeChat", OpenAI w/ "ChatGPT", etc) can generate completions using either a basic or streaming API:
64
+
65
+ #### Basic
66
+
67
+ ```ruby
63
68
  completion = client.chat.completion('Tell me a joke.')
64
- completion.choice.message.content # '...'
69
+ puts(completion.choice.message.content) # '...'
70
+ ```
71
+
72
+ #### Streaming
73
+
74
+ ```ruby
75
+ client.chat.completion 'Tell me a joke.', stream: proc do |chunk|
76
+ print(chunk.choice.delta.content) # '...'
77
+ end
65
78
  ```
@@ -4,14 +4,26 @@ module OmniAI
4
4
  class Chat
5
5
  # A choice returned by the API.
6
6
  class Choice
7
- attr_accessor :index, :message, :role
7
+ attr_accessor :data
8
8
 
9
- # @param index [Integer]
10
- # @param message [OmniAI::Chat::Message]
11
- # @param role [String]
12
- def initialize(index:, message:)
13
- @index = index
14
- @message = message
9
+ # @param data [Hash]
10
+ def initialize(data:)
11
+ @data = data
12
+ end
13
+
14
+ # @return [Integer]
15
+ def index
16
+ @data['index']
17
+ end
18
+
19
+ # @return [OmniAI::Chat::Delta]
20
+ def delta
21
+ Delta.new(data: @data['delta']) if @data['delta']
22
+ end
23
+
24
+ # @return [OmniAI::Chat::Message]
25
+ def message
26
+ Message.new(data: @data['message']) if @data['message']
15
27
  end
16
28
  end
17
29
  end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OmniAI
4
+ class Chat
5
+ # A chunk returned by the API.
6
+ class Chunk
7
+ attr_accessor :data
8
+
9
+ # @param data [Hash]
10
+ def initialize(data:)
11
+ @data = data
12
+ end
13
+
14
+ # @return [String]
15
+ def id
16
+ @data['id']
17
+ end
18
+
19
+ # @return [Time]
20
+ def created
21
+ Time.at(@data['created']) if @data['created']
22
+ end
23
+
24
+ # @return [Time]
25
+ def updated
26
+ Time.at(@data['updated']) if @data['updated']
27
+ end
28
+
29
+ # @return [String]
30
+ def model
31
+ @data['model']
32
+ end
33
+
34
+ # @param [index] [Integer]
35
+ # @return [OmniAI::Chat::Delta]
36
+ def choice(index: 0)
37
+ choices[index]
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OmniAI
4
+ class Chat
5
+ # A completion returned by the API.
6
+ class Completion
7
+ attr_accessor :data
8
+
9
+ # @param data [Hash]
10
+ def initialize(data:)
11
+ @data = data
12
+ end
13
+
14
+ # @return [String]
15
+ def id
16
+ @data['id']
17
+ end
18
+
19
+ # @return [Time]
20
+ def created
21
+ Time.at(@data['created']) if @data['created']
22
+ end
23
+
24
+ # @return [Time]
25
+ def updated
26
+ Time.at(@data['updated']) if @data['updated']
27
+ end
28
+
29
+ # @return [String]
30
+ def model
31
+ @data['model']
32
+ end
33
+
34
+ # @return [OmniAI::Chat::Usage]
35
+ def usage
36
+ @usage ||= Usage.new(data: @data['usage']) if @data['usage']
37
+ end
38
+
39
+ # @return [Array<OmniAI::Chat::Choice>]
40
+ def choices
41
+ @choices ||= @data['choices'].map { |choice| Choice.new(data: choice) }
42
+ end
43
+
44
+ # @param [index] [Integer] optional - default is 0
45
+ # @return [OmniAI::Chat::Choice]
46
+ def choice(index: 0)
47
+ choices[index]
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OmniAI
4
+ class Chat
5
+ # A delta returned by the API.
6
+ class Delta
7
+ attr_accessor :data
8
+
9
+ # @param content [Integer]
10
+ # @param role [String]
11
+ def initialize(data:)
12
+ @data = data
13
+ end
14
+
15
+ # @return [String, nil]
16
+ def role
17
+ @data['role']
18
+ end
19
+
20
+ # @return [String, nil]
21
+ def content
22
+ @data['content']
23
+ end
24
+ end
25
+ end
26
+ end
@@ -4,13 +4,22 @@ module OmniAI
4
4
  class Chat
5
5
  # A message returned by the API.
6
6
  class Message
7
- attr_accessor :content, :role
7
+ attr_accessor :data
8
8
 
9
9
  # @param content [Integer]
10
10
  # @param role [String]
11
- def initialize(content:, role:)
12
- @content = content
13
- @role = role
11
+ def initialize(data:)
12
+ @data = data
13
+ end
14
+
15
+ # @return [String]
16
+ def role
17
+ @data['role']
18
+ end
19
+
20
+ # @return [String]
21
+ def content
22
+ @data['content']
14
23
  end
15
24
  end
16
25
  end
@@ -46,7 +46,26 @@ module OmniAI
46
46
  # @param response [HTTP::Response]
47
47
  # @return [OmniAI::Chat::Completion::Response]
48
48
  def parse!(response:)
49
- raise NotImplementedError, "#{self.class.name}#parse! undefined"
49
+ if @stream
50
+ stream!(response:)
51
+ else
52
+ OmniAI::OpenAI::Chat::Completion.new(data: response.parse)
53
+ end
54
+ end
55
+
56
+ # @param response [HTTP::Response]
57
+ # @return [OmniAI::Chat::Chunk]
58
+ def stream!(response:)
59
+ parser = EventStreamParser::Parser.new
60
+
61
+ response.body.each do |chunk|
62
+ parser.feed(chunk) do |_, data|
63
+ break if data.eql?('[DONE]')
64
+
65
+ chunk = OmniAI::OpenAI::Chat::Chunk.new(data: data.parse)
66
+ @stream.call(chunk)
67
+ end
68
+ end
50
69
  end
51
70
 
52
71
  # @return [Hash]
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OmniAI
4
+ class Chat
5
+ # A usage returned by the API.
6
+ class Completion
7
+ attr_accessor :data
8
+
9
+ # @param data [Hash]
10
+ def initialize(data:)
11
+ @data = data
12
+ end
13
+
14
+ # @return [Integer]
15
+ def completion_tokens
16
+ @data['completion_tokens']
17
+ end
18
+
19
+ # @return [Integer]
20
+ def prompt_tokens
21
+ @data['prompt_tokens']
22
+ end
23
+
24
+ # @return [Integer]
25
+ def total_tokens
26
+ @data['total_tokens']
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OmniAI
4
- VERSION = '0.0.8'
4
+ VERSION = '0.1.0'
5
5
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omniai
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.1.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-11 00:00:00.000000000 Z
11
+ date: 2024-06-12 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: event_stream_parser
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: http
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -53,10 +67,12 @@ files:
53
67
  - lib/omniai.rb
54
68
  - lib/omniai/chat.rb
55
69
  - lib/omniai/chat/choice.rb
70
+ - lib/omniai/chat/chunk.rb
71
+ - lib/omniai/chat/completion.rb
72
+ - lib/omniai/chat/delta.rb
56
73
  - lib/omniai/chat/message.rb
57
74
  - lib/omniai/chat/request.rb
58
- - lib/omniai/chat/response.rb
59
- - lib/omniai/chat/stream.rb
75
+ - lib/omniai/chat/usage.rb
60
76
  - lib/omniai/client.rb
61
77
  - lib/omniai/version.rb
62
78
  homepage: https://github.com/ksylvest/omniai
@@ -1,34 +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 responses.
6
- #
7
- # Usage:
8
- #
9
- # class OmniAI::OpenAI::Chat::Response < OmniAI::Chat::Response
10
- # def choices
11
- # # TODO: implement
12
- # end
13
- # end
14
- class Response
15
- attr_accessor :data
16
-
17
- # @param data [Hash]
18
- def initialize(data:)
19
- @data = data
20
- end
21
-
22
- # @param [index] [Integer]
23
- # @return [OmniAI::Chat::Choice]
24
- def choice(index: 0)
25
- choices[index]
26
- end
27
-
28
- # @return [Array<OmniAI::Chat::Choice>]
29
- def choices
30
- raise NotImplementedError, "#{self.class.name}#choices undefined"
31
- end
32
- end
33
- end
34
- end
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OmniAI
4
- class Chat
5
- # A processor for streaming back events in chunks.
6
- class Stream
7
- LINE_REGEX = /data:\s*(?<data>.*)\n\n/
8
-
9
- def initialize
10
- @buffer = String.new
11
- end
12
-
13
- # @yield [data] a parsed hash
14
- # @param [String] chunk
15
- def process!(chunk)
16
- @buffer << chunk
17
-
18
- while (line = @buffer.slice!(LINE_REGEX))
19
- match = LINE_REGEX.match(line)
20
- data = match[:data]
21
- break if data.eql?('[DONE]')
22
-
23
- yield JSON.parse(data)
24
- end
25
- end
26
- end
27
- end
28
- end