From 6713b66da402655ed6cbdc5ba0b6cafaac00d28f Mon Sep 17 00:00:00 2001 From: bertybuttface <110790513+bertybuttface@users.noreply.github.com> Date: Sun, 8 Jan 2023 20:19:43 +0000 Subject: [PATCH] Add Markdown support for ChatGPT --- package.json | 1 + src/handlers.ts | 4 ++-- src/utils.ts | 45 +++++++++++++++++++++++++++++++++++++-------- 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 6474311..3d89791 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "dependencies": { "chatgpt": "^3.3.10", "dotenv": "^16.0.3", + "markdown-it": "^13.0.1", "matrix-bot-sdk": "^0.6.3", "puppeteer": "^19.4.1", "typescript": "^4.9.4", diff --git a/src/handlers.ts b/src/handlers.ts index eed04eb..c68b3c0 100644 --- a/src/handlers.ts +++ b/src/handlers.ts @@ -44,7 +44,7 @@ export default class CommandHandler { if (MATRIX_BLACKLIST.split(" ").find(b => event.sender.endsWith(b))) return; // Ignore if on blacklist if set } if ((MATRIX_WHITELIST !== undefined) && MATRIX_WHITELIST){ - if (!MATRIX_WHITELIST.split(" ").find(w => event.sender.endsWith(w))) return; // Ignore if not on whitelist if set + if (!MATRIX_WHITELIST.split(" ").find(w => event.sender.endsWith(w))) return; // Ignore if not on whitelist if set } const rootEventId: string = (relatesTo !== undefined && relatesTo.event_id !== undefined) ? relatesTo.event_id : event.event_id; const storedValue: string = await this.client.storageProvider.readValue('gpt-' + rootEventId) @@ -88,7 +88,7 @@ export default class CommandHandler { result = await this.chatGPT.sendMessage(question, {timeoutMs: CHATGPT_TIMEOUT}); } - await Promise.all([this.client.setTyping(roomId, false, 500), sendThreadReply(this.client, `${result.response}`, roomId, rootEventId)]); + await Promise.all([this.client.setTyping(roomId, false, 500), sendThreadReply(this.client, roomId, rootEventId,`${result.response}`, true)]); await this.client.storageProvider.storeValue('gpt-' + rootEventId, JSON.stringify({ conversationId: result.conversationId, diff --git a/src/utils.ts b/src/utils.ts index 046c06b..052f1de 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,6 +1,9 @@ +import Markdown from 'markdown-it'; import { MatrixClient } from "matrix-bot-sdk"; import { MessageEvent } from "./interfaces.js"; +const md = Markdown(); + export function parseMatrixUsernamePretty(matrix_username: string): string { if (matrix_username.includes(":") === false || matrix_username.includes("@") === false) { return matrix_username; @@ -19,23 +22,49 @@ export async function sendError(client: MatrixClient, text: string, roomId: stri /** * Send a thread reply. - * @param client Matrix client - * @param param1 Object containing text, root_event_id and roomId. root_event_id is the event_id - * of the message the thread "replying" to. + * @param {MatrixClient} client Matrix client + * @param {string} roomId the room ID the event being replied to resides in + * @param {string} rootEventId the root event of the thread + * @param {string} text the plain text to reply with + * @param {boolean} rich should the plain text be rendered to html using markdown? */ -export async function sendThreadReply(client: MatrixClient, text: string, roomId: string, root_event_id: string): Promise { - const content = { +export async function sendThreadReply(client: MatrixClient, roomId: string, rootEventId: string, text: string, rich:boolean = false): Promise { + + const contentCommon = { body: text, msgtype: "m.text", - "org.matrix.msc1767.text": text, "m.relates_to": { - event_id: root_event_id, + event_id: rootEventId, is_falling_back: true, "m.in_reply_to": { - "event_id": root_event_id + "event_id": rootEventId }, rel_type: "m.thread" } } + + const contentTextOnly = { + "org.matrix.msc1767.text": text, + } + + const renderedText = md.render(text) + + const contentRichOnly = { + format: "org.matrix.custom.html", + formatted_body: renderedText, + "org.matrix.msc1767.message": [ + { + "body": text, + "mimetype": "text/plain" + }, + { + "body": renderedText, + "mimetype": "text/html" + } + ] + } + + const content = rich ? { ...contentCommon, ...contentRichOnly } : { ...contentCommon, ...contentTextOnly }; + await client.sendEvent(roomId, "m.room.message", content); }