Skip to content

Commit

Permalink
Implement Ririko HuggingChat Support (#245)
Browse files Browse the repository at this point in the history
* Add support for Ririko HuggingChat Server

* 0.12.0
  • Loading branch information
earnestangel authored Sep 24, 2023
1 parent 40872de commit f746a20
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 110 deletions.
10 changes: 7 additions & 3 deletions config.example.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ module.exports = {
// Prefix of the AI part of the bot
Prefix: ".",

// The provider to use for the bot. Must be one of: NLPCloudProvider | OpenAIProvider | RirikoLLaMAProvider
// The provider to use for the bot. Must be one of:
// NLPCloudProvider | OpenAIProvider | RirikoLLaMAProvider | RirikoHuggingChatProvider
Provider: "OpenAIProvider",

// Provider Token
Expand All @@ -77,7 +78,7 @@ module.exports = {

// URL of the local server for Ririko AI. Leave this empty if you don't have a local server.
// Example: http://localhost:5000/api/v1/ask
LocalServerURL: "",
LocalServerURL: "http://localhost:5000/api/v1/ask",

// Enable or disable the Whitelist.
EnableWhitelist: true,
Expand All @@ -87,6 +88,8 @@ module.exports = {
* It is also possible to make Ririko cosplay as someone - you gotta try to experiment them it's fun :)
* Placeholders:
* - %CURRENT_TIME% = to always include current time in the prompt, will be replaced in RirikoAI-NLP
*
* Does not work with RirikoHuggingChatProvider (for now)
*/
Personality: [
"This is a chat between a [Human] and [Friend]. ",
Expand All @@ -97,11 +100,12 @@ module.exports = {
],

// This is the past prompts, also adds the abilities
// Does not work with RirikoHuggingChatProvider (for now)
Prompts: [
"Human: When you're asked to play any song, please reply with this format: Now playing 🎵 insert the song title here 🎵",
"Friend: Understood! I will play the song you requested in the given format whenever you ask me to do so.",
"Human: Also, when you're asked to play a link similar to these https://www.youtube.com/ or https://open.spotify.com/, " +
"reply with this format: Now playing 🎵 insert the link here 🎵",
"reply with this format: Now playing 🎵 insert the link here 🎵",
"Friend: Understood! I'll always use the format asked to play a link.",
"Human: Play https://youtube.com/watch?v=Lh63pBzylFg",
"Friend: Sure! Now Playing 🎵 https://youtube.com/watch?v=Lh63pBzylFg 🎵",
Expand Down
98 changes: 8 additions & 90 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ririko",
"version": "0.11.0",
"version": "0.12.0",
"description": "Ririko - A powerful AI-powered general Discord bot that you can call your companion",
"author": "Earnest Angel",
"email": "[email protected]",
Expand Down Expand Up @@ -89,8 +89,8 @@
"pino-pretty": "^10.0.0",
"pretty-ms": "^8.0.0",
"quick.db": "^9.1.6",
"redis": "^4.6.7",
"replicate": "^0.17.0",
"ririkohuggingchat-bot-client": "^1.0.1",
"ririkollama-bot-client": "^1.0.0",
"save-dev": "^0.0.1-security",
"semver": "^7.5.3",
Expand Down
48 changes: 48 additions & 0 deletions src/app/Providers/AI/RirikoHuggingChatProvider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
const {RirikoHuggingChatClient} = require("ririkohuggingchat-bot-client");
const {AIProviderBase} = require("app/Providers/AIProviderBase");
const config = require("config");
const getconfig = require("helpers/getconfig");

class RirikoHuggingChatProvider extends AIProviderBase {
constructor() {
super();
this.ririkoHuggingChatClient = new RirikoHuggingChatClient({
apiUrl: getconfig.localAIServerURL(),
token: this.token = getconfig.AIToken(),
settings: {
}
});
}

getClient() {
return this.ririkoHuggingChatClient;
}

/**
* Send chat to NLP Cloud
* @param {String} messageText
* @param {String} context
* @param {Array} history
* @param discordMessage
* @returns {Promise<*>}
*/
async sendChat(messageText, context, history, discordMessage) {
try {
// Send request to NLP Cloud.
const response = await this.ririkoHuggingChatClient.ask(
messageText,
discordMessage.author.username
);

if (typeof response.data["answer"] !== "undefined") {
return response.data["answer"];
} else {
return "(no response)";
}
} catch (e) {
throw e;
}
}
}

module.exports = {RirikoHuggingChatProvider};
4 changes: 2 additions & 2 deletions src/app/Providers/AIProviderBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ class AIProviderBase {
* set as the AI's personality.
* @param history {*} Some providers requires the chat history to be in a separate payload,
* but oftentimes can be combined with the context parameter.
*
* @param discordMessage (Optional) Discord Message object
* Returns response from the provider as string.
* @returns {Promise<string>} Response from the provider
*/
async sendChat(messageText, context, history) {}
async sendChat(messageText, context, history, discordMessage) {}
}

module.exports = { AIProviderBase };
31 changes: 18 additions & 13 deletions src/app/RirikoAI-NLP.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const colors = require("colors");
const { OpenAIProvider } = require("app/Providers/AI/OpenAIProvider");
const { NLPCloudProvider } = require("app/Providers/AI/NLPCloudProvider");
const { RirikoLLaMAProvider } = require("app/Providers/AI/RirikoLLaMAProvider");
const { RirikoHuggingChatProvider } = require("app/Providers/AI/RirikoHuggingChatProvider");

const getconfig = require("helpers/getconfig");
const { AIProvider, AIPersonality, AIPrompts } = require("helpers/getconfig");
Expand Down Expand Up @@ -59,6 +60,8 @@ class RirikoAINLP {
this.provider = new OpenAIProvider();
} else if (AIProvider() === 'RirikoLLaMAProvider') {
this.provider = new RirikoLLaMAProvider();
} else if (AIProvider() === 'RirikoHuggingChatProvider') {
this.provider = new RirikoHuggingChatProvider();
}

// AI provider has been initialized
Expand Down Expand Up @@ -155,7 +158,7 @@ class RirikoAINLP {

const currentToken = this.calculateTokenWithEverything(discordMessage);

let answer = await this.sendChatRequest(messageText, chatHistory);
let answer = await this.sendChatRequest(messageText, chatHistory, discordMessage);

if (!answer) {
return await this.retryAsk(messageText, discordMessage);
Expand All @@ -179,13 +182,15 @@ class RirikoAINLP {
* Send the chat request to the AI provider
* @param {String} messageText
* @param {Array} chatHistory
* @param discordMessage
* @returns {Promise<*>}
*/
async sendChatRequest(messageText, chatHistory) {
async sendChatRequest(messageText, chatHistory, discordMessage) {
return await this.provider.sendChat(
messageText,
this.getPersonalitiesAndAbilities(),
chatHistory
chatHistory,
discordMessage
);
}

Expand Down Expand Up @@ -215,17 +220,17 @@ class RirikoAINLP {
logTokenCost(totalToken) {
console.info(
"[RirikoAI-NLP] Request complete, costs ".blue +
totalToken +
` tokens, that's about `.blue +
`$${(this.costPerToken * totalToken).toFixed(5)}`
totalToken +
` tokens, that's about `.blue +
`$${(this.costPerToken * totalToken).toFixed(5)}`
);
}

handleRequestError(e) {
console.error(
"Something went wrong when trying to send the request to the AI provider: " +
"Check if your API key is still valid, or if your prompts are not corrupted / too long. Also try to clear your " +
"chat history with Ririko by entering .clear in Discord."
"Check if your API key is still valid, or if your prompts are not corrupted / too long. Also try to clear your " +
"chat history with Ririko by entering .clear in Discord."
);

if (e.response) {
Expand Down Expand Up @@ -272,7 +277,7 @@ class RirikoAINLP {
// check upfront if the current message does not exceed the maxChatToken
const tokens = this.calculateToken(
this.getPersonalitiesAndAbilities() +
this.getCurrentPrompt(discordMessage)
this.getCurrentPrompt(discordMessage)
);

if (tokens > this.maxChatTokens - 1000) {
Expand Down Expand Up @@ -348,8 +353,8 @@ class RirikoAINLP {
calculateTokenWithEverything(discordMessage) {
return this.calculateToken(
this.getPersonalitiesAndAbilities() +
this.getChatHistory(discordMessage).toString() +
this.getCurrentPrompt(discordMessage)
this.getChatHistory(discordMessage).toString() +
this.getCurrentPrompt(discordMessage)
);
}

Expand All @@ -364,8 +369,8 @@ class RirikoAINLP {

console.info(
"[RirikoAI-NLP] A new request with ".blue +
chatTokens +
" tokens is being prepared.".blue
chatTokens +
" tokens is being prepared.".blue
);

return chatTokens < this.maxChatTokens;
Expand Down

0 comments on commit f746a20

Please sign in to comment.