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.
- fabricatio/_rust.cp312-win_amd64.pyd +0 -0
- fabricatio/actions/article.py +26 -19
- fabricatio/models/extra/article_base.py +291 -0
- fabricatio/models/extra/article_main.py +45 -174
- fabricatio/models/extra/article_outline.py +52 -141
- fabricatio/models/extra/article_proposal.py +12 -14
- fabricatio/models/generic.py +79 -6
- fabricatio-0.2.7.dev5.data/scripts/tdown.exe +0 -0
- fabricatio-0.2.7.dev5.dist-info/METADATA +181 -0
- {fabricatio-0.2.7.dev3.dist-info → fabricatio-0.2.7.dev5.dist-info}/RECORD +12 -11
- fabricatio-0.2.7.dev3.data/scripts/tdown.exe +0 -0
- fabricatio-0.2.7.dev3.dist-info/METADATA +0 -436
- {fabricatio-0.2.7.dev3.dist-info → fabricatio-0.2.7.dev5.dist-info}/WHEEL +0 -0
- {fabricatio-0.2.7.dev3.dist-info → fabricatio-0.2.7.dev5.dist-info}/licenses/LICENSE +0 -0
Binary file
|
fabricatio/actions/article.py
CHANGED
@@ -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 =
|
96
|
-
|
97
|
-
|
98
|
-
|
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
|
-
|
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
|
-
|
110
|
-
|
111
|
-
reference=f"#
|
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.
|
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
|