fabricatio 0.2.8.dev4__cp312-cp312-win_amd64.whl → 0.2.9__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/__init__.py +4 -11
- fabricatio/actions/__init__.py +1 -0
- fabricatio/actions/article.py +98 -110
- fabricatio/actions/article_rag.py +15 -10
- fabricatio/actions/output.py +60 -4
- fabricatio/actions/rag.py +2 -1
- fabricatio/actions/rules.py +72 -0
- fabricatio/capabilities/__init__.py +1 -0
- fabricatio/capabilities/censor.py +23 -6
- fabricatio/capabilities/check.py +46 -27
- fabricatio/capabilities/correct.py +35 -16
- fabricatio/capabilities/rag.py +5 -4
- fabricatio/capabilities/rating.py +56 -49
- fabricatio/capabilities/review.py +1 -1
- fabricatio/capabilities/task.py +2 -1
- fabricatio/config.py +5 -3
- fabricatio/fs/readers.py +20 -1
- fabricatio/models/action.py +59 -36
- fabricatio/models/extra/__init__.py +1 -0
- fabricatio/models/extra/advanced_judge.py +4 -4
- fabricatio/models/extra/article_base.py +124 -61
- fabricatio/models/extra/article_main.py +100 -17
- fabricatio/models/extra/article_outline.py +2 -3
- fabricatio/models/extra/article_proposal.py +15 -14
- fabricatio/models/extra/patches.py +17 -4
- fabricatio/models/extra/problem.py +31 -23
- fabricatio/models/extra/rule.py +39 -8
- fabricatio/models/generic.py +369 -78
- fabricatio/models/task.py +1 -1
- fabricatio/models/tool.py +149 -14
- fabricatio/models/usages.py +46 -42
- fabricatio/parser.py +5 -5
- fabricatio/rust.cp312-win_amd64.pyd +0 -0
- fabricatio/{_rust.pyi → rust.pyi} +42 -4
- fabricatio/{_rust_instances.py → rust_instances.py} +1 -1
- fabricatio/utils.py +5 -5
- fabricatio/workflows/__init__.py +1 -0
- fabricatio/workflows/articles.py +3 -5
- fabricatio-0.2.9.data/scripts/tdown.exe +0 -0
- {fabricatio-0.2.8.dev4.dist-info → fabricatio-0.2.9.dist-info}/METADATA +1 -1
- fabricatio-0.2.9.dist-info/RECORD +61 -0
- fabricatio/_rust.cp312-win_amd64.pyd +0 -0
- fabricatio-0.2.8.dev4.data/scripts/tdown.exe +0 -0
- fabricatio-0.2.8.dev4.dist-info/RECORD +0 -56
- {fabricatio-0.2.8.dev4.dist-info → fabricatio-0.2.9.dist-info}/WHEEL +0 -0
- {fabricatio-0.2.8.dev4.dist-info → fabricatio-0.2.9.dist-info}/licenses/LICENSE +0 -0
@@ -8,6 +8,8 @@ from typing import Optional, Unpack
|
|
8
8
|
|
9
9
|
from fabricatio.capabilities.check import Check
|
10
10
|
from fabricatio.capabilities.correct import Correct
|
11
|
+
from fabricatio.journal import logger
|
12
|
+
from fabricatio.models.extra.problem import Improvement
|
11
13
|
from fabricatio.models.extra.rule import RuleSet
|
12
14
|
from fabricatio.models.generic import ProposedUpdateAble, SketchedAble
|
13
15
|
from fabricatio.models.kwargs_types import ReferencedKwargs
|
@@ -19,6 +21,7 @@ class Censor(Correct, Check):
|
|
19
21
|
|
20
22
|
Inherits from both Correct and Check classes.
|
21
23
|
Provides methods to censor objects and strings by first checking them against a ruleset and then correcting them if necessary.
|
24
|
+
|
22
25
|
"""
|
23
26
|
|
24
27
|
async def censor_obj[M: SketchedAble](
|
@@ -39,8 +42,12 @@ class Censor(Correct, Check):
|
|
39
42
|
"""
|
40
43
|
imp = await self.check_obj(obj, ruleset, **override_kwargs(kwargs, default=None))
|
41
44
|
if imp is None:
|
42
|
-
return
|
43
|
-
|
45
|
+
return None
|
46
|
+
if not imp:
|
47
|
+
logger.info(f"No improvement found for `{obj.__class__.__name__}`.")
|
48
|
+
return obj
|
49
|
+
logger.info(f'Generated {len(imp)} improvement(s) for `{obj.__class__.__name__}')
|
50
|
+
return await self.correct_obj(obj, Improvement.gather(*imp), **kwargs)
|
44
51
|
|
45
52
|
async def censor_string(
|
46
53
|
self, input_text: str, ruleset: RuleSet, **kwargs: Unpack[ReferencedKwargs[str]]
|
@@ -60,8 +67,13 @@ class Censor(Correct, Check):
|
|
60
67
|
"""
|
61
68
|
imp = await self.check_string(input_text, ruleset, **override_kwargs(kwargs, default=None))
|
62
69
|
if imp is None:
|
63
|
-
|
64
|
-
|
70
|
+
logger.warning(f"Censor failed for string:\n{input_text}")
|
71
|
+
return None
|
72
|
+
if not imp:
|
73
|
+
logger.info("No improvement found for string.")
|
74
|
+
return input_text
|
75
|
+
logger.info(f'Generated {len(imp)} improvement(s) for string.')
|
76
|
+
return await self.correct_string(input_text, Improvement.gather(*imp), **kwargs)
|
65
77
|
|
66
78
|
async def censor_obj_inplace[M: ProposedUpdateAble](
|
67
79
|
self, obj: M, ruleset: RuleSet, **kwargs: Unpack[ReferencedKwargs[M]]
|
@@ -83,5 +95,10 @@ class Censor(Correct, Check):
|
|
83
95
|
"""
|
84
96
|
imp = await self.check_obj(obj, ruleset, **override_kwargs(kwargs, default=None))
|
85
97
|
if imp is None:
|
86
|
-
|
87
|
-
|
98
|
+
logger.warning(f"Censor failed for `{obj.__class__.__name__}`")
|
99
|
+
return None
|
100
|
+
if not imp:
|
101
|
+
logger.info(f"No improvement found for `{obj.__class__.__name__}`.")
|
102
|
+
return obj
|
103
|
+
logger.info(f'Generated {len(imp)} improvement(s) for `{obj.__class__.__name__}')
|
104
|
+
return await self.correct_obj_inplace(obj, improvement=Improvement.gather(*imp), **kwargs)
|
fabricatio/capabilities/check.py
CHANGED
@@ -1,16 +1,19 @@
|
|
1
1
|
"""A class that provides the capability to check strings and objects against rules and guidelines."""
|
2
2
|
|
3
|
-
from
|
3
|
+
from asyncio import gather
|
4
|
+
from typing import List, Optional, Unpack
|
4
5
|
|
5
6
|
from fabricatio import TEMPLATE_MANAGER
|
6
7
|
from fabricatio.capabilities.advanced_judge import AdvancedJudge
|
7
8
|
from fabricatio.capabilities.propose import Propose
|
8
9
|
from fabricatio.config import configs
|
9
|
-
from fabricatio.
|
10
|
+
from fabricatio.journal import logger
|
11
|
+
from fabricatio.models.extra.patches import RuleSetMetadata
|
10
12
|
from fabricatio.models.extra.problem import Improvement
|
11
13
|
from fabricatio.models.extra.rule import Rule, RuleSet
|
12
14
|
from fabricatio.models.generic import Display, WithBriefing
|
13
15
|
from fabricatio.models.kwargs_types import ValidateKwargs
|
16
|
+
from fabricatio.rust import detect_language
|
14
17
|
from fabricatio.utils import override_kwargs
|
15
18
|
|
16
19
|
|
@@ -39,32 +42,43 @@ class Check(AdvancedJudge, Propose):
|
|
39
42
|
- Returns None if any step in rule generation fails
|
40
43
|
- Uses `alist_str` for requirement breakdown and iterative rule proposal
|
41
44
|
"""
|
42
|
-
rule_reqs =
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
45
|
+
rule_reqs = (
|
46
|
+
await self.alist_str(
|
47
|
+
TEMPLATE_MANAGER.render_template(
|
48
|
+
configs.templates.ruleset_requirement_breakdown_template,
|
49
|
+
{"ruleset_requirement": ruleset_requirement},
|
50
|
+
),
|
51
|
+
rule_count,
|
52
|
+
**override_kwargs(kwargs, default=None),
|
53
|
+
)
|
54
|
+
if rule_count > 1
|
55
|
+
else [ruleset_requirement]
|
48
56
|
)
|
49
57
|
|
50
58
|
if rule_reqs is None:
|
51
59
|
return None
|
52
60
|
|
53
|
-
rules = await self.propose(
|
61
|
+
rules = await self.propose(
|
62
|
+
Rule,
|
63
|
+
[
|
64
|
+
TEMPLATE_MANAGER.render_template(configs.templates.rule_requirement_template, {"rule_requirement": r})
|
65
|
+
for r in rule_reqs
|
66
|
+
],
|
67
|
+
**kwargs,
|
68
|
+
)
|
54
69
|
if any(r for r in rules if r is None):
|
55
70
|
return None
|
56
71
|
|
57
72
|
ruleset_patch = await self.propose(
|
58
|
-
|
59
|
-
f"
|
60
|
-
f"You need to write a concise and detailed patch for this ruleset that can be applied to the ruleset nicely",
|
73
|
+
RuleSetMetadata,
|
74
|
+
f"{ruleset_requirement}\n\nYou should use `{detect_language(ruleset_requirement)}`!",
|
61
75
|
**override_kwargs(kwargs, default=None),
|
62
76
|
)
|
63
77
|
|
64
78
|
if ruleset_patch is None:
|
65
79
|
return None
|
66
80
|
|
67
|
-
return
|
81
|
+
return RuleSet(rules=rules, **ruleset_patch.as_kwargs())
|
68
82
|
|
69
83
|
async def check_string_against_rule(
|
70
84
|
self,
|
@@ -90,14 +104,16 @@ class Check(AdvancedJudge, Propose):
|
|
90
104
|
- Proposes Improvement only when violation is confirmed
|
91
105
|
"""
|
92
106
|
if judge := await self.evidently_judge(
|
93
|
-
f"# Content to exam\n{input_text}\n\n# Rule Must to follow\n{rule.display()}\nDoes `Content to exam` provided above violate the `
|
107
|
+
f"# Content to exam\n{input_text}\n\n# Rule Must to follow\n{rule.display()}\nDoes `Content to exam` provided above violate the `{rule.name}` provided above?"
|
108
|
+
f"should I take some measure to fix that violation? true for I do need, false for I don't need.",
|
94
109
|
**override_kwargs(kwargs, default=None),
|
95
110
|
):
|
111
|
+
logger.info(f"Rule `{rule.name}` violated: \n{judge.display()}")
|
96
112
|
return await self.propose(
|
97
113
|
Improvement,
|
98
114
|
TEMPLATE_MANAGER.render_template(
|
99
115
|
configs.templates.check_string_template,
|
100
|
-
{"to_check": input_text, "rule": rule, "judge": judge.display(), "reference": reference},
|
116
|
+
{"to_check": input_text, "rule": rule.display(), "judge": judge.display(), "reference": reference},
|
101
117
|
),
|
102
118
|
**kwargs,
|
103
119
|
)
|
@@ -141,7 +157,7 @@ class Check(AdvancedJudge, Propose):
|
|
141
157
|
ruleset: RuleSet,
|
142
158
|
reference: str = "",
|
143
159
|
**kwargs: Unpack[ValidateKwargs[Improvement]],
|
144
|
-
) -> Optional[Improvement]:
|
160
|
+
) -> Optional[List[Improvement]]:
|
145
161
|
"""Validate text against full ruleset.
|
146
162
|
|
147
163
|
Args:
|
@@ -158,12 +174,13 @@ class Check(AdvancedJudge, Propose):
|
|
158
174
|
- Halts validation after first successful improvement proposal
|
159
175
|
- Maintains rule execution order from ruleset.rules list
|
160
176
|
"""
|
161
|
-
imp_seq =
|
162
|
-
|
163
|
-
|
164
|
-
if
|
165
|
-
|
166
|
-
|
177
|
+
imp_seq = await gather(
|
178
|
+
*[self.check_string_against_rule(input_text, rule, reference, **kwargs) for rule in ruleset.rules]
|
179
|
+
)
|
180
|
+
if imp_seq is None:
|
181
|
+
logger.warning(f"Generation failed for string check against `{ruleset.name}`")
|
182
|
+
return None
|
183
|
+
return [imp for imp in imp_seq if imp]
|
167
184
|
|
168
185
|
async def check_obj[M: (Display, WithBriefing)](
|
169
186
|
self,
|
@@ -171,7 +188,7 @@ class Check(AdvancedJudge, Propose):
|
|
171
188
|
ruleset: RuleSet,
|
172
189
|
reference: str = "",
|
173
190
|
**kwargs: Unpack[ValidateKwargs[Improvement]],
|
174
|
-
) -> Optional[Improvement]:
|
191
|
+
) -> Optional[List[Improvement]]:
|
175
192
|
"""Validate object against full ruleset.
|
176
193
|
|
177
194
|
Args:
|
@@ -188,7 +205,9 @@ class Check(AdvancedJudge, Propose):
|
|
188
205
|
- Maintains same early termination behavior as check_string
|
189
206
|
- Validates object through text conversion mechanism
|
190
207
|
"""
|
191
|
-
imp_seq =
|
192
|
-
|
193
|
-
|
194
|
-
|
208
|
+
imp_seq = await gather(*[self.check_obj_against_rule(obj, rule, reference, **kwargs) for rule in ruleset.rules])
|
209
|
+
|
210
|
+
if imp_seq is None:
|
211
|
+
logger.warning(f"Generation Failed for `{obj.__class__.__name__}` against Ruleset `{ruleset.name}`")
|
212
|
+
return None
|
213
|
+
return [i for i in imp_seq if i]
|
@@ -1,8 +1,8 @@
|
|
1
1
|
"""A module containing the Correct capability for reviewing, validating, and improving objects."""
|
2
2
|
|
3
|
+
from asyncio import gather
|
3
4
|
from typing import Optional, Type, Unpack, cast
|
4
5
|
|
5
|
-
from fabricatio._rust_instances import TEMPLATE_MANAGER
|
6
6
|
from fabricatio.capabilities.propose import Propose
|
7
7
|
from fabricatio.capabilities.rating import Rating
|
8
8
|
from fabricatio.config import configs
|
@@ -14,7 +14,8 @@ from fabricatio.models.kwargs_types import (
|
|
14
14
|
BestKwargs,
|
15
15
|
ValidateKwargs,
|
16
16
|
)
|
17
|
-
from fabricatio.
|
17
|
+
from fabricatio.rust_instances import TEMPLATE_MANAGER
|
18
|
+
from fabricatio.utils import fallback_kwargs, ok, override_kwargs
|
18
19
|
|
19
20
|
|
20
21
|
class Correct(Rating, Propose):
|
@@ -33,8 +34,9 @@ class Correct(Rating, Propose):
|
|
33
34
|
ProblemSolutions: The problem solutions with the best solution selected.
|
34
35
|
"""
|
35
36
|
if (leng := len(problem_solutions.solutions)) == 0:
|
36
|
-
logger.error(f"No solutions found in ProblemSolutions, Skip: {problem_solutions.problem}")
|
37
|
+
logger.error(f"No solutions found in ProblemSolutions, Skip: `{problem_solutions.problem.name}`")
|
37
38
|
if leng > 1:
|
39
|
+
logger.info(f"{leng} solutions found in Problem `{problem_solutions.problem.name}`, select the best.")
|
38
40
|
problem_solutions.solutions = await self.best(problem_solutions.solutions, **kwargs)
|
39
41
|
return problem_solutions
|
40
42
|
|
@@ -48,11 +50,25 @@ class Correct(Rating, Propose):
|
|
48
50
|
Returns:
|
49
51
|
Improvement: The improvement with the best solutions selected for each problem solution.
|
50
52
|
"""
|
51
|
-
if
|
53
|
+
if leng := len(improvement.problem_solutions):
|
54
|
+
logger.debug(f"{leng} problem_solutions found in Improvement, decide solution for each of them.")
|
55
|
+
await gather(
|
56
|
+
*[
|
57
|
+
self.decide_solution(
|
58
|
+
ps,
|
59
|
+
**fallback_kwargs(
|
60
|
+
kwargs, topic=f"which solution is better to deal this problem {ps.problem.description}\n\n"
|
61
|
+
),
|
62
|
+
)
|
63
|
+
for ps in improvement.problem_solutions
|
64
|
+
],
|
65
|
+
)
|
66
|
+
if any(not (violated := ps).decided() for ps in improvement.problem_solutions):
|
67
|
+
logger.error(f"Some problem_solutions are not decided: {violated}")
|
68
|
+
else:
|
69
|
+
logger.success(f"All problem_solutions are decided '{improvement.focused_on}'")
|
70
|
+
else:
|
52
71
|
logger.error(f"No problem_solutions found in Improvement, Skip: {improvement}")
|
53
|
-
if leng > 1:
|
54
|
-
for ps in improvement.problem_solutions:
|
55
|
-
ps.solutions = await self.best(ps.solutions, **kwargs)
|
56
72
|
return improvement
|
57
73
|
|
58
74
|
async def fix_troubled_obj[M: SketchedAble](
|
@@ -78,11 +94,11 @@ class Correct(Rating, Propose):
|
|
78
94
|
TEMPLATE_MANAGER.render_template(
|
79
95
|
configs.templates.fix_troubled_obj_template,
|
80
96
|
{
|
81
|
-
"problem": problem_solutions.problem,
|
97
|
+
"problem": problem_solutions.problem.display(),
|
82
98
|
"solution": ok(
|
83
99
|
problem_solutions.final_solution(),
|
84
|
-
f"
|
85
|
-
),
|
100
|
+
f"{len(problem_solutions.solutions)} solution Found for `{problem_solutions.problem.name}`.",
|
101
|
+
).display(),
|
86
102
|
"reference": reference,
|
87
103
|
},
|
88
104
|
),
|
@@ -111,11 +127,11 @@ class Correct(Rating, Propose):
|
|
111
127
|
TEMPLATE_MANAGER.render_template(
|
112
128
|
configs.templates.fix_troubled_string_template,
|
113
129
|
{
|
114
|
-
"problem": problem_solutions.problem,
|
130
|
+
"problem": problem_solutions.problem.display(),
|
115
131
|
"solution": ok(
|
116
132
|
problem_solutions.final_solution(),
|
117
133
|
f"No solution found for problem: {problem_solutions.problem}",
|
118
|
-
),
|
134
|
+
).display(),
|
119
135
|
"reference": reference,
|
120
136
|
"string_to_fix": input_text,
|
121
137
|
},
|
@@ -148,14 +164,15 @@ class Correct(Rating, Propose):
|
|
148
164
|
TypeError: If the provided object doesn't implement Display or WithBriefing interfaces.
|
149
165
|
"""
|
150
166
|
if not improvement.decided():
|
167
|
+
logger.info(f"Improvement {improvement.focused_on} not decided, start deciding...")
|
151
168
|
improvement = await self.decide_improvement(improvement, **override_kwargs(kwargs, default=None))
|
152
169
|
|
153
|
-
|
170
|
+
total = len(improvement.problem_solutions)
|
171
|
+
for idx, ps in enumerate(improvement.problem_solutions):
|
172
|
+
logger.info(f"[{idx + 1}/{total}] Fixing {obj.__class__.__name__} for problem `{ps.problem.name}`")
|
154
173
|
fixed_obj = await self.fix_troubled_obj(obj, ps, reference, **kwargs)
|
155
174
|
if fixed_obj is None:
|
156
|
-
logger.error(
|
157
|
-
f"Failed to fix troubling obj {obj.__class__.__name__} when deal with problem: {ps.problem}",
|
158
|
-
)
|
175
|
+
logger.error(f"[{idx + 1}/{total}] Failed to fix problem `{ps.problem.name}`")
|
159
176
|
return None
|
160
177
|
obj = fixed_obj
|
161
178
|
return obj
|
@@ -178,6 +195,8 @@ class Correct(Rating, Propose):
|
|
178
195
|
Optional[str]: A corrected version of the input string, or None if correction fails.
|
179
196
|
"""
|
180
197
|
if not improvement.decided():
|
198
|
+
logger.info(f"Improvement {improvement.focused_on} not decided, start deciding...")
|
199
|
+
|
181
200
|
improvement = await self.decide_improvement(improvement, **override_kwargs(kwargs, default=None))
|
182
201
|
|
183
202
|
for ps in improvement.problem_solutions:
|
fabricatio/capabilities/rag.py
CHANGED
@@ -3,14 +3,16 @@
|
|
3
3
|
try:
|
4
4
|
from pymilvus import MilvusClient
|
5
5
|
except ImportError as e:
|
6
|
-
raise RuntimeError("pymilvus is not installed. Have you installed `fabricatio[rag]` instead of `fabricatio
|
6
|
+
raise RuntimeError("pymilvus is not installed. Have you installed `fabricatio[rag]` instead of `fabricatio`?") from e
|
7
7
|
from functools import lru_cache
|
8
8
|
from operator import itemgetter
|
9
9
|
from os import PathLike
|
10
10
|
from pathlib import Path
|
11
11
|
from typing import Any, Callable, Dict, List, Optional, Self, Union, Unpack, cast, overload
|
12
12
|
|
13
|
-
from
|
13
|
+
from more_itertools.recipes import flatten, unique
|
14
|
+
from pydantic import Field, PrivateAttr
|
15
|
+
|
14
16
|
from fabricatio.config import configs
|
15
17
|
from fabricatio.journal import logger
|
16
18
|
from fabricatio.models.kwargs_types import (
|
@@ -23,9 +25,8 @@ from fabricatio.models.kwargs_types import (
|
|
23
25
|
)
|
24
26
|
from fabricatio.models.usages import EmbeddingUsage
|
25
27
|
from fabricatio.models.utils import MilvusData
|
28
|
+
from fabricatio.rust_instances import TEMPLATE_MANAGER
|
26
29
|
from fabricatio.utils import ok
|
27
|
-
from more_itertools.recipes import flatten, unique
|
28
|
-
from pydantic import Field, PrivateAttr
|
29
30
|
|
30
31
|
|
31
32
|
@lru_cache(maxsize=None)
|
@@ -4,19 +4,20 @@ from itertools import permutations
|
|
4
4
|
from random import sample
|
5
5
|
from typing import Dict, List, Optional, Set, Tuple, Union, Unpack, overload
|
6
6
|
|
7
|
-
from
|
7
|
+
from more_itertools import flatten, windowed
|
8
|
+
from pydantic import Field, NonNegativeInt, PositiveInt, create_model
|
9
|
+
|
10
|
+
from fabricatio.capabilities.propose import Propose
|
8
11
|
from fabricatio.config import configs
|
9
12
|
from fabricatio.journal import logger
|
10
|
-
from fabricatio.models.generic import Display
|
13
|
+
from fabricatio.models.generic import Display, ProposedAble
|
11
14
|
from fabricatio.models.kwargs_types import CompositeScoreKwargs, ValidateKwargs
|
12
|
-
from fabricatio.models.usages import LLMUsage
|
13
15
|
from fabricatio.parser import JsonCapture
|
14
|
-
from fabricatio.
|
15
|
-
from
|
16
|
-
from pydantic import NonNegativeInt, PositiveInt
|
16
|
+
from fabricatio.rust_instances import TEMPLATE_MANAGER
|
17
|
+
from fabricatio.utils import fallback_kwargs, ok, override_kwargs
|
17
18
|
|
18
19
|
|
19
|
-
class Rating(
|
20
|
+
class Rating(Propose):
|
20
21
|
"""A class that provides functionality to rate tasks based on a rating manual and score range.
|
21
22
|
|
22
23
|
References:
|
@@ -29,7 +30,7 @@ class Rating(LLMUsage):
|
|
29
30
|
rating_manual: Dict[str, str],
|
30
31
|
score_range: Tuple[float, float],
|
31
32
|
**kwargs: Unpack[ValidateKwargs[Dict[str, float]]],
|
32
|
-
) ->
|
33
|
+
) -> Dict[str, float] | List[Dict[str, float]] | List[Optional[Dict[str, float]]] | None:
|
33
34
|
"""Rate a given string based on a rating manual and score range.
|
34
35
|
|
35
36
|
Args:
|
@@ -41,45 +42,49 @@ class Rating(LLMUsage):
|
|
41
42
|
Returns:
|
42
43
|
Dict[str, float]: A dictionary with the ratings for each dimension.
|
43
44
|
"""
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
"to_rate": to_rate,
|
61
|
-
"min_score": score_range[0],
|
62
|
-
"max_score": score_range[1],
|
63
|
-
"rating_manual": rating_manual,
|
64
|
-
},
|
45
|
+
min_score, max_score = score_range
|
46
|
+
tip = (max_score - min_score) / 9
|
47
|
+
|
48
|
+
model = create_model( # pyright: ignore [reportCallIssue]
|
49
|
+
"RatingResult",
|
50
|
+
__base__=ProposedAble,
|
51
|
+
__doc__=f"The rating result contains the scores against each criterion, with min_score={min_score} and max_score={max_score}.",
|
52
|
+
**{ # pyright: ignore [reportArgumentType]
|
53
|
+
criterion: (
|
54
|
+
float,
|
55
|
+
Field(
|
56
|
+
ge=min_score,
|
57
|
+
le=max_score,
|
58
|
+
description=desc,
|
59
|
+
examples=[round(min_score + tip * i, 2) for i in range(10)],
|
60
|
+
),
|
65
61
|
)
|
62
|
+
for criterion, desc in rating_manual.items()
|
63
|
+
},
|
64
|
+
)
|
65
|
+
|
66
|
+
res = await self.propose(
|
67
|
+
model,
|
68
|
+
TEMPLATE_MANAGER.render_template(
|
69
|
+
configs.templates.rate_fine_grind_template,
|
70
|
+
{"to_rate": to_rate, "min_score": min_score, "max_score": max_score},
|
66
71
|
)
|
67
72
|
if isinstance(to_rate, str)
|
68
73
|
else [
|
69
74
|
TEMPLATE_MANAGER.render_template(
|
70
75
|
configs.templates.rate_fine_grind_template,
|
71
|
-
{
|
72
|
-
"to_rate": item,
|
73
|
-
"min_score": score_range[0],
|
74
|
-
"max_score": score_range[1],
|
75
|
-
"rating_manual": rating_manual,
|
76
|
-
},
|
76
|
+
{"to_rate": t, "min_score": min_score, "max_score": max_score},
|
77
77
|
)
|
78
|
-
for
|
78
|
+
for t in to_rate
|
79
79
|
],
|
80
|
-
|
81
|
-
**kwargs,
|
80
|
+
**override_kwargs(kwargs, default=None),
|
82
81
|
)
|
82
|
+
default = kwargs.get("default")
|
83
|
+
if isinstance(res, list):
|
84
|
+
return [r.model_dump() if r else default for r in res]
|
85
|
+
if res is None:
|
86
|
+
return default
|
87
|
+
return res.model_dump()
|
83
88
|
|
84
89
|
@overload
|
85
90
|
async def rate(
|
@@ -87,7 +92,7 @@ class Rating(LLMUsage):
|
|
87
92
|
to_rate: str,
|
88
93
|
topic: str,
|
89
94
|
criteria: Set[str],
|
90
|
-
manual: Optional[Dict[str, str]],
|
95
|
+
manual: Optional[Dict[str, str]] = None,
|
91
96
|
score_range: Tuple[float, float] = (0.0, 1.0),
|
92
97
|
**kwargs: Unpack[ValidateKwargs],
|
93
98
|
) -> Dict[str, float]: ...
|
@@ -98,7 +103,7 @@ class Rating(LLMUsage):
|
|
98
103
|
to_rate: List[str],
|
99
104
|
topic: str,
|
100
105
|
criteria: Set[str],
|
101
|
-
manual: Optional[Dict[str, str]],
|
106
|
+
manual: Optional[Dict[str, str]] = None,
|
102
107
|
score_range: Tuple[float, float] = (0.0, 1.0),
|
103
108
|
**kwargs: Unpack[ValidateKwargs],
|
104
109
|
) -> List[Dict[str, float]]: ...
|
@@ -108,10 +113,10 @@ class Rating(LLMUsage):
|
|
108
113
|
to_rate: Union[str, List[str]],
|
109
114
|
topic: str,
|
110
115
|
criteria: Set[str],
|
111
|
-
manual: Optional[Dict[str, str]],
|
116
|
+
manual: Optional[Dict[str, str]] = None,
|
112
117
|
score_range: Tuple[float, float] = (0.0, 1.0),
|
113
118
|
**kwargs: Unpack[ValidateKwargs],
|
114
|
-
) ->
|
119
|
+
) -> Dict[str, float] | List[Dict[str, float]] | List[Optional[Dict[str, float]]] | None:
|
115
120
|
"""Rate a given string or a sequence of strings based on a topic, criteria, and score range.
|
116
121
|
|
117
122
|
Args:
|
@@ -132,7 +137,7 @@ class Rating(LLMUsage):
|
|
132
137
|
or dict(zip(criteria, criteria, strict=True))
|
133
138
|
)
|
134
139
|
|
135
|
-
return await self.rate_fine_grind(to_rate, manual, score_range, **kwargs)
|
140
|
+
return await self.rate_fine_grind(to_rate, manual, score_range, **fallback_kwargs(kwargs, co_extractor={}))
|
136
141
|
|
137
142
|
async def draft_rating_manual(
|
138
143
|
self, topic: str, criteria: Optional[Set[str]] = None, **kwargs: Unpack[ValidateKwargs[Dict[str, str]]]
|
@@ -169,7 +174,7 @@ class Rating(LLMUsage):
|
|
169
174
|
configs.templates.draft_rating_manual_template,
|
170
175
|
{
|
171
176
|
"topic": topic,
|
172
|
-
"criteria": criteria,
|
177
|
+
"criteria": list(criteria),
|
173
178
|
},
|
174
179
|
)
|
175
180
|
),
|
@@ -243,7 +248,7 @@ class Rating(LLMUsage):
|
|
243
248
|
|
244
249
|
# extract reasons from the comparison of ordered pairs of extracted from examples
|
245
250
|
reasons = flatten(
|
246
|
-
await self.aask_validate(
|
251
|
+
await self.aask_validate( # pyright: ignore [reportArgumentType]
|
247
252
|
question=[
|
248
253
|
TEMPLATE_MANAGER.render_template(
|
249
254
|
configs.templates.extract_reasons_from_examples_template,
|
@@ -318,9 +323,11 @@ class Rating(LLMUsage):
|
|
318
323
|
validator=lambda resp: JsonCapture.validate_with(resp, target_type=float),
|
319
324
|
**kwargs,
|
320
325
|
)
|
326
|
+
if not all(relative_weights):
|
327
|
+
raise ValueError(f"found illegal weight: {relative_weights}")
|
321
328
|
weights = [1.0]
|
322
329
|
for rw in relative_weights:
|
323
|
-
weights.append(weights[-1] * rw)
|
330
|
+
weights.append(weights[-1] * rw) # pyright: ignore [reportOperatorIssue]
|
324
331
|
total = sum(weights)
|
325
332
|
return dict(zip(criteria_seq, [w / total for w in weights], strict=True))
|
326
333
|
|
@@ -359,14 +366,14 @@ class Rating(LLMUsage):
|
|
359
366
|
return [sum(ratings[c] * weights[c] for c in criteria) for ratings in ratings_seq]
|
360
367
|
|
361
368
|
@overload
|
362
|
-
async def best(self, candidates: List[str], k: int=1, **kwargs: Unpack[CompositeScoreKwargs]) -> List[str]: ...
|
369
|
+
async def best(self, candidates: List[str], k: int = 1, **kwargs: Unpack[CompositeScoreKwargs]) -> List[str]: ...
|
363
370
|
@overload
|
364
371
|
async def best[T: Display](
|
365
|
-
self, candidates: List[T], k: int=1, **kwargs: Unpack[CompositeScoreKwargs]
|
372
|
+
self, candidates: List[T], k: int = 1, **kwargs: Unpack[CompositeScoreKwargs]
|
366
373
|
) -> List[T]: ...
|
367
374
|
|
368
375
|
async def best[T: Display](
|
369
|
-
self, candidates: List[str] | List[T], k: int=1, **kwargs: Unpack[CompositeScoreKwargs]
|
376
|
+
self, candidates: List[str] | List[T], k: int = 1, **kwargs: Unpack[CompositeScoreKwargs]
|
370
377
|
) -> Optional[List[str] | List[T]]:
|
371
378
|
"""Choose the best candidates from the list of candidates based on the composite score.
|
372
379
|
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
from typing import Dict, Optional, Set, Unpack
|
4
4
|
|
5
|
-
from fabricatio._rust_instances import TEMPLATE_MANAGER
|
6
5
|
from fabricatio.capabilities.propose import Propose
|
7
6
|
from fabricatio.capabilities.rating import Rating
|
8
7
|
from fabricatio.config import configs
|
@@ -10,6 +9,7 @@ from fabricatio.models.extra.problem import Improvement
|
|
10
9
|
from fabricatio.models.generic import Display, WithBriefing
|
11
10
|
from fabricatio.models.kwargs_types import ReviewKwargs, ValidateKwargs
|
12
11
|
from fabricatio.models.task import Task
|
12
|
+
from fabricatio.rust_instances import TEMPLATE_MANAGER
|
13
13
|
from fabricatio.utils import ok
|
14
14
|
|
15
15
|
|
fabricatio/capabilities/task.py
CHANGED
@@ -4,7 +4,7 @@ from types import CodeType
|
|
4
4
|
from typing import Any, Dict, List, Optional, Tuple, Unpack
|
5
5
|
|
6
6
|
import orjson
|
7
|
-
|
7
|
+
|
8
8
|
from fabricatio.capabilities.propose import Propose
|
9
9
|
from fabricatio.config import configs
|
10
10
|
from fabricatio.journal import logger
|
@@ -13,6 +13,7 @@ from fabricatio.models.task import Task
|
|
13
13
|
from fabricatio.models.tool import Tool, ToolExecutor
|
14
14
|
from fabricatio.models.usages import ToolBoxUsage
|
15
15
|
from fabricatio.parser import JsonCapture, PythonCapture
|
16
|
+
from fabricatio.rust_instances import TEMPLATE_MANAGER
|
16
17
|
|
17
18
|
|
18
19
|
class ProposeTask(Propose):
|
fabricatio/config.py
CHANGED
@@ -44,7 +44,7 @@ class LLMConfig(BaseModel):
|
|
44
44
|
top_p (NonNegativeFloat): The top p of the LLM model. Controls diversity via nucleus sampling. Set to 0.35 as per request.
|
45
45
|
generation_count (PositiveInt): The number of generations to generate. Default is 1.
|
46
46
|
stream (bool): Whether to stream the LLM model's response. Default is False.
|
47
|
-
max_tokens (PositiveInt): The maximum number of tokens to generate.
|
47
|
+
max_tokens (PositiveInt): The maximum number of tokens to generate.
|
48
48
|
"""
|
49
49
|
|
50
50
|
model_config = ConfigDict(use_attribute_docstrings=True)
|
@@ -79,7 +79,7 @@ class LLMConfig(BaseModel):
|
|
79
79
|
"""Whether to stream the LLM model's response. Default is False."""
|
80
80
|
|
81
81
|
max_tokens: Optional[PositiveInt] = Field(default=None)
|
82
|
-
"""The maximum number of tokens to generate.
|
82
|
+
"""The maximum number of tokens to generate."""
|
83
83
|
|
84
84
|
rpm: Optional[PositiveInt] = Field(default=100)
|
85
85
|
"""The rate limit of the LLM model in requests per minute. None means not checked."""
|
@@ -247,6 +247,8 @@ class TemplateConfig(BaseModel):
|
|
247
247
|
fix_troubled_string_template: str = Field(default="fix_troubled_string")
|
248
248
|
"""The name of the fix troubled string template which will be used to fix a troubled string."""
|
249
249
|
|
250
|
+
rule_requirement_template: str = Field(default="rule_requirement")
|
251
|
+
"""The name of the rule requirement template which will be used to generate a rule requirement."""
|
250
252
|
class MagikaConfig(BaseModel):
|
251
253
|
"""Magika configuration class."""
|
252
254
|
|
@@ -301,7 +303,7 @@ class CacheConfig(BaseModel):
|
|
301
303
|
|
302
304
|
model_config = ConfigDict(use_attribute_docstrings=True)
|
303
305
|
|
304
|
-
type:
|
306
|
+
type: LiteLLMCacheType = LiteLLMCacheType.LOCAL
|
305
307
|
"""The type of cache to use. If None, the default cache type will be used."""
|
306
308
|
params: CacheKwargs = Field(default_factory=CacheKwargs)
|
307
309
|
"""The parameters for the cache. If type is None, the default parameters will be used."""
|
fabricatio/fs/readers.py
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
"""Filesystem readers for Fabricatio."""
|
2
2
|
|
3
3
|
from pathlib import Path
|
4
|
-
from typing import Dict
|
4
|
+
from typing import Dict, List, Tuple
|
5
5
|
|
6
6
|
import orjson
|
7
|
+
import regex
|
7
8
|
from magika import Magika
|
8
9
|
|
9
10
|
from fabricatio.config import configs
|
@@ -44,3 +45,21 @@ def safe_json_read(path: Path | str) -> Dict:
|
|
44
45
|
except (orjson.JSONDecodeError, IsADirectoryError, FileNotFoundError) as e:
|
45
46
|
logger.error(f"Failed to read file {path}: {e!s}")
|
46
47
|
return {}
|
48
|
+
|
49
|
+
|
50
|
+
def extract_sections(string: str, level: int, section_char: str = "#") -> List[Tuple[str, str]]:
|
51
|
+
"""Extract sections from markdown-style text by header level.
|
52
|
+
|
53
|
+
Args:
|
54
|
+
string (str): Input text to parse
|
55
|
+
level (int): Header level (e.g., 1 for '#', 2 for '##')
|
56
|
+
section_char (str, optional): The character used for headers (default: '#')
|
57
|
+
|
58
|
+
Returns:
|
59
|
+
List[Tuple[str, str]]: List of (header_text, section_content) tuples
|
60
|
+
"""
|
61
|
+
return regex.findall(
|
62
|
+
r"^%s{%d}\s+(.+?)\n((?:(?!^%s{%d}\s).|\n)*)" % (section_char, level, section_char, level),
|
63
|
+
string,
|
64
|
+
regex.MULTILINE,
|
65
|
+
)
|