fabricatio 0.2.11.dev1__cp312-cp312-win_amd64.whl → 0.2.11.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.
- fabricatio/actions/article.py +20 -4
- fabricatio/actions/article_rag.py +129 -41
- fabricatio/decorators.py +27 -10
- fabricatio/models/action.py +14 -7
- fabricatio/models/extra/aricle_rag.py +6 -0
- fabricatio/models/extra/article_base.py +27 -8
- fabricatio/models/task.py +13 -1
- fabricatio/models/usages.py +1 -1
- fabricatio/rust.cp312-win_amd64.pyd +0 -0
- fabricatio/rust.pyi +126 -139
- fabricatio/utils.py +29 -10
- {fabricatio-0.2.11.dev1.data → fabricatio-0.2.11.dev3.data}/scripts/tdown.exe +0 -0
- {fabricatio-0.2.11.dev1.dist-info → fabricatio-0.2.11.dev3.dist-info}/METADATA +4 -2
- {fabricatio-0.2.11.dev1.dist-info → fabricatio-0.2.11.dev3.dist-info}/RECORD +16 -16
- {fabricatio-0.2.11.dev1.dist-info → fabricatio-0.2.11.dev3.dist-info}/WHEEL +0 -0
- {fabricatio-0.2.11.dev1.dist-info → fabricatio-0.2.11.dev3.dist-info}/licenses/LICENSE +0 -0
fabricatio/actions/article.py
CHANGED
@@ -149,10 +149,10 @@ class GenerateInitialOutline(Action, Extract):
|
|
149
149
|
async def _execute(
|
150
150
|
self,
|
151
151
|
article_proposal: ArticleProposal,
|
152
|
+
supervisor: Optional[bool] = None,
|
152
153
|
**_,
|
153
154
|
) -> Optional[ArticleOutline]:
|
154
|
-
|
155
|
-
f"{(article_proposal.as_prompt())}\n"
|
155
|
+
req = (
|
156
156
|
f"Design each chapter of a proper and academic and ready for release manner.\n"
|
157
157
|
f"You Must make sure every chapter have sections, and every section have subsections.\n"
|
158
158
|
f"Make the chapter and sections and subsections bing divided into a specific enough article component.\n"
|
@@ -160,14 +160,16 @@ class GenerateInitialOutline(Action, Extract):
|
|
160
160
|
f"Note that you SHALL use `{article_proposal.language}` as written language",
|
161
161
|
)
|
162
162
|
|
163
|
-
|
163
|
+
raw_outline = await self.aask(f"{(article_proposal.as_prompt())}\n{req}")
|
164
|
+
|
165
|
+
if supervisor or (supervisor is None and self.supervisor):
|
164
166
|
from questionary import confirm, text
|
165
167
|
|
166
168
|
r_print(raw_outline)
|
167
169
|
while not await confirm("Accept this version and continue?", default=True).ask_async():
|
168
170
|
imp = await text("Enter the improvement:").ask_async()
|
169
171
|
raw_outline = await self.aask(
|
170
|
-
f"{article_proposal.as_prompt()}\n{wrapp_in_block(raw_outline, 'Previous ArticleOutline')}\n{imp}"
|
172
|
+
f"{article_proposal.as_prompt()}\n{wrapp_in_block(raw_outline, 'Previous ArticleOutline')}\n{req}\n{wrapp_in_block(imp, title='Improvement')}"
|
171
173
|
)
|
172
174
|
r_print(raw_outline)
|
173
175
|
|
@@ -177,6 +179,20 @@ class GenerateInitialOutline(Action, Extract):
|
|
177
179
|
).update_ref(article_proposal)
|
178
180
|
|
179
181
|
|
182
|
+
class ExtractOutlineFromRaw(Action, Extract):
|
183
|
+
"""Extract the outline from the raw outline."""
|
184
|
+
|
185
|
+
output_key: str = "article_outline_from_raw"
|
186
|
+
|
187
|
+
async def _execute(self, article_outline_raw_path: str | Path, **cxt) -> ArticleOutline:
|
188
|
+
logger.info(f"Extracting outline from raw: {Path(article_outline_raw_path).as_posix()}")
|
189
|
+
|
190
|
+
return ok(
|
191
|
+
await self.extract(ArticleOutline, safe_text_read(article_outline_raw_path)),
|
192
|
+
"Could not extract the outline from raw.",
|
193
|
+
)
|
194
|
+
|
195
|
+
|
180
196
|
class FixIntrospectedErrors(Action, Censor):
|
181
197
|
"""Fix introspected errors in the article outline."""
|
182
198
|
|
@@ -8,6 +8,7 @@ from fabricatio import BibManager
|
|
8
8
|
from fabricatio.capabilities.censor import Censor
|
9
9
|
from fabricatio.capabilities.extract import Extract
|
10
10
|
from fabricatio.capabilities.rag import RAG
|
11
|
+
from fabricatio.decorators import precheck_package
|
11
12
|
from fabricatio.journal import logger
|
12
13
|
from fabricatio.models.action import Action
|
13
14
|
from fabricatio.models.extra.aricle_rag import ArticleChunk, CitationManager
|
@@ -15,7 +16,7 @@ from fabricatio.models.extra.article_essence import ArticleEssence
|
|
15
16
|
from fabricatio.models.extra.article_main import Article, ArticleChapter, ArticleSection, ArticleSubsection
|
16
17
|
from fabricatio.models.extra.article_outline import ArticleOutline
|
17
18
|
from fabricatio.models.extra.rule import RuleSet
|
18
|
-
from fabricatio.utils import ok
|
19
|
+
from fabricatio.utils import ask_retain, ok
|
19
20
|
|
20
21
|
|
21
22
|
class WriteArticleContentRAG(Action, RAG, Extract):
|
@@ -23,11 +24,14 @@ class WriteArticleContentRAG(Action, RAG, Extract):
|
|
23
24
|
|
24
25
|
ref_limit: int = 35
|
25
26
|
"""The limit of references to be retrieved"""
|
27
|
+
threshold: float = 0.55
|
28
|
+
"""The threshold of relevance"""
|
26
29
|
extractor_model: str
|
27
30
|
"""The model to use for extracting the content from the retrieved references."""
|
28
31
|
query_model: str
|
29
32
|
"""The model to use for querying the database"""
|
30
|
-
|
33
|
+
supervisor: bool = False
|
34
|
+
"""Whether to use supervisor mode"""
|
31
35
|
req: str = (
|
32
36
|
"citation number is REQUIRED to cite any reference!\n"
|
33
37
|
"Everything is build upon the typst language, which is similar to latex, \n"
|
@@ -40,31 +44,75 @@ class WriteArticleContentRAG(Action, RAG, Extract):
|
|
40
44
|
"you can refer to that label by using the syntax with prefix of `@eqt:`"
|
41
45
|
"Below is a usage example:\n"
|
42
46
|
"```typst\n"
|
43
|
-
"See @eqt:mass-energy-equation , it's the
|
47
|
+
"See @eqt:mass-energy-equation , it's the foundation of physics.\n"
|
44
48
|
"$$\n"
|
45
49
|
"E = m c^2"
|
46
50
|
"$$\n"
|
47
|
-
"<mass-energy-equation
|
48
|
-
"In @eqt:mass-energy-equation ,
|
51
|
+
"<mass-energy-equation>\n\n"
|
52
|
+
"In @eqt:mass-energy-equation , $m$ stands for mass, $c$ stands for speed of light, and $E$ stands for energy. \n"
|
49
53
|
"```"
|
50
54
|
)
|
51
55
|
|
52
56
|
async def _execute(
|
53
57
|
self,
|
54
58
|
article_outline: ArticleOutline,
|
55
|
-
writing_ruleset: RuleSet,
|
56
59
|
collection_name: str = "article_chunks",
|
60
|
+
supervisor: Optional[bool] = None,
|
57
61
|
**cxt,
|
58
62
|
) -> Article:
|
59
63
|
article = Article.from_outline(article_outline).update_ref(article_outline)
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
64
|
+
|
65
|
+
if supervisor or (supervisor is None and self.supervisor):
|
66
|
+
await gather(
|
67
|
+
*[
|
68
|
+
self._supervisor_inner(article, article_outline, chap, sec, subsec)
|
69
|
+
for chap, sec, subsec in article.iter_subsections()
|
70
|
+
]
|
71
|
+
)
|
72
|
+
else:
|
73
|
+
await gather(
|
74
|
+
*[
|
75
|
+
self._inner(article, article_outline, chap, sec, subsec)
|
76
|
+
for chap, sec, subsec in article.iter_subsections()
|
77
|
+
]
|
78
|
+
)
|
66
79
|
return article.convert_tex()
|
67
80
|
|
81
|
+
@precheck_package(
|
82
|
+
"questionary", "`questionary` is required for supervisor mode, please install it by `fabricatio[qa]`"
|
83
|
+
)
|
84
|
+
async def _supervisor_inner(
|
85
|
+
self,
|
86
|
+
article: Article,
|
87
|
+
article_outline: ArticleOutline,
|
88
|
+
chap: ArticleChapter,
|
89
|
+
sec: ArticleSection,
|
90
|
+
subsec: ArticleSubsection,
|
91
|
+
) -> ArticleSubsection:
|
92
|
+
from questionary import confirm, text
|
93
|
+
from rich import print as r_print
|
94
|
+
|
95
|
+
ret = await self.search_database(article, article_outline, chap, sec, subsec)
|
96
|
+
|
97
|
+
cm = CitationManager(article_chunks=await ask_retain([r.chunk for r in ret], ret)).set_cite_number_all()
|
98
|
+
|
99
|
+
raw = await self.write_raw(article, article_outline, chap, sec, subsec, cm)
|
100
|
+
r_print(raw)
|
101
|
+
|
102
|
+
while not await confirm("Accept this version and continue?").ask_async():
|
103
|
+
if await confirm("Search for more refs?").ask_async():
|
104
|
+
new_refs = await self.search_database(article, article_outline, chap, sec, subsec, supervisor=True)
|
105
|
+
cm.add_chunks(await ask_retain([r.chunk for r in new_refs], new_refs))
|
106
|
+
|
107
|
+
instruction = await text("Enter the instructions to improve").ask_async()
|
108
|
+
raw = await self.write_raw(article, article_outline, chap, sec, subsec, cm, instruction)
|
109
|
+
if await confirm("Edit it?").ask_async():
|
110
|
+
raw = await text("Edit", default=raw).ask_async() or raw
|
111
|
+
|
112
|
+
r_print(raw)
|
113
|
+
|
114
|
+
return await self.extract_new_subsec(subsec, raw, cm)
|
115
|
+
|
68
116
|
async def _inner(
|
69
117
|
self,
|
70
118
|
article: Article,
|
@@ -73,35 +121,17 @@ class WriteArticleContentRAG(Action, RAG, Extract):
|
|
73
121
|
sec: ArticleSection,
|
74
122
|
subsec: ArticleSubsection,
|
75
123
|
) -> ArticleSubsection:
|
76
|
-
|
77
|
-
|
78
|
-
f"{article_outline.display()}\n\nAbove is my article outline, I m writing graduate thesis titled `{article.title}`. "
|
79
|
-
f"More specifically, i m witting the Chapter `{chap.title}` >> Section `{sec.title}` >> Subsection `{subsec.title}`.\n"
|
80
|
-
f"I need to search related references to build up the content of the subsec mentioned above, which is `{subsec.title}`.\n"
|
81
|
-
f"plus, you can search required formulas by using latex equation code.\n"
|
82
|
-
f"provide 10 queries as possible, to get best result!\n"
|
83
|
-
f"You should provide both English version and chinese version of the refined queries!\n",
|
84
|
-
model=self.query_model,
|
85
|
-
),
|
86
|
-
"Failed to refine query.",
|
87
|
-
)
|
88
|
-
ret = await self.aretrieve(ref_q, ArticleChunk, final_limit=self.ref_limit, result_per_query=6)
|
89
|
-
ret.reverse()
|
90
|
-
cm = CitationManager().update_chunks(ret)
|
91
|
-
|
92
|
-
raw_paras = await self.aask(
|
93
|
-
f"{cm.as_prompt()}\nAbove is some related reference retrieved for you."
|
94
|
-
f"{article.referenced.display()}\n\nAbove is my article outline, I m writing graduate thesis titled `{article.title}`. "
|
95
|
-
f"More specifically, i m witting the Chapter `{chap.title}` >> Section `{sec.title}` >> Subsection `{subsec.title}`.\n"
|
96
|
-
f"Please help me write the paragraphs of the subsec mentioned above, which is `{subsec.title}`.\n"
|
97
|
-
f"{self.req}\n"
|
98
|
-
f"You SHALL use `{article.language}` as writing language."
|
99
|
-
)
|
124
|
+
ret = await self.search_database(article, article_outline, chap, sec, subsec)
|
125
|
+
cm = CitationManager(article_chunks=ret).set_cite_number_all()
|
100
126
|
|
101
|
-
raw_paras = (
|
102
|
-
|
103
|
-
)
|
127
|
+
raw_paras = await self.write_raw(article, article_outline, chap, sec, subsec, cm)
|
128
|
+
|
129
|
+
return await self.extract_new_subsec(subsec, raw_paras, cm)
|
104
130
|
|
131
|
+
async def extract_new_subsec(
|
132
|
+
self, subsec: ArticleSubsection, raw_paras: str, cm: CitationManager
|
133
|
+
) -> ArticleSubsection:
|
134
|
+
"""Extract the new subsec."""
|
105
135
|
new_subsec = ok(
|
106
136
|
await self.extract(
|
107
137
|
ArticleSubsection,
|
@@ -112,14 +142,72 @@ class WriteArticleContentRAG(Action, RAG, Extract):
|
|
112
142
|
),
|
113
143
|
"Failed to propose new subsection.",
|
114
144
|
)
|
115
|
-
|
116
145
|
for p in new_subsec.paragraphs:
|
117
146
|
p.content = cm.apply(p.content).replace("$$", "\n$$\n")
|
118
|
-
|
119
147
|
subsec.update_from(new_subsec)
|
120
148
|
logger.debug(f"{subsec.title}:rpl\n{subsec.display()}")
|
121
149
|
return subsec
|
122
150
|
|
151
|
+
async def write_raw(
|
152
|
+
self,
|
153
|
+
article: Article,
|
154
|
+
article_outline: ArticleOutline,
|
155
|
+
chap: ArticleChapter,
|
156
|
+
sec: ArticleSection,
|
157
|
+
subsec: ArticleSubsection,
|
158
|
+
cm: CitationManager,
|
159
|
+
extra_instruction: str = "",
|
160
|
+
) -> str:
|
161
|
+
"""Write the raw paragraphs of the subsec."""
|
162
|
+
return (
|
163
|
+
(
|
164
|
+
await self.aask(
|
165
|
+
f"{cm.as_prompt()}\nAbove is some related reference retrieved for you."
|
166
|
+
f"{article_outline.finalized_dump()}\n\nAbove is my article outline, I m writing graduate thesis titled `{article.title}`. "
|
167
|
+
f"More specifically, i m witting the Chapter `{chap.title}` >> Section `{sec.title}` >> Subsection `{subsec.title}`.\n"
|
168
|
+
f"Please help me write the paragraphs of the subsec mentioned above, which is `{subsec.title}`.\n"
|
169
|
+
f"{self.req}\n"
|
170
|
+
f"You SHALL use `{article.language}` as writing language.\n{extra_instruction}"
|
171
|
+
)
|
172
|
+
)
|
173
|
+
.replace(r" \( ", "$")
|
174
|
+
.replace(r" \) ", "$")
|
175
|
+
.replace(r"\(", "$")
|
176
|
+
.replace(r"\)", "$")
|
177
|
+
.replace("\\[\n", "$$\n")
|
178
|
+
.replace("\n\\]", "\n$$")
|
179
|
+
)
|
180
|
+
|
181
|
+
async def search_database(
|
182
|
+
self,
|
183
|
+
article: Article,
|
184
|
+
article_outline: ArticleOutline,
|
185
|
+
chap: ArticleChapter,
|
186
|
+
sec: ArticleSection,
|
187
|
+
subsec: ArticleSubsection,
|
188
|
+
extra_instruction: str = "",
|
189
|
+
supervisor: bool = False,
|
190
|
+
) -> List[ArticleChunk]:
|
191
|
+
"""Search database for related references."""
|
192
|
+
ref_q = ok(
|
193
|
+
await self.arefined_query(
|
194
|
+
f"{article_outline.finalized_dump()}\n\nAbove is my article outline, I m writing graduate thesis titled `{article.title}`. "
|
195
|
+
f"More specifically, i m witting the Chapter `{chap.title}` >> Section `{sec.title}` >> Subsection `{subsec.title}`.\n"
|
196
|
+
f"I need to search related references to build up the content of the subsec mentioned above, which is `{subsec.title}`.\n"
|
197
|
+
f"provide 10~16 queries as possible, to get best result!\n"
|
198
|
+
f"You should provide both English version and chinese version of the refined queries!\n{extra_instruction}\n",
|
199
|
+
model=self.query_model,
|
200
|
+
),
|
201
|
+
"Failed to refine query.",
|
202
|
+
)
|
203
|
+
|
204
|
+
if supervisor:
|
205
|
+
ref_q = await ask_retain(ref_q)
|
206
|
+
|
207
|
+
return await self.aretrieve(
|
208
|
+
ref_q, ArticleChunk, final_limit=self.ref_limit, result_per_query=3, similarity_threshold=self.threshold
|
209
|
+
)
|
210
|
+
|
123
211
|
|
124
212
|
class TweakArticleRAG(Action, RAG, Censor):
|
125
213
|
"""Write an article based on the provided outline.
|
fabricatio/decorators.py
CHANGED
@@ -6,7 +6,7 @@ from importlib.util import find_spec
|
|
6
6
|
from inspect import signature
|
7
7
|
from shutil import which
|
8
8
|
from types import ModuleType
|
9
|
-
from typing import Callable, List, Optional
|
9
|
+
from typing import Callable, Coroutine, List, Optional
|
10
10
|
|
11
11
|
from fabricatio.config import configs
|
12
12
|
from fabricatio.journal import logger
|
@@ -23,7 +23,20 @@ def precheck_package[**P, R](package_name: str, msg: str) -> Callable[[Callable[
|
|
23
23
|
bool: True if the package exists, False otherwise.
|
24
24
|
"""
|
25
25
|
|
26
|
-
def _wrapper(
|
26
|
+
def _wrapper(
|
27
|
+
func: Callable[P, R] | Callable[P, Coroutine[None, None, R]],
|
28
|
+
) -> Callable[P, R] | Callable[P, Coroutine[None, None, R]]:
|
29
|
+
if iscoroutinefunction(func):
|
30
|
+
|
31
|
+
@wraps(func)
|
32
|
+
async def _async_inner(*args: P.args, **kwargs: P.kwargs) -> R:
|
33
|
+
if find_spec(package_name):
|
34
|
+
return await func(*args, **kwargs)
|
35
|
+
raise RuntimeError(msg)
|
36
|
+
|
37
|
+
return _async_inner
|
38
|
+
|
39
|
+
@wraps(func)
|
27
40
|
def _inner(*args: P.args, **kwargs: P.kwargs) -> R:
|
28
41
|
if find_spec(package_name):
|
29
42
|
return func(*args, **kwargs)
|
@@ -35,7 +48,7 @@ def precheck_package[**P, R](package_name: str, msg: str) -> Callable[[Callable[
|
|
35
48
|
|
36
49
|
|
37
50
|
def depend_on_external_cmd[**P, R](
|
38
|
-
|
51
|
+
bin_name: str, install_tip: Optional[str], homepage: Optional[str] = None
|
39
52
|
) -> Callable[[Callable[P, R]], Callable[P, R]]:
|
40
53
|
"""Decorator to check for the presence of an external command.
|
41
54
|
|
@@ -88,8 +101,9 @@ def logging_execution_info[**P, R](func: Callable[P, R]) -> Callable[P, R]:
|
|
88
101
|
return _wrapper
|
89
102
|
|
90
103
|
|
91
|
-
@precheck_package(
|
92
|
-
|
104
|
+
@precheck_package(
|
105
|
+
"questionary", "'questionary' is required to run this function. Have you installed `fabricatio[qa]`?."
|
106
|
+
)
|
93
107
|
def confirm_to_execute[**P, R](func: Callable[P, R]) -> Callable[P, Optional[R]] | Callable[P, R]:
|
94
108
|
"""Decorator to confirm before executing a function.
|
95
109
|
|
@@ -109,8 +123,8 @@ def confirm_to_execute[**P, R](func: Callable[P, R]) -> Callable[P, Optional[R]]
|
|
109
123
|
@wraps(func)
|
110
124
|
async def _wrapper(*args: P.args, **kwargs: P.kwargs) -> Optional[R]:
|
111
125
|
if await confirm(
|
112
|
-
|
113
|
-
|
126
|
+
f"Are you sure to execute function: {func.__name__}{signature(func)} \n📦 Args:{args}\n🔑 Kwargs:{kwargs}\n",
|
127
|
+
instruction="Please input [Yes/No] to proceed (default: Yes):",
|
114
128
|
).ask_async():
|
115
129
|
return await func(*args, **kwargs)
|
116
130
|
logger.warning(f"Function: {func.__name__}{signature(func)} canceled by user.")
|
@@ -121,8 +135,8 @@ def confirm_to_execute[**P, R](func: Callable[P, R]) -> Callable[P, Optional[R]]
|
|
121
135
|
@wraps(func)
|
122
136
|
def _wrapper(*args: P.args, **kwargs: P.kwargs) -> Optional[R]:
|
123
137
|
if confirm(
|
124
|
-
|
125
|
-
|
138
|
+
f"Are you sure to execute function: {func.__name__}{signature(func)} \n📦 Args:{args}\n��� Kwargs:{kwargs}\n",
|
139
|
+
instruction="Please input [Yes/No] to proceed (default: Yes):",
|
126
140
|
).ask():
|
127
141
|
return func(*args, **kwargs)
|
128
142
|
logger.warning(f"Function: {func.__name__}{signature(func)} canceled by user.")
|
@@ -203,7 +217,9 @@ def use_temp_module[**P, R](modules: ModuleType | List[ModuleType]) -> Callable[
|
|
203
217
|
return _decorator
|
204
218
|
|
205
219
|
|
206
|
-
def logging_exec_time[**P, R](
|
220
|
+
def logging_exec_time[**P, R](
|
221
|
+
func: Callable[P, R] | Callable[P, Coroutine[None, None, R]],
|
222
|
+
) -> Callable[P, R] | Callable[P, Coroutine[None, None, R]]:
|
207
223
|
"""Decorator to log the execution time of a function.
|
208
224
|
|
209
225
|
Args:
|
@@ -215,6 +231,7 @@ def logging_exec_time[**P, R](func: Callable[P, R]) -> Callable[P, R]:
|
|
215
231
|
from time import time
|
216
232
|
|
217
233
|
if iscoroutinefunction(func):
|
234
|
+
|
218
235
|
@wraps(func)
|
219
236
|
async def _async_wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
|
220
237
|
start_time = time()
|
fabricatio/models/action.py
CHANGED
@@ -18,6 +18,7 @@ from fabricatio.journal import logger
|
|
18
18
|
from fabricatio.models.generic import WithBriefing
|
19
19
|
from fabricatio.models.task import Task
|
20
20
|
from fabricatio.models.usages import LLMUsage, ToolBoxUsage
|
21
|
+
from fabricatio.utils import override_kwargs
|
21
22
|
from pydantic import Field, PrivateAttr
|
22
23
|
|
23
24
|
OUTPUT_KEY = "task_output"
|
@@ -55,7 +56,7 @@ class Action(WithBriefing, LLMUsage):
|
|
55
56
|
self.description = self.description or self.__class__.__doc__ or ""
|
56
57
|
|
57
58
|
@abstractmethod
|
58
|
-
async def _execute(self, *_:Any, **cxt) -> Any:
|
59
|
+
async def _execute(self, *_: Any, **cxt) -> Any:
|
59
60
|
"""Implement the core logic of the action.
|
60
61
|
|
61
62
|
Args:
|
@@ -95,11 +96,12 @@ class Action(WithBriefing, LLMUsage):
|
|
95
96
|
return f"## Your personality: \n{self.personality}\n# The action you are going to perform: \n{super().briefing}"
|
96
97
|
return f"# The action you are going to perform: \n{super().briefing}"
|
97
98
|
|
98
|
-
def to_task_output(self)->Self:
|
99
|
+
def to_task_output(self) -> Self:
|
99
100
|
"""Set the output key to OUTPUT_KEY and return the action instance."""
|
100
|
-
self.output_key=OUTPUT_KEY
|
101
|
+
self.output_key = OUTPUT_KEY
|
101
102
|
return self
|
102
103
|
|
104
|
+
|
103
105
|
class WorkFlow(WithBriefing, ToolBoxUsage):
|
104
106
|
"""Manages sequences of actions to fulfill tasks.
|
105
107
|
|
@@ -177,7 +179,7 @@ class WorkFlow(WithBriefing, ToolBoxUsage):
|
|
177
179
|
current_action = None
|
178
180
|
try:
|
179
181
|
# Process each action in sequence
|
180
|
-
for i,step in enumerate(self._instances):
|
182
|
+
for i, step in enumerate(self._instances):
|
181
183
|
current_action = step.name
|
182
184
|
logger.info(f"Executing step [{i}] >> {current_action}")
|
183
185
|
|
@@ -227,8 +229,13 @@ class WorkFlow(WithBriefing, ToolBoxUsage):
|
|
227
229
|
- Any extra_init_context values
|
228
230
|
"""
|
229
231
|
logger.debug(f"Initializing context for workflow: {self.name}")
|
230
|
-
|
231
|
-
|
232
|
+
ctx = override_kwargs(self.extra_init_context, **task.extra_init_context)
|
233
|
+
if self.task_input_key in ctx:
|
234
|
+
raise ValueError(
|
235
|
+
f"Task input key: `{self.task_input_key}`, which is reserved, is already set in the init context"
|
236
|
+
)
|
237
|
+
|
238
|
+
await self._context.put({self.task_input_key: task, **ctx})
|
232
239
|
|
233
240
|
def steps_fallback_to_self(self) -> Self:
|
234
241
|
"""Configure all steps to use this workflow's configuration as fallback.
|
@@ -245,7 +252,7 @@ class WorkFlow(WithBriefing, ToolBoxUsage):
|
|
245
252
|
Returns:
|
246
253
|
Self: The workflow instance for method chaining.
|
247
254
|
"""
|
248
|
-
self.provide_tools_to(i for i in self._instances if isinstance(i,ToolBoxUsage))
|
255
|
+
self.provide_tools_to(i for i in self._instances if isinstance(i, ToolBoxUsage))
|
249
256
|
return self
|
250
257
|
|
251
258
|
def update_init_context(self, /, **kwargs) -> Self:
|
@@ -190,6 +190,12 @@ class CitationManager(AsPrompt):
|
|
190
190
|
self.set_cite_number_all()
|
191
191
|
return self
|
192
192
|
|
193
|
+
def add_chunks(self, article_chunks: List[ArticleChunk], set_cite_number: bool = True)-> Self:
|
194
|
+
"""Add article chunks."""
|
195
|
+
self.article_chunks.extend(article_chunks)
|
196
|
+
if set_cite_number:
|
197
|
+
self.set_cite_number_all()
|
198
|
+
return self
|
193
199
|
def set_cite_number_all(self) -> Self:
|
194
200
|
"""Set citation numbers for all article chunks."""
|
195
201
|
for i, a in enumerate(self.article_chunks, 1):
|
@@ -18,6 +18,7 @@ from fabricatio.models.generic import (
|
|
18
18
|
Titled,
|
19
19
|
WordCount,
|
20
20
|
)
|
21
|
+
from fabricatio.rust import comment
|
21
22
|
from pydantic import Field
|
22
23
|
|
23
24
|
|
@@ -29,11 +30,9 @@ class ReferringType(StrEnum):
|
|
29
30
|
SUBSECTION = "subsection"
|
30
31
|
|
31
32
|
|
32
|
-
|
33
33
|
type RefKey = Tuple[str, Optional[str], Optional[str]]
|
34
34
|
|
35
35
|
|
36
|
-
|
37
36
|
class ArticleMetaData(SketchedAble, Described, WordCount, Titled, Language):
|
38
37
|
"""Metadata for an article component."""
|
39
38
|
|
@@ -48,8 +47,6 @@ class ArticleMetaData(SketchedAble, Described, WordCount, Titled, Language):
|
|
48
47
|
"""List of writing aims of the research component in academic style."""
|
49
48
|
|
50
49
|
|
51
|
-
|
52
|
-
|
53
50
|
class ArticleOutlineBase(
|
54
51
|
ArticleMetaData,
|
55
52
|
ResolveUpdateConflict,
|
@@ -92,7 +89,13 @@ class SubSectionBase(ArticleOutlineBase):
|
|
92
89
|
|
93
90
|
def to_typst_code(self) -> str:
|
94
91
|
"""Converts the component into a Typst code snippet for rendering."""
|
95
|
-
return
|
92
|
+
return (
|
93
|
+
f"=== {self.title}\n"
|
94
|
+
f"{comment(f'Desc:\n{self.description}\nAims:\n{"\n".join(self.aims)}')}\n"
|
95
|
+
+ f"Expected Word Count:{self.expected_word_count}"
|
96
|
+
if self.expected_word_count
|
97
|
+
else ""
|
98
|
+
)
|
96
99
|
|
97
100
|
def introspect(self) -> str:
|
98
101
|
"""Introspects the article subsection outline."""
|
@@ -117,7 +120,13 @@ class SectionBase[T: SubSectionBase](ArticleOutlineBase):
|
|
117
120
|
Returns:
|
118
121
|
str: The formatted Typst code snippet.
|
119
122
|
"""
|
120
|
-
return
|
123
|
+
return (
|
124
|
+
f"== {self.title}\n"
|
125
|
+
f"{comment(f'Desc:\n{self.description}\nAims:\n{"\n".join(self.aims)}')}\n"
|
126
|
+
+ f"Expected Word Count:{self.expected_word_count}"
|
127
|
+
if self.expected_word_count
|
128
|
+
else ""
|
129
|
+
) + "\n\n".join(subsec.to_typst_code() for subsec in self.subsections)
|
121
130
|
|
122
131
|
def resolve_update_conflict(self, other: Self) -> str:
|
123
132
|
"""Resolve update errors in the article outline."""
|
@@ -160,7 +169,13 @@ class ChapterBase[T: SectionBase](ArticleOutlineBase):
|
|
160
169
|
|
161
170
|
def to_typst_code(self) -> str:
|
162
171
|
"""Converts the chapter into a Typst formatted code snippet for rendering."""
|
163
|
-
return
|
172
|
+
return (
|
173
|
+
f"= {self.title}\n"
|
174
|
+
f"{comment(f'Desc:\n{self.description}\nAims:\n{"\n".join(self.aims)}')}\n"
|
175
|
+
+ f"Expected Word Count:{self.expected_word_count}"
|
176
|
+
if self.expected_word_count
|
177
|
+
else ""
|
178
|
+
) + "\n\n".join(sec.to_typst_code() for sec in self.sections)
|
164
179
|
|
165
180
|
def resolve_update_conflict(self, other: Self) -> str:
|
166
181
|
"""Resolve update errors in the article outline."""
|
@@ -302,4 +317,8 @@ class ArticleBase[T: ChapterBase](FinalizedDumpAble, AsPrompt, WordCount, Descri
|
|
302
317
|
=== Implementation Details
|
303
318
|
== Evaluation Protocol
|
304
319
|
"""
|
305
|
-
return
|
320
|
+
return comment(
|
321
|
+
f"Title:{self.title}\nDesc:\n{self.description}\n" + f"Word Count:{self.expected_word_count}"
|
322
|
+
if self.expected_word_count
|
323
|
+
else ""
|
324
|
+
) + "\n\n".join(a.to_typst_code() for a in self.chapters)
|
fabricatio/models/task.py
CHANGED
@@ -4,7 +4,7 @@ It includes methods to manage the task's lifecycle, such as starting, finishing,
|
|
4
4
|
"""
|
5
5
|
|
6
6
|
from asyncio import Queue
|
7
|
-
from typing import Any, List, Optional, Self
|
7
|
+
from typing import Any, Dict, List, Optional, Self
|
8
8
|
|
9
9
|
from fabricatio.config import configs
|
10
10
|
from fabricatio.constants import TaskStatus
|
@@ -50,6 +50,18 @@ class Task[T](WithBriefing, ProposedAble, WithDependency):
|
|
50
50
|
|
51
51
|
_namespace: Event = PrivateAttr(default_factory=Event)
|
52
52
|
"""The namespace of the task as an event, which is generated from the namespace list."""
|
53
|
+
_extra_init_context: Dict = PrivateAttr(default_factory=dict)
|
54
|
+
"""Extra initialization context for the task, which is designed to override the one of the Workflow."""
|
55
|
+
|
56
|
+
@property
|
57
|
+
def extra_init_context(self) -> Dict:
|
58
|
+
"""Extra initialization context for the task, which is designed to override the one of the Workflow."""
|
59
|
+
return self._extra_init_context
|
60
|
+
|
61
|
+
def update_init_context(self, /, **kwargs) -> Self:
|
62
|
+
"""Update the extra initialization context for the task."""
|
63
|
+
self.extra_init_context.update(kwargs)
|
64
|
+
return self
|
53
65
|
|
54
66
|
def model_post_init(self, __context: Any) -> None:
|
55
67
|
"""Initialize the task with a namespace event."""
|
fabricatio/models/usages.py
CHANGED
@@ -31,7 +31,7 @@ from pydantic import BaseModel, ConfigDict, Field, NonNegativeInt, PositiveInt
|
|
31
31
|
|
32
32
|
if configs.cache.enabled and configs.cache.type:
|
33
33
|
litellm.enable_cache(type=configs.cache.type, **configs.cache.params)
|
34
|
-
logger.
|
34
|
+
logger.debug(f"{configs.cache.type.name} Cache enabled")
|
35
35
|
|
36
36
|
ROUTER = Router(
|
37
37
|
routing_strategy="usage-based-routing-v2",
|
Binary file
|
fabricatio/rust.pyi
CHANGED
@@ -24,7 +24,7 @@ class TemplateManager:
|
|
24
24
|
"""
|
25
25
|
|
26
26
|
def __init__(
|
27
|
-
|
27
|
+
self, template_dirs: List[Path], suffix: Optional[str] = None, active_loading: Optional[bool] = None
|
28
28
|
) -> None:
|
29
29
|
"""Initialize the template manager.
|
30
30
|
|
@@ -55,13 +55,9 @@ class TemplateManager:
|
|
55
55
|
"""
|
56
56
|
|
57
57
|
@overload
|
58
|
-
def render_template(self, name: str, data: Dict[str, Any]) -> str:
|
59
|
-
...
|
60
|
-
|
58
|
+
def render_template(self, name: str, data: Dict[str, Any]) -> str: ...
|
61
59
|
@overload
|
62
|
-
def render_template(self, name: str, data: List[Dict[str, Any]]) -> List[str]:
|
63
|
-
...
|
64
|
-
|
60
|
+
def render_template(self, name: str, data: List[Dict[str, Any]]) -> List[str]: ...
|
65
61
|
def render_template(self, name: str, data: Dict[str, Any] | List[Dict[str, Any]]) -> str | List[str]:
|
66
62
|
"""Render a template with context data.
|
67
63
|
|
@@ -77,13 +73,9 @@ class TemplateManager:
|
|
77
73
|
"""
|
78
74
|
|
79
75
|
@overload
|
80
|
-
def render_template_raw(self, template: str, data: Dict[str, Any]) -> str:
|
81
|
-
...
|
82
|
-
|
76
|
+
def render_template_raw(self, template: str, data: Dict[str, Any]) -> str: ...
|
83
77
|
@overload
|
84
|
-
def render_template_raw(self, template: str, data: List[Dict[str, Any]]) -> List[str]:
|
85
|
-
...
|
86
|
-
|
78
|
+
def render_template_raw(self, template: str, data: List[Dict[str, Any]]) -> List[str]: ...
|
87
79
|
def render_template_raw(self, template: str, data: Dict[str, Any] | List[Dict[str, Any]]) -> str | List[str]:
|
88
80
|
"""Render a template with context data.
|
89
81
|
|
@@ -95,6 +87,113 @@ class TemplateManager:
|
|
95
87
|
Rendered template content as string or list of strings
|
96
88
|
"""
|
97
89
|
|
90
|
+
class BibManager:
|
91
|
+
"""BibTeX bibliography manager for parsing and querying citation data."""
|
92
|
+
|
93
|
+
def __init__(self, path: str) -> None:
|
94
|
+
"""Initialize the bibliography manager.
|
95
|
+
|
96
|
+
Args:
|
97
|
+
path: Path to BibTeX (.bib) file to load
|
98
|
+
|
99
|
+
Raises:
|
100
|
+
RuntimeError: If file cannot be read or parsed
|
101
|
+
"""
|
102
|
+
|
103
|
+
def get_cite_key_by_title(self, title: str) -> Optional[str]:
|
104
|
+
"""Find citation key by exact title match.
|
105
|
+
|
106
|
+
Args:
|
107
|
+
title: Full title to search for (case-insensitive)
|
108
|
+
|
109
|
+
Returns:
|
110
|
+
Citation key if exact match found, None otherwise
|
111
|
+
"""
|
112
|
+
|
113
|
+
def get_cite_key_by_title_fuzzy(self, title: str) -> Optional[str]:
|
114
|
+
"""Find citation key by fuzzy title match.
|
115
|
+
|
116
|
+
Args:
|
117
|
+
title: Search term to find in bibliography entries
|
118
|
+
|
119
|
+
Returns:
|
120
|
+
Citation key of best matching entry, or None if no good match
|
121
|
+
"""
|
122
|
+
|
123
|
+
def get_cite_key_fuzzy(self, query: str) -> Optional[str]:
|
124
|
+
"""Find best matching citation using fuzzy text search.
|
125
|
+
|
126
|
+
Args:
|
127
|
+
query: Search term to find in bibliography entries
|
128
|
+
|
129
|
+
Returns:
|
130
|
+
Citation key of best matching entry, or None if no good match
|
131
|
+
|
132
|
+
Notes:
|
133
|
+
Uses nucleo_matcher for high-quality fuzzy text searching
|
134
|
+
See: https://crates.io/crates/nucleo-matcher
|
135
|
+
"""
|
136
|
+
|
137
|
+
def list_titles(self, is_verbatim: Optional[bool] = False) -> List[str]:
|
138
|
+
"""List all titles in the bibliography.
|
139
|
+
|
140
|
+
Args:
|
141
|
+
is_verbatim: Whether to return verbatim titles (without formatting)
|
142
|
+
|
143
|
+
Returns:
|
144
|
+
List of all titles in the bibliography
|
145
|
+
"""
|
146
|
+
|
147
|
+
def get_author_by_key(self, key: str) -> Optional[List[str]]:
|
148
|
+
"""Retrieve authors by citation key.
|
149
|
+
|
150
|
+
Args:
|
151
|
+
key: Citation key
|
152
|
+
|
153
|
+
Returns:
|
154
|
+
List of authors if found, None otherwise
|
155
|
+
"""
|
156
|
+
|
157
|
+
def get_year_by_key(self, key: str) -> Optional[int]:
|
158
|
+
"""Retrieve the publication year by citation key.
|
159
|
+
|
160
|
+
Args:
|
161
|
+
key: Citation key
|
162
|
+
|
163
|
+
Returns:
|
164
|
+
Publication year if found, None otherwise
|
165
|
+
"""
|
166
|
+
|
167
|
+
def get_abstract_by_key(self, key: str) -> Optional[str]:
|
168
|
+
"""Retrieve the abstract by citation key.
|
169
|
+
|
170
|
+
Args:
|
171
|
+
key: Citation key
|
172
|
+
|
173
|
+
Returns:
|
174
|
+
Abstract if found, None otherwise
|
175
|
+
"""
|
176
|
+
|
177
|
+
def get_title_by_key(self, key: str) -> Optional[str]:
|
178
|
+
"""Retrieve the title by citation key.
|
179
|
+
|
180
|
+
Args:
|
181
|
+
key: Citation key
|
182
|
+
|
183
|
+
Returns:
|
184
|
+
Title if found, None otherwise
|
185
|
+
"""
|
186
|
+
|
187
|
+
def get_field_by_key(self, key: str, field: str) -> Optional[str]:
|
188
|
+
"""Retrieve a specific field by citation key.
|
189
|
+
|
190
|
+
Args:
|
191
|
+
key: Citation key
|
192
|
+
field: Field name
|
193
|
+
|
194
|
+
Returns:
|
195
|
+
Field value if found, None otherwise
|
196
|
+
"""
|
98
197
|
|
99
198
|
def blake3_hash(content: bytes) -> str:
|
100
199
|
"""Calculate the BLAKE3 cryptographic hash of data.
|
@@ -106,11 +205,9 @@ def blake3_hash(content: bytes) -> str:
|
|
106
205
|
Hex-encoded BLAKE3 hash string
|
107
206
|
"""
|
108
207
|
|
109
|
-
|
110
208
|
def detect_language(string: str) -> str:
|
111
209
|
"""Detect the language of a given string."""
|
112
210
|
|
113
|
-
|
114
211
|
def split_word_bounds(string: str) -> List[str]:
|
115
212
|
"""Split the string into words based on word boundaries.
|
116
213
|
|
@@ -121,7 +218,6 @@ def split_word_bounds(string: str) -> List[str]:
|
|
121
218
|
A list of words extracted from the string.
|
122
219
|
"""
|
123
220
|
|
124
|
-
|
125
221
|
def split_sentence_bounds(string: str) -> List[str]:
|
126
222
|
"""Split the string into sentences based on sentence boundaries.
|
127
223
|
|
@@ -132,7 +228,6 @@ def split_sentence_bounds(string: str) -> List[str]:
|
|
132
228
|
A list of sentences extracted from the string.
|
133
229
|
"""
|
134
230
|
|
135
|
-
|
136
231
|
def split_into_chunks(string: str, max_chunk_size: int, max_overlapping_rate: float = 0.3) -> List[str]:
|
137
232
|
"""Split the string into chunks of a specified size.
|
138
233
|
|
@@ -145,7 +240,6 @@ def split_into_chunks(string: str, max_chunk_size: int, max_overlapping_rate: fl
|
|
145
240
|
A list of chunks extracted from the string.
|
146
241
|
"""
|
147
242
|
|
148
|
-
|
149
243
|
def word_count(string: str) -> int:
|
150
244
|
"""Count the number of words in the string.
|
151
245
|
|
@@ -156,67 +250,51 @@ def word_count(string: str) -> int:
|
|
156
250
|
The number of words in the string.
|
157
251
|
"""
|
158
252
|
|
159
|
-
|
160
253
|
def is_chinese(string: str) -> bool:
|
161
254
|
"""Check if the given string is in Chinese."""
|
162
255
|
|
163
|
-
|
164
256
|
def is_english(string: str) -> bool:
|
165
257
|
"""Check if the given string is in English."""
|
166
258
|
|
167
|
-
|
168
259
|
def is_japanese(string: str) -> bool:
|
169
260
|
"""Check if the given string is in Japanese."""
|
170
261
|
|
171
|
-
|
172
262
|
def is_korean(string: str) -> bool:
|
173
263
|
"""Check if the given string is in Korean."""
|
174
264
|
|
175
|
-
|
176
265
|
def is_arabic(string: str) -> bool:
|
177
266
|
"""Check if the given string is in Arabic."""
|
178
267
|
|
179
|
-
|
180
268
|
def is_russian(string: str) -> bool:
|
181
269
|
"""Check if the given string is in Russian."""
|
182
270
|
|
183
|
-
|
184
271
|
def is_german(string: str) -> bool:
|
185
272
|
"""Check if the given string is in German."""
|
186
273
|
|
187
|
-
|
188
274
|
def is_french(string: str) -> bool:
|
189
275
|
"""Check if the given string is in French."""
|
190
276
|
|
191
|
-
|
192
277
|
def is_hindi(string: str) -> bool:
|
193
278
|
"""Check if the given string is in Hindi."""
|
194
279
|
|
195
|
-
|
196
280
|
def is_italian(string: str) -> bool:
|
197
281
|
"""Check if the given string is in Italian."""
|
198
282
|
|
199
|
-
|
200
283
|
def is_dutch(string: str) -> bool:
|
201
284
|
"""Check if the given string is in Dutch."""
|
202
285
|
|
203
|
-
|
204
286
|
def is_portuguese(string: str) -> bool:
|
205
287
|
"""Check if the given string is in Portuguese."""
|
206
288
|
|
207
|
-
|
208
289
|
def is_swedish(string: str) -> bool:
|
209
290
|
"""Check if the given string is in Swedish."""
|
210
291
|
|
211
|
-
|
212
292
|
def is_turkish(string: str) -> bool:
|
213
293
|
"""Check if the given string is in Turkish."""
|
214
294
|
|
215
|
-
|
216
295
|
def is_vietnamese(string: str) -> bool:
|
217
296
|
"""Check if the given string is in Vietnamese."""
|
218
297
|
|
219
|
-
|
220
298
|
def tex_to_typst(string: str) -> str:
|
221
299
|
"""Convert TeX to Typst.
|
222
300
|
|
@@ -227,7 +305,6 @@ def tex_to_typst(string: str) -> str:
|
|
227
305
|
The converted Typst string.
|
228
306
|
"""
|
229
307
|
|
230
|
-
|
231
308
|
def convert_all_inline_tex(string: str) -> str:
|
232
309
|
"""Convert all inline TeX code in the string.
|
233
310
|
|
@@ -238,7 +315,6 @@ def convert_all_inline_tex(string: str) -> str:
|
|
238
315
|
The converted string with inline TeX code replaced.
|
239
316
|
"""
|
240
317
|
|
241
|
-
|
242
318
|
def convert_all_block_tex(string: str) -> str:
|
243
319
|
"""Convert all block TeX code in the string.
|
244
320
|
|
@@ -249,111 +325,22 @@ def convert_all_block_tex(string: str) -> str:
|
|
249
325
|
The converted string with block TeX code replaced.
|
250
326
|
"""
|
251
327
|
|
328
|
+
def comment(string: str) -> str:
|
329
|
+
"""Add comment to the string.
|
252
330
|
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
def __init__(self, path: str) -> None:
|
257
|
-
"""Initialize the bibliography manager.
|
258
|
-
|
259
|
-
Args:
|
260
|
-
path: Path to BibTeX (.bib) file to load
|
261
|
-
|
262
|
-
Raises:
|
263
|
-
RuntimeError: If file cannot be read or parsed
|
264
|
-
"""
|
265
|
-
|
266
|
-
def get_cite_key_by_title(self, title: str) -> Optional[str]:
|
267
|
-
"""Find citation key by exact title match.
|
268
|
-
|
269
|
-
Args:
|
270
|
-
title: Full title to search for (case-insensitive)
|
271
|
-
|
272
|
-
Returns:
|
273
|
-
Citation key if exact match found, None otherwise
|
274
|
-
"""
|
275
|
-
|
276
|
-
def get_cite_key_by_title_fuzzy(self, title: str) -> Optional[str]:
|
277
|
-
"""Find citation key by fuzzy title match.
|
278
|
-
|
279
|
-
Args:
|
280
|
-
title: Search term to find in bibliography entries
|
281
|
-
|
282
|
-
Returns:
|
283
|
-
Citation key of best matching entry, or None if no good match
|
284
|
-
"""
|
285
|
-
|
286
|
-
def get_cite_key_fuzzy(self, query: str) -> Optional[str]:
|
287
|
-
"""Find best matching citation using fuzzy text search.
|
288
|
-
|
289
|
-
Args:
|
290
|
-
query: Search term to find in bibliography entries
|
291
|
-
|
292
|
-
Returns:
|
293
|
-
Citation key of best matching entry, or None if no good match
|
294
|
-
|
295
|
-
Notes:
|
296
|
-
Uses nucleo_matcher for high-quality fuzzy text searching
|
297
|
-
See: https://crates.io/crates/nucleo-matcher
|
298
|
-
"""
|
299
|
-
|
300
|
-
def list_titles(self, is_verbatim: Optional[bool] = False) -> List[str]:
|
301
|
-
"""List all titles in the bibliography.
|
302
|
-
|
303
|
-
Args:
|
304
|
-
is_verbatim: Whether to return verbatim titles (without formatting)
|
305
|
-
|
306
|
-
Returns:
|
307
|
-
List of all titles in the bibliography
|
308
|
-
"""
|
309
|
-
|
310
|
-
def get_author_by_key(self, key: str) -> Optional[List[str]]:
|
311
|
-
"""Retrieve authors by citation key.
|
312
|
-
|
313
|
-
Args:
|
314
|
-
key: Citation key
|
315
|
-
|
316
|
-
Returns:
|
317
|
-
List of authors if found, None otherwise
|
318
|
-
"""
|
319
|
-
|
320
|
-
def get_year_by_key(self, key: str) -> Optional[int]:
|
321
|
-
"""Retrieve the publication year by citation key.
|
322
|
-
|
323
|
-
Args:
|
324
|
-
key: Citation key
|
325
|
-
|
326
|
-
Returns:
|
327
|
-
Publication year if found, None otherwise
|
328
|
-
"""
|
329
|
-
|
330
|
-
def get_abstract_by_key(self, key: str) -> Optional[str]:
|
331
|
-
"""Retrieve the abstract by citation key.
|
332
|
-
|
333
|
-
Args:
|
334
|
-
key: Citation key
|
335
|
-
|
336
|
-
Returns:
|
337
|
-
Abstract if found, None otherwise
|
338
|
-
"""
|
339
|
-
|
340
|
-
def get_title_by_key(self, key: str) -> Optional[str]:
|
341
|
-
"""Retrieve the title by citation key.
|
342
|
-
|
343
|
-
Args:
|
344
|
-
key: Citation key
|
331
|
+
Args:
|
332
|
+
string: The input string to which comments will be added.
|
345
333
|
|
346
|
-
|
347
|
-
|
348
|
-
|
334
|
+
Returns:
|
335
|
+
The string with each line prefixed by '// '.
|
336
|
+
"""
|
349
337
|
|
350
|
-
|
351
|
-
|
338
|
+
def uncomment(string: str) -> str:
|
339
|
+
"""Remove comment from the string.
|
352
340
|
|
353
|
-
|
354
|
-
|
355
|
-
field: Field name
|
341
|
+
Args:
|
342
|
+
string: The input string from which comments will be removed.
|
356
343
|
|
357
|
-
|
358
|
-
|
359
|
-
|
344
|
+
Returns:
|
345
|
+
The string with comments (lines starting with '// ' or '//') removed.
|
346
|
+
"""
|
fabricatio/utils.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
"""A collection of utility functions for the fabricatio package."""
|
2
2
|
|
3
|
-
from typing import Any, Dict, List, Mapping, Optional
|
3
|
+
from typing import Any, Dict, List, Mapping, Optional, overload
|
4
4
|
|
5
5
|
from fabricatio.decorators import precheck_package
|
6
6
|
|
@@ -8,9 +8,7 @@ from fabricatio.decorators import precheck_package
|
|
8
8
|
@precheck_package(
|
9
9
|
"questionary", "'questionary' is required to run this function. Have you installed `fabricatio[qa]`?."
|
10
10
|
)
|
11
|
-
async def ask_edit(
|
12
|
-
text_seq: List[str],
|
13
|
-
) -> List[str]:
|
11
|
+
async def ask_edit(text_seq: List[str]) -> List[str]:
|
14
12
|
"""Asks the user to edit a list of texts.
|
15
13
|
|
16
14
|
Args:
|
@@ -30,17 +28,40 @@ async def ask_edit(
|
|
30
28
|
return res
|
31
29
|
|
32
30
|
|
31
|
+
@overload
|
32
|
+
async def ask_retain[V](candidates: List[str]) -> List[str]: ...
|
33
|
+
|
34
|
+
|
35
|
+
@overload
|
36
|
+
async def ask_retain[V](candidates: List[str], value_mapping: List[V]) -> List[V]: ...
|
37
|
+
|
38
|
+
|
39
|
+
@precheck_package(
|
40
|
+
"questionary", "'questionary' is required to run this function. Have you installed `fabricatio[qa]`?."
|
41
|
+
)
|
42
|
+
async def ask_retain[V](candidates: List[str], value_mapping: Optional[List[V]] = None) -> List[str] | List[V]:
|
43
|
+
"""Asks the user to retain a list of candidates."""
|
44
|
+
from questionary import Choice, checkbox
|
45
|
+
|
46
|
+
return await checkbox(
|
47
|
+
"Please choose those that should be retained.",
|
48
|
+
choices=[Choice(p, value=p, checked=True) for p in candidates]
|
49
|
+
if value_mapping is None
|
50
|
+
else [Choice(p, value=v) for p, v in zip(candidates, value_mapping, strict=True)],
|
51
|
+
).ask_async()
|
52
|
+
|
53
|
+
|
33
54
|
def override_kwargs(kwargs: Mapping[str, Any], **overrides) -> Dict[str, Any]:
|
34
55
|
"""Override the values in kwargs with the provided overrides."""
|
35
56
|
new_kwargs = dict(kwargs.items())
|
36
|
-
new_kwargs.update(
|
57
|
+
new_kwargs.update(overrides)
|
37
58
|
return new_kwargs
|
38
59
|
|
39
60
|
|
40
|
-
def fallback_kwargs(kwargs: Mapping[str, Any], **
|
41
|
-
"""Fallback the values in kwargs with the provided
|
61
|
+
def fallback_kwargs(kwargs: Mapping[str, Any], **fallbacks) -> Dict[str, Any]:
|
62
|
+
"""Fallback the values in kwargs with the provided fallbacks."""
|
42
63
|
new_kwargs = dict(kwargs.items())
|
43
|
-
new_kwargs.update({k: v for k, v in
|
64
|
+
new_kwargs.update({k: v for k, v in fallbacks.items() if k not in new_kwargs})
|
44
65
|
return new_kwargs
|
45
66
|
|
46
67
|
|
@@ -71,5 +92,3 @@ def wrapp_in_block(string: str, title: str, style: str = "-") -> str:
|
|
71
92
|
str: The wrapped string.
|
72
93
|
"""
|
73
94
|
return f"--- Start of {title} ---\n{string}\n--- End of {title} ---".replace("-", style)
|
74
|
-
|
75
|
-
|
Binary file
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: fabricatio
|
3
|
-
Version: 0.2.11.
|
3
|
+
Version: 0.2.11.dev3
|
4
4
|
Classifier: License :: OSI Approved :: MIT License
|
5
5
|
Classifier: Programming Language :: Rust
|
6
6
|
Classifier: Programming Language :: Python :: 3.12
|
@@ -20,18 +20,20 @@ Requires-Dist: pydantic-settings>=2.7.1
|
|
20
20
|
Requires-Dist: pymitter>=1.0.0
|
21
21
|
Requires-Dist: rich>=13.9.4
|
22
22
|
Requires-Dist: ujson>=5.10.0
|
23
|
-
Requires-Dist: fabricatio[calc,ftd,plot,qa,rag] ; extra == 'full'
|
23
|
+
Requires-Dist: fabricatio[calc,ftd,plot,qa,rag,cli] ; extra == 'full'
|
24
24
|
Requires-Dist: pymilvus>=2.5.4 ; extra == 'rag'
|
25
25
|
Requires-Dist: sympy>=1.13.3 ; extra == 'calc'
|
26
26
|
Requires-Dist: matplotlib>=3.10.1 ; extra == 'plot'
|
27
27
|
Requires-Dist: questionary>=2.1.0 ; extra == 'qa'
|
28
28
|
Requires-Dist: magika>=0.6.1 ; extra == 'ftd'
|
29
|
+
Requires-Dist: typer-slim[standard]>=0.15.2 ; extra == 'cli'
|
29
30
|
Provides-Extra: full
|
30
31
|
Provides-Extra: rag
|
31
32
|
Provides-Extra: calc
|
32
33
|
Provides-Extra: plot
|
33
34
|
Provides-Extra: qa
|
34
35
|
Provides-Extra: ftd
|
36
|
+
Provides-Extra: cli
|
35
37
|
License-File: LICENSE
|
36
38
|
Summary: A LLM multi-agent framework.
|
37
39
|
Keywords: ai,agents,multi-agent,llm,pyo3
|
@@ -1,8 +1,8 @@
|
|
1
|
-
fabricatio-0.2.11.
|
2
|
-
fabricatio-0.2.11.
|
3
|
-
fabricatio-0.2.11.
|
4
|
-
fabricatio/actions/article.py,sha256=
|
5
|
-
fabricatio/actions/article_rag.py,sha256=
|
1
|
+
fabricatio-0.2.11.dev3.dist-info/METADATA,sha256=alou2beIqeg3_FeS2dp-VQx15_Ep-0bf-tbGrUSxGmw,5263
|
2
|
+
fabricatio-0.2.11.dev3.dist-info/WHEEL,sha256=jABKVkLC9kJr8mi_er5jOqpiQUjARSLXDUIIxDqsS50,96
|
3
|
+
fabricatio-0.2.11.dev3.dist-info/licenses/LICENSE,sha256=do7J7EiCGbq0QPbMAL_FqLYufXpHnCnXBOuqVPwSV8Y,1088
|
4
|
+
fabricatio/actions/article.py,sha256=SFl1zc0hz9vW2sW4VJm9-w8E7kLEty-2LzXi9wgWMmE,10905
|
5
|
+
fabricatio/actions/article_rag.py,sha256=P1Bgvk6w8HogEMOw15-_cn2lzKpIcmfe_Ku2mlkdkYk,14318
|
6
6
|
fabricatio/actions/fs.py,sha256=gJR14U4ln35nt8Z7OWLVAZpqGaLnED-r1Yi-lX22tkI,959
|
7
7
|
fabricatio/actions/output.py,sha256=ttXLC2wZmtVN9Ik8zsA7g45rwBO656LyRjOGRdVSyJA,6977
|
8
8
|
fabricatio/actions/rag.py,sha256=KN-OWgcQjGmNgSZ-s5B8m4LpYKSGFJR8eq72mo2CP9k,3592
|
@@ -22,17 +22,17 @@ fabricatio/capabilities/__init__.py,sha256=v1cHRHIJ2gxyqMLNCs6ERVcCakSasZNYzmMI4
|
|
22
22
|
fabricatio/config.py,sha256=okqrVoLhvmAjmfQXlLY3js4nC_qW4v7mxoYaGO2dMQ8,17984
|
23
23
|
fabricatio/constants.py,sha256=thfDuF6JEtJ5CHOnAJLfqvn5834n8ep6DH2jc6XGzQM,577
|
24
24
|
fabricatio/core.py,sha256=VQ_JKgUGIy2gZ8xsTBZCdr_IP7wC5aPg0_bsOmjQ588,6458
|
25
|
-
fabricatio/decorators.py,sha256=
|
25
|
+
fabricatio/decorators.py,sha256=RFMYUlQPf561-BIHetpMd7fPig5bZ2brzWiQTgoLOlY,8966
|
26
26
|
fabricatio/fs/curd.py,sha256=p8y0LGKgVDk-CWOlm37E6wg7RK6RCD6denKo-VsW28c,4763
|
27
27
|
fabricatio/fs/readers.py,sha256=UXvcJO3UCsxHu9PPkg34Yh55Zi-miv61jD_wZQJgKRs,1751
|
28
28
|
fabricatio/fs/__init__.py,sha256=FydmlEY_3QY74r1BpGDc5lFLhE6g6gkwOAtE30Fo-aI,786
|
29
29
|
fabricatio/journal.py,sha256=stnEP88aUBA_GmU9gfTF2EZI8FS2OyMLGaMSTgK4QgA,476
|
30
|
-
fabricatio/models/action.py,sha256=
|
30
|
+
fabricatio/models/action.py,sha256=SnL8FAZsUCi9xM9BZT-CSjSRuI-4YBC5By8-ZHEBrW8,10109
|
31
31
|
fabricatio/models/adv_kwargs_types.py,sha256=kUO-SiZtFuz5cZCmMLnJJ9tjQ4-Zd_foo6R8HQMlM5A,1950
|
32
32
|
fabricatio/models/events.py,sha256=wiirk_ASg3iXDOZU_gIimci1VZVzWE1nDmxy-hQVJ9M,4150
|
33
33
|
fabricatio/models/extra/advanced_judge.py,sha256=INUl_41C8jkausDekkjnEmTwNfLCJ23TwFjq2cM23Cw,1092
|
34
|
-
fabricatio/models/extra/aricle_rag.py,sha256=
|
35
|
-
fabricatio/models/extra/article_base.py,sha256=
|
34
|
+
fabricatio/models/extra/aricle_rag.py,sha256=bJ9qNa9DkTVvja8GVue5wMnJCwnr6TEO7_fQbQK7fv4,9780
|
35
|
+
fabricatio/models/extra/article_base.py,sha256=CeYs0D6XghxgpSnQ-rhtWuuFhcouy_vc6E5oUCPck_w,12840
|
36
36
|
fabricatio/models/extra/article_essence.py,sha256=mlIkkRMR3I1RtqiiOnmIE3Vy623L4eECumkRzryE1pw,2749
|
37
37
|
fabricatio/models/extra/article_main.py,sha256=4rjev0wpI2jf52NLNatRbqFQmN6rtKaMB9iy30hSEXM,9818
|
38
38
|
fabricatio/models/extra/article_outline.py,sha256=w7O0SHgC7exbptWVbR62FMHAueMgBpyWKVYMGGl_oj8,1427
|
@@ -45,21 +45,21 @@ fabricatio/models/extra/__init__.py,sha256=XlYnS_2B9nhLhtQkjE7rvvfPmAAtXVdNi9bSD
|
|
45
45
|
fabricatio/models/generic.py,sha256=7wcG01DN9g4q1DJGZsTUxSTMixQgwXX0xlX4HbbLc6U,31185
|
46
46
|
fabricatio/models/kwargs_types.py,sha256=GEw75ZiiDEFx_ImhCBENnPF7K0BcdTQ1ocH5jSPwMRs,4774
|
47
47
|
fabricatio/models/role.py,sha256=-CRcj5_M3_ciLPzwiNn92grBmwoSLQ-n4koVZiCNTBM,2953
|
48
|
-
fabricatio/models/task.py,sha256=
|
48
|
+
fabricatio/models/task.py,sha256=bLYSKjlRAlb4jMYyF12RTnm_8pVXysSmX8CYLrEmbQ8,11096
|
49
49
|
fabricatio/models/tool.py,sha256=jQ51g4lwTPfsMF1nbreDJtBczbxIHoXcPuLSOqHliq8,12506
|
50
|
-
fabricatio/models/usages.py,sha256=
|
50
|
+
fabricatio/models/usages.py,sha256=0bzITf0vug9ZaN6qnjNfFB7T8BAvpXE0bvx0otFYLLA,33356
|
51
51
|
fabricatio/parser.py,sha256=-RbW2yzfJiu2ARq-lZw4tfgsjY2rIZWtJpoUmaE6gJQ,6637
|
52
52
|
fabricatio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
53
|
-
fabricatio/rust.pyi,sha256=
|
53
|
+
fabricatio/rust.pyi,sha256=GJRLeeQ1UIaf5kOgJWX2GkwIacoTBk3yBKuD5cKW8i4,10489
|
54
54
|
fabricatio/rust_instances.py,sha256=Byeo8KHW_dJiXujJq7YPGDLBX5bHNDYbBc4sY3uubVY,313
|
55
55
|
fabricatio/toolboxes/arithmetic.py,sha256=WLqhY-Pikv11Y_0SGajwZx3WhsLNpHKf9drzAqOf_nY,1369
|
56
56
|
fabricatio/toolboxes/fs.py,sha256=l4L1CVxJmjw9Ld2XUpIlWfV0_Fu_2Og6d3E13I-S4aE,736
|
57
57
|
fabricatio/toolboxes/__init__.py,sha256=KBJi5OG_pExscdlM7Bnt_UF43j4I3Lv6G71kPVu4KQU,395
|
58
|
-
fabricatio/utils.py,sha256=
|
58
|
+
fabricatio/utils.py,sha256=sLD6L_BHXusJjCu3gsUpxOFbmEOnT577xU1kaZQ04SE,3084
|
59
59
|
fabricatio/workflows/articles.py,sha256=ObYTFUqLUk_CzdmmnX6S7APfxcGmPFqnFr9pdjU7Z4Y,969
|
60
60
|
fabricatio/workflows/rag.py,sha256=-YYp2tlE9Vtfgpg6ROpu6QVO8j8yVSPa6yDzlN3qVxs,520
|
61
61
|
fabricatio/workflows/__init__.py,sha256=5ScFSTA-bvhCesj3U9Mnmi6Law6N1fmh5UKyh58L3u8,51
|
62
62
|
fabricatio/__init__.py,sha256=Rmvq2VgdS2u68vnOi2i5RbeWbAwrJDbk8D8D883PJWE,1022
|
63
|
-
fabricatio/rust.cp312-win_amd64.pyd,sha256=
|
64
|
-
fabricatio-0.2.11.
|
65
|
-
fabricatio-0.2.11.
|
63
|
+
fabricatio/rust.cp312-win_amd64.pyd,sha256=Z3wuzfa_m81nq1W6MVF66ne-gQ0-gkNFdknay_wVskY,4150272
|
64
|
+
fabricatio-0.2.11.dev3.data/scripts/tdown.exe,sha256=nHWlrICGMzmDpo1bZA-l1tqyCZhSreyrc5S1J3E7KgU,3350016
|
65
|
+
fabricatio-0.2.11.dev3.dist-info/RECORD,,
|
File without changes
|
File without changes
|