Skip to content

Commit 1870dfa

Browse files
authored
Merge pull request #17 from oracle-devrel/add-summarization
add summarization
2 parents f5b7bcc + 15812e9 commit 1870dfa

28 files changed

+532
-159
lines changed

LOCAL.md

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Run Local
22

3-
## Web
3+
## Run components
4+
5+
### Run web
46

57
Run locally in a terminal with:
68

@@ -12,23 +14,59 @@ cd web
1214
npm run dev
1315
```
1416

15-
## Backend
17+
### Run Backend
1618

1719
Run locally on another terminal with:
1820

1921
```bash
2022
cd backend
2123
```
2224

23-
Edit `/backend/src/main/resources/application.yaml` to have the correct values.
25+
Copy `/backend/src/main/resources/application.yaml` to `/backend/src/main/resources/application-local.yaml` and modify the values required.
26+
27+
It should look like this:
28+
29+
```yaml
30+
spring:
31+
main:
32+
banner-mode: "off"
33+
profiles:
34+
active: production
35+
datasource:
36+
driver-class-name: oracle.jdbc.OracleDriver
37+
url: jdbc:oracle:thin:@ADB_SERVICE_NAME_GOES_HERE_high?TNS_ADMIN=/PATH/TO/WALLET/UNZIPPED/IN/TERRAFORM/GENERATED
38+
username: ADMIN
39+
password: "ADB_PASSWORD_GOES_HERE"
40+
type: oracle.ucp.jdbc.PoolDataSource
41+
oracleucp:
42+
sql-for-validate-connection: SELECT * FROM dual
43+
connection-pool-name: connectionPoolName1
44+
initial-pool-size: 5
45+
min-pool-size: 5
46+
max-pool-size: 10
47+
jpa:
48+
hibernate:
49+
use-new-id-generator-mappings: false
50+
ddl-auto: update
51+
oracle:
52+
jdbc:
53+
fanEnabled: true
54+
55+
genai:
56+
endpoint: "https://inference.generativeai.us-chicago-1.oci.oraclecloud.com"
57+
region: "us-chicago-1"
58+
compartment_id: "GENAI_COMPARTMENT_OCID_GOES_HERE"
59+
chat_model_id: "GEN_AI_CHAT_MODEL_OCID_GOES_HERE"
60+
summarization_model_id: "GEN_AI_SUMMARIZATION_MODEL_OCID_GOES_HERE"
61+
```
62+
63+
Run the Spring Boot backend application in local profile:
2464
2565
```bash
26-
./gradlew bootRun
66+
./gradlew bootRun -Plocal
2767
```
2868

29-
## Build for distribution
30-
31-
## Build artifacts
69+
## Other tasks
3270

3371
### Build Java Application:
3472

backend/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ dependencies {
3030
implementation 'com.oracle.database.security:oraclepki:21.8.0.0'
3131
implementation 'com.oracle.database.security:osdt_cert:21.8.0.0'
3232
implementation 'com.oracle.database.security:osdt_core:21.8.0.0'
33+
implementation 'org.apache.pdfbox:pdfbox:3.0.2' exclude(group: 'commons-logging', module: 'commons-logging')
3334
testImplementation 'org.springframework.boot:spring-boot-starter-test'
3435
}
3536

backend/src/main/java/dev/victormartin/oci/genai/backend/backend/InvalidPromptRequest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@
55

66
@ResponseStatus(code = HttpStatus.BAD_REQUEST, reason = "Invalid request params")
77
public class InvalidPromptRequest extends RuntimeException {
8+
9+
810
}

backend/src/main/java/dev/victormartin/oci/genai/backend/backend/ClientConfigurationBean.java renamed to backend/src/main/java/dev/victormartin/oci/genai/backend/backend/config/ClientConfigurationBean.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package dev.victormartin.oci.genai.backend.backend;
1+
package dev.victormartin.oci.genai.backend.backend.config;
22

33
import com.oracle.bmc.ClientConfiguration;
44
import com.oracle.bmc.retrier.RetryConfiguration;

backend/src/main/java/dev/victormartin/oci/genai/backend/backend/GenerativeAiClientConfig.java renamed to backend/src/main/java/dev/victormartin/oci/genai/backend/backend/config/GenerativeAiClientConfig.java

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
package dev.victormartin.oci.genai.backend.backend;
1+
package dev.victormartin.oci.genai.backend.backend.config;
22

33
import com.oracle.bmc.ClientConfiguration;
44
import com.oracle.bmc.ConfigFileReader;
55
import com.oracle.bmc.Region;
66
import com.oracle.bmc.auth.AuthenticationDetailsProvider;
77
import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider;
8-
import com.oracle.bmc.auth.InstancePrincipalsAuthenticationDetailsProvider;
98
import com.oracle.bmc.auth.okeworkloadidentity.OkeWorkloadIdentityAuthenticationDetailsProvider;
109
import com.oracle.bmc.generativeai.GenerativeAiClient;
1110
import jakarta.annotation.PostConstruct;
@@ -39,8 +38,11 @@ public class GenerativeAiClientConfig {
3938
@Value("${genai.config.profile}")
4039
private String CONFIG_PROFILE;
4140

42-
@Value("${genai.model_id}")
43-
private String modelId;
41+
@Value("${genai.chat_model_id}")
42+
private String chatModelId;
43+
44+
@Value("${genai.summarization_model_id}")
45+
private String summarizationModelId;
4446

4547
private Region region;
4648

@@ -62,12 +64,11 @@ GenerativeAiClient genAiClient() throws IOException {
6264
}
6365

6466
GenerativeAiClient instancePrincipalConfig() throws IOException {
65-
final OkeWorkloadIdentityAuthenticationDetailsProvider okeProvider =
66-
new OkeWorkloadIdentityAuthenticationDetailsProvider
67-
.OkeWorkloadIdentityAuthenticationDetailsProviderBuilder()
68-
.build();
69-
// final InstancePrincipalsAuthenticationDetailsProvider provider =
70-
// new InstancePrincipalsAuthenticationDetailsProvider.InstancePrincipalsAuthenticationDetailsProviderBuilder().build();
67+
final OkeWorkloadIdentityAuthenticationDetailsProvider okeProvider = new OkeWorkloadIdentityAuthenticationDetailsProvider.OkeWorkloadIdentityAuthenticationDetailsProviderBuilder()
68+
.build();
69+
// final InstancePrincipalsAuthenticationDetailsProvider provider =
70+
// new
71+
// InstancePrincipalsAuthenticationDetailsProvider.InstancePrincipalsAuthenticationDetailsProviderBuilder().build();
7172

7273
GenerativeAiClient generativeAiClient = new GenerativeAiClient(okeProvider, clientConfiguration);
7374
generativeAiClient.setRegion(okeProvider.getRegion());
@@ -76,9 +77,11 @@ GenerativeAiClient instancePrincipalConfig() throws IOException {
7677
}
7778

7879
GenerativeAiClient localConfig() throws IOException {
79-
// Configuring the AuthenticationDetailsProvider. It's assuming there is a default OCI config file
80-
// "~/.oci/config", and a profile in that config with the name defined in CONFIG_PROFILE variable.
81-
final ConfigFileReader.ConfigFile configFile = ConfigFileReader.parse(CONFIG_LOCATION, CONFIG_PROFILE);
80+
// Configuring the AuthenticationDetailsProvider. It's assuming there is a
81+
// default OCI config file
82+
// "~/.oci/config", and a profile in that config with the name defined in
83+
// CONFIG_PROFILE variable.
84+
final ConfigFileReader.ConfigFile configFile = ConfigFileReader.parse(CONFIG_LOCATION, CONFIG_PROFILE);
8285
final AuthenticationDetailsProvider provider = new ConfigFileAuthenticationDetailsProvider(configFile);
8386

8487
GenerativeAiClient generativeAiClient = new GenerativeAiClient(provider,

backend/src/main/java/dev/victormartin/oci/genai/backend/backend/GenerativeAiInferenceClientConfig.java renamed to backend/src/main/java/dev/victormartin/oci/genai/backend/backend/config/GenerativeAiInferenceClientConfig.java

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package dev.victormartin.oci.genai.backend.backend;
1+
package dev.victormartin.oci.genai.backend.backend.config;
22

33
import com.oracle.bmc.ClientConfiguration;
44
import com.oracle.bmc.ConfigFileReader;
@@ -38,8 +38,11 @@ public class GenerativeAiInferenceClientConfig {
3838
@Value("${genai.config.profile}")
3939
private String CONFIG_PROFILE;
4040

41-
@Value("${genai.model_id}")
42-
private String modelId;
41+
@Value("${genai.chat_model_id}")
42+
private String modelChatId;
43+
44+
@Value("${genai.summarization_model_id}")
45+
private String modelSummarizationId;
4346

4447
private Region region;
4548

@@ -62,8 +65,8 @@ GenerativeAiInferenceClient genAiInferenceClient() throws IOException {
6265
}
6366

6467
GenerativeAiInferenceClient instancePrincipalConfig() throws IOException {
65-
final InstancePrincipalsAuthenticationDetailsProvider provider =
66-
new InstancePrincipalsAuthenticationDetailsProvider.InstancePrincipalsAuthenticationDetailsProviderBuilder().build();
68+
final InstancePrincipalsAuthenticationDetailsProvider provider = new InstancePrincipalsAuthenticationDetailsProvider.InstancePrincipalsAuthenticationDetailsProviderBuilder()
69+
.build();
6770

6871
GenerativeAiInferenceClient generativeAiInferenceClient = new GenerativeAiInferenceClient(provider,
6972
clientConfiguration);
@@ -73,12 +76,14 @@ GenerativeAiInferenceClient instancePrincipalConfig() throws IOException {
7376
}
7477

7578
GenerativeAiInferenceClient localConfig() throws IOException {
76-
// Configuring the AuthenticationDetailsProvider. It's assuming there is a default OCI config file
77-
// "~/.oci/config", and a profile in that config with the name defined in CONFIG_PROFILE variable.
78-
final ConfigFileReader.ConfigFile configFile = ConfigFileReader.parse(CONFIG_LOCATION, CONFIG_PROFILE);
79+
// Configuring the AuthenticationDetailsProvider. It's assuming there is a
80+
// default OCI config file
81+
// "~/.oci/config", and a profile in that config with the name defined in
82+
// CONFIG_PROFILE variable.
83+
final ConfigFileReader.ConfigFile configFile = ConfigFileReader.parse(CONFIG_LOCATION, CONFIG_PROFILE);
7984
final AuthenticationDetailsProvider provider = new ConfigFileAuthenticationDetailsProvider(configFile);
8085

81-
GenerativeAiInferenceClient generativeAiInferenceClient = new GenerativeAiInferenceClient(provider,
86+
GenerativeAiInferenceClient generativeAiInferenceClient = new GenerativeAiInferenceClient(provider,
8287
clientConfiguration);
8388
generativeAiInferenceClient.setEndpoint(ENDPOINT);
8489
generativeAiInferenceClient.setRegion(region);

backend/src/main/java/dev/victormartin/oci/genai/backend/backend/WebSocketConfig.java renamed to backend/src/main/java/dev/victormartin/oci/genai/backend/backend/config/WebSocketConfig.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package dev.victormartin.oci.genai.backend.backend;
1+
package dev.victormartin.oci.genai.backend.backend.config;
22

33
import org.springframework.context.annotation.Configuration;
44
import org.springframework.messaging.simp.config.MessageBrokerRegistry;

backend/src/main/java/dev/victormartin/oci/genai/backend/backend/GenAIController.java renamed to backend/src/main/java/dev/victormartin/oci/genai/backend/backend/controller/GenAIController.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
package dev.victormartin.oci.genai.backend.backend;
1+
package dev.victormartin.oci.genai.backend.backend.controller;
22

3-
import com.oracle.bmc.ClientConfiguration;
43
import com.oracle.bmc.generativeai.GenerativeAiClient;
54
import com.oracle.bmc.generativeai.model.ModelCapability;
65
import com.oracle.bmc.generativeai.requests.ListModelsRequest;
76
import com.oracle.bmc.generativeai.responses.ListModelsResponse;
87
import dev.victormartin.oci.genai.backend.backend.dao.GenAiModel;
9-
import org.bouncycastle.util.Objects;
108
import org.slf4j.Logger;
119
import org.slf4j.LoggerFactory;
1210
import org.springframework.beans.factory.annotation.Autowired;
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package dev.victormartin.oci.genai.backend.backend.controller;
2+
3+
4+
import dev.victormartin.oci.genai.backend.backend.service.OCIGenAIService;
5+
import dev.victormartin.oci.genai.backend.backend.service.PDFConvertorService;
6+
import org.slf4j.Logger;
7+
import org.slf4j.LoggerFactory;
8+
import org.springframework.beans.factory.annotation.Autowired;
9+
import org.springframework.beans.factory.annotation.Value;
10+
import org.springframework.util.StringUtils;
11+
import org.springframework.web.bind.annotation.PostMapping;
12+
import org.springframework.web.bind.annotation.RequestParam;
13+
import org.springframework.web.bind.annotation.RestController;
14+
import org.springframework.web.multipart.MaxUploadSizeExceededException;
15+
import org.springframework.web.multipart.MultipartFile;
16+
17+
import java.io.File;
18+
19+
@RestController
20+
public class PDFConvertorController {
21+
Logger log = LoggerFactory.getLogger(PDFConvertorController.class);
22+
23+
@Value("${storage.path}")
24+
String storagePath;
25+
26+
@Value("${genai.summarization_model_id}")
27+
String summarizationModelId;
28+
29+
@Autowired
30+
OCIGenAIService ociGenAIService;
31+
32+
@Autowired
33+
PDFConvertorService pdfConvertorService;
34+
35+
@Autowired
36+
SummaryController summaryController;
37+
38+
@PostMapping("/api/upload")
39+
public String fileUploading(@RequestParam("file") MultipartFile multipartFile) {
40+
String filename = StringUtils.cleanPath(multipartFile.getOriginalFilename());
41+
log.info("File uploaded {} {} bytes ({})", filename, multipartFile.getSize(), multipartFile.getContentType());
42+
try {
43+
if (filename.contains("..")) {
44+
throw new Exception("Filename contains invalid path sequence");
45+
}
46+
if (multipartFile.getBytes().length > (1024 * 1024)) {
47+
throw new Exception("File size exceeds maximum limit");
48+
}
49+
String fileDestinationPath = StringUtils.cleanPath(storagePath);
50+
File file = new File(fileDestinationPath + File.separator + filename);
51+
multipartFile.transferTo(file);
52+
log.info("File destination path: {}", file.getAbsolutePath());
53+
String convertedText = pdfConvertorService.convert(file.getAbsolutePath());
54+
String summaryText = ociGenAIService.summaryText(convertedText, summarizationModelId);
55+
log.info("Summary text: {}(...)", summaryText.substring(0, 40));
56+
summaryController.handleSummary(summaryText);
57+
return summaryText;
58+
} catch (MaxUploadSizeExceededException maxUploadSizeExceededException) {
59+
log.error(maxUploadSizeExceededException.getMessage());
60+
throw new RuntimeException(maxUploadSizeExceededException);
61+
} catch (Exception e) {
62+
log.error(e.getMessage());
63+
throw new RuntimeException(e);
64+
}
65+
}
66+
}

backend/src/main/java/dev/victormartin/oci/genai/backend/backend/PromptController.java renamed to backend/src/main/java/dev/victormartin/oci/genai/backend/backend/controller/PromptController.java

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
package dev.victormartin.oci.genai.backend.backend;
1+
package dev.victormartin.oci.genai.backend.backend.controller;
22

33
import com.oracle.bmc.model.BmcException;
4+
import dev.victormartin.oci.genai.backend.backend.InvalidPromptRequest;
5+
import dev.victormartin.oci.genai.backend.backend.service.OCIGenAIService;
46
import dev.victormartin.oci.genai.backend.backend.dao.Answer;
57
import dev.victormartin.oci.genai.backend.backend.dao.Prompt;
68
import dev.victormartin.oci.genai.backend.backend.data.Interaction;
@@ -21,14 +23,17 @@
2123
public class PromptController {
2224
Logger logger = LoggerFactory.getLogger(PromptController.class);
2325

24-
@Value("${genai.model_id}")
25-
private String hardcodedModelId;
26+
@Value("${genai.chat_model_id}")
27+
private String hardcodedChatModelId;
28+
29+
@Value("${genai.summarization_model_id}")
30+
private String hardcodedSummarizationModelId;
2631

2732
@Autowired
2833
private final InteractionRepository interactionRepository;
2934

3035
@Autowired
31-
OCIGenAIService genAI;
36+
OCIGenAIService genAI;
3237

3338
public PromptController(InteractionRepository interactionRepository, OCIGenAIService genAI) {
3439
this.interactionRepository = interactionRepository;
@@ -40,17 +45,21 @@ public PromptController(InteractionRepository interactionRepository, OCIGenAISer
4045
public Answer handlePrompt(Prompt prompt) {
4146
String promptEscaped = HtmlUtils.htmlEscape(prompt.content());
4247
logger.info("Prompt " + promptEscaped + " received, on model " + prompt.modelId() + " but using hardcoded one" +
43-
" " + hardcodedModelId);
48+
" " + hardcodedChatModelId);
4449
Interaction interaction = new Interaction();
4550
interaction.setConversationId(prompt.conversationId());
4651
interaction.setDatetimeRequest(new Date());
47-
interaction.setModelId(hardcodedModelId);
52+
interaction.setModelId(hardcodedChatModelId);
4853
interaction.setRequest(promptEscaped);
4954
Interaction saved = interactionRepository.save(interaction);
5055
try {
51-
if (prompt.content() == null || prompt.content().length()< 1) { throw new InvalidPromptRequest(); }
52-
// if (prompt.modelId() == null || !prompt.modelId().startsWith("ocid1.generativeaimodel.")) { throw new InvalidPromptRequest(); }
53-
String responseFromGenAI = genAI.request(promptEscaped, hardcodedModelId);
56+
if (prompt.content() == null || prompt.content().length() < 1) {
57+
throw new InvalidPromptRequest();
58+
}
59+
// if (prompt.modelId() == null ||
60+
// !prompt.modelId().startsWith("ocid1.generativeaimodel.")) { throw new
61+
// InvalidPromptRequest(); }
62+
String responseFromGenAI = genAI.request(promptEscaped, hardcodedChatModelId);
5463
saved.setDatetimeResponse(new Date());
5564
saved.setResponse(responseFromGenAI);
5665
interactionRepository.save(saved);
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package dev.victormartin.oci.genai.backend.backend.controller;
2+
3+
import com.oracle.bmc.model.BmcException;
4+
import dev.victormartin.oci.genai.backend.backend.InvalidPromptRequest;
5+
import dev.victormartin.oci.genai.backend.backend.dao.Answer;
6+
import dev.victormartin.oci.genai.backend.backend.dao.Prompt;
7+
import dev.victormartin.oci.genai.backend.backend.data.Interaction;
8+
import dev.victormartin.oci.genai.backend.backend.data.InteractionRepository;
9+
import dev.victormartin.oci.genai.backend.backend.service.OCIGenAIService;
10+
import org.slf4j.Logger;
11+
import org.slf4j.LoggerFactory;
12+
import org.springframework.beans.factory.annotation.Autowired;
13+
import org.springframework.beans.factory.annotation.Value;
14+
import org.springframework.http.HttpStatus;
15+
import org.springframework.messaging.handler.annotation.MessageMapping;
16+
import org.springframework.messaging.simp.annotation.SendToUser;
17+
import org.springframework.messaging.simp.annotation.SubscribeMapping;
18+
import org.springframework.stereotype.Controller;
19+
import org.springframework.web.util.HtmlUtils;
20+
21+
import java.util.Date;
22+
23+
@Controller
24+
public class SummaryController {
25+
Logger logger = LoggerFactory.getLogger(SummaryController.class);
26+
27+
@SendToUser("/queue/summary")
28+
public Answer handleSummary(String summary) {
29+
logger.info("handleSummary");
30+
return new Answer(summary , "");
31+
}
32+
33+
}

0 commit comments

Comments
 (0)