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:
@@ -7257,6 +7257,25 @@ impl ChatApp {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn populate_model_details_cache_from_session(&mut self) {
|
||||||
|
self.model_details_cache.clear();
|
||||||
|
|
||||||
|
let mut populated = false;
|
||||||
|
if let Ok(details) = self.controller.all_model_details(false).await {
|
||||||
|
for info in details {
|
||||||
|
self.model_details_cache.insert(info.name.clone(), info);
|
||||||
|
}
|
||||||
|
populated = !self.model_details_cache.is_empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
if !populated {
|
||||||
|
let cached = self.controller.cached_model_details().await;
|
||||||
|
for info in cached {
|
||||||
|
self.model_details_cache.insert(info.name.clone(), info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn refresh_models(&mut self) -> Result<()> {
|
async fn refresh_models(&mut self) -> Result<()> {
|
||||||
let config_model_name = self.controller.config().general.default_model.clone();
|
let config_model_name = self.controller.config().general.default_model.clone();
|
||||||
let config_model_provider = self.controller.config().general.default_provider.clone();
|
let config_model_provider = self.controller.config().general.default_provider.clone();
|
||||||
@@ -7286,9 +7305,9 @@ impl ChatApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.models = all_models;
|
self.models = all_models;
|
||||||
self.model_details_cache.clear();
|
|
||||||
self.model_info_panel.clear();
|
self.model_info_panel.clear();
|
||||||
self.set_model_info_visible(false);
|
self.set_model_info_visible(false);
|
||||||
|
self.populate_model_details_cache_from_session().await;
|
||||||
|
|
||||||
self.recompute_available_providers();
|
self.recompute_available_providers();
|
||||||
|
|
||||||
|
|||||||
@@ -2832,22 +2832,64 @@ fn build_model_selector_label(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut meta_parts: Vec<String> = Vec::new();
|
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(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
|
if let Some(parameters) = detail
|
||||||
.parameter_size
|
.parameter_size
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.or(detail.parameters.as_ref())
|
.or(detail.parameters.as_ref())
|
||||||
&& !parameters.trim().is_empty()
|
&& !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 {
|
if let Some(size) = detail.size {
|
||||||
meta_parts.push(format_short_size(size));
|
push_meta(format_short_size(size));
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(ctx) = detail.context_length {
|
|
||||||
meta_parts.push(format!("ctx {}", ctx));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(quant) = detail
|
if let Some(quant) = detail
|
||||||
@@ -2855,8 +2897,10 @@ fn build_model_selector_label(
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.filter(|q| !q.trim().is_empty())
|
.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() {
|
if let Some(desc) = model.description.as_deref() {
|
||||||
|
|||||||
Reference in New Issue
Block a user