fabricatio 0.2.6.dev8__cp312-cp312-manylinux_2_34_x86_64.whl → 0.2.7__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.
- fabricatio/_rust.cpython-312-x86_64-linux-gnu.so +0 -0
- fabricatio/_rust.pyi +11 -2
- fabricatio/actions/article.py +146 -44
- fabricatio/actions/article_rag.py +35 -0
- fabricatio/actions/output.py +21 -6
- fabricatio/actions/rag.py +49 -2
- fabricatio/capabilities/correct.py +36 -4
- fabricatio/capabilities/rag.py +41 -5
- fabricatio/capabilities/rating.py +15 -6
- fabricatio/capabilities/review.py +7 -4
- fabricatio/capabilities/task.py +3 -3
- fabricatio/config.py +3 -0
- fabricatio/decorators.py +32 -0
- fabricatio/models/action.py +9 -7
- fabricatio/models/extra/article_base.py +378 -0
- fabricatio/models/extra/article_essence.py +226 -0
- fabricatio/models/extra/article_main.py +196 -0
- fabricatio/models/extra/article_outline.py +32 -0
- fabricatio/models/extra/article_proposal.py +35 -0
- fabricatio/models/generic.py +164 -14
- fabricatio/models/kwargs_types.py +22 -3
- fabricatio/models/tool.py +6 -2
- fabricatio/models/usages.py +48 -37
- fabricatio/models/utils.py +6 -4
- fabricatio-0.2.7.data/scripts/tdown +0 -0
- fabricatio-0.2.7.dist-info/METADATA +181 -0
- fabricatio-0.2.7.dist-info/RECORD +47 -0
- fabricatio/models/extra.py +0 -655
- fabricatio-0.2.6.dev8.data/scripts/tdown +0 -0
- fabricatio-0.2.6.dev8.dist-info/METADATA +0 -432
- fabricatio-0.2.6.dev8.dist-info/RECORD +0 -42
- {fabricatio-0.2.6.dev8.dist-info → fabricatio-0.2.7.dist-info}/WHEEL +0 -0
- {fabricatio-0.2.6.dev8.dist-info → fabricatio-0.2.7.dist-info}/licenses/LICENSE +0 -0
Binary file
|
fabricatio/_rust.pyi
CHANGED
@@ -11,7 +11,7 @@ class TemplateManager:
|
|
11
11
|
"""
|
12
12
|
|
13
13
|
def __init__(
|
14
|
-
|
14
|
+
self, template_dirs: List[Path], suffix: Optional[str] = None, active_loading: Optional[bool] = None
|
15
15
|
) -> None:
|
16
16
|
"""Initialize the template manager.
|
17
17
|
|
@@ -55,6 +55,16 @@ class TemplateManager:
|
|
55
55
|
RuntimeError: If template rendering fails
|
56
56
|
"""
|
57
57
|
|
58
|
+
def render_template_raw(self, template: str, data: Dict[str, Any]) -> str:
|
59
|
+
"""Render a template with context data.
|
60
|
+
|
61
|
+
Args:
|
62
|
+
template: The template string
|
63
|
+
data: Context dictionary to provide variables to the template
|
64
|
+
|
65
|
+
Returns:
|
66
|
+
Rendered template content as string
|
67
|
+
"""
|
58
68
|
|
59
69
|
def blake3_hash(content: bytes) -> str:
|
60
70
|
"""Calculate the BLAKE3 cryptographic hash of data.
|
@@ -66,7 +76,6 @@ def blake3_hash(content: bytes) -> str:
|
|
66
76
|
Hex-encoded BLAKE3 hash string
|
67
77
|
"""
|
68
78
|
|
69
|
-
|
70
79
|
class BibManager:
|
71
80
|
"""BibTeX bibliography manager for parsing and querying citation data."""
|
72
81
|
|
fabricatio/actions/article.py
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
"""Actions for transmitting tasks to targets."""
|
2
2
|
|
3
|
-
from os import PathLike
|
4
3
|
from pathlib import Path
|
5
4
|
from typing import Any, Callable, List, Optional
|
6
5
|
|
7
6
|
from fabricatio.fs import safe_text_read
|
8
7
|
from fabricatio.journal import logger
|
9
8
|
from fabricatio.models.action import Action
|
10
|
-
from fabricatio.models.extra import ArticleEssence
|
9
|
+
from fabricatio.models.extra.article_essence import ArticleEssence
|
10
|
+
from fabricatio.models.extra.article_main import Article
|
11
|
+
from fabricatio.models.extra.article_outline import ArticleOutline
|
12
|
+
from fabricatio.models.extra.article_proposal import ArticleProposal
|
11
13
|
from fabricatio.models.task import Task
|
12
|
-
from
|
13
|
-
from rich import print as rprint
|
14
|
+
from fabricatio.models.utils import ok
|
14
15
|
|
15
16
|
|
16
17
|
class ExtractArticleEssence(Action):
|
@@ -24,10 +25,10 @@ class ExtractArticleEssence(Action):
|
|
24
25
|
output_key: str = "article_essence"
|
25
26
|
"""The key of the output data."""
|
26
27
|
|
27
|
-
async def _execute
|
28
|
+
async def _execute(
|
28
29
|
self,
|
29
30
|
task_input: Task,
|
30
|
-
reader: Callable[[
|
31
|
+
reader: Callable[[str], str] = lambda p: Path(p).read_text(encoding="utf-8"),
|
31
32
|
**_,
|
32
33
|
) -> Optional[List[ArticleEssence]]:
|
33
34
|
if not task_input.dependencies:
|
@@ -51,18 +52,34 @@ class GenerateArticleProposal(Action):
|
|
51
52
|
|
52
53
|
async def _execute(
|
53
54
|
self,
|
54
|
-
task_input: Task,
|
55
|
+
task_input: Optional[Task] = None,
|
56
|
+
article_briefing: Optional[str] = None,
|
57
|
+
article_briefing_path: Optional[str] = None,
|
55
58
|
**_,
|
56
59
|
) -> Optional[ArticleProposal]:
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
return
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
60
|
+
if article_briefing is None and article_briefing_path is None and task_input is None:
|
61
|
+
logger.error("Task not approved, since all inputs are None.")
|
62
|
+
return None
|
63
|
+
|
64
|
+
return ok(
|
65
|
+
await self.propose(
|
66
|
+
ArticleProposal,
|
67
|
+
briefing := (
|
68
|
+
article_briefing
|
69
|
+
or safe_text_read(
|
70
|
+
ok(
|
71
|
+
article_briefing_path
|
72
|
+
or await self.awhich_pathstr(
|
73
|
+
f"{ok(task_input).briefing}\nExtract the path of file which contains the article briefing."
|
74
|
+
),
|
75
|
+
"Could not find the path of file to read.",
|
76
|
+
)
|
77
|
+
)
|
78
|
+
),
|
79
|
+
**self.prepend_sys_msg(),
|
80
|
+
),
|
81
|
+
"Could not generate the proposal.",
|
82
|
+
).update_ref(briefing)
|
66
83
|
|
67
84
|
|
68
85
|
class GenerateOutline(Action):
|
@@ -76,35 +93,111 @@ class GenerateOutline(Action):
|
|
76
93
|
article_proposal: ArticleProposal,
|
77
94
|
**_,
|
78
95
|
) -> Optional[ArticleOutline]:
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
96
|
+
out = ok(
|
97
|
+
await self.propose(
|
98
|
+
ArticleOutline,
|
99
|
+
article_proposal.as_prompt(),
|
100
|
+
**self.prepend_sys_msg(),
|
101
|
+
),
|
102
|
+
"Could not generate the outline.",
|
103
|
+
)
|
104
|
+
|
105
|
+
introspect_manual = ok(
|
106
|
+
await self.draft_rating_manual(
|
107
|
+
topic=(
|
108
|
+
intro_topic
|
109
|
+
:= "Fix the error in the article outline, make sure there is no more error in the article outline."
|
110
|
+
),
|
111
|
+
),
|
112
|
+
"Could not generate the rating manual.",
|
113
|
+
)
|
114
|
+
|
115
|
+
while pack := out.find_introspected():
|
116
|
+
component, err = ok(pack)
|
117
|
+
logger.warning(f"Found introspected error: {err}")
|
118
|
+
corrected = ok(
|
119
|
+
await self.correct_obj(
|
120
|
+
component,
|
121
|
+
reference=f"# Original Article Outline\n{out.display()}\n# Error Need to be fixed\n{err}",
|
122
|
+
topic=intro_topic,
|
123
|
+
rating_manual=introspect_manual,
|
124
|
+
supervisor_check=False,
|
125
|
+
),
|
126
|
+
"Could not correct the component.",
|
127
|
+
)
|
128
|
+
component.update_from(corrected)
|
129
|
+
|
130
|
+
ref_manual = ok(
|
131
|
+
await self.draft_rating_manual(
|
132
|
+
topic=(
|
133
|
+
ref_topic
|
134
|
+
:= "Fix the internal referring error, make sure there is no more `ArticleRef` pointing to a non-existing article component."
|
135
|
+
),
|
136
|
+
),
|
137
|
+
"Could not generate the rating manual.",
|
138
|
+
)
|
139
|
+
|
140
|
+
while pack := out.find_illegal_ref():
|
141
|
+
component, err = ok(pack)
|
142
|
+
logger.warning(f"Found illegal referring error: {err}")
|
143
|
+
corrected_metadata = ok(
|
144
|
+
await self.correct_obj(
|
145
|
+
component.metadata,
|
146
|
+
reference=f"# Original Article Outline\n{out.display()}\n# Error Need to be fixed\n{err}\n\n# Create a new metadata to handle the error.",
|
147
|
+
topic=ref_topic,
|
148
|
+
rating_manual=ref_manual,
|
149
|
+
supervisor_check=False,
|
150
|
+
)
|
151
|
+
)
|
152
|
+
component.update_metadata(corrected_metadata)
|
153
|
+
return out.update_ref(article_proposal)
|
154
|
+
|
155
|
+
|
156
|
+
class GenerateArticle(Action):
|
157
|
+
"""Generate the article based on the outline."""
|
158
|
+
|
159
|
+
output_key: str = "article"
|
160
|
+
"""The key of the output data."""
|
161
|
+
|
162
|
+
async def _execute(
|
163
|
+
self,
|
164
|
+
article_outline: ArticleOutline,
|
165
|
+
**_,
|
166
|
+
) -> Optional[Article]:
|
167
|
+
article: Article = Article.from_outline(ok(article_outline, "Article outline not specified.")).update_ref(
|
168
|
+
article_outline
|
83
169
|
)
|
84
170
|
|
171
|
+
write_para_manual = ok(
|
172
|
+
await self.draft_rating_manual(w_topic := "write the following paragraph in the subsection.")
|
173
|
+
)
|
174
|
+
|
175
|
+
for *_, subsec in article.iter_subsections():
|
176
|
+
corrected_subsec = await self.correct_obj(
|
177
|
+
subsec,
|
178
|
+
reference=f"# Original Article Outline\n{article_outline.display()}\n# Error Need to be fixed\n{subsec.introspect()}",
|
179
|
+
topic=w_topic,
|
180
|
+
rating_manual=write_para_manual,
|
181
|
+
supervisor_check=False,
|
182
|
+
)
|
183
|
+
subsec.paragraphs.clear()
|
184
|
+
subsec.paragraphs.extend(corrected_subsec.paragraphs)
|
185
|
+
|
186
|
+
logger.success(f"Finished: {article.display()}")
|
187
|
+
logger.success(f"Dump: {article.finalized_dump()}")
|
188
|
+
return article
|
189
|
+
|
85
190
|
|
86
191
|
class CorrectProposal(Action):
|
87
192
|
"""Correct the proposal of the article."""
|
88
193
|
|
89
194
|
output_key: str = "corrected_proposal"
|
90
195
|
|
91
|
-
async def _execute(self,
|
92
|
-
|
93
|
-
|
196
|
+
async def _execute(self, article_proposal: ArticleProposal, **_) -> Any:
|
197
|
+
return (await self.censor_obj(article_proposal, reference=article_proposal.referenced)).update_ref(
|
198
|
+
article_proposal
|
94
199
|
)
|
95
200
|
|
96
|
-
ret = None
|
97
|
-
while await confirm("Do you want to correct the Proposal?").ask_async():
|
98
|
-
rprint(article_proposal.display())
|
99
|
-
while not (topic := await text("What is the topic of the proposal reviewing?").ask_async()):
|
100
|
-
...
|
101
|
-
ret = await self.correct_obj(
|
102
|
-
article_proposal,
|
103
|
-
safe_text_read(input_path),
|
104
|
-
topic=topic,
|
105
|
-
)
|
106
|
-
return ret or article_proposal
|
107
|
-
|
108
201
|
|
109
202
|
class CorrectOutline(Action):
|
110
203
|
"""Correct the outline of the article."""
|
@@ -115,14 +208,23 @@ class CorrectOutline(Action):
|
|
115
208
|
async def _execute(
|
116
209
|
self,
|
117
210
|
article_outline: ArticleOutline,
|
118
|
-
|
211
|
+
**_,
|
212
|
+
) -> ArticleOutline:
|
213
|
+
return (await self.censor_obj(article_outline, reference=article_outline.referenced.as_prompt())).update_ref(
|
214
|
+
article_outline
|
215
|
+
)
|
216
|
+
|
217
|
+
|
218
|
+
class CorrectArticle(Action):
|
219
|
+
"""Correct the article based on the outline."""
|
119
220
|
|
221
|
+
output_key: str = "corrected_article"
|
222
|
+
"""The key of the output data."""
|
223
|
+
|
224
|
+
async def _execute(
|
225
|
+
self,
|
226
|
+
article: Article,
|
227
|
+
article_outline: ArticleOutline,
|
120
228
|
**_,
|
121
|
-
) ->
|
122
|
-
|
123
|
-
while await confirm("Do you want to correct the outline?").ask_async():
|
124
|
-
rprint(article_outline.finalized_dump())
|
125
|
-
while not (topic := await text("What is the topic of the outline reviewing?").ask_async()):
|
126
|
-
...
|
127
|
-
ret = await self.correct_obj(article_outline, article_proposal.display(), topic=topic)
|
128
|
-
return ret or article_outline
|
229
|
+
) -> Article:
|
230
|
+
return await self.censor_obj(article, reference=article_outline.referenced.as_prompt())
|
@@ -0,0 +1,35 @@
|
|
1
|
+
"""A module for writing articles using RAG (Retrieval-Augmented Generation) capabilities."""
|
2
|
+
|
3
|
+
from typing import Optional
|
4
|
+
|
5
|
+
from fabricatio.capabilities.rag import RAG
|
6
|
+
from fabricatio.journal import logger
|
7
|
+
from fabricatio.models.action import Action
|
8
|
+
from fabricatio.models.extra.article_main import Article
|
9
|
+
from fabricatio.models.extra.article_outline import ArticleOutline
|
10
|
+
|
11
|
+
|
12
|
+
class GenerateArticleRAG(Action, RAG):
|
13
|
+
"""Write an article based on the provided outline."""
|
14
|
+
|
15
|
+
output_key: str = "article"
|
16
|
+
|
17
|
+
async def _execute(self, article_outline: ArticleOutline, **cxt) -> Optional[Article]:
|
18
|
+
"""Write an article based on the provided outline."""
|
19
|
+
logger.info(f"Writing an article based on the outline:\n{article_outline.title}")
|
20
|
+
refined_q = await self.arefined_query(article_outline.display())
|
21
|
+
return await self.propose(
|
22
|
+
Article,
|
23
|
+
article_outline.display(),
|
24
|
+
**self.prepend_sys_msg(f"{await self.aretrieve_compact(refined_q)}\n{self.briefing}"),
|
25
|
+
)
|
26
|
+
|
27
|
+
|
28
|
+
class WriteArticleFineGrind(Action, RAG):
|
29
|
+
"""Fine-grind an article based on the provided outline."""
|
30
|
+
|
31
|
+
output_key: str = "article"
|
32
|
+
|
33
|
+
async def _execute(self, article_outline: ArticleOutline, **cxt) -> Optional[Article]:
|
34
|
+
"""Fine-grind an article based on the provided outline."""
|
35
|
+
logger.info(f"Fine-grinding an article based on the outline:\n{article_outline.title}")
|
fabricatio/actions/output.py
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
"""Dump the finalized output to a file."""
|
2
2
|
|
3
|
+
from pathlib import Path
|
4
|
+
from typing import Optional
|
5
|
+
|
3
6
|
from fabricatio.models.action import Action
|
4
7
|
from fabricatio.models.generic import FinalizedDumpAble
|
5
8
|
from fabricatio.models.task import Task
|
9
|
+
from fabricatio.models.utils import ok
|
6
10
|
|
7
11
|
|
8
12
|
class DumpFinalizedOutput(Action):
|
@@ -10,10 +14,21 @@ class DumpFinalizedOutput(Action):
|
|
10
14
|
|
11
15
|
output_key: str = "dump_path"
|
12
16
|
|
13
|
-
async def _execute(
|
14
|
-
|
15
|
-
|
17
|
+
async def _execute(
|
18
|
+
self,
|
19
|
+
to_dump: FinalizedDumpAble,
|
20
|
+
task_input: Optional[Task] = None,
|
21
|
+
dump_path: Optional[str | Path] = None,
|
22
|
+
**_,
|
23
|
+
) -> str:
|
24
|
+
dump_path = Path(
|
25
|
+
dump_path
|
26
|
+
or ok(
|
27
|
+
await self.awhich_pathstr(
|
28
|
+
f"{ok(task_input, 'Neither `task_input` and `dump_path` is provided.').briefing}\n\nExtract a single path of the file, to which I will dump the data."
|
29
|
+
),
|
30
|
+
"Could not find the path of file to dump the data.",
|
31
|
+
)
|
16
32
|
)
|
17
|
-
|
18
|
-
|
19
|
-
return dump_path
|
33
|
+
ok(to_dump, "Could not dump the data since the path is not specified.").finalized_dump_to(dump_path)
|
34
|
+
return dump_path.as_posix()
|
fabricatio/actions/rag.py
CHANGED
@@ -6,6 +6,8 @@ from fabricatio.capabilities.rag import RAG
|
|
6
6
|
from fabricatio.journal import logger
|
7
7
|
from fabricatio.models.action import Action
|
8
8
|
from fabricatio.models.generic import PrepareVectorization
|
9
|
+
from fabricatio.models.task import Task
|
10
|
+
from questionary import text
|
9
11
|
|
10
12
|
|
11
13
|
class InjectToDB(Action, RAG):
|
@@ -14,13 +16,58 @@ class InjectToDB(Action, RAG):
|
|
14
16
|
output_key: str = "collection_name"
|
15
17
|
|
16
18
|
async def _execute[T: PrepareVectorization](
|
17
|
-
self, to_inject: Optional[T] | List[Optional[T]], collection_name:
|
19
|
+
self, to_inject: Optional[T] | List[Optional[T]], collection_name: str = "my_collection",override_inject:bool=False, **_
|
18
20
|
) -> Optional[str]:
|
19
21
|
if not isinstance(to_inject, list):
|
20
22
|
to_inject = [to_inject]
|
21
23
|
logger.info(f"Injecting {len(to_inject)} items into the collection '{collection_name}'")
|
24
|
+
if override_inject:
|
25
|
+
self.check_client().client.drop_collection(collection_name)
|
22
26
|
await self.view(collection_name, create=True).consume_string(
|
23
|
-
[
|
27
|
+
[
|
28
|
+
t.prepare_vectorization(self.embedding_max_sequence_length)
|
29
|
+
for t in to_inject
|
30
|
+
if isinstance(t, PrepareVectorization)
|
31
|
+
],
|
24
32
|
)
|
25
33
|
|
26
34
|
return collection_name
|
35
|
+
|
36
|
+
|
37
|
+
class RAGTalk(Action, RAG):
|
38
|
+
"""RAG-enabled conversational action that processes user questions based on a given task.
|
39
|
+
|
40
|
+
This action establishes an interactive conversation loop where it retrieves context-relevant
|
41
|
+
information to answer user queries according to the assigned task briefing.
|
42
|
+
|
43
|
+
Notes:
|
44
|
+
task_input: Task briefing that guides how to respond to user questions
|
45
|
+
collection_name: Name of the vector collection to use for retrieval (default: "my_collection")
|
46
|
+
|
47
|
+
Returns:
|
48
|
+
Number of conversation turns completed before termination
|
49
|
+
"""
|
50
|
+
|
51
|
+
output_key: str = "task_output"
|
52
|
+
|
53
|
+
async def _execute(self, task_input: Task[str], **kwargs) -> int:
|
54
|
+
collection_name = kwargs.get("collection_name", "my_collection")
|
55
|
+
counter = 0
|
56
|
+
|
57
|
+
self.view(collection_name, create=True)
|
58
|
+
|
59
|
+
try:
|
60
|
+
while True:
|
61
|
+
user_say = await text("User: ").ask_async()
|
62
|
+
if user_say is None:
|
63
|
+
break
|
64
|
+
gpt_say = await self.aask_retrieved(
|
65
|
+
user_say,
|
66
|
+
user_say,
|
67
|
+
extra_system_message=f"You have to answer to user obeying task assigned to you:\n{task_input.briefing}",
|
68
|
+
)
|
69
|
+
print(f"GPT: {gpt_say}") # noqa: T201
|
70
|
+
counter += 1
|
71
|
+
except KeyboardInterrupt:
|
72
|
+
logger.info(f"executed talk action {counter} times")
|
73
|
+
return counter
|
@@ -10,9 +10,11 @@ from typing import Optional, Unpack, cast
|
|
10
10
|
from fabricatio._rust_instances import TEMPLATE_MANAGER
|
11
11
|
from fabricatio.capabilities.review import Review, ReviewResult
|
12
12
|
from fabricatio.config import configs
|
13
|
-
from fabricatio.models.generic import Display, ProposedAble, WithBriefing
|
14
|
-
from fabricatio.models.kwargs_types import CorrectKwargs, ReviewKwargs
|
13
|
+
from fabricatio.models.generic import CensoredAble, Display, ProposedAble, WithBriefing
|
14
|
+
from fabricatio.models.kwargs_types import CensoredCorrectKwargs, CorrectKwargs, ReviewKwargs
|
15
15
|
from fabricatio.models.task import Task
|
16
|
+
from questionary import confirm, text
|
17
|
+
from rich import print as rprint
|
16
18
|
|
17
19
|
|
18
20
|
class Correct(Review):
|
@@ -55,7 +57,7 @@ class Correct(Review):
|
|
55
57
|
if supervisor_check:
|
56
58
|
await review_res.supervisor_check()
|
57
59
|
if "default" in kwargs:
|
58
|
-
cast(ReviewKwargs[None], kwargs)["default"] = None
|
60
|
+
cast("ReviewKwargs[None]", kwargs)["default"] = None
|
59
61
|
return await self.propose(
|
60
62
|
obj.__class__,
|
61
63
|
TEMPLATE_MANAGER.render_template(
|
@@ -89,7 +91,7 @@ class Correct(Review):
|
|
89
91
|
await review_res.supervisor_check()
|
90
92
|
|
91
93
|
if "default" in kwargs:
|
92
|
-
cast(ReviewKwargs[None], kwargs)["default"] = None
|
94
|
+
cast("ReviewKwargs[None]", kwargs)["default"] = None
|
93
95
|
return await self.ageneric_string(
|
94
96
|
TEMPLATE_MANAGER.render_template(
|
95
97
|
configs.templates.correct_template, {"content": input_text, "review": review_res.display()}
|
@@ -113,3 +115,33 @@ class Correct(Review):
|
|
113
115
|
Optional[Task[T]]: The corrected task, or None if correction fails.
|
114
116
|
"""
|
115
117
|
return await self.correct_obj(task, **kwargs)
|
118
|
+
|
119
|
+
async def censor_obj[M: CensoredAble](
|
120
|
+
self, obj: M, **kwargs: Unpack[CensoredCorrectKwargs[ReviewResult[str]]]
|
121
|
+
) -> M:
|
122
|
+
"""Censor and correct an object based on defined criteria and templates.
|
123
|
+
|
124
|
+
Args:
|
125
|
+
obj (M): The object to be reviewed and corrected.
|
126
|
+
**kwargs (Unpack[CensoredCorrectKwargs]): Additional keyword
|
127
|
+
|
128
|
+
Returns:
|
129
|
+
M: The censored and corrected object.
|
130
|
+
"""
|
131
|
+
last_modified_obj = obj
|
132
|
+
modified_obj = None
|
133
|
+
rprint(obj.finalized_dump())
|
134
|
+
while await confirm("Begin to correct obj above with human censorship?").ask_async():
|
135
|
+
while (topic := await text("What is the topic of the obj reviewing?").ask_async()) is not None and topic:
|
136
|
+
...
|
137
|
+
if (
|
138
|
+
modified_obj := await self.correct_obj(
|
139
|
+
last_modified_obj,
|
140
|
+
topic=topic,
|
141
|
+
**kwargs,
|
142
|
+
)
|
143
|
+
) is None:
|
144
|
+
break
|
145
|
+
last_modified_obj = modified_obj
|
146
|
+
rprint(last_modified_obj.finalized_dump())
|
147
|
+
return modified_obj or last_modified_obj
|
fabricatio/capabilities/rag.py
CHANGED
@@ -19,6 +19,7 @@ from fabricatio.models.kwargs_types import (
|
|
19
19
|
EmbeddingKwargs,
|
20
20
|
FetchKwargs,
|
21
21
|
LLMKwargs,
|
22
|
+
RetrievalKwargs,
|
22
23
|
)
|
23
24
|
from fabricatio.models.usages import EmbeddingUsage
|
24
25
|
from fabricatio.models.utils import MilvusData, ok
|
@@ -213,6 +214,25 @@ class RAG(EmbeddingUsage):
|
|
213
214
|
self.add_document(await self.pack(text), collection_name or self.safe_target_collection, flush=True)
|
214
215
|
return self
|
215
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]: ...
|
216
236
|
async def afetch_document[V: (int, str, float, bytes)](
|
217
237
|
self,
|
218
238
|
vecs: List[List[float]],
|
@@ -275,7 +295,7 @@ class RAG(EmbeddingUsage):
|
|
275
295
|
if isinstance(query, str):
|
276
296
|
query = [query]
|
277
297
|
return cast(
|
278
|
-
List[str],
|
298
|
+
"List[str]",
|
279
299
|
await self.afetch_document(
|
280
300
|
vecs=(await self.vectorize(query)),
|
281
301
|
desired_fields="text",
|
@@ -283,6 +303,24 @@ class RAG(EmbeddingUsage):
|
|
283
303
|
),
|
284
304
|
)[:final_limit]
|
285
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
|
+
|
286
324
|
async def aask_retrieved(
|
287
325
|
self,
|
288
326
|
question: str,
|
@@ -313,16 +351,14 @@ class RAG(EmbeddingUsage):
|
|
313
351
|
Returns:
|
314
352
|
str: A string response generated after asking with the context of retrieved documents.
|
315
353
|
"""
|
316
|
-
|
354
|
+
rendered = await self.aretrieve_compact(
|
317
355
|
query or question,
|
318
|
-
final_limit,
|
356
|
+
final_limit=final_limit,
|
319
357
|
collection_name=collection_name,
|
320
358
|
result_per_query=result_per_query,
|
321
359
|
similarity_threshold=similarity_threshold,
|
322
360
|
)
|
323
361
|
|
324
|
-
rendered = TEMPLATE_MANAGER.render_template(configs.templates.retrieved_display_template, {"docs": docs[::-1]})
|
325
|
-
|
326
362
|
logger.debug(f"Retrieved Documents: \n{rendered}")
|
327
363
|
return await self.aask(
|
328
364
|
question,
|
@@ -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
|
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.
|
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.
|
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.
|
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.
|
313
|
+
**self.prepend_sys_msg(kwargs),
|
305
314
|
)
|
306
315
|
weights = [1]
|
307
316
|
for rw in relative_weights:
|