fabricatio 0.3.15.dev4__cp313-cp313-win_amd64.whl → 0.4.0__cp313-cp313-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/__init__.py +9 -8
- fabricatio/actions/output.py +21 -22
- fabricatio/actions/rules.py +83 -83
- fabricatio/rust.cp313-win_amd64.pyd +0 -0
- fabricatio/workflows/rag.py +2 -1
- fabricatio-0.4.0.data/scripts/tdown.exe +0 -0
- {fabricatio-0.3.15.dev4.dist-info → fabricatio-0.4.0.dist-info}/METADATA +18 -16
- fabricatio-0.4.0.dist-info/RECORD +18 -0
- fabricatio/actions/article.py +0 -415
- fabricatio/actions/article_rag.py +0 -407
- fabricatio/capabilities/__init__.py +0 -1
- fabricatio/capabilities/advanced_judge.py +0 -20
- fabricatio/capabilities/advanced_rag.py +0 -61
- fabricatio/capabilities/censor.py +0 -105
- fabricatio/capabilities/check.py +0 -212
- fabricatio/capabilities/correct.py +0 -228
- fabricatio/capabilities/extract.py +0 -74
- fabricatio/capabilities/persist.py +0 -103
- fabricatio/capabilities/propose.py +0 -65
- fabricatio/capabilities/rag.py +0 -264
- fabricatio/capabilities/rating.py +0 -404
- fabricatio/capabilities/review.py +0 -114
- fabricatio/capabilities/task.py +0 -113
- fabricatio/decorators.py +0 -253
- fabricatio/emitter.py +0 -177
- fabricatio/fs/__init__.py +0 -35
- fabricatio/fs/curd.py +0 -153
- fabricatio/fs/readers.py +0 -61
- fabricatio/journal.py +0 -12
- fabricatio/models/action.py +0 -263
- fabricatio/models/adv_kwargs_types.py +0 -63
- fabricatio/models/extra/__init__.py +0 -1
- fabricatio/models/extra/advanced_judge.py +0 -32
- fabricatio/models/extra/aricle_rag.py +0 -286
- fabricatio/models/extra/article_base.py +0 -486
- fabricatio/models/extra/article_essence.py +0 -101
- fabricatio/models/extra/article_main.py +0 -286
- fabricatio/models/extra/article_outline.py +0 -46
- fabricatio/models/extra/article_proposal.py +0 -52
- fabricatio/models/extra/patches.py +0 -20
- fabricatio/models/extra/problem.py +0 -165
- fabricatio/models/extra/rag.py +0 -98
- fabricatio/models/extra/rule.py +0 -52
- fabricatio/models/generic.py +0 -812
- fabricatio/models/kwargs_types.py +0 -121
- fabricatio/models/role.py +0 -99
- fabricatio/models/task.py +0 -310
- fabricatio/models/tool.py +0 -328
- fabricatio/models/usages.py +0 -791
- fabricatio/parser.py +0 -114
- fabricatio/rust.pyi +0 -846
- fabricatio/utils.py +0 -156
- fabricatio/workflows/articles.py +0 -24
- fabricatio-0.3.15.dev4.data/scripts/tdown.exe +0 -0
- fabricatio-0.3.15.dev4.data/scripts/ttm.exe +0 -0
- fabricatio-0.3.15.dev4.dist-info/RECORD +0 -64
- {fabricatio-0.3.15.dev4.dist-info → fabricatio-0.4.0.dist-info}/WHEEL +0 -0
- {fabricatio-0.3.15.dev4.dist-info → fabricatio-0.4.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,486 +0,0 @@
|
|
1
|
-
"""A foundation for hierarchical document components with dependency tracking."""
|
2
|
-
|
3
|
-
from abc import ABC
|
4
|
-
from enum import StrEnum
|
5
|
-
from pathlib import Path
|
6
|
-
from typing import ClassVar, Generator, List, Optional, Self, Tuple, Type
|
7
|
-
|
8
|
-
from fabricatio.capabilities.persist import PersistentAble
|
9
|
-
from fabricatio.fs import dump_text, safe_text_read
|
10
|
-
from fabricatio.fs.readers import extract_sections
|
11
|
-
from fabricatio.journal import logger
|
12
|
-
from fabricatio.models.generic import (
|
13
|
-
AsPrompt,
|
14
|
-
Described,
|
15
|
-
FinalizedDumpAble,
|
16
|
-
Introspect,
|
17
|
-
Language,
|
18
|
-
ModelHash,
|
19
|
-
ProposedUpdateAble,
|
20
|
-
SketchedAble,
|
21
|
-
Titled,
|
22
|
-
WordCount,
|
23
|
-
)
|
24
|
-
from fabricatio.rust import (
|
25
|
-
detect_language,
|
26
|
-
extract_body,
|
27
|
-
replace_thesis_body,
|
28
|
-
split_out_metadata,
|
29
|
-
strip_comment,
|
30
|
-
to_metadata,
|
31
|
-
word_count,
|
32
|
-
)
|
33
|
-
from fabricatio.utils import fallback_kwargs, ok
|
34
|
-
from pydantic import Field
|
35
|
-
|
36
|
-
ARTICLE_WRAPPER = "// =-=-=-=-=-=-=-=-=-="
|
37
|
-
|
38
|
-
|
39
|
-
class ReferringType(StrEnum):
|
40
|
-
"""Enumeration of different types of references that can be made in an article."""
|
41
|
-
|
42
|
-
CHAPTER = "chapter"
|
43
|
-
SECTION = "section"
|
44
|
-
SUBSECTION = "subsection"
|
45
|
-
|
46
|
-
|
47
|
-
type RefKey = Tuple[str, Optional[str], Optional[str]]
|
48
|
-
|
49
|
-
|
50
|
-
class ArticleMetaData(SketchedAble, Described, WordCount, Titled, Language):
|
51
|
-
"""Metadata for an article component."""
|
52
|
-
|
53
|
-
description: str = Field(
|
54
|
-
alias="elaboration",
|
55
|
-
description=Described.model_fields["description"].description,
|
56
|
-
)
|
57
|
-
|
58
|
-
title: str = Field(alias="heading", description=Titled.model_fields["title"].description)
|
59
|
-
|
60
|
-
aims: List[str]
|
61
|
-
"""List of writing aims of the research component in academic style."""
|
62
|
-
|
63
|
-
_unstructured_body: str = ""
|
64
|
-
"""Store the source of the unknown information."""
|
65
|
-
|
66
|
-
@property
|
67
|
-
def typst_metadata_comment(self) -> str:
|
68
|
-
"""Generates a comment for the metadata of the article component."""
|
69
|
-
data = self.model_dump(
|
70
|
-
include={"description", "aims", "expected_word_count"},
|
71
|
-
by_alias=True,
|
72
|
-
)
|
73
|
-
return to_metadata({k: v for k, v in data.items() if v})
|
74
|
-
|
75
|
-
@property
|
76
|
-
def unstructured_body(self) -> str:
|
77
|
-
"""Returns the unstructured body of the article component."""
|
78
|
-
return self._unstructured_body
|
79
|
-
|
80
|
-
def update_unstructured_body[S: "ArticleMetaData"](self: S, body: str) -> S:
|
81
|
-
"""Update the unstructured body of the article component."""
|
82
|
-
self._unstructured_body = body
|
83
|
-
return self
|
84
|
-
|
85
|
-
@property
|
86
|
-
def language(self) -> str:
|
87
|
-
return detect_language(self.title)
|
88
|
-
|
89
|
-
|
90
|
-
class FromTypstCode(ArticleMetaData):
|
91
|
-
"""Base class for article components that can be created from a Typst code snippet."""
|
92
|
-
|
93
|
-
@classmethod
|
94
|
-
def from_typst_code(cls, title: str, body: str, **kwargs) -> Self:
|
95
|
-
"""Converts a Typst code snippet into an article component."""
|
96
|
-
data, body = split_out_metadata(body)
|
97
|
-
|
98
|
-
return cls(
|
99
|
-
heading=title.strip(),
|
100
|
-
**fallback_kwargs(data or {}, elaboration="", expected_word_count=word_count(body), aims=[]),
|
101
|
-
**kwargs,
|
102
|
-
)
|
103
|
-
|
104
|
-
|
105
|
-
class ToTypstCode(ArticleMetaData):
|
106
|
-
"""Base class for article components that can be converted to a Typst code snippet."""
|
107
|
-
|
108
|
-
def to_typst_code(self) -> str:
|
109
|
-
"""Converts the component into a Typst code snippet for rendering."""
|
110
|
-
return f"{self.title}\n{self.typst_metadata_comment}\n\n{self._unstructured_body}"
|
111
|
-
|
112
|
-
|
113
|
-
class ArticleOutlineBase(
|
114
|
-
ProposedUpdateAble,
|
115
|
-
PersistentAble,
|
116
|
-
ModelHash,
|
117
|
-
Introspect,
|
118
|
-
FromTypstCode,
|
119
|
-
ToTypstCode,
|
120
|
-
ABC,
|
121
|
-
):
|
122
|
-
"""Base class for article outlines."""
|
123
|
-
|
124
|
-
@property
|
125
|
-
def metadata(self) -> ArticleMetaData:
|
126
|
-
"""Returns the metadata of the article component."""
|
127
|
-
return ArticleMetaData.model_validate(self, from_attributes=True)
|
128
|
-
|
129
|
-
def update_metadata(self, other: ArticleMetaData) -> Self:
|
130
|
-
"""Updates the metadata of the current instance with the attributes of another instance."""
|
131
|
-
self.aims.clear()
|
132
|
-
self.aims.extend(other.aims)
|
133
|
-
self.description = other.description
|
134
|
-
return self
|
135
|
-
|
136
|
-
def update_from_inner(self, other: Self) -> Self:
|
137
|
-
"""Updates the current instance with the attributes of another instance."""
|
138
|
-
return self.update_metadata(other)
|
139
|
-
|
140
|
-
|
141
|
-
class SubSectionBase(ArticleOutlineBase):
|
142
|
-
"""Base class for article sections and subsections."""
|
143
|
-
|
144
|
-
def to_typst_code(self) -> str:
|
145
|
-
"""Converts the component into a Typst code snippet for rendering."""
|
146
|
-
return f"=== {super().to_typst_code()}"
|
147
|
-
|
148
|
-
def introspect(self) -> str:
|
149
|
-
"""Introspects the article subsection outline."""
|
150
|
-
return ""
|
151
|
-
|
152
|
-
def resolve_update_conflict(self, other: Self) -> str:
|
153
|
-
"""Resolve update errors in the article outline."""
|
154
|
-
if self.title != other.title:
|
155
|
-
return f"Title mismatched, expected `{self.title}`, got `{other.title}`"
|
156
|
-
return ""
|
157
|
-
|
158
|
-
|
159
|
-
class SectionBase[T: SubSectionBase](ArticleOutlineBase):
|
160
|
-
"""Base class for article sections and subsections."""
|
161
|
-
|
162
|
-
subsections: List[T]
|
163
|
-
"""Subsections of the section. Contains at least one subsection. You can also add more as needed."""
|
164
|
-
|
165
|
-
child_type: ClassVar[Type[SubSectionBase]]
|
166
|
-
|
167
|
-
def to_typst_code(self) -> str:
|
168
|
-
"""Converts the section into a Typst formatted code snippet.
|
169
|
-
|
170
|
-
Returns:
|
171
|
-
str: The formatted Typst code snippet.
|
172
|
-
"""
|
173
|
-
return f"== {super().to_typst_code()}" + "\n\n".join(subsec.to_typst_code() for subsec in self.subsections)
|
174
|
-
|
175
|
-
@classmethod
|
176
|
-
def from_typst_code(cls, title: str, body: str, **kwargs) -> Self:
|
177
|
-
"""Creates an Article object from the given Typst code."""
|
178
|
-
raw = extract_sections(body, level=3, section_char="=")
|
179
|
-
|
180
|
-
return (
|
181
|
-
super()
|
182
|
-
.from_typst_code(
|
183
|
-
title,
|
184
|
-
body,
|
185
|
-
subsections=[cls.child_type.from_typst_code(*pack) for pack in raw],
|
186
|
-
)
|
187
|
-
.update_unstructured_body("" if raw else strip_comment(body))
|
188
|
-
)
|
189
|
-
|
190
|
-
def resolve_update_conflict(self, other: Self) -> str:
|
191
|
-
"""Resolve update errors in the article outline."""
|
192
|
-
out = ""
|
193
|
-
if self.title != other.title:
|
194
|
-
out += f"Title mismatched, expected `{self.title}`, got `{other.title}`"
|
195
|
-
if len(self.subsections) != len(other.subsections):
|
196
|
-
out += f"Section count mismatched, expected `{len(self.subsections)}`, got `{len(other.subsections)}`"
|
197
|
-
return out or "\n".join(
|
198
|
-
[
|
199
|
-
conf
|
200
|
-
for s, o in zip(self.subsections, other.subsections, strict=True)
|
201
|
-
if (conf := s.resolve_update_conflict(o))
|
202
|
-
]
|
203
|
-
)
|
204
|
-
|
205
|
-
def update_from_inner(self, other: Self) -> Self:
|
206
|
-
"""Updates the current instance with the attributes of another instance."""
|
207
|
-
super().update_from_inner(other)
|
208
|
-
if len(self.subsections) == 0:
|
209
|
-
self.subsections = other.subsections
|
210
|
-
return self
|
211
|
-
|
212
|
-
for self_subsec, other_subsec in zip(self.subsections, other.subsections, strict=True):
|
213
|
-
self_subsec.update_from(other_subsec)
|
214
|
-
return self
|
215
|
-
|
216
|
-
def introspect(self) -> str:
|
217
|
-
"""Introspects the article section outline."""
|
218
|
-
if len(self.subsections) == 0:
|
219
|
-
return f"Section `{self.title}` contains no subsections, expected at least one, but got 0, you can add one or more as needed."
|
220
|
-
return ""
|
221
|
-
|
222
|
-
@property
|
223
|
-
def exact_word_count(self) -> int:
|
224
|
-
"""Returns the exact word count of the article section outline."""
|
225
|
-
return sum(a.exact_word_count for a in self.subsections)
|
226
|
-
|
227
|
-
|
228
|
-
class ChapterBase[T: SectionBase](ArticleOutlineBase):
|
229
|
-
"""Base class for article chapters."""
|
230
|
-
|
231
|
-
sections: List[T]
|
232
|
-
"""Sections of the chapter. Contains at least one section. You can also add more as needed."""
|
233
|
-
child_type: ClassVar[Type[SectionBase]]
|
234
|
-
|
235
|
-
def to_typst_code(self) -> str:
|
236
|
-
"""Converts the chapter into a Typst formatted code snippet for rendering."""
|
237
|
-
return f"= {super().to_typst_code()}" + "\n\n".join(sec.to_typst_code() for sec in self.sections)
|
238
|
-
|
239
|
-
@classmethod
|
240
|
-
def from_typst_code(cls, title: str, body: str, **kwargs) -> Self:
|
241
|
-
"""Creates an Article object from the given Typst code."""
|
242
|
-
raw_sec = extract_sections(body, level=2, section_char="=")
|
243
|
-
|
244
|
-
return (
|
245
|
-
super()
|
246
|
-
.from_typst_code(
|
247
|
-
title,
|
248
|
-
body,
|
249
|
-
sections=[cls.child_type.from_typst_code(*pack) for pack in raw_sec],
|
250
|
-
)
|
251
|
-
.update_unstructured_body("" if raw_sec else strip_comment(body))
|
252
|
-
)
|
253
|
-
|
254
|
-
def resolve_update_conflict(self, other: Self) -> str:
|
255
|
-
"""Resolve update errors in the article outline."""
|
256
|
-
out = ""
|
257
|
-
|
258
|
-
if self.title != other.title:
|
259
|
-
out += f"Title mismatched, expected `{self.title}`, got `{other.title}`"
|
260
|
-
if len(self.sections) == len(other.sections):
|
261
|
-
out += f"Chapter count mismatched, expected `{len(self.sections)}`, got `{len(other.sections)}`"
|
262
|
-
|
263
|
-
return out or "\n".join(
|
264
|
-
[conf for s, o in zip(self.sections, other.sections, strict=True) if (conf := s.resolve_update_conflict(o))]
|
265
|
-
)
|
266
|
-
|
267
|
-
def update_from_inner(self, other: Self) -> Self:
|
268
|
-
"""Updates the current instance with the attributes of another instance."""
|
269
|
-
if len(self.sections) == 0:
|
270
|
-
self.sections = other.sections
|
271
|
-
return self
|
272
|
-
|
273
|
-
for self_sec, other_sec in zip(self.sections, other.sections, strict=True):
|
274
|
-
self_sec.update_from(other_sec)
|
275
|
-
return self
|
276
|
-
|
277
|
-
def introspect(self) -> str:
|
278
|
-
"""Introspects the article chapter outline."""
|
279
|
-
if len(self.sections) == 0:
|
280
|
-
return f"Chapter `{self.title}` contains no sections, expected at least one, but got 0, you can add one or more as needed."
|
281
|
-
return ""
|
282
|
-
|
283
|
-
@property
|
284
|
-
def exact_word_count(self) -> int:
|
285
|
-
"""Calculates the total word count across all sections in the chapter.
|
286
|
-
|
287
|
-
Returns:
|
288
|
-
int: The cumulative word count of all sections.
|
289
|
-
"""
|
290
|
-
return sum(a.exact_word_count for a in self.sections)
|
291
|
-
|
292
|
-
|
293
|
-
class ArticleBase[T: ChapterBase](FinalizedDumpAble, AsPrompt, FromTypstCode, ToTypstCode, ABC):
|
294
|
-
"""Base class for article outlines."""
|
295
|
-
|
296
|
-
description: str = Field(
|
297
|
-
alias="elaboration",
|
298
|
-
)
|
299
|
-
"""The abstract of this article, which serves as a concise summary of an academic article, encapsulating its core purpose, methodologies, key results,
|
300
|
-
and conclusions while enabling readers to rapidly assess the relevance and significance of the study.
|
301
|
-
Functioning as the article's distilled essence, it succinctly articulates the research problem, objectives,
|
302
|
-
and scope, providing a roadmap for the full text while also facilitating database indexing, literature reviews,
|
303
|
-
and citation tracking through standardized metadata. Additionally, it acts as an accessibility gateway,
|
304
|
-
allowing scholars to gauge the study's contribution to existing knowledge, its methodological rigor,
|
305
|
-
and its broader implications without engaging with the entire manuscript, thereby optimizing scholarly communication efficiency."""
|
306
|
-
|
307
|
-
chapters: List[T]
|
308
|
-
"""Chapters of the article. Contains at least one chapter. You can also add more as needed."""
|
309
|
-
|
310
|
-
child_type: ClassVar[Type[ChapterBase]]
|
311
|
-
|
312
|
-
@property
|
313
|
-
def language(self) -> str:
|
314
|
-
if self.title:
|
315
|
-
return super().language
|
316
|
-
return self.chapters[0].language
|
317
|
-
|
318
|
-
@property
|
319
|
-
def exact_word_count(self) -> int:
|
320
|
-
"""Calculates the total word count across all chapters in the article.
|
321
|
-
|
322
|
-
Returns:
|
323
|
-
int: The cumulative word count of all chapters.
|
324
|
-
"""
|
325
|
-
return sum(ch.exact_word_count for ch in self.chapters)
|
326
|
-
|
327
|
-
@classmethod
|
328
|
-
def from_typst_code(cls, title: str, body: str, **kwargs) -> Self:
|
329
|
-
"""Generates an article from the given Typst code."""
|
330
|
-
raw = extract_sections(body, level=1, section_char="=")
|
331
|
-
return (
|
332
|
-
super()
|
333
|
-
.from_typst_code(
|
334
|
-
title,
|
335
|
-
body,
|
336
|
-
chapters=[cls.child_type.from_typst_code(*pack) for pack in raw],
|
337
|
-
)
|
338
|
-
.update_unstructured_body("" if raw else strip_comment(body))
|
339
|
-
)
|
340
|
-
|
341
|
-
def iter_dfs_rev(
|
342
|
-
self,
|
343
|
-
) -> Generator[ArticleOutlineBase, None, None]:
|
344
|
-
"""Performs a depth-first search (DFS) through the article structure in reverse order.
|
345
|
-
|
346
|
-
Returns:
|
347
|
-
Generator[ArticleMainBase]: Each component in the article structure in reverse order.
|
348
|
-
"""
|
349
|
-
for chap in self.chapters:
|
350
|
-
for sec in chap.sections:
|
351
|
-
yield from sec.subsections
|
352
|
-
yield sec
|
353
|
-
yield chap
|
354
|
-
|
355
|
-
def iter_dfs(self) -> Generator[ArticleOutlineBase, None, None]:
|
356
|
-
"""Performs a depth-first search (DFS) through the article structure.
|
357
|
-
|
358
|
-
Returns:
|
359
|
-
Generator[ArticleMainBase]: Each component in the article structure.
|
360
|
-
"""
|
361
|
-
for chap in self.chapters:
|
362
|
-
yield chap
|
363
|
-
for sec in chap.sections:
|
364
|
-
yield sec
|
365
|
-
yield from sec.subsections
|
366
|
-
|
367
|
-
def iter_sections(self) -> Generator[Tuple[ChapterBase, SectionBase], None, None]:
|
368
|
-
"""Iterates through all sections in the article.
|
369
|
-
|
370
|
-
Returns:
|
371
|
-
Generator[ArticleOutlineBase]: Each section in the article.
|
372
|
-
"""
|
373
|
-
for chap in self.chapters:
|
374
|
-
for sec in chap.sections:
|
375
|
-
yield chap, sec
|
376
|
-
|
377
|
-
def iter_subsections(self) -> Generator[Tuple[ChapterBase, SectionBase, SubSectionBase], None, None]:
|
378
|
-
"""Iterates through all subsections in the article.
|
379
|
-
|
380
|
-
Returns:
|
381
|
-
Generator[ArticleOutlineBase]: Each subsection in the article.
|
382
|
-
"""
|
383
|
-
for chap, sec in self.iter_sections():
|
384
|
-
for subsec in sec.subsections:
|
385
|
-
yield chap, sec, subsec
|
386
|
-
|
387
|
-
def find_introspected(self) -> Optional[Tuple[ArticleOutlineBase, str]]:
|
388
|
-
"""Finds the first introspected component in the article structure."""
|
389
|
-
summary = ""
|
390
|
-
for component in self.iter_dfs_rev():
|
391
|
-
summary += component.introspect()
|
392
|
-
if summary:
|
393
|
-
return component, summary
|
394
|
-
return None
|
395
|
-
|
396
|
-
def gather_introspected(self) -> Optional[str]:
|
397
|
-
"""Gathers all introspected components in the article structure."""
|
398
|
-
return "\n".join([i for component in self.chapters if (i := component.introspect())])
|
399
|
-
|
400
|
-
def iter_chap_title(self) -> Generator[str, None, None]:
|
401
|
-
"""Iterates through all chapter titles in the article."""
|
402
|
-
for chap in self.chapters:
|
403
|
-
yield chap.title
|
404
|
-
|
405
|
-
def iter_section_title(self) -> Generator[str, None, None]:
|
406
|
-
"""Iterates through all section titles in the article."""
|
407
|
-
for _, sec in self.iter_sections():
|
408
|
-
yield sec.title
|
409
|
-
|
410
|
-
def iter_subsection_title(self) -> Generator[str, None, None]:
|
411
|
-
"""Iterates through all subsection titles in the article."""
|
412
|
-
for _, _, subsec in self.iter_subsections():
|
413
|
-
yield subsec.title
|
414
|
-
|
415
|
-
def to_typst_code(self) -> str:
|
416
|
-
"""Generates the Typst code representation of the article."""
|
417
|
-
return f"// #Title: {super().to_typst_code()}\n" + "\n\n".join(a.to_typst_code() for a in self.chapters)
|
418
|
-
|
419
|
-
def finalized_dump(self) -> str:
|
420
|
-
"""Generates standardized hierarchical markup for academic publishing systems.
|
421
|
-
|
422
|
-
Implements ACL 2024 outline conventions with four-level structure:
|
423
|
-
= Chapter Title (Level 1)
|
424
|
-
== Section Title (Level 2)
|
425
|
-
=== Subsection Title (Level 3)
|
426
|
-
==== Subsubsection Title (Level 4)
|
427
|
-
|
428
|
-
Returns:
|
429
|
-
str: Strictly formatted outline with academic sectioning
|
430
|
-
|
431
|
-
Example:
|
432
|
-
= Methodology
|
433
|
-
== Neural Architecture Search Framework
|
434
|
-
=== Differentiable Search Space
|
435
|
-
==== Constrained Optimization Parameters
|
436
|
-
=== Implementation Details
|
437
|
-
== Evaluation Protocol
|
438
|
-
"""
|
439
|
-
return self.to_typst_code()
|
440
|
-
|
441
|
-
def avg_chap_wordcount[S: "ArticleBase"](self: S) -> S:
|
442
|
-
"""Set all chap have same word count sum up to be `self.expected_word_count`."""
|
443
|
-
avg = int(self.expected_word_count / len(self.chapters))
|
444
|
-
for c in self.chapters:
|
445
|
-
c.expected_word_count = avg
|
446
|
-
return self
|
447
|
-
|
448
|
-
def avg_sec_wordcount[S: "ArticleBase"](self: S) -> S:
|
449
|
-
"""Set all sec have same word count sum up to be `self.expected_word_count`."""
|
450
|
-
for c in self.chapters:
|
451
|
-
avg = int(c.expected_word_count / len(c.sections))
|
452
|
-
for s in c.sections:
|
453
|
-
s.expected_word_count = avg
|
454
|
-
return self
|
455
|
-
|
456
|
-
def avg_subsec_wordcount[S: "ArticleBase"](self: S) -> S:
|
457
|
-
"""Set all subsec have same word count sum up to be `self.expected_word_count`."""
|
458
|
-
for _, s in self.iter_sections():
|
459
|
-
avg = int(s.expected_word_count / len(s.subsections))
|
460
|
-
for ss in s.subsections:
|
461
|
-
ss.expected_word_count = avg
|
462
|
-
return self
|
463
|
-
|
464
|
-
def avg_wordcount_recursive[S: "ArticleBase"](self: S) -> S:
|
465
|
-
"""Set all chap, sec, subsec have same word count sum up to be `self.expected_word_count`."""
|
466
|
-
return self.avg_chap_wordcount().avg_sec_wordcount().avg_subsec_wordcount()
|
467
|
-
|
468
|
-
def update_article_file[S: "ArticleBase"](self: S, file: str | Path) -> S:
|
469
|
-
"""Update the article file."""
|
470
|
-
file = Path(file)
|
471
|
-
string = safe_text_read(file)
|
472
|
-
if updated := replace_thesis_body(string, ARTICLE_WRAPPER, f"\n\n{self.to_typst_code()}\n\n"):
|
473
|
-
dump_text(file, updated)
|
474
|
-
logger.success(f"Successfully updated {file.as_posix()}.")
|
475
|
-
else:
|
476
|
-
logger.warning(f"Failed to update {file.as_posix()}. Please make sure there are paired `{ARTICLE_WRAPPER}`")
|
477
|
-
return self
|
478
|
-
|
479
|
-
@classmethod
|
480
|
-
def from_article_file[S: "ArticleBase"](cls: Type[S], file: str | Path, title: str = "") -> S:
|
481
|
-
"""Load article from file."""
|
482
|
-
file = Path(file)
|
483
|
-
string = safe_text_read(file)
|
484
|
-
return cls.from_typst_code(
|
485
|
-
title, ok(extract_body(string, ARTICLE_WRAPPER), "Failed to extract body from file.")
|
486
|
-
)
|
@@ -1,101 +0,0 @@
|
|
1
|
-
"""ArticleEssence: Semantic fingerprint of academic paper for structured analysis."""
|
2
|
-
|
3
|
-
from typing import List
|
4
|
-
|
5
|
-
from fabricatio.capabilities.persist import PersistentAble
|
6
|
-
from fabricatio.models.extra.rag import MilvusDataBase
|
7
|
-
from fabricatio.models.generic import SketchedAble
|
8
|
-
from pydantic import BaseModel
|
9
|
-
|
10
|
-
|
11
|
-
class Equation(BaseModel):
|
12
|
-
"""Mathematical formalism specification for research contributions."""
|
13
|
-
|
14
|
-
description: str
|
15
|
-
"""Structured significance including:
|
16
|
-
1. Conceptual meaning
|
17
|
-
2. Technical workflow role
|
18
|
-
3. Contribution relationship
|
19
|
-
"""
|
20
|
-
|
21
|
-
latex_code: str
|
22
|
-
"""Typeset-ready notation."""
|
23
|
-
|
24
|
-
|
25
|
-
class Figure(BaseModel):
|
26
|
-
"""Visual component with academic captioning."""
|
27
|
-
|
28
|
-
description: str
|
29
|
-
"""Interpretation guide covering:
|
30
|
-
1. Visual element mapping
|
31
|
-
2. Data representation method
|
32
|
-
3. Research connection
|
33
|
-
"""
|
34
|
-
|
35
|
-
figure_caption: str
|
36
|
-
"""Nature-style caption containing:
|
37
|
-
1. Overview statement
|
38
|
-
2. Technical details
|
39
|
-
3. Result implications
|
40
|
-
"""
|
41
|
-
|
42
|
-
figure_serial_number: int
|
43
|
-
"""Image serial number extracted from Markdown path"""
|
44
|
-
|
45
|
-
|
46
|
-
class Highlightings(BaseModel):
|
47
|
-
"""Technical component aggregator."""
|
48
|
-
|
49
|
-
highlighted_equations: List[Equation]
|
50
|
-
"""Equations that highlight the article's core contributions"""
|
51
|
-
|
52
|
-
highlighted_figures: List[Figure]
|
53
|
-
"""key figures requiring:
|
54
|
-
1. Framework overview
|
55
|
-
2. Quantitative results
|
56
|
-
"""
|
57
|
-
|
58
|
-
|
59
|
-
class ArticleEssence(SketchedAble, PersistentAble, MilvusDataBase):
|
60
|
-
"""Structured representation of a scientific article's core elements in its original language."""
|
61
|
-
|
62
|
-
language: str
|
63
|
-
"""Language of the original article."""
|
64
|
-
|
65
|
-
title: str
|
66
|
-
"""Exact title of the original article."""
|
67
|
-
|
68
|
-
authors: List[str]
|
69
|
-
"""Original author full names as they appear in the source document."""
|
70
|
-
|
71
|
-
keywords: List[str]
|
72
|
-
"""Original keywords as they appear in the source document."""
|
73
|
-
|
74
|
-
publication_year: int
|
75
|
-
"""Publication year in ISO 8601 (YYYY format)."""
|
76
|
-
|
77
|
-
highlightings: Highlightings
|
78
|
-
"""Technical highlights including equations, algorithms, figures, and tables."""
|
79
|
-
|
80
|
-
abstract: str
|
81
|
-
"""Abstract text in the original language."""
|
82
|
-
|
83
|
-
core_contributions: List[str]
|
84
|
-
"""Technical contributions using CRediT taxonomy verbs."""
|
85
|
-
|
86
|
-
technical_novelty: List[str]
|
87
|
-
"""Patent-style claims with technical specificity."""
|
88
|
-
|
89
|
-
research_problems: List[str]
|
90
|
-
"""Problem statements as how/why questions."""
|
91
|
-
|
92
|
-
limitations: List[str]
|
93
|
-
"""Technical limitations analysis."""
|
94
|
-
|
95
|
-
bibtex_cite_key: str
|
96
|
-
"""Bibtex cite key of the original article."""
|
97
|
-
|
98
|
-
def _prepare_vectorization_inner(self) -> str:
|
99
|
-
return self.compact()
|
100
|
-
|
101
|
-
|