fabricatio 0.2.8.dev2__cp312-cp312-manylinux_2_34_x86_64.whl → 0.2.8.dev4__cp312-cp312-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/_rust.cpython-312-x86_64-linux-gnu.so +0 -0
- fabricatio/_rust.pyi +1 -1
- fabricatio/actions/article.py +112 -121
- fabricatio/actions/article_rag.py +55 -45
- fabricatio/actions/output.py +4 -3
- fabricatio/actions/rag.py +3 -3
- fabricatio/capabilities/censor.py +87 -0
- fabricatio/capabilities/check.py +194 -0
- fabricatio/capabilities/correct.py +142 -98
- fabricatio/capabilities/propose.py +20 -4
- fabricatio/capabilities/rag.py +3 -2
- fabricatio/capabilities/rating.py +67 -22
- fabricatio/capabilities/review.py +18 -187
- fabricatio/capabilities/task.py +8 -9
- fabricatio/config.py +11 -3
- fabricatio/models/action.py +8 -5
- fabricatio/models/adv_kwargs_types.py +25 -0
- fabricatio/models/extra/advanced_judge.py +10 -7
- fabricatio/models/extra/article_base.py +47 -27
- fabricatio/models/extra/article_essence.py +40 -209
- fabricatio/models/extra/article_main.py +3 -4
- fabricatio/models/extra/patches.py +7 -0
- fabricatio/models/extra/problem.py +153 -0
- fabricatio/models/extra/rule.py +21 -0
- fabricatio/models/generic.py +71 -37
- fabricatio/models/kwargs_types.py +23 -17
- fabricatio/models/role.py +4 -1
- fabricatio/models/usages.py +17 -20
- fabricatio/models/utils.py +0 -46
- fabricatio/parser.py +7 -8
- fabricatio/utils.py +54 -0
- fabricatio-0.2.8.dev4.data/scripts/tdown +0 -0
- {fabricatio-0.2.8.dev2.dist-info → fabricatio-0.2.8.dev4.dist-info}/METADATA +2 -1
- fabricatio-0.2.8.dev4.dist-info/RECORD +56 -0
- fabricatio-0.2.8.dev2.data/scripts/tdown +0 -0
- fabricatio-0.2.8.dev2.dist-info/RECORD +0 -49
- {fabricatio-0.2.8.dev2.dist-info → fabricatio-0.2.8.dev4.dist-info}/WHEEL +0 -0
- {fabricatio-0.2.8.dev2.dist-info → fabricatio-0.2.8.dev4.dist-info}/licenses/LICENSE +0 -0
Binary file
|
fabricatio/_rust.pyi
CHANGED
fabricatio/actions/article.py
CHANGED
@@ -5,20 +5,24 @@ from pathlib import Path
|
|
5
5
|
from typing import Any, Callable, List, Optional
|
6
6
|
|
7
7
|
from fabricatio._rust import BibManager
|
8
|
-
from fabricatio.capabilities.
|
8
|
+
from fabricatio.capabilities.censor import Censor
|
9
|
+
from fabricatio.capabilities.correct import Correct
|
10
|
+
from fabricatio.capabilities.propose import Propose
|
9
11
|
from fabricatio.fs import safe_text_read
|
10
12
|
from fabricatio.journal import logger
|
11
13
|
from fabricatio.models.action import Action
|
12
|
-
from fabricatio.models.extra.article_base import
|
14
|
+
from fabricatio.models.extra.article_base import ArticleRefSequencePatch
|
13
15
|
from fabricatio.models.extra.article_essence import ArticleEssence
|
14
16
|
from fabricatio.models.extra.article_main import Article
|
15
17
|
from fabricatio.models.extra.article_outline import ArticleOutline
|
16
18
|
from fabricatio.models.extra.article_proposal import ArticleProposal
|
19
|
+
from fabricatio.models.extra.rule import RuleSet
|
17
20
|
from fabricatio.models.task import Task
|
18
|
-
from fabricatio.
|
21
|
+
from fabricatio.utils import ok
|
22
|
+
from more_itertools import filter_map
|
19
23
|
|
20
24
|
|
21
|
-
class ExtractArticleEssence(Action):
|
25
|
+
class ExtractArticleEssence(Action, Propose):
|
22
26
|
"""Extract the essence of article(s) in text format from the paths specified in the task dependencies.
|
23
27
|
|
24
28
|
Notes:
|
@@ -32,39 +36,65 @@ class ExtractArticleEssence(Action):
|
|
32
36
|
async def _execute(
|
33
37
|
self,
|
34
38
|
task_input: Task,
|
35
|
-
reader: Callable[[str], str] = lambda p: Path(p).read_text(encoding="utf-8"),
|
39
|
+
reader: Callable[[str], Optional[str]] = lambda p: Path(p).read_text(encoding="utf-8"),
|
36
40
|
**_,
|
37
|
-
) ->
|
41
|
+
) -> List[ArticleEssence]:
|
38
42
|
if not task_input.dependencies:
|
39
43
|
logger.info(err := "Task not approved, since no dependencies are provided.")
|
40
44
|
raise RuntimeError(err)
|
41
|
-
|
45
|
+
logger.info(f"Extracting article essence from {len(task_input.dependencies)} files.")
|
42
46
|
# trim the references
|
43
|
-
contents =
|
44
|
-
|
47
|
+
contents = list(filter_map(reader, task_input.dependencies))
|
48
|
+
logger.info(f"Read {len(task_input.dependencies)} to get {len(contents)} contents.")
|
49
|
+
|
50
|
+
out = []
|
51
|
+
|
52
|
+
for ess in await self.propose(
|
53
|
+
ArticleEssence,
|
54
|
+
[
|
55
|
+
f"{c}\n\n\nBased the provided academic article above, you need to extract the essence from it."
|
56
|
+
for c in contents
|
57
|
+
],
|
58
|
+
):
|
59
|
+
if ess is None:
|
60
|
+
logger.warning("Could not extract article essence")
|
61
|
+
else:
|
62
|
+
out.append(ess)
|
63
|
+
logger.info(f"Extracted {len(out)} article essence from {len(task_input.dependencies)} files.")
|
64
|
+
return out
|
45
65
|
|
46
66
|
|
47
67
|
class FixArticleEssence(Action):
|
48
68
|
"""Fix the article essence based on the bibtex key."""
|
49
69
|
|
70
|
+
output_key: str = "fixed_article_essence"
|
71
|
+
"""The key of the output data."""
|
72
|
+
|
50
73
|
async def _execute(
|
51
74
|
self,
|
52
75
|
bib_mgr: BibManager,
|
53
76
|
article_essence: List[ArticleEssence],
|
54
77
|
**_,
|
55
|
-
) ->
|
78
|
+
) -> List[ArticleEssence]:
|
79
|
+
out = []
|
80
|
+
count = 0
|
56
81
|
for a in article_essence:
|
57
82
|
if key := (bib_mgr.get_cite_key(a.title) or bib_mgr.get_cite_key_fuzzy(a.title)):
|
58
83
|
a.title = bib_mgr.get_title_by_key(key) or a.title
|
59
84
|
a.authors = bib_mgr.get_author_by_key(key) or a.authors
|
60
85
|
a.publication_year = bib_mgr.get_year_by_key(key) or a.publication_year
|
61
86
|
a.bibtex_cite_key = key
|
62
|
-
logger.info(f
|
87
|
+
logger.info(f"Updated {a.title} with {key}")
|
88
|
+
out.append(a)
|
63
89
|
else:
|
64
90
|
logger.warning(f"No key found for {a.title}")
|
91
|
+
count += 1
|
92
|
+
if count:
|
93
|
+
logger.warning(f"{count} articles have no key")
|
94
|
+
return out
|
65
95
|
|
66
96
|
|
67
|
-
class GenerateArticleProposal(Action):
|
97
|
+
class GenerateArticleProposal(Action, Propose):
|
68
98
|
"""Generate an outline for the article based on the extracted essence."""
|
69
99
|
|
70
100
|
output_key: str = "article_proposal"
|
@@ -97,7 +127,6 @@ class GenerateArticleProposal(Action):
|
|
97
127
|
)
|
98
128
|
)
|
99
129
|
),
|
100
|
-
**self.prepend_sys_msg(),
|
101
130
|
),
|
102
131
|
"Could not generate the proposal.",
|
103
132
|
).update_ref(briefing)
|
@@ -107,7 +136,7 @@ class GenerateArticleProposal(Action):
|
|
107
136
|
return proposal
|
108
137
|
|
109
138
|
|
110
|
-
class GenerateInitialOutline(Action):
|
139
|
+
class GenerateInitialOutline(Action, Propose):
|
111
140
|
"""Generate the initial article outline based on the article proposal."""
|
112
141
|
|
113
142
|
output_key: str = "initial_article_outline"
|
@@ -122,44 +151,34 @@ class GenerateInitialOutline(Action):
|
|
122
151
|
await self.propose(
|
123
152
|
ArticleOutline,
|
124
153
|
article_proposal.as_prompt(),
|
125
|
-
**self.prepend_sys_msg(),
|
126
154
|
),
|
127
155
|
"Could not generate the initial outline.",
|
128
156
|
).update_ref(article_proposal)
|
129
157
|
|
130
158
|
|
131
|
-
class FixIntrospectedErrors(Action):
|
159
|
+
class FixIntrospectedErrors(Action, Censor):
|
132
160
|
"""Fix introspected errors in the article outline."""
|
133
161
|
|
134
162
|
output_key: str = "introspected_errors_fixed_outline"
|
135
163
|
"""The key of the output data."""
|
136
164
|
|
165
|
+
ruleset: Optional[RuleSet] = None
|
166
|
+
"""The ruleset to use to fix the introspected errors."""
|
167
|
+
|
137
168
|
async def _execute(
|
138
169
|
self,
|
139
170
|
article_outline: ArticleOutline,
|
140
|
-
|
171
|
+
ruleset: Optional[RuleSet] = None,
|
141
172
|
**_,
|
142
173
|
) -> Optional[ArticleOutline]:
|
143
|
-
introspect_manual = ok(
|
144
|
-
await self.draft_rating_manual(
|
145
|
-
topic=(
|
146
|
-
intro_topic
|
147
|
-
:= "Fix the error in the article outline, make sure there is no more error in the article outline."
|
148
|
-
),
|
149
|
-
),
|
150
|
-
"Could not generate the rating manual.",
|
151
|
-
)
|
152
|
-
|
153
174
|
while pack := article_outline.find_introspected():
|
154
175
|
component, err = ok(pack)
|
155
176
|
logger.warning(f"Found introspected error: {err}")
|
156
177
|
corrected = ok(
|
157
|
-
await self.
|
178
|
+
await self.censor_obj(
|
158
179
|
component,
|
159
|
-
|
160
|
-
|
161
|
-
rating_manual=introspect_manual,
|
162
|
-
supervisor_check=supervisor_check,
|
180
|
+
ruleset=ok(ruleset or self.ruleset, "No ruleset provided"),
|
181
|
+
reference=f"# Original Article Outline\n{article_outline.display()}\n# Some Basic errors found from `{component.title}` that need to be fixed\n{err}",
|
163
182
|
),
|
164
183
|
"Could not correct the component.",
|
165
184
|
)
|
@@ -168,141 +187,117 @@ class FixIntrospectedErrors(Action):
|
|
168
187
|
return article_outline
|
169
188
|
|
170
189
|
|
171
|
-
class FixIllegalReferences(Action):
|
190
|
+
class FixIllegalReferences(Action, Censor):
|
172
191
|
"""Fix illegal references in the article outline."""
|
173
192
|
|
174
193
|
output_key: str = "illegal_references_fixed_outline"
|
175
194
|
"""The key of the output data."""
|
176
195
|
|
196
|
+
ruleset: Optional[RuleSet] = None
|
197
|
+
"""Ruleset to use to fix the illegal references."""
|
198
|
+
|
177
199
|
async def _execute(
|
178
200
|
self,
|
179
201
|
article_outline: ArticleOutline,
|
180
|
-
|
202
|
+
ruleset: Optional[RuleSet] = None,
|
181
203
|
**_,
|
182
204
|
) -> Optional[ArticleOutline]:
|
183
|
-
|
184
|
-
|
185
|
-
topic=(
|
186
|
-
ref_topic
|
187
|
-
:= "Fix the internal referring error, make sure there is no more `ArticleRef` pointing to a non-existing article component."
|
188
|
-
),
|
189
|
-
),
|
190
|
-
"Could not generate the rating manual.",
|
191
|
-
)
|
192
|
-
|
193
|
-
while pack := article_outline.find_illegal_ref():
|
194
|
-
ref, err = ok(pack)
|
205
|
+
while pack := article_outline.find_illegal_ref(gather_identical=True):
|
206
|
+
refs, err = ok(pack)
|
195
207
|
logger.warning(f"Found illegal referring error: {err}")
|
196
|
-
ok(
|
197
|
-
await self.
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
rating_manual=ref_manual,
|
202
|
-
supervisor_check=supervisor_check,
|
208
|
+
corrected_ref = ok(
|
209
|
+
await self.censor_obj(
|
210
|
+
refs[0], # pyright: ignore [reportIndexIssue]
|
211
|
+
ruleset=ok(ruleset or self.ruleset, "No ruleset provided"),
|
212
|
+
reference=f"# Original Article Outline\n{article_outline.display()}\n# Some Basic errors found that need to be fixed\n{err}",
|
203
213
|
)
|
204
214
|
)
|
215
|
+
for ref in refs:
|
216
|
+
ref.update_from(corrected_ref) # pyright: ignore [reportAttributeAccessIssue]
|
217
|
+
|
205
218
|
return article_outline.update_ref(article_outline)
|
206
219
|
|
207
220
|
|
208
|
-
class
|
209
|
-
"""Tweak the
|
221
|
+
class TweakOutlineForwardRef(Action, Censor):
|
222
|
+
"""Tweak the forward references in the article outline.
|
210
223
|
|
211
|
-
Ensures that the
|
224
|
+
Ensures that the conclusions of the current chapter effectively support the analysis of subsequent chapters.
|
212
225
|
"""
|
213
226
|
|
214
|
-
output_key: str = "
|
227
|
+
output_key: str = "article_outline_fw_ref_checked"
|
228
|
+
ruleset: Optional[RuleSet] = None
|
229
|
+
"""Ruleset to use to fix the illegal references."""
|
215
230
|
|
216
|
-
async def _execute(
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
231
|
+
async def _execute(
|
232
|
+
self, article_outline: ArticleOutline, ruleset: Optional[RuleSet] = None, **cxt
|
233
|
+
) -> ArticleOutline:
|
234
|
+
return await self._inner(
|
235
|
+
article_outline,
|
236
|
+
ruleset=ok(ruleset or self.ruleset, "No ruleset provided"),
|
237
|
+
field_name="support_to",
|
222
238
|
)
|
223
239
|
|
240
|
+
async def _inner(self, article_outline: ArticleOutline, ruleset: RuleSet, field_name: str) -> ArticleOutline:
|
224
241
|
for a in article_outline.iter_dfs():
|
225
|
-
if await self.evidently_judge(
|
242
|
+
if judge := await self.evidently_judge(
|
226
243
|
f"{article_outline.as_prompt()}\n\n{a.display()}\n"
|
227
|
-
f"Does the `{a.__class__.__name__}`'s `
|
244
|
+
f"Does the `{a.__class__.__name__}`'s `{field_name}` field need to be extended or tweaked?"
|
228
245
|
):
|
229
|
-
patch =
|
230
|
-
patch.tweaked = a
|
246
|
+
patch = ArticleRefSequencePatch.default()
|
247
|
+
patch.tweaked = getattr(a, field_name)
|
231
248
|
|
232
|
-
await self.
|
249
|
+
await self.censor_obj_inplace(
|
233
250
|
patch,
|
234
|
-
|
235
|
-
reference=f"{article_outline.as_prompt()}\
|
236
|
-
|
237
|
-
|
251
|
+
ruleset=ruleset,
|
252
|
+
reference=f"{article_outline.as_prompt()}\n"
|
253
|
+
f"The Article component titled `{a.title}` whose `{field_name}` field needs to be extended or tweaked.\n"
|
254
|
+
f"# Judgement\n{judge.display()}",
|
238
255
|
)
|
239
|
-
|
240
256
|
return article_outline
|
241
257
|
|
242
258
|
|
243
|
-
class TweakOutlineForwardRef
|
244
|
-
"""Tweak the
|
259
|
+
class TweakOutlineBackwardRef(TweakOutlineForwardRef):
|
260
|
+
"""Tweak the backward references in the article outline.
|
245
261
|
|
246
|
-
Ensures that the
|
262
|
+
Ensures that the prerequisites of the current chapter are correctly referenced in the `depend_on` field.
|
247
263
|
"""
|
248
264
|
|
249
|
-
output_key: str = "
|
265
|
+
output_key: str = "article_outline_bw_ref_checked"
|
266
|
+
ruleset: Optional[RuleSet] = None
|
250
267
|
|
251
|
-
async def _execute(
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
268
|
+
async def _execute(
|
269
|
+
self, article_outline: ArticleOutline, ruleset: Optional[RuleSet] = None, **cxt
|
270
|
+
) -> ArticleOutline:
|
271
|
+
return await self._inner(
|
272
|
+
article_outline,
|
273
|
+
ruleset=ok(ruleset or self.ruleset, "No ruleset provided"),
|
274
|
+
field_name="depend_on",
|
257
275
|
)
|
258
276
|
|
259
|
-
for a in article_outline.iter_dfs():
|
260
|
-
if await self.evidently_judge(
|
261
|
-
f"{article_outline.as_prompt()}\n\n{a.display()}\n"
|
262
|
-
f"Does the `{a.__class__.__name__}`'s `support_to` field need to be extended or tweaked?"
|
263
|
-
):
|
264
|
-
patch = ArticleRefPatch.default()
|
265
|
-
patch.tweaked = a.support_to
|
266
|
-
|
267
|
-
await self.correct_obj_inplace(
|
268
|
-
patch,
|
269
|
-
topic=topic,
|
270
|
-
reference=f"{article_outline.as_prompt()}\nThe Article component whose `support_to` field needs to be extended or tweaked",
|
271
|
-
rating_manual=tweak_support_to_manual,
|
272
|
-
supervisor_check=supervisor_check,
|
273
|
-
)
|
274
|
-
|
275
|
-
return article_outline
|
276
277
|
|
277
|
-
|
278
|
-
class GenerateArticle(Action):
|
278
|
+
class GenerateArticle(Action, Censor):
|
279
279
|
"""Generate the article based on the outline."""
|
280
280
|
|
281
281
|
output_key: str = "article"
|
282
282
|
"""The key of the output data."""
|
283
|
+
ruleset: Optional[RuleSet] = None
|
283
284
|
|
284
285
|
async def _execute(
|
285
286
|
self,
|
286
287
|
article_outline: ArticleOutline,
|
287
|
-
|
288
|
+
ruleset: Optional[RuleSet] = None,
|
288
289
|
**_,
|
289
290
|
) -> Optional[Article]:
|
290
291
|
article: Article = Article.from_outline(ok(article_outline, "Article outline not specified.")).update_ref(
|
291
292
|
article_outline
|
292
293
|
)
|
293
294
|
|
294
|
-
write_para_manual = ok(
|
295
|
-
await self.draft_rating_manual(w_topic := "write the following paragraph in the subsection.")
|
296
|
-
)
|
297
|
-
|
298
295
|
await gather(
|
299
296
|
*[
|
300
|
-
self.
|
297
|
+
self.censor_obj_inplace(
|
301
298
|
subsec,
|
299
|
+
ruleset=ok(ruleset or self.ruleset, "No ruleset provided"),
|
302
300
|
reference=f"# Original Article Outline\n{article_outline.display()}\n# Error Need to be fixed\n{err}",
|
303
|
-
topic=w_topic,
|
304
|
-
rating_manual=write_para_manual,
|
305
|
-
supervisor_check=supervisor_check,
|
306
301
|
)
|
307
302
|
for _, __, subsec in article.iter_subsections()
|
308
303
|
if (err := subsec.introspect())
|
@@ -313,18 +308,16 @@ class GenerateArticle(Action):
|
|
313
308
|
return article
|
314
309
|
|
315
310
|
|
316
|
-
class CorrectProposal(Action):
|
311
|
+
class CorrectProposal(Action, Censor):
|
317
312
|
"""Correct the proposal of the article."""
|
318
313
|
|
319
314
|
output_key: str = "corrected_proposal"
|
320
315
|
|
321
316
|
async def _execute(self, article_proposal: ArticleProposal, **_) -> Any:
|
322
|
-
|
323
|
-
article_proposal
|
324
|
-
)
|
317
|
+
raise NotImplementedError("Not implemented.")
|
325
318
|
|
326
319
|
|
327
|
-
class CorrectOutline(Action):
|
320
|
+
class CorrectOutline(Action, Correct):
|
328
321
|
"""Correct the outline of the article."""
|
329
322
|
|
330
323
|
output_key: str = "corrected_outline"
|
@@ -335,12 +328,10 @@ class CorrectOutline(Action):
|
|
335
328
|
article_outline: ArticleOutline,
|
336
329
|
**_,
|
337
330
|
) -> ArticleOutline:
|
338
|
-
|
339
|
-
article_outline
|
340
|
-
)
|
331
|
+
raise NotImplementedError("Not implemented.")
|
341
332
|
|
342
333
|
|
343
|
-
class CorrectArticle(Action):
|
334
|
+
class CorrectArticle(Action, Correct):
|
344
335
|
"""Correct the article based on the outline."""
|
345
336
|
|
346
337
|
output_key: str = "corrected_article"
|
@@ -352,4 +343,4 @@ class CorrectArticle(Action):
|
|
352
343
|
article_outline: ArticleOutline,
|
353
344
|
**_,
|
354
345
|
) -> Article:
|
355
|
-
|
346
|
+
raise NotImplementedError("Not implemented.")
|
@@ -1,74 +1,86 @@
|
|
1
1
|
"""A module for writing articles using RAG (Retrieval-Augmented Generation) capabilities."""
|
2
2
|
|
3
3
|
from asyncio import gather
|
4
|
-
from typing import
|
4
|
+
from typing import Optional
|
5
5
|
|
6
|
+
from fabricatio.capabilities.censor import Censor
|
6
7
|
from fabricatio.capabilities.rag import RAG
|
7
8
|
from fabricatio.models.action import Action
|
8
|
-
from fabricatio.models.extra.article_main import Article,
|
9
|
-
from fabricatio.models.
|
9
|
+
from fabricatio.models.extra.article_main import Article, ArticleParagraphSequencePatch, ArticleSubsection
|
10
|
+
from fabricatio.models.extra.rule import RuleSet
|
11
|
+
from fabricatio.utils import ok
|
10
12
|
|
11
13
|
|
12
|
-
class TweakArticleRAG(Action, RAG):
|
13
|
-
"""Write an article based on the provided outline.
|
14
|
+
class TweakArticleRAG(Action, RAG, Censor):
|
15
|
+
"""Write an article based on the provided outline.
|
16
|
+
|
17
|
+
This class inherits from `Action`, `RAG`, and `Censor` to provide capabilities for writing and refining articles
|
18
|
+
using Retrieval-Augmented Generation (RAG) techniques. It processes an article outline, enhances subsections by
|
19
|
+
searching for related references, and applies censoring rules to ensure compliance with the provided ruleset.
|
20
|
+
|
21
|
+
Attributes:
|
22
|
+
output_key (str): The key used to store the output of the action.
|
23
|
+
ruleset (Optional[RuleSet]): The ruleset to be used for censoring the article.
|
24
|
+
"""
|
14
25
|
|
15
26
|
output_key: str = "rag_tweaked_article"
|
27
|
+
"""The key used to store the output of the action."""
|
28
|
+
|
29
|
+
ruleset: Optional[RuleSet] = None
|
30
|
+
"""The ruleset to be used for censoring the article."""
|
16
31
|
|
17
32
|
async def _execute(
|
18
33
|
self,
|
19
34
|
article: Article,
|
20
35
|
collection_name: str = "article_essence",
|
21
|
-
|
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,
|
36
|
+
ruleset: Optional[RuleSet] = None,
|
31
37
|
parallel: bool = False,
|
32
38
|
**cxt,
|
33
39
|
) -> Optional[Article]:
|
34
|
-
"""Write an article based on the provided outline.
|
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,
|
42
|
-
)
|
40
|
+
"""Write an article based on the provided outline.
|
43
41
|
|
44
|
-
|
45
|
-
|
46
|
-
|
42
|
+
This method processes the article outline, either in parallel or sequentially, by enhancing each subsection
|
43
|
+
with relevant references and applying censoring rules.
|
44
|
+
|
45
|
+
Args:
|
46
|
+
article (Article): The article to be processed.
|
47
|
+
collection_name (str): The name of the collection to view for processing.
|
48
|
+
ruleset (Optional[RuleSet]): The ruleset to apply for censoring. If not provided, the class's ruleset is used.
|
49
|
+
parallel (bool): If True, process subsections in parallel. Otherwise, process them sequentially.
|
50
|
+
**cxt: Additional context parameters.
|
51
|
+
|
52
|
+
Returns:
|
53
|
+
Optional[Article]: The processed article with enhanced subsections and applied censoring rules.
|
54
|
+
"""
|
47
55
|
self.view(collection_name)
|
48
56
|
|
49
57
|
if parallel:
|
50
58
|
await gather(
|
51
59
|
*[
|
52
|
-
self._inner(article, subsec,
|
60
|
+
self._inner(article, subsec, ok(ruleset or self.ruleset, "No ruleset provided!"))
|
53
61
|
for _, __, subsec in article.iter_subsections()
|
54
62
|
],
|
55
63
|
return_exceptions=True,
|
56
64
|
)
|
57
65
|
else:
|
58
66
|
for _, __, subsec in article.iter_subsections():
|
59
|
-
await self._inner(article, subsec,
|
60
|
-
|
67
|
+
await self._inner(article, subsec, ok(ruleset or self.ruleset, "No ruleset provided!"))
|
61
68
|
return article
|
62
69
|
|
63
|
-
async def _inner(
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
70
|
+
async def _inner(self, article: Article, subsec: ArticleSubsection, ruleset: RuleSet) -> None:
|
71
|
+
"""Enhance a subsection of the article with references and apply censoring rules.
|
72
|
+
|
73
|
+
This method refines the query for the subsection, retrieves related references, and applies censoring rules
|
74
|
+
to the subsection's paragraphs.
|
75
|
+
|
76
|
+
Args:
|
77
|
+
article (Article): The article containing the subsection.
|
78
|
+
subsec (ArticleSubsection): The subsection to be enhanced.
|
79
|
+
ruleset (RuleSet): The ruleset to apply for censoring.
|
80
|
+
|
81
|
+
Returns:
|
82
|
+
None
|
83
|
+
"""
|
72
84
|
refind_q = ok(
|
73
85
|
await self.arefined_query(
|
74
86
|
f"{article.referenced.as_prompt()}\n"
|
@@ -79,12 +91,10 @@ class TweakArticleRAG(Action, RAG):
|
|
79
91
|
f"prioritizing both original article language and English usage",
|
80
92
|
)
|
81
93
|
)
|
82
|
-
patch =
|
94
|
+
patch = ArticleParagraphSequencePatch.default()
|
83
95
|
patch.tweaked = subsec.paragraphs
|
84
|
-
await self.
|
96
|
+
await self.censor_obj_inplace(
|
85
97
|
patch,
|
86
|
-
|
87
|
-
|
88
|
-
rating_manual=tweak_manual,
|
89
|
-
supervisor_check=supervisor_check,
|
98
|
+
ruleset=ruleset,
|
99
|
+
reference=await self.aretrieve_compact(refind_q, final_limit=30),
|
90
100
|
)
|
fabricatio/actions/output.py
CHANGED
@@ -7,7 +7,7 @@ from fabricatio.journal import logger
|
|
7
7
|
from fabricatio.models.action import Action
|
8
8
|
from fabricatio.models.generic import FinalizedDumpAble, PersistentAble
|
9
9
|
from fabricatio.models.task import Task
|
10
|
-
from fabricatio.
|
10
|
+
from fabricatio.utils import ok
|
11
11
|
|
12
12
|
|
13
13
|
class DumpFinalizedOutput(Action):
|
@@ -67,17 +67,18 @@ class PersistentAll(Action):
|
|
67
67
|
|
68
68
|
for k, v in cxt.items():
|
69
69
|
final_dir = persist_dir.joinpath(k)
|
70
|
-
final_dir.mkdir(parents=True, exist_ok=True)
|
71
70
|
if isinstance(v, PersistentAble):
|
71
|
+
final_dir.mkdir(parents=True, exist_ok=True)
|
72
72
|
v.persist(final_dir)
|
73
73
|
count += 1
|
74
74
|
if isinstance(v, Iterable) and any(
|
75
75
|
persistent_ables := (pers for pers in v if isinstance(pers, PersistentAble))
|
76
76
|
):
|
77
|
+
final_dir.mkdir(parents=True, exist_ok=True)
|
77
78
|
for per in persistent_ables:
|
78
79
|
per.persist(final_dir)
|
79
80
|
count += 1
|
80
|
-
|
81
|
+
logger.info(f"Persisted {count} objects to {persist_dir}")
|
81
82
|
return count
|
82
83
|
|
83
84
|
|
fabricatio/actions/rag.py
CHANGED
@@ -5,7 +5,7 @@ from typing import List, Optional
|
|
5
5
|
from fabricatio.capabilities.rag import RAG
|
6
6
|
from fabricatio.journal import logger
|
7
7
|
from fabricatio.models.action import Action
|
8
|
-
from fabricatio.models.generic import
|
8
|
+
from fabricatio.models.generic import Vectorizable
|
9
9
|
from fabricatio.models.task import Task
|
10
10
|
from questionary import text
|
11
11
|
|
@@ -15,7 +15,7 @@ class InjectToDB(Action, RAG):
|
|
15
15
|
|
16
16
|
output_key: str = "collection_name"
|
17
17
|
|
18
|
-
async def _execute[T:
|
18
|
+
async def _execute[T: Vectorizable](
|
19
19
|
self, to_inject: Optional[T] | List[Optional[T]], collection_name: str = "my_collection",override_inject:bool=False, **_
|
20
20
|
) -> Optional[str]:
|
21
21
|
if not isinstance(to_inject, list):
|
@@ -27,7 +27,7 @@ class InjectToDB(Action, RAG):
|
|
27
27
|
[
|
28
28
|
t.prepare_vectorization(self.embedding_max_sequence_length)
|
29
29
|
for t in to_inject
|
30
|
-
if isinstance(t,
|
30
|
+
if isinstance(t, Vectorizable)
|
31
31
|
],
|
32
32
|
)
|
33
33
|
|