Skip to content

Commit 1f1d9a2

Browse files
OCI GenAI (#43)
* OCI GenAI Signed-off-by: Anders Swanson <anders.swanson@oracle.com>
1 parent 1419f40 commit 1f1d9a2

File tree

33 files changed

+1394
-0
lines changed

33 files changed

+1394
-0
lines changed

docs/src/main/asciidoc/genai.adoc

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Copyright (c) 2024, Oracle and/or its affiliates.
2+
// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
3+
4+
[#cloud-genai]
5+
== Generative AI
6+
7+
https://docs.oracle.com/en-us/iaas/Content/generative-ai/home.htm[OCI Generative AI] is a fully managed service that provides a set of state-of-the-art, customizable large language models (LLMs) that cover a wide range of use cases, including chat and creating text embeddings.
8+
9+
Maven coordinates, using <<getting-started.adoc#bill-of-materials, Spring Cloud OCI BOM>>:
10+
11+
[source,xml]
12+
----
13+
<dependency>
14+
<groupId>com.oracle.cloud.spring</groupId>
15+
<artifactId>spring-cloud-oci-starter-gen-ai</artifactId>
16+
</dependency>
17+
----
18+
19+
Gradle coordinates:
20+
21+
[source,subs="normal"]
22+
----
23+
dependencies {
24+
implementation("com.oracle.cloud.spring:spring-cloud-oci-starter-gen-ai")
25+
}
26+
----
27+
28+
=== Using Generative AI Chat
29+
30+
The starter configures and registers a `ChatModel` bean in the Spring application context.
31+
The `ChatModel` bean (link[Javadoc]) can be used to interact with OCI Generative AI Chat Models.
32+
33+
[source,java]
34+
----
35+
@Autowired
36+
@Autowired
37+
private ChatModel chatModel;
38+
39+
public void embed() {
40+
ChatResponse response = chatModel.chat("my chat prompt");
41+
}
42+
----
43+
44+
=== Using Generative AI Embedding
45+
46+
The starter configures and registers an `EmbeddingModel` bean in the Spring application context.
47+
The `EmbeddingModel` bean (link[Javadoc]) can be used to create text embeddings using OCI Generative AI Embedding Models.
48+
49+
[source,java]
50+
----
51+
@Autowired
52+
private EmbeddingModel embeddingModel;
53+
54+
public void embed() {
55+
EmbedTextResponse response = embeddingModel.embed("my embedding text");
56+
}
57+
----
58+
59+
=== Configuration
60+
61+
The Spring Boot Starter for Oracle Cloud Generative AI provides the following configuration options:
62+
63+
|===
64+
^| Name ^| Description ^| Required ^| Default value
65+
| `spring.cloud.oci.genai.enabled` | Enables the OCI Generative AI Client. | No | `true`
66+
| `spring.cloud.oci.genai.embedding.enabled` | Enables the OCI Generative AI Embedding APIs. | No | `false`
67+
| `spring.cloud.oci.genai.embedding.on-demand-model-id` | On-demand model ID to be used for embedding text. One of `spring.cloud.oci.genai.embedding.dedicated-cluster-endpoint` or `spring.cloud.oci.genai.embedding.on-demand-model-id` must be specified | No |
68+
| `spring.cloud.oci.genai.embedding.dedicated-cluster-endpoint` | Dedicated cluster endpoint used for embedding text. One of `spring.cloud.oci.genai.embedding.dedicated-cluster-endpoint` or `spring.cloud.oci.genai.embedding.on-demand-model-id` must be specified. | No |
69+
| `spring.cloud.oci.genai.embedding.compartment` | Embedding model compartment. | Yes |
70+
| `spring.cloud.oci.genai.embedding.truncate` | How to truncate embedding text when it is greater than the model's maximum tokens. May be `START`, `END`, or `NONE`. | No | `NONE`
71+
| `spring.cloud.oci.genai.chat.enabled` | Enables the OCI Generative AI Chat APIs. | No | `false`
72+
| `spring.cloud.oci.genai.chat.on-demand-model-id` | On-demand model ID to be used for chat. One of `spring.cloud.oci.genai.chat.dedicated-cluster-endpoint` or `spring.cloud.oci.genai.chat.on-demand-model-id` must be specified | No |
73+
| `spring.cloud.oci.genai.chat.dedicated-cluster-endpoint` | Dedicated cluster endpoint used for chat. One of `spring.cloud.oci.genai.chat.dedicated-cluster-endpoint` or `spring.cloud.oci.genai.chat.on-demand-model-id` must be specified. | No |
74+
| `spring.cloud.oci.genai.chat.compartment` | Chat model compartment. | Yes |
75+
| `spring.cloud.oci.genai.chat.preample-override` | If specified, overrides the model's prompt preamble. | No |
76+
| `spring.cloud.oci.genai.chat.temperature` | Chat text generation temperature. Higher values are more random or creative. Learn more about https://docs.oracle.com/en-us/iaas/Content/generative-ai/concepts.htm#temperature[temperature]. | No | `1.0`
77+
| `spring.cloud.oci.genai.chat.top-p` | Ensures that only the most likely tokens with probabilities that sum to P are generated. Learn more about https://docs.oracle.com/en-us/iaas/Content/generative-ai/concepts.htm#top-p[Top P]. | No | `0.75`
78+
| `spring.cloud.oci.genai.chat.top-k` | Ensures that only the top K most probably tokens are considered in each step of text generation. Learn more about https://docs.oracle.com/en-us/iaas/Content/generative-ai/concepts.htm#top-k[Top K]. | No | `0.0`
79+
| `spring.cloud.oci.genai.chat.frequency-penalty` | Assigns a penalty for tokens that appear frequently. A higher value results in less repetitive text. | No | `0.0`
80+
| `spring.cloud.oci.genai.chat.presence-penalty` | Assigns an equal penalty if a token appears in the text. A higher value results in less reptitive text. | No | `0.0`
81+
| `spring.cloud.oci.genai.chat.max-tokens` | Maximum response output tokens. Estimate 2-3 tokens per word. | No | `600`
82+
83+
|===
84+
85+
86+
=== Sample
87+
88+
A sample application provided https://github.com/oracle/spring-cloud-oci/tree/main/spring-cloud-oci-samples/spring-cloud-oci-gen-ai-sample[here] contains the examples to demonstrates the usage of OCI Spring Cloud Generative AI module.

docs/src/main/asciidoc/getting-started.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ The following table highlights several samples of the most used integrations in
6464
| Cloud Notification
6565
| https://github.com/oracle/spring-cloud-oci/tree/main/spring-cloud-oci-samples/spring-cloud-oci-notification-sample[spring-cloud-oci-notification-sample]
6666

67+
| Cloud Generative AI
68+
| https://github.com/oracle/spring-cloud-oci/tree/main/spring-cloud-oci-samples/spring-cloud-oci-gen-ai-sample[spring-cloud-oci-gen-ai-sample]
69+
6770
| Cloud Logging
6871
| https://github.com/oracle/spring-cloud-oci/tree/main/spring-cloud-oci-samples/spring-cloud-oci-logging-sample[spring-cloud-oci-logging-sample]
6972

docs/src/main/asciidoc/index.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ include::storage.adoc[]
2222

2323
include::notifications.adoc[]
2424

25+
include::genai.adoc[]
26+
2527
include::logging.adoc[]
2628

2729
include::function.adoc[]

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ Licensed under the Universal Permissive License v 1.0 as shown at https://oss.or
5353
<module>spring-cloud-oci-starters</module>
5454
<module>spring-cloud-oci-storage</module>
5555
<module>spring-cloud-oci-notification</module>
56+
<module>spring-cloud-oci-gen-ai</module>
5657
<module>spring-cloud-oci-logging</module>
5758
<module>spring-cloud-oci-function</module>
5859
<module>spring-cloud-oci-streaming</module>

spring-cloud-oci-autoconfigure/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ Licensed under the Universal Permissive License v 1.0 as shown at https://oss.or
7979
<artifactId>spring-cloud-oci-notification</artifactId>
8080
<optional>true</optional>
8181
</dependency>
82+
<dependency>
83+
<groupId>com.oracle.cloud.spring</groupId>
84+
<artifactId>spring-cloud-oci-gen-ai</artifactId>
85+
<optional>true</optional>
86+
</dependency>
8287
<dependency>
8388
<groupId>com.oracle.cloud.spring</groupId>
8489
<artifactId>spring-cloud-oci-logging</artifactId>
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
** Copyright (c) 2024, Oracle and/or its affiliates.
3+
** Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
4+
*/
5+
6+
package com.oracle.cloud.spring.genai;
7+
8+
import com.oracle.bmc.auth.RegionProvider;
9+
import com.oracle.bmc.generativeaiinference.GenerativeAiInference;
10+
import com.oracle.bmc.generativeaiinference.GenerativeAiInferenceClient;
11+
import com.oracle.bmc.generativeaiinference.model.DedicatedServingMode;
12+
import com.oracle.bmc.generativeaiinference.model.EmbedTextDetails;
13+
import com.oracle.bmc.generativeaiinference.model.OnDemandServingMode;
14+
import com.oracle.bmc.generativeaiinference.model.ServingMode;
15+
import com.oracle.cloud.spring.autoconfigure.core.CredentialsProvider;
16+
import org.springframework.beans.factory.annotation.Qualifier;
17+
import org.springframework.boot.autoconfigure.AutoConfiguration;
18+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
19+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
20+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
21+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
22+
import org.springframework.cloud.context.config.annotation.RefreshScope;
23+
import org.springframework.context.annotation.Bean;
24+
import org.springframework.util.StringUtils;
25+
26+
import static com.oracle.cloud.spring.autoconfigure.core.CredentialsProviderAutoConfiguration.credentialsProviderQualifier;
27+
import static com.oracle.cloud.spring.autoconfigure.core.RegionProviderAutoConfiguration.regionProviderQualifier;
28+
29+
/**
30+
* Auto-configuration for initializing the OCI GenAI component.
31+
* Depends on {@link com.oracle.cloud.spring.autoconfigure.core.CredentialsProviderAutoConfiguration} and
32+
* {@link com.oracle.cloud.spring.autoconfigure.core.RegionProviderAutoConfiguration}
33+
* for loading the Authentication configuration
34+
*
35+
* @see ChatModel
36+
* @see EmbeddingModel
37+
*/
38+
@AutoConfiguration
39+
@ConditionalOnClass({ChatModel.class})
40+
@EnableConfigurationProperties(GenAIProperties.class)
41+
@ConditionalOnProperty(name = "spring.cloud.oci.genai.enabled", havingValue = "true", matchIfMissing = true)
42+
public class GenAIAutoConfiguration {
43+
private final GenAIProperties properties;
44+
45+
public GenAIAutoConfiguration(GenAIProperties properties) {
46+
this.properties = properties;
47+
}
48+
49+
@Bean
50+
@RefreshScope
51+
@ConditionalOnProperty(name = "spring.cloud.oci.genai.embedding.enabled", havingValue = "true", matchIfMissing = true)
52+
@ConditionalOnMissingBean(EmbeddingModel.class)
53+
public EmbeddingModel embeddingModel(GenerativeAiInference generativeAiInference) {
54+
GenAIProperties.Embedding embedding = properties.getEmbedding();
55+
return EmbeddingModelImpl.builder()
56+
.client(generativeAiInference)
57+
.truncate(StringUtils.hasText(embedding.getTruncate()) ?
58+
EmbedTextDetails.Truncate.valueOf(embedding.getTruncate()) :
59+
EmbedTextDetails.Truncate.None)
60+
.compartment(embedding.getCompartment())
61+
.servingMode(servingMode(embedding.getOnDemandModelId(), embedding.getDedicatedClusterEndpoint()))
62+
.build();
63+
}
64+
65+
@Bean
66+
@RefreshScope
67+
@ConditionalOnProperty(name = "spring.cloud.oci.genai.chat.enabled", havingValue = "true", matchIfMissing = true)
68+
@ConditionalOnMissingBean(ChatModel.class)
69+
public ChatModel chatModel(GenerativeAiInference generativeAiInference) {
70+
GenAIProperties.Chat chat = properties.getChat();
71+
return ChatModelImpl.builder()
72+
.client(generativeAiInference)
73+
.preambleOverride(chat.getPreambleOverride())
74+
.inferenceRequestType(chat.getInferenceRequestType())
75+
.servingMode(servingMode(chat.getOnDemandModelId(), chat.getDedicatedClusterEndpoint()))
76+
.topK(chat.getTopK())
77+
.topP(chat.getTopP())
78+
.compartment(chat.getCompartment())
79+
.frequencyPenalty(chat.getFrequencyPenalty())
80+
.presencePenalty(chat.getPresencePenalty())
81+
.temperature(chat.getTemperature())
82+
.build();
83+
}
84+
85+
@Bean
86+
@RefreshScope
87+
@ConditionalOnMissingBean
88+
GenerativeAiInference genAIClient(@Qualifier(regionProviderQualifier) RegionProvider regionProvider,
89+
@Qualifier(credentialsProviderQualifier)
90+
CredentialsProvider cp) {
91+
GenerativeAiInference generativeAiInference = GenerativeAiInferenceClient.builder()
92+
.build(cp.getAuthenticationDetailsProvider());
93+
if (regionProvider.getRegion() != null) {
94+
generativeAiInference.setRegion(regionProvider.getRegion());
95+
}
96+
return generativeAiInference;
97+
}
98+
99+
private ServingMode servingMode(String onDemandModelId, String dedicatedClusterEndpoint) {
100+
if (StringUtils.hasText(onDemandModelId)) {
101+
return OnDemandServingMode.builder().modelId(onDemandModelId).build();
102+
} else if (StringUtils.hasText(dedicatedClusterEndpoint)) {
103+
return DedicatedServingMode.builder().endpointId(dedicatedClusterEndpoint).build();
104+
}
105+
throw new IllegalArgumentException("One of spring.cloud.oci.genai.embedding.onDemandModelId or spring.cloud.oci.genai.embedding.dedicatedClusterEndpoint must be specified.");
106+
}
107+
}

0 commit comments

Comments
 (0)