diff --git a/crates/whisper_cpp/src/lib.rs b/crates/whisper_cpp/src/lib.rs
index 55b542d..2749b1d 100644
--- a/crates/whisper_cpp/src/lib.rs
+++ b/crates/whisper_cpp/src/lib.rs
@@ -18,7 +18,7 @@ use whisper_cpp_sys::{
whisper_full_params__bindgen_ty_2, whisper_full_with_state,
whisper_init_from_file_with_params_no_state, whisper_init_state, whisper_log_set,
whisper_sampling_strategy_WHISPER_SAMPLING_BEAM_SEARCH,
- whisper_sampling_strategy_WHISPER_SAMPLING_GREEDY, whisper_state, whisper_token,
+ whisper_sampling_strategy_WHISPER_SAMPLING_GREEDY, whisper_state,
};
/// Boolean indicating if a logger has already been set using [`whisper_log_set`].
@@ -64,15 +64,19 @@ pub struct WhisperModel {
}
impl WhisperModel {
- /// Loads a new *ggml* *whisper* model, given its file path.
+ /// Loads a new *ggml* *whisper* model, given its file path. If a device (GPU) index is
+ /// provided, the model is loaded into the GPU.
#[doc(alias = "whisper_init_from_file_with_params_no_state")]
- pub fn new_from_file
(model_path: P, use_gpu: bool) -> Result
+ pub fn new_from_file(model_path: P, device: Option) -> Result
where
P: AsRef,
{
set_log();
- let params = whisper_context_params { use_gpu };
+ let params = whisper_context_params {
+ use_gpu: device.is_some(),
+ gpu_device: device.unwrap_or(0) as i32,
+ };
let path_bytes = model_path
.as_ref()
@@ -152,7 +156,6 @@ pub enum WhisperSessionError {
pub struct WhisperSession {
context: Arc>,
state: WhisperState,
- prompt: Vec,
}
impl WhisperSession {
@@ -171,7 +174,6 @@ impl WhisperSession {
Ok(Self {
context,
state: WhisperState(state),
- prompt: vec![],
})
}
@@ -237,13 +239,11 @@ impl WhisperSession {
/// Run the entire model: PCM -> log mel spectrogram -> encoder -> decoder -> text.
/// Uses the specified decoding strategy to obtain the text.
#[doc(alias = "whisper_full_with_state")]
- pub async fn full(
+ pub async fn advance(
&mut self,
- mut params: WhisperParams,
+ params: WhisperParams,
samples: &[f32],
) -> Result<(), WhisperSessionError> {
- // TODO use no_context from whisper_params instead
- params.prompt_tokens = self.prompt.clone();
let locked = self.context.read().await;
let res = unsafe {
let (_vec, c_params) = params.c_params()?;
@@ -260,15 +260,6 @@ impl WhisperSession {
return Err(WhisperSessionError::Internal);
}
- let segments = self.segment_count();
-
- for s in 0..segments {
- let tokens = self.token_count(s);
- for t in 0..tokens {
- self.prompt.push(self.token_id(s, t));
- }
- }
-
Ok(())
}
@@ -305,6 +296,11 @@ impl WhisperSession {
pub fn segment_text(&self, segment: u32) -> Result {
let text = unsafe {
let res = whisper_full_get_segment_text_from_state(self.state.0, segment as c_int);
+
+ if res.is_null() {
+ return Err(WhisperSessionError::Internal);
+ }
+
CStr::from_ptr(res.cast_mut())
};
@@ -345,6 +341,17 @@ impl WhisperSession {
pub fn token_probability(&self) {
todo!()
}
+
+ /// Returns the decoded text of the last segment encoding.
+ pub fn new_context(&self) -> Result {
+ let mut res = "".to_string();
+
+ for i in 0..self.segment_count() {
+ res += &*self.segment_text(i)?;
+ }
+
+ Ok(res)
+ }
}
#[derive(Debug, Error)]
@@ -402,7 +409,7 @@ pub struct WhisperParams {
translate: bool,
/// Do not use past transcription (if any) as initial prompt for the decoder.
- no_context: bool,
+ pub no_context: bool,
/// Do not generate timestamps.
no_timestamps: bool,
diff --git a/crates/whisper_cpp_sys/build.rs b/crates/whisper_cpp_sys/build.rs
index 0232c9d..e70c8a1 100644
--- a/crates/whisper_cpp_sys/build.rs
+++ b/crates/whisper_cpp_sys/build.rs
@@ -1,5 +1,5 @@
-use std::path::PathBuf;
use std::{env, fs};
+use std::path::PathBuf;
// TODO add feature compatibility checks
@@ -15,7 +15,7 @@ fn main() {
let mut config = cmake::Config::new(submodule_dir);
config
- .define("BUILD_SHARED_LIBS", "OFF")
+ .define("BUILD_SHARED_LIBS", "ON")
.define("WHISPER_BUILD_EXAMPLES", "OFF")
.define("WHISPER_BUILD_TESTS", "OFF")
.define("WHISPER_NO_ACCELERATE", "ON") // TODO accelerate is used by default, but is causing issues atm, check why
@@ -23,35 +23,42 @@ fn main() {
#[cfg(not(feature = "avx"))]
{
- config.define("WHISPER_NO_AVX", "ON")
+ config.define("WHISPER_NO_AVX", "ON");
}
#[cfg(not(feature = "avx2"))]
{
- config.define("WHISPER_NO_AVX2", "ON")
+ config.define("WHISPER_NO_AVX2", "ON");
}
#[cfg(not(feature = "fma"))]
{
- config.define("WHISPER_NO_FMA", "ON")
+ config.define("WHISPER_NO_FMA", "ON");
}
#[cfg(not(feature = "f16c"))]
{
- config.define("WHISPER_NO_F16C", "ON")
+ config.define("WHISPER_NO_F16C", "ON");
+ }
+
+ #[cfg(feature = "cuda")]
+ {
+ config.define("WHISPER_CUBLAS", "ON");
}
let dst = config.build();
- println!(
- "cargo:rustc-link-search=native={}/lib/static",
- dst.display()
- );
- println!(
- "cargo:rustc-link-search=native={}/lib64/static",
- dst.display()
- );
- println!("cargo:rustc-link-lib=static=whisper");
+ if cfg!(target_family = "windows") {
+ println!("cargo:rustc-link-search=native={}/bin", dst.display());
+ println!(
+ "cargo:rustc-link-search=native={}/lib/static",
+ dst.display()
+ );
+ println!("cargo:rustc-link-lib=dylib=whisper");
+ } else {
+ println!("cargo:rustc-link-search=native={}/lib", dst.display());
+ println!("cargo:rustc-link-lib=dylib=whisper");
+ }
let bindings = bindgen::Builder::default()
.header(submodule_dir.join("ggml.h").to_string_lossy())
@@ -80,34 +87,26 @@ fn main() {
#[cfg(feature = "compat")]
mod compat {
- use std::path::Path;
+ use std::collections::HashSet;
+ use std::env;
+ use std::fmt::{Display, Formatter};
+ use std::path::{Path, PathBuf};
use std::process::Command;
pub fn redefine_symbols(out_path: impl AsRef) {
- // TODO this whole section is a bit hacky, could probably clean it up a bit, particularly the retrieval of symbols from the library files
- // TODO do this for cuda if necessary
-
let whisper_lib_name = lib_name();
- let (nm_name, objcopy_name) = tool_names();
- println!("Modifying {whisper_lib_name}, symbols acquired via \"{nm_name}\" and modified via \"{objcopy_name}\"");
+ let (nm, objcopy) = tools();
+ println!("Modifying {whisper_lib_name}, symbols acquired via \"{nm}\" and modified via \"{objcopy}\"");
- let lib_path = out_path.as_ref().join("lib").join("static");
+ let lib_path = if cfg!(target_family = "windows") {
+ out_path.as_ref().join("bin")
+ } else {
+ out_path.as_ref().join("lib")
+ };
// Modifying symbols exposed by the ggml library
- let output = Command::new(nm_name)
- .current_dir(&lib_path)
- .arg(whisper_lib_name)
- .args(["-p", "-P"])
- .output()
- .expect("Failed to acquire symbols from the compiled library.");
- if !output.status.success() {
- panic!(
- "An error has occurred while acquiring symbols from the compiled library ({})",
- output.status
- );
- }
- let out_str = String::from_utf8_lossy(output.stdout.as_slice());
+ let out_str = nm_symbols(&nm, whisper_lib_name, &lib_path);
let symbols = get_symbols(
&out_str,
[
@@ -133,86 +132,137 @@ mod compat {
},
],
);
-
- let mut cmd = Command::new(objcopy_name);
- cmd.current_dir(&lib_path);
- for symbol in symbols {
- cmd.arg(format!("--redefine-sym={symbol}=whisper_{symbol}"));
- }
- let status = cmd
- .arg(whisper_lib_name)
- .status()
- .expect("Failed to modify global symbols from the ggml library.");
- if !status.success() {
- panic!(
- "An error as occurred while modifying global symbols from library file ({})",
- status
- );
- }
+ objcopy_redefine(&objcopy, whisper_lib_name, "whisp_", symbols, &lib_path);
}
/// Returns *Whisper.cpp*'s compiled library name, based on the operating system.
fn lib_name() -> &'static str {
if cfg!(target_family = "windows") {
- "whisper.lib"
- } else if cfg!(target_family = "unix") {
- "libwhisper.a"
+ "whisper.dll"
+ } else if cfg!(target_os = "linux") {
+ "libwhisper.so"
+ } else if cfg!(any(
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "dragonfly"
+ )) {
+ "libwhisper.dylib"
} else {
println!("cargo:warning=Unknown target family, defaulting to Unix lib names");
- "libwhisper.a"
+ "libwhisper.so"
}
}
- /// Returns the names of tools equivalent to [nm][nm] and [objcopy][objcopy].
+ /// Returns [`Tool`]s equivalent to [nm][nm] and [objcopy][objcopy].
///
/// [nm]: https://www.man7.org/linux/man-pages/man1/nm.1.html
/// [objcopy]: https://www.man7.org/linux/man-pages/man1/objcopy.1.html
- fn tool_names() -> (&'static str, &'static str) {
+ fn tools() -> (Tool, Tool) {
let nm_names;
let objcopy_names;
- if cfg!(target_family = "unix") {
+ let nm_help;
+ let objcopy_help;
+ if cfg!(target_os = "linux") {
nm_names = vec!["nm", "llvm-nm"];
objcopy_names = vec!["objcopy", "llvm-objcopy"];
+ nm_help = vec!["\"nm\" from GNU Binutils", "\"llvm-nm\" from LLVM"];
+ objcopy_help = vec![
+ "\"objcopy\" from GNU Binutils",
+ "\"llvm-objcopy\" from LLVM",
+ ];
+ } else if cfg!(any(
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "dragonfly"
+ )) {
+ nm_names = vec!["nm", "llvm-nm"];
+ objcopy_names = vec!["llvm-objcopy"];
+ nm_help = vec!["\"llvm-nm\" from LLVM 17"];
+ objcopy_help = vec!["\"llvm-objcopy\" from LLVM 17"];
} else {
nm_names = vec!["llvm-nm"];
objcopy_names = vec!["llvm-objcopy"];
+ nm_help = vec!["\"llvm-nm\" from LLVM 17"];
+ objcopy_help = vec!["\"llvm-objcopy\" from LLVM 17"];
}
- let nm_name;
+ let nm_env = "NM_PATH";
+ println!("cargo:rerun-if-env-changed={nm_env}");
+ println!("Looking for \"nm\" or an equivalent tool");
+ let nm_name = find_tool(&nm_names, nm_env).unwrap_or_else(move || {
+ panic_tool_help("nm", nm_env, &nm_help);
+ unreachable!("The function above should have panicked")
+ });
+
+ let objcopy_env = "OBJCOPY_PATH";
+ println!("cargo:rerun-if-env-changed={objcopy_env}");
+ println!("Looking for \"objcopy\" or an equivalent tool..");
+ let objcopy_name = find_tool(&objcopy_names, objcopy_env).unwrap_or_else(move || {
+ panic_tool_help("objcopy", objcopy_env, &objcopy_help);
+ unreachable!("The function above should have panicked")
+ });
- if let Some(path) = option_env!("NM_PATH") {
- nm_name = path;
- } else {
- println!("Looking for \"nm\" or an equivalent tool");
- nm_name = find_tool(&nm_names).expect(
- "No suitable tool equivalent to \"nm\" has been found in \
- PATH, if one is already installed, either add it to PATH or set NM_PATH to its full path",
- );
- }
+ (nm_name, objcopy_name)
+ }
- let objcopy_name;
- if let Some(path) = option_env!("OBJCOPY_PATH") {
- objcopy_name = path;
- } else {
- println!("Looking for \"objcopy\" or an equivalent tool");
- objcopy_name = find_tool(&objcopy_names).expect("No suitable tool equivalent to \"objcopy\" has \
- been found in PATH, if one is already installed, either add it to PATH or set OBJCOPY_PATH to its full path");
- }
+ /// A command line tool name present in `PATH` or its full [`Path`].
+ enum Tool {
+ /// The name of a tool present in `PATH`.
+ Name(&'static str),
- (nm_name, objcopy_name)
+ /// The full [`Path`] to a tool.
+ FullPath(PathBuf),
}
- /// Returns the first tool found in the system, given a list of tool names, returning the first one found and
- /// printing its version.
+ impl Display for Tool {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ match self {
+ Tool::Name(name) => write!(f, "{}", name),
+ Tool::FullPath(path) => write!(f, "{}", path.display()),
+ }
+ }
+ }
+
+ /// Returns the first [`Tool`] found in the system `PATH`, given a list of tool names, returning
+ /// the first one found and printing its version.
+ ///
+ /// If a value is present in the provided environment variable name, it will get checked
+ /// instead.
///
- /// Returns [`Option::None`] if no tool is found.
- fn find_tool<'a>(names: &[&'a str]) -> Option<&'a str> {
+ /// ## Panic
+ /// Returns [`Option::None`] if no [`Tool`] is found.
+ fn find_tool(names: &[&'static str], env: &str) -> Option {
+ if let Ok(path_str) = env::var(env) {
+ let path_str = path_str.trim_matches([' ', '"', '\''].as_slice());
+ println!("{env} is set, checking if \"{path_str}\" is a valid tool");
+ let path = PathBuf::from(&path_str);
+
+ if !path.is_file() {
+ panic!("\"{path_str}\" is not a file path.")
+ }
+
+ let output = Command::new(path_str)
+ .arg("--version")
+ .output()
+ .unwrap_or_else(|e| panic!("Failed to run \"{path_str} --version\". ({e})"));
+
+ if output.status.success() {
+ let out_str = String::from_utf8_lossy(&output.stdout);
+ println!("Valid tool found:\n{out_str}");
+ } else {
+ println!("cargo:warning=Tool \"{path_str}\" found, but could not execute \"{path_str} --version\"")
+ }
+
+ return Some(Tool::FullPath(path));
+ }
+
+ println!("{env} not set, looking for {names:?} in PATH");
for name in names {
if let Ok(output) = Command::new(name).arg("--version").output() {
if output.status.success() {
let out_str = String::from_utf8_lossy(&output.stdout);
- println!("Valid \"tool\" found:\n{out_str}");
- return Some(name);
+ println!("Valid tool found:\n{out_str}");
+ return Some(Tool::Name(name));
}
}
}
@@ -220,6 +270,80 @@ mod compat {
None
}
+ /// Always panics, printing suggestions for finding the specified tool.
+ fn panic_tool_help(name: &str, env: &str, suggestions: &[&str]) {
+ let suggestions_str = if suggestions.is_empty() {
+ String::new()
+ } else {
+ let mut suggestions_str = "For your Operating System we recommend:\n".to_string();
+ for suggestion in &suggestions[..suggestions.len() - 1] {
+ suggestions_str.push_str(&format!("{suggestion}\nOR\n"));
+ }
+ suggestions_str.push_str(suggestions[suggestions.len() - 1]);
+ suggestions_str
+ };
+
+ panic!("No suitable tool equivalent to \"{name}\" has been found in PATH, if one is already installed, either add its directory to PATH or set {env} to its full path. {suggestions_str}")
+ }
+
+ /// Executes [nm][nm] or an equivalent tool in portable mode and returns the output.
+ ///
+ /// ## Panic
+ /// Will panic on any errors.
+ ///
+ /// [nm]: https://www.man7.org/linux/man-pages/man1/nm.1.html
+ fn nm_symbols(tool: &Tool, target_lib: &str, out_path: impl AsRef) -> String {
+ let output = Command::new(tool.to_string())
+ .current_dir(&out_path)
+ .arg(target_lib)
+ .args(["-p", "-P"])
+ .output()
+ .unwrap_or_else(move |e| panic!("Failed to run \"{tool}\". ({e})"));
+
+ if !output.status.success() {
+ panic!(
+ "An error has occurred while acquiring symbols from the compiled library \"{target_lib}\" ({}):\n{}",
+ output.status,
+ String::from_utf8_lossy(&output.stderr)
+ );
+ }
+
+ String::from_utf8_lossy(&output.stdout).to_string()
+ }
+
+ /// Executes [objcopy][objcopy], adding a prefix to the specified symbols of the target library.
+ ///
+ /// ## Panic
+ /// Will panic on any errors.
+ ///
+ /// [objcopy]: https://www.man7.org/linux/man-pages/man1/objcopy.1.html
+ fn objcopy_redefine(
+ tool: &Tool,
+ target_lib: &str,
+ prefix: &str,
+ symbols: HashSet<&str>,
+ out_path: impl AsRef,
+ ) {
+ let mut cmd = Command::new(tool.to_string());
+ cmd.current_dir(&out_path);
+ for symbol in symbols {
+ cmd.arg(format!("--redefine-sym={symbol}={prefix}{symbol}"));
+ }
+
+ let output = cmd
+ .arg(target_lib)
+ .output()
+ .unwrap_or_else(move |e| panic!("Failed to run \"{tool}\". ({e})"));
+
+ if !output.status.success() {
+ panic!(
+ "An error has occurred while redefining symbols from library file \"{target_lib}\" ({}):\n{}",
+ output.status,
+ String::from_utf8_lossy(&output.stderr)
+ );
+ }
+ }
+
/// A filter for a symbol in a library.
struct Filter<'a> {
prefix: &'a str,
@@ -232,14 +356,15 @@ mod compat {
fn get_symbols<'a, const N: usize>(
nm_output: &'a str,
filters: [Filter<'a>; N],
- ) -> impl Iterator- + 'a {
- nm_output
+ ) -> HashSet<&'a str> {
+ let iter = nm_output
.lines()
.map(|symbol| {
// Strip irrelevant information
let mut stripped = symbol;
while stripped.split(' ').count() > 2 {
+ // SAFETY: We just made sure ' ' is present above
let idx = unsafe { stripped.rfind(' ').unwrap_unchecked() };
stripped = &stripped[..idx]
}
@@ -257,6 +382,9 @@ mod compat {
}
false
})
- .map(|symbol| &symbol[..symbol.len() - 2]) // Strip the type, so only the symbol remains
+ .map(|symbol| &symbol[..symbol.len() - 2]); // Strip the type, so only the symbol remains
+
+ // Filter duplicates
+ HashSet::from_iter(iter)
}
}
diff --git a/crates/whisper_cpp_sys/src/lib.rs b/crates/whisper_cpp_sys/src/lib.rs
index 452f5b0..5b05ada 100644
--- a/crates/whisper_cpp_sys/src/lib.rs
+++ b/crates/whisper_cpp_sys/src/lib.rs
@@ -1,4 +1,3 @@
-
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
diff --git a/crates/whisper_cpp_sys/thirdparty/whisper.cpp b/crates/whisper_cpp_sys/thirdparty/whisper.cpp
index a01b2e0..3d42463 160000
--- a/crates/whisper_cpp_sys/thirdparty/whisper.cpp
+++ b/crates/whisper_cpp_sys/thirdparty/whisper.cpp
@@ -1 +1 @@
-Subproject commit a01b2e0971caabbe40ce993513c1462a47462234
+Subproject commit 3d4246384525824b1dc6efc86f86003c8c615295
diff --git a/crates/whisper_cpp_tests/Cargo.toml b/crates/whisper_cpp_tests/Cargo.toml
index 7b3229b..90ed359 100644
--- a/crates/whisper_cpp_tests/Cargo.toml
+++ b/crates/whisper_cpp_tests/Cargo.toml
@@ -10,3 +10,6 @@ thiserror = { workspace = true }
tokio = { workspace = true, features = ["full"] }
wav = "1.0.0"
whisper_cpp = { version = "^0.2.1", path = "../whisper_cpp", default-features = false, features = ["compat", "native"] }
+
+[features]
+cuda = ["whisper_cpp/cuda"]
diff --git a/crates/whisper_cpp_tests/src/lib.rs b/crates/whisper_cpp_tests/src/lib.rs
index d2b6d7f..2baf417 100644
--- a/crates/whisper_cpp_tests/src/lib.rs
+++ b/crates/whisper_cpp_tests/src/lib.rs
@@ -17,7 +17,7 @@ mod tests {
#[tokio::test]
async fn it_works() -> Result<(), TestError> {
let model_paths = {
- let mut dir = std::env::var("WHISPER_TEST_MODEL_DIR").unwrap_or_else(|_| {
+ let dir = std::env::var("WHISPER_TEST_MODEL_DIR").unwrap_or_else(|_| {
eprintln!(
"WHISPER_TEST_MODEL environment variable not set. \
Please set this to the path to a Whisper GGUF model file for the test to run."
@@ -26,11 +26,12 @@ mod tests {
std::process::exit(0)
});
- if !dir.ends_with('/') {
- dir.push('/');
+ let dir = std::path::Path::new(&dir);
+
+ if !dir.is_dir() {
+ panic!("\"{}\" is not a directory", dir.to_string_lossy());
}
- let dir = std::path::Path::new(&dir);
let mut models = tokio::fs::read_dir(dir).await.unwrap();
let mut rv = vec![];
@@ -58,7 +59,13 @@ mod tests {
});
for model_path_str in model_paths {
- let model = WhisperModel::new_from_file(model_path_str, false)?;
+ let device = if cfg!(any(feature = "cuda")) {
+ Some(0)
+ } else {
+ None
+ };
+
+ let model = WhisperModel::new_from_file(model_path_str, device)?;
let mut session = model.new_session().await?;
@@ -72,14 +79,10 @@ mod tests {
.map(|v| *v as f32 / 32768.)
.collect();
- session.full(params, &samples).await?;
-
- let mut result = "".to_string();
- for i in 0..session.segment_count() {
- result += &*session.segment_text(i)?;
- }
+ session.advance(params, &samples).await?;
+ let result = session.new_context()?;
- println!("{result}");
+ println!("\n{result}\n");
}
Ok(())
diff --git a/flake.lock b/flake.lock
index d82c0cf..34aadc4 100644
--- a/flake.lock
+++ b/flake.lock
@@ -10,11 +10,11 @@
"pre-commit-hooks": "pre-commit-hooks"
},
"locked": {
- "lastModified": 1700140236,
- "narHash": "sha256-OpukFO0rRG2hJzD+pCQq+nSWuT9dBL6DSvADQaUlmFg=",
+ "lastModified": 1707004164,
+ "narHash": "sha256-9Hr8onWtvLk5A8vCEkaE9kxA0D7PR62povFokM1oL5Q=",
"owner": "cachix",
"repo": "devenv",
- "rev": "525d60c44de848a6b2dd468f6efddff078eb2af2",
+ "rev": "0e68853bb27981a4ffd7a7225b59ed84f7180fc7",
"type": "github"
},
"original": {
@@ -31,11 +31,11 @@
"rust-analyzer-src": "rust-analyzer-src"
},
"locked": {
- "lastModified": 1700461394,
- "narHash": "sha256-lBpjEshdBxeuJwc4+vh4jbO3AmhXbiFrkdWy2pABAAc=",
+ "lastModified": 1706941198,
+ "narHash": "sha256-t6/qloMYdknVJ9a3QzjylQIZnQfgefJ5kMim50B7dwA=",
"owner": "nix-community",
"repo": "fenix",
- "rev": "5ad1b10123ca40c9d983fb0863403fd97a06c0f8",
+ "rev": "28dbd8b43ea328ee708f7da538c63e03d5ed93c8",
"type": "github"
},
"original": {
@@ -85,11 +85,11 @@
]
},
"locked": {
- "lastModified": 1694529238,
- "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
+ "lastModified": 1705309234,
+ "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
"owner": "numtide",
"repo": "flake-utils",
- "rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
+ "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
"type": "github"
},
"original": {
@@ -162,16 +162,16 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1700403855,
- "narHash": "sha256-Q0Uzjik9kUTN9pd/kp52XJi5kletBhy29ctBlAG+III=",
+ "lastModified": 1707238373,
+ "narHash": "sha256-WKxT0yLzWbFZwYi92lI0yWJpYtRaFSWHGX8QXzejapw=",
"owner": "NixOS",
"repo": "nixpkgs",
- "rev": "0c5678df521e1407884205fe3ce3cf1d7df297db",
+ "rev": "fb0c047e30b69696acc42e669d02452ca1b55755",
"type": "github"
},
"original": {
"owner": "NixOS",
- "ref": "nixos-23.05",
+ "ref": "nixos-23.11",
"repo": "nixpkgs",
"type": "github"
}
@@ -223,11 +223,11 @@
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
- "lastModified": 1688056373,
- "narHash": "sha256-2+SDlNRTKsgo3LBRiMUcoEUb6sDViRNQhzJquZ4koOI=",
+ "lastModified": 1704725188,
+ "narHash": "sha256-qq8NbkhRZF1vVYQFt1s8Mbgo8knj+83+QlL5LBnYGpI=",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
- "rev": "5843cf069272d92b60c3ed9e55b7a8989c01d4c7",
+ "rev": "ea96f0c05924341c551a797aaba8126334c505d2",
"type": "github"
},
"original": {
@@ -248,11 +248,11 @@
"rust-analyzer-src": {
"flake": false,
"locked": {
- "lastModified": 1700247620,
- "narHash": "sha256-+Xg0qZLbC9dZx0Z6JbaVHR/BklAr2I83dzKLB8r41c8=",
+ "lastModified": 1706875368,
+ "narHash": "sha256-KOBXxNurIU2lEmO6lR2A5El32X9x8ITt25McxKZ/Ew0=",
"owner": "rust-lang",
"repo": "rust-analyzer",
- "rev": "255eed40c45fcf108ba844b4ad126bdc4e7a18df",
+ "rev": "8f6a72871ec87ed53cfe43a09fb284168a284e7e",
"type": "github"
},
"original": {
diff --git a/flake.nix b/flake.nix
index b6607c0..9c2967b 100644
--- a/flake.nix
+++ b/flake.nix
@@ -1,6 +1,6 @@
{
inputs = {
- nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.05";
+ nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
systems.url = "github:nix-systems/default";
flake-utils = {
url = "github:numtide/flake-utils";