@qvac/translation-nmtcpp 0.18.1 → 0.19.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.
@@ -0,0 +1,141 @@
1
+ 'use strict'
2
+
3
+ const test = require('brittle')
4
+ const fs = require('bare-fs')
5
+ const os = require('bare-os')
6
+ const path = require('bare-path')
7
+ const process = require('bare-process')
8
+ const TranslationNmtcpp = require('../../index.js')
9
+ const { ensureIndicTransModel, ensureBergamotModel, TEST_TIMEOUT } = require('./utils')
10
+
11
+ test('fit rejects a relative model path before native use', (t) => {
12
+ let error
13
+ try {
14
+ TranslationNmtcpp.assessFit({
15
+ files: { model: 'model.bin' },
16
+ config: { modelType: TranslationNmtcpp.ModelTypes.IndicTrans }
17
+ })
18
+ } catch (caught) {
19
+ error = caught
20
+ }
21
+ t.ok(error instanceof TypeError)
22
+ t.ok(error && error.message.includes('absolute path'))
23
+ })
24
+
25
+ test('fit reports a missing model without loading it', (t) => {
26
+ const result = TranslationNmtcpp.assessFit({
27
+ files: { model: path.resolve(__dirname, 'missing-model.bin') },
28
+ config: { modelType: TranslationNmtcpp.ModelTypes.IndicTrans }
29
+ })
30
+ t.is(result.status, 'error')
31
+ t.is(result.reason, 'model-unreadable')
32
+ t.is(result.modelBytes, 0)
33
+ })
34
+
35
+ test('fit reads model, pivot, and vocab files below a Unicode directory', (t) => {
36
+ const dir = path.join(os.tmpdir(), `nmt-fit-${process.pid}-${Date.now()}-módèles-日本語`)
37
+ fs.mkdirSync(dir, { recursive: true })
38
+ try {
39
+ const files = {
40
+ model: path.join(dir, 'model.intgemm.bin'),
41
+ pivotModel: path.join(dir, 'pivot.intgemm.bin'),
42
+ srcVocab: path.join(dir, 'src.spm'),
43
+ dstVocab: path.join(dir, 'dst.spm'),
44
+ pivotSrcVocab: path.join(dir, 'pivot-src.spm'),
45
+ pivotDstVocab: path.join(dir, 'pivot-dst.spm')
46
+ }
47
+ for (const file of Object.values(files)) fs.writeFileSync(file, Buffer.alloc(64))
48
+
49
+ const fit = TranslationNmtcpp.assessFit({
50
+ files,
51
+ config: { modelType: TranslationNmtcpp.ModelTypes.Bergamot }
52
+ })
53
+ t.is(fit.modelBytes, 64 * 6)
54
+ t.ok(!fit.report.includes('unreadable'), 'every UTF-8 path was inspected')
55
+ } finally {
56
+ fs.rmSync(dir, { recursive: true, force: true })
57
+ }
58
+ })
59
+
60
+ function checkRealModelFit(t, request) {
61
+ const fit = TranslationNmtcpp.assessFit(request)
62
+ t.comment(`backend=${fit.backend} status=${fit.status} reason=${fit.reason}`)
63
+ t.ok(fit.modelBytes > 0, 'model file bytes were inspected')
64
+ if (fit.freeBytes === 0) {
65
+ t.is(fit.status, 'error')
66
+ t.is(fit.reason, 'device-memory-unavailable')
67
+ return
68
+ }
69
+ t.ok(fit.requiredBytes > fit.modelBytes, 'load allowance includes overhead')
70
+ t.ok(fit.freeBytes > 0, 'current device memory was queried')
71
+ t.ok(fit.report.includes('Translation load estimate:'), 'a readable report was returned')
72
+ t.ok(
73
+ fit.status === 'fits' ||
74
+ fit.status === 'does-not-fit' ||
75
+ (fit.status === 'error' && fit.reason === 'insufficient-evidence'),
76
+ 'the ordinary assessment has a capacity verdict or explicitly reports uncertainty'
77
+ )
78
+
79
+ // The same real model cannot fit when the caller reserves every available
80
+ // byte. This checks the capacity decision without assuming a runner's RAM.
81
+ const reserved = TranslationNmtcpp.assessFit({
82
+ ...request,
83
+ marginBytes: Number.MAX_SAFE_INTEGER
84
+ })
85
+ t.is(reserved.status, 'does-not-fit')
86
+ t.is(reserved.reason, 'does-not-fit')
87
+ t.ok(reserved.modelBytes >= fit.modelBytes)
88
+ }
89
+
90
+ test(
91
+ 'fit assesses a real IndicTrans model without loading it',
92
+ { timeout: TEST_TIMEOUT },
93
+ async (t) => {
94
+ const model = await ensureIndicTransModel()
95
+ checkRealModelFit(t, {
96
+ files: { model },
97
+ config: { modelType: TranslationNmtcpp.ModelTypes.IndicTrans, use_gpu: false }
98
+ })
99
+ }
100
+ )
101
+
102
+ test(
103
+ 'fit gives an empty canonical GPU backend precedence over its alias',
104
+ { timeout: TEST_TIMEOUT },
105
+ async (t) => {
106
+ const model = await ensureIndicTransModel()
107
+ const files = { model }
108
+ const config = { modelType: TranslationNmtcpp.ModelTypes.IndicTrans, use_gpu: true }
109
+ const automatic = TranslationNmtcpp.assessFit({ files, config })
110
+ const conflicting = TranslationNmtcpp.assessFit({
111
+ files,
112
+ config: { ...config, gpu_backend: '', gpuBackend: 'no-such-backend' }
113
+ })
114
+ t.is(conflicting.status, automatic.status)
115
+ t.is(conflicting.reason, automatic.reason)
116
+ t.is(conflicting.backend, automatic.backend)
117
+ }
118
+ )
119
+
120
+ test(
121
+ 'fit assesses a real Bergamot model without loading it',
122
+ { timeout: TEST_TIMEOUT },
123
+ async (t) => {
124
+ const modelDir = await ensureBergamotModel()
125
+ const names = fs.readdirSync(modelDir)
126
+ const modelName = names.find((name) => name.includes('.intgemm'))
127
+ const vocabName = names.find((name) => name.endsWith('.spm'))
128
+ t.ok(modelName, 'Bergamot weights are available')
129
+ t.ok(vocabName, 'Bergamot vocabulary is available')
130
+ if (!modelName || !vocabName) return
131
+
132
+ checkRealModelFit(t, {
133
+ files: {
134
+ model: path.join(modelDir, modelName),
135
+ srcVocab: path.join(modelDir, vocabName),
136
+ dstVocab: path.join(modelDir, vocabName)
137
+ },
138
+ config: { modelType: TranslationNmtcpp.ModelTypes.Bergamot }
139
+ })
140
+ }
141
+ )
@@ -11,6 +11,10 @@ async function runEsmDefaultExport (options = {}) { // eslint-disable-line no-un
11
11
  return runIntegrationModule('../integration/esm-default-export.test.js', options)
12
12
  }
13
13
 
14
+ async function runFit (options = {}) { // eslint-disable-line no-unused-vars
15
+ return runIntegrationModule('../integration/fit.test.js', options)
16
+ }
17
+
14
18
  async function runIndictrans (options = {}) { // eslint-disable-line no-unused-vars
15
19
  return runIntegrationModule('../integration/indictrans.test.js', options)
16
20
  }