NeCSuS is a chat app which makes it simple to connect "bots" (i.e., simple HTTP servers that reply to messages). NeCSuS has the ability to host chats in "rooms", listen to voice commands and speak chat messages out loud.
A web app that allows you to create rooms in which you can import and interact with chatbots.
Yes, there is a simple guide to NeCSuS. You can also look at the NeCSuS API docs and the bot API docs.
You can render a single image by putting an image
key in your response.
{"text": "A cute dog!", "image": "https://images.dog.ceo/breeds/terrier-norfolk/n02094114_1505.jpg"}
The client also renders HTML in messages. All the usual HTML elements for images, links, and text formatting will work. For example, the bot can respond with:
{"text": "Lasagna <i>is</i> a <b>sandwich</b>!"}
Note that some characters should be escaped using character
references
if you do not wish them to be interpreted as HTML. For example: {"text": "1 < 2"}
would produce 1 < 2
.
You can embed a sound or video using the media
key.
{"text": "Ring!", "media": "https://upload.wikimedia.org/wikipedia/commons/transcoded/d/de/Back_Rounds.ogg/Back_Rounds.ogg.mp3"}
The simplest way to create a room is to add your name onto the end of your group's room such that it has the form:
https://chat.ncss.cloud/group<group_number>-<your_name>
For example: https://chat.ncss.cloud/group4-kenni
All bots should consist of 3 main elements:
Clicking on the "open settings" button at the top right hand section of the page, we can see a new side panel open up.
Under the red reset room button - press the "add bot" button to create a new blank bot.
From there, fill in the bot name (preferably something unique and not normally used in a sentence).
You can then post the base link for the bot. This is the link to your bot endpoint in Flask (e.g. <url>/<app route>
.
Every time a message is sent by a user to a room - NeCSuS scans the message to see if there is a message that matches either an existing bot name
, or the Responds to
field for all active bots in the chatroom.
Depending on the contents of the Responds to
field - the data will be sent to the bot either as plain text or it will have additional key:value
pairs
Awesome! You can use named capturing groups to do this. For example, repeat bot requires two things from a message:
- A string to repeat (lets call this
word
) - How many times to repeat it (lets call this
count
)
We can then use the following regex string in the Responds to
field of our NeCSuS bot to get these:
repeat (?P<word>\w+) (?P<count>\d+) times
So, if I sent the message repeat hello 5 times
to a chatroom with repeat bot - NeCSuS would send data in the following way.
{
"room": "shrey",
"author": "Anonymous",
"text": "repeat hello 5 times",
"params": {
"word": "hello",
"count": "5"
}
}
you can get this data by using request.get_json() in your python server :)
NeCSuS expects two things to be returned as JSON from bot. So, a basic server that sends the same message every time should look like:
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/', methods=['POST'])
def home_handler():
# Create a message to send to NeCSuS
message = {
'author': 'Appreciation Bot',
'text': "Yay! I'm here to tell you that you did a great job!",
}
# Return the JSON
return jsonify(message)
app.run(host='0.0.0.0')
So, every time this bot is activated - it will send the same message back: Yay! I'm here to tell you that you did a great job!"
You may have noticed that it is easy with necsus to facilitate an interaction like
> I saw a cat behind the college
Catbot: I've recorded the sighting of the cat behind the college
and quite difficult to facilitate one like
> I saw a cat!
Catbot: Where did you see the cat?
> Behind the college
Catbot: I've recorded the sighting of the cat behind the college
because you will somehow need a regular expression to dispatch on Behind the college
. Furthermore, in a longer conversation you may have to query the user multiple times to learn a lot of information before performing an action, and so your conversation needs to have some state
associated with it.
By returning some extra state from your bot, you will switch necsus into a mode where it only talks to that one bot, and forwards all messages to that one bot. So by returning
{
"text": "Where did you see the cat?",
"state": ["any", "non", "null", {"json": "object"}]
}
all further messages will be forwarded to the bot which returned that state, and no other bot. The state will also be returned: the next message that bot might see will be
{
"room": "catspot",
"author": "Joel",
"text": "Behind the college",
"params": {},
"state": ["any", "non", "null", {"json": "object"}]
}
in other words, the same state it previously sent gets handed back. At this point the bot can choose to not return state
(or return a null
json object for state), in which case necsus switches back to normal mode. Otherwise, the stateful conversation continues.
The NeCSuS client has special support for HTML forms.
Whenever a bot returns some HTML containing a <form>
element, a special Javascript handler is attached to the form, which will redirect the submit action of the form back to the NeCSuS server.
The NeCSuS server then makes a POST request back to the bot responsible to the original form, with an object containing the form_data
key, and the bot may return a message as usual.
For example, let's suppose that the "desserts" bot at the endpoint https://example.com/bots/desserts
has returned the following HTML, as part of its text
field in a previous interaction:
<form>
<button name="dessert" value="apple-crumble">Apple crumble</button>
<button name="dessert" value="ice-cream">Ice cream</button>
<button name="dessert" value="affogato">Affogato</button>
</form>
When the user clicks on the "Apple crumble" button, the same bot endpoint https://example.com/bots/desserts
will recieve a POST request with the following data:
{
"room": "some-room-name",
"form_data": {
"dessert": "apple-crumble"
}
}
Note that this object is a different shape to a regular message to a bot, which would have the text
field for example.
The bot can then return a JSON object as usual, and say something like "I see that Apple Crumble is your favourite."
The method=
on a <form>
is ignored (the system will always make a POST request to the bot, no matter what), but the action=
attribute can be used to change which endpoint the form data gets posted to.
The action is considered relative to the bot endpoint, so for example if the bot endpoint is https://example.com/bots/desserts
, then:
<form>
or<form action="">
will POST tohttps://example.com/bots/desserts
,<form action="foo">
will POST tohttps://example.com/bots/foo
<form action="/foo">
will POST tohttps://example.com/foo
<form action="https://some.other.domain/baz">
will POST tohttps://some.other.domain/baz
Documentation on the API can be found on the main NeCSuS server or at /docs
on your local instance.
Install the projects dependencies using Poetry:
poetry env use python3.10
poetry install
To run the NeCSuS server, use one of the following two commands:
poetry run uvicorn necsus:app --log-config logconfig.yaml --reload # Debug mode.
poetry run uvicorn necsus:app --log-config logconfig.yaml --host localhost --port 6277 # Production mode.
Then visit http://localhost:6277/.
The chat room will be stored in a local SQLite database called necsus.db
.
There are some example bots as well, which can be run using
poetry run python example_bots/server.py