Java: Add Example44_MultiChatCompletion (#4725)

Add Example44_MultiChatCompletion
This commit is contained in:
Milder Hernandez
2024-01-24 13:55:24 -05:00
committed by GitHub
parent ec10bf18af
commit 300efbe54e
5 changed files with 103 additions and 2 deletions
@@ -19,12 +19,12 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.aiservices.openai.textcompletion.OpenAITextGenerationService;
import com.microsoft.semantickernel.chatcompletion.AuthorRole;
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.chatcompletion.ChatHistory;
import com.microsoft.semantickernel.chatcompletion.ChatMessageContent;
import com.microsoft.semantickernel.chatcompletion.StreamingChatMessageContent;
import com.microsoft.semantickernel.exceptions.AIException;
import com.microsoft.semantickernel.orchestration.FunctionResultMetadata;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
@@ -266,6 +266,10 @@ public class OpenAIChatCompletion implements ChatCompletionService {
if (promptExecutionSettings == null) {
return options;
}
if (promptExecutionSettings.getResultsPerPrompt() < 1
|| promptExecutionSettings.getResultsPerPrompt() > MAX_RESULTS_PER_PROMPT) {
throw new AIException(AIException.ErrorCodes.INVALID_REQUEST, String.format("Results per prompt must be in range between 1 and %d, inclusive.", MAX_RESULTS_PER_PROMPT));
}
Map<String, Integer> logit = null;
if (promptExecutionSettings.getTokenSelectionBiases() != null) {
@@ -286,6 +290,7 @@ public class OpenAIChatCompletion implements ChatCompletionService {
.setFrequencyPenalty(promptExecutionSettings.getFrequencyPenalty())
.setPresencePenalty(promptExecutionSettings.getPresencePenalty())
.setMaxTokens(promptExecutionSettings.getMaxTokens())
.setN(promptExecutionSettings.getResultsPerPrompt())
// Azure OpenAI WithData API does not allow to send empty array of stop sequences
// Gives back "Validation error at #/stop/str: Input should be a valid string\nValidation error at #/stop/list[str]: List should have at least 1 item after validation, not 0"
.setStop(promptExecutionSettings.getStopSequences() == null
@@ -126,6 +126,10 @@ public class OpenAITextGenerationService implements TextGenerationService {
if (requestSettings.getMaxTokens() < 1) {
throw new AIException(AIException.ErrorCodes.INVALID_REQUEST, "Max tokens must be >0");
}
if (requestSettings.getResultsPerPrompt() < 1
|| requestSettings.getResultsPerPrompt() > MAX_RESULTS_PER_PROMPT) {
throw new AIException(AIException.ErrorCodes.INVALID_REQUEST, String.format("Results per prompt must be in range between 1 and %d, inclusive.", MAX_RESULTS_PER_PROMPT));
}
CompletionsOptions options =
new CompletionsOptions(Collections.singletonList(text))
@@ -135,6 +139,7 @@ public class OpenAITextGenerationService implements TextGenerationService {
.setFrequencyPenalty(requestSettings.getFrequencyPenalty())
.setPresencePenalty(requestSettings.getPresencePenalty())
.setModel(getModelId())
.setN(requestSettings.getResultsPerPrompt())
.setUser(requestSettings.getUser())
.setBestOf(requestSettings.getBestOf())
.setLogitBias(new HashMap<>());
@@ -0,0 +1,76 @@
package com.microsoft.semantickernel.samples.syntaxexamples;
import com.azure.ai.openai.OpenAIAsyncClient;
import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.credential.KeyCredential;
import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion;
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.chatcompletion.ChatHistory;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
public class Example44_MultiChatCompletion {
private static final String CLIENT_KEY = System.getenv("CLIENT_KEY");
private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY");
// Only required if AZURE_CLIENT_KEY is set
private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT");
private static final String MODEL_ID = System.getenv()
.getOrDefault("MODEL_ID", "gpt-35-turbo");
public static void main(String[] args) {
System.out.println("======== Open AI - Multiple Chat Completion ========");
OpenAIAsyncClient client;
if (AZURE_CLIENT_KEY != null) {
client = new OpenAIClientBuilder()
.credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
.endpoint(CLIENT_ENDPOINT)
.buildAsyncClient();
} else {
client = new OpenAIClientBuilder()
.credential(new KeyCredential(CLIENT_KEY))
.buildAsyncClient();
}
ChatCompletionService chatGPT = OpenAIChatCompletion.builder()
.withModelId(MODEL_ID)
.withOpenAIAsyncClient(client)
.build();
System.out.println("Chat content:");
System.out.println("------------------------");
ChatHistory chatHistory = new ChatHistory("You are a librarian, expert about books");
var executionSettings = PromptExecutionSettings.builder()
.withMaxTokens(1024)
.withTemperature(1)
.withResultsPerPrompt(2)
.build();
chatHistory.addUserMessage("Hi, I'm looking for 3 different book suggestions about sci-fi");
messageOutput(chatHistory);
GPTReply(chatGPT, chatHistory, executionSettings);
}
private static void messageOutput(ChatHistory chatHistory) {
var message = chatHistory.getLastMessage().get();
System.out.println(message.getAuthorRole() + ": " + message.getContent());
System.out.println("------------------------");
}
private static void GPTReply(ChatCompletionService chatGPT, ChatHistory chatHistory,
PromptExecutionSettings settings) {
var reply = chatGPT.getChatMessageContentsAsync(chatHistory, settings, null)
.block();
reply.forEach(chatMessageContent -> {
chatHistory.addAssistantMessage(chatMessageContent.getContent());
messageOutput(chatHistory);
});
}
}
@@ -5,5 +5,5 @@ package com.microsoft.semantickernel;
* Marker interface for Text AI services, typically Chat or Text generation for OpenAI
*/
public interface TextAIService extends AIService {
int MAX_RESULTS_PER_PROMPT = 128;
}
@@ -13,6 +13,7 @@ public class PromptExecutionSettings {
public static final double DEFAULT_PRESENCE_PENALTY = 0.0;
public static final double DEFAULT_FREQUENCY_PENALTY = 0.0;
public static final int DEFAULT_BEST_OF = 1;
public static final int DEFAULT_RESULTS_PER_PROMPT = 1;
/// <summary>
/// Service identifier.
@@ -33,6 +34,7 @@ public class PromptExecutionSettings {
private final double frequencyPenalty;
private final int maxTokens;
private final int bestOf;
private final int resultsPerPrompt;
private final String user;
private final List<String> stopSequences;
@@ -49,6 +51,7 @@ public class PromptExecutionSettings {
@JsonProperty("presence_penalty") double presencePenalty,
@JsonProperty("frequency_penalty") double frequencyPenalty,
@JsonProperty("max_tokens") int maxTokens,
@JsonProperty("results_per_prompt") int resultsPerPrompt,
@JsonProperty("best_of") int bestOf,
@JsonProperty("user") String user,
@JsonProperty(value = "stop_sequences") List<String> stopSequences,
@@ -60,6 +63,7 @@ public class PromptExecutionSettings {
this.presencePenalty = presencePenalty;
this.frequencyPenalty = frequencyPenalty;
this.maxTokens = maxTokens;
this.resultsPerPrompt = resultsPerPrompt;
this.bestOf = bestOf;
this.user = user;
this.stopSequences = stopSequences;
@@ -94,6 +98,10 @@ public class PromptExecutionSettings {
return maxTokens;
}
public int getResultsPerPrompt() {
return resultsPerPrompt;
}
public int getBestOf() {
// TODO: not present in com.azure:azure-ai-openai
return bestOf;
@@ -125,6 +133,7 @@ public class PromptExecutionSettings {
private double presencePenalty = Double.NaN;
private double frequencyPenalty = Double.NaN;
private int maxTokens = Integer.MIN_VALUE;
private int resultsPerPrompt = Integer.MIN_VALUE;
private int bestOf = Integer.MIN_VALUE;
private String user;
private List<String> stopSequences;
@@ -165,6 +174,11 @@ public class PromptExecutionSettings {
return this;
}
public Builder withResultsPerPrompt(int resultsPerPrompt) {
this.resultsPerPrompt = resultsPerPrompt;
return this;
}
public Builder withBestOf(int bestOf) {
this.bestOf = bestOf;
return this;
@@ -194,6 +208,7 @@ public class PromptExecutionSettings {
Double.isNaN(presencePenalty) ? DEFAULT_PRESENCE_PENALTY : presencePenalty,
Double.isNaN(frequencyPenalty) ? DEFAULT_FREQUENCY_PENALTY : frequencyPenalty,
maxTokens == Integer.MIN_VALUE ? DEFAULT_MAX_TOKENS : maxTokens,
resultsPerPrompt == Integer.MIN_VALUE ? DEFAULT_RESULTS_PER_PROMPT : resultsPerPrompt,
bestOf == Integer.MIN_VALUE ? DEFAULT_BEST_OF : bestOf,
user,
stopSequences,