diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/constants/PluginConstants.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/constants/PluginConstants.java
index 7d337ffc79..8d5aebfead 100644
--- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/constants/PluginConstants.java
+++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/constants/PluginConstants.java
@@ -14,6 +14,7 @@ public interface PluginConstants {
String GRAPH_QL_PLUGIN = "graphql-plugin";
String OPEN_AI_PLUGIN = "openai-plugin";
String ANTHROPIC_PLUGIN = "anthropic-plugin";
+ String GOOGLE_AI_PLUGIN = "googleai-plugin";
}
public static final String DEFAULT_REST_DATASOURCE = "DEFAULT_REST_DATASOURCE";
@@ -39,6 +40,7 @@ public interface PluginConstants {
public static final String OPEN_AI_PLUGIN_NAME = "Open AI";
public static final String ANTHROPIC_PLUGIN_NAME = "Anthropic";
+ public static final String GOOGLE_AI_PLUGIN_NAME = "Google AI";
}
interface HostName {
diff --git a/app/server/appsmith-plugins/googleAiPlugin/pom.xml b/app/server/appsmith-plugins/googleAiPlugin/pom.xml
new file mode 100644
index 0000000000..9c8ba07e5c
--- /dev/null
+++ b/app/server/appsmith-plugins/googleAiPlugin/pom.xml
@@ -0,0 +1,108 @@
+
+
+ 4.0.0
+
+ com.appsmith
+ appsmith-plugins
+ 1.0-SNAPSHOT
+
+
+ com.external.plugins
+ googleAiPlugin
+ 1.0-SNAPSHOT
+ googleAiPlugin
+ http://maven.apache.org
+
+
+
+
+ org.springframework
+ spring-core
+ provided
+
+
+
+ org.springframework
+ spring-web
+ provided
+
+
+
+ org.springframework
+ spring-webflux
+
+
+ io.projectreactor
+ reactor-core
+
+
+ org.springframework
+ spring-core
+
+
+ org.springframework
+ spring-web
+
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson-bom.version}
+ provided
+
+
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jdk8
+ ${jackson-bom.version}
+
+
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+ ${jackson-bom.version}
+
+
+ com.google.guava
+ guava
+ 32.0.1-jre
+
+
+
+
+
+
+ org.assertj
+ assertj-core
+ 3.13.2
+ test
+
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+ ${spring-boot.version}
+ test
+
+
+ org.springframework
+ spring-test
+ test
+
+
+ io.projectreactor.netty
+ reactor-netty-http
+ provided
+
+
+
+
+
diff --git a/app/server/appsmith-plugins/googleAiPlugin/src/main/java/com/external/plugins/GoogleAiPlugin.java b/app/server/appsmith-plugins/googleAiPlugin/src/main/java/com/external/plugins/GoogleAiPlugin.java
new file mode 100644
index 0000000000..534fce99f7
--- /dev/null
+++ b/app/server/appsmith-plugins/googleAiPlugin/src/main/java/com/external/plugins/GoogleAiPlugin.java
@@ -0,0 +1,209 @@
+package com.external.plugins;
+
+import com.appsmith.external.dtos.ExecuteActionDTO;
+import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginError;
+import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginException;
+import com.appsmith.external.helpers.restApiUtils.connections.APIConnection;
+import com.appsmith.external.helpers.restApiUtils.helpers.RequestCaptureFilter;
+import com.appsmith.external.models.ActionConfiguration;
+import com.appsmith.external.models.ActionExecutionRequest;
+import com.appsmith.external.models.ActionExecutionResult;
+import com.appsmith.external.models.ApiKeyAuth;
+import com.appsmith.external.models.DatasourceConfiguration;
+import com.appsmith.external.models.DatasourceTestResult;
+import com.appsmith.external.models.TriggerRequestDTO;
+import com.appsmith.external.models.TriggerResultDTO;
+import com.appsmith.external.plugins.BasePlugin;
+import com.appsmith.external.plugins.BaseRestApiPluginExecutor;
+import com.appsmith.external.services.SharedConfig;
+import com.external.plugins.commands.GoogleAICommand;
+import com.external.plugins.constants.GoogleAIConstants;
+import com.external.plugins.models.GoogleAIRequestDTO;
+import com.external.plugins.utils.GoogleAIMethodStrategy;
+import com.external.plugins.utils.RequestUtils;
+import com.google.gson.Gson;
+import lombok.extern.slf4j.Slf4j;
+import org.pf4j.PluginWrapper;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatusCode;
+import org.springframework.util.StringUtils;
+import org.springframework.web.reactive.function.BodyInserters;
+import org.springframework.web.util.UriComponentsBuilder;
+import reactor.core.publisher.Mono;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static com.external.plugins.constants.GoogleAIConstants.BODY;
+import static com.external.plugins.constants.GoogleAIConstants.GOOGLE_AI_API_ENDPOINT;
+import static com.external.plugins.constants.GoogleAIConstants.LABEL;
+import static com.external.plugins.constants.GoogleAIConstants.MODELS;
+import static com.external.plugins.constants.GoogleAIConstants.VALUE;
+import static com.external.plugins.constants.GoogleAIErrorMessages.EMPTY_API_KEY;
+import static com.external.plugins.constants.GoogleAIErrorMessages.INVALID_API_KEY;
+import static com.external.plugins.constants.GoogleAIErrorMessages.QUERY_FAILED_TO_EXECUTE;
+
+@Slf4j
+public class GoogleAiPlugin extends BasePlugin {
+ public GoogleAiPlugin(PluginWrapper wrapper) {
+ super(wrapper);
+ }
+
+ public static class GoogleAiPluginExecutor extends BaseRestApiPluginExecutor {
+ private static final Gson gson = new Gson();
+
+ protected GoogleAiPluginExecutor(SharedConfig sharedConfig) {
+ super(sharedConfig);
+ }
+
+ /**
+ * Tries to fetch the models list from GoogleAI API and if request succeed, then datasource configuration is valid
+ */
+ @Override
+ public Mono testDatasource(DatasourceConfiguration datasourceConfiguration) {
+ final ApiKeyAuth apiKeyAuth = (ApiKeyAuth) datasourceConfiguration.getAuthentication();
+ if (!StringUtils.hasText(apiKeyAuth.getValue())) {
+ return Mono.error(new AppsmithPluginException(
+ AppsmithPluginError.PLUGIN_DATASOURCE_ARGUMENT_ERROR, EMPTY_API_KEY));
+ }
+
+ URI uri = UriComponentsBuilder.fromUriString(GOOGLE_AI_API_ENDPOINT)
+ .path(MODELS)
+ .build()
+ .toUri();
+ HttpMethod httpMethod = HttpMethod.GET;
+
+ return RequestUtils.makeRequest(httpMethod, uri, apiKeyAuth, BodyInserters.empty())
+ .map(responseEntity -> {
+ if (responseEntity.getStatusCode().is2xxSuccessful()) {
+ // valid credentials
+ return new DatasourceTestResult();
+ }
+ return new DatasourceTestResult(INVALID_API_KEY);
+ })
+ .onErrorResume(error -> Mono.just(new DatasourceTestResult(
+ "Error while trying to test the datasource configurations" + error.getMessage())));
+ }
+
+ @Override
+ public Mono executeParameterized(
+ APIConnection connection,
+ ExecuteActionDTO executeActionDTO,
+ DatasourceConfiguration datasourceConfiguration,
+ ActionConfiguration actionConfiguration) {
+ // Get prompt from action configuration
+ List> parameters = new ArrayList<>();
+
+ prepareConfigurationsForExecution(executeActionDTO, actionConfiguration, datasourceConfiguration);
+
+ // Initializing object for error condition
+ ActionExecutionResult errorResult = new ActionExecutionResult();
+ initUtils.initializeResponseWithError(errorResult);
+
+ GoogleAICommand googleAICommand = GoogleAIMethodStrategy.selectExecutionMethod(actionConfiguration, gson);
+ googleAICommand.validateRequest(actionConfiguration);
+ GoogleAIRequestDTO googleAIRequestDTO = googleAICommand.makeRequestBody(actionConfiguration);
+
+ URI uri = googleAICommand.createExecutionUri(actionConfiguration);
+ HttpMethod httpMethod = googleAICommand.getExecutionMethod();
+ ActionExecutionRequest actionExecutionRequest =
+ RequestCaptureFilter.populateRequestFields(actionConfiguration, uri, parameters, objectMapper);
+
+ final ApiKeyAuth apiKeyAuth = (ApiKeyAuth) datasourceConfiguration.getAuthentication();
+
+ if (!StringUtils.hasText(apiKeyAuth.getValue())) {
+ ActionExecutionResult apiKeyNotPresentErrorResult = new ActionExecutionResult();
+ apiKeyNotPresentErrorResult.setIsExecutionSuccess(false);
+ apiKeyNotPresentErrorResult.setErrorInfo(new AppsmithPluginException(
+ AppsmithPluginError.PLUGIN_DATASOURCE_ARGUMENT_ERROR, EMPTY_API_KEY));
+ return Mono.just(apiKeyNotPresentErrorResult);
+ }
+
+ return RequestUtils.makeRequest(httpMethod, uri, apiKeyAuth, BodyInserters.fromValue(googleAIRequestDTO))
+ .flatMap(responseEntity -> {
+ HttpStatusCode statusCode = responseEntity.getStatusCode();
+
+ ActionExecutionResult actionExecutionResult = new ActionExecutionResult();
+ actionExecutionResult.setRequest(actionExecutionRequest);
+ actionExecutionResult.setStatusCode(statusCode.toString());
+
+ if (HttpStatusCode.valueOf(401).isSameCodeAs(statusCode)) {
+ actionExecutionResult.setIsExecutionSuccess(false);
+ String errorMessage = "";
+ if (responseEntity.getBody() != null && responseEntity.getBody().length > 0) {
+ errorMessage = new String(responseEntity.getBody());
+ }
+ actionExecutionResult.setErrorInfo(new AppsmithPluginException(
+ AppsmithPluginError.PLUGIN_AUTHENTICATION_ERROR, errorMessage));
+ return Mono.just(actionExecutionResult);
+ }
+
+ if (statusCode.is4xxClientError()) {
+ actionExecutionResult.setIsExecutionSuccess(false);
+ String errorMessage = "";
+ if (responseEntity.getBody() != null && responseEntity.getBody().length > 0) {
+ errorMessage = new String(responseEntity.getBody());
+ }
+ actionExecutionResult.setErrorInfo(new AppsmithPluginException(
+ AppsmithPluginError.PLUGIN_DATASOURCE_ERROR, errorMessage));
+
+ return Mono.just(actionExecutionResult);
+ }
+
+ Object body;
+ try {
+ body = objectMapper.readValue(responseEntity.getBody(), Object.class);
+ actionExecutionResult.setBody(body);
+ } catch (IOException ex) {
+ actionExecutionResult.setIsExecutionSuccess(false);
+ actionExecutionResult.setErrorInfo(new AppsmithPluginException(
+ AppsmithPluginError.PLUGIN_JSON_PARSE_ERROR, BODY, ex.getMessage()));
+ return Mono.just(actionExecutionResult);
+ }
+
+ if (!statusCode.is2xxSuccessful()) {
+ actionExecutionResult.setIsExecutionSuccess(false);
+ actionExecutionResult.setErrorInfo(new AppsmithPluginException(
+ AppsmithPluginError.PLUGIN_ERROR, QUERY_FAILED_TO_EXECUTE, body));
+ return Mono.just(actionExecutionResult);
+ }
+
+ actionExecutionResult.setIsExecutionSuccess(true);
+
+ return Mono.just(actionExecutionResult);
+ })
+ .onErrorResume(error -> {
+ errorResult.setIsExecutionSuccess(false);
+ log.error(
+ "An error has occurred while trying to run the Google AI API query command with error {}",
+ error.getMessage());
+ if (!(error instanceof AppsmithPluginException)) {
+ error = new AppsmithPluginException(
+ AppsmithPluginError.PLUGIN_ERROR, error.getMessage(), error);
+ }
+ errorResult.setErrorInfo(error);
+ return Mono.just(errorResult);
+ });
+ }
+
+ @Override
+ public Mono trigger(
+ APIConnection connection, DatasourceConfiguration datasourceConfiguration, TriggerRequestDTO request) {
+ return Mono.just(new TriggerResultDTO(getDataToMap(GoogleAIConstants.GOOGLE_AI_MODELS)));
+ }
+
+ @Override
+ public Set validateDatasource(DatasourceConfiguration datasourceConfiguration) {
+ return RequestUtils.validateApiKeyAuthDatasource(datasourceConfiguration);
+ }
+
+ private List