Skip to content

Commit fe37f7d

Browse files
authored
Improve ychat class on server side (#69)
* Add some chat manipulation functions to ychat class in python * Add metadata functions
1 parent 8b38ad0 commit fe37f7d

File tree

2 files changed

+76
-27
lines changed
  • packages
    • jupyterlab-collaborative-chat/jupyterlab_collaborative_chat
    • jupyterlab-ws-chat/jupyterlab_ws_chat

2 files changed

+76
-27
lines changed

packages/jupyterlab-collaborative-chat/jupyterlab_collaborative_chat/ychat.py

Lines changed: 73 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@
77
import time
88
import asyncio
99
from functools import partial
10-
from typing import Any, Callable, Dict, List, Set
11-
from uuid import uuid4
12-
1310
from jupyter_ydoc.ybasedoc import YBaseDoc
11+
from typing import Any, Callable, Set
12+
from uuid import uuid4
1413
from pycrdt import Array, ArrayEvent, Map, MapEvent
1514

1615

@@ -42,40 +41,91 @@ def create_task(self, coro):
4241
task.add_done_callback(self._background_tasks.discard)
4342

4443
@property
45-
def messages(self) -> List:
46-
return self._ymessages.to_py()
44+
def ymessages(self) -> Array:
45+
return self._ymessages
4746

4847
@property
49-
def users(self) -> Map:
50-
return self._yusers.to_py()
48+
def yusers(self) -> Map:
49+
return self._yusers
5150

5251
@property
53-
def metadata(self) -> Map:
54-
return self._ymetadata.to_py()
52+
def ymetadata(self) -> Map:
53+
return self._ymetadata
54+
55+
def get_user(self, username: str) -> dict[str, str] | None:
56+
"""
57+
Returns a message from its id, or None
58+
"""
59+
return self.get_users().get(username, None)
5560

56-
def get_users(self) -> Dict:
61+
def get_user_by_name(self, name: str) -> dict[str, str] | None:
62+
"""
63+
Returns a user from its name property, or None.
64+
"""
65+
return next(
66+
(user for user in self.get_users().values() if user["name"] == name),
67+
None
68+
)
69+
70+
def get_users(self) -> dict[str, dict[str, str]]:
5771
"""
5872
Returns the users of the document.
5973
:return: Document's users.
60-
:rtype: string
6174
"""
75+
return self._yusers.to_py()
76+
77+
def set_user(self, user: dict[str, str]) -> None:
78+
"""
79+
Adds or modifies a user.
80+
"""
81+
with self._ydoc.transaction():
82+
self._yusers.update({user["username"]: user})
6283

63-
users = self._yusers.to_py()
64-
return dict(users=users)
84+
def get_message(self, id: str) -> dict | None:
85+
"""
86+
Returns a message from its id, or None
87+
"""
88+
return next(
89+
(msg for msg in self.get_messages() if msg["id"] == id),
90+
None
91+
)
6592

66-
def get_messages(self) -> Dict:
93+
def get_messages(self) -> list[dict]:
6794
"""
6895
Returns the messages of the document.
6996
:return: Document's messages.
70-
:rtype: string
7197
"""
98+
return self._ymessages.to_py()
99+
100+
def add_message(self, message: dict) -> None:
101+
"""
102+
Appends a message to the document.
103+
"""
104+
with self._ydoc.transaction():
105+
self._ymessages.append(message)
106+
107+
def get_single_metadata(self, name) -> dict:
108+
"""
109+
Return a single metadata.
110+
"""
111+
return self.get_metadata().get(name, {})
72112

73-
messages = self._ymessages.to_py()
74-
return dict(messages=messages)
113+
def get_metadata(self) -> dict[str, dict]:
114+
"""
115+
Returns the metadata of the document.
116+
"""
117+
return self._ymetadata.to_py()
118+
119+
def set_metadata(self, name: str, metadata: dict):
120+
"""
121+
Adds or modifies a metadata of the document.
122+
"""
123+
with self._ydoc.transaction():
124+
self._ymetadata.update({name: metadata})
75125

76126
async def create_id(self) -> str:
77127
"""
78-
Create a new ID for the document.
128+
Creates a new ID for the document.
79129
"""
80130
id = str(uuid4())
81131
self.set_id(id)
@@ -97,13 +147,12 @@ def set_id(self, id: str) -> None:
97147
def get(self) -> str:
98148
"""
99149
Returns the contents of the document.
100-
:return: Document's contents.
101-
:rtype: string
150+
:return: Document's contents in JSON.
102151
"""
103152
return json.dumps({
104-
"messages": self.messages,
105-
"users": self.users,
106-
"metadata": self.metadata
153+
"messages": self.get_messages(),
154+
"users": self.get_users(),
155+
"metadata": self.get_metadata()
107156
})
108157

109158
def set(self, value: str) -> None:
@@ -209,7 +258,7 @@ async def _set_timestamp(self, msg_idx: int, timestamp: float):
209258
# should be the last one.
210259
# The next() function below return the index of the first message with a timestamp inferior of the
211260
# current one, starting from the end of the list.
212-
new_idx = len(self._ymessages) - next((i for i, v in enumerate(self._ymessages.to_py()[::-1]) if v["time"] < timestamp), len(self._ymessages))
261+
new_idx = len(self._ymessages) - next((i for i, v in enumerate(self.get_messages()[::-1]) if v["time"] < timestamp), len(self._ymessages))
213262
if msg_idx != new_idx:
214263
message = self._ymessages.pop(msg_idx)
215264
self._ymessages.insert(new_idx, message)

packages/jupyterlab-ws-chat/jupyterlab_ws_chat/models.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# Copyright (c) Jupyter Development Team.
22
# Distributed under the terms of the Modified BSD License.
33

4-
from typing import Any, Dict, List, Literal, Optional, Union
5-
64
from pydantic.v1 import BaseModel, validator
5+
from typing import Literal, Optional, Union
6+
77

88
DEFAULT_CHUNK_SIZE = 2000
99
DEFAULT_CHUNK_OVERLAP = 100
@@ -55,7 +55,7 @@ class ClearMessage(BaseModel):
5555
class ChatHistory(BaseModel):
5656
"""History of chat messages"""
5757

58-
messages: List[ChatMessage]
58+
messages: list[ChatMessage]
5959

6060

6161
class DescribeConfigResponse(BaseModel):

0 commit comments

Comments
 (0)