fabricatio 0.2.7.dev1__cp312-cp312-manylinux_2_34_x86_64.whl → 0.2.7.dev2__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/actions/article.py +66 -15
- fabricatio/capabilities/rating.py +11 -2
- fabricatio/capabilities/review.py +6 -3
- fabricatio/decorators.py +32 -0
- fabricatio/models/action.py +9 -7
- fabricatio/models/extra.py +171 -72
- fabricatio/models/generic.py +1 -1
- fabricatio/models/kwargs_types.py +2 -1
- fabricatio/models/usages.py +4 -1
- {fabricatio-0.2.7.dev1.data → fabricatio-0.2.7.dev2.data}/scripts/tdown +0 -0
- {fabricatio-0.2.7.dev1.dist-info → fabricatio-0.2.7.dev2.dist-info}/METADATA +1 -1
- {fabricatio-0.2.7.dev1.dist-info → fabricatio-0.2.7.dev2.dist-info}/RECORD +15 -15
- {fabricatio-0.2.7.dev1.dist-info → fabricatio-0.2.7.dev2.dist-info}/WHEEL +0 -0
- {fabricatio-0.2.7.dev1.dist-info → fabricatio-0.2.7.dev2.dist-info}/licenses/LICENSE +0 -0
Binary file
|
fabricatio/actions/article.py
CHANGED
@@ -55,19 +55,23 @@ class GenerateArticleProposal(Action):
|
|
55
55
|
**_,
|
56
56
|
) -> Optional[ArticleProposal]:
|
57
57
|
if article_briefing is None and article_briefing_path is None and task_input is None:
|
58
|
-
logger.
|
58
|
+
logger.error("Task not approved, since all inputs are None.")
|
59
59
|
return None
|
60
|
-
if article_briefing_path is None and task_input:
|
61
|
-
article_briefing_path = await self.awhich_pathstr(
|
62
|
-
f"{task_input.briefing}\nExtract the path of file which contains the article briefing."
|
63
|
-
)
|
64
60
|
|
65
61
|
return (
|
66
62
|
await self.propose(
|
67
63
|
ArticleProposal,
|
68
64
|
briefing := (
|
69
65
|
article_briefing
|
70
|
-
or safe_text_read(
|
66
|
+
or safe_text_read(
|
67
|
+
ok(
|
68
|
+
article_briefing_path
|
69
|
+
or await self.awhich_pathstr(
|
70
|
+
f"{task_input.briefing}\nExtract the path of file which contains the article briefing."
|
71
|
+
),
|
72
|
+
"Could not find the path of file to read.",
|
73
|
+
)
|
74
|
+
)
|
71
75
|
),
|
72
76
|
**self.prepend_sys_msg(),
|
73
77
|
)
|
@@ -85,13 +89,28 @@ class GenerateOutline(Action):
|
|
85
89
|
article_proposal: ArticleProposal,
|
86
90
|
**_,
|
87
91
|
) -> Optional[ArticleOutline]:
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
92
|
+
out = await self.propose(
|
93
|
+
ArticleOutline,
|
94
|
+
article_proposal.as_prompt(),
|
95
|
+
**self.prepend_sys_msg(),
|
96
|
+
)
|
97
|
+
|
98
|
+
manual = await self.draft_rating_manual(
|
99
|
+
topic=(
|
100
|
+
topic
|
101
|
+
:= "Fix the internal referring error, make sure there is no more `ArticleRef` pointing to a non-existing article component."
|
102
|
+
),
|
103
|
+
)
|
104
|
+
while err := out.resolve_ref_error():
|
105
|
+
logger.warning(f"Found error in the outline: \n{err}")
|
106
|
+
out = await self.correct_obj(
|
107
|
+
out,
|
108
|
+
reference=f"# Referring Error\n{err}",
|
109
|
+
topic=topic,
|
110
|
+
rating_manual=manual,
|
111
|
+
supervisor_check=False,
|
93
112
|
)
|
94
|
-
|
113
|
+
return out.update_ref(article_proposal)
|
95
114
|
|
96
115
|
|
97
116
|
class CorrectProposal(Action):
|
@@ -134,10 +153,42 @@ class GenerateArticle(Action):
|
|
134
153
|
) -> Optional[Article]:
|
135
154
|
article: Article = Article.from_outline(article_outline).update_ref(article_outline)
|
136
155
|
|
137
|
-
|
138
|
-
|
139
|
-
|
156
|
+
writing_manual = await self.draft_rating_manual(
|
157
|
+
topic=(
|
158
|
+
topic_1
|
159
|
+
:= "improve the content of the subsection to fit the outline. SHALL never add or remove any section or subsection, you can only add or delete paragraphs within the subsection."
|
160
|
+
),
|
161
|
+
)
|
162
|
+
err_resolve_manual = await self.draft_rating_manual(
|
163
|
+
topic=(topic_2 := "this article component has violated the constrain, please correct it.")
|
164
|
+
)
|
165
|
+
for c, deps in article.iter_dfs_with_deps(chapter=False):
|
166
|
+
logger.info(f"Updating the article component: \n{c.display()}")
|
167
|
+
|
168
|
+
out = ok(
|
169
|
+
await self.correct_obj(
|
170
|
+
c,
|
171
|
+
reference=(
|
172
|
+
ref := f"{article_outline.referenced.as_prompt()}\n" + "\n".join(d.display() for d in deps)
|
173
|
+
),
|
174
|
+
topic=topic_1,
|
175
|
+
rating_manual=writing_manual,
|
176
|
+
supervisor_check=False,
|
177
|
+
),
|
178
|
+
"Could not correct the article component.",
|
140
179
|
)
|
180
|
+
while err := c.resolve_update_error(out):
|
181
|
+
logger.warning(f"Found error in the article component: \n{err}")
|
182
|
+
out = ok(
|
183
|
+
await self.correct_obj(
|
184
|
+
out,
|
185
|
+
reference=f"{ref}\n\n# Violated Error\n{err}",
|
186
|
+
topic=topic_2,
|
187
|
+
rating_manual=err_resolve_manual,
|
188
|
+
supervisor_check=False,
|
189
|
+
),
|
190
|
+
"Could not correct the article component.",
|
191
|
+
)
|
141
192
|
|
142
193
|
c.update_from(out)
|
143
194
|
return article
|
@@ -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(
|
@@ -1,6 +1,6 @@
|
|
1
1
|
"""A module that provides functionality to rate tasks based on a rating manual and score range."""
|
2
2
|
|
3
|
-
from typing import List, Optional, Self, Set, Unpack, cast
|
3
|
+
from typing import Dict, List, Optional, Self, Set, Unpack, cast
|
4
4
|
|
5
5
|
from fabricatio._rust_instances import TEMPLATE_MANAGER
|
6
6
|
from fabricatio.capabilities.propose import Propose
|
@@ -200,13 +200,14 @@ class Review(GiveRating, Propose):
|
|
200
200
|
ReviewResult[Task[T]]: A review result containing identified problems and proposed solutions,
|
201
201
|
with a reference to the original task.
|
202
202
|
"""
|
203
|
-
return cast(
|
203
|
+
return cast("ReviewResult[Task[T]]", await self.review_obj(task, **kwargs))
|
204
204
|
|
205
205
|
async def review_string(
|
206
206
|
self,
|
207
207
|
input_text: str,
|
208
208
|
topic: str,
|
209
209
|
criteria: Optional[Set[str]] = None,
|
210
|
+
rating_manual: Optional[Dict[str, str]] = None,
|
210
211
|
**kwargs: Unpack[ValidateKwargs[ReviewResult[str]]],
|
211
212
|
) -> ReviewResult[str]:
|
212
213
|
"""Review a string based on specified topic and criteria.
|
@@ -219,6 +220,7 @@ class Review(GiveRating, Propose):
|
|
219
220
|
topic (str): The subject topic for the review criteria.
|
220
221
|
criteria (Optional[Set[str]], optional): A set of criteria for the review.
|
221
222
|
If not provided, criteria will be drafted automatically. Defaults to None.
|
223
|
+
rating_manual (Optional[Dict[str,str]], optional): A dictionary of rating criteria and their corresponding scores.
|
222
224
|
**kwargs (Unpack[ValidateKwargs]): Additional keyword arguments for the LLM usage.
|
223
225
|
|
224
226
|
Returns:
|
@@ -227,12 +229,13 @@ class Review(GiveRating, Propose):
|
|
227
229
|
"""
|
228
230
|
default = None
|
229
231
|
if "default" in kwargs:
|
232
|
+
# this `default` is the default for the `propose` method
|
230
233
|
default = kwargs.pop("default")
|
231
234
|
|
232
235
|
criteria = criteria or (await self.draft_rating_criteria(topic, **kwargs))
|
233
236
|
if not criteria:
|
234
237
|
raise ValueError("No criteria provided for review.")
|
235
|
-
manual = await self.draft_rating_manual(topic, criteria, **kwargs)
|
238
|
+
manual = rating_manual or await self.draft_rating_manual(topic, criteria, **kwargs)
|
236
239
|
|
237
240
|
if default is not None:
|
238
241
|
kwargs["default"] = default
|
fabricatio/decorators.py
CHANGED
@@ -177,3 +177,35 @@ def use_temp_module[**P, R](modules: ModuleType | List[ModuleType]) -> Callable[
|
|
177
177
|
return _wrapper
|
178
178
|
|
179
179
|
return _decorator
|
180
|
+
|
181
|
+
|
182
|
+
def logging_exec_time[**P, R](func: Callable[P, R]) -> Callable[P, R]:
|
183
|
+
"""Decorator to log the execution time of a function.
|
184
|
+
|
185
|
+
Args:
|
186
|
+
func (Callable): The function to be executed
|
187
|
+
|
188
|
+
Returns:
|
189
|
+
Callable: A decorator that wraps the function to log the execution time.
|
190
|
+
"""
|
191
|
+
from time import time
|
192
|
+
|
193
|
+
if iscoroutinefunction(func):
|
194
|
+
|
195
|
+
@wraps(func)
|
196
|
+
async def _async_wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
|
197
|
+
start_time = time()
|
198
|
+
result = await func(*args, **kwargs)
|
199
|
+
logger.debug(f"Execution time of `{func.__name__}`: {time() - start_time:.2f} s")
|
200
|
+
return result
|
201
|
+
|
202
|
+
return _async_wrapper
|
203
|
+
|
204
|
+
@wraps(func)
|
205
|
+
def _wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
|
206
|
+
start_time = time()
|
207
|
+
result = func(*args, **kwargs)
|
208
|
+
logger.debug(f"Execution time of {func.__name__}: {(time() - start_time) * 1000:.2f} ms")
|
209
|
+
return result
|
210
|
+
|
211
|
+
return _wrapper
|
fabricatio/models/action.py
CHANGED
@@ -48,7 +48,7 @@ class Action(HandleTask, ProposeTask, Correct):
|
|
48
48
|
self.description = self.description or self.__class__.__doc__ or ""
|
49
49
|
|
50
50
|
@abstractmethod
|
51
|
-
async def _execute(self
|
51
|
+
async def _execute(self, *_, **cxt) -> Any: # noqa: ANN002
|
52
52
|
"""Execute the action logic with the provided context arguments.
|
53
53
|
|
54
54
|
This method must be implemented by subclasses to define the actual behavior.
|
@@ -147,6 +147,8 @@ class WorkFlow(WithBriefing, ToolBoxUsage):
|
|
147
147
|
Args:
|
148
148
|
task: The task to be processed.
|
149
149
|
"""
|
150
|
+
logger.info(f"Start execute workflow: {self.name}")
|
151
|
+
|
150
152
|
await task.start()
|
151
153
|
await self._init_context(task)
|
152
154
|
|
@@ -155,12 +157,11 @@ class WorkFlow(WithBriefing, ToolBoxUsage):
|
|
155
157
|
# Process each action in sequence
|
156
158
|
for step in self._instances:
|
157
159
|
current_action = step.name
|
158
|
-
logger.
|
160
|
+
logger.info(f"Executing step: {current_action}")
|
159
161
|
|
160
162
|
# Get current context and execute action
|
161
163
|
context = await self._context.get()
|
162
164
|
act_task = create_task(step.act(context))
|
163
|
-
|
164
165
|
# Handle task cancellation
|
165
166
|
if task.is_cancelled():
|
166
167
|
act_task.cancel(f"Cancelled by task: {task.name}")
|
@@ -168,9 +169,10 @@ class WorkFlow(WithBriefing, ToolBoxUsage):
|
|
168
169
|
|
169
170
|
# Update context with modified values
|
170
171
|
modified_ctx = await act_task
|
172
|
+
logger.success(f"Step execution finished: {current_action}")
|
171
173
|
await self._context.put(modified_ctx)
|
172
174
|
|
173
|
-
logger.
|
175
|
+
logger.success(f"Workflow execution finished: {self.name}")
|
174
176
|
|
175
177
|
# Get final context and extract result
|
176
178
|
final_ctx = await self._context.get()
|
@@ -184,9 +186,9 @@ class WorkFlow(WithBriefing, ToolBoxUsage):
|
|
184
186
|
|
185
187
|
await task.finish(result)
|
186
188
|
|
187
|
-
except
|
188
|
-
logger.
|
189
|
-
logger.
|
189
|
+
except Exception as e: # noqa: BLE001
|
190
|
+
logger.critical(f"Error during task: {current_action} execution: {e}")
|
191
|
+
logger.critical(traceback.format_exc())
|
190
192
|
await task.fail()
|
191
193
|
|
192
194
|
async def _init_context[T](self, task: Task[T]) -> None:
|
fabricatio/models/extra.py
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
"""Extra models for built-in actions."""
|
2
2
|
|
3
3
|
from abc import abstractmethod
|
4
|
+
from enum import Enum
|
4
5
|
from itertools import chain
|
5
|
-
from typing import Dict, Generator, List, Optional, Self, Tuple, final
|
6
|
+
from typing import Dict, Generator, List, Optional, Self, Tuple, Union, final, overload
|
6
7
|
|
7
8
|
from fabricatio.journal import logger
|
8
9
|
from fabricatio.models.generic import AsPrompt, Base, CensoredAble, Display, PrepareVectorization, ProposedAble, WithRef
|
@@ -263,44 +264,82 @@ class ArticleProposal(CensoredAble, Display, WithRef[str], AsPrompt):
|
|
263
264
|
return {"ArticleBriefing": self.referenced, "ArticleProposal": self.display()}
|
264
265
|
|
265
266
|
|
266
|
-
class
|
267
|
-
"""
|
267
|
+
class ReferringType(str, Enum):
|
268
|
+
"""Enumeration of different types of references that can be made in an article."""
|
268
269
|
|
269
|
-
|
270
|
-
""
|
270
|
+
CHAPTER: str = "chapter"
|
271
|
+
SECTION: str = "section"
|
272
|
+
SUBSECTION: str = "subsection"
|
273
|
+
|
274
|
+
|
275
|
+
class ArticleRef(CensoredAble):
|
276
|
+
"""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."""
|
271
277
|
|
272
278
|
referred_chapter_title: str
|
273
|
-
"""
|
279
|
+
"""`title` Field of the referenced chapter"""
|
274
280
|
|
275
281
|
referred_section_title: Optional[str] = None
|
276
|
-
"""
|
282
|
+
"""`title` Field of the referenced section. Defaults to None if not applicable, which means the reference is pointing to the entire chapter."""
|
277
283
|
|
278
284
|
referred_subsection_title: Optional[str] = None
|
279
|
-
"""
|
285
|
+
"""`title` Field of the referenced subsection. Defaults to None if not applicable, which means the reference is pointing to the entire section."""
|
280
286
|
|
281
287
|
def __hash__(self) -> int:
|
282
288
|
"""Overrides the default hash function to ensure consistent hashing across instances."""
|
283
289
|
return hash((self.referred_chapter_title, self.referred_section_title, self.referred_subsection_title))
|
284
290
|
|
291
|
+
@overload
|
292
|
+
def deref(self, article: "Article") -> Optional["ArticleBase"]:
|
293
|
+
"""Dereference the reference to the actual section or subsection within the provided article."""
|
294
|
+
|
295
|
+
@overload
|
296
|
+
def deref(self, article: "ArticleOutline") -> Optional["ArticleOutlineBase"]:
|
297
|
+
"""Dereference the reference to the actual section or subsection within the provided article."""
|
298
|
+
|
299
|
+
def deref(self, article: Union["ArticleOutline", "Article"]) -> Union["ArticleOutlineBase", "ArticleBase", None]:
|
300
|
+
"""Dereference the reference to the actual section or subsection within the provided article.
|
301
|
+
|
302
|
+
Args:
|
303
|
+
article (ArticleOutline | Article): The article to dereference the reference from.
|
304
|
+
|
305
|
+
Returns:
|
306
|
+
ArticleBase | ArticleOutline | None: The dereferenced section or subsection, or None if not found.
|
307
|
+
"""
|
308
|
+
chap = next((chap for chap in article.chapters if chap.title == self.referred_chapter_title), None)
|
309
|
+
if self.referred_section_title is None or chap is None:
|
310
|
+
return chap
|
311
|
+
sec = next((sec for sec in chap.sections if sec.title == self.referred_section_title), None)
|
312
|
+
if self.referred_subsection_title is None or sec is None:
|
313
|
+
return sec
|
314
|
+
return next((subsec for subsec in sec.subsections if subsec.title == self.referred_subsection_title), None)
|
315
|
+
|
316
|
+
@property
|
317
|
+
def referring_type(self) -> ReferringType:
|
318
|
+
"""Determine the type of reference based on the presence of specific attributes."""
|
319
|
+
if self.referred_subsection_title is not None:
|
320
|
+
return ReferringType.SUBSECTION
|
321
|
+
if self.referred_section_title is not None:
|
322
|
+
return ReferringType.SECTION
|
323
|
+
return ReferringType.CHAPTER
|
324
|
+
|
285
325
|
|
286
326
|
# <editor-fold desc="ArticleOutline">
|
287
327
|
class ArticleOutlineBase(Base):
|
288
|
-
"""
|
328
|
+
"""Base class for article outlines."""
|
289
329
|
|
290
330
|
writing_aim: List[str]
|
291
331
|
"""Required: List of specific rhetorical objectives (3-5 items).
|
292
332
|
Format: Each item must be an actionable phrase starting with a verb.
|
293
333
|
Example: ['Establish metric validity', 'Compare with baseline approaches',
|
294
334
|
'Justify threshold selection']"""
|
295
|
-
support_to: List[ArticleRef]
|
296
|
-
"""Required: List of ArticleRef objects identifying components this section provides evidence for.
|
297
|
-
Format: Each reference must point to a specific chapter, section, or subsection.
|
298
|
-
Note: References form a directed acyclic graph in the document structure."""
|
299
|
-
|
300
335
|
depend_on: List[ArticleRef]
|
301
|
-
"""Required: List of ArticleRef objects identifying components this section builds upon.
|
336
|
+
"""Required: List of all essential ArticleRef objects identifying components this section builds upon.
|
302
337
|
Format: Each reference must point to a previously defined chapter, section, or subsection.
|
303
338
|
Note: Circular dependencies are not permitted."""
|
339
|
+
support_to: List[ArticleRef]
|
340
|
+
"""Required: List of all essential ArticleRef objects identifying components this section provides evidence for.
|
341
|
+
Format: Each reference must point to a specific chapter, section, or subsection.
|
342
|
+
Note: References form a directed acyclic graph in the document structure."""
|
304
343
|
|
305
344
|
description: str = Field(...)
|
306
345
|
"""Description of the research component in academic style."""
|
@@ -313,34 +352,16 @@ class ArticleSubsectionOutline(ArticleOutlineBase):
|
|
313
352
|
|
314
353
|
|
315
354
|
class ArticleSectionOutline(ArticleOutlineBase):
|
316
|
-
"""
|
317
|
-
|
318
|
-
subsections: List[ArticleSubsectionOutline] = Field(
|
319
|
-
|
320
|
-
)
|
321
|
-
"""IMRaD-compliant substructure with technical progression:
|
322
|
-
1. Conceptual Framework
|
323
|
-
2. Methodological Details
|
324
|
-
3. Implementation Strategy
|
325
|
-
4. Validation Approach
|
326
|
-
5. Transition Logic
|
327
|
-
|
328
|
-
Example Flow:
|
329
|
-
[
|
330
|
-
'Search Space Constraints',
|
331
|
-
'Gradient Optimization Protocol',
|
332
|
-
'Multi-GPU Implementation',
|
333
|
-
'Convergence Validation',
|
334
|
-
'Cross-Lingual Extension'
|
335
|
-
]"""
|
355
|
+
"""A slightly more detailed research component specification for academic paper generation."""
|
356
|
+
|
357
|
+
subsections: List[ArticleSubsectionOutline] = Field(min_length=1)
|
358
|
+
"""List of subsections, each containing a specific research component. Must contains at least 1 subsection, But do remember you should always add more subsection as required."""
|
336
359
|
|
337
360
|
|
338
361
|
class ArticleChapterOutline(ArticleOutlineBase):
|
339
362
|
"""Macro-structural unit implementing standard academic paper organization."""
|
340
363
|
|
341
|
-
sections: List[ArticleSectionOutline] = Field(
|
342
|
-
...,
|
343
|
-
)
|
364
|
+
sections: List[ArticleSectionOutline] = Field(min_length=1)
|
344
365
|
"""Standard academic progression implementing chapter goals:
|
345
366
|
1. Context Establishment
|
346
367
|
2. Technical Presentation
|
@@ -348,25 +369,15 @@ class ArticleChapterOutline(ArticleOutlineBase):
|
|
348
369
|
4. Comparative Analysis
|
349
370
|
5. Synthesis
|
350
371
|
|
351
|
-
|
352
|
-
|
353
|
-
'Experimental Setup',
|
354
|
-
'Monolingual Baselines',
|
355
|
-
'Cross-Lingual Transfer',
|
356
|
-
'Low-Resource Scaling',
|
357
|
-
'Error Analysis'
|
358
|
-
]"""
|
372
|
+
Must contains at least 1 sections, But do remember you should always add more section as required.
|
373
|
+
"""
|
359
374
|
|
360
375
|
|
361
376
|
class ArticleOutline(Display, CensoredAble, WithRef[ArticleProposal]):
|
362
377
|
"""Complete academic paper blueprint with hierarchical validation."""
|
363
378
|
|
364
379
|
title: str = Field(...)
|
365
|
-
"""
|
366
|
-
- Title Case with 12-18 word limit
|
367
|
-
- Structure: [Method] for [Task] via [Approach] in [Domain]
|
368
|
-
Example: 'Efficient Differentiable NAS for Low-Resource MT Through
|
369
|
-
Parameter-Sharing: A Cross-Lingual Study'"""
|
380
|
+
"""Title of the academic paper."""
|
370
381
|
|
371
382
|
prospect: str = Field(...)
|
372
383
|
"""Consolidated research statement with four pillars:
|
@@ -381,15 +392,7 @@ class ArticleOutline(Display, CensoredAble, WithRef[ArticleProposal]):
|
|
381
392
|
60% reduced search costs.'"""
|
382
393
|
|
383
394
|
chapters: List[ArticleChapterOutline]
|
384
|
-
"""
|
385
|
-
1. Introduction: Problem Space & Contributions
|
386
|
-
2. Background: Theoretical Foundations
|
387
|
-
3. Methods: Technical Innovations
|
388
|
-
4. Experiments: Protocol Design
|
389
|
-
5. Results: Empirical Findings
|
390
|
-
6. Discussion: Interpretation & Limitations
|
391
|
-
7. Conclusion: Synthesis & Future Work
|
392
|
-
8. Appendices: Supplementary Materials"""
|
395
|
+
"""List of ArticleChapterOutline objects representing the academic paper's structure."""
|
393
396
|
|
394
397
|
abstract: str = Field(...)
|
395
398
|
"""The abstract is a concise summary of the academic paper's main findings."""
|
@@ -423,6 +426,38 @@ class ArticleOutline(Display, CensoredAble, WithRef[ArticleProposal]):
|
|
423
426
|
lines.append(f"=== {i}.{j}.{k} {subsection.title}")
|
424
427
|
return "\n".join(lines)
|
425
428
|
|
429
|
+
def iter_dfs(self) -> Generator[ArticleOutlineBase, None, None]:
|
430
|
+
"""Iterates through the article outline in a depth-first manner.
|
431
|
+
|
432
|
+
Returns:
|
433
|
+
ArticleOutlineBase: Each component in the article outline.
|
434
|
+
"""
|
435
|
+
for chapter in self.chapters:
|
436
|
+
for section in chapter.sections:
|
437
|
+
yield from section.subsections
|
438
|
+
yield section
|
439
|
+
yield chapter
|
440
|
+
|
441
|
+
def resolve_ref_error(self) -> str:
|
442
|
+
"""Resolve reference errors in the article outline.
|
443
|
+
|
444
|
+
Returns:
|
445
|
+
str: Error message indicating reference errors in the article outline.
|
446
|
+
|
447
|
+
Notes:
|
448
|
+
This function is designed to find all invalid `ArticleRef` objs in `depend_on` and `support_to` fields, which will be added to the final error summary.
|
449
|
+
"""
|
450
|
+
summary = ""
|
451
|
+
for component in self.iter_dfs():
|
452
|
+
for ref in component.depend_on:
|
453
|
+
if not ref.deref(self):
|
454
|
+
summary += f"Invalid internal reference in {component.__class__.__name__} titled `{component.title}` at `depend_on` field, because the referred {ref.referring_type} is not exists within the article, see the original obj dump: {ref.model_dump()}\n"
|
455
|
+
for ref in component.support_to:
|
456
|
+
if not ref.deref(self):
|
457
|
+
summary += f"Invalid internal reference in {component.__class__.__name__} titled `{component.title}` at `support_to` field, because the referred {ref.referring_type} is not exists within the article, see the original obj dump: {ref.model_dump()}\n"
|
458
|
+
|
459
|
+
return summary
|
460
|
+
|
426
461
|
|
427
462
|
# </editor-fold>
|
428
463
|
|
@@ -456,6 +491,15 @@ class ArticleBase(CensoredAble, Display, ArticleOutlineBase):
|
|
456
491
|
raise TypeError(f"Cannot update from a non-{self.__class__} instance.")
|
457
492
|
if self.title != other.title:
|
458
493
|
raise ValueError("Cannot update from a different title.")
|
494
|
+
return self
|
495
|
+
|
496
|
+
@abstractmethod
|
497
|
+
def resolve_update_error(self, other: Self) -> str:
|
498
|
+
"""Resolve update errors in the article outline.
|
499
|
+
|
500
|
+
Returns:
|
501
|
+
str: Error message indicating update errors in the article outline.
|
502
|
+
"""
|
459
503
|
|
460
504
|
@abstractmethod
|
461
505
|
def _update_from_inner(self, other: Self) -> Self:
|
@@ -481,6 +525,12 @@ class ArticleSubsection(ArticleBase):
|
|
481
525
|
paragraphs: List[Paragraph]
|
482
526
|
"""List of Paragraph objects containing the content of the subsection."""
|
483
527
|
|
528
|
+
def resolve_update_error(self, other: Self) -> str:
|
529
|
+
"""Resolve update errors in the article outline."""
|
530
|
+
if self.title != other.title:
|
531
|
+
return f"Title `{other.title}` mismatched, expected `{self.title}`. "
|
532
|
+
return ""
|
533
|
+
|
484
534
|
def _update_from_inner(self, other: Self) -> Self:
|
485
535
|
"""Updates the current instance with the attributes of another instance."""
|
486
536
|
logger.debug(f"Updating SubSection {self.title}")
|
@@ -500,9 +550,30 @@ class ArticleSection(ArticleBase):
|
|
500
550
|
"""Atomic argumentative unit with high-level specificity."""
|
501
551
|
|
502
552
|
subsections: List[ArticleSubsection]
|
553
|
+
"""List of ArticleSubsection objects containing the content of the section."""
|
554
|
+
|
555
|
+
def resolve_update_error(self, other: Self) -> str:
|
556
|
+
"""Resolve update errors in the article outline."""
|
557
|
+
if (s_len := len(self.subsections)) == 0:
|
558
|
+
return ""
|
559
|
+
|
560
|
+
if s_len != len(other.subsections):
|
561
|
+
return f"Subsections length mismatched, expected {len(self.subsections)}, got {len(other.subsections)}"
|
562
|
+
|
563
|
+
sub_sec_err_seq = [
|
564
|
+
out for s, o in zip(self.subsections, other.subsections, strict=True) if (out := s.resolve_update_error(o))
|
565
|
+
]
|
566
|
+
|
567
|
+
if sub_sec_err_seq:
|
568
|
+
return "\n".join(sub_sec_err_seq)
|
569
|
+
return ""
|
503
570
|
|
504
571
|
def _update_from_inner(self, other: Self) -> Self:
|
505
572
|
"""Updates the current instance with the attributes of another instance."""
|
573
|
+
if len(self.subsections) == 0:
|
574
|
+
self.subsections = other.subsections
|
575
|
+
return self
|
576
|
+
|
506
577
|
for self_subsec, other_subsec in zip(self.subsections, other.subsections, strict=True):
|
507
578
|
self_subsec.update_from(other_subsec)
|
508
579
|
return self
|
@@ -522,8 +593,26 @@ class ArticleChapter(ArticleBase):
|
|
522
593
|
sections: List[ArticleSection]
|
523
594
|
"""Thematic progression implementing chapter's research function."""
|
524
595
|
|
596
|
+
def resolve_update_error(self, other: Self) -> str:
|
597
|
+
"""Resolve update errors in the article outline."""
|
598
|
+
if (s_len := len(self.sections)) == 0:
|
599
|
+
return ""
|
600
|
+
|
601
|
+
if s_len != len(other.sections):
|
602
|
+
return f"Sections length mismatched, expected {len(self.sections)}, got {len(other.sections)}"
|
603
|
+
sec_err_seq = [
|
604
|
+
out for s, o in zip(self.sections, other.sections, strict=True) if (out := s.resolve_update_error(o))
|
605
|
+
]
|
606
|
+
if sec_err_seq:
|
607
|
+
return "\n".join(sec_err_seq)
|
608
|
+
return ""
|
609
|
+
|
525
610
|
def _update_from_inner(self, other: Self) -> Self:
|
526
611
|
"""Updates the current instance with the attributes of another instance."""
|
612
|
+
if len(self.sections) == 0:
|
613
|
+
self.sections = other.sections
|
614
|
+
return self
|
615
|
+
|
527
616
|
for self_sec, other_sec in zip(self.sections, other.sections, strict=True):
|
528
617
|
self_sec.update_from(other_sec)
|
529
618
|
return self
|
@@ -636,15 +725,7 @@ class Article(Display, CensoredAble, WithRef[ArticleOutline]):
|
|
636
725
|
Returns:
|
637
726
|
ArticleBase: The corresponding section or subsection.
|
638
727
|
"""
|
639
|
-
|
640
|
-
next(chap for chap in self.chap_iter() if chap.title == ref.referred_chapter_title), "Chapter not found"
|
641
|
-
)
|
642
|
-
if ref.referred_section_title is None:
|
643
|
-
return chap
|
644
|
-
sec = ok(next(sec for sec in chap.sections if sec.title == ref.referred_section_title))
|
645
|
-
if ref.referred_subsection_title is None:
|
646
|
-
return sec
|
647
|
-
return ok(next(subsec for subsec in sec.subsections if subsec.title == ref.referred_subsection_title))
|
728
|
+
return ok(ref.deref(self), f"{ref} not found in {self.title}")
|
648
729
|
|
649
730
|
def gather_dependencies(self, article: ArticleBase) -> List[ArticleBase]:
|
650
731
|
"""Gathers dependencies for all sections and subsections in the article.
|
@@ -672,7 +753,8 @@ class Article(Display, CensoredAble, WithRef[ArticleOutline]):
|
|
672
753
|
q = self.gather_dependencies(article)
|
673
754
|
|
674
755
|
deps = []
|
675
|
-
while
|
756
|
+
while q:
|
757
|
+
a = q.pop()
|
676
758
|
deps.extend(self.gather_dependencies(a))
|
677
759
|
|
678
760
|
deps = list(
|
@@ -688,7 +770,8 @@ class Article(Display, CensoredAble, WithRef[ArticleOutline]):
|
|
688
770
|
processed_components = []
|
689
771
|
|
690
772
|
# Process all dependencies
|
691
|
-
while
|
773
|
+
while deps:
|
774
|
+
component = deps.pop()
|
692
775
|
# Skip duplicates
|
693
776
|
if (component_code := component.to_typst_code()) in formatted_code:
|
694
777
|
continue
|
@@ -699,13 +782,29 @@ class Article(Display, CensoredAble, WithRef[ArticleOutline]):
|
|
699
782
|
|
700
783
|
return processed_components
|
701
784
|
|
702
|
-
def iter_dfs_with_deps(
|
785
|
+
def iter_dfs_with_deps(
|
786
|
+
self, chapter: bool = True, section: bool = True, subsection: bool = True
|
787
|
+
) -> Generator[Tuple[ArticleBase, List[ArticleBase]], None, None]:
|
703
788
|
"""Iterates through the article in a depth-first manner, yielding each component and its dependencies.
|
704
789
|
|
790
|
+
Args:
|
791
|
+
chapter (bool, optional): Whether to include chapter components. Defaults to True.
|
792
|
+
section (bool, optional): Whether to include section components. Defaults to True.
|
793
|
+
subsection (bool, optional): Whether to include subsection components. Defaults to True.
|
794
|
+
|
705
795
|
Yields:
|
706
796
|
Tuple[ArticleBase, List[ArticleBase]]: Each component and its dependencies.
|
707
797
|
"""
|
798
|
+
if all((not chapter, not section, not subsection)):
|
799
|
+
raise ValueError("At least one of chapter, section, or subsection must be True.")
|
800
|
+
|
708
801
|
for component in self.iter_dfs():
|
802
|
+
if not chapter and isinstance(component, ArticleChapter):
|
803
|
+
continue
|
804
|
+
if not section and isinstance(component, ArticleSection):
|
805
|
+
continue
|
806
|
+
if not subsection and isinstance(component, ArticleSubsection):
|
807
|
+
continue
|
709
808
|
yield component, (self.gather_dependencies_recursive(component))
|
710
809
|
|
711
810
|
|
fabricatio/models/generic.py
CHANGED
@@ -94,7 +94,7 @@ class WithRef[T](Base):
|
|
94
94
|
"""Get the referenced object."""
|
95
95
|
return ok(self._reference, "_reference is None")
|
96
96
|
|
97
|
-
def update_ref(self, reference: T |
|
97
|
+
def update_ref[S](self: S, reference: T | S) -> S: # noqa: PYI019
|
98
98
|
"""Update the reference of the object."""
|
99
99
|
if isinstance(reference, self.__class__):
|
100
100
|
self._reference = reference.referenced
|
@@ -1,7 +1,7 @@
|
|
1
1
|
"""This module contains the types for the keyword arguments of the methods in the models module."""
|
2
2
|
|
3
3
|
from importlib.util import find_spec
|
4
|
-
from typing import Any, Required, TypedDict
|
4
|
+
from typing import Any, Dict, Required, TypedDict
|
5
5
|
|
6
6
|
from litellm.caching.caching import CacheMode
|
7
7
|
from litellm.types.caching import CachingSupportedCallTypes
|
@@ -114,6 +114,7 @@ class ReviewKwargs[T](ReviewInnerKwargs[T], total=False):
|
|
114
114
|
specific topics and review criteria.
|
115
115
|
"""
|
116
116
|
|
117
|
+
rating_manual: Dict[str, str]
|
117
118
|
topic: Required[str]
|
118
119
|
|
119
120
|
|
fabricatio/models/usages.py
CHANGED
@@ -7,6 +7,7 @@ import asyncstdlib
|
|
7
7
|
import litellm
|
8
8
|
from fabricatio._rust_instances import TEMPLATE_MANAGER
|
9
9
|
from fabricatio.config import configs
|
10
|
+
from fabricatio.decorators import logging_exec_time
|
10
11
|
from fabricatio.journal import logger
|
11
12
|
from fabricatio.models.generic import ScopedConfig, WithBriefing
|
12
13
|
from fabricatio.models.kwargs_types import ChooseKwargs, EmbeddingKwargs, GenerateKwargs, LLMKwargs, ValidateKwargs
|
@@ -148,9 +149,10 @@ class LLMUsage(ScopedConfig):
|
|
148
149
|
async for chunk in resp:
|
149
150
|
chunks.append(chunk)
|
150
151
|
buffer += chunk.choices[0].delta.content or ""
|
151
|
-
if len(buffer)
|
152
|
+
if len(buffer) > stream_buffer_size:
|
152
153
|
print(buffer, end="") # noqa: T201
|
153
154
|
buffer = ""
|
155
|
+
print(buffer) # noqa: T201
|
154
156
|
if pack := stream_chunk_builder(chunks):
|
155
157
|
return pack.choices
|
156
158
|
logger.critical(err := f"Unexpected response type: {type(resp)}")
|
@@ -186,6 +188,7 @@ class LLMUsage(ScopedConfig):
|
|
186
188
|
**kwargs: Unpack[LLMKwargs],
|
187
189
|
) -> str: ...
|
188
190
|
|
191
|
+
@logging_exec_time
|
189
192
|
async def aask(
|
190
193
|
self,
|
191
194
|
question: str | List[str],
|
Binary file
|
@@ -1,18 +1,18 @@
|
|
1
|
-
fabricatio-0.2.7.
|
2
|
-
fabricatio-0.2.7.
|
3
|
-
fabricatio-0.2.7.
|
4
|
-
fabricatio/decorators.py,sha256=
|
1
|
+
fabricatio-0.2.7.dev2.dist-info/METADATA,sha256=O-a8w-I-ZYDDO8utQOE2Ggf3F70kE4OZXrNS5nR-AGA,13844
|
2
|
+
fabricatio-0.2.7.dev2.dist-info/WHEEL,sha256=7FgAcpQES0h1xhfN9Ugve9FTUilU6sRAr1WJ5ph2cuw,108
|
3
|
+
fabricatio-0.2.7.dev2.dist-info/licenses/LICENSE,sha256=yDZaTLnOi03bi3Dk6f5IjhLUc5old2yOsihHWU0z-i0,1067
|
4
|
+
fabricatio/decorators.py,sha256=GrkclNTGT2bk7cjTyuca7mqSVlKwTcujcj3uBuZpT8s,7343
|
5
5
|
fabricatio/core.py,sha256=MaEKZ6DDmbdScAY-7F1gwGA6fr7ADX6Mz5rNVi2msFA,6277
|
6
|
-
fabricatio/models/generic.py,sha256=
|
6
|
+
fabricatio/models/generic.py,sha256=7rVwpdw0GsufvfxJg5gSRcpHFhAu9QVbDh0XQ80UT5M,15274
|
7
7
|
fabricatio/models/tool.py,sha256=ifivEnYiEUtjeRxQkX8vjfyzn1m1acgfrsABbQqCsGs,6912
|
8
8
|
fabricatio/models/role.py,sha256=UgIfGdfIBu4cOug8Nm1a04JCEwjXR_MDZUQhumwMptk,2710
|
9
|
-
fabricatio/models/extra.py,sha256=
|
10
|
-
fabricatio/models/kwargs_types.py,sha256=
|
9
|
+
fabricatio/models/extra.py,sha256=od7NhLAOjZ7GWTQuI5kn9YH4xcZjLK0S6YDTxNmcOF4,32604
|
10
|
+
fabricatio/models/kwargs_types.py,sha256=2tiApAy8JvpkDWKk_26_X1_g08mcHHKQz3c8pCd73x0,5286
|
11
11
|
fabricatio/models/utils.py,sha256=E1Jz7oodbn09OkBspSpzCgKkv0AiuxyQElqCgHF7bVY,5718
|
12
|
-
fabricatio/models/usages.py,sha256=
|
12
|
+
fabricatio/models/usages.py,sha256=c_yU0pBjzUW9e-om6nIImmRV32eRiX9oxSlkC2HAtz4,30837
|
13
13
|
fabricatio/models/events.py,sha256=UvOc6V3vfjKuvh7irDezJ8EGpsNo5yzLdq4xQexVonw,4063
|
14
14
|
fabricatio/models/task.py,sha256=-EnzpEyM6Z687gF1lPcmA2szEUw6dFpu3lOtseaz95o,10193
|
15
|
-
fabricatio/models/action.py,sha256=
|
15
|
+
fabricatio/models/action.py,sha256=qFEY4aISSCSMkltl166DI2j-c-Mjxo1X0SjgfnyCVpg,8537
|
16
16
|
fabricatio/toolboxes/fs.py,sha256=OQMdeokYxSNVrCZJAweJ0cYiK4k2QuEiNdIbS5IHIV8,705
|
17
17
|
fabricatio/toolboxes/__init__.py,sha256=dYm_Gd8XolSU_h4wnkA09dlaLDK146eeFz0CUgPZ8_c,380
|
18
18
|
fabricatio/toolboxes/arithmetic.py,sha256=sSTPkKI6-mb278DwQKFO9jKyzc9kCx45xNH7V6bGBpE,1307
|
@@ -25,18 +25,18 @@ fabricatio/journal.py,sha256=Op0wC-JlZumnAc_aDmYM4ljnSNLoKEEMfcIRbCF69ow,455
|
|
25
25
|
fabricatio/__init__.py,sha256=6EjK4SxbnvFxdO9ftkXD9rxSuoPEIITNzUkuMO9s3yU,1092
|
26
26
|
fabricatio/actions/output.py,sha256=sBQcpLKPslGv-HI751zTrL1H8Ec23uIWgnGDjmkF4e0,1127
|
27
27
|
fabricatio/actions/rag.py,sha256=Tsjn9IkO8OlKlhBBnk7J6qh9st61jzD6SUYClGhYs7I,2686
|
28
|
-
fabricatio/actions/article.py,sha256=
|
28
|
+
fabricatio/actions/article.py,sha256=iHpzfrHEil1Q0t9AbiFSU-X_AHxnFc7qsdd3ReFE7WM,7305
|
29
29
|
fabricatio/_rust_instances.py,sha256=bQmlhUCcxTmRgvw1SfzYzNNpgW_UCjmkYw5f-VPAyg8,304
|
30
30
|
fabricatio/workflows/articles.py,sha256=oHNV5kNKEcOKP55FA7I1SlxQRlk6N26cpem_QYu05g0,1021
|
31
31
|
fabricatio/workflows/rag.py,sha256=uOZXprD479fUhLA6sYvEM8RWcVcUZXXtP0xRbTMPdHE,509
|
32
32
|
fabricatio/parser.py,sha256=OV6bIAfLJ-GfaKoTeIOqS3X3GqCgyvzSJsgYMO3ogj4,6100
|
33
33
|
fabricatio/capabilities/correct.py,sha256=QVI1K5fU_1akCiE9r0hJgVe0Pd-rFH1pCaFlLAJyhPk,6337
|
34
34
|
fabricatio/capabilities/rag.py,sha256=FsjaMKeFgl-kBmUGDfkWn2Sa9Gp1AfOWpOZRZXZlNFY,17270
|
35
|
-
fabricatio/capabilities/rating.py,sha256=
|
36
|
-
fabricatio/capabilities/review.py,sha256=
|
35
|
+
fabricatio/capabilities/rating.py,sha256=K6dIaMDMWNUhCenuP_lFriaofj6gBPjfNXEILp5yzjU,14556
|
36
|
+
fabricatio/capabilities/review.py,sha256=_m7uGNfhW7iDhcCJrLiSBmEvMq56fpPIzNGh1X20YZM,11103
|
37
37
|
fabricatio/capabilities/propose.py,sha256=4QvONVVUp1rs34Te2Rjams6NioEt6FhEAxDWiveQnSg,1544
|
38
38
|
fabricatio/capabilities/task.py,sha256=5XUxYNkPIHKm-Q0_oCeEqS-i3kfq9twHqcDiZL0rKVo,4526
|
39
39
|
fabricatio/_rust.pyi,sha256=n6mFYqLQlyfumJZQ_E3SesR_yLrjfRLjf6N1VdlF6U8,3707
|
40
|
-
fabricatio/_rust.cpython-312-x86_64-linux-gnu.so,sha256=
|
41
|
-
fabricatio-0.2.7.
|
42
|
-
fabricatio-0.2.7.
|
40
|
+
fabricatio/_rust.cpython-312-x86_64-linux-gnu.so,sha256=D6X2ze73ooY-RQDwxI7sAXy7N45SsYt4mvf6c-gmMsk,1916440
|
41
|
+
fabricatio-0.2.7.dev2.data/scripts/tdown,sha256=6uM32dDtLgRz2941ErcuJf6GFvEzcgkS9bKm_qmFNRc,4590176
|
42
|
+
fabricatio-0.2.7.dev2.dist-info/RECORD,,
|
File without changes
|
File without changes
|