Merge pull request #67 from matrixgpt/optional-threads

Optional threads
This commit is contained in:
bertybuttface 2023-01-27 18:24:41 +00:00 committed by GitHub
commit 2a5845c954
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 16 additions and 6 deletions

View File

@ -68,6 +68,8 @@ MATRIX_WHITELIST=
# Matrix Feature Flags (optional) # Matrix Feature Flags (optional)
MATRIX_AUTOJOIN=true MATRIX_AUTOJOIN=true
MATRIX_ENCRYPTION=true MATRIX_ENCRYPTION=true
# If you turn threads off you will have problems if you don't set CHATGPT_CONTEXT=room
MATRIX_THREADS=true
MATRIX_PREFIX_DM=false MATRIX_PREFIX_DM=false
MATRIX_RICH_TEXT=true MATRIX_RICH_TEXT=true
``` ```

View File

@ -13,6 +13,7 @@ export const {
/** Matrix Bot Features */ /** Matrix Bot Features */
MATRIX_AUTOJOIN, MATRIX_AUTOJOIN,
MATRIX_ENCRYPTION, MATRIX_ENCRYPTION,
MATRIX_THREADS,
MATRIX_PREFIX_DM, MATRIX_PREFIX_DM,
MATRIX_RICH_TEXT, MATRIX_RICH_TEXT,
/** Matrix Access Control */ /** Matrix Access Control */
@ -38,6 +39,7 @@ export const {
/** Matrix Bot Features */ /** Matrix Bot Features */
MATRIX_AUTOJOIN: { schema: z.boolean().default(true), description: "Set to true if you want the bot to autojoin when invited" }, MATRIX_AUTOJOIN: { schema: z.boolean().default(true), description: "Set to true if you want the bot to autojoin when invited" },
MATRIX_ENCRYPTION: { schema: z.boolean().default(true), description: "Set to true if you want the bot to support encrypted channels" }, MATRIX_ENCRYPTION: { schema: z.boolean().default(true), description: "Set to true if you want the bot to support encrypted channels" },
MATRIX_THREADS: { schema: z.boolean().default(true), description: "Set to true if you want the bot to answer always in a new thread/conversation" },
MATRIX_PREFIX_DM: { schema: z.boolean().default(false), description: "Set to false if you want the bot to answer to all messages in a one-to-one room" }, MATRIX_PREFIX_DM: { schema: z.boolean().default(false), description: "Set to false if you want the bot to answer to all messages in a one-to-one room" },
MATRIX_RICH_TEXT: { schema: z.boolean().default(true), description: "Set to true if you want the bot to answer with enriched text" }, MATRIX_RICH_TEXT: { schema: z.boolean().default(true), description: "Set to true if you want the bot to answer with enriched text" },
/** Matrix Access Control */ /** Matrix Access Control */

View File

@ -1,8 +1,8 @@
import { ChatGPTAPIBrowser } from "chatgpt"; import { ChatGPTAPIBrowser } from "chatgpt";
import { LogService, MatrixClient, UserID } from "matrix-bot-sdk"; import { LogService, MatrixClient, UserID } from "matrix-bot-sdk";
import { CHATGPT_CONTEXT, CHATGPT_TIMEOUT, MATRIX_DEFAULT_PREFIX_REPLY, MATRIX_DEFAULT_PREFIX, MATRIX_BLACKLIST, MATRIX_WHITELIST, MATRIX_RICH_TEXT, MATRIX_PREFIX_DM } from "./env.js"; import { CHATGPT_CONTEXT, CHATGPT_TIMEOUT, MATRIX_DEFAULT_PREFIX_REPLY, MATRIX_DEFAULT_PREFIX, MATRIX_BLACKLIST, MATRIX_WHITELIST, MATRIX_RICH_TEXT, MATRIX_PREFIX_DM, MATRIX_THREADS } from "./env.js";
import { RelatesTo, MessageEvent, StoredConversation, StoredConversationConfig } from "./interfaces.js"; import { RelatesTo, MessageEvent, StoredConversation, StoredConversationConfig } from "./interfaces.js";
import { sendChatGPTMessage, sendError, sendThreadReply } from "./utils.js"; import { sendChatGPTMessage, sendError, sendReply } from "./utils.js";
export default class CommandHandler { export default class CommandHandler {
@ -124,7 +124,7 @@ export default class CommandHandler {
const result = await sendChatGPTMessage(this.chatGPT, await bodyWithoutPrefix, storedConversation); const result = await sendChatGPTMessage(this.chatGPT, await bodyWithoutPrefix, storedConversation);
await Promise.all([ await Promise.all([
this.client.setTyping(roomId, false, 500), this.client.setTyping(roomId, false, 500),
sendThreadReply(this.client, roomId, this.getRootEventId(event), `${result.response}`, MATRIX_RICH_TEXT) sendReply(this.client, roomId, this.getRootEventId(event), `${result.response}`, MATRIX_THREADS, MATRIX_RICH_TEXT)
]); ]);
const storedConfig = ((storedConversation !== undefined && storedConversation.config !== undefined) ? storedConversation.config : {}) const storedConfig = ((storedConversation !== undefined && storedConversation.config !== undefined) ? storedConversation.config : {})

View File

@ -7,7 +7,7 @@ import {
} from "matrix-bot-sdk"; } from "matrix-bot-sdk";
import * as path from "path"; import * as path from "path";
import { DATA_PATH, OPENAI_EMAIL, OPENAI_PASSWORD, OPENAI_LOGIN_TYPE, OPENAI_PRO, MATRIX_HOMESERVER_URL, MATRIX_ACCESS_TOKEN, MATRIX_AUTOJOIN, MATRIX_BOT_PASSWORD, MATRIX_BOT_USERNAME, MATRIX_ENCRYPTION } from './env.js' import { DATA_PATH, OPENAI_EMAIL, OPENAI_PASSWORD, OPENAI_LOGIN_TYPE, OPENAI_PRO, MATRIX_HOMESERVER_URL, MATRIX_ACCESS_TOKEN, MATRIX_AUTOJOIN, MATRIX_BOT_PASSWORD, MATRIX_BOT_USERNAME, MATRIX_ENCRYPTION, MATRIX_THREADS, CHATGPT_CONTEXT } from './env.js'
import { parseMatrixUsernamePretty } from './utils.js'; import { parseMatrixUsernamePretty } from './utils.js';
import CommandHandler from "./handlers.js" import CommandHandler from "./handlers.js"
import { ChatGPTAPIBrowser } from 'chatgpt' import { ChatGPTAPIBrowser } from 'chatgpt'
@ -38,6 +38,7 @@ async function main() {
console.log("Set MATRIX_ACCESS_TOKEN to above token, MATRIX_BOT_PASSWORD can now be blank") console.log("Set MATRIX_ACCESS_TOKEN to above token, MATRIX_BOT_PASSWORD can now be blank")
return; return;
} }
if (!MATRIX_THREADS && CHATGPT_CONTEXT !== "room") throw Error("You must set CHATGPT_CONTEXT to 'room' if you set MATRIX_THREADS to false")
const client: MatrixClient = new MatrixClient(MATRIX_HOMESERVER_URL, MATRIX_ACCESS_TOKEN, storage, cryptoStore); const client: MatrixClient = new MatrixClient(MATRIX_HOMESERVER_URL, MATRIX_ACCESS_TOKEN, storage, cryptoStore);
// use puppeteer to bypass cloudflare (headful because of captchas) // use puppeteer to bypass cloudflare (headful because of captchas)

View File

@ -28,13 +28,17 @@ export async function sendError(client: MatrixClient, text: string, roomId: stri
* @param {string} roomId the room ID the event being replied to resides in * @param {string} roomId the room ID the event being replied to resides in
* @param {string} rootEventId the root event of the thread * @param {string} rootEventId the root event of the thread
* @param {string} text the plain text to reply with * @param {string} text the plain text to reply with
* @param {boolean} thread reply as a thread
* @param {boolean} rich should the plain text be rendered to html using markdown? * @param {boolean} rich should the plain text be rendered to html using markdown?
*/ */
export async function sendThreadReply(client: MatrixClient, roomId: string, rootEventId: string, text: string, rich:boolean = false): Promise<void> { export async function sendReply(client: MatrixClient, roomId: string, rootEventId: string, text: string, thread: boolean = false, rich:boolean = false): Promise<void> {
const contentCommon = { const contentCommon = {
body: text, body: text,
msgtype: "m.text", msgtype: "m.text",
}
const contentThreadOnly = {
"m.relates_to": { "m.relates_to": {
event_id: rootEventId, event_id: rootEventId,
is_falling_back: true, is_falling_back: true,
@ -67,8 +71,9 @@ export async function sendThreadReply(client: MatrixClient, roomId: string, root
} }
const content = rich ? { ...contentCommon, ...contentRichOnly } : { ...contentCommon, ...contentTextOnly }; const content = rich ? { ...contentCommon, ...contentRichOnly } : { ...contentCommon, ...contentTextOnly };
const finalContent = thread ? { ...content, ...contentThreadOnly } : content
await client.sendEvent(roomId, "m.room.message", content); await client.sendEvent(roomId, "m.room.message", finalContent);
} }
export async function sendChatGPTMessage(chatGPT: ChatGPTAPIBrowser, question: string, storedConversation: StoredConversation) { export async function sendChatGPTMessage(chatGPT: ChatGPTAPIBrowser, question: string, storedConversation: StoredConversation) {