chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from semantic_kernel.connectors.ai.embedding_generator_base import EmbeddingGeneratorBase
|
||||
from semantic_kernel.connectors.ai.prompt_execution_settings import PromptExecutionSettings
|
||||
from tests.integration.embeddings.test_embedding_service_base import (
|
||||
EmbeddingServiceTestBase,
|
||||
google_ai_setup,
|
||||
mistral_ai_setup,
|
||||
ollama_setup,
|
||||
vertex_ai_setup,
|
||||
)
|
||||
|
||||
pytestmark = pytest.mark.parametrize(
|
||||
"service_id, execution_settings_kwargs, output_dimensionality",
|
||||
[
|
||||
pytest.param(
|
||||
"openai",
|
||||
{},
|
||||
1536, # text-embedding-ada-002 doesn't support custom output dimensionality
|
||||
id="openai",
|
||||
),
|
||||
pytest.param(
|
||||
"azure",
|
||||
{},
|
||||
1536, # text-embedding-ada-002 doesn't support custom output dimensionality
|
||||
id="azure",
|
||||
),
|
||||
pytest.param(
|
||||
"azure_custom_client",
|
||||
{},
|
||||
1536, # text-embedding-ada-002 doesn't support custom output dimensionality
|
||||
id="azure_custom_client",
|
||||
),
|
||||
pytest.param(
|
||||
"azure_ai_inference",
|
||||
{},
|
||||
1536, # text-embedding-ada-002 doesn't support custom output dimensionality
|
||||
id="azure_ai_inference",
|
||||
),
|
||||
pytest.param(
|
||||
"mistral_ai",
|
||||
{},
|
||||
1024,
|
||||
marks=pytest.mark.skipif(not mistral_ai_setup, reason="Mistral AI environment variables not set"),
|
||||
id="mistral_ai",
|
||||
),
|
||||
pytest.param(
|
||||
"hugging_face",
|
||||
{},
|
||||
384,
|
||||
id="hugging_face",
|
||||
),
|
||||
pytest.param(
|
||||
"ollama",
|
||||
{},
|
||||
768,
|
||||
marks=(
|
||||
pytest.mark.skipif(not ollama_setup, reason="Ollama not setup"),
|
||||
pytest.mark.ollama,
|
||||
),
|
||||
id="ollama",
|
||||
),
|
||||
pytest.param(
|
||||
"google_ai",
|
||||
{"output_dimensionality": 10},
|
||||
10,
|
||||
marks=pytest.mark.skipif(not google_ai_setup, reason="Google AI environment variables not set"),
|
||||
id="google_ai",
|
||||
),
|
||||
pytest.param(
|
||||
"vertex_ai",
|
||||
{"output_dimensionality": 10},
|
||||
10,
|
||||
marks=(
|
||||
pytest.mark.skipif(not vertex_ai_setup, reason="Vertex AI environment variables not set"),
|
||||
pytest.mark.timeout(300), # Vertex AI may take longer time
|
||||
),
|
||||
id="vertex_ai",
|
||||
),
|
||||
pytest.param(
|
||||
"bedrock_amazon_titan-v1",
|
||||
{},
|
||||
1536, # This model doesn't support custom output dimensionality
|
||||
id="bedrock_amazon_titan-v1",
|
||||
),
|
||||
pytest.param(
|
||||
"bedrock_amazon_titan-v2",
|
||||
{"extension_data": {"dimensions": 256}},
|
||||
256,
|
||||
id="bedrock_amazon_titan-v2",
|
||||
),
|
||||
pytest.param(
|
||||
"bedrock_cohere",
|
||||
{},
|
||||
1024,
|
||||
id="bedrock_cohere",
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
class TestEmbeddingService(EmbeddingServiceTestBase):
|
||||
"""Test embedding service with memory.
|
||||
|
||||
This tests if the embedding service can be used with the semantic memory.
|
||||
"""
|
||||
|
||||
async def test_embedding_service(
|
||||
self,
|
||||
service_id,
|
||||
services: dict[str, tuple[EmbeddingGeneratorBase, type[PromptExecutionSettings]]],
|
||||
execution_settings_kwargs: dict[str, Any],
|
||||
output_dimensionality: int,
|
||||
):
|
||||
embedding_generator, settings_type = services[service_id]
|
||||
embeddings = await embedding_generator.generate_embeddings(
|
||||
texts=["Hello, world!", "Hello, universe!"],
|
||||
settings=settings_type(**execution_settings_kwargs),
|
||||
)
|
||||
|
||||
assert embeddings.shape == (2, output_dimensionality)
|
||||
@@ -0,0 +1,129 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from importlib import util
|
||||
|
||||
import pytest
|
||||
from azure.ai.inference.aio import EmbeddingsClient
|
||||
from azure.identity import AzureCliCredential
|
||||
from openai import AsyncAzureOpenAI
|
||||
|
||||
from semantic_kernel.connectors.ai.azure_ai_inference import (
|
||||
AzureAIInferenceEmbeddingPromptExecutionSettings,
|
||||
AzureAIInferenceTextEmbedding,
|
||||
)
|
||||
from semantic_kernel.connectors.ai.bedrock import BedrockEmbeddingPromptExecutionSettings, BedrockTextEmbedding
|
||||
from semantic_kernel.connectors.ai.embedding_generator_base import EmbeddingGeneratorBase
|
||||
from semantic_kernel.connectors.ai.google.google_ai import (
|
||||
GoogleAIEmbeddingPromptExecutionSettings,
|
||||
GoogleAITextEmbedding,
|
||||
)
|
||||
from semantic_kernel.connectors.ai.hugging_face import HuggingFaceTextEmbedding
|
||||
from semantic_kernel.connectors.ai.mistral_ai import MistralAITextEmbedding
|
||||
from semantic_kernel.connectors.ai.ollama import OllamaEmbeddingPromptExecutionSettings, OllamaTextEmbedding
|
||||
from semantic_kernel.connectors.ai.open_ai import (
|
||||
AzureOpenAISettings,
|
||||
AzureTextEmbedding,
|
||||
OpenAIEmbeddingPromptExecutionSettings,
|
||||
OpenAITextEmbedding,
|
||||
)
|
||||
from semantic_kernel.connectors.ai.prompt_execution_settings import PromptExecutionSettings
|
||||
from semantic_kernel.utils.authentication.entra_id_authentication import get_entra_auth_token
|
||||
from tests.utils import is_service_setup_for_testing
|
||||
|
||||
hugging_face_setup = util.find_spec("torch") is not None
|
||||
|
||||
# Make sure all services are setup for before running the tests
|
||||
# The following exceptions apply:
|
||||
# 1. OpenAI and Azure OpenAI services are always setup for testing.
|
||||
azure_openai_setup = True
|
||||
# 2. The current Hugging Face service don't require any environment variables.
|
||||
# 3. Bedrock services don't use API keys and model providers are tested individually,
|
||||
# so no environment variables are required.
|
||||
mistral_ai_setup: bool = is_service_setup_for_testing(
|
||||
["MISTRALAI_API_KEY", "MISTRALAI_EMBEDDING_MODEL_ID"], raise_if_not_set=False
|
||||
) # We don't have a MistralAI deployment
|
||||
google_ai_setup: bool = is_service_setup_for_testing(["GOOGLE_AI_API_KEY", "GOOGLE_AI_EMBEDDING_MODEL_ID"])
|
||||
vertex_ai_setup: bool = is_service_setup_for_testing([
|
||||
"GOOGLE_AI_CLOUD_PROJECT_ID",
|
||||
"GOOGLE_AI_EMBEDDING_MODEL_ID",
|
||||
"GOOGLE_AI_CLOUD_REGION",
|
||||
])
|
||||
ollama_setup: bool = is_service_setup_for_testing(["OLLAMA_EMBEDDING_MODEL_ID"])
|
||||
# When testing Bedrock, after logging into AWS CLI this has been set, so we can use it to check if the service is setup
|
||||
bedrock_setup: bool = is_service_setup_for_testing(["AWS_DEFAULT_REGION"], raise_if_not_set=False)
|
||||
|
||||
|
||||
class EmbeddingServiceTestBase:
|
||||
@pytest.fixture(scope="class")
|
||||
def services(self) -> dict[str, tuple[EmbeddingGeneratorBase | None, type[PromptExecutionSettings]]]:
|
||||
azure_openai_setup = True
|
||||
credential = AzureCliCredential()
|
||||
azure_openai_settings = AzureOpenAISettings()
|
||||
endpoint = str(azure_openai_settings.endpoint)
|
||||
deployment_name = azure_openai_settings.embedding_deployment_name
|
||||
ad_token = get_entra_auth_token(credential, azure_openai_settings.token_endpoint)
|
||||
if not ad_token:
|
||||
azure_openai_setup = False
|
||||
api_version = azure_openai_settings.api_version
|
||||
azure_custom_client = None
|
||||
azure_ai_inference_client = None
|
||||
if azure_openai_setup:
|
||||
azure_custom_client = AzureTextEmbedding(
|
||||
async_client=AsyncAzureOpenAI(
|
||||
azure_endpoint=endpoint,
|
||||
azure_deployment=deployment_name,
|
||||
azure_ad_token=ad_token,
|
||||
api_version=api_version,
|
||||
default_headers={"Test-User-X-ID": "test"},
|
||||
),
|
||||
credential=credential,
|
||||
)
|
||||
azure_ai_inference_client = AzureAIInferenceTextEmbedding(
|
||||
ai_model_id=deployment_name,
|
||||
client=EmbeddingsClient(
|
||||
endpoint=f"{endpoint.strip('/')}/openai/deployments/{deployment_name}",
|
||||
credential=credential,
|
||||
credential_scopes=["https://cognitiveservices.azure.com/.default"],
|
||||
),
|
||||
)
|
||||
|
||||
return {
|
||||
"openai": (OpenAITextEmbedding(), OpenAIEmbeddingPromptExecutionSettings),
|
||||
"azure": (
|
||||
AzureTextEmbedding(credential=credential) if azure_openai_setup else None,
|
||||
OpenAIEmbeddingPromptExecutionSettings,
|
||||
),
|
||||
"azure_custom_client": (azure_custom_client, OpenAIEmbeddingPromptExecutionSettings),
|
||||
"azure_ai_inference": (azure_ai_inference_client, AzureAIInferenceEmbeddingPromptExecutionSettings),
|
||||
"mistral_ai": (
|
||||
MistralAITextEmbedding() if mistral_ai_setup else None,
|
||||
PromptExecutionSettings,
|
||||
),
|
||||
"hugging_face": (
|
||||
HuggingFaceTextEmbedding(ai_model_id="sentence-transformers/all-MiniLM-L6-v2")
|
||||
if hugging_face_setup
|
||||
else None,
|
||||
PromptExecutionSettings,
|
||||
),
|
||||
"ollama": (OllamaTextEmbedding() if ollama_setup else None, OllamaEmbeddingPromptExecutionSettings),
|
||||
"google_ai": (
|
||||
GoogleAITextEmbedding() if google_ai_setup else None,
|
||||
GoogleAIEmbeddingPromptExecutionSettings,
|
||||
),
|
||||
"vertex_ai": (
|
||||
GoogleAITextEmbedding(use_vertexai=True) if vertex_ai_setup else None,
|
||||
GoogleAIEmbeddingPromptExecutionSettings,
|
||||
),
|
||||
"bedrock_amazon_titan-v1": (
|
||||
BedrockTextEmbedding(model_id="amazon.titan-embed-text-v1") if bedrock_setup else None,
|
||||
BedrockEmbeddingPromptExecutionSettings,
|
||||
),
|
||||
"bedrock_amazon_titan-v2": (
|
||||
BedrockTextEmbedding(model_id="amazon.titan-embed-text-v2:0") if bedrock_setup else None,
|
||||
BedrockEmbeddingPromptExecutionSettings,
|
||||
),
|
||||
"bedrock_cohere": (
|
||||
BedrockTextEmbedding(model_id="cohere.embed-english-v3") if bedrock_setup else None,
|
||||
BedrockEmbeddingPromptExecutionSettings,
|
||||
),
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from semantic_kernel.connectors.ai.embedding_generator_base import EmbeddingGeneratorBase
|
||||
from semantic_kernel.connectors.ai.prompt_execution_settings import PromptExecutionSettings
|
||||
from semantic_kernel.memory.semantic_text_memory import SemanticTextMemory
|
||||
from semantic_kernel.memory.volatile_memory_store import VolatileMemoryStore
|
||||
from tests.integration.embeddings.test_embedding_service_base import (
|
||||
EmbeddingServiceTestBase,
|
||||
google_ai_setup,
|
||||
mistral_ai_setup,
|
||||
ollama_setup,
|
||||
vertex_ai_setup,
|
||||
)
|
||||
|
||||
pytestmark = pytest.mark.parametrize(
|
||||
"service_id, execution_settings_kwargs",
|
||||
[
|
||||
pytest.param(
|
||||
"openai",
|
||||
{},
|
||||
id="openai",
|
||||
),
|
||||
pytest.param(
|
||||
"azure",
|
||||
{},
|
||||
id="azure",
|
||||
),
|
||||
pytest.param(
|
||||
"azure_custom_client",
|
||||
{},
|
||||
id="azure_custom_client",
|
||||
),
|
||||
pytest.param(
|
||||
"azure_ai_inference",
|
||||
{},
|
||||
id="azure_ai_inference",
|
||||
),
|
||||
pytest.param(
|
||||
"mistral_ai",
|
||||
{},
|
||||
marks=pytest.mark.skipif(not mistral_ai_setup, reason="Mistral AI environment variables not set"),
|
||||
id="mistral_ai",
|
||||
),
|
||||
pytest.param(
|
||||
"hugging_face",
|
||||
{},
|
||||
id="hugging_face",
|
||||
),
|
||||
pytest.param(
|
||||
"ollama",
|
||||
{},
|
||||
marks=(
|
||||
pytest.mark.skipif(not ollama_setup, reason="Ollama environment variables not set"),
|
||||
pytest.mark.ollama,
|
||||
),
|
||||
id="ollama",
|
||||
),
|
||||
pytest.param(
|
||||
"google_ai",
|
||||
{},
|
||||
marks=pytest.mark.skipif(not google_ai_setup, reason="Google AI environment variables not set"),
|
||||
id="google_ai",
|
||||
),
|
||||
pytest.param(
|
||||
"vertex_ai",
|
||||
{},
|
||||
marks=(
|
||||
pytest.mark.skipif(not vertex_ai_setup, reason="Vertex AI environment variables not set"),
|
||||
pytest.mark.timeout(300), # Vertex AI may take longer time
|
||||
),
|
||||
id="vertex_ai",
|
||||
),
|
||||
pytest.param(
|
||||
"bedrock_amazon_titan-v1",
|
||||
{},
|
||||
id="bedrock_amazon_titan-v1",
|
||||
),
|
||||
pytest.param(
|
||||
"bedrock_amazon_titan-v2",
|
||||
{},
|
||||
marks=pytest.mark.skip(reason="This is known to fail to get the correct answer for 'What are birds?'"),
|
||||
id="bedrock_amazon_titan-v2",
|
||||
),
|
||||
pytest.param(
|
||||
"bedrock_cohere",
|
||||
{},
|
||||
id="bedrock_cohere",
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
class TestEmbeddingServiceWithMemory(EmbeddingServiceTestBase):
|
||||
"""Test embedding service with memory.
|
||||
|
||||
This tests if the embedding service can be used with the semantic memory.
|
||||
"""
|
||||
|
||||
async def test_embedding_service(
|
||||
self,
|
||||
service_id,
|
||||
services: dict[str, tuple[EmbeddingGeneratorBase, type[PromptExecutionSettings]]],
|
||||
execution_settings_kwargs: dict[str, Any],
|
||||
):
|
||||
embedding_generator, settings_type = services[service_id]
|
||||
|
||||
if embedding_generator is None:
|
||||
pytest.skip(f"Service {service_id} not set up")
|
||||
|
||||
memory = SemanticTextMemory(
|
||||
storage=VolatileMemoryStore(),
|
||||
embeddings_generator=embedding_generator,
|
||||
)
|
||||
|
||||
# Add some documents to the semantic memory
|
||||
embeddings_kwargs = {"settings": settings_type(**execution_settings_kwargs)}
|
||||
await memory.save_information(
|
||||
"test",
|
||||
id="info1",
|
||||
text="Sharks are fish.",
|
||||
embeddings_kwargs=embeddings_kwargs,
|
||||
)
|
||||
await memory.save_information(
|
||||
"test",
|
||||
id="info2",
|
||||
text="Whales are mammals.",
|
||||
embeddings_kwargs=embeddings_kwargs,
|
||||
)
|
||||
await memory.save_information(
|
||||
"test",
|
||||
id="info3",
|
||||
text="Penguins are birds.",
|
||||
embeddings_kwargs=embeddings_kwargs,
|
||||
)
|
||||
await memory.save_information(
|
||||
"test",
|
||||
id="info4",
|
||||
text="Dolphins are mammals.",
|
||||
embeddings_kwargs=embeddings_kwargs,
|
||||
)
|
||||
await memory.save_information(
|
||||
"test",
|
||||
id="info5",
|
||||
text="Flies are insects.",
|
||||
embeddings_kwargs=embeddings_kwargs,
|
||||
)
|
||||
|
||||
# Search for documents
|
||||
query = "What are mammals?"
|
||||
result = await memory.search("test", query, limit=2, min_relevance_score=0.0)
|
||||
assert "mammals." in result[0].text
|
||||
assert "mammals." in result[1].text
|
||||
|
||||
query = "What are fish?"
|
||||
result = await memory.search("test", query, limit=1, min_relevance_score=0.0)
|
||||
assert result[0].text == "Sharks are fish."
|
||||
|
||||
query = "What are insects?"
|
||||
result = await memory.search("test", query, limit=1, min_relevance_score=0.0)
|
||||
assert result[0].text == "Flies are insects."
|
||||
|
||||
query = "What are birds?"
|
||||
result = await memory.search("test", query, limit=1, min_relevance_score=0.0)
|
||||
assert result[0].text == "Penguins are birds."
|
||||
Reference in New Issue
Block a user