{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import panel as pn\n",
    "pn.extension()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The ``ChatBox`` widget shows conversations between users.\n",
    "\n",
    "For more information about listening to widget events and laying out widgets refer to the [widgets user guide](../../user_guide/Widgets.ipynb). Alternatively you can learn how to build GUIs by declaring parameters independently of any specific widgets in the [param user guide](../../user_guide/Param.ipynb). To express interactivity entirely using Javascript without the need for a Python server take a look at the [links user guide](../../user_guide/Param.ipynb).\n",
    "\n",
    "#### Parameters:\n",
    "\n",
    "For layout and styling related parameters see the [customization user guide](../../user_guide/Customization.ipynb).\n",
    "\n",
    "##### Core\n",
    "\n",
    "* **``value``** (List[Dict[str, Any]]): List of messages, mapping user to message, e.g. `[{'You': 'Welcome!'}]`. The message can be any Python object that can be rendered by Panel\n",
    "* **``primary_name``** (str): Name of the primary input user; the first key found in value will be used if unspecified\n",
    "* **``allow_input``** (boolean): Whether to allow the primary user to interactively enter messages\n",
    "* **``allow_likes``** (boolean): Whether to allow the primary user to interactively like messages\n",
    "* **``ascending``** (boolean): Whether to display messages in ascending time order. If true, the latest messages and message_input_widgets will be at the bottom of the chat box. Otherwise, they will be at the top.\n",
    "* **``message_icons``** (Dict[str, str]): Dictionary mapping name of users to their icons, e.g. `[{'You': 'path/to/icon.png'}]`\n",
    "* **``message_colors``** (Dict[str, str]): Dictionary mapping name of users to their colors, e.g. `[{'You': 'red'}]`\n",
    "* **``message_hue``** (int): Base hue of the message bubbles if `message_colors` is not specified for a user.\n",
    "* **``message_input_widgets``** (List[pn.widgets.Widget]): List of widgets to use for message input. Multiple widgets will be nested under tabs.\n",
    "* **``default_message_callable``** (pn.pane.PaneBase | pn.widgets.Widget) The type of Panel object to use for items in value if they are not already rendered as a Panel object; if None, uses the pn.panel function to render a displayable Panel object. If the item is not serializable, will fall back to pn.panel.\n",
    "\n",
    "##### Display\n",
    "\n",
    "* **``disabled``** (boolean): Whether the widget is editable\n",
    "* **``name``** (str): The name to display at the top center of the chat box\n",
    "\n",
    "___"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "chat_box = pn.widgets.ChatBox(\n",
    "    value=[\n",
    "        {\"You\": \"Hello!\"},\n",
    "        {\"Machine\": \"Greetings!\"},\n",
    "        {\"You\": \"Question for you...\"},\n",
    "        {\"You\": \"What is the meaning of life?\"},\n",
    "        {\"Machine\": \"I don't know. Do you know?\"},\n",
    "    ],\n",
    ")\n",
    "\n",
    "chat_box"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "``ChatBox.value`` parameter returns a list of dictionaries that map a user to their message.\n",
    "\n",
    "Each dictionary should only contain a single key--two or more keys will raise an error."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "chat_box.value"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The individual `ChatRow`s that make up the `ChatBox` can be accessed through the `rows` property, which exposes the `rows`' parameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "rows = chat_box.rows\n",
    "\n",
    "row = rows[0]\n",
    "print(row.value, row.icon, row.liked)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You may bind the row's liked parameter to a callback."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pn.bind(lambda liked: print(liked), row.param.liked, watch=True)\n",
    "\n",
    "row.liked = True"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`ChatBox` can support more than two users and the primary input user can be separate from the existing users and also allows setting a `message_hue` to distinguish multiple users:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "chat_box = pn.widgets.ChatBox(\n",
    "    value=[\n",
    "        {\"Machine 1\": \"Morning!\"},\n",
    "        {\"Machine 2\": \"Afternoon~\"},\n",
    "        {\"Machine 3\": \"Night zzz...\"},\n",
    "    ],\n",
    "    message_hue=220,\n",
    "    primary_name=\"You\",\n",
    ")\n",
    "\n",
    "chat_box"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "User interactive input can be disabled."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "chat_box = pn.widgets.ChatBox(\n",
    "    value=[\n",
    "        {\"Machine 1\": \"It's just us machines!\"},\n",
    "        {\"Machine 2\": \"Beep boop beep!\"},\n",
    "    ],\n",
    "    allow_input=False\n",
    ")\n",
    "\n",
    "chat_box"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Messages can be appended or extended after instantiating."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "chat_box = pn.widgets.ChatBox(\n",
    "    value=[\n",
    "        {\"Machine 1\": \"I'm machine 1!\"},\n",
    "        {\"Machine 2\": \"I'm machine 2!\"},\n",
    "    ],\n",
    ")\n",
    "\n",
    "chat_box.append({\"Machine 3\": \"How do you do fellow machines?\"})\n",
    "chat_box.extend([{\"Machine 1\": \"Oh hi!\"}, {\"Machine 2\": \"Welcome!\"}])\n",
    "\n",
    "chat_box"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The logs from the `ChatBox` can also be cleared for a clean slate."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "chat_box = pn.widgets.ChatBox(\n",
    "    value=[\n",
    "        {\"Machine 1\": \"It's over!\"},\n",
    "        {\"Machine 2\": \"Good bye.\"},\n",
    "    ],\n",
    ")\n",
    "chat_box.clear()\n",
    "\n",
    "chat_box"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The messages do *not* only have to be strings; they can be Panel objects as well."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "chat_box = pn.widgets.ChatBox(\n",
    "    value=[\n",
    "        {\"Machine 1\": pn.widgets.TextInput(value=\"This is editable!\")},\n",
    "        {\"Machine 2\": pn.pane.Image(\"https://panel.holoviz.org/_images/logo_horizontal_light_theme.png\", height=100)},\n",
    "    ]\n",
    ")\n",
    "\n",
    "chat_box"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "String messages can be rendered within `pn.widgets.TextInput`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "chat_box = pn.widgets.ChatBox(\n",
    "    value=[\n",
    "        {\"Machine 1\": pn.widgets.Button(name=\"I won't be affected\")},\n",
    "        {\"Machine 2\": \"I will be used as the value for the text input below!\"},\n",
    "        {\"Machine 3\": \"Me too!\"},\n",
    "    ],\n",
    "    default_message_callable=pn.widgets.TextInput,\n",
    ")\n",
    "\n",
    "chat_box"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
