From e6c4eb3f1c2257f9084a70e6261de06bf1bbc184 Mon Sep 17 00:00:00 2001
From: Sean Hatfield <seanhatfield5@gmail.com>
Date: Wed, 25 Sep 2024 13:44:26 -0700
Subject: [PATCH] Support attachments in developer API (#2373)

* support attachments in developer api

* lint

---------

Co-authored-by: Timothy Carambat <rambat1010@gmail.com>
---
 server/endpoints/api/workspace/index.js | 34 ++++++++++++++++++++++---
 server/swagger/openapi.json             | 18 +++++++++++--
 server/utils/chats/apiChatHandler.js    |  6 +++++
 3 files changed, 52 insertions(+), 6 deletions(-)

diff --git a/server/endpoints/api/workspace/index.js b/server/endpoints/api/workspace/index.js
index d2040be1e..fca441e25 100644
--- a/server/endpoints/api/workspace/index.js
+++ b/server/endpoints/api/workspace/index.js
@@ -546,7 +546,14 @@ function apiWorkspaceEndpoints(app) {
            example: {
              message: "What is AnythingLLM?",
              mode: "query | chat",
-             sessionId: "identifier-to-partition-chats-by-external-id"
+             sessionId: "identifier-to-partition-chats-by-external-id",
+             attachments: [
+               {
+                 name: "image.png",
+                 mime: "image/png",
+                 contentString: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
+               }
+             ]
            }
          }
        }
@@ -576,7 +583,12 @@ function apiWorkspaceEndpoints(app) {
    */
       try {
         const { slug } = request.params;
-        const { message, mode = "query", sessionId = null } = reqBody(request);
+        const {
+          message,
+          mode = "query",
+          sessionId = null,
+          attachments = [],
+        } = reqBody(request);
         const workspace = await Workspace.get({ slug: String(slug) });
 
         if (!workspace) {
@@ -612,6 +624,7 @@ function apiWorkspaceEndpoints(app) {
           user: null,
           thread: null,
           sessionId: !!sessionId ? String(sessionId) : null,
+          attachments,
         });
 
         await Telemetry.sendTelemetry("sent_chat", {
@@ -655,7 +668,14 @@ function apiWorkspaceEndpoints(app) {
            example: {
              message: "What is AnythingLLM?",
              mode: "query | chat",
-             sessionId: "identifier-to-partition-chats-by-external-id"
+             sessionId: "identifier-to-partition-chats-by-external-id",
+             attachments: [
+               {
+                 name: "image.png",
+                 mime: "image/png",
+                 contentString: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
+               }
+             ]
            }
          }
        }
@@ -706,7 +726,12 @@ function apiWorkspaceEndpoints(app) {
    */
       try {
         const { slug } = request.params;
-        const { message, mode = "query", sessionId = null } = reqBody(request);
+        const {
+          message,
+          mode = "query",
+          sessionId = null,
+          attachments = [],
+        } = reqBody(request);
         const workspace = await Workspace.get({ slug: String(slug) });
 
         if (!workspace) {
@@ -749,6 +774,7 @@ function apiWorkspaceEndpoints(app) {
           user: null,
           thread: null,
           sessionId: !!sessionId ? String(sessionId) : null,
+          attachments,
         });
         await Telemetry.sendTelemetry("sent_chat", {
           LLMSelection:
diff --git a/server/swagger/openapi.json b/server/swagger/openapi.json
index f412f0a4f..6107331d5 100644
--- a/server/swagger/openapi.json
+++ b/server/swagger/openapi.json
@@ -1958,7 +1958,14 @@
               "example": {
                 "message": "What is AnythingLLM?",
                 "mode": "query | chat",
-                "sessionId": "identifier-to-partition-chats-by-external-id"
+                "sessionId": "identifier-to-partition-chats-by-external-id",
+                "attachments": [
+                  {
+                    "name": "image.png",
+                    "mime": "image/png",
+                    "contentString": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
+                  }
+                ]
               }
             }
           }
@@ -2053,7 +2060,14 @@
               "example": {
                 "message": "What is AnythingLLM?",
                 "mode": "query | chat",
-                "sessionId": "identifier-to-partition-chats-by-external-id"
+                "sessionId": "identifier-to-partition-chats-by-external-id",
+                "attachments": [
+                  {
+                    "name": "image.png",
+                    "mime": "image/png",
+                    "contentString": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
+                  }
+                ]
               }
             }
           }
diff --git a/server/utils/chats/apiChatHandler.js b/server/utils/chats/apiChatHandler.js
index 3fa475ca1..f37508534 100644
--- a/server/utils/chats/apiChatHandler.js
+++ b/server/utils/chats/apiChatHandler.js
@@ -29,6 +29,7 @@ const { Telemetry } = require("../../models/telemetry");
  *  user: import("@prisma/client").users|null,
  *  thread: import("@prisma/client").workspace_threads|null,
  *  sessionId: string|null,
+ *  attachments: { name: string; mime: string; contentString: string }[],
  * }} parameters
  * @returns {Promise<ResponseObject>}
  */
@@ -39,6 +40,7 @@ async function chatSync({
   user = null,
   thread = null,
   sessionId = null,
+  attachments = [],
 }) {
   const uuid = uuidv4();
   const chatMode = mode ?? "chat";
@@ -251,6 +253,7 @@ async function chatSync({
       userPrompt: message,
       contextTexts,
       chatHistory,
+      attachments,
     },
     rawHistory
   );
@@ -301,6 +304,7 @@ async function chatSync({
  *  user: import("@prisma/client").users|null,
  *  thread: import("@prisma/client").workspace_threads|null,
  *  sessionId: string|null,
+ *  attachments: { name: string; mime: string; contentString: string }[],
  * }} parameters
  * @returns {Promise<VoidFunction>}
  */
@@ -312,6 +316,7 @@ async function streamChat({
   user = null,
   thread = null,
   sessionId = null,
+  attachments = [],
 }) {
   const uuid = uuidv4();
   const chatMode = mode ?? "chat";
@@ -536,6 +541,7 @@ async function streamChat({
       userPrompt: message,
       contextTexts,
       chatHistory,
+      attachments,
     },
     rawHistory
   );