diff --git a/BotNet.Services/BotCommands/OpenAI.cs b/BotNet.Services/BotCommands/OpenAI.cs index d07e1d0..f0b0fc1 100644 --- a/BotNet.Services/BotCommands/OpenAI.cs +++ b/BotNet.Services/BotCommands/OpenAI.cs @@ -765,6 +765,7 @@ await botClient.SendTextMessageAsync( } } + private static readonly RateLimiter IMAGE_GENERATION_RATE_LIMITER = RateLimiter.PerUser(1, TimeSpan.FromMinutes(3)); public static async Task StreamChatWithFriendlyBotAsync( ITelegramBotClient botClient, IServiceProvider serviceProvider, @@ -828,6 +829,10 @@ await serviceProvider.GetRequiredService().StreamChatAsync( ); break; case ChatIntent.ImageGeneration: + IMAGE_GENERATION_RATE_LIMITER.ValidateActionRate( + chatId: message.Chat.Id, + userId: message.From.Id + ); Message busyMessage = await botClient.SendTextMessageAsync( chatId: message.Chat.Id, text: "Generating image… ⏳", diff --git a/BotNet.Services/OpenAI/Skills/ImageGenerationBot.cs b/BotNet.Services/OpenAI/Skills/ImageGenerationBot.cs index c4221de..b5f1e08 100644 --- a/BotNet.Services/OpenAI/Skills/ImageGenerationBot.cs +++ b/BotNet.Services/OpenAI/Skills/ImageGenerationBot.cs @@ -7,14 +7,23 @@ public class ImageGenerationBot( OpenAIClient openAIClient ) { private readonly OpenAIClient _openAIClient = openAIClient; + private static readonly SemaphoreSlim SEMAPHORE = new(1, 1); - public Task GenerateImageAsync( + public async Task GenerateImageAsync( string prompt, CancellationToken cancellationToken - ) => _openAIClient.GenerateImageAsync( - model: "dall-e-3", - prompt: prompt, - cancellationToken: cancellationToken - ); + ) { + // dall-e-3 endpoint does not allow concurrent requests + await SEMAPHORE.WaitAsync(cancellationToken); + try { + return await _openAIClient.GenerateImageAsync( + model: "dall-e-3", + prompt: prompt, + cancellationToken: cancellationToken + ); + } finally { + SEMAPHORE.Release(); + } + } } }