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 +4 -4
- data/lib/lara/client.rb +8 -2
- data/lib/lara/models/text.rb +137 -3
- data/lib/lara/styleguides.rb +25 -0
- data/lib/lara/translator.rb +55 -4
- data/lib/lara/version.rb +1 -1
- data/lib/lara.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 20907c5322ca25cec94d4475f543ba03a04f611c8707711ca5b188b1aac5d708
|
|
4
|
+
data.tar.gz: 41f47a2c9a56145711d5275a9f8db3b1dc9a66e3b514d4d4106cbf2fa69bcb8e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
|
|
230
|
-
|
|
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)
|
data/lib/lara/models/text.rb
CHANGED
|
@@ -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
|
data/lib/lara/translator.rb
CHANGED
|
@@ -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,
|
|
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
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.
|
|
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-
|
|
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
|