Java: feat(): add PostChatCompletionEvent (#5342)

### Motivation and Context

Fix:https://github.com/microsoft/semantic-kernel/issues/5314

### Description

After the Chat Completion, triggered an PostChatCompletionEvent.

### Contribution Checklist

<!-- Before submitting this PR, please make sure: -->

- [x] The code builds clean without any errors or warnings
- [x] The PR follows the [SK Contribution
Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md)
and the [pre-submission formatting
script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts)
raises no violations
- [x] All unit tests pass, and I have added new tests where possible
- [x] I didn't break anyone 😄

---------

Co-authored-by: gaozhirong <[email protected]>
This commit is contained in:
calm
2024-03-08 11:47:30 -05:00
committed by GitHub
co-authored by gaozhirong
parent ac97fea4c0
commit 622b720d06
5 changed files with 72 additions and 0 deletions
@@ -25,6 +25,7 @@ import com.microsoft.semantickernel.contextvariables.ContextVariableTypes;
import com.microsoft.semantickernel.exceptions.AIException;
import com.microsoft.semantickernel.exceptions.SKException;
import com.microsoft.semantickernel.hooks.KernelHooks;
import com.microsoft.semantickernel.hooks.PostChatCompletionEvent;
import com.microsoft.semantickernel.hooks.PreChatCompletionEvent;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.FunctionResultMetadata;
@@ -154,6 +155,9 @@ public class OpenAIChatCompletion implements ChatCompletionService {
.filter(Objects::nonNull)
.collect(Collectors.toList());
// execute post chat completion hook
kernelHooks.executeHooks(new PostChatCompletionEvent(completions));
// Just return the result:
// If we don't want to attempt to invoke any functions
// Or if we are auto-invoking, but we somehow end up with other than 1 choice even though only 1 was requested
@@ -19,6 +19,7 @@ import com.microsoft.semantickernel.hooks.KernelHook.PreChatCompletionHook;
import com.microsoft.semantickernel.hooks.KernelHook.PromptRenderedHook;
import com.microsoft.semantickernel.hooks.KernelHook.PromptRenderingHook;
import com.microsoft.semantickernel.hooks.KernelHooks;
import com.microsoft.semantickernel.hooks.PostChatCompletionEvent;
import com.microsoft.semantickernel.hooks.PreChatCompletionEvent;
import com.microsoft.semantickernel.hooks.PromptRenderedEvent;
import com.microsoft.semantickernel.orchestration.FunctionResult;
@@ -347,6 +348,12 @@ public class Example57_KernelHooks {
PreChatCompletionHook.cloneOptionsWithMessages(options, messages));
});
kernel.getGlobalKernelHooks().addPostChatCompletionHook(event -> {
System.out.println("Chat completion");
System.out.println("Id: " + event.getChatCompletions().getId());
return event;
});
try {
// Invoke prompt to trigger execution hooks.
var result = kernel.invokeAsync(writerFunction)
@@ -118,4 +118,17 @@ public interface KernelHook<T extends KernelHookEvent> extends Predicate<KernelH
return PreChatCompletionEvent.class.isAssignableFrom(arguments.getClass());
}
}
/**
* A hook that accepts {@link PostChatCompletionEvent}
*/
interface PostChatCompletionHook extends KernelHook<PostChatCompletionEvent> {
@Override
default boolean test(KernelHookEvent arguments) {
return PostChatCompletionEvent.class.isAssignableFrom(arguments.getClass());
}
}
}
@@ -3,6 +3,7 @@ package com.microsoft.semantickernel.hooks;
import com.microsoft.semantickernel.hooks.KernelHook.FunctionInvokedHook;
import com.microsoft.semantickernel.hooks.KernelHook.FunctionInvokingHook;
import com.microsoft.semantickernel.hooks.KernelHook.PostChatCompletionHook;
import com.microsoft.semantickernel.hooks.KernelHook.PreChatCompletionHook;
import com.microsoft.semantickernel.hooks.KernelHook.PromptRenderedHook;
import com.microsoft.semantickernel.hooks.KernelHook.PromptRenderingHook;
@@ -101,6 +102,17 @@ public class KernelHooks {
return addHook((PreChatCompletionHook) function::apply);
}
/**
* Add a {@link PostChatCompletionEvent} to the collection of hooks.
*
* @param function the function to add
* @return the key of the hook in the collection
*/
public String addPostChatCompletionHook(
Function<PostChatCompletionEvent, PostChatCompletionEvent> function) {
return addHook((PostChatCompletionHook) function::apply);
}
/**
* Add a {@link PromptRenderedHook} to the collection of hooks.
*
@@ -227,6 +239,12 @@ public class KernelHooks {
throw new UnsupportedOperationException("unmodifiable instance of KernelHooks");
}
@Override
public String addPostChatCompletionHook(
Function<PostChatCompletionEvent, PostChatCompletionEvent> function) {
throw new UnsupportedOperationException("unmodifiable instance of KernelHooks");
}
@Override
public String addPromptRenderedHook(
Function<PromptRenderedEvent, PromptRenderedEvent> function) {
@@ -0,0 +1,30 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.hooks;
import com.azure.ai.openai.models.ChatCompletions;
/**
* Represents a KernelHookEvent that is raised after a chat completion is invoked.
*/
public class PostChatCompletionEvent implements KernelHookEvent {
private final ChatCompletions chatCompletions;
/**
* Creates a new instance of the {@link PostChatCompletionEvent} class.
*
* @param chatCompletions the chat completions
*/
public PostChatCompletionEvent(ChatCompletions chatCompletions) {
this.chatCompletions = chatCompletions;
}
/**
* Gets the chat completions.
*
* @return the chat completions
*/
public ChatCompletions getChatCompletions() {
return chatCompletions;
}
}