88 lines
2.8 KiB
C#
88 lines
2.8 KiB
C#
using MarketAlly.GitCommitEditor.Models;
|
|
using MarketAlly.GitCommitEditor.Options;
|
|
using MarketAlly.GitCommitEditor.Resources;
|
|
using MarketAlly.GitCommitEditor.Services;
|
|
|
|
namespace MarketAlly.GitCommitEditor.Rewriters;
|
|
|
|
/// <summary>
|
|
/// Exception thrown when AI features are used without an API key configured.
|
|
/// </summary>
|
|
public class ApiKeyNotConfiguredException : InvalidOperationException
|
|
{
|
|
public ApiKeyNotConfiguredException()
|
|
: base(Str.Service_ApiKeyNotConfigured)
|
|
{
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Dynamic commit rewriter that uses AI when configured, or throws if not.
|
|
/// </summary>
|
|
public sealed class DynamicCommitRewriter : ICommitMessageRewriter, IDisposable
|
|
{
|
|
private readonly AiOptions _options;
|
|
private readonly ICostTrackingService? _costTracker;
|
|
private AICommitRewriter? _aiRewriter;
|
|
private string? _lastApiKey;
|
|
private string? _lastProvider;
|
|
private string? _lastModel;
|
|
|
|
public DynamicCommitRewriter(AiOptions options, ICostTrackingService? costTracker = null)
|
|
{
|
|
_options = options ?? throw new ArgumentNullException(nameof(options));
|
|
_costTracker = costTracker;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns true if an API key is configured and AI features are available.
|
|
/// </summary>
|
|
public bool IsConfigured => !string.IsNullOrEmpty(_options.ApiKey);
|
|
|
|
private AICommitRewriter GetRewriter()
|
|
{
|
|
// If no API key, throw exception
|
|
if (string.IsNullOrEmpty(_options.ApiKey))
|
|
{
|
|
throw new ApiKeyNotConfiguredException();
|
|
}
|
|
|
|
// Check if we need to create/recreate the AI rewriter
|
|
// (API key, provider, or model changed)
|
|
if (_aiRewriter == null ||
|
|
_lastApiKey != _options.ApiKey ||
|
|
_lastProvider != _options.Provider ||
|
|
_lastModel != _options.Model)
|
|
{
|
|
// Dispose old rewriter if exists
|
|
_aiRewriter?.Dispose();
|
|
|
|
// Create new rewriter with current settings
|
|
_aiRewriter = new AICommitRewriter(_options, _costTracker);
|
|
_lastApiKey = _options.ApiKey;
|
|
_lastProvider = _options.Provider;
|
|
_lastModel = _options.Model;
|
|
}
|
|
|
|
return _aiRewriter;
|
|
}
|
|
|
|
public Task<SuggestionResult> SuggestImprovedMessageAsync(CommitAnalysis analysis, CancellationToken ct = default)
|
|
{
|
|
return GetRewriter().SuggestImprovedMessageAsync(analysis, ct);
|
|
}
|
|
|
|
public Task<IReadOnlyList<(CommitAnalysis Analysis, SuggestionResult Result)>> SuggestBatchAsync(
|
|
IEnumerable<CommitAnalysis> analyses,
|
|
IProgress<int>? progress = null,
|
|
CancellationToken ct = default)
|
|
{
|
|
return GetRewriter().SuggestBatchAsync(analyses, progress, ct);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_aiRewriter?.Dispose();
|
|
}
|
|
}
|