fabricatio 0.2.8.dev3__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.
- fabricatio/__init__.py +4 -11
- fabricatio/actions/__init__.py +1 -0
- fabricatio/actions/article.py +128 -165
- fabricatio/actions/article_rag.py +62 -46
- fabricatio/actions/output.py +60 -4
- fabricatio/actions/rag.py +2 -1
- fabricatio/actions/rules.py +72 -0
- fabricatio/capabilities/__init__.py +1 -0
- fabricatio/capabilities/censor.py +104 -0
- fabricatio/capabilities/check.py +148 -32
- fabricatio/capabilities/correct.py +162 -100
- fabricatio/capabilities/rag.py +5 -4
- fabricatio/capabilities/rating.py +109 -54
- fabricatio/capabilities/review.py +1 -1
- fabricatio/capabilities/task.py +2 -1
- fabricatio/config.py +14 -6
- fabricatio/fs/readers.py +20 -1
- fabricatio/models/action.py +63 -41
- fabricatio/models/adv_kwargs_types.py +25 -0
- fabricatio/models/extra/__init__.py +1 -0
- fabricatio/models/extra/advanced_judge.py +7 -4
- fabricatio/models/extra/article_base.py +125 -79
- fabricatio/models/extra/article_main.py +101 -19
- fabricatio/models/extra/article_outline.py +2 -3
- fabricatio/models/extra/article_proposal.py +15 -14
- fabricatio/models/extra/patches.py +20 -0
- fabricatio/models/extra/problem.py +64 -23
- fabricatio/models/extra/rule.py +39 -10
- fabricatio/models/generic.py +405 -75
- fabricatio/models/kwargs_types.py +23 -17
- fabricatio/models/task.py +1 -1
- fabricatio/models/tool.py +149 -14
- fabricatio/models/usages.py +55 -56
- fabricatio/parser.py +12 -13
- fabricatio/rust.cp312-win_amd64.pyd +0 -0
- fabricatio/{_rust.pyi → rust.pyi} +42 -4
- fabricatio/{_rust_instances.py → rust_instances.py} +1 -1
- fabricatio/utils.py +5 -5
- fabricatio/workflows/__init__.py +1 -0
- fabricatio/workflows/articles.py +3 -5
- fabricatio-0.2.9.data/scripts/tdown.exe +0 -0
- {fabricatio-0.2.8.dev3.dist-info → fabricatio-0.2.9.dist-info}/METADATA +1 -1
- fabricatio-0.2.9.dist-info/RECORD +61 -0
- fabricatio/_rust.cp312-win_amd64.pyd +0 -0
- fabricatio-0.2.8.dev3.data/scripts/tdown.exe +0 -0
- fabricatio-0.2.8.dev3.dist-info/RECORD +0 -53
- {fabricatio-0.2.8.dev3.dist-info → fabricatio-0.2.9.dist-info}/WHEEL +0 -0
- {fabricatio-0.2.8.dev3.dist-info → fabricatio-0.2.9.dist-info}/licenses/LICENSE +0 -0
fabricatio/models/generic.py
CHANGED
@@ -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,47 +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
|
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
|
-
"""
|
51
|
+
"""Generate pretty-printed JSON representation.
|
43
52
|
|
44
53
|
Returns:
|
45
|
-
str:
|
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
|
-
"""
|
59
|
+
"""Generate compact JSON representation.
|
60
|
+
|
61
|
+
Returns:
|
62
|
+
str: Minified JSON string without whitespace
|
63
|
+
"""
|
64
|
+
return self.model_dump_json(by_alias=True)
|
65
|
+
|
66
|
+
@staticmethod
|
67
|
+
def seq_display(seq: Iterable["Display"], compact: bool = False) -> str:
|
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
|
51
73
|
|
52
74
|
Returns:
|
53
|
-
str:
|
75
|
+
str: Combined display output with boundary markers
|
54
76
|
"""
|
55
|
-
return
|
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
|
+
)
|
56
82
|
|
57
83
|
|
58
84
|
class Named(Base):
|
59
|
-
"""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
|
+
"""
|
60
89
|
|
61
|
-
name: str
|
62
|
-
"""The name of
|
90
|
+
name: str
|
91
|
+
"""The name of this object,briefly and conclusively."""
|
63
92
|
|
64
93
|
|
65
94
|
class Described(Base):
|
66
|
-
"""Class that includes a description attribute.
|
95
|
+
"""Class that includes a description attribute.
|
67
96
|
|
68
|
-
description
|
69
|
-
"""
|
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."""
|
70
119
|
|
71
120
|
|
72
121
|
class AsPrompt(Base):
|
73
|
-
"""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
|
+
"""
|
74
126
|
|
75
127
|
@final
|
76
128
|
def as_prompt(self) -> str:
|
@@ -85,31 +137,53 @@ class AsPrompt(Base):
|
|
85
137
|
)
|
86
138
|
|
87
139
|
@abstractmethod
|
88
|
-
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
|
+
"""
|
89
148
|
|
90
149
|
|
91
150
|
class WithRef[T](Base):
|
92
|
-
"""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
|
+
"""
|
93
155
|
|
94
156
|
_reference: Optional[T] = PrivateAttr(None)
|
95
157
|
|
96
158
|
@property
|
97
159
|
def referenced(self) -> T:
|
98
|
-
"""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
|
+
"""
|
99
168
|
return ok(
|
100
|
-
self._reference, f"`{self.__class__.__name__}`'
|
169
|
+
self._reference, f"`{self.__class__.__name__}`'s `_reference` field is None. Have you called `update_ref`?"
|
101
170
|
)
|
102
171
|
|
103
172
|
@overload
|
104
173
|
def update_ref[S: WithRef](self: S, reference: T) -> S: ...
|
105
|
-
|
106
174
|
@overload
|
107
175
|
def update_ref[S: WithRef](self: S, reference: "WithRef[T]") -> S: ...
|
108
|
-
|
109
176
|
@overload
|
110
177
|
def update_ref[S: WithRef](self: S, reference: None = None) -> S: ...
|
111
178
|
def update_ref[S: WithRef](self: S, reference: Union[T, "WithRef[T]", None] = None) -> S: # noqa: PYI019
|
112
|
-
"""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
|
+
"""
|
113
187
|
if isinstance(reference, self.__class__):
|
114
188
|
self._reference = reference.referenced
|
115
189
|
else:
|
@@ -117,29 +191,44 @@ class WithRef[T](Base):
|
|
117
191
|
return self
|
118
192
|
|
119
193
|
def derive[S: WithRef](self: S, reference: Any) -> S: # noqa: PYI019
|
120
|
-
"""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
|
+
"""
|
121
202
|
new = self.model_copy()
|
122
203
|
new._reference = reference
|
123
204
|
return new
|
124
205
|
|
125
206
|
|
126
207
|
class PersistentAble(Base):
|
127
|
-
"""Class
|
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
|
+
"""
|
128
213
|
|
129
214
|
def persist(self, path: str | Path) -> Self:
|
130
|
-
"""
|
215
|
+
"""Save model instance to disk with versioned filename.
|
131
216
|
|
132
217
|
Args:
|
133
|
-
path (str | Path):
|
218
|
+
path (str | Path): Target directory or file path. If directory, filename is auto-generated.
|
134
219
|
|
135
220
|
Returns:
|
136
|
-
Self:
|
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
|
137
226
|
"""
|
138
227
|
p = Path(path)
|
139
|
-
out =
|
228
|
+
out = self.model_dump_json(indent=1,by_alias=True)
|
140
229
|
|
141
230
|
# Generate a timestamp in the format YYYYMMDD_HHMMSS
|
142
|
-
timestamp = datetime.now().strftime("%Y%m%
|
231
|
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
143
232
|
|
144
233
|
# Generate the hash
|
145
234
|
file_hash = blake3_hash(out.encode())[:6]
|
@@ -156,32 +245,103 @@ class PersistentAble(Base):
|
|
156
245
|
logger.info(f"Persisted `{self.__class__.__name__}` to {p.as_posix()}")
|
157
246
|
return self
|
158
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
|
+
|
159
281
|
@classmethod
|
160
282
|
def from_persistent(cls, path: str | Path) -> Self:
|
161
|
-
"""Load
|
283
|
+
"""Load an instance from a specific persisted file.
|
162
284
|
|
163
285
|
Args:
|
164
|
-
path (str | Path):
|
286
|
+
path (str | Path): Path to the JSON file.
|
165
287
|
|
166
288
|
Returns:
|
167
|
-
Self: The
|
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.
|
168
294
|
"""
|
169
|
-
return cls.
|
295
|
+
return cls.model_validate_json(safe_text_read(path))
|
296
|
+
|
170
297
|
|
298
|
+
class Language(Base):
|
299
|
+
"""Class that provides a language attribute."""
|
171
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))
|
172
312
|
class ModelHash(Base):
|
173
|
-
"""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
|
+
"""
|
174
317
|
|
175
318
|
def __hash__(self) -> int:
|
176
|
-
"""Calculates a hash value for the
|
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
|
+
"""
|
177
324
|
return hash(self.model_dump_json())
|
178
325
|
|
179
326
|
|
180
327
|
class UpdateFrom(Base):
|
181
|
-
"""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
|
+
"""
|
182
332
|
|
183
333
|
def update_pre_check(self, other: Self) -> Self:
|
184
|
-
"""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
|
+
"""
|
185
345
|
if not isinstance(other, self.__class__):
|
186
346
|
raise TypeError(f"Cannot update from a non-{self.__class__.__name__} instance.")
|
187
347
|
|
@@ -189,16 +349,35 @@ class UpdateFrom(Base):
|
|
189
349
|
|
190
350
|
@abstractmethod
|
191
351
|
def update_from_inner(self, other: Self) -> Self:
|
192
|
-
"""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
|
+
"""
|
193
362
|
|
194
363
|
@final
|
195
364
|
def update_from(self, other: Self) -> Self:
|
196
|
-
"""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
|
+
"""
|
197
373
|
return self.update_pre_check(other).update_from_inner(other)
|
198
374
|
|
199
375
|
|
200
376
|
class ResolveUpdateConflict(Base):
|
201
|
-
"""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
|
+
"""
|
202
381
|
|
203
382
|
@abstractmethod
|
204
383
|
def resolve_update_conflict(self, other: Self) -> str:
|
@@ -213,7 +392,10 @@ class ResolveUpdateConflict(Base):
|
|
213
392
|
|
214
393
|
|
215
394
|
class Introspect(Base):
|
216
|
-
"""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
|
+
"""
|
217
399
|
|
218
400
|
@abstractmethod
|
219
401
|
def introspect(self) -> str:
|
@@ -225,7 +407,10 @@ class Introspect(Base):
|
|
225
407
|
|
226
408
|
|
227
409
|
class WithBriefing(Named, Described):
|
228
|
-
"""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
|
+
"""
|
229
414
|
|
230
415
|
@property
|
231
416
|
def briefing(self) -> str:
|
@@ -238,15 +423,29 @@ class WithBriefing(Named, Described):
|
|
238
423
|
|
239
424
|
|
240
425
|
class UnsortGenerate(GenerateJsonSchema):
|
241
|
-
"""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
|
+
"""
|
242
430
|
|
243
431
|
def sort(self, value: JsonSchemaValue, parent_key: str | None = None) -> JsonSchemaValue:
|
244
|
-
"""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
|
+
"""
|
245
441
|
return value
|
246
442
|
|
247
443
|
|
248
444
|
class WithFormatedJsonSchema(Base):
|
249
|
-
"""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
|
+
"""
|
250
449
|
|
251
450
|
@classmethod
|
252
451
|
def formated_json_schema(cls) -> str:
|
@@ -262,25 +461,26 @@ class WithFormatedJsonSchema(Base):
|
|
262
461
|
|
263
462
|
|
264
463
|
class CreateJsonObjPrompt(WithFormatedJsonSchema):
|
265
|
-
"""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
|
+
"""
|
266
468
|
|
267
469
|
@classmethod
|
268
470
|
@overload
|
269
471
|
def create_json_prompt(cls, requirement: List[str]) -> List[str]: ...
|
270
|
-
|
271
472
|
@classmethod
|
272
473
|
@overload
|
273
474
|
def create_json_prompt(cls, requirement: str) -> str: ...
|
274
|
-
|
275
475
|
@classmethod
|
276
476
|
def create_json_prompt(cls, requirement: str | List[str]) -> str | List[str]:
|
277
477
|
"""Create the prompt for creating a JSON object with given requirement.
|
278
478
|
|
279
479
|
Args:
|
280
|
-
requirement (str): The requirement for the JSON object.
|
480
|
+
requirement (str | List[str]): The requirement for the JSON object.
|
281
481
|
|
282
482
|
Returns:
|
283
|
-
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.
|
284
484
|
"""
|
285
485
|
if isinstance(requirement, str):
|
286
486
|
return TEMPLATE_MANAGER.render_template(
|
@@ -297,7 +497,10 @@ class CreateJsonObjPrompt(WithFormatedJsonSchema):
|
|
297
497
|
|
298
498
|
|
299
499
|
class InstantiateFromString(Base):
|
300
|
-
"""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
|
+
"""
|
301
504
|
|
302
505
|
@classmethod
|
303
506
|
def instantiate_from_string(cls, string: str) -> Self | None:
|
@@ -309,19 +512,37 @@ class InstantiateFromString(Base):
|
|
309
512
|
Returns:
|
310
513
|
Self | None: The instance of the class or None if the string is not valid.
|
311
514
|
"""
|
312
|
-
|
515
|
+
obj = JsonCapture.convert_with(string, cls.model_validate_json)
|
516
|
+
logger.debug(f"Instantiate `{cls.__name__}` from string, {'Failed' if obj is None else 'Success'}.")
|
517
|
+
return obj
|
313
518
|
|
314
519
|
|
315
520
|
class ProposedAble(CreateJsonObjPrompt, InstantiateFromString):
|
316
|
-
"""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
|
+
"""
|
525
|
+
|
526
|
+
|
527
|
+
class SketchedAble(ProposedAble, Display):
|
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
|
+
"""
|
317
532
|
|
318
533
|
|
319
|
-
class ProposedUpdateAble(
|
320
|
-
"""Make the obj can be updated from the proposed obj in place.
|
534
|
+
class ProposedUpdateAble(SketchedAble, UpdateFrom, ABC):
|
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
|
+
"""
|
321
539
|
|
322
540
|
|
323
541
|
class FinalizedDumpAble(Base):
|
324
|
-
"""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
|
+
"""
|
325
546
|
|
326
547
|
def finalized_dump(self) -> str:
|
327
548
|
"""Finalize the dump of the object.
|
@@ -329,7 +550,7 @@ class FinalizedDumpAble(Base):
|
|
329
550
|
Returns:
|
330
551
|
str: The finalized dump of the object.
|
331
552
|
"""
|
332
|
-
return self.model_dump_json()
|
553
|
+
return self.model_dump_json(indent=1,by_alias=True)
|
333
554
|
|
334
555
|
def finalized_dump_to(self, path: str | Path) -> Self:
|
335
556
|
"""Finalize the dump of the object to a file.
|
@@ -344,12 +565,11 @@ class FinalizedDumpAble(Base):
|
|
344
565
|
return self
|
345
566
|
|
346
567
|
|
347
|
-
class CensoredAble(ProposedAble, FinalizedDumpAble):
|
348
|
-
"""Class that provides a method to censor the object."""
|
349
|
-
|
350
|
-
|
351
568
|
class WithDependency(Base):
|
352
|
-
"""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
|
+
"""
|
353
573
|
|
354
574
|
dependencies: List[str] = Field(default_factory=list)
|
355
575
|
"""The file dependencies which is needed to read or write to meet a specific requirement, a list of file paths."""
|
@@ -437,7 +657,10 @@ class WithDependency(Base):
|
|
437
657
|
|
438
658
|
|
439
659
|
class Vectorizable(Base):
|
440
|
-
"""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
|
+
"""
|
441
664
|
|
442
665
|
def _prepare_vectorization_inner(self) -> str:
|
443
666
|
return rtoml.dumps(self.model_dump())
|
@@ -446,20 +669,30 @@ class Vectorizable(Base):
|
|
446
669
|
def prepare_vectorization(self, max_length: Optional[int] = None) -> str:
|
447
670
|
"""Prepare the vectorization of the model.
|
448
671
|
|
672
|
+
Args:
|
673
|
+
max_length (Optional[int]): The maximum token length for the vectorization. Defaults to the configuration.
|
674
|
+
|
449
675
|
Returns:
|
450
676
|
str: The prepared vectorization of the model.
|
677
|
+
|
678
|
+
Raises:
|
679
|
+
ValueError: If the chunk exceeds the maximum sequence length.
|
451
680
|
"""
|
452
681
|
max_length = max_length or configs.embedding.max_sequence_length
|
453
682
|
chunk = self._prepare_vectorization_inner()
|
454
683
|
if max_length and (length := token_counter(text=chunk)) > max_length:
|
455
|
-
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}")
|
456
685
|
raise ValueError(err)
|
457
686
|
|
458
687
|
return chunk
|
459
688
|
|
460
689
|
|
461
690
|
class ScopedConfig(Base):
|
462
|
-
"""
|
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
|
+
"""
|
463
696
|
|
464
697
|
llm_api_endpoint: Optional[HttpUrl] = None
|
465
698
|
"""The OpenAI API endpoint."""
|
@@ -517,27 +750,33 @@ class ScopedConfig(Base):
|
|
517
750
|
|
518
751
|
embedding_dimensions: Optional[PositiveInt] = None
|
519
752
|
"""The dimensions of the embedding."""
|
753
|
+
|
520
754
|
embedding_caching: Optional[bool] = False
|
521
755
|
"""Whether to cache the embedding result."""
|
522
756
|
|
523
757
|
milvus_uri: Optional[HttpUrl] = Field(default=None)
|
524
758
|
"""The URI of the Milvus server."""
|
759
|
+
|
525
760
|
milvus_token: Optional[SecretStr] = Field(default=None)
|
526
761
|
"""The token for the Milvus server."""
|
762
|
+
|
527
763
|
milvus_timeout: Optional[PositiveFloat] = Field(default=None)
|
528
764
|
"""The timeout for the Milvus server."""
|
765
|
+
|
529
766
|
milvus_dimensions: Optional[PositiveInt] = Field(default=None)
|
530
767
|
"""The dimensions of the Milvus server."""
|
531
768
|
|
532
769
|
@final
|
533
770
|
def fallback_to(self, other: "ScopedConfig") -> Self:
|
534
|
-
"""
|
771
|
+
"""Merge configuration values with fallback priority.
|
772
|
+
|
773
|
+
Copies non-null values from 'other' to self where current values are None.
|
535
774
|
|
536
775
|
Args:
|
537
|
-
other (ScopedConfig):
|
776
|
+
other (ScopedConfig): Configuration to fallback to
|
538
777
|
|
539
778
|
Returns:
|
540
|
-
Self:
|
779
|
+
Self: Current instance with merged values
|
541
780
|
"""
|
542
781
|
# Iterate over the attribute names and copy values from 'other' to 'self' where applicable
|
543
782
|
# noinspection PydanticTypeChecker,PyTypeChecker
|
@@ -551,13 +790,15 @@ class ScopedConfig(Base):
|
|
551
790
|
|
552
791
|
@final
|
553
792
|
def hold_to(self, others: Union["ScopedConfig", Iterable["ScopedConfig"]]) -> Self:
|
554
|
-
"""
|
793
|
+
"""Propagate non-null values to other configurations.
|
794
|
+
|
795
|
+
Copies current non-null values to target configurations where they are None.
|
555
796
|
|
556
797
|
Args:
|
557
|
-
others (
|
798
|
+
others (ScopedConfig|Iterable): Target configurations to update
|
558
799
|
|
559
800
|
Returns:
|
560
|
-
Self:
|
801
|
+
Self: Current instance unchanged
|
561
802
|
"""
|
562
803
|
if not isinstance(others, Iterable):
|
563
804
|
others = [others]
|
@@ -567,3 +808,92 @@ class ScopedConfig(Base):
|
|
567
808
|
if (attr := getattr(self, attr_name)) is not None and getattr(other, attr_name) is None:
|
568
809
|
setattr(other, attr_name, attr)
|
569
810
|
return self
|
811
|
+
|
812
|
+
|
813
|
+
class Patch[T](ProposedAble):
|
814
|
+
"""Base class for patches.
|
815
|
+
|
816
|
+
This class provides a base implementation for patches that can be applied to other objects.
|
817
|
+
"""
|
818
|
+
|
819
|
+
def apply(self, other: T) -> T:
|
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
|
+
"""
|
831
|
+
for field in self.__class__.model_fields:
|
832
|
+
if not hasattr(other, field):
|
833
|
+
raise ValueError(f"{field} not found in {other}, are you applying to the wrong type?")
|
834
|
+
setattr(other, field, getattr(self, field))
|
835
|
+
return other
|
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
|
+
|
869
|
+
|
870
|
+
class SequencePatch[T](ProposedUpdateAble):
|
871
|
+
"""Base class for patches.
|
872
|
+
|
873
|
+
This class provides a base implementation for patches that can be applied to sequences of objects.
|
874
|
+
"""
|
875
|
+
|
876
|
+
tweaked: List[T]
|
877
|
+
"""Tweaked content list"""
|
878
|
+
|
879
|
+
def update_from_inner(self, other: Self) -> Self:
|
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
|
+
"""
|
888
|
+
self.tweaked.clear()
|
889
|
+
self.tweaked.extend(other.tweaked)
|
890
|
+
return self
|
891
|
+
|
892
|
+
@classmethod
|
893
|
+
def default(cls) -> Self:
|
894
|
+
"""Defaults to empty list.
|
895
|
+
|
896
|
+
Returns:
|
897
|
+
Self: A new instance with an empty list of tweaks.
|
898
|
+
"""
|
899
|
+
return cls(tweaked=[])
|