Browse Source

Add documentation.md for rendering in modal;

Implement functions for start/stop typing;
Add parameter to decide if messages should be saved after sending a botMessage;
Add birbmemes, animememes & codingmemes to message-reactions;
React to "meme" & "memes";
Add backupAnswer if no reaction is found;
Rename occurrences of "vue = this" to "Kara = this";
Implement lyrics command & max message height with scrolling;
master
Nero Ignis 5 years ago
parent
commit
2f020f2f62
  1. 158
      app.js
  2. 74
      documentation.md
  3. 31
      index.html

158
app.js

@ -55,7 +55,7 @@ let kara = new Vue({
this.askForName(); this.askForName();
} }
this.isTyping = false; this.stopTyping();
} else { } else {
this.welcomeBack(); this.welcomeBack();
} }
@ -74,7 +74,8 @@ let kara = new Vue({
"Hi! I'm " + this.name + ". :)", "Hi! I'm " + this.name + ". :)",
"Hi, nice to meet you! My name is " + this.name + ". :)" "Hi, nice to meet you! My name is " + this.name + ". :)"
] ]
) ),
false
); );
}, },
welcomeBack() { welcomeBack() {
@ -85,7 +86,8 @@ let kara = new Vue({
"Welcome back! :)", "Welcome back! :)",
"Hey :) Good to see you :)", "Hey :) Good to see you :)",
] ]
) ),
false
); );
}, },
@ -97,7 +99,8 @@ let kara = new Vue({
'Whats your name? :)', 'Whats your name? :)',
'How can i call you?', 'How can i call you?',
'How did your developers call you? :)' 'How did your developers call you? :)'
]) ]),
false
); );
this.askedForName = true; this.askedForName = true;
@ -114,8 +117,6 @@ let kara = new Vue({
"Nice to meet you, " + this.username + ". :D" "Nice to meet you, " + this.username + ". :D"
]) ])
) )
this.updateStorage();
}, },
// Messages / Chat // Messages / Chat
@ -142,14 +143,21 @@ let kara = new Vue({
this.scrollDown(); this.scrollDown();
}, 1000); }, 1000);
this.stopTyping();
this.updateStorage(); this.updateStorage();
}, },
botMessage(message) { botMessage(message, save = true) {
this.addMessage(message, true); this.addMessage(message, true);
if (this.talk) { if (this.talk) {
this.say(message); this.say(message);
} }
this.stopTyping();
if (save) {
this.updateStorage();
}
}, },
userMessage(body) { userMessage(body) {
this.addMessage(body, false); this.addMessage(body, false);
@ -174,13 +182,11 @@ let kara = new Vue({
this.react(message, true); this.react(message, true);
}, },
react(message, recursive = false) { react(message, recursive = false) {
this.isTyping = true; this.startTyping();
if (message.search('/') === 0 && !recursive) { if (message.search('/') === 0 && !recursive) {
setTimeout(() => { setTimeout(() => {
this.processCommands(message); this.processCommands(message);
this.isTyping = false;
this.scrollDown(); this.scrollDown();
}, 1000); }, 1000);
} else { } else {
@ -199,7 +205,6 @@ let kara = new Vue({
this.updateStorage(); this.updateStorage();
} }
this.isTyping = false;
this.scrollDown(); this.scrollDown();
}, 1800); }, 1800);
} }
@ -315,7 +320,7 @@ let kara = new Vue({
} }
if (this.includesAllOf(keywords, ['weather']) && if (this.includesAllOf(keywords, ['weather']) &&
this.includesOneOf(keywords, ['how', 'whats']) this.includesOneOf(keywords, ['how','hows', 'what', 'whats'])
) { ) {
this.checkWeather(); this.checkWeather();
return false; return false;
@ -331,22 +336,18 @@ let kara = new Vue({
return false; return false;
} }
if (this.includesAllOf(keywords, ['cat']) && if (this.includesAllOf(keywords, ['birb', 'meme'])) {
this.includesOneOf(keywords, ['images', 'photos', 'send']) this.getRandomMeme('birbmemes');
) {
this.getRandomCat();
return false; return false;
} }
if (this.includesOneOf(keywords, ['doggo', 'dog', 'shiba']) && if (this.includesAllOf(keywords, ['anime', 'meme'])) {
this.includesOneOf(keywords, ['images', 'photos', 'send']) this.getRandomMeme('animememes');
) {
this.getRandomShiba();
return false; return false;
} }
if (this.includesAllOf(keywords, ['dank', 'meme'])) { if (this.includesAllOf(keywords, ['coding', 'meme'])) {
this.getRandomMeme('dankmemes') this.getRandomMeme('codingmemes');
return false; return false;
} }
@ -403,7 +404,7 @@ let kara = new Vue({
return answer; return answer;
} }
this.botMessage("I don't know what to say.."); this.rsaBackupAnswer(message);
}, },
// Forms // Forms
@ -413,7 +414,6 @@ let kara = new Vue({
this.location = this.settingsModal.location; this.location = this.settingsModal.location;
this.updateStorage(); this.updateStorage();
// this.botMessage('Settings saved! :)');
this.scrollDown(); this.scrollDown();
}, },
@ -506,7 +506,7 @@ let kara = new Vue({
if (commandFound) { if (commandFound) {
return; return;
} }
let commandString = '/' + command; let commandString = '/' + command.toLowerCase();
if (message.search(commandString) === 0) { if (message.search(commandString) === 0) {
parameter = message.replace(commandString, '').trim(); parameter = message.replace(commandString, '').trim();
@ -517,10 +517,10 @@ let kara = new Vue({
return parameter ? parameter : commandFound; return parameter ? parameter : commandFound;
}, },
checkWeather() { checkWeather() {
let vue = this; let Kara = this;
if (!vue.location) { if (!Kara.location) {
vue.botMessage('Please set your location in the settings. ⚙'); Kara.botMessage('Please set your location in the settings. ⚙');
return; return;
} }
@ -529,17 +529,17 @@ let kara = new Vue({
axios.get(url) axios.get(url)
.then(function (response) { .then(function (response) {
vue.botMessage('In ' + response.data.name + ' it\'s ' + response.data.main.temp.toFixed() + '°C with ' + response.data.weather[0].description + '.'); Kara.botMessage('In ' + response.data.name + ' it\'s ' + response.data.main.temp.toFixed() + '°C with ' + response.data.weather[0].description + '.');
}) })
.catch(function (error) { .catch(function (error) {
alertify.notify(error, 'danger'); alertify.notify(error, 'danger');
vue.botMessage('I couldn\'t check the weather for your location. 🤔'); Kara.botMessage('I couldn\'t check the weather for your location. 🤔');
}) })
this.updateStorage(); this.updateStorage();
}, },
getRandomMeme(category = 'memes') { getRandomMeme(category = 'memes') {
let vue = this; let Kara = this;
let url = 'https://meme-api.herokuapp.com/gimme/'; let url = 'https://meme-api.herokuapp.com/gimme/';
let categorySet = false; let categorySet = false;
@ -553,24 +553,24 @@ let kara = new Vue({
axios.get(url + category) axios.get(url + category)
.then(function (response) { .then(function (response) {
vue.addImageMessage({ Kara.addImageMessage({
body: response.data.title, body: response.data.title,
src: response.data.url src: response.data.url
}, true); }, true);
vue.lastMessageData = { Kara.lastMessageData = {
meme: true, meme: true,
category: category category: category
}; };
}) })
.catch(function (error) { .catch(function (error) {
vue.botMessage("Hmm.. i can't think of any good memes right now, sorry.. 😞"); Kara.botMessage("Hmm.. i can't think of any good memes right now, sorry.. 😞");
}) })
this.updateStorage(); this.updateStorage();
}, },
tellJoke(category) { tellJoke(category) {
let vue = this; let Kara = this;
let categorySet = false; let categorySet = false;
if (category !== true && category !== false) { if (category !== true && category !== false) {
@ -586,14 +586,14 @@ let kara = new Vue({
.then(function (response) { .then(function (response) {
let joke = response.data[0]; let joke = response.data[0];
vue.botMessage(joke.setup); Kara.botMessage(joke.setup);
setTimeout(() => { setTimeout(() => {
vue.botMessage(joke.punchline); Kara.botMessage(joke.punchline);
vue.scrollDown(); Kara.scrollDown();
}, 3500); }, 3500);
vue.lastMessageData = { Kara.lastMessageData = {
joke: true, joke: true,
category: category category: category
}; };
@ -602,54 +602,54 @@ let kara = new Vue({
console.log(error); console.log(error);
if (categorySet) { if (categorySet) {
vue.botMessage("Sorry, i don't know any jokes about this topic.. 🙄"); Kara.botMessage("Sorry, i don't know any jokes about this topic.. 🙄");
} else { } else {
vue.botMessage("I can't remember any jokes right now, sorry. 😢"); Kara.botMessage("I can't remember any jokes right now, sorry. 😢");
} }
}); });
this.updateStorage(); this.updateStorage();
}, },
startQuiz() { startQuiz() {
let vue = this; let Kara = this;
let url = 'https://jservice.io/api/random'; let url = 'https://jservice.io/api/random';
axios.get(url) axios.get(url)
.then(function (response) { .then(function (response) {
let clue = response.data[0]; let clue = response.data[0];
vue.botMessage('Okay! Here is your question from the category "' + clue.category.title + '":'); Kara.botMessage('Okay! Here is your question from the category "' + clue.category.title + '":');
vue.botMessage(clue.question); Kara.botMessage(clue.question);
vue.lastMessageData = { Kara.lastMessageData = {
isTrivia: true, isTrivia: true,
answer: clue.answer answer: clue.answer
}; };
}) })
.catch(function (error) { .catch(function (error) {
vue.botMessage("It's not a good time for a quiz."); Kara.botMessage("It's not a good time for a quiz.");
}); });
this.updateStorage(); this.updateStorage();
}, },
startJeopardy() { startJeopardy() {
let vue = this; let Kara = this;
let url = 'https://jservice.io/api/random'; let url = 'https://jservice.io/api/random';
axios.get(url) axios.get(url)
.then(function (response) { .then(function (response) {
let clue = response.data[0]; let clue = response.data[0];
vue.botMessage('Okay! Here we go. The category is "' + clue.category.title + '":'); Kara.botMessage('Okay! Here we go. The category is "' + clue.category.title + '":');
vue.botMessage(clue.answer); Kara.botMessage(clue.answer);
vue.lastMessageData = { Kara.lastMessageData = {
isJeopardy: true, isJeopardy: true,
question: clue.question question: clue.question
}; };
}) })
.catch(function (error) { .catch(function (error) {
vue.botMessage("It's not a good time for a quiz."); Kara.botMessage("It's not a good time for a quiz.");
}); });
this.updateStorage(); this.updateStorage();
@ -704,53 +704,74 @@ let kara = new Vue({
// Some Random API Commands // Some Random API Commands
rsaRandomAnimalImage(animal, emoji = '😄') { rsaRandomAnimalImage(animal, emoji = '😄') {
let vue = this; let Kara = this;
Kara.startTyping();
axios.post('/api/curlJson', { axios.post('/api/curlJson', {
url: 'https://some-random-api.ml/img/' + animal url: 'https://some-random-api.ml/img/' + animal
}) })
.catch((error) => { .catch((error) => {
vue.botMessage("Sorry, i can't find any good pictures right now 🙁" + emoji); Kara.botMessage("Sorry, i can't find any good pictures right now 🙁" + emoji);
}) })
.then((response) => { .then((response) => {
vue.addImageMessage({ Kara.addImageMessage({
body: emoji, body: emoji,
src: response.data.link src: response.data.link
}, true); }, true);
}) })
}, },
rsaRandomAnimalFact(animal, emoji = '😄') { rsaRandomAnimalFact(animal, emoji = '😄') {
let vue = this; let Kara = this;
Kara.startTyping();
axios.post('/api/curlJson', { axios.post('/api/curlJson', {
url: 'https://some-random-api.ml/facts/' + animal url: 'https://some-random-api.ml/facts/' + animal
}) })
.catch((error) => { .catch((error) => {
vue.botMessage("Sorry, i can't think of any good facts right now 🙁" + emoji); Kara.botMessage("Sorry, i can't think of any good facts right now 🙁" + emoji);
}) })
.then((response) => { .then((response) => {
vue.botMessage(response.data.fact); Kara.botMessage(response.data.fact);
}) })
}, },
rsaLyrics(searchFor) { rsaLyrics(searchFor) {
let vue = this; let Kara = this;
Kara.startTyping();
axios.post('/api/curlJson', { axios.post('/api/curlJson', {
url: 'https://some-random-api.ml/lyrics/?title=' + searchFor.replace(' ', '%20') url: 'https://some-random-api.ml/lyrics/?title=' + searchFor.replace(' ', '%20')
}) })
.catch((error) => { .catch((error) => {
vue.botMessage("Hmm.. i just can't remember the lyrics, but i love that song! 🎵🎧"); Kara.botMessage("Hmm.. i just can't remember the lyrics, but i love that song! 🎵🎧");
}) })
.then((response) => { .then((response) => {
vue.addImageMessage({ Kara.addImageMessage({
body: "Here you go!<br>" + body: "Here you go!<br>" +
"<br>" + "<br>" +
response.data.title + ' from ' + response.data.author + '<br>' + response.data.title + ' from ' + response.data.author + '<br>' +
'<br>' + '<br>' +
response.data.lyrics, response.data.lyrics,
src: response.data.thumbnail.genius src: response.data.thumbnail.genius
}); }, true);
})
},
rsaBackupAnswer(message) {
let Kara = this;
Kara.startTyping();
axios.post('/api/curlJson', {
url: 'https://some-random-api.ml/chatbot?message=' + message
}) })
.catch((error) => {
Kara.botMessage("I don't know what to say..");
})
.then((response) => {
Kara.botMessage(response.data.response);
});
}, },
// LocalStorage // LocalStorage
@ -800,6 +821,13 @@ let kara = new Vue({
scrollTop: ($('#chat-box')[0].scrollHeight * 10) scrollTop: ($('#chat-box')[0].scrollHeight * 10)
}, 800); }, 800);
}, },
startTyping() {
this.isTyping = true;
},
stopTyping() {
this.scrollDown();
this.isTyping = false;
},
oneOf(answers) { oneOf(answers) {
let amountOfAnswers = answers.length; let amountOfAnswers = answers.length;
let randomIndex = Math.floor(Math.random() * (amountOfAnswers)); let randomIndex = Math.floor(Math.random() * (amountOfAnswers));
@ -876,22 +904,22 @@ let kara = new Vue({
// Ajax calls for saving/receiving reactions & themes // Ajax calls for saving/receiving reactions & themes
getBootswatchThemes() { getBootswatchThemes() {
let vue = this; let Kara = this;
axios.get('https://bootswatch.com/api/4.json') axios.get('https://bootswatch.com/api/4.json')
.then(function (response) { .then(function (response) {
vue.themes = response.data.themes; Kara.themes = response.data.themes;
}) })
.catch(function (error) { .catch(function (error) {
console.log(error); console.log(error);
}) })
}, },
getReactions() { getReactions() {
let vue = this; let Kara = this;
axios.get('/reactions/get').then((response) => { axios.get('/reactions/get').then((response) => {
response.data.forEach((reaction) => { response.data.forEach((reaction) => {
vue.reactions.push(JSON.parse(reaction.reaction)); Kara.reactions.push(JSON.parse(reaction.reaction));
}); });
}).catch((error) => { }).catch((error) => {
console.log(error); console.log(error);

74
documentation.md

@ -0,0 +1,74 @@
#### Commands
##### ```/clear```
Clears the chat.
##### ```/say```
Repeats your message.
##### ```/todo```
Adds a new todo to the list.\
Todos can be viewed by clicking on the clipboard-icon in the upper right.
##### ```/weather```
Tells you the weather in your location.\
Your location can be set in the settings.\
\
Can be triggered by messages like:
- _How is the weather?_
##### ```/joke```
Tells a joke with an opener and a delayed punchline.\
Categories are: general (default), knock-knock, programming
\
Can be triggered by messages like:
- _Tell me a joke_
- _Tell me a knock knock joke_
- _Tell me a programming joke_
##### ```/meme```
Sends a random meme from reddit.\
You can pass a subreddit of your choice (Yes, NSFW too..)
\
Some predefined meme-categories can be triggerd by:
- _Send me a coding meme_
- _Send me a dank meme_
- _Send me a birb meme_
##### ```/me```
Sends a classical "_User farted_" message.
##### Animal images & facts
There are a number of commands to receive random animal images & facts.\
Animals:\
_birb, dog, cat, fox, panda, red_panda & koala_
To get a fact or an image, use:
```/youranimalImg``` or ```/youranimalFact```
##### ```/lyrics```
Fetch lyrics for songs.\
Usage: ```/lyrics songname``` (you can also search for things like ```songname artist```)
##### ```/quiz```
Get a quiz-question and guess the answer.\
You can always give up by typing "i give up".
##### ```/jeopardy```
The opposite of ```/quiz```.\
Guess the right question to the given answer.
##### ```/dice```
Roll the dice!
---
#### Experimental
##### ```/talk```
Activate talking. Kara will now talk to you.\
The voice-language heavily depends on the device used.

31
index.html

@ -22,6 +22,9 @@
<div class="btn btn-sm btn-secondary" data-toggle="modal" data-target="#settingsModal"> <div class="btn btn-sm btn-secondary" data-toggle="modal" data-target="#settingsModal">
<i class="fas fa-sliders-h"></i> <i class="fas fa-sliders-h"></i>
</div> </div>
<div class="btn btn-sm btn-secondary" data-toggle="modal" data-target="#helpModal">
<i class="fas fa-question-circle"></i>
</div>
<div class="btn btn-sm btn-secondary" data-toggle="modal" data-target="#todoModal" v-if="todos.length > 0"> <div class="btn btn-sm btn-secondary" data-toggle="modal" data-target="#todoModal" v-if="todos.length > 0">
<i class="fas fa-clipboard"></i> <i class="fas fa-clipboard"></i>
</div> </div>
@ -157,6 +160,34 @@
</div> </div>
</div> </div>
</div> </div>
<div class="modal fade" id="helpModal" tabindex="-1" role="dialog" aria-labelledby="helpModal" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Documentation</h5>
</div>
<div class="modal-body">
<h6>Commands</h6>
<ul>
<li>/clear</li>
<li>/meme </li>
<li>/say </li>
<li>/joke</li>
<li>/weather</li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
<hr/>
<h6></h6>
</div>
</div>
</div>
</div>
<link rel="stylesheet" :href="'https://maxcdn.bootstrapcdn.com/bootswatch/4.3.1/' + activeTheme + '/bootstrap.min.css'"> <link rel="stylesheet" :href="'https://maxcdn.bootstrapcdn.com/bootswatch/4.3.1/' + activeTheme + '/bootstrap.min.css'">
<link href="app.css" rel="stylesheet" type="text/css"/> <link href="app.css" rel="stylesheet" type="text/css"/>
</div> </div>

Loading…
Cancel
Save