using System; using System.IO; using System.Security.Claims; using System.Threading.Tasks; using D3ROVoice.Api.Data; using D3ROVoice.Api.Dtos; using D3ROVoice.Api.Services; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; namespace D3ROVoice.Api.Controllers; [ApiController] [Route("api/[controller]")] public class SttController : ControllerBase { private readonly ISttProxyService _sttService; public SttController(ISttProxyService sttService) { _sttService = sttService; } [HttpPost("transcribe")] [Consumes("application/json", "multipart/form-data")] public async Task Transcribe() { var userIdStr = User.FindFirstValue(ClaimTypes.NameIdentifier); var userEmail = User.FindFirstValue(ClaimTypes.Email) ?? "user@d3ro.voice"; int userId = int.TryParse(userIdStr, out var id) ? id : 1; if (Request.HasFormContentType) { var form = await Request.ReadFormAsync(); var file = form.Files.GetFile("file") ?? form.Files.GetFile("audio"); if (file == null || file.Length == 0) { return BadRequest(new { message = "전송할 오디오 파일(file 또는 audio)이 필요합니다." }); } using var memoryStream = new MemoryStream(); await file.CopyToAsync(memoryStream); var audioBytes = memoryStream.ToArray(); var language = form["language"].ToString(); var prompt = form["prompt"].ToString(); var model = form["model"].ToString(); var provider = form["provider"].ToString(); var request = new SttTranscribeRequest( AudioBase64: null, Language: string.IsNullOrWhiteSpace(language) ? "ko" : language, InitialPrompt: string.IsNullOrWhiteSpace(prompt) ? null : prompt, ModelId: string.IsNullOrWhiteSpace(model) ? null : model, Provider: string.IsNullOrWhiteSpace(provider) ? null : provider ); var result = await _sttService.TranscribeAsync( userId, userEmail, request, audioBytes, file.ContentType ?? "audio/webm", file.FileName ?? "recording.webm" ); return Ok(result); } else { // Read JSON body using var reader = new StreamReader(Request.Body); var json = await reader.ReadToEndAsync(); if (string.IsNullOrWhiteSpace(json)) { return BadRequest(new { message = "요청 본문이 비어있습니다." }); } var request = System.Text.Json.JsonSerializer.Deserialize( json, new System.Text.Json.JsonSerializerOptions { PropertyNameCaseInsensitive = true } ); if (request == null || string.IsNullOrWhiteSpace(request.AudioBase64)) { return BadRequest(new { message = "AudioBase64 데이터가 필요합니다." }); } var result = await _sttService.TranscribeAsync(userId, userEmail, request); return Ok(result); } } [HttpGet("providers")] public async Task GetActiveProviders() { var endpoints = await _sttService.GetAllEndpointsAsync(); return Ok(endpoints); } [HttpPost("test")] public async Task TestConnection([FromQuery] int endpointId = 0) { var result = await _sttService.TestEndpointAsync(endpointId); return Ok(result); } }