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.
- fabricatio/_rust.cp39-win_amd64.pyd +0 -0
- fabricatio/_rust.pyi +11 -2
- fabricatio/actions/article.py +69 -42
- fabricatio/actions/output.py +21 -6
- fabricatio/capabilities/correct.py +34 -4
- fabricatio/capabilities/rag.py +41 -5
- fabricatio/capabilities/rating.py +4 -4
- fabricatio/capabilities/task.py +2 -2
- fabricatio/config.py +3 -0
- fabricatio/models/extra.py +285 -258
- fabricatio/models/generic.py +60 -9
- fabricatio/models/kwargs_types.py +20 -2
- fabricatio/models/usages.py +45 -37
- fabricatio-0.2.7.dev1.data/scripts/tdown.exe +0 -0
- {fabricatio-0.2.7.dev0.dist-info → fabricatio-0.2.7.dev1.dist-info}/METADATA +6 -2
- {fabricatio-0.2.7.dev0.dist-info → fabricatio-0.2.7.dev1.dist-info}/RECORD +18 -18
- fabricatio-0.2.7.dev0.data/scripts/tdown.exe +0 -0
- {fabricatio-0.2.7.dev0.dist-info → fabricatio-0.2.7.dev1.dist-info}/WHEEL +0 -0
- {fabricatio-0.2.7.dev0.dist-info → fabricatio-0.2.7.dev1.dist-info}/licenses/LICENSE +0 -0
fabricatio/models/extra.py
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
"""Extra models for built-in actions."""
|
2
2
|
|
3
|
-
from
|
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.
|
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(
|
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]
|
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]
|
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]
|
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]
|
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
|
-
|
263
|
-
"""
|
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
|
-
|
269
|
-
"""
|
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
|
-
|
275
|
-
|
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
|
-
|
280
|
-
"""
|
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
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
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
|
-
"""
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
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
|
-
|
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(
|
338
|
+
class ArticleChapterOutline(ArticleOutlineBase):
|
318
339
|
"""Macro-structural unit implementing standard academic paper organization."""
|
319
340
|
|
320
|
-
|
321
|
-
|
322
|
-
|
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(
|
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]
|
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(
|
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
|
-
|
435
|
-
"""
|
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
|
-
|
466
|
-
|
467
|
-
|
450
|
+
@abstractmethod
|
451
|
+
def to_typst_code(self) -> str:
|
452
|
+
"""Converts the component into a Typst code snippet for rendering."""
|
468
453
|
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
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
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
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
|
-
|
481
|
-
|
482
|
-
|
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
|
-
|
486
|
-
|
487
|
-
|
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
|
-
|
495
|
-
"""
|
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
|
-
|
525
|
-
|
490
|
+
def to_typst_code(self) -> str:
|
491
|
+
"""Converts the component into a Typst code snippet for rendering.
|
526
492
|
|
527
|
-
|
528
|
-
|
529
|
-
|
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
|
-
|
536
|
-
"""
|
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]
|
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
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
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
|
-
|
558
|
-
|
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
|
-
|
565
|
-
"""
|
566
|
-
Example: [SectionRef(chapter='Abstract', section='', subsection='')]"""
|
519
|
+
class ArticleChapter(ArticleBase):
|
520
|
+
"""Thematic progression implementing research function."""
|
567
521
|
|
568
|
-
|
569
|
-
"""
|
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
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
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
|
-
|
581
|
-
|
582
|
-
|
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(
|
536
|
+
class Article(Display, CensoredAble, WithRef[ArticleOutline]):
|
591
537
|
"""Complete academic paper specification with validation constraints."""
|
592
538
|
|
593
539
|
title: str = Field(...)
|
594
|
-
"""
|
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
|
-
"""
|
601
|
-
|
602
|
-
|
603
|
-
|
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
|
-
|
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
|
-
|
621
|
-
|
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
|
561
|
+
outline (ArticleOutline): The outline to generate the article from.
|
625
562
|
|
626
563
|
Returns:
|
627
|
-
|
564
|
+
Article: The generated article.
|
628
565
|
"""
|
629
566
|
# Set the title from the outline
|
630
|
-
|
567
|
+
article = Article(**outline.model_dump(include={"title", "abstract"}), chapters=[])
|
631
568
|
|
632
|
-
|
633
|
-
self.chapters = []
|
634
|
-
|
635
|
-
for chapter_outline in outline.chapters:
|
569
|
+
for chapter in outline.chapters:
|
636
570
|
# Create a new chapter
|
637
|
-
|
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
|
-
|
647
|
-
|
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
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
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
|
-
|
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
|
-
|
592
|
+
def chap_iter(self) -> Generator[ArticleChapter, None, None]:
|
593
|
+
"""Iterates over all chapters in the article.
|
676
594
|
|
677
|
-
|
595
|
+
Yields:
|
596
|
+
ArticleChapter: Each chapter in the article.
|
597
|
+
"""
|
598
|
+
yield from self.chapters
|
678
599
|
|
679
|
-
|
680
|
-
|
600
|
+
def section_iter(self) -> Generator[ArticleSection, None, None]:
|
601
|
+
"""Iterates over all sections in the article.
|
681
602
|
|
682
|
-
|
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>
|