AdrianHagen commited on
Commit
3cf4417
·
1 Parent(s): 21fb9ff

Quick update

Browse files
Dockerfile CHANGED
@@ -38,9 +38,6 @@ COPY src/ ./src/
38
  COPY app.py ./
39
  COPY config.toml ./
40
 
41
- # Copy models
42
- COPY models/ ./models/
43
-
44
  # Expose Streamlit port (Hugging Face Spaces uses 7860)
45
  EXPOSE 7860
46
 
 
38
  COPY app.py ./
39
  COPY config.toml ./
40
 
 
 
 
41
  # Expose Streamlit port (Hugging Face Spaces uses 7860)
42
  EXPOSE 7860
43
 
pyproject.toml CHANGED
@@ -23,6 +23,7 @@ dependencies = [
23
  "ipykernel>=6.30.1",
24
  "ipywidgets>=8.1.7",
25
  "matplotlib>=3.10.6",
 
26
  "mlflow>=2,<3",
27
  "numpy>=2.2.6",
28
  "pandas>=2.3.2",
 
23
  "ipykernel>=6.30.1",
24
  "ipywidgets>=8.1.7",
25
  "matplotlib>=3.10.6",
26
+ "mkdocs>=1.6.1",
27
  "mlflow>=2,<3",
28
  "numpy>=2.2.6",
29
  "pandas>=2.3.2",
src/models/prithiv_ml_food101.py CHANGED
@@ -4,7 +4,6 @@ from PIL import Image
4
  import io
5
  import os
6
  import tempfile
7
- from pathlib import Path
8
 
9
  from src.models.food_classification_model import FoodClassificationModel
10
 
@@ -20,61 +19,28 @@ class PrithivMlFood101(FoodClassificationModel):
20
 
21
  def __init__(self, model_name: str = "prithivMLmods/Food-101-93M"):
22
  """
23
- Load the PrithivML Food-101 model.
24
-
25
- Preference order:
26
- 1) Load from local repo snapshot at <repo_root>/models/prithivMLmods/Food-101-93M
27
- 2) If not present, prompt the user to download using Makefile
28
- make download-hf-model MODEL_PATH=prithivMLmods/Food-101-93M
29
  """
30
 
31
  # Set up proper cache directory for HF Spaces (safe no-op locally)
32
  if not os.environ.get("HF_HOME"):
33
- cache_dir = Path(tempfile.gettempdir()) / "transformers_cache"
34
- cache_dir.mkdir(exist_ok=True)
35
  os.environ["HF_HOME"] = str(cache_dir)
36
 
37
- # Resolve repo root robustly from this file's location
38
- repo_root = Path(__file__).resolve().parents[2]
39
- local_model_dir = repo_root / "models" / "prithivMLmods" / "Food-101-93M"
40
 
41
- # Determine whether a local copy exists (safetensors or bin)
42
- local_exists = local_model_dir.exists() and (
43
- (local_model_dir / "model.safetensors").exists()
44
- or (local_model_dir / "pytorch_model.bin").exists()
45
  )
46
-
47
- if not local_exists:
48
- # Provide a clear, actionable message to fetch the model snapshot
49
- make_cmd = "make download-hf-model MODEL_PATH=prithivMLmods/Food-101-93M"
50
- raise RuntimeError(
51
- "Local model not found at 'models/prithivMLmods/Food-101-93M'. "
52
- "Please download it first using:\n"
53
- f" {make_cmd}\n"
54
- "After download completes, re-run your program."
55
- )
56
-
57
- # Load from local directory snapshot
58
- try:
59
- self.model = SiglipForImageClassification.from_pretrained(
60
- str(local_model_dir),
61
- cache_dir=os.environ.get("HF_HOME"),
62
- local_files_only=True,
63
- force_download=False,
64
- )
65
- self.processor = AutoImageProcessor.from_pretrained(
66
- str(local_model_dir),
67
- cache_dir=os.environ.get("HF_HOME"),
68
- local_files_only=True,
69
- force_download=False,
70
- use_fast=True, # Use fast processor to avoid warning
71
- )
72
- self.model_name = str(local_model_dir)
73
- except Exception as e:
74
- raise RuntimeError(
75
- "Failed to load local model from 'models/prithivMLmods/Food-101-93M': "
76
- f"{str(e)}"
77
- )
78
 
79
  def classify(self, image: bytes) -> int:
80
  pil_image = Image.open(io.BytesIO(image)).convert("RGB")
 
4
  import io
5
  import os
6
  import tempfile
 
7
 
8
  from src.models.food_classification_model import FoodClassificationModel
9
 
 
19
 
20
  def __init__(self, model_name: str = "prithivMLmods/Food-101-93M"):
21
  """
22
+ Always load from the Hugging Face Hub. No local model storage.
 
 
 
 
 
23
  """
24
 
25
  # Set up proper cache directory for HF Spaces (safe no-op locally)
26
  if not os.environ.get("HF_HOME"):
27
+ cache_dir = tempfile.mkdtemp(prefix="transformers_cache_")
 
28
  os.environ["HF_HOME"] = str(cache_dir)
29
 
30
+ cache_dir = os.environ.get("HF_HOME")
 
 
31
 
32
+ # Load from the Hub
33
+ self.model = SiglipForImageClassification.from_pretrained(
34
+ model_name,
35
+ cache_dir=cache_dir,
36
  )
37
+ self.processor = AutoImageProcessor.from_pretrained(
38
+ model_name,
39
+ cache_dir=cache_dir,
40
+ use_fast=True,
41
+ )
42
+ self.model_name = model_name
43
+ self.model_path = model_name
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
  def classify(self, image: bytes) -> int:
46
  pil_image = Image.open(io.BytesIO(image)).convert("RGB")
src/models/resnet18.py CHANGED
@@ -3,7 +3,6 @@ from transformers import AutoImageProcessor, AutoModelForImageClassification
3
  from PIL import Image
4
  import io
5
  import os
6
- from pathlib import Path
7
 
8
  from src.models.food_classification_model import FoodClassificationModel
9
 
@@ -20,35 +19,23 @@ class Resnet18(FoodClassificationModel):
20
  model_path: str = "microsoft/resnet-18",
21
  ):
22
  """
23
- Prefer loading from a local snapshot under models/microsoft/resnet-18.
24
- If the local snapshot doesn't exist, prompt the user to download it via Makefile.
25
  """
26
 
27
- # Resolve repo root and local model dir
28
- repo_root = Path(__file__).resolve().parents[2]
29
- local_model_dir = repo_root / "models" / "microsoft" / "resnet-18"
30
 
31
- # Check if a local HF snapshot exists (config + weights)
32
- local_exists = local_model_dir.exists() and (
33
- (local_model_dir / "pytorch_model.bin").exists()
34
- or (local_model_dir / "model.safetensors").exists()
35
  )
36
-
37
- if not local_exists:
38
- make_cmd = "make download-hf-model MODEL_PATH=microsoft/resnet-18"
39
- raise RuntimeError(
40
- "Local model not found at 'models/microsoft/resnet-18'. "
41
- "Please download it first using:\n"
42
- f" {make_cmd}\n"
43
- "After download completes, re-run your program."
44
- )
45
-
46
- # Load from local folder
47
- self.image_processor = AutoImageProcessor.from_pretrained(str(local_model_dir))
48
  self.model = AutoModelForImageClassification.from_pretrained(
49
- str(local_model_dir)
50
  )
51
 
 
 
 
 
52
  def classify(self, image: bytes) -> int:
53
  pil_image = Image.open(io.BytesIO(image))
54
  inputs = self.image_processor(pil_image, return_tensors="pt")
 
3
  from PIL import Image
4
  import io
5
  import os
 
6
 
7
  from src.models.food_classification_model import FoodClassificationModel
8
 
 
19
  model_path: str = "microsoft/resnet-18",
20
  ):
21
  """
22
+ Always load from the Hugging Face Hub. No local model storage.
 
23
  """
24
 
25
+ cache_dir = os.environ.get("HF_HOME")
 
 
26
 
27
+ # Load from the Hub (will cache under HF_HOME if set)
28
+ self.image_processor = AutoImageProcessor.from_pretrained(
29
+ preprocessor_path, cache_dir=cache_dir
 
30
  )
 
 
 
 
 
 
 
 
 
 
 
 
31
  self.model = AutoModelForImageClassification.from_pretrained(
32
+ model_path, cache_dir=cache_dir
33
  )
34
 
35
+ # For metadata/logging
36
+ self.model_path = model_path
37
+ self.preprocessor_path = preprocessor_path
38
+
39
  def classify(self, image: bytes) -> int:
40
  pil_image = Image.open(io.BytesIO(image))
41
  inputs = self.image_processor(pil_image, return_tensors="pt")
src/models/vgg16.py CHANGED
@@ -4,7 +4,6 @@ import torchvision.transforms as transforms
4
  import torchvision.models as models
5
  from PIL import Image
6
  import io
7
- from pathlib import Path
8
  from typing import Dict, Any
9
  from src.models.food_classification_model import FoodClassificationModel
10
 
@@ -14,93 +13,16 @@ class VGG16(FoodClassificationModel):
14
 
15
  def __init__(self, weights: str = "IMAGENET1K_V1", num_classes: int = 101):
16
  """
17
- Initialize VGG-16. Prefer loading local fine-tuned weights if available.
18
-
19
- Priority:
20
- 1) Load ImageNet base and replace classifier, then load local fine-tuned checkpoint
21
- from <repo_root>/models/vgg16/vgg16-397923af.pth (if exists).
22
- 2) Otherwise, fall back to ImageNet weights only (not Food-101 trained), and
23
- instruct user to provide or train a .pth for Food-101 fine-tuning.
24
  """
25
- repo_root = Path(__file__).resolve().parents[2]
26
- local_weights = repo_root / "models" / "vgg16/vgg16-397923af.pth"
27
-
28
  # Base model with ImageNet weights
29
  self.model = models.vgg16(weights=weights)
30
 
31
  num_features = self.model.classifier[6].in_features
32
  self.model.classifier[6] = nn.Linear(num_features, num_classes)
33
 
34
- # If local fine-tuned weights exist, load them
35
- if local_weights.exists():
36
- try:
37
- raw_ckpt: Dict[str, Any] = torch.load(local_weights, map_location="cpu")
38
-
39
- # Unwrap common checkpoint formats
40
- if isinstance(raw_ckpt, dict) and "state_dict" in raw_ckpt:
41
- ckpt = raw_ckpt["state_dict"]
42
- else:
43
- ckpt = raw_ckpt
44
-
45
- # Normalize key prefixes commonly introduced by wrappers
46
- def strip_prefix(
47
- sd: Dict[str, torch.Tensor], prefix: str
48
- ) -> Dict[str, torch.Tensor]:
49
- if all(k.startswith(prefix) for k in sd.keys()):
50
- return {k[len(prefix) :]: v for k, v in sd.items()}
51
- return sd
52
-
53
- for p in ("module.", "model.", "net."):
54
- ckpt = strip_prefix(ckpt, p)
55
-
56
- # Filter out mismatched keys (e.g., classifier.6 for 1000->101 classes)
57
- model_sd = self.model.state_dict()
58
- filtered_ckpt = {}
59
- skipped = []
60
- for k, v in ckpt.items():
61
- if k in model_sd and isinstance(v, torch.Tensor):
62
- if model_sd[k].shape == v.shape:
63
- filtered_ckpt[k] = v
64
- else:
65
- skipped.append(
66
- (k, tuple(v.shape), tuple(model_sd[k].shape))
67
- )
68
- # Silently ignore keys not present in the current model
69
-
70
- missing_before = set(model_sd.keys()) - set(filtered_ckpt.keys())
71
- self.model.load_state_dict(filtered_ckpt, strict=False)
72
-
73
- # Optional: print a brief summary to logs for transparency
74
- if skipped:
75
- skipped_str = ", ".join(
76
- [f"{k}: {src} -> {dst}" for k, src, dst in skipped[:5]]
77
- )
78
- more = "" if len(skipped) <= 5 else f" (+{len(skipped)-5} more)"
79
- print(
80
- f"[VGG16] Partially loaded checkpoint from '{local_weights}'. "
81
- f"Skipped mismatched keys: {skipped_str}{more}"
82
- )
83
-
84
- if (
85
- "classifier.6.weight" in missing_before
86
- or "classifier.6.bias" in missing_before
87
- ):
88
- print(
89
- "[VGG16] Final classifier layer initialized for 101 classes and was not loaded from checkpoint."
90
- )
91
-
92
- except Exception as e:
93
- raise RuntimeError(
94
- f"Failed to load local VGG16 weights from '{local_weights}': {e}"
95
- )
96
- else:
97
- # No local fine-tuned weights: keep ImageNet weights but warn with action
98
- raise RuntimeError(
99
- "Local fine-tuned weights not found at 'models/vgg16/vgg16-397923af.pth'.\n"
100
- "Please place your fine-tuned checkpoint there, or train/export one.\n"
101
- "Alternatively, switch to a HF model with a Makefile download target."
102
- )
103
-
104
  self.model.eval()
105
 
106
  self.transform = transforms.Compose(
@@ -125,6 +47,6 @@ class VGG16(FoodClassificationModel):
125
 
126
  with torch.no_grad():
127
  outputs = self.model(input_batch)
128
- predicted_idx = torch.argmax(outputs).item()
129
 
130
  return predicted_idx
 
4
  import torchvision.models as models
5
  from PIL import Image
6
  import io
 
7
  from typing import Dict, Any
8
  from src.models.food_classification_model import FoodClassificationModel
9
 
 
13
 
14
  def __init__(self, weights: str = "IMAGENET1K_V1", num_classes: int = 101):
15
  """
16
+ Initialize VGG-16 strictly from torchvision weights (no local checkpoints).
17
+ Note: This will not be Food-101 fine-tuned unless you use a hub-published
18
+ VGG-16 checkpoint. Consider switching to hub-based models for best results.
 
 
 
 
19
  """
 
 
 
20
  # Base model with ImageNet weights
21
  self.model = models.vgg16(weights=weights)
22
 
23
  num_features = self.model.classifier[6].in_features
24
  self.model.classifier[6] = nn.Linear(num_features, num_classes)
25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  self.model.eval()
27
 
28
  self.transform = transforms.Compose(
 
47
 
48
  with torch.no_grad():
49
  outputs = self.model(input_batch)
50
+ predicted_idx = torch.argmax(outputs, dim=1).item()
51
 
52
  return predicted_idx
uv.lock CHANGED
@@ -1454,6 +1454,18 @@ wheels = [
1454
  { url = "https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl", hash = "sha256:53df23c8bb1651b12f095df764bfb057935d49537a56de211b098f4c79614bb0", size = 30891, upload-time = "2023-03-28T06:22:42.576Z" },
1455
  ]
1456
 
 
 
 
 
 
 
 
 
 
 
 
 
1457
  [[package]]
1458
  name = "gitdb"
1459
  version = "4.0.12"
@@ -2439,6 +2451,53 @@ wheels = [
2439
  { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
2440
  ]
2441
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2442
  [[package]]
2443
  name = "mlflow"
2444
  version = "2.22.2"
@@ -3763,6 +3822,18 @@ wheels = [
3763
  { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" },
3764
  ]
3765
 
 
 
 
 
 
 
 
 
 
 
 
 
3766
  [[package]]
3767
  name = "pyzmq"
3768
  version = "27.1.0"
@@ -4725,6 +4796,7 @@ dependencies = [
4725
  { name = "ipykernel" },
4726
  { name = "ipywidgets" },
4727
  { name = "matplotlib" },
 
4728
  { name = "mlflow" },
4729
  { name = "numpy" },
4730
  { name = "pandas" },
@@ -4758,6 +4830,7 @@ requires-dist = [
4758
  { name = "ipykernel", specifier = ">=6.30.1" },
4759
  { name = "ipywidgets", specifier = ">=8.1.7" },
4760
  { name = "matplotlib", specifier = ">=3.10.6" },
 
4761
  { name = "mlflow", specifier = ">=2,<3" },
4762
  { name = "numpy", specifier = ">=2.2.6" },
4763
  { name = "pandas", specifier = ">=2.3.2" },
@@ -5149,6 +5222,20 @@ version = "6.0.0"
5149
  source = { registry = "https://pypi.org/simple" }
5150
  sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" }
5151
  wheels = [
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5152
  { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" },
5153
  { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" },
5154
  { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" },
 
1454
  { url = "https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl", hash = "sha256:53df23c8bb1651b12f095df764bfb057935d49537a56de211b098f4c79614bb0", size = 30891, upload-time = "2023-03-28T06:22:42.576Z" },
1455
  ]
1456
 
1457
+ [[package]]
1458
+ name = "ghp-import"
1459
+ version = "2.1.0"
1460
+ source = { registry = "https://pypi.org/simple" }
1461
+ dependencies = [
1462
+ { name = "python-dateutil" },
1463
+ ]
1464
+ sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943, upload-time = "2022-05-02T15:47:16.11Z" }
1465
+ wheels = [
1466
+ { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034, upload-time = "2022-05-02T15:47:14.552Z" },
1467
+ ]
1468
+
1469
  [[package]]
1470
  name = "gitdb"
1471
  version = "4.0.12"
 
2451
  { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
2452
  ]
2453
 
2454
+ [[package]]
2455
+ name = "mergedeep"
2456
+ version = "1.3.4"
2457
+ source = { registry = "https://pypi.org/simple" }
2458
+ sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661, upload-time = "2021-02-05T18:55:30.623Z" }
2459
+ wheels = [
2460
+ { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354, upload-time = "2021-02-05T18:55:29.583Z" },
2461
+ ]
2462
+
2463
+ [[package]]
2464
+ name = "mkdocs"
2465
+ version = "1.6.1"
2466
+ source = { registry = "https://pypi.org/simple" }
2467
+ dependencies = [
2468
+ { name = "click" },
2469
+ { name = "colorama", marker = "sys_platform == 'win32'" },
2470
+ { name = "ghp-import" },
2471
+ { name = "jinja2" },
2472
+ { name = "markdown" },
2473
+ { name = "markupsafe" },
2474
+ { name = "mergedeep" },
2475
+ { name = "mkdocs-get-deps" },
2476
+ { name = "packaging" },
2477
+ { name = "pathspec" },
2478
+ { name = "pyyaml" },
2479
+ { name = "pyyaml-env-tag" },
2480
+ { name = "watchdog" },
2481
+ ]
2482
+ sdist = { url = "https://files.pythonhosted.org/packages/bc/c6/bbd4f061bd16b378247f12953ffcb04786a618ce5e904b8c5a01a0309061/mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2", size = 3889159, upload-time = "2024-08-30T12:24:06.899Z" }
2483
+ wheels = [
2484
+ { url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451, upload-time = "2024-08-30T12:24:05.054Z" },
2485
+ ]
2486
+
2487
+ [[package]]
2488
+ name = "mkdocs-get-deps"
2489
+ version = "0.2.0"
2490
+ source = { registry = "https://pypi.org/simple" }
2491
+ dependencies = [
2492
+ { name = "mergedeep" },
2493
+ { name = "platformdirs" },
2494
+ { name = "pyyaml" },
2495
+ ]
2496
+ sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239, upload-time = "2023-11-20T17:51:09.981Z" }
2497
+ wheels = [
2498
+ { url = "https://files.pythonhosted.org/packages/9f/d4/029f984e8d3f3b6b726bd33cafc473b75e9e44c0f7e80a5b29abc466bdea/mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134", size = 9521, upload-time = "2023-11-20T17:51:08.587Z" },
2499
+ ]
2500
+
2501
  [[package]]
2502
  name = "mlflow"
2503
  version = "2.22.2"
 
3822
  { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" },
3823
  ]
3824
 
3825
+ [[package]]
3826
+ name = "pyyaml-env-tag"
3827
+ version = "1.1"
3828
+ source = { registry = "https://pypi.org/simple" }
3829
+ dependencies = [
3830
+ { name = "pyyaml" },
3831
+ ]
3832
+ sdist = { url = "https://files.pythonhosted.org/packages/eb/2e/79c822141bfd05a853236b504869ebc6b70159afc570e1d5a20641782eaa/pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff", size = 5737, upload-time = "2025-05-13T15:24:01.64Z" }
3833
+ wheels = [
3834
+ { url = "https://files.pythonhosted.org/packages/04/11/432f32f8097b03e3cd5fe57e88efb685d964e2e5178a48ed61e841f7fdce/pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04", size = 4722, upload-time = "2025-05-13T15:23:59.629Z" },
3835
+ ]
3836
+
3837
  [[package]]
3838
  name = "pyzmq"
3839
  version = "27.1.0"
 
4796
  { name = "ipykernel" },
4797
  { name = "ipywidgets" },
4798
  { name = "matplotlib" },
4799
+ { name = "mkdocs" },
4800
  { name = "mlflow" },
4801
  { name = "numpy" },
4802
  { name = "pandas" },
 
4830
  { name = "ipykernel", specifier = ">=6.30.1" },
4831
  { name = "ipywidgets", specifier = ">=8.1.7" },
4832
  { name = "matplotlib", specifier = ">=3.10.6" },
4833
+ { name = "mkdocs", specifier = ">=1.6.1" },
4834
  { name = "mlflow", specifier = ">=2,<3" },
4835
  { name = "numpy", specifier = ">=2.2.6" },
4836
  { name = "pandas", specifier = ">=2.3.2" },
 
5222
  source = { registry = "https://pypi.org/simple" }
5223
  sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" }
5224
  wheels = [
5225
+ { url = "https://files.pythonhosted.org/packages/0c/56/90994d789c61df619bfc5ce2ecdabd5eeff564e1eb47512bd01b5e019569/watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26", size = 96390, upload-time = "2024-11-01T14:06:24.793Z" },
5226
+ { url = "https://files.pythonhosted.org/packages/55/46/9a67ee697342ddf3c6daa97e3a587a56d6c4052f881ed926a849fcf7371c/watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112", size = 88389, upload-time = "2024-11-01T14:06:27.112Z" },
5227
+ { url = "https://files.pythonhosted.org/packages/44/65/91b0985747c52064d8701e1075eb96f8c40a79df889e59a399453adfb882/watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3", size = 89020, upload-time = "2024-11-01T14:06:29.876Z" },
5228
+ { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393, upload-time = "2024-11-01T14:06:31.756Z" },
5229
+ { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392, upload-time = "2024-11-01T14:06:32.99Z" },
5230
+ { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019, upload-time = "2024-11-01T14:06:34.963Z" },
5231
+ { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471, upload-time = "2024-11-01T14:06:37.745Z" },
5232
+ { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449, upload-time = "2024-11-01T14:06:39.748Z" },
5233
+ { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054, upload-time = "2024-11-01T14:06:41.009Z" },
5234
+ { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" },
5235
+ { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" },
5236
+ { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" },
5237
+ { url = "https://files.pythonhosted.org/packages/30/ad/d17b5d42e28a8b91f8ed01cb949da092827afb9995d4559fd448d0472763/watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881", size = 87902, upload-time = "2024-11-01T14:06:53.119Z" },
5238
+ { url = "https://files.pythonhosted.org/packages/5c/ca/c3649991d140ff6ab67bfc85ab42b165ead119c9e12211e08089d763ece5/watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11", size = 88380, upload-time = "2024-11-01T14:06:55.19Z" },
5239
  { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" },
5240
  { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" },
5241
  { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" },