fabricatio 0.2.7.dev3__cp312-cp312-win_amd64.whl → 0.2.7.dev5__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.
Binary file
@@ -61,7 +61,7 @@ class GenerateArticleProposal(Action):
61
61
  logger.error("Task not approved, since all inputs are None.")
62
62
  return None
63
63
 
64
- return (
64
+ return ok(
65
65
  await self.propose(
66
66
  ArticleProposal,
67
67
  briefing := (
@@ -70,14 +70,15 @@ class GenerateArticleProposal(Action):
70
70
  ok(
71
71
  article_briefing_path
72
72
  or await self.awhich_pathstr(
73
- f"{task_input.briefing}\nExtract the path of file which contains the article briefing."
73
+ f"{ok(task_input).briefing}\nExtract the path of file which contains the article briefing."
74
74
  ),
75
75
  "Could not find the path of file to read.",
76
76
  )
77
77
  )
78
78
  ),
79
79
  **self.prepend_sys_msg(),
80
- )
80
+ ),
81
+ "Could not generate the proposal."
81
82
  ).update_ref(briefing)
82
83
 
83
84
 
@@ -92,27 +93,33 @@ class GenerateOutline(Action):
92
93
  article_proposal: ArticleProposal,
93
94
  **_,
94
95
  ) -> Optional[ArticleOutline]:
95
- out = await self.propose(
96
- ArticleOutline,
97
- article_proposal.as_prompt(),
98
- **self.prepend_sys_msg(),
96
+ out = ok(
97
+ await self.propose(
98
+ ArticleOutline,
99
+ article_proposal.as_prompt(),
100
+ **self.prepend_sys_msg(),
101
+ ),
102
+ "Could not generate the outline.",
99
103
  )
100
104
 
101
- manual = await self.draft_rating_manual(
105
+ manual = ok(await self.draft_rating_manual(
102
106
  topic=(
103
107
  topic
104
108
  := "Fix the internal referring error, make sure there is no more `ArticleRef` pointing to a non-existing article component."
105
109
  ),
106
- )
107
- while err := out.resolve_ref_error():
110
+ ),"Could not generate the rating manual.")
111
+
112
+ while pack := out.find_illegal():
113
+ component, err = ok(pack)
108
114
  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}",
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}",
112
118
  topic=topic,
113
119
  rating_manual=manual,
114
120
  supervisor_check=False,
115
- )
121
+ ),"Could not correct the component.")
122
+ component.update_from(corrected)
116
123
  return out.update_ref(article_proposal)
117
124
 
118
125
 
@@ -156,15 +163,15 @@ class GenerateArticle(Action):
156
163
  ) -> Optional[Article]:
157
164
  article: Article = Article.from_outline(article_outline).update_ref(article_outline)
158
165
 
159
- writing_manual = await self.draft_rating_manual(
166
+ writing_manual = ok(await self.draft_rating_manual(
160
167
  topic=(
161
168
  topic_1
162
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."
163
170
  ),
164
- )
165
- err_resolve_manual = await self.draft_rating_manual(
171
+ ))
172
+ err_resolve_manual = ok(await self.draft_rating_manual(
166
173
  topic=(topic_2 := "this article component has violated the constrain, please correct it.")
167
- )
174
+ ))
168
175
  for c, deps in article.iter_dfs_with_deps(chapter=False):
169
176
  logger.info(f"Updating the article component: \n{c.display()}")
170
177
 
@@ -180,7 +187,7 @@ class GenerateArticle(Action):
180
187
  ),
181
188
  "Could not correct the article component.",
182
189
  )
183
- while err := c.resolve_update_error(out):
190
+ while err := c.resolve_update_conflict(out):
184
191
  logger.warning(f"Found error in the article component: \n{err}")
185
192
  out = ok(
186
193
  await self.correct_obj(
@@ -0,0 +1,291 @@
1
+ """A foundation for hierarchical document components with dependency tracking."""
2
+ from abc import ABC
3
+ from enum import StrEnum
4
+ from typing import TYPE_CHECKING, Generator, List, Optional, Self, Union, overload
5
+
6
+ from fabricatio.models.generic import (
7
+ Base,
8
+ CensoredAble,
9
+ Display,
10
+ Introspect,
11
+ ModelHash,
12
+ PersistentAble,
13
+ ProposedAble,
14
+ ResolveUpdateConflict,
15
+ UpdateFrom,
16
+ )
17
+
18
+ if TYPE_CHECKING:
19
+ from fabricatio.models.extra.article_main import Article
20
+ from fabricatio.models.extra.article_outline import ArticleOutline
21
+
22
+
23
+ class ReferringType(StrEnum):
24
+ """Enumeration of different types of references that can be made in an article."""
25
+
26
+ CHAPTER = "chapter"
27
+ SECTION = "section"
28
+ SUBSECTION = "subsection"
29
+
30
+
31
+ class ArticleRef(CensoredAble):
32
+ """Reference to a specific chapter, section or subsection within the article. You SHALL not refer to an article component that is external and not present within our own article.
33
+
34
+ Examples:
35
+ - Referring to a chapter titled `Introduction`:
36
+ Using Python
37
+ ```python
38
+ ArticleRef(referred_chapter_title="Introduction")
39
+ ```
40
+ Using JSON
41
+ ```json
42
+ {referred_chapter_title="Introduction"}
43
+ ```
44
+ - Referring to a section titled `Background` under the `Introduction` chapter:
45
+ Using Python
46
+ ```python
47
+ ArticleRef(referred_chapter_title="Introduction", referred_section_title="Background")
48
+ ```
49
+ Using JSON
50
+ ```json
51
+ {referred_chapter_title="Introduction", referred_section_title="Background"}
52
+ ```
53
+ - Referring to a subsection titled `Related Work` under the `Background` section of the `Introduction` chapter:
54
+ Using Python
55
+ ```python
56
+ ArticleRef(referred_chapter_title="Introduction", referred_section_title="Background", referred_subsection_title="Related Work")
57
+ ```
58
+ Using JSON
59
+ ```json
60
+ {referred_chapter_title="Introduction", referred_section_title="Background", referred_subsection_title="Related Work"}
61
+ ```
62
+ """
63
+
64
+ referred_subsection_title: Optional[str] = None
65
+ """`title` Field of the referenced subsection."""
66
+
67
+ referred_section_title: Optional[str] = None
68
+ """`title` Field of the referenced section."""
69
+
70
+ referred_chapter_title: str
71
+ """`title` Field of the referenced chapter"""
72
+
73
+ def __hash__(self) -> int:
74
+ """Overrides the default hash function to ensure consistent hashing across instances."""
75
+ return hash((self.referred_chapter_title, self.referred_section_title, self.referred_subsection_title))
76
+
77
+ @overload
78
+ def deref(self, article: "Article") -> Optional["ArticleMainBase"]:
79
+ """Dereference the reference to the actual section or subsection within the provided article."""
80
+
81
+ @overload
82
+ def deref(self, article: "ArticleOutline") -> Optional["ArticleOutlineBase"]:
83
+ """Dereference the reference to the actual section or subsection within the provided article."""
84
+
85
+ def deref(
86
+ self, article: Union["ArticleOutline", "Article"]
87
+ ) -> Union["ArticleOutlineBase", "ArticleMainBase", None]:
88
+ """Dereference the reference to the actual section or subsection within the provided article.
89
+
90
+ Args:
91
+ article (ArticleOutline | Article): The article to dereference the reference from.
92
+
93
+ Returns:
94
+ ArticleMainBase | ArticleOutline | None: The dereferenced section or subsection, or None if not found.
95
+ """
96
+ chap = next((chap for chap in article.chapters if chap.title == self.referred_chapter_title), None)
97
+ if self.referred_section_title is None or chap is None:
98
+ return chap
99
+ sec = next((sec for sec in chap.sections if sec.title == self.referred_section_title), None)
100
+ if self.referred_subsection_title is None or sec is None:
101
+ return sec
102
+ return next((subsec for subsec in sec.subsections if subsec.title == self.referred_subsection_title), None)
103
+
104
+ @property
105
+ def referring_type(self) -> ReferringType:
106
+ """Determine the type of reference based on the presence of specific attributes."""
107
+ if self.referred_subsection_title is not None:
108
+ return ReferringType.SUBSECTION
109
+ if self.referred_section_title is not None:
110
+ return ReferringType.SECTION
111
+ return ReferringType.CHAPTER
112
+
113
+
114
+ class SubSectionBase(
115
+ UpdateFrom,
116
+ Introspect,
117
+ ):
118
+ """Base class for article sections and subsections."""
119
+
120
+ title: str
121
+ """Title of the subsection, do not add any prefix or suffix to the title. should not contain special characters."""
122
+
123
+ def to_typst_code(self) -> str:
124
+ """Converts the component into a Typst code snippet for rendering."""
125
+ return f"=== {self.title}\n"
126
+
127
+ def update_from_inner(self, other: Self) -> Self:
128
+ return self
129
+
130
+ def introspect(self) -> str:
131
+ """Introspects the article subsection outline."""
132
+ return ""
133
+
134
+ def resolve_update_conflict(self, other: Self) -> str:
135
+ """Resolve update errors in the article outline."""
136
+ if self.title != other.title:
137
+ return f"Title mismatched, expected `{self.title}`, got `{other.title}`"
138
+ return ""
139
+
140
+
141
+ class SectionBase[T: SubSectionBase](
142
+ UpdateFrom,
143
+ Introspect,
144
+ ):
145
+ """Base class for article sections and subsections."""
146
+
147
+ subsections: List[T]
148
+ """Subsections of the section. Contains at least one subsection. You can also add more as needed."""
149
+ title: str
150
+ """Title of the section, do not add any prefix or suffix to the title. should not contain special characters."""
151
+
152
+ def to_typst_code(self) -> str:
153
+ """Converts the section into a Typst formatted code snippet.
154
+
155
+ Returns:
156
+ str: The formatted Typst code snippet.
157
+ """
158
+ return f"== {self.title}\n" + "\n\n".join(subsec.to_typst_code() for subsec in self.subsections)
159
+
160
+ def resolve_update_conflict(self, other: Self) -> str:
161
+ """Resolve update errors in the article outline."""
162
+ out = ""
163
+ if self.title != other.title:
164
+ out += f"Title mismatched, expected `{self.title}`, got `{other.title}`"
165
+ if len(self.subsections) != len(other.subsections):
166
+ out += f"Section count mismatched, expected `{len(self.subsections)}`, got `{len(other.subsections)}`"
167
+ return out or "\n".join(
168
+ [
169
+ conf
170
+ for s, o in zip(self.subsections, other.subsections, strict=True)
171
+ if (conf := s.resolve_update_conflict(o))
172
+ ]
173
+ )
174
+
175
+ def update_from_inner(self, other: Self) -> Self:
176
+ """Updates the current instance with the attributes of another instance."""
177
+ if len(self.subsections) == 0:
178
+ self.subsections = other.subsections
179
+ return self
180
+
181
+ for self_subsec, other_subsec in zip(self.subsections, other.subsections, strict=True):
182
+ self_subsec.update_from(other_subsec)
183
+ return self
184
+
185
+ def introspect(self) -> str:
186
+ """Introspects the article section outline."""
187
+ if len(self.subsections) == 0:
188
+ return f"Section `{self.title}` contains no subsections, expected at least one, but got 0, you can add one or more as needed."
189
+ return ""
190
+
191
+
192
+ class ChapterBase[T: SectionBase](
193
+ UpdateFrom,
194
+ Introspect,
195
+ ):
196
+ """Base class for article chapters."""
197
+
198
+ sections: List[T]
199
+ """Sections of the chapter. Contains at least one section. You can also add more as needed."""
200
+ title: str
201
+ """Title of the chapter, do not add any prefix or suffix to the title. should not contain special characters."""
202
+ def to_typst_code(self) -> str:
203
+ """Converts the chapter into a Typst formatted code snippet for rendering."""
204
+ return f"= {self.title}\n" + "\n\n".join(sec.to_typst_code() for sec in self.sections)
205
+
206
+ def resolve_update_conflict(self, other: Self) -> str:
207
+ """Resolve update errors in the article outline."""
208
+ out = ""
209
+
210
+ if self.title != other.title:
211
+ out += f"Title mismatched, expected `{self.title}`, got `{other.title}`"
212
+ if len(self.sections) == len(other.sections):
213
+ out += f"Chapter count mismatched, expected `{len(self.sections)}`, got `{len(other.sections)}`"
214
+
215
+ return out or "\n".join(
216
+ [conf for s, o in zip(self.sections, other.sections, strict=True) if (conf := s.resolve_update_conflict(o))]
217
+ )
218
+
219
+ def update_from_inner(self, other: Self) -> Self:
220
+ """Updates the current instance with the attributes of another instance."""
221
+ if len(self.sections) == 0:
222
+ self.sections = other.sections
223
+ return self
224
+
225
+ for self_sec, other_sec in zip(self.sections, other.sections, strict=True):
226
+ self_sec.update_from(other_sec)
227
+ return self
228
+
229
+ def introspect(self) -> str:
230
+ """Introspects the article chapter outline."""
231
+ if len(self.sections) == 0:
232
+ return f"Chapter `{self.title}` contains no sections, expected at least one, but got 0, you can add one or more as needed."
233
+ return ""
234
+
235
+
236
+ class ArticleBase[T: ChapterBase](Base):
237
+ """Base class for article outlines."""
238
+
239
+ chapters: List[T]
240
+ """Chapters of the article. Contains at least one chapter. You can also add more as needed."""
241
+ title: str
242
+ """Title of the article outline, do not add any prefix or suffix to the title. should not contain special characters."""
243
+
244
+ def iter_dfs(
245
+ self,
246
+ ) -> Generator[ChapterBase | SectionBase | SubSectionBase, None, None]:
247
+ """Performs a depth-first search (DFS) through the article structure.
248
+
249
+ Returns:
250
+ Generator[ArticleMainBase]: Each component in the article structure.
251
+ """
252
+ for chap in self.chapters:
253
+ for sec in chap.sections:
254
+ yield from sec.subsections
255
+ yield sec
256
+ yield chap
257
+
258
+
259
+ class ArticleOutlineBase(
260
+ CensoredAble,
261
+ UpdateFrom,
262
+ ResolveUpdateConflict,
263
+ ProposedAble,
264
+ PersistentAble,
265
+ Display,
266
+ ModelHash,
267
+ ABC,
268
+ ):
269
+ """Base class for article outlines."""
270
+
271
+ description: str
272
+ """Description of the research component in academic style."""
273
+
274
+ support_to: List[ArticleRef]
275
+ """List of references to other component of this articles that this component supports."""
276
+ depend_on: List[ArticleRef]
277
+ """List of references to other component of this articles that this component depends on."""
278
+
279
+ writing_aim: List[str]
280
+ """List of writing aims of the research component in academic style."""
281
+
282
+ def update_from_inner(self, other: Self) -> Self:
283
+ """Updates the current instance with the attributes of another instance."""
284
+ self.support_to.clear()
285
+ self.support_to.extend(other.support_to)
286
+ self.depend_on.clear()
287
+ self.depend_on.extend(other.depend_on)
288
+ self.writing_aim.clear()
289
+ self.writing_aim.extend(other.writing_aim)
290
+ self.description = other.description
291
+ return self