Last active
April 15, 2019 11:45
-
-
Save deeplook/8cf23a0b895b653005d872a657e29096 to your computer and use it in GitHub Desktop.
A very simple multi-party chat ipywidget.
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
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# IPyChat" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"from ipywidgets import VBox, HBox, Textarea, Text, Layout, HTML" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"class IPyChat:\n", | |
" \"\"\"\n", | |
" A very simple multi-party chat ipywidget.\n", | |
" \n", | |
" At the moment this allows for chats between multiple instances of this\n", | |
" class running in the same process. The \"first\" instance becomes the main\n", | |
" participant, or host, or hub, and accepts other participants and manages\n", | |
" the communication between them in a star shape.\n", | |
" \n", | |
" Sadly, ipywidget.Textarea cannot be scrolled up automatically when it fills\n", | |
" up... :( see::\n", | |
" \n", | |
" https://github.com/jupyter-widgets/ipywidgets/issues/1815#issuecomment-480788783\n", | |
"\n", | |
" Clearly, a better version could use some IPC via ZMQ where all participents\n", | |
" publish and subscribe to all without a centralized component needed (all\n", | |
" contributions welcome!).\n", | |
" \"\"\"\n", | |
" def __init__(self, server=None, name=None):\n", | |
" \"\"\"Create a chat instance.\n", | |
" \n", | |
" :param server: an object representing the central server to connect to\n", | |
" as a client\n", | |
" :param name: a string used to easily between different chat participants\n", | |
"\n", | |
" When no ``server`` is specified this instnace becomes the chat host\n", | |
" and maintains a list of clients. Otherwise it becomes a client and\n", | |
" regards the given server as its host.\n", | |
" \"\"\"\n", | |
" self.name = name or id(self)\n", | |
" self.clients = []\n", | |
" self.server = server\n", | |
" if self.server:\n", | |
" self.server.add_client(self) \n", | |
" self.build_ui()\n", | |
"\n", | |
" def build_ui(self):\n", | |
" \"\"\"Build UI widgets to be rendered later.\"\"\"\n", | |
" title = f'<strong>IPyChat</strong> ({self.name})'\n", | |
" self.title_ht = HTML(title)\n", | |
" self.history_ta = Textarea(layout=Layout(height='100px'))\n", | |
" self.history_ta.disbaled = True\n", | |
" self.message_tx = Text(layout=Layout())\n", | |
" self.message_tx.on_submit(self.submitted_cb)\n", | |
" self.ui = VBox([\n", | |
" self.title_ht,\n", | |
" self.history_ta,\n", | |
" self.message_tx,\n", | |
" ])\n", | |
"\n", | |
" def add_client(self, client):\n", | |
" \"\"\"As a server, add client to our list of clients.\"\"\"\n", | |
" if not self.server:\n", | |
" self.clients.append(client)\n", | |
" \n", | |
" def append_message(self, text, sender):\n", | |
" \"\"\"Append a message from some sender to our history widget.\"\"\"\n", | |
" if not self.server:\n", | |
" # we're a server/host\n", | |
" if sender == self:\n", | |
" self.history_ta.value += f'{sender.name}: {text}\\n'\n", | |
" else:\n", | |
" self.history_ta.value += f'{sender.name}: {text}\\n'\n", | |
" for client in self.clients:\n", | |
" if client != self:\n", | |
" client.history_ta.value += f'{sender.name}: {text}\\n' \n", | |
" else:\n", | |
" # we're a client\n", | |
" self.server.append_message(text, self)\n", | |
" \n", | |
" def submitted_cb(self, sender):\n", | |
" \"When sender was submitted, pick text from input line and 'send' it.\"\n", | |
" text = self.message_tx.value\n", | |
" self.append_message(text, sender=self)\n", | |
" self.message_tx.value = ''" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"application/vnd.jupyter.widget-view+json": { | |
"model_id": "227093aa1d9f4717b91b680cdd061a8c", | |
"version_major": 2, | |
"version_minor": 0 | |
}, | |
"text/plain": [ | |
"VBox(children=(HTML(value='<strong>IPyChat</strong> (Test)'), Textarea(value='', layout=Layout(height='100px')…" | |
] | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"IPyChat(name='Test').ui" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 6, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"host = IPyChat(name='Admin')\n", | |
"client1 = IPyChat(server=host, name='Alice')\n", | |
"client2 = IPyChat(server=host, name='Bob')" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 7, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"application/vnd.jupyter.widget-view+json": { | |
"model_id": "397442546e694ac7a74b32ca966f1845", | |
"version_major": 2, | |
"version_minor": 0 | |
}, | |
"text/plain": [ | |
"HBox(children=(VBox(children=(HTML(value='<strong>IPyChat</strong> (Admin)'), Textarea(value='', layout=Layout…" | |
] | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"HBox([host.ui, client1.ui, client2.ui])" | |
] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python 3", | |
"language": "python", | |
"name": "python3" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython3", | |
"version": "3.7.3" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment