using Deal.Contracts.Integrations; using Deal.Contracts.Integrations.Models; using Deal.Infrastructure.Integrations.Abstractions; using Deal.Infrastructure.Integrations.Exceptions; using Deal.Infrastructure.Integrations.Extensions; using Deal.Infrastructure.Integrations.Models; using Deal.Infrastructure.Integrations.Options; namespace Deal.Infrastructure.Integrations.Services; /// /// Локальная реализация без внешнего ИИ-сервиса (Ruling 9, план Task 15). /// /// /// Регистрируется при Services:Ai:UseLocal=true (default, Ruling 6). Методы НЕ поддерживаются — на /// этапе 6 локальной генерации ключей/оценки fit нет: Discovery-воркер сам выбирает эвристику (при /// aiEnabled=false или сбое, python discovery_eval L186–194), а generate-keywords-эндпоинт (Task 19) ловит /// исключение и отдаёт мягкую ошибку {keywords: [], error} (Ruling 11). NotSupportedException — явный сигнал /// «вызов порта в локальном режиме — ошибка сценария», чтобы будущий потребитель (Discovery) не получил /// молча пустые ключи/ложный fit. Scoped-зависимостей нет (экземпляр лёгкий, как LocalAiClassifier на дефолты). /// public sealed class LocalAiTools : IAiTools { // Сообщение исключения методов (локальный режим = ai-service не подключён). private const string NotSupportedMessage = "ИИ-инструменты доступны только при подключённом ai-service (Services:Ai:UseLocal=false)."; /// public Task GenerateKeywordsAsync(string description, CancellationToken ct) => throw new NotSupportedException(NotSupportedMessage); /// public Task EvaluateFitAsync( string text, string description, IReadOnlyCollection keywords, CancellationToken ct) => throw new NotSupportedException(NotSupportedMessage); }