Skip to content

Commit

Permalink
Add some documentation about integrating jupyterlab-collaborative-chat
Browse files Browse the repository at this point in the history
  • Loading branch information
brichet committed Aug 8, 2024
1 parent 6f17be5 commit 93c7522
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 11 deletions.
2 changes: 1 addition & 1 deletion docs/source/developers/contributing/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Contributing

This project is part of *jupyterlab* organization.
This project is included in *jupyterlab* organization.

Before contributing to it, please read the [jupyter contributing guide](https://docs.jupyter.org/en/latest/contributing/content-contributor.html).

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# jupyterlab-collaborative-chat
# Collaborative chat

The `jupyterlab-collaborative-chat` extension adds collaborative chats to jupyterlab.

Expand Down
2 changes: 1 addition & 1 deletion docs/source/developers/contributing/jupyterlab-ws-chat.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# jupyterlab-collaborative-chat
# Websocket chat

The `jupyterlab-ws-chat` extension adds a chat panel relying on websocket for messaging.

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,8 @@ const myChatExtension: JupyterFrontEndPlugin<void> = {
};
```

(autocompletion-registry)=

### autocompletionRegistry

The `autocompletionRegistry` adds autocompletion feature to the chat input. This can be
Expand Down
6 changes: 3 additions & 3 deletions docs/source/developers/developing_extensions/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

Other extensions can depends on one or the other of the packages.

This section describe how an extension can provide a chat, and how an extension can
extend the features of a chat extension.
This section describe how an extension can provide a chat, and how to make use of one
of the chat extensions in another extension.

```{toctree}
---
maxdepth: 2
---
./extension-providing-chat
./extending-extension
./using-chat-extensions
```
152 changes: 152 additions & 0 deletions docs/source/developers/developing_extensions/using-chat-extensions.md
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
})

```
2 changes: 1 addition & 1 deletion docs/source/developers/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This section is addressed to developers, and contains documentation about:

- how to develop an extension providing a chat or extending a chat extension
- how to develop an extension providing a chat or to include a chat extension
- how to contribute to this project

```{toctree}
Expand Down
6 changes: 3 additions & 3 deletions docs/source/users/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Users

## jupyterlab-collaborative-chat
## Collaborative chat

The `jupyterlab-collaborative-chat` extension adds collaborative chats to jupyterlab.

Expand Down Expand Up @@ -61,7 +61,7 @@ area, like any other document.
Opening a chat from the left panel will open it in the left panel.
```

## jupyterlab-ws-chat
## Websocket chat

The `jupyterlab-ws-chat` extension adds a chat panel relying on websocket for messaging.

Expand All @@ -87,7 +87,7 @@ pip uninstall jupyterlab-ws-chat

The chat can be opened from the left panel ![chat icon](../../../packages/jupyter-chat/style/icons/chat.svg){w=24px}.

## Using the chat
## Chat usage

The chat UI is composed of a list of messages and an input to send new messages.

Expand Down

0 comments on commit 93c7522

Please sign in to comment.