From 15812e9068104e8d96af4740854dce755a3fc9a0 Mon Sep 17 00:00:00 2001 From: Victor Martin Date: Mon, 17 Jun 2024 19:42:29 +0200 Subject: [PATCH] add summarization --- LOCAL.md | 52 ++++++- backend/build.gradle | 1 + .../backend/backend/InvalidPromptRequest.java | 2 + .../{ => config}/ClientConfigurationBean.java | 2 +- .../GenerativeAiClientConfig.java | 29 ++-- .../GenerativeAiInferenceClientConfig.java | 23 +-- .../backend/{ => config}/WebSocketConfig.java | 2 +- .../{ => controller}/GenAIController.java | 4 +- .../controller/PDFConvertorController.java | 66 +++++++++ .../{ => controller}/PromptController.java | 27 ++-- .../backend/controller/SummaryController.java | 33 +++++ .../{ => service}/OCIGenAIService.java | 19 ++- .../backend/service/PDFConvertorService.java | 28 ++++ backend/src/main/resources/application.yaml | 5 + deploy/k8s/backend/application.yaml.mustache | 5 +- deploy/k8s/backend/backend.yaml | 5 + deploy/terraform/.terraform.lock.hcl | 137 +++++++++--------- deploy/terraform/terraform.tfvars.mustache | 1 - deploy/terraform/variables.tf | 6 +- scripts/kustom.mjs | 9 +- scripts/setenv.mjs | 70 ++++++--- scripts/tfvars.mjs | 2 - web/package-lock.json | 55 +++++++ web/package.json | 4 +- web/src/App.jsx | 3 +- web/src/Chat.jsx | 11 +- web/src/Routing.jsx | 20 +++ web/src/Summary.jsx | 70 +++++++++ 28 files changed, 532 insertions(+), 159 deletions(-) rename backend/src/main/java/dev/victormartin/oci/genai/backend/backend/{ => config}/ClientConfigurationBean.java (91%) rename backend/src/main/java/dev/victormartin/oci/genai/backend/backend/{ => config}/GenerativeAiClientConfig.java (77%) rename backend/src/main/java/dev/victormartin/oci/genai/backend/backend/{ => config}/GenerativeAiInferenceClientConfig.java (82%) rename backend/src/main/java/dev/victormartin/oci/genai/backend/backend/{ => config}/WebSocketConfig.java (93%) rename backend/src/main/java/dev/victormartin/oci/genai/backend/backend/{ => controller}/GenAIController.java (92%) create mode 100644 backend/src/main/java/dev/victormartin/oci/genai/backend/backend/controller/PDFConvertorController.java rename backend/src/main/java/dev/victormartin/oci/genai/backend/backend/{ => controller}/PromptController.java (77%) create mode 100644 backend/src/main/java/dev/victormartin/oci/genai/backend/backend/controller/SummaryController.java rename backend/src/main/java/dev/victormartin/oci/genai/backend/backend/{ => service}/OCIGenAIService.java (69%) create mode 100644 backend/src/main/java/dev/victormartin/oci/genai/backend/backend/service/PDFConvertorService.java create mode 100644 web/src/Routing.jsx create mode 100644 web/src/Summary.jsx diff --git a/LOCAL.md b/LOCAL.md index 61cc8b9f..d97c2359 100644 --- a/LOCAL.md +++ b/LOCAL.md @@ -1,6 +1,8 @@ # Run Local -## Web +## Run components + +### Run web Run locally in a terminal with: @@ -12,7 +14,7 @@ cd web npm run dev ``` -## Backend +### Run Backend Run locally on another terminal with: @@ -20,15 +22,51 @@ Run locally on another terminal with: cd backend ``` -Edit `/backend/src/main/resources/application.yaml` to have the correct values. +Copy `/backend/src/main/resources/application.yaml` to `/backend/src/main/resources/application-local.yaml` and modify the values required. + +It should look like this: + +```yaml +spring: + main: + banner-mode: "off" + profiles: + active: production + datasource: + driver-class-name: oracle.jdbc.OracleDriver + url: jdbc:oracle:thin:@ADB_SERVICE_NAME_GOES_HERE_high?TNS_ADMIN=/PATH/TO/WALLET/UNZIPPED/IN/TERRAFORM/GENERATED + username: ADMIN + password: "ADB_PASSWORD_GOES_HERE" + type: oracle.ucp.jdbc.PoolDataSource + oracleucp: + sql-for-validate-connection: SELECT * FROM dual + connection-pool-name: connectionPoolName1 + initial-pool-size: 5 + min-pool-size: 5 + max-pool-size: 10 + jpa: + hibernate: + use-new-id-generator-mappings: false + ddl-auto: update +oracle: + jdbc: + fanEnabled: true + +genai: + endpoint: "https://inference.generativeai.us-chicago-1.oci.oraclecloud.com" + region: "us-chicago-1" + compartment_id: "GENAI_COMPARTMENT_OCID_GOES_HERE" + chat_model_id: "GEN_AI_CHAT_MODEL_OCID_GOES_HERE" + summarization_model_id: "GEN_AI_SUMMARIZATION_MODEL_OCID_GOES_HERE" +``` + +Run the Spring Boot backend application in local profile: ```bash -./gradlew bootRun +./gradlew bootRun -Plocal ``` -## Build for distribution - -## Build artifacts +## Other tasks ### Build Java Application: diff --git a/backend/build.gradle b/backend/build.gradle index 4f2a17c5..9deb513a 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -30,6 +30,7 @@ dependencies { implementation 'com.oracle.database.security:oraclepki:21.8.0.0' implementation 'com.oracle.database.security:osdt_cert:21.8.0.0' implementation 'com.oracle.database.security:osdt_core:21.8.0.0' + implementation 'org.apache.pdfbox:pdfbox:3.0.2' exclude(group: 'commons-logging', module: 'commons-logging') testImplementation 'org.springframework.boot:spring-boot-starter-test' } diff --git a/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/InvalidPromptRequest.java b/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/InvalidPromptRequest.java index 96f0fa75..11119758 100644 --- a/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/InvalidPromptRequest.java +++ b/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/InvalidPromptRequest.java @@ -5,4 +5,6 @@ @ResponseStatus(code = HttpStatus.BAD_REQUEST, reason = "Invalid request params") public class InvalidPromptRequest extends RuntimeException { + + } diff --git a/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/ClientConfigurationBean.java b/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/config/ClientConfigurationBean.java similarity index 91% rename from backend/src/main/java/dev/victormartin/oci/genai/backend/backend/ClientConfigurationBean.java rename to backend/src/main/java/dev/victormartin/oci/genai/backend/backend/config/ClientConfigurationBean.java index aeba0c91..1bcc9425 100644 --- a/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/ClientConfigurationBean.java +++ b/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/config/ClientConfigurationBean.java @@ -1,4 +1,4 @@ -package dev.victormartin.oci.genai.backend.backend; +package dev.victormartin.oci.genai.backend.backend.config; import com.oracle.bmc.ClientConfiguration; import com.oracle.bmc.retrier.RetryConfiguration; diff --git a/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/GenerativeAiClientConfig.java b/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/config/GenerativeAiClientConfig.java similarity index 77% rename from backend/src/main/java/dev/victormartin/oci/genai/backend/backend/GenerativeAiClientConfig.java rename to backend/src/main/java/dev/victormartin/oci/genai/backend/backend/config/GenerativeAiClientConfig.java index 6061b5ad..5ff82466 100644 --- a/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/GenerativeAiClientConfig.java +++ b/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/config/GenerativeAiClientConfig.java @@ -1,11 +1,10 @@ -package dev.victormartin.oci.genai.backend.backend; +package dev.victormartin.oci.genai.backend.backend.config; import com.oracle.bmc.ClientConfiguration; import com.oracle.bmc.ConfigFileReader; import com.oracle.bmc.Region; import com.oracle.bmc.auth.AuthenticationDetailsProvider; import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider; -import com.oracle.bmc.auth.InstancePrincipalsAuthenticationDetailsProvider; import com.oracle.bmc.auth.okeworkloadidentity.OkeWorkloadIdentityAuthenticationDetailsProvider; import com.oracle.bmc.generativeai.GenerativeAiClient; import jakarta.annotation.PostConstruct; @@ -39,8 +38,11 @@ public class GenerativeAiClientConfig { @Value("${genai.config.profile}") private String CONFIG_PROFILE; - @Value("${genai.model_id}") - private String modelId; + @Value("${genai.chat_model_id}") + private String chatModelId; + + @Value("${genai.summarization_model_id}") + private String summarizationModelId; private Region region; @@ -62,12 +64,11 @@ GenerativeAiClient genAiClient() throws IOException { } GenerativeAiClient instancePrincipalConfig() throws IOException { - final OkeWorkloadIdentityAuthenticationDetailsProvider okeProvider = - new OkeWorkloadIdentityAuthenticationDetailsProvider - .OkeWorkloadIdentityAuthenticationDetailsProviderBuilder() - .build(); -// final InstancePrincipalsAuthenticationDetailsProvider provider = -// new InstancePrincipalsAuthenticationDetailsProvider.InstancePrincipalsAuthenticationDetailsProviderBuilder().build(); + final OkeWorkloadIdentityAuthenticationDetailsProvider okeProvider = new OkeWorkloadIdentityAuthenticationDetailsProvider.OkeWorkloadIdentityAuthenticationDetailsProviderBuilder() + .build(); + // final InstancePrincipalsAuthenticationDetailsProvider provider = + // new + // InstancePrincipalsAuthenticationDetailsProvider.InstancePrincipalsAuthenticationDetailsProviderBuilder().build(); GenerativeAiClient generativeAiClient = new GenerativeAiClient(okeProvider, clientConfiguration); generativeAiClient.setRegion(okeProvider.getRegion()); @@ -76,9 +77,11 @@ GenerativeAiClient instancePrincipalConfig() throws IOException { } GenerativeAiClient localConfig() throws IOException { - // Configuring the AuthenticationDetailsProvider. It's assuming there is a default OCI config file - // "~/.oci/config", and a profile in that config with the name defined in CONFIG_PROFILE variable. - final ConfigFileReader.ConfigFile configFile = ConfigFileReader.parse(CONFIG_LOCATION, CONFIG_PROFILE); + // Configuring the AuthenticationDetailsProvider. It's assuming there is a + // default OCI config file + // "~/.oci/config", and a profile in that config with the name defined in + // CONFIG_PROFILE variable. + final ConfigFileReader.ConfigFile configFile = ConfigFileReader.parse(CONFIG_LOCATION, CONFIG_PROFILE); final AuthenticationDetailsProvider provider = new ConfigFileAuthenticationDetailsProvider(configFile); GenerativeAiClient generativeAiClient = new GenerativeAiClient(provider, diff --git a/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/GenerativeAiInferenceClientConfig.java b/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/config/GenerativeAiInferenceClientConfig.java similarity index 82% rename from backend/src/main/java/dev/victormartin/oci/genai/backend/backend/GenerativeAiInferenceClientConfig.java rename to backend/src/main/java/dev/victormartin/oci/genai/backend/backend/config/GenerativeAiInferenceClientConfig.java index ae4c65bb..56a513ef 100644 --- a/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/GenerativeAiInferenceClientConfig.java +++ b/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/config/GenerativeAiInferenceClientConfig.java @@ -1,4 +1,4 @@ -package dev.victormartin.oci.genai.backend.backend; +package dev.victormartin.oci.genai.backend.backend.config; import com.oracle.bmc.ClientConfiguration; import com.oracle.bmc.ConfigFileReader; @@ -38,8 +38,11 @@ public class GenerativeAiInferenceClientConfig { @Value("${genai.config.profile}") private String CONFIG_PROFILE; - @Value("${genai.model_id}") - private String modelId; + @Value("${genai.chat_model_id}") + private String modelChatId; + + @Value("${genai.summarization_model_id}") + private String modelSummarizationId; private Region region; @@ -62,8 +65,8 @@ GenerativeAiInferenceClient genAiInferenceClient() throws IOException { } GenerativeAiInferenceClient instancePrincipalConfig() throws IOException { - final InstancePrincipalsAuthenticationDetailsProvider provider = - new InstancePrincipalsAuthenticationDetailsProvider.InstancePrincipalsAuthenticationDetailsProviderBuilder().build(); + final InstancePrincipalsAuthenticationDetailsProvider provider = new InstancePrincipalsAuthenticationDetailsProvider.InstancePrincipalsAuthenticationDetailsProviderBuilder() + .build(); GenerativeAiInferenceClient generativeAiInferenceClient = new GenerativeAiInferenceClient(provider, clientConfiguration); @@ -73,12 +76,14 @@ GenerativeAiInferenceClient instancePrincipalConfig() throws IOException { } GenerativeAiInferenceClient localConfig() throws IOException { - // Configuring the AuthenticationDetailsProvider. It's assuming there is a default OCI config file - // "~/.oci/config", and a profile in that config with the name defined in CONFIG_PROFILE variable. - final ConfigFileReader.ConfigFile configFile = ConfigFileReader.parse(CONFIG_LOCATION, CONFIG_PROFILE); + // Configuring the AuthenticationDetailsProvider. It's assuming there is a + // default OCI config file + // "~/.oci/config", and a profile in that config with the name defined in + // CONFIG_PROFILE variable. + final ConfigFileReader.ConfigFile configFile = ConfigFileReader.parse(CONFIG_LOCATION, CONFIG_PROFILE); final AuthenticationDetailsProvider provider = new ConfigFileAuthenticationDetailsProvider(configFile); - GenerativeAiInferenceClient generativeAiInferenceClient = new GenerativeAiInferenceClient(provider, + GenerativeAiInferenceClient generativeAiInferenceClient = new GenerativeAiInferenceClient(provider, clientConfiguration); generativeAiInferenceClient.setEndpoint(ENDPOINT); generativeAiInferenceClient.setRegion(region); diff --git a/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/WebSocketConfig.java b/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/config/WebSocketConfig.java similarity index 93% rename from backend/src/main/java/dev/victormartin/oci/genai/backend/backend/WebSocketConfig.java rename to backend/src/main/java/dev/victormartin/oci/genai/backend/backend/config/WebSocketConfig.java index 8074e3e0..b4a0e6d4 100644 --- a/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/WebSocketConfig.java +++ b/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/config/WebSocketConfig.java @@ -1,4 +1,4 @@ -package dev.victormartin.oci.genai.backend.backend; +package dev.victormartin.oci.genai.backend.backend.config; import org.springframework.context.annotation.Configuration; import org.springframework.messaging.simp.config.MessageBrokerRegistry; diff --git a/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/GenAIController.java b/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/controller/GenAIController.java similarity index 92% rename from backend/src/main/java/dev/victormartin/oci/genai/backend/backend/GenAIController.java rename to backend/src/main/java/dev/victormartin/oci/genai/backend/backend/controller/GenAIController.java index e30bcc18..bd8d1d98 100644 --- a/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/GenAIController.java +++ b/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/controller/GenAIController.java @@ -1,12 +1,10 @@ -package dev.victormartin.oci.genai.backend.backend; +package dev.victormartin.oci.genai.backend.backend.controller; -import com.oracle.bmc.ClientConfiguration; import com.oracle.bmc.generativeai.GenerativeAiClient; import com.oracle.bmc.generativeai.model.ModelCapability; import com.oracle.bmc.generativeai.requests.ListModelsRequest; import com.oracle.bmc.generativeai.responses.ListModelsResponse; import dev.victormartin.oci.genai.backend.backend.dao.GenAiModel; -import org.bouncycastle.util.Objects; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/controller/PDFConvertorController.java b/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/controller/PDFConvertorController.java new file mode 100644 index 00000000..5af08852 --- /dev/null +++ b/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/controller/PDFConvertorController.java @@ -0,0 +1,66 @@ +package dev.victormartin.oci.genai.backend.backend.controller; + + +import dev.victormartin.oci.genai.backend.backend.service.OCIGenAIService; +import dev.victormartin.oci.genai.backend.backend.service.PDFConvertorService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MaxUploadSizeExceededException; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; + +@RestController +public class PDFConvertorController { + Logger log = LoggerFactory.getLogger(PDFConvertorController.class); + + @Value("${storage.path}") + String storagePath; + + @Value("${genai.summarization_model_id}") + String summarizationModelId; + + @Autowired + OCIGenAIService ociGenAIService; + + @Autowired + PDFConvertorService pdfConvertorService; + + @Autowired + SummaryController summaryController; + + @PostMapping("/api/upload") + public String fileUploading(@RequestParam("file") MultipartFile multipartFile) { + String filename = StringUtils.cleanPath(multipartFile.getOriginalFilename()); + log.info("File uploaded {} {} bytes ({})", filename, multipartFile.getSize(), multipartFile.getContentType()); + try { + if (filename.contains("..")) { + throw new Exception("Filename contains invalid path sequence"); + } + if (multipartFile.getBytes().length > (1024 * 1024)) { + throw new Exception("File size exceeds maximum limit"); + } + String fileDestinationPath = StringUtils.cleanPath(storagePath); + File file = new File(fileDestinationPath + File.separator + filename); + multipartFile.transferTo(file); + log.info("File destination path: {}", file.getAbsolutePath()); + String convertedText = pdfConvertorService.convert(file.getAbsolutePath()); + String summaryText = ociGenAIService.summaryText(convertedText, summarizationModelId); + log.info("Summary text: {}(...)", summaryText.substring(0, 40)); + summaryController.handleSummary(summaryText); + return summaryText; + } catch (MaxUploadSizeExceededException maxUploadSizeExceededException) { + log.error(maxUploadSizeExceededException.getMessage()); + throw new RuntimeException(maxUploadSizeExceededException); + } catch (Exception e) { + log.error(e.getMessage()); + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/PromptController.java b/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/controller/PromptController.java similarity index 77% rename from backend/src/main/java/dev/victormartin/oci/genai/backend/backend/PromptController.java rename to backend/src/main/java/dev/victormartin/oci/genai/backend/backend/controller/PromptController.java index 0822712b..6eda8fe4 100644 --- a/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/PromptController.java +++ b/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/controller/PromptController.java @@ -1,6 +1,8 @@ -package dev.victormartin.oci.genai.backend.backend; +package dev.victormartin.oci.genai.backend.backend.controller; import com.oracle.bmc.model.BmcException; +import dev.victormartin.oci.genai.backend.backend.InvalidPromptRequest; +import dev.victormartin.oci.genai.backend.backend.service.OCIGenAIService; import dev.victormartin.oci.genai.backend.backend.dao.Answer; import dev.victormartin.oci.genai.backend.backend.dao.Prompt; import dev.victormartin.oci.genai.backend.backend.data.Interaction; @@ -21,14 +23,17 @@ public class PromptController { Logger logger = LoggerFactory.getLogger(PromptController.class); - @Value("${genai.model_id}") - private String hardcodedModelId; + @Value("${genai.chat_model_id}") + private String hardcodedChatModelId; + + @Value("${genai.summarization_model_id}") + private String hardcodedSummarizationModelId; @Autowired private final InteractionRepository interactionRepository; @Autowired - OCIGenAIService genAI; + OCIGenAIService genAI; public PromptController(InteractionRepository interactionRepository, OCIGenAIService genAI) { this.interactionRepository = interactionRepository; @@ -40,17 +45,21 @@ public PromptController(InteractionRepository interactionRepository, OCIGenAISer public Answer handlePrompt(Prompt prompt) { String promptEscaped = HtmlUtils.htmlEscape(prompt.content()); logger.info("Prompt " + promptEscaped + " received, on model " + prompt.modelId() + " but using hardcoded one" + - " " + hardcodedModelId); + " " + hardcodedChatModelId); Interaction interaction = new Interaction(); interaction.setConversationId(prompt.conversationId()); interaction.setDatetimeRequest(new Date()); - interaction.setModelId(hardcodedModelId); + interaction.setModelId(hardcodedChatModelId); interaction.setRequest(promptEscaped); Interaction saved = interactionRepository.save(interaction); try { - if (prompt.content() == null || prompt.content().length()< 1) { throw new InvalidPromptRequest(); } -// if (prompt.modelId() == null || !prompt.modelId().startsWith("ocid1.generativeaimodel.")) { throw new InvalidPromptRequest(); } - String responseFromGenAI = genAI.request(promptEscaped, hardcodedModelId); + if (prompt.content() == null || prompt.content().length() < 1) { + throw new InvalidPromptRequest(); + } + // if (prompt.modelId() == null || + // !prompt.modelId().startsWith("ocid1.generativeaimodel.")) { throw new + // InvalidPromptRequest(); } + String responseFromGenAI = genAI.request(promptEscaped, hardcodedChatModelId); saved.setDatetimeResponse(new Date()); saved.setResponse(responseFromGenAI); interactionRepository.save(saved); diff --git a/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/controller/SummaryController.java b/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/controller/SummaryController.java new file mode 100644 index 00000000..8c49ed5f --- /dev/null +++ b/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/controller/SummaryController.java @@ -0,0 +1,33 @@ +package dev.victormartin.oci.genai.backend.backend.controller; + +import com.oracle.bmc.model.BmcException; +import dev.victormartin.oci.genai.backend.backend.InvalidPromptRequest; +import dev.victormartin.oci.genai.backend.backend.dao.Answer; +import dev.victormartin.oci.genai.backend.backend.dao.Prompt; +import dev.victormartin.oci.genai.backend.backend.data.Interaction; +import dev.victormartin.oci.genai.backend.backend.data.InteractionRepository; +import dev.victormartin.oci.genai.backend.backend.service.OCIGenAIService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.messaging.handler.annotation.MessageMapping; +import org.springframework.messaging.simp.annotation.SendToUser; +import org.springframework.messaging.simp.annotation.SubscribeMapping; +import org.springframework.stereotype.Controller; +import org.springframework.web.util.HtmlUtils; + +import java.util.Date; + +@Controller +public class SummaryController { + Logger logger = LoggerFactory.getLogger(SummaryController.class); + + @SendToUser("/queue/summary") + public Answer handleSummary(String summary) { + logger.info("handleSummary"); + return new Answer(summary , ""); + } + +} diff --git a/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/OCIGenAIService.java b/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/service/OCIGenAIService.java similarity index 69% rename from backend/src/main/java/dev/victormartin/oci/genai/backend/backend/OCIGenAIService.java rename to backend/src/main/java/dev/victormartin/oci/genai/backend/backend/service/OCIGenAIService.java index 21b91c3c..ca4a5356 100644 --- a/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/OCIGenAIService.java +++ b/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/service/OCIGenAIService.java @@ -1,11 +1,12 @@ -package dev.victormartin.oci.genai.backend.backend; +package dev.victormartin.oci.genai.backend.backend.service; import com.oracle.bmc.generativeaiinference.GenerativeAiInferenceClient; import com.oracle.bmc.generativeaiinference.model.*; import com.oracle.bmc.generativeaiinference.requests.GenerateTextRequest; +import com.oracle.bmc.generativeaiinference.requests.SummarizeTextRequest; import com.oracle.bmc.generativeaiinference.responses.GenerateTextResponse; +import com.oracle.bmc.generativeaiinference.responses.SummarizeTextResponse; 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; @@ -46,4 +47,18 @@ public String request(String input, String modelId) { String responseTexts = response.getGeneratedTexts().stream().map(t -> t.getText()).collect(Collectors.joining(",")); return responseTexts; } + + public String summaryText(String input, String modelId) { + SummarizeTextDetails summarizeTextDetails = SummarizeTextDetails.builder() + .servingMode(OnDemandServingMode.builder().modelId(modelId).build()) + .compartmentId(COMPARTMENT_ID) + .input(input) + .build(); + SummarizeTextRequest request = SummarizeTextRequest.builder() + .summarizeTextDetails(summarizeTextDetails) + .build(); + SummarizeTextResponse summarizeTextResponse = generativeAiInferenceClient.summarizeText(request); + String summaryText = summarizeTextResponse.getSummarizeTextResult().getSummary(); + return summaryText; + } } diff --git a/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/service/PDFConvertorService.java b/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/service/PDFConvertorService.java new file mode 100644 index 00000000..489572b5 --- /dev/null +++ b/backend/src/main/java/dev/victormartin/oci/genai/backend/backend/service/PDFConvertorService.java @@ -0,0 +1,28 @@ +package dev.victormartin.oci.genai.backend.backend.service; + +import org.apache.pdfbox.Loader; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.text.PDFTextStripper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import org.springframework.util.ResourceUtils; + +import java.io.File; +import java.io.IOException; + +@Service +public class PDFConvertorService { + Logger log = LoggerFactory.getLogger(PDFConvertorService.class); + + public String convert(String filePath) { + try { + File file = ResourceUtils.getFile(filePath); + PDDocument doc = Loader.loadPDF(file); + return new PDFTextStripper().getText(doc); + } catch (IOException e) { + log.error(e.getMessage()); + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/backend/src/main/resources/application.yaml b/backend/src/main/resources/application.yaml index ea57646c..395a64e1 100644 --- a/backend/src/main/resources/application.yaml +++ b/backend/src/main/resources/application.yaml @@ -30,3 +30,8 @@ genai: location: "~/.oci/config" profile: "DEFAULT" compartment_id: "COMPARTMENT_ID" + chat_model_id: "ocid1.generativeaimodel.AAAAAAAAAAAAA" + summarization_model_id: "ocid1.generativeaimodel.AAAAAAAAAAAAA" +storage: + path: "/PATH/FOR/UPLOAD/FILES" + diff --git a/deploy/k8s/backend/application.yaml.mustache b/deploy/k8s/backend/application.yaml.mustache index 745be48b..3b1de91f 100644 --- a/deploy/k8s/backend/application.yaml.mustache +++ b/deploy/k8s/backend/application.yaml.mustache @@ -27,4 +27,7 @@ genai: endpoint: "https://inference.generativeai.{{{region_name}}}.oci.oraclecloud.com" region: "{{{region_name}}}" compartment_id: "{{{compartment_ocid}}}" - model_id: "{{{genai_model_ocid}}}" + chat_model_id: "{{{genai_model_chat_ocid}}}" + summarization_model_id: "{{{genai_model_summarization_ocid}}}" +storage: + path: "/temp" diff --git a/deploy/k8s/backend/backend.yaml b/deploy/k8s/backend/backend.yaml index 2f7d61b9..b2a3e4cd 100644 --- a/deploy/k8s/backend/backend.yaml +++ b/deploy/k8s/backend/backend.yaml @@ -61,6 +61,8 @@ spec: mountPath: /config - name: wallet-volume mountPath: /wallet + - name: temp + mountPath: /temp volumes: - name: config-volume configMap: @@ -71,5 +73,8 @@ spec: - name: wallet-volume emptyDir: sizeLimit: 50Mi + - name: temp + emptyDir: + sizeLimit: 500Mi imagePullSecrets: - name: ocir-secret \ No newline at end of file diff --git a/deploy/terraform/.terraform.lock.hcl b/deploy/terraform/.terraform.lock.hcl index 854822c7..f028cf39 100644 --- a/deploy/terraform/.terraform.lock.hcl +++ b/deploy/terraform/.terraform.lock.hcl @@ -22,42 +22,42 @@ provider "registry.terraform.io/hashicorp/cloudinit" { } provider "registry.terraform.io/hashicorp/helm" { - version = "2.13.1" + version = "2.13.2" constraints = ">= 2.9.0" hashes = [ - "h1:crwHSTDCQ6fS8dQYGkoi700MI5UpbA2BDLgMZgL3B+E=", - "zh:1bf0ae1ecfd2a5d5a57f695a33b2328ef197138f27ff372fed820c975eac9783", - "zh:4676295e3a929848b98869d3040f54f17fbed3d133342b6a1f7b72d5797239e0", - "zh:4bf3705e061e28d16a525aad9229fdd842cdc96f7c23d040d3148957ba3149d8", - "zh:69db9550eacd61d85cf456d438f08addfefea4fcbc4f4a8119105093ea3d950a", - "zh:6e11560e3ea61b141f03842771bfad143ff1c56bd0d1bc01069496107cad0ab6", - "zh:733ea41e2eb4bd63cfdae6886ed47d224dabb0cd37959c6e2b213b1914a80121", - "zh:74caefb2dc8e6055259d716c11194cc0709261c592d41466abf2dc0b21d88297", - "zh:89682ab50b5cf1f1c41eabfc76f53a56482ac7b4bf77d9cb087d789524fd3e31", - "zh:a5ff95092f2f123027b89f585612a225c9bce7e65977b4ffaf4de3ae3e7870bc", - "zh:c85fce024cb5a387702ceb42a3a06e32519cd1e61bc9dd820a762da21110ab96", - "zh:d828ef2db612798179322bcb3fe829a43dd47e740cabb67e3654c8561ae661ff", + "h1:KHLdE3Xb4XbLCWwCSArYcXulYyBJKTFizaIzBiYVJxQ=", + "zh:06c0663031ef5aa19e238fe50be5d3cbf5fb00548d2b26e779c607dfd2dc69a7", + "zh:1850b8f2e729553ba8b96d69dce035b814ce959c6805c25484f407c4e720c497", + "zh:1ec76814a99461cd79ee4c879ed455ab338a3cb9e63fbe9308f91b5515e72e42", + "zh:78546b2f0b2e9072370c017d8056a2ffda908c2e463d2792244e4be6562ab772", + "zh:9205eef438aa3d5e49505655b7c300f7cecfa30f8fa37ed84679f674420403f2", + "zh:9335c7300675e5088ab4090af3c8150701c0bb8ea67ad23ebd753f6ab3a922a9", + "zh:9722d8b419e9615a04b8fc9acb50e52d6ba988c7565cc517bc16faa0a9e895b3", + "zh:aa93d9fc7db91f261b6e41970453926341eaa4222c1b8d507cdeabd0be0af4eb", + "zh:c59a2af538de99c37e4ffe988f33633a9fb064e5360230adac5f6eb0fd473be8", + "zh:d6323f61f255131a7d9f5a645982eb0f0d12f685270f54beade95c0b51a7a6c9", + "zh:e7f46dd2aac9537d20aaac217806f2ebb3a347aaf6bbd28192c042286103635c", "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", ] } provider "registry.terraform.io/hashicorp/http" { - version = "3.4.2" + version = "3.4.3" constraints = ">= 3.2.1" hashes = [ - "h1:vaoPfsLm6mOk6avKTrWi35o+9p4fEeZAY3hzYoXVTfo=", - "zh:0ba051c9c8659ce0fec94a3d50926745f11759509c4d6de0ad5f5eb289f0edd9", - "zh:23e6760e8406fef645913bf47bfab1ca984c1c5805d2bb0ef8310b16913d29cd", - "zh:3c69fde4548bfe65b968534c4df8d699648c921d6a065b97fec5faece73a442b", - "zh:41c7f9a8c117704b7a8fa96a57ebfb92b72129d9625128eeb0dee7d5a09d1110", - "zh:59d09d2e00727df10565cc82a33250b44201fcd353eb2b1579507a5a0adcce18", + "h1:Ep4kCumou6eEyPkFJFAfuzd7IAsYM7xMAdDaFTwdDZ8=", + "zh:001e12b8079955a9fa7f8fcd515ae665b2e1087107fd337c4b872e88a86d540b", + "zh:0874fb3f870b2ac24c967a9685f2da641079589024109340389694696301a85b", + "zh:3b5e533c3d2859575945568aad0aac66b71bfc709706231fc2de94e01ca76d7f", + "zh:622ee28d42ed9d4b1399dde377db515e62cac08bd65bb2455068621f7a42d90d", + "zh:6dea688d78840a3f678e06ee602d37c766ce2ee625dcdce0c6658116ebcbde8e", "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:c95b2f63d4357b3068531b90d9dca62a32551d7693defb7ab14b650b5d139c57", - "zh:cc0a3bbd3026191b35f417d3a8f26bdfad376d15be9e8d99a8803487ca5b0105", - "zh:d1185c6abb3ba25123fb7df1ad7dbe2b9cd8f43962628da551040fbe1934656f", - "zh:dfb26fccab7ecdc150f67415e6cfe19d699dc43e8bf5722f36032b17b46a0fbe", - "zh:eb1fcc00073bc0463f64e49600a73d925b1a0c0ae5b94dd7b67d3ebac248a113", - "zh:ec9b9ad69cf790cb0603a1036d758063bbbc35c0c75f72dd04a1eddaf46ad010", + "zh:7f57a1436a464bc2e1698457b402ff0fd98ef9e7dcf6707d6bd0debc67fad164", + "zh:829d89d82e6fc3c89714950dc8afa51d622bb8e4f4bd5c73037505fb55a67834", + "zh:e453202d09b62531ed3278926307d315276e05784e7c6448a2c21c6a2da6e48f", + "zh:e76edc035240b4ad9334b4a0282b44a086e001df3007a2fc51f6262c4db032d1", + "zh:eeb0379da9093e155a193f666079de6baf8ed02855bf2a443448903f7cfef378", + "zh:fcb00eeb665ccae383645173d8e10c3071946396629a7797db39c798997f21b0", ] } @@ -102,63 +102,64 @@ provider "registry.terraform.io/hashicorp/null" { } provider "registry.terraform.io/hashicorp/random" { - version = "3.6.1" + version = "3.6.2" constraints = "~> 3.0, >= 3.4.3" hashes = [ - "h1:a+Goawwh6Qtg4/bRWzfDtIdrEFfPlnVy0y4LdUQY3nI=", - "zh:2a0ec154e39911f19c8214acd6241e469157489fc56b6c739f45fbed5896a176", - "zh:57f4e553224a5e849c99131f5e5294be3a7adcabe2d867d8a4fef8d0976e0e52", - "zh:58f09948c608e601bd9d0a9e47dcb78e2b2c13b4bda4d8f097d09152ea9e91c5", - "zh:5c2a297146ed6fb3fe934c800e78380f700f49ff24dbb5fb5463134948e3a65f", + "h1:VavG5unYCa3SYISMKF9pzc3718M0bhPlcbUZZGl7wuo=", + "zh:0ef01a4f81147b32c1bea3429974d4d104bbc4be2ba3cfa667031a8183ef88ec", + "zh:1bcd2d8161e89e39886119965ef0f37fcce2da9c1aca34263dd3002ba05fcb53", + "zh:37c75d15e9514556a5f4ed02e1548aaa95c0ecd6ff9af1119ac905144c70c114", + "zh:4210550a767226976bc7e57d988b9ce48f4411fa8a60cd74a6b246baf7589dad", + "zh:562007382520cd4baa7320f35e1370ffe84e46ed4e2071fdc7e4b1a9b1f8ae9b", + "zh:5efb9da90f665e43f22c2e13e0ce48e86cae2d960aaf1abf721b497f32025916", + "zh:6f71257a6b1218d02a573fc9bff0657410404fb2ef23bc66ae8cd968f98d5ff6", "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:7ce41e26f0603e31cdac849085fc99e5cd5b3b73414c6c6d955c0ceb249b593f", - "zh:8c9e8d30c4ef08ee8bcc4294dbf3c2115cd7d9049c6ba21422bd3471d92faf8a", - "zh:93e91be717a7ffbd6410120eb925ebb8658cc8f563de35a8b53804d33c51c8b0", - "zh:982542e921970d727ce10ed64795bf36c4dec77a5db0741d4665230d12250a0d", - "zh:b9d1873f14d6033e216510ef541c891f44d249464f13cc07d3f782d09c7d18de", - "zh:cfe27faa0bc9556391c8803ade135a5856c34a3fe85b9ae3bdd515013c0c87c1", - "zh:e4aabf3184bbb556b89e4b195eab1514c86a2914dd01c23ad9813ec17e863a8a", + "zh:9647e18f221380a85f2f0ab387c68fdafd58af6193a932417299cdcae4710150", + "zh:bb6297ce412c3c2fa9fec726114e5e0508dd2638cad6a0cb433194930c97a544", + "zh:f83e925ed73ff8a5ef6e3608ad9225baa5376446349572c2449c0c0b3cf184b7", + "zh:fbef0781cb64de76b1df1ca11078aecba7800d82fd4a956302734999cfd9a4af", ] } provider "registry.terraform.io/hashicorp/time" { - version = "0.11.1" + version = "0.11.2" + constraints = ">= 0.9.1" hashes = [ - "h1:pQGSL9mdgw4qsLndFYsEF93mbsIxyxNoAyIbBqhS3Xo=", - "zh:19a393db736ec4fd024d098d55aefaef07056c37a448ece3b55b3f5f4c2c7e4a", - "zh:227fa1e221de2907f37be78d40c06ca6a6f7b243a1ec33ade014dfaf6d92cd9c", - "zh:29970fecbf4a3ca23bacbb05d6b90cdd33dd379f90059fe39e08289951502d9f", - "zh:65024596f22f10e7dcb5e0e4a75277f275b529daa0bc0daf34ca7901c678ab88", - "zh:694d080cb5e3bf5ef08c7409208d061c135a4f5f4cdc93ea8607860995264b2e", + "h1:qg3O4PmHnlPcvuZ2LvzOYEAPGOKtccgD5kPdQPZw094=", + "zh:02588b5b8ba5d31e86d93edc93b306bcbf47c789f576769245968cc157a9e8c5", + "zh:088a30c23796133678d1d6614da5cf5544430570408a17062288b58c0bd67ac8", + "zh:0df5faa072d67616154d38021934d8a8a316533429a3f582df3b4b48c836cf89", + "zh:12edeeaef96c47f694bd1ba7ead6ccdb96028b25df352eea4bc5e40de7a59177", + "zh:1e859504a656a6e988f07b908e6ffe946b28bfb56889417c0a07ea9605a3b7b0", + "zh:64a6ae0320d4956c4fdb05629cfcebd03bcbd2206e2d733f2f18e4a97f4d5c7c", "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:b29d15d13e1b3412e6a4e1627d378dbd102659132f7488f64017dd6b6d5216d3", - "zh:bb79f4cae9f8c17c73998edc54aa16c2130a03227f7f4e71fc6ac87e230575ec", - "zh:ceccf80e95929d97f62dcf1bb3c7c7553d5757b2d9e7d222518722fc934f7ad5", - "zh:f40e638336527490e294d9c938ae55919069e6987e85a80506784ba90348792a", - "zh:f99ef33b1629a3b2278201142a3011a8489e66d92da832a5b99e442204de18fb", - "zh:fded14754ea46fdecc62a52cd970126420d4cd190e598cb61190b4724a727edb", + "zh:924d137959193bf7aee6ebf241fbb9aec46d6eef828c5cf8d3c588770acae7b2", + "zh:b3cc76281a4faa9c2293a2460fc6962f6539e900994053f85185304887dddab8", + "zh:cbb40c791d4a1cdba56cffa43a9c0ed8e69930d49aa6bd931546b18c36e3b720", + "zh:d227d43594f8cb3d24f1fdd71382f14502cbe2a6deaddbc74242656bb5b38daf", + "zh:d4840641c46176bb9d70ba3aff09de749282136c779996b546c81e5ff701bbf6", ] } provider "registry.terraform.io/oracle/oci" { - version = "5.39.0" + version = "5.46.0" constraints = ">= 4.67.3, >= 4.119.0, ~> 5.38" hashes = [ - "h1:Fz75vMgyrbbX15nCCKBsHaBk6WQSFmj+AGt2feO3i30=", - "zh:16ecadd604105acbbf0c672312cd8bcd767d1d70f4c22d42c87a8b47cb091af7", - "zh:25aa3b4c7393b871964a3191c9b29ad8903c8b14c3992b201112fbd088c3f62a", - "zh:2da84f62599e2ba05cc0c68ba57f70b86c35b5de2486ad687885473921f5cc73", - "zh:33c436714d21402a5284082b264b1f1f97be171b038a1dcc9d502e670b1252a7", - "zh:63ced8cd3826e7b9e72ee3181ec0839a4df766910866e5c4a9dfa3116ffb4581", - "zh:7b069a26ed5996cb352115b024efd4b000206226285449766eb2135f81c7b630", - "zh:8cb0fbb334dab8d4192458dbcfb65c413c987caea1ab26025da88e805657d383", - "zh:941bc8354db5fc99c5029a6c5ac9c0e1f77a97b8e066fff96b3d10a3ee08a5a4", + "h1:YnxOoKaBVUxvyEAcRrc8/amNglrtGTzxeTDmzm3R+LY=", + "zh:0dac7eba4d556d209627d11e2af6ae564a579617b548f411b5282952632d6820", + "zh:1b2d3e2282de8252ed6c017fc693c65747a0bf078b01423d6455df4723f5db60", + "zh:27763b8525aa2561adfb7c10f879e06fed71b4862f0f4d19086a0e22c05d6b49", + "zh:30cb5dca2edbfe4d31a73004ef049bde4b9f91ea85fdc188fc12f8e660563a45", + "zh:33b46e57b2d5a81e9bca7b6c7cd1a56dd0dc90f47f0624834e7eb1092a19a2d4", + "zh:3944bb473e7ed85fd08f6d47d65b5796f0da7714b51748c3e1c4854e9bc328a5", + "zh:3f2a950cd9604b00f03fb5ecdf0597b682fb9928a05e58d55c59c4b044824ba2", + "zh:47c85fc844dc0d685d5f3e513494ada8d785bb94188faad2ae00124ef10b319c", + "zh:5fc8235fb0be1192cfbd22b2cd14d20037b6611c3e783b9881ba3810befff805", "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", - "zh:b290e335dd764a215e6b76ab90043f946c9c031c99f0642f6887b0c21d594410", - "zh:c5ae643fe1a0ecc437c211878ee6c70470ba1ea4cc4d81f0c711fd6163de2ad6", - "zh:dea1baf7d1e452c385ed428bb9409620486160b263a61f0579421ebea4a49059", - "zh:e7ee0a50d6f94e248a2b6b513461690f0cd7d1df87d6894e849a89f3cb13caf3", - "zh:f99c0ce0433f95a57a53f9f4c4e15a07616fcfb7a00d3daf4fc5588c9b4c8d71", - "zh:fae86a1450561e463beeb0edfdc5b0dbfe82e4ed0a6fe246d4b94ef538ebce85", + "zh:ac6537a460a506b6e09a7c90b1e26020fea4f621acc340a45286c9259a1e8a6f", + "zh:b4e4bc61eca8b7ee631976d40a506d67c4036c5ba63e74e2e19a28de57a13f77", + "zh:f0d67a9b83ad23b8083a9be648522b4e2f76fe302c782a0f5ece740e27111fb1", + "zh:f1daa463d29a83b97b51fa43e128abfae86613bedd4e214f085646c7702f8ee6", + "zh:fbc09b3f713baf0f0525a70dcabd774b05f494ad9773870bcf6fe104c46feb92", ] } diff --git a/deploy/terraform/terraform.tfvars.mustache b/deploy/terraform/terraform.tfvars.mustache index dd0e6bf3..a4b8f311 100644 --- a/deploy/terraform/terraform.tfvars.mustache +++ b/deploy/terraform/terraform.tfvars.mustache @@ -6,7 +6,6 @@ ssh_private_key_path = "{{{ ssh_private_key_path }}}" cert_fullchain = "{{{ cert_fullchain }}}" cert_private_key = "{{{ cert_private_key }}}" genai_endpoint = "{{{ genai_endpoint }}}" -genai_model_id = "{{ genai_model_id }}" # web_artifact_url = "" # backend_artifact_url = "" diff --git a/deploy/terraform/variables.tf b/deploy/terraform/variables.tf index 08f563bd..7ce9bdc6 100644 --- a/deploy/terraform/variables.tf +++ b/deploy/terraform/variables.tf @@ -67,8 +67,4 @@ variable "artifacts_par_expiration_in_days" { variable "genai_endpoint" { type = string -} - -variable "genai_model_id" { - type = string -} +} \ No newline at end of file diff --git a/scripts/kustom.mjs b/scripts/kustom.mjs index ce3a9348..bde1d658 100644 --- a/scripts/kustom.mjs +++ b/scripts/kustom.mjs @@ -22,10 +22,10 @@ const webVersion = config.get("webVersion"); const backendVersion = config.get("webVersion"); const certFullchain = config.get("certFullchain"); const certPrivateKey = config.get("certPrivateKey"); +const genAiModelChat = config.get("genAiModelChat"); +const genAiModelSummarization = config.get("genAiModelSummarization"); -const { db_service, db_password, cohere_model_id } = await getOutputValues( - "./deploy/terraform" -); +const { db_service, db_password } = await getOutputValues("./deploy/terraform"); await createBackendProperties(); await createProdKustomization(); @@ -47,7 +47,8 @@ async function createBackendProperties() { path_to_wallet: "/wallet", region_name: regionName, compartment_ocid: compartmentId, - genai_model_ocid: cohere_model_id, + genai_model_chat_ocid: genAiModelChat, + genai_model_summarization_ocid: genAiModelSummarization, }); await fs.writeFile(backendPropertiesPath, backendPropertiesOutput); diff --git a/scripts/setenv.mjs b/scripts/setenv.mjs index d798951d..00732357 100644 --- a/scripts/setenv.mjs +++ b/scripts/setenv.mjs @@ -27,7 +27,8 @@ await setRegionEnv(); await setCompartmentEnv(); await createSSHKeys(projectName); await createCerts(); -await setLatestGenAIModel(); +await setLatestGenAIModelChat(); +await setLatestGenAIModelSummarization(); console.log(`\nConfiguration file saved in: ${chalk.green(config.path)}`); @@ -50,22 +51,27 @@ async function setRegionEnv() { (r) => r.key === "ord" ); - await inquirer - .prompt([ - { - type: "list", - name: "region", - message: "Select the region", - choices: listWithGenAISupportingRegions.map((r) => r.name), - filter(val) { - return listWithGenAISupportingRegions.find((r) => r.name === val); + if (listWithGenAISupportingRegions.length === 1) { + config.set("regionName", listWithGenAISupportingRegions[0].name); + config.set("regionKey", listWithGenAISupportingRegions[0].key); + } else { + await inquirer + .prompt([ + { + type: "list", + name: "region", + message: "Select the region", + choices: listWithGenAISupportingRegions.map((r) => r.name), + filter(val) { + return listWithGenAISupportingRegions.find((r) => r.name === val); + }, }, - }, - ]) - .then((answers) => { - config.set("regionName", answers.region.name); - config.set("regionKey", answers.region.key); - }); + ]) + .then((answers) => { + config.set("regionName", answers.region.name); + config.set("regionKey", answers.region.key); + }); + } } async function setCompartmentEnv() { @@ -107,12 +113,34 @@ async function createCerts() { config.set("certPrivateKey", path.join(certPath, "tls.key")); } -async function setLatestGenAIModel() { +async function setLatestGenAIModelChat() { + const latestVersionModel = await getLatestGenAIModels( + config.get("compartmentId"), + config.get("regionName"), + "cohere", + "CHAT" + ); + + const { id, vendor: vendorName, version, capabilities } = latestVersionModel; + const displayName = latestVersionModel["display-name"]; + const timeCreated = moment(latestVersionModel["time-created"]).fromNow(); + console.log( + `Using GenAI Model ${chalk.green(vendorName)}:${chalk.green( + version + )} (${chalk.green(displayName)}) with ${chalk.green( + capabilities.join(",") + )} created ${timeCreated}` + ); + + config.set("genAiModelChat", id); +} + +async function setLatestGenAIModelSummarization() { const latestVersionModel = await getLatestGenAIModels( config.get("compartmentId"), config.get("regionName"), "cohere", - "TEXT_GENERATION" + "TEXT_SUMMARIZATION" ); const { id, vendor: vendorName, version, capabilities } = latestVersionModel; @@ -121,10 +149,10 @@ async function setLatestGenAIModel() { console.log( `Using GenAI Model ${chalk.green(vendorName)}:${chalk.green( version - )} (${chalk.green(displayName)}) with ${capabilities.join( - "," + )} (${chalk.green(displayName)}) with ${chalk.green( + capabilities.join(",") )} created ${timeCreated}` ); - config.set("genAiModel", id); + config.set("genAiModelSummarization", id); } diff --git a/scripts/tfvars.mjs b/scripts/tfvars.mjs index 068da19d..bb1425c6 100644 --- a/scripts/tfvars.mjs +++ b/scripts/tfvars.mjs @@ -19,7 +19,6 @@ async function generateTFVars() { const compartmentName = config.get("compartmentName"); const regionName = config.get("regionName"); const tenancyId = config.get("tenancyId"); - const genAiModel = config.get("genAiModel"); const publicKeyContent = config.get("publicKeyContent"); const sshPrivateKeyPath = config.get("privateKeyPath"); const certFullchain = config.get("certFullchain"); @@ -53,7 +52,6 @@ async function generateTFVars() { // ansible_web_artifact_url: ansibleWebArtifactUrl, // ansible_backend_artifact_url: ansibleBackendArtifactUrl, genai_endpoint: genaiEndpoint, - genai_model_id: genAiModel, }); console.log( diff --git a/web/package-lock.json b/web/package-lock.json index 7ccd7139..881c0ca7 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -16,6 +16,8 @@ "@stomp/stompjs": "^7.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-hook-form": "^7.52.0", + "react-router-dom": "^6.23.1", "uuid": "^9.0.1", "ws": "^8.16.0" }, @@ -1391,6 +1393,14 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@remix-run/router": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.16.1.tgz", + "integrity": "sha512-es2g3dq6Nb07iFxGk5GuHN20RwBZOsuDQN7izWIisUcv9r+d2C5jQxqmgkdebXgReWfiyUabcki6Fg77mSNrig==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.9.5", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.5.tgz", @@ -3897,6 +3907,21 @@ "react": "^18.2.0" } }, + "node_modules/react-hook-form": { + "version": "7.52.0", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.52.0.tgz", + "integrity": "sha512-mJX506Xc6mirzLsmXUJyqlAI3Kj9Ph2RhplYhUVffeOQSnubK2uVqBFOBJmvKikvbFV91pxVXmDiR+QMF19x6A==", + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -3911,6 +3936,36 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.23.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.23.1.tgz", + "integrity": "sha512-fzcOaRF69uvqbbM7OhvQyBTFDVrrGlsFdS3AL+1KfIBtGETibHzi3FkoTRyiDJnWNc2VxrfvR+657ROHjaNjqQ==", + "dependencies": { + "@remix-run/router": "1.16.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.23.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.23.1.tgz", + "integrity": "sha512-utP+K+aSTtEdbWpC+4gxhdlPFwuEfDKq8ZrPFU65bbRJY+l706qjR7yaidBpo3MSeA/fzwbXWbKBI6ftOnP3OQ==", + "dependencies": { + "@remix-run/router": "1.16.1", + "react-router": "6.23.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", diff --git a/web/package.json b/web/package.json index 46ba450e..e794e3bb 100644 --- a/web/package.json +++ b/web/package.json @@ -18,6 +18,8 @@ "@stomp/stompjs": "^7.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-hook-form": "^7.52.0", + "react-router-dom": "^6.23.1", "uuid": "^9.0.1", "ws": "^8.16.0" }, @@ -31,4 +33,4 @@ "eslint-plugin-react-refresh": "^0.4.5", "vite": "^5.0.13" } -} \ No newline at end of file +} diff --git a/web/src/App.jsx b/web/src/App.jsx index 68f4add4..b819f91d 100644 --- a/web/src/App.jsx +++ b/web/src/App.jsx @@ -1,6 +1,7 @@ import { Container, Typography } from "@mui/material"; import { StompProvider } from "./stompHook"; import Chat from "./Chat"; +import Routing from "./Routing"; const protocol = window.location.protocol === "http:" ? "ws://" : "wss://"; const hostname = @@ -20,7 +21,7 @@ function App() { OCI GenAI PoC - + ); diff --git a/web/src/Chat.jsx b/web/src/Chat.jsx index a9de507c..c4d9f126 100644 --- a/web/src/Chat.jsx +++ b/web/src/Chat.jsx @@ -1,14 +1,5 @@ import { useState, useEffect } from "react"; -import { - FormControl, - InputLabel, - MenuItem, - Select, - Box, - CircularProgress, - Snackbar, - Divider, -} from "@mui/material"; +import { Box, CircularProgress, Snackbar } from "@mui/material"; import PromptInput from "./PromptInput"; import Conversation from "./Conversation"; import { useStomp } from "./stompHook"; diff --git a/web/src/Routing.jsx b/web/src/Routing.jsx new file mode 100644 index 00000000..e177820f --- /dev/null +++ b/web/src/Routing.jsx @@ -0,0 +1,20 @@ +import { createBrowserRouter, RouterProvider } from "react-router-dom"; +import Chat from "./Chat"; +import Summary from "./Summary"; + +const router = createBrowserRouter([ + { + path: "/", + element: , + }, + { + path: "/summary", + element: , + }, +]); + +function Routing() { + return ; +} + +export default Routing; diff --git a/web/src/Summary.jsx b/web/src/Summary.jsx new file mode 100644 index 00000000..cd72cda4 --- /dev/null +++ b/web/src/Summary.jsx @@ -0,0 +1,70 @@ +import { Box, Button, Snackbar, Stack, TextField } from "@mui/material"; +import { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import { useStomp } from "./stompHook"; + +function Summary() { + const { register, handleSubmit } = useForm(); + const [waiting, setWaiting] = useState(false); + const [showError, setShowError] = useState(false); + const [errorMessage, setErrorMessage] = useState(); + const { subscribe, unsubscribe, isConnected } = useStomp(); + + useEffect(() => { + if (isConnected) { + subscribe("/user/queue/summary", (message) => { + setWaiting(false); + if (message.errorMessage.length > 0) { + setErrorMessage(message.errorMessage); + setShowError(true); + } else { + console.log("/user/queue/summary"); + console.log(message); + } + }); + } + + return () => { + unsubscribe("/user/queue/summary"); + }; + }, [isConnected]); + + const onSubmit = async (data) => { + const formData = new FormData(); + formData.append("file", data.file[0]); + + const res = await fetch("/api/upload", { + method: "POST", + body: formData, + }); + const text = await res.text(); + console.log(text); + }; + return ( + +
+ + + + + +
+ { + setErrorMessage(); + setShowError(false); + }} + message={errorMessage} + /> +
+ ); +} + +export default Summary;