fabricatio 0.2.8.dev4__cp312-cp312-win_amd64.whl → 0.2.9__cp312-cp312-win_amd64.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.
Files changed (46) hide show
  1. fabricatio/__init__.py +4 -11
  2. fabricatio/actions/__init__.py +1 -0
  3. fabricatio/actions/article.py +98 -110
  4. fabricatio/actions/article_rag.py +15 -10
  5. fabricatio/actions/output.py +60 -4
  6. fabricatio/actions/rag.py +2 -1
  7. fabricatio/actions/rules.py +72 -0
  8. fabricatio/capabilities/__init__.py +1 -0
  9. fabricatio/capabilities/censor.py +23 -6
  10. fabricatio/capabilities/check.py +46 -27
  11. fabricatio/capabilities/correct.py +35 -16
  12. fabricatio/capabilities/rag.py +5 -4
  13. fabricatio/capabilities/rating.py +56 -49
  14. fabricatio/capabilities/review.py +1 -1
  15. fabricatio/capabilities/task.py +2 -1
  16. fabricatio/config.py +5 -3
  17. fabricatio/fs/readers.py +20 -1
  18. fabricatio/models/action.py +59 -36
  19. fabricatio/models/extra/__init__.py +1 -0
  20. fabricatio/models/extra/advanced_judge.py +4 -4
  21. fabricatio/models/extra/article_base.py +124 -61
  22. fabricatio/models/extra/article_main.py +100 -17
  23. fabricatio/models/extra/article_outline.py +2 -3
  24. fabricatio/models/extra/article_proposal.py +15 -14
  25. fabricatio/models/extra/patches.py +17 -4
  26. fabricatio/models/extra/problem.py +31 -23
  27. fabricatio/models/extra/rule.py +39 -8
  28. fabricatio/models/generic.py +369 -78
  29. fabricatio/models/task.py +1 -1
  30. fabricatio/models/tool.py +149 -14
  31. fabricatio/models/usages.py +46 -42
  32. fabricatio/parser.py +5 -5
  33. fabricatio/rust.cp312-win_amd64.pyd +0 -0
  34. fabricatio/{_rust.pyi → rust.pyi} +42 -4
  35. fabricatio/{_rust_instances.py → rust_instances.py} +1 -1
  36. fabricatio/utils.py +5 -5
  37. fabricatio/workflows/__init__.py +1 -0
  38. fabricatio/workflows/articles.py +3 -5
  39. fabricatio-0.2.9.data/scripts/tdown.exe +0 -0
  40. {fabricatio-0.2.8.dev4.dist-info → fabricatio-0.2.9.dist-info}/METADATA +1 -1
  41. fabricatio-0.2.9.dist-info/RECORD +61 -0
  42. fabricatio/_rust.cp312-win_amd64.pyd +0 -0
  43. fabricatio-0.2.8.dev4.data/scripts/tdown.exe +0 -0
  44. fabricatio-0.2.8.dev4.dist-info/RECORD +0 -56
  45. {fabricatio-0.2.8.dev4.dist-info → fabricatio-0.2.9.dist-info}/WHEEL +0 -0
  46. {fabricatio-0.2.8.dev4.dist-info → fabricatio-0.2.9.dist-info}/licenses/LICENSE +0 -0
@@ -1,18 +1,18 @@
1
- """This module defines generic classes for models in the Fabricatio library."""
1
+ """This module defines generic classes for models in the Fabricatio library, providing a foundation for various model functionalities."""
2
2
 
3
3
  from abc import ABC, abstractmethod
4
4
  from datetime import datetime
5
5
  from pathlib import Path
6
- from typing import Any, Callable, Dict, Iterable, List, Optional, Self, Union, final, overload
6
+ from typing import Any, Callable, Dict, Iterable, List, Optional, Self, Type, Union, final, overload
7
7
 
8
8
  import orjson
9
9
  import rtoml
10
- from fabricatio._rust import blake3_hash
11
- from fabricatio._rust_instances import TEMPLATE_MANAGER
12
10
  from fabricatio.config import configs
13
11
  from fabricatio.fs.readers import MAGIKA, safe_text_read
14
12
  from fabricatio.journal import logger
15
13
  from fabricatio.parser import JsonCapture
14
+ from fabricatio.rust import blake3_hash, detect_language
15
+ from fabricatio.rust_instances import TEMPLATE_MANAGER
16
16
  from fabricatio.utils import ok
17
17
  from litellm.utils import token_counter
18
18
  from pydantic import (
@@ -30,52 +30,99 @@ from pydantic.json_schema import GenerateJsonSchema, JsonSchemaValue
30
30
 
31
31
 
32
32
  class Base(BaseModel):
33
- """Base class for all models with Pydantic configuration."""
33
+ """Base class for all models with Pydantic configuration.
34
+
35
+ This class sets up the basic Pydantic configuration for all models in the Fabricatio library.
36
+ The `model_config` uses `use_attribute_docstrings=True` to ensure field descriptions are
37
+ pulled from the attribute's docstring instead of the default Pydantic behavior.
38
+ """
34
39
 
35
40
  model_config = ConfigDict(use_attribute_docstrings=True)
36
41
 
37
42
 
38
43
  class Display(Base):
39
- """Class that provides a method to display the model in a formatted JSON string."""
44
+ """Class that provides formatted JSON representation utilities.
45
+
46
+ Provides methods to generate both pretty-printed and compact JSON representations of the model.
47
+ Used for debugging and logging purposes.
48
+ """
40
49
 
41
50
  def display(self) -> str:
42
- """Display the model in a formatted JSON string.
51
+ """Generate pretty-printed JSON representation.
43
52
 
44
53
  Returns:
45
- str: The formatted JSON string of the model.
54
+ str: JSON string with 1-level indentation for readability
46
55
  """
47
- return self.model_dump_json(indent=1)
56
+ return self.model_dump_json(indent=1,by_alias=True)
48
57
 
49
58
  def compact(self) -> str:
50
- """Display the model in a compact JSON string.
59
+ """Generate compact JSON representation.
51
60
 
52
61
  Returns:
53
- str: The compact JSON string of the model.
62
+ str: Minified JSON string without whitespace
54
63
  """
55
- return self.model_dump_json()
64
+ return self.model_dump_json(by_alias=True)
56
65
 
57
66
  @staticmethod
58
67
  def seq_display(seq: Iterable["Display"], compact: bool = False) -> str:
59
- """Display a sequence of Display objects in a formatted JSON string."""
60
- return "\n".join(d.compact() if compact else d.display() for d in seq)
68
+ """Generate formatted display for sequence of Display objects.
69
+
70
+ Args:
71
+ seq (Iterable[Display]): Sequence of objects to display
72
+ compact (bool): Use compact format instead of pretty print
73
+
74
+ Returns:
75
+ str: Combined display output with boundary markers
76
+ """
77
+ return (
78
+ "--- Start of Extra Info Sequence ---"
79
+ + "\n".join(d.compact() if compact else d.display() for d in seq)
80
+ + "--- End of Extra Info Sequence ---"
81
+ )
61
82
 
62
83
 
63
84
  class Named(Base):
64
- """Class that includes a name attribute."""
85
+ """Class that includes a name attribute.
86
+
87
+ This class adds a name attribute to models, which is intended to be a unique identifier.
88
+ """
65
89
 
66
- name: str = Field(frozen=True)
67
- """The name of the object."""
90
+ name: str
91
+ """The name of this object,briefly and conclusively."""
68
92
 
69
93
 
70
94
  class Described(Base):
71
- """Class that includes a description attribute."""
95
+ """Class that includes a description attribute.
72
96
 
73
- description: str = Field(frozen=True)
74
- """The description of the object."""
97
+ This class adds a description attribute to models, providing additional context or information.
98
+ """
99
+
100
+ description: str
101
+ """A comprehensive description of this object, including its purpose, scope, and context.
102
+ This should clearly explain what this object is about, why it exists, and in what situations
103
+ it applies. The description should be detailed enough to provide full understanding of
104
+ this object's intent and application."""
105
+
106
+
107
+ class Titled(Base):
108
+ """Class that includes a title attribute."""
109
+
110
+ title: str
111
+ """The title of this object, make it professional and concise.No prefixed heading number should be included."""
112
+
113
+
114
+ class WordCount(Base):
115
+ """Class that includes a word count attribute."""
116
+
117
+ expected_word_count: int
118
+ """Expected word count of this research component."""
75
119
 
76
120
 
77
121
  class AsPrompt(Base):
78
- """Class that provides a method to generate a prompt from the model."""
122
+ """Class that provides a method to generate a prompt from the model.
123
+
124
+ This class includes a method to generate a prompt based on the model's attributes.
125
+ """
79
126
 
80
127
  @final
81
128
  def as_prompt(self) -> str:
@@ -90,31 +137,53 @@ class AsPrompt(Base):
90
137
  )
91
138
 
92
139
  @abstractmethod
93
- def _as_prompt_inner(self) -> Dict[str, str]: ...
140
+ def _as_prompt_inner(self) -> Dict[str, str]:
141
+ """Generate the inner part of the prompt.
142
+
143
+ This method should be implemented by subclasses to provide the specific data for the prompt.
144
+
145
+ Returns:
146
+ Dict[str, str]: The data for the prompt.
147
+ """
94
148
 
95
149
 
96
150
  class WithRef[T](Base):
97
- """Class that provides a reference to another object."""
151
+ """Class that provides a reference to another object.
152
+
153
+ This class manages a reference to another object, allowing for easy access and updates.
154
+ """
98
155
 
99
156
  _reference: Optional[T] = PrivateAttr(None)
100
157
 
101
158
  @property
102
159
  def referenced(self) -> T:
103
- """Get the referenced object."""
160
+ """Get the referenced object.
161
+
162
+ Returns:
163
+ T: The referenced object.
164
+
165
+ Raises:
166
+ ValueError: If the reference is not set.
167
+ """
104
168
  return ok(
105
- self._reference, f"`{self.__class__.__name__}`' s `_reference` field is None. Have you called `update_ref`?"
169
+ self._reference, f"`{self.__class__.__name__}`'s `_reference` field is None. Have you called `update_ref`?"
106
170
  )
107
171
 
108
172
  @overload
109
173
  def update_ref[S: WithRef](self: S, reference: T) -> S: ...
110
-
111
174
  @overload
112
175
  def update_ref[S: WithRef](self: S, reference: "WithRef[T]") -> S: ...
113
-
114
176
  @overload
115
177
  def update_ref[S: WithRef](self: S, reference: None = None) -> S: ...
116
178
  def update_ref[S: WithRef](self: S, reference: Union[T, "WithRef[T]", None] = None) -> S: # noqa: PYI019
117
- """Update the reference of the object."""
179
+ """Update the reference of the object.
180
+
181
+ Args:
182
+ reference (Union[T, WithRef[T], None]): The new reference to set.
183
+
184
+ Returns:
185
+ S: The current instance with the updated reference.
186
+ """
118
187
  if isinstance(reference, self.__class__):
119
188
  self._reference = reference.referenced
120
189
  else:
@@ -122,29 +191,44 @@ class WithRef[T](Base):
122
191
  return self
123
192
 
124
193
  def derive[S: WithRef](self: S, reference: Any) -> S: # noqa: PYI019
125
- """Derive a new object from the current object."""
194
+ """Derive a new object from the current object.
195
+
196
+ Args:
197
+ reference (Any): The reference for the new object.
198
+
199
+ Returns:
200
+ S: A new instance derived from the current object with the provided reference.
201
+ """
126
202
  new = self.model_copy()
127
203
  new._reference = reference
128
204
  return new
129
205
 
130
206
 
131
207
  class PersistentAble(Base):
132
- """Class that provides a method to persist the object."""
208
+ """Class providing file persistence capabilities.
209
+
210
+ Enables saving model instances to disk with timestamped filenames and loading from persisted files.
211
+ Implements basic versioning through filename hashing and timestamping.
212
+ """
133
213
 
134
214
  def persist(self, path: str | Path) -> Self:
135
- """Persist the object to a file or directory.
215
+ """Save model instance to disk with versioned filename.
136
216
 
137
217
  Args:
138
- path (str | Path): The path to save the object.
218
+ path (str | Path): Target directory or file path. If directory, filename is auto-generated.
139
219
 
140
220
  Returns:
141
- Self: The current instance of the object.
221
+ Self: Current instance for method chaining
222
+
223
+ Notes:
224
+ - Filename format: <ClassName>_<YYYYMMDD_HHMMSS>_<6-char_hash>.json
225
+ - Hash generated from JSON content ensures uniqueness
142
226
  """
143
227
  p = Path(path)
144
- out = self.model_dump_json()
228
+ out = self.model_dump_json(indent=1,by_alias=True)
145
229
 
146
230
  # Generate a timestamp in the format YYYYMMDD_HHMMSS
147
- timestamp = datetime.now().strftime("%Y%m%d")
231
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
148
232
 
149
233
  # Generate the hash
150
234
  file_hash = blake3_hash(out.encode())[:6]
@@ -161,32 +245,103 @@ class PersistentAble(Base):
161
245
  logger.info(f"Persisted `{self.__class__.__name__}` to {p.as_posix()}")
162
246
  return self
163
247
 
248
+ @classmethod
249
+ def from_latest_persistent(cls, dir_path: str | Path) -> Optional[Self]:
250
+ """Load most recent persisted instance from directory.
251
+
252
+ Args:
253
+ dir_path (str | Path): Directory containing persisted files
254
+
255
+ Returns:
256
+ Self: Most recently modified instance
257
+
258
+ Raises:
259
+ NotADirectoryError: If path is not a valid directory
260
+ FileNotFoundError: If no matching files found
261
+ """
262
+ dir_path = Path(dir_path)
263
+ if not dir_path.is_dir():
264
+ return None
265
+
266
+ pattern = f"{cls.__name__}_*.json"
267
+ files = list(dir_path.glob(pattern))
268
+
269
+ if not files:
270
+ return None
271
+
272
+ def _get_timestamp(file_path: Path) -> datetime:
273
+ stem = file_path.stem
274
+ parts = stem.split("_")
275
+ return datetime.strptime(f"{parts[1]}_{parts[2]}", "%Y%m%d_%H%M%S")
276
+
277
+ files.sort(key=lambda f: _get_timestamp(f), reverse=True)
278
+
279
+ return cls.from_persistent(files.pop(0))
280
+
164
281
  @classmethod
165
282
  def from_persistent(cls, path: str | Path) -> Self:
166
- """Load the object from a file.
283
+ """Load an instance from a specific persisted file.
167
284
 
168
285
  Args:
169
- path (str | Path): The path to load the object from.
286
+ path (str | Path): Path to the JSON file.
170
287
 
171
288
  Returns:
172
- Self: The current instance of the object.
289
+ Self: The loaded instance from the file.
290
+
291
+ Raises:
292
+ FileNotFoundError: If the specified file does not exist.
293
+ ValueError: If the file content is invalid for the model.
173
294
  """
174
295
  return cls.model_validate_json(safe_text_read(path))
175
296
 
176
297
 
298
+ class Language(Base):
299
+ """Class that provides a language attribute."""
300
+
301
+ @property
302
+ def language(self)->str:
303
+ """Get the language of the object."""
304
+ if isinstance(self,Described):
305
+ return detect_language(self.description)
306
+ if isinstance(self,Titled):
307
+ return detect_language(self.title)
308
+ if isinstance(self,Named):
309
+ return detect_language(self.name)
310
+
311
+ return detect_language(self.model_dump_json(by_alias=True))
177
312
  class ModelHash(Base):
178
- """Class that provides a hash value for the object."""
313
+ """Class that provides a hash value for the object.
314
+
315
+ This class includes a method to calculate a hash value for the object based on its JSON representation.
316
+ """
179
317
 
180
318
  def __hash__(self) -> int:
181
- """Calculates a hash value for the ArticleBase object based on its model_dump_json representation."""
319
+ """Calculates a hash value for the object based on its model_dump_json representation.
320
+
321
+ Returns:
322
+ int: The hash value of the object.
323
+ """
182
324
  return hash(self.model_dump_json())
183
325
 
184
326
 
185
327
  class UpdateFrom(Base):
186
- """Class that provides a method to update the object from another object."""
328
+ """Class that provides a method to update the object from another object.
329
+
330
+ This class includes methods to update the current object with the attributes of another object.
331
+ """
187
332
 
188
333
  def update_pre_check(self, other: Self) -> Self:
189
- """Pre-check for updating the object from another object."""
334
+ """Pre-check for updating the object from another object.
335
+
336
+ Args:
337
+ other (Self): The other object to update from.
338
+
339
+ Returns:
340
+ Self: The current instance after pre-check.
341
+
342
+ Raises:
343
+ TypeError: If the other object is not of the same type.
344
+ """
190
345
  if not isinstance(other, self.__class__):
191
346
  raise TypeError(f"Cannot update from a non-{self.__class__.__name__} instance.")
192
347
 
@@ -194,16 +349,35 @@ class UpdateFrom(Base):
194
349
 
195
350
  @abstractmethod
196
351
  def update_from_inner(self, other: Self) -> Self:
197
- """Updates the current instance with the attributes of another instance."""
352
+ """Updates the current instance with the attributes of another instance.
353
+
354
+ This method should be implemented by subclasses to provide the specific update logic.
355
+
356
+ Args:
357
+ other (Self): The other instance to update from.
358
+
359
+ Returns:
360
+ Self: The current instance with updated attributes.
361
+ """
198
362
 
199
363
  @final
200
364
  def update_from(self, other: Self) -> Self:
201
- """Updates the current instance with the attributes of another instance."""
365
+ """Updates the current instance with the attributes of another instance.
366
+
367
+ Args:
368
+ other (Self): The other instance to update from.
369
+
370
+ Returns:
371
+ Self: The current instance with updated attributes.
372
+ """
202
373
  return self.update_pre_check(other).update_from_inner(other)
203
374
 
204
375
 
205
376
  class ResolveUpdateConflict(Base):
206
- """Class that provides a method to update the object from another object."""
377
+ """Class that provides a method to update the object from another object.
378
+
379
+ This class includes a method to resolve conflicts when updating the object from another object.
380
+ """
207
381
 
208
382
  @abstractmethod
209
383
  def resolve_update_conflict(self, other: Self) -> str:
@@ -218,7 +392,10 @@ class ResolveUpdateConflict(Base):
218
392
 
219
393
 
220
394
  class Introspect(Base):
221
- """Class that provides a method to introspect the object."""
395
+ """Class that provides a method to introspect the object.
396
+
397
+ This class includes a method to perform internal introspection of the object.
398
+ """
222
399
 
223
400
  @abstractmethod
224
401
  def introspect(self) -> str:
@@ -230,7 +407,10 @@ class Introspect(Base):
230
407
 
231
408
 
232
409
  class WithBriefing(Named, Described):
233
- """Class that provides a briefing based on the name and description."""
410
+ """Class that provides a briefing based on the name and description.
411
+
412
+ This class combines the name and description attributes to provide a brief summary of the object.
413
+ """
234
414
 
235
415
  @property
236
416
  def briefing(self) -> str:
@@ -243,15 +423,29 @@ class WithBriefing(Named, Described):
243
423
 
244
424
 
245
425
  class UnsortGenerate(GenerateJsonSchema):
246
- """Class that provides a reverse JSON schema of the model."""
426
+ """Class that provides a reverse JSON schema of the model.
427
+
428
+ This class overrides the sorting behavior of the JSON schema generation to maintain the original order.
429
+ """
247
430
 
248
431
  def sort(self, value: JsonSchemaValue, parent_key: str | None = None) -> JsonSchemaValue:
249
- """Not sort."""
432
+ """Not sort.
433
+
434
+ Args:
435
+ value (JsonSchemaValue): The JSON schema value to sort.
436
+ parent_key (str | None): The parent key of the JSON schema value.
437
+
438
+ Returns:
439
+ JsonSchemaValue: The JSON schema value without sorting.
440
+ """
250
441
  return value
251
442
 
252
443
 
253
444
  class WithFormatedJsonSchema(Base):
254
- """Class that provides a formatted JSON schema of the model."""
445
+ """Class that provides a formatted JSON schema of the model.
446
+
447
+ This class includes a method to generate a formatted JSON schema of the model.
448
+ """
255
449
 
256
450
  @classmethod
257
451
  def formated_json_schema(cls) -> str:
@@ -267,25 +461,26 @@ class WithFormatedJsonSchema(Base):
267
461
 
268
462
 
269
463
  class CreateJsonObjPrompt(WithFormatedJsonSchema):
270
- """Class that provides a prompt for creating a JSON object."""
464
+ """Class that provides a prompt for creating a JSON object.
465
+
466
+ This class includes a method to create a prompt for creating a JSON object based on the model's schema and a requirement.
467
+ """
271
468
 
272
469
  @classmethod
273
470
  @overload
274
471
  def create_json_prompt(cls, requirement: List[str]) -> List[str]: ...
275
-
276
472
  @classmethod
277
473
  @overload
278
474
  def create_json_prompt(cls, requirement: str) -> str: ...
279
-
280
475
  @classmethod
281
476
  def create_json_prompt(cls, requirement: str | List[str]) -> str | List[str]:
282
477
  """Create the prompt for creating a JSON object with given requirement.
283
478
 
284
479
  Args:
285
- requirement (str): The requirement for the JSON object.
480
+ requirement (str | List[str]): The requirement for the JSON object.
286
481
 
287
482
  Returns:
288
- str: The prompt for creating a JSON object with given requirement.
483
+ str | List[str]: The prompt for creating a JSON object with given requirement.
289
484
  """
290
485
  if isinstance(requirement, str):
291
486
  return TEMPLATE_MANAGER.render_template(
@@ -302,7 +497,10 @@ class CreateJsonObjPrompt(WithFormatedJsonSchema):
302
497
 
303
498
 
304
499
  class InstantiateFromString(Base):
305
- """Class that provides a method to instantiate the class from a string."""
500
+ """Class that provides a method to instantiate the class from a string.
501
+
502
+ This class includes a method to instantiate the class from a JSON string representation.
503
+ """
306
504
 
307
505
  @classmethod
308
506
  def instantiate_from_string(cls, string: str) -> Self | None:
@@ -320,19 +518,31 @@ class InstantiateFromString(Base):
320
518
 
321
519
 
322
520
  class ProposedAble(CreateJsonObjPrompt, InstantiateFromString):
323
- """Class that provides a method to propose a JSON object based on the requirement."""
521
+ """Class that provides a method to propose a JSON object based on the requirement.
522
+
523
+ This class combines the functionality to create a prompt for a JSON object and instantiate it from a string.
524
+ """
324
525
 
325
526
 
326
527
  class SketchedAble(ProposedAble, Display):
327
- """Class that provides a method to scratch the object."""
528
+ """Class that provides a method to scratch the object.
529
+
530
+ This class combines the functionality to propose a JSON object, instantiate it from a string, and display it.
531
+ """
328
532
 
329
533
 
330
534
  class ProposedUpdateAble(SketchedAble, UpdateFrom, ABC):
331
- """Make the obj can be updated from the proposed obj in place."""
535
+ """Make the obj can be updated from the proposed obj in place.
536
+
537
+ This class provides the ability to update an object in place from a proposed object.
538
+ """
332
539
 
333
540
 
334
541
  class FinalizedDumpAble(Base):
335
- """Class that provides a method to finalize the dump of the object."""
542
+ """Class that provides a method to finalize the dump of the object.
543
+
544
+ This class includes methods to finalize the JSON representation of the object and dump it to a file.
545
+ """
336
546
 
337
547
  def finalized_dump(self) -> str:
338
548
  """Finalize the dump of the object.
@@ -340,7 +550,7 @@ class FinalizedDumpAble(Base):
340
550
  Returns:
341
551
  str: The finalized dump of the object.
342
552
  """
343
- return self.model_dump_json()
553
+ return self.model_dump_json(indent=1,by_alias=True)
344
554
 
345
555
  def finalized_dump_to(self, path: str | Path) -> Self:
346
556
  """Finalize the dump of the object to a file.
@@ -355,10 +565,11 @@ class FinalizedDumpAble(Base):
355
565
  return self
356
566
 
357
567
 
358
-
359
-
360
568
  class WithDependency(Base):
361
- """Class that manages file dependencies."""
569
+ """Class that manages file dependencies.
570
+
571
+ This class includes methods to manage file dependencies required for reading or writing.
572
+ """
362
573
 
363
574
  dependencies: List[str] = Field(default_factory=list)
364
575
  """The file dependencies which is needed to read or write to meet a specific requirement, a list of file paths."""
@@ -446,7 +657,10 @@ class WithDependency(Base):
446
657
 
447
658
 
448
659
  class Vectorizable(Base):
449
- """Class that prepares the vectorization of the model."""
660
+ """Class that prepares the vectorization of the model.
661
+
662
+ This class includes methods to prepare the model for vectorization, ensuring it fits within a specified token length.
663
+ """
450
664
 
451
665
  def _prepare_vectorization_inner(self) -> str:
452
666
  return rtoml.dumps(self.model_dump())
@@ -455,20 +669,30 @@ class Vectorizable(Base):
455
669
  def prepare_vectorization(self, max_length: Optional[int] = None) -> str:
456
670
  """Prepare the vectorization of the model.
457
671
 
672
+ Args:
673
+ max_length (Optional[int]): The maximum token length for the vectorization. Defaults to the configuration.
674
+
458
675
  Returns:
459
676
  str: The prepared vectorization of the model.
677
+
678
+ Raises:
679
+ ValueError: If the chunk exceeds the maximum sequence length.
460
680
  """
461
681
  max_length = max_length or configs.embedding.max_sequence_length
462
682
  chunk = self._prepare_vectorization_inner()
463
683
  if max_length and (length := token_counter(text=chunk)) > max_length:
464
- logger.error(err := f"Chunk exceeds maximum sequence length {max_length}, got {length},see {chunk}")
684
+ logger.error(err := f"Chunk exceeds maximum sequence length {max_length}, got {length}, see {chunk}")
465
685
  raise ValueError(err)
466
686
 
467
687
  return chunk
468
688
 
469
689
 
470
690
  class ScopedConfig(Base):
471
- """Class that manages a scoped configuration."""
691
+ """Configuration holder with hierarchical fallback mechanism.
692
+
693
+ Manages LLM, embedding, and vector database configurations with fallback logic.
694
+ Allows configuration values to be overridden in a hierarchical manner.
695
+ """
472
696
 
473
697
  llm_api_endpoint: Optional[HttpUrl] = None
474
698
  """The OpenAI API endpoint."""
@@ -526,27 +750,33 @@ class ScopedConfig(Base):
526
750
 
527
751
  embedding_dimensions: Optional[PositiveInt] = None
528
752
  """The dimensions of the embedding."""
753
+
529
754
  embedding_caching: Optional[bool] = False
530
755
  """Whether to cache the embedding result."""
531
756
 
532
757
  milvus_uri: Optional[HttpUrl] = Field(default=None)
533
758
  """The URI of the Milvus server."""
759
+
534
760
  milvus_token: Optional[SecretStr] = Field(default=None)
535
761
  """The token for the Milvus server."""
762
+
536
763
  milvus_timeout: Optional[PositiveFloat] = Field(default=None)
537
764
  """The timeout for the Milvus server."""
765
+
538
766
  milvus_dimensions: Optional[PositiveInt] = Field(default=None)
539
767
  """The dimensions of the Milvus server."""
540
768
 
541
769
  @final
542
770
  def fallback_to(self, other: "ScopedConfig") -> Self:
543
- """Fallback to another instance's attribute values if the current instance's attributes are None.
771
+ """Merge configuration values with fallback priority.
772
+
773
+ Copies non-null values from 'other' to self where current values are None.
544
774
 
545
775
  Args:
546
- other (ScopedConfig): Another instance from which to copy attribute values.
776
+ other (ScopedConfig): Configuration to fallback to
547
777
 
548
778
  Returns:
549
- Self: The current instance, allowing for method chaining.
779
+ Self: Current instance with merged values
550
780
  """
551
781
  # Iterate over the attribute names and copy values from 'other' to 'self' where applicable
552
782
  # noinspection PydanticTypeChecker,PyTypeChecker
@@ -560,13 +790,15 @@ class ScopedConfig(Base):
560
790
 
561
791
  @final
562
792
  def hold_to(self, others: Union["ScopedConfig", Iterable["ScopedConfig"]]) -> Self:
563
- """Hold to another instance's attribute values if the current instance's attributes are None.
793
+ """Propagate non-null values to other configurations.
794
+
795
+ Copies current non-null values to target configurations where they are None.
564
796
 
565
797
  Args:
566
- others (Union[ScopedConfig, Iterable[ScopedConfig]]): Another instance or iterable of instances from which to copy attribute values.
798
+ others (ScopedConfig|Iterable): Target configurations to update
567
799
 
568
800
  Returns:
569
- Self: The current instance, allowing for method chaining.
801
+ Self: Current instance unchanged
570
802
  """
571
803
  if not isinstance(others, Iterable):
572
804
  others = [others]
@@ -579,30 +811,89 @@ class ScopedConfig(Base):
579
811
 
580
812
 
581
813
  class Patch[T](ProposedAble):
582
- """Base class for patches."""
814
+ """Base class for patches.
815
+
816
+ This class provides a base implementation for patches that can be applied to other objects.
817
+ """
583
818
 
584
819
  def apply(self, other: T) -> T:
585
- """Apply the patch to another instance."""
820
+ """Apply the patch to another instance.
821
+
822
+ Args:
823
+ other (T): The instance to apply the patch to.
824
+
825
+ Returns:
826
+ T: The instance with the patch applied.
827
+
828
+ Raises:
829
+ ValueError: If a field in the patch is not found in the target instance.
830
+ """
586
831
  for field in self.__class__.model_fields:
587
832
  if not hasattr(other, field):
588
833
  raise ValueError(f"{field} not found in {other}, are you applying to the wrong type?")
589
834
  setattr(other, field, getattr(self, field))
590
835
  return other
591
836
 
837
+ def as_kwargs(self) -> Dict[str, Any]:
838
+ """Get the kwargs of the patch."""
839
+ return self.model_dump()
840
+
841
+ @staticmethod
842
+ def ref_cls() -> Optional[Type[BaseModel]]:
843
+ """Get the reference class of the model."""
844
+ return None
845
+
846
+ @classmethod
847
+ def formated_json_schema(cls) -> str:
848
+ """Get the JSON schema of the model in a formatted string.
849
+
850
+ Returns:
851
+ str: The JSON schema of the model in a formatted string.
852
+ """
853
+ my_schema = cls.model_json_schema(schema_generator=UnsortGenerate)
854
+
855
+ ref_cls = cls.ref_cls()
856
+ if ref_cls is not None:
857
+ # copy the desc info of each corresponding fields from `ref_cls`
858
+ for field_name in [f for f in cls.model_fields if f in ref_cls.model_fields]:
859
+ my_schema["properties"][field_name]["description"] = (
860
+ ref_cls.model_fields[field_name].description or my_schema["properties"][field_name]["description"]
861
+ )
862
+ my_schema["description"] = ref_cls.__doc__
863
+
864
+ return orjson.dumps(
865
+ my_schema,
866
+ option=orjson.OPT_INDENT_2,
867
+ ).decode()
868
+
592
869
 
593
870
  class SequencePatch[T](ProposedUpdateAble):
594
- """Base class for patches."""
871
+ """Base class for patches.
872
+
873
+ This class provides a base implementation for patches that can be applied to sequences of objects.
874
+ """
595
875
 
596
876
  tweaked: List[T]
597
877
  """Tweaked content list"""
598
878
 
599
879
  def update_from_inner(self, other: Self) -> Self:
600
- """Updates the current instance with the attributes of another instance."""
880
+ """Updates the current instance with the attributes of another instance.
881
+
882
+ Args:
883
+ other (Self): The other instance to update from.
884
+
885
+ Returns:
886
+ Self: The current instance with updated attributes.
887
+ """
601
888
  self.tweaked.clear()
602
889
  self.tweaked.extend(other.tweaked)
603
890
  return self
604
891
 
605
892
  @classmethod
606
893
  def default(cls) -> Self:
607
- """Defaults to empty list."""
894
+ """Defaults to empty list.
895
+
896
+ Returns:
897
+ Self: A new instance with an empty list of tweaks.
898
+ """
608
899
  return cls(tweaked=[])