Friendlier unsupported model errors, show estimated download size
1. Backend: When a model fails with "No config file found" or similar unsupported-model errors, wrap the message with "This model is not supported yet. Try a different model." instead of showing the raw Unsloth exception. 2. Frontend: Compute estimated download size from the HF search API's safetensors.parameters dtype breakdown (BF16=2B/param, I32=4B/param, F32=4B/param, etc.) and show it in the model picker instead of just the param count. For example, Kimi-K2.5 now shows "~554 GB" instead of "171B" (which was misleading since 171B params != 171GB download).
This commit is contained in:
parent
1471c63b96
commit
f20c7ca54d
3 changed files with 41 additions and 4 deletions
|
|
@ -288,7 +288,17 @@ async def load_model(
|
|||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error loading model: {e}", exc_info = True)
|
||||
raise HTTPException(status_code = 500, detail = f"Failed to load model: {str(e)}")
|
||||
msg = str(e)
|
||||
# Surface a friendlier message for models that Unsloth cannot load
|
||||
not_supported_hints = [
|
||||
"No config file found",
|
||||
"not yet supported",
|
||||
"is not supported",
|
||||
"does not support",
|
||||
]
|
||||
if any(h.lower() in msg.lower() for h in not_supported_hints):
|
||||
msg = f"This model is not supported yet. Try a different model. (Original error: {msg})"
|
||||
raise HTTPException(status_code = 500, detail = f"Failed to load model: {msg}")
|
||||
|
||||
|
||||
@router.post("/validate", response_model = ValidateModelResponse)
|
||||
|
|
|
|||
|
|
@ -408,8 +408,13 @@ export function HubModelPicker({
|
|||
() =>
|
||||
new Map(
|
||||
results
|
||||
.filter((result) => result.totalParams)
|
||||
.map((result) => [result.id, formatCompact(result.totalParams!)]),
|
||||
.filter((result) => result.totalParams || result.estimatedSizeBytes)
|
||||
.map((result) => [
|
||||
result.id,
|
||||
result.estimatedSizeBytes
|
||||
? `~${formatBytes(result.estimatedSizeBytes)}`
|
||||
: formatCompact(result.totalParams!),
|
||||
]),
|
||||
),
|
||||
[results],
|
||||
);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ export interface HfModelResult {
|
|||
downloads: number;
|
||||
likes: number;
|
||||
totalParams?: number;
|
||||
estimatedSizeBytes?: number;
|
||||
}
|
||||
|
||||
const EXCLUDED_TAGS = new Set([
|
||||
|
|
@ -54,13 +55,33 @@ function withPopularitySort(
|
|||
return fetch(url, init);
|
||||
}
|
||||
|
||||
/** Bytes per parameter for each dtype. */
|
||||
const DTYPE_BYTES: Record<string, number> = {
|
||||
F64: 8, F32: 4, F16: 2, BF16: 2,
|
||||
I64: 8, I32: 4, I16: 2, I8: 1, U8: 1,
|
||||
// Quantized types (4-bit)
|
||||
NF4: 0.5, FP4: 0.5, INT4: 0.5, GPTQ: 0.5,
|
||||
};
|
||||
|
||||
function estimateSizeFromDtypes(
|
||||
params: Record<string, number> | undefined,
|
||||
): number | undefined {
|
||||
if (!params) return undefined;
|
||||
let total = 0;
|
||||
for (const [dtype, count] of Object.entries(params)) {
|
||||
const bpp = DTYPE_BYTES[dtype.toUpperCase()] ?? 2; // default BF16
|
||||
total += count * bpp;
|
||||
}
|
||||
return total > 0 ? total : undefined;
|
||||
}
|
||||
|
||||
function makeMapModel(excludeGguf: boolean) {
|
||||
return (raw: unknown): HfModelResult | null => {
|
||||
const m = raw as {
|
||||
name: string;
|
||||
downloads: number;
|
||||
likes: number;
|
||||
safetensors?: { total: number };
|
||||
safetensors?: { total: number; parameters?: Record<string, number> };
|
||||
tags?: string[];
|
||||
};
|
||||
const isEmbedding = m.tags?.some((t) => EMBEDDING_TAGS.has(t));
|
||||
|
|
@ -75,6 +96,7 @@ function makeMapModel(excludeGguf: boolean) {
|
|||
downloads: m.downloads,
|
||||
likes: m.likes,
|
||||
totalParams: m.safetensors?.total,
|
||||
estimatedSizeBytes: estimateSizeFromDtypes(m.safetensors?.parameters),
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue