mirror of https://github.com/vladmandic/automatic
parent
6876d2b84d
commit
73b90c5228
15
CHANGELOG.md
15
CHANGELOG.md
|
|
@ -1,7 +1,15 @@
|
|||
# Change Log for SD.Next
|
||||
|
||||
## Update for 2026-02-12
|
||||
## Update for 2026-02-14
|
||||
|
||||
### Highlights for 2026-02-14
|
||||
|
||||
TBD
|
||||
|
||||
### Details for 2026-02-14
|
||||
|
||||
- **Models**
|
||||
- TBD
|
||||
- **Image manipulation**
|
||||
- use high-quality [sharpfin](https://github.com/drhead/Sharpfin) accelerated library
|
||||
when available (cuda-only), thanks @CalamitousFelicitousness
|
||||
|
|
@ -18,6 +26,11 @@
|
|||
instead of being used implicitly via quantization, thanks @CalamitousFelicitousness
|
||||
- removed: old `codeformer` and `gfpgan` face restorers, thanks @CalamitousFelicitousness
|
||||
- **UI**
|
||||
- ui: **localization** improved translation quality and new translations locales:
|
||||
*en, en1, en2, en3, en4, hr, es, it, fr, de, pt, ru, zh, ja, ko, hi, ar, bn, ur, id, vi, tr, sr, po, he, xx, yy, qq, tlh*
|
||||
yes, this now includes stuff like *latin, esperanto, arabic, hebrew, klingon* and a lot more!
|
||||
and also intruce some pseudo-locales such as: *techno-babbel*, *for-n00bs*
|
||||
*hint*: click on locale icon in bottom-left corner to cycle through available locales, or set default in *settings -> ui*
|
||||
- ui: **themes** add *CTD-NT64Light*, *CTD-NT64Medium* and *CTD-NT64Dark*, thanks @resonantsky
|
||||
- ui: **gallery** add option to auto-refresh gallery, thanks @awsr
|
||||
- **Internal**
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ const jsConfig = defineConfig([
|
|||
camelcase: 'off',
|
||||
'default-case': 'off',
|
||||
'max-classes-per-file': 'warn',
|
||||
'guard-for-in': 'off',
|
||||
'no-await-in-loop': 'off',
|
||||
'no-bitwise': 'off',
|
||||
'no-continue': 'off',
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit ddf821483c8bcdac4868f15a9a838b45b4dd30ad
|
||||
Subproject commit 264ac9f38a718b37ca2c6ce17fd906d5d153cb2e
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit d25f3ee3a012d8a99cd6ded09152126a877b742e
|
||||
Subproject commit fc7cf10dcc3f17377b6a18c4cd0dbd2be5480f0b
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
19345
html/locale_de.json
19345
html/locale_de.json
File diff suppressed because it is too large
Load Diff
3015
html/locale_en.json
3015
html/locale_en.json
File diff suppressed because it is too large
Load Diff
17425
html/locale_es.json
17425
html/locale_es.json
File diff suppressed because it is too large
Load Diff
16803
html/locale_fr.json
16803
html/locale_fr.json
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
17173
html/locale_hr.json
17173
html/locale_hr.json
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
16903
html/locale_it.json
16903
html/locale_it.json
File diff suppressed because it is too large
Load Diff
16907
html/locale_ja.json
16907
html/locale_ja.json
File diff suppressed because it is too large
Load Diff
18011
html/locale_ko.json
18011
html/locale_ko.json
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
16433
html/locale_pt.json
16433
html/locale_pt.json
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
15359
html/locale_ru.json
15359
html/locale_ru.json
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
18819
html/locale_zh.json
18819
html/locale_zh.json
File diff suppressed because it is too large
Load Diff
14
installer.py
14
installer.py
|
|
@ -688,23 +688,23 @@ def check_diffusers():
|
|||
t_start = time.time()
|
||||
if args.skip_all:
|
||||
return
|
||||
sha = '5bf248ddd8796b4f4958559429071a28f9b2dd3a' # diffusers commit hash
|
||||
target_commit = '6141ae2348c1af14836ac076bf089a0259daa340' # diffusers commit hash
|
||||
# if args.use_rocm or args.use_zluda or args.use_directml:
|
||||
# sha = '043ab2520f6a19fce78e6e060a68dbc947edb9f9' # lock diffusers versions for now
|
||||
pkg = pkg_resources.working_set.by_key.get('diffusers', None)
|
||||
minor = int(pkg.version.split('.')[1] if pkg is not None else -1)
|
||||
cur = opts.get('diffusers_version', '') if minor > -1 else ''
|
||||
if (minor == -1) or ((cur != sha) and (not args.experimental)):
|
||||
current = opts.get('diffusers_version', '') if minor > -1 else ''
|
||||
if (minor == -1) or ((current != target_commit) and (not args.experimental)):
|
||||
if minor == -1:
|
||||
log.info(f'Diffusers install: commit={sha}')
|
||||
log.info(f'Diffusers install: commit={target_commit}')
|
||||
else:
|
||||
log.info(f'Diffusers update: current={pkg.version} hash={cur} target={sha}')
|
||||
log.info(f'Diffusers update: current={pkg.version} hash={current} target={target_commit}')
|
||||
pip('uninstall --yes diffusers', ignore=True, quiet=True, uv=False)
|
||||
if args.skip_git:
|
||||
log.warning('Git: marked as not available but required for diffusers installation')
|
||||
pip(f'install --upgrade git+https://github.com/huggingface/diffusers@{sha}', ignore=False, quiet=True, uv=False)
|
||||
pip(f'install --upgrade git+https://github.com/huggingface/diffusers@{target_commit}', ignore=False, quiet=True, uv=False)
|
||||
global diffusers_commit # pylint: disable=global-statement
|
||||
diffusers_commit = sha
|
||||
diffusers_commit = target_commit
|
||||
ts('diffusers', t_start)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
const allLocales = ['en', 'de', 'es', 'fr', 'it', 'ja', 'ko', 'pt', 'hr', 'ru', 'zh'];
|
||||
const allLocales = ['en', 'tb', 'nb', 'hr', 'es', 'it', 'fr', 'de', 'pt', 'ru', 'zh', 'ja', 'ko', 'hi', 'ar', 'bn', 'ur', 'id', 'vi', 'tr', 'sr', 'po', 'he', 'xx', 'qq', 'tlh'];
|
||||
const localeData = {
|
||||
prev: null,
|
||||
locale: null,
|
||||
|
|
@ -168,48 +168,6 @@ async function tooltipHide(e) {
|
|||
localeData.currentElement = null;
|
||||
}
|
||||
|
||||
async function validateHints(json, elements, tab) {
|
||||
json.missing = [];
|
||||
const data = Object.values(json).flat().filter((e) => e.hint.length > 0);
|
||||
for (const e of data) e.label = e.label.trim();
|
||||
if (tab) {
|
||||
elements = elements.filter((el) => el.closest(`#${tab}_tabitem`)); // include only elements within specified tab
|
||||
elements = elements.filter((el) => !el.closest(`#${tab}_scripts_tabitem`));
|
||||
}
|
||||
let original = elements.map((e) => e.textContent.toLowerCase().trim()).sort(); // should be case sensitive
|
||||
let duplicateUI = original.filter((e, i, a) => a.indexOf(e.toLowerCase()) !== i).sort();
|
||||
original = [...new Set(original)]; // remove duplicates
|
||||
duplicateUI = [...new Set(duplicateUI)]; // remove duplicates
|
||||
const current = data.map((e) => e.label.toLowerCase().trim()).sort(); // should be case sensitive
|
||||
// log('all elements:', original);
|
||||
// log('all hints:', current);
|
||||
log('hints-differences', { elements: original.length, hints: current.length });
|
||||
const missingHints = original.filter((e) => !current.includes(e.toLowerCase())).sort();
|
||||
const orphanedHints = current.filter((e) => !original.includes(e.toLowerCase())).sort();
|
||||
const duplicateHints = current.filter((e, i, a) => a.indexOf(e.toLowerCase()) !== i).sort();
|
||||
log('duplicate hints:', duplicateHints);
|
||||
log('duplicate labels:', duplicateUI);
|
||||
return [missingHints, orphanedHints];
|
||||
}
|
||||
|
||||
async function addMissingHints(json, missingHints) {
|
||||
if (missingHints.length === 0) return;
|
||||
json.missing = [];
|
||||
for (const h of missingHints.sort()) {
|
||||
if (h.length <= 1) continue;
|
||||
json.missing.push({ id: '', label: h, localized: '', hint: h, longHint: '' }); // Add longHint property
|
||||
}
|
||||
log('missing hints', missingHints);
|
||||
log('added missing hints:', { missing: json.missing });
|
||||
}
|
||||
|
||||
async function removeOrphanedHints(json, orphanedHints) {
|
||||
const data = Object.values(json).flat().filter((e) => e.hint.length > 0);
|
||||
for (const e of data) e.label = e.label.trim();
|
||||
const orphaned = data.filter((e) => orphanedHints.includes(e.label.toLowerCase()));
|
||||
log('orphaned hints:', { orphaned });
|
||||
}
|
||||
|
||||
async function replaceButtonText(el) {
|
||||
// https://www.nerdfonts.com/cheat-sheet
|
||||
// use unicode of icon with format nf-md-<icon>_circle
|
||||
|
|
@ -289,7 +247,58 @@ async function setHint(el, entry) {
|
|||
}
|
||||
}
|
||||
|
||||
async function setHints(analyze = false) {
|
||||
function createLocaleJSON() {
|
||||
const excludeText = ['▼']; // add any common non-label elements to exclude
|
||||
const ecxcludeIds = ['logo_nav']; // add any specific element IDs to exclude
|
||||
const elements = [
|
||||
...Array.from(gradioApp().querySelectorAll('button')),
|
||||
...Array.from(gradioApp().querySelectorAll('h1')),
|
||||
...Array.from(gradioApp().querySelectorAll('h2')),
|
||||
...Array.from(gradioApp().querySelectorAll('h3')),
|
||||
...Array.from(gradioApp().querySelectorAll('label > span')),
|
||||
...Array.from(gradioApp().querySelectorAll('.label-wrap > span')),
|
||||
];
|
||||
const json = {};
|
||||
const allSeen = {};
|
||||
for (const el of elements) {
|
||||
const label = el.textContent.trim();
|
||||
if (!label || label.length < 1 || label.length > 1024) continue; // likely not UI element
|
||||
if (excludeText.includes(label)) continue; // skip common non-label elements
|
||||
if (ecxcludeIds.includes(el.id)) continue; // skip specific element IDs
|
||||
|
||||
let hint = el.dataset.hint || '';
|
||||
if (hint.toLowerCase() === label.toLowerCase()) hint = ''; // skip if hint is same as label
|
||||
if (Object.keys(allSeen).includes(label.toLowerCase())) {
|
||||
if (hint.length === 0 || allSeen[label.toLowerCase()] === hint) continue; // seen this label and hint is empty or same as before
|
||||
hint = allSeen[label.toLowerCase()]; // use existing hint for this label
|
||||
}
|
||||
allSeen[label.toLowerCase()] = hint; // track seen labels
|
||||
|
||||
let section = label[0].toLowerCase();
|
||||
if (section >= '0' && section <= '9') section = '0';
|
||||
if ((section < 'a' || section > 'z') && section !== '0') section = '_';
|
||||
|
||||
let ui = el.closest('.group-extension')
|
||||
|| el.closest('.group-scripts')
|
||||
|| el.closest('.main-tab')
|
||||
|| el.closest('.settings_section')
|
||||
|| el.closest('.tabitem')
|
||||
|| 'other';
|
||||
ui = ui?.id?.replace('_tabitem_parent', '').replace('_section_row', '');
|
||||
if (ui?.includes('_script')) ui = ui?.split('_').slice(1).join('_').split(':')[0];
|
||||
|
||||
if (!json[section]) json[section] = [];
|
||||
const entry = { id: el.id || '', label, localized: '', hint, ui };
|
||||
json[section].push(entry); // add new entry
|
||||
}
|
||||
const sorted = Object.keys(json).sort().reduce((obj, key) => {
|
||||
obj[key] = json[key];
|
||||
return obj;
|
||||
}, {});
|
||||
console.log('localeJSON', sorted);
|
||||
}
|
||||
|
||||
async function setHints() {
|
||||
let json = {};
|
||||
let overrideData = [];
|
||||
if (localeData.finished) return;
|
||||
|
|
@ -311,6 +320,7 @@ async function setHints(analyze = false) {
|
|||
let localized = 0;
|
||||
let hints = 0;
|
||||
const t0 = performance.now();
|
||||
|
||||
for (const el of elements) {
|
||||
// localize elements text
|
||||
let found;
|
||||
|
|
@ -318,8 +328,8 @@ async function setHints(analyze = false) {
|
|||
else found = localeData.data.find((l) => l.label.toLowerCase().trim() === el.textContent.toLowerCase().trim());
|
||||
if (found?.localized?.length > 0) {
|
||||
if (!el.dataset.original) el.dataset.original = el.textContent;
|
||||
localized++;
|
||||
replaceTextContent(el, found.localized);
|
||||
localized++;
|
||||
} else if (found?.label && !localeData.initial && (localeData.locale === 'en')) { // reset to english
|
||||
replaceTextContent(el, found.label);
|
||||
}
|
||||
|
|
@ -336,19 +346,7 @@ async function setHints(analyze = false) {
|
|||
log('touchDevice', isTouchDevice);
|
||||
log('setHints', { type: localeData.type, locale: localeData.locale, elements: elements.length, localized, hints, data: localeData.data.length, override: overrideData.length, time: Math.round(t1 - t0) });
|
||||
// sortUIElements();
|
||||
if (analyze) {
|
||||
log('analyzing hints', 'control_tabitem');
|
||||
const [missingHints, orphanedHints] = await validateHints(json, elements);
|
||||
await addMissingHints(json, missingHints);
|
||||
await removeOrphanedHints(json, orphanedHints);
|
||||
}
|
||||
}
|
||||
|
||||
const analyzeHints = async () => {
|
||||
localeData.finished = false;
|
||||
localeData.data = [];
|
||||
await setHints(true);
|
||||
};
|
||||
|
||||
// Apply hints to a single element immediately
|
||||
async function applyHintToElement(el) {
|
||||
|
|
|
|||
|
|
@ -255,10 +255,9 @@ def check_quant(module: str = ''):
|
|||
|
||||
def check_nunchaku(module: str = ''):
|
||||
from modules import shared
|
||||
model_name = getattr(shared.opts, 'sd_model_checkpoint', '')
|
||||
if '+nunchaku' not in model_name:
|
||||
if 'nunchaku' not in shared.opts.sd_model_checkpoint.lower():
|
||||
return False
|
||||
base_path = model_name.split('+')[0]
|
||||
base_path = shared.opts.sd_model_checkpoint.split('+')[0]
|
||||
for v in shared.reference_models.values():
|
||||
if v.get('path', '') != base_path:
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -44,10 +44,10 @@
|
|||
"eslint": "^9.39.2",
|
||||
"eslint-config-airbnb-extended": "^3.0.0",
|
||||
"eslint-plugin-promise": "^7.2.1",
|
||||
"@google/genai": "^1.41.0",
|
||||
"globals": "^17.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@google/generative-ai": "^0.24.1",
|
||||
"argparse": "^2.0.1"
|
||||
},
|
||||
"//": {
|
||||
|
|
|
|||
|
|
@ -1,67 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
// script used to localize sdnext ui and hints to multiple languages using google gemini ai
|
||||
|
||||
const fs = require('node:fs');
|
||||
|
||||
const { GoogleGenerativeAI } = require('@google/generative-ai');
|
||||
|
||||
const api_key = process.env.GOOGLE_AI_API_KEY;
|
||||
const model = 'gemini-2.5-flash';
|
||||
const prompt = `Translate attached JSON from English to {language} using following rules: fields id, label and reload should be preserved from original, field localized should be a translated version of field label and field hint should be translated in-place.
|
||||
if field is less than 3 characters, do not translate it and keep it as is.
|
||||
Every JSON entry should have id, label, localized, reload and hint fields.
|
||||
Output should be pure JSON without any additional text. To better match translation, context of the text is related to Stable Diffusion and topic of Generative AI.`;
|
||||
const languages = {
|
||||
hr: 'Croatian',
|
||||
de: 'German',
|
||||
es: 'Spanish',
|
||||
fr: 'French',
|
||||
it: 'Italian',
|
||||
pt: 'Portuguese',
|
||||
zh: 'Chinese',
|
||||
ja: 'Japanese',
|
||||
ko: 'Korean',
|
||||
ru: 'Russian',
|
||||
};
|
||||
const chunkLines = 100;
|
||||
|
||||
async function localize() {
|
||||
if (!api_key || api_key.length < 10) {
|
||||
console.error('localize: set GOOGLE_AI_API_KEY env variable with your API key');
|
||||
process.exit();
|
||||
}
|
||||
const genAI = new GoogleGenerativeAI(api_key);
|
||||
const instance = genAI.getGenerativeModel({ model });
|
||||
const raw = fs.readFileSync('html/locale_en.json');
|
||||
const json = JSON.parse(raw);
|
||||
for (const locale of Object.keys(languages)) {
|
||||
const lang = languages[locale];
|
||||
const target = prompt.replace('{language}', lang).trim();
|
||||
const output = {};
|
||||
const fn = `html/locale_${locale}.json`;
|
||||
for (const section of Object.keys(json)) {
|
||||
const data = json[section];
|
||||
output[section] = [];
|
||||
for (let i = 0; i < data.length; i += chunkLines) {
|
||||
let markdown;
|
||||
try {
|
||||
const chunk = data.slice(i, i + chunkLines);
|
||||
const result = await instance.generateContent([target, JSON.stringify(chunk)]);
|
||||
markdown = result.response.text();
|
||||
const text = markdown.replaceAll('```', '').replace(/^.*\n/, '');
|
||||
const parsed = JSON.parse(text);
|
||||
output[section].push(...parsed);
|
||||
console.log(`localize: locale=${locale} lang=${lang} section=${section} chunk=${chunk.length} output=${output[section].length} fn=${fn}`);
|
||||
} catch (err) {
|
||||
console.error('localize:', err);
|
||||
console.error('localize input:', { target, section, i });
|
||||
console.error('localize output:', { markdown });
|
||||
}
|
||||
}
|
||||
const txt = JSON.stringify(output, null, 2);
|
||||
fs.writeFileSync(fn, txt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
localize();
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
#!/usr/bin/env node
|
||||
// script used to localize sdnext ui and hints to multiple languages using google gemini ai
|
||||
|
||||
import { GoogleGenAI, Type, ThinkingLevel } from '@google/genai';
|
||||
import * as fs from 'node:fs';
|
||||
import * as process from 'node:process';
|
||||
|
||||
const apiKey = process.env.GOOGLE_API_KEY;
|
||||
const model = 'gemini-3-flash-preview';
|
||||
const prompt = `## You are expert translator AI.
|
||||
Translate attached JSON from English to {language}.
|
||||
## Translation Rules:
|
||||
- Fields \`id\`, \`label\` and \`reload\` should be preserved from original.
|
||||
- Field \`localized\` should be a translated version of field \`label\`.
|
||||
- If field \`localized\` is less than 3 characters, do not translate it and keep it as is.
|
||||
- Field \`hint\` should be translated in-place.
|
||||
- Use alphabet and writing system of the target language.
|
||||
- Use terminology that is commonly used in the target language for software interfaces, especially in the context of Stable Diffusion and Generative AI.
|
||||
- Do not leave non-translated words in the output, except for technical terms that do not have a widely accepted translation in the target language. In such cases, provide a transliteration or a brief explanation in parentheses.
|
||||
- Ensure that all lines are present in the output, and that the output is valid JSON matching the provided schema.
|
||||
`;
|
||||
|
||||
const languages = {
|
||||
tb: 'English: Techno-Babble',
|
||||
nb: 'English: For-N00bs',
|
||||
hr: 'Croatian',
|
||||
es: 'Spanish',
|
||||
it: 'Italian',
|
||||
xx: 'Esperanto',
|
||||
qq: 'Latin',
|
||||
fr: 'French',
|
||||
de: 'German',
|
||||
pt: 'Portuguese',
|
||||
ru: 'Russian',
|
||||
zh: 'Chinese',
|
||||
ja: 'Japanese',
|
||||
ko: 'Korean',
|
||||
hi: 'Hindi',
|
||||
ar: 'Arabic',
|
||||
bn: 'Bengali',
|
||||
ur: 'Urdu',
|
||||
id: 'Indonesian',
|
||||
vi: 'Vietnamese',
|
||||
tr: 'Turkish',
|
||||
sr: 'Serbian',
|
||||
po: 'Polish',
|
||||
he: 'Hebrew',
|
||||
tlh: 'Klingon',
|
||||
};
|
||||
|
||||
const responseSchema = {
|
||||
type: Type.ARRAY,
|
||||
items: {
|
||||
type: Type.OBJECT,
|
||||
properties: {
|
||||
id: { type: Type.INTEGER, description: 'id of the item' },
|
||||
label: { type: Type.STRING, description: 'original label of the item' },
|
||||
localized: { type: Type.STRING, description: 'translated label of the item' },
|
||||
reload: { type: Type.STRING, description: 'n/a' },
|
||||
hint: { type: Type.STRING, description: 'long hint for the item' },
|
||||
},
|
||||
required: ['id', 'label', 'localized', 'reload', 'hint'],
|
||||
},
|
||||
};
|
||||
|
||||
async function localize() {
|
||||
if (!apiKey || apiKey.length < 10) {
|
||||
console.error('localize: set GOOGLE_API_KEY env variable with your API key');
|
||||
process.exit();
|
||||
}
|
||||
|
||||
const httpOptions = { timeout: 60000 };
|
||||
const ai = new GoogleGenAI({ apiKey, httpOptions });
|
||||
const thinkingConfig = {
|
||||
includeThoughts: false,
|
||||
thinkingLevel: ThinkingLevel.LOW,
|
||||
};
|
||||
|
||||
const params = {
|
||||
model,
|
||||
contents: {
|
||||
parts: [
|
||||
{ text: 'prompt' },
|
||||
{ text: 'data' },
|
||||
],
|
||||
},
|
||||
config: {
|
||||
responseMimeType: 'application/json',
|
||||
thinkingConfig,
|
||||
responseSchema,
|
||||
},
|
||||
};
|
||||
console.log('params:', params);
|
||||
|
||||
const raw = fs.readFileSync('html/locale_en.json');
|
||||
console.log('raw:', { bytes: raw.length });
|
||||
const json = JSON.parse(raw);
|
||||
console.log('targets:', { lang: Object.keys(languages), count: Object.keys(languages).length });
|
||||
|
||||
for (const index in Object.keys(languages)) {
|
||||
const locale = Object.keys(languages)[index];
|
||||
const lang = languages[locale];
|
||||
const langPrompt = prompt.replace('{language}', lang).trim();
|
||||
const output = {};
|
||||
const fn = `html/locale_${locale}.json`;
|
||||
if (fs.existsSync(fn)) {
|
||||
console.log('skip:', { index, locale, lang, fn });
|
||||
continue;
|
||||
}
|
||||
console.log('localize:', { index, locale, lang, fn });
|
||||
const t0 = performance.now();
|
||||
let allOk = true;
|
||||
for (const section of Object.keys(json)) {
|
||||
const keys = Object.keys(json[section]).length;
|
||||
console.log(' start:', { locale, section, keys });
|
||||
try {
|
||||
const t1 = performance.now();
|
||||
const sectionJSON = json[section];
|
||||
const sectionParams = { ...params };
|
||||
sectionParams.contents.parts[0].text = langPrompt;
|
||||
sectionParams.contents.parts[1].text = `## JSON Data: \n${JSON.stringify(sectionJSON)}`;
|
||||
const response = await ai.models.generateContent(sectionParams);
|
||||
const responseJSON = JSON.parse(response.text);
|
||||
const diff = Math.abs(keys - responseJSON.length);
|
||||
if (diff > 1) {
|
||||
console.error(' error:', { locale, section, input: keys, output: responseJSON.length });
|
||||
allOk = false;
|
||||
continue;
|
||||
}
|
||||
output[section] = JSON.parse(response.text);
|
||||
const t2 = performance.now();
|
||||
const kps = Math.round(1000000 * keys / (t2 - t1)) / 1000;
|
||||
console.log(' end:', { locale, section, time: Math.round(t2 - t1) / 1000, kps });
|
||||
} catch (err) {
|
||||
allOk = false;
|
||||
console.error(' error:', err);
|
||||
process.exit(1);
|
||||
}
|
||||
// break; // for testing, remove this to process all sections
|
||||
}
|
||||
if (allOk) {
|
||||
const txt = JSON.stringify(output, null, 2);
|
||||
fs.writeFileSync(fn, txt);
|
||||
}
|
||||
const t3 = performance.now();
|
||||
console.log(' time:', { locale, time: Math.round(t3 - t0) / 1000 });
|
||||
}
|
||||
}
|
||||
|
||||
localize();
|
||||
2
wiki
2
wiki
|
|
@ -1 +1 @@
|
|||
Subproject commit 64e9a355dc17eef9e237f7d3c9c4bde09e5aa6b2
|
||||
Subproject commit 8afa5d9c71b06d3cd7b81e8f6099d0d88e021c05
|
||||
Loading…
Reference in New Issue