chore(release): v0.2.28 — auto-detect ready CMF quant & update section title

This commit is contained in:
infosave2007
2026-07-21 23:35:14 +03:00
parent 66ee32b233
commit 1661c19550
6 changed files with 43 additions and 9 deletions
+5 -1
View File
@@ -3,7 +3,11 @@
All notable changes to this project are documented here.
The format is based on [Keep a Changelog](https://keepachangelog.com/).
## [0.2.27] - 2026-07-21
## [0.2.28] - 2026-07-21
### Fixed
- **Quantization Badge & Title for Pre-Converted Models**: Automatically detect quantization (`Q1`, `Q1T`) for ready-to-run `.cmf` models (e.g. `infosave/Bonsai-27Bcmf`) from repo name and downloaded filename, resolving default `Q8_2F` badge fallback. Updated section title to "Загрузки / Конвертации" ("Downloads & Conversions").
### Fixed
- **Automatic CMF Local Server Lifecycle**: Registering an imported `.cmf` model automatically adds it to `[[cmf.servers]]` and reloads the runtime (`cmf_runtime::manage`), automatically spawning `cortiq serve` on port 8090 so chat completion requests route seamlessly without `upstream unavailable` errors.
Generated
+1 -1
View File
@@ -285,7 +285,7 @@ checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
[[package]]
name = "cortiq-gateway"
version = "0.2.27"
version = "0.2.28"
dependencies = [
"anyhow",
"arc-swap",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "cortiq-gateway"
version = "0.2.27"
version = "0.2.28"
edition = "2021"
rust-version = "1.75"
license = "Apache-2.0"
+34 -4
View File
@@ -160,6 +160,14 @@ impl JobStore {
}
}
}
fn update_quant(&self, id: &str, quant: String) {
if let Some(j) = self.jobs.lock().unwrap().get_mut(id) {
j.quant = quant.clone();
if !j.log.is_empty() && j.log[0].starts_with("→ downloading ready .cmf model") {
j.log[0] = format!("→ downloading ready .cmf model {} ({})", j.repo, quant);
}
}
}
fn set_state(&self, id: &str, state: &str) {
if let Some(j) = self.jobs.lock().unwrap().get_mut(id) {
j.state = state.into();
@@ -321,6 +329,21 @@ async fn download_cmf_repo(
}
};
let path_lower = cmf_path.to_ascii_lowercase();
let detected_quant =
if path_lower.contains("-q1t.") || repo.to_ascii_lowercase().contains("2bit") {
"Q1T".to_string()
} else if path_lower.contains("-q1.") || repo.to_ascii_lowercase().contains("cmf") {
"Q1".to_string()
} else if path_lower.contains("-q4.") {
"Q4".to_string()
} else if path_lower.contains("-q8.") {
"Q8".to_string()
} else {
"READY_CMF".to_string()
};
store.update_quant(&id, detected_quant);
store.push_line(&id, format!("→ downloading {cmf_path} from HuggingFace..."));
store.set_progress(&id, 0.05, "downloading".into());
@@ -464,12 +487,19 @@ pub fn start_import(store: Arc<JobStore>, cfg: &CmfCfg, p: ImportParams) -> Resu
let id = gen_id(&p.repo);
let is_cmf = is_cmf_repo(&p.repo);
let quant_display = if p.quant.is_empty() || p.quant == "auto" {
if is_cmf {
"READY_CMF".to_string()
let quant_display = if is_cmf {
let r = p.repo.to_lowercase();
if r.contains("2bit") || r.contains("q1t") {
"Q1T".to_string()
} else if r.contains("1.7bcmf") || r.contains("27bcmf") || r.contains("cmf") {
"Q1".to_string()
} else if p.quant.is_empty() || p.quant == "auto" || p.quant == "Q8_2F" {
"Q1".to_string()
} else {
"q8".to_string()
p.quant.clone()
}
} else if p.quant.is_empty() || p.quant == "auto" {
"q8".to_string()
} else {
p.quant.clone()
};
+1 -1
View File
@@ -374,7 +374,7 @@ export default {
"import.failed": "Conversion failed — see the log.",
"import.register": "Register as local model",
"import.registered": "Registered as '{id}'. Run cortiq-server to serve it.",
"import.jobs": "Conversions",
"import.jobs": "Downloads & Conversions",
"import.cancel": "Cancel",
"import.cancelling": "Cancelling — cleaning up partial output…",
"import.delete": "Delete",
+1 -1
View File
@@ -373,7 +373,7 @@ export default {
"import.failed": "Конвертация не удалась — смотрите лог.",
"import.register": "Подключить как локальную модель",
"import.registered": "Подключено как '{id}'. Запустите cortiq-server для обслуживания.",
"import.jobs": "Конвертации",
"import.jobs": "Загрузки / Конвертации",
"import.cancel": "Отменить",
"import.cancelling": "Отмена — удаляю недописанный файл…",
"import.delete": "Удалить",