mmar-mapi 1.0.14__py3-none-any.whl → 1.0.16__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 mmar-mapi might be problematic. Click here for more details.
- mmar_mapi/file_storage.py +8 -2
- mmar_mapi/models/chat.py +61 -10
- mmar_mapi/models/chat_item.py +3 -0
- mmar_mapi/utils.py +1 -1
- mmar_mapi/utils_import.py +2 -1
- {mmar_mapi-1.0.14.dist-info → mmar_mapi-1.0.16.dist-info}/METADATA +1 -1
- {mmar_mapi-1.0.14.dist-info → mmar_mapi-1.0.16.dist-info}/RECORD +9 -9
- {mmar_mapi-1.0.14.dist-info → mmar_mapi-1.0.16.dist-info}/WHEEL +0 -0
- {mmar_mapi-1.0.14.dist-info → mmar_mapi-1.0.16.dist-info}/licenses/LICENSE +0 -0
mmar_mapi/file_storage.py
CHANGED
|
@@ -6,7 +6,7 @@ from pathlib import Path
|
|
|
6
6
|
from zipfile import ZipFile, is_zipfile
|
|
7
7
|
|
|
8
8
|
ResourceId = str
|
|
9
|
-
|
|
9
|
+
ASCII_DIGITS_SPECIAL = set(string.ascii_lowercase + string.digits + "-")
|
|
10
10
|
SUFFIX_DIR = ".dir"
|
|
11
11
|
SUFFIX_METADATA = ".metadata"
|
|
12
12
|
|
|
@@ -18,7 +18,7 @@ def _validate_exist(files_dir):
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
def _validate_dtype(dtype: str):
|
|
21
|
-
if all(map(
|
|
21
|
+
if all(map(ASCII_DIGITS_SPECIAL.__contains__, dtype)):
|
|
22
22
|
return
|
|
23
23
|
raise ValueError(f"Bad dtype: {dtype}")
|
|
24
24
|
|
|
@@ -61,6 +61,12 @@ class FileStorage:
|
|
|
61
61
|
|
|
62
62
|
return str(fpath)
|
|
63
63
|
|
|
64
|
+
def get_metadata(self, resource_id: ResourceId) -> dict | None:
|
|
65
|
+
metadata_path = Path(resource_id).with_suffix(SUFFIX_METADATA)
|
|
66
|
+
if not metadata_path.exists():
|
|
67
|
+
return None
|
|
68
|
+
return json.loads(metadata_path.read_text())
|
|
69
|
+
|
|
64
70
|
async def upload_async(self, content: bytes | str, fname: str) -> ResourceId:
|
|
65
71
|
return self.upload(content, fname)
|
|
66
72
|
|
mmar_mapi/models/chat.py
CHANGED
|
@@ -4,14 +4,14 @@ from copy import deepcopy
|
|
|
4
4
|
from datetime import datetime
|
|
5
5
|
from typing import Any, Literal, TypeVar
|
|
6
6
|
|
|
7
|
-
from
|
|
7
|
+
from pydantic import Field, ValidationError
|
|
8
|
+
|
|
9
|
+
from mmar_mapi.models.chat_item import ChatItem, OuterContextItem, ReplicaItem
|
|
8
10
|
from mmar_mapi.models.widget import Widget
|
|
9
11
|
from mmar_mapi.type_union import TypeUnion
|
|
10
|
-
from pydantic import Field, ValidationError
|
|
11
12
|
|
|
12
13
|
from .base import Base
|
|
13
14
|
|
|
14
|
-
|
|
15
15
|
_DT_FORMAT: str = "%Y-%m-%d-%H-%M-%S"
|
|
16
16
|
_EXAMPLE_DT: str = datetime(year=1970, month=1, day=1).strftime(_DT_FORMAT)
|
|
17
17
|
StrDict = dict[str, Any]
|
|
@@ -96,6 +96,22 @@ def _get_resource_id(obj: Content) -> str | None:
|
|
|
96
96
|
return None
|
|
97
97
|
|
|
98
98
|
|
|
99
|
+
def _get_resource_name(obj: Content) -> str | None:
|
|
100
|
+
if isinstance(obj, list):
|
|
101
|
+
return next((el for el in map(_get_resource_name, obj) if el), None)
|
|
102
|
+
if isinstance(obj, dict) and obj.get("type") == "resource_id":
|
|
103
|
+
return _get_field(obj, "resource_name", str)
|
|
104
|
+
return None
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _get_resource(obj: Content) -> str | None:
|
|
108
|
+
if isinstance(obj, list):
|
|
109
|
+
return next((el for el in map(_get_resource_id, obj) if el), None)
|
|
110
|
+
if isinstance(obj, dict) and obj.get("type") == "resource_id":
|
|
111
|
+
return obj
|
|
112
|
+
return None
|
|
113
|
+
|
|
114
|
+
|
|
99
115
|
def _get_command(obj: Content) -> dict | None:
|
|
100
116
|
if isinstance(obj, list):
|
|
101
117
|
return next((el for el in map(_get_command, obj) if el), None)
|
|
@@ -138,6 +154,15 @@ class BaseMessage(Base):
|
|
|
138
154
|
def resource_id(self) -> str | None:
|
|
139
155
|
return _get_resource_id(self.content)
|
|
140
156
|
|
|
157
|
+
@property
|
|
158
|
+
def resource_name(self) -> str | None:
|
|
159
|
+
res = _get_resource_name(self.content)
|
|
160
|
+
return res
|
|
161
|
+
|
|
162
|
+
@property
|
|
163
|
+
def resource(self) -> dict | None:
|
|
164
|
+
return _get_resource(self.content)
|
|
165
|
+
|
|
141
166
|
@property
|
|
142
167
|
def command(self) -> dict | None:
|
|
143
168
|
return _get_command(self.content)
|
|
@@ -162,7 +187,7 @@ class BaseMessage(Base):
|
|
|
162
187
|
return _DT_FORMAT
|
|
163
188
|
|
|
164
189
|
@staticmethod
|
|
165
|
-
def find_resource_id(msg: "BaseMessage", ext: str | None = None, type: str=None) -> str | None:
|
|
190
|
+
def find_resource_id(msg: "BaseMessage", ext: str | None = None, type: str = None) -> str | None:
|
|
166
191
|
resource_id = msg.resource_id
|
|
167
192
|
if type and type != msg.type:
|
|
168
193
|
return None
|
|
@@ -188,6 +213,7 @@ class AIMessage(BaseMessage):
|
|
|
188
213
|
def with_state(self, state: str) -> "AIMessage":
|
|
189
214
|
return self.model_copy(update=dict(state=state))
|
|
190
215
|
|
|
216
|
+
|
|
191
217
|
class MiscMessage(BaseMessage):
|
|
192
218
|
type: Literal["misc"] = "misc"
|
|
193
219
|
|
|
@@ -259,20 +285,37 @@ def make_content(
|
|
|
259
285
|
text: str | None = None,
|
|
260
286
|
*,
|
|
261
287
|
resource_id: str | None = None,
|
|
288
|
+
resource: dict | None = None,
|
|
262
289
|
command: dict | None = None,
|
|
263
290
|
widget: Widget | None = None,
|
|
264
291
|
content: Content | None = None,
|
|
265
292
|
) -> Content:
|
|
266
|
-
|
|
293
|
+
if resource and resource_id:
|
|
294
|
+
raise ValueError("Cannot pass both 'resource' and 'resource_id'")
|
|
295
|
+
|
|
296
|
+
if resource_id:
|
|
297
|
+
resource = {"type": "resource_id", "resource_id": resource_id}
|
|
298
|
+
elif resource:
|
|
299
|
+
if not isinstance(resource, dict):
|
|
300
|
+
raise TypeError("'resource' must be a dict")
|
|
301
|
+
resource_id = resource.get("resource_id")
|
|
302
|
+
if not resource_id:
|
|
303
|
+
raise ValueError("'resource' must contain 'resource_id'")
|
|
304
|
+
resource_name = resource.get("resource_name")
|
|
305
|
+
resource = {"type": "resource_id", "resource_id": resource_id}
|
|
306
|
+
if resource_name:
|
|
307
|
+
resource["resource_name"] = resource_name
|
|
308
|
+
else:
|
|
309
|
+
resource = None
|
|
310
|
+
|
|
267
311
|
command = (command or None) and {"type": "command", "command": command}
|
|
268
312
|
|
|
269
313
|
content = content if isinstance(content, list) else [content] if content else []
|
|
270
|
-
content += list(filter(None, [text,
|
|
314
|
+
content += list(filter(None, [text, resource, command, widget]))
|
|
271
315
|
if len(content) == 0:
|
|
272
316
|
content = ""
|
|
273
317
|
elif len(content) == 1:
|
|
274
318
|
content = content[0]
|
|
275
|
-
|
|
276
319
|
return content
|
|
277
320
|
|
|
278
321
|
|
|
@@ -285,13 +328,19 @@ def convert_replica_item_to_message(replica: ReplicaItem) -> ChatMessage:
|
|
|
285
328
|
widget=replica.widget,
|
|
286
329
|
)
|
|
287
330
|
# legacy: eliminate after migration
|
|
288
|
-
resource_id
|
|
331
|
+
if resource_id := replica.resource_id:
|
|
332
|
+
resource = {"type": "resource_id", "resource_id": resource_id}
|
|
333
|
+
resource_name = replica.resource_name
|
|
334
|
+
if resource_name:
|
|
335
|
+
resource["resource_name"] = resource_name
|
|
336
|
+
else:
|
|
337
|
+
resource = None
|
|
289
338
|
body = replica.body
|
|
290
339
|
command = (replica.command or None) and {"type": "command", "command": replica.command}
|
|
291
340
|
widget = replica.widget
|
|
292
341
|
date_time = replica.date_time
|
|
293
342
|
|
|
294
|
-
content = list(filter(None, [body,
|
|
343
|
+
content = list(filter(None, [body, resource, command, widget]))
|
|
295
344
|
if len(content) == 0:
|
|
296
345
|
content = ""
|
|
297
346
|
elif len(content) == 1:
|
|
@@ -375,6 +424,7 @@ def convert_message_to_replica_item(message: ChatMessage) -> ReplicaItem | None:
|
|
|
375
424
|
role=role,
|
|
376
425
|
body=message.text,
|
|
377
426
|
resource_id=message.resource_id,
|
|
427
|
+
resource_name=message.resource_name,
|
|
378
428
|
command=message.command,
|
|
379
429
|
widget=message.widget,
|
|
380
430
|
date_time=message.date_time,
|
|
@@ -388,10 +438,11 @@ def convert_message_to_replica_item(message: ChatMessage) -> ReplicaItem | None:
|
|
|
388
438
|
|
|
389
439
|
def convert_chat_to_chat_item(chat: Chat) -> ChatItem:
|
|
390
440
|
# legacy: eliminate after migration
|
|
391
|
-
|
|
441
|
+
res = ChatItem(
|
|
392
442
|
outer_context=convert_context_to_outer_context(chat.context),
|
|
393
443
|
inner_context=dict(replicas=list(map(convert_message_to_replica_item, chat.messages))),
|
|
394
444
|
)
|
|
445
|
+
return res
|
|
395
446
|
|
|
396
447
|
|
|
397
448
|
def parse_chat_item_as_chat(chat_obj: str | dict | ChatItem) -> Chat:
|
mmar_mapi/models/chat_item.py
CHANGED
|
@@ -69,6 +69,9 @@ class ReplicaItem(Base):
|
|
|
69
69
|
resource_id: Annotated[str | None, AfterValidator(nullify_empty)] = Field(
|
|
70
70
|
None, alias="ResourceId", examples=["<link-id>"]
|
|
71
71
|
)
|
|
72
|
+
resource_name: Annotated[str | None, AfterValidator(nullify_empty)] = Field(
|
|
73
|
+
None, alias="ResourceName", examples=["filename"]
|
|
74
|
+
)
|
|
72
75
|
widget: Widget | None = Field(None, alias="Widget", examples=[None])
|
|
73
76
|
command: dict | None = Field(None, alias="Command", examples=[None])
|
|
74
77
|
role: bool = Field(False, alias="Role", description="True = ai, False = client", examples=[False])
|
mmar_mapi/utils.py
CHANGED
|
@@ -6,7 +6,7 @@ from datetime import datetime
|
|
|
6
6
|
def make_session_id(with_millis=False) -> str:
|
|
7
7
|
dt = datetime.now()
|
|
8
8
|
fmt = "%Y-%m-%d--%H-%M-%S-%f" if with_millis else "%Y-%m-%d--%H-%M-%S"
|
|
9
|
-
return
|
|
9
|
+
return dt.strftime(fmt)
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def chunked(items: Iterable, n) -> list:
|
mmar_mapi/utils_import.py
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
mmar_mapi/__init__.py,sha256=Q2WFyNje0mDzP3eK7k-900W4Uty82BlulKv9-FmkcZs,1177
|
|
2
2
|
mmar_mapi/api.py,sha256=C9Sr8dISvf51xfEznPjccI_odaG4coQE3HI_0jVpjMQ,1677
|
|
3
|
-
mmar_mapi/file_storage.py,sha256=
|
|
3
|
+
mmar_mapi/file_storage.py,sha256=RNPHKDV7JIo2ZlSOyi7UfE8q7kpMvv7ZzfpTdoVg1vM,4687
|
|
4
4
|
mmar_mapi/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
mmar_mapi/models/base.py,sha256=mKtXV2x51XVj7W-et9tjGcPMDUUUMelW-BywMgFc2p0,411
|
|
6
|
-
mmar_mapi/models/chat.py,sha256
|
|
7
|
-
mmar_mapi/models/chat_item.py,sha256=
|
|
6
|
+
mmar_mapi/models/chat.py,sha256=-XilkiderIOFG1oSKRDG9NDOEN21sBpbTPHUrqVPjc4,15400
|
|
7
|
+
mmar_mapi/models/chat_item.py,sha256=TRuV5qn7pi3eOvSG7GUqtTHEaq4b7fPoCCZtW-TyEIU,5702
|
|
8
8
|
mmar_mapi/models/enums.py,sha256=J-GNpql9MCnKnWiV9aJRQGI-pAybvV86923RZs99grA,1006
|
|
9
9
|
mmar_mapi/models/tracks.py,sha256=HKDp-BX1p7AlDfSEKfOKCu0TRSK9cD4Dmq1vJt8oRjw,307
|
|
10
10
|
mmar_mapi/models/widget.py,sha256=ue5o4AkN8SG09aA8eQLOOxbwah-mkZir0ZGL6OA8S9Q,1355
|
|
11
11
|
mmar_mapi/type_union.py,sha256=diwmzcnbqkpGFckPHNw9o8zyQ955mOGNvhTlcBJ0RMI,1905
|
|
12
|
-
mmar_mapi/utils.py,sha256=
|
|
13
|
-
mmar_mapi/utils_import.py,sha256=
|
|
12
|
+
mmar_mapi/utils.py,sha256=FlW9n-84xz2zSHsahHzJ3Y4Wu5mjpFer6t9z6PF6lS0,488
|
|
13
|
+
mmar_mapi/utils_import.py,sha256=pUyMFd8SItTxBKI-GO9JhRmy43jG_OQlUPr8QCBOSwg,1682
|
|
14
14
|
mmar_mapi/xml_parser.py,sha256=VvLIX_XCZao9i0qqpTVx8nx0vbFXSe8pEbdJdXnj97g,568
|
|
15
|
-
mmar_mapi-1.0.
|
|
16
|
-
mmar_mapi-1.0.
|
|
17
|
-
mmar_mapi-1.0.
|
|
18
|
-
mmar_mapi-1.0.
|
|
15
|
+
mmar_mapi-1.0.16.dist-info/licenses/LICENSE,sha256=2A90w8WjhOgQXnFuUijKJYazaqZ4_NTokYb9Po4y-9k,1061
|
|
16
|
+
mmar_mapi-1.0.16.dist-info/WHEEL,sha256=-neZj6nU9KAMg2CnCY6T3w8J53nx1kFGw_9HfoSzM60,79
|
|
17
|
+
mmar_mapi-1.0.16.dist-info/METADATA,sha256=C_euDto9FvTmLelGMbi7HSMyfd6Gm6JK0rAUT9h1kMk,944
|
|
18
|
+
mmar_mapi-1.0.16.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|