rasa-pro 3.12.0.dev4__py3-none-any.whl → 3.12.0.dev6__py3-none-any.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.
Potentially problematic release.
This version of rasa-pro might be problematic. Click here for more details.
- rasa/cli/dialogue_understanding_test.py +40 -5
- rasa/constants.py +0 -1
- rasa/core/actions/action.py +4 -2
- rasa/core/actions/custom_action_executor.py +1 -1
- rasa/core/channels/inspector/dist/assets/Tableau10-1b767f5e.js +1 -0
- rasa/core/channels/inspector/dist/assets/arc-f0f8bd46.js +1 -0
- rasa/core/channels/inspector/dist/assets/blockDiagram-38ab4fdb-7162c77d.js +118 -0
- rasa/core/channels/inspector/dist/assets/c4Diagram-3d4e48cf-b1d0d098.js +10 -0
- rasa/core/channels/inspector/dist/assets/channel-e265ea59.js +1 -0
- rasa/core/channels/inspector/dist/assets/classDiagram-70f12bd4-807a1b27.js +2 -0
- rasa/core/channels/inspector/dist/assets/classDiagram-v2-f2320105-5238dcdb.js +2 -0
- rasa/core/channels/inspector/dist/assets/clone-21f8a43d.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-62fc7601-89c73b31.js → createText-2e5e7dd3-75dfaa67.js} +1 -1
- rasa/core/channels/inspector/dist/assets/edges-e0da2a9e-df20501d.js +4 -0
- rasa/core/channels/inspector/dist/assets/{erDiagram-9d236eb7-907e0440.js → erDiagram-9861fffd-13cf4797.js} +4 -4
- rasa/core/channels/inspector/dist/assets/flowDb-956e92f1-a4991264.js +10 -0
- rasa/core/channels/inspector/dist/assets/flowDiagram-66a62f08-ccecf773.js +4 -0
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-5c8ce12d.js +1 -0
- rasa/core/channels/inspector/dist/assets/flowchart-elk-definition-4a651766-b5801783.js +139 -0
- rasa/core/channels/inspector/dist/assets/ganttDiagram-c361ad54-161e079a.js +257 -0
- rasa/core/channels/inspector/dist/assets/gitGraphDiagram-72cf32ee-f38e86a4.js +70 -0
- rasa/core/channels/inspector/dist/assets/graph-be6ef5d8.js +1 -0
- rasa/core/channels/inspector/dist/assets/index-3862675e-d9ce8994.js +1 -0
- rasa/core/channels/inspector/dist/assets/{index-e793d777.js → index-7794b245.js} +200 -195
- rasa/core/channels/inspector/dist/assets/{infoDiagram-736b4530-8ceba4db.js → infoDiagram-f8f76790-5000a3dc.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-df861f2b-960d3809.js → journeyDiagram-49397b02-8ef0a17a.js} +4 -4
- rasa/core/channels/inspector/dist/assets/katex-498eb57e.js +261 -0
- rasa/core/channels/inspector/dist/assets/layout-d649bc98.js +1 -0
- rasa/core/channels/inspector/dist/assets/{line-eeccc4e2.js → line-95add810.js} +1 -1
- rasa/core/channels/inspector/dist/assets/linear-f6025094.js +1 -0
- rasa/core/channels/inspector/dist/assets/mindmap-definition-fc14e90a-2e8531c4.js +312 -0
- rasa/core/channels/inspector/dist/assets/{pieDiagram-dbbf0591-dc9b5e1b.js → pieDiagram-8a3498a8-918adfdb.js} +7 -7
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-4d7f4fd6-a08cba6d.js → quadrantDiagram-120e2f19-cbd01797.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-6fc4c22a-87242b9e.js → requirementDiagram-deff3bca-6a8b877b.js} +2 -2
- rasa/core/channels/inspector/dist/assets/sankeyDiagram-04a897e0-c377c3fe.js +8 -0
- rasa/core/channels/inspector/dist/assets/sequenceDiagram-704730f1-ab9e9b7f.js +122 -0
- rasa/core/channels/inspector/dist/assets/stateDiagram-587899a1-5e6ae67d.js +1 -0
- rasa/core/channels/inspector/dist/assets/stateDiagram-v2-d93cdb3a-40643476.js +1 -0
- rasa/core/channels/inspector/dist/assets/{styles-9c745c82-cef936a6.js → styles-6aaf32cf-afb8d108.js} +1 -1
- rasa/core/channels/inspector/dist/assets/styles-9a916d00-7edc9423.js +160 -0
- rasa/core/channels/inspector/dist/assets/styles-c10674c1-c1d8f7e9.js +116 -0
- rasa/core/channels/inspector/dist/assets/svgDrawCommon-08f97a94-f494b2ef.js +1 -0
- rasa/core/channels/inspector/dist/assets/{timeline-definition-5b62e21b-0d39bdb2.js → timeline-definition-85554ec2-11c7cdd0.js} +3 -3
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-2b33534f-a03fa445.js → xychartDiagram-e933f94c-3f191ec1.js} +3 -3
- rasa/core/channels/inspector/dist/index.html +1 -1
- rasa/core/channels/inspector/package.json +10 -3
- rasa/core/channels/inspector/yarn.lock +89 -99
- rasa/core/channels/studio_chat.py +14 -0
- rasa/core/nlg/contextual_response_rephraser.py +2 -1
- rasa/core/policies/enterprise_search_policy.py +2 -1
- rasa/core/processor.py +3 -3
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +2 -1
- rasa/dialogue_understanding_test/command_metric_calculation.py +8 -4
- rasa/dialogue_understanding_test/du_test_result.py +9 -0
- rasa/e2e_test/assertions.py +203 -174
- rasa/e2e_test/assertions_schema.yml +6 -0
- rasa/e2e_test/constants.py +16 -1
- rasa/e2e_test/e2e_config.py +102 -41
- rasa/e2e_test/e2e_config_schema.yml +28 -10
- rasa/e2e_test/llm_judge_prompts/answer_relevance_prompt_template.jinja2 +89 -0
- rasa/e2e_test/llm_judge_prompts/groundedness_prompt_template.jinja2 +165 -0
- rasa/e2e_test/utils/generative_assertions.py +243 -0
- rasa/server.py +3 -1
- rasa/shared/nlu/constants.py +1 -0
- rasa/shared/providers/llm/llm_response.py +21 -1
- rasa/tracing/instrumentation/attribute_extractors.py +23 -7
- rasa/utils/common.py +0 -14
- rasa/version.py +1 -1
- {rasa_pro-3.12.0.dev4.dist-info → rasa_pro-3.12.0.dev6.dist-info}/METADATA +1 -3
- {rasa_pro-3.12.0.dev4.dist-info → rasa_pro-3.12.0.dev6.dist-info}/RECORD +73 -64
- rasa/core/channels/inspector/dist/assets/arc-632a63ec.js +0 -1
- rasa/core/channels/inspector/dist/assets/c4Diagram-d0fbc5ce-081e0df4.js +0 -10
- rasa/core/channels/inspector/dist/assets/classDiagram-936ed81e-3df0afc2.js +0 -2
- rasa/core/channels/inspector/dist/assets/classDiagram-v2-c3cb15f1-8c5ed31e.js +0 -2
- rasa/core/channels/inspector/dist/assets/edges-f2ad444c-4fc48c3e.js +0 -4
- rasa/core/channels/inspector/dist/assets/flowDb-1972c806-9ec53a3c.js +0 -6
- rasa/core/channels/inspector/dist/assets/flowDiagram-7ea5b25a-41da787a.js +0 -4
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-8bea338b.js +0 -1
- rasa/core/channels/inspector/dist/assets/flowchart-elk-definition-abe16c3d-ce370633.js +0 -139
- rasa/core/channels/inspector/dist/assets/ganttDiagram-9b5ea136-90a36523.js +0 -266
- rasa/core/channels/inspector/dist/assets/gitGraphDiagram-99d0ae7c-41e1aa3f.js +0 -70
- rasa/core/channels/inspector/dist/assets/index-2c4b9a3b-e6f2af62.js +0 -1
- rasa/core/channels/inspector/dist/assets/layout-498807d8.js +0 -1
- rasa/core/channels/inspector/dist/assets/linear-8a078617.js +0 -1
- rasa/core/channels/inspector/dist/assets/mindmap-definition-beec6740-396d17dd.js +0 -109
- rasa/core/channels/inspector/dist/assets/sankeyDiagram-8f13d901-53f6f391.js +0 -8
- rasa/core/channels/inspector/dist/assets/sequenceDiagram-b655622a-715c9c20.js +0 -122
- rasa/core/channels/inspector/dist/assets/stateDiagram-59f0c015-2e8fb31f.js +0 -1
- rasa/core/channels/inspector/dist/assets/stateDiagram-v2-2b26beab-7e2d2aa0.js +0 -1
- rasa/core/channels/inspector/dist/assets/styles-080da4f6-4420cea6.js +0 -110
- rasa/core/channels/inspector/dist/assets/styles-3dcbcfbf-28676cf4.js +0 -159
- rasa/core/channels/inspector/dist/assets/svgDrawCommon-4835440b-151251e9.js +0 -1
- {rasa_pro-3.12.0.dev4.dist-info → rasa_pro-3.12.0.dev6.dist-info}/NOTICE +0 -0
- {rasa_pro-3.12.0.dev4.dist-info → rasa_pro-3.12.0.dev6.dist-info}/WHEEL +0 -0
- {rasa_pro-3.12.0.dev4.dist-info → rasa_pro-3.12.0.dev6.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
|
|
3
|
+
|
|
4
|
+
import jsonschema
|
|
5
|
+
import numpy as np
|
|
6
|
+
import structlog
|
|
7
|
+
from pydantic import BaseModel, ConfigDict
|
|
8
|
+
|
|
9
|
+
from rasa.core.constants import (
|
|
10
|
+
UTTER_SOURCE_METADATA_KEY,
|
|
11
|
+
)
|
|
12
|
+
from rasa.e2e_test.constants import (
|
|
13
|
+
KEY_JUSTIFICATION,
|
|
14
|
+
KEY_SCORE,
|
|
15
|
+
)
|
|
16
|
+
from rasa.e2e_test.e2e_config import LLMJudgeConfig
|
|
17
|
+
from rasa.shared.constants import MODEL_CONFIG_KEY, OPENAI_PROVIDER, PROVIDER_CONFIG_KEY
|
|
18
|
+
from rasa.shared.core.events import BotUttered
|
|
19
|
+
from rasa.shared.exceptions import RasaException
|
|
20
|
+
from rasa.shared.utils.llm import DEFAULT_OPENAI_EMBEDDING_MODEL_NAME, embedder_factory
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from rasa.shared.core.events import Event
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
structlogger = structlog.get_logger()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
DEFAULT_EMBEDDINGS_CONFIG = {
|
|
30
|
+
PROVIDER_CONFIG_KEY: OPENAI_PROVIDER,
|
|
31
|
+
MODEL_CONFIG_KEY: DEFAULT_OPENAI_EMBEDDING_MODEL_NAME,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
ELIGIBLE_UTTER_SOURCE_METADATA = [
|
|
35
|
+
"EnterpriseSearchPolicy",
|
|
36
|
+
"ContextualResponseRephraser",
|
|
37
|
+
"IntentlessPolicy",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
GROUNDEDNESS_JSON_SUB_SCHEMA = {
|
|
41
|
+
"properties": {
|
|
42
|
+
"statements": {
|
|
43
|
+
"type": "array",
|
|
44
|
+
"items": {
|
|
45
|
+
"type": "object",
|
|
46
|
+
"properties": {
|
|
47
|
+
"statement": {"type": "string"},
|
|
48
|
+
"score": {"type": "number"},
|
|
49
|
+
"justification": {"type": "string"},
|
|
50
|
+
},
|
|
51
|
+
"required": ["statement", "score", "justification"],
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"required": ["statements"],
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
ANSWER_RELEVANCE_JSON_SUB_SCHEMA = {
|
|
59
|
+
"properties": {
|
|
60
|
+
"question_variations": {
|
|
61
|
+
"type": "array",
|
|
62
|
+
"items": {"type": "string"},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
"required": ["question_variations"],
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
LLM_JUDGE_OUTPUT_JSON_SCHEMA = {
|
|
69
|
+
"type": "object",
|
|
70
|
+
"oneOf": [
|
|
71
|
+
GROUNDEDNESS_JSON_SUB_SCHEMA,
|
|
72
|
+
ANSWER_RELEVANCE_JSON_SUB_SCHEMA,
|
|
73
|
+
],
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class ScoreInputs(BaseModel):
|
|
78
|
+
"""Input data for the score calculation."""
|
|
79
|
+
|
|
80
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
81
|
+
|
|
82
|
+
threshold: float
|
|
83
|
+
matching_event: BotUttered
|
|
84
|
+
user_question: str
|
|
85
|
+
llm_judge_config: LLMJudgeConfig
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _calculate_similarity(
|
|
89
|
+
user_question: str,
|
|
90
|
+
generated_questions: List[str],
|
|
91
|
+
llm_judge_config: LLMJudgeConfig,
|
|
92
|
+
) -> np.ndarray:
|
|
93
|
+
"""Calculate the cosine similarity between the user question and the generated questions.""" # noqa: E501
|
|
94
|
+
embedding_client = embedder_factory(
|
|
95
|
+
llm_judge_config.embeddings_config_as_dict, DEFAULT_EMBEDDINGS_CONFIG
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
user_question_embedding_response = embedding_client.embed([user_question])
|
|
99
|
+
question_vector = np.asarray(user_question_embedding_response.data[0]).reshape(
|
|
100
|
+
1, -1
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
gen_questions_embedding_response = embedding_client.embed(generated_questions)
|
|
104
|
+
generated_questions_vectors = np.asarray(
|
|
105
|
+
gen_questions_embedding_response.data
|
|
106
|
+
).reshape(len(generated_questions), -1)
|
|
107
|
+
|
|
108
|
+
# calculate norm
|
|
109
|
+
question_vector_norm = np.linalg.norm(question_vector, axis=1)
|
|
110
|
+
generated_questions_vectors_norm = np.linalg.norm(
|
|
111
|
+
generated_questions_vectors, axis=1
|
|
112
|
+
)
|
|
113
|
+
norm = generated_questions_vectors_norm * question_vector_norm
|
|
114
|
+
norm = np.maximum(norm, 1e-10)
|
|
115
|
+
|
|
116
|
+
# calculate the dot product
|
|
117
|
+
dot_product = np.dot(generated_questions_vectors, question_vector.T).reshape(-1)
|
|
118
|
+
|
|
119
|
+
# calculate and return cosine similarity
|
|
120
|
+
return dot_product / norm
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def calculate_relevance_score(
|
|
124
|
+
processed_output: List[Union[str, Dict[str, Any]]],
|
|
125
|
+
score_inputs: ScoreInputs,
|
|
126
|
+
) -> Tuple[float, str]:
|
|
127
|
+
"""Calculate the score based on the LLM response."""
|
|
128
|
+
user_question = score_inputs.user_question
|
|
129
|
+
llm_judge_config = score_inputs.llm_judge_config
|
|
130
|
+
|
|
131
|
+
generated_questions = [output for output in processed_output]
|
|
132
|
+
if all(not question for question in generated_questions):
|
|
133
|
+
score = 0.0
|
|
134
|
+
error_justification = "No relevant questions were generated"
|
|
135
|
+
return score, error_justification
|
|
136
|
+
|
|
137
|
+
cosine_sim = _calculate_similarity(
|
|
138
|
+
user_question, generated_questions, llm_judge_config
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
score = cosine_sim.mean()
|
|
142
|
+
|
|
143
|
+
if score < score_inputs.threshold:
|
|
144
|
+
error_justifications = [
|
|
145
|
+
f"Question '{generated_questions[i]}' "
|
|
146
|
+
f"has a cosine similarity score of '{round(cosine_sim[i], 2)}' "
|
|
147
|
+
f"with the user question '{user_question}'"
|
|
148
|
+
for i in range(len(generated_questions))
|
|
149
|
+
]
|
|
150
|
+
error_justification = ", ".join(error_justifications)
|
|
151
|
+
return score, error_justification
|
|
152
|
+
|
|
153
|
+
return score, ""
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def calculate_groundedness_score(
|
|
157
|
+
processed_output: List[Any],
|
|
158
|
+
score_inputs: ScoreInputs,
|
|
159
|
+
) -> Tuple[float, str]:
|
|
160
|
+
"""Calculate the score based on the LLM response."""
|
|
161
|
+
matching_event = score_inputs.matching_event
|
|
162
|
+
|
|
163
|
+
total_statements = len(processed_output)
|
|
164
|
+
correct_statements = sum([output.get(KEY_SCORE, 0) for output in processed_output])
|
|
165
|
+
score = correct_statements / total_statements
|
|
166
|
+
|
|
167
|
+
structlogger.debug(
|
|
168
|
+
"generative_response_is_grounded_assertion.run_results",
|
|
169
|
+
matching_event=repr(matching_event),
|
|
170
|
+
score=score,
|
|
171
|
+
justification=f"There were {correct_statements} correct statements "
|
|
172
|
+
f"out of {total_statements} total extracted statements.",
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
if score < score_inputs.threshold:
|
|
176
|
+
justifications = [
|
|
177
|
+
output.get(KEY_JUSTIFICATION, "")
|
|
178
|
+
for output in processed_output
|
|
179
|
+
if output.get(KEY_SCORE, 0) == 0
|
|
180
|
+
]
|
|
181
|
+
justification = ", ".join(justifications).replace(".", "")
|
|
182
|
+
|
|
183
|
+
error_justification = (
|
|
184
|
+
f"There were {total_statements - correct_statements} "
|
|
185
|
+
f"incorrect statements out of {total_statements} total "
|
|
186
|
+
f"extracted statements. The justifications for "
|
|
187
|
+
f"these statements include: {justification}"
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
return score, error_justification
|
|
191
|
+
|
|
192
|
+
return score, ""
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _find_matching_generative_events(
|
|
196
|
+
turn_events: List["Event"], utter_source: Optional[str]
|
|
197
|
+
) -> List[BotUttered]:
|
|
198
|
+
"""Find the matching events for the generative response assertions."""
|
|
199
|
+
if utter_source is None:
|
|
200
|
+
return [
|
|
201
|
+
event
|
|
202
|
+
for event in turn_events
|
|
203
|
+
if isinstance(event, BotUttered)
|
|
204
|
+
and event.metadata.get(UTTER_SOURCE_METADATA_KEY)
|
|
205
|
+
in ELIGIBLE_UTTER_SOURCE_METADATA
|
|
206
|
+
]
|
|
207
|
+
|
|
208
|
+
return [
|
|
209
|
+
event
|
|
210
|
+
for event in turn_events
|
|
211
|
+
if isinstance(event, BotUttered)
|
|
212
|
+
and event.metadata.get(UTTER_SOURCE_METADATA_KEY) == utter_source
|
|
213
|
+
]
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _parse_llm_output(llm_response: str, bot_message: str) -> Dict[str, Any]:
|
|
217
|
+
"""Parse the LLM output."""
|
|
218
|
+
llm_output = (
|
|
219
|
+
llm_response.replace("```json\n", "").replace("```", "").replace("\n", "")
|
|
220
|
+
)
|
|
221
|
+
try:
|
|
222
|
+
parsed_llm_output = json.loads(llm_output)
|
|
223
|
+
except json.JSONDecodeError as exc:
|
|
224
|
+
raise RasaException(
|
|
225
|
+
f"Failed to parse the LLM Judge response '{llm_output}' for "
|
|
226
|
+
f"the generative bot message '{bot_message}': {exc}"
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
return parsed_llm_output
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def _validate_parsed_llm_output(
|
|
233
|
+
parsed_llm_output: Dict[str, Any], bot_message: str
|
|
234
|
+
) -> None:
|
|
235
|
+
"""Validate the parsed LLM output."""
|
|
236
|
+
try:
|
|
237
|
+
jsonschema.validate(parsed_llm_output, LLM_JUDGE_OUTPUT_JSON_SCHEMA)
|
|
238
|
+
except jsonschema.ValidationError as exc:
|
|
239
|
+
raise RasaException(
|
|
240
|
+
f"Failed to validate the LLM Judge json response "
|
|
241
|
+
f"'{parsed_llm_output}' for the generative bot message "
|
|
242
|
+
f"'{bot_message}'. Error: {exc}"
|
|
243
|
+
)
|
rasa/server.py
CHANGED
|
@@ -272,7 +272,9 @@ def requires_auth(
|
|
|
272
272
|
raise ErrorResponse(
|
|
273
273
|
HTTPStatus.UNAUTHORIZED,
|
|
274
274
|
"NotAuthenticated",
|
|
275
|
-
"User is not authenticated.",
|
|
275
|
+
"User is not authenticated. ",
|
|
276
|
+
"Please make sure the use of token is supported and that "
|
|
277
|
+
"the supplied token is valid.",
|
|
276
278
|
help_url=_docs(
|
|
277
279
|
"/user-guide/configuring-http-api/#security-considerations"
|
|
278
280
|
),
|
rasa/shared/nlu/constants.py
CHANGED
|
@@ -9,6 +9,7 @@ KEY_SYSTEM_PROMPT = "system_prompt"
|
|
|
9
9
|
KEY_LLM_RESPONSE_METADATA = "llm_response_metadata"
|
|
10
10
|
KEY_PROMPT_NAME = "prompt_name"
|
|
11
11
|
KEY_COMPONENT_NAME = "component_name"
|
|
12
|
+
KEY_LATENCY = "latency"
|
|
12
13
|
LLM_COMMANDS = "llm_commands" # needed for fine-tuning
|
|
13
14
|
LLM_PROMPT = "llm_prompt" # needed for fine-tuning
|
|
14
15
|
FLOWS_FROM_SEMANTIC_SEARCH = "flows_from_semantic_search"
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import time
|
|
1
3
|
from dataclasses import asdict, dataclass, field
|
|
2
|
-
from typing import Any, Dict, List, Optional, Text, Union
|
|
4
|
+
from typing import Any, Awaitable, Callable, Dict, List, Optional, Text, Union
|
|
3
5
|
|
|
4
6
|
import structlog
|
|
5
7
|
|
|
@@ -57,6 +59,9 @@ class LLMResponse:
|
|
|
57
59
|
"""Optional dictionary for storing additional information related to the
|
|
58
60
|
completion that may not be covered by other fields."""
|
|
59
61
|
|
|
62
|
+
latency: Optional[float] = None
|
|
63
|
+
"""Optional field to store the latency of the LLM API call."""
|
|
64
|
+
|
|
60
65
|
@classmethod
|
|
61
66
|
def from_dict(cls, data: Dict[Text, Any]) -> "LLMResponse":
|
|
62
67
|
"""Creates an LLMResponse from a dictionary."""
|
|
@@ -70,6 +75,7 @@ class LLMResponse:
|
|
|
70
75
|
model=data.get("model"),
|
|
71
76
|
usage=usage_obj,
|
|
72
77
|
additional_info=data.get("additional_info"),
|
|
78
|
+
latency=data.get("latency"),
|
|
73
79
|
)
|
|
74
80
|
|
|
75
81
|
@classmethod
|
|
@@ -87,3 +93,17 @@ class LLMResponse:
|
|
|
87
93
|
if self.usage:
|
|
88
94
|
result["usage"] = self.usage.to_dict()
|
|
89
95
|
return result
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def measure_llm_latency(
|
|
99
|
+
func: Callable[..., Awaitable[Optional[LLMResponse]]],
|
|
100
|
+
) -> Callable[..., Awaitable[Optional[LLMResponse]]]:
|
|
101
|
+
@functools.wraps(func)
|
|
102
|
+
async def wrapper(*args: Any, **kwargs: Any) -> Optional[LLMResponse]:
|
|
103
|
+
start = time.perf_counter()
|
|
104
|
+
result: Optional[LLMResponse] = await func(*args, **kwargs)
|
|
105
|
+
if result:
|
|
106
|
+
result.latency = time.perf_counter() - start
|
|
107
|
+
return result
|
|
108
|
+
|
|
109
|
+
return wrapper
|
|
@@ -24,7 +24,6 @@ from rasa.dialogue_understanding.stack.dialogue_stack import DialogueStack
|
|
|
24
24
|
from rasa.dialogue_understanding_test.du_test_result import (
|
|
25
25
|
KEY_TEST_CASES_ACCURACY,
|
|
26
26
|
KEY_USER_UTTERANCES_ACCURACY,
|
|
27
|
-
OUTPUT_COMMAND_METRICS,
|
|
28
27
|
OUTPUT_NAMES_OF_FAILED_TESTS,
|
|
29
28
|
OUTPUT_NAMES_OF_PASSED_TESTS,
|
|
30
29
|
OUTPUT_NUMBER_OF_FAILED_TESTS,
|
|
@@ -44,6 +43,7 @@ from rasa.shared.constants import (
|
|
|
44
43
|
LLM_CONFIG_KEY,
|
|
45
44
|
MODEL_CONFIG_KEY,
|
|
46
45
|
MODEL_GROUP_ID_CONFIG_KEY,
|
|
46
|
+
MODELS_CONFIG_KEY,
|
|
47
47
|
PROVIDER_CONFIG_KEY,
|
|
48
48
|
TIMEOUT_CONFIG_KEY,
|
|
49
49
|
)
|
|
@@ -614,12 +614,28 @@ def extract_attrs_for_du_print_test_results(
|
|
|
614
614
|
),
|
|
615
615
|
}
|
|
616
616
|
if test_suite_result.command_metrics:
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
617
|
+
for (
|
|
618
|
+
command_name,
|
|
619
|
+
command_metric,
|
|
620
|
+
) in test_suite_result.command_metrics.items():
|
|
621
|
+
# OpenTelemetry / Honeycomb doesn't support dictionaries/json values,
|
|
622
|
+
# so we need to set the values as separate attributes
|
|
623
|
+
for metric_name, value in command_metric.as_dict().items():
|
|
624
|
+
attributes_dict[f"{command_name}_{metric_name}"] = value
|
|
625
|
+
|
|
626
|
+
if test_suite_result.llm_config:
|
|
627
|
+
# check if model group syntax is used
|
|
628
|
+
if MODELS_CONFIG_KEY in test_suite_result.llm_config:
|
|
629
|
+
for idx, model_group in enumerate(
|
|
630
|
+
test_suite_result.llm_config[MODELS_CONFIG_KEY]
|
|
631
|
+
):
|
|
632
|
+
for key, value in model_group.items():
|
|
633
|
+
if value is not None:
|
|
634
|
+
attributes_dict[f"llm_config_{idx}_{key}"] = value
|
|
635
|
+
else:
|
|
636
|
+
for key, value in test_suite_result.llm_config.items():
|
|
637
|
+
attributes_dict[f"llm_config_0_{key}"] = value
|
|
638
|
+
|
|
623
639
|
return attributes_dict
|
|
624
640
|
|
|
625
641
|
|
rasa/utils/common.py
CHANGED
|
@@ -35,7 +35,6 @@ from rasa.constants import (
|
|
|
35
35
|
ENV_LOG_LEVEL_KAFKA,
|
|
36
36
|
ENV_LOG_LEVEL_LIBRARIES,
|
|
37
37
|
ENV_LOG_LEVEL_MATPLOTLIB,
|
|
38
|
-
ENV_LOG_LEVEL_MLFLOW,
|
|
39
38
|
ENV_LOG_LEVEL_RABBITMQ,
|
|
40
39
|
)
|
|
41
40
|
from rasa.shared.constants import DEFAULT_LOG_LEVEL, ENV_LOG_LEVEL, TCP_PROTOCOL
|
|
@@ -396,19 +395,6 @@ def update_faker_log_level(library_log_level: Text) -> None:
|
|
|
396
395
|
logging.getLogger("faker").propagate = False
|
|
397
396
|
|
|
398
397
|
|
|
399
|
-
def update_mlflow_log_level() -> None:
|
|
400
|
-
"""Set the log level of mlflow.
|
|
401
|
-
|
|
402
|
-
Uses the library specific log level or the general libraries log level.
|
|
403
|
-
"""
|
|
404
|
-
library_log_level = os.environ.get(
|
|
405
|
-
ENV_LOG_LEVEL_LIBRARIES, DEFAULT_LOG_LEVEL_LIBRARIES
|
|
406
|
-
)
|
|
407
|
-
log_level = os.environ.get(ENV_LOG_LEVEL_MLFLOW, library_log_level)
|
|
408
|
-
logging.getLogger("mlflow").setLevel(log_level)
|
|
409
|
-
logging.getLogger("mlflow").propagate = False
|
|
410
|
-
|
|
411
|
-
|
|
412
398
|
def sort_list_of_dicts_by_first_key(dicts: List[Dict]) -> List[Dict]:
|
|
413
399
|
"""Sorts a list of dictionaries by their first key."""
|
|
414
400
|
return sorted(dicts, key=lambda d: next(iter(d.keys())))
|
rasa/version.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: rasa-pro
|
|
3
|
-
Version: 3.12.0.
|
|
3
|
+
Version: 3.12.0.dev6
|
|
4
4
|
Summary: State-of-the-art open-core Conversational AI framework for Enterprises that natively leverages generative AI for effortless assistant development.
|
|
5
5
|
Home-page: https://rasa.com
|
|
6
6
|
Keywords: nlp,machine-learning,machine-learning-library,bot,bots,botkit,rasa conversational-agents,conversational-ai,chatbot,chatbot-framework,bot-framework
|
|
@@ -20,7 +20,6 @@ Provides-Extra: full
|
|
|
20
20
|
Provides-Extra: gh-release-notes
|
|
21
21
|
Provides-Extra: jieba
|
|
22
22
|
Provides-Extra: metal
|
|
23
|
-
Provides-Extra: mlflow
|
|
24
23
|
Provides-Extra: spacy
|
|
25
24
|
Provides-Extra: transformers
|
|
26
25
|
Requires-Dist: CacheControl (>=0.14.2,<0.15.0)
|
|
@@ -67,7 +66,6 @@ Requires-Dist: langchain-community (>=0.2.0,<0.3.0)
|
|
|
67
66
|
Requires-Dist: litellm (>=1.52.6,<1.53.0)
|
|
68
67
|
Requires-Dist: matplotlib (>=3.7,<3.8)
|
|
69
68
|
Requires-Dist: mattermostwrapper (>=2.2,<2.3)
|
|
70
|
-
Requires-Dist: mlflow (>=2.15.1,<3.0.0) ; extra == "mlflow"
|
|
71
69
|
Requires-Dist: networkx (>=3.1,<3.2)
|
|
72
70
|
Requires-Dist: numpy (>=1.26.4,<1.27.0)
|
|
73
71
|
Requires-Dist: openai (>=1.55.3,<1.56.0)
|