llm-tuner 0.1.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.
- package/LICENSE +21 -0
- package/README.es.md +123 -0
- package/README.md +123 -0
- package/electron/icon.ico +0 -0
- package/electron/icon.png +0 -0
- package/electron/launch.js +85 -0
- package/electron/main.js +63 -0
- package/package.json +48 -0
- package/src/cli/index.js +303 -0
- package/src/cli/profile.js +74 -0
- package/src/core/benchmark.js +101 -0
- package/src/core/engines/lmstudio.js +358 -0
- package/src/core/engines/ollama.js +335 -0
- package/src/core/errors.js +16 -0
- package/src/core/estimator.js +237 -0
- package/src/core/gguf.js +187 -0
- package/src/core/hardware.js +162 -0
- package/src/core/index.js +10 -0
- package/src/core/installer.js +59 -0
- package/src/core/llama-server.js +107 -0
- package/src/core/presets.js +112 -0
- package/src/core/profiles.js +137 -0
- package/src/core/settings.js +44 -0
- package/src/core/tuner.js +305 -0
- package/src/core/util.js +148 -0
- package/src/i18n/core.js +11 -0
- package/src/i18n/en.js +243 -0
- package/src/i18n/es.js +243 -0
- package/src/i18n/index.js +23 -0
- package/src/web/public/app.js +551 -0
- package/src/web/public/favicon.ico +0 -0
- package/src/web/public/icon.png +0 -0
- package/src/web/public/index.html +131 -0
- package/src/web/public/profile.js +100 -0
- package/src/web/public/style.css +330 -0
- package/src/web/server.js +205 -0
package/src/i18n/en.js
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
// English catalog: the base language. Every key here must also exist in es.js.
|
|
2
|
+
export default {
|
|
3
|
+
// Engine choice
|
|
4
|
+
'engine.reason.onlyInstalled': '{name} is the only one installed.',
|
|
5
|
+
'engine.reason.multiGpu': 'You have several GPUs: LM Studio lets you set the GPU order and the KV type per model.',
|
|
6
|
+
'engine.reason.singleGpu': 'With a single GPU both perform the same; Ollama is lighter and runs as a service.',
|
|
7
|
+
'engine.reason.noneInstalled': 'No engine is installed; one can be installed automatically.',
|
|
8
|
+
|
|
9
|
+
// Progress
|
|
10
|
+
'status.freeingVram': 'Freeing VRAM (unloading loaded models)…',
|
|
11
|
+
'status.engine': 'Engine: {name}',
|
|
12
|
+
'status.searchNone': 'No preset for this context: looking for the best configuration…',
|
|
13
|
+
'status.searchHardware': 'The hardware changed since the last preset: looking for the best configuration…',
|
|
14
|
+
'status.searchModel': 'The model file changed: looking for the best configuration…',
|
|
15
|
+
'status.searchForced': 'New measurement requested: looking for the best configuration…',
|
|
16
|
+
'status.searchVariants': 'The downloaded variants of this model changed: looking for the best configuration…',
|
|
17
|
+
'status.applying': 'Applying configuration…',
|
|
18
|
+
'status.loading': 'Loading the model…',
|
|
19
|
+
|
|
20
|
+
// Load profiles: names, descriptions and the reason codes the core emits
|
|
21
|
+
'profile.name.speed': 'Speed',
|
|
22
|
+
'profile.name.balanced': 'Balanced',
|
|
23
|
+
'profile.name.quality': 'Quality',
|
|
24
|
+
'profile.desc.speed': 'fastest tokens per second; accepts lossy optimizations',
|
|
25
|
+
'profile.desc.balanced': 'speed weighted by quality; the default behaviour',
|
|
26
|
+
'profile.desc.quality': 'least loss that still runs fully on GPU',
|
|
27
|
+
'profile.variant.lightest': 'Variant {quant} ({key}): the lightest one downloaded.',
|
|
28
|
+
'profile.variant.selected': 'Variant {quant} ({key}): the one selected.',
|
|
29
|
+
'profile.variant.heaviestFit': 'Variant {quant} ({key}): the heaviest one downloaded that fits fully on GPU.',
|
|
30
|
+
'profile.variant.noFullGpu': 'No downloaded variant fits fully on GPU: the quality profile uses the balanced rule with {quant} ({key}).',
|
|
31
|
+
'profile.variant.preset': 'Variant {quant} ({key}): the one measured for the saved preset.',
|
|
32
|
+
'profile.variant.none': 'No downloaded variant was found: using {quant} ({key}).',
|
|
33
|
+
'profile.recommend.qualityFits': 'Quality is recommended: a downloaded variant fits fully on GPU with a precise KV cache.',
|
|
34
|
+
'profile.recommend.balancedFits': 'Balanced is recommended: the selected variant fits fully on GPU only with a more compressed KV cache than the quality profile allows.',
|
|
35
|
+
'profile.recommend.partialOffload': 'Speed is recommended: the selected variant does not fit fully on GPU at this context, so part of it will run on the CPU.',
|
|
36
|
+
'profile.preview.vramBusy': "VRAM is in use right now, so this preview is conservative. Loading first unloads this engine's models and then makes the real choice.",
|
|
37
|
+
'profile.fallback.noFullGpuConfig': 'No fully-on-GPU configuration passed the measurement: the quality profile used the balanced rule.',
|
|
38
|
+
|
|
39
|
+
// Errors
|
|
40
|
+
'errors.unknownEngine': 'Unknown engine: {engine}',
|
|
41
|
+
'errors.noConfigWorked': 'No configuration worked with this context. Try a smaller one.',
|
|
42
|
+
'errors.ggufNotFound': 'Cannot find the GGUF file for {key}',
|
|
43
|
+
'errors.lmstudioOpen': 'LM Studio is open; close it before applying the configuration.',
|
|
44
|
+
'errors.ollamaUnknownModel': 'Ollama does not recognize the model {key}',
|
|
45
|
+
|
|
46
|
+
// Install methods
|
|
47
|
+
'install.ollamaScript': 'Official script (ollama.com/install.sh, asks for sudo)',
|
|
48
|
+
'install.ollamaBrew': 'Homebrew (brew install --cask ollama)',
|
|
49
|
+
'install.ollamaDmg': 'Download Ollama.dmg',
|
|
50
|
+
'install.ollamaWinget': 'winget (Ollama.Ollama)',
|
|
51
|
+
'install.ollamaPs1': 'Official PowerShell script',
|
|
52
|
+
'install.lmsHeadless': 'LM Studio headless (llmster + lms, no sudo)',
|
|
53
|
+
'install.lmsBrew': 'Desktop app with Homebrew (brew install --cask lm-studio)',
|
|
54
|
+
'install.lmsWinget': 'Desktop app with winget (ElementLabs.LMStudio)',
|
|
55
|
+
'install.lmsHeadlessPs1': 'LM Studio headless (llmster, PowerShell script)',
|
|
56
|
+
'install.lmsDownload': 'Download the desktop app from lmstudio.ai',
|
|
57
|
+
|
|
58
|
+
// Benchmark and load results
|
|
59
|
+
'bench.oom': 'Not enough VRAM (OOM)',
|
|
60
|
+
'bench.oomOnLoad': 'Not enough VRAM (OOM while loading)',
|
|
61
|
+
'bench.lmsUnavailable': 'lms is not available',
|
|
62
|
+
'bench.ollamaTestServerFailed': 'Could not start a test Ollama server: {detail}',
|
|
63
|
+
'bench.loadFailed': 'Could not load the model',
|
|
64
|
+
'bench.mainServerNote': 'Measured on the main server: the KV type and Flash Attention are whatever it already has configured.',
|
|
65
|
+
|
|
66
|
+
// Applied changes
|
|
67
|
+
'changes.lmsHardware': 'Hardware config updated (GPU order and VRAM limit)',
|
|
68
|
+
'changes.lmsModelFull': 'Model config: {ctx} tokens, KV {kvType}, all layers on GPU, {threads} threads',
|
|
69
|
+
'changes.lmsModelPartial': 'Model config: {ctx} tokens, KV {kvType}, {gpuLayers}/{totalLayers} layers on GPU, {threads} threads',
|
|
70
|
+
'changes.lmsRestarted': 'LM Studio restarted',
|
|
71
|
+
'changes.ollamaExists': 'The model {name} already exists; left unchanged',
|
|
72
|
+
'changes.ollamaCreated': 'Model created: {name}',
|
|
73
|
+
'changes.ollamaSetx': 'User environment variables updated (setx)',
|
|
74
|
+
'changes.ollamaLaunchctl': 'Variables set with launchctl (until the next reboot; also add them to your profile if you want them to persist)',
|
|
75
|
+
'changes.ollamaSystemd': 'systemd override installed and Ollama restarted',
|
|
76
|
+
|
|
77
|
+
'errors.unknownLocale': 'Unknown language "{lang}". Valid values: {list}',
|
|
78
|
+
'errors.unknownTheme': 'Unknown theme "{theme}". Valid values: {list}',
|
|
79
|
+
'errors.unknownProfile': 'Unknown profile "{profile}". Valid values: {list}',
|
|
80
|
+
'errors.installNotFinished': 'The installation did not finish. Run llm-tuner again when it is done.',
|
|
81
|
+
'errors.modelDownloadFailed': 'Could not download the model',
|
|
82
|
+
'errors.noInstaller': 'There is no automatic installer for this system.',
|
|
83
|
+
'errors.installerExit': 'The installer exited with code {code}',
|
|
84
|
+
|
|
85
|
+
// Candidate description (CLI and web)
|
|
86
|
+
'candidate.allGpu': 'all on GPU',
|
|
87
|
+
'candidate.layersGpu': '{gpu}/{total} layers on GPU',
|
|
88
|
+
'candidate.expertsRam': ' · experts of {layers} layers in RAM',
|
|
89
|
+
'candidate.threads': ' · {n} threads',
|
|
90
|
+
'candidate.probe': ' · optimistic probe',
|
|
91
|
+
|
|
92
|
+
// Shared by CLI and web
|
|
93
|
+
'common.error': 'Error: {message}',
|
|
94
|
+
'common.na': 'n/a',
|
|
95
|
+
'common.longPrompt': 'long prompt (~{tokens} tokens)…',
|
|
96
|
+
'common.presetSaved': 'Preset saved: {file}',
|
|
97
|
+
'common.backups': 'Backups: {list}',
|
|
98
|
+
|
|
99
|
+
// CLI
|
|
100
|
+
'cli.help': `llm-tuner — load your local LLM with the fastest configuration for the context you need
|
|
101
|
+
|
|
102
|
+
Usage: llm-tuner [options]
|
|
103
|
+
--engine <lmstudio|ollama> Engine
|
|
104
|
+
--model <key> Model (LM Studio key or Ollama name)
|
|
105
|
+
--ctx <tokens> Context (e.g. 16384)
|
|
106
|
+
--profile <speed|balanced|quality> What to optimize for (asked in the wizard; balanced with --yes, --json, or when engine, model and context are all given)
|
|
107
|
+
--force Measure again even if a preset exists
|
|
108
|
+
--candidates <n> Configurations to test when measuring (3)
|
|
109
|
+
--yes Do not ask for confirmation
|
|
110
|
+
--dry-run Measure and show the changes without applying anything or saving a preset
|
|
111
|
+
--presets List saved presets
|
|
112
|
+
--json Final output as JSON
|
|
113
|
+
--lang <en|es> Interface language (saved for next time)
|
|
114
|
+
--theme <system|light|dark> Interface theme (saved for next time)
|
|
115
|
+
/settings Interactive settings menu
|
|
116
|
+
|
|
117
|
+
Presets are saved in {presetsDir}`,
|
|
118
|
+
'cli.desktopStartFailed': 'Could not start the desktop app: {error}\nThe desktop runtime (Electron) is downloaded the first time you run llm-tuner-desktop, so that first run needs a network connection.\nThe terminal interface works without it: run llm-tuner.',
|
|
119
|
+
'cli.settingsTitle': 'Settings',
|
|
120
|
+
'cli.settingsMenu': 'Select an option to configure:',
|
|
121
|
+
'cli.settingsLanguage': 'Language',
|
|
122
|
+
'cli.settingsTheme': 'Theme',
|
|
123
|
+
'cli.settingsExit': 'Save and return',
|
|
124
|
+
'cli.settingsSaved': 'Settings saved.',
|
|
125
|
+
'cli.langNotSaved': 'Could not save the language preference: {error}',
|
|
126
|
+
'cli.themeNotSaved': 'Could not save the theme preference: {error}',
|
|
127
|
+
'cli.noPresets': 'No saved presets.',
|
|
128
|
+
'cli.partial': 'partial',
|
|
129
|
+
'cli.display': ' · display',
|
|
130
|
+
'cli.noGpu': 'No compatible GPU: only the CPU will be used.',
|
|
131
|
+
'cli.whichEngine': 'Which engine do you want to use?',
|
|
132
|
+
'cli.installed': 'installed',
|
|
133
|
+
'cli.notInstalled': 'not installed · will be installed',
|
|
134
|
+
'cli.recommended': 'recommended',
|
|
135
|
+
'cli.noModels': '{engine} has no downloaded models.',
|
|
136
|
+
'cli.downloadOllama': 'Model to download (e.g. qwen2.5-coder:14b):',
|
|
137
|
+
'cli.downloadLms': 'Model to download (e.g. qwen/qwen2.5-coder-14b):',
|
|
138
|
+
'cli.model': 'Model:',
|
|
139
|
+
'cli.maxFullGpu': 'Maximum fully on GPU (estimated): {list} · trained up to {train}K',
|
|
140
|
+
'cli.tunedContexts': 'Contexts already tuned: {list}',
|
|
141
|
+
'cli.context': 'Context (tokens):',
|
|
142
|
+
'cli.contextRange': 'Between 512 and {limit}',
|
|
143
|
+
'cli.profile': 'Load profile:',
|
|
144
|
+
'cli.profileHint': 'Estimate: {quant} (about {size}) is not downloaded and would fit fully on your GPUs.',
|
|
145
|
+
'cli.profileSwitch': 'The {quant} variant suits this profile better: select it in {engine} to use it. The one selected now is the one that will be loaded.',
|
|
146
|
+
'cli.profileNotSaved': 'Could not save the profile preference: {error}',
|
|
147
|
+
'cli.presetHit': 'Preset found ({date}): {config} · {tps} t/s measured. No need to measure again.',
|
|
148
|
+
'cli.benchShort': '{tps} short',
|
|
149
|
+
'cli.benchDeep': ' · {tps} with {tokens} tokens',
|
|
150
|
+
'cli.changes': 'Changes:',
|
|
151
|
+
'cli.lmsRestart': 'LM Studio will close and reopen to save the hardware config.',
|
|
152
|
+
'cli.ollamaNewModel': 'New model {name} with num_ctx/num_gpu/num_thread fixed',
|
|
153
|
+
'cli.ollamaServer': 'Ollama server: {env}',
|
|
154
|
+
'cli.confirmApply': 'Apply and load the model?',
|
|
155
|
+
'cli.dryRun': '--dry-run: nothing was applied and no preset was saved.',
|
|
156
|
+
'cli.pending': 'To finish, run (asks for the administrator password):',
|
|
157
|
+
'cli.loaded': 'Model loaded in {engine}: {tps}',
|
|
158
|
+
'cli.usesModel': ' (uses the model {model})',
|
|
159
|
+
'cli.loadFailed': 'Could not load: {error}',
|
|
160
|
+
'cli.installMethod': 'Install method:',
|
|
161
|
+
'cli.installNow': 'Install now?',
|
|
162
|
+
'cli.installManual': 'Install the downloaded app and press Enter',
|
|
163
|
+
|
|
164
|
+
'errors.unknownInstallPlan': 'Unknown install plan',
|
|
165
|
+
'errors.loadInProgress': 'A load is already in progress',
|
|
166
|
+
'errors.invalidChatRequest': 'Invalid chat request',
|
|
167
|
+
|
|
168
|
+
// Web UI
|
|
169
|
+
'web.tagline': 'load your model with the fastest configuration',
|
|
170
|
+
'web.language': 'Language',
|
|
171
|
+
'web.stepEngine': 'Engine',
|
|
172
|
+
'web.modelAndContext': 'Model and context',
|
|
173
|
+
'web.stepLoad': 'Load',
|
|
174
|
+
'web.detectingHw': 'Detecting hardware…',
|
|
175
|
+
'web.railNote': 'The configuration is decided from your hardware, the model metadata and real measurements. The result is saved as a preset: it is only measured again if you change the context or the load profile.',
|
|
176
|
+
'web.whichEngine': 'Which engine do you want to use?',
|
|
177
|
+
'web.installMethod': 'Install method',
|
|
178
|
+
'web.install': 'Install',
|
|
179
|
+
'web.model': 'Model',
|
|
180
|
+
'web.context': 'Context (tokens)',
|
|
181
|
+
'web.profile': 'Load profile',
|
|
182
|
+
'web.profileDetail': 'Will load {quant}; KV cache types allowed: {kv}.',
|
|
183
|
+
'web.profileHint': 'Estimate: {quant} (about {size}) is not downloaded and would fit fully on your GPUs.',
|
|
184
|
+
'web.profileSwitch': 'The {quant} variant suits this profile better: select it in {engine} to use it. The one selected now is the one that will be loaded.',
|
|
185
|
+
'web.profileNotSaved': 'Could not save the profile preference: {error}',
|
|
186
|
+
'web.loadButton': 'Load',
|
|
187
|
+
'web.force': 'Measure again even if a preset exists',
|
|
188
|
+
'web.loading': 'Loading',
|
|
189
|
+
'web.inProgress': 'in progress',
|
|
190
|
+
'web.benchIntro': 'There is no preset for this context and profile: several configurations are tested on your hardware. It takes a few minutes and only happens once.',
|
|
191
|
+
'web.colConfig': 'Configuration',
|
|
192
|
+
'web.colGpuLayers': 'GPU layers',
|
|
193
|
+
'web.colEstimated': 'Estimated',
|
|
194
|
+
'web.colShort': 'Short',
|
|
195
|
+
'web.colDeep': 'With context',
|
|
196
|
+
'web.colVram': 'Peak VRAM',
|
|
197
|
+
'web.connectionLost': 'Lost connection to the local server',
|
|
198
|
+
'web.noGpu': 'No compatible GPU (CPU only)',
|
|
199
|
+
'web.recommended': 'recommended',
|
|
200
|
+
'web.installed': 'Installed',
|
|
201
|
+
'web.notInstalled': 'Not installed: it will be installed when you choose it',
|
|
202
|
+
'web.readingModels': 'Reading models…',
|
|
203
|
+
'web.noModels': 'No downloaded models',
|
|
204
|
+
'web.needsAdmin': 'This installer asks for the administrator password. Run in a terminal:\n\n {command}\n\nThen reload this page.',
|
|
205
|
+
'web.downloadOpened': 'The download was opened. Install the app and reload this page.',
|
|
206
|
+
'web.installDone': 'Installation finished.',
|
|
207
|
+
'web.installerFailed': 'the installer failed',
|
|
208
|
+
'web.readingModel': 'Reading the model…',
|
|
209
|
+
'web.modelReadFailed': 'Could not read the model: {error}',
|
|
210
|
+
'web.layers': '{n} layers',
|
|
211
|
+
'web.trainedUpTo': 'trained up to {ctx}',
|
|
212
|
+
'web.maxAllGpu': 'maximum all on GPU: {list}',
|
|
213
|
+
'web.presetSavedTitle': 'Saved preset · {tps} t/s',
|
|
214
|
+
'web.fitsGpu': 'Fits entirely on GPU',
|
|
215
|
+
'web.mayNeedKv': 'May need compressed KV or part on CPU',
|
|
216
|
+
'web.presetPillSaved': 'saved preset · {tps} t/s',
|
|
217
|
+
'web.presetPillNone': 'no preset · will be measured',
|
|
218
|
+
'web.gpuLayers': '{layers} layers · {used} of {free} free',
|
|
219
|
+
'web.vramAria': 'Estimated VRAM use on GPU {index}',
|
|
220
|
+
'web.legendOther': 'Other processes',
|
|
221
|
+
'web.legendModel': 'Model and context (estimated for the best option)',
|
|
222
|
+
'web.loadingTitle': 'Loading {model} with {ctx} of context',
|
|
223
|
+
'web.presetHit': 'Preset found ({date}): {config}. No measurements.',
|
|
224
|
+
'web.pending': 'pending',
|
|
225
|
+
'web.fromPreset': 'loaded from preset',
|
|
226
|
+
'web.measuredLoaded': 'measured and loaded',
|
|
227
|
+
'web.threadsCtx': '{threads} threads · {ctx} of context',
|
|
228
|
+
'web.usesModel': 'Uses the model',
|
|
229
|
+
'web.pendingCommands': 'To finish, run in a terminal (asks for the administrator password):',
|
|
230
|
+
'web.error': 'error',
|
|
231
|
+
'web.chatTitle': 'Test connection',
|
|
232
|
+
'web.chatSubtitle': 'Send a prompt to test model response',
|
|
233
|
+
'web.chatPlaceholder': 'Type a prompt to test…',
|
|
234
|
+
'web.chatSend': 'Send',
|
|
235
|
+
'web.chatThinking': 'Generating response…',
|
|
236
|
+
'web.theme': 'Theme',
|
|
237
|
+
'web.themeSystem': 'System',
|
|
238
|
+
'web.themeLight': 'Light',
|
|
239
|
+
'web.themeDark': 'Dark',
|
|
240
|
+
'web.settings': 'Settings',
|
|
241
|
+
'web.close': 'Close',
|
|
242
|
+
};
|
|
243
|
+
|
package/src/i18n/es.js
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
// Spanish catalog. Same keys and {params} as en.js.
|
|
2
|
+
export default {
|
|
3
|
+
// Engine choice
|
|
4
|
+
'engine.reason.onlyInstalled': '{name} es el único instalado.',
|
|
5
|
+
'engine.reason.multiGpu': 'Tienes varias GPUs: LM Studio permite fijar el orden de GPUs y el tipo de KV por modelo.',
|
|
6
|
+
'engine.reason.singleGpu': 'Con una sola GPU ambos rinden igual; Ollama es más ligero y funciona como servicio.',
|
|
7
|
+
'engine.reason.noneInstalled': 'No hay ningún motor instalado; se puede instalar automáticamente.',
|
|
8
|
+
|
|
9
|
+
// Progress
|
|
10
|
+
'status.freeingVram': 'Liberando VRAM (descargando modelos cargados)…',
|
|
11
|
+
'status.engine': 'Motor: {name}',
|
|
12
|
+
'status.searchNone': 'No hay preset para este contexto: buscando la mejor configuración…',
|
|
13
|
+
'status.searchHardware': 'El hardware cambió desde el último preset: buscando la mejor configuración…',
|
|
14
|
+
'status.searchModel': 'El archivo del modelo cambió: buscando la mejor configuración…',
|
|
15
|
+
'status.searchForced': 'Nueva medición solicitada: buscando la mejor configuración…',
|
|
16
|
+
'status.searchVariants': 'Las variantes descargadas de este modelo cambiaron: buscando la mejor configuración…',
|
|
17
|
+
'status.applying': 'Aplicando configuración…',
|
|
18
|
+
'status.loading': 'Cargando el modelo…',
|
|
19
|
+
|
|
20
|
+
// Load profiles: names, descriptions and the reason codes the core emits
|
|
21
|
+
'profile.name.speed': 'Velocidad',
|
|
22
|
+
'profile.name.balanced': 'Equilibrado',
|
|
23
|
+
'profile.name.quality': 'Calidad',
|
|
24
|
+
'profile.desc.speed': 'más tokens por segundo; acepta optimizaciones con pérdida',
|
|
25
|
+
'profile.desc.balanced': 'velocidad ponderada por calidad; el comportamiento predeterminado',
|
|
26
|
+
'profile.desc.quality': 'la menor pérdida que aún se ejecuta por completo en GPU',
|
|
27
|
+
'profile.variant.lightest': 'Variante {quant} ({key}): la más ligera de las descargadas.',
|
|
28
|
+
'profile.variant.selected': 'Variante {quant} ({key}): la seleccionada.',
|
|
29
|
+
'profile.variant.heaviestFit': 'Variante {quant} ({key}): la más pesada de las descargadas que cabe por completo en GPU.',
|
|
30
|
+
'profile.variant.noFullGpu': 'Ninguna variante descargada cabe por completo en GPU: el perfil de calidad usa la regla del equilibrado con {quant} ({key}).',
|
|
31
|
+
'profile.variant.preset': 'Variante {quant} ({key}): la que se midió para el preset guardado.',
|
|
32
|
+
'profile.variant.none': 'No se encontró ninguna variante descargada: se usa {quant} ({key}).',
|
|
33
|
+
'profile.recommend.qualityFits': 'Se recomienda Calidad: una variante descargada cabe por completo en GPU con una caché KV precisa.',
|
|
34
|
+
'profile.recommend.balancedFits': 'Se recomienda Equilibrado: la variante seleccionada cabe por completo en GPU solo con una caché KV más comprimida de la que admite el perfil de calidad.',
|
|
35
|
+
'profile.recommend.partialOffload': 'Se recomienda Velocidad: la variante seleccionada no cabe por completo en GPU con este contexto, así que una parte se ejecutará en la CPU.',
|
|
36
|
+
'profile.preview.vramBusy': 'La VRAM está en uso en este momento, así que esta vista previa es conservadora. Al cargar, primero se descargan los modelos de este motor y después se hace la elección real.',
|
|
37
|
+
'profile.fallback.noFullGpuConfig': 'Ninguna configuración con todo en GPU superó la medición: el perfil de calidad usó la regla del equilibrado.',
|
|
38
|
+
|
|
39
|
+
// Errors
|
|
40
|
+
'errors.unknownEngine': 'Motor desconocido: {engine}',
|
|
41
|
+
'errors.noConfigWorked': 'Ninguna configuración funcionó con este contexto. Prueba con uno menor.',
|
|
42
|
+
'errors.ggufNotFound': 'No encuentro el archivo GGUF de {key}',
|
|
43
|
+
'errors.lmstudioOpen': 'LM Studio está abierto; ciérralo antes de aplicar la configuración.',
|
|
44
|
+
'errors.ollamaUnknownModel': 'Ollama no reconoce el modelo {key}',
|
|
45
|
+
|
|
46
|
+
// Install methods
|
|
47
|
+
'install.ollamaScript': 'Script oficial (ollama.com/install.sh, pide sudo)',
|
|
48
|
+
'install.ollamaBrew': 'Homebrew (brew install --cask ollama)',
|
|
49
|
+
'install.ollamaDmg': 'Descargar Ollama.dmg',
|
|
50
|
+
'install.ollamaWinget': 'winget (Ollama.Ollama)',
|
|
51
|
+
'install.ollamaPs1': 'Script oficial PowerShell',
|
|
52
|
+
'install.lmsHeadless': 'LM Studio sin interfaz (llmster + lms, sin sudo)',
|
|
53
|
+
'install.lmsBrew': 'App de escritorio con Homebrew (brew install --cask lm-studio)',
|
|
54
|
+
'install.lmsWinget': 'App de escritorio con winget (ElementLabs.LMStudio)',
|
|
55
|
+
'install.lmsHeadlessPs1': 'LM Studio sin interfaz (llmster, script PowerShell)',
|
|
56
|
+
'install.lmsDownload': 'Descargar la app de escritorio desde lmstudio.ai',
|
|
57
|
+
|
|
58
|
+
// Benchmark and load results
|
|
59
|
+
'bench.oom': 'Sin VRAM suficiente (OOM)',
|
|
60
|
+
'bench.oomOnLoad': 'Sin VRAM suficiente (OOM al cargar)',
|
|
61
|
+
'bench.lmsUnavailable': 'lms no disponible',
|
|
62
|
+
'bench.ollamaTestServerFailed': 'No pude iniciar un servidor Ollama de pruebas: {detail}',
|
|
63
|
+
'bench.loadFailed': 'No se pudo cargar el modelo',
|
|
64
|
+
'bench.mainServerNote': 'Medido en el servidor principal: el tipo de KV y Flash Attention son los que ya tenga configurados.',
|
|
65
|
+
|
|
66
|
+
// Applied changes
|
|
67
|
+
'changes.lmsHardware': 'Config de hardware actualizada (orden de GPUs y límite de VRAM)',
|
|
68
|
+
'changes.lmsModelFull': 'Config del modelo: {ctx} tokens, KV {kvType}, todas las capas en GPU, {threads} hilos',
|
|
69
|
+
'changes.lmsModelPartial': 'Config del modelo: {ctx} tokens, KV {kvType}, {gpuLayers}/{totalLayers} capas en GPU, {threads} hilos',
|
|
70
|
+
'changes.lmsRestarted': 'LM Studio reiniciado',
|
|
71
|
+
'changes.ollamaExists': 'El modelo {name} ya existe; no se modifica',
|
|
72
|
+
'changes.ollamaCreated': 'Modelo creado: {name}',
|
|
73
|
+
'changes.ollamaSetx': 'Variables de entorno de usuario actualizadas (setx)',
|
|
74
|
+
'changes.ollamaLaunchctl': 'Variables aplicadas con launchctl (hasta el próximo reinicio; añade también a tu perfil si quieres que persistan)',
|
|
75
|
+
'changes.ollamaSystemd': 'Override de systemd instalado y Ollama reiniciado',
|
|
76
|
+
|
|
77
|
+
'errors.unknownLocale': 'Idioma desconocido "{lang}". Valores válidos: {list}',
|
|
78
|
+
'errors.unknownTheme': 'Tema desconocido "{theme}". Valores válidos: {list}',
|
|
79
|
+
'errors.unknownProfile': 'Perfil desconocido "{profile}". Valores válidos: {list}',
|
|
80
|
+
'errors.installNotFinished': 'La instalación no terminó. Vuelve a ejecutar llm-tuner cuando acabe.',
|
|
81
|
+
'errors.modelDownloadFailed': 'No se pudo descargar el modelo',
|
|
82
|
+
'errors.noInstaller': 'No hay un instalador automático para este sistema.',
|
|
83
|
+
'errors.installerExit': 'El instalador terminó con código {code}',
|
|
84
|
+
|
|
85
|
+
// Candidate description (CLI and web)
|
|
86
|
+
'candidate.allGpu': 'todo en GPU',
|
|
87
|
+
'candidate.layersGpu': '{gpu}/{total} capas en GPU',
|
|
88
|
+
'candidate.expertsRam': ' · expertos de {layers} capas en RAM',
|
|
89
|
+
'candidate.threads': ' · {n} hilos',
|
|
90
|
+
'candidate.probe': ' · prueba optimista',
|
|
91
|
+
|
|
92
|
+
// Shared by CLI and web
|
|
93
|
+
'common.error': 'Error: {message}',
|
|
94
|
+
'common.na': 'n/d',
|
|
95
|
+
'common.longPrompt': 'prompt largo (~{tokens} tokens)…',
|
|
96
|
+
'common.presetSaved': 'Preset guardado: {file}',
|
|
97
|
+
'common.backups': 'Copias de seguridad: {list}',
|
|
98
|
+
|
|
99
|
+
// CLI
|
|
100
|
+
'cli.help': `llm-tuner — carga tu LLM local con la configuración más rápida para el contexto que necesitas
|
|
101
|
+
|
|
102
|
+
Uso: llm-tuner [opciones]
|
|
103
|
+
--engine <lmstudio|ollama> Motor
|
|
104
|
+
--model <clave> Modelo (clave de LM Studio o nombre de Ollama)
|
|
105
|
+
--ctx <tokens> Contexto (p. ej. 16384)
|
|
106
|
+
--profile <speed|balanced|quality> Qué optimizar (se pregunta en el asistente; balanced con --yes, --json, o si se indican motor, modelo y contexto)
|
|
107
|
+
--force Volver a medir aunque exista un preset
|
|
108
|
+
--candidates <n> Configuraciones a probar al medir (3)
|
|
109
|
+
--yes No pedir confirmación
|
|
110
|
+
--dry-run Medir y mostrar cambios sin aplicar nada ni guardar preset
|
|
111
|
+
--presets Listar presets guardados
|
|
112
|
+
--json Salida final en JSON
|
|
113
|
+
--lang <en|es> Idioma de la interfaz (se guarda para la próxima vez)
|
|
114
|
+
--theme <system|light|dark> Tema de la interfaz (se guarda para la próxima)
|
|
115
|
+
/settings Menú interactivo de configuración
|
|
116
|
+
|
|
117
|
+
Los presets se guardan en {presetsDir}`,
|
|
118
|
+
'cli.desktopStartFailed': 'No se pudo iniciar la aplicación de escritorio: {error}\nEl entorno de escritorio (Electron) se descarga la primera vez que ejecutas llm-tuner-desktop, así que esa primera ejecución necesita conexión a la red.\nLa interfaz de terminal funciona sin él: ejecuta llm-tuner.',
|
|
119
|
+
'cli.settingsTitle': 'Configuración',
|
|
120
|
+
'cli.settingsMenu': 'Selecciona una opción para configurar:',
|
|
121
|
+
'cli.settingsLanguage': 'Idioma',
|
|
122
|
+
'cli.settingsTheme': 'Tema',
|
|
123
|
+
'cli.settingsExit': 'Guardar y volver',
|
|
124
|
+
'cli.settingsSaved': 'Configuración guardada.',
|
|
125
|
+
'cli.langNotSaved': 'No se pudo guardar la preferencia de idioma: {error}',
|
|
126
|
+
'cli.themeNotSaved': 'No se pudo guardar la preferencia de tema: {error}',
|
|
127
|
+
'cli.noPresets': 'No hay presets guardados.',
|
|
128
|
+
'cli.partial': 'parcial',
|
|
129
|
+
'cli.display': ' · pantalla',
|
|
130
|
+
'cli.noGpu': 'Sin GPU compatible: se usará solo CPU.',
|
|
131
|
+
'cli.whichEngine': '¿Qué motor quieres usar?',
|
|
132
|
+
'cli.installed': 'instalado',
|
|
133
|
+
'cli.notInstalled': 'no instalado · se instalará',
|
|
134
|
+
'cli.recommended': 'recomendado',
|
|
135
|
+
'cli.noModels': '{engine} no tiene modelos descargados.',
|
|
136
|
+
'cli.downloadOllama': 'Modelo a descargar (p. ej. qwen2.5-coder:14b):',
|
|
137
|
+
'cli.downloadLms': 'Modelo a descargar (p. ej. qwen/qwen2.5-coder-14b):',
|
|
138
|
+
'cli.model': 'Modelo:',
|
|
139
|
+
'cli.maxFullGpu': 'Máximo con todo en GPU (estimado): {list} · entrenado hasta {train}K',
|
|
140
|
+
'cli.tunedContexts': 'Contextos ya ajustados: {list}',
|
|
141
|
+
'cli.context': 'Contexto (tokens):',
|
|
142
|
+
'cli.contextRange': 'Entre 512 y {limit}',
|
|
143
|
+
'cli.profile': 'Perfil de carga:',
|
|
144
|
+
'cli.profileHint': 'Estimación: {quant} (unos {size}) no está descargada y cabría por completo en tus GPUs.',
|
|
145
|
+
'cli.profileSwitch': 'La variante {quant} se ajusta mejor a este perfil: selecciónala en {engine} para usarla. Se cargará la que está seleccionada ahora.',
|
|
146
|
+
'cli.profileNotSaved': 'No se pudo guardar la preferencia de perfil: {error}',
|
|
147
|
+
'cli.presetHit': 'Preset encontrado ({date}): {config} · {tps} t/s medidos. No hace falta volver a medir.',
|
|
148
|
+
'cli.benchShort': '{tps} corto',
|
|
149
|
+
'cli.benchDeep': ' · {tps} con {tokens} tokens',
|
|
150
|
+
'cli.changes': 'Cambios:',
|
|
151
|
+
'cli.lmsRestart': 'LM Studio se cerrará y se volverá a abrir para guardar la config de hardware.',
|
|
152
|
+
'cli.ollamaNewModel': 'Nuevo modelo {name} con num_ctx/num_gpu/num_thread fijados',
|
|
153
|
+
'cli.ollamaServer': 'Servidor Ollama: {env}',
|
|
154
|
+
'cli.confirmApply': '¿Aplicar y cargar el modelo?',
|
|
155
|
+
'cli.dryRun': '--dry-run: no se aplicó nada ni se guardó preset.',
|
|
156
|
+
'cli.pending': 'Para terminar ejecuta (pide contraseña de administrador):',
|
|
157
|
+
'cli.loaded': 'Modelo cargado en {engine}: {tps}',
|
|
158
|
+
'cli.usesModel': ' (usa el modelo {model})',
|
|
159
|
+
'cli.loadFailed': 'No se pudo cargar: {error}',
|
|
160
|
+
'cli.installMethod': 'Método de instalación:',
|
|
161
|
+
'cli.installNow': '¿Instalar ahora?',
|
|
162
|
+
'cli.installManual': 'Instala la app descargada y pulsa Enter',
|
|
163
|
+
|
|
164
|
+
'errors.unknownInstallPlan': 'Plan de instalación desconocido',
|
|
165
|
+
'errors.loadInProgress': 'Ya hay una carga en curso',
|
|
166
|
+
'errors.invalidChatRequest': 'Solicitud de chat no válida',
|
|
167
|
+
|
|
168
|
+
// Web UI
|
|
169
|
+
'web.tagline': 'carga tu modelo con la configuración más rápida',
|
|
170
|
+
'web.language': 'Idioma',
|
|
171
|
+
'web.stepEngine': 'Motor',
|
|
172
|
+
'web.modelAndContext': 'Modelo y contexto',
|
|
173
|
+
'web.stepLoad': 'Carga',
|
|
174
|
+
'web.detectingHw': 'Detectando hardware…',
|
|
175
|
+
'web.railNote': 'La configuración se decide con tu hardware, los metadatos del modelo y mediciones reales. El resultado se guarda como preset: solo se vuelve a medir si cambias el contexto o el perfil de carga.',
|
|
176
|
+
'web.whichEngine': '¿Qué motor quieres usar?',
|
|
177
|
+
'web.installMethod': 'Método de instalación',
|
|
178
|
+
'web.install': 'Instalar',
|
|
179
|
+
'web.model': 'Modelo',
|
|
180
|
+
'web.context': 'Contexto (tokens)',
|
|
181
|
+
'web.profile': 'Perfil de carga',
|
|
182
|
+
'web.profileDetail': 'Se cargará {quant}; tipos de caché KV permitidos: {kv}.',
|
|
183
|
+
'web.profileHint': 'Estimación: {quant} (unos {size}) no está descargada y cabría por completo en tus GPUs.',
|
|
184
|
+
'web.profileSwitch': 'La variante {quant} se ajusta mejor a este perfil: selecciónala en {engine} para usarla. Se cargará la que está seleccionada ahora.',
|
|
185
|
+
'web.profileNotSaved': 'No se pudo guardar la preferencia de perfil: {error}',
|
|
186
|
+
'web.loadButton': 'Cargar',
|
|
187
|
+
'web.force': 'Volver a medir aunque exista un preset',
|
|
188
|
+
'web.loading': 'Cargando',
|
|
189
|
+
'web.inProgress': 'en curso',
|
|
190
|
+
'web.benchIntro': 'No hay preset para este contexto y perfil: se prueban varias configuraciones con tu hardware. Tarda unos minutos y solo ocurre una vez.',
|
|
191
|
+
'web.colConfig': 'Configuración',
|
|
192
|
+
'web.colGpuLayers': 'Capas GPU',
|
|
193
|
+
'web.colEstimated': 'Estimado',
|
|
194
|
+
'web.colShort': 'Corto',
|
|
195
|
+
'web.colDeep': 'Con contexto',
|
|
196
|
+
'web.colVram': 'VRAM pico',
|
|
197
|
+
'web.connectionLost': 'Se perdió la conexión con el servidor local',
|
|
198
|
+
'web.noGpu': 'Sin GPU compatible (solo CPU)',
|
|
199
|
+
'web.recommended': 'recomendado',
|
|
200
|
+
'web.installed': 'Instalado',
|
|
201
|
+
'web.notInstalled': 'No instalado: se instalará al elegirlo',
|
|
202
|
+
'web.readingModels': 'Leyendo modelos…',
|
|
203
|
+
'web.noModels': 'No hay modelos descargados',
|
|
204
|
+
'web.needsAdmin': 'Este instalador pide la contraseña de administrador. Ejecuta en una terminal:\n\n {command}\n\nDespués recarga esta página.',
|
|
205
|
+
'web.downloadOpened': 'Se abrió la descarga. Instala la app y recarga esta página.',
|
|
206
|
+
'web.installDone': 'Instalación terminada.',
|
|
207
|
+
'web.installerFailed': 'el instalador falló',
|
|
208
|
+
'web.readingModel': 'Leyendo el modelo…',
|
|
209
|
+
'web.modelReadFailed': 'No pude leer el modelo: {error}',
|
|
210
|
+
'web.layers': '{n} capas',
|
|
211
|
+
'web.trainedUpTo': 'entrenado hasta {ctx}',
|
|
212
|
+
'web.maxAllGpu': 'máximo todo en GPU: {list}',
|
|
213
|
+
'web.presetSavedTitle': 'Preset guardado · {tps} t/s',
|
|
214
|
+
'web.fitsGpu': 'Cabe entero en GPU',
|
|
215
|
+
'web.mayNeedKv': 'Puede requerir KV comprimido o parte en CPU',
|
|
216
|
+
'web.presetPillSaved': 'preset guardado · {tps} t/s',
|
|
217
|
+
'web.presetPillNone': 'sin preset · se medirá',
|
|
218
|
+
'web.gpuLayers': '{layers} capas · {used} de {free} libres',
|
|
219
|
+
'web.vramAria': 'Uso estimado de VRAM en GPU {index}',
|
|
220
|
+
'web.legendOther': 'Otros procesos',
|
|
221
|
+
'web.legendModel': 'Modelo y contexto (estimado para la mejor opción)',
|
|
222
|
+
'web.loadingTitle': 'Cargando {model} con {ctx} de contexto',
|
|
223
|
+
'web.presetHit': 'Preset encontrado ({date}): {config}. Sin mediciones.',
|
|
224
|
+
'web.pending': 'pendiente',
|
|
225
|
+
'web.fromPreset': 'cargado desde preset',
|
|
226
|
+
'web.measuredLoaded': 'medido y cargado',
|
|
227
|
+
'web.threadsCtx': '{threads} hilos · {ctx} de contexto',
|
|
228
|
+
'web.usesModel': 'Usa el modelo',
|
|
229
|
+
'web.pendingCommands': 'Para terminar, ejecuta en una terminal (pide contraseña de administrador):',
|
|
230
|
+
'web.error': 'error',
|
|
231
|
+
'web.chatTitle': 'Probar conexión',
|
|
232
|
+
'web.chatSubtitle': 'Envía un mensaje para probar la respuesta del modelo',
|
|
233
|
+
'web.chatPlaceholder': 'Escribe un mensaje de prueba…',
|
|
234
|
+
'web.chatSend': 'Enviar',
|
|
235
|
+
'web.chatThinking': 'Generando respuesta…',
|
|
236
|
+
'web.theme': 'Tema',
|
|
237
|
+
'web.themeSystem': 'Sistema',
|
|
238
|
+
'web.themeLight': 'Claro',
|
|
239
|
+
'web.themeDark': 'Oscuro',
|
|
240
|
+
'web.settings': 'Configuración',
|
|
241
|
+
'web.close': 'Cerrar',
|
|
242
|
+
};
|
|
243
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import en from './en.js';
|
|
2
|
+
import es from './es.js';
|
|
3
|
+
import { LOCALES, DEFAULT_LOCALE, normalizeLocale, format } from './core.js';
|
|
4
|
+
|
|
5
|
+
export { LOCALES, DEFAULT_LOCALE, normalizeLocale, format };
|
|
6
|
+
|
|
7
|
+
export const CATALOGS = { en, es };
|
|
8
|
+
|
|
9
|
+
/** Translate `key`; falls back to English, then to the key itself so gaps are visible. */
|
|
10
|
+
export function t(locale, key, params) {
|
|
11
|
+
return format(CATALOGS[normalizeLocale(locale)][key] ?? CATALOGS.en[key] ?? key, params);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Full message table for a locale, with English filling any gap. */
|
|
15
|
+
export function messagesFor(locale) {
|
|
16
|
+
return { ...CATALOGS.en, ...CATALOGS[normalizeLocale(locale)] };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Text for an error: TunerErrors are translated, anything else is shown as-is. */
|
|
20
|
+
export function errorText(locale, err) {
|
|
21
|
+
if (err?.name === 'TunerError' && err.code) return t(locale, err.code, err.params);
|
|
22
|
+
return String(err?.message ?? err);
|
|
23
|
+
}
|