Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions PACKAGES.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,6 +39,9 @@ A BOM is provided that can be used to define the versions of all Semantic Kernel
`semantickernel-aiservices-openai`
: Provides a connector that can be used to interact with the OpenAI API.

`semantickernel-aiservices-voyageai`
: Provides connectors for VoyageAI's embedding and reranking services, including text embeddings, contextualized embeddings, multimodal embeddings, and document reranking.

## Example Configurations

### Example: OpenAI + SQLite
Expand DownExpand Up@@ -72,5 +75,36 @@ POM XML for a simple project that uses OpenAI.
</project>
```

### Example: VoyageAI Embeddings and Reranking

POM XML for a project that uses VoyageAI for embeddings and reranking.

```xml

<project>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-bom</artifactId>
<version>${semantickernel.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-aiservices-voyageai</artifactId>
</dependency>
</dependencies>
</project>
```



89 changes: 89 additions & 0 deletions aiservices/voyageai/pom.xml
Original file line numberDiff line numberDiff line change
@@ -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.semantic-kernel</groupId>
<artifactId>semantickernel-parent</artifactId>
<version>1.5.1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

<artifactId>semantickernel-aiservices-voyageai</artifactId>
<name>Semantic Kernel VoyageAI Services</name>
<description>VoyageAI services for Semantic Kernel</description>

<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-builders</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-ai-services</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-textembedding-services</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-exceptions</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-localization</artifactId>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<scope>compile</scope>
</dependency>

<!-- HTTP Client -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>

<!-- Reactive Streams -->
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
</dependency>

<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>

<!-- Test Dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.aiservices.voyageai.contextualizedembedding;

import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIClient;
import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIModels;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.services.textembedding.Embedding;
import com.microsoft.semantickernel.services.textembedding.TextEmbeddingGenerationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
* VoyageAI contextualized embedding generation service.
* Generates embeddings that capture both local chunk details and global document-level metadata.
* Supports models like voyage-3.
*/
public final class VoyageAIContextualizedEmbeddingGenerationService implements TextEmbeddingGenerationService {

private static final Logger LOGGER = LoggerFactory.getLogger(VoyageAIContextualizedEmbeddingGenerationService.class);

private final VoyageAIClient client;
private final String modelId;
private final String serviceId;

/**
* Creates a new instance of VoyageAI contextualized embedding generation service.
*
* @param client VoyageAI client
* @param modelId Model ID (e.g., "voyage-3")
* @param serviceId Optional service ID
*/
public VoyageAIContextualizedEmbeddingGenerationService(
VoyageAIClient client,
String modelId,
@Nullable String serviceId) {

if (client == null) {
throw new IllegalArgumentException("Client cannot be null");
}
if (modelId == null || modelId.trim().isEmpty()) {
throw new IllegalArgumentException("Model ID cannot be null or empty");
}

this.client = client;
this.modelId = modelId;
this.serviceId = serviceId != null ? serviceId : PromptExecutionSettings.DEFAULT_SERVICE_ID;
}

@Override
public String getServiceId() {
return serviceId;
}

@Override
public String getModelId() {
return modelId;
}

/**
* Generates contextualized embeddings for document chunks.
*
* @param inputs List of lists where each inner list contains document chunks
* @return A Mono containing a list of embeddings for all chunks across all documents
*/
public Mono<List<Embedding>> generateContextualizedEmbeddingsAsync(List<List<String>> inputs) {
if (inputs == null || inputs.isEmpty()) {
return Mono.just(Collections.emptyList());
}

LOGGER.debug("Generating contextualized embeddings for {} document groups using model {}",
inputs.size(), modelId);

VoyageAIModels.ContextualizedEmbeddingRequest request =
new VoyageAIModels.ContextualizedEmbeddingRequest();
request.setInputs(inputs);
request.setModel(modelId);

return client.sendRequestAsync(
"contextualizedembeddings",
request,
VoyageAIModels.ContextualizedEmbeddingResponse.class)
.map(response -> {
List<Embedding> embeddings = new ArrayList<>();
// Parse nested data structure: {"data":[{"data":[{"embedding":[...]}]}]}
for (VoyageAIModels.ContextualizedEmbeddingDataList dataList : response.getData()) {
for (VoyageAIModels.EmbeddingDataItem item : dataList.getData()) {
embeddings.add(new Embedding(item.getEmbedding()));
}
}

LOGGER.debug("Received {} contextualized embeddings from VoyageAI", embeddings.size());
return embeddings;
});
}

/**
* Generates embeddings for the given text.
* For standard text embedding, wraps the data as a single input.
*
* @param data The text to generate embeddings for
* @return A Mono that completes with the embedding
*/
@Override
public Mono<Embedding> generateEmbeddingAsync(String data) {
return generateEmbeddingsAsync(Arrays.asList(data))
.flatMap(embeddings -> {
if (embeddings.isEmpty()) {
return Mono.empty();
}
return Mono.just(embeddings.get(0));
});
}

/**
* Generates embeddings for the given texts.
* Each text is treated as a separate document for contextualized embeddings.
*
* @param data The texts to generate embeddings for
* @return A Mono that completes with the list of embeddings
*/
@Override
public Mono<List<Embedding>> generateEmbeddingsAsync(List<String> data) {
if (data == null || data.isEmpty()) {
return Mono.just(Collections.emptyList());
}

// Convert each string to a single-element list for contextualized embeddings
List<List<String>> inputs = new ArrayList<>();
for (String text : data) {
inputs.add(Arrays.asList(text));
}

return generateContextualizedEmbeddingsAsync(inputs);
}

/**
* Creates a builder for VoyageAI contextualized embedding generation service.
*
* @return A new builder instance
*/
public static Builder builder() {
return new Builder();
}

/**
* Builder for {@link VoyageAIContextualizedEmbeddingGenerationService}.
*/
public static class Builder {
private VoyageAIClient client;
private String modelId;
private String serviceId;

/**
* Sets the VoyageAI client.
*
* @param client VoyageAI client
* @return This builder
*/
public Builder withClient(VoyageAIClient client) {
this.client = client;
return this;
}

/**
* Sets the model ID.
*
* @param modelId Model ID (e.g., "voyage-3")
* @return This builder
*/
public Builder withModelId(String modelId) {
this.modelId = modelId;
return this;
}

/**
* Sets the service ID.
*
* @param serviceId Service ID
* @return This builder
*/
public Builder withServiceId(String serviceId) {
this.serviceId = serviceId;
return this;
}

/**
* Builds the VoyageAI contextualized embedding generation service.
*
* @return A new instance of VoyageAIContextualizedEmbeddingGenerationService
*/
public VoyageAIContextualizedEmbeddingGenerationService build() {
return new VoyageAIContextualizedEmbeddingGenerationService(client, modelId, serviceId);
}
}
}
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions PACKAGES.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,6 +39,9 @@ A BOM is provided that can be used to define the versions of all Semantic Kernel
`semantickernel-aiservices-openai`
: Provides a connector that can be used to interact with the OpenAI API.

`semantickernel-aiservices-voyageai`
: Provides connectors for VoyageAI's embedding and reranking services, including text embeddings, contextualized embeddings, multimodal embeddings, and document reranking.

## Example Configurations

### Example: OpenAI + SQLite
Expand DownExpand Up@@ -72,5 +75,36 @@ POM XML for a simple project that uses OpenAI.
</project>
```

### Example: VoyageAI Embeddings and Reranking

POM XML for a project that uses VoyageAI for embeddings and reranking.

```xml

<project>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-bom</artifactId>
<version>${semantickernel.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-aiservices-voyageai</artifactId>
</dependency>
</dependencies>
</project>
```



89 changes: 89 additions & 0 deletions aiservices/voyageai/pom.xml
Original file line numberDiff line numberDiff line change
@@ -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.semantic-kernel</groupId>
<artifactId>semantickernel-parent</artifactId>
<version>1.5.1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

<artifactId>semantickernel-aiservices-voyageai</artifactId>
<name>Semantic Kernel VoyageAI Services</name>
<description>VoyageAI services for Semantic Kernel</description>

<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-builders</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-ai-services</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-textembedding-services</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-exceptions</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-localization</artifactId>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<scope>compile</scope>
</dependency>

<!-- HTTP Client -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>

<!-- Reactive Streams -->
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
</dependency>

<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>

<!-- Test Dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.aiservices.voyageai.contextualizedembedding;

import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIClient;
import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIModels;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.services.textembedding.Embedding;
import com.microsoft.semantickernel.services.textembedding.TextEmbeddingGenerationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
* VoyageAI contextualized embedding generation service.
* Generates embeddings that capture both local chunk details and global document-level metadata.
* Supports models like voyage-3.
*/
public final class VoyageAIContextualizedEmbeddingGenerationService implements TextEmbeddingGenerationService {

private static final Logger LOGGER = LoggerFactory.getLogger(VoyageAIContextualizedEmbeddingGenerationService.class);

private final VoyageAIClient client;
private final String modelId;
private final String serviceId;

/**
* Creates a new instance of VoyageAI contextualized embedding generation service.
*
* @param client VoyageAI client
* @param modelId Model ID (e.g., "voyage-3")
* @param serviceId Optional service ID
*/
public VoyageAIContextualizedEmbeddingGenerationService(
VoyageAIClient client,
String modelId,
@Nullable String serviceId) {

if (client == null) {
throw new IllegalArgumentException("Client cannot be null");
}
if (modelId == null || modelId.trim().isEmpty()) {
throw new IllegalArgumentException("Model ID cannot be null or empty");
}

this.client = client;
this.modelId = modelId;
this.serviceId = serviceId != null ? serviceId : PromptExecutionSettings.DEFAULT_SERVICE_ID;
}

@Override
public String getServiceId() {
return serviceId;
}

@Override
public String getModelId() {
return modelId;
}

/**
* Generates contextualized embeddings for document chunks.
*
* @param inputs List of lists where each inner list contains document chunks
* @return A Mono containing a list of embeddings for all chunks across all documents
*/
public Mono<List<Embedding>> generateContextualizedEmbeddingsAsync(List<List<String>> inputs) {
if (inputs == null || inputs.isEmpty()) {
return Mono.just(Collections.emptyList());
}

LOGGER.debug("Generating contextualized embeddings for {} document groups using model {}",
inputs.size(), modelId);

VoyageAIModels.ContextualizedEmbeddingRequest request =
new VoyageAIModels.ContextualizedEmbeddingRequest();
request.setInputs(inputs);
request.setModel(modelId);

return client.sendRequestAsync(
"contextualizedembeddings",
request,
VoyageAIModels.ContextualizedEmbeddingResponse.class)
.map(response -> {
List<Embedding> embeddings = new ArrayList<>();
// Parse nested data structure: {"data":[{"data":[{"embedding":[...]}]}]}
for (VoyageAIModels.ContextualizedEmbeddingDataList dataList : response.getData()) {
for (VoyageAIModels.EmbeddingDataItem item : dataList.getData()) {
embeddings.add(new Embedding(item.getEmbedding()));
}
}

LOGGER.debug("Received {} contextualized embeddings from VoyageAI", embeddings.size());
return embeddings;
});
}

/**
* Generates embeddings for the given text.
* For standard text embedding, wraps the data as a single input.
*
* @param data The text to generate embeddings for
* @return A Mono that completes with the embedding
*/
@Override
public Mono<Embedding> generateEmbeddingAsync(String data) {
return generateEmbeddingsAsync(Arrays.asList(data))
.flatMap(embeddings -> {
if (embeddings.isEmpty()) {
return Mono.empty();
}
return Mono.just(embeddings.get(0));
});
}

/**
* Generates embeddings for the given texts.
* Each text is treated as a separate document for contextualized embeddings.
*
* @param data The texts to generate embeddings for
* @return A Mono that completes with the list of embeddings
*/
@Override
public Mono<List<Embedding>> generateEmbeddingsAsync(List<String> data) {
if (data == null || data.isEmpty()) {
return Mono.just(Collections.emptyList());
}

// Convert each string to a single-element list for contextualized embeddings
List<List<String>> inputs = new ArrayList<>();
for (String text : data) {
inputs.add(Arrays.asList(text));
}

return generateContextualizedEmbeddingsAsync(inputs);
}

/**
* Creates a builder for VoyageAI contextualized embedding generation service.
*
* @return A new builder instance
*/
public static Builder builder() {
return new Builder();
}

/**
* Builder for {@link VoyageAIContextualizedEmbeddingGenerationService}.
*/
public static class Builder {
private VoyageAIClient client;
private String modelId;
private String serviceId;

/**
* Sets the VoyageAI client.
*
* @param client VoyageAI client
* @return This builder
*/
public Builder withClient(VoyageAIClient client) {
this.client = client;
return this;
}

/**
* Sets the model ID.
*
* @param modelId Model ID (e.g., "voyage-3")
* @return This builder
*/
public Builder withModelId(String modelId) {
this.modelId = modelId;
return this;
}

/**
* Sets the service ID.
*
* @param serviceId Service ID
* @return This builder
*/
public Builder withServiceId(String serviceId) {
this.serviceId = serviceId;
return this;
}

/**
* Builds the VoyageAI contextualized embedding generation service.
*
* @return A new instance of VoyageAIContextualizedEmbeddingGenerationService
*/
public VoyageAIContextualizedEmbeddingGenerationService build() {
return new VoyageAIContextualizedEmbeddingGenerationService(client, modelId, serviceId);
}
}
}
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions PACKAGES.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,6 +39,9 @@ A BOM is provided that can be used to define the versions of all Semantic Kernel
`semantickernel-aiservices-openai`
: Provides a connector that can be used to interact with the OpenAI API.

`semantickernel-aiservices-voyageai`
: Provides connectors for VoyageAI's embedding and reranking services, including text embeddings, contextualized embeddings, multimodal embeddings, and document reranking.

## Example Configurations

### Example: OpenAI + SQLite
Expand DownExpand Up@@ -72,5 +75,36 @@ POM XML for a simple project that uses OpenAI.
</project>
```

### Example: VoyageAI Embeddings and Reranking

POM XML for a project that uses VoyageAI for embeddings and reranking.

```xml

<project>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-bom</artifactId>
<version>${semantickernel.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-aiservices-voyageai</artifactId>
</dependency>
</dependencies>
</project>
```



89 changes: 89 additions & 0 deletions aiservices/voyageai/pom.xml
Original file line numberDiff line numberDiff line change
@@ -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.semantic-kernel</groupId>
<artifactId>semantickernel-parent</artifactId>
<version>1.5.1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

<artifactId>semantickernel-aiservices-voyageai</artifactId>
<name>Semantic Kernel VoyageAI Services</name>
<description>VoyageAI services for Semantic Kernel</description>

<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-builders</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-ai-services</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-textembedding-services</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-exceptions</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-localization</artifactId>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<scope>compile</scope>
</dependency>

<!-- HTTP Client -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>

<!-- Reactive Streams -->
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
</dependency>

<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>

<!-- Test Dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.aiservices.voyageai.contextualizedembedding;

import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIClient;
import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIModels;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.services.textembedding.Embedding;
import com.microsoft.semantickernel.services.textembedding.TextEmbeddingGenerationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
* VoyageAI contextualized embedding generation service.
* Generates embeddings that capture both local chunk details and global document-level metadata.
* Supports models like voyage-3.
*/
public final class VoyageAIContextualizedEmbeddingGenerationService implements TextEmbeddingGenerationService {

private static final Logger LOGGER = LoggerFactory.getLogger(VoyageAIContextualizedEmbeddingGenerationService.class);

private final VoyageAIClient client;
private final String modelId;
private final String serviceId;

/**
* Creates a new instance of VoyageAI contextualized embedding generation service.
*
* @param client VoyageAI client
* @param modelId Model ID (e.g., "voyage-3")
* @param serviceId Optional service ID
*/
public VoyageAIContextualizedEmbeddingGenerationService(
VoyageAIClient client,
String modelId,
@Nullable String serviceId) {

if (client == null) {
throw new IllegalArgumentException("Client cannot be null");
}
if (modelId == null || modelId.trim().isEmpty()) {
throw new IllegalArgumentException("Model ID cannot be null or empty");
}

this.client = client;
this.modelId = modelId;
this.serviceId = serviceId != null ? serviceId : PromptExecutionSettings.DEFAULT_SERVICE_ID;
}

@Override
public String getServiceId() {
return serviceId;
}

@Override
public String getModelId() {
return modelId;
}

/**
* Generates contextualized embeddings for document chunks.
*
* @param inputs List of lists where each inner list contains document chunks
* @return A Mono containing a list of embeddings for all chunks across all documents
*/
public Mono<List<Embedding>> generateContextualizedEmbeddingsAsync(List<List<String>> inputs) {
if (inputs == null || inputs.isEmpty()) {
return Mono.just(Collections.emptyList());
}

LOGGER.debug("Generating contextualized embeddings for {} document groups using model {}",
inputs.size(), modelId);

VoyageAIModels.ContextualizedEmbeddingRequest request =
new VoyageAIModels.ContextualizedEmbeddingRequest();
request.setInputs(inputs);
request.setModel(modelId);

return client.sendRequestAsync(
"contextualizedembeddings",
request,
VoyageAIModels.ContextualizedEmbeddingResponse.class)
.map(response -> {
List<Embedding> embeddings = new ArrayList<>();
// Parse nested data structure: {"data":[{"data":[{"embedding":[...]}]}]}
for (VoyageAIModels.ContextualizedEmbeddingDataList dataList : response.getData()) {
for (VoyageAIModels.EmbeddingDataItem item : dataList.getData()) {
embeddings.add(new Embedding(item.getEmbedding()));
}
}

LOGGER.debug("Received {} contextualized embeddings from VoyageAI", embeddings.size());
return embeddings;
});
}

/**
* Generates embeddings for the given text.
* For standard text embedding, wraps the data as a single input.
*
* @param data The text to generate embeddings for
* @return A Mono that completes with the embedding
*/
@Override
public Mono<Embedding> generateEmbeddingAsync(String data) {
return generateEmbeddingsAsync(Arrays.asList(data))
.flatMap(embeddings -> {
if (embeddings.isEmpty()) {
return Mono.empty();
}
return Mono.just(embeddings.get(0));
});
}

/**
* Generates embeddings for the given texts.
* Each text is treated as a separate document for contextualized embeddings.
*
* @param data The texts to generate embeddings for
* @return A Mono that completes with the list of embeddings
*/
@Override
public Mono<List<Embedding>> generateEmbeddingsAsync(List<String> data) {
if (data == null || data.isEmpty()) {
return Mono.just(Collections.emptyList());
}

// Convert each string to a single-element list for contextualized embeddings
List<List<String>> inputs = new ArrayList<>();
for (String text : data) {
inputs.add(Arrays.asList(text));
}

return generateContextualizedEmbeddingsAsync(inputs);
}

/**
* Creates a builder for VoyageAI contextualized embedding generation service.
*
* @return A new builder instance
*/
public static Builder builder() {
return new Builder();
}

/**
* Builder for {@link VoyageAIContextualizedEmbeddingGenerationService}.
*/
public static class Builder {
private VoyageAIClient client;
private String modelId;
private String serviceId;

/**
* Sets the VoyageAI client.
*
* @param client VoyageAI client
* @return This builder
*/
public Builder withClient(VoyageAIClient client) {
this.client = client;
return this;
}

/**
* Sets the model ID.
*
* @param modelId Model ID (e.g., "voyage-3")
* @return This builder
*/
public Builder withModelId(String modelId) {
this.modelId = modelId;
return this;
}

/**
* Sets the service ID.
*
* @param serviceId Service ID
* @return This builder
*/
public Builder withServiceId(String serviceId) {
this.serviceId = serviceId;
return this;
}

/**
* Builds the VoyageAI contextualized embedding generation service.
*
* @return A new instance of VoyageAIContextualizedEmbeddingGenerationService
*/
public VoyageAIContextualizedEmbeddingGenerationService build() {
return new VoyageAIContextualizedEmbeddingGenerationService(client, modelId, serviceId);
}
}
}
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions PACKAGES.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,6 +39,9 @@ A BOM is provided that can be used to define the versions of all Semantic Kernel
`semantickernel-aiservices-openai`
: Provides a connector that can be used to interact with the OpenAI API.

`semantickernel-aiservices-voyageai`
: Provides connectors for VoyageAI's embedding and reranking services, including text embeddings, contextualized embeddings, multimodal embeddings, and document reranking.

## Example Configurations

### Example: OpenAI + SQLite
Expand DownExpand Up@@ -72,5 +75,36 @@ POM XML for a simple project that uses OpenAI.
</project>
```

### Example: VoyageAI Embeddings and Reranking

POM XML for a project that uses VoyageAI for embeddings and reranking.

```xml

<project>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-bom</artifactId>
<version>${semantickernel.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-aiservices-voyageai</artifactId>
</dependency>
</dependencies>
</project>
```



89 changes: 89 additions & 0 deletions aiservices/voyageai/pom.xml
Original file line numberDiff line numberDiff line change
@@ -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.semantic-kernel</groupId>
<artifactId>semantickernel-parent</artifactId>
<version>1.5.1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

<artifactId>semantickernel-aiservices-voyageai</artifactId>
<name>Semantic Kernel VoyageAI Services</name>
<description>VoyageAI services for Semantic Kernel</description>

<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-builders</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-ai-services</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-textembedding-services</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-exceptions</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-localization</artifactId>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<scope>compile</scope>
</dependency>

<!-- HTTP Client -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>

<!-- Reactive Streams -->
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
</dependency>

<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>

<!-- Test Dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.aiservices.voyageai.contextualizedembedding;

import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIClient;
import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIModels;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.services.textembedding.Embedding;
import com.microsoft.semantickernel.services.textembedding.TextEmbeddingGenerationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
* VoyageAI contextualized embedding generation service.
* Generates embeddings that capture both local chunk details and global document-level metadata.
* Supports models like voyage-3.
*/
public final class VoyageAIContextualizedEmbeddingGenerationService implements TextEmbeddingGenerationService {

private static final Logger LOGGER = LoggerFactory.getLogger(VoyageAIContextualizedEmbeddingGenerationService.class);

private final VoyageAIClient client;
private final String modelId;
private final String serviceId;

/**
* Creates a new instance of VoyageAI contextualized embedding generation service.
*
* @param client VoyageAI client
* @param modelId Model ID (e.g., "voyage-3")
* @param serviceId Optional service ID
*/
public VoyageAIContextualizedEmbeddingGenerationService(
VoyageAIClient client,
String modelId,
@Nullable String serviceId) {

if (client == null) {
throw new IllegalArgumentException("Client cannot be null");
}
if (modelId == null || modelId.trim().isEmpty()) {
throw new IllegalArgumentException("Model ID cannot be null or empty");
}

this.client = client;
this.modelId = modelId;
this.serviceId = serviceId != null ? serviceId : PromptExecutionSettings.DEFAULT_SERVICE_ID;
}

@Override
public String getServiceId() {
return serviceId;
}

@Override
public String getModelId() {
return modelId;
}

/**
* Generates contextualized embeddings for document chunks.
*
* @param inputs List of lists where each inner list contains document chunks
* @return A Mono containing a list of embeddings for all chunks across all documents
*/
public Mono<List<Embedding>> generateContextualizedEmbeddingsAsync(List<List<String>> inputs) {
if (inputs == null || inputs.isEmpty()) {
return Mono.just(Collections.emptyList());
}

LOGGER.debug("Generating contextualized embeddings for {} document groups using model {}",
inputs.size(), modelId);

VoyageAIModels.ContextualizedEmbeddingRequest request =
new VoyageAIModels.ContextualizedEmbeddingRequest();
request.setInputs(inputs);
request.setModel(modelId);

return client.sendRequestAsync(
"contextualizedembeddings",
request,
VoyageAIModels.ContextualizedEmbeddingResponse.class)
.map(response -> {
List<Embedding> embeddings = new ArrayList<>();
// Parse nested data structure: {"data":[{"data":[{"embedding":[...]}]}]}
for (VoyageAIModels.ContextualizedEmbeddingDataList dataList : response.getData()) {
for (VoyageAIModels.EmbeddingDataItem item : dataList.getData()) {
embeddings.add(new Embedding(item.getEmbedding()));
}
}

LOGGER.debug("Received {} contextualized embeddings from VoyageAI", embeddings.size());
return embeddings;
});
}

/**
* Generates embeddings for the given text.
* For standard text embedding, wraps the data as a single input.
*
* @param data The text to generate embeddings for
* @return A Mono that completes with the embedding
*/
@Override
public Mono<Embedding> generateEmbeddingAsync(String data) {
return generateEmbeddingsAsync(Arrays.asList(data))
.flatMap(embeddings -> {
if (embeddings.isEmpty()) {
return Mono.empty();
}
return Mono.just(embeddings.get(0));
});
}

/**
* Generates embeddings for the given texts.
* Each text is treated as a separate document for contextualized embeddings.
*
* @param data The texts to generate embeddings for
* @return A Mono that completes with the list of embeddings
*/
@Override
public Mono<List<Embedding>> generateEmbeddingsAsync(List<String> data) {
if (data == null || data.isEmpty()) {
return Mono.just(Collections.emptyList());
}

// Convert each string to a single-element list for contextualized embeddings
List<List<String>> inputs = new ArrayList<>();
for (String text : data) {
inputs.add(Arrays.asList(text));
}

return generateContextualizedEmbeddingsAsync(inputs);
}

/**
* Creates a builder for VoyageAI contextualized embedding generation service.
*
* @return A new builder instance
*/
public static Builder builder() {
return new Builder();
}

/**
* Builder for {@link VoyageAIContextualizedEmbeddingGenerationService}.
*/
public static class Builder {
private VoyageAIClient client;
private String modelId;
private String serviceId;

/**
* Sets the VoyageAI client.
*
* @param client VoyageAI client
* @return This builder
*/
public Builder withClient(VoyageAIClient client) {
this.client = client;
return this;
}

/**
* Sets the model ID.
*
* @param modelId Model ID (e.g., "voyage-3")
* @return This builder
*/
public Builder withModelId(String modelId) {
this.modelId = modelId;
return this;
}

/**
* Sets the service ID.
*
* @param serviceId Service ID
* @return This builder
*/
public Builder withServiceId(String serviceId) {
this.serviceId = serviceId;
return this;
}

/**
* Builds the VoyageAI contextualized embedding generation service.
*
* @return A new instance of VoyageAIContextualizedEmbeddingGenerationService
*/
public VoyageAIContextualizedEmbeddingGenerationService build() {
return new VoyageAIContextualizedEmbeddingGenerationService(client, modelId, serviceId);
}
}
}
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions PACKAGES.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,6 +39,9 @@ A BOM is provided that can be used to define the versions of all Semantic Kernel
`semantickernel-aiservices-openai`
: Provides a connector that can be used to interact with the OpenAI API.

`semantickernel-aiservices-voyageai`
: Provides connectors for VoyageAI's embedding and reranking services, including text embeddings, contextualized embeddings, multimodal embeddings, and document reranking.

## Example Configurations

### Example: OpenAI + SQLite
Expand DownExpand Up@@ -72,5 +75,36 @@ POM XML for a simple project that uses OpenAI.
</project>
```

### Example: VoyageAI Embeddings and Reranking

POM XML for a project that uses VoyageAI for embeddings and reranking.

```xml

<project>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-bom</artifactId>
<version>${semantickernel.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-aiservices-voyageai</artifactId>
</dependency>
</dependencies>
</project>
```



89 changes: 89 additions & 0 deletions aiservices/voyageai/pom.xml
Original file line numberDiff line numberDiff line change
@@ -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.semantic-kernel</groupId>
<artifactId>semantickernel-parent</artifactId>
<version>1.5.1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

<artifactId>semantickernel-aiservices-voyageai</artifactId>
<name>Semantic Kernel VoyageAI Services</name>
<description>VoyageAI services for Semantic Kernel</description>

<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-builders</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-ai-services</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-textembedding-services</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-exceptions</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-localization</artifactId>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<scope>compile</scope>
</dependency>

<!-- HTTP Client -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>

<!-- Reactive Streams -->
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
</dependency>

<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>

<!-- Test Dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.aiservices.voyageai.contextualizedembedding;

import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIClient;
import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIModels;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.services.textembedding.Embedding;
import com.microsoft.semantickernel.services.textembedding.TextEmbeddingGenerationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
* VoyageAI contextualized embedding generation service.
* Generates embeddings that capture both local chunk details and global document-level metadata.
* Supports models like voyage-3.
*/
public final class VoyageAIContextualizedEmbeddingGenerationService implements TextEmbeddingGenerationService {

private static final Logger LOGGER = LoggerFactory.getLogger(VoyageAIContextualizedEmbeddingGenerationService.class);

private final VoyageAIClient client;
private final String modelId;
private final String serviceId;

/**
* Creates a new instance of VoyageAI contextualized embedding generation service.
*
* @param client VoyageAI client
* @param modelId Model ID (e.g., "voyage-3")
* @param serviceId Optional service ID
*/
public VoyageAIContextualizedEmbeddingGenerationService(
VoyageAIClient client,
String modelId,
@Nullable String serviceId) {

if (client == null) {
throw new IllegalArgumentException("Client cannot be null");
}
if (modelId == null || modelId.trim().isEmpty()) {
throw new IllegalArgumentException("Model ID cannot be null or empty");
}

this.client = client;
this.modelId = modelId;
this.serviceId = serviceId != null ? serviceId : PromptExecutionSettings.DEFAULT_SERVICE_ID;
}

@Override
public String getServiceId() {
return serviceId;
}

@Override
public String getModelId() {
return modelId;
}

/**
* Generates contextualized embeddings for document chunks.
*
* @param inputs List of lists where each inner list contains document chunks
* @return A Mono containing a list of embeddings for all chunks across all documents
*/
public Mono<List<Embedding>> generateContextualizedEmbeddingsAsync(List<List<String>> inputs) {
if (inputs == null || inputs.isEmpty()) {
return Mono.just(Collections.emptyList());
}

LOGGER.debug("Generating contextualized embeddings for {} document groups using model {}",
inputs.size(), modelId);

VoyageAIModels.ContextualizedEmbeddingRequest request =
new VoyageAIModels.ContextualizedEmbeddingRequest();
request.setInputs(inputs);
request.setModel(modelId);

return client.sendRequestAsync(
"contextualizedembeddings",
request,
VoyageAIModels.ContextualizedEmbeddingResponse.class)
.map(response -> {
List<Embedding> embeddings = new ArrayList<>();
// Parse nested data structure: {"data":[{"data":[{"embedding":[...]}]}]}
for (VoyageAIModels.ContextualizedEmbeddingDataList dataList : response.getData()) {
for (VoyageAIModels.EmbeddingDataItem item : dataList.getData()) {
embeddings.add(new Embedding(item.getEmbedding()));
}
}

LOGGER.debug("Received {} contextualized embeddings from VoyageAI", embeddings.size());
return embeddings;
});
}

/**
* Generates embeddings for the given text.
* For standard text embedding, wraps the data as a single input.
*
* @param data The text to generate embeddings for
* @return A Mono that completes with the embedding
*/
@Override
public Mono<Embedding> generateEmbeddingAsync(String data) {
return generateEmbeddingsAsync(Arrays.asList(data))
.flatMap(embeddings -> {
if (embeddings.isEmpty()) {
return Mono.empty();
}
return Mono.just(embeddings.get(0));
});
}

/**
* Generates embeddings for the given texts.
* Each text is treated as a separate document for contextualized embeddings.
*
* @param data The texts to generate embeddings for
* @return A Mono that completes with the list of embeddings
*/
@Override
public Mono<List<Embedding>> generateEmbeddingsAsync(List<String> data) {
if (data == null || data.isEmpty()) {
return Mono.just(Collections.emptyList());
}

// Convert each string to a single-element list for contextualized embeddings
List<List<String>> inputs = new ArrayList<>();
for (String text : data) {
inputs.add(Arrays.asList(text));
}

return generateContextualizedEmbeddingsAsync(inputs);
}

/**
* Creates a builder for VoyageAI contextualized embedding generation service.
*
* @return A new builder instance
*/
public static Builder builder() {
return new Builder();
}

/**
* Builder for {@link VoyageAIContextualizedEmbeddingGenerationService}.
*/
public static class Builder {
private VoyageAIClient client;
private String modelId;
private String serviceId;

/**
* Sets the VoyageAI client.
*
* @param client VoyageAI client
* @return This builder
*/
public Builder withClient(VoyageAIClient client) {
this.client = client;
return this;
}

/**
* Sets the model ID.
*
* @param modelId Model ID (e.g., "voyage-3")
* @return This builder
*/
public Builder withModelId(String modelId) {
this.modelId = modelId;
return this;
}

/**
* Sets the service ID.
*
* @param serviceId Service ID
* @return This builder
*/
public Builder withServiceId(String serviceId) {
this.serviceId = serviceId;
return this;
}

/**
* Builds the VoyageAI contextualized embedding generation service.
*
* @return A new instance of VoyageAIContextualizedEmbeddingGenerationService
*/
public VoyageAIContextualizedEmbeddingGenerationService build() {
return new VoyageAIContextualizedEmbeddingGenerationService(client, modelId, serviceId);
}
}
}
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions PACKAGES.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,6 +39,9 @@ A BOM is provided that can be used to define the versions of all Semantic Kernel
`semantickernel-aiservices-openai`
: Provides a connector that can be used to interact with the OpenAI API.

`semantickernel-aiservices-voyageai`
: Provides connectors for VoyageAI's embedding and reranking services, including text embeddings, contextualized embeddings, multimodal embeddings, and document reranking.

## Example Configurations

### Example: OpenAI + SQLite
Expand DownExpand Up@@ -72,5 +75,36 @@ POM XML for a simple project that uses OpenAI.
</project>
```

### Example: VoyageAI Embeddings and Reranking

POM XML for a project that uses VoyageAI for embeddings and reranking.

```xml

<project>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-bom</artifactId>
<version>${semantickernel.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-aiservices-voyageai</artifactId>
</dependency>
</dependencies>
</project>
```



89 changes: 89 additions & 0 deletions aiservices/voyageai/pom.xml
Original file line numberDiff line numberDiff line change
@@ -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.semantic-kernel</groupId>
<artifactId>semantickernel-parent</artifactId>
<version>1.5.1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

<artifactId>semantickernel-aiservices-voyageai</artifactId>
<name>Semantic Kernel VoyageAI Services</name>
<description>VoyageAI services for Semantic Kernel</description>

<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-builders</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-ai-services</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-textembedding-services</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-exceptions</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-localization</artifactId>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<scope>compile</scope>
</dependency>

<!-- HTTP Client -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>

<!-- Reactive Streams -->
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
</dependency>

<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>

<!-- Test Dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.aiservices.voyageai.contextualizedembedding;

import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIClient;
import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIModels;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.services.textembedding.Embedding;
import com.microsoft.semantickernel.services.textembedding.TextEmbeddingGenerationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
* VoyageAI contextualized embedding generation service.
* Generates embeddings that capture both local chunk details and global document-level metadata.
* Supports models like voyage-3.
*/
public final class VoyageAIContextualizedEmbeddingGenerationService implements TextEmbeddingGenerationService {

private static final Logger LOGGER = LoggerFactory.getLogger(VoyageAIContextualizedEmbeddingGenerationService.class);

private final VoyageAIClient client;
private final String modelId;
private final String serviceId;

/**
* Creates a new instance of VoyageAI contextualized embedding generation service.
*
* @param client VoyageAI client
* @param modelId Model ID (e.g., "voyage-3")
* @param serviceId Optional service ID
*/
public VoyageAIContextualizedEmbeddingGenerationService(
VoyageAIClient client,
String modelId,
@Nullable String serviceId) {

if (client == null) {
throw new IllegalArgumentException("Client cannot be null");
}
if (modelId == null || modelId.trim().isEmpty()) {
throw new IllegalArgumentException("Model ID cannot be null or empty");
}

this.client = client;
this.modelId = modelId;
this.serviceId = serviceId != null ? serviceId : PromptExecutionSettings.DEFAULT_SERVICE_ID;
}

@Override
public String getServiceId() {
return serviceId;
}

@Override
public String getModelId() {
return modelId;
}

/**
* Generates contextualized embeddings for document chunks.
*
* @param inputs List of lists where each inner list contains document chunks
* @return A Mono containing a list of embeddings for all chunks across all documents
*/
public Mono<List<Embedding>> generateContextualizedEmbeddingsAsync(List<List<String>> inputs) {
if (inputs == null || inputs.isEmpty()) {
return Mono.just(Collections.emptyList());
}

LOGGER.debug("Generating contextualized embeddings for {} document groups using model {}",
inputs.size(), modelId);

VoyageAIModels.ContextualizedEmbeddingRequest request =
new VoyageAIModels.ContextualizedEmbeddingRequest();
request.setInputs(inputs);
request.setModel(modelId);

return client.sendRequestAsync(
"contextualizedembeddings",
request,
VoyageAIModels.ContextualizedEmbeddingResponse.class)
.map(response -> {
List<Embedding> embeddings = new ArrayList<>();
// Parse nested data structure: {"data":[{"data":[{"embedding":[...]}]}]}
for (VoyageAIModels.ContextualizedEmbeddingDataList dataList : response.getData()) {
for (VoyageAIModels.EmbeddingDataItem item : dataList.getData()) {
embeddings.add(new Embedding(item.getEmbedding()));
}
}

LOGGER.debug("Received {} contextualized embeddings from VoyageAI", embeddings.size());
return embeddings;
});
}

/**
* Generates embeddings for the given text.
* For standard text embedding, wraps the data as a single input.
*
* @param data The text to generate embeddings for
* @return A Mono that completes with the embedding
*/
@Override
public Mono<Embedding> generateEmbeddingAsync(String data) {
return generateEmbeddingsAsync(Arrays.asList(data))
.flatMap(embeddings -> {
if (embeddings.isEmpty()) {
return Mono.empty();
}
return Mono.just(embeddings.get(0));
});
}

/**
* Generates embeddings for the given texts.
* Each text is treated as a separate document for contextualized embeddings.
*
* @param data The texts to generate embeddings for
* @return A Mono that completes with the list of embeddings
*/
@Override
public Mono<List<Embedding>> generateEmbeddingsAsync(List<String> data) {
if (data == null || data.isEmpty()) {
return Mono.just(Collections.emptyList());
}

// Convert each string to a single-element list for contextualized embeddings
List<List<String>> inputs = new ArrayList<>();
for (String text : data) {
inputs.add(Arrays.asList(text));
}

return generateContextualizedEmbeddingsAsync(inputs);
}

/**
* Creates a builder for VoyageAI contextualized embedding generation service.
*
* @return A new builder instance
*/
public static Builder builder() {
return new Builder();
}

/**
* Builder for {@link VoyageAIContextualizedEmbeddingGenerationService}.
*/
public static class Builder {
private VoyageAIClient client;
private String modelId;
private String serviceId;

/**
* Sets the VoyageAI client.
*
* @param client VoyageAI client
* @return This builder
*/
public Builder withClient(VoyageAIClient client) {
this.client = client;
return this;
}

/**
* Sets the model ID.
*
* @param modelId Model ID (e.g., "voyage-3")
* @return This builder
*/
public Builder withModelId(String modelId) {
this.modelId = modelId;
return this;
}

/**
* Sets the service ID.
*
* @param serviceId Service ID
* @return This builder
*/
public Builder withServiceId(String serviceId) {
this.serviceId = serviceId;
return this;
}

/**
* Builds the VoyageAI contextualized embedding generation service.
*
* @return A new instance of VoyageAIContextualizedEmbeddingGenerationService
*/
public VoyageAIContextualizedEmbeddingGenerationService build() {
return new VoyageAIContextualizedEmbeddingGenerationService(client, modelId, serviceId);
}
}
}
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions PACKAGES.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,6 +39,9 @@ A BOM is provided that can be used to define the versions of all Semantic Kernel
`semantickernel-aiservices-openai`
: Provides a connector that can be used to interact with the OpenAI API.

`semantickernel-aiservices-voyageai`
: Provides connectors for VoyageAI's embedding and reranking services, including text embeddings, contextualized embeddings, multimodal embeddings, and document reranking.

## Example Configurations

### Example: OpenAI + SQLite
Expand DownExpand Up@@ -72,5 +75,36 @@ POM XML for a simple project that uses OpenAI.
</project>
```

### Example: VoyageAI Embeddings and Reranking

POM XML for a project that uses VoyageAI for embeddings and reranking.

```xml

<project>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-bom</artifactId>
<version>${semantickernel.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-aiservices-voyageai</artifactId>
</dependency>
</dependencies>
</project>
```



89 changes: 89 additions & 0 deletions aiservices/voyageai/pom.xml
Original file line numberDiff line numberDiff line change
@@ -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.semantic-kernel</groupId>
<artifactId>semantickernel-parent</artifactId>
<version>1.5.1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

<artifactId>semantickernel-aiservices-voyageai</artifactId>
<name>Semantic Kernel VoyageAI Services</name>
<description>VoyageAI services for Semantic Kernel</description>

<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-builders</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-ai-services</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-textembedding-services</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-exceptions</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-localization</artifactId>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<scope>compile</scope>
</dependency>

<!-- HTTP Client -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>

<!-- Reactive Streams -->
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
</dependency>

<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>

<!-- Test Dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.aiservices.voyageai.contextualizedembedding;

import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIClient;
import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIModels;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.services.textembedding.Embedding;
import com.microsoft.semantickernel.services.textembedding.TextEmbeddingGenerationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
* VoyageAI contextualized embedding generation service.
* Generates embeddings that capture both local chunk details and global document-level metadata.
* Supports models like voyage-3.
*/
public final class VoyageAIContextualizedEmbeddingGenerationService implements TextEmbeddingGenerationService {

private static final Logger LOGGER = LoggerFactory.getLogger(VoyageAIContextualizedEmbeddingGenerationService.class);

private final VoyageAIClient client;
private final String modelId;
private final String serviceId;

/**
* Creates a new instance of VoyageAI contextualized embedding generation service.
*
* @param client VoyageAI client
* @param modelId Model ID (e.g., "voyage-3")
* @param serviceId Optional service ID
*/
public VoyageAIContextualizedEmbeddingGenerationService(
VoyageAIClient client,
String modelId,
@Nullable String serviceId) {

if (client == null) {
throw new IllegalArgumentException("Client cannot be null");
}
if (modelId == null || modelId.trim().isEmpty()) {
throw new IllegalArgumentException("Model ID cannot be null or empty");
}

this.client = client;
this.modelId = modelId;
this.serviceId = serviceId != null ? serviceId : PromptExecutionSettings.DEFAULT_SERVICE_ID;
}

@Override
public String getServiceId() {
return serviceId;
}

@Override
public String getModelId() {
return modelId;
}

/**
* Generates contextualized embeddings for document chunks.
*
* @param inputs List of lists where each inner list contains document chunks
* @return A Mono containing a list of embeddings for all chunks across all documents
*/
public Mono<List<Embedding>> generateContextualizedEmbeddingsAsync(List<List<String>> inputs) {
if (inputs == null || inputs.isEmpty()) {
return Mono.just(Collections.emptyList());
}

LOGGER.debug("Generating contextualized embeddings for {} document groups using model {}",
inputs.size(), modelId);

VoyageAIModels.ContextualizedEmbeddingRequest request =
new VoyageAIModels.ContextualizedEmbeddingRequest();
request.setInputs(inputs);
request.setModel(modelId);

return client.sendRequestAsync(
"contextualizedembeddings",
request,
VoyageAIModels.ContextualizedEmbeddingResponse.class)
.map(response -> {
List<Embedding> embeddings = new ArrayList<>();
// Parse nested data structure: {"data":[{"data":[{"embedding":[...]}]}]}
for (VoyageAIModels.ContextualizedEmbeddingDataList dataList : response.getData()) {
for (VoyageAIModels.EmbeddingDataItem item : dataList.getData()) {
embeddings.add(new Embedding(item.getEmbedding()));
}
}

LOGGER.debug("Received {} contextualized embeddings from VoyageAI", embeddings.size());
return embeddings;
});
}

/**
* Generates embeddings for the given text.
* For standard text embedding, wraps the data as a single input.
*
* @param data The text to generate embeddings for
* @return A Mono that completes with the embedding
*/
@Override
public Mono<Embedding> generateEmbeddingAsync(String data) {
return generateEmbeddingsAsync(Arrays.asList(data))
.flatMap(embeddings -> {
if (embeddings.isEmpty()) {
return Mono.empty();
}
return Mono.just(embeddings.get(0));
});
}

/**
* Generates embeddings for the given texts.
* Each text is treated as a separate document for contextualized embeddings.
*
* @param data The texts to generate embeddings for
* @return A Mono that completes with the list of embeddings
*/
@Override
public Mono<List<Embedding>> generateEmbeddingsAsync(List<String> data) {
if (data == null || data.isEmpty()) {
return Mono.just(Collections.emptyList());
}

// Convert each string to a single-element list for contextualized embeddings
List<List<String>> inputs = new ArrayList<>();
for (String text : data) {
inputs.add(Arrays.asList(text));
}

return generateContextualizedEmbeddingsAsync(inputs);
}

/**
* Creates a builder for VoyageAI contextualized embedding generation service.
*
* @return A new builder instance
*/
public static Builder builder() {
return new Builder();
}

/**
* Builder for {@link VoyageAIContextualizedEmbeddingGenerationService}.
*/
public static class Builder {
private VoyageAIClient client;
private String modelId;
private String serviceId;

/**
* Sets the VoyageAI client.
*
* @param client VoyageAI client
* @return This builder
*/
public Builder withClient(VoyageAIClient client) {
this.client = client;
return this;
}

/**
* Sets the model ID.
*
* @param modelId Model ID (e.g., "voyage-3")
* @return This builder
*/
public Builder withModelId(String modelId) {
this.modelId = modelId;
return this;
}

/**
* Sets the service ID.
*
* @param serviceId Service ID
* @return This builder
*/
public Builder withServiceId(String serviceId) {
this.serviceId = serviceId;
return this;
}

/**
* Builds the VoyageAI contextualized embedding generation service.
*
* @return A new instance of VoyageAIContextualizedEmbeddingGenerationService
*/
public VoyageAIContextualizedEmbeddingGenerationService build() {
return new VoyageAIContextualizedEmbeddingGenerationService(client, modelId, serviceId);
}
}
}
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions PACKAGES.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,6 +39,9 @@ A BOM is provided that can be used to define the versions of all Semantic Kernel
`semantickernel-aiservices-openai`
: Provides a connector that can be used to interact with the OpenAI API.

`semantickernel-aiservices-voyageai`
: Provides connectors for VoyageAI's embedding and reranking services, including text embeddings, contextualized embeddings, multimodal embeddings, and document reranking.

## Example Configurations

### Example: OpenAI + SQLite
Expand DownExpand Up@@ -72,5 +75,36 @@ POM XML for a simple project that uses OpenAI.
</project>
```

### Example: VoyageAI Embeddings and Reranking

POM XML for a project that uses VoyageAI for embeddings and reranking.

```xml

<project>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-bom</artifactId>
<version>${semantickernel.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-aiservices-voyageai</artifactId>
</dependency>
</dependencies>
</project>
```



89 changes: 89 additions & 0 deletions aiservices/voyageai/pom.xml
Original file line numberDiff line numberDiff line change
@@ -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.semantic-kernel</groupId>
<artifactId>semantickernel-parent</artifactId>
<version>1.5.1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

<artifactId>semantickernel-aiservices-voyageai</artifactId>
<name>Semantic Kernel VoyageAI Services</name>
<description>VoyageAI services for Semantic Kernel</description>

<dependencies>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-builders</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-ai-services</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-textembedding-services</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-exceptions</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-api-localization</artifactId>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<scope>compile</scope>
</dependency>

<!-- HTTP Client -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>

<!-- Reactive Streams -->
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
</dependency>

<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>

<!-- Test Dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.aiservices.voyageai.contextualizedembedding;

import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIClient;
import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIModels;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.services.textembedding.Embedding;
import com.microsoft.semantickernel.services.textembedding.TextEmbeddingGenerationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
* VoyageAI contextualized embedding generation service.
* Generates embeddings that capture both local chunk details and global document-level metadata.
* Supports models like voyage-3.
*/
public final class VoyageAIContextualizedEmbeddingGenerationService implements TextEmbeddingGenerationService {

private static final Logger LOGGER = LoggerFactory.getLogger(VoyageAIContextualizedEmbeddingGenerationService.class);

private final VoyageAIClient client;
private final String modelId;
private final String serviceId;

/**
* Creates a new instance of VoyageAI contextualized embedding generation service.
*
* @param client VoyageAI client
* @param modelId Model ID (e.g., "voyage-3")
* @param serviceId Optional service ID
*/
public VoyageAIContextualizedEmbeddingGenerationService(
VoyageAIClient client,
String modelId,
@Nullable String serviceId) {

if (client == null) {
throw new IllegalArgumentException("Client cannot be null");
}
if (modelId == null || modelId.trim().isEmpty()) {
throw new IllegalArgumentException("Model ID cannot be null or empty");
}

this.client = client;
this.modelId = modelId;
this.serviceId = serviceId != null ? serviceId : PromptExecutionSettings.DEFAULT_SERVICE_ID;
}

@Override
public String getServiceId() {
return serviceId;
}

@Override
public String getModelId() {
return modelId;
}

/**
* Generates contextualized embeddings for document chunks.
*
* @param inputs List of lists where each inner list contains document chunks
* @return A Mono containing a list of embeddings for all chunks across all documents
*/
public Mono<List<Embedding>> generateContextualizedEmbeddingsAsync(List<List<String>> inputs) {
if (inputs == null || inputs.isEmpty()) {
return Mono.just(Collections.emptyList());
}

LOGGER.debug("Generating contextualized embeddings for {} document groups using model {}",
inputs.size(), modelId);

VoyageAIModels.ContextualizedEmbeddingRequest request =
new VoyageAIModels.ContextualizedEmbeddingRequest();
request.setInputs(inputs);
request.setModel(modelId);

return client.sendRequestAsync(
"contextualizedembeddings",
request,
VoyageAIModels.ContextualizedEmbeddingResponse.class)
.map(response -> {
List<Embedding> embeddings = new ArrayList<>();
// Parse nested data structure: {"data":[{"data":[{"embedding":[...]}]}]}
for (VoyageAIModels.ContextualizedEmbeddingDataList dataList : response.getData()) {
for (VoyageAIModels.EmbeddingDataItem item : dataList.getData()) {
embeddings.add(new Embedding(item.getEmbedding()));
}
}

LOGGER.debug("Received {} contextualized embeddings from VoyageAI", embeddings.size());
return embeddings;
});
}

/**
* Generates embeddings for the given text.
* For standard text embedding, wraps the data as a single input.
*
* @param data The text to generate embeddings for
* @return A Mono that completes with the embedding
*/
@Override
public Mono<Embedding> generateEmbeddingAsync(String data) {
return generateEmbeddingsAsync(Arrays.asList(data))
.flatMap(embeddings -> {
if (embeddings.isEmpty()) {
return Mono.empty();
}
return Mono.just(embeddings.get(0));
});
}

/**
* Generates embeddings for the given texts.
* Each text is treated as a separate document for contextualized embeddings.
*
* @param data The texts to generate embeddings for
* @return A Mono that completes with the list of embeddings
*/
@Override
public Mono<List<Embedding>> generateEmbeddingsAsync(List<String> data) {
if (data == null || data.isEmpty()) {
return Mono.just(Collections.emptyList());
}

// Convert each string to a single-element list for contextualized embeddings
List<List<String>> inputs = new ArrayList<>();
for (String text : data) {
inputs.add(Arrays.asList(text));
}

return generateContextualizedEmbeddingsAsync(inputs);
}

/**
* Creates a builder for VoyageAI contextualized embedding generation service.
*
* @return A new builder instance
*/
public static Builder builder() {
return new Builder();
}

/**
* Builder for {@link VoyageAIContextualizedEmbeddingGenerationService}.
*/
public static class Builder {
private VoyageAIClient client;
private String modelId;
private String serviceId;

/**
* Sets the VoyageAI client.
*
* @param client VoyageAI client
* @return This builder
*/
public Builder withClient(VoyageAIClient client) {
this.client = client;
return this;
}

/**
* Sets the model ID.
*
* @param modelId Model ID (e.g., "voyage-3")
* @return This builder
*/
public Builder withModelId(String modelId) {
this.modelId = modelId;
return this;
}

/**
* Sets the service ID.
*
* @param serviceId Service ID
* @return This builder
*/
public Builder withServiceId(String serviceId) {
this.serviceId = serviceId;
return this;
}

/**
* Builds the VoyageAI contextualized embedding generation service.
*
* @return A new instance of VoyageAIContextualizedEmbeddingGenerationService
*/
public VoyageAIContextualizedEmbeddingGenerationService build() {
return new VoyageAIContextualizedEmbeddingGenerationService(client, modelId, serviceId);
}
}
}
Loading