mmar-mapi 1.0.25__py3-none-any.whl → 1.1.0__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/__init__.py +0 -5
- mmar_mapi/models/chat.py +36 -178
- {mmar_mapi-1.0.25.dist-info → mmar_mapi-1.1.0.dist-info}/METADATA +1 -1
- {mmar_mapi-1.0.25.dist-info → mmar_mapi-1.1.0.dist-info}/RECORD +6 -7
- mmar_mapi/models/chat_item.py +0 -160
- {mmar_mapi-1.0.25.dist-info → mmar_mapi-1.1.0.dist-info}/WHEEL +0 -0
- {mmar_mapi-1.0.25.dist-info → mmar_mapi-1.1.0.dist-info}/licenses/LICENSE +0 -0
mmar_mapi/__init__.py
CHANGED
|
@@ -11,7 +11,6 @@ from .models.chat import (
|
|
|
11
11
|
Content,
|
|
12
12
|
BaseMessage,
|
|
13
13
|
)
|
|
14
|
-
from .models.chat_item import ChatItem, OuterContextItem, InnerContextItem, ReplicaItem
|
|
15
14
|
from .models.enums import MTRSLabelEnum, DiagnosticsXMLTagEnum, MTRSXMLTagEnum, DoctorChoiceXMLTagEnum
|
|
16
15
|
from .models.tracks import TrackInfo, DomainInfo
|
|
17
16
|
from .models.widget import Widget
|
|
@@ -25,7 +24,6 @@ __all__ = [
|
|
|
25
24
|
"Base",
|
|
26
25
|
"BaseMessage",
|
|
27
26
|
"Chat",
|
|
28
|
-
"ChatItem",
|
|
29
27
|
"ChatMessage",
|
|
30
28
|
"Content",
|
|
31
29
|
"Context",
|
|
@@ -34,12 +32,9 @@ __all__ = [
|
|
|
34
32
|
"DomainInfo",
|
|
35
33
|
"FileStorage",
|
|
36
34
|
"HumanMessage",
|
|
37
|
-
"InnerContextItem",
|
|
38
35
|
"MTRSLabelEnum",
|
|
39
36
|
"MTRSXMLTagEnum",
|
|
40
37
|
"MiscMessage",
|
|
41
|
-
"OuterContextItem",
|
|
42
|
-
"ReplicaItem",
|
|
43
38
|
"ResourceId",
|
|
44
39
|
"TrackInfo",
|
|
45
40
|
"Widget",
|
mmar_mapi/models/chat.py
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import warnings
|
|
2
2
|
from collections.abc import Callable
|
|
3
|
-
from copy import deepcopy
|
|
4
3
|
from datetime import datetime
|
|
5
|
-
from typing import Any, Literal, TypeVar
|
|
4
|
+
from typing import Any, Literal, NotRequired, TypedDict, TypeVar
|
|
6
5
|
|
|
7
|
-
from pydantic import Field
|
|
6
|
+
from pydantic import Field
|
|
8
7
|
|
|
9
|
-
from mmar_mapi.models.chat_item import ChatItem, OuterContextItem, ReplicaItem
|
|
10
8
|
from mmar_mapi.models.widget import Widget
|
|
11
9
|
from mmar_mapi.type_union import TypeUnion
|
|
12
10
|
|
|
@@ -15,7 +13,25 @@ from .base import Base
|
|
|
15
13
|
_DT_FORMAT: str = "%Y-%m-%d-%H-%M-%S"
|
|
16
14
|
_EXAMPLE_DT: str = datetime(year=1970, month=1, day=1).strftime(_DT_FORMAT)
|
|
17
15
|
StrDict = dict[str, Any]
|
|
18
|
-
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ResourceDict(TypedDict):
|
|
19
|
+
type: Literal["resource_id"]
|
|
20
|
+
resource_id: str
|
|
21
|
+
resource_name: NotRequired[str]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TextDict(TypedDict):
|
|
25
|
+
type: Literal["text"]
|
|
26
|
+
text: str
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class CommandDict(TypedDict):
|
|
30
|
+
type: Literal["command"]
|
|
31
|
+
command: StrDict
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
ContentBase = str | Widget | ResourceDict | CommandDict | TextDict | StrDict
|
|
19
35
|
Content = ContentBase | list[ContentBase]
|
|
20
36
|
T = TypeVar("T")
|
|
21
37
|
|
|
@@ -33,10 +49,12 @@ class Context(Base):
|
|
|
33
49
|
|
|
34
50
|
def create_id(self, short: bool = False) -> str:
|
|
35
51
|
uid, sid, cid = self.user_id, self.session_id, self.client_id
|
|
36
|
-
if short:
|
|
37
|
-
return f"{cid}_{uid}_{sid}"
|
|
38
52
|
return f"client_{cid}_user_{uid}_session_{sid}"
|
|
39
53
|
|
|
54
|
+
def create_trace_id(self) -> str:
|
|
55
|
+
uid, sid, cid = self.user_id, self.session_id, self.client_id
|
|
56
|
+
return f"{cid}_{uid}_{sid}"
|
|
57
|
+
|
|
40
58
|
def _get_deprecated_extra(self, field, default):
|
|
41
59
|
# legacy: eliminate after migration
|
|
42
60
|
res = (self.extra or {}).get(field, default)
|
|
@@ -241,11 +259,8 @@ class Chat(Base):
|
|
|
241
259
|
return self.context.create_id(short)
|
|
242
260
|
|
|
243
261
|
@staticmethod
|
|
244
|
-
def parse(chat_obj: str | dict
|
|
245
|
-
return
|
|
246
|
-
|
|
247
|
-
def to_chat_item(self, failsafe: bool=False) -> ChatItem:
|
|
248
|
-
return convert_chat_to_chat_item(self, failsafe)
|
|
262
|
+
def parse(chat_obj: str | dict) -> "Chat":
|
|
263
|
+
return _parse_chat(chat_obj)
|
|
249
264
|
|
|
250
265
|
def add_message(self, message: ChatMessage):
|
|
251
266
|
self.messages.append(message)
|
|
@@ -277,7 +292,10 @@ class Chat(Base):
|
|
|
277
292
|
message = messages[-1]
|
|
278
293
|
return message if isinstance(message, HumanMessage) else None
|
|
279
294
|
|
|
280
|
-
def count_messages(self, func: Callable[[ChatMessage], bool]) -> int:
|
|
295
|
+
def count_messages(self, func: Callable[[ChatMessage], bool] | type) -> int:
|
|
296
|
+
if isinstance(func, type):
|
|
297
|
+
msg_type = func
|
|
298
|
+
func = lambda msg: isinstance(msg, msg_type)
|
|
281
299
|
return sum(map(func, self.messages))
|
|
282
300
|
|
|
283
301
|
|
|
@@ -319,171 +337,11 @@ def make_content(
|
|
|
319
337
|
return content
|
|
320
338
|
|
|
321
339
|
|
|
322
|
-
def
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
text=replica.body,
|
|
326
|
-
resource_id=replica.resource_id,
|
|
327
|
-
command=replica.command,
|
|
328
|
-
widget=replica.widget,
|
|
329
|
-
)
|
|
330
|
-
# legacy: eliminate after migration
|
|
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
|
|
338
|
-
body = replica.body
|
|
339
|
-
command = (replica.command or None) and {"type": "command", "command": replica.command}
|
|
340
|
-
widget = replica.widget
|
|
341
|
-
date_time = replica.date_time
|
|
342
|
-
|
|
343
|
-
content = list(filter(None, [body, resource, command, widget]))
|
|
344
|
-
if len(content) == 0:
|
|
345
|
-
content = ""
|
|
346
|
-
elif len(content) == 1:
|
|
347
|
-
content = content[0]
|
|
348
|
-
|
|
349
|
-
is_bot_message = replica.role
|
|
350
|
-
|
|
351
|
-
if is_bot_message:
|
|
352
|
-
kwargs = dict(
|
|
353
|
-
content=content,
|
|
354
|
-
date_time=date_time,
|
|
355
|
-
state=replica.state,
|
|
356
|
-
extra=dict(
|
|
357
|
-
**(replica.extra or {}),
|
|
358
|
-
action=replica.action,
|
|
359
|
-
moderation=replica.moderation,
|
|
360
|
-
),
|
|
361
|
-
)
|
|
362
|
-
res = AIMessage(**kwargs)
|
|
363
|
-
else:
|
|
364
|
-
kwargs = dict(content=content, date_time=date_time)
|
|
365
|
-
res = HumanMessage(**kwargs)
|
|
366
|
-
return res
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
def convert_outer_context_to_context(octx: OuterContextItem) -> Context:
|
|
370
|
-
# legacy: eliminate after migration
|
|
371
|
-
context = Context(
|
|
372
|
-
client_id=octx.client_id,
|
|
373
|
-
user_id=octx.user_id,
|
|
374
|
-
session_id=octx.session_id,
|
|
375
|
-
track_id=octx.track_id,
|
|
376
|
-
extra=dict(
|
|
377
|
-
sex=octx.sex,
|
|
378
|
-
age=octx.age,
|
|
379
|
-
parent_session_id=octx.parent_session_id,
|
|
380
|
-
entrypoint_key=octx.entrypoint_key,
|
|
381
|
-
language_code=octx.language_code,
|
|
382
|
-
),
|
|
383
|
-
)
|
|
384
|
-
return context
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
def convert_chat_item_to_chat(chat_item: ChatItem) -> Chat:
|
|
388
|
-
# legacy: eliminate after migration
|
|
389
|
-
context = convert_outer_context_to_context(chat_item.outer_context)
|
|
390
|
-
messages = list(map(convert_replica_item_to_message, chat_item.inner_context.replicas))
|
|
391
|
-
res = Chat(context=context, messages=messages)
|
|
392
|
-
return res
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
def convert_context_to_outer_context(context: Context, failsafe: bool=False) -> OuterContextItem:
|
|
396
|
-
# legacy: eliminate after migration
|
|
397
|
-
extra = context.extra or {}
|
|
398
|
-
if failsafe:
|
|
399
|
-
extra['sex'] = extra.get('sex') or True
|
|
400
|
-
extra['age'] = extra.get('age') or 42
|
|
401
|
-
extra['language_code'] = extra.get('language_code') or ''
|
|
402
|
-
extra['entrypoint_key'] = extra.get('entrypoint_key') or ''
|
|
403
|
-
return OuterContextItem(
|
|
404
|
-
client_id=context.client_id,
|
|
405
|
-
user_id=context.user_id,
|
|
406
|
-
session_id=context.session_id,
|
|
407
|
-
track_id=context.track_id,
|
|
408
|
-
sex=extra["sex"],
|
|
409
|
-
age=extra["age"],
|
|
410
|
-
entrypoint_key=extra["entrypoint_key"],
|
|
411
|
-
language_code=extra["language_code"],
|
|
412
|
-
parent_session_id=extra.get("parent_session_id"),
|
|
413
|
-
)
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
def convert_message_to_replica_item(message: ChatMessage) -> ReplicaItem | None:
|
|
417
|
-
# legacy: eliminate after migration
|
|
418
|
-
m_type = message.type
|
|
419
|
-
if m_type in {"ai", "human"}:
|
|
420
|
-
role = m_type == "ai"
|
|
421
|
-
else:
|
|
422
|
-
return None
|
|
423
|
-
|
|
424
|
-
extra = deepcopy(message.extra) if message.extra else {}
|
|
425
|
-
action = extra.pop("action", "")
|
|
426
|
-
moderation = extra.pop("moderation", "OK")
|
|
427
|
-
|
|
428
|
-
kwargs = dict(
|
|
429
|
-
role=role,
|
|
430
|
-
body=message.text,
|
|
431
|
-
resource_id=message.resource_id,
|
|
432
|
-
resource_name=message.resource_name,
|
|
433
|
-
command=message.command,
|
|
434
|
-
widget=message.widget,
|
|
435
|
-
date_time=message.date_time,
|
|
436
|
-
extra=extra or None,
|
|
437
|
-
state=getattr(message, "state", ""),
|
|
438
|
-
action=action,
|
|
439
|
-
moderation=moderation,
|
|
440
|
-
)
|
|
441
|
-
return ReplicaItem(**kwargs)
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
def convert_chat_to_chat_item(chat: Chat, failsafe: bool=False) -> ChatItem:
|
|
445
|
-
# legacy: eliminate after migration
|
|
446
|
-
res = ChatItem(
|
|
447
|
-
outer_context=convert_context_to_outer_context(chat.context, failsafe=failsafe),
|
|
448
|
-
inner_context=dict(replicas=list(map(convert_message_to_replica_item, chat.messages))),
|
|
449
|
-
)
|
|
450
|
-
return res
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
def parse_chat_item_as_chat(chat_obj: str | dict | ChatItem) -> Chat:
|
|
454
|
-
# legacy: eliminate after migration
|
|
455
|
-
if isinstance(chat_obj, ChatItem):
|
|
456
|
-
chat_item = chat_obj
|
|
457
|
-
else:
|
|
458
|
-
chat_item = ChatItem.parse(chat_obj)
|
|
459
|
-
res = convert_chat_item_to_chat(chat_item)
|
|
460
|
-
return res
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
def _parse_chat(chat_obj: str | dict) -> Chat:
|
|
340
|
+
def _parse_chat(chat_obj: str | dict | Chat) -> Chat:
|
|
341
|
+
if isinstance(chat_obj, Chat):
|
|
342
|
+
return chat_obj
|
|
464
343
|
if isinstance(chat_obj, dict):
|
|
465
344
|
return Chat.model_validate(chat_obj)
|
|
466
|
-
|
|
467
|
-
return Chat.model_validate_json(chat_obj)
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
def is_chat_item(chat_obj: str | dict | ChatItem) -> bool:
|
|
471
|
-
if isinstance(chat_obj, ChatItem):
|
|
472
|
-
return True
|
|
473
|
-
if isinstance(chat_obj, dict):
|
|
474
|
-
return "OuterContext" in chat_obj
|
|
475
345
|
if isinstance(chat_obj, str):
|
|
476
|
-
return
|
|
477
|
-
|
|
478
|
-
return False
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
def _parse_chat_compat(chat_obj: str | dict | ChatItem) -> Chat:
|
|
482
|
-
# legacy: eliminate after migration
|
|
483
|
-
if is_chat_item(chat_obj):
|
|
484
|
-
return parse_chat_item_as_chat(chat_obj)
|
|
485
|
-
try:
|
|
486
|
-
return _parse_chat(chat_obj)
|
|
487
|
-
except ValidationError as ex:
|
|
488
|
-
warnings.warn(f"Failed to parse chat: {ex}")
|
|
489
|
-
return parse_chat_item_as_chat(chat_obj)
|
|
346
|
+
return Chat.model_validate_json(chat_obj)
|
|
347
|
+
raise ValueError(f"Bad chat_obj {type(chat_obj)}: {chat_obj}")
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
mmar_mapi/__init__.py,sha256=
|
|
1
|
+
mmar_mapi/__init__.py,sha256=Wq3MAvrtONYfUY63ShtqzbO-05uhxPzKU5I6p27aZc0,1085
|
|
2
2
|
mmar_mapi/api.py,sha256=VGoZ2nYIvm35U4FO4yhFG9nYSaK-gjOUC3pNyfBrq3o,6109
|
|
3
3
|
mmar_mapi/decorators_maybe_lru_cache.py,sha256=eO2I6t1fHLUNRABClK1c8EZzHAmCeSK6O-hbJGb2c9E,444
|
|
4
4
|
mmar_mapi/file_storage.py,sha256=km4xA0h-GU07kBc6v3cG2fd9gDF75OfwBJiy0WOmtn4,5067
|
|
5
5
|
mmar_mapi/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
6
|
mmar_mapi/models/base.py,sha256=mKtXV2x51XVj7W-et9tjGcPMDUUUMelW-BywMgFc2p0,411
|
|
7
|
-
mmar_mapi/models/chat.py,sha256=
|
|
8
|
-
mmar_mapi/models/chat_item.py,sha256=TRuV5qn7pi3eOvSG7GUqtTHEaq4b7fPoCCZtW-TyEIU,5702
|
|
7
|
+
mmar_mapi/models/chat.py,sha256=hViSGiRCozpT8Ze_ZBa7kObsTPOttz6TKFKRk47wZQw,10893
|
|
9
8
|
mmar_mapi/models/enums.py,sha256=J-GNpql9MCnKnWiV9aJRQGI-pAybvV86923RZs99grA,1006
|
|
10
9
|
mmar_mapi/models/tracks.py,sha256=HKDp-BX1p7AlDfSEKfOKCu0TRSK9cD4Dmq1vJt8oRjw,307
|
|
11
10
|
mmar_mapi/models/widget.py,sha256=ue5o4AkN8SG09aA8eQLOOxbwah-mkZir0ZGL6OA8S9Q,1355
|
|
@@ -13,7 +12,7 @@ mmar_mapi/type_union.py,sha256=diwmzcnbqkpGFckPHNw9o8zyQ955mOGNvhTlcBJ0RMI,1905
|
|
|
13
12
|
mmar_mapi/utils.py,sha256=FlW9n-84xz2zSHsahHzJ3Y4Wu5mjpFer6t9z6PF6lS0,488
|
|
14
13
|
mmar_mapi/utils_import.py,sha256=pUyMFd8SItTxBKI-GO9JhRmy43jG_OQlUPr8QCBOSwg,1682
|
|
15
14
|
mmar_mapi/xml_parser.py,sha256=VvLIX_XCZao9i0qqpTVx8nx0vbFXSe8pEbdJdXnj97g,568
|
|
16
|
-
mmar_mapi-1.0.
|
|
17
|
-
mmar_mapi-1.0.
|
|
18
|
-
mmar_mapi-1.0.
|
|
19
|
-
mmar_mapi-1.0.
|
|
15
|
+
mmar_mapi-1.1.0.dist-info/licenses/LICENSE,sha256=2A90w8WjhOgQXnFuUijKJYazaqZ4_NTokYb9Po4y-9k,1061
|
|
16
|
+
mmar_mapi-1.1.0.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
|
|
17
|
+
mmar_mapi-1.1.0.dist-info/METADATA,sha256=dJuZVT4KmFH2gUDL7xtFtnq083Xk_tqKVPGXCOJecsI,943
|
|
18
|
+
mmar_mapi-1.1.0.dist-info/RECORD,,
|
mmar_mapi/models/chat_item.py
DELETED
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
from datetime import datetime
|
|
2
|
-
from typing import Annotated, Any
|
|
3
|
-
from collections.abc import Callable
|
|
4
|
-
|
|
5
|
-
from mmar_mapi.models.widget import Widget
|
|
6
|
-
from pydantic import Field, ConfigDict, BeforeValidator, AfterValidator
|
|
7
|
-
|
|
8
|
-
from .base import Base
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
_DT_FORMAT: str = "%Y-%m-%d-%H-%M-%S"
|
|
12
|
-
_EXAMPLE_DT_0 = datetime(1970, 1, 1, 0, 0, 0)
|
|
13
|
-
_EXAMPLE_DT: str = _EXAMPLE_DT_0.strftime(_DT_FORMAT)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def now_pretty() -> str:
|
|
17
|
-
return datetime.now().strftime(ReplicaItem.DATETIME_FORMAT())
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class OuterContextItem(Base):
|
|
21
|
-
# remove annoying warning for protected `model_` namespace
|
|
22
|
-
model_config = ConfigDict(protected_namespaces=())
|
|
23
|
-
|
|
24
|
-
sex: bool = Field(False, alias="Sex", description="True = male, False = female", examples=[True])
|
|
25
|
-
age: int = Field(0, alias="Age", examples=[20])
|
|
26
|
-
user_id: str = Field("", alias="UserId", examples=["123456789"])
|
|
27
|
-
parent_session_id: str | None = Field(None, alias="ParentSessionId", examples=["987654320"])
|
|
28
|
-
session_id: str = Field("", alias="SessionId", examples=["987654321"])
|
|
29
|
-
client_id: str = Field("", alias="ClientId", examples=["543216789"])
|
|
30
|
-
track_id: str = Field(default="Consultation", alias="TrackId")
|
|
31
|
-
entrypoint_key: str = Field("", alias="EntrypointKey", examples=["giga"])
|
|
32
|
-
language_code: str = Field("ru", alias="LanguageCode", examples=["ru"])
|
|
33
|
-
|
|
34
|
-
def create_id(self, short: bool = False) -> str:
|
|
35
|
-
uid, sid, cid = self.user_id, self.session_id, self.client_id
|
|
36
|
-
if short:
|
|
37
|
-
return f"{uid}_{sid}_{cid}"
|
|
38
|
-
return f"user_{uid}_session_{sid}_client_{cid}"
|
|
39
|
-
|
|
40
|
-
def to_dict(self) -> dict[str, Any]:
|
|
41
|
-
return self.model_dump(by_alias=True)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
LABELS = {
|
|
45
|
-
0: "OK",
|
|
46
|
-
1: "NON_MED",
|
|
47
|
-
2: "CHILD",
|
|
48
|
-
3: "ABSURD",
|
|
49
|
-
4: "GREETING",
|
|
50
|
-
5: "RECEIPT",
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def fix_deprecated_moderation(moderation):
|
|
55
|
-
if isinstance(moderation, int):
|
|
56
|
-
return LABELS.get(moderation, "OK")
|
|
57
|
-
elif isinstance(moderation, str):
|
|
58
|
-
return moderation
|
|
59
|
-
else:
|
|
60
|
-
raise ValueError(f"Unsupported moderation: {moderation} :: {type(moderation)}")
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def nullify_empty(text: str) -> str | None:
|
|
64
|
-
return text or None
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
class ReplicaItem(Base):
|
|
68
|
-
body: str = Field("", alias="Body", examples=["Привет"])
|
|
69
|
-
resource_id: Annotated[str | None, AfterValidator(nullify_empty)] = Field(
|
|
70
|
-
None, alias="ResourceId", examples=["<link-id>"]
|
|
71
|
-
)
|
|
72
|
-
resource_name: Annotated[str | None, AfterValidator(nullify_empty)] = Field(
|
|
73
|
-
None, alias="ResourceName", examples=["filename"]
|
|
74
|
-
)
|
|
75
|
-
widget: Widget | None = Field(None, alias="Widget", examples=[None])
|
|
76
|
-
command: dict | None = Field(None, alias="Command", examples=[None])
|
|
77
|
-
role: bool = Field(False, alias="Role", description="True = ai, False = client", examples=[False])
|
|
78
|
-
date_time: str = Field(
|
|
79
|
-
default_factory=now_pretty, alias="DateTime", examples=[_EXAMPLE_DT], description=f"Format: {_DT_FORMAT}"
|
|
80
|
-
)
|
|
81
|
-
state: str = Field("", alias="State", description="chat manager fsm state", examples=["COLLECTION"])
|
|
82
|
-
action: str = Field("", alias="Action", description="chat manager fsm action", examples=["DIAGNOSIS"])
|
|
83
|
-
# todo fix: support loading from `moderation: int`
|
|
84
|
-
moderation: Annotated[str, BeforeValidator(str)] = Field(
|
|
85
|
-
"OK", alias="Moderation", description="moderation outcome", examples=["OK"]
|
|
86
|
-
)
|
|
87
|
-
extra: dict | None = Field(None, alias="Extra", examples=[None])
|
|
88
|
-
|
|
89
|
-
def to_dict(self) -> dict[str, Any]:
|
|
90
|
-
return self.model_dump(by_alias=True)
|
|
91
|
-
|
|
92
|
-
@staticmethod
|
|
93
|
-
def DATETIME_FORMAT() -> str:
|
|
94
|
-
return _DT_FORMAT
|
|
95
|
-
|
|
96
|
-
def with_now_datetime(self):
|
|
97
|
-
return self.model_copy(update=dict(date_time=now_pretty()))
|
|
98
|
-
|
|
99
|
-
@property
|
|
100
|
-
def is_ai(self):
|
|
101
|
-
return self.role
|
|
102
|
-
|
|
103
|
-
@property
|
|
104
|
-
def is_human(self):
|
|
105
|
-
return not self.role
|
|
106
|
-
|
|
107
|
-
def modify_text(self, callback: Callable[[str], str]) -> "ReplicaItem":
|
|
108
|
-
body_upd = callback(self.body)
|
|
109
|
-
return self.model_copy(update=dict(body=body_upd))
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
class InnerContextItem(Base):
|
|
113
|
-
replicas: list[ReplicaItem] = Field(alias="Replicas")
|
|
114
|
-
attrs: dict[str, str | int] | None = Field(default={}, alias="Attrs")
|
|
115
|
-
|
|
116
|
-
def to_dict(self) -> dict[str, list]:
|
|
117
|
-
return self.model_dump(by_alias=True)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
class ChatItem(Base):
|
|
121
|
-
outer_context: OuterContextItem = Field(alias="OuterContext")
|
|
122
|
-
inner_context: InnerContextItem = Field(alias="InnerContext")
|
|
123
|
-
|
|
124
|
-
def create_id(self, short: bool = False) -> str:
|
|
125
|
-
return self.outer_context.create_id(short)
|
|
126
|
-
|
|
127
|
-
def to_dict(self) -> dict[str, Any]:
|
|
128
|
-
return self.model_dump(by_alias=True)
|
|
129
|
-
|
|
130
|
-
def add_replica(self, replica: ReplicaItem):
|
|
131
|
-
self.inner_context.replicas.append(replica)
|
|
132
|
-
|
|
133
|
-
def add_replicas(self, replicas: list[ReplicaItem]):
|
|
134
|
-
for replica in replicas:
|
|
135
|
-
self.inner_context.replicas.append(replica)
|
|
136
|
-
|
|
137
|
-
def replace_replicas(self, replicas: list[ReplicaItem]):
|
|
138
|
-
return self.model_copy(update=dict(inner_context=InnerContextItem(replicas=replicas)))
|
|
139
|
-
|
|
140
|
-
def get_last_state(self, default: str = "empty") -> str:
|
|
141
|
-
replicas = self.inner_context.replicas
|
|
142
|
-
for ii in range(len(replicas) - 1, -1, -1):
|
|
143
|
-
replica = replicas[ii]
|
|
144
|
-
if replica.role:
|
|
145
|
-
return replica.state
|
|
146
|
-
return default
|
|
147
|
-
|
|
148
|
-
def zip_history(self, field: str) -> list[Any]:
|
|
149
|
-
return [replica.to_dict().get(field, None) for replica in self.inner_context.replicas]
|
|
150
|
-
|
|
151
|
-
@classmethod
|
|
152
|
-
def parse(cls, chat_obj: str | dict) -> "ChatItem":
|
|
153
|
-
return _parse_chat_item(chat_obj)
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
def _parse_chat_item(chat_obj: str | dict) -> ChatItem:
|
|
157
|
-
if isinstance(chat_obj, dict):
|
|
158
|
-
return ChatItem.model_validate(chat_obj)
|
|
159
|
-
|
|
160
|
-
return ChatItem.model_validate_json(chat_obj)
|
|
File without changes
|
|
File without changes
|