chatgraph 0.5.3__py3-none-any.whl → 0.6.1__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 chatgraph might be problematic. Click here for more details.
- chatgraph/__init__.py +25 -16
- chatgraph/bot/chatbot_model.py +17 -3
- chatgraph/gRPC/gRPCCall.py +30 -3
- chatgraph/pb/router.proto +25 -1
- chatgraph/pb/router_pb2.py +57 -55
- chatgraph/pb/router_pb2_grpc.py +551 -318
- chatgraph/types/end_types.py +22 -8
- chatgraph/types/image.py +92 -0
- chatgraph/types/request_types.py +57 -9
- {chatgraph-0.5.3.dist-info → chatgraph-0.6.1.dist-info}/METADATA +2 -1
- chatgraph-0.6.1.dist-info/RECORD +23 -0
- chatgraph-0.5.3.dist-info/RECORD +0 -22
- {chatgraph-0.5.3.dist-info → chatgraph-0.6.1.dist-info}/LICENSE +0 -0
- {chatgraph-0.5.3.dist-info → chatgraph-0.6.1.dist-info}/WHEEL +0 -0
- {chatgraph-0.5.3.dist-info → chatgraph-0.6.1.dist-info}/entry_points.txt +0 -0
chatgraph/types/end_types.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
class RedirectResponse:
|
|
3
2
|
"""
|
|
4
3
|
Representa uma resposta que redireciona o fluxo do chatbot para uma nova rota.
|
|
@@ -16,6 +15,7 @@ class RedirectResponse:
|
|
|
16
15
|
"""
|
|
17
16
|
self.route = route
|
|
18
17
|
|
|
18
|
+
|
|
19
19
|
class EndChatResponse:
|
|
20
20
|
"""
|
|
21
21
|
Representa uma resposta que indica o fim do chatbot.
|
|
@@ -25,21 +25,35 @@ class EndChatResponse:
|
|
|
25
25
|
observations (str): As observações finais do chatbot.
|
|
26
26
|
"""
|
|
27
27
|
|
|
28
|
-
def __init__(self, tabulation_id: str, observations:str) -> None:
|
|
29
|
-
|
|
28
|
+
def __init__(self, tabulation_id: str, observations: str) -> None:
|
|
29
|
+
"""
|
|
30
30
|
Finzaliza e tabula as informações do chatbot.
|
|
31
|
-
|
|
31
|
+
"""
|
|
32
32
|
self.tabulation_id = tabulation_id
|
|
33
33
|
self.observations = observations
|
|
34
34
|
|
|
35
|
+
|
|
35
36
|
class TransferToHuman:
|
|
36
37
|
"""
|
|
37
38
|
Representa uma transferencia para um atendente humano.
|
|
38
39
|
"""
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
|
|
41
|
+
def __init__(self, campaign_id: str, observations: str) -> None:
|
|
42
|
+
"""
|
|
41
43
|
Finzaliza e tabula as informações do chatbot.
|
|
42
|
-
|
|
44
|
+
"""
|
|
43
45
|
self.campaign_id = campaign_id
|
|
44
46
|
self.observations = observations
|
|
45
|
-
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class TransferToMenu:
|
|
50
|
+
"""
|
|
51
|
+
Representa uma transferencia para outro Menu.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def __init__(self, menu: str, user_message: str) -> None:
|
|
55
|
+
"""
|
|
56
|
+
Finzaliza e tabula as informações do chatbot.
|
|
57
|
+
"""
|
|
58
|
+
self.menu = menu.lower()
|
|
59
|
+
self.user_message = user_message
|
chatgraph/types/image.py
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
from datetime import datetime, timedelta
|
|
2
|
+
import hashlib
|
|
3
|
+
import base64
|
|
4
|
+
from chatgraph.types.message_types import Message
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ImageData:
|
|
8
|
+
"""
|
|
9
|
+
Representa dados de uma imagem, seja por URL ou arquivo local. Caso fornecido um url e um caminho de arquivo, o url será utilizado.
|
|
10
|
+
Atributos:
|
|
11
|
+
type (str): Tipo de imagem, "link" para URL ou "file" para arquivo local.
|
|
12
|
+
url (str): URL da imagem, se aplicável.
|
|
13
|
+
image_path (str): Caminho do arquivo de imagem, se aplicável.
|
|
14
|
+
expiration (int): Tempo de expiração em minutos, 0 para sem expiração.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, *, url: str = None, image_path: str = None, expiration: int = 0):
|
|
18
|
+
|
|
19
|
+
if not url and not image_path:
|
|
20
|
+
raise ValueError("URL or image path must be provided.")
|
|
21
|
+
|
|
22
|
+
self.type = "link" if url else "file"
|
|
23
|
+
self.url = url
|
|
24
|
+
self.expiration = expiration
|
|
25
|
+
|
|
26
|
+
self.image_bytes = None
|
|
27
|
+
self.file_extension = None
|
|
28
|
+
if self.type == "file":
|
|
29
|
+
if not image_path:
|
|
30
|
+
raise ValueError("Image path must be provided for file type.")
|
|
31
|
+
self.file_extension = image_path.split(".")[-1]
|
|
32
|
+
with open(image_path, "rb") as f:
|
|
33
|
+
self.image_bytes = f.read()
|
|
34
|
+
|
|
35
|
+
# Create hash of image bytes if available, otherwise use URL
|
|
36
|
+
hash_input = self.image_bytes if self.image_bytes else url.encode("utf-8")
|
|
37
|
+
|
|
38
|
+
# Create SHA-256 hash and encode in base64
|
|
39
|
+
self.image_id = base64.b64encode(hashlib.sha256(hash_input).digest()).decode(
|
|
40
|
+
"utf-8"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
def get_upload_dict(self):
|
|
44
|
+
dict_data = {}
|
|
45
|
+
if self.expiration > 0:
|
|
46
|
+
now = datetime.now()
|
|
47
|
+
expiration_time = now + timedelta(minutes=self.expiration)
|
|
48
|
+
dict_data["expiration"] = expiration_time.strftime("%Y-%m-%d %H:%M:%S")
|
|
49
|
+
|
|
50
|
+
if self.type == "file":
|
|
51
|
+
dict_data["file_type"] = self.type
|
|
52
|
+
dict_data["file_content"] = self.image_bytes
|
|
53
|
+
dict_data["file_extension"] = self.file_extension
|
|
54
|
+
else:
|
|
55
|
+
dict_data["file_type"] = self.type
|
|
56
|
+
dict_data["file_url"] = self.url
|
|
57
|
+
|
|
58
|
+
return dict_data
|
|
59
|
+
|
|
60
|
+
def get_dict(self):
|
|
61
|
+
dict_data = {
|
|
62
|
+
"image_id": self.image_id,
|
|
63
|
+
"file_type": self.type,
|
|
64
|
+
}
|
|
65
|
+
if self.type == "file":
|
|
66
|
+
dict_data["file_content"] = self.image_bytes
|
|
67
|
+
dict_data["file_extension"] = self.file_extension
|
|
68
|
+
else:
|
|
69
|
+
dict_data["file_url"] = self.url
|
|
70
|
+
return dict_data
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class ImageMessage:
|
|
74
|
+
def __init__(self, image: ImageData, message: Message = None):
|
|
75
|
+
if not isinstance(image, ImageData):
|
|
76
|
+
raise TypeError("Expected an instance of ImageData.")
|
|
77
|
+
|
|
78
|
+
self.type = "image"
|
|
79
|
+
self.image = image
|
|
80
|
+
self.message = message
|
|
81
|
+
|
|
82
|
+
def to_dict(self):
|
|
83
|
+
if not self.message:
|
|
84
|
+
return {
|
|
85
|
+
"file_id": self.image.image_id,
|
|
86
|
+
"message": {},
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
"file_id": self.image.image_id,
|
|
91
|
+
"message": self.message.to_dict(),
|
|
92
|
+
}
|
chatgraph/types/request_types.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from chatgraph.gRPC.gRPCCall import RouterServiceClient
|
|
2
|
+
from chatgraph.types.image import ImageData, ImageMessage
|
|
2
3
|
from chatgraph.types.message_types import Message, Button, MessageTypes, messageTypes
|
|
3
4
|
from typing import Optional
|
|
4
5
|
from datetime import datetime
|
|
@@ -157,7 +158,7 @@ class UserCall:
|
|
|
157
158
|
|
|
158
159
|
def __str__(self):
|
|
159
160
|
return f"UserCall({self.type}, {self.__type_message}, {self.__content_message}, {self.__user_state})"
|
|
160
|
-
|
|
161
|
+
|
|
161
162
|
def send(
|
|
162
163
|
self,
|
|
163
164
|
message: messageTypes | Message,
|
|
@@ -174,11 +175,39 @@ class UserCall:
|
|
|
174
175
|
detail=str(message),
|
|
175
176
|
)
|
|
176
177
|
|
|
178
|
+
if isinstance(message, ImageData):
|
|
179
|
+
message = ImageMessage(
|
|
180
|
+
image=message,
|
|
181
|
+
)
|
|
182
|
+
|
|
177
183
|
if isinstance(message, Message):
|
|
178
184
|
self.__send(message)
|
|
185
|
+
elif isinstance(message, ImageMessage):
|
|
186
|
+
self.__send_image(message)
|
|
179
187
|
else:
|
|
180
188
|
raise ValueError("Tipo de mensagem inválido.")
|
|
181
189
|
|
|
190
|
+
def __upload_file(self, image: ImageData) -> None:
|
|
191
|
+
dict_image = image.get_upload_dict()
|
|
192
|
+
response = self.__router_client.upload_file(dict_image)
|
|
193
|
+
|
|
194
|
+
if not response.status:
|
|
195
|
+
raise ValueError("Erro ao fazer upload do arquivo.")
|
|
196
|
+
else:
|
|
197
|
+
print("Arquivo enviado com sucesso.")
|
|
198
|
+
|
|
199
|
+
def __send_image(self, message: ImageMessage) -> None:
|
|
200
|
+
dict_message = message.to_dict()
|
|
201
|
+
dict_message["message"]["chat_id"] = self.__user_state.chatID.to_dict()
|
|
202
|
+
response = self.__router_client.send_image(dict_message)
|
|
203
|
+
|
|
204
|
+
if not response.status and response.message != "arquivo não encontrado":
|
|
205
|
+
raise ValueError("Erro ao enviar imagem.")
|
|
206
|
+
elif response.message == "arquivo não encontrado":
|
|
207
|
+
self.__upload_file(message.image)
|
|
208
|
+
print("tentando enviar imagem novamente...")
|
|
209
|
+
self.__send_image(message)
|
|
210
|
+
|
|
182
211
|
def __send(self, message: Message) -> None:
|
|
183
212
|
|
|
184
213
|
dict_message = message.to_dict()
|
|
@@ -192,26 +221,41 @@ class UserCall:
|
|
|
192
221
|
raise ValueError("Erro ao enviar mensagem de botões.")
|
|
193
222
|
|
|
194
223
|
def transfer_to_human(self, message: str, campaign_name: str) -> None:
|
|
195
|
-
|
|
224
|
+
|
|
196
225
|
campaign = self.__router_client.get_campaign_id({"name": campaign_name})
|
|
197
|
-
|
|
226
|
+
|
|
198
227
|
response = self.__router_client.transfer_to_human(
|
|
199
228
|
{
|
|
200
229
|
"chat_id": self.__user_state.chatID.to_dict(),
|
|
201
230
|
"campaign_id": campaign.id,
|
|
231
|
+
"observation": message,
|
|
202
232
|
}
|
|
203
233
|
)
|
|
204
234
|
|
|
205
235
|
if not response.status:
|
|
206
236
|
raise ValueError("Erro ao transferir chat para humano.")
|
|
207
237
|
|
|
238
|
+
def transfer_to_menu(self, menu: str, message: str) -> None:
|
|
239
|
+
|
|
240
|
+
response = self.__router_client.transfer_to_menu(
|
|
241
|
+
{
|
|
242
|
+
"chat_id": self.__user_state.chatID.to_dict(),
|
|
243
|
+
"menu": menu,
|
|
244
|
+
"user_message": message,
|
|
245
|
+
}
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
if not response.status:
|
|
249
|
+
raise ValueError("Erro ao transferir chat para menu.")
|
|
250
|
+
|
|
208
251
|
def end_chat(self, message: str, tabulation_name: str) -> None:
|
|
209
252
|
tabulation = self.__router_client.get_tabulation_id({"name": tabulation_name})
|
|
210
|
-
|
|
253
|
+
|
|
211
254
|
response = self.__router_client.end_chat(
|
|
212
255
|
{
|
|
213
256
|
"chat_id": self.__user_state.chatID.to_dict(),
|
|
214
257
|
"tabulation_id": tabulation.id,
|
|
258
|
+
"observation": message,
|
|
215
259
|
}
|
|
216
260
|
)
|
|
217
261
|
|
|
@@ -263,15 +307,15 @@ class UserCall:
|
|
|
263
307
|
@property
|
|
264
308
|
def protocol(self):
|
|
265
309
|
return self.__user_state.protocol
|
|
266
|
-
|
|
310
|
+
|
|
267
311
|
@property
|
|
268
312
|
def observation(self):
|
|
269
313
|
return self.__user_state.observation
|
|
270
|
-
|
|
314
|
+
|
|
271
315
|
@property
|
|
272
316
|
def type_message(self):
|
|
273
317
|
return self.__type_message
|
|
274
|
-
|
|
318
|
+
|
|
275
319
|
@property
|
|
276
320
|
def content_message(self):
|
|
277
321
|
return self.__content_message
|
|
@@ -279,12 +323,16 @@ class UserCall:
|
|
|
279
323
|
@menu.setter
|
|
280
324
|
def menu(self, menu):
|
|
281
325
|
|
|
282
|
-
self.update_user_state(
|
|
326
|
+
self.update_user_state(
|
|
327
|
+
menu, self.__user_state.route, self.__user_state.observation
|
|
328
|
+
)
|
|
283
329
|
|
|
284
330
|
@route.setter
|
|
285
331
|
def route(self, route):
|
|
286
332
|
|
|
287
|
-
self.update_user_state(
|
|
333
|
+
self.update_user_state(
|
|
334
|
+
self.__user_state.menu, route, self.__user_state.observation
|
|
335
|
+
)
|
|
288
336
|
|
|
289
337
|
@observation.setter
|
|
290
338
|
def observation(self, observation):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: chatgraph
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.1
|
|
4
4
|
Summary: A user-friendly chatbot library
|
|
5
5
|
Home-page: https://github.com/irissonnlima/chatgraph
|
|
6
6
|
License: MIT
|
|
@@ -16,6 +16,7 @@ Requires-Dist: grpcio-tools (>=1.67.0,<2.0.0)
|
|
|
16
16
|
Requires-Dist: matplotlib (>=3.10.0,<4.0.0)
|
|
17
17
|
Requires-Dist: networkx (>=3.4.2,<4.0.0)
|
|
18
18
|
Requires-Dist: pika (>=1.3.2,<2.0.0)
|
|
19
|
+
Requires-Dist: protobuf (>=6.31.1,<7.0.0)
|
|
19
20
|
Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
|
|
20
21
|
Requires-Dist: rich (>=13.8.1,<14.0.0)
|
|
21
22
|
Requires-Dist: typer (>=0.12.5,<0.13.0)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
chatgraph/__init__.py,sha256=cQk87BOUYKvOjgCkS5Vexy9EYeLOeuQn6vR1vXx1Akc,935
|
|
2
|
+
chatgraph/auth/credentials.py,sha256=xsMEpLQnc66novPjL6upocMcnUnvFJ7yxINzUenkxmc,2388
|
|
3
|
+
chatgraph/bot/chatbot_model.py,sha256=wLVXehmHEWItRwvl6J8HM96lC69FXmqsNG8KqplBboI,7373
|
|
4
|
+
chatgraph/bot/chatbot_router.py,sha256=bVbm9dBoC2OesetXlQJpCrkaiLM3GUro0GrOyCSgreI,2586
|
|
5
|
+
chatgraph/cli/__init__.py,sha256=tfgYhGoKy1nD4STN4xDh6J4VV55RICk7v1GZmzAg-bM,7413
|
|
6
|
+
chatgraph/error/chatbot_error.py,sha256=4sEcW8vz0eQk2QDmDygucVM4caHliZW5iH7XJvmLBuk,1897
|
|
7
|
+
chatgraph/error/route_error.py,sha256=CY8m82ap7-Sr-DXPsolltRW50TqD__5RyXBmNNJCWr8,793
|
|
8
|
+
chatgraph/gRPC/gRPCCall.py,sha256=KXLhxfX7Mrm48BVuWhTA4xw4T4vghXnljvE37FAxmfQ,6402
|
|
9
|
+
chatgraph/messages/message_consumer.py,sha256=yHhfLYjtmXQYG44o7SNO6XUaeM4-jH8BpIpPHI-mt8Y,6116
|
|
10
|
+
chatgraph/pb/router.proto,sha256=0FDhMe7GrabeQz7QRJN8PN2mcuRjA5YrGt6TC9GWBak,3488
|
|
11
|
+
chatgraph/pb/router_pb2.py,sha256=eSo0ncYDSG3ryIfWNFzqmG3anx-VmQ2nGXBy1gPnXmQ,7962
|
|
12
|
+
chatgraph/pb/router_pb2_grpc.py,sha256=iaQQsYPc8Tihuf4sWEI48DhvhtCYtDqFBHhwRtE57ps,29886
|
|
13
|
+
chatgraph/types/background_task.py,sha256=j-Bpd1l_LCDiWukhfG8wNr1F0_GUaOL_J2_BCUnTof4,928
|
|
14
|
+
chatgraph/types/end_types.py,sha256=ulVq3XybRs-EGcOxw6e1FF6U2p3nbtPfOv3uRe6oJfo,1638
|
|
15
|
+
chatgraph/types/image.py,sha256=-Lf9ns8_M4jmROoFnHlZiYeScYD_GhF1pgIGLVjsRtI,3216
|
|
16
|
+
chatgraph/types/message_types.py,sha256=__LOk09Xfvojum0xiq9n157_3QSSLNaDMc02iq8dGpk,3434
|
|
17
|
+
chatgraph/types/request_types.py,sha256=pGpJhzk6LGSrREGsG2gC14SoS9DTpUO5w9MzmLUg7PU,10500
|
|
18
|
+
chatgraph/types/route.py,sha256=FO5INy5UXgicuQ8FKEZKcPv6WS5YH10dPx2OaPu_0sE,2978
|
|
19
|
+
chatgraph-0.6.1.dist-info/entry_points.txt,sha256=bO9_Q-PqE5vCNNo6ke_-3j2gHfKQMDGnKDTkNuCdBuA,48
|
|
20
|
+
chatgraph-0.6.1.dist-info/LICENSE,sha256=rVJozpRzDlplOpvI8A1GvmfVS0ReYdZvMWc1j2jV0v8,1090
|
|
21
|
+
chatgraph-0.6.1.dist-info/METADATA,sha256=avh_0Xu-Mfkhzr4b5v9mKZyJcd2CprrvUIMBnlWWr6g,12908
|
|
22
|
+
chatgraph-0.6.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
23
|
+
chatgraph-0.6.1.dist-info/RECORD,,
|
chatgraph-0.5.3.dist-info/RECORD
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
chatgraph/__init__.py,sha256=QtS8l6UjQ7N9gPNruTaPKUTNP8-EvTYeiTBoiSKGp7E,781
|
|
2
|
-
chatgraph/auth/credentials.py,sha256=xsMEpLQnc66novPjL6upocMcnUnvFJ7yxINzUenkxmc,2388
|
|
3
|
-
chatgraph/bot/chatbot_model.py,sha256=PhWCDDTIfT92rwS-USciugVjXuCDKk44NJbiOfEhvRk,7051
|
|
4
|
-
chatgraph/bot/chatbot_router.py,sha256=bVbm9dBoC2OesetXlQJpCrkaiLM3GUro0GrOyCSgreI,2586
|
|
5
|
-
chatgraph/cli/__init__.py,sha256=tfgYhGoKy1nD4STN4xDh6J4VV55RICk7v1GZmzAg-bM,7413
|
|
6
|
-
chatgraph/error/chatbot_error.py,sha256=4sEcW8vz0eQk2QDmDygucVM4caHliZW5iH7XJvmLBuk,1897
|
|
7
|
-
chatgraph/error/route_error.py,sha256=CY8m82ap7-Sr-DXPsolltRW50TqD__5RyXBmNNJCWr8,793
|
|
8
|
-
chatgraph/gRPC/gRPCCall.py,sha256=d8nobBb8yDSKl_eFd1ZUfozvpyDZSoul2HlBIO8Q288,5308
|
|
9
|
-
chatgraph/messages/message_consumer.py,sha256=yHhfLYjtmXQYG44o7SNO6XUaeM4-jH8BpIpPHI-mt8Y,6116
|
|
10
|
-
chatgraph/pb/router.proto,sha256=pw3hTwjdMN8-yJIAlKHNigVKYqM-w2nme9-2bCTBiJ0,2853
|
|
11
|
-
chatgraph/pb/router_pb2.py,sha256=jw-Rg05NMwgOKrRsoubFFb82v_O80KgWY4tIqwUf2Aw,6571
|
|
12
|
-
chatgraph/pb/router_pb2_grpc.py,sha256=KxhVxCMVD9tpuX7CyXqIkzZ4P3zfXeVT92Bt_Hi7mrE,24109
|
|
13
|
-
chatgraph/types/background_task.py,sha256=j-Bpd1l_LCDiWukhfG8wNr1F0_GUaOL_J2_BCUnTof4,928
|
|
14
|
-
chatgraph/types/end_types.py,sha256=--Ty2gM_y7J-yRAvZV26e4HMUpoguAMAhfOIS9-kQTk,1316
|
|
15
|
-
chatgraph/types/message_types.py,sha256=__LOk09Xfvojum0xiq9n157_3QSSLNaDMc02iq8dGpk,3434
|
|
16
|
-
chatgraph/types/request_types.py,sha256=BeUI2l9XZpBf5c8xyPvKI68WZ5u6n98cC8DmUfWKlQ0,8788
|
|
17
|
-
chatgraph/types/route.py,sha256=FO5INy5UXgicuQ8FKEZKcPv6WS5YH10dPx2OaPu_0sE,2978
|
|
18
|
-
chatgraph-0.5.3.dist-info/entry_points.txt,sha256=bO9_Q-PqE5vCNNo6ke_-3j2gHfKQMDGnKDTkNuCdBuA,48
|
|
19
|
-
chatgraph-0.5.3.dist-info/LICENSE,sha256=rVJozpRzDlplOpvI8A1GvmfVS0ReYdZvMWc1j2jV0v8,1090
|
|
20
|
-
chatgraph-0.5.3.dist-info/METADATA,sha256=X4TtQbT5Bcpbaes_XIrLjuoELAMuYU3y105R8F7Ilnw,12866
|
|
21
|
-
chatgraph-0.5.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
22
|
-
chatgraph-0.5.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|