fabricatio 0.2.8.dev1__cp312-cp312-win_amd64.whl → 0.2.8.dev2__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/_rust.cp312-win_amd64.pyd +0 -0
- fabricatio/_rust.pyi +50 -0
- fabricatio/actions/article.py +38 -16
- fabricatio/actions/article_rag.py +74 -19
- fabricatio/actions/output.py +36 -4
- fabricatio/fs/curd.py +4 -0
- fabricatio/models/action.py +5 -4
- fabricatio/models/extra/advanced_judge.py +11 -4
- fabricatio/models/extra/article_base.py +12 -6
- fabricatio/models/extra/article_essence.py +57 -12
- fabricatio/models/extra/article_main.py +5 -0
- fabricatio/models/extra/article_proposal.py +19 -1
- fabricatio/models/generic.py +24 -11
- fabricatio-0.2.8.dev2.data/scripts/tdown.exe +0 -0
- {fabricatio-0.2.8.dev1.dist-info → fabricatio-0.2.8.dev2.dist-info}/METADATA +1 -1
- {fabricatio-0.2.8.dev1.dist-info → fabricatio-0.2.8.dev2.dist-info}/RECORD +18 -18
- fabricatio-0.2.8.dev1.data/scripts/tdown.exe +0 -0
- {fabricatio-0.2.8.dev1.dist-info → fabricatio-0.2.8.dev2.dist-info}/WHEEL +0 -0
- {fabricatio-0.2.8.dev1.dist-info → fabricatio-0.2.8.dev2.dist-info}/licenses/LICENSE +0 -0
Binary file
|
fabricatio/_rust.pyi
CHANGED
@@ -122,3 +122,53 @@ class BibManager:
|
|
122
122
|
Returns:
|
123
123
|
List of all titles in the bibliography
|
124
124
|
"""
|
125
|
+
|
126
|
+
def get_author_by_key(self, key: str) -> Optional[List[str]]:
|
127
|
+
"""Retrieve authors by citation key.
|
128
|
+
|
129
|
+
Args:
|
130
|
+
key: Citation key
|
131
|
+
|
132
|
+
Returns:
|
133
|
+
List of authors if found, None otherwise
|
134
|
+
"""
|
135
|
+
|
136
|
+
def get_year_by_key(self, key: str) -> Optional[int]:
|
137
|
+
"""Retrieve the publication year by citation key.
|
138
|
+
|
139
|
+
Args:
|
140
|
+
key: Citation key
|
141
|
+
|
142
|
+
Returns:
|
143
|
+
Publication year if found, None otherwise
|
144
|
+
"""
|
145
|
+
|
146
|
+
def get_abstract_by_key(self, key: str) -> Optional[str]:
|
147
|
+
"""Retrieve the abstract by citation key.
|
148
|
+
|
149
|
+
Args:
|
150
|
+
key: Citation key
|
151
|
+
|
152
|
+
Returns:
|
153
|
+
Abstract if found, None otherwise
|
154
|
+
"""
|
155
|
+
def get_title_by_key(self, key: str) -> Optional[str]:
|
156
|
+
"""Retrieve the title by citation key.
|
157
|
+
|
158
|
+
Args:
|
159
|
+
key: Citation key
|
160
|
+
|
161
|
+
Returns:
|
162
|
+
Title if found, None otherwise
|
163
|
+
"""
|
164
|
+
|
165
|
+
def get_field_by_key(self, key: str, field: str)-> Optional[str]:
|
166
|
+
"""Retrieve a specific field by citation key.
|
167
|
+
|
168
|
+
Args:
|
169
|
+
key: Citation key
|
170
|
+
field: Field name
|
171
|
+
|
172
|
+
Returns:
|
173
|
+
Field value if found, None otherwise
|
174
|
+
"""
|
fabricatio/actions/article.py
CHANGED
@@ -4,6 +4,7 @@ from asyncio import gather
|
|
4
4
|
from pathlib import Path
|
5
5
|
from typing import Any, Callable, List, Optional
|
6
6
|
|
7
|
+
from fabricatio._rust import BibManager
|
7
8
|
from fabricatio.capabilities.advanced_judge import AdvancedJudge
|
8
9
|
from fabricatio.fs import safe_text_read
|
9
10
|
from fabricatio.journal import logger
|
@@ -40,11 +41,27 @@ class ExtractArticleEssence(Action):
|
|
40
41
|
|
41
42
|
# trim the references
|
42
43
|
contents = ["References".join(c.split("References")[:-1]) for c in map(reader, task_input.dependencies)]
|
43
|
-
return await self.propose(
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
44
|
+
return await self.propose(ArticleEssence, contents, **self.prepend_sys_msg())
|
45
|
+
|
46
|
+
|
47
|
+
class FixArticleEssence(Action):
|
48
|
+
"""Fix the article essence based on the bibtex key."""
|
49
|
+
|
50
|
+
async def _execute(
|
51
|
+
self,
|
52
|
+
bib_mgr: BibManager,
|
53
|
+
article_essence: List[ArticleEssence],
|
54
|
+
**_,
|
55
|
+
) -> None:
|
56
|
+
for a in article_essence:
|
57
|
+
if key := (bib_mgr.get_cite_key(a.title) or bib_mgr.get_cite_key_fuzzy(a.title)):
|
58
|
+
a.title = bib_mgr.get_title_by_key(key) or a.title
|
59
|
+
a.authors = bib_mgr.get_author_by_key(key) or a.authors
|
60
|
+
a.publication_year = bib_mgr.get_year_by_key(key) or a.publication_year
|
61
|
+
a.bibtex_cite_key = key
|
62
|
+
logger.info(f'Updated {a.title} with {key}')
|
63
|
+
else:
|
64
|
+
logger.warning(f"No key found for {a.title}")
|
48
65
|
|
49
66
|
|
50
67
|
class GenerateArticleProposal(Action):
|
@@ -108,7 +125,7 @@ class GenerateInitialOutline(Action):
|
|
108
125
|
**self.prepend_sys_msg(),
|
109
126
|
),
|
110
127
|
"Could not generate the initial outline.",
|
111
|
-
)
|
128
|
+
).update_ref(article_proposal)
|
112
129
|
|
113
130
|
|
114
131
|
class FixIntrospectedErrors(Action):
|
@@ -120,6 +137,7 @@ class FixIntrospectedErrors(Action):
|
|
120
137
|
async def _execute(
|
121
138
|
self,
|
122
139
|
article_outline: ArticleOutline,
|
140
|
+
supervisor_check: bool = False,
|
123
141
|
**_,
|
124
142
|
) -> Optional[ArticleOutline]:
|
125
143
|
introspect_manual = ok(
|
@@ -141,7 +159,7 @@ class FixIntrospectedErrors(Action):
|
|
141
159
|
reference=f"# Original Article Outline\n{article_outline.display()}\n# Error Need to be fixed\n{err}",
|
142
160
|
topic=intro_topic,
|
143
161
|
rating_manual=introspect_manual,
|
144
|
-
supervisor_check=
|
162
|
+
supervisor_check=supervisor_check,
|
145
163
|
),
|
146
164
|
"Could not correct the component.",
|
147
165
|
)
|
@@ -159,6 +177,7 @@ class FixIllegalReferences(Action):
|
|
159
177
|
async def _execute(
|
160
178
|
self,
|
161
179
|
article_outline: ArticleOutline,
|
180
|
+
supervisor_check: bool = False,
|
162
181
|
**_,
|
163
182
|
) -> Optional[ArticleOutline]:
|
164
183
|
ref_manual = ok(
|
@@ -177,10 +196,10 @@ class FixIllegalReferences(Action):
|
|
177
196
|
ok(
|
178
197
|
await self.correct_obj_inplace(
|
179
198
|
ref,
|
180
|
-
reference=f"# Original Article Outline\n{article_outline.display()}\n# Error Need to be fixed\n{err}
|
199
|
+
reference=f"# Original Article Outline\n{article_outline.display()}\n# Error Need to be fixed\n{err}",
|
181
200
|
topic=ref_topic,
|
182
201
|
rating_manual=ref_manual,
|
183
|
-
supervisor_check=
|
202
|
+
supervisor_check=supervisor_check,
|
184
203
|
)
|
185
204
|
)
|
186
205
|
return article_outline.update_ref(article_outline)
|
@@ -194,7 +213,7 @@ class TweakOutlineBackwardRef(Action, AdvancedJudge):
|
|
194
213
|
|
195
214
|
output_key: str = "article_outline_bw_ref_checked"
|
196
215
|
|
197
|
-
async def _execute(self, article_outline: ArticleOutline, **cxt) -> ArticleOutline:
|
216
|
+
async def _execute(self, article_outline: ArticleOutline, supervisor_check: bool = False, **cxt) -> ArticleOutline:
|
198
217
|
tweak_depend_on_manual = ok(
|
199
218
|
await self.draft_rating_manual(
|
200
219
|
topic := "Ensure prerequisites are correctly referenced in the `depend_on` field."
|
@@ -207,14 +226,15 @@ class TweakOutlineBackwardRef(Action, AdvancedJudge):
|
|
207
226
|
f"{article_outline.as_prompt()}\n\n{a.display()}\n"
|
208
227
|
f"Does the `{a.__class__.__name__}`'s `depend_on` field need to be extended or tweaked?"
|
209
228
|
):
|
210
|
-
patch=ArticleRefPatch.default()
|
211
|
-
patch.tweaked=a.depend_on
|
229
|
+
patch = ArticleRefPatch.default()
|
230
|
+
patch.tweaked = a.depend_on
|
212
231
|
|
213
232
|
await self.correct_obj_inplace(
|
214
233
|
patch,
|
215
234
|
topic=topic,
|
216
235
|
reference=f"{article_outline.as_prompt()}\nThe Article component whose `depend_on` field needs to be extended or tweaked",
|
217
236
|
rating_manual=tweak_depend_on_manual,
|
237
|
+
supervisor_check=supervisor_check,
|
218
238
|
)
|
219
239
|
|
220
240
|
return article_outline
|
@@ -228,7 +248,7 @@ class TweakOutlineForwardRef(Action, AdvancedJudge):
|
|
228
248
|
|
229
249
|
output_key: str = "article_outline_fw_ref_checked"
|
230
250
|
|
231
|
-
async def _execute(self, article_outline: ArticleOutline, **cxt) -> ArticleOutline:
|
251
|
+
async def _execute(self, article_outline: ArticleOutline, supervisor_check: bool = False, **cxt) -> ArticleOutline:
|
232
252
|
tweak_support_to_manual = ok(
|
233
253
|
await self.draft_rating_manual(
|
234
254
|
topic := "Ensure conclusions support the analysis of subsequent chapters, sections or subsections."
|
@@ -241,14 +261,15 @@ class TweakOutlineForwardRef(Action, AdvancedJudge):
|
|
241
261
|
f"{article_outline.as_prompt()}\n\n{a.display()}\n"
|
242
262
|
f"Does the `{a.__class__.__name__}`'s `support_to` field need to be extended or tweaked?"
|
243
263
|
):
|
244
|
-
patch=ArticleRefPatch.default()
|
245
|
-
patch.tweaked=a.support_to
|
264
|
+
patch = ArticleRefPatch.default()
|
265
|
+
patch.tweaked = a.support_to
|
246
266
|
|
247
267
|
await self.correct_obj_inplace(
|
248
268
|
patch,
|
249
269
|
topic=topic,
|
250
270
|
reference=f"{article_outline.as_prompt()}\nThe Article component whose `support_to` field needs to be extended or tweaked",
|
251
271
|
rating_manual=tweak_support_to_manual,
|
272
|
+
supervisor_check=supervisor_check,
|
252
273
|
)
|
253
274
|
|
254
275
|
return article_outline
|
@@ -263,6 +284,7 @@ class GenerateArticle(Action):
|
|
263
284
|
async def _execute(
|
264
285
|
self,
|
265
286
|
article_outline: ArticleOutline,
|
287
|
+
supervisor_check: bool = False,
|
266
288
|
**_,
|
267
289
|
) -> Optional[Article]:
|
268
290
|
article: Article = Article.from_outline(ok(article_outline, "Article outline not specified.")).update_ref(
|
@@ -280,7 +302,7 @@ class GenerateArticle(Action):
|
|
280
302
|
reference=f"# Original Article Outline\n{article_outline.display()}\n# Error Need to be fixed\n{err}",
|
281
303
|
topic=w_topic,
|
282
304
|
rating_manual=write_para_manual,
|
283
|
-
supervisor_check=
|
305
|
+
supervisor_check=supervisor_check,
|
284
306
|
)
|
285
307
|
for _, __, subsec in article.iter_subsections()
|
286
308
|
if (err := subsec.introspect())
|
@@ -1,35 +1,90 @@
|
|
1
1
|
"""A module for writing articles using RAG (Retrieval-Augmented Generation) capabilities."""
|
2
2
|
|
3
|
-
from
|
3
|
+
from asyncio import gather
|
4
|
+
from typing import Dict, Optional
|
4
5
|
|
5
6
|
from fabricatio.capabilities.rag import RAG
|
6
|
-
from fabricatio.journal import logger
|
7
7
|
from fabricatio.models.action import Action
|
8
|
-
from fabricatio.models.extra.article_main import Article
|
9
|
-
from fabricatio.models.
|
8
|
+
from fabricatio.models.extra.article_main import Article, ArticleParagraphPatch, ArticleSubsection
|
9
|
+
from fabricatio.models.utils import ok
|
10
10
|
|
11
11
|
|
12
|
-
class
|
12
|
+
class TweakArticleRAG(Action, RAG):
|
13
13
|
"""Write an article based on the provided outline."""
|
14
14
|
|
15
|
-
output_key: str = "
|
15
|
+
output_key: str = "rag_tweaked_article"
|
16
16
|
|
17
|
-
async def _execute(
|
17
|
+
async def _execute(
|
18
|
+
self,
|
19
|
+
article: Article,
|
20
|
+
collection_name: str = "article_essence",
|
21
|
+
citation_requirement: str = "# Citation Format\n"
|
22
|
+
"Use correct citation format based on author count. Cite using author surnames and year:"
|
23
|
+
"For 3+ authors: 'Author1, Author2 et al. (YYYY)'"
|
24
|
+
"For 2 authors: 'Author1 & Author2 (YYYY)'"
|
25
|
+
"Single author: 'Author1 (YYYY)'"
|
26
|
+
"Multiple citations: 'Author1 (YYYY), Author2 (YYYY)'"
|
27
|
+
"Prioritize formulas from reference highlights."
|
28
|
+
"Specify authors/years only - no numeric citations"
|
29
|
+
"Paragraphs must exceed 2-3 sentences",
|
30
|
+
supervisor_check: bool = False,
|
31
|
+
parallel: bool = False,
|
32
|
+
**cxt,
|
33
|
+
) -> Optional[Article]:
|
18
34
|
"""Write an article based on the provided outline."""
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
35
|
+
criteria = await self.draft_rating_criteria(
|
36
|
+
topic := "choose appropriate reference to insert into the article, "
|
37
|
+
"making conclusions or reasoning based on concrete evidence instead of unreliable guesses."
|
38
|
+
"Extensively use formulas highlighted in reference文献 should be translated to 'references'."
|
39
|
+
"Only specify authors and years without numeric citation numbers (like [1],[2])."
|
40
|
+
"Each paragraph should not end with just 2-3 sentences for better readability.",
|
41
|
+
criteria_count=13,
|
25
42
|
)
|
26
43
|
|
44
|
+
tweak_manual = ok(
|
45
|
+
await self.draft_rating_manual(topic, criteria=criteria, co_extractor={"model": "openai/qwen-max"})
|
46
|
+
)
|
47
|
+
self.view(collection_name)
|
27
48
|
|
28
|
-
|
29
|
-
|
49
|
+
if parallel:
|
50
|
+
await gather(
|
51
|
+
*[
|
52
|
+
self._inner(article, subsec, supervisor_check, citation_requirement, topic, tweak_manual)
|
53
|
+
for _, __, subsec in article.iter_subsections()
|
54
|
+
],
|
55
|
+
return_exceptions=True,
|
56
|
+
)
|
57
|
+
else:
|
58
|
+
for _, __, subsec in article.iter_subsections():
|
59
|
+
await self._inner(article, subsec, supervisor_check, citation_requirement, topic, tweak_manual)
|
30
60
|
|
31
|
-
|
61
|
+
return article
|
32
62
|
|
33
|
-
async def
|
34
|
-
|
35
|
-
|
63
|
+
async def _inner(
|
64
|
+
self,
|
65
|
+
article: Article,
|
66
|
+
subsec: ArticleSubsection,
|
67
|
+
supervisor_check: bool,
|
68
|
+
citation_requirement: str,
|
69
|
+
topic: str,
|
70
|
+
tweak_manual: Dict[str, str],
|
71
|
+
) -> None:
|
72
|
+
refind_q = ok(
|
73
|
+
await self.arefined_query(
|
74
|
+
f"{article.referenced.as_prompt()}\n"
|
75
|
+
f"# Subsection requiring reference enhancement\n"
|
76
|
+
f"{subsec.display()}\n"
|
77
|
+
f"# Requirement\n"
|
78
|
+
f"Search related articles in the base to find reference candidates, "
|
79
|
+
f"prioritizing both original article language and English usage",
|
80
|
+
)
|
81
|
+
)
|
82
|
+
patch = ArticleParagraphPatch.default()
|
83
|
+
patch.tweaked = subsec.paragraphs
|
84
|
+
await self.correct_obj_inplace(
|
85
|
+
patch,
|
86
|
+
reference=f"{await self.aretrieve_compact(refind_q, final_limit=50)}\n{citation_requirement}",
|
87
|
+
topic=topic,
|
88
|
+
rating_manual=tweak_manual,
|
89
|
+
supervisor_check=supervisor_check,
|
90
|
+
)
|
fabricatio/actions/output.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
"""Dump the finalized output to a file."""
|
2
2
|
|
3
3
|
from pathlib import Path
|
4
|
-
from typing import Optional
|
4
|
+
from typing import Iterable, List, Optional, Type
|
5
5
|
|
6
6
|
from fabricatio.journal import logger
|
7
7
|
from fabricatio.models.action import Action
|
@@ -14,6 +14,7 @@ class DumpFinalizedOutput(Action):
|
|
14
14
|
"""Dump the finalized output to a file."""
|
15
15
|
|
16
16
|
output_key: str = "dump_path"
|
17
|
+
dump_path: Optional[str] = None
|
17
18
|
|
18
19
|
async def _execute(
|
19
20
|
self,
|
@@ -24,6 +25,7 @@ class DumpFinalizedOutput(Action):
|
|
24
25
|
) -> str:
|
25
26
|
dump_path = Path(
|
26
27
|
dump_path
|
28
|
+
or self.dump_path
|
27
29
|
or ok(
|
28
30
|
await self.awhich_pathstr(
|
29
31
|
f"{ok(task_input, 'Neither `task_input` and `dump_path` is provided.').briefing}\n\nExtract a single path of the file, to which I will dump the data."
|
@@ -39,6 +41,7 @@ class PersistentAll(Action):
|
|
39
41
|
"""Persist all the data to a file."""
|
40
42
|
|
41
43
|
output_key: str = "persistent_count"
|
44
|
+
persist_dir: Optional[str] = None
|
42
45
|
|
43
46
|
async def _execute(
|
44
47
|
self,
|
@@ -48,6 +51,7 @@ class PersistentAll(Action):
|
|
48
51
|
) -> int:
|
49
52
|
persist_dir = Path(
|
50
53
|
persist_dir
|
54
|
+
or self.persist_dir
|
51
55
|
or ok(
|
52
56
|
await self.awhich_pathstr(
|
53
57
|
f"{ok(task_input, 'Neither `task_input` and `dump_path` is provided.').briefing}\n\nExtract a single path of the file, to which I will persist the data."
|
@@ -60,10 +64,38 @@ class PersistentAll(Action):
|
|
60
64
|
if persist_dir.is_file():
|
61
65
|
logger.warning("Dump should be a directory, but it is a file. Skip dumping.")
|
62
66
|
return count
|
63
|
-
|
64
|
-
for v in cxt.
|
67
|
+
|
68
|
+
for k, v in cxt.items():
|
69
|
+
final_dir = persist_dir.joinpath(k)
|
70
|
+
final_dir.mkdir(parents=True, exist_ok=True)
|
65
71
|
if isinstance(v, PersistentAble):
|
66
|
-
v.persist(
|
72
|
+
v.persist(final_dir)
|
67
73
|
count += 1
|
74
|
+
if isinstance(v, Iterable) and any(
|
75
|
+
persistent_ables := (pers for pers in v if isinstance(pers, PersistentAble))
|
76
|
+
):
|
77
|
+
for per in persistent_ables:
|
78
|
+
per.persist(final_dir)
|
79
|
+
count += 1
|
68
80
|
|
69
81
|
return count
|
82
|
+
|
83
|
+
|
84
|
+
class RetrieveFromPersistent[T: PersistentAble](Action):
|
85
|
+
"""Retrieve the object from the persistent file."""
|
86
|
+
|
87
|
+
output_key: str = "retrieved_obj"
|
88
|
+
"""Retrieve the object from the persistent file."""
|
89
|
+
load_path: str
|
90
|
+
"""The path of the persistent file or directory contains multiple file."""
|
91
|
+
retrieve_cls: Type[T]
|
92
|
+
"""The class of the object to retrieve."""
|
93
|
+
|
94
|
+
async def _execute(self, /, **__) -> Optional[T | List[T]]:
|
95
|
+
logger.info(f"Retrieve `{self.retrieve_cls.__name__}` from persistent file: {self.load_path}")
|
96
|
+
if not (p := Path(self.load_path)).exists():
|
97
|
+
return None
|
98
|
+
|
99
|
+
if p.is_dir():
|
100
|
+
return [self.retrieve_cls.from_persistent(per) for per in p.glob("*")]
|
101
|
+
return self.retrieve_cls.from_persistent(self.load_path)
|
fabricatio/fs/curd.py
CHANGED
@@ -145,5 +145,9 @@ def gather_files(directory: str | Path | PathLike, extension: str) -> list[str]:
|
|
145
145
|
|
146
146
|
Returns:
|
147
147
|
list[str]: A list of file paths with the specified extension.
|
148
|
+
|
149
|
+
Example:
|
150
|
+
>>> gather_files('/path/to/directory', 'txt')
|
151
|
+
['/path/to/directory/file1.txt', '/path/to/directory/file2.txt']
|
148
152
|
"""
|
149
153
|
return [file.as_posix() for file in Path(directory).rglob(f"*.{extension}")]
|
fabricatio/models/action.py
CHANGED
@@ -104,7 +104,7 @@ class WorkFlow(WithBriefing, ToolBoxUsage):
|
|
104
104
|
_instances: Tuple[Action, ...] = PrivateAttr(default_factory=tuple)
|
105
105
|
"""Instantiated action objects to be executed in this workflow."""
|
106
106
|
|
107
|
-
steps: Tuple[Union[Type[Action], Action], ...] = Field(
|
107
|
+
steps: Tuple[Union[Type[Action], Action], ...] = Field(frozen=True,)
|
108
108
|
"""The sequence of actions to be executed, can be action classes or instances."""
|
109
109
|
|
110
110
|
task_input_key: str = Field(default="task_input")
|
@@ -157,13 +157,14 @@ class WorkFlow(WithBriefing, ToolBoxUsage):
|
|
157
157
|
# Process each action in sequence
|
158
158
|
for step in self._instances:
|
159
159
|
current_action = step.name
|
160
|
-
logger.info(f"Executing step
|
160
|
+
logger.info(f"Executing step >> {current_action}")
|
161
161
|
|
162
162
|
# Get current context and execute action
|
163
163
|
context = await self._context.get()
|
164
164
|
act_task = create_task(step.act(context))
|
165
165
|
# Handle task cancellation
|
166
166
|
if task.is_cancelled():
|
167
|
+
logger.warning(f"Task cancelled by task: {task.name}")
|
167
168
|
act_task.cancel(f"Cancelled by task: {task.name}")
|
168
169
|
break
|
169
170
|
|
@@ -171,7 +172,7 @@ class WorkFlow(WithBriefing, ToolBoxUsage):
|
|
171
172
|
modified_ctx = await act_task
|
172
173
|
logger.success(f"Step execution finished: {current_action}")
|
173
174
|
if step.output_key:
|
174
|
-
logger.success(f"Setting output
|
175
|
+
logger.success(f"Setting output to `{step.output_key}`")
|
175
176
|
await self._context.put(modified_ctx)
|
176
177
|
|
177
178
|
logger.success(f"Workflow execution finished: {self.name}")
|
@@ -182,7 +183,7 @@ class WorkFlow(WithBriefing, ToolBoxUsage):
|
|
182
183
|
|
183
184
|
if self.task_output_key not in final_ctx:
|
184
185
|
logger.warning(
|
185
|
-
f"Task output key: {self.task_output_key} not found in the context, None will be returned. "
|
186
|
+
f"Task output key: `{self.task_output_key}` not found in the context, None will be returned. "
|
186
187
|
f"You can check if `Action.output_key` is set the same as `WorkFlow.task_output_key`."
|
187
188
|
)
|
188
189
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
"""
|
1
|
+
"""Module containing the JudgeMent class for holding judgment results."""
|
2
2
|
|
3
3
|
from typing import List
|
4
4
|
|
@@ -6,7 +6,10 @@ from fabricatio.models.generic import ProposedAble
|
|
6
6
|
|
7
7
|
|
8
8
|
class JudgeMent(ProposedAble):
|
9
|
-
"""
|
9
|
+
"""Represents a judgment result containing supporting/denying evidence and final verdict.
|
10
|
+
|
11
|
+
The class stores both affirmative and denies evidence lists along with the final boolean judgment.
|
12
|
+
"""
|
10
13
|
|
11
14
|
affirm_evidence: List[str]
|
12
15
|
"""List of evidence supporting the affirmation."""
|
@@ -15,8 +18,12 @@ class JudgeMent(ProposedAble):
|
|
15
18
|
"""List of evidence supporting the denial."""
|
16
19
|
|
17
20
|
final_judgement: bool
|
18
|
-
"""The final
|
21
|
+
"""The final judgment made according to all extracted evidence."""
|
19
22
|
|
20
23
|
def __bool__(self) -> bool:
|
21
|
-
"""Return the final
|
24
|
+
"""Return the final judgment value.
|
25
|
+
|
26
|
+
Returns:
|
27
|
+
bool: The stored final_judgement value indicating the judgment result.
|
28
|
+
"""
|
22
29
|
return self.final_judgement
|
@@ -122,24 +122,30 @@ class ArticleMetaData(CensoredAble, Display):
|
|
122
122
|
"""Do not add any prefix or suffix to the title. should not contain special characters."""
|
123
123
|
|
124
124
|
|
125
|
-
class
|
126
|
-
"""
|
127
|
-
|
128
|
-
tweaked: List[ArticleRef]
|
129
|
-
"""Tweaked refs"""
|
125
|
+
class Patch[T](ProposedUpdateAble, Display):
|
126
|
+
"""Base class for patches."""
|
130
127
|
|
128
|
+
tweaked: List[T]
|
129
|
+
"""Tweaked content list"""
|
131
130
|
def update_from_inner(self, other: Self) -> Self:
|
132
131
|
"""Updates the current instance with the attributes of another instance."""
|
133
132
|
self.tweaked.clear()
|
134
133
|
self.tweaked.extend(other.tweaked)
|
135
134
|
return self
|
136
135
|
|
136
|
+
|
137
137
|
@classmethod
|
138
|
-
def default(cls) ->
|
138
|
+
def default(cls) -> Self:
|
139
139
|
"""Defaults to empty list."""
|
140
140
|
return cls(tweaked=[])
|
141
141
|
|
142
142
|
|
143
|
+
class ArticleRefPatch(Patch[ArticleRef]):
|
144
|
+
"""Patch for article refs."""
|
145
|
+
|
146
|
+
|
147
|
+
|
148
|
+
|
143
149
|
class ArticleOutlineBase(
|
144
150
|
ArticleMetaData,
|
145
151
|
ResolveUpdateConflict,
|
@@ -1,8 +1,8 @@
|
|
1
1
|
"""ArticleEssence: Semantic fingerprint of academic paper for structured analysis."""
|
2
2
|
|
3
|
-
from typing import List
|
3
|
+
from typing import List, Self
|
4
4
|
|
5
|
-
from fabricatio.models.generic import Display, PrepareVectorization, ProposedAble
|
5
|
+
from fabricatio.models.generic import Display, PersistentAble, PrepareVectorization, ProposedAble
|
6
6
|
from pydantic import BaseModel, Field
|
7
7
|
|
8
8
|
|
@@ -20,12 +20,49 @@ class Equation(BaseModel):
|
|
20
20
|
Example: "Defines constrained search space dimensionality reduction. Used in architecture optimization phase (Section 3.2). Enables 40% parameter reduction."
|
21
21
|
"""
|
22
22
|
|
23
|
-
|
24
|
-
"""
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
23
|
+
typst_code: str
|
24
|
+
r"""The typst code for the equation, including the equation itself and any necessary formatting.
|
25
|
+
#let x = 5 // Define a code variable
|
26
|
+
|
27
|
+
// Basic syntax examples
|
28
|
+
$x^2$ // Inline formula
|
29
|
+
$ x^2 $ // Block formula (spaces before/after $ for standalone display)
|
30
|
+
|
31
|
+
// Variables and text handling
|
32
|
+
$ A = pi r^2 $ // Single-letter variables as-is
|
33
|
+
$"area" = pi dot "radius"^2 $ // Multi-letter variables in quotes
|
34
|
+
$ cal(A) := { x in RR | x "is natural" } $ // Calligraphic font and text
|
35
|
+
$ #x < 17 $ // Access code variables with #
|
36
|
+
|
37
|
+
// Symbols and shorthands
|
38
|
+
$x < y => x gt.eq.not y $ // Symbol shorthand (=> for ⇒, gt.eq.not for ≯)
|
39
|
+
|
40
|
+
// Multi-line equations with alignment
|
41
|
+
$ sum_(k=0)^n k
|
42
|
+
&= 1 + ... + n \
|
43
|
+
&= (n(n+1))/2 $ // Multi-line with & alignment
|
44
|
+
|
45
|
+
// Function calls and formatting
|
46
|
+
$ frac(a^2, 2) $ // Fraction
|
47
|
+
$ vec(1, 2, delim: "[") $ // Custom vector delimiter
|
48
|
+
$ mat(1, 2; 3, 4) $ // 2D matrix (semicolon separates rows)
|
49
|
+
$ mat(..#range(1, 5).chunks(2)) $ // Dynamic matrix with array expansion
|
50
|
+
|
51
|
+
// Advanced alignment example
|
52
|
+
$ (3x + y)/7 &= 9 && "given" \
|
53
|
+
3x + y &= 63 & "multiply by 7" \
|
54
|
+
3x &= 63 - y && "subtract y" \
|
55
|
+
x &= 21 - y/3 & "divide by 3" $
|
56
|
+
// && skips a column alignment (left/right alternation)
|
57
|
+
|
58
|
+
// Math font configuration
|
59
|
+
#show math.equation: set text(font: "Fira Math") // Set math font (requires Fira Math installed)
|
60
|
+
$ sum_(i in NN) 1 + i $ // Display with new font
|
61
|
+
|
62
|
+
// Escaping and special syntax
|
63
|
+
$ frac(a\,, b) $ // Escape comma to display as literal
|
64
|
+
$ f(x; y) $ // Literal semicolon (not for 2D arrays)
|
65
|
+
$ lim_x = op("lim", limits: #true)_x $ // Custom operator with limits
|
29
66
|
"""
|
30
67
|
|
31
68
|
|
@@ -133,11 +170,11 @@ class Highlightings(BaseModel):
|
|
133
170
|
"""
|
134
171
|
|
135
172
|
|
136
|
-
class ArticleEssence(ProposedAble, Display, PrepareVectorization):
|
137
|
-
"""ArticleEssence is a structured representation of the core elements of a scientific article."""
|
173
|
+
class ArticleEssence(ProposedAble, Display, PersistentAble, PrepareVectorization):
|
174
|
+
"""ArticleEssence is a structured representation of the core elements of a scientific article,using its original language."""
|
138
175
|
|
139
|
-
language: str
|
140
|
-
"""Language of the original article."""
|
176
|
+
language: str
|
177
|
+
"""Language of the original article, note that you should not attempt to translate the original language when generating JSON."""
|
141
178
|
|
142
179
|
title: str = Field(...)
|
143
180
|
"""Exact title of the original article without any modification.
|
@@ -219,5 +256,13 @@ class ArticleEssence(ProposedAble, Display, PrepareVectorization):
|
|
219
256
|
Example:
|
220
257
|
'Predicted 150+ citations via integration into MMEngine (Alibaba OpenMMLab)'"""
|
221
258
|
|
259
|
+
bibtex_cite_key: str
|
260
|
+
"""Bibtex cite_key of the original article."""
|
261
|
+
|
262
|
+
def update_cite_key(self, new_cite_key: str) -> Self:
|
263
|
+
"""Update the bibtex_cite_key of the article."""
|
264
|
+
self.bibtex_cite_key = new_cite_key
|
265
|
+
return self
|
266
|
+
|
222
267
|
def _prepare_vectorization_inner(self) -> str:
|
223
268
|
return self.model_dump_json()
|
@@ -8,6 +8,7 @@ from fabricatio.models.extra.article_base import (
|
|
8
8
|
ArticleBase,
|
9
9
|
ArticleOutlineBase,
|
10
10
|
ChapterBase,
|
11
|
+
Patch,
|
11
12
|
SectionBase,
|
12
13
|
SubSectionBase,
|
13
14
|
)
|
@@ -31,6 +32,10 @@ class Paragraph(CensoredAble):
|
|
31
32
|
"""The actual content of the paragraph, represented as a string."""
|
32
33
|
|
33
34
|
|
35
|
+
class ArticleParagraphPatch(Patch[Paragraph]):
|
36
|
+
"""Patch for `Paragraph` list of `ArticleSubsection`."""
|
37
|
+
|
38
|
+
|
34
39
|
class ArticleSubsection(SubSectionBase):
|
35
40
|
"""Atomic argumentative unit with technical specificity."""
|
36
41
|
|
@@ -29,5 +29,23 @@ class ArticleProposal(CensoredAble, Display, WithRef[str], AsPrompt, PersistentA
|
|
29
29
|
research_aim: List[str]
|
30
30
|
"""A list of primary research objectives that the paper seeks to achieve."""
|
31
31
|
|
32
|
+
literature_review: List[str]
|
33
|
+
"""A list of key references and literature that support the research context and background."""
|
34
|
+
|
35
|
+
expected_outcomes: List[str]
|
36
|
+
"""A list of anticipated results or contributions that the research aims to achieve."""
|
37
|
+
|
38
|
+
keywords: List[str]
|
39
|
+
"""A list of keywords that represent the main topics and focus areas of the research."""
|
40
|
+
|
41
|
+
abstract: str
|
42
|
+
"""A concise summary of the research proposal, outlining the main points and objectives."""
|
43
|
+
|
44
|
+
min_word_count: int
|
45
|
+
"""The minimum number of words required for the research proposal."""
|
46
|
+
|
32
47
|
def _as_prompt_inner(self) -> Dict[str, str]:
|
33
|
-
return {
|
48
|
+
return {
|
49
|
+
"ArticleBriefing": self.referenced,
|
50
|
+
"ArticleProposal": self.display(),
|
51
|
+
}
|
fabricatio/models/generic.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
"""This module defines generic classes for models in the Fabricatio library."""
|
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, Optional, Self, Union, final, overload
|
6
7
|
|
@@ -93,7 +94,9 @@ class WithRef[T](Base):
|
|
93
94
|
@property
|
94
95
|
def referenced(self) -> T:
|
95
96
|
"""Get the referenced object."""
|
96
|
-
return ok(
|
97
|
+
return ok(
|
98
|
+
self._reference, f"`{self.__class__.__name__}`' s `_reference` field is None. Have you called `update_ref`?"
|
99
|
+
)
|
97
100
|
|
98
101
|
def update_ref[S: "WithRef"](self: S, reference: T | S) -> S: # noqa: PYI019
|
99
102
|
"""Update the reference of the object."""
|
@@ -118,17 +121,27 @@ class PersistentAble(Base):
|
|
118
121
|
"""
|
119
122
|
p = Path(path)
|
120
123
|
out = self.model_dump_json(indent=1)
|
124
|
+
|
125
|
+
# Generate a timestamp in the format YYYYMMDD_HHMMSS
|
126
|
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
127
|
+
|
128
|
+
# Generate the hash
|
129
|
+
file_hash = blake3_hash(out.encode())[:6]
|
130
|
+
|
131
|
+
# Construct the file name with timestamp and hash
|
132
|
+
file_name = f"{self.__class__.__name__}_{timestamp}_{file_hash}.json"
|
133
|
+
|
121
134
|
if p.is_dir():
|
122
|
-
p.joinpath(
|
123
|
-
|
124
|
-
)
|
125
|
-
|
126
|
-
|
127
|
-
p.
|
128
|
-
logger.info(f"Persisted {self} to {p.as_posix()}")
|
135
|
+
p.joinpath(file_name).write_text(out, encoding="utf-8")
|
136
|
+
else:
|
137
|
+
p.mkdir(exist_ok=True, parents=True)
|
138
|
+
p.write_text(out, encoding="utf-8")
|
139
|
+
|
140
|
+
logger.info(f"Persisted `{self.__class__.__name__}` to {p.as_posix()}")
|
129
141
|
return self
|
130
142
|
|
131
|
-
|
143
|
+
@classmethod
|
144
|
+
def from_persistent(cls, path: str | Path) -> Self:
|
132
145
|
"""Load the object from a file.
|
133
146
|
|
134
147
|
Args:
|
@@ -137,7 +150,7 @@ class PersistentAble(Base):
|
|
137
150
|
Returns:
|
138
151
|
Self: The current instance of the object.
|
139
152
|
"""
|
140
|
-
return
|
153
|
+
return cls.model_validate_json(Path(path).read_text(encoding="utf-8"))
|
141
154
|
|
142
155
|
|
143
156
|
class ModelHash(Base):
|
@@ -308,7 +321,7 @@ class ProposedAble(CreateJsonObjPrompt, InstantiateFromString):
|
|
308
321
|
"""Class that provides a method to propose a JSON object based on the requirement."""
|
309
322
|
|
310
323
|
|
311
|
-
class ProposedUpdateAble(
|
324
|
+
class ProposedUpdateAble(ProposedAble, UpdateFrom, ABC):
|
312
325
|
"""Make the obj can be updated from the proposed obj in place."""
|
313
326
|
|
314
327
|
|
Binary file
|
@@ -1,9 +1,9 @@
|
|
1
|
-
fabricatio-0.2.8.
|
2
|
-
fabricatio-0.2.8.
|
3
|
-
fabricatio-0.2.8.
|
4
|
-
fabricatio/actions/article.py,sha256=
|
5
|
-
fabricatio/actions/article_rag.py,sha256=
|
6
|
-
fabricatio/actions/output.py,sha256=
|
1
|
+
fabricatio-0.2.8.dev2.dist-info/METADATA,sha256=jSG3EsC4mXSR7vZlV1ZCFmjZ-dAAB6QEWB7sCVsMFaE,5259
|
2
|
+
fabricatio-0.2.8.dev2.dist-info/WHEEL,sha256=jABKVkLC9kJr8mi_er5jOqpiQUjARSLXDUIIxDqsS50,96
|
3
|
+
fabricatio-0.2.8.dev2.dist-info/licenses/LICENSE,sha256=do7J7EiCGbq0QPbMAL_FqLYufXpHnCnXBOuqVPwSV8Y,1088
|
4
|
+
fabricatio/actions/article.py,sha256=FcpNfiKhFOTZ1TE5NJdoNAk_cHndJuB8lZ6_CrpBB7o,13185
|
5
|
+
fabricatio/actions/article_rag.py,sha256=UqL7eZR9dDZ5oK7i7vCQcZHA0gmj4Zl-L3dAjnyoWzk,3795
|
6
|
+
fabricatio/actions/output.py,sha256=FpHQkY_EO5XnyUxM5bvoAMOBc_ZRuu6E0QMlX3i8SXQ,3629
|
7
7
|
fabricatio/actions/rag.py,sha256=QBdzEM8MloM_ahx5pTBZAETm9_631lTe_0ih_he_Iuo,2759
|
8
8
|
fabricatio/capabilities/advanced_judge.py,sha256=selB0Gwf1F4gGJlwBiRo6gI4KOUROgh3WnzO3mZFEls,706
|
9
9
|
fabricatio/capabilities/correct.py,sha256=2093ggHkY8vQW8fl7VwXC8u39oW1xsfjxDjGoQ5puOA,7269
|
@@ -15,19 +15,19 @@ fabricatio/capabilities/task.py,sha256=vtS0YOe639vN8iTrkP2WK0AJVCr5N_JAaJuvRGyY2
|
|
15
15
|
fabricatio/config.py,sha256=hUv5XMzOkEw8cQjsVHTpPPix52IKwmxjBsZM6Px3xZI,16915
|
16
16
|
fabricatio/core.py,sha256=VQ_JKgUGIy2gZ8xsTBZCdr_IP7wC5aPg0_bsOmjQ588,6458
|
17
17
|
fabricatio/decorators.py,sha256=C0Gi7wcXC-0sWITqsSv3JdBGcgVJOlRvOt0FfO0aUsA,7554
|
18
|
-
fabricatio/fs/curd.py,sha256=
|
18
|
+
fabricatio/fs/curd.py,sha256=p8y0LGKgVDk-CWOlm37E6wg7RK6RCD6denKo-VsW28c,4763
|
19
19
|
fabricatio/fs/readers.py,sha256=EZKN_AZdrp8DggJECP53QHw3uHeSDf-AwCAA_V7fNKU,1202
|
20
20
|
fabricatio/fs/__init__.py,sha256=PCf0s_9KDjVfNw7AfPoJzGt3jMq4gJOfbcT4pb0D0ZY,588
|
21
21
|
fabricatio/journal.py,sha256=stnEP88aUBA_GmU9gfTF2EZI8FS2OyMLGaMSTgK4QgA,476
|
22
|
-
fabricatio/models/action.py,sha256=
|
22
|
+
fabricatio/models/action.py,sha256=xYuwnDO9T2sKWT8erQTqelW5AICpgOE5Tp6XVpZ4lN8,8976
|
23
23
|
fabricatio/models/events.py,sha256=QvlnS8FEELg6KNabcJMeh2GV_y0ZBzKOPphcteKYWYU,4183
|
24
|
-
fabricatio/models/extra/advanced_judge.py,sha256=
|
25
|
-
fabricatio/models/extra/article_base.py,sha256=
|
26
|
-
fabricatio/models/extra/article_essence.py,sha256
|
27
|
-
fabricatio/models/extra/article_main.py,sha256=
|
24
|
+
fabricatio/models/extra/advanced_judge.py,sha256=mjJMps65Wfm5uJVREss5ndOqCFLheFdz9rJ9QLg5IvU,910
|
25
|
+
fabricatio/models/extra/article_base.py,sha256=zZ2Gn_VssBL8LZ7hJ-id064tE9AW3HHDyqo5J9PBtDc,15891
|
26
|
+
fabricatio/models/extra/article_essence.py,sha256=XqnOnNmnWtje0H61UqQZh5h36yTVYjTMqo_KY2wogWg,10806
|
27
|
+
fabricatio/models/extra/article_main.py,sha256=402wYN00ymHJDPb7gX5n-MBFPseIGfb8fezBn8NTgkA,8213
|
28
28
|
fabricatio/models/extra/article_outline.py,sha256=jFbVgiwlo7rnwCGS6ToVgeMUOoRe99Edgbx95THR6z8,1450
|
29
|
-
fabricatio/models/extra/article_proposal.py,sha256=
|
30
|
-
fabricatio/models/generic.py,sha256=
|
29
|
+
fabricatio/models/extra/article_proposal.py,sha256=L2kPvH1XCCQSNcI1KQU3ULGq7C24Y88ssugX43LgbsE,2043
|
30
|
+
fabricatio/models/generic.py,sha256=5ZnnNaVK5hFp8c87NtyX6zBolEauEOeLSUP7PK0CXRo,19648
|
31
31
|
fabricatio/models/kwargs_types.py,sha256=chJ-rHaeBVRUPuORHuGR3DdNxxTUrotz0eflPEh4l4w,5474
|
32
32
|
fabricatio/models/role.py,sha256=mmQbJ6GKr2Gx3wtjEz8d-vYoXs09ffcEkT_eCXaDd3E,2782
|
33
33
|
fabricatio/models/task.py,sha256=8NaR7ojQWyM740EDTqt9stwHKdrD6axCRpLKo0QzS-I,10492
|
@@ -41,9 +41,9 @@ fabricatio/toolboxes/fs.py,sha256=l4L1CVxJmjw9Ld2XUpIlWfV0_Fu_2Og6d3E13I-S4aE,73
|
|
41
41
|
fabricatio/toolboxes/__init__.py,sha256=KBJi5OG_pExscdlM7Bnt_UF43j4I3Lv6G71kPVu4KQU,395
|
42
42
|
fabricatio/workflows/articles.py,sha256=G5HGRr-DHuYuEcfhFdFAuDvTTJ9aSU_UQ2yYXEjTMtM,1047
|
43
43
|
fabricatio/workflows/rag.py,sha256=-YYp2tlE9Vtfgpg6ROpu6QVO8j8yVSPa6yDzlN3qVxs,520
|
44
|
-
fabricatio/_rust.pyi,sha256=
|
44
|
+
fabricatio/_rust.pyi,sha256=1MAPGjFWw2RaxgVNBqOb6wSwxAf6YrcikD51T_K4QWA,5102
|
45
45
|
fabricatio/_rust_instances.py,sha256=2GwF8aVfYNemRI2feBzH1CZfBGno-XJJE5imJokGEYw,314
|
46
46
|
fabricatio/__init__.py,sha256=SzBYsRhZeL77jLtfJEjmoHOSwHwUGyvMATX6xfndLDM,1135
|
47
|
-
fabricatio/_rust.cp312-win_amd64.pyd,sha256=
|
48
|
-
fabricatio-0.2.8.
|
49
|
-
fabricatio-0.2.8.
|
47
|
+
fabricatio/_rust.cp312-win_amd64.pyd,sha256=44oKDBFbAF02G5WneLn3_UaN9jYSNsJXAlS96_wbPhM,1885696
|
48
|
+
fabricatio-0.2.8.dev2.data/scripts/tdown.exe,sha256=YRgDNGlGCqN9QmhcifAM3KHLWzk4e_OVy4jXCsj42s0,3401216
|
49
|
+
fabricatio-0.2.8.dev2.dist-info/RECORD,,
|
Binary file
|
File without changes
|
File without changes
|