Page 1 of 1

tsNetPostSync issues with AnythingLLM server document upload. (SOLVED)

Posted: Fri Jan 17, 2025 4:24 pm
by mrcoollion
Hello all LC friends.
Mayby somebody can help me with the following issue I have been working on for hours and hours... :-( >>> (SOLVED :-) )

I have the following code to communicate with AnythingLLM for uploading data for use by an AI in a specific workplace. Moving the uploaded file to a workspace will be the next command but i first need to get this working!
I use tsNetPostSync but I cannot seem to get the post data correct. The serverkeeps throwing me error 500 with message : {"success":false,"error":"Invalid file upload. Unexpected end of form"}.
The to upload file only has one word in it Hello , so I do not think the problem is the file.
The following code is the original code i need to translate to LiveCode script.

Code: Select all

import requests
import os

api_url = "http://localhost:3001/api/v1/document/upload"
headers = {
    "Authorization": "[My API Key]",
    "accept": "application/json"
}

pdf_filename = "temp.pdf"
files = {'file': open(pdf_filename, 'rb')}
print(f"Sending files: {pdf_filename}")
response = requests.post(api_url, headers=headers, files=files)
if response.status_code == 200:
    print("PDF successfully uploaded to the API.")
else:
    print(f"Failed. Status code: {response.status_code}, Response: {response.text}")
Here is the full code of the LiveCode command:

Code: Select all

command AI_AnythingLLM_File_Upload tInPathAndFile @tOutMessage @tOutResultCode @tOutFilename @tOutDocumentID @tOutResultMessage
   ------------------------------------------------------------------
   put "binfile:" & tInPathAndFile into tInBinPathAndFile
   try
      put URL tInBinPathAndFile into tFileContent
   catch errorVariable
      put "Error 1" into tOutResultCode
      put "Could not Read file " & tInPathAndFile into tOutResultMessage
      exit AI_AnythingLLM_File_Upload
   end try
   ------------------------------------------------------------------
   put "Hello" into tFileContent
   ------------------------------------------------------------------
   set the itemdelimiter to "\"
   put the last item of tInPathAndFile into tFilename
   put tInPathAndFile into tInPath
   delete the last item of tInPath
   put "\" after tInPath
   set the itemdelimiter to comma
   ------------------------------------------------------------------
   # API key and URL
   # AnythingLLM API key
   put "NH*******************DR65" into tApiKey //AnythingLLM
   ------------------------------------------------------------------
   put "http://localhost:3001/api/v1/document/upload" into tURLString
   ------------------------------------------------------------------
   -- Generate a unique boundary string
   put "UniqueDataBoundary" & the ticks into tBoundary
   ------------------------------------------------------------------
   -- Construct the multipart/form-data body
   put "" into tPostData  -- Initialize tPostData
   
   put "--" & tBoundary & cr & ¬  -- Use cr instead of return
   "Content-Disposition: form-data; name=" & quote & "file" & quote & "; filename=" & quote & tFilename & quote & cr & ¬
   "Content-Type: text/csv" & cr & cr & ¬  
   tFileContent & cr & ¬
   "--" & tBoundary & "--" & cr into tPostData 
   ------------------------------------------------------------------   -- Calculate the length of tPostData in bytes
   put the length of tPostData into tContentLength
   ------------------------------------------------------------------
   -- Prepare headers
   put "Content-Type: multipart/form-data; boundary=" & tBoundary & cr & ¬
   "Content-Length: " & tContentLength & cr & ¬
   "accept: application/json" & cr & ¬
   "Authorization: Bearer " & tApiKey into tHeaders
   ------------------------------------------------------------------
   put tHeaders into tPrePostHeaders
   ------------------------------------------------------------------
   # Make the API call using TSNet
   tsNetInit
   put tsNetPostSync(tURLString, tHeaders, tPostData, tRecvHeaders, tResult, tBytes) into tData
   tsNetClose
   ------------------------------------------------------------------
   put tResult into tOutResultCode
   if tResult is not 200 
   then 
      put "--- Result ---" &return& "Could not upload file. Error code : " & tResult &return& "Data: " & tData &return& "RecvHeaders: " & tRecvHeaders &return&"--- Posted information ---" &return& "RequestString: " & tURLString &return&  "Headers: " & tHeaders &return& "PostData: " & tPostData into tOutResultMessage
   else 
      put JSONtoArray(tData) into tResultArray
      put tResultArray["textResponse"] into tOutResultMessage
   end if
   ------------------------------------------------------------------
end AI_AnythingLLM_File_Upload

After 2 days of experimenting I got it working with the following code for those who are interested.
Explenations are in the code comments.

Code: Select all

-- Data between boundary
      -- Boundary must start with --   and end with -- including the start boundar variable --  
      -- in PostData part every line must end with crlf
      -- The data part in tPostData needs to start and end with crlf
      put "--" & tBoundary & crlf & \  
            "Content-Disposition: form-data; name=~file~;filename=~"& tFilename & "~" & crlf & \
            "Content-Type: text/csv" & crlf &\ // text/csv
            crlf & tFileContent & crlf & \
            "--" & tBoundary & "--" into tPostData 
      -- Prepare headers, in Headers do not use crlf but use lf
      -- Also boundary needs to be the plain boundary string without the pre  --
      put "Content-Type: multipart/form-data; boundary=" & tBoundary & lf & \  
            "accept: application/json" & lf & \
            "Authorization: Bearer " & tApiKey into tHeaders
I Use

Code: Select all

 put repQ(tPostData,"~") into tPostData 
to place quotes into the variable data. Below is the function ( got it from this forum :-) )

Code: Select all

function repQ pText,pQ
   replace pQ with quote in pText
   return pText
end repQ