vcon 0.2__tar.gz → 0.3.0__tar.gz
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.
- vcon-0.2/LICENSE → vcon-0.3.0/LICENSE.txt +2 -2
- vcon-0.3.0/PKG-INFO +136 -0
- vcon-0.3.0/README.md +112 -0
- vcon-0.3.0/pyproject.toml +34 -0
- vcon-0.3.0/src/vcon/__init__.py +3 -0
- vcon-0.3.0/src/vcon/civic_address.py +90 -0
- vcon-0.3.0/src/vcon/dialog.py +277 -0
- vcon-0.3.0/src/vcon/party.py +87 -0
- vcon-0.3.0/src/vcon/vcon.py +480 -0
- vcon-0.2/PKG-INFO +0 -10
- vcon-0.2/README.md +0 -71
- vcon-0.2/setup.cfg +0 -4
- vcon-0.2/setup.py +0 -76
- vcon-0.2/tests/test_dates.py +0 -59
- vcon-0.2/tests/test_external_content.py +0 -231
- vcon-0.2/tests/test_filter_plugins.py +0 -95
- vcon-0.2/tests/test_jwe.py +0 -244
- vcon-0.2/tests/test_migrate.py +0 -25
- vcon-0.2/tests/test_minimalist.py +0 -266
- vcon-0.2/tests/test_party_search.py +0 -43
- vcon-0.2/tests/test_redis_mgr.py +0 -39
- vcon-0.2/tests/test_signature.py +0 -325
- vcon-0.2/tests/test_uuid.py +0 -57
- vcon-0.2/tests/test_vcon_cli.py +0 -183
- vcon-0.2/tests/test_whisper_plugin.py +0 -135
- vcon-0.2/vcon/__init__.py +0 -1354
- vcon-0.2/vcon/bin/vcon +0 -10
- vcon-0.2/vcon/cli.py +0 -337
- vcon-0.2/vcon/filter_plugins/__init__.py +0 -268
- vcon-0.2/vcon/filter_plugins/impl/whisper.py +0 -145
- vcon-0.2/vcon/filter_plugins/whisper.py +0 -9
- vcon-0.2/vcon/security.py +0 -373
- vcon-0.2/vcon/utils.py +0 -81
- vcon-0.2/vcon.egg-info/PKG-INFO +0 -10
- vcon-0.2/vcon.egg-info/SOURCES.txt +0 -29
- vcon-0.2/vcon.egg-info/dependency_links.txt +0 -1
- vcon-0.2/vcon.egg-info/not-zip-safe +0 -1
- vcon-0.2/vcon.egg-info/requires.txt +0 -17
- vcon-0.2/vcon.egg-info/top_level.txt +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) [2024] [StrolidInc]
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
18
18
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
19
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
20
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
21
|
+
SOFTWARE.
|
vcon-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: vcon
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: The vCon library
|
|
5
|
+
License: MIT
|
|
6
|
+
Author: pair
|
|
7
|
+
Author-email: dev_team@strolid.com
|
|
8
|
+
Requires-Python: >=3.8,<4.0
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Requires-Dist: authlib (>=1.3.2,<2.0.0)
|
|
17
|
+
Requires-Dist: pydash (>=8.0.3,<9.0.0)
|
|
18
|
+
Requires-Dist: pytest (>=8.3.2,<9.0.0)
|
|
19
|
+
Requires-Dist: pytest-cov (>=5.0.0,<6.0.0)
|
|
20
|
+
Requires-Dist: pytest-mock (>=3.14.0,<4.0.0)
|
|
21
|
+
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
|
22
|
+
Requires-Dist: uuid6 (>=2024.7.10,<2025.0.0)
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# vCon Python Library
|
|
26
|
+
|
|
27
|
+
This Python library provides a convenient way to work with vCon (Virtualized Conversation) objects. vCon is a standard for representing conversation data, including metadata, dialog, analysis, and attachments.
|
|
28
|
+
|
|
29
|
+
## Features
|
|
30
|
+
|
|
31
|
+
- Create and manipulate vCon objects
|
|
32
|
+
- Add parties, dialogs, attachments, and analysis to vCons
|
|
33
|
+
- Sign and verify vCons using JWS (JSON Web Signature)
|
|
34
|
+
- Generate UUID8 identifiers
|
|
35
|
+
- Pack and unpack dialogs
|
|
36
|
+
- Add and retrieve tags
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
To install the vCon library, use pip:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
pip install vcon
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Usage
|
|
47
|
+
from vcon import Vcon
|
|
48
|
+
from vcon.party import Party
|
|
49
|
+
|
|
50
|
+
# Create a new vcon
|
|
51
|
+
vcon = Vcon.build_new()
|
|
52
|
+
|
|
53
|
+
# Add a party to the vcon
|
|
54
|
+
party = Party(mailto="example@example.com")
|
|
55
|
+
vcon.add_party(party)
|
|
56
|
+
|
|
57
|
+
# Add a dialog to the vcon
|
|
58
|
+
dialog = {
|
|
59
|
+
"id": "dialog1",
|
|
60
|
+
"type": "text",
|
|
61
|
+
"start": "2024-05-03T20:13:48.414984",
|
|
62
|
+
"parties": [0],
|
|
63
|
+
"body": "Hello, world!",
|
|
64
|
+
"encoding": "none"
|
|
65
|
+
}
|
|
66
|
+
vcon.add_dialog(dialog)
|
|
67
|
+
|
|
68
|
+
# Add an attachment to the vcon
|
|
69
|
+
attachment = {
|
|
70
|
+
"type": "tags",
|
|
71
|
+
"body": ["tag1:value1", "tag2:value2"],
|
|
72
|
+
"encoding": "json"
|
|
73
|
+
}
|
|
74
|
+
vcon.add_attachment(attachment)
|
|
75
|
+
|
|
76
|
+
# Add analysis to the vcon
|
|
77
|
+
analysis = {
|
|
78
|
+
"type": "transcript",
|
|
79
|
+
"dialog": 0,
|
|
80
|
+
"vendor": "openai",
|
|
81
|
+
"body": {"key": "value"},
|
|
82
|
+
"encoding": "json"
|
|
83
|
+
}
|
|
84
|
+
vcon.add_analysis(analysis)
|
|
85
|
+
|
|
86
|
+
# Serialize the vcon to JSON
|
|
87
|
+
json_string = vcon.to_json()
|
|
88
|
+
print(json_string)
|
|
89
|
+
|
|
90
|
+
# Create a new vcon from the JSON string
|
|
91
|
+
new_vcon = Vcon.build_from_json(json_string)
|
|
92
|
+
|
|
93
|
+
# Print the new vcon's UUID
|
|
94
|
+
print(new_vcon.uuid)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
## API Reference
|
|
98
|
+
|
|
99
|
+
For detailed information about the available methods and their usage, please refer to the docstrings in the source code.
|
|
100
|
+
|
|
101
|
+
## Contributing
|
|
102
|
+
|
|
103
|
+
Contributions to the vCon library are welcome! Please submit pull requests or open issues on the GitHub repository.
|
|
104
|
+
|
|
105
|
+
## License
|
|
106
|
+
|
|
107
|
+
This project is licensed under the MIT License:
|
|
108
|
+
|
|
109
|
+
MIT License
|
|
110
|
+
|
|
111
|
+
Copyright (c) 2023 Thomas McCarthy-Howe
|
|
112
|
+
|
|
113
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
114
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
115
|
+
in the Software without restriction, including without limitation the rights
|
|
116
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
117
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
118
|
+
furnished to do so, subject to the following conditions:
|
|
119
|
+
|
|
120
|
+
The above copyright notice and this permission notice shall be included in all
|
|
121
|
+
copies or substantial portions of the Software.
|
|
122
|
+
|
|
123
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
124
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
125
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
126
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
127
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
128
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
129
|
+
SOFTWARE.
|
|
130
|
+
|
|
131
|
+
## Contact
|
|
132
|
+
|
|
133
|
+
For questions or support, please contact:
|
|
134
|
+
|
|
135
|
+
Thomas McCarthy-Howe
|
|
136
|
+
Email: ghostofbasho@gmail.com
|
vcon-0.3.0/README.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# vCon Python Library
|
|
2
|
+
|
|
3
|
+
This Python library provides a convenient way to work with vCon (Virtualized Conversation) objects. vCon is a standard for representing conversation data, including metadata, dialog, analysis, and attachments.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Create and manipulate vCon objects
|
|
8
|
+
- Add parties, dialogs, attachments, and analysis to vCons
|
|
9
|
+
- Sign and verify vCons using JWS (JSON Web Signature)
|
|
10
|
+
- Generate UUID8 identifiers
|
|
11
|
+
- Pack and unpack dialogs
|
|
12
|
+
- Add and retrieve tags
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
To install the vCon library, use pip:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
pip install vcon
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
from vcon import Vcon
|
|
24
|
+
from vcon.party import Party
|
|
25
|
+
|
|
26
|
+
# Create a new vcon
|
|
27
|
+
vcon = Vcon.build_new()
|
|
28
|
+
|
|
29
|
+
# Add a party to the vcon
|
|
30
|
+
party = Party(mailto="example@example.com")
|
|
31
|
+
vcon.add_party(party)
|
|
32
|
+
|
|
33
|
+
# Add a dialog to the vcon
|
|
34
|
+
dialog = {
|
|
35
|
+
"id": "dialog1",
|
|
36
|
+
"type": "text",
|
|
37
|
+
"start": "2024-05-03T20:13:48.414984",
|
|
38
|
+
"parties": [0],
|
|
39
|
+
"body": "Hello, world!",
|
|
40
|
+
"encoding": "none"
|
|
41
|
+
}
|
|
42
|
+
vcon.add_dialog(dialog)
|
|
43
|
+
|
|
44
|
+
# Add an attachment to the vcon
|
|
45
|
+
attachment = {
|
|
46
|
+
"type": "tags",
|
|
47
|
+
"body": ["tag1:value1", "tag2:value2"],
|
|
48
|
+
"encoding": "json"
|
|
49
|
+
}
|
|
50
|
+
vcon.add_attachment(attachment)
|
|
51
|
+
|
|
52
|
+
# Add analysis to the vcon
|
|
53
|
+
analysis = {
|
|
54
|
+
"type": "transcript",
|
|
55
|
+
"dialog": 0,
|
|
56
|
+
"vendor": "openai",
|
|
57
|
+
"body": {"key": "value"},
|
|
58
|
+
"encoding": "json"
|
|
59
|
+
}
|
|
60
|
+
vcon.add_analysis(analysis)
|
|
61
|
+
|
|
62
|
+
# Serialize the vcon to JSON
|
|
63
|
+
json_string = vcon.to_json()
|
|
64
|
+
print(json_string)
|
|
65
|
+
|
|
66
|
+
# Create a new vcon from the JSON string
|
|
67
|
+
new_vcon = Vcon.build_from_json(json_string)
|
|
68
|
+
|
|
69
|
+
# Print the new vcon's UUID
|
|
70
|
+
print(new_vcon.uuid)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
## API Reference
|
|
74
|
+
|
|
75
|
+
For detailed information about the available methods and their usage, please refer to the docstrings in the source code.
|
|
76
|
+
|
|
77
|
+
## Contributing
|
|
78
|
+
|
|
79
|
+
Contributions to the vCon library are welcome! Please submit pull requests or open issues on the GitHub repository.
|
|
80
|
+
|
|
81
|
+
## License
|
|
82
|
+
|
|
83
|
+
This project is licensed under the MIT License:
|
|
84
|
+
|
|
85
|
+
MIT License
|
|
86
|
+
|
|
87
|
+
Copyright (c) 2023 Thomas McCarthy-Howe
|
|
88
|
+
|
|
89
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
90
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
91
|
+
in the Software without restriction, including without limitation the rights
|
|
92
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
93
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
94
|
+
furnished to do so, subject to the following conditions:
|
|
95
|
+
|
|
96
|
+
The above copyright notice and this permission notice shall be included in all
|
|
97
|
+
copies or substantial portions of the Software.
|
|
98
|
+
|
|
99
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
100
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
101
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
102
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
103
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
104
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
105
|
+
SOFTWARE.
|
|
106
|
+
|
|
107
|
+
## Contact
|
|
108
|
+
|
|
109
|
+
For questions or support, please contact:
|
|
110
|
+
|
|
111
|
+
Thomas McCarthy-Howe
|
|
112
|
+
Email: ghostofbasho@gmail.com
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "vcon"
|
|
3
|
+
version = "0.3.0"
|
|
4
|
+
description = "The vCon library"
|
|
5
|
+
authors = ["pair <dev_team@strolid.com>"]
|
|
6
|
+
license = "MIT"
|
|
7
|
+
readme = "README.md"
|
|
8
|
+
packages = [
|
|
9
|
+
{ include = "vcon", from = "src" }
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
[[tool.poetry.source]]
|
|
13
|
+
name = "testpypi"
|
|
14
|
+
url = "https://test.pypi.org/legacy/"
|
|
15
|
+
priority = "primary"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
[[tool.poetry.source]]
|
|
19
|
+
name = "PyPI"
|
|
20
|
+
priority = "primary"
|
|
21
|
+
|
|
22
|
+
[tool.poetry.dependencies]
|
|
23
|
+
python = "^3.8"
|
|
24
|
+
authlib = "^1.3.2"
|
|
25
|
+
pytest = "^8.3.2"
|
|
26
|
+
uuid6 = "^2024.7.10"
|
|
27
|
+
requests = "^2.32.3"
|
|
28
|
+
pydash = "^8.0.3"
|
|
29
|
+
pytest-cov = "^5.0.0"
|
|
30
|
+
pytest-mock = "^3.14.0"
|
|
31
|
+
|
|
32
|
+
[build-system]
|
|
33
|
+
requires = ["poetry-core"]
|
|
34
|
+
build-backend = "poetry.core.masonry.api"
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
class CivicAddress:
|
|
5
|
+
def __init__(self,
|
|
6
|
+
country: Optional[str] = None,
|
|
7
|
+
a1: Optional[str] = None,
|
|
8
|
+
a2: Optional[str] = None,
|
|
9
|
+
a3: Optional[str] = None,
|
|
10
|
+
a4: Optional[str] = None,
|
|
11
|
+
a5: Optional[str] = None,
|
|
12
|
+
a6: Optional[str] = None,
|
|
13
|
+
prd: Optional[str] = None,
|
|
14
|
+
pod: Optional[str] = None,
|
|
15
|
+
sts: Optional[str] = None,
|
|
16
|
+
hno: Optional[str] = None,
|
|
17
|
+
hns: Optional[str] = None,
|
|
18
|
+
lmk: Optional[str] = None,
|
|
19
|
+
loc: Optional[str] = None,
|
|
20
|
+
flr: Optional[str] = None,
|
|
21
|
+
nam: Optional[str] = None,
|
|
22
|
+
pc: Optional[str] = None):
|
|
23
|
+
"""
|
|
24
|
+
Initialize a new CivicAddress object.
|
|
25
|
+
|
|
26
|
+
:param country: Country code (ISO 3166-1 alpha-2)
|
|
27
|
+
:type country: str
|
|
28
|
+
:param a1: Administrative area 1 (e.g. state or province)
|
|
29
|
+
:type a1: str
|
|
30
|
+
:param a2: Administrative area 2 (e.g. county or municipality)
|
|
31
|
+
:type a2: str
|
|
32
|
+
:param a3: Administrative area 3 (e.g. city or town)
|
|
33
|
+
:type a3: str
|
|
34
|
+
:param a4: Administrative area 4 (e.g. neighborhood or district)
|
|
35
|
+
:type a4: str
|
|
36
|
+
:param a5: Administrative area 5 (e.g. postal code)
|
|
37
|
+
:type a5: str
|
|
38
|
+
:param a6: Administrative area 6 (e.g. building or floor)
|
|
39
|
+
:type a6: str
|
|
40
|
+
:param prd: Premier (e.g. department or suite number)
|
|
41
|
+
:type prd: str
|
|
42
|
+
:param pod: Post office box identifier
|
|
43
|
+
:type pod: str
|
|
44
|
+
:param sts: Street name
|
|
45
|
+
:type sts: str
|
|
46
|
+
:param hno: House number
|
|
47
|
+
:type hno: str
|
|
48
|
+
:param hns: House name
|
|
49
|
+
:type hns: str
|
|
50
|
+
:param lmk: Landmark name
|
|
51
|
+
:type lmk: str
|
|
52
|
+
:param loc: Location name
|
|
53
|
+
:type loc: str
|
|
54
|
+
:param flr: Floor
|
|
55
|
+
:type flr: str
|
|
56
|
+
:param nam: Name of the location
|
|
57
|
+
:type nam: str
|
|
58
|
+
:param pc: Postal code
|
|
59
|
+
:type pc: str
|
|
60
|
+
"""
|
|
61
|
+
self.country = country
|
|
62
|
+
self.a1 = a1
|
|
63
|
+
self.a2 = a2
|
|
64
|
+
self.a3 = a3
|
|
65
|
+
self.a4 = a4
|
|
66
|
+
self.a5 = a5
|
|
67
|
+
self.a6 = a6
|
|
68
|
+
self.prd = prd
|
|
69
|
+
self.pod = pod
|
|
70
|
+
self.sts = sts
|
|
71
|
+
self.hno = hno
|
|
72
|
+
self.hns = hns
|
|
73
|
+
self.lmk = lmk
|
|
74
|
+
self.loc = loc
|
|
75
|
+
self.flr = flr
|
|
76
|
+
self.nam = nam
|
|
77
|
+
self.pc = pc
|
|
78
|
+
|
|
79
|
+
def to_dict(self) -> dict[str, Optional[str]]:
|
|
80
|
+
"""
|
|
81
|
+
Convert the CivicAddress object to a dictionary.
|
|
82
|
+
|
|
83
|
+
The dictionary keys are the attribute names of the object, and the
|
|
84
|
+
values are the attribute values.
|
|
85
|
+
|
|
86
|
+
:return: A dictionary of the object's attributes
|
|
87
|
+
:rtype: dict[str, Optional[str]]
|
|
88
|
+
"""
|
|
89
|
+
return {attr: getattr(self, attr) for attr in dir(self) if not attr.startswith("_") and getattr(self, attr) is not None and not callable(getattr(self, attr))}
|
|
90
|
+
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import hashlib
|
|
3
|
+
import base64
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Optional, List
|
|
6
|
+
from .party import PartyHistory
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
MIME_TYPES = [
|
|
10
|
+
"text/plain",
|
|
11
|
+
"audio/x-wav",
|
|
12
|
+
"audio/x-mp3",
|
|
13
|
+
"audio/x-mp4",
|
|
14
|
+
"audio/ogg",
|
|
15
|
+
"video/x-mp4",
|
|
16
|
+
"video/ogg",
|
|
17
|
+
"multipart/mixed",
|
|
18
|
+
"message/external-body",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Dialog:
|
|
23
|
+
def __init__(self,
|
|
24
|
+
type: str,
|
|
25
|
+
start: datetime,
|
|
26
|
+
parties: List[int],
|
|
27
|
+
originator: Optional[int] = None,
|
|
28
|
+
mimetype: Optional[str] = None,
|
|
29
|
+
filename: Optional[str] = None,
|
|
30
|
+
body: Optional[str] = None,
|
|
31
|
+
encoding: Optional[str] = None,
|
|
32
|
+
url: Optional[str] = None,
|
|
33
|
+
alg: Optional[str] = None,
|
|
34
|
+
signature: Optional[str] = None,
|
|
35
|
+
disposition: Optional[str] = None,
|
|
36
|
+
party_history: Optional[List[PartyHistory]] = None,
|
|
37
|
+
transferee: Optional[int] = None,
|
|
38
|
+
transferor: Optional[int] = None,
|
|
39
|
+
transfer_target: Optional[int] = None,
|
|
40
|
+
original: Optional[int] = None,
|
|
41
|
+
consultation: Optional[int] = None,
|
|
42
|
+
target_dialog: Optional[int] = None,
|
|
43
|
+
campaign: Optional[str] = None,
|
|
44
|
+
interaction: Optional[str] = None,
|
|
45
|
+
skill: Optional[str] = None,
|
|
46
|
+
duration: Optional[float] = None) -> None:
|
|
47
|
+
"""
|
|
48
|
+
Initialize a Dialog object.
|
|
49
|
+
|
|
50
|
+
:param type: the type of the dialog (e.g. "text", "audio", etc.)
|
|
51
|
+
:type type: str
|
|
52
|
+
:param start: the start time of the dialog
|
|
53
|
+
:type start: datetime
|
|
54
|
+
:param parties: the parties involved in the dialog
|
|
55
|
+
:type parties: List[int]
|
|
56
|
+
:param originator: the party that originated the dialog
|
|
57
|
+
:type originator: int or None
|
|
58
|
+
:param mimetype: the MIME type of the dialog body
|
|
59
|
+
:type mimetype: str or None
|
|
60
|
+
:param filename: the filename of the dialog body
|
|
61
|
+
:type filename: str or None
|
|
62
|
+
:param body: the body of the dialog
|
|
63
|
+
:type body: str or None
|
|
64
|
+
:param encoding: the encoding of the dialog body
|
|
65
|
+
:type encoding: str or None
|
|
66
|
+
:param url: the URL of the dialog
|
|
67
|
+
:type url: str or None
|
|
68
|
+
:param alg: the algorithm used to sign the dialog
|
|
69
|
+
:type alg: str or None
|
|
70
|
+
:param signature: the signature of the dialog
|
|
71
|
+
:type signature: str or None
|
|
72
|
+
:param disposition: the disposition of the dialog
|
|
73
|
+
:type disposition: str or None
|
|
74
|
+
:param party_history: the history of parties involved in the dialog
|
|
75
|
+
:type party_history: List[PartyHistory] or None
|
|
76
|
+
:param transferee: the party that the dialog was transferred to
|
|
77
|
+
:type transferee: int or None
|
|
78
|
+
:param transferor: the party that transferred the dialog
|
|
79
|
+
:type transferor: int or None
|
|
80
|
+
:param transfer_target: the target of the transfer
|
|
81
|
+
:type transfer_target: int or None
|
|
82
|
+
:param original: the original dialog
|
|
83
|
+
:type original: int or None
|
|
84
|
+
:param consultation: the consultation dialog
|
|
85
|
+
:type consultation: int or None
|
|
86
|
+
:param target_dialog: the target dialog
|
|
87
|
+
:type target_dialog: int or None
|
|
88
|
+
:param campaign: the campaign that the dialog is associated with
|
|
89
|
+
:type campaign: str or None
|
|
90
|
+
:param interaction: the interaction that the dialog is associated with
|
|
91
|
+
:type interaction: str or None
|
|
92
|
+
:param skill: the skill that the dialog is associated with
|
|
93
|
+
:type skill: str or None
|
|
94
|
+
:param duration: the duration of the dialog
|
|
95
|
+
:type duration: float or None
|
|
96
|
+
"""
|
|
97
|
+
self.type = type
|
|
98
|
+
self.start = start
|
|
99
|
+
self.parties = parties
|
|
100
|
+
self.originator = originator
|
|
101
|
+
self.mimetype = mimetype
|
|
102
|
+
self.filename = filename
|
|
103
|
+
self.body = body
|
|
104
|
+
self.encoding = encoding
|
|
105
|
+
self.url = url
|
|
106
|
+
self.alg = alg
|
|
107
|
+
self.signature = signature
|
|
108
|
+
self.disposition = disposition
|
|
109
|
+
self.party_history = party_history
|
|
110
|
+
self.transferee = transferee
|
|
111
|
+
self.transferor = transferor
|
|
112
|
+
self.transfer_target = transfer_target
|
|
113
|
+
self.original = original
|
|
114
|
+
self.consultation = consultation
|
|
115
|
+
self.target_dialog = target_dialog
|
|
116
|
+
self.campaign = campaign
|
|
117
|
+
self.interaction = interaction
|
|
118
|
+
self.skill = skill
|
|
119
|
+
self.duration = duration
|
|
120
|
+
|
|
121
|
+
def to_dict(self):
|
|
122
|
+
"""
|
|
123
|
+
Returns a dictionary representation of the Dialog object.
|
|
124
|
+
|
|
125
|
+
:return: a dictionary containing the Dialog object's attributes
|
|
126
|
+
:rtype: dict
|
|
127
|
+
"""
|
|
128
|
+
dialog_dict = {
|
|
129
|
+
"type": self.type,
|
|
130
|
+
"start": self.start.isoformat(),
|
|
131
|
+
"duration": self.duration,
|
|
132
|
+
"parties": self.parties,
|
|
133
|
+
"originator": self.originator,
|
|
134
|
+
"mimetype": self.mimetype,
|
|
135
|
+
"filename": self.filename,
|
|
136
|
+
"body": self.body,
|
|
137
|
+
"encoding": self.encoding,
|
|
138
|
+
"url": self.url,
|
|
139
|
+
"alg": self.alg,
|
|
140
|
+
"signature": self.signature,
|
|
141
|
+
"disposition": self.disposition,
|
|
142
|
+
"party_history": (
|
|
143
|
+
[party_history.to_dict() for party_history in self.party_history]
|
|
144
|
+
if self.party_history
|
|
145
|
+
else None
|
|
146
|
+
),
|
|
147
|
+
"transferee": self.transferee,
|
|
148
|
+
"transferor": self.transferor,
|
|
149
|
+
"transfer_target": self.transfer_target,
|
|
150
|
+
"original": self.original,
|
|
151
|
+
"consultation": self.consultation,
|
|
152
|
+
"target_dialog": self.target_dialog,
|
|
153
|
+
"campaign": self.campaign,
|
|
154
|
+
"interaction": self.interaction,
|
|
155
|
+
"skill": self.skill
|
|
156
|
+
}
|
|
157
|
+
return {k: v for k, v in dialog_dict.items() if v is not None}
|
|
158
|
+
|
|
159
|
+
def add_external_data(self, url: str, filename: str, mimetype: str) -> None:
|
|
160
|
+
"""
|
|
161
|
+
Add external data to the dialog.
|
|
162
|
+
|
|
163
|
+
:param url: the URL of the external data
|
|
164
|
+
:type url: str
|
|
165
|
+
:return: None
|
|
166
|
+
:rtype: None
|
|
167
|
+
"""
|
|
168
|
+
response = requests.get(url)
|
|
169
|
+
if response.status_code == 200:
|
|
170
|
+
self.body = response.text
|
|
171
|
+
self.mimetype = response.headers["Content-Type"]
|
|
172
|
+
else:
|
|
173
|
+
raise Exception(f"Failed to fetch external data: {response.status_code}")
|
|
174
|
+
|
|
175
|
+
# Overide the filename if provided, otherwise use the filename from the URL
|
|
176
|
+
if filename:
|
|
177
|
+
self.filename = filename
|
|
178
|
+
else:
|
|
179
|
+
self.filename = url.split("/")[-1]
|
|
180
|
+
|
|
181
|
+
# Overide the mimetype if provided, otherwise use the mimetype from the URL
|
|
182
|
+
if mimetype:
|
|
183
|
+
self.mimetype = mimetype
|
|
184
|
+
|
|
185
|
+
# Calculate the SHA-256 hash of the body as the signature
|
|
186
|
+
self.alg = "sha256"
|
|
187
|
+
self.encoding = "base64url"
|
|
188
|
+
self.signature = base64.urlsafe_b64encode(hashlib.sha256(self.body.encode()).digest()).decode()
|
|
189
|
+
|
|
190
|
+
def add_inline_data(self, body: str, filename: str, mimetype: str) -> None:
|
|
191
|
+
"""
|
|
192
|
+
Add inline data to the dialog.
|
|
193
|
+
|
|
194
|
+
:param body: the body of the inline data
|
|
195
|
+
:type body: str
|
|
196
|
+
:param filename: the filename of the inline data
|
|
197
|
+
:type filename: str
|
|
198
|
+
:param mimetype: the mimetype of the inline data
|
|
199
|
+
:type mimetype: str
|
|
200
|
+
:return: None
|
|
201
|
+
:rtype: None
|
|
202
|
+
"""
|
|
203
|
+
self.body = body
|
|
204
|
+
self.mimetype = mimetype
|
|
205
|
+
self.filename = filename
|
|
206
|
+
self.alg = "sha256"
|
|
207
|
+
self.encoding = "base64url"
|
|
208
|
+
self.signature = base64.urlsafe_b64encode(
|
|
209
|
+
hashlib.sha256(self.body.encode()).digest()).decode()
|
|
210
|
+
|
|
211
|
+
# Check if the dialog is an external data dialog
|
|
212
|
+
def is_external_data(self) -> bool:
|
|
213
|
+
return self.url is not None
|
|
214
|
+
|
|
215
|
+
# Check if the dialog is an inline data dialog
|
|
216
|
+
def is_inline_data(self) -> bool:
|
|
217
|
+
return self.body is not None
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
# Check if the dialog is a text dialog
|
|
221
|
+
def is_text(self) -> bool:
|
|
222
|
+
return self.mimetype == "text/plain"
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
# Check if the dialog is an audio dialog
|
|
226
|
+
def is_audio(self) -> bool:
|
|
227
|
+
return self.mimetype in ["audio/x-wav", "audio/x-mp3", "audio/x-mp4", "audio/ogg"]
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
# Check if the dialog is a video dialog
|
|
231
|
+
def is_video(self) -> bool:
|
|
232
|
+
return self.mimetype in ["video/x-mp4", "video/ogg"]
|
|
233
|
+
|
|
234
|
+
# Check if the dialog is an email dialog
|
|
235
|
+
def is_email(self) -> bool:
|
|
236
|
+
return self.mimetype == "message/rfc822"
|
|
237
|
+
|
|
238
|
+
# Check to see if it's an external data dialog, that the contents are valid by
|
|
239
|
+
# checking the hash of the body against the signature
|
|
240
|
+
def is_external_data_changed(self) -> bool:
|
|
241
|
+
if not self.is_external_data():
|
|
242
|
+
return False
|
|
243
|
+
try:
|
|
244
|
+
body_hash = base64.urlsafe_b64decode(self.signature.encode())
|
|
245
|
+
return hashlib.sha256(self.body.encode()).digest() != body_hash
|
|
246
|
+
except Exception as e:
|
|
247
|
+
print(e)
|
|
248
|
+
return True
|
|
249
|
+
|
|
250
|
+
# Convert the dialog from an external data dialog to an inline data dialog
|
|
251
|
+
# by reading the contents from the URL then adding the contents to the body
|
|
252
|
+
def to_inline_data(self) -> None:
|
|
253
|
+
# Read the contents from the URL
|
|
254
|
+
response = requests.get(self.url)
|
|
255
|
+
if response.status_code == 200:
|
|
256
|
+
self.body = response.text
|
|
257
|
+
self.mimetype = response.headers["Content-Type"]
|
|
258
|
+
else:
|
|
259
|
+
raise Exception(f"Failed to fetch external data: {response.status_code}")
|
|
260
|
+
|
|
261
|
+
# Calculate the SHA-256 hash of the body as the signature
|
|
262
|
+
self.alg = "sha256"
|
|
263
|
+
self.encoding = "base64url"
|
|
264
|
+
self.signature = base64.urlsafe_b64encode(hashlib.sha256(self.body.encode()).digest()).decode()
|
|
265
|
+
|
|
266
|
+
# Overide the filename if provided, otherwise use the filename from the URL
|
|
267
|
+
if self.filename:
|
|
268
|
+
self.filename = self.filename
|
|
269
|
+
else:
|
|
270
|
+
self.filename = self.url.split("/")[-1]
|
|
271
|
+
|
|
272
|
+
# Overide the mimetype if provided, otherwise use the mimetype from the URL
|
|
273
|
+
if self.mimetype:
|
|
274
|
+
self.mimetype = self.mimetype
|
|
275
|
+
|
|
276
|
+
# Add the body to the dialog
|
|
277
|
+
self.add_inline_data(self.body, self.filename, self.mimetype)
|