Giter Club home page Giter Club logo

salesforce-sdk's Introduction

IBM Watson Salesforce SDK

Build Status Slack semantic-release

The IBM Watson Salesforce SDK uses the Watson API services to help you solve complex problems using Apex in your Salesforce environment. If you'd like, you can follow along with our video playlist here to start using the SDK. Otherwise, continue reading to learn how to get started.

NOTE: This is a Community SDK and not an official SDK. See https://cloud.ibm.com/docs/watson?topic=watson-using-sdks#community-sdks

Before you begin

Getting credentials

To find out which authentication to use, view the service credentials. You find the service credentials for authentication the same way for all Watson services:

  1. Go to the IBM Cloud Dashboard page.
  2. Either click an existing Watson service instance in your resource list or click Create resource > AI and create a service instance.
  3. Click on the Manage item in the left nav bar of your service instance.

On this page, you should be able to see your credentials for accessing your service instance.

You'll also need a Salesforce account to run your Apex code. To get one, you can visit this link.

Installation

There are three supported installation methods: automatically using Salesforce DX, manually using Salesforce DX, and manually using the Ant build tool. By default, all classes in the SDK will be deployed to your Salesforce org, but using Ant allows you to specify which services you want to deploy to save space. Note though that this is only supported with the Ant build tool method.

Salesforce DX automatic deployment

You can automatically deploy the SDK to a new scratch environment using the Deploy to SFDX button.

Note: To use the automatic deployment button, you must log in using a Dev Hub org. If you do not have one, there should be a link to get one after you click the button.

Deploy

Salesforce DX manual deployment

You can also manually deploy the SDK code using the Salesforce DX CLI, which you can install here.

The first step to manual deployment is cloning the repository from GitHub using the following command:

git clone https://github.com/watson-developer-cloud/salesforce-sdk

Be sure to navigate to the cloned directory before continuing.

To deploy to a scratch org, do the following:

  1. Create a new scratch environment (optional if you don't want to re-use an existing one):

    sfdx force:org:create -a watson-sdk -s -f config/project-scratch-def.json
  2. Push the source to the scratch environment:

    sfdx force:source:push

If you want to use the Watson SDK within a non-scratch environment you can follow these steps:

  1. Authenticate the Salesforce DX CLI to the target environment:

    sfdx force:auth:web:login --setdefaultusername

    In the browser window that opens, sign in to your org with your credentials. More information here

  2. Convert the source code:

    sfdx force:source:convert -d mdapioutput/
  3. Deploy the source code:

    sfdx force:mdapi:deploy -d mdapioutput/ -w 100

Installation using the Ant Build Tool

Finally, you can also install or update the SDK using the Ant Build Tool. This method also allows you to specify which services you'd like to deploy.

  1. Clone this repository from GitHub using the following command:

    git clone https://github.com/watson-developer-cloud/salesforce-sdk
  2. Edit install/build.properties to insert your Salesforce username and password. Since you will be using the API to access Salesforce, remember to append your Security Token to your password.

  3. Open your command line to the install folder, then deploy using Ant:

    ant deployWatson

    By default, this will deploy all of the classes. To specify a service, use the -Dservice flag. Here is an example of just deploying the Watson Assistant service:

    ant deployWatson -Dservice=assistant

    Valid service names are all services listed here written as one word (e.g. Visual Recognition becomes visualrecognition). The parameter is case-insensitive. To deploy multiple services, just run the command again with the next desired service flag.

Authentication

To access your Watson services through Apex, you'll need to authenticate with your service credentials. There are two ways to do this: using a credential file or specifying credentials in the Apex code.

Note: Previously, it was possible to authenticate using a token in a header called X-Watson-Authorization-Token. This method is deprecated. The token continues to work with Cloud Foundry services, but is not supported for services that use Identity and Access Management (IAM) authentication. See here for details.

Using a credential file

With a credential file, you just need to put the file in the right place and the SDK will do the work of parsing it and authenticating. You can get this file by clicking the Download button for the credentials in the Manage tab of your service instance.

Once you've downloaded your file, you'll need to do the following:

  1. Log in to your Salesforce dashboard
  2. Go to Setup by clicking on the gear icon on the top right of the page
  3. Enter Static Resources in the quick find box and select the highlighted entry
  4. Create a new static resource
  5. Enter the name ibm_credentials (:point_left: this must be the name!)
  6. Upload the file you downloaded from the service dashboard page
  7. Set the cache control to Public

Once this is done, you're good to go! As an example, if you uploaded a credential file for your Discovery service, you just need to do the following in your code

IBMWatsonAuthenticator authenticator = new IBMWatsonConfigBasedAuthenticatorFactory('discovery');
IBMDiscoveryV1 discovery = new IBMDiscoveryV1('2019-04-30', authenticator);

and you'll be authenticated โœ…

If you're using more than one service at a time in your code and get two different credetnial files, just put the contents together in one file and upload it to your Static Resources with the same name as above. The SDK will handle assigning credentials to their appropriate services.

Specifying credentials in the Apex code

If the methods above don't work for you, setting credentials in the code is always an option. The examples below just show the minimum required arguments for each IBMWatsonAuthenticator implementation, but there are other constructors you can play with for more options.

Username and password

IBMWatsonAuthenticator authenticator = new IBMWatsonBasicAuthenticator('USERNAME', 'PASSWORD');
IBMDiscoveryV1 discovery = new IBMDiscoveryV1('2019-04-30', authenticator);
discovery.setServiceURL('URL');

Using IAM

IBMWatsonAuthenticator authenticator = new IBMWatsonIAMAuthenticator('API_KEY');
IBMDiscoveryV1 service = new IBMDiscoveryV1('2019-04-30', authenticator);
service.setServiceURL('URL');

ICP

IBMWatsonAuthenticator authenticator =
  new IBMWatsonBasicAuthenticator('USERNAME', 'PASSWORD');
IBMDiscoveryV1 service = new IBMDiscoveryV1('2019-04-30', authenticator);
service.setServiceURL('SERVICE ICP URL');

Note: Make sure you've got your self-signed certificate all set up in your Salesforce organization for this to work properly.

Cloud Pak for Data

IBMWatsonAuthenticator authenticator =
  new IBMWatsonCloudPakForDataAuthenticator('CP4D TOKEN EXCHANGE BASE URL', 'USERNAME', 'PASSWORD');
IBMDiscoveryV1 service = new IBMDiscoveryV1('2019-04-30', authenticator);
service.setServiceURL('SERVICE CP4D URL');

Setting remote site settings

The final piece of setup to access Watson services from your Salesforce environment is setting your remote site settings. To do so:

  1. Go to Setup by clicking on the gear icon on the top right of the Salesforce dashboard
  2. Enter Remote Site Settings in the quick find box and select the highlighted entry
  3. Click New Remote Site
  4. Add whatever name you desire, with the following URL: https://gateway.watsonplatform.net/
  5. Click Save

If you're authenticating with IAM, you'll also need to add your IAM URL in your remote site settings. The default URL is https://iam.cloud.ibm.com/identity/token.

Examples

Getting started using a service is very simple! All services follow the same pattern of service instantiation, option building, and requesting. To get an idea, below is an example of using the Discovery service to get a list of your current environments:

IBMWatsonAuthenticator authenticator = new IBMWatsonIAMAuthenticator('API_KEY');
IBMDiscoveryV1 discovery = new IBMDiscoveryV1('2019-04-30', authenticator);

// configuring options for listing environments
IBMDiscoveryV1Models.ListEnvironmentsOptions options =
  new IBMDiscoveryV1Models.ListEnvironmentsOptionsBuilder()
    .build();

// making request
IBMDiscoveryV1Models.ListEnvironmentsResponse environmentList = discovery.listEnvironments(options);
System.debug(environmentList);

Similarly, here is an example of creating an intent in the Watson Assistant service:

IBMWatsonAuthenticator authenticator = new IBMWatsonIAMAuthenticator('API_KEY');
IBMAssistantV1 assistant = new IBMAssistantV1('2019-02-28', authenticator);

// configuring options for creating intent
IBMAssistantV1Models.CreateIntentOptions options =
  new IBMAssistantV1Models.CreateIntentOptionsBuilder()
    .workspaceId('<workspace_id>')
    .intentName('MyIntent')
    .description('This is an example of creating an intent!')
    .build();

// making request
IBMAssistantV1Models.Intent intent = assistant.createIntent(options);
System.debug(intent);

The manner of instantiating and using services should be consistent no matter which you decide to use, which should make it easy to explore the many capabilities Watson services have to offer.

Request and response headers

The SDK supports sending custom headers with any request as well as parsing headers that are returned by the service.

To send request headers, simply add them as a property when building up your Options model. Here's an example in the Discovery service:

IBMDiscoveryV1Models.QueryOptions options =
  new IBMDiscoveryV1Models.QueryOptionsBuilder()
    .environmentId('<environment_id>')
    .collectionId('<collection_id>')
    .naturalLanguageQuery('Articles about the Boston Celtics')
    .addHeader('Custon-Header', 'custom_value') // custom header added here
    .build();

To get headers returned by the service, call the getHeaders() method on a response model. This is what it looks like to get the headers returned after making the above call:

IBMDiscoveryV1Models.QueryResponse response = discovery.query(options);
Map<String, String> responseHeaders = response.getHeaders();

Transaction IDs

Every SDK call returns a response with a transaction ID in the x-global-transaction-id header. This transaction ID is useful for troubleshooting and accessing relevant logs from your service instance.

IBMWatsonAuthenticator authenticator = new IBMWatsonIAMAuthenticator('API_KEY');
IBMAssistantV1 service = new IBMAssistantV1('2019-02-28', authenticator);

IBMAssistantV1Models.CreateIntentOptions options =
  new IBMAssistantV1Models.ListWorkspacesOptionsBuilder().build();
IBMAssistantV1Models.WorkspaceCollection> response;

try {
  // In a successful case, you can grab the ID with the following code.
  response = service.listWorkspaces(options);
	String transactionId = response.getHeaders().get('x-global-transaction-id');
} catch (IBMWatsonServiceExceptions.ServiceException e) {
  // This is how you get the ID from a failed request.
  // Make sure to use the IBMWatsonServiceExceptions.ServiceException class
  // or one of its subclasses!
  String transactionId = e.getResponse().getHeader('x-global-transaction-id');
}

Using the SDK with Lightning

The Watson Salesforce SDK models are Lightning-ready, meaning that you can access model properties through Javascript for your Lightning apps. Everything should work as expected, but it's important to note that there are two ways to go about dealing with dynamic models through Javascript. These models are ones which may have properties unknown until runtime and which extend IBMWatsonDynamicModel.

Using the additionalProperties object

Dynamic models have an extra "AuraEnabled" property called additionalProperties, which is a map that holds all of the dynamic properties returned with the model. If you're dealing with a dynamic model in your Javascript code and want to access any dynamic properties, you can do the following:

action.setCallback(this, function(response) {
  var resp = response.getReturnValue(); // resp is a dynamic model
  console.log(resp.additionalProperties["enriched_text"]["concepts"][0]["text"]);
});
$A.enqueueAction(action);

Any properties within the additionalProperties object can be accessed exactly like a generic Javascript object.

Using the model string representation

If going through the additionalProperties object is undesired for any reason, you can still access the dynamic properties as top-level properties with a small workaround. All models in the SDK override the toString() method to output the models as pretty-printed JSON with the additional properties brought up to the top level. Therefore, if you tweak your server-side controller to return the string representation instead of the model object, as follows:

public class ServerSideController {
  @AuraEnabled
  public static String query(String environmentId, String collectionId) {
    IBMDiscoveryV1 discovery = new IBMDiscoveryV1('2019-04-30');
    IBMDiscoveryV1Models.QueryOptions options = new IBMDiscoveryV1Models.QueryOptionsBuilder(environmentId, collectionId)
      .naturalLanguageQuery('example query')
      .build();
    IBMDiscoveryV1Models.QueryResponse response = discovery.query(options);

    // IMPORTANT: return the string instead of the model
    return response.toString();
  }
}

you can use JSON.parse() to access the whole object as a generic JSON object. Here is an example of accessing the same property in Javascript using this aternate method:

action.setCallback(this, function(response) {
  var resp = response.getReturnValue(); // resp is now the string representation of our dynamic model
  console.log(JSON.parse(resp)["enriched_text"]["concepts"][0]["text"]);
});
$A.enqueueAction(action);

Both methods shown above will print out the same information.

WebSocket support

Both the Text to Speech and Speech to Text services have API endpoints which support the use of WebSockets. However, the use of WebSockets are not supported natively by Apex. If you would like to take advantage of this functionality, the recommendation would be to leverage the Watson Speech Javascript SDK.

The above library adds minimal overhead and will allow for the use of WebSockets. Also, being Javascript, this SDK can integrate smoothly with Lightning apps and be used alongside the Salesforce SDK.

ICP/Cloud Pak for Data

If you're using this SDK to interact with a service on IBM Cloud Private (ICP) or Cloud Pak for Data (CP4D), you'll need to add your self-signed certificate to your Salesforce organization. You can do this in the Certificate and Key Management section of the security settings.

Functional tests

The force-app/main/test folder contains the example calls for each service. These examples are used for functional testing of services. Developers can use them for reference and testing the installed SDK.

Featured projects

We'd love to highlight cool open-source projects that use this SDK! If you'd like to get your project added to the list, feel free to make an issue linking us to it.

Contributing

If you're interested in helping to make this project better, see Contributing.md.

License

This library is licensed under the MIT license. Full license text is available in LICENSE.

salesforce-sdk's People

Contributors

benjdewan avatar germanattanasio avatar lpatino10 avatar magdielhf avatar maniax89 avatar mediumtaj avatar muenzpraeger avatar padamstx avatar pradeep-dani avatar ryanguest avatar semantic-release-bot avatar stevemart avatar sumeetbath avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

salesforce-sdk's Issues

Regenerate all current services

Since services have released, changes have been made to the APIs. We should regenerate all services to capture any changed/new functionality.

Acceptance Criteria:

  • Regenerate all services and put in new api-update branch
  • Update failing tests or add new ones to capture any changes in functionality
  • Update change log to explain breaking changes

Request time out while inserting file

Opening issue as I see the 500 request timeout error again. Here is the sample code where I am doing file insert but am getting this response. Let me know if I am doing anything wrong

Line: 152, Column: 1IBMWatsonServiceExceptions.InternalServerErrorException: { "code" : 500, "error" : "Request timed out, please try again." }

// finding PDF file uploaded to Salesforce with the name "sample_pdf"
String fileTitle = 'SalesSummit-ebrochure';
SObject[] queryResult = Database.query('Select VersionNumber, VersionData, Title, Origin, FileType, FileExtension, Description, ContentUrl, ContentSize, ContentLocation, ContentDocumentId From ContentVersion WHERE Title = :fileTitle');

IBMDiscoveryV1 discovery = new IBMDiscoveryV1('2017-11-07');

// the VersionData property has the Blob we want to use for our file
Blob fileBlob = (Blob) queryResult[0].get('VersionData');
IBMWatsonFile.FileBuilder fileBuilder = new IBMWatsonFile.FileBuilder();
fileBuilder.body(fileBlob);
IBMWatsonFile file = fileBuilder.build();

// we need to specify the filename and content type - validators have been added to check for this
IBMDiscoveryV1Models.AddDocumentOptions options = new IBMDiscoveryV1Models.AddDocumentOptionsBuilder()
  .environmentId('<<environment id>>')
  .collectionId('<<collectionid>>')
  .file(file)
  .filename('SalesSummit-ebrochure')
  .fileContentType(IBMWatsonHttpMediaType.APPLICATION_PDF)
  .build();

IBMDiscoveryV1Models.DocumentAccepted resp = discovery.addDocument(options);

Ensure scratch orgs created in Travis are always deleted

In our Travis build script, we create a temporary scratch org to make sure the code compiles and passes all tests. This org is deleted after a successful build, but the deletion command gets passed over if the build fails.

This has resulted in a lot of built up scratch orgs, and there's a limit of 40 we can have at a time. We should tweak the script to always delete the temporary org, no matter the build result.

Query Exception when multiple SDK versions are installed in different namespaces

Remember, an issue is not the place to ask questions. You can use Stack Overflow for that, or you may want to start a discussion on the dW Answers.

Before you open an issue, please check if a similar issue already exists or has been closed before.

When reporting a bug, please be sure to include the following

  • Salesforce version
  • SDK version
  • Steps to reproduce
  • Expected behavior
  • Actual behavior

When you open an issue for a feature request, please add as much detail as possible

  • A descriptive title starting with the service name: Conversation, Discovery...
  • A description of the problem you're trying to solve
  • A suggested solution if possible

Code coverage for Apex classes less than 75% - Reopen(#197)

Hello lpation10,

I work with posolutionez (Patrick) and we deployed the fix to our sandbox but there are still some classes which fall below the 75% threshold.

Following are the classes-

IBMWatsonDynamicResponseModel - 0%
IBMWatsonIAMToken - 60%
IBMWatsonICP4DToken - 73%
IBMWatsonICP4DTokenResponse - 5%
IBMWatsonNoauthAuthenticator - 25%
IBMWatsonResponseModel - 46%
IBMWatsonService - 73%

We are leveraging Watson Assistant and NLU part of the SDK but due to dependency between the classes above mentioned classes are also needed. When we deploy code from Sandbox to Stage and Production all classes need to have a minimum of 75% coverage it doesn't look for the whole SDK coverage. Please advice.

Originally posted by @daiyaharsh90 in #197 (comment)

When using an attachment we should not ask for filename or contentType

This

IBMDiscoveryV1Models.AddDocumentOptionsBuilder()
      .environmentId(environmentId)
      .collectionId(collectionId)
      .file(testfile)
      .filename(att.Name)
      .fileContentType(att.ContentType)
      .build();

Should be

IBMDiscoveryV1Models.AddDocumentOptionsBuilder()
      .environmentId(environmentId)
      .collectionId(collectionId)
      .file(testfile)
      .build();

This means setting the filename and content type inside the setter for file. You should still be able to set those manually if you want, though.

Investigate how to deploy the code for an specific service

We currently deploy the entire project which for some of our users could be a LOT of useless code. Apex has a 3mb limit and our SDK is ~ 1.2MB.

We could potentially update the ant script and deploy only the services that the users want to use.

Something like:

ant deploy conversation

Code coverage for Apex classes less than 75%

When trying to use the SDK for Assistant and/or NaturalLanguageUnderstanding capabilities, we're having issues installing the SDK files in our production org due to the fact that many of the tests do not have 75% code coverage or better. Since this is enforced by SF for production organizations, should this be considered a bug with this SDK? I am using the latest version of the SDK files here. Please advise and thanks!

Issue with Watson Assistant ListLogsOptions Method

Using the lastest sdk version and trying to get the Watson Assistant Log

IBMWatsonAuthenticator authenticator = new IBMWatsonBasicAuthenticator(username, password);
IBMAssistantV1 assistant = new IBMAssistantV1('2019-02-28', authenticator);
assistant.setServiceURL('https://gateway.watsonplatform.net/assistant/api');

IBMAssistantV1Models.ListLogsOptions listOptions = new IBMAssistantV1Models.ListLogsOptionsBuilder()
    .workspaceId(workspaceId)
    .build();
IBMAssistantV1Models.LogCollection response = assistant.listLogs(listOptions);
System.debug(response);

Currently getting this error

Line: 15, Column: 1
System.JSONException: Illegal value for boolean: true at [line:1, column:27]

Example of implementing Watson Assistant Context object

Currently, I'm trying to save the context object in lighting and bringing it back to the apex controller to use, but I'm having no luck. I tried passing the object, json serialize/deseralize, using the Context. deserialize method and so far nothing is working. I was thinking to try to save the context in the database, but then I realize that I'll have the same issue as before. Also, I can't save the context in the Apex Controller, due to the fact that Apex classes are stateless. One possible solution to solve this problem is creating a deserialize method that will cast the object we pass in as the Context object.

Tweak generator to instantiate "fileBody" variables inline

Currently, we have code that looks like this:

IBMWatsonRequestBody fileBody;
multipartBuilder.addFormDataPart('name', createClassifierOptions.name());
fileBody = IBMWatsonRequestBody.create(createClassifierOptions.classnamePositiveExamples(), 'application/octet-stream');

We want something like this:

multipartBuilder.addFormDataPart('name', createClassifierOptions.name());
IBMWatsonRequestBody fileBody = IBMWatsonRequestBody.create(createClassifierOptions.classnamePositiveExamples(), 'application/octet-stream');

Personality Insights, content_items_serialized_name param is invalid

"contentItems" JSON parameter for Personality Insights watson request is case sensitive and doesn't contain an underscore. This parameter (named "content_items_serialized_name") is incorrect in IBMPersonalityInsightsV3Models class which is causing following error: "{"code":400,"sub_code":"S00005","error":"Invalid JSON input at line 1, column 19"}".

Solution:
"content_items_serialized_name" attribute (all references) in IBMPersonalityInsightsV3Models class should be changed to "contentItems_serialized_name".

Enable Travis

Encrypt the build.properties file and add environment variables to Travis

Hide IBMWatsonMapModel object from the outside

Internally, any properties that would be of type Map<String, Object> use the wrapper model IBMWatsonMapModel because the base Apex deserializer doesn't support the former.

However, from a developer's perspective, they should be able to set properties that would be of type Map<String, Object> by using the standard Map. It's awkward to have to use an SDK-specific type and prevents things like inline initialization.

Acceptance Criteria:

  • Developers are able to set Map parameters using the standard datatype
  • Models are still properly serialized/deserialized internally

deploy to salesforce doesn't work

Trying to use the deploy to SFDX button results in an error. Sorry for the lack of detail here but there isn't much to go on...

Salesforce version

  • Not sure?

SDK version

  • from master branch

Steps to reproduce

allow_perms

  • Error is generated

error

v5.0.0 goals

Schedule

We're looking forward and planning on releasing the next major release (v5.0.0) in late September, with a release candidate being released early that month.

Breaking changes

  • Remove old deprecation methods in BaseService, like setUsernameAndPassword() and setIamOptions() in favor of the constructor and single method to set auth in this release

Non-breaking major changes


We'll be updating this issue periodically with scheduling details and more information on what will be changed. In the meantime, feel free to give feedback on anything in the issue and to reply with things you'd like to see!

Ability to setAdditionalProperties Context - Watson Assistant

Before a customer starts talking to Watson Assistant I want to pass in some context data before such as the customer's name, address, email, etc. Right now there is now getAdditionalProperties but no setAdditionalProperties methond. setAdditionalProperties will allow me to pass in the relevant information to have a more personalized conversation with the customer.

Example
Watson : Hello Jim, my name is Kate your Virtual Agent. I can see that you have an outstanding bill, would you like to pay for it right now?

Assistant support requested for new fields for search skills results

We want to demo the new Discovery search skill in WatsonAssistant from Salesforce.
To do this we need the new fields returned in IBMAssistantV2Models for output/generic/header and output/generic/results.
I have coded the additions to IBMAssistantV2Models.apxc for handling the deserialization of the new return fields and tested them in my local SF org. Let me know if you want the updated source.

Deployment Errors

When cloning and attempting to deploy the SDK version from 05/08/19 to a new Salesforce developer edition, I encountered errors saying that the IBMWatsonService is invalid and needs to be recompiled. I followed the instructions in the readme. I cloned the repo, navigated to the directory, authenticated my org, and tried to deploy the mdapioutput folder. The terminal errors are attached.
Screen Shot 2019-05-08 at 1 13 50 PM

Generate Speech to Text service

Acceptance Criteria:

  • Speech to Text service and model code generated in speech-to-text branch
  • Write any necessary methods by hand (and other small tweaks not covered by the generator)
  • Build passing in Travis

Investigate deserialization failure

The Conversation service shown here was working before, but a recent test of it is returning errors when the Context object is not null.

This should be investigated in case it has any further implications about a deserialization bug with dynamic objects.

[Discovery] Query Results not available in Javascript (AuraEnabled)

Problem

When I write the code like the following:

String environmentId = 'myEnvironmentId';
List<String> collectionIDs = new List<String>();
collectionIDs.add('collectionId1');
collectionIDs.add('collectionId2');
String query = 'my query';

IBMDiscoveryV1 discovery = new IBMDiscoveryV1(IBMDiscoveryV1.VERSION_DATE_2017_09_01);
IBMDiscoveryV1Models.FederatedQueryOptions options = new IBMDiscoveryV1Models.FederatedQueryOptionsBuilder(environmentId, collectionIDs).naturalLanguageQuery(query).build();

System.debug(discovery.federatedQuery(options).getResults());

I get the following response:

[
  {
    "id": "my_id",
    "score": 1.0,
    "collection_id": "my_collection_id",
    "additional_properties" : {
       //more fields here
    }
  }
]

However, when I try to access the same response in Javascript (aura) layer with the following code:

action.setParams({
    "environmentId": "myEnvironmentId",
    "collectionIDs": ["collectionId1", "collectionId2"],
    "query": "my query"
});
action.setCallback(this, function(response) {
    var resp = response.getReturnValue();
    console.log(resp.results);
});
$A.enqueueAction(action);

I get the following:

[
  {
    "id": "my_id",
    "score": 1.0,
    "collection_id": "my_collection_id"
  }
]

Expected

I expect to be able to retrieve the following response for both situations:

[
  {
    "id": "my_id",
    "score": 1.0,
    "collection_id": "my_collection_id",
    //more fields here
  }
]

(specifically, no additional_properties object)

Solution

I believe an @AuraEnabled flag needs placed somewhere on the dynamic models for the parent class of IBMDiscoveryV1Models.QueryResult. Not exactly clear where.

SOQL queries cause errors when SDK is namespaced

When a managed package (or multiple) contain the SDK (or a class named the same as IBMWatsonService), it throws an exception List has more than 1 row for assignment to SObject coming from https://github.com/watson-developer-cloud/salesforce-sdk/blob/master/force-app/main/default/classes/IBMWatsonService.cls#L35

We need to make sure the query only returns a single record OR we handle the case when there are multiple records coming back from the query:

ApexClass ac = [Select ApiVersion From ApexClass Where Name = 'IBMWatsonService'];

When reporting a bug, please be sure to include the following

  • Salesforce version Summer '18
  • SDK version v2.1.0
  • Steps to reproduce *include multiple namespaced classes called IBMWatsonService in the same org and attempt to construct the class new IBMWatsonService('discovery');
  • Expected behavior the class is constructed without error
  • Actual behavior the class throws an exception: List has more than 1 row for assignment to SObject

[Discovery] Annotate tests with @isTest

Problem

The SDK package is 1.3MB when deployed. This is too large for applications that want to include it within their package (since this is an unmanaged package).

Solution

The tests in the package should be annotated with @isTest so they are not deployed with a parent application package.

This will cut down the size of the files pushed when using the SDK that will help other applications stay under the 3MB limit of packages on Salesforce AppExchange

When reporting a bug, please be sure to include the following

  • Salesforce version: N/A
  • SDK version: 0.1.1
  • Steps to reproduce: try deploying the SDK using sfdx and see that all tests are pulled in that are not annotated
  • Expected behavior: tests are excluded
  • Actual behavior: tests are included

When you open an issue for a feature request, please add as much detail as possible

  • A descriptive title starting with the service name: Conversation, Discovery...
  • A description of the problem you're trying to solve
  • A suggested solution if possible

[Discovery]: Add @isTest to IBMWatsonMockResponses

When reporting a bug, please be sure to include the following

  • Salesforce version: all
  • SDK version: 2.0
  • Steps to reproduce:
    - sfdx force:apex:test:run
  • Expected behavior:
    - all test-related classes are excluded from code coverage
  • Actual behavior:
    - IBMWatsonMockResponses class is included in code coverage (and lowers coverage significantly)

When you open an issue for a feature request, please add as much detail as possible

  • A descriptive title starting with the service name: Conversation, Discovery...
  • A description of the problem you're trying to solve:
    - trying to include SDK v2.0.0 with just Discovery + Core and test coverage is too low for a managed package
  • A suggested solution if possible
    - add @isTest to the IBMWatsonMockResponses class to remove it
    - turn all the IBMWatsonMockResponses into static resources and load the JSON instead of embedding JSON into code

Request timed out when adding a document to the watson collection

I am trying to upload a sample document from Salesforce Apex class to IBM Watson. I am trying with the following snippet but am getting this error

{
"code" : 500,
"error" : "Request timed out, please try again."
}

Somehow it is getting timed out.

            Blob fileBlob = Blob.valueOf('This is a sample pdf file');
            IBMDiscoveryV1 discovery = new IBMDiscoveryV1('2017-11-07');
            discovery.setEndPoint('https://gateway.watsonplatform.net/discovery/api');
            discovery.setUsernameAndPassword('<<userId>>', '<<password>>');
            IBMDiscoveryV1Models.AddDocumentOptionsBuilder builder = new IBMDiscoveryV1Models.AddDocumentOptionsBuilder(
                    '<<environmentId>>,
                    '<<collectionId>>');

            IBMWatsonFile.FileBuilder fileBuilder = new IBMWatsonFile.FileBuilder();
            fileBuilder.name('Sample.pdf');
            fileBuilder.body(fileBlob);
            IBMWatsonFile file = fileBuilder.build();

            builder.file(file);
            IBMDiscoveryV1Models.AddDocumentOptions options = builder.build();

            docResponse = discovery.addDocument(options);
            System.debug(docResponse.getDocumentId());

Ignore deployment of functional test classes to Salesforce orgs

The functional tests are there as a reference for developers and, in the future, for use in Travis to ensure code quality. They should be kept out of deployment to Salesforce to try and keep the total package size down. This should ideally be implemented for all three deployment methods.

Error deploying all Services with Ant

I have tried deploy all services provided in the SDK using ant to my Developer Edition Org. I have followed the steps and I got the next errors:

IBMDiscoveryV1 | Apex Class | 77 | 13 | Dependent class is invalid and needs recompilation: IBMDiscoveryV1Models: line 734, column 140: Initial term of field expression must be a concrete SObject: Map<String,Object>

IBMDiscoveryV1Models | Apex Class | 734 | 140 | Initial term of field expression must be a concrete SObject: Map<String,Object>

IBMDiscoveryV1Test | Apex Class | 13 | 36 | Dependent class is invalid and needs recompilation: Class.IBMDiscoveryV1.createEnvironment: line 77, column 13 IBMDiscoveryV1Models: line 734, column 140: Initial term of field expression must be a concrete SObject: Map<String,Object>

IBMWatsonServiceTest | Apex Class | 25 | 38 | Dependent class is invalid and needs recompilation: Class.IBMDiscoveryV1.createEnvironment: line 77, column 13 IBMDiscoveryV1Models: line 734, column 140: Initial term of field expression must be a concrete SObject: Map<String,Object>

Force case sensitive JSON for dynamic model deserialization

JSON deserialization for models using IBMWatsonDynamicModel fails when JSON object keys are case insensitive.

The following Apex code can be run and errors out with: System.JSONException: Duplicate field: IBMDiscoveryV1Models.QueryResult.id_serialized_name

String responseText = '{"id":"1","Id":"2"}';
Map<String, Object> jsonMap = (Map<String, Object>) JSON.deserializeUntyped(responseText);
Map<String, Object> safeJsonMap = IBMWatsonJSONUtil.prepareResponse(jsonMap);
String jsonString = JSON.serialize(safeJsonMap);
IBMDiscoveryV1Models.QueryResult foo = (IBMDiscoveryV1Models.QueryResult) new IBMWatsonDynamicModel().deserialize(jsonString, safeJsonMap, IBMDiscoveryV1Models.QueryResult.class);
System.debug(foo);

I would expect that the Id field would get deserialized into the additional_properties and id would be deserialized to just id_serialized_name. The alternative is to not try and mix dynamic and static model types and just make the entire object dynamic (everything is a Map<String, Object>)

When reporting a bug, please be sure to include the following

  • SDK version - 1.0
  • Steps to reproduce
  • Expected behavior
  • Actual behavior

IBMAssistantV1Models.InputData -- Invalid type

When I execute an assistant snippet I get an error saying Invalid type.

IBMAssistantV1 assistant = new IBMAssistantV1('2018-02-16');

IBMAssistantV1Models.InputData input
= new IBMAssistantV1Models.InputDataBuilder()
.text('Hello!')
.build();
IBMAssistantV1Models.MessageOptions options
= new IBMAssistantV1Models.MessageOptionsBuilder()
.workspaceId('bf674ec9-a********7-3fd5a4ed3fc8') // Place your workspace ID here!
.input(input)
.build();
IBMAssistantV1Models.MessageResponse response = assistant.message(options);

String reply = response.getOutput().getText().get(0);
System.debug(reply);

[Discovery] Allow JSON to pass-through to calling method

Right now the SDK can produce significantly large heap sizes while serializing/deserializing JSON responses. Many times with large documents we are getting https://salesforce.stackexchange.com/questions/143598/exceeded-max-size-limit-of-6000000

I think to buy us some time, we could potentially pass the JSON response (in this case Discovery) directly to the calling method with a parameter of some sort like raw = true or a different method like queryRaw that just returns the response body as-is instead of attempting to deserialize it.

When reporting a bug, please be sure to include the following

  • Salesforce version: Fall 2018
  • SDK version: 2.9.0
  • Steps to reproduce: using Watson Discovery, make a query that produces a fairly large response/result set - when the response exceeds 6MB, it fails
  • Expected behavior: the apex code errors out with large JSON responses
  • Actual behavior: the apex code doesn't error out with large JSON responses

When you open an issue for a feature request, please add as much detail as possible

  • A descriptive title starting with the service name: Conversation, Discovery...
  • A description of the problem you're trying to solve: see above
  • A suggested solution if possible: see above

Release Text to Speech and Speech to Text

Acceptance Criteria:

  • Merge text-to-speech and speech-to-text branches into develop
  • Merge develop into master
  • Update any necessary documentation (README, release notes, etc.)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.