lara-sdk 1.0.9 → 1.2.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: bec4d6b11a9be0d2481e0c83488befb4230e87cba9ec5d598f8ee397307b0c8c
4
- data.tar.gz: 9db2905ef0db583ef555c1792d326369776c2508d2d5bdc3a75ff9176320c284
3
+ metadata.gz: 20907c5322ca25cec94d4475f543ba03a04f611c8707711ca5b188b1aac5d708
4
+ data.tar.gz: 41f47a2c9a56145711d5275a9f8db3b1dc9a66e3b514d4d4106cbf2fa69bcb8e
5
5
  SHA512:
6
- metadata.gz: 9b644e13aeb677fa3a95af224165f87d1b35fdaf7f356ad25d1fc803cd0e243641e99a25514e5cbfef15d110efb4bca232d69e92fff333348ce68794d4e9f6f3
7
- data.tar.gz: 488de412d6562bbca3b8c6f9ba613da79150dccbdfdb58a1be4e1288ccaa8f3f060d6584c98b58ecb9e1802f12dae6b2ffa6e41b34ac52469c2a0aa3c9b1d271
6
+ metadata.gz: 323a5b9dbe032b6cc66ca30f42cf599ebd451f29b87c9a7fa7ed0f98769b91a952c57ece507d4bf9a9a120159364c6c224059a4b7a4a09b76ec65c3a0e50f078
7
+ data.tar.gz: 6123b7826259215d940b6e06e75b912756f9351cf750837e793059488472dac3ff3fc47906a4e6922b966873ea9803e240e588d9e9cf80f8c67509e3798136a0
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,83 @@ 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
56
+
57
+ def initialize(masked_text:, profanities: [])
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
+ end
69
+ end
70
+
71
+ class StyleguideChange < Base
72
+ attr_reader :id, :original_translation, :refined_translation, :explanation
73
+
74
+ def initialize(id:, original_translation:, refined_translation:, explanation:)
75
+ super()
76
+ @id = id
77
+ @original_translation = original_translation
78
+ @refined_translation = refined_translation
79
+ @explanation = explanation
80
+ end
81
+
82
+ def to_s
83
+ "StyleguideChange{id='#{id}', explanation='#{explanation}'}"
84
+ end
85
+ end
86
+
87
+ class StyleguideResults < Base
88
+ attr_reader :original_translation, :changes
89
+
90
+ def initialize(original_translation:, changes: [])
91
+ super()
92
+ @original_translation = original_translation
93
+ @changes = changes
94
+ end
95
+
96
+ def to_s
97
+ "StyleguideResults{changes=#{changes&.size || 0}}"
98
+ end
99
+ end
100
+
101
+ class Styleguide < Base
102
+ attr_reader :id, :name, :content, :owner_id, :created_at, :updated_at
103
+
104
+ def initialize(id:, name:, content: nil, owner_id: nil, created_at: nil, updated_at: nil, **_kwargs)
105
+ super()
106
+ @id = id
107
+ @name = name
108
+ @content = content
109
+ @owner_id = owner_id
110
+ @created_at = Base.parse_time(created_at)
111
+ @updated_at = Base.parse_time(updated_at)
112
+ end
113
+
114
+ def to_s
115
+ "Styleguide{id='#{id}', name='#{name}'}"
116
+ end
117
+ end
118
+
42
119
  class DetectPrediction < Base
43
120
  attr_reader :language, :confidence
44
121
 
@@ -60,10 +137,20 @@ module Lara
60
137
  end
61
138
  end
62
139
 
140
+ class QualityEstimationResult < Base
141
+ attr_reader :score
142
+
143
+ def initialize(score:)
144
+ super()
145
+ @score = score
146
+ end
147
+ end
148
+
63
149
  class TextResult < Base
64
150
  attr_reader :content_type, :source_language, :translation,
65
151
  :adapted_to, :glossaries,
66
- :adapted_to_matches, :glossaries_matches
152
+ :adapted_to_matches, :glossaries_matches,
153
+ :profanities, :styleguide_results
67
154
 
68
155
  def self.from_hash(hash)
69
156
  return nil unless hash.is_a?(Hash)
@@ -78,6 +165,8 @@ module Lara
78
165
 
79
166
  adapted_to_matches = convert_matches(hash["adapted_to_matches"], NGMemoryMatch)
80
167
  glossaries_matches = convert_matches(hash["glossaries_matches"], NGGlossaryMatch)
168
+ profanities = convert_profanities(hash["profanities"])
169
+ styleguide_results = convert_styleguide_results(hash["styleguide_results"])
81
170
 
82
171
  new(
83
172
  content_type: hash["content_type"],
@@ -86,12 +175,15 @@ module Lara
86
175
  adapted_to: hash["adapted_to"],
87
176
  glossaries: hash["glossaries"],
88
177
  adapted_to_matches: adapted_to_matches,
89
- glossaries_matches: glossaries_matches
178
+ glossaries_matches: glossaries_matches,
179
+ profanities: profanities,
180
+ styleguide_results: styleguide_results
90
181
  )
91
182
  end
92
183
 
93
184
  def initialize(content_type:, source_language:, translation:, adapted_to: nil, glossaries: nil,
94
- adapted_to_matches: nil, glossaries_matches: nil)
185
+ adapted_to_matches: nil, glossaries_matches: nil, profanities: nil,
186
+ styleguide_results: nil)
95
187
  super()
96
188
  @content_type = content_type
97
189
  @source_language = source_language
@@ -100,6 +192,8 @@ module Lara
100
192
  @glossaries = glossaries
101
193
  @adapted_to_matches = adapted_to_matches
102
194
  @glossaries_matches = glossaries_matches
195
+ @profanities = profanities
196
+ @styleguide_results = styleguide_results
103
197
  end
104
198
 
105
199
  class << self
@@ -119,6 +213,46 @@ module Lara
119
213
  end
120
214
  end
121
215
 
216
+ def convert_profanities(value)
217
+ return nil if value.nil?
218
+
219
+ if value.is_a?(Hash)
220
+ ProfanityDetectResult.new(
221
+ masked_text: value["masked_text"],
222
+ profanities: value["profanities"] || []
223
+ )
224
+ elsif value.is_a?(Array)
225
+ value.map do |v|
226
+ next nil if v.nil?
227
+
228
+ ProfanityDetectResult.new(
229
+ masked_text: v["masked_text"],
230
+ profanities: v["profanities"] || []
231
+ )
232
+ end
233
+ end
234
+ end
235
+
236
+ def convert_styleguide_results(value)
237
+ return nil if value.nil?
238
+ return nil unless value.is_a?(Hash)
239
+
240
+ original_translation = value["original_translation"]
241
+ changes = (value["changes"] || []).map do |c|
242
+ StyleguideChange.new(
243
+ id: c["id"],
244
+ original_translation: c["original_translation"],
245
+ refined_translation: c["refined_translation"],
246
+ explanation: c["explanation"]
247
+ )
248
+ end
249
+
250
+ StyleguideResults.new(
251
+ original_translation: original_translation,
252
+ changes: changes
253
+ )
254
+ end
255
+
122
256
  def build_match(klass, h)
123
257
  case klass.name.split("::").last
124
258
  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,16 @@ 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 profanity_filter [String,nil] One of "detect", "avoid", "hide"
58
60
  # @yield [Lara::Models::TextResult] Partial translation result (only when reasoning is true)
59
61
  # @return [Lara::Models::TextResult] Final translation result
60
62
  def translate(text, target:, source: nil, source_hint: nil, adapt_to: nil, glossaries: nil,
61
63
  instructions: nil, content_type: nil, multiline: true, timeout_ms: nil,
62
64
  priority: nil, use_cache: nil, cache_ttl_s: nil, no_trace: false, verbose: false,
63
- style: nil, reasoning: false, headers: nil, metadata: nil, &callback)
65
+ style: nil, reasoning: false, headers: nil, metadata: nil,
66
+ profanity_filter: nil,
67
+ styleguide_id: nil, styleguide_reasoning: nil,
68
+ styleguide_explanation_language: nil, &callback)
64
69
  q = normalize_text_input(text)
65
70
 
66
71
  use_cache_value = case use_cache
@@ -86,7 +91,11 @@ module Lara
86
91
  verbose: verbose,
87
92
  style: style,
88
93
  reasoning: reasoning,
89
- metadata: metadata
94
+ metadata: metadata,
95
+ profanity_filter: profanity_filter,
96
+ styleguide_id: styleguide_id,
97
+ styleguide_reasoning: styleguide_reasoning,
98
+ styleguide_explanation_language: styleguide_explanation_language
90
99
  }.compact
91
100
 
92
101
  request_headers = {}
@@ -112,7 +121,7 @@ module Lara
112
121
  body[:passlist] = passlist if passlist&.any?
113
122
  body = body.compact
114
123
 
115
- result = @client.post("/v2/detect", body: body)
124
+ result = @client.post("/v2/detect/language", body: body)
116
125
  Lara::Models::DetectResult.new(
117
126
  language: result["language"],
118
127
  content_type: result["content_type"],
@@ -120,6 +129,48 @@ module Lara
120
129
  )
121
130
  end
122
131
 
132
+ VALID_CONTENT_TYPES = %w[text/plain text/html text/xml application/xliff+xml].freeze
133
+
134
+ # Detects profanities in the given text.
135
+ # @param text [String] Text to check for profanities
136
+ # @param language [String] Language code (e.g. "en")
137
+ # @param content_type [String] One of "text/plain", "text/html", "text/xml", "application/xliff+xml"
138
+ # @return [Lara::Models::ProfanityDetectResult]
139
+ def detect_profanities(text, language:, content_type: "text/plain")
140
+ unless VALID_CONTENT_TYPES.include?(content_type)
141
+ raise ArgumentError, "Invalid content_type '#{content_type}'. Must be one of: #{VALID_CONTENT_TYPES.join(', ')}"
142
+ end
143
+
144
+ body = { text: text, language: language, content_type: content_type }
145
+ result = @client.post("/v2/detect/profanities", body: body)
146
+ Lara::Models::ProfanityDetectResult.new(
147
+ masked_text: result["masked_text"],
148
+ profanities: result["profanities"] || []
149
+ )
150
+ end
151
+
152
+ # Estimates translation quality for a sentence pair (or batch of pairs).
153
+ # @param source [String]
154
+ # @param target [String]
155
+ # @param sentence [String, Array<String>]
156
+ # @param translation [String, Array<String>]
157
+ # @return [Lara::Models::QualityEstimationResult, Array<Lara::Models::QualityEstimationResult>]
158
+ def quality_estimation(source:, target:, sentence:, translation:)
159
+ body = {
160
+ source: source,
161
+ target: target,
162
+ sentence: sentence,
163
+ translation: translation
164
+ }
165
+
166
+ result = @client.post("/v2/detect/quality-estimation", body: body)
167
+ if result.is_a?(Array)
168
+ result.map { |r| Lara::Models::QualityEstimationResult.new(score: r["score"] || r[:score]) }
169
+ else
170
+ Lara::Models::QualityEstimationResult.new(score: result["score"] || result[:score])
171
+ end
172
+ end
173
+
123
174
  # Lists supported language codes.
124
175
  def get_languages
125
176
  @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.1"
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.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-03-16 00:00:00.000000000 Z
11
+ date: 2026-04-21 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