Wiring up the AI calls.

This commit is contained in:
Burak Kaan Köse
2026-03-25 00:25:05 +01:00
parent fd81ee31ce
commit 7aad6b0157
6 changed files with 208 additions and 0 deletions
@@ -254,6 +254,15 @@ public sealed class WinoAccountProfileService : BaseDatabaseService, IWinoAccoun
return response;
}
public async Task<ApiEnvelope<AiTextResultDto>> SummarizeAsync(string html, CancellationToken cancellationToken = default)
=> await ExecuteAiOperationAsync(account => _apiClient.SummarizeAsync(html, cancellationToken), "summarize", cancellationToken).ConfigureAwait(false);
public async Task<ApiEnvelope<AiTextResultDto>> TranslateAsync(string html, string targetLanguage, CancellationToken cancellationToken = default)
=> await ExecuteAiOperationAsync(account => _apiClient.TranslateAsync(html, targetLanguage, cancellationToken), "translate", cancellationToken).ConfigureAwait(false);
public async Task<ApiEnvelope<AiTextResultDto>> RewriteAsync(string html, string mode, CancellationToken cancellationToken = default)
=> await ExecuteAiOperationAsync(account => _apiClient.RewriteAsync(html, mode, cancellationToken), "rewrite", cancellationToken).ConfigureAwait(false);
public async Task<ApiEnvelope<CheckoutSessionResultDto>> CreateCheckoutSessionAsync(WinoAddOnProductType productId, CancellationToken cancellationToken = default)
{
var account = await GetAuthenticatedAccountAsync(cancellationToken).ConfigureAwait(false);
@@ -409,6 +418,30 @@ public sealed class WinoAccountProfileService : BaseDatabaseService, IWinoAccoun
return response.IsSuccess && response.Result?.HasAiPack == true;
}
private async Task<ApiEnvelope<AiTextResultDto>> ExecuteAiOperationAsync(Func<WinoAccount, Task<ApiEnvelope<AiTextResultDto>>> executeAsync,
string operationName,
CancellationToken cancellationToken)
{
var account = await GetAuthenticatedAccountAsync(cancellationToken).ConfigureAwait(false);
if (account == null)
{
return ApiEnvelope<AiTextResultDto>.Failure("MissingAccessToken");
}
var response = await executeAsync(account).ConfigureAwait(false);
if (!response.IsSuccess)
{
_logger.Warning("Failed to {Operation} HTML with AI for Wino account {Email}. Error code: {ErrorCode}", operationName, account.Email, response.ErrorCode);
}
if (response.Quota != null)
{
await PersistAddOnCacheAsync(account.Id, Map(response.Quota)).ConfigureAwait(false);
}
return response;
}
private async Task<bool> HasUnlimitedAccountsAsync(CancellationToken cancellationToken)
{
var cachedSnapshot = await GetCachedAddOnSnapshotAsync().ConfigureAwait(false);
@@ -478,6 +511,17 @@ public sealed class WinoAccountProfileService : BaseDatabaseService, IWinoAccoun
cache.HasUnlimitedAccounts,
new DateTimeOffset(DateTime.SpecifyKind(cache.LastUpdatedUtc, DateTimeKind.Utc)));
private static AiStatusResultDto Map(QuotaInfoDto quota)
=> new(
quota.HasAiPack,
quota.EntitlementStatus,
quota.CurrentPeriodStartUtc,
quota.CurrentPeriodEndUtc,
quota.MonthlyLimit,
quota.Used,
quota.Remaining,
quota.Product);
private static bool AreEquivalentProfiles(WinoAccount left, WinoAccount right)
=> left.Id == right.Id &&
string.Equals(left.Email, right.Email, StringComparison.Ordinal) &&