fabricatio 0.2.9.dev3__cp312-cp312-manylinux_2_34_x86_64.whl → 0.2.9.dev4__cp312-cp312-manylinux_2_34_x86_64.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.
@@ -105,7 +105,6 @@ class GenerateArticleProposal(Action, Propose):
105
105
  task_input: Optional[Task] = None,
106
106
  article_briefing: Optional[str] = None,
107
107
  article_briefing_path: Optional[str] = None,
108
- langauge: Optional[str] = None,
109
108
  **_,
110
109
  ) -> Optional[ArticleProposal]:
111
110
  if article_briefing is None and article_briefing_path is None and task_input is None:
@@ -122,17 +121,14 @@ class GenerateArticleProposal(Action, Propose):
122
121
  )
123
122
  )
124
123
 
125
- proposal = ok(
124
+ logger.info("Start generating the proposal.")
125
+ return ok(
126
126
  await self.propose(
127
127
  ArticleProposal,
128
- f"{briefing}\n\nWrite the value string using `{detect_language(briefing)}`",
128
+ f"{briefing}\n\nWrite the value string using `{detect_language(briefing)}` as written language.",
129
129
  ),
130
130
  "Could not generate the proposal.",
131
131
  ).update_ref(briefing)
132
- if langauge:
133
- proposal.language = langauge
134
-
135
- return proposal
136
132
 
137
133
 
138
134
  class GenerateInitialOutline(Action, Propose):
@@ -149,7 +145,7 @@ class GenerateInitialOutline(Action, Propose):
149
145
  return ok(
150
146
  await self.propose(
151
147
  ArticleOutline,
152
- f"{(p := article_proposal.as_prompt())}\n\nNote that you should use `{detect_language(p)}` to write the `ArticleOutline`\n"
148
+ f"{(article_proposal.as_prompt())}\n\nNote that you should use `{article_proposal.language}` to write the `ArticleOutline`\n"
153
149
  f"You Must make sure every chapter have sections, and every section have subsections.",
154
150
  ),
155
151
  "Could not generate the initial outline.",
@@ -318,7 +314,7 @@ class GenerateArticle(Action, Censor):
318
314
  self.censor_obj_inplace(
319
315
  subsec,
320
316
  ruleset=ok(article_gen_ruleset or self.ruleset, "No ruleset provided"),
321
- reference=f"{article_outline.as_prompt()}\n# Error Need to be fixed\n{err}",
317
+ reference=f"{article_outline.as_prompt()}\n# Error Need to be fixed\n{err}\nYou should use `{subsec.language}` to write the new `Subsection`.",
322
318
  )
323
319
  for _, _, subsec in article.iter_subsections()
324
320
  if (err := subsec.introspect()) and logger.warning(f"Found Introspection Error:\n{err}") is None
@@ -29,6 +29,9 @@ class TweakArticleRAG(Action, RAG, Censor):
29
29
  ruleset: Optional[RuleSet] = None
30
30
  """The ruleset to be used for censoring the article."""
31
31
 
32
+ ref_limit: int = 30
33
+ """The limit of references to be retrieved"""
34
+
32
35
  async def _execute(
33
36
  self,
34
37
  article: Article,
@@ -88,11 +91,15 @@ class TweakArticleRAG(Action, RAG, Censor):
88
91
  f"{subsec.display()}\n"
89
92
  f"# Requirement\n"
90
93
  f"Search related articles in the base to find reference candidates, "
91
- f"prioritizing both original article language and English usage, which can return multiple candidates.",
94
+ f"provide queries in both `English` and `{subsec.language}` can get more accurate results.",
92
95
  )
93
96
  )
94
97
  await self.censor_obj_inplace(
95
98
  subsec,
96
99
  ruleset=ruleset,
97
- reference=await self.aretrieve_compact(refind_q, final_limit=30),
100
+ reference=f"{await self.aretrieve_compact(refind_q, final_limit=self.ref_limit)}\n\n"
101
+ f"You can use Reference above to rewrite the `{subsec.__class__.__name__}`.\n"
102
+ f"You should Always use `{subsec.language}` as written language, "
103
+ f"which is the original language of the `{subsec.title}`. "
104
+ f"since rewrite a `{subsec.__class__.__name__}` in a different language is usually a bad choice",
98
105
  )
@@ -8,7 +8,7 @@ from fabricatio.capabilities.advanced_judge import AdvancedJudge
8
8
  from fabricatio.capabilities.propose import Propose
9
9
  from fabricatio.config import configs
10
10
  from fabricatio.journal import logger
11
- from fabricatio.models.extra.patches import RuleSetBriefingPatch
11
+ from fabricatio.models.extra.patches import RuleSetMetadata
12
12
  from fabricatio.models.extra.problem import Improvement
13
13
  from fabricatio.models.extra.rule import Rule, RuleSet
14
14
  from fabricatio.models.generic import Display, WithBriefing
@@ -42,12 +42,17 @@ class Check(AdvancedJudge, Propose):
42
42
  - Returns None if any step in rule generation fails
43
43
  - Uses `alist_str` for requirement breakdown and iterative rule proposal
44
44
  """
45
- rule_reqs = await self.alist_str(
46
- TEMPLATE_MANAGER.render_template(
47
- configs.templates.ruleset_requirement_breakdown_template, {"ruleset_requirement": ruleset_requirement}
48
- ),
49
- rule_count,
50
- **override_kwargs(kwargs, default=None),
45
+ rule_reqs = (
46
+ await self.alist_str(
47
+ TEMPLATE_MANAGER.render_template(
48
+ configs.templates.ruleset_requirement_breakdown_template,
49
+ {"ruleset_requirement": ruleset_requirement},
50
+ ),
51
+ rule_count,
52
+ **override_kwargs(kwargs, default=None),
53
+ )
54
+ if rule_count > 1
55
+ else [ruleset_requirement]
51
56
  )
52
57
 
53
58
  if rule_reqs is None:
@@ -65,7 +70,7 @@ class Check(AdvancedJudge, Propose):
65
70
  return None
66
71
 
67
72
  ruleset_patch = await self.propose(
68
- RuleSetBriefingPatch,
73
+ RuleSetMetadata,
69
74
  f"{ruleset_requirement}\n\nYou should use `{detect_language(ruleset_requirement)}`!",
70
75
  **override_kwargs(kwargs, default=None),
71
76
  )
@@ -57,7 +57,7 @@ class Correct(Rating, Propose):
57
57
  self.decide_solution(
58
58
  ps,
59
59
  **fallback_kwargs(
60
- kwargs, topic=f"which solution is better to deal this problem {ps.problem.compact()}\n\n"
60
+ kwargs, topic=f"which solution is better to deal this problem {ps.problem.description}\n\n"
61
61
  ),
62
62
  )
63
63
  for ps in improvement.problem_solutions
@@ -167,13 +167,12 @@ class Correct(Rating, Propose):
167
167
  logger.info(f"Improvement {improvement.focused_on} not decided, start deciding...")
168
168
  improvement = await self.decide_improvement(improvement, **override_kwargs(kwargs, default=None))
169
169
 
170
- for ps in improvement.problem_solutions:
171
- logger.info(f"Fixing troubling obj {obj.__class__.__name__} when deal with problem: {ps.problem.name}")
170
+ total = len(improvement.problem_solutions)
171
+ for idx, ps in enumerate(improvement.problem_solutions):
172
+ logger.info(f"[{idx + 1}/{total}] Fixing {obj.__class__.__name__} for problem `{ps.problem.name}`")
172
173
  fixed_obj = await self.fix_troubled_obj(obj, ps, reference, **kwargs)
173
174
  if fixed_obj is None:
174
- logger.error(
175
- f"Failed to fix troubling obj {obj.__class__.__name__} when deal with problem: {ps.problem.name}",
176
- )
175
+ logger.error(f"[{idx + 1}/{total}] Failed to fix problem `{ps.problem.name}`")
177
176
  return None
178
177
  obj = fixed_obj
179
178
  return obj
@@ -5,19 +5,19 @@ from random import sample
5
5
  from typing import Dict, List, Optional, Set, Tuple, Union, Unpack, overload
6
6
 
7
7
  from more_itertools import flatten, windowed
8
- from pydantic import NonNegativeInt, PositiveInt
8
+ from pydantic import Field, NonNegativeInt, PositiveInt, create_model
9
9
 
10
+ from fabricatio.capabilities.propose import Propose
10
11
  from fabricatio.config import configs
11
12
  from fabricatio.journal import logger
12
- from fabricatio.models.generic import Display
13
+ from fabricatio.models.generic import Display, ProposedAble
13
14
  from fabricatio.models.kwargs_types import CompositeScoreKwargs, ValidateKwargs
14
- from fabricatio.models.usages import LLMUsage
15
15
  from fabricatio.parser import JsonCapture
16
16
  from fabricatio.rust_instances import TEMPLATE_MANAGER
17
- from fabricatio.utils import ok, override_kwargs
17
+ from fabricatio.utils import fallback_kwargs, ok, override_kwargs
18
18
 
19
19
 
20
- class Rating(LLMUsage):
20
+ class Rating(Propose):
21
21
  """A class that provides functionality to rate tasks based on a rating manual and score range.
22
22
 
23
23
  References:
@@ -30,7 +30,7 @@ class Rating(LLMUsage):
30
30
  rating_manual: Dict[str, str],
31
31
  score_range: Tuple[float, float],
32
32
  **kwargs: Unpack[ValidateKwargs[Dict[str, float]]],
33
- ) -> Optional[Dict[str, float] | List[Dict[str, float]]]:
33
+ ) -> Dict[str, float] | List[Dict[str, float]] | List[Optional[Dict[str, float]]] | None:
34
34
  """Rate a given string based on a rating manual and score range.
35
35
 
36
36
  Args:
@@ -42,45 +42,49 @@ class Rating(LLMUsage):
42
42
  Returns:
43
43
  Dict[str, float]: A dictionary with the ratings for each dimension.
44
44
  """
45
-
46
- def _validator(response: str) -> Optional[Dict[str, float]] :
47
- if (
48
- (json_data := JsonCapture.validate_with(response, dict, str))
49
- and json_data.keys() == rating_manual.keys()
50
- and all(score_range[0] <= v <= score_range[1] for v in json_data.values())
51
- ):
52
- return json_data
53
- return None
54
-
55
- logger.info(f"Rating for {to_rate}")
56
- return await self.aask_validate(
57
- question=(
58
- TEMPLATE_MANAGER.render_template(
59
- configs.templates.rate_fine_grind_template,
60
- {
61
- "to_rate": to_rate,
62
- "min_score": score_range[0],
63
- "max_score": score_range[1],
64
- "rating_manual": rating_manual,
65
- },
45
+ min_score, max_score = score_range
46
+ tip = (max_score - min_score) / 9
47
+
48
+ model = create_model( # pyright: ignore [reportCallIssue]
49
+ "RatingResult",
50
+ __base__=ProposedAble,
51
+ __doc__=f"The rating result contains the scores against each criterion, with min_score={min_score} and max_score={max_score}.",
52
+ **{ # pyright: ignore [reportArgumentType]
53
+ criterion: (
54
+ float,
55
+ Field(
56
+ ge=min_score,
57
+ le=max_score,
58
+ description=desc,
59
+ examples=[round(min_score + tip * i, 2) for i in range(10)],
60
+ ),
66
61
  )
62
+ for criterion, desc in rating_manual.items()
63
+ },
64
+ )
65
+
66
+ res = await self.propose(
67
+ model,
68
+ TEMPLATE_MANAGER.render_template(
69
+ configs.templates.rate_fine_grind_template,
70
+ {"to_rate": to_rate, "min_score": min_score, "max_score": max_score},
67
71
  )
68
72
  if isinstance(to_rate, str)
69
73
  else [
70
74
  TEMPLATE_MANAGER.render_template(
71
75
  configs.templates.rate_fine_grind_template,
72
- {
73
- "to_rate": item,
74
- "min_score": score_range[0],
75
- "max_score": score_range[1],
76
- "rating_manual": rating_manual,
77
- },
76
+ {"to_rate": t, "min_score": min_score, "max_score": max_score},
78
77
  )
79
- for item in to_rate
78
+ for t in to_rate
80
79
  ],
81
- validator=_validator,
82
- **kwargs,
80
+ **override_kwargs(kwargs, default=None),
83
81
  )
82
+ default = kwargs.get("default")
83
+ if isinstance(res, list):
84
+ return [r.model_dump() if r else default for r in res]
85
+ if res is None:
86
+ return default
87
+ return res.model_dump()
84
88
 
85
89
  @overload
86
90
  async def rate(
@@ -112,7 +116,7 @@ class Rating(LLMUsage):
112
116
  manual: Optional[Dict[str, str]] = None,
113
117
  score_range: Tuple[float, float] = (0.0, 1.0),
114
118
  **kwargs: Unpack[ValidateKwargs],
115
- ) -> Optional[Dict[str, float] | List[Dict[str, float]]]:
119
+ ) -> Dict[str, float] | List[Dict[str, float]] | List[Optional[Dict[str, float]]] | None:
116
120
  """Rate a given string or a sequence of strings based on a topic, criteria, and score range.
117
121
 
118
122
  Args:
@@ -133,7 +137,7 @@ class Rating(LLMUsage):
133
137
  or dict(zip(criteria, criteria, strict=True))
134
138
  )
135
139
 
136
- return await self.rate_fine_grind(to_rate, manual, score_range, **kwargs)
140
+ return await self.rate_fine_grind(to_rate, manual, score_range, **fallback_kwargs(kwargs, co_extractor={}))
137
141
 
138
142
  async def draft_rating_manual(
139
143
  self, topic: str, criteria: Optional[Set[str]] = None, **kwargs: Unpack[ValidateKwargs[Dict[str, str]]]
@@ -244,7 +248,7 @@ class Rating(LLMUsage):
244
248
 
245
249
  # extract reasons from the comparison of ordered pairs of extracted from examples
246
250
  reasons = flatten(
247
- await self.aask_validate(
251
+ await self.aask_validate( # pyright: ignore [reportArgumentType]
248
252
  question=[
249
253
  TEMPLATE_MANAGER.render_template(
250
254
  configs.templates.extract_reasons_from_examples_template,
@@ -319,9 +323,11 @@ class Rating(LLMUsage):
319
323
  validator=lambda resp: JsonCapture.validate_with(resp, target_type=float),
320
324
  **kwargs,
321
325
  )
326
+ if not all(relative_weights):
327
+ raise ValueError(f"found illegal weight: {relative_weights}")
322
328
  weights = [1.0]
323
329
  for rw in relative_weights:
324
- weights.append(weights[-1] * rw)
330
+ weights.append(weights[-1] * rw) # pyright: ignore [reportOperatorIssue]
325
331
  total = sum(weights)
326
332
  return dict(zip(criteria_seq, [w / total for w in weights], strict=True))
327
333
 
fabricatio/config.py CHANGED
@@ -44,7 +44,7 @@ class LLMConfig(BaseModel):
44
44
  top_p (NonNegativeFloat): The top p of the LLM model. Controls diversity via nucleus sampling. Set to 0.35 as per request.
45
45
  generation_count (PositiveInt): The number of generations to generate. Default is 1.
46
46
  stream (bool): Whether to stream the LLM model's response. Default is False.
47
- max_tokens (PositiveInt): The maximum number of tokens to generate. Set to 8192 as per request.
47
+ max_tokens (PositiveInt): The maximum number of tokens to generate.
48
48
  """
49
49
 
50
50
  model_config = ConfigDict(use_attribute_docstrings=True)
@@ -79,7 +79,7 @@ class LLMConfig(BaseModel):
79
79
  """Whether to stream the LLM model's response. Default is False."""
80
80
 
81
81
  max_tokens: Optional[PositiveInt] = Field(default=None)
82
- """The maximum number of tokens to generate. Set to 8192 as per request."""
82
+ """The maximum number of tokens to generate."""
83
83
 
84
84
  rpm: Optional[PositiveInt] = Field(default=100)
85
85
  """The rate limit of the LLM model in requests per minute. None means not checked."""
fabricatio/fs/readers.py CHANGED
@@ -1,9 +1,10 @@
1
1
  """Filesystem readers for Fabricatio."""
2
2
 
3
3
  from pathlib import Path
4
- from typing import Dict
4
+ from typing import Dict, List, Tuple
5
5
 
6
6
  import orjson
7
+ import regex
7
8
  from magika import Magika
8
9
 
9
10
  from fabricatio.config import configs
@@ -44,3 +45,21 @@ def safe_json_read(path: Path | str) -> Dict:
44
45
  except (orjson.JSONDecodeError, IsADirectoryError, FileNotFoundError) as e:
45
46
  logger.error(f"Failed to read file {path}: {e!s}")
46
47
  return {}
48
+
49
+
50
+ def extract_sections(string: str, level: int, section_char: str = "#") -> List[Tuple[str, str]]:
51
+ """Extract sections from markdown-style text by header level.
52
+
53
+ Args:
54
+ string (str): Input text to parse
55
+ level (int): Header level (e.g., 1 for '#', 2 for '##')
56
+ section_char (str, optional): The character used for headers (default: '#')
57
+
58
+ Returns:
59
+ List[Tuple[str, str]]: List of (header_text, section_content) tuples
60
+ """
61
+ return regex.findall(
62
+ r"^%s{%d}\s+(.+?)\n((?:(?!^%s{%d}\s).|\n)*)" % (section_char, level, section_char, level),
63
+ string,
64
+ regex.MULTILINE,
65
+ )
@@ -2,17 +2,17 @@
2
2
 
3
3
  from typing import List
4
4
 
5
- from fabricatio.models.generic import Display, ProposedAble
5
+ from fabricatio.models.generic import SketchedAble
6
6
 
7
7
 
8
- class JudgeMent(ProposedAble, Display):
8
+ class JudgeMent(SketchedAble):
9
9
  """Represents a judgment result containing supporting/denying evidence and final verdict.
10
10
 
11
11
  The class stores both affirmative and denies evidence, truth and reasons lists along with the final boolean judgment.
12
12
  """
13
13
 
14
14
  issue_to_judge: str
15
- """The issue to be judged"""
15
+ """The issue to be judged, true for affirmation, false for denial."""
16
16
 
17
17
  deny_evidence: List[str]
18
18
  """List of clues supporting the denial."""
@@ -17,7 +17,10 @@ from fabricatio.models.generic import (
17
17
  ResolveUpdateConflict,
18
18
  SequencePatch,
19
19
  SketchedAble,
20
+ Titled,
21
+ WordCount,
20
22
  )
23
+ from pydantic import Field
21
24
 
22
25
 
23
26
  class ReferringType(StrEnum):
@@ -38,44 +41,44 @@ class ArticleRef(ProposedUpdateAble):
38
41
  - Referring to a chapter titled `Introduction`:
39
42
  Using Python
40
43
  ```python
41
- ArticleRef(referred_chapter_title="Introduction")
44
+ ArticleRef(chap="Introduction")
42
45
  ```
43
46
  Using JSON
44
47
  ```json
45
- {referred_chapter_title="Introduction"}
48
+ {chap="Introduction"}
46
49
  ```
47
50
  - Referring to a section titled `Background` under the `Introduction` chapter:
48
51
  Using Python
49
52
  ```python
50
- ArticleRef(referred_chapter_title="Introduction", referred_section_title="Background")
53
+ ArticleRef(chap="Introduction", sec="Background")
51
54
  ```
52
55
  Using JSON
53
56
  ```json
54
- {referred_chapter_title="Introduction", referred_section_title="Background"}
57
+ {chap="Introduction", sec="Background"}
55
58
  ```
56
59
  - Referring to a subsection titled `Related Work` under the `Background` section of the `Introduction` chapter:
57
60
  Using Python
58
61
  ```python
59
- ArticleRef(referred_chapter_title="Introduction", referred_section_title="Background", referred_subsection_title="Related Work")
62
+ ArticleRef(chap="Introduction", sec="Background", subsec="Related Work")
60
63
  ```
61
64
  Using JSON
62
65
  ```json
63
- {referred_chapter_title="Introduction", referred_section_title="Background", referred_subsection_title="Related Work"}
66
+ {chap="Introduction", sec="Background", subsec="Related Work"}
64
67
  ```
65
68
  """
66
69
 
67
- referred_chapter_title: str
70
+ chap: str
68
71
  """`title` Field of the referenced chapter"""
69
- referred_section_title: Optional[str] = None
72
+ sec: Optional[str] = None
70
73
  """`title` Field of the referenced section."""
71
- referred_subsection_title: Optional[str] = None
74
+ subsec: Optional[str] = None
72
75
  """`title` Field of the referenced subsection."""
73
76
 
74
77
  def update_from_inner(self, other: Self) -> Self:
75
78
  """Updates the current instance with the attributes of another instance."""
76
- self.referred_chapter_title = other.referred_chapter_title
77
- self.referred_section_title = other.referred_section_title
78
- self.referred_subsection_title = other.referred_subsection_title
79
+ self.chap = other.chap
80
+ self.sec = other.sec
81
+ self.subsec = other.subsec
79
82
  return self
80
83
 
81
84
  def deref(self, article: "ArticleBase") -> Optional["ArticleOutlineBase"]:
@@ -87,39 +90,41 @@ class ArticleRef(ProposedUpdateAble):
87
90
  Returns:
88
91
  ArticleMainBase | ArticleOutline | None: The dereferenced section or subsection, or None if not found.
89
92
  """
90
- chap = next((chap for chap in article.chapters if chap.title == self.referred_chapter_title), None)
91
- if self.referred_section_title is None or chap is None:
93
+ chap = next((chap for chap in article.chapters if chap.title == self.chap), None)
94
+ if self.sec is None or chap is None:
92
95
  return chap
93
- sec = next((sec for sec in chap.sections if sec.title == self.referred_section_title), None)
94
- if self.referred_subsection_title is None or sec is None:
96
+ sec = next((sec for sec in chap.sections if sec.title == self.sec), None)
97
+ if self.subsec is None or sec is None:
95
98
  return sec
96
- return next((subsec for subsec in sec.subsections if subsec.title == self.referred_subsection_title), None)
99
+ return next((subsec for subsec in sec.subsections if subsec.title == self.subsec), None)
97
100
 
98
101
  @property
99
102
  def referring_type(self) -> ReferringType:
100
103
  """Determine the type of reference based on the presence of specific attributes."""
101
- if self.referred_subsection_title is not None:
104
+ if self.subsec is not None:
102
105
  return ReferringType.SUBSECTION
103
- if self.referred_section_title is not None:
106
+ if self.sec is not None:
104
107
  return ReferringType.SECTION
105
108
  return ReferringType.CHAPTER
106
109
 
107
110
 
108
- class ArticleMetaData(SketchedAble, Described, Language):
111
+ class ArticleMetaData(SketchedAble, Described, WordCount, Titled, Language):
109
112
  """Metadata for an article component."""
110
113
 
111
- support_to: List[ArticleRef]
112
- """List of references to other component of this articles that this component supports."""
113
- depend_on: List[ArticleRef]
114
- """List of references to other component of this articles that this component depends on."""
114
+ description: str = Field(
115
+ alias="elaboration",
116
+ description=Described.model_fields["description"].description,
117
+ )
118
+
119
+ title: str = Field(alias="heading", description=Titled.model_fields["title"].description)
115
120
 
116
- writing_aim: List[str]
121
+ aims: List[str]
117
122
  """List of writing aims of the research component in academic style."""
118
- title: str
119
- """Do not add any prefix or suffix to the title. should not contain special characters."""
120
123
 
121
- expected_word_count: int
122
- """Expected word count of this research component."""
124
+ support_to: List[ArticleRef]
125
+ """List of references to other future components in this article that this component supports to."""
126
+ depend_on: List[ArticleRef]
127
+ """List of references to other previous components in this article that this component depends on."""
123
128
 
124
129
 
125
130
  class ArticleRefSequencePatch(SequencePatch[ArticleRef]):
@@ -147,8 +152,8 @@ class ArticleOutlineBase(
147
152
  self.support_to.extend(other.support_to)
148
153
  self.depend_on.clear()
149
154
  self.depend_on.extend(other.depend_on)
150
- self.writing_aim.clear()
151
- self.writing_aim.extend(other.writing_aim)
155
+ self.aims.clear()
156
+ self.aims.extend(other.aims)
152
157
  self.description = other.description
153
158
  return self
154
159
 
@@ -272,22 +277,19 @@ class ChapterBase[T: SectionBase](ArticleOutlineBase):
272
277
  return ""
273
278
 
274
279
 
275
- class ArticleBase[T: ChapterBase](FinalizedDumpAble, AsPrompt, Language, ABC):
280
+ class ArticleBase[T: ChapterBase](FinalizedDumpAble, AsPrompt, WordCount, Described, Titled, Language, ABC):
276
281
  """Base class for article outlines."""
277
282
 
278
- title: str
279
- """Title of the academic paper."""
283
+ title: str = Field(alias="heading", description=Titled.model_fields["title"].description)
284
+ description: str = Field(alias="abstract")
285
+ """The abstract serves as a concise summary of an academic article, encapsulating its core purpose, methodologies, key results,
286
+ and conclusions while enabling readers to rapidly assess the relevance and significance of the study.
287
+ Functioning as the article's distilled essence, it succinctly articulates the research problem, objectives,
288
+ and scope, providing a roadmap for the full text while also facilitating database indexing, literature reviews,
289
+ and citation tracking through standardized metadata. Additionally, it acts as an accessibility gateway,
290
+ allowing scholars to gauge the study's contribution to existing knowledge, its methodological rigor,
291
+ and its broader implications without engaging with the entire manuscript, thereby optimizing scholarly communication efficiency."""
280
292
 
281
- prospect: str
282
- """Consolidated research statement with four pillars:
283
- 1. Problem Identification: Current limitations
284
- 2. Methodological Response: Technical approach
285
- 3. Empirical Validation: Evaluation strategy
286
- 4. Scholarly Impact: Field contributions
287
- """
288
-
289
- abstract: str
290
- """The abstract is a concise summary of the academic paper's main findings."""
291
293
  chapters: List[T]
292
294
  """Chapters of the article. Contains at least one chapter. You can also add more as needed."""
293
295
 
@@ -415,14 +417,12 @@ class ArticleBase[T: ChapterBase](FinalizedDumpAble, AsPrompt, Language, ABC):
415
417
  if not ref.deref(self):
416
418
  summary += f"Invalid internal reference in `{component.__class__.__name__}` titled `{component.title}`, because the referred {ref.referring_type} is not exists within the article, see the original obj dump: {ref.model_dump()}\n"
417
419
 
418
- if ref.referred_chapter_title not in (chap_titles_set):
419
- summary += f"Chapter titled `{ref.referred_chapter_title}` is not any of {chap_titles_set}\n"
420
- if ref.referred_section_title and ref.referred_section_title not in (sec_titles_set):
421
- summary += f"Section Titled `{ref.referred_section_title}` is not any of {sec_titles_set}\n"
422
- if ref.referred_subsection_title and ref.referred_subsection_title not in (subsec_titles_set):
423
- summary += (
424
- f"Subsection Titled `{ref.referred_subsection_title}` is not any of {subsec_titles_set}"
425
- )
420
+ if ref.chap not in (chap_titles_set):
421
+ summary += f"Chapter titled `{ref.chap}` is not any of {chap_titles_set}\n"
422
+ if ref.sec and ref.sec not in (sec_titles_set):
423
+ summary += f"Section Titled `{ref.sec}` is not any of {sec_titles_set}\n"
424
+ if ref.subsec and ref.subsec not in (subsec_titles_set):
425
+ summary += f"Subsection Titled `{ref.subsec}` is not any of {subsec_titles_set}"
426
426
 
427
427
  if summary:
428
428
  return (
@@ -453,17 +453,15 @@ class ArticleBase[T: ChapterBase](FinalizedDumpAble, AsPrompt, Language, ABC):
453
453
  r for r in chain(component.depend_on, component.support_to) if not r.deref(self) and r not in res_seq
454
454
  ):
455
455
  res_seq.append(ref)
456
- if ref.referred_chapter_title not in chap_titles_set:
457
- summary.append(
458
- f"Chapter titled `{ref.referred_chapter_title}` is not exist, since it is not any of {chap_titles_set}."
459
- )
460
- if ref.referred_section_title and (ref.referred_section_title not in sec_titles_set):
456
+ if ref.chap not in chap_titles_set:
461
457
  summary.append(
462
- f"Section Titled `{ref.referred_section_title}` is not exist, since it is not any of {sec_titles_set}"
458
+ f"Chapter titled `{ref.chap}` is not exist, since it is not any of {chap_titles_set}."
463
459
  )
464
- if ref.referred_subsection_title and (ref.referred_subsection_title not in subsec_titles_set):
460
+ if ref.sec and (ref.sec not in sec_titles_set):
461
+ summary.append(f"Section Titled `{ref.sec}` is not exist, since it is not any of {sec_titles_set}")
462
+ if ref.subsec and (ref.subsec not in subsec_titles_set):
465
463
  summary.append(
466
- f"Subsection Titled `{ref.referred_subsection_title}` is not exist, since it is not any of {subsec_titles_set}"
464
+ f"Subsection Titled `{ref.subsec}` is not exist, since it is not any of {subsec_titles_set}"
467
465
  )
468
466
 
469
467
  return res_seq, "\n".join(summary)
@@ -3,6 +3,7 @@
3
3
  from itertools import chain
4
4
  from typing import Dict, Generator, List, Self, Tuple, override
5
5
 
6
+ from fabricatio.fs.readers import extract_sections
6
7
  from fabricatio.journal import logger
7
8
  from fabricatio.models.extra.article_base import (
8
9
  ArticleBase,
@@ -14,26 +15,33 @@ from fabricatio.models.extra.article_base import (
14
15
  from fabricatio.models.extra.article_outline import (
15
16
  ArticleOutline,
16
17
  )
17
- from fabricatio.models.generic import PersistentAble, SequencePatch, SketchedAble, WithRef
18
- from fabricatio.rust import word_count
18
+ from fabricatio.models.generic import Described, PersistentAble, SequencePatch, SketchedAble, WithRef, WordCount
19
+ from fabricatio.rust import detect_language, word_count
19
20
  from fabricatio.utils import ok
21
+ from pydantic import Field
20
22
 
23
+ PARAGRAPH_SEP = "// - - -"
21
24
 
22
- class Paragraph(SketchedAble):
25
+
26
+ class Paragraph(SketchedAble, WordCount, Described):
23
27
  """Structured academic paragraph blueprint for controlled content generation."""
24
28
 
25
- description: str
26
- """Functional summary of the paragraph's role in document structure."""
29
+ description: str = Field(
30
+ alias="elaboration",
31
+ description=Described.model_fields["description"].description,
32
+ )
27
33
 
28
- writing_aim: List[str]
34
+ aims: List[str]
29
35
  """Specific communicative objectives for this paragraph's content."""
30
36
 
31
- expected_word_count: int
32
- """Expected word count for the paragraph."""
33
-
34
37
  content: str
35
38
  """The actual content of the paragraph, represented as a string."""
36
39
 
40
+ @classmethod
41
+ def from_content(cls, content: str) -> Self:
42
+ """Create a Paragraph object from the given content."""
43
+ return cls(elaboration="", aims=[], expected_word_count=word_count(content), content=content)
44
+
37
45
 
38
46
  class ArticleParagraphSequencePatch(SequencePatch[Paragraph]):
39
47
  """Patch for `Paragraph` list of `ArticleSubsection`."""
@@ -57,12 +65,11 @@ class ArticleSubsection(SubSectionBase):
57
65
  """Introspects the subsection and returns a summary of its state."""
58
66
  summary = ""
59
67
  if len(self.paragraphs) == 0:
60
- summary += f"`{self.__class__.__name__}` titled `{self.title}` have no paragraphs!\n"
61
- if (
62
- abs((wc := self.word_count) - self.expected_word_count) / self.expected_word_count
63
- > self._max_word_count_deviation
64
- ):
65
- summary += f"`{self.__class__.__name__}` titled `{self.title}` have {wc} words, expected {self.expected_word_count} words!"
68
+ summary += f"`{self.__class__.__name__}` titled `{self.title}` have no paragraphs, You should add some!\n"
69
+ if abs((wc := self.word_count) - self.expected_word_count) / self.expected_word_count > self._max_word_count_deviation:
70
+ summary += (
71
+ f"`{self.__class__.__name__}` titled `{self.title}` have {wc} words, expected {self.word_count} words!"
72
+ )
66
73
 
67
74
  return summary
68
75
 
@@ -80,16 +87,64 @@ class ArticleSubsection(SubSectionBase):
80
87
  Returns:
81
88
  str: Typst code snippet for rendering.
82
89
  """
83
- return f"=== {self.title}\n" + "\n\n".join(p.content for p in self.paragraphs)
90
+ return f"=== {self.title}\n" + f"\n{PARAGRAPH_SEP}\n".join(p.content for p in self.paragraphs)
91
+
92
+ @classmethod
93
+ def from_typst_code(cls, title: str, body: str, language: str) -> Self:
94
+ """Creates an Article object from the given Typst code."""
95
+ return cls(
96
+ heading=title,
97
+ elaboration="",
98
+ paragraphs=[Paragraph.from_content(p) for p in body.split(PARAGRAPH_SEP)],
99
+ expected_word_count=word_count(body),
100
+ language=language,
101
+ aims=[],
102
+ support_to=[],
103
+ depend_on=[],
104
+ )
84
105
 
85
106
 
86
107
  class ArticleSection(SectionBase[ArticleSubsection]):
87
108
  """Atomic argumentative unit with high-level specificity."""
88
109
 
110
+ @classmethod
111
+ def from_typst_code(cls, title: str, body: str, language: str) -> Self:
112
+ """Creates an Article object from the given Typst code."""
113
+ return cls(
114
+ subsections=[
115
+ ArticleSubsection.from_typst_code(*pack, language=language)
116
+ for pack in extract_sections(body, level=3, section_char="=")
117
+ ],
118
+ heading=title,
119
+ elaboration="",
120
+ expected_word_count=word_count(body),
121
+ language=language,
122
+ aims=[],
123
+ support_to=[],
124
+ depend_on=[],
125
+ )
126
+
89
127
 
90
128
  class ArticleChapter(ChapterBase[ArticleSection]):
91
129
  """Thematic progression implementing research function."""
92
130
 
131
+ @classmethod
132
+ def from_typst_code(cls, title: str, body: str, language: str) -> Self:
133
+ """Creates an Article object from the given Typst code."""
134
+ return cls(
135
+ sections=[
136
+ ArticleSection.from_typst_code(*pack, language=language)
137
+ for pack in extract_sections(body, level=2, section_char="=")
138
+ ],
139
+ heading=title,
140
+ elaboration="",
141
+ expected_word_count=word_count(body),
142
+ language=language,
143
+ aims=[],
144
+ support_to=[],
145
+ depend_on=[],
146
+ )
147
+
93
148
 
94
149
  class Article(
95
150
  SketchedAble,
@@ -126,31 +181,45 @@ class Article(
126
181
  Article: The generated article.
127
182
  """
128
183
  # Set the title from the outline
129
- article = Article(**outline.model_dump(exclude={"chapters"}), chapters=[])
184
+ article = Article(**outline.model_dump(exclude={"chapters"}, by_alias=True), chapters=[])
130
185
 
131
186
  for chapter in outline.chapters:
132
187
  # Create a new chapter
133
188
  article_chapter = ArticleChapter(
134
189
  sections=[],
135
- **chapter.model_dump(exclude={"sections"}),
190
+ **chapter.model_dump(exclude={"sections"}, by_alias=True),
136
191
  )
137
192
  for section in chapter.sections:
138
193
  # Create a new section
139
194
  article_section = ArticleSection(
140
195
  subsections=[],
141
- **section.model_dump(exclude={"subsections"}),
196
+ **section.model_dump(exclude={"subsections"}, by_alias=True),
142
197
  )
143
198
  for subsection in section.subsections:
144
199
  # Create a new subsection
145
200
  article_subsection = ArticleSubsection(
146
201
  paragraphs=[],
147
- **subsection.model_dump(),
202
+ **subsection.model_dump(by_alias=True),
148
203
  )
149
204
  article_section.subsections.append(article_subsection)
150
205
  article_chapter.sections.append(article_section)
151
206
  article.chapters.append(article_chapter)
152
207
  return article
153
208
 
209
+ @classmethod
210
+ def from_typst_code(cls, title: str, body: str) -> Self:
211
+ """Generates an article from the given Typst code."""
212
+ return cls(
213
+ language=(lang := detect_language(body)),
214
+ chapters=[
215
+ ArticleChapter.from_typst_code(*pack, language=lang)
216
+ for pack in extract_sections(body, level=1, section_char="=")
217
+ ],
218
+ heading=title,
219
+ expected_word_count=word_count(body),
220
+ abstract="",
221
+ )
222
+
154
223
  def gather_dependencies(self, article: ArticleOutlineBase) -> List[ArticleOutlineBase]:
155
224
  """Gathers dependencies for all sections and subsections in the article.
156
225
 
@@ -2,21 +2,25 @@
2
2
 
3
3
  from typing import Dict, List
4
4
 
5
- from fabricatio.models.generic import AsPrompt, PersistentAble, SketchedAble, WithRef
6
-
7
-
8
- class ArticleProposal(SketchedAble, WithRef[str], AsPrompt, PersistentAble):
5
+ from fabricatio.models.generic import (
6
+ AsPrompt,
7
+ Described,
8
+ Language,
9
+ PersistentAble,
10
+ SketchedAble,
11
+ Titled,
12
+ WithRef,
13
+ WordCount,
14
+ )
15
+ from pydantic import Field
16
+
17
+
18
+ class ArticleProposal(SketchedAble, WithRef[str], AsPrompt, PersistentAble, WordCount, Described, Titled, Language):
9
19
  """Structured proposal for academic paper development with core research elements.
10
20
 
11
21
  Guides LLM in generating comprehensive research proposals with clearly defined components.
12
22
  """
13
23
 
14
- language: str
15
- """The language in which the article is written. This should align with the language specified in the article briefing."""
16
-
17
- title: str
18
- """The title of the academic paper, formatted in Title Case."""
19
-
20
24
  focused_problem: List[str]
21
25
  """A list of specific research problems or questions that the paper aims to address."""
22
26
 
@@ -38,12 +42,9 @@ class ArticleProposal(SketchedAble, WithRef[str], AsPrompt, PersistentAble):
38
42
  keywords: List[str]
39
43
  """A list of keywords that represent the main topics and focus areas of the research."""
40
44
 
41
- abstract: str
45
+ description: str = Field(alias="abstract")
42
46
  """A concise summary of the research proposal, outlining the main points and objectives."""
43
47
 
44
- expected_word_count: int
45
- """The estimated word count of the final academic paper."""
46
-
47
48
  def _as_prompt_inner(self) -> Dict[str, str]:
48
49
  return {
49
50
  "ArticleBriefing": self.referenced,
@@ -3,17 +3,17 @@
3
3
  from typing import Optional, Type
4
4
 
5
5
  from fabricatio.models.extra.rule import RuleSet
6
- from fabricatio.models.generic import Patch, WithBriefing
6
+ from fabricatio.models.generic import Language, Patch, WithBriefing
7
7
  from pydantic import BaseModel
8
8
 
9
9
 
10
- class BriefingPatch[T: WithBriefing](Patch[T], WithBriefing):
11
- """Patch class for updating the description and name of a `WithBriefing` object, all fields within this instance will be directly copied onto the target model's field."""
10
+ class BriefingMetadata[T: WithBriefing](Patch[T], WithBriefing):
11
+ """A patch class for updating the description and name of a `WithBriefing` object, all fields within this instance will be directly copied onto the target model's field."""
12
12
 
13
13
 
14
- class RuleSetBriefingPatch(BriefingPatch[RuleSet]):
15
- """Patch class for updating the description and name of a `RuleSet` object, all fields within this instance will be directly copied onto the target model's field."""
16
- language: str
14
+ class RuleSetMetadata(BriefingMetadata[RuleSet], Language):
15
+ """A patch class for updating the description and name of a `RuleSet` object, all fields within this instance will be directly copied onto the target model's field."""
16
+
17
17
  @staticmethod
18
18
  def ref_cls() -> Optional[Type[BaseModel]]:
19
19
  """Get the reference class of the model."""
@@ -36,6 +36,7 @@ class Base(BaseModel):
36
36
  The `model_config` uses `use_attribute_docstrings=True` to ensure field descriptions are
37
37
  pulled from the attribute's docstring instead of the default Pydantic behavior.
38
38
  """
39
+
39
40
  model_config = ConfigDict(use_attribute_docstrings=True)
40
41
 
41
42
 
@@ -45,6 +46,7 @@ class Display(Base):
45
46
  Provides methods to generate both pretty-printed and compact JSON representations of the model.
46
47
  Used for debugging and logging purposes.
47
48
  """
49
+
48
50
  def display(self) -> str:
49
51
  """Generate pretty-printed JSON representation.
50
52
 
@@ -102,6 +104,20 @@ class Described(Base):
102
104
  this object's intent and application."""
103
105
 
104
106
 
107
+ class Titled(Base):
108
+ """Class that includes a title attribute."""
109
+
110
+ title: str
111
+ """The title of this object, make it professional and concise.No prefixed heading number should be included."""
112
+
113
+
114
+ class WordCount(Base):
115
+ """Class that includes a word count attribute."""
116
+
117
+ expected_word_count: int
118
+ """Expected word count of this research component."""
119
+
120
+
105
121
  class AsPrompt(Base):
106
122
  """Class that provides a method to generate a prompt from the model.
107
123
 
@@ -194,6 +210,7 @@ class PersistentAble(Base):
194
210
  Enables saving model instances to disk with timestamped filenames and loading from persisted files.
195
211
  Implements basic versioning through filename hashing and timestamping.
196
212
  """
213
+
197
214
  def persist(self, path: str | Path) -> Self:
198
215
  """Save model instance to disk with versioned filename.
199
216
 
@@ -208,7 +225,7 @@ class PersistentAble(Base):
208
225
  - Hash generated from JSON content ensures uniqueness
209
226
  """
210
227
  p = Path(path)
211
- out = self.model_dump_json()
228
+ out = self.model_dump_json(indent=1)
212
229
 
213
230
  # Generate a timestamp in the format YYYYMMDD_HHMMSS
214
231
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
@@ -282,8 +299,7 @@ class Language(Base):
282
299
  """Class that provides a language attribute."""
283
300
 
284
301
  language: str
285
- """The written language of this object, which should be aligned to the original requirement
286
- For example if the requirement is in Chinese, the language should be set to `zh`, if the requirement is in English, the language should be set to `en` and etc."""
302
+ """The fullname of the written language of this object."""
287
303
 
288
304
 
289
305
  class ModelHash(Base):
@@ -670,6 +686,7 @@ class ScopedConfig(Base):
670
686
  Manages LLM, embedding, and vector database configurations with fallback logic.
671
687
  Allows configuration values to be overridden in a hierarchical manner.
672
688
  """
689
+
673
690
  llm_api_endpoint: Optional[HttpUrl] = None
674
691
  """The OpenAI API endpoint."""
675
692
 
@@ -299,10 +299,11 @@ class LLMUsage(ScopedConfig):
299
299
  for lap in range(max_validations):
300
300
  try:
301
301
  if ((validated := validator(response := await self.aask(question=q, **kwargs))) is not None) or (
302
- co_extractor
302
+ co_extractor is not None
303
+ and logger.debug("Co-extraction is enabled.") is None
303
304
  and (
304
305
  validated := validator(
305
- await self.aask(
306
+ response:=await self.aask(
306
307
  question=(
307
308
  TEMPLATE_MANAGER.render_template(
308
309
  configs.templates.co_validation_template,
@@ -319,12 +320,13 @@ class LLMUsage(ScopedConfig):
319
320
  return validated
320
321
 
321
322
  except RateLimitError as e:
322
- logger.warning(f"Rate limit error: {e}")
323
+ logger.warning(f"Rate limit error:\n{e}")
323
324
  continue
324
325
  except Exception as e: # noqa: BLE001
325
- logger.error(f"Error during validation: \n{e}")
326
+ logger.error(f"Error during validation:\n{e}")
326
327
  logger.debug(traceback.format_exc())
327
328
  break
329
+ logger.error(f"Failed to validate the response at {lap}th attempt:\n{response}")
328
330
  if not kwargs.get("no_cache"):
329
331
  kwargs["no_cache"] = True
330
332
  logger.debug("Closed the cache for the next attempt")
fabricatio/parser.py CHANGED
@@ -48,10 +48,10 @@ class Capture(BaseModel):
48
48
  case "json" if configs.general.use_json_repair:
49
49
  logger.debug("Applying json repair to text.")
50
50
  if isinstance(text, str):
51
- return repair_json(text, ensure_ascii=False)
52
- return [repair_json(item, ensure_ascii=False) for item in text]
51
+ return repair_json(text, ensure_ascii=False) # pyright: ignore [reportReturnType]
52
+ return [repair_json(item, ensure_ascii=False) for item in text] # pyright: ignore [reportReturnType, reportGeneralTypeIssues]
53
53
  case _:
54
- return text
54
+ return text # pyright: ignore [reportReturnType]
55
55
 
56
56
  def capture(self, text: str) -> Tuple[str, ...] | str | None:
57
57
  """Capture the first occurrence of the pattern in the given text.
@@ -88,7 +88,7 @@ class Capture(BaseModel):
88
88
  if (cap := self.capture(text)) is None:
89
89
  return None
90
90
  try:
91
- return convertor(cap)
91
+ return convertor(cap) # pyright: ignore [reportArgumentType]
92
92
  except (ValueError, SyntaxError, ValidationError) as e:
93
93
  logger.error(f"Failed to convert text using {convertor.__name__} to convert.\nerror: {e}\n {cap}")
94
94
  return None
@@ -120,7 +120,7 @@ class Capture(BaseModel):
120
120
  judges.append(lambda output_obj: len(output_obj) == length)
121
121
 
122
122
  if (out := self.convert_with(text, deserializer)) and all(j(out) for j in judges):
123
- return out
123
+ return out # pyright: ignore [reportReturnType]
124
124
  return None
125
125
 
126
126
  @classmethod
fabricatio/rust.pyi CHANGED
@@ -1,5 +1,4 @@
1
- """
2
- Python interface definitions for Rust-based functionality.
1
+ """Python interface definitions for Rust-based functionality.
3
2
 
4
3
  This module provides type stubs and documentation for Rust-implemented utilities,
5
4
  including template rendering, cryptographic hashing, language detection, and
@@ -12,13 +11,11 @@ Key Features:
12
11
  - Text utilities: Word boundary splitting and word counting.
13
12
  """
14
13
 
15
-
16
14
  from pathlib import Path
17
15
  from typing import List, Optional
18
16
 
19
17
  from pydantic import JsonValue
20
18
 
21
-
22
19
  class TemplateManager:
23
20
  """Template rendering engine using Handlebars templates.
24
21
 
@@ -97,7 +94,6 @@ def blake3_hash(content: bytes) -> str:
97
94
  def detect_language(string: str) -> str:
98
95
  """Detect the language of a given string."""
99
96
 
100
-
101
97
  def split_word_bounds(string: str) -> List[str]:
102
98
  """Split the string into words based on word boundaries.
103
99
 
@@ -107,6 +103,7 @@ def split_word_bounds(string: str) -> List[str]:
107
103
  Returns:
108
104
  A list of words extracted from the string.
109
105
  """
106
+
110
107
  def word_count(string: str) -> int:
111
108
  """Count the number of words in the string.
112
109
 
@@ -117,8 +114,6 @@ def word_count(string: str) -> int:
117
114
  The number of words in the string.
118
115
  """
119
116
 
120
-
121
-
122
117
  class BibManager:
123
118
  """BibTeX bibliography manager for parsing and querying citation data."""
124
119
 
Binary file
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fabricatio
3
- Version: 0.2.9.dev3
3
+ Version: 0.2.9.dev4
4
4
  Classifier: License :: OSI Approved :: MIT License
5
5
  Classifier: Programming Language :: Rust
6
6
  Classifier: Programming Language :: Python :: 3.12
@@ -1,25 +1,25 @@
1
- fabricatio-0.2.9.dev3.dist-info/METADATA,sha256=-YMYKshfG1_fnGcenw1aPHgSv1gz1RglZhmVhba4DFY,5151
2
- fabricatio-0.2.9.dev3.dist-info/WHEEL,sha256=7FgAcpQES0h1xhfN9Ugve9FTUilU6sRAr1WJ5ph2cuw,108
3
- fabricatio-0.2.9.dev3.dist-info/licenses/LICENSE,sha256=yDZaTLnOi03bi3Dk6f5IjhLUc5old2yOsihHWU0z-i0,1067
1
+ fabricatio-0.2.9.dev4.dist-info/METADATA,sha256=lhC_1huUN-HvdYRbIkko8yv7ZLD7SsXjWKxobL7c-sY,5151
2
+ fabricatio-0.2.9.dev4.dist-info/WHEEL,sha256=7FgAcpQES0h1xhfN9Ugve9FTUilU6sRAr1WJ5ph2cuw,108
3
+ fabricatio-0.2.9.dev4.dist-info/licenses/LICENSE,sha256=yDZaTLnOi03bi3Dk6f5IjhLUc5old2yOsihHWU0z-i0,1067
4
4
  fabricatio/decorators.py,sha256=GrkclNTGT2bk7cjTyuca7mqSVlKwTcujcj3uBuZpT8s,7343
5
5
  fabricatio/core.py,sha256=MaEKZ6DDmbdScAY-7F1gwGA6fr7ADX6Mz5rNVi2msFA,6277
6
- fabricatio/models/generic.py,sha256=k2BiGvtNCdkH7BXGVH4f9cOKWGcUs9FVsY9sWTGEgHE,29163
6
+ fabricatio/models/generic.py,sha256=TbL76hSM-cjCyQJhGtP-IHpC9OwsTcQ0RQQNlyvjddI,29345
7
7
  fabricatio/models/tool.py,sha256=VM3rMeDpUbeeFAKpsPfweJ2JGHf-w5f1voDnuhK99ew,12178
8
8
  fabricatio/models/role.py,sha256=iao4teYzY5QjfN1B2tEY5wbQq5afFz7jdhi6IziIong,2878
9
9
  fabricatio/models/kwargs_types.py,sha256=N-CqIDGzkcDSveY8NKUntkTJykst5dAhqjzDw5Zi54I,5479
10
10
  fabricatio/models/utils.py,sha256=x4ZSk5YfHjRuEz_zzcU-rI9nBV_idq9N9RFF6UT8FXg,4269
11
- fabricatio/models/extra/article_proposal.py,sha256=Y1F5UBnffKA8F8tYFGJP0zIPEANnWO-iWgVD1OzVpEw,1969
12
- fabricatio/models/extra/advanced_judge.py,sha256=iiiERQ12uOyloZAsSQpKoFX7LKVM5ci1zmtEgMoi6lw,967
13
- fabricatio/models/extra/article_main.py,sha256=Pix3tvFjAWLjqz5ns0N0TNDYTW4V8DxN-f4D614sqbI,8747
11
+ fabricatio/models/extra/article_proposal.py,sha256=4G2qLkMxtK54G1ANgPW0G3w4Pahxgk2lhGPU5KMxuzw,1818
12
+ fabricatio/models/extra/advanced_judge.py,sha256=LX84QK1WRbMlFiilCz1s6q1QoOh0tiI39bMTHEe8fGM,990
13
+ fabricatio/models/extra/article_main.py,sha256=rthKqXbFa1GbzsxS02rezrQb2F2_JhQxkC8kt4W32iE,11368
14
14
  fabricatio/models/extra/problem.py,sha256=M4U9p1FcWFz2kZco_a6oULT96udh-PyuLs-KqAjBmV0,6490
15
15
  fabricatio/models/extra/article_essence.py,sha256=Fc1h05RFgKowHpHkdh-PNx3IxaUKLYdHVora-QM63WI,2726
16
16
  fabricatio/models/extra/article_outline.py,sha256=2vqMDhXwfRooHEe_cblkOj-4V96VsIAy68x22KBEQPQ,1387
17
17
  fabricatio/models/extra/__init__.py,sha256=0R9eZsCNu6OV-Xtf15H7FrqhfHTFBFf3fBrcd7ChsJ0,53
18
18
  fabricatio/models/extra/rule.py,sha256=UOqR6nuSpGJf0xVYLDM4wYR3x_ItfalCFlsaBE56LdM,2616
19
- fabricatio/models/extra/article_base.py,sha256=OFPWQTmyFd3z4n2jvC8jBpL14FR82xla75B1Tl-6Uf8,19862
20
- fabricatio/models/extra/patches.py,sha256=5Pw_xNiFsbcV-Cnh6hE3PLvwdrDptTxGY_j_AWTfnjo,969
19
+ fabricatio/models/extra/article_base.py,sha256=GTr1M-5RlaWXJWjKMTihPWcwISxU5lHzKXFLjmzLsZM,19586
20
+ fabricatio/models/extra/patches.py,sha256=_ghmnlvTZQq7UJyaH77mTZE9abjvxRJ2mgWHUbezUls,977
21
21
  fabricatio/models/adv_kwargs_types.py,sha256=NzTrhNvLGFns2qZJCCs4Xht5DKmPgX9nztOJFJjZWQ4,835
22
- fabricatio/models/usages.py,sha256=QJav_hEh6b7lq-ddoBYroHiOnbdceTPCgHKUOfXCL9g,31099
22
+ fabricatio/models/usages.py,sha256=zim4NcEwbJVN9X5URwci6w3Qyj3jchJn3BtgtTtrr4U,31296
23
23
  fabricatio/models/events.py,sha256=UvOc6V3vfjKuvh7irDezJ8EGpsNo5yzLdq4xQexVonw,4063
24
24
  fabricatio/models/task.py,sha256=MygHTr3wC5MT3tdIU-seBhaRGq94aBAJFb464m5tm-g,10192
25
25
  fabricatio/models/action.py,sha256=b4Ml_RSKzEQ_Tr_aHbsHlNRMiwOdK_8Ui6-Lh8psnfU,9576
@@ -27,35 +27,35 @@ fabricatio/toolboxes/fs.py,sha256=OQMdeokYxSNVrCZJAweJ0cYiK4k2QuEiNdIbS5IHIV8,70
27
27
  fabricatio/toolboxes/__init__.py,sha256=dYm_Gd8XolSU_h4wnkA09dlaLDK146eeFz0CUgPZ8_c,380
28
28
  fabricatio/toolboxes/arithmetic.py,sha256=sSTPkKI6-mb278DwQKFO9jKyzc9kCx45xNH7V6bGBpE,1307
29
29
  fabricatio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
- fabricatio/fs/readers.py,sha256=5bLlpqcdhIwWfysh7gvfVv0PPPVAeDlTPGwNTio6j9M,1156
30
+ fabricatio/fs/readers.py,sha256=56IR91ishQAvxfGPtEHlPn0DgkUd5x2QCrqm4pLHlqo,1819
31
31
  fabricatio/fs/curd.py,sha256=QqwnyLdVALNnerYGXf6a0irqoPSNE9_GJV9bJ33kbl0,4610
32
32
  fabricatio/fs/__init__.py,sha256=hTuYtzmvIGtbg7PTdoqLEQJ0E63hOzZltCIrLlDKaSE,559
33
33
  fabricatio/rust_instances.py,sha256=i5fIt6XkE8UwUU4JarmPt50AZs8aJW6efaypSLGLl0I,303
34
- fabricatio/config.py,sha256=NleUcBs5R1x63qZY0gQah9OVfCg9o2BXI4rC836p9LQ,17269
34
+ fabricatio/config.py,sha256=Nes4-4YHKGJC6DDZEg6lEc7Z-EfhYxlszW92POMhVXo,17213
35
35
  fabricatio/utils.py,sha256=l852eYiDZZEy44SM29dWEoI1gDVzKu0odZU_fDEBArM,1656
36
36
  fabricatio/journal.py,sha256=Op0wC-JlZumnAc_aDmYM4ljnSNLoKEEMfcIRbCF69ow,455
37
- fabricatio/rust.pyi,sha256=8YH6SUlwpVEmWPz1ykhDzOdYrAoZyfLSPSh4ZIOp8Sg,6059
37
+ fabricatio/rust.pyi,sha256=NBcID6R1gTtUfl7XKbPoEkvHqZ2YIUI2MSBrXMXz0Uk,6054
38
38
  fabricatio/__init__.py,sha256=OXoMMHJKHEB_vN97_34U4I5QpAKL9xnVQEVcBCvwBCg,986
39
39
  fabricatio/actions/output.py,sha256=GiZdrp5WYBo2YTKpbprIRpg0r8y4Bvg0Pg5FIs2vFJU,6340
40
- fabricatio/actions/article_rag.py,sha256=8N1vEAyX8tb2O5AOGA4zTbRjDlZnAF7Y4QavBa-B9vE,4195
40
+ fabricatio/actions/article_rag.py,sha256=xYmRAXPrG8rIBiXUqMQOyjEVofx845S7t7EklJpbA5I,4630
41
41
  fabricatio/actions/rag.py,sha256=0jkk-weJN6HyXK18hMP-U24kL-HsurVTEFx4LST9qZE,2663
42
42
  fabricatio/actions/__init__.py,sha256=ZMa1LeM5BNeqp-J-D32W-f5bD53-kdXGyt0zuueJofM,47
43
- fabricatio/actions/article.py,sha256=wfa0EJRATc8JQ-pQWlXRDjFWg7v07unnOnQTXXmSGNo,12332
43
+ fabricatio/actions/article.py,sha256=qzaTkxmjCcfGcRCNxVMzJ-EGVPfsfnDQ9xSV7VpuL4k,12345
44
44
  fabricatio/actions/rules.py,sha256=AtYqkPgErIiDUE3L4RDQk3IeIq2PhEQADAX3G3ko-ro,2785
45
45
  fabricatio/workflows/articles.py,sha256=ZDV5nqUKRo1GOuuKWeSV7ZI32FYZU7WiTrD4YDuCeEo,945
46
46
  fabricatio/workflows/rag.py,sha256=uOZXprD479fUhLA6sYvEM8RWcVcUZXXtP0xRbTMPdHE,509
47
47
  fabricatio/workflows/__init__.py,sha256=Lq9pFo2cudwFCrQUUNgSTr1CoU0J1Nw-HNEQN7cHLp8,50
48
- fabricatio/parser.py,sha256=AD9vgy-MljB8o3kH89RfwUyD5V296nrGnAe5u1nE00M,6165
48
+ fabricatio/parser.py,sha256=mAXrvB3_bk6Cc1tDd11sq_XpsKuTcvypVVR3wFAZuLI,6382
49
49
  fabricatio/capabilities/censor.py,sha256=j6vyjKpR1CfLzC-XrOZSZePjJz3jsoM104gqqsWwi1Q,4615
50
50
  fabricatio/capabilities/advanced_judge.py,sha256=bvb8fYoiKoGlBwMZVMflVE9R2MoS1VtmZAo65jMJFew,683
51
- fabricatio/capabilities/check.py,sha256=b5SA7_y-n1PeTVpco69uJIxJeP3PxuE2K4gSI4WCUPQ,8180
52
- fabricatio/capabilities/correct.py,sha256=Gjs1BKBqP93j5C3lveykfc-lMvYG7yAYRZVH3gipgfY,10199
51
+ fabricatio/capabilities/check.py,sha256=SOnXGRWMbQg5zdqAPgklyavvCifhvw0v4i67QGCnwpY,8308
52
+ fabricatio/capabilities/correct.py,sha256=Et3Ud-oLZlwTVSy2XyT5UX2shT_OJ9j4HWP9b5Hntvk,10192
53
53
  fabricatio/capabilities/rag.py,sha256=It5uWwqbrX64MfQ3FbSvmgcpECAo8XWkLhtRSdTb0ME,17300
54
54
  fabricatio/capabilities/__init__.py,sha256=skaJ43CqAQaZMH-mCRzF4Fps3x99P2SwJ8vSM9pInX8,56
55
- fabricatio/capabilities/rating.py,sha256=qugLs9bKR10LBEnlW4X-FH_knVEsWUj0kzI6AwRgvpo,16655
55
+ fabricatio/capabilities/rating.py,sha256=6kKQLaSA4pZF50fsukeUJV995hS_4jenEfCsSLwjidg,17245
56
56
  fabricatio/capabilities/review.py,sha256=EPL8IlxSKO0XStBkXdW7FJMbPztDQMv9w7tHgu6r3PM,4948
57
57
  fabricatio/capabilities/propose.py,sha256=vOJvmmnMBHUQB6N1AmZNFw42jf7Bl2mBRNlBK15TpNI,1942
58
58
  fabricatio/capabilities/task.py,sha256=gg1xcNlvHy7voR1GXiVDpKW16IvFofLInMlXgkhzBiQ,4304
59
- fabricatio/rust.cpython-312-x86_64-linux-gnu.so,sha256=zBLLbD9U7_jdOdsTcuN5ndxztWWF50k3unlI3PmIW5s,2259608
60
- fabricatio-0.2.9.dev3.data/scripts/tdown,sha256=zld9LfTDv-oL3cnxHkqRnI-5jG1r6woHRyNleB3g3GQ,4587928
61
- fabricatio-0.2.9.dev3.dist-info/RECORD,,
59
+ fabricatio/rust.cpython-312-x86_64-linux-gnu.so,sha256=4RuvwA9hIlrKqb0RAEVA6yuLrjYQ9hZGZRPFIHCprT8,2261576
60
+ fabricatio-0.2.9.dev4.data/scripts/tdown,sha256=tr6RMP9zOjtAtEuTvQq7fk64mpNMdyU7UGXpRJpTM3s,4603104
61
+ fabricatio-0.2.9.dev4.dist-info/RECORD,,
Binary file