omniai 1.1.2 → 1.1.5

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: facf65abfc03bc2fedc0572bbdebe5baca776da08b3eba9f4bde4b082bf037a7
4
- data.tar.gz: 265613b4ab126f34d68d079241d8f4d2eae96c3e5c4f083aa9ff2761003a5678
3
+ metadata.gz: a82c1b8f8724f5dd7f35239ca2454e4ec7631fa1b8b0544249a49f8b6c52962f
4
+ data.tar.gz: 85e9a9ee74f30ad4c4ba6ef8fbbaa88dc0d31fea6927774d5c7a421e2d38e341
5
5
  SHA512:
6
- metadata.gz: a689d6591eabb97d47fea58a73c2b7fcc133c62aea51180bffe846976086b3819099708757cae85e20c5db3e38964b9dc7c0dc1cbc9fa8b076bc322a56dec4cb
7
- data.tar.gz: bc80184100a4ca2888fb8a0ee3b93ac8d9d301e875e541e692b9a08564eb85fa59d58fcd88e35c4d72142624621ef73174b276c8da95ae53bfcabd1fc1ae776d
6
+ metadata.gz: 42c6324488864562480cf898c8e087ac841d035468a0f4b4dbcd7c86f4239d61ca8361c80e8dcd06ddb9dc565c2e04faa047c2e1342bacf1ac8d2d3825d85b25
7
+ data.tar.gz: cbeef3a03122130ce8c2bf634700df52a2a44aa1c013e8d0f2862379940965326f693f4e87f2704d0dd0a197cddf136cc5cd440d4c36a5a573ba00910845d044
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # OmniAI
2
2
 
3
- OmniAI is a flexible AI library that standardizes the APIs for multipe AI providers:
3
+ [![CircleCI](https://circleci.com/gh/ksylvest/omniai.svg?style=svg)](https://circleci.com/gh/ksylvest/omniai)
4
+
5
+ OmniAI is a flexible AI library that standardizes the APIs for multiple AI providers:
4
6
 
5
7
  - [OmniAI::Anthropic](https://github.com/ksylvest/omniai-anthropic)
6
8
  - [OmniAI::Google](https://github.com/ksylvest/omniai-google)
@@ -29,7 +31,7 @@ OmniAI implements APIs for a number of popular clients by default. A client can
29
31
  #### [OmniAI::Anthropic](https://github.com/ksylvest/omniai-anthropic)
30
32
 
31
33
  ```ruby
32
- require 'omniai-anthropic'
34
+ require 'omniai/anthropic'
33
35
 
34
36
  client = OmniAI::Anthropic::Client.new
35
37
  ```
@@ -37,7 +39,7 @@ client = OmniAI::Anthropic::Client.new
37
39
  #### [OmniAI::Google](https://github.com/ksylvest/omniai-google)
38
40
 
39
41
  ```ruby
40
- require 'omniai-google'
42
+ require 'omniai/google'
41
43
 
42
44
  client = OmniAI::Google::Client.new
43
45
  ```
@@ -45,7 +47,7 @@ client = OmniAI::Google::Client.new
45
47
  #### [OmniAI::Mistral](https://github.com/ksylvest/omniai-mistral)
46
48
 
47
49
  ```ruby
48
- require 'omniai-mistral'
50
+ require 'omniai/mistral'
49
51
 
50
52
  client = OmniAI::Mistral::Client.new
51
53
  ```
@@ -53,7 +55,7 @@ client = OmniAI::Mistral::Client.new
53
55
  #### [OmniAI::OpenAI](https://github.com/ksylvest/omniai-openai)
54
56
 
55
57
  ```ruby
56
- require 'omniai-openai'
58
+ require 'omniai/openai'
57
59
 
58
60
  client = OmniAI::OpenAI::Client.new
59
61
  ```
@@ -62,19 +64,19 @@ client = OmniAI::OpenAI::Client.new
62
64
 
63
65
  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:
64
66
 
65
- #### w/ a Simple Prompt
67
+ #### Completions using Single Message
66
68
 
67
69
  ```ruby
68
70
  completion = client.chat('Tell me a joke.')
69
71
  completion.choice.message.content # '...'
70
72
  ```
71
73
 
72
- #### w/ a Collection of Messages
74
+ #### Completions using Multiple Messages
73
75
 
74
76
  ```ruby
75
77
  messages = [
76
78
  {
77
- role: 'system',
79
+ role: OmniAI::Chat::Role::SYSTEM,
78
80
  content: 'You are a helpful assistant with an expertise in geography.',
79
81
  },
80
82
  'What is the capital of Canada?'
@@ -83,40 +85,53 @@ completion = client.chat(messages, model: '...', temperature: 0.7, format: :json
83
85
  completion.choice.message.content # '...'
84
86
  ```
85
87
 
86
- #### w/ a Collection of Files
88
+ #### Completions using Real-Time Streaming
87
89
 
88
90
  ```ruby
91
+ stream = proc do |chunk|
92
+ print(chunk.choice.delta.content) # '...'
93
+ end
94
+ client.chat('Tell me a joke.', stream:)
95
+ ```
89
96
 
90
- image_a_url = "https://images.unsplash.com/photo-1517849845537-4d257902454a?w=800&h=800&format=jpeg&fit=crop"
91
- image_b_url = "https://images.unsplash.com/photo-1537151625747-768eb6cf92b2?q=80&w=1024&h=1024&format=jpeg"
97
+ ### Transcribe
92
98
 
93
- message = {
94
- role: 'user',
95
- content: [
96
- OmniAI::Chat::Content.new('What are in these images and are they different?'),
97
- OmniAI::Chat::Content.new(image_a_url, type: :image),
98
- OmniAI::Chat::Content.new(image_b_url, type: :image),
99
- ]
100
- }
99
+ Clients that support transcribe (e.g. OpenAI w/ "Whisper") convert recordings to text via the following calls:
101
100
 
102
- completion = client.chat(message)
103
- completion.choice.message.content # '...'
101
+ #### Transcriptions with Path
102
+
103
+ ```ruby
104
+ transcription = client.transcribe("example.ogg")
105
+ transcription.text # '...'
104
106
  ```
105
107
 
106
- #### Streaming
108
+ #### Transcriptions with Files
107
109
 
108
110
  ```ruby
109
- stream = proc do |chunk|
110
- print(chunk.choice.delta.content) # '...'
111
+ File.open("example.ogg", "rb") do |file|
112
+ transcription = client.transcribe(file)
113
+ transcription.text # '...'
111
114
  end
112
- client.chat('Tell me a joke.', stream:)
113
115
  ```
114
116
 
115
- ### Transcribe
117
+ ### Speak
118
+
119
+ Clients that support speak (e.g. OpenAI w/ "Whisper") convert text to recordings via the following calls:
116
120
 
117
- Clients that support chat (e.g. OpenAI w/ "Whisper", etc) convert recordings to text via the following calls:
121
+ #### Speech with Stream
118
122
 
119
123
  ```ruby
120
- transcription = client.transcribe(file.path)
121
- transcription.text # '...'
124
+ File.open('example.ogg', 'wb') do |file|
125
+ client.speak('The quick brown fox jumps over a lazy dog.', voice: 'HAL') do |chunk|
126
+ file << chunk
127
+ end
128
+ end
129
+ ```
130
+
131
+ #### Speech with File
132
+
133
+ ```ruby
134
+ tempfile = client.speak('The quick brown fox jumps over a lazy dog.', voice: 'HAL')
135
+ tempfile.close
136
+ tempfile.unlink
122
137
  ```
@@ -16,7 +16,9 @@ module OmniAI
16
16
  new(index:, delta:, message:)
17
17
  end
18
18
 
19
- # @param data [Hash]
19
+ # @param index [Integer]
20
+ # @param delta [OmniAI::Chat::Delta] optional
21
+ # @param message [OmniAI::Chat::Message] optional
20
22
  def initialize(index:, delta:, message:)
21
23
  @index = index
22
24
  @delta = delta
@@ -36,7 +36,7 @@ module OmniAI
36
36
  @choices ||= @data['choices'].map { |data| Choice.for(data:) }
37
37
  end
38
38
 
39
- # @param [index] [Integer]
39
+ # @param index [Integer]
40
40
  # @return [OmniAI::Chat::Delta]
41
41
  def choice(index: 0)
42
42
  choices[index]
@@ -43,7 +43,7 @@ module OmniAI
43
43
  @choices ||= @data['choices'].map { |data| Choice.for(data:) }
44
44
  end
45
45
 
46
- # @param [index] [Integer] optional - default is 0
46
+ # @param index [Integer] optional - default is 0
47
47
  # @return [OmniAI::Chat::Choice]
48
48
  def choice(index: 0)
49
49
  choices[index]
@@ -6,8 +6,7 @@ module OmniAI
6
6
  class Content
7
7
  attr_accessor :type, :value
8
8
 
9
- # @param url [String]
10
- # @param text [String]
9
+ # @param value [String]
11
10
  # @param type [Symbol] :image / :video / :audio / :text
12
11
  def initialize(value, type: :text)
13
12
  @value = value
@@ -5,7 +5,6 @@ module OmniAI
5
5
  # A stream given when streaming.
6
6
  class Stream
7
7
  # @param response [HTTP::Response]
8
- # @param block [Proc]
9
8
  def initialize(response:)
10
9
  @response = response
11
10
  @parser = EventStreamParser::Parser.new
data/lib/omniai/chat.rb CHANGED
@@ -56,7 +56,7 @@ module OmniAI
56
56
  @format = format
57
57
  end
58
58
 
59
- # @raise [ExecutionError]
59
+ # @raise [HTTPError]
60
60
  def process!
61
61
  response = request!
62
62
  raise HTTPError, response.flush unless response.status.ok?
data/lib/omniai/client.rb CHANGED
@@ -48,7 +48,7 @@ module OmniAI
48
48
 
49
49
  # @raise [OmniAI::Error]
50
50
  #
51
- # @param file [IO]
51
+ # @param io [String, Pathname, IO] required
52
52
  # @param model [String]
53
53
  # @param language [String, nil] optional
54
54
  # @param prompt [String, nil] optional
@@ -56,7 +56,28 @@ module OmniAI
56
56
  # @param format [Symbol] :text, :srt, :vtt, or :json (default)
57
57
  #
58
58
  # @return text [OmniAI::Transcribe::Transcription]
59
- def transcribe(file, model:, language: nil, prompt: nil, temperature: nil, format: nil)
59
+ def transcribe(io, model:, language: nil, prompt: nil, temperature: nil, format: nil)
60
+ raise NotImplementedError, "#{self.class.name}#speak undefined"
61
+ end
62
+
63
+ # @raise [OmniAI::Error]
64
+ #
65
+ # @param input [String] required
66
+ # @param model [String] required
67
+ # @param voice [String] required
68
+ # @param speed [Float] optional
69
+ # @param format [String] optional (default "aac"):
70
+ # - "aac"
71
+ # - "mp3"
72
+ # - "flac"
73
+ # - "opus"
74
+ # - "pcm"
75
+ # - "wav"
76
+ #
77
+ # @yield [output] optional
78
+ #
79
+ # @return [Tempfile``]
80
+ def speak(input, model:, voice:, speed: nil, format: nil, &stream)
60
81
  raise NotImplementedError, "#{self.class.name}#speak undefined"
61
82
  end
62
83
  end
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OmniAI
4
+ # An abstract class that provides a consistent interface for processing speak requests.
5
+ #
6
+ # Usage:
7
+ #
8
+ # class OmniAI::OpenAI::Speak < OmniAI::Speakw
9
+ # module Model
10
+ # WHISPER_1 = "whisper-1"
11
+ # end
12
+ #
13
+ # protected
14
+ #
15
+ # # @return [Hash]
16
+ # def payload
17
+ # raise NotImplementedError, "#{self.class.name}#payload undefined"
18
+ # end
19
+ #
20
+ # # @return [String]
21
+ # def path
22
+ # raise NotImplementedError, "#{self.class.name}#path undefined"
23
+ # end
24
+ # end
25
+ #
26
+ # client.transcribe(File.open("..."), model: "...", format: :json)
27
+ class Speak
28
+ module Format
29
+ AAC = 'aac'
30
+ FLAC = 'flac'
31
+ MP3 = 'mp3'
32
+ OPUS = 'opus'
33
+ PCM = 'pcm'
34
+ WAV = 'wav'
35
+ end
36
+
37
+ # @raise [HTTPError]
38
+ #
39
+ # @param client [OmniAI::Client] required
40
+ # @param input [String] required
41
+ # @param model [String] required
42
+ # @param voice [String] required
43
+ # @param speed [Float] optional
44
+ # @param format [String] optional (default "aac"):
45
+ # - "aac"
46
+ # - "mp3"
47
+ # - "flac"
48
+ # - "opus"
49
+ # - "pcm"
50
+ # - "wav"
51
+ #
52
+ # @yield [chunk]
53
+ #
54
+ # @return [Tempfile]
55
+ def self.process!(input, client:, model:, voice:, speed: nil, format: nil, &)
56
+ new(input, client:, model:, voice:, speed:, format:).process!(&)
57
+ end
58
+
59
+ # @param client [OmniAI::Client] required
60
+ # @param input [String] required
61
+ # @param model [String] required
62
+ # @param voice [String] required
63
+ # @param speed [Float] optional
64
+ # @param format [String] optional (default "aac"):
65
+ # - "aac"
66
+ # - "mp3"
67
+ # - "flac"
68
+ # - "opus"
69
+ # - "pcm"
70
+ # - "wav"
71
+ def initialize(input, client:, model:, voice:, speed: nil, format: nil)
72
+ @input = input
73
+ @client = client
74
+ @model = model
75
+ @voice = voice
76
+ @speed = speed
77
+ @format = format
78
+ end
79
+
80
+ # @raise [HTTPError]
81
+ #
82
+ # @yield [chunk]
83
+ #
84
+ # @return [Tempfile]
85
+ def process!(&block)
86
+ response = request!
87
+ raise HTTPError, response.flush unless response.status.ok?
88
+
89
+ if block
90
+ stream!(response:, &block)
91
+ else
92
+ fetch!(response:)
93
+ end
94
+ end
95
+
96
+ protected
97
+
98
+ # @param response [HTTP::Response]
99
+ #
100
+ # @yield [chunk]
101
+ def stream!(response:, &block)
102
+ response.body.each { |chunk| block.call(chunk) }
103
+ end
104
+
105
+ # @param response [HTTP::Response]
106
+ #
107
+ # @return [Tempfile]
108
+ def fetch!(response:)
109
+ tempfile = Tempfile.new(['', ".#{@format}"])
110
+ tempfile.binmode
111
+ response.body.each { |chunk| tempfile << chunk }
112
+ tempfile.rewind
113
+ tempfile
114
+ end
115
+
116
+ # @return [Hash]
117
+ def payload
118
+ {
119
+ model: @model,
120
+ voice: @voice,
121
+ input: @input,
122
+ speed: @speed,
123
+ }.compact
124
+ end
125
+
126
+ # @return [String]
127
+ def path
128
+ raise NotImplementedError, "#{self.class.name}#path undefined"
129
+ end
130
+
131
+ # @return [HTTP::Response]
132
+ def request!
133
+ @client
134
+ .connection
135
+ .post(path, json: payload)
136
+ end
137
+ end
138
+ end
@@ -96,15 +96,15 @@ module OmniAI
96
96
  new(...).process!
97
97
  end
98
98
 
99
- # @param path [String] required
99
+ # @param io [String, Pathname, IO] required
100
100
  # @param client [OmniAI::Client] the client
101
101
  # @param model [String] required
102
102
  # @param language [String, nil] optional
103
103
  # @param prompt [String, nil] optional
104
104
  # @param temperature [Float, nil] optional
105
105
  # @param format [String, nil] optional
106
- def initialize(path, client:, model:, language: nil, prompt: nil, temperature: nil, format: Format::JSON)
107
- @path = path
106
+ def initialize(io, client:, model:, language: nil, prompt: nil, temperature: nil, format: Format::JSON)
107
+ @io = io
108
108
  @model = model
109
109
  @language = language
110
110
  @prompt = prompt
@@ -113,8 +113,8 @@ module OmniAI
113
113
  @client = client
114
114
  end
115
115
 
116
+ # @raise [HTTPError]
116
117
  # @return [OmniAI::Transcribe::Transcription]
117
- # @raise [ExecutionError]
118
118
  def process!
119
119
  response = request!
120
120
  raise HTTPError, response.flush unless response.status.ok?
@@ -128,7 +128,7 @@ module OmniAI
128
128
  # @return [Hash]
129
129
  def payload
130
130
  {
131
- file: HTTP::FormData::File.new(@path),
131
+ file: HTTP::FormData::File.new(@io),
132
132
  model: @model,
133
133
  language: @language,
134
134
  prompt: @prompt,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OmniAI
4
- VERSION = '1.1.2'
4
+ VERSION = '1.1.5'
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.1.2
4
+ version: 1.1.5
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-17 00:00:00.000000000 Z
11
+ date: 2024-06-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: event_stream_parser
@@ -76,11 +76,13 @@ files:
76
76
  - lib/omniai/chat/usage.rb
77
77
  - lib/omniai/client.rb
78
78
  - lib/omniai/config.rb
79
+ - lib/omniai/speak.rb
79
80
  - lib/omniai/transcribe.rb
80
81
  - lib/omniai/transcribe/transcription.rb
81
82
  - lib/omniai/version.rb
82
83
  homepage: https://github.com/ksylvest/omniai
83
- licenses: []
84
+ licenses:
85
+ - MIT
84
86
  metadata:
85
87
  homepage_uri: https://github.com/ksylvest/omniai
86
88
  changelog_uri: https://github.com/ksylvest/omniai/releases