mirror of
https://github.com/AlexsJones/llmfit.git
synced 2026-10-19 07:23:24 +00:00
feat(models): add the Qwen3.8 family and fix Qwen generation parsing (#893)
Pin all four official Qwen3.8 repos in the curated catalog:
Qwen/Qwen3.8-27B 27.78B dense, 64 layers (16 full / 48 linear)
Qwen/Qwen3.8-27B-FP8 same weights, FP8 checkpoint
Qwen/Qwen3.8-2.4T-A95B 2.446T total / 95B active, 512 experts (10 active),
92 layers (23 full / 69 linear)
Qwen/Qwen3.8-2.4T-A95B-FP8 same, FP8 checkpoint
The automated weekly refresh in #892 picked up three of these via trending
discovery, but none were in TARGET_MODELS, so they could drop out of any
later scrape; the non-FP8 2.4T-A95B was missing entirely. Catalog entries
were merged in surgically (four entries) rather than by a full re-scrape so
this diff stays reviewable alongside #892.
infer_attention_layout_from_name now matches qwen3.8- and handles the new
-a95b 92-layer shape, and OLLAMA_MAPPINGS gains qwen3.8-27b -> qwen3.8:27b
(Ollama publishes only the 27B; the 2.4T has no library entry).
Also fixes a generation-scoring bug this surfaced. parse_generation
consulted the architecture string before the model name, but Qwen3.6 and
Qwen3.8 both ship as model_type "qwen3_5" -- so every Qwen3.6 model in the
catalog scored as generation 3.5, and the name-based 3.6 branch added in
5397a8a was dead code for anything with an architecture set. The existing
test passed None for architecture, so it never caught this.
qwen_minor_generation_from_name is now consulted first inside the Qwen arch
branch. It matches only explicit minor versions and returns None for a bare
"Qwen3", so qwen3_next still resolves from the architecture string instead
of regressing to 3.0. scripts/validate_generation_scoring.py, which
documents itself as a mirror of the Rust logic, is updated to match.
Quality bonus is (generation - 1) * 3 clamped to 9, so Qwen3.6 models gain
+0.3 and Qwen3.8 lands at +8.4.
This commit is contained in:
parent
a9ac7ed91c
commit
6e024b2e51
6 changed files with 283 additions and 18 deletions
|
|
@ -1,6 +1,6 @@
|
|||
# Supported Models
|
||||
|
||||
llmfit ships with a curated database of 106 LLM models from HuggingFace. All memory estimates assume Q4_K_M quantization (0.5 bytes per parameter) unless noted otherwise.
|
||||
llmfit ships with a curated database of 108 LLM models from HuggingFace. All memory estimates assume Q4_K_M quantization (0.5 bytes per parameter) unless noted otherwise.
|
||||
|
||||
### 01.ai
|
||||
|
||||
|
|
@ -34,6 +34,7 @@ llmfit ships with a curated database of 106 LLM models from HuggingFace. All mem
|
|||
| [Qwen/Qwen3-14B](https://huggingface.co/Qwen/Qwen3-14B) | 14.8B | Q4_K_M | 128k | General purpose text generation |
|
||||
| [Qwen/Qwen2.5-Coder-14B-Instruct](https://huggingface.co/Qwen/Qwen2.5-Coder-14B-Instruct) | 14.8B | Q4_K_M | 32k | Code generation and completion |
|
||||
| [Qwen/Qwen3.5-27B](https://huggingface.co/Qwen/Qwen3.5-27B) | 27.8B | Q4_K_M | 256k | Multimodal, vision and text |
|
||||
| [Qwen/Qwen3.8-27B](https://huggingface.co/Qwen/Qwen3.8-27B) | 27.8B | Q4_K_M | 256k | Multimodal, vision and text |
|
||||
| [Qwen/Qwen3-30B-A3B](https://huggingface.co/Qwen/Qwen3-30B-A3B) | 30.5B (MoE) | Q4_K_M | 40k | Efficient MoE, general purpose |
|
||||
| [Qwen/Qwen3.5-35B-A3B](https://huggingface.co/Qwen/Qwen3.5-35B-A3B) | 36.0B (MoE) | Q4_K_M | 256k | Multimodal, vision and text |
|
||||
| [Qwen/Qwen2.5-32B-Instruct](https://huggingface.co/Qwen/Qwen2.5-32B-Instruct) | 32.5B | Q4_K_M | 128k | Instruction following, chat |
|
||||
|
|
@ -44,6 +45,7 @@ llmfit ships with a curated database of 106 LLM models from HuggingFace. All mem
|
|||
| [Qwen/Qwen3-235B-A22B](https://huggingface.co/Qwen/Qwen3-235B-A22B) | 235B (MoE) | Q4_K_M | 40k | State-of-the-art, MoE architecture |
|
||||
| [Qwen/Qwen3.5-397B-A17B](https://huggingface.co/Qwen/Qwen3.5-397B-A17B) | 403.4B (MoE) | Q4_K_M | 256k | Multimodal, vision and text |
|
||||
| [Qwen/Qwen3-Coder-480B-A35B-Instruct](https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct) | 480B (MoE) | Q4_K_M | 256k | Code generation and completion |
|
||||
| [Qwen/Qwen3.8-2.4T-A95B](https://huggingface.co/Qwen/Qwen3.8-2.4T-A95B) | 2446.2B (MoE) | Q4_K_M | 256k | General purpose text generation |
|
||||
|
||||
### Allen Institute
|
||||
|
||||
|
|
|
|||
|
|
@ -274430,6 +274430,88 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Qwen/Qwen3.8-27B",
|
||||
"provider": "Alibaba",
|
||||
"parameter_count": "27.8B",
|
||||
"parameters_raw": 27781427952,
|
||||
"min_ram_gb": 15.5,
|
||||
"recommended_ram_gb": 25.9,
|
||||
"min_vram_gb": 14.2,
|
||||
"quantization": "Q4_K_M",
|
||||
"format": "gguf",
|
||||
"context_length": 262144,
|
||||
"use_case": "Multimodal, vision and text",
|
||||
"capabilities": [
|
||||
"vision",
|
||||
"tool_use"
|
||||
],
|
||||
"languages": [],
|
||||
"pipeline_tag": "image-text-to-text",
|
||||
"architecture": "qwen3_5",
|
||||
"hf_downloads": 267725,
|
||||
"hf_likes": 10385,
|
||||
"release_date": "2026-08-05",
|
||||
"num_hidden_layers": 64,
|
||||
"num_attention_heads": 24,
|
||||
"num_key_value_heads": 4,
|
||||
"head_dim": 256,
|
||||
"hidden_size": 5120,
|
||||
"vocab_size": 248320,
|
||||
"moe_intermediate_size": 17408,
|
||||
"shared_expert_intermediate_size": null,
|
||||
"license": "apache-2.0",
|
||||
"gguf_sources": [
|
||||
{
|
||||
"repo": "unsloth/Qwen3.8-27B-GGUF",
|
||||
"provider": "unsloth"
|
||||
},
|
||||
{
|
||||
"repo": "bartowski/Qwen3.8-27B-GGUF",
|
||||
"provider": "bartowski"
|
||||
},
|
||||
{
|
||||
"repo": "ggml-org/Qwen3.8-27B-GGUF",
|
||||
"provider": "ggml-org"
|
||||
},
|
||||
{
|
||||
"repo": "mradermacher/Qwen3.8-27B-GGUF",
|
||||
"provider": "mradermacher"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Qwen/Qwen3.8-27B-FP8",
|
||||
"provider": "Alibaba",
|
||||
"parameter_count": "27.8B",
|
||||
"parameters_raw": 27781427952,
|
||||
"min_ram_gb": 15.5,
|
||||
"recommended_ram_gb": 25.9,
|
||||
"min_vram_gb": 14.2,
|
||||
"quantization": "Q4_K_M",
|
||||
"format": "gguf",
|
||||
"context_length": 262144,
|
||||
"use_case": "Multimodal, vision and text",
|
||||
"capabilities": [
|
||||
"vision",
|
||||
"tool_use"
|
||||
],
|
||||
"languages": [],
|
||||
"pipeline_tag": "image-text-to-text",
|
||||
"architecture": "qwen3_5",
|
||||
"hf_downloads": 352971,
|
||||
"hf_likes": 494,
|
||||
"release_date": "2026-08-13",
|
||||
"num_hidden_layers": 64,
|
||||
"num_attention_heads": 24,
|
||||
"num_key_value_heads": 4,
|
||||
"head_dim": 256,
|
||||
"hidden_size": 5120,
|
||||
"vocab_size": 248320,
|
||||
"moe_intermediate_size": 17408,
|
||||
"shared_expert_intermediate_size": null,
|
||||
"license": "apache-2.0"
|
||||
},
|
||||
{
|
||||
"name": "cbert33/Qwen3.6-27B-Fable-Fusion-711-Uncensored-Heretic-FP8-KV-Calibrated",
|
||||
"provider": "cbert33",
|
||||
|
|
@ -345304,6 +345386,82 @@
|
|||
"_discovered": true,
|
||||
"license": "kimi-k3"
|
||||
},
|
||||
{
|
||||
"name": "Qwen/Qwen3.8-2.4T-A95B",
|
||||
"provider": "Alibaba",
|
||||
"parameter_count": "2446.2B",
|
||||
"parameters_raw": 2446182725504,
|
||||
"min_ram_gb": 1366.9,
|
||||
"recommended_ram_gb": 2278.2,
|
||||
"min_vram_gb": 1253.0,
|
||||
"quantization": "Q4_K_M",
|
||||
"format": "gguf",
|
||||
"context_length": 262144,
|
||||
"use_case": "General purpose text generation",
|
||||
"capabilities": [
|
||||
"tool_use"
|
||||
],
|
||||
"languages": [],
|
||||
"pipeline_tag": "text-generation",
|
||||
"architecture": "qwen3_5_moe_text",
|
||||
"hf_downloads": 7932,
|
||||
"hf_likes": 1016,
|
||||
"release_date": "2026-08-08",
|
||||
"num_hidden_layers": 92,
|
||||
"num_attention_heads": 64,
|
||||
"num_key_value_heads": 4,
|
||||
"head_dim": 256,
|
||||
"hidden_size": 8192,
|
||||
"vocab_size": 248320,
|
||||
"moe_intermediate_size": 2048,
|
||||
"shared_expert_intermediate_size": 2048,
|
||||
"license": "qwen3.8-max",
|
||||
"is_moe": true,
|
||||
"num_experts": 512,
|
||||
"active_experts": 10,
|
||||
"active_parameters": 95000000000,
|
||||
"gguf_sources": [
|
||||
{
|
||||
"repo": "unsloth/Qwen3.8-2.4T-A95B-GGUF",
|
||||
"provider": "unsloth"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Qwen/Qwen3.8-2.4T-A95B-FP8",
|
||||
"provider": "Alibaba",
|
||||
"parameter_count": "2446.2B",
|
||||
"parameters_raw": 2446182725504,
|
||||
"min_ram_gb": 1366.9,
|
||||
"recommended_ram_gb": 2278.2,
|
||||
"min_vram_gb": 1253.0,
|
||||
"quantization": "Q4_K_M",
|
||||
"format": "gguf",
|
||||
"context_length": 262144,
|
||||
"use_case": "General purpose text generation",
|
||||
"capabilities": [
|
||||
"tool_use"
|
||||
],
|
||||
"languages": [],
|
||||
"pipeline_tag": "text-generation",
|
||||
"architecture": "qwen3_5_moe_text",
|
||||
"hf_downloads": 11311,
|
||||
"hf_likes": 210,
|
||||
"release_date": "2026-08-08",
|
||||
"num_hidden_layers": 92,
|
||||
"num_attention_heads": 64,
|
||||
"num_key_value_heads": 4,
|
||||
"head_dim": 256,
|
||||
"hidden_size": 8192,
|
||||
"vocab_size": 248320,
|
||||
"moe_intermediate_size": 2048,
|
||||
"shared_expert_intermediate_size": 2048,
|
||||
"license": "qwen3.8-max",
|
||||
"is_moe": true,
|
||||
"num_experts": 512,
|
||||
"active_experts": 10,
|
||||
"active_parameters": 95000000000
|
||||
},
|
||||
{
|
||||
"name": "moonshotai/Kimi-K3",
|
||||
"provider": "moonshotai",
|
||||
|
|
|
|||
|
|
@ -114,6 +114,26 @@ pub fn quant_quality_penalty(quant: &str) -> f64 {
|
|||
}
|
||||
}
|
||||
|
||||
/// Explicit Qwen minor version spelled out in a repo name (`Qwen3.8-27B` → 3.8).
|
||||
///
|
||||
/// Only matches names that carry the minor version. A bare `Qwen3` returns
|
||||
/// `None` so callers can fall back to the architecture string, which is what
|
||||
/// distinguishes variants like `qwen3_next`.
|
||||
fn qwen_minor_generation_from_name(name_lower: &str) -> Option<f64> {
|
||||
const VERSIONS: &[(&str, &str, f64)] = &[
|
||||
("qwen3.8", "qwen3_8", 3.8),
|
||||
("qwen3.6", "qwen3_6", 3.6),
|
||||
("qwen3.5", "qwen3_5", 3.5),
|
||||
("qwen2.5", "qwen2_5", 2.5),
|
||||
];
|
||||
VERSIONS
|
||||
.iter()
|
||||
.find(|(dotted, underscored, _)| {
|
||||
name_lower.contains(dotted) || name_lower.contains(underscored)
|
||||
})
|
||||
.map(|(_, _, generation)| *generation)
|
||||
}
|
||||
|
||||
/// Parse model generation from architecture string and model name.
|
||||
///
|
||||
/// Returns a generation number (e.g. 2.0 for "qwen2", 3.5 for "qwen3_5_moe",
|
||||
|
|
@ -135,6 +155,11 @@ pub fn parse_generation(architecture: Option<&str>, name: &str) -> Option<f64> {
|
|||
}
|
||||
// Qwen: qwen2, qwen3, qwen3_moe, qwen3_5, qwen3_5_moe, qwen3_next
|
||||
if let Some(suffix) = arch_lower.strip_prefix("qwen") {
|
||||
// Qwen3.6 and Qwen3.8 ship under the `qwen3_5` architecture string,
|
||||
// so an explicit minor version in the repo name wins over the arch.
|
||||
if let Some(generation) = qwen_minor_generation_from_name(&name.to_lowercase()) {
|
||||
return Some(generation);
|
||||
}
|
||||
if suffix.starts_with("3_5") || suffix.starts_with("3.5") {
|
||||
return Some(3.5);
|
||||
}
|
||||
|
|
@ -218,19 +243,13 @@ pub fn parse_generation(architecture: Option<&str>, name: &str) -> Option<f64> {
|
|||
// Fallback: parse generation from model name
|
||||
let name_lower = name.to_lowercase();
|
||||
|
||||
// Qwen3.6, Qwen3.5, Qwen3, Qwen2.5, Qwen2
|
||||
if name_lower.contains("qwen3.6") || name_lower.contains("qwen3_6") {
|
||||
return Some(3.6);
|
||||
}
|
||||
if name_lower.contains("qwen3.5") || name_lower.contains("qwen3_5") {
|
||||
return Some(3.5);
|
||||
// Qwen3.8, Qwen3.6, Qwen3.5, Qwen3, Qwen2.5, Qwen2
|
||||
if let Some(generation) = qwen_minor_generation_from_name(&name_lower) {
|
||||
return Some(generation);
|
||||
}
|
||||
if name_lower.contains("qwen3") {
|
||||
return Some(3.0);
|
||||
}
|
||||
if name_lower.contains("qwen2.5") || name_lower.contains("qwen2_5") {
|
||||
return Some(2.5);
|
||||
}
|
||||
if name_lower.contains("qwen2") {
|
||||
return Some(2.0);
|
||||
}
|
||||
|
|
@ -1572,10 +1591,18 @@ pub fn infer_attention_layout_from_name(name: &str) -> Option<AttentionLayout> {
|
|||
});
|
||||
}
|
||||
|
||||
// Qwen3.5 / Qwen3.6 hybrid models use 1 full attention per 4 layers.
|
||||
// Qwen3.5 / Qwen3.6 / Qwen3.8 hybrid models use 1 full attention per 4
|
||||
// layers (`full_attention_interval: 4` in their configs).
|
||||
// The dense 27B variants have 64 layers → 16 full + 48 linear.
|
||||
// The MoE A3B variants have 40 layers → 10 full + 30 linear.
|
||||
if lower.contains("qwen3.5-") || lower.contains("qwen3.6-") {
|
||||
// Qwen3.8-2.4T-A95B has 92 layers → 23 full + 69 linear.
|
||||
if lower.contains("qwen3.5-") || lower.contains("qwen3.6-") || lower.contains("qwen3.8-") {
|
||||
if lower.contains("-a95b") {
|
||||
return Some(AttentionLayout {
|
||||
full: 23,
|
||||
linear: 69,
|
||||
});
|
||||
}
|
||||
if lower.contains("-a3b") || lower.contains("-a10b") || lower.contains("-a17b") {
|
||||
return Some(AttentionLayout {
|
||||
full: 10,
|
||||
|
|
@ -3231,6 +3258,19 @@ mod tests {
|
|||
assert!(layout.compressible_fraction() < 0.5);
|
||||
}
|
||||
|
||||
/// Layer counts here come from the published `config.json` for each repo:
|
||||
/// Qwen3.8-27B is 64 layers (16 full), Qwen3.8-2.4T-A95B is 92 (23 full).
|
||||
#[test]
|
||||
fn test_infer_attention_layout_qwen3_8() {
|
||||
let dense = infer_attention_layout_from_name("Qwen/Qwen3.8-27B").unwrap();
|
||||
assert_eq!(dense.full, 16);
|
||||
assert_eq!(dense.linear, 48);
|
||||
|
||||
let moe = infer_attention_layout_from_name("Qwen/Qwen3.8-2.4T-A95B").unwrap();
|
||||
assert_eq!(moe.full, 23);
|
||||
assert_eq!(moe.linear, 69);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_infer_attention_layout_dense_returns_none() {
|
||||
assert!(infer_attention_layout_from_name("meta-llama/Llama-3.1-8B").is_none());
|
||||
|
|
@ -3311,6 +3351,7 @@ mod tests {
|
|||
|
||||
// Name-only (no architecture)
|
||||
assert_eq!(parse_generation(None, "Qwen/Qwen3.6-35B-A3B"), Some(3.6));
|
||||
assert_eq!(parse_generation(None, "Qwen/Qwen3.8-27B"), Some(3.8));
|
||||
assert_eq!(parse_generation(None, "Qwen/Qwen2.5-72B"), Some(2.5));
|
||||
assert_eq!(
|
||||
parse_generation(None, "deepseek-ai/DeepSeek-V4-Flash"),
|
||||
|
|
@ -3319,6 +3360,33 @@ mod tests {
|
|||
assert_eq!(parse_generation(None, "google/gemma-3-12b-it"), Some(3.0));
|
||||
}
|
||||
|
||||
/// Qwen3.6 and Qwen3.8 both ship under the `qwen3_5` architecture string,
|
||||
/// so the minor version in the repo name has to win over the arch.
|
||||
#[test]
|
||||
fn test_parse_generation_name_beats_qwen_architecture() {
|
||||
assert_eq!(
|
||||
parse_generation(Some("qwen3_5"), "Qwen/Qwen3.8-27B"),
|
||||
Some(3.8)
|
||||
);
|
||||
assert_eq!(
|
||||
parse_generation(Some("qwen3_5_moe"), "Qwen/Qwen3.8-2.4T-A95B"),
|
||||
Some(3.8)
|
||||
);
|
||||
assert_eq!(
|
||||
parse_generation(Some("qwen3_5"), "Qwen/Qwen3.6-27B"),
|
||||
Some(3.6)
|
||||
);
|
||||
// A bare Qwen3 name must not override the more specific arch string.
|
||||
assert_eq!(
|
||||
parse_generation(Some("qwen3_next"), "Qwen/Qwen3-Next-80B-A3B"),
|
||||
Some(3.8)
|
||||
);
|
||||
assert_eq!(
|
||||
parse_generation(Some("qwen3_5"), "Qwen/Qwen3.5-27B"),
|
||||
Some(3.5)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generation_quality_bonus_values() {
|
||||
// Gen 1.0: bonus = 0
|
||||
|
|
|
|||
|
|
@ -3810,6 +3810,9 @@ const OLLAMA_MAPPINGS: &[(&str, &str)] = &[
|
|||
("qwen3.5-27b", "qwen3.5"),
|
||||
("qwen3.5-35b-a3b", "qwen3.5:35b"),
|
||||
("qwen3.5-122b-a10b", "qwen3.5:122b"),
|
||||
// Qwen 3.8 — 27B is the only size Ollama publishes; the 2.4T-A95B MoE
|
||||
// has no library entry.
|
||||
("qwen3.8-27b", "qwen3.8:27b"),
|
||||
// Qwen3-Coder-Next
|
||||
("qwen3-coder-next", "qwen3-coder-next"),
|
||||
// DeepSeek
|
||||
|
|
@ -4516,6 +4519,14 @@ mod tests {
|
|||
assert!(candidates.contains(&"qwen2.5:14b".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_qwen3_8_resolves_to_its_ollama_tag() {
|
||||
assert_eq!(
|
||||
hf_name_to_ollama_candidates("Qwen/Qwen3.8-27B"),
|
||||
vec!["qwen3.8:27b".to_string()]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_llama_mapping() {
|
||||
let candidates = hf_name_to_ollama_candidates("meta-llama/Llama-3.1-8B-Instruct");
|
||||
|
|
|
|||
|
|
@ -109,6 +109,11 @@ TARGET_MODELS = [
|
|||
"Qwen/Qwen3.6-27B",
|
||||
"Qwen/Qwen3.6-35B-A3B",
|
||||
"huihui-ai/Huihui-Qwen3.6-35B-A3B-abliterated",
|
||||
# Qwen 3.8 (hybrid attention, Aug 2026)
|
||||
"Qwen/Qwen3.8-27B",
|
||||
"Qwen/Qwen3.8-27B-FP8",
|
||||
"Qwen/Qwen3.8-2.4T-A95B",
|
||||
"Qwen/Qwen3.8-2.4T-A95B-FP8",
|
||||
# Microsoft Phi
|
||||
"microsoft/phi-3-mini-4k-instruct",
|
||||
"microsoft/Phi-3-medium-14b-instruct",
|
||||
|
|
@ -346,6 +351,8 @@ MOE_ACTIVE_PARAMS = {
|
|||
"Qwen/Qwen3.5-397B-A17B": 17_000_000_000,
|
||||
"Qwen/Qwen3.6-35B-A3B": 3_000_000_000,
|
||||
"huihui-ai/Huihui-Qwen3.6-35B-A3B-abliterated": 3_000_000_000, # Qwen3.6-35B-A3B finetune
|
||||
"Qwen/Qwen3.8-2.4T-A95B": 95_000_000_000,
|
||||
"Qwen/Qwen3.8-2.4T-A95B-FP8": 95_000_000_000,
|
||||
"meta-llama/Llama-4-Scout-17B-16E-Instruct": 17_000_000_000,
|
||||
"meta-llama/Llama-4-Maverick-17B-128E-Instruct": 17_000_000_000,
|
||||
"xai-org/grok-1": 86_000_000_000,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,23 @@ import sys
|
|||
from collections import defaultdict
|
||||
|
||||
|
||||
def qwen_minor_generation_from_name(name_lower: str) -> float | None:
|
||||
"""Mirror of models::qwen_minor_generation_from_name in Rust.
|
||||
|
||||
Only matches names carrying an explicit minor version; a bare ``Qwen3``
|
||||
returns ``None`` so callers can fall back to the architecture string.
|
||||
"""
|
||||
for dotted, underscored, generation in (
|
||||
("qwen3.8", "qwen3_8", 3.8),
|
||||
("qwen3.6", "qwen3_6", 3.6),
|
||||
("qwen3.5", "qwen3_5", 3.5),
|
||||
("qwen2.5", "qwen2_5", 2.5),
|
||||
):
|
||||
if dotted in name_lower or underscored in name_lower:
|
||||
return generation
|
||||
return None
|
||||
|
||||
|
||||
def parse_generation(architecture: str | None, name: str) -> float | None:
|
||||
"""Mirror of models::parse_generation in Rust."""
|
||||
if architecture:
|
||||
|
|
@ -30,6 +47,11 @@ def parse_generation(architecture: str | None, name: str) -> float | None:
|
|||
# Qwen
|
||||
if arch.startswith("qwen"):
|
||||
suffix = arch[len("qwen"):]
|
||||
# Qwen3.6 and Qwen3.8 ship under the `qwen3_5` architecture string,
|
||||
# so an explicit minor version in the repo name wins over the arch.
|
||||
named = qwen_minor_generation_from_name(name.lower())
|
||||
if named is not None:
|
||||
return named
|
||||
if suffix.startswith("3_5") or suffix.startswith("3.5"):
|
||||
return 3.5
|
||||
if suffix.startswith("3_next") or suffix.startswith("3next"):
|
||||
|
|
@ -99,14 +121,11 @@ def parse_generation(architecture: str | None, name: str) -> float | None:
|
|||
# Fallback: name-based
|
||||
name_lower = name.lower()
|
||||
|
||||
if "qwen3.6" in name_lower or "qwen3_6" in name_lower:
|
||||
return 3.6
|
||||
if "qwen3.5" in name_lower or "qwen3_5" in name_lower:
|
||||
return 3.5
|
||||
named = qwen_minor_generation_from_name(name_lower)
|
||||
if named is not None:
|
||||
return named
|
||||
if "qwen3" in name_lower:
|
||||
return 3.0
|
||||
if "qwen2.5" in name_lower or "qwen2_5" in name_lower:
|
||||
return 2.5
|
||||
if "qwen2" in name_lower:
|
||||
return 2.0
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue