Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 9 additions & 13 deletions source/Cute/Commands/Content/ContentTranslateCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,7 @@ namespace Cute.Commands.Content;

public class ContentTranslateCommand(IConsoleWriter console, ILogger<ContentTranslateCommand> logger,
AppSettings appSettings, TranslateFactory translateFactory, HttpClient httpClient) : BaseLoggedInCommand<ContentTranslateCommand.Settings>(console, logger, appSettings)
{
private const int ENTRY_BATCH_SIZE = 20;
private const int TRANSLATION_BATCH_SIZE = 50;
private const int MAX_ENTRY_UPDATE_CONCURRENCY = 10;

{
private readonly TranslateFactory _translateFactory = translateFactory;
private readonly HttpClient _httpClient = httpClient;
private readonly ConcurrentDictionary<TranslationService, ITranslator> _translatorCache = new();
Expand Down Expand Up @@ -59,6 +55,10 @@ public class Settings : ContentCommandSettings
[Description("Indicates how many concurrent calls can be made to a translation service for a single entry. Default is 10")]
public int MaxConcurrency { get; set; } = 10;

[CommandOption("--entry-batch-size")]
[Description("Indicates how many concurrent calls can be made to a translation service for a single entry. Default is 10")]
public int EntryBatchSize { get; set; } = 10;

[CommandOption("--fallback-service")]
[Description("Fallback translation service (Azure, Google, Deepl, GPT4o), in case configured one doesn't return a value. Will translate without a custom model and glossary")]
public TranslationService? FallbackService { get; set; } = null;
Expand Down Expand Up @@ -162,7 +162,6 @@ public override async Task<int> ExecuteCommandAsync(CommandContext context, Sett
{
// Create semaphores to limit concurrent operations
var throttler = new SemaphoreSlim(settings.MaxConcurrency);
var updateSemaphore = new SemaphoreSlim(MAX_ENTRY_UPDATE_CONCURRENCY);
bool needToPublish = false;
Dictionary<string, List<string>> failedEntryIds = new Dictionary<string, List<string>>();

Expand Down Expand Up @@ -204,7 +203,7 @@ await ProgressBars.Instance()

entryBatch.Add(entry);

if (entryBatch.Count >= ENTRY_BATCH_SIZE)
if (entryBatch.Count >= settings.EntryBatchSize)
{
var (batchSymbols, batchNeedsPublish, batchFailures) = await ProcessEntryBatch(
entryBatch,
Expand All @@ -217,7 +216,6 @@ await ProgressBars.Instance()
translationConfiguration,
settings,
throttler,
updateSemaphore,
taskTranslate,
glossary);

Expand Down Expand Up @@ -250,7 +248,6 @@ await ProgressBars.Instance()
translationConfiguration,
settings,
throttler,
updateSemaphore,
taskTranslate,
glossary);

Expand All @@ -266,7 +263,7 @@ await ProgressBars.Instance()
}

// Flush any remaining pending updates
await FlushPendingUpdates(updateSemaphore);
await FlushPendingUpdates(throttler);

taskTranslate.Description = $"{Emoji.Known.Robot} Translation completed ({symbols} symbols translated)";
taskTranslate.StopTask();
Expand Down Expand Up @@ -314,7 +311,6 @@ await PerformBulkOperations(
Dictionary<string, CuteLanguage> translationConfiguration,
Settings settings,
SemaphoreSlim throttler,
SemaphoreSlim updateSemaphore,
ProgressTask taskTranslate,
Dictionary<string, Dictionary<string, string>>? glossary = null)
{
Expand Down Expand Up @@ -449,7 +445,7 @@ flatEntryTargetLocaleValue is null ||
if (entryChanged)
{
needsPublish = true;
updateTasks.Add(UpdateEntryAsync(entryId, originalEntry, flatEntry, serializer, fieldsToTranslate, targetLocaleCodes, updateSemaphore));
updateTasks.Add(UpdateEntryAsync(entryId, originalEntry, flatEntry, serializer, fieldsToTranslate, targetLocaleCodes, throttler));
}
}

Expand Down Expand Up @@ -512,7 +508,7 @@ private async Task UpdateEntryAsync(
}
else
{
translations = await translator.Translate(text, from, targetLanguages);
translations = await translator.Translate(text, from, targetLanguages, glossaries);
}
}
catch (Exception ex)
Expand Down
6 changes: 3 additions & 3 deletions source/Cute/Services/Translation/AzureOpenAiTranslator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,11 @@ public AzureOpenAiTranslator(IAzureOpenAiOptionsProvider azureOpenAiOptionsProvi
var symbolCount = textToTranslate.Length;
var toLanguageCodesArray = toLanguageCodes.ToArray();
var targetLanguagesStr = string.Join(", ", toLanguageCodesArray);

// Check if we should translate one-by-one: using threshold model (GPT-4o) with multiple languages
// When text >= symbolCountThreshold, we use GPT-4o which has limited output tokens, so translate one by one
var isUsingThresholdModel = symbolCountThreshold.HasValue && !string.IsNullOrEmpty(thresholdSetting) && textToTranslate.Length >= symbolCountThreshold;
var shouldTranslateOneByOne = isUsingThresholdModel && toLanguageCodesArray.Length > 1;
var isSubThresholdModel = symbolCountThreshold.HasValue && !string.IsNullOrEmpty(thresholdSetting) && textToTranslate.Length <= symbolCountThreshold;
var shouldTranslateOneByOne = !isSubThresholdModel && toLanguageCodesArray.Length > 1;

if (shouldTranslateOneByOne)
{
Expand Down