From f7a5953a309840d6feba3cf20f130e0bba296d81 Mon Sep 17 00:00:00 2001 From: Earnest Angel <57413115+earnestangel@users.noreply.github.com> Date: Fri, 15 Sep 2023 20:13:47 +0800 Subject: [PATCH] Implement RirikoLLaMA (self hosted OpenLLaMA for Ririko AI bot), replace deprecated OpenAI model (davinci 003) with 002, code cleanup (#236) * Add a new provider: RirikoLLaMA - allowing you to host your own GPT model at home * Remove openai text-davinci-003 (deprecated model) and replace with text-davinci-002 * Cleanup code in ririko stream checker * 0.11.0 --- config.example.js | 11 +- package-lock.json | 146 +++++++++++++++++++- package.json | 4 +- src/app/Providers/AI/OpenAIProvider.js | 5 +- src/app/Providers/AI/RirikoLLaMAProvider.js | 57 ++++++++ src/app/RirikoAI-NLP.js | 5 +- src/helpers/getconfig.js | 9 ++ src/ririkoStreamChecker.js | 2 - 8 files changed, 228 insertions(+), 11 deletions(-) create mode 100644 src/app/Providers/AI/RirikoLLaMAProvider.js diff --git a/config.example.js b/config.example.js index bc06cbfa..d722d5ca 100644 --- a/config.example.js +++ b/config.example.js @@ -66,13 +66,18 @@ module.exports = { // Prefix of the AI part of the bot Prefix: ".", - // The provider to use for the bot. Must be one of: NLPCloudProvider or OpenAIProvider + // The provider to use for the bot. Must be one of: NLPCloudProvider | OpenAIProvider | RirikoLLaMAProvider Provider: "OpenAIProvider", // Provider Token Token: "", - GPTModel: "davinci", // Must be one of: davinci or gpt35 + // Must be one of: davinci or gpt35 + GPTModel: "gpt35", + + // 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: "", // Enable or disable the Whitelist. EnableWhitelist: true, @@ -277,5 +282,5 @@ module.exports = { LogDir: "logs", }, - VERSION: "6", // DO NOT TOUCH + VERSION: "7", // DO NOT TOUCH }; diff --git a/package-lock.json b/package-lock.json index 14a91089..5a98d6ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ririko", - "version": "0.10.0", + "version": "0.11.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ririko", - "version": "0.10.0", + "version": "0.11.0", "license": "MIT", "dependencies": { "@discordjs/builders": "^1.6.3", @@ -59,6 +59,7 @@ "quick.db": "^9.1.6", "redis": "^4.6.7", "replicate": "^0.17.0", + "ririkollama-bot-client": "^1.0.0", "save-dev": "^0.0.1-security", "semver": "^7.5.3", "source-map-support": "^0.5.21", @@ -76,6 +77,7 @@ "@babel/preset-env": "^7.22.5", "babel-plugin-module-resolver": "^5.0.0", "babel-plugin-source-map-support": "^2.2.0", + "babel-preset-env": "^1.7.0", "babel-preset-es2015": "^6.24.1", "babel-preset-minify": "^0.5.2", "nodemon": "^3.0.1" @@ -3611,6 +3613,17 @@ "node": ">=0.8.0" } }, + "node_modules/babel-helper-builder-binary-assignment-operator-visitor": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", + "integrity": "sha512-gCtfYORSG1fUMX4kKraymq607FWgMWg+j42IFPc18kFQEsmtaibP4UrqsXt8FlEJle25HUd4tsoDR7H2wDhe9Q==", + "dev": true, + "dependencies": { + "babel-helper-explode-assignable-expression": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, "node_modules/babel-helper-call-delegate": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", @@ -3641,6 +3654,17 @@ "integrity": "sha512-mUh0UhS607bGh5wUMAQfOpt2JX2ThXMtppHRdRU1kL7ZLRWIXxoV2UIV1r2cAeeNeU1M5SB5/RSUgUxrK8yOkA==", "dev": true }, + "node_modules/babel-helper-explode-assignable-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", + "integrity": "sha512-qe5csbhbvq6ccry9G7tkXbzNtcDiH4r51rrPUbwwoTzZ18AqxWYRZT6AOmxrpxKnQBW0pYlBI/8vh73Z//78nQ==", + "dev": true, + "dependencies": { + "babel-runtime": "^6.22.0", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, "node_modules/babel-helper-flip-expressions": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.4.3.tgz", @@ -3719,6 +3743,19 @@ "lodash": "^4.17.4" } }, + "node_modules/babel-helper-remap-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", + "integrity": "sha512-RYqaPD0mQyQIFRu7Ho5wE2yvA/5jxqCIj/Lv4BXNq23mHYu/vxikOy2JueLiBxQknwapwrJeNCesvY0ZcfnlHg==", + "dev": true, + "dependencies": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, "node_modules/babel-helper-remove-or-void": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.4.3.tgz", @@ -4114,6 +4151,35 @@ "@babel/helper-module-imports": "^7.16.7" } }, + "node_modules/babel-plugin-syntax-async-functions": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", + "integrity": "sha512-4Zp4unmHgw30A1eWI5EpACji2qMocisdXhAftfhXoSV9j0Tvj6nRFE3tOmRY912E0FMRm/L5xWE7MGVT2FoLnw==", + "dev": true + }, + "node_modules/babel-plugin-syntax-exponentiation-operator": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", + "integrity": "sha512-Z/flU+T9ta0aIEKl1tGEmN/pZiI1uXmCiGFRegKacQfEJzp7iNsKloZmyJlQr+75FCJtiFfGIK03SiCvCt9cPQ==", + "dev": true + }, + "node_modules/babel-plugin-syntax-trailing-function-commas": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", + "integrity": "sha512-Gx9CH3Q/3GKbhs07Bszw5fPTlU+ygrOGfAhEt7W2JICwufpC4SuO0mG0+4NykPBSYPMJhqvVlDBU17qB1D+hMQ==", + "dev": true + }, + "node_modules/babel-plugin-transform-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", + "integrity": "sha512-7BgYJujNCg0Ti3x0c/DL3tStvnKS6ktIYOmo9wginv/dfZOrbSZ+qG4IRRHMBOzZ5Awb1skTiAsQXg/+IWkZYw==", + "dev": true, + "dependencies": { + "babel-helper-remap-async-to-generator": "^6.24.1", + "babel-plugin-syntax-async-functions": "^6.8.0", + "babel-runtime": "^6.22.0" + } + }, "node_modules/babel-plugin-transform-es2015-arrow-functions": { "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", @@ -4380,6 +4446,17 @@ "regjsparser": "bin/parser" } }, + "node_modules/babel-plugin-transform-exponentiation-operator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", + "integrity": "sha512-LzXDmbMkklvNhprr20//RStKVcT8Cu+SQtX18eMHLhjHf2yFzwtQ0S2f0jQ+89rokoNdmwoSqYzAhq86FxlLSQ==", + "dev": true, + "dependencies": { + "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1", + "babel-plugin-syntax-exponentiation-operator": "^6.8.0", + "babel-runtime": "^6.22.0" + } + }, "node_modules/babel-plugin-transform-inline-consecutive-adds": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.4.3.tgz", @@ -4504,6 +4581,66 @@ "@babel/core": "^7.0.0" } }, + "node_modules/babel-preset-env": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz", + "integrity": "sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg==", + "dev": true, + "dependencies": { + "babel-plugin-check-es2015-constants": "^6.22.0", + "babel-plugin-syntax-trailing-function-commas": "^6.22.0", + "babel-plugin-transform-async-to-generator": "^6.22.0", + "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoping": "^6.23.0", + "babel-plugin-transform-es2015-classes": "^6.23.0", + "babel-plugin-transform-es2015-computed-properties": "^6.22.0", + "babel-plugin-transform-es2015-destructuring": "^6.23.0", + "babel-plugin-transform-es2015-duplicate-keys": "^6.22.0", + "babel-plugin-transform-es2015-for-of": "^6.23.0", + "babel-plugin-transform-es2015-function-name": "^6.22.0", + "babel-plugin-transform-es2015-literals": "^6.22.0", + "babel-plugin-transform-es2015-modules-amd": "^6.22.0", + "babel-plugin-transform-es2015-modules-commonjs": "^6.23.0", + "babel-plugin-transform-es2015-modules-systemjs": "^6.23.0", + "babel-plugin-transform-es2015-modules-umd": "^6.23.0", + "babel-plugin-transform-es2015-object-super": "^6.22.0", + "babel-plugin-transform-es2015-parameters": "^6.23.0", + "babel-plugin-transform-es2015-shorthand-properties": "^6.22.0", + "babel-plugin-transform-es2015-spread": "^6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "^6.22.0", + "babel-plugin-transform-es2015-template-literals": "^6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "^6.23.0", + "babel-plugin-transform-es2015-unicode-regex": "^6.22.0", + "babel-plugin-transform-exponentiation-operator": "^6.22.0", + "babel-plugin-transform-regenerator": "^6.22.0", + "browserslist": "^3.2.6", + "invariant": "^2.2.2", + "semver": "^5.3.0" + } + }, + "node_modules/babel-preset-env/node_modules/browserslist": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz", + "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==", + "dev": true, + "dependencies": { + "caniuse-lite": "^1.0.30000844", + "electron-to-chromium": "^1.3.47" + }, + "bin": { + "browserslist": "cli.js" + } + }, + "node_modules/babel-preset-env/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, "node_modules/babel-preset-es2015": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz", @@ -11095,6 +11232,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/ririkollama-bot-client": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ririkollama-bot-client/-/ririkollama-bot-client-1.0.0.tgz", + "integrity": "sha512-YfAYXmL4VHaj2LjEhFf+EeO/FaTyuthk2rPhkBFEPbXRp0SsXWns/JL6cS6U6IsXJyIpcTc35vxJ2f8i4O/PRQ==" + }, "node_modules/safe-array-concat": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", diff --git a/package.json b/package.json index 66177691..f9e3525e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ririko", - "version": "0.10.0", + "version": "0.11.0", "description": "Ririko - A powerful AI-powered general Discord bot that you can call your companion", "author": "Earnest Angel", "email": "me@angel.net.my", @@ -91,6 +91,7 @@ "quick.db": "^9.1.6", "redis": "^4.6.7", "replicate": "^0.17.0", + "ririkollama-bot-client": "^1.0.0", "save-dev": "^0.0.1-security", "semver": "^7.5.3", "source-map-support": "^0.5.21", @@ -105,6 +106,7 @@ "@babel/preset-env": "^7.22.5", "babel-plugin-module-resolver": "^5.0.0", "babel-plugin-source-map-support": "^2.2.0", + "babel-preset-env": "^1.7.0", "babel-preset-es2015": "^6.24.1", "babel-preset-minify": "^0.5.2", "nodemon": "^3.0.1" diff --git a/src/app/Providers/AI/OpenAIProvider.js b/src/app/Providers/AI/OpenAIProvider.js index 98cff119..c715d200 100644 --- a/src/app/Providers/AI/OpenAIProvider.js +++ b/src/app/Providers/AI/OpenAIProvider.js @@ -63,9 +63,10 @@ class OpenAIProvider extends AIProviderBase { return response.data.choices[0].message.content; // Uncomment for GPT-3.5-turbo } else if (model === "davinci") { - // Send request to OpenAI for text-davinci-003 + // Send request to OpenAI for text-davinci-002 + // NOTE: text-davinci-003 is now removed from OpenAI API const response = await this.openAiClient.createCompletion({ - model: "text-davinci-003", + model: "text-davinci-002", prompt, temperature: 1, max_tokens: 2000, diff --git a/src/app/Providers/AI/RirikoLLaMAProvider.js b/src/app/Providers/AI/RirikoLLaMAProvider.js new file mode 100644 index 00000000..5afe186a --- /dev/null +++ b/src/app/Providers/AI/RirikoLLaMAProvider.js @@ -0,0 +1,57 @@ +const {RirikoLLaMAClient} = require("ririkollama-bot-client"); +const {AIProviderBase} = require("app/Providers/AIProviderBase"); +const config = require("config"); +const getconfig = require("helpers/getconfig"); + +class RirikoLLaMAProvider extends AIProviderBase { + constructor() { + super(); + this.ririkoLlamaClient = new RirikoLLaMAClient({ + apiUrl: getconfig.localAIServerURL(), + token: this.token = getconfig.AIToken(), + settings: { + "max_new_tokens": 30, + "temperature": 1.0, + "repetition_penalty": 1, + "top_p": 0.2, + "start": "", + "break": "\nHuman:" + } + }); + } + + getClient() { + return this.ririkoLlamaClient; + } + + /** + * Send chat to NLP Cloud + * @param {String} messageText + * @param {String} context + * @param {Array} history + * @returns {Promise<*>} + */ + async sendChat(messageText, context, history) { + try { + let prompt = context + history.join("\n"); + prompt = prompt.replace(/\n$/, ''); + + prompt += "\nHuman: " + messageText + "\nFriend:"; + + // Send request to NLP Cloud. + const response = await this.ririkoLlamaClient.ask( + prompt, + ); + + if (typeof response.data["answer"] !== "undefined") { + return response.data["answer"]; + } else { + return "(no response)"; + } + } catch (e) { + throw e; + } + } +} + +module.exports = {RirikoLLaMAProvider}; diff --git a/src/app/RirikoAI-NLP.js b/src/app/RirikoAI-NLP.js index 5c413c14..e97b0eed 100644 --- a/src/app/RirikoAI-NLP.js +++ b/src/app/RirikoAI-NLP.js @@ -3,8 +3,9 @@ */ const colors = require("colors"); -const { OpenAIProvider } = require("./Providers/AI/OpenAIProvider"); +const { OpenAIProvider } = require("app/Providers/AI/OpenAIProvider"); const { NLPCloudProvider } = require("app/Providers/AI/NLPCloudProvider"); +const { RirikoLLaMAProvider } = require("app/Providers/AI/RirikoLLaMAProvider"); const getconfig = require("helpers/getconfig"); const { AIProvider, AIPersonality, AIPrompts } = require("helpers/getconfig"); @@ -56,6 +57,8 @@ class RirikoAINLP { } else if (AIProvider() === "OpenAIProvider") { // If the provider is OpenAIProvider, initialize the OpenAIProvider this.provider = new OpenAIProvider(); + } else if (AIProvider() === 'RirikoLLaMAProvider') { + this.provider = new RirikoLLaMAProvider(); } // AI provider has been initialized diff --git a/src/helpers/getconfig.js b/src/helpers/getconfig.js index 25b1350c..08a976b5 100644 --- a/src/helpers/getconfig.js +++ b/src/helpers/getconfig.js @@ -224,6 +224,14 @@ const replicateToken = () => { return process.env.REPLICATE_TOKEN || config.StableDiffusion.ReplicateToken; }; +/** + * @version 7 + * @returns {*|string} AI token + */ +const localAIServerURL = () => { + return process.env.AI_LOCAL_SERVER_URL || config.AI.LocalServerURL; +}; + module.exports = { port, language, @@ -248,5 +256,6 @@ module.exports = { geniusEnabled, lyristUrl, lyristEnabled, + localAIServerURL, replicateToken, }; diff --git a/src/ririkoStreamChecker.js b/src/ririkoStreamChecker.js index ea65883f..396544df 100644 --- a/src/ririkoStreamChecker.js +++ b/src/ririkoStreamChecker.js @@ -188,8 +188,6 @@ async function fetchStreamersInfo(streams) { if (streams.onlineStreamers.length === 0) return; if (!accessToken) await twitchLogin(); - console.log('accessToken', accessToken) - let onlineStreamers = [], streamerDetails = [], users;