Skip to content

Commit

Permalink
Merge pull request #12347 from ashera96/api-chat
Browse files Browse the repository at this point in the history
Add devportal rest api changes for API Chat feature
  • Loading branch information
Arshardh authored Mar 23, 2024
2 parents 3a1a822 + b9053a0 commit 1ab51af
Show file tree
Hide file tree
Showing 26 changed files with 1,896 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,28 @@ Set<SubscribedAPI> getPaginatedSubscribedAPIsByApplication(Application applicati
*/
Tier getThrottlePolicyByName(String name, int policyType, String organization) throws APIManagementException;

/**
* Returns the API Chat execute call response as a string
*
* @param apiChatRequestId Request UUID
* @param requestPayload Request payload to be used for the AI service execute call
* @return execution response as a string
* @throws APIManagementException if execute call failed
*/
String invokeApiChatExecute(String apiChatRequestId, String requestPayload) throws APIManagementException;

/**
* Returns the API Chat prepare call response as a string
*
* @param apiId ID of the API
* @param apiChatRequestId Request UUID
* @param organization Identifier of an organization
* @return prepare response
* @throws APIManagementException if prepare call failed
*/
String invokeApiChatPrepare(String apiId, String apiChatRequestId, String organization)
throws APIManagementException;

/**
* This method used to retrieve key manager configurations for tenant
* @param organization organization of the key manager
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,11 @@ public enum ExceptionCodes implements ErrorHandler {
KEY_MANAGER_RESTRICTED_FOR_USER(902013, "Unauthorized Access to Key Manager", 403, "Key Manager is Restricted for this user"),
// Admin portal get apis and api provider change related errors
CHANGE_API_PROVIDER_FAILED(903011, "Error while changing the API provider", 500, "Error while changing the API provider in the registry or DB"),
GET_SEARCH_APIS_IN_ADMIN_FAILED(903012, "Error while getting the apis", 500, "Error while getting/searching the apis from registry");
GET_SEARCH_APIS_IN_ADMIN_FAILED(903012, "Error while getting the apis", 500, "Error while getting/searching the apis from registry"),

// AI service invocation related exceptions
AI_SERVICE_INVALID_RESPONSE(903100, "Invalid response from AI service", 500, "Error while invoking AI service. %s", false),
AI_SERVICE_INVALID_ACCESS_TOKEN(900906, "Invalid access token provided for AI service", 401, "Invalid access token provided for AI service");

private final long errorCode;
private final String errorMessage;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.wso2.carbon.apimgt.api.model;

import org.json.simple.JSONArray;

public class APIChatAPISpec {
private String serviceUrl = null;
private JSONArray tools;

public String getServiceUrl() {
return serviceUrl;
}

public void setServiceUrl(String serviceUrl) {
this.serviceUrl = serviceUrl;
}

public JSONArray getTools() {
return tools;
}

public void setTools(JSONArray tools) {
this.tools = tools;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.wso2.carbon.apimgt.api.model;

public class APIChatExecutionResponse {
private Integer code = null;
private String path = null;
private Object headers = null;
private Object body = null;

public Integer getCode() {
return code;
}

public void setCode(Integer code) {
this.code = code;
}

public String getPath() {
return path;
}

public void setPath(String path) {
this.path = path;
}

public Object getHeaders() {
return headers;
}

public void setHeaders(Object headers) {
this.headers = headers;
}

public Object getBody() {
return body;
}

public void setBody(Object body) {
this.body = body;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.wso2.carbon.apimgt.api.model;

/**
* Details related to API Chat test execution
*/
public class APIChatTestExecutionInfo {
private APIChatExecutionResponse response = null;

public APIChatExecutionResponse getResponse() {
return response;
}

public void setResponse(APIChatExecutionResponse response) {
this.response = response;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.wso2.carbon.apimgt.api.model;

import org.json.simple.JSONObject;

/**
* Details related to API Chat test initialization
*/
public class APIChatTestInitializerInfo {
private String command = null;
private APIChatAPISpec apiSpec = null;

public String getCommand() {
return command;
}

public void setCommand(String command) {
this.command = command;
}

public APIChatAPISpec getApiSpec() {
return apiSpec;
}

public void setApiSpec(APIChatAPISpec apiSpec) {
this.apiSpec = apiSpec;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,23 @@ public final class APIConstants {
public static final String DIGEST = "x5t#S256";
public static final String CNF = "cnf";

// Constants related to AI features: API chat and Marketplace Assistant
public static class AI {

public static final String API_CHAT = "APIChat.";
public static final String API_CHAT_ENABLED = API_CHAT + "Enabled";
public static final String API_CHAT_AUTH_TOKEN = API_CHAT + "AuthToken";
public static final String API_CHAT_ENDPOINT = API_CHAT + "Endpoint";
public static final String API_CHAT_PREPARE_RESOURCE = "/prepare";
public static final String API_CHAT_EXECUTE_RESOURCE = "/chat";
public static final String API_CHAT_ACTION_PREPARE = "PREPARE";
public static final String API_CHAT_ACTION_EXECUTE = "EXECUTE";

private AI() {

}
}

//documentation rxt

public static final String DOC_NAME = "overview_name";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3308,6 +3308,24 @@ public String getOpenAPIDefinition(String apiId, String organization) throws API
return APIUtil.removeXMediationScriptsFromSwagger(definition);
}

@Override
public String invokeApiChatExecute(String apiChatRequestId, String requestPayload) throws APIManagementException {
return APIUtil.invokeAIService(APIConstants.AI.API_CHAT_ENDPOINT,
APIConstants.AI.API_CHAT_AUTH_TOKEN, APIConstants.AI.API_CHAT_EXECUTE_RESOURCE, requestPayload,
apiChatRequestId);
}

@Override
public String invokeApiChatPrepare(String apiId, String apiChatRequestId, String organization)
throws APIManagementException {
String swaggerDefinition = getOpenAPIDefinition(apiId, organization);
String payload = "{\"openapi\": " + swaggerDefinition + "}";
String prepareResponse = APIUtil.invokeAIService(APIConstants.AI.API_CHAT_ENDPOINT,
APIConstants.AI.API_CHAT_AUTH_TOKEN, APIConstants.AI.API_CHAT_PREPARE_RESOURCE, payload,
apiChatRequestId);
return prepareResponse;
}

@Override
public String getOpenAPIDefinitionForEnvironment(API api, String environmentName)
throws APIManagementException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10387,4 +10387,71 @@ public static String getScopesAsString(Set<Scope> scopes) {
}
return scopesStringBuilder.toString().trim();
}

/**
* Check whether API Chat feature is enabled
*
* @return returns true if API Chat feature is enabled, false if disabled.
*/
public static boolean isApiChatEnabled() {
APIManagerConfiguration config = ServiceReferenceHolder.getInstance().
getAPIManagerConfigurationService().getAPIManagerConfiguration();
String isApiChatEnabled = config.getFirstProperty(APIConstants.AI.API_CHAT_ENABLED);
return Boolean.parseBoolean(isApiChatEnabled);
}

/**
* Checks whether an auth token is provided for AI features to use. This token is utilized for authentication and
* throttling purposes.
*
* @return returns true if a valid auth token is found, false otherwise.
*/
public static boolean isAuthTokenProvidedForAIFeatures() {
APIManagerConfiguration config = ServiceReferenceHolder.getInstance().
getAPIManagerConfigurationService().getAPIManagerConfiguration();
String authToken = config.getFirstProperty(APIConstants.AI.API_CHAT_AUTH_TOKEN);
if (StringUtils.isEmpty(authToken)) {
return false;
}
return true;
}

public static String invokeAIService(String endpointConfigName, String authTokenConfigName,
String resource, String payload, String requestId) throws APIManagementException {

APIManagerConfiguration config = ServiceReferenceHolder.getInstance().
getAPIManagerConfigurationService().getAPIManagerConfiguration();
String endpoint = config.getFirstProperty(endpointConfigName);
String authToken = config.getFirstProperty(authTokenConfigName);
try {
HttpPost preparePost = new HttpPost(endpoint + resource);
preparePost.setHeader(HttpHeaders.AUTHORIZATION, APIConstants.AUTHORIZATION_BEARER + authToken);
preparePost.setHeader(HttpHeaders.CONTENT_TYPE, APIConstants.APPLICATION_JSON_MEDIA_TYPE);
preparePost.setHeader("x-request-id", requestId);
StringEntity requestEntity = new StringEntity(payload, ContentType.APPLICATION_JSON);
preparePost.setEntity(requestEntity);

URL url = new URL(endpoint);
int port = url.getPort();
String protocol = url.getProtocol();
HttpClient httpClient = APIUtil.getHttpClient(port, protocol);

CloseableHttpResponse response = executeHTTPRequest(preparePost, httpClient);
int statusCode = response.getStatusLine().getStatusCode();
String responseStr = EntityUtils.toString(response.getEntity());
if (statusCode == HttpStatus.SC_CREATED) {
return responseStr;
} else if (statusCode == HttpStatus.SC_UNAUTHORIZED) {
throw new APIManagementException("Unexpected response detected from the AI service." + responseStr,
ExceptionCodes.AI_SERVICE_INVALID_ACCESS_TOKEN);
} else {
throw new APIManagementException("Unexpected response detected from the AI service." + responseStr,
ExceptionCodes.AI_SERVICE_INVALID_RESPONSE);
}
} catch (MalformedURLException e) {
throw new APIManagementException("Invalid/malformed URL encountered. URL: " + endpoint, e);
} catch (APIManagementException | IOException e) {
throw new APIManagementException("Error encountered while connecting to service", e);
}
}
}
Loading

0 comments on commit 1ab51af

Please sign in to comment.