1# frozen_string_literal: true
2
3require "em-http"
4require "em_promise"
5require "json"
6
7class RevAi
8 class Failed < StandardError; end
9
10 def initialize(token: CONFIG[:rev_ai_token])
11 @token = token
12 end
13
14 def stt(language, media_url, callback_url, **kwargs)
15 req(
16 :post,
17 "https://api.rev.ai/speechtotext/v1/jobs",
18 metadata: { media_url: media_url }.merge(kwargs).to_json,
19 source_config: { url: media_url },
20 notification_config: { url: callback_url },
21 remove_disfluencies: language == "en",
22 skip_diarization: true,
23 language: language
24 )
25 end
26
27 def stt_result(job)
28 job = job["job"]
29 return failed(job) if job["status"] == "failed"
30
31 req(
32 :get,
33 "https://api.rev.ai/speechtotext/v1/jobs/#{job['id']}/transcript",
34 accept: "text/plain"
35 ).then do |res|
36 text = res.response.split(" ", 3)[2]&.strip.to_s
37 job.merge("text" => text, "metadata" => JSON.parse(job["metadata"]))
38 end
39 end
40
41 def language_id(media_url, callback_url, **kwargs)
42 req(
43 :post,
44 "https://api.rev.ai/languageid/v1/jobs",
45 metadata: { media_url: media_url }.merge(kwargs).to_json,
46 source_config: { url: media_url },
47 notification_config: { url: callback_url }
48 )
49 end
50
51 def language_id_result(job)
52 job = job["job"]
53 return failed(job) if job["status"] == "failed"
54
55 req(
56 :get,
57 "https://api.rev.ai/languageid/v1/jobs/#{job['id']}/result"
58 ).then do |res|
59 json = JSON.parse(res.response)
60 job.merge(json).merge("metadata" => JSON.parse(job["metadata"]))
61 end
62 end
63
64protected
65
66 def req(m, url, accept: nil, **kwargs)
67 EM::HttpRequest.new(
68 url, tls: { verify_peer: true }
69 ).public_send(
70 "a#{m}",
71 head: {
72 "Authorization" => "Bearer #{@token}",
73 "Content-Type" => "application/json",
74 "Accept" => accept
75 }, body: kwargs.to_json
76 )
77 end
78
79 def failed(job)
80 EMPromise.reject(Failed.new("#{job['failure']} #{job['failure_detail']}"))
81 end
82end