From ca6b8c3f9c85f0947221e4982bcac6ca4e6acd69 Mon Sep 17 00:00:00 2001 From: Kevin Dang <77701718+kevinthedang@users.noreply.github.com> Date: Wed, 7 Feb 2024 09:59:06 -0800 Subject: [PATCH] Docker Container Setup (#15) * minor package update and env * added docker scripts * added working docker compose * fixed docker container bridge --- .env.sample | 14 +- .gitignore | 2 + Dockerfile | 18 +++ README.md | 4 + docker-compose.yml | 45 ++++++ package-lock.json | 314 ++---------------------------------- package.json | 11 +- src/client.ts | 8 +- src/events/messageCreate.ts | 4 +- src/events/ready.ts | 4 +- src/keys.ts | 4 +- src/utils/events.ts | 22 +-- src/utils/messageEmbed.ts | 11 +- 13 files changed, 124 insertions(+), 337 deletions(-) create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/.env.sample b/.env.sample index b9276ab..9e71d51 100644 --- a/.env.sample +++ b/.env.sample @@ -1,14 +1,18 @@ # Discord token for the bot -CLIENT_TOKEN = INSERT_BOT_TOKEN +CLIENT_TOKEN = BOT_TOKEN # id token of a discord server -GUILD_ID = INSERT_GUILD_ID +GUILD_ID = GUILD_ID # Channel where the bot listens to messages -CHANNEL_ID = INSERT_CHANNEL_ID +CHANNEL_ID = CHANNEL_ID # model for the bot to query from (i.e. llama2 [llama2:13b], mistral, ... ) -MODEL = INSERT_MODEL_NAME +MODEL = MODEL_NAME # discord bot user id for mentions -BOT_UID = INSERT_BOT_USER_ID \ No newline at end of file +CLIENT_UID = BOT_USER_ID + +# ip address of docker container, this will have to be found manually (docker can also change it too) +OLLAMA_IP = IP_ADDRESS +OLLAMA_PORT = PORT \ No newline at end of file diff --git a/.gitignore b/.gitignore index 2cec983..2f1ff63 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ # builds build/ dist/ +app/ +tmp/ # dotenv environment variable files .env diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1c3e12f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +# use node LTS image for version 18 +FROM node:18.18.2 + +# set working directory inside container +WORKDIR /app + +# copy package.json and the lock file into the container, and src files +COPY ./src ./src +COPY ./*.json ./ + +# install dependencies, breaks +RUN npm install + +# build the typescript code +RUN npm run build + +# start the application +CMD ["npm", "run", "prod"] diff --git a/README.md b/README.md index 3fbc019..16a021d 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,12 @@ Ollama is an AI model management tool that allows users to install and use custo * To run dev with `tsx`, you can use `v20.10.0` or earlier. * This project supports any NodeJS version above `16.x.x` to only allow ESModules. * [Ollama](https://ollama.ai/) + * [Ollama Docker Image](https://hub.docker.com/r/ollama/ollama) + * **IMPORTANT**: For Nvidia GPU setup, **install** `nvidia container toolkit` then **configure** it with Docker to utilize Nvidia driver. * [Discord Developer Portal](https://discord.com/developers/docs/intro) * [Discord.js Docs](https://discord.js.org/docs/packages/discord.js/main) +* [Setting up Docker (Ubuntu)][https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-20-04] + * [Setting up Nvidia Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html) ## Acknowledgement * [Kevin Dang](https://github.com/kevinthedang) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..21fbf65 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,45 @@ +# creates the docker compose +version: '3.7' + +# build individual services +services: + # setup discord bot container + discord: + build: ./ # find docker file in designated path + container_name: discord + restart: always # rebuild container always + environment: + CLIENT_TOKEN: ${CLIENT_TOKEN} + GUILD_ID: ${GUILD_ID} + CHANNEL_ID: ${CHANNEL_ID} + MODEL: ${MODEL} + CLIENT_UID: ${CLIENT_UID} + OLLAMA_IP: ${OLLAMA_IP} + OLLAMA_PORT: ${OLLAMA_PORT} + networks: + - ollama-net + volumes: + - discord:/src/app # docker will not make this for you, make it yourself + + # setup ollama container + ollama: + image: ollama/ollama:latest # build the image using ollama + container_name: ollama + restart: always + networks: + - ollama-net + # runtime: nvidia # use Nvidia Container Toolkit for GPU support + # devices: + # - /dev/nvidia0 + volumes: + - ollama:/root/.ollama + ports: + - 11434:11434 + +networks: + ollama-net: + driver: bridge + +volumes: + ollama: + discord: diff --git a/package-lock.json b/package-lock.json index bd22fc0..87f27fa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,18 @@ { "name": "discord-ollama", - "version": "0.1.4", + "version": "0.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "discord-ollama", - "version": "0.1.4", + "version": "0.2.0", "license": "ISC", "dependencies": { "axios": "^1.6.2", - "concurrently": "^8.2.2", "discord.js": "^14.14.1", "dotenv": "^16.3.1", - "ollama": "^0.4.3" + "ollama": "^0.4.6" }, "devDependencies": { "@types/node": "^20.10.5", @@ -26,17 +25,6 @@ "node": ">=16.0.0" } }, - "node_modules/@babel/runtime": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", - "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -603,9 +591,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.11.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.13.tgz", - "integrity": "sha512-5G4zQwdiQBSWYTDAH1ctw2eidqdhMJaNsiIDKHFr55ihz5Trl2qqR8fdrT732yPBho5gkNxXm67OxWFBqX9aPg==", + "version": "20.11.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.14.tgz", + "integrity": "sha512-w3yWCcwULefjP9DmDDsgUskrMoOy5Z8MiwKHr1FvqGPtx7CvJzQvxD7eKpxNtklQxLruxSXWddyeRtyud0RcXQ==", "dependencies": { "undici-types": "~5.26.4" } @@ -654,28 +642,6 @@ "node": ">=0.4.0" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -747,32 +713,6 @@ "node": ">=8" } }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -800,35 +740,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -846,53 +757,12 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "node_modules/concurrently": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.2.2.tgz", - "integrity": "sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==", - "dependencies": { - "chalk": "^4.1.2", - "date-fns": "^2.30.0", - "lodash": "^4.17.21", - "rxjs": "^7.8.1", - "shell-quote": "^1.8.1", - "spawn-command": "0.0.2", - "supports-color": "^8.1.1", - "tree-kill": "^1.2.2", - "yargs": "^17.7.2" - }, - "bin": { - "conc": "dist/bin/concurrently.js", - "concurrently": "dist/bin/concurrently.js" - }, - "engines": { - "node": "^14.13.0 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" - } - }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, - "node_modules/date-fns": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", - "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", - "dependencies": { - "@babel/runtime": "^7.21.0" - }, - "engines": { - "node": ">=0.11" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" - } - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -967,11 +837,6 @@ "url": "https://github.com/motdotla/dotenv?sponsor=1" } }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, "node_modules/esbuild": { "version": "0.19.12", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", @@ -1010,14 +875,6 @@ "@esbuild/win32-x64": "0.19.12" } }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "engines": { - "node": ">=6" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -1081,14 +938,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, "node_modules/get-tsconfig": { "version": "4.7.2", "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.2.tgz", @@ -1113,14 +962,6 @@ "node": ">= 6" } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, "node_modules/ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", @@ -1148,14 +989,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -1321,9 +1154,9 @@ } }, "node_modules/ollama": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/ollama/-/ollama-0.4.4.tgz", - "integrity": "sha512-vAOZ3LM3DUE98Yy+iUJHu9Y9juKmjDAMntYoe8XqGAEkJkU5ZRkO1lwJxu5sRNU6WkEQ3MoHsvgeVIWr+cQmbg==", + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/ollama/-/ollama-0.4.6.tgz", + "integrity": "sha512-/Im2atcM9hAxOgEi7mc5pG2G+MeN4jFo1bubfCzAd8bZT6nQ3he5tr+jypGufau9+WQKY0MHhTajqKTNfnlZQA==", "dependencies": { "whatwg-fetch": "^3.6.20" } @@ -1363,19 +1196,6 @@ "node": ">=8.10.0" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", @@ -1385,14 +1205,6 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, - "node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -1408,14 +1220,6 @@ "node": ">=10" } }, - "node_modules/shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/simple-update-notifier": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", @@ -1428,49 +1232,6 @@ "node": ">=10" } }, - "node_modules/spawn-command": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz", - "integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==" - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -1495,14 +1256,6 @@ "nodetouch": "bin/nodetouch.js" } }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "bin": { - "tree-kill": "cli.js" - } - }, "node_modules/ts-mixer": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz", @@ -1621,22 +1374,6 @@ "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==" }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/ws": { "version": "8.14.2", "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", @@ -1657,45 +1394,12 @@ } } }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "engines": { - "node": ">=10" - } - }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "engines": { - "node": ">=12" - } - }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/package.json b/package.json index 2c80152..ff2fa7f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "discord-ollama", - "version": "0.1.4", + "version": "0.2.0", "description": "Ollama Integration into discord", "main": "build/index.js", "exports": "./build/index.js", @@ -9,18 +9,17 @@ "dev-mon": "nodemon --config nodemon.json src/index.ts", "build": "tsc", "prod": "node .", - "client": "npm run build && npm run prod", - "API": "ollama serve", - "start": "concurrently \"npm:API\" \"npm:client\"" + "client": "npm i && npm run build && npm run prod", + "clean": "docker rmi $(docker images -a -q) -f && docker images -a", + "start": "echo \"y\" | docker-compose rm && docker-compose build && docker-compose up" }, "author": "Kevin Dang", "license": "ISC", "dependencies": { "axios": "^1.6.2", - "concurrently": "^8.2.2", "discord.js": "^14.14.1", "dotenv": "^16.3.1", - "ollama": "^0.4.3" + "ollama": "^0.4.6" }, "devDependencies": { "@types/node": "^20.10.5", diff --git a/src/client.ts b/src/client.ts index d968145..56dd83d 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,6 +1,7 @@ import { Client, GatewayIntentBits } from 'discord.js' import { registerEvents } from './utils/events.js' import Events from './events/index.js' +import { Ollama } from 'ollama' // Import keys/tokens import Keys from './keys.js' @@ -16,6 +17,11 @@ const client = new Client({ ] }); +// initialize connection to ollama container +const ollama = new Ollama({ + host: `http://${Keys.ipAddress}:${Keys.portAddress}`, +}) + const messageHistory = [ { role: 'system', @@ -30,7 +36,7 @@ const messageHistory = [ * @param client the bot reference * @param Keys tokens from .env files */ -registerEvents(client, Events, messageHistory, Keys) +registerEvents(client, Events, messageHistory, Keys, ollama) // Try to log in the client await client.login(Keys.clientToken) diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts index 1b53f7e..bb01e51 100644 --- a/src/events/messageCreate.ts +++ b/src/events/messageCreate.ts @@ -4,7 +4,7 @@ import { embedMessage, event, Events } from '../utils/index.js' * Max Message length for free users is 2000 characters (bot or not). * @param message the message received from the channel */ -export default event(Events.MessageCreate, async ({ log, msgHist, tokens }, message) => { +export default event(Events.MessageCreate, async ({ log, msgHist, tokens, ollama }, message) => { log(`Message created \"${message.content}\" from ${message.author.tag}.`) // Hard-coded channel to test output there only, in our case "ollama-endpoint" @@ -23,7 +23,7 @@ export default event(Events.MessageCreate, async ({ log, msgHist, tokens }, mess }) // Try to query and send embed - const response = await embedMessage(message, tokens, msgHist) + const response = await embedMessage(message, ollama, tokens, msgHist) // Try to query and send message // log(normalMessage(message, tokens, msgHist)) diff --git a/src/events/ready.ts b/src/events/ready.ts index 3b7ff6b..8744e40 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -4,8 +4,6 @@ import commands from '../commands/index.js' // Log when the bot successfully logs in and export it export default event(Events.ClientReady, ({ log }, client) => { - log(`Logged in as ${client.user.username}.`) - // Register the commands associated with the bot upon loggin in registerCommands(client, commands) @@ -14,4 +12,6 @@ export default event(Events.ClientReady, ({ log }, client) => { name: 'Powered by Ollama', type: ActivityType.Custom }) + + log(`Logged in as ${client.user.username}.`) }) \ No newline at end of file diff --git a/src/keys.ts b/src/keys.ts index 401c0b7..20c6db6 100644 --- a/src/keys.ts +++ b/src/keys.ts @@ -5,7 +5,9 @@ export const Keys = { channel: getEnvVar('CHANNEL_ID'), model: getEnvVar('MODEL'), clientUid: getEnvVar('CLIENT_UID'), - guildId: getEnvVar('GUILD_ID') + guildId: getEnvVar('GUILD_ID'), + ipAddress: getEnvVar('OLLAMA_IP'), + portAddress: getEnvVar('OLLAMA_PORT') } as const // readonly keys export default Keys \ No newline at end of file diff --git a/src/utils/events.ts b/src/utils/events.ts index 447c922..fbc9434 100644 --- a/src/utils/events.ts +++ b/src/utils/events.ts @@ -1,21 +1,24 @@ import type { ClientEvents, Awaitable, Client } from 'discord.js' +import { Ollama } from 'ollama' // Export events through here to reduce amount of imports export { Events } from 'discord.js' export type LogMethod = (...args: unknown[]) => void export type EventKeys = keyof ClientEvents // only wants keys of ClientEvents object +export type Tokens = { + channel: string, + model: string, + clientUid: string +} // Event properties export interface EventProps { client: Client log: LogMethod msgHist: { role: string, content: string }[] - tokens: { - channel: string, - model: string, - clientUid: string - } + tokens: Tokens, + ollama: Ollama } export type EventCallback = ( props: EventProps, @@ -36,11 +39,8 @@ export function registerEvents( client: Client, events: Event[], msgHist: { role: string, content: string }[], - tokens: { - channel: string, - model: string, - clientUid: string - } + tokens: Tokens, + ollama: Ollama ): void { for (const { key, callback } of events) { client.on(key, (...args) => { @@ -49,7 +49,7 @@ export function registerEvents( // Handle Errors, call callback, log errors as needed try { - callback({ client, log, msgHist, tokens }, ...args) + callback({ client, log, msgHist, tokens, ollama }, ...args) } catch (error) { log('[Uncaught Error]', error) } diff --git a/src/utils/messageEmbed.ts b/src/utils/messageEmbed.ts index 4d7de0d..1f05771 100644 --- a/src/utils/messageEmbed.ts +++ b/src/utils/messageEmbed.ts @@ -1,5 +1,5 @@ import { EmbedBuilder, Message } from 'discord.js' -import ollama, { ChatResponse } from 'ollama' +import { ChatResponse, Ollama } from 'ollama' /** * Method to send replies as normal text on discord like any other user @@ -8,7 +8,8 @@ import ollama, { ChatResponse } from 'ollama' * @param msgHist message history between user and model */ export async function embedMessage( - message: Message, + message: Message, + ollama: Ollama, tokens: { channel: string, model: string @@ -44,17 +45,19 @@ export async function embedMessage( stream: false }) + // dummy message to let user know that query is underway const newEmbed = new EmbedBuilder() .setTitle(`Responding to ${message.author.tag}`) - .setDescription(response.message.content) + .setDescription(response.message.content || 'No Content to Provided...') .setColor('#00FF00') // edit the message sentMessage.edit({ embeds: [newEmbed] }) } catch(error: any) { + console.log(`[Event: messageEmbed] Error creating message: ${error.message}`); const errorEmbed = new EmbedBuilder() .setTitle(`Responding to ${message.author.tag}`) - .setDescription(error.error) + .setDescription(`Issue creating response: ${error.message}`) .setColor('#00FF00') // send back error