mirror of
https://github.com/microsoft/semantic-kernel.git
synced 2026-10-12 02:19:06 +00:00
Initial proposal for Java Kernel (#1081)
### 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 SK Contribution Guidelines (https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) - [ ] The code follows the .NET coding conventions (https://learn.microsoft.com/dotnet/csharp/fundamentals/coding-style/coding-conventions) verified with `dotnet format` - [ ] All unit tests pass, and I have added new tests where possible - [ ] I didn't break anyone 😄 --------- Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Milder Hernandez Cagua <[email protected]> Co-authored-by: Milder Hernandez <[email protected]> Co-authored-by: Yoshio Terada <[email protected]> Co-authored-by: Mark Wallace <[email protected]> Co-authored-by: name <email> Co-authored-by: Almir Kazazic <[email protected]> Co-authored-by: Gudge <[email protected]> Co-authored-by: Devis Lucato <[email protected]> Co-authored-by: Alexander Siniouguine <[email protected]> Co-authored-by: Harleen Thind <[email protected]> Co-authored-by: David Barkol <[email protected]> Co-authored-by: Adrian Bonar <[email protected]> Co-authored-by: Mark Karle <[email protected]> Co-authored-by: poweihuang0817 <[email protected]> Co-authored-by: Po-Wei Huang <[email protected]> Co-authored-by: Lee Miller <[email protected]> Co-authored-by: Ikko Eltociear Ashimine <[email protected]> Co-authored-by: Adrian Bonar (HE/HIM) <[email protected]> Co-authored-by: Tao Chen <[email protected]> Co-authored-by: Teresa Hoang <[email protected]> Co-authored-by: Gil LaHaye <[email protected]> Co-authored-by: Shawn Callegari <[email protected]> Co-authored-by: Vivien Hung <[email protected]> Co-authored-by: Abby Harrison <[email protected]> Co-authored-by: Abby Harrison <[email protected]> Co-authored-by: Devis Lucato <[email protected]> Co-authored-by: Gina Triolo <[email protected]> Co-authored-by: fabio fumarola <[email protected]> Co-authored-by: cdMSFT <[email protected]> Co-authored-by: Dmytro Struk <[email protected]> Co-authored-by: Lex Li <[email protected]> Co-authored-by: Damir Dobric <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Aman Sachan <[email protected]> Co-authored-by: Roger Barreto <[email protected]> Co-authored-by: Stephen Toub <[email protected]> Co-authored-by: Craig Presti <[email protected]> Co-authored-by: Joowon <[email protected]> Co-authored-by: Richard Edgar <[email protected]> Co-authored-by: nacharya1 <[email protected]> Co-authored-by: Kevdome3000 <[email protected]> Co-authored-by: tech <[email protected]> Co-authored-by: Masumi Morishige <[email protected]> Co-authored-by: adityachallapally <[email protected]> Co-authored-by: Jadyn <[email protected]> Co-authored-by: Alex Chao <[email protected]> Co-authored-by: Alex Chao <[email protected]>
This commit is contained in:
committed by
name
co-authored by
Milder Hernandez Cagua
Milder Hernandez
Yoshio Terada
Mark Wallace
name
Almir Kazazic
Gudge
Devis Lucato
Alexander Siniouguine
Harleen Thind
David Barkol
Adrian Bonar
Mark Karle
poweihuang0817
Po-Wei Huang
Lee Miller
Ikko Eltociear Ashimine
Adrian Bonar
Tao Chen
Teresa Hoang
Gil LaHaye
Shawn Callegari
Vivien Hung
Abby Harrison
Abby Harrison
Devis Lucato
Gina Triolo
fabio fumarola
cdMSFT
Dmytro Struk
Lex Li
Damir Dobric
dependabot[bot]
Aman Sachan
Roger Barreto
Stephen Toub
Craig Presti
Joowon
Richard Edgar
nacharya1
Kevdome3000
tech
Masumi Morishige
adityachallapally
Jadyn
Alex Chao
Alex Chao
parent
39c7a08520
commit
7c18866cc2
@@ -0,0 +1,10 @@
|
||||
--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
@@ -0,0 +1,18 @@
|
||||
# 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.1/apache-maven-3.9.1-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
# Semantic Kernel for Java
|
||||
|
||||
Semantic Kernel (SK) is a lightweight SDK 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.
|
||||
|
||||
To learn more about Microsoft Semantic Kernel, visit
|
||||
the [Microsoft Semantic Kernel documentation](https://learn.microsoft.com/en-us/semantic-kernel/whatissk).
|
||||
|
||||
The Semantic Kernel for Java is an SDK that implements the key concepts of the Semantic Kernel in Java. It is designed
|
||||
to be used in Java applications and services in an idiomatic way, and to be easily integrated with other Java libraries
|
||||
and frameworks.
|
||||
|
||||
## Get Started
|
||||
|
||||
To run the LLM prompts and semantic functions in this kernel, make sure you have
|
||||
an [Open AI API Key](https://openai.com/api/)
|
||||
or [Azure Open AI service key](https://learn.microsoft.com/azure/cognitive-services/openai/quickstart?pivots=rest-api).
|
||||
|
||||
### Requirements
|
||||
|
||||
To build the semantic kernel, you will need to have:
|
||||
|
||||
- **Required**:
|
||||
- [JDK 8](https://microsoft.com/openjdk/) or newer to build the Semantic Kernel library
|
||||
- [JDK 17](https://microsoft.com/openjdk/) or newer to run samples
|
||||
|
||||
### Build the semantic kernel
|
||||
|
||||
1. Clone this repository
|
||||
|
||||
git clone git@github.com:microsoft/semantic-kernel.git
|
||||
|
||||
2. Build the semantic kernel
|
||||
|
||||
cd semantic-kernel/java
|
||||
mvn install
|
||||
|
||||
## Using the semantic kernel
|
||||
|
||||
Check the `samples` folder for examples of how to use the semantic kernel.
|
||||
|
||||
## 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 integration tests that require an OpenAI key to run. To run the integration tests locally, you
|
||||
will need to set the following environment variable:
|
||||
|
||||
- `OPENAI_API_KEY` - the OpenAI API key.
|
||||
|
||||
If you are using Azure OpenAI, you will also need to set the following environment variables:
|
||||
|
||||
- `AZURE_OPENAI_ENDPOINT` - the Azure OpenAI endpoint found in **Keys * Endpoint** section of the Azure OpenAI service.
|
||||
- `AZURE_OPENAI_API_KEY` - the Azure OpoenAI API key found in **Keys * Endpoint** section of the Azure OpenAI service.
|
||||
- `AZURE_OPENAI_DEPLOYMENT_NAME` - 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:
|
||||
|
||||
mvn package
|
||||
|
||||
To run all tests, including integration tests that require an OpenAI key, run the following command:
|
||||
|
||||
mvn verify
|
||||
|
||||
### 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 `main` 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).
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<?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.semantickernel.test</groupId>
|
||||
<artifactId>api-test</artifactId>
|
||||
<version>0.2.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>api-usage-example</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel</groupId>
|
||||
<artifactId>semantickernel-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j2-impl</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,126 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
import com.azure.ai.openai.OpenAIClientBuilder;
|
||||
import com.azure.core.credential.AzureKeyCredential;
|
||||
import com.microsoft.openai.AzureOpenAIClient;
|
||||
import com.microsoft.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.KernelConfig;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Properties;
|
||||
|
||||
public class InlineFunctionExample {
|
||||
public static final String AZURE_CONF_PROPERTIES = "conf.properties";
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(InlineFunctionExample.class);
|
||||
private static final String MODEL = "text-davinci-003";
|
||||
|
||||
public static String getToken(String configName) throws IOException {
|
||||
return getConfigValue(configName, "token");
|
||||
}
|
||||
|
||||
public static String getEndpoint(String configName) throws IOException {
|
||||
return getConfigValue(configName, "endpoint");
|
||||
}
|
||||
|
||||
private static String getConfigValue(String configName, String propertyName)
|
||||
throws IOException {
|
||||
Path configPath = Paths.get(System.getProperty("user.home"), ".oai", configName);
|
||||
Properties props = new Properties();
|
||||
try (var reader = Files.newBufferedReader(configPath)) {
|
||||
props.load(reader);
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Failed to read config file: " + configPath);
|
||||
throw e;
|
||||
}
|
||||
String apiKey = props.getProperty(propertyName);
|
||||
if (apiKey == null) {
|
||||
LOGGER.error("NO PROPERTY " + propertyName);
|
||||
return "";
|
||||
}
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
String apiKey = getToken(AZURE_CONF_PROPERTIES);
|
||||
|
||||
OpenAIAsyncClient client =
|
||||
new AzureOpenAIClient(
|
||||
new OpenAIClientBuilder()
|
||||
.endpoint(getEndpoint(AZURE_CONF_PROPERTIES))
|
||||
.credential(new AzureKeyCredential(apiKey))
|
||||
.buildAsyncClient());
|
||||
|
||||
TextCompletion textCompletion = SKBuilders.textCompletionService().build(client, MODEL);
|
||||
|
||||
KernelConfig kernelConfig =
|
||||
new KernelConfig.Builder()
|
||||
.addTextCompletionService(MODEL, kernel -> textCompletion)
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
|
||||
String prompt = "{{$input}}\n" + "Summarize the content above.";
|
||||
|
||||
CompletionSKFunction summarize =
|
||||
kernel.getSemanticFunctionBuilder()
|
||||
.createFunction(
|
||||
prompt,
|
||||
"summarize",
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0.2, 0.5, 0, 0, 2000, new ArrayList<>()));
|
||||
|
||||
String text =
|
||||
"""
|
||||
Demo (ancient Greek poet)
|
||||
From Wikipedia, the free encyclopedia
|
||||
Demo or Damo (Greek: Δεμώ, Δαμώ; fl. c. AD 200) was a Greek woman of the
|
||||
Roman period, known for a single epigram, engraved upon the Colossus of
|
||||
Memnon, which bears her name. She speaks of herself therein as a lyric
|
||||
poetess dedicated to the Muses, but nothing is known of her life.[1]
|
||||
Identity
|
||||
Demo was evidently Greek, as her name, a traditional epithet of Demeter,
|
||||
signifies. The name was relatively common in the Hellenistic world, in
|
||||
Egypt and elsewhere, and she cannot be further identified. The date of her
|
||||
visit to the Colossus of Memnon cannot be established with certainty, but
|
||||
internal evidence on the left leg suggests her poem was inscribed there at
|
||||
some point in or after AD 196.[2]
|
||||
Epigram
|
||||
There are a number of graffiti inscriptions on the Colossus of Memnon.
|
||||
Following three epigrams by Julia Balbilla, a fourth epigram, in elegiac
|
||||
couplets, entitled and presumably authored by "Demo" or "Damo" (the
|
||||
Greek inscription is difficult to read), is a dedication to the Muses.[2]
|
||||
The poem is traditionally published with the works of Balbilla, though the
|
||||
internal evidence suggests a different author.[1]
|
||||
In the poem, Demo explains that Memnon has shown her special respect. In
|
||||
return, Demo offers the gift for poetry, as a gift to the hero. At the end
|
||||
of this epigram, she addresses Memnon, highlighting his divine status by
|
||||
recalling his strength and holiness.[2]
|
||||
Demo, like Julia Balbilla, writes in the artificial and poetic Aeolic
|
||||
dialect. The language indicates she was knowledgeable in Homeric
|
||||
poetry—'bearing a pleasant gift', for example, alludes to the use of that
|
||||
phrase throughout the Iliad and Odyssey.[a][2];
|
||||
""";
|
||||
|
||||
CompletionSKContext context = summarize.invokeAsync(text).block();
|
||||
|
||||
if (context != null) {
|
||||
LOGGER.info("Result: " + context.getResult());
|
||||
} else {
|
||||
LOGGER.error("Null result");
|
||||
}
|
||||
}
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
import com.azure.ai.openai.OpenAIClientBuilder;
|
||||
import com.azure.core.credential.AzureKeyCredential;
|
||||
import com.microsoft.openai.AzureOpenAIClient;
|
||||
import com.microsoft.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.KernelConfig;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.rmi.RemoteException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Properties;
|
||||
|
||||
public class InlineFunctionWithPreBuiltSkillExample {
|
||||
public static final String AZURE_CONF_PROPERTIES = "conf.properties";
|
||||
|
||||
private static final Logger LOGGER =
|
||||
LoggerFactory.getLogger(InlineFunctionWithPreBuiltSkillExample.class);
|
||||
|
||||
private static final String MODEL = "text-davinci-003";
|
||||
|
||||
private static final String TEXT_TO_SUMMARIZE =
|
||||
"Demo (ancient Greek poet)\n"
|
||||
+ "From Wikipedia, the free encyclopedia\n"
|
||||
+ "Demo or Damo (Greek: Δεμώ, Δαμώ; fl. c. AD 200) was a Greek woman of the"
|
||||
+ " Roman period, known for a single epigram, engraved upon the Colossus of"
|
||||
+ " Memnon, which bears her name. She speaks of herself therein as a lyric"
|
||||
+ " poetess dedicated to the Muses, but nothing is known of her life.[1]\n"
|
||||
+ "Identity\n"
|
||||
+ "Demo was evidently Greek, as her name, a traditional epithet of Demeter,"
|
||||
+ " signifies. The name was relatively common in the Hellenistic world, in"
|
||||
+ " Egypt and elsewhere, and she cannot be further identified. The date of her"
|
||||
+ " visit to the Colossus of Memnon cannot be established with certainty, but"
|
||||
+ " internal evidence on the left leg suggests her poem was inscribed there at"
|
||||
+ " some point in or after AD 196.[2]\n"
|
||||
+ "Epigram\n"
|
||||
+ "There are a number of graffiti inscriptions on the Colossus of Memnon."
|
||||
+ " Following three epigrams by Julia Balbilla, a fourth epigram, in elegiac"
|
||||
+ " couplets, entitled and presumably authored by \"Demo\" or \"Damo\" (the"
|
||||
+ " Greek inscription is difficult to read), is a dedication to the Muses.[2]"
|
||||
+ " The poem is traditionally published with the works of Balbilla, though the"
|
||||
+ " internal evidence suggests a different author.[1]\n"
|
||||
+ "In the poem, Demo explains that Memnon has shown her special respect. In"
|
||||
+ " return, Demo offers the gift for poetry, as a gift to the hero. At the end"
|
||||
+ " of this epigram, she addresses Memnon, highlighting his divine status by"
|
||||
+ " recalling his strength and holiness.[2]\n"
|
||||
+ "Demo, like Julia Balbilla, writes in the artificial and poetic Aeolic"
|
||||
+ " dialect. The language indicates she was knowledgeable in Homeric"
|
||||
+ " poetry—'bearing a pleasant gift', for example, alludes to the use of that"
|
||||
+ " phrase throughout the Iliad and Odyssey.[a][2]\n";
|
||||
|
||||
public static String getToken(String configName) throws IOException {
|
||||
return getConfigValue(configName, "token");
|
||||
}
|
||||
|
||||
public static String getEndpoint(String configName) throws IOException {
|
||||
return getConfigValue(configName, "endpoint");
|
||||
}
|
||||
|
||||
private static String getConfigValue(String configName, String propertyName)
|
||||
throws IOException {
|
||||
String home = new File(System.getProperty("user.home")).getAbsolutePath();
|
||||
|
||||
try (FileInputStream fis = new FileInputStream(home + "/.oai/" + configName)) {
|
||||
Properties props = new Properties();
|
||||
props.load(fis);
|
||||
String apiKey = props.getProperty(propertyName);
|
||||
if (apiKey == null) {
|
||||
System.err.println("NO PROPERTY " + propertyName);
|
||||
return "";
|
||||
}
|
||||
return apiKey;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
String apiKey = getToken(AZURE_CONF_PROPERTIES);
|
||||
|
||||
OpenAIAsyncClient client =
|
||||
new AzureOpenAIClient(
|
||||
new OpenAIClientBuilder()
|
||||
.endpoint(getEndpoint(AZURE_CONF_PROPERTIES))
|
||||
.credential(new AzureKeyCredential(apiKey))
|
||||
.buildAsyncClient());
|
||||
|
||||
TextCompletion textCompletion = SKBuilders.textCompletionService().build(client, MODEL);
|
||||
|
||||
String prompt = "{{$input}}\nSummarize the content above.";
|
||||
|
||||
CompletionSKFunction summarizeFunc =
|
||||
SKBuilders.completionFunctions()
|
||||
.createFunction(
|
||||
prompt,
|
||||
"summarize",
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0.2, 0.5, 0, 0, 2000, new ArrayList<>()));
|
||||
|
||||
KernelConfig kernelConfig =
|
||||
new KernelConfig.Builder()
|
||||
.addTextCompletionService(MODEL, kernel -> textCompletion)
|
||||
.addSkill(summarizeFunc)
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
|
||||
CompletionSKFunction summarize =
|
||||
kernel.getSkills().getFunction("summarize", CompletionSKFunction.class);
|
||||
|
||||
if (summarize == null) {
|
||||
throw new RemoteException("No function");
|
||||
}
|
||||
|
||||
CompletionSKContext context = summarize.invokeAsync(TEXT_TO_SUMMARIZE).block();
|
||||
|
||||
if (context != null) {
|
||||
LOGGER.info("Result: " + context.getResult());
|
||||
} else {
|
||||
LOGGER.error("Null result");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?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="info">
|
||||
<AppenderRef ref="Console"/>
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
||||
@@ -0,0 +1,70 @@
|
||||
<?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.semantickernel.test</groupId>
|
||||
<artifactId>api-test</artifactId>
|
||||
<version>0.2.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>integration-tests</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel</groupId>
|
||||
<artifactId>semantickernel-core</artifactId>
|
||||
</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.semantickernel.connectors</groupId>
|
||||
<artifactId>semantickernel-connectors</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel.extensions</groupId>
|
||||
<artifactId>sequentialplanner-extensions</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel</groupId>
|
||||
<artifactId>semantickernel-core-skills</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.e2e;
|
||||
|
||||
import com.azure.ai.openai.OpenAIClientBuilder;
|
||||
import com.azure.core.credential.AzureKeyCredential;
|
||||
import com.microsoft.openai.AzureOpenAIClient;
|
||||
import com.microsoft.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.KernelConfig;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.connectors.ai.openai.textcompletion.OpenAITextCompletion;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
@EnabledIf("isAzureTestEnabled")
|
||||
public class AbstractKernelTest {
|
||||
|
||||
public static final String CONF_OPENAI_PROPERTIES = "conf.openai.properties";
|
||||
public static final String AZURE_CONF_PROPERTIES = "conf.properties";
|
||||
|
||||
public static Kernel buildTextCompletionKernel() throws IOException {
|
||||
String model = "text-davinci-003";
|
||||
TextCompletion textCompletion = new OpenAITextCompletion(getAzureOpenAIClient(), model);
|
||||
|
||||
KernelConfig kernelConfig =
|
||||
SKBuilders.kernelConfig()
|
||||
.addTextCompletionService(model, kernel -> textCompletion)
|
||||
.build();
|
||||
|
||||
return SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
}
|
||||
|
||||
public static OpenAIAsyncClient getOpenAIClient() throws IOException {
|
||||
String apiKey = getToken(CONF_OPENAI_PROPERTIES);
|
||||
return new com.microsoft.openai.OpenAIClientBuilder().setApiKey(apiKey).build();
|
||||
}
|
||||
|
||||
public static OpenAIAsyncClient getAzureOpenAIClient() throws IOException {
|
||||
String apiKey = getToken(AZURE_CONF_PROPERTIES);
|
||||
|
||||
com.azure.ai.openai.OpenAIAsyncClient client =
|
||||
new OpenAIClientBuilder()
|
||||
.endpoint(getEndpoint(AZURE_CONF_PROPERTIES))
|
||||
.credential(new AzureKeyCredential(apiKey))
|
||||
.buildAsyncClient();
|
||||
|
||||
return new AzureOpenAIClient(client);
|
||||
}
|
||||
|
||||
public static String getAzureModel() throws IOException {
|
||||
return getConfigValue(AZURE_CONF_PROPERTIES, "model");
|
||||
}
|
||||
|
||||
public static String getOpenAIModel() throws IOException {
|
||||
return getConfigValue(CONF_OPENAI_PROPERTIES, "model");
|
||||
}
|
||||
|
||||
public static String getModel(String configName) throws IOException {
|
||||
return getConfigValue(configName, "model");
|
||||
}
|
||||
|
||||
public static String getToken(String configName) throws IOException {
|
||||
return getConfigValue(configName, "token");
|
||||
}
|
||||
|
||||
public static String getEndpoint(String configName) throws IOException {
|
||||
return getConfigValue(configName, "endpoint");
|
||||
}
|
||||
|
||||
private static String getConfigValue(String configName, String propertyName)
|
||||
throws IOException {
|
||||
String home = new File(System.getProperty("user.home")).getAbsolutePath();
|
||||
|
||||
try (FileInputStream fis = new FileInputStream(home + "/.oai/" + configName)) {
|
||||
Properties props = new Properties();
|
||||
props.load(fis);
|
||||
String apiKey = props.getProperty(propertyName);
|
||||
if (apiKey == null) {
|
||||
System.err.println("NO PROPERTY " + propertyName);
|
||||
return "";
|
||||
}
|
||||
return apiKey;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isOpenAIComTestEnabled() {
|
||||
return checkConfig(AbstractKernelTest.CONF_OPENAI_PROPERTIES);
|
||||
}
|
||||
|
||||
public static boolean isAzureTestEnabled() {
|
||||
return checkConfig(AbstractKernelTest.AZURE_CONF_PROPERTIES);
|
||||
}
|
||||
|
||||
private static boolean checkConfig(String confOpenaiProperties) {
|
||||
if (!Boolean.getBoolean("enable_external_tests")
|
||||
&& !System.getProperties().containsKey("intellij.debug.agent")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
if (AbstractKernelTest.getEndpoint(confOpenaiProperties) == null) {
|
||||
System.out.println("Test disabled due to lack of configured azure endpoint");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (AbstractKernelTest.getToken(confOpenaiProperties) == null) {
|
||||
System.out.println("Test disabled due to lack of configured azure token");
|
||||
return false;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.e2e;
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class ContextVariableFunctionTest extends AbstractKernelTest {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ContextVariableFunctionTest.class);
|
||||
|
||||
public static void main(String[] args)
|
||||
throws IOException, ExecutionException, InterruptedException, TimeoutException {
|
||||
new ContextVariableFunctionTest().runContextVariableTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledIf("isAzureTestEnabled")
|
||||
public void runContextVariableTest()
|
||||
throws IOException, ExecutionException, InterruptedException, TimeoutException {
|
||||
Kernel kernel = buildTextCompletionKernel();
|
||||
|
||||
String prompt =
|
||||
"\n"
|
||||
+ "ChatBot can have a conversation with you about any topic.\n"
|
||||
+ "It can give explicit instructions or say 'I don't know' if it does not have"
|
||||
+ " an answer.\n"
|
||||
+ "\n"
|
||||
+ "{{$history}}\n"
|
||||
+ "User: {{$user_input}}\n"
|
||||
+ "ChatBot: ";
|
||||
|
||||
CompletionSKFunction chat =
|
||||
kernel.getSemanticFunctionBuilder()
|
||||
.createFunction(
|
||||
prompt,
|
||||
"ChatBot",
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0.7, 0.5, 0, 0, 2000, new ArrayList<>()));
|
||||
|
||||
CompletionSKContext readOnlySkContext = chat.buildContext();
|
||||
|
||||
chat("Hi, I'm looking for book suggestions?", chat, readOnlySkContext)
|
||||
.flatMap(
|
||||
chat(
|
||||
"I love history and philosophy, I'd like to learn something new"
|
||||
+ " about Greece, any suggestion?",
|
||||
chat))
|
||||
.flatMap(chat("that sounds interesting, what is it about?", chat))
|
||||
.flatMap(
|
||||
chat(
|
||||
"if I read that book, what exactly will I learn about Greece"
|
||||
+ " history?",
|
||||
chat))
|
||||
.flatMap(
|
||||
chat("could you list some more books I could read about this topic?", chat))
|
||||
.block();
|
||||
}
|
||||
|
||||
private Function<CompletionSKContext, Mono<CompletionSKContext>> chat(
|
||||
String input, CompletionSKFunction chat) {
|
||||
return (context) -> {
|
||||
try {
|
||||
return chat(input, chat, context);
|
||||
} catch (ExecutionException | InterruptedException | TimeoutException e) {
|
||||
return Mono.error(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Mono<CompletionSKContext> chat(
|
||||
String input, CompletionSKFunction chat, CompletionSKContext context)
|
||||
throws ExecutionException, InterruptedException, TimeoutException {
|
||||
context = context.setVariable("user_input", input);
|
||||
|
||||
LOGGER.info("User:\n" + input);
|
||||
|
||||
CompletionSKContext finalContext = context;
|
||||
return chat.invokeAsync(context, null)
|
||||
.map(
|
||||
result -> {
|
||||
LOGGER.info("Bot:\n\t\t" + result.getResult());
|
||||
|
||||
String existingHistoy = finalContext.getVariables().get("history");
|
||||
if (existingHistoy == null) {
|
||||
existingHistoy = "";
|
||||
}
|
||||
existingHistoy +=
|
||||
"\nUser: " + input + "\nChatBot: " + result.getResult() + "\n";
|
||||
return finalContext.setVariable("history", existingHistoy);
|
||||
});
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.e2e;
|
||||
|
||||
import com.microsoft.semantickernel.extensions.KernelExtensions;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@EnabledIf("isAzureTestEnabled")
|
||||
public class FunSkillTest extends AbstractKernelTest {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(FunSkillTest.class);
|
||||
|
||||
@Test
|
||||
public void tellAJoke() throws IOException {
|
||||
Mono<CompletionSKContext> result =
|
||||
buildTextCompletionKernel()
|
||||
.importSkill(
|
||||
"FunSkill",
|
||||
KernelExtensions.importSemanticSkillFromDirectory(
|
||||
"../../../samples/skills", "FunSkill"))
|
||||
.getFunction("joke", CompletionSKFunction.class)
|
||||
.invokeAsync("time travel to dinosaur age");
|
||||
|
||||
if (result != null) {
|
||||
LOGGER.info(result.block().getResult());
|
||||
}
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.e2e;
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class InlineFunctionTest extends AbstractKernelTest {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(InlineFunctionTest.class);
|
||||
|
||||
@Test
|
||||
@EnabledIf("isAzureTestEnabled")
|
||||
public void executeInlineFunction() throws IOException {
|
||||
Kernel kernel = buildTextCompletionKernel();
|
||||
String prompt = "{{$input}}\n" + "Summarize the content above.";
|
||||
|
||||
CompletionSKFunction summarize =
|
||||
kernel.getSemanticFunctionBuilder()
|
||||
.createFunction(
|
||||
prompt,
|
||||
"summarize",
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0.2, 0.5, 0, 0, 2000, new ArrayList<>()));
|
||||
|
||||
String text =
|
||||
"Demo (ancient Greek poet)\n"
|
||||
+ "From Wikipedia, the free encyclopedia\n"
|
||||
+ "Demo or Damo (Greek: Δεμώ, Δαμώ; fl. c. AD 200) was a Greek woman of the"
|
||||
+ " Roman period, known for a single epigram, engraved upon the Colossus of"
|
||||
+ " Memnon, which bears her name. She speaks of herself therein as a lyric"
|
||||
+ " poetess dedicated to the Muses, but nothing is known of her life.[1]\n"
|
||||
+ "Identity\n"
|
||||
+ "Demo was evidently Greek, as her name, a traditional epithet of Demeter,"
|
||||
+ " signifies. The name was relatively common in the Hellenistic world, in"
|
||||
+ " Egypt and elsewhere, and she cannot be further identified. The date of her"
|
||||
+ " visit to the Colossus of Memnon cannot be established with certainty, but"
|
||||
+ " internal evidence on the left leg suggests her poem was inscribed there at"
|
||||
+ " some point in or after AD 196.[2]\n"
|
||||
+ "Epigram\n"
|
||||
+ "There are a number of graffiti inscriptions on the Colossus of Memnon."
|
||||
+ " Following three epigrams by Julia Balbilla, a fourth epigram, in elegiac"
|
||||
+ " couplets, entitled and presumably authored by \"Demo\" or \"Damo\" (the"
|
||||
+ " Greek inscription is difficult to read), is a dedication to the Muses.[2]"
|
||||
+ " The poem is traditionally published with the works of Balbilla, though the"
|
||||
+ " internal evidence suggests a different author.[1]\n"
|
||||
+ "In the poem, Demo explains that Memnon has shown her special respect. In"
|
||||
+ " return, Demo offers the gift for poetry, as a gift to the hero. At the end"
|
||||
+ " of this epigram, she addresses Memnon, highlighting his divine status by"
|
||||
+ " recalling his strength and holiness.[2]\n"
|
||||
+ "Demo, like Julia Balbilla, writes in the artificial and poetic Aeolic"
|
||||
+ " dialect. The language indicates she was knowledgeable in Homeric"
|
||||
+ " poetry—'bearing a pleasant gift', for example, alludes to the use of that"
|
||||
+ " phrase throughout the Iliad and Odyssey.[a][2]\n";
|
||||
|
||||
Mono<CompletionSKContext> result = summarize.invokeAsync(text);
|
||||
|
||||
LOGGER.info("Result: " + result.block().getResult());
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.e2e;
|
||||
|
||||
import com.microsoft.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.KernelConfig;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.connectors.ai.openai.textcompletion.OpenAITextCompletion;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class KernelTest extends AbstractKernelTest {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(KernelTest.class);
|
||||
|
||||
@Test
|
||||
@EnabledIf("isAzureTestEnabled")
|
||||
public void endToEndTextGenerationTestAzureOpenAI() throws IOException {
|
||||
Kernel kernel = buildKernel(getAzureOpenAIClient(), "text-davinci-003");
|
||||
executeCompletion(kernel);
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledIf("isAzureTestEnabled")
|
||||
public void endToEndTextGenerationTestOpenAI() throws IOException {
|
||||
Kernel kernel = buildKernel(getOpenAIClient(), getOpenAIModel());
|
||||
executeCompletion(kernel);
|
||||
}
|
||||
|
||||
private static void executeCompletion(Kernel kernel) {
|
||||
CompletionSKFunction summarize =
|
||||
kernel.getSemanticFunctionBuilder()
|
||||
.createFunction(
|
||||
"{{$input}}\n" + "\n" + "One line TLDR with the fewest words.",
|
||||
null,
|
||||
"",
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0, 0, 0, 0, 256, new ArrayList<>()));
|
||||
|
||||
String text1 =
|
||||
"1st Law of Thermodynamics - Energy cannot be created or destroyed.\n"
|
||||
+ "2nd Law of Thermodynamics - For a spontaneous process, the entropy of the"
|
||||
+ " universe increases.\n"
|
||||
+ "3rd Law of Thermodynamics - A perfect crystal at zero Kelvin has zero"
|
||||
+ " entropy";
|
||||
|
||||
Mono<CompletionSKContext> mono = summarize.invokeAsync(text1);
|
||||
CompletionSKContext result = mono.block();
|
||||
|
||||
LOGGER.info("Result: " + result.getResult());
|
||||
}
|
||||
|
||||
public static Kernel buildKernel(OpenAIAsyncClient client, String model) {
|
||||
|
||||
TextCompletion textCompletion = new OpenAITextCompletion(client, model);
|
||||
|
||||
KernelConfig kernelConfig =
|
||||
SKBuilders.kernelConfig()
|
||||
.addTextCompletionService(model, kernel -> textCompletion)
|
||||
.build();
|
||||
|
||||
return SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.e2e;
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.extensions.KernelExtensions;
|
||||
import com.microsoft.semantickernel.planner.sequentialplanner.SequentialPlanner;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class PlannerTest extends AbstractKernelTest {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(PlannerTest.class);
|
||||
|
||||
@Test
|
||||
@EnabledIf("isAzureTestEnabled")
|
||||
public void executeInlineFunction() throws IOException {
|
||||
Kernel kernel = buildTextCompletionKernel();
|
||||
kernel.importSkill(
|
||||
"SummarizeSkill",
|
||||
KernelExtensions.importSemanticSkillFromDirectory(
|
||||
"../../../samples/skills", "SummarizeSkill"));
|
||||
kernel.importSkill(
|
||||
"WriterSkill",
|
||||
KernelExtensions.importSemanticSkillFromDirectory(
|
||||
"../../../samples/skills", "WriterSkill"));
|
||||
|
||||
SequentialPlanner planner = new SequentialPlanner(kernel, null, null);
|
||||
|
||||
CompletionSKContext result =
|
||||
planner.createPlanAsync(
|
||||
"Write a poem about John Doe, then translate it into Italian.")
|
||||
.block();
|
||||
LOGGER.info("Result: " + result.getResult());
|
||||
}
|
||||
}
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.e2e; // Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import com.microsoft.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.KernelConfig;
|
||||
import com.microsoft.semantickernel.ai.embeddings.EmbeddingGeneration;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.connectors.ai.openai.textembeddings.OpenAITextEmbeddingGeneration;
|
||||
import com.microsoft.semantickernel.coreskills.TextMemorySkill;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlyFunctionCollection;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TextEmbeddingsTest extends AbstractKernelTest {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(TextEmbeddingsTest.class);
|
||||
private static final int EXPECTED_EMBEDDING_SIZE = 1536;
|
||||
|
||||
@Test
|
||||
@EnabledIf("isOpenAIComTestEnabled")
|
||||
public void testEmbeddingGenerationOpenAI() throws IOException {
|
||||
testEmbeddingGeneration(getOpenAIClient(), EXPECTED_EMBEDDING_SIZE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledIf("isAzureTestEnabled")
|
||||
public void testEmbeddingGenerationAzure() throws IOException {
|
||||
testEmbeddingGeneration(getAzureOpenAIClient(), EXPECTED_EMBEDDING_SIZE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledIf("isAzureTestEnabled")
|
||||
public void testEmbeddingGeneration() throws IOException {
|
||||
String model = "text-embedding-ada-002";
|
||||
EmbeddingGeneration<String, Double> embeddingGeneration =
|
||||
new OpenAITextEmbeddingGeneration(getOpenAIClient(), model);
|
||||
|
||||
List<String> data = new ArrayList<>();
|
||||
data.add("This is just a test");
|
||||
|
||||
LOGGER.info(String.valueOf(embeddingGeneration.generateEmbeddingsAsync(data).block()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledIf("isAzureTestEnabled")
|
||||
public void testMemory() throws IOException {
|
||||
String model = "text-embedding-ada-002";
|
||||
EmbeddingGeneration<String, Double> embeddingGeneration =
|
||||
new OpenAITextEmbeddingGeneration(getAzureOpenAIClient(), model);
|
||||
|
||||
Kernel kernel = buildTextEmbeddingsKernel();
|
||||
|
||||
ReadOnlyFunctionCollection memory = kernel.importSkill(new TextMemorySkill(), null);
|
||||
|
||||
String skPrompt =
|
||||
"\n"
|
||||
+ "ChatBot can have a conversation with you about any topic.\n"
|
||||
+ "It can give explicit instructions or say 'I don't know' if it does not have"
|
||||
+ " an answer.\n"
|
||||
+ "\n"
|
||||
+ "Information about me, from previous conversations:\n"
|
||||
+ "- {{$fact1}} {{recall $fact1}}\n"
|
||||
+ "- {{$fact2}} {{recall $fact2}}\n"
|
||||
+ "- {{$fact3}} {{recall $fact3}}\n"
|
||||
+ "- {{$fact4}} {{recall $fact4}}\n"
|
||||
+ "- {{$fact5}} {{recall $fact5}}\n"
|
||||
+ "\n"
|
||||
+ "Chat:\n"
|
||||
+ "{{$history}}\n"
|
||||
+ "User: {{$userInput}}\n"
|
||||
+ "ChatBot: ";
|
||||
|
||||
Mono<CompletionSKContext> mono =
|
||||
memory.getFunction("retrieve", CompletionSKFunction.class).invokeAsync("");
|
||||
CompletionSKContext result = mono.block();
|
||||
|
||||
LOGGER.info(result.getResult());
|
||||
}
|
||||
|
||||
public void testEmbeddingGeneration(OpenAIAsyncClient client, int expectedEmbeddingSize) {
|
||||
String model = "text-embedding-ada-002";
|
||||
EmbeddingGeneration<String, Double> embeddingGeneration =
|
||||
new OpenAITextEmbeddingGeneration(client, model);
|
||||
|
||||
List<String> data = new ArrayList<>();
|
||||
data.add("This is just");
|
||||
data.add("a test");
|
||||
|
||||
embeddingGeneration
|
||||
.generateEmbeddingsAsync(data)
|
||||
.block()
|
||||
.forEach(
|
||||
embedding -> {
|
||||
Assertions.assertEquals(
|
||||
expectedEmbeddingSize, embedding.getVector().size());
|
||||
});
|
||||
}
|
||||
|
||||
private Kernel buildTextEmbeddingsKernel() throws IOException {
|
||||
String model = "text-embedding-ada-002";
|
||||
EmbeddingGeneration<String, Double> embeddingGeneration =
|
||||
new OpenAITextEmbeddingGeneration(getOpenAIClient(), model);
|
||||
|
||||
KernelConfig kernelConfig =
|
||||
SKBuilders.kernelConfig()
|
||||
.addTextEmbeddingsGenerationService(model, kernel -> embeddingGeneration)
|
||||
.build();
|
||||
|
||||
// TODO: .WithMemoryStorage(new VolatileMemoryStore())
|
||||
|
||||
// TODO: .WithMemoryStorage(new VolatileMemoryStore())
|
||||
|
||||
return SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?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="info">
|
||||
<AppenderRef ref="Console"/>
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
||||
@@ -0,0 +1,89 @@
|
||||
<?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.semantickernel</groupId>
|
||||
<artifactId>semantickernel-parent</artifactId>
|
||||
<version>0.2.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>com.microsoft.semantickernel.test</groupId>
|
||||
<artifactId>api-test</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<properties>
|
||||
<jdk.version>17</jdk.version>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<maven.compiler.testSource>17</maven.compiler.testSource>
|
||||
<maven.compiler.testTarget>17</maven.compiler.testTarget>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
<module>api-usage-example</module>
|
||||
<module>integration-tests</module>
|
||||
</modules>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel</groupId>
|
||||
<artifactId>semantickernel-bom</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>import</scope>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<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>3.10.1</version>
|
||||
<configuration>
|
||||
<source>17</source>
|
||||
<target>17</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
<showWarnings>true</showWarnings>
|
||||
<compilerArgs>
|
||||
<arg>-XDcompilePolicy=simple</arg>
|
||||
|
||||
<!-- 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
|
||||
</arg>
|
||||
</compilerArgs>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>com.google.errorprone</groupId>
|
||||
<artifactId>error_prone_core</artifactId>
|
||||
<version>2.18.0</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>com.uber.nullaway</groupId>
|
||||
<artifactId>nullaway</artifactId>
|
||||
<version>0.10.10</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<FindBugsFilter>
|
||||
|
||||
</FindBugsFilter>
|
||||
@@ -0,0 +1,308 @@
|
||||
#!/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
@@ -0,0 +1,205 @@
|
||||
@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%
|
||||
@@ -0,0 +1,36 @@
|
||||
<?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.semantickernel</groupId>
|
||||
<artifactId>semantickernel-parent</artifactId>
|
||||
<version>0.2.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>openai-sdk</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.azure</groupId>
|
||||
<artifactId>azure-ai-openai</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
</project>
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.openai;
|
||||
|
||||
import com.azure.ai.openai.models.*;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Create an OpenAIAsyncClient that delegates to an com.azure.ai.openai.OpenAIAsyncClient provided
|
||||
* by com.azure:azure-ai-openai
|
||||
*/
|
||||
public class AzureOpenAIClient implements OpenAIAsyncClient {
|
||||
private final com.azure.ai.openai.OpenAIAsyncClient delegate;
|
||||
|
||||
public AzureOpenAIClient(com.azure.ai.openai.OpenAIAsyncClient delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Embeddings> getEmbeddings(
|
||||
String deploymentId, EmbeddingsOptions embeddingsOptions) {
|
||||
return delegate.getEmbeddings(deploymentId, embeddingsOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Completions> getCompletions(
|
||||
String deploymentId, CompletionsOptions completionsOptions) {
|
||||
return delegate.getCompletions(deploymentId, completionsOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ChatCompletions> getChatCompletions(
|
||||
String deploymentId, ChatCompletionsOptions chatCompletionsOptions) {
|
||||
return delegate.getChatCompletions(deploymentId, chatCompletionsOptions);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.openai; // Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
// Code generated by Microsoft (R) AutoRest Code Generator.
|
||||
|
||||
import com.azure.ai.openai.models.*;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/** Interface for an OpenAI client */
|
||||
public interface OpenAIAsyncClient {
|
||||
Mono<Embeddings> getEmbeddings(String deploymentId, EmbeddingsOptions embeddingsOptions);
|
||||
|
||||
Mono<Completions> getCompletions(String deploymentId, CompletionsOptions completionsOptions);
|
||||
|
||||
Mono<ChatCompletions> getChatCompletions(
|
||||
String deploymentId, ChatCompletionsOptions chatCompletionsOptions);
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.openai;
|
||||
|
||||
import com.azure.ai.openai.models.*;
|
||||
import com.azure.core.annotation.*;
|
||||
import com.azure.core.exception.ClientAuthenticationException;
|
||||
import com.azure.core.exception.HttpResponseException;
|
||||
import com.azure.core.exception.ResourceModifiedException;
|
||||
import com.azure.core.exception.ResourceNotFoundException;
|
||||
import com.azure.core.http.HttpHeaderName;
|
||||
import com.azure.core.http.HttpPipeline;
|
||||
import com.azure.core.http.HttpPipelineBuilder;
|
||||
import com.azure.core.http.policy.CookiePolicy;
|
||||
import com.azure.core.http.policy.RetryPolicy;
|
||||
import com.azure.core.http.policy.UserAgentPolicy;
|
||||
import com.azure.core.http.rest.RequestOptions;
|
||||
import com.azure.core.http.rest.Response;
|
||||
import com.azure.core.http.rest.RestProxy;
|
||||
import com.azure.core.util.*;
|
||||
import com.azure.core.util.serializer.JacksonAdapter;
|
||||
import com.azure.core.util.serializer.SerializerAdapter;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
class OpenAIAsyncClientImpl implements OpenAIAsyncClient {
|
||||
private final OpenAIClientService service;
|
||||
private final String endpoint;
|
||||
|
||||
public String getEndpoint() {
|
||||
return this.endpoint;
|
||||
}
|
||||
|
||||
private final SerializerAdapter serializerAdapter;
|
||||
|
||||
public SerializerAdapter getSerializerAdapter() {
|
||||
return this.serializerAdapter;
|
||||
}
|
||||
|
||||
private String apiKey;
|
||||
|
||||
public OpenAIAsyncClientImpl(String endpoint, String apiKey) {
|
||||
this(
|
||||
new HttpPipelineBuilder()
|
||||
.policies(new UserAgentPolicy(), new RetryPolicy(), new CookiePolicy())
|
||||
.build(),
|
||||
JacksonAdapter.createDefaultSerializerAdapter(),
|
||||
endpoint);
|
||||
this.apiKey = apiKey;
|
||||
}
|
||||
|
||||
public OpenAIAsyncClientImpl(
|
||||
HttpPipeline httpPipeline, SerializerAdapter serializerAdapter, String endpoint) {
|
||||
this.serializerAdapter = serializerAdapter;
|
||||
this.endpoint = endpoint;
|
||||
this.service =
|
||||
RestProxy.create(
|
||||
OpenAIClientService.class, httpPipeline, this.getSerializerAdapter());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Embeddings> getEmbeddings(
|
||||
String deploymentId, EmbeddingsOptions embeddingsOptions) {
|
||||
final String accept = "application/json";
|
||||
return FluxUtil.withContext(
|
||||
context ->
|
||||
service.getEmbeddings(
|
||||
this.getEndpoint(),
|
||||
accept,
|
||||
BinaryData.fromObject(embeddingsOptions),
|
||||
new RequestOptions()
|
||||
.addHeader(
|
||||
HttpHeaderName.AUTHORIZATION,
|
||||
"Bearer " + this.apiKey),
|
||||
context))
|
||||
.flatMap(FluxUtil::toMono)
|
||||
.map(protocolMethodData -> protocolMethodData.toObject(Embeddings.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Completions> getCompletions(
|
||||
String deploymentId, CompletionsOptions completionsOptions) {
|
||||
final String accept = "application/json";
|
||||
return FluxUtil.withContext(
|
||||
context ->
|
||||
service.getCompletions(
|
||||
this.getEndpoint(),
|
||||
accept,
|
||||
BinaryData.fromObject(completionsOptions),
|
||||
new RequestOptions()
|
||||
.addHeader(
|
||||
HttpHeaderName.AUTHORIZATION,
|
||||
"Bearer " + this.apiKey),
|
||||
context))
|
||||
.flatMap(FluxUtil::toMono)
|
||||
.map(protocolMethodData -> protocolMethodData.toObject(Completions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ChatCompletions> getChatCompletions(
|
||||
String deploymentId, ChatCompletionsOptions chatCompletionsOptions) {
|
||||
final String accept = "application/json";
|
||||
return FluxUtil.withContext(
|
||||
context ->
|
||||
service.getChatCompletions(
|
||||
this.getEndpoint(),
|
||||
accept,
|
||||
BinaryData.fromObject(chatCompletionsOptions),
|
||||
new RequestOptions()
|
||||
.addHeader(
|
||||
HttpHeaderName.AUTHORIZATION,
|
||||
"Bearer " + this.apiKey),
|
||||
context))
|
||||
.flatMap(FluxUtil::toMono)
|
||||
.map(protocolMethodData -> protocolMethodData.toObject(ChatCompletions.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* The interface defining all the services for OpenAIAPI to be used by the proxy service to
|
||||
* perform REST calls.
|
||||
*/
|
||||
@Host("{endpoint}")
|
||||
@ServiceInterface(name = "OpenAIClient")
|
||||
public interface OpenAIClientService {
|
||||
|
||||
@Post("/embeddings")
|
||||
@ExpectedResponses({200})
|
||||
@UnexpectedResponseExceptionType(
|
||||
value = ClientAuthenticationException.class,
|
||||
code = {401})
|
||||
@UnexpectedResponseExceptionType(
|
||||
value = ResourceNotFoundException.class,
|
||||
code = {404})
|
||||
@UnexpectedResponseExceptionType(
|
||||
value = ResourceModifiedException.class,
|
||||
code = {409})
|
||||
@UnexpectedResponseExceptionType(HttpResponseException.class)
|
||||
Mono<Response<BinaryData>> getEmbeddings(
|
||||
@HostParam("endpoint") String endpoint,
|
||||
@HeaderParam("accept") String accept,
|
||||
@BodyParam("application/json") BinaryData embeddingsOptions,
|
||||
RequestOptions requestOptions,
|
||||
Context context);
|
||||
|
||||
@Post("/completions")
|
||||
@ExpectedResponses({200})
|
||||
@UnexpectedResponseExceptionType(
|
||||
value = ClientAuthenticationException.class,
|
||||
code = {401})
|
||||
@UnexpectedResponseExceptionType(
|
||||
value = ResourceNotFoundException.class,
|
||||
code = {404})
|
||||
@UnexpectedResponseExceptionType(
|
||||
value = ResourceModifiedException.class,
|
||||
code = {409})
|
||||
@UnexpectedResponseExceptionType(HttpResponseException.class)
|
||||
Mono<Response<BinaryData>> getCompletions(
|
||||
@HostParam("endpoint") String endpoint,
|
||||
@HeaderParam("accept") String accept,
|
||||
@BodyParam("application/json") BinaryData completionsOptions,
|
||||
RequestOptions requestOptions,
|
||||
Context context);
|
||||
|
||||
@Post("/chat/completions")
|
||||
@ExpectedResponses({200})
|
||||
@UnexpectedResponseExceptionType(
|
||||
value = ClientAuthenticationException.class,
|
||||
code = {401})
|
||||
@UnexpectedResponseExceptionType(
|
||||
value = ResourceNotFoundException.class,
|
||||
code = {404})
|
||||
@UnexpectedResponseExceptionType(
|
||||
value = ResourceModifiedException.class,
|
||||
code = {409})
|
||||
@UnexpectedResponseExceptionType(HttpResponseException.class)
|
||||
Mono<Response<BinaryData>> getChatCompletions(
|
||||
@HostParam("endpoint") String endpoint,
|
||||
@HeaderParam("accept") String accept,
|
||||
@BodyParam("application/json") BinaryData chatCompletionsOptions,
|
||||
RequestOptions requestOptions,
|
||||
Context context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.openai; // Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
// Code generated by Microsoft (R) AutoRest Code Generator.
|
||||
|
||||
/** Builds an OpenAIClient for use with <a href="https://api.openai.com/v1">api.openai.com/v1</a> */
|
||||
public final class OpenAIClientBuilder {
|
||||
private String endpoint = "https://api.openai.com/v1";
|
||||
private String apiKey;
|
||||
|
||||
public OpenAIClientBuilder setApiKey(String apiKey) {
|
||||
this.apiKey = apiKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OpenAIClientBuilder setEndpoint(String endpoint) {
|
||||
this.endpoint = endpoint;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OpenAIAsyncClient build() {
|
||||
return new OpenAIAsyncClientImpl(endpoint, apiKey);
|
||||
}
|
||||
}
|
||||
+232
@@ -0,0 +1,232 @@
|
||||
<?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.semantickernel</groupId>
|
||||
<artifactId>semantickernel-parent</artifactId>
|
||||
<version>0.2.0-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
|
||||
<properties>
|
||||
<jdk.version>1.8</jdk.version>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<maven.compiler.testSource>1.8</maven.compiler.testSource>
|
||||
<maven.compiler.testTarget>1.8</maven.compiler.testTarget>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
<module>openai-sdk</module>
|
||||
<module>semantickernel-bom</module>
|
||||
<module>semantickernel-api</module>
|
||||
<module>semantickernel-core</module>
|
||||
<module>semantickernel-extensions-parent</module>
|
||||
<module>semantickernel-connectors-parent</module>
|
||||
<module>semantickernel-core-skills</module>
|
||||
</modules>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel</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>5.9.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>5.9.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>2.20.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>2.20.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j2-impl</artifactId>
|
||||
<version>2.20.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>4.11.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.azure</groupId>
|
||||
<artifactId>azure-ai-openai</artifactId>
|
||||
<version>1.0.0-alpha.20230505.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel.connectors</groupId>
|
||||
<artifactId>semantickernel-connectors</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel.extensions</groupId>
|
||||
<artifactId>sequentialplanner-extensions</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>central</id>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
<url>https://repo1.maven.org/maven2/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>azure-sdk-for-java</id>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
<url>https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-java/maven/v1</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.5.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</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>3.10.1</version>
|
||||
<configuration>
|
||||
<source>8</source>
|
||||
<target>8</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
<showWarnings>true</showWarnings>
|
||||
<compilerArgs>
|
||||
<arg>-XDcompilePolicy=simple</arg>
|
||||
|
||||
<!-- 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
|
||||
</arg>
|
||||
</compilerArgs>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>com.google.errorprone</groupId>
|
||||
<artifactId>error_prone_core</artifactId>
|
||||
<version>2.18.0</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>com.uber.nullaway</groupId>
|
||||
<artifactId>nullaway</artifactId>
|
||||
<version>0.10.10</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.diffplug.spotless</groupId>
|
||||
<artifactId>spotless-maven-plugin</artifactId>
|
||||
<version>2.36.0</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>
|
||||
<java>
|
||||
<googleJavaFormat>
|
||||
<version>1.16.0</version>
|
||||
<style>AOSP</style>
|
||||
<reflowLongStrings>true</reflowLongStrings>
|
||||
</googleJavaFormat>
|
||||
|
||||
<licenseHeader>
|
||||
<content>// Copyright (c) Microsoft. All rights reserved.</content>
|
||||
</licenseHeader>
|
||||
</java>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.github.spotbugs</groupId>
|
||||
<artifactId>spotbugs-maven-plugin</artifactId>
|
||||
<version>4.7.3.4</version>
|
||||
<configuration>
|
||||
<excludeFilterFile>spotbugs-exclude.xml</excludeFilterFile>
|
||||
<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>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
@@ -0,0 +1,2 @@
|
||||
token: "Your Azure OpenAI Key"
|
||||
endpoint: "Azure OpenAI endpoint"
|
||||
@@ -0,0 +1 @@
|
||||
token: "Your OpenAI Key"
|
||||
@@ -0,0 +1,122 @@
|
||||
<?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.semantickernel</groupId>
|
||||
<artifactId>samples</artifactId>
|
||||
<version>0.2.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<jdk.version>17</jdk.version>
|
||||
<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.semantickernel</groupId>
|
||||
<artifactId>semantickernel-bom</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>import</scope>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel</groupId>
|
||||
<artifactId>semantickernel-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel.connectors</groupId>
|
||||
<artifactId>semantickernel-connectors</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel</groupId>
|
||||
<artifactId>openai-sdk</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel</groupId>
|
||||
<artifactId>semantickernel-core</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel</groupId>
|
||||
<artifactId>semantickernel-core-skills</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>2.20.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>2.20.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j2-impl</artifactId>
|
||||
<version>2.20.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel.extensions</groupId>
|
||||
<artifactId>sequentialplanner-extensions</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<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>3.10.1</version>
|
||||
<configuration>
|
||||
<source>17</source>
|
||||
<target>17</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
<showWarnings>true</showWarnings>
|
||||
<compilerArgs>
|
||||
<arg>-XDcompilePolicy=simple</arg>
|
||||
|
||||
<!-- 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
|
||||
</arg>
|
||||
</compilerArgs>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>com.google.errorprone</groupId>
|
||||
<artifactId>error_prone_core</artifactId>
|
||||
<version>2.18.0</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>com.uber.nullaway</groupId>
|
||||
<artifactId>nullaway</artifactId>
|
||||
<version>0.10.10</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.microsoft.semantickernel;
|
||||
|
||||
import com.azure.core.credential.AzureKeyCredential;
|
||||
import com.microsoft.openai.AzureOpenAIClient;
|
||||
import com.microsoft.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.openai.OpenAIClientBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
public class Config {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Config.class);
|
||||
|
||||
public static final String OPEN_AI_CONF_PROPERTIES = "samples/java/semantickernel-samples/conf.openai.properties";
|
||||
public static final String AZURE_CONF_PROPERTIES = "samples/java/semantickernel-samples/conf.azure.properties";
|
||||
|
||||
|
||||
public static String getOpenAIKey(String conf) {
|
||||
return getConfigValue(conf, "token");
|
||||
}
|
||||
|
||||
public static String getAzureOpenAIEndpoint(String conf) {
|
||||
return getConfigValue(conf, "endpoint");
|
||||
}
|
||||
|
||||
private static String getConfigValue(String configFile, String propertyName) {
|
||||
File config = new File(configFile);
|
||||
try (FileInputStream fis = new FileInputStream(config.getAbsolutePath())) {
|
||||
Properties props = new Properties();
|
||||
props.load(fis);
|
||||
return props.getProperty(propertyName);
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Unable to load config value " + propertyName + " from file" + configFile, e);
|
||||
throw new RuntimeException(configFile + " not configured properly");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the client that will handle AzureOpenAI or OpenAI requests.
|
||||
*
|
||||
* @param useAzureOpenAI whether to use AzureOpenAI or OpenAI.
|
||||
* @return client to be used by the kernel.
|
||||
*/
|
||||
public static OpenAIAsyncClient getClient(boolean useAzureOpenAI) {
|
||||
if (useAzureOpenAI) {
|
||||
return new AzureOpenAIClient(
|
||||
new com.azure.ai.openai.OpenAIClientBuilder()
|
||||
.endpoint(Config.getAzureOpenAIEndpoint(AZURE_CONF_PROPERTIES))
|
||||
.credential(new AzureKeyCredential(Config.getOpenAIKey(AZURE_CONF_PROPERTIES)))
|
||||
.buildAsyncClient());
|
||||
}
|
||||
|
||||
return new OpenAIClientBuilder()
|
||||
.setApiKey(Config.getOpenAIKey(OPEN_AI_CONF_PROPERTIES))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.microsoft.semantickernel;
|
||||
|
||||
import com.microsoft.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.openai.OpenAIClientBuilder;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.extensions.KernelExtensions;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlyFunctionCollection;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Getting started
|
||||
*
|
||||
* First create a configuration file based on the examples files at the root of this module:
|
||||
* conf.azure.properties if using Azure OpenAI
|
||||
* conf.openai.properties if using OpenAI
|
||||
*
|
||||
* <a href="https://learn.microsoft.com/en-us/azure/cognitive-services/openai/quickstart">Get started with Azure OpenAI</a>
|
||||
* <a href="https://openai.com/product">Get started with OpenAI</a>
|
||||
*/
|
||||
public class Example00GettingStarted {
|
||||
|
||||
/**
|
||||
* Returns a Semantic Kernel with Text Completion.
|
||||
*
|
||||
* @param client Client that will handle requests to AzureOpenAI or OpenAI.
|
||||
* @return
|
||||
*/
|
||||
public static Kernel getKernel(OpenAIAsyncClient client) {
|
||||
KernelConfig config = SKBuilders.kernelConfig()
|
||||
.addTextCompletionService("davinci", kernel -> SKBuilders.textCompletionService().build(client, "text-davinci-003"))
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel()
|
||||
.setKernelConfig(config)
|
||||
.build();
|
||||
|
||||
return kernel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports 'FunSkill' from directory examples and runs the 'Joke' function within it.
|
||||
*
|
||||
* @param kernel Kernel with Text Completion.
|
||||
*/
|
||||
public static void joke (Kernel kernel) {
|
||||
|
||||
ReadOnlyFunctionCollection skill = kernel
|
||||
.importSkill("FunSkill", KernelExtensions.importSemanticSkillFromDirectory(
|
||||
"samples/skills", "FunSkill"));
|
||||
|
||||
CompletionSKFunction function = skill.getFunction("Joke",
|
||||
CompletionSKFunction.class);
|
||||
|
||||
Mono<CompletionSKContext> result = function.invokeAsync("time travel to dinosaur age");
|
||||
|
||||
if (result != null) {
|
||||
System.out.println(result.block().getResult());
|
||||
}
|
||||
}
|
||||
|
||||
public static void run (boolean useAzureOpenAI) {
|
||||
OpenAIAsyncClient client = Config.getClient(useAzureOpenAI);
|
||||
Kernel kernel = getKernel(client);
|
||||
joke(kernel);
|
||||
}
|
||||
|
||||
public static void main (String args[]) {
|
||||
// Send whether AzureOpenAI will be used. If false, OpenAI will be used.
|
||||
run(false);
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package com.microsoft.semantickernel;
|
||||
|
||||
import com.microsoft.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.extensions.KernelExtensions;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlyFunctionCollection;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Using Semantic Functions stored on disk
|
||||
*
|
||||
* A Semantic Skill is a collection of Semantic Functions, where each function is defined with natural language that can be provided with a text file.
|
||||
* Refer to our <a href="https://github.com/microsoft/semantic-kernel/blob/main/docs/GLOSSARY.md">glossary</a> for an in-depth guide to the terms.
|
||||
*
|
||||
* The repository includes some examples under the <a href="https://github.com/microsoft/semantic-kernel/tree/main/samples">samples</a> folder.
|
||||
*/
|
||||
public class Example02RunnningPromptsFromFile {
|
||||
|
||||
/**
|
||||
* Imports skill 'FunSkill' stored in the samples folder and then returns the semantic function 'Joke' within it.
|
||||
*
|
||||
* @param kernel Kernel with Text Completion
|
||||
* @return Joke function
|
||||
*/
|
||||
public static CompletionSKFunction getJokeFunction(Kernel kernel) {
|
||||
ReadOnlyFunctionCollection skill = kernel
|
||||
.importSkill("FunSkill", KernelExtensions.importSemanticSkillFromDirectory(
|
||||
"samples/skills", "FunSkill"));
|
||||
|
||||
return skill.getFunction("Joke", CompletionSKFunction.class);
|
||||
}
|
||||
|
||||
public static void run (boolean useAzureOpenAI) {
|
||||
OpenAIAsyncClient client = Config.getClient(useAzureOpenAI);
|
||||
Kernel kernel = Example00GettingStarted.getKernel(client);
|
||||
CompletionSKFunction jokeFunction = getJokeFunction(kernel);
|
||||
|
||||
System.out.println(jokeFunction.invokeAsync("time travel to dinosaur age").block().getResult());
|
||||
}
|
||||
|
||||
public static void main (String args[]) throws IOException {
|
||||
run(false);
|
||||
}
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
package com.microsoft.semantickernel;
|
||||
|
||||
import com.microsoft.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.orchestration.SKFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Define a Semantic Function inline with Java code.
|
||||
*/
|
||||
public class Example03SemanticFunctionInline {
|
||||
|
||||
/**
|
||||
* Defines and runs an inline Semantic Function
|
||||
*
|
||||
* @param kernel Kernel with Text Completion
|
||||
* @param prompt String prompt
|
||||
* @param functionName Name of the function
|
||||
* @param text Input to the function
|
||||
*/
|
||||
public static void inlineFunction(Kernel kernel, String prompt, String functionName, String text) {
|
||||
SKFunction summarize =
|
||||
kernel
|
||||
.getSemanticFunctionBuilder()
|
||||
.createFunction(
|
||||
prompt,
|
||||
functionName,
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0.2,
|
||||
0.5,
|
||||
0,
|
||||
0,
|
||||
2000,
|
||||
new ArrayList<>()
|
||||
));
|
||||
|
||||
Mono<CompletionSKContext> result = summarize.invokeAsync(text);
|
||||
|
||||
if (result != null) {
|
||||
System.out.println(result.block().getResult());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example prompt that summarizes text
|
||||
*
|
||||
* @param kernel
|
||||
*/
|
||||
public static void summarize(Kernel kernel) {
|
||||
String prompt = """
|
||||
{{$input}}
|
||||
Summarize the content above.
|
||||
""";
|
||||
|
||||
String text = """
|
||||
Demo (ancient Greek poet)
|
||||
From Wikipedia, the free encyclopedia
|
||||
Demo or Damo (Greek: Δεμώ, Δαμώ; fl. c. AD 200) was a Greek woman of the Roman period,
|
||||
known for a single epigram, engraved upon the Colossus of Memnon, which bears her name.
|
||||
She speaks of herself therein as a lyric poetess dedicated to the Muses, but nothing is known of her life.[1]
|
||||
Identity
|
||||
Demo was evidently Greek, as her name, a traditional epithet of Demeter, signifies.
|
||||
The name was relatively common in the Hellenistic world, in Egypt and elsewhere,
|
||||
and she cannot be further identified.
|
||||
The date of her visit to the Colossus of Memnon cannot be established with certainty,
|
||||
but internal evidence on the left leg suggests her poem was inscribed there at some point in or after AD 196.[2]
|
||||
Epigram
|
||||
There are a number of graffiti inscriptions on the Colossus of Memnon.
|
||||
Following three epigrams by Julia Balbilla, a fourth epigram, in elegiac couplets,
|
||||
entitled and presumably authored by "Demo" or "Damo"
|
||||
(the Greek inscription is difficult to read), is a dedication to the Muses.[2]
|
||||
The poem is traditionally published with the works of Balbilla,
|
||||
though the internal evidence suggests a different author.[1]
|
||||
In the poem, Demo explains that Memnon has shown her special respect.
|
||||
In return, Demo offers the gift for poetry, as a gift to the hero.
|
||||
At the end of this epigram, she addresses Memnon,
|
||||
highlighting his divine status by recalling his strength and holiness.[2]
|
||||
Demo, like Julia Balbilla, writes in the artificial and poetic Aeolic dialect.
|
||||
The language indicates she was knowledgeable in Homeric poetry—'bearing a pleasant gift',
|
||||
for example, alludes to the use of that phrase throughout the Iliad and Odyssey.[a][2]
|
||||
""";
|
||||
|
||||
inlineFunction(kernel, prompt, "summarize", text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example of a prompt returning a TLDR of a text
|
||||
*
|
||||
* @param kernel
|
||||
*/
|
||||
public static void TLDR(Kernel kernel) {
|
||||
String propmt = """
|
||||
{{$input}}
|
||||
|
||||
Give me the TLDR in 5 words.
|
||||
""";
|
||||
|
||||
String text = """
|
||||
1) A robot may not injure a human being or, through inaction,
|
||||
allow a human being to come to harm.
|
||||
|
||||
2) A robot must obey orders given it by human beings except where
|
||||
such orders would conflict with the First Law.
|
||||
|
||||
3) A robot must protect its own existence as long as such protection
|
||||
does not conflict with the First or Second Law.
|
||||
""";
|
||||
|
||||
inlineFunction(kernel, propmt, "tldr", text);
|
||||
}
|
||||
|
||||
public static void run(boolean useAzureOpenAI) {
|
||||
OpenAIAsyncClient client = Config.getClient(useAzureOpenAI);
|
||||
Kernel kernel = Example00GettingStarted.getKernel(client);
|
||||
|
||||
summarize(kernel);
|
||||
TLDR(kernel);
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws IOException {
|
||||
run(false);
|
||||
}
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
package com.microsoft.semantickernel;
|
||||
|
||||
import com.microsoft.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Chatbot using context variables
|
||||
*
|
||||
* Context Variables object which in this demo functions similarly as a key-value store that you can use when running the kernel.
|
||||
* The context is local (i.e. in your computer's RAM) and not persisted anywhere beyond the life of the JVM execution.
|
||||
*/
|
||||
public class Example04ContextVariablesChat {
|
||||
public static void startChat (Kernel kernel)
|
||||
throws ExecutionException, InterruptedException, TimeoutException {
|
||||
String prompt ="""
|
||||
ChatBot can have a conversation with you about any topic.
|
||||
It can give explicit instructions or say 'I don't know' if it does not have an answer.
|
||||
|
||||
{{$history}}
|
||||
User: {{$user_input}}
|
||||
ChatBot: """;
|
||||
|
||||
CompletionSKFunction chat = kernel
|
||||
.getSemanticFunctionBuilder()
|
||||
.createFunction(
|
||||
prompt,
|
||||
"ChatBot",
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0.7,
|
||||
0.5,
|
||||
0,
|
||||
0,
|
||||
2000,
|
||||
new ArrayList<>()
|
||||
));
|
||||
|
||||
CompletionSKContext readOnlySkContext = chat.buildContext();
|
||||
|
||||
chat("Hi, I'm looking for book suggestions?", chat, readOnlySkContext)
|
||||
.flatMap(
|
||||
chat(
|
||||
"I love history and philosophy, I'd like to learn something new"
|
||||
+ " about Greece, any suggestion?",
|
||||
chat))
|
||||
.flatMap(chat("that sounds interesting, what is it about?", chat))
|
||||
.flatMap(
|
||||
chat(
|
||||
"if I read that book, what exactly will I learn about Greece"
|
||||
+ " history?",
|
||||
chat))
|
||||
.flatMap(
|
||||
chat("could you list some more books I could read about this topic?", chat))
|
||||
.block();
|
||||
}
|
||||
|
||||
private static Mono<CompletionSKContext> chat(
|
||||
String input, CompletionSKFunction chat, CompletionSKContext context)
|
||||
throws ExecutionException, InterruptedException, TimeoutException {
|
||||
context = context.setVariable("user_input", input);
|
||||
|
||||
System.out.println("User: " + input);
|
||||
|
||||
CompletionSKContext finalContext = context;
|
||||
return chat.invokeAsync(context, null)
|
||||
.map(
|
||||
result -> {
|
||||
System.out.println("Bot: " + result.getResult() + "\n");
|
||||
|
||||
String existingHistoy =
|
||||
finalContext.getVariables().asMap().get("history");
|
||||
if (existingHistoy == null) {
|
||||
existingHistoy = "";
|
||||
}
|
||||
existingHistoy +=
|
||||
"\nUser: " + input + "\nChatBot: " + result.getResult() + "\n";
|
||||
return finalContext.setVariable("history", existingHistoy);
|
||||
});
|
||||
}
|
||||
|
||||
private static Function<CompletionSKContext, Mono<CompletionSKContext>> chat(
|
||||
String input, CompletionSKFunction chat) {
|
||||
return (context) -> {
|
||||
try {
|
||||
return chat(input, chat, context);
|
||||
} catch (ExecutionException | InterruptedException | TimeoutException e) {
|
||||
return Mono.error(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static void run (boolean useAzureOpenAI)
|
||||
throws ExecutionException, InterruptedException, TimeoutException {
|
||||
OpenAIAsyncClient client = Config.getClient(useAzureOpenAI);
|
||||
Kernel kernel = Example00GettingStarted.getKernel(client);
|
||||
|
||||
startChat(kernel);
|
||||
}
|
||||
|
||||
public static void main (String[] args)
|
||||
throws ExecutionException, InterruptedException, TimeoutException {
|
||||
run(false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.microsoft.semantickernel;
|
||||
|
||||
import com.microsoft.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.extensions.KernelExtensions;
|
||||
import com.microsoft.semantickernel.planner.sequentialplanner.SequentialPlanner;
|
||||
|
||||
public class Example05UsingThePlanner {
|
||||
|
||||
public static SequentialPlanner getPlanner(Kernel kernel) {
|
||||
kernel.importSkill("SummarizeSkill", KernelExtensions.importSemanticSkillFromDirectory(
|
||||
"samples/skills", "SummarizeSkill"));
|
||||
kernel.importSkill("WriterSkill", KernelExtensions.importSemanticSkillFromDirectory(
|
||||
"samples/skills", "WriterSkill"));
|
||||
|
||||
return new SequentialPlanner(kernel, null, null);
|
||||
}
|
||||
|
||||
public static void run(boolean useAzureOpenAI) {
|
||||
OpenAIAsyncClient client = Config.getClient(useAzureOpenAI);
|
||||
Kernel kernel = Example00GettingStarted.getKernel(client);
|
||||
|
||||
SequentialPlanner planner = getPlanner(kernel);
|
||||
System.out.println(planner.createPlanAsync(
|
||||
"Write a poem about John Doe, then translate it into Italian.")
|
||||
.block().getResult());
|
||||
|
||||
// TODO: execute the plan
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
run(true);
|
||||
}
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.microsoft.semantickernel;
|
||||
|
||||
import com.microsoft.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
|
||||
public class Example06MemoryAndEmbeddings {
|
||||
|
||||
public static Kernel getKernel(OpenAIAsyncClient client) {
|
||||
KernelConfig config = SKBuilders.kernelConfig()
|
||||
.addTextCompletionService(
|
||||
"davinci", kernel -> SKBuilders.textCompletionService().build(client, "text-davinci-003"))
|
||||
.addTextEmbeddingsGenerationService(
|
||||
"embeddings", kernel -> SKBuilders.textEmbeddingGenerationService().build(client, "text-embedding-ada-002"))
|
||||
.build();
|
||||
|
||||
// TODO: Add Volatile memory
|
||||
|
||||
Kernel kernel = SKBuilders.kernel()
|
||||
.setKernelConfig(config)
|
||||
.build();
|
||||
|
||||
return kernel;
|
||||
}
|
||||
|
||||
public static void run (boolean useAzureOpenAI) {
|
||||
OpenAIAsyncClient client = Config.getClient(useAzureOpenAI);
|
||||
Kernel kernel = getKernel(client);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
run(false);
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.microsoft.semantickernel.syntaxexamples;
|
||||
|
||||
import com.microsoft.semantickernel.coreskills.TextSkill;
|
||||
|
||||
public class Example01_NativeFunctions {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
// Load native skill
|
||||
TextSkill text = new TextSkill();
|
||||
|
||||
// Use function without kernel
|
||||
String result = text.uppercase("ciao!").block();
|
||||
|
||||
System.out.println(result);
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.microsoft.semantickernel.syntaxexamples;
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.KernelConfig;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.coreskills.TextSkill;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlyFunctionCollection;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public class Example02_Pipeline {
|
||||
public static void main(String[] args) {
|
||||
KernelConfig kernelConfig = SKBuilders.kernelConfig().build();
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
|
||||
// Load native skill
|
||||
ReadOnlyFunctionCollection text = kernel.importSkill(new TextSkill(), null);
|
||||
|
||||
Mono<SKContext<?>> result =
|
||||
kernel.runAsync(
|
||||
" i n f i n i t e s p a c e ",
|
||||
text.getFunction("LStrip"),
|
||||
text.getFunction("RStrip"),
|
||||
text.getFunction("Uppercase"));
|
||||
|
||||
System.out.println(result.block().getResult());
|
||||
}
|
||||
}
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
package com.microsoft.semantickernel.syntaxexamples;// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import com.microsoft.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.Config;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.KernelConfig;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.connectors.ai.openai.textcompletion.OpenAITextCompletion;
|
||||
import com.microsoft.semantickernel.connectors.ai.openai.textembeddings.OpenAITextEmbeddingGeneration;
|
||||
import com.microsoft.semantickernel.coreskills.TimeSkill;
|
||||
import com.microsoft.semantickernel.memory.NullMemory;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.templateengine.PromptTemplateEngine;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Example06_TemplateLanguage {
|
||||
/// <summary>
|
||||
/// Show how to invoke a Native Function written in C#
|
||||
/// from a Semantic Function written in natural language
|
||||
/// </summary>
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("======== TemplateLanguage ========");
|
||||
|
||||
|
||||
OpenAIAsyncClient client = Config.getClient(true);
|
||||
|
||||
KernelConfig kernelConfig = SKBuilders.kernelConfig()
|
||||
.addTextCompletionService(
|
||||
"text-davinci-003",
|
||||
kernel -> SKBuilders.textCompletionService().build(client, "text-davinci-003")
|
||||
)
|
||||
.addTextEmbeddingsGenerationService(
|
||||
"text-embedding-ada-002",
|
||||
kernel -> SKBuilders.textEmbeddingGenerationService().build(client, "text-embedding-ada-002"))
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
|
||||
// Load native skill into the kernel skill collection, sharing its functions with prompt templates
|
||||
// Functions loaded here are available as "time.*"
|
||||
kernel.importSkill(new TimeSkill(), "time");
|
||||
|
||||
// Semantic Function invoking time.Date and time.Time native functions
|
||||
String functionDefinition = """
|
||||
Today is: {{time.Date}}
|
||||
Current time is: {{time.Time}}
|
||||
|
||||
Answer to the following questions using JSON syntax, including the data used.
|
||||
Is it morning, afternoon, evening, or night (morning/afternoon/evening/night)?
|
||||
Is it weekend time (weekend/not weekend)?
|
||||
""";
|
||||
|
||||
// This allows to see the prompt before it's sent to OpenAI
|
||||
System.out.println("--- Rendered Prompt");
|
||||
|
||||
var promptRenderer = SKBuilders.promptTemplate().build(functionDefinition, null);
|
||||
|
||||
SKContext skContext = SKBuilders
|
||||
.context()
|
||||
.build(kernel.getSkills());
|
||||
|
||||
PromptTemplateEngine promptTemplateEngine = SKBuilders.promptTemplateEngine().build();
|
||||
|
||||
var renderedPrompt = promptRenderer.renderAsync(skContext, promptTemplateEngine);
|
||||
System.out.println(renderedPrompt.block());
|
||||
|
||||
// Run the prompt / semantic function
|
||||
var kindOfDay = kernel.getSemanticFunctionBuilder()
|
||||
.createFunction(
|
||||
functionDefinition,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0, 0, 0, 0, 256, new ArrayList<>()
|
||||
)
|
||||
);
|
||||
|
||||
// Show the result
|
||||
System.out.println("--- Semantic Function result");
|
||||
var result = kindOfDay.invokeAsync("").block().getResult();
|
||||
System.out.println(result);
|
||||
/* OUTPUT:
|
||||
|
||||
--- Rendered Prompt
|
||||
|
||||
Today is: Friday, April 28, 2023
|
||||
Current time is: 11:04:30 PM
|
||||
|
||||
Answer to the following questions using JSON syntax, including the data used.
|
||||
Is it morning, afternoon, evening, or night (morning/afternoon/evening/night)?
|
||||
Is it weekend time (weekend/not weekend)?
|
||||
|
||||
--- Semantic Function result
|
||||
|
||||
{
|
||||
"date": "Friday, April 28, 2023",
|
||||
"time": "11:04:30 PM",
|
||||
"period": "night",
|
||||
"weekend": "weekend"
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
package com.microsoft.semantickernel.syntaxexamples;// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
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.openai.AzureOpenAIClient;
|
||||
import com.microsoft.semantickernel.Config;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.KernelConfig;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static com.microsoft.semantickernel.Config.AZURE_CONF_PROPERTIES;
|
||||
|
||||
public class Example08_RetryHandler {
|
||||
|
||||
public static void main(String[] args) {
|
||||
RetryOptions retryOptions = new RetryOptions(new ExponentialBackoffOptions()
|
||||
.setMaxDelay(Duration.ofSeconds(180))
|
||||
.setBaseDelay(Duration.ofSeconds(60))
|
||||
.setMaxRetries(3)
|
||||
);
|
||||
|
||||
AzureOpenAIClient client = new AzureOpenAIClient(
|
||||
new OpenAIClientBuilder()
|
||||
.retryOptions(retryOptions)
|
||||
.endpoint(Config.getAzureOpenAIEndpoint(AZURE_CONF_PROPERTIES))
|
||||
.credential(new AzureKeyCredential(Config.getOpenAIKey(AZURE_CONF_PROPERTIES)))
|
||||
.buildAsyncClient());
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
String text =
|
||||
"""
|
||||
Demo (ancient Greek poet)
|
||||
From Wikipedia, the free encyclopedia
|
||||
Demo or Damo (Greek: Δεμώ, Δαμώ; fl. c. AD 200) was a Greek woman of the
|
||||
Roman period, known for a single epigram, engraved upon the Colossus of
|
||||
Memnon, which bears her name. She speaks of herself therein as a lyric
|
||||
poetess dedicated to the Muses, but nothing is known of her life.[1]
|
||||
Identity
|
||||
Demo was evidently Greek, as her name, a traditional epithet of Demeter,
|
||||
signifies. The name was relatively common in the Hellenistic world, in
|
||||
Egypt and elsewhere, and she cannot be further identified. The date of her
|
||||
visit to the Colossus of Memnon cannot be established with certainty, but
|
||||
internal evidence on the left leg suggests her poem was inscribed there at
|
||||
some point in or after AD 196.[2]
|
||||
Epigram
|
||||
There are a number of graffiti inscriptions on the Colossus of Memnon.
|
||||
Following three epigrams by Julia Balbilla, a fourth epigram, in elegiac
|
||||
couplets, entitled and presumably authored by "Demo" or "Damo" (the
|
||||
Greek inscription is difficult to read), is a dedication to the Muses.[2]
|
||||
The poem is traditionally published with the works of Balbilla, though the
|
||||
internal evidence suggests a different author.[1]
|
||||
In the poem, Demo explains that Memnon has shown her special respect. In
|
||||
return, Demo offers the gift for poetry, as a gift to the hero. At the end
|
||||
of this epigram, she addresses Memnon, highlighting his divine status by
|
||||
recalling his strength and holiness.[2]
|
||||
Demo, like Julia Balbilla, writes in the artificial and poetic Aeolic
|
||||
dialect. The language indicates she was knowledgeable in Homeric
|
||||
poetry—'bearing a pleasant gift', for example, alludes to the use of that
|
||||
phrase throughout the Iliad and Odyssey.[a][2];
|
||||
""";
|
||||
|
||||
String prompt = "{{$input}}\nSummarize the content above.";
|
||||
|
||||
TextCompletion textCompletion = SKBuilders.textCompletionService().build(client, "text-davinci-003");
|
||||
|
||||
CompletionSKFunction summarizeFunc =
|
||||
SKBuilders.completionFunctions()
|
||||
.createFunction(
|
||||
prompt,
|
||||
"summarize",
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0.2, 0.5, 0, 0, 2000, new ArrayList<>()));
|
||||
|
||||
KernelConfig kernelConfig =
|
||||
new KernelConfig.Builder()
|
||||
.addTextCompletionService("text-davinci-003", kernel -> textCompletion)
|
||||
.addSkill(summarizeFunc)
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
|
||||
CompletionSKFunction summarize =
|
||||
kernel.getSkills().getFunction("summarize", CompletionSKFunction.class);
|
||||
|
||||
CompletionSKContext context = summarize.invokeAsync(text).block();
|
||||
|
||||
System.out.println(context.getResult());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?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.semantickernel</groupId>
|
||||
<artifactId>semantickernel-parent</artifactId>
|
||||
<version>0.2.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>semantickernel-api</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>jsr305</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel</groupId>
|
||||
<artifactId>openai-sdk</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
</project>
|
||||
@@ -0,0 +1,165 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel;
|
||||
|
||||
import com.microsoft.semantickernel.builders.BuildersSingleton;
|
||||
import com.microsoft.semantickernel.exceptions.SkillsNotFoundException;
|
||||
import com.microsoft.semantickernel.memory.SemanticTextMemory;
|
||||
import com.microsoft.semantickernel.orchestration.ContextVariables;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.orchestration.SKFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.SemanticFunctionConfig;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlyFunctionCollection;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
|
||||
import com.microsoft.semantickernel.templateengine.PromptTemplateEngine;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Interface for the semantic kernel. */
|
||||
public interface Kernel {
|
||||
|
||||
/**
|
||||
* Settings required to execute functions, including details about AI dependencies, e.g.
|
||||
* endpoints and API keys.
|
||||
*/
|
||||
KernelConfig getConfig();
|
||||
|
||||
/**
|
||||
* Reference to the engine rendering prompt templates
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
PromptTemplateEngine getPromptTemplateEngine();
|
||||
|
||||
/**
|
||||
* Set the semantic memory to use.
|
||||
*
|
||||
* @param memory {@link SemanticTextMemory} instance
|
||||
*/
|
||||
void registerMemory(SemanticTextMemory memory);
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Set the semantic memory to use
|
||||
/// </summary>
|
||||
/// <param name="memory">Semantic memory instance</param>
|
||||
void RegisterMemory(ISemanticTextMemory memory);
|
||||
*/
|
||||
/**
|
||||
* Run a pipeline composed of synchronous and asynchronous functions.
|
||||
*
|
||||
* @param pipeline List of functions
|
||||
* @return Result of the function composition
|
||||
*/
|
||||
Mono<SKContext<?>> runAsync(SKFunction... pipeline);
|
||||
|
||||
/**
|
||||
* Run a pipeline composed of synchronous and asynchronous functions.
|
||||
*
|
||||
* @param input Input to process
|
||||
* @param pipeline List of functions
|
||||
* @return Result of the function composition
|
||||
*/
|
||||
Mono<SKContext<?>> runAsync(String input, SKFunction... pipeline);
|
||||
|
||||
/**
|
||||
* Run a pipeline composed of synchronous and asynchronous functions.
|
||||
*
|
||||
* @param variables variables to initialise the context with
|
||||
* @param pipeline List of functions
|
||||
* @return Result of the function composition
|
||||
*/
|
||||
Mono<SKContext<?>> runAsync(ContextVariables variables, SKFunction... pipeline);
|
||||
|
||||
/**
|
||||
* Import a set of skills
|
||||
*
|
||||
* @param skillName
|
||||
* @param skills
|
||||
* @return
|
||||
* @throws SkillsNotFoundException
|
||||
*/
|
||||
ReadOnlyFunctionCollection importSkill(
|
||||
String skillName, Map<String, SemanticFunctionConfig> skills)
|
||||
throws SkillsNotFoundException;
|
||||
|
||||
/**
|
||||
* Get function collection with the skill name
|
||||
*
|
||||
* @param skillName
|
||||
* @return
|
||||
* @throws SkillsNotFoundException
|
||||
*/
|
||||
ReadOnlyFunctionCollection getSkill(String skillName) throws SkillsNotFoundException;
|
||||
|
||||
/**
|
||||
* Imports the native functions annotated on the given object as a skill.
|
||||
*
|
||||
* @param nativeSkill
|
||||
* @param skillName
|
||||
* @return
|
||||
*/
|
||||
ReadOnlyFunctionCollection importSkill(Object nativeSkill, @Nullable String skillName);
|
||||
|
||||
/**
|
||||
* @return Reference to the read-only skill collection containing all the imported functions
|
||||
*/
|
||||
ReadOnlySkillCollection getSkills();
|
||||
|
||||
CompletionSKFunction.Builder getSemanticFunctionBuilder();
|
||||
|
||||
/** Obtains the service with the given name and type */
|
||||
<T> T getService(@Nullable String name, Class<T> clazz) throws KernelException;
|
||||
|
||||
/** Registers a semantic functon on this kernel */
|
||||
<
|
||||
RequestConfiguration,
|
||||
ContextType extends SKContext<ContextType>,
|
||||
FunctionType extends SKFunction<RequestConfiguration, ContextType>>
|
||||
FunctionType registerSemanticFunction(FunctionType semanticFunctionDefinition);
|
||||
|
||||
// <T extends ReadOnlySKContext<T>> T createNewContext();
|
||||
|
||||
class Builder {
|
||||
@Nullable private KernelConfig kernelConfig = null;
|
||||
@Nullable private PromptTemplateEngine promptTemplateEngine = null;
|
||||
|
||||
@Nullable private ReadOnlySkillCollection skillCollection = null;
|
||||
|
||||
public Builder setKernelConfig(KernelConfig kernelConfig) {
|
||||
this.kernelConfig = kernelConfig;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setPromptTemplateEngine(PromptTemplateEngine promptTemplateEngine) {
|
||||
this.promptTemplateEngine = promptTemplateEngine;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setSkillCollection(@Nullable ReadOnlySkillCollection skillCollection) {
|
||||
this.skillCollection = skillCollection;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Kernel build() {
|
||||
if (kernelConfig == null) {
|
||||
throw new IllegalStateException("Must provide a kernel configuration");
|
||||
}
|
||||
|
||||
return BuildersSingleton.INST
|
||||
.getKernelBuilder()
|
||||
.build(kernelConfig, promptTemplateEngine, skillCollection);
|
||||
}
|
||||
}
|
||||
|
||||
interface InternalBuilder {
|
||||
Kernel build(
|
||||
KernelConfig kernelConfig,
|
||||
@Nullable PromptTemplateEngine promptTemplateEngine,
|
||||
@Nullable ReadOnlySkillCollection skillCollection);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel;
|
||||
|
||||
import com.microsoft.semantickernel.ai.embeddings.EmbeddingGeneration;
|
||||
import com.microsoft.semantickernel.orchestration.SKFunction;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public final class KernelConfig {
|
||||
|
||||
private static final String DEFAULT_SERVICE_ID = "__SK_DEFAULT";
|
||||
private final Map<String, Function<Kernel, TextCompletion>> textCompletionServices;
|
||||
|
||||
private final Map<String, Function<Kernel, EmbeddingGeneration<String, Double>>>
|
||||
textEmbeddingGenerationServices;
|
||||
private final ArrayList<SKFunction<?, ?>> skills;
|
||||
|
||||
public KernelConfig(
|
||||
Map<String, Function<Kernel, TextCompletion>> textCompletionServices,
|
||||
Map<String, Function<Kernel, EmbeddingGeneration<String, Double>>>
|
||||
textEmbeddingGenerationServices,
|
||||
List<SKFunction<?, ?>> skills) {
|
||||
this.textCompletionServices = new HashMap<>();
|
||||
this.textCompletionServices.putAll(textCompletionServices);
|
||||
this.textEmbeddingGenerationServices = new HashMap<>(textEmbeddingGenerationServices);
|
||||
this.skills = new ArrayList<>(skills);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Function<Kernel, TextCompletion> getTextCompletionService(String serviceId) {
|
||||
return textCompletionServices.get(serviceId);
|
||||
}
|
||||
|
||||
public List<SKFunction<?, ?>> getSkills() {
|
||||
return Collections.unmodifiableList(skills);
|
||||
}
|
||||
|
||||
public Function<Kernel, TextCompletion> getTextCompletionServiceOrDefault(
|
||||
@Nullable String serviceId) {
|
||||
if (serviceId == null) {
|
||||
serviceId = DEFAULT_SERVICE_ID;
|
||||
}
|
||||
|
||||
if (!this.textCompletionServices.containsKey(serviceId)) {
|
||||
throw new KernelException(
|
||||
KernelException.ErrorCodes.ServiceNotFound,
|
||||
"A text completion service id '" + serviceId + "' doesn't exist");
|
||||
}
|
||||
|
||||
return this.textCompletionServices.get(serviceId);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private Map<String, Function<Kernel, TextCompletion>> textCompletionServices =
|
||||
new HashMap<>();
|
||||
|
||||
private List<SKFunction<?, ?>> skillBuilders = new ArrayList<>();
|
||||
|
||||
private Map<String, Function<Kernel, EmbeddingGeneration<String, Double>>>
|
||||
textEmbeddingGenerationServices = new HashMap<>();
|
||||
|
||||
public Builder addSkill(SKFunction<?, ?> functionDefinition) {
|
||||
skillBuilders.add(functionDefinition);
|
||||
return this;
|
||||
}
|
||||
|
||||
// TODO, is there a need for this to be a factory?
|
||||
public Builder addTextCompletionService(
|
||||
String serviceId, Function<Kernel, TextCompletion> serviceFactory) {
|
||||
if (serviceId == null || serviceId.isEmpty()) {
|
||||
throw new IllegalArgumentException("Null or empty serviceId");
|
||||
}
|
||||
|
||||
textCompletionServices.put(serviceId, serviceFactory);
|
||||
|
||||
if (textCompletionServices.size() == 1) {
|
||||
textCompletionServices.put(DEFAULT_SERVICE_ID, serviceFactory);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addTextEmbeddingsGenerationService(
|
||||
String serviceId,
|
||||
Function<Kernel, EmbeddingGeneration<String, Double>> serviceFactory) {
|
||||
if (serviceId == null || serviceId.isEmpty()) {
|
||||
throw new IllegalArgumentException("Null or empty serviceId");
|
||||
}
|
||||
|
||||
textEmbeddingGenerationServices.put(serviceId, serviceFactory);
|
||||
|
||||
if (textEmbeddingGenerationServices.size() == 1) {
|
||||
textEmbeddingGenerationServices.put(DEFAULT_SERVICE_ID, serviceFactory);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setDefaultTextCompletionService(String serviceId) {
|
||||
if (!this.textCompletionServices.containsKey(serviceId)) {
|
||||
throw new KernelException(
|
||||
KernelException.ErrorCodes.ServiceNotFound,
|
||||
"A text completion service id '" + serviceId + "' doesn't exist");
|
||||
}
|
||||
|
||||
this.textCompletionServices.put(
|
||||
DEFAULT_SERVICE_ID, textCompletionServices.get(serviceId));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public KernelConfig build() {
|
||||
return new KernelConfig(
|
||||
Collections.unmodifiableMap(textCompletionServices),
|
||||
textEmbeddingGenerationServices,
|
||||
skillBuilders);
|
||||
}
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Kernel logic exception */
|
||||
public class KernelException extends RuntimeException {
|
||||
|
||||
@Nonnull private final ErrorCodes errorCode;
|
||||
|
||||
public KernelException(@Nonnull ErrorCodes error) {
|
||||
this(error, null, null);
|
||||
}
|
||||
|
||||
public KernelException(@Nonnull ErrorCodes errorCode, @Nullable String message) {
|
||||
this(errorCode, message, null);
|
||||
}
|
||||
|
||||
public KernelException(
|
||||
@Nonnull ErrorCodes errorCode,
|
||||
@Nullable String message,
|
||||
@Nullable Throwable innerException) {
|
||||
super(getDefaultMessage(errorCode, message), innerException);
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
public ErrorCodes getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/* Translate the error code into a default message */
|
||||
private static String getDefaultMessage(
|
||||
@Nonnull ErrorCodes errorCode, @Nullable String message) {
|
||||
return String.format("%s: %s", errorCode.getMessage(), message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Semantic kernel error codes.
|
||||
/// </summary>
|
||||
public enum ErrorCodes {
|
||||
/// <summary>
|
||||
/// Unknown error.
|
||||
/// </summary>
|
||||
UnknownError("Unknown error"),
|
||||
|
||||
InvalidFunctionDescription("Invalid function description"),
|
||||
|
||||
FunctionOverloadNotSupported("Function overload not supported"),
|
||||
|
||||
FunctionNotAvailable("Function not available"),
|
||||
|
||||
FunctionTypeNotSupported("Function type not supported"),
|
||||
|
||||
InvalidFunctionType("Invalid function type"),
|
||||
|
||||
InvalidServiceConfiguration("Invalid service configuration"),
|
||||
|
||||
ServiceNotFound("Service not found"),
|
||||
|
||||
SkillCollectionNotSet("Skill collection not set"),
|
||||
|
||||
FunctionInvokeError("Represents an error that occurs when invoking a function");
|
||||
|
||||
private final String message;
|
||||
|
||||
ErrorCodes(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel;
|
||||
|
||||
public class SKException extends RuntimeException {}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.ai; // Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** AI logic exception */
|
||||
public class AIException extends RuntimeException {
|
||||
|
||||
@Nonnull private final ErrorCodes errorCode;
|
||||
|
||||
public AIException(@Nonnull ErrorCodes error) {
|
||||
this(error, null, null);
|
||||
}
|
||||
|
||||
public AIException(@Nonnull ErrorCodes errorCode, @Nullable String message) {
|
||||
this(errorCode, message, null);
|
||||
}
|
||||
|
||||
public AIException(
|
||||
@Nonnull ErrorCodes errorCode,
|
||||
@Nullable String message,
|
||||
@Nullable Throwable innerException) {
|
||||
super(getDefaultMessage(errorCode, message), innerException);
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
public ErrorCodes getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/* Translate the error code into a default message */
|
||||
private static String getDefaultMessage(
|
||||
@Nonnull ErrorCodes errorCode, @Nullable String message) {
|
||||
return String.format("%s: %s", errorCode.getMessage(), message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Possible error codes for exceptions
|
||||
/// </summary>
|
||||
public enum ErrorCodes {
|
||||
UnknownError("Unknown error"),
|
||||
|
||||
NoResponse("No response"),
|
||||
|
||||
AccessDenied("Access is denied"),
|
||||
|
||||
InvalidRequest("The request was invalid"),
|
||||
|
||||
InvalidResponseContent("The content of the response was invalid"),
|
||||
|
||||
Throttling("The request was throttled"),
|
||||
|
||||
RequestTimeout("The request timed out"),
|
||||
|
||||
ServiceError("There was an error in the service"),
|
||||
|
||||
ModelNotAvailable("The requested model is not available"),
|
||||
|
||||
InvalidConfiguration("The supplied configuration was invalid"),
|
||||
|
||||
FunctionTypeNotSupported("The function is not supported");
|
||||
private final String message;
|
||||
|
||||
ErrorCodes(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.ai.embeddings;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a strongly typed vector of numeric data.
|
||||
*
|
||||
* @param <EmbeddingType>
|
||||
*/
|
||||
public class Embedding<EmbeddingType extends Number> {
|
||||
|
||||
public List<EmbeddingType> getVector() {
|
||||
return Collections.unmodifiableList(vector);
|
||||
}
|
||||
|
||||
private final List<EmbeddingType> vector;
|
||||
|
||||
// /// <summary>
|
||||
// /// An empty <see cref="Embedding{TEmbedding}"/> instance.
|
||||
// /// </summary>
|
||||
// [SuppressMessage("Design", "CA1000:Do not declare static members on generic types",
|
||||
// Justification = "Static empty struct instance.")]
|
||||
// public static Embedding<TEmbedding> Empty { get; } = new
|
||||
// Embedding<TEmbedding>(Array.Empty<TEmbedding>());
|
||||
|
||||
private static final Embedding<Number> EMPTY =
|
||||
new Embedding(Collections.unmodifiableList(new ArrayList<>()));
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <EmbeddingType extends Number> Embedding<EmbeddingType> empty() {
|
||||
return (Embedding<EmbeddingType>) EMPTY;
|
||||
}
|
||||
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Initializes a new instance of the <see cref="Embedding{TEmbedding}"/> class that
|
||||
// contains numeric elements copied from the specified collection.
|
||||
// /// </summary>
|
||||
// /// <exception cref="ArgumentException">Type <typeparamref name="TEmbedding"/> is
|
||||
// unsupported.</exception>
|
||||
// /// <exception cref="ArgumentNullException">A <c>null</c> vector is passed in.</exception>
|
||||
public Embedding() {
|
||||
this.vector = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the <see cref="Embedding{TEmbedding}"/> class that contains
|
||||
* numeric elements copied from the specified collection
|
||||
*
|
||||
* @param vector
|
||||
*/
|
||||
public Embedding(List<EmbeddingType> vector) {
|
||||
// Verify.NotNull(vector, nameof(vector));
|
||||
this.vector = Collections.unmodifiableList(vector);
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.ai.embeddings; // Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import com.microsoft.openai.OpenAIAsyncClient;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** Interface for text embedding generation services */
|
||||
public interface EmbeddingGeneration<TValue, TEmbedding extends Number> {
|
||||
/**
|
||||
* Generates a list of embeddings associated to the data
|
||||
*
|
||||
* @param data List of texts to generate embeddings for
|
||||
* @return List of embeddings of each data point
|
||||
*/
|
||||
Mono<List<Embedding<TEmbedding>>> generateEmbeddingsAsync(List<TValue> data);
|
||||
|
||||
interface Builder<TValue, TEmbedding extends Number> {
|
||||
EmbeddingGeneration<TValue, TEmbedding> build(OpenAIAsyncClient client, String modelId);
|
||||
}
|
||||
}
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.builders;
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.ai.embeddings.EmbeddingGeneration;
|
||||
import com.microsoft.semantickernel.orchestration.ContextVariables;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplate;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
|
||||
import com.microsoft.semantickernel.templateengine.PromptTemplateEngine;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/** Enum singleton that service loads builder implementations */
|
||||
public enum BuildersSingleton {
|
||||
INST;
|
||||
|
||||
// Fallback classes in case the META-INF/services directory is missing
|
||||
private static final String FALLBACK_FUNCTION_BUILDER_CLASS =
|
||||
"com.microsoft.semantickernel.SkFunctionBuilders";
|
||||
private static final String FALLBACK_KERNEL_BUILDER_CLASS =
|
||||
"com.microsoft.semantickernel.KernelDefaultBuilder";
|
||||
private static final String FALLBACK_TEXT_COMPLETION_BUILDER_CLASS =
|
||||
"com.microsoft.semantickernel.connectors.ai.openai.textcompletion.OpenAITextCompletionBuilder";
|
||||
|
||||
private static final String FALLBACK_TEXT_EMBEDDING_GENERATION_BUILDER_CLASS =
|
||||
"com.microsoft.semantickernel.connectors.ai.openai.textembeddings.OpenAITextEmbeddingGenerationBuilder";
|
||||
private static final String FALLBACK_SKILL_COLLECTION_BUILDER_CLASS =
|
||||
"com.microsoft.semantickernel.skilldefinition.DefaultCollection$Builder";
|
||||
|
||||
private static final String FALLBACK_PROMPT_TEMPLATE_BUILDER_CLASS =
|
||||
"com.microsoft.semantickernel.semanticfunctions.DefaultPromptTemplateBuilder";
|
||||
|
||||
private static final String FALLBACK_VARIABLE_BUILDER_CLASS =
|
||||
"com.microsoft.semantickernel.orchestration.DefaultContextVariables$Builder";
|
||||
|
||||
private static final String FALLBACK_CONTEXT_BUILDER_CLASS =
|
||||
"com.microsoft.semantickernel.orchestration.DefaultSemanticSKContext$Builder";
|
||||
private static final String FALLBACK_PROMPT_TEMPLATE_ENGINE_BUILDER_CLASS =
|
||||
"com.microsoft.semantickernel.templateengine.DefaultPromptTemplateEngine$Builder";
|
||||
|
||||
private final FunctionBuilders functionBuilders;
|
||||
private final Kernel.InternalBuilder kernelBuilder;
|
||||
private final TextCompletion.Builder textCompletionBuilder;
|
||||
private final EmbeddingGeneration.Builder<String, Double> textEmbeddingGenerationBuilder;
|
||||
private final ReadOnlySkillCollection.Builder readOnlySkillCollection;
|
||||
private final PromptTemplate.Builder promptTemplate;
|
||||
private final ContextVariables.Builder variables;
|
||||
private final SKContext.Builder context;
|
||||
private final PromptTemplateEngine.Builder promptTemplateEngine;
|
||||
|
||||
BuildersSingleton() {
|
||||
try {
|
||||
functionBuilders =
|
||||
ServiceLoadUtil.findServiceLoader(
|
||||
FunctionBuilders.class, FALLBACK_FUNCTION_BUILDER_CLASS);
|
||||
|
||||
kernelBuilder =
|
||||
ServiceLoadUtil.findServiceLoader(
|
||||
Kernel.InternalBuilder.class, FALLBACK_KERNEL_BUILDER_CLASS);
|
||||
|
||||
textCompletionBuilder =
|
||||
ServiceLoadUtil.findServiceLoader(
|
||||
TextCompletion.Builder.class, FALLBACK_TEXT_COMPLETION_BUILDER_CLASS);
|
||||
|
||||
textEmbeddingGenerationBuilder =
|
||||
ServiceLoadUtil.findServiceLoader(
|
||||
EmbeddingGeneration.Builder.class,
|
||||
FALLBACK_TEXT_EMBEDDING_GENERATION_BUILDER_CLASS);
|
||||
|
||||
readOnlySkillCollection =
|
||||
ServiceLoadUtil.findServiceLoader(
|
||||
ReadOnlySkillCollection.Builder.class,
|
||||
FALLBACK_SKILL_COLLECTION_BUILDER_CLASS);
|
||||
|
||||
promptTemplate =
|
||||
ServiceLoadUtil.findServiceLoader(
|
||||
PromptTemplate.Builder.class, FALLBACK_PROMPT_TEMPLATE_BUILDER_CLASS);
|
||||
|
||||
variables =
|
||||
ServiceLoadUtil.findServiceLoader(
|
||||
ContextVariables.Builder.class, FALLBACK_VARIABLE_BUILDER_CLASS);
|
||||
|
||||
context =
|
||||
ServiceLoadUtil.findServiceLoader(
|
||||
SKContext.Builder.class, FALLBACK_CONTEXT_BUILDER_CLASS);
|
||||
|
||||
promptTemplateEngine =
|
||||
ServiceLoadUtil.findServiceLoader(
|
||||
PromptTemplateEngine.Builder.class,
|
||||
FALLBACK_PROMPT_TEMPLATE_ENGINE_BUILDER_CLASS);
|
||||
|
||||
} catch (Throwable e) {
|
||||
Logger LOGGER = LoggerFactory.getLogger(BuildersSingleton.class);
|
||||
LOGGER.error("Failed to discover Semantic Kernel Builders", e);
|
||||
LOGGER.error(
|
||||
"This is likely due to:\n\n"
|
||||
+ "- The Semantic Kernel implementation (typically provided by"
|
||||
+ " semantickernel-core) is not present on the classpath at runtime, ensure"
|
||||
+ " that this dependency is available at runtime. In maven this would be"
|
||||
+ " achieved by adding:\n"
|
||||
+ "\n"
|
||||
+ " <dependency>\n"
|
||||
+ " <groupId>com.microsoft.semantickernel</groupId>\n"
|
||||
+ " <artifactId>semantickernel-core</artifactId>\n"
|
||||
+ " <version>${skversion}</version>\n"
|
||||
+ " <scope>runtime</scope>\n"
|
||||
+ " </dependency>\n\n"
|
||||
+ "- The META-INF/services files that define the service loading have been"
|
||||
+ " filtered out and are not present within the running application\n\n"
|
||||
+ "- The class names have been changed (for instance shaded) preventing"
|
||||
+ " discovering the classes");
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public FunctionBuilders getFunctionBuilders() {
|
||||
return functionBuilders;
|
||||
}
|
||||
|
||||
public Kernel.InternalBuilder getKernelBuilder() {
|
||||
return kernelBuilder;
|
||||
}
|
||||
|
||||
public TextCompletion.Builder getTextCompletionBuilder() {
|
||||
return textCompletionBuilder;
|
||||
}
|
||||
|
||||
public EmbeddingGeneration.Builder<String, Double> getTextEmbeddingGenerationBuilder() {
|
||||
return textEmbeddingGenerationBuilder;
|
||||
}
|
||||
|
||||
public ReadOnlySkillCollection.Builder getReadOnlySkillCollection() {
|
||||
return readOnlySkillCollection;
|
||||
}
|
||||
|
||||
public PromptTemplate.Builder getPromptTemplateBuilder() {
|
||||
return promptTemplate;
|
||||
}
|
||||
|
||||
public PromptTemplateEngine.Builder getPromptTemplateEngineBuilder() {
|
||||
return promptTemplateEngine;
|
||||
}
|
||||
|
||||
public ContextVariables.Builder variables() {
|
||||
return variables;
|
||||
}
|
||||
|
||||
public SKContext.Builder context() {
|
||||
return context;
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.builders;
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Provides various builders for completion functions */
|
||||
public interface FunctionBuilders {
|
||||
|
||||
static CompletionSKFunction.Builder getCompletionBuilder() {
|
||||
return getCompletionBuilder(null);
|
||||
}
|
||||
|
||||
static CompletionSKFunction.Builder getCompletionBuilder(@Nullable Kernel kernel) {
|
||||
return BuildersSingleton.INST.getFunctionBuilders().completionBuilders(kernel);
|
||||
}
|
||||
|
||||
CompletionSKFunction.Builder completionBuilders(@Nullable Kernel kernel);
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.builders;
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.KernelConfig;
|
||||
import com.microsoft.semantickernel.ai.embeddings.EmbeddingGeneration;
|
||||
import com.microsoft.semantickernel.orchestration.ContextVariables;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplate;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
|
||||
import com.microsoft.semantickernel.templateengine.PromptTemplateEngine;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
|
||||
public class SKBuilders {
|
||||
|
||||
public static CompletionSKFunction.Builder completionFunctions() {
|
||||
return FunctionBuilders.getCompletionBuilder();
|
||||
}
|
||||
|
||||
public static TextCompletion.Builder textCompletionService() {
|
||||
return BuildersSingleton.INST.getTextCompletionBuilder();
|
||||
}
|
||||
|
||||
public static EmbeddingGeneration.Builder<String, Double> textEmbeddingGenerationService() {
|
||||
return BuildersSingleton.INST.getTextEmbeddingGenerationBuilder();
|
||||
}
|
||||
|
||||
public static Kernel.Builder kernel() {
|
||||
return new Kernel.Builder();
|
||||
}
|
||||
|
||||
public static KernelConfig.Builder kernelConfig() {
|
||||
return new KernelConfig.Builder();
|
||||
}
|
||||
|
||||
public static ReadOnlySkillCollection.Builder skillCollection() {
|
||||
return BuildersSingleton.INST.getReadOnlySkillCollection();
|
||||
}
|
||||
|
||||
public static PromptTemplate.Builder promptTemplate() {
|
||||
return BuildersSingleton.INST.getPromptTemplateBuilder();
|
||||
}
|
||||
|
||||
public static PromptTemplateEngine.Builder promptTemplateEngine() {
|
||||
return BuildersSingleton.INST.getPromptTemplateEngineBuilder();
|
||||
}
|
||||
|
||||
public static ContextVariables.Builder variables() {
|
||||
return BuildersSingleton.INST.variables();
|
||||
}
|
||||
|
||||
public static SKContext.Builder context() {
|
||||
return BuildersSingleton.INST.context();
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.builders;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
public class ServiceLoadUtil {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ServiceLoadUtil.class);
|
||||
|
||||
public static <T> T findServiceLoader(Class<T> clazz, String alternativeClassName) {
|
||||
List<T> services = findAllServiceLoaders(clazz);
|
||||
if (services.size() > 0) {
|
||||
return services.get(0);
|
||||
}
|
||||
|
||||
try {
|
||||
// Service loader not found, attempt to load the alternative class
|
||||
Object instance =
|
||||
Class.forName(alternativeClassName).getDeclaredConstructor().newInstance();
|
||||
if (clazz.isInstance(instance)) {
|
||||
return (T) instance;
|
||||
}
|
||||
} catch (ClassNotFoundException
|
||||
| InvocationTargetException
|
||||
| InstantiationException
|
||||
| IllegalAccessException
|
||||
| NoSuchMethodException
|
||||
| RuntimeException e) {
|
||||
LOGGER.error("Unable to load service " + clazz.getName() + " ", e);
|
||||
}
|
||||
|
||||
throw new RuntimeException("Service not found: " + clazz.getName());
|
||||
}
|
||||
|
||||
static <T> List<T> findAllServiceLoaders(Class<T> clazz) {
|
||||
List<T> serviceLoaders = new ArrayList<T>();
|
||||
|
||||
ServiceLoader<T> factory = ServiceLoader.load(clazz);
|
||||
Iterator<T> iterator = factory.iterator();
|
||||
iterator.forEachRemaining(serviceLoaders::add);
|
||||
|
||||
return serviceLoaders;
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.diagnostics;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Provides the base exception from which all Semantic Kernel exceptions derive. */
|
||||
public class SKException extends RuntimeException {
|
||||
|
||||
/** Initializes a new instance of the {@code SKException} class with a default message. */
|
||||
protected SKException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the {@code SKException} class with its message set to {@code
|
||||
* message}.
|
||||
*
|
||||
* @param message A string that describes the error.
|
||||
*/
|
||||
protected SKException(@Nullable String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the {@code SKException} class with its message set to {@code
|
||||
* message}.
|
||||
*
|
||||
* @param message A string that describes the error.
|
||||
* @param cause The exception that is the cause of the current exception.
|
||||
*/
|
||||
protected SKException(@Nullable String message, @Nullable Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.exceptions;
|
||||
|
||||
public class NotSupportedException extends RuntimeException {
|
||||
public NotSupportedException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.exceptions;
|
||||
|
||||
public class SkillsNotFoundException extends RuntimeException {}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.extensions;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplate;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.semanticfunctions.SemanticFunctionConfig;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class KernelExtensions {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(KernelExtensions.class);
|
||||
|
||||
public static Map<String, SemanticFunctionConfig> importSemanticSkillFromDirectory(
|
||||
String parentDirectory, String skillDirectoryName) {
|
||||
|
||||
String CONFIG_FILE = "config.json";
|
||||
String PROMPT_FILE = "skprompt.txt";
|
||||
|
||||
// Verify.ValidSkillName(skillDirectoryName);
|
||||
File skillDir = new File(parentDirectory, skillDirectoryName);
|
||||
// Verify.DirectoryExists(skillDir);
|
||||
|
||||
File[] files = skillDir.listFiles();
|
||||
if (files == null) {
|
||||
return Collections.unmodifiableMap(new HashMap<>());
|
||||
}
|
||||
|
||||
HashMap<String, SemanticFunctionConfig> skills = new HashMap<>();
|
||||
|
||||
for (File dir : files) {
|
||||
try {
|
||||
// Continue only if prompt template exists
|
||||
File promptPath = new File(dir, PROMPT_FILE);
|
||||
if (!promptPath.exists()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Load prompt configuration. Note: the configuration is
|
||||
// optional.
|
||||
PromptTemplateConfig config = new PromptTemplateConfig("", "", null);
|
||||
|
||||
File configPath = new File(dir, CONFIG_FILE);
|
||||
if (configPath.exists()) {
|
||||
config = new ObjectMapper().readValue(configPath, PromptTemplateConfig.class);
|
||||
|
||||
// Verify.NotNull(config, $"Invalid prompt template
|
||||
// configuration, unable to parse {configPath}");
|
||||
}
|
||||
|
||||
// kernel.Log.LogTrace("Config {0}: {1}", functionName,
|
||||
// config.ToJson());
|
||||
|
||||
// Load prompt template
|
||||
PromptTemplate template =
|
||||
SKBuilders.promptTemplate()
|
||||
.build(
|
||||
new String(
|
||||
Files.readAllBytes(promptPath.toPath()),
|
||||
Charset.defaultCharset()),
|
||||
config);
|
||||
|
||||
skills.put(dir.getName(), new SemanticFunctionConfig(config, template));
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Failed to read file", e);
|
||||
}
|
||||
}
|
||||
|
||||
return skills;
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.memory;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** A base class for data entries. */
|
||||
public class DataEntryBase {
|
||||
@Nonnull private final String key;
|
||||
@Nullable private final ZonedDateTime timestamp;
|
||||
|
||||
/**
|
||||
* Creates an instance of a {@code DataEntryBase}.
|
||||
*
|
||||
* @param key The key of the data.
|
||||
* @param timestamp The timestamp of the data.
|
||||
*/
|
||||
public DataEntryBase(@Nullable String key, @Nullable ZonedDateTime timestamp) {
|
||||
this.key = key != null ? key : "";
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the key of the data.
|
||||
*
|
||||
* @return The key of the data
|
||||
*/
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the timestamp of the data.
|
||||
*
|
||||
* @return The timestamp of the data.
|
||||
*/
|
||||
@Nullable
|
||||
public ZonedDateTime getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the data has a timestamp.
|
||||
*
|
||||
* @return {@code true} if the data has a timestamp; otherwise, {@code false}.
|
||||
*/
|
||||
public boolean hasTimestamp() {
|
||||
return timestamp != null;
|
||||
}
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.memory;
|
||||
|
||||
import com.microsoft.semantickernel.diagnostics.SKException;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Exception thrown for errors related to memory logic. */
|
||||
public class MemoryException extends SKException {
|
||||
@Nonnull private final ErrorCodes errorCode;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the {@code MemoryException} class with a provided error code.
|
||||
*
|
||||
* @param error The error code.
|
||||
*/
|
||||
public MemoryException(@Nonnull ErrorCodes error) {
|
||||
this(error, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the {@code MemoryException} class with a provided error code
|
||||
* and message.
|
||||
*
|
||||
* @param errorCode The error code.
|
||||
* @param message A string that describes the error.
|
||||
*/
|
||||
public MemoryException(@Nonnull ErrorCodes errorCode, @Nullable String message) {
|
||||
this(errorCode, message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the {@code MemoryException} class with a provided error code,
|
||||
* message, and inner exception.
|
||||
*
|
||||
* @param errorCode The error code.
|
||||
* @param message A string that describes the error.
|
||||
* @param innerException The exception that is the cause of the current exception.
|
||||
*/
|
||||
public MemoryException(
|
||||
@Nonnull ErrorCodes errorCode,
|
||||
@Nullable String message,
|
||||
@Nullable Throwable innerException) {
|
||||
super(getDefaultMessage(errorCode, message), innerException);
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the error code for this exception.
|
||||
*
|
||||
* @return The error code for this exception.
|
||||
*/
|
||||
public ErrorCodes getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/* Translate the error code into a default message */
|
||||
private static String getDefaultMessage(
|
||||
@Nonnull ErrorCodes errorCode, @Nullable String message) {
|
||||
return String.format("%s: %s", errorCode.getMessage(), message);
|
||||
}
|
||||
|
||||
/** Semantic kernel memory error codes. */
|
||||
public enum ErrorCodes {
|
||||
/** Unknown error. */
|
||||
UNKNOWN("Unknown error"),
|
||||
|
||||
/** Failed to create collection. */
|
||||
FAILED_TO_CREATE_COLLECTION("Failed to create collection"),
|
||||
|
||||
/** Failed to delete collection. */
|
||||
FAILED_TO_DELETE_COLLECTION("Failed to delete collection"),
|
||||
|
||||
/** Unable to construct memory from serialized metadata. */
|
||||
UNABLE_TO_DESERIALIZE_METADATA("Unable to deserialize metadata"),
|
||||
|
||||
/** Attempted to access a memory collection that does not exist. */
|
||||
ATTEMPTED_TO_ACCESS_NONEXISTENT_COLLECTION("Attempted to access non-existent collection");
|
||||
|
||||
/**
|
||||
* Gets the error message.
|
||||
*
|
||||
* @return The error message.
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
private ErrorCodes(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
private final String message;
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.memory;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/** Copy of metadata associated with a memory entry. */
|
||||
public class MemoryQueryResult {
|
||||
/**
|
||||
* Whether the source data used to calculate embeddings are stored in the local storage provider
|
||||
* or is available through an external service, such as website, MS Graph, etc.
|
||||
*/
|
||||
@Nonnull private final MemoryRecordMetadata metadata;
|
||||
|
||||
/** Search relevance, from 0 to 1, where 1 means perfect match. */
|
||||
private final double relevance;
|
||||
|
||||
/**
|
||||
* Create a new instance of MemoryQueryResult
|
||||
*
|
||||
* @param metadata Whether the source data used to calculate embeddings are stored in the local
|
||||
* storage provider or is available through an external service, such as website, MS Graph,
|
||||
* etc.
|
||||
* @param relevance Search relevance, from 0 to 1, where 1 means perfect match.
|
||||
*/
|
||||
public MemoryQueryResult(@Nonnull MemoryRecordMetadata metadata, double relevance) {
|
||||
this.metadata = metadata;
|
||||
this.relevance = clampRelevance(relevance);
|
||||
}
|
||||
|
||||
public MemoryRecordMetadata getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public double getRelevance() {
|
||||
return relevance;
|
||||
}
|
||||
|
||||
// function to clamp relevance to [0, 1]
|
||||
private static double clampRelevance(double relevance) {
|
||||
return !Double.isNaN(relevance) ? Math.max(0, Math.min(1, relevance)) : 0d;
|
||||
}
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Create a new instance of MemoryQueryResult from a json string representing MemoryRecord metadata.
|
||||
/// </summary>
|
||||
/// <param name="json">The json string to deserialize.</param>
|
||||
/// <param name="relevance">The similarity score associated with the result.</param>
|
||||
/// <returns>A new instance of MemoryQueryResult.</returns>
|
||||
/// <exception cref="MemoryException"></exception>
|
||||
public static MemoryQueryResult FromJsonMetadata(
|
||||
string json,
|
||||
double relevance)
|
||||
{
|
||||
var metadata = JsonSerializer.Deserialize<MemoryRecordMetadata>(json);
|
||||
if (metadata != null)
|
||||
{
|
||||
return new MemoryQueryResult(metadata, relevance);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new MemoryException(
|
||||
MemoryException.ErrorCodes.UnableToDeserializeMetadata,
|
||||
"Unable to create memory query result from serialized metadata");
|
||||
}
|
||||
}
|
||||
|
||||
internal static MemoryQueryResult FromMemoryRecord(
|
||||
MemoryRecord rec,
|
||||
double relevance)
|
||||
{
|
||||
return new MemoryQueryResult(
|
||||
(MemoryRecordMetadata)rec.Metadata.Clone(),
|
||||
relevance);
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.memory;
|
||||
|
||||
import com.microsoft.semantickernel.ai.embeddings.Embedding;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A record in a Semantic Kernel memory. IMPORTANT: this is a storage schema. Changing the fields
|
||||
* will invalidate existing metadata stored in persistent vector DBs.
|
||||
*/
|
||||
public class MemoryRecord extends DataEntryBase {
|
||||
@Nonnull private final Embedding<Float> embedding;
|
||||
|
||||
@Nonnull private final MemoryRecordMetadata metadata;
|
||||
|
||||
/**
|
||||
* Creates an instance of a {@code MemoryRecord}.
|
||||
*
|
||||
* @param metadata The metadata associated with a Semantic Kernel memory.
|
||||
* @param embedding The source content embeddings.
|
||||
* @param key The key of the data.
|
||||
* @param timestamp The timestamp of the data.
|
||||
*/
|
||||
public MemoryRecord(
|
||||
@Nonnull MemoryRecordMetadata metadata,
|
||||
@Nonnull Embedding<Float> embedding,
|
||||
@Nullable String key,
|
||||
@Nullable ZonedDateTime timestamp) {
|
||||
super(key, timestamp);
|
||||
this.metadata = metadata;
|
||||
this.embedding = embedding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the source content embeddings.
|
||||
*
|
||||
* @return The source content embeddings.
|
||||
*/
|
||||
public Embedding<Float> getEmbedding() {
|
||||
return embedding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the metadata associated with a Semantic Kernel memory.
|
||||
*
|
||||
* @return The metadata associated with a Semantic Kernel memory.
|
||||
*/
|
||||
public MemoryRecordMetadata getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an instance about a memory which source is stored externally. The universal resource
|
||||
* identifies points to the URL (or equivalent) to find the original source.
|
||||
*
|
||||
* @param externalId URL (or equivalent) to find the original source.
|
||||
* @param sourceName Name of the external service, e.g. "MSTeams", "GitHub", "WebSite", "Outlook
|
||||
* IMAP", etc.
|
||||
* @param description Optional description of the record. Note: the description is not indexed.
|
||||
* @param embedding Source content embedding.
|
||||
* @param additionalMetadata Optional string for saving custom metadata.
|
||||
* @param key Optional existing database key.
|
||||
* @param timestamp optional timestamp.
|
||||
* @return Memory record
|
||||
*/
|
||||
public static MemoryRecord referenceRecord(
|
||||
@Nonnull String externalId,
|
||||
@Nonnull String sourceName,
|
||||
@Nullable String description,
|
||||
@Nonnull Embedding<Float> embedding,
|
||||
@Nullable String additionalMetadata,
|
||||
@Nullable String key,
|
||||
@Nullable ZonedDateTime timestamp) {
|
||||
|
||||
MemoryRecordMetadata metadata =
|
||||
new MemoryRecordMetadata(
|
||||
true,
|
||||
externalId,
|
||||
"",
|
||||
description != null ? description : "",
|
||||
sourceName,
|
||||
additionalMetadata != null ? additionalMetadata : "");
|
||||
return new MemoryRecord(metadata, embedding, key, timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an instance for a memory stored in the internal storage provider.
|
||||
*
|
||||
* @param id Resource identifier within the storage provider, e.g. record ID/GUID/incremental
|
||||
* counter etc.
|
||||
* @param text Full text used to generate the embeddings.
|
||||
* @param description Optional description of the record. Note: the description is not indexed.
|
||||
* @param embedding Source content embedding.
|
||||
* @param additionalMetadata Optional string for saving custom metadata.
|
||||
* @param key Optional existing database key.
|
||||
* @param timestamp optional timestamp.
|
||||
* @return Memory record
|
||||
*/
|
||||
public static MemoryRecord localRecord(
|
||||
@Nonnull String id,
|
||||
@Nonnull String text,
|
||||
@Nullable String description,
|
||||
@Nonnull Embedding<Float> embedding,
|
||||
@Nullable String additionalMetadata,
|
||||
@Nullable String key,
|
||||
@Nullable ZonedDateTime timestamp) {
|
||||
|
||||
boolean isReference = true;
|
||||
String emptyString = "";
|
||||
MemoryRecordMetadata metadata =
|
||||
new MemoryRecordMetadata(
|
||||
isReference,
|
||||
id,
|
||||
text,
|
||||
description != null ? description : emptyString,
|
||||
emptyString,
|
||||
additionalMetadata != null ? additionalMetadata : emptyString);
|
||||
return new MemoryRecord(metadata, embedding, key, timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a memory record from a memory record's metadata.
|
||||
*
|
||||
* @param metadata Metadata associated with a memory.
|
||||
* @param embedding Optional embedding associated with a memory record.
|
||||
* @param key Optional existing database key.
|
||||
* @param timestamp optional timestamp.
|
||||
* @return Memory record
|
||||
*/
|
||||
public static MemoryRecord fromMetadata(
|
||||
@Nonnull MemoryRecordMetadata metadata,
|
||||
@Nullable Embedding<Float> embedding,
|
||||
@Nullable String key,
|
||||
@Nullable ZonedDateTime timestamp) {
|
||||
return new MemoryRecord(
|
||||
metadata, embedding != null ? embedding : Embedding.empty(), key, timestamp);
|
||||
}
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Create a memory record from a serialized metadata string.
|
||||
/// </summary>
|
||||
/// <param name="json">Json string representing a memory record's metadata.</param>
|
||||
/// <param name="embedding">Optional embedding associated with a memory record.</param>
|
||||
/// <param name="key">Optional existing database key.</param>
|
||||
/// <param name="timestamp">optional timestamp.</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="MemoryException"></exception>
|
||||
public static MemoryRecord FromJsonMetadata(
|
||||
string json,
|
||||
Embedding<float>? embedding,
|
||||
string? key = null,
|
||||
DateTimeOffset? timestamp = null)
|
||||
{
|
||||
var metadata = JsonSerializer.Deserialize<MemoryRecordMetadata>(json);
|
||||
if (metadata != null)
|
||||
{
|
||||
return new MemoryRecord(metadata, embedding ?? Embedding<float>.Empty, key, timestamp);
|
||||
}
|
||||
|
||||
throw new MemoryException(
|
||||
MemoryException.ErrorCodes.UnableToDeserializeMetadata,
|
||||
"Unable to create memory record from serialized metadata");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serialize the metadata of a memory record.
|
||||
/// </summary>
|
||||
/// <returns>The memory record's metadata serialized to a json string.</returns>
|
||||
public string GetSerializedMetadata()
|
||||
{
|
||||
return JsonSerializer.Serialize(this.Metadata);
|
||||
}
|
||||
*/
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.memory;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/** Class representing the metadata associated with a Semantic Kernel memory. */
|
||||
public class MemoryRecordMetadata {
|
||||
|
||||
@Nonnull private final boolean isReference;
|
||||
@Nonnull private final String externalSourceName;
|
||||
@Nonnull private final String id;
|
||||
@Nonnull private final String description;
|
||||
@Nonnull private final String text;
|
||||
@Nonnull private final String additionalMetadata;
|
||||
|
||||
/**
|
||||
* Whether the source data used to calculate embeddings are stored in the local storage provider
|
||||
* or is available through and external service, such as web site, MS Graph, etc.
|
||||
*/
|
||||
public boolean isReference() {
|
||||
return isReference;
|
||||
}
|
||||
|
||||
/**
|
||||
* A value used to understand which external service owns the data, to avoid storing the
|
||||
* information inside the URI. E.g. this could be "MSTeams", "WebSite", "GitHub", etc.
|
||||
*
|
||||
* @return Name of the external service if isReference is true.
|
||||
*/
|
||||
public String getExternalSourceName() {
|
||||
return externalSourceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unique identifier. The format of the value is domain specific, so it can be a URL, a GUID,
|
||||
* etc.
|
||||
*
|
||||
* @return Unique string used to identify the {@code MemoryRecord}.
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional title describing the content. Note: the title is not indexed.
|
||||
*
|
||||
* @return the optional title describing the content.
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Source text, available only when the memory is not an external source.
|
||||
*
|
||||
* @return Source text when the memory is not an external source.
|
||||
*/
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom metadata associated with a memory.
|
||||
*
|
||||
* @return Custom metadata associated with a memory.
|
||||
*/
|
||||
public String getAdditionalMetadata() {
|
||||
return additionalMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param isReference True if source data is local, false if source data comes from an external
|
||||
* service.
|
||||
* @param id Unique string used to identify the {@code MemoryRecord}.
|
||||
* @param text Local source data associated with a {@code MemoryRecord} embedding.
|
||||
* @param description {@code MemoryRecord} description.
|
||||
* @param externalSourceName Name of the external source if isReference is true.
|
||||
* @param additionalMetadata Field for saving custom metadata with a memory.
|
||||
*/
|
||||
public MemoryRecordMetadata(
|
||||
boolean isReference,
|
||||
@Nonnull String id,
|
||||
@Nonnull String text,
|
||||
@Nonnull String description,
|
||||
@Nonnull String externalSourceName,
|
||||
@Nonnull String additionalMetadata) {
|
||||
this.isReference = isReference;
|
||||
this.id = id;
|
||||
this.text = text;
|
||||
this.description = description;
|
||||
this.externalSourceName = externalSourceName;
|
||||
this.additionalMetadata = additionalMetadata;
|
||||
}
|
||||
}
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.memory;
|
||||
|
||||
import com.microsoft.semantickernel.ai.embeddings.Embedding;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.function.Tuple2;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/** An interface for storing and retrieving indexed {@link MemoryRecord} objects in a data store. */
|
||||
public interface MemoryStore {
|
||||
|
||||
/**
|
||||
* Creates a new collection in the data store.
|
||||
*
|
||||
* @param collectionName The name associated with a collection of embeddings
|
||||
* @return A future that completes when the collection is created.
|
||||
*/
|
||||
Mono<Void> createCollectionAsync(@Nonnull String collectionName);
|
||||
|
||||
/**
|
||||
* Gets all collection names in the data store.
|
||||
*
|
||||
* @return An unmodifiable group of collection names.
|
||||
*/
|
||||
Mono<Collection<String>> getCollectionsAsync();
|
||||
|
||||
/**
|
||||
* Determines if a collection exists in the data store.
|
||||
*
|
||||
* @param collectionName The name associated with a collection of embeddings.
|
||||
* @return A future that completes with a boolean indicating whether the collection exists.
|
||||
*/
|
||||
Mono<Boolean> doesCollectionExistAsync(@Nonnull String collectionName);
|
||||
|
||||
/**
|
||||
* Deletes a collection from the data store.
|
||||
*
|
||||
* @param collectionName The name associated with a collection of embeddings.
|
||||
* @return
|
||||
*/
|
||||
Mono<Void> deleteCollectionAsync(@Nonnull String collectionName);
|
||||
|
||||
/**
|
||||
* Upserts a memory record into the data store. Does not guarantee that the collection exists.
|
||||
* If the record already exists, it will be updated. If the record does not exist, it will be
|
||||
* created.
|
||||
*
|
||||
* @param collectionName The name associated with a collection of embeddings.
|
||||
* @param record The memory record to upsert.
|
||||
* @return The unique identifier for the memory record.
|
||||
*/
|
||||
Mono<String> upsertAsync(@Nonnull String collectionName, @Nonnull MemoryRecord record);
|
||||
|
||||
/**
|
||||
* Upserts a group of memory records into the data store. Does not guarantee that the collection
|
||||
* exists. If the record already exists, it will be updated. If the record does not exist, it
|
||||
* will be created.
|
||||
*
|
||||
* @param collectionName The name associated with a collection of vectors.
|
||||
* @param records The memory records to upsert.
|
||||
* @return The unique identifiers for the memory records.
|
||||
*/
|
||||
Mono<Collection<String>> upsertBatchAsync(
|
||||
@Nonnull String collectionName, @Nonnull Collection<MemoryRecord> records);
|
||||
|
||||
/**
|
||||
* Gets a memory record from the data store. Does not guarantee that the collection exists.
|
||||
*
|
||||
* @param collectionName The name associated with a collection of embeddings.
|
||||
* @param key The unique id associated with the memory record to get.
|
||||
* @param withEmbedding If true, the embedding will be returned in the memory record.
|
||||
* @return The memory record if found, otherwise null.
|
||||
*/
|
||||
Mono<MemoryRecord> getAsync(
|
||||
@Nonnull String collectionName, @Nonnull String key, boolean withEmbedding);
|
||||
|
||||
/**
|
||||
* Gets a batch of memory records from the data store. Does not guarantee that the collection
|
||||
* exists.
|
||||
*
|
||||
* @param collectionName The name associated with a collection of embedding.
|
||||
* @param keys The unique ids associated with the memory record to get.
|
||||
* @param withEmbeddings If true, the embeddings will be returned in the memory records.
|
||||
* @return The memory records associated with the unique keys provided.
|
||||
*/
|
||||
Mono<Collection<MemoryRecord>> getBatchAsync(
|
||||
@Nonnull String collectionName,
|
||||
@Nonnull Collection<String> keys,
|
||||
boolean withEmbeddings);
|
||||
|
||||
/**
|
||||
* Removes a memory record from the data store. Does not guarantee that the collection exists.
|
||||
*
|
||||
* @param collectionName The name associated with a collection of embeddings.
|
||||
* @param key The unique id associated with the memory record to remove.
|
||||
* @return A {@link Mono} that completes when the operation is done.
|
||||
*/
|
||||
Mono<Void> removeAsync(@Nonnull String collectionName, @Nonnull String key);
|
||||
|
||||
/**
|
||||
* Removes a batch of memory records from the data store. Does not guarantee that the collection
|
||||
* exists.
|
||||
*
|
||||
* @param collectionName The name associated with a collection of embeddings.
|
||||
* @param keys The unique ids associated with the memory record to remove.
|
||||
* @return A {@link Mono} that completes when the operation is done.
|
||||
*/
|
||||
Mono<Void> removeBatchAsync(@Nonnull String collectionName, @Nonnull Collection<String> keys);
|
||||
|
||||
/**
|
||||
* Gets the nearest matches to the {@link Embedding} of type {@code Float}. Does not guarantee
|
||||
* that the collection exists.
|
||||
*
|
||||
* @param collectionName The name associated with a collection of embeddings.
|
||||
* @param embedding The {@link Embedding} to compare the collection's embeddings with.
|
||||
* @param limit The maximum number of similarity results to return.
|
||||
* @param minRelevanceScore The minimum relevance threshold for returned results.
|
||||
* @param withEmbeddings If true, the embeddings will be returned in the memory records.
|
||||
* @return A collection of tuples where item1 is a {@link MemoryRecord} and item2 is its
|
||||
* similarity score as a {@code double}.
|
||||
*/
|
||||
Mono<Collection<Tuple2<MemoryRecord, Double>>> getNearestMatchesAsync(
|
||||
@Nonnull String collectionName,
|
||||
@Nonnull Embedding<Float> embedding,
|
||||
int limit,
|
||||
double minRelevanceScore,
|
||||
boolean withEmbeddings);
|
||||
|
||||
/**
|
||||
* Gets the nearest match to the {@link Embedding} of type {@code Float}. Does not guarantee
|
||||
* that the collection exists.
|
||||
*
|
||||
* @param collectionName The name associated with a collection of embeddings.
|
||||
* @param embedding The {@link Embedding} to compare the collection's embeddings with.
|
||||
* @param minRelevanceScore The minimum relevance threshold for returned results.
|
||||
* @param withEmbedding If true, the embedding will be returned in the memory record.
|
||||
* @return A tuple consisting of the {@link MemoryRecord} and item2 is its similarity score as a
|
||||
* {@code double}. Null if no nearest match found.
|
||||
*/
|
||||
Mono<Tuple2<MemoryRecord, Double>> getNearestMatchAsync(
|
||||
@Nonnull String collectionName,
|
||||
@Nonnull Embedding<Float> embedding,
|
||||
double minRelevanceScore,
|
||||
boolean withEmbedding);
|
||||
}
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.memory; // Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.CheckReturnValue;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Implementation of {@link SemanticTextMemory} that stores nothing. */
|
||||
public final class NullMemory implements SemanticTextMemory {
|
||||
|
||||
private static final NullMemory DEFAULT = new NullMemory();
|
||||
|
||||
/**
|
||||
* Gets the singleton instance of {@code }NullMemory}.
|
||||
*
|
||||
* @return The singleton instance of {@code NullMemory}.
|
||||
*/
|
||||
public static NullMemory getInstance() {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
private static final String EMPTY_STRING = "";
|
||||
|
||||
@Override
|
||||
@CheckReturnValue
|
||||
public SemanticTextMemory copy() {
|
||||
return new NullMemory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<String> saveInformationAsync(
|
||||
@Nonnull String collection,
|
||||
@Nonnull String text,
|
||||
@Nonnull String externalId,
|
||||
@Nullable String description,
|
||||
@Nullable String additionalMetadata) {
|
||||
return Mono.just(EMPTY_STRING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<String> saveReferenceAsync(
|
||||
@Nonnull String collection,
|
||||
@Nonnull String text,
|
||||
@Nonnull String externalId,
|
||||
@Nonnull String externalSourceName,
|
||||
@Nullable String description,
|
||||
@Nullable String additionalMetadata) {
|
||||
return Mono.just(EMPTY_STRING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<MemoryQueryResult> getAsync(String collection, String key, boolean withEmbedding) {
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> removeAsync(@Nonnull String collection, @Nonnull String key) {
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<List<MemoryQueryResult>> searchAsync(
|
||||
@Nonnull String collection,
|
||||
@Nonnull String query,
|
||||
int limit,
|
||||
double minRelevanceScore,
|
||||
boolean withEmbeddings) {
|
||||
return Mono.just(Collections.emptyList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<List<String>> getCollectionsAsync() {
|
||||
return Mono.just(Collections.emptyList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SemanticTextMemory merge(MemoryQueryResult b) {
|
||||
return this;
|
||||
}
|
||||
/*
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<string> SaveInformationAsync(
|
||||
string collection,
|
||||
string text,
|
||||
string id,
|
||||
string? description = null,
|
||||
string? additionalMetadata = null,
|
||||
CancellationToken cancel = default)
|
||||
{
|
||||
return Task.FromResult(string.Empty);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<string> SaveReferenceAsync(
|
||||
string collection,
|
||||
string text,
|
||||
string externalId,
|
||||
string externalSourceName,
|
||||
string? description = null,
|
||||
string? additionalMetadata = null,
|
||||
CancellationToken cancel = default)
|
||||
{
|
||||
return Task.FromResult(string.Empty);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<MemoryQueryResult?> GetAsync(
|
||||
string collection,
|
||||
string key,
|
||||
bool withEmbedding = false,
|
||||
CancellationToken cancel = default)
|
||||
{
|
||||
return Task.FromResult(null as MemoryQueryResult);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task RemoveAsync(
|
||||
string collection,
|
||||
string key,
|
||||
CancellationToken cancel = default)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IAsyncEnumerable<MemoryQueryResult> SearchAsync(
|
||||
string collection,
|
||||
string query,
|
||||
int limit = 1,
|
||||
double minRelevanceScore = 0.7,
|
||||
bool withEmbeddings = false,
|
||||
CancellationToken cancel = default)
|
||||
{
|
||||
return AsyncEnumerable.Empty<MemoryQueryResult>();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IList<string>> GetCollectionsAsync(
|
||||
CancellationToken cancel = default)
|
||||
{
|
||||
return Task.FromResult(new List<string>() as IList<string>);
|
||||
}
|
||||
|
||||
private NullMemory()
|
||||
{
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.memory;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.CheckReturnValue;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** An interface for semantic memory that creates and recalls memories associated with text. */
|
||||
public interface SemanticTextMemory {
|
||||
|
||||
@CheckReturnValue
|
||||
SemanticTextMemory copy();
|
||||
|
||||
/**
|
||||
* Save some information into the semantic memory, keeping a copy of the source information.
|
||||
*
|
||||
* @param collection Collection where to save the information.
|
||||
* @param text Information to save.
|
||||
* @param externalId Unique identifier, e.g. URL or GUID to the original source.
|
||||
* @param description Optional description.
|
||||
* @param additionalMetadata Optional string for saving custom metadata.
|
||||
* @return Unique identifier of the saved memory record.
|
||||
*/
|
||||
public Mono<String> saveInformationAsync(
|
||||
@Nonnull String collection,
|
||||
@Nonnull String text,
|
||||
@Nonnull String externalId,
|
||||
@Nullable String description,
|
||||
@Nullable String additionalMetadata);
|
||||
|
||||
/**
|
||||
* Save some information into the semantic memory, keeping only a reference to the source
|
||||
* information.
|
||||
*
|
||||
* @param collection Collection where to save the information.
|
||||
* @param text Information to save.
|
||||
* @param externalId Unique identifier, e.g. URL or GUID to the original source.
|
||||
* @param externalSourceName Name of the external service, e.g. "MSTeams", "GitHub", "WebSite",
|
||||
* "Outlook IMAP", etc.
|
||||
* @param description Optional description.
|
||||
* @param additionalMetadata Optional string for saving custom metadata.
|
||||
* @return Unique identifier of the saved memory record.
|
||||
*/
|
||||
public Mono<String> saveReferenceAsync(
|
||||
@Nonnull String collection,
|
||||
@Nonnull String text,
|
||||
@Nonnull String externalId,
|
||||
@Nonnull String externalSourceName,
|
||||
@Nullable String description,
|
||||
@Nullable String additionalMetadata);
|
||||
|
||||
/**
|
||||
* Fetch a memory by key. For local memories the key is the "id" used when saving the record.
|
||||
* For external reference, the key is the "URI" used when saving the record.
|
||||
*
|
||||
* @param collection Collection to search.
|
||||
* @param key Unique memory record identifier.
|
||||
* @param withEmbedding Whether to return the embedding of the memory found.
|
||||
* @return Memory record, or null when nothing is found
|
||||
*/
|
||||
public Mono<MemoryQueryResult> getAsync(
|
||||
@Nonnull String collection, @Nonnull String key, boolean withEmbedding);
|
||||
|
||||
SemanticTextMemory merge(MemoryQueryResult b);
|
||||
|
||||
/**
|
||||
* Remove a memory by key. For local memories the key is the "id" used when saving the record.
|
||||
* For external reference, the key is the "URI" used when saving the record.
|
||||
*
|
||||
* @param collection Collection to search.
|
||||
* @param key Unique memory record identifier.
|
||||
* @return Mono completion.
|
||||
*/
|
||||
public Mono<Void> removeAsync(@Nonnull String collection, @Nonnull String key);
|
||||
|
||||
/**
|
||||
* Find some information in memory
|
||||
*
|
||||
* @param collection Collection to search
|
||||
* @param query What to search for
|
||||
* @param limit How many results to return
|
||||
* @param minRelevanceScore Minimum relevance score, from 0 to 1, where 1 means exact match.
|
||||
* @param withEmbeddings Whether to return the embeddings of the memories found.
|
||||
* @return Memories found
|
||||
*/
|
||||
public Mono<List<MemoryQueryResult>> searchAsync(
|
||||
@Nonnull String collection,
|
||||
@Nonnull String query,
|
||||
int limit,
|
||||
double minRelevanceScore,
|
||||
boolean withEmbeddings);
|
||||
|
||||
/**
|
||||
* Gets a group of all available collection names.
|
||||
*
|
||||
* @return A group of collection names.
|
||||
*/
|
||||
public Mono<List<String>> getCollectionsAsync();
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.orchestration;
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.memory.SemanticTextMemory;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
|
||||
|
||||
import reactor.util.annotation.NonNull;
|
||||
import reactor.util.annotation.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.annotation.CheckReturnValue;
|
||||
|
||||
/// <summary>
|
||||
/// Semantic Kernel context.
|
||||
/// </summary>memory
|
||||
public abstract class AbstractSKContext<T extends SKContext<T>> implements SKContext<T> {
|
||||
@Nullable private final ReadOnlySkillCollection skills;
|
||||
private final WritableContextVariables variables;
|
||||
@Nullable private final SemanticTextMemory memory;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getResult() {
|
||||
return getVariables().asMap().get(ContextVariables.MAIN_KEY);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// User variables
|
||||
/// </summary>
|
||||
@Override
|
||||
public ContextVariables getVariables() {
|
||||
return SKBuilders.variables().build(Collections.unmodifiableMap(variables.asMap()));
|
||||
}
|
||||
|
||||
AbstractSKContext(ContextVariables variables) {
|
||||
this(variables, null, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for the context.
|
||||
/// </summary>
|
||||
/// <param name="variables">Context variables to include in context.</param>
|
||||
/// <param name="memory">Semantic text memory unit to include in context.</param>
|
||||
/// <param name="skills">Skills to include in context.</param>
|
||||
/// <param name="logger">Logger for operations in context.</param>
|
||||
/// <param name="cancellationToken">Optional cancellation token for operations in
|
||||
// context.</param>
|
||||
protected AbstractSKContext(
|
||||
ContextVariables variables,
|
||||
@Nullable SemanticTextMemory memory,
|
||||
@Nullable ReadOnlySkillCollection skills) {
|
||||
this.variables = InternalBuildersSingleton.variables().build(variables.asMap());
|
||||
|
||||
if (memory != null) {
|
||||
this.memory = memory.copy();
|
||||
} else {
|
||||
this.memory = null;
|
||||
}
|
||||
|
||||
this.skills = skills;
|
||||
}
|
||||
|
||||
@CheckReturnValue
|
||||
@Override
|
||||
public T copy() {
|
||||
ReadOnlySkillCollection clonedSkill;
|
||||
if (skills == null) {
|
||||
clonedSkill = skills;
|
||||
} else {
|
||||
clonedSkill = skills.copy();
|
||||
}
|
||||
return build(variables.writableClone(), memory, clonedSkill);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public SemanticTextMemory getSemanticMemory() {
|
||||
return memory != null ? memory.copy() : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ReadOnlySkillCollection getSkills() {
|
||||
return skills;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setVariable(@NonNull String key, @NonNull String content) {
|
||||
variables.setVariable(key, content);
|
||||
return getThis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T appendToVariable(@NonNull String key, @NonNull String content) {
|
||||
variables.appendToVariable(key, content);
|
||||
return getThis();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the main input text with the new value after a function is complete.
|
||||
/// </summary>
|
||||
/// <param name="content">The new input value, for the next function in the pipeline, or as a
|
||||
// result for the user
|
||||
/// if the pipeline reached the end.</param>
|
||||
/// <returns>The current instance</returns>
|
||||
@Override
|
||||
public T update(@NonNull String content) {
|
||||
variables.update(content);
|
||||
return getThis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T update(@NonNull ContextVariables newData) {
|
||||
variables.update(newData, true);
|
||||
return getThis();
|
||||
}
|
||||
|
||||
protected abstract T getThis();
|
||||
}
|
||||
+222
@@ -0,0 +1,222 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.orchestration;
|
||||
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.memory.NullMemory;
|
||||
import com.microsoft.semantickernel.memory.SemanticTextMemory;
|
||||
import com.microsoft.semantickernel.skilldefinition.KernelSkillsSupplier;
|
||||
import com.microsoft.semantickernel.skilldefinition.ParameterView;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public abstract class AbstractSkFunction<
|
||||
RequestConfiguration, ContextType extends SKContext<ContextType>>
|
||||
implements SKFunction<RequestConfiguration, ContextType>, RegistrableSkFunction {
|
||||
|
||||
private final DelegateTypes delegateType;
|
||||
private final List<ParameterView> parameters;
|
||||
private final String skillName;
|
||||
private final String functionName;
|
||||
private final String description;
|
||||
@Nullable private KernelSkillsSupplier skillsSupplier;
|
||||
|
||||
public AbstractSkFunction(
|
||||
DelegateTypes delegateType,
|
||||
List<ParameterView> parameters,
|
||||
String skillName,
|
||||
String functionName,
|
||||
String description,
|
||||
@Nullable KernelSkillsSupplier skillsSupplier) {
|
||||
|
||||
this.delegateType = delegateType;
|
||||
this.parameters = new ArrayList<>(parameters);
|
||||
this.skillName = skillName;
|
||||
this.functionName = functionName;
|
||||
this.description = description;
|
||||
this.skillsSupplier = skillsSupplier;
|
||||
}
|
||||
|
||||
protected void assertSkillSupplierRegistered() {
|
||||
if (skillsSupplier == null) {
|
||||
throw new FunctionNotRegisteredException(getName());
|
||||
}
|
||||
}
|
||||
|
||||
protected void setSkillsSupplier(@Nullable KernelSkillsSupplier skillsSupplier) {
|
||||
this.skillsSupplier = skillsSupplier;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public KernelSkillsSupplier getSkillsSupplier() {
|
||||
return skillsSupplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ContextType> invokeAsync(
|
||||
String input, @Nullable ContextType context, @Nullable RequestConfiguration settings) {
|
||||
if (context == null) {
|
||||
assertSkillSupplierRegistered();
|
||||
context =
|
||||
buildContext(
|
||||
SKBuilders.variables().build(),
|
||||
NullMemory.getInstance(),
|
||||
skillsSupplier.get());
|
||||
} else {
|
||||
context = context.copy();
|
||||
}
|
||||
|
||||
context = context.update(input);
|
||||
|
||||
return this.invokeAsync(context, settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ContextType> invokeAsync(String input) {
|
||||
return invokeAsync(input, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ContextType> invokeAsync(
|
||||
ContextType context, @Nullable RequestConfiguration settings) {
|
||||
// return new FutureTask<SKContext>(() -> function.run(null, settings, context));
|
||||
|
||||
if (context == null) {
|
||||
context = buildContext(SKBuilders.variables().build(), NullMemory.getInstance(), null);
|
||||
} else {
|
||||
context = context.copy();
|
||||
}
|
||||
|
||||
return this.invokeAsyncInternal(context, settings);
|
||||
}
|
||||
|
||||
protected abstract Mono<ContextType> invokeAsyncInternal(
|
||||
ContextType context, @Nullable RequestConfiguration settings);
|
||||
|
||||
@Override
|
||||
public String getSkillName() {
|
||||
return skillName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return functionName;
|
||||
}
|
||||
|
||||
public DelegateTypes getDelegateType() {
|
||||
return delegateType;
|
||||
}
|
||||
|
||||
public List<ParameterView> getParameters() {
|
||||
return Collections.unmodifiableList(parameters);
|
||||
}
|
||||
|
||||
public enum DelegateTypes {
|
||||
Unknown(0),
|
||||
Void(1),
|
||||
OutString(2),
|
||||
OutTaskString(3),
|
||||
InSKContext(4),
|
||||
InSKContextOutString(5),
|
||||
InSKContextOutTaskString(6),
|
||||
ContextSwitchInSKContextOutTaskSKContext(7),
|
||||
InString(8),
|
||||
InStringOutString(9),
|
||||
InStringOutTaskString(10),
|
||||
InStringAndContext(11),
|
||||
InStringAndContextOutString(12),
|
||||
InStringAndContextOutTaskString(13),
|
||||
ContextSwitchInStringAndContextOutTaskContext(14),
|
||||
InStringOutTask(15),
|
||||
InContextOutTask(16),
|
||||
InStringAndContextOutTask(17),
|
||||
OutTask(18);
|
||||
|
||||
final int num;
|
||||
|
||||
DelegateTypes(int num) {
|
||||
this.num = num;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The function to create a fully qualified name for
|
||||
*
|
||||
* @return A fully qualified name for a function
|
||||
*/
|
||||
@Override
|
||||
public String toFullyQualifiedName() {
|
||||
return skillName + "." + functionName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toEmbeddingString() {
|
||||
String inputs =
|
||||
parameters.stream()
|
||||
.map(p -> " - " + p.getName() + ": " + p.getDescription())
|
||||
.collect(Collectors.joining("\n"));
|
||||
|
||||
return getName() + ":\n description: " + getDescription() + "\n inputs:\n" + inputs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toManualString() {
|
||||
String inputs =
|
||||
parameters.stream()
|
||||
.map(
|
||||
parameter -> {
|
||||
String defaultValueString;
|
||||
if (parameter.getDefaultValue() == null
|
||||
|| parameter.getDefaultValue().isEmpty()) {
|
||||
defaultValueString = "";
|
||||
} else {
|
||||
defaultValueString =
|
||||
" (default value: "
|
||||
+ parameter.getDefaultValue()
|
||||
+ ")";
|
||||
}
|
||||
|
||||
return " - "
|
||||
+ parameter.getName()
|
||||
+ ": "
|
||||
+ parameter.getDescription()
|
||||
+ defaultValueString;
|
||||
})
|
||||
.collect(Collectors.joining("\n"));
|
||||
|
||||
return toFullyQualifiedName()
|
||||
+ ":\n"
|
||||
+ " description: "
|
||||
+ getDescription()
|
||||
+ "\n"
|
||||
+ " inputs:\n"
|
||||
+ inputs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextType buildContext() {
|
||||
assertSkillSupplierRegistered();
|
||||
return buildContext(SKBuilders.variables().build(), null, getSkillsSupplier().get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ContextType> invokeWithCustomInputAsync(
|
||||
ContextVariables input,
|
||||
SemanticTextMemory semanticMemory,
|
||||
ReadOnlySkillCollection skills) {
|
||||
ContextType tmpContext = buildContext(input, semanticMemory, skills);
|
||||
return invokeAsync(tmpContext, null);
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.orchestration;
|
||||
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.CheckReturnValue;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Context Variables is a data structure that holds temporary data while a task is being performed.
|
||||
* It is accessed by functions in the pipeline.
|
||||
*/
|
||||
public interface ContextVariables {
|
||||
|
||||
String MAIN_KEY = "input";
|
||||
|
||||
Map<String, String> asMap();
|
||||
|
||||
@CheckReturnValue
|
||||
WritableContextVariables writableClone();
|
||||
|
||||
interface Builder {
|
||||
ContextVariables build();
|
||||
|
||||
/**
|
||||
* Builds an instance with the given content in the default main key
|
||||
*
|
||||
* @param content Entry to place in the "input" slot
|
||||
* @return an instantiation of ContextVariables
|
||||
*/
|
||||
ContextVariables build(String content);
|
||||
|
||||
/**
|
||||
* Builds an instance with the given variables
|
||||
*
|
||||
* @param map Existing varibles
|
||||
* @return an instantiation of ContextVariables
|
||||
*/
|
||||
ContextVariables build(Map<String, String> map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the variable with the given name
|
||||
*
|
||||
* @param key variable name
|
||||
* @return content of the variable
|
||||
*/
|
||||
@Nullable
|
||||
String get(String key);
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.orchestration;
|
||||
|
||||
public class FunctionNotRegisteredException extends RuntimeException {
|
||||
|
||||
public FunctionNotRegisteredException(String name) {
|
||||
super(
|
||||
"It does not appear this function("
|
||||
+ name
|
||||
+ ") has been registered on a kernel.\n"
|
||||
+ "Register it on a kernel either by passing it to"
|
||||
+ " KernelConfig.Builder().addSkill() when building the kernel, or\n"
|
||||
+ "passing it to Kernel.registerSemanticFunction");
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.orchestration;
|
||||
|
||||
import com.microsoft.semantickernel.builders.ServiceLoadUtil;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
enum InternalBuildersSingleton {
|
||||
INST;
|
||||
|
||||
// Fallback classes in case the META-INF/services directory is missing
|
||||
|
||||
private static final String FALLBACK_VARIABLE_BUILDER_CLASS =
|
||||
"com.microsoft.semantickernel.orchestration.DefaultContextVariables$WritableBuilder";
|
||||
|
||||
private final WritableContextVariables.Builder variables;
|
||||
|
||||
InternalBuildersSingleton() {
|
||||
try {
|
||||
variables =
|
||||
ServiceLoadUtil.findServiceLoader(
|
||||
WritableContextVariables.Builder.class,
|
||||
FALLBACK_VARIABLE_BUILDER_CLASS);
|
||||
|
||||
} catch (Throwable e) {
|
||||
Logger LOGGER = LoggerFactory.getLogger(InternalBuildersSingleton.class);
|
||||
LOGGER.error("Failed to discover Semantic Kernel Builders", e);
|
||||
LOGGER.error(
|
||||
"This is likely due to:\n\n"
|
||||
+ "- The Semantic Kernel implementation (typically provided by"
|
||||
+ " semantickernel-core) is not present on the classpath at runtime, ensure"
|
||||
+ " that this dependency is available at runtime. In maven this would be"
|
||||
+ " achieved by adding:\n"
|
||||
+ "\n"
|
||||
+ " <dependency>\n"
|
||||
+ " <groupId>com.microsoft.semantickernel</groupId>\n"
|
||||
+ " <artifactId>semantickernel-core</artifactId>\n"
|
||||
+ " <version>${skversion}</version>\n"
|
||||
+ " <scope>runtime</scope>\n"
|
||||
+ " </dependency>\n\n"
|
||||
+ "- The META-INF/services files that define the service loading have been"
|
||||
+ " filtered out and are not present within the running application\n\n"
|
||||
+ "- The class names have been changed (for instance shaded) preventing"
|
||||
+ " discovering the classes");
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public static WritableContextVariables.Builder variables() {
|
||||
return INST.variables;
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.orchestration;
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
|
||||
public interface RegistrableSkFunction {
|
||||
|
||||
void registerOnKernel(Kernel kernel);
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.orchestration;
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import com.microsoft.semantickernel.memory.SemanticTextMemory;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
|
||||
|
||||
import reactor.util.annotation.NonNull;
|
||||
import reactor.util.annotation.Nullable;
|
||||
|
||||
import javax.annotation.CheckReturnValue;
|
||||
|
||||
/** Semantic Kernel context. */
|
||||
public interface SKContext<Type extends SKContext<Type>> {
|
||||
|
||||
Type build(
|
||||
ContextVariables variables,
|
||||
@Nullable SemanticTextMemory memory,
|
||||
@Nullable ReadOnlySkillCollection skills);
|
||||
|
||||
/**
|
||||
* Obtain the result of the execution that produced this context. This will be the "input" entry
|
||||
* in the variables.
|
||||
*
|
||||
* @return the "input" entry in the variables
|
||||
*/
|
||||
@Nullable
|
||||
String getResult();
|
||||
|
||||
/**
|
||||
* Return a copy of all variables within the context
|
||||
*
|
||||
* @return a clone of the variables
|
||||
*/
|
||||
ContextVariables getVariables();
|
||||
|
||||
/** Provides access to the contexts semantic memory */
|
||||
@Nullable
|
||||
SemanticTextMemory getSemanticMemory();
|
||||
|
||||
/**
|
||||
* Provides access to the skills within this context
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
ReadOnlySkillCollection getSkills();
|
||||
|
||||
/**
|
||||
* Sets the given variable
|
||||
*
|
||||
* @param key if null defaults to the "input" key
|
||||
* @param content
|
||||
* @return Context for fluent calls
|
||||
*/
|
||||
Type setVariable(@NonNull String key, @NonNull String content);
|
||||
|
||||
/**
|
||||
* Appends data to the given key
|
||||
*
|
||||
* @param key
|
||||
* @param content
|
||||
* @return Context for fluent calls
|
||||
*/
|
||||
Type appendToVariable(@NonNull String key, @NonNull String content);
|
||||
|
||||
/**
|
||||
* Updates the input entry with the given data
|
||||
*
|
||||
* @param content
|
||||
* @return Context for fluent calls
|
||||
*/
|
||||
@CheckReturnValue
|
||||
Type update(@NonNull String content);
|
||||
|
||||
/**
|
||||
* Merges in the given variables. Duplicate keys provided by newData will overwrite existing
|
||||
* entries.
|
||||
*
|
||||
* @param newData
|
||||
* @return Context for fluent calls
|
||||
*/
|
||||
@CheckReturnValue
|
||||
Type update(@NonNull ContextVariables newData);
|
||||
|
||||
Type copy();
|
||||
|
||||
interface Builder {
|
||||
SKContext build(ReadOnlySkillCollection skills);
|
||||
}
|
||||
}
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.orchestration;
|
||||
|
||||
import com.microsoft.semantickernel.memory.SemanticTextMemory;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import javax.annotation.CheckReturnValue;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Semantic Kernel callable function interface
|
||||
*
|
||||
* @param <RequestConfiguration> The type of the configuration argument that will be provided when
|
||||
* the function is invoked
|
||||
*/
|
||||
public interface SKFunction<RequestConfiguration, ContextType extends SKContext<ContextType>> {
|
||||
/*
|
||||
/// <summary>
|
||||
/// Name of the function. The name is used by the skill collection and in prompt templates e.g. {{skillName.functionName}}
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the skill containing the function. The name is used by the skill collection and in prompt templates e.g. {{skillName.functionName}}
|
||||
/// </summary>
|
||||
string SkillName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Function description. The description is used in combination with embeddings when searching relevant functions.
|
||||
/// </summary>
|
||||
string Description { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the function is defined using a prompt template.
|
||||
/// IMPORTANT: native functions might use semantic functions internally,
|
||||
/// so when this property is False, executing the function might still involve AI calls.
|
||||
/// </summary>
|
||||
public bool IsSemantic { get; }
|
||||
|
||||
/// <summary>
|
||||
/// AI service settings
|
||||
/// </summary>
|
||||
public CompleteRequestSettings RequestSettings { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a description of the function, including parameters.
|
||||
/// </summary>
|
||||
/// <returns>An instance of <see cref="FunctionView"/> describing the function</returns>
|
||||
FunctionView Describe();
|
||||
*/
|
||||
// TODO: CancellationToken
|
||||
/// <summary>
|
||||
/// Invoke the internal delegate with an explicit string input
|
||||
/// </summary>
|
||||
/// <param name="input">String input</param>
|
||||
/// <param name="context">SK context</param>
|
||||
/// <param name="settings">LLM completion settings</param>
|
||||
/// <param name="log">Application logger</param>
|
||||
/// <param name="cancel">Cancellation token</param>
|
||||
/// <returns>The updated context, potentially a new one if context switching is
|
||||
// implemented.</returns>
|
||||
|
||||
/**
|
||||
* Invokes the function with the given input, context and settings
|
||||
*
|
||||
* @param input input provided to the function
|
||||
* @param context Request context
|
||||
* @param settings Configuration of the request
|
||||
* @return an updated context with the result of the request
|
||||
*/
|
||||
@CheckReturnValue
|
||||
Mono<ContextType> invokeAsync(String input, ContextType context, RequestConfiguration settings);
|
||||
|
||||
/**
|
||||
* Invokes the function with the given input
|
||||
*
|
||||
* @param input input provided to the function
|
||||
* @return an updated context with the result of the request
|
||||
*/
|
||||
@CheckReturnValue
|
||||
Mono<ContextType> invokeAsync(String input);
|
||||
|
||||
Class<RequestConfiguration> getType();
|
||||
|
||||
/**
|
||||
* Invokes the function with the given context and settings
|
||||
*
|
||||
* @param context Request context
|
||||
* @param settings Configuration of the request
|
||||
* @return an updated context with the result of the request
|
||||
*/
|
||||
@CheckReturnValue
|
||||
Mono<ContextType> invokeAsync(ContextType context, @Nullable RequestConfiguration settings);
|
||||
|
||||
/// <summary>
|
||||
/// Set the default skill collection to use when the function is invoked
|
||||
/// without a context or with a context that doesn't have a collection.
|
||||
/// </summary>
|
||||
/// <param name="skills">Kernel's skill collection</param>
|
||||
/// <returns>Self instance</returns>
|
||||
/*
|
||||
SKFunction<RequestConfiguration> setDefaultSkillCollection(SkillCollection skills);
|
||||
/// <summary>
|
||||
/// Set the AI service used by the semantic function, passing a factory method.
|
||||
/// The factory allows to lazily instantiate the client and to properly handle its disposal.
|
||||
/// </summary>
|
||||
/// <param name="serviceFactory">AI service factory</param>
|
||||
/// <returns>Self instance</returns>
|
||||
SKFunction setAIService(Supplier<TextCompletion> serviceFactory);
|
||||
|
||||
/// <summary>
|
||||
/// Set the AI completion settings used with LLM requests
|
||||
/// </summary>
|
||||
/// <param name="settings">LLM completion settings</param>
|
||||
/// <returns>Self instance</returns>
|
||||
SKFunction setAIConfiguration(CompleteRequestSettings settings);
|
||||
*/
|
||||
|
||||
/**
|
||||
* @return The name of the skill that this function is within
|
||||
*/
|
||||
String getSkillName();
|
||||
|
||||
/**
|
||||
* @return The name of this function
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* The function to create a fully qualified name for
|
||||
*
|
||||
* @return A fully qualified name for a function
|
||||
*/
|
||||
String toFullyQualifiedName();
|
||||
|
||||
String getDescription();
|
||||
|
||||
String toEmbeddingString();
|
||||
|
||||
String toManualString();
|
||||
|
||||
ContextType buildContext(
|
||||
ContextVariables variables,
|
||||
@Nullable SemanticTextMemory memory,
|
||||
@Nullable ReadOnlySkillCollection skills);
|
||||
|
||||
ContextType buildContext();
|
||||
|
||||
Mono<ContextType> invokeWithCustomInputAsync(
|
||||
ContextVariables variablesClone,
|
||||
SemanticTextMemory semanticMemory,
|
||||
ReadOnlySkillCollection skills);
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.orchestration;
|
||||
|
||||
/** Semantic Kernel context. */
|
||||
public interface SemanticSKContext extends SKContext<SemanticSKContext> {}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.orchestration;
|
||||
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import reactor.util.annotation.NonNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Context Variables is a data structure that holds temporary data while a task is being performed.
|
||||
* It is accessed by functions in the pipeline.
|
||||
*/
|
||||
public interface WritableContextVariables extends ContextVariables {
|
||||
|
||||
/**
|
||||
* Set the value
|
||||
*
|
||||
* @param key variable name
|
||||
* @param content value to set
|
||||
* @return Contect for fluent calls
|
||||
*/
|
||||
ContextVariables setVariable(@NonNull String key, @NonNull String content);
|
||||
|
||||
ContextVariables appendToVariable(@NonNull String key, @NonNull String content);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the main input text with the new value after a function is complete.
|
||||
/// </summary>
|
||||
/// <param name="content">The new input value, for the next function in the pipeline, or as a
|
||||
// result for the user
|
||||
/// if the pipeline reached the end.</param>
|
||||
/// <returns>The current instance</returns>
|
||||
ContextVariables update(@NonNull String content);
|
||||
|
||||
ContextVariables update(@NonNull ContextVariables newData, boolean merge);
|
||||
|
||||
interface Builder {
|
||||
/**
|
||||
* Builds an instance with the given variables
|
||||
*
|
||||
* @param map Existing varibles
|
||||
* @return an instantiation of ContextVariables
|
||||
*/
|
||||
WritableContextVariables build(Map<String, String> map);
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.semanticfunctions; // Copyright (c) Microsoft. All rights
|
||||
// reserved.
|
||||
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.skilldefinition.ParameterView;
|
||||
import com.microsoft.semantickernel.templateengine.PromptTemplateEngine;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** Interface for prompt template */
|
||||
public interface PromptTemplate {
|
||||
/**
|
||||
* Get the list of parameters required by the template, using configuration and template info
|
||||
*
|
||||
* @return List of parameters
|
||||
*/
|
||||
List<ParameterView> getParameters();
|
||||
|
||||
/**
|
||||
* Render the template using the information in the context
|
||||
*
|
||||
* @param executionContext Kernel execution context helpers
|
||||
* @param promptTemplateEngine
|
||||
* @return Prompt rendered to string
|
||||
*/
|
||||
Mono<String> renderAsync(SKContext executionContext, PromptTemplateEngine promptTemplateEngine);
|
||||
|
||||
interface Builder {
|
||||
PromptTemplate build(String promptTemplate, PromptTemplateConfig config);
|
||||
}
|
||||
}
|
||||
+270
@@ -0,0 +1,270 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.semanticfunctions; // Copyright (c) Microsoft. All rights
|
||||
// reserved.
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import reactor.util.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** Prompt template configuration */
|
||||
public class PromptTemplateConfig {
|
||||
private final CompletionConfig completionConfig;
|
||||
private final InputConfig input;
|
||||
|
||||
/**
|
||||
* A returns the configuration for the text completion
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public CompletionConfig getCompletionConfig() {
|
||||
return completionConfig;
|
||||
}
|
||||
|
||||
/** Completion configuration parameters */
|
||||
public static class CompletionConfig {
|
||||
/*
|
||||
/// <summary>
|
||||
/// Sampling temperature to use, between 0 and 2. Higher values will make the output more random.
|
||||
/// Lower values will make it more focused and deterministic.
|
||||
/// </summary>
|
||||
[JsonPropertyName("temperature")]
|
||||
[JsonPropertyOrder(1)]
|
||||
*/
|
||||
private final double temperature;
|
||||
/*
|
||||
/// <summary>
|
||||
/// Cut-off of top_p probability mass of tokens to consider.
|
||||
/// For example, 0.1 means only the tokens comprising the top 10% probability mass are considered.
|
||||
/// </summary>
|
||||
[JsonPropertyName("top_p")]
|
||||
[JsonPropertyOrder(2)]
|
||||
*/
|
||||
private final double topP;
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Lowers the probability of a word appearing if it already appeared in the predicted text.
|
||||
/// Unlike the frequency penalty, the presence penalty does not depend on the frequency at which words
|
||||
/// appear in past predictions.
|
||||
/// </summary>
|
||||
[JsonPropertyName("presence_penalty")]
|
||||
[JsonPropertyOrder(3)]
|
||||
*/
|
||||
private final double presencePenalty;
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Controls the model’s tendency to repeat predictions. The frequency penalty reduces the probability
|
||||
/// of words that have already been generated. The penalty depends on how many times a word has already
|
||||
/// occurred in the prediction.
|
||||
/// </summary>
|
||||
[JsonPropertyName("frequency_penalty")]
|
||||
[JsonPropertyOrder(4)]
|
||||
*/
|
||||
private final double frequencyPenalty;
|
||||
/*
|
||||
/// <summary>
|
||||
/// Maximum number of tokens that can be generated.
|
||||
/// </summary>
|
||||
[JsonPropertyName("max_tokens")]
|
||||
[JsonPropertyOrder(5)]*/
|
||||
private final int maxTokens; // { get; set; } = 256;
|
||||
/*
|
||||
/// <summary>
|
||||
/// Stop sequences are optional sequences that tells the AI model when to stop generating tokens.
|
||||
/// </summary>
|
||||
[JsonPropertyName("stop_sequences")]
|
||||
[JsonPropertyOrder(6)]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
*/
|
||||
public final List<String> stopSequences; // { get; set; } = new();
|
||||
|
||||
public CompletionConfig() {
|
||||
this(0.0, 0.0, 0.0, 0.0, 256, new ArrayList<>());
|
||||
}
|
||||
|
||||
@JsonCreator
|
||||
public CompletionConfig(
|
||||
@JsonProperty("temperature") double temperature,
|
||||
@JsonProperty("top_p") double topP,
|
||||
@JsonProperty("presence_penalty") double presencePenalty,
|
||||
@JsonProperty("frequency_penalty") double frequencyPenalty,
|
||||
@JsonProperty("max_tokens") int maxTokens,
|
||||
@JsonProperty(value = "stop_sequences") List<String> stopSequences) {
|
||||
this.temperature = temperature;
|
||||
this.topP = topP;
|
||||
this.presencePenalty = presencePenalty;
|
||||
this.frequencyPenalty = frequencyPenalty;
|
||||
this.maxTokens = maxTokens;
|
||||
if (stopSequences == null) {
|
||||
stopSequences = new ArrayList<>();
|
||||
}
|
||||
this.stopSequences = stopSequences;
|
||||
}
|
||||
|
||||
public double getTemperature() {
|
||||
return temperature;
|
||||
}
|
||||
|
||||
public double getTopP() {
|
||||
return topP;
|
||||
}
|
||||
|
||||
public double getPresencePenalty() {
|
||||
return presencePenalty;
|
||||
}
|
||||
|
||||
public double getFrequencyPenalty() {
|
||||
return frequencyPenalty;
|
||||
}
|
||||
|
||||
public int getMaxTokens() {
|
||||
return maxTokens;
|
||||
}
|
||||
}
|
||||
|
||||
/** Input parameter for semantic functions */
|
||||
public static class InputParameter {
|
||||
private final String name;
|
||||
private final String description;
|
||||
|
||||
private final String defaultValue;
|
||||
|
||||
@JsonCreator
|
||||
public InputParameter(
|
||||
@JsonProperty("name") String name,
|
||||
@JsonProperty("description") String description,
|
||||
@JsonProperty("defaultValue") String defaultValue) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/** Input configuration (list of all input parameters for a semantic function). */
|
||||
public static class InputConfig {
|
||||
|
||||
public final List<InputParameter> parameters;
|
||||
|
||||
@JsonCreator
|
||||
public InputConfig(@JsonProperty("parameters") List<InputParameter> parameters) {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Schema - Not currently used.
|
||||
/// </summary>
|
||||
[JsonPropertyName("schema")]
|
||||
[JsonPropertyOrder(1)]
|
||||
public int Schema { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Type, such as "completion", "embeddings", etc.
|
||||
/// </summary>
|
||||
/// <remarks>TODO: use enum</remarks>
|
||||
[JsonPropertyName("type")]
|
||||
[JsonPropertyOrder(2)]
|
||||
*/
|
||||
private final int schema;
|
||||
|
||||
private final String type; // { get; set; } = "completion";
|
||||
/*
|
||||
/// <summary>
|
||||
/// Description
|
||||
/// </summary>
|
||||
[JsonPropertyName("description")]
|
||||
[JsonPropertyOrder(3)]
|
||||
*/
|
||||
private final String description;
|
||||
|
||||
public PromptTemplateConfig(
|
||||
String description, String type, @Nullable CompletionConfig completionConfig) {
|
||||
this(1, description, type, completionConfig, new InputConfig(new ArrayList<>()));
|
||||
}
|
||||
|
||||
@JsonCreator
|
||||
public PromptTemplateConfig(
|
||||
@JsonProperty("schema") int schema,
|
||||
@JsonProperty("description") String description,
|
||||
@JsonProperty("type") String type,
|
||||
@Nullable @JsonProperty("completion") CompletionConfig completionConfig,
|
||||
@JsonProperty("input") InputConfig input) {
|
||||
if (completionConfig == null) {
|
||||
completionConfig = new CompletionConfig();
|
||||
}
|
||||
this.schema = schema;
|
||||
this.description = description;
|
||||
this.type = type;
|
||||
this.completionConfig = completionConfig;
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Completion configuration parameters.
|
||||
/// </summary>
|
||||
[JsonPropertyName("completion")]
|
||||
[JsonPropertyOrder(4)]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
|
||||
*/
|
||||
// private final CompletionConfig completion = null;
|
||||
|
||||
/*
|
||||
|
||||
/// <summary>
|
||||
/// Default AI services to use.
|
||||
/// </summary>
|
||||
[JsonPropertyName("default_services")]
|
||||
[JsonPropertyOrder(5)]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public List<string> DefaultServices { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Input configuration (that is, list of all input parameters).
|
||||
/// </summary>
|
||||
[JsonPropertyName("input")]
|
||||
[JsonPropertyOrder(6)]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public InputConfig Input { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Remove some default properties to reduce the JSON complexity.
|
||||
/// </summary>
|
||||
/// <returns>Compacted prompt template configuration.</returns>
|
||||
public PromptTemplateConfig Compact()
|
||||
{
|
||||
if (this.Completion.StopSequences.Count == 0)
|
||||
{
|
||||
this.Completion.StopSequences = null!;
|
||||
}
|
||||
|
||||
if (this.DefaultServices.Count == 0)
|
||||
{
|
||||
this.DefaultServices = null!;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a prompt template configuration from JSON.
|
||||
/// </summary>
|
||||
/// <param name="json">JSON of the prompt template configuration.</param>
|
||||
/// <returns>Prompt template configuration.</returns>
|
||||
public static PromptTemplateConfig FromJson(String json) throws JsonProcessingException {
|
||||
return new ObjectMapper().readValue(json, PromptTemplateConfig.class);
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.semanticfunctions;
|
||||
|
||||
/** Semantic function configuration */
|
||||
public class SemanticFunctionConfig {
|
||||
private final PromptTemplateConfig config;
|
||||
/** Prompt template */
|
||||
private final PromptTemplate template;
|
||||
|
||||
/**
|
||||
* Constructor for SemanticFunctionConfig.
|
||||
*
|
||||
* @param config Prompt template configuration.
|
||||
* @param template Prompt template.
|
||||
*/
|
||||
public SemanticFunctionConfig(PromptTemplateConfig config, PromptTemplate template) {
|
||||
this.config = config;
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
public PromptTemplateConfig getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public PromptTemplate getTemplate() {
|
||||
return template;
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.skilldefinition;
|
||||
|
||||
public class FunctionNotFound extends RuntimeException {
|
||||
public FunctionNotFound(String functionName) {
|
||||
super("Could not find function: " + functionName);
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.skilldefinition;
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public interface KernelSkillsSupplier extends Supplier<ReadOnlySkillCollection> {
|
||||
|
||||
static KernelSkillsSupplier getInstance(Kernel kernel) {
|
||||
return kernel::getSkills;
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.skilldefinition; // Copyright (c) Microsoft. All rights
|
||||
// reserved.
|
||||
|
||||
/// <summary>
|
||||
/// Class used to copy and export data from
|
||||
/// <see cref="SKFunctionContextParameterAttribute"/>
|
||||
/// and <see cref="SKFunctionInputAttribute"/>
|
||||
/// for planner and related scenarios.
|
||||
/// </summary>
|
||||
public class ParameterView {
|
||||
private final String name;
|
||||
private final String description;
|
||||
private final String defaultValue;
|
||||
|
||||
/// <summary>
|
||||
/// Create a function parameter view, using information provided by the skill developer.
|
||||
/// </summary>
|
||||
/// <param name="name">Parameter name. The name must be alphanumeric (underscore is the only
|
||||
// special char allowed).</param>
|
||||
/// <param name="description">Parameter description</param>
|
||||
/// <param name="defaultValue">Default parameter value, if not provided</param>
|
||||
public ParameterView(String name, String description, String defaultValue) {
|
||||
// TODO
|
||||
// Verify.ValidFunctionParamName(name);
|
||||
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public String getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.skilldefinition;
|
||||
|
||||
import com.microsoft.semantickernel.orchestration.SKFunction;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.CheckReturnValue;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public interface ReadOnlyFunctionCollection {
|
||||
|
||||
String getSkillName();
|
||||
|
||||
SKFunction<?, ?> getFunction(String functionName);
|
||||
|
||||
/**
|
||||
* Get function with the given SKFunction type argument.
|
||||
*
|
||||
* @param functionName the name of the function to retrieve
|
||||
* @param clazz The class of the SKFunction parameter type
|
||||
* @param <T> SKFunction parameter type
|
||||
* @return The given function
|
||||
* @throws RuntimeException if the given entry is not of the expected type
|
||||
*/
|
||||
<T extends SKFunction> T getFunction(String functionName, @Nullable Class<T> clazz);
|
||||
|
||||
/**
|
||||
* @return A clone of this collection
|
||||
*/
|
||||
@CheckReturnValue
|
||||
ReadOnlyFunctionCollection copy();
|
||||
|
||||
/**
|
||||
* @return An unmodifiable list of all functions
|
||||
*/
|
||||
List<SKFunction<?, ?>> getAll();
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.skilldefinition; // Copyright (c) Microsoft. All rights
|
||||
// reserved.
|
||||
|
||||
import com.microsoft.semantickernel.orchestration.SKFunction;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.CheckReturnValue;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Skill collection interface.
|
||||
*
|
||||
* <p>This is read only
|
||||
*/
|
||||
public interface ReadOnlySkillCollection {
|
||||
|
||||
String GlobalSkill = "_GLOBAL_FUNCTIONS_";
|
||||
|
||||
@CheckReturnValue
|
||||
ReadOnlySkillCollection copy();
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Add a native function to the collection
|
||||
/// </summary>
|
||||
/// <param name="functionInstance">Wrapped function delegate</param>
|
||||
/// <returns>Self instance</returns>
|
||||
*/
|
||||
|
||||
/** Get this collection as an unmodifiable map */
|
||||
Map<String, ReadOnlyFunctionCollection> asMap();
|
||||
|
||||
ReadOnlyFunctionCollection getAllFunctions();
|
||||
|
||||
/** Get function with name from the global scope */
|
||||
@Nullable
|
||||
<T extends SKFunction<?, ?>> T getFunction(
|
||||
String functionName, @Nullable Class<T> functionType);
|
||||
|
||||
@Nullable
|
||||
<T extends SKFunction<?, ?>> T getFunction(
|
||||
String skillName, String funName, Class<T> functionClazz);
|
||||
|
||||
@Nullable
|
||||
ReadOnlyFunctionCollection getFunctions(String skillName);
|
||||
|
||||
boolean hasFunction(String functionName);
|
||||
|
||||
public interface Builder {
|
||||
public ReadOnlySkillCollection build();
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.skilldefinition.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/** Annotation that defines a method that can be invoked as a native function */
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface DefineSKFunction {
|
||||
String description();
|
||||
|
||||
String name();
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.skilldefinition.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/** Annotates a parameter to a native function */
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface SKFunctionParameters {
|
||||
String description();
|
||||
|
||||
String name();
|
||||
|
||||
String defaultValue();
|
||||
|
||||
Class<?> type();
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.templateengine; // Copyright (c) Microsoft. All rights
|
||||
// reserved.
|
||||
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/** Prompt template engine interface */
|
||||
public interface PromptTemplateEngine {
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Given a prompt template string, extract all the blocks (text, variables, function calls)
|
||||
/// </summary>
|
||||
/// <param name="templateText">Prompt template (see skprompt.txt files)</param>
|
||||
/// <param name="validate">Whether to validate the blocks syntax, or just return the blocks found, which could contain invalid code</param>
|
||||
/// <returns>A list of all the blocks, ie the template tokenized in text, variables and function calls</returns>
|
||||
IList<Block> ExtractBlocks(
|
||||
string?templateText,
|
||||
bool validate =true);
|
||||
*/
|
||||
|
||||
/**
|
||||
* Given a prompt template, replace the variables with their values and execute the functions
|
||||
* replacing their reference with the function result
|
||||
*
|
||||
* @param templateText Prompt template (see skprompt.txt files)
|
||||
* @param context Access into the current kernel execution context
|
||||
* @return The prompt template ready to be used for an AI request
|
||||
*/
|
||||
Mono<String> renderAsync(String templateText, SKContext context);
|
||||
|
||||
interface Builder {
|
||||
PromptTemplateEngine build();
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.templateengine.blocks;
|
||||
|
||||
/** Base class for blocks parsed from a prompt template */
|
||||
public abstract class Block {
|
||||
private final String content;
|
||||
private final BlockTypes type;
|
||||
|
||||
/*
|
||||
|
||||
// internal virtual bool? SynchronousRendering => null;
|
||||
|
||||
/// <summary>
|
||||
/// The block content
|
||||
/// </summary>
|
||||
internal string Content { get; }
|
||||
|
||||
/// <summary>
|
||||
/// App logger
|
||||
/// </summary>
|
||||
protected ILogger Log { get; } = NullLogger.Instance;
|
||||
*/
|
||||
/// <summary>
|
||||
/// Base constructor
|
||||
/// </summary>
|
||||
/// <param name="content">Block content</param>
|
||||
/// <param name="log">App logger</param>
|
||||
public Block(String content, BlockTypes type) {
|
||||
if (content == null) {
|
||||
content = "";
|
||||
}
|
||||
|
||||
this.content = content;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the block content is valid.
|
||||
/// </summary>
|
||||
/// <param name="errorMsg">Error message in case the content is not valid</param>
|
||||
/// <returns>True if the block content is valid</returns>
|
||||
// TODO ERROR MESSAGE
|
||||
public abstract boolean isValid();
|
||||
|
||||
public BlockTypes getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.templateengine.blocks; // Copyright (c) Microsoft. All rights
|
||||
// reserved.
|
||||
|
||||
public enum BlockTypes {
|
||||
Undefined(0),
|
||||
Text(1),
|
||||
Code(2),
|
||||
Variable(3),
|
||||
Value(4),
|
||||
FunctionId(5);
|
||||
|
||||
BlockTypes(int i) {}
|
||||
}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.textcompletion;
|
||||
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/** Settings for a text completion request */
|
||||
public class CompletionRequestSettings {
|
||||
/**
|
||||
* Temperature controls the randomness of the completion. The higher the temperature, the more
|
||||
* random the completion
|
||||
*/
|
||||
private final double temperature; // { get; set; } = 0;
|
||||
|
||||
/**
|
||||
* TopP controls the diversity of the completion. The higher the TopP, the more diverse the
|
||||
* completion.
|
||||
*/
|
||||
private final double topP; // { get; set; } = 0;
|
||||
|
||||
/**
|
||||
* Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear
|
||||
* in the text so far, increasing the model's likelihood to talk about new topics.
|
||||
*/
|
||||
private final double presencePenalty; // { get; set; } = 0;
|
||||
|
||||
/**
|
||||
* Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing
|
||||
* frequency in the text so far, decreasing the model's likelihood to repeat the same line
|
||||
* verbatim.
|
||||
*/
|
||||
private final double frequencyPenalty; // { get; set; } = 0;
|
||||
|
||||
/** The maximum number of tokens to generate in the completion. */
|
||||
private final int maxTokens; // { get; set; } = 256;
|
||||
|
||||
/** Sequences where the completion will stop generating further tokens. */
|
||||
private final List<String> stopSequences; // { get; set; } = Array.Empty<string>();
|
||||
|
||||
public CompletionRequestSettings(
|
||||
double temperature,
|
||||
double topP,
|
||||
double presencePenalty,
|
||||
double frequencyPenalty,
|
||||
int maxTokens,
|
||||
List<String> stopSequences) {
|
||||
this.temperature = temperature;
|
||||
this.topP = topP;
|
||||
this.presencePenalty = presencePenalty;
|
||||
this.frequencyPenalty = frequencyPenalty;
|
||||
this.maxTokens = maxTokens;
|
||||
this.stopSequences = new ArrayList<>(stopSequences);
|
||||
}
|
||||
|
||||
public CompletionRequestSettings() {
|
||||
this(0, 0, 0, 0, 256, new ArrayList<>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new settings object with the values from another settings object.
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <returns>An instance of <see cref="CompleteRequestSettings"/> </returns>
|
||||
public static CompletionRequestSettings fromCompletionConfig(
|
||||
PromptTemplateConfig.CompletionConfig config) {
|
||||
return new CompletionRequestSettings(
|
||||
config.getTemperature(),
|
||||
config.getTopP(),
|
||||
config.getPresencePenalty(),
|
||||
config.getFrequencyPenalty(),
|
||||
config.getMaxTokens(),
|
||||
new ArrayList<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Temperature controls the randomness of the completion. The higher the temperature, the more
|
||||
* random the completion
|
||||
*/
|
||||
public double getTemperature() {
|
||||
return temperature;
|
||||
}
|
||||
|
||||
/**
|
||||
* TopP controls the diversity of the completion. The higher the TopP, the more diverse the
|
||||
* completion.
|
||||
*/
|
||||
public double getTopP() {
|
||||
return topP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear
|
||||
* in the text so far, increasing the model's likelihood to talk about new topics.
|
||||
*/
|
||||
public double getPresencePenalty() {
|
||||
return presencePenalty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing
|
||||
* frequency in the text so far, decreasing the model's likelihood to repeat the same line
|
||||
* verbatim.
|
||||
*/
|
||||
public double getFrequencyPenalty() {
|
||||
return frequencyPenalty;
|
||||
}
|
||||
|
||||
/** The maximum number of tokens to generate in the completion. */
|
||||
public int getMaxTokens() {
|
||||
return maxTokens;
|
||||
}
|
||||
|
||||
/** Sequences where the completion will stop generating further tokens. */
|
||||
public List<String> getStopSequences() {
|
||||
return Collections.unmodifiableList(stopSequences);
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.textcompletion;
|
||||
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
|
||||
public interface CompletionSKContext extends SKContext<CompletionSKContext> {}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.textcompletion;
|
||||
|
||||
import com.microsoft.semantickernel.builders.BuildersSingleton;
|
||||
import com.microsoft.semantickernel.orchestration.SKFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.semanticfunctions.SemanticFunctionConfig;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public interface CompletionSKFunction
|
||||
extends SKFunction<CompletionRequestSettings, CompletionSKContext> {
|
||||
|
||||
static CompletionSKFunction.Builder builder() {
|
||||
return BuildersSingleton.INST.getFunctionBuilders().completionBuilders(null);
|
||||
}
|
||||
|
||||
interface Builder {
|
||||
CompletionSKFunction createFunction(
|
||||
String promptTemplate,
|
||||
PromptTemplateConfig config,
|
||||
String functionName,
|
||||
@Nullable String skillName);
|
||||
|
||||
CompletionSKFunction createFunction(
|
||||
String functionName, SemanticFunctionConfig functionConfig);
|
||||
|
||||
CompletionSKFunction createFunction(
|
||||
@Nullable String skillNameFinal,
|
||||
String functionName,
|
||||
SemanticFunctionConfig functionConfig);
|
||||
|
||||
CompletionSKFunction createFunction(
|
||||
String promptTemplate,
|
||||
@Nullable String functionName,
|
||||
@Nullable String skillName,
|
||||
@Nullable String description);
|
||||
|
||||
CompletionSKFunction createFunction(
|
||||
String prompt,
|
||||
@Nullable String functionName,
|
||||
@Nullable String skillName,
|
||||
@Nullable String description,
|
||||
PromptTemplateConfig.CompletionConfig completionConfig);
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.textcompletion; // Copyright (c) Microsoft. All rights
|
||||
// reserved.
|
||||
|
||||
import com.microsoft.openai.OpenAIAsyncClient;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** Interface for text completion services */
|
||||
public interface TextCompletion {
|
||||
// TODO: Support Cancellation Token
|
||||
|
||||
/**
|
||||
* Creates a completion for the prompt and settings.
|
||||
*
|
||||
* @param text The prompt to complete.
|
||||
* @param requestSettings Request settings for the completion API
|
||||
* @return Text generated by the remote model
|
||||
*/
|
||||
Mono<List<String>> completeAsync(String text, CompletionRequestSettings requestSettings);
|
||||
|
||||
interface Builder {
|
||||
TextCompletion build(OpenAIAsyncClient client, String modelId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?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.semantickernel</groupId>
|
||||
<artifactId>semantickernel-bom</artifactId>
|
||||
<version>0.2.0-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel</groupId>
|
||||
<artifactId>semantickernel-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel</groupId>
|
||||
<artifactId>semantickernel-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel.connectors</groupId>
|
||||
<artifactId>semantickernel-connectors</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel</groupId>
|
||||
<artifactId>semantickernel-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel.extensions</groupId>
|
||||
<artifactId>sequentialplanner-extensions</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel</groupId>
|
||||
<artifactId>semantickernel-core-skills</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>2.0.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
<version>2.14.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.14.2</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-core</artifactId>
|
||||
<version>3.5.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>jsr305</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel</groupId>
|
||||
<artifactId>openai-sdk</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.azure</groupId>
|
||||
<artifactId>azure-core-http-netty</artifactId>
|
||||
<version>1.13.2</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
</project>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?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.semantickernel</groupId>
|
||||
<artifactId>semantickernel-parent</artifactId>
|
||||
<version>0.2.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<groupId>com.microsoft.semantickernel.connectors</groupId>
|
||||
<artifactId>semantickernel-connectors-parent</artifactId>
|
||||
|
||||
<modules>
|
||||
<module>semantickernel-connectors</module>
|
||||
</modules>
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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.semantickernel.connectors</groupId>
|
||||
<artifactId>semantickernel-connectors-parent</artifactId>
|
||||
<version>0.2.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>semantickernel-connectors</artifactId>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel</groupId>
|
||||
<artifactId>semantickernel-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel</groupId>
|
||||
<artifactId>openai-sdk</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.connectors.ai.openai.azuresdk; // Copyright (c) Microsoft. All
|
||||
// rights reserved.
|
||||
|
||||
import com.microsoft.openai.OpenAIAsyncClient;
|
||||
|
||||
public abstract class ClientBase {
|
||||
private final String modelId;
|
||||
private final OpenAIAsyncClient client;
|
||||
|
||||
public ClientBase(OpenAIAsyncClient client, String modelId) {
|
||||
this.modelId = modelId;
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
protected String getModelId() {
|
||||
return modelId;
|
||||
}
|
||||
|
||||
protected OpenAIAsyncClient getClient() {
|
||||
return client;
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.connectors.ai.openai.textcompletion;
|
||||
|
||||
import com.azure.ai.openai.models.Choice;
|
||||
import com.azure.ai.openai.models.Completions;
|
||||
import com.azure.ai.openai.models.CompletionsOptions;
|
||||
import com.microsoft.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.ai.AIException;
|
||||
import com.microsoft.semantickernel.connectors.ai.openai.azuresdk.ClientBase;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionRequestSettings;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/// <summary>
|
||||
/// OpenAI text completion service.
|
||||
/// TODO: forward ETW logging to ILogger, see
|
||||
// https://learn.microsoft.com/en-us/dotnet/azure/sdk/logging
|
||||
/// </summary>
|
||||
public class OpenAITextCompletion extends ClientBase implements TextCompletion {
|
||||
/// <summary>
|
||||
/// Create an instance of the OpenAI text completion connector
|
||||
/// </summary>
|
||||
/// <param name="modelId">Model name</param>
|
||||
/// <param name="apiKey">OpenAI API Key</param>
|
||||
/// <param name="organization">OpenAI Organization Id (usually optional)</param>
|
||||
/// <param name="handlerFactory">Retry handler factory for HTTP requests.</param>
|
||||
/// <param name="log">Application logger</param>
|
||||
public OpenAITextCompletion(OpenAIAsyncClient client, String modelId) {
|
||||
super(client, modelId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<List<String>> completeAsync(
|
||||
String text, CompletionRequestSettings requestSettings) {
|
||||
return this.internalCompleteTextAsync(text, requestSettings);
|
||||
}
|
||||
|
||||
protected Mono<List<String>> internalCompleteTextAsync(
|
||||
String text, CompletionRequestSettings requestSettings) {
|
||||
// TODO
|
||||
|
||||
if (requestSettings.getMaxTokens() < 1) {
|
||||
throw new AIException(AIException.ErrorCodes.InvalidRequest, "Max tokens must be >0");
|
||||
}
|
||||
|
||||
CompletionsOptions completionsOptions =
|
||||
new CompletionsOptions(Collections.singletonList(text))
|
||||
.setMaxTokens(requestSettings.getMaxTokens())
|
||||
.setTemperature(requestSettings.getTemperature())
|
||||
.setTopP(requestSettings.getTopP())
|
||||
.setFrequencyPenalty(requestSettings.getFrequencyPenalty())
|
||||
.setPresencePenalty(requestSettings.getPresencePenalty())
|
||||
.setModel(getModelId())
|
||||
.setUser(null);
|
||||
|
||||
return getClient()
|
||||
.getCompletions(getModelId(), completionsOptions)
|
||||
.flatMapIterable(Completions::getChoices)
|
||||
.mapNotNull(Choice::getText)
|
||||
.collectList();
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.connectors.ai.openai.textcompletion;
|
||||
|
||||
import com.microsoft.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
|
||||
public class OpenAITextCompletionBuilder implements TextCompletion.Builder {
|
||||
@Override
|
||||
public TextCompletion build(OpenAIAsyncClient client, String modelId) {
|
||||
return new OpenAITextCompletion(client, modelId);
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.connectors.ai.openai.textembeddings;
|
||||
|
||||
import com.azure.ai.openai.models.EmbeddingItem;
|
||||
import com.azure.ai.openai.models.Embeddings;
|
||||
import com.azure.ai.openai.models.EmbeddingsOptions;
|
||||
import com.microsoft.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.ai.embeddings.Embedding;
|
||||
import com.microsoft.semantickernel.ai.embeddings.EmbeddingGeneration;
|
||||
import com.microsoft.semantickernel.connectors.ai.openai.azuresdk.ClientBase;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class OpenAITextEmbeddingGeneration extends ClientBase
|
||||
implements EmbeddingGeneration<String, Double> {
|
||||
|
||||
public OpenAITextEmbeddingGeneration(OpenAIAsyncClient client, String modelId) {
|
||||
super(client, modelId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<List<Embedding<Double>>> generateEmbeddingsAsync(List<String> data) {
|
||||
return this.internalGenerateTextEmbeddingsAsync(data);
|
||||
}
|
||||
|
||||
protected Mono<List<Embedding<Double>>> internalGenerateTextEmbeddingsAsync(List<String> data) {
|
||||
EmbeddingsOptions options = new EmbeddingsOptions(data).setModel(getModelId());
|
||||
|
||||
return getClient()
|
||||
.getEmbeddings(getModelId(), options)
|
||||
.flatMapIterable(Embeddings::getData)
|
||||
.mapNotNull(EmbeddingItem::getEmbedding)
|
||||
.mapNotNull(Embedding::new)
|
||||
.collectList();
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.connectors.ai.openai.textembeddings;
|
||||
|
||||
import com.microsoft.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.ai.embeddings.EmbeddingGeneration;
|
||||
|
||||
public class OpenAITextEmbeddingGenerationBuilder
|
||||
implements EmbeddingGeneration.Builder<String, Double> {
|
||||
|
||||
@Override
|
||||
public EmbeddingGeneration<String, Double> build(OpenAIAsyncClient client, String modelId) {
|
||||
return new OpenAITextEmbeddingGeneration(client, modelId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?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.semantickernel</groupId>
|
||||
<artifactId>semantickernel-parent</artifactId>
|
||||
<version>0.2.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>semantickernel-core-skills</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel</groupId>
|
||||
<artifactId>semantickernel-api</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user