Coverage for src / lilbee / catalog / models.py: 100%

57 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-05-15 20:55 +0000

1"""Catalog dataclasses and pydantic types: leaf module, no sibling imports.""" 

2 

3from dataclasses import dataclass 

4 

5from pydantic import BaseModel 

6 

7from lilbee.catalog.types import ModelTask 

8 

9 

10class HfGgufMeta(BaseModel): 

11 """GGUF metadata returned by the HF API when expand=gguf is requested. 

12 

13 ModelInfo.gguf is typed as ``dict | None`` upstream, so we validate it ourselves. 

14 """ 

15 

16 total: int = 0 

17 architecture: str = "" 

18 context_length: int = 0 

19 

20 

21@dataclass 

22class DownloadProgress: 

23 """Human-readable snapshot of download progress. 

24 

25 ``percent`` is a float (0.0 to 100.0) so the ProgressBar renders smooth 

26 fractional movement during multi-GB downloads. Call sites that need 

27 an integer for display format it themselves. 

28 """ 

29 

30 percent: float 

31 detail: str 

32 is_cache_hit: bool 

33 

34 

35@dataclass(frozen=True) 

36class CatalogModel: 

37 """One catalog entry, keyed by HuggingFace repo. ``gguf_filename`` may be a glob.""" 

38 

39 hf_repo: str 

40 gguf_filename: str 

41 size_gb: float 

42 min_ram_gb: float 

43 description: str 

44 featured: bool 

45 downloads: int 

46 task: ModelTask 

47 recommended: bool = False 

48 

49 @property 

50 def ref(self) -> str: 

51 """Browse-time ref (the HF repo); concrete filename is resolved at install.""" 

52 return self.hf_repo 

53 

54 @property 

55 def display_name(self) -> str: 

56 """Human-readable label derived from the HuggingFace repo id.""" 

57 # Local import keeps models.py a leaf (no sibling imports at module top). 

58 from lilbee.catalog.formatting import clean_display_name 

59 

60 return clean_display_name(self.hf_repo) 

61 

62 

63@dataclass(frozen=True) 

64class CatalogResult: 

65 """Paginated catalog result.""" 

66 

67 total: int 

68 limit: int 

69 offset: int 

70 models: list[CatalogModel] 

71 has_more: bool = False 

72 

73 

74@dataclass(frozen=True) 

75class HfPage: 

76 """One page of HuggingFace API results.""" 

77 

78 models: list[CatalogModel] 

79 has_more: bool 

80 

81 

82@dataclass(frozen=True) 

83class ModelVariant: 

84 """One quantization within a model family. ``filename`` may be a glob.""" 

85 

86 hf_repo: str 

87 filename: str 

88 param_count: str 

89 quant: str 

90 size_mb: int 

91 recommended: bool 

92 mmproj_filename: str = "" 

93 

94 

95@dataclass(frozen=True) 

96class ModelFamily: 

97 """A group of related model variants (e.g. Qwen3 in multiple sizes).""" 

98 

99 slug: str # family slug for building refs: "qwen3" 

100 name: str # display name: "Qwen3" 

101 task: ModelTask 

102 description: str 

103 variants: tuple[ModelVariant, ...]