fabricatio 0.2.10.dev0__cp312-cp312-manylinux_2_34_x86_64.whl → 0.2.11.dev0__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.
@@ -78,7 +78,7 @@ class FixArticleEssence(Action):
78
78
  out = []
79
79
  count = 0
80
80
  for a in article_essence:
81
- if key := (bib_mgr.get_cite_key(a.title) or bib_mgr.get_cite_key_fuzzy(a.title)):
81
+ if key := (bib_mgr.get_cite_key_by_title(a.title) or bib_mgr.get_cite_key_fuzzy(a.title)):
82
82
  a.title = bib_mgr.get_title_by_key(key) or a.title
83
83
  a.authors = bib_mgr.get_author_by_key(key) or a.authors
84
84
  a.publication_year = bib_mgr.get_year_by_key(key) or a.publication_year
@@ -145,7 +145,8 @@ class GenerateInitialOutline(Action, Propose):
145
145
  f"{(article_proposal.as_prompt())}\n\nNote that you should use `{article_proposal.language}` to write the `ArticleOutline`\n"
146
146
  f"Design each chapter of a proper and academic and ready for release manner.\n"
147
147
  f"You Must make sure every chapter have sections, and every section have subsections.\n"
148
- f"Make the chapter and sections and subsections bing divided into a specific enough article component.",
148
+ f"Make the chapter and sections and subsections bing divided into a specific enough article component.\n"
149
+ f"Every chapter must have sections, every section must have subsections.",
149
150
  )
150
151
 
151
152
  return ok(
@@ -226,3 +227,12 @@ class GenerateArticle(Action, Censor):
226
227
  )
227
228
 
228
229
  return article
230
+
231
+
232
+ class LoadArticle(Action):
233
+ """Load the article from the outline and typst code."""
234
+
235
+ output_key: str = "loaded_article"
236
+
237
+ async def _execute(self, article_outline: ArticleOutline, typst_code: str, **cxt) -> Article:
238
+ return Article.from_mixed_source(article_outline, typst_code)
@@ -1,16 +1,114 @@
1
1
  """A module for writing articles using RAG (Retrieval-Augmented Generation) capabilities."""
2
2
 
3
3
  from asyncio import gather
4
- from typing import Optional
4
+ from pathlib import Path
5
+ from typing import List, Optional
5
6
 
7
+ from fabricatio import BibManager
6
8
  from fabricatio.capabilities.censor import Censor
9
+ from fabricatio.capabilities.propose import Propose
7
10
  from fabricatio.capabilities.rag import RAG
11
+ from fabricatio.journal import logger
8
12
  from fabricatio.models.action import Action
9
- from fabricatio.models.extra.article_main import Article, ArticleSubsection
13
+ from fabricatio.models.extra.aricle_rag import ArticleChunk, CitationManager
14
+ from fabricatio.models.extra.article_essence import ArticleEssence
15
+ from fabricatio.models.extra.article_main import Article, ArticleChapter, ArticleSection, ArticleSubsection
16
+ from fabricatio.models.extra.article_outline import ArticleOutline
10
17
  from fabricatio.models.extra.rule import RuleSet
11
18
  from fabricatio.utils import ok
12
19
 
13
20
 
21
+ class WriteArticleContentRAG(Action, RAG, Propose):
22
+ """Write an article based on the provided outline."""
23
+
24
+ ref_limit: int = 100
25
+ """The limit of references to be retrieved"""
26
+ extractor_model: str
27
+ """The model to use for extracting the content from the retrieved references."""
28
+ query_model: str
29
+ """The model to use for querying the database"""
30
+
31
+ async def _execute(
32
+ self,
33
+ article_outline: ArticleOutline,
34
+ writing_ruleset: RuleSet,
35
+ collection_name: str = "article_chunks",
36
+ **cxt,
37
+ ) -> Article:
38
+ article = Article.from_outline(article_outline).update_ref(article_outline)
39
+ await gather(
40
+ *[
41
+ self._inner(article, article_outline, chap, sec, subsec)
42
+ for chap, sec, subsec in article.iter_subsections()
43
+ ]
44
+ )
45
+ return article.convert_tex()
46
+
47
+ async def _inner(
48
+ self,
49
+ article: Article,
50
+ article_outline: ArticleOutline,
51
+ chap: ArticleChapter,
52
+ sec: ArticleSection,
53
+ subsec: ArticleSubsection,
54
+ ) -> ArticleSubsection:
55
+ ref_q = ok(
56
+ await self.arefined_query(
57
+ f"{article_outline.display()}\n\nAbove is my article outline, I m writing graduate thesis titled `{article.title}`. "
58
+ f"More specifically, i m witting the Chapter `{chap.title}` >> Section `{sec.title}` >> Subsection `{subsec.title}`.\n"
59
+ f"I need to search related references to build up the content of the subsec mentioned above, which is `{subsec.title}`.\n"
60
+ f"plus, you can search required formulas by using latex equation code.\n"
61
+ f"provide 10 queries as possible, to get best result!\n"
62
+ f"You should provide both English version and chinese version of the refined queries!\n",
63
+ model=self.query_model,
64
+ ),
65
+ "Failed to refine query.",
66
+ )
67
+ ret = await self.aretrieve(ref_q, ArticleChunk, final_limit=self.ref_limit, result_per_query=25)
68
+ ret.reverse()
69
+ cm = CitationManager().update_chunks(ret)
70
+
71
+ raw_paras = await self.aask(
72
+ f"{cm.as_prompt()}\nAbove is some related reference retrieved for you. When need to cite some of them ,you MUST follow the academic convention,"
73
+ f"{article.referenced.display()}\n\nAbove is my article outline, I m writing graduate thesis titled `{article.title}`. "
74
+ f"More specifically, i m witting the Chapter `{chap.title}` >> Section `{sec.title}` >> Subsection `{subsec.title}`.\n"
75
+ f"Please help me write the paragraphs of the subsec mentioned above, which is `{subsec.title}`\n"
76
+ f"You can output the written paragraphs directly, without explanation. you should use `{subsec.language}`, and maintain academic writing style."
77
+ f"In addition,you MUST follow the academic convention and use [[1]] to cite the first reference, and use [[9]] to cite the second reference, and so on.\n"
78
+ f"It 's greatly recommended to cite multiple references that stands for the same opinion at a single sentences, like [[1,5,9]] for 1th,5th and 9th references,[[1-9,16]] for 1th to 9th and 16th references.\n"
79
+ f"citation number is REQUIRED to cite any reference!\n"
80
+ f"for paragraphs that need write equation you should also no forget to doing so. wrapp inline equation using $ $, and wrapp block equation using $$ $$.\n"
81
+ )
82
+
83
+ raw_paras = (
84
+ raw_paras.replace(r" \( ", "$").replace(r" \) ", "$").replace("\\[\n", "$$\n").replace("\n\\]", "\n$$")
85
+ )
86
+
87
+ new_subsec = ok(
88
+ await self.propose(
89
+ ArticleSubsection,
90
+ f"{raw_paras}\nAbove is the subsection titled `{subsec.title}`.\n"
91
+ f"I need you to extract the content to update my subsection obj provided below.\n"
92
+ f"Everything is build upon the typst language, which is similar to latex, \n"
93
+ f"so reference annotation like `[[1]]` for 1th reference or `[[2,6]]` for 2th and 6th reference or "
94
+ f"`[[1,5,9]]` for 1th,5th and 9th references or "
95
+ f"`[[1-9,16]]` for 1th to 9th and 16th references\n"
96
+ f"Those reference mark shall not be omitted during the extraction\n"
97
+ f"Wrapp inline expression using $ $, and wrapp block equation using $$ $$\n\n\n"
98
+ f"{subsec.display()}",
99
+ model=self.extractor_model,
100
+ ),
101
+ "Failed to propose new subsection.",
102
+ )
103
+
104
+ for p in new_subsec.paragraphs:
105
+ p.content = cm.apply(p.content)
106
+
107
+ subsec.update_from(new_subsec)
108
+ logger.debug(f"{subsec.title}:rpl\n{subsec.display()}")
109
+ return subsec
110
+
111
+
14
112
  class TweakArticleRAG(Action, RAG, Censor):
15
113
  """Write an article based on the provided outline.
16
114
 
@@ -39,7 +137,7 @@ class TweakArticleRAG(Action, RAG, Censor):
39
137
  twk_rag_ruleset: Optional[RuleSet] = None,
40
138
  parallel: bool = False,
41
139
  **cxt,
42
- ) -> Optional[Article]:
140
+ ) -> Article:
43
141
  """Write an article based on the provided outline.
44
142
 
45
143
  This method processes the article outline, either in parallel or sequentially, by enhancing each subsection
@@ -53,7 +151,7 @@ class TweakArticleRAG(Action, RAG, Censor):
53
151
  **cxt: Additional context parameters.
54
152
 
55
153
  Returns:
56
- Optional[Article]: The processed article with enhanced subsections and applied censoring rules.
154
+ Article: The processed article with enhanced subsections and applied censoring rules.
57
155
  """
58
156
  self.view(collection_name)
59
157
 
@@ -86,20 +184,43 @@ class TweakArticleRAG(Action, RAG, Censor):
86
184
  """
87
185
  refind_q = ok(
88
186
  await self.arefined_query(
89
- f"{article.referenced.as_prompt()}\n"
90
- f"# Subsection requiring reference enhancement\n"
91
- f"{subsec.display()}\n"
92
- f"# Requirement\n"
93
- f"Search related articles in the base to find reference candidates, "
94
- f"provide queries in both `English` and `{subsec.language}` can get more accurate results.",
187
+ f"{article.referenced.as_prompt()}\n# Subsection requiring reference enhancement\n{subsec.display()}\n"
95
188
  )
96
189
  )
97
190
  await self.censor_obj_inplace(
98
191
  subsec,
99
192
  ruleset=ruleset,
100
- reference=f"{await self.aretrieve_compact(refind_q, final_limit=self.ref_limit)}\n\n"
193
+ reference=f"{'\n\n'.join(d.display() for d in await self.aretrieve(refind_q, document_model=ArticleEssence, final_limit=self.ref_limit))}\n\n"
101
194
  f"You can use Reference above to rewrite the `{subsec.__class__.__name__}`.\n"
102
195
  f"You should Always use `{subsec.language}` as written language, "
103
196
  f"which is the original language of the `{subsec.title}`. "
104
197
  f"since rewrite a `{subsec.__class__.__name__}` in a different language is usually a bad choice",
105
198
  )
199
+
200
+
201
+ class ChunkArticle(Action):
202
+ """Chunk an article into smaller chunks."""
203
+
204
+ output_key: str = "article_chunks"
205
+ """The key used to store the output of the action."""
206
+ max_chunk_size: Optional[int] = None
207
+ """The maximum size of each chunk."""
208
+ max_overlapping_rate: Optional[float] = None
209
+ """The maximum overlapping rate between chunks."""
210
+
211
+ async def _execute(
212
+ self,
213
+ article_path: str | Path,
214
+ bib_manager: BibManager,
215
+ max_chunk_size: Optional[int] = None,
216
+ max_overlapping_rate: Optional[float] = None,
217
+ **_,
218
+ ) -> List[ArticleChunk]:
219
+ return ArticleChunk.from_file(
220
+ article_path,
221
+ bib_manager,
222
+ max_chunk_size=ok(max_chunk_size or self.max_chunk_size, "No max_chunk_size provided!"),
223
+ max_overlapping_rate=ok(
224
+ max_overlapping_rate or self.max_overlapping_rate, "No max_overlapping_rate provided!"
225
+ ),
226
+ )
@@ -0,0 +1,25 @@
1
+ """A module for file system utilities."""
2
+
3
+ from pathlib import Path
4
+ from typing import Any, List, Mapping, Self
5
+
6
+ from fabricatio.fs import safe_text_read
7
+ from fabricatio.journal import logger
8
+ from fabricatio.models.action import Action
9
+ from fabricatio.models.generic import FromMapping
10
+
11
+
12
+ class ReadText(Action, FromMapping):
13
+ """Read text from a file."""
14
+ output_key: str = "read_text"
15
+ read_path: str | Path
16
+ """Path to the file to read."""
17
+
18
+ async def _execute(self, *_: Any, **cxt) -> str:
19
+ logger.info(f"Read text from {Path(self.read_path).as_posix()} to {self.output_key}")
20
+ return safe_text_read(self.read_path)
21
+
22
+ @classmethod
23
+ def from_mapping(cls, mapping: Mapping[str, str | Path], **kwargs: Any) -> List[Self]:
24
+ """Create a list of ReadText actions from a mapping of output_key to read_path."""
25
+ return [cls(read_path=p, output_key=k, **kwargs) for k, p in mapping.items()]
@@ -1,11 +1,11 @@
1
1
  """Dump the finalized output to a file."""
2
2
 
3
3
  from pathlib import Path
4
- from typing import Any, Iterable, List, Optional, Type
4
+ from typing import Any, Iterable, List, Mapping, Optional, Type
5
5
 
6
6
  from fabricatio.journal import logger
7
7
  from fabricatio.models.action import Action
8
- from fabricatio.models.generic import FinalizedDumpAble, PersistentAble
8
+ from fabricatio.models.generic import FinalizedDumpAble, FromMapping, PersistentAble
9
9
  from fabricatio.models.task import Task
10
10
  from fabricatio.utils import ok
11
11
 
@@ -115,7 +115,7 @@ class RetrieveFromPersistent[T: PersistentAble](Action):
115
115
  return self.retrieve_cls.from_persistent(self.load_path)
116
116
 
117
117
 
118
- class RetrieveFromLatest[T: PersistentAble](RetrieveFromPersistent[T]):
118
+ class RetrieveFromLatest[T: PersistentAble](RetrieveFromPersistent[T], FromMapping):
119
119
  """Retrieve the object from the latest persistent file in the dir at `load_path`."""
120
120
 
121
121
  async def _execute(self, /, **_) -> Optional[T]:
@@ -130,6 +130,20 @@ class RetrieveFromLatest[T: PersistentAble](RetrieveFromPersistent[T]):
130
130
  logger.error(f"Path {self.load_path} is not a directory")
131
131
  return None
132
132
 
133
+ @classmethod
134
+ def from_mapping(
135
+ cls,
136
+ mapping: Mapping[str, str | Path],
137
+ *,
138
+ retrieve_cls: Type[T],
139
+ **kwargs,
140
+ ) -> List["RetrieveFromLatest[T]"]:
141
+ """Create a list of `RetrieveFromLatest` from the mapping."""
142
+ return [
143
+ cls(retrieve_cls=retrieve_cls, load_path=Path(p).as_posix(), output_key=o, **kwargs)
144
+ for o, p in mapping.items()
145
+ ]
146
+
133
147
 
134
148
  class GatherAsList(Action):
135
149
  """Gather the objects from the context as a list.
fabricatio/actions/rag.py CHANGED
@@ -2,37 +2,57 @@
2
2
 
3
3
  from typing import List, Optional
4
4
 
5
- from questionary import text
6
-
7
5
  from fabricatio.capabilities.rag import RAG
6
+ from fabricatio.config import configs
8
7
  from fabricatio.journal import logger
9
8
  from fabricatio.models.action import Action
10
- from fabricatio.models.generic import Vectorizable
9
+ from fabricatio.models.extra.rag import MilvusClassicModel, MilvusDataBase
11
10
  from fabricatio.models.task import Task
11
+ from fabricatio.utils import ok
12
12
 
13
13
 
14
14
  class InjectToDB(Action, RAG):
15
15
  """Inject data into the database."""
16
16
 
17
17
  output_key: str = "collection_name"
18
+ collection_name: str = "my_collection"
19
+ """The name of the collection to inject data into."""
18
20
 
19
- async def _execute[T: Vectorizable](
20
- self, to_inject: Optional[T] | List[Optional[T]], collection_name: str = "my_collection",override_inject:bool=False, **_
21
+ async def _execute[T: MilvusDataBase](
22
+ self, to_inject: Optional[T] | List[Optional[T]], override_inject: bool = False, **_
21
23
  ) -> Optional[str]:
24
+ from pymilvus.milvus_client import IndexParams
25
+
26
+ if to_inject is None:
27
+ return None
22
28
  if not isinstance(to_inject, list):
23
29
  to_inject = [to_inject]
24
- logger.info(f"Injecting {len(to_inject)} items into the collection '{collection_name}'")
30
+ if not (seq := [t for t in to_inject if t is not None]): # filter out None
31
+ return None
32
+ logger.info(f"Injecting {len(seq)} items into the collection '{self.collection_name}'")
25
33
  if override_inject:
26
- self.check_client().client.drop_collection(collection_name)
27
- await self.view(collection_name, create=True).consume_string(
28
- [
29
- t.prepare_vectorization(self.embedding_max_sequence_length)
30
- for t in to_inject
31
- if isinstance(t, Vectorizable)
32
- ],
33
- )
34
-
35
- return collection_name
34
+ self.check_client().client.drop_collection(self.collection_name)
35
+
36
+ await self.view(
37
+ self.collection_name,
38
+ create=True,
39
+ schema=seq[0].as_milvus_schema(
40
+ ok(
41
+ self.milvus_dimensions
42
+ or configs.rag.milvus_dimensions
43
+ or self.embedding_dimensions
44
+ or configs.embedding.dimensions
45
+ ),
46
+ ),
47
+ index_params=IndexParams(
48
+ seq[0].vector_field_name,
49
+ index_name=seq[0].vector_field_name,
50
+ index_type=seq[0].index_type,
51
+ metric_type=seq[0].metric_type,
52
+ ),
53
+ ).add_document(seq, flush=True)
54
+
55
+ return self.collection_name
36
56
 
37
57
 
38
58
  class RAGTalk(Action, RAG):
@@ -52,6 +72,8 @@ class RAGTalk(Action, RAG):
52
72
  output_key: str = "task_output"
53
73
 
54
74
  async def _execute(self, task_input: Task[str], **kwargs) -> int:
75
+ from questionary import text
76
+
55
77
  collection_name = kwargs.get("collection_name", "my_collection")
56
78
  counter = 0
57
79
 
@@ -62,10 +84,10 @@ class RAGTalk(Action, RAG):
62
84
  user_say = await text("User: ").ask_async()
63
85
  if user_say is None:
64
86
  break
65
- gpt_say = await self.aask_retrieved(
66
- user_say,
67
- user_say,
68
- extra_system_message=f"You have to answer to user obeying task assigned to you:\n{task_input.briefing}",
87
+ ret: List[MilvusClassicModel] = await self.aretrieve(user_say, document_model=MilvusClassicModel)
88
+
89
+ gpt_say = await self.aask(
90
+ user_say, system_message="\n".join(m.text for m in ret) + "\nYou can refer facts provided above."
69
91
  )
70
92
  print(f"GPT: {gpt_say}") # noqa: T201
71
93
  counter += 1
@@ -1,15 +1,16 @@
1
1
  """A module containing the DraftRuleSet action."""
2
2
 
3
- from typing import List, Optional
3
+ from typing import Any, List, Mapping, Optional, Self, Tuple
4
4
 
5
5
  from fabricatio.capabilities.check import Check
6
6
  from fabricatio.journal import logger
7
7
  from fabricatio.models.action import Action
8
8
  from fabricatio.models.extra.rule import RuleSet
9
+ from fabricatio.models.generic import FromMapping
9
10
  from fabricatio.utils import ok
10
11
 
11
12
 
12
- class DraftRuleSet(Action, Check):
13
+ class DraftRuleSet(Action, Check, FromMapping):
13
14
  """Action to draft a ruleset based on a given requirement description."""
14
15
 
15
16
  output_key: str = "drafted_ruleset"
@@ -45,8 +46,13 @@ class DraftRuleSet(Action, Check):
45
46
  logger.warning(f"Drafting Rule Failed for:\n{ruleset_requirement}")
46
47
  return ruleset
47
48
 
49
+ @classmethod
50
+ def from_mapping(cls, mapping: Mapping[str, Tuple[int, str]], **kwargs) -> List[Self]:
51
+ """Create a list of DraftRuleSet actions from a mapping of output keys to tuples of rule counts and requirements."""
52
+ return [cls(ruleset_requirement=r, rule_count=c, output_key=k, **kwargs) for k, (c, r) in mapping.items()]
48
53
 
49
- class GatherRuleset(Action):
54
+
55
+ class GatherRuleset(Action, FromMapping):
50
56
  """Action to gather a ruleset from a given requirement description."""
51
57
 
52
58
  output_key: str = "gathered_ruleset"
@@ -55,6 +61,11 @@ class GatherRuleset(Action):
55
61
  to_gather: List[str]
56
62
  """the cxt name of RuleSet to gather"""
57
63
 
64
+ @classmethod
65
+ def from_mapping(cls, mapping: Mapping[str, List[str]], **kwargs: Any) -> List[Self]:
66
+ """Create a list of GatherRuleset actions from a mapping of output keys to tuples of rule counts and requirements."""
67
+ return [cls(to_gather=t, output_key=k, **kwargs) for k, t in mapping.items()]
68
+
58
69
  async def _execute(self, **cxt) -> RuleSet:
59
70
  logger.info(f"Gathering Ruleset from {self.to_gather}")
60
71
  # Fix for not_found
@@ -0,0 +1,65 @@
1
+ """A module that provide capabilities for extracting information from a given source to a model."""
2
+
3
+ from typing import List, Optional, Type, Unpack, overload
4
+
5
+ from fabricatio import TEMPLATE_MANAGER
6
+ from fabricatio.capabilities.propose import Propose
7
+ from fabricatio.config import configs
8
+ from fabricatio.models.generic import ProposedAble
9
+ from fabricatio.models.kwargs_types import ValidateKwargs
10
+
11
+
12
+ class Extract(Propose):
13
+ """A class that extract information from a given source to a model."""
14
+
15
+ @overload
16
+ async def extract[M: ProposedAble](
17
+ self,
18
+ cls: Type[M],
19
+ source: str,
20
+ extract_requirement: Optional[str] = None,
21
+ **kwargs: Unpack[ValidateKwargs[M]],
22
+ ) -> M: ...
23
+ @overload
24
+ async def extract[M: ProposedAble](
25
+ self,
26
+ cls: Type[M],
27
+ source: str,
28
+ extract_requirement: Optional[str] = None,
29
+ **kwargs: Unpack[ValidateKwargs[None]],
30
+ ) -> Optional[M]: ...
31
+
32
+ @overload
33
+ async def extract[M: ProposedAble](
34
+ self,
35
+ cls: Type[M],
36
+ source: List[str],
37
+ extract_requirement: Optional[str] = None,
38
+ **kwargs: Unpack[ValidateKwargs[M]],
39
+ ) -> List[M]: ...
40
+ @overload
41
+ async def extract[M: ProposedAble](
42
+ self,
43
+ cls: Type[M],
44
+ source: List[str],
45
+ extract_requirement: Optional[str] = None,
46
+ **kwargs: Unpack[ValidateKwargs[None]],
47
+ ) -> List[Optional[M]]: ...
48
+ async def extract[M: ProposedAble](
49
+ self,
50
+ cls: Type[M],
51
+ source: List[str] | str,
52
+ extract_requirement: Optional[str] = None,
53
+ **kwargs: Unpack[ValidateKwargs[Optional[M]]],
54
+ ) -> M | List[M] | Optional[M] | List[Optional[M]]:
55
+ """Extract information from a given source to a model."""
56
+ return await self.propose(
57
+ cls,
58
+ prompt=TEMPLATE_MANAGER.render_template(
59
+ configs.templates.extract_template,
60
+ [{"source": s, "extract_requirement": extract_requirement} for s in source]
61
+ if isinstance(source, list)
62
+ else {"source": source, "extract_requirement": extract_requirement},
63
+ ),
64
+ **kwargs,
65
+ )
@@ -130,7 +130,7 @@ class RAG(EmbeddingUsage):
130
130
  if isinstance(data, MilvusDataBase):
131
131
  data = [data]
132
132
 
133
- data_vec = await self.vectorize([d.to_vectorize for d in data])
133
+ data_vec = await self.vectorize([d.prepare_vectorization() for d in data])
134
134
  prepared_data = [d.prepare_insertion(vec) for d, vec in zip(data, data_vec, strict=True)]
135
135
 
136
136
  c_name = collection_name or self.safe_target_collection
@@ -188,13 +188,15 @@ class RAG(EmbeddingUsage):
188
188
  async def aretrieve[D: MilvusDataBase](
189
189
  self,
190
190
  query: List[str] | str,
191
+ document_model: Type[D],
191
192
  final_limit: int = 20,
192
- **kwargs: Unpack[FetchKwargs[D]],
193
+ **kwargs: Unpack[FetchKwargs],
193
194
  ) -> List[D]:
194
195
  """Retrieve data from the collection.
195
196
 
196
197
  Args:
197
198
  query (List[str] | str): The query to be used for retrieval.
199
+ document_model (Type[D]): The model class used to convert retrieved data into document objects.
198
200
  final_limit (int): The final limit on the number of results to return.
199
201
  **kwargs (Unpack[FetchKwargs]): Additional keyword arguments for retrieval.
200
202
 
@@ -206,6 +208,7 @@ class RAG(EmbeddingUsage):
206
208
  return (
207
209
  await self.afetch_document(
208
210
  vecs=(await self.vectorize(query)),
211
+ document_model=document_model,
209
212
  **kwargs,
210
213
  )
211
214
  )[:final_limit]
@@ -14,7 +14,7 @@ from fabricatio.models.generic import Display, ProposedAble
14
14
  from fabricatio.models.kwargs_types import CompositeScoreKwargs, ValidateKwargs
15
15
  from fabricatio.parser import JsonCapture
16
16
  from fabricatio.rust_instances import TEMPLATE_MANAGER
17
- from fabricatio.utils import fallback_kwargs, ok, override_kwargs
17
+ from fabricatio.utils import ok, override_kwargs
18
18
 
19
19
 
20
20
  class Rating(Propose):
@@ -137,7 +137,7 @@ class Rating(Propose):
137
137
  or dict(zip(criteria, criteria, strict=True))
138
138
  )
139
139
 
140
- return await self.rate_fine_grind(to_rate, manual, score_range, **fallback_kwargs(kwargs, co_extractor={}))
140
+ return await self.rate_fine_grind(to_rate, manual, score_range, **kwargs)
141
141
 
142
142
  async def draft_rating_manual(
143
143
  self, topic: str, criteria: Optional[Set[str]] = None, **kwargs: Unpack[ValidateKwargs[Dict[str, str]]]
@@ -338,6 +338,7 @@ class Rating(Propose):
338
338
  criteria: Optional[Set[str]] = None,
339
339
  weights: Optional[Dict[str, float]] = None,
340
340
  manual: Optional[Dict[str, str]] = None,
341
+ approx: bool = False,
341
342
  **kwargs: Unpack[ValidateKwargs[List[Dict[str, float]]]],
342
343
  ) -> List[float]:
343
344
  """Calculates the composite scores for a list of items based on a given topic and criteria.
@@ -348,6 +349,7 @@ class Rating(Propose):
348
349
  criteria (Optional[Set[str]]): A set of criteria for the rating. Defaults to None.
349
350
  weights (Optional[Dict[str, float]]): A dictionary of rating weights for each criterion. Defaults to None.
350
351
  manual (Optional[Dict[str, str]]): A dictionary of manual ratings for each item. Defaults to None.
352
+ approx (bool): Whether to use approximate rating criteria. Defaults to False.
351
353
  **kwargs (Unpack[ValidateKwargs]): Additional keyword arguments for the LLM usage.
352
354
 
353
355
  Returns:
@@ -355,6 +357,7 @@ class Rating(Propose):
355
357
  """
356
358
  criteria = ok(
357
359
  criteria
360
+ or (await self.draft_rating_criteria(topic, **override_kwargs(kwargs, default=None)) if approx else None)
358
361
  or await self.draft_rating_criteria_from_examples(topic, to_rate, **override_kwargs(kwargs, default=None))
359
362
  )
360
363
  weights = ok(
@@ -3,7 +3,7 @@
3
3
  from types import CodeType
4
4
  from typing import Any, Dict, List, Optional, Tuple, Unpack
5
5
 
6
- import orjson
6
+ import ujson
7
7
 
8
8
  from fabricatio.capabilities.propose import Propose
9
9
  from fabricatio.config import configs
@@ -20,9 +20,9 @@ class ProposeTask(Propose):
20
20
  """A class that proposes a task based on a prompt."""
21
21
 
22
22
  async def propose_task[T](
23
- self,
24
- prompt: str,
25
- **kwargs: Unpack[ValidateKwargs[Task[T]]],
23
+ self,
24
+ prompt: str,
25
+ **kwargs: Unpack[ValidateKwargs[Task[T]]],
26
26
  ) -> Optional[Task[T]]:
27
27
  """Asynchronously proposes a task based on a given prompt and parameters.
28
28
 
@@ -44,11 +44,11 @@ class HandleTask(ToolBoxUsage):
44
44
  """A class that handles a task based on a task object."""
45
45
 
46
46
  async def draft_tool_usage_code(
47
- self,
48
- task: Task,
49
- tools: List[Tool],
50
- data: Dict[str, Any],
51
- **kwargs: Unpack[ValidateKwargs],
47
+ self,
48
+ task: Task,
49
+ tools: List[Tool],
50
+ data: Dict[str, Any],
51
+ **kwargs: Unpack[ValidateKwargs],
52
52
  ) -> Optional[Tuple[CodeType, List[str]]]:
53
53
  """Asynchronously drafts the tool usage code for a task based on a given task object and tools."""
54
54
  logger.info(f"Drafting tool usage code for task: {task.briefing}")
@@ -60,7 +60,7 @@ class HandleTask(ToolBoxUsage):
60
60
 
61
61
  def _validator(response: str) -> Tuple[CodeType, List[str]] | None:
62
62
  if (source := PythonCapture.convert_with(response, lambda resp: compile(resp, "<string>", "exec"))) and (
63
- to_extract := JsonCapture.convert_with(response, orjson.loads)
63
+ to_extract := JsonCapture.convert_with(response, ujson.loads)
64
64
  ):
65
65
  return source, to_extract
66
66
 
@@ -85,12 +85,12 @@ class HandleTask(ToolBoxUsage):
85
85
  )
86
86
 
87
87
  async def handle_fine_grind(
88
- self,
89
- task: Task,
90
- data: Dict[str, Any],
91
- box_choose_kwargs: Optional[ChooseKwargs] = None,
92
- tool_choose_kwargs: Optional[ChooseKwargs] = None,
93
- **kwargs: Unpack[ValidateKwargs],
88
+ self,
89
+ task: Task,
90
+ data: Dict[str, Any],
91
+ box_choose_kwargs: Optional[ChooseKwargs] = None,
92
+ tool_choose_kwargs: Optional[ChooseKwargs] = None,
93
+ **kwargs: Unpack[ValidateKwargs],
94
94
  ) -> Optional[Tuple]:
95
95
  """Asynchronously handles a task based on a given task object and parameters."""
96
96
  logger.info(f"Handling task: \n{task.briefing}")
fabricatio/config.py CHANGED
@@ -86,8 +86,10 @@ 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
-
90
-
89
+ presence_penalty:Optional[PositiveFloat]=None
90
+ """The presence penalty of the LLM model."""
91
+ frequency_penalty:Optional[PositiveFloat]=None
92
+ """The frequency penalty of the LLM model."""
91
93
  class EmbeddingConfig(BaseModel):
92
94
  """Embedding configuration class."""
93
95
 
@@ -249,6 +251,11 @@ class TemplateConfig(BaseModel):
249
251
 
250
252
  rule_requirement_template: str = Field(default="rule_requirement")
251
253
  """The name of the rule requirement template which will be used to generate a rule requirement."""
254
+
255
+
256
+ extract_template: str = Field(default="extract")
257
+ """The name of the extract template which will be used to extract model from string."""
258
+
252
259
  class MagikaConfig(BaseModel):
253
260
  """Magika configuration class."""
254
261