lara-sdk 1.8.0 → 1.9.0

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: 40c690defef56e7663867a644181be99f0a6cc6576abc9b4d7f79e57193c3853
4
- data.tar.gz: 6d847c2b8b5caeaef7a45ec6624906a9b26ba29ff3105ea76e2eab7eb4d84adf
3
+ metadata.gz: 6441d4e8ad5cc6064ed3367644ed969d3c91e2dc5d5bcf2645680b2389d491b6
4
+ data.tar.gz: 1bbdb83ca6fb7f330ebb3adf69b8126facb9c1045875f083196580a2915d8b67
5
5
  SHA512:
6
- metadata.gz: ec70756013dfda0e007d16fcc2c165836b737017c1a8ad198cfe9d4763694c2a251d069ed9a177d3683b636fdae997a40559a1d6743c8c632387cfa5c628e3bf
7
- data.tar.gz: e8672051a95c85a847d66560c5ccbbb16dcbaf2b2d1060f5468d4b609b30cb007b8e1c823c96df2f01259b16da4cd50e5c6272823dec68ba0f90ef00669e608e
6
+ metadata.gz: c8b12451198b5a52a076766e310e4622cab58c1a1ce6173d6f3852291c183835b3111fcded6aee2ce60b0631727066d9b3dd443644ea03d12856f2db01314f07
7
+ data.tar.gz: b7dd274d9cdf562a91d0fcb496c9ce2f4053d9be3a99bb4fe5bfdb9d09d93d271ef46e82e2f8538b9b4fb24da8489401ef40bf79f6eeb29c1bc68bbbce3add2f
data/lib/lara/client.rb CHANGED
@@ -92,6 +92,15 @@ module Lara
92
92
 
93
93
  def request(method, path, body: nil, files: nil, headers: nil, params: nil,
94
94
  raw_response: false, &callback)
95
+ file_positions = (files || {}).each_with_object({}) do |(name, file), positions|
96
+ next unless file.respond_to?(:pos) && file.respond_to?(:seek)
97
+
98
+ begin
99
+ positions[name] = file.pos
100
+ rescue IOError, SystemCallError
101
+ # Non-seekable uploads can still be sent once.
102
+ end
103
+ end
95
104
  ensure_valid_token
96
105
 
97
106
  make_request(method, path, body: body, files: files, headers: headers, params: params,
@@ -100,6 +109,8 @@ module Lara
100
109
  raise unless e.status_code == 401
101
110
 
102
111
  @auth_mutex.synchronize { refresh_or_reauthenticate }
112
+ # Multipart encoding consumed the files; replay their original bytes.
113
+ file_positions.each { |name, position| files[name].seek(position) }
103
114
  make_request(method, path, body: body, files: files, headers: headers, params: params,
104
115
  raw_response: raw_response, &callback)
105
116
  end
data/lib/lara/images.rb CHANGED
@@ -46,10 +46,12 @@ module Lara
46
46
  # @param glossaries [Array<String>, nil] Glossary IDs to apply.
47
47
  # @param style [String, nil] Translation style ("faithful", "fluid", "creative").
48
48
  # @param verbose [Boolean] If true, includes match details in the response.
49
+ # @param include_layout [Boolean] When true, includes complete geometry and styling on every
50
+ # paragraph independently of verbose.
49
51
  # @param no_trace [Boolean] If true, disables request tracing.
50
52
  # @return [Lara::Models::ImageTextResult]
51
53
  def translate_text(file_path:, target:, source: nil, adapt_to: nil, glossaries: nil,
52
- style: nil, verbose: false, no_trace: false)
54
+ style: nil, verbose: false, no_trace: false, include_layout: false)
53
55
  image_upload = Faraday::Multipart::FilePart.new(file_path, mime_type_for(file_path))
54
56
 
55
57
  body = {
@@ -58,7 +60,8 @@ module Lara
58
60
  adapt_to: adapt_to&.to_json,
59
61
  glossaries: glossaries&.to_json,
60
62
  style: style,
61
- verbose: verbose.to_s
63
+ verbose: verbose.to_s,
64
+ include_layout: include_layout.to_s
62
65
  }.compact
63
66
 
64
67
  headers = {}
@@ -69,6 +72,27 @@ module Lara
69
72
  Lara::Models::ImageTextResult.from_hash(result)
70
73
  end
71
74
 
75
+ # Renders supplied translations onto the original image without translating again.
76
+ # Overlay and inpainting require ImageLayoutParagraph instances. Generative models
77
+ # accept either ImageParagraph or ImageLayoutParagraph. An omitted model defaults
78
+ # to generative_fast.
79
+ # @param paragraphs [Array<Lara::Models::ImageParagraph>] Text and translations to render.
80
+ # @return [String] Binary image data.
81
+ def render_translated(file_path:, target:, paragraphs:, source: nil, model: nil, no_trace: false)
82
+ image_upload = Faraday::Multipart::FilePart.new(file_path, mime_type_for(file_path))
83
+ body = {
84
+ source: source,
85
+ target: target,
86
+ paragraphs: paragraphs.map(&:to_render_hash).to_json,
87
+ model: model
88
+ }.compact
89
+ headers = {}
90
+ headers["X-No-Trace"] = "true" if no_trace
91
+
92
+ @client.post("/v2/images/render-translated", body: body, files: { image: image_upload },
93
+ headers: headers, raw_response: true)
94
+ end
95
+
72
96
  private
73
97
 
74
98
  def mime_type_for(file_path)
@@ -18,6 +18,51 @@ module Lara
18
18
  end
19
19
  end
20
20
 
21
+ # Four corners, each an [x, y] pair of pixel coordinates.
22
+ class ImageBBox < Base
23
+ attr_reader :top_left, :top_right, :bottom_right, :bottom_left
24
+
25
+ def initialize(top_left:, top_right:, bottom_right:, bottom_left:)
26
+ super()
27
+ @top_left = top_left
28
+ @top_right = top_right
29
+ @bottom_right = bottom_right
30
+ @bottom_left = bottom_left
31
+ end
32
+
33
+ def self.from_hash(hash)
34
+ new(top_left: hash["top_left"] || hash["topLeft"],
35
+ top_right: hash["top_right"] || hash["topRight"],
36
+ bottom_right: hash["bottom_right"] || hash["bottomRight"],
37
+ bottom_left: hash["bottom_left"] || hash["bottomLeft"])
38
+ end
39
+
40
+ def to_render_hash
41
+ { top_left: top_left, top_right: top_right, bottom_right: bottom_right, bottom_left: bottom_left }
42
+ end
43
+ end
44
+
45
+ # Original text direction (ltr, rtl, or ttb) and colors.
46
+ class ImageTextInfo < Base
47
+ attr_reader :direction, :text_color, :background_color
48
+
49
+ def initialize(direction:, text_color:, background_color:)
50
+ super()
51
+ @direction = direction
52
+ @text_color = text_color
53
+ @background_color = background_color
54
+ end
55
+
56
+ def self.from_hash(hash)
57
+ new(direction: hash["direction"], text_color: hash["text_color"] || hash["textColor"],
58
+ background_color: hash["background_color"] || hash["backgroundColor"])
59
+ end
60
+
61
+ def to_render_hash
62
+ { direction: direction, text_color: text_color, background_color: background_color }
63
+ end
64
+ end
65
+
21
66
  class ImageParagraph < Base
22
67
  attr_reader :text, :translation, :adapted_to_matches, :glossaries_matches
23
68
 
@@ -28,6 +73,29 @@ module Lara
28
73
  @adapted_to_matches = adapted_to_matches
29
74
  @glossaries_matches = glossaries_matches
30
75
  end
76
+
77
+ def to_render_hash
78
+ { text: text, translation: translation }
79
+ end
80
+ end
81
+
82
+ class ImageLayoutParagraph < ImageParagraph
83
+ attr_reader :bbox, :lines_bboxes, :text_info, :alignment
84
+
85
+ def initialize(text:, translation:, bbox:, lines_bboxes:, text_info:, alignment:,
86
+ adapted_to_matches: nil, glossaries_matches: nil)
87
+ super(text: text, translation: translation, adapted_to_matches: adapted_to_matches,
88
+ glossaries_matches: glossaries_matches)
89
+ @bbox = bbox
90
+ @lines_bboxes = lines_bboxes
91
+ @text_info = text_info
92
+ @alignment = alignment
93
+ end
94
+
95
+ def to_render_hash
96
+ super.merge(bbox: bbox.to_render_hash, lines_bboxes: lines_bboxes.map(&:to_render_hash),
97
+ text_info: text_info.to_render_hash, alignment: alignment)
98
+ end
31
99
  end
32
100
 
33
101
  class ImageTextResult < Base
@@ -39,8 +107,8 @@ module Lara
39
107
  paragraphs = (hash["paragraphs"] || []).map { |p| build_paragraph(p) }
40
108
 
41
109
  new(
42
- source_language: hash["sourceLanguage"],
43
- adapted_to: hash["adaptedTo"],
110
+ source_language: hash["source_language"] || hash["sourceLanguage"],
111
+ adapted_to: hash["adapted_to"] || hash["adaptedTo"],
44
112
  glossaries: hash["glossaries"],
45
113
  paragraphs: paragraphs
46
114
  )
@@ -50,15 +118,30 @@ module Lara
50
118
  private
51
119
 
52
120
  def build_paragraph(paragraph_hash)
53
- adapted_to_matches = convert_matches(paragraph_hash["adaptedToMatches"], NGMemoryMatch)
54
- glossaries_matches = convert_matches(paragraph_hash["glossariesMatches"], NGGlossaryMatch)
121
+ adapted_to_matches = convert_matches(
122
+ paragraph_hash["adapted_to_matches"] || paragraph_hash["adaptedToMatches"], NGMemoryMatch
123
+ )
124
+ glossaries_matches = convert_matches(
125
+ paragraph_hash["glossaries_matches"] || paragraph_hash["glossariesMatches"], NGGlossaryMatch
126
+ )
55
127
 
56
- ImageParagraph.new(
128
+ attributes = {
57
129
  text: paragraph_hash["text"],
58
130
  translation: paragraph_hash["translation"],
59
131
  adapted_to_matches: adapted_to_matches,
60
132
  glossaries_matches: glossaries_matches
61
- )
133
+ }
134
+ bbox = paragraph_hash["bbox"]
135
+ lines_bboxes = paragraph_hash["lines_bboxes"] || paragraph_hash["linesBboxes"]
136
+ text_info = paragraph_hash["text_info"] || paragraph_hash["textInfo"]
137
+ alignment = paragraph_hash["alignment"]
138
+ if bbox && lines_bboxes && text_info && alignment
139
+ ImageLayoutParagraph.new(**attributes, bbox: ImageBBox.from_hash(bbox),
140
+ lines_bboxes: lines_bboxes.map { |box| ImageBBox.from_hash(box) },
141
+ text_info: ImageTextInfo.from_hash(text_info), alignment: alignment)
142
+ else
143
+ ImageParagraph.new(**attributes)
144
+ end
62
145
  end
63
146
 
64
147
  def convert_matches(value, klass)
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.8.0"
4
+ VERSION = "1.9.0"
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.8.0
4
+ version: 1.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Translated
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-09-11 00:00:00.000000000 Z
11
+ date: 2026-09-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday