fabricatio 0.2.12.dev3__cp312-cp312-manylinux_2_34_x86_64.whl → 0.2.13.dev1__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.
@@ -8,10 +8,12 @@ from more_itertools import filter_map
8
8
  from pydantic import Field
9
9
  from rich import print as r_print
10
10
 
11
+ from fabricatio import TEMPLATE_MANAGER
11
12
  from fabricatio.capabilities.censor import Censor
12
13
  from fabricatio.capabilities.extract import Extract
13
14
  from fabricatio.capabilities.propose import Propose
14
- from fabricatio.fs import safe_text_read
15
+ from fabricatio.config import configs
16
+ from fabricatio.fs import dump_text, safe_text_read
15
17
  from fabricatio.journal import logger
16
18
  from fabricatio.models.action import Action
17
19
  from fabricatio.models.extra.article_essence import ArticleEssence
@@ -21,6 +23,7 @@ from fabricatio.models.extra.article_proposal import ArticleProposal
21
23
  from fabricatio.models.extra.rule import RuleSet
22
24
  from fabricatio.models.kwargs_types import ValidateKwargs
23
25
  from fabricatio.models.task import Task
26
+ from fabricatio.models.usages import LLMUsage
24
27
  from fabricatio.rust import BibManager, detect_language
25
28
  from fabricatio.utils import ok, wrapp_in_block
26
29
 
@@ -271,3 +274,48 @@ class LoadArticle(Action):
271
274
 
272
275
  async def _execute(self, article_outline: ArticleOutline, typst_code: str, **cxt) -> Article:
273
276
  return Article.from_mixed_source(article_outline, typst_code)
277
+
278
+
279
+ class WriteChapterSummary(Action, LLMUsage):
280
+ """Write the chapter summary."""
281
+
282
+ output_key: str = "chapter_summaries"
283
+
284
+ paragraph_count: int = 1
285
+
286
+ summary_word_count: int = 200
287
+
288
+ summary_title: str = "Chapter Summary"
289
+ write_to: Optional[Path] = None
290
+
291
+ async def _execute(self, article: Article, write_to: Optional[Path] = None, **cxt) -> List[str]:
292
+ logger.info(";".join(a.title for a in article.chapters))
293
+
294
+ ret = [
295
+ f"== {self.summary_title}\n{raw}"
296
+ for raw in (
297
+ await self.aask(
298
+ TEMPLATE_MANAGER.render_template(
299
+ configs.templates.chap_summary_template,
300
+ [
301
+ {
302
+ "chapter": a.to_typst_code(),
303
+ "title": a.title,
304
+ "language": a.language,
305
+ "summary_word_count": self.summary_word_count,
306
+ "paragraph_count": self.paragraph_count,
307
+ }
308
+ for a in article.chapters
309
+ ],
310
+ )
311
+ )
312
+ )
313
+ ]
314
+
315
+ if (to := (self.write_to or write_to)) is not None:
316
+ dump_text(
317
+ to,
318
+ "\n\n\n".join(f"//{a.title}\n\n{s}" for a, s in zip(article.chapters, ret, strict=True)),
319
+ )
320
+
321
+ return ret
@@ -2,7 +2,7 @@
2
2
 
3
3
  from asyncio import gather
4
4
  from pathlib import Path
5
- from typing import List, Optional
5
+ from typing import ClassVar, List, Optional
6
6
 
7
7
  from pydantic import Field, PositiveInt
8
8
 
@@ -20,6 +20,7 @@ from fabricatio.models.extra.article_main import Article, ArticleChapter, Articl
20
20
  from fabricatio.models.extra.article_outline import ArticleOutline
21
21
  from fabricatio.models.extra.rule import RuleSet
22
22
  from fabricatio.models.kwargs_types import ChooseKwargs, LLMKwargs
23
+ from fabricatio.rust import convert_to_block_formula, convert_to_inline_formula
23
24
  from fabricatio.utils import ask_retain, ok
24
25
 
25
26
  TYPST_CITE_USAGE = (
@@ -162,6 +163,7 @@ class WriteArticleContentRAG(Action, RAG, Extract):
162
163
  )
163
164
  for p in new_subsec.paragraphs:
164
165
  p.content = cm.apply(p.content)
166
+ p.description = cm.apply(p.description)
165
167
  subsec.update_from(new_subsec)
166
168
  logger.debug(f"{subsec.title}:rpl\n{subsec.display()}")
167
169
  return subsec
@@ -255,6 +257,7 @@ class WriteArticleContentRAG(Action, RAG, Extract):
255
257
  class ArticleConsultRAG(Action, AdvancedRAG):
256
258
  """Write an article based on the provided outline."""
257
259
 
260
+ ctx_override: ClassVar[bool] = True
258
261
  output_key: str = "consult_count"
259
262
  search_increment_multiplier: float = 1.6
260
263
  """The multiplier to increase the limit of references to retrieve per query."""
@@ -268,6 +271,7 @@ class ArticleConsultRAG(Action, AdvancedRAG):
268
271
  """The model to use for refining query."""
269
272
  req: str = TYPST_CITE_USAGE
270
273
  """The request for the rag model."""
274
+ tei_endpoint: Optional[str] = None
271
275
 
272
276
  @precheck_package(
273
277
  "questionary", "`questionary` is required for supervisor mode, please install it by `fabricatio[qa]`"
@@ -286,6 +290,10 @@ class ArticleConsultRAG(Action, AdvancedRAG):
286
290
  while (req := await text("User: ").ask_async()) is not None:
287
291
  if await confirm("Empty the cm?").ask_async():
288
292
  cm.empty()
293
+
294
+ req = convert_to_block_formula(req)
295
+ req = convert_to_inline_formula(req)
296
+
289
297
  await self.clued_search(
290
298
  req,
291
299
  cm,
@@ -294,6 +302,7 @@ class ArticleConsultRAG(Action, AdvancedRAG):
294
302
  base_accepted=self.ref_limit,
295
303
  result_per_query=self.ref_per_q,
296
304
  similarity_threshold=self.similarity_threshold,
305
+ tei_endpoint=self.tei_endpoint,
297
306
  )
298
307
 
299
308
  ret = await self.aask(f"{cm.as_prompt()}\n{self.req}\n{req}")
@@ -24,7 +24,7 @@ class AdvancedRAG(RAG):
24
24
  **kwargs: Unpack[FetchKwargs],
25
25
  ) -> CitationManager:
26
26
  """Asynchronously performs a clued search based on a given requirement and citation manager."""
27
- if max_round<=0:
27
+ if max_round <= 0:
28
28
  raise ValueError("max_round should be greater than 0")
29
29
  if max_round == 1:
30
30
  logger.warning(
@@ -33,21 +33,21 @@ class AdvancedRAG(RAG):
33
33
 
34
34
  refinery_kwargs = refinery_kwargs or {}
35
35
 
36
- for i in range(max_round + 1, 1):
37
- logger.info(f"Round [{i + 1}/{max_round}] search started.")
36
+ for i in range(1, max_round + 1):
37
+ logger.info(f"Round [{i}/{max_round}] search started.")
38
38
  ref_q = await self.arefined_query(
39
39
  f"{cm.as_prompt()}\n\nAbove is the retrieved references in the {i - 1}th RAG, now we need to perform the {i}th RAG."
40
40
  f"\n\n{requirement}",
41
41
  **refinery_kwargs,
42
42
  )
43
43
  if ref_q is None:
44
- logger.error(f"At round [{i + 1}/{max_round}] search, failed to refine the query, exit.")
44
+ logger.error(f"At round [{i}/{max_round}] search, failed to refine the query, exit.")
45
45
  return cm
46
46
  refs = await self.aretrieve(ref_q, ArticleChunk, base_accepted, **kwargs)
47
47
 
48
48
  if (max_capacity := max_capacity - len(refs)) < 0:
49
49
  cm.add_chunks(refs[0:max_capacity])
50
- logger.debug(f"At round [{i + 1}/{max_round}] search, the capacity is not enough, exit.")
50
+ logger.debug(f"At round [{i}/{max_round}] search, the capacity is not enough, exit.")
51
51
  return cm
52
52
 
53
53
  cm.add_chunks(refs)
@@ -143,21 +143,25 @@ class RAG(EmbeddingUsage):
143
143
 
144
144
  async def afetch_document[D: MilvusDataBase](
145
145
  self,
146
- vecs: List[List[float]],
146
+ query: List[str],
147
147
  document_model: Type[D],
148
148
  collection_name: Optional[str] = None,
149
149
  similarity_threshold: float = 0.37,
150
150
  result_per_query: int = 10,
151
+ tei_endpoint: Optional[str] = None,
152
+ reranker_threshold: float = 0.7,
151
153
  ) -> List[D]:
152
154
  """Asynchronously fetches documents from a Milvus database based on input vectors.
153
155
 
154
156
  Args:
155
- vecs (List[List[float]]): A list of vectors to search for in the database.
157
+ query (List[str]): A list of vectors to search for in the database.
156
158
  document_model (Type[D]): The model class used to convert fetched data into document objects.
157
159
  collection_name (Optional[str]): The name of the collection to search within.
158
160
  If None, the currently viewed collection is used.
159
161
  similarity_threshold (float): The similarity threshold for vector search. Defaults to 0.37.
160
162
  result_per_query (int): The maximum number of results to return per query. Defaults to 10.
163
+ tei_endpoint (str): the endpoint of the TEI api.
164
+ reranker_threshold (float): The threshold used to filtered low relativity document.
161
165
 
162
166
  Returns:
163
167
  List[D]: A list of document objects created from the fetched data.
@@ -165,15 +169,34 @@ class RAG(EmbeddingUsage):
165
169
  # Step 1: Search for vectors
166
170
  search_results = self.check_client().client.search(
167
171
  collection_name or self.safe_target_collection,
168
- vecs,
172
+ await self.vectorize(query),
169
173
  search_params={"radius": similarity_threshold},
170
174
  output_fields=list(document_model.model_fields),
171
175
  limit=result_per_query,
172
176
  )
177
+ if tei_endpoint is not None:
178
+ from fabricatio.utils import RerankerAPI
179
+
180
+ reranker = RerankerAPI(base_url=tei_endpoint)
181
+
182
+ retrieved_id = set()
183
+ raw_result = []
184
+
185
+ for q, g in zip(query, search_results, strict=True):
186
+ models = document_model.from_sequence([res["entity"] for res in g if res["id"] not in retrieved_id])
187
+ retrieved_id.update(res["id"] for res in g)
188
+ rank_scores = await reranker.arerank(q, [m.prepare_vectorization() for m in models])
189
+ raw_result.extend(
190
+ (models[s["index"]], s["score"]) for s in rank_scores if s["score"] > reranker_threshold
191
+ )
192
+
193
+ raw_result_sorted = sorted(raw_result, key=lambda x: x[1], reverse=True)
194
+ return [r[0] for r in raw_result_sorted]
173
195
 
174
196
  # Step 2: Flatten the search results
175
197
  flattened_results = flatten(search_results)
176
198
  unique_results = unique(flattened_results, key=itemgetter("id"))
199
+
177
200
  # Step 3: Sort by distance (descending)
178
201
  sorted_results = sorted(unique_results, key=itemgetter("distance"), reverse=True)
179
202
 
@@ -205,15 +228,18 @@ class RAG(EmbeddingUsage):
205
228
  """
206
229
  if isinstance(query, str):
207
230
  query = [query]
231
+
208
232
  return (
209
233
  await self.afetch_document(
210
- vecs=(await self.vectorize(query)),
234
+ query=query,
211
235
  document_model=document_model,
212
236
  **kwargs,
213
237
  )
214
238
  )[:max_accepted]
215
239
 
216
- async def arefined_query(self, question: List[str] | str, **kwargs: Unpack[ChooseKwargs[Optional[List[str]]]]) -> Optional[List[str]]:
240
+ async def arefined_query(
241
+ self, question: List[str] | str, **kwargs: Unpack[ChooseKwargs[Optional[List[str]]]]
242
+ ) -> Optional[List[str]]:
217
243
  """Refines the given question using a template.
218
244
 
219
245
  Args:
fabricatio/config.py CHANGED
@@ -86,10 +86,12 @@ class LLMConfig(BaseModel):
86
86
 
87
87
  tpm: Optional[PositiveInt] = Field(default=1000000)
88
88
  """The rate limit of the LLM model in tokens per minute. None means not checked."""
89
- presence_penalty:Optional[PositiveFloat]=None
89
+ presence_penalty: Optional[PositiveFloat] = None
90
90
  """The presence penalty of the LLM model."""
91
- frequency_penalty:Optional[PositiveFloat]=None
91
+ frequency_penalty: Optional[PositiveFloat] = None
92
92
  """The frequency penalty of the LLM model."""
93
+
94
+
93
95
  class EmbeddingConfig(BaseModel):
94
96
  """Embedding configuration class."""
95
97
 
@@ -252,10 +254,13 @@ class TemplateConfig(BaseModel):
252
254
  rule_requirement_template: str = Field(default="rule_requirement")
253
255
  """The name of the rule requirement template which will be used to generate a rule requirement."""
254
256
 
255
-
256
257
  extract_template: str = Field(default="extract")
257
258
  """The name of the extract template which will be used to extract model from string."""
258
259
 
260
+ chap_summary_template: str = Field(default="chap_summary")
261
+ """The name of the chap summary template which will be used to generate a chapter summary."""
262
+
263
+
259
264
  class MagikaConfig(BaseModel):
260
265
  """Magika configuration class."""
261
266
 
@@ -12,7 +12,7 @@ Classes:
12
12
  import traceback
13
13
  from abc import abstractmethod
14
14
  from asyncio import Queue, create_task
15
- from typing import Any, Dict, Self, Sequence, Tuple, Type, Union, final
15
+ from typing import Any, ClassVar, Dict, Self, Sequence, Tuple, Type, Union, final
16
16
 
17
17
  from fabricatio.journal import logger
18
18
  from fabricatio.models.generic import WithBriefing
@@ -33,6 +33,9 @@ class Action(WithBriefing):
33
33
  a specific operation and can modify the shared context data.
34
34
  """
35
35
 
36
+ ctx_override: ClassVar[bool] = False
37
+ """Whether to override the instance attr by the context variable."""
38
+
36
39
  name: str = Field(default="")
37
40
  """The name of the action."""
38
41
 
@@ -157,6 +160,15 @@ class WorkFlow(WithBriefing, ToolBoxUsage):
157
160
  action.personality = personality
158
161
  return self
159
162
 
163
+ def override_action_variable(self, action: Action, ctx: Dict[str, Any]) -> Self:
164
+ """Override action variable with context values."""
165
+ if action.ctx_override:
166
+ for k, v in ctx.items():
167
+ if hasattr(action, k):
168
+ setattr(action, k, v)
169
+
170
+ return self
171
+
160
172
  async def serve(self, task: Task) -> None:
161
173
  """Execute workflow to complete given task.
162
174
 
@@ -178,11 +190,12 @@ class WorkFlow(WithBriefing, ToolBoxUsage):
178
190
  try:
179
191
  # Process each action in sequence
180
192
  for i, step in enumerate(self._instances):
181
- current_action = step.name
182
- logger.info(f"Executing step [{i}] >> {current_action}")
193
+ logger.info(f"Executing step [{i}] >> {(current_action := step.name)}")
183
194
 
184
195
  # Get current context and execute action
185
196
  context = await self._context.get()
197
+
198
+ self.override_action_variable(step, context)
186
199
  act_task = create_task(step.act(context))
187
200
  # Handle task cancellation
188
201
  if task.is_cancelled():
@@ -1,7 +1,7 @@
1
1
  """A module containing kwargs types for content correction and checking operations."""
2
2
 
3
3
  from importlib.util import find_spec
4
- from typing import NotRequired, TypedDict
4
+ from typing import NotRequired, Optional, TypedDict
5
5
 
6
6
  from fabricatio.models.extra.problem import Improvement
7
7
  from fabricatio.models.extra.rule import RuleSet
@@ -58,3 +58,5 @@ if find_spec("pymilvus"):
58
58
  collection_name: NotRequired[str | None]
59
59
  similarity_threshold: NotRequired[float]
60
60
  result_per_query: NotRequired[int]
61
+ tei_endpoint: NotRequired[Optional[str]]
62
+ reranker_threshold: NotRequired[float]
@@ -2,8 +2,9 @@
2
2
 
3
3
  from abc import ABC
4
4
  from enum import StrEnum
5
- from typing import Generator, List, Optional, Self, Tuple
5
+ from typing import ClassVar, Generator, List, Optional, Self, Tuple, Type
6
6
 
7
+ from fabricatio.fs.readers import extract_sections
7
8
  from fabricatio.models.generic import (
8
9
  AsPrompt,
9
10
  Described,
@@ -105,12 +106,6 @@ class ArticleOutlineBase(
105
106
  self.description = other.description
106
107
  return self
107
108
 
108
- def display_metadata(self) -> str:
109
- """Displays the metadata of the current instance."""
110
- return self.model_dump_json(
111
- indent=1, include={"title", "writing_aim", "description", "support_to", "depend_on"}
112
- )
113
-
114
109
  def update_from_inner(self, other: Self) -> Self:
115
110
  """Updates the current instance with the attributes of another instance."""
116
111
  return self.update_metadata(other)
@@ -140,6 +135,8 @@ class SectionBase[T: SubSectionBase](ArticleOutlineBase):
140
135
  subsections: List[T]
141
136
  """Subsections of the section. Contains at least one subsection. You can also add more as needed."""
142
137
 
138
+ child_type: ClassVar[Type[SubSectionBase]]
139
+
143
140
  def to_typst_code(self) -> str:
144
141
  """Converts the section into a Typst formatted code snippet.
145
142
 
@@ -148,6 +145,17 @@ class SectionBase[T: SubSectionBase](ArticleOutlineBase):
148
145
  """
149
146
  return f"== {super().to_typst_code()}" + "\n\n".join(subsec.to_typst_code() for subsec in self.subsections)
150
147
 
148
+ @classmethod
149
+ def from_typst_code(cls, title: str, body: str, **kwargs) -> Self:
150
+ """Creates an Article object from the given Typst code."""
151
+ return super().from_typst_code(
152
+ title,
153
+ body,
154
+ subsections=[
155
+ cls.child_type.from_typst_code(*pack) for pack in extract_sections(body, level=3, section_char="=")
156
+ ],
157
+ )
158
+
151
159
  def resolve_update_conflict(self, other: Self) -> str:
152
160
  """Resolve update errors in the article outline."""
153
161
  out = ""
@@ -186,11 +194,23 @@ class ChapterBase[T: SectionBase](ArticleOutlineBase):
186
194
 
187
195
  sections: List[T]
188
196
  """Sections of the chapter. Contains at least one section. You can also add more as needed."""
197
+ child_type: ClassVar[Type[SectionBase]]
189
198
 
190
199
  def to_typst_code(self) -> str:
191
200
  """Converts the chapter into a Typst formatted code snippet for rendering."""
192
201
  return f"= {super().to_typst_code()}" + "\n\n".join(sec.to_typst_code() for sec in self.sections)
193
202
 
203
+ @classmethod
204
+ def from_typst_code(cls, title: str, body: str, **kwargs) -> Self:
205
+ """Creates an Article object from the given Typst code."""
206
+ return super().from_typst_code(
207
+ title,
208
+ body,
209
+ sections=[
210
+ cls.child_type.from_typst_code(*pack) for pack in extract_sections(body, level=2, section_char="=")
211
+ ],
212
+ )
213
+
194
214
  def resolve_update_conflict(self, other: Self) -> str:
195
215
  """Resolve update errors in the article outline."""
196
216
  out = ""
@@ -238,6 +258,19 @@ class ArticleBase[T: ChapterBase](FinalizedDumpAble, AsPrompt, FromTypstCode, To
238
258
  chapters: List[T]
239
259
  """Chapters of the article. Contains at least one chapter. You can also add more as needed."""
240
260
 
261
+ child_type: ClassVar[Type[ChapterBase]]
262
+
263
+ @classmethod
264
+ def from_typst_code(cls, title: str, body: str, **kwargs) -> Self:
265
+ """Generates an article from the given Typst code."""
266
+ return super().from_typst_code(
267
+ title,
268
+ body,
269
+ chapters=[
270
+ cls.child_type.from_typst_code(*pack) for pack in extract_sections(body, level=1, section_char="=")
271
+ ],
272
+ )
273
+
241
274
  def iter_dfs_rev(
242
275
  self,
243
276
  ) -> Generator[ArticleOutlineBase, None, None]:
@@ -1,9 +1,8 @@
1
1
  """ArticleBase and ArticleSubsection classes for managing hierarchical document components."""
2
2
 
3
- from typing import Dict, Generator, List, Self, Tuple, override
3
+ from typing import ClassVar, Dict, Generator, List, Self, Tuple, Type, override
4
4
 
5
5
  from fabricatio.decorators import precheck_package
6
- from fabricatio.fs.readers import extract_sections
7
6
  from fabricatio.journal import logger
8
7
  from fabricatio.models.extra.article_base import (
9
8
  ArticleBase,
@@ -52,6 +51,10 @@ class Paragraph(SketchedAble, WordCount, Described):
52
51
  """Create a Paragraph object from the given content."""
53
52
  return cls(elaboration="", aims=[], expected_word_count=word_count(content), content=content)
54
53
 
54
+ @property
55
+ def exact_wordcount(self) -> int:
56
+ return word_count(self.content)
57
+
55
58
 
56
59
  class ArticleParagraphSequencePatch(SequencePatch[Paragraph]):
57
60
  """Patch for `Paragraph` list of `ArticleSubsection`."""
@@ -115,31 +118,13 @@ class ArticleSubsection(SubSectionBase):
115
118
  class ArticleSection(SectionBase[ArticleSubsection]):
116
119
  """Atomic argumentative unit with high-level specificity."""
117
120
 
118
- @classmethod
119
- def from_typst_code(cls, title: str, body: str, **kwargs) -> Self:
120
- """Creates an Article object from the given Typst code."""
121
- return super().from_typst_code(
122
- title,
123
- body,
124
- subsections=[
125
- ArticleSubsection.from_typst_code(*pack) for pack in extract_sections(body, level=3, section_char="=")
126
- ],
127
- )
121
+ child_type: ClassVar[Type[SubSectionBase]] = ArticleSubsection
128
122
 
129
123
 
130
124
  class ArticleChapter(ChapterBase[ArticleSection]):
131
125
  """Thematic progression implementing research function."""
132
126
 
133
- @classmethod
134
- def from_typst_code(cls, title: str, body: str, **kwargs) -> Self:
135
- """Creates an Article object from the given Typst code."""
136
- return super().from_typst_code(
137
- title,
138
- body,
139
- sections=[
140
- ArticleSection.from_typst_code(*pack) for pack in extract_sections(body, level=2, section_char="=")
141
- ],
142
- )
127
+ child_type: ClassVar[Type[SectionBase]] = ArticleSection
143
128
 
144
129
 
145
130
  class Article(
@@ -153,6 +138,8 @@ class Article(
153
138
  aiming to provide a comprehensive model for academic papers.
154
139
  """
155
140
 
141
+ child_type: ClassVar[Type[ChapterBase]] = ArticleChapter
142
+
156
143
  def _as_prompt_inner(self) -> Dict[str, str]:
157
144
  return {
158
145
  "Original Article Briefing": self.referenced.referenced.referenced,
@@ -161,13 +148,20 @@ class Article(
161
148
  "Original Article": self.display(),
162
149
  }
163
150
 
164
- def convert_tex(self) -> Self:
151
+ def convert_tex(self, paragraphs: bool = True, descriptions: bool = True) -> Self:
165
152
  """Convert tex to typst code."""
166
- for _, _, subsec in self.iter_subsections():
167
- for p in subsec.paragraphs:
168
- p.content = fix_misplaced_labels(p.content)
169
- p.content = convert_all_inline_tex(p.content)
170
- p.content = convert_all_block_tex(p.content)
153
+ if descriptions:
154
+ for a in self.iter_dfs():
155
+ a.description = fix_misplaced_labels(a.description)
156
+ a.description = convert_all_inline_tex(a.description)
157
+ a.description = convert_all_block_tex(a.description)
158
+
159
+ if paragraphs:
160
+ for _, _, subsec in self.iter_subsections():
161
+ for p in subsec.paragraphs:
162
+ p.content = fix_misplaced_labels(p.content)
163
+ p.content = convert_all_inline_tex(p.content)
164
+ p.content = convert_all_block_tex(p.content)
171
165
  return self
172
166
 
173
167
  @override
@@ -254,17 +248,6 @@ class Article(
254
248
  article.chapters.append(article_chapter)
255
249
  return article
256
250
 
257
- @classmethod
258
- def from_typst_code(cls, title: str, body: str, **kwargs) -> Self:
259
- """Generates an article from the given Typst code."""
260
- return super().from_typst_code(
261
- title,
262
- body,
263
- chapters=[
264
- ArticleChapter.from_typst_code(*pack) for pack in extract_sections(body, level=1, section_char="=")
265
- ],
266
- )
267
-
268
251
  @classmethod
269
252
  def from_mixed_source(cls, article_outline: ArticleOutline, typst_code: str) -> Self:
270
253
  """Generates an article from the given outline and Typst code."""
@@ -285,3 +268,15 @@ class Article(
285
268
  for a in self.iter_dfs():
286
269
  a.title = await text(f"Edit `{a.title}`.", default=a.title).ask_async() or a.title
287
270
  return self
271
+
272
+ def check_short_paragraphs(self, threshold: int = 60) -> str:
273
+ """Checks for short paragraphs in the article."""
274
+ err = []
275
+ for chap, sec, subsec in self.iter_subsections():
276
+ for i, p in enumerate(subsec.paragraphs):
277
+ if p.exact_wordcount <= threshold:
278
+ err.append(
279
+ f"{chap.title}->{sec.title}->{subsec.title}-> Paragraph [{i}] is too short, {p.exact_wordcount} words."
280
+ )
281
+
282
+ return "\n".join(err)
@@ -312,11 +312,11 @@ class Language(Base):
312
312
  @property
313
313
  def language(self) -> str:
314
314
  """Get the language of the object."""
315
- if isinstance(self, Described):
315
+ if isinstance(self, Described) and self.description:
316
316
  return detect_language(self.description)
317
- if isinstance(self, Titled):
317
+ if isinstance(self, Titled) and self.title:
318
318
  return detect_language(self.title)
319
- if isinstance(self, Named):
319
+ if isinstance(self, Named) and self.name:
320
320
  return detect_language(self.name)
321
321
 
322
322
  return detect_language(self.model_dump_json(by_alias=True))
@@ -1,6 +1,6 @@
1
1
  """This module contains the types for the keyword arguments of the methods in the models module."""
2
2
 
3
- from typing import Any, Dict, List, NotRequired, Optional, Required, TypedDict
3
+ from typing import Any, Dict, List, Literal, NotRequired, Optional, Required, TypedDict
4
4
 
5
5
  from litellm.caching.caching import CacheMode
6
6
  from litellm.types.caching import CachingSupportedCallTypes
@@ -164,3 +164,11 @@ class CacheKwargs(TypedDict, total=False):
164
164
  qdrant_collection_name: str
165
165
  qdrant_quantization_config: str
166
166
  qdrant_semantic_cache_embedding_model: str
167
+
168
+
169
+ class RerankOptions(TypedDict, total=False):
170
+ """Optional keyword arguments for the rerank method."""
171
+
172
+ raw_scores: bool
173
+ truncate: bool
174
+ truncation_direction: Literal["Left", "Right"]
fabricatio/rust.pyi CHANGED
@@ -377,3 +377,8 @@ def to_metadata(data: JsonValue) -> str:
377
377
  The YAML string representation of the input data.
378
378
  """
379
379
 
380
+ def convert_to_inline_formula(string: str) -> str:
381
+ r"""Convert `$...$` to inline formula `\(...\)` and trim spaces."""
382
+
383
+ def convert_to_block_formula(string: str) -> str:
384
+ r"""Convert `$$...$$` to block formula `\[...\]` and trim spaces."""
fabricatio/utils.py CHANGED
@@ -1,8 +1,13 @@
1
1
  """A collection of utility functions for the fabricatio package."""
2
2
 
3
- from typing import Any, Dict, List, Mapping, Optional, overload
3
+ from typing import Any, Dict, List, Mapping, Optional, TypedDict, Unpack, overload
4
+
5
+ import aiohttp
6
+ import requests
4
7
 
5
8
  from fabricatio.decorators import precheck_package
9
+ from fabricatio.journal import logger
10
+ from fabricatio.models.kwargs_types import RerankOptions
6
11
 
7
12
 
8
13
  @precheck_package(
@@ -92,3 +97,159 @@ def wrapp_in_block(string: str, title: str, style: str = "-") -> str:
92
97
  str: The wrapped string.
93
98
  """
94
99
  return f"--- Start of {title} ---\n{string}\n--- End of {title} ---".replace("-", style)
100
+
101
+
102
+ class RerankResult(TypedDict):
103
+ """The rerank result."""
104
+
105
+ index: int
106
+ score: float
107
+
108
+
109
+ class RerankerAPI:
110
+ """A class to interact with the /rerank API for text reranking."""
111
+
112
+ def __init__(self, base_url: str) -> None:
113
+ """Initialize the RerankerAPI instance.
114
+
115
+ Args:
116
+ base_url (str): The base URL of the TEI-deployed reranker model API.
117
+ Example: "http://localhost:8000".
118
+ """
119
+ self.base_url = base_url.rstrip("/") # Ensure no trailing slashes
120
+
121
+ @staticmethod
122
+ def _map_error_code(status_code: int, error_data: Dict[str, str]) -> Exception:
123
+ """Map HTTP status codes and error data to specific exceptions.
124
+
125
+ Args:
126
+ status_code (int): The HTTP status code returned by the API.
127
+ error_data (Dict[str, str]): The error details returned by the API.
128
+
129
+ Returns:
130
+ Exception: A specific exception based on the error code and message.
131
+ """
132
+ error_message = error_data.get("error", "Unknown error")
133
+
134
+ if status_code == 400:
135
+ return ValueError(f"Bad request: {error_message}")
136
+ if status_code == 413:
137
+ return ValueError(f"Batch size error: {error_message}")
138
+ if status_code == 422:
139
+ return RuntimeError(f"Tokenization error: {error_message}")
140
+ if status_code == 424:
141
+ return RuntimeError(f"Rerank error: {error_message}")
142
+ if status_code == 429:
143
+ return RuntimeError(f"Model overloaded: {error_message}")
144
+ return RuntimeError(f"Unexpected error ({status_code}): {error_message}")
145
+
146
+ def rerank(self, query: str, texts: List[str], **kwargs: Unpack[RerankOptions]) -> List[RerankResult]:
147
+ """Call the /rerank API to rerank a list of texts based on a query (synchronous).
148
+
149
+ Args:
150
+ query (str): The query string used for matching with the texts.
151
+ texts (List[str]): A list of texts to be reranked.
152
+ **kwargs (Unpack[RerankOptions]): Optional keyword arguments:
153
+ - raw_scores (bool, optional): Whether to return raw scores. Defaults to False.
154
+ - truncate (bool, optional): Whether to truncate the texts. Defaults to False.
155
+ - truncation_direction (Literal["left", "right"], optional): Direction of truncation. Defaults to "right".
156
+
157
+ Returns:
158
+ List[RerankResult]: A list of dictionaries containing the reranked results.
159
+ Each dictionary includes:
160
+ - "index" (int): The original index of the text.
161
+ - "score" (float): The relevance score.
162
+
163
+ Raises:
164
+ ValueError: If input parameters are invalid or the API returns a client-side error.
165
+ RuntimeError: If the API call fails or returns a server-side error.
166
+ """
167
+ # Validate inputs
168
+ if not isinstance(query, str) or not query.strip():
169
+ raise ValueError("Query must be a non-empty string.")
170
+ if not isinstance(texts, list) or not all(isinstance(text, str) for text in texts):
171
+ raise ValueError("Texts must be a list of strings.")
172
+
173
+ # Construct the request payload
174
+ payload = {
175
+ "query": query,
176
+ "texts": texts,
177
+ **kwargs,
178
+ }
179
+
180
+ try:
181
+ # Send POST request to the API
182
+ response = requests.post(f"{self.base_url}/rerank", json=payload)
183
+
184
+ # Handle non-200 status codes
185
+ if response.ok:
186
+ error_data = None
187
+ if "application/json" in response.headers.get("Content-Type", ""):
188
+ error_data = response.json()
189
+ else:
190
+ error_data = {"error": response.text, "error_type": "unexpected_mimetype"}
191
+ raise self._map_error_code(response.status_code, error_data)
192
+
193
+ # Parse the JSON response
194
+ data: List[RerankResult] = response.json()
195
+ logger.debug(f"Rerank for `{query}` get {[s['score'] for s in data]}")
196
+ return data
197
+
198
+ except requests.exceptions.RequestException as e:
199
+ raise RuntimeError(f"Failed to connect to the API: {e}") from e
200
+
201
+ async def arerank(self, query: str, texts: List[str], **kwargs: Unpack[RerankOptions]) -> List[RerankResult]:
202
+ """Call the /rerank API to rerank a list of texts based on a query (asynchronous).
203
+
204
+ Args:
205
+ query (str): The query string used for matching with the texts.
206
+ texts (List[str]): A list of texts to be reranked.
207
+ **kwargs (Unpack[RerankOptions]): Optional keyword arguments:
208
+ - raw_scores (bool, optional): Whether to return raw scores. Defaults to False.
209
+ - truncate (bool, optional): Whether to truncate the texts. Defaults to False.
210
+ - truncation_direction (Literal["left", "right"], optional): Direction of truncation. Defaults to "right".
211
+
212
+ Returns:
213
+ List[RerankResult]: A list of dictionaries containing the reranked results.
214
+ Each dictionary includes:
215
+ - "index" (int): The original index of the text.
216
+ - "score" (float): The relevance score.
217
+
218
+ Raises:
219
+ ValueError: If input parameters are invalid or the API returns a client-side error.
220
+ RuntimeError: If the API call fails or returns a server-side error.
221
+ """
222
+ # Validate inputs
223
+ if not isinstance(query, str) or not query.strip():
224
+ raise ValueError("Query must be a non-empty string.")
225
+ if not isinstance(texts, list) or not all(isinstance(text, str) for text in texts):
226
+ raise ValueError("Texts must be a list of strings.")
227
+
228
+ # Construct the request payload
229
+ payload = {
230
+ "query": query,
231
+ "texts": texts,
232
+ **kwargs,
233
+ }
234
+
235
+ try:
236
+ # Send POST request to the API using aiohttp
237
+ async with (
238
+ aiohttp.ClientSession() as session,
239
+ session.post(f"{self.base_url}/rerank", json=payload) as response,
240
+ ):
241
+ # Handle non-200 status codes
242
+ if response.ok:
243
+ if "application/json" in response.headers.get("Content-Type", ""):
244
+ error_data = await response.json()
245
+ else:
246
+ error_data = {"error": await response.text(), "error_type": "unexpected_mimetype"}
247
+ raise self._map_error_code(response.status, error_data)
248
+
249
+ # Parse the JSON response
250
+ data: List[RerankResult] = await response.json()
251
+ logger.debug(f"Rerank for `{query}` get {[s['score'] for s in data]}")
252
+ return data
253
+
254
+ except aiohttp.ClientError as e:
255
+ raise RuntimeError(f"Failed to connect to the API: {e}") from e
Binary file
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fabricatio
3
- Version: 0.2.12.dev3
3
+ Version: 0.2.13.dev1
4
4
  Classifier: License :: OSI Approved :: MIT License
5
5
  Classifier: Programming Language :: Rust
6
6
  Classifier: Programming Language :: Python :: 3.12
@@ -165,6 +165,10 @@ max_tokens = 8192
165
165
  ```bash
166
166
  make test
167
167
  ```
168
+ ## TODO
169
+
170
+ - Add an element based format strategy
171
+
168
172
 
169
173
  ## Contributing
170
174
 
@@ -1,66 +1,67 @@
1
- fabricatio-0.2.12.dev3.dist-info/METADATA,sha256=YCdvNpYywNbwF7ZX4_mBS-A5yhGbYTvoiOyihr24qzo,5120
2
- fabricatio-0.2.12.dev3.dist-info/WHEEL,sha256=7FgAcpQES0h1xhfN9Ugve9FTUilU6sRAr1WJ5ph2cuw,108
3
- fabricatio-0.2.12.dev3.dist-info/licenses/LICENSE,sha256=yDZaTLnOi03bi3Dk6f5IjhLUc5old2yOsihHWU0z-i0,1067
4
- fabricatio/decorators.py,sha256=iuFCTtZ4VXwxJpM_z-CtrEpTaVZsv_eBFe5mOhe4wlo,8715
5
- fabricatio/constants.py,sha256=JxtaKGTf0IQhM-MNCHtr6x85Ejg8FWYcie-Z_RupCBg,557
6
- fabricatio/core.py,sha256=MaEKZ6DDmbdScAY-7F1gwGA6fr7ADX6Mz5rNVi2msFA,6277
7
- fabricatio/models/generic.py,sha256=a22CjQSlu-0WDdDVQiCIOddylaMFnv9lMLVuIeNKV1w,30392
8
- fabricatio/models/tool.py,sha256=VM3rMeDpUbeeFAKpsPfweJ2JGHf-w5f1voDnuhK99ew,12178
9
- fabricatio/models/role.py,sha256=5SJ1Vm6H3FwOVEk5Z-4GBJWABI3OKAKwkz5t170osi8,2855
10
- fabricatio/models/kwargs_types.py,sha256=aI844DNQXLbSBC3P0bZQLJpuJxwwF66WTDbbYQTftaE,4618
11
- fabricatio/models/extra/article_proposal.py,sha256=4G2qLkMxtK54G1ANgPW0G3w4Pahxgk2lhGPU5KMxuzw,1818
12
- fabricatio/models/extra/advanced_judge.py,sha256=CKPP4Lseb_Ey8Y7i2V9HJfB-mZgCknFdqq7Zo41o6s4,1060
13
- fabricatio/models/extra/article_main.py,sha256=PVFfTNDSWMGVSkrQqKXkZafHoKygD_3czeri-aCRM2M,10924
14
- fabricatio/models/extra/problem.py,sha256=1Sd8hsThQK6pXMXhErRhP1ft58z4PvqeB8AV8VcXiaI,7051
1
+ fabricatio-0.2.13.dev1.dist-info/METADATA,sha256=ho55CHS_a1lyoaMS_0IPkZhEnTE85U-DYhEdY4zhxyg,5169
2
+ fabricatio-0.2.13.dev1.dist-info/WHEEL,sha256=7FgAcpQES0h1xhfN9Ugve9FTUilU6sRAr1WJ5ph2cuw,108
3
+ fabricatio-0.2.13.dev1.dist-info/licenses/LICENSE,sha256=yDZaTLnOi03bi3Dk6f5IjhLUc5old2yOsihHWU0z-i0,1067
4
+ fabricatio/capabilities/check.py,sha256=TLtkUIR6tX73qR_V5TkXpdmplrmqFt4dZj32PBy81H0,8409
5
+ fabricatio/capabilities/propose.py,sha256=vOJvmmnMBHUQB6N1AmZNFw42jf7Bl2mBRNlBK15TpNI,1942
6
+ fabricatio/capabilities/correct.py,sha256=Et3Ud-oLZlwTVSy2XyT5UX2shT_OJ9j4HWP9b5Hntvk,10192
7
+ fabricatio/capabilities/rating.py,sha256=nolk5iBSiOzsOqqKIh1c4YSdRLwcllo9vBHuwp1dV74,17432
8
+ fabricatio/capabilities/censor.py,sha256=j6vyjKpR1CfLzC-XrOZSZePjJz3jsoM104gqqsWwi1Q,4615
9
+ fabricatio/capabilities/advanced_rag.py,sha256=y1XMENFdGGr0AcXZHgloRM9jX2yJpPEM-q0Y9Z-EI1k,2320
10
+ fabricatio/capabilities/task.py,sha256=_BAQonNy5JH3JxhLmPGfn0nDvn_ENKXyOdql8EVXRLE,4362
11
+ fabricatio/capabilities/rag.py,sha256=8unTYyyzeRifLrMAYlN_SrICfwkvoWHZPJcTljWTXXc,10485
12
+ fabricatio/capabilities/extract.py,sha256=b4_Tuc9O6Pe71y4Tj-JHMb4simdhduVR-rcfD9yW8RA,2425
13
+ fabricatio/capabilities/advanced_judge.py,sha256=bvb8fYoiKoGlBwMZVMflVE9R2MoS1VtmZAo65jMJFew,683
14
+ fabricatio/capabilities/review.py,sha256=EPL8IlxSKO0XStBkXdW7FJMbPztDQMv9w7tHgu6r3PM,4948
15
+ fabricatio/capabilities/__init__.py,sha256=skaJ43CqAQaZMH-mCRzF4Fps3x99P2SwJ8vSM9pInX8,56
16
+ fabricatio/parser.py,sha256=rMXd9Lo5TjxUkI0rocYigF9d1kC0rSySenuMW8uqXm8,6483
17
+ fabricatio/models/action.py,sha256=_8iwX7BJWUOUKzM0Zn6B7jSrjRPJgzr88vTiYVHxRgE,10330
18
+ fabricatio/models/extra/article_outline.py,sha256=B_qMldX_vxPZ52uvCp124R4vVYFFYPjUjLJc0-_lGog,2715
15
19
  fabricatio/models/extra/article_essence.py,sha256=zUfZ2_bX3h__RaVPwJlxQ-tkFyfSV8SdX8DsmFX6v_w,2649
20
+ fabricatio/models/extra/article_main.py,sha256=Ppgzqj28ATECkvevQUxRNBy56GMqhAc376R1HE1Kobo,10866
21
+ fabricatio/models/extra/article_proposal.py,sha256=4G2qLkMxtK54G1ANgPW0G3w4Pahxgk2lhGPU5KMxuzw,1818
22
+ fabricatio/models/extra/article_base.py,sha256=Kyfuvv9S6jTQafCdq1_DhzsimsK72iViuB1GqrihQQY,15298
16
23
  fabricatio/models/extra/rag.py,sha256=RWv_YJhDX6UL4t3sRtQt-LYMtxN-K-t931nmyiJXkKM,3857
17
- fabricatio/models/extra/article_outline.py,sha256=B_qMldX_vxPZ52uvCp124R4vVYFFYPjUjLJc0-_lGog,2715
18
- fabricatio/models/extra/__init__.py,sha256=0R9eZsCNu6OV-Xtf15H7FrqhfHTFBFf3fBrcd7ChsJ0,53
19
24
  fabricatio/models/extra/rule.py,sha256=b756_XmWeDoJ1qOFEGy6ZfP8O7rBjOZs4XvfZvWKXXI,2574
20
- fabricatio/models/extra/aricle_rag.py,sha256=-w1fxs5PrsLTYPmNtUhWSeucQ9evnasUB75aMlzutL0,10722
21
- fabricatio/models/extra/article_base.py,sha256=fiwhy5TuNi9hPB12zfjCAThymcCSoZ66vxsklCYymng,14150
25
+ fabricatio/models/extra/problem.py,sha256=1Sd8hsThQK6pXMXhErRhP1ft58z4PvqeB8AV8VcXiaI,7051
22
26
  fabricatio/models/extra/patches.py,sha256=_ghmnlvTZQq7UJyaH77mTZE9abjvxRJ2mgWHUbezUls,977
23
- fabricatio/models/adv_kwargs_types.py,sha256=659KMMuvdVq1xJxavLbUAMWxPOAz0RP9bNaZm3hyz-4,1890
27
+ fabricatio/models/extra/advanced_judge.py,sha256=CKPP4Lseb_Ey8Y7i2V9HJfB-mZgCknFdqq7Zo41o6s4,1060
28
+ fabricatio/models/extra/aricle_rag.py,sha256=-w1fxs5PrsLTYPmNtUhWSeucQ9evnasUB75aMlzutL0,10722
29
+ fabricatio/models/extra/__init__.py,sha256=0R9eZsCNu6OV-Xtf15H7FrqhfHTFBFf3fBrcd7ChsJ0,53
24
30
  fabricatio/models/usages.py,sha256=FVRhh_AulXlJF9uUmJzKEdiLz-di0rAiaQm4snYEid0,32571
25
31
  fabricatio/models/events.py,sha256=-9Xy8kcZug1tYwxmt3GpXtCkNfZUMSFvAH5HdZoRJTI,4030
32
+ fabricatio/models/generic.py,sha256=oUsYgAx2LmA35ePlavGvT-UjUqbL-a-4-5GuPPUAtvo,30442
33
+ fabricatio/models/adv_kwargs_types.py,sha256=iHYV4uB5YQPdywxg2vACLFbqHCLJCDek26aMb3ByWkY,1996
34
+ fabricatio/models/role.py,sha256=5SJ1Vm6H3FwOVEk5Z-4GBJWABI3OKAKwkz5t170osi8,2855
26
35
  fabricatio/models/task.py,sha256=O4v5T3HuzYblGeeqNzTDOCbulhGovR6olV2ojD0FJvk,10785
27
- fabricatio/models/action.py,sha256=oOyxkhocfWDetfz9EEvAyDU1U3w0X1OrzdtwNHTxDr8,9854
28
- fabricatio/toolboxes/fs.py,sha256=OQMdeokYxSNVrCZJAweJ0cYiK4k2QuEiNdIbS5IHIV8,705
29
- fabricatio/toolboxes/__init__.py,sha256=dYm_Gd8XolSU_h4wnkA09dlaLDK146eeFz0CUgPZ8_c,380
30
- fabricatio/toolboxes/arithmetic.py,sha256=sSTPkKI6-mb278DwQKFO9jKyzc9kCx45xNH7V6bGBpE,1307
36
+ fabricatio/models/kwargs_types.py,sha256=ts2P7dWAiy3knWvLVzJMVIl5TNrODbaoA7YhIP6CuD8,4826
37
+ fabricatio/models/tool.py,sha256=VM3rMeDpUbeeFAKpsPfweJ2JGHf-w5f1voDnuhK99ew,12178
38
+ fabricatio/config.py,sha256=WL7lGN_XD98NHXuPYi95HWUY-xnGxXJxxqSFk0xVPRA,17696
31
39
  fabricatio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
- fabricatio/fs/readers.py,sha256=hFHfGw1E58Da0ndBXXWcD2t-4HNdR1FimeDxuMI4-oE,1690
33
- fabricatio/fs/curd.py,sha256=x7Je9V1ydv-BdZTjlLc3syZ6380gkOhpfrfnhXstisg,4624
34
- fabricatio/fs/__init__.py,sha256=abIYGDiX5bZ9vSHfro1-OtogzD_3vuR71FZMvZt8820,750
35
- fabricatio/rust_instances.py,sha256=i5fIt6XkE8UwUU4JarmPt50AZs8aJW6efaypSLGLl0I,303
36
- fabricatio/config.py,sha256=Zc2UG1Jf8u0XfwHR7yrApgynzdX_uC6jInMw8PDm64o,17526
37
- fabricatio/utils.py,sha256=DZDOsJN1FxTVqq-i1fAJZdLfDYxyVoMAJFQURuYt1rY,3004
38
- fabricatio/journal.py,sha256=Op0wC-JlZumnAc_aDmYM4ljnSNLoKEEMfcIRbCF69ow,455
39
- fabricatio/rust.pyi,sha256=UhQY1bEB6RrCo8Yv3mq6NRtzEWOSsZzeeYtxSGagGWc,10960
40
- fabricatio/__init__.py,sha256=OXoMMHJKHEB_vN97_34U4I5QpAKL9xnVQEVcBCvwBCg,986
41
- fabricatio/actions/fs.py,sha256=nlTmk-tYDW158nz_fzlsNfuYJwj7j4BHn_MFY5hxdqs,934
40
+ fabricatio/core.py,sha256=MaEKZ6DDmbdScAY-7F1gwGA6fr7ADX6Mz5rNVi2msFA,6277
41
+ fabricatio/constants.py,sha256=JxtaKGTf0IQhM-MNCHtr6x85Ejg8FWYcie-Z_RupCBg,557
42
+ fabricatio/rust.pyi,sha256=9GXuLBMTmRfea9PUBZgycYACly02kCaGzDb1YGgg0g8,11207
43
+ fabricatio/actions/article.py,sha256=7N2TJARtN7iBWagmrtTI7Zqcp7U_8yxzKP6eB0t4PiM,12241
44
+ fabricatio/actions/rules.py,sha256=07ILsiwR250AUcKLPHTUPpWD_mPhPCfWKSkEAKcPv3A,3557
42
45
  fabricatio/actions/output.py,sha256=lTvMgXzY-fwA_kNrivdFZkk3kT8DMpjBSIWLyav2B1k,8089
43
- fabricatio/actions/article_rag.py,sha256=XcPSHJzODKUGJHjY_3Mj6la7hwZmTeWLECeATq8iRfk,18297
44
46
  fabricatio/actions/rag.py,sha256=-bA7KkZEFfWEanAPHzYwRHG7zRlTZcNDI7HL3n-lDuE,3496
47
+ fabricatio/actions/article_rag.py,sha256=ri6EL2V8CHY6geheI4URfTUUFbWBN5Tq0GytMQe5wtk,18665
48
+ fabricatio/actions/fs.py,sha256=nlTmk-tYDW158nz_fzlsNfuYJwj7j4BHn_MFY5hxdqs,934
45
49
  fabricatio/actions/__init__.py,sha256=ZMa1LeM5BNeqp-J-D32W-f5bD53-kdXGyt0zuueJofM,47
46
- fabricatio/actions/article.py,sha256=syUjEyKppdT72Xd1LSXKR3Djo1aybRPeFRHRzifNhm0,10632
47
- fabricatio/actions/rules.py,sha256=07ILsiwR250AUcKLPHTUPpWD_mPhPCfWKSkEAKcPv3A,3557
50
+ fabricatio/fs/curd.py,sha256=x7Je9V1ydv-BdZTjlLc3syZ6380gkOhpfrfnhXstisg,4624
51
+ fabricatio/fs/readers.py,sha256=hFHfGw1E58Da0ndBXXWcD2t-4HNdR1FimeDxuMI4-oE,1690
52
+ fabricatio/fs/__init__.py,sha256=abIYGDiX5bZ9vSHfro1-OtogzD_3vuR71FZMvZt8820,750
53
+ fabricatio/decorators.py,sha256=iuFCTtZ4VXwxJpM_z-CtrEpTaVZsv_eBFe5mOhe4wlo,8715
48
54
  fabricatio/workflows/articles.py,sha256=ZDV5nqUKRo1GOuuKWeSV7ZI32FYZU7WiTrD4YDuCeEo,945
49
55
  fabricatio/workflows/rag.py,sha256=uOZXprD479fUhLA6sYvEM8RWcVcUZXXtP0xRbTMPdHE,509
50
56
  fabricatio/workflows/__init__.py,sha256=Lq9pFo2cudwFCrQUUNgSTr1CoU0J1Nw-HNEQN7cHLp8,50
51
- fabricatio/parser.py,sha256=rMXd9Lo5TjxUkI0rocYigF9d1kC0rSySenuMW8uqXm8,6483
52
- fabricatio/capabilities/censor.py,sha256=j6vyjKpR1CfLzC-XrOZSZePjJz3jsoM104gqqsWwi1Q,4615
53
- fabricatio/capabilities/advanced_judge.py,sha256=bvb8fYoiKoGlBwMZVMflVE9R2MoS1VtmZAo65jMJFew,683
54
- fabricatio/capabilities/check.py,sha256=TLtkUIR6tX73qR_V5TkXpdmplrmqFt4dZj32PBy81H0,8409
55
- fabricatio/capabilities/advanced_rag.py,sha256=gv2qHqPQpiCmIPHhbibdBeWVhrKB4Xm3kqERCg7HEAw,2330
56
- fabricatio/capabilities/correct.py,sha256=Et3Ud-oLZlwTVSy2XyT5UX2shT_OJ9j4HWP9b5Hntvk,10192
57
- fabricatio/capabilities/rag.py,sha256=f7d3y6ZmjkbGZL_KyK9d-DAFE-yJFBck-NBrTPTVF8c,9387
58
- fabricatio/capabilities/__init__.py,sha256=skaJ43CqAQaZMH-mCRzF4Fps3x99P2SwJ8vSM9pInX8,56
59
- fabricatio/capabilities/rating.py,sha256=nolk5iBSiOzsOqqKIh1c4YSdRLwcllo9vBHuwp1dV74,17432
60
- fabricatio/capabilities/review.py,sha256=EPL8IlxSKO0XStBkXdW7FJMbPztDQMv9w7tHgu6r3PM,4948
61
- fabricatio/capabilities/propose.py,sha256=vOJvmmnMBHUQB6N1AmZNFw42jf7Bl2mBRNlBK15TpNI,1942
62
- fabricatio/capabilities/task.py,sha256=_BAQonNy5JH3JxhLmPGfn0nDvn_ENKXyOdql8EVXRLE,4362
63
- fabricatio/capabilities/extract.py,sha256=b4_Tuc9O6Pe71y4Tj-JHMb4simdhduVR-rcfD9yW8RA,2425
64
- fabricatio/rust.cpython-312-x86_64-linux-gnu.so,sha256=k-zgqY_boW8AjnkndawuMWVuPt1QuWKufO2zzpdeG4U,4727424
65
- fabricatio-0.2.12.dev3.data/scripts/tdown,sha256=VYqmPnlR2_DvwJGkX9lP45fBgPl7MLVJGD2rVt73okg,4585400
66
- fabricatio-0.2.12.dev3.dist-info/RECORD,,
57
+ fabricatio/toolboxes/arithmetic.py,sha256=sSTPkKI6-mb278DwQKFO9jKyzc9kCx45xNH7V6bGBpE,1307
58
+ fabricatio/toolboxes/fs.py,sha256=OQMdeokYxSNVrCZJAweJ0cYiK4k2QuEiNdIbS5IHIV8,705
59
+ fabricatio/toolboxes/__init__.py,sha256=dYm_Gd8XolSU_h4wnkA09dlaLDK146eeFz0CUgPZ8_c,380
60
+ fabricatio/rust_instances.py,sha256=i5fIt6XkE8UwUU4JarmPt50AZs8aJW6efaypSLGLl0I,303
61
+ fabricatio/utils.py,sha256=QsS9kIly_4uEzzPCid1V8ZDfkKtSxWzoLVpQXjCXxD8,10036
62
+ fabricatio/journal.py,sha256=Op0wC-JlZumnAc_aDmYM4ljnSNLoKEEMfcIRbCF69ow,455
63
+ fabricatio/__init__.py,sha256=OXoMMHJKHEB_vN97_34U4I5QpAKL9xnVQEVcBCvwBCg,986
64
+ fabricatio/rust.cpython-312-x86_64-linux-gnu.so,sha256=Z4iO633RTLw3qF0bzJG7EneVa3c2zhWdYi8WzRLVb10,4735000
65
+ fabricatio-0.2.13.dev1.data/scripts/tdown,sha256=aY-0gG_0xs7kJuvYyHT1ol57cIgam2tXhoRSCsLOKbE,4587880
66
+ fabricatio-0.2.13.dev1.data/scripts/ttm,sha256=Q3E4jfmKWP4hIOU8JZ54I1wbSlPg3m72qCFxlr3pUNc,3924408
67
+ fabricatio-0.2.13.dev1.dist-info/RECORD,,