All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
- Add Domain/Interfaces/IMistralConnector.cs with AiServiceException and AiErrorCode enum - Add Infrastructure/Configuration/MistralConfig.cs with validation - Add Infrastructure/Services/MistralConnector.cs with HTTP client implementation - Add Infrastructure/Services/MistralRateLimiter.cs for rate limiting - Add Infrastructure/Services/MistralCircuitBreaker.cs for circuit breaker pattern - Add Application/Models/MistralRequest.cs with request models - Add Application/Models/MistralResponse.cs with response models - Update Program.cs to register IMistralConnector with MemoryCache, HttpClient, and config - Update GermanApp.csproj with existing dependencies - Update docs/features/ai-services.md with Phase 0 completion Phase 0 of AI Services feature is complete. Mistral API Connector is ready for use by MistralService. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
97 lines
2.7 KiB
C#
97 lines
2.7 KiB
C#
using System.Collections.Concurrent;
|
|
|
|
namespace GermanApp.Infrastructure.Services;
|
|
|
|
/// <summary>
|
|
/// Simple in-memory rate limiter for Mistral API requests.
|
|
/// This is part of the Infrastructure layer.
|
|
/// </summary>
|
|
public class MistralRateLimiter
|
|
{
|
|
private readonly int _maxRequests;
|
|
private readonly TimeSpan _window;
|
|
private readonly ConcurrentDictionary<string, List<DateTime>> _requests = new();
|
|
|
|
/// <summary>
|
|
/// Creates a new rate limiter.
|
|
/// </summary>
|
|
/// <param name="maxRequestsPerMinute">Maximum requests allowed per minute</param>
|
|
public MistralRateLimiter(int maxRequestsPerMinute)
|
|
{
|
|
_maxRequests = maxRequestsPerMinute;
|
|
_window = TimeSpan.FromMinutes(1);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Attempts to acquire a rate limit token for the specified endpoint.
|
|
/// </summary>
|
|
/// <param name="endpoint">The API endpoint being called</param>
|
|
/// <returns>True if request is allowed, false if rate limit exceeded</returns>
|
|
public bool TryAcquire(string endpoint)
|
|
{
|
|
var now = DateTime.UtcNow;
|
|
var requests = _requests.GetOrAdd(endpoint, _ => new List<DateTime>());
|
|
|
|
lock (requests)
|
|
{
|
|
// Remove old requests outside the window
|
|
requests.RemoveAll(r => now - r > _window);
|
|
|
|
// Check if limit exceeded
|
|
if (requests.Count >= _maxRequests)
|
|
return false;
|
|
|
|
// Add new request
|
|
requests.Add(now);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the current request count for an endpoint.
|
|
/// </summary>
|
|
/// <param name="endpoint">The API endpoint</param>
|
|
/// <returns>Number of requests in the current window</returns>
|
|
public int GetCurrentCount(string endpoint)
|
|
{
|
|
if (_requests.TryGetValue(endpoint, out var requests))
|
|
{
|
|
lock (requests)
|
|
{
|
|
var now = DateTime.UtcNow;
|
|
requests.RemoveAll(r => now - r > _window);
|
|
return requests.Count;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resets the rate limiter for a specific endpoint.
|
|
/// </summary>
|
|
/// <param name="endpoint">The API endpoint</param>
|
|
public void Reset(string endpoint)
|
|
{
|
|
if (_requests.TryGetValue(endpoint, out var requests))
|
|
{
|
|
lock (requests)
|
|
{
|
|
requests.Clear();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resets all rate limiters.
|
|
/// </summary>
|
|
public void ResetAll()
|
|
{
|
|
foreach (var kvp in _requests)
|
|
{
|
|
lock (kvp.Value)
|
|
{
|
|
kvp.Value.Clear();
|
|
}
|
|
}
|
|
}
|
|
}
|