fabricatio 0.2.7.dev0__cp39-cp39-win_amd64.whl → 0.2.7.dev1__cp39-cp39-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,11 +1,15 @@
1
1
  """Extra models for built-in actions."""
2
2
 
3
- from typing import List, Self
3
+ from abc import abstractmethod
4
+ from itertools import chain
5
+ from typing import Dict, Generator, List, Optional, Self, Tuple, final
4
6
 
5
- from fabricatio.models.generic import Base, Display, FinalizedDumpAble, PrepareVectorization, ProposedAble
7
+ from fabricatio.journal import logger
8
+ from fabricatio.models.generic import AsPrompt, Base, CensoredAble, Display, PrepareVectorization, ProposedAble, WithRef
9
+ from fabricatio.models.utils import ok
10
+ from pydantic import BaseModel, Field
6
11
 
7
12
  # <editor-fold desc="ArticleEssence">
8
- from pydantic import BaseModel, Field
9
13
 
10
14
 
11
15
  class Equation(BaseModel):
@@ -231,7 +235,7 @@ class ArticleEssence(ProposedAble, Display, PrepareVectorization):
231
235
  # </editor-fold>
232
236
 
233
237
 
234
- class ArticleProposal(ProposedAble, Display):
238
+ class ArticleProposal(CensoredAble, Display, WithRef[str], AsPrompt):
235
239
  """Structured proposal for academic paper development with core research elements.
236
240
 
237
241
  Guides LLM in generating comprehensive research proposals with clearly defined components.
@@ -240,63 +244,80 @@ class ArticleProposal(ProposedAble, Display):
240
244
  title: str = Field(...)
241
245
  """Paper title in academic style (Title Case, 8-15 words). Example: 'Exploring Neural Architecture Search for Low-Resource Machine Translation'"""
242
246
 
243
- focused_problem: List[str] = Field(default_factory=list)
247
+ focused_problem: List[str]
244
248
  """Specific research problem(s) or question(s) addressed (list of 1-3 concise statements).
245
249
  Example: ['NAS computational overhead in low-resource settings', 'Architecture transferability across language pairs']"""
246
250
 
247
- research_aim: List[str] = Field(default_factory=list)
251
+ research_aim: List[str]
248
252
  """Primary research objectives (list of 2-4 measurable goals).
249
253
  Example: ['Develop parameter-efficient NAS framework', 'Establish cross-lingual architecture transfer metrics']"""
250
254
 
251
- research_methods: List[str] = Field(default_factory=list)
255
+ research_methods: List[str]
252
256
  """Methodological components (list of techniques/tools).
253
257
  Example: ['Differentiable architecture search', 'Transformer-based search space', 'Multi-lingual perplexity evaluation']"""
254
258
 
255
- technical_approaches: List[str] = Field(default_factory=list)
259
+ technical_approaches: List[str]
260
+ """Technical approaches"""
256
261
 
262
+ def _as_prompt_inner(self) -> Dict[str, str]:
263
+ return {"ArticleBriefing": self.referenced, "ArticleProposal": self.display()}
257
264
 
258
- # <editor-fold desc="ArticleOutline">
259
- class ArticleSubsectionOutline(Base):
260
- """Atomic research component specification for academic paper generation."""
261
265
 
262
- title: str = Field(...)
263
- """Technical focus descriptor following ACL title conventions:
264
- - Title Case with 4-8 word limit
265
- - Contains method and domain components
266
- Example: 'Differentiable Search Space Optimization'"""
266
+ class ArticleRef(CensoredAble):
267
+ """Reference to a specific section or subsection within an article.
267
268
 
268
- description: str = Field(...)
269
- """Tripartite content specification with strict structure:
270
- 1. Technical Core: Method/algorithm/formalism (1 sentence)
271
- 2. Structural Role: Placement rationale in section (1 clause)
272
- 3. Research Value: Contribution to paper's thesis (1 clause)
269
+ Always instantiated with a fine-grind reference to a specific subsection if possible.
270
+ """
273
271
 
274
- Example: 'Introduces entropy-constrained architecture parameters enabling
275
- gradient-based NAS. Serves as foundation for Section 3.2. Critical for
276
- maintaining search space diversity while ensuring convergence.'"""
272
+ referred_chapter_title: str
273
+ """Full title of the chapter that contains the referenced section."""
277
274
 
275
+ referred_section_title: Optional[str] = None
276
+ """Full title of the section that contains the referenced subsection. Defaults to None if not applicable, which means the reference is to the entire chapter."""
278
277
 
279
- class ArticleSectionOutline(Base):
280
- """Methodological unit organizing related technical components."""
278
+ referred_subsection_title: Optional[str] = None
279
+ """Full title of the subsection that contains the referenced paragraph. Defaults to None if not applicable, which means the reference is to the entire section."""
280
+
281
+ def __hash__(self) -> int:
282
+ """Overrides the default hash function to ensure consistent hashing across instances."""
283
+ return hash((self.referred_chapter_title, self.referred_section_title, self.referred_subsection_title))
281
284
 
282
- title: str = Field(...)
283
- """Process-oriented header with phase identification:
284
- - Title Case with 5-10 word limit
285
- - Indicates research stage/methodological focus
286
- Example: 'Cross-Lingual Evaluation Protocol'"""
285
+
286
+ # <editor-fold desc="ArticleOutline">
287
+ class ArticleOutlineBase(Base):
288
+ """Atomic research component specification for academic paper generation."""
289
+
290
+ writing_aim: List[str]
291
+ """Required: List of specific rhetorical objectives (3-5 items).
292
+ Format: Each item must be an actionable phrase starting with a verb.
293
+ Example: ['Establish metric validity', 'Compare with baseline approaches',
294
+ 'Justify threshold selection']"""
295
+ support_to: List[ArticleRef]
296
+ """Required: List of ArticleRef objects identifying components this section provides evidence for.
297
+ Format: Each reference must point to a specific chapter, section, or subsection.
298
+ Note: References form a directed acyclic graph in the document structure."""
299
+
300
+ depend_on: List[ArticleRef]
301
+ """Required: List of ArticleRef objects identifying components this section builds upon.
302
+ Format: Each reference must point to a previously defined chapter, section, or subsection.
303
+ Note: Circular dependencies are not permitted."""
287
304
 
288
305
  description: str = Field(...)
289
- """Functional specification with four required elements:
290
- 1. Research Stage: Paper progression position
291
- 2. Technical Innovations: Novel components
292
- 3. Scholarly Context: Relationship to prior work
293
- 4. Forward Flow: Connection to subsequent sections
306
+ """Description of the research component in academic style."""
307
+ title: str = Field(...)
308
+ """Title of the research component in academic style."""
309
+
310
+
311
+ class ArticleSubsectionOutline(ArticleOutlineBase):
312
+ """Atomic research component specification for academic paper generation."""
294
313
 
295
- Example: 'Implements constrained NAS framework building on Section 2's
296
- theoretical foundations. Introduces dynamic resource allocation mechanism.
297
- Directly supports Results section through ablation study parameters.'"""
298
314
 
299
- subsections: List[ArticleSubsectionOutline] = Field(..., min_length=3, max_length=5)
315
+ class ArticleSectionOutline(ArticleOutlineBase):
316
+ """Methodological unit organizing related technical components."""
317
+
318
+ subsections: List[ArticleSubsectionOutline] = Field(
319
+ ...,
320
+ )
300
321
  """IMRaD-compliant substructure with technical progression:
301
322
  1. Conceptual Framework
302
323
  2. Methodological Details
@@ -314,27 +335,12 @@ class ArticleSectionOutline(Base):
314
335
  ]"""
315
336
 
316
337
 
317
- class ArticleChapterOutline(Base):
338
+ class ArticleChapterOutline(ArticleOutlineBase):
318
339
  """Macro-structural unit implementing standard academic paper organization."""
319
340
 
320
- title: str = Field(...)
321
- """IMRaD-compliant chapter title with domain specification:
322
- - Title Case with 2-4 word limit
323
- - Matches standard paper sections
324
- Example: 'Multilingual Evaluation Results'"""
325
-
326
- description: str = Field(...)
327
- """Strategic chapter definition containing:
328
- 1. Research Phase: Introduction/Methods/Results/etc.
329
- 2. Chapter Objectives: 3-5 specific goals
330
- 3. Thesis Alignment: Supported claims/contributions
331
- 4. Structural Flow: Adjacent chapter relationships
332
-
333
- Example: 'Presents cross-lingual NAS results across 10 language pairs.
334
- Validates efficiency claims from Introduction. Provides empirical basis
335
- for Discussion chapter. Contrasts with single-language baselines.'"""
336
-
337
- sections: List[ArticleSectionOutline] = Field(..., min_length=3, max_length=5)
341
+ sections: List[ArticleSectionOutline] = Field(
342
+ ...,
343
+ )
338
344
  """Standard academic progression implementing chapter goals:
339
345
  1. Context Establishment
340
346
  2. Technical Presentation
@@ -352,7 +358,7 @@ class ArticleChapterOutline(Base):
352
358
  ]"""
353
359
 
354
360
 
355
- class ArticleOutline(ProposedAble, Display, FinalizedDumpAble):
361
+ class ArticleOutline(Display, CensoredAble, WithRef[ArticleProposal]):
356
362
  """Complete academic paper blueprint with hierarchical validation."""
357
363
 
358
364
  title: str = Field(...)
@@ -374,7 +380,7 @@ class ArticleOutline(ProposedAble, Display, FinalizedDumpAble):
374
380
  across 50+ languages, enabling efficient architecture discovery with
375
381
  60% reduced search costs.'"""
376
382
 
377
- chapters: List[ArticleChapterOutline] = Field(..., min_length=5, max_length=8)
383
+ chapters: List[ArticleChapterOutline]
378
384
  """IMRaD structure with enhanced academic validation:
379
385
  1. Introduction: Problem Space & Contributions
380
386
  2. Background: Theoretical Foundations
@@ -385,6 +391,9 @@ class ArticleOutline(ProposedAble, Display, FinalizedDumpAble):
385
391
  7. Conclusion: Synthesis & Future Work
386
392
  8. Appendices: Supplementary Materials"""
387
393
 
394
+ abstract: str = Field(...)
395
+ """The abstract is a concise summary of the academic paper's main findings."""
396
+
388
397
  def finalized_dump(self) -> str:
389
398
  """Generates standardized hierarchical markup for academic publishing systems.
390
399
 
@@ -419,7 +428,7 @@ class ArticleOutline(ProposedAble, Display, FinalizedDumpAble):
419
428
 
420
429
 
421
430
  # <editor-fold desc="Article">
422
- class Paragraph(ProposedAble):
431
+ class Paragraph(CensoredAble):
423
432
  """Structured academic paragraph blueprint for controlled content generation."""
424
433
 
425
434
  description: str
@@ -431,255 +440,273 @@ class Paragraph(ProposedAble):
431
440
  Example: ['Introduce gradient-based NAS', 'Compare computational costs',
432
441
  'Link efficiency to practical applications']"""
433
442
 
434
- lines: List[str]
435
- """Hierarchically structured content with enforced rhetorical elements:
436
- 1. Topic Sentence: Principal claim/position (1 sentence)
437
- 2. Development: Evidence chain with citations (2-4 sentences)
438
- 3. Synthesis: Interpretation & significance (1 sentence)
439
- 4. Transition: Logical bridge to next paragraph (optional)
440
-
441
- Example: [
442
- 'Differentiable NAS revolutionized architecture search efficiency.',
443
- 'DARTS reduced search costs from 2000+ to 4 GPU days (Liu et al., 2019) while maintaining competitive ImageNet accuracy.',
444
- 'This order-of-magnitude improvement enables NAS deployment in resource-constrained research contexts.',
445
- 'These efficiency gains directly impact our framework's design choices as detailed in Section 3.'
446
- ]"""
447
-
448
-
449
- class SectionRef(ProposedAble):
450
- """Cross-component reference system for maintaining document consistency."""
451
-
452
- ref_chapter_title: str
453
- """Title of referenced chapter (e.g., 'Methodology')"""
454
-
455
- ref_section_title: str
456
- """Exact section header text (e.g., '3.2 Gradient Optimization')"""
443
+ sentences: List[str]
444
+ """List of sentences forming the paragraph's content."""
457
445
 
458
- ref_subsection_title: str
459
- """Specific subsection identifier (e.g., '3.2.1 Learning Rate Scheduling')"""
460
446
 
461
-
462
- class ArticleBase(ProposedAble, Display):
447
+ class ArticleBase(CensoredAble, Display, ArticleOutlineBase):
463
448
  """Foundation for hierarchical document components with dependency tracking."""
464
449
 
465
- description: str
466
- """Functional purpose statement for this component's role in the paper.
467
- Example: 'Defines evaluation metrics for cross-lingual transfer experiments'"""
450
+ @abstractmethod
451
+ def to_typst_code(self) -> str:
452
+ """Converts the component into a Typst code snippet for rendering."""
468
453
 
469
- writing_aim: List[str]
470
- """Author intentions mapped to rhetorical moves:
471
- Example: ['Establish metric validity', 'Compare with baseline approaches',
472
- 'Justify threshold selection']"""
454
+ def _update_pre_check(self, other: Self) -> Self:
455
+ if not isinstance(other, self.__class__):
456
+ raise TypeError(f"Cannot update from a non-{self.__class__} instance.")
457
+ if self.title != other.title:
458
+ raise ValueError("Cannot update from a different title.")
473
459
 
474
- title: str = Field(...)
475
- """Standardized academic header following ACL style guidelines:
476
- - Title Case with maximal 12-word length
477
- - No abbreviations without prior definition
478
- Example: 'Multilingual Benchmark Construction'"""
460
+ @abstractmethod
461
+ def _update_from_inner(self, other: Self) -> Self:
462
+ """Updates the current instance with the attributes of another instance."""
463
+
464
+ @final
465
+ def update_from(self, other: Self) -> Self:
466
+ """Updates the current instance with the attributes of another instance."""
467
+ return self._update_pre_check(other)._update_from_inner(other)
479
468
 
480
- support_to: List[SectionRef]
481
- """Upstream dependencies requiring this component's validation.
482
- Format: List of hierarchical references to supported claims/sections
483
- Example: [SectionRef(chapter='Results', section='4.1', subsection='4.1.2')]"""
469
+ def __eq__(self, other: "ArticleBase") -> bool:
470
+ """Compares two ArticleBase objects based on their model_dump_json representation."""
471
+ return self.model_dump_json() == other.model_dump_json()
484
472
 
485
- depend_on: List[SectionRef]
486
- """Downstream prerequisites for content validity.
487
- Format: List of references to foundational components
488
- Example: [SectionRef(chapter='Methods', section='2.3', subsection='2.3.4')]"""
473
+ def __hash__(self) -> int:
474
+ """Calculates a hash value for the ArticleBase object based on its model_dump_json representation."""
475
+ return hash(self.model_dump_json())
489
476
 
490
477
 
491
478
  class ArticleSubsection(ArticleBase):
492
479
  """Atomic argumentative unit with technical specificity."""
493
480
 
494
- title: str = Field(...)
495
- """Technical descriptor with maximal information density:
496
- Format: [Method]-[Domain]-[Innovation]
497
- Example: 'Transformer-Based Architecture Search Space'"""
498
-
499
- support_to: List[SectionRef]
500
- """Immediate parent components and supported hypotheses.
501
- Example: [SectionRef(chapter='Methods', section='3', subsection='3.1')]"""
502
-
503
- depend_on: List[SectionRef]
504
- """Technical dependencies including equations, algorithms, and datasets.
505
- Example: [SectionRef(chapter='Background', section='2.2', subsection='2.2.3')]"""
506
-
507
- paragraphs: List[Paragraph] = Field(..., min_length=3, max_length=5)
508
- """Technical exposition following ACM writing guidelines:
509
- 1. Contextualization: Position in research design
510
- 2. Technical Detail: Equations/algorithms/code
511
- 3. Validation: Citations/experimental confirmation
512
- 4. Interpretation: Scholarly significance
513
- 5. Transition: Logical connection to subsequent content
514
-
515
- Example Paragraph Chain:
516
- [
517
- 'Our search space builds on standard CNN architectures...',
518
- 'Formally, we define architecture parameters $\\alpha \\in R^d$ where...',
519
- 'This parameterization reduces search complexity by 42% compared to...',
520
- 'The efficiency gains validate our approach to...'
521
- ]"""
481
+ paragraphs: List[Paragraph]
482
+ """List of Paragraph objects containing the content of the subsection."""
522
483
 
484
+ def _update_from_inner(self, other: Self) -> Self:
485
+ """Updates the current instance with the attributes of another instance."""
486
+ logger.debug(f"Updating SubSection {self.title}")
487
+ self.paragraphs = other.paragraphs
488
+ return self
523
489
 
524
- class ArticleSection(ArticleBase):
525
- """Methodological complete unit presenting cohesive research phase."""
490
+ def to_typst_code(self) -> str:
491
+ """Converts the component into a Typst code snippet for rendering.
526
492
 
527
- title: str = Field(...)
528
- """Process-oriented header indicating methodological scope.
529
- Example: 'Cross-Lingual Transfer Evaluation Protocol'"""
493
+ Returns:
494
+ str: Typst code snippet for rendering.
495
+ """
496
+ return f"=== {self.title}\n" + "\n\n".join("".join(p.sentences) for p in self.paragraphs)
530
497
 
531
- support_to: List[SectionRef]
532
- """Supported research questions and paper-level claims.
533
- Example: [SectionRef(chapter='Introduction', section='1', subsection='1.2')]"""
534
498
 
535
- depend_on: List[SectionRef]
536
- """Required methodological components and theoretical frameworks.
537
- Example: [SectionRef(chapter='Background', section='2', subsection='2.4')]"""
499
+ class ArticleSection(ArticleBase):
500
+ """Atomic argumentative unit with high-level specificity."""
538
501
 
539
- subsections: List[ArticleSubsection] = Field(..., min_length=3, max_length=5)
540
- """Thematic progression implementing section's research function:
541
- 1. Conceptual Framework
542
- 2. Technical Implementation
543
- 3. Experimental Validation
544
- 4. Comparative Analysis
545
- 5. Synthesis
502
+ subsections: List[ArticleSubsection]
546
503
 
547
- Example Subsection Flow:
548
- [
549
- 'Evaluation Metrics',
550
- 'Dataset Preparation',
551
- 'Baseline Comparisons',
552
- 'Ablation Studies',
553
- 'Interpretation Framework'
554
- ]"""
504
+ def _update_from_inner(self, other: Self) -> Self:
505
+ """Updates the current instance with the attributes of another instance."""
506
+ for self_subsec, other_subsec in zip(self.subsections, other.subsections, strict=True):
507
+ self_subsec.update_from(other_subsec)
508
+ return self
555
509
 
510
+ def to_typst_code(self) -> str:
511
+ """Converts the section into a Typst formatted code snippet.
556
512
 
557
- class ArticleChapter(ArticleBase):
558
- """Macro-structural unit implementing IMRaD document architecture."""
513
+ Returns:
514
+ str: The formatted Typst code snippet.
515
+ """
516
+ return f"== {self.title}\n" + "\n\n".join(subsec.to_typst_code() for subsec in self.subsections)
559
517
 
560
- title: str = Field(...)
561
- """Standard IMRaD chapter title with domain specification.
562
- Example: 'Neural Architecture Search for Low-Resource Languages'"""
563
518
 
564
- support_to: List[SectionRef]
565
- """Supported thesis statements and paper-level contributions.
566
- Example: [SectionRef(chapter='Abstract', section='', subsection='')]"""
519
+ class ArticleChapter(ArticleBase):
520
+ """Thematic progression implementing research function."""
567
521
 
568
- depend_on: List[SectionRef]
569
- """Foundational chapters and external knowledge prerequisites.
570
- Example: [SectionRef(chapter='Related Work', section='2', subsection='2.3')]"""
522
+ sections: List[ArticleSection]
523
+ """Thematic progression implementing chapter's research function."""
571
524
 
572
- sections: List[ArticleSection] = Field(..., min_length=3, max_length=5)
573
- """Complete research narrative implementing chapter objectives:
574
- 1. Context Establishment
575
- 2. Methodology Exposition
576
- 3. Results Presentation
577
- 4. Critical Analysis
578
- 5. Synthesis
525
+ def _update_from_inner(self, other: Self) -> Self:
526
+ """Updates the current instance with the attributes of another instance."""
527
+ for self_sec, other_sec in zip(self.sections, other.sections, strict=True):
528
+ self_sec.update_from(other_sec)
529
+ return self
579
530
 
580
- Example Section Hierarchy:
581
- [
582
- 'Theoretical Framework',
583
- 'Experimental Design',
584
- 'Results Analysis',
585
- 'Threats to Validity',
586
- 'Comparative Discussion'
587
- ]"""
531
+ def to_typst_code(self) -> str:
532
+ """Converts the chapter into a Typst formatted code snippet for rendering."""
533
+ return f"= {self.title}\n" + "\n\n".join(sec.to_typst_code() for sec in self.sections)
588
534
 
589
535
 
590
- class Article(ProposedAble, Display):
536
+ class Article(Display, CensoredAble, WithRef[ArticleOutline]):
591
537
  """Complete academic paper specification with validation constraints."""
592
538
 
593
539
  title: str = Field(...)
594
- """Full technical descriptor following ACL 2024 guidelines:
595
- Structure: [Method] for [Task] in [Domain]: [Subtitle with Technical Focus]
596
- Example: 'Efficient Differentiable NAS for Low-Resource MT:
597
- A Parameter-Sharing Approach to Cross-Lingual Transfer'"""
540
+ """The academic title"""
598
541
 
599
542
  abstract: str = Field(...)
600
- """Structured summary with controlled natural language:
601
- 1. Context: 2 clauses (problem + gap)
602
- 2. Methods: 3 clauses (approach + innovation + implementation)
603
- 3. Results: 3 clauses (metrics + comparisons + significance)
604
- 4. Impact: 2 clauses (theoretical + practical)
605
-
606
- Example: 'Neural architecture search (NAS) faces prohibitive... [150 words]'"""
607
-
608
- chapters: List[ArticleChapter] = Field(..., min_length=5, max_length=8)
609
- """IMRaD-compliant document structure with enhanced validation:
610
- 1. Introduction: Motivation & Contributions
611
- 2. Background: Literature & Theory
612
- 3. Methods: Technical Implementation
613
- 4. Experiments: Protocols & Setup
614
- 5. Results: Empirical Findings
615
- 6. Discussion: Interpretation & Limitations
616
- 7. Conclusion: Summary & Future Work
543
+ """Abstract of the academic paper."""
544
+
545
+ chapters: List[ArticleChapter]
546
+ """List of ArticleChapter objects representing the academic paper's structure."""
617
547
 
618
- Additional: Appendices, Ethics Review, Reproducibility Statements"""
548
+ def finalized_dump(self) -> str:
549
+ """Exports the article in `typst` format.
550
+
551
+ Returns:
552
+ str: Strictly formatted outline with typst formatting.
553
+ """
554
+ return "\n\n".join(c.to_typst_code() for c in self.chapters)
619
555
 
620
- def init_from_outline(self, outline: ArticleOutline) -> Self:
621
- """Initialize the article from a given outline.
556
+ @classmethod
557
+ def from_outline(cls, outline: ArticleOutline) -> "Article":
558
+ """Generates an article from the given outline.
622
559
 
623
560
  Args:
624
- outline (ArticleOutline): The outline to initialize from.
561
+ outline (ArticleOutline): The outline to generate the article from.
625
562
 
626
563
  Returns:
627
- Self: The current instance of the article.
564
+ Article: The generated article.
628
565
  """
629
566
  # Set the title from the outline
630
- self.title = outline.title
567
+ article = Article(**outline.model_dump(include={"title", "abstract"}), chapters=[])
631
568
 
632
- # Initialize chapters based on outline's chapters
633
- self.chapters = []
634
-
635
- for chapter_outline in outline.chapters:
569
+ for chapter in outline.chapters:
636
570
  # Create a new chapter
637
- chapter = ArticleChapter(
638
- title=chapter_outline.title,
639
- description=chapter_outline.description,
640
- writing_aim=["Implement " + chapter_outline.description],
641
- support_to=[],
642
- depend_on=[],
571
+ article_chapter = ArticleChapter(
643
572
  sections=[],
573
+ **chapter.model_dump(exclude={"sections"}),
644
574
  )
645
-
646
- # Create sections for each chapter
647
- for section_outline in chapter_outline.sections:
648
- section = ArticleSection(
649
- title=section_outline.title,
650
- description=section_outline.description,
651
- writing_aim=["Address " + section_outline.description],
652
- support_to=[],
653
- depend_on=[],
575
+ for section in chapter.sections:
576
+ # Create a new section
577
+ article_section = ArticleSection(
654
578
  subsections=[],
579
+ **section.model_dump(exclude={"subsections"}),
655
580
  )
656
-
657
- # Create subsections for each section
658
- for subsection_outline in section_outline.subsections:
659
- subsection = ArticleSubsection(
660
- title=subsection_outline.title,
661
- description=subsection_outline.description,
662
- writing_aim=["Explain " + subsection_outline.description],
663
- support_to=[],
664
- depend_on=[],
665
- paragraphs=[
666
- Paragraph(
667
- description=f"Implementation of {subsection_outline.title}",
668
- writing_aim=["Present key concepts", "Support main arguments"],
669
- lines=[],
670
- )
671
- ],
581
+ for subsection in section.subsections:
582
+ # Create a new subsection
583
+ article_subsection = ArticleSubsection(
584
+ paragraphs=[],
585
+ **subsection.model_dump(),
672
586
  )
673
- section.subsections.append(subsection)
587
+ article_section.subsections.append(article_subsection)
588
+ article_chapter.sections.append(article_section)
589
+ article.chapters.append(article_chapter)
590
+ return article
674
591
 
675
- chapter.sections.append(section)
592
+ def chap_iter(self) -> Generator[ArticleChapter, None, None]:
593
+ """Iterates over all chapters in the article.
676
594
 
677
- self.chapters.append(chapter)
595
+ Yields:
596
+ ArticleChapter: Each chapter in the article.
597
+ """
598
+ yield from self.chapters
678
599
 
679
- # Generate a placeholder abstract from the outline's prospect
680
- self.abstract = f"Abstract: {outline.prospect}"
600
+ def section_iter(self) -> Generator[ArticleSection, None, None]:
601
+ """Iterates over all sections in the article.
681
602
 
682
- return self
603
+ Yields:
604
+ ArticleSection: Each section in the article.
605
+ """
606
+ for chap in self.chapters:
607
+ yield from chap.sections
608
+
609
+ def subsection_iter(self) -> Generator[ArticleSubsection, None, None]:
610
+ """Iterates over all subsections in the article.
611
+
612
+ Yields:
613
+ ArticleSubsection: Each subsection in the article.
614
+ """
615
+ for sec in self.section_iter():
616
+ yield from sec.subsections
617
+
618
+ def iter_dfs(self) -> Generator[ArticleBase, None, None]:
619
+ """Performs a depth-first search (DFS) through the article structure.
620
+
621
+ Returns:
622
+ Generator[ArticleBase]: Each component in the article structure.
623
+ """
624
+ for chap in self.chap_iter():
625
+ for sec in chap.sections:
626
+ yield from sec.subsections
627
+ yield sec
628
+ yield chap
629
+
630
+ def deref(self, ref: ArticleRef) -> ArticleBase:
631
+ """Resolves a reference to the corresponding section or subsection in the article.
632
+
633
+ Args:
634
+ ref (ArticleRef): The reference to resolve.
635
+
636
+ Returns:
637
+ ArticleBase: The corresponding section or subsection.
638
+ """
639
+ chap = ok(
640
+ next(chap for chap in self.chap_iter() if chap.title == ref.referred_chapter_title), "Chapter not found"
641
+ )
642
+ if ref.referred_section_title is None:
643
+ return chap
644
+ sec = ok(next(sec for sec in chap.sections if sec.title == ref.referred_section_title))
645
+ if ref.referred_subsection_title is None:
646
+ return sec
647
+ return ok(next(subsec for subsec in sec.subsections if subsec.title == ref.referred_subsection_title))
648
+
649
+ def gather_dependencies(self, article: ArticleBase) -> List[ArticleBase]:
650
+ """Gathers dependencies for all sections and subsections in the article.
651
+
652
+ This method should be called after the article is fully constructed.
653
+ """
654
+ depends = [self.deref(a) for a in article.depend_on]
655
+
656
+ supports = []
657
+ for a in self.iter_dfs():
658
+ if article in {self.deref(b) for b in a.support_to}:
659
+ supports.append(a)
660
+
661
+ return list(set(depends + supports))
662
+
663
+ def gather_dependencies_recursive(self, article: ArticleBase) -> List[ArticleBase]:
664
+ """Gathers all dependencies recursively for the given article.
665
+
666
+ Args:
667
+ article (ArticleBase): The article to gather dependencies for.
668
+
669
+ Returns:
670
+ List[ArticleBase]: A list of all dependencies for the given article.
671
+ """
672
+ q = self.gather_dependencies(article)
673
+
674
+ deps = []
675
+ while a := q.pop():
676
+ deps.extend(self.gather_dependencies(a))
677
+
678
+ deps = list(
679
+ chain(
680
+ filter(lambda x: isinstance(x, ArticleChapter), deps),
681
+ filter(lambda x: isinstance(x, ArticleSection), deps),
682
+ filter(lambda x: isinstance(x, ArticleSubsection), deps),
683
+ )
684
+ )
685
+
686
+ # Initialize result containers
687
+ formatted_code = ""
688
+ processed_components = []
689
+
690
+ # Process all dependencies
691
+ while component := deps.pop():
692
+ # Skip duplicates
693
+ if (component_code := component.to_typst_code()) in formatted_code:
694
+ continue
695
+
696
+ # Add this component
697
+ formatted_code += component_code
698
+ processed_components.append(component)
699
+
700
+ return processed_components
701
+
702
+ def iter_dfs_with_deps(self) -> Generator[Tuple[ArticleBase, List[ArticleBase]], None, None]:
703
+ """Iterates through the article in a depth-first manner, yielding each component and its dependencies.
704
+
705
+ Yields:
706
+ Tuple[ArticleBase, List[ArticleBase]]: Each component and its dependencies.
707
+ """
708
+ for component in self.iter_dfs():
709
+ yield component, (self.gather_dependencies_recursive(component))
683
710
 
684
711
 
685
712
  # </editor-fold>