fabricatio 0.2.6.dev2__cp312-cp312-win_amd64.whl → 0.2.7.dev2__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.
@@ -1,171 +1,811 @@
1
1
  """Extra models for built-in actions."""
2
2
 
3
- from typing import List
3
+ from abc import abstractmethod
4
+ from enum import Enum
5
+ from itertools import chain
6
+ from typing import Dict, Generator, List, Optional, Self, Tuple, Union, final, overload
4
7
 
5
- from fabricatio.models.generic import Base, Display, FinalizedDumpAble, PrepareVectorization, ProposedAble
6
- from pydantic import Field
8
+ from fabricatio.journal import logger
9
+ from fabricatio.models.generic import AsPrompt, Base, CensoredAble, Display, PrepareVectorization, ProposedAble, WithRef
10
+ from fabricatio.models.utils import ok
11
+ from pydantic import BaseModel, Field
7
12
 
13
+ # <editor-fold desc="ArticleEssence">
8
14
 
9
- class Equation(Base):
10
- """Structured representation of mathematical equations (including their physical or conceptual meanings)."""
15
+
16
+ class Equation(BaseModel):
17
+ """Mathematical formalism specification for research contributions.
18
+
19
+ Encodes equations with dual representation: semantic meaning and typeset-ready notation.
20
+ """
11
21
 
12
22
  description: str
13
- """A concise explanation of the equation's meaning, purpose, and relevance in the context of the research."""
23
+ """Equation significance structured in three elements:
24
+ 1. Physical/conceptual meaning of the equation.
25
+ 2. Role in technical workflow (e.g., derivation, optimization, or analysis).
26
+ 3. Relationship to the paper's core contribution (e.g., theoretical foundation, empirical validation).
27
+ Example: "Defines constrained search space dimensionality reduction. Used in architecture optimization phase (Section 3.2). Enables 40% parameter reduction."
28
+ """
14
29
 
15
30
  latex_code: str
16
- """The LaTeX code used to represent the equation in a publication-ready format."""
31
+ """LaTeX representation following academic typesetting standards:
32
+ - Must use equation environment (e.g., `equation`, `align`).
33
+ - Multiline equations must align at '=' using `&`.
34
+ - Include unit annotations where applicable.
35
+ Example: "\\begin{equation} \\mathcal{L}_{NAS} = \\alpha \\|\\theta\\|_2 + \\beta H(p) \\end{equation}"
36
+ """
37
+
17
38
 
39
+ class Figure(BaseModel):
40
+ """Visual component specification for technical communication.
18
41
 
19
- class Figure(Base):
20
- """Structured representation of figures (including their academic significance and explanatory captions)."""
42
+ Combines graphical assets with structured academic captioning.Extracted from the article provided
43
+ """
21
44
 
22
45
  description: str
23
- """A detailed explanation of the figure's content and its role in conveying key insights."""
46
+ """Figure interpretation guide containing:
47
+ 1. Key visual elements mapping (e.g., axes, legends, annotations).
48
+ 2. Data representation methodology (e.g., visualization type, statistical measures).
49
+ 3. Connection to research findings (e.g., supports hypothesis, demonstrates performance).
50
+ Example: "Architecture search space topology (left) vs. convergence curves (right). Demonstrates NAS efficiency gains through constrained search."
51
+ """
24
52
 
25
53
  figure_caption: str
26
- """The caption accompanying the figure, summarizing its main points and academic value."""
54
+ """Complete caption following Nature-style guidelines:
55
+ 1. Brief overview statement (首句总结).
56
+ 2. Technical detail layer (e.g., data sources, experimental conditions).
57
+ 3. Result implication (e.g., key insights, implications for future work).
58
+ Example: "Figure 3: Differentiable NAS framework. (a) Search space topology with constrained dimensions. (b) Training convergence across language pairs. Dashed lines indicate baseline methods."
59
+ """
60
+
61
+ figure_serial_number: int
62
+ """The Image serial number extracted from the Markdown article provided, the path usually in the form of `![](images/1.jpg)`, in this case the serial number is `1`"""
63
+
27
64
 
28
- figure_path: str
29
- """The file path to the figure"""
65
+ class Algorithm(BaseModel):
66
+ """Algorithm specification for research contributions."""
30
67
 
68
+ title: str
69
+ """Algorithm title with technical focus descriptor (e.g., 'Gradient Descent Optimization').
31
70
 
32
- class Highlightings(Base):
33
- """Structured representation of highlighted elements in an academic paper (including equations, algorithms, figures, and tables)."""
71
+ Tip: Do not attempt to translate the original element titles when generating JSON.
72
+ """
73
+
74
+ description: str
75
+ """Algorithm description with technical focus descriptor:
76
+ - Includes input/output specifications.
77
+ - Describes key steps and their purpose.
78
+ - Explains its role in the research workflow.
79
+ Example: "Proposed algorithm for neural architecture search. Inputs include search space constraints and training data. Outputs optimized architecture."
80
+ """
34
81
 
35
- # Academic Achievements Showcase
36
- highlighted_equations: List[Equation] = Field(default_factory=list)
37
- """Core mathematical equations that represent breakthroughs in the field, accompanied by explanations of their physical or conceptual significance,Should always be in LaTeX format wrapped in $ or $$ signs."""
38
82
 
39
- highlighted_algorithms: List[str] = Field(default_factory=list)
40
- """Pseudocode for key algorithms, annotated to highlight innovative components."""
83
+ class Table(BaseModel):
84
+ """Table specification for research contributions."""
41
85
 
42
- highlighted_figures: List[Figure] = Field(default_factory=list)
43
- """Critical diagrams or illustrations, each accompanied by a caption explaining their academic importance."""
86
+ title: str
87
+ """Table title with technical focus descriptor (e.g., 'Comparison of Model Performance Metrics').
44
88
 
45
- highlighted_tables: List[str] = Field(default_factory=list)
46
- """Important data tables, annotated to indicate statistical significance or other notable findings."""
89
+ Tip: Do not attempt to translate the original element titles when generating JSON.
90
+ """
91
+
92
+ description: str
93
+ """Table description with technical focus descriptor:
94
+ - Includes data source and structure.
95
+ - Explains key columns/rows and their significance.
96
+ - Connects to research findings or hypotheses.
97
+ Example: "Performance metrics for different architectures. Columns represent accuracy, F1-score, and inference time. Highlights efficiency gains of proposed method."
98
+ """
99
+
100
+
101
+ class Highlightings(BaseModel):
102
+ """Technical showcase aggregator for research artifacts.
103
+
104
+ Curates core scientific components with machine-parseable annotations.
105
+ """
106
+
107
+ highlighted_equations: List[Equation]
108
+ """3-5 pivotal equations representing theoretical contributions:
109
+ - Each equation must be wrapped in $$ for display math.
110
+ - Contain at least one novel operator/symbol.
111
+ - Be referenced in Methods/Results sections.
112
+ Example: Equation describing proposed loss function.
113
+ """
114
+
115
+ highlighted_algorithms: List[Algorithm]
116
+ """1-2 key algorithms demonstrating methodological contributions:
117
+ - Include pseudocode or step-by-step descriptions.
118
+ - Highlight innovation in computational approach.
119
+ Example: Algorithm for constrained search space exploration.
120
+
121
+ Tip: Do not attempt to translate the original element titles when generating JSON.
122
+ """
123
+
124
+ highlighted_figures: List[Figure]
125
+ """4-6 key figures demonstrating:
126
+ 1. Framework overview (1 required).
127
+ 2. Quantitative results (2-3 required).
128
+ 3. Ablation studies (1 optional).
129
+ Each must appear in Results/Discussion chapters.
130
+ Example: Figure showing architecture topology and convergence curves.
131
+ """
132
+
133
+ highlighted_tables: List[Table]
134
+ """2-3 key tables summarizing:
135
+ - Comparative analysis of methods.
136
+ - Empirical results supporting claims.
137
+ Example: Table comparing model performance across datasets.
138
+
139
+ Tip: Do not attempt to translate the original element titles when generating JSON.
140
+ """
47
141
 
48
142
 
49
143
  class ArticleEssence(ProposedAble, Display, PrepareVectorization):
50
- """Structured representation of the core elements of an academic paper(providing a comprehensive digital profile of the paper's essential information)."""
144
+ """Semantic fingerprint of academic paper for structured analysis.
145
+
146
+ Encodes research artifacts with dual human-machine interpretability.
147
+ """
51
148
 
52
- # Basic Metadata
53
149
  title: str = Field(...)
54
- """The full title of the paper, including any subtitles if applicable."""
150
+ """Exact title of the original article without any modification.
151
+ Must be preserved precisely from the source material without:
152
+ - Translation
153
+ - Paraphrasing
154
+ - Adding/removing words
155
+ - Altering style or formatting
156
+ """
55
157
 
56
158
  authors: List[str]
57
- """A list of the paper's authors, typically in the order of contribution."""
159
+ """Original author names exactly as they appear in the source document. No translation or paraphrasing.
160
+ Extract complete list without any modifications or formatting changes."""
58
161
 
59
162
  keywords: List[str]
60
- """A list of keywords that summarize the paper's focus and facilitate indexing."""
163
+ """Original keywords exactly as they appear in the source document. No translation or paraphrasing.
164
+ Extract the complete set without modifying format or terminology."""
61
165
 
62
166
  publication_year: int
63
- """The year in which the paper was published."""
167
+ """Publication timestamp in ISO 8601 (YYYY format)."""
64
168
 
65
- # Core Content Elements
66
- highlightings: Highlightings = Field(default_factory=Highlightings)
67
- """A collection of highlighted elements in the paper, including equations, algorithms, figures, and tables."""
169
+ highlightings: Highlightings
170
+ """Technical highlight reel containing:
171
+ - Core equations (Theory)
172
+ - Key algorithms (Implementation)
173
+ - Critical figures (Results)
174
+ - Benchmark tables (Evaluation)"""
68
175
 
69
176
  domain: List[str]
70
- """The research domains or fields addressed by the paper (e.g., ['Natural Language Processing', 'Computer Vision'])."""
177
+ """Domain tags for research focus."""
71
178
 
72
179
  abstract: str = Field(...)
73
- """A structured abstract that outlines the research problem, methodology, and conclusions in three distinct sections."""
180
+ """Three-paragraph structured abstract:
181
+ Paragraph 1: Problem & Motivation (2-3 sentences)
182
+ Paragraph 2: Methodology & Innovations (3-4 sentences)
183
+ Paragraph 3: Results & Impact (2-3 sentences)
184
+ Total length: 150-250 words"""
74
185
 
75
186
  core_contributions: List[str]
76
- """Key academic contributions that distinguish the paper from prior work in the field."""
187
+ """3-5 technical contributions using CRediT taxonomy verbs.
188
+ Each item starts with action verb.
189
+ Example:
190
+ - 'Developed constrained NAS framework'
191
+ - 'Established cross-lingual transfer metrics'"""
77
192
 
78
193
  technical_novelty: List[str]
79
- """Specific technical innovations introduced by the research, listed as individual points."""
194
+ """Patent-style claims with technical specificity.
195
+ Format: 'A [system/method] comprising [novel components]...'
196
+ Example:
197
+ 'A neural architecture search system comprising:
198
+ a differentiable constrained search space;
199
+ multi-lingual transferability predictors...'"""
80
200
 
81
- # Academic Discussion Dimensions
82
201
  research_problems: List[str]
83
- """A clearly defined research question or problem addressed by the study."""
202
+ """Problem statements as how/why questions.
203
+ Example:
204
+ - 'How to reduce NAS computational overhead while maintaining search diversity?'
205
+ - 'Why do existing architectures fail in low-resource cross-lingual transfer?'"""
84
206
 
85
207
  limitations: List[str]
86
- """An analysis of the methodological or experimental limitations of the research."""
208
+ """Technical limitations analysis containing:
209
+ 1. Constraint source (data/method/theory)
210
+ 2. Impact quantification
211
+ 3. Mitigation pathway
212
+ Example:
213
+ 'Methodology constraint: Single-objective optimization (affects 5% edge cases),
214
+ mitigated through future multi-task extension'"""
87
215
 
88
216
  future_work: List[str]
89
- """Suggestions for potential directions or topics for follow-up studies."""
217
+ """Research roadmap items with 3 horizons:
218
+ 1. Immediate extensions (1 year)
219
+ 2. Mid-term directions (2-3 years)
220
+ 3. Long-term vision (5+ years)
221
+ Example:
222
+ 'Short-term: Adapt framework for vision transformers (ongoing with CVPR submission)'"""
90
223
 
91
224
  impact_analysis: List[str]
92
- """An assessment of the paper's potential influence on the development of the field."""
225
+ """Bibliometric impact projections:
226
+ - Expected citation counts (next 3 years)
227
+ - Target application domains
228
+ - Standard adoption potential
229
+ Example:
230
+ 'Predicted 150+ citations via integration into MMEngine (Alibaba OpenMMLab)'"""
93
231
 
94
232
  def _prepare_vectorization_inner(self) -> str:
95
233
  return self.model_dump_json()
96
234
 
97
235
 
98
- class ArticleProposal(ProposedAble, Display):
99
- """Structured representation of the proposal for an academic paper."""
236
+ # </editor-fold>
237
+
238
+
239
+ class ArticleProposal(CensoredAble, Display, WithRef[str], AsPrompt):
240
+ """Structured proposal for academic paper development with core research elements.
241
+
242
+ Guides LLM in generating comprehensive research proposals with clearly defined components.
243
+ """
100
244
 
101
245
  title: str = Field(...)
102
- """The proposed title of the paper."""
246
+ """Paper title in academic style (Title Case, 8-15 words). Example: 'Exploring Neural Architecture Search for Low-Resource Machine Translation'"""
103
247
 
104
- focused_problem: List[str] = Field(default_factory=list)
105
- """The specific research problem or question that the paper aims to address."""
106
- research_aim: List[str] = Field(default_factory=list)
107
- """The main objective or goal of the research, outlining what the study aims to achieve."""
108
- research_methods: List[str] = Field(default_factory=list)
109
- """The methods used in the research, including the approach, techniques, and tools employed."""
248
+ focused_problem: List[str]
249
+ """Specific research problem(s) or question(s) addressed (list of 1-3 concise statements).
250
+ Example: ['NAS computational overhead in low-resource settings', 'Architecture transferability across language pairs']"""
110
251
 
252
+ research_aim: List[str]
253
+ """Primary research objectives (list of 2-4 measurable goals).
254
+ Example: ['Develop parameter-efficient NAS framework', 'Establish cross-lingual architecture transfer metrics']"""
111
255
 
112
- class ArticleSubsectionOutline(Base):
113
- """Structured representation of the subsections of an academic paper."""
256
+ research_methods: List[str]
257
+ """Methodological components (list of techniques/tools).
258
+ Example: ['Differentiable architecture search', 'Transformer-based search space', 'Multi-lingual perplexity evaluation']"""
114
259
 
115
- title: str = Field(...)
116
- """The title of the subsection."""
260
+ technical_approaches: List[str]
261
+ """Technical approaches"""
117
262
 
118
- description: str = Field(...)
119
- """A brief description of the subsection's content should be, how it fits into the overall structure of the paper, and its significance in the context of the research."""
263
+ def _as_prompt_inner(self) -> Dict[str, str]:
264
+ return {"ArticleBriefing": self.referenced, "ArticleProposal": self.display()}
120
265
 
121
266
 
122
- class ArticleSectionOutline(Base):
123
- """Structured representation of the sections of an academic paper."""
267
+ class ReferringType(str, Enum):
268
+ """Enumeration of different types of references that can be made in an article."""
124
269
 
125
- title: str = Field(...)
126
- """The title of the section."""
127
- description: str = Field(...)
128
- """A brief description of the section's content should be, how it fits into the overall structure of the paper, and its significance in the context of the research."""
129
- subsections: List[ArticleSubsectionOutline] = Field(default_factory=list)
130
- """The subsections of the section, outlining their content and significance."""
270
+ CHAPTER: str = "chapter"
271
+ SECTION: str = "section"
272
+ SUBSECTION: str = "subsection"
131
273
 
132
274
 
133
- class ArticleChapterOutline(Base):
134
- """Structured representation of the chapters of an academic paper."""
275
+ class ArticleRef(CensoredAble):
276
+ """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."""
277
+
278
+ referred_chapter_title: str
279
+ """`title` Field of the referenced chapter"""
280
+
281
+ referred_section_title: Optional[str] = None
282
+ """`title` Field of the referenced section. Defaults to None if not applicable, which means the reference is pointing to the entire chapter."""
283
+
284
+ referred_subsection_title: Optional[str] = None
285
+ """`title` Field of the referenced subsection. Defaults to None if not applicable, which means the reference is pointing to the entire section."""
286
+
287
+ def __hash__(self) -> int:
288
+ """Overrides the default hash function to ensure consistent hashing across instances."""
289
+ return hash((self.referred_chapter_title, self.referred_section_title, self.referred_subsection_title))
290
+
291
+ @overload
292
+ def deref(self, article: "Article") -> Optional["ArticleBase"]:
293
+ """Dereference the reference to the actual section or subsection within the provided article."""
294
+
295
+ @overload
296
+ def deref(self, article: "ArticleOutline") -> Optional["ArticleOutlineBase"]:
297
+ """Dereference the reference to the actual section or subsection within the provided article."""
298
+
299
+ def deref(self, article: Union["ArticleOutline", "Article"]) -> Union["ArticleOutlineBase", "ArticleBase", None]:
300
+ """Dereference the reference to the actual section or subsection within the provided article.
301
+
302
+ Args:
303
+ article (ArticleOutline | Article): The article to dereference the reference from.
304
+
305
+ Returns:
306
+ ArticleBase | ArticleOutline | None: The dereferenced section or subsection, or None if not found.
307
+ """
308
+ chap = next((chap for chap in article.chapters if chap.title == self.referred_chapter_title), None)
309
+ if self.referred_section_title is None or chap is None:
310
+ return chap
311
+ sec = next((sec for sec in chap.sections if sec.title == self.referred_section_title), None)
312
+ if self.referred_subsection_title is None or sec is None:
313
+ return sec
314
+ return next((subsec for subsec in sec.subsections if subsec.title == self.referred_subsection_title), None)
315
+
316
+ @property
317
+ def referring_type(self) -> ReferringType:
318
+ """Determine the type of reference based on the presence of specific attributes."""
319
+ if self.referred_subsection_title is not None:
320
+ return ReferringType.SUBSECTION
321
+ if self.referred_section_title is not None:
322
+ return ReferringType.SECTION
323
+ return ReferringType.CHAPTER
324
+
325
+
326
+ # <editor-fold desc="ArticleOutline">
327
+ class ArticleOutlineBase(Base):
328
+ """Base class for article outlines."""
329
+
330
+ writing_aim: List[str]
331
+ """Required: List of specific rhetorical objectives (3-5 items).
332
+ Format: Each item must be an actionable phrase starting with a verb.
333
+ Example: ['Establish metric validity', 'Compare with baseline approaches',
334
+ 'Justify threshold selection']"""
335
+ depend_on: List[ArticleRef]
336
+ """Required: List of all essential ArticleRef objects identifying components this section builds upon.
337
+ Format: Each reference must point to a previously defined chapter, section, or subsection.
338
+ Note: Circular dependencies are not permitted."""
339
+ support_to: List[ArticleRef]
340
+ """Required: List of all essential ArticleRef objects identifying components this section provides evidence for.
341
+ Format: Each reference must point to a specific chapter, section, or subsection.
342
+ Note: References form a directed acyclic graph in the document structure."""
135
343
 
136
- title: str = Field(...)
137
- """The title of the chapter."""
138
344
  description: str = Field(...)
139
- """A brief description of the chapter's content should be, how it fits into the overall structure of the paper, and its significance in the context of the research."""
140
- sections: List[ArticleSectionOutline] = Field(default_factory=list)
141
- """The sections of the chapter, outlining their content and significance."""
345
+ """Description of the research component in academic style."""
346
+ title: str = Field(...)
347
+ """Title of the research component in academic style."""
348
+
349
+
350
+ class ArticleSubsectionOutline(ArticleOutlineBase):
351
+ """Atomic research component specification for academic paper generation."""
352
+
353
+
354
+ class ArticleSectionOutline(ArticleOutlineBase):
355
+ """A slightly more detailed research component specification for academic paper generation."""
356
+
357
+ subsections: List[ArticleSubsectionOutline] = Field(min_length=1)
358
+ """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."""
359
+
360
+
361
+ class ArticleChapterOutline(ArticleOutlineBase):
362
+ """Macro-structural unit implementing standard academic paper organization."""
363
+
364
+ sections: List[ArticleSectionOutline] = Field(min_length=1)
365
+ """Standard academic progression implementing chapter goals:
366
+ 1. Context Establishment
367
+ 2. Technical Presentation
368
+ 3. Empirical Validation
369
+ 4. Comparative Analysis
370
+ 5. Synthesis
142
371
 
372
+ Must contains at least 1 sections, But do remember you should always add more section as required.
373
+ """
143
374
 
144
- class ArticleOutline(ProposedAble, Display, FinalizedDumpAble):
145
- """Structured representation of the outline for an academic paper."""
375
+
376
+ class ArticleOutline(Display, CensoredAble, WithRef[ArticleProposal]):
377
+ """Complete academic paper blueprint with hierarchical validation."""
146
378
 
147
379
  title: str = Field(...)
148
- """The proposed title of the paper."""
380
+ """Title of the academic paper."""
149
381
 
150
382
  prospect: str = Field(...)
151
- """A brief description of the research problem or question that the paper aims to address manipulating methods or techniques"""
383
+ """Consolidated research statement with four pillars:
384
+ 1. Problem Identification: Current limitations
385
+ 2. Methodological Response: Technical approach
386
+ 3. Empirical Validation: Evaluation strategy
387
+ 4. Scholarly Impact: Field contributions
388
+
389
+ Example: 'Addressing NAS computational barriers through constrained
390
+ differentiable search spaces, validated via cross-lingual MT experiments
391
+ across 50+ languages, enabling efficient architecture discovery with
392
+ 60% reduced search costs.'"""
152
393
 
153
- chapters: List[ArticleChapterOutline] = Field(default_factory=list)
154
- """The chapters of the paper, outlining their content and significance."""
394
+ chapters: List[ArticleChapterOutline]
395
+ """List of ArticleChapterOutline objects representing the academic paper's structure."""
396
+
397
+ abstract: str = Field(...)
398
+ """The abstract is a concise summary of the academic paper's main findings."""
155
399
 
156
400
  def finalized_dump(self) -> str:
157
- """Finalized dump of the article outline.
401
+ """Generates standardized hierarchical markup for academic publishing systems.
402
+
403
+ Implements ACL 2024 outline conventions with four-level structure:
404
+ = Chapter Title (Level 1)
405
+ == Section Title (Level 2)
406
+ === Subsection Title (Level 3)
407
+ ==== Subsubsection Title (Level 4)
158
408
 
159
409
  Returns:
160
- str: The finalized dump of the article outline.
410
+ str: Strictly formatted outline with academic sectioning
411
+
412
+ Example:
413
+ = Methodology
414
+ == Neural Architecture Search Framework
415
+ === Differentiable Search Space
416
+ ==== Constrained Optimization Parameters
417
+ === Implementation Details
418
+ == Evaluation Protocol
161
419
  """
162
420
  lines: List[str] = []
421
+ for i, chapter in enumerate(self.chapters, 1):
422
+ lines.append(f"= Chapter {i}: {chapter.title}")
423
+ for j, section in enumerate(chapter.sections, 1):
424
+ lines.append(f"== {i}.{j} {section.title}")
425
+ for k, subsection in enumerate(section.subsections, 1):
426
+ lines.append(f"=== {i}.{j}.{k} {subsection.title}")
427
+ return "\n".join(lines)
163
428
 
429
+ def iter_dfs(self) -> Generator[ArticleOutlineBase, None, None]:
430
+ """Iterates through the article outline in a depth-first manner.
431
+
432
+ Returns:
433
+ ArticleOutlineBase: Each component in the article outline.
434
+ """
164
435
  for chapter in self.chapters:
165
- lines.append(f"= {chapter.title}")
166
436
  for section in chapter.sections:
167
- lines.append(f"== {section.title}")
437
+ yield from section.subsections
438
+ yield section
439
+ yield chapter
440
+
441
+ def resolve_ref_error(self) -> str:
442
+ """Resolve reference errors in the article outline.
443
+
444
+ Returns:
445
+ str: Error message indicating reference errors in the article outline.
446
+
447
+ Notes:
448
+ 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.
449
+ """
450
+ summary = ""
451
+ for component in self.iter_dfs():
452
+ for ref in component.depend_on:
453
+ if not ref.deref(self):
454
+ summary += f"Invalid internal reference in {component.__class__.__name__} titled `{component.title}` at `depend_on` field, because the referred {ref.referring_type} is not exists within the article, see the original obj dump: {ref.model_dump()}\n"
455
+ for ref in component.support_to:
456
+ if not ref.deref(self):
457
+ 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"
458
+
459
+ return summary
460
+
461
+
462
+ # </editor-fold>
463
+
464
+
465
+ # <editor-fold desc="Article">
466
+ class Paragraph(CensoredAble):
467
+ """Structured academic paragraph blueprint for controlled content generation."""
468
+
469
+ description: str
470
+ """Functional summary of the paragraph's role in document structure.
471
+ Example: 'Establishes NAS efficiency improvements through differentiable methods'"""
472
+
473
+ writing_aim: List[str]
474
+ """Specific communicative objectives for this paragraph's content.
475
+ Example: ['Introduce gradient-based NAS', 'Compare computational costs',
476
+ 'Link efficiency to practical applications']"""
477
+
478
+ sentences: List[str]
479
+ """List of sentences forming the paragraph's content."""
480
+
481
+
482
+ class ArticleBase(CensoredAble, Display, ArticleOutlineBase):
483
+ """Foundation for hierarchical document components with dependency tracking."""
484
+
485
+ @abstractmethod
486
+ def to_typst_code(self) -> str:
487
+ """Converts the component into a Typst code snippet for rendering."""
488
+
489
+ def _update_pre_check(self, other: Self) -> Self:
490
+ if not isinstance(other, self.__class__):
491
+ raise TypeError(f"Cannot update from a non-{self.__class__} instance.")
492
+ if self.title != other.title:
493
+ raise ValueError("Cannot update from a different title.")
494
+ return self
495
+
496
+ @abstractmethod
497
+ def resolve_update_error(self, other: Self) -> str:
498
+ """Resolve update errors in the article outline.
499
+
500
+ Returns:
501
+ str: Error message indicating update errors in the article outline.
502
+ """
503
+
504
+ @abstractmethod
505
+ def _update_from_inner(self, other: Self) -> Self:
506
+ """Updates the current instance with the attributes of another instance."""
507
+
508
+ @final
509
+ def update_from(self, other: Self) -> Self:
510
+ """Updates the current instance with the attributes of another instance."""
511
+ return self._update_pre_check(other)._update_from_inner(other)
512
+
513
+ def __eq__(self, other: "ArticleBase") -> bool:
514
+ """Compares two ArticleBase objects based on their model_dump_json representation."""
515
+ return self.model_dump_json() == other.model_dump_json()
516
+
517
+ def __hash__(self) -> int:
518
+ """Calculates a hash value for the ArticleBase object based on its model_dump_json representation."""
519
+ return hash(self.model_dump_json())
520
+
521
+
522
+ class ArticleSubsection(ArticleBase):
523
+ """Atomic argumentative unit with technical specificity."""
524
+
525
+ paragraphs: List[Paragraph]
526
+ """List of Paragraph objects containing the content of the subsection."""
527
+
528
+ def resolve_update_error(self, other: Self) -> str:
529
+ """Resolve update errors in the article outline."""
530
+ if self.title != other.title:
531
+ return f"Title `{other.title}` mismatched, expected `{self.title}`. "
532
+ return ""
533
+
534
+ def _update_from_inner(self, other: Self) -> Self:
535
+ """Updates the current instance with the attributes of another instance."""
536
+ logger.debug(f"Updating SubSection {self.title}")
537
+ self.paragraphs = other.paragraphs
538
+ return self
539
+
540
+ def to_typst_code(self) -> str:
541
+ """Converts the component into a Typst code snippet for rendering.
542
+
543
+ Returns:
544
+ str: Typst code snippet for rendering.
545
+ """
546
+ return f"=== {self.title}\n" + "\n\n".join("".join(p.sentences) for p in self.paragraphs)
547
+
548
+
549
+ class ArticleSection(ArticleBase):
550
+ """Atomic argumentative unit with high-level specificity."""
551
+
552
+ subsections: List[ArticleSubsection]
553
+ """List of ArticleSubsection objects containing the content of the section."""
554
+
555
+ def resolve_update_error(self, other: Self) -> str:
556
+ """Resolve update errors in the article outline."""
557
+ if (s_len := len(self.subsections)) == 0:
558
+ return ""
559
+
560
+ if s_len != len(other.subsections):
561
+ return f"Subsections length mismatched, expected {len(self.subsections)}, got {len(other.subsections)}"
562
+
563
+ sub_sec_err_seq = [
564
+ out for s, o in zip(self.subsections, other.subsections, strict=True) if (out := s.resolve_update_error(o))
565
+ ]
566
+
567
+ if sub_sec_err_seq:
568
+ return "\n".join(sub_sec_err_seq)
569
+ return ""
570
+
571
+ def _update_from_inner(self, other: Self) -> Self:
572
+ """Updates the current instance with the attributes of another instance."""
573
+ if len(self.subsections) == 0:
574
+ self.subsections = other.subsections
575
+ return self
576
+
577
+ for self_subsec, other_subsec in zip(self.subsections, other.subsections, strict=True):
578
+ self_subsec.update_from(other_subsec)
579
+ return self
580
+
581
+ def to_typst_code(self) -> str:
582
+ """Converts the section into a Typst formatted code snippet.
583
+
584
+ Returns:
585
+ str: The formatted Typst code snippet.
586
+ """
587
+ return f"== {self.title}\n" + "\n\n".join(subsec.to_typst_code() for subsec in self.subsections)
588
+
589
+
590
+ class ArticleChapter(ArticleBase):
591
+ """Thematic progression implementing research function."""
592
+
593
+ sections: List[ArticleSection]
594
+ """Thematic progression implementing chapter's research function."""
595
+
596
+ def resolve_update_error(self, other: Self) -> str:
597
+ """Resolve update errors in the article outline."""
598
+ if (s_len := len(self.sections)) == 0:
599
+ return ""
600
+
601
+ if s_len != len(other.sections):
602
+ return f"Sections length mismatched, expected {len(self.sections)}, got {len(other.sections)}"
603
+ sec_err_seq = [
604
+ out for s, o in zip(self.sections, other.sections, strict=True) if (out := s.resolve_update_error(o))
605
+ ]
606
+ if sec_err_seq:
607
+ return "\n".join(sec_err_seq)
608
+ return ""
609
+
610
+ def _update_from_inner(self, other: Self) -> Self:
611
+ """Updates the current instance with the attributes of another instance."""
612
+ if len(self.sections) == 0:
613
+ self.sections = other.sections
614
+ return self
615
+
616
+ for self_sec, other_sec in zip(self.sections, other.sections, strict=True):
617
+ self_sec.update_from(other_sec)
618
+ return self
619
+
620
+ def to_typst_code(self) -> str:
621
+ """Converts the chapter into a Typst formatted code snippet for rendering."""
622
+ return f"= {self.title}\n" + "\n\n".join(sec.to_typst_code() for sec in self.sections)
623
+
624
+
625
+ class Article(Display, CensoredAble, WithRef[ArticleOutline]):
626
+ """Complete academic paper specification with validation constraints."""
627
+
628
+ title: str = Field(...)
629
+ """The academic title"""
630
+
631
+ abstract: str = Field(...)
632
+ """Abstract of the academic paper."""
633
+
634
+ chapters: List[ArticleChapter]
635
+ """List of ArticleChapter objects representing the academic paper's structure."""
636
+
637
+ def finalized_dump(self) -> str:
638
+ """Exports the article in `typst` format.
639
+
640
+ Returns:
641
+ str: Strictly formatted outline with typst formatting.
642
+ """
643
+ return "\n\n".join(c.to_typst_code() for c in self.chapters)
644
+
645
+ @classmethod
646
+ def from_outline(cls, outline: ArticleOutline) -> "Article":
647
+ """Generates an article from the given outline.
648
+
649
+ Args:
650
+ outline (ArticleOutline): The outline to generate the article from.
651
+
652
+ Returns:
653
+ Article: The generated article.
654
+ """
655
+ # Set the title from the outline
656
+ article = Article(**outline.model_dump(include={"title", "abstract"}), chapters=[])
657
+
658
+ for chapter in outline.chapters:
659
+ # Create a new chapter
660
+ article_chapter = ArticleChapter(
661
+ sections=[],
662
+ **chapter.model_dump(exclude={"sections"}),
663
+ )
664
+ for section in chapter.sections:
665
+ # Create a new section
666
+ article_section = ArticleSection(
667
+ subsections=[],
668
+ **section.model_dump(exclude={"subsections"}),
669
+ )
168
670
  for subsection in section.subsections:
169
- lines.append(f"=== {subsection.title}")
671
+ # Create a new subsection
672
+ article_subsection = ArticleSubsection(
673
+ paragraphs=[],
674
+ **subsection.model_dump(),
675
+ )
676
+ article_section.subsections.append(article_subsection)
677
+ article_chapter.sections.append(article_section)
678
+ article.chapters.append(article_chapter)
679
+ return article
680
+
681
+ def chap_iter(self) -> Generator[ArticleChapter, None, None]:
682
+ """Iterates over all chapters in the article.
683
+
684
+ Yields:
685
+ ArticleChapter: Each chapter in the article.
686
+ """
687
+ yield from self.chapters
688
+
689
+ def section_iter(self) -> Generator[ArticleSection, None, None]:
690
+ """Iterates over all sections in the article.
691
+
692
+ Yields:
693
+ ArticleSection: Each section in the article.
694
+ """
695
+ for chap in self.chapters:
696
+ yield from chap.sections
697
+
698
+ def subsection_iter(self) -> Generator[ArticleSubsection, None, None]:
699
+ """Iterates over all subsections in the article.
700
+
701
+ Yields:
702
+ ArticleSubsection: Each subsection in the article.
703
+ """
704
+ for sec in self.section_iter():
705
+ yield from sec.subsections
706
+
707
+ def iter_dfs(self) -> Generator[ArticleBase, None, None]:
708
+ """Performs a depth-first search (DFS) through the article structure.
709
+
710
+ Returns:
711
+ Generator[ArticleBase]: Each component in the article structure.
712
+ """
713
+ for chap in self.chap_iter():
714
+ for sec in chap.sections:
715
+ yield from sec.subsections
716
+ yield sec
717
+ yield chap
718
+
719
+ def deref(self, ref: ArticleRef) -> ArticleBase:
720
+ """Resolves a reference to the corresponding section or subsection in the article.
721
+
722
+ Args:
723
+ ref (ArticleRef): The reference to resolve.
724
+
725
+ Returns:
726
+ ArticleBase: The corresponding section or subsection.
727
+ """
728
+ return ok(ref.deref(self), f"{ref} not found in {self.title}")
729
+
730
+ def gather_dependencies(self, article: ArticleBase) -> List[ArticleBase]:
731
+ """Gathers dependencies for all sections and subsections in the article.
732
+
733
+ This method should be called after the article is fully constructed.
734
+ """
735
+ depends = [self.deref(a) for a in article.depend_on]
736
+
737
+ supports = []
738
+ for a in self.iter_dfs():
739
+ if article in {self.deref(b) for b in a.support_to}:
740
+ supports.append(a)
741
+
742
+ return list(set(depends + supports))
743
+
744
+ def gather_dependencies_recursive(self, article: ArticleBase) -> List[ArticleBase]:
745
+ """Gathers all dependencies recursively for the given article.
746
+
747
+ Args:
748
+ article (ArticleBase): The article to gather dependencies for.
749
+
750
+ Returns:
751
+ List[ArticleBase]: A list of all dependencies for the given article.
752
+ """
753
+ q = self.gather_dependencies(article)
754
+
755
+ deps = []
756
+ while q:
757
+ a = q.pop()
758
+ deps.extend(self.gather_dependencies(a))
759
+
760
+ deps = list(
761
+ chain(
762
+ filter(lambda x: isinstance(x, ArticleChapter), deps),
763
+ filter(lambda x: isinstance(x, ArticleSection), deps),
764
+ filter(lambda x: isinstance(x, ArticleSubsection), deps),
765
+ )
766
+ )
767
+
768
+ # Initialize result containers
769
+ formatted_code = ""
770
+ processed_components = []
771
+
772
+ # Process all dependencies
773
+ while deps:
774
+ component = deps.pop()
775
+ # Skip duplicates
776
+ if (component_code := component.to_typst_code()) in formatted_code:
777
+ continue
778
+
779
+ # Add this component
780
+ formatted_code += component_code
781
+ processed_components.append(component)
782
+
783
+ return processed_components
784
+
785
+ def iter_dfs_with_deps(
786
+ self, chapter: bool = True, section: bool = True, subsection: bool = True
787
+ ) -> Generator[Tuple[ArticleBase, List[ArticleBase]], None, None]:
788
+ """Iterates through the article in a depth-first manner, yielding each component and its dependencies.
789
+
790
+ Args:
791
+ chapter (bool, optional): Whether to include chapter components. Defaults to True.
792
+ section (bool, optional): Whether to include section components. Defaults to True.
793
+ subsection (bool, optional): Whether to include subsection components. Defaults to True.
794
+
795
+ Yields:
796
+ Tuple[ArticleBase, List[ArticleBase]]: Each component and its dependencies.
797
+ """
798
+ if all((not chapter, not section, not subsection)):
799
+ raise ValueError("At least one of chapter, section, or subsection must be True.")
800
+
801
+ for component in self.iter_dfs():
802
+ if not chapter and isinstance(component, ArticleChapter):
803
+ continue
804
+ if not section and isinstance(component, ArticleSection):
805
+ continue
806
+ if not subsection and isinstance(component, ArticleSubsection):
807
+ continue
808
+ yield component, (self.gather_dependencies_recursive(component))
809
+
170
810
 
171
- return "\n\n".join(lines)
811
+ # </editor-fold>