beta release conversation context
This commit is contained in:
		
							
								
								
									
										35
									
								
								src/api.ts
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								src/api.ts
									
									
									
									
									
								
							| @ -1,5 +1,5 @@ | ||||
| import { envConfig, prisma } from "./main.js"; | ||||
| import { PleromaEmoji, Notification } from "../types.js"; | ||||
| import { PleromaEmoji, Notification, ContextResponse } from "../types.js"; | ||||
|  | ||||
| const getNotifications = async () => { | ||||
|   const { bearerToken, pleromaInstanceUrl } = envConfig; | ||||
| @ -22,6 +22,32 @@ const getNotifications = async () => { | ||||
|   } | ||||
| }; | ||||
|  | ||||
| const getStatusContext = async (statusId: string) => { | ||||
|   const { bearerToken, pleromaInstanceUrl } = envConfig; | ||||
|   try { | ||||
|     const response = await fetch( | ||||
|       `${pleromaInstanceUrl}/api/v1/statuses/${statusId}/context`, | ||||
|       { | ||||
|         method: "GET", | ||||
|         headers: { | ||||
|           Authorization: `Bearer ${bearerToken}`, | ||||
|         }, | ||||
|       } | ||||
|     ); | ||||
|     if (!response.ok) { | ||||
|       throw new Error( | ||||
|         `Could not get conversation context: ${response.status} - ${response.statusText}` | ||||
|       ); | ||||
|     } | ||||
|     const data: ContextResponse = await response.json(); | ||||
|     return data; | ||||
|   } catch (error: unknown) { | ||||
|     if (error instanceof Error) { | ||||
|       throw new Error(error.message); | ||||
|     } | ||||
|   } | ||||
| }; | ||||
|  | ||||
| const getInstanceEmojis = async () => { | ||||
|   const { bearerToken, pleromaInstanceUrl } = envConfig; | ||||
|   try { | ||||
| @ -72,4 +98,9 @@ const deleteNotification = async (notification: Notification) => { | ||||
|   } | ||||
| }; | ||||
|  | ||||
| export { deleteNotification, getInstanceEmojis, getNotifications }; | ||||
| export { | ||||
|   deleteNotification, | ||||
|   getInstanceEmojis, | ||||
|   getNotifications, | ||||
|   getStatusContext, | ||||
| }; | ||||
|  | ||||
							
								
								
									
										41
									
								
								src/main.ts
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								src/main.ts
									
									
									
									
									
								
							| @ -6,6 +6,7 @@ import { | ||||
|   // OllamaChatResponse, | ||||
|   OllamaRequest, | ||||
|   OllamaResponse, | ||||
|   PostAncestorsForModel, | ||||
| } from "../types.js"; | ||||
| // import striptags from "striptags"; | ||||
| import { PrismaClient } from "../generated/prisma/client.js"; | ||||
| @ -13,13 +14,14 @@ import { | ||||
|   getInstanceEmojis, | ||||
|   deleteNotification, | ||||
|   getNotifications, | ||||
|   getStatusContext, | ||||
| } from "./api.js"; | ||||
| import { storeUserData, storePromptData } from "./prisma.js"; | ||||
| import { | ||||
|   isFromWhitelistedDomain, | ||||
|   alreadyRespondedTo, | ||||
|   recordPendingResponse, | ||||
|   trimInputData, | ||||
|   // trimInputData, | ||||
|   selectRandomEmoji, | ||||
|   shouldContinue, | ||||
| } from "./util.js"; | ||||
| @ -44,6 +46,7 @@ export const envConfig = { | ||||
|     ? parseInt(process.env.RANDOM_POST_INTERVAL) | ||||
|     : 3600000, | ||||
|   botAccountId: process.env.PLEROMA_ACCOUNT_ID, | ||||
|   replyWithContext: process.env.REPLY_WITH_CONTEXT === "true" ? true : false, | ||||
| }; | ||||
|  | ||||
| const ollamaConfig: OllamaConfigOptions = { | ||||
| @ -60,8 +63,13 @@ const ollamaConfig: OllamaConfigOptions = { | ||||
| const generateOllamaRequest = async ( | ||||
|   notification: Notification | ||||
| ): Promise<OllamaResponse | undefined> => { | ||||
|   const { whitelistOnly, ollamaModel, ollamaSystemPrompt, ollamaUrl } = | ||||
|     envConfig; | ||||
|   const { | ||||
|     whitelistOnly, | ||||
|     ollamaModel, | ||||
|     ollamaSystemPrompt, | ||||
|     ollamaUrl, | ||||
|     replyWithContext, | ||||
|   } = envConfig; | ||||
|   try { | ||||
|     if (shouldContinue(notification)) { | ||||
|       if (whitelistOnly && !isFromWhitelistedDomain(notification)) { | ||||
| @ -73,12 +81,30 @@ const generateOllamaRequest = async ( | ||||
|       } | ||||
|       await recordPendingResponse(notification); | ||||
|       await storeUserData(notification); | ||||
|       let conversationHistory: PostAncestorsForModel[] = []; | ||||
|       if (replyWithContext) { | ||||
|         const contextPosts = await getStatusContext(notification.status.id); | ||||
|         if (!contextPosts?.ancestors || !contextPosts) { | ||||
|           throw new Error(`Unable to obtain post context ancestors.`); | ||||
|         } | ||||
|         conversationHistory = contextPosts.ancestors.map((ancestor) => { | ||||
|           const mentions = ancestor.mentions.map((mention) => mention.acct); | ||||
|           return { | ||||
|             account_fqn: ancestor.account.fqn, | ||||
|             mentions, | ||||
|             plaintext_content: ancestor.pleroma.content["text/plain"], | ||||
|           }; | ||||
|         }); | ||||
|         // console.log(conversationHistory); | ||||
|       } | ||||
|       const oneOffPrompt = `${notification.status.account.fqn} says: ${notification.status.pleroma.content["text/plain"]}\n[/INST]`; | ||||
|       const contextPrompt = `<<SYS>>[INST]\n${ollamaSystemPrompt}\nHere is the previous conversation context in JSON format:\n${JSON.stringify( | ||||
|         conversationHistory | ||||
|       )}\nAssume the {account_fqn} key is the user who posted the {plaintext_content} to the users in {mentions}\nReply as if you are a party to the conversation. If you see '@nice-ai' or 'nice-ai' in the {mentions}, you are an addressee of the conversation.\nAppend the '@' sign to each username at the beginning when addressing users.<</SYS>>`; | ||||
|       const ollamaRequestBody: OllamaRequest = { | ||||
|         model: ollamaModel, | ||||
|         prompt: `${notification.status.account.fqn} says: ${trimInputData( | ||||
|           notification.status.content | ||||
|         )}`, | ||||
|         system: ollamaSystemPrompt, | ||||
|         prompt: oneOffPrompt, | ||||
|         system: replyWithContext ? contextPrompt : ollamaSystemPrompt, | ||||
|         stream: false, | ||||
|         options: ollamaConfig, | ||||
|       }; | ||||
| @ -87,6 +113,7 @@ const generateOllamaRequest = async ( | ||||
|         body: JSON.stringify(ollamaRequestBody), | ||||
|       }); | ||||
|       const ollamaResponse: OllamaResponse = await response.json(); | ||||
|  | ||||
|       await storePromptData(notification, ollamaResponse); | ||||
|       return ollamaResponse; | ||||
|     } | ||||
|  | ||||
| @ -40,7 +40,7 @@ const shouldContinue = (notification: Notification) => { | ||||
|     const { botAccountId } = envConfig; | ||||
|     const statusContent = trimInputData(notification.status.content); | ||||
|     if ( | ||||
|       notification.status.visibility !== "private" && | ||||
|       // notification.status.visibility !== "private" && | ||||
|       !notification.account.bot && | ||||
|       notification.type === "mention" | ||||
|     ) { | ||||
|  | ||||
		Reference in New Issue
	
	Block a user