File size: 2,932 Bytes
178c53e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fdbda9e
178c53e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import pandas as pd
from datetime import datetime
from huggingface_hub.hf_api import ModelInfo

# constant mapping for precision normalization
PRECISION_MAP = {
    "torch.float16": "float16", "float16": "float16", "fp16": "float16",
    "torch.float32": "float32", "float32": "float32", "fp32": "float32",
    "torch.bfloat16": "bfloat16", "bfloat16": "bfloat16", "bf16": "bfloat16",
    "8bit": "8bit",
    "4bit": "4bit"
}

def unify_precision(raw_precision: str) -> str:
    """
    Map raw precision strings to canonical forms.
    """
    if not raw_precision:
        return "Missing"
    
    clean_p = raw_precision.strip().lower()
    
    if clean_p in ["missing", "unk", "none"]:
        return "Missing"
        
    return PRECISION_MAP.get(clean_p, "Missing")

def get_model_size(model_info: ModelInfo) -> float:
    """
    Return approximate model parameter size in billions.
    """
    try:
        # Safely access safetensors, defaulting to None if attribute missing
        safetensors = getattr(model_info, "safetensors", None)
        total_bytes = safetensors.get("total", 0) if safetensors else 0
        model_size = round(total_bytes / 1e9, 3)
    except (AttributeError, TypeError):
        return 0.0

    # Specific logic for GPTQ models
    if model_info.modelId and "gptq" in model_info.modelId.lower():
        return model_size * 8
        
    return model_size

def parse_datetime(dt_str: str) -> datetime:
    """
    Safely parse an ISO datetime string into a Python datetime object.
    """
    try:
        # Remove Z for compatibility with older fromisoformat versions
        return datetime.fromisoformat(dt_str.replace("Z", ""))
    except (ValueError, TypeError):
        return datetime.min

def fix_df_for_display(df: pd.DataFrame) -> pd.DataFrame:
    """
    Converts list columns to strings for st.dataframe compatibility.
    """
    if df.empty:
        return df

    target_cols = ["license", "model_type"]
    
    for col in target_cols:
        if col in df.columns:
            df[col] = df[col].apply(
                lambda x: ", ".join(x) if isinstance(x, list) else str(x)
            )
            
    return df

# --- Helper: Filter Options Generator ---
def get_filter_options(df, column):
    if df.empty:
        return ["Missing"]
    opts = sorted(df[column].dropna().unique().tolist())
    if "Missing" not in opts:
        opts.append("Missing")
    return opts

# Helper for Categorical Filters (Handles 'Missing')
def apply_cat_filter(df_in, col_name, selected_opts):
    if not selected_opts:
        return df_in
    if "Missing" in selected_opts:
        # Valid matches OR Nulls OR "Missing" string
        return df_in[
            df_in[col_name].isin(selected_opts) | 
            df_in[col_name].isna() | 
            (df_in[col_name] == "Missing") |
            (df_in[col_name] == "")
        ]
    return df_in[df_in[col_name].isin(selected_opts)]