fabricatio 0.2.6.dev2__cp312-cp312-win_amd64.whl → 0.2.7.dev3__cp312-cp312-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. fabricatio/__init__.py +7 -24
  2. fabricatio/_rust.cp312-win_amd64.pyd +0 -0
  3. fabricatio/_rust.pyi +22 -0
  4. fabricatio/actions/article.py +150 -19
  5. fabricatio/actions/article_rag.py +35 -0
  6. fabricatio/actions/output.py +21 -6
  7. fabricatio/actions/rag.py +51 -3
  8. fabricatio/capabilities/correct.py +34 -4
  9. fabricatio/capabilities/rag.py +67 -16
  10. fabricatio/capabilities/rating.py +15 -6
  11. fabricatio/capabilities/review.py +7 -4
  12. fabricatio/capabilities/task.py +5 -5
  13. fabricatio/config.py +29 -21
  14. fabricatio/decorators.py +32 -0
  15. fabricatio/models/action.py +117 -43
  16. fabricatio/models/extra/article_essence.py +226 -0
  17. fabricatio/models/extra/article_main.py +359 -0
  18. fabricatio/models/extra/article_outline.py +276 -0
  19. fabricatio/models/extra/article_proposal.py +37 -0
  20. fabricatio/models/generic.py +95 -9
  21. fabricatio/models/kwargs_types.py +40 -10
  22. fabricatio/models/role.py +30 -6
  23. fabricatio/models/tool.py +6 -2
  24. fabricatio/models/usages.py +94 -47
  25. fabricatio/models/utils.py +29 -2
  26. fabricatio/parser.py +2 -0
  27. fabricatio/workflows/articles.py +12 -1
  28. fabricatio-0.2.7.dev3.data/scripts/tdown.exe +0 -0
  29. {fabricatio-0.2.6.dev2.dist-info → fabricatio-0.2.7.dev3.dist-info}/METADATA +6 -2
  30. fabricatio-0.2.7.dev3.dist-info/RECORD +46 -0
  31. {fabricatio-0.2.6.dev2.dist-info → fabricatio-0.2.7.dev3.dist-info}/WHEEL +1 -1
  32. fabricatio/models/extra.py +0 -171
  33. fabricatio-0.2.6.dev2.data/scripts/tdown.exe +0 -0
  34. fabricatio-0.2.6.dev2.dist-info/RECORD +0 -42
  35. {fabricatio-0.2.6.dev2.dist-info → fabricatio-0.2.7.dev3.dist-info}/licenses/LICENSE +0 -0
@@ -15,13 +15,14 @@ from fabricatio.config import configs
15
15
  from fabricatio.journal import logger
16
16
  from fabricatio.models.kwargs_types import (
17
17
  ChooseKwargs,
18
- CollectionSimpleConfigKwargs,
18
+ CollectionConfigKwargs,
19
19
  EmbeddingKwargs,
20
20
  FetchKwargs,
21
21
  LLMKwargs,
22
+ RetrievalKwargs,
22
23
  )
23
24
  from fabricatio.models.usages import EmbeddingUsage
24
- from fabricatio.models.utils import MilvusData
25
+ from fabricatio.models.utils import MilvusData, ok
25
26
  from more_itertools.recipes import flatten, unique
26
27
  from pydantic import Field, PrivateAttr
27
28
 
@@ -60,13 +61,21 @@ class RAG(EmbeddingUsage):
60
61
  ) -> Self:
61
62
  """Initialize the Milvus client."""
62
63
  self._client = create_client(
63
- uri=milvus_uri or (self.milvus_uri or configs.rag.milvus_uri).unicode_string(),
64
+ uri=milvus_uri or ok(self.milvus_uri or configs.rag.milvus_uri).unicode_string(),
64
65
  token=milvus_token
65
66
  or (token.get_secret_value() if (token := (self.milvus_token or configs.rag.milvus_token)) else ""),
66
- timeout=milvus_timeout or self.milvus_timeout,
67
+ timeout=milvus_timeout or self.milvus_timeout or configs.rag.milvus_timeout,
67
68
  )
68
69
  return self
69
70
 
71
+ def check_client(self, init: bool = True) -> Self:
72
+ """Check if the client is initialized, and if not, initialize it."""
73
+ if self._client is None and init:
74
+ return self.init_client()
75
+ if self._client is None and not init:
76
+ raise RuntimeError("Client is not initialized. Have you called `self.init_client()`?")
77
+ return self
78
+
70
79
  @overload
71
80
  async def pack(
72
81
  self, input_text: List[str], subject: Optional[str] = None, **kwargs: Unpack[EmbeddingKwargs]
@@ -102,17 +111,24 @@ class RAG(EmbeddingUsage):
102
111
  ]
103
112
 
104
113
  def view(
105
- self, collection_name: Optional[str], create: bool = False, **kwargs: Unpack[CollectionSimpleConfigKwargs]
114
+ self, collection_name: Optional[str], create: bool = False, **kwargs: Unpack[CollectionConfigKwargs]
106
115
  ) -> Self:
107
116
  """View the specified collection.
108
117
 
109
118
  Args:
110
119
  collection_name (str): The name of the collection.
111
120
  create (bool): Whether to create the collection if it does not exist.
112
- **kwargs (Unpack[CollectionSimpleConfigKwargs]): Additional keyword arguments for collection configuration.
121
+ **kwargs (Unpack[CollectionConfigKwargs]): Additional keyword arguments for collection configuration.
113
122
  """
114
- if create and collection_name and self.client.has_collection(collection_name):
115
- kwargs["dimension"] = kwargs.get("dimension") or self.milvus_dimensions or configs.rag.milvus_dimensions
123
+ if create and collection_name and not self.check_client().client.has_collection(collection_name):
124
+ kwargs["dimension"] = ok(
125
+ kwargs.get("dimension")
126
+ or self.milvus_dimensions
127
+ or configs.rag.milvus_dimensions
128
+ or self.embedding_dimensions
129
+ or configs.embedding.dimensions,
130
+ "`dimension` is not set at any level.",
131
+ )
116
132
  self.client.create_collection(collection_name, auto_id=True, **kwargs)
117
133
  logger.info(f"Creating collection {collection_name}")
118
134
 
@@ -158,7 +174,7 @@ class RAG(EmbeddingUsage):
158
174
  else:
159
175
  raise TypeError(f"Expected MilvusData or list of MilvusData, got {type(data)}")
160
176
  c_name = collection_name or self.safe_target_collection
161
- self.client.insert(c_name, prepared_data)
177
+ self.check_client().client.insert(c_name, prepared_data)
162
178
 
163
179
  if flush:
164
180
  logger.debug(f"Flushing collection {c_name}")
@@ -198,6 +214,25 @@ class RAG(EmbeddingUsage):
198
214
  self.add_document(await self.pack(text), collection_name or self.safe_target_collection, flush=True)
199
215
  return self
200
216
 
217
+ @overload
218
+ async def afetch_document[V: (int, str, float, bytes)](
219
+ self,
220
+ vecs: List[List[float]],
221
+ desired_fields: List[str],
222
+ collection_name: Optional[str] = None,
223
+ similarity_threshold: float = 0.37,
224
+ result_per_query: int = 10,
225
+ ) -> List[Dict[str, V]]: ...
226
+
227
+ @overload
228
+ async def afetch_document[V: (int, str, float, bytes)](
229
+ self,
230
+ vecs: List[List[float]],
231
+ desired_fields: str,
232
+ collection_name: Optional[str] = None,
233
+ similarity_threshold: float = 0.37,
234
+ result_per_query: int = 10,
235
+ ) -> List[V]: ...
201
236
  async def afetch_document[V: (int, str, float, bytes)](
202
237
  self,
203
238
  vecs: List[List[float]],
@@ -219,7 +254,7 @@ class RAG(EmbeddingUsage):
219
254
  List[Dict[str, Any]] | List[Any]: The retrieved data.
220
255
  """
221
256
  # Step 1: Search for vectors
222
- search_results = self.client.search(
257
+ search_results = self.check_client().client.search(
223
258
  collection_name or self.safe_target_collection,
224
259
  vecs,
225
260
  search_params={"radius": similarity_threshold},
@@ -260,7 +295,7 @@ class RAG(EmbeddingUsage):
260
295
  if isinstance(query, str):
261
296
  query = [query]
262
297
  return cast(
263
- List[str],
298
+ "List[str]",
264
299
  await self.afetch_document(
265
300
  vecs=(await self.vectorize(query)),
266
301
  desired_fields="text",
@@ -268,6 +303,24 @@ class RAG(EmbeddingUsage):
268
303
  ),
269
304
  )[:final_limit]
270
305
 
306
+ async def aretrieve_compact(
307
+ self,
308
+ query: List[str] | str,
309
+ **kwargs: Unpack[RetrievalKwargs],
310
+ ) -> str:
311
+ """Retrieve data from the collection and format it for display.
312
+
313
+ Args:
314
+ query (List[str] | str): The query to be used for retrieval.
315
+ **kwargs (Unpack[RetrievalKwargs]): Additional keyword arguments for retrieval.
316
+
317
+ Returns:
318
+ str: A formatted string containing the retrieved data.
319
+ """
320
+ return TEMPLATE_MANAGER.render_template(
321
+ configs.templates.retrieved_display_template, {"docs": (await self.aretrieve(query, **kwargs))}
322
+ )
323
+
271
324
  async def aask_retrieved(
272
325
  self,
273
326
  question: str,
@@ -298,16 +351,14 @@ class RAG(EmbeddingUsage):
298
351
  Returns:
299
352
  str: A string response generated after asking with the context of retrieved documents.
300
353
  """
301
- docs = await self.aretrieve(
354
+ rendered = await self.aretrieve_compact(
302
355
  query or question,
303
- final_limit,
356
+ final_limit=final_limit,
304
357
  collection_name=collection_name,
305
358
  result_per_query=result_per_query,
306
359
  similarity_threshold=similarity_threshold,
307
360
  )
308
361
 
309
- rendered = TEMPLATE_MANAGER.render_template(configs.templates.retrieved_display_template, {"docs": docs[::-1]})
310
-
311
362
  logger.debug(f"Retrieved Documents: \n{rendered}")
312
363
  return await self.aask(
313
364
  question,
@@ -315,7 +366,7 @@ class RAG(EmbeddingUsage):
315
366
  **kwargs,
316
367
  )
317
368
 
318
- async def arefined_query(self, question: List[str] | str, **kwargs: Unpack[ChooseKwargs]) -> List[str]:
369
+ async def arefined_query(self, question: List[str] | str, **kwargs: Unpack[ChooseKwargs]) -> Optional[List[str]]:
319
370
  """Refines the given question using a template.
320
371
 
321
372
  Args:
@@ -10,6 +10,7 @@ from fabricatio.journal import logger
10
10
  from fabricatio.models.generic import WithBriefing
11
11
  from fabricatio.models.kwargs_types import ValidateKwargs
12
12
  from fabricatio.models.usages import LLMUsage
13
+ from fabricatio.models.utils import override_kwargs
13
14
  from fabricatio.parser import JsonCapture
14
15
  from more_itertools import flatten, windowed
15
16
  from pydantic import NonNegativeInt, PositiveInt
@@ -126,13 +127,13 @@ class GiveRating(WithBriefing, LLMUsage):
126
127
  return await self.rate_fine_grind(to_rate, manual, score_range, **kwargs)
127
128
 
128
129
  async def draft_rating_manual(
129
- self, topic: str, criteria: Set[str], **kwargs: Unpack[ValidateKwargs[Dict[str, str]]]
130
+ self, topic: str, criteria: Optional[Set[str]] = None, **kwargs: Unpack[ValidateKwargs[Dict[str, str]]]
130
131
  ) -> Optional[Dict[str, str]]:
131
132
  """Drafts a rating manual based on a topic and dimensions.
132
133
 
133
134
  Args:
134
135
  topic (str): The topic for the rating manual.
135
- criteria (Set[str]): A set of dimensions for the rating manual.
136
+ criteria (Optional[Set[str]], optional): A set of criteria for the rating manual. If not specified, then this method will draft the criteria automatically.
136
137
  **kwargs (Unpack[ValidateKwargs]): Additional keyword arguments for the LLM usage.
137
138
 
138
139
  Returns:
@@ -148,6 +149,14 @@ class GiveRating(WithBriefing, LLMUsage):
148
149
  return json_data
149
150
  return None
150
151
 
152
+ criteria = criteria or await self.draft_rating_criteria(
153
+ topic, **self.prepend_sys_msg(override_kwargs(dict(kwargs), default=None))
154
+ )
155
+
156
+ if criteria is None:
157
+ logger.error(f"Failed to draft rating criteria for topic {topic}")
158
+ return None
159
+
151
160
  return await self.aask_validate(
152
161
  question=(
153
162
  TEMPLATE_MANAGER.render_template(
@@ -159,7 +168,7 @@ class GiveRating(WithBriefing, LLMUsage):
159
168
  )
160
169
  ),
161
170
  validator=_validator,
162
- **self.prepend(kwargs),
171
+ **self.prepend_sys_msg(kwargs),
163
172
  )
164
173
 
165
174
  async def draft_rating_criteria(
@@ -191,7 +200,7 @@ class GiveRating(WithBriefing, LLMUsage):
191
200
  validator=lambda resp: set(out)
192
201
  if (out := JsonCapture.validate_with(resp, list, str, criteria_count)) is not None
193
202
  else out,
194
- **self.prepend(kwargs),
203
+ **self.prepend_sys_msg(kwargs),
195
204
  )
196
205
 
197
206
  async def draft_rating_criteria_from_examples(
@@ -244,7 +253,7 @@ class GiveRating(WithBriefing, LLMUsage):
244
253
  validator=lambda resp: JsonCapture.validate_with(
245
254
  resp, target_type=list, elements_type=str, length=reasons_count
246
255
  ),
247
- **self.prepend(kwargs),
256
+ **self.prepend_sys_msg(kwargs),
248
257
  )
249
258
  )
250
259
  # extract certain mount of criteria from reasons according to their importance and frequency
@@ -301,7 +310,7 @@ class GiveRating(WithBriefing, LLMUsage):
301
310
  for pair in windows
302
311
  ],
303
312
  validator=lambda resp: JsonCapture.validate_with(resp, target_type=float),
304
- **self.prepend(kwargs),
313
+ **self.prepend_sys_msg(kwargs),
305
314
  )
306
315
  weights = [1]
307
316
  for rw in relative_weights:
@@ -1,6 +1,6 @@
1
1
  """A module that provides functionality to rate tasks based on a rating manual and score range."""
2
2
 
3
- from typing import List, Optional, Self, Set, Unpack, cast
3
+ from typing import Dict, List, Optional, Self, Set, Unpack, cast
4
4
 
5
5
  from fabricatio._rust_instances import TEMPLATE_MANAGER
6
6
  from fabricatio.capabilities.propose import Propose
@@ -121,7 +121,7 @@ class ReviewResult[T](ProposedAble, Display):
121
121
  ReviewResult[K]: The current instance with updated reference type.
122
122
  """
123
123
  self._ref = ref # pyright: ignore [reportAttributeAccessIssue]
124
- return cast(ReviewResult[K], self)
124
+ return cast("ReviewResult[K]", self)
125
125
 
126
126
  def deref(self) -> T:
127
127
  """Retrieve the referenced object that was reviewed.
@@ -200,13 +200,14 @@ class Review(GiveRating, Propose):
200
200
  ReviewResult[Task[T]]: A review result containing identified problems and proposed solutions,
201
201
  with a reference to the original task.
202
202
  """
203
- return cast(ReviewResult[Task[T]], await self.review_obj(task, **kwargs))
203
+ return cast("ReviewResult[Task[T]]", await self.review_obj(task, **kwargs))
204
204
 
205
205
  async def review_string(
206
206
  self,
207
207
  input_text: str,
208
208
  topic: str,
209
209
  criteria: Optional[Set[str]] = None,
210
+ rating_manual: Optional[Dict[str, str]] = None,
210
211
  **kwargs: Unpack[ValidateKwargs[ReviewResult[str]]],
211
212
  ) -> ReviewResult[str]:
212
213
  """Review a string based on specified topic and criteria.
@@ -219,6 +220,7 @@ class Review(GiveRating, Propose):
219
220
  topic (str): The subject topic for the review criteria.
220
221
  criteria (Optional[Set[str]], optional): A set of criteria for the review.
221
222
  If not provided, criteria will be drafted automatically. Defaults to None.
223
+ rating_manual (Optional[Dict[str,str]], optional): A dictionary of rating criteria and their corresponding scores.
222
224
  **kwargs (Unpack[ValidateKwargs]): Additional keyword arguments for the LLM usage.
223
225
 
224
226
  Returns:
@@ -227,12 +229,13 @@ class Review(GiveRating, Propose):
227
229
  """
228
230
  default = None
229
231
  if "default" in kwargs:
232
+ # this `default` is the default for the `propose` method
230
233
  default = kwargs.pop("default")
231
234
 
232
235
  criteria = criteria or (await self.draft_rating_criteria(topic, **kwargs))
233
236
  if not criteria:
234
237
  raise ValueError("No criteria provided for review.")
235
- manual = await self.draft_rating_manual(topic, criteria, **kwargs)
238
+ manual = rating_manual or await self.draft_rating_manual(topic, criteria, **kwargs)
236
239
 
237
240
  if default is not None:
238
241
  kwargs["default"] = default
@@ -23,7 +23,7 @@ class ProposeTask(WithBriefing, Propose):
23
23
  self,
24
24
  prompt: str,
25
25
  **kwargs: Unpack[ValidateKwargs[Task[T]]],
26
- ) -> Task[T]:
26
+ ) -> Optional[Task[T]]:
27
27
  """Asynchronously proposes a task based on a given prompt and parameters.
28
28
 
29
29
  Parameters:
@@ -37,7 +37,7 @@ class ProposeTask(WithBriefing, Propose):
37
37
  logger.error(err := f"{self.name}: Prompt must be provided.")
38
38
  raise ValueError(err)
39
39
 
40
- return await self.propose(Task, prompt, **self.prepend(cast(Dict[str, Any], kwargs)))
40
+ return await self.propose(Task, prompt, **self.prepend_sys_msg(cast("Dict[str, Any]", kwargs)))
41
41
 
42
42
 
43
43
  class HandleTask(WithBriefing, ToolBoxUsage):
@@ -81,10 +81,10 @@ class HandleTask(WithBriefing, ToolBoxUsage):
81
81
  return await self.aask_validate(
82
82
  question=q,
83
83
  validator=_validator,
84
- **self.prepend(cast(Dict[str, Any], kwargs)),
84
+ **self.prepend_sys_msg(cast("Dict[str, Any]", kwargs)),
85
85
  )
86
86
 
87
- async def handle_fin_grind(
87
+ async def handle_fine_grind(
88
88
  self,
89
89
  task: Task,
90
90
  data: Dict[str, Any],
@@ -110,4 +110,4 @@ class HandleTask(WithBriefing, ToolBoxUsage):
110
110
 
111
111
  async def handle(self, task: Task, data: Dict[str, Any], **kwargs: Unpack[ValidateKwargs]) -> Optional[Tuple]:
112
112
  """Asynchronously handles a task based on a given task object and parameters."""
113
- return await self.handle_fin_grind(task, data, **kwargs)
113
+ return await self.handle_fine_grind(task, data, **kwargs)
fabricatio/config.py CHANGED
@@ -48,37 +48,37 @@ class LLMConfig(BaseModel):
48
48
  """
49
49
 
50
50
  model_config = ConfigDict(use_attribute_docstrings=True)
51
- api_endpoint: HttpUrl = Field(default=HttpUrl("https://api.openai.com"))
51
+ api_endpoint: Optional[HttpUrl] = Field(default=HttpUrl("https://api.openai.com"))
52
52
  """OpenAI API Endpoint."""
53
53
 
54
- api_key: SecretStr = Field(default=SecretStr(""))
54
+ api_key: Optional[SecretStr] = Field(default=SecretStr("sk-setyourkey"))
55
55
  """OpenAI API key. Empty by default for security reasons, should be set before use."""
56
56
 
57
- timeout: PositiveInt = Field(default=300)
57
+ timeout: Optional[PositiveInt] = Field(default=300)
58
58
  """The timeout of the LLM model in seconds. Default is 300 seconds as per request."""
59
59
 
60
- max_retries: PositiveInt = Field(default=3)
60
+ max_retries: Optional[PositiveInt] = Field(default=3)
61
61
  """The maximum number of retries. Default is 3 retries."""
62
62
 
63
- model: str = Field(default="gpt-3.5-turbo")
63
+ model: Optional[str] = Field(default="gpt-3.5-turbo")
64
64
  """The LLM model name. Set to 'gpt-3.5-turbo' as per request."""
65
65
 
66
- temperature: NonNegativeFloat = Field(default=1.0)
66
+ temperature: Optional[NonNegativeFloat] = Field(default=1.0)
67
67
  """The temperature of the LLM model. Controls randomness in generation. Set to 1.0 as per request."""
68
68
 
69
- stop_sign: str | List[str] = Field(default_factory=lambda: ["\n\n\n", "User:"])
69
+ stop_sign: Optional[str | List[str]] = Field(default=None)
70
70
  """The stop sign of the LLM model. No default stop sign specified."""
71
71
 
72
- top_p: NonNegativeFloat = Field(default=0.35)
72
+ top_p: Optional[NonNegativeFloat] = Field(default=0.35)
73
73
  """The top p of the LLM model. Controls diversity via nucleus sampling. Set to 0.35 as per request."""
74
74
 
75
- generation_count: PositiveInt = Field(default=1)
75
+ generation_count: Optional[PositiveInt] = Field(default=1)
76
76
  """The number of generations to generate. Default is 1."""
77
77
 
78
- stream: bool = Field(default=False)
78
+ stream: Optional[bool] = Field(default=False)
79
79
  """Whether to stream the LLM model's response. Default is False."""
80
80
 
81
- max_tokens: PositiveInt = Field(default=8192)
81
+ max_tokens: Optional[PositiveInt] = Field(default=None)
82
82
  """The maximum number of tokens to generate. Set to 8192 as per request."""
83
83
 
84
84
  rpm: Optional[PositiveInt] = Field(default=100)
@@ -93,7 +93,7 @@ class EmbeddingConfig(BaseModel):
93
93
 
94
94
  model_config = ConfigDict(use_attribute_docstrings=True)
95
95
 
96
- model: str = Field(default="text-embedding-ada-002")
96
+ model: Optional[str] = Field(default="text-embedding-ada-002")
97
97
  """The embedding model name. """
98
98
 
99
99
  dimensions: Optional[PositiveInt] = Field(default=None)
@@ -102,10 +102,10 @@ class EmbeddingConfig(BaseModel):
102
102
  timeout: Optional[PositiveInt] = Field(default=None)
103
103
  """The timeout of the embedding model in seconds."""
104
104
 
105
- max_sequence_length: PositiveInt = Field(default=8192)
105
+ max_sequence_length: Optional[PositiveInt] = Field(default=8192)
106
106
  """The maximum sequence length of the embedding model. Default is 8192 as per request."""
107
107
 
108
- caching: bool = Field(default=False)
108
+ caching: Optional[bool] = Field(default=False)
109
109
  """Whether to cache the embedding. Default is False."""
110
110
 
111
111
  api_endpoint: Optional[HttpUrl] = None
@@ -148,13 +148,13 @@ class DebugConfig(BaseModel):
148
148
  log_level: Literal["DEBUG", "INFO", "SUCCESS", "WARNING", "ERROR", "CRITICAL"] = Field(default="INFO")
149
149
  """The log level of the application."""
150
150
 
151
- log_file: FilePath = Field(default=Path(rf"{ROAMING_DIR}\fabricatio.log"))
151
+ log_file: FilePath = Field(default=Path(rf"{ROAMING_DIR}\fabricatio.log"), frozen=True)
152
152
  """The log file of the application."""
153
153
 
154
- rotation: int = Field(default=1)
154
+ rotation: int = Field(default=1, frozen=True)
155
155
  """The rotation of the log file. in weeks."""
156
156
 
157
- retention: int = Field(default=2)
157
+ retention: int = Field(default=2, frozen=True)
158
158
  """The retention of the log file. in weeks."""
159
159
 
160
160
  streaming_visible: bool = Field(default=False)
@@ -232,6 +232,12 @@ class TemplateConfig(BaseModel):
232
232
  correct_template: str = Field(default="correct")
233
233
  """The name of the correct template which will be used to correct a string."""
234
234
 
235
+ co_validation_template: str = Field(default="co_validation")
236
+ """The name of the co-validation template which will be used to co-validate a string."""
237
+
238
+ as_prompt_template: str = Field(default="as_prompt")
239
+ """The name of the as prompt template which will be used to convert a string to a prompt."""
240
+
235
241
 
236
242
  class MagikaConfig(BaseModel):
237
243
  """Magika configuration class."""
@@ -272,9 +278,9 @@ class RagConfig(BaseModel):
272
278
 
273
279
  model_config = ConfigDict(use_attribute_docstrings=True)
274
280
 
275
- milvus_uri: HttpUrl = Field(default=HttpUrl("http://localhost:19530"))
281
+ milvus_uri: Optional[HttpUrl] = Field(default=HttpUrl("http://localhost:19530"))
276
282
  """The URI of the Milvus server."""
277
- milvus_timeout: Optional[PositiveFloat] = Field(default=None)
283
+ milvus_timeout: Optional[PositiveFloat] = Field(default=30.0)
278
284
  """The timeout of the Milvus server."""
279
285
  milvus_token: Optional[SecretStr] = Field(default=None)
280
286
  """The token of the Milvus server."""
@@ -300,11 +306,13 @@ class RoutingConfig(BaseModel):
300
306
 
301
307
  model_config = ConfigDict(use_attribute_docstrings=True)
302
308
 
303
- allowed_fails: Optional[int] = 1
309
+ max_parallel_requests: Optional[int] = 60
310
+ """The maximum number of parallel requests. None means not checked."""
311
+ allowed_fails: Optional[int] = 3
304
312
  """The number of allowed fails before the routing is considered failed."""
305
313
  retry_after: int = 15
306
314
  """The time in seconds to wait before retrying the routing after a fail."""
307
- cooldown_time: Optional[int] = 120
315
+ cooldown_time: Optional[int] = 30
308
316
  """The time in seconds to wait before retrying the routing after a cooldown."""
309
317
 
310
318
 
fabricatio/decorators.py CHANGED
@@ -177,3 +177,35 @@ def use_temp_module[**P, R](modules: ModuleType | List[ModuleType]) -> Callable[
177
177
  return _wrapper
178
178
 
179
179
  return _decorator
180
+
181
+
182
+ def logging_exec_time[**P, R](func: Callable[P, R]) -> Callable[P, R]:
183
+ """Decorator to log the execution time of a function.
184
+
185
+ Args:
186
+ func (Callable): The function to be executed
187
+
188
+ Returns:
189
+ Callable: A decorator that wraps the function to log the execution time.
190
+ """
191
+ from time import time
192
+
193
+ if iscoroutinefunction(func):
194
+
195
+ @wraps(func)
196
+ async def _async_wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
197
+ start_time = time()
198
+ result = await func(*args, **kwargs)
199
+ logger.debug(f"Execution time of `{func.__name__}`: {time() - start_time:.2f} s")
200
+ return result
201
+
202
+ return _async_wrapper
203
+
204
+ @wraps(func)
205
+ def _wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
206
+ start_time = time()
207
+ result = func(*args, **kwargs)
208
+ logger.debug(f"Execution time of {func.__name__}: {(time() - start_time) * 1000:.2f} ms")
209
+ return result
210
+
211
+ return _wrapper