fabricatio 0.2.7.dev4__cp312-cp312-manylinux_2_34_x86_64.whl → 0.2.8.dev0__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,5 +1,6 @@
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
 
@@ -55,13 +56,14 @@ class GenerateArticleProposal(Action):
55
56
  task_input: Optional[Task] = None,
56
57
  article_briefing: Optional[str] = None,
57
58
  article_briefing_path: Optional[str] = None,
59
+ langauge: Optional[str] = None,
58
60
  **_,
59
61
  ) -> Optional[ArticleProposal]:
60
62
  if article_briefing is None and article_briefing_path is None and task_input is None:
61
63
  logger.error("Task not approved, since all inputs are None.")
62
64
  return None
63
65
 
64
- return (
66
+ proposal = ok(
65
67
  await self.propose(
66
68
  ArticleProposal,
67
69
  briefing := (
@@ -70,15 +72,20 @@ class GenerateArticleProposal(Action):
70
72
  ok(
71
73
  article_briefing_path
72
74
  or await self.awhich_pathstr(
73
- f"{task_input.briefing}\nExtract the path of file which contains the article briefing."
75
+ f"{ok(task_input).briefing}\nExtract the path of file which contains the article briefing."
74
76
  ),
75
77
  "Could not find the path of file to read.",
76
78
  )
77
79
  )
78
80
  ),
79
81
  **self.prepend_sys_msg(),
80
- )
82
+ ),
83
+ "Could not generate the proposal.",
81
84
  ).update_ref(briefing)
85
+ if langauge:
86
+ proposal.language = langauge
87
+
88
+ return proposal
82
89
 
83
90
 
84
91
  class GenerateOutline(Action):
@@ -92,30 +99,101 @@ class GenerateOutline(Action):
92
99
  article_proposal: ArticleProposal,
93
100
  **_,
94
101
  ) -> Optional[ArticleOutline]:
95
- out = await self.propose(
96
- ArticleOutline,
97
- article_proposal.as_prompt(),
98
- **self.prepend_sys_msg(),
102
+ out = ok(
103
+ await self.propose(
104
+ ArticleOutline,
105
+ article_proposal.as_prompt(),
106
+ **self.prepend_sys_msg(),
107
+ ),
108
+ "Could not generate the outline.",
99
109
  )
100
110
 
101
- manual = await self.draft_rating_manual(
102
- topic=(
103
- topic
104
- := "Fix the internal referring error, make sure there is no more `ArticleRef` pointing to a non-existing article component."
111
+ introspect_manual = ok(
112
+ await self.draft_rating_manual(
113
+ topic=(
114
+ intro_topic
115
+ := "Fix the error in the article outline, make sure there is no more error in the article outline."
116
+ ),
105
117
  ),
118
+ "Could not generate the rating manual.",
106
119
  )
107
- while err := out.resolve_ref_error():
108
- logger.warning(f"Found error in the outline: \n{err}")
109
- out = await self.correct_obj(
110
- out,
111
- reference=f"# Referring Error\n{err}",
112
- topic=topic,
113
- rating_manual=manual,
114
- supervisor_check=False,
120
+
121
+ while pack := out.find_introspected():
122
+ component, err = ok(pack)
123
+ logger.warning(f"Found introspected error: {err}")
124
+ corrected = ok(
125
+ await self.correct_obj(
126
+ component,
127
+ reference=f"# Original Article Outline\n{out.display()}\n# Error Need to be fixed\n{err}",
128
+ topic=intro_topic,
129
+ rating_manual=introspect_manual,
130
+ supervisor_check=False,
131
+ ),
132
+ "Could not correct the component.",
133
+ )
134
+ component.update_from(corrected)
135
+
136
+ ref_manual = ok(
137
+ await self.draft_rating_manual(
138
+ topic=(
139
+ ref_topic
140
+ := "Fix the internal referring error, make sure there is no more `ArticleRef` pointing to a non-existing article component."
141
+ ),
142
+ ),
143
+ "Could not generate the rating manual.",
144
+ )
145
+
146
+ while pack := out.find_illegal_ref():
147
+ ref, err = ok(pack)
148
+ logger.warning(f"Found illegal referring error: {err}")
149
+ ok(
150
+ await self.correct_obj_inplace(
151
+ ref,
152
+ reference=f"# Original Article Outline\n{out.display()}\n# Error Need to be fixed\n{err}\n\n",
153
+ topic=ref_topic,
154
+ rating_manual=ref_manual,
155
+ supervisor_check=False,
156
+ )
115
157
  )
116
158
  return out.update_ref(article_proposal)
117
159
 
118
160
 
161
+ class GenerateArticle(Action):
162
+ """Generate the article based on the outline."""
163
+
164
+ output_key: str = "article"
165
+ """The key of the output data."""
166
+
167
+ async def _execute(
168
+ self,
169
+ article_outline: ArticleOutline,
170
+ **_,
171
+ ) -> Optional[Article]:
172
+ article: Article = Article.from_outline(ok(article_outline, "Article outline not specified.")).update_ref(
173
+ article_outline
174
+ )
175
+
176
+ write_para_manual = ok(
177
+ await self.draft_rating_manual(w_topic := "write the following paragraph in the subsection.")
178
+ )
179
+
180
+ await gather(
181
+ *[
182
+ self.correct_obj_inplace(
183
+ subsec,
184
+ reference=f"# Original Article Outline\n{article_outline.display()}\n# Error Need to be fixed\n{err}",
185
+ topic=w_topic,
186
+ rating_manual=write_para_manual,
187
+ supervisor_check=False,
188
+ )
189
+ for _, __, subsec in article.iter_subsections()
190
+ if (err := subsec.introspect())
191
+ ],
192
+ return_exceptions=True,
193
+ )
194
+ return article
195
+
196
+
119
197
  class CorrectProposal(Action):
120
198
  """Correct the proposal of the article."""
121
199
 
@@ -143,60 +221,6 @@ class CorrectOutline(Action):
143
221
  )
144
222
 
145
223
 
146
- class GenerateArticle(Action):
147
- """Generate the article based on the outline."""
148
-
149
- output_key: str = "article"
150
- """The key of the output data."""
151
-
152
- async def _execute(
153
- self,
154
- article_outline: ArticleOutline,
155
- **_,
156
- ) -> Optional[Article]:
157
- article: Article = Article.from_outline(article_outline).update_ref(article_outline)
158
-
159
- writing_manual = await self.draft_rating_manual(
160
- topic=(
161
- topic_1
162
- := "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."
163
- ),
164
- )
165
- err_resolve_manual = await self.draft_rating_manual(
166
- topic=(topic_2 := "this article component has violated the constrain, please correct it.")
167
- )
168
- for c, deps in article.iter_dfs_with_deps(chapter=False):
169
- logger.info(f"Updating the article component: \n{c.display()}")
170
-
171
- out = ok(
172
- await self.correct_obj(
173
- c,
174
- reference=(
175
- ref := f"{article_outline.referenced.as_prompt()}\n" + "\n".join(d.display() for d in deps)
176
- ),
177
- topic=topic_1,
178
- rating_manual=writing_manual,
179
- supervisor_check=False,
180
- ),
181
- "Could not correct the article component.",
182
- )
183
- while err := c.resolve_update_error(out):
184
- logger.warning(f"Found error in the article component: \n{err}")
185
- out = ok(
186
- await self.correct_obj(
187
- out,
188
- reference=f"{ref}\n\n# Violated Error\n{err}",
189
- topic=topic_2,
190
- rating_manual=err_resolve_manual,
191
- supervisor_check=False,
192
- ),
193
- "Could not correct the article component.",
194
- )
195
-
196
- c.update_from(out)
197
- return article
198
-
199
-
200
224
  class CorrectArticle(Action):
201
225
  """Correct the article based on the outline."""
202
226
 
@@ -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
@@ -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
@@ -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}")