matrix-chatgpt-bot/src/utils.ts
2023-01-27 17:45:41 +00:00

92 lines
2.9 KiB
TypeScript

import { ChatGPTAPIBrowser, ChatResponse } from "chatgpt";
import Markdown from 'markdown-it';
import { MatrixClient } from "matrix-bot-sdk";
import { MessageEvent, StoredConversation } from "./interfaces.js";
import { CHATGPT_TIMEOUT } from "./env.js";
const md = Markdown();
export function parseMatrixUsernamePretty(matrix_username: string): string {
if (matrix_username.includes(":") === false || matrix_username.includes("@") === false) {
return matrix_username;
}
const withoutUrl = matrix_username.split(':')[0];
return withoutUrl.split('@')[1]
}
export function isEventAMessage(event: any): event is MessageEvent {
return event.type === 'm.room.message'
}
export async function sendError(client: MatrixClient, text: string, roomId: string, eventId: string): Promise<void> {
Promise.all([client.setTyping(roomId, false, 500), client.sendText(roomId, text), client.sendReadReceipt(roomId, eventId)]);
}
/**
* Send a thread reply.
* @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} thread reply as a thread
* @param {boolean} rich should the plain text be rendered to html using markdown?
*/
export async function sendReply(client: MatrixClient, roomId: string, rootEventId: string, text: string, thread: boolean = false, rich:boolean = false): Promise<void> {
const contentCommon = {
body: text,
msgtype: "m.text",
}
const contentThreadOnly = {
"m.relates_to": {
event_id: rootEventId,
is_falling_back: true,
"m.in_reply_to": {
"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 };
const finalContent = thread ? { ...content, ...contentThreadOnly } : content
await client.sendEvent(roomId, "m.room.message", finalContent);
}
export async function sendChatGPTMessage(chatGPT: ChatGPTAPIBrowser, question: string, storedConversation: StoredConversation) {
let result: ChatResponse
if (storedConversation !== undefined) {
result = await chatGPT.sendMessage(question, {
timeoutMs: CHATGPT_TIMEOUT,
conversationId: storedConversation.conversationId,
parentMessageId: storedConversation.messageId
});
} else {
result = await chatGPT.sendMessage(question, { timeoutMs: CHATGPT_TIMEOUT });
}
return result
}