Though Teneo developers usually manage their solutions using Teneo Studio, there are occasions when you may want to automate tasks from the outside. Doing periodic tasks via the Teneo Studio API can be more efficient than opening the Studio and doing them manually, especially when you are managing number of solutions.
For example:
- You need to run Auto-test for all your solutions and check the result every week/month/quarter.
- You need to collect real user inputs and select some of them as training data for the machine learning model of your solution every week/month/quarter.
- You need to publish your solutions every week/month/quarter.
For these (and further) use cases, you can create a Groovy file with the code provided in this article to perform these tasks periodically instead of opening your Teneo studio then doing the same work solution by solution. You can also adapt the code to other programming languages you are more familiar with.
Before calling Teneo Studio API
-
If you are using Teneo Sandbox
First, you need to log in on Teneo.ai. After logging in, please make sure the environment is running as the following screenshot shows:
If the environment is stopped, please start it, and refresh the status until it shows Running.
Then you need to copy the Server URL by clicking the copy icon.
-
If you have a SaaS environment
SaaS environment is always running so you do not need to check the environment status before using the Teneo Studio API. As for the Server URL, you can open the Studio and click on the About button on the left (before you open any solution), and copy the URL from the Connected to:
To run the Groovy code presented in this article, you need to import the following packages:
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse
import groovy.json.JsonBuilder
import groovy.json.JsonSlurper
Please be aware that the java.net.http package is only included in Java 11 and later versions. If you are more comfortable using other packages to make API calls, you can adapt the code in this article.
Now you need to create a class (called SolutionApi, for example) to contain all the objects and methods related to Teneo Studio API:
class SolutionApi {
private static final String serverURL = "your_server_url"
private static final String username = "your_username"
private static final String password = "your_password"
private static String accessToken = ""
}
This class should contain the following four String objects:
- serverURL: fill in with your server URL as the initial value
- username: fill in with your username as the initial value
- password: fill in with your password as the initial value
- accessToken: leave it empty as the initial value
Log in
Before you do anything with the Teneo Studio API, you should first call the log in method. Create it within the SolutionApi class:
public static boolean login() {
def apiUrl = (serverURL.endsWith("/")?serverURL:serverURL + "/") + "teneo-studio/rest/auth/login"
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(apiUrl))
.header("content-type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(new JsonBuilder(["username":username,"password":password]).toString()))
.build()
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString())
if (response.statusCode() == 200) {
accessToken = new JsonSlurper().parseText(response.body())
return true
} else {
return false
}
}
Then run it with the following code to log in and retrieve the result (successful or not):
def loginSuccessful = SolutionApi.login()
You should only use other methods of Solution API when you have logged in successfully. If the returned value is false, check if you have filled in the correct Server URL, username and password. If you are using Teneo Sandbox, please also check the Environment Status on Teneo.ai.
Use Case 1: Run Auto-test and retrieve the test summary
Create the runAutotest method within the SolutionApi class for running auto test:
public static String runAutotest(String solutionId, boolean trigger = true, boolean transition = true, boolean url = true, boolean stable = false, boolean flow_scope = false) {
def apiUrl = (serverURL.endsWith("/")?serverURL:serverURL + "/") + "teneo-studio/rest/auto-tests/begin/" + solutionId + "?trigger-tests=" + trigger + "&transition-tests=" + transition + "&url-tests=" + url + "&stable=" + stable + "&flow-scope=" + flow_scope
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(apiUrl))
.header("content-type", "application/json")
.header("Authorization", "Bearer "+accessToken)
.method("POST", HttpRequest.BodyPublishers.ofString('{}'))
.build()
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString())
def autotestId = new JsonSlurper().parseText(response.body())
return autotestId
}
Then run it with the following code passing your solution ID to run an Auto-test and retrieve the ID of the auto test summary:
def summaryId = SolutionApi.runAutotest(solutionId)
You can add the following extra arguments to this method:
- trigger: boolean, by default true. If true, all triggers in the solution will be included in the auto test.
- transition: boolean, by default true. If true, all triggers in the solution will be included in the auto test.
- url: boolean, by default true. If true, all triggers in the solution will be included in the auto test.
- stable: boolean, by default false. If true, the auto test will run on the stable version of the solution. If false, the auto test will run on the current version of the solution. Click here for more information about the stable version of documents.
- flow_scope: boolean, by default false. If true, the auto test will run on the flow scope. If false, the auto test will run on the solution scope. Click here for more information about running test using flow scope.
Please be aware that the summary ID will be returned immediately when you start an Auto-test via Solution API, but the process of this test will take a few minutes to finish, depends on how many examples need to be tested. Please note that you will not receive a notification when the Auto-test is finished here. You can check in Teneo Studio the approximate duration of your Auto-tests from the previous reports:
Schedule the getAutotestSummary call then with some additional minutes in between to ensure you receive the test results. You can create the getAutotestSummary method within the SolutionApi class for retrieving the Auto-test result by the summary ID:
public static HashMap getAutotestSummary(String solutionId, String summaryId, boolean ignore_skipped = true, boolean ignore_success = true, boolean ignore_warnings = false) {
def apiUrl = (serverURL.endsWith("/")?serverURL:serverURL + "/") + "teneo-studio/rest/auto-tests/summaries/" + solutionId + "/" + summaryId + "?ignore-skipped=" + ignore_skipped + "&ignore_success=" + ignore_success + "&ignore_warnings=" + ignore_warnings
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(apiUrl))
.header("content-type", "application/json")
.header("Authorization", "Bearer "+accessToken)
.method("GET", HttpRequest.BodyPublishers.noBody())
.build()
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString())
def summary = new JsonSlurper().parseText(response.body())
return summary
}
Then run it with the following code passing your solution ID and summary ID to retrieve the Auto-test summary:
def summary = SolutionApi.getAutotestSummary(solutionId,summaryId)
You can add the following extra arguments to this method:
- ignore_skipped: boolean, by default true. If true, all user intents which are not included in auto test will not be included in the summary.
- ignore_success: boolean, by default true. If true, all user intents which have passed the auto test will not be included in the summary.
- ignore_warnings: boolean, by default false. If true, all user intents which have passed the auto test but with warning will not be included in the summary.
Use Case 2: Add a new class or edit an existing class
Create the createClass method within the SolutionApi class for adding a new class in your solution:
public static HashMap createClass(String solutionId, String className, List<String> trainingData) {
def apiUrl = (serverURL.endsWith("/")?serverURL:serverURL + "/") + "teneo-studio/rest/classes/" + solutionId
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(apiUrl))
.header("content-type", "application/json")
.header("Authorization", "Bearer "+accessToken)
.method("POST",HttpRequest.BodyPublishers.ofString(new JsonBuilder(["name":className,"trainingData":trainingData]).toString()))
.build()
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString())
def classAdded = new JsonSlurper().parseText(response.body())
return classAdded
}
Then run it with the following code passing your solution ID, class name and training examples to create a new class and return the details of this new class:
def classAdded = SolutionApi.createClass(solutionId,className, trainingData)
In which the variable className should be a String containing the name of the class, while the variable trainingData should be a List of Strings containing the training examples.
If you want to modify an existing class, create this method within the SolutionApi class:
public static HashMap updateClass(String solutionId, String classId, String className, List<String> trainingData) {
def apiUrl = (serverURL.endsWith("/")?serverURL:serverURL + "/") + "teneo-studio/rest/classes/" + solutionId + "/" + classId
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(apiUrl))
.header("content-type", "application/json")
.header("Authorization", "Bearer "+accessToken)
.method("PUT",HttpRequest.BodyPublishers.ofString(new JsonBuilder(["name":className,"trainingData":trainingData]).toString()))
.build()
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString())
def classUpdated = new JsonSlurper().parseText(response.body())
return classUpdated
}
Then run it with the following code passing your solution ID, class ID, new class name and new training examples to modify this class and return the details of this class after modification:
def classModified = SolutionApi.updateClass(solutionId,classId,className,trainingData)
If you don’t know the class ID, you can copy it from the Class Manager in Teneo Studio:
Please note that the training examples you put in the updateClass method will not append to but replace the existing training examples. If you want to add new training examples in an existing class without touching the current class name and training examples, please first add the getClassInfo method within the SolutionApi class:
public static HashMap getClassInfo(String solutionId, String classId) {
def apiUrl = (serverURL.endsWith("/")?serverURL:serverURL + "/") + "teneo-studio/rest/classes/" + solutionId + "/" + classId
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(apiUrl))
.header("content-type", "application/json")
.header("Authorization", "Bearer "+accessToken)
.method("GET", HttpRequest.BodyPublishers.noBody())
.build()
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString())
def classes = new JsonSlurper().parseText(response.body())
return classes
}
Then run the following code to extract the current training examples and update the class with current training examples + new training examples:
def classInfo = SolutionApi.getClassInfo(solutionId,classId)
def newTrainingData = [] // your new training examples here
def classUpdated = SolutionApi.updateClass(solutionId,classId,classInfo.name,classInfo.trainingData + newTrainingData)
Use Case 3: Publish your solution
Create the publishToEnvironment method within the SolutionApi class for publishing your solution:
public static String publishToEnvironment(String solutionId, String environmentId, boolean forceFullPublish = false) {
def apiUrl = (serverURL.endsWith("/")?serverURL:serverURL + "/") + "teneo-studio/rest/publish-environments/publish/begin/" + solutionId + "/" + environmentId
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(apiUrl))
.header("content-type", "application/json")
.header("Authorization", "Bearer "+accessToken)
.method("POST",HttpRequest.BodyPublishers.ofString(new JsonBuilder(["forceFullPublish":forceFullPublish]).toString()))
.build()
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString())
def publishId = new JsonSlurper().parseText(response.body())
return publishId
}
Then run it with the following code passing your solution ID and environment ID to publish your solution. This method will return a task ID:
def publishTaskId = SolutionApi.publishToEnvironment(solutionId,environmentId)
You can add the following extra arguments to this method:
- forceFullPublish: boolean, by default false. If true, a full application deployment will be applied.
You can copy the environment ID by opening Solution > Publish > Manage > Edit environment:
Then click the copy icon next to Topic.
Log out
After using Studio API, we recommend you always remember to log out. Adding the logout method within the SolutionApi class:
public static void logout() {
def apiUrl = (serverURL.endsWith("/")?serverURL:serverURL + "/") + "teneo-studio/rest/auth/logout"
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(apiUrl))
.header("content-type", "application/json")
.header("Authorization", "Bearer "+accessToken)
.method("POST", HttpRequest.BodyPublishers.noBody())
.build()
HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString())
}
Then run it with the following code to log out from the studio:
SolutionApi.logout()
Conclusion
This article gives an introduction on how to run Auto-test, modify classes and publish solutions outside of Teneo Studio via Teneo Studio API. If you have further use cases that you automate via Teneo Studio API, we encourage you to share them here with the wonderful Teneo Developers Community. You can find the complete code in one single script in our Code Snippets section. We hope you found this article useful, and feel free to ask here any questions you might have on this topic.