-
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add some documentation about integrating jupyterlab-collaborative-chat
- Loading branch information
Showing
9 changed files
with
164 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
docs/source/developers/contributing/jupyterlab-collaborative-chat.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 0 additions & 1 deletion
1
docs/source/developers/developing_extensions/extending-extension.md
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
152 changes: 152 additions & 0 deletions
152
docs/source/developers/developing_extensions/using-chat-extensions.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
# Using a chat extension in another extension | ||
|
||
## Collaborative chat | ||
|
||
The collaborative chat depends on [jupyter collaboration](https://jupyterlab-realtime-collaboration.readthedocs.io/en/latest/index.html) | ||
to exchange the messages. | ||
|
||
As a very brief summary, jupyter collaboration allows jupyterlab users to share a | ||
document in real time, based on [CRDT](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type). | ||
All changes made to the document are propagated to all users. These change can occur | ||
from the frontend or from the backend. The shared document has an object representation | ||
in Typescript (for the frontend) and in Python (for the backend). These representation | ||
can be accessed and used by external extensions. | ||
|
||
### Exposed token | ||
|
||
`jupyterlab-collaborative-chat` expose several token that allow external extension to | ||
interact with. | ||
|
||
#### IChatFactory | ||
|
||
This token is composed of: | ||
|
||
- `widgetConfig` object, to retrieve and change the current [settings](#chat-settings) | ||
of all the chats | ||
- `tracker`, a widget tracker that allow to track all the collaborative chats, and to | ||
get the current one. | ||
|
||
```{caution} | ||
Currently the widget tracker only track the main area widgets, not the one opened in the | ||
side panel. | ||
``` | ||
|
||
#### IChatPanel | ||
|
||
This token is a pointer to the left panel containing chats.\ | ||
It can be useful to programmatically open chat in the panel for example, or to list the | ||
opened chats. | ||
|
||
#### IAutocompletionRegistry | ||
|
||
this is the [autocompletion registry](#autocompletion-registry) used by the chat widgets. | ||
|
||
Autocompletion commands can be added to it, and than usable from the chat widget. | ||
|
||
### Interact with the chat from the backend | ||
|
||
`jupyter_collaboration` provides a websocket server to handle every shared document | ||
server side. This server can be used in an extension to retrieve a shared document. | ||
|
||
In addition, when a shared document is created, an event is emitted. We can use that | ||
event data to trigger a connection to the shared document. | ||
|
||
Below is an example of an server extension that respond every message written to any | ||
collaborative chat: | ||
|
||
```python | ||
import jupyter_collaboration | ||
import time | ||
import uuid | ||
from functools import partial | ||
from jupyter_collaboration.utils import JUPYTER_COLLABORATION_EVENTS_URI | ||
from jupyter_events import EventLogger | ||
from jupyter_server.extension.application import ExtensionApp | ||
from pycrdt import ArrayEvent | ||
|
||
from .ychat import YChat | ||
|
||
|
||
if int(jupyter_collaboration.__version__[0]) >= 3: | ||
COLLAB_VERSION = 3 | ||
else: | ||
COLLAB_VERSION = 2 | ||
|
||
BOT = { | ||
"username": str(uuid.uuid4()), | ||
"name": "user", | ||
"display_name": "User" | ||
} | ||
|
||
|
||
class MyExtension(ExtensionApp): | ||
name = "my_extension" | ||
app_name = "My Extension" | ||
description = """ | ||
this extension interact with collaborative chats | ||
""" | ||
|
||
def initialize(self): | ||
super().initialize() | ||
self.event_logger = self.serverapp.web_app.settings["event_logger"] | ||
self.event_logger.add_listener( | ||
schema_id=JUPYTER_COLLABORATION_EVENTS_URI, | ||
listener=self.connect_chat | ||
) | ||
|
||
async def connect_chat(self, logger: EventLogger, schema_id: str, data: dict) -> None: | ||
if data["room"].startswith("text:chat:") \ | ||
and data["action"] == "initialize"\ | ||
and data["msg"] == "Room initialized": | ||
|
||
self.log.info(f"Collaborative chat server is listening for {data["room"]}") | ||
chat = await self.get_chat(data["room"]) | ||
callback = partial(self.on_change, chat) | ||
chat.ymessages.observe(callback) | ||
|
||
async def get_chat(self, room_id: str) -> YChat: | ||
if COLLAB_VERSION == 3: | ||
collaboration = self.serverapp.web_app.settings["jupyter_server_ydoc"] | ||
document = await collaboration.get_document( | ||
room_id=room_id, | ||
copy=False | ||
) | ||
else: | ||
collaboration = self.serverapp.web_app.settings["jupyter_collaboration"] | ||
server = collaboration.ywebsocket_server | ||
|
||
room = await server.get_room(room_id) | ||
document = room._document | ||
return document | ||
|
||
def on_change(self, chat: YChat, events: ArrayEvent) -> None: | ||
for change in events.delta: | ||
if not "insert" in change.keys(): | ||
continue | ||
messages = change["insert"] | ||
for message in messages: | ||
if message["sender"] == BOT["username"] or message["raw_time"]: | ||
continue | ||
chat.create_task( | ||
self.write_message( | ||
chat, | ||
f"Received:\n\n- **id**: *{message["id"]}*:\n\n- **body**: *{message["body"]}*") | ||
) | ||
|
||
async def write_message(self, chat: YChat, body: str) -> None: | ||
bot = chat.get_user_by_name(BOT["name"]) | ||
if not bot: | ||
chat.set_user(BOT) | ||
else: | ||
BOT["username"] = bot["username"] | ||
|
||
chat.add_message({ | ||
"type": "msg", | ||
"body": body, | ||
"id": str(uuid.uuid4()), | ||
"time": time.time(), | ||
"sender": BOT["username"], | ||
"raw_time": False | ||
}) | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters