mirror of
https://github.com/kevinthedang/discord-ollama.git
synced 2026-08-08 23:54:01 -04:00
Compare commits
9
Commits
v0.8.7
..
7a4879cdb3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a4879cdb3 | ||
|
|
2987aa386f | ||
|
|
c6af5765c8 | ||
|
|
e0888c4d7c | ||
|
|
0124da5027 | ||
|
|
effcc1fd15 | ||
|
|
b492d8f62f | ||
|
|
4aadea4611 | ||
|
|
c0e29b3bbe |
@@ -8,10 +8,10 @@ assignees: ''
|
|||||||
---
|
---
|
||||||
|
|
||||||
## Issue
|
## Issue
|
||||||
A clear and concise description of what the problem/feature is.
|
A clear and concise description of what the problem/feature is. PLease describe it as best as possible.
|
||||||
|
|
||||||
## Solution
|
## Solution
|
||||||
* Provide steps or ideals to how to implement or investigate this new feature.
|
* Provide steps or ideas to how to implement or investigate this new feature.
|
||||||
|
|
||||||
## References
|
## References
|
||||||
* Provide additional context and external references here
|
* Provide additional context and external references here
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
name: Builds
|
name: Builds
|
||||||
run-name: Validate Node and Docker Builds
|
run-name: Validate Node and Docker Builds
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
@@ -9,15 +10,16 @@ jobs:
|
|||||||
Discord-Node-Build: # test if the node install and run
|
Discord-Node-Build: # test if the node install and run
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 2
|
timeout-minutes: 2
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Node Environment lts/jod
|
- name: Set up Node Environment
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: lts/jod
|
node-version: lts/jod
|
||||||
cache: "npm"
|
cache: npm
|
||||||
|
|
||||||
- name: Install Project Dependencies
|
- name: Install Project Dependencies
|
||||||
run: |
|
run: |
|
||||||
@@ -48,11 +50,11 @@ jobs:
|
|||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Node Environment lts/jod
|
- name: Set up Node Environment
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: lts/jod
|
node-version: lts/jod
|
||||||
cache: "npm"
|
cache: npm
|
||||||
|
|
||||||
- name: Create Environment Variables
|
- name: Create Environment Variables
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -1,28 +1,32 @@
|
|||||||
name: Coverage
|
name: Coverage
|
||||||
run-name: Code Coverage
|
run-name: Code Coverage
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
|
types: [opened, synchronize, reopened, closed]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Discord-Node-Coverage:
|
Discord-Node-Coverage:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
environment: coverage
|
|
||||||
timeout-minutes: 2
|
timeout-minutes: 2
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Node Environment lts/jod
|
- name: Set up Node Environment
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: lts/jod
|
node-version: lts/jod
|
||||||
cache: "npm"
|
cache: npm
|
||||||
|
|
||||||
- name: Install Project Dependencies
|
- name: Install Project Dependencies
|
||||||
run: |
|
run: npm install
|
||||||
npm install
|
|
||||||
|
|
||||||
- name: Create Environment Variables
|
- name: Create Environment Variables
|
||||||
run: |
|
run: |
|
||||||
@@ -32,19 +36,21 @@ jobs:
|
|||||||
echo OLLAMA_PORT = ${{ secrets.OLLAMA_PORT }} >> .env
|
echo OLLAMA_PORT = ${{ secrets.OLLAMA_PORT }} >> .env
|
||||||
echo MODEL = ${{ secrets.MODEL }} >> .env
|
echo MODEL = ${{ secrets.MODEL }} >> .env
|
||||||
|
|
||||||
- name: Collect Code Coverage
|
- name: Run tests with coverage
|
||||||
run: |
|
run: npm run coverage
|
||||||
LINE_PCT=$(npm run coverage | tail -2 | head -1 | awk '{print $3}')
|
|
||||||
echo "COVERAGE=$LINE_PCT" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Upload Code Coverage
|
- name: Generate coverage badge
|
||||||
uses: schneegans/dynamic-badges-action@v1.7.0
|
uses: wjervis7/vitest-badge-action@v1.0.0
|
||||||
|
if: success() || failure()
|
||||||
with:
|
with:
|
||||||
auth: ${{ secrets.GIST_SECRET }}
|
result-type: statements
|
||||||
gistID: ${{ vars.GIST_ID }}
|
badge-text: 'Coverage (Statements)'
|
||||||
filename: coverage.json
|
badge-path: ./imgs/coverage.svg
|
||||||
label: Coverage
|
upload-badge: false
|
||||||
message: ${{ env.COVERAGE }}
|
|
||||||
valColorRange: ${{ env.COVERAGE }}
|
- name: Commit badge with merge
|
||||||
maxColorRange: 100
|
if: github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged == true
|
||||||
minColorRange: 0
|
uses: stefanzweifel/git-auto-commit-action@v7
|
||||||
|
with:
|
||||||
|
file_pattern: ./imgs/coverage.svg
|
||||||
|
commit_message: 'update with coverage badge'
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
name: Deploy
|
name: Deploy
|
||||||
run-name: Deploy Application Latest
|
run-name: Deploy Application Latest
|
||||||
on:
|
|
||||||
push:
|
on: workflow_dispatch
|
||||||
tags:
|
|
||||||
- 'v*'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Deploy-Application:
|
Deploy-Application:
|
||||||
runs-on: self-hosted
|
runs-on: self-hosted
|
||||||
environment: deploy
|
environment: deploy
|
||||||
timeout-minutes: 5
|
timeout-minutes: 5
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Repo
|
- name: Checkout Repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -39,7 +38,7 @@ jobs:
|
|||||||
git clone https://github.com/kevinthedang/discord-ollama.git ${{ secrets.PATH }}
|
git clone https://github.com/kevinthedang/discord-ollama.git ${{ secrets.PATH }}
|
||||||
cd ${{ secrets.PATH }}
|
cd ${{ secrets.PATH }}
|
||||||
|
|
||||||
- name: Install nvm and Node.js lts/jod
|
- name: Install nvm and Node.js
|
||||||
run: |
|
run: |
|
||||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
|
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
|
||||||
export NVM_DIR="$HOME/.nvm"
|
export NVM_DIR="$HOME/.nvm"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
name: Tests
|
name: Tests
|
||||||
run-name: Unit Tests
|
run-name: Unit Tests
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
@@ -21,15 +22,16 @@ jobs:
|
|||||||
Discord-Node-Test:
|
Discord-Node-Test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 2
|
timeout-minutes: 2
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Node Environment lts/jod
|
- name: Set up Node Environment
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: lts/jod
|
node-version: lts/jod
|
||||||
cache: "npm"
|
cache: npm
|
||||||
|
|
||||||
- name: Install Project Dependencies
|
- name: Install Project Dependencies
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@
|
|||||||
# Technical/Business Code Ownership
|
# Technical/Business Code Ownership
|
||||||
/src/ @kevinthedang @JT2M0L3Y
|
/src/ @kevinthedang @JT2M0L3Y
|
||||||
/tests/ @JT2M0L3Y
|
/tests/ @JT2M0L3Y
|
||||||
/.github/ @kevinthedang
|
/.github/ @kevinthedang @JT2M0L3Y
|
||||||
|
|
||||||
# Docker Ownership
|
# Docker Ownership
|
||||||
Dockerfile @kevinthedang
|
Dockerfile @kevinthedang
|
||||||
|
|||||||
@@ -4,10 +4,9 @@
|
|||||||
<h3><a href="#"></a>Ollama as your Discord AI Assistant</h3>
|
<h3><a href="#"></a>Ollama as your Discord AI Assistant</h3>
|
||||||
<p><a href="#"></a><a href="https://creativecommons.org/licenses/by/4.0/"><img alt="License" src="https://img.shields.io/badge/License-CC_BY_4.0-darkgreen.svg" /></a>
|
<p><a href="#"></a><a href="https://creativecommons.org/licenses/by/4.0/"><img alt="License" src="https://img.shields.io/badge/License-CC_BY_4.0-darkgreen.svg" /></a>
|
||||||
<a href="#"></a><a href="https://github.com/kevinthedang/discord-ollama/releases/latest"><img alt="Release" src="https://img.shields.io/github/v/release/kevinthedang/discord-ollama?logo=github" /></a>
|
<a href="#"></a><a href="https://github.com/kevinthedang/discord-ollama/releases/latest"><img alt="Release" src="https://img.shields.io/github/v/release/kevinthedang/discord-ollama?logo=github" /></a>
|
||||||
<a href="#"></a><a href="https://github.com/kevinthedang/discord-ollama/actions/workflows/build.yml"><img alt="Build Status" src="https://github.com/kevinthedang/discord-ollama/actions/workflows/build.yml/badge.svg" /></a>
|
<a href="#"></a><a href="https://github.com/kevinthedang/discord-ollama/actions/workflows/build.yml"><img alt="Builds" src="https://github.com/kevinthedang/discord-ollama/actions/workflows/build.yml/badge.svg" /></a>
|
||||||
<a href="#"></a><a href="https://github.com/kevinthedang/discord-ollama/actions/workflows/deploy.yml"><img alt="Deploy Status" src="https://github.com/kevinthedang/discord-ollama/actions/workflows/deploy.yml/badge.svg" /></a>
|
<a href="#"></a><a href="https://github.com/kevinthedang/discord-ollama/actions/workflows/test.yml"><img alt="Tests" src="https://github.com/kevinthedang/discord-ollama/actions/workflows/test.yml/badge.svg" /></a>
|
||||||
<a href="#"></a><a href="https://github.com/kevinthedang/discord-ollama/actions/workflows/test.yml"><img alt="Testing Status" src="https://github.com/kevinthedang/discord-ollama/actions/workflows/test.yml/badge.svg" /></a>
|
<a href="#"></a><a href="https://github.com/kevinthedang/discord-ollama/actions/workflows/coverage.yml"><img alt="Coverage" src="https://github.com/kevinthedang/discord-ollama/blob/main/imgs/coverage.svg?raw=true" /></a>
|
||||||
<a href="#"></a><a href="https://github.com/kevinthedang/discord-ollama/actions/workflows/coverage.yml"><img alt="Code Coverage" src="https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/kevinthedang/bc7b5dcfa16561ab02bb3df67a99b22d/raw/coverage.json"></a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
## About/Goals
|
## About/Goals
|
||||||
@@ -18,7 +17,7 @@ The project aims to:
|
|||||||
* [x] Message Persistance
|
* [x] Message Persistance
|
||||||
* [x] Containerization with Docker
|
* [x] Containerization with Docker
|
||||||
* [x] Slash Commands Compatible
|
* [x] Slash Commands Compatible
|
||||||
* [ ] Summary Command
|
* [x] Summary Command
|
||||||
* [ ] Model Info Command
|
* [ ] Model Info Command
|
||||||
* [ ] List Models Command
|
* [ ] List Models Command
|
||||||
* [x] Pull Model Command
|
* [x] Pull Model Command
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ services:
|
|||||||
build: ./ # find docker file in designated path
|
build: ./ # find docker file in designated path
|
||||||
container_name: discord
|
container_name: discord
|
||||||
restart: always # rebuild container always
|
restart: always # rebuild container always
|
||||||
image: kevinthedang/discord-ollama:0.8.7
|
image: kevinthedang/discord-ollama:0.9.1
|
||||||
environment:
|
environment:
|
||||||
CLIENT_TOKEN: ${CLIENT_TOKEN}
|
CLIENT_TOKEN: ${CLIENT_TOKEN}
|
||||||
OLLAMA_IP: ${OLLAMA_IP}
|
OLLAMA_IP: ${OLLAMA_IP}
|
||||||
|
|||||||
Generated
+484
-384
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "discord-ollama",
|
"name": "discord-ollama",
|
||||||
"version": "0.8.7",
|
"version": "0.9.1",
|
||||||
"description": "Ollama Integration into discord",
|
"description": "Ollama Integration into discord",
|
||||||
"main": "build/index.js",
|
"main": "build/index.js",
|
||||||
"exports": "./build/index.js",
|
"exports": "./build/index.js",
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { ClearUserChannelHistory } from './cleanUserChannelHistory.js'
|
|||||||
import { PullModel } from './pullModel.js'
|
import { PullModel } from './pullModel.js'
|
||||||
import { SwitchModel } from './switchModel.js'
|
import { SwitchModel } from './switchModel.js'
|
||||||
import { DeleteModel } from './deleteModel.js'
|
import { DeleteModel } from './deleteModel.js'
|
||||||
|
import { Summary } from './summary.js'
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
ThreadCreate,
|
ThreadCreate,
|
||||||
@@ -20,5 +21,6 @@ export default [
|
|||||||
ClearUserChannelHistory,
|
ClearUserChannelHistory,
|
||||||
PullModel,
|
PullModel,
|
||||||
SwitchModel,
|
SwitchModel,
|
||||||
DeleteModel
|
DeleteModel,
|
||||||
|
Summary
|
||||||
] as SlashCommand[]
|
] as SlashCommand[]
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import { Client, CommandInteraction, Message, MessageFlags, SendableChannels } from "discord.js";
|
||||||
|
import { accessChannelContext, normalMessage, SlashCommand, summarizeContextHistory, UserCommand, UserMessage } from "../utils/index.js";
|
||||||
|
import { ollama } from "../client.js"
|
||||||
|
|
||||||
|
export const Summary: SlashCommand = {
|
||||||
|
name: 'summary',
|
||||||
|
description: 'provides a summary of the chat history.',
|
||||||
|
|
||||||
|
// Generate Summary from additional context
|
||||||
|
run: async (client: Client, interaction: CommandInteraction) => {
|
||||||
|
// fetch channel
|
||||||
|
const channel = await client.channels.fetch(interaction.channelId)
|
||||||
|
if (!channel || !UserCommand.includes(channel.type)) return
|
||||||
|
|
||||||
|
// Defer
|
||||||
|
await interaction.deferReply({ flags: MessageFlags.Ephemeral })
|
||||||
|
|
||||||
|
// create summary using context
|
||||||
|
let channelContext: UserMessage[] = await new Promise((resolve) => {
|
||||||
|
accessChannelContext(interaction.channelId, (additionalContext) => {
|
||||||
|
if (additionalContext?.messages)
|
||||||
|
resolve(additionalContext.messages)
|
||||||
|
else
|
||||||
|
resolve([])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
if (channelContext.length === 0) {
|
||||||
|
interaction.reply({
|
||||||
|
content: `There are no recent chat messages in this channel.`,
|
||||||
|
flags: MessageFlags.Ephemeral
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push summarize prompt
|
||||||
|
channelContext.push({
|
||||||
|
role: "user",
|
||||||
|
content: "Please Summarize everything from the prior messages, provide in bullet point fashion on what people have said prior. For example: \"Someone mentioned/talked about ...\"",
|
||||||
|
images: []
|
||||||
|
})
|
||||||
|
|
||||||
|
// todo: instead of a default of codellama, we can user default model somehow. Look into later.
|
||||||
|
const response: string = await summarizeContextHistory(ollama, "codellama", channelContext)
|
||||||
|
|
||||||
|
console.log(response)
|
||||||
|
|
||||||
|
interaction.editReply({ content: response })
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -89,6 +89,21 @@ export async function addToChannelContext(filename: string, channel : TextChanne
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function accessChannelContext(filename: string, callback: (config: Channel | undefined) => void): Promise<void> {
|
||||||
|
const fullFileName = `data/${filename}-context.json`
|
||||||
|
if (fs.existsSync(fullFileName)) {
|
||||||
|
fs.readFile(fullFileName, 'utf8', (error, data) => {
|
||||||
|
if (error) {
|
||||||
|
callback(undefined)
|
||||||
|
return // something went wrong... stop
|
||||||
|
}
|
||||||
|
callback(JSON.parse(data))
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
callback(undefined) // file not found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to open the channel history
|
* Method to open the channel history
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -90,6 +90,38 @@ export async function normalMessage(
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function summarizeContextHistory(
|
||||||
|
ollama: Ollama,
|
||||||
|
model: string,
|
||||||
|
msgHist: UserMessage[],
|
||||||
|
): Promise<string> {
|
||||||
|
// todo: this stuff to create a response in a simpler way!
|
||||||
|
try {
|
||||||
|
const params: ChatParams = {
|
||||||
|
model: model,
|
||||||
|
ollama: ollama,
|
||||||
|
msgHist: msgHist
|
||||||
|
}
|
||||||
|
const response: ChatResponse = await blockResponse(params)
|
||||||
|
let result = response.message.content
|
||||||
|
|
||||||
|
if (hasThinking(result))
|
||||||
|
result = result.replace(/<think>[\s\S]*?<\/think>/g, '').trim()
|
||||||
|
|
||||||
|
return result
|
||||||
|
} catch (error: any) {
|
||||||
|
console.log(`[Util: messageNormal] Error creating message: ${error.message}`)
|
||||||
|
if (error.message.includes('fetch failed'))
|
||||||
|
error.message = 'Missing ollama service on machine'
|
||||||
|
else if (error.message.includes('try pulling it first'))
|
||||||
|
error.message = `You do not have the ${model} downloaded. Ask an admin to pull it using the \`pull-model\` command.`
|
||||||
|
return `**Response generation failed.**\n\nReason: ${error.message}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Region: Helpers
|
||||||
function hasThinking(message: string): boolean {
|
function hasThinking(message: string): boolean {
|
||||||
return /<think>[\s\S]*?<\/think>/i.test(message)
|
return /<think>[\s\S]*?<\/think>/i.test(message)
|
||||||
}
|
}
|
||||||
|
// End Region: Helpers
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ describe('Commands Existence', () => {
|
|||||||
// test specific commands in the object
|
// test specific commands in the object
|
||||||
it('references specific commands', () => {
|
it('references specific commands', () => {
|
||||||
const commandsString = commands.map(e => e.name).join(', ')
|
const commandsString = commands.map(e => e.name).join(', ')
|
||||||
const expectedCommands = ['thread', 'private-thread', 'message-stream', 'toggle-chat', 'shutoff', 'modify-capacity', 'clear-user-channel-history', 'pull-model', 'switch-model', 'delete-model']
|
const expectedCommands = ['thread', 'private-thread', 'message-stream', 'toggle-chat', 'shutoff', 'modify-capacity', 'clear-user-channel-history', 'pull-model', 'switch-model', 'delete-model', 'summary']
|
||||||
expect(commandsString).toBe(expectedCommands.join(', '))
|
expect(commandsString).toBe(expectedCommands.join(', '))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
+3
-3
@@ -1,4 +1,4 @@
|
|||||||
import { defineConfig, configDefaults } from 'vitest/config'
|
import { defineConfig } from 'vitest/config'
|
||||||
|
|
||||||
// config for vitest
|
// config for vitest
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
@@ -6,8 +6,8 @@ export default defineConfig({
|
|||||||
globals: true, // <-- reduces test file imports
|
globals: true, // <-- reduces test file imports
|
||||||
reporters: ['verbose'], // <-- verbose output
|
reporters: ['verbose'], // <-- verbose output
|
||||||
coverage: {
|
coverage: {
|
||||||
exclude: [...configDefaults.exclude, 'build/*', 'tests/*'], // <-- exclude JS build
|
include: ['src/**/*.ts'],
|
||||||
reporter: ['text-summary'] // <-- report in text-summary
|
reporter: 'json-summary'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
Reference in New Issue
Block a user