lara-sdk 1.5.2 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 16d7ebfcc581f7cf377274d58579d0d306eb98c83907c28de3de277fefe0c40f
4
- data.tar.gz: 5ae057fa1538580898d922d41f387fcd6d583726eb98fde453811f0fc0d6a3de
3
+ metadata.gz: 6a3b69ad7aedd5fba6abf61cd338174f91c6784780afb48ed888f2d6781c225f
4
+ data.tar.gz: 8f736b1507a97c1da997e8136bf6407de5e3a687c704573397284ea093c4fa2b
5
5
  SHA512:
6
- metadata.gz: 61f703c0ac1fa6059d3f58181ba65d1252a687085e7106b808377da35c13aa7b8f1380d612e451e0e1d2d1dbf734e21cce9cae409fc522d8dca113890a19161b
7
- data.tar.gz: be6e69b110dbeefe2093f47aa8e741dd6d4c8fe014b4b3c0b3e66cc4929d313a8832cf5f93c4d7c0af50e18ba11d6d592f8f0bb5a059d7d71437de5fbd64d7be
6
+ metadata.gz: ed938c0f7ddd966f7307cb13c33500931d2e5f87d10cdd4590b999b37b660148b95a7d5e73a73b0d69eafc464eb98a1c8a03e3b533cfd362f8e434aca995db96
7
+ data.tar.gz: c3b778924d5b7e09ddf9efff21aed919579cf86df566ada5f96a044c043f6bf3e3fc529ee81c2c7f34c84d576f7f628b07a08719fcf1eadbef3dc7becf34e9c5
data/lib/lara/audio.rb CHANGED
@@ -25,7 +25,7 @@ module Lara
25
25
  # Uploads an audio file to S3 and creates a translation job.
26
26
  # @return [Lara::Models::Audio]
27
27
  def upload(file_path:, filename:, target:, source: nil, adapt_to: nil, glossaries: nil,
28
- no_trace: false, style: nil, voice_gender: nil)
28
+ no_trace: false, style: nil, voice_gender: nil, voice_cloning: nil)
29
29
  response_data = @client.get("/v2/audio/upload-url", params: { filename: filename })
30
30
  url = response_data["url"]
31
31
  fields = response_data["fields"]
@@ -39,6 +39,7 @@ module Lara
39
39
  adapt_to: adapt_to,
40
40
  glossaries: glossaries,
41
41
  style: style,
42
+ voice_cloning: voice_cloning,
42
43
  voice_gender: voice_gender
43
44
  }.compact
44
45
 
@@ -68,10 +69,10 @@ module Lara
68
69
  # Translates an audio file end-to-end
69
70
  # @return [String] translated audio bytes
70
71
  def translate(file_path:, filename:, target:, source: nil, adapt_to: nil, glossaries: nil,
71
- no_trace: false, style: nil, voice_gender: nil)
72
+ no_trace: false, style: nil, voice_gender: nil, voice_cloning: nil)
72
73
  audio = upload(file_path: file_path, filename: filename, target: target, source: source,
73
74
  adapt_to: adapt_to, glossaries: glossaries, no_trace: no_trace, style: style,
74
- voice_gender: voice_gender)
75
+ voice_gender: voice_gender, voice_cloning: voice_cloning)
75
76
 
76
77
  max_wait_time = 60 * 15 # 15 minutes
77
78
  start = Time.now
@@ -93,6 +94,76 @@ module Lara
93
94
  end
94
95
  end
95
96
 
97
+ # Uploads an audio file to S3 and creates a transcript translation job.
98
+ # @return [Lara::Models::Audio]
99
+ def upload_for_transcription(file_path:, filename:, target:, source: nil, adapt_to: nil, glossaries: nil,
100
+ no_trace: false, style: nil)
101
+ response_data = @client.get("/v2/audio/upload-url", params: { filename: filename })
102
+ url = response_data["url"]
103
+ fields = response_data["fields"]
104
+
105
+ @s3.upload(url: url, fields: fields, io: file_path)
106
+
107
+ body = {
108
+ s3key: fields["key"],
109
+ target: target,
110
+ source: source,
111
+ adapt_to: adapt_to,
112
+ glossaries: glossaries,
113
+ style: style
114
+ }.compact
115
+
116
+ headers = {}
117
+ headers["X-No-Trace"] = "true" if no_trace
118
+
119
+ response = @client.post("/v2/audio/translate-transcript", body: body, headers: headers)
120
+ response_params = response.transform_keys(&:to_sym)
121
+ Lara::Models::Audio.new(**filter_audio_params(response_params))
122
+ end
123
+
124
+ # Retrieves the translated transcript JSON.
125
+ # @return [Lara::Models::AudioTextResult]
126
+ def get_translated_transcript(id)
127
+ response = @client.get("/v2/audio/#{id}/translated-transcript")
128
+ Lara::Models::AudioTextResult.new(
129
+ id: response["id"],
130
+ source: response["source"],
131
+ target: response["target"],
132
+ filename: response["filename"],
133
+ duration: response["duration"],
134
+ text: response["text"],
135
+ translation: response["translation"],
136
+ segments: response["segments"]
137
+ )
138
+ end
139
+
140
+ # Translates an audio transcript end-to-end
141
+ # @return [Lara::Models::AudioTextResult]
142
+ def translate_transcript(file_path:, filename:, target:, source: nil, adapt_to: nil, glossaries: nil,
143
+ no_trace: false, style: nil)
144
+ audio = upload_for_transcription(file_path: file_path, filename: filename, target: target, source: source,
145
+ adapt_to: adapt_to, glossaries: glossaries, no_trace: no_trace, style: style)
146
+
147
+ max_wait_time = 60 * 15 # 15 minutes
148
+ start = Time.now
149
+
150
+ loop do |_|
151
+ current = status(audio.id)
152
+
153
+ case current.status
154
+ when Lara::Models::AudioStatus::TRANSLATED
155
+ return get_translated_transcript(current.id)
156
+ when Lara::Models::AudioStatus::ERROR
157
+ raise Lara::LaraApiError.new(500, "AudioError",
158
+ current.error_reason || "Unknown error")
159
+ end
160
+
161
+ raise Timeout::Error if Time.now - start > max_wait_time
162
+
163
+ sleep @polling_interval
164
+ end
165
+ end
166
+
96
167
  private
97
168
 
98
169
  def filter_audio_params(params)
data/lib/lara/client.rb CHANGED
@@ -16,7 +16,7 @@ module Lara
16
16
  DEFAULT_BASE_URL = "https://api.laratranslate.com"
17
17
 
18
18
  def initialize(auth_method, base_url: DEFAULT_BASE_URL, connection_timeout: nil,
19
- read_timeout: nil)
19
+ read_timeout: nil, session_id: nil)
20
20
  case auth_method
21
21
  when Credentials
22
22
  @credentials = auth_method
@@ -31,6 +31,7 @@ module Lara
31
31
  @base_url = base_url.to_s.sub(%r{/+$}, "")
32
32
  @connection_timeout = connection_timeout
33
33
  @read_timeout = read_timeout
34
+ @session_id = session_id
34
35
  @extra_headers = {}
35
36
  @auth_mutex = Monitor.new
36
37
 
@@ -148,6 +149,8 @@ module Lara
148
149
  'application/json', timestamp)}"
149
150
  }
150
151
 
152
+ headers["X-Lara-Auth-Session-Id"] = @session_id if @session_id && !@session_id.empty?
153
+
151
154
  conn = Faraday.new(url: @base_url) do |c|
152
155
  c.adapter Faraday.default_adapter
153
156
  end
@@ -52,5 +52,52 @@ module Lara
52
52
  @error_reason = error_reason
53
53
  end
54
54
  end
55
+
56
+ # Audio text segment for transcript results
57
+ class AudioTextSegment < Base
58
+ attr_reader :id, :start, :text, :translation
59
+
60
+ # JSON field is "end"; expose as #end to match the wire contract / other SDKs.
61
+ attr_reader :end
62
+
63
+ def initialize(id: nil, start: nil, end_time: nil, text: nil, translation: nil, **kwargs)
64
+ super()
65
+ @id = id
66
+ @start = start
67
+ @end = end_time.nil? ? (kwargs[:end] || kwargs["end"]) : end_time
68
+ @text = text
69
+ @translation = translation
70
+ end
71
+ end
72
+
73
+ # Audio text result for transcript translation
74
+ class AudioTextResult < Base
75
+ attr_reader :id, :source, :target, :filename, :duration, :text, :translation, :segments
76
+
77
+ def initialize(id: nil, source: nil, target: nil, filename: nil, duration: nil, text: nil,
78
+ translation: nil, segments: nil, **_kwargs)
79
+ super()
80
+ @id = id
81
+ @source = source
82
+ @target = target
83
+ @filename = filename
84
+ @duration = duration
85
+ @text = text
86
+ @translation = translation
87
+ @segments = Array(segments).map do |seg|
88
+ if seg.is_a?(Hash)
89
+ AudioTextSegment.new(
90
+ id: seg["id"] || seg[:id],
91
+ start: seg["start"] || seg[:start],
92
+ end_time: seg["end"] || seg[:end],
93
+ text: seg["text"] || seg[:text],
94
+ translation: seg["translation"] || seg[:translation]
95
+ )
96
+ else
97
+ seg
98
+ end
99
+ end
100
+ end
101
+ end
55
102
  end
56
103
  end
@@ -11,8 +11,9 @@ module Lara
11
11
  # @param base_url [String,nil]
12
12
  # @param connection_timeout [Integer,nil]
13
13
  # @param read_timeout [Integer,nil]
14
+ # @param session_id [String,nil]
14
15
  def initialize(credentials: nil, auth_token: nil, access_key_id: nil, access_key_secret: nil,
15
- base_url: nil, connection_timeout: nil, read_timeout: nil)
16
+ base_url: nil, connection_timeout: nil, read_timeout: nil, session_id: nil)
16
17
  auth_method = if auth_token
17
18
  auth_token
18
19
  elsif credentials
@@ -25,7 +26,8 @@ module Lara
25
26
  end
26
27
 
27
28
  @client = Client.new(auth_method, base_url: base_url,
28
- connection_timeout: connection_timeout, read_timeout: read_timeout)
29
+ connection_timeout: connection_timeout, read_timeout: read_timeout,
30
+ session_id: session_id)
29
31
  @memories = Memories.new(@client)
30
32
  @glossaries = Glossaries.new(@client)
31
33
  @styleguides = Styleguides.new(@client)
@@ -140,7 +142,8 @@ module Lara
140
142
  # @return [Lara::Models::ProfanityDetectResult]
141
143
  def detect_profanities(text, language:, content_type: "text/plain")
142
144
  unless VALID_CONTENT_TYPES.include?(content_type)
143
- raise ArgumentError, "Invalid content_type '#{content_type}'. Must be one of: #{VALID_CONTENT_TYPES.join(', ')}"
145
+ raise ArgumentError,
146
+ "Invalid content_type '#{content_type}'. Must be one of: #{VALID_CONTENT_TYPES.join(', ')}"
144
147
  end
145
148
 
146
149
  body = { text: text, language: language, content_type: content_type }
data/lib/lara/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lara
4
- VERSION = "1.5.2"
4
+ VERSION = "1.6.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lara-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.2
4
+ version: 1.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Translated
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-07-13 00:00:00.000000000 Z
11
+ date: 2026-08-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday