datashare-translation-worker 0.4.2__tar.gz

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.
@@ -0,0 +1,21 @@
1
+ .idea/
2
+ # Python
3
+ *.log
4
+ venv
5
+ *.egg-info
6
+ .eggs
7
+ __pycache__
8
+ *.pytest_cache
9
+ *.pyc
10
+ build
11
+ dist
12
+ test/.env
13
+ .cache
14
+ tmp
15
+ ./*.csv
16
+ .DS_Store
17
+
18
+ # VS code
19
+ .vscode
20
+ # Doc
21
+ site
@@ -0,0 +1,54 @@
1
+ FROM python:3.13-slim-trixie AS builder
2
+
3
+
4
+ FROM python:3.13-slim-trixie AS translation-worker-builder
5
+
6
+ ENV PYTHONUNBUFFERED=1
7
+ ENV UV_HTTP_TIMEOUT=300
8
+ ENV UV_LINK_MODE=copy
9
+ ENV UV_COMPILE_BYTECODE=1
10
+ ENV UV_NO_DEV=1
11
+
12
+ COPY --from=ghcr.io/astral-sh/uv:0.11.6 /uv /uvx /bin/
13
+
14
+ WORKDIR /app
15
+
16
+
17
+ FROM translation-worker-builder AS io-worker
18
+ # Install deps first to optimize layer cache
19
+ RUN --mount=type=cache,target=~/.cache/uv \
20
+ --mount=type=bind,source=uv.dist.lock,target=uv.lock \
21
+ --mount=type=bind,source=pyproject.toml,target=pyproject.toml \
22
+ uv sync -v --frozen --no-editable --no-install-project
23
+
24
+ # Then copy code
25
+ ADD uv.dist.lock ./uv.lock
26
+ ADD pyproject.toml README.md ./
27
+ ADD translation_worker ./translation_worker/
28
+ ADD entrypoints/io_worker.sh ./entrypoints/io_worker.sh
29
+
30
+ # Then install service
31
+ RUN --mount=type=cache,target=~/.cache/uv uv sync -v --frozen --no-editable
32
+ RUN rm -rf ~/.cache/pip
33
+
34
+ ENTRYPOINT ["entrypoints/io_worker.sh"]
35
+
36
+
37
+ FROM translation-worker-builder AS inference-worker
38
+ # Install deps first to optimize layer cache
39
+ RUN --mount=type=cache,target=~/.cache/uv \
40
+ --mount=type=bind,source=uv.dist.lock,target=uv.lock \
41
+ --mount=type=bind,source=pyproject.toml,target=pyproject.toml \
42
+ uv sync -v --frozen --no-editable --no-install-project --extra inference
43
+
44
+ # Then copy code
45
+ ADD uv.dist.lock ./uv.lock
46
+ ADD pyproject.toml README.md ./
47
+ ADD translation_worker ./translation_worker/
48
+ ADD entrypoints/inference_worker.sh ./entrypoints/inference_worker.sh
49
+
50
+ # Then install service
51
+ RUN --mount=type=cache,target=~/.cache/uv uv sync -v --frozen --no-editable --extra inference
52
+ RUN rm -rf ~/.cache/pip
53
+
54
+ ENTRYPOINT ["entrypoints/inference_worker.sh"]
@@ -0,0 +1,16 @@
1
+ Metadata-Version: 2.4
2
+ Name: datashare-translation-worker
3
+ Version: 0.4.2
4
+ Summary: Translation worker implementation in Temporal
5
+ Author-email: Clément Doumouro <cdoumouro@icij.org>, Clément Doumouro <clement.doumouro@gmail.com>, Lion Summerbell <lsummerbell@icij.org>
6
+ Requires-Python: <3.13,>=3.11.0
7
+ Requires-Dist: datashare-python~=0.8.4
8
+ Requires-Dist: pydantic-extra-types[pycountry]==2.11.1
9
+ Provides-Extra: inference
10
+ Requires-Dist: argostranslate==1.11.0; extra == 'inference'
11
+ Description-Content-Type: text/markdown
12
+
13
+ # Translation worker implementation in Temporal
14
+
15
+ Implements a translation worker for `temporalio` based on the `argostranslate`
16
+ translation library.
@@ -0,0 +1,4 @@
1
+ # Translation worker implementation in Temporal
2
+
3
+ Implements a translation worker for `temporalio` based on the `argostranslate`
4
+ translation library.
@@ -0,0 +1,6 @@
1
+ #!/bin/bash
2
+
3
+ uv run --no-sync datashare-python worker start \
4
+ --dependencies inference \
5
+ --queue translation.inference.cpu \
6
+ --activities translation.translate_docs
@@ -0,0 +1,9 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ uv run --no-sync datashare-python worker start \
5
+ --dependencies io \
6
+ --queue translation.io \
7
+ --activities translation.worker_config \
8
+ --activities translation.create_translation_batches \
9
+ --workflows translation
@@ -0,0 +1,89 @@
1
+ [project]
2
+ name = "datashare-translation-worker"
3
+ dynamic = ["version"]
4
+ description = "Translation worker implementation in Temporal"
5
+ authors = [
6
+ { name = "Clément Doumouro", email = "cdoumouro@icij.org" },
7
+ { name = "Clément Doumouro", email = "clement.doumouro@gmail.com" },
8
+ { name = "Lion Summerbell", email = "lsummerbell@icij.org" }
9
+ ]
10
+ readme = "README.md"
11
+ requires-python = ">=3.11.0, <3.13"
12
+
13
+ dependencies = [
14
+ "datashare-python~=0.8.4",
15
+ "pydantic-extra-types[pycountry]==2.11.1",
16
+ ]
17
+
18
+ [project.entry-points."datashare.workflows"]
19
+ workflows = "translation_worker.workflows:WORKFLOWS"
20
+
21
+ [project.entry-points."datashare.activities"]
22
+ activities = "translation_worker.activities:ACTIVITIES"
23
+
24
+ [project.entry-points."datashare.dependencies"]
25
+ dependencies = "translation_worker.dependencies:REGISTRY"
26
+
27
+ [project.entry-points."datashare.worker_config_cls"]
28
+ worker_config_cls = "translation_worker.objects:WORKER_CONFIG_CLS"
29
+
30
+ [project.optional-dependencies]
31
+ inference = [
32
+ "argostranslate==1.11.0",
33
+ ]
34
+
35
+ [tool.uv.sources]
36
+ datashare-python = { path = "../../datashare-python", editable = true }
37
+
38
+ [tool.uv]
39
+ package = true
40
+ exclude-dependencies = [
41
+ # TODO: put me back when this is solved: https://github.com/argosopentech/argos-translate/pull/521
42
+ # "torch",
43
+ ]
44
+
45
+ [tool.uv-dynamic-versioning]
46
+ fallback-version = "0.0.0"
47
+ pattern-prefix = "translation-worker-"
48
+ pattern = "default-unprefixed"
49
+
50
+ [dependency-groups]
51
+ dev = [
52
+ "datashare-python~=0.2",
53
+ "nest-asyncio>=1.6.0",
54
+ "pre-commit>=4.5.1",
55
+ "psutil>=6.1.0",
56
+ "pytest~=8.1",
57
+ "pytest-asyncio~=0.24",
58
+ "pytest-timeout==2.4.0",
59
+ "redis[hiredis]>=5.2.1",
60
+ "ruff==0.15.2",
61
+ "typing-extensions>=4.15.0",
62
+ ]
63
+
64
+ [build-system]
65
+ requires = ["hatchling", "uv-dynamic-versioning"]
66
+ build-backend = "hatchling.build"
67
+
68
+ [tool.hatch.version]
69
+ source = "uv-dynamic-versioning"
70
+
71
+ [tool.hatch.build.targets.wheel]
72
+ packages = ["translation_worker"]
73
+
74
+ [tool.hatch.build.targets.sdist]
75
+ exclude = [
76
+ "tests"
77
+ ]
78
+
79
+ [tool.pytest.ini_options]
80
+ asyncio_mode = "auto"
81
+ asyncio_default_fixture_loop_scope = "session"
82
+ markers = [
83
+ "integration",
84
+ "pull",
85
+ ]
86
+ log_cli = 1
87
+ log_cli_level = "DEBUG"
88
+ log_file_format = "[%(levelname)s][%(asctime)s.%(msecs)03d][%(name)s]: %(message)s"
89
+ log_file_date_format = "%Y-%m-%d %H:%M:%S"
@@ -0,0 +1,438 @@
1
+ import asyncio
2
+ import logging
3
+ from collections import defaultdict
4
+ from collections.abc import AsyncGenerator, AsyncIterator, Iterable
5
+ from copy import deepcopy
6
+ from functools import partial
7
+ from typing import Any, cast
8
+
9
+ from aiostream.stream import chain
10
+ from datashare_python.dependencies import lifespan_es_client, lifespan_worker_config
11
+ from datashare_python.objects import Document
12
+ from datashare_python.types_ import ProgressRateHandler
13
+ from datashare_python.utils import ActivityWithProgress, activity_defn, to_raw_progress
14
+ from elasticsearch._async.helpers import async_bulk
15
+ from icij_common.es import (
16
+ BOOL,
17
+ DOC_LANGUAGE,
18
+ HITS,
19
+ ID_,
20
+ QUERY,
21
+ SOURCE,
22
+ TERM,
23
+ ESClient,
24
+ has_id,
25
+ must_not,
26
+ )
27
+ from icij_common.iter_utils import before_and_after, once
28
+ from pydantic_extra_types.language_code import LanguageAlpha2, LanguageName
29
+
30
+ from .constants import BATCHING_DOC_SOURCES, CONTENT_LENGTH, TRANSLATION_DOC_SOURCES
31
+ from .core import (
32
+ Sentencizer,
33
+ TranslationEnsemble,
34
+ get_translation_ensemble,
35
+ has_language,
36
+ translate_as_list,
37
+ )
38
+ from .objects import BatchSentence, TranslationWorkerConfig
39
+
40
+ logger = logging.getLogger(__name__)
41
+
42
+
43
+ class TranslationActivities(ActivityWithProgress):
44
+ @activity_defn(name="translation.worker_config")
45
+ async def translation_worker_config(self) -> TranslationWorkerConfig:
46
+ worker_config = cast(TranslationWorkerConfig, lifespan_worker_config())
47
+ return worker_config
48
+
49
+ @activity_defn(name="translation.create_translation_batches")
50
+ async def create_translation_batches(
51
+ self, project: str, target_language: LanguageAlpha2
52
+ ) -> list[tuple[str, list[list[str]]]]:
53
+ es_client = lifespan_es_client()
54
+ worker_config = cast(TranslationWorkerConfig, lifespan_worker_config())
55
+ max_batch_byte_len = worker_config.max_batch_byte_len
56
+ batches = await create_translation_batches(
57
+ project=project,
58
+ target_language=target_language,
59
+ max_batch_byte_len=max_batch_byte_len,
60
+ es_client=es_client,
61
+ )
62
+ return batches
63
+
64
+ @activity_defn(name="translation.translate_docs")
65
+ async def translate_docs(
66
+ self,
67
+ doc_id_batch_with_lang: tuple[str, list[list[str]]],
68
+ target_language: LanguageAlpha2,
69
+ *,
70
+ project: str,
71
+ progress: ProgressRateHandler | None = None,
72
+ ) -> int:
73
+ es_client = lifespan_es_client()
74
+ worker_config = cast(TranslationWorkerConfig, lifespan_worker_config())
75
+ n_translated = await translate_docs(
76
+ doc_id_batch_with_lang,
77
+ target_language=target_language,
78
+ project=project,
79
+ es_client=es_client,
80
+ progress=progress,
81
+ worker_config=worker_config,
82
+ )
83
+ return n_translated
84
+
85
+
86
+ async def create_translation_batches(
87
+ *,
88
+ project: str,
89
+ target_language: LanguageAlpha2,
90
+ max_batch_byte_len: int = 1000000,
91
+ es_client: ESClient | None = None,
92
+ ) -> list[tuple[str, list[list[str]]]]:
93
+ """Batch doc ids by language and/or total batch byte length
94
+
95
+ :param project: Project name
96
+ :param target_language: Target language
97
+ :param max_batch_byte_len: Maximum batch byte length
98
+ :param es_client: ES client
99
+ :return: list of batches keyed by language
100
+ """
101
+ # Retrieve unprocessed docs.
102
+ es_docs = _get_es_docs(
103
+ es_client,
104
+ project,
105
+ target_language_alpha_code=target_language,
106
+ source_includes=BATCHING_DOC_SOURCES,
107
+ )
108
+ all_results = {}
109
+ current_batch = []
110
+ current_batch_byte_len = 0
111
+
112
+ async for es_doc_id_batch in es_docs:
113
+ first_doc = await anext(es_doc_id_batch, None)
114
+ if first_doc is None:
115
+ continue
116
+
117
+ source_alpha_2 = LanguageName(first_doc[SOURCE][DOC_LANGUAGE].title()).alpha2
118
+ all_results[source_alpha_2] = []
119
+ current_batch.append(first_doc[ID_])
120
+
121
+ async for item in es_doc_id_batch:
122
+ doc_id = item[ID_]
123
+ doc_byte_len = item[SOURCE][CONTENT_LENGTH]
124
+
125
+ if 0 < max_batch_byte_len < current_batch_byte_len + doc_byte_len:
126
+ all_results[source_alpha_2].append(deepcopy(current_batch))
127
+ current_batch = []
128
+ current_batch_byte_len = 0
129
+
130
+ current_batch.append(doc_id)
131
+ current_batch_byte_len += doc_byte_len
132
+
133
+ if len(current_batch) > 0:
134
+ all_results[source_alpha_2].append(deepcopy(current_batch))
135
+ current_batch = []
136
+ current_batch_byte_len = 0
137
+
138
+ return list(all_results.items())
139
+
140
+
141
+ async def translate_docs(
142
+ doc_id_batch_with_lang: tuple[str, list[list[str]]],
143
+ target_language: LanguageAlpha2,
144
+ *,
145
+ project: str,
146
+ es_client: ESClient | None = None,
147
+ worker_config: TranslationWorkerConfig | None = None,
148
+ progress: ProgressRateHandler | None = None, # noqa: F821
149
+ ) -> int:
150
+ """Translate sentence batches and reconstruct translations from original
151
+ sentence ordering, inserting them into ES
152
+
153
+ :param doc_id_batch_with_lang: doc_ids keyed by document language alpha code
154
+ :param target_language: Target language alpha2 code
155
+ :param project: Project name
156
+ :param es_client: ES client
157
+ :param progress: ProgressRateHandler
158
+ :param worker_config: worker config
159
+ :return: number of documents translated
160
+ """
161
+ if worker_config is None:
162
+ worker_config = TranslationWorkerConfig()
163
+
164
+ # TODO: this should not happen
165
+ if not isinstance(worker_config, TranslationWorkerConfig):
166
+ worker_config = TranslationWorkerConfig.model_validate(worker_config)
167
+
168
+ source_language_alpha_code, doc_id_batches = doc_id_batch_with_lang
169
+
170
+ # Get documents
171
+ translation_ensemble = get_translation_ensemble(
172
+ source_language_alpha_code=source_language_alpha_code,
173
+ target_language_alpha_code=target_language,
174
+ device=worker_config.device,
175
+ inter_threads=worker_config.inter_threads,
176
+ intra_threads=worker_config.intra_threads,
177
+ compute_type=worker_config.compute_type,
178
+ )
179
+
180
+ all_sentences = []
181
+ all_translations = []
182
+ translation_tasks = []
183
+
184
+ # unit here is a sentence
185
+ seen = 0
186
+ total = 0
187
+
188
+ for doc_id_batch in doc_id_batches:
189
+ sentences_batches = _get_doc_contents_and_split_on_sentences(
190
+ es_client,
191
+ project,
192
+ doc_id_batch,
193
+ translation_ensemble.sentencizer,
194
+ worker_config.batch_size,
195
+ )
196
+
197
+ # Create translation tasks
198
+ async for sentences_batch in sentences_batches:
199
+ n_sentences = len(sentences_batch)
200
+ if not n_sentences:
201
+ continue
202
+
203
+ # Convert the progress to a "raw" progress to update the progress
204
+ # incrementally rather than setting the progress rate
205
+ if progress is not None:
206
+ progress = to_raw_progress(progress, max_progress=n_sentences)
207
+ total += n_sentences
208
+
209
+ # Translate
210
+ translation_tasks.append(
211
+ asyncio.create_task(
212
+ _translate_batch(
213
+ sentences_batch, translation_ensemble, worker_config.beam_size
214
+ )
215
+ )
216
+ )
217
+
218
+ all_sentences += sentences_batch
219
+
220
+ # Run translation tasks
221
+ for task in asyncio.as_completed(translation_tasks):
222
+ translation_batch = await task
223
+ all_translations.extend(translation_batch)
224
+
225
+ seen += len(translation_batch)
226
+
227
+ if progress is not None:
228
+ await progress(int(seen / total))
229
+
230
+ all_translations = await asyncio.gather(*translation_tasks)
231
+ all_translations = [
232
+ translation for batch in all_translations for translation in batch
233
+ ]
234
+
235
+ # Reconstruct documents from sentences
236
+ # TODO: separate into a function for testing
237
+ reconstructed_docs = defaultdict(dict)
238
+
239
+ for batch_sentence, translation in zip(
240
+ all_sentences, all_translations, strict=False
241
+ ):
242
+ key = batch_sentence.doc_id, batch_sentence.root_document
243
+ reconstructed_docs[key][batch_sentence.sentence_index] = translation
244
+
245
+ # Combine sentences into translations and key with doc_id and root_document
246
+ # for insertion
247
+ translations_with_doc_ids_and_root_doc = []
248
+
249
+ for (doc_id, root_document), sentence_idx_mapping in reconstructed_docs.items():
250
+ ordered_translation = " ".join(
251
+ [translation for (_, translation) in sorted(sentence_idx_mapping.items())]
252
+ )
253
+ seen += len(ordered_translation)
254
+
255
+ translations_with_doc_ids_and_root_doc.append(
256
+ (doc_id, root_document, ordered_translation)
257
+ )
258
+
259
+ if progress is not None:
260
+ await progress(int(seen / total))
261
+
262
+ await _add_translation(
263
+ es_client,
264
+ translations_with_doc_ids_and_root_doc,
265
+ project,
266
+ target_language_alpha_code=target_language,
267
+ )
268
+ # Return the number of translated documents
269
+ return len(reconstructed_docs)
270
+
271
+
272
+ # async
273
+ async def _get_doc_contents_and_split_on_sentences(
274
+ es_client: ESClient,
275
+ project: str,
276
+ doc_ids: list[str],
277
+ sentencizer: Sentencizer,
278
+ sentence_batch_size: int = 16,
279
+ ) -> AsyncGenerator[list[BatchSentence] | None, Any]:
280
+ if len(doc_ids) == 0:
281
+ return
282
+
283
+ batch_gen = _async_query_es(
284
+ es_client,
285
+ project,
286
+ body={QUERY: has_id(doc_ids)},
287
+ source_includes=TRANSLATION_DOC_SOURCES,
288
+ )
289
+
290
+ async for batch in _iter_sentences(batch_gen, sentencizer, sentence_batch_size):
291
+ yield batch
292
+
293
+
294
+ async def _iter_sentences(
295
+ doc_iter: AsyncGenerator[dict, None],
296
+ sentencizer: Sentencizer,
297
+ sentence_batch_size: int = 16,
298
+ ) -> AsyncGenerator[list[BatchSentence], None]:
299
+ sentence_batch = []
300
+
301
+ async for doc in doc_iter:
302
+ es_doc = Document.from_es(doc)
303
+ sentences = await asyncio.to_thread(sentencizer, es_doc.content)
304
+ for idx, sentence in enumerate(sentences):
305
+ sentence_batch.append(
306
+ BatchSentence(
307
+ doc_id=es_doc.id,
308
+ root_document=es_doc.root_document,
309
+ sentence_index=idx,
310
+ sentence=sentence,
311
+ )
312
+ )
313
+
314
+ if len(sentence_batch) >= sentence_batch_size:
315
+ yield sentence_batch
316
+ sentence_batch = []
317
+
318
+ if len(sentence_batch) > 0:
319
+ yield sentence_batch
320
+
321
+
322
+ async def _translate_batch(
323
+ sentence_batch: list[BatchSentence],
324
+ translation_ensemble: TranslationEnsemble,
325
+ max_parallel_batches: int = 8,
326
+ beam_size: int = 4,
327
+ ) -> list[str]:
328
+ async with asyncio.Semaphore(max_parallel_batches):
329
+ return await asyncio.to_thread(
330
+ translate_as_list, sentence_batch, translation_ensemble, beam_size
331
+ )
332
+
333
+
334
+ async def _get_es_docs(
335
+ es_client: ESClient,
336
+ project: str,
337
+ target_language_alpha_code: str,
338
+ source_includes: list[str],
339
+ ) -> AsyncGenerator[AsyncIterator[dict], None]:
340
+ # Get all documents that are not in the target language sorted by language
341
+ docs = _async_query_es(
342
+ es_client,
343
+ project,
344
+ body=_untranslated_query(target_language_alpha_code),
345
+ source_includes=source_includes,
346
+ sort=[f"{DOC_LANGUAGE}:asc", "_doc:asc"],
347
+ )
348
+ while True:
349
+ try:
350
+ next_doc = await anext(aiter(docs))
351
+ except StopAsyncIteration:
352
+ return
353
+ current_language = next_doc[SOURCE][DOC_LANGUAGE]
354
+
355
+ # Consume the iterator until we find a doc with a different language
356
+ language_docs, docs = before_and_after(
357
+ docs, predicate=partial(has_language, language=current_language)
358
+ )
359
+ # Group all docs of same language
360
+ grouped_docs = chain(once(next_doc), language_docs)
361
+
362
+ yield aiter(grouped_docs)
363
+
364
+
365
+ _SCRIPT_SOURCES = """
366
+ if( !ctx._source.containsKey("content_translated") ) {
367
+ ctx._source.content_translated = new HashMap();
368
+ }
369
+ ctx._source.content_translated[params.language] = params.translation;
370
+ """
371
+
372
+
373
+ async def _add_translation(
374
+ es_client: ESClient,
375
+ translations: Iterable[tuple[Document, str]],
376
+ project: str,
377
+ *,
378
+ target_language_alpha_code: str,
379
+ ) -> None:
380
+ actions = (
381
+ {
382
+ "_op_type": "update",
383
+ "_index": project,
384
+ "_routing": root_document,
385
+ ID_: doc_id,
386
+ "script": {
387
+ "source": _SCRIPT_SOURCES,
388
+ "lang": "painless",
389
+ "params": {
390
+ "language": target_language_alpha_code,
391
+ "translation": translation,
392
+ },
393
+ },
394
+ }
395
+ for doc_id, root_document, translation in translations
396
+ )
397
+ await async_bulk(es_client, actions, raise_on_error=True, refresh="wait_for")
398
+
399
+
400
+ def _untranslated_query(target_language_alpha_code: str) -> dict:
401
+ query = {
402
+ "query": {
403
+ BOOL: must_not(
404
+ {
405
+ "exists": {
406
+ "field": f"content_translated.{target_language_alpha_code}"
407
+ }
408
+ },
409
+ {TERM: {DOC_LANGUAGE: target_language_alpha_code}},
410
+ )
411
+ }
412
+ }
413
+ return query
414
+
415
+
416
+ async def _async_query_es(
417
+ es_client: ESClient,
418
+ project: str,
419
+ *,
420
+ body: dict,
421
+ source_includes: list[str] = None,
422
+ sort: list[str] = None,
423
+ ) -> AsyncGenerator[dict, None]:
424
+ async for res in es_client.poll_search_pages(
425
+ index=project,
426
+ body=body,
427
+ _source_includes=source_includes,
428
+ sort=sort,
429
+ ):
430
+ for hit in res[HITS][HITS]:
431
+ yield hit
432
+
433
+
434
+ ACTIVITIES = [
435
+ TranslationActivities.translation_worker_config,
436
+ TranslationActivities.create_translation_batches,
437
+ TranslationActivities.translate_docs,
438
+ ]
@@ -0,0 +1,17 @@
1
+ from datashare_python.config import WorkerConfig
2
+ from pydantic import Field
3
+
4
+ from .constants import TorchDevice
5
+
6
+
7
+ class TranslationWorkerConfig(WorkerConfig):
8
+ device: TorchDevice = Field(default=TorchDevice.CPU, frozen=True)
9
+
10
+ batch_size: int = 16
11
+ max_parallel_batches: int = 8
12
+ max_batch_byte_len: int = 1000000
13
+ # ctranslate2 params
14
+ beam_size: int = 4
15
+ inter_threads: int = 1
16
+ intra_threads: int = 0
17
+ compute_type: str = "auto" # quantization
@@ -0,0 +1,24 @@
1
+ from enum import StrEnum
2
+
3
+ from icij_common.es import DOC_CONTENT, DOC_LANGUAGE, DOC_ROOT_ID
4
+
5
+
6
+ class TaskQueue(StrEnum):
7
+ IO = "translation.io"
8
+ INFERENCE = "translation.inference"
9
+
10
+
11
+ class TorchDevice(StrEnum):
12
+ CPU = "cpu"
13
+ GPU = "cuda"
14
+
15
+
16
+ TRANSLATION_TASK_NAME = "translation"
17
+
18
+ TRANSLATION_WORKER_NAME = "translation-worker"
19
+ TRANSLATION_WORKFLOW_NAME = "translation"
20
+
21
+ CONTENT_LENGTH = "content_length"
22
+
23
+ TRANSLATION_DOC_SOURCES = [DOC_CONTENT, DOC_ROOT_ID, DOC_LANGUAGE]
24
+ BATCHING_DOC_SOURCES = TRANSLATION_DOC_SOURCES[1:] + [CONTENT_LENGTH]