diff --git a/src/main.ts b/src/main.ts index 77724ca..a001d62 100644 --- a/src/main.ts +++ b/src/main.ts @@ -10,14 +10,35 @@ import { PrismaClient } from "../generated/prisma/client.js"; const prisma = new PrismaClient(); +const envConfig = { + pleromaInstanceUrl: process.env.PLEROMA_INSTANCE_URL || "", + pleromaInstanceDomain: process.env.PLEROMA_INSTANCE_DOMAIN || "", + onlyLocalReplies: process.env.ONLY_LOCAL_REPLIES === "true" ? true : false, + ollamaUrl: process.env.OLLAMA_URL || "", + ollamaSystemPrompt: + process.env.OLLAMA_SYSTEM_PROMPT || + "You are a helpful AI assistant. Answer all questions concisely.", + ollamaModel: process.env.OLLAMA_MODEL || "", + fetchInterval: process.env.FETCH_INTERVAL + ? parseInt(process.env.FETCH_INTERVAL) + : 15000, + bearerToken: process.env.INSTANCE_BEARER_TOKEN || "", +}; + +const ollamaConfig: OllamaConfigOptions = { + temperature: 0.3, + num_predict: 400, +}; + const getNotifications = async () => { + const { bearerToken, pleromaInstanceUrl } = envConfig; try { const request = await fetch( - `${process.env.PLEROMA_INSTANCE_URL}/api/v1/notifications?types[]=mention`, + `${pleromaInstanceUrl}/api/v1/notifications?types[]=mention`, { method: "GET", headers: { - Authorization: `Bearer ${process.env.INSTANCE_BEARER_TOKEN}`, + Authorization: `Bearer ${bearerToken}`, }, } ); @@ -82,11 +103,12 @@ const storePromptData = async ( } }; -const trimInputData = (input: string) => { +const trimInputData = (input: string): string => { const strippedInput = striptags(input); const split = strippedInput.split(" "); const promptStringIndex = split.indexOf("!prompt"); - return split.slice(promptStringIndex + 1).join(" "); // returns everything after the !prompt + split.splice(promptStringIndex, 1); + return split.join(" "); // returns everything after the !prompt }; const recordPendingResponse = async (notification: Notification) => { @@ -104,6 +126,13 @@ const recordPendingResponse = async (notification: Notification) => { const generateOllamaRequest = async ( notification: Notification ): Promise => { + const { + onlyLocalReplies, + pleromaInstanceDomain, + ollamaModel, + ollamaSystemPrompt, + ollamaUrl, + } = envConfig; try { if ( striptags(notification.status.content).includes("!prompt") && @@ -111,10 +140,8 @@ const generateOllamaRequest = async ( notification.type === "mention" ) { if ( - process.env.ONLY_LOCAL_REPLIES === "true" && - !notification.status.account.fqn.includes( - `@${process.env.PLEROMA_INSTANCE_DOMAIN}` - ) + onlyLocalReplies && + !notification.status.account.fqn.includes(`@${pleromaInstanceDomain}`) ) { return; } @@ -123,20 +150,16 @@ const generateOllamaRequest = async ( } await recordPendingResponse(notification); await storeUserData(notification); - const ollamaConfig: OllamaConfigOptions = { - temperature: 1.2, - num_predict: 400, - }; const ollamaRequestBody: OllamaRequest = { - model: process.env.OLLAMA_MODEL as string, - system: process.env.OLLAMA_SYSTEM_PROMPT as string, + model: ollamaModel, + system: ollamaSystemPrompt, prompt: `@${notification.status.account.fqn} says: ${trimInputData( notification.status.content )}`, stream: false, options: ollamaConfig, }; - const response = await fetch(`${process.env.OLLAMA_URL}/api/generate`, { + const response = await fetch(`${ollamaUrl}/api/generate`, { method: "POST", body: JSON.stringify(ollamaRequestBody), }); @@ -153,6 +176,7 @@ const postReplyToStatus = async ( notification: Notification, ollamaResponseBody: OllamaResponse ) => { + const { pleromaInstanceUrl, bearerToken } = envConfig; try { let mentions: string[]; const statusBody: NewStatusBody = { @@ -170,17 +194,14 @@ const postReplyToStatus = async ( statusBody.to = mentions; } - const response = await fetch( - `${process.env.PLEROMA_INSTANCE_URL}/api/v1/statuses`, - { - method: "POST", - headers: { - Authorization: `Bearer ${process.env.INSTANCE_BEARER_TOKEN}`, - "Content-Type": "application/json", - }, - body: JSON.stringify(statusBody), - } - ); + const response = await fetch(`${pleromaInstanceUrl}/api/v1/statuses`, { + method: "POST", + headers: { + Authorization: `Bearer ${bearerToken}`, + "Content-Type": "application/json", + }, + body: JSON.stringify(statusBody), + }); if (!response.ok) { throw new Error(`New status request failed: ${response.statusText}`); @@ -193,6 +214,7 @@ const postReplyToStatus = async ( }; const deleteNotification = async (notification: Notification) => { + const { pleromaInstanceUrl, bearerToken } = envConfig; try { if (!notification.id) { return; @@ -203,11 +225,11 @@ const deleteNotification = async (notification: Notification) => { data: { isProcessing: false }, }); const response = await fetch( - `${process.env.PLEROMA_INSTANCE_URL}/api/v1/notifications/${notification.id}/dismiss`, + `${pleromaInstanceUrl}/api/v1/notifications/${notification.id}/dismiss`, { method: "POST", headers: { - Authorization: `Bearer ${process.env.INSTANCE_BEARER_TOKEN}`, + Authorization: `Bearer ${bearerToken}`, }, } ); @@ -221,10 +243,6 @@ const deleteNotification = async (notification: Notification) => { } }; -const fetchInterval = process.env.FETCH_INTERVAL - ? parseInt(process.env.FETCH_INTERVAL) - : 15000; - let notifications = []; const beginFetchCycle = async () => { setInterval(async () => { @@ -243,12 +261,12 @@ const beginFetchCycle = async () => { }) ); } - }, fetchInterval); // lower intervals may cause the bot to respond multiple times to the same message, but we try to mitigate this with the deleteNotification function + }, envConfig.fetchInterval); // lower intervals may cause the bot to respond multiple times to the same message, but we try to mitigate this with the deleteNotification function }; console.log( - `Fetching notifications from ${process.env.PLEROMA_INSTANCE_DOMAIN}, every ${ - fetchInterval / 1000 + `Fetching notifications from ${envConfig.pleromaInstanceDomain}, every ${ + envConfig.fetchInterval / 1000 } seconds.` ); await beginFetchCycle();