fabricatio 0.2.9.dev4__cp312-cp312-win_amd64.whl → 0.2.10.dev0__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.
@@ -12,7 +12,7 @@ class JudgeMent(SketchedAble):
12
12
  """
13
13
 
14
14
  issue_to_judge: str
15
- """The issue to be judged, true for affirmation, false for denial."""
15
+ """The issue to be judged, including the original question and context"""
16
16
 
17
17
  deny_evidence: List[str]
18
18
  """List of clues supporting the denial."""
@@ -21,7 +21,7 @@ class JudgeMent(SketchedAble):
21
21
  """List of clues supporting the affirmation."""
22
22
 
23
23
  final_judgement: bool
24
- """The final judgment made according to all extracted clues."""
24
+ """The final judgment made according to all extracted clues. true for the `issue_to_judge` is correct and false for incorrect."""
25
25
 
26
26
  def __bool__(self) -> bool:
27
27
  """Return the final judgment value.
@@ -2,8 +2,7 @@
2
2
 
3
3
  from abc import ABC, abstractmethod
4
4
  from enum import StrEnum
5
- from itertools import chain
6
- from typing import Generator, List, Optional, Self, Tuple, overload
5
+ from typing import Generator, List, Optional, Self, Tuple
7
6
 
8
7
  from fabricatio.models.generic import (
9
8
  AsPrompt,
@@ -15,7 +14,6 @@ from fabricatio.models.generic import (
15
14
  PersistentAble,
16
15
  ProposedUpdateAble,
17
16
  ResolveUpdateConflict,
18
- SequencePatch,
19
17
  SketchedAble,
20
18
  Titled,
21
19
  WordCount,
@@ -31,81 +29,9 @@ class ReferringType(StrEnum):
31
29
  SUBSECTION = "subsection"
32
30
 
33
31
 
34
- type RefKey = Tuple[str, Optional[str], Optional[str]]
35
-
36
-
37
- class ArticleRef(ProposedUpdateAble):
38
- """Reference to a specific chapter, section or subsection within the article. You SHALL not refer to an article component that is external and not present within our own article.
39
-
40
- Examples:
41
- - Referring to a chapter titled `Introduction`:
42
- Using Python
43
- ```python
44
- ArticleRef(chap="Introduction")
45
- ```
46
- Using JSON
47
- ```json
48
- {chap="Introduction"}
49
- ```
50
- - Referring to a section titled `Background` under the `Introduction` chapter:
51
- Using Python
52
- ```python
53
- ArticleRef(chap="Introduction", sec="Background")
54
- ```
55
- Using JSON
56
- ```json
57
- {chap="Introduction", sec="Background"}
58
- ```
59
- - Referring to a subsection titled `Related Work` under the `Background` section of the `Introduction` chapter:
60
- Using Python
61
- ```python
62
- ArticleRef(chap="Introduction", sec="Background", subsec="Related Work")
63
- ```
64
- Using JSON
65
- ```json
66
- {chap="Introduction", sec="Background", subsec="Related Work"}
67
- ```
68
- """
69
-
70
- chap: str
71
- """`title` Field of the referenced chapter"""
72
- sec: Optional[str] = None
73
- """`title` Field of the referenced section."""
74
- subsec: Optional[str] = None
75
- """`title` Field of the referenced subsection."""
76
-
77
- def update_from_inner(self, other: Self) -> Self:
78
- """Updates the current instance with the attributes of another instance."""
79
- self.chap = other.chap
80
- self.sec = other.sec
81
- self.subsec = other.subsec
82
- return self
83
-
84
- def deref(self, article: "ArticleBase") -> Optional["ArticleOutlineBase"]:
85
- """Dereference the reference to the actual section or subsection within the provided article.
86
-
87
- Args:
88
- article (ArticleOutline | Article): The article to dereference the reference from.
89
32
 
90
- Returns:
91
- ArticleMainBase | ArticleOutline | None: The dereferenced section or subsection, or None if not found.
92
- """
93
- chap = next((chap for chap in article.chapters if chap.title == self.chap), None)
94
- if self.sec is None or chap is None:
95
- return chap
96
- sec = next((sec for sec in chap.sections if sec.title == self.sec), None)
97
- if self.subsec is None or sec is None:
98
- return sec
99
- return next((subsec for subsec in sec.subsections if subsec.title == self.subsec), None)
33
+ type RefKey = Tuple[str, Optional[str], Optional[str]]
100
34
 
101
- @property
102
- def referring_type(self) -> ReferringType:
103
- """Determine the type of reference based on the presence of specific attributes."""
104
- if self.subsec is not None:
105
- return ReferringType.SUBSECTION
106
- if self.sec is not None:
107
- return ReferringType.SECTION
108
- return ReferringType.CHAPTER
109
35
 
110
36
 
111
37
  class ArticleMetaData(SketchedAble, Described, WordCount, Titled, Language):
@@ -121,15 +47,8 @@ class ArticleMetaData(SketchedAble, Described, WordCount, Titled, Language):
121
47
  aims: List[str]
122
48
  """List of writing aims of the research component in academic style."""
123
49
 
124
- support_to: List[ArticleRef]
125
- """List of references to other future components in this article that this component supports to."""
126
- depend_on: List[ArticleRef]
127
- """List of references to other previous components in this article that this component depends on."""
128
50
 
129
51
 
130
- class ArticleRefSequencePatch(SequencePatch[ArticleRef]):
131
- """Patch for article refs."""
132
-
133
52
 
134
53
  class ArticleOutlineBase(
135
54
  ArticleMetaData,
@@ -148,10 +67,6 @@ class ArticleOutlineBase(
148
67
 
149
68
  def update_metadata(self, other: ArticleMetaData) -> Self:
150
69
  """Updates the metadata of the current instance with the attributes of another instance."""
151
- self.support_to.clear()
152
- self.support_to.extend(other.support_to)
153
- self.depend_on.clear()
154
- self.depend_on.extend(other.depend_on)
155
70
  self.aims.clear()
156
71
  self.aims.extend(other.aims)
157
72
  self.description = other.description
@@ -319,34 +234,6 @@ class ArticleBase[T: ChapterBase](FinalizedDumpAble, AsPrompt, WordCount, Descri
319
234
  yield sec
320
235
  yield from sec.subsections
321
236
 
322
- def iter_support_on(self, rev: bool = False) -> Generator[ArticleRef, None, None]:
323
- """Iterates over all references that the article components support.
324
-
325
- Args:
326
- rev (bool): If True, iterate in reverse order.
327
-
328
- Yields:
329
- ArticleRef: Each reference that the article components support.
330
- """
331
- if rev:
332
- yield from chain(*[a.support_to for a in self.iter_dfs_rev()])
333
- return
334
- yield from chain(*[a.support_to for a in self.iter_dfs()])
335
-
336
- def iter_depend_on(self, rev: bool = False) -> Generator[ArticleRef, None, None]:
337
- """Iterates over all references that the article components depend on.
338
-
339
- Args:
340
- rev (bool): If True, iterate in reverse order.
341
-
342
- Yields:
343
- ArticleRef: Each reference that the article components depend on.
344
- """
345
- if rev:
346
- yield from chain(*[a.depend_on for a in self.iter_dfs_rev()])
347
- return
348
- yield from chain(*[a.depend_on for a in self.iter_dfs()])
349
-
350
237
  def iter_sections(self) -> Generator[Tuple[ChapterBase, SectionBase], None, None]:
351
238
  """Iterates through all sections in the article.
352
239
 
@@ -380,12 +267,6 @@ class ArticleBase[T: ChapterBase](FinalizedDumpAble, AsPrompt, WordCount, Descri
380
267
  """Gathers all introspected components in the article structure."""
381
268
  return "\n".join([i for component in self.chapters if (i := component.introspect())])
382
269
 
383
- @overload
384
- def find_illegal_ref(self, gather_identical: bool) -> Optional[Tuple[ArticleRef | List[ArticleRef], str]]: ...
385
-
386
- @overload
387
- def find_illegal_ref(self) -> Optional[Tuple[ArticleRef, str]]: ...
388
-
389
270
  def iter_chap_title(self) -> Generator[str, None, None]:
390
271
  """Iterates through all chapter titles in the article."""
391
272
  for chap in self.chapters:
@@ -401,71 +282,6 @@ class ArticleBase[T: ChapterBase](FinalizedDumpAble, AsPrompt, WordCount, Descri
401
282
  for _, _, subsec in self.iter_subsections():
402
283
  yield subsec.title
403
284
 
404
- def find_illegal_ref(self, gather_identical: bool = False) -> Optional[Tuple[ArticleRef | List[ArticleRef], str]]:
405
- """Finds the first illegal component in the outline.
406
-
407
- Returns:
408
- Tuple[ArticleOutlineBase, str]: A tuple containing the illegal component and an error message.
409
- """
410
- summary = ""
411
- chap_titles_set = set(self.iter_chap_title())
412
- sec_titles_set = set(self.iter_section_title())
413
- subsec_titles_set = set(self.iter_subsection_title())
414
-
415
- for component in self.iter_dfs_rev():
416
- for ref in chain(component.depend_on, component.support_to):
417
- if not ref.deref(self):
418
- summary += f"Invalid internal reference in `{component.__class__.__name__}` titled `{component.title}`, because the referred {ref.referring_type} is not exists within the article, see the original obj dump: {ref.model_dump()}\n"
419
-
420
- if ref.chap not in (chap_titles_set):
421
- summary += f"Chapter titled `{ref.chap}` is not any of {chap_titles_set}\n"
422
- if ref.sec and ref.sec not in (sec_titles_set):
423
- summary += f"Section Titled `{ref.sec}` is not any of {sec_titles_set}\n"
424
- if ref.subsec and ref.subsec not in (subsec_titles_set):
425
- summary += f"Subsection Titled `{ref.subsec}` is not any of {subsec_titles_set}"
426
-
427
- if summary:
428
- return (
429
- (
430
- [
431
- identical_ref
432
- for identical_ref in chain(self.iter_depend_on(), self.iter_support_on())
433
- if identical_ref == ref
434
- ],
435
- summary,
436
- )
437
- if gather_identical
438
- else (ref, summary)
439
- )
440
-
441
- return None
442
-
443
- def gather_illegal_ref(self) -> Tuple[List[ArticleRef], str]:
444
- """Gathers all illegal references in the article."""
445
- summary = []
446
- chap_titles_set = set(self.iter_chap_title())
447
- sec_titles_set = set(self.iter_section_title())
448
- subsec_titles_set = set(self.iter_subsection_title())
449
- res_seq = []
450
-
451
- for component in self.iter_dfs():
452
- for ref in (
453
- r for r in chain(component.depend_on, component.support_to) if not r.deref(self) and r not in res_seq
454
- ):
455
- res_seq.append(ref)
456
- if ref.chap not in chap_titles_set:
457
- summary.append(
458
- f"Chapter titled `{ref.chap}` is not exist, since it is not any of {chap_titles_set}."
459
- )
460
- if ref.sec and (ref.sec not in sec_titles_set):
461
- summary.append(f"Section Titled `{ref.sec}` is not exist, since it is not any of {sec_titles_set}")
462
- if ref.subsec and (ref.subsec not in subsec_titles_set):
463
- summary.append(
464
- f"Subsection Titled `{ref.subsec}` is not exist, since it is not any of {subsec_titles_set}"
465
- )
466
-
467
- return res_seq, "\n".join(summary)
468
-
469
285
  def finalized_dump(self) -> str:
470
286
  """Generates standardized hierarchical markup for academic publishing systems.
471
287
 
@@ -1,13 +1,11 @@
1
1
  """ArticleBase and ArticleSubsection classes for managing hierarchical document components."""
2
2
 
3
- from itertools import chain
4
3
  from typing import Dict, Generator, List, Self, Tuple, override
5
4
 
6
5
  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,
10
- ArticleOutlineBase,
11
9
  ChapterBase,
12
10
  SectionBase,
13
11
  SubSectionBase,
@@ -16,8 +14,7 @@ from fabricatio.models.extra.article_outline import (
16
14
  ArticleOutline,
17
15
  )
18
16
  from fabricatio.models.generic import Described, PersistentAble, SequencePatch, SketchedAble, WithRef, WordCount
19
- from fabricatio.rust import detect_language, word_count
20
- from fabricatio.utils import ok
17
+ from fabricatio.rust import word_count
21
18
  from pydantic import Field
22
19
 
23
20
  PARAGRAPH_SEP = "// - - -"
@@ -66,10 +63,11 @@ class ArticleSubsection(SubSectionBase):
66
63
  summary = ""
67
64
  if len(self.paragraphs) == 0:
68
65
  summary += f"`{self.__class__.__name__}` titled `{self.title}` have no paragraphs, You should add some!\n"
69
- if abs((wc := self.word_count) - self.expected_word_count) / self.expected_word_count > self._max_word_count_deviation:
70
- summary += (
71
- f"`{self.__class__.__name__}` titled `{self.title}` have {wc} words, expected {self.word_count} words!"
72
- )
66
+ if (
67
+ abs((wc := self.word_count) - self.expected_word_count) / self.expected_word_count
68
+ > self._max_word_count_deviation
69
+ ):
70
+ summary += f"`{self.__class__.__name__}` titled `{self.title}` have {wc} words, expected {self.expected_word_count} words!"
73
71
 
74
72
  return summary
75
73
 
@@ -90,17 +88,14 @@ class ArticleSubsection(SubSectionBase):
90
88
  return f"=== {self.title}\n" + f"\n{PARAGRAPH_SEP}\n".join(p.content for p in self.paragraphs)
91
89
 
92
90
  @classmethod
93
- def from_typst_code(cls, title: str, body: str, language: str) -> Self:
91
+ def from_typst_code(cls, title: str, body: str) -> Self:
94
92
  """Creates an Article object from the given Typst code."""
95
93
  return cls(
96
94
  heading=title,
97
95
  elaboration="",
98
96
  paragraphs=[Paragraph.from_content(p) for p in body.split(PARAGRAPH_SEP)],
99
97
  expected_word_count=word_count(body),
100
- language=language,
101
98
  aims=[],
102
- support_to=[],
103
- depend_on=[],
104
99
  )
105
100
 
106
101
 
@@ -108,20 +103,16 @@ class ArticleSection(SectionBase[ArticleSubsection]):
108
103
  """Atomic argumentative unit with high-level specificity."""
109
104
 
110
105
  @classmethod
111
- def from_typst_code(cls, title: str, body: str, language: str) -> Self:
106
+ def from_typst_code(cls, title: str, body: str) -> Self:
112
107
  """Creates an Article object from the given Typst code."""
113
108
  return cls(
114
109
  subsections=[
115
- ArticleSubsection.from_typst_code(*pack, language=language)
116
- for pack in extract_sections(body, level=3, section_char="=")
110
+ ArticleSubsection.from_typst_code(*pack) for pack in extract_sections(body, level=3, section_char="=")
117
111
  ],
118
112
  heading=title,
119
113
  elaboration="",
120
114
  expected_word_count=word_count(body),
121
- language=language,
122
115
  aims=[],
123
- support_to=[],
124
- depend_on=[],
125
116
  )
126
117
 
127
118
 
@@ -129,20 +120,16 @@ class ArticleChapter(ChapterBase[ArticleSection]):
129
120
  """Thematic progression implementing research function."""
130
121
 
131
122
  @classmethod
132
- def from_typst_code(cls, title: str, body: str, language: str) -> Self:
123
+ def from_typst_code(cls, title: str, body: str) -> Self:
133
124
  """Creates an Article object from the given Typst code."""
134
125
  return cls(
135
126
  sections=[
136
- ArticleSection.from_typst_code(*pack, language=language)
137
- for pack in extract_sections(body, level=2, section_char="=")
127
+ ArticleSection.from_typst_code(*pack) for pack in extract_sections(body, level=2, section_char="=")
138
128
  ],
139
129
  heading=title,
140
130
  elaboration="",
141
131
  expected_word_count=word_count(body),
142
- language=language,
143
132
  aims=[],
144
- support_to=[],
145
- depend_on=[],
146
133
  )
147
134
 
148
135
 
@@ -210,92 +197,10 @@ class Article(
210
197
  def from_typst_code(cls, title: str, body: str) -> Self:
211
198
  """Generates an article from the given Typst code."""
212
199
  return cls(
213
- language=(lang := detect_language(body)),
214
200
  chapters=[
215
- ArticleChapter.from_typst_code(*pack, language=lang)
216
- for pack in extract_sections(body, level=1, section_char="=")
201
+ ArticleChapter.from_typst_code(*pack) for pack in extract_sections(body, level=1, section_char="=")
217
202
  ],
218
203
  heading=title,
219
204
  expected_word_count=word_count(body),
220
205
  abstract="",
221
206
  )
222
-
223
- def gather_dependencies(self, article: ArticleOutlineBase) -> List[ArticleOutlineBase]:
224
- """Gathers dependencies for all sections and subsections in the article.
225
-
226
- This method should be called after the article is fully constructed.
227
- """
228
- depends = [ok(a.deref(self)) for a in article.depend_on]
229
-
230
- supports = []
231
- for a in self.iter_dfs_rev():
232
- if article in {ok(b.deref(self)) for b in a.support_to}:
233
- supports.append(a)
234
-
235
- return list(set(depends + supports))
236
-
237
- def gather_dependencies_recursive(self, article: ArticleOutlineBase) -> List[ArticleOutlineBase]:
238
- """Gathers all dependencies recursively for the given article.
239
-
240
- Args:
241
- article (ArticleOutlineBase): The article to gather dependencies for.
242
-
243
- Returns:
244
- List[ArticleBase]: A list of all dependencies for the given article.
245
- """
246
- q = self.gather_dependencies(article)
247
-
248
- deps = []
249
- while q:
250
- a = q.pop()
251
- deps.extend(self.gather_dependencies(a))
252
-
253
- deps = list(
254
- chain(
255
- filter(lambda x: isinstance(x, ArticleChapter), deps),
256
- filter(lambda x: isinstance(x, ArticleSection), deps),
257
- filter(lambda x: isinstance(x, ArticleSubsection), deps),
258
- )
259
- )
260
-
261
- # Initialize result containers
262
- formatted_code = ""
263
- processed_components = []
264
-
265
- # Process all dependencies
266
- while deps:
267
- component = deps.pop()
268
- # Skip duplicates
269
- if (component_code := component.to_typst_code()) in formatted_code:
270
- continue
271
-
272
- # Add this component
273
- formatted_code += component_code
274
- processed_components.append(component)
275
-
276
- return processed_components
277
-
278
- def iter_dfs_with_deps(
279
- self, chapter: bool = True, section: bool = True, subsection: bool = True
280
- ) -> Generator[Tuple[ArticleOutlineBase, List[ArticleOutlineBase]], None, None]:
281
- """Iterates through the article in a depth-first manner, yielding each component and its dependencies.
282
-
283
- Args:
284
- chapter (bool, optional): Whether to include chapter components. Defaults to True.
285
- section (bool, optional): Whether to include section components. Defaults to True.
286
- subsection (bool, optional): Whether to include subsection components. Defaults to True.
287
-
288
- Yields:
289
- Tuple[ArticleBase, List[ArticleBase]]: Each component and its dependencies.
290
- """
291
- if all((not chapter, not section, not subsection)):
292
- raise ValueError("At least one of chapter, section, or subsection must be True.")
293
-
294
- for component in self.iter_dfs_rev():
295
- if not chapter and isinstance(component, ArticleChapter):
296
- continue
297
- if not section and isinstance(component, ArticleSection):
298
- continue
299
- if not subsection and isinstance(component, ArticleSubsection):
300
- continue
301
- yield component, (self.gather_dependencies_recursive(component))
@@ -1,11 +1,12 @@
1
1
  """A class representing a problem-solution pair identified during a review process."""
2
2
 
3
3
  from itertools import chain
4
- from typing import Any, List, Literal, Optional, Self, Tuple, Unpack
4
+ from typing import Any, List, Optional, Self, Tuple, Unpack
5
5
 
6
6
  from fabricatio.journal import logger
7
7
  from fabricatio.models.generic import SketchedAble, WithBriefing
8
8
  from fabricatio.utils import ask_edit
9
+ from pydantic import Field
9
10
  from questionary import Choice, checkbox, text
10
11
  from rich import print as r_print
11
12
 
@@ -13,36 +14,30 @@ from rich import print as r_print
13
14
  class Problem(SketchedAble, WithBriefing):
14
15
  """Represents a problem identified during review."""
15
16
 
16
- description: str
17
- """Description of the problem, The """
17
+ description: str = Field(alias="cause")
18
+ """The cause of the problem, including the root cause, the context, and the impact, make detailed enough for engineer to understand the problem and its impact."""
18
19
 
19
- severity: Literal["low", "medium", "high"]
20
- """Severity level of the problem."""
21
-
22
- category: str
23
- """Category of the problem."""
20
+ severity_level: int = Field(ge=0, le=10)
21
+ """Severity level of the problem, which is a number between 0 and 10, 0 means the problem is not severe, 10 means the problem is extremely severe."""
24
22
 
25
23
  location: str
26
24
  """Location where the problem was identified."""
27
25
 
28
- recommendation: str
29
- """Recommended solution or action."""
30
-
31
26
 
32
27
  class Solution(SketchedAble, WithBriefing):
33
28
  """Represents a proposed solution to a problem."""
34
29
 
35
- description: str
30
+ description: str = Field(alias="mechanism")
36
31
  """Description of the solution, including a detailed description of the execution steps, and the mechanics, principle or fact."""
37
32
 
38
33
  execute_steps: List[str]
39
- """A list of steps to execute to implement the solution, which is expected to be able to finally solve the corresponding problem."""
34
+ """A list of steps to execute to implement the solution, which is expected to be able to finally solve the corresponding problem, and which should be an Idiot-proof tutorial."""
40
35
 
41
- feasibility: Literal["low", "medium", "high"]
42
- """Feasibility level of the solution."""
36
+ feasibility_level: int = Field(ge=0, le=10)
37
+ """Feasibility level of the solution, which is a number between 0 and 10, 0 means the solution is not feasible, 10 means the solution is complete feasible."""
43
38
 
44
- impact: Literal["low", "medium", "high"]
45
- """Impact level of the solution."""
39
+ impact_level: int = Field(ge=0, le=10)
40
+ """Impact level of the solution, which is a number between 0 and 10, 0 means the solution is not impactful, 10 means the solution is extremely impactful."""
46
41
 
47
42
 
48
43
  class ProblemSolutions(SketchedAble):
@@ -0,0 +1,72 @@
1
+ """A module containing the RAG (Retrieval-Augmented Generation) models."""
2
+
3
+ from abc import ABCMeta, abstractmethod
4
+ from typing import TYPE_CHECKING, Any, ClassVar, Dict, List, Self, Sequence
5
+
6
+ from fabricatio.decorators import precheck_package
7
+ from pydantic import BaseModel, ConfigDict, JsonValue
8
+
9
+ if TYPE_CHECKING:
10
+ from importlib.util import find_spec
11
+
12
+ from pydantic.fields import FieldInfo
13
+
14
+ if find_spec("pymilvus"):
15
+ from pymilvus import CollectionSchema
16
+
17
+
18
+ class MilvusDataBase(BaseModel, metaclass=ABCMeta):
19
+ """A base class for Milvus data."""
20
+
21
+ model_config = ConfigDict(use_attribute_docstrings=True)
22
+
23
+ primary_field_name: ClassVar[str] = "id"
24
+
25
+ vector_field_name: ClassVar[str] = "vector"
26
+
27
+ def prepare_insertion(self, vector: List[float]) -> Dict[str, Any]:
28
+ """Prepares the data for insertion into Milvus.
29
+
30
+ Returns:
31
+ dict: A dictionary containing the data to be inserted into Milvus.
32
+ """
33
+ return {**self.model_dump(exclude_none=True, by_alias=True), self.vector_field_name: vector}
34
+
35
+ @property
36
+ @abstractmethod
37
+ def to_vectorize(self) -> str:
38
+ """The text representation of the data."""
39
+
40
+ @classmethod
41
+ @precheck_package(
42
+ "pymilvus", "pymilvus is not installed. Have you installed `fabricatio[rag]` instead of `fabricatio`?"
43
+ )
44
+ def as_milvus_schema(cls, dimension: int = 1024) -> "CollectionSchema":
45
+ """Generates the schema for Milvus collection."""
46
+ from pymilvus import CollectionSchema, DataType, FieldSchema
47
+
48
+ fields = [
49
+ FieldSchema(cls.primary_field_name, dtype=DataType.INT64, is_primary=True, auto_id=True),
50
+ FieldSchema(cls.vector_field_name, dtype=DataType.FLOAT_VECTOR, dim=dimension),
51
+ ]
52
+
53
+ type_mapping = {
54
+ str: DataType.STRING,
55
+ int: DataType.INT64,
56
+ float: DataType.DOUBLE,
57
+ JsonValue: DataType.JSON,
58
+ # TODO add more mapping
59
+ }
60
+
61
+ for k, v in cls.model_fields.items():
62
+ k: str
63
+ v: FieldInfo
64
+ fields.append(
65
+ FieldSchema(k, dtype=type_mapping.get(v.annotation, DataType.UNKNOWN), description=v.description or "")
66
+ )
67
+ return CollectionSchema(fields)
68
+
69
+ @classmethod
70
+ def from_sequence(cls, data: Sequence[Dict[str, Any]]) -> List[Self]:
71
+ """Constructs a list of instances from a sequence of dictionaries."""
72
+ return [cls(**d) for d in data]
@@ -40,12 +40,11 @@ class RuleSet(SketchedAble, PersistentAble, WithBriefing, Language):
40
40
  framework for the topic or domain covered by the rule set."""
41
41
 
42
42
  @classmethod
43
- def gather(cls, *rulesets: Unpack[Tuple["RuleSet",...]]) -> Self:
43
+ def gather(cls, *rulesets: Unpack[Tuple["RuleSet", ...]]) -> Self:
44
44
  """Gathers multiple rule sets into a single rule set."""
45
45
  if not rulesets:
46
46
  raise ValueError("No rulesets provided")
47
47
  return cls(
48
- language=rulesets[0].language,
49
48
  name=";".join(ruleset.name for ruleset in rulesets),
50
49
  description=";".join(ruleset.description for ruleset in rulesets),
51
50
  rules=list(flatten(r.rules for r in rulesets)),
@@ -11,7 +11,7 @@ from fabricatio.config import configs
11
11
  from fabricatio.fs.readers import MAGIKA, safe_text_read
12
12
  from fabricatio.journal import logger
13
13
  from fabricatio.parser import JsonCapture
14
- from fabricatio.rust import blake3_hash
14
+ from fabricatio.rust import blake3_hash, detect_language
15
15
  from fabricatio.rust_instances import TEMPLATE_MANAGER
16
16
  from fabricatio.utils import ok
17
17
  from litellm.utils import token_counter
@@ -53,7 +53,7 @@ class Display(Base):
53
53
  Returns:
54
54
  str: JSON string with 1-level indentation for readability
55
55
  """
56
- return self.model_dump_json(indent=1)
56
+ return self.model_dump_json(indent=1,by_alias=True)
57
57
 
58
58
  def compact(self) -> str:
59
59
  """Generate compact JSON representation.
@@ -61,7 +61,7 @@ class Display(Base):
61
61
  Returns:
62
62
  str: Minified JSON string without whitespace
63
63
  """
64
- return self.model_dump_json()
64
+ return self.model_dump_json(by_alias=True)
65
65
 
66
66
  @staticmethod
67
67
  def seq_display(seq: Iterable["Display"], compact: bool = False) -> str:
@@ -225,7 +225,7 @@ class PersistentAble(Base):
225
225
  - Hash generated from JSON content ensures uniqueness
226
226
  """
227
227
  p = Path(path)
228
- out = self.model_dump_json(indent=1)
228
+ out = self.model_dump_json(indent=1,by_alias=True)
229
229
 
230
230
  # Generate a timestamp in the format YYYYMMDD_HHMMSS
231
231
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
@@ -298,10 +298,17 @@ class PersistentAble(Base):
298
298
  class Language(Base):
299
299
  """Class that provides a language attribute."""
300
300
 
301
- language: str
302
- """The fullname of the written language of this object."""
303
-
304
-
301
+ @property
302
+ def language(self)->str:
303
+ """Get the language of the object."""
304
+ if isinstance(self,Described):
305
+ return detect_language(self.description)
306
+ if isinstance(self,Titled):
307
+ return detect_language(self.title)
308
+ if isinstance(self,Named):
309
+ return detect_language(self.name)
310
+
311
+ return detect_language(self.model_dump_json(by_alias=True))
305
312
  class ModelHash(Base):
306
313
  """Class that provides a hash value for the object.
307
314
 
@@ -543,7 +550,7 @@ class FinalizedDumpAble(Base):
543
550
  Returns:
544
551
  str: The finalized dump of the object.
545
552
  """
546
- return self.model_dump_json()
553
+ return self.model_dump_json(indent=1,by_alias=True)
547
554
 
548
555
  def finalized_dump_to(self, path: str | Path) -> Self:
549
556
  """Finalize the dump of the object to a file.