-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
280 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
PATH | ||
remote: . | ||
specs: | ||
omniai (1.0.9) | ||
omniai (1.1.0) | ||
event_stream_parser | ||
http | ||
zeitwerk | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
# frozen_string_literal: true | ||
|
||
module OmniAI | ||
# An abstract class that provides a consistent interface for processing transcribe requests. | ||
# | ||
# Usage: | ||
# | ||
# class OmniAI::OpenAI::Transcribe < OmniAI::Transcribe | ||
# module Model | ||
# WHISPER_1 = "whisper-1" | ||
# end | ||
# | ||
# protected | ||
# | ||
# # @return [Hash] | ||
# def payload | ||
# raise NotImplementedError, "#{self.class.name}#payload undefined" | ||
# end | ||
# | ||
# # @return [String] | ||
# def path | ||
# raise NotImplementedError, "#{self.class.name}#path undefined" | ||
# end | ||
# end | ||
# | ||
# client.transcribe(File.open("..."), model: "...", format: :json) | ||
class Transcribe | ||
module Language | ||
AFRIKAANS = 'af' | ||
ARABIC = 'ar' | ||
ARMENIAN = 'hy' | ||
AZERBAIJANI = 'az' | ||
BELARUSIAN = 'be' | ||
BOSNIAN = 'bs' | ||
BULGARIAN = 'bg' | ||
CATALAN = 'ca' | ||
CHINESE = 'zh' | ||
CROATIAN = 'hr' | ||
CZECH = 'cs' | ||
DANISH = 'da' | ||
DUTCH = 'nl' | ||
ENGLISH = 'en' | ||
ESTONIAN = 'et' | ||
FINNISH = 'fi' | ||
FRENCH = 'fr' | ||
GALICIAN = 'gl' | ||
GERMAN = 'de' | ||
GREEK = 'el' | ||
HEBREW = 'he' | ||
HINDI = 'hi' | ||
HUNGARIAN = 'hu' | ||
ICELANDIC = 'is' | ||
INDONESIAN = 'id' | ||
ITALIAN = 'it' | ||
JAPANESE = 'ja' | ||
KANNADA = 'kn' | ||
KAZAKH = 'kk' | ||
KOREAN = 'ko' | ||
LATVIAN = 'lv' | ||
LITHUANIAN = 'lt' | ||
MACEDONIAN = 'mk' | ||
MALAY = 'ms' | ||
MARATHI = 'mr' | ||
MAORI = 'mi' | ||
NEPALI = 'ne' | ||
NORWEGIAN = 'no' | ||
PERSIAN = 'fa' | ||
POLISH = 'pl' | ||
PORTUGUESE = 'pt' | ||
ROMANIAN = 'ro' | ||
RUSSIAN = 'ru' | ||
SERBIAN = 'sr' | ||
SLOVAK = 'sk' | ||
SLOVENIAN = 'sl' | ||
SPANISH = 'es' | ||
SWAHILI = 'sw' | ||
SWEDISH = 'sv' | ||
TAGALOG = 'tl' | ||
TAMIL = 'ta' | ||
THAI = 'th' | ||
TURKISH = 'tr' | ||
UKRAINIAN = 'uk' | ||
URDU = 'ur' | ||
VIETNAMESE = 'vi' | ||
WELSH = 'cy' | ||
end | ||
|
||
module Format | ||
JSON = 'json' | ||
TEXT = 'text' | ||
VTT = 'vtt' | ||
SRT = 'srt' | ||
end | ||
|
||
def self.process!(...) | ||
new(...).process! | ||
end | ||
|
||
# @param path [String] required | ||
# @param client [OmniAI::Client] the client | ||
# @param model [String] required | ||
# @param language [String, nil] optional | ||
# @param prompt [String, nil] optional | ||
# @param temperature [Float, nil] optional | ||
# @param format [String, nil] optional | ||
def initialize(path, client:, model:, language: nil, prompt: nil, temperature: nil, format: Format::JSON) | ||
@path = path | ||
@model = model | ||
@language = language | ||
@prompt = prompt | ||
@temperature = temperature | ||
@format = format | ||
@client = client | ||
end | ||
|
||
# @return [OmniAI::Transcribe::Transcription] | ||
# @raise [ExecutionError] | ||
def process! | ||
response = request! | ||
raise HTTPError, response.flush unless response.status.ok? | ||
|
||
data = @format.eql?(Format::JSON) ? response.parse : { text: String(response.body) } | ||
Transcription.new(format: @format, data:) | ||
end | ||
|
||
protected | ||
|
||
# @return [Hash] | ||
def payload | ||
{ | ||
file: HTTP::FormData::File.new(@path), | ||
model: @model, | ||
language: @language, | ||
prompt: @prompt, | ||
temperature: @temperature, | ||
}.compact | ||
end | ||
|
||
# @return [String] | ||
def path | ||
raise NotImplementedError, "#{self.class.name}#path undefined" | ||
end | ||
|
||
# @return [HTTP::Response] | ||
def request! | ||
@client | ||
.connection | ||
.accept(@format.eql?(Format::JSON) ? :json : :text) | ||
.post(path, form: payload) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# frozen_string_literal: true | ||
|
||
module OmniAI | ||
class Transcribe | ||
# A transcription returned by the API. | ||
class Transcription | ||
attr_accessor :data, :format | ||
|
||
# @param data [Hash] | ||
def initialize(data:, format:) | ||
@data = data | ||
@format = format | ||
end | ||
|
||
# @return [String] | ||
def text | ||
@data['text'] | ||
end | ||
|
||
# @return [String] | ||
def inspect | ||
"#<#{self.class} text=#{text.inspect} format=#{format.inspect}>" | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
# frozen_string_literal: true | ||
|
||
module OmniAI | ||
VERSION = '1.0.9' | ||
VERSION = '1.1.0' | ||
end |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# frozen_string_literal: true | ||
|
||
RSpec.describe OmniAI::Transcribe::Transcription do | ||
subject(:transcription) { described_class.new(format: OmniAI::Transcribe::Format::JSON, data: { 'text' => 'Hi!' }) } | ||
|
||
describe '#format' do | ||
it { expect(transcription.format).to eq('json') } | ||
end | ||
|
||
describe '#text' do | ||
it { expect(transcription.text).to eq('Hi!') } | ||
end | ||
|
||
describe '#inspect' do | ||
it { expect(transcription.inspect).to eq('#<OmniAI::Transcribe::Transcription text="Hi!" format="json">') } | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
# frozen_string_literal: true | ||
|
||
class FakeClient < OmniAI::Client | ||
def connection | ||
HTTP.persistent('http://localhost:8080') | ||
end | ||
end | ||
|
||
class FakeTranscribe < OmniAI::Transcribe | ||
module Model | ||
FAKE = 'fake' | ||
end | ||
|
||
def path | ||
'/transcribe' | ||
end | ||
end | ||
|
||
RSpec.describe OmniAI::Transcribe do | ||
subject(:transcribe) { described_class.new(path, model:, client:) } | ||
|
||
let(:model) { '...' } | ||
let(:client) { OmniAI::Client.new(api_key: '...') } | ||
let(:path) { Pathname.new(File.dirname(__FILE__)).join('..', 'fixtures', 'file.ogg') } | ||
|
||
describe '#path' do | ||
it { expect { transcribe.send(:path) }.to raise_error(NotImplementedError) } | ||
end | ||
|
||
describe '.process!' do | ||
subject(:process!) { FakeTranscribe.process!(path, client:, model:) } | ||
|
||
let(:client) { FakeClient.new(api_key: '...') } | ||
let(:model) { FakeTranscribe::Model::FAKE } | ||
|
||
context 'when OK' do | ||
before do | ||
stub_request(:post, 'http://localhost:8080/transcribe') | ||
.to_return_json(status: 200, body: { | ||
text: 'Hi!', | ||
}) | ||
end | ||
|
||
it { expect(process!).to be_a(OmniAI::Transcribe::Transcription) } | ||
it { expect(process!.text).to eq('Hi!') } | ||
end | ||
|
||
context 'when UNPROCESSABLE' do | ||
before do | ||
stub_request(:post, 'http://localhost:8080/transcribe') | ||
.to_return(status: 422, body: 'An unknown error occurred.') | ||
end | ||
|
||
it { expect { process! }.to raise_error(OmniAI::HTTPError) } | ||
end | ||
end | ||
end |