0

I'm trying to create a whisper-rs server using Axum. In this server I'd like to only have to create the whisper state once at server startup. Hence, I created an AppState struct that could then be passed around using an Arc<Mutex<AppState>>.

However, I seem to be having issues with ownership (classic) when implementing ::new for this struct, and I have the idea that it may have to do with the underlying implementation of WhisperContext and WhisperState, since they using raw pointers underneath, and a lifetime specifier for a PhantomData<&'a WhisperContext> as a field for WhisperState.

My implementation is as follows:

// src/state.rs
use log::info;
use whisper_rs::{WhisperContext, WhisperState};

/// Application state
///
/// This struct holds the whisper context and state necessary for transcribing
///
/// # Fields
/// * `whisper_ctx` - The whisper context
/// * `whisper_state` - The whisper state
pub struct AppState<'ctx> {
    pub whisper_ctx: WhisperContext,
    pub whisper_state: WhisperState<'ctx>
}

impl<'ctx> AppState<'ctx> {
    /// Create a new AppState struct
    ///
    /// # Arguments
    /// * `model_path` - The path to the model file, e.g. "models/ggml-medium.bin"
    ///
    /// # Returns
    /// * `AppState` - The AppState struct
    ///
    /// # Example
    /// ```
    /// let model_path = "models/ggml-medium.bin";
    /// let app_state = AppState::new(model_path);
    /// ```
    fn new(model_path: &'_ str) -> Self {
        info!("Loading model from {}", model_path);
        // Strip the file name from the path
        let model_name = model_path.split('/').last().unwrap().to_string();
        info!("Model name: {}", model_name);

        // load a context and model
        let whisper_ctx = WhisperContext::new(model_path).expect("failed to load model");
        let whisper_state = whisper_ctx.create_state().expect("failed to create state");

        // Create AppState struct with owned data
        Self {
            whisper_ctx,
            whisper_state
        }
    }
}

A summarized view of the whisper-rs specific abstractions that I use. You can find more at https://github.com/tazz4843/whisper-rs.

// whisper_rs/lib.rs
#[derive(Debug)]
pub struct WhisperContext {
    ctx: *mut whisper_rs_sys::whisper_context,
}

#[derive(Debug)]
pub struct WhisperState<'a> {
    ctx: *mut whisper_rs_sys::whisper_context,
    ptr: *mut whisper_rs_sys::whisper_state,
    _phantom: PhantomData<&'a WhisperContext>,
}

This yields the following compilation error:

|
38 |           let whisper_state = whisper_ctx.create_state().expect("failed to create state");
|                               -------------------------- `whisper_ctx` is borrowed here
...
41 | /         Self {
42 | |             whisper_ctx,
43 | |             whisper_state
44 | |         }
| |\________\_^ returns a value referencing data owned by the current function

Perhaps this has got to do with my understanding of Rust, in which case please tell me so.

Otherwise I'm curious to hear your thoughts, any help is greatly appreciated. I've unfortunately been stuck for some time.

So far I've tried most things that conventional googling and/or ChatGPT would suggest such as wrapping the struct's field types in Arc, but to no avail.

0 Answers0