runGpt function

Future<void> runGpt(
  1. List<String> arguments
)

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})');
}