Repository: ggerganov/whisper.cpp
File: src/whisper.cpp (C++)

Code before:

                    const int max_ctx_half = std::min(params.n_max_text_ctx, whisper_n_text_ctx(ctx) / 2);
                    if (max_ctx_half > 0 && (can_take0 || can_take1)) {
                        // Always start with previous token marker to connect continuity
                        prompt.push_back(whisper_token_prev(ctx));

                        // Take static tokens (initial prompt) first, up to budget minus the prev token
                        int n_take0 = 0;
                        if (can_take0) {
                            n_take0 = std::min<int>(max_ctx_half - 1, prompt_past0.size());
                            prompt.insert(prompt.end(), prompt_past0.end() - n_take0, prompt_past0.end());
                        }

                        // Fill remaining budget with dynamic tokens (rolling context)
                        const int n_take1 = std::min<int>(max_ctx_half - n_take0 - 1, prompt_past1.size());
                        prompt.insert(prompt.end(), prompt_past1.end() - n_take1, prompt_past1.end());
                    }
                }

                // init new transcription with sot, language (opt) and task tokens
                prompt.insert(prompt.end(), prompt_init.begin(), prompt_init.end());

                // print the prompt
                WHISPER_LOG_DEBUG("\n\n");
                for (int i = 0; i < (int) prompt.size(); i++) {
                    WHISPER_LOG_DEBUG("%s: prompt[%d] = %s\n", __func__, i, ctx->vocab.id_to_token.at(prompt[i]).c_str());
                }
                WHISPER_LOG_DEBUG("\n\n");

                // recreate the KV cache if the number of decoders has changed
                if (state->kv_self_n_dec < n_decoders_cur) {
                    WHISPER_LOG_DEBUG("%s: recreating KV cache: n_decoders_cur = %d\n", __func__, n_decoders_cur);

                    whisper_kv_cache_free(state->kv_self);

                    // overallocate to workaround KV cache fragmentation issues
                    const int factor = n_decoders_cur > 1 ? n_decoders_cur + 2 : 1;

                    if (!whisper_kv_cache_init(state->kv_self, state->backends[0], ctx->itype,
                                ctx->model.hparams.n_text_state,
                                ctx->model.hparams.n_text_layer,
                                GGML_PAD(ctx->model.hparams.n_text_ctx, 256)*factor)) {
                        WHISPER_LOG_ERROR("%s: whisper_kv_cache_init() failed for self-attention cache\n", __func__);
                        whisper_free_state(state);
                        return -7;
                    }

                    state->kv_self_n_dec = n_decoders_cur;
                }

                whisper_kv_cache_clear(state->kv_self);

Review comment (suggestion):
When `params.n_max_text_ctx == 0`, the `n_take1` will become `-1`. Probably we have to clamp it to `0` to avoid iterating past the end of the vector. Same for `n_take0`.

Edit: nvm - we have a check for `params.n_max_text_ctx > 0` earlier.

Code after:
                }
            }

            // init prompt and kv cache for the current iteration
            // TODO: do not recompute the prompt if it is the same as previous time
            {
                prompt.clear();

                if (params.n_max_text_ctx > 0 && t_cur < WHISPER_HISTORY_CONDITIONING_TEMP_CUTOFF) {
                    const bool can_take0 = params.carry_initial_prompt && !prompt_past0.empty();
                    const bool can_take1 = !prompt_past1.empty();

                    if (max_prompt_ctx > 0 && (can_take0 || can_take1)) {
                        // Always start with previous token marker to connect continuity
                        prompt.push_back(whisper_token_prev(ctx));

                        // Take static tokens (initial prompt) first
                        int n_take0 = 0;
                        if (can_take0) {
                            n_take0 = prompt_past0.size();
                            prompt.insert(prompt.end(), prompt_past0.end() - n_take0, prompt_past0.end());
                        }

                        // Fill remaining budget with dynamic tokens (rolling context)
                        const int n_take1 = std::min<int>(max_prompt_ctx - n_take0 - 1, prompt_past1.size());
                        prompt.insert(prompt.end(), prompt_past1.end() - n_take1, prompt_past1.end());
                    }
                }

                // init new transcription with sot, language (opt) and task tokens
                prompt.insert(prompt.end(), prompt_init.begin(), prompt_init.end());

                // print the prompt
                WHISPER_LOG_DEBUG("\n\n");
                for (int i = 0; i < (int) prompt.size(); i++) {
                    WHISPER_LOG_DEBUG("%s: prompt[%d] = %s\n", __func__, i, ctx->vocab.id_to_token.at(prompt[i]).c_str());
                }
                WHISPER_LOG_DEBUG("\n\n");

                // recreate the KV cache if the number of decoders has changed
                if (state->kv_self_n_dec < n_decoders_cur) {
                    WHISPER_LOG_DEBUG("%s: recreating KV cache: n_decoders_cur = %d\n", __func__, n_decoders_cur);

                    whisper_kv_cache_free(state->kv_self);

                    // overallocate to workaround KV cache fragmentation issues
                    const int factor = n_decoders_cur > 1 ? n_decoders_cur + 2 : 1;

                    if (!whisper_kv_cache_init(state->kv_self, state->backends[0], ctx->itype,
                                ctx->model.hparams.n_text_state,
                                ctx->model.hparams.n_text_layer,