runGpt function
Runs the GPT translation script.
Implementation
Future<void> runGpt(List<String> arguments) async {
print('Running GPT for slang...');
String? apiKey;
List<I18nLocale>? targetLocales;
String? outDir;
bool debug = false;
bool full = false;
for (final a in arguments) {
if (a.startsWith('--api-key=')) {
apiKey = a.substring(10);
} else if (a.startsWith('--target=')) {
final id = a.substring(9);
final preset = getPreset(id);
if (preset != null) {
targetLocales = preset;
} else {
targetLocales = [I18nLocale.fromString(id)];
}
} else if (a.startsWith('--outdir=')) {
outDir = a.substring(9);
} else if (a == '-f' || a == '--full') {
full = true;
} else if (a == '-d' || a == '--debug') {
debug = true;
}
}
if (apiKey == null) {
throw 'Missing API key. Specify it with --api-key=...';
}
if (targetLocales != null) {
print('');
print('Target: ${targetLocales.map((e) => e.languageTag).join(', ')}\n');
}
final fileCollection = SlangFileCollectionBuilder.readFromFileSystem(
verbose: false,
);
if (outDir == null) {
outDir = fileCollection.config.inputDirectory;
if (outDir == null) {
throw 'input_directory or --outdir=<path> must be specified.';
}
}
final gptConfig = GptConfig.fromMap(fileCollection.config.rawMap);
print(
'GPT config: ${gptConfig.model.id} / ${gptConfig.maxInputLength} max input length / ${gptConfig.temperature ?? 'default'} temperature',
);
if (gptConfig.excludes.isNotEmpty) {
print(
'Excludes: ${gptConfig.excludes.map((e) => e.languageTag).join(', ')}');
}
int promptCount = 0;
int inputTokens = 0;
int outputTokens = 0;
for (final file in fileCollection.files) {
if (file.locale != fileCollection.config.baseLocale) {
// Only use base locale as source
continue;
}
final raw = await file.read();
final Map<String, dynamic> originalTranslations;
try {
originalTranslations =
BaseDecoder.decodeWithFileType(fileCollection.config.fileType, raw);
} on FormatException catch (e) {
throw 'File: ${file.path}\n$e';
}
if (targetLocales == null) {
// translate to existing locales
for (final destFile in fileCollection.files) {
if (gptConfig.excludes.contains(destFile.locale)) {
// skip excluded locales
continue;
}
if (fileCollection.config.namespaces &&
destFile.namespace != file.namespace) {
// skip files in different namespaces
continue;
}
if (destFile.locale == file.locale) {
// skip same locale
continue;
}
final metrics = await _translate(
fileCollection: fileCollection,
gptConfig: gptConfig,
targetLocale: destFile.locale,
outDir: outDir,
full: full,
debug: debug,
file: file,
originalTranslations: originalTranslations,
apiKey: apiKey,
promptCount: promptCount,
);
promptCount = metrics.endPromptCount;
inputTokens += metrics.inputTokens;
outputTokens += metrics.outputTokens;
}
} else {
// translate to specified locales (they may not exist yet)
for (final targetLocale in targetLocales) {
final metrics = await _translate(
fileCollection: fileCollection,
gptConfig: gptConfig,
targetLocale: targetLocale,
outDir: outDir,
full: full,
debug: debug,
file: file,
originalTranslations: originalTranslations,
apiKey: apiKey,
promptCount: promptCount,
);
promptCount = metrics.endPromptCount;
inputTokens += metrics.inputTokens;
outputTokens += metrics.outputTokens;
}
}
}
print('');
print('Summary:');
print(' -> Total requests: $promptCount');
print(' -> Total input tokens: $inputTokens');
print(' -> Total output tokens: $outputTokens');
print(
' -> Total cost: \$${inputTokens * gptConfig.model.costPerInputToken + outputTokens * gptConfig.model.costPerOutputToken} ($inputTokens x \$${gptConfig.model.costPerInputToken} + $outputTokens x \$${gptConfig.model.costPerOutputToken})');
}