fabricatio 0.2.7.dev5__cp312-cp312-manylinux_2_34_x86_64.whl → 0.2.8.dev1__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.
@@ -1,11 +1,14 @@
1
1
  """Actions for transmitting tasks to targets."""
2
2
 
3
+ from asyncio import gather
3
4
  from pathlib import Path
4
5
  from typing import Any, Callable, List, Optional
5
6
 
7
+ from fabricatio.capabilities.advanced_judge import AdvancedJudge
6
8
  from fabricatio.fs import safe_text_read
7
9
  from fabricatio.journal import logger
8
10
  from fabricatio.models.action import Action
11
+ from fabricatio.models.extra.article_base import ArticleRefPatch
9
12
  from fabricatio.models.extra.article_essence import ArticleEssence
10
13
  from fabricatio.models.extra.article_main import Article
11
14
  from fabricatio.models.extra.article_outline import ArticleOutline
@@ -55,13 +58,14 @@ class GenerateArticleProposal(Action):
55
58
  task_input: Optional[Task] = None,
56
59
  article_briefing: Optional[str] = None,
57
60
  article_briefing_path: Optional[str] = None,
61
+ langauge: Optional[str] = None,
58
62
  **_,
59
63
  ) -> Optional[ArticleProposal]:
60
64
  if article_briefing is None and article_briefing_path is None and task_input is None:
61
65
  logger.error("Task not approved, since all inputs are None.")
62
66
  return None
63
67
 
64
- return ok(
68
+ proposal = ok(
65
69
  await self.propose(
66
70
  ArticleProposal,
67
71
  briefing := (
@@ -78,14 +82,18 @@ class GenerateArticleProposal(Action):
78
82
  ),
79
83
  **self.prepend_sys_msg(),
80
84
  ),
81
- "Could not generate the proposal."
85
+ "Could not generate the proposal.",
82
86
  ).update_ref(briefing)
87
+ if langauge:
88
+ proposal.language = langauge
83
89
 
90
+ return proposal
84
91
 
85
- class GenerateOutline(Action):
86
- """Generate the article based on the outline."""
87
92
 
88
- output_key: str = "article_outline"
93
+ class GenerateInitialOutline(Action):
94
+ """Generate the initial article outline based on the article proposal."""
95
+
96
+ output_key: str = "initial_article_outline"
89
97
  """The key of the output data."""
90
98
 
91
99
  async def _execute(
@@ -93,62 +101,158 @@ class GenerateOutline(Action):
93
101
  article_proposal: ArticleProposal,
94
102
  **_,
95
103
  ) -> Optional[ArticleOutline]:
96
- out = ok(
104
+ return ok(
97
105
  await self.propose(
98
106
  ArticleOutline,
99
107
  article_proposal.as_prompt(),
100
108
  **self.prepend_sys_msg(),
101
109
  ),
102
- "Could not generate the outline.",
110
+ "Could not generate the initial outline.",
103
111
  )
104
112
 
105
- manual = ok(await self.draft_rating_manual(
106
- topic=(
107
- topic
108
- := "Fix the internal referring error, make sure there is no more `ArticleRef` pointing to a non-existing article component."
109
- ),
110
- ),"Could not generate the rating manual.")
111
113
 
112
- while pack := out.find_illegal():
113
- component, err = ok(pack)
114
- logger.warning(f"Found error in the outline: \n{err}")
115
- corrected = ok(await self.correct_obj(
116
- component,
117
- reference=f"# Original Article Outline\n{out.display()}\n# Error Need to be fixed\n{err}",
118
- topic=topic,
119
- rating_manual=manual,
120
- supervisor_check=False,
121
- ),"Could not correct the component.")
122
- component.update_from(corrected)
123
- return out.update_ref(article_proposal)
114
+ class FixIntrospectedErrors(Action):
115
+ """Fix introspected errors in the article outline."""
124
116
 
117
+ output_key: str = "introspected_errors_fixed_outline"
118
+ """The key of the output data."""
125
119
 
126
- class CorrectProposal(Action):
127
- """Correct the proposal of the article."""
120
+ async def _execute(
121
+ self,
122
+ article_outline: ArticleOutline,
123
+ **_,
124
+ ) -> Optional[ArticleOutline]:
125
+ introspect_manual = ok(
126
+ await self.draft_rating_manual(
127
+ topic=(
128
+ intro_topic
129
+ := "Fix the error in the article outline, make sure there is no more error in the article outline."
130
+ ),
131
+ ),
132
+ "Could not generate the rating manual.",
133
+ )
128
134
 
129
- output_key: str = "corrected_proposal"
135
+ while pack := article_outline.find_introspected():
136
+ component, err = ok(pack)
137
+ logger.warning(f"Found introspected error: {err}")
138
+ corrected = ok(
139
+ await self.correct_obj(
140
+ component,
141
+ reference=f"# Original Article Outline\n{article_outline.display()}\n# Error Need to be fixed\n{err}",
142
+ topic=intro_topic,
143
+ rating_manual=introspect_manual,
144
+ supervisor_check=False,
145
+ ),
146
+ "Could not correct the component.",
147
+ )
148
+ component.update_from(corrected)
130
149
 
131
- async def _execute(self, article_proposal: ArticleProposal, **_) -> Any:
132
- return (await self.censor_obj(article_proposal, reference=article_proposal.referenced)).update_ref(
133
- article_proposal
134
- )
150
+ return article_outline
135
151
 
136
152
 
137
- class CorrectOutline(Action):
138
- """Correct the outline of the article."""
153
+ class FixIllegalReferences(Action):
154
+ """Fix illegal references in the article outline."""
139
155
 
140
- output_key: str = "corrected_outline"
156
+ output_key: str = "illegal_references_fixed_outline"
141
157
  """The key of the output data."""
142
158
 
143
159
  async def _execute(
144
160
  self,
145
161
  article_outline: ArticleOutline,
146
162
  **_,
147
- ) -> ArticleOutline:
148
- return (await self.censor_obj(article_outline, reference=article_outline.referenced.as_prompt())).update_ref(
149
- article_outline
163
+ ) -> Optional[ArticleOutline]:
164
+ ref_manual = ok(
165
+ await self.draft_rating_manual(
166
+ topic=(
167
+ ref_topic
168
+ := "Fix the internal referring error, make sure there is no more `ArticleRef` pointing to a non-existing article component."
169
+ ),
170
+ ),
171
+ "Could not generate the rating manual.",
172
+ )
173
+
174
+ while pack := article_outline.find_illegal_ref():
175
+ ref, err = ok(pack)
176
+ logger.warning(f"Found illegal referring error: {err}")
177
+ ok(
178
+ await self.correct_obj_inplace(
179
+ ref,
180
+ reference=f"# Original Article Outline\n{article_outline.display()}\n# Error Need to be fixed\n{err}\n\n",
181
+ topic=ref_topic,
182
+ rating_manual=ref_manual,
183
+ supervisor_check=False,
184
+ )
185
+ )
186
+ return article_outline.update_ref(article_outline)
187
+
188
+
189
+ class TweakOutlineBackwardRef(Action, AdvancedJudge):
190
+ """Tweak the backward references in the article outline.
191
+
192
+ Ensures that the prerequisites of the current chapter are correctly referenced in the `depend_on` field.
193
+ """
194
+
195
+ output_key: str = "article_outline_bw_ref_checked"
196
+
197
+ async def _execute(self, article_outline: ArticleOutline, **cxt) -> ArticleOutline:
198
+ tweak_depend_on_manual = ok(
199
+ await self.draft_rating_manual(
200
+ topic := "Ensure prerequisites are correctly referenced in the `depend_on` field."
201
+ ),
202
+ "Could not generate the rating manual.",
150
203
  )
151
204
 
205
+ for a in article_outline.iter_dfs():
206
+ if await self.evidently_judge(
207
+ f"{article_outline.as_prompt()}\n\n{a.display()}\n"
208
+ f"Does the `{a.__class__.__name__}`'s `depend_on` field need to be extended or tweaked?"
209
+ ):
210
+ patch=ArticleRefPatch.default()
211
+ patch.tweaked=a.depend_on
212
+
213
+ await self.correct_obj_inplace(
214
+ patch,
215
+ topic=topic,
216
+ reference=f"{article_outline.as_prompt()}\nThe Article component whose `depend_on` field needs to be extended or tweaked",
217
+ rating_manual=tweak_depend_on_manual,
218
+ )
219
+
220
+ return article_outline
221
+
222
+
223
+ class TweakOutlineForwardRef(Action, AdvancedJudge):
224
+ """Tweak the forward references in the article outline.
225
+
226
+ Ensures that the conclusions of the current chapter effectively support the analysis of subsequent chapters.
227
+ """
228
+
229
+ output_key: str = "article_outline_fw_ref_checked"
230
+
231
+ async def _execute(self, article_outline: ArticleOutline, **cxt) -> ArticleOutline:
232
+ tweak_support_to_manual = ok(
233
+ await self.draft_rating_manual(
234
+ topic := "Ensure conclusions support the analysis of subsequent chapters, sections or subsections."
235
+ ),
236
+ "Could not generate the rating manual.",
237
+ )
238
+
239
+ for a in article_outline.iter_dfs():
240
+ if await self.evidently_judge(
241
+ f"{article_outline.as_prompt()}\n\n{a.display()}\n"
242
+ f"Does the `{a.__class__.__name__}`'s `support_to` field need to be extended or tweaked?"
243
+ ):
244
+ patch=ArticleRefPatch.default()
245
+ patch.tweaked=a.support_to
246
+
247
+ await self.correct_obj_inplace(
248
+ patch,
249
+ topic=topic,
250
+ reference=f"{article_outline.as_prompt()}\nThe Article component whose `support_to` field needs to be extended or tweaked",
251
+ rating_manual=tweak_support_to_manual,
252
+ )
253
+
254
+ return article_outline
255
+
152
256
 
153
257
  class GenerateArticle(Action):
154
258
  """Generate the article based on the outline."""
@@ -161,49 +265,59 @@ class GenerateArticle(Action):
161
265
  article_outline: ArticleOutline,
162
266
  **_,
163
267
  ) -> Optional[Article]:
164
- article: Article = Article.from_outline(article_outline).update_ref(article_outline)
268
+ article: Article = Article.from_outline(ok(article_outline, "Article outline not specified.")).update_ref(
269
+ article_outline
270
+ )
165
271
 
166
- writing_manual = ok(await self.draft_rating_manual(
167
- topic=(
168
- topic_1
169
- := "improve the content of the subsection to fit the outline. SHALL never add or remove any section or subsection, you can only add or delete paragraphs within the subsection."
170
- ),
171
- ))
172
- err_resolve_manual = ok(await self.draft_rating_manual(
173
- topic=(topic_2 := "this article component has violated the constrain, please correct it.")
174
- ))
175
- for c, deps in article.iter_dfs_with_deps(chapter=False):
176
- logger.info(f"Updating the article component: \n{c.display()}")
177
-
178
- out = ok(
179
- await self.correct_obj(
180
- c,
181
- reference=(
182
- ref := f"{article_outline.referenced.as_prompt()}\n" + "\n".join(d.display() for d in deps)
183
- ),
184
- topic=topic_1,
185
- rating_manual=writing_manual,
272
+ write_para_manual = ok(
273
+ await self.draft_rating_manual(w_topic := "write the following paragraph in the subsection.")
274
+ )
275
+
276
+ await gather(
277
+ *[
278
+ self.correct_obj_inplace(
279
+ subsec,
280
+ reference=f"# Original Article Outline\n{article_outline.display()}\n# Error Need to be fixed\n{err}",
281
+ topic=w_topic,
282
+ rating_manual=write_para_manual,
186
283
  supervisor_check=False,
187
- ),
188
- "Could not correct the article component.",
189
- )
190
- while err := c.resolve_update_conflict(out):
191
- logger.warning(f"Found error in the article component: \n{err}")
192
- out = ok(
193
- await self.correct_obj(
194
- out,
195
- reference=f"{ref}\n\n# Violated Error\n{err}",
196
- topic=topic_2,
197
- rating_manual=err_resolve_manual,
198
- supervisor_check=False,
199
- ),
200
- "Could not correct the article component.",
201
284
  )
285
+ for _, __, subsec in article.iter_subsections()
286
+ if (err := subsec.introspect())
287
+ ],
288
+ return_exceptions=True,
289
+ )
202
290
 
203
- c.update_from(out)
204
291
  return article
205
292
 
206
293
 
294
+ class CorrectProposal(Action):
295
+ """Correct the proposal of the article."""
296
+
297
+ output_key: str = "corrected_proposal"
298
+
299
+ async def _execute(self, article_proposal: ArticleProposal, **_) -> Any:
300
+ return (await self.censor_obj(article_proposal, reference=article_proposal.referenced)).update_ref(
301
+ article_proposal
302
+ )
303
+
304
+
305
+ class CorrectOutline(Action):
306
+ """Correct the outline of the article."""
307
+
308
+ output_key: str = "corrected_outline"
309
+ """The key of the output data."""
310
+
311
+ async def _execute(
312
+ self,
313
+ article_outline: ArticleOutline,
314
+ **_,
315
+ ) -> ArticleOutline:
316
+ return (await self.censor_obj(article_outline, reference=article_outline.referenced.as_prompt())).update_ref(
317
+ article_outline
318
+ )
319
+
320
+
207
321
  class CorrectArticle(Action):
208
322
  """Correct the article based on the outline."""
209
323
 
@@ -3,8 +3,9 @@
3
3
  from pathlib import Path
4
4
  from typing import Optional
5
5
 
6
+ from fabricatio.journal import logger
6
7
  from fabricatio.models.action import Action
7
- from fabricatio.models.generic import FinalizedDumpAble
8
+ from fabricatio.models.generic import FinalizedDumpAble, PersistentAble
8
9
  from fabricatio.models.task import Task
9
10
  from fabricatio.models.utils import ok
10
11
 
@@ -32,3 +33,37 @@ class DumpFinalizedOutput(Action):
32
33
  )
33
34
  ok(to_dump, "Could not dump the data since the path is not specified.").finalized_dump_to(dump_path)
34
35
  return dump_path.as_posix()
36
+
37
+
38
+ class PersistentAll(Action):
39
+ """Persist all the data to a file."""
40
+
41
+ output_key: str = "persistent_count"
42
+
43
+ async def _execute(
44
+ self,
45
+ task_input: Optional[Task] = None,
46
+ persist_dir: Optional[str | Path] = None,
47
+ **cxt,
48
+ ) -> int:
49
+ persist_dir = Path(
50
+ persist_dir
51
+ or ok(
52
+ await self.awhich_pathstr(
53
+ 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."
54
+ ),
55
+ "Can not find the path of file to persist the data.",
56
+ )
57
+ )
58
+
59
+ count = 0
60
+ if persist_dir.is_file():
61
+ logger.warning("Dump should be a directory, but it is a file. Skip dumping.")
62
+ return count
63
+ persist_dir.mkdir(parents=True, exist_ok=True)
64
+ for v in cxt.values():
65
+ if isinstance(v, PersistentAble):
66
+ v.persist(persist_dir)
67
+ count += 1
68
+
69
+ return count
@@ -0,0 +1,23 @@
1
+ """The Capabilities module for advanced judging."""
2
+
3
+ from typing import Optional, Unpack
4
+
5
+ from fabricatio.capabilities.propose import Propose
6
+ from fabricatio.models.extra.advanced_judge import JudgeMent
7
+ from fabricatio.models.kwargs_types import ValidateKwargs
8
+
9
+
10
+ class AdvancedJudge(Propose):
11
+ """A class that judges the evidence and makes a final decision."""
12
+ async def evidently_judge(
13
+ self,
14
+ prompt: str,
15
+ **kwargs: Unpack[ValidateKwargs[JudgeMent]],
16
+ ) -> Optional[JudgeMent]:
17
+ """Judge the evidence and make a final decision."""
18
+ return await self.propose(
19
+ JudgeMent,
20
+ prompt,
21
+ **kwargs
22
+ )
23
+
@@ -10,7 +10,7 @@ from typing import Optional, Unpack, cast
10
10
  from fabricatio._rust_instances import TEMPLATE_MANAGER
11
11
  from fabricatio.capabilities.review import Review, ReviewResult
12
12
  from fabricatio.config import configs
13
- from fabricatio.models.generic import CensoredAble, Display, ProposedAble, WithBriefing
13
+ from fabricatio.models.generic import CensoredAble, Display, ProposedAble, ProposedUpdateAble, WithBriefing
14
14
  from fabricatio.models.kwargs_types import CensoredCorrectKwargs, CorrectKwargs, ReviewKwargs
15
15
  from fabricatio.models.task import Task
16
16
  from questionary import confirm, text
@@ -134,12 +134,32 @@ class Correct(Review):
134
134
  while await confirm("Begin to correct obj above with human censorship?").ask_async():
135
135
  while (topic := await text("What is the topic of the obj reviewing?").ask_async()) is not None and topic:
136
136
  ...
137
- if (modified_obj := await self.correct_obj(
138
- last_modified_obj,
139
- topic=topic,
140
- **kwargs,
141
- )) is None:
137
+ if (
138
+ modified_obj := await self.correct_obj(
139
+ last_modified_obj,
140
+ topic=topic,
141
+ **kwargs,
142
+ )
143
+ ) is None:
142
144
  break
143
145
  last_modified_obj = modified_obj
144
146
  rprint(last_modified_obj.finalized_dump())
145
147
  return modified_obj or last_modified_obj
148
+
149
+ async def correct_obj_inplace[M: ProposedUpdateAble](
150
+ self, obj: M, **kwargs: Unpack[CorrectKwargs[ReviewResult[str]]]
151
+ ) -> Optional[M]:
152
+ """Correct an object in place based on defined criteria and templates.
153
+
154
+ Args:
155
+ obj (M): The object to be corrected.
156
+ **kwargs (Unpack[CensoredCorrectKwargs]): Additional keyword arguments for the correction process.
157
+
158
+ Returns:
159
+ Optional[M]: The corrected object, or None if correction fails.
160
+ """
161
+ corrected_obj = await self.correct_obj(obj, **kwargs)
162
+ if corrected_obj is None:
163
+ return corrected_obj
164
+ obj.update_from(corrected_obj)
165
+ return obj
@@ -16,7 +16,7 @@ from more_itertools import flatten, windowed
16
16
  from pydantic import NonNegativeInt, PositiveInt
17
17
 
18
18
 
19
- class GiveRating(WithBriefing, LLMUsage):
19
+ class Rating(WithBriefing, LLMUsage):
20
20
  """A class that provides functionality to rate tasks based on a rating manual and score range.
21
21
 
22
22
  References:
@@ -4,7 +4,7 @@ from typing import Dict, List, Optional, Self, Set, Unpack, cast
4
4
 
5
5
  from fabricatio._rust_instances import TEMPLATE_MANAGER
6
6
  from fabricatio.capabilities.propose import Propose
7
- from fabricatio.capabilities.rating import GiveRating
7
+ from fabricatio.capabilities.rating import Rating
8
8
  from fabricatio.config import configs
9
9
  from fabricatio.models.generic import Base, Display, ProposedAble, WithBriefing
10
10
  from fabricatio.models.kwargs_types import ReviewKwargs, ValidateKwargs
@@ -175,7 +175,7 @@ class ReviewResult[T](ProposedAble, Display):
175
175
  return self
176
176
 
177
177
 
178
- class Review(GiveRating, Propose):
178
+ class Review(Rating, Propose):
179
179
  """Class that provides functionality to review tasks and strings using a language model.
180
180
 
181
181
  This class extends GiveRating and Propose capabilities to analyze content,
@@ -170,6 +170,8 @@ class WorkFlow(WithBriefing, ToolBoxUsage):
170
170
  # Update context with modified values
171
171
  modified_ctx = await act_task
172
172
  logger.success(f"Step execution finished: {current_action}")
173
+ if step.output_key:
174
+ logger.success(f"Setting output: {step.output_key}")
173
175
  await self._context.put(modified_ctx)
174
176
 
175
177
  logger.success(f"Workflow execution finished: {self.name}")
@@ -219,7 +221,7 @@ class WorkFlow(WithBriefing, ToolBoxUsage):
219
221
  self.provide_tools_to(self._instances)
220
222
  return self
221
223
 
222
- def update_init_context(self, **kwargs) -> Self:
224
+ def update_init_context(self, /, **kwargs) -> Self:
223
225
  """Update the initial context with additional key-value pairs.
224
226
 
225
227
  Args:
@@ -0,0 +1,22 @@
1
+ """A module containing the JudgeMent class."""
2
+
3
+ from typing import List
4
+
5
+ from fabricatio.models.generic import ProposedAble
6
+
7
+
8
+ class JudgeMent(ProposedAble):
9
+ """A class representing a judgment made by a judge."""
10
+
11
+ affirm_evidence: List[str]
12
+ """List of evidence supporting the affirmation."""
13
+
14
+ deny_evidence: List[str]
15
+ """List of evidence supporting the denial."""
16
+
17
+ final_judgement: bool
18
+ """The final judgement."""
19
+
20
+ def __bool__(self) -> bool:
21
+ """Return the final judgement."""
22
+ return self.final_judgement