Permalink
Show file tree
Hide file tree
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
3 changed files
with
286 additions
and
334 deletions.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
{ | ||
"name": "chatbot", | ||
"tagline": "Year 1 Project", | ||
"body": "### Introduction\r\nThis is a reflective piece on my Year 1 group project. Please view the code [here](https://github.coventry.ac.uk/soperd/chatbot).\r\n\r\nThe project is a chatbot written in Python 3 primarily for use with Discord. Current features include:\r\n- Some natural language understanding with [RasaNLU](https://rasa.com/).\r\n- Weather forecast integration with [DarkSky](https://darksky.net/).\r\n- Location services with [Nominantim by OpenStreetMaps](https://nominatim.openstreetmap.org/).\r\n- Datastore integration with [Redis](https://redis.io/).\r\n\r\n\r\n### Design\r\nAs the most experienced member of my team, I set down the foundation for the bot's design and structure. At the time, we were unsure what platform which platforms we wanted to target, so I set out by separating the platform-specific implementations from the platform-neutral services.\r\n\r\nI did this by putting all code that provided some kind of generic services into the `handlers` folder of the project. Here you can find a file called `services.py` which contains a class called `Service` that acts as a configurable base class. All other services in `handlers` inherits this `Service` class and implements its own functionality. For example, the `WeatherService` class in `weather.py` contains methods like `get_weather_at` that takes a given longitude and latitude and queries DarkSky's forecast API. \r\n\r\nThe services can then be registered using the `register_service` decorator that can be found in `services.py`. The decorator takes a name as a parameter, then resolves the config provided to that service with the same name detailed in `config.json`, and stores it in the dictionary `global_services`.\r\n\r\nFor all the platform specific implementations, I put the code in the `wrappers` folder. This contains a file called `bot.py` which has a class `ChatBot`. This acts as an interface that defines common behaviours for every bot with methods such as `start` and `stop`, since the reasoning behind it was that every bot must at least start and be able to be stopped. At the moment, the only implemented platform is Discord, the code for which can be seen in `discord.py`. Here we can see the bot inherits `ChatBot`, implements the `start` method and defines its own. `ChatBot` also declares three class members:\r\n- `services`: A dictionary containing instances of services for the bot to use.\r\n- `datastore`: A Redis client object for the bot to access the datastore.\r\n- `config`: A `ConfigDict` object that acts as a representation of the bot's config in `config.json` (see below).\r\n\r\nBoth services and wrappers are configurable via the `config.json` file, which looks something like this:\r\n\r\n```json\r\n{\r\n \"discord\": {\r\n \"token\": \"<DISCORD TOKEN HERE>\",\r\n \"services\": [\r\n \"weather\",\r\n \"location\"\r\n ]\r\n },\r\n \"services\": {\r\n \"weather\": {\r\n \"token\": \"<DARKSKY TOKEN HERE>\"\r\n }\r\n },\r\n \"redis\": {\r\n \"host\": \"localhost\",\r\n \"port\": 6379\r\n }\r\n}\r\n```\r\n\r\nThis details that the Discord bot has a token and a set of services it can use. For this example, it can use the weather and location services. When we run the bot using the `run_discord.py` script, this passes the `discord` configuration to the `DiscordBot` class constructor, which in turn calls `ChatBot`'s constructor. If the optional parameter `services` :p is `None` then `ChatBot`'s constructor then will find the services listed in `config.json` from the `global_services` and store them in the `services` class member. This was my attempt to \"inject\" services into the bot automatically.\r\n\r\n`DiscordBot` is currently the only functioning bot. It uses the Discord.py library which makes for easy integration with Discord's API.\r\n\r\n### Reflection\r\nI think my design worked well for the most part. If we decided we wanted to integrate the app into WhatsApp or Messenger, I feel that my design would aid in porting our features over to the new bot. This design also allows for multiple bots with similar features on the same platform, which I am happy with. I do, however, believe that in some areas my code is poorly implemented, such as :p the `global_services` dictionary. This seems like a bit of a hack, and it wasn't really necessary to achieve my goal. That being said, this is the first time I've used a custom decorator in Python and I can see its potential elsewhere.", | ||
"body": "### Introduction\r\nThis is a reflective piece on my Year 1 group project. Please view the code [here](https://github.coventry.ac.uk/soperd/chatbot).\r\n\r\nThe project is a chatbot written in Python 3 primarily for use with Discord. Current features include:\r\n- Some natural language understanding with [RasaNLU](https://rasa.com/).\r\n- Weather forecast integration with [DarkSky](https://darksky.net/).\r\n- Location services with [Nominantim by OpenStreetMaps](https://nominatim.openstreetmap.org/).\r\n- Datastore integration with [Redis](https://redis.io/).\r\n\r\n\r\n### Design\r\nAs the most experienced member of my team, I set down the foundation for the bot's design and structure. At the time, we were unsure what platform which platforms we wanted to target, so I set out by separating the platform-specific implementations from the platform-neutral services.\r\n\r\nI did this by putting all code that provided some kind of generic services into the `handlers` folder of the project. Here you can find a file called `services.py` which contains a class called `Service` that acts as a configurable base class. All other services in `handlers` inherits this `Service` class and implements its own functionality. For example, the `WeatherService` class in `weather.py` contains methods like `get_weather_at` that takes a given longitude and latitude and queries DarkSky's forecast API. \r\n\r\nThe services can then be registered using the `register_service` decorator that can be found in `services.py`. The decorator takes a name as a parameter, then resolves the config provided to that service with the same name detailed in `config.json`, and stores it in the dictionary `global_services`.\r\n\r\nFor all the platform specific implementations, I put the code in the `wrappers` folder. This contains a file called `bot.py` which has a class `ChatBot`. This acts as an interface that defines common behaviours for every bot with methods such as `start` and `stop`, since the reasoning behind it was that every bot must at least start and be able to be stopped. At the moment, the only implemented platform is Discord, the code for which can be seen in `discord.py`. Here we can see the bot inherits `ChatBot`, implements the `start` method and defines its own. `ChatBot` also declares three class members:\r\n- `services`: A dictionary containing instances of services for the bot to use.\r\n- `datastore`: A Redis client object for the bot to access the datastore.\r\n- `config`: A `ConfigDict` object that acts as a representation of the bot's config in `config.json` (see below).\r\n\r\nBoth services and wrappers are configurable via the `config.json` file, which looks something like this:\r\n\r\n```json\r\n{\r\n \"discord\": {\r\n \"token\": \"<DISCORD TOKEN HERE>\",\r\n \"services\": [\r\n \"weather\",\r\n \"location\"\r\n ]\r\n },\r\n \"services\": {\r\n \"weather\": {\r\n \"token\": \"<DARKSKY TOKEN HERE>\"\r\n }\r\n },\r\n \"redis\": {\r\n \"host\": \"localhost\",\r\n \"port\": 6379\r\n }\r\n}\r\n```\r\n\r\nThis details that the Discord bot has a token and a set of services it can use. For this example, it can use the weather and location services. When we run the bot using the `run_discord.py` script, this passes the `discord` configuration to the `DiscordBot` class constructor, which in turn calls `ChatBot`'s constructor. If the optional parameter `services` is `None` then `ChatBot`'s constructor then will find the services listed in `config.json` from the `global_services` and store them in the `services` class member. This was my attempt to \"inject\" services into the bot automatically.\r\n\r\n`DiscordBot` is currently the only functioning bot. It uses the Discord.py library which makes for easy integration with Discord's API.\r\n\r\n### Reflection\r\nI think my design worked well for the most part. If we decided we wanted to integrate the app into WhatsApp or Messenger, I feel that my design would aid in porting our features over to the new bot. This design also allows for multiple bots with similar features on the same platform, which I am happy with. I do, however, believe that in some areas my code is poorly implemented, such as the `global_services` dictionary. This seems like a bit of a hack, and it wasn't really necessary to achieve my goal. That being said, this is the first time I've used a custom decorator in Python and I can see its potential elsewhere.", | ||
"note": "Don't delete this file! It's used internally to help with page regeneration." | ||
} |
Oops, something went wrong.