lara-sdk 1.0.9 → 1.2.2

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: bec4d6b11a9be0d2481e0c83488befb4230e87cba9ec5d598f8ee397307b0c8c
4
- data.tar.gz: 9db2905ef0db583ef555c1792d326369776c2508d2d5bdc3a75ff9176320c284
3
+ metadata.gz: 3a959c719f2393f4626f029c7116d426f1402889baeaea48a16800fbb58cd229
4
+ data.tar.gz: 54b9f604df73458c8abebb16ecce4389dcf4486f255d53187e3ad8dd7d2145c4
5
5
  SHA512:
6
- metadata.gz: 9b644e13aeb677fa3a95af224165f87d1b35fdaf7f356ad25d1fc803cd0e243641e99a25514e5cbfef15d110efb4bca232d69e92fff333348ce68794d4e9f6f3
7
- data.tar.gz: 488de412d6562bbca3b8c6f9ba613da79150dccbdfdb58a1be4e1288ccaa8f3f060d6584c98b58ecb9e1802f12dae6b2ffa6e41b34ac52469c2a0aa3c9b1d271
6
+ metadata.gz: 0d29539cdb0b1fe5add2b2f3200b812666d1edd1c0ebac1d77604f9c696f1f791cac76a791a0fedf7d75d6c263086090b57116705c477f1d9455ae27bb2e4c67
7
+ data.tar.gz: 29de437c146d524cca9b29a198ebbdb3426e8bf258a073d72e9740efedcd84edb83d01156870f3a461b1d62fcb144cb52b27c178bb51a8d7b7b521593d60ecff
data/lib/lara/client.rb CHANGED
@@ -226,8 +226,14 @@ module Lara
226
226
  end
227
227
 
228
228
  def parse_json(body)
229
- parsed = body.nil? || body.empty? ? {} : JSON.parse(body)
230
- parsed.is_a?(Hash) && parsed.key?("content") ? parsed["content"] : parsed
229
+ return {} if body.nil? || body.empty?
230
+
231
+ parsed = JSON.parse(body)
232
+ if parsed.is_a?(Hash) && parsed.key?("content")
233
+ inner = parsed["content"]
234
+ return inner if inner.is_a?(Hash) || inner.is_a?(Array)
235
+ end
236
+ parsed
231
237
  end
232
238
 
233
239
  def parse_stream_response(body, &block)
@@ -39,6 +39,99 @@ module Lara
39
39
  end
40
40
  end
41
41
 
42
+ class DetectedProfanity < Base
43
+ attr_reader :text, :start_char_index, :end_char_index, :score
44
+
45
+ def initialize(text:, start_char_index:, end_char_index:, score:)
46
+ super()
47
+ @text = text
48
+ @start_char_index = start_char_index
49
+ @end_char_index = end_char_index
50
+ @score = score
51
+ end
52
+ end
53
+
54
+ class ProfanityDetectResult < Base
55
+ attr_reader :masked_text, :profanities, :error
56
+
57
+ def initialize(masked_text:, profanities: [], error: nil)
58
+ super()
59
+ @masked_text = masked_text
60
+ @profanities = profanities.map do |p|
61
+ DetectedProfanity.new(
62
+ text: p["text"] || p[:text],
63
+ start_char_index: p["start_char_index"] || p[:start_char_index],
64
+ end_char_index: p["end_char_index"] || p[:end_char_index],
65
+ score: p["score"] || p[:score]
66
+ )
67
+ end
68
+ @error = error
69
+ end
70
+ end
71
+
72
+ # Wraps profanity detection results for both target and (optionally) source text.
73
+ # Returned in TextResult#profanities when profanities_detect is set.
74
+ class ProfanitiesResult < Base
75
+ # @return [ProfanityDetectResult, Array<ProfanityDetectResult, nil>, nil]
76
+ attr_reader :target
77
+ # @return [ProfanityDetectResult, Array<ProfanityDetectResult, nil>, nil]
78
+ attr_reader :source
79
+
80
+ def initialize(target: nil, source: nil)
81
+ super()
82
+ @target = target
83
+ @source = source
84
+ end
85
+ end
86
+
87
+ class StyleguideChange < Base
88
+ attr_reader :id, :original_translation, :refined_translation, :explanation
89
+
90
+ def initialize(id:, original_translation:, refined_translation:, explanation:)
91
+ super()
92
+ @id = id
93
+ @original_translation = original_translation
94
+ @refined_translation = refined_translation
95
+ @explanation = explanation
96
+ end
97
+
98
+ def to_s
99
+ "StyleguideChange{id='#{id}', explanation='#{explanation}'}"
100
+ end
101
+ end
102
+
103
+ class StyleguideResults < Base
104
+ attr_reader :original_translation, :changes
105
+
106
+ def initialize(original_translation:, changes: [])
107
+ super()
108
+ @original_translation = original_translation
109
+ @changes = changes
110
+ end
111
+
112
+ def to_s
113
+ "StyleguideResults{changes=#{changes&.size || 0}}"
114
+ end
115
+ end
116
+
117
+ class Styleguide < Base
118
+ attr_reader :id, :name, :content, :owner_id, :created_at, :updated_at
119
+
120
+ def initialize(id:, name:, content: nil, owner_id: nil, created_at: nil, updated_at: nil, **_kwargs)
121
+ super()
122
+ @id = id
123
+ @name = name
124
+ @content = content
125
+ @owner_id = owner_id
126
+ @created_at = Base.parse_time(created_at)
127
+ @updated_at = Base.parse_time(updated_at)
128
+ end
129
+
130
+ def to_s
131
+ "Styleguide{id='#{id}', name='#{name}'}"
132
+ end
133
+ end
134
+
42
135
  class DetectPrediction < Base
43
136
  attr_reader :language, :confidence
44
137
 
@@ -60,10 +153,20 @@ module Lara
60
153
  end
61
154
  end
62
155
 
156
+ class QualityEstimationResult < Base
157
+ attr_reader :score
158
+
159
+ def initialize(score:)
160
+ super()
161
+ @score = score
162
+ end
163
+ end
164
+
63
165
  class TextResult < Base
64
166
  attr_reader :content_type, :source_language, :translation,
65
167
  :adapted_to, :glossaries,
66
- :adapted_to_matches, :glossaries_matches
168
+ :adapted_to_matches, :glossaries_matches,
169
+ :profanities, :styleguide_results
67
170
 
68
171
  def self.from_hash(hash)
69
172
  return nil unless hash.is_a?(Hash)
@@ -78,6 +181,8 @@ module Lara
78
181
 
79
182
  adapted_to_matches = convert_matches(hash["adapted_to_matches"], NGMemoryMatch)
80
183
  glossaries_matches = convert_matches(hash["glossaries_matches"], NGGlossaryMatch)
184
+ profanities = convert_profanities(hash["profanities"])
185
+ styleguide_results = convert_styleguide_results(hash["styleguide_results"])
81
186
 
82
187
  new(
83
188
  content_type: hash["content_type"],
@@ -86,12 +191,15 @@ module Lara
86
191
  adapted_to: hash["adapted_to"],
87
192
  glossaries: hash["glossaries"],
88
193
  adapted_to_matches: adapted_to_matches,
89
- glossaries_matches: glossaries_matches
194
+ glossaries_matches: glossaries_matches,
195
+ profanities: profanities,
196
+ styleguide_results: styleguide_results
90
197
  )
91
198
  end
92
199
 
93
200
  def initialize(content_type:, source_language:, translation:, adapted_to: nil, glossaries: nil,
94
- adapted_to_matches: nil, glossaries_matches: nil)
201
+ adapted_to_matches: nil, glossaries_matches: nil, profanities: nil,
202
+ styleguide_results: nil)
95
203
  super()
96
204
  @content_type = content_type
97
205
  @source_language = source_language
@@ -100,6 +208,8 @@ module Lara
100
208
  @glossaries = glossaries
101
209
  @adapted_to_matches = adapted_to_matches
102
210
  @glossaries_matches = glossaries_matches
211
+ @profanities = profanities
212
+ @styleguide_results = styleguide_results
103
213
  end
104
214
 
105
215
  class << self
@@ -119,6 +229,59 @@ module Lara
119
229
  end
120
230
  end
121
231
 
232
+ def convert_profanities(value)
233
+ return nil if value.nil?
234
+ return nil unless value.is_a?(Hash)
235
+ return nil unless value.key?("target") || value.key?("source")
236
+
237
+ ProfanitiesResult.new(
238
+ target: parse_profanity_value(value["target"]),
239
+ source: parse_profanity_value(value["source"])
240
+ )
241
+ end
242
+
243
+ def parse_profanity_value(value)
244
+ return nil if value.nil?
245
+
246
+ if value.is_a?(Hash)
247
+ ProfanityDetectResult.new(
248
+ masked_text: value["masked_text"],
249
+ profanities: value["profanities"] || [],
250
+ error: value["error"]
251
+ )
252
+ elsif value.is_a?(Array)
253
+ value.map do |v|
254
+ next nil if v.nil?
255
+
256
+ ProfanityDetectResult.new(
257
+ masked_text: v["masked_text"],
258
+ profanities: v["profanities"] || [],
259
+ error: v["error"]
260
+ )
261
+ end
262
+ end
263
+ end
264
+
265
+ def convert_styleguide_results(value)
266
+ return nil if value.nil?
267
+ return nil unless value.is_a?(Hash)
268
+
269
+ original_translation = value["original_translation"]
270
+ changes = (value["changes"] || []).map do |c|
271
+ StyleguideChange.new(
272
+ id: c["id"],
273
+ original_translation: c["original_translation"],
274
+ refined_translation: c["refined_translation"],
275
+ explanation: c["explanation"]
276
+ )
277
+ end
278
+
279
+ StyleguideResults.new(
280
+ original_translation: original_translation,
281
+ changes: changes
282
+ )
283
+ end
284
+
122
285
  def build_match(klass, h)
123
286
  case klass.name.split("::").last
124
287
  when "NGMemoryMatch"
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lara
4
+ class Styleguides
5
+ def initialize(client)
6
+ @client = client
7
+ end
8
+
9
+ # @return [Array<Lara::Models::Styleguide>]
10
+ def list
11
+ (@client.get("/v2/styleguides") || []).map do |h|
12
+ Lara::Models::Styleguide.new(**h.transform_keys(&:to_sym))
13
+ end
14
+ end
15
+
16
+ # @return [Lara::Models::Styleguide,nil]
17
+ def get(id)
18
+ Lara::Models::Styleguide.new(**@client.get("/v2/styleguides/#{id}").transform_keys(&:to_sym))
19
+ rescue Lara::LaraApiError => e
20
+ return nil if e.status_code == 404
21
+
22
+ raise
23
+ end
24
+ end
25
+ end
@@ -28,12 +28,13 @@ module Lara
28
28
  connection_timeout: connection_timeout, read_timeout: read_timeout)
29
29
  @memories = Memories.new(@client)
30
30
  @glossaries = Glossaries.new(@client)
31
+ @styleguides = Styleguides.new(@client)
31
32
  @documents = Documents.new(@client)
32
33
  @images = Images.new(@client)
33
34
  @audio = AudioTranslator.new(@client)
34
35
  end
35
36
 
36
- attr_reader :client, :memories, :glossaries, :documents, :images, :audio
37
+ attr_reader :client, :memories, :glossaries, :styleguides, :documents, :images, :audio
37
38
 
38
39
  # Translates text with optional tuning parameters.
39
40
  # @param text [String, Array<String>, Array<Lara::Models::TextBlock>]
@@ -55,12 +56,17 @@ module Lara
55
56
  # @param reasoning [Boolean] When true with a block, yields partial results during reasoning
56
57
  # @param headers [Hash,nil]
57
58
  # @param metadata [String, Hash, nil]
59
+ # @param profanities_detect [String,nil] One of "target", "source_target"
60
+ # @param profanities_handling [String,nil] One of "detect", "avoid", "hide" (default: "hide" when profanities_detect is set)
58
61
  # @yield [Lara::Models::TextResult] Partial translation result (only when reasoning is true)
59
62
  # @return [Lara::Models::TextResult] Final translation result
60
63
  def translate(text, target:, source: nil, source_hint: nil, adapt_to: nil, glossaries: nil,
61
64
  instructions: nil, content_type: nil, multiline: true, timeout_ms: nil,
62
65
  priority: nil, use_cache: nil, cache_ttl_s: nil, no_trace: false, verbose: false,
63
- style: nil, reasoning: false, headers: nil, metadata: nil, &callback)
66
+ style: nil, reasoning: false, headers: nil, metadata: nil,
67
+ profanities_detect: nil, profanities_handling: nil,
68
+ styleguide_id: nil, styleguide_reasoning: nil,
69
+ styleguide_explanation_language: nil, &callback)
64
70
  q = normalize_text_input(text)
65
71
 
66
72
  use_cache_value = case use_cache
@@ -86,7 +92,12 @@ module Lara
86
92
  verbose: verbose,
87
93
  style: style,
88
94
  reasoning: reasoning,
89
- metadata: metadata
95
+ metadata: metadata,
96
+ profanities_detect: profanities_detect,
97
+ profanities_handling: profanities_handling,
98
+ styleguide_id: styleguide_id,
99
+ styleguide_reasoning: styleguide_reasoning,
100
+ styleguide_explanation_language: styleguide_explanation_language
90
101
  }.compact
91
102
 
92
103
  request_headers = {}
@@ -112,7 +123,7 @@ module Lara
112
123
  body[:passlist] = passlist if passlist&.any?
113
124
  body = body.compact
114
125
 
115
- result = @client.post("/v2/detect", body: body)
126
+ result = @client.post("/v2/detect/language", body: body)
116
127
  Lara::Models::DetectResult.new(
117
128
  language: result["language"],
118
129
  content_type: result["content_type"],
@@ -120,6 +131,49 @@ module Lara
120
131
  )
121
132
  end
122
133
 
134
+ VALID_CONTENT_TYPES = %w[text/plain text/html text/xml application/xliff+xml].freeze
135
+
136
+ # Detects profanities in the given text.
137
+ # @param text [String] Text to check for profanities
138
+ # @param language [String] Language code (e.g. "en")
139
+ # @param content_type [String] One of "text/plain", "text/html", "text/xml", "application/xliff+xml"
140
+ # @return [Lara::Models::ProfanityDetectResult]
141
+ def detect_profanities(text, language:, content_type: "text/plain")
142
+ unless VALID_CONTENT_TYPES.include?(content_type)
143
+ raise ArgumentError, "Invalid content_type '#{content_type}'. Must be one of: #{VALID_CONTENT_TYPES.join(', ')}"
144
+ end
145
+
146
+ body = { text: text, language: language, content_type: content_type }
147
+ result = @client.post("/v2/detect/profanities", body: body)
148
+ Lara::Models::ProfanityDetectResult.new(
149
+ masked_text: result["masked_text"],
150
+ profanities: result["profanities"] || [],
151
+ error: result["error"]
152
+ )
153
+ end
154
+
155
+ # Estimates translation quality for a sentence pair (or batch of pairs).
156
+ # @param source [String]
157
+ # @param target [String]
158
+ # @param sentence [String, Array<String>]
159
+ # @param translation [String, Array<String>]
160
+ # @return [Lara::Models::QualityEstimationResult, Array<Lara::Models::QualityEstimationResult>]
161
+ def quality_estimation(source:, target:, sentence:, translation:)
162
+ body = {
163
+ source: source,
164
+ target: target,
165
+ sentence: sentence,
166
+ translation: translation
167
+ }
168
+
169
+ result = @client.post("/v2/detect/quality-estimation", body: body)
170
+ if result.is_a?(Array)
171
+ result.map { |r| Lara::Models::QualityEstimationResult.new(score: r["score"] || r[:score]) }
172
+ else
173
+ Lara::Models::QualityEstimationResult.new(score: result["score"] || result[:score])
174
+ end
175
+ end
176
+
123
177
  # Lists supported language codes.
124
178
  def get_languages
125
179
  @client.get("/v2/languages")
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.0.9"
4
+ VERSION = "1.2.2"
5
5
  end
data/lib/lara.rb CHANGED
@@ -8,6 +8,7 @@ require_relative "lara/client"
8
8
  require_relative "lara/translator"
9
9
  require_relative "lara/memories"
10
10
  require_relative "lara/glossaries"
11
+ require_relative "lara/styleguides"
11
12
  require_relative "lara/s3_client"
12
13
  require_relative "lara/documents"
13
14
  require_relative "lara/images"
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.0.9
4
+ version: 1.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Translated
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-03-16 00:00:00.000000000 Z
11
+ date: 2026-04-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -167,6 +167,7 @@ files:
167
167
  - lib/lara/models/memories.rb
168
168
  - lib/lara/models/text.rb
169
169
  - lib/lara/s3_client.rb
170
+ - lib/lara/styleguides.rb
170
171
  - lib/lara/translator.rb
171
172
  - lib/lara/version.rb
172
173
  homepage: https://laratranslate.com