fabricatio 0.3.15.dev4__cp313-cp313-manylinux_2_34_x86_64.whl → 0.3.15.dev5__cp313-cp313-manylinux_2_34_x86_64.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/actions/output.py +21 -22
- fabricatio/models/extra/article_base.py +3 -1
- fabricatio/models/extra/article_essence.py +1 -4
- fabricatio/models/extra/article_main.py +1 -2
- fabricatio/models/extra/article_outline.py +1 -2
- fabricatio/models/extra/article_proposal.py +1 -1
- fabricatio/models/extra/rule.py +1 -2
- fabricatio/models/generic.py +92 -0
- fabricatio/models/role.py +73 -16
- fabricatio/rust.cpython-313-x86_64-linux-gnu.so +0 -0
- fabricatio-0.3.15.dev5.data/scripts/tdown +0 -0
- fabricatio-0.3.15.dev5.data/scripts/ttm +0 -0
- {fabricatio-0.3.15.dev4.dist-info → fabricatio-0.3.15.dev5.dist-info}/METADATA +2 -1
- {fabricatio-0.3.15.dev4.dist-info → fabricatio-0.3.15.dev5.dist-info}/RECORD +16 -17
- fabricatio/capabilities/persist.py +0 -103
- fabricatio-0.3.15.dev4.data/scripts/tdown +0 -0
- fabricatio-0.3.15.dev4.data/scripts/ttm +0 -0
- {fabricatio-0.3.15.dev4.dist-info → fabricatio-0.3.15.dev5.dist-info}/WHEEL +0 -0
- {fabricatio-0.3.15.dev4.dist-info → fabricatio-0.3.15.dev5.dist-info}/licenses/LICENSE +0 -0
fabricatio/actions/output.py
CHANGED
@@ -3,11 +3,10 @@
|
|
3
3
|
from pathlib import Path
|
4
4
|
from typing import Any, Iterable, List, Mapping, Optional, Self, Sequence, Type
|
5
5
|
|
6
|
-
from fabricatio.capabilities.persist import PersistentAble
|
7
6
|
from fabricatio.fs import dump_text
|
8
7
|
from fabricatio.journal import logger
|
9
8
|
from fabricatio.models.action import Action
|
10
|
-
from fabricatio.models.generic import FinalizedDumpAble, FromMapping, FromSequence
|
9
|
+
from fabricatio.models.generic import FinalizedDumpAble, FromMapping, FromSequence, PersistentAble
|
11
10
|
from fabricatio.models.task import Task
|
12
11
|
from fabricatio.models.usages import LLMUsage
|
13
12
|
from fabricatio.rust import TEMPLATE_MANAGER
|
@@ -21,11 +20,11 @@ class DumpFinalizedOutput(Action, LLMUsage):
|
|
21
20
|
dump_path: Optional[str] = None
|
22
21
|
|
23
22
|
async def _execute(
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
23
|
+
self,
|
24
|
+
to_dump: FinalizedDumpAble,
|
25
|
+
task_input: Optional[Task] = None,
|
26
|
+
dump_path: Optional[str | Path] = None,
|
27
|
+
**_,
|
29
28
|
) -> str:
|
30
29
|
dump_path = Path(
|
31
30
|
dump_path
|
@@ -52,11 +51,11 @@ class RenderedDump(Action, LLMUsage):
|
|
52
51
|
"""The template name to render the data."""
|
53
52
|
|
54
53
|
async def _execute(
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
54
|
+
self,
|
55
|
+
to_dump: FinalizedDumpAble,
|
56
|
+
task_input: Optional[Task] = None,
|
57
|
+
dump_path: Optional[str | Path] = None,
|
58
|
+
**_,
|
60
59
|
) -> str:
|
61
60
|
dump_path = Path(
|
62
61
|
dump_path
|
@@ -91,10 +90,10 @@ class PersistentAll(Action, LLMUsage):
|
|
91
90
|
"""Whether to remove the existing dir before dumping."""
|
92
91
|
|
93
92
|
async def _execute(
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
93
|
+
self,
|
94
|
+
task_input: Optional[Task] = None,
|
95
|
+
persist_dir: Optional[str | Path] = None,
|
96
|
+
**cxt,
|
98
97
|
) -> int:
|
99
98
|
persist_dir = Path(
|
100
99
|
persist_dir
|
@@ -124,7 +123,7 @@ class PersistentAll(Action, LLMUsage):
|
|
124
123
|
v.persist(final_dir)
|
125
124
|
count += 1
|
126
125
|
if isinstance(v, Iterable) and any(
|
127
|
-
|
126
|
+
persistent_ables := (pers for pers in v if isinstance(pers, PersistentAble))
|
128
127
|
):
|
129
128
|
logger.info(f"Persisting collection {k} to {final_dir}")
|
130
129
|
final_dir.mkdir(parents=True, exist_ok=True)
|
@@ -174,11 +173,11 @@ class RetrieveFromLatest[T: PersistentAble](RetrieveFromPersistent[T], FromMappi
|
|
174
173
|
|
175
174
|
@classmethod
|
176
175
|
def from_mapping(
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
176
|
+
cls,
|
177
|
+
mapping: Mapping[str, str | Path],
|
178
|
+
*,
|
179
|
+
retrieve_cls: Type[T],
|
180
|
+
**kwargs,
|
182
181
|
) -> List["RetrieveFromLatest[T]"]:
|
183
182
|
"""Create a list of `RetrieveFromLatest` from the mapping."""
|
184
183
|
return [
|
@@ -5,7 +5,6 @@ from enum import StrEnum
|
|
5
5
|
from pathlib import Path
|
6
6
|
from typing import ClassVar, Generator, List, Optional, Self, Tuple, Type
|
7
7
|
|
8
|
-
from fabricatio.capabilities.persist import PersistentAble
|
9
8
|
from fabricatio.fs import dump_text, safe_text_read
|
10
9
|
from fabricatio.fs.readers import extract_sections
|
11
10
|
from fabricatio.journal import logger
|
@@ -16,6 +15,7 @@ from fabricatio.models.generic import (
|
|
16
15
|
Introspect,
|
17
16
|
Language,
|
18
17
|
ModelHash,
|
18
|
+
PersistentAble,
|
19
19
|
ProposedUpdateAble,
|
20
20
|
SketchedAble,
|
21
21
|
Titled,
|
@@ -84,6 +84,7 @@ class ArticleMetaData(SketchedAble, Described, WordCount, Titled, Language):
|
|
84
84
|
|
85
85
|
@property
|
86
86
|
def language(self) -> str:
|
87
|
+
"""Get the language of the article component."""
|
87
88
|
return detect_language(self.title)
|
88
89
|
|
89
90
|
|
@@ -311,6 +312,7 @@ class ArticleBase[T: ChapterBase](FinalizedDumpAble, AsPrompt, FromTypstCode, To
|
|
311
312
|
|
312
313
|
@property
|
313
314
|
def language(self) -> str:
|
315
|
+
"""Get the language of the article."""
|
314
316
|
if self.title:
|
315
317
|
return super().language
|
316
318
|
return self.chapters[0].language
|
@@ -2,9 +2,8 @@
|
|
2
2
|
|
3
3
|
from typing import List
|
4
4
|
|
5
|
-
from fabricatio.capabilities.persist import PersistentAble
|
6
5
|
from fabricatio.models.extra.rag import MilvusDataBase
|
7
|
-
from fabricatio.models.generic import SketchedAble
|
6
|
+
from fabricatio.models.generic import PersistentAble, SketchedAble
|
8
7
|
from pydantic import BaseModel
|
9
8
|
|
10
9
|
|
@@ -97,5 +96,3 @@ class ArticleEssence(SketchedAble, PersistentAble, MilvusDataBase):
|
|
97
96
|
|
98
97
|
def _prepare_vectorization_inner(self) -> str:
|
99
98
|
return self.compact()
|
100
|
-
|
101
|
-
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
from typing import ClassVar, Dict, Generator, List, Self, Tuple, Type, override
|
4
4
|
|
5
|
-
from fabricatio.capabilities.persist import PersistentAble
|
6
5
|
from fabricatio.decorators import precheck_package
|
7
6
|
from fabricatio.journal import logger
|
8
7
|
from fabricatio.models.extra.article_base import (
|
@@ -17,7 +16,7 @@ from fabricatio.models.extra.article_outline import (
|
|
17
16
|
ArticleSectionOutline,
|
18
17
|
ArticleSubsectionOutline,
|
19
18
|
)
|
20
|
-
from fabricatio.models.generic import Described, SequencePatch, SketchedAble, WithRef, WordCount
|
19
|
+
from fabricatio.models.generic import Described, PersistentAble, SequencePatch, SketchedAble, WithRef, WordCount
|
21
20
|
from fabricatio.rust import (
|
22
21
|
convert_all_tex_math,
|
23
22
|
fix_misplaced_labels,
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
from typing import ClassVar, Dict, Type
|
4
4
|
|
5
|
-
from fabricatio.capabilities.persist import PersistentAble
|
6
5
|
from fabricatio.models.extra.article_base import (
|
7
6
|
ArticleBase,
|
8
7
|
ChapterBase,
|
@@ -10,7 +9,7 @@ from fabricatio.models.extra.article_base import (
|
|
10
9
|
SubSectionBase,
|
11
10
|
)
|
12
11
|
from fabricatio.models.extra.article_proposal import ArticleProposal
|
13
|
-
from fabricatio.models.generic import WithRef
|
12
|
+
from fabricatio.models.generic import PersistentAble, WithRef
|
14
13
|
|
15
14
|
|
16
15
|
class ArticleSubsectionOutline(SubSectionBase):
|
fabricatio/models/extra/rule.py
CHANGED
@@ -10,8 +10,7 @@ complex rule management systems.
|
|
10
10
|
|
11
11
|
from typing import List, Self, Tuple, Unpack
|
12
12
|
|
13
|
-
from fabricatio.
|
14
|
-
from fabricatio.models.generic import Language, SketchedAble, WithBriefing
|
13
|
+
from fabricatio.models.generic import Language, PersistentAble, SketchedAble, WithBriefing
|
15
14
|
from more_itertools import flatten
|
16
15
|
|
17
16
|
|
fabricatio/models/generic.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
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
|
+
from datetime import datetime
|
4
5
|
from pathlib import Path
|
5
6
|
from typing import Any, Callable, Dict, Iterable, List, Mapping, Optional, Self, Sequence, Type, Union, final, overload
|
6
7
|
|
@@ -810,3 +811,94 @@ class SequencePatch[T](ProposedUpdateAble, ABC):
|
|
810
811
|
Self: A new instance with an empty list of tweaks.
|
811
812
|
"""
|
812
813
|
return cls(tweaked=[])
|
814
|
+
|
815
|
+
|
816
|
+
class PersistentAble(Base, ABC):
|
817
|
+
"""Class providing file persistence capabilities.
|
818
|
+
|
819
|
+
Enables saving model instances to disk with timestamped filenames and loading from persisted files.
|
820
|
+
Implements basic versioning through filename hashing and timestamping.
|
821
|
+
"""
|
822
|
+
|
823
|
+
def persist(self, path: str | Path) -> Self:
|
824
|
+
"""Save model instance to disk with versioned filename.
|
825
|
+
|
826
|
+
Args:
|
827
|
+
path (str | Path): Target directory or file path. If directory, filename is auto-generated.
|
828
|
+
|
829
|
+
Returns:
|
830
|
+
Self: Current instance for method chaining
|
831
|
+
|
832
|
+
Notes:
|
833
|
+
- Filename format: <ClassName>_<YYYYMMDD_HHMMSS>_<6-char_hash>.json
|
834
|
+
- Hash generated from JSON content ensures uniqueness
|
835
|
+
"""
|
836
|
+
p = Path(path)
|
837
|
+
out = self.model_dump_json(indent=1, by_alias=True)
|
838
|
+
|
839
|
+
# Generate a timestamp in the format YYYYMMDD_HHMMSS
|
840
|
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
841
|
+
|
842
|
+
# Generate the hash
|
843
|
+
file_hash = blake3_hash(out.encode())[:6]
|
844
|
+
|
845
|
+
# Construct the file name with timestamp and hash
|
846
|
+
file_name = f"{self.__class__.__name__}_{timestamp}_{file_hash}.json"
|
847
|
+
|
848
|
+
if p.is_dir():
|
849
|
+
p.joinpath(file_name).write_text(out, encoding="utf-8")
|
850
|
+
else:
|
851
|
+
p.mkdir(exist_ok=True, parents=True)
|
852
|
+
p.write_text(out, encoding="utf-8")
|
853
|
+
|
854
|
+
logger.info(f"Persisted `{self.__class__.__name__}` to {p.as_posix()}")
|
855
|
+
return self
|
856
|
+
|
857
|
+
@classmethod
|
858
|
+
def from_latest_persistent(cls, dir_path: str | Path) -> Optional[Self]:
|
859
|
+
"""Load most recent persisted instance from directory.
|
860
|
+
|
861
|
+
Args:
|
862
|
+
dir_path (str | Path): Directory containing persisted files
|
863
|
+
|
864
|
+
Returns:
|
865
|
+
Self: Most recently modified instance
|
866
|
+
|
867
|
+
Raises:
|
868
|
+
NotADirectoryError: If path is not a valid directory
|
869
|
+
FileNotFoundError: If no matching files found
|
870
|
+
"""
|
871
|
+
dir_path = Path(dir_path)
|
872
|
+
if not dir_path.is_dir():
|
873
|
+
return None
|
874
|
+
|
875
|
+
pattern = f"{cls.__name__}_*.json"
|
876
|
+
files = list(dir_path.glob(pattern))
|
877
|
+
|
878
|
+
if not files:
|
879
|
+
return None
|
880
|
+
|
881
|
+
def _get_timestamp(file_path: Path) -> datetime:
|
882
|
+
stem = file_path.stem
|
883
|
+
parts = stem.split("_")
|
884
|
+
return datetime.strptime(f"{parts[1]}_{parts[2]}", "%Y%m%d_%H%M%S")
|
885
|
+
|
886
|
+
files.sort(key=lambda f: _get_timestamp(f), reverse=True)
|
887
|
+
|
888
|
+
return cls.from_persistent(files.pop(0))
|
889
|
+
|
890
|
+
@classmethod
|
891
|
+
def from_persistent(cls, path: str | Path) -> Self:
|
892
|
+
"""Load an instance from a specific persisted file.
|
893
|
+
|
894
|
+
Args:
|
895
|
+
path (str | Path): Path to the JSON file.
|
896
|
+
|
897
|
+
Returns:
|
898
|
+
Self: The loaded instance from the file.
|
899
|
+
|
900
|
+
Raises:
|
901
|
+
FileNotFoundError: If the specified file does not exist.
|
902
|
+
ValueError: If the file content is invalid for the model.
|
903
|
+
"""
|
904
|
+
return cls.model_validate_json(safe_text_read(path))
|
fabricatio/models/role.py
CHANGED
@@ -30,6 +30,8 @@ class Role(WithBriefing):
|
|
30
30
|
|
31
31
|
registry: Dict[Event, WorkFlow] = Field(default_factory=dict)
|
32
32
|
"""The registry of events and workflows."""
|
33
|
+
dispatch_on_init: bool = True
|
34
|
+
"""Whether to dispatch registered workflows on initialization."""
|
33
35
|
|
34
36
|
def model_post_init(self, __context: Any) -> None:
|
35
37
|
"""Initialize the role by resolving configurations and registering workflows.
|
@@ -39,9 +41,20 @@ class Role(WithBriefing):
|
|
39
41
|
"""
|
40
42
|
self.name = self.name or self.__class__.__name__
|
41
43
|
|
42
|
-
self.
|
44
|
+
if self.dispatch_on_init:
|
45
|
+
self.resolve_configuration().dispatch()
|
43
46
|
|
44
|
-
def
|
47
|
+
def register_workflow(self, event: Event, workflow: WorkFlow) -> Self:
|
48
|
+
"""Register a workflow to the role's registry."""
|
49
|
+
if event in self.registry:
|
50
|
+
logger.warning(
|
51
|
+
f"Event `{event.collapse()}` is already registered with workflow "
|
52
|
+
f"`{self.registry[event].name}`. It will be overwritten by `{workflow.name}`."
|
53
|
+
)
|
54
|
+
self.registry[event] = workflow
|
55
|
+
return self
|
56
|
+
|
57
|
+
def dispatch(self) -> Self:
|
45
58
|
"""Register each workflow in the registry to its corresponding event in the event bus.
|
46
59
|
|
47
60
|
Returns:
|
@@ -63,8 +76,8 @@ class Role(WithBriefing):
|
|
63
76
|
"""
|
64
77
|
for workflow in self.registry.values():
|
65
78
|
logger.debug(f"Resolving config for workflow: `{workflow.name}`")
|
66
|
-
self._configure_scoped_config(workflow)
|
67
|
-
|
79
|
+
self._configure_scoped_config(workflow)._configure_toolbox_usage(workflow)
|
80
|
+
|
68
81
|
workflow.inject_personality(self.briefing)
|
69
82
|
return self
|
70
83
|
|
@@ -74,26 +87,70 @@ class Role(WithBriefing):
|
|
74
87
|
has_capability: Callable[[Type], bool],
|
75
88
|
config_method_name: str,
|
76
89
|
capability_description: str,
|
77
|
-
) ->
|
78
|
-
"""Propagates configuration
|
79
|
-
|
80
|
-
|
90
|
+
) -> Self:
|
91
|
+
"""Propagates configuration from the Role to a Workflow and its Actions.
|
92
|
+
|
93
|
+
This method checks if the Role, Workflow, or its Actions possess a specific
|
94
|
+
capability (e.g., being a ScopedConfig or ToolBoxUsage). If they do,
|
95
|
+
a specified configuration method is called on them to apply or inherit
|
96
|
+
settings.
|
97
|
+
|
98
|
+
The configuration flows hierarchically:
|
99
|
+
1. If the Role has the capability, it's the initial source.
|
100
|
+
2. If the Workflow also has the capability, it can inherit from the Role
|
101
|
+
and then becomes the source for its Actions.
|
102
|
+
3. Actions with the capability inherit from the determined source (either
|
103
|
+
Workflow or Role).
|
81
104
|
|
82
|
-
|
105
|
+
Args:
|
106
|
+
workflow: The WorkFlow instance to configure.
|
107
|
+
has_capability: A callable that takes a Type and returns True if
|
108
|
+
the type possesses the specific capability, False otherwise.
|
109
|
+
config_method_name: The name of the method to call on an object
|
110
|
+
(Role, Workflow, Action) to apply the configuration.
|
111
|
+
For example, "fallback_to" or "supply_tools_from".
|
112
|
+
capability_description: A string describing the capability, used for
|
113
|
+
logging purposes (e.g., "scoped config", "toolbox usage").
|
114
|
+
"""
|
115
|
+
# This variable will hold the object from which Actions should inherit their configuration.
|
116
|
+
# It could be the Role itself or the Workflow, depending on their capabilities.
|
117
|
+
config_source_for_actions = None
|
118
|
+
|
119
|
+
# Check if the Role itself has the capability.
|
120
|
+
if has_capability(self.__class__):
|
121
|
+
# If the Role has the capability, it becomes the initial source for configuration.
|
122
|
+
config_source_for_actions = self
|
123
|
+
|
124
|
+
# Check if the Workflow has the capability.
|
83
125
|
if has_capability(workflow.__class__):
|
84
126
|
logger.debug(
|
85
127
|
f"Configuring {capability_description} inherited from `{self.name}` for workflow: `{workflow.name}`"
|
86
128
|
)
|
87
|
-
|
129
|
+
# If the Role was already identified as a config source,
|
130
|
+
# the Workflow an inherit its configuration directly from the Role.
|
131
|
+
if config_source_for_actions is not None:
|
132
|
+
# Call the specified configuration method on the workflow, passing the Role (self) as the source.
|
133
|
+
getattr(workflow, config_method_name)(config_source_for_actions)
|
134
|
+
|
135
|
+
# After potentially inheriting from the Role, the Workflow itself becomes
|
136
|
+
# the source of configuration for its Actions.
|
88
137
|
config_source_for_actions = workflow
|
89
138
|
|
90
|
-
|
91
|
-
|
139
|
+
# If a configuration source (either Role or Workflow) has been established:
|
140
|
+
if config_source_for_actions is not None:
|
141
|
+
# Iterate over all actions within the workflow.
|
142
|
+
# Filter for actions that possess the specified capability.
|
143
|
+
for action in (act for act in workflow.iter_actions() if has_capability(act.__class__)):
|
144
|
+
# Call the specified configuration method on the action,
|
145
|
+
# passing the determined config_source_for_actions.
|
146
|
+
getattr(action, config_method_name)(config_source_for_actions)
|
147
|
+
|
148
|
+
return self
|
92
149
|
|
93
|
-
def _configure_scoped_config(self, workflow: WorkFlow) ->
|
150
|
+
def _configure_scoped_config(self, workflow: WorkFlow) -> Self:
|
94
151
|
"""Configure scoped configuration for workflow and its actions."""
|
95
|
-
self._propagate_config(workflow, is_scoped_config, "fallback_to", "scoped config")
|
152
|
+
return self._propagate_config(workflow, is_scoped_config, "fallback_to", "scoped config")
|
96
153
|
|
97
|
-
def _configure_toolbox_usage(self, workflow: WorkFlow) ->
|
154
|
+
def _configure_toolbox_usage(self, workflow: WorkFlow) -> Self:
|
98
155
|
"""Configure toolbox usage for workflow and its actions."""
|
99
|
-
self._propagate_config(workflow, is_toolbox_usage, "supply_tools_from", "toolbox usage")
|
156
|
+
return self._propagate_config(workflow, is_toolbox_usage, "supply_tools_from", "toolbox usage")
|
Binary file
|
Binary file
|
Binary file
|
@@ -1,9 +1,10 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: fabricatio
|
3
|
-
Version: 0.3.15.
|
3
|
+
Version: 0.3.15.dev5
|
4
4
|
Classifier: License :: OSI Approved :: MIT License
|
5
5
|
Classifier: Programming Language :: Rust
|
6
6
|
Classifier: Programming Language :: Python :: 3.12
|
7
|
+
Classifier: Programming Language :: Python :: 3.13
|
7
8
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
8
9
|
Classifier: Framework :: AsyncIO
|
9
10
|
Classifier: Framework :: Pydantic :: 2
|
@@ -1,14 +1,14 @@
|
|
1
|
-
fabricatio-0.3.15.
|
2
|
-
fabricatio-0.3.15.
|
3
|
-
fabricatio-0.3.15.
|
4
|
-
fabricatio-0.3.15.
|
5
|
-
fabricatio-0.3.15.
|
1
|
+
fabricatio-0.3.15.dev5.data/scripts/tdown,sha256=kOUNC-Fj426KqvkK1MaOhkmJLpFzpmUadLJiOxMZz1g,4731456
|
2
|
+
fabricatio-0.3.15.dev5.data/scripts/ttm,sha256=1NDJgExOy6aW2zbrXLxqVnEyTOLyduDy8_HD3a7oLro,3937688
|
3
|
+
fabricatio-0.3.15.dev5.dist-info/METADATA,sha256=lBlJJr7OtXs-u0rItYYYIoOJ4GsLLHrAbqvrQdhchhc,5068
|
4
|
+
fabricatio-0.3.15.dev5.dist-info/WHEEL,sha256=OZYXF4emuP5o7uCHyen8StXv3k74AF7eDhQe1rxgOqQ,108
|
5
|
+
fabricatio-0.3.15.dev5.dist-info/licenses/LICENSE,sha256=yDZaTLnOi03bi3Dk6f5IjhLUc5old2yOsihHWU0z-i0,1067
|
6
6
|
fabricatio/__init__.py,sha256=pSLe6QL4zQGaZXfhF9KW4fa1D8chqCQm_7yInCP6Kt8,732
|
7
7
|
fabricatio/actions/__init__.py,sha256=ZMa1LeM5BNeqp-J-D32W-f5bD53-kdXGyt0zuueJofM,47
|
8
8
|
fabricatio/actions/article.py,sha256=DtArcKFQM1jp4f3OKPng9ciqY7TmNIUjrjCaZO3OCg8,16695
|
9
9
|
fabricatio/actions/article_rag.py,sha256=2lQogjV_1iZkbYI4C9kGGpQH9TBeIDaQCkyi7ueqFus,17582
|
10
10
|
fabricatio/actions/fs.py,sha256=nlTmk-tYDW158nz_fzlsNfuYJwj7j4BHn_MFY5hxdqs,934
|
11
|
-
fabricatio/actions/output.py,sha256=
|
11
|
+
fabricatio/actions/output.py,sha256=cLJqeNOhW2vzZB4Tgzh2t09v0flH_eZhDWTxOXUqI7A,9724
|
12
12
|
fabricatio/actions/rag.py,sha256=GuRU6VJzIxo3V8dvGWNQ0uQbu6nF0g_qgVuC8NPRx2Y,3487
|
13
13
|
fabricatio/actions/rules.py,sha256=07ILsiwR250AUcKLPHTUPpWD_mPhPCfWKSkEAKcPv3A,3557
|
14
14
|
fabricatio/capabilities/__init__.py,sha256=skaJ43CqAQaZMH-mCRzF4Fps3x99P2SwJ8vSM9pInX8,56
|
@@ -18,7 +18,6 @@ fabricatio/capabilities/censor.py,sha256=m90gGDAkEkkxkUKcZNkyhYsRwAxkcDut_-gZEBK
|
|
18
18
|
fabricatio/capabilities/check.py,sha256=eiZZaiX78k-Zt7-Ik43Pn5visXHeOJLk8yLWgtqln40,8379
|
19
19
|
fabricatio/capabilities/correct.py,sha256=z7KiMK1KykGXNdLVA0sB28x63LsQ6Hd4wbtYd0bkEKE,10175
|
20
20
|
fabricatio/capabilities/extract.py,sha256=eLQagkRnHVLZ64yPBtLVcPELO7ubJlN3fbwoaNMWT70,2449
|
21
|
-
fabricatio/capabilities/persist.py,sha256=GAbj93lYLnGVPu74H_ImrINGWNAglIDH9aGSLJKMLkw,3318
|
22
21
|
fabricatio/capabilities/propose.py,sha256=KqeXaUURJ6O-Ve0ijZYg88rgQYCZEFbuWoqIepI-nQ8,1965
|
23
22
|
fabricatio/capabilities/rag.py,sha256=VSk4BKN8Clwi28-8bz-roqHRln9vu6mGnozr6snaPeY,10930
|
24
23
|
fabricatio/capabilities/rating.py,sha256=FSIh3h0E7G1OkBKAkY83VA4w0G6OZ2bXq27b40WRsL8,17411
|
@@ -35,24 +34,24 @@ fabricatio/models/adv_kwargs_types.py,sha256=nmj1D0GVosZxKcdiw-B5vJB04Whr5zh30ZB
|
|
35
34
|
fabricatio/models/extra/__init__.py,sha256=0R9eZsCNu6OV-Xtf15H7FrqhfHTFBFf3fBrcd7ChsJ0,53
|
36
35
|
fabricatio/models/extra/advanced_judge.py,sha256=CKPP4Lseb_Ey8Y7i2V9HJfB-mZgCknFdqq7Zo41o6s4,1060
|
37
36
|
fabricatio/models/extra/aricle_rag.py,sha256=KaryVIaMZRV6vpUYwkHDe09tgOihVWGPb1mGs1GXKSw,11723
|
38
|
-
fabricatio/models/extra/article_base.py,sha256=
|
39
|
-
fabricatio/models/extra/article_essence.py,sha256=
|
40
|
-
fabricatio/models/extra/article_main.py,sha256=
|
41
|
-
fabricatio/models/extra/article_outline.py,sha256=
|
42
|
-
fabricatio/models/extra/article_proposal.py,sha256=
|
37
|
+
fabricatio/models/extra/article_base.py,sha256=SD1tQdr20Sah4M8yM9r2KSnTRrx9lkM_3Ya1quiolrc,18394
|
38
|
+
fabricatio/models/extra/article_essence.py,sha256=OGci-Z4NRvaJdMuS2YUpY425rSozdush6z2LlBoWOpA,2647
|
39
|
+
fabricatio/models/extra/article_main.py,sha256=fxIdHEtlPDHCkaZX5azp18V2shloN_h10Gn54ciRUXk,10978
|
40
|
+
fabricatio/models/extra/article_outline.py,sha256=K3Ajb86JQSsjo61briVCkIJkqRwvJ46uNU94NCrW-cY,1584
|
41
|
+
fabricatio/models/extra/article_proposal.py,sha256=4G2qLkMxtK54G1ANgPW0G3w4Pahxgk2lhGPU5KMxuzw,1818
|
43
42
|
fabricatio/models/extra/patches.py,sha256=_ghmnlvTZQq7UJyaH77mTZE9abjvxRJ2mgWHUbezUls,977
|
44
43
|
fabricatio/models/extra/problem.py,sha256=1Sd8hsThQK6pXMXhErRhP1ft58z4PvqeB8AV8VcXiaI,7051
|
45
44
|
fabricatio/models/extra/rag.py,sha256=fwyEXOECQNe8LPUKGAxEcp9vp7o5356rna-TzGpkvnE,3869
|
46
|
-
fabricatio/models/extra/rule.py,sha256=
|
47
|
-
fabricatio/models/generic.py,sha256=
|
45
|
+
fabricatio/models/extra/rule.py,sha256=b756_XmWeDoJ1qOFEGy6ZfP8O7rBjOZs4XvfZvWKXXI,2574
|
46
|
+
fabricatio/models/generic.py,sha256=GTJV5uToM0OFe19B-UgCmM6OFQ7lMg93O7WIcdp_3IA,30092
|
48
47
|
fabricatio/models/kwargs_types.py,sha256=VrzAJaOSlQ-xN5NIIi3k4KpIY0c9beuxcuUnF-mkEEk,3282
|
49
|
-
fabricatio/models/role.py,sha256=
|
48
|
+
fabricatio/models/role.py,sha256=n1vOr6HZH-7-rSYarnJdDKsR1OmGSMXkCmXudAHeOqs,7337
|
50
49
|
fabricatio/models/task.py,sha256=CdR1Zbf-lZN0jODj9iriTn1X2DxLxjXlvZgy3kEd6lI,10723
|
51
50
|
fabricatio/models/tool.py,sha256=jYdN6FWEz6pE-vEh3H78VHDPpSttUQE79nfXOD4FE6U,12091
|
52
51
|
fabricatio/models/usages.py,sha256=bpM-a9i-WpSOh-XL3LiYTa3AxQUd_ckn44lh-uuKM6M,32250
|
53
52
|
fabricatio/parser.py,sha256=3vT5u5SGpzDH4WLJdMwK5CP8RqO4g1MyQUYpiDKDoEo,4528
|
54
53
|
fabricatio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
55
|
-
fabricatio/rust.cpython-313-x86_64-linux-gnu.so,sha256=
|
54
|
+
fabricatio/rust.cpython-313-x86_64-linux-gnu.so,sha256=liZlbr9MJ00X9xQONvi6yGBz-Sy3ZA7ruUkZ4U5LXe4,7921600
|
56
55
|
fabricatio/rust.pyi,sha256=D-YxXyjvX6d1Y5pkjcvv-EjQvxpkeA7qgcTaaHOtJpY,25491
|
57
56
|
fabricatio/toolboxes/__init__.py,sha256=dYm_Gd8XolSU_h4wnkA09dlaLDK146eeFz0CUgPZ8_c,380
|
58
57
|
fabricatio/toolboxes/arithmetic.py,sha256=sSTPkKI6-mb278DwQKFO9jKyzc9kCx45xNH7V6bGBpE,1307
|
@@ -61,4 +60,4 @@ fabricatio/utils.py,sha256=qvl4R8ThuNIIoBJuR1DGEuWYZ7jRFT_8SRx4I_FA8pU,5298
|
|
61
60
|
fabricatio/workflows/__init__.py,sha256=Lq9pFo2cudwFCrQUUNgSTr1CoU0J1Nw-HNEQN7cHLp8,50
|
62
61
|
fabricatio/workflows/articles.py,sha256=ZDV5nqUKRo1GOuuKWeSV7ZI32FYZU7WiTrD4YDuCeEo,945
|
63
62
|
fabricatio/workflows/rag.py,sha256=uOZXprD479fUhLA6sYvEM8RWcVcUZXXtP0xRbTMPdHE,509
|
64
|
-
fabricatio-0.3.15.
|
63
|
+
fabricatio-0.3.15.dev5.dist-info/RECORD,,
|
@@ -1,103 +0,0 @@
|
|
1
|
-
"""Persistence capabilities for model instances."""
|
2
|
-
|
3
|
-
from abc import ABC
|
4
|
-
from datetime import datetime
|
5
|
-
from pathlib import Path
|
6
|
-
from typing import Optional, Self
|
7
|
-
|
8
|
-
from loguru import logger
|
9
|
-
|
10
|
-
from fabricatio.fs import safe_text_read
|
11
|
-
from fabricatio.models.generic import Base
|
12
|
-
from fabricatio.rust import blake3_hash
|
13
|
-
|
14
|
-
|
15
|
-
class PersistentAble(Base, ABC):
|
16
|
-
"""Class providing file persistence capabilities.
|
17
|
-
|
18
|
-
Enables saving model instances to disk with timestamped filenames and loading from persisted files.
|
19
|
-
Implements basic versioning through filename hashing and timestamping.
|
20
|
-
"""
|
21
|
-
|
22
|
-
def persist(self, path: str | Path) -> Self:
|
23
|
-
"""Save model instance to disk with versioned filename.
|
24
|
-
|
25
|
-
Args:
|
26
|
-
path (str | Path): Target directory or file path. If directory, filename is auto-generated.
|
27
|
-
|
28
|
-
Returns:
|
29
|
-
Self: Current instance for method chaining
|
30
|
-
|
31
|
-
Notes:
|
32
|
-
- Filename format: <ClassName>_<YYYYMMDD_HHMMSS>_<6-char_hash>.json
|
33
|
-
- Hash generated from JSON content ensures uniqueness
|
34
|
-
"""
|
35
|
-
p = Path(path)
|
36
|
-
out = self.model_dump_json(indent=1, by_alias=True)
|
37
|
-
|
38
|
-
# Generate a timestamp in the format YYYYMMDD_HHMMSS
|
39
|
-
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
40
|
-
|
41
|
-
# Generate the hash
|
42
|
-
file_hash = blake3_hash(out.encode())[:6]
|
43
|
-
|
44
|
-
# Construct the file name with timestamp and hash
|
45
|
-
file_name = f"{self.__class__.__name__}_{timestamp}_{file_hash}.json"
|
46
|
-
|
47
|
-
if p.is_dir():
|
48
|
-
p.joinpath(file_name).write_text(out, encoding="utf-8")
|
49
|
-
else:
|
50
|
-
p.mkdir(exist_ok=True, parents=True)
|
51
|
-
p.write_text(out, encoding="utf-8")
|
52
|
-
|
53
|
-
logger.info(f"Persisted `{self.__class__.__name__}` to {p.as_posix()}")
|
54
|
-
return self
|
55
|
-
|
56
|
-
@classmethod
|
57
|
-
def from_latest_persistent(cls, dir_path: str | Path) -> Optional[Self]:
|
58
|
-
"""Load most recent persisted instance from directory.
|
59
|
-
|
60
|
-
Args:
|
61
|
-
dir_path (str | Path): Directory containing persisted files
|
62
|
-
|
63
|
-
Returns:
|
64
|
-
Self: Most recently modified instance
|
65
|
-
|
66
|
-
Raises:
|
67
|
-
NotADirectoryError: If path is not a valid directory
|
68
|
-
FileNotFoundError: If no matching files found
|
69
|
-
"""
|
70
|
-
dir_path = Path(dir_path)
|
71
|
-
if not dir_path.is_dir():
|
72
|
-
return None
|
73
|
-
|
74
|
-
pattern = f"{cls.__name__}_*.json"
|
75
|
-
files = list(dir_path.glob(pattern))
|
76
|
-
|
77
|
-
if not files:
|
78
|
-
return None
|
79
|
-
|
80
|
-
def _get_timestamp(file_path: Path) -> datetime:
|
81
|
-
stem = file_path.stem
|
82
|
-
parts = stem.split("_")
|
83
|
-
return datetime.strptime(f"{parts[1]}_{parts[2]}", "%Y%m%d_%H%M%S")
|
84
|
-
|
85
|
-
files.sort(key=lambda f: _get_timestamp(f), reverse=True)
|
86
|
-
|
87
|
-
return cls.from_persistent(files.pop(0))
|
88
|
-
|
89
|
-
@classmethod
|
90
|
-
def from_persistent(cls, path: str | Path) -> Self:
|
91
|
-
"""Load an instance from a specific persisted file.
|
92
|
-
|
93
|
-
Args:
|
94
|
-
path (str | Path): Path to the JSON file.
|
95
|
-
|
96
|
-
Returns:
|
97
|
-
Self: The loaded instance from the file.
|
98
|
-
|
99
|
-
Raises:
|
100
|
-
FileNotFoundError: If the specified file does not exist.
|
101
|
-
ValueError: If the file content is invalid for the model.
|
102
|
-
"""
|
103
|
-
return cls.model_validate_json(safe_text_read(path))
|
Binary file
|
Binary file
|
File without changes
|
File without changes
|