Skip to content

Commit

Permalink
1596 - implementation of genAI service support (#1613)
Browse files Browse the repository at this point in the history
  • Loading branch information
Vladysl authored Feb 12, 2024
1 parent 94650de commit a4f3ba6
Show file tree
Hide file tree
Showing 10 changed files with 181 additions and 2 deletions.
5 changes: 4 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ oddrn-generator-java = '0.1.21'
odd-integration-manifests = '0.0.6'
apache-collections = '4.4'
apache-lang = '3.12.0'
apache-text = '1.9'
r2dbc-spi = '1.0.0.RELEASE'
r2dbc-postgresql = '1.0.1.RELEASE'
r2dbc-pool = '1.0.0.RELEASE'
Expand Down Expand Up @@ -67,6 +68,7 @@ oddrn-generator-java = { module = 'org.opendatadiscovery:oddrn-generator-java',
odd-integration-manifests = { module = 'org.opendatadiscovery:integration-manifests', version.ref = 'odd-integration-manifests' }
apache-collections = { module = 'org.apache.commons:commons-collections4', version.ref = 'apache-collections' }
apache-lang = { module = 'org.apache.commons:commons-lang3', version.ref = 'apache-lang' }
apache-text = { module = 'org.apache.commons:commons-text', version.ref = 'apache-text' }
r2dbc-spi = { module = 'io.r2dbc:r2dbc-spi', version.ref = 'r2dbc-spi' }
r2dbc-postgresql = { module = 'org.postgresql:r2dbc-postgresql', version.ref = 'r2dbc-postgresql' }
r2dbc-pool = { module = 'io.r2dbc:r2dbc-pool', version.ref = 'r2dbc-pool' }
Expand Down Expand Up @@ -142,7 +144,8 @@ internal = [
]
apache-commons = [
'apache-collections',
'apache-lang'
'apache-lang',
'apache-text'
]
r2dbc = [
'r2dbc-spi',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.opendatadiscovery.oddplatform.config;

import java.time.Duration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;

@Configuration
public class WebClientConfiguration {
@Value("${genai.url:}")
private String genAIUrl;
@Value("${genai.request_timeout:2}")
private Integer getAiRequestTimeout;

@Bean("genAiWebClient")
public WebClient webClient() {
final HttpClient httpClient = HttpClient.create().responseTimeout(Duration.ofMinutes(getAiRequestTimeout));
final ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);

return WebClient.builder()
.clientConnector(connector)
.baseUrl(genAIUrl)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.opendatadiscovery.oddplatform.controller;

import lombok.RequiredArgsConstructor;
import org.opendatadiscovery.oddplatform.api.contract.api.GenaiApi;
import org.opendatadiscovery.oddplatform.api.contract.model.GenAIRequest;
import org.opendatadiscovery.oddplatform.api.contract.model.GenAIResponse;
import org.opendatadiscovery.oddplatform.service.genai.GenAIService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@RestController
@RequiredArgsConstructor
public class GenAIController implements GenaiApi {
private final GenAIService genAIService;

@Override
public Mono<ResponseEntity<GenAIResponse>> genAiQuestion(final Mono<GenAIRequest> genAIRequest,
final ServerWebExchange exchange) {
return genAIRequest.flatMap(genAIService::getResponseFromGenAI)
.map(ResponseEntity::ok);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.opendatadiscovery.oddplatform.exception.CascadeDeleteException;
import org.opendatadiscovery.oddplatform.exception.ErrorCode;
import org.opendatadiscovery.oddplatform.exception.ExceptionWithErrorCode;
import org.opendatadiscovery.oddplatform.exception.GenAIException;
import org.opendatadiscovery.oddplatform.exception.NotFoundException;
import org.opendatadiscovery.oddplatform.exception.UniqueConstraintException;
import org.springframework.http.HttpStatus;
Expand Down Expand Up @@ -51,6 +52,12 @@ public ErrorResponse handleException(final WebExchangeBindException e) {
return buildResponse(e);
}

@ExceptionHandler(GenAIException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResponse handleGenAIException(final GenAIException e) {
return buildResponse(e);
}

@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResponse handleServerException(final Exception e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.opendatadiscovery.oddplatform.exception;

public class GenAIException extends ExceptionWithErrorCode {

public GenAIException(final String message) {
super(ErrorCode.SERVER_EXCEPTION, message);
}

public GenAIException(final Throwable e) {
super(ErrorCode.SERVER_EXCEPTION, e.getMessage());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.opendatadiscovery.oddplatform.service.genai;

import org.opendatadiscovery.oddplatform.api.contract.model.GenAIRequest;
import org.opendatadiscovery.oddplatform.api.contract.model.GenAIResponse;
import reactor.core.publisher.Mono;

public interface GenAIService {
Mono<GenAIResponse> getResponseFromGenAI(final GenAIRequest item);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package org.opendatadiscovery.oddplatform.service.genai;

import com.google.common.base.CharMatcher;
import io.netty.handler.timeout.ReadTimeoutException;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.opendatadiscovery.oddplatform.api.contract.model.GenAIRequest;
import org.opendatadiscovery.oddplatform.api.contract.model.GenAIResponse;
import org.opendatadiscovery.oddplatform.exception.BadUserRequestException;
import org.opendatadiscovery.oddplatform.exception.GenAIException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

@Slf4j
@Service
public class GenAIServiceImpl implements GenAIService {
public static final String QUERY_DATA = "/query_data";
public static final String QUESTION_FIELD = "question";

private final String genAIUrl;
private final Integer getAiRequestTimeout;
private final WebClient webClient;

@Autowired
public GenAIServiceImpl(@Value("${genai.url:}") final String genAIUrl,
@Value("${genai.request_timeout:2}") final Integer getAiRequestTimeout,
@Qualifier("genAiWebClient") final WebClient webClient) {
this.genAIUrl = genAIUrl;
this.getAiRequestTimeout = getAiRequestTimeout;
this.webClient = webClient;
}

@Override
public Mono<GenAIResponse> getResponseFromGenAI(final GenAIRequest request) {
if (StringUtils.isBlank(genAIUrl)) {
return Mono.error(new BadUserRequestException("Gen AI is disabled"));
}

return webClient.post()
.uri(QUERY_DATA)
.bodyValue(Map.of(QUESTION_FIELD, request.getBody()))
.retrieve()
.bodyToMono(String.class)
.map(item -> new GenAIResponse()
.body(StringEscapeUtils.unescapeJava(CharMatcher.is('\"').trimFrom(item))))
.onErrorResume(e -> e.getCause() instanceof ReadTimeoutException
? Mono.error(new GenAIException(
"Gen AI request take longer that %s min".formatted(getAiRequestTimeout)))
: Mono.error(new GenAIException(e)));
}
}
4 changes: 4 additions & 0 deletions odd-platform-api/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ spring:
codec:
max-in-memory-size: 20MB

#genai:
# url: http://localhost:5000
# request_timeout: 2

springdoc:
api-docs:
path: /api/v3/swagger-ui.html
Expand Down
12 changes: 12 additions & 0 deletions odd-platform-specification/components.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4063,6 +4063,18 @@ components:
- GRAPH
- ALL

GenAIRequest:
type: object
properties:
body:
type: string

GenAIResponse:
type: object
properties:
body:
type: string

parameters:
PageParam:
name: page
Expand Down
24 changes: 23 additions & 1 deletion odd-platform-specification/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ tags:
- name: dataQualityRuns
- name: queryExample
- name: referenceData
- name: genai

paths:
/api/integrations:
Expand Down Expand Up @@ -3883,4 +3884,25 @@ paths:
schema:
$ref: './components.yaml/#/components/schemas/DataEntityGraphRelationshipDetails'
tags:
- relationship
- relationship

/api/genai/ask:
post:
summary: Request to genai service
description: create request to genai service with specific question
operationId: genAiQuestion
requestBody:
required: true
content:
application/json:
schema:
$ref: './components.yaml/#/components/schemas/GenAIRequest'
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: './components.yaml/#/components/schemas/GenAIResponse'
tags:
- genai

0 comments on commit a4f3ba6

Please sign in to comment.