From 854e189e309679107c146fcce9226364a021dbeb Mon Sep 17 00:00:00 2001 From: Oleg Orlov Date: Sat, 1 Nov 2025 23:18:09 +0300 Subject: [PATCH] Add --verbose flag for colored logging - Add termcolor library dependency via FetchContent - Add --verbose/-v flag to whisper-cli to control INFO level messages - Implement log filtering callback that hides INFO messages unless verbose is enabled - Add colored output to log messages (red for errors, yellow for warnings, cyan for info) - Add better error handling for backend buffer allocation failures - INFO messages are now hidden by default, only shown with --verbose flag --- CMakeLists.txt | 10 ++++++++ examples/cli/CMakeLists.txt | 2 +- examples/cli/cli.cpp | 48 +++++++++++++++++++++++++++++++++++++ src/CMakeLists.txt | 1 + src/whisper.cpp | 32 +++++++++++++++++++++---- 5 files changed, 88 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2df1dbaa8e8..7b0bdaec55b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,16 @@ endif() # Add path to modules list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") +# Add termcolor for colored terminal output +include(FetchContent) +FetchContent_Declare( + termcolor + GIT_REPOSITORY https://github.com/ikalnytskyi/termcolor.git + GIT_TAG v2.1.0 + GIT_SHALLOW TRUE +) +FetchContent_MakeAvailable(termcolor) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) diff --git a/examples/cli/CMakeLists.txt b/examples/cli/CMakeLists.txt index 3a73776c5cd..395ea73ff15 100644 --- a/examples/cli/CMakeLists.txt +++ b/examples/cli/CMakeLists.txt @@ -3,6 +3,6 @@ add_executable(${TARGET} cli.cpp) include(DefaultTargetOptions) -target_link_libraries(${TARGET} PRIVATE common whisper ${FFMPEG_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries(${TARGET} PRIVATE common whisper termcolor::termcolor ${FFMPEG_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) install(TARGETS ${TARGET} RUNTIME) diff --git a/examples/cli/cli.cpp b/examples/cli/cli.cpp index 457a1ff35c2..6010f3161db 100644 --- a/examples/cli/cli.cpp +++ b/examples/cli/cli.cpp @@ -5,14 +5,18 @@ #include "grammar-parser.h" #include +#include #include #include +#include #include #include #include #include #include +#include + #if defined(_WIN32) #ifndef NOMINMAX #define NOMINMAX @@ -77,6 +81,7 @@ struct whisper_params { bool use_gpu = true; bool flash_attn = true; bool suppress_nst = false; + bool verbose = false; std::string language = "en"; std::string prompt; @@ -208,6 +213,7 @@ static bool whisper_params_parse(int argc, char ** argv, whisper_params & params else if (arg == "-vmsd" || arg == "--vad-max-speech-duration-s") { params.vad_max_speech_duration_s = std::stof(ARGV_NEXT); } else if (arg == "-vp" || arg == "--vad-speech-pad-ms") { params.vad_speech_pad_ms = std::stoi(ARGV_NEXT); } else if (arg == "-vo" || arg == "--vad-samples-overlap") { params.vad_samples_overlap = std::stof(ARGV_NEXT); } + else if (arg == "-v" || arg == "--verbose") { params.verbose = true; } else { fprintf(stderr, "error: unknown argument: %s\n", arg.c_str()); whisper_print_usage(argc, argv, params); @@ -258,6 +264,7 @@ static void whisper_print_usage(int /*argc*/, char ** argv, const whisper_params fprintf(stderr, " -ojf, --output-json-full [%-7s] include more information in the JSON file\n", params.output_jsn_full ? "true" : "false"); fprintf(stderr, " -of FNAME, --output-file FNAME [%-7s] output file path (without file extension)\n", ""); fprintf(stderr, " -np, --no-prints [%-7s] do not print anything other than the results\n", params.no_prints ? "true" : "false"); + fprintf(stderr, " -v, --verbose [%-7s] enable verbose output (show INFO level messages)\n", params.verbose ? "true" : "false"); fprintf(stderr, " -ps, --print-special [%-7s] print special tokens\n", params.print_special ? "true" : "false"); fprintf(stderr, " -pc, --print-colors [%-7s] print colors\n", params.print_colors ? "true" : "false"); fprintf(stderr, " --print-confidence [%-7s] print confidence\n", params.print_confidence ? "true" : "false"); @@ -910,6 +917,41 @@ static void output_lrc(struct whisper_context * ctx, std::ofstream & fout, const static void cb_log_disable(enum ggml_log_level , const char * , void * ) { } +// Custom log callback that filters INFO messages based on verbose flag +struct log_filter_data { + bool verbose; +}; + +static void cb_log_filter(enum ggml_log_level level, const char * text, void * user_data) { + log_filter_data * data = (log_filter_data *) user_data; + + // Apply colors based on log level (same as whisper.cpp default callback) + switch (level) { + case GGML_LOG_LEVEL_ERROR: + std::cerr << termcolor::red << text << termcolor::reset; + break; + case GGML_LOG_LEVEL_WARN: + std::cerr << termcolor::yellow << text << termcolor::reset; + break; + case GGML_LOG_LEVEL_INFO: + // Show info messages only if verbose is enabled + if (data->verbose) { + std::cerr << termcolor::cyan << text << termcolor::reset; + } + break; + case GGML_LOG_LEVEL_DEBUG: + // Show debug messages only in debug mode + #ifdef WHISPER_DEBUG + std::cerr << text; + #endif + break; + default: + std::cerr << text; + break; + } + std::cerr.flush(); +} + int main(int argc, char ** argv) { ggml_backend_load_all(); @@ -987,8 +1029,14 @@ int main(int argc, char ** argv) { exit(0); } + // Setup logging based on flags + static log_filter_data log_data; + log_data.verbose = params.verbose; + if (params.no_prints) { whisper_log_set(cb_log_disable, NULL); + } else { + whisper_log_set(cb_log_filter, &log_data); } // whisper init diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2eae0c66c78..3ef51d12052 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -126,6 +126,7 @@ if (WHISPER_EXTRA_FLAGS) endif() target_link_libraries(whisper PUBLIC ggml) +target_link_libraries(whisper PRIVATE termcolor::termcolor) if (WHISPER_COREML) target_link_libraries(whisper PRIVATE whisper.coreml) diff --git a/src/whisper.cpp b/src/whisper.cpp index 39c53ba233a..2765451475d 100644 --- a/src/whisper.cpp +++ b/src/whisper.cpp @@ -14,6 +14,8 @@ #include "openvino/whisper-openvino-encoder.h" #endif +#include + #include #include #include @@ -22,11 +24,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -1841,6 +1845,10 @@ static bool whisper_model_load(struct whisper_model_loader * loader, whisper_con size_t size_main = ggml_backend_buffer_get_size(buf); WHISPER_LOG_INFO("%s: %12s total size = %8.2f MB\n", __func__, ggml_backend_buffer_name(buf), size_main / 1e6); + } else { + WHISPER_LOG_ERROR("%s: failed to allocate backend buffer for %s\n", __func__, ggml_backend_buft_name(buft)); + WHISPER_LOG_ERROR("%s: not enough memory available - try using a smaller model or reducing GPU usage\n", __func__); + return false; } } @@ -4970,14 +4978,16 @@ struct whisper_vad_context * whisper_vad_init_with_params( size_t size_main = ggml_backend_buffer_get_size(buf); WHISPER_LOG_INFO("%s: %12s total size = %8.2f MB\n", __func__, ggml_backend_buffer_name(buf), size_main / 1e6); + } else { + WHISPER_LOG_ERROR("%s: failed to allocate backend buffer for %s\n", __func__, ggml_backend_buft_name(buft)); + WHISPER_LOG_ERROR("%s: not enough memory available - try using a smaller model or reducing GPU usage\n", __func__); + return nullptr; } } // load weights { size_t total_size = 0; - model.n_loaded = 0; - std::vector read_buf; while (true) { int32_t n_dims; @@ -8938,13 +8948,27 @@ static void whisper_log_internal(ggml_log_level level, const char * format, ...) } static void whisper_log_callback_default(ggml_log_level level, const char * text, void * user_data) { - (void) level; (void) user_data; #ifndef WHISPER_DEBUG if (level == GGML_LOG_LEVEL_DEBUG) { return; } #endif - fputs(text, stderr); + + // Apply colors based on log level + switch (level) { + case GGML_LOG_LEVEL_ERROR: + std::cerr << termcolor::red << text << termcolor::reset; + break; + case GGML_LOG_LEVEL_WARN: + std::cerr << termcolor::yellow << text << termcolor::reset; + break; + case GGML_LOG_LEVEL_INFO: + std::cerr << termcolor::cyan << text << termcolor::reset; + break; + default: + fputs(text, stderr); + break; + } fflush(stderr); }