Apex Integrations OpenAI SOQL 

Upload a file from Apex to use in the OpenAI Assistant

Remember the OpenAI Assistant from this recent post? Yep, still up and running, since recently doing so on steroids.

The extra fuel? Custom data. So that your assistant is not only able to rely on ChatGPT’s wisdom on its own, but also to allow it to perform searches, predictions, analyses, based on data you feed to the assistant.

That all might sound pretty straightforward, but unfortunately the implementation itself isn’t. After several attempts, the only scenario that proved working makes use of a random boundary, in combination with a plain text (so not Base64 encoded) body.

The following code, to be implemented inside an Apex method, has proved working with XML, CSV and JSON formats (take a look at the previous post for instructions to set up Subscription Key, Named Credential and other Salesforce to OpenAI integration basics):

String SUBSCRIPTION_KEY = '{insert key here}';
String fileId = null;
HttpRequest requestFile = new HttpRequest();
requestFile.setEndpoint('callout:OpenAI/v1/files');
requestFile.setMethod('POST');

// Set any unique random boundary string
String boundary = '----WebKitFormBoundary7MA4YWxkTrZu0gW'; 
requestFile.setHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
requestFile.setHeader('Authorization', 'Bearer ' + SUBSCRIPTION_KEY);

// Replace this with the plain text string of the file you wish to upload
String csvContentString = 'Header1,Header2\n1,2\n3,4';

// Construct the JSON body for the request
String body;
body = '--' + boundary + '\n';
body += 'Content-Disposition: form-data; name="purpose"\n';
body += '\n';
body += 'assistants\n';  // Assuming the purpose is for assistants, change it as required for your use case
body += '--' + boundary + '\n';

// Replace any csv reference in the following 2 lines with the file format you are using, e.g. json or xml
body += 'Content-Disposition: form-data; name="file"; filename="data.csv"\n';+
body += 'Content-Type: text/csv\n\n';

// From here on, code is generic again
body += csvContentString + '\n';
body += '--' + boundary + '--';

requestFile.setBody(body);

// Send the request and handle the response
Http httpFile = new Http();
HttpResponse responseFile = httpFile.send(requestFile);
if (responseFile.getStatusCode() >= 200 && responseFile.getStatusCode() < 300) {
    Map<String, Object> responseDataFile = (Map<String, Object>) JSON.deserializeUntyped(responseFile.getBody());
    if(responseDataFile.containsKey('id')){
        fileId = String.valueOf(responseDataFile.get('id'));
        // Continue processing fileId...
    }
}

The fileId retrieved can then be used in the request body to create a thread, like:

HttpRequest addMessageRequest = new HttpRequest();
addMessageRequest.setEndpoint('callout:OpenAI/v1/threads/' + threadId + '/messages');
addMessageRequest.setMethod('POST');
addMessageRequest.setHeader('Content-Type', 'application/json');
addMessageRequest.setHeader('Authorization', 'Bearer ' + SUBSCRIPTION_KEY);
addMessageRequest.setHeader('OpenAI-Beta', 'assistants=v1');

String requestBodyThread = '{' +
'"role": "user",' +
'"content": "Give a summary about the referenced file.",' + 
'"file_ids": ["' + fileId '"]' +
'}';
addMessageRequest.setBody(requestBodyThread);

Leave a Reply

Your email address will not be published. Required fields are marked *