fabricatio 0.2.13.dev3__cp312-cp312-win_amd64.whl → 0.3.14__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 +7 -14
- fabricatio/actions/article.py +58 -23
- fabricatio/actions/article_rag.py +6 -15
- fabricatio/actions/output.py +38 -3
- fabricatio/actions/rag.py +4 -4
- fabricatio/capabilities/advanced_judge.py +4 -7
- fabricatio/capabilities/advanced_rag.py +2 -1
- fabricatio/capabilities/censor.py +5 -4
- fabricatio/capabilities/check.py +6 -7
- fabricatio/capabilities/correct.py +5 -5
- fabricatio/capabilities/extract.py +7 -3
- fabricatio/capabilities/persist.py +103 -0
- fabricatio/capabilities/propose.py +2 -2
- fabricatio/capabilities/rag.py +43 -43
- fabricatio/capabilities/rating.py +11 -10
- fabricatio/capabilities/review.py +8 -6
- fabricatio/capabilities/task.py +22 -22
- fabricatio/decorators.py +4 -2
- fabricatio/{core.py → emitter.py} +35 -39
- fabricatio/fs/__init__.py +1 -2
- fabricatio/journal.py +2 -11
- fabricatio/models/action.py +14 -30
- fabricatio/models/extra/aricle_rag.py +14 -8
- fabricatio/models/extra/article_base.py +56 -25
- fabricatio/models/extra/article_essence.py +2 -1
- fabricatio/models/extra/article_main.py +16 -13
- fabricatio/models/extra/article_outline.py +2 -1
- fabricatio/models/extra/article_proposal.py +1 -1
- fabricatio/models/extra/rag.py +2 -2
- fabricatio/models/extra/rule.py +2 -1
- fabricatio/models/generic.py +56 -166
- fabricatio/models/kwargs_types.py +1 -54
- fabricatio/models/role.py +49 -26
- fabricatio/models/task.py +8 -9
- fabricatio/models/tool.py +7 -7
- fabricatio/models/usages.py +67 -61
- fabricatio/parser.py +60 -100
- fabricatio/rust.cp312-win_amd64.pyd +0 -0
- fabricatio/rust.pyi +469 -74
- fabricatio/utils.py +63 -162
- fabricatio-0.3.14.data/scripts/tdown.exe +0 -0
- fabricatio-0.3.14.data/scripts/ttm.exe +0 -0
- {fabricatio-0.2.13.dev3.dist-info → fabricatio-0.3.14.dist-info}/METADATA +10 -15
- fabricatio-0.3.14.dist-info/RECORD +64 -0
- {fabricatio-0.2.13.dev3.dist-info → fabricatio-0.3.14.dist-info}/WHEEL +1 -1
- fabricatio/config.py +0 -430
- fabricatio/constants.py +0 -20
- fabricatio/models/events.py +0 -120
- fabricatio/rust_instances.py +0 -10
- fabricatio-0.2.13.dev3.data/scripts/tdown.exe +0 -0
- fabricatio-0.2.13.dev3.data/scripts/ttm.exe +0 -0
- fabricatio-0.2.13.dev3.dist-info/RECORD +0 -67
- {fabricatio-0.2.13.dev3.dist-info → fabricatio-0.3.14.dist-info}/licenses/LICENSE +0 -0
fabricatio/__init__.py
CHANGED
@@ -1,36 +1,29 @@
|
|
1
1
|
"""Fabricatio is a Python library for building llm app using event-based agent structure."""
|
2
2
|
|
3
|
-
from fabricatio import actions, capabilities, toolboxes, workflows
|
4
|
-
from fabricatio.core import env
|
3
|
+
from fabricatio import actions, capabilities, fs, models, parser, toolboxes, utils, workflows
|
5
4
|
from fabricatio.journal import logger
|
6
|
-
from fabricatio.models import extra
|
7
5
|
from fabricatio.models.action import Action, WorkFlow
|
8
|
-
from fabricatio.models.events import Event
|
9
6
|
from fabricatio.models.role import Role
|
10
7
|
from fabricatio.models.task import Task
|
11
8
|
from fabricatio.models.tool import ToolBox
|
12
|
-
from fabricatio.
|
13
|
-
from fabricatio.rust import BibManager
|
14
|
-
from fabricatio.rust_instances import TEMPLATE_MANAGER
|
9
|
+
from fabricatio.rust import CONFIG, TEMPLATE_MANAGER, Event
|
15
10
|
|
16
11
|
__all__ = [
|
12
|
+
"CONFIG",
|
17
13
|
"TEMPLATE_MANAGER",
|
18
14
|
"Action",
|
19
|
-
"BibManager",
|
20
|
-
"Capture",
|
21
15
|
"Event",
|
22
|
-
"GenericCapture",
|
23
|
-
"JsonCapture",
|
24
|
-
"PythonCapture",
|
25
16
|
"Role",
|
26
17
|
"Task",
|
27
18
|
"ToolBox",
|
28
19
|
"WorkFlow",
|
29
20
|
"actions",
|
30
21
|
"capabilities",
|
31
|
-
"
|
32
|
-
"extra",
|
22
|
+
"fs",
|
33
23
|
"logger",
|
24
|
+
"models",
|
25
|
+
"parser",
|
34
26
|
"toolboxes",
|
27
|
+
"utils",
|
35
28
|
"workflows",
|
36
29
|
]
|
fabricatio/actions/article.py
CHANGED
@@ -2,29 +2,27 @@
|
|
2
2
|
|
3
3
|
from asyncio import gather
|
4
4
|
from pathlib import Path
|
5
|
-
from typing import Callable, List, Optional
|
5
|
+
from typing import Callable, ClassVar, List, Optional
|
6
6
|
|
7
7
|
from more_itertools import filter_map
|
8
8
|
from pydantic import Field
|
9
9
|
from rich import print as r_print
|
10
10
|
|
11
|
-
from fabricatio import TEMPLATE_MANAGER
|
12
11
|
from fabricatio.capabilities.censor import Censor
|
13
12
|
from fabricatio.capabilities.extract import Extract
|
14
13
|
from fabricatio.capabilities.propose import Propose
|
15
|
-
from fabricatio.config import configs
|
16
14
|
from fabricatio.fs import dump_text, safe_text_read
|
17
15
|
from fabricatio.journal import logger
|
18
16
|
from fabricatio.models.action import Action
|
19
17
|
from fabricatio.models.extra.article_essence import ArticleEssence
|
20
|
-
from fabricatio.models.extra.article_main import Article
|
18
|
+
from fabricatio.models.extra.article_main import Article, ArticleChapter, ArticleSubsection
|
21
19
|
from fabricatio.models.extra.article_outline import ArticleOutline
|
22
20
|
from fabricatio.models.extra.article_proposal import ArticleProposal
|
23
21
|
from fabricatio.models.extra.rule import RuleSet
|
24
22
|
from fabricatio.models.kwargs_types import ValidateKwargs
|
25
23
|
from fabricatio.models.task import Task
|
26
24
|
from fabricatio.models.usages import LLMUsage
|
27
|
-
from fabricatio.rust import BibManager, detect_language
|
25
|
+
from fabricatio.rust import CONFIG, TEMPLATE_MANAGER, BibManager, detect_language
|
28
26
|
from fabricatio.utils import ok, wrapp_in_block
|
29
27
|
|
30
28
|
|
@@ -279,43 +277,80 @@ class LoadArticle(Action):
|
|
279
277
|
class WriteChapterSummary(Action, LLMUsage):
|
280
278
|
"""Write the chapter summary."""
|
281
279
|
|
282
|
-
|
280
|
+
ctx_override: ClassVar[bool] = True
|
283
281
|
|
284
282
|
paragraph_count: int = 1
|
285
283
|
|
286
|
-
summary_word_count: int =
|
287
|
-
|
284
|
+
summary_word_count: int = 120
|
285
|
+
output_key: str = "summarized_article"
|
288
286
|
summary_title: str = "Chapter Summary"
|
289
|
-
write_to: Optional[Path] = None
|
290
287
|
|
291
|
-
|
292
|
-
|
288
|
+
skip_chapters: List[str] = Field(default_factory=list)
|
289
|
+
|
290
|
+
async def _execute(self, article_path: Path, **cxt) -> Article:
|
291
|
+
article = Article.from_article_file(article_path, article_path.stem)
|
292
|
+
|
293
|
+
chaps = [c for c in article.chapters if c.title not in self.skip_chapters]
|
294
|
+
|
295
|
+
retained_chapters = []
|
296
|
+
# Count chapters before filtering based on section presence,
|
297
|
+
# chaps at this point has already been filtered by self.skip_chapters
|
298
|
+
initial_chaps_for_summary_step_count = len(chaps)
|
299
|
+
|
300
|
+
for chapter_candidate in chaps:
|
301
|
+
if chapter_candidate.sections: # Check if the sections list is non-empty
|
302
|
+
retained_chapters.append(chapter_candidate)
|
303
|
+
else:
|
304
|
+
# Log c warning for each chapter skipped due to lack of sections
|
305
|
+
logger.warning(
|
306
|
+
f"Chapter '{chapter_candidate.title}' has no sections and will be skipped for summary generation."
|
307
|
+
)
|
308
|
+
|
309
|
+
chaps = retained_chapters # Update chaps to only include chapters with sections
|
310
|
+
|
311
|
+
# If chaps is now empty, but there were chapters to consider at the start of this step,
|
312
|
+
# log c specific warning.
|
313
|
+
if not chaps and initial_chaps_for_summary_step_count > 0:
|
314
|
+
logger.warning(
|
315
|
+
"All chapters considered for summary were skipped as they lack sections. No summaries will be generated for these."
|
316
|
+
)
|
293
317
|
|
318
|
+
# This line was part of the original selection.
|
319
|
+
# It will now log the titles of the chapters that are actually being processed (those with sections).
|
320
|
+
# If 'chaps' is empty, this will result in logger.info(""), which is acceptable.
|
321
|
+
logger.info(";".join(a.title for a in chaps))
|
294
322
|
ret = [
|
295
|
-
|
323
|
+
ArticleSubsection.from_typst_code(self.summary_title, raw)
|
296
324
|
for raw in (
|
297
325
|
await self.aask(
|
298
326
|
TEMPLATE_MANAGER.render_template(
|
299
|
-
|
327
|
+
CONFIG.templates.chap_summary_template,
|
300
328
|
[
|
301
329
|
{
|
302
|
-
"chapter":
|
303
|
-
"title":
|
304
|
-
"language":
|
330
|
+
"chapter": c.to_typst_code(),
|
331
|
+
"title": c.title,
|
332
|
+
"language": c.language,
|
305
333
|
"summary_word_count": self.summary_word_count,
|
306
334
|
"paragraph_count": self.paragraph_count,
|
307
335
|
}
|
308
|
-
for
|
336
|
+
for c in chaps
|
309
337
|
],
|
310
338
|
)
|
311
339
|
)
|
312
340
|
)
|
313
341
|
]
|
314
342
|
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
343
|
+
for c, n in zip(chaps, ret, strict=True):
|
344
|
+
c: ArticleChapter
|
345
|
+
n: ArticleSubsection
|
346
|
+
if c.sections[-1].title == self.summary_title:
|
347
|
+
c.sections.pop()
|
320
348
|
|
321
|
-
|
349
|
+
c.sections[-1].subsections.append(n)
|
350
|
+
|
351
|
+
article.update_article_file(article_path)
|
352
|
+
|
353
|
+
article_string = safe_text_read(article_path)
|
354
|
+
article_string.replace(f"=== {self.summary_title}", f"== {self.summary_title}")
|
355
|
+
dump_text(article_path, article_string)
|
356
|
+
return article
|
@@ -6,7 +6,6 @@ from typing import ClassVar, List, Optional
|
|
6
6
|
|
7
7
|
from pydantic import Field, PositiveInt
|
8
8
|
|
9
|
-
from fabricatio import BibManager
|
10
9
|
from fabricatio.capabilities.advanced_rag import AdvancedRAG
|
11
10
|
from fabricatio.capabilities.censor import Censor
|
12
11
|
from fabricatio.capabilities.extract import Extract
|
@@ -21,10 +20,8 @@ from fabricatio.models.extra.article_outline import ArticleOutline
|
|
21
20
|
from fabricatio.models.extra.rule import RuleSet
|
22
21
|
from fabricatio.models.kwargs_types import ChooseKwargs, LLMKwargs
|
23
22
|
from fabricatio.rust import (
|
24
|
-
|
25
|
-
|
26
|
-
convert_to_block_formula,
|
27
|
-
convert_to_inline_formula,
|
23
|
+
BibManager,
|
24
|
+
convert_all_tex_math,
|
28
25
|
fix_misplaced_labels,
|
29
26
|
)
|
30
27
|
from fabricatio.utils import ok
|
@@ -129,8 +126,7 @@ class WriteArticleContentRAG(Action, Extract, AdvancedRAG):
|
|
129
126
|
raw_paras = edt
|
130
127
|
|
131
128
|
raw_paras = fix_misplaced_labels(raw_paras)
|
132
|
-
raw_paras =
|
133
|
-
raw_paras = convert_all_block_tex(raw_paras)
|
129
|
+
raw_paras = convert_all_tex_math(raw_paras)
|
134
130
|
|
135
131
|
r_print(raw_paras)
|
136
132
|
|
@@ -153,8 +149,7 @@ class WriteArticleContentRAG(Action, Extract, AdvancedRAG):
|
|
153
149
|
raw_paras = "\n".join(p for p in raw_paras.splitlines() if p and not p.endswith("**") and not p.startswith("#"))
|
154
150
|
|
155
151
|
raw_paras = fix_misplaced_labels(raw_paras)
|
156
|
-
raw_paras =
|
157
|
-
raw_paras = convert_all_block_tex(raw_paras)
|
152
|
+
raw_paras = convert_all_tex_math(raw_paras)
|
158
153
|
|
159
154
|
return await self.extract_new_subsec(subsec, raw_paras, cm)
|
160
155
|
|
@@ -261,8 +256,6 @@ class ArticleConsultRAG(Action, AdvancedRAG):
|
|
261
256
|
from questionary import confirm, text
|
262
257
|
from rich import print as r_print
|
263
258
|
|
264
|
-
from fabricatio.rust import convert_all_block_tex, convert_all_inline_tex, fix_misplaced_labels
|
265
|
-
|
266
259
|
self.target_collection = collection_name or self.safe_target_collection
|
267
260
|
|
268
261
|
cm = CitationManager()
|
@@ -272,8 +265,7 @@ class ArticleConsultRAG(Action, AdvancedRAG):
|
|
272
265
|
if await confirm("Empty the cm?").ask_async():
|
273
266
|
cm.empty()
|
274
267
|
|
275
|
-
req =
|
276
|
-
req = convert_to_inline_formula(req)
|
268
|
+
req = convert_all_tex_math(req)
|
277
269
|
|
278
270
|
await self.clued_search(
|
279
271
|
req,
|
@@ -289,8 +281,7 @@ class ArticleConsultRAG(Action, AdvancedRAG):
|
|
289
281
|
ret = await self.aask(f"{cm.as_prompt()}\n{self.req}\n{req}")
|
290
282
|
|
291
283
|
ret = fix_misplaced_labels(ret)
|
292
|
-
ret =
|
293
|
-
ret = convert_all_block_tex(ret)
|
284
|
+
ret = convert_all_tex_math(ret)
|
294
285
|
ret = cm.apply(ret)
|
295
286
|
|
296
287
|
r_print(ret)
|
fabricatio/actions/output.py
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
"""Dump the finalized output to a file."""
|
2
2
|
|
3
3
|
from pathlib import Path
|
4
|
-
from typing import Any, Iterable, List, Mapping, Optional, Type
|
4
|
+
from typing import Any, Iterable, List, Mapping, Optional, Self, Sequence, Type
|
5
5
|
|
6
|
-
from fabricatio import
|
6
|
+
from fabricatio.capabilities.persist import PersistentAble
|
7
7
|
from fabricatio.fs import dump_text
|
8
8
|
from fabricatio.journal import logger
|
9
9
|
from fabricatio.models.action import Action
|
10
|
-
from fabricatio.models.generic import FinalizedDumpAble, FromMapping,
|
10
|
+
from fabricatio.models.generic import FinalizedDumpAble, FromMapping, FromSequence
|
11
11
|
from fabricatio.models.task import Task
|
12
12
|
from fabricatio.models.usages import LLMUsage
|
13
|
+
from fabricatio.rust import TEMPLATE_MANAGER
|
13
14
|
from fabricatio.utils import ok
|
14
15
|
|
15
16
|
|
@@ -211,3 +212,37 @@ class GatherAsList(Action):
|
|
211
212
|
result = [cxt[k] for k in cxt if k.startswith(self.gather_prefix)]
|
212
213
|
logger.debug(f"Gathered {len(result)} items with prefix {self.gather_prefix}")
|
213
214
|
return result
|
215
|
+
|
216
|
+
|
217
|
+
class Forward(Action, FromMapping, FromSequence):
|
218
|
+
"""Forward the object from the context to the output."""
|
219
|
+
|
220
|
+
output_key: str = "forwarded"
|
221
|
+
"""Gather the objects from the context as a list."""
|
222
|
+
original: str
|
223
|
+
|
224
|
+
async def _execute(self, *_: Any, **cxt) -> Any:
|
225
|
+
source = cxt.get(self.original)
|
226
|
+
if source is None:
|
227
|
+
logger.warning(f"Original object {self.original} not found in the context")
|
228
|
+
return source
|
229
|
+
|
230
|
+
@classmethod
|
231
|
+
def from_sequence(cls, sequence: Sequence[str], *, original: str, **kwargs: Any) -> List[Self]:
|
232
|
+
"""Create a list of `Forward` from the sequence."""
|
233
|
+
return [cls(original=original, output_key=o, **kwargs) for o in sequence]
|
234
|
+
|
235
|
+
@classmethod
|
236
|
+
def from_mapping(cls, mapping: Mapping[str, str | Sequence[str]], **kwargs: Any) -> List[Self]:
|
237
|
+
"""Create a list of `Forward` from the mapping."""
|
238
|
+
actions = []
|
239
|
+
for original_key, output_val in mapping.items():
|
240
|
+
if isinstance(output_val, str):
|
241
|
+
actions.append(cls(original=original_key, output_key=output_val, **kwargs))
|
242
|
+
elif isinstance(output_val, Sequence):
|
243
|
+
actions.extend(cls(original=original_key, output_key=output_key, **kwargs) for output_key in output_val)
|
244
|
+
else:
|
245
|
+
logger.warning(
|
246
|
+
f"Invalid type for output key value in mapping: {type(output_val)} for original key {original_key}. Expected str or Sequence[str]."
|
247
|
+
)
|
248
|
+
return actions
|
fabricatio/actions/rag.py
CHANGED
@@ -3,11 +3,11 @@
|
|
3
3
|
from typing import List, Optional
|
4
4
|
|
5
5
|
from fabricatio.capabilities.rag import RAG
|
6
|
-
from fabricatio.config import configs
|
7
6
|
from fabricatio.journal import logger
|
8
7
|
from fabricatio.models.action import Action
|
9
8
|
from fabricatio.models.extra.rag import MilvusClassicModel, MilvusDataBase
|
10
9
|
from fabricatio.models.task import Task
|
10
|
+
from fabricatio.rust import CONFIG
|
11
11
|
from fabricatio.utils import ok
|
12
12
|
|
13
13
|
|
@@ -19,7 +19,7 @@ class InjectToDB(Action, RAG):
|
|
19
19
|
"""The name of the collection to inject data into."""
|
20
20
|
|
21
21
|
async def _execute[T: MilvusDataBase](
|
22
|
-
|
22
|
+
self, to_inject: Optional[T] | List[Optional[T]], override_inject: bool = False, **_
|
23
23
|
) -> Optional[str]:
|
24
24
|
from pymilvus.milvus_client import IndexParams
|
25
25
|
|
@@ -39,9 +39,9 @@ class InjectToDB(Action, RAG):
|
|
39
39
|
schema=seq[0].as_milvus_schema(
|
40
40
|
ok(
|
41
41
|
self.milvus_dimensions
|
42
|
-
or
|
42
|
+
or CONFIG.rag.milvus_dimensions
|
43
43
|
or self.embedding_dimensions
|
44
|
-
or
|
44
|
+
or CONFIG.embedding.dimensions
|
45
45
|
),
|
46
46
|
),
|
47
47
|
index_params=IndexParams(
|
@@ -1,5 +1,6 @@
|
|
1
1
|
"""The Capabilities module for advanced judging."""
|
2
2
|
|
3
|
+
from abc import ABC
|
3
4
|
from typing import Optional, Unpack
|
4
5
|
|
5
6
|
from fabricatio.capabilities.propose import Propose
|
@@ -7,17 +8,13 @@ from fabricatio.models.extra.advanced_judge import JudgeMent
|
|
7
8
|
from fabricatio.models.kwargs_types import ValidateKwargs
|
8
9
|
|
9
10
|
|
10
|
-
class AdvancedJudge(Propose):
|
11
|
+
class AdvancedJudge(Propose, ABC):
|
11
12
|
"""A class that judges the evidence and makes a final decision."""
|
13
|
+
|
12
14
|
async def evidently_judge(
|
13
15
|
self,
|
14
16
|
prompt: str,
|
15
17
|
**kwargs: Unpack[ValidateKwargs[JudgeMent]],
|
16
18
|
) -> Optional[JudgeMent]:
|
17
19
|
"""Judge the evidence and make a final decision."""
|
18
|
-
return await self.propose(
|
19
|
-
JudgeMent,
|
20
|
-
prompt,
|
21
|
-
**kwargs
|
22
|
-
)
|
23
|
-
|
20
|
+
return await self.propose(JudgeMent, prompt, **kwargs)
|
@@ -1,5 +1,6 @@
|
|
1
1
|
"""Advanced RAG (Retrieval Augmented Generation) model."""
|
2
2
|
|
3
|
+
from abc import ABC
|
3
4
|
from typing import Optional, Unpack
|
4
5
|
|
5
6
|
from fabricatio.capabilities.rag import RAG
|
@@ -10,7 +11,7 @@ from fabricatio.models.kwargs_types import ChooseKwargs
|
|
10
11
|
from fabricatio.utils import fallback_kwargs
|
11
12
|
|
12
13
|
|
13
|
-
class AdvancedRAG(RAG):
|
14
|
+
class AdvancedRAG(RAG, ABC):
|
14
15
|
"""A class representing the Advanced RAG (Retrieval Augmented Generation) model."""
|
15
16
|
|
16
17
|
async def clued_search(
|
@@ -4,6 +4,7 @@ This module includes the Censor class which inherits from both Correct and Check
|
|
4
4
|
It provides methods to censor objects and strings by first checking them against a ruleset and then correcting them if necessary.
|
5
5
|
"""
|
6
6
|
|
7
|
+
from abc import ABC
|
7
8
|
from typing import Optional, Unpack
|
8
9
|
|
9
10
|
from fabricatio.capabilities.check import Check
|
@@ -16,7 +17,7 @@ from fabricatio.models.kwargs_types import ReferencedKwargs
|
|
16
17
|
from fabricatio.utils import override_kwargs
|
17
18
|
|
18
19
|
|
19
|
-
class Censor(Correct, Check):
|
20
|
+
class Censor(Correct, Check, ABC):
|
20
21
|
"""Class to censor objects and strings based on provided rulesets.
|
21
22
|
|
22
23
|
Inherits from both Correct and Check classes.
|
@@ -46,7 +47,7 @@ class Censor(Correct, Check):
|
|
46
47
|
if not imp:
|
47
48
|
logger.info(f"No improvement found for `{obj.__class__.__name__}`.")
|
48
49
|
return obj
|
49
|
-
logger.info(f
|
50
|
+
logger.info(f"Generated {len(imp)} improvement(s) for `{obj.__class__.__name__}")
|
50
51
|
return await self.correct_obj(obj, Improvement.gather(*imp), **kwargs)
|
51
52
|
|
52
53
|
async def censor_string(
|
@@ -72,7 +73,7 @@ class Censor(Correct, Check):
|
|
72
73
|
if not imp:
|
73
74
|
logger.info("No improvement found for string.")
|
74
75
|
return input_text
|
75
|
-
logger.info(f
|
76
|
+
logger.info(f"Generated {len(imp)} improvement(s) for string.")
|
76
77
|
return await self.correct_string(input_text, Improvement.gather(*imp), **kwargs)
|
77
78
|
|
78
79
|
async def censor_obj_inplace[M: ProposedUpdateAble](
|
@@ -100,5 +101,5 @@ class Censor(Correct, Check):
|
|
100
101
|
if not imp:
|
101
102
|
logger.info(f"No improvement found for `{obj.__class__.__name__}`.")
|
102
103
|
return obj
|
103
|
-
logger.info(f
|
104
|
+
logger.info(f"Generated {len(imp)} improvement(s) for `{obj.__class__.__name__}")
|
104
105
|
return await self.correct_obj_inplace(obj, improvement=Improvement.gather(*imp), **kwargs)
|
fabricatio/capabilities/check.py
CHANGED
@@ -1,23 +1,22 @@
|
|
1
1
|
"""A class that provides the capability to check strings and objects against rules and guidelines."""
|
2
2
|
|
3
|
+
from abc import ABC
|
3
4
|
from asyncio import gather
|
4
5
|
from typing import List, Optional, Unpack
|
5
6
|
|
6
|
-
from fabricatio import TEMPLATE_MANAGER
|
7
7
|
from fabricatio.capabilities.advanced_judge import AdvancedJudge
|
8
8
|
from fabricatio.capabilities.propose import Propose
|
9
|
-
from fabricatio.config import configs
|
10
9
|
from fabricatio.journal import logger
|
11
10
|
from fabricatio.models.extra.patches import RuleSetMetadata
|
12
11
|
from fabricatio.models.extra.problem import Improvement
|
13
12
|
from fabricatio.models.extra.rule import Rule, RuleSet
|
14
13
|
from fabricatio.models.generic import Display, WithBriefing
|
15
14
|
from fabricatio.models.kwargs_types import ValidateKwargs
|
16
|
-
from fabricatio.rust import detect_language
|
15
|
+
from fabricatio.rust import CONFIG, TEMPLATE_MANAGER, detect_language
|
17
16
|
from fabricatio.utils import override_kwargs
|
18
17
|
|
19
18
|
|
20
|
-
class Check(AdvancedJudge, Propose):
|
19
|
+
class Check(AdvancedJudge, Propose, ABC):
|
21
20
|
"""Class for validating strings/objects against predefined rules and guidelines.
|
22
21
|
|
23
22
|
This capability combines rule-based judgment and proposal generation to provide
|
@@ -45,7 +44,7 @@ class Check(AdvancedJudge, Propose):
|
|
45
44
|
rule_reqs = (
|
46
45
|
await self.alist_str(
|
47
46
|
TEMPLATE_MANAGER.render_template(
|
48
|
-
|
47
|
+
CONFIG.templates.ruleset_requirement_breakdown_template,
|
49
48
|
{"ruleset_requirement": ruleset_requirement},
|
50
49
|
),
|
51
50
|
rule_count,
|
@@ -61,7 +60,7 @@ class Check(AdvancedJudge, Propose):
|
|
61
60
|
rules = await self.propose(
|
62
61
|
Rule,
|
63
62
|
[
|
64
|
-
TEMPLATE_MANAGER.render_template(
|
63
|
+
TEMPLATE_MANAGER.render_template(CONFIG.templates.rule_requirement_template, {"rule_requirement": r})
|
65
64
|
for r in rule_reqs
|
66
65
|
],
|
67
66
|
**kwargs,
|
@@ -112,7 +111,7 @@ class Check(AdvancedJudge, Propose):
|
|
112
111
|
return await self.propose(
|
113
112
|
Improvement,
|
114
113
|
TEMPLATE_MANAGER.render_template(
|
115
|
-
|
114
|
+
CONFIG.templates.check_string_template,
|
116
115
|
{"to_check": input_text, "rule": rule.display(), "judge": judge.display(), "reference": reference},
|
117
116
|
),
|
118
117
|
**kwargs,
|
@@ -1,11 +1,11 @@
|
|
1
1
|
"""A module containing the Correct capability for reviewing, validating, and improving objects."""
|
2
2
|
|
3
|
+
from abc import ABC
|
3
4
|
from asyncio import gather
|
4
5
|
from typing import Optional, Type, Unpack, cast
|
5
6
|
|
6
7
|
from fabricatio.capabilities.propose import Propose
|
7
8
|
from fabricatio.capabilities.rating import Rating
|
8
|
-
from fabricatio.config import configs
|
9
9
|
from fabricatio.journal import logger
|
10
10
|
from fabricatio.models.adv_kwargs_types import CorrectKwargs
|
11
11
|
from fabricatio.models.extra.problem import Improvement, ProblemSolutions
|
@@ -14,11 +14,11 @@ from fabricatio.models.kwargs_types import (
|
|
14
14
|
BestKwargs,
|
15
15
|
ValidateKwargs,
|
16
16
|
)
|
17
|
-
from fabricatio.
|
17
|
+
from fabricatio.rust import CONFIG, TEMPLATE_MANAGER
|
18
18
|
from fabricatio.utils import fallback_kwargs, ok, override_kwargs
|
19
19
|
|
20
20
|
|
21
|
-
class Correct(Rating, Propose):
|
21
|
+
class Correct(Rating, Propose, ABC):
|
22
22
|
"""A class that provides the capability to correct objects."""
|
23
23
|
|
24
24
|
async def decide_solution(
|
@@ -92,7 +92,7 @@ class Correct(Rating, Propose):
|
|
92
92
|
return await self.propose(
|
93
93
|
cast("Type[M]", obj.__class__),
|
94
94
|
TEMPLATE_MANAGER.render_template(
|
95
|
-
|
95
|
+
CONFIG.templates.fix_troubled_obj_template,
|
96
96
|
{
|
97
97
|
"problem": problem_solutions.problem.display(),
|
98
98
|
"solution": ok(
|
@@ -125,7 +125,7 @@ class Correct(Rating, Propose):
|
|
125
125
|
"""
|
126
126
|
return await self.ageneric_string(
|
127
127
|
TEMPLATE_MANAGER.render_template(
|
128
|
-
|
128
|
+
CONFIG.templates.fix_troubled_string_template,
|
129
129
|
{
|
130
130
|
"problem": problem_solutions.problem.display(),
|
131
131
|
"solution": ok(
|
@@ -1,15 +1,16 @@
|
|
1
1
|
"""A module that provide capabilities for extracting information from a given source to a model."""
|
2
2
|
|
3
|
+
from abc import ABC
|
3
4
|
from typing import List, Optional, Type, Unpack, overload
|
4
5
|
|
5
6
|
from fabricatio import TEMPLATE_MANAGER
|
6
7
|
from fabricatio.capabilities.propose import Propose
|
7
|
-
from fabricatio.config import configs
|
8
8
|
from fabricatio.models.generic import ProposedAble
|
9
9
|
from fabricatio.models.kwargs_types import ValidateKwargs
|
10
|
+
from fabricatio.rust import CONFIG
|
10
11
|
|
11
12
|
|
12
|
-
class Extract(Propose):
|
13
|
+
class Extract(Propose, ABC):
|
13
14
|
"""A class that extract information from a given source to a model."""
|
14
15
|
|
15
16
|
@overload
|
@@ -21,6 +22,7 @@ class Extract(Propose):
|
|
21
22
|
align_language: bool = True,
|
22
23
|
**kwargs: Unpack[ValidateKwargs[M]],
|
23
24
|
) -> M: ...
|
25
|
+
|
24
26
|
@overload
|
25
27
|
async def extract[M: ProposedAble](
|
26
28
|
self,
|
@@ -40,6 +42,7 @@ class Extract(Propose):
|
|
40
42
|
align_language: bool = True,
|
41
43
|
**kwargs: Unpack[ValidateKwargs[M]],
|
42
44
|
) -> List[M]: ...
|
45
|
+
|
43
46
|
@overload
|
44
47
|
async def extract[M: ProposedAble](
|
45
48
|
self,
|
@@ -49,6 +52,7 @@ class Extract(Propose):
|
|
49
52
|
align_language: bool = True,
|
50
53
|
**kwargs: Unpack[ValidateKwargs[None]],
|
51
54
|
) -> List[Optional[M]]: ...
|
55
|
+
|
52
56
|
async def extract[M: ProposedAble](
|
53
57
|
self,
|
54
58
|
cls: Type[M],
|
@@ -61,7 +65,7 @@ class Extract(Propose):
|
|
61
65
|
return await self.propose(
|
62
66
|
cls,
|
63
67
|
prompt=TEMPLATE_MANAGER.render_template(
|
64
|
-
|
68
|
+
CONFIG.templates.extract_template,
|
65
69
|
[{"source": s, "extract_requirement": extract_requirement} for s in source]
|
66
70
|
if isinstance(source, list)
|
67
71
|
else {"source": source, "extract_requirement": extract_requirement, "align_language": align_language},
|
@@ -0,0 +1,103 @@
|
|
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))
|