feat(tui): deduplicate model metadata and populate model details cache from session

- Add `seen_meta` set and `push_meta` helper to avoid duplicate entries when building model metadata strings.
- Extend metadata handling to include context length fallback, architecture/family information, embedding length, size formatting, and quantization details.
- Introduce `populate_model_details_cache_from_session` to load model details from the controller, with a fallback to cached details.
- Update `refresh_models` to use the new cache‑population method instead of manually clearing the cache.
This commit is contained in:
2025-10-13 23:36:26 +02:00
parent 44a00619b5
commit 990f93d467
2 changed files with 71 additions and 8 deletions

View File

@@ -2832,22 +2832,64 @@ fn build_model_selector_label(
}
let mut meta_parts: Vec<String> = Vec::new();
let mut seen_meta: HashSet<String> = HashSet::new();
let mut push_meta = |value: String| {
let trimmed = value.trim();
if trimmed.is_empty() {
return;
}
let key = trimmed.to_ascii_lowercase();
if seen_meta.insert(key) {
meta_parts.push(trimmed.to_string());
}
};
if let Some(detail) = detail {
if let Some(ctx) = detail.context_length {
push_meta(format!("max tokens {}", ctx));
} else if let Some(ctx) = model.context_window {
push_meta(format!("max tokens {}", ctx));
}
if let Some(parameters) = detail
.parameter_size
.as_ref()
.or(detail.parameters.as_ref())
&& !parameters.trim().is_empty()
{
meta_parts.push(parameters.trim().to_string());
push_meta(parameters.trim().to_string());
}
if let Some(arch) = detail.architecture.as_deref() {
let trimmed = arch.trim();
if !trimmed.is_empty() {
push_meta(format!("arch {}", trimmed));
}
} else if let Some(family) = detail.family.as_deref() {
let trimmed = family.trim();
if !trimmed.is_empty() {
push_meta(format!("family {}", trimmed));
}
} else if !detail.families.is_empty() {
let families = detail
.families
.iter()
.map(|f| f.trim())
.filter(|f| !f.is_empty())
.take(2)
.collect::<Vec<_>>()
.join("/");
if !families.is_empty() {
push_meta(format!("family {}", families));
}
}
if let Some(embedding) = detail.embedding_length {
push_meta(format!("embedding {}", embedding));
}
if let Some(size) = detail.size {
meta_parts.push(format_short_size(size));
}
if let Some(ctx) = detail.context_length {
meta_parts.push(format!("ctx {}", ctx));
push_meta(format_short_size(size));
}
if let Some(quant) = detail
@@ -2855,8 +2897,10 @@ fn build_model_selector_label(
.as_ref()
.filter(|q| !q.trim().is_empty())
{
meta_parts.push(quant.trim().to_string());
push_meta(format!("quant {}", quant.trim()));
}
} else if let Some(ctx) = model.context_window {
push_meta(format!("max tokens {}", ctx));
}
if let Some(desc) = model.description.as_deref() {