fabricatio 0.2.8.dev2__cp312-cp312-win_amd64.whl → 0.2.8.dev4__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 (37) hide show
  1. fabricatio/_rust.cp312-win_amd64.pyd +0 -0
  2. fabricatio/_rust.pyi +1 -1
  3. fabricatio/actions/article.py +112 -121
  4. fabricatio/actions/article_rag.py +55 -45
  5. fabricatio/actions/output.py +4 -3
  6. fabricatio/actions/rag.py +3 -3
  7. fabricatio/capabilities/censor.py +87 -0
  8. fabricatio/capabilities/check.py +194 -0
  9. fabricatio/capabilities/correct.py +142 -98
  10. fabricatio/capabilities/propose.py +20 -4
  11. fabricatio/capabilities/rag.py +3 -2
  12. fabricatio/capabilities/rating.py +67 -22
  13. fabricatio/capabilities/review.py +18 -187
  14. fabricatio/capabilities/task.py +8 -9
  15. fabricatio/config.py +11 -3
  16. fabricatio/models/action.py +8 -5
  17. fabricatio/models/adv_kwargs_types.py +25 -0
  18. fabricatio/models/extra/advanced_judge.py +10 -7
  19. fabricatio/models/extra/article_base.py +47 -27
  20. fabricatio/models/extra/article_essence.py +40 -209
  21. fabricatio/models/extra/article_main.py +3 -4
  22. fabricatio/models/extra/patches.py +7 -0
  23. fabricatio/models/extra/problem.py +153 -0
  24. fabricatio/models/extra/rule.py +21 -0
  25. fabricatio/models/generic.py +71 -37
  26. fabricatio/models/kwargs_types.py +23 -17
  27. fabricatio/models/role.py +4 -1
  28. fabricatio/models/usages.py +17 -20
  29. fabricatio/models/utils.py +0 -46
  30. fabricatio/parser.py +7 -8
  31. fabricatio/utils.py +54 -0
  32. {fabricatio-0.2.8.dev2.data → fabricatio-0.2.8.dev4.data}/scripts/tdown.exe +0 -0
  33. {fabricatio-0.2.8.dev2.dist-info → fabricatio-0.2.8.dev4.dist-info}/METADATA +2 -1
  34. fabricatio-0.2.8.dev4.dist-info/RECORD +56 -0
  35. fabricatio-0.2.8.dev2.dist-info/RECORD +0 -49
  36. {fabricatio-0.2.8.dev2.dist-info → fabricatio-0.2.8.dev4.dist-info}/WHEEL +0 -0
  37. {fabricatio-0.2.8.dev2.dist-info → fabricatio-0.2.8.dev4.dist-info}/licenses/LICENSE +0 -0
@@ -6,13 +6,15 @@ from pathlib import Path
6
6
  from typing import Any, Callable, Dict, Iterable, List, Optional, Self, Union, final, overload
7
7
 
8
8
  import orjson
9
+ import rtoml
9
10
  from fabricatio._rust import blake3_hash
10
11
  from fabricatio._rust_instances import TEMPLATE_MANAGER
11
12
  from fabricatio.config import configs
12
13
  from fabricatio.fs.readers import MAGIKA, safe_text_read
13
14
  from fabricatio.journal import logger
14
- from fabricatio.models.utils import ok
15
15
  from fabricatio.parser import JsonCapture
16
+ from fabricatio.utils import ok
17
+ from litellm.utils import token_counter
16
18
  from pydantic import (
17
19
  BaseModel,
18
20
  ConfigDict,
@@ -52,6 +54,11 @@ class Display(Base):
52
54
  """
53
55
  return self.model_dump_json()
54
56
 
57
+ @staticmethod
58
+ def seq_display(seq: Iterable["Display"], compact: bool = False) -> str:
59
+ """Display a sequence of Display objects in a formatted JSON string."""
60
+ return "\n".join(d.compact() if compact else d.display() for d in seq)
61
+
55
62
 
56
63
  class Named(Base):
57
64
  """Class that includes a name attribute."""
@@ -63,7 +70,7 @@ class Named(Base):
63
70
  class Described(Base):
64
71
  """Class that includes a description attribute."""
65
72
 
66
- description: str = Field(default="", frozen=True)
73
+ description: str = Field(frozen=True)
67
74
  """The description of the object."""
68
75
 
69
76
 
@@ -98,14 +105,28 @@ class WithRef[T](Base):
98
105
  self._reference, f"`{self.__class__.__name__}`' s `_reference` field is None. Have you called `update_ref`?"
99
106
  )
100
107
 
101
- def update_ref[S: "WithRef"](self: S, reference: T | S) -> S: # noqa: PYI019
108
+ @overload
109
+ def update_ref[S: WithRef](self: S, reference: T) -> S: ...
110
+
111
+ @overload
112
+ def update_ref[S: WithRef](self: S, reference: "WithRef[T]") -> S: ...
113
+
114
+ @overload
115
+ def update_ref[S: WithRef](self: S, reference: None = None) -> S: ...
116
+ def update_ref[S: WithRef](self: S, reference: Union[T, "WithRef[T]", None] = None) -> S: # noqa: PYI019
102
117
  """Update the reference of the object."""
103
118
  if isinstance(reference, self.__class__):
104
119
  self._reference = reference.referenced
105
120
  else:
106
- self._reference = reference
121
+ self._reference = reference # pyright: ignore [reportAttributeAccessIssue]
107
122
  return self
108
123
 
124
+ def derive[S: WithRef](self: S, reference: Any) -> S: # noqa: PYI019
125
+ """Derive a new object from the current object."""
126
+ new = self.model_copy()
127
+ new._reference = reference
128
+ return new
129
+
109
130
 
110
131
  class PersistentAble(Base):
111
132
  """Class that provides a method to persist the object."""
@@ -120,10 +141,10 @@ class PersistentAble(Base):
120
141
  Self: The current instance of the object.
121
142
  """
122
143
  p = Path(path)
123
- out = self.model_dump_json(indent=1)
144
+ out = self.model_dump_json()
124
145
 
125
146
  # Generate a timestamp in the format YYYYMMDD_HHMMSS
126
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
147
+ timestamp = datetime.now().strftime("%Y%m%d")
127
148
 
128
149
  # Generate the hash
129
150
  file_hash = blake3_hash(out.encode())[:6]
@@ -150,7 +171,7 @@ class PersistentAble(Base):
150
171
  Returns:
151
172
  Self: The current instance of the object.
152
173
  """
153
- return cls.model_validate_json(Path(path).read_text(encoding="utf-8"))
174
+ return cls.model_validate_json(safe_text_read(path))
154
175
 
155
176
 
156
177
  class ModelHash(Base):
@@ -220,27 +241,6 @@ class WithBriefing(Named, Described):
220
241
  """
221
242
  return f"{self.name}: {self.description}" if self.description else self.name
222
243
 
223
- def _prepend_inner(self, input_text: str) -> str:
224
- return f"# your personal briefing: \n{self.briefing}\n{input_text}"
225
-
226
- def prepend_sys_msg[D: (Dict[str, Any], str)](self, system_msg_like: D = "") -> Dict[str, Any]:
227
- """Prepend the system message with the briefing.
228
-
229
- Args:
230
- system_msg_like (str | dict): The system message or a dictionary containing the system message.
231
-
232
- Returns:
233
- dict: The system message with the briefing prepended.
234
- """
235
- match system_msg_like:
236
- case dict(d):
237
- d["system_message"] = self._prepend_inner(d.get("system_message", ""))
238
- return d
239
- case str(s):
240
- return {"system_message": self._prepend_inner(s)}
241
- case _:
242
- raise TypeError(f"{system_msg_like} is not a dict or str")
243
-
244
244
 
245
245
  class UnsortGenerate(GenerateJsonSchema):
246
246
  """Class that provides a reverse JSON schema of the model."""
@@ -314,14 +314,20 @@ class InstantiateFromString(Base):
314
314
  Returns:
315
315
  Self | None: The instance of the class or None if the string is not valid.
316
316
  """
317
- return JsonCapture.convert_with(string, cls.model_validate_json)
317
+ obj = JsonCapture.convert_with(string, cls.model_validate_json)
318
+ logger.debug(f"Instantiate `{cls.__name__}` from string, {'Failed' if obj is None else 'Success'}.")
319
+ return obj
318
320
 
319
321
 
320
322
  class ProposedAble(CreateJsonObjPrompt, InstantiateFromString):
321
323
  """Class that provides a method to propose a JSON object based on the requirement."""
322
324
 
323
325
 
324
- class ProposedUpdateAble(ProposedAble, UpdateFrom, ABC):
326
+ class SketchedAble(ProposedAble, Display):
327
+ """Class that provides a method to scratch the object."""
328
+
329
+
330
+ class ProposedUpdateAble(SketchedAble, UpdateFrom, ABC):
325
331
  """Make the obj can be updated from the proposed obj in place."""
326
332
 
327
333
 
@@ -349,8 +355,6 @@ class FinalizedDumpAble(Base):
349
355
  return self
350
356
 
351
357
 
352
- class CensoredAble(ProposedAble, FinalizedDumpAble):
353
- """Class that provides a method to censor the object."""
354
358
 
355
359
 
356
360
  class WithDependency(Base):
@@ -441,13 +445,13 @@ class WithDependency(Base):
441
445
  )
442
446
 
443
447
 
444
- class PrepareVectorization(Base):
448
+ class Vectorizable(Base):
445
449
  """Class that prepares the vectorization of the model."""
446
450
 
447
- @abstractmethod
448
451
  def _prepare_vectorization_inner(self) -> str:
449
- """Prepare the vectorization of the model."""
452
+ return rtoml.dumps(self.model_dump())
450
453
 
454
+ @final
451
455
  def prepare_vectorization(self, max_length: Optional[int] = None) -> str:
452
456
  """Prepare the vectorization of the model.
453
457
 
@@ -456,8 +460,8 @@ class PrepareVectorization(Base):
456
460
  """
457
461
  max_length = max_length or configs.embedding.max_sequence_length
458
462
  chunk = self._prepare_vectorization_inner()
459
- if max_length and len(chunk) > max_length:
460
- logger.error(err := f"Chunk exceeds maximum sequence length {max_length}.")
463
+ if max_length and (length := token_counter(text=chunk)) > max_length:
464
+ logger.error(err := f"Chunk exceeds maximum sequence length {max_length}, got {length},see {chunk}")
461
465
  raise ValueError(err)
462
466
 
463
467
  return chunk
@@ -572,3 +576,33 @@ class ScopedConfig(Base):
572
576
  if (attr := getattr(self, attr_name)) is not None and getattr(other, attr_name) is None:
573
577
  setattr(other, attr_name, attr)
574
578
  return self
579
+
580
+
581
+ class Patch[T](ProposedAble):
582
+ """Base class for patches."""
583
+
584
+ def apply(self, other: T) -> T:
585
+ """Apply the patch to another instance."""
586
+ for field in self.__class__.model_fields:
587
+ if not hasattr(other, field):
588
+ raise ValueError(f"{field} not found in {other}, are you applying to the wrong type?")
589
+ setattr(other, field, getattr(self, field))
590
+ return other
591
+
592
+
593
+ class SequencePatch[T](ProposedUpdateAble):
594
+ """Base class for patches."""
595
+
596
+ tweaked: List[T]
597
+ """Tweaked content list"""
598
+
599
+ def update_from_inner(self, other: Self) -> Self:
600
+ """Updates the current instance with the attributes of another instance."""
601
+ self.tweaked.clear()
602
+ self.tweaked.extend(other.tweaked)
603
+ return self
604
+
605
+ @classmethod
606
+ def default(cls) -> Self:
607
+ """Defaults to empty list."""
608
+ return cls(tweaked=[])
@@ -1,7 +1,7 @@
1
1
  """This module contains the types for the keyword arguments of the methods in the models module."""
2
2
 
3
3
  from importlib.util import find_spec
4
- from typing import Any, Dict, Required, TypedDict
4
+ from typing import Any, Dict, List, Optional, Required, TypedDict
5
5
 
6
6
  from litellm.caching.caching import CacheMode
7
7
  from litellm.types.caching import CachingSupportedCallTypes
@@ -95,11 +95,30 @@ class ValidateKwargs[T](GenerateKwargs, total=False):
95
95
  such as limiting the number of validation attempts.
96
96
  """
97
97
 
98
- default: T
98
+ default: Optional[T]
99
99
  max_validations: int
100
100
  co_extractor: GenerateKwargs
101
101
 
102
102
 
103
+ class CompositeScoreKwargs(ValidateKwargs[List[Dict[str, float]]], total=False):
104
+ """Arguments for composite score generation operations.
105
+
106
+ Extends GenerateKwargs with parameters for generating composite scores
107
+ based on specific criteria and weights.
108
+ """
109
+
110
+ topic: str
111
+ criteria: set[str]
112
+ weights: Dict[str, float]
113
+ manual: Dict[str, str]
114
+
115
+
116
+ class BestKwargs(CompositeScoreKwargs, total=False):
117
+ """Arguments for choose top-k operations."""
118
+
119
+ k: int
120
+
121
+
103
122
  class ReviewInnerKwargs[T](ValidateKwargs[T], total=False):
104
123
  """Arguments for content review operations."""
105
124
 
@@ -118,22 +137,9 @@ class ReviewKwargs[T](ReviewInnerKwargs[T], total=False):
118
137
  topic: Required[str]
119
138
 
120
139
 
121
- class CorrectKwargs[T](ReviewKwargs[T], total=False):
122
- """Arguments for content correction operations.
123
-
124
- Extends GenerateKwargs with parameters for correcting content based on
125
- specific criteria and templates.
126
- """
127
-
128
- reference: str
129
- supervisor_check: bool
130
-
131
-
132
- class CensoredCorrectKwargs[T](ReviewInnerKwargs[T], total=False):
133
- """Arguments for content censorship operations."""
134
-
140
+ class ReferencedKwargs[T](ValidateKwargs[T], total=False):
141
+ """Arguments for content review operations."""
135
142
  reference: str
136
- supervisor_check: bool
137
143
 
138
144
 
139
145
  # noinspection PyTypedDict
fabricatio/models/role.py CHANGED
@@ -8,11 +8,12 @@ from fabricatio.core import env
8
8
  from fabricatio.journal import logger
9
9
  from fabricatio.models.action import WorkFlow
10
10
  from fabricatio.models.events import Event
11
+ from fabricatio.models.generic import WithBriefing
11
12
  from fabricatio.models.tool import ToolBox
12
13
  from pydantic import Field
13
14
 
14
15
 
15
- class Role(ProposeTask, HandleTask, Correct):
16
+ class Role(WithBriefing, ProposeTask, HandleTask, Correct):
16
17
  """Class that represents a role with a registry of events and workflows.
17
18
 
18
19
  A Role serves as a container for workflows, managing their registration to events
@@ -22,6 +23,8 @@ class Role(ProposeTask, HandleTask, Correct):
22
23
  registry: Mapping of events to workflows that handle them
23
24
  toolboxes: Set of toolboxes available to this role and its workflows
24
25
  """
26
+ description:str =""
27
+ """A brief description of the role's responsibilities and capabilities."""
25
28
 
26
29
  registry: dict[Event | str, WorkFlow] = Field(default_factory=dict)
27
30
  """The registry of events and workflows."""
@@ -2,7 +2,7 @@
2
2
 
3
3
  import traceback
4
4
  from asyncio import gather
5
- from typing import Callable, Dict, Iterable, List, Optional, Self, Sequence, Set, Type, Union, Unpack, overload
5
+ from typing import Callable, Dict, Iterable, List, Optional, Self, Sequence, Set, Union, Unpack, overload
6
6
 
7
7
  import asyncstdlib
8
8
  import litellm
@@ -14,8 +14,9 @@ from fabricatio.models.generic import ScopedConfig, WithBriefing
14
14
  from fabricatio.models.kwargs_types import ChooseKwargs, EmbeddingKwargs, GenerateKwargs, LLMKwargs, ValidateKwargs
15
15
  from fabricatio.models.task import Task
16
16
  from fabricatio.models.tool import Tool, ToolBox
17
- from fabricatio.models.utils import Messages, ok
17
+ from fabricatio.models.utils import Messages
18
18
  from fabricatio.parser import GenericCapture, JsonCapture
19
+ from fabricatio.utils import ok
19
20
  from litellm import RateLimitError, Router, stream_chunk_builder # pyright: ignore [reportPrivateImportUsage]
20
21
  from litellm.types.router import Deployment, LiteLLM_Params, ModelInfo
21
22
  from litellm.types.utils import (
@@ -52,10 +53,6 @@ class LLMUsage(ScopedConfig):
52
53
  self._added_deployment = ROUTER.upsert_deployment(deployment)
53
54
  return ROUTER
54
55
 
55
- @classmethod
56
- def _scoped_model(cls) -> Type["LLMUsage"]:
57
- return LLMUsage
58
-
59
56
  # noinspection PyTypeChecker,PydanticTypeChecker
60
57
  async def aquery(
61
58
  self,
@@ -280,7 +277,7 @@ class LLMUsage(ScopedConfig):
280
277
  question: str | List[str],
281
278
  validator: Callable[[str], T | None],
282
279
  default: Optional[T] = None,
283
- max_validations: PositiveInt = 2,
280
+ max_validations: PositiveInt = 3,
284
281
  co_extractor: Optional[GenerateKwargs] = None,
285
282
  **kwargs: Unpack[GenerateKwargs],
286
283
  ) -> Optional[T] | List[Optional[T]] | List[T] | T:
@@ -302,12 +299,11 @@ class LLMUsage(ScopedConfig):
302
299
  async def _inner(q: str) -> Optional[T]:
303
300
  for lap in range(max_validations):
304
301
  try:
305
- if (
306
- (response := await self.aask(question=q, **kwargs))
307
- or (
308
- co_extractor
309
- and (
310
- response := await self.aask(
302
+ if ((validated := validator(response := await self.aask(question=q, **kwargs))) is not None) or (
303
+ co_extractor
304
+ and (
305
+ validated := validator(
306
+ await self.aask(
311
307
  question=(
312
308
  TEMPLATE_MANAGER.render_template(
313
309
  configs.templates.co_validation_template,
@@ -318,7 +314,8 @@ class LLMUsage(ScopedConfig):
318
314
  )
319
315
  )
320
316
  )
321
- ) and (validated := validator(response)):
317
+ is not None
318
+ ):
322
319
  logger.debug(f"Successfully validated the response at {lap}th attempt.")
323
320
  return validated
324
321
 
@@ -338,7 +335,7 @@ class LLMUsage(ScopedConfig):
338
335
 
339
336
  return await (gather(*[_inner(q) for q in question]) if isinstance(question, list) else _inner(question))
340
337
 
341
- async def aliststr(
338
+ async def alist_str(
342
339
  self, requirement: str, k: NonNegativeInt = 0, **kwargs: Unpack[ValidateKwargs[List[str]]]
343
340
  ) -> Optional[List[str]]:
344
341
  """Asynchronously generates a list of strings based on a given requirement.
@@ -370,7 +367,7 @@ class LLMUsage(ScopedConfig):
370
367
  Returns:
371
368
  List[str]: The validated response as a list of strings.
372
369
  """
373
- return await self.aliststr(
370
+ return await self.alist_str(
374
371
  TEMPLATE_MANAGER.render_template(
375
372
  configs.templates.pathstr_template,
376
373
  {"requirement": requirement},
@@ -550,8 +547,8 @@ class EmbeddingUsage(LLMUsage):
550
547
  """
551
548
  # check seq length
552
549
  max_len = self.embedding_max_sequence_length or configs.embedding.max_sequence_length
553
- if max_len and any(len(t) > max_len for t in input_text):
554
- logger.error(err := f"Input text exceeds maximum sequence length {max_len}.")
550
+ if max_len and any(length := (token_counter(text=t)) > max_len for t in input_text):
551
+ logger.error(err := f"Input text exceeds maximum sequence length {max_len}, got {length}.")
555
552
  raise ValueError(err)
556
553
 
557
554
  return await litellm.aembedding(
@@ -712,7 +709,7 @@ class ToolBoxUsage(LLMUsage):
712
709
  """
713
710
  if isinstance(others, ToolBoxUsage):
714
711
  others = [others]
715
- for other in others:
712
+ for other in (x for x in others if isinstance(x, ToolBoxUsage)):
716
713
  self.toolboxes.update(other.toolboxes)
717
714
  return self
718
715
 
@@ -728,6 +725,6 @@ class ToolBoxUsage(LLMUsage):
728
725
  """
729
726
  if isinstance(others, ToolBoxUsage):
730
727
  others = [others]
731
- for other in others:
728
+ for other in (x for x in others if isinstance(x, ToolBoxUsage)):
732
729
  other.toolboxes.update(self.toolboxes)
733
730
  return self
@@ -4,7 +4,6 @@ from enum import Enum
4
4
  from typing import Any, Dict, List, Literal, Optional, Self
5
5
 
6
6
  from pydantic import BaseModel, ConfigDict, Field
7
- from questionary import text
8
7
 
9
8
 
10
9
  class Message(BaseModel):
@@ -147,48 +146,3 @@ class TaskStatus(Enum):
147
146
  Cancelled = "cancelled"
148
147
 
149
148
 
150
- async def ask_edit(
151
- text_seq: List[str],
152
- ) -> List[str]:
153
- """Asks the user to edit a list of texts.
154
-
155
- Args:
156
- text_seq (List[str]): A list of texts to be edited.
157
-
158
- Returns:
159
- List[str]: A list of edited texts.
160
- If the user does not edit a text, it will not be included in the returned list.
161
- """
162
- res = []
163
- for i, t in enumerate(text_seq):
164
- edited = await text(f"[{i}] ", default=t).ask_async()
165
- if edited:
166
- res.append(edited)
167
- return res
168
-
169
-
170
- def override_kwargs[T](kwargs: Dict[str, T], **overrides) -> Dict[str, T]:
171
- """Override the values in kwargs with the provided overrides."""
172
- kwargs.update({k: v for k, v in overrides.items() if v is not None})
173
- return kwargs
174
-
175
-
176
- def fallback_kwargs[T](kwargs: Dict[str, T], **overrides) -> Dict[str, T]:
177
- """Fallback the values in kwargs with the provided overrides."""
178
- kwargs.update({k: v for k, v in overrides.items() if k not in kwargs})
179
- return kwargs
180
-
181
-
182
- def ok[T](val: Optional[T], msg: str = "Value is None") -> T:
183
- """Check if a value is None and raise a ValueError with the provided message if it is.
184
-
185
- Args:
186
- val: The value to check.
187
- msg: The message to include in the ValueError if val is None.
188
-
189
- Returns:
190
- T: The value if it is not None.
191
- """
192
- if val is None:
193
- raise ValueError(msg)
194
- return val
fabricatio/parser.py CHANGED
@@ -45,14 +45,14 @@ class Capture(BaseModel):
45
45
  str | List[str]: The fixed text with the same type as input.
46
46
  """
47
47
  match self.capture_type:
48
- case "json":
48
+ case "json" if configs.general.use_json_repair:
49
+ logger.debug("Applying json repair to text.")
49
50
  if isinstance(text, str):
50
51
  return repair_json(text, ensure_ascii=False)
51
52
  return [repair_json(item, ensure_ascii=False) for item in text]
52
53
  case _:
53
54
  return text
54
55
 
55
-
56
56
  def capture(self, text: str) -> Tuple[str, ...] | str | None:
57
57
  """Capture the first occurrence of the pattern in the given text.
58
58
 
@@ -63,11 +63,10 @@ class Capture(BaseModel):
63
63
  str | None: The captured text if the pattern is found, otherwise None.
64
64
 
65
65
  """
66
- match = self._compiled.search(text)
67
- if match is None:
68
- logger.debug(f"Capture Failed: \n{text}")
66
+ if (match :=self._compiled.match(text) or self._compiled.search(text) ) is None:
67
+ logger.debug(f"Capture Failed {type(text)}: \n{text}")
69
68
  return None
70
- groups = self.fix(match.groups()) if configs.general.use_json_repair else match.groups()
69
+ groups = self.fix(match.groups())
71
70
  if self.target_groups:
72
71
  cap = tuple(groups[g - 1] for g in self.target_groups)
73
72
  logger.debug(f"Captured text: {'\n\n'.join(cap)}")
@@ -134,7 +133,7 @@ class Capture(BaseModel):
134
133
  Returns:
135
134
  Self: The instance of the class with the captured code block.
136
135
  """
137
- return cls(pattern=f"```{language}\n(.*?)\n```", capture_type=language)
136
+ return cls(pattern=f"```{language}(.*?)```", capture_type=language)
138
137
 
139
138
  @classmethod
140
139
  def capture_generic_block(cls, language: str) -> Self:
@@ -143,7 +142,7 @@ class Capture(BaseModel):
143
142
  Returns:
144
143
  Self: The instance of the class with the captured code block.
145
144
  """
146
- return cls(pattern=f"--- Start of {language} ---\n(.*?)\n--- end of {language} ---", capture_type=language)
145
+ return cls(pattern=f"--- Start of {language} ---(.*?)--- end of {language} ---", capture_type=language)
147
146
 
148
147
 
149
148
  JsonCapture = Capture.capture_code_block("json")
fabricatio/utils.py ADDED
@@ -0,0 +1,54 @@
1
+ """A collection of utility functions for the fabricatio package."""
2
+
3
+ from typing import Any, Dict, List, Optional
4
+
5
+ from questionary import text
6
+
7
+
8
+ async def ask_edit(
9
+ text_seq: List[str],
10
+ ) -> List[str]:
11
+ """Asks the user to edit a list of texts.
12
+
13
+ Args:
14
+ text_seq (List[str]): A list of texts to be edited.
15
+
16
+ Returns:
17
+ List[str]: A list of edited texts.
18
+ If the user does not edit a text, it will not be included in the returned list.
19
+ """
20
+ res = []
21
+ for i, t in enumerate(text_seq):
22
+ edited = await text(f"[{i}] ", default=t).ask_async()
23
+ if edited:
24
+ res.append(edited)
25
+ return res
26
+
27
+
28
+ def override_kwargs(kwargs: Dict[str,Any], **overrides) -> Dict[str, Any]:
29
+ """Override the values in kwargs with the provided overrides."""
30
+ new_kwargs = kwargs.copy()
31
+ new_kwargs.update({k: v for k, v in overrides.items() if v is not None})
32
+ return new_kwargs
33
+
34
+
35
+ def fallback_kwargs(kwargs: Dict[str, Any], **overrides) -> Dict[str, Any]:
36
+ """Fallback the values in kwargs with the provided overrides."""
37
+ new_kwargs = kwargs.copy()
38
+ new_kwargs.update({k: v for k, v in overrides.items() if k not in new_kwargs and v is not None})
39
+ return new_kwargs
40
+
41
+
42
+ def ok[T](val: Optional[T], msg: str = "Value is None") -> T:
43
+ """Check if a value is None and raise a ValueError with the provided message if it is.
44
+
45
+ Args:
46
+ val: The value to check.
47
+ msg: The message to include in the ValueError if val is None.
48
+
49
+ Returns:
50
+ T: The value if it is not None.
51
+ """
52
+ if val is None:
53
+ raise ValueError(msg)
54
+ return val
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fabricatio
3
- Version: 0.2.8.dev2
3
+ Version: 0.2.8.dev4
4
4
  Classifier: License :: OSI Approved :: MIT License
5
5
  Classifier: Programming Language :: Rust
6
6
  Classifier: Programming Language :: Python :: 3.12
@@ -23,6 +23,7 @@ Requires-Dist: pymitter>=1.0.0
23
23
  Requires-Dist: questionary>=2.1.0
24
24
  Requires-Dist: regex>=2024.11.6
25
25
  Requires-Dist: rich>=13.9.4
26
+ Requires-Dist: rtoml>=0.12.0
26
27
  Requires-Dist: pymilvus>=2.5.4 ; extra == 'rag'
27
28
  Requires-Dist: fabricatio[calc,plot,rag] ; extra == 'full'
28
29
  Requires-Dist: sympy>=1.13.3 ; extra == 'calc'
@@ -0,0 +1,56 @@
1
+ fabricatio-0.2.8.dev4.dist-info/METADATA,sha256=m8008QWQ2qtSzryx4jr2DpTqfNQDyhBUscJQgQzmM0I,5288
2
+ fabricatio-0.2.8.dev4.dist-info/WHEEL,sha256=jABKVkLC9kJr8mi_er5jOqpiQUjARSLXDUIIxDqsS50,96
3
+ fabricatio-0.2.8.dev4.dist-info/licenses/LICENSE,sha256=do7J7EiCGbq0QPbMAL_FqLYufXpHnCnXBOuqVPwSV8Y,1088
4
+ fabricatio/actions/article.py,sha256=i5-u5tCiJd7b_lQ4_vHjV57ZXDoUIAHmgD9QFoFaTuM,12787
5
+ fabricatio/actions/article_rag.py,sha256=dkfskNqntVPi81Xm_NFdTQM8v2nR9FJIexzkK9rg-NU,4352
6
+ fabricatio/actions/output.py,sha256=-FfTzXEHIb_zOT-j4T4b5ND96zHLDEGdjlmmPviIbiM,3754
7
+ fabricatio/actions/rag.py,sha256=wb3vt-gS6fDHYJ57Yfu_OR0kpewT9vMqwtXsqXd42Kg,2735
8
+ fabricatio/capabilities/advanced_judge.py,sha256=selB0Gwf1F4gGJlwBiRo6gI4KOUROgh3WnzO3mZFEls,706
9
+ fabricatio/capabilities/censor.py,sha256=-FZTDFfqlIwqMd4hkKzEHAknlp2pH5sawXDQ-7XJcXA,3784
10
+ fabricatio/capabilities/check.py,sha256=_4FS0kTa37A3M8Cjl1oVxp1j971W5O58NxmtsU1TizA,8005
11
+ fabricatio/capabilities/correct.py,sha256=8ax8oa9e4EIzho-cTXku-Sy7rC1zrOdlo23ooDZEyuM,9178
12
+ fabricatio/capabilities/propose.py,sha256=hkBeSlmcTdfYWT-ph6nlbtHXBozi_JXqXlWcnBy3W78,2007
13
+ fabricatio/capabilities/rag.py,sha256=7xDxDEvhlmb7Y-mEquSgvlVIYpHsM2YFxA9LjRpVajo,17720
14
+ fabricatio/capabilities/rating.py,sha256=3gBqmYpEpzKge4mpxclJ4f9Nl_MTnADjuj4uqxw2Ilo,17011
15
+ fabricatio/capabilities/review.py,sha256=1MGyJudPxHVOQod_GYKJ7NyB3jOWuwZhqBP30hAZ5Z4,5061
16
+ fabricatio/capabilities/task.py,sha256=JG9kD2n86FvZQIjqZq-aqw8j9jpuuDpEDKTJCB6HzX4,4416
17
+ fabricatio/config.py,sha256=aA-wirVVfjRuk1AXj-l9UFQFaDEBtV3YnzQIwCPE_G0,17503
18
+ fabricatio/core.py,sha256=VQ_JKgUGIy2gZ8xsTBZCdr_IP7wC5aPg0_bsOmjQ588,6458
19
+ fabricatio/decorators.py,sha256=C0Gi7wcXC-0sWITqsSv3JdBGcgVJOlRvOt0FfO0aUsA,7554
20
+ fabricatio/fs/curd.py,sha256=p8y0LGKgVDk-CWOlm37E6wg7RK6RCD6denKo-VsW28c,4763
21
+ fabricatio/fs/readers.py,sha256=EZKN_AZdrp8DggJECP53QHw3uHeSDf-AwCAA_V7fNKU,1202
22
+ fabricatio/fs/__init__.py,sha256=PCf0s_9KDjVfNw7AfPoJzGt3jMq4gJOfbcT4pb0D0ZY,588
23
+ fabricatio/journal.py,sha256=stnEP88aUBA_GmU9gfTF2EZI8FS2OyMLGaMSTgK4QgA,476
24
+ fabricatio/models/action.py,sha256=dZkPP-7DaJIOjsFYWnp6vcOObMgjvda1O2FjboSDYjo,9003
25
+ fabricatio/models/adv_kwargs_types.py,sha256=dcYMLn6xcnWLZTLTBdtpgUZWi-VBeub721GzHRZFT1g,860
26
+ fabricatio/models/events.py,sha256=QvlnS8FEELg6KNabcJMeh2GV_y0ZBzKOPphcteKYWYU,4183
27
+ fabricatio/models/extra/advanced_judge.py,sha256=mi3KiB8FUuSYICzXPXKwVhCyRE1GL3gHLkwuc-4mh3c,999
28
+ fabricatio/models/extra/article_base.py,sha256=1Fg3iWbod1TCU3nIJK9mOq_8K3oGBtSW03VUwi2I5tg,17058
29
+ fabricatio/models/extra/article_essence.py,sha256=xd6j-PDqjhrMjgUmyfk6HqkyMLu-sS9feUo0sZ3QABY,2825
30
+ fabricatio/models/extra/article_main.py,sha256=0Xj54pRxUw5Iaj9npYmHKT-ZMvEIBlZ6G1ysNJRgceM,8225
31
+ fabricatio/models/extra/article_outline.py,sha256=jFbVgiwlo7rnwCGS6ToVgeMUOoRe99Edgbx95THR6z8,1450
32
+ fabricatio/models/extra/article_proposal.py,sha256=L2kPvH1XCCQSNcI1KQU3ULGq7C24Y88ssugX43LgbsE,2043
33
+ fabricatio/models/extra/patches.py,sha256=_yyyDbaQ8wkj6QP-NU-3I74HehFgwD889vD0SlCjynU,303
34
+ fabricatio/models/extra/problem.py,sha256=KwYkc7kjoEG7cwj9C8sWLoZgtBqJVuxlU_7KkvtSgO0,5828
35
+ fabricatio/models/extra/rule.py,sha256=_ThlHOViuHcJdAhc6qdEUHaFOevvQYHvH89STzucUyM,719
36
+ fabricatio/models/generic.py,sha256=uuCwpG4DS5DwnZ-2lRMBDufWbKp_5x4yuh1eAFwkFKY,20682
37
+ fabricatio/models/kwargs_types.py,sha256=sMDA85SoC1AOJ5k6qC8qUiUv0Ne0_5ThU9FZITRNen4,5673
38
+ fabricatio/models/role.py,sha256=-CRcj5_M3_ciLPzwiNn92grBmwoSLQ-n4koVZiCNTBM,2953
39
+ fabricatio/models/task.py,sha256=8NaR7ojQWyM740EDTqt9stwHKdrD6axCRpLKo0QzS-I,10492
40
+ fabricatio/models/tool.py,sha256=kD0eB7OxO9geZOxO6JIKvCBeG-KOpRAkfRZqK_WGfW4,7105
41
+ fabricatio/models/usages.py,sha256=UC-igtnfW0scIkedb5leZuuR4XoSZYI7kf1S0L418CU,31813
42
+ fabricatio/models/utils.py,sha256=Ac5g-8ic6q_w7dhNuh-iiofpL1sqOACxbjPPTljP2LY,4417
43
+ fabricatio/parser.py,sha256=UOSvXigEXK-eXsr3m3b7glOhbBWs4kDJTeTNyuqA9ic,6315
44
+ fabricatio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
+ fabricatio/toolboxes/arithmetic.py,sha256=WLqhY-Pikv11Y_0SGajwZx3WhsLNpHKf9drzAqOf_nY,1369
46
+ fabricatio/toolboxes/fs.py,sha256=l4L1CVxJmjw9Ld2XUpIlWfV0_Fu_2Og6d3E13I-S4aE,736
47
+ fabricatio/toolboxes/__init__.py,sha256=KBJi5OG_pExscdlM7Bnt_UF43j4I3Lv6G71kPVu4KQU,395
48
+ fabricatio/utils.py,sha256=QJR00IuclL2nNTSfpTNBRYJmNjc_DNXGtrYWjatWpq8,1681
49
+ fabricatio/workflows/articles.py,sha256=G5HGRr-DHuYuEcfhFdFAuDvTTJ9aSU_UQ2yYXEjTMtM,1047
50
+ fabricatio/workflows/rag.py,sha256=-YYp2tlE9Vtfgpg6ROpu6QVO8j8yVSPa6yDzlN3qVxs,520
51
+ fabricatio/_rust.pyi,sha256=_N8Jw1DMOFAaoibSQolxkKZ07nCfJao7Z9qkojHtLy0,5104
52
+ fabricatio/_rust_instances.py,sha256=2GwF8aVfYNemRI2feBzH1CZfBGno-XJJE5imJokGEYw,314
53
+ fabricatio/__init__.py,sha256=SzBYsRhZeL77jLtfJEjmoHOSwHwUGyvMATX6xfndLDM,1135
54
+ fabricatio/_rust.cp312-win_amd64.pyd,sha256=y_AwUxK1t-eJJnlDm9MowMbM8s_GzUXAPX5W9Ao_06U,1892352
55
+ fabricatio-0.2.8.dev4.data/scripts/tdown.exe,sha256=OKVp-_Q3lDufrVIc_ZmFJRKukM6TGqWnMMs0YOXULQE,3402240
56
+ fabricatio-0.2.8.dev4.dist-info/RECORD,,