rasa-pro 3.11.10__py3-none-any.whl → 3.11.12__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.

@@ -6,7 +6,18 @@ import uuid
6
6
  from collections import defaultdict
7
7
  from dataclasses import asdict
8
8
  from datetime import datetime, timedelta, timezone
9
- from typing import Any, Awaitable, Callable, Dict, List, Optional, Set, Text, Union
9
+ from typing import (
10
+ Any,
11
+ Awaitable,
12
+ Callable,
13
+ Dict,
14
+ List,
15
+ Optional,
16
+ Set,
17
+ Text,
18
+ Union,
19
+ Tuple,
20
+ )
10
21
 
11
22
  import structlog
12
23
  from jsonschema import ValidationError, validate
@@ -48,8 +59,8 @@ def map_call_params(parameters: Dict[Text, Any]) -> CallParameters:
48
59
  """Map the Audiocodes parameters to the CallParameters dataclass."""
49
60
  return CallParameters(
50
61
  call_id=parameters.get("vaigConversationId"),
51
- user_phone=parameters.get("callee"),
52
- bot_phone=parameters.get("caller"),
62
+ user_phone=parameters.get("caller"),
63
+ bot_phone=parameters.get("callee"),
53
64
  user_name=parameters.get("callerDisplayName"),
54
65
  user_host=parameters.get("callerHost"),
55
66
  bot_host=parameters.get("calleeHost"),
@@ -76,35 +87,45 @@ class Conversation:
76
87
 
77
88
  @staticmethod
78
89
  def get_metadata(activity: Dict[Text, Any]) -> Optional[Dict[Text, Any]]:
79
- """Get metadata from the activity."""
80
- return asdict(map_call_params(activity["parameters"]))
90
+ """Get metadata from the activity.
91
+
92
+ ONLY used for activities NOT for events (see _handle_event)."""
93
+ return activity.get("parameters")
81
94
 
82
95
  @staticmethod
83
- def _handle_event(event: Dict[Text, Any]) -> Text:
84
- """Handle start and DTMF event and return the corresponding text."""
96
+ def _handle_event(event: Dict[Text, Any]) -> Tuple[Text, Dict[Text, Any]]:
97
+ """Handle events and return a tuple of text and metadata.
98
+
99
+ Args:
100
+ event: The event to handle.
101
+
102
+ Returns:
103
+ Tuple of text and metadata.
104
+ text is either /session_start or /vaig_event_<event_name>
105
+ metadata is a dictionary with the event parameters.
106
+ """
85
107
  structlogger.debug("audiocodes.handle.event", event_payload=event)
86
108
  if "name" not in event:
87
109
  structlogger.warning(
88
110
  "audiocodes.handle.event.no_name_key", event_payload=event
89
111
  )
90
- return ""
112
+ return "", {}
91
113
 
92
114
  if event["name"] == EVENT_START:
93
115
  text = f"{INTENT_MESSAGE_PREFIX}{USER_INTENT_SESSION_START}"
116
+ metadata = asdict(map_call_params(event.get("parameters", {})))
94
117
  elif event["name"] == EVENT_DTMF:
95
118
  text = f"{INTENT_MESSAGE_PREFIX}vaig_event_DTMF"
96
- event_params = {"value": event["value"]}
97
- text += json.dumps(event_params)
119
+ metadata = {"value": event["value"]}
98
120
  else:
99
121
  # handle other events described by Audiocodes
100
122
  # https://techdocs.audiocodes.com/voice-ai-connect/#VAIG_Combined/inactivity-detection.htm?TocPath=Bot%2520integration%257CReceiving%2520notifications%257C_____3
101
123
  text = f"{INTENT_MESSAGE_PREFIX}vaig_event_{event['name']}"
102
- event_params = {**event.get("parameters", {})}
124
+ metadata = {**event.get("parameters", {})}
103
125
  if "value" in event:
104
- event_params["value"] = event["value"]
105
- text += json.dumps(event_params)
126
+ metadata["value"] = event["value"]
106
127
 
107
- return text
128
+ return text, metadata
108
129
 
109
130
  def is_active_conversation(self, now: datetime, delta: timedelta) -> bool:
110
131
  """Check if the conversation is active."""
@@ -150,16 +171,18 @@ class Conversation:
150
171
  self.activity_ids.append(activity[ACTIVITY_ID_KEY])
151
172
  if activity["type"] == ACTIVITY_MESSAGE:
152
173
  text = activity["text"]
174
+ metadata = self.get_metadata(activity)
153
175
  elif activity["type"] == ACTIVITY_EVENT:
154
- text = self._handle_event(activity)
176
+ text, metadata = self._handle_event(activity)
155
177
  else:
156
178
  structlogger.warning(
157
179
  "audiocodes.handle.activities.unknown_activity_type",
158
180
  activity=activity,
159
181
  )
182
+ continue
183
+
160
184
  if not text:
161
185
  continue
162
- metadata = self.get_metadata(activity)
163
186
  user_msg = UserMessage(
164
187
  text=text,
165
188
  input_channel=input_channel_name,
rasa/keys ADDED
@@ -0,0 +1 @@
1
+ {"segment": "CcvVD1I68Nkkxrv93cIqv1twIwrwG8nz", "sentry": "a283f1fde04347b099c8d729109dd450@o251570"}
@@ -1,10 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
- from collections import OrderedDict
4
- from enum import Enum
5
3
  import logging
4
+ import shutil
6
5
  import typing
7
- from typing import Any, Dict, List, Optional, Text, Tuple, Callable, Type
6
+ from collections import OrderedDict
7
+ from enum import Enum
8
+ from pathlib import Path
9
+ from typing import Any, Callable, Dict, List, Optional, Text, Tuple, Type
8
10
 
9
11
  import numpy as np
10
12
 
@@ -43,6 +45,10 @@ if typing.TYPE_CHECKING:
43
45
 
44
46
  CONFIG_FEATURES = "features"
45
47
 
48
+ TAGGERS_DIR = "taggers"
49
+ CRFSUITE_MODEL_FILE_NAME = "model.crfsuite"
50
+ PLAIN_CRF_MODEL_FILE_NAME = "model.txt"
51
+
46
52
 
47
53
  class CRFToken:
48
54
  def __init__(
@@ -419,19 +425,11 @@ class CRFEntityExtractor(GraphComponent, EntityExtractorMixin):
419
425
  """Loads trained component (see parent class for full docstring)."""
420
426
  try:
421
427
  with model_storage.read_from(resource) as model_dir:
422
- dataset = rasa.shared.utils.io.read_json_file(
423
- model_dir / "crf_dataset.json"
424
- )
425
428
  crf_order = rasa.shared.utils.io.read_json_file(
426
429
  model_dir / "crf_order.json"
427
430
  )
428
431
 
429
- dataset = [
430
- [CRFToken.create_from_dict(token_data) for token_data in sub_list]
431
- for sub_list in dataset
432
- ]
433
-
434
- entity_taggers = cls.train_model(dataset, config, crf_order)
432
+ entity_taggers = cls._load_taggers(model_dir, config)
435
433
 
436
434
  entity_extractor = cls(config, model_storage, resource, entity_taggers)
437
435
  entity_extractor.crf_order = crf_order
@@ -443,19 +441,71 @@ class CRFEntityExtractor(GraphComponent, EntityExtractorMixin):
443
441
  )
444
442
  return cls(config, model_storage, resource)
445
443
 
444
+ @classmethod
445
+ def _load_taggers(
446
+ cls, model_dir: Path, config: Dict[Text, Any]
447
+ ) -> Dict[str, "CRF"]:
448
+ """
449
+ Load taggers from model directory that persists trained binary
450
+ `model.crfsuite` files.
451
+ """
452
+
453
+ import pycrfsuite
454
+ import sklearn_crfsuite
455
+
456
+ # Get tagger directories
457
+ taggers_base = model_dir / TAGGERS_DIR
458
+ if not taggers_base.exists():
459
+ return {}
460
+
461
+ taggers_dirs = [
462
+ directory for directory in taggers_base.iterdir() if directory.is_dir()
463
+ ]
464
+
465
+ entity_taggers: Dict[str, "CRF"] = {}
466
+
467
+ for tagger_dir in taggers_dirs:
468
+ # Instantiate sklearns CRF wrapper for the pycrfsuite's Tagger
469
+ entity_tagger = sklearn_crfsuite.CRF(
470
+ algorithm="lbfgs",
471
+ # coefficient for L1 penalty
472
+ c1=config["L1_c"],
473
+ # coefficient for L2 penalty
474
+ c2=config["L2_c"],
475
+ # stop earlier
476
+ max_iterations=config["max_iterations"],
477
+ # include transitions that are possible, but not observed
478
+ all_possible_transitions=True,
479
+ )
480
+
481
+ # Load pycrfsuite tagger from the persisted binary model.crfsuite file
482
+ entity_tagger._tagger = pycrfsuite.Tagger()
483
+ entity_tagger._tagger.open(str(tagger_dir / CRFSUITE_MODEL_FILE_NAME))
484
+
485
+ entity_taggers[tagger_dir.name] = entity_tagger
486
+
487
+ return entity_taggers
488
+
446
489
  def persist(self, dataset: List[List[CRFToken]]) -> None:
447
490
  """Persist this model into the passed directory."""
448
491
  with self._model_storage.write_to(self._resource) as model_dir:
449
- data_to_store = [
450
- [token.to_dict() for token in sub_list] for sub_list in dataset
451
- ]
452
-
453
- rasa.shared.utils.io.dump_obj_as_json_to_file(
454
- model_dir / "crf_dataset.json", data_to_store
455
- )
456
492
  rasa.shared.utils.io.dump_obj_as_json_to_file(
457
493
  model_dir / "crf_order.json", self.crf_order
458
494
  )
495
+ if self.entity_taggers is not None:
496
+ for tag_name, entity_tagger in self.entity_taggers.items():
497
+ # Create the directories for storing the CRF model
498
+ tagger_dir = model_dir / TAGGERS_DIR / tag_name
499
+ tagger_dir.mkdir(parents=True, exist_ok=True)
500
+ # Create a plain text version of the CRF model
501
+ entity_tagger.tagger_.dump(
502
+ str(tagger_dir / PLAIN_CRF_MODEL_FILE_NAME)
503
+ )
504
+ # Persist binary version of the model.crfsuite
505
+ shutil.copy2(
506
+ src=entity_tagger.modelfile.name,
507
+ dst=tagger_dir / CRFSUITE_MODEL_FILE_NAME,
508
+ )
459
509
 
460
510
  @classmethod
461
511
  def _crf_tokens_to_features(
rasa/version.py CHANGED
@@ -1,3 +1,3 @@
1
1
  # this file will automatically be changed,
2
2
  # do not add anything but the version number here!
3
- __version__ = "3.11.10"
3
+ __version__ = "3.11.12"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: rasa-pro
3
- Version: 3.11.10
3
+ Version: 3.11.12
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
  Keywords: nlp,machine-learning,machine-learning-library,bot,bots,botkit,rasa conversational-agents,conversational-ai,chatbot,chatbot-framework,bot-framework
6
6
  Author: Rasa Technologies GmbH
@@ -265,7 +265,7 @@ rasa/core/channels/telegram.py,sha256=5BrNECFM3qe9XjNpDb8Q9fbqCT5aKr5L6IH21W8sum
265
265
  rasa/core/channels/twilio.py,sha256=GsdjfplZdBj0fRB60bSggPF1DXFZ_x18V_dlcDy5VFs,5943
266
266
  rasa/core/channels/vier_cvg.py,sha256=PfvSluQqgJbP0JzZPFUvum3z7H55JPPeobcD-z5zCkw,13544
267
267
  rasa/core/channels/voice_ready/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
268
- rasa/core/channels/voice_ready/audiocodes.py,sha256=jJmLkqI2RciTvB7cAsvRJi_EL70dRyiwNwPWzVPSUj0,21888
268
+ rasa/core/channels/voice_ready/audiocodes.py,sha256=T1Tx2z4HvDhNiehsRynQ9xaJkgP9wbpILCzI_SYyD78,22289
269
269
  rasa/core/channels/voice_ready/jambonz.py,sha256=S7yjdj7nYwQWMalqcGv8eomZGj0c2Dza-51tiNHEpVM,4784
270
270
  rasa/core/channels/voice_ready/jambonz_protocol.py,sha256=OzW-6YMU2SIc88Mur_wktbiE46igHR8vH17DCfRijIU,13139
271
271
  rasa/core/channels/voice_ready/twilio_voice.py,sha256=z2pdausxQnXQP9htGh8AL2q9AvcMIx70Y5tErWpssV4,16224
@@ -495,6 +495,7 @@ rasa/graph_components/validators/default_recipe_validator.py,sha256=BHrF6NTfJz42
495
495
  rasa/graph_components/validators/finetuning_validator.py,sha256=38AcwmV8cF5TIlWhUIzh98wtZf934ix04HcczCJiWkU,12863
496
496
  rasa/hooks.py,sha256=3nsfCA142V56mBQ7ktBXhD_RyaSrfj7fY3t7HnsD4Pc,3709
497
497
  rasa/jupyter.py,sha256=x_GF9PK2zMhltb48GEIV9YZ4pRhCto8nV5SioYSCljI,1782
498
+ rasa/keys,sha256=2Stg1fstgJ203cOoW1B2gGMY29fhEnjIfTVxKv_fqPo,101
498
499
  rasa/llm_fine_tuning/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
499
500
  rasa/llm_fine_tuning/annotation_module.py,sha256=wFmW3d6lI5o49OWmdbYQlgr24rqHDgA0T0hLM1pSb9U,8578
500
501
  rasa/llm_fine_tuning/conversations.py,sha256=iW2hoR23Km5wnMC7t8pOXH2Zj3LVcA62xrx2aKDRP78,5208
@@ -544,7 +545,7 @@ rasa/nlu/emulators/luis.py,sha256=AWMGI17Su1q6PcE8l1S1mDJpwfVtx7ibY9rwBmg3Maw,30
544
545
  rasa/nlu/emulators/no_emulator.py,sha256=tLJ2DyWhOtaIBudVf7mJGsubca9Vunb6VhJB_tWJ8wU,334
545
546
  rasa/nlu/emulators/wit.py,sha256=0eMj_q49JGj0Z6JZjR7rHIABNF-F3POX7s5W5OkANyo,1930
546
547
  rasa/nlu/extractors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
547
- rasa/nlu/extractors/crf_entity_extractor.py,sha256=5IW7Fa4lLLUxMrbHiRmBD7Y6B7TmS_o66USoSxYBOZk,27532
548
+ rasa/nlu/extractors/crf_entity_extractor.py,sha256=pLiM6vEybqSW4refbBRr68QbE-9haxyHQo7vslymyI0,29400
548
549
  rasa/nlu/extractors/duckling_entity_extractor.py,sha256=XooWjw6eDC0sxZ-T1YgDnrLcRTBx6B40SFGLjHTHg-w,7686
549
550
  rasa/nlu/extractors/entity_synonyms.py,sha256=WShheUF7wbP7VWfpCNw3J4NouAcFjAupDsT4oAj_TUc,7148
550
551
  rasa/nlu/extractors/extractor.py,sha256=m6p07GDBZi1VhgYCkYJrWs_Zk87okV77hvoiwG_1xxA,17539
@@ -779,9 +780,9 @@ rasa/utils/train_utils.py,sha256=f1NWpp5y6al0dzoQyyio4hc4Nf73DRoRSHDzEK6-C4E,212
779
780
  rasa/utils/url_tools.py,sha256=JQcHL2aLqLHu82k7_d9imUoETCm2bmlHaDpOJ-dKqBc,1218
780
781
  rasa/utils/yaml.py,sha256=KjbZq5C94ZP7Jdsw8bYYF7HASI6K4-C_kdHfrnPLpSI,2000
781
782
  rasa/validator.py,sha256=O1wjCeV7ITJ0luvb3GCWy8x1fGgzWVbClEMlPnLBowQ,67265
782
- rasa/version.py,sha256=pyAPlQXkP-rQmG_UV6VI6hvQcb20q31MmlJ3pMgkNik,118
783
- rasa_pro-3.11.10.dist-info/METADATA,sha256=qWOhRdBx8QpPqHsZGkp2NQaj5blpEUsPyd6VX50_32A,10729
784
- rasa_pro-3.11.10.dist-info/NOTICE,sha256=7HlBoMHJY9CL2GlYSfTQ-PZsVmLmVkYmMiPlTjhuCqA,218
785
- rasa_pro-3.11.10.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
786
- rasa_pro-3.11.10.dist-info/entry_points.txt,sha256=ckJ2SfEyTPgBqj_I6vm_tqY9dZF_LAPJZA335Xp0Q9U,43
787
- rasa_pro-3.11.10.dist-info/RECORD,,
783
+ rasa/version.py,sha256=CgppFzIc7-kYA4G-bTW0JQ0GGCnzxv9tadLtKLUPrfE,118
784
+ rasa_pro-3.11.12.dist-info/METADATA,sha256=-Zu3BDmQMQHVhndlAJPOMyf-SNU7Oa_GqCjAvs6CyvY,10729
785
+ rasa_pro-3.11.12.dist-info/NOTICE,sha256=7HlBoMHJY9CL2GlYSfTQ-PZsVmLmVkYmMiPlTjhuCqA,218
786
+ rasa_pro-3.11.12.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
787
+ rasa_pro-3.11.12.dist-info/entry_points.txt,sha256=ckJ2SfEyTPgBqj_I6vm_tqY9dZF_LAPJZA335Xp0Q9U,43
788
+ rasa_pro-3.11.12.dist-info/RECORD,,