Compare commits

16 Commits

Author SHA1 Message Date
Logan Cusano
dfb2765f39 Add a new key for feeds to set active status 2024-09-21 11:36:02 -04:00
Logan Cusano
33680209ba Added missing packages to dev
Some checks failed
release-tag / release-image (push) Has been cancelled
Update Wiki from JSDoc / update-wiki (push) Failing after 12s
Lint JavaScript/Node.js / lint-js (push) Successful in 12s
DRB Tests / drb_mocha_tests (push) Successful in 31s
2024-08-18 01:29:23 -04:00
Logan Cusano
f70ea4229a Trying node dev #25
Some checks failed
DRB Tests / drb_mocha_tests (push) Has been cancelled
Lint JavaScript/Node.js / lint-js (push) Has been cancelled
Update Wiki from JSDoc / update-wiki (push) Has been cancelled
release-tag / release-image (push) Successful in 2m4s
2024-08-18 01:27:01 -04:00
Logan Cusano
acadc9faee Another attempt #25
Some checks failed
release-tag / release-image (push) Successful in 2m1s
Update Wiki from JSDoc / update-wiki (push) Failing after 11s
Lint JavaScript/Node.js / lint-js (push) Successful in 11s
DRB Tests / drb_mocha_tests (push) Successful in 29s
2024-08-18 01:23:14 -04:00
Logan Cusano
f725ec88f9 Sepcify dir for #25
All checks were successful
release-tag / release-image (push) Successful in 2m1s
Update Wiki from JSDoc / update-wiki (push) Successful in 12s
Lint JavaScript/Node.js / lint-js (push) Successful in 11s
DRB Tests / drb_mocha_tests (push) Successful in 27s
2024-08-18 01:05:05 -04:00
Logan Cusano
8d34b93527 Hopefully fix for action issue #25
All checks were successful
release-tag / release-image (push) Successful in 2m1s
Update Wiki from JSDoc / update-wiki (push) Successful in 12s
Lint JavaScript/Node.js / lint-js (push) Successful in 11s
DRB Tests / drb_mocha_tests (push) Successful in 28s
2024-08-18 01:00:38 -04:00
Logan Cusano
918cfe06e4 More debug for #25
All checks were successful
release-tag / release-image (push) Successful in 2m4s
Update Wiki from JSDoc / update-wiki (push) Successful in 13s
Lint JavaScript/Node.js / lint-js (push) Successful in 11s
DRB Tests / drb_mocha_tests (push) Successful in 26s
2024-08-18 00:43:44 -04:00
Logan Cusano
e2f276e65b #25
All checks were successful
release-tag / release-image (push) Successful in 2m4s
Update Wiki from JSDoc / update-wiki (push) Successful in 14s
Lint JavaScript/Node.js / lint-js (push) Successful in 11s
DRB Tests / drb_mocha_tests (push) Successful in 27s
2024-08-18 00:36:02 -04:00
52353ec1fb Merge pull request '#22 - Add Automated Docs' (#24) from automated-docs-#22 into main
All checks were successful
release-tag / release-image (push) Successful in 2m2s
Update Wiki from JSDoc / update-wiki (push) Successful in 13s
Lint JavaScript/Node.js / lint-js (push) Successful in 11s
DRB Tests / drb_mocha_tests (push) Successful in 26s
Reviewed-on: #24
2024-08-17 19:48:46 -04:00
Logan Cusano
750877db1a Remove docs on PRs
All checks were successful
Lint JavaScript/Node.js / lint-js (pull_request) Successful in 11s
DRB Tests / drb_mocha_tests (pull_request) Successful in 28s
- Update wiki step
2024-08-17 19:46:15 -04:00
Logan Cusano
a18337d0f8 Updated 'home' -> 'Home'
All checks were successful
Update Wiki from JSDoc / update-wiki (pull_request) Successful in 12s
Lint JavaScript/Node.js / lint-js (pull_request) Successful in 11s
DRB Tests / drb_mocha_tests (pull_request) Successful in 29s
2024-08-17 19:40:18 -04:00
Logan Cusano
6f45a60030 Update action to force copy
Some checks failed
Update Wiki from JSDoc / update-wiki (pull_request) Failing after 11s
Lint JavaScript/Node.js / lint-js (pull_request) Successful in 10s
DRB Tests / drb_mocha_tests (pull_request) Successful in 26s
2024-08-17 19:33:06 -04:00
Logan Cusano
1fb4728b0a Revert incomplete changes to GPT handler
Some checks failed
Update Wiki from JSDoc / update-wiki (pull_request) Failing after 11s
Lint JavaScript/Node.js / lint-js (pull_request) Successful in 11s
DRB Tests / drb_mocha_tests (pull_request) Successful in 28s
2024-08-17 19:28:44 -04:00
Logan Cusano
ebf48c7618 Linting 2024-08-17 19:27:48 -04:00
Logan Cusano
11b3504f28 Update docs for test
Some checks failed
Update Wiki from JSDoc / update-wiki (pull_request) Successful in 12s
Lint JavaScript/Node.js / lint-js (pull_request) Failing after 10s
DRB Tests / drb_mocha_tests (pull_request) Successful in 29s
2024-08-17 19:15:02 -04:00
Logan Cusano
14171a9c13 Fix homepage name 2024-08-17 19:13:44 -04:00
9 changed files with 1463 additions and 231 deletions

View File

@@ -4,13 +4,13 @@ on:
push:
branches:
- main
# TODO - REMOVE AFTER TESTING
pull_request:
branches:
- "*"
# schedule:
# - cron: '0 0 * * 1' # Every Monday at midnight (UTC)
env:
NODE_ENV: development
jobs:
update-wiki:
runs-on: ubuntu-latest
@@ -35,12 +35,22 @@ jobs:
repository: logan/drb-server.wiki # Replace with your wiki repository
path: wiki
- name: Output Generated Documentation
run: |
cat Home.md
ls
- name: Update wiki
run: |
cp -r home.md wiki/
cp -rf Home.md wiki/Home.md
cd wiki
git config user.name "gitea-actions"
git config user.email "gitea-actions@cusano.net"
git add .
# Check if there are any changes to commit
if git diff --cached --quiet; then
echo "No changes to commit."
else
git commit -m "Update wiki from JSDoc"
git push
fi

View File

@@ -1,5 +1,10 @@
{
"source": {
"includePattern": ".+\\.([mc]?js(doc|x)?)$"
"includePattern": ".+([mc]?js(doc|x)?)$"
},
"plugins": ["node_modules/jsdoc-babel"],
"babel": {
"presets": [ "es2015" ],
"plugins": [ "transform-async-to-generator" ]
}
}

1327
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
"description": "",
"main": "src/server.js",
"scripts": {
"docs": "jsdoc2md -c jsdoc.conf src/**/*.mjs >> home.md",
"docs": "jsdoc2md -c jsdoc.conf src/*js > Home.md",
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"test": "mocha --timeout 5000",
@@ -14,11 +14,14 @@
"license": "ISC",
"type": "module",
"devDependencies": {
"babel-plugin-transform-async-to-generator": "^6.24.1",
"babel-preset-es2015": "^6.24.1",
"chai": "^5.1.1",
"eslint": "^9.9.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-unused-imports": "^4.1.3",
"jsdoc-babel": "^0.5.0",
"jsdoc-to-markdown": "^8.0.3",
"mocha": "^10.4.0",
"prettier": "^3.3.3",

View File

@@ -1,97 +1,17 @@
import { DebugBuilder } from "../../modules/debugger.mjs";
import { requestNodeJoinSystem } from "../../modules/socketServerWrappers.mjs";
import { getSystemByName } from "../../modules/mongo-wrappers/mongoSystemsWrappers.mjs";
import { getConfig } from "../../modules/mongo-wrappers/mongoConfigWrappers.mjs";
import { getAvailableTokensInGuild } from "../modules/wrappers.mjs";
const log = new DebugBuilder("server", "discordBot.modules.gptHandler");
import dotenv from "dotenv";
dotenv.config();
import { OpenAI } from "openai";
import { EventEmitter } from "events";
// Initialize environment variables
dotenv.config();
const log = new DebugBuilder("server", "discordBot.modules.gptHandler");
let assistant;
let eventHandler;
(async () => {
try {
const openai = new OpenAI(process.env.OPENAI_API_KEY);
assistant = await openai.beta.assistants.create({
const assistant = await openai.beta.assistants.create({
name: "Emmelia",
instructions: (await getConfig("emmeliaInitialPrompt")) || "",
model: "gpt-4o-mini",
tools: [
{
type: "function",
function: {
name: "checkUserVoiceChannel",
description: "Check if the user is in a voice channel",
parameters: {
type: "object",
properties: {
userId: {
type: "string",
description: "The ID of the user",
},
guildId: {
type: "string",
description: "The ID of the guild",
},
},
required: ["userId", "guildId"],
},
},
},
{
type: "function",
function: {
name: "getSelectedSystem",
description: "Retrieve the selected system details",
parameters: {
type: "object",
properties: {
systemName: {
type: "string",
description: "The name of the system",
},
},
required: ["systemName"],
},
},
},
{
type: "function",
function: {
name: "joinSelectedSystem",
description: "Join the selected system in the user's voice channel",
parameters: {
type: "object",
properties: {
userId: {
type: "string",
description: "The ID of the user",
},
guildId: {
type: "string",
description: "The ID of the guild",
},
systemName: {
type: "string",
description: "The name of the system",
},
channelId: {
type: "string",
description: "The ID of the voice channel",
},
},
required: ["userId", "guildId", "systemName", "channelId"],
},
},
},
],
instructions: process.env.DRB_SERVER_INITIAL_PROMPT,
model: "gpt-4o",
});
class EventHandler extends EventEmitter {
@@ -103,6 +23,8 @@ let eventHandler;
async onEvent(event) {
try {
console.log(event);
// Retrieve events that are denoted with 'requires_action'
// since these will have our tool_calls
if (event.event === "thread.run.requires_action") {
await this.handleRequiresAction(
event.data,
@@ -117,88 +39,28 @@ let eventHandler;
async handleRequiresAction(data, runId, threadId) {
try {
const toolOutputs = await Promise.all(
data.required_action.submit_tool_outputs.tool_calls.map(
async (toolCall) => {
const toolOutputs =
data.required_action.submit_tool_outputs.tool_calls.map((toolCall) => {
// Call the function
switch (toolCall.function.name) {
case "checkUserVoiceChannel":
return await this.checkUserVoiceChannel(toolCall);
case "getSelectedSystem":
return await this.getSelectedSystem(toolCall);
case "joinSelectedSystem":
return await this.joinSelectedSystem(toolCall);
default:
throw new Error(
`Unknown function: ${toolCall.function.name}`,
);
case "getCurrentTemperature":
return {
tool_call_id: toolCall.id,
output: "57",
};
}
},
),
);
});
// Submit all the tool outputs at the same time
await this.submitToolOutputs(toolOutputs, runId, threadId);
} catch (error) {
console.error("Error processing required action:", error);
}
}
async checkUserVoiceChannel(toolCall) {
const { userId, guildId } = JSON.parse(toolCall.function.arguments);
const guild = await this.client.guilds.get(guildId);
const member = await guild.members.get(userId);
const isInVoiceChannel = !!member.voice.channel;
return {
tool_call_id: toolCall.id,
output: JSON.stringify({
isInVoiceChannel,
channelId: member.voice.channelId,
}),
};
}
async getSelectedSystem(toolCall) {
const { systemName } = JSON.parse(toolCall.function.arguments);
const system = await getSystemByName(systemName);
return {
tool_call_id: toolCall.id,
output: JSON.stringify(system),
};
}
async joinSelectedSystem(toolCall) {
const { userId, guildId, systemName, channelId } = JSON.parse(
toolCall.function.arguments,
);
const system = await getSystemByName(systemName);
const guild = await this.client.guilds.fetch(guildId);
const discordToken = await getAvailableTokensInGuild(guildId);
if (discordToken) {
const result = await requestNodeJoinSystem(
system,
channelId,
discordToken,
);
return {
tool_call_id: toolCall.id,
output: JSON.stringify({ success: true, result }),
};
} else {
return {
tool_call_id: toolCall.id,
output: JSON.stringify({
success: false,
message: "No available bots.",
}),
};
}
}
async submitToolOutputs(toolOutputs, runId, threadId) {
try {
const stream =
this.client.beta.threads.runs.submitToolOutputsStream(
// Use the submitToolOutputsStream helper
const stream = this.client.beta.threads.runs.submitToolOutputsStream(
threadId,
runId,
{ tool_outputs: toolOutputs },
@@ -212,21 +74,21 @@ let eventHandler;
}
}
eventHandler = new EventHandler(openai);
const eventHandler = new EventHandler(openai);
eventHandler.on("event", eventHandler.onEvent.bind(eventHandler));
} catch (error) {
console.error("Initialization error:", error);
}
})();
export const gptHandler = async (additionalMessages) => {
try {
const thread = await openai.beta.threads.create();
// Add the additional messages to the conversation
for (const msgObj of additionalMessages) {
await openai.beta.threads.messages.create(thread.id, msgObj);
}
log.DEBUG("AI Conversation:", thread);
// Run the thread to get a response
try {
const stream = await openai.beta.threads.runs.stream(
thread.id,
{ assistant_id: assistant.id },
@@ -237,8 +99,9 @@ export const gptHandler = async (additionalMessages) => {
eventHandler.emit("event", event);
}
let response;
const messages = await openai.beta.threads.messages.list(thread.id);
const response = messages.data[0].content[0].text.value;
response = messages.data[0].content[0].text.value;
log.DEBUG("AI Response:", response);

View File

@@ -2,8 +2,11 @@ import {
getConfig,
setConfig,
} from "../../modules/mongo-wrappers/mongoConfigWrappers.mjs";
import { ActivityType, PresenceUpdateStatus, Client } from "discord.js";
import { ActivityType, PresenceUpdateStatus } from "discord.js";
/**
* Control the presence or activity of the discord bot.
*/
class PresenceManager {
/**
* Creates an instance of PresenceManager.

View File

@@ -71,6 +71,22 @@ export const updateFeedByLink = async (link, updatedFields) => {
}
};
// Wrapper for deactivating a feed by link
export const deactivateFeedByLink = async (link) => {
try {
const updatedCount = await updateDocumentByField(
feedCollectionName,
"link",
link,
[{'active':false}]
);
return updatedCount;
} catch (error) {
log.ERROR("Error deleting feed by link:", error);
throw error;
}
};
// Wrapper for deleting a feed by link
export const deleteFeedByLink = async (link) => {
try {

View File

@@ -51,6 +51,10 @@ export const updateFeeds = async (client) => {
const sourcePromiseArray = records.map(async (source) => {
log.DEBUG("Processing source:", source.title);
// Check if the feed is active
if (!source.active) {
return
}
try {
const parsedFeed = await parser.parseURL(source.link);

View File

@@ -3,7 +3,7 @@ const log = new DebugBuilder("server", "sourceManager");
import {
createFeed,
getFeedByLink,
deleteFeedByLink,
deactivateFeedByLink,
} from "../modules/mongo-wrappers/mongoFeedsWrappers.mjs";
class SourceManager {
@@ -48,7 +48,7 @@ class SourceManager {
return;
}
const results = await deleteFeedByLink(sourceURL);
const results = await deactivateFeedByLink(sourceURL);
if (!results) {
log.WARN(`Failed to remove source: ${sourceURL}`);
return;
@@ -70,6 +70,7 @@ class SourceManager {
category,
guild_id: guildId,
channel_id: channelId,
active: true
};
const record = await createFeed(feed);
log.DEBUG("Source added:", record);