using TarninaHub.Application.Abstractions; using TarninaHub.Application.Dtos; using TarninaHub.Application.Matchmaking; namespace TarninaHub.Infrastructure.Assist; /// /// Idea-creator assistant. Uses the configured LLM when available and falls /// back to deterministic, stage-aware suggestions otherwise. /// public sealed class IdeaAssistant : IIdeaAssistant { private const string SystemPrompt = "Jesteś asystentem kreatora innowacji społecznych w Małopolskim Hubie Innowacji Społecznych. " + "Rozwijasz pomysł mieszkańca: podajesz konkretne, praktyczne podpowiedzi prostym językiem. " + "Nie wymyślaj faktów ani danych liczbowych."; private readonly IIdeaService _ideaService; private readonly ILlmProvider _llmProvider; private readonly ILlmRequestLimiter _llmRequestLimiter; public IdeaAssistant( IIdeaService ideaService, ILlmProvider llmProvider, ILlmRequestLimiter llmRequestLimiter) { _ideaService = ideaService; _llmProvider = llmProvider; _llmRequestLimiter = llmRequestLimiter; } public async Task AssistAsync( string ideaId, IdeaAssistRequest request, CancellationToken cancellationToken) { var idea = await _ideaService.GetAsync(ideaId, cancellationToken); if (idea is null) { return null; } var improvedDescription = idea.Description; var fromLlm = false; if (_llmProvider.IsConfigured && _llmRequestLimiter.TryAcquire()) { var userPrompt = $"Pomysł: {idea.Title}\n" + $"Opis: {idea.Description}\n" + $"Etap: {idea.Card?.Stage ?? "idea"}\n" + $"Odbiorca: {idea.Card?.Audience ?? "nieokreślony"}\n" + $"Fokus: {request.Focus ?? "ogólny"}\n" + "Rozwiń opis pomysłu i dodaj praktyczne wskazówki."; var completion = await _llmProvider.CompleteAsync(SystemPrompt, userPrompt, cancellationToken); if (!string.IsNullOrWhiteSpace(completion)) { improvedDescription = completion.Trim(); fromLlm = true; } } return new IdeaAssistResponse(BuildSuggestions(idea), improvedDescription, fromLlm); } private static IReadOnlyList BuildSuggestions(IdeaResponse idea) { var stage = idea.Card?.Stage ?? "idea"; var suggestions = new List { "Doprecyzuj grupę docelową i jej konkretną potrzebę.", "Określ, jak zmierzysz efekt (wskaźniki, liczba odbiorców).", "Zaplanuj mały pilotaż i wskaż partnerów (NGO/JST/firma).", $"Dopasuj opis do etapu '{stage}' i sprawdź wymagania naboru.", }; if (!string.IsNullOrWhiteSpace(idea.Card?.Audience)) { suggestions.Add($"Rozwiń opis odbiorcy: {idea.Card.Audience}."); } return suggestions; } }