| 658 | if (words_out.has_value()) { |
| 659 | write_words_result(result, *words_out, id); |
| 660 | } |
| 661 | record_result_paths(id, result, audio_out, text_out, words_out, step_dir, context); |
| 662 | |
| 663 | std::cout << "workflow_step=" << id << "\n"; |
| 664 | } |
| 665 | |
| 666 | std::vector<engine::runtime::WordTimestamp> read_word_timestamps_json(const std::filesystem::path & path) { |
| 667 | const auto root = engine::io::json::parse_file(path); |
| 668 | if (!root.is_array()) { |
| 669 | throw std::runtime_error("word timestamp input must be a JSON array: " + path.string()); |
| 670 | } |
| 671 | std::vector<engine::runtime::WordTimestamp> words; |
| 672 | for (const auto & item : root.as_array()) { |
| 673 | engine::runtime::WordTimestamp word; |
| 674 | word.span.start_sample = engine::io::json::require_i64(item, "start_sample"); |
| 675 | word.span.end_sample = engine::io::json::require_i64(item, "end_sample"); |
| 676 | word.word = engine::io::json::require_string(item, "word"); |
| 677 | const auto * confidence = item.find("confidence"); |
| 678 | if (confidence != nullptr && !confidence->is_null()) { |
| 679 | word.confidence = confidence->as_f32(); |
| 680 | } |
| 681 | words.push_back(std::move(word)); |
no test coverage detected