Coverage for src / lilbee / model_info.py: 100%

54 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-04-29 19:16 +0000

1"""Public API for reading model architecture metadata from GGUF files.""" 

2 

3from __future__ import annotations 

4 

5import logging 

6from dataclasses import dataclass 

7 

8from lilbee.config import cfg 

9 

10log = logging.getLogger(__name__) 

11 

12 

13@dataclass 

14class ModelArchInfo: 

15 """Architecture metadata for installed models.""" 

16 

17 chat_arch: str = "unknown" 

18 embed_arch: str = "unknown" 

19 vision_projector: str = "unknown" 

20 active_handler: str = "not loaded" 

21 

22 

23def get_model_architecture() -> ModelArchInfo: 

24 """Return architecture metadata for the currently configured models. 

25 Reads GGUF headers for chat, embedding, and (optionally) vision models. 

26 Falls back gracefully if llama-cpp-python is not installed or models 

27 are not available. 

28 """ 

29 info = ModelArchInfo() 

30 try: 

31 import lilbee.providers.llama_cpp_provider # noqa: F401 

32 

33 info = _read_chat_arch(info) 

34 info = _read_embed_arch(info) 

35 info = _read_vision_arch(info) 

36 except ImportError: 

37 pass 

38 return info 

39 

40 

41def _read_chat_arch(info: ModelArchInfo) -> ModelArchInfo: 

42 """Read chat model architecture from GGUF metadata.""" 

43 try: 

44 from lilbee.providers.llama_cpp_provider import read_gguf_metadata, resolve_model_path 

45 

46 path = resolve_model_path(cfg.chat_model) 

47 meta = read_gguf_metadata(path) 

48 if meta: 

49 info.chat_arch = meta.get("architecture", "unknown") 

50 info.active_handler = "llama-cpp" 

51 except Exception: 

52 log.debug("Failed to read chat model architecture", exc_info=True) 

53 return info 

54 

55 

56def _read_embed_arch(info: ModelArchInfo) -> ModelArchInfo: 

57 """Read embedding model architecture from GGUF metadata.""" 

58 try: 

59 from lilbee.providers.llama_cpp_provider import read_gguf_metadata, resolve_model_path 

60 

61 path = resolve_model_path(cfg.embedding_model) 

62 meta = read_gguf_metadata(path) 

63 if meta: 

64 info.embed_arch = meta.get("architecture", "unknown") 

65 except Exception: 

66 log.debug("Failed to read embedding model architecture", exc_info=True) 

67 return info 

68 

69 

70def _read_vision_arch(info: ModelArchInfo) -> ModelArchInfo: 

71 """Read vision projector type from GGUF metadata for ``cfg.vision_model``. 

72 

73 Reads the vision model name from the global ``cfg`` singleton (same 

74 pattern as :func:`_read_chat_arch` / :func:`_read_embed_arch`) rather 

75 than taking it as a parameter. The chat model is never inspected for 

76 vision capability here: role separation is explicit. Returns the 

77 input unchanged when no vision model is configured. 

78 """ 

79 if not cfg.vision_model: 

80 return info 

81 try: 

82 from lilbee.providers.llama_cpp_provider import ( 

83 find_mmproj_for_model, 

84 read_mmproj_projector_type, 

85 resolve_model_path, 

86 ) 

87 

88 path = resolve_model_path(cfg.vision_model) 

89 mmproj = find_mmproj_for_model(path) 

90 proj_type = read_mmproj_projector_type(mmproj) 

91 info.vision_projector = proj_type or "unknown" 

92 except Exception: 

93 log.debug("Failed to read vision projector type", exc_info=True) 

94 return info