| 513 | if (const auto * value = body.find("text")) { |
| 514 | context = value->as_string(); |
| 515 | } |
| 516 | if (!language.empty() || !context.empty()) { |
| 517 | request.text_input = engine::runtime::Transcript{std::move(context), std::move(language)}; |
| 518 | } |
| 519 | return request; |
| 520 | } |
| 521 | |
| 522 | } // namespace |
| 523 | |
| 524 | ServerState::ServerState(ServerConfig config, std::filesystem::path request_base) |
| 525 | : config_(std::move(config)), |
| 526 | request_base_(std::move(request_base)) { |
| 527 | if (config_.backend != engine::core::BackendType::Cuda) { |
| 528 | std::cerr |
| 529 | << "audio.cpp is optimized for CUDA. The " |
| 530 | << backend_name(config_.backend) |
| 531 | << " server backend is intended for portability and testing, but performance and model coverage may be lower than CUDA.\n"; |
| 532 | } |
| 533 | load_models(); |
| 534 | } |
| 535 | |
| 536 | HttpResponse ServerState::handle(const HttpRequest & request) { |
| 537 | if (request.method == "GET" && request.path == "/health") { |
| 538 | return json_response( |
| 539 | "{\"status\":\"ok\",\"backend\":\"" + |
| 540 | std::string(backend_name(config_.backend)) + |
| 541 | "\",\"models\":" + |
| 542 | std::to_string(models_.size()) + |
| 543 | "}"); |
| 544 | } |
| 545 | if (request.method == "GET" && request.path == "/v1/models") { |
| 546 | return json_response(models_json()); |
| 547 | } |
| 548 | if (request.method == "GET" && request.path == "/v1/audio/voices") { |
| 549 | return handle_voices(request); |
| 550 | } |
| 551 | if (request.method == "POST" && request.path == "/v1/audio/speech") { |
| 552 | return handle_speech(request.body); |
| 553 | } |
| 554 | if (request.method == "POST" && request.path == "/v1/audio/transcriptions") { |
| 555 | return handle_transcription(request); |
| 556 | } |
| 557 | if (request.method == "POST" && request.path == "/v1/tasks/run") { |
| 558 | return handle_generic_run(request.body); |
| 559 | } |
| 560 | if (request.method == "POST" && request.path == "/v1/tasks/stream") { |
| 561 | return handle_generic_stream(request.body); |
| 562 | } |
| 563 | return error_response(404, "unknown endpoint: " + request.path, "not_found"); |
| 564 | } |
| 565 | |
| 566 | void ServerState::load_models() { |
| 567 | for (auto & config : config_.models) { |
| 568 | auto loaded = std::make_unique<LoadedModel>(); |
| 569 | loaded->config = std::move(config); |
| 570 | loaded->task = engine::runtime::TaskSpec{ |
| 571 | engine::runtime::parse_voice_task_kind(loaded->config.task), |
| 572 | engine::runtime::parse_run_mode(loaded->config.mode), |
nothing calls this directly
no test coverage detected