fabricatio 0.2.7.dev4__cp312-cp312-win_amd64.whl → 0.2.8.dev0__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 +97 -73
- fabricatio/actions/output.py +36 -1
- fabricatio/capabilities/correct.py +26 -6
- fabricatio/models/action.py +2 -0
- fabricatio/models/extra/article_base.py +279 -89
- fabricatio/models/extra/article_main.py +35 -126
- fabricatio/models/extra/article_outline.py +6 -155
- fabricatio/models/extra/article_proposal.py +12 -14
- fabricatio/models/generic.py +71 -20
- fabricatio/models/usages.py +5 -1
- fabricatio-0.2.8.dev0.data/scripts/tdown.exe +0 -0
- {fabricatio-0.2.7.dev4.dist-info → fabricatio-0.2.8.dev0.dist-info}/METADATA +1 -1
- {fabricatio-0.2.7.dev4.dist-info → fabricatio-0.2.8.dev0.dist-info}/RECORD +16 -16
- fabricatio-0.2.7.dev4.data/scripts/tdown.exe +0 -0
- {fabricatio-0.2.7.dev4.dist-info → fabricatio-0.2.8.dev0.dist-info}/WHEEL +0 -0
- {fabricatio-0.2.7.dev4.dist-info → fabricatio-0.2.8.dev0.dist-info}/licenses/LICENSE +0 -0
@@ -2,25 +2,35 @@
|
|
2
2
|
|
3
3
|
from abc import abstractmethod
|
4
4
|
from enum import StrEnum
|
5
|
-
from
|
6
|
-
|
7
|
-
from
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
5
|
+
from functools import cache
|
6
|
+
from itertools import chain
|
7
|
+
from typing import Generator, List, Optional, Self, Tuple
|
8
|
+
|
9
|
+
from fabricatio.models.generic import (
|
10
|
+
CensoredAble,
|
11
|
+
Display,
|
12
|
+
FinalizedDumpAble,
|
13
|
+
Introspect,
|
14
|
+
ModelHash,
|
15
|
+
PersistentAble,
|
16
|
+
ProposedUpdateAble,
|
17
|
+
ResolveUpdateConflict,
|
18
|
+
)
|
13
19
|
|
14
20
|
|
15
21
|
class ReferringType(StrEnum):
|
16
22
|
"""Enumeration of different types of references that can be made in an article."""
|
17
23
|
|
18
|
-
CHAPTER
|
19
|
-
SECTION
|
20
|
-
SUBSECTION
|
24
|
+
CHAPTER = "chapter"
|
25
|
+
SECTION = "section"
|
26
|
+
SUBSECTION = "subsection"
|
27
|
+
|
21
28
|
|
29
|
+
type RefKey = Tuple[str, Optional[str], Optional[str]]
|
22
30
|
|
23
|
-
|
31
|
+
|
32
|
+
@cache
|
33
|
+
class ArticleRef(CensoredAble, Display, ProposedUpdateAble):
|
24
34
|
"""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.
|
25
35
|
|
26
36
|
Examples:
|
@@ -53,30 +63,21 @@ class ArticleRef(CensoredAble):
|
|
53
63
|
```
|
54
64
|
"""
|
55
65
|
|
56
|
-
referred_subsection_title: Optional[str] = None
|
57
|
-
"""`title` Field of the referenced subsection."""
|
58
|
-
|
59
|
-
referred_section_title: Optional[str] = None
|
60
|
-
"""`title` Field of the referenced section."""
|
61
|
-
|
62
66
|
referred_chapter_title: str
|
63
67
|
"""`title` Field of the referenced chapter"""
|
68
|
+
referred_section_title: Optional[str] = None
|
69
|
+
"""`title` Field of the referenced section."""
|
70
|
+
referred_subsection_title: Optional[str] = None
|
71
|
+
"""`title` Field of the referenced subsection."""
|
64
72
|
|
65
|
-
def
|
66
|
-
"""
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
"""Dereference the reference to the actual section or subsection within the provided article."""
|
72
|
-
|
73
|
-
@overload
|
74
|
-
def deref(self, article: "ArticleOutline") -> Optional["ArticleOutlineBase"]:
|
75
|
-
"""Dereference the reference to the actual section or subsection within the provided article."""
|
73
|
+
def update_from_inner(self, other: Self) -> Self:
|
74
|
+
"""Updates the current instance with the attributes of another instance."""
|
75
|
+
self.referred_chapter_title = other.referred_chapter_title
|
76
|
+
self.referred_section_title = other.referred_section_title
|
77
|
+
self.referred_subsection_title = other.referred_subsection_title
|
78
|
+
return self
|
76
79
|
|
77
|
-
def deref(
|
78
|
-
self, article: Union["ArticleOutline", "Article"]
|
79
|
-
) -> Union["ArticleOutlineBase", "ArticleMainBase", None]:
|
80
|
+
def deref(self, article: "ArticleBase") -> Optional["ArticleOutlineBase"]:
|
80
81
|
"""Dereference the reference to the actual section or subsection within the provided article.
|
81
82
|
|
82
83
|
Args:
|
@@ -103,90 +104,279 @@ class ArticleRef(CensoredAble):
|
|
103
104
|
return ReferringType.CHAPTER
|
104
105
|
|
105
106
|
|
106
|
-
class
|
107
|
-
"""
|
107
|
+
class ArticleMetaData(CensoredAble, Display):
|
108
|
+
"""Metadata for an article component."""
|
109
|
+
|
110
|
+
description: str
|
111
|
+
"""Description of the research component in academic style."""
|
112
|
+
|
113
|
+
support_to: List[ArticleRef]
|
114
|
+
"""List of references to other component of this articles that this component supports."""
|
115
|
+
depend_on: List[ArticleRef]
|
116
|
+
"""List of references to other component of this articles that this component depends on."""
|
117
|
+
|
118
|
+
writing_aim: List[str]
|
119
|
+
"""List of writing aims of the research component in academic style."""
|
120
|
+
title: str
|
121
|
+
"""Do not add any prefix or suffix to the title. should not contain special characters."""
|
122
|
+
|
123
|
+
|
124
|
+
class ArticleOutlineBase(
|
125
|
+
ArticleMetaData,
|
126
|
+
ResolveUpdateConflict,
|
127
|
+
ProposedUpdateAble,
|
128
|
+
PersistentAble,
|
129
|
+
ModelHash,
|
130
|
+
Introspect,
|
131
|
+
):
|
132
|
+
"""Base class for article outlines."""
|
133
|
+
|
134
|
+
@property
|
135
|
+
def metadata(self) -> ArticleMetaData:
|
136
|
+
"""Returns the metadata of the article component."""
|
137
|
+
return ArticleMetaData.model_validate(self, from_attributes=True)
|
138
|
+
|
139
|
+
def update_metadata(self, other: ArticleMetaData) -> Self:
|
140
|
+
"""Updates the metadata of the current instance with the attributes of another instance."""
|
141
|
+
self.support_to.clear()
|
142
|
+
self.support_to.extend(other.support_to)
|
143
|
+
self.depend_on.clear()
|
144
|
+
self.depend_on.extend(other.depend_on)
|
145
|
+
self.writing_aim.clear()
|
146
|
+
self.writing_aim.extend(other.writing_aim)
|
147
|
+
self.description = other.description
|
148
|
+
return self
|
149
|
+
|
150
|
+
def display_metadata(self) -> str:
|
151
|
+
"""Displays the metadata of the current instance."""
|
152
|
+
return self.model_dump_json(
|
153
|
+
indent=1, include={"title", "writing_aim", "description", "support_to", "depend_on"}
|
154
|
+
)
|
155
|
+
|
156
|
+
def update_from_inner(self, other: Self) -> Self:
|
157
|
+
"""Updates the current instance with the attributes of another instance."""
|
158
|
+
return self.update_metadata(other)
|
159
|
+
|
160
|
+
@abstractmethod
|
161
|
+
def to_typst_code(self) -> str:
|
162
|
+
"""Converts the component into a Typst code snippet for rendering."""
|
108
163
|
|
109
164
|
|
110
|
-
class
|
165
|
+
class SubSectionBase(ArticleOutlineBase):
|
111
166
|
"""Base class for article sections and subsections."""
|
112
167
|
|
113
|
-
|
114
|
-
|
168
|
+
def to_typst_code(self) -> str:
|
169
|
+
"""Converts the component into a Typst code snippet for rendering."""
|
170
|
+
return f"=== {self.title}\n"
|
115
171
|
|
172
|
+
def introspect(self) -> str:
|
173
|
+
"""Introspects the article subsection outline."""
|
174
|
+
return ""
|
116
175
|
|
117
|
-
|
118
|
-
|
176
|
+
def resolve_update_conflict(self, other: Self) -> str:
|
177
|
+
"""Resolve update errors in the article outline."""
|
178
|
+
if self.title != other.title:
|
179
|
+
return f"Title mismatched, expected `{self.title}`, got `{other.title}`"
|
180
|
+
return ""
|
119
181
|
|
120
|
-
sections: List[T] = Field(min_length=1)
|
121
|
-
"""List of sections, each containing a specific research component. Must contains at least 1 section, But do remember you should always add more section as required."""
|
122
182
|
|
183
|
+
class SectionBase[T: SubSectionBase](ArticleOutlineBase):
|
184
|
+
"""Base class for article sections and subsections."""
|
123
185
|
|
124
|
-
|
125
|
-
"""
|
186
|
+
subsections: List[T]
|
187
|
+
"""Subsections of the section. Contains at least one subsection. You can also add more as needed."""
|
126
188
|
|
127
|
-
|
128
|
-
|
189
|
+
def to_typst_code(self) -> str:
|
190
|
+
"""Converts the section into a Typst formatted code snippet.
|
129
191
|
|
192
|
+
Returns:
|
193
|
+
str: The formatted Typst code snippet.
|
194
|
+
"""
|
195
|
+
return f"== {self.title}\n" + "\n\n".join(subsec.to_typst_code() for subsec in self.subsections)
|
130
196
|
|
131
|
-
|
132
|
-
|
197
|
+
def resolve_update_conflict(self, other: Self) -> str:
|
198
|
+
"""Resolve update errors in the article outline."""
|
199
|
+
out = ""
|
200
|
+
if self.title != other.title:
|
201
|
+
out += f"Title mismatched, expected `{self.title}`, got `{other.title}`"
|
202
|
+
if len(self.subsections) != len(other.subsections):
|
203
|
+
out += f"Section count mismatched, expected `{len(self.subsections)}`, got `{len(other.subsections)}`"
|
204
|
+
return out or "\n".join(
|
205
|
+
[
|
206
|
+
conf
|
207
|
+
for s, o in zip(self.subsections, other.subsections, strict=True)
|
208
|
+
if (conf := s.resolve_update_conflict(o))
|
209
|
+
]
|
210
|
+
)
|
211
|
+
|
212
|
+
def update_from_inner(self, other: Self) -> Self:
|
213
|
+
"""Updates the current instance with the attributes of another instance."""
|
214
|
+
super().update_from_inner(other)
|
215
|
+
if len(self.subsections) == 0:
|
216
|
+
self.subsections = other.subsections
|
217
|
+
return self
|
133
218
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
"""Description of the research component in academic style."""
|
219
|
+
for self_subsec, other_subsec in zip(self.subsections, other.subsections, strict=True):
|
220
|
+
self_subsec.update_from(other_subsec)
|
221
|
+
return self
|
138
222
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
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."""
|
223
|
+
def introspect(self) -> str:
|
224
|
+
"""Introspects the article section outline."""
|
225
|
+
if len(self.subsections) == 0:
|
226
|
+
return f"Section `{self.title}` contains no subsections, expected at least one, but got 0, you can add one or more as needed."
|
227
|
+
return ""
|
147
228
|
|
148
|
-
writing_aim: List[str]
|
149
|
-
"""Required: List of specific rhetorical objectives (3-5 items).
|
150
|
-
Format: Each item must be an actionable phrase starting with a verb.
|
151
|
-
Example: ['Establish metric validity', 'Compare with baseline approaches',
|
152
|
-
'Justify threshold selection']"""
|
153
229
|
|
230
|
+
class ChapterBase[T: SectionBase](ArticleOutlineBase):
|
231
|
+
"""Base class for article chapters."""
|
154
232
|
|
155
|
-
|
156
|
-
"""
|
233
|
+
sections: List[T]
|
234
|
+
"""Sections of the chapter. Contains at least one section. You can also add more as needed."""
|
157
235
|
|
158
|
-
@abstractmethod
|
159
236
|
def to_typst_code(self) -> str:
|
160
|
-
"""Converts the
|
237
|
+
"""Converts the chapter into a Typst formatted code snippet for rendering."""
|
238
|
+
return f"= {self.title}\n" + "\n\n".join(sec.to_typst_code() for sec in self.sections)
|
239
|
+
|
240
|
+
def resolve_update_conflict(self, other: Self) -> str:
|
241
|
+
"""Resolve update errors in the article outline."""
|
242
|
+
out = ""
|
161
243
|
|
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
244
|
if self.title != other.title:
|
166
|
-
|
245
|
+
out += f"Title mismatched, expected `{self.title}`, got `{other.title}`"
|
246
|
+
if len(self.sections) == len(other.sections):
|
247
|
+
out += f"Chapter count mismatched, expected `{len(self.sections)}`, got `{len(other.sections)}`"
|
248
|
+
|
249
|
+
return out or "\n".join(
|
250
|
+
[conf for s, o in zip(self.sections, other.sections, strict=True) if (conf := s.resolve_update_conflict(o))]
|
251
|
+
)
|
252
|
+
|
253
|
+
def update_from_inner(self, other: Self) -> Self:
|
254
|
+
"""Updates the current instance with the attributes of another instance."""
|
255
|
+
if len(self.sections) == 0:
|
256
|
+
self.sections = other.sections
|
257
|
+
return self
|
258
|
+
|
259
|
+
for self_sec, other_sec in zip(self.sections, other.sections, strict=True):
|
260
|
+
self_sec.update_from(other_sec)
|
167
261
|
return self
|
168
262
|
|
169
|
-
|
170
|
-
|
171
|
-
|
263
|
+
def introspect(self) -> str:
|
264
|
+
"""Introspects the article chapter outline."""
|
265
|
+
if len(self.sections) == 0:
|
266
|
+
return f"Chapter `{self.title}` contains no sections, expected at least one, but got 0, you can add one or more as needed."
|
267
|
+
return ""
|
268
|
+
|
269
|
+
|
270
|
+
class ArticleBase[T: ChapterBase](FinalizedDumpAble):
|
271
|
+
"""Base class for article outlines."""
|
272
|
+
|
273
|
+
language: str
|
274
|
+
"""Written language of the article. SHALL be aligned to the language of the article proposal provided."""
|
275
|
+
|
276
|
+
title: str
|
277
|
+
"""Title of the academic paper."""
|
278
|
+
|
279
|
+
prospect: str
|
280
|
+
"""Consolidated research statement with four pillars:
|
281
|
+
1. Problem Identification: Current limitations
|
282
|
+
2. Methodological Response: Technical approach
|
283
|
+
3. Empirical Validation: Evaluation strategy
|
284
|
+
4. Scholarly Impact: Field contributions
|
285
|
+
"""
|
286
|
+
|
287
|
+
abstract: str
|
288
|
+
"""The abstract is a concise summary of the academic paper's main findings."""
|
289
|
+
chapters: List[T]
|
290
|
+
"""Chapters of the article. Contains at least one chapter. You can also add more as needed."""
|
291
|
+
|
292
|
+
def iter_dfs_rev(
|
293
|
+
self,
|
294
|
+
) -> Generator[ArticleOutlineBase, None, None]:
|
295
|
+
"""Performs a depth-first search (DFS) through the article structure in reverse order.
|
172
296
|
|
173
297
|
Returns:
|
174
|
-
|
298
|
+
Generator[ArticleMainBase]: Each component in the article structure in reverse order.
|
175
299
|
"""
|
300
|
+
for chap in self.chapters:
|
301
|
+
for sec in chap.sections:
|
302
|
+
yield from sec.subsections
|
303
|
+
yield sec
|
304
|
+
yield chap
|
176
305
|
|
177
|
-
|
178
|
-
|
179
|
-
"""Updates the current instance with the attributes of another instance."""
|
306
|
+
def iter_dfs(self) -> Generator[ArticleOutlineBase, None, None]:
|
307
|
+
"""Performs a depth-first search (DFS) through the article structure.
|
180
308
|
|
181
|
-
|
182
|
-
|
183
|
-
"""
|
184
|
-
|
309
|
+
Returns:
|
310
|
+
Generator[ArticleMainBase]: Each component in the article structure.
|
311
|
+
"""
|
312
|
+
for chap in self.chapters:
|
313
|
+
yield chap
|
314
|
+
for sec in chap.sections:
|
315
|
+
yield sec
|
316
|
+
yield from sec.subsections
|
185
317
|
|
186
|
-
def
|
187
|
-
"""
|
188
|
-
return self.model_dump_json() == other.model_dump_json()
|
318
|
+
def iter_sections(self) -> Generator[Tuple[ChapterBase, SectionBase], None, None]:
|
319
|
+
"""Iterates through all sections in the article.
|
189
320
|
|
190
|
-
|
191
|
-
|
192
|
-
|
321
|
+
Returns:
|
322
|
+
Generator[ArticleOutlineBase]: Each section in the article.
|
323
|
+
"""
|
324
|
+
for chap in self.chapters:
|
325
|
+
for sec in chap.sections:
|
326
|
+
yield chap, sec
|
327
|
+
|
328
|
+
def iter_subsections(self) -> Generator[Tuple[ChapterBase, SectionBase, SubSectionBase], None, None]:
|
329
|
+
"""Iterates through all subsections in the article.
|
330
|
+
|
331
|
+
Returns:
|
332
|
+
Generator[ArticleOutlineBase]: Each subsection in the article.
|
333
|
+
"""
|
334
|
+
for chap, sec in self.iter_sections():
|
335
|
+
for subsec in sec.subsections:
|
336
|
+
yield chap, sec, subsec
|
337
|
+
|
338
|
+
def find_introspected(self) -> Optional[Tuple[ArticleOutlineBase, str]]:
|
339
|
+
"""Finds the first introspected component in the article structure."""
|
340
|
+
summary = ""
|
341
|
+
for component in self.iter_dfs_rev():
|
342
|
+
summary += component.introspect()
|
343
|
+
if summary:
|
344
|
+
return component, summary
|
345
|
+
return None
|
346
|
+
|
347
|
+
def find_illegal_ref(self) -> Optional[Tuple[ArticleRef, str]]:
|
348
|
+
"""Finds the first illegal component in the outline.
|
349
|
+
|
350
|
+
Returns:
|
351
|
+
Tuple[ArticleOutlineBase, str]: A tuple containing the illegal component and an error message.
|
352
|
+
"""
|
353
|
+
summary = ""
|
354
|
+
for component in self.iter_dfs_rev():
|
355
|
+
for ref in chain(component.depend_on, component.support_to):
|
356
|
+
if not ref.deref(self):
|
357
|
+
summary += f"Invalid internal reference in `{component.__class__.__name__}` titled `{component.title}`, because the referred {ref.referring_type} is not exists within the article, see the original obj dump: {ref.model_dump()}\n"
|
358
|
+
if summary:
|
359
|
+
return ref, summary
|
360
|
+
return None
|
361
|
+
|
362
|
+
def finalized_dump(self) -> str:
|
363
|
+
"""Generates standardized hierarchical markup for academic publishing systems.
|
364
|
+
|
365
|
+
Implements ACL 2024 outline conventions with four-level structure:
|
366
|
+
= Chapter Title (Level 1)
|
367
|
+
== Section Title (Level 2)
|
368
|
+
=== Subsection Title (Level 3)
|
369
|
+
==== Subsubsection Title (Level 4)
|
370
|
+
|
371
|
+
Returns:
|
372
|
+
str: Strictly formatted outline with academic sectioning
|
373
|
+
|
374
|
+
Example:
|
375
|
+
= Methodology
|
376
|
+
== Neural Architecture Search Framework
|
377
|
+
=== Differentiable Search Space
|
378
|
+
==== Constrained Optimization Parameters
|
379
|
+
=== Implementation Details
|
380
|
+
== Evaluation Protocol
|
381
|
+
"""
|
382
|
+
return "\n\n".join(a.to_typst_code() for a in self.chapters)
|