DeepFabric 4.8.0__py3-none-any.whl → 4.8.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,13 +2,13 @@ import json
2
2
  import logging
3
3
  import sys
4
4
 
5
+ from functools import cached_property
5
6
  from typing import Any
6
7
 
7
- import torch
8
-
9
8
  from transformers import AutoConfig, AutoModelForCausalLM, AutoTokenizer
10
9
 
11
10
  from ...schemas import ToolDefinition
11
+ from ...utils import import_optional_dependency
12
12
  from ..inference import InferenceBackend, InferenceConfig, ModelResponse
13
13
  from .tool_call_parsers import ToolCallParser, get_parser
14
14
 
@@ -29,6 +29,30 @@ logger = logging.getLogger(__name__)
29
29
  class TransformersBackend(InferenceBackend):
30
30
  """Inference backend using HuggingFace Transformers."""
31
31
 
32
+ @cached_property
33
+ def _torch(self) -> Any:
34
+ """Dynamically import 'torch' and verify its availability.
35
+
36
+ Returns:
37
+ The imported torch module.
38
+
39
+ Raises:
40
+ ModuleNotFoundError: If 'torch' is not installed in the environment.
41
+ """
42
+ return import_optional_dependency("torch", "training")
43
+
44
+ @cached_property
45
+ def _peft(self) -> Any:
46
+ """Dynamically import 'peft' and verify its availability.
47
+
48
+ Returns:
49
+ The imported peft module.
50
+
51
+ Raises:
52
+ ModuleNotFoundError: If 'peft' is not installed in the environment.
53
+ """
54
+ return import_optional_dependency("peft", "training")
55
+
32
56
  def __init__(self, config: InferenceConfig):
33
57
  """Initialize Transformers backend.
34
58
 
@@ -47,22 +71,22 @@ class TransformersBackend(InferenceBackend):
47
71
  # Get device from pre-loaded model
48
72
  self.device = str(next(config.model.parameters()).device)
49
73
  # Auto-detect best available device
50
- elif torch.cuda.is_available():
74
+ elif self._torch.cuda.is_available():
51
75
  self.device = "cuda"
52
- elif torch.backends.mps.is_available():
76
+ elif self._torch.backends.mps.is_available():
53
77
  self.device = "mps"
54
78
  else:
55
79
  self.device = "cpu"
56
80
 
57
81
  # Determine dtype based on device
58
82
  if self.device == "cuda" or self.device.startswith("cuda:"):
59
- dtype = torch.float16
83
+ dtype = self._torch.float16
60
84
  device_map = "auto"
61
85
  elif self.device == "mps":
62
- dtype = torch.float32 # MPS works best with float32
86
+ dtype = self._torch.float32 # MPS works best with float32
63
87
  device_map = None
64
88
  else:
65
- dtype = torch.float32
89
+ dtype = self._torch.float32
66
90
  device_map = None
67
91
 
68
92
  # Handle pre-loaded model case - skip all loading logic
@@ -138,9 +162,9 @@ class TransformersBackend(InferenceBackend):
138
162
  load_in_4bit=config.load_in_4bit,
139
163
  )
140
164
  # Load LoRA adapter using PEFT
141
- from peft import PeftModel # noqa: PLC0415
142
-
143
- self.model = PeftModel.from_pretrained(self.model, config.adapter_path)
165
+ self.model = self._peft.PeftModel.from_pretrained(
166
+ self.model, config.adapter_path
167
+ )
144
168
  else:
145
169
  # Load merged model or base model directly
146
170
  self.model, self.tokenizer = FastLanguageModel.from_pretrained(
@@ -172,9 +196,7 @@ class TransformersBackend(InferenceBackend):
172
196
 
173
197
  # Load PEFT adapter if provided
174
198
  if config.adapter_path:
175
- from peft import PeftModel # noqa: PLC0415
176
-
177
- self.model = PeftModel.from_pretrained(self.model, config.adapter_path)
199
+ self.model = self._peft.PeftModel.from_pretrained(self.model, config.adapter_path)
178
200
 
179
201
  # Move to device if not using device_map
180
202
  if self.device in ("cpu", "mps"):
@@ -217,7 +239,7 @@ class TransformersBackend(InferenceBackend):
217
239
  ).to(self.model.device)
218
240
 
219
241
  # Generate with optimizations
220
- with torch.no_grad():
242
+ with self._torch.no_grad():
221
243
  outputs = self.model.generate(
222
244
  **inputs,
223
245
  max_new_tokens=self.config.max_tokens,
@@ -273,7 +295,7 @@ class TransformersBackend(InferenceBackend):
273
295
  ).to(self.model.device)
274
296
 
275
297
  # Generate batch with optimizations
276
- with torch.no_grad():
298
+ with self._torch.no_grad():
277
299
  outputs = self.model.generate(
278
300
  **inputs,
279
301
  max_new_tokens=self.config.max_tokens,
@@ -316,8 +338,8 @@ class TransformersBackend(InferenceBackend):
316
338
  del self.model
317
339
  if hasattr(self, "tokenizer"):
318
340
  del self.tokenizer
319
- if torch.cuda.is_available():
320
- torch.cuda.empty_cache()
341
+ if self._torch.cuda.is_available():
342
+ self._torch.cuda.empty_cache()
321
343
 
322
344
  def _format_prompt(
323
345
  self,
@@ -24,6 +24,25 @@ from .reporters import BaseReporter, CloudReporter, FileReporter, MultiReporter
24
24
 
25
25
  console = Console()
26
26
 
27
+ # Mapping for legacy conversation_type values
28
+ _CONVERSATION_TYPE_ALIASES = {
29
+ "chain_of_thought": "cot",
30
+ }
31
+
32
+
33
+ def _normalize_conversation_type(value: str) -> str:
34
+ """Normalize conversation_type to valid values.
35
+
36
+ Handles legacy values like 'chain_of_thought' -> 'cot'.
37
+
38
+ Args:
39
+ value: Raw conversation_type value from dataset
40
+
41
+ Returns:
42
+ Normalized value ('basic' or 'cot')
43
+ """
44
+ return _CONVERSATION_TYPE_ALIASES.get(value, value)
45
+
27
46
 
28
47
  class EvaluatorConfig(BaseModel):
29
48
  """Configuration for evaluation run."""
@@ -247,9 +266,10 @@ class Evaluator:
247
266
  # Convert sample dict to Conversation object
248
267
  conversation = Conversation.model_validate(sample)
249
268
 
250
- # Determine conversation type from metadata
269
+ # Determine conversation type from metadata (normalize legacy values)
251
270
  metadata = conversation.metadata or {}
252
- conv_type = metadata.get("conversation_type", "basic")
271
+ raw_conv_type = metadata.get("conversation_type", "basic")
272
+ conv_type = _normalize_conversation_type(raw_conv_type)
253
273
  reasoning_style = metadata.get("reasoning_style")
254
274
  agent_mode = metadata.get("agent_mode")
255
275
 
deepfabric/schemas.py CHANGED
@@ -136,7 +136,7 @@ class MCPInputSchemaProperty(BaseModel):
136
136
 
137
137
  model_config = {"extra": "allow"}
138
138
 
139
- type: str = Field(default="string", description="JSON Schema type")
139
+ type: str | list[str] = Field(default="string", description="JSON Schema type (string or array for nullable)")
140
140
  description: str = Field(default="", description="Property description")
141
141
  default: Any | None = Field(default=None, description="Default value")
142
142
 
@@ -159,7 +159,7 @@ class MCPToolDefinition(BaseModel):
159
159
  See: https://modelcontextprotocol.io/specification/2025-06-18/schema#tool
160
160
  """
161
161
 
162
- model_config = {"extra": "allow"}
162
+ model_config = {"extra": "allow", "populate_by_name": True}
163
163
 
164
164
  name: str = Field(description="Tool name")
165
165
  description: str = Field(default="", description="Tool description")
@@ -367,7 +367,15 @@ class ToolDefinition(BaseModel):
367
367
  required_params = set(input_schema.required)
368
368
 
369
369
  for param_name, param_props in input_schema.properties.items():
370
- df_type = type_mapping.get(param_props.type, "str")
370
+ # Handle type as either string or array (for nullable types like ["string", "null"])
371
+ param_type = param_props.type
372
+ if isinstance(param_type, list):
373
+ # Extract the primary type (non-null type from array)
374
+ primary_type = next((t for t in param_type if t != "null"), "string")
375
+ else:
376
+ primary_type = param_type
377
+
378
+ df_type = type_mapping.get(primary_type, "str")
371
379
  default_str = str(param_props.default) if param_props.default is not None else ""
372
380
 
373
381
  parameters.append(
@@ -298,9 +298,10 @@ class DeepFabricCallback:
298
298
  Returns:
299
299
  Model name or None
300
300
  """
301
- # Try args first
302
- if hasattr(args, "model_name_or_path"):
303
- return args.model_name_or_path
301
+ # Try args first (model_name_or_path exists on SFTConfig and similar subclasses)
302
+ model_name_or_path = getattr(args, "model_name_or_path", None)
303
+ if model_name_or_path is not None:
304
+ return model_name_or_path
304
305
 
305
306
  # Try model config
306
307
  if model is not None:
@@ -310,8 +311,9 @@ class DeepFabricCallback:
310
311
  return model.name_or_path
311
312
 
312
313
  # Try output_dir as fallback
313
- if hasattr(args, "output_dir"):
314
- return os.path.basename(args.output_dir)
314
+ output_dir = getattr(args, "output_dir", None)
315
+ if output_dir is not None:
316
+ return os.path.basename(output_dir)
315
317
 
316
318
  return None
317
319
 
deepfabric/utils.py CHANGED
@@ -1,9 +1,12 @@
1
1
  import ast
2
2
  import asyncio
3
+ import importlib
3
4
  import json
4
5
  import os
5
6
  import re
6
7
 
8
+ from typing import Any
9
+
7
10
  VALIDATION_ERROR_INDICATORS = [
8
11
  "validation error",
9
12
  "value error",
@@ -162,3 +165,33 @@ def get_bool_env(key: str, default: bool = False) -> bool:
162
165
  if val is None:
163
166
  return default
164
167
  return val.lower() in ("1", "true", "yes", "on")
168
+
169
+
170
+ def import_optional_dependency(
171
+ module_name: str,
172
+ extra: str | None = None,
173
+ ) -> Any:
174
+ """
175
+ Import an optional dependency at runtime.
176
+
177
+ Args:
178
+ module_name (str): The name of the module to import.
179
+ extra (str | None): The optional dependency group providing this module.
180
+
181
+ Returns:
182
+ Any: The imported module.
183
+
184
+ Raises:
185
+ ModuleNotFoundError: If the module is not installed.
186
+ """
187
+ try:
188
+ return importlib.import_module(module_name)
189
+ except ModuleNotFoundError:
190
+ if extra:
191
+ msg = (
192
+ f"The '{module_name}' library is required for the '{extra}' features. "
193
+ f"Please install it using: pip install 'deepfabric[{extra}]'"
194
+ )
195
+ else:
196
+ msg = f"The '{module_name}' library is required but is not installed."
197
+ raise ModuleNotFoundError(msg) from None
@@ -1,11 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: DeepFabric
3
- Version: 4.8.0
3
+ Version: 4.8.2
4
4
  Summary: Curate High Quality Datasets, Train, Evaluate and Ship
5
5
  Author-email: DeepFabric Team <oss@alwaysfurther.ai>
6
6
  License-File: LICENSE
7
7
  Requires-Python: >=3.10
8
- Requires-Dist: accelerate>=0.20.0
9
8
  Requires-Dist: anthropic>=0.75.0
10
9
  Requires-Dist: click>=8.1.7
11
10
  Requires-Dist: componentize-py>=0.19.3
@@ -19,7 +18,6 @@ Requires-Dist: ollama>=0.6.1
19
18
  Requires-Dist: openai>=1.107.2
20
19
  Requires-Dist: outlines==1.2.9
21
20
  Requires-Dist: packaging>=25.0
22
- Requires-Dist: peft>=0.7.0
23
21
  Requires-Dist: posthog>=3.0.0
24
22
  Requires-Dist: protobuf>=3.20.0
25
23
  Requires-Dist: pydantic>=2.0.0
@@ -27,9 +25,7 @@ Requires-Dist: pyyaml>=6.0.1
27
25
  Requires-Dist: rich>=13.0.0
28
26
  Requires-Dist: sentencepiece>=0.1.99
29
27
  Requires-Dist: spin-sdk>=3.4.1
30
- Requires-Dist: torch>=2.4.0
31
28
  Requires-Dist: transformers>=4.57.1
32
- Requires-Dist: trl>=0.26.2
33
29
  Provides-Extra: dev
34
30
  Requires-Dist: bandit>=1.7.10; extra == 'dev'
35
31
  Requires-Dist: mermaid-py>=0.2.0; extra == 'dev'
@@ -42,6 +38,11 @@ Requires-Dist: ruff>=0.1.0; extra == 'dev'
42
38
  Provides-Extra: docs
43
39
  Requires-Dist: mkdocs-material>=9.0.0; extra == 'docs'
44
40
  Requires-Dist: mkdocstrings[python]>=0.30.0; extra == 'docs'
41
+ Provides-Extra: training
42
+ Requires-Dist: accelerate>=0.20.0; extra == 'training'
43
+ Requires-Dist: peft>=0.7.0; extra == 'training'
44
+ Requires-Dist: torch>=2.4.0; extra == 'training'
45
+ Requires-Dist: trl>=0.26.2; extra == 'training'
45
46
  Description-Content-Type: text/markdown
46
47
 
47
48
  <div align="center">
@@ -21,17 +21,17 @@ deepfabric/loader.py,sha256=YNTGZZE-POjR0BIlx6WCT4bIzf0T4lW_fQl7ev9UFqE,18584
21
21
  deepfabric/metrics.py,sha256=iwtNHBX4ZTYUg2FZgtFcG3U0e9RlV2c1cm1Kp34FeWU,6129
22
22
  deepfabric/progress.py,sha256=3XQQrf2pUZlyd-8eRcNATH1v0Oi8JMedVHGbhPcca-8,9354
23
23
  deepfabric/prompts.py,sha256=JVFMeeBa2qqOMvmP_xx8bWzZ6ot9eyqOP3u8XzzPx3g,10290
24
- deepfabric/schemas.py,sha256=ckzAjDc6IlC8Y-Pi2hyYRqcSwARX7z_GELuCypXuSgI,37401
24
+ deepfabric/schemas.py,sha256=r8qQuu19o9ev0JNxcChjbpWym9m5WLItyxw8szYLSjI,37867
25
25
  deepfabric/stream_simulator.py,sha256=GzvAxWxHVsuTwgXlqwXNfrTUDn6sND2kJOoQuYg88FA,3028
26
26
  deepfabric/topic_manager.py,sha256=6YxMO6dQHaGyxghsI8iNJGP1miaekBe5Mh1WdYeLqdI,11164
27
27
  deepfabric/topic_model.py,sha256=i_wYpw2kUl8NLodOSaqNu-C4_d6caYT1kPe_vkKjoyw,707
28
28
  deepfabric/tree.py,sha256=Kxl2iLHU55xPq2MwdoLM0-M2nZRx51bRj9FM36jqs-M,14933
29
29
  deepfabric/tui.py,sha256=9ETtGFQk26U9PQ2b5foplVYDKxaFGd-8UqK7uSKyHwE,50480
30
30
  deepfabric/update_checker.py,sha256=AUa9iUdkGNzu7tWkQRxIlF19YRmKLetwxu-Ys2ONS8Y,5145
31
- deepfabric/utils.py,sha256=ve6tku_-jgW_ZIkh9osUEQ3C_03J6R_zOw0Xf5UGJYc,4891
31
+ deepfabric/utils.py,sha256=a9G6VTw52UdddTFoMw-JjunjawtPN54N275-XGPL2cQ,5822
32
32
  deepfabric/validation.py,sha256=1x1X_45kyI0w_FCdUiNdvy4LQu3B0KVR-fyvLkrKEGw,5125
33
33
  deepfabric/evaluation/__init__.py,sha256=7xMLmYXaNC1U7qf88S9fMxWTABoDRiOcimSYfCt_PSo,1224
34
- deepfabric/evaluation/evaluator.py,sha256=ExUrL5Zil4DzibzjzngA7dfxnmGIVp9H7319FhLHYmk,33918
34
+ deepfabric/evaluation/evaluator.py,sha256=qNowle5v2ukDJ11igNOCParlBfXT8QUeOvXx6sSJ_Ug,34480
35
35
  deepfabric/evaluation/inference.py,sha256=y7JA0IsBDwe0sJzVQeItYHAV5wUJn6Bjp1Wsp3r7qYQ,7644
36
36
  deepfabric/evaluation/metrics.py,sha256=ITNevYj7CBXzYs-rYhsihO6-rE9n30CYRaVUfdTbcFQ,12026
37
37
  deepfabric/evaluation/parser.py,sha256=AXyiCtNV4rueZQxLE_GqqkFNeDAewGoC--0vXHW-jW8,10603
@@ -39,7 +39,7 @@ deepfabric/evaluation/backends/__init__.py,sha256=GqC0FfpWmtgJmjHd0kVKNg7g-NjhRo
39
39
  deepfabric/evaluation/backends/llm_eval_backend.py,sha256=4jp5tnTp7v_0pHCGhcPbI55ig79-eVxdzooesi2PymA,18827
40
40
  deepfabric/evaluation/backends/ollama_backend.py,sha256=mtPp1JtIDRjb76X_rTa1jS1ETzMjte8t3WJjuYV1oDQ,4372
41
41
  deepfabric/evaluation/backends/tool_call_parsers.py,sha256=Ufg4Xt3mrDS-WbGor6tOOr4xZNCHk3Co2C-z_o-pAkM,14126
42
- deepfabric/evaluation/backends/transformers_backend.py,sha256=WcqB9gkayQpjx2Em00lhzJg8RcWdQEYbctDNXLzFChA,14484
42
+ deepfabric/evaluation/backends/transformers_backend.py,sha256=f3rbFxjWdv2NhDvlMfl0YwFUkfh0i5dlM3JKYeoJgvQ,15243
43
43
  deepfabric/evaluation/evaluators/__init__.py,sha256=NdH65YvanskRGe6r7JepkTNGGt8xA-GLugagU3VQ_WM,353
44
44
  deepfabric/evaluation/evaluators/base.py,sha256=1TiLr-_oF9dRmdSgJs94dDbf0gTwRS8TGGz2C1Z3nag,2946
45
45
  deepfabric/evaluation/evaluators/registry.py,sha256=VGeb1AHFGkn9TLpcqfuGIZi1jgh7Qw0NNILT6z3Se6M,2171
@@ -66,11 +66,11 @@ deepfabric/tools/loader.py,sha256=Bv56D-76JChlK_QXfHLw_rneGLZYRhkn5ETbJMIdJsA,29
66
66
  deepfabric/tools/mcp_client.py,sha256=uQRrlDSVwF0ZatOl9bidBNU7IgXgJKQU-xG50dK0Uy4,23377
67
67
  deepfabric/training/__init__.py,sha256=MJazTELfrTB15rIiCE04hDeUL8LSSg4-4LWWG6j2BRw,1566
68
68
  deepfabric/training/api_key_prompt.py,sha256=pSIMX3eDGyV9x_r7MHE4TyIsIB2SqYb8gKCdAtTY-q8,9371
69
- deepfabric/training/callback.py,sha256=NUNrMAEYKt9kPjrX9mckvs8H4uoeVtRWPsfrjW90fWI,13051
69
+ deepfabric/training/callback.py,sha256=5zdifbHA2PWILHl2cVFyO65aW7cGAQhcvDqm3s8_I0Q,13221
70
70
  deepfabric/training/dataset_utils.py,sha256=klx8DoawEwuMigBDP-RpMAfe7FvYxRbhj599MErxBr4,7313
71
71
  deepfabric/training/metrics_sender.py,sha256=ZCyvMv5hRu8XJnQYVGXJ9wh7HEMJ0l3Ktyi8_etOpZs,10833
72
- deepfabric-4.8.0.dist-info/METADATA,sha256=N3ttE4MjkF2rk_Zq75-wjDds3BM0L8jEciHz8wnAnx0,20427
73
- deepfabric-4.8.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
74
- deepfabric-4.8.0.dist-info/entry_points.txt,sha256=zatevils13hfs8x29_vmUyivQ6rTtq7hE2RBusZw1Fo,50
75
- deepfabric-4.8.0.dist-info/licenses/LICENSE,sha256=-qRt8wmrhQ9aMf7KhmZXc2vrTETYZF-6_T1KCeUhvHY,11340
76
- deepfabric-4.8.0.dist-info/RECORD,,
72
+ deepfabric-4.8.2.dist-info/METADATA,sha256=15ZBOITSr6pigZYD-GBn_IwRlnzftZ64hwrXldKr1mg,20536
73
+ deepfabric-4.8.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
74
+ deepfabric-4.8.2.dist-info/entry_points.txt,sha256=zatevils13hfs8x29_vmUyivQ6rTtq7hE2RBusZw1Fo,50
75
+ deepfabric-4.8.2.dist-info/licenses/LICENSE,sha256=-qRt8wmrhQ9aMf7KhmZXc2vrTETYZF-6_T1KCeUhvHY,11340
76
+ deepfabric-4.8.2.dist-info/RECORD,,