Skip to content
This repository was archived by the owner on Aug 29, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
52b7df4
move hardcoded string to application.properties
iosdev747 May 28, 2019
47a1854
remove redundant annotation with @SpringBootApplication
iosdev747 May 28, 2019
f828f47
Update application.properties
iosdev747 May 29, 2019
aa4d0c4
Add messenger4j dependency
iosdev747 May 29, 2019
a8f706c
Add facebook messenger chat service
iosdev747 May 29, 2019
eb1ceb7
Create server config
iosdev747 May 30, 2019
f83519e
Disable Cross Site Request Forgery(CSRF)
iosdev747 May 30, 2019
57456c9
temporarily changing slack integration
iosdev747 May 31, 2019
4ed1f07
add login method to get credentials
iosdev747 Jun 6, 2019
458a859
minor bugs fix in FB messenger integration
iosdev747 Jun 6, 2019
62d95b2
create Basic HTTP auth method
iosdev747 Jun 7, 2019
38c93a2
Improve ApiClient constructors
iosdev747 Jun 7, 2019
62f3ebf
implement authentication in handlers using ApiClient
iosdev747 Jun 8, 2019
a6a565b
create database setting component
iosdev747 Jun 9, 2019
09e198a
add database properties in application.properties
iosdev747 Jun 9, 2019
c5d6835
create database configuration
iosdev747 Jun 9, 2019
bc34b0d
Create Database handler
iosdev747 Jun 9, 2019
6355f6a
add database build.gradle
iosdev747 Jun 9, 2019
4c5180b
Remove old implementation of JDBC and reimplement with JPA and JDBC t…
iosdev747 Jun 10, 2019
082af69
Create user model, add dependencies and implement query methods
iosdev747 Jun 10, 2019
c686347
Update authentication in FB messenger integration
iosdev747 Jun 11, 2019
47233e0
Minor bug fix in authentication in FB messenger integration
iosdev747 Jun 12, 2019
6a3ae4f
remove sout and update authentication logic
iosdev747 Jun 12, 2019
a0e6869
minor bug fix in authentication (FB messenger integration)
iosdev747 Jun 12, 2019
b107e8d
add logic to handle logout
iosdev747 Jun 12, 2019
d2733f0
Add telegram API dependency
iosdev747 Jun 14, 2019
bbce0da
Integrate telegram bot
iosdev747 Jun 14, 2019
a09656a
Add Telegram database handler methods
iosdev747 Jun 14, 2019
93f456d
add login logic to telegram integration
iosdev747 Jun 14, 2019
7aa38f8
minor bug fix with authentication
iosdev747 Jun 15, 2019
013587e
bug fix with dependency conflict related to telegram API
iosdev747 Jun 15, 2019
710fa30
improve bot response and login logic
iosdev747 Jun 15, 2019
1e923a1
code cleanup: remove print statements
iosdev747 Jun 15, 2019
bcfafb8
Add log statements
iosdev747 Jun 16, 2019
8a13220
Add Slack database handler methods
iosdev747 Jun 17, 2019
4009160
Update chatCallback method parameters
iosdev747 Jun 17, 2019
25e82e7
standardizing method name
iosdev747 Jun 17, 2019
8c964f1
add authentication to slack integration
iosdev747 Jun 17, 2019
d261a51
code cleanup: slackChatService
iosdev747 Jun 18, 2019
2f2e853
remove redundant variables and code cleanup
iosdev747 Jun 18, 2019
cf24c0f
moved protocol beans from MifosChatbotApplication to ProtocolConfig
iosdev747 Jun 18, 2019
5537ccf
Code cleanup and minor bug fixes as suggested in PR code review
iosdev747 Jun 29, 2019
44555f8
Encod password for more security
iosdev747 Jun 29, 2019
3da5365
fix grammatical error
iosdev747 Jul 2, 2019
7703d67
add Rasa NLU dataset
iosdev747 Jul 3, 2019
7c3c60c
add more Rasa NLU dataset
iosdev747 Jul 3, 2019
a23ba30
add Rasa NLU dataset for loan handlers
iosdev747 Jul 3, 2019
a9dace2
add Rasa NLU dataset for loan product handlers
iosdev747 Jul 3, 2019
53954e9
add Rasa NLU dataset for saving handlers
iosdev747 Jul 4, 2019
dbe450f
add Rasa NLU config
iosdev747 Jul 4, 2019
939d3ba
add RasaNLUService component
iosdev747 Jul 5, 2019
a9383ab
implement Rasa handler
iosdev747 Jul 6, 2019
b0bdc67
fix dataset issue
iosdev747 Jul 7, 2019
e77d571
implement rasa NLU service
iosdev747 Jul 10, 2019
29fd628
add dependencies for json and apache http
iosdev747 Jul 13, 2019
c383eba
import optimize
iosdev747 Jul 14, 2019
ce36a4c
fix bad grammer MySQL
iosdev747 Jul 16, 2019
24955ad
add Rasa NLU model
iosdev747 Jul 19, 2019
b5eb1b4
Update readme for Rasa
iosdev747 Jul 19, 2019
c6f4f86
update NLPService recognize method
iosdev747 Jul 20, 2019
716fb7b
fix chatbot adapter service handler method
iosdev747 Jul 21, 2019
9a0250a
Replace getter and setter methods with annotation
iosdev747 Jul 21, 2019
a2af033
Add isSmallTalkRequest method
iosdev747 Jul 25, 2019
b1bcb37
implement isSmallTalkRequest method
iosdev747 Jul 25, 2019
c9c27e5
Small fixes in SlackChatService
iosdev747 Jul 26, 2019
9da7479
Add SmallTalkHandler base
iosdev747 Jul 26, 2019
4f3dc95
Add isSmallTalk method implementation
iosdev747 Jul 27, 2019
6b7a9ed
Implement SmallTalkHandler and Update SmallTalk class
iosdev747 Jul 28, 2019
b9a266e
Add more intent response
iosdev747 Jul 28, 2019
95571d2
Add handle logic for SmallTalk request in Slack
iosdev747 Jul 29, 2019
3389431
add dependencies for joestelmach parser
iosdev747 Jul 29, 2019
91a7268
Improve date and id finding logic in RasaNLUService
iosdev747 Jul 29, 2019
04447f6
Increase and add response to intents defined in SmallTalkHandler
iosdev747 Jul 31, 2019
f23f5cb
Code cleanup
iosdev747 Jul 31, 2019
5a06fdf
Add skypeChatService
iosdev747 Aug 1, 2019
90f8552
Add skype dependency
iosdev747 Aug 1, 2019
46da0ad
remove skype as API depreciated
iosdev747 Aug 3, 2019
99e5b1f
remove skype dependencies
iosdev747 Aug 3, 2019
0d12c94
small bug fix in debug statement
iosdev747 Aug 4, 2019
81ab0a5
Integrate small talk in facebook messenger and telegram
iosdev747 Aug 4, 2019
c474cb1
Improve intent handlers
iosdev747 Aug 7, 2019
bdcb581
Add small talk dataset
iosdev747 Aug 8, 2019
f7e84b6
Replace Rasa NLU model
iosdev747 Aug 10, 2019
be048f8
Add slack(deleted accidentally)
iosdev747 Aug 10, 2019
d846e17
Fix PR review
iosdev747 Aug 11, 2019
95328ea
typo fix
iosdev747 Aug 11, 2019
8acf203
Code Cleanup
iosdev747 Aug 12, 2019
7db2089
Bug fix with message length max limit
iosdev747 Aug 13, 2019
0355b02
Update README.md
iosdev747 Aug 15, 2019
e1a43d8
Update README.md with setting up database.
iosdev747 Aug 16, 2019
4595dd5
Added checks to handle exceptions
iosdev747 Aug 20, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 108 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,98 @@ If you want to contribute to this project, there are several things that you hav
2. Exactly Java 1.8
3. MySQL & Tomcat
4. Gradle
5. Slack account
5. Slack/Telegram/Facebook account

And for NLU, you are required to have
1. Python 3.6.1 (as NOW Rasa NLU is having dependency issues with Python 3.7)
2. Microsoft VC++ Compiler
3. Rasa (for offline training and testing models)

```
# install Rasa NLU using these commands

pip install rasa[spacy]
python -m spacy download en_core_web_md
python -m spacy link en_core_web_md en
```

## Getting started

### Installing on Mac OS
Java: <br>
### Setting up
##### Java:
There are two options.
1. Download Java 1.8 from [official website](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html), install it and configure it on class path
2. If you have `brew` installed in your system, you can also download from homebrew. `brew cask install java8` to install Java 8 on Mac OS.

MySQL:
##### MySQL:
1. Download from [official website](https://dev.mysql.com/downloads/mysql/), install it and configure it. During installation, if the user does not set the initial password, then the initial password should be set in the System Preferences -> MySQL -> set initial password. Then configure mysql in the classpath.
1.1. If you want to use Cloud Service for database, you are free to do that. Remember to update `application.properties` file.
2. Create table `user_creds` using following MySQL command
```
create table users_creds
(
username varchar(255) not null,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can potentially look into encrypting these fields at the database level for when we want to extend this work.

secret_key varchar(255) not null,
fb_userid varchar(255) null,
slack_userid varchar(255) null,
telegram_userid varchar(255) null,
skype_userid varchar(255) null
);
```

2. If you want to use Cloud Service instead of local installation of database, you can use Docker to create a virtual database.

Gradle <br>
##### Gradle:
Download Gradle from [official website](https://gradle.org/install/).

Slack
1. Join Mifos workspace and search for `chatbot` in the application page to access service.
2. If you want to have your own Slack bot, apply from [here](https://api.slack.com/apps?new_app=1).

### Playing with chatbot
After forking and cloning chatbot project , do a gradle import run the unit tests in those modules to understand the function of each module.<br>

Key in text in the chatbot and read the response to understand more.

For example, you can type `Check my arrear day`, `Check my due interest`, `Check my next due date` in the Slack interface. Then you will receive response from the Slack bot, like "478 days" as the response of `arrear day`, "1150.0" as the response of `due interest` and `Sat Apr 29 00:00:00 SGT 2017` as the response of `next due date`.
Now we need a platform to run your chatbot, we have integration with Slack, Telegram and Facebook messenger (atleast one is required to setup).
##### Slack:
1. Deploy your own Slack bot, apply from [here](https://api.slack.com/apps?new_app=1).
2. Get `Bot User OAuth Access Token` from OAuth & Permission.
3. Set token to environment variable with name `MIFOS_SLACK_API_TOKEN`.

Now you are all setup to test bot on Slack.
##### Telegram:
1. Search for the “botfather” telegram bot on either [web.telegram.org](https://web.telegram.org/) or on telegram app.
2. Create bot using `/newbot` command.
3. Set username of bot to name `TELEGRAMBOT_USERNAME` and token to `TELEGRAMBOT_TOKEN` environment variables.

Now you are all setup to test bot on telegram.
##### Facebook Messenger:
1. Create a facebook page (here we will deploy our bot) and set page access token to `MESSENGER_PAGE_ACCESS_TOKEN` environment variable.
2. Create facebook app from [here](https://developers.facebook.com/).
3. Set messenger app token to `MESSENGER_APP_SECRET` and verify token (will be used to setup callback) to `MESSENGER_VERIFY_TOKEN` environment variables.
4. Set callback url to endpoint where chatbot is deployed and messenger verify token on Webhooks section (by clicking on "Edit Subscription" button).

Now you are all setup to test bot on Facebook Messenger.
### Training your NLU own model
Use the following command to train Rasa NLU model. Make sure you have prerequisites for Rasa and Rasa is installed on your local system.
```
rasa train nlu
```
Remember to use following structure for Rasa, else provide training data and other configuration files manually.
###### Rasa structure
```
mifos-chatbot\nlp\src\main\resources\rasa/
|-- data/
| |
| |-- nlu.md
|
|-- models
| |
| |-- nlu-XXXXXXXX-XXXXXX.tar.gz
|
|-- config.yml
```

### Deploying and testing your own model
Use the following command to run Rasa NLU model locally.
```
# Start a server with your NLU model as web service
rasa run --enable-api -m models/nlu-XXXXXXXX-XXXXXX.tar.gz
# Test your model on shell
rasa shell -m models/nlu-XXXXXXXX-XXXXXX.tar.gz
```

### Playing with Fineract and Chatbot
### Playing with Fineract

As you may know, the Chatbot project will query information from Fineract. Hence, we are supposed to have a public instance or a local instance of Fineract running on Tomcat server.

Expand All @@ -49,28 +111,45 @@ Set up database using mysql-first-time.sql to populate sample data into local da

For the public instance, [open demo org] is available for use. One minor issue about this instance is that the authority level is that everyone involved in Fineract related project can change it. Hence, if someone push the code with bugs to the server, then it may cause errors.

After settling down issues about Fineract, configure mifos.url in application.properties in server package. Apply for your own bot user in the application page of Slack and put the token in application.properties file also.
### Playing with chatbot

The sample application properties file is like that:
```
server.port=10000
Fork and clone chatbot project, do a gradle import and run the unit tests in those modules to understand the function of each module.<br>

mifos.apiUrl=https://demo.openmf.org/fineract-provider/api/v1
Run chatbot and type your queries on respective chat platform. For example, you can type `Check my arrear day`, `Check my due interest`, `Check my next due date`. Then you will receive response from the Mifos chatbot, like "478 days" as the response of `arrear day`, "1150.0" as the response of `due interest` and `Sat Apr 29 00:00:00 SGT 2017` as the response of `next due date`.

#Slack
mifos.slackApiToken=xoxb-15186592304-405342609110-7PHj7JTsvcQ3wlGrGb8XLMjW
Remember to configure application.properties in server package.

mifos.username=mifos
mifos.password=password
The sample application properties file is like that:
```
server.port="port where chatbot will run"
mifos.apiUrl="fineract endpoint"
mifos.slackApiToken=${MIFOS_SLACK_API_TOKEN}
mifos.username=${MIFOS_USERNAME}
mifos.password=${MIFOS_PASSWORD}
messenger4j.appSecret=${MESSENGER_APP_SECRET}
messenger4j.verifyToken=${MESSENGER_VERIFY_TOKEN}
messenger4j.pageAccessToken=${MESSENGER_PAGE_ACCESS_TOKEN}
telegram.botUsername=${TELEGRAMBOT_USERNAME}
telegram.botToken=${TELEGRAMBOT_TOKEN}
developer.metadata="developer defined Metadata"
# configured for mysql
spring.jpa.hibernate.ddl-auto=none
spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.url = "database url"
spring.datasource.username = "database username"
spring.datasource.password = "database password"
rasa.nlu.service.url = "Rasa NLU model endpoint"
logging.level.org.springframework=DEBUG
```

Run `./gradlew server:bootRun` to startup the application and input text in the Slack interface.

## Authors
[Zhao Dingfan](https://github.com/ZhaoDingfan)
- [Zhao Dingfan](https://github.com/ZhaoDingfan) (GSoC 2018)
- [Anshul Singh](https://github/com/iosdev747) (GSoC 2019)

## Mentor
Aleksandar
- Aleksandar

## License
This project is licensed under Apache License Version 2.0.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@
import lombok.extern.slf4j.Slf4j;
import org.mifos.chatbot.core.AdapterService;
import org.mifos.chatbot.core.IntentHandler;
import org.mifos.chatbot.core.SmallTalkService;
import org.mifos.chatbot.core.model.Intent;
import org.mifos.chatbot.core.model.MifosResponse;
import org.mifos.chatbot.nlp.OpenNLPService;
import org.mifos.chatbot.nlp.RasaNLUService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
Expand All @@ -32,38 +34,42 @@
@Service
public class MifosChatbotAdapterService implements AdapterService {
@Autowired
private OpenNLPService openNLPService;
private RasaNLUService rasaNLUService;

@Autowired
private List<IntentHandler> handlers;

@Autowired
private SmallTalkService smallTalkService;

@Override
public List<MifosResponse> handle(Intent intent) {
return handlers
.stream()
.filter(handler -> handler.canHandle(intent))
.map(handler -> handler.handle(intent))
.collect(Collectors.toList());
.stream()
.filter(handler -> handler.canHandle(intent))
.map(handler -> handler.handle(intent))
.collect(Collectors.toList());
}

@Override
public List<MifosResponse> handle(String input) {
List<MifosResponse> results = new ArrayList<>();
Intent[] intents = openNLPService.recognize(input);

Long id = 1L; // default id, set to 1

for(Intent intent : intents) {
results.addAll(handle(intent));
Intent intent = null;
try {
intent = rasaNLUService.recognize(input);
} catch (IOException e) {
e.printStackTrace();
}
return results;
return new ArrayList<>(handle(intent));
}

/*


[Slack/Viber/XMPP/IRC/Skype] -> NLP -> Intent1, Intent2, Intent3 -> AdapterService(Intent) -> responses -> [Slack/Viber/XMPP/IRC/Skype]


*/
@Override
public boolean isSmallTalkRequest(String messageText) {
Intent intent = null;
try {
intent = rasaNLUService.recognize(messageText);
} catch (IOException e) {
e.printStackTrace();
}
return smallTalkService.isSmallTalkRequest(intent);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.apache.commons.lang3.time.FastDateFormat;
import org.mifos.chatbot.adapter.handler.HandlerUtils;
import org.mifos.chatbot.client.ApiException;
import org.mifos.chatbot.client.Configuration;
import org.mifos.chatbot.client.api.LoansApi;
import org.mifos.chatbot.client.model.GetLoansLoanIdResponse;
import org.mifos.chatbot.core.model.Intent;
Expand All @@ -35,13 +36,14 @@
@Slf4j
@Component
public class ArrearDayHandler extends BaseLoanIntentHandler {
private static final String[] INTENT_KEYWORDS = {"arrear", "day"};
private static final String[] INTENT_KEYWORDS = {"arrear_day"};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move to static file

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This INTENT_KEYWORDS is specific for this class, so my intention is to keep it here or should i move it?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep it here then.


@Autowired
private LoansApi loansApi;

@Override
public Boolean canHandle(Intent intent) {
// not removing this logic because it is possible that multiple intent can be handled with same handler
for(String intent_keyword : INTENT_KEYWORDS) {
if (!intent.getKeyword().toLowerCase().contains(intent_keyword.toLowerCase())) {
return false;
Expand All @@ -53,10 +55,15 @@ public Boolean canHandle(Intent intent) {

@Override
public MifosResponse handle(Intent intent) {
loansApi.setApiClient(Configuration.getDefaultApiClient());
MifosResponse response = new MifosResponse();
try {
GetLoansLoanIdResponse result = loansApi.retrieveLoan(intent.getParameterAsLong("ID"), false);
List<Long> overdueSinceDate = result.getSummary().getOverdueSinceDate();
if(overdueSinceDate == null) {
response.setContent("No data found for the given id.");
return response;
}
//
// StringBuffer sb = new StringBuffer();
// sb.append(String.format("%04d", overdueSinceDate.get(0)));
Expand All @@ -74,7 +81,7 @@ public MifosResponse handle(Intent intent) {

long diffDays = TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS);

response.setContent(String.valueOf(diffDays) + " days");
response.setContent(diffDays + " days");
} catch (ApiException e) {
log.info("Error", e);
response.setContent(e.getMessage());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import lombok.extern.slf4j.Slf4j;
import org.mifos.chatbot.adapter.handler.HandlerUtils;
import org.mifos.chatbot.client.ApiException;
import org.mifos.chatbot.client.Configuration;
import org.mifos.chatbot.client.api.ClientApi;
import org.mifos.chatbot.client.model.GetClientsClientIdResponse;
import org.mifos.chatbot.core.model.Intent;
Expand All @@ -30,7 +31,7 @@
@Slf4j
@Component
public class ClientActivationDateHandler extends BaseLoanIntentHandler {
private static final String[] INTENT_KEYWORDS = {"client", "activation", "date"};
private static final String[] INTENT_KEYWORDS = {"client_activation_date"};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All such hard coded strings to static files

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved


@Autowired
private ClientApi clientApi;
Expand All @@ -48,6 +49,7 @@ public Boolean canHandle(Intent intent) {

@Override
public MifosResponse handle(Intent intent) {
clientApi.setApiClient(Configuration.getDefaultApiClient());
MifosResponse response = new MifosResponse();
try {
GetClientsClientIdResponse result = clientApi.retrieveOne(intent.getParameterAsLong("ID"), false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import lombok.extern.slf4j.Slf4j;
import org.mifos.chatbot.client.ApiException;
import org.mifos.chatbot.client.Configuration;
import org.mifos.chatbot.client.api.LoansApi;
import org.mifos.chatbot.client.model.GetLoansLoanIdResponse;
import org.mifos.chatbot.core.model.Intent;
Expand All @@ -27,7 +28,7 @@
@Slf4j
@Component
public class DueInterestHandler extends BaseLoanIntentHandler {
private static final String[] INTENT_KEYWORDS = {"due", "Interest"};
private static final String[] INTENT_KEYWORDS = {"due_interest"};

@Autowired
private LoansApi loansApi;
Expand All @@ -45,6 +46,7 @@ public Boolean canHandle(Intent intent) {

@Override
public MifosResponse handle(Intent intent) {
loansApi.setApiClient(Configuration.getDefaultApiClient());
MifosResponse response = new MifosResponse();
try {
GetLoansLoanIdResponse result = loansApi.retrieveLoan(intent.getParameterAsLong("ID"), false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,18 @@

import lombok.extern.slf4j.Slf4j;
import org.mifos.chatbot.client.ApiException;
import org.mifos.chatbot.client.Configuration;
import org.mifos.chatbot.client.api.LoansApi;
import org.mifos.chatbot.client.model.GetLoansLoanIdResponse;
import org.mifos.chatbot.core.model.Intent;
import org.mifos.chatbot.core.model.MifosResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class DuePrincipalHandler extends BaseLoanIntentHandler {
private static final String[] INTENT_KEYWORDS = {"due", "principal"};
private static final String[] INTENT_KEYWORDS = {"due_principal"};

@Autowired
private LoansApi loansApi;
Expand All @@ -43,6 +46,7 @@ public Boolean canHandle(Intent intent) {

@Override
public MifosResponse handle(Intent intent) {
loansApi.setApiClient(Configuration.getDefaultApiClient());
MifosResponse response = new MifosResponse();
try {
GetLoansLoanIdResponse result = loansApi.retrieveLoan(intent.getParameterAsLong("ID"), false);
Expand Down
Loading