using Deal.Contracts.Integrations.Models;
namespace Deal.Contracts.Integrations;
///
/// Порт ИИ-инструментов Discovery и генерации ключевых слов (Ruling 9, план Task 15/18/19).
///
///
/// Порт объявлен в Contracts, потому что контракт потребляет модуль Discovery (воркер/эндпоинты) на этапе 6;
/// реализация — gRPC-адаптер ai-service GrpcAiTools, регистрируемый при Services:Ai:UseLocal=false
/// (Ruling 6). Локальная реализация LocalAiTools (UseLocal=true) методы не поддерживает: Discovery-воркер
/// при aiEnabled=false/сбое сам выбирает эвристику (python discovery_eval L186–194), generate-keywords-эндпоинт
/// (Task 19) отдаёт мягкую ошибку {keywords: [], error}. Методы повторяют прототип 1:1:
/// backend/app/routers/discovery_routes.py L189–211 (generate-keywords) и
/// backend/app/services/discovery_eval.py L50–54/L153–194 (оценка fit). Выключатели aiEnabled/aiFilterEnabled
/// порт не читает — ветки выключателей отрабатывает вызывающий (воркер Discovery, Ruling 10).
///
public interface IAiTools
{
///
/// Генерация поисковых ключевых слов discovery-задачи по описанию ниши (discovery_routes L36–47).
///
///
/// Очистку (_clean_keywords: ≤30, ≤60 символов, дедуп) и мягкую ошибку {keywords: [], error} для UI
/// делает вызывающий (эндпоинт Task 19, Ruling 11); адаптер возвращает сырые ключи модели и ok=false при
/// недоступности сервиса/провайдера (без исключений наружу — мягкая форма Ruling 11).
///
/// Описание ниши/задачи (вызывающий режет до 4000, как discovery_routes L29).
/// Токен отмены.
/// Результат: ok + ключевые слова (пусто — модель не выделила ключей или сервис недоступен) + текст ошибки.
public Task GenerateKeywordsAsync(string description, CancellationToken ct);
///
/// Оценка соответствия сообщения задаче поиска (промпт discovery_eval L50–54; Ruling 5/10).
///
///
/// Вызывающий (воркер Discovery, Task 18) зовёт только при aiEnabled и при сбое/исключении сам падает в
/// эвристику по ключам (python evaluate_message L186–194) — порт ошибки пробрасывает наружу.
///
/// Текст сообщения кандидата (вызывающий режет до 4000).
/// Описание задачи поиска (discovery_eval L51).
/// Ключи задачи (discovery_eval L52).
/// Токен отмены.
/// Решение fit + краткая причина (потолок причины 200, как _AI_REASON_LIMIT L43).
public Task EvaluateFitAsync(
string text,
string description,
IReadOnlyCollection keywords,
CancellationToken ct);
}