added websocket updates
This commit is contained in:
46
backend/package-lock.json
generated
46
backend/package-lock.json
generated
@@ -8,6 +8,7 @@
|
|||||||
"name": "ai-backend",
|
"name": "ai-backend",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/express-ws": "^3.0.4",
|
||||||
"ajv-formats": "^3.0.1",
|
"ajv-formats": "^3.0.1",
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
"compression": "^1.7.4",
|
"compression": "^1.7.4",
|
||||||
@@ -18,9 +19,9 @@
|
|||||||
"filewatcher": "^3.0.1",
|
"filewatcher": "^3.0.1",
|
||||||
"glob": "^10.3.16",
|
"glob": "^10.3.16",
|
||||||
"knex": "^3.1.0",
|
"knex": "^3.1.0",
|
||||||
|
"mitt": "^3.0.1",
|
||||||
"mysql2": "^3.9.7",
|
"mysql2": "^3.9.7",
|
||||||
"objection": "^3.1.4",
|
"objection": "^3.1.4",
|
||||||
"semaphore": "^1.1.0",
|
|
||||||
"sqlite3": "^5.1.7",
|
"sqlite3": "^5.1.7",
|
||||||
"typescript-ioc": "^3.2.2"
|
"typescript-ioc": "^3.2.2"
|
||||||
},
|
},
|
||||||
@@ -2163,7 +2164,6 @@
|
|||||||
"version": "1.19.5",
|
"version": "1.19.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz",
|
||||||
"integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==",
|
"integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/connect": "*",
|
"@types/connect": "*",
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
@@ -2182,7 +2182,6 @@
|
|||||||
"version": "3.4.38",
|
"version": "3.4.38",
|
||||||
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
|
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
|
||||||
"integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
|
"integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
@@ -2209,7 +2208,6 @@
|
|||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz",
|
||||||
"integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==",
|
"integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/body-parser": "*",
|
"@types/body-parser": "*",
|
||||||
"@types/express-serve-static-core": "^4.17.33",
|
"@types/express-serve-static-core": "^4.17.33",
|
||||||
@@ -2221,7 +2219,6 @@
|
|||||||
"version": "4.19.1",
|
"version": "4.19.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.1.tgz",
|
||||||
"integrity": "sha512-ej0phymbFLoCB26dbbq5PGScsf2JAJ4IJHjG10LalgUV36XKTmA4GdA+PVllKvRk0sEKt64X8975qFnkSi0hqA==",
|
"integrity": "sha512-ej0phymbFLoCB26dbbq5PGScsf2JAJ4IJHjG10LalgUV36XKTmA4GdA+PVllKvRk0sEKt64X8975qFnkSi0hqA==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"@types/qs": "*",
|
"@types/qs": "*",
|
||||||
@@ -2238,6 +2235,17 @@
|
|||||||
"@types/express": "*"
|
"@types/express": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/express-ws": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/express-ws/-/express-ws-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-Yjj18CaivG5KndgcvzttWe8mPFinPCHJC2wvyQqVzA7hqeufM8EtWMj6mpp5omg3s8XALUexhOu8aXAyi/DyJQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/express": "*",
|
||||||
|
"@types/express-serve-static-core": "*",
|
||||||
|
"@types/ws": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/graceful-fs": {
|
"node_modules/@types/graceful-fs": {
|
||||||
"version": "4.1.9",
|
"version": "4.1.9",
|
||||||
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz",
|
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz",
|
||||||
@@ -2256,8 +2264,7 @@
|
|||||||
"node_modules/@types/http-errors": {
|
"node_modules/@types/http-errors": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz",
|
||||||
"integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==",
|
"integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/istanbul-lib-coverage": {
|
"node_modules/@types/istanbul-lib-coverage": {
|
||||||
"version": "2.0.6",
|
"version": "2.0.6",
|
||||||
@@ -2328,8 +2335,7 @@
|
|||||||
"node_modules/@types/mime": {
|
"node_modules/@types/mime": {
|
||||||
"version": "1.3.5",
|
"version": "1.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
|
||||||
"integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
|
"integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/multer": {
|
"node_modules/@types/multer": {
|
||||||
"version": "1.4.11",
|
"version": "1.4.11",
|
||||||
@@ -2351,14 +2357,12 @@
|
|||||||
"node_modules/@types/qs": {
|
"node_modules/@types/qs": {
|
||||||
"version": "6.9.15",
|
"version": "6.9.15",
|
||||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz",
|
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz",
|
||||||
"integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==",
|
"integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/range-parser": {
|
"node_modules/@types/range-parser": {
|
||||||
"version": "1.2.7",
|
"version": "1.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
|
||||||
"integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
|
"integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/semaphore": {
|
"node_modules/@types/semaphore": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.4",
|
||||||
@@ -2371,7 +2375,6 @@
|
|||||||
"version": "0.17.4",
|
"version": "0.17.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz",
|
||||||
"integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==",
|
"integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/mime": "^1",
|
"@types/mime": "^1",
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
@@ -2381,7 +2384,6 @@
|
|||||||
"version": "1.15.7",
|
"version": "1.15.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz",
|
||||||
"integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==",
|
"integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/http-errors": "*",
|
"@types/http-errors": "*",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
@@ -6629,6 +6631,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||||
},
|
},
|
||||||
|
"node_modules/mitt": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/mkdirp": {
|
"node_modules/mkdirp": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||||
@@ -7894,14 +7902,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||||
},
|
},
|
||||||
"node_modules/semaphore": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/semaphore/-/semaphore-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-O4OZEaNtkMd/K0i6js9SL+gqy0ZCBMgUvlSqHKi4IBdjhe7wB8pwztUk1BbZ1fmrvpwFrPbHzqd2w5pTcJH6LA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.8.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/semver": {
|
"node_modules/semver": {
|
||||||
"version": "7.6.2",
|
"version": "7.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
"tsoa:routes": "npm exec tsoa routes"
|
"tsoa:routes": "npm exec tsoa routes"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/express-ws": "^3.0.4",
|
||||||
"ajv-formats": "^3.0.1",
|
"ajv-formats": "^3.0.1",
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
"compression": "^1.7.4",
|
"compression": "^1.7.4",
|
||||||
@@ -28,6 +29,7 @@
|
|||||||
"filewatcher": "^3.0.1",
|
"filewatcher": "^3.0.1",
|
||||||
"glob": "^10.3.16",
|
"glob": "^10.3.16",
|
||||||
"knex": "^3.1.0",
|
"knex": "^3.1.0",
|
||||||
|
"mitt": "^3.0.1",
|
||||||
"mysql2": "^3.9.7",
|
"mysql2": "^3.9.7",
|
||||||
"objection": "^3.1.4",
|
"objection": "^3.1.4",
|
||||||
"sqlite3": "^5.1.7",
|
"sqlite3": "^5.1.7",
|
||||||
|
|||||||
7
backend/src/event/emitter.ts
Normal file
7
backend/src/event/emitter.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import mitt from 'mitt';
|
||||||
|
import {Events} from './events';
|
||||||
|
|
||||||
|
const emitter = mitt<Events>();
|
||||||
|
export default function getEmitter<Events>() {
|
||||||
|
return emitter;
|
||||||
|
}
|
||||||
25
backend/src/event/events.ts
Normal file
25
backend/src/event/events.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import AiInstance from '../models/business/AiInstance';
|
||||||
|
|
||||||
|
export type AiEvent = {
|
||||||
|
aiInstance: AiInstance,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ChatEvent = AiEvent & {
|
||||||
|
role: string,
|
||||||
|
name: string,
|
||||||
|
content: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DiscordOnlineEvent = AiEvent & {
|
||||||
|
online: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DiscordReactToChatEvent = AiEvent & {
|
||||||
|
reactToChat: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Events = {
|
||||||
|
chatText: ChatEvent,
|
||||||
|
discordOnline: DiscordOnlineEvent,
|
||||||
|
discordReactToChat: DiscordReactToChatEvent,
|
||||||
|
}
|
||||||
35
backend/src/event/listener.ts
Normal file
35
backend/src/event/listener.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import getEmitter from './emitter';
|
||||||
|
import {Container} from 'typescript-ioc';
|
||||||
|
import {ExpressWsProvider} from '../ioc';
|
||||||
|
import {ChatEvent, DiscordOnlineEvent, DiscordReactToChatEvent} from './events';
|
||||||
|
|
||||||
|
export function registerEvents(): void {
|
||||||
|
const emitter = getEmitter();
|
||||||
|
|
||||||
|
emitter.on('chatText', (event: ChatEvent) => {
|
||||||
|
Container.get(ExpressWsProvider).get().getWss().clients
|
||||||
|
.forEach(c => c.send(JSON.stringify({
|
||||||
|
type: 'chatText',
|
||||||
|
aiInstance: event.aiInstance.configuration.id,
|
||||||
|
role: event.role,
|
||||||
|
name: event.name,
|
||||||
|
content: event.content,
|
||||||
|
})));
|
||||||
|
});
|
||||||
|
emitter.on('discordOnline', (event: DiscordOnlineEvent) => {
|
||||||
|
Container.get(ExpressWsProvider).get().getWss().clients
|
||||||
|
.forEach(c => c.send(JSON.stringify({
|
||||||
|
type: 'discordOnline',
|
||||||
|
aiInstance: event.aiInstance.configuration.id,
|
||||||
|
online: event.online,
|
||||||
|
})));
|
||||||
|
});
|
||||||
|
emitter.on('discordReactToChat', (event: DiscordReactToChatEvent) => {
|
||||||
|
Container.get(ExpressWsProvider).get().getWss().clients
|
||||||
|
.forEach(c => c.send(JSON.stringify({
|
||||||
|
type: 'discordReactToChat',
|
||||||
|
aiInstance: event.aiInstance.configuration.id,
|
||||||
|
reactToChat: event.reactToChat,
|
||||||
|
})));
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,12 +1,25 @@
|
|||||||
import {Container, Scope} from 'typescript-ioc';
|
import {Container, Scope} from 'typescript-ioc';
|
||||||
import {IocContainer} from '@tsoa/runtime';
|
import {IocContainer} from '@tsoa/runtime';
|
||||||
import {ConfigProvider} from './config/confighelper';
|
import {ConfigProvider} from './config/confighelper';
|
||||||
import AiService from "./services/AiService";
|
import AiService from './services/AiService';
|
||||||
import AiPythonConnector from './services/AiPythonConnector';
|
import AiPythonConnector from './services/AiPythonConnector';
|
||||||
|
import expressWs from 'express-ws';
|
||||||
|
|
||||||
const iocContainer: () => IocContainer = () => Container;
|
const iocContainer: () => IocContainer = () => Container;
|
||||||
Container.bind(ConfigProvider).to(ConfigProvider).scope(Scope.Singleton);
|
Container.bind(ConfigProvider).to(ConfigProvider).scope(Scope.Singleton);
|
||||||
Container.bind(AiPythonConnector).to(AiPythonConnector).scope(Scope.Singleton);
|
Container.bind(AiPythonConnector).to(AiPythonConnector).scope(Scope.Singleton);
|
||||||
Container.bind(AiService).to(AiService).scope(Scope.Singleton);
|
Container.bind(AiService).to(AiService).scope(Scope.Singleton);
|
||||||
|
|
||||||
export {iocContainer};
|
export {iocContainer};
|
||||||
|
|
||||||
|
export class ExpressWsProvider {
|
||||||
|
private readonly instance: expressWs.Instance;
|
||||||
|
|
||||||
|
constructor(instance: expressWs.Instance) {
|
||||||
|
this.instance = instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
get(): expressWs.Instance {
|
||||||
|
return this.instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ import AiConfiguration from '../db/AiConfiguration';
|
|||||||
import DiscordStatus from './DiscordStatus';
|
import DiscordStatus from './DiscordStatus';
|
||||||
import AiPythonConnector from '../../services/AiPythonConnector';
|
import AiPythonConnector from '../../services/AiPythonConnector';
|
||||||
import Semaphore from '../../util/Semaphore';
|
import Semaphore from '../../util/Semaphore';
|
||||||
|
import getEmitter from '../../event/emitter';
|
||||||
|
|
||||||
export type ChatMessage = {
|
export type ChatMessage = {
|
||||||
role: string,
|
role: string,
|
||||||
@@ -27,9 +28,9 @@ export default class AiInstance {
|
|||||||
try {
|
try {
|
||||||
await this._messagesSemaphore.acquire();
|
await this._messagesSemaphore.acquire();
|
||||||
this.messages.push({'role': 'user', 'name': user, 'content': text});
|
this.messages.push({'role': 'user', 'name': user, 'content': text});
|
||||||
// chat_text_signal.send(sender = this.__class__, ai_name = this.configuration.name, message = this.messages[-1]);
|
getEmitter().emit('chatText', {aiInstance: this, ...this.messages[this.messages.length - 1]!});
|
||||||
this.messages = await this.aiPythonConnector.chat(this.configuration.modelIdOrPath, this.messages);
|
this.messages = await this.aiPythonConnector.chat(this.configuration.modelIdOrPath, this.messages);
|
||||||
// chat_text_signal.send(sender = this.__class__, ai_name = this.configuration.name, message = this.messages[-1]);
|
getEmitter().emit('chatText', {aiInstance: this, ...this.messages[this.messages.length - 1]!});
|
||||||
return this.messages[this.messages.length - 1]!;
|
return this.messages[this.messages.length - 1]!;
|
||||||
} finally {
|
} finally {
|
||||||
this._messagesSemaphore.release();
|
this._messagesSemaphore.release();
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
import type AiInstance from './AiInstance';
|
import type AiInstance from './AiInstance';
|
||||||
import DcClient from './DcClient';
|
import DcClient from './DcClient';
|
||||||
|
import getEmitter from '../../event/emitter';
|
||||||
|
|
||||||
export default class DiscordStatus {
|
export default class DiscordStatus {
|
||||||
// private _instance: AiInstance;
|
private readonly _instance: AiInstance;
|
||||||
private _client: DcClient;
|
private _client: DcClient;
|
||||||
private _online = false;
|
private _online = false;
|
||||||
private _reactToChat = false;
|
private _reactToChat = false;
|
||||||
|
|
||||||
constructor(instance: AiInstance) {
|
constructor(instance: AiInstance) {
|
||||||
// this._instance = instance;
|
this._instance = instance;
|
||||||
this._client = new DcClient(instance);
|
this._client = new DcClient(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,7 +26,7 @@ export default class DiscordStatus {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._online = value;
|
this._online = value;
|
||||||
// discord_online_signal.send(sender = this.__class__, ai_name = this._instance.configuration.name, status = this.online);
|
getEmitter().emit('discordOnline', {aiInstance: this._instance, online: value});
|
||||||
}
|
}
|
||||||
|
|
||||||
isReactToChat(): boolean {
|
isReactToChat(): boolean {
|
||||||
@@ -34,8 +35,7 @@ export default class DiscordStatus {
|
|||||||
|
|
||||||
setReactToChat(value: boolean) {
|
setReactToChat(value: boolean) {
|
||||||
this._reactToChat = value;
|
this._reactToChat = value;
|
||||||
// discord_react_to_chat_signal.send(sender = this.__class__, ai_name = this._instance.configuration.name,
|
getEmitter().emit('discordReactToChat', {aiInstance: this._instance, reactToChat: value});
|
||||||
// status = this._reactToChat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async dispose(): Promise<void> {
|
async dispose(): Promise<void> {
|
||||||
|
|||||||
@@ -2,9 +2,19 @@ import {Express, static as _static} from 'express';
|
|||||||
import type {ConfigType} from './config/confighelper';
|
import type {ConfigType} from './config/confighelper';
|
||||||
import catchAllRedirect from './middleware/CatchAllRedirect';
|
import catchAllRedirect from './middleware/CatchAllRedirect';
|
||||||
import {RegisterRoutes} from './tsoa.gen/routes';
|
import {RegisterRoutes} from './tsoa.gen/routes';
|
||||||
|
import expressWs from 'express-ws';
|
||||||
|
|
||||||
export function registerRoutes(express: Express, config: ConfigType) {
|
export function registerRoutes(express: Express, config: ConfigType, ws: expressWs.Instance): void {
|
||||||
RegisterRoutes(express);
|
RegisterRoutes(express);
|
||||||
|
// (express as any as expressWs.Application).ws('ws/dashboard', (ws, req, next) => isAuthenticatedMiddleware(req, req.res!, next));
|
||||||
|
(express as any as expressWs.Application).ws('ws/dashboard', (ws, req) => {
|
||||||
|
// ws.on('open', function () {
|
||||||
|
// console.log(this);
|
||||||
|
// });
|
||||||
|
// ws.on('message', function (msg) {
|
||||||
|
// ws.send(msg);
|
||||||
|
// });
|
||||||
|
});
|
||||||
express.use(_static('_client')); //for production
|
express.use(_static('_client')); //for production
|
||||||
express.use(catchAllRedirect(express, '/'));
|
express.use(catchAllRedirect(express, '/'));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ import {initGlobals} from './util/GlobalInit';
|
|||||||
import {seedDb} from './DbSeed';
|
import {seedDb} from './DbSeed';
|
||||||
import {uncaughtErrorHandler} from './middleware/UncaughtErrorHandler';
|
import {uncaughtErrorHandler} from './middleware/UncaughtErrorHandler';
|
||||||
import compression from 'compression';
|
import compression from 'compression';
|
||||||
import {iocContainer} from './ioc';
|
import {ExpressWsProvider, iocContainer} from './ioc';
|
||||||
|
import expressWs from 'express-ws';
|
||||||
|
import {Container, Scope} from 'typescript-ioc';
|
||||||
|
import {registerEvents} from './event/listener';
|
||||||
|
|
||||||
export default class Server {
|
export default class Server {
|
||||||
// @ts-ignore TS6133
|
// @ts-ignore TS6133
|
||||||
@@ -24,6 +27,7 @@ export default class Server {
|
|||||||
|
|
||||||
private config!: ConfigType;
|
private config!: ConfigType;
|
||||||
private express: Express | undefined;
|
private express: Express | undefined;
|
||||||
|
private expressWsInstance: expressWs.Instance | undefined;
|
||||||
private server: http.Server | undefined;
|
private server: http.Server | undefined;
|
||||||
private expressHost: string | undefined;
|
private expressHost: string | undefined;
|
||||||
private expressPort: number | undefined;
|
private expressPort: number | undefined;
|
||||||
@@ -38,6 +42,7 @@ export default class Server {
|
|||||||
initGlobals();
|
initGlobals();
|
||||||
this.initConfigChangeWatcher();
|
this.initConfigChangeWatcher();
|
||||||
this.initShutdownHooks();
|
this.initShutdownHooks();
|
||||||
|
registerEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
private initConfigChangeWatcher(): void {
|
private initConfigChangeWatcher(): void {
|
||||||
@@ -75,6 +80,7 @@ export default class Server {
|
|||||||
this.expressPort = this.config.server.port ?? 3000;
|
this.expressPort = this.config.server.port ?? 3000;
|
||||||
|
|
||||||
this.express = express();
|
this.express = express();
|
||||||
|
this.expressWsInstance = expressWs(this.express);
|
||||||
|
|
||||||
const sessionStore = new DbStore();
|
const sessionStore = new DbStore();
|
||||||
|
|
||||||
@@ -84,12 +90,14 @@ export default class Server {
|
|||||||
this.express.use(session(getSessionSettings(this.config, sessionStore)));
|
this.express.use(session(getSessionSettings(this.config, sessionStore)));
|
||||||
this.express.use(sessionUserdataMiddleware());
|
this.express.use(sessionUserdataMiddleware());
|
||||||
this.express.use(express.json());
|
this.express.use(express.json());
|
||||||
registerRoutes(this.express, this.config);
|
registerRoutes(this.express, this.config, this.expressWsInstance);
|
||||||
// RegisterRoutes(app);
|
|
||||||
this.express.use(errorLogHandler());
|
this.express.use(errorLogHandler());
|
||||||
this.express.use(apiErrorHandler());
|
this.express.use(apiErrorHandler());
|
||||||
// registerOpenApiLast(this.express);
|
// registerOpenApiLast(this.express);
|
||||||
this.express.use(uncaughtErrorHandler());
|
this.express.use(uncaughtErrorHandler());
|
||||||
|
|
||||||
|
const expressWsProviderFactory = () => new ExpressWsProvider(this.expressWsInstance!);
|
||||||
|
Container.bind(ExpressWsProvider).factory(expressWsProviderFactory).scope(Scope.Singleton);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async initDatabase(): Promise<void> {
|
private async initDatabase(): Promise<void> {
|
||||||
|
|||||||
@@ -1,15 +1,19 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {Options, Vue} from 'vue-class-component';
|
import {Options, Vue} from 'vue-class-component';
|
||||||
import AiInstanceTabs from "@/components/dashboard/AiInstanceTabs.vue";
|
import AiInstanceTabs from "@/components/dashboard/AiInstanceTabs.vue";
|
||||||
|
import WsUpdater from "@/components/dashboard/WsUpdater.vue";
|
||||||
|
|
||||||
@Options({
|
@Options({
|
||||||
name: 'DashBoard',
|
name: 'DashBoard',
|
||||||
components: {AiInstanceTabs},
|
components: {WsUpdater, AiInstanceTabs},
|
||||||
})
|
})
|
||||||
export default class DashBoard extends Vue {
|
export default class DashBoard extends Vue {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<AiInstanceTabs class="m-3"/>
|
<div>
|
||||||
|
<WsUpdater/>
|
||||||
|
<AiInstanceTabs class="m-3"/>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
78
frontend/src/components/dashboard/WsUpdater.vue
Normal file
78
frontend/src/components/dashboard/WsUpdater.vue
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import {Options, Vue} from 'vue-class-component';
|
||||||
|
import {AiInstanceStore} from '@/stores/AiInstanceStore';
|
||||||
|
import {ChatMessageVmV1} from 'ai-oas';
|
||||||
|
|
||||||
|
@Options({
|
||||||
|
name: 'WsUpdater',
|
||||||
|
components: {},
|
||||||
|
})
|
||||||
|
export default class WsUpdater extends Vue {
|
||||||
|
readonly baseurl = 'ws://' + window.location.host + '/';
|
||||||
|
private socket!: WebSocket;
|
||||||
|
private readonly aiInstanceStore = new AiInstanceStore();
|
||||||
|
private reconnect = false;
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.reconnect = true;
|
||||||
|
this.initSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
private initSocket(): void {
|
||||||
|
this.socket = new WebSocket(this.baseurl + 'ws/dashboard/');
|
||||||
|
this.socket.onmessage = (e) => {
|
||||||
|
const message = JSON.parse(e.data);
|
||||||
|
switch (message.type) {
|
||||||
|
case 'chatText': {
|
||||||
|
const aiInstanceId = message.aiInstance;
|
||||||
|
const ai = this.aiInstanceStore.aiInstances.find(e => e.configuration.id == aiInstanceId);
|
||||||
|
if (ai) {
|
||||||
|
ai.messages.push(ChatMessageVmV1.fromJson(message));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'discordOnline': {
|
||||||
|
const aiInstanceId = message.aiInstance;
|
||||||
|
const ai = this.aiInstanceStore.aiInstances.find(e => e.configuration.id == aiInstanceId);
|
||||||
|
if (ai) {
|
||||||
|
ai.discord.online = message.online;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'discordReactToChat': {
|
||||||
|
const aiInstanceId = message.aiInstance;
|
||||||
|
const ai = this.aiInstanceStore.aiInstances.find(e => e.configuration.id == aiInstanceId);
|
||||||
|
if (ai) {
|
||||||
|
ai.discord.reactToChat = message.reactToChat;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
console.log('WsUpdater: Unknown message type', message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.socket.onopen = () => {
|
||||||
|
console.info('Chat socket connected');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.socket.onclose = (event: CloseEvent) => {
|
||||||
|
if (this.reconnect) {
|
||||||
|
console.error('Chat socket closed unexpectedly. Reconnecting ...');
|
||||||
|
this.$nextTick(() => this.initSocket());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
unmounted() {
|
||||||
|
this.reconnect = false;
|
||||||
|
this.socket.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessage(message: any) {
|
||||||
|
this.socket.send(JSON.stringify(message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
</template>
|
||||||
@@ -29,11 +29,15 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
clearScreen: false,
|
clearScreen: false,
|
||||||
server: {
|
server: {
|
||||||
proxy: {//for dev
|
proxy: {//for dev
|
||||||
'^/api/.*$': {
|
'^/api/.*$': {
|
||||||
target: 'http://localhost:5172',
|
target: 'http://localhost:5172',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
|
}, '^/ws/.*$': {
|
||||||
|
target: 'http://localhost:5172',
|
||||||
|
changeOrigin: true,
|
||||||
|
ws: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user