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], logger: log)
11 @token = token
12 @log = logger
13 end
14
15 def stt(language, media_url, callback_url, **kwargs)
16 req(
17 :post,
18 "https://api.rev.ai/speechtotext/v1/jobs",
19 metadata: { media_url: media_url }.merge(kwargs).to_json,
20 source_config: { url: media_url },
21 notification_config: { url: callback_url },
22 remove_disfluencies: language == "en",
23 skip_diarization: true,
24 language: language
25 )
26 end
27
28 def stt_result(job, url)
29 job = job["job"]
30 return maybe_retry_as_en(job, url) if job["status"] == "failed"
31
32 req(
33 :get,
34 "https://api.rev.ai/speechtotext/v1/jobs/#{job['id']}/transcript",
35 accept: "text/plain"
36 ).then do |res|
37 text = res.response.split(" ", 3)[2]&.strip.to_s
38 job.merge("text" => text, "metadata" => JSON.parse(job["metadata"]))
39 end
40 end
41
42 def language_id(media_url, callback_url, **kwargs)
43 req(
44 :post,
45 "https://api.rev.ai/languageid/v1/jobs",
46 metadata: { media_url: media_url }.merge(kwargs).to_json,
47 source_config: { url: media_url },
48 notification_config: { url: callback_url }
49 )
50 end
51
52 def language_id_result(job)
53 job = job["job"]
54 return failed(job) if job["status"] == "failed"
55
56 req(
57 :get,
58 "https://api.rev.ai/languageid/v1/jobs/#{job['id']}/result"
59 ).then do |res|
60 json = JSON.parse(res.response)
61 job.merge(json).merge("metadata" => JSON.parse(job["metadata"]))
62 end
63 end
64
65protected
66
67 def req(m, url, accept: nil, **kwargs)
68 EM::HttpRequest.new(
69 url, tls: { verify_peer: true }
70 ).public_send(
71 "a#{m}",
72 head: {
73 "Authorization" => "Bearer #{@token}",
74 "Content-Type" => "application/json",
75 "Accept" => accept
76 }, body: kwargs.to_json
77 )
78 end
79
80 def failed(job)
81 EMPromise.reject(Failed.new("#{job['failure']} #{job['failure_detail']}"))
82 end
83
84 def maybe_retry_as_en(job, url)
85 return failed(job) if job["language"] == "en"
86
87 metadata = JSON.parse(job["metadata"]).transform_keys(&:to_sym)
88 return failed(job) if metadata[:retry]
89
90 retry_as_en(metadata, url)
91 end
92
93 def retry_as_en(metadata, url)
94 @log.info "Retry transcription as EN"
95 stt("en", metadata[:media_url], url, **metadata.merge(retry: true)).then do
96 {}
97 end
98 end
99end