From 701130f400eef560d71c3501fffcd78fae49b751 Mon Sep 17 00:00:00 2001 From: bluelovers Date: Sat, 25 Apr 2026 22:10:18 +0800 Subject: [PATCH] refactor(utils): Improve formatModelName logic to handle complex model IDs. ``` import { formatModelName } from "../src/utils/format-model-name"; let ret: string; [ 'qwen/qwen3-30b-a3b', 'ollama/gemma4/gemma4-8.0b-q4_k_m.gguf', 'ollama/gemma4/gemma4-8.0b-q4_k_m.gguf', 'ollama/gemma4/gemma4-8.0b-q4_k_m_7.0a', 'ollama/gemma4/gemma4-8.0b-q4_k_m_7.0', 'qwen3.6-35b-a3b-uncensored-hauhaucs-aggressive', 'nvidia/nemotron-3-nano-4b', 'google/gemma-4-e4b', ].forEach(id => { ret = formatModelName({ id } as any); console.dir(ret); }); ``` --- src/utils/format-model-name.ts | 57 +++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/src/utils/format-model-name.ts b/src/utils/format-model-name.ts index bd8a832..8c21aed 100644 --- a/src/utils/format-model-name.ts +++ b/src/utils/format-model-name.ts @@ -1,3 +1,4 @@ +import { parse } from 'path' import type { LMStudioModel } from '../types' /** @@ -16,27 +17,61 @@ export function extractModelOwner(modelId: string): string | undefined { * Creates readable titles like "Qwen3 30B A3B" instead of "qwen/qwen3-30b-a3b" */ export function formatModelName(model: LMStudioModel): string { - const { id } = model - // Extract parts from model ID - const parts = id.split('/') - const modelPart = parts.length > 1 ? parts[1] : parts[0] - + const parts = model.id.split('/') + let modelPart: string[]; + + // Support 'google/gemma-4-e4b' , 'ollama/gemma4/gemma4-8.0b-q4_k_m.gguf' + if (parts.length > 2) { + modelPart = (parts.length > 2 ? parts.slice(1) : parts) + } else { + modelPart = parts + } + + modelPart = modelPart + .flatMap(part => { + return part.split(/[-_]/) + }) + ; + + const parsed = parse(modelPart[modelPart.length - 1]) + + if (parsed.ext) { + let m = parsed.ext.match(/^(\.\d+)([^\d].*)?$/) + if (!m) { + // Support 'ollama/gemma4/gemma4-8.0b-q4_k_m.gguf' + modelPart[modelPart.length - 1] = parsed.name + modelPart.push(parsed.ext) + } + } + + modelPart = modelPart + .filter((part, index, parts) => { + part = part.trim().toLowerCase() + let next = parts[index + 1]?.trim().toLowerCase() + + // Support 'qwen/qwen3-30b-a3b' + if (next?.startsWith(part)) { + return false + } + + return Boolean(part) + }) + ; + // Common acronyms that should be uppercase const acronyms = new Set(['gpt', 'oss', 'api', 'gguf', 'ggml', 'nomic', 'vl', 'it', 'mlx']) - + // Split by common separators and format const tokens = modelPart - .split(/[-_]/) - .filter(Boolean) .map(token => { const lowerToken = token.toLowerCase() - + // Handle common acronyms if (acronyms.has(lowerToken)) { return token.toUpperCase() } - + // Handle version numbers and sizes (e.g., "30b", "3.2", "a3b", "q4", "q8") if (/^\d+[bkmg]$/i.test(token)) { return token.toUpperCase() @@ -57,7 +92,7 @@ export function formatModelName(model: LMStudioModel): string { return token.charAt(0).toUpperCase() + token.slice(1).toLowerCase() }) .join(' ') - + return tokens }