rasa-pro 3.10.16__py3-none-any.whl → 3.11.0a1__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.
- README.md +396 -17
- rasa/api.py +9 -3
- rasa/cli/arguments/default_arguments.py +23 -2
- rasa/cli/arguments/run.py +15 -0
- rasa/cli/arguments/train.py +3 -9
- rasa/cli/e2e_test.py +1 -1
- rasa/cli/evaluate.py +1 -1
- rasa/cli/inspect.py +8 -4
- rasa/cli/llm_fine_tuning.py +12 -15
- rasa/cli/run.py +8 -1
- rasa/cli/studio/studio.py +8 -18
- rasa/cli/train.py +11 -53
- rasa/cli/utils.py +8 -10
- rasa/cli/x.py +1 -1
- rasa/constants.py +1 -1
- rasa/core/actions/action.py +2 -0
- rasa/core/actions/action_hangup.py +29 -0
- rasa/core/agent.py +2 -2
- rasa/core/brokers/kafka.py +3 -1
- rasa/core/brokers/pika.py +3 -1
- rasa/core/channels/__init__.py +8 -6
- rasa/core/channels/channel.py +21 -4
- rasa/core/channels/development_inspector.py +143 -46
- rasa/core/channels/inspector/README.md +1 -1
- rasa/core/channels/inspector/dist/assets/{arc-b6e548fe.js → arc-86942a71.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-d0fbc5ce-fa03ac9e.js → c4Diagram-d0fbc5ce-b0290676.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-936ed81e-ee67392a.js → classDiagram-936ed81e-f6405f6e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-c3cb15f1-9b283fae.js → classDiagram-v2-c3cb15f1-ef61ac77.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{createText-62fc7601-8b6fcc2a.js → createText-62fc7601-f0411e58.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-f2ad444c-22e77f4f.js → edges-f2ad444c-7dcc4f3b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9d236eb7-60ffc87f.js → erDiagram-9d236eb7-e0c092d7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-1972c806-9dd802e4.js → flowDb-1972c806-fba2e3ce.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-7ea5b25a-5fa1912f.js → flowDiagram-7ea5b25a-7a70b71a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-24a5f41a.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-abe16c3d-622a1fd2.js → flowchart-elk-definition-abe16c3d-00a59b68.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-9b5ea136-e285a63a.js → ganttDiagram-9b5ea136-293c91fa.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-99d0ae7c-f237bdca.js → gitGraphDiagram-99d0ae7c-07b2d68c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-2c4b9a3b-4b03d70e.js → index-2c4b9a3b-bc959fbd.js} +1 -1
- rasa/core/channels/inspector/dist/assets/index-3a8a5a28.js +1317 -0
- rasa/core/channels/inspector/dist/assets/{infoDiagram-736b4530-72a0fa5f.js → infoDiagram-736b4530-4a350f72.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-df861f2b-82218c41.js → journeyDiagram-df861f2b-af464fb7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-78cff630.js → layout-0071f036.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-5038b469.js → line-2f73cc83.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-c4fc4098.js → linear-f014b4cc.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-beec6740-c33c8ea6.js → mindmap-definition-beec6740-d2426fb6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-dbbf0591-a8d03059.js → pieDiagram-dbbf0591-776f01a2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-4d7f4fd6-6a0e56b2.js → quadrantDiagram-4d7f4fd6-82e00b57.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-6fc4c22a-2dc7c7bd.js → requirementDiagram-6fc4c22a-ea13c6bb.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-8f13d901-2360fe39.js → sankeyDiagram-8f13d901-1feca7e9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-b655622a-41b9f9ad.js → sequenceDiagram-b655622a-070c61d2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-59f0c015-0aad326f.js → stateDiagram-59f0c015-24f46263.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-2b26beab-9847d984.js → stateDiagram-v2-2b26beab-c9056051.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-080da4f6-564d890e.js → styles-080da4f6-08abc34a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-3dcbcfbf-38957613.js → styles-3dcbcfbf-bc74c25a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9c745c82-f0fc6921.js → styles-9c745c82-4e5d66de.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-4835440b-ef3c5a77.js → svgDrawCommon-4835440b-849c4517.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-5b62e21b-bf3e91c1.js → timeline-definition-5b62e21b-d0fb1598.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-2b33534f-4d4026c0.js → xychartDiagram-2b33534f-04d115e2.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +18 -17
- rasa/core/channels/inspector/index.html +17 -16
- rasa/core/channels/inspector/package.json +5 -1
- rasa/core/channels/inspector/src/App.tsx +117 -67
- rasa/core/channels/inspector/src/components/Chat.tsx +95 -0
- rasa/core/channels/inspector/src/components/DiagramFlow.tsx +11 -10
- rasa/core/channels/inspector/src/components/DialogueStack.tsx +10 -25
- rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +1 -1
- rasa/core/channels/inspector/src/helpers/formatters.test.ts +10 -0
- rasa/core/channels/inspector/src/helpers/formatters.ts +107 -41
- rasa/core/channels/inspector/src/helpers/utils.ts +92 -7
- rasa/core/channels/inspector/src/types.ts +21 -1
- rasa/core/channels/inspector/yarn.lock +94 -1
- rasa/core/channels/rest.py +51 -46
- rasa/core/channels/socketio.py +22 -0
- rasa/core/channels/{audiocodes.py → voice_ready/audiocodes.py} +110 -68
- rasa/core/channels/{voice_aware → voice_ready}/jambonz.py +11 -4
- rasa/core/channels/{voice_aware → voice_ready}/jambonz_protocol.py +57 -5
- rasa/core/channels/{twilio_voice.py → voice_ready/twilio_voice.py} +58 -7
- rasa/core/channels/{voice_aware → voice_ready}/utils.py +16 -0
- rasa/core/channels/voice_stream/asr/__init__.py +0 -0
- rasa/core/channels/voice_stream/asr/asr_engine.py +71 -0
- rasa/core/channels/voice_stream/asr/asr_event.py +13 -0
- rasa/core/channels/voice_stream/asr/deepgram.py +77 -0
- rasa/core/channels/voice_stream/audio_bytes.py +7 -0
- rasa/core/channels/voice_stream/tts/__init__.py +0 -0
- rasa/core/channels/voice_stream/tts/azure.py +100 -0
- rasa/core/channels/voice_stream/tts/cartesia.py +114 -0
- rasa/core/channels/voice_stream/tts/tts_cache.py +27 -0
- rasa/core/channels/voice_stream/tts/tts_engine.py +48 -0
- rasa/core/channels/voice_stream/twilio_media_streams.py +164 -0
- rasa/core/channels/voice_stream/util.py +57 -0
- rasa/core/channels/voice_stream/voice_channel.py +247 -0
- rasa/core/featurizers/single_state_featurizer.py +1 -22
- rasa/core/featurizers/tracker_featurizers.py +18 -115
- rasa/core/nlg/contextual_response_rephraser.py +11 -2
- rasa/{nlu → core}/persistor.py +16 -38
- rasa/core/policies/enterprise_search_policy.py +12 -15
- rasa/core/policies/flows/flow_executor.py +8 -18
- rasa/core/policies/intentless_policy.py +10 -15
- rasa/core/policies/ted_policy.py +33 -58
- rasa/core/policies/unexpected_intent_policy.py +7 -15
- rasa/core/processor.py +13 -64
- rasa/core/run.py +11 -1
- rasa/core/secrets_manager/constants.py +4 -0
- rasa/core/secrets_manager/factory.py +8 -0
- rasa/core/secrets_manager/vault.py +11 -1
- rasa/core/training/interactive.py +1 -1
- rasa/core/utils.py +1 -11
- rasa/dialogue_understanding/coexistence/llm_based_router.py +10 -10
- rasa/dialogue_understanding/commands/__init__.py +2 -0
- rasa/dialogue_understanding/commands/change_flow_command.py +0 -6
- rasa/dialogue_understanding/commands/session_end_command.py +61 -0
- rasa/dialogue_understanding/generator/flow_retrieval.py +0 -7
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +12 -3
- rasa/dialogue_understanding/generator/llm_command_generator.py +1 -1
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +3 -28
- rasa/dialogue_understanding/generator/nlu_command_adapter.py +1 -19
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +4 -37
- rasa/e2e_test/aggregate_test_stats_calculator.py +1 -11
- rasa/e2e_test/assertions.py +6 -48
- rasa/e2e_test/e2e_test_runner.py +6 -9
- rasa/e2e_test/utils/e2e_yaml_utils.py +1 -1
- rasa/e2e_test/utils/io.py +1 -3
- rasa/engine/graph.py +3 -10
- rasa/engine/recipes/config_files/default_config.yml +0 -3
- rasa/engine/recipes/default_recipe.py +0 -1
- rasa/engine/recipes/graph_recipe.py +0 -1
- rasa/engine/runner/dask.py +2 -2
- rasa/engine/storage/local_model_storage.py +12 -42
- rasa/engine/storage/storage.py +1 -5
- rasa/engine/validation.py +1 -78
- rasa/keys +1 -0
- rasa/model_training.py +13 -16
- rasa/nlu/classifiers/diet_classifier.py +25 -38
- rasa/nlu/classifiers/logistic_regression_classifier.py +9 -22
- rasa/nlu/classifiers/sklearn_intent_classifier.py +16 -37
- rasa/nlu/extractors/crf_entity_extractor.py +50 -93
- rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +16 -45
- rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +17 -52
- rasa/nlu/featurizers/sparse_featurizer/regex_featurizer.py +3 -5
- rasa/server.py +1 -1
- rasa/shared/constants.py +3 -12
- rasa/shared/core/constants.py +4 -0
- rasa/shared/core/domain.py +101 -47
- rasa/shared/core/events.py +29 -0
- rasa/shared/core/flows/flows_list.py +20 -11
- rasa/shared/core/flows/validation.py +25 -0
- rasa/shared/core/flows/yaml_flows_io.py +3 -24
- rasa/shared/importers/importer.py +40 -39
- rasa/shared/importers/multi_project.py +23 -11
- rasa/shared/importers/rasa.py +7 -2
- rasa/shared/importers/remote_importer.py +196 -0
- rasa/shared/importers/utils.py +3 -1
- rasa/shared/nlu/training_data/features.py +2 -120
- rasa/shared/nlu/training_data/training_data.py +18 -19
- rasa/shared/providers/_configs/azure_openai_client_config.py +3 -5
- rasa/shared/providers/embedding/_base_litellm_embedding_client.py +1 -6
- rasa/shared/providers/llm/_base_litellm_client.py +11 -31
- rasa/shared/providers/llm/self_hosted_llm_client.py +3 -15
- rasa/shared/utils/common.py +3 -22
- rasa/shared/utils/io.py +0 -1
- rasa/shared/utils/llm.py +30 -27
- rasa/shared/utils/schemas/events.py +2 -0
- rasa/shared/utils/schemas/model_config.yml +0 -10
- rasa/shared/utils/yaml.py +44 -0
- rasa/studio/auth.py +5 -3
- rasa/studio/config.py +4 -13
- rasa/studio/constants.py +0 -1
- rasa/studio/data_handler.py +3 -10
- rasa/studio/upload.py +8 -17
- rasa/tracing/instrumentation/attribute_extractors.py +1 -1
- rasa/utils/io.py +66 -0
- rasa/utils/tensorflow/model_data.py +193 -2
- rasa/validator.py +0 -12
- rasa/version.py +1 -1
- rasa_pro-3.11.0a1.dist-info/METADATA +576 -0
- {rasa_pro-3.10.16.dist-info → rasa_pro-3.11.0a1.dist-info}/RECORD +181 -164
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-1844e5a5.js +0 -1
- rasa/core/channels/inspector/dist/assets/index-a5d3e69d.js +0 -1040
- rasa/utils/tensorflow/feature_array.py +0 -366
- rasa_pro-3.10.16.dist-info/METADATA +0 -196
- /rasa/core/channels/{voice_aware → voice_ready}/__init__.py +0 -0
- /rasa/core/channels/{voice_native → voice_stream}/__init__.py +0 -0
- {rasa_pro-3.10.16.dist-info → rasa_pro-3.11.0a1.dist-info}/NOTICE +0 -0
- {rasa_pro-3.10.16.dist-info → rasa_pro-3.11.0a1.dist-info}/WHEEL +0 -0
- {rasa_pro-3.10.16.dist-info → rasa_pro-3.11.0a1.dist-info}/entry_points.txt +0 -0
|
@@ -1674,6 +1674,23 @@
|
|
|
1674
1674
|
"@jridgewell/resolve-uri" "^3.1.0"
|
|
1675
1675
|
"@jridgewell/sourcemap-codec" "^1.4.14"
|
|
1676
1676
|
|
|
1677
|
+
"@lit-labs/react@^2.1.3":
|
|
1678
|
+
version "2.1.3"
|
|
1679
|
+
resolved "https://registry.yarnpkg.com/@lit-labs/react/-/react-2.1.3.tgz#5fca408c435f0b6297fc1314471dc2426206d413"
|
|
1680
|
+
integrity sha512-OD9h2JynerBQUMNzb563jiVpxfvPF0HjQkKY2mx0lpVYvD7F+rtJpOGz6ek+6ufMidV3i+MPT9SX62OKWHFrQg==
|
|
1681
|
+
dependencies:
|
|
1682
|
+
"@lit/react" "^1.0.3"
|
|
1683
|
+
|
|
1684
|
+
"@lit/react@^1.0.3":
|
|
1685
|
+
version "1.0.5"
|
|
1686
|
+
resolved "https://registry.yarnpkg.com/@lit/react/-/react-1.0.5.tgz#9c53a8d719f91ef7edca0bdd68f5589ea579ffc1"
|
|
1687
|
+
integrity sha512-RSHhrcuSMa4vzhqiTenzXvtQ6QDq3hSPsnHHO3jaPmmvVFeoNNm4DHoQ0zLdKAUvY3wP3tTENSUf7xpyVfrDEA==
|
|
1688
|
+
|
|
1689
|
+
"@microsoft/fetch-event-source@^2.0.1":
|
|
1690
|
+
version "2.0.1"
|
|
1691
|
+
resolved "https://registry.yarnpkg.com/@microsoft/fetch-event-source/-/fetch-event-source-2.0.1.tgz#9ceecc94b49fbaa15666e38ae8587f64acce007d"
|
|
1692
|
+
integrity sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA==
|
|
1693
|
+
|
|
1677
1694
|
"@nodelib/fs.scandir@2.1.5":
|
|
1678
1695
|
version "2.1.5"
|
|
1679
1696
|
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
|
|
@@ -2215,7 +2232,7 @@ arg@^4.1.0:
|
|
|
2215
2232
|
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
|
|
2216
2233
|
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
|
|
2217
2234
|
|
|
2218
|
-
argparse@^1.0.7:
|
|
2235
|
+
argparse@^1.0.10, argparse@^1.0.7:
|
|
2219
2236
|
version "1.0.10"
|
|
2220
2237
|
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
|
|
2221
2238
|
integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
|
|
@@ -2266,6 +2283,13 @@ asynckit@^0.4.0:
|
|
|
2266
2283
|
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
|
2267
2284
|
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
|
|
2268
2285
|
|
|
2286
|
+
autolinker@^3.11.0:
|
|
2287
|
+
version "3.16.2"
|
|
2288
|
+
resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-3.16.2.tgz#6bb4f32432fc111b65659336863e653973bfbcc9"
|
|
2289
|
+
integrity sha512-JiYl7j2Z19F9NdTmirENSUUIIL/9MytEWtmzhfmsKPCp9E+G35Y0UNCMoM9tFigxT59qSc8Ml2dlZXOCVTYwuA==
|
|
2290
|
+
dependencies:
|
|
2291
|
+
tslib "^2.3.0"
|
|
2292
|
+
|
|
2269
2293
|
available-typed-arrays@^1.0.5:
|
|
2270
2294
|
version "1.0.5"
|
|
2271
2295
|
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7"
|
|
@@ -2999,11 +3023,33 @@ decode-named-character-reference@^1.0.0:
|
|
|
2999
3023
|
dependencies:
|
|
3000
3024
|
character-entities "^2.0.0"
|
|
3001
3025
|
|
|
3026
|
+
decode-uri-component@^0.4.1:
|
|
3027
|
+
version "0.4.1"
|
|
3028
|
+
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.4.1.tgz#2ac4859663c704be22bf7db760a1494a49ab2cc5"
|
|
3029
|
+
integrity sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ==
|
|
3030
|
+
|
|
3002
3031
|
dedent@^1.0.0:
|
|
3003
3032
|
version "1.5.1"
|
|
3004
3033
|
resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff"
|
|
3005
3034
|
integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==
|
|
3006
3035
|
|
|
3036
|
+
deep-chat-react@2.0.1:
|
|
3037
|
+
version "2.0.1"
|
|
3038
|
+
resolved "https://registry.yarnpkg.com/deep-chat-react/-/deep-chat-react-2.0.1.tgz#a8590a708787c478ab0bd469f1afddca3b65a62e"
|
|
3039
|
+
integrity sha512-oq3ztyhwgPemvJ+LAP2Zbb8rBFty41TlxtCE6bpzGx60mv3tEXd9DvmcI+CQWPDcYRonJLu0tMNxKVwTlY3Ybg==
|
|
3040
|
+
dependencies:
|
|
3041
|
+
"@lit-labs/react" "^2.1.3"
|
|
3042
|
+
deep-chat "2.0.1"
|
|
3043
|
+
|
|
3044
|
+
deep-chat@2.0.1:
|
|
3045
|
+
version "2.0.1"
|
|
3046
|
+
resolved "https://registry.yarnpkg.com/deep-chat/-/deep-chat-2.0.1.tgz#a3892a994e312f60f6fea38d8b63818a93e32dc2"
|
|
3047
|
+
integrity sha512-dLzEvRah+lr+Z6MZq/XSkuIJu2jyd38QVdqMeXGy2WKJQGmBnFZOK/m+F+hsLm9nz2MSfnMYXxGitQI4SNzBcQ==
|
|
3048
|
+
dependencies:
|
|
3049
|
+
"@microsoft/fetch-event-source" "^2.0.1"
|
|
3050
|
+
remarkable "^2.0.1"
|
|
3051
|
+
speech-to-element "^0.1.66"
|
|
3052
|
+
|
|
3007
3053
|
deep-equal@^2.0.5:
|
|
3008
3054
|
version "2.2.2"
|
|
3009
3055
|
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.2.2.tgz#9b2635da569a13ba8e1cc159c2f744071b115daa"
|
|
@@ -3444,6 +3490,11 @@ fill-range@^7.0.1:
|
|
|
3444
3490
|
dependencies:
|
|
3445
3491
|
to-regex-range "^5.0.1"
|
|
3446
3492
|
|
|
3493
|
+
filter-obj@^5.1.0:
|
|
3494
|
+
version "5.1.0"
|
|
3495
|
+
resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-5.1.0.tgz#5bd89676000a713d7db2e197f660274428e524ed"
|
|
3496
|
+
integrity sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng==
|
|
3497
|
+
|
|
3447
3498
|
find-root@^1.1.0:
|
|
3448
3499
|
version "1.1.0"
|
|
3449
3500
|
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
|
|
@@ -3780,6 +3831,11 @@ ignore@^5.2.0, ignore@^5.2.4:
|
|
|
3780
3831
|
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324"
|
|
3781
3832
|
integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==
|
|
3782
3833
|
|
|
3834
|
+
immutable-json-patch@^6.0.1:
|
|
3835
|
+
version "6.0.1"
|
|
3836
|
+
resolved "https://registry.yarnpkg.com/immutable-json-patch/-/immutable-json-patch-6.0.1.tgz#b60b609633e97bb2bc7c74726ff607729e61fd5b"
|
|
3837
|
+
integrity sha512-BHL/cXMjwFZlTOffiWNdY8ZTvNyYLrutCnWxrcKPHr5FqpAb6vsO6WWSPnVSys3+DruFN6lhHJJPHi8uELQL5g==
|
|
3838
|
+
|
|
3783
3839
|
import-fresh@^3.2.1:
|
|
3784
3840
|
version "3.3.0"
|
|
3785
3841
|
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
|
|
@@ -5301,6 +5357,15 @@ pure-rand@^6.0.0:
|
|
|
5301
5357
|
resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.4.tgz#50b737f6a925468679bff00ad20eade53f37d5c7"
|
|
5302
5358
|
integrity sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==
|
|
5303
5359
|
|
|
5360
|
+
query-string@^9.0.0:
|
|
5361
|
+
version "9.0.0"
|
|
5362
|
+
resolved "https://registry.yarnpkg.com/query-string/-/query-string-9.0.0.tgz#1fe177cd95545600f0deab93f5fb02fd4e3e7273"
|
|
5363
|
+
integrity sha512-4EWwcRGsO2H+yzq6ddHcVqkCQ2EFUSfDMEjF8ryp8ReymyZhIuaFRGLomeOQLkrzacMHoyky2HW0Qe30UbzkKw==
|
|
5364
|
+
dependencies:
|
|
5365
|
+
decode-uri-component "^0.4.1"
|
|
5366
|
+
filter-obj "^5.1.0"
|
|
5367
|
+
split-on-first "^3.0.0"
|
|
5368
|
+
|
|
5304
5369
|
querystringify@^2.1.1:
|
|
5305
5370
|
version "2.2.0"
|
|
5306
5371
|
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6"
|
|
@@ -5402,6 +5467,11 @@ react-syntax-highlighter@15.5.0:
|
|
|
5402
5467
|
prismjs "^1.27.0"
|
|
5403
5468
|
refractor "^3.6.0"
|
|
5404
5469
|
|
|
5470
|
+
react-use-websocket@^4.8.1:
|
|
5471
|
+
version "4.8.1"
|
|
5472
|
+
resolved "https://registry.yarnpkg.com/react-use-websocket/-/react-use-websocket-4.8.1.tgz#be06a0bc956c6d56391a29cbe2caa6ae8edb5615"
|
|
5473
|
+
integrity sha512-FTXuG5O+LFozmu1BRfrzl7UIQngECvGJmL7BHsK4TYXuVt+mCizVA8lT0hGSIF0Z0TedF7bOo1nRzOUdginhDw==
|
|
5474
|
+
|
|
5405
5475
|
react@18.2.0:
|
|
5406
5476
|
version "18.2.0"
|
|
5407
5477
|
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
|
|
@@ -5440,6 +5510,14 @@ regexp.prototype.flags@^1.5.0:
|
|
|
5440
5510
|
define-properties "^1.2.0"
|
|
5441
5511
|
set-function-name "^2.0.0"
|
|
5442
5512
|
|
|
5513
|
+
remarkable@^2.0.1:
|
|
5514
|
+
version "2.0.1"
|
|
5515
|
+
resolved "https://registry.yarnpkg.com/remarkable/-/remarkable-2.0.1.tgz#280ae6627384dfb13d98ee3995627ca550a12f31"
|
|
5516
|
+
integrity sha512-YJyMcOH5lrR+kZdmB0aJJ4+93bEojRZ1HGDn9Eagu6ibg7aVZhc3OWbbShRid+Q5eAfsEqWxpe+g5W5nYNfNiA==
|
|
5517
|
+
dependencies:
|
|
5518
|
+
argparse "^1.0.10"
|
|
5519
|
+
autolinker "^3.11.0"
|
|
5520
|
+
|
|
5443
5521
|
require-directory@^2.1.1:
|
|
5444
5522
|
version "2.1.1"
|
|
5445
5523
|
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
|
|
@@ -5638,6 +5716,16 @@ space-separated-tokens@^1.0.0:
|
|
|
5638
5716
|
resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899"
|
|
5639
5717
|
integrity sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==
|
|
5640
5718
|
|
|
5719
|
+
speech-to-element@^0.1.66:
|
|
5720
|
+
version "0.1.66"
|
|
5721
|
+
resolved "https://registry.yarnpkg.com/speech-to-element/-/speech-to-element-0.1.66.tgz#911279115fa72bd997a92fab428ed857062e4ba0"
|
|
5722
|
+
integrity sha512-tHDZ8ttFCsXtQLgWHDDVVTGuiCGWqkxRoIGLygBbU0DUsod2Ho89fws7OeCHpGOeDL9s5rBVpEqj45BsEIKy+Q==
|
|
5723
|
+
|
|
5724
|
+
split-on-first@^3.0.0:
|
|
5725
|
+
version "3.0.0"
|
|
5726
|
+
resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-3.0.0.tgz#f04959c9ea8101b9b0bbf35a61b9ebea784a23e7"
|
|
5727
|
+
integrity sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA==
|
|
5728
|
+
|
|
5641
5729
|
sprintf-js@~1.0.2:
|
|
5642
5730
|
version "1.0.3"
|
|
5643
5731
|
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
|
@@ -5855,6 +5943,11 @@ tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0:
|
|
|
5855
5943
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
|
|
5856
5944
|
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
|
|
5857
5945
|
|
|
5946
|
+
tslib@^2.3.0:
|
|
5947
|
+
version "2.6.3"
|
|
5948
|
+
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0"
|
|
5949
|
+
integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==
|
|
5950
|
+
|
|
5858
5951
|
type-check@^0.4.0, type-check@~0.4.0:
|
|
5859
5952
|
version "0.4.0"
|
|
5860
5953
|
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
|
rasa/core/channels/rest.py
CHANGED
|
@@ -9,7 +9,6 @@ import structlog
|
|
|
9
9
|
from asyncio import Queue, CancelledError
|
|
10
10
|
from sanic import Blueprint, response
|
|
11
11
|
from sanic.request import Request
|
|
12
|
-
from sanic.response import HTTPResponse, ResponseStream
|
|
13
12
|
from typing import (
|
|
14
13
|
Text,
|
|
15
14
|
Dict,
|
|
@@ -20,6 +19,7 @@ from typing import (
|
|
|
20
19
|
NoReturn,
|
|
21
20
|
Union,
|
|
22
21
|
)
|
|
22
|
+
from sanic.response import HTTPResponse, ResponseStream, BaseHTTPResponse
|
|
23
23
|
|
|
24
24
|
import rasa.utils.endpoints
|
|
25
25
|
from rasa.core.channels.channel import (
|
|
@@ -128,6 +128,54 @@ class RestInput(InputChannel):
|
|
|
128
128
|
|
|
129
129
|
await task
|
|
130
130
|
|
|
131
|
+
async def receive_messages(
|
|
132
|
+
self, request: Request, on_new_message: Callable[[UserMessage], Awaitable[None]]
|
|
133
|
+
) -> Union[BaseHTTPResponse, ResponseStream]:
|
|
134
|
+
sender_id = await self._extract_sender(request)
|
|
135
|
+
text = self._extract_message(request)
|
|
136
|
+
should_use_stream = rasa.utils.endpoints.bool_arg(
|
|
137
|
+
request, "stream", default=False
|
|
138
|
+
)
|
|
139
|
+
input_channel = self._extract_input_channel(request)
|
|
140
|
+
metadata = self.get_metadata(request)
|
|
141
|
+
|
|
142
|
+
if should_use_stream:
|
|
143
|
+
return ResponseStream(
|
|
144
|
+
partial(
|
|
145
|
+
self.stream_response,
|
|
146
|
+
on_new_message,
|
|
147
|
+
text,
|
|
148
|
+
sender_id,
|
|
149
|
+
input_channel,
|
|
150
|
+
metadata,
|
|
151
|
+
),
|
|
152
|
+
content_type="text/event-stream",
|
|
153
|
+
)
|
|
154
|
+
else:
|
|
155
|
+
collector = CollectingOutputChannel()
|
|
156
|
+
# noinspection PyBroadException
|
|
157
|
+
try:
|
|
158
|
+
await on_new_message(
|
|
159
|
+
UserMessage(
|
|
160
|
+
text,
|
|
161
|
+
collector,
|
|
162
|
+
sender_id,
|
|
163
|
+
input_channel=input_channel,
|
|
164
|
+
metadata=metadata,
|
|
165
|
+
headers=request.headers,
|
|
166
|
+
)
|
|
167
|
+
)
|
|
168
|
+
except CancelledError:
|
|
169
|
+
structlogger.error(
|
|
170
|
+
"rest.message.received.timeout", text=copy.deepcopy(text)
|
|
171
|
+
)
|
|
172
|
+
except Exception:
|
|
173
|
+
structlogger.exception(
|
|
174
|
+
"rest.message.received.failure", text=copy.deepcopy(text)
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
return response.json(collector.messages)
|
|
178
|
+
|
|
131
179
|
def blueprint(
|
|
132
180
|
self, on_new_message: Callable[[UserMessage], Awaitable[None]]
|
|
133
181
|
) -> Blueprint:
|
|
@@ -149,51 +197,8 @@ class RestInput(InputChannel):
|
|
|
149
197
|
return response.json({"status": "ok"})
|
|
150
198
|
|
|
151
199
|
@custom_webhook.route("/webhook", methods=["POST"])
|
|
152
|
-
async def receive(request: Request) -> Union[ResponseStream,
|
|
153
|
-
|
|
154
|
-
text = self._extract_message(request)
|
|
155
|
-
should_use_stream = rasa.utils.endpoints.bool_arg(
|
|
156
|
-
request, "stream", default=False
|
|
157
|
-
)
|
|
158
|
-
input_channel = self._extract_input_channel(request)
|
|
159
|
-
metadata = self.get_metadata(request)
|
|
160
|
-
|
|
161
|
-
if should_use_stream:
|
|
162
|
-
return ResponseStream(
|
|
163
|
-
partial(
|
|
164
|
-
self.stream_response,
|
|
165
|
-
on_new_message,
|
|
166
|
-
text,
|
|
167
|
-
sender_id,
|
|
168
|
-
input_channel,
|
|
169
|
-
metadata,
|
|
170
|
-
),
|
|
171
|
-
content_type="text/event-stream",
|
|
172
|
-
)
|
|
173
|
-
else:
|
|
174
|
-
collector = CollectingOutputChannel()
|
|
175
|
-
# noinspection PyBroadException
|
|
176
|
-
try:
|
|
177
|
-
await on_new_message(
|
|
178
|
-
UserMessage(
|
|
179
|
-
text,
|
|
180
|
-
collector,
|
|
181
|
-
sender_id,
|
|
182
|
-
input_channel=input_channel,
|
|
183
|
-
metadata=metadata,
|
|
184
|
-
headers=request.headers,
|
|
185
|
-
)
|
|
186
|
-
)
|
|
187
|
-
except CancelledError:
|
|
188
|
-
structlogger.error(
|
|
189
|
-
"rest.message.received.timeout", text=copy.deepcopy(text)
|
|
190
|
-
)
|
|
191
|
-
except Exception:
|
|
192
|
-
structlogger.exception(
|
|
193
|
-
"rest.message.received.failure", text=copy.deepcopy(text)
|
|
194
|
-
)
|
|
195
|
-
|
|
196
|
-
return response.json(collector.messages)
|
|
200
|
+
async def receive(request: Request) -> Union[ResponseStream, BaseHTTPResponse]:
|
|
201
|
+
return await self.receive_messages(request, on_new_message)
|
|
197
202
|
|
|
198
203
|
return custom_webhook
|
|
199
204
|
|
rasa/core/channels/socketio.py
CHANGED
|
@@ -49,9 +49,31 @@ class SocketIOOutput(OutputChannel):
|
|
|
49
49
|
def __init__(self, sio: AsyncServer, bot_message_evt: Text) -> None:
|
|
50
50
|
self.sio = sio
|
|
51
51
|
self.bot_message_evt = bot_message_evt
|
|
52
|
+
self.last_event_timestamp = (
|
|
53
|
+
-1
|
|
54
|
+
) # Initialize with -1 to send all events on first message
|
|
55
|
+
|
|
56
|
+
def _get_new_events(self) -> List[Dict[Text, Any]]:
|
|
57
|
+
"""Get events that are newer than the last sent event."""
|
|
58
|
+
events = self.tracker_state.get("events", [])
|
|
59
|
+
new_events = [
|
|
60
|
+
event for event in events if event["timestamp"] > self.last_event_timestamp
|
|
61
|
+
]
|
|
62
|
+
if new_events:
|
|
63
|
+
self.last_event_timestamp = new_events[-1]["timestamp"]
|
|
64
|
+
return new_events
|
|
52
65
|
|
|
53
66
|
async def _send_message(self, socket_id: Text, response: Any) -> None:
|
|
54
67
|
"""Sends a message to the recipient using the bot event."""
|
|
68
|
+
# send tracker state (contains stack, slots and more)
|
|
69
|
+
await self.sio.emit("tracker_state", self.tracker_state, room=socket_id)
|
|
70
|
+
|
|
71
|
+
# send new events
|
|
72
|
+
new_events = self._get_new_events()
|
|
73
|
+
if new_events:
|
|
74
|
+
await self.sio.emit("rasa_events", new_events, room=socket_id)
|
|
75
|
+
|
|
76
|
+
# send bot response
|
|
55
77
|
await self.sio.emit(self.bot_message_evt, response, room=socket_id)
|
|
56
78
|
|
|
57
79
|
async def send_text_message(
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import copy
|
|
2
|
-
import datetime
|
|
2
|
+
from datetime import datetime, timezone, timedelta
|
|
3
3
|
import json
|
|
4
|
-
import logging
|
|
5
4
|
import uuid
|
|
6
5
|
from typing import Any, Awaitable, Callable, Dict, List, Optional, Text, Union
|
|
6
|
+
from dataclasses import asdict
|
|
7
7
|
|
|
8
8
|
import structlog
|
|
9
9
|
from jsonschema import ValidationError, validate
|
|
10
10
|
from rasa.core import jobs
|
|
11
11
|
from rasa.core.channels.channel import InputChannel, OutputChannel, UserMessage
|
|
12
|
-
from rasa.core.channels.
|
|
12
|
+
from rasa.core.channels.voice_ready.utils import (
|
|
13
|
+
validate_voice_license_scope,
|
|
14
|
+
CallParameters,
|
|
15
|
+
)
|
|
13
16
|
from rasa.shared.constants import INTENT_MESSAGE_PREFIX
|
|
17
|
+
from rasa.shared.core.constants import USER_INTENT_SESSION_START
|
|
14
18
|
from rasa.shared.exceptions import RasaException
|
|
15
19
|
from sanic import Blueprint, response
|
|
16
20
|
from sanic.exceptions import NotFound, SanicException, ServerError
|
|
@@ -18,15 +22,37 @@ from sanic.request import Request
|
|
|
18
22
|
from sanic.response import HTTPResponse
|
|
19
23
|
|
|
20
24
|
|
|
21
|
-
logger = logging.getLogger(__name__)
|
|
22
25
|
structlogger = structlog.get_logger()
|
|
23
26
|
|
|
24
27
|
CHANNEL_NAME = "audiocodes"
|
|
25
28
|
KEEP_ALIVE_SECONDS = 120
|
|
26
29
|
KEEP_ALIVE_EXPIRATION_FACTOR = 1.5
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
EVENT_START = "start"
|
|
31
|
+
EVENT_DTMF = "DTMF"
|
|
32
|
+
ACTIVITY_MESSAGE = "message"
|
|
33
|
+
ACTIVITY_EVENT = "event"
|
|
34
|
+
INFO_UNKNOWN = "unknown"
|
|
35
|
+
ACTIVITY_ID_KEY = "id"
|
|
36
|
+
CREDENTIALS_TOKEN_KEY = "token"
|
|
37
|
+
CREDENTIALS_USE_WEBSOCKET_KEY = "use_websocket"
|
|
38
|
+
CREDENTIALS_KEEP_ALIVE_KEY = "keep_alive"
|
|
39
|
+
CREDENTIALS_KEEP_ALIVE_EXPIRATION_FACTOR_KEY = "keep_alive_expiration_factor"
|
|
40
|
+
CLEANUP_INTERVAL_MINUTES = 10
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def map_call_params(parameters: Dict[Text, Any]) -> CallParameters:
|
|
44
|
+
"""Map the Audiocodes parameters to the CallParameters dataclass."""
|
|
45
|
+
return CallParameters(
|
|
46
|
+
call_id=parameters.get("vaigConversationId"),
|
|
47
|
+
user_phone=parameters.get("callee"),
|
|
48
|
+
bot_phone=parameters.get("caller"),
|
|
49
|
+
user_name=parameters.get("callerDisplayName"),
|
|
50
|
+
user_host=parameters.get("callerHost"),
|
|
51
|
+
bot_host=parameters.get("calleeHost"),
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class HttpUnauthorized(SanicException):
|
|
30
56
|
"""**Status**: 401 Not Authorized."""
|
|
31
57
|
|
|
32
58
|
status_code = 401
|
|
@@ -41,30 +67,44 @@ class Conversation:
|
|
|
41
67
|
self.update()
|
|
42
68
|
|
|
43
69
|
def update(self) -> None:
|
|
44
|
-
|
|
70
|
+
"""Update the last activity time."""
|
|
71
|
+
self.last_activity: datetime = datetime.now(timezone.utc)
|
|
45
72
|
|
|
46
73
|
@staticmethod
|
|
47
74
|
def get_metadata(activity: Dict[Text, Any]) -> Optional[Dict[Text, Any]]:
|
|
75
|
+
"""Get metadata from the activity."""
|
|
48
76
|
return activity.get("parameters")
|
|
49
77
|
|
|
50
78
|
@staticmethod
|
|
51
79
|
def _handle_event(event: Dict[Text, Any]) -> Text:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if "
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
80
|
+
"""Handle start and DTMF event and return the corresponding text."""
|
|
81
|
+
structlogger.debug("audiocodes.handle.event", event_payload=event)
|
|
82
|
+
if "name" not in event:
|
|
83
|
+
structlogger.warning(
|
|
84
|
+
"audiocodes.handle.event.no_name_key", event_payload=event
|
|
85
|
+
)
|
|
86
|
+
return ""
|
|
87
|
+
|
|
88
|
+
if event["name"] == EVENT_START:
|
|
89
|
+
text = f"{INTENT_MESSAGE_PREFIX}{USER_INTENT_SESSION_START}"
|
|
90
|
+
event_params = asdict(map_call_params(event["parameters"]))
|
|
91
|
+
elif event["name"] == EVENT_DTMF:
|
|
92
|
+
text = f"{INTENT_MESSAGE_PREFIX}vaig_event_DTMF"
|
|
93
|
+
event_params = {"value": event["value"]}
|
|
94
|
+
else:
|
|
95
|
+
structlogger.warning(
|
|
96
|
+
"audiocodes.handle.event.unknown_event", event_payload=event
|
|
97
|
+
)
|
|
98
|
+
return ""
|
|
99
|
+
|
|
100
|
+
text += json.dumps(event_params)
|
|
60
101
|
return text
|
|
61
102
|
|
|
62
|
-
def is_active_conversation(
|
|
63
|
-
|
|
64
|
-
) -> bool:
|
|
103
|
+
def is_active_conversation(self, now: datetime, delta: timedelta) -> bool:
|
|
104
|
+
"""Check if the conversation is active."""
|
|
65
105
|
if now - self.last_activity > delta:
|
|
66
|
-
|
|
67
|
-
|
|
106
|
+
structlogger.warning(
|
|
107
|
+
"audiocodes.conversation.inactive", conversation=self.conversation_id
|
|
68
108
|
)
|
|
69
109
|
return False
|
|
70
110
|
return True
|
|
@@ -75,24 +115,25 @@ class Conversation:
|
|
|
75
115
|
output_channel: OutputChannel,
|
|
76
116
|
on_new_message: Callable[[UserMessage], Awaitable[Any]],
|
|
77
117
|
) -> None:
|
|
78
|
-
|
|
118
|
+
"""Handle activities sent by Audiocodes."""
|
|
119
|
+
structlogger.debug("audiocodes.handle.activities")
|
|
79
120
|
for activity in message["activities"]:
|
|
80
121
|
text = None
|
|
81
|
-
if activity[
|
|
82
|
-
|
|
83
|
-
"
|
|
84
|
-
|
|
122
|
+
if activity[ACTIVITY_ID_KEY] in self.activity_ids:
|
|
123
|
+
structlogger.warning(
|
|
124
|
+
"audiocodes.handle.activities.duplicate_activity",
|
|
125
|
+
activity_id=activity[ACTIVITY_ID_KEY],
|
|
85
126
|
)
|
|
86
127
|
continue
|
|
87
|
-
self.activity_ids.append(activity[
|
|
88
|
-
if activity["type"] ==
|
|
128
|
+
self.activity_ids.append(activity[ACTIVITY_ID_KEY])
|
|
129
|
+
if activity["type"] == ACTIVITY_MESSAGE:
|
|
89
130
|
text = activity["text"]
|
|
90
|
-
elif activity["type"] ==
|
|
131
|
+
elif activity["type"] == ACTIVITY_EVENT:
|
|
91
132
|
text = self._handle_event(activity)
|
|
92
133
|
else:
|
|
93
|
-
|
|
94
|
-
"
|
|
95
|
-
|
|
134
|
+
structlogger.warning(
|
|
135
|
+
"audiocodes.handle.activities.unknown_activity_type",
|
|
136
|
+
activity=activity,
|
|
96
137
|
)
|
|
97
138
|
if not text:
|
|
98
139
|
continue
|
|
@@ -111,13 +152,14 @@ class Conversation:
|
|
|
111
152
|
elif isinstance(user_msg.text, str):
|
|
112
153
|
anonymized_info = user_msg.text
|
|
113
154
|
else:
|
|
114
|
-
anonymized_info =
|
|
155
|
+
anonymized_info = INFO_UNKNOWN
|
|
115
156
|
|
|
116
157
|
structlogger.exception(
|
|
117
158
|
"audiocodes.handle.activities.failure",
|
|
118
159
|
user_message=copy.deepcopy(anonymized_info),
|
|
160
|
+
error=e,
|
|
161
|
+
exc_info=True,
|
|
119
162
|
)
|
|
120
|
-
logger.debug(e, exc_info=True)
|
|
121
163
|
|
|
122
164
|
await output_channel.send_custom_json(
|
|
123
165
|
self.conversation_id,
|
|
@@ -158,11 +200,12 @@ class AudiocodesInput(InputChannel):
|
|
|
158
200
|
raise RasaException(f"Invalid credentials: {e.message}")
|
|
159
201
|
|
|
160
202
|
return cls(
|
|
161
|
-
credentials.get(
|
|
162
|
-
credentials.get(
|
|
163
|
-
credentials.get(
|
|
203
|
+
credentials.get(CREDENTIALS_TOKEN_KEY, ""),
|
|
204
|
+
credentials.get(CREDENTIALS_USE_WEBSOCKET_KEY, True),
|
|
205
|
+
credentials.get(CREDENTIALS_KEEP_ALIVE_KEY, KEEP_ALIVE_SECONDS),
|
|
164
206
|
credentials.get(
|
|
165
|
-
|
|
207
|
+
CREDENTIALS_KEEP_ALIVE_EXPIRATION_FACTOR_KEY,
|
|
208
|
+
KEEP_ALIVE_EXPIRATION_FACTOR,
|
|
166
209
|
),
|
|
167
210
|
)
|
|
168
211
|
|
|
@@ -185,12 +228,12 @@ class AudiocodesInput(InputChannel):
|
|
|
185
228
|
if self.scheduler_job:
|
|
186
229
|
self.scheduler_job.remove()
|
|
187
230
|
self.scheduler_job = (await jobs.scheduler()).add_job(
|
|
188
|
-
self.clean_old_conversations, "interval", minutes=
|
|
231
|
+
self.clean_old_conversations, "interval", minutes=CLEANUP_INTERVAL_MINUTES
|
|
189
232
|
)
|
|
190
233
|
|
|
191
234
|
def _check_token(self, token: Optional[Text]) -> None:
|
|
192
235
|
if not token:
|
|
193
|
-
raise
|
|
236
|
+
raise HttpUnauthorized("Authentication token required.")
|
|
194
237
|
|
|
195
238
|
def _get_conversation(
|
|
196
239
|
self, token: Optional[Text], conversation_id: Text
|
|
@@ -203,14 +246,11 @@ class AudiocodesInput(InputChannel):
|
|
|
203
246
|
return conversation
|
|
204
247
|
|
|
205
248
|
def clean_old_conversations(self) -> None:
|
|
206
|
-
|
|
207
|
-
"
|
|
208
|
-
f" {len(self.conversations)}"
|
|
209
|
-
)
|
|
210
|
-
now = datetime.datetime.utcnow()
|
|
211
|
-
delta = datetime.timedelta(
|
|
212
|
-
seconds=self.keep_alive * self.keep_alive_expiration_factor
|
|
249
|
+
structlogger.debug(
|
|
250
|
+
"audiocodes.clean_old_conversations", current_number=len(self.conversations)
|
|
213
251
|
)
|
|
252
|
+
now = datetime.now(timezone.utc)
|
|
253
|
+
delta = timedelta(seconds=self.keep_alive * self.keep_alive_expiration_factor)
|
|
214
254
|
self.conversations = {
|
|
215
255
|
k: v
|
|
216
256
|
for k, v in self.conversations.items()
|
|
@@ -221,9 +261,8 @@ class AudiocodesInput(InputChannel):
|
|
|
221
261
|
conversation_id = body["conversation"]
|
|
222
262
|
if conversation_id in self.conversations:
|
|
223
263
|
raise ServerError("Conversation already exists")
|
|
224
|
-
|
|
225
|
-
"
|
|
226
|
-
f" Conversation: {conversation_id}"
|
|
264
|
+
structlogger.debug(
|
|
265
|
+
"audiocodes.handle_start_conversation", conversation=conversation_id
|
|
227
266
|
)
|
|
228
267
|
self.conversations[conversation_id] = Conversation(conversation_id)
|
|
229
268
|
urls = {
|
|
@@ -248,16 +287,15 @@ class AudiocodesInput(InputChannel):
|
|
|
248
287
|
"""Triggered on new websocket connection."""
|
|
249
288
|
if self.use_websocket is False:
|
|
250
289
|
raise ConnectionRefusedError("websocket is unavailable")
|
|
251
|
-
|
|
252
|
-
"
|
|
253
|
-
f" Conversation: {conversation_id}"
|
|
290
|
+
structlogger.debug(
|
|
291
|
+
"audiocodes.new_client_connection", conversation=conversation_id
|
|
254
292
|
)
|
|
255
293
|
conversation = self._get_conversation(request.token, conversation_id)
|
|
256
294
|
if conversation:
|
|
257
295
|
if conversation.ws:
|
|
258
|
-
|
|
259
|
-
"
|
|
260
|
-
|
|
296
|
+
structlogger.debug(
|
|
297
|
+
"audiocodes.new_client_connection.already_connected",
|
|
298
|
+
conversation=conversation_id,
|
|
261
299
|
)
|
|
262
300
|
else:
|
|
263
301
|
conversation.ws = ws
|
|
@@ -265,11 +303,9 @@ class AudiocodesInput(InputChannel):
|
|
|
265
303
|
try:
|
|
266
304
|
await ws.recv()
|
|
267
305
|
except Exception:
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
f"{conversation_id}"
|
|
272
|
-
)
|
|
306
|
+
structlogger.warning(
|
|
307
|
+
"audiocodes.new_client_connection.closed",
|
|
308
|
+
conversation=conversation_id,
|
|
273
309
|
)
|
|
274
310
|
if conversation:
|
|
275
311
|
conversation.ws = None
|
|
@@ -308,10 +344,7 @@ class AudiocodesInput(InputChannel):
|
|
|
308
344
|
Example of payload:
|
|
309
345
|
{"conversation": <conversation_id>, "activities": List[Activity]}.
|
|
310
346
|
"""
|
|
311
|
-
|
|
312
|
-
"(on_activities) --- New activities from the user. Conversation: "
|
|
313
|
-
f"{conversation_id}"
|
|
314
|
-
)
|
|
347
|
+
structlogger.debug("audiocodes.on_activities", conversation=conversation_id)
|
|
315
348
|
conversation = self._get_conversation(request.token, conversation_id)
|
|
316
349
|
if conversation is None:
|
|
317
350
|
return response.json({})
|
|
@@ -353,13 +386,18 @@ class AudiocodesInput(InputChannel):
|
|
|
353
386
|
reason = json.dumps({"reason": request.json.get("reason")})
|
|
354
387
|
await on_new_message(
|
|
355
388
|
UserMessage(
|
|
356
|
-
text=f"{INTENT_MESSAGE_PREFIX}
|
|
389
|
+
text=f"{INTENT_MESSAGE_PREFIX}session_end",
|
|
357
390
|
output_channel=None,
|
|
358
391
|
sender_id=conversation_id,
|
|
392
|
+
metadata=reason,
|
|
359
393
|
)
|
|
360
394
|
)
|
|
361
395
|
del self.conversations[conversation_id]
|
|
362
|
-
|
|
396
|
+
structlogger.debug(
|
|
397
|
+
"audiocodes.disconnect",
|
|
398
|
+
conversation=conversation_id,
|
|
399
|
+
request=request.json,
|
|
400
|
+
)
|
|
363
401
|
return response.json({})
|
|
364
402
|
|
|
365
403
|
@ac_webhook.route("/conversation/<conversation_id>/keepalive", methods=["POST"])
|
|
@@ -397,7 +435,7 @@ class AudiocodesOutput(OutputChannel):
|
|
|
397
435
|
)
|
|
398
436
|
message.update(
|
|
399
437
|
{
|
|
400
|
-
"timestamp": datetime.
|
|
438
|
+
"timestamp": datetime.now(timezone.utc).isoformat("T")[:-3] + "Z",
|
|
401
439
|
"id": str(uuid.uuid4()),
|
|
402
440
|
}
|
|
403
441
|
)
|
|
@@ -429,6 +467,10 @@ class AudiocodesOutput(OutputChannel):
|
|
|
429
467
|
"""Send an activity."""
|
|
430
468
|
await self.add_message(json_message)
|
|
431
469
|
|
|
470
|
+
async def hangup(self, recipient_id: Text, **kwargs: Any) -> None:
|
|
471
|
+
"""Indicate that the conversation should be ended."""
|
|
472
|
+
await self.add_message({"type": "event", "name": "hangup"})
|
|
473
|
+
|
|
432
474
|
|
|
433
475
|
class WebsocketOutput(AudiocodesOutput):
|
|
434
476
|
def __init__(self, ws: Any, conversation_id: Text) -> None:
|