Skip to main content

IChatPlugin

IChatPlugin is a (very) simple plugin binding for you to interact with a chat API (e.g., ChatGPT API), but it is pretty out of the box to use.

We've provided a test_chat.py file in the tests folder, and here we will break it down for you to understand how IChatPlugin works.

Here's the complete code:

tests/test_chat.py
import time

from cfdraw import *
from lorem_text import lorem


class ChatPlugin(IChatPlugin):
notification = "A plugin that generates lorem ipsum chat."

@property
def settings(self) -> IPluginSettings:
return IPluginSettings(
w=600,
h=400,
useModal=True,
tooltip="Pseudo Chat",
pivot=PivotType.RIGHT,
pluginInfo=IChatPluginInfo(
closeOnSubmit=False,
toastOnSubmit=False,
),
)

async def process(self, data: ISocketRequest) -> str:
request = data.extraData
context = request["context"]
userInput = request["userInput"]
if context:
context += "\n"
new_context = f"{context}\nYou: {userInput}\n\nBot: "
text = lorem.words(20)
for char in text:
new_context += char
self.send_progress(textList=[new_context])
time.sleep(0.025)
return new_context


register_plugin("chat")(ChatPlugin)
app = App()

Imports

tests/test_chat.py
import time

from cfdraw import *
from lorem_text import lorem

Nothing special, but notice that we import lorem_text so we can generate some random text later.

Notification

tests/test_chat.py
class ChatPlugin(IChatPlugin):
notification = "A plugin that generates lorem ipsum chat."

By specifying the notification property, a notification will be logged to the console when the plugin is loaded.

Notification

Styles

API reference
tests/test_chat.py
class ChatPlugin(IChatPlugin):
@property
def settings(self) -> IPluginSettings:
return IPluginSettings(
w=600,
h=400,
useModal=True,
tooltip="Pseudo Chat",
pivot=PivotType.RIGHT,
pluginInfo=IChatPluginInfo(
initialText="Bot: Hello, can I help you?",
closeOnSubmit=False,
toastOnSubmit=False,
),
)

These are common styles settings, and this line:

tests/test_chat.py
class ChatPlugin(IChatPlugin):
@property
def settings(self) -> IPluginSettings:
return IPluginSettings(
...,
pluginInfo=IChatPluginInfo(
initialText="Bot: Hello, can I help you?",
closeOnSubmit=False,
toastOnSubmit=False,
),
)

Specifies the initial text of the chat.

note

We specified:

tests/test_chat.py
class ChatPlugin(IChatPlugin):
@property
def settings(self) -> IPluginSettings:
return IPluginSettings(
...,
pluginInfo=IChatPluginInfo(
initialText="Bot: Hello, can I help you?",
closeOnSubmit=False,
toastOnSubmit=False,
),
)

Because we want users to be more engaged with the plugin, and don't want the plugin to be closed or toasted after the users submit their chats.

Logics

In order to interact with the chat API, we (at least) need to get two things:

  • context: The previous context of the chat.
  • userInput: The latest user input.

Therefore, IChatPlugin injected them into the extraData property:

tests/test_chat.py
class ChatPlugin(IChatPlugin):
...

async def process(self, data: ISocketRequest) -> str:
request = data.extraData
context = request["context"]
userInput = request["userInput"]
if context:
context += "\n"
new_context = f"{context}\nYou: {userInput}\n\nBot: "
text = lorem.words(20)
for char in text:
new_context += char
self.send_progress(textList=[new_context])
time.sleep(0.025)
return new_context

With context and userInput, we should be able to send the corresponding data to the chat API and receive new responses. In this example, we simply generate some random text to mimic a chat API:

tests/test_chat.py
class ChatPlugin(IChatPlugin):
...

async def process(self, data: ISocketRequest) -> str:
request = data.extraData
context = request["context"]
userInput = request["userInput"]
if context:
context += "\n"
new_context = f"{context}\nYou: {userInput}\n\nBot: "
text = lorem.words(20)
for char in text:
new_context += char
self.send_progress(textList=[new_context])
time.sleep(0.025)
return new_context

What's more, we even use time.sleep to mimic the streaming process of the chat API. Also, we utilized the built-in send_progress method to make sure that as long as the (pseudo) streaming chat API responses a char / word, we can send it immediately to the drawboard 🎨 and ask it to refresh the chat:

tests/test_chat.py
class ChatPlugin(IChatPlugin):
...

async def process(self, data: ISocketRequest) -> str:
request = data.extraData
context = request["context"]
userInput = request["userInput"]
if context:
context += "\n"
new_context = f"{context}\nYou: {userInput}\n\nBot: "
text = lorem.words(20)
for char in text:
new_context += char
self.send_progress(textList=[new_context])
time.sleep(0.025)
return new_context

Run

tests
cfdraw run --module test_chat.py

And here's a demo video of how this plugin works: