agi-med-common 5.2.1__tar.gz → 5.2.3__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.
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/PKG-INFO +1 -1
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/src/agi_med_common/__init__.py +1 -1
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/src/agi_med_common/api.py +5 -7
- agi_med_common-5.2.3/src/agi_med_common/file_storage.py +113 -0
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/src/agi_med_common/models/chat.py +7 -6
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/src/agi_med_common/models/chat_item.py +4 -3
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/src/agi_med_common/models/widget.py +3 -3
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/src/agi_med_common/parallel_map.py +3 -1
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/src/agi_med_common/utils.py +2 -2
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/src/agi_med_common.egg-info/PKG-INFO +1 -1
- agi_med_common-5.2.1/src/agi_med_common/file_storage.py +0 -63
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/README.md +0 -0
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/pyproject.toml +0 -0
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/setup.cfg +0 -0
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/src/agi_med_common/models/__init__.py +0 -0
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/src/agi_med_common/models/base.py +0 -0
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/src/agi_med_common/models/base_config_models/__init__.py +0 -0
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/src/agi_med_common/models/base_config_models/gigachat_config.py +0 -0
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/src/agi_med_common/models/enums.py +0 -0
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/src/agi_med_common/models/tracks.py +0 -0
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/src/agi_med_common/type_union.py +0 -0
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/src/agi_med_common/validators.py +0 -0
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/src/agi_med_common/xml_parser.py +0 -0
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/src/agi_med_common.egg-info/SOURCES.txt +0 -0
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/src/agi_med_common.egg-info/dependency_links.txt +0 -0
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/src/agi_med_common.egg-info/requires.txt +0 -0
- {agi_med_common-5.2.1 → agi_med_common-5.2.3}/src/agi_med_common.egg-info/top_level.txt +0 -0
@@ -1,5 +1,3 @@
|
|
1
|
-
from typing import List, Tuple
|
2
|
-
|
3
1
|
from agi_med_common.models.chat import Chat, ChatMessage
|
4
2
|
from agi_med_common.models.tracks import DomainInfo, TrackInfo
|
5
3
|
from pydantic import BaseModel
|
@@ -11,13 +9,13 @@ ResourceId = str
|
|
11
9
|
|
12
10
|
|
13
11
|
class ChatManagerAPI:
|
14
|
-
def get_domains(self, *, client_id: str, language_code: str = "ru") ->
|
12
|
+
def get_domains(self, *, client_id: str, language_code: str = "ru") -> list[DomainInfo]:
|
15
13
|
raise NotImplementedError
|
16
14
|
|
17
|
-
def get_tracks(self, *, client_id: str, language_code: str = "ru") ->
|
15
|
+
def get_tracks(self, *, client_id: str, language_code: str = "ru") -> list[TrackInfo]:
|
18
16
|
raise NotImplementedError
|
19
17
|
|
20
|
-
def get_response(self, *, chat: Chat) ->
|
18
|
+
def get_response(self, *, chat: Chat) -> list[ChatMessage]:
|
21
19
|
raise NotImplementedError
|
22
20
|
|
23
21
|
|
@@ -40,7 +38,7 @@ class ContentInterpreterRemoteAPI:
|
|
40
38
|
|
41
39
|
|
42
40
|
class ClassifierAPI:
|
43
|
-
def get_values(self) ->
|
41
|
+
def get_values(self) -> list[Value]:
|
44
42
|
raise NotImplementedError
|
45
43
|
|
46
44
|
def evaluate(self, *, chat: Chat) -> Value:
|
@@ -55,7 +53,7 @@ class CriticAPI:
|
|
55
53
|
class ContentInterpreterAPI:
|
56
54
|
def interpret(
|
57
55
|
self, *, kind: str, query: str, resource_id: str = "", chat: Chat | None = None
|
58
|
-
) ->
|
56
|
+
) -> tuple[Interpretation, ResourceId | None]:
|
59
57
|
raise NotImplementedError
|
60
58
|
|
61
59
|
|
@@ -0,0 +1,113 @@
|
|
1
|
+
import string
|
2
|
+
from hashlib import md5
|
3
|
+
from pathlib import Path
|
4
|
+
from zipfile import ZipFile, is_zipfile
|
5
|
+
|
6
|
+
|
7
|
+
ResourceId = str
|
8
|
+
ASCII_DIGITS = set(string.ascii_lowercase + string.digits)
|
9
|
+
SUFFIX_DIR = ".dir"
|
10
|
+
|
11
|
+
|
12
|
+
def _validate_exist(files_dir):
|
13
|
+
if not files_dir.exists():
|
14
|
+
err = f"Failed to access file-storage directory: {files_dir}"
|
15
|
+
raise OSError(err)
|
16
|
+
|
17
|
+
|
18
|
+
def _validate_dtype(dtype: str):
|
19
|
+
if all(map(ASCII_DIGITS.__contains__, dtype)):
|
20
|
+
return
|
21
|
+
raise ValueError(f"Bad dtype: {dtype}")
|
22
|
+
|
23
|
+
|
24
|
+
def generate_fname(content, dtype):
|
25
|
+
fname_hash = md5(content).hexdigest()
|
26
|
+
fname = f"{fname_hash}.{dtype}"
|
27
|
+
return fname
|
28
|
+
|
29
|
+
|
30
|
+
class FileStorage:
|
31
|
+
def __init__(self, files_dir):
|
32
|
+
self.files_dir = Path(files_dir)
|
33
|
+
self.files_dir.mkdir(exist_ok=True, parents=True)
|
34
|
+
_validate_exist(self.files_dir)
|
35
|
+
|
36
|
+
def _generate_fname_path(self, content: bytes, dtype: str):
|
37
|
+
fpath = self.files_dir / generate_fname(content, dtype)
|
38
|
+
return fpath
|
39
|
+
|
40
|
+
def upload_maybe(self, content: bytes | None, dtype: str) -> ResourceId | None:
|
41
|
+
if not content:
|
42
|
+
return None
|
43
|
+
resource_id = self.upload(content, dtype)
|
44
|
+
return resource_id
|
45
|
+
|
46
|
+
def upload(self, content: bytes | str, dtype: str) -> ResourceId:
|
47
|
+
_validate_dtype(dtype)
|
48
|
+
if isinstance(content, str):
|
49
|
+
content = content.encode()
|
50
|
+
fpath = self._generate_fname_path(content, dtype)
|
51
|
+
fpath.write_bytes(content)
|
52
|
+
return str(fpath)
|
53
|
+
|
54
|
+
def upload_dir(self, resource_ids: list[ResourceId]) -> ResourceId:
|
55
|
+
content = "\n".join(resource_ids)
|
56
|
+
res = self.upload(content, "dir")
|
57
|
+
return res
|
58
|
+
|
59
|
+
def download(self, resource_id: ResourceId) -> bytes:
|
60
|
+
return Path(resource_id).read_bytes()
|
61
|
+
|
62
|
+
def download_text(self, resource_id: ResourceId) -> str:
|
63
|
+
return Path(resource_id).read_text(encoding="utf-8")
|
64
|
+
|
65
|
+
def read_dir_or_none(self, resource_id: ResourceId) -> list[ResourceId] | None:
|
66
|
+
if not self.is_dir(resource_id):
|
67
|
+
return None
|
68
|
+
res = self.download_text(resource_id).split("\n")
|
69
|
+
return res
|
70
|
+
|
71
|
+
def _get_path(self, resource_id: ResourceId | None) -> Path | None:
|
72
|
+
if not resource_id:
|
73
|
+
return None
|
74
|
+
path = Path(resource_id)
|
75
|
+
return path if (path.exists() and path.is_file()) else None
|
76
|
+
|
77
|
+
def is_valid(self, resource_id: ResourceId | None) -> bool:
|
78
|
+
path = self._get_path(resource_id)
|
79
|
+
return path is not None
|
80
|
+
|
81
|
+
def is_file(self, resource_id: ResourceId | None) -> bool:
|
82
|
+
path = self._get_path(resource_id)
|
83
|
+
return path and path.suffix != SUFFIX_DIR
|
84
|
+
|
85
|
+
def is_dir(self, resource_id: ResourceId | None) -> bool:
|
86
|
+
path = self._get_path(resource_id)
|
87
|
+
return path and path.suffix == SUFFIX_DIR
|
88
|
+
|
89
|
+
def get_dtype(self, resource_id: ResourceId | None) -> str | None:
|
90
|
+
return resource_id and resource_id.rsplit(".")[-1]
|
91
|
+
|
92
|
+
def unzip_file(self, resource_id: str) -> ResourceId:
|
93
|
+
""" takes resource_id which refer to zip-archive, unpacks it and returns directory ResourceId with content of zip-archive """
|
94
|
+
path = self._get_path(resource_id)
|
95
|
+
if not path:
|
96
|
+
raise ValueError(f"Not found path: {resource_id}")
|
97
|
+
if not is_zipfile(resource_id):
|
98
|
+
raise ValueError(f"Expected zip archive but found: {resource_id}")
|
99
|
+
|
100
|
+
resource_ids = []
|
101
|
+
|
102
|
+
with ZipFile(path, mode='r') as zip_file:
|
103
|
+
files_info = zip_file.filelist
|
104
|
+
|
105
|
+
for file_info in zip_file.filelist:
|
106
|
+
file_dtype = file_info.filename.rsplit('.')[-1]
|
107
|
+
file_bytes = zip_file.read(file_info)
|
108
|
+
rid = self.upload(file_bytes, file_dtype)
|
109
|
+
resource_ids.append(rid)
|
110
|
+
|
111
|
+
res = self.upload_dir(resource_ids)
|
112
|
+
return res
|
113
|
+
|
@@ -1,7 +1,8 @@
|
|
1
1
|
import warnings
|
2
2
|
from copy import deepcopy
|
3
3
|
from datetime import datetime
|
4
|
-
from typing import Any,
|
4
|
+
from typing import Any, Literal, TypeVar
|
5
|
+
from collections.abc import Callable
|
5
6
|
|
6
7
|
from agi_med_common.models.chat_item import ChatItem, ReplicaItem, OuterContextItem
|
7
8
|
from agi_med_common.models.widget import Widget
|
@@ -14,9 +15,9 @@ from .base import Base
|
|
14
15
|
|
15
16
|
_DT_FORMAT: str = "%Y-%m-%d-%H-%M-%S"
|
16
17
|
_EXAMPLE_DT: str = datetime(year=1970, month=1, day=1).strftime(_DT_FORMAT)
|
17
|
-
StrDict =
|
18
|
+
StrDict = dict[str, Any]
|
18
19
|
ContentBase = str | Widget | StrDict
|
19
|
-
Content = ContentBase |
|
20
|
+
Content = ContentBase | list[ContentBase]
|
20
21
|
T = TypeVar("T")
|
21
22
|
|
22
23
|
|
@@ -184,7 +185,7 @@ ChatMessage = TypeUnion[HumanMessage, AIMessage, MiscMessage]
|
|
184
185
|
|
185
186
|
class Chat(Base):
|
186
187
|
context: Context = Field(default_factory=Context)
|
187
|
-
messages:
|
188
|
+
messages: list[ChatMessage] = Field(default_factory=list)
|
188
189
|
|
189
190
|
class Config:
|
190
191
|
extra = Extra.ignore
|
@@ -208,11 +209,11 @@ class Chat(Base):
|
|
208
209
|
def add_message(self, message: ChatMessage):
|
209
210
|
self.messages.append(message)
|
210
211
|
|
211
|
-
def add_messages(self, messages:
|
212
|
+
def add_messages(self, messages: list[ChatMessage]):
|
212
213
|
for message in messages:
|
213
214
|
self.messages.append(message)
|
214
215
|
|
215
|
-
def replace_messages(self, messages:
|
216
|
+
def replace_messages(self, messages: list[ChatMessage]):
|
216
217
|
return self.model_copy(update=dict(messages=messages))
|
217
218
|
|
218
219
|
def get_last_state(self, default: str = "empty") -> str:
|
@@ -1,5 +1,6 @@
|
|
1
1
|
from datetime import datetime
|
2
|
-
from typing import Annotated, Any
|
2
|
+
from typing import Annotated, Any
|
3
|
+
from collections.abc import Callable
|
3
4
|
|
4
5
|
from agi_med_common.models.widget import Widget
|
5
6
|
from pydantic import Field, ConfigDict, BeforeValidator, AfterValidator
|
@@ -126,11 +127,11 @@ class ChatItem(Base):
|
|
126
127
|
def add_replica(self, replica: ReplicaItem):
|
127
128
|
self.inner_context.replicas.append(replica)
|
128
129
|
|
129
|
-
def add_replicas(self, replicas:
|
130
|
+
def add_replicas(self, replicas: list[ReplicaItem]):
|
130
131
|
for replica in replicas:
|
131
132
|
self.inner_context.replicas.append(replica)
|
132
133
|
|
133
|
-
def replace_replicas(self, replicas:
|
134
|
+
def replace_replicas(self, replicas: list[ReplicaItem]):
|
134
135
|
return self.model_copy(update=dict(inner_context=InnerContextItem(replicas=replicas)))
|
135
136
|
|
136
137
|
def get_last_state(self, default: str = "empty") -> str:
|
@@ -1,12 +1,12 @@
|
|
1
|
-
from typing import
|
1
|
+
from typing import Self, Literal
|
2
2
|
|
3
3
|
from pydantic import BaseModel, model_validator
|
4
4
|
|
5
5
|
|
6
6
|
class Widget(BaseModel):
|
7
7
|
type: Literal["widget"] = "widget"
|
8
|
-
buttons:
|
9
|
-
ibuttons:
|
8
|
+
buttons: list[list[str]] | None = None
|
9
|
+
ibuttons: list[list[str]] | None = None
|
10
10
|
|
11
11
|
@model_validator(mode="after")
|
12
12
|
def check(self) -> Self:
|
@@ -1,13 +1,13 @@
|
|
1
1
|
import codecs
|
2
2
|
import json
|
3
3
|
import os
|
4
|
+
from collections.abc import Iterable
|
4
5
|
from datetime import datetime
|
5
6
|
from pathlib import Path
|
6
|
-
from typing import Iterable
|
7
7
|
|
8
8
|
|
9
9
|
def make_session_id() -> str:
|
10
|
-
return f"{datetime.now():%
|
10
|
+
return f"{datetime.now():%Y-%m-%d--%H-%M-%S}"
|
11
11
|
|
12
12
|
|
13
13
|
def read_json(path: Path | os.PathLike[str] | str) -> list | dict:
|
@@ -1,63 +0,0 @@
|
|
1
|
-
import string
|
2
|
-
from hashlib import md5
|
3
|
-
from pathlib import Path
|
4
|
-
|
5
|
-
ResourceId = str
|
6
|
-
ASCII_DIGITS = set(string.ascii_lowercase + string.digits)
|
7
|
-
|
8
|
-
|
9
|
-
def _validate_exist(files_dir):
|
10
|
-
if not files_dir.exists():
|
11
|
-
err = f"Failed to access file-storage directory: {files_dir}"
|
12
|
-
raise OSError(err)
|
13
|
-
|
14
|
-
|
15
|
-
def _validate_dtype(dtype: str):
|
16
|
-
if all(map(ASCII_DIGITS.__contains__, dtype)):
|
17
|
-
return
|
18
|
-
raise ValueError(f"Bad dtype: {dtype}")
|
19
|
-
|
20
|
-
|
21
|
-
def generate_fname(content, dtype):
|
22
|
-
fname_hash = md5(content).hexdigest()
|
23
|
-
fname = f"{fname_hash}.{dtype}"
|
24
|
-
return fname
|
25
|
-
|
26
|
-
|
27
|
-
class FileStorage:
|
28
|
-
def __init__(self, files_dir):
|
29
|
-
self.files_dir = Path(files_dir)
|
30
|
-
self.files_dir.mkdir(exist_ok=True, parents=True)
|
31
|
-
_validate_exist(self.files_dir)
|
32
|
-
|
33
|
-
def _generate_fname_path(self, content, dtype):
|
34
|
-
fpath = self.files_dir / generate_fname(content, dtype)
|
35
|
-
return fpath
|
36
|
-
|
37
|
-
def upload_maybe(
|
38
|
-
self,
|
39
|
-
content: bytes | None,
|
40
|
-
dtype: str,
|
41
|
-
) -> ResourceId | None:
|
42
|
-
if not content:
|
43
|
-
return None
|
44
|
-
resource_id = self.upload(content, dtype)
|
45
|
-
return resource_id
|
46
|
-
|
47
|
-
def upload(self, content: bytes, dtype: str) -> ResourceId | None:
|
48
|
-
_validate_dtype(dtype)
|
49
|
-
fpath = self._generate_fname_path(content, dtype)
|
50
|
-
fpath.write_bytes(content)
|
51
|
-
return str(fpath)
|
52
|
-
|
53
|
-
def download(self, rid: ResourceId) -> bytes:
|
54
|
-
return Path(rid).read_bytes()
|
55
|
-
|
56
|
-
def download_text(self, rid: ResourceId) -> str:
|
57
|
-
return Path(rid).read_text(encoding="utf-8")
|
58
|
-
|
59
|
-
def is_valid(self, rid: ResourceId | None) -> bool:
|
60
|
-
return rid and Path(rid).exists() and Path(rid).is_file()
|
61
|
-
|
62
|
-
def get_dtype(self, rid: ResourceId | None) -> str | None:
|
63
|
-
return rid and rid.rsplit(".")[-1]
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{agi_med_common-5.2.1 → agi_med_common-5.2.3}/src/agi_med_common.egg-info/dependency_links.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|