mirror of
https://github.com/microsoft/semantic-kernel.git
synced 2026-10-12 02:19:06 +00:00
Java: Migrate java code to new repository (#7460)
### Motivation and Context <!-- Thank you for your contribution to the semantic-kernel repo! Please help reviewers and future users, providing the following information: 1. Why is this change required? 2. What problem does it solve? 3. What scenario does it contribute to? 4. If it fixes an open issue, please link to the issue here. --> ### Description <!-- Describe your changes, the overall approach, the underlying design. These notes will help understanding how your code works. Thanks! --> ### Contribution Checklist <!-- Before submitting this PR, please make sure: --> - [ ] The code builds clean without any errors or warnings - [ ] 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 - [ ] All unit tests pass, and I have added new tests where possible - [ ] I didn't break anyone 😄 Co-authored-by: Bruno Borges <[email protected]>
This commit is contained in:
co-authored by
Bruno Borges
parent
430dd8d66b
commit
d3172f8f36
@@ -1,10 +0,0 @@
|
||||
--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
|
||||
--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
|
||||
--add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED
|
||||
--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED
|
||||
--add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
|
||||
--add-exports jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED
|
||||
--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED
|
||||
--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
|
||||
--add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED
|
||||
--add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
|
||||
@@ -1,29 +0,0 @@
|
||||
# 1.1.3
|
||||
|
||||
- Fix bug appending plugin name to tool calls
|
||||
- Improve exception handling in OpenAIChatCompletion
|
||||
|
||||
# 1.1.2
|
||||
|
||||
- Upgrade azure-identity to 1.12.1
|
||||
- Remove fixed netty version in bom
|
||||
|
||||
# 1.1.1
|
||||
|
||||
- Upgrade azure-ai-openai to 1.0.0-beta.8
|
||||
|
||||
# 1.1.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- `ChatHistory` no longer has a default message, see below for more details.
|
||||
|
||||
### Api Changes
|
||||
- Allow setting deployment name in addition to modelId on AI services.
|
||||
- Remove default message of "Assistant is a large language model" from ChatHistory
|
||||
- **This is a breaking change if you were relying on the default message in your code**
|
||||
- Add InvocationReturnMode and rework OpenAi chat completion to allow configuring what data is returned from Chat requests
|
||||
|
||||
### Other
|
||||
- Reorganize example projects and documentation structure.
|
||||
- Number of sample updates and bug fixes.
|
||||
@@ -1,76 +0,0 @@
|
||||
# Semantic Kernel for Java Packages
|
||||
|
||||
The Semantic Kernel has the packages below, all are under the groupId `com.microsoft.semantic-kernel`, and can be imported
|
||||
to maven.
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-api</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
A BOM is provided that can be used to define the versions of all Semantic Kernel packages.
|
||||
|
||||
```xml
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-bom</artifactId>
|
||||
<version>${semantickernel.version}</version>
|
||||
<scope>import</scope>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
```
|
||||
|
||||
## Common Packages
|
||||
|
||||
`semantickernel-bom`
|
||||
: A Maven project BOM that can be used to define the versions of all Semantic Kernel packages.
|
||||
|
||||
`semantickernel-api`
|
||||
: Package that defines the core public API for the Semantic Kernel for a Maven project.
|
||||
|
||||
## Services
|
||||
|
||||
`semantickernel-aiservices-openai`
|
||||
: Provides a connector that can be used to interact with the OpenAI API.
|
||||
|
||||
## Example Configurations
|
||||
|
||||
### Example: OpenAI + SQLite
|
||||
|
||||
POM XML for a simple project that uses OpenAI.
|
||||
|
||||
```xml
|
||||
|
||||
<project>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-bom</artifactId>
|
||||
<version>${semantickernel.version}</version>
|
||||
<scope>import</scope>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-connectors-ai-openai</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
```
|
||||
|
||||
|
||||
|
||||
+5
-115
@@ -1,118 +1,8 @@
|
||||
# Semantic Kernel for Java
|
||||
|
||||
Semantic Kernel (SK) is a lightweight foundation that lets you easily mix conventional programming languages with the
|
||||
latest in
|
||||
Large Language Model (LLM) AI "prompts" with templating, chaining, and planning capabilities out-of-the-box.
|
||||
The Semantic Kernel for Java code has moved
|
||||
to [semantic-kernel-java](https://github.com/microsoft/semantic-kernel-java), please make code changes and submit issues
|
||||
to that repository. This move is purely to ease the development. The various Semantic Kernel languages are all still
|
||||
aligned in their development.
|
||||
|
||||
To learn more about Microsoft Semantic Kernel, visit
|
||||
the [Microsoft Semantic Kernel documentation](https://learn.microsoft.com/en-us/semantic-kernel/whatissk).
|
||||
|
||||
The Microsoft Semantic Kernel for Java is a library that implements the key concepts and foundations of Microsoft
|
||||
Semantic Kernel. It is designed
|
||||
to be used in Java applications in both client (desktop, mobile, CLIs) and server environments in an idiomatic way, and
|
||||
to be easily integrated with other Java libraries
|
||||
and frameworks.
|
||||
|
||||
## Quickstart
|
||||
|
||||
To get an idea of how to use the Semantic Kernel for Java, you can check
|
||||
the [syntax-examples](samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples) folder for
|
||||
examples of common AI-enabled scenarios.
|
||||
|
||||
## Get started
|
||||
|
||||
To run the LLM prompts and semantic functions in this kernel, make sure you have
|
||||
an [Open AI API Key](https://platform.openai.com/)
|
||||
or [Azure Open AI service key](https://learn.microsoft.com/azure/cognitive-services/openai/).
|
||||
|
||||
### Requirements
|
||||
|
||||
To build the Semantic Kernel for Java, you will need:
|
||||
|
||||
- **Required**:
|
||||
- [OpenJDK 17](https://microsoft.com/openjdk/) or newer
|
||||
|
||||
### Build the Semantic Kernel
|
||||
|
||||
1. Clone this repository
|
||||
|
||||
git clone -b java-v1 https://github.com/microsoft/semantic-kernel/
|
||||
|
||||
2. Build the project with the Maven Wrapper
|
||||
|
||||
cd semantic-kernel/java
|
||||
./mvnw install
|
||||
|
||||
3. (Optional) To run a FULL build including static analysis and end-to-end tests that might require a valid OpenAI key,
|
||||
run the following command:
|
||||
|
||||
./mvnw clean install -Prelease,bug-check,with-samples
|
||||
|
||||
## Using the Semantic Kernel for Java
|
||||
|
||||
The library is organized in a set of dependencies published to Maven Central. For a list of the Maven dependencies and
|
||||
how to use each of them, see [PACKAGES.md](PACKAGES.md).
|
||||
|
||||
Alternatively, check the `samples` folder for examples of common AI-enabled scenarios implemented with Semantic Kernel
|
||||
for Java.
|
||||
|
||||
## Discord community
|
||||
|
||||
Join the [Microsoft Semantic Kernel Discord community](https://aka.ms/java-sk-discord) to discuss the Semantic Kernel
|
||||
and get help from the community. We have a `#java` channel for Java-specific questions.
|
||||
|
||||
## Contributing
|
||||
|
||||
### Testing locally
|
||||
|
||||
The project may contain end-to-end tests that require an OpenAI key to run. To run these tests locally, you
|
||||
will need to set the following environment variable:
|
||||
|
||||
- `CLIENT_KEY` - the OpenAI API key.
|
||||
|
||||
If you are using Azure OpenAI, you will also need to set the following environment variables:
|
||||
|
||||
- `CLIENT_ENDPOINT` - the Azure OpenAI endpoint found in **Keys * Endpoint** section of the Azure OpenAI service.
|
||||
- `AZURE_CLIENT_KEY` - the Azure OpenAI API key found in **Keys * Endpoint** section of the Azure OpenAI service.
|
||||
- `MODEL_ID` - the custom name you chose for your deployment when you deployed a model. It can be
|
||||
found under **Resource Management > Deployments** in the Azure Portal.
|
||||
|
||||
For more information, see the Azure OpenAI documentation
|
||||
on [how to get your Azure OpenAI credentials](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/quickstart?pivots=rest-api&tabs=command-line#retrieve-key-and-endpoint).
|
||||
|
||||
To run the unit tests only, run the following command:
|
||||
|
||||
./mvnw package
|
||||
|
||||
To run all tests, including integration tests that require an OpenAI key, run the following command:
|
||||
|
||||
./mvnw verify -Prelease,bug-check,with-samples
|
||||
|
||||
### Submitting a pull request
|
||||
|
||||
Before submitting a pull request, please make sure that you have run the project with the command:
|
||||
|
||||
```shell
|
||||
./mvnw clean package -Pbug-check
|
||||
```
|
||||
|
||||
The bug-check profile will detect some static analysis issues that will prevent merging as well as apply formatting
|
||||
requirements to the code base.
|
||||
|
||||
Also ensure that:
|
||||
|
||||
- All new code is covered by unit tests
|
||||
- All new code is covered by integration tests
|
||||
|
||||
Once your proposal is ready, submit a pull request to the `java-v1` branch. The pull request will be reviewed by the
|
||||
project maintainers.
|
||||
|
||||
Make sure your pull request has an objective title and a clear description explaining the problem and solution.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the [MIT License](../LICENSE).
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](../CODE_OF_CONDUCT.md).
|
||||
Project coordination is still performed within this [Project Board](https://github.com/orgs/microsoft/projects/866).
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-parent</artifactId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>semantickernel-aiservices-openai</artifactId>
|
||||
<name>Semantic Kernel OpenAI Services</name>
|
||||
<description>OpenAI services for Semantic Kernel</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.azure</groupId>
|
||||
<artifactId>azure-ai-openai</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Required for Android -->
|
||||
<dependency>
|
||||
<groupId>javax.xml.stream</groupId>
|
||||
<artifactId>stax-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.aiservices.openai;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.services.AIService;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Provides OpenAI service.
|
||||
*/
|
||||
public abstract class OpenAiService implements AIService {
|
||||
|
||||
private final OpenAIAsyncClient client;
|
||||
@Nullable
|
||||
private final String serviceId;
|
||||
private final String modelId;
|
||||
private final String deploymentName;
|
||||
|
||||
protected OpenAiService(
|
||||
OpenAIAsyncClient client,
|
||||
@Nullable String serviceId,
|
||||
String modelId,
|
||||
String deploymentName) {
|
||||
this.client = client;
|
||||
this.serviceId = serviceId;
|
||||
this.modelId = modelId;
|
||||
this.deploymentName = deploymentName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getModelId() {
|
||||
return modelId;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getServiceId() {
|
||||
return serviceId;
|
||||
}
|
||||
|
||||
protected OpenAIAsyncClient getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
public String getDeploymentName() {
|
||||
return deploymentName;
|
||||
}
|
||||
}
|
||||
-123
@@ -1,123 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.aiservices.openai.audio;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.models.AudioTranscription;
|
||||
import com.azure.ai.openai.models.AudioTranscriptionFormat;
|
||||
import com.azure.ai.openai.models.AudioTranscriptionOptions;
|
||||
import com.microsoft.semantickernel.aiservices.openai.OpenAiService;
|
||||
import com.microsoft.semantickernel.exceptions.SKException;
|
||||
import com.microsoft.semantickernel.services.audio.AudioContent;
|
||||
import com.microsoft.semantickernel.services.audio.AudioToTextExecutionSettings;
|
||||
import com.microsoft.semantickernel.services.audio.AudioToTextService;
|
||||
import javax.annotation.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Provides OpenAi implementation of audio to text service.
|
||||
*/
|
||||
public class OpenAiAudioToTextService extends OpenAiService implements AudioToTextService {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(OpenAiAudioToTextService.class);
|
||||
|
||||
/**
|
||||
* Creates an instance of OpenAi audio to text service.
|
||||
*
|
||||
* @param client OpenAI client.
|
||||
* @param modelId The model ID.
|
||||
*/
|
||||
public OpenAiAudioToTextService(
|
||||
OpenAIAsyncClient client,
|
||||
String modelId,
|
||||
String deploymentName) {
|
||||
super(client, null, modelId, deploymentName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<String> getTextContentsAsync(
|
||||
AudioContent content,
|
||||
@Nullable AudioToTextExecutionSettings executionSettings) {
|
||||
|
||||
AudioTranscriptionOptions options = convertOptions(content, executionSettings);
|
||||
|
||||
// TODO: Should use getAudioTranscriptionTextWithResponse, and OpenAIRequestSettings.getRequestOptions()
|
||||
// however currently this breaks the request
|
||||
return getClient()
|
||||
.getAudioTranscription(
|
||||
getDeploymentName(),
|
||||
options.getFilename(),
|
||||
options)
|
||||
.map(AudioTranscription::getText);
|
||||
}
|
||||
|
||||
private AudioTranscriptionOptions convertOptions(
|
||||
AudioContent content,
|
||||
@Nullable AudioToTextExecutionSettings executionSettings) {
|
||||
AudioTranscriptionOptions options = new AudioTranscriptionOptions(content.getData());
|
||||
|
||||
options.setModel(getModelId());
|
||||
if (executionSettings == null) {
|
||||
return options;
|
||||
}
|
||||
|
||||
if (executionSettings.getResponseFormat() != null) {
|
||||
options.setResponseFormat(
|
||||
AudioTranscriptionFormat.fromString(executionSettings.getResponseFormat()));
|
||||
}
|
||||
|
||||
if (executionSettings.getFilename() != null) {
|
||||
options.setFilename(executionSettings.getFilename());
|
||||
}
|
||||
|
||||
if (executionSettings.getLanguage() != null) {
|
||||
options.setLanguage(executionSettings.getLanguage());
|
||||
}
|
||||
|
||||
if (executionSettings.getPrompt() != null) {
|
||||
options.setPrompt(executionSettings.getPrompt());
|
||||
}
|
||||
|
||||
if (executionSettings.getTemperature() != null) {
|
||||
options.setTemperature(executionSettings.getTemperature());
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for OpenAiAudioToTextService.
|
||||
*
|
||||
* @return The builder.
|
||||
*/
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a builder for OpenAiAudioToTextService.
|
||||
*/
|
||||
public static class Builder extends AudioToTextService.Builder {
|
||||
|
||||
/**
|
||||
* builds the OpenAiAudioToTextService.
|
||||
*/
|
||||
@Override
|
||||
public AudioToTextService build() {
|
||||
if (client == null) {
|
||||
throw new SKException("OpenAI client is required");
|
||||
}
|
||||
|
||||
if (modelId == null) {
|
||||
throw new SKException("Model id is required");
|
||||
}
|
||||
|
||||
if (deploymentName == null) {
|
||||
LOGGER.debug("Deployment name is not provided, using model id as deployment name");
|
||||
deploymentName = modelId;
|
||||
}
|
||||
|
||||
return new OpenAiAudioToTextService(client, modelId, deploymentName);
|
||||
}
|
||||
}
|
||||
}
|
||||
-107
@@ -1,107 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.aiservices.openai.audio;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.models.SpeechGenerationOptions;
|
||||
import com.azure.ai.openai.models.SpeechGenerationResponseFormat;
|
||||
import com.azure.ai.openai.models.SpeechVoice;
|
||||
import com.microsoft.semantickernel.aiservices.openai.OpenAiService;
|
||||
import com.microsoft.semantickernel.exceptions.SKException;
|
||||
import com.microsoft.semantickernel.services.audio.AudioContent;
|
||||
import com.microsoft.semantickernel.services.audio.TextToAudioExecutionSettings;
|
||||
import com.microsoft.semantickernel.services.audio.TextToAudioService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Provides OpenAi implementation of text to audio service.
|
||||
*/
|
||||
public class OpenAiTextToAudioService extends OpenAiService implements TextToAudioService {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(OpenAiTextToAudioService.class);
|
||||
|
||||
/**
|
||||
* Creates an instance of OpenAi text to audio service.
|
||||
*
|
||||
* @param client OpenAI client.
|
||||
* @param modelId The model ID.
|
||||
*/
|
||||
public OpenAiTextToAudioService(
|
||||
OpenAIAsyncClient client,
|
||||
String modelId,
|
||||
String deploymentName) {
|
||||
super(client, null, modelId, deploymentName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<AudioContent> getAudioContentAsync(
|
||||
String text,
|
||||
TextToAudioExecutionSettings executionSettings) {
|
||||
|
||||
SpeechGenerationOptions options = convertOptions(text, executionSettings);
|
||||
|
||||
return getClient().generateSpeechFromText(getDeploymentName(), options)
|
||||
.map(response -> new AudioContent(response.toBytes(), getModelId()));
|
||||
}
|
||||
|
||||
private SpeechGenerationOptions convertOptions(
|
||||
String text,
|
||||
TextToAudioExecutionSettings executionSettings) {
|
||||
SpeechGenerationOptions options = new SpeechGenerationOptions(
|
||||
text,
|
||||
SpeechVoice.fromString(executionSettings.getVoice()));
|
||||
|
||||
options.setModel(getModelId());
|
||||
|
||||
if (executionSettings.getResponseFormat() != null) {
|
||||
options.setResponseFormat(
|
||||
SpeechGenerationResponseFormat.fromString(executionSettings.getResponseFormat()));
|
||||
}
|
||||
|
||||
if (executionSettings.getSpeed() != null) {
|
||||
options.setSpeed(executionSettings.getSpeed());
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new builder.
|
||||
*
|
||||
* @return The builder.
|
||||
*/
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a builder for OpenAi text to audio service.
|
||||
*/
|
||||
|
||||
public static class Builder extends TextToAudioService.Builder {
|
||||
|
||||
/**
|
||||
* Builds the OpenAi text to audio service.
|
||||
*
|
||||
* @return The OpenAi text to audio service.
|
||||
*/
|
||||
@Override
|
||||
public TextToAudioService build() {
|
||||
if (client == null) {
|
||||
throw new SKException("OpenAI client is required");
|
||||
}
|
||||
|
||||
if (modelId == null) {
|
||||
throw new SKException("Model id is required");
|
||||
}
|
||||
|
||||
if (deploymentName == null) {
|
||||
LOGGER.debug("Deployment name is not provided, using model id as deployment name");
|
||||
deploymentName = modelId;
|
||||
}
|
||||
|
||||
return new OpenAiTextToAudioService(client, modelId, deploymentName);
|
||||
}
|
||||
}
|
||||
}
|
||||
-985
@@ -1,985 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.aiservices.openai.chatcompletion;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.models.ChatChoice;
|
||||
import com.azure.ai.openai.models.ChatCompletions;
|
||||
import com.azure.ai.openai.models.ChatCompletionsFunctionToolCall;
|
||||
import com.azure.ai.openai.models.ChatCompletionsFunctionToolDefinition;
|
||||
import com.azure.ai.openai.models.ChatCompletionsJsonResponseFormat;
|
||||
import com.azure.ai.openai.models.ChatCompletionsOptions;
|
||||
import com.azure.ai.openai.models.ChatCompletionsTextResponseFormat;
|
||||
import com.azure.ai.openai.models.ChatCompletionsToolCall;
|
||||
import com.azure.ai.openai.models.ChatCompletionsToolDefinition;
|
||||
import com.azure.ai.openai.models.ChatRequestAssistantMessage;
|
||||
import com.azure.ai.openai.models.ChatRequestMessage;
|
||||
import com.azure.ai.openai.models.ChatRequestSystemMessage;
|
||||
import com.azure.ai.openai.models.ChatRequestToolMessage;
|
||||
import com.azure.ai.openai.models.ChatRequestUserMessage;
|
||||
import com.azure.ai.openai.models.ChatResponseMessage;
|
||||
import com.azure.ai.openai.models.FunctionCall;
|
||||
import com.azure.core.util.BinaryData;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ContainerNode;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.aiservices.openai.OpenAiService;
|
||||
import com.microsoft.semantickernel.aiservices.openai.implementation.OpenAIRequestSettings;
|
||||
import com.microsoft.semantickernel.contextvariables.ContextVariable;
|
||||
import com.microsoft.semantickernel.contextvariables.ContextVariableTypes;
|
||||
import com.microsoft.semantickernel.exceptions.AIException;
|
||||
import com.microsoft.semantickernel.exceptions.AIException.ErrorCodes;
|
||||
import com.microsoft.semantickernel.exceptions.SKCheckedException;
|
||||
import com.microsoft.semantickernel.exceptions.SKException;
|
||||
import com.microsoft.semantickernel.hooks.KernelHookEvent;
|
||||
import com.microsoft.semantickernel.hooks.KernelHooks;
|
||||
import com.microsoft.semantickernel.hooks.PostChatCompletionEvent;
|
||||
import com.microsoft.semantickernel.hooks.PreChatCompletionEvent;
|
||||
import com.microsoft.semantickernel.hooks.PreToolCallEvent;
|
||||
import com.microsoft.semantickernel.implementation.CollectionUtil;
|
||||
import com.microsoft.semantickernel.orchestration.FunctionResult;
|
||||
import com.microsoft.semantickernel.orchestration.FunctionResultMetadata;
|
||||
import com.microsoft.semantickernel.orchestration.InvocationContext;
|
||||
import com.microsoft.semantickernel.orchestration.InvocationReturnMode;
|
||||
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
|
||||
import com.microsoft.semantickernel.orchestration.ToolCallBehavior;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.AuthorRole;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatHistory;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import javax.annotation.CheckReturnValue;
|
||||
import javax.annotation.Nullable;
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* OpenAI chat completion service.
|
||||
*/
|
||||
public class OpenAIChatCompletion extends OpenAiService implements ChatCompletionService {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(OpenAIChatCompletion.class);
|
||||
|
||||
protected OpenAIChatCompletion(
|
||||
OpenAIAsyncClient client,
|
||||
String deploymentName,
|
||||
String modelId,
|
||||
@Nullable String serviceId) {
|
||||
super(client, serviceId, modelId, deploymentName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of {@link OpenAIChatCompletion.Builder}.
|
||||
*
|
||||
* @return a new instance of {@link OpenAIChatCompletion.Builder}
|
||||
*/
|
||||
public static OpenAIChatCompletion.Builder builder() {
|
||||
return new OpenAIChatCompletion.Builder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<List<ChatMessageContent<?>>> getChatMessageContentsAsync(
|
||||
ChatHistory chatHistory,
|
||||
@Nullable Kernel kernel,
|
||||
@Nullable InvocationContext invocationContext) {
|
||||
|
||||
List<ChatRequestMessage> chatRequestMessages = getChatRequestMessages(chatHistory);
|
||||
|
||||
ChatMessages messages = new ChatMessages(chatRequestMessages);
|
||||
|
||||
return internalChatMessageContentsAsync(
|
||||
messages,
|
||||
kernel,
|
||||
invocationContext)
|
||||
.flatMap(history -> {
|
||||
try {
|
||||
ChatHistory chatHistoryResult;
|
||||
|
||||
if (invocationContext != null
|
||||
&& invocationContext.returnMode() == InvocationReturnMode.FULL_HISTORY) {
|
||||
chatHistoryResult = new ChatHistory(chatHistory.getMessages());
|
||||
} else {
|
||||
chatHistoryResult = new ChatHistory();
|
||||
}
|
||||
|
||||
chatHistoryResult.addAll(
|
||||
new ChatHistory(toOpenAIChatMessageContent(history.newMessages)));
|
||||
chatHistoryResult.addAll(new ChatHistory(history.newChatMessageContent));
|
||||
|
||||
if (invocationContext != null
|
||||
&& invocationContext
|
||||
.returnMode() == InvocationReturnMode.LAST_MESSAGE_ONLY) {
|
||||
chatHistoryResult = new ChatHistory(
|
||||
Collections.singletonList(
|
||||
CollectionUtil.getLastOrNull(chatHistory.getMessages())));
|
||||
}
|
||||
|
||||
return Mono.just(chatHistoryResult.getMessages());
|
||||
} catch (Exception e) {
|
||||
return Mono.error(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<List<ChatMessageContent<?>>> getChatMessageContentsAsync(
|
||||
String prompt,
|
||||
@Nullable Kernel kernel,
|
||||
@Nullable InvocationContext invocationContext) {
|
||||
ParsedPrompt parsedPrompt = XMLPromptParser.parse(prompt);
|
||||
|
||||
ChatMessages messages = new ChatMessages(parsedPrompt.getChatRequestMessages());
|
||||
|
||||
return internalChatMessageContentsAsync(
|
||||
messages,
|
||||
kernel,
|
||||
invocationContext)
|
||||
.flatMap(m -> {
|
||||
try {
|
||||
ChatHistory result = new ChatHistory(toOpenAIChatMessageContent(m.allMessages));
|
||||
|
||||
result.addAll(new ChatHistory(m.newChatMessageContent));
|
||||
|
||||
if (invocationContext != null
|
||||
&& invocationContext
|
||||
.returnMode() == InvocationReturnMode.LAST_MESSAGE_ONLY) {
|
||||
result = new ChatHistory(
|
||||
Collections.singletonList(
|
||||
CollectionUtil.getLastOrNull(result.getMessages())));
|
||||
}
|
||||
|
||||
return Mono.just(result.getMessages());
|
||||
} catch (SKCheckedException e) {
|
||||
return Mono.error(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Holds messages temporarily as we build up our result
|
||||
private static class ChatMessages {
|
||||
|
||||
private final List<ChatRequestMessage> newMessages;
|
||||
private final List<ChatRequestMessage> allMessages;
|
||||
private final List<OpenAIChatMessageContent> newChatMessageContent;
|
||||
|
||||
public ChatMessages(List<ChatRequestMessage> allMessages) {
|
||||
this.allMessages = Collections.unmodifiableList(allMessages);
|
||||
this.newMessages = Collections.unmodifiableList(new ArrayList<>());
|
||||
this.newChatMessageContent = Collections.unmodifiableList(new ArrayList<>());
|
||||
}
|
||||
|
||||
private ChatMessages(
|
||||
List<ChatRequestMessage> allMessages,
|
||||
List<ChatRequestMessage> newMessages,
|
||||
List<OpenAIChatMessageContent> newChatMessageContent) {
|
||||
this.allMessages = Collections.unmodifiableList(allMessages);
|
||||
this.newMessages = Collections.unmodifiableList(newMessages);
|
||||
this.newChatMessageContent = Collections.unmodifiableList(newChatMessageContent);
|
||||
}
|
||||
|
||||
@CheckReturnValue
|
||||
public ChatMessages addAll(List<ChatRequestMessage> requestMessage) {
|
||||
List<ChatRequestMessage> tmpAllMessages = new ArrayList<>(allMessages);
|
||||
List<ChatRequestMessage> tmpNewMessages = new ArrayList<>(newMessages);
|
||||
tmpAllMessages.addAll(requestMessage);
|
||||
tmpNewMessages.addAll(requestMessage);
|
||||
return new ChatMessages(
|
||||
tmpAllMessages,
|
||||
tmpNewMessages,
|
||||
newChatMessageContent);
|
||||
}
|
||||
|
||||
@CheckReturnValue
|
||||
public ChatMessages add(ChatRequestMessage requestMessage) {
|
||||
return addAll(Arrays.asList(requestMessage));
|
||||
}
|
||||
|
||||
@CheckReturnValue
|
||||
public ChatMessages addChatMessage(List<OpenAIChatMessageContent> chatMessageContent) {
|
||||
ArrayList<OpenAIChatMessageContent> tmpChatMessageContent = new ArrayList<>(
|
||||
newChatMessageContent);
|
||||
tmpChatMessageContent.addAll(chatMessageContent);
|
||||
|
||||
return new ChatMessages(
|
||||
allMessages,
|
||||
newMessages,
|
||||
tmpChatMessageContent);
|
||||
}
|
||||
}
|
||||
|
||||
private Mono<ChatMessages> internalChatMessageContentsAsync(
|
||||
ChatMessages messages,
|
||||
@Nullable Kernel kernel,
|
||||
@Nullable InvocationContext invocationContext) {
|
||||
|
||||
List<OpenAIFunction> functions = new ArrayList<>();
|
||||
if (kernel != null) {
|
||||
kernel.getPlugins()
|
||||
.forEach(plugin -> plugin.getFunctions().forEach((name, function) -> functions
|
||||
.add(OpenAIFunction.build(function.getMetadata(), plugin.getName()))));
|
||||
}
|
||||
|
||||
// Create copy to avoid reactor exceptions when updating request messages internally
|
||||
return internalChatMessageContentsAsync(
|
||||
messages,
|
||||
kernel,
|
||||
functions,
|
||||
invocationContext,
|
||||
Math.min(MAXIMUM_INFLIGHT_AUTO_INVOKES,
|
||||
invocationContext != null && invocationContext.getToolCallBehavior() != null
|
||||
? invocationContext.getToolCallBehavior().getMaximumAutoInvokeAttempts()
|
||||
: 0));
|
||||
}
|
||||
|
||||
private Mono<ChatMessages> internalChatMessageContentsAsync(
|
||||
ChatMessages messages,
|
||||
@Nullable Kernel kernel,
|
||||
List<OpenAIFunction> functions,
|
||||
@Nullable InvocationContext invocationContext,
|
||||
int autoInvokeAttempts) {
|
||||
|
||||
ChatCompletionsOptions options = executeHook(
|
||||
invocationContext,
|
||||
new PreChatCompletionEvent(
|
||||
getCompletionsOptions(
|
||||
this,
|
||||
messages.allMessages,
|
||||
functions,
|
||||
invocationContext)))
|
||||
.getOptions();
|
||||
|
||||
return getClient()
|
||||
.getChatCompletionsWithResponse(getDeploymentName(), options,
|
||||
OpenAIRequestSettings.getRequestOptions())
|
||||
.flatMap(completionsResult -> {
|
||||
if (completionsResult.getStatusCode() >= 400) {
|
||||
return Mono.error(new AIException(ErrorCodes.SERVICE_ERROR,
|
||||
"Request failed: " + completionsResult.getStatusCode()));
|
||||
}
|
||||
return Mono.just(completionsResult.getValue());
|
||||
})
|
||||
.flatMap(completions -> {
|
||||
List<ChatResponseMessage> responseMessages = completions
|
||||
.getChoices()
|
||||
.stream()
|
||||
.map(ChatChoice::getMessage)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// execute post chat completion hook
|
||||
executeHook(invocationContext, 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
|
||||
if (autoInvokeAttempts == 0 || responseMessages.size() != 1) {
|
||||
return getChatMessageContentsAsync(completions)
|
||||
.flatMap(m -> {
|
||||
return Mono.just(messages.addChatMessage(m));
|
||||
});
|
||||
}
|
||||
// Or if there are no tool calls to be done
|
||||
ChatResponseMessage response = responseMessages.get(0);
|
||||
List<ChatCompletionsToolCall> toolCalls = response.getToolCalls();
|
||||
if (toolCalls == null || toolCalls.isEmpty()) {
|
||||
return getChatMessageContentsAsync(completions)
|
||||
.flatMap(m -> {
|
||||
return Mono.just(messages.addChatMessage(m));
|
||||
});
|
||||
}
|
||||
|
||||
ChatRequestAssistantMessage requestMessage = new ChatRequestAssistantMessage(
|
||||
response.getContent());
|
||||
requestMessage.setToolCalls(toolCalls);
|
||||
|
||||
// Add the original assistant message to the chat options; this is required for the service
|
||||
// to understand the tool call responses
|
||||
ChatMessages messagesWithToolCall = messages.add(requestMessage);
|
||||
|
||||
return Flux
|
||||
.fromIterable(toolCalls)
|
||||
.reduce(
|
||||
Mono.just(messagesWithToolCall),
|
||||
(requestMessages, toolCall) -> {
|
||||
if (toolCall instanceof ChatCompletionsFunctionToolCall) {
|
||||
return performToolCall(kernel, invocationContext, requestMessages,
|
||||
toolCall);
|
||||
}
|
||||
|
||||
return requestMessages;
|
||||
})
|
||||
.flatMap(it -> it)
|
||||
.flatMap(msgs -> {
|
||||
return internalChatMessageContentsAsync(msgs, kernel, functions,
|
||||
invocationContext, autoInvokeAttempts - 1);
|
||||
})
|
||||
.onErrorResume(e -> {
|
||||
|
||||
LOGGER.warn("Tool invocation attempt failed: ", e);
|
||||
|
||||
// If FunctionInvocationError occurred and there are still attempts left, retry, else exit
|
||||
if (autoInvokeAttempts > 0) {
|
||||
ChatMessages currentMessages = messages;
|
||||
if (e instanceof FunctionInvocationError) {
|
||||
currentMessages = currentMessages.addAll(
|
||||
((FunctionInvocationError) e).getMessages());
|
||||
}
|
||||
return internalChatMessageContentsAsync(
|
||||
currentMessages,
|
||||
kernel,
|
||||
functions,
|
||||
invocationContext,
|
||||
autoInvokeAttempts - 1);
|
||||
} else {
|
||||
return Mono.error(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private Mono<ChatMessages> performToolCall(
|
||||
@Nullable Kernel kernel,
|
||||
@Nullable InvocationContext invocationContext,
|
||||
Mono<ChatMessages> requestMessages,
|
||||
ChatCompletionsToolCall toolCall) {
|
||||
|
||||
return requestMessages
|
||||
.flatMap(messages -> {
|
||||
try {
|
||||
// OpenAI only supports function tool call at the moment
|
||||
ChatCompletionsFunctionToolCall functionToolCall = (ChatCompletionsFunctionToolCall) toolCall;
|
||||
if (kernel == null) {
|
||||
return Mono.error(new SKException(
|
||||
"A tool call was requested, but no kernel was provided to the invocation, this is a unsupported configuration"));
|
||||
}
|
||||
|
||||
ContextVariableTypes contextVariableTypes = invocationContext == null
|
||||
? new ContextVariableTypes()
|
||||
: invocationContext.getContextVariableTypes();
|
||||
|
||||
return invokeFunctionTool(
|
||||
kernel,
|
||||
invocationContext,
|
||||
functionToolCall,
|
||||
contextVariableTypes)
|
||||
.map(functionResult -> {
|
||||
// Add chat request tool message to the chat options
|
||||
ChatRequestMessage requestToolMessage = new ChatRequestToolMessage(
|
||||
functionResult.getResult(),
|
||||
functionToolCall.getId());
|
||||
|
||||
return messages.add(requestToolMessage);
|
||||
})
|
||||
.switchIfEmpty(Mono.fromSupplier(
|
||||
() -> {
|
||||
ChatRequestMessage requestToolMessage = new ChatRequestToolMessage(
|
||||
"Completed successfully with no return value",
|
||||
functionToolCall.getId());
|
||||
|
||||
return messages.add(requestToolMessage);
|
||||
}))
|
||||
.onErrorResume(e -> emitError(toolCall, messages, e));
|
||||
} catch (Exception e) {
|
||||
return emitError(toolCall, messages, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Mono<ChatMessages> emitError(
|
||||
ChatCompletionsToolCall toolCall,
|
||||
ChatMessages msgs,
|
||||
Throwable e) {
|
||||
msgs = msgs.add(new ChatRequestToolMessage(
|
||||
"Call failed: " + e.getMessage(),
|
||||
toolCall.getId()));
|
||||
|
||||
return Mono.error(new FunctionInvocationError(e, msgs.allMessages));
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception to be thrown when a function invocation fails.
|
||||
*/
|
||||
private static class FunctionInvocationError extends SKException {
|
||||
|
||||
private final List<ChatRequestMessage> messages;
|
||||
|
||||
public FunctionInvocationError(Throwable e, List<ChatRequestMessage> msgs) {
|
||||
super(e.getMessage(), e);
|
||||
this.messages = msgs;
|
||||
}
|
||||
|
||||
public List<ChatRequestMessage> getMessages() {
|
||||
return messages;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("StringSplitter")
|
||||
private Mono<FunctionResult<String>> invokeFunctionTool(
|
||||
Kernel kernel,
|
||||
@Nullable InvocationContext invocationContext,
|
||||
ChatCompletionsFunctionToolCall toolCall,
|
||||
ContextVariableTypes contextVariableTypes) {
|
||||
|
||||
try {
|
||||
OpenAIFunctionToolCall openAIFunctionToolCall = extractOpenAIFunctionToolCall(toolCall);
|
||||
String pluginName = openAIFunctionToolCall.getPluginName();
|
||||
if (pluginName == null || pluginName.isEmpty()) {
|
||||
return Mono.error(
|
||||
new SKException("Plugin name is required for function tool call"));
|
||||
}
|
||||
|
||||
KernelFunction<?> function = kernel.getFunction(
|
||||
pluginName,
|
||||
openAIFunctionToolCall.getFunctionName());
|
||||
|
||||
PreToolCallEvent hookResult = executeHook(invocationContext, new PreToolCallEvent(
|
||||
openAIFunctionToolCall.getFunctionName(),
|
||||
openAIFunctionToolCall.getArguments(),
|
||||
function,
|
||||
contextVariableTypes));
|
||||
|
||||
function = hookResult.getFunction();
|
||||
KernelFunctionArguments arguments = hookResult.getArguments();
|
||||
|
||||
return function
|
||||
.invokeAsync(kernel)
|
||||
.withArguments(arguments)
|
||||
.withResultType(contextVariableTypes.getVariableTypeForClass(String.class));
|
||||
} catch (JsonProcessingException e) {
|
||||
return Mono.error(new SKException("Failed to parse tool arguments", e));
|
||||
}
|
||||
}
|
||||
|
||||
private static <T extends KernelHookEvent> T executeHook(
|
||||
@Nullable InvocationContext invocationContext,
|
||||
T event) {
|
||||
KernelHooks kernelHooks = invocationContext != null
|
||||
&& invocationContext.getKernelHooks() != null
|
||||
? invocationContext.getKernelHooks()
|
||||
: new KernelHooks();
|
||||
|
||||
return kernelHooks.executeHooks(event);
|
||||
}
|
||||
|
||||
@SuppressWarnings("StringSplitter")
|
||||
private OpenAIFunctionToolCall extractOpenAIFunctionToolCall(
|
||||
ChatCompletionsFunctionToolCall toolCall)
|
||||
throws JsonProcessingException {
|
||||
|
||||
// Split the full name of a function into plugin and function name
|
||||
String name = toolCall.getFunction().getName();
|
||||
String[] parts = name.split(OpenAIFunction.getNameSeparator());
|
||||
String pluginName = parts.length > 1 ? parts[0] : "";
|
||||
String fnName = parts.length > 1 ? parts[1] : parts[0];
|
||||
|
||||
KernelFunctionArguments arguments = KernelFunctionArguments.builder().build();
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode jsonToolCallArguments = mapper.readTree(toolCall.getFunction().getArguments());
|
||||
|
||||
jsonToolCallArguments.fields().forEachRemaining(
|
||||
entry -> {
|
||||
if (entry.getValue() instanceof ContainerNode) {
|
||||
arguments.put(entry.getKey(),
|
||||
ContextVariable.of(entry.getValue().toPrettyString()));
|
||||
} else {
|
||||
arguments.put(entry.getKey(),
|
||||
ContextVariable.of(entry.getValue().asText()));
|
||||
}
|
||||
});
|
||||
|
||||
return new OpenAIFunctionToolCall(
|
||||
toolCall.getId(),
|
||||
pluginName,
|
||||
fnName,
|
||||
arguments);
|
||||
}
|
||||
|
||||
private Mono<List<OpenAIChatMessageContent>> getChatMessageContentsAsync(
|
||||
ChatCompletions completions) {
|
||||
FunctionResultMetadata completionMetadata = FunctionResultMetadata.build(
|
||||
completions.getId(),
|
||||
completions.getUsage(),
|
||||
completions.getCreatedAt());
|
||||
|
||||
List<ChatResponseMessage> responseMessages = completions
|
||||
.getChoices()
|
||||
.stream()
|
||||
.map(ChatChoice::getMessage)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return Flux.fromIterable(responseMessages)
|
||||
.flatMap(response -> {
|
||||
try {
|
||||
return Mono.just(new OpenAIChatMessageContent(
|
||||
AuthorRole.ASSISTANT,
|
||||
response.getContent(),
|
||||
this.getModelId(),
|
||||
null,
|
||||
null,
|
||||
completionMetadata,
|
||||
formOpenAiToolCalls(response)));
|
||||
} catch (Exception e) {
|
||||
return Mono.error(e);
|
||||
}
|
||||
})
|
||||
.collectList();
|
||||
}
|
||||
|
||||
private List<ChatMessageContent<?>> toOpenAIChatMessageContent(
|
||||
List<ChatRequestMessage> requestMessages) throws SKCheckedException {
|
||||
try {
|
||||
return requestMessages
|
||||
.stream()
|
||||
.map(message -> {
|
||||
if (message instanceof ChatRequestUserMessage) {
|
||||
return new OpenAIChatMessageContent<>(
|
||||
AuthorRole.USER,
|
||||
((ChatRequestUserMessage) message).getContent().toString(),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
} else if (message instanceof ChatRequestSystemMessage) {
|
||||
return new OpenAIChatMessageContent<>(
|
||||
AuthorRole.SYSTEM,
|
||||
((ChatRequestSystemMessage) message).getContent(),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
} else if (message instanceof ChatRequestAssistantMessage) {
|
||||
try {
|
||||
List<OpenAIFunctionToolCall> calls = getToolCalls(
|
||||
((ChatRequestAssistantMessage) message).getToolCalls());
|
||||
return new OpenAIChatMessageContent<>(
|
||||
AuthorRole.ASSISTANT,
|
||||
((ChatRequestAssistantMessage) message).getContent(),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
calls);
|
||||
} catch (SKCheckedException e) {
|
||||
throw SKException.build("Failed to form assistant message", e);
|
||||
}
|
||||
} else if (message instanceof ChatRequestToolMessage) {
|
||||
return new OpenAIChatMessageContent<>(
|
||||
AuthorRole.TOOL,
|
||||
((ChatRequestToolMessage) message).getContent(),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
FunctionResultMetadata.build(
|
||||
((ChatRequestToolMessage) message).getToolCallId(),
|
||||
null,
|
||||
null),
|
||||
null);
|
||||
}
|
||||
|
||||
throw new SKException(
|
||||
"Unknown message type: " + message.getClass().getSimpleName());
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
} catch (SKException e) {
|
||||
throw SKCheckedException.build("Failed to form OpenAI chat message content", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private List<OpenAIFunctionToolCall> getToolCalls(
|
||||
@Nullable List<ChatCompletionsToolCall> toolCalls) throws SKCheckedException {
|
||||
if (toolCalls == null || toolCalls.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return toolCalls
|
||||
.stream()
|
||||
.map(call -> {
|
||||
if (call instanceof ChatCompletionsFunctionToolCall) {
|
||||
try {
|
||||
return extractOpenAIFunctionToolCall(
|
||||
(ChatCompletionsFunctionToolCall) call);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw SKException.build("Failed to parse tool arguments", e);
|
||||
}
|
||||
} else {
|
||||
return new OpenAIFunctionToolCall(
|
||||
call.getId(),
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
} catch (SKException e) {
|
||||
throw SKCheckedException.build("Failed to form tool call", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private List<OpenAIFunctionToolCall> formOpenAiToolCalls(
|
||||
ChatResponseMessage response) throws SKCheckedException {
|
||||
if (response.getToolCalls() == null || response.getToolCalls().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return response
|
||||
.getToolCalls()
|
||||
.stream()
|
||||
.map(call -> {
|
||||
if (call instanceof ChatCompletionsFunctionToolCall) {
|
||||
try {
|
||||
return extractOpenAIFunctionToolCall(
|
||||
(ChatCompletionsFunctionToolCall) call);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw SKException.build("Failed to parse tool arguments", e);
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
} catch (SKException e) {
|
||||
throw SKCheckedException.build("Failed to form tool call", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static ChatCompletionsOptions getCompletionsOptions(
|
||||
ChatCompletionService chatCompletionService,
|
||||
List<ChatRequestMessage> chatRequestMessages,
|
||||
@Nullable List<OpenAIFunction> functions,
|
||||
@Nullable InvocationContext invocationContext) {
|
||||
|
||||
chatRequestMessages = chatRequestMessages
|
||||
.stream()
|
||||
.map(XMLPromptParser::unescapeRequest)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
ChatCompletionsOptions options = new ChatCompletionsOptions(chatRequestMessages)
|
||||
.setModel(chatCompletionService.getModelId());
|
||||
|
||||
if (invocationContext != null && invocationContext.getToolCallBehavior() != null) {
|
||||
configureToolCallBehaviorOptions(
|
||||
options,
|
||||
invocationContext.getToolCallBehavior(),
|
||||
functions,
|
||||
chatRequestMessages);
|
||||
}
|
||||
|
||||
PromptExecutionSettings promptExecutionSettings = invocationContext != null
|
||||
? invocationContext.getPromptExecutionSettings()
|
||||
: null;
|
||||
|
||||
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) {
|
||||
logit = promptExecutionSettings
|
||||
.getTokenSelectionBiases()
|
||||
.entrySet()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(
|
||||
entry -> entry.getKey().toString(),
|
||||
Map.Entry::getValue));
|
||||
}
|
||||
|
||||
options
|
||||
.setTemperature(promptExecutionSettings.getTemperature())
|
||||
.setTopP(promptExecutionSettings.getTopP())
|
||||
.setPresencePenalty(promptExecutionSettings.getPresencePenalty())
|
||||
.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
|
||||
|| promptExecutionSettings.getStopSequences().isEmpty() ? null
|
||||
: promptExecutionSettings.getStopSequences())
|
||||
.setUser(promptExecutionSettings.getUser())
|
||||
.setLogitBias(logit);
|
||||
|
||||
if (promptExecutionSettings.getResponseFormat() != null) {
|
||||
switch (promptExecutionSettings.getResponseFormat()) {
|
||||
case JSON_OBJECT:
|
||||
options.setResponseFormat(new ChatCompletionsJsonResponseFormat());
|
||||
break;
|
||||
case TEXT:
|
||||
options.setResponseFormat(new ChatCompletionsTextResponseFormat());
|
||||
break;
|
||||
default:
|
||||
throw new SKException(
|
||||
"Unknown response format: " + promptExecutionSettings.getResponseFormat());
|
||||
}
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
private static void configureToolCallBehaviorOptions(
|
||||
ChatCompletionsOptions options,
|
||||
@Nullable ToolCallBehavior toolCallBehavior,
|
||||
@Nullable List<OpenAIFunction> functions,
|
||||
List<ChatRequestMessage> chatRequestMessages) {
|
||||
|
||||
if (toolCallBehavior == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (functions == null || functions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If a specific function is required to be called
|
||||
if (toolCallBehavior instanceof ToolCallBehavior.RequiredKernelFunction) {
|
||||
KernelFunction<?> toolChoice = ((ToolCallBehavior.RequiredKernelFunction) toolCallBehavior)
|
||||
.getRequiredFunction();
|
||||
|
||||
String toolChoiceName = String.format("%s%s%s",
|
||||
toolChoice.getPluginName(),
|
||||
OpenAIFunction.getNameSeparator(),
|
||||
toolChoice.getName());
|
||||
|
||||
// If required tool call has already been called dont ask for it again
|
||||
boolean hasBeenExecuted = hasToolCallBeenExecuted(chatRequestMessages, toolChoiceName);
|
||||
if (hasBeenExecuted) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<ChatCompletionsToolDefinition> toolDefinitions = new ArrayList<>();
|
||||
|
||||
toolDefinitions.add(new ChatCompletionsFunctionToolDefinition(
|
||||
OpenAIFunction.toFunctionDefinition(
|
||||
toolChoice.getMetadata(),
|
||||
toolChoice.getPluginName())));
|
||||
|
||||
options.setTools(toolDefinitions);
|
||||
try {
|
||||
String json = String.format(
|
||||
"{\"type\":\"function\",\"function\":{\"name\":\"%s\"}}", toolChoiceName);
|
||||
options.setToolChoice(BinaryData.fromObject(new ObjectMapper().readTree(json)));
|
||||
} catch (JsonProcessingException e) {
|
||||
throw SKException.build("Failed to parse tool choice", e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If a set of functions are enabled to be called
|
||||
ToolCallBehavior.AllowedKernelFunctions enabledKernelFunctions = (ToolCallBehavior.AllowedKernelFunctions) toolCallBehavior;
|
||||
List<ChatCompletionsToolDefinition> toolDefinitions = functions.stream()
|
||||
.filter(function -> {
|
||||
// check if all kernel functions are enabled
|
||||
if (enabledKernelFunctions.isAllKernelFunctionsAllowed()) {
|
||||
return true;
|
||||
}
|
||||
// otherwise, check for the specific function
|
||||
return enabledKernelFunctions.isFunctionAllowed(function.getPluginName(),
|
||||
function.getName());
|
||||
})
|
||||
.map(OpenAIFunction::getFunctionDefinition)
|
||||
.map(ChatCompletionsFunctionToolDefinition::new)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (toolDefinitions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
options.setTools(toolDefinitions);
|
||||
options.setToolChoice(BinaryData.fromString("auto"));
|
||||
}
|
||||
|
||||
private static boolean hasToolCallBeenExecuted(List<ChatRequestMessage> chatRequestMessages,
|
||||
String toolChoiceName) {
|
||||
return chatRequestMessages
|
||||
.stream()
|
||||
.flatMap(message -> {
|
||||
// Extract tool calls
|
||||
if (message instanceof ChatRequestAssistantMessage) {
|
||||
return ((ChatRequestAssistantMessage) message).getToolCalls().stream();
|
||||
}
|
||||
return Stream.empty();
|
||||
})
|
||||
.filter(toolCall -> {
|
||||
// Filter if tool call has correct name
|
||||
if (toolCall instanceof ChatCompletionsFunctionToolCall) {
|
||||
return ((ChatCompletionsFunctionToolCall) toolCall).getFunction().getName()
|
||||
.equals(toolChoiceName);
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.allMatch(toolcall -> {
|
||||
String id = toolcall.getId();
|
||||
// True if tool call id has a response message
|
||||
return chatRequestMessages
|
||||
.stream()
|
||||
.filter(
|
||||
chatRequestMessage -> chatRequestMessage instanceof ChatRequestToolMessage)
|
||||
.anyMatch(
|
||||
chatRequestMessage -> ((ChatRequestToolMessage) chatRequestMessage)
|
||||
.getToolCallId()
|
||||
.equals(id));
|
||||
});
|
||||
}
|
||||
|
||||
private static List<ChatRequestMessage> getChatRequestMessages(
|
||||
List<? extends ChatMessageContent> messages) {
|
||||
if (messages == null || messages.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return messages.stream()
|
||||
.map(OpenAIChatCompletion::getChatRequestMessage)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static List<ChatRequestMessage> getChatRequestMessages(ChatHistory chatHistory) {
|
||||
return getChatRequestMessages(chatHistory.getMessages());
|
||||
}
|
||||
|
||||
private static ChatRequestMessage getChatRequestMessage(
|
||||
ChatMessageContent<?> message) {
|
||||
|
||||
AuthorRole authorRole = message.getAuthorRole();
|
||||
String content = message.getContent();
|
||||
|
||||
switch (authorRole) {
|
||||
case ASSISTANT:
|
||||
return formAssistantMessage(message, content);
|
||||
case SYSTEM:
|
||||
return new ChatRequestSystemMessage(content);
|
||||
case USER:
|
||||
return new ChatRequestUserMessage(content);
|
||||
case TOOL:
|
||||
String id = null;
|
||||
|
||||
if (message.getMetadata() != null) {
|
||||
id = message.getMetadata().getId();
|
||||
}
|
||||
|
||||
if (id == null) {
|
||||
throw new SKException(
|
||||
"Require to create a tool call message, but no tool call id is available");
|
||||
}
|
||||
return new ChatRequestToolMessage(content, id);
|
||||
default:
|
||||
LOGGER.debug("Unexpected author role: {}", authorRole);
|
||||
throw new SKException("Unexpected author role: " + authorRole);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static ChatRequestAssistantMessage formAssistantMessage(
|
||||
ChatMessageContent<?> message,
|
||||
@Nullable String content) {
|
||||
// TODO: handle tools other than function calls
|
||||
ChatRequestAssistantMessage asstMessage = new ChatRequestAssistantMessage(content);
|
||||
|
||||
List<OpenAIFunctionToolCall> toolCalls = null;
|
||||
if (message instanceof OpenAIChatMessageContent) {
|
||||
toolCalls = ((OpenAIChatMessageContent<?>) message).getToolCall();
|
||||
}
|
||||
|
||||
if (toolCalls != null) {
|
||||
asstMessage.setToolCalls(
|
||||
toolCalls.stream()
|
||||
.map(toolCall -> {
|
||||
KernelFunctionArguments arguments = toolCall.getArguments();
|
||||
|
||||
String args = arguments != null && !arguments.isEmpty()
|
||||
? arguments.entrySet().stream()
|
||||
.map(entry -> String.format("\"%s\": \"%s\"",
|
||||
StringEscapeUtils.escapeJson(entry.getKey()),
|
||||
StringEscapeUtils.escapeJson(
|
||||
entry.getValue().toPromptString())))
|
||||
.collect(Collectors.joining(",", "{", "}"))
|
||||
: "{}";
|
||||
|
||||
String prefix = "";
|
||||
if (toolCall.getPluginName() != null) {
|
||||
prefix = toolCall.getPluginName() + OpenAIFunction.getNameSeparator();
|
||||
}
|
||||
String name = prefix + toolCall.getFunctionName();
|
||||
|
||||
FunctionCall fnCall = new FunctionCall(name, args);
|
||||
return new ChatCompletionsFunctionToolCall(toolCall.getId(),
|
||||
fnCall);
|
||||
})
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
return asstMessage;
|
||||
}
|
||||
|
||||
static ChatRequestMessage getChatRequestMessage(
|
||||
AuthorRole authorRole,
|
||||
String content) {
|
||||
|
||||
switch (authorRole) {
|
||||
case ASSISTANT:
|
||||
return new ChatRequestAssistantMessage(content);
|
||||
case SYSTEM:
|
||||
return new ChatRequestSystemMessage(content);
|
||||
case USER:
|
||||
return new ChatRequestUserMessage(content);
|
||||
case TOOL:
|
||||
return new ChatRequestToolMessage(content, null);
|
||||
default:
|
||||
LOGGER.debug("Unexpected author role: " + authorRole);
|
||||
throw new SKException("Unexpected author role: " + authorRole);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for creating a new instance of {@link OpenAIChatCompletion}.
|
||||
*/
|
||||
public static class Builder extends ChatCompletionService.Builder {
|
||||
|
||||
@Override
|
||||
public OpenAIChatCompletion build() {
|
||||
|
||||
if (this.client == null) {
|
||||
throw new AIException(AIException.ErrorCodes.INVALID_REQUEST,
|
||||
"OpenAI client must be provided");
|
||||
}
|
||||
|
||||
if (this.modelId == null || modelId.isEmpty()) {
|
||||
throw new AIException(AIException.ErrorCodes.INVALID_REQUEST,
|
||||
"OpenAI model id must be provided");
|
||||
}
|
||||
|
||||
if (deploymentName == null) {
|
||||
LOGGER.debug("Deployment name is not provided, using model id as deployment name");
|
||||
deploymentName = modelId;
|
||||
}
|
||||
|
||||
return new OpenAIChatCompletion(client, deploymentName, modelId, serviceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
-59
@@ -1,59 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.aiservices.openai.chatcompletion;
|
||||
|
||||
import com.microsoft.semantickernel.orchestration.FunctionResultMetadata;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.AuthorRole;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Represents the content of a chat message.
|
||||
*
|
||||
* @param <T> The type of the inner content.
|
||||
*/
|
||||
public class OpenAIChatMessageContent<T> extends ChatMessageContent<T> {
|
||||
|
||||
@Nullable
|
||||
private final List<OpenAIFunctionToolCall> toolCall;
|
||||
|
||||
/**
|
||||
* Creates a new instance of the {@link OpenAIChatMessageContent} class.
|
||||
*
|
||||
* @param authorRole The author role that generated the content.
|
||||
* @param content The content.
|
||||
* @param modelId The model id.
|
||||
* @param innerContent The inner content.
|
||||
* @param encoding The encoding.
|
||||
* @param metadata The metadata.
|
||||
* @param toolCall The tool call.
|
||||
*/
|
||||
public OpenAIChatMessageContent(
|
||||
AuthorRole authorRole,
|
||||
String content,
|
||||
@Nullable String modelId,
|
||||
@Nullable T innerContent,
|
||||
@Nullable Charset encoding,
|
||||
@Nullable FunctionResultMetadata metadata,
|
||||
@Nullable List<OpenAIFunctionToolCall> toolCall) {
|
||||
super(authorRole, content, modelId, innerContent, encoding, metadata);
|
||||
|
||||
if (toolCall == null) {
|
||||
this.toolCall = null;
|
||||
} else {
|
||||
this.toolCall = Collections.unmodifiableList(toolCall);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets any tool calls requested.
|
||||
*
|
||||
* @return The tool call.
|
||||
*/
|
||||
@Nullable
|
||||
public List<OpenAIFunctionToolCall> getToolCall() {
|
||||
return toolCall;
|
||||
}
|
||||
}
|
||||
-156
@@ -1,156 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.aiservices.openai.chatcompletion;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents the response from the OpenAI chat completion API.
|
||||
*/
|
||||
public interface OpenAIChatResponse {
|
||||
|
||||
/**
|
||||
* Represents the usage of the chat completion API.
|
||||
*/
|
||||
interface Usage {
|
||||
|
||||
/**
|
||||
* Gets the number of tokens used for the prompt.
|
||||
*
|
||||
* @return the number of tokens used for the prompt
|
||||
*/
|
||||
@JsonProperty("prompt_tokens")
|
||||
int getPromptTokens();
|
||||
|
||||
/**
|
||||
* Gets the number of tokens used for the completion.
|
||||
*
|
||||
* @return the number of tokens used for the completion
|
||||
*/
|
||||
@JsonProperty("completion_tokens")
|
||||
int getCompletionTokens();
|
||||
|
||||
/**
|
||||
* Gets the total number of tokens used.
|
||||
*
|
||||
* @return the total number of tokens used
|
||||
*/
|
||||
@JsonProperty("total_tokens")
|
||||
int getTotalTokens();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a choice in the chat completion response.
|
||||
*/
|
||||
interface Choice {
|
||||
|
||||
/**
|
||||
* Gets the message in the chat completion response.
|
||||
*
|
||||
* @return the message in the chat completion response
|
||||
*/
|
||||
@JsonProperty("message")
|
||||
Message getMessage();
|
||||
|
||||
/**
|
||||
* Gets the finish details in the chat completion response.
|
||||
*
|
||||
* @return the finish details in the chat completion response
|
||||
*/
|
||||
@JsonProperty("finish_details")
|
||||
FinishDetails getFinishDetails();
|
||||
|
||||
/**
|
||||
* Gets the index of the choice.
|
||||
*
|
||||
* @return the index of the choice
|
||||
*/
|
||||
@JsonProperty("index")
|
||||
int getIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a message in the chat completion response.
|
||||
*/
|
||||
interface Message {
|
||||
|
||||
/**
|
||||
* Gets the role of the message.
|
||||
*
|
||||
* @return the role of the message
|
||||
*/
|
||||
@JsonProperty("role")
|
||||
String getRole();
|
||||
|
||||
/**
|
||||
* Gets the content of the message.
|
||||
*
|
||||
* @return the content of the message
|
||||
*/
|
||||
@JsonProperty("content")
|
||||
String getContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the finish details in the chat completion response.
|
||||
*/
|
||||
interface FinishDetails {
|
||||
|
||||
/**
|
||||
* Gets the type of the finish details.
|
||||
*
|
||||
* @return the type of the finish details
|
||||
*/
|
||||
@JsonProperty("type")
|
||||
String getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id of the chat completion response.
|
||||
*
|
||||
* @return the id of the chat completion response
|
||||
*/
|
||||
@JsonProperty("id")
|
||||
String getId();
|
||||
|
||||
/**
|
||||
* Gets the object of the chat completion response.
|
||||
*
|
||||
* @return the object of the chat completion response
|
||||
*/
|
||||
@JsonProperty("object")
|
||||
String getObject();
|
||||
|
||||
/**
|
||||
* Gets the created time of the chat completion response.
|
||||
*
|
||||
* @return the created time of the chat completion response
|
||||
*/
|
||||
@JsonProperty("created")
|
||||
Long getCreated();
|
||||
|
||||
/**
|
||||
* Gets the model of the chat completion response.
|
||||
*
|
||||
* @return the model of the chat completion response
|
||||
*/
|
||||
@JsonProperty("model")
|
||||
String getModel();
|
||||
|
||||
/**
|
||||
* Gets the usage of the chat completion response.
|
||||
*
|
||||
* @return the usage of the chat completion response
|
||||
*/
|
||||
@JsonProperty("Usage")
|
||||
List<Usage> getUsage();
|
||||
|
||||
/**
|
||||
* Gets the choices of the chat completion response.
|
||||
*
|
||||
* @return the choices of the chat completion response
|
||||
*/
|
||||
@JsonProperty("choices")
|
||||
List<Choice> getChoices();
|
||||
|
||||
}
|
||||
-182
@@ -1,182 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.aiservices.openai.chatcompletion;
|
||||
|
||||
import com.azure.ai.openai.models.FunctionDefinition;
|
||||
import com.azure.core.util.BinaryData;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.microsoft.semantickernel.semanticfunctions.InputVariable;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionMetadata;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
class OpenAIFunction {
|
||||
|
||||
private final String pluginName;
|
||||
private final String name;
|
||||
private final FunctionDefinition functionDefinition;
|
||||
|
||||
protected OpenAIFunction(
|
||||
@Nonnull String name,
|
||||
@Nonnull String pluginName,
|
||||
@Nonnull FunctionDefinition functionDefinition) {
|
||||
this.name = name;
|
||||
this.pluginName = pluginName;
|
||||
this.functionDefinition = functionDefinition;
|
||||
}
|
||||
|
||||
public static OpenAIFunction build(KernelFunctionMetadata<?> metadata, String pluginName) {
|
||||
String name = metadata.getName();
|
||||
FunctionDefinition functionDefinition = toFunctionDefinition(metadata, pluginName);
|
||||
return new OpenAIFunction(name, pluginName, functionDefinition);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getPluginName() {
|
||||
return pluginName;
|
||||
}
|
||||
|
||||
public FunctionDefinition getFunctionDefinition() {
|
||||
return functionDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the separator used between the plugin name and the function name, if a plugin name is
|
||||
* present.
|
||||
*
|
||||
* @return The separator used between the plugin name and the function name.
|
||||
*/
|
||||
public static String getNameSeparator() {
|
||||
return "-";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fully-qualified name of the function.
|
||||
*
|
||||
* @return The fully-qualified name of the function.
|
||||
*/
|
||||
private static String getFullyQualifiedName(
|
||||
@Nullable String pluginName, String functionName) {
|
||||
return (pluginName == null || pluginName.isEmpty()) ? functionName
|
||||
: pluginName + getNameSeparator() + functionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a KernelFunctionMetadata representation to the SDK's FunctionDefinition
|
||||
* representation.
|
||||
*
|
||||
* @return A FunctionDefinition containing all the function information.
|
||||
*/
|
||||
public static FunctionDefinition toFunctionDefinition(KernelFunctionMetadata<?> metadata,
|
||||
@Nullable String pluginName) {
|
||||
BinaryData resultParameters;
|
||||
|
||||
Map<String, JsonNode> properties = new HashMap<>();
|
||||
List<String> required = new ArrayList<>();
|
||||
|
||||
try {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
for (InputVariable parameter : metadata.getParameters()) {
|
||||
String parameterJsonSchema = getSchemaForFunctionParameter(parameter);
|
||||
|
||||
properties.put(parameter.getName(), objectMapper.readTree(parameterJsonSchema));
|
||||
|
||||
if (parameter.isRequired()) {
|
||||
required.add(parameter.getName());
|
||||
}
|
||||
}
|
||||
|
||||
String json = objectMapper
|
||||
.writeValueAsString(new OpenAIFunctionParameter("object", required, properties));
|
||||
resultParameters = BinaryData.fromObject(objectMapper.readTree(json));
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
FunctionDefinition functionDefinition = new FunctionDefinition(
|
||||
getFullyQualifiedName(pluginName, metadata.getName()));
|
||||
functionDefinition.setDescription(metadata.getDescription());
|
||||
functionDefinition.setParameters(resultParameters);
|
||||
|
||||
return functionDefinition;
|
||||
}
|
||||
|
||||
private static class OpenAIFunctionParameter {
|
||||
|
||||
@JsonProperty("type")
|
||||
private String type;
|
||||
@JsonProperty("required")
|
||||
private List<String> required;
|
||||
@JsonProperty("properties")
|
||||
private Map<String, JsonNode> properties;
|
||||
|
||||
public OpenAIFunctionParameter(
|
||||
String type,
|
||||
List<String> required,
|
||||
Map<String, JsonNode> properties) {
|
||||
this.type = type;
|
||||
this.required = Collections.unmodifiableList(required);
|
||||
this.properties = Collections.unmodifiableMap(properties);
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedMethod")
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedMethod")
|
||||
public List<String> getRequired() {
|
||||
return required;
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedMethod")
|
||||
public Map<String, JsonNode> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getSchemaForFunctionParameter(@Nullable InputVariable parameter) {
|
||||
List<String> entries = new ArrayList<>();
|
||||
|
||||
entries.add("\"type\":\"string\"");
|
||||
|
||||
// Add description if present
|
||||
if (parameter != null && parameter.getDescription() != null && !parameter.getDescription()
|
||||
.isEmpty()) {
|
||||
String description = parameter.getDescription();
|
||||
description = description.replace("\n", "");
|
||||
description = description.replace("\"", "\\\"");
|
||||
|
||||
description = String.format("\"description\":\"%s\"", description);
|
||||
entries.add(description);
|
||||
}
|
||||
|
||||
// Add enum options if parameter is an enum
|
||||
if (parameter != null && parameter.getEnumValues() != null && !parameter.getEnumValues()
|
||||
.isEmpty()) {
|
||||
String enumEntry = parameter
|
||||
.getEnumValues()
|
||||
.stream()
|
||||
.map(Object::toString)
|
||||
.map(it -> "\"" + it + "\"")
|
||||
.collect(Collectors.joining(","));
|
||||
|
||||
entries.add("\"enum\":[ " + enumEntry + " ]");
|
||||
}
|
||||
|
||||
String schema = String.join(",", entries);
|
||||
|
||||
return "{" + schema + "}";
|
||||
}
|
||||
}
|
||||
-92
@@ -1,92 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.aiservices.openai.chatcompletion;
|
||||
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Represents a call to a function in the OpenAI tool.
|
||||
*/
|
||||
public class OpenAIFunctionToolCall {
|
||||
|
||||
/// <summary>Gets the ID of the tool call.</summary>
|
||||
@Nullable
|
||||
private final String id;
|
||||
|
||||
/// <summary>Gets the name of the plugin with which this function is associated, if any.</summary>
|
||||
|
||||
@Nullable
|
||||
private final String pluginName;
|
||||
|
||||
/// <summary>Gets the name of the function.</summary>
|
||||
private final String functionName;
|
||||
|
||||
/// <summary>Gets a name/value collection of the arguments to the function, if any.</summary>
|
||||
@Nullable
|
||||
private final KernelFunctionArguments arguments;
|
||||
|
||||
/**
|
||||
* Creates a new instance of the {@link OpenAIFunctionToolCall} class.
|
||||
*
|
||||
* @param id The ID of the tool call.
|
||||
* @param pluginName The name of the plugin with which this function is associated, if any.
|
||||
* @param functionName The name of the function.
|
||||
* @param arguments A name/value collection of the arguments to the function, if any.
|
||||
*/
|
||||
public OpenAIFunctionToolCall(
|
||||
@Nullable String id,
|
||||
@Nullable String pluginName,
|
||||
String functionName,
|
||||
@Nullable KernelFunctionArguments arguments) {
|
||||
this.id = id;
|
||||
this.pluginName = pluginName;
|
||||
this.functionName = functionName;
|
||||
if (arguments == null) {
|
||||
this.arguments = null;
|
||||
} else {
|
||||
this.arguments = arguments.copy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ID of the tool call.
|
||||
*
|
||||
* @return The ID of the tool call.
|
||||
*/
|
||||
@Nullable
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the plugin with which this function is associated, if any.
|
||||
*
|
||||
* @return The name of the plugin with which this function is associated, if any.
|
||||
*/
|
||||
@Nullable
|
||||
public String getPluginName() {
|
||||
return pluginName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the function.
|
||||
*
|
||||
* @return The name of the function.
|
||||
*/
|
||||
public String getFunctionName() {
|
||||
return functionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a name/value collection of the arguments to the function, if any.
|
||||
*
|
||||
* @return A name/value collection of the arguments to the function, if any.
|
||||
*/
|
||||
@Nullable
|
||||
public KernelFunctionArguments getArguments() {
|
||||
if (arguments == null) {
|
||||
return null;
|
||||
}
|
||||
return arguments.copy();
|
||||
}
|
||||
}
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.aiservices.openai.chatcompletion;
|
||||
|
||||
import com.azure.ai.openai.models.ChatRequestMessage;
|
||||
import com.azure.ai.openai.models.FunctionDefinition;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
class ParsedPrompt {
|
||||
|
||||
private final List<ChatRequestMessage> chatRequestMessages;
|
||||
private final List<FunctionDefinition> functions;
|
||||
|
||||
protected ParsedPrompt(List<ChatRequestMessage> parsedMessages,
|
||||
@Nullable List<FunctionDefinition> parsedFunctions) {
|
||||
this.chatRequestMessages = parsedMessages;
|
||||
if (parsedFunctions == null) {
|
||||
parsedFunctions = new ArrayList<>();
|
||||
}
|
||||
this.functions = parsedFunctions;
|
||||
}
|
||||
|
||||
public List<ChatRequestMessage> getChatRequestMessages() {
|
||||
return chatRequestMessages;
|
||||
}
|
||||
|
||||
public List<FunctionDefinition> getFunctions() {
|
||||
return functions;
|
||||
}
|
||||
}
|
||||
-273
@@ -1,273 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.aiservices.openai.chatcompletion;
|
||||
|
||||
import com.azure.ai.openai.models.ChatRequestAssistantMessage;
|
||||
import com.azure.ai.openai.models.ChatRequestFunctionMessage;
|
||||
import com.azure.ai.openai.models.ChatRequestMessage;
|
||||
import com.azure.ai.openai.models.ChatRequestSystemMessage;
|
||||
import com.azure.ai.openai.models.ChatRequestToolMessage;
|
||||
import com.azure.ai.openai.models.ChatRequestUserMessage;
|
||||
import com.azure.ai.openai.models.FunctionDefinition;
|
||||
import com.azure.core.util.BinaryData;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.microsoft.semantickernel.exceptions.SKException;
|
||||
import com.microsoft.semantickernel.orchestration.ToolCallBehavior;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.AuthorRole;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.XMLInputFactory;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.events.Attribute;
|
||||
import javax.xml.stream.events.StartElement;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
class XMLPromptParser {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(XMLPromptParser.class);
|
||||
|
||||
public static ParsedPrompt parse(String rawPrompt) {
|
||||
List<String> prompts = Arrays.asList(
|
||||
rawPrompt,
|
||||
"<prompt>" + rawPrompt + "</prompt>");
|
||||
|
||||
for (String prompt : prompts) {
|
||||
try {
|
||||
List<ChatRequestMessage> parsedMessages = getChatRequestMessages(prompt);
|
||||
List<FunctionDefinition> parsedFunctions = getFunctionDefinitions(prompt);
|
||||
|
||||
if (!parsedMessages.isEmpty()) {
|
||||
return new ParsedPrompt(parsedMessages, parsedFunctions);
|
||||
}
|
||||
} catch (SKException e) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
|
||||
ChatRequestUserMessage message = new ChatRequestUserMessage(rawPrompt);
|
||||
|
||||
if (message.getName() == null) {
|
||||
message.setName(UUID.randomUUID().toString());
|
||||
}
|
||||
|
||||
return new ParsedPrompt(Collections.singletonList(message), null);
|
||||
}
|
||||
|
||||
private static List<ChatRequestMessage> getChatRequestMessages(String prompt) {
|
||||
|
||||
// TODO: XML parsing should be done as a chain of XMLEvent handlers.
|
||||
// If one handler does not recognize the element, it should pass it to the next handler.
|
||||
// In this way, we can avoid parsing the whole prompt twice and easily extend the parsing logic.
|
||||
List<ChatRequestMessage> messages = new ArrayList<>();
|
||||
try (InputStream is = new ByteArrayInputStream(prompt.getBytes(StandardCharsets.UTF_8))) {
|
||||
XMLInputFactory factory = XMLInputFactory.newInstance();
|
||||
XMLEventReader reader = factory.createXMLEventReader(is);
|
||||
while (reader.hasNext()) {
|
||||
XMLEvent event = reader.nextEvent();
|
||||
if (event.isStartElement()) {
|
||||
String name = getElementName(event);
|
||||
if (name.equals("message")) {
|
||||
String role = getAttributeValue(event, "role");
|
||||
String content = reader.getElementText();
|
||||
messages.add(getChatRequestMessage(role, content));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException | XMLStreamException | IllegalArgumentException e) {
|
||||
throw new SKException("Failed to parse messages");
|
||||
}
|
||||
return messages;
|
||||
}
|
||||
|
||||
private static List<FunctionDefinition> getFunctionDefinitions(String prompt) {
|
||||
// TODO: XML parsing should be done as a chain of XMLEvent handlers. See previous remark.
|
||||
// <function pluginName=\"%s\" name=\"%s\" description=\"%s\">
|
||||
// <parameter name=\"%s\" description=\"%s\" defaultValue=\"%s\" isRequired=\"%s\" type=\"%s\"/>...
|
||||
// </function>
|
||||
List<FunctionDefinition> functionDefinitions = new ArrayList<>();
|
||||
try (InputStream is = new ByteArrayInputStream(prompt.getBytes(StandardCharsets.UTF_8))) {
|
||||
XMLInputFactory factory = XMLInputFactory.newFactory();
|
||||
XMLEventReader reader = factory.createXMLEventReader(is);
|
||||
FunctionDefinition functionDefinition = null;
|
||||
Map<String, String> parameters = new HashMap<>();
|
||||
List<String> requiredParameters = new ArrayList<>();
|
||||
while (reader.hasNext()) {
|
||||
XMLEvent event = reader.nextEvent();
|
||||
if (event.isStartElement()) {
|
||||
String elementName = getElementName(event);
|
||||
if (elementName.equals("function")) {
|
||||
assert functionDefinition == null;
|
||||
assert parameters.isEmpty();
|
||||
assert requiredParameters.isEmpty();
|
||||
String pluginName = getAttributeValue(event, "pluginName");
|
||||
String name = getAttributeValue(event, "name");
|
||||
String description = getAttributeValue(event, "description");
|
||||
// name has to match '^[a-zA-Z0-9_-]{1,64}$'
|
||||
functionDefinition = new FunctionDefinition(
|
||||
ToolCallBehavior.formFullFunctionName(pluginName, name))
|
||||
.setDescription(description);
|
||||
} else if (elementName.equals("parameter")) {
|
||||
String name = getAttributeValue(event, "name");
|
||||
String type = getAttributeValue(event, "type").toLowerCase(Locale.ROOT);
|
||||
String description = getAttributeValue(event, "description");
|
||||
parameters.put(name,
|
||||
String.format("{\"type\": \"%s\", \"description\": \"%s\"}",
|
||||
"string",
|
||||
description));
|
||||
|
||||
String isRequired = getAttributeValue(event, "isRequired");
|
||||
if (Boolean.parseBoolean(isRequired)) {
|
||||
requiredParameters.add(name);
|
||||
}
|
||||
}
|
||||
} else if (event.isEndElement()) {
|
||||
String elementName = getElementName(event);
|
||||
if (elementName.equals("function")) {
|
||||
// Example JSON Schema:
|
||||
// {
|
||||
// "type": "function",
|
||||
// "function": {
|
||||
// "name": "get_current_weather",
|
||||
// "description": "Get the current weather in a given location",
|
||||
// "parameters": {
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "location": {
|
||||
// "type": "string",
|
||||
// "description": "The city and state, e.g. San Francisco, CA",
|
||||
// },
|
||||
// "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
|
||||
// },
|
||||
// "required": ["location"],
|
||||
// },
|
||||
// },
|
||||
//}
|
||||
if (functionDefinition == null) {
|
||||
throw new SKException("Failed to parse function definition");
|
||||
}
|
||||
if (!parameters.isEmpty()) {
|
||||
StringBuilder sb = new StringBuilder(
|
||||
"{\"type\": \"object\", \"properties\": {");
|
||||
parameters.forEach((name, value) -> {
|
||||
// make "param": {"type": "string", "description": "desc"},
|
||||
sb.append(String.format("\"%s\": %s,", name, value));
|
||||
});
|
||||
// strip off trailing comma and close the properties object
|
||||
sb.replace(sb.length() - 1, sb.length(), "}");
|
||||
if (!requiredParameters.isEmpty()) {
|
||||
sb.append(", \"required\": [");
|
||||
requiredParameters.forEach(name -> {
|
||||
sb.append(String.format("\"%s\",", name));
|
||||
});
|
||||
// strip off trailing comma and close the required array
|
||||
sb.replace(sb.length() - 1, sb.length(), "]");
|
||||
}
|
||||
// close the object
|
||||
sb.append("}");
|
||||
//System.out.println(sb.toString());
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
JsonNode jsonNode = objectMapper.readTree(sb.toString());
|
||||
BinaryData binaryData = BinaryData.fromObject(jsonNode);
|
||||
functionDefinition.setParameters(binaryData);
|
||||
}
|
||||
functionDefinitions.add(functionDefinition);
|
||||
functionDefinition = null;
|
||||
parameters.clear();
|
||||
requiredParameters.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException | XMLStreamException | IllegalArgumentException e) {
|
||||
LOGGER.error("Error parsing prompt", e);
|
||||
}
|
||||
return functionDefinitions;
|
||||
}
|
||||
|
||||
private static String getElementName(XMLEvent xmlEvent) {
|
||||
if (xmlEvent.isStartElement()) {
|
||||
return xmlEvent.asStartElement().getName().getLocalPart();
|
||||
} else if (xmlEvent.isEndElement()) {
|
||||
return xmlEvent.asEndElement().getName().getLocalPart();
|
||||
}
|
||||
// TODO: programmer's error - log at debug
|
||||
return "";
|
||||
}
|
||||
|
||||
private static String getAttributeValue(XMLEvent xmlEvent, String attributeName) {
|
||||
if (xmlEvent.isStartElement()) {
|
||||
StartElement element = xmlEvent.asStartElement();
|
||||
Attribute attribute = element.getAttributeByName(QName.valueOf(attributeName));
|
||||
return attribute != null ? attribute.getValue() : "";
|
||||
}
|
||||
// TODO: programmer's error - log at debug
|
||||
return "";
|
||||
}
|
||||
|
||||
private static ChatRequestMessage getChatRequestMessage(
|
||||
String role,
|
||||
String content) {
|
||||
try {
|
||||
AuthorRole authorRole = AuthorRole.valueOf(role.toUpperCase(Locale.ROOT));
|
||||
return OpenAIChatCompletion.getChatRequestMessage(authorRole, content);
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOGGER.debug("Unknown author role: " + role);
|
||||
throw new SKException("Unknown author role: " + role);
|
||||
}
|
||||
}
|
||||
|
||||
public static ChatRequestMessage unescapeRequest(ChatRequestMessage message) {
|
||||
if (message instanceof ChatRequestUserMessage) {
|
||||
ChatRequestUserMessage chatRequestMessage = (ChatRequestUserMessage) message;
|
||||
String content = StringEscapeUtils.unescapeXml(
|
||||
chatRequestMessage.getContent().toString());
|
||||
|
||||
return new ChatRequestUserMessage(content)
|
||||
.setName(chatRequestMessage.getName());
|
||||
} else if (message instanceof ChatRequestSystemMessage) {
|
||||
ChatRequestSystemMessage chatRequestMessage = (ChatRequestSystemMessage) message;
|
||||
String content = StringEscapeUtils.unescapeXml(chatRequestMessage.getContent());
|
||||
|
||||
return new ChatRequestSystemMessage(content)
|
||||
.setName(chatRequestMessage.getName());
|
||||
} else if (message instanceof ChatRequestAssistantMessage) {
|
||||
ChatRequestAssistantMessage chatRequestMessage = (ChatRequestAssistantMessage) message;
|
||||
String content = StringEscapeUtils.unescapeXml(chatRequestMessage.getContent());
|
||||
|
||||
return new ChatRequestAssistantMessage(content)
|
||||
.setToolCalls(chatRequestMessage.getToolCalls())
|
||||
.setFunctionCall(chatRequestMessage.getFunctionCall())
|
||||
.setName(chatRequestMessage.getName());
|
||||
} else if (message instanceof ChatRequestFunctionMessage) {
|
||||
ChatRequestFunctionMessage chatRequestMessage = (ChatRequestFunctionMessage) message;
|
||||
String content = StringEscapeUtils.unescapeXml(chatRequestMessage.getContent());
|
||||
|
||||
return new ChatRequestFunctionMessage(
|
||||
chatRequestMessage.getName(),
|
||||
content);
|
||||
} else if (message instanceof ChatRequestToolMessage) {
|
||||
ChatRequestToolMessage chatRequestMessage = (ChatRequestToolMessage) message;
|
||||
String content = StringEscapeUtils.unescapeXml(chatRequestMessage.getContent());
|
||||
|
||||
return new ChatRequestToolMessage(
|
||||
content,
|
||||
chatRequestMessage.getToolCallId());
|
||||
}
|
||||
|
||||
throw new SKException("Unknown message type: " + message.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
-58
@@ -1,58 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.aiservices.openai.implementation;
|
||||
|
||||
import com.azure.core.http.HttpHeaderName;
|
||||
import com.azure.core.http.rest.RequestOptions;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
/**
|
||||
* Provides Http request settings for OpenAI requests.
|
||||
*/
|
||||
public final class OpenAIRequestSettings {
|
||||
|
||||
private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger(
|
||||
OpenAIRequestSettings.class);
|
||||
|
||||
private static final String SEMANTIC_KERNEL_VERSION_PROPERTY_NAME = "semantic-kernel.version";
|
||||
private static final String SEMANTIC_KERNEL_VERSION_PROPERTIES_FILE = "semantic-kernel-version.properties";
|
||||
private static final String version;
|
||||
|
||||
static {
|
||||
version = loadVersion();
|
||||
}
|
||||
|
||||
private static String loadVersion() {
|
||||
|
||||
String version = "Java/unknown";
|
||||
|
||||
try (InputStream settingsFile = OpenAIRequestSettings.class.getResourceAsStream(
|
||||
SEMANTIC_KERNEL_VERSION_PROPERTIES_FILE)) {
|
||||
|
||||
Properties props = new Properties();
|
||||
props.load(settingsFile);
|
||||
if (props.containsKey(SEMANTIC_KERNEL_VERSION_PROPERTY_NAME)) {
|
||||
String skVersion = props.getProperty(SEMANTIC_KERNEL_VERSION_PROPERTY_NAME);
|
||||
if (skVersion != null && !skVersion.isEmpty()) {
|
||||
return "Java/" + skVersion;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
//Ignore
|
||||
LOGGER.trace("Failed to load Semantic Kernel version from properties file", e);
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTTP request options for OpenAI requests.
|
||||
*
|
||||
* @return The request options
|
||||
*/
|
||||
public static RequestOptions getRequestOptions() {
|
||||
return new RequestOptions()
|
||||
.setHeader(HttpHeaderName.fromString("Semantic-Kernel-Version"), version);
|
||||
}
|
||||
}
|
||||
-173
@@ -1,173 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.aiservices.openai.textcompletion;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.models.CompletionsOptions;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.aiservices.openai.OpenAiService;
|
||||
import com.microsoft.semantickernel.aiservices.openai.implementation.OpenAIRequestSettings;
|
||||
import com.microsoft.semantickernel.exceptions.AIException;
|
||||
import com.microsoft.semantickernel.exceptions.AIException.ErrorCodes;
|
||||
import com.microsoft.semantickernel.orchestration.FunctionResultMetadata;
|
||||
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
|
||||
import com.microsoft.semantickernel.services.textcompletion.StreamingTextContent;
|
||||
import com.microsoft.semantickernel.services.textcompletion.TextContent;
|
||||
import com.microsoft.semantickernel.services.textcompletion.TextGenerationService;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Nullable;
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* An OpenAI implementation of a {@link TextGenerationService}.
|
||||
*/
|
||||
public class OpenAITextGenerationService extends OpenAiService implements TextGenerationService {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(OpenAITextGenerationService.class);
|
||||
|
||||
/**
|
||||
* Creates a new {@link OpenAITextGenerationService}.
|
||||
*
|
||||
* @param client OpenAI client
|
||||
* @param modelId OpenAI model id
|
||||
* @param serviceId Service id
|
||||
*/
|
||||
protected OpenAITextGenerationService(
|
||||
OpenAIAsyncClient client,
|
||||
String modelId,
|
||||
@Nullable String serviceId,
|
||||
String deploymentName) {
|
||||
super(client, serviceId, modelId, deploymentName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a builder for creating a {@link OpenAITextGenerationService}.
|
||||
*
|
||||
* @return A new {@link OpenAITextGenerationService} builder.
|
||||
*/
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<List<TextContent>> getTextContentsAsync(
|
||||
String prompt,
|
||||
@Nullable PromptExecutionSettings executionSettings,
|
||||
@Nullable Kernel kernel) {
|
||||
return this.internalCompleteTextAsync(prompt, executionSettings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<StreamingTextContent> getStreamingTextContentsAsync(
|
||||
String prompt,
|
||||
@Nullable PromptExecutionSettings executionSettings,
|
||||
@Nullable Kernel kernel) {
|
||||
return this
|
||||
.internalCompleteTextAsync(prompt, executionSettings)
|
||||
.flatMapMany(it -> Flux.fromStream(it.stream())
|
||||
.map(StreamingTextContent::new));
|
||||
}
|
||||
|
||||
protected Mono<List<TextContent>> internalCompleteTextAsync(
|
||||
String text,
|
||||
@Nullable PromptExecutionSettings requestSettings) {
|
||||
|
||||
CompletionsOptions completionsOptions = getCompletionsOptions(text, requestSettings);
|
||||
|
||||
return getClient()
|
||||
.getCompletionsWithResponse(getDeploymentName(), completionsOptions,
|
||||
OpenAIRequestSettings.getRequestOptions())
|
||||
.flatMap(completionsResult -> {
|
||||
if (completionsResult.getStatusCode() >= 400) {
|
||||
return Mono.error(new AIException(ErrorCodes.SERVICE_ERROR,
|
||||
"Request failed: " + completionsResult.getStatusCode()));
|
||||
}
|
||||
return Mono.just(completionsResult.getValue());
|
||||
})
|
||||
.map(completions -> {
|
||||
FunctionResultMetadata metadata = FunctionResultMetadata.build(
|
||||
completions.getId(),
|
||||
completions.getUsage(),
|
||||
completions.getCreatedAt());
|
||||
|
||||
return completions
|
||||
.getChoices()
|
||||
.stream()
|
||||
.map(choice -> {
|
||||
return new TextContent(
|
||||
choice.getText(),
|
||||
completionsOptions.getModel(),
|
||||
metadata);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
||||
private CompletionsOptions getCompletionsOptions(
|
||||
String text,
|
||||
@Nullable PromptExecutionSettings requestSettings) {
|
||||
text = StringEscapeUtils.unescapeXml(text);
|
||||
|
||||
if (requestSettings == null) {
|
||||
return new CompletionsOptions(Collections.singletonList(text))
|
||||
.setMaxTokens(PromptExecutionSettings.DEFAULT_MAX_TOKENS);
|
||||
}
|
||||
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))
|
||||
.setMaxTokens(requestSettings.getMaxTokens())
|
||||
.setTemperature(requestSettings.getTemperature())
|
||||
.setTopP(requestSettings.getTopP())
|
||||
.setFrequencyPenalty(requestSettings.getFrequencyPenalty())
|
||||
.setPresencePenalty(requestSettings.getPresencePenalty())
|
||||
.setModel(getModelId())
|
||||
.setN(requestSettings.getResultsPerPrompt())
|
||||
.setUser(requestSettings.getUser())
|
||||
.setBestOf(requestSettings.getBestOf())
|
||||
.setLogitBias(new HashMap<>());
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for a TextGenerationService
|
||||
*/
|
||||
public static class Builder extends TextGenerationService.Builder {
|
||||
|
||||
@Override
|
||||
public TextGenerationService build() {
|
||||
|
||||
if (this.client == null) {
|
||||
throw new AIException(AIException.ErrorCodes.INVALID_REQUEST,
|
||||
"OpenAI client must be provided");
|
||||
}
|
||||
if (this.modelId == null) {
|
||||
throw new AIException(AIException.ErrorCodes.INVALID_REQUEST,
|
||||
"OpenAI model id must be provided");
|
||||
}
|
||||
if (deploymentName == null) {
|
||||
LOGGER.debug("Deployment name is not provided, using model id as deployment name");
|
||||
deploymentName = modelId;
|
||||
}
|
||||
|
||||
return new OpenAITextGenerationService(
|
||||
this.client,
|
||||
this.modelId,
|
||||
this.serviceId,
|
||||
this.deploymentName);
|
||||
}
|
||||
}
|
||||
}
|
||||
-1
@@ -1 +0,0 @@
|
||||
com.microsoft.semantickernel.aiservices.openai.audio.OpenAiAudioToTextService$Builder
|
||||
-1
@@ -1 +0,0 @@
|
||||
com.microsoft.semantickernel.aiservices.openai.audio.OpenAiTextToAudioService$Builder
|
||||
-1
@@ -1 +0,0 @@
|
||||
com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion$Builder
|
||||
-1
@@ -1 +0,0 @@
|
||||
com.microsoft.semantickernel.aiservices.openai.textcompletion.OpenAITextGenerationService$Builder
|
||||
-1
@@ -1 +0,0 @@
|
||||
semantic-kernel.version=${project.version}
|
||||
-123
@@ -1,123 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.aiservices.openai.chatcompletion;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.models.ChatCompletions;
|
||||
import com.azure.ai.openai.models.ChatCompletionsFunctionToolCall;
|
||||
import com.azure.ai.openai.models.ChatCompletionsOptions;
|
||||
import com.azure.ai.openai.models.ChatRequestAssistantMessage;
|
||||
import com.azure.core.http.HttpHeaders;
|
||||
import com.azure.core.http.HttpRequest;
|
||||
import com.azure.core.http.rest.Response;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.microsoft.semantickernel.implementation.EmbeddedResourceLoader;
|
||||
import com.microsoft.semantickernel.orchestration.FunctionResultMetadata;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.AuthorRole;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatHistory;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public class OpenAiChatCompletionTest {
|
||||
|
||||
@Test
|
||||
public void serializesToolCallsCorrectly() {
|
||||
OpenAIAsyncClient client = Mockito.mock(OpenAIAsyncClient.class);
|
||||
OpenAIChatCompletion chatCompletion = mockClient(client);
|
||||
|
||||
ChatHistory chatHistory = new ChatHistory();
|
||||
|
||||
chatHistory.addUserMessage(
|
||||
"What is the name of the pet with id ca2fc6bc-1307-4da6-a009-d7bf88dec37b?");
|
||||
|
||||
chatHistory.addMessage(new OpenAIChatMessageContent(
|
||||
AuthorRole.ASSISTANT,
|
||||
"",
|
||||
"test",
|
||||
null,
|
||||
Charset.defaultCharset(),
|
||||
null,
|
||||
Arrays.asList(
|
||||
new OpenAIFunctionToolCall(
|
||||
"a-tool-id",
|
||||
"pluginName",
|
||||
"funcName",
|
||||
KernelFunctionArguments.builder()
|
||||
.withVariable("id", "ca2fc6bc-1307-4da6-a009-d7bf88dec37b")
|
||||
.build()))));
|
||||
chatHistory.addMessage(new OpenAIChatMessageContent(
|
||||
AuthorRole.TOOL,
|
||||
"Snuggles",
|
||||
"test",
|
||||
null,
|
||||
Charset.defaultCharset(),
|
||||
FunctionResultMetadata.build("a-tool-id"),
|
||||
null));
|
||||
|
||||
chatCompletion
|
||||
.getChatMessageContentsAsync(chatHistory, null, null).block();
|
||||
|
||||
Mockito.verify(client, Mockito.times(1))
|
||||
.getChatCompletionsWithResponse(
|
||||
Mockito.any(),
|
||||
Mockito.<ChatCompletionsOptions>argThat(options -> {
|
||||
ChatRequestAssistantMessage message = ((ChatRequestAssistantMessage) options
|
||||
.getMessages()
|
||||
.get(1));
|
||||
ChatCompletionsFunctionToolCall toolcall = ((ChatCompletionsFunctionToolCall) message
|
||||
.getToolCalls()
|
||||
.get(0));
|
||||
return toolcall
|
||||
.getFunction()
|
||||
.getArguments()
|
||||
.equals("{\"id\": \"ca2fc6bc-1307-4da6-a009-d7bf88dec37b\"}");
|
||||
}),
|
||||
Mockito.any());
|
||||
}
|
||||
|
||||
private static OpenAIChatCompletion mockClient(OpenAIAsyncClient client) {
|
||||
Mockito.when(client.getChatCompletionsWithResponse(Mockito.any(),
|
||||
Mockito.<ChatCompletionsOptions>any(), Mockito.any()))
|
||||
.thenReturn(Mono.just(
|
||||
new Response<ChatCompletions>() {
|
||||
@Override
|
||||
public int getStatusCode() {
|
||||
return 200;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders getHeaders() {
|
||||
return new HttpHeaders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpRequest getRequest() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChatCompletions getValue() {
|
||||
try {
|
||||
String message = EmbeddedResourceLoader.readFile("chatCompletion.txt",
|
||||
OpenAiChatCompletionTest.class);
|
||||
|
||||
return new ObjectMapper()
|
||||
.readValue(String.format(message, "Snuggles"),
|
||||
ChatCompletions.class);
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}));
|
||||
return new OpenAIChatCompletion(
|
||||
client,
|
||||
"test",
|
||||
"test",
|
||||
"test");
|
||||
}
|
||||
|
||||
}
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
{
|
||||
"choices" : [
|
||||
{
|
||||
"content_filter_results" : {
|
||||
"hate" : {
|
||||
"filtered" : false,
|
||||
"severity" : "safe"
|
||||
},
|
||||
"self_harm" : {
|
||||
"filtered" : false,
|
||||
"severity" : "safe"
|
||||
},
|
||||
"sexual" : {
|
||||
"filtered" : false,
|
||||
"severity" : "safe"
|
||||
},
|
||||
"violence" : {
|
||||
"filtered" : false,
|
||||
"severity" : "safe"
|
||||
}
|
||||
},
|
||||
"finish_reason" : "stop",
|
||||
"index" : 0,
|
||||
"message" : {
|
||||
"content" : "%s",
|
||||
"role" : "assistant"
|
||||
}
|
||||
}
|
||||
],
|
||||
"created" : 1707253039,
|
||||
"id" : "chatcmpl-xxx",
|
||||
"prompt_filter_results" : [
|
||||
{
|
||||
"content_filter_results" : {
|
||||
"hate" : {
|
||||
"filtered" : false,
|
||||
"severity" : "safe"
|
||||
},
|
||||
"self_harm" : {
|
||||
"filtered" : false,
|
||||
"severity" : "safe"
|
||||
},
|
||||
"sexual" : {
|
||||
"filtered" : false,
|
||||
"severity" : "safe"
|
||||
},
|
||||
"violence" : {
|
||||
"filtered" : false,
|
||||
"severity" : "safe"
|
||||
}
|
||||
},
|
||||
"prompt_index" : 0
|
||||
}
|
||||
],
|
||||
"usage" : {
|
||||
"completion_tokens" : 131,
|
||||
"prompt_tokens" : 26,
|
||||
"total_tokens" : 157
|
||||
}
|
||||
}
|
||||
@@ -1,187 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>api-test</artifactId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<name>Semantic Kernel Integration Tests</name>
|
||||
<artifactId>integration-tests</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-syntax-examples</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j2-impl</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
<artifactId>sqlite-jdbc</artifactId>
|
||||
<version>3.44.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<version>8.2.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>mysql</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.wiremock</groupId>
|
||||
<artifactId>wiremock</artifactId>
|
||||
<version>3.3.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>testcontainers-bom</artifactId>
|
||||
<version>1.18.3</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>exec</goal>
|
||||
</goals>
|
||||
<id>recordmappings</id>
|
||||
<configuration>
|
||||
<executable>java</executable>
|
||||
<arguments>
|
||||
<argument>-Djavax.net.ssl.trustStore=scripts/client.truststore</argument>
|
||||
<argument>-Djavax.net.ssl.trustStorePassword=password</argument>
|
||||
</arguments>
|
||||
<mainClass>com.microsoft.semantickernel.syntaxexamples.WiremockRecord</mainClass>
|
||||
<classpathScope>test</classpathScope>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>run-wiremocks</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>exec</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<executable>./generateCert.sh</executable>
|
||||
<workingDirectory>scripts</workingDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.2.5</version>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>**/WiremockExamplesIT.java</include>
|
||||
</includes>
|
||||
<reuseForks>false</reuseForks>
|
||||
<forkCount>1</forkCount>
|
||||
<argLine>
|
||||
-Djavax.net.ssl.trustStore=scripts/client.truststore
|
||||
-Djavax.net.ssl.trustStorePassword=password
|
||||
</argLine>
|
||||
<environmentVariables>
|
||||
<AZURE_CLIENT_KEY>foo</AZURE_CLIENT_KEY>
|
||||
<CLIENT_ENDPOINT>https://localhost:8443/</CLIENT_ENDPOINT>
|
||||
<PLUGIN_DIR>../../../</PLUGIN_DIR>
|
||||
</environmentVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
|
||||
</project>
|
||||
@@ -1,35 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
KEYTOOL_ARGS="-noprompt -srcstorepass password -deststorepass password -srckeypass password"
|
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
cd $SCRIPT_DIR
|
||||
|
||||
if [ -f client.keystore ]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
rm client.keystore client.truststore server.keystore server.truststore || true
|
||||
|
||||
openssl genrsa -out diagserverCA.key 2048
|
||||
openssl req -x509 -new -nodes -key diagserverCA.key -sha256 -days 1024 -out diagserverCA.pem -subj "/C=US/ST=NA/L=NA/O=NA/OU=NA/CN=localhost"
|
||||
openssl pkcs12 -export -name server-cert -password pass:password -in diagserverCA.pem -inkey diagserverCA.key -out serverkeystore.p12
|
||||
|
||||
openssl genrsa -out diagclientCA.key 2048
|
||||
openssl req -x509 -new -nodes -key diagclientCA.key -sha256 -days 1024 -out diagclientCA.pem -subj "/C=US/ST=NA/L=NA/O=NA/OU=NA/CN=localhost"
|
||||
openssl pkcs12 -export -name client-cert -password pass:password -in diagclientCA.pem -inkey diagclientCA.key -out clientkeystore.p12
|
||||
|
||||
|
||||
keytool -importkeystore $KEYTOOL_ARGS -destkeystore server.keystore -srckeystore serverkeystore.p12 -srcstoretype pkcs12 -alias server-cert
|
||||
keytool -import $KEYTOOL_ARGS -alias client-cert -file diagclientCA.pem -keystore server.truststore
|
||||
keytool -import $KEYTOOL_ARGS -alias server-cert -file diagserverCA.pem -keystore server.truststore
|
||||
|
||||
|
||||
keytool -importkeystore $KEYTOOL_ARGS -destkeystore client.keystore -srckeystore clientkeystore.p12 -srcstoretype pkcs12 -alias client-cert
|
||||
keytool -import $KEYTOOL_ARGS -alias server-cert -file diagserverCA.pem -keystore client.truststore
|
||||
keytool -import $KEYTOOL_ARGS -alias client-cert -file diagclientCA.pem -keystore client.truststore
|
||||
|
||||
keytool -importkeystore -srckeystore /usr/lib/jvm/default-java/lib/security/cacerts -destkeystore client.truststore -srcstorepass changeit -deststorepass password
|
||||
keytool -importkeystore -srckeystore /usr/lib/jvm/default-java/lib/security/cacerts -destkeystore server.truststore -srcstorepass changeit -deststorepass password
|
||||
|
||||
rm diagclientCA.key diagserverCA.pem clientkeystore.p12 diagclientCA.pem serverkeystore.p12 diagserverCA.key || true
|
||||
@@ -1,34 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Run this from the api-test/integration-tests directory
|
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
ROOT_DIR="$SCRIPT_DIR/.."
|
||||
|
||||
cd $SCRIPT_DIR
|
||||
|
||||
if [ ! -f client.truststore ]; then
|
||||
./generateCert.sh
|
||||
fi
|
||||
|
||||
rm -r "$ROOT_DIR/target/wiremock/mappings" || true
|
||||
rm -r "$ROOT_DIR/src/test/resources/wiremock/mappings/" || true
|
||||
mkdir -p "$ROOT_DIR/target/wiremock/mappings"
|
||||
mkdir -p "$ROOT_DIR/src/test/resources/wiremock/mappings/"
|
||||
|
||||
cd $ROOT_DIR
|
||||
source "$ROOT_DIR/../../.env.record"
|
||||
export AZURE_CLIENT_KEY
|
||||
export CLIENT_ENDPOINT
|
||||
export PLUGIN_DIR="$ROOT_DIR/../../../"
|
||||
|
||||
../../mvnw clean package -DskipTests -Pcompile-jdk17
|
||||
|
||||
MAVEN_OPTS="-Djavax.net.ssl.trustStore=scripts/client.truststore -Djavax.net.ssl.trustStorePassword=password" \
|
||||
../../mvnw exec:java@recordmappings -Pcompile-jdk17
|
||||
|
||||
for f in $ROOT_DIR/target/wiremock/mappings/*.json; do
|
||||
cat $f | jq 'del(.response.headers[])' > /tmp/mapping.json
|
||||
cat /tmp/mapping.json | json_pp > $f
|
||||
mv $f src/test/resources/wiremock/mappings/
|
||||
done
|
||||
@@ -1,15 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
ROOT_DIR="$SCRIPT_DIR/.."
|
||||
|
||||
cd $SCRIPT_DIR
|
||||
|
||||
if [ ! -f client.truststore ]; then
|
||||
./generateCert.sh
|
||||
fi
|
||||
|
||||
|
||||
cd $ROOT_DIR
|
||||
|
||||
../../mvnw clean test -Dtest=WiremockExamplesIT -Prun-wiremocks
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.tests;
|
||||
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class Example01NativeFunctionsTest {
|
||||
|
||||
private static class TextPlugin {
|
||||
|
||||
@DefineKernelFunction(description = "Change all string chars to uppercase.", name = "Uppercase")
|
||||
public String uppercase(
|
||||
@KernelFunctionParameter(description = "Text to uppercase", name = "input") String text) {
|
||||
return text.toUpperCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void run() {
|
||||
// Load native plugin
|
||||
TextPlugin text = new TextPlugin();
|
||||
|
||||
// Use function without kernel
|
||||
String result = text.uppercase("ciao!");
|
||||
|
||||
Assertions.assertEquals("CIAO!", result);
|
||||
}
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.tests;
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.orchestration.FunctionResult;
|
||||
import com.microsoft.semantickernel.plugin.KernelPlugin;
|
||||
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example03_Arguments.StaticTextPlugin;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Demonstrates running a pipeline (a sequence of functions) on a
|
||||
* {@code com.microsoft.semantickernel.orchestration.SKContext}
|
||||
*/
|
||||
public class Example03_ArgumentsTest {
|
||||
|
||||
@Test
|
||||
public void main() {
|
||||
Kernel kernel = Kernel.builder().build();
|
||||
|
||||
// Load native plugin
|
||||
KernelPlugin functionCollection = KernelPluginFactory
|
||||
.createFromObject(new StaticTextPlugin(), "text");
|
||||
|
||||
KernelFunctionArguments arguments = KernelFunctionArguments.builder()
|
||||
.withInput("Today is: ")
|
||||
.withVariable("day", "Monday")
|
||||
.build();
|
||||
|
||||
FunctionResult<String> resultValue = kernel.invokeAsync(
|
||||
functionCollection.<String>get("AppendDay"))
|
||||
.withArguments(arguments)
|
||||
.block();
|
||||
|
||||
Assertions.assertEquals("Today is: Monday", resultValue.getResult());
|
||||
}
|
||||
}
|
||||
-107
@@ -1,107 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.tests;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.OpenAIClientBuilder;
|
||||
import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
|
||||
import com.github.tomakehurst.wiremock.junit5.WireMockTest;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.orchestration.FunctionResult;
|
||||
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
|
||||
import com.microsoft.semantickernel.services.textcompletion.TextGenerationService;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@WireMockTest
|
||||
public class Example05_InlineFunctionDefinitionTest {
|
||||
|
||||
@Test
|
||||
public void main(WireMockRuntimeInfo wmRuntimeInfo) {
|
||||
final OpenAIAsyncClient client = new OpenAIClientBuilder()
|
||||
.endpoint("http://localhost:" + wmRuntimeInfo.getHttpPort())
|
||||
.buildAsyncClient();
|
||||
|
||||
TextGenerationService textGenerationService = TextGenerationService.builder()
|
||||
.withOpenAIAsyncClient(client)
|
||||
.withModelId("text-davinci-003")
|
||||
.build();
|
||||
|
||||
Kernel kernel = Kernel.builder()
|
||||
.withAIService(TextGenerationService.class, textGenerationService)
|
||||
.build();
|
||||
|
||||
System.out.println("======== Inline Function Definition ========");
|
||||
|
||||
// Function defined using few-shot design pattern
|
||||
String promptTemplate = """
|
||||
Generate a creative reason or excuse for the given event.
|
||||
Be creative and be funny. Let your imagination run wild.
|
||||
|
||||
Event: I am running late.
|
||||
Excuse: I was being held ransom by giraffe gangsters.
|
||||
|
||||
Event: I haven't been to the gym for a year
|
||||
Excuse: I've been too busy training my pet dragon.
|
||||
|
||||
Event: {{$input}}
|
||||
""".stripIndent();
|
||||
|
||||
var excuseFunction = new KernelFunctionFromPrompt.Builder<String>()
|
||||
.withName("Excuse")
|
||||
.withTemplate(promptTemplate)
|
||||
.withDefaultExecutionSettings(
|
||||
new PromptExecutionSettings.Builder()
|
||||
.withTemperature(0.4)
|
||||
.withTopP(1)
|
||||
.withMaxTokens(100)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
WireMockUtil.mockCompletionResponse("I missed the F1 final race", "a-response");
|
||||
|
||||
var result = kernel.invokeAsync(excuseFunction)
|
||||
.withArguments(
|
||||
KernelFunctionArguments.builder()
|
||||
.withInput("I missed the F1 final race")
|
||||
.build())
|
||||
.block();
|
||||
|
||||
Assertions.assertEquals("a-response", result.getResult());
|
||||
|
||||
WireMockUtil.mockCompletionResponse("sorry I forgot your birthday", "a-response-2");
|
||||
|
||||
result = kernel.invokeAsync(excuseFunction)
|
||||
.withArguments(
|
||||
KernelFunctionArguments.builder()
|
||||
.withInput("sorry I forgot your birthday")
|
||||
.build())
|
||||
.block();
|
||||
|
||||
Assertions.assertEquals("a-response-2", result.getResult());
|
||||
|
||||
WireMockUtil.mockCompletionResponse("Translate this date ", "a-response-3");
|
||||
|
||||
var date = DateTimeFormatter.ISO_LOCAL_DATE.withZone(ZoneOffset.UTC)
|
||||
.format(Instant.ofEpochSecond(1));
|
||||
var message = "Translate this date " + date + " to French format";
|
||||
var fixedFunction = KernelFunction.<String>createFromPrompt(message)
|
||||
.withDefaultExecutionSettings(
|
||||
PromptExecutionSettings.builder()
|
||||
.withMaxTokens(100)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
FunctionResult<String> fixedFunctionResult = kernel
|
||||
.invokeAsync(fixedFunction)
|
||||
.block();
|
||||
|
||||
Assertions.assertEquals("a-response-3", fixedFunctionResult.getResult());
|
||||
|
||||
}
|
||||
}
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.tests;
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.plugin.KernelPlugin;
|
||||
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class ImportingMultiplePluginsTest {
|
||||
|
||||
@Test
|
||||
public void canImportMultiplePlugins() {
|
||||
KernelPlugin summarize = KernelPluginFactory.importPluginFromResourcesDirectory(
|
||||
"Plugins",
|
||||
"SummarizePlugin",
|
||||
"Summarize",
|
||||
null,
|
||||
String.class);
|
||||
|
||||
KernelPlugin topics = KernelPluginFactory.importPluginFromResourcesDirectory(
|
||||
"Plugins",
|
||||
"SummarizePlugin",
|
||||
"Topics",
|
||||
null,
|
||||
String.class);
|
||||
|
||||
KernelPlugin notegen = KernelPluginFactory.importPluginFromResourcesDirectory(
|
||||
"Plugins",
|
||||
"SummarizePlugin",
|
||||
"Notegen",
|
||||
null,
|
||||
String.class);
|
||||
|
||||
Kernel kernel = Kernel.builder()
|
||||
.withPlugin(summarize)
|
||||
.withPlugin(topics)
|
||||
.withPlugin(notegen)
|
||||
.build();
|
||||
|
||||
Assertions.assertEquals(3,
|
||||
kernel.getPlugin("SummarizePlugin").getFunctions().size());
|
||||
Assertions.assertEquals("Summarize",
|
||||
kernel.getPlugin("SummarizePlugin").get("Summarize").getName());
|
||||
Assertions.assertEquals("Topics",
|
||||
kernel.getPlugin("SummarizePlugin").get("Topics").getName());
|
||||
Assertions.assertEquals("Notegen",
|
||||
kernel.getPlugin("SummarizePlugin").get("Notegen").getName());
|
||||
|
||||
}
|
||||
}
|
||||
-103
@@ -1,103 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.tests;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.OpenAIClientBuilder;
|
||||
import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
|
||||
import com.github.tomakehurst.wiremock.junit5.WireMockTest;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.Kernel.Builder;
|
||||
import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion;
|
||||
import com.microsoft.semantickernel.hooks.KernelHook.FunctionInvokedHook;
|
||||
import com.microsoft.semantickernel.hooks.KernelHook.FunctionInvokingHook;
|
||||
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
|
||||
import com.microsoft.semantickernel.semanticfunctions.OutputVariable;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@WireMockTest
|
||||
public class KernelHooksTest {
|
||||
|
||||
private static Builder getKernelBuilder(WireMockRuntimeInfo wmRuntimeInfo) {
|
||||
final OpenAIAsyncClient client = new OpenAIClientBuilder()
|
||||
.endpoint("http://localhost:" + wmRuntimeInfo.getHttpPort())
|
||||
.buildAsyncClient();
|
||||
|
||||
ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder()
|
||||
.withModelId("text-davinci-003")
|
||||
.withOpenAIAsyncClient(client)
|
||||
.build();
|
||||
|
||||
return Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class, openAIChatCompletion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getUsageAsync(WireMockRuntimeInfo wmRuntimeInfo) {
|
||||
WireMockUtil.mockChatCompletionResponse("Write a random paragraph about", "a-response");
|
||||
Kernel kernel = getKernelBuilder(wmRuntimeInfo).build();
|
||||
|
||||
System.out.println("\n======== Get Usage Data ========\n");
|
||||
|
||||
// Initialize prompt
|
||||
String functionPrompt = "Write a random paragraph about: {{$input}}.";
|
||||
|
||||
KernelFunction<String> excuseFunction = KernelFunctionFromPrompt.builder()
|
||||
.withTemplate(functionPrompt)
|
||||
.withName("Excuse")
|
||||
.withDefaultExecutionSettings(PromptExecutionSettings
|
||||
.builder()
|
||||
.withMaxTokens(100)
|
||||
.withTemperature(0.4)
|
||||
.withTopP(1)
|
||||
.build())
|
||||
.withOutputVariable(new OutputVariable<>("result", String.class))
|
||||
.build();
|
||||
|
||||
AtomicBoolean preHookTriggered = new AtomicBoolean(false);
|
||||
|
||||
FunctionInvokingHook preHook = event -> {
|
||||
preHookTriggered.set(true);
|
||||
return event;
|
||||
};
|
||||
|
||||
AtomicBoolean removedPreExecutionHandlerTriggered = new AtomicBoolean(false);
|
||||
|
||||
FunctionInvokingHook removedPreExecutionHandler = event -> {
|
||||
removedPreExecutionHandlerTriggered.set(true);
|
||||
return event;
|
||||
};
|
||||
|
||||
AtomicBoolean postExecutionHandlerTriggered = new AtomicBoolean(false);
|
||||
|
||||
FunctionInvokedHook postExecutionHandler = event -> {
|
||||
postExecutionHandlerTriggered.set(true);
|
||||
return event;
|
||||
};
|
||||
|
||||
kernel.getGlobalKernelHooks().addHook(preHook);
|
||||
|
||||
// Demonstrate pattern for removing a handler.
|
||||
kernel.getGlobalKernelHooks().addHook("pre-invoke-removed", removedPreExecutionHandler);
|
||||
kernel.getGlobalKernelHooks().removeHook("pre-invoke-removed");
|
||||
kernel.getGlobalKernelHooks().addHook(postExecutionHandler);
|
||||
|
||||
kernel.invokeAsync(
|
||||
excuseFunction)
|
||||
.withArguments(
|
||||
KernelFunctionArguments
|
||||
.builder()
|
||||
.withVariable("input", "I missed the F1 final race")
|
||||
.build())
|
||||
.block();
|
||||
|
||||
Assertions.assertTrue(preHookTriggered.get());
|
||||
Assertions.assertFalse(removedPreExecutionHandlerTriggered.get());
|
||||
Assertions.assertTrue(postExecutionHandlerTriggered.get());
|
||||
}
|
||||
}
|
||||
-312
@@ -1,312 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.tests;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.OpenAIClientBuilder;
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import com.github.tomakehurst.wiremock.junit5.WireMockTest;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion;
|
||||
import com.microsoft.semantickernel.aiservices.openai.textcompletion.OpenAITextGenerationService;
|
||||
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
|
||||
import com.microsoft.semantickernel.services.textcompletion.TextGenerationService;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@WireMockTest
|
||||
public class RenderingTest {
|
||||
|
||||
private WireMockServer wm;
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
wm = new WireMockServer();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void after() {
|
||||
wm.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void textSemanticKernelTemplateXml() {
|
||||
buildTextKernel()
|
||||
.invokeAsync(
|
||||
KernelFunction
|
||||
.createFromPrompt("""
|
||||
Value: {{$value}}
|
||||
""")
|
||||
.withTemplateFormat(PromptTemplateConfig.SEMANTIC_KERNEL_TEMPLATE_FORMAT)
|
||||
.build())
|
||||
.withArguments(KernelFunctionArguments
|
||||
.builder()
|
||||
.withVariable("value", "<message role=\"user\">\"hello world\"</message>")
|
||||
.build())
|
||||
.block();
|
||||
|
||||
// The actual body will be escaped as its json
|
||||
Assertions.assertTrue(
|
||||
wm.getAllServeEvents().get(0).getRequest().getBodyAsString()
|
||||
.contains("<message role=\\\"user\\\">\\\"hello world\\\"</message>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void textSemanticKernelTemplate() {
|
||||
buildTextKernel()
|
||||
.invokeAsync(
|
||||
KernelFunction
|
||||
.createFromPrompt("""
|
||||
Value: {{$value}}
|
||||
""")
|
||||
.withTemplateFormat(PromptTemplateConfig.SEMANTIC_KERNEL_TEMPLATE_FORMAT)
|
||||
.build())
|
||||
.withArguments(KernelFunctionArguments
|
||||
.builder()
|
||||
.withVariable("value", "{{$ignore}}")
|
||||
.withVariable("ignore", "dont show")
|
||||
.build())
|
||||
.block();
|
||||
|
||||
Assertions.assertFalse(
|
||||
wm.getAllServeEvents().get(0).getRequest().getBodyAsString().contains("dont show"));
|
||||
Assertions.assertTrue(
|
||||
wm.getAllServeEvents().get(0).getRequest().getBodyAsString().contains("{{$ignore}}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void textHandleBarsTemplate() {
|
||||
buildTextKernel()
|
||||
.invokeAsync(
|
||||
KernelFunction
|
||||
.createFromPrompt("""
|
||||
Value: {{value}}
|
||||
""")
|
||||
.withTemplateFormat("handlebars")
|
||||
.build())
|
||||
.withArguments(KernelFunctionArguments
|
||||
.builder()
|
||||
.withVariable("value", "{{ignore}}")
|
||||
.withVariable("ignore", "dont show")
|
||||
.build())
|
||||
.block();
|
||||
|
||||
Assertions.assertFalse(
|
||||
wm.getAllServeEvents().get(0).getRequest().getBodyAsString().contains("dont show"));
|
||||
Assertions.assertTrue(
|
||||
wm.getAllServeEvents().get(0).getRequest().getBodyAsString().contains("{{ignore}}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chatSemanticKernelTemplateXml() {
|
||||
buildChatKernel()
|
||||
.invokeAsync(
|
||||
KernelFunction
|
||||
.createFromPrompt("""
|
||||
Value: {{$value}}
|
||||
""")
|
||||
.withTemplateFormat(PromptTemplateConfig.SEMANTIC_KERNEL_TEMPLATE_FORMAT)
|
||||
.build())
|
||||
.withArguments(KernelFunctionArguments
|
||||
.builder()
|
||||
.withVariable("value", "<message role=\"user\">\"hello world\"</message>")
|
||||
.build())
|
||||
.block();
|
||||
|
||||
// The actual body will be escaped as its json
|
||||
Assertions.assertTrue(
|
||||
wm.getAllServeEvents().get(0).getRequest().getBodyAsString()
|
||||
.contains("<message role=\\\"user\\\">\\\"hello world\\\"</message>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chatSemanticKernelTemplate() {
|
||||
buildChatKernel()
|
||||
.invokeAsync(
|
||||
KernelFunction
|
||||
.createFromPrompt("""
|
||||
Value: {{$value}}
|
||||
""")
|
||||
.withTemplateFormat(PromptTemplateConfig.SEMANTIC_KERNEL_TEMPLATE_FORMAT)
|
||||
.build())
|
||||
.withArguments(KernelFunctionArguments
|
||||
.builder()
|
||||
.withVariable("value", "{{$ignore}}")
|
||||
.withVariable("ignore", "dont show")
|
||||
.build())
|
||||
.block();
|
||||
|
||||
Assertions.assertFalse(
|
||||
wm.getAllServeEvents().get(0).getRequest().getBodyAsString().contains("dont show"));
|
||||
Assertions.assertTrue(
|
||||
wm.getAllServeEvents().get(0).getRequest().getBodyAsString().contains("{{$ignore}}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chatHandleBarsTemplate() {
|
||||
buildChatKernel()
|
||||
.invokeAsync(
|
||||
KernelFunction
|
||||
.createFromPrompt("""
|
||||
Value: {{value}}
|
||||
""")
|
||||
.withTemplateFormat("handlebars")
|
||||
.build())
|
||||
.withArguments(KernelFunctionArguments
|
||||
.builder()
|
||||
.withVariable("value", "{{ignore}}")
|
||||
.withVariable("ignore", "dont show")
|
||||
.build())
|
||||
.block();
|
||||
|
||||
Assertions.assertFalse(
|
||||
wm.getAllServeEvents().get(0).getRequest().getBodyAsString().contains("dont show"));
|
||||
Assertions.assertTrue(
|
||||
wm.getAllServeEvents().get(0).getRequest().getBodyAsString().contains("{{ignore}}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chatSemanticKernelTemplate2() {
|
||||
buildChatKernel()
|
||||
.invokeAsync(
|
||||
KernelFunction
|
||||
.createFromPrompt("""
|
||||
<message role="user">Value: {{$value}}</message>
|
||||
""")
|
||||
.withTemplateFormat(PromptTemplateConfig.SEMANTIC_KERNEL_TEMPLATE_FORMAT)
|
||||
.build())
|
||||
.withArguments(KernelFunctionArguments
|
||||
.builder()
|
||||
.withVariable("value", "{{$ignore}}")
|
||||
.withVariable("ignore", "dont show")
|
||||
.build())
|
||||
.block();
|
||||
|
||||
Assertions.assertFalse(
|
||||
wm.getAllServeEvents().get(0).getRequest().getBodyAsString().contains("dont show"));
|
||||
Assertions.assertTrue(
|
||||
wm.getAllServeEvents().get(0).getRequest().getBodyAsString().contains("{{$ignore}}"));
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "WithEmptyListReturn")
|
||||
public List<Integer> WithEmptyListReturn() {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "WithListReturn")
|
||||
public List<Integer> WithListReturn() {
|
||||
return List.of(1, 2, 3);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "WithListReturn2", returnType = "java.util.List")
|
||||
public List<Integer> WithListReturn2() {
|
||||
return List.of(1, 2, 3);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "WithListReturn3", returnType = "java.util.List")
|
||||
public Mono<List<Integer>> WithListReturn3() {
|
||||
return Mono.just(List.of(1, 2, 3));
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "WithListReturn4", returnType = "java.util.List")
|
||||
public Mono<List<Integer>> WithListReturn4() {
|
||||
return Mono.just(List.of());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canHandleIterableReturnFromFunction() {
|
||||
buildChatKernel()
|
||||
.invokeAsync(
|
||||
KernelFunction
|
||||
.createFromPrompt("""
|
||||
<message role="user">{{RenderingTest-WithEmptyListReturn}}</message>
|
||||
<message role="user">{{RenderingTest-WithListReturn}}</message>
|
||||
<message role="user">{{RenderingTest-WithListReturn2}}</message>
|
||||
<message role="user">{{RenderingTest-WithListReturn3}}</message>
|
||||
<message role="user">{{RenderingTest-WithListReturn4}}</message>
|
||||
""")
|
||||
.withTemplateFormat("handlebars")
|
||||
.build())
|
||||
.block();
|
||||
|
||||
Assertions.assertTrue(
|
||||
wm.getAllServeEvents().get(0).getRequest().getBodyAsString().equals(
|
||||
"{\"messages\":["
|
||||
+ "{\"role\":\"user\",\"content\":\"[]\"},"
|
||||
+ "{\"role\":\"user\",\"content\":\"[1, 2, 3]\"},"
|
||||
+ "{\"role\":\"user\",\"content\":\"[1, 2, 3]\"},"
|
||||
+ "{\"role\":\"user\",\"content\":\"[1, 2, 3]\"},"
|
||||
+ "{\"role\":\"user\",\"content\":\"[]\"}"
|
||||
+ "],\"model\":\"gpt-35-turbo-2\"}"));
|
||||
}
|
||||
|
||||
private Kernel buildTextKernel() {
|
||||
wm.addStubMapping(
|
||||
stubFor(
|
||||
ToolCallBehaviourTest.buildTextResponse(" ", """
|
||||
"choices": [
|
||||
{
|
||||
"text": "Value: bar"
|
||||
}
|
||||
]
|
||||
""")));
|
||||
wm.start();
|
||||
|
||||
final OpenAIAsyncClient client = new OpenAIClientBuilder()
|
||||
.endpoint("http://localhost:" + wm.port() + "/")
|
||||
.buildAsyncClient();
|
||||
|
||||
TextGenerationService textGenerationService = OpenAITextGenerationService.builder()
|
||||
.withOpenAIAsyncClient(client)
|
||||
.withModelId("gpt-35-turbo-2")
|
||||
.build();
|
||||
|
||||
Kernel kernel = Kernel.builder()
|
||||
.withAIService(TextGenerationService.class, textGenerationService)
|
||||
.build();
|
||||
return kernel;
|
||||
}
|
||||
|
||||
private Kernel buildChatKernel() {
|
||||
wm.addStubMapping(
|
||||
stubFor(
|
||||
ToolCallBehaviourTest.buildResponse(" ", """
|
||||
"choices" : [
|
||||
{
|
||||
"finish_reason" : "stop",
|
||||
"index" : 0,
|
||||
"message" : {
|
||||
"content" : "done",
|
||||
"role" : "assistant"
|
||||
}
|
||||
}
|
||||
]
|
||||
""")));
|
||||
wm.start();
|
||||
|
||||
final OpenAIAsyncClient client = new OpenAIClientBuilder()
|
||||
.endpoint("http://localhost:" + wm.port() + "/")
|
||||
.buildAsyncClient();
|
||||
|
||||
ChatCompletionService textGenerationService = OpenAIChatCompletion.builder()
|
||||
.withOpenAIAsyncClient(client)
|
||||
.withModelId("gpt-35-turbo-2")
|
||||
.build();
|
||||
|
||||
Kernel kernel = Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class, textGenerationService)
|
||||
.withPlugin(KernelPluginFactory.createFromObject(this, "RenderingTest"))
|
||||
.build();
|
||||
return kernel;
|
||||
}
|
||||
}
|
||||
-367
@@ -1,367 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.tests;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.post;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.OpenAIClientBuilder;
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import com.github.tomakehurst.wiremock.client.MappingBuilder;
|
||||
import com.github.tomakehurst.wiremock.junit5.WireMockTest;
|
||||
import com.github.tomakehurst.wiremock.matching.ContainsPattern;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatMessageContent;
|
||||
import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIFunctionToolCall;
|
||||
import com.microsoft.semantickernel.implementation.CollectionUtil;
|
||||
import com.microsoft.semantickernel.orchestration.InvocationContext;
|
||||
import com.microsoft.semantickernel.orchestration.InvocationReturnMode;
|
||||
import com.microsoft.semantickernel.orchestration.ToolCallBehavior;
|
||||
import com.microsoft.semantickernel.plugin.KernelPlugin;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromMethod;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.AuthorRole;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatHistory;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
@WireMockTest
|
||||
public class ToolCallBehaviourTest {
|
||||
|
||||
private WireMockServer wm;
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
wm = new WireMockServer();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void after() {
|
||||
wm.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonAutoInvokedIsNotCalled() throws NoSuchMethodException {
|
||||
ChatCompletionService chatCompletionService = getChatCompletionService();
|
||||
|
||||
TestPlugin testPlugin = Mockito.spy(new TestPlugin());
|
||||
KernelFunction<String> method = KernelFunctionFromMethod.<String>builder()
|
||||
.withFunctionName("doIt")
|
||||
.withMethod(TestPlugin.class.getMethod("doIt"))
|
||||
.withTarget(testPlugin)
|
||||
.withPluginName("apluginname")
|
||||
.build();
|
||||
|
||||
Kernel kernel = Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class, chatCompletionService)
|
||||
.withPlugin(
|
||||
new KernelPlugin(
|
||||
"apluginname",
|
||||
"A plugin description",
|
||||
Map.of("doIt", method)))
|
||||
.build();
|
||||
|
||||
ChatHistory messages = new ChatHistory();
|
||||
messages.addMessage(
|
||||
new ChatMessageContent<>(
|
||||
AuthorRole.USER,
|
||||
"Call A function"));
|
||||
|
||||
List<ChatMessageContent<?>> result = chatCompletionService
|
||||
.getChatMessageContentsAsync(
|
||||
messages,
|
||||
kernel,
|
||||
InvocationContext.builder()
|
||||
.withToolCallBehavior(
|
||||
ToolCallBehavior.allowOnlyKernelFunctions(false, method))
|
||||
.build())
|
||||
.block();
|
||||
|
||||
List<OpenAIFunctionToolCall> toolCalls = ((OpenAIChatMessageContent<?>) CollectionUtil.getLastOrNull(
|
||||
result))
|
||||
.getToolCall();
|
||||
|
||||
Assertions.assertNotNull(toolCalls);
|
||||
Assertions.assertEquals(1, toolCalls.size());
|
||||
Assertions.assertEquals("apluginname",
|
||||
CollectionUtil.getLastOrNull(toolCalls).getPluginName());
|
||||
Assertions.assertEquals("doIt", CollectionUtil.getLastOrNull(toolCalls).getFunctionName());
|
||||
Assertions.assertEquals("call_abc123", CollectionUtil.getLastOrNull(toolCalls).getId());
|
||||
|
||||
Mockito.verify(testPlugin, Mockito.times(0)).doIt();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toolIsInvoked() throws NoSuchMethodException {
|
||||
ChatCompletionService chatCompletionService = getChatCompletionService();
|
||||
|
||||
TestPlugin testPlugin = Mockito.spy(new TestPlugin());
|
||||
KernelFunction<String> method = KernelFunctionFromMethod.<String>builder()
|
||||
.withFunctionName("doIt")
|
||||
.withMethod(TestPlugin.class.getMethod("doIt"))
|
||||
.withTarget(testPlugin)
|
||||
.withPluginName("apluginname")
|
||||
.build();
|
||||
|
||||
Kernel kernel = Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class, chatCompletionService)
|
||||
.withPlugin(
|
||||
new KernelPlugin(
|
||||
"apluginname",
|
||||
"A plugin description",
|
||||
Map.of("doIt", method)))
|
||||
.build();
|
||||
|
||||
ChatHistory messages = new ChatHistory();
|
||||
messages.addMessage(
|
||||
new ChatMessageContent<>(
|
||||
AuthorRole.USER,
|
||||
"Call A function"));
|
||||
|
||||
List<ChatMessageContent<?>> result = chatCompletionService
|
||||
.getChatMessageContentsAsync(
|
||||
messages,
|
||||
kernel,
|
||||
InvocationContext.builder()
|
||||
.withToolCallBehavior(
|
||||
ToolCallBehavior.allowAllKernelFunctions(true))
|
||||
.build())
|
||||
.block();
|
||||
|
||||
Assertions.assertTrue(
|
||||
CollectionUtil.getLastOrNull(result).getContent().contains("tool call done"));
|
||||
Mockito.verify(testPlugin, Mockito.times(1)).doIt();
|
||||
|
||||
result = chatCompletionService
|
||||
.getChatMessageContentsAsync(
|
||||
messages,
|
||||
kernel,
|
||||
InvocationContext.builder()
|
||||
.withToolCallBehavior(
|
||||
ToolCallBehavior.allowOnlyKernelFunctions(true, Arrays.asList(method)))
|
||||
.build())
|
||||
.block();
|
||||
|
||||
Assertions.assertTrue(
|
||||
CollectionUtil.getLastOrNull(result).getContent().contains("tool call done"));
|
||||
Mockito.verify(testPlugin, Mockito.times(2)).doIt();
|
||||
|
||||
result = chatCompletionService
|
||||
.getChatMessageContentsAsync(
|
||||
messages,
|
||||
kernel,
|
||||
InvocationContext.builder()
|
||||
.withToolCallBehavior(
|
||||
ToolCallBehavior.allowOnlyKernelFunctions(true, method))
|
||||
.build())
|
||||
.block();
|
||||
|
||||
Assertions.assertTrue(
|
||||
CollectionUtil.getLastOrNull(result).getContent().contains("tool call done"));
|
||||
Mockito.verify(testPlugin, Mockito.times(3)).doIt();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void toolCallingHistoryPassed() throws NoSuchMethodException {
|
||||
ChatCompletionService chatCompletionService = getChatCompletionService();
|
||||
|
||||
TestPlugin testPlugin = Mockito.spy(new TestPlugin());
|
||||
KernelFunction<String> method = KernelFunctionFromMethod.<String>builder()
|
||||
.withFunctionName("doIt")
|
||||
.withMethod(TestPlugin.class.getMethod("doIt"))
|
||||
.withTarget(testPlugin)
|
||||
.withPluginName("apluginname")
|
||||
.build();
|
||||
|
||||
Kernel kernel = Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class, chatCompletionService)
|
||||
.withPlugin(
|
||||
new KernelPlugin(
|
||||
"apluginname",
|
||||
"A plugin description",
|
||||
Map.of("doIt", method)))
|
||||
.build();
|
||||
|
||||
ChatHistory messages = new ChatHistory();
|
||||
messages.addMessage(
|
||||
new ChatMessageContent<>(
|
||||
AuthorRole.USER,
|
||||
"Call A function"));
|
||||
|
||||
List<ChatMessageContent<?>> result = chatCompletionService
|
||||
.getChatMessageContentsAsync(
|
||||
messages,
|
||||
kernel,
|
||||
InvocationContext.builder()
|
||||
.withToolCallBehavior(
|
||||
ToolCallBehavior.allowAllKernelFunctions(true))
|
||||
.withReturnMode(InvocationReturnMode.FULL_HISTORY)
|
||||
.build())
|
||||
.block();
|
||||
|
||||
ChatHistory newHistory = new ChatHistory(result);
|
||||
newHistory.addMessage(AuthorRole.USER, "do something else");
|
||||
|
||||
List<ChatMessageContent<?>> result2 = chatCompletionService
|
||||
.getChatMessageContentsAsync(
|
||||
newHistory,
|
||||
kernel,
|
||||
InvocationContext.builder()
|
||||
.withToolCallBehavior(
|
||||
ToolCallBehavior.allowAllKernelFunctions(true))
|
||||
.withReturnMode(InvocationReturnMode.FULL_HISTORY)
|
||||
.build())
|
||||
.block();
|
||||
Assertions.assertTrue(result2.size() == 6);
|
||||
}
|
||||
|
||||
private ChatCompletionService getChatCompletionService() {
|
||||
wm
|
||||
.addStubMapping(
|
||||
stubFor(
|
||||
buildResponse("Call A function", """
|
||||
"choices": [
|
||||
{
|
||||
"index": 0,
|
||||
"message": {
|
||||
"role": "assistant",
|
||||
"content": null,
|
||||
"tool_calls": [
|
||||
{
|
||||
"id": "call_abc123",
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "apluginname-doIt",
|
||||
"arguments": "{}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"logprobs": null,
|
||||
"finish_reason": "tool_calls"
|
||||
}
|
||||
]
|
||||
""")));
|
||||
|
||||
wm.addStubMapping(
|
||||
stubFor(
|
||||
buildResponse("Tool call performed", """
|
||||
"choices" : [
|
||||
{
|
||||
"finish_reason" : "stop",
|
||||
"index" : 0,
|
||||
"message" : {
|
||||
"content" : "tool call done",
|
||||
"role" : "assistant"
|
||||
}
|
||||
}
|
||||
]
|
||||
""")));
|
||||
|
||||
wm.start();
|
||||
|
||||
final OpenAIAsyncClient client = new OpenAIClientBuilder()
|
||||
.endpoint("http://localhost:" + wm.port() + "/")
|
||||
.buildAsyncClient();
|
||||
|
||||
return ChatCompletionService.builder()
|
||||
.withOpenAIAsyncClient(client)
|
||||
.withModelId("gpt-35-turbo-2")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
public static MappingBuilder buildTextResponse(String bodyMatcher, String responseBody) {
|
||||
return post(urlEqualTo(
|
||||
"//openai/deployments/gpt-35-turbo-2/completions?api-version=2024-03-01-preview"))
|
||||
.withRequestBody(new ContainsPattern(bodyMatcher))
|
||||
.willReturn(
|
||||
aResponse()
|
||||
.withStatus(200)
|
||||
.withHeader("Content-Type", "application/json")
|
||||
.withBody(formTextResponse(responseBody)));
|
||||
}
|
||||
|
||||
public static MappingBuilder buildResponse(String bodyMatcher, String responseBody) {
|
||||
return post(urlEqualTo(
|
||||
"//openai/deployments/gpt-35-turbo-2/chat/completions?api-version=2024-03-01-preview"))
|
||||
.withRequestBody(new ContainsPattern(bodyMatcher))
|
||||
.willReturn(
|
||||
aResponse()
|
||||
.withStatus(200)
|
||||
.withHeader("Content-Type", "application/json")
|
||||
.withBody(formResponse(responseBody)));
|
||||
}
|
||||
|
||||
public static class TestPlugin {
|
||||
|
||||
public String doIt() {
|
||||
return "Tool call performed";
|
||||
}
|
||||
}
|
||||
|
||||
private static String formTextResponse(String chatChoices) {
|
||||
return """
|
||||
{
|
||||
"id": "cmpl-3QJ9z1J9z1J9z1J9z1J9z1J9",
|
||||
"usage": {
|
||||
"total_tokens": 4,
|
||||
"completion_tokens": 1,
|
||||
"prompt_tokens": 1
|
||||
},
|
||||
%s
|
||||
}
|
||||
""".formatted(chatChoices);
|
||||
}
|
||||
|
||||
private static String formResponse(String chatChoices) {
|
||||
return """
|
||||
{
|
||||
%s,
|
||||
"created" : 1707253061,
|
||||
"id" : "chatcmpl-xxx",
|
||||
"model" : "gpt-35-turbo",
|
||||
"object" : "chat.completion",
|
||||
"prompt_filter_results" : [
|
||||
{
|
||||
"content_filter_results" : {
|
||||
"hate" : {
|
||||
"filtered" : false,
|
||||
"severity" : "safe"
|
||||
},
|
||||
"self_harm" : {
|
||||
"filtered" : false,
|
||||
"severity" : "safe"
|
||||
},
|
||||
"sexual" : {
|
||||
"filtered" : false,
|
||||
"severity" : "safe"
|
||||
},
|
||||
"violence" : {
|
||||
"filtered" : false,
|
||||
"severity" : "safe"
|
||||
}
|
||||
},
|
||||
"prompt_index" : 0
|
||||
}
|
||||
],
|
||||
"usage" : {
|
||||
"completion_tokens" : 67,
|
||||
"prompt_tokens" : 17,
|
||||
"total_tokens" : 84
|
||||
}
|
||||
}
|
||||
""".formatted(chatChoices);
|
||||
}
|
||||
}
|
||||
-125
@@ -1,125 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.tests;
|
||||
|
||||
import com.github.tomakehurst.wiremock.client.WireMock;
|
||||
import com.github.tomakehurst.wiremock.matching.RegexPattern;
|
||||
import com.github.tomakehurst.wiremock.matching.UrlPathPattern;
|
||||
|
||||
public class WireMockUtil {
|
||||
|
||||
public static void mockCompletionResponse(
|
||||
String regexMatcher,
|
||||
String response) {
|
||||
String body = """
|
||||
{
|
||||
"id": "1",
|
||||
"object": "text_completion",
|
||||
"created": 1589478378,
|
||||
"model": "text-davinci-003",
|
||||
"system_fingerprint": "fp_44709d6fb",
|
||||
"choices": [
|
||||
{
|
||||
"text": "%s",
|
||||
"index": 0,
|
||||
"logprobs": null,
|
||||
"finish_reason": "length"
|
||||
}
|
||||
],
|
||||
"usage": {
|
||||
"prompt_tokens": 1,
|
||||
"completion_tokens": 2,
|
||||
"total_tokens": 3
|
||||
}
|
||||
}
|
||||
"""
|
||||
.formatted(response);
|
||||
|
||||
WireMock.reset();
|
||||
WireMock.stubFor(WireMock
|
||||
.post(new UrlPathPattern(
|
||||
new RegexPattern("/openai/deployments/text-davinci-003/completions"), true))
|
||||
.withRequestBody(WireMock.matching(".*" + regexMatcher + ".*"))
|
||||
.willReturn(WireMock.ok()
|
||||
.withBody(body)));
|
||||
}
|
||||
|
||||
public static void mockChatCompletionResponse(
|
||||
String regexMatcher,
|
||||
String response) {
|
||||
String body = """
|
||||
{
|
||||
"choices" : [
|
||||
{
|
||||
"content_filter_results" : {
|
||||
"hate" : {
|
||||
"filtered" : false,
|
||||
"severity" : "safe"
|
||||
},
|
||||
"self_harm" : {
|
||||
"filtered" : false,
|
||||
"severity" : "safe"
|
||||
},
|
||||
"sexual" : {
|
||||
"filtered" : false,
|
||||
"severity" : "safe"
|
||||
},
|
||||
"violence" : {
|
||||
"filtered" : false,
|
||||
"severity" : "safe"
|
||||
}
|
||||
},
|
||||
"finish_reason" : "length",
|
||||
"index" : 0,
|
||||
"message" : {
|
||||
"content" : "%s",
|
||||
"role" : "assistant"
|
||||
}
|
||||
}
|
||||
],
|
||||
"created" : 1707253019,
|
||||
"id" : "chatcmpl-xxx",
|
||||
"model" : "gpt-35-turbo",
|
||||
"object" : "chat.completion",
|
||||
"prompt_filter_results" : [
|
||||
{
|
||||
"content_filter_results" : {
|
||||
"hate" : {
|
||||
"filtered" : false,
|
||||
"severity" : "safe"
|
||||
},
|
||||
"self_harm" : {
|
||||
"filtered" : false,
|
||||
"severity" : "safe"
|
||||
},
|
||||
"sexual" : {
|
||||
"filtered" : false,
|
||||
"severity" : "safe"
|
||||
},
|
||||
"violence" : {
|
||||
"filtered" : false,
|
||||
"severity" : "safe"
|
||||
}
|
||||
},
|
||||
"prompt_index" : 0
|
||||
}
|
||||
],
|
||||
"usage" : {
|
||||
"completion_tokens" : 256,
|
||||
"prompt_tokens" : 69,
|
||||
"total_tokens" : 325
|
||||
}
|
||||
}
|
||||
|
||||
"""
|
||||
.formatted(response);
|
||||
|
||||
WireMock.reset();
|
||||
WireMock.stubFor(WireMock
|
||||
.post(new UrlPathPattern(
|
||||
new RegexPattern("/openai/deployments/text-davinci-003/chat/completions"), true))
|
||||
.withRequestBody(WireMock.matching(".*" + regexMatcher + ".*"))
|
||||
.willReturn(WireMock.ok()
|
||||
.withBody(body)));
|
||||
}
|
||||
|
||||
}
|
||||
-162
@@ -1,162 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.tests;
|
||||
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.Example43_GetModelResult;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.Example49_LogitBias;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.Example55_TextChunker;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.Example57_KernelHooks;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.Example61_MultipleLLMs;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.Example62_CustomAIServiceSelector;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.Example69_MutableKernelPlugin;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.Example17_ChatGPT;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.Example33_Chat;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.Example44_MultiChatCompletion;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.Example63_ChatCompletionPrompts;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.configuration.Example41_HttpClientUsage;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.configuration.Example58_ConfigureExecutionSettings;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example01_NativeFunctions;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example03_Arguments;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example05_InlineFunctionDefinition;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example09_FunctionTypes;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example27_PromptFunctionsUsingChatGPT;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example60_AdvancedMethodFunctions;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.java.FunctionsWithinPrompts_Example;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.java.KernelFunctionYaml_Example;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.stream.Stream;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.plugins.Example10_DescribeAllPluginsAndFunctions;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.plugins.Example13_ConversationSummaryPlugin;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.template.Example06_TemplateLanguage;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.template.Example56_TemplateMethodFunctionsWithMultipleArguments;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.template.Example64_MultiplePromptTemplates;
|
||||
import org.junit.jupiter.api.DynamicTest;
|
||||
import org.junit.jupiter.api.TestFactory;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
public class WiremockExamplesIT {
|
||||
|
||||
public static List<Class<?>> mains = Arrays.asList(
|
||||
FunctionsWithinPrompts_Example.class,
|
||||
KernelFunctionYaml_Example.class,
|
||||
Example01_NativeFunctions.class,
|
||||
Example03_Arguments.class,
|
||||
Example05_InlineFunctionDefinition.class,
|
||||
Example06_TemplateLanguage.class,
|
||||
//Example08_RetryHandler.class,
|
||||
Example09_FunctionTypes.class,
|
||||
Example10_DescribeAllPluginsAndFunctions.class,
|
||||
//Example11_WebSearchQueries.class,
|
||||
Example13_ConversationSummaryPlugin.class,
|
||||
Example17_ChatGPT.class,
|
||||
//Example26_AADAuth.class,
|
||||
|
||||
Example27_PromptFunctionsUsingChatGPT.class,
|
||||
|
||||
// Difficulty with time causing wiremock to fail
|
||||
//Example30_ChatWithPrompts.class,
|
||||
Example33_Chat.class,
|
||||
Example41_HttpClientUsage.class,
|
||||
Example43_GetModelResult.class,
|
||||
Example44_MultiChatCompletion.class,
|
||||
Example49_LogitBias.class,
|
||||
Example55_TextChunker.class,
|
||||
Example56_TemplateMethodFunctionsWithMultipleArguments.class,
|
||||
Example57_KernelHooks.class,
|
||||
Example58_ConfigureExecutionSettings.class,
|
||||
Example60_AdvancedMethodFunctions.class,
|
||||
Example61_MultipleLLMs.class,
|
||||
Example62_CustomAIServiceSelector.class,
|
||||
Example63_ChatCompletionPrompts.class,
|
||||
Example64_MultiplePromptTemplates.class,
|
||||
Example69_MutableKernelPlugin.class);
|
||||
|
||||
public static WireMockServer createWiremockServer(String dir) {
|
||||
return new WireMockServer(
|
||||
WireMockConfiguration.wireMockConfig()
|
||||
.httpsPort(8443)
|
||||
.trustStorePath("scripts/client.truststore")
|
||||
.trustStorePassword("password")
|
||||
.trustStoreType("jks")
|
||||
.keystorePath("scripts/server.keystore")
|
||||
.keystorePassword("password")
|
||||
.keystoreType("jks")
|
||||
.usingFilesUnderDirectory(dir));
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
mockInputStream();
|
||||
|
||||
new WiremockExamplesIT()
|
||||
.runSamplesTest()
|
||||
.forEach(it -> {
|
||||
try {
|
||||
it.getExecutable().execute();
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void mockInputStream() throws IOException {
|
||||
FunctionsWithinPrompts_Example.INPUT = Mockito.mock(InputStream.class);
|
||||
|
||||
Queue<String> messages = new ArrayDeque<>();
|
||||
|
||||
messages.addAll(Arrays.asList(
|
||||
"Can you draft me an email to the marketing team?",
|
||||
"Tell them to go ahead with the plan",
|
||||
"That is all"));
|
||||
|
||||
Mockito
|
||||
.when(FunctionsWithinPrompts_Example.INPUT.read(
|
||||
Mockito.any(byte[].class),
|
||||
Mockito.anyInt(),
|
||||
Mockito.anyInt()))
|
||||
.then(invocation -> {
|
||||
String message = messages.poll() + "\n";
|
||||
byte[] bytes = invocation.getArgument(0);
|
||||
System.arraycopy(message.getBytes(), 0, bytes, 0, message.getBytes().length);
|
||||
|
||||
return message.getBytes().length;
|
||||
});
|
||||
}
|
||||
|
||||
@TestFactory
|
||||
public Stream<DynamicTest> runSamplesTest() {
|
||||
return mains
|
||||
.stream()
|
||||
.map(
|
||||
testClazz -> DynamicTest
|
||||
.dynamicTest(
|
||||
testClazz.getSimpleName() + "Test",
|
||||
() -> {
|
||||
mockInputStream();
|
||||
System.out.println("Running: " + testClazz.getSimpleName());
|
||||
WireMockServer server = null;
|
||||
try {
|
||||
Method main = testClazz.getMethod("main",
|
||||
String[].class);
|
||||
|
||||
server = createWiremockServer("src/test/resources/wiremock");
|
||||
|
||||
server.start();
|
||||
main.invoke(null, new Object[] { null });
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
if (server != null) {
|
||||
server.stop();
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
-104
@@ -1,104 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.tests;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import com.github.tomakehurst.wiremock.recording.RecordSpecBuilder;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.UUID;
|
||||
|
||||
public class WiremockRecord {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
record(
|
||||
() -> {
|
||||
WiremockExamplesIT.mains.forEach(testClazz -> {
|
||||
try {
|
||||
Method main = testClazz.getMethod("main", String[].class);
|
||||
main.invoke(null, new Object[] { null });
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
},
|
||||
args[0]);
|
||||
}
|
||||
|
||||
public static void compressRecordings(Path mappings) throws IOException {
|
||||
Files.newDirectoryStream(mappings)
|
||||
.forEach(path -> {
|
||||
try {
|
||||
JsonNode data = new ObjectMapper().readTree(path.toFile());
|
||||
|
||||
JsonNode body = new ObjectMapper().readTree(
|
||||
data.get("response").get("body").asText());
|
||||
|
||||
if (body.get("id").asText().contains("chatcmpl-")) {
|
||||
|
||||
((ObjectNode) body).put("id", "chatcmpl-xxx");
|
||||
|
||||
body
|
||||
.get("choices")
|
||||
.forEach(choice -> {
|
||||
((ObjectNode) choice.get("message")).put("content",
|
||||
UUID.randomUUID().toString());
|
||||
});
|
||||
|
||||
((ObjectNode) data.get("response")).put("body", body.toString());
|
||||
} else if (body.get("id").asText().contains("cmpl-")) {
|
||||
|
||||
((ObjectNode) body).put("id", "cmpl-xxx");
|
||||
|
||||
body
|
||||
.get("choices")
|
||||
.forEach(choice -> {
|
||||
((ObjectNode) choice).put("text", UUID.randomUUID().toString());
|
||||
});
|
||||
|
||||
((ObjectNode) data.get("response")).put("body", body.toString());
|
||||
}
|
||||
|
||||
Files.writeString(path, data.toPrettyString());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void record(Runnable run, String targetUrl) throws IOException {
|
||||
Path dir = Path.of("target", "wiremock");
|
||||
if (dir.toFile().exists()) {
|
||||
dir.toFile().delete();
|
||||
}
|
||||
|
||||
Files.createDirectories(dir.resolve("mappings"));
|
||||
|
||||
System.out.println("Recording to: " + dir.toFile().getCanonicalPath());
|
||||
|
||||
WireMockServer wireMockServer = WiremockExamplesIT.createWiremockServer(
|
||||
dir.toFile().getCanonicalPath() + "/");
|
||||
wireMockServer.start();
|
||||
wireMockServer.startRecording(
|
||||
new RecordSpecBuilder()
|
||||
.forTarget(targetUrl)
|
||||
.makeStubsPersistent(true)
|
||||
.build());
|
||||
|
||||
try {
|
||||
run.run();
|
||||
} finally {
|
||||
wireMockServer.stopRecording().getStubMappings();
|
||||
wireMockServer.stop();
|
||||
}
|
||||
|
||||
compressRecordings(dir.resolve("mappings"));
|
||||
|
||||
System.out.println("Saved output to: " + dir.toFile().getAbsolutePath());
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="info">
|
||||
<Appenders>
|
||||
<Console name="Console" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="%d{HH:mm:ss} %-5level %c{1.} - %msg%n"/>
|
||||
</Console>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Root level="warn">
|
||||
<AppenderRef ref="Console"/>
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"priority": 1,
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "//openai/deployments/gpt-35-turbo-2/chat/completions?api-version=2024-03-01-preview",
|
||||
"bodyPatterns": [
|
||||
{
|
||||
"contains": "That is all"
|
||||
}
|
||||
]
|
||||
},
|
||||
"response": {
|
||||
"body": "{\"id\":\"chatcmpl-xxx\",\"object\":\"chat.completion\",\"created\":1707253061,\"model\":\"gpt-35-turbo\",\"prompt_filter_results\":[{\"prompt_index\":0,\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}}}],\"choices\":[{\"finish_reason\":\"stop\",\"index\":0,\"message\":{\"role\":\"assistant\",\"content\":\"EndConversation\"},\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}}}],\"usage\":{\"prompt_tokens\":17,\"completion_tokens\":67,\"total_tokens\":84}}",
|
||||
"headers": {},
|
||||
"status": 200
|
||||
}
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "//openai/deployments/gpt-35-turbo-2/chat/completions?api-version=2024-03-01-preview"
|
||||
},
|
||||
"response": {
|
||||
"body": "{\"id\":\"chatcmpl-xxx\",\"object\":\"chat.completion\",\"created\":1707253061,\"model\":\"gpt-35-turbo\",\"prompt_filter_results\":[{\"prompt_index\":0,\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}}}],\"choices\":[{\"finish_reason\":\"stop\",\"index\":0,\"message\":{\"role\":\"assistant\",\"content\":\"1979b4ce-5463-4cfb-8ec8-1d05c4b44ccf\"},\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}}}],\"usage\":{\"prompt_tokens\":17,\"completion_tokens\":67,\"total_tokens\":84}}",
|
||||
"headers": {},
|
||||
"status": 200
|
||||
}
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "//openai/deployments/gpt-35-turbo/chat/completions?api-version=2024-03-01-preview"
|
||||
},
|
||||
"response": {
|
||||
"body": "{\"id\":\"chatcmpl-xxx\",\"object\":\"chat.completion\",\"created\":1707253039,\"model\":\"gpt-35-turbo\",\"prompt_filter_results\":[{\"prompt_index\":0,\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}}}],\"choices\":[{\"finish_reason\":\"stop\",\"index\":0,\"message\":{\"role\":\"assistant\",\"content\":\"ac9817bc-7e1a-48e4-b06c-0ff7618b88c6\"},\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}}}],\"usage\":{\"prompt_tokens\":26,\"completion_tokens\":131,\"total_tokens\":157}}",
|
||||
"headers": {},
|
||||
"status": 200
|
||||
}
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "//openai/deployments/text-davinci-003/completions?api-version=2024-03-01-preview"
|
||||
},
|
||||
"response": {
|
||||
"body": "{\"id\":\"cmpl-xxx\",\"object\":\"text_completion\",\"created\":1707253062,\"model\":\"text-davinci-003\",\"prompt_filter_results\":[{\"prompt_index\":0,\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}}}],\"choices\":[{\"text\":\"7949e981-c632-422f-9b76-335a2379cd83\",\"index\":0,\"finish_reason\":\"stop\",\"logprobs\":null,\"content_filter_results\":{\"hate\":{\"filtered\":false,\"severity\":\"safe\"},\"self_harm\":{\"filtered\":false,\"severity\":\"safe\"},\"sexual\":{\"filtered\":false,\"severity\":\"safe\"},\"violence\":{\"filtered\":false,\"severity\":\"safe\"}}}],\"usage\":{\"prompt_tokens\":10,\"completion_tokens\":26,\"total_tokens\":36}}",
|
||||
"headers": {},
|
||||
"status": 200
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-parent</artifactId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<name>Semantic Kernel Api Tests</name>
|
||||
<artifactId>api-test</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<properties>
|
||||
<maven.compiler-plugin.version>3.11.0</maven.compiler-plugin.version>
|
||||
<maven.compiler.release>17</maven.compiler.release>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
<module>integration-tests</module>
|
||||
</modules>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-bom</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>import</scope>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven.compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<source>${maven.compiler.release}</source>
|
||||
<target>${maven.compiler.release}</target>
|
||||
<release>${maven.compiler.release}</release>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.diffplug.spotless</groupId>
|
||||
<artifactId>spotless-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<FindBugsFilter>
|
||||
|
||||
</FindBugsFilter>
|
||||
@@ -1,58 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-parent</artifactId>
|
||||
<version>0.2.14-alpha-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>semantickernel-connectors-memory-redis</artifactId>
|
||||
|
||||
<name>Semantic Kernel Redis Memory Connector</name>
|
||||
<description>Defines connector for Redis to be used with the Semantic Kernel</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
<version>5.1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-connectors-memory-jdbc</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.spotbugs</groupId>
|
||||
<artifactId>spotbugs-annotations</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
-163
@@ -1,163 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.connectors.memory.redis;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.microsoft.semantickernel.ai.embeddings.Embedding;
|
||||
import com.microsoft.semantickernel.memory.MemoryRecord;
|
||||
import com.microsoft.semantickernel.memory.MemoryRecordMetadata;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
/** Represents an entry in the Semantic Kernel Memory Table. */
|
||||
public class JsonMemoryRecord {
|
||||
|
||||
static final String ID = "Id";
|
||||
static final String TEXT = "Text";
|
||||
static final String DESCRIPTION = "Description";
|
||||
static final String ADDITIONAL_METADATA = "AdditionalMetadata";
|
||||
static final String EMBEDDING = "Embedding";
|
||||
static final String EXTERNAL_SOURCE_NAME = "ExternalSourceName";
|
||||
static final String IS_REFERENCE = "Reference";
|
||||
static final String TIME = "Timestamp";
|
||||
|
||||
private final String id;
|
||||
private final String text;
|
||||
private final String description;
|
||||
private final String additionalMetadata;
|
||||
private final List<Float> embedding;
|
||||
private final String externalSourceName;
|
||||
private final boolean isReference;
|
||||
|
||||
@JsonCreator
|
||||
public JsonMemoryRecord(
|
||||
@JsonProperty(ID) String id,
|
||||
@JsonProperty(TEXT) String text,
|
||||
@JsonProperty(DESCRIPTION) String description,
|
||||
@JsonProperty(ADDITIONAL_METADATA) String additionalMetadata,
|
||||
@JsonProperty(EMBEDDING) List<Float> embedding,
|
||||
@JsonProperty(EXTERNAL_SOURCE_NAME) String externalSourceName,
|
||||
@JsonProperty(IS_REFERENCE) boolean isReference) {
|
||||
this.id = id;
|
||||
this.text = text;
|
||||
this.description = description;
|
||||
this.additionalMetadata = additionalMetadata;
|
||||
this.embedding = embedding != null ? embedding : Collections.emptyList();
|
||||
this.externalSourceName = externalSourceName;
|
||||
this.isReference = isReference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record ID. The record is not filterable to save quota, also SK uses only semantic search.
|
||||
*
|
||||
* @return Record ID.
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Content is stored here.
|
||||
*
|
||||
* @return Content is stored here, {@code null} if not set.
|
||||
*/
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional description of the content, e.g. a title. This can be useful when indexing external
|
||||
* data without pulling in the entire content.
|
||||
*
|
||||
* @return Optional description of the content, {@code null} if not set.
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional metadata. Currently, this is a String where you could store serialized data as
|
||||
* JSON. In future the design might change to allow storing named values and leverage filters.
|
||||
*
|
||||
* @return Additional metadata, {@code null} if not set.
|
||||
*/
|
||||
public String getAdditionalMetadata() {
|
||||
return additionalMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Embedding vector.
|
||||
*
|
||||
* @return Embedding vector.
|
||||
*/
|
||||
public List<Float> getEmbedding() {
|
||||
return Collections.unmodifiableList(embedding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the external source, in cases where the content and the Id are referenced to external
|
||||
* information.
|
||||
*
|
||||
* @return Name of the external source, in cases where the content and the Id are referenced to
|
||||
* external information, {@code null} if not set.
|
||||
*/
|
||||
public String getExternalSourceName() {
|
||||
return externalSourceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the record references external information.
|
||||
*
|
||||
* @return {@code true} if the record references external information, {@code false} otherwise.
|
||||
*/
|
||||
public boolean isReference() {
|
||||
return isReference;
|
||||
}
|
||||
|
||||
public MemoryRecordMetadata toMemoryRecordMetadata() {
|
||||
return new MemoryRecordMetadata(
|
||||
this.isReference,
|
||||
decodeId(this.id),
|
||||
this.text,
|
||||
this.description,
|
||||
this.externalSourceName,
|
||||
this.additionalMetadata);
|
||||
}
|
||||
|
||||
public static JsonMemoryRecord fromMemoryRecord(MemoryRecord record) {
|
||||
return new JsonMemoryRecord(
|
||||
record.getMetadata().getId(),
|
||||
record.getMetadata().getText(),
|
||||
record.getMetadata().getDescription(),
|
||||
record.getMetadata().getAdditionalMetadata(),
|
||||
record.getEmbedding().getVector(),
|
||||
record.getMetadata().getExternalSourceName(),
|
||||
record.getMetadata().isReference());
|
||||
}
|
||||
|
||||
public MemoryRecord toMemoryRecord() {
|
||||
return toMemoryRecord(true);
|
||||
}
|
||||
|
||||
public MemoryRecord toMemoryRecord(boolean withEmbeddings) {
|
||||
return new MemoryRecord(
|
||||
this.toMemoryRecordMetadata(),
|
||||
new Embedding(withEmbeddings ? this.embedding : Collections.emptyList()),
|
||||
this.id,
|
||||
null);
|
||||
}
|
||||
|
||||
// ACS keys can contain only letters, digits, underscore, dash, equal sign, recommending
|
||||
// to encode values with a URL-safe algorithm.
|
||||
// <param name="realId">Original Id</param>
|
||||
// <returns>Encoded id</returns>
|
||||
static String encodeId(String realId) {
|
||||
byte[] bytes = Base64.getUrlEncoder().encode(realId.getBytes(StandardCharsets.UTF_8));
|
||||
return new String(bytes, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
static String decodeId(String encodedId) {
|
||||
byte[] bytes = Base64.getUrlDecoder().decode(encodedId.getBytes(StandardCharsets.UTF_8));
|
||||
return new String(bytes, StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
-69
@@ -1,69 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.connectors.memory.redis;
|
||||
|
||||
import com.microsoft.semantickernel.SKException;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Exception thrown by the SQL connector. */
|
||||
public class RedisException extends SKException {
|
||||
|
||||
private final ErrorCodes errorCode;
|
||||
|
||||
/**
|
||||
* Create an exception with a message
|
||||
*
|
||||
* @param errorCode The error code
|
||||
*/
|
||||
public RedisException(@Nonnull ErrorCodes errorCode) {
|
||||
|
||||
this(errorCode, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an exception with a message
|
||||
*
|
||||
* @param errorCode The error code
|
||||
* @param message a description of the cause of the exception
|
||||
*/
|
||||
public RedisException(@Nonnull ErrorCodes errorCode, @Nullable String message) {
|
||||
|
||||
this(errorCode, message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an exception with a message and a cause
|
||||
*
|
||||
* @param errorCode the error code
|
||||
* @param message a description of the cause of the exception
|
||||
* @param cause the cause of the exception
|
||||
*/
|
||||
public RedisException(
|
||||
@Nonnull ErrorCodes errorCode, @Nullable String message, @Nullable Throwable cause) {
|
||||
super(message, cause);
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
public ErrorCodes getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
public enum ErrorCodes {
|
||||
REDIS_ERROR("Redis error"),
|
||||
UNKNOWN_ERROR("Unknown error"),
|
||||
INVALID_EMBEDDING_SIZE("Invalid embedding size"),
|
||||
INVALID_INDEX_NAME("Invalid index name"),
|
||||
READ_FAILURE("Read failure"),
|
||||
WRITE_FAILURE("Write failure");
|
||||
|
||||
final String message;
|
||||
|
||||
ErrorCodes(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
}
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.connectors.memory.redis;
|
||||
|
||||
public class RedisIndexSchemaParams {
|
||||
|
||||
public static final String TYPE = "TYPE";
|
||||
public static final String DIM = "DIM";
|
||||
public static final String DIST = "DISTANCE_METRIC";
|
||||
}
|
||||
-106
@@ -1,106 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.connectors.memory.redis;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.microsoft.semantickernel.ai.embeddings.Embedding;
|
||||
import com.microsoft.semantickernel.memory.MemoryRecord;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
import redis.clients.jedis.search.Document;
|
||||
|
||||
/** Represents an entry in the Semantic Kernel Memory Table. */
|
||||
public class RedisMemoryRecord extends JsonMemoryRecord {
|
||||
|
||||
public RedisMemoryRecord(
|
||||
String id,
|
||||
String text,
|
||||
String description,
|
||||
String additionalMetadata,
|
||||
List<Float> embedding,
|
||||
String externalSourceName,
|
||||
boolean isReference) {
|
||||
super(
|
||||
id,
|
||||
text,
|
||||
description,
|
||||
additionalMetadata,
|
||||
embedding,
|
||||
externalSourceName,
|
||||
isReference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a RedisSearch Document to a HashMap.
|
||||
*
|
||||
* @param document A Redis Search Document
|
||||
* @return A HashMap containing the iterator's entries
|
||||
*/
|
||||
protected Map<String, Object> documentToMap(Document document) {
|
||||
return StreamSupport.stream(document.getProperties().spliterator(), false)
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the embedding information associated with the entry.
|
||||
*
|
||||
* @param map A hashmap with keys representing a record
|
||||
* @param withEmbedding A boolean flag indicating that the embedding should be returned with the
|
||||
* metadata
|
||||
* @return A MemoryRecord object.
|
||||
*/
|
||||
public static MemoryRecord mapToRecord(Map<String, String> map, boolean withEmbedding) {
|
||||
Embedding embedding = Embedding.empty();
|
||||
ZonedDateTime time = null;
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
try {
|
||||
if (map.get(TIME) != null) {
|
||||
time =
|
||||
mapper.readValue(
|
||||
map.getOrDefault(TIME, ZonedDateTime.now().toString()),
|
||||
ZonedDateTime.class);
|
||||
}
|
||||
if (withEmbedding) {
|
||||
List<Float> embeddings = mapper.readValue(map.get(EMBEDDING), List.class);
|
||||
embedding = new Embedding(embeddings);
|
||||
}
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RedisException(
|
||||
RedisException.ErrorCodes.REDIS_ERROR, "Error deserializing Redis entry", e);
|
||||
}
|
||||
|
||||
return MemoryRecord.localRecord(
|
||||
map.get(ID),
|
||||
map.get(TEXT),
|
||||
map.get(DESCRIPTION),
|
||||
embedding,
|
||||
map.get(ADDITIONAL_METADATA),
|
||||
map.get(EXTERNAL_SOURCE_NAME),
|
||||
time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the embedding information associated with the entry.
|
||||
*
|
||||
* @param record A MemoryRecord object
|
||||
* @return A hashmap containing the entries of the record.
|
||||
*/
|
||||
public static Map<String, Object> recordToMap(MemoryRecord record) {
|
||||
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
|
||||
map.put(ID, record.getMetadata().getId());
|
||||
map.put(EXTERNAL_SOURCE_NAME, record.getMetadata().getExternalSourceName());
|
||||
map.put(TEXT, record.getMetadata().getText());
|
||||
map.put(DESCRIPTION, record.getMetadata().getDescription());
|
||||
map.put(EMBEDDING, record.getEmbedding().getVector());
|
||||
map.put(ADDITIONAL_METADATA, record.getMetadata().getAdditionalMetadata());
|
||||
map.put(IS_REFERENCE, record.getMetadata().isReference());
|
||||
|
||||
return map;
|
||||
}
|
||||
}
|
||||
-658
@@ -1,658 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.connectors.memory.redis;
|
||||
|
||||
import com.microsoft.semantickernel.SKException;
|
||||
import com.microsoft.semantickernel.ai.embeddings.Embedding;
|
||||
import com.microsoft.semantickernel.memory.MemoryException;
|
||||
import com.microsoft.semantickernel.memory.MemoryException.ErrorCodes;
|
||||
import com.microsoft.semantickernel.memory.MemoryRecord;
|
||||
import com.microsoft.semantickernel.memory.MemoryStore;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.text.MessageFormat;
|
||||
import java.time.Instant;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Nonnull;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.function.Tuple2;
|
||||
import reactor.util.function.Tuples;
|
||||
import redis.clients.jedis.JedisPooled;
|
||||
import redis.clients.jedis.exceptions.JedisDataException;
|
||||
import redis.clients.jedis.resps.ScanResult;
|
||||
import redis.clients.jedis.search.Document;
|
||||
import redis.clients.jedis.search.IndexDefinition;
|
||||
import redis.clients.jedis.search.IndexOptions;
|
||||
import redis.clients.jedis.search.Query;
|
||||
import redis.clients.jedis.search.Schema;
|
||||
import redis.clients.jedis.search.SearchResult;
|
||||
import redis.clients.jedis.search.schemafields.VectorField.VectorAlgorithm;
|
||||
|
||||
/**
|
||||
* Semantic Memory implementation using Redis Vector Search. For more information about Redis Vector
|
||||
* Search {@see https://redis.com/solutions/use-cases/vector-database/}
|
||||
*/
|
||||
public class RedisMemoryStore implements MemoryStore {
|
||||
|
||||
private static final VectorAlgorithm DefaultIndexAlgorithm =
|
||||
VectorAlgorithm.HNSW; // FLAT or HNSW
|
||||
private static final String DefaultVectorType =
|
||||
RedisVectorType.FLOAT32; // prefer better accuracy
|
||||
private static final String DefaultDistanceMetric = RedisVectorDistanceMetric.L2;
|
||||
private static final Integer DefaultQueryDialect =
|
||||
2; // this has to be >= 2 for vector functionality
|
||||
private static final Integer DefaultVectorSize = 1536; // framework model dependent - ada-002
|
||||
private static final String SUFFIX = "sk";
|
||||
private static final String INDEX = "idx";
|
||||
private static final String OK = "OK";
|
||||
|
||||
private final JedisPooled client;
|
||||
private final String vectorDistanceMetric;
|
||||
|
||||
@SuppressFBWarnings("SS_SHOULD_BE_STATIC")
|
||||
private final String vectorType = DefaultVectorType;
|
||||
|
||||
private final Integer queryDialect;
|
||||
|
||||
public static void isXinRange(Integer x, Integer lower, Integer upper, String message) {
|
||||
if (lower > x || x > upper) {
|
||||
throw new IllegalArgumentException(MessageFormat.format(message, x));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of semantic memory using Redis.
|
||||
*
|
||||
* @param client A Redis Database client connection.
|
||||
* @param vectorSize Embedding vector size, defaults to 1536 - framework model dependent -
|
||||
* ada-002.
|
||||
* @param vectorDistanceMetric Metric for measuring vector distances, defaults to "COSINE"
|
||||
* @param queryDialect Query dialect, must be 2 or greater for vector similarity searching,
|
||||
* defaults to 2
|
||||
*/
|
||||
@SuppressFBWarnings("EI_EXPOSE_REP2")
|
||||
public RedisMemoryStore(
|
||||
JedisPooled client,
|
||||
Integer vectorSize,
|
||||
String vectorDistanceMetric,
|
||||
Integer queryDialect) {
|
||||
|
||||
isXinRange(
|
||||
vectorSize,
|
||||
0,
|
||||
8192,
|
||||
"Invalid vector size: {x}. Vector size must be in the range 0-8192.");
|
||||
isXinRange(
|
||||
queryDialect,
|
||||
2,
|
||||
4,
|
||||
"Invalid query dialect: {x}. Query dialect must be in the range 2-4.");
|
||||
|
||||
this.client = client;
|
||||
this.vectorDistanceMetric = vectorDistanceMetric;
|
||||
this.queryDialect = queryDialect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of semantic memory using Redis.
|
||||
*
|
||||
* @param connectionString Provide connection URL to a Redis instance.
|
||||
* @param vectorSize Embedding vector size, defaults to 1536.
|
||||
* @param vectorIndexAlgorithm Indexing algorithm for vectors, defaults to "HNSW"
|
||||
* @param vectorDistanceMetric Metric for measuring vector distances, defaults to "COSINE"
|
||||
* @param queryDialect Query dialect, must be 2 or greater for vector similarity searching,
|
||||
* defaults to 2
|
||||
*/
|
||||
public RedisMemoryStore(
|
||||
String connectionString,
|
||||
Integer vectorSize,
|
||||
VectorAlgorithm vectorIndexAlgorithm,
|
||||
String vectorDistanceMetric,
|
||||
Integer queryDialect) {
|
||||
|
||||
isXinRange(
|
||||
vectorSize,
|
||||
0,
|
||||
8192,
|
||||
"Invalid vector size: {x}. Vector size must be in the range 0-8192.");
|
||||
isXinRange(
|
||||
queryDialect,
|
||||
2,
|
||||
4,
|
||||
"Invalid query dialect: {x}. Query dialect must be in the range 2-4.");
|
||||
|
||||
this.client = new JedisPooled(connectionString);
|
||||
this.vectorDistanceMetric = vectorDistanceMetric;
|
||||
this.queryDialect = queryDialect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Redis key
|
||||
*
|
||||
* @param collectionName The name associated with a collection of embeddings.
|
||||
* @param key The unique id associated with the memory record to get.
|
||||
* @return A Redis key that identifies a particular Hash of Json object.
|
||||
*/
|
||||
private static String getRedisKey(String collectionName, String key) {
|
||||
if (key == null) {
|
||||
throw new SKException("cannot create a key with a null value");
|
||||
}
|
||||
|
||||
if (collectionName == null) {
|
||||
throw new SKException("cannot form a redis key with a null collection name");
|
||||
}
|
||||
|
||||
String name = collectionName.toLowerCase(Locale.ROOT);
|
||||
String id = JsonMemoryRecord.encodeId(key);
|
||||
return String.format("%s:%s", name, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a long timestamp given a OffsetDateTime
|
||||
*
|
||||
* @param timestamp An OffsetDateTime.
|
||||
* @return A long timestamp or -1 in the case of an error.
|
||||
*/
|
||||
private static long toTimestampLong(OffsetDateTime timestamp) {
|
||||
if (timestamp != null) {
|
||||
return timestamp.toInstant().toEpochMilli();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an OffsetDateTime given a valid timestamp
|
||||
*
|
||||
* @param timestamp A long timestamp value.
|
||||
* @return An OffsetDateTime if the timestamp is valid, else null.
|
||||
*/
|
||||
private static OffsetDateTime toDateTime(long timestamp) {
|
||||
if (timestamp > 0) {
|
||||
Instant instant = Instant.ofEpochMilli(timestamp);
|
||||
return OffsetDateTime.ofInstant(instant, ZoneId.systemDefault());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<List<String>> getCollectionsAsync() {
|
||||
return getIndexesAsync()
|
||||
.map(
|
||||
names ->
|
||||
names.stream()
|
||||
.map(
|
||||
name ->
|
||||
name.substring(
|
||||
0,
|
||||
name.length() - "-sk-idx".length()))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a List of Index(Collection) Names
|
||||
*
|
||||
* @return A list of names of the embedding indexes, including suffix, in the database
|
||||
*/
|
||||
private Mono<List<String>> getIndexesAsync() {
|
||||
return Mono.just(
|
||||
this.client.ftList().stream()
|
||||
.filter(name -> name.endsWith("-sk-idx"))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> createCollectionAsync(@Nonnull String collectionName) {
|
||||
// Indexes are created when sending a record; creation requires the size of the embedding
|
||||
// vector
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
public Mono<Boolean> doesIndexExistAsync(@Nonnull String collectionName) {
|
||||
|
||||
try {
|
||||
Map<String, Object> info = this.client.ftInfo(collectionName);
|
||||
return Mono.just(info != null && !info.isEmpty());
|
||||
} catch (Exception e) {
|
||||
if (!(e instanceof JedisDataException)) {
|
||||
throw e;
|
||||
}
|
||||
return Mono.just(false);
|
||||
}
|
||||
// return Mono.just(this.client.ftInfo(createIndexName(collectionName)) != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> doesCollectionExistAsync(@Nonnull String collectionName) {
|
||||
|
||||
Objects.requireNonNull(collectionName);
|
||||
String normalizedIndexName = createIndexName(collectionName);
|
||||
return getIndexesAsync()
|
||||
.map(
|
||||
list ->
|
||||
list.stream()
|
||||
.anyMatch(
|
||||
name ->
|
||||
name.equalsIgnoreCase(collectionName)
|
||||
|| name.equalsIgnoreCase(
|
||||
normalizedIndexName)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> deleteCollectionAsync(@Nonnull String collectionName) {
|
||||
Objects.requireNonNull(collectionName);
|
||||
try {
|
||||
this.client.ftDropIndex(createIndexName(collectionName));
|
||||
return Mono.empty();
|
||||
} catch (Exception e) {
|
||||
return Mono.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<MemoryRecord> getAsync(
|
||||
@Nonnull String collectionName, @Nonnull String key, boolean withEmbedding) {
|
||||
|
||||
Map<String, String> map =
|
||||
this.client.hgetAll(
|
||||
String.format("%s:%s", collectionName, key).toLowerCase(Locale.ROOT));
|
||||
if (map == null || map.isEmpty()) {
|
||||
return Mono.empty();
|
||||
}
|
||||
MemoryRecord record = RedisMemoryRecord.mapToRecord(map, withEmbedding);
|
||||
return Mono.just(record);
|
||||
}
|
||||
|
||||
public Mono<MemoryRecord> getInternalAsync(
|
||||
@Nonnull String collectionName, @Nonnull String key, boolean withEmbedding) {
|
||||
|
||||
Objects.requireNonNull(collectionName);
|
||||
Objects.requireNonNull(key);
|
||||
|
||||
Map<String, String> entry =
|
||||
this.client.hgetAll(String.format("%s:%s", collectionName, key));
|
||||
|
||||
if (entry == null) return Mono.empty();
|
||||
|
||||
return Mono.just(RedisMemoryRecord.mapToRecord(entry, withEmbedding));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a RedisSearch Document to a HashMap.
|
||||
*
|
||||
* @param document A Redis Search Document
|
||||
* @return A HashMap containing the iterator's entries
|
||||
*/
|
||||
protected Map<String, String> documentToMap(Document document) {
|
||||
|
||||
return iterableToMap(document.getProperties());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an Iterable<Map.Entry<String, Object>> to a HashMap.
|
||||
*
|
||||
* @param entryIterator An Iterable<Map.Entry<String, Object>>
|
||||
* @return A HashMap containing the iterator's entries
|
||||
*/
|
||||
protected Map<String, String> iterableToMap(Iterable<Map.Entry<String, Object>> entryIterator) {
|
||||
|
||||
Map<String, String> entryMap = new HashMap<>();
|
||||
entryIterator.forEach((e) -> entryMap.put(e.getKey(), e.getValue().toString()));
|
||||
|
||||
return entryMap;
|
||||
}
|
||||
|
||||
protected MemoryRecord documentToMemoryRecord(Document document, boolean withEmbedding) {
|
||||
|
||||
Map<String, String> map = documentToMap(document);
|
||||
return RedisMemoryRecord.mapToRecord(map, withEmbedding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Collection<MemoryRecord>> getBatchAsync(
|
||||
@Nonnull String collectionName,
|
||||
@Nonnull Collection<String> keys,
|
||||
boolean withEmbeddings) {
|
||||
Objects.requireNonNull(collectionName);
|
||||
// ACS issues one query per key; redis has several possible calls, fastest will be hkeys
|
||||
// followed by hvals
|
||||
|
||||
return Flux.fromIterable(keys)
|
||||
.flatMap(key -> getAsync(collectionName, key, withEmbeddings))
|
||||
.collectList()
|
||||
.map(records -> records);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<String> upsertAsync(@Nonnull String collectionName, @Nonnull MemoryRecord record) {
|
||||
return upsertRecordAsync(collectionName, record);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key of the upserted object (wraps the record in a list and calls the batch
|
||||
* function).
|
||||
*
|
||||
* @param collectionName The name associated with a collection of embeddings.
|
||||
* @param record The memory record to upsert.
|
||||
* @return The key of the newly created record.
|
||||
*/
|
||||
public Mono<String> upsertRecordAsync(
|
||||
@Nonnull String collectionName, @Nonnull MemoryRecord record) {
|
||||
return upsertBatchAsync(collectionName, Collections.singletonList(record))
|
||||
.map(Collection::iterator)
|
||||
.map(Iterator::next);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Collection<String>> upsertBatchAsync(
|
||||
@Nonnull String collectionName, @Nonnull Collection<MemoryRecord> records) {
|
||||
|
||||
Objects.requireNonNull(collectionName);
|
||||
Objects.requireNonNull(records);
|
||||
|
||||
if (records.isEmpty()) {
|
||||
return Mono.just(Collections.emptyList());
|
||||
}
|
||||
|
||||
doesCollectionExistAsync(collectionName)
|
||||
.map(
|
||||
exists -> {
|
||||
if (!exists) {
|
||||
int embeddingSize =
|
||||
records.stream()
|
||||
.map(record -> record.getEmbedding().getVector())
|
||||
.map(List::size)
|
||||
.max(Integer::compareTo)
|
||||
.orElse(0);
|
||||
createIndexAsync(collectionName, embeddingSize);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
return Mono.just(
|
||||
records.stream()
|
||||
.map(
|
||||
record -> {
|
||||
Map<String, Object> map = RedisMemoryRecord.recordToMap(record);
|
||||
// we have to change the embeddings to bytes - it's easiest to
|
||||
// modify the map
|
||||
List<Float> embedding = record.getEmbedding().getVector();
|
||||
map.replace(
|
||||
RedisMemoryRecord.EMBEDDING,
|
||||
embedding,
|
||||
embeddingToBytes(embedding));
|
||||
String key =
|
||||
getRedisKey(
|
||||
collectionName, record.getMetadata().getId());
|
||||
this.client.hsetObject(key, map);
|
||||
return key;
|
||||
})
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> removeAsync(@Nonnull String collectionName, @Nonnull String key) {
|
||||
return Mono.fromRunnable(
|
||||
() -> this.client.hdel(String.format("%s:%s", collectionName, key)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> removeBatchAsync(
|
||||
@Nonnull String collectionName, @Nonnull Collection<String> keys) {
|
||||
return Mono.fromRunnable(
|
||||
() -> {
|
||||
// ScanResult<String> results = this.client.scan(collectionName);
|
||||
// results.getResult().forEach(key -> this.client.hdel(key));
|
||||
keys.forEach(
|
||||
key -> this.client.hdel(String.format("%s:%s", collectionName, key)));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new search index.
|
||||
*
|
||||
* @param collectionName Index name
|
||||
* @param embeddingSize Size of the embedding vector
|
||||
* @return A Mono that completes when the index is created
|
||||
*/
|
||||
private Mono<Boolean> createIndexAsync(@Nonnull String collectionName, int embeddingSize) {
|
||||
if (embeddingSize < 1) {
|
||||
throw new RedisException(
|
||||
RedisException.ErrorCodes.INVALID_EMBEDDING_SIZE,
|
||||
"the value must be greater than zero");
|
||||
}
|
||||
|
||||
Map<String, Object> attributes = new HashMap<>();
|
||||
|
||||
attributes.put(RedisIndexSchemaParams.TYPE, vectorType);
|
||||
attributes.put(RedisIndexSchemaParams.DIM, embeddingSize);
|
||||
attributes.put(RedisIndexSchemaParams.DIST, vectorDistanceMetric);
|
||||
|
||||
Schema schema =
|
||||
new Schema()
|
||||
.addVectorField("Embedding", Schema.VectorField.VectorAlgo.FLAT, attributes)
|
||||
.as("Embedding")
|
||||
.addTextField("Id", 1.0)
|
||||
.as("Id")
|
||||
.addTextField("Text", 1.0)
|
||||
.as("Text")
|
||||
.addTextField("Description", 1.0)
|
||||
.as("Description")
|
||||
.addTextField("AdditionalMetadata", 1.0)
|
||||
.as("AdditionalMetadata")
|
||||
.addTextField("ExternalSourceName", 1.0)
|
||||
.as("ExternalSourceName");
|
||||
|
||||
IndexDefinition rule =
|
||||
new IndexDefinition(IndexDefinition.Type.HASH)
|
||||
.setPrefixes(collectionName.toLowerCase() + ":");
|
||||
// customarily redis indexes are named <collection>-idx; we're going to suffix them
|
||||
// (-sk-idx) so we can find them
|
||||
String normalizedIndexName = createIndexName(collectionName);
|
||||
String result =
|
||||
this.client.ftCreate(
|
||||
normalizedIndexName,
|
||||
IndexOptions.defaultOptions().setDefinition(rule),
|
||||
schema);
|
||||
|
||||
if (result.equals(OK)) {
|
||||
return Mono.just(true);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Collection<Tuple2<MemoryRecord, Float>>> getNearestMatchesAsync(
|
||||
@Nonnull String collectionName,
|
||||
@Nonnull Embedding embedding,
|
||||
int limit,
|
||||
float minRelevanceScore,
|
||||
boolean withEmbedding) {
|
||||
|
||||
Objects.requireNonNull(collectionName);
|
||||
Objects.requireNonNull(embedding);
|
||||
|
||||
if (limit <= 0) {
|
||||
return Mono.just(Collections.emptyList());
|
||||
}
|
||||
Query query =
|
||||
new Query("*=>[KNN $k @Embedding $vec AS vector_score]")
|
||||
.returnFields("Id", "Text", "Description", "vector_score")
|
||||
.setSortBy("vector_score", true)
|
||||
.addParam("k", limit)
|
||||
.addParam("vec", embeddingToBytes(embedding.getVector()))
|
||||
.limit(0, limit)
|
||||
.dialect(queryDialect);
|
||||
String indexName = createIndexName(collectionName);
|
||||
SearchResult results = this.client.ftSearch(indexName, query);
|
||||
|
||||
// TODO convert to Collection<Tuple2<MemoryRecord, Float>>
|
||||
Collection<Tuple2<MemoryRecord, Float>> searchTuples =
|
||||
results.getDocuments().stream()
|
||||
.map(
|
||||
document -> {
|
||||
MemoryRecord memoryRecord =
|
||||
documentToMemoryRecord(document, withEmbedding);
|
||||
return Tuples.of(
|
||||
memoryRecord, document.getScore().floatValue());
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
return Mono.just(searchTuples);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Tuple2<MemoryRecord, Float>> getNearestMatchAsync(
|
||||
@Nonnull String collectionName,
|
||||
@Nonnull Embedding embedding,
|
||||
float minRelevanceScore,
|
||||
boolean withEmbedding) {
|
||||
return getNearestMatchesAsync(
|
||||
collectionName, embedding, 1, minRelevanceScore, withEmbedding)
|
||||
.flatMap(
|
||||
nearestMatches -> {
|
||||
if (nearestMatches.isEmpty()) {
|
||||
return Mono.empty();
|
||||
}
|
||||
return Mono.just(nearestMatches.iterator().next());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the Azure List<Float> embedding structure to byte[] for storage in Redis
|
||||
*
|
||||
* @param embeddings the list of vectors returned by the model
|
||||
* @return byte[]
|
||||
*/
|
||||
private byte[] embeddingToBytes(List<Float> embeddings) {
|
||||
ByteBuffer bytes = ByteBuffer.allocate(Float.BYTES * embeddings.size());
|
||||
bytes.order(ByteOrder.LITTLE_ENDIAN);
|
||||
embeddings.iterator().forEachRemaining(bytes::putFloat);
|
||||
return bytes.array();
|
||||
}
|
||||
|
||||
private static OffsetDateTime ParseTimestamp(Long timestamp) {
|
||||
if (timestamp != null && timestamp > 0) {
|
||||
return OffsetDateTime.parse(timestamp.toString());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize an index name
|
||||
*
|
||||
* @param indexName Index name
|
||||
* @return A string to be used as the root of the index name; minus '-idx'
|
||||
*/
|
||||
private static String normalizeCollectionName(String indexName) {
|
||||
if (indexName.length() > 128) {
|
||||
throw new IllegalArgumentException("The collection name cannot exceed 128 chars");
|
||||
}
|
||||
return indexName.toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
private static String createIndexName(String collectionName) {
|
||||
|
||||
if (collectionName.length() > 128) {
|
||||
throw new IllegalArgumentException("The indexName name cannot exceed 128 chars");
|
||||
}
|
||||
return String.format(
|
||||
"%s-%s-%s",
|
||||
normalizeCollectionName(collectionName), RedisMemoryStore.SUFFIX, INDEX);
|
||||
}
|
||||
|
||||
protected Map<String, MemoryRecord> getCollection(@Nonnull String collectionName) {
|
||||
Objects.requireNonNull(collectionName);
|
||||
ScanResult<String> results = this.client.scan(collectionName);
|
||||
|
||||
if (results == null)
|
||||
throw new MemoryException(
|
||||
ErrorCodes.ATTEMPTED_TO_ACCESS_NONEXISTENT_COLLECTION, collectionName);
|
||||
|
||||
return Collections.unmodifiableMap(
|
||||
(Map<String, MemoryRecord>)
|
||||
results.getResult().stream()
|
||||
.map(
|
||||
key ->
|
||||
RedisMemoryRecord.mapToRecord(
|
||||
this.client.hgetAll(
|
||||
String.format(
|
||||
"%s:%s",
|
||||
collectionName, key)),
|
||||
false)));
|
||||
}
|
||||
|
||||
public static class Builder implements MemoryStore.Builder<RedisMemoryStore> {
|
||||
private String connectionString;
|
||||
private int vectorSize; // in theory determined by the model but can be overridden
|
||||
private VectorAlgorithm vectorIndexAlgorithm;
|
||||
private String vectorDistanceMetric;
|
||||
private int queryDialect = 0; // must best at least two for vector index
|
||||
|
||||
public Builder connectionString(String connectionString) {
|
||||
this.connectionString = connectionString;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder vectorSize(int vectorSize) {
|
||||
this.vectorSize = vectorSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder vectorIndexAlgorithm(VectorAlgorithm vectorIndexAlgorithm) {
|
||||
this.vectorIndexAlgorithm = vectorIndexAlgorithm;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder vectorDistanceMetric(String vectorDistanceMetric) {
|
||||
this.vectorDistanceMetric = vectorDistanceMetric;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder queryDialect(int queryDialect) {
|
||||
this.queryDialect = queryDialect;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
/*
|
||||
* Create a RedisMemoryStore using assigned values.
|
||||
*
|
||||
* @return A RedisMemoryStore object configured with the specified values
|
||||
*/
|
||||
public RedisMemoryStore build() {
|
||||
|
||||
// make sure everything we need has been set
|
||||
return new RedisMemoryStore(
|
||||
connectionString,
|
||||
vectorSize,
|
||||
vectorIndexAlgorithm,
|
||||
vectorDistanceMetric,
|
||||
queryDialect);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a RedisMemoryStore object using default settings; requires a valid connection
|
||||
* string.
|
||||
*
|
||||
* @return A RedisMemoryStore object configured with default values
|
||||
*/
|
||||
public RedisMemoryStore buildDefault() {
|
||||
return new RedisMemoryStore(
|
||||
connectionString,
|
||||
DefaultVectorSize,
|
||||
RedisMemoryStore.DefaultIndexAlgorithm,
|
||||
RedisMemoryStore.DefaultDistanceMetric,
|
||||
RedisMemoryStore.DefaultQueryDialect);
|
||||
}
|
||||
}
|
||||
}
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.connectors.memory.redis;
|
||||
|
||||
/* <summary>
|
||||
Supported distance metrics are {L2, IP, COSINE}. The default value is "COSINE".
|
||||
<see href="https://redis.io/docs/interact/search-and-query/search/vectors/"/>
|
||||
</summary> */
|
||||
public class RedisVectorDistanceMetric {
|
||||
|
||||
/* <summary> Euclidean distance between two vectors </summary> */
|
||||
public static final String L2 = "L2";
|
||||
|
||||
/* <summary> Inner product of two vectors </summary> */
|
||||
public static final String IP = "IP";
|
||||
|
||||
/* <summary> Cosine distance of two vectors </summary> */
|
||||
public static final String COS = "COSINE";
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.connectors.memory.redis;
|
||||
|
||||
public class RedisVectorType {
|
||||
public static final String FLOAT32 = "FLOAT32";
|
||||
public static final String FLOAT64 = "FLOAT64";
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-parent</artifactId>
|
||||
<version>1.0.0-rc2-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>semantickernel-connectors-web-bing</artifactId>
|
||||
|
||||
<name>Semantic Kernel Bing Connector</name>
|
||||
<description>Defines Bing connectors to be used with the Semantic Kernel</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -1,420 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<profiles version="13">
|
||||
<profile kind="CodeFormatterProfile" name="Eclipse" version="13">
|
||||
<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode" value="enabled"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="10"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.compliance" value="10"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.source" value="10"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression"
|
||||
value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration"
|
||||
value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="100"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments"
|
||||
value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header"
|
||||
value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header"
|
||||
value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header"
|
||||
value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
|
||||
<setting
|
||||
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
|
||||
<setting
|
||||
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
|
||||
<setting
|
||||
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference"
|
||||
value="do not insert"/>
|
||||
<setting
|
||||
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw"
|
||||
value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression"
|
||||
value="do not insert"/>
|
||||
<setting
|
||||
id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation"
|
||||
value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="100"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration"
|
||||
value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statement" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_declaration" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
|
||||
</profile>
|
||||
</profiles>
|
||||
@@ -1,308 +0,0 @@
|
||||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------------
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Apache Maven Wrapper startup batch script, version 3.2.0
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# JAVA_HOME - location of a JDK home dir
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
# e.g. to debug Maven itself, use
|
||||
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if [ -z "$MAVEN_SKIP_RC" ] ; then
|
||||
|
||||
if [ -f /usr/local/etc/mavenrc ] ; then
|
||||
. /usr/local/etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f /etc/mavenrc ] ; then
|
||||
. /etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f "$HOME/.mavenrc" ] ; then
|
||||
. "$HOME/.mavenrc"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# OS specific support. $var _must_ be set to either true or false.
|
||||
cygwin=false;
|
||||
darwin=false;
|
||||
mingw=false
|
||||
case "$(uname)" in
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true;;
|
||||
Darwin*) darwin=true
|
||||
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
|
||||
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
if [ -x "/usr/libexec/java_home" ]; then
|
||||
JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME
|
||||
else
|
||||
JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
if [ -r /etc/gentoo-release ] ; then
|
||||
JAVA_HOME=$(java-config --jre-home)
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
|
||||
fi
|
||||
|
||||
# For Mingw, ensure paths are in UNIX format before anything is touched
|
||||
if $mingw ; then
|
||||
[ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)"
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
javaExecutable="$(which javac)"
|
||||
if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then
|
||||
# readlink(1) is not available as standard on Solaris 10.
|
||||
readLink=$(which readlink)
|
||||
if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then
|
||||
if $darwin ; then
|
||||
javaHome="$(dirname "\"$javaExecutable\"")"
|
||||
javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac"
|
||||
else
|
||||
javaExecutable="$(readlink -f "\"$javaExecutable\"")"
|
||||
fi
|
||||
javaHome="$(dirname "\"$javaExecutable\"")"
|
||||
javaHome=$(expr "$javaHome" : '\(.*\)/bin')
|
||||
JAVA_HOME="$javaHome"
|
||||
export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$JAVACMD" ] ; then
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
else
|
||||
JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||
echo " We cannot execute $JAVACMD" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
echo "Warning: JAVA_HOME environment variable is not set."
|
||||
fi
|
||||
|
||||
# traverses directory structure from process work directory to filesystem root
|
||||
# first directory with .mvn subdirectory is considered project base directory
|
||||
find_maven_basedir() {
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo "Path not specified to find_maven_basedir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
basedir="$1"
|
||||
wdir="$1"
|
||||
while [ "$wdir" != '/' ] ; do
|
||||
if [ -d "$wdir"/.mvn ] ; then
|
||||
basedir=$wdir
|
||||
break
|
||||
fi
|
||||
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||
if [ -d "${wdir}" ]; then
|
||||
wdir=$(cd "$wdir/.." || exit 1; pwd)
|
||||
fi
|
||||
# end of workaround
|
||||
done
|
||||
printf '%s' "$(cd "$basedir" || exit 1; pwd)"
|
||||
}
|
||||
|
||||
# concatenates all lines of a file
|
||||
concat_lines() {
|
||||
if [ -f "$1" ]; then
|
||||
# Remove \r in case we run on Windows within Git Bash
|
||||
# and check out the repository with auto CRLF management
|
||||
# enabled. Otherwise, we may read lines that are delimited with
|
||||
# \r\n and produce $'-Xarg\r' rather than -Xarg due to word
|
||||
# splitting rules.
|
||||
tr -s '\r\n' ' ' < "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
log() {
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
printf '%s\n' "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
|
||||
if [ -z "$BASE_DIR" ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
|
||||
log "$MAVEN_PROJECTBASEDIR"
|
||||
|
||||
##########################################################################################
|
||||
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
# This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
##########################################################################################
|
||||
wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
|
||||
if [ -r "$wrapperJarPath" ]; then
|
||||
log "Found $wrapperJarPath"
|
||||
else
|
||||
log "Couldn't find $wrapperJarPath, downloading it ..."
|
||||
|
||||
if [ -n "$MVNW_REPOURL" ]; then
|
||||
wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||
else
|
||||
wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||
fi
|
||||
while IFS="=" read -r key value; do
|
||||
# Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
|
||||
safeValue=$(echo "$value" | tr -d '\r')
|
||||
case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;;
|
||||
esac
|
||||
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
log "Downloading from: $wrapperUrl"
|
||||
|
||||
if $cygwin; then
|
||||
wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
|
||||
fi
|
||||
|
||||
if command -v wget > /dev/null; then
|
||||
log "Found wget ... using wget"
|
||||
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||
else
|
||||
wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
elif command -v curl > /dev/null; then
|
||||
log "Found curl ... using curl"
|
||||
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
|
||||
else
|
||||
curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
else
|
||||
log "Falling back to using Java to download"
|
||||
javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||
javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
|
||||
# For Cygwin, switch paths to Windows format before running javac
|
||||
if $cygwin; then
|
||||
javaSource=$(cygpath --path --windows "$javaSource")
|
||||
javaClass=$(cygpath --path --windows "$javaClass")
|
||||
fi
|
||||
if [ -e "$javaSource" ]; then
|
||||
if [ ! -e "$javaClass" ]; then
|
||||
log " - Compiling MavenWrapperDownloader.java ..."
|
||||
("$JAVA_HOME/bin/javac" "$javaSource")
|
||||
fi
|
||||
if [ -e "$javaClass" ]; then
|
||||
log " - Running MavenWrapperDownloader.java ..."
|
||||
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
##########################################################################################
|
||||
# End of extension
|
||||
##########################################################################################
|
||||
|
||||
# If specified, validate the SHA-256 sum of the Maven wrapper jar file
|
||||
wrapperSha256Sum=""
|
||||
while IFS="=" read -r key value; do
|
||||
case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;;
|
||||
esac
|
||||
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
if [ -n "$wrapperSha256Sum" ]; then
|
||||
wrapperSha256Result=false
|
||||
if command -v sha256sum > /dev/null; then
|
||||
if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then
|
||||
wrapperSha256Result=true
|
||||
fi
|
||||
elif command -v shasum > /dev/null; then
|
||||
if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then
|
||||
wrapperSha256Result=true
|
||||
fi
|
||||
else
|
||||
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available."
|
||||
echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties."
|
||||
exit 1
|
||||
fi
|
||||
if [ $wrapperSha256Result = false ]; then
|
||||
echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
|
||||
echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
|
||||
echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
|
||||
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
|
||||
MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
|
||||
fi
|
||||
|
||||
# Provide a "standardized" way to retrieve the CLI args that will
|
||||
# work with both Windows and non-Windows executions.
|
||||
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*"
|
||||
export MAVEN_CMD_LINE_ARGS
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
# shellcheck disable=SC2086 # safe args
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
$MAVEN_DEBUG_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
||||
Vendored
-205
@@ -1,205 +0,0 @@
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Apache Maven Wrapper startup batch script, version 3.2.0
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
|
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
@REM e.g. to debug Maven itself, use
|
||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||
@echo off
|
||||
@REM set title of command window
|
||||
title %0
|
||||
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
|
||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||
|
||||
@REM set %HOME% to equivalent of $HOME
|
||||
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||
|
||||
@REM Execute a user defined script before this one
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
|
||||
if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
|
||||
:skipRcPre
|
||||
|
||||
@setlocal
|
||||
|
||||
set ERROR_CODE=0
|
||||
|
||||
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||
@setlocal
|
||||
|
||||
@REM ==== START VALIDATION ====
|
||||
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME not found in your environment. >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
:OkJHome
|
||||
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
@REM ==== END VALIDATION ====
|
||||
|
||||
:init
|
||||
|
||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||
@REM Fallback to current working directory if not found.
|
||||
|
||||
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||
|
||||
set EXEC_DIR=%CD%
|
||||
set WDIR=%EXEC_DIR%
|
||||
:findBaseDir
|
||||
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||
cd ..
|
||||
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||
set WDIR=%CD%
|
||||
goto findBaseDir
|
||||
|
||||
:baseDirFound
|
||||
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||
cd "%EXEC_DIR%"
|
||||
goto endDetectBaseDir
|
||||
|
||||
:baseDirNotFound
|
||||
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||
cd "%EXEC_DIR%"
|
||||
|
||||
:endDetectBaseDir
|
||||
|
||||
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||
|
||||
@setlocal EnableExtensions EnableDelayedExpansion
|
||||
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||
|
||||
:endReadAdditionalConfig
|
||||
|
||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||
|
||||
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||
IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
|
||||
)
|
||||
|
||||
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
if exist %WRAPPER_JAR% (
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Found %WRAPPER_JAR%
|
||||
)
|
||||
) else (
|
||||
if not "%MVNW_REPOURL%" == "" (
|
||||
SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||
)
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||
echo Downloading from: %WRAPPER_URL%
|
||||
)
|
||||
|
||||
powershell -Command "&{"^
|
||||
"$webclient = new-object System.Net.WebClient;"^
|
||||
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
|
||||
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
|
||||
"}"^
|
||||
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
|
||||
"}"
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Finished downloading %WRAPPER_JAR%
|
||||
)
|
||||
)
|
||||
@REM End of extension
|
||||
|
||||
@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
|
||||
SET WRAPPER_SHA_256_SUM=""
|
||||
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||
IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
|
||||
)
|
||||
IF NOT %WRAPPER_SHA_256_SUM%=="" (
|
||||
powershell -Command "&{"^
|
||||
"$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
|
||||
"If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
|
||||
" Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
|
||||
" Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
|
||||
" Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
|
||||
" exit 1;"^
|
||||
"}"^
|
||||
"}"
|
||||
if ERRORLEVEL 1 goto error
|
||||
)
|
||||
|
||||
@REM Provide a "standardized" way to retrieve the CLI args that will
|
||||
@REM work with both Windows and non-Windows executions.
|
||||
set MAVEN_CMD_LINE_ARGS=%*
|
||||
|
||||
%MAVEN_JAVA_EXE% ^
|
||||
%JVM_CONFIG_MAVEN_PROPS% ^
|
||||
%MAVEN_OPTS% ^
|
||||
%MAVEN_DEBUG_OPTS% ^
|
||||
-classpath %WRAPPER_JAR% ^
|
||||
"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
|
||||
%WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
|
||||
if ERRORLEVEL 1 goto error
|
||||
goto end
|
||||
|
||||
:error
|
||||
set ERROR_CODE=1
|
||||
|
||||
:end
|
||||
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||
|
||||
if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
|
||||
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
|
||||
if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
|
||||
:skipRcPost
|
||||
|
||||
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||
if "%MAVEN_BATCH_PAUSE%"=="on" pause
|
||||
|
||||
if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
|
||||
|
||||
cmd /C exit /B %ERROR_CODE%
|
||||
-788
@@ -1,788 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-parent</artifactId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<url>https://www.github.com/microsoft/semantic-kernel</url>
|
||||
<name>Semantic Kernel Parent</name>
|
||||
<description>Parent pom for the Semantic Kernel Project</description>
|
||||
|
||||
<properties>
|
||||
<azure-ai-openai.version>1.0.0-beta.8</azure-ai-openai.version>
|
||||
<checkstyle.version>10.13.0</checkstyle.version>
|
||||
<com.uber.nullaway.version>0.10.21</com.uber.nullaway.version>
|
||||
<google.errorprone.core.version>2.19.1</google.errorprone.core.version>
|
||||
<google.java.format.version>1.17.0</google.java.format.version>
|
||||
<jreleaser.plugin.version>1.6.0</jreleaser.plugin.version>
|
||||
<junit5.version>5.10.2</junit5.version>
|
||||
<log4j2.version>2.22.1</log4j2.version>
|
||||
<maven.antrun-plugin.version>3.1.0</maven.antrun-plugin.version>
|
||||
<maven.changes-plugin.version>2.12.1</maven.changes-plugin.version>
|
||||
<maven.checkstyle-plugin.version>3.3.1</maven.checkstyle-plugin.version>
|
||||
<maven.clean-plugin.version>3.3.2</maven.clean-plugin.version>
|
||||
<maven.compiler-plugin.version>3.12.1</maven.compiler-plugin.version>
|
||||
<maven.compiler.release>8</maven.compiler.release>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<maven.dependency-plugin.version>3.6.1</maven.dependency-plugin.version>
|
||||
<maven.deploy-plugin.version>3.1.1</maven.deploy-plugin.version>
|
||||
<maven.directory-maven-plugin.version>1.0</maven.directory-maven-plugin.version>
|
||||
<maven.enforcer-plugin.version>3.4.1</maven.enforcer-plugin.version>
|
||||
<maven.exec-plugin.version>3.1.1</maven.exec-plugin.version>
|
||||
<maven.install-plugin.version>3.1.1</maven.install-plugin.version>
|
||||
<maven.jacoco-plugin.version>0.8.11</maven.jacoco-plugin.version>
|
||||
<maven.jar-plugin.version>3.3.0</maven.jar-plugin.version>
|
||||
<maven.javadoc-plugin.version>3.6.3</maven.javadoc-plugin.version>
|
||||
<maven.jxr-plugin.version>3.3.2</maven.jxr-plugin.version>
|
||||
<maven.license-plugin.version>2.4.0</maven.license-plugin.version>
|
||||
<maven.pmd-plugin.version>3.21.2</maven.pmd-plugin.version>
|
||||
<maven.project-info-reports-plugin.version>3.5.0</maven.project-info-reports-plugin.version>
|
||||
<maven.rat-plugin.version>0.16.1</maven.rat-plugin.version>
|
||||
<maven.release-plugin.version>3.0.1</maven.release-plugin.version>
|
||||
<maven.resources-plugin.version>3.3.1</maven.resources-plugin.version>
|
||||
<maven.site-plugin.version>4.0.0-M13</maven.site-plugin.version>
|
||||
<maven.shade-plugin.version>3.5.1</maven.shade-plugin.version>
|
||||
<maven.source-plugin.version>3.3.0</maven.source-plugin.version>
|
||||
<maven.spotbugs-plugin.version>4.8.3.1</maven.spotbugs-plugin.version>
|
||||
<!-- TODO 2.30.0 is the last supported version for Java 8 Not sure how 2.38.0 is working... -->
|
||||
<maven.spotless-plugin.version>2.38.0</maven.spotless-plugin.version>
|
||||
<maven.surefire-plugin.version>3.2.5</maven.surefire-plugin.version>
|
||||
<maven.version>3.9.3</maven.version>
|
||||
<maven.versions-plugin.version>2.16.2</maven.versions-plugin.version>
|
||||
<mockito.version>5.10.0</mockito.version>
|
||||
<mutability.detector.version>0.9.1</mutability.detector.version>
|
||||
<pmd.version>6.55.0</pmd.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.github.repository>microsoft/semantic-kernel</project.github.repository>
|
||||
<repository.url>[email protected]:${project.github.repository}.git</repository.url>
|
||||
<spotbugs.version>4.8.3</spotbugs.version>
|
||||
<compilingJdk8>false</compilingJdk8>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
<module>semantickernel-bom</module>
|
||||
|
||||
<module>aiservices/openai</module>
|
||||
|
||||
<module>semantickernel-api</module>
|
||||
</modules>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-bom</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>${junit5.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>${junit5.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>${log4j2.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>${log4j2.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j2-impl</artifactId>
|
||||
<version>${log4j2.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>${mockito.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.azure</groupId>
|
||||
<artifactId>azure-ai-openai</artifactId>
|
||||
<version>${azure-ai-openai.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-connectors-ai-openai</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantic-kernel.extensions</groupId>
|
||||
<artifactId>semantickernel-sequentialplanner-extension</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantic-kernel.extensions</groupId>
|
||||
<artifactId>semantickernel-actionplanner-extension</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.spotbugs</groupId>
|
||||
<artifactId>spotbugs-annotations</artifactId>
|
||||
<version>${spotbugs.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<!--
|
||||
NOTE: Some plugin configuration is set in the reporting section below as
|
||||
opposed to here by design -->
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.github.spotbugs</groupId>
|
||||
<artifactId>spotbugs-maven-plugin</artifactId>
|
||||
<version>${maven.spotbugs-plugin.version}</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.github.spotbugs</groupId>
|
||||
<artifactId>spotbugs</artifactId>
|
||||
<version>${spotbugs.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-changes-plugin</artifactId>
|
||||
<version>${maven.changes-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>${maven.checkstyle-plugin.version}</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.puppycrawl.tools</groupId>
|
||||
<artifactId>checkstyle</artifactId>
|
||||
<version>${checkstyle.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>${maven.clean-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven.compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<source>${maven.compiler.release}</source>
|
||||
<target>${maven.compiler.release}</target>
|
||||
<release>8</release>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>${maven.dependency-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>${maven.deploy-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>${maven.enforcer-plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>enforce-maven</id>
|
||||
<goals>
|
||||
<goal>enforce</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<requireMavenVersion>
|
||||
<version>${maven.version}</version>
|
||||
</requireMavenVersion>
|
||||
</rules>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-install-plugin</artifactId>
|
||||
<version>${maven.install-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>${maven.jar-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>${maven.javadoc-plugin.version}</version>
|
||||
<configuration>
|
||||
<!-- TODO: Tighten this up when we go GA -->
|
||||
<failOnError>false</failOnError>
|
||||
<nohelp>true</nohelp>
|
||||
<show>public</show>
|
||||
<excludePackageNames>*.implementation.*:*.implementation</excludePackageNames>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jxr-plugin</artifactId>
|
||||
<version>${maven.jxr-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-pmd-plugin</artifactId>
|
||||
<version>${maven.pmd-plugin.version}</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd-core</artifactId>
|
||||
<version>${pmd.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd-java</artifactId>
|
||||
<version>${pmd.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd-javascript</artifactId>
|
||||
<version>${pmd.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd-jsp</artifactId>
|
||||
<version>${pmd.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-release-plugin</artifactId>
|
||||
<version>${maven.release-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>${maven.shade-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>${maven.source-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${maven.surefire-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>${maven.site-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>${maven.project-info-reports-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>${maven.resources-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<version>${maven.antrun-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.rat</groupId>
|
||||
<artifactId>apache-rat-plugin</artifactId>
|
||||
<version>${maven.rat-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>${maven.exec-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<version>${maven.license-plugin.version}</version>
|
||||
<configuration>
|
||||
<organizationName>Microsoft</organizationName>
|
||||
<inceptionYear>2023</inceptionYear>
|
||||
<licenseName>mit</licenseName>
|
||||
<licenseFile>${basedir}/target/LICENSE</licenseFile>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>versions-maven-plugin</artifactId>
|
||||
<version>${maven.versions-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.commonjava.maven.plugins</groupId>
|
||||
<artifactId>directory-maven-plugin</artifactId>
|
||||
<version>${maven.directory-maven-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>${maven.jacoco-plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>report</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>animal-sniffer-maven-plugin</artifactId>
|
||||
<version>1.23</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>android</id>
|
||||
<phase>test</phase>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<!--
|
||||
COMPATIBLE: Android API level 26 (Android 8.0)
|
||||
See https://developer.android.com/studio/releases/platforms
|
||||
|
||||
Note: anything below this requires changes to the codebase to pass compatibility
|
||||
-->
|
||||
<signature>
|
||||
<groupId>net.sf.androidscents.signature</groupId>
|
||||
<artifactId>android-api-level-26</artifactId>
|
||||
<version>8.0.0_r2</version>
|
||||
</signature>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.github.spotbugs</groupId>
|
||||
<artifactId>spotbugs-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>update-project-license</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>jar-no-fork</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<!--
|
||||
If versions are not explicitly set it means they're inheriting from the
|
||||
pluginManagement section above
|
||||
-->
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.github.spotbugs</groupId>
|
||||
<artifactId>spotbugs-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.mutabilitydetector</groupId>
|
||||
<artifactId>MutabilityDetector4FindBugs</artifactId>
|
||||
<version>${mutability.detector.version}</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-changes-plugin</artifactId>
|
||||
<!-- TODO: This configuration is only for when we produce GitHub published reports -->
|
||||
<!--
|
||||
<configuration>
|
||||
<githubAPIScheme>https</githubAPIScheme>
|
||||
<githubAPIPort>443</githubAPIPort>
|
||||
<includeOpenIssues>false</includeOpenIssues>
|
||||
<onlyCurrentVersion>false</onlyCurrentVersion>
|
||||
</configuration>
|
||||
-->
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>changes-report</report>
|
||||
<!-- TODO: Might be able to generate a report based off GH issues -->
|
||||
<!-- <report>github-report</report> -->
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>checkstyle</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jxr-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-pmd-plugin</artifactId>
|
||||
<configuration>
|
||||
<targetJdk>${maven.compiler.release}</targetJdk>
|
||||
<!-- TODO: Add a rule set -->
|
||||
<!--
|
||||
<rulesets>
|
||||
<ruleset>pmd-ruleset.xml</ruleset>
|
||||
</rulesets>
|
||||
-->
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.rat</groupId>
|
||||
<artifactId>apache-rat-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>versions-maven-plugin</artifactId>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>dependency-updates-report</report>
|
||||
<report>plugin-updates-report</report>
|
||||
<report>property-updates-report</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>${maven.jacoco-plugin.version}</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>central</id>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
<url>https://repo1.maven.org/maven2/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>compile-jdk8</id>
|
||||
<properties>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<compilingJdk8>true</compilingJdk8>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<!-- IF YOU CHANGE THIS FROM 17 GO UPDATE JDK_COMPILER_VERSION ON THE sk-java MAVEN DEPLOY -->
|
||||
<id>compile-jdk17</id>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>bug-check</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven.compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<source>${maven.compiler.release}</source>
|
||||
<target>${maven.compiler.release}</target>
|
||||
<!-- Ensure we compile against JDK 8 APIs -->
|
||||
<release>8</release>
|
||||
<encoding>${project.build.sourceEncoding}</encoding>
|
||||
<showWarnings>true</showWarnings>
|
||||
<compilerArgs>
|
||||
<arg>-XDcompilePolicy=simple</arg>
|
||||
|
||||
<!-- TODO: Remove exclusions when more project is stable -->
|
||||
<arg>-Xplugin:ErrorProne
|
||||
-XepOpt:NullAway:AnnotatedPackages=com.microsoft.semantickernel
|
||||
-Xep:AlmostJavadoc:OFF -Xep:MissingSummary:OFF
|
||||
-Xep:UnusedVariable:OFF -Xep:EmptyBlockTag:OFF
|
||||
-XepExcludedPaths:.*/src/test/java/.*
|
||||
</arg>
|
||||
</compilerArgs>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>com.google.errorprone</groupId>
|
||||
<artifactId>error_prone_core</artifactId>
|
||||
<version>${google.errorprone.core.version}</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>com.uber.nullaway</groupId>
|
||||
<artifactId>nullaway</artifactId>
|
||||
<version>${com.uber.nullaway.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.diffplug.spotless</groupId>
|
||||
<artifactId>spotless-maven-plugin</artifactId>
|
||||
<version>${maven.spotless-plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>check</id>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
<phase>compile</phase>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>apply</id>
|
||||
<goals>
|
||||
<goal>apply</goal>
|
||||
</goals>
|
||||
<phase>process-sources</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<skip>${compilingJdk8}</skip>
|
||||
<java>
|
||||
<eclipse>
|
||||
<version>4.30</version>
|
||||
<file>eclipse-formatter.xml</file>
|
||||
</eclipse>
|
||||
<!--
|
||||
<googleJavaFormat>
|
||||
<version>${google.java.format.version}</version>
|
||||
<style>AOSP</style>
|
||||
<reflowLongStrings>true</reflowLongStrings>
|
||||
</googleJavaFormat>
|
||||
-->
|
||||
<licenseHeader>
|
||||
<content>// Copyright (c) Microsoft. All rights reserved.</content>
|
||||
</licenseHeader>
|
||||
<toggleOffOn />
|
||||
</java>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.github.spotbugs</groupId>
|
||||
<artifactId>spotbugs-maven-plugin</artifactId>
|
||||
<version>${maven.spotbugs-plugin.version}</version>
|
||||
<configuration>
|
||||
<effort>Max</effort>
|
||||
<!-- Lower when more project is stable -->
|
||||
<threshold>Normal</threshold>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>spotbugs</goal>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- Check compatibility with Android API -->
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>animal-sniffer-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>with-samples</id>
|
||||
<modules>
|
||||
<module>samples</module>
|
||||
<module>api-test</module>
|
||||
</modules>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>release</id>
|
||||
<properties>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<configuration>
|
||||
<javadoc>true</javadoc>
|
||||
<sources>true</sources>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-release-plugin</artifactId>
|
||||
<configuration>
|
||||
<tagNameFormat>java-@{project.version}</tagNameFormat>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>${releaseRepoId}</id>
|
||||
<url>${releaseRepoUrl}</url>
|
||||
<name>${releaseRepoName}</name>
|
||||
</repository>
|
||||
</repositories>
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>${releaseRepoId}</id>
|
||||
<url>${releaseRepoUrl}</url>
|
||||
<name>${releaseRepoName}</name>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<id>microsoft</id>
|
||||
<name>Microsoft</name>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>MIT License</name>
|
||||
<url>https://opensource.org/licenses/MIT</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<scm>
|
||||
<url>https://github.com/microsoft/semantic-kernel</url>
|
||||
<connection>scm:git:https://github.com/microsoft/semantic-kernel.git</connection>
|
||||
<developerConnection>scm:git:https://github.com/microsoft/semantic-kernel.git</developerConnection>
|
||||
<tag>HEAD</tag>
|
||||
</scm>
|
||||
</project>
|
||||
@@ -1,8 +0,0 @@
|
||||
## Kernel Samples
|
||||
|
||||
| Type | Description |
|
||||
|-----------------------------------------------------------------|----------------------------------------------------------------------------------------------------------|
|
||||
| [semantickernel-demos](semantickernel-demos) | Look here to find a sample which demonstrate how to use many of Semantic Kernel features. |
|
||||
| [semantickernel-learn-resources](semantickernel-learn-resources) | Code snippets that are related to online documentation sources like Microsoft Learn, DevBlogs and others |
|
||||
| [semantickernel-concepts](semantickernel-concepts) | This section contains samples which illustrate how to use Semantic Kernel concepts. |
|
||||
| [semantickernel-sample-plugins](semantickernel-sample-plugins) | This section contains samples which illustrate how to create Semantic Kernel plugins. |
|
||||
@@ -1,6 +0,0 @@
|
||||
client.openai.key=OPEN_AI_KEY
|
||||
client.openai.organizationid=OPEN_AI_ORGANIZATION_ID
|
||||
|
||||
client.azureopenai.key=AZURE_OPEN_AI_KEY
|
||||
client.azureopenai.endpoint=AZURE_OPEN_AI_ENDPOINT
|
||||
client.azureopenai.deploymentname=AZURE_OPEN_AI_DEPLOYMENT_NAME
|
||||
@@ -1,155 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-parent</artifactId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>semantickernel-samples-parent</artifactId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Semantic Kernel Samples Parent</name>
|
||||
<description>Parent pom for sample code for using the Semantic Kernel project</description>
|
||||
|
||||
<modules>
|
||||
<module>semantickernel-concepts</module>
|
||||
<module>semantickernel-demos</module>
|
||||
<module>semantickernel-learn-resources</module>
|
||||
<module>semantickernel-sample-plugins</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<com.uber.nullaway.version>0.10.21</com.uber.nullaway.version>
|
||||
<google.errorprone.core.version>2.19.1</google.errorprone.core.version>
|
||||
<log4j2.version>2.20.0</log4j2.version>
|
||||
<maven.compiler-plugin.version>3.11.0</maven.compiler-plugin.version>
|
||||
<maven.compiler.release>17</maven.compiler.release>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-bom</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>import</scope>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven.compiler-plugin.version}</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${maven.compiler.release}</source>
|
||||
<target>${maven.compiler.release}</target>
|
||||
<release>${maven.compiler.release}</release>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>enforce-maven</id>
|
||||
<goals>
|
||||
<goal>enforce</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<requireMavenVersion>
|
||||
<version>3.9.3</version>
|
||||
</requireMavenVersion>
|
||||
</rules>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>animal-sniffer-maven-plugin</artifactId>
|
||||
<version>1.23</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>android</id>
|
||||
<phase>test</phase>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>bug-check</id>
|
||||
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
</activation>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven.compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<source>${maven.compiler.release}</source>
|
||||
<target>${maven.compiler.release}</target>
|
||||
<encoding>${project.build.sourceEncoding}</encoding>
|
||||
<showWarnings>true</showWarnings>
|
||||
<compilerArgs>
|
||||
<arg />
|
||||
<compilerArg />
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<!-- Ignore linting on samples -->
|
||||
<plugin>
|
||||
<groupId>com.github.spotbugs</groupId>
|
||||
<artifactId>spotbugs-maven-plugin</artifactId>
|
||||
<version>${maven.spotbugs-plugin.version}</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-samples-parent</artifactId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>semantickernel-concepts</artifactId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>semantickernel-concepts</name>
|
||||
|
||||
<modules>
|
||||
<module>semantickernel-syntax-examples</module>
|
||||
</modules>
|
||||
</project>
|
||||
@@ -1,140 +0,0 @@
|
||||
# Java Samples
|
||||
|
||||
## TL;DR
|
||||
|
||||
Run with:
|
||||
|
||||
```shell
|
||||
# AZURE:
|
||||
OPENAI_CLIENT_TYPE=AZURE_OPEN_AI \
|
||||
AZURE_OPEN_AI_KEY="my-key" \
|
||||
AZURE_OPEN_AI_ENDPOINT="endpoint url" \
|
||||
../../mvnw clean package exec:java -Dsample=Example04_CombineLLMPromptsAndNativeCode
|
||||
|
||||
# OPENAI:
|
||||
OPENAI_CLIENT_TYPE=OPENAI \
|
||||
OPEN_AI_KEY="my-key" \
|
||||
OPEN_AI_ORGANIZATION_ID="organisation id" \
|
||||
../../mvnw clean package exec:java -Dsample=Example04_CombineLLMPromptsAndNativeCode
|
||||
```
|
||||
|
||||
# Compile
|
||||
|
||||
These samples can be compiled via:
|
||||
|
||||
```shell
|
||||
../../mvnw clean package
|
||||
```
|
||||
|
||||
They can then be run by:
|
||||
|
||||
```shell
|
||||
../../mvnw exec:java -Dsample=Example04_CombineLLMPromptsAndNativeCode
|
||||
```
|
||||
|
||||
# Configuration
|
||||
|
||||
By default, the samples will use the Open AI client, but you can also use the Azure Open AI client.
|
||||
|
||||
## Open AI client type
|
||||
|
||||
You can define the provider of Open AI (openai.com or Azure), this can be done by setting the `OPENAI_CLIENT_TYPE`
|
||||
property or environment variable to either [`OPENAI`](https://platform.openai.com/)
|
||||
or [`AZURE_OPEN_AI`](https://learn.microsoft.com/azure/cognitive-services/openai/). By default, the samples will use the
|
||||
Open AI client.
|
||||
|
||||
```shell
|
||||
OPENAI_CLIENT_TYPE=OPEN_AI ../../mvnw exec:java -Dsample=Example04_CombineLLMPromptsAndNativeCode
|
||||
|
||||
OR
|
||||
|
||||
../../mvnw exec:java -DOPENAI_CLIENT_TYPE=AZURE_OPEN_AI -Dsample=Example04_CombineLLMPromptsAndNativeCode
|
||||
```
|
||||
|
||||
## Client Settings
|
||||
The samples search for the client settings in the following order:
|
||||
1. Properties file whose location is defined by the `CONF_PROPERTIES` property or environment variable.
|
||||
1. System properties defined on the command line.
|
||||
1. Environment variables.
|
||||
1. Properties file at `java/samples/conf.properties`.
|
||||
1. Properties file at `~/.sk/conf.properties`.
|
||||
|
||||
## Properties File
|
||||
|
||||
You can set the location of a properties file, by setting the `CONF_PROPERTIES` property or environment variable, ie:
|
||||
|
||||
```shell
|
||||
CONF_PROPERTIES=my.properties \
|
||||
OPENAI_CLIENT_TYPE=OPEN_AI \
|
||||
../../mvnw exec:java -Dsample=Example04_CombineLLMPromptsAndNativeCode
|
||||
|
||||
OR
|
||||
|
||||
../../mvnw exec:java \
|
||||
-DCONF_PROPERTIES=my.properties \
|
||||
-DOPENAI_CLIENT_TYPE=AZURE_OPEN_AI \
|
||||
-Dsample=Example04_CombineLLMPromptsAndNativeCode
|
||||
```
|
||||
|
||||
A properties file looks as follows:
|
||||
|
||||
```properties
|
||||
# If using openai.com
|
||||
client.openai.key:"my-key"
|
||||
client.openai.organizationid:"my-org-id"
|
||||
# if using Azure Open AI
|
||||
client.azureopenai.key:"my-key"
|
||||
client.azureopenai.endpoint:"url of azure openai endpoint"
|
||||
client.azureopenai.deploymentname:"deployment name"
|
||||
```
|
||||
|
||||
## System Properties
|
||||
|
||||
As an alternative to providing the key/endpoint properties via a file, you can set them directly via system properties,
|
||||
ie:
|
||||
|
||||
```shell
|
||||
# OpenAI
|
||||
../../mvnw exec:java \
|
||||
-DOPENAI_CLIENT_TYPE=AZURE_OPEN_AI \
|
||||
-Dclient.openai.key="my-key" \
|
||||
-Dclient.openai.organizationid="my-org-id" \
|
||||
-Dsample=Example04_CombineLLMPromptsAndNativeCode
|
||||
|
||||
# Azure
|
||||
../../mvnw exec:java \
|
||||
-DOPENAI_CLIENT_TYPE=AZURE_OPEN_AI \
|
||||
-Dclient.azureopenai.key="my-key" \
|
||||
-Dclient.azureopenai.endpoint="url of azure openai endpoint" \
|
||||
-Dsample=Example04_CombineLLMPromptsAndNativeCode
|
||||
```
|
||||
|
||||
## Environment variables
|
||||
|
||||
Alternative to properties, you can set environment variables as follows:
|
||||
|
||||
```shell
|
||||
# AZURE:
|
||||
OPENAI_CLIENT_TYPE=AZURE_OPEN_AI \
|
||||
AZURE_OPEN_AI_KEY="my-key" \
|
||||
AZURE_OPEN_AI_ENDPOINT="endpoint url" \
|
||||
../../mvnw clean package exec:java -Dsample=Example04_CombineLLMPromptsAndNativeCode
|
||||
|
||||
# OPENAI:
|
||||
OPENAI_CLIENT_TYPE=OPEN_AI \
|
||||
OPEN_AI_KEY="my-key" \
|
||||
OPEN_AI_ORGANIZATION_ID="organisation id" \
|
||||
../../mvnw clean package exec:java -Dsample=Example04_CombineLLMPromptsAndNativeCode
|
||||
```
|
||||
|
||||
## Managed Identity and Azure CLI Credentials (Azure only)
|
||||
|
||||
The `credentialtype` setting (i.e `client.openai.credentialtype`):
|
||||
|
||||
- `managed_identity`: will attempt to obtain credentials via Azure's managed identity.
|
||||
- `azure_cli`: will attempt to obtain credentials via Azure's CLI, to use this you must have logged in to the az client
|
||||
for instance by running `az login`.
|
||||
|
||||
To use either of these settings, the `azure-identity` dependency must be available to the application. Additionally, you
|
||||
must have the "Cognitive Services User" role assigned to your identity.
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-concepts</artifactId>
|
||||
<version>1.1.5-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>semantickernel-syntax-examples</artifactId>
|
||||
<name>Semantic Kernel Samples</name>
|
||||
<description>Sample code for using the Semantic Kernel project</description>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-bom</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j2-impl</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.azure</groupId>
|
||||
<artifactId>azure-identity</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantic-kernel</groupId>
|
||||
<artifactId>semantickernel-aiservices-openai</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>bug-check</id>
|
||||
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
</activation>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- Ignore linting on samples -->
|
||||
<plugin>
|
||||
<groupId>com.github.spotbugs</groupId>
|
||||
<artifactId>spotbugs-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>17</source>
|
||||
<target>17</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>run-sample</id>
|
||||
<goals>
|
||||
<goal>java</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<mainClass>com.microsoft.semantickernel.samples.syntaxexamples.${sample}</mainClass>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
-163
@@ -1,163 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.connectors.web.bing;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.azure.core.http.HttpClient;
|
||||
import com.azure.core.http.HttpHeaderName;
|
||||
import com.azure.core.http.HttpMethod;
|
||||
import com.azure.core.http.HttpRequest;
|
||||
import com.azure.core.http.HttpResponse;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.microsoft.semantickernel.connectors.WebSearchEngineConnector;
|
||||
import com.microsoft.semantickernel.exceptions.SKException;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public class BingConnector implements WebSearchEngineConnector {
|
||||
|
||||
private static String BING_SEARCH_URL;
|
||||
static {
|
||||
String bingSearchUrl = System.getProperty("bing.search.url");
|
||||
if (bingSearchUrl == null || bingSearchUrl.isEmpty())
|
||||
bingSearchUrl = System.getenv("BING_SEARCH_URL");
|
||||
if (bingSearchUrl == null || bingSearchUrl.isEmpty())
|
||||
bingSearchUrl = "https://api.bing.microsoft.com/v7.0/search";
|
||||
BING_SEARCH_URL = bingSearchUrl;
|
||||
}
|
||||
|
||||
private static final String OCP_APIM_SUBSCRIPTION_KEY = "Ocp-Apim-Subscription-Key";
|
||||
private static final HttpHeaderName OCP_APIM_SUBSCRIPTION_KEY_HEADER = HttpHeaderName
|
||||
.fromString(OCP_APIM_SUBSCRIPTION_KEY);
|
||||
|
||||
private static class BingSearchResponse {
|
||||
private final WebPages webPages;
|
||||
|
||||
@JsonCreator
|
||||
public BingSearchResponse(
|
||||
@JsonProperty("webPages") WebPages webPages) {
|
||||
this.webPages = webPages;
|
||||
}
|
||||
|
||||
public WebPages getWebPages() {
|
||||
return webPages;
|
||||
}
|
||||
}
|
||||
|
||||
private static class WebPages {
|
||||
private final WebPage[] value;
|
||||
|
||||
@JsonCreator
|
||||
public WebPages(
|
||||
@JsonProperty("value") BingWebPage[] value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public WebPage[] getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public static class BingWebPage implements WebPage {
|
||||
private final String name;
|
||||
private final String url;
|
||||
private final String snippet;
|
||||
|
||||
@JsonCreator
|
||||
public BingWebPage(
|
||||
@JsonProperty("name") String name,
|
||||
@JsonProperty("url") String url,
|
||||
@JsonProperty("snippet") String snippet) {
|
||||
this.name = name;
|
||||
this.url = url;
|
||||
this.snippet = snippet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSnippet() {
|
||||
return snippet;
|
||||
}
|
||||
}
|
||||
|
||||
private final String apiKey; // TODO: secure this
|
||||
private final HttpClient httpClient;
|
||||
|
||||
public BingConnector(String apiKey, HttpClient httpClient) {
|
||||
this.apiKey = apiKey;
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
public BingConnector(String apiKey) {
|
||||
this(apiKey, HttpClient.createDefault());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<List<WebPage>> searchAsync(String query, int count, int offset) {
|
||||
|
||||
if (count <= 0 || 50 <= count)
|
||||
throw new IllegalArgumentException("count must be between 1 and 50");
|
||||
if (offset < 0)
|
||||
throw new IllegalArgumentException("offset must be greater than or equal to 0");
|
||||
|
||||
HttpRequest request = new HttpRequest(HttpMethod.GET, searchUrl(query, count, offset));
|
||||
request.setHeader(OCP_APIM_SUBSCRIPTION_KEY_HEADER, apiKey);
|
||||
|
||||
return httpClient.send(request).flatMap(BingConnector::handleResponse);
|
||||
|
||||
}
|
||||
|
||||
private static String searchUrl(String query, int count, int offset) {
|
||||
|
||||
try {
|
||||
query = URLEncoder.encode(query, StandardCharsets.UTF_8.toString());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// ignored - UTF-8 is always supported
|
||||
}
|
||||
|
||||
String url = String.format("%s?q=%s&count=%s&offset=%s",
|
||||
BING_SEARCH_URL, query, Integer.toString(count), Integer.toString(offset));
|
||||
return url;
|
||||
}
|
||||
|
||||
private static Mono<List<WebPage>> handleResponse(HttpResponse response) {
|
||||
return response.getBodyAsString()
|
||||
.map(body -> {
|
||||
if (body == null || body.isEmpty())
|
||||
return null;
|
||||
try {
|
||||
ObjectMapper objectMapper = new ObjectMapper()
|
||||
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
|
||||
.configure(DeserializationFeature.FAIL_ON_MISSING_CREATOR_PROPERTIES,
|
||||
false);
|
||||
|
||||
BingSearchResponse bingSearchResponse = objectMapper.readValue(body,
|
||||
BingSearchResponse.class);
|
||||
if (bingSearchResponse.getWebPages() != null
|
||||
&& bingSearchResponse.getWebPages().getValue() != null) {
|
||||
return Arrays.asList(bingSearchResponse.getWebPages().getValue());
|
||||
}
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new SKException(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
-121
@@ -1,121 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.plugins;
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.contextvariables.ContextVariableTypes;
|
||||
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter;
|
||||
import com.microsoft.semantickernel.text.TextChunker;
|
||||
import java.util.List;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/// <summary>
|
||||
/// Semantic plugin that enables conversations summarization.
|
||||
/// </summary>
|
||||
public class ConversationSummaryPlugin {
|
||||
|
||||
/// <summary>
|
||||
/// The max tokens to process in a single prompt function call.
|
||||
/// </summary>
|
||||
private static final int MaxTokens = 1024;
|
||||
|
||||
private KernelFunction<String> summarizeConversationFunction;
|
||||
private KernelFunction<String> conversationActionItemsFunction;
|
||||
private KernelFunction<String> conversationTopicsFunction;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConversationSummaryPlugin"/> class.
|
||||
/// </summary>
|
||||
public ConversationSummaryPlugin() {
|
||||
PromptExecutionSettings settings = PromptExecutionSettings.builder()
|
||||
.withMaxTokens(MaxTokens)
|
||||
.withTemperature(0.1)
|
||||
.withTopP(0.5)
|
||||
.build();
|
||||
|
||||
this.summarizeConversationFunction = KernelFunction
|
||||
.<String>createFromPrompt(PromptFunctionConstants.SummarizeConversationDefinition)
|
||||
.withDefaultExecutionSettings(settings)
|
||||
.withName("summarizeConversation")
|
||||
.withDescription(
|
||||
"Given a section of a conversation transcript, summarize the part of the conversation.")
|
||||
.build();
|
||||
|
||||
this.conversationActionItemsFunction = KernelFunction
|
||||
.<String>createFromPrompt(PromptFunctionConstants.GetConversationActionItemsDefinition)
|
||||
.withDefaultExecutionSettings(settings)
|
||||
.withName("conversationActionItems")
|
||||
.withDescription("Given a section of a conversation transcript, identify action items.")
|
||||
.build();
|
||||
|
||||
this.conversationTopicsFunction = KernelFunction
|
||||
.<String>createFromPrompt(PromptFunctionConstants.GetConversationTopicsDefinition)
|
||||
.withDefaultExecutionSettings(settings)
|
||||
.withName("conversationTopics")
|
||||
.withDescription(
|
||||
"Analyze a conversation transcript and extract key topics worth remembering.")
|
||||
.build();
|
||||
}
|
||||
|
||||
private static Mono<String> processAsync(KernelFunction<String> func, String input,
|
||||
Kernel kernel) {
|
||||
List<String> lines = TextChunker.splitPlainTextLines(input, MaxTokens);
|
||||
List<String> paragraphs = TextChunker.splitPlainTextParagraphs(lines, MaxTokens);
|
||||
|
||||
return Flux.fromIterable(paragraphs)
|
||||
.concatMap(paragraph -> {
|
||||
// The first parameter is the input text.
|
||||
return func.invokeAsync(kernel)
|
||||
.withArguments(
|
||||
new KernelFunctionArguments.Builder()
|
||||
.withInput(paragraph)
|
||||
.build())
|
||||
.withResultType(
|
||||
ContextVariableTypes.getGlobalVariableTypeForClass(String.class));
|
||||
})
|
||||
.reduce("", (acc, next) -> {
|
||||
return acc + "\n" + next.getResult();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a long conversation transcript, summarize the conversation.
|
||||
/// </summary>
|
||||
/// <param name="input">A long conversation transcript.</param>
|
||||
/// <param name="kernel">The <see cref="Kernel"/> containing services, plugins, and other state for use throughout the operation.</param>
|
||||
@DefineKernelFunction(description = "Given a long conversation transcript, summarize the conversation.", name = "SummarizeConversation", returnType = "java.lang.String")
|
||||
public Mono<String> SummarizeConversationAsync(
|
||||
@KernelFunctionParameter(description = "A long conversation transcript.", name = "input") String input,
|
||||
Kernel kernel) {
|
||||
return processAsync(this.summarizeConversationFunction, input, kernel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a long conversation transcript, identify action items.
|
||||
/// </summary>
|
||||
/// <param name="input">A long conversation transcript.</param>
|
||||
/// <param name="kernel">The <see cref="Kernel"/> containing services, plugins, and other state for use throughout the operation.</param>
|
||||
@DefineKernelFunction(description = "Given a long conversation transcript, identify action items.", name = "GetConversationActionItems", returnType = "java.lang.String")
|
||||
public Mono<String> GetConversationActionItemsAsync(
|
||||
@KernelFunctionParameter(description = "A long conversation transcript.", name = "input") String input,
|
||||
Kernel kernel) {
|
||||
return processAsync(this.conversationActionItemsFunction, input, kernel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a long conversation transcript, identify topics.
|
||||
/// </summary>
|
||||
/// <param name="input">A long conversation transcript.</param>
|
||||
/// <param name="kernel">The <see cref="Kernel"/> containing services, plugins, and other state for use throughout the operation.</param>
|
||||
@DefineKernelFunction(description = "Given a long conversation transcript, identify topics worth remembering.", name = "GetConversationTopics", returnType = "java.lang.String")
|
||||
|
||||
public Mono<String> GetConversationTopicsAsync(
|
||||
@KernelFunctionParameter(description = "A long conversation transcript.", name = "input") String input,
|
||||
Kernel kernel) {
|
||||
return processAsync(this.conversationTopicsFunction, input, kernel);
|
||||
}
|
||||
}
|
||||
-121
@@ -1,121 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.plugins;
|
||||
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter;
|
||||
|
||||
// <KernelPlugin>
|
||||
public class MathPlugin {
|
||||
// </KernelPlugin>
|
||||
|
||||
// <KernelFunction>
|
||||
@DefineKernelFunction(name = "sqrt", description = "Take the square root of a number")
|
||||
public static double sqrt(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take a square root of", type = double.class) double number1) {
|
||||
return Math.sqrt(number1);
|
||||
}
|
||||
// </KernelFunction>
|
||||
|
||||
@DefineKernelFunction(name = "add", description = "Add two numbers")
|
||||
public static double add(
|
||||
@KernelFunctionParameter(name = "number1", description = "The first number to add", type = double.class) double number1,
|
||||
@KernelFunctionParameter(name = "number2", description = "The second number to add", type = double.class) double number2) {
|
||||
return number1 + number2;
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "subtract", description = "Subtract two numbers")
|
||||
public static double subtract(
|
||||
@KernelFunctionParameter(name = "number1", description = "The first number to subtract from", type = double.class) double number1,
|
||||
@KernelFunctionParameter(name = "number2", description = "The second number to subtract away", type = double.class) double number2) {
|
||||
return number1 - number2;
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "multiply", description = "Multiply two numbers. When increasing by a percentage, don't forget to add 1 to the percentage.")
|
||||
public static double multiply(
|
||||
@KernelFunctionParameter(name = "number1", description = "The first number to multiply", type = double.class) double number1,
|
||||
@KernelFunctionParameter(name = "number2", description = "The second number to multiply", type = double.class) double number2) {
|
||||
return number1 * number2;
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "divide", description = "Divide two numbers")
|
||||
public static double divide(
|
||||
@KernelFunctionParameter(name = "number1", description = "The first number to divide from", type = double.class) double number1,
|
||||
@KernelFunctionParameter(name = "number2", description = "The second number to divide by", type = double.class) double number2) {
|
||||
return number1 / number2;
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "power", description = "Raise a number to a power")
|
||||
public static double power(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to raise", type = double.class) double number1,
|
||||
@KernelFunctionParameter(name = "number2", description = "The power to raise the number to", type = double.class) double number2) {
|
||||
return Math.pow(number1, number2);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "log", description = "Take the log of a number")
|
||||
public static double log(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the log of", type = double.class) double number1,
|
||||
@KernelFunctionParameter(name = "number2", description = "The base of the log", type = double.class) double number2) {
|
||||
return Math.log(number1) / Math.log(number2);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "round", description = "Round a number to the target number of decimal places")
|
||||
public static double round(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to round", type = double.class) double number1,
|
||||
@KernelFunctionParameter(name = "number2", description = "The number of decimal places to round to", type = double.class) int number2) {
|
||||
return Math.round(number1 * Math.pow(10, number2)) / Math.pow(10, number2);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "abs", description = "Take the absolute value of a number")
|
||||
public static double abs(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the absolute value of", type = double.class) double number1) {
|
||||
return Math.abs(number1);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "floor", description = "Take the floor of a number")
|
||||
public static double floor(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the floor of", type = double.class) double number1) {
|
||||
return Math.floor(number1);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "ceiling", description = "Take the ceiling of a number")
|
||||
public static double ceiling(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the ceiling of", type = double.class) double number1) {
|
||||
return Math.ceil(number1);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "sin", description = "Take the sine of a number")
|
||||
public static double sin(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the sine of", type = double.class) double number1) {
|
||||
return Math.sin(number1);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "cos", description = "Take the cosine of a number")
|
||||
public static double cos(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the cosine of", type = double.class) double number1) {
|
||||
return Math.cos(number1);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "tan", description = "Take the tangent of a number")
|
||||
public static double tan(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the tangent of", type = double.class) double number1) {
|
||||
return Math.tan(number1);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "asin", description = "Take the arcsine of a number")
|
||||
public static double asin(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the arcsine of", type = double.class) double number1) {
|
||||
return Math.asin(number1);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "acos", description = "Take the arccosine of a number")
|
||||
public static double acos(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the arccosine of", type = double.class) double number1) {
|
||||
return Math.acos(number1);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "atan", description = "Take the arctangent of a number")
|
||||
public static double atan(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the arctangent of", type = double.class) double number1) {
|
||||
return Math.atan(number1);
|
||||
}
|
||||
}
|
||||
-95
@@ -1,95 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.plugins;
|
||||
|
||||
public class PromptFunctionConstants {
|
||||
|
||||
public static final String SummarizeConversationDefinition = """
|
||||
BEGIN CONTENT TO SUMMARIZE:
|
||||
{{$INPUT}}
|
||||
|
||||
END CONTENT TO SUMMARIZE.
|
||||
|
||||
Summarize the conversation in 'CONTENT TO SUMMARIZE', identifying main points of discussion and any conclusions that were reached.
|
||||
Do not incorporate other general knowledge.
|
||||
Summary is in plain text, in complete sentences, with no markup or tags.
|
||||
|
||||
BEGIN SUMMARY:
|
||||
"""
|
||||
.stripIndent();
|
||||
|
||||
public static final String GetConversationActionItemsDefinition = """
|
||||
You are an action item extractor. You will be given chat history and need to make note of action items mentioned in the chat.
|
||||
Extract action items from the content if there are any. If there are no action, return nothing. If a single field is missing, use an empty string.
|
||||
Return the action items in json.
|
||||
|
||||
Possible statuses for action items are: Open, Closed, In Progress.
|
||||
|
||||
EXAMPLE INPUT WITH ACTION ITEMS:
|
||||
|
||||
John Doe said: "I will record a demo for the new feature by Friday"
|
||||
I said: "Great, thanks John. We may not use all of it but it's good to get it out there."
|
||||
|
||||
EXAMPLE OUTPUT:
|
||||
{
|
||||
"actionItems": [
|
||||
{
|
||||
"owner": "John Doe",
|
||||
"actionItem": "Record a demo for the new feature",
|
||||
"dueDate": "Friday",
|
||||
"status": "Open",
|
||||
"notes": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
EXAMPLE INPUT WITHOUT ACTION ITEMS:
|
||||
|
||||
John Doe said: "Hey I'm going to the store, do you need anything?"
|
||||
I said: "No thanks, I'm good."
|
||||
|
||||
EXAMPLE OUTPUT:
|
||||
{
|
||||
"action_items": []
|
||||
}
|
||||
|
||||
CONTENT STARTS HERE.
|
||||
|
||||
{{$INPUT}}
|
||||
|
||||
CONTENT STOPS HERE.
|
||||
|
||||
OUTPUT:
|
||||
"""
|
||||
.stripIndent();
|
||||
|
||||
public static final String GetConversationTopicsDefinition = """
|
||||
Analyze the following extract taken from a conversation transcript and extract key topics.
|
||||
- Topics only worth remembering.
|
||||
- Be brief. Short phrases.
|
||||
- Can use broken English.
|
||||
- Conciseness is very important.
|
||||
- Topics can include names of memories you want to recall.
|
||||
- NO LONG SENTENCES. SHORT PHRASES.
|
||||
- Return in JSON
|
||||
[Input]
|
||||
My name is Macbeth. I used to be King of Scotland, but I died. My wife's name is Lady Macbeth and we were married for 15 years. We had no children. Our beloved dog Toby McDuff was a famous hunter of rats in the forest.
|
||||
My tragic story was immortalized by Shakespeare in a play.
|
||||
[Output]
|
||||
{
|
||||
"topics": [
|
||||
"Macbeth",
|
||||
"King of Scotland",
|
||||
"Lady Macbeth",
|
||||
"Dog",
|
||||
"Toby McDuff",
|
||||
"Shakespeare",
|
||||
"Play",
|
||||
"Tragedy"
|
||||
]
|
||||
}
|
||||
+++++
|
||||
[Input]
|
||||
{{$INPUT}}
|
||||
[Output]"""
|
||||
.stripIndent();
|
||||
}
|
||||
-303
@@ -1,303 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.plugins;
|
||||
|
||||
import com.microsoft.semantickernel.samples.util.LocaleParser;
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.TextStyle;
|
||||
import java.util.Locale;
|
||||
|
||||
public class TimePlugin {
|
||||
|
||||
public static final String DAY_MONTH_DAY_YEAR = "EEEE, MMMM d, yyyy";
|
||||
|
||||
/**
|
||||
* Get the current date and time for the system default timezone.
|
||||
*
|
||||
* @return a ZonedDateTime object with the current date and time.
|
||||
*/
|
||||
public ZonedDateTime now() {
|
||||
return ZonedDateTime.now(ZoneId.systemDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current date.
|
||||
*
|
||||
* <p>Example: {{time.date}} => Sunday, January 12, 2025
|
||||
*
|
||||
* @return The current date.
|
||||
*/
|
||||
@DefineKernelFunction(name = "date", description = "Get the current date")
|
||||
public String date(
|
||||
@KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) {
|
||||
// Example: Sunday, 12 January, 2025
|
||||
return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR)
|
||||
.withLocale(parseLocale(locale))
|
||||
.format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current time.
|
||||
*
|
||||
* <p>Example: {{time.time}} => 9:15:00 AM
|
||||
*
|
||||
* @return The current time.
|
||||
*/
|
||||
@DefineKernelFunction(name = "time", description = "Get the current time")
|
||||
public String time(
|
||||
@KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) {
|
||||
// Example: 09:15:07 PM
|
||||
return DateTimeFormatter.ofPattern("hh:mm:ss a")
|
||||
.withLocale(parseLocale(locale))
|
||||
.format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current UTC date and time.
|
||||
*
|
||||
* <p>Example: {{time.utcNow}} => Sunday, January 13, 2025 5:15 AM
|
||||
*
|
||||
* @return The current UTC date and time.
|
||||
*/
|
||||
@DefineKernelFunction(name = "utcNow", description = "Get the current UTC date and time")
|
||||
public String utcNow(
|
||||
@KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) {
|
||||
return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR + " h:mm a")
|
||||
.withLocale(parseLocale(locale))
|
||||
.format(now().withZoneSameInstant(ZoneOffset.UTC));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current date (alias for date() method).
|
||||
*
|
||||
* <p>Example: {{time.today}} => Sunday, January 12, 2025
|
||||
*
|
||||
* @return The current date.
|
||||
*/
|
||||
@DefineKernelFunction(name = "today", description = "Get the current date")
|
||||
public String today(
|
||||
@KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) {
|
||||
return date(locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current date and time in the local time zone.
|
||||
*
|
||||
* <p>Example: {{time.now}} => Sunday, January 12, 2025 9:15 AM
|
||||
*
|
||||
* @return The current date and time in the local time zone.
|
||||
*/
|
||||
@DefineKernelFunction(name = "now", description = "Get the current date and time in the local time zone")
|
||||
public String now(
|
||||
@KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) {
|
||||
return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR + " h:mm a")
|
||||
.withLocale(parseLocale(locale))
|
||||
.format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current year.
|
||||
*
|
||||
* <p>Example: {{time.year}} => 2025
|
||||
*
|
||||
* @return The current year.
|
||||
*/
|
||||
@DefineKernelFunction(name = "year", description = "Get the current year")
|
||||
public String year(
|
||||
@KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) {
|
||||
return DateTimeFormatter.ofPattern("yyyy").withLocale(parseLocale(locale)).format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current month name.
|
||||
*
|
||||
* <p>Example: {{time.month}} => January
|
||||
*
|
||||
* @return The current month name.
|
||||
*/
|
||||
@DefineKernelFunction(name = "month", description = "Get the current month name")
|
||||
public String month(
|
||||
@KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) {
|
||||
return DateTimeFormatter.ofPattern("MMMM").withLocale(parseLocale(locale)).format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current month number.
|
||||
*
|
||||
* <p>Example: {{time.monthNumber}} => 01
|
||||
*
|
||||
* @return The current month number.
|
||||
*/
|
||||
@DefineKernelFunction(name = "monthNumber", description = "Get the current month number")
|
||||
public String monthNumber(
|
||||
@KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) {
|
||||
return DateTimeFormatter.ofPattern("MM").withLocale(parseLocale(locale)).format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current day of the month.
|
||||
*
|
||||
* <p>Example: {{time.day}} => 12
|
||||
*
|
||||
* @return The current day of the month.
|
||||
*/
|
||||
@DefineKernelFunction(name = "day", description = "Get the current day of the month")
|
||||
public String day(
|
||||
@KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) {
|
||||
return DateTimeFormatter.ofPattern("d").withLocale(parseLocale(locale)).format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current day of the week.
|
||||
*
|
||||
* <p>Example: {{time.dayOfWeek}} => Sunday
|
||||
*
|
||||
* @return The current day of the week.
|
||||
*/
|
||||
@DefineKernelFunction(name = "dayOfWeek", description = "Get the current day of the week")
|
||||
public String dayOfWeek(
|
||||
@KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) {
|
||||
return DateTimeFormatter.ofPattern("EEEE").withLocale(parseLocale(locale)).format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current clock hour.
|
||||
*
|
||||
* <p>Example: {{time.hour}} => 9 AM
|
||||
*
|
||||
* @return The current clock hour.
|
||||
*/
|
||||
@DefineKernelFunction(name = "hour", description = "Get the current clock hour")
|
||||
public String hour(
|
||||
@KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) {
|
||||
return DateTimeFormatter.ofPattern("h a").withLocale(parseLocale(locale)).format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current clock 24-hour number.
|
||||
*
|
||||
* <p>Example: {{time.hourNumber}} => 09
|
||||
*
|
||||
* @return The current clock 24-hour number.
|
||||
*/
|
||||
@DefineKernelFunction(name = "hourNumber", description = "Get the current clock 24-hour number")
|
||||
public String hourNumber(
|
||||
@KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) {
|
||||
return DateTimeFormatter.ofPattern("HH").withLocale(parseLocale(locale)).format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the date of offset from today by a provided number of days
|
||||
*
|
||||
* <p>Example: SKContext context = SKBuilders.context().build(); context.setVariable("input",
|
||||
* "3"); {{time.daysAgo $input}} => Saturday, January 11, 2031
|
||||
*
|
||||
* @param days Number of days to subtract from the current day
|
||||
* @return The date of offset from today by a provided number of days
|
||||
*/
|
||||
@DefineKernelFunction(name = "daysAgo", description = "Get the date of offset from today by a provided number of days")
|
||||
public String daysAgo(
|
||||
@KernelFunctionParameter(name = "days", description = "Number of days to offset from today.") String days,
|
||||
@KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) {
|
||||
int offsetDays = Integer.parseInt(days);
|
||||
return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR)
|
||||
.withLocale(parseLocale(locale))
|
||||
.format(now().minusDays(offsetDays));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the date of the last day matching the supplied week day name
|
||||
*
|
||||
* <p>Example: {{time.dateMatchingLastDayName "Monday"}} => Monday, January 6, 2031
|
||||
*
|
||||
* @param dayName Name of the day to match
|
||||
* @return The date of the last day matching the supplied week day name
|
||||
*/
|
||||
@DefineKernelFunction(name = "dateMatchingLastDayName", description = "Get the date of the last day matching the supplied week day name")
|
||||
public String dateMatchingLastDayName(
|
||||
@KernelFunctionParameter(name = "dayName", description = "Week name day.") String dayName,
|
||||
@KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) {
|
||||
ZonedDateTime currentDate = now();
|
||||
for (int i = 1; i <= 7; i++) {
|
||||
currentDate = currentDate.minusDays(1);
|
||||
String currentDayName = currentDate.getDayOfWeek().getDisplayName(TextStyle.FULL,
|
||||
parseLocale(locale));
|
||||
|
||||
if (currentDayName.equalsIgnoreCase(dayName)) {
|
||||
return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR)
|
||||
.withLocale(parseLocale(locale))
|
||||
.format(currentDate);
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("dayName is not recognized");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the minutes on the current hour.
|
||||
*
|
||||
* <p>Example: {{time.minute}} => 15
|
||||
*
|
||||
* @return The minutes on the current hour.
|
||||
*/
|
||||
@DefineKernelFunction(name = "minute", description = "Get the minutes on the current hour")
|
||||
public String minute(
|
||||
@KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) {
|
||||
return DateTimeFormatter.ofPattern("mm").withLocale(parseLocale(locale)).format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the seconds on the current minute.
|
||||
*
|
||||
* <p>Example: {{time.second}} => 00
|
||||
*
|
||||
* @return The seconds on the current minute.
|
||||
*/
|
||||
@DefineKernelFunction(name = "second", description = "Get the seconds on the current minute")
|
||||
public String second(
|
||||
@KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) {
|
||||
return DateTimeFormatter.ofPattern("ss").withLocale(parseLocale(locale)).format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the local time zone offset from UTC.
|
||||
*
|
||||
* <p>Example: {{time.timeZoneOffset}} => +03:00
|
||||
*
|
||||
* @return The local time zone offset from UTC.
|
||||
*/
|
||||
@DefineKernelFunction(name = "timeZoneOffset", description = "Get the local time zone offset from UTC")
|
||||
public String timeZoneOffset(
|
||||
@KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) {
|
||||
return DateTimeFormatter.ofPattern("XXX").withLocale(parseLocale(locale)).format(now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the local time zone name.
|
||||
*
|
||||
* <p>Example: {{time.timeZoneName}} => Pacific Time
|
||||
*
|
||||
* @return The local time zone name.
|
||||
*/
|
||||
@DefineKernelFunction(name = "timeZoneName", description = "Get the local time zone name")
|
||||
public String timeZoneName(
|
||||
@KernelFunctionParameter(name = "locale", description = "Locale to use when formatting the date", required = false) String locale) {
|
||||
ZoneId zoneId = ZoneId.systemDefault();
|
||||
return zoneId.getDisplayName(TextStyle.FULL, parseLocale(locale));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the locale string into a Locale object.
|
||||
*
|
||||
* <p>By default, it parses using the LocaleParser utility class.
|
||||
*
|
||||
* @param locale string
|
||||
* @return a locale object
|
||||
*/
|
||||
protected Locale parseLocale(String locale) {
|
||||
return LocaleParser.parseLocale(locale);
|
||||
}
|
||||
}
|
||||
-57
@@ -1,57 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.plugins.text;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter;
|
||||
|
||||
/**
|
||||
* TextPlugin provides a set of functions to manipulate strings.
|
||||
*/
|
||||
public class TextPlugin {
|
||||
|
||||
@DefineKernelFunction(description = "Change all string chars to uppercase.", name = "Uppercase")
|
||||
public String uppercase(
|
||||
@KernelFunctionParameter(description = "Text to uppercase", name = "input") String text) {
|
||||
return text.toUpperCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(description = "Remove spaces to the left of a string.", name = "LStrip")
|
||||
public String lStrip(
|
||||
@KernelFunctionParameter(description = "Text to edit", name = "input") String text) {
|
||||
return text.replaceAll("^ +", "");
|
||||
}
|
||||
|
||||
@DefineKernelFunction(description = "Remove spaces to the right of a string.", name = "RStrip")
|
||||
public String rStrip(
|
||||
@KernelFunctionParameter(description = "Text to edit", name = "input") String text) {
|
||||
return text.replaceAll(" +$", "");
|
||||
}
|
||||
|
||||
@DefineKernelFunction(description = "Remove spaces to the left and right of a string", name = "Strip")
|
||||
public String strip(
|
||||
@KernelFunctionParameter(description = "Text to edit", name = "input") String input) {
|
||||
return input.trim();
|
||||
}
|
||||
|
||||
@DefineKernelFunction(description = "Change all string chars to lowercase", name = "lowercase")
|
||||
public String lowercase(
|
||||
@KernelFunctionParameter(description = "Text to lowercase", name = "input") String input) {
|
||||
return input.toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Concatenate two strings into one
|
||||
/// </summary>
|
||||
/// <param name="input">First input to concatenate with</param>
|
||||
/// <param name="input2">Second input to concatenate with</param>
|
||||
/// <returns>Concatenation result from both inputs.</returns>
|
||||
@DefineKernelFunction(description = "Concat two strings into one.", name = "Concat")
|
||||
public String concat(
|
||||
@KernelFunctionParameter(description = "First input to concatenate with", name = "input") String input,
|
||||
@KernelFunctionParameter(description = "Second input to concatenate with", name = "input2") String input2) {
|
||||
return (input + input2);
|
||||
}
|
||||
|
||||
}
|
||||
-159
@@ -1,159 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.plugins.web;
|
||||
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
public class SearchUrlPlugin {
|
||||
/*
|
||||
* Amazon Search URLs
|
||||
*/
|
||||
/// <summary>
|
||||
/// Get search URL for Amazon
|
||||
/// </summary>
|
||||
@DefineKernelFunction(name = "AmazonSearchUrl", description = "Return URL for Amazon search query")
|
||||
public String AmazonSearchUrl(
|
||||
@KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) {
|
||||
String encoded = encode(query);
|
||||
return String.format("https://www.amazon.com/s?k=%s", encoded);
|
||||
}
|
||||
|
||||
/*
|
||||
* Bing Search URLs
|
||||
*/
|
||||
/// <summary>
|
||||
/// Get search URL for Bing
|
||||
/// </summary>
|
||||
@DefineKernelFunction(name = "BingSearchUrl", description = "Return URL for Bing search query.")
|
||||
public String BingSearchUrl(
|
||||
@KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) {
|
||||
String encoded = encode(query);
|
||||
return String.format("https://www.bing.com/search?q=%s", encoded);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get search URL for Bing Images
|
||||
/// </summary>
|
||||
@DefineKernelFunction(name = "BingImagesSearchUrl", description = "Return URL for Bing Images search query.")
|
||||
public String BingImagesSearchUrl(
|
||||
@KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) {
|
||||
String encoded = encode(query);
|
||||
return String.format("https://www.bing.com/images/search?q=%s", encoded);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get search URL for Bing Maps
|
||||
/// </summary>
|
||||
@DefineKernelFunction(name = "BingMapsSearchUrl", description = "Return URL for Bing Maps search query.")
|
||||
public String BingMapsSearchUrl(
|
||||
@KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) {
|
||||
String encoded = encode(query);
|
||||
return String.format("https://www.bing.com/maps?q=%s", encoded);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get search URL for Bing Shopping
|
||||
/// </summary>
|
||||
@DefineKernelFunction(name = "BingShoppingSearchUrl", description = "Return URL for Bing Shopping search query.")
|
||||
public String BingShoppingSearchUrl(
|
||||
@KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) {
|
||||
String encoded = encode(query);
|
||||
return String.format("https://www.bing.com/shop?q=%s", encoded);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get search URL for Bing News
|
||||
/// </summary>
|
||||
@DefineKernelFunction(name = "BingNewsSearchUrl", description = "Return URL for Bing News search query.")
|
||||
public String BingNewsSearchUrl(
|
||||
@KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) {
|
||||
String encoded = encode(query);
|
||||
return String.format("https://www.bing.com/news/search?q=%s", encoded);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get search URL for Bing Travel
|
||||
/// </summary>
|
||||
@DefineKernelFunction(name = "BingTravelSearchUrl", description = "Return URL for Bing Travel search query.")
|
||||
public String BingTravelSearchUrl(
|
||||
@KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) {
|
||||
String encoded = encode(query);
|
||||
return String.format("https://www.bing.com/travel/search?q=%s", encoded);
|
||||
}
|
||||
|
||||
/*
|
||||
* Facebook Search URLs
|
||||
*/
|
||||
/// <summary>
|
||||
/// Get search URL for Facebook
|
||||
/// </summary>
|
||||
@DefineKernelFunction(name = "FacebookSearchUrl", description = "Return URL for Facebook search query.")
|
||||
public String FacebookSearchUrl(
|
||||
@KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) {
|
||||
String encoded = encode(query);
|
||||
return String.format("https://www.facebook.com/search/top/?q=%s", encoded);
|
||||
}
|
||||
|
||||
/*
|
||||
* GitHub Search URLs
|
||||
*/
|
||||
/// <summary>
|
||||
/// Get search URL for GitHub
|
||||
/// </summary>
|
||||
@DefineKernelFunction(name = "GitHubSearchUrl", description = "Return URL for GitHub search query.")
|
||||
public String GitHubSearchUrl(
|
||||
@KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) {
|
||||
String encoded = encode(query);
|
||||
return String.format("https://github.com/search?q=%s", encoded);
|
||||
}
|
||||
|
||||
/*
|
||||
* LinkedIn Search URLs
|
||||
*/
|
||||
/// <summary>
|
||||
/// Get search URL for LinkedIn
|
||||
/// </summary>
|
||||
@DefineKernelFunction(name = "LinkedInSearchUrl", description = "Return URL for LinkedIn search query.")
|
||||
public String LinkedInSearchUrl(
|
||||
@KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) {
|
||||
String encoded = encode(query);
|
||||
return String.format("https://www.linkedin.com/search/results/index/?keywords=%s", encoded);
|
||||
}
|
||||
|
||||
/*
|
||||
* Twitter Search URLs
|
||||
*/
|
||||
/// <summary>
|
||||
/// Get search URL for Twitter
|
||||
/// </summary>
|
||||
@DefineKernelFunction(name = "TwitterSearchUrl", description = "Return URL for Twitter search query.")
|
||||
public String TwitterSearchUrl(
|
||||
@KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) {
|
||||
String encoded = encode(query);
|
||||
return String.format("https://twitter.com/search?q=%s", encoded);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wikipedia Search URLs
|
||||
*/
|
||||
/// <summary>
|
||||
/// Get search URL for Wikipedia
|
||||
/// </summary>
|
||||
@DefineKernelFunction(name = "WikipediaSearchUrl", description = "Return URL for Wikipedia search query.")
|
||||
public String WikipediaSearchUrl(
|
||||
@KernelFunctionParameter(description = "Text to search for", name = "query", required = true, type = String.class) String query) {
|
||||
String encoded = encode(query);
|
||||
return String.format("https://wikipedia.org/w/index.php?search=%s", encoded);
|
||||
}
|
||||
|
||||
private static String encode(String query) {
|
||||
try {
|
||||
return URLEncoder.encode(query, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// should never happen since UTF-8 is always supported
|
||||
return query;
|
||||
}
|
||||
}
|
||||
}
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.plugins.web;
|
||||
|
||||
import com.microsoft.semantickernel.connectors.WebSearchEngineConnector;
|
||||
import com.microsoft.semantickernel.connectors.WebSearchEngineConnector.WebPage;
|
||||
import com.microsoft.semantickernel.exceptions.SKException;
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter;
|
||||
import java.util.stream.Collectors;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/// <summary>
|
||||
/// Web search engine plugin (e.g. Bing).
|
||||
/// </summary>
|
||||
public class WebSearchEnginePlugin {
|
||||
|
||||
/// <summary>
|
||||
/// The count parameter name.
|
||||
/// </summary>
|
||||
public static final String COUNT_PARAM = "count";
|
||||
|
||||
/// <summary>
|
||||
/// The offset parameter name.
|
||||
/// </summary>
|
||||
public static final String OFFSET_PARAM = "offset";
|
||||
|
||||
private final WebSearchEngineConnector connector;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WebSearchEnginePlugin"/> class.
|
||||
/// </summary>
|
||||
/// <param name="connector">The web search engine connector.</param>
|
||||
public WebSearchEnginePlugin(WebSearchEngineConnector connector) {
|
||||
this.connector = connector;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a web search using the provided query, count, and offset.
|
||||
/// </summary>
|
||||
/// <param name="query">The text to search for.</param>
|
||||
/// <param name="count">The number of results to return. Default is 1.</param>
|
||||
/// <param name="offset">The number of results to skip. Default is 0.</param>
|
||||
/// <param name="cancellationToken">A cancellation token to observe while waiting for the task to complete.</param>
|
||||
/// <returns>A task that represents the asynchronous operation. The value of the TResult parameter contains the search results as a string.</returns>
|
||||
/// <remarks>
|
||||
/// This method is marked as "unsafe." The usage of JavaScriptEncoder.UnsafeRelaxedJsonEscaping may introduce security risks.
|
||||
/// Only use this method if you are aware of the potential risks and have validated the input to prevent security vulnerabilities.
|
||||
/// </remarks>
|
||||
@DefineKernelFunction(name = "search", description = "Searches the web for the given query", returnType = "java.lang.String")
|
||||
public Mono<String> searchAsync(
|
||||
@KernelFunctionParameter(description = "The search query", name = "query", type = String.class) String query,
|
||||
@KernelFunctionParameter(description = "The number of results to return", name = "count", defaultValue = "1", type = int.class) int count,
|
||||
@KernelFunctionParameter(description = "The number of results to skip", name = "offset", defaultValue = "0", type = int.class) int offset) {
|
||||
|
||||
return connector.searchAsync(query, count, offset).map(results -> {
|
||||
|
||||
if (results == null || results.isEmpty()) {
|
||||
throw new SKException("Failed to get a response from the web search engine.");
|
||||
}
|
||||
|
||||
return count == 1
|
||||
? results.get(0).getSnippet()
|
||||
// TODO: .NET code does `JsonSerializer.Serialize(results, s_jsonOptionsCache)` here
|
||||
// The joiner results in "[\"result1\",\"result2\"]"
|
||||
: results.stream()
|
||||
.limit(count)
|
||||
.map(WebPage::getSnippet)
|
||||
.collect(Collectors.joining("\",\"", "[\"", "\"]"));
|
||||
});
|
||||
}
|
||||
}
|
||||
-41
@@ -1,41 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.syntaxexamples;
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
|
||||
import com.microsoft.semantickernel.samples.plugins.web.SearchUrlPlugin;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
|
||||
|
||||
public class Example11_WebSearchQueries {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
var kernel = Kernel.builder().build();
|
||||
|
||||
// Load native plugins
|
||||
var searchUrlPlugin = KernelPluginFactory.createFromObject(new SearchUrlPlugin(),
|
||||
"SearchUrlPlugin");
|
||||
var bingSearchFunction = searchUrlPlugin.get("BingSearchUrl");
|
||||
|
||||
// Run
|
||||
var ask = "What's the largest building in Europe?";
|
||||
var kernelArguments = KernelFunctionArguments.builder()
|
||||
.withVariable("query", ask)
|
||||
.build();
|
||||
|
||||
var result = kernel.invokeAsync(bingSearchFunction).withArguments(kernelArguments).block();
|
||||
|
||||
System.out.println(ask);
|
||||
System.out.println(result.getResult());
|
||||
|
||||
/*
|
||||
* Expected output:
|
||||
* ======== WebSearchQueries ========
|
||||
* What's the tallest building in Europe?
|
||||
*
|
||||
* https://www.bing.com/search?q=What%27s%20the%20tallest%20building%20in%20Europe%3F
|
||||
* == DONE ==
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
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.azure.core.http.HttpClient;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
|
||||
import com.microsoft.semantickernel.samples.plugins.ConversationSummaryPlugin;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
|
||||
import com.microsoft.semantickernel.services.textcompletion.TextGenerationService;
|
||||
|
||||
public class Example42_KernelBuilder {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// KernelBuilder provides a simple way to configure a Kernel. This constructs a kernel
|
||||
// with logging and an Azure OpenAI chat completion service configured.
|
||||
OpenAIAsyncClient client = new OpenAIClientBuilder()
|
||||
.credential(new AzureKeyCredential("a-key"))
|
||||
.endpoint("an-endpoint")
|
||||
.buildAsyncClient();
|
||||
|
||||
Kernel kernel1 = Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class,
|
||||
ChatCompletionService.builder()
|
||||
.withOpenAIAsyncClient(client)
|
||||
.withModelId("gpt-35-turbo-2")
|
||||
.build())
|
||||
.build();
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// Kernel with custom HttpClient
|
||||
HttpClient httpClient = HttpClient.createDefault();
|
||||
|
||||
OpenAIAsyncClient client2 = new OpenAIClientBuilder()
|
||||
.httpClient(httpClient)
|
||||
.credential(new KeyCredential("a-key"))
|
||||
.buildAsyncClient();
|
||||
|
||||
TextGenerationService textGenerationService = TextGenerationService.builder()
|
||||
.withOpenAIAsyncClient(client2)
|
||||
.withModelId("text-davinci-003")
|
||||
.build();
|
||||
|
||||
Kernel kernel2 = Kernel.builder()
|
||||
.withAIService(TextGenerationService.class, textGenerationService)
|
||||
.build();
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
//Plugins may also be configured via the corresponding Plugins property
|
||||
|
||||
Kernel kernel3 = Kernel.builder()
|
||||
.withPlugin(KernelPluginFactory.createFromObject(new ConversationSummaryPlugin(),
|
||||
"ConversationSummaryPlugin"))
|
||||
.build();
|
||||
|
||||
}
|
||||
}
|
||||
-76
@@ -1,76 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
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.Kernel;
|
||||
import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion;
|
||||
import com.microsoft.semantickernel.orchestration.FunctionResult;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
|
||||
|
||||
public class Example43_GetModelResult {
|
||||
|
||||
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 - ChatGPT Streaming ========");
|
||||
|
||||
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 chatCompletionService = OpenAIChatCompletion.builder()
|
||||
.withModelId(MODEL_ID)
|
||||
.withOpenAIAsyncClient(client)
|
||||
.build();
|
||||
|
||||
Kernel kernel = Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class, chatCompletionService)
|
||||
.build();
|
||||
|
||||
System.out.println("======== Inline Function Definition + Invocation ========");
|
||||
|
||||
// Create function
|
||||
String FunctionDefinition = "Hi, give me 5 book suggestions about: {{$input}}";
|
||||
KernelFunction<String> myFunction = KernelFunctionFromPrompt.<String>builder()
|
||||
.withTemplate(FunctionDefinition).build();
|
||||
|
||||
// Invoke function through kernel
|
||||
FunctionResult<String> result = kernel.invokeAsync(
|
||||
myFunction)
|
||||
.withArguments(
|
||||
KernelFunctionArguments.builder()
|
||||
.withVariable("input", "travel")
|
||||
.build())
|
||||
.block();
|
||||
|
||||
// Display results
|
||||
System.out.println(result.getResult());
|
||||
System.out.println(
|
||||
"Usage: " + result
|
||||
.getMetadata()
|
||||
.getUsage().getTotalTokens());
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
-118
@@ -1,118 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
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.Kernel;
|
||||
import com.microsoft.semantickernel.orchestration.InvocationContext;
|
||||
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatHistory;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Logit_bias is an optional parameter that modifies the likelihood of specified tokens appearing in
|
||||
* a Completion. When using the Token Selection Biases parameter, the bias is added to the logits
|
||||
* generated by the model prior to sampling.
|
||||
*/
|
||||
public class Example49_LogitBias {
|
||||
|
||||
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");
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
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 openAIChatCompletion = ChatCompletionService.builder()
|
||||
.withOpenAIAsyncClient(client)
|
||||
.withModelId("gpt-35-turbo-2")
|
||||
.build();
|
||||
|
||||
Kernel kernel = Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class, openAIChatCompletion)
|
||||
.build();
|
||||
|
||||
// To use Logit Bias you will need to know the token ids of the words you want to use.
|
||||
// Getting the token ids using the GPT Tokenizer: https://platform.openai.com/tokenizer
|
||||
|
||||
// The following text is the tokenized version of the book related tokens
|
||||
// "novel literature reading author library story chapter paperback hardcover ebook publishing fiction nonfiction manuscript textbook bestseller bookstore reading list bookworm"
|
||||
var keys = new int[] { 39142, 301, 17649, 5403, 3229, 6875, 3446, 12735, 86831, 2653, 3773,
|
||||
35097, 23763, 17422, 2536, 58162, 47913, 56185, 1888, 35199, 79761, 5403, 1160,
|
||||
2363,
|
||||
56741 };
|
||||
/*
|
||||
* // If using GPT-3 (not GPT-3.5 or GPT-4)
|
||||
* var keys = new int[]{3919, 626, 9285, 3555, 1772, 5888, 1621, 6843, 46771, 1327, 9631,
|
||||
* 47179, 12407, 10165, 1729, 24046, 17116, 28979, 1266, 32932, 44346, 3555, 1351, 1492,
|
||||
* 25323};
|
||||
*/
|
||||
// This will make the model try its best to avoid any of the above related words.
|
||||
//-100 to potentially ban all the tokens from the list.
|
||||
Map<Integer, Integer> biases = new HashMap<>();
|
||||
Arrays.stream(keys)
|
||||
.asLongStream()
|
||||
.forEach(key -> biases.put((int) key, -100));
|
||||
|
||||
var settings = PromptExecutionSettings.builder()
|
||||
.withTokenSelectionBiases(biases)
|
||||
.build();
|
||||
|
||||
var invocationContext = InvocationContext.builder().withPromptExecutionSettings(settings)
|
||||
.build();
|
||||
|
||||
System.out.println("Chat content:");
|
||||
System.out.println("------------------------");
|
||||
|
||||
var chatHistory = new ChatHistory("You are a librarian expert");
|
||||
|
||||
// First user message
|
||||
chatHistory.addUserMessage("Hi, I'm looking some suggestions");
|
||||
messageOutputAsync(chatHistory);
|
||||
|
||||
var replyMessage = openAIChatCompletion.getChatMessageContentsAsync(chatHistory,
|
||||
kernel, invocationContext).block();
|
||||
|
||||
chatHistory = new ChatHistory(replyMessage);
|
||||
|
||||
messageOutputAsync(chatHistory);
|
||||
|
||||
chatHistory.addUserMessage(
|
||||
"I love history and philosophy, I'd like to learn something new about Greece, any suggestion");
|
||||
messageOutputAsync(chatHistory);
|
||||
|
||||
replyMessage = openAIChatCompletion.getChatMessageContentsAsync(chatHistory,
|
||||
kernel, invocationContext).block();
|
||||
chatHistory = new ChatHistory(replyMessage);
|
||||
messageOutputAsync(chatHistory);
|
||||
|
||||
}
|
||||
|
||||
private static void messageOutputAsync(ChatHistory chatHistory) {
|
||||
var message = chatHistory.getLastMessage();
|
||||
|
||||
System.out.println(message.get().getAuthorRole() + ": " + message.get().getContent());
|
||||
System.out.println("------------------------");
|
||||
}
|
||||
|
||||
}
|
||||
-55
@@ -1,55 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.syntaxexamples;
|
||||
|
||||
import com.microsoft.semantickernel.text.TextChunker;
|
||||
import java.util.List;
|
||||
|
||||
public class Example55_TextChunker {
|
||||
|
||||
private static final String text = """
|
||||
The city of Venice, located in the northeastern part of Italy,
|
||||
is renowned for its unique geographical features. Built on more than 100 small islands in a lagoon in the
|
||||
Adriatic Sea, it has no roads, just canals including the Grand Canal thoroughfare lined with Renaissance and
|
||||
Gothic palaces. The central square, Piazza San Marco, contains St. Mark's Basilica, which is tiled with Byzantine
|
||||
mosaics, and the Campanile bell tower offering views of the city's red roofs.
|
||||
|
||||
The Amazon Rainforest, also known as Amazonia, is a moist broadleaf tropical rainforest in the Amazon biome that
|
||||
covers most of the Amazon basin of South America. This basin encompasses 7 million square kilometers, of which
|
||||
5.5 million square kilometers are covered by the rainforest. This region includes territory belonging to nine nations
|
||||
and 3.4 million square kilometers of uncontacted tribes. The Amazon represents over half of the planet's remaining
|
||||
rainforests and comprises the largest and most biodiverse tract of tropical rainforest in the world.
|
||||
|
||||
The Great Barrier Reef is the world's largest coral reef system composed of over 2,900 individual reefs and 900 islands
|
||||
stretching for over 2,300 kilometers over an area of approximately 344,400 square kilometers. The reef is located in the
|
||||
Coral Sea, off the coast of Queensland, Australia. The Great Barrier Reef can be seen from outer space and is the world's
|
||||
biggest single structure made by living organisms. This reef structure is composed of and built by billions of tiny organisms,
|
||||
known as coral polyps.
|
||||
"""
|
||||
.stripIndent();
|
||||
|
||||
public static void main(String[] args) {
|
||||
RunExample();
|
||||
|
||||
// TODO: This example should also demo using token counters, not supported in Java atm
|
||||
}
|
||||
|
||||
private static void RunExample() {
|
||||
System.out.println("=== Text chunking ===");
|
||||
|
||||
var lines = TextChunker.splitPlainTextLines(text, 40);
|
||||
var paragraphs = TextChunker.splitPlainTextParagraphs(lines, 120);
|
||||
|
||||
writeParagraphsToConsole(paragraphs);
|
||||
}
|
||||
|
||||
private static void writeParagraphsToConsole(List<String> paragraphs) {
|
||||
for (var i = 0; i < paragraphs.size(); i++) {
|
||||
System.out.println(paragraphs.get(i));
|
||||
|
||||
if (i < paragraphs.size() - 1) {
|
||||
System.out.println("------------------------");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-412
@@ -1,412 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.syntaxexamples;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.OpenAIClientBuilder;
|
||||
import com.azure.ai.openai.models.ChatCompletionsOptions;
|
||||
import com.azure.ai.openai.models.ChatRequestMessage;
|
||||
import com.azure.ai.openai.models.ChatRequestSystemMessage;
|
||||
import com.azure.core.credential.AzureKeyCredential;
|
||||
import com.azure.core.credential.KeyCredential;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.Kernel.Builder;
|
||||
import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion;
|
||||
import com.microsoft.semantickernel.contextvariables.ContextVariable;
|
||||
import com.microsoft.semantickernel.hooks.FunctionInvokedEvent;
|
||||
import com.microsoft.semantickernel.hooks.KernelHook.FunctionInvokedHook;
|
||||
import com.microsoft.semantickernel.hooks.KernelHook.FunctionInvokingHook;
|
||||
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.PreChatCompletionEvent;
|
||||
import com.microsoft.semantickernel.hooks.PromptRenderedEvent;
|
||||
import com.microsoft.semantickernel.orchestration.FunctionResult;
|
||||
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
|
||||
import com.microsoft.semantickernel.semanticfunctions.OutputVariable;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class Example57_KernelHooks {
|
||||
|
||||
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) {
|
||||
|
||||
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 openAIChatCompletion = OpenAIChatCompletion.builder()
|
||||
.withModelId(MODEL_ID)
|
||||
.withOpenAIAsyncClient(client)
|
||||
.build();
|
||||
|
||||
Builder kernelBuilder = Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class, openAIChatCompletion);
|
||||
|
||||
getUsageAsync(kernelBuilder.build());
|
||||
getRenderedPromptAsync(kernelBuilder.build());
|
||||
changingResultAsync(kernelBuilder.build());
|
||||
beforeInvokeCancellationAsync(kernelBuilder.build());
|
||||
afterInvokeCancellationAsync(kernelBuilder.build());
|
||||
chatCompletionHook(kernelBuilder.build());
|
||||
invocationHook(kernelBuilder.build());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrate using kernel invocation-hooks to monitor usage:
|
||||
/// <see cref="Kernel.FunctionInvoking"/>
|
||||
/// <see cref="Kernel.FunctionInvoked"/>
|
||||
/// </summary>
|
||||
private static void getUsageAsync(Kernel kernel) {
|
||||
System.out.println("\n======== Get Usage Data ========\n");
|
||||
|
||||
// Initialize prompt
|
||||
String functionPrompt = "Write a random paragraph about: {{$input}}.";
|
||||
|
||||
var excuseFunction = KernelFunctionFromPrompt.builder()
|
||||
.withTemplate(functionPrompt)
|
||||
.withName("Excuse")
|
||||
.withDefaultExecutionSettings(PromptExecutionSettings
|
||||
.builder()
|
||||
.withMaxTokens(100)
|
||||
.withTemperature(0.4)
|
||||
.withTopP(1)
|
||||
.build())
|
||||
.withOutputVariable(new OutputVariable<>("result", String.class))
|
||||
.build();
|
||||
|
||||
FunctionInvokingHook preHook = event -> {
|
||||
System.out.println(
|
||||
event.getFunction().getName() + " : Pre Execution Handler - Triggered");
|
||||
return event;
|
||||
};
|
||||
|
||||
FunctionInvokingHook removedPreExecutionHandler = event -> {
|
||||
System.out.println(
|
||||
event.getFunction().getName() + " : Pre Execution Handler - Should not trigger");
|
||||
return event;
|
||||
};
|
||||
|
||||
FunctionInvokedHook postExecutionHandler = event -> {
|
||||
System.out.println(
|
||||
event.getFunction().getName() + " : Post Execution Handler - Usage: " + event
|
||||
.getResult()
|
||||
.getMetadata()
|
||||
.getUsage()
|
||||
.getTotalTokens());
|
||||
return event;
|
||||
};
|
||||
|
||||
kernel.getGlobalKernelHooks().addHook(preHook);
|
||||
|
||||
// Demonstrate pattern for removing a handler.
|
||||
kernel.getGlobalKernelHooks().addHook("pre-invoke-removed", removedPreExecutionHandler);
|
||||
kernel.getGlobalKernelHooks().removeHook("pre-invoke-removed");
|
||||
|
||||
kernel.getGlobalKernelHooks().addHook(postExecutionHandler);
|
||||
|
||||
// Invoke prompt to trigger execution hooks.
|
||||
String input = "I missed the F1 final race";
|
||||
var result = kernel.invokeAsync(excuseFunction)
|
||||
.withArguments(
|
||||
KernelFunctionArguments
|
||||
.builder()
|
||||
.withVariable("input", input)
|
||||
.build())
|
||||
.block();
|
||||
System.out.println("Function Result: " + result.getResult());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrate using kernel-hooks to around prompt rendering:
|
||||
/// <see cref="Kernel.PromptRendering"/>
|
||||
/// <see cref="Kernel.PromptRendered"/>
|
||||
/// </summary>
|
||||
private static void getRenderedPromptAsync(Kernel kernel) {
|
||||
System.out.println("\n======== Get Rendered Prompt ========\n");
|
||||
|
||||
// Initialize prompt
|
||||
String functionPrompt = "Write a random paragraph about: {{$input}} in the style of {{$style}}.";
|
||||
|
||||
var excuseFunction = KernelFunctionFromPrompt.builder()
|
||||
.withTemplate(functionPrompt)
|
||||
.withName("Excuse")
|
||||
.withDefaultExecutionSettings(PromptExecutionSettings
|
||||
.builder()
|
||||
.withMaxTokens(100)
|
||||
.withTemperature(0.4)
|
||||
.withTopP(1)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
PromptRenderingHook myRenderingHandler = event -> {
|
||||
System.out.println(
|
||||
event.getFunction().getName() + " : Prompt Rendering Handler - Triggered");
|
||||
|
||||
event.getArguments().put("style", ContextVariable.of("Seinfeld"));
|
||||
return event;
|
||||
};
|
||||
|
||||
PromptRenderedHook myRenderedHandler = event -> {
|
||||
System.out.println(
|
||||
event.getFunction().getName() + " : Prompt Rendered Handler - Triggered");
|
||||
|
||||
String prompt = event.getPrompt() + "\nUSE SHORT, CLEAR, COMPLETE SENTENCES.";
|
||||
|
||||
return new PromptRenderedEvent(
|
||||
event.getFunction(),
|
||||
event.getArguments(),
|
||||
prompt);
|
||||
};
|
||||
kernel.getGlobalKernelHooks().addHook(myRenderingHandler);
|
||||
kernel.getGlobalKernelHooks().addHook(myRenderedHandler);
|
||||
|
||||
// Invoke prompt to trigger execution hooks.
|
||||
String input = "I missed the F1 final race";
|
||||
var result = kernel.invokeAsync(excuseFunction)
|
||||
.withArguments(
|
||||
KernelFunctionArguments
|
||||
.builder()
|
||||
.withVariable("input", input)
|
||||
.build())
|
||||
.block();
|
||||
System.out.println("Function Result: " + result.getResult());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrate using kernel invocation-hooks to post process result:
|
||||
/// <see cref="Kernel.FunctionInvoked"/>
|
||||
/// </summary>
|
||||
private static void changingResultAsync(Kernel kernel) {
|
||||
System.out.println("\n======== Changing/Filtering Function Result ========\n");
|
||||
|
||||
// Initialize function
|
||||
String functionPrompt = "Write a paragraph about Handlers.";
|
||||
|
||||
var writerFunction = KernelFunctionFromPrompt.builder()
|
||||
.withTemplate(functionPrompt)
|
||||
.withName("Writer")
|
||||
.withDefaultExecutionSettings(PromptExecutionSettings
|
||||
.builder()
|
||||
.withMaxTokens(100)
|
||||
.withTemperature(0.4)
|
||||
.withTopP(1)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
FunctionInvokedHook hook = event -> {
|
||||
String result = (String) event.getResult().getResult();
|
||||
result = result.replaceAll("[aeiouAEIOU0-9]", "*");
|
||||
|
||||
return new FunctionInvokedEvent(
|
||||
event.getFunction(),
|
||||
event.getArguments(),
|
||||
new FunctionResult<>(
|
||||
ContextVariable.of(result),
|
||||
event.getResult().getMetadata(),
|
||||
result));
|
||||
};
|
||||
kernel.getGlobalKernelHooks().addHook(hook);
|
||||
|
||||
// Invoke prompt to trigger execution hooks.
|
||||
var result = kernel.invokeAsync(writerFunction)
|
||||
.withArguments(
|
||||
KernelFunctionArguments.builder().build())
|
||||
.block();
|
||||
System.out.println("Function Result: " + result.getResult());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrate using kernel invocation-hooks to cancel prior to execution:
|
||||
/// <see cref="Kernel.FunctionInvoking"/>
|
||||
/// <see cref="Kernel.FunctionInvoked"/>
|
||||
/// </summary>
|
||||
private static void beforeInvokeCancellationAsync(Kernel kernel) {
|
||||
System.out.println("\n======== Cancelling Pipeline Execution - Invoking event ========\n");
|
||||
|
||||
// Initialize prompt
|
||||
String functionPrompt = "Write a paragraph about: Cancellation.";
|
||||
|
||||
var writerFunction = KernelFunctionFromPrompt.builder()
|
||||
.withTemplate(functionPrompt)
|
||||
.withName("Writer")
|
||||
.withDefaultExecutionSettings(PromptExecutionSettings
|
||||
.builder()
|
||||
.withMaxTokens(1000)
|
||||
.withTemperature(1)
|
||||
.withTopP(0.5)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
FunctionInvokingHook hook = event -> {
|
||||
System.out.println(
|
||||
event.getFunction().getName()
|
||||
+ " : FunctionInvoking - Cancelling before execution");
|
||||
throw new RuntimeException("Cancelled");
|
||||
};
|
||||
|
||||
kernel.getGlobalKernelHooks().addHook(hook);
|
||||
|
||||
try {
|
||||
// Invoke prompt to trigger execution hooks.
|
||||
var result = kernel.invokeAsync(writerFunction)
|
||||
.withArguments(
|
||||
KernelFunctionArguments.builder().build())
|
||||
.block();
|
||||
System.out.println("Function Result: " + result.getResult());
|
||||
} catch (Exception e) {
|
||||
System.out.println("Exception: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrate using kernel invocation-hooks to cancel post after execution:
|
||||
/// <see cref="Kernel.FunctionInvoking"/>
|
||||
/// <see cref="Kernel.FunctionInvoked"/>
|
||||
/// </summary>
|
||||
private static void afterInvokeCancellationAsync(Kernel kernel) {
|
||||
System.out.println("\n======== Cancelling Pipeline Execution - Invoked event ========\n");
|
||||
|
||||
// Initialize prompts
|
||||
var firstFunction = KernelFunctionFromPrompt.<String>builder()
|
||||
.withTemplate("Write a phrase with Invoke.").build();
|
||||
var secondFunction = KernelFunctionFromPrompt.<String>builder()
|
||||
.withTemplate("Write a phrase with Cancellation.").build();
|
||||
|
||||
AtomicInteger invokingCounter = new AtomicInteger(0);
|
||||
kernel.getGlobalKernelHooks().addHook((FunctionInvokingHook) event -> {
|
||||
invokingCounter.incrementAndGet();
|
||||
return event;
|
||||
});
|
||||
|
||||
AtomicInteger invokedCounter = new AtomicInteger(0);
|
||||
kernel.getGlobalKernelHooks().addHook((FunctionInvokedHook) event -> {
|
||||
invokedCounter.incrementAndGet();
|
||||
throw new RuntimeException("Cancelled");
|
||||
});
|
||||
|
||||
// Invoke prompt to trigger execution hooks.
|
||||
try {
|
||||
var result = kernel.invokeAsync(secondFunction)
|
||||
.withArguments(KernelFunctionArguments.builder().build())
|
||||
.block();
|
||||
System.out.println("Function Result: " + result.getResult());
|
||||
} catch (Exception e) {
|
||||
System.out.println("Exception: " + e.getMessage());
|
||||
System.out.println("Function Invoked Times: " + invokedCounter.get());
|
||||
System.out.println("Function Invoking Times: " + invokedCounter.get());
|
||||
}
|
||||
}
|
||||
|
||||
private static void chatCompletionHook(Kernel kernel) {
|
||||
// Initialize prompt
|
||||
String functionPrompt = "Write a paragraph about hats";
|
||||
|
||||
var writerFunction = KernelFunctionFromPrompt.builder()
|
||||
.withTemplate(functionPrompt)
|
||||
.withName("Writer")
|
||||
.withDefaultExecutionSettings(PromptExecutionSettings
|
||||
.builder()
|
||||
.withMaxTokens(1000)
|
||||
.withTemperature(1)
|
||||
.withTopP(0.5)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
kernel.getGlobalKernelHooks().addPreChatCompletionHook(event -> {
|
||||
ChatCompletionsOptions options = event.getOptions();
|
||||
List<ChatRequestMessage> messages = options.getMessages();
|
||||
|
||||
messages = new ArrayList<>(messages);
|
||||
messages.add(
|
||||
new ChatRequestSystemMessage("Use upper case text when responding to the prompt."));
|
||||
|
||||
return new PreChatCompletionEvent(
|
||||
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)
|
||||
.withArguments(
|
||||
KernelFunctionArguments.builder().build())
|
||||
.block();
|
||||
System.out.println("Function Result: " + result.getResult());
|
||||
} catch (Exception e) {
|
||||
System.out.println("Exception: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show use of hooks added on a single invocations.
|
||||
*
|
||||
* @param kernel
|
||||
*/
|
||||
private static void invocationHook(Kernel kernel) {
|
||||
// Initialize prompt
|
||||
String functionPrompt = "Write a paragraph about hats";
|
||||
|
||||
var writerFunction = KernelFunctionFromPrompt.builder()
|
||||
.withTemplate(functionPrompt)
|
||||
.withName("Writer")
|
||||
.withDefaultExecutionSettings(PromptExecutionSettings
|
||||
.builder()
|
||||
.withMaxTokens(1000)
|
||||
.withTemperature(1)
|
||||
.withTopP(0.5)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
KernelHooks kernelHooks = new KernelHooks();
|
||||
kernelHooks.addPreChatCompletionHook(event -> {
|
||||
ChatCompletionsOptions options = event.getOptions();
|
||||
List<ChatRequestMessage> messages = options.getMessages();
|
||||
|
||||
messages = new ArrayList<>(messages);
|
||||
messages.add(
|
||||
new ChatRequestSystemMessage("Use upper case text when responding to the prompt."));
|
||||
|
||||
return new PreChatCompletionEvent(
|
||||
PreChatCompletionHook.cloneOptionsWithMessages(options, messages));
|
||||
});
|
||||
|
||||
try {
|
||||
// Invoke prompt to trigger execution hooks.
|
||||
var result = kernel.invokeAsync(writerFunction)
|
||||
.withArguments(KernelFunctionArguments.builder().build())
|
||||
.addKernelHooks(kernelHooks)
|
||||
.block();
|
||||
System.out.println("Function Result: " + result.getResult());
|
||||
} catch (Exception e) {
|
||||
System.out.println("Exception: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
-144
@@ -1,144 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
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.Kernel;
|
||||
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
|
||||
import com.microsoft.semantickernel.services.textcompletion.TextGenerationService;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class Example61_MultipleLLMs {
|
||||
|
||||
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");
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("======== Example61_MultipleLLMs ========");
|
||||
|
||||
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();
|
||||
}
|
||||
System.out.println("======== Using Chat GPT model for text generation ========");
|
||||
|
||||
var openAIChatCompletion = ChatCompletionService.builder()
|
||||
.withOpenAIAsyncClient(client)
|
||||
.withServiceId("AzureOpenAIChat")
|
||||
.withModelId("gpt-35-turbo-2")
|
||||
.build();
|
||||
|
||||
var textGenerationService = TextGenerationService.builder()
|
||||
.withOpenAIAsyncClient(client)
|
||||
.withServiceId("AzureOpenAIText")
|
||||
.withModelId("text-davinci-003")
|
||||
.build();
|
||||
|
||||
var kernel = Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class, openAIChatCompletion)
|
||||
.withAIService(TextGenerationService.class, textGenerationService)
|
||||
.build();
|
||||
|
||||
runByServiceIdAsync(kernel, "AzureOpenAIText");
|
||||
runByServiceIdAsync(kernel, "AzureOpenAIChat");
|
||||
|
||||
runByModelIdAsync(kernel, "gpt-35-turbo-2");
|
||||
|
||||
runByFirstModelIdAsync(kernel, "text-davinci-003", "gpt-35-turbo-2");
|
||||
}
|
||||
|
||||
public static void runByServiceIdAsync(Kernel kernel, String serviceId) {
|
||||
System.out.println("======== Service Id: " + serviceId + " ========");
|
||||
|
||||
var prompt = "Hello AI, what can you do for me?";
|
||||
|
||||
KernelFunctionArguments arguments = KernelFunctionArguments.builder().build();
|
||||
|
||||
KernelFunction<?> func = KernelFunctionFromPrompt
|
||||
.builder()
|
||||
.withTemplate(prompt)
|
||||
.withDefaultExecutionSettings(
|
||||
PromptExecutionSettings.builder()
|
||||
.withServiceId(serviceId)
|
||||
.build())
|
||||
.withOutputVariable("result", "java.lang.String")
|
||||
.build();
|
||||
|
||||
var result = kernel.invokeAsync(func).withArguments(arguments).block();
|
||||
System.out.println(result.getResult());
|
||||
}
|
||||
|
||||
public static void runByModelIdAsync(Kernel kernel, String modelId) {
|
||||
System.out.println("======== Model Id: " + modelId + " ========");
|
||||
|
||||
var prompt = "Hello AI, what can you do for me?";
|
||||
|
||||
var result = kernel.invokeAsync(
|
||||
KernelFunctionFromPrompt
|
||||
.builder()
|
||||
.withTemplate(prompt)
|
||||
.withDefaultExecutionSettings(
|
||||
PromptExecutionSettings.builder()
|
||||
.withModelId(modelId)
|
||||
.build())
|
||||
.withOutputVariable("result", "java.lang.String")
|
||||
.build())
|
||||
.withArguments(KernelFunctionArguments.builder().build())
|
||||
.block();
|
||||
|
||||
System.out.println(result.getResult());
|
||||
}
|
||||
|
||||
public static void runByFirstModelIdAsync(Kernel kernel, String... modelIds) {
|
||||
System.out.println("======== Model Ids: " + String.join(",", modelIds) + " ========");
|
||||
|
||||
var prompt = "Hello AI, what can you do for me?";
|
||||
|
||||
var modelSettings = new HashMap<String, PromptExecutionSettings>();
|
||||
|
||||
Arrays.stream(modelIds).forEach(
|
||||
modelId -> {
|
||||
modelSettings.put(
|
||||
modelId,
|
||||
PromptExecutionSettings.builder()
|
||||
.withModelId(modelId)
|
||||
.build());
|
||||
});
|
||||
|
||||
var promptConfig = PromptTemplateConfig.defaultTemplateBuilder()
|
||||
.withTemplate(prompt)
|
||||
.withName("HelloAI")
|
||||
.withExecutionSettings(modelSettings)
|
||||
.build();
|
||||
|
||||
var function = KernelFunctionFromPrompt.builder().withPromptTemplateConfig(promptConfig)
|
||||
.build();
|
||||
|
||||
var result = kernel.invokeAsync(function)
|
||||
.withArguments(KernelFunctionArguments.builder().build())
|
||||
.block();
|
||||
|
||||
System.out.println(result.getResult());
|
||||
}
|
||||
|
||||
}
|
||||
-115
@@ -1,115 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
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.Kernel;
|
||||
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
|
||||
import com.microsoft.semantickernel.services.AIService;
|
||||
import com.microsoft.semantickernel.services.AIServiceCollection;
|
||||
import com.microsoft.semantickernel.services.AIServiceSelection;
|
||||
import com.microsoft.semantickernel.services.BaseAIServiceSelector;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
|
||||
import com.microsoft.semantickernel.services.textcompletion.TextGenerationService;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class Example62_CustomAIServiceSelector {
|
||||
|
||||
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");
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("======== Example62_CustomAIServiceSelector ========");
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
// Build a kernel with multiple chat completion services
|
||||
|
||||
var openAIChatCompletion = ChatCompletionService.builder()
|
||||
.withOpenAIAsyncClient(client)
|
||||
.withServiceId("AzureOpenAIChat")
|
||||
.withModelId("gpt-35-turbo-2")
|
||||
.build();
|
||||
|
||||
var textGenerationService = TextGenerationService.builder()
|
||||
.withOpenAIAsyncClient(client)
|
||||
.withServiceId("AzureOpenAIText")
|
||||
.withModelId("text-davinci-003")
|
||||
.build();
|
||||
|
||||
var kernel = Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class, openAIChatCompletion)
|
||||
.withAIService(TextGenerationService.class, textGenerationService)
|
||||
.withServiceSelector(CustomAIServiceSelector::new)
|
||||
.build();
|
||||
|
||||
var prompt = "Hello AI, what can you do for me?";
|
||||
|
||||
KernelFunctionArguments arguments = KernelFunctionArguments.builder().build();
|
||||
|
||||
KernelFunction<?> func = KernelFunctionFromPrompt
|
||||
.builder()
|
||||
.withTemplate(prompt)
|
||||
.withDefaultExecutionSettings(
|
||||
PromptExecutionSettings.builder()
|
||||
.withTopP(1.0)
|
||||
.build())
|
||||
.withOutputVariable("result", "java.lang.String")
|
||||
.build();
|
||||
|
||||
var result = kernel.invokeAsync(func).withArguments(arguments).block();
|
||||
System.out.println(result.getResult());
|
||||
}
|
||||
|
||||
// A dumb AIServiceSelector that just returns the first service and execution settings it finds
|
||||
static class CustomAIServiceSelector extends BaseAIServiceSelector {
|
||||
|
||||
public CustomAIServiceSelector(AIServiceCollection services) {
|
||||
super(services);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends AIService> AIServiceSelection<T> trySelectAIService(
|
||||
Class<T> serviceType,
|
||||
|
||||
@Nullable KernelFunction<?> function,
|
||||
|
||||
@Nullable KernelFunctionArguments arguments,
|
||||
Map<Class<? extends AIService>, AIService> services) {
|
||||
|
||||
// Just get the first one
|
||||
PromptExecutionSettings executionSettings = function.getExecutionSettings()
|
||||
.values().stream().findFirst().get();
|
||||
// unchecked cast
|
||||
T service = (T) services.values().stream().findFirst().get();
|
||||
|
||||
return new AIServiceSelection<>(
|
||||
service,
|
||||
executionSettings);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.syntaxexamples;
|
||||
|
||||
/*
|
||||
* Currently the Java Semantic Kernel does not support streaming. If this is a feature you would like to see, please
|
||||
* let us know by creating an issue on github or letting us know on Discord.
|
||||
*/
|
||||
public class Example67_KernelStreaming {
|
||||
|
||||
}
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.syntaxexamples;
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.plugin.KernelPlugin;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction;
|
||||
|
||||
public class Example69_MutableKernelPlugin {
|
||||
|
||||
/**
|
||||
* Mutable KernelPlugin example
|
||||
* <p>
|
||||
* KernelFunction can be added directly to the function collection of the KernelPlugin by using
|
||||
* KernelPlugin.getFunctions and putting the corresponding KernelFunction
|
||||
*/
|
||||
public static void main(String[] args) throws NoSuchMethodException {
|
||||
System.out.println("======== Example69_MutableKernelPlugin ========");
|
||||
|
||||
KernelPlugin plugin = new KernelPlugin("Plugin", "Mutable plugin", null);
|
||||
plugin.addFunction(KernelFunction.createFromMethod(
|
||||
Time.class.getMethod("date"), new Time())
|
||||
.withFunctionName("dateFunction")
|
||||
.build());
|
||||
|
||||
Kernel kernel = Kernel.builder()
|
||||
.withPlugin(plugin)
|
||||
.build();
|
||||
|
||||
var result = kernel.invokeAsync(kernel.getFunction("Plugin", "dateFunction"))
|
||||
.block();
|
||||
|
||||
System.out.println("Result: " + result.getResult());
|
||||
}
|
||||
|
||||
public static class Time {
|
||||
|
||||
@DefineKernelFunction(name = "date")
|
||||
public String date() {
|
||||
return "2021-09-01";
|
||||
}
|
||||
}
|
||||
}
|
||||
-87
@@ -1,87 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.syntaxexamples;
|
||||
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.Example17_ChatGPT;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.Example30_ChatWithPrompts;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.Example33_Chat;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.Example44_MultiChatCompletion;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion.Example63_ChatCompletionPrompts;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.configuration.Example08_RetryHandler;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.configuration.Example41_HttpClientUsage;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.configuration.Example58_ConfigureExecutionSettings;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example01_NativeFunctions;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example03_Arguments;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example05_InlineFunctionDefinition;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example09_FunctionTypes;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example27_PromptFunctionsUsingChatGPT;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.functions.Example60_AdvancedMethodFunctions;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.plugins.Example10_DescribeAllPluginsAndFunctions;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.plugins.Example13_ConversationSummaryPlugin;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.template.Example06_TemplateLanguage;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.template.Example56_TemplateMethodFunctionsWithMultipleArguments;
|
||||
import com.microsoft.semantickernel.samples.syntaxexamples.template.Example64_MultiplePromptTemplates;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* Run all the syntax examples.
|
||||
* <p>
|
||||
* Refer to the <a href=
|
||||
* "https://github.com/microsoft/semantic-kernel/blob/experimental-java/java/samples/sample-code/README.md">
|
||||
* README</a> for configuring your environment to run the examples.
|
||||
*/
|
||||
public class RunAll {
|
||||
|
||||
public static void main(String[] args) {
|
||||
List<MainMethod> mains = Arrays.asList(
|
||||
Example01_NativeFunctions::main,
|
||||
Example03_Arguments::main,
|
||||
Example05_InlineFunctionDefinition::main,
|
||||
Example06_TemplateLanguage::main,
|
||||
Example08_RetryHandler::main,
|
||||
Example09_FunctionTypes::main,
|
||||
Example10_DescribeAllPluginsAndFunctions::main,
|
||||
//Example11_WebSearchQueries::main,
|
||||
Example13_ConversationSummaryPlugin::main,
|
||||
Example17_ChatGPT::main,
|
||||
//Example26_AADAuth::main,
|
||||
|
||||
Example27_PromptFunctionsUsingChatGPT::main,
|
||||
Example30_ChatWithPrompts::main,
|
||||
Example33_Chat::main,
|
||||
Example41_HttpClientUsage::main,
|
||||
Example43_GetModelResult::main,
|
||||
Example44_MultiChatCompletion::main,
|
||||
Example49_LogitBias::main,
|
||||
Example55_TextChunker::main,
|
||||
Example56_TemplateMethodFunctionsWithMultipleArguments::main,
|
||||
Example57_KernelHooks::main,
|
||||
Example58_ConfigureExecutionSettings::main,
|
||||
Example60_AdvancedMethodFunctions::main,
|
||||
Example61_MultipleLLMs::main,
|
||||
Example62_CustomAIServiceSelector::main,
|
||||
Example63_ChatCompletionPrompts::main,
|
||||
Example64_MultiplePromptTemplates::main,
|
||||
Example69_MutableKernelPlugin::main);
|
||||
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
mains.forEach(mainMethod -> {
|
||||
try {
|
||||
|
||||
System.out.println("========================================");
|
||||
mainMethod.run(args);
|
||||
|
||||
System.out.println("Press any key to continue...");
|
||||
scanner.nextLine();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public interface MainMethod {
|
||||
|
||||
void run(String[] args) throws Exception;
|
||||
}
|
||||
}
|
||||
-125
@@ -1,125 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.syntaxexamples.audio;
|
||||
|
||||
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.azure.core.util.BinaryData;
|
||||
import com.microsoft.semantickernel.services.audio.AudioContent;
|
||||
import com.microsoft.semantickernel.services.audio.AudioToTextExecutionSettings;
|
||||
import com.microsoft.semantickernel.services.audio.AudioToTextService;
|
||||
import com.microsoft.semantickernel.services.audio.TextToAudioExecutionSettings;
|
||||
import com.microsoft.semantickernel.services.audio.TextToAudioService;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
||||
public class Example82_Audio {
|
||||
|
||||
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");
|
||||
|
||||
private static final String TextToAudioModel = "tts-1";
|
||||
private static final String AudioToTextModel = "whisper-1";
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
System.out.println("======== Example82_Audio ========");
|
||||
File file = null;
|
||||
try {
|
||||
file = Files.createTempFile("audio", ".mp3").toFile();
|
||||
file.deleteOnExit();
|
||||
|
||||
textToAudioAsync(file);
|
||||
audioToTextAsync(file);
|
||||
} finally {
|
||||
if (file != null) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void textToAudioAsync(File audioFile) throws IOException {
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
var textToAudioService = TextToAudioService.builder()
|
||||
.withModelId(TextToAudioModel)
|
||||
.withOpenAIAsyncClient(client)
|
||||
.build();
|
||||
|
||||
String sampleText = "Hello, my name is John. I am a software engineer. I am working on a project to convert text to audio.";
|
||||
|
||||
// Set execution settings (optional)
|
||||
TextToAudioExecutionSettings executionSettings = TextToAudioExecutionSettings.builder()
|
||||
.withVoice("alloy")
|
||||
.withResponseFormat("mp3")
|
||||
.withSpeed(1.0)
|
||||
.build();
|
||||
|
||||
// Convert text to audio
|
||||
AudioContent audioContent = textToAudioService.getAudioContentAsync(
|
||||
sampleText,
|
||||
executionSettings)
|
||||
.block();
|
||||
|
||||
// Save audio content to a file
|
||||
Files.write(audioFile.toPath(), audioContent.getData());
|
||||
}
|
||||
|
||||
public static void audioToTextAsync(File audioFile) {
|
||||
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();
|
||||
}
|
||||
|
||||
var textToAudioService = AudioToTextService.builder()
|
||||
.withModelId(AudioToTextModel)
|
||||
.withOpenAIAsyncClient(client)
|
||||
.build();
|
||||
byte[] data = BinaryData.fromFile(audioFile.toPath()).toBytes();
|
||||
|
||||
// Set execution settings (optional)
|
||||
AudioToTextExecutionSettings executionSettings = AudioToTextExecutionSettings.builder()
|
||||
.withLanguage("en")
|
||||
.withPrompt("sample prompt")
|
||||
.withResponseFormat("json")
|
||||
.withTemperature(0.3)
|
||||
.withFilename(audioFile.getName())
|
||||
.build();
|
||||
|
||||
String text = textToAudioService.getTextContentsAsync(
|
||||
AudioContent.builder()
|
||||
.withData(data)
|
||||
.build(),
|
||||
executionSettings).block();
|
||||
|
||||
System.out.println(text);
|
||||
}
|
||||
}
|
||||
-80
@@ -1,80 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion;
|
||||
|
||||
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.services.chatcompletion.ChatCompletionService;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatHistory;
|
||||
|
||||
public class Example17_ChatGPT {
|
||||
|
||||
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 - ChatGPT ========");
|
||||
|
||||
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");
|
||||
|
||||
// First user message
|
||||
chatHistory.addUserMessage("Hi, I'm looking for book suggestions");
|
||||
messageOutput(chatHistory);
|
||||
|
||||
GPTReply(chatGPT, chatHistory);
|
||||
messageOutput(chatHistory);
|
||||
|
||||
chatHistory.addUserMessage(
|
||||
"I love history and philosophy, I'd like to learn something new about Greece, any suggestion");
|
||||
messageOutput(chatHistory);
|
||||
|
||||
GPTReply(chatGPT, chatHistory);
|
||||
messageOutput(chatHistory);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
var reply = chatGPT.getChatMessageContentsAsync(chatHistory, null, null)
|
||||
.block();
|
||||
|
||||
StringBuilder message = new StringBuilder();
|
||||
reply.forEach(chatMessageContent -> message.append(chatMessageContent.getContent()));
|
||||
chatHistory.addAssistantMessage(message.toString());
|
||||
}
|
||||
}
|
||||
-129
@@ -1,129 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion;
|
||||
|
||||
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.Kernel;
|
||||
import com.microsoft.semantickernel.implementation.EmbeddedResourceLoader;
|
||||
import com.microsoft.semantickernel.plugin.KernelPlugin;
|
||||
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
|
||||
import com.microsoft.semantickernel.samples.plugins.TimePlugin;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateFactory;
|
||||
import com.microsoft.semantickernel.services.ServiceNotFoundException;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatHistory;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
public class Example30_ChatWithPrompts {
|
||||
|
||||
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) throws FileNotFoundException, ServiceNotFoundException {
|
||||
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 openAIChatCompletion = ChatCompletionService.builder()
|
||||
.withOpenAIAsyncClient(client)
|
||||
.withModelId(MODEL_ID)
|
||||
.build();
|
||||
|
||||
Kernel kernel = Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class, openAIChatCompletion)
|
||||
.build();
|
||||
|
||||
System.out.println("======== Chat with prompts ========");
|
||||
|
||||
/*
|
||||
* Load 3 files:
|
||||
* - 30-system-prompt.txt: the system prompt, used to initialize the chat session.
|
||||
* - 30-user-context.txt: the user context, e.g. a piece of a document the user selected and
|
||||
* is asking to process.
|
||||
* - 30-user-prompt.txt: the user prompt, just for demo purpose showing that one can
|
||||
* leverage the same approach also to augment user messages.
|
||||
*/
|
||||
|
||||
var systemPromptTemplate = EmbeddedResourceLoader.readFile("30-system-prompt.txt",
|
||||
Example30_ChatWithPrompts.class);
|
||||
var selectedText = EmbeddedResourceLoader.readFile("30-user-context.txt",
|
||||
Example30_ChatWithPrompts.class);
|
||||
var userPromptTemplate = EmbeddedResourceLoader.readFile("30-user-prompt.txt",
|
||||
Example30_ChatWithPrompts.class);
|
||||
|
||||
// As an example, we import the time plugin, which is used in system prompt to read the current date.
|
||||
// We could also use a variable, this is just to show that the prompt can invoke functions.
|
||||
KernelPlugin timePlugin = KernelPluginFactory.createFromObject(
|
||||
new TimePlugin(), "time");
|
||||
kernel = kernel.toBuilder().withPlugin(timePlugin).build();
|
||||
|
||||
// Adding required arguments referenced by the prompt templates.
|
||||
|
||||
var arguments = KernelFunctionArguments
|
||||
.builder()
|
||||
.withVariable("selectedText", selectedText)
|
||||
.withVariable("startTime", DateTimeFormatter.ofPattern("hh:mm:ss a zz").format(
|
||||
ZonedDateTime.of(2000, 1, 1, 1, 1, 1, 1, ZoneId.systemDefault())))
|
||||
.withVariable("userMessage", "extract locations as a bullet point list")
|
||||
.build();
|
||||
|
||||
// Render the system prompt. This string is used to configure the chat.
|
||||
// This contains the context, ie a piece of a wikipedia page selected by the user.
|
||||
String systemMessage = PromptTemplateFactory
|
||||
.build(PromptTemplateConfig.builder().withTemplate(systemPromptTemplate).build())
|
||||
.renderAsync(kernel, arguments, null)
|
||||
.block();
|
||||
|
||||
System.out.println("------------------------------------\n" + systemMessage);
|
||||
|
||||
// Render the user prompt. This string is the query sent by the user
|
||||
// This contains the user request, ie "extract locations as a bullet point list"
|
||||
String userMessage = PromptTemplateFactory
|
||||
.build(PromptTemplateConfig.builder().withTemplate(userPromptTemplate).build())
|
||||
.renderAsync(kernel, arguments, null)
|
||||
.block();
|
||||
|
||||
System.out.println("------------------------------------\n" + userMessage);
|
||||
|
||||
// Client used to request answers
|
||||
var chatCompletion = kernel.getService(ChatCompletionService.class);
|
||||
|
||||
// The full chat history. Depending on your scenario, you can pass the full chat if useful,
|
||||
// or create a new one every time, assuming that the "system message" contains all the
|
||||
// information needed.
|
||||
var chatHistory = new ChatHistory(systemMessage);
|
||||
|
||||
// Add the user query to the chat history
|
||||
chatHistory.addUserMessage(userMessage);
|
||||
|
||||
// Finally, get the response from AI
|
||||
var answer = chatCompletion
|
||||
.getChatMessageContentsAsync(chatHistory, kernel, null)
|
||||
.block();
|
||||
System.out.println(
|
||||
"------------------------------------\n" + answer.stream().findFirst().get()
|
||||
.getContent());
|
||||
}
|
||||
}
|
||||
-90
@@ -1,90 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion;
|
||||
|
||||
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.implementation.CollectionUtil;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.AuthorRole;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatHistory;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
// In .net this is streaming, this is a non-streaming example
|
||||
public class Example33_Chat {
|
||||
|
||||
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 - ChatGPT Streaming ========");
|
||||
|
||||
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");
|
||||
|
||||
// First user message
|
||||
chatHistory.addUserMessage("Hi, I'm looking for book suggestions");
|
||||
messageOutput(chatHistory);
|
||||
|
||||
GPTReply(chatGPT, chatHistory);
|
||||
|
||||
chatHistory.addUserMessage(
|
||||
"I love history and philosophy, I'd like to learn something new about Greece, any suggestion");
|
||||
messageOutput(chatHistory);
|
||||
|
||||
GPTReply(chatGPT, chatHistory);
|
||||
}
|
||||
|
||||
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) {
|
||||
var reply = chatGPT.getChatMessageContentsAsync(chatHistory, null, null);
|
||||
System.out.print(AuthorRole.ASSISTANT + ": ");
|
||||
|
||||
String message = reply
|
||||
.mapNotNull(CollectionUtil::getLastOrNull)
|
||||
.doOnNext(streamingChatMessage -> {
|
||||
String content = streamingChatMessage.getContent();
|
||||
System.out.print(content);
|
||||
})
|
||||
.map(ChatMessageContent::getContent)
|
||||
.block();
|
||||
|
||||
System.out.println("\n------------------------");
|
||||
chatHistory.addAssistantMessage(message);
|
||||
}
|
||||
}
|
||||
-82
@@ -1,82 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion;
|
||||
|
||||
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.orchestration.InvocationContext;
|
||||
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatHistory;
|
||||
|
||||
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 invocationContext = InvocationContext.builder().withPromptExecutionSettings(settings)
|
||||
.build();
|
||||
|
||||
var reply = chatGPT.getChatMessageContentsAsync(chatHistory, null, invocationContext)
|
||||
.block();
|
||||
|
||||
reply.forEach(chatMessageContent -> {
|
||||
chatHistory.addAssistantMessage(chatMessageContent.getContent());
|
||||
messageOutput(chatHistory);
|
||||
});
|
||||
}
|
||||
}
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion;
|
||||
|
||||
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.Kernel;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
public class Example63_ChatCompletionPrompts {
|
||||
|
||||
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) throws InterruptedException {
|
||||
|
||||
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 openAIChatCompletion = ChatCompletionService.builder()
|
||||
.withOpenAIAsyncClient(client)
|
||||
.withModelId(MODEL_ID)
|
||||
.build();
|
||||
|
||||
Kernel kernel = Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class, openAIChatCompletion)
|
||||
.build();
|
||||
|
||||
String chatPrompt = """
|
||||
<message role="user">What is Seattle?</message>
|
||||
<message role="system">Respond with JSON.</message>
|
||||
""".stripIndent();
|
||||
|
||||
var chatSemanticFunction = KernelFunctionFromPrompt.<String>builder()
|
||||
.withTemplate(chatPrompt).build();
|
||||
var chatPromptResult = kernel.invokeAsync(chatSemanticFunction).block();
|
||||
|
||||
System.out.println("Chat Prompt:");
|
||||
System.out.println(chatPrompt);
|
||||
System.out.println("Chat Prompt Result:");
|
||||
System.out.println(chatPromptResult.getResult());
|
||||
|
||||
CountDownLatch cdl = new CountDownLatch(1);
|
||||
System.out.println("Chat Prompt Result:");
|
||||
kernel
|
||||
.invokeAsync(chatSemanticFunction)
|
||||
.doFinally(x -> cdl.countDown())
|
||||
.subscribe(result -> System.out.println(result.getResult()));
|
||||
|
||||
cdl.await();
|
||||
}
|
||||
}
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.syntaxexamples.configuration;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.OpenAIClientBuilder;
|
||||
import com.azure.core.credential.AzureKeyCredential;
|
||||
import com.azure.core.http.policy.ExponentialBackoffOptions;
|
||||
import com.azure.core.http.policy.RetryOptions;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.exceptions.ConfigurationException;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
|
||||
import com.microsoft.semantickernel.services.textcompletion.TextGenerationService;
|
||||
import java.time.Duration;
|
||||
|
||||
public class Example08_RetryHandler {
|
||||
|
||||
private static final String MODEL_ID = System.getenv()
|
||||
.getOrDefault("MODEL_ID", "text-davinci-003");
|
||||
|
||||
public static void main(String[] args) throws ConfigurationException {
|
||||
// Create a Kernel with the HttpClient
|
||||
RetryOptions retryOptions = new RetryOptions(new ExponentialBackoffOptions()
|
||||
.setMaxDelay(Duration.ofSeconds(10))
|
||||
.setBaseDelay(Duration.ofSeconds(2))
|
||||
.setMaxRetries(3));
|
||||
|
||||
OpenAIAsyncClient client = new OpenAIClientBuilder()
|
||||
.retryOptions(retryOptions)
|
||||
.endpoint("https://localhost:5000")
|
||||
.credential(new AzureKeyCredential("BAD KEY"))
|
||||
.buildAsyncClient();
|
||||
|
||||
TextGenerationService textGenerationService = TextGenerationService.builder()
|
||||
.withOpenAIAsyncClient(client)
|
||||
.withModelId(MODEL_ID)
|
||||
.build();
|
||||
|
||||
Kernel kernel = Kernel.builder()
|
||||
.withAIService(TextGenerationService.class, textGenerationService)
|
||||
.build();
|
||||
|
||||
String question = "How popular is the Polly library?";
|
||||
|
||||
KernelFunction<String> function = KernelFunctionFromPrompt.<String>builder()
|
||||
.withTemplate(question)
|
||||
.build();
|
||||
|
||||
try {
|
||||
// Will retry 3 times with exponential backoff
|
||||
kernel.invokeAsync(function).block();
|
||||
} catch (Exception e) {
|
||||
System.out.println("Hit max retries");
|
||||
}
|
||||
}
|
||||
}
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.syntaxexamples.configuration;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.OpenAIClientBuilder;
|
||||
import com.azure.identity.DeviceCodeCredential;
|
||||
import com.azure.identity.DeviceCodeCredentialBuilder;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.exceptions.ConfigurationException;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatHistory;
|
||||
|
||||
public class Example26_AADAuth {
|
||||
|
||||
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) throws ConfigurationException {
|
||||
|
||||
DeviceCodeCredential token = new DeviceCodeCredentialBuilder()
|
||||
.build();
|
||||
|
||||
OpenAIAsyncClient client = new OpenAIClientBuilder()
|
||||
.credential(token)
|
||||
.endpoint(CLIENT_ENDPOINT)
|
||||
.buildAsyncClient();
|
||||
|
||||
ChatCompletionService chatService = ChatCompletionService.builder()
|
||||
.withOpenAIAsyncClient(client)
|
||||
.withModelId(MODEL_ID)
|
||||
.build();
|
||||
|
||||
Kernel kernel = Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class, chatService)
|
||||
.build();
|
||||
|
||||
var chatHistory = new ChatHistory();
|
||||
|
||||
// User message
|
||||
chatHistory.addUserMessage("Tell me a joke about hourglasses");
|
||||
|
||||
// Bot reply
|
||||
var reply = chatService.getChatMessageContentsAsync(chatHistory, kernel, null).block();
|
||||
System.out.println(reply);
|
||||
}
|
||||
}
|
||||
-58
@@ -1,58 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.syntaxexamples.configuration;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.OpenAIClientBuilder;
|
||||
import com.azure.core.credential.AzureKeyCredential;
|
||||
import com.azure.core.http.HttpClient;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
|
||||
import com.microsoft.semantickernel.services.textcompletion.TextGenerationService;
|
||||
|
||||
public class Example41_HttpClientUsage {
|
||||
|
||||
public static void main(String[] args) {
|
||||
useDefaultHttpClient();
|
||||
useCustomHttpClient();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrates the usage of the default HttpClient provided by the SK SDK.
|
||||
/// </summary>
|
||||
private static void useDefaultHttpClient() {
|
||||
OpenAIAsyncClient client = new OpenAIClientBuilder()
|
||||
.credential(new AzureKeyCredential("a-key"))
|
||||
.endpoint("an-endpoint")
|
||||
.buildAsyncClient();
|
||||
|
||||
var kernel = Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class,
|
||||
ChatCompletionService.builder()
|
||||
.withOpenAIAsyncClient(client)
|
||||
.withModelId("gpt-35-turbo-2")
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrates the usage of a custom HttpClient.
|
||||
/// </summary>
|
||||
private static void useCustomHttpClient() {
|
||||
HttpClient customHttpClient = HttpClient.createDefault();
|
||||
|
||||
OpenAIAsyncClient client = new OpenAIClientBuilder()
|
||||
.httpClient(customHttpClient)
|
||||
.endpoint("https://localhost:5000")
|
||||
.credential(new AzureKeyCredential("BAD KEY"))
|
||||
.buildAsyncClient();
|
||||
|
||||
TextGenerationService textGenerationService = TextGenerationService.builder()
|
||||
.withOpenAIAsyncClient(client)
|
||||
.withModelId("text-davinci-003")
|
||||
.build();
|
||||
|
||||
Kernel kernel = Kernel.builder()
|
||||
.withAIService(TextGenerationService.class, textGenerationService)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
-103
@@ -1,103 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.syntaxexamples.configuration;
|
||||
|
||||
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.Kernel;
|
||||
import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion;
|
||||
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
|
||||
import com.microsoft.semantickernel.semanticfunctions.OutputVariable;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
|
||||
|
||||
public class Example58_ConfigureExecutionSettings {
|
||||
|
||||
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("======== Example58_ConfigureExecutionSettings ========");
|
||||
|
||||
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 openAIChatCompletion = OpenAIChatCompletion.builder()
|
||||
.withModelId(MODEL_ID)
|
||||
.withOpenAIAsyncClient(client)
|
||||
.build();
|
||||
|
||||
var kernel = Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class, openAIChatCompletion)
|
||||
.build();
|
||||
|
||||
var prompt = "Hello AI, what can you do for me?";
|
||||
|
||||
// Option 1:
|
||||
// Invoke the prompt function and pass an OpenAI specific instance containing the execution settings
|
||||
var result = kernel.invokeAsync(
|
||||
KernelFunctionFromPrompt.builder()
|
||||
.withTemplate(prompt)
|
||||
.withDefaultExecutionSettings(
|
||||
PromptExecutionSettings.builder()
|
||||
.withMaxTokens(60)
|
||||
.withTemperature(0.7)
|
||||
.build())
|
||||
.withOutputVariable(new OutputVariable<>("result", String.class))
|
||||
.build())
|
||||
.block();
|
||||
|
||||
System.out.println(result.getResult());
|
||||
|
||||
// Option 2:
|
||||
// Load prompt template configuration including the execution settings from a JSON payload
|
||||
// Create the prompt functions using the prompt template and the configuration (loaded in the previous step)
|
||||
// Invoke the prompt function using the implicitly set execution settings
|
||||
String configPayload = """
|
||||
{
|
||||
"schema": 1,
|
||||
"name": "HelloAI",
|
||||
"description": "Say hello to an AI",
|
||||
"type": "completion",
|
||||
"completion": {
|
||||
"max_tokens": 256,
|
||||
"temperature": 0.5,
|
||||
"top_p": 0.0,
|
||||
"presence_penalty": 0.0,
|
||||
"frequency_penalty": 0.0
|
||||
}
|
||||
}""".stripIndent();
|
||||
|
||||
var promptConfig = PromptTemplateConfig
|
||||
.parseFromJson(configPayload)
|
||||
.copy()
|
||||
.withTemplate(prompt)
|
||||
.build();
|
||||
|
||||
var func = KernelFunction
|
||||
.createFromPrompt(promptConfig)
|
||||
.build();
|
||||
|
||||
var result2 = kernel.invokeAsync(func).block();
|
||||
System.out.println(result2.getResult());
|
||||
}
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.syntaxexamples.functions;
|
||||
|
||||
import com.microsoft.semantickernel.samples.plugins.text.TextPlugin;
|
||||
|
||||
/**
|
||||
* Demonstrates a native function.
|
||||
*/
|
||||
public class Example01_NativeFunctions {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
// Load native skill
|
||||
TextPlugin text = new TextPlugin();
|
||||
|
||||
// Use function without kernel
|
||||
String result = text.uppercase("ciao!");
|
||||
|
||||
System.out.println(result);
|
||||
}
|
||||
}
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.syntaxexamples.functions;
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.orchestration.FunctionResult;
|
||||
import com.microsoft.semantickernel.plugin.KernelPlugin;
|
||||
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter;
|
||||
import java.util.Locale;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Demonstrates running a pipeline (a sequence of functions) on a
|
||||
* {@code com.microsoft.semantickernel.orchestration.SKContext}
|
||||
*/
|
||||
public class Example03_Arguments {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Kernel kernel = Kernel.builder().build();
|
||||
|
||||
// Load native plugin
|
||||
KernelPlugin functionCollection = KernelPluginFactory
|
||||
.createFromObject(new StaticTextPlugin(), "text");
|
||||
|
||||
KernelFunctionArguments arguments = KernelFunctionArguments.builder()
|
||||
.withInput("Today is: ")
|
||||
.withVariable("day", "Monday")
|
||||
.build();
|
||||
|
||||
FunctionResult<?> resultValue = kernel.invokeAsync(functionCollection.get("AppendDay"))
|
||||
.withArguments(arguments)
|
||||
.block();
|
||||
|
||||
System.out.println(resultValue.getResult());
|
||||
}
|
||||
|
||||
public static class StaticTextPlugin {
|
||||
|
||||
@DefineKernelFunction(description = "Change all string chars to uppercase.", name = "Uppercase", returnType = "java.lang.String")
|
||||
public static Mono<String> uppercase(
|
||||
@KernelFunctionParameter(description = "Text to uppercase", name = "input") String text) {
|
||||
return Mono.just(text.toUpperCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
@DefineKernelFunction(description = "Append the day variable", name = "appendDay", returnType = "java.lang.String")
|
||||
public Mono<String> appendDay(
|
||||
@KernelFunctionParameter(description = "Text to append to", name = "input") String input,
|
||||
@KernelFunctionParameter(description = "Current day", name = "day") String day) {
|
||||
return Mono.just(input + day);
|
||||
}
|
||||
}
|
||||
}
|
||||
-113
@@ -1,113 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.syntaxexamples.functions;
|
||||
|
||||
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.Kernel;
|
||||
import com.microsoft.semantickernel.exceptions.ConfigurationException;
|
||||
import com.microsoft.semantickernel.orchestration.FunctionResult;
|
||||
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
|
||||
import com.microsoft.semantickernel.services.textcompletion.TextGenerationService;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
public class Example05_InlineFunctionDefinition {
|
||||
|
||||
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", "text-davinci-003");
|
||||
|
||||
public static void main(String[] args) throws ConfigurationException {
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
TextGenerationService textGenerationService = TextGenerationService.builder()
|
||||
.withOpenAIAsyncClient(client)
|
||||
.withModelId(MODEL_ID)
|
||||
.build();
|
||||
|
||||
Kernel kernel = Kernel.builder()
|
||||
.withAIService(TextGenerationService.class, textGenerationService)
|
||||
.build();
|
||||
|
||||
System.out.println("======== Inline Function Definition ========");
|
||||
|
||||
// Function defined using few-shot design pattern
|
||||
String promptTemplate = """
|
||||
Generate a creative reason or excuse for the given event.
|
||||
Be creative and be funny. Let your imagination run wild.
|
||||
|
||||
Event: I am running late.
|
||||
Excuse: I was being held ransom by giraffe gangsters.
|
||||
|
||||
Event: I haven't been to the gym for a year
|
||||
Excuse: I've been too busy training my pet dragon.
|
||||
|
||||
Event: {{$input}}
|
||||
""".stripIndent();
|
||||
|
||||
var excuseFunction = KernelFunctionFromPrompt.builder()
|
||||
.withTemplate(promptTemplate)
|
||||
.withDefaultExecutionSettings(
|
||||
PromptExecutionSettings.builder()
|
||||
.withTemperature(0.4)
|
||||
.withTopP(1)
|
||||
.withMaxTokens(100)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
var result = kernel
|
||||
.invokeAsync(excuseFunction)
|
||||
.withArguments(
|
||||
KernelFunctionArguments.builder()
|
||||
.withInput("I missed the F1 final race")
|
||||
.build())
|
||||
.block();
|
||||
System.out.println(result.getResult());
|
||||
|
||||
result = kernel.invokeAsync(excuseFunction)
|
||||
.withArguments(
|
||||
KernelFunctionArguments.builder()
|
||||
.withInput("sorry I forgot your birthday")
|
||||
.build())
|
||||
.block();
|
||||
System.out.println(result.getResult());
|
||||
|
||||
var date = DateTimeFormatter.ISO_LOCAL_DATE.withZone(ZoneOffset.UTC)
|
||||
.format(Instant.ofEpochSecond(1));
|
||||
var message = "Translate this date " + date + " to French format";
|
||||
var fixedFunction = KernelFunction.createFromPrompt(message)
|
||||
.withDefaultExecutionSettings(
|
||||
PromptExecutionSettings.builder()
|
||||
.withMaxTokens(100)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
FunctionResult<?> fixedFunctionResult = kernel
|
||||
.invokeAsync(fixedFunction)
|
||||
.block();
|
||||
System.out.println(fixedFunctionResult.getResult());
|
||||
|
||||
}
|
||||
}
|
||||
-714
@@ -1,714 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.syntaxexamples.functions;
|
||||
|
||||
import static com.microsoft.semantickernel.contextvariables.ContextVariableTypes.convert;
|
||||
|
||||
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.Kernel;
|
||||
import com.microsoft.semantickernel.aiservices.openai.textcompletion.OpenAITextGenerationService;
|
||||
import com.microsoft.semantickernel.contextvariables.ContextVariable;
|
||||
import com.microsoft.semantickernel.contextvariables.ContextVariableType;
|
||||
import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter;
|
||||
import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter.NoopConverter;
|
||||
import com.microsoft.semantickernel.orchestration.FunctionResult;
|
||||
import com.microsoft.semantickernel.plugin.KernelPlugin;
|
||||
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter;
|
||||
import com.microsoft.semantickernel.services.textcompletion.TextGenerationService;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public class Example09_FunctionTypes {
|
||||
|
||||
private static final String PLUGIN_DIR = System.getenv("PLUGIN_DIR") == null ? "."
|
||||
: System.getenv("PLUGIN_DIR");
|
||||
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", "text-davinci-003");
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
|
||||
System.out.println("======== Method Function types ========");
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
TextGenerationService textGenerationService = OpenAITextGenerationService.builder()
|
||||
.withOpenAIAsyncClient(client)
|
||||
.withModelId(MODEL_ID)
|
||||
.build();
|
||||
|
||||
// Load native plugin into the kernel function collection, sharing its functions with prompt templates
|
||||
KernelPlugin plugin = KernelPluginFactory
|
||||
.createFromObject(new LocalExamplePlugin(), "Examples");
|
||||
|
||||
KernelPlugin summarize = KernelPluginFactory
|
||||
.importPluginFromDirectory(
|
||||
Path.of(PLUGIN_DIR,
|
||||
"java/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/resources/Plugins"),
|
||||
"SummarizePlugin",
|
||||
null);
|
||||
|
||||
KernelPlugin examplePlugin = KernelPluginFactory
|
||||
.importPluginFromResourcesDirectory(
|
||||
"Plugins",
|
||||
"ExamplePlugins",
|
||||
"ExampleFunctionRoot",
|
||||
null,
|
||||
Example09_FunctionTypes.class);
|
||||
|
||||
Kernel kernel = Kernel.builder()
|
||||
.withAIService(TextGenerationService.class, textGenerationService)
|
||||
.withPlugin(plugin)
|
||||
.withPlugin(summarize)
|
||||
.withPlugin(examplePlugin)
|
||||
.build();
|
||||
|
||||
// Different ways to invoke a function (not limited to these examples)
|
||||
FunctionResult<?> result = kernel.invokeAsync(plugin.get("NoInputWithVoidResult"))
|
||||
.block();
|
||||
assert result == null;
|
||||
|
||||
CountDownLatch cdl = new CountDownLatch(1);
|
||||
|
||||
kernel
|
||||
.invokeAsync(plugin.get("NoInputWithVoidResult"))
|
||||
.doFinally(ignore -> cdl.countDown())
|
||||
.subscribe(ignore -> {
|
||||
throw new RuntimeException("No return expected");
|
||||
});
|
||||
|
||||
cdl.await();
|
||||
|
||||
System.out.println(result != null ? result.getResult() : "null");
|
||||
result = kernel.invokeAsync(plugin.get("NoInputTaskWithVoidResult"))
|
||||
.block();
|
||||
assert result == null;
|
||||
System.out.println(result != null ? result.getResult() : "null");
|
||||
|
||||
result = kernel
|
||||
.invokeAsync(plugin.<String>get("InputDateTimeWithStringResult"))
|
||||
.withArguments(
|
||||
KernelFunctionArguments
|
||||
.builder()
|
||||
.withVariable("currentDate",
|
||||
ContextVariable.of(
|
||||
ZonedDateTime.of(1, 1, 1, 1, 1, 1, 1, ZoneOffset.UTC),
|
||||
new DateTimeContextVariableTypeConverter()))
|
||||
.build())
|
||||
.block();
|
||||
System.out.println(result.getResult());
|
||||
|
||||
result = kernel.invokeAsync(plugin.<String>get("NoInputTaskWithStringResult"))
|
||||
.block();
|
||||
System.out.println(result.getResult());
|
||||
|
||||
result = kernel.invokeAsync(plugin.<String>get("MultipleInputsWithVoidResult"))
|
||||
.withArguments(
|
||||
KernelFunctionArguments
|
||||
.builder()
|
||||
.withVariable("x", "x string")
|
||||
.withVariable("y", 100)
|
||||
.withVariable("z", 1.5)
|
||||
.build())
|
||||
.block();
|
||||
|
||||
result = kernel
|
||||
.invokeAsync(plugin.<String>get("ComplexInputWithStringResult"))
|
||||
.withArguments(
|
||||
KernelFunctionArguments
|
||||
.builder()
|
||||
.withVariable(
|
||||
"complexObject",
|
||||
ContextVariable.of(
|
||||
new Object() {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "A complex object";
|
||||
}
|
||||
},
|
||||
new NoopConverter<>(Object.class)))
|
||||
.build())
|
||||
.block();
|
||||
System.out.println(result.getResult());
|
||||
|
||||
result = kernel
|
||||
.invokeAsync(plugin.<String>get("InputStringTaskWithStringResult"))
|
||||
.withArguments(
|
||||
KernelFunctionArguments
|
||||
.builder()
|
||||
.withVariable("echoInput", "return this")
|
||||
.build())
|
||||
.block();
|
||||
System.out.println(result.getResult());
|
||||
|
||||
result = kernel
|
||||
.invokeAsync(plugin.<String>get("InputStringTaskWithVoidResult"))
|
||||
.withArguments(
|
||||
KernelFunctionArguments
|
||||
.builder()
|
||||
.withVariable("x", "x input")
|
||||
.build())
|
||||
.block();
|
||||
assert result == null;
|
||||
System.out.println(result != null ? result.getResult() : "null");
|
||||
|
||||
result = kernel
|
||||
.invokeAsync(plugin.<String>get("noInputComplexReturnTypeAsync"))
|
||||
.block();
|
||||
System.out.println(result.getResult());
|
||||
|
||||
var temporalResult = kernel
|
||||
.invokeAsync(plugin.<Temporal>get("noInputComplexReturnType"))
|
||||
.block();
|
||||
System.out.println(temporalResult.getResult());
|
||||
|
||||
// Possibilities for return type combinations:
|
||||
// | Method return type | Declared Function Return Type | Invocation Return type |
|
||||
// |--------------------|-------------------------------|------------------------|
|
||||
// | T | T | T |
|
||||
// | T | T | V converted from T |
|
||||
|
||||
// | T | U extends T | T |
|
||||
// | T | U extends T | U |
|
||||
// | T | U extends T | V converted from U |
|
||||
|
||||
var result1 = kernel
|
||||
.invokeAsync(plugin.<OffsetDateTime>get("conversionScenarioA"))
|
||||
.block();
|
||||
System.out.println(result1.getResult());
|
||||
|
||||
var result2 = kernel
|
||||
.invokeAsync(plugin.<Instant>get("conversionScenarioA"))
|
||||
.block();
|
||||
System.out.println(result2.getResult());
|
||||
|
||||
var result3 = kernel
|
||||
.invokeAsync(plugin.<OffsetDateTime>get("conversionScenarioB"))
|
||||
.block();
|
||||
System.out.println(result3.getResult());
|
||||
|
||||
var result4 = kernel
|
||||
.invokeAsync(plugin.<Temporal>get("conversionScenarioB"))
|
||||
.block();
|
||||
System.out.println(result4.getResult());
|
||||
|
||||
var result5 = kernel
|
||||
.invokeAsync(plugin.<Instant>get("conversionScenarioB"))
|
||||
.block();
|
||||
System.out.println(result5.getResult());
|
||||
|
||||
var result6 = kernel
|
||||
.invokeAsync(plugin.get("noInputComplexReturnType"))
|
||||
.block();
|
||||
System.out.println(result6.getResult());
|
||||
|
||||
var result7 = kernel
|
||||
.invokeAsync(plugin.get("withDefaultValue"))
|
||||
.block();
|
||||
System.out.println(result7.getResult());
|
||||
|
||||
var result8 = kernel
|
||||
.invokeAsync(plugin.get("noInputComplexReturnType"))
|
||||
.withResultType(
|
||||
new ContextVariableType<>(
|
||||
new DateTimeContextVariableTypeConverter(),
|
||||
ZonedDateTime.class))
|
||||
.block();
|
||||
System.out.println(result8.getResult());
|
||||
|
||||
var result9 = kernel
|
||||
.invokeAsync(plugin.get("noInputComplexReturnType"))
|
||||
.withResultType(
|
||||
new ContextVariableType<>(
|
||||
new DateTimeContextVariableTypeConverter(),
|
||||
ZonedDateTime.class))
|
||||
.block();
|
||||
System.out.println(result9.getResult());
|
||||
|
||||
result = kernel.invokeAsync(plugin.get("MultipleComplexInputsWithVoidResult"))
|
||||
.withArguments(
|
||||
KernelFunctionArguments
|
||||
.builder()
|
||||
.withVariable("x", OffsetDateTime.of(1, 1, 1, 1, 1, 1, 1, ZoneOffset.UTC))
|
||||
.withVariable("y", OffsetDateTime.of(1, 1, 1, 1, 1, 1, 1, ZoneOffset.UTC))
|
||||
.build())
|
||||
.withTypeConverter(new DateTimeContextVariableTypeConverter())
|
||||
.block();
|
||||
|
||||
var result10 = kernel
|
||||
.invokeAsync(plugin.get("WithPrimitiveReturnType"))
|
||||
.block();
|
||||
System.out.println(result10.getResult());
|
||||
|
||||
var result11 = kernel
|
||||
.invokeAsync(plugin.get("WithBoxedPrimitiveReturnType"))
|
||||
.block();
|
||||
System.out.println(result11.getResult());
|
||||
|
||||
var result12 = kernel
|
||||
.invokeAsync(plugin.get("AsyncWithBoxedPrimitiveReturnType"))
|
||||
.block();
|
||||
System.out.println(result12.getResult());
|
||||
|
||||
var result13 = kernel
|
||||
.invokeAsync(plugin.get("WithEmptyListReturn"))
|
||||
.block();
|
||||
System.out.println(result13.getResult());
|
||||
|
||||
var result14 = kernel
|
||||
.invokeAsync(plugin.get("WithListReturn"))
|
||||
.block();
|
||||
System.out.println(result14.getResult());
|
||||
|
||||
var result15 = kernel
|
||||
.invokeAsync(plugin.get("WithListReturn2"))
|
||||
.block();
|
||||
System.out.println(result15.getResult());
|
||||
|
||||
var result16 = kernel
|
||||
.invokeAsync(plugin.get("WithListReturn3"))
|
||||
.block();
|
||||
System.out.println(result16.getResult());
|
||||
|
||||
/*
|
||||
* TODO: support FunctionResult
|
||||
* kernel
|
||||
* .invokeAsync(plugin.get("NoInputWithFunctionResult"),
|
||||
* null,
|
||||
* Void.class)
|
||||
* .block();
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO: support injection
|
||||
* // Injecting Parameters Examples
|
||||
* await kernel.InvokeAsync(plugin[nameof(LocalExamplePlugin.
|
||||
* TaskInjectingKernelFunctionWithStringResult)]);
|
||||
* await
|
||||
* kernel.InvokeAsync(plugin[nameof(LocalExamplePlugin.TaskInjectingLoggerWithNoResult)]);
|
||||
* await kernel.InvokeAsync(plugin[nameof(LocalExamplePlugin.
|
||||
* TaskInjectingLoggerFactoryWithNoResult)]);
|
||||
* await kernel.InvokeAsync(plugin[nameof(LocalExamplePlugin.
|
||||
* TaskInjectingCultureInfoOrIFormatProviderWithStringResult)]);
|
||||
* await kernel.InvokeAsync(plugin[nameof(LocalExamplePlugin.
|
||||
* TaskInjectingCancellationTokenWithStringResult)]);
|
||||
* await kernel.InvokeAsync(plugin[nameof(LocalExamplePlugin.
|
||||
* TaskInjectingServiceSelectorWithStringResult)]);
|
||||
* await kernel.InvokeAsync(plugin[nameof(LocalExamplePlugin.
|
||||
* TaskInjectingKernelWithInputTextAndStringResult)],
|
||||
* new()
|
||||
* {
|
||||
* ["textToSummarize"] = @"C# is a modern, versatile language by Microsoft, blending the
|
||||
* efficiency of C++
|
||||
* with Visual Basic's simplicity. It's ideal for a wide range of applications,
|
||||
* emphasizing type safety, modularity, and modern programming paradigms."
|
||||
* });
|
||||
*
|
||||
*/
|
||||
|
||||
// You can also use the kernel.Plugins collection to invoke a function
|
||||
kernel
|
||||
.invokeAsync(
|
||||
kernel.getFunction("Examples", "NoInputWithVoidResult"))
|
||||
.block();
|
||||
}
|
||||
|
||||
private static class DateTimeContextVariableTypeConverter extends
|
||||
ContextVariableTypeConverter<ZonedDateTime> {
|
||||
|
||||
private static final List<Converter<ZonedDateTime, ?>> converters = List.of(
|
||||
new DefaultConverter<>(ZonedDateTime.class, Date.class) {
|
||||
@Override
|
||||
public Date toObject(ZonedDateTime zonedDateTime) {
|
||||
return new Date(zonedDateTime.toInstant().toEpochMilli());
|
||||
}
|
||||
},
|
||||
new DefaultConverter<>(ZonedDateTime.class, String.class) {
|
||||
@Override
|
||||
public String toObject(ZonedDateTime zonedDateTime) {
|
||||
return zonedDateTime.format(DateTimeFormatter.ISO_DATE_TIME);
|
||||
}
|
||||
});
|
||||
|
||||
public DateTimeContextVariableTypeConverter() {
|
||||
super(
|
||||
ZonedDateTime.class,
|
||||
(x) -> {
|
||||
if (x instanceof OffsetDateTime) {
|
||||
return ((OffsetDateTime) x).toZonedDateTime();
|
||||
}
|
||||
return convert(x, ZonedDateTime.class);
|
||||
},
|
||||
zonedDateTime -> zonedDateTime.format(DateTimeFormatter.ISO_DATE_TIME),
|
||||
promptString -> ZonedDateTime.parse(promptString, DateTimeFormatter.ISO_DATE_TIME),
|
||||
converters);
|
||||
}
|
||||
}
|
||||
|
||||
public static class LocalExamplePlugin {
|
||||
|
||||
/// <summary>
|
||||
/// Example of using a void function with no input
|
||||
/// </summary>
|
||||
@DefineKernelFunction(name = "NoInputWithVoidResult", returnType = "void")
|
||||
public void NoInputWithVoidResult() {
|
||||
System.out.println("Running this.NoInputWithVoidResult) -> No input");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Example of using a void task function with no input
|
||||
/// </summary>
|
||||
@DefineKernelFunction(name = "NoInputTaskWithVoidResult", returnType = "java.lang.Void")
|
||||
public Mono<Void> NoInputTaskWithVoidResult() {
|
||||
return Mono.fromRunnable(
|
||||
() -> System.out.println("Running this.NoInputTaskWithVoidResult) -> No input"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Example of using a function with a DateTime input and a string result
|
||||
/// </summary>
|
||||
@DefineKernelFunction(name = "InputDateTimeWithStringResult", returnType = "java.lang.String")
|
||||
public String InputDateTimeWithStringResult(
|
||||
@KernelFunctionParameter(name = "currentDate", description = "Current date time", type = ZonedDateTime.class) ZonedDateTime currentDate) {
|
||||
var result = currentDate.format(DateTimeFormatter.ISO_DATE_TIME);
|
||||
System.out.println(
|
||||
"Running {nameof(this.InputDateTimeWithStringResult)} -> [currentDate = {"
|
||||
+ currentDate + "}] -> result: {" + result + "}");
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Example of using a Task function with no input and a string result
|
||||
/// </summary>
|
||||
@DefineKernelFunction(name = "NoInputTaskWithStringResult", returnType = "java.lang.String")
|
||||
public Mono<String> NoInputTaskWithStringResult() {
|
||||
return Mono.fromCallable(() -> {
|
||||
var result = "string result";
|
||||
System.out.println(
|
||||
"Running {nameof(this.NoInputTaskWithStringResult)} -> No input -> result: {"
|
||||
+ result + "}");
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Example passing multiple parameters with multiple types
|
||||
/// </summary>
|
||||
@DefineKernelFunction(name = "MultipleInputsWithVoidResult")
|
||||
public void MultipleInputsWithVoidResult(
|
||||
@KernelFunctionParameter(name = "x") String x,
|
||||
|
||||
@KernelFunctionParameter(name = "y", type = int.class) int y,
|
||||
|
||||
@KernelFunctionParameter(name = "z", type = double.class) double z) {
|
||||
System.out.println(
|
||||
"Running {nameof(this.MultipleInputsWithVoidResult)} -> input: [x = {" + x
|
||||
+ "}, y = {" + y + "}, z = {" + z + "}]");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Example passing a complex object and returning a string result
|
||||
/// </summary>
|
||||
@DefineKernelFunction(name = "ComplexInputWithStringResult")
|
||||
public String ComplexInputWithStringResult(
|
||||
@KernelFunctionParameter(name = "complexObject", type = Object.class) Object complexObject) {
|
||||
String result = complexObject.toString();
|
||||
System.out.println(
|
||||
"Running {nameof(this.ComplexInputWithStringResult)} -> input: [complexObject = "
|
||||
+ complexObject + "] -> result: {"
|
||||
+ result + "}");
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Example using an async task function echoing the input
|
||||
/// </summary>
|
||||
@DefineKernelFunction(name = "InputStringTaskWithStringResult", returnType = "java.lang.String")
|
||||
public Mono<String> InputStringTaskWithStringResult(
|
||||
|
||||
@KernelFunctionParameter(name = "echoInput") String echoInput) {
|
||||
return Mono.fromCallable(() -> {
|
||||
System.out.println(
|
||||
"Running {nameof(this.InputStringTaskWithStringResult)} -> input: [echoInput = "
|
||||
+ echoInput + "] -> result: {"
|
||||
+ echoInput + "}");
|
||||
return echoInput;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Example using an async void task with string input
|
||||
/// </summary>
|
||||
@DefineKernelFunction(name = "InputStringTaskWithVoidResult", returnType = "java.lang.Void")
|
||||
public Mono<Void> InputStringTaskWithVoidResult(
|
||||
@KernelFunctionParameter(name = "x") String x) {
|
||||
return Mono.fromRunnable(() -> {
|
||||
System.out.println(
|
||||
"Running {nameof(this.InputStringTaskWithVoidResult)} -> input: [x = {" + x
|
||||
+ "}]");
|
||||
});
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "noInputComplexReturnTypeAsync", returnType = "java.time.temporal.Temporal")
|
||||
public Mono<OffsetDateTime> noInputComplexReturnTypeAsync() {
|
||||
return Mono.just(
|
||||
OffsetDateTime.of(1, 1, 1, 1, 1, 1, 1, ZoneOffset.UTC));
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "noInputComplexReturnType", returnType = "java.time.temporal.Temporal")
|
||||
public OffsetDateTime noInputComplexReturnType() {
|
||||
return OffsetDateTime.of(1, 1, 1, 1, 1, 1, 1, ZoneOffset.UTC);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "withDefaultValue", returnType = "java.lang.String")
|
||||
public String withDefaultValue(
|
||||
@KernelFunctionParameter(name = "x", defaultValue = "1", type = int.class) int x) {
|
||||
return Integer.toString(x);
|
||||
}
|
||||
|
||||
// Possibilities for return type combinations:
|
||||
// | Method return type | Declared Function Return Type |
|
||||
// |--------------------|-------------------------------|
|
||||
// | T | T |
|
||||
// | T | U extends T |
|
||||
@DefineKernelFunction(name = "conversionScenarioA", returnType = "java.time.OffsetDateTime")
|
||||
public OffsetDateTime conversionScenarioA() {
|
||||
return OffsetDateTime.of(1, 1, 1, 1, 1, 1, 1, ZoneOffset.UTC);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "conversionScenarioB", returnType = "java.time.temporal.Temporal")
|
||||
public OffsetDateTime conversionScenarioB() {
|
||||
return OffsetDateTime.of(1, 1, 1, 1, 1, 1, 1, ZoneOffset.UTC);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "MultipleComplexInputsWithVoidResult")
|
||||
public void MultipleComplexInputsWithVoidResult(
|
||||
@KernelFunctionParameter(name = "x", type = ZonedDateTime.class) ZonedDateTime x,
|
||||
|
||||
@KernelFunctionParameter(name = "y", type = ZonedDateTime.class) ZonedDateTime y) {
|
||||
System.out.println(
|
||||
"Running {nameof(this.MultipleComplexInputsWithVoidResult)} -> input: [x = {" + x
|
||||
+ "}, y = {" + y + "}]");
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "WithPrimitiveReturnType", returnType = "int")
|
||||
public int WithPrimitiveReturnType() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "WithBoxedPrimitiveReturnType", returnType = "int")
|
||||
public Integer WithBoxedPrimitiveReturnType() {
|
||||
return Integer.valueOf(1);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "AsyncWithBoxedPrimitiveReturnType", returnType = "int")
|
||||
public Mono<Integer> AsyncWithBoxedPrimitiveReturnType() {
|
||||
return Mono.just(Integer.valueOf(1));
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "WithEmptyListReturn")
|
||||
public List<Integer> WithEmptyListReturn() {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "WithListReturn")
|
||||
public List<Integer> WithListReturn() {
|
||||
return List.of(1, 2, 3);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "WithListReturn2", returnType = "java.util.List")
|
||||
public List<Integer> WithListReturn2() {
|
||||
return List.of(1, 2, 3);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "WithListReturn3", returnType = "java.util.List")
|
||||
public Mono<List<Integer>> WithListReturn3() {
|
||||
return Mono.just(List.of(1, 2, 3));
|
||||
}
|
||||
|
||||
/*
|
||||
* /// <summary>
|
||||
* /// Example using a function to return the result of another inner function
|
||||
* /// </summary>
|
||||
*
|
||||
* @DefineKernelFunction(name = "InputStringTaskWithVoidResult")
|
||||
* public FunctionResult NoInputWithFunctionResult()
|
||||
* {
|
||||
* var myInternalFunction = KernelFunctionFactory.CreateFromMethod(() => { });
|
||||
* var result = new FunctionResult(myInternalFunction);
|
||||
* Console.WriteLine(
|
||||
* $"Running {nameof(this.NoInputWithFunctionResult)} -> No input -> result: {result.GetType().Name}"
|
||||
* );
|
||||
* return result;
|
||||
* }
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* /// <summary>
|
||||
* /// Example using a task function to return the result of another kernel function
|
||||
* /// </summary>
|
||||
* [KernelFunction]
|
||||
* public async Task<FunctionResult> NoInputTaskWithFunctionResult(Kernel kernel)
|
||||
* {
|
||||
* var result = await
|
||||
* kernel.InvokeAsync(kernel.Plugins["Examples"][nameof(this.NoInputWithVoidResult)]);
|
||||
* Console.WriteLine(
|
||||
* $"Running {nameof(this.NoInputTaskWithFunctionResult)} -> Injected kernel -> result: {result.GetType().Name}"
|
||||
* );
|
||||
* return result;
|
||||
* }
|
||||
*
|
||||
* /// <summary>
|
||||
* /// Example how to inject Kernel in your function
|
||||
* /// This example uses the injected kernel to invoke a plugin from within another function
|
||||
* /// </summary>
|
||||
* [KernelFunction]
|
||||
* public async Task<string> TaskInjectingKernelWithInputTextAndStringResult(Kernel kernel,
|
||||
* string textToSummarize)
|
||||
* {
|
||||
* var summary = await
|
||||
* kernel.InvokeAsync<string>(kernel.Plugins["SummarizePlugin"]["Summarize"], new() {
|
||||
* ["input"] = textToSummarize });
|
||||
* Console.WriteLine(
|
||||
* $"Running {nameof(this.TaskInjectingKernelWithInputTextAndStringResult)} -> Injected kernel + input: [textToSummarize: {textToSummarize[..15]}...{textToSummarize[^15..]}] -> result: {summary}"
|
||||
* );
|
||||
* return summary!;
|
||||
* }
|
||||
*
|
||||
* /// <summary>
|
||||
* /// Example how to inject the executing KernelFunction as a parameter
|
||||
* /// </summary>
|
||||
* [KernelFunction, Description("Example function injecting itself as a parameter")]
|
||||
* public async Task<string> TaskInjectingKernelFunctionWithStringResult(KernelFunction
|
||||
* executingFunction)
|
||||
* {
|
||||
* var result =
|
||||
* $"Name: {executingFunction.Name}, Description: {executingFunction.Description}";
|
||||
* Console.WriteLine(
|
||||
* $"Running {nameof(this.TaskInjectingKernelWithInputTextAndStringResult)} -> Injected Function -> result: {result}"
|
||||
* );
|
||||
* return result;
|
||||
* }
|
||||
*
|
||||
* /// <summary>
|
||||
* /// Example how to inject ILogger in your function
|
||||
* /// </summary>
|
||||
* [KernelFunction]
|
||||
* public Task TaskInjectingLoggerWithNoResult(ILogger logger)
|
||||
* {
|
||||
* logger.LogWarning("Running {FunctionName} -> Injected Logger",
|
||||
* nameof(this.TaskInjectingLoggerWithNoResult));
|
||||
* Console.WriteLine(
|
||||
* $"Running {nameof(this.TaskInjectingKernelWithInputTextAndStringResult)} -> Injected Logger"
|
||||
* );
|
||||
* return Task.CompletedTask;
|
||||
* }
|
||||
*
|
||||
* /// <summary>
|
||||
* /// Example how to inject ILoggerFactory in your function
|
||||
* /// </summary>
|
||||
* [KernelFunction]
|
||||
* public Task TaskInjectingLoggerFactoryWithNoResult(ILoggerFactory loggerFactory)
|
||||
* {
|
||||
* loggerFactory
|
||||
* .CreateLogger<LocalExamplePlugin>()
|
||||
* .LogWarning("Running {FunctionName} -> Injected Logger",
|
||||
* nameof(this.TaskInjectingLoggerWithNoResult));
|
||||
*
|
||||
* Console.WriteLine(
|
||||
* $"Running {nameof(this.TaskInjectingKernelWithInputTextAndStringResult)} -> Injected Logger"
|
||||
* );
|
||||
* return Task.CompletedTask;
|
||||
* }
|
||||
*
|
||||
* /// <summary>
|
||||
* /// Example how to inject a service selector in your function and use a specific service
|
||||
* /// </summary>
|
||||
* [KernelFunction]
|
||||
* public async Task<string> TaskInjectingServiceSelectorWithStringResult(Kernel kernel,
|
||||
* KernelFunction function, KernelArguments arguments, IAIServiceSelector serviceSelector)
|
||||
* {
|
||||
* ChatMessageContent? chatMessageContent = null;
|
||||
* if (serviceSelector.TrySelectAIService<IChatCompletionService>(kernel, function,
|
||||
* arguments, out var chatCompletion, out var executionSettings))
|
||||
* {
|
||||
* chatMessageContent = await chatCompletion.GetChatMessageContentAsync(new
|
||||
* ChatHistory("How much is 5 + 5 ?"), executionSettings);
|
||||
* }
|
||||
*
|
||||
* var result = chatMessageContent?.Content;
|
||||
* Console.WriteLine(
|
||||
* $"Running {nameof(this.TaskInjectingKernelWithInputTextAndStringResult)} -> Injected Kernel, KernelFunction, KernelArguments, Service Selector -> result: {result}"
|
||||
* );
|
||||
* return result ?? string.Empty;
|
||||
* }
|
||||
*
|
||||
* /// <summary>
|
||||
* /// Example how to inject CultureInfo or IFormatProvider in your function
|
||||
* /// </summary>
|
||||
* public async Task<string>
|
||||
* TaskInjectingCultureInfoOrIFormatProviderWithStringResult(CultureInfo cultureInfo,
|
||||
* IFormatProvider formatProvider)
|
||||
* {
|
||||
* var result =
|
||||
* $"Culture Name: {cultureInfo.Name}, FormatProvider Equals CultureInfo?: {formatProvider.Equals(cultureInfo)}"
|
||||
* ;
|
||||
* Console.WriteLine(
|
||||
* $"Running {nameof(this.TaskInjectingCultureInfoOrIFormatProviderWithStringResult)} -> Injected CultureInfo, IFormatProvider -> result: {result}"
|
||||
* );
|
||||
* return result;
|
||||
* }
|
||||
*
|
||||
* /// <summary>
|
||||
* /// Example how to inject current CancellationToken in your function
|
||||
* /// </summary>
|
||||
* [KernelFunction]
|
||||
* public async Task<string>
|
||||
* TaskInjectingCancellationTokenWithStringResult(CancellationToken cancellationToken)
|
||||
* {
|
||||
* var result = $"Cancellation resquested: {cancellationToken.IsCancellationRequested}";
|
||||
* Console.WriteLine(
|
||||
* $"Running {nameof(this.TaskInjectingCultureInfoOrIFormatProviderWithStringResult)} -> Injected Cancellation Token -> result: {result}"
|
||||
* );
|
||||
* return result;
|
||||
* }
|
||||
*
|
||||
* public override string ToString()
|
||||
* {
|
||||
* return "Complex type result ToString override";
|
||||
* }
|
||||
*
|
||||
*/
|
||||
}
|
||||
}
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.syntaxexamples.functions;
|
||||
|
||||
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.Kernel;
|
||||
import com.microsoft.semantickernel.contextvariables.ContextVariableTypes;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
|
||||
|
||||
public class Example27_PromptFunctionsUsingChatGPT {
|
||||
|
||||
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) {
|
||||
|
||||
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();
|
||||
}
|
||||
System.out.println("======== Using Chat GPT model for text generation ========");
|
||||
|
||||
ChatCompletionService openAIChatCompletion = ChatCompletionService.builder()
|
||||
.withOpenAIAsyncClient(client)
|
||||
.withModelId(MODEL_ID)
|
||||
.build();
|
||||
|
||||
Kernel kernel = Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class, openAIChatCompletion)
|
||||
.build();
|
||||
|
||||
var func = KernelFunction.<String>createFromPrompt(
|
||||
"List the two planets closest to '{{$input}}', excluding moons, using bullet points.")
|
||||
.build();
|
||||
|
||||
var result = func.invokeAsync(kernel)
|
||||
.withArguments(
|
||||
KernelFunctionArguments.builder()
|
||||
.withVariable("input", "Jupiter")
|
||||
.build())
|
||||
.withResultType(ContextVariableTypes.getGlobalVariableTypeForClass(String.class))
|
||||
.block();
|
||||
System.out.println(result.getResult());
|
||||
|
||||
}
|
||||
}
|
||||
-272
@@ -1,272 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.syntaxexamples.functions;
|
||||
|
||||
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.Kernel;
|
||||
import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion;
|
||||
import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatMessageContent;
|
||||
import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIFunctionToolCall;
|
||||
import com.microsoft.semantickernel.contextvariables.ContextVariableTypes;
|
||||
import com.microsoft.semantickernel.implementation.CollectionUtil;
|
||||
import com.microsoft.semantickernel.orchestration.FunctionResult;
|
||||
import com.microsoft.semantickernel.orchestration.FunctionResultMetadata;
|
||||
import com.microsoft.semantickernel.orchestration.InvocationContext;
|
||||
import com.microsoft.semantickernel.orchestration.InvocationReturnMode;
|
||||
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
|
||||
import com.microsoft.semantickernel.orchestration.ToolCallBehavior;
|
||||
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.AuthorRole;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatHistory;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
|
||||
public class Example59_OpenAIFunctionCalling {
|
||||
|
||||
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-2");
|
||||
|
||||
// Define functions that can be called by the model
|
||||
public static class HelperFunctions {
|
||||
|
||||
@DefineKernelFunction(name = "currentUtcTime", description = "Retrieves the current time in UTC.")
|
||||
public String currentUtcTime() {
|
||||
return ZonedDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "getWeatherForCity", description = "Gets the current weather for the specified city")
|
||||
public String getWeatherForCity(
|
||||
@KernelFunctionParameter(name = "cityName", description = "Name of the city") String cityName) {
|
||||
switch (cityName) {
|
||||
case "Thrapston":
|
||||
return "80 and sunny";
|
||||
case "Boston":
|
||||
return "61 and rainy";
|
||||
case "London":
|
||||
return "55 and cloudy";
|
||||
case "Miami":
|
||||
return "80 and sunny";
|
||||
case "Paris":
|
||||
return "60 and rainy";
|
||||
case "Tokyo":
|
||||
return "50 and sunny";
|
||||
case "Sydney":
|
||||
return "75 and sunny";
|
||||
case "Tel Aviv":
|
||||
return "80 and sunny";
|
||||
default:
|
||||
return "31 and snowing";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws NoSuchMethodException {
|
||||
System.out.println("======== Open AI - Function calling ========");
|
||||
|
||||
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 chat = OpenAIChatCompletion.builder()
|
||||
.withModelId(MODEL_ID)
|
||||
.withOpenAIAsyncClient(client)
|
||||
.build();
|
||||
|
||||
var plugin = KernelPluginFactory.createFromObject(new HelperFunctions(), "HelperFunctions");
|
||||
|
||||
var kernel = Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class, chat)
|
||||
.withPlugin(plugin)
|
||||
.build();
|
||||
|
||||
System.out.println("======== Example 1: Use automated function calling ========");
|
||||
|
||||
var function = KernelFunctionFromPrompt.builder()
|
||||
.withTemplate(
|
||||
"Given the current time of day and weather, what is the likely color of the sky in Boston?")
|
||||
.withDefaultExecutionSettings(
|
||||
PromptExecutionSettings.builder()
|
||||
.withTemperature(0.4)
|
||||
.withTopP(1)
|
||||
.withMaxTokens(100)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
var result = kernel
|
||||
.invokeAsync(function)
|
||||
.withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true))
|
||||
.withResultType(ContextVariableTypes.getGlobalVariableTypeForClass(String.class))
|
||||
.block();
|
||||
System.out.println(result.getResult());
|
||||
|
||||
System.out.println("======== Example 2: Use manual function calling ========");
|
||||
|
||||
var chatHistory = new ChatHistory();
|
||||
chatHistory.addUserMessage(
|
||||
"Given the current time of day and weather, what is the likely color of the sky in Boston?");
|
||||
|
||||
while (true) {
|
||||
var messages = chat.getChatMessageContentsAsync(
|
||||
chatHistory,
|
||||
kernel,
|
||||
InvocationContext.builder()
|
||||
.withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(false))
|
||||
.withReturnMode(InvocationReturnMode.FULL_HISTORY)
|
||||
.build())
|
||||
.block();
|
||||
|
||||
chatHistory = new ChatHistory(messages);
|
||||
|
||||
ChatMessageContent<?> lastMessage = CollectionUtil.getLastOrNull(messages);
|
||||
|
||||
List<OpenAIFunctionToolCall> toolCalls = null;
|
||||
|
||||
if (lastMessage instanceof OpenAIChatMessageContent) {
|
||||
toolCalls = ((OpenAIChatMessageContent<?>) lastMessage).getToolCall();
|
||||
}
|
||||
|
||||
if (toolCalls == null || toolCalls.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (OpenAIFunctionToolCall toolCall : toolCalls) {
|
||||
String content;
|
||||
try {
|
||||
// getFunction will throw an exception if the function is not found
|
||||
var fn = kernel.getFunction(toolCall.getPluginName(),
|
||||
toolCall.getFunctionName());
|
||||
FunctionResult<?> fnResult = fn
|
||||
.invokeAsync(kernel, toolCall.getArguments(), null, null).block();
|
||||
content = (String) fnResult.getResult();
|
||||
} catch (IllegalArgumentException e) {
|
||||
content = "Unable to find function. Please try again!";
|
||||
}
|
||||
|
||||
chatHistory.addMessage(
|
||||
AuthorRole.TOOL,
|
||||
content,
|
||||
StandardCharsets.UTF_8,
|
||||
FunctionResultMetadata.build(toolCall.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
chatHistory.getMessages().stream()
|
||||
.filter(it -> it.getContent() != null)
|
||||
.forEach(it -> System.out.println(it.getContent()));
|
||||
|
||||
multiTurnaroundCall();
|
||||
}
|
||||
|
||||
public static class PetPlugin {
|
||||
|
||||
@DefineKernelFunction(name = "getPetName", description = "Retrieves the pet for a given ID.")
|
||||
public String getPetName(
|
||||
@KernelFunctionParameter(name = "petId", description = "The pets id") String id) {
|
||||
if (id.equals("ca2fc6bc-1307-4da6-a009-d7bf88dec37b")) {
|
||||
return "Snuggles";
|
||||
}
|
||||
|
||||
throw new RuntimeException("Pet not found");
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "getPetType", description = "Retrieves the type of pet for a given ID.")
|
||||
public String getPetType(
|
||||
@KernelFunctionParameter(name = "petId", description = "The pets id") String id) {
|
||||
if (id.equals("ca2fc6bc-1307-4da6-a009-d7bf88dec37b")) {
|
||||
return "cat";
|
||||
}
|
||||
|
||||
throw new RuntimeException("Pet not found");
|
||||
}
|
||||
}
|
||||
|
||||
public static void multiTurnaroundCall() {
|
||||
System.out.println("======== Open AI - Function calling ========");
|
||||
|
||||
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 chat = OpenAIChatCompletion.builder()
|
||||
.withModelId(MODEL_ID)
|
||||
.withOpenAIAsyncClient(client)
|
||||
.build();
|
||||
|
||||
var plugin = KernelPluginFactory.createFromObject(new PetPlugin(), "PetPlugin");
|
||||
|
||||
var kernel = Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class, chat)
|
||||
.withPlugin(plugin)
|
||||
.build();
|
||||
|
||||
System.out.println("======== Example 3: Multiple auto function calling ========");
|
||||
|
||||
var chatHistory = new ChatHistory();
|
||||
chatHistory.addUserMessage(
|
||||
"What is the name of the pet with id ca2fc6bc-1307-4da6-a009-d7bf88dec37b?");
|
||||
|
||||
var messages = chat.getChatMessageContentsAsync(
|
||||
chatHistory,
|
||||
kernel,
|
||||
InvocationContext.builder()
|
||||
.withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true))
|
||||
.withReturnMode(InvocationReturnMode.FULL_HISTORY)
|
||||
.build())
|
||||
.block();
|
||||
|
||||
chatHistory = new ChatHistory(messages);
|
||||
|
||||
System.out.println(chatHistory.getLastMessage().get().getContent());
|
||||
|
||||
chatHistory.addMessage(AuthorRole.USER, "What type of animal are they?");
|
||||
|
||||
messages = chat.getChatMessageContentsAsync(
|
||||
chatHistory,
|
||||
kernel,
|
||||
InvocationContext.builder()
|
||||
.withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true))
|
||||
.withReturnMode(InvocationReturnMode.FULL_HISTORY)
|
||||
.build())
|
||||
.block();
|
||||
|
||||
chatHistory = new ChatHistory(messages);
|
||||
|
||||
System.out.println(chatHistory.getLastMessage().get().getContent());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user