Files
intendant/Intendant/Intendant.Web/Services/OpenAiSettingsService.cs
T
2026-10-06 01:27:51 +02:00

92 lines
2.9 KiB
C#

using System.Text.Json;
using Intendant.Shared.Services;
namespace Intendant.Web.Services;
public sealed class OpenAiSettingsService : IOpenAiSettingsService
{
private readonly SemaphoreSlim _lock = new(1, 1);
private readonly OpenAiResponsesOptions _defaults;
private readonly string _filePath;
private OpenAiResponsesOptions? _cache;
public OpenAiSettingsService(IConfiguration configuration, IWebHostEnvironment environment)
{
_defaults = configuration.GetSection(OpenAiResponsesOptions.SectionName).Get<OpenAiResponsesOptions>() ?? new OpenAiResponsesOptions();
string directoryPath = Path.Combine(environment.ContentRootPath, "App_Data");
_filePath = Path.Combine(directoryPath, "openai-settings.json");
}
public async Task<OpenAiResponsesOptions> GetAsync(CancellationToken cancellationToken = default)
{
await _lock.WaitAsync(cancellationToken);
try
{
if (_cache is not null)
{
return Clone(_cache);
}
if (!File.Exists(_filePath))
{
_cache = Clone(_defaults);
return Clone(_cache);
}
await using FileStream stream = File.OpenRead(_filePath);
OpenAiResponsesOptions? stored = await JsonSerializer.DeserializeAsync<OpenAiResponsesOptions>(stream, cancellationToken: cancellationToken);
_cache = Normalize(stored ?? new OpenAiResponsesOptions());
return Clone(_cache);
}
finally
{
_lock.Release();
}
}
public async Task SaveAsync(OpenAiResponsesOptions options, CancellationToken cancellationToken = default)
{
OpenAiResponsesOptions normalized = Normalize(options);
await _lock.WaitAsync(cancellationToken);
try
{
string? directory = Path.GetDirectoryName(_filePath);
if (!string.IsNullOrWhiteSpace(directory))
{
Directory.CreateDirectory(directory);
}
await using FileStream stream = File.Create(_filePath);
await JsonSerializer.SerializeAsync(stream, normalized, cancellationToken: cancellationToken);
_cache = Clone(normalized);
}
finally
{
_lock.Release();
}
}
private OpenAiResponsesOptions Normalize(OpenAiResponsesOptions options)
{
return new OpenAiResponsesOptions
{
ApiKey = options.ApiKey?.Trim() ?? string.Empty,
Endpoint = options.Endpoint?.Trim() ?? string.Empty,
Model = string.IsNullOrWhiteSpace(options.Model) ? _defaults.Model : options.Model.Trim(),
};
}
private static OpenAiResponsesOptions Clone(OpenAiResponsesOptions source)
{
return new OpenAiResponsesOptions
{
ApiKey = source.ApiKey,
Endpoint = source.Endpoint,
Model = source.Model,
};
}
}