fabricatio 0.2.7.dev4__cp312-cp312-manylinux_2_34_x86_64.whl → 0.2.7.dev5__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/actions/article.py +26 -19
- fabricatio/models/extra/article_base.py +166 -67
- fabricatio/models/extra/article_main.py +29 -92
- fabricatio/models/extra/article_outline.py +30 -24
- fabricatio/models/generic.py +59 -4
- fabricatio-0.2.7.dev5.data/scripts/tdown +0 -0
- {fabricatio-0.2.7.dev4.dist-info → fabricatio-0.2.7.dev5.dist-info}/METADATA +1 -1
- {fabricatio-0.2.7.dev4.dist-info → fabricatio-0.2.7.dev5.dist-info}/RECORD +11 -11
- fabricatio-0.2.7.dev4.data/scripts/tdown +0 -0
- {fabricatio-0.2.7.dev4.dist-info → fabricatio-0.2.7.dev5.dist-info}/WHEEL +0 -0
- {fabricatio-0.2.7.dev4.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(
|
@@ -1,11 +1,19 @@
|
|
1
1
|
"""A foundation for hierarchical document components with dependency tracking."""
|
2
|
-
|
3
|
-
from abc import abstractmethod
|
2
|
+
from abc import ABC
|
4
3
|
from enum import StrEnum
|
5
|
-
from typing import TYPE_CHECKING, List, Optional, Self, Union,
|
6
|
-
|
7
|
-
from fabricatio.models.generic import
|
8
|
-
|
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
|
+
)
|
9
17
|
|
10
18
|
if TYPE_CHECKING:
|
11
19
|
from fabricatio.models.extra.article_main import Article
|
@@ -15,9 +23,9 @@ if TYPE_CHECKING:
|
|
15
23
|
class ReferringType(StrEnum):
|
16
24
|
"""Enumeration of different types of references that can be made in an article."""
|
17
25
|
|
18
|
-
CHAPTER
|
19
|
-
SECTION
|
20
|
-
SUBSECTION
|
26
|
+
CHAPTER = "chapter"
|
27
|
+
SECTION = "section"
|
28
|
+
SUBSECTION = "subsection"
|
21
29
|
|
22
30
|
|
23
31
|
class ArticleRef(CensoredAble):
|
@@ -103,90 +111,181 @@ class ArticleRef(CensoredAble):
|
|
103
111
|
return ReferringType.CHAPTER
|
104
112
|
|
105
113
|
|
106
|
-
class SubSectionBase(
|
114
|
+
class SubSectionBase(
|
115
|
+
UpdateFrom,
|
116
|
+
Introspect,
|
117
|
+
):
|
107
118
|
"""Base class for article sections and subsections."""
|
108
119
|
|
120
|
+
title: str
|
121
|
+
"""Title of the subsection, do not add any prefix or suffix to the title. should not contain special characters."""
|
109
122
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
subsections: List[T] = Field(min_length=1)
|
114
|
-
"""List of subsections, each containing a specific research component. Must contains at least 1 subsection, But do remember you should always add more subsection as required."""
|
123
|
+
def to_typst_code(self) -> str:
|
124
|
+
"""Converts the component into a Typst code snippet for rendering."""
|
125
|
+
return f"=== {self.title}\n"
|
115
126
|
|
127
|
+
def update_from_inner(self, other: Self) -> Self:
|
128
|
+
return self
|
116
129
|
|
117
|
-
|
118
|
-
|
130
|
+
def introspect(self) -> str:
|
131
|
+
"""Introspects the article subsection outline."""
|
132
|
+
return ""
|
119
133
|
|
120
|
-
|
121
|
-
|
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 ""
|
122
139
|
|
123
140
|
|
124
|
-
class
|
125
|
-
|
141
|
+
class SectionBase[T: SubSectionBase](
|
142
|
+
UpdateFrom,
|
143
|
+
Introspect,
|
144
|
+
):
|
145
|
+
"""Base class for article sections and subsections."""
|
126
146
|
|
127
|
-
|
128
|
-
"""
|
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."""
|
129
151
|
|
152
|
+
def to_typst_code(self) -> str:
|
153
|
+
"""Converts the section into a Typst formatted code snippet.
|
130
154
|
|
131
|
-
|
132
|
-
|
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)
|
133
159
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
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
|
138
180
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
Note: References form a directed acyclic graph in the document structure."""
|
143
|
-
depend_on: List[ArticleRef]
|
144
|
-
"""Required: List of all essential ArticleRef objects identifying components this section builds upon.
|
145
|
-
Format: Each reference must point to a previously defined chapter, section, or subsection.
|
146
|
-
Note: Circular dependencies are not permitted."""
|
181
|
+
for self_subsec, other_subsec in zip(self.subsections, other.subsections, strict=True):
|
182
|
+
self_subsec.update_from(other_subsec)
|
183
|
+
return self
|
147
184
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
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 ""
|
153
190
|
|
154
191
|
|
155
|
-
class
|
156
|
-
|
192
|
+
class ChapterBase[T: SectionBase](
|
193
|
+
UpdateFrom,
|
194
|
+
Introspect,
|
195
|
+
):
|
196
|
+
"""Base class for article chapters."""
|
157
197
|
|
158
|
-
|
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."""
|
159
202
|
def to_typst_code(self) -> str:
|
160
|
-
"""Converts the
|
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 = ""
|
161
209
|
|
162
|
-
def _update_pre_check(self, other: Self) -> Self:
|
163
|
-
if not isinstance(other, self.__class__):
|
164
|
-
raise TypeError(f"Cannot update from a non-{self.__class__} instance.")
|
165
210
|
if self.title != other.title:
|
166
|
-
|
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)
|
167
227
|
return self
|
168
228
|
|
169
|
-
|
170
|
-
|
171
|
-
|
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.
|
172
248
|
|
173
249
|
Returns:
|
174
|
-
|
250
|
+
Generator[ArticleMainBase]: Each component in the article structure.
|
175
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."""
|
176
270
|
|
177
|
-
|
178
|
-
|
179
|
-
"""Updates the current instance with the attributes of another instance."""
|
271
|
+
description: str
|
272
|
+
"""Description of the research component in academic style."""
|
180
273
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
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."""
|
185
278
|
|
186
|
-
|
187
|
-
|
188
|
-
return self.model_dump_json() == other.model_dump_json()
|
279
|
+
writing_aim: List[str]
|
280
|
+
"""List of writing aims of the research component in academic style."""
|
189
281
|
|
190
|
-
def
|
191
|
-
"""
|
192
|
-
|
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
|
@@ -1,12 +1,12 @@
|
|
1
1
|
"""ArticleBase and ArticleSubsection classes for managing hierarchical document components."""
|
2
2
|
|
3
3
|
from itertools import chain
|
4
|
-
from typing import Generator, List, Self, Tuple
|
4
|
+
from typing import Generator, List, Self, Tuple, override
|
5
5
|
|
6
6
|
from fabricatio.journal import logger
|
7
7
|
from fabricatio.models.extra.article_base import (
|
8
8
|
ArticleBase,
|
9
|
-
|
9
|
+
ArticleOutlineBase,
|
10
10
|
ArticleRef,
|
11
11
|
ChapterBase,
|
12
12
|
SectionBase,
|
@@ -32,22 +32,19 @@ class Paragraph(CensoredAble):
|
|
32
32
|
"""List of sentences forming the paragraph's content."""
|
33
33
|
|
34
34
|
|
35
|
-
class ArticleSubsection(
|
35
|
+
class ArticleSubsection(ArticleOutlineBase, SubSectionBase):
|
36
36
|
"""Atomic argumentative unit with technical specificity."""
|
37
37
|
|
38
38
|
paragraphs: List[Paragraph]
|
39
39
|
"""List of Paragraph objects containing the content of the subsection."""
|
40
40
|
|
41
|
-
def
|
42
|
-
"""Resolve update errors in the article outline."""
|
43
|
-
if self.title != other.title:
|
44
|
-
return f"Title `{other.title}` mismatched, expected `{self.title}`. "
|
45
|
-
return ""
|
46
|
-
|
47
|
-
def _update_from_inner(self, other: Self) -> Self:
|
41
|
+
def update_from_inner(self, other: Self) -> Self:
|
48
42
|
"""Updates the current instance with the attributes of another instance."""
|
49
43
|
logger.debug(f"Updating SubSection {self.title}")
|
50
|
-
self
|
44
|
+
SubSectionBase.update_from(self, other)
|
45
|
+
ArticleOutlineBase.update_from(self, other)
|
46
|
+
self.paragraphs.clear()
|
47
|
+
self.paragraphs.extend(other.paragraphs)
|
51
48
|
return self
|
52
49
|
|
53
50
|
def to_typst_code(self) -> str:
|
@@ -59,77 +56,23 @@ class ArticleSubsection(ArticleMainBase, SubSectionBase):
|
|
59
56
|
return f"=== {self.title}\n" + "\n\n".join("".join(p.sentences) for p in self.paragraphs)
|
60
57
|
|
61
58
|
|
62
|
-
class ArticleSection(
|
59
|
+
class ArticleSection(ArticleOutlineBase, SectionBase[ArticleSubsection]):
|
63
60
|
"""Atomic argumentative unit with high-level specificity."""
|
64
61
|
|
65
|
-
def resolve_update_error(self, other: Self) -> str:
|
66
|
-
"""Resolve update errors in the article outline."""
|
67
|
-
if (s_len := len(self.subsections)) == 0:
|
68
|
-
return ""
|
69
|
-
|
70
|
-
if s_len != len(other.subsections):
|
71
|
-
return f"Subsections length mismatched, expected {len(self.subsections)}, got {len(other.subsections)}"
|
72
|
-
|
73
|
-
sub_sec_err_seq = [
|
74
|
-
out for s, o in zip(self.subsections, other.subsections, strict=True) if (out := s.resolve_update_error(o))
|
75
|
-
]
|
76
|
-
|
77
|
-
if sub_sec_err_seq:
|
78
|
-
return "\n".join(sub_sec_err_seq)
|
79
|
-
return ""
|
80
|
-
|
81
|
-
def _update_from_inner(self, other: Self) -> Self:
|
82
|
-
"""Updates the current instance with the attributes of another instance."""
|
83
|
-
if len(self.subsections) == 0:
|
84
|
-
self.subsections = other.subsections
|
85
|
-
return self
|
86
|
-
|
87
|
-
for self_subsec, other_subsec in zip(self.subsections, other.subsections, strict=True):
|
88
|
-
self_subsec.update_from(other_subsec)
|
89
|
-
return self
|
90
|
-
|
91
|
-
def to_typst_code(self) -> str:
|
92
|
-
"""Converts the section into a Typst formatted code snippet.
|
93
|
-
|
94
|
-
Returns:
|
95
|
-
str: The formatted Typst code snippet.
|
96
|
-
"""
|
97
|
-
return f"== {self.title}\n" + "\n\n".join(subsec.to_typst_code() for subsec in self.subsections)
|
98
62
|
|
99
63
|
|
100
|
-
class ArticleChapter(
|
64
|
+
class ArticleChapter(ArticleOutlineBase, ChapterBase[ArticleSection]):
|
101
65
|
"""Thematic progression implementing research function."""
|
102
66
|
|
103
|
-
def resolve_update_error(self, other: Self) -> str:
|
104
|
-
"""Resolve update errors in the article outline."""
|
105
|
-
if (s_len := len(self.sections)) == 0:
|
106
|
-
return ""
|
107
|
-
|
108
|
-
if s_len != len(other.sections):
|
109
|
-
return f"Sections length mismatched, expected {len(self.sections)}, got {len(other.sections)}"
|
110
|
-
sec_err_seq = [
|
111
|
-
out for s, o in zip(self.sections, other.sections, strict=True) if (out := s.resolve_update_error(o))
|
112
|
-
]
|
113
|
-
if sec_err_seq:
|
114
|
-
return "\n".join(sec_err_seq)
|
115
|
-
return ""
|
116
|
-
|
117
|
-
def _update_from_inner(self, other: Self) -> Self:
|
118
|
-
"""Updates the current instance with the attributes of another instance."""
|
119
|
-
if len(self.sections) == 0:
|
120
|
-
self.sections = other.sections
|
121
|
-
return self
|
122
|
-
|
123
|
-
for self_sec, other_sec in zip(self.sections, other.sections, strict=True):
|
124
|
-
self_sec.update_from(other_sec)
|
125
|
-
return self
|
126
67
|
|
127
|
-
def to_typst_code(self) -> str:
|
128
|
-
"""Converts the chapter into a Typst formatted code snippet for rendering."""
|
129
|
-
return f"= {self.title}\n" + "\n\n".join(sec.to_typst_code() for sec in self.sections)
|
130
68
|
|
131
|
-
|
132
|
-
|
69
|
+
class Article(
|
70
|
+
Display,
|
71
|
+
CensoredAble,
|
72
|
+
WithRef[ArticleOutline],
|
73
|
+
PersistentAble,
|
74
|
+
ArticleBase[ArticleChapter],
|
75
|
+
):
|
133
76
|
"""Represents a complete academic paper specification, incorporating validation constraints.
|
134
77
|
|
135
78
|
This class integrates display, censorship processing, article structure referencing, and persistence capabilities,
|
@@ -189,30 +132,24 @@ class Article(Display, CensoredAble, WithRef[ArticleOutline], PersistentAble, Ar
|
|
189
132
|
article.chapters.append(article_chapter)
|
190
133
|
return article
|
191
134
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
for sec in chap.sections:
|
200
|
-
yield from sec.subsections
|
201
|
-
yield sec
|
202
|
-
yield chap
|
203
|
-
|
204
|
-
def deref(self, ref: ArticleRef) -> ArticleMainBase:
|
135
|
+
@override
|
136
|
+
def iter_dfs(
|
137
|
+
self,
|
138
|
+
) -> Generator[ArticleChapter | ArticleSection | ArticleSubsection, None, None]:
|
139
|
+
return super().iter_dfs()
|
140
|
+
|
141
|
+
def deref(self, ref: ArticleRef) -> ArticleOutlineBase:
|
205
142
|
"""Resolves a reference to the corresponding section or subsection in the article.
|
206
143
|
|
207
144
|
Args:
|
208
145
|
ref (ArticleRef): The reference to resolve.
|
209
146
|
|
210
147
|
Returns:
|
211
|
-
|
148
|
+
ArticleOutlineBase: The corresponding section or subsection.
|
212
149
|
"""
|
213
150
|
return ok(ref.deref(self), f"{ref} not found in {self.title}")
|
214
151
|
|
215
|
-
def gather_dependencies(self, article:
|
152
|
+
def gather_dependencies(self, article: ArticleOutlineBase) -> List[ArticleOutlineBase]:
|
216
153
|
"""Gathers dependencies for all sections and subsections in the article.
|
217
154
|
|
218
155
|
This method should be called after the article is fully constructed.
|
@@ -226,11 +163,11 @@ class Article(Display, CensoredAble, WithRef[ArticleOutline], PersistentAble, Ar
|
|
226
163
|
|
227
164
|
return list(set(depends + supports))
|
228
165
|
|
229
|
-
def gather_dependencies_recursive(self, article:
|
166
|
+
def gather_dependencies_recursive(self, article: ArticleOutlineBase) -> List[ArticleOutlineBase]:
|
230
167
|
"""Gathers all dependencies recursively for the given article.
|
231
168
|
|
232
169
|
Args:
|
233
|
-
article (
|
170
|
+
article (ArticleOutlineBase): The article to gather dependencies for.
|
234
171
|
|
235
172
|
Returns:
|
236
173
|
List[ArticleBase]: A list of all dependencies for the given article.
|
@@ -269,7 +206,7 @@ class Article(Display, CensoredAble, WithRef[ArticleOutline], PersistentAble, Ar
|
|
269
206
|
|
270
207
|
def iter_dfs_with_deps(
|
271
208
|
self, chapter: bool = True, section: bool = True, subsection: bool = True
|
272
|
-
) -> Generator[Tuple[
|
209
|
+
) -> Generator[Tuple[ArticleOutlineBase, List[ArticleOutlineBase]], None, None]:
|
273
210
|
"""Iterates through the article in a depth-first manner, yielding each component and its dependencies.
|
274
211
|
|
275
212
|
Args:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
"""A module containing the ArticleOutline class, which represents the outline of an academic paper."""
|
2
2
|
|
3
|
-
from typing import Generator, List, Optional, Tuple, Union
|
3
|
+
from typing import Generator, List, Optional, Self, Tuple, Union, override
|
4
4
|
|
5
5
|
import regex
|
6
6
|
from fabricatio.models.extra.article_base import (
|
@@ -19,12 +19,26 @@ class ArticleSubsectionOutline(ArticleOutlineBase, SubSectionBase):
|
|
19
19
|
"""Atomic research component specification for academic paper generation."""
|
20
20
|
|
21
21
|
|
22
|
+
|
22
23
|
class ArticleSectionOutline(ArticleOutlineBase, SectionBase[ArticleSubsectionOutline]):
|
23
|
-
"""A slightly more detailed research component specification for academic paper generation."""
|
24
|
+
"""A slightly more detailed research component specification for academic paper generation, Must contain subsections."""
|
25
|
+
|
26
|
+
|
27
|
+
def update_from_inner(self, other: Self) -> Self:
|
28
|
+
"""Updates the current instance with the attributes of another instance."""
|
29
|
+
super().update_from_inner(other)
|
30
|
+
super(ArticleOutlineBase, self).update_from_inner(other)
|
31
|
+
return self
|
24
32
|
|
25
33
|
|
26
34
|
class ArticleChapterOutline(ArticleOutlineBase, ChapterBase[ArticleSectionOutline]):
|
27
|
-
"""Macro-structural unit implementing standard academic paper organization."""
|
35
|
+
"""Macro-structural unit implementing standard academic paper organization. Must contain sections."""
|
36
|
+
|
37
|
+
def update_from_inner(self, other: Self) -> Self:
|
38
|
+
"""Updates the current instance with the attributes of another instance."""
|
39
|
+
super().update_from_inner(other)
|
40
|
+
super(ArticleOutlineBase, self).update_from_inner(other)
|
41
|
+
return self
|
28
42
|
|
29
43
|
|
30
44
|
class ArticleOutline(
|
@@ -34,7 +48,7 @@ class ArticleOutline(
|
|
34
48
|
PersistentAble,
|
35
49
|
ArticleBase[ArticleChapterOutline],
|
36
50
|
):
|
37
|
-
"""
|
51
|
+
"""A class representing the outline of an academic paper."""
|
38
52
|
|
39
53
|
abstract: str
|
40
54
|
"""The abstract is a concise summary of the academic paper's main findings."""
|
@@ -82,26 +96,16 @@ class ArticleOutline(
|
|
82
96
|
lines.append(f"=== {i}.{j}.{k} {subsection.title}")
|
83
97
|
return "\n".join(lines)
|
84
98
|
|
85
|
-
|
86
|
-
|
99
|
+
@override
|
100
|
+
def iter_dfs(
|
101
|
+
self,
|
102
|
+
) -> Generator[ArticleChapterOutline | ArticleSectionOutline | ArticleSubsectionOutline, None, None]:
|
103
|
+
return super().iter_dfs()
|
104
|
+
def find_illegal(self) -> Optional[Tuple[ArticleOutlineBase, str]]:
|
105
|
+
"""Finds the first illegal component in the outline.
|
87
106
|
|
88
107
|
Returns:
|
89
|
-
ArticleOutlineBase:
|
90
|
-
"""
|
91
|
-
for chapter in self.chapters:
|
92
|
-
for section in chapter.sections:
|
93
|
-
yield from section.subsections
|
94
|
-
yield section
|
95
|
-
yield chapter
|
96
|
-
|
97
|
-
def resolve_ref_error(self) -> str:
|
98
|
-
"""Resolve reference errors in the article outline.
|
99
|
-
|
100
|
-
Returns:
|
101
|
-
str: Error message indicating reference errors in the article outline.
|
102
|
-
|
103
|
-
Notes:
|
104
|
-
This function is designed to find all invalid `ArticleRef` objs in `depend_on` and `support_to` fields, which will be added to the final error summary.
|
108
|
+
Tuple[ArticleOutlineBase, str]: A tuple containing the illegal component and an error message.
|
105
109
|
"""
|
106
110
|
summary = ""
|
107
111
|
for component in self.iter_dfs():
|
@@ -111,8 +115,10 @@ class ArticleOutline(
|
|
111
115
|
for ref in component.support_to:
|
112
116
|
if not ref.deref(self):
|
113
117
|
summary += f"Invalid internal reference in {component.__class__.__name__} titled `{component.title}` at `support_to` field, because the referred {ref.referring_type} is not exists within the article, see the original obj dump: {ref.model_dump()}\n"
|
114
|
-
|
115
|
-
|
118
|
+
summary += component.introspect()
|
119
|
+
if summary:
|
120
|
+
return component, summary
|
121
|
+
return None
|
116
122
|
|
117
123
|
@classmethod
|
118
124
|
def from_typst_code(
|
fabricatio/models/generic.py
CHANGED
@@ -95,7 +95,7 @@ class WithRef[T](Base):
|
|
95
95
|
"""Get the referenced object."""
|
96
96
|
return ok(self._reference, "_reference is None")
|
97
97
|
|
98
|
-
def update_ref[S](self: S, reference: T | S) -> S: # noqa: PYI019
|
98
|
+
def update_ref[S: "WithRef"](self: S, reference: T | S) -> S: # noqa: PYI019
|
99
99
|
"""Update the reference of the object."""
|
100
100
|
if isinstance(reference, self.__class__):
|
101
101
|
self._reference = reference.referenced
|
@@ -139,6 +139,61 @@ class PersistentAble(Base):
|
|
139
139
|
return self.model_validate_json(Path(path).read_text(encoding="utf-8"))
|
140
140
|
|
141
141
|
|
142
|
+
class ModelHash(Base):
|
143
|
+
"""Class that provides a hash value for the object."""
|
144
|
+
|
145
|
+
def __hash__(self) -> int:
|
146
|
+
"""Calculates a hash value for the ArticleBase object based on its model_dump_json representation."""
|
147
|
+
return hash(self.model_dump_json())
|
148
|
+
|
149
|
+
|
150
|
+
class UpdateFrom(Base):
|
151
|
+
"""Class that provides a method to update the object from another object."""
|
152
|
+
|
153
|
+
def update_pre_check(self, other: Self) -> Self:
|
154
|
+
"""Pre-check for updating the object from another object."""
|
155
|
+
if not isinstance(other, self.__class__):
|
156
|
+
raise TypeError(f"Cannot update from a non-{self.__class__.__name__} instance.")
|
157
|
+
|
158
|
+
return self
|
159
|
+
|
160
|
+
@abstractmethod
|
161
|
+
def update_from_inner(self, other: Self) -> Self:
|
162
|
+
"""Updates the current instance with the attributes of another instance."""
|
163
|
+
|
164
|
+
@final
|
165
|
+
def update_from(self, other: Self) -> Self:
|
166
|
+
"""Updates the current instance with the attributes of another instance."""
|
167
|
+
return self.update_pre_check(other).update_from_inner(other)
|
168
|
+
|
169
|
+
|
170
|
+
class ResolveUpdateConflict(Base):
|
171
|
+
"""Class that provides a method to update the object from another object."""
|
172
|
+
|
173
|
+
@abstractmethod
|
174
|
+
def resolve_update_conflict(self, other: Self) -> str:
|
175
|
+
"""Resolve the update conflict between two objects.
|
176
|
+
|
177
|
+
Args:
|
178
|
+
other (Self): The other object to resolve the update conflict with.
|
179
|
+
|
180
|
+
Returns:
|
181
|
+
str: The resolved update conflict.
|
182
|
+
"""
|
183
|
+
|
184
|
+
|
185
|
+
class Introspect(Base):
|
186
|
+
"""Class that provides a method to introspect the object."""
|
187
|
+
|
188
|
+
@abstractmethod
|
189
|
+
def introspect(self) -> str:
|
190
|
+
"""Internal introspection of the object.
|
191
|
+
|
192
|
+
Returns:
|
193
|
+
str: The internal introspection of the object.
|
194
|
+
"""
|
195
|
+
|
196
|
+
|
142
197
|
class WithBriefing(Named, Described):
|
143
198
|
"""Class that provides a briefing based on the name and description."""
|
144
199
|
|
@@ -392,7 +447,7 @@ class PrepareVectorization(Base):
|
|
392
447
|
"""
|
393
448
|
max_length = max_length or configs.embedding.max_sequence_length
|
394
449
|
chunk = self._prepare_vectorization_inner()
|
395
|
-
if len(chunk) > max_length:
|
450
|
+
if max_length and len(chunk) > max_length:
|
396
451
|
logger.error(err := f"Chunk exceeds maximum sequence length {max_length}.")
|
397
452
|
raise ValueError(err)
|
398
453
|
|
@@ -475,7 +530,7 @@ class ScopedConfig(Base):
|
|
475
530
|
"""Fallback to another instance's attribute values if the current instance's attributes are None.
|
476
531
|
|
477
532
|
Args:
|
478
|
-
other (
|
533
|
+
other (ScopedConfig): Another instance from which to copy attribute values.
|
479
534
|
|
480
535
|
Returns:
|
481
536
|
Self: The current instance, allowing for method chaining.
|
@@ -495,7 +550,7 @@ class ScopedConfig(Base):
|
|
495
550
|
"""Hold to another instance's attribute values if the current instance's attributes are None.
|
496
551
|
|
497
552
|
Args:
|
498
|
-
others (
|
553
|
+
others (Union[ScopedConfig, Iterable[ScopedConfig]]): Another instance or iterable of instances from which to copy attribute values.
|
499
554
|
|
500
555
|
Returns:
|
501
556
|
Self: The current instance, allowing for method chaining.
|
Binary file
|
@@ -1,18 +1,18 @@
|
|
1
|
-
fabricatio-0.2.7.
|
2
|
-
fabricatio-0.2.7.
|
3
|
-
fabricatio-0.2.7.
|
1
|
+
fabricatio-0.2.7.dev5.dist-info/METADATA,sha256=BL0X5JL2P3Rwk3o-nHr4puOd9XlTorm7KUf_gKw5Nmw,5122
|
2
|
+
fabricatio-0.2.7.dev5.dist-info/WHEEL,sha256=7FgAcpQES0h1xhfN9Ugve9FTUilU6sRAr1WJ5ph2cuw,108
|
3
|
+
fabricatio-0.2.7.dev5.dist-info/licenses/LICENSE,sha256=yDZaTLnOi03bi3Dk6f5IjhLUc5old2yOsihHWU0z-i0,1067
|
4
4
|
fabricatio/decorators.py,sha256=GrkclNTGT2bk7cjTyuca7mqSVlKwTcujcj3uBuZpT8s,7343
|
5
5
|
fabricatio/core.py,sha256=MaEKZ6DDmbdScAY-7F1gwGA6fr7ADX6Mz5rNVi2msFA,6277
|
6
|
-
fabricatio/models/generic.py,sha256=
|
6
|
+
fabricatio/models/generic.py,sha256=YknfoEKTr4iCjIBrAN7-OAqGLCueMpds0lDiJhq_Raw,18927
|
7
7
|
fabricatio/models/tool.py,sha256=ifivEnYiEUtjeRxQkX8vjfyzn1m1acgfrsABbQqCsGs,6912
|
8
8
|
fabricatio/models/role.py,sha256=UgIfGdfIBu4cOug8Nm1a04JCEwjXR_MDZUQhumwMptk,2710
|
9
9
|
fabricatio/models/kwargs_types.py,sha256=2tiApAy8JvpkDWKk_26_X1_g08mcHHKQz3c8pCd73x0,5286
|
10
10
|
fabricatio/models/utils.py,sha256=MYwUmvr2P2F4Q3b73IUft2D8WG5FN3hMHLBXKtru0kU,5678
|
11
11
|
fabricatio/models/extra/article_proposal.py,sha256=3X1zB6AvSowSESIXzCgGCCqU4TbeBWAdwv8uxU3Cx6Y,1685
|
12
|
-
fabricatio/models/extra/article_main.py,sha256=
|
12
|
+
fabricatio/models/extra/article_main.py,sha256=II9PbfNFsaX63I63E3mRblPPUZEZmDF-Y_2uScrIq2c,8268
|
13
13
|
fabricatio/models/extra/article_essence.py,sha256=q80VKO11QONkounDL98IpfG6DSC8ymfm7iQiWkzp3rY,9003
|
14
|
-
fabricatio/models/extra/article_outline.py,sha256=
|
15
|
-
fabricatio/models/extra/article_base.py,sha256=
|
14
|
+
fabricatio/models/extra/article_outline.py,sha256=5HEUNZ_ATUlQ8tKjlq-oxR48pY6Z_OTDt5BRg16MeWc,7553
|
15
|
+
fabricatio/models/extra/article_base.py,sha256=ANja0PAff3hBIPw_1uYmnaE9PYBGUglN9my4dHiBZik,11178
|
16
16
|
fabricatio/models/usages.py,sha256=c_yU0pBjzUW9e-om6nIImmRV32eRiX9oxSlkC2HAtz4,30837
|
17
17
|
fabricatio/models/events.py,sha256=UvOc6V3vfjKuvh7irDezJ8EGpsNo5yzLdq4xQexVonw,4063
|
18
18
|
fabricatio/models/task.py,sha256=-EnzpEyM6Z687gF1lPcmA2szEUw6dFpu3lOtseaz95o,10193
|
@@ -30,7 +30,7 @@ fabricatio/__init__.py,sha256=6EjK4SxbnvFxdO9ftkXD9rxSuoPEIITNzUkuMO9s3yU,1092
|
|
30
30
|
fabricatio/actions/output.py,sha256=sBQcpLKPslGv-HI751zTrL1H8Ec23uIWgnGDjmkF4e0,1127
|
31
31
|
fabricatio/actions/article_rag.py,sha256=jAoFU75vZ-jFROGh4bZKmvY10K9zJPLqzeEa7wSiwu8,1421
|
32
32
|
fabricatio/actions/rag.py,sha256=Tsjn9IkO8OlKlhBBnk7J6qh9st61jzD6SUYClGhYs7I,2686
|
33
|
-
fabricatio/actions/article.py,sha256=
|
33
|
+
fabricatio/actions/article.py,sha256=XApvwkhcOTxqyaubYE0fWIKMPacIv4HLze7Oi_dmodA,7854
|
34
34
|
fabricatio/_rust_instances.py,sha256=bQmlhUCcxTmRgvw1SfzYzNNpgW_UCjmkYw5f-VPAyg8,304
|
35
35
|
fabricatio/workflows/articles.py,sha256=oHNV5kNKEcOKP55FA7I1SlxQRlk6N26cpem_QYu05g0,1021
|
36
36
|
fabricatio/workflows/rag.py,sha256=uOZXprD479fUhLA6sYvEM8RWcVcUZXXtP0xRbTMPdHE,509
|
@@ -42,6 +42,6 @@ fabricatio/capabilities/review.py,sha256=_m7uGNfhW7iDhcCJrLiSBmEvMq56fpPIzNGh1X2
|
|
42
42
|
fabricatio/capabilities/propose.py,sha256=4QvONVVUp1rs34Te2Rjams6NioEt6FhEAxDWiveQnSg,1544
|
43
43
|
fabricatio/capabilities/task.py,sha256=5XUxYNkPIHKm-Q0_oCeEqS-i3kfq9twHqcDiZL0rKVo,4526
|
44
44
|
fabricatio/_rust.pyi,sha256=n6mFYqLQlyfumJZQ_E3SesR_yLrjfRLjf6N1VdlF6U8,3707
|
45
|
-
fabricatio/_rust.cpython-312-x86_64-linux-gnu.so,sha256=
|
46
|
-
fabricatio-0.2.7.
|
47
|
-
fabricatio-0.2.7.
|
45
|
+
fabricatio/_rust.cpython-312-x86_64-linux-gnu.so,sha256=EEpBtEeNd9mQ5lv5AJgI7bdSdtxzwWsFas-ec8T77M4,1914816
|
46
|
+
fabricatio-0.2.7.dev5.data/scripts/tdown,sha256=-rU6hPSXsdxUNfS2MJFnqtZRAs5KUUJByjD275jPl5c,4588520
|
47
|
+
fabricatio-0.2.7.dev5.dist-info/RECORD,,
|
Binary file
|
File without changes
|
File without changes
|