using Microsoft.AspNetCore.Mvc; using RMuseum.Models.Ganjoor.SemanticSearch; using RMuseum.Services.Implementation; using RMuseum.Utils.SemanticSearch; using System; using System.Net; using System.Threading.Tasks; namespace RMuseum.Controllers { /// /// Semantic ("find a poem about...") search — deliberately its own controller, not a method /// on GanjoorController, after a production incident: GanjoorController's constructor took /// ISemanticSearchService (indirectly requiring EmbeddingIndex/QueryEmbedder to load /// successfully), so a resource-loading failure prevented the ENTIRE controller from being /// constructed — a 503 on every endpoint under /api/ganjoor, not just this feature. Same /// route prefix as before (api/ganjoor), so the endpoint's URL is unchanged /// (POST /api/ganjoor/search/semantic) — only which controller class hosts it changed. /// A future failure in this feature's own dependencies can now only ever affect this one /// controller/endpoint, never GanjoorController or anything else. /// [Produces("application/json")] [Route("api/ganjoor")] [ApiController] public class SemanticSearchController : ControllerBase { protected readonly ISemanticSearchService _semanticSearchService; public SemanticSearchController(ISemanticSearchService semanticSearchService) { _semanticSearchService = semanticSearchService; } /// /// semantic ("find a poem about...") search /// [HttpPost("search/semantic")] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.ServiceUnavailable, Type = typeof(string))] public async Task SemanticSearch([FromBody] SemanticSearchRequestDto request) { try { var result = await _semanticSearchService.SearchAsync(request); return Ok(result); } catch (SemanticSearchUnavailableException exp) { // distinct from a plain 400/500 - lets a client (or a person reading logs) tell // "this feature isn't loaded/configured right now" apart from a bad query or an // actual crash return StatusCode((int)HttpStatusCode.ServiceUnavailable, exp.Message); } catch (ArgumentException exp) { return BadRequest(exp.Message); } catch (Exception exp) { return BadRequest(exp.ToString()); } } } }