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