| 135 | } |
| 136 | |
| 137 | inline io::json::Value speaker_turns_json(const std::vector<runtime::SpeakerTurn> & turns) { |
| 138 | io::json::Value::Array out; |
| 139 | out.reserve(turns.size()); |
| 140 | for (const auto & turn : turns) { |
| 141 | out.push_back(io::json::Value::make_object({ |
| 142 | {"start_sample", number(static_cast<double>(turn.span.start_sample))}, |
| 143 | {"end_sample", number(static_cast<double>(turn.span.end_sample))}, |
| 144 | {"speaker_id", string(turn.speaker_id)}, |
| 145 | {"confidence", number(turn.confidence)}, |
| 146 | })); |
| 147 | } |
| 148 | return io::json::Value::make_array(std::move(out)); |
| 149 | } |
| 150 | |
| 151 | inline io::json::Value result_step_json( |
| 152 | const AudioTaskBenchConfig & config, |
| 153 | const runtime::TaskResult & result, |
| 154 | int request_index, |
| 155 | const std::filesystem::path & audio_path, |
| 156 | double wall_ms) { |
| 157 | io::json::Value::Object step{ |
| 158 | {"request_index", number(request_index)}, |
| 159 | {"audio", string(audio_path.string())}, |
| 160 | {"metrics", io::json::Value::make_object({{"wall_ms", number(wall_ms)}})}, |
| 161 | }; |
| 162 | switch (config.output_kind) { |
| 163 | case AudioTaskOutputKind::Asr: |
| 164 | step.emplace( |
| 165 | "text_output", |
| 166 | string(result.text_output.has_value() ? result.text_output->text : "")); |
| 167 | step.emplace("word_timestamps", word_timestamps_json(result.word_timestamps)); |
| 168 | break; |
| 169 | case AudioTaskOutputKind::Vad: |
| 170 | step.emplace("speech_segments", speech_segments_json(result.speech_segments)); |
| 171 | break; |
| 172 | case AudioTaskOutputKind::Speaker: |
| 173 | { |
| 174 | const runtime::VoiceArtifact * speaker_artifact = nullptr; |
| 175 | for (const auto & artifact : result.output_artifacts) { |
| 176 | if (artifact.kind == runtime::ArtifactKind::SpeakerEmbedding || artifact.kind == runtime::ArtifactKind::Custom) { |
| 177 | speaker_artifact = &artifact; |
| 178 | break; |
| 179 | } |
| 180 | } |
| 181 | const auto & meta = speaker_artifact != nullptr ? speaker_artifact->meta : std::unordered_map<std::string, std::string>{}; |
| 182 | const auto label = meta.find("label"); |
| 183 | const auto index = meta.find("index"); |
| 184 | const auto score = meta.find("score"); |
| 185 | step.emplace("label", string(label != meta.end() ? label->second : "")); |
no test coverage detected