mirror of
https://github.com/microsoft/semantic-kernel.git
synced 2026-10-12 02:19:06 +00:00
Python: upgraded all files to 310 plus format and removed from future (#6353)
### Motivation and Context <!-- Thank you for your contribution to the semantic-kernel repo! Please help reviewers and future users, providing the following information: 1. Why is this change required? 2. What problem does it solve? 3. What scenario does it contribute to? 4. If it fixes an open issue, please link to the issue here. --> Now that we only support 310 and up, we could unify all files, to use the new style typing and annotations. ### Description <!-- Describe your changes, the overall approach, the underlying design. These notes will help understanding how your code works. Thanks! --> ### Contribution Checklist <!-- Before submitting this PR, please make sure: --> - [x] The code builds clean without any errors or warnings - [x] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [x] All unit tests pass, and I have added new tests where possible - [x] I didn't break anyone 😄
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
import asyncio
|
||||
import os
|
||||
from functools import reduce
|
||||
from typing import TYPE_CHECKING, List
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from semantic_kernel import Kernel
|
||||
from semantic_kernel.connectors.ai.function_call_behavior import FunctionCallBehavior
|
||||
@@ -108,7 +108,7 @@ async def handle_streaming(
|
||||
)
|
||||
|
||||
print("Mosscap:> ", end="")
|
||||
streamed_chunks: List[StreamingChatMessageContent] = []
|
||||
streamed_chunks: list[StreamingChatMessageContent] = []
|
||||
async for message in response:
|
||||
if not execution_settings.function_call_behavior.auto_invoke_kernel_functions and isinstance(
|
||||
message[0], ChatMessageContent
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Any, Dict
|
||||
from typing import Any
|
||||
|
||||
from semantic_kernel import Kernel
|
||||
from semantic_kernel.connectors.ai import PromptExecutionSettings
|
||||
@@ -18,7 +18,7 @@ Read more about logit bias and how to configure output: https://help.openai.com/
|
||||
"""
|
||||
|
||||
|
||||
def _config_ban_tokens(settings: PromptExecutionSettings, keys: Dict[Any, Any]):
|
||||
def _config_ban_tokens(settings: PromptExecutionSettings, keys: dict[Any, Any]):
|
||||
# Map each token in the keys list to a bias value from -100 (a potential ban) to 100 (exclusive selection)
|
||||
for k in keys:
|
||||
# -100 to potentially ban all tokens in the list
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
from typing import Any, Callable, Coroutine
|
||||
from collections.abc import Callable, Coroutine
|
||||
from typing import Any
|
||||
|
||||
from semantic_kernel.connectors.ai.open_ai.services.azure_chat_completion import AzureChatCompletion
|
||||
from semantic_kernel.contents.chat_history import ChatHistory
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import datetime
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from typing import Dict, Optional
|
||||
|
||||
import httpx
|
||||
from aiohttp import ClientSession
|
||||
@@ -47,7 +45,7 @@ class OpenAIAuthenticationProvider:
|
||||
"""A Sample Authentication Provider for an OpenAI/OpenAPI plugin"""
|
||||
|
||||
def __init__(
|
||||
self, oauth_values: Optional[Dict[str, Dict[str, str]]] = None, credentials: Optional[Dict[str, str]] = None
|
||||
self, oauth_values: dict[str, dict[str, str]] | None = None, credentials: dict[str, str] | None = None
|
||||
):
|
||||
"""Initializes the OpenAIAuthenticationProvider."""
|
||||
self.oauth_values = oauth_values or {}
|
||||
@@ -145,7 +143,7 @@ async def main():
|
||||
openai_spec_file = os.path.join(
|
||||
os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "resources", "open_ai_plugins", "akv-openai.json"
|
||||
)
|
||||
with open(openai_spec_file, "r") as file:
|
||||
with open(openai_spec_file) as file:
|
||||
openai_spec = file.read()
|
||||
|
||||
http_client = httpx.AsyncClient()
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import sys
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
from typing import Annotated
|
||||
else:
|
||||
from typing_extensions import Annotated
|
||||
from typing import Annotated
|
||||
|
||||
from semantic_kernel.functions.kernel_function_decorator import kernel_function
|
||||
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import sys
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
from typing import Annotated
|
||||
else:
|
||||
from typing_extensions import Annotated
|
||||
from typing import Annotated
|
||||
|
||||
from msgraph import GraphServiceClient
|
||||
from msgraph.generated.models.booking_appointment import BookingAppointment
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
from typing import Annotated
|
||||
|
||||
from service_configurator import add_service
|
||||
|
||||
import semantic_kernel as sk
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
from typing import Annotated
|
||||
else:
|
||||
from typing_extensions import Annotated
|
||||
|
||||
from semantic_kernel.functions.kernel_function_decorator import kernel_function
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import math
|
||||
import sys
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
from typing import Annotated
|
||||
else:
|
||||
from typing_extensions import Annotated
|
||||
from typing import Annotated
|
||||
|
||||
from semantic_kernel.functions.kernel_function_decorator import kernel_function
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import TYPE_CHECKING, Any, AsyncGenerator
|
||||
from collections.abc import AsyncGenerator
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from semantic_kernel.services.ai_service_client_base import AIServiceClientBase
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import TYPE_CHECKING, Any, List
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from semantic_kernel.services.ai_service_client_base import AIServiceClientBase
|
||||
from semantic_kernel.utils.experimental_decorator import experimental_class
|
||||
@@ -13,5 +13,5 @@ if TYPE_CHECKING:
|
||||
@experimental_class
|
||||
class EmbeddingGeneratorBase(AIServiceClientBase, ABC):
|
||||
@abstractmethod
|
||||
async def generate_embeddings(self, texts: List[str], **kwargs: Any) -> "ndarray":
|
||||
async def generate_embeddings(self, texts: list[str], **kwargs: Any) -> "ndarray":
|
||||
pass
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Callable, Literal
|
||||
from collections.abc import Callable
|
||||
from typing import TYPE_CHECKING, Literal
|
||||
|
||||
from pydantic.dataclasses import dataclass
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from typing import Any, Dict, Iterable, List, Optional, Union
|
||||
from collections.abc import Iterable
|
||||
from typing import Any, Union
|
||||
|
||||
from pydantic import Field, model_validator
|
||||
|
||||
@@ -8,34 +9,34 @@ from semantic_kernel.connectors.ai.prompt_execution_settings import PromptExecut
|
||||
from semantic_kernel.exceptions import ServiceInvalidExecutionSettingsError
|
||||
|
||||
# TODO: replace back with google types once pydantic issue is fixed.
|
||||
MessagesOptions = List[Dict[str, Any]]
|
||||
MessagesOptions = list[dict[str, Any]]
|
||||
|
||||
MessagePromptOption = Union[str, Dict[str, Any]]
|
||||
MessagePromptOptions = Union[MessagePromptOption, List[MessagePromptOption]]
|
||||
MessagePromptOption = Union[str, dict[str, Any]]
|
||||
MessagePromptOptions = Union[MessagePromptOption, list[MessagePromptOption]]
|
||||
|
||||
ExampleOptions = Union[Dict[str, Any], List[Dict[str, Any]]]
|
||||
ExampleOptions = Union[dict[str, Any], list[dict[str, Any]]]
|
||||
|
||||
|
||||
class GooglePalmPromptExecutionSettings(PromptExecutionSettings):
|
||||
ai_model_id: Optional[str] = Field(None, serialization_alias="model")
|
||||
ai_model_id: str | None = Field(None, serialization_alias="model")
|
||||
temperature: float = Field(0.0, ge=0.0, le=1.0)
|
||||
top_p: float = 1.0
|
||||
top_k: int = 1
|
||||
candidate_count: int = Field(1, ge=1, le=8)
|
||||
safety_settings: Optional[Dict[str, Any]] = None
|
||||
prompt: Optional[MessagePromptOptions] = None
|
||||
safety_settings: dict[str, Any] | None = None
|
||||
prompt: MessagePromptOptions | None = None
|
||||
|
||||
|
||||
class GooglePalmTextPromptExecutionSettings(GooglePalmPromptExecutionSettings):
|
||||
max_output_tokens: int = Field(256, gt=0)
|
||||
stop_sequences: Optional[Union[str, Iterable[str]]] = None
|
||||
stop_sequences: str | Iterable[str] | None = None
|
||||
|
||||
|
||||
class GooglePalmChatPromptExecutionSettings(GooglePalmPromptExecutionSettings):
|
||||
messages: Optional[MessagesOptions] = None
|
||||
examples: Optional[ExampleOptions] = None
|
||||
context: Optional[str] = None
|
||||
token_selection_biases: Optional[Dict[int, int]] = None
|
||||
messages: MessagesOptions | None = None
|
||||
examples: ExampleOptions | None = None
|
||||
context: str | None = None
|
||||
token_selection_biases: dict[int, int] | None = None
|
||||
|
||||
@model_validator(mode="after")
|
||||
def validate_input(self):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from typing import Annotated, Any, List, Tuple
|
||||
from typing import Annotated, Any
|
||||
|
||||
import google.generativeai as palm
|
||||
from google.generativeai.types import ChatResponse, MessageDict
|
||||
@@ -76,7 +76,7 @@ class GooglePalmChatCompletion(ChatCompletionClientBase, TextCompletionClientBas
|
||||
chat_history: ChatHistory,
|
||||
settings: GooglePalmPromptExecutionSettings,
|
||||
**kwargs: Any,
|
||||
) -> List[ChatMessageContent]:
|
||||
) -> list[ChatMessageContent]:
|
||||
"""
|
||||
This is the method that is called from the kernel to get a response from a chat-optimized LLM.
|
||||
|
||||
@@ -124,7 +124,7 @@ class GooglePalmChatCompletion(ChatCompletionClientBase, TextCompletionClientBas
|
||||
|
||||
async def get_streaming_chat_message_contents(
|
||||
self,
|
||||
messages: List[Tuple[str, str]],
|
||||
messages: list[tuple[str, str]],
|
||||
settings: GooglePalmPromptExecutionSettings,
|
||||
**kwargs: Any,
|
||||
):
|
||||
@@ -134,7 +134,7 @@ class GooglePalmChatCompletion(ChatCompletionClientBase, TextCompletionClientBas
|
||||
self,
|
||||
prompt: str,
|
||||
settings: GooglePalmPromptExecutionSettings,
|
||||
) -> List[TextContent]:
|
||||
) -> list[TextContent]:
|
||||
"""
|
||||
This is the method that is called from the kernel to get a response from a text-optimized LLM.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from typing import Annotated, List
|
||||
from typing import Annotated
|
||||
|
||||
import google.generativeai as palm
|
||||
from google.generativeai.types import Completion
|
||||
@@ -51,7 +51,7 @@ class GooglePalmTextCompletion(TextCompletionClientBase):
|
||||
|
||||
async def get_text_contents(
|
||||
self, prompt: str, settings: GooglePalmTextPromptExecutionSettings
|
||||
) -> List[TextContent]:
|
||||
) -> list[TextContent]:
|
||||
"""
|
||||
This is the method that is called from the kernel to get a response from a text-optimized LLM.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from typing import Annotated, Any, List
|
||||
from typing import Annotated, Any
|
||||
|
||||
import google.generativeai as palm
|
||||
from numpy import array, ndarray
|
||||
@@ -48,7 +48,7 @@ class GooglePalmTextEmbedding(EmbeddingGeneratorBase):
|
||||
)
|
||||
super().__init__(ai_model_id=ai_model_id, api_key=api_key)
|
||||
|
||||
async def generate_embeddings(self, texts: List[str], **kwargs: Any) -> ndarray:
|
||||
async def generate_embeddings(self, texts: list[str], **kwargs: Any) -> ndarray:
|
||||
"""
|
||||
Generates embeddings for a list of texts.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Any, Dict
|
||||
from typing import Any
|
||||
|
||||
from transformers import GenerationConfig
|
||||
|
||||
@@ -25,7 +25,7 @@ class HuggingFacePromptExecutionSettings(PromptExecutionSettings):
|
||||
)
|
||||
)
|
||||
|
||||
def prepare_settings_dict(self, **kwargs) -> Dict[str, Any]:
|
||||
def prepare_settings_dict(self, **kwargs) -> dict[str, Any]:
|
||||
gen_config = self.get_generation_config()
|
||||
settings = {
|
||||
"generation_config": gen_config,
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from collections.abc import AsyncGenerator
|
||||
from threading import Thread
|
||||
from typing import TYPE_CHECKING, Any, AsyncGenerator, Dict, List, Literal, Optional
|
||||
from typing import TYPE_CHECKING, Any, Literal
|
||||
|
||||
import torch
|
||||
from transformers import AutoTokenizer, TextIteratorStreamer, pipeline
|
||||
@@ -27,11 +28,11 @@ class HuggingFaceTextCompletion(TextCompletionClientBase):
|
||||
def __init__(
|
||||
self,
|
||||
ai_model_id: str,
|
||||
task: Optional[str] = "text2text-generation",
|
||||
device: Optional[int] = -1,
|
||||
service_id: Optional[str] = None,
|
||||
model_kwargs: Optional[Dict[str, Any]] = None,
|
||||
pipeline_kwargs: Optional[Dict[str, Any]] = None,
|
||||
task: str | None = "text2text-generation",
|
||||
device: int | None = -1,
|
||||
service_id: str | None = None,
|
||||
model_kwargs: dict[str, Any] | None = None,
|
||||
pipeline_kwargs: dict[str, Any] | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initializes a new instance of the HuggingFaceTextCompletion class.
|
||||
@@ -77,7 +78,7 @@ class HuggingFaceTextCompletion(TextCompletionClientBase):
|
||||
self,
|
||||
prompt: str,
|
||||
settings: HuggingFacePromptExecutionSettings,
|
||||
) -> List[TextContent]:
|
||||
) -> list[TextContent]:
|
||||
"""
|
||||
This is the method that is called from the kernel to get a response from a text-optimized LLM.
|
||||
|
||||
@@ -96,7 +97,7 @@ class HuggingFaceTextCompletion(TextCompletionClientBase):
|
||||
return [self._create_text_content(results, result) for result in results]
|
||||
return [self._create_text_content(results, results)]
|
||||
|
||||
def _create_text_content(self, response: Any, candidate: Dict[str, str]) -> TextContent:
|
||||
def _create_text_content(self, response: Any, candidate: dict[str, str]) -> TextContent:
|
||||
return TextContent(
|
||||
inner_content=response,
|
||||
ai_model_id=self.ai_model_id,
|
||||
@@ -107,7 +108,7 @@ class HuggingFaceTextCompletion(TextCompletionClientBase):
|
||||
self,
|
||||
prompt: str,
|
||||
settings: HuggingFacePromptExecutionSettings,
|
||||
) -> AsyncGenerator[List[StreamingTextContent], Any]:
|
||||
) -> AsyncGenerator[list[StreamingTextContent], Any]:
|
||||
"""
|
||||
Streams a text completion using a Hugging Face model.
|
||||
Note that this method does not support multiple responses.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from typing import Any, List, Optional
|
||||
from typing import Any
|
||||
|
||||
import sentence_transformers
|
||||
import torch
|
||||
@@ -22,8 +22,8 @@ class HuggingFaceTextEmbedding(EmbeddingGeneratorBase):
|
||||
def __init__(
|
||||
self,
|
||||
ai_model_id: str,
|
||||
device: Optional[int] = -1,
|
||||
service_id: Optional[str] = None,
|
||||
device: int | None = -1,
|
||||
service_id: str | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initializes a new instance of the HuggingFaceTextEmbedding class.
|
||||
@@ -44,7 +44,7 @@ class HuggingFaceTextEmbedding(EmbeddingGeneratorBase):
|
||||
generator=sentence_transformers.SentenceTransformer(model_name_or_path=ai_model_id, device=resolved_device),
|
||||
)
|
||||
|
||||
async def generate_embeddings(self, texts: List[str], **kwargs: Any) -> ndarray:
|
||||
async def generate_embeddings(self, texts: list[str], **kwargs: Any) -> ndarray:
|
||||
"""
|
||||
Generates embeddings for a list of texts.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from typing import Any, Dict, List, Literal, Optional
|
||||
from typing import Any, Literal
|
||||
|
||||
from pydantic import Field
|
||||
|
||||
@@ -9,18 +9,18 @@ from semantic_kernel.connectors.ai.prompt_execution_settings import PromptExecut
|
||||
|
||||
class OllamaPromptExecutionSettings(PromptExecutionSettings):
|
||||
ai_model_id: str = Field("", serialization_alias="model")
|
||||
format: Optional[Literal["json"]] = None
|
||||
options: Optional[Dict[str, Any]] = None
|
||||
format: Literal["json"] | None = None
|
||||
options: dict[str, Any] | None = None
|
||||
stream: bool = False
|
||||
|
||||
|
||||
class OllamaTextPromptExecutionSettings(OllamaPromptExecutionSettings):
|
||||
prompt: Optional[str] = None
|
||||
context: Optional[str] = None
|
||||
system: Optional[str] = None
|
||||
template: Optional[str] = None
|
||||
prompt: str | None = None
|
||||
context: str | None = None
|
||||
system: str | None = None
|
||||
template: str | None = None
|
||||
raw: bool = False
|
||||
|
||||
|
||||
class OllamaChatPromptExecutionSettings(OllamaPromptExecutionSettings):
|
||||
messages: Optional[List[Dict[str, str]]] = None
|
||||
messages: list[dict[str, str]] | None = None
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
import json
|
||||
import logging
|
||||
from typing import Any, AsyncGenerator, List, Optional
|
||||
from collections.abc import AsyncGenerator
|
||||
from typing import Any
|
||||
|
||||
import aiohttp
|
||||
from pydantic import HttpUrl
|
||||
@@ -33,14 +34,14 @@ class OllamaChatCompletion(TextCompletionClientBase, ChatCompletionClientBase):
|
||||
"""
|
||||
|
||||
url: HttpUrl = "http://localhost:11434/api/chat"
|
||||
session: Optional[aiohttp.ClientSession] = None
|
||||
session: aiohttp.ClientSession | None = None
|
||||
|
||||
async def get_chat_message_contents(
|
||||
self,
|
||||
chat_history: ChatHistory,
|
||||
settings: OllamaChatPromptExecutionSettings,
|
||||
**kwargs: Any,
|
||||
) -> List[ChatMessageContent]:
|
||||
) -> list[ChatMessageContent]:
|
||||
"""
|
||||
This is the method that is called from the kernel to get a response from a chat-optimized LLM.
|
||||
|
||||
@@ -75,7 +76,7 @@ class OllamaChatCompletion(TextCompletionClientBase, ChatCompletionClientBase):
|
||||
chat_history: ChatHistory,
|
||||
settings: OllamaChatPromptExecutionSettings,
|
||||
**kwargs: Any,
|
||||
) -> AsyncGenerator[List[StreamingChatMessageContent], Any]:
|
||||
) -> AsyncGenerator[list[StreamingChatMessageContent], Any]:
|
||||
"""
|
||||
Streams a text completion using a Ollama model.
|
||||
Note that this method does not support multiple responses.
|
||||
@@ -116,7 +117,7 @@ class OllamaChatCompletion(TextCompletionClientBase, ChatCompletionClientBase):
|
||||
self,
|
||||
prompt: str,
|
||||
settings: OllamaChatPromptExecutionSettings,
|
||||
) -> List[TextContent]:
|
||||
) -> list[TextContent]:
|
||||
"""
|
||||
This is the method that is called from the kernel to get a response from a text-optimized LLM.
|
||||
|
||||
@@ -147,7 +148,7 @@ class OllamaChatCompletion(TextCompletionClientBase, ChatCompletionClientBase):
|
||||
self,
|
||||
prompt: str,
|
||||
settings: OllamaChatPromptExecutionSettings,
|
||||
) -> AsyncGenerator[List[StreamingTextContent], Any]:
|
||||
) -> AsyncGenerator[list[StreamingTextContent], Any]:
|
||||
"""
|
||||
Streams a text completion using a Ollama model.
|
||||
Note that this method does not support multiple responses.
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
import json
|
||||
import logging
|
||||
from typing import Any, AsyncGenerator, List, Optional
|
||||
from collections.abc import AsyncGenerator
|
||||
from typing import Any
|
||||
|
||||
import aiohttp
|
||||
from pydantic import HttpUrl
|
||||
@@ -28,13 +29,13 @@ class OllamaTextCompletion(TextCompletionClientBase):
|
||||
"""
|
||||
|
||||
url: HttpUrl = "http://localhost:11434/api/generate"
|
||||
session: Optional[aiohttp.ClientSession] = None
|
||||
session: aiohttp.ClientSession | None = None
|
||||
|
||||
async def get_text_contents(
|
||||
self,
|
||||
prompt: str,
|
||||
settings: OllamaTextPromptExecutionSettings,
|
||||
) -> List[TextContent]:
|
||||
) -> list[TextContent]:
|
||||
"""
|
||||
This is the method that is called from the kernel to get a response from a text-optimized LLM.
|
||||
|
||||
@@ -60,7 +61,7 @@ class OllamaTextCompletion(TextCompletionClientBase):
|
||||
self,
|
||||
prompt: str,
|
||||
settings: OllamaTextPromptExecutionSettings,
|
||||
) -> AsyncGenerator[List[StreamingTextContent], Any]:
|
||||
) -> AsyncGenerator[list[StreamingTextContent], Any]:
|
||||
"""
|
||||
Streams a text completion using a Ollama model.
|
||||
Note that this method does not support multiple responses,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from typing import Any, List, Optional
|
||||
from typing import Any
|
||||
|
||||
import aiohttp
|
||||
from numpy import array, ndarray
|
||||
@@ -27,9 +27,9 @@ class OllamaTextEmbedding(EmbeddingGeneratorBase):
|
||||
"""
|
||||
|
||||
url: HttpUrl = "http://localhost:11434/api/embeddings"
|
||||
session: Optional[aiohttp.ClientSession] = None
|
||||
session: aiohttp.ClientSession | None = None
|
||||
|
||||
async def generate_embeddings(self, texts: List[str], **kwargs: Any) -> ndarray:
|
||||
async def generate_embeddings(self, texts: list[str], **kwargs: Any) -> ndarray:
|
||||
"""
|
||||
Generates embeddings for a list of texts.
|
||||
|
||||
|
||||
+3
-3
@@ -2,7 +2,7 @@
|
||||
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from typing import Any, Dict
|
||||
from typing import Any
|
||||
|
||||
from openai import BadRequestError
|
||||
|
||||
@@ -22,7 +22,7 @@ class ContentFilterResult:
|
||||
severity: ContentFilterResultSeverity = ContentFilterResultSeverity.SAFE
|
||||
|
||||
@classmethod
|
||||
def from_inner_error_result(cls, inner_error_results: Dict[str, Any]) -> "ContentFilterResult":
|
||||
def from_inner_error_result(cls, inner_error_results: dict[str, Any]) -> "ContentFilterResult":
|
||||
"""Creates a ContentFilterResult from the inner error results.
|
||||
|
||||
Arguments:
|
||||
@@ -56,7 +56,7 @@ class ContentFilterAIException(ServiceContentFilterException):
|
||||
content_filter_code: ContentFilterCodes
|
||||
|
||||
# The results of the different content filter checks.
|
||||
content_filter_result: Dict[str, ContentFilterResult]
|
||||
content_filter_result: dict[str, ContentFilterResult]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
||||
+29
-30
@@ -1,10 +1,9 @@
|
||||
import logging
|
||||
from typing import Any, Dict, List, Literal, Optional, Union
|
||||
from typing import Annotated, Any, Literal, Union
|
||||
|
||||
from pydantic import AliasGenerator, ConfigDict, Field
|
||||
from pydantic.alias_generators import to_camel, to_snake
|
||||
from pydantic.functional_validators import AfterValidator
|
||||
from typing_extensions import Annotated
|
||||
|
||||
from semantic_kernel.connectors.ai.open_ai.prompt_execution_settings.open_ai_prompt_execution_settings import (
|
||||
OpenAIChatPromptExecutionSettings,
|
||||
@@ -24,46 +23,46 @@ class AzureChatRequestBase(KernelBaseModel):
|
||||
|
||||
class ConnectionStringAuthentication(AzureChatRequestBase):
|
||||
type: Annotated[Literal["ConnectionString", "connection_string"], AfterValidator(to_snake)] = "connection_string"
|
||||
connection_string: Optional[str] = None
|
||||
connection_string: str | None = None
|
||||
|
||||
|
||||
class ApiKeyAuthentication(AzureChatRequestBase):
|
||||
type: Annotated[Literal["APIKey", "api_key"], AfterValidator(to_snake)] = "api_key"
|
||||
key: Optional[str] = None
|
||||
key: str | None = None
|
||||
|
||||
|
||||
class AzureEmbeddingDependency(AzureChatRequestBase):
|
||||
type: Annotated[Literal["DeploymentName", "deployment_name"], AfterValidator(to_snake)] = "deployment_name"
|
||||
deployment_name: Optional[str] = None
|
||||
deployment_name: str | None = None
|
||||
|
||||
|
||||
class DataSourceFieldsMapping(AzureChatRequestBase):
|
||||
title_field: Optional[str] = None
|
||||
url_field: Optional[str] = None
|
||||
filepath_field: Optional[str] = None
|
||||
content_fields: Optional[List[str]] = None
|
||||
vector_fields: Optional[List[str]] = None
|
||||
content_fields_separator: Optional[str] = "\n"
|
||||
title_field: str | None = None
|
||||
url_field: str | None = None
|
||||
filepath_field: str | None = None
|
||||
content_fields: list[str] | None = None
|
||||
vector_fields: list[str] | None = None
|
||||
content_fields_separator: str | None = "\n"
|
||||
|
||||
|
||||
class AzureDataSourceParameters(AzureChatRequestBase):
|
||||
index_name: str
|
||||
index_language: Optional[str] = None
|
||||
fields_mapping: Optional[DataSourceFieldsMapping] = None
|
||||
in_scope: Optional[bool] = True
|
||||
top_n_documents: Optional[int] = 5
|
||||
semantic_configuration: Optional[str] = None
|
||||
role_information: Optional[str] = None
|
||||
filter: Optional[str] = None
|
||||
index_language: str | None = None
|
||||
fields_mapping: DataSourceFieldsMapping | None = None
|
||||
in_scope: bool | None = True
|
||||
top_n_documents: int | None = 5
|
||||
semantic_configuration: str | None = None
|
||||
role_information: str | None = None
|
||||
filter: str | None = None
|
||||
strictness: int = 3
|
||||
embedding_dependency: Optional[AzureEmbeddingDependency] = None
|
||||
embedding_dependency: AzureEmbeddingDependency | None = None
|
||||
|
||||
|
||||
class AzureCosmosDBDataSourceParameters(AzureDataSourceParameters):
|
||||
authentication: Optional[ConnectionStringAuthentication] = None
|
||||
database_name: Optional[str] = None
|
||||
container_name: Optional[str] = None
|
||||
embedding_dependency_type: Optional[AzureEmbeddingDependency] = None
|
||||
authentication: ConnectionStringAuthentication | None = None
|
||||
database_name: str | None = None
|
||||
container_name: str | None = None
|
||||
embedding_dependency_type: AzureEmbeddingDependency | None = None
|
||||
|
||||
|
||||
class AzureCosmosDBDataSource(AzureChatRequestBase):
|
||||
@@ -72,11 +71,11 @@ class AzureCosmosDBDataSource(AzureChatRequestBase):
|
||||
|
||||
|
||||
class AzureAISearchDataSourceParameters(AzureDataSourceParameters):
|
||||
endpoint: Optional[str] = None
|
||||
endpoint: str | None = None
|
||||
query_type: Annotated[
|
||||
Literal["simple", "semantic", "vector", "vectorSimpleHybrid", "vectorSemanticHybrid"], AfterValidator(to_snake)
|
||||
] = "simple"
|
||||
authentication: Optional[ApiKeyAuthentication] = None
|
||||
authentication: ApiKeyAuthentication | None = None
|
||||
|
||||
|
||||
class AzureAISearchDataSource(AzureChatRequestBase):
|
||||
@@ -88,9 +87,9 @@ DataSource = Annotated[Union[AzureAISearchDataSource, AzureCosmosDBDataSource],
|
||||
|
||||
|
||||
class ExtraBody(KernelBaseModel):
|
||||
data_sources: Optional[List[DataSource]] = None
|
||||
input_language: Optional[str] = Field(None, serialization_alias="inputLanguage")
|
||||
output_language: Optional[str] = Field(None, serialization_alias="outputLanguage")
|
||||
data_sources: list[DataSource] | None = None
|
||||
input_language: str | None = Field(None, serialization_alias="inputLanguage")
|
||||
output_language: str | None = Field(None, serialization_alias="outputLanguage")
|
||||
|
||||
def __getitem__(self, item):
|
||||
return getattr(self, item)
|
||||
@@ -99,5 +98,5 @@ class ExtraBody(KernelBaseModel):
|
||||
class AzureChatPromptExecutionSettings(OpenAIChatPromptExecutionSettings):
|
||||
"""Specific settings for the Azure OpenAI Chat Completion endpoint."""
|
||||
|
||||
response_format: Optional[str] = None
|
||||
extra_body: Optional[Union[Dict[str, Any], ExtraBody]] = None
|
||||
response_format: str | None = None
|
||||
extra_body: dict[str, Any] | ExtraBody | None = None
|
||||
|
||||
+27
-28
@@ -1,8 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any, Dict, List, Literal, Optional, Union
|
||||
from typing import Any, Literal
|
||||
|
||||
from pydantic import Field, field_validator, model_validator
|
||||
|
||||
@@ -16,28 +15,28 @@ logger = logging.getLogger(__name__)
|
||||
class OpenAIPromptExecutionSettings(PromptExecutionSettings):
|
||||
"""Common request settings for (Azure) OpenAI services."""
|
||||
|
||||
ai_model_id: Optional[str] = Field(None, serialization_alias="model")
|
||||
ai_model_id: str | None = Field(None, serialization_alias="model")
|
||||
frequency_penalty: float = Field(0.0, ge=-2.0, le=2.0)
|
||||
logit_bias: Dict[Union[str, int], float] = Field(default_factory=dict)
|
||||
logit_bias: dict[str | int, float] = Field(default_factory=dict)
|
||||
max_tokens: int = Field(256, gt=0)
|
||||
number_of_responses: int = Field(1, ge=1, le=128, serialization_alias="n")
|
||||
presence_penalty: float = Field(0.0, ge=-2.0, le=2.0)
|
||||
seed: Optional[int] = None
|
||||
stop: Optional[Union[str, List[str]]] = None
|
||||
seed: int | None = None
|
||||
stop: str | list[str] | None = None
|
||||
stream: bool = False
|
||||
temperature: float = Field(0.0, ge=0.0, le=2.0)
|
||||
top_p: float = Field(1.0, ge=0.0, le=1.0)
|
||||
user: Optional[str] = None
|
||||
user: str | None = None
|
||||
|
||||
|
||||
class OpenAITextPromptExecutionSettings(OpenAIPromptExecutionSettings):
|
||||
"""Specific settings for the completions endpoint."""
|
||||
|
||||
prompt: Optional[str] = None
|
||||
best_of: Optional[int] = Field(None, ge=1)
|
||||
prompt: str | None = None
|
||||
best_of: int | None = Field(None, ge=1)
|
||||
echo: bool = False
|
||||
logprobs: Optional[int] = Field(None, ge=0, le=5)
|
||||
suffix: Optional[str] = None
|
||||
logprobs: int | None = Field(None, ge=0, le=5)
|
||||
suffix: str | None = None
|
||||
|
||||
@model_validator(mode="after")
|
||||
def check_best_of_and_n(self) -> "OpenAITextPromptExecutionSettings":
|
||||
@@ -58,17 +57,17 @@ class OpenAITextPromptExecutionSettings(OpenAIPromptExecutionSettings):
|
||||
class OpenAIChatPromptExecutionSettings(OpenAIPromptExecutionSettings):
|
||||
"""Specific settings for the Chat Completion endpoint."""
|
||||
|
||||
response_format: Optional[Dict[Literal["type"], Literal["text", "json_object"]]] = None
|
||||
tools: Optional[List[Dict[str, Any]]] = Field(None, max_length=64)
|
||||
tool_choice: Optional[str] = None
|
||||
function_call: Optional[str] = None
|
||||
functions: Optional[List[Dict[str, Any]]] = None
|
||||
messages: Optional[List[Dict[str, Any]]] = None
|
||||
function_call_behavior: Optional[FunctionCallBehavior] = Field(None, exclude=True)
|
||||
response_format: dict[Literal["type"], Literal["text", "json_object"]] | None = None
|
||||
tools: list[dict[str, Any]] | None = Field(None, max_length=64)
|
||||
tool_choice: str | None = None
|
||||
function_call: str | None = None
|
||||
functions: list[dict[str, Any]] | None = None
|
||||
messages: list[dict[str, Any]] | None = None
|
||||
function_call_behavior: FunctionCallBehavior | None = Field(None, exclude=True)
|
||||
|
||||
@field_validator("functions", "function_call", mode="after")
|
||||
@classmethod
|
||||
def validate_function_call(cls, v: Optional[Union[str, List[Dict[str, Any]]]] = None):
|
||||
def validate_function_call(cls, v: str | list[dict[str, Any]] | None = None):
|
||||
if v is not None:
|
||||
logger.warning(
|
||||
"The function_call and functions parameters are deprecated. Please use the tool_choice and tools parameters instead." # noqa: E501
|
||||
@@ -77,12 +76,12 @@ class OpenAIChatPromptExecutionSettings(OpenAIPromptExecutionSettings):
|
||||
|
||||
|
||||
class OpenAIEmbeddingPromptExecutionSettings(PromptExecutionSettings):
|
||||
input: Optional[Union[str, List[str], List[int], List[List[int]]]] = None
|
||||
ai_model_id: Optional[str] = Field(None, serialization_alias="model")
|
||||
encoding_format: Optional[Literal["float", "base64"]] = None
|
||||
user: Optional[str] = None
|
||||
extra_headers: Optional[Dict] = None
|
||||
extra_query: Optional[Dict] = None
|
||||
extra_body: Optional[Dict] = None
|
||||
timeout: Optional[float] = None
|
||||
dimensions: Optional[int] = Field(None, gt=0, le=3072)
|
||||
input: str | list[str] | list[int] | list[list[int]] | None = None
|
||||
ai_model_id: str | None = Field(None, serialization_alias="model")
|
||||
encoding_format: Literal["float", "base64"] | None = None
|
||||
user: str | None = None
|
||||
extra_headers: dict | None = None
|
||||
extra_query: dict | None = None
|
||||
extra_body: dict | None = None
|
||||
timeout: float | None = None
|
||||
dimensions: int | None = Field(None, gt=0, le=3072)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import json
|
||||
import logging
|
||||
from collections.abc import Mapping
|
||||
from copy import deepcopy
|
||||
from typing import Any, Dict, Mapping, Optional, Union
|
||||
from typing import Any
|
||||
from uuid import uuid4
|
||||
|
||||
from openai import AsyncAzureOpenAI
|
||||
@@ -120,7 +121,7 @@ class AzureChatCompletion(AzureOpenAIConfigBase, OpenAIChatCompletionBase, OpenA
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, settings: Dict[str, str]) -> "AzureChatCompletion":
|
||||
def from_dict(cls, settings: dict[str, str]) -> "AzureChatCompletion":
|
||||
"""
|
||||
Initialize an Azure OpenAI service from a dictionary of settings.
|
||||
|
||||
@@ -148,7 +149,7 @@ class AzureChatCompletion(AzureOpenAIConfigBase, OpenAIChatCompletionBase, OpenA
|
||||
return AzureChatPromptExecutionSettings
|
||||
|
||||
def _create_chat_message_content(
|
||||
self, response: ChatCompletion, choice: Choice, response_metadata: Dict[str, Any]
|
||||
self, response: ChatCompletion, choice: Choice, response_metadata: dict[str, Any]
|
||||
) -> ChatMessageContent:
|
||||
"""Create a Azure chat message content object from a choice."""
|
||||
content = super()._create_chat_message_content(response, choice, response_metadata)
|
||||
@@ -158,7 +159,7 @@ class AzureChatCompletion(AzureOpenAIConfigBase, OpenAIChatCompletionBase, OpenA
|
||||
self,
|
||||
chunk: ChatCompletionChunk,
|
||||
choice: ChunkChoice,
|
||||
chunk_metadata: Dict[str, Any],
|
||||
chunk_metadata: dict[str, Any],
|
||||
) -> "StreamingChatMessageContent":
|
||||
"""Create a Azure streaming chat message content object from a choice."""
|
||||
content = super()._create_streaming_chat_message_content(chunk, choice, chunk_metadata)
|
||||
@@ -186,7 +187,7 @@ class AzureChatCompletion(AzureOpenAIConfigBase, OpenAIChatCompletionBase, OpenA
|
||||
content.items.insert(1, result)
|
||||
return content
|
||||
|
||||
def _get_tool_message_from_chat_choice(self, choice: Union[Choice, ChunkChoice]) -> Optional[str]:
|
||||
def _get_tool_message_from_chat_choice(self, choice: Choice | ChunkChoice) -> str | None:
|
||||
"""Get the tool message from a choice."""
|
||||
if isinstance(choice, Choice):
|
||||
content = choice.message
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from typing import Awaitable, Callable, Dict, Mapping, Optional, Union
|
||||
from collections.abc import Awaitable, Callable, Mapping
|
||||
|
||||
from openai import AsyncAzureOpenAI
|
||||
from pydantic import ConfigDict, validate_call
|
||||
@@ -23,15 +23,15 @@ class AzureOpenAIConfigBase(OpenAIHandler):
|
||||
self,
|
||||
deployment_name: str,
|
||||
ai_model_type: OpenAIModelTypes,
|
||||
endpoint: Optional[HttpsUrl] = None,
|
||||
base_url: Optional[HttpsUrl] = None,
|
||||
endpoint: HttpsUrl | None = None,
|
||||
base_url: HttpsUrl | None = None,
|
||||
api_version: str = DEFAULT_AZURE_API_VERSION,
|
||||
service_id: Optional[str] = None,
|
||||
api_key: Optional[str] = None,
|
||||
ad_token: Optional[str] = None,
|
||||
ad_token_provider: Optional[Callable[[], Union[str, Awaitable[str]]]] = None,
|
||||
default_headers: Union[Mapping[str, str], None] = None,
|
||||
async_client: Optional[AsyncAzureOpenAI] = None,
|
||||
service_id: str | None = None,
|
||||
api_key: str | None = None,
|
||||
ad_token: str | None = None,
|
||||
ad_token_provider: Callable[[], str | Awaitable[str]] | None = None,
|
||||
default_headers: Mapping[str, str] | None = None,
|
||||
async_client: AsyncAzureOpenAI | None = None,
|
||||
) -> None:
|
||||
"""Internal class for configuring a connection to an Azure OpenAI service.
|
||||
|
||||
@@ -90,7 +90,7 @@ class AzureOpenAIConfigBase(OpenAIHandler):
|
||||
args["service_id"] = service_id
|
||||
super().__init__(**args)
|
||||
|
||||
def to_dict(self) -> Dict[str, str]:
|
||||
def to_dict(self) -> dict[str, str]:
|
||||
client_settings = {
|
||||
"base_url": str(self.client.base_url),
|
||||
"api_version": self.client._custom_query["api-version"],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from typing import Mapping
|
||||
from collections.abc import Mapping
|
||||
|
||||
from openai import AsyncAzureOpenAI
|
||||
from openai.lib.azure import AsyncAzureADTokenProvider
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
|
||||
import logging
|
||||
from typing import Mapping
|
||||
from collections.abc import Mapping
|
||||
|
||||
from openai import AsyncAzureOpenAI
|
||||
from openai.lib.azure import AsyncAzureADTokenProvider
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from typing import (
|
||||
Dict,
|
||||
Mapping,
|
||||
)
|
||||
from collections.abc import Mapping
|
||||
|
||||
from openai import AsyncOpenAI
|
||||
from pydantic import ValidationError
|
||||
@@ -77,7 +74,7 @@ class OpenAIChatCompletion(OpenAIConfigBase, OpenAIChatCompletionBase, OpenAITex
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, settings: Dict[str, str]) -> "OpenAIChatCompletion":
|
||||
def from_dict(cls, settings: dict[str, str]) -> "OpenAIChatCompletion":
|
||||
"""
|
||||
Initialize an Open AI service from a dictionary of settings.
|
||||
|
||||
|
||||
+13
-12
@@ -2,9 +2,10 @@
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from collections.abc import AsyncGenerator
|
||||
from copy import copy
|
||||
from functools import reduce
|
||||
from typing import TYPE_CHECKING, Any, AsyncGenerator, Dict, List, Optional, Union
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from openai import AsyncStream
|
||||
from openai.types.chat.chat_completion import ChatCompletion, Choice
|
||||
@@ -73,7 +74,7 @@ class OpenAIChatCompletionBase(OpenAIHandler, ChatCompletionClientBase):
|
||||
chat_history: ChatHistory,
|
||||
settings: OpenAIChatPromptExecutionSettings,
|
||||
**kwargs: Any,
|
||||
) -> List["ChatMessageContent"]:
|
||||
) -> list["ChatMessageContent"]:
|
||||
"""Executes a chat completion request and returns the result.
|
||||
|
||||
Arguments:
|
||||
@@ -150,7 +151,7 @@ class OpenAIChatCompletionBase(OpenAIHandler, ChatCompletionClientBase):
|
||||
chat_history: ChatHistory,
|
||||
settings: OpenAIChatPromptExecutionSettings,
|
||||
**kwargs: Any,
|
||||
) -> AsyncGenerator[List[StreamingChatMessageContent | None], Any]:
|
||||
) -> AsyncGenerator[list[StreamingChatMessageContent | None], Any]:
|
||||
"""Executes a streaming chat completion request and returns the result.
|
||||
|
||||
Arguments:
|
||||
@@ -239,7 +240,7 @@ class OpenAIChatCompletionBase(OpenAIHandler, ChatCompletionClientBase):
|
||||
|
||||
self._update_settings(settings, chat_history, kernel=kernel)
|
||||
|
||||
def _chat_message_content_to_dict(self, message: "ChatMessageContent") -> Dict[str, Optional[str]]:
|
||||
def _chat_message_content_to_dict(self, message: "ChatMessageContent") -> dict[str, str | None]:
|
||||
msg = super()._chat_message_content_to_dict(message)
|
||||
if message.role == "assistant":
|
||||
if tool_calls := getattr(message, "tool_calls", None):
|
||||
@@ -256,7 +257,7 @@ class OpenAIChatCompletionBase(OpenAIHandler, ChatCompletionClientBase):
|
||||
# endregion
|
||||
# region internal handlers
|
||||
|
||||
async def _send_chat_request(self, settings: OpenAIChatPromptExecutionSettings) -> List["ChatMessageContent"]:
|
||||
async def _send_chat_request(self, settings: OpenAIChatPromptExecutionSettings) -> list["ChatMessageContent"]:
|
||||
"""Send the chat request"""
|
||||
response = await self._send_request(request_settings=settings)
|
||||
response_metadata = self._get_metadata_from_chat_response(response)
|
||||
@@ -284,7 +285,7 @@ class OpenAIChatCompletionBase(OpenAIHandler, ChatCompletionClientBase):
|
||||
# region content creation
|
||||
|
||||
def _create_chat_message_content(
|
||||
self, response: ChatCompletion, choice: Choice, response_metadata: Dict[str, Any]
|
||||
self, response: ChatCompletion, choice: Choice, response_metadata: dict[str, Any]
|
||||
) -> "ChatMessageContent":
|
||||
"""Create a chat message content object from a choice."""
|
||||
metadata = self._get_metadata_from_chat_choice(choice)
|
||||
@@ -308,7 +309,7 @@ class OpenAIChatCompletionBase(OpenAIHandler, ChatCompletionClientBase):
|
||||
self,
|
||||
chunk: ChatCompletionChunk,
|
||||
choice: ChunkChoice,
|
||||
chunk_metadata: Dict[str, Any],
|
||||
chunk_metadata: dict[str, Any],
|
||||
) -> StreamingChatMessageContent | None:
|
||||
"""Create a streaming chat message content object from a choice."""
|
||||
metadata = self._get_metadata_from_chat_choice(choice)
|
||||
@@ -328,7 +329,7 @@ class OpenAIChatCompletionBase(OpenAIHandler, ChatCompletionClientBase):
|
||||
items=items,
|
||||
)
|
||||
|
||||
def _get_metadata_from_chat_response(self, response: ChatCompletion) -> Dict[str, Any]:
|
||||
def _get_metadata_from_chat_response(self, response: ChatCompletion) -> dict[str, Any]:
|
||||
"""Get metadata from a chat response."""
|
||||
return {
|
||||
"id": response.id,
|
||||
@@ -337,7 +338,7 @@ class OpenAIChatCompletionBase(OpenAIHandler, ChatCompletionClientBase):
|
||||
"usage": getattr(response, "usage", None),
|
||||
}
|
||||
|
||||
def _get_metadata_from_streaming_chat_response(self, response: ChatCompletionChunk) -> Dict[str, Any]:
|
||||
def _get_metadata_from_streaming_chat_response(self, response: ChatCompletionChunk) -> dict[str, Any]:
|
||||
"""Get metadata from a streaming chat response."""
|
||||
return {
|
||||
"id": response.id,
|
||||
@@ -345,13 +346,13 @@ class OpenAIChatCompletionBase(OpenAIHandler, ChatCompletionClientBase):
|
||||
"system_fingerprint": response.system_fingerprint,
|
||||
}
|
||||
|
||||
def _get_metadata_from_chat_choice(self, choice: Union[Choice, ChunkChoice]) -> Dict[str, Any]:
|
||||
def _get_metadata_from_chat_choice(self, choice: Choice | ChunkChoice) -> dict[str, Any]:
|
||||
"""Get metadata from a chat choice."""
|
||||
return {
|
||||
"logprobs": getattr(choice, "logprobs", None),
|
||||
}
|
||||
|
||||
def _get_tool_calls_from_chat_choice(self, choice: Union[Choice, ChunkChoice]) -> List[FunctionCallContent]:
|
||||
def _get_tool_calls_from_chat_choice(self, choice: Choice | ChunkChoice) -> list[FunctionCallContent]:
|
||||
"""Get tool calls from a chat choice."""
|
||||
if isinstance(choice, Choice):
|
||||
content = choice.message
|
||||
@@ -369,7 +370,7 @@ class OpenAIChatCompletionBase(OpenAIHandler, ChatCompletionClientBase):
|
||||
for tool in content.tool_calls
|
||||
]
|
||||
|
||||
def _get_function_call_from_chat_choice(self, choice: Union[Choice, ChunkChoice]) -> List[FunctionCallContent]:
|
||||
def _get_function_call_from_chat_choice(self, choice: Choice | ChunkChoice) -> list[FunctionCallContent]:
|
||||
"""Get a function call from a chat choice."""
|
||||
if isinstance(choice, Choice):
|
||||
content = choice.message
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from typing import Dict, Mapping, Optional
|
||||
from collections.abc import Mapping
|
||||
|
||||
from openai import AsyncOpenAI
|
||||
from pydantic import ConfigDict, Field, validate_call
|
||||
@@ -20,12 +20,12 @@ class OpenAIConfigBase(OpenAIHandler):
|
||||
def __init__(
|
||||
self,
|
||||
ai_model_id: str = Field(min_length=1),
|
||||
api_key: Optional[str] = Field(min_length=1),
|
||||
ai_model_type: Optional[OpenAIModelTypes] = OpenAIModelTypes.CHAT,
|
||||
org_id: Optional[str] = None,
|
||||
service_id: Optional[str] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
async_client: Optional[AsyncOpenAI] = None,
|
||||
api_key: str | None = Field(min_length=1),
|
||||
ai_model_type: OpenAIModelTypes | None = OpenAIModelTypes.CHAT,
|
||||
org_id: str | None = None,
|
||||
service_id: str | None = None,
|
||||
default_headers: Mapping[str, str] | None = None,
|
||||
async_client: AsyncOpenAI | None = None,
|
||||
) -> None:
|
||||
"""Initialize a client for OpenAI services.
|
||||
|
||||
@@ -68,7 +68,7 @@ class OpenAIConfigBase(OpenAIHandler):
|
||||
args["service_id"] = service_id
|
||||
super().__init__(**args)
|
||||
|
||||
def to_dict(self) -> Dict[str, str]:
|
||||
def to_dict(self) -> dict[str, str]:
|
||||
"""
|
||||
Create a dict of the service settings.
|
||||
"""
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import logging
|
||||
from abc import ABC
|
||||
from typing import List, Union
|
||||
|
||||
from numpy import array, ndarray
|
||||
from openai import AsyncOpenAI, AsyncStream, BadRequestError
|
||||
@@ -37,7 +36,7 @@ class OpenAIHandler(KernelBaseModel, ABC):
|
||||
async def _send_request(
|
||||
self,
|
||||
request_settings: OpenAIPromptExecutionSettings,
|
||||
) -> Union[ChatCompletion, Completion, AsyncStream[ChatCompletionChunk], AsyncStream[Completion]]:
|
||||
) -> ChatCompletion | Completion | AsyncStream[ChatCompletionChunk] | AsyncStream[Completion]:
|
||||
"""
|
||||
Completes the given prompt. Returns a single string completion.
|
||||
Cannot return multiple completions. Cannot return logprobs.
|
||||
@@ -75,7 +74,7 @@ class OpenAIHandler(KernelBaseModel, ABC):
|
||||
ex,
|
||||
) from ex
|
||||
|
||||
async def _send_embedding_request(self, settings: OpenAIEmbeddingPromptExecutionSettings) -> List[ndarray]:
|
||||
async def _send_embedding_request(self, settings: OpenAIEmbeddingPromptExecutionSettings) -> list[ndarray]:
|
||||
try:
|
||||
response = await self.client.embeddings.create(**settings.prepare_settings_dict())
|
||||
self.store_usage(response)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import json
|
||||
import logging
|
||||
from typing import Dict, Mapping, Optional
|
||||
from collections.abc import Mapping
|
||||
|
||||
from openai import AsyncOpenAI
|
||||
from pydantic import ValidationError
|
||||
@@ -29,9 +29,9 @@ class OpenAITextCompletion(OpenAITextCompletionBase, OpenAIConfigBase):
|
||||
ai_model_id: str | None = None,
|
||||
api_key: str | None = None,
|
||||
org_id: str | None = None,
|
||||
service_id: Optional[str] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
async_client: Optional[AsyncOpenAI] = None,
|
||||
service_id: str | None = None,
|
||||
default_headers: Mapping[str, str] | None = None,
|
||||
async_client: AsyncOpenAI | None = None,
|
||||
env_file_path: str | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
@@ -75,7 +75,7 @@ class OpenAITextCompletion(OpenAITextCompletionBase, OpenAIConfigBase):
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, settings: Dict[str, str]) -> "OpenAITextCompletion":
|
||||
def from_dict(cls, settings: dict[str, str]) -> "OpenAITextCompletion":
|
||||
"""
|
||||
Initialize an Open AI service from a dictionary of settings.
|
||||
|
||||
|
||||
+10
-9
@@ -1,7 +1,8 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, Any, AsyncGenerator, Dict, List, Union
|
||||
from collections.abc import AsyncGenerator
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from openai import AsyncStream
|
||||
from openai.types import Completion, CompletionChoice
|
||||
@@ -35,7 +36,7 @@ class OpenAITextCompletionBase(OpenAIHandler, TextCompletionClientBase):
|
||||
self,
|
||||
prompt: str,
|
||||
settings: "OpenAIPromptExecutionSettings",
|
||||
) -> List["TextContent"]:
|
||||
) -> list["TextContent"]:
|
||||
"""Executes a completion request and returns the result.
|
||||
|
||||
Arguments:
|
||||
@@ -58,8 +59,8 @@ class OpenAITextCompletionBase(OpenAIHandler, TextCompletionClientBase):
|
||||
def _create_text_content(
|
||||
self,
|
||||
response: Completion,
|
||||
choice: Union[CompletionChoice, ChatCompletionChoice],
|
||||
response_metadata: Dict[str, Any],
|
||||
choice: CompletionChoice | ChatCompletionChoice,
|
||||
response_metadata: dict[str, Any],
|
||||
) -> "TextContent":
|
||||
"""Create a text content object from a choice."""
|
||||
choice_metadata = self._get_metadata_from_text_choice(choice)
|
||||
@@ -76,7 +77,7 @@ class OpenAITextCompletionBase(OpenAIHandler, TextCompletionClientBase):
|
||||
self,
|
||||
prompt: str,
|
||||
settings: "OpenAIPromptExecutionSettings",
|
||||
) -> AsyncGenerator[List["StreamingTextContent"], Any]:
|
||||
) -> AsyncGenerator[list["StreamingTextContent"], Any]:
|
||||
"""
|
||||
Executes a completion request and streams the result.
|
||||
Supports both chat completion and text completion.
|
||||
@@ -108,7 +109,7 @@ class OpenAITextCompletionBase(OpenAIHandler, TextCompletionClientBase):
|
||||
yield [self._create_streaming_text_content(chunk, choice, chunk_metadata) for choice in chunk.choices]
|
||||
|
||||
def _create_streaming_text_content(
|
||||
self, chunk: Completion, choice: Union[CompletionChoice, ChatCompletionChunk], response_metadata: Dict[str, Any]
|
||||
self, chunk: Completion, choice: CompletionChoice | ChatCompletionChunk, response_metadata: dict[str, Any]
|
||||
) -> "StreamingTextContent":
|
||||
"""Create a streaming text content object from a choice."""
|
||||
choice_metadata = self._get_metadata_from_text_choice(choice)
|
||||
@@ -122,7 +123,7 @@ class OpenAITextCompletionBase(OpenAIHandler, TextCompletionClientBase):
|
||||
text=text,
|
||||
)
|
||||
|
||||
def _get_metadata_from_text_response(self, response: Completion) -> Dict[str, Any]:
|
||||
def _get_metadata_from_text_response(self, response: Completion) -> dict[str, Any]:
|
||||
"""Get metadata from a completion response."""
|
||||
return {
|
||||
"id": response.id,
|
||||
@@ -131,7 +132,7 @@ class OpenAITextCompletionBase(OpenAIHandler, TextCompletionClientBase):
|
||||
"usage": response.usage,
|
||||
}
|
||||
|
||||
def _get_metadata_from_streaming_text_response(self, response: Completion) -> Dict[str, Any]:
|
||||
def _get_metadata_from_streaming_text_response(self, response: Completion) -> dict[str, Any]:
|
||||
"""Get metadata from a streaming completion response."""
|
||||
return {
|
||||
"id": response.id,
|
||||
@@ -139,7 +140,7 @@ class OpenAITextCompletionBase(OpenAIHandler, TextCompletionClientBase):
|
||||
"system_fingerprint": response.system_fingerprint,
|
||||
}
|
||||
|
||||
def _get_metadata_from_text_choice(self, choice: CompletionChoice) -> Dict[str, Any]:
|
||||
def _get_metadata_from_text_choice(self, choice: CompletionChoice) -> dict[str, Any]:
|
||||
"""Get metadata from a completion choice."""
|
||||
return {
|
||||
"logprobs": getattr(choice, "logprobs", None),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from typing import Dict, Mapping, Optional
|
||||
from collections.abc import Mapping
|
||||
|
||||
from openai import AsyncOpenAI
|
||||
from pydantic import ValidationError
|
||||
@@ -30,9 +30,9 @@ class OpenAITextEmbedding(OpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
ai_model_id: str,
|
||||
api_key: str | None = None,
|
||||
org_id: str | None = None,
|
||||
service_id: Optional[str] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
async_client: Optional[AsyncOpenAI] = None,
|
||||
service_id: str | None = None,
|
||||
default_headers: Mapping[str, str] | None = None,
|
||||
async_client: AsyncOpenAI | None = None,
|
||||
env_file_path: str | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
@@ -76,7 +76,7 @@ class OpenAITextEmbedding(OpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, settings: Dict[str, str]) -> "OpenAITextEmbedding":
|
||||
def from_dict(cls, settings: dict[str, str]) -> "OpenAITextEmbedding":
|
||||
"""
|
||||
Initialize an Open AI service from a dictionary of settings.
|
||||
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from typing import Any, List, Optional
|
||||
from typing import Any
|
||||
|
||||
from numpy import array, ndarray
|
||||
|
||||
@@ -15,7 +15,7 @@ from semantic_kernel.utils.experimental_decorator import experimental_class
|
||||
|
||||
@experimental_class
|
||||
class OpenAITextEmbeddingBase(OpenAIHandler, EmbeddingGeneratorBase):
|
||||
async def generate_embeddings(self, texts: List[str], batch_size: Optional[int] = None, **kwargs: Any) -> ndarray:
|
||||
async def generate_embeddings(self, texts: list[str], batch_size: int | None = None, **kwargs: Any) -> ndarray:
|
||||
"""Generates embeddings for the given texts.
|
||||
|
||||
Arguments:
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
@@ -56,7 +55,7 @@ class PromptExecutionSettings(KernelBaseModel):
|
||||
by_alias=True,
|
||||
)
|
||||
|
||||
def update_from_prompt_execution_settings(self, config: PromptExecutionSettings) -> None:
|
||||
def update_from_prompt_execution_settings(self, config: "PromptExecutionSettings") -> None:
|
||||
"""Update the prompt execution settings from a completion config."""
|
||||
if config.service_id is not None:
|
||||
self.service_id = config.service_id
|
||||
@@ -65,7 +64,7 @@ class PromptExecutionSettings(KernelBaseModel):
|
||||
self.unpack_extension_data()
|
||||
|
||||
@classmethod
|
||||
def from_prompt_execution_settings(cls, config: PromptExecutionSettings) -> PromptExecutionSettings:
|
||||
def from_prompt_execution_settings(cls, config: "PromptExecutionSettings") -> "PromptExecutionSettings":
|
||||
"""Create a prompt execution settings from a completion config."""
|
||||
config.pack_extension_data()
|
||||
return cls(
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import TYPE_CHECKING, Any, AsyncGenerator
|
||||
from collections.abc import AsyncGenerator
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from semantic_kernel.services.ai_service_client_base import AIServiceClientBase
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import json
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
import aiohttp
|
||||
|
||||
@@ -26,7 +25,7 @@ class AstraClient:
|
||||
keyspace_name: str,
|
||||
embedding_dim: int,
|
||||
similarity_function: str,
|
||||
session: Optional[aiohttp.ClientSession] = None,
|
||||
session: aiohttp.ClientSession | None = None,
|
||||
):
|
||||
self.astra_id = astra_id
|
||||
self.astra_application_token = astra_application_token
|
||||
@@ -45,7 +44,7 @@ class AstraClient:
|
||||
}
|
||||
self._session = session
|
||||
|
||||
async def _run_query(self, request_url: str, query: Dict):
|
||||
async def _run_query(self, request_url: str, query: dict):
|
||||
async with AsyncSession(self._session) as session:
|
||||
async with session.post(request_url, data=json.dumps(query), headers=self.request_header) as response:
|
||||
if response.status == 200:
|
||||
@@ -74,8 +73,8 @@ class AstraClient:
|
||||
async def create_collection(
|
||||
self,
|
||||
collection_name: str,
|
||||
embedding_dim: Optional[int] = None,
|
||||
similarity_function: Optional[str] = None,
|
||||
embedding_dim: int | None = None,
|
||||
similarity_function: str | None = None,
|
||||
):
|
||||
query = {
|
||||
"createCollection": {
|
||||
@@ -102,12 +101,12 @@ class AstraClient:
|
||||
async def find_documents(
|
||||
self,
|
||||
collection_name: str,
|
||||
filter: Optional[Dict] = None,
|
||||
vector: Optional[List[float]] = None,
|
||||
limit: Optional[int] = None,
|
||||
include_vector: Optional[bool] = None,
|
||||
include_similarity: Optional[bool] = None,
|
||||
) -> List[Dict]:
|
||||
filter: dict | None = None,
|
||||
vector: list[float] | None = None,
|
||||
limit: int | None = None,
|
||||
include_vector: bool | None = None,
|
||||
include_similarity: bool | None = None,
|
||||
) -> list[dict]:
|
||||
find_query = {}
|
||||
|
||||
if filter is not None:
|
||||
@@ -132,17 +131,17 @@ class AstraClient:
|
||||
result = await self._run_query(self._build_request_collection_url(collection_name), query)
|
||||
return result["data"]["documents"]
|
||||
|
||||
async def insert_document(self, collection_name: str, document: Dict) -> str:
|
||||
async def insert_document(self, collection_name: str, document: dict) -> str:
|
||||
query = {"insertOne": {"document": document}}
|
||||
result = await self._run_query(self._build_request_collection_url(collection_name), query)
|
||||
return result["status"]["insertedIds"][0]
|
||||
|
||||
async def insert_documents(self, collection_name: str, documents: List[Dict]) -> List[str]:
|
||||
async def insert_documents(self, collection_name: str, documents: list[dict]) -> list[str]:
|
||||
query = {"insertMany": {"documents": documents}}
|
||||
result = await self._run_query(self._build_request_collection_url(collection_name), query)
|
||||
return result["status"]["insertedIds"]
|
||||
|
||||
async def update_document(self, collection_name: str, filter: Dict, update: Dict, upsert: bool = True) -> Dict:
|
||||
async def update_document(self, collection_name: str, filter: dict, update: dict, upsert: bool = True) -> dict:
|
||||
query = {
|
||||
"findOneAndUpdate": {
|
||||
"filter": filter,
|
||||
@@ -153,7 +152,7 @@ class AstraClient:
|
||||
result = await self._run_query(self._build_request_collection_url(collection_name), query)
|
||||
return result["status"]
|
||||
|
||||
async def update_documents(self, collection_name: str, filter: Dict, update: Dict):
|
||||
async def update_documents(self, collection_name: str, filter: dict, update: dict):
|
||||
query = {
|
||||
"updateMany": {
|
||||
"filter": filter,
|
||||
@@ -163,7 +162,7 @@ class AstraClient:
|
||||
result = await self._run_query(self._build_request_collection_url(collection_name), query)
|
||||
return result["status"]
|
||||
|
||||
async def delete_documents(self, collection_name: str, filter: Dict) -> int:
|
||||
async def delete_documents(self, collection_name: str, filter: dict) -> int:
|
||||
query = {"deleteMany": {"filter": filter}}
|
||||
result = await self._run_query(self._build_request_collection_url(collection_name), query)
|
||||
return result["status"]["deletedCount"]
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
import aiohttp
|
||||
from numpy import ndarray
|
||||
@@ -99,7 +98,7 @@ class AstraDBMemoryStore(MemoryStoreBase):
|
||||
session=self._session,
|
||||
)
|
||||
|
||||
async def get_collections(self) -> List[str]:
|
||||
async def get_collections(self) -> list[str]:
|
||||
"""Gets the list of collections.
|
||||
|
||||
Returns:
|
||||
@@ -110,8 +109,8 @@ class AstraDBMemoryStore(MemoryStoreBase):
|
||||
async def create_collection(
|
||||
self,
|
||||
collection_name: str,
|
||||
dimension_num: Optional[int] = None,
|
||||
distance_type: Optional[str] = "cosine",
|
||||
dimension_num: int | None = None,
|
||||
distance_type: str | None = "cosine",
|
||||
) -> None:
|
||||
"""Creates a new collection in Astra if it does not exist.
|
||||
|
||||
@@ -179,7 +178,7 @@ class AstraDBMemoryStore(MemoryStoreBase):
|
||||
|
||||
return status["upsertedId"] if "upsertedId" in status else record._id
|
||||
|
||||
async def upsert_batch(self, collection_name: str, records: List[MemoryRecord]) -> List[str]:
|
||||
async def upsert_batch(self, collection_name: str, records: list[MemoryRecord]) -> list[str]:
|
||||
"""Upserts a batch of memory records into the data store. Does not guarantee that the collection exists.
|
||||
If the record already exists, it will be updated.
|
||||
If the record does not exist, it will be created.
|
||||
@@ -217,8 +216,8 @@ class AstraDBMemoryStore(MemoryStoreBase):
|
||||
return parse_payload(documents[0])
|
||||
|
||||
async def get_batch(
|
||||
self, collection_name: str, keys: List[str], with_embeddings: bool = False
|
||||
) -> List[MemoryRecord]:
|
||||
self, collection_name: str, keys: list[str], with_embeddings: bool = False
|
||||
) -> list[MemoryRecord]:
|
||||
"""Gets a batch of records. Does not guarantee that the collection exists.
|
||||
|
||||
Arguments:
|
||||
@@ -251,7 +250,7 @@ class AstraDBMemoryStore(MemoryStoreBase):
|
||||
filter = {"_id": key}
|
||||
await self._client.delete_documents(collection_name, filter)
|
||||
|
||||
async def remove_batch(self, collection_name: str, keys: List[str]) -> None:
|
||||
async def remove_batch(self, collection_name: str, keys: list[str]) -> None:
|
||||
"""Removes a batch of records. Does not guarantee that the collection exists.
|
||||
|
||||
Arguments:
|
||||
@@ -270,7 +269,7 @@ class AstraDBMemoryStore(MemoryStoreBase):
|
||||
embedding: ndarray,
|
||||
min_relevance_score: float = 0.0,
|
||||
with_embedding: bool = False,
|
||||
) -> Tuple[MemoryRecord, float]:
|
||||
) -> tuple[MemoryRecord, float]:
|
||||
"""Gets the nearest match to an embedding using cosine similarity.
|
||||
Arguments:
|
||||
collection_name {str} -- The name of the collection to get the nearest matches from.
|
||||
@@ -297,7 +296,7 @@ class AstraDBMemoryStore(MemoryStoreBase):
|
||||
limit: int,
|
||||
min_relevance_score: float = 0.0,
|
||||
with_embeddings: bool = False,
|
||||
) -> List[Tuple[MemoryRecord, float]]:
|
||||
) -> list[tuple[MemoryRecord, float]]:
|
||||
"""Gets the nearest matches to an embedding using cosine similarity.
|
||||
Arguments:
|
||||
collection_name {str} -- The name of the collection to get the nearest matches from.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from typing import Any, Dict
|
||||
from typing import Any
|
||||
|
||||
import aiohttp
|
||||
import numpy
|
||||
@@ -18,11 +18,11 @@ class AsyncSession:
|
||||
await self._session.close()
|
||||
|
||||
|
||||
def build_payload(record: MemoryRecord) -> Dict[str, Any]:
|
||||
def build_payload(record: MemoryRecord) -> dict[str, Any]:
|
||||
"""
|
||||
Builds a metadata payload to be sent to AstraDb from a MemoryRecord.
|
||||
"""
|
||||
payload: Dict[str, Any] = {}
|
||||
payload: dict[str, Any] = {}
|
||||
payload["$vector"] = record.embedding.tolist()
|
||||
if record._text:
|
||||
payload["text"] = record._text
|
||||
@@ -33,7 +33,7 @@ def build_payload(record: MemoryRecord) -> Dict[str, Any]:
|
||||
return payload
|
||||
|
||||
|
||||
def parse_payload(document: Dict[str, Any]) -> MemoryRecord:
|
||||
def parse_payload(document: dict[str, Any]) -> MemoryRecord:
|
||||
"""
|
||||
Parses a record from AstraDb into a MemoryRecord.
|
||||
"""
|
||||
|
||||
+9
-10
@@ -3,7 +3,6 @@
|
||||
import logging
|
||||
import uuid
|
||||
from inspect import isawaitable
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
from azure.core.credentials import AzureKeyCredential, TokenCredential
|
||||
from azure.core.exceptions import ResourceNotFoundError
|
||||
@@ -101,8 +100,8 @@ class AzureCognitiveSearchMemoryStore(MemoryStoreBase):
|
||||
async def create_collection(
|
||||
self,
|
||||
collection_name: str,
|
||||
vector_config: Optional[HnswAlgorithmConfiguration] = None,
|
||||
search_resource_encryption_key: Optional[SearchResourceEncryptionKey] = None,
|
||||
vector_config: HnswAlgorithmConfiguration | None = None,
|
||||
search_resource_encryption_key: SearchResourceEncryptionKey | None = None,
|
||||
) -> None:
|
||||
"""Creates a new collection if it does not exist.
|
||||
|
||||
@@ -166,7 +165,7 @@ class AzureCognitiveSearchMemoryStore(MemoryStoreBase):
|
||||
|
||||
await self._search_index_client.create_index(index)
|
||||
|
||||
async def get_collections(self) -> List[str]:
|
||||
async def get_collections(self) -> list[str]:
|
||||
"""Gets the list of collections.
|
||||
|
||||
Returns:
|
||||
@@ -230,7 +229,7 @@ class AzureCognitiveSearchMemoryStore(MemoryStoreBase):
|
||||
return result[0]
|
||||
return None
|
||||
|
||||
async def upsert_batch(self, collection_name: str, records: List[MemoryRecord]) -> List[str]:
|
||||
async def upsert_batch(self, collection_name: str, records: list[MemoryRecord]) -> list[str]:
|
||||
"""Upsert a batch of records.
|
||||
|
||||
Arguments:
|
||||
@@ -296,8 +295,8 @@ class AzureCognitiveSearchMemoryStore(MemoryStoreBase):
|
||||
return dict_to_memory_record(search_result, with_embedding)
|
||||
|
||||
async def get_batch(
|
||||
self, collection_name: str, keys: List[str], with_embeddings: bool = False
|
||||
) -> List[MemoryRecord]:
|
||||
self, collection_name: str, keys: list[str], with_embeddings: bool = False
|
||||
) -> list[MemoryRecord]:
|
||||
"""Gets a batch of records.
|
||||
|
||||
Arguments:
|
||||
@@ -321,7 +320,7 @@ class AzureCognitiveSearchMemoryStore(MemoryStoreBase):
|
||||
|
||||
return search_results
|
||||
|
||||
async def remove_batch(self, collection_name: str, keys: List[str]) -> None:
|
||||
async def remove_batch(self, collection_name: str, keys: list[str]) -> None:
|
||||
"""Removes a batch of records.
|
||||
|
||||
Arguments:
|
||||
@@ -359,7 +358,7 @@ class AzureCognitiveSearchMemoryStore(MemoryStoreBase):
|
||||
embedding: ndarray,
|
||||
min_relevance_score: float = 0.0,
|
||||
with_embedding: bool = False,
|
||||
) -> Tuple[MemoryRecord, float]:
|
||||
) -> tuple[MemoryRecord, float]:
|
||||
"""Gets the nearest match to an embedding using vector configuration parameters.
|
||||
|
||||
Arguments:
|
||||
@@ -392,7 +391,7 @@ class AzureCognitiveSearchMemoryStore(MemoryStoreBase):
|
||||
limit: int,
|
||||
min_relevance_score: float = 0.0,
|
||||
with_embeddings: bool = False,
|
||||
) -> List[Tuple[MemoryRecord, float]]:
|
||||
) -> list[tuple[MemoryRecord, float]]:
|
||||
"""Gets the nearest matches to an embedding using vector configuration.
|
||||
|
||||
Parameters:
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import base64
|
||||
import os
|
||||
from typing import List, Optional
|
||||
|
||||
from azure.core.credentials import AzureKeyCredential, TokenCredential
|
||||
from azure.search.documents.indexes.aio import SearchIndexClient
|
||||
@@ -23,10 +22,10 @@ SEARCH_FIELD_IS_REF = "IsReference"
|
||||
|
||||
|
||||
def get_search_index_async_client(
|
||||
search_endpoint: Optional[str] = None,
|
||||
admin_key: Optional[str] = None,
|
||||
azure_credential: Optional[AzureKeyCredential] = None,
|
||||
token_credential: Optional[TokenCredential] = None,
|
||||
search_endpoint: str | None = None,
|
||||
admin_key: str | None = None,
|
||||
azure_credential: AzureKeyCredential | None = None,
|
||||
token_credential: TokenCredential | None = None,
|
||||
):
|
||||
"""Return a client for Azure Cognitive Search.
|
||||
|
||||
@@ -147,7 +146,7 @@ def get_index_schema(vector_size: int, vector_search_profile_name: str) -> list:
|
||||
return search_fields
|
||||
|
||||
|
||||
def get_field_selection(with_embeddings: bool) -> List[str]:
|
||||
def get_field_selection(with_embeddings: bool) -> list[str]:
|
||||
"""Get the list of fields to search and load.
|
||||
|
||||
Arguments:
|
||||
|
||||
+16
-17
@@ -1,7 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from typing import List, Tuple
|
||||
|
||||
from numpy import ndarray
|
||||
from pydantic import ValidationError
|
||||
@@ -150,7 +149,7 @@ class AzureCosmosDBMemoryStore(MemoryStoreBase):
|
||||
"""
|
||||
return await self.cosmosStore.create_collection(collection_name)
|
||||
|
||||
async def get_collections(self) -> List[str]:
|
||||
async def get_collections(self) -> list[str]:
|
||||
"""Gets the list of collections.
|
||||
|
||||
Returns:
|
||||
@@ -167,7 +166,7 @@ class AzureCosmosDBMemoryStore(MemoryStoreBase):
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
return await self.cosmosStore.delete_collection(str())
|
||||
return await self.cosmosStore.delete_collection("")
|
||||
|
||||
async def does_collection_exist(self, collection_name: str) -> bool:
|
||||
"""Checks if a collection exists.
|
||||
@@ -178,7 +177,7 @@ class AzureCosmosDBMemoryStore(MemoryStoreBase):
|
||||
Returns:
|
||||
bool -- True if the collection exists; otherwise, False.
|
||||
"""
|
||||
return await self.cosmosStore.does_collection_exist(str())
|
||||
return await self.cosmosStore.does_collection_exist("")
|
||||
|
||||
async def upsert(self, collection_name: str, record: MemoryRecord) -> str:
|
||||
"""Upsert a record.
|
||||
@@ -190,9 +189,9 @@ class AzureCosmosDBMemoryStore(MemoryStoreBase):
|
||||
Returns:
|
||||
str -- The unique record id of the record.
|
||||
"""
|
||||
return await self.cosmosStore.upsert(str(), record)
|
||||
return await self.cosmosStore.upsert("", record)
|
||||
|
||||
async def upsert_batch(self, collection_name: str, records: List[MemoryRecord]) -> List[str]:
|
||||
async def upsert_batch(self, collection_name: str, records: list[MemoryRecord]) -> list[str]:
|
||||
"""Upsert a batch of records.
|
||||
|
||||
Arguments:
|
||||
@@ -202,7 +201,7 @@ class AzureCosmosDBMemoryStore(MemoryStoreBase):
|
||||
Returns:
|
||||
List[str] -- The unique database keys of the records.
|
||||
"""
|
||||
return await self.cosmosStore.upsert_batch(str(), records)
|
||||
return await self.cosmosStore.upsert_batch("", records)
|
||||
|
||||
async def get(self, collection_name: str, key: str, with_embedding: bool) -> MemoryRecord:
|
||||
"""Gets a record.
|
||||
@@ -215,9 +214,9 @@ class AzureCosmosDBMemoryStore(MemoryStoreBase):
|
||||
Returns:
|
||||
MemoryRecord -- The record.
|
||||
"""
|
||||
return await self.cosmosStore.get(str(), key, with_embedding)
|
||||
return await self.cosmosStore.get("", key, with_embedding)
|
||||
|
||||
async def get_batch(self, collection_name: str, keys: List[str], with_embeddings: bool) -> List[MemoryRecord]:
|
||||
async def get_batch(self, collection_name: str, keys: list[str], with_embeddings: bool) -> list[MemoryRecord]:
|
||||
"""Gets a batch of records.
|
||||
|
||||
Arguments:
|
||||
@@ -228,7 +227,7 @@ class AzureCosmosDBMemoryStore(MemoryStoreBase):
|
||||
Returns:
|
||||
List[MemoryRecord] -- The records.
|
||||
"""
|
||||
return await self.cosmosStore.get_batch(str(), keys, with_embeddings)
|
||||
return await self.cosmosStore.get_batch("", keys, with_embeddings)
|
||||
|
||||
async def remove(self, collection_name: str, key: str) -> None:
|
||||
"""Removes a record.
|
||||
@@ -240,9 +239,9 @@ class AzureCosmosDBMemoryStore(MemoryStoreBase):
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
return await self.cosmosStore.remove(str(), key)
|
||||
return await self.cosmosStore.remove("", key)
|
||||
|
||||
async def remove_batch(self, collection_name: str, keys: List[str]) -> None:
|
||||
async def remove_batch(self, collection_name: str, keys: list[str]) -> None:
|
||||
"""Removes a batch of records.
|
||||
|
||||
Arguments:
|
||||
@@ -252,7 +251,7 @@ class AzureCosmosDBMemoryStore(MemoryStoreBase):
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
return await self.cosmosStore.remove_batch(str(), keys)
|
||||
return await self.cosmosStore.remove_batch("", keys)
|
||||
|
||||
async def get_nearest_matches(
|
||||
self,
|
||||
@@ -261,7 +260,7 @@ class AzureCosmosDBMemoryStore(MemoryStoreBase):
|
||||
limit: int,
|
||||
min_relevance_score: float,
|
||||
with_embeddings: bool,
|
||||
) -> List[Tuple[MemoryRecord, float]]:
|
||||
) -> list[tuple[MemoryRecord, float]]:
|
||||
"""Gets the nearest matches to an embedding using vector configuration.
|
||||
|
||||
Parameters:
|
||||
@@ -274,7 +273,7 @@ class AzureCosmosDBMemoryStore(MemoryStoreBase):
|
||||
Returns:
|
||||
List[Tuple[MemoryRecord, float]] -- The records and their relevance scores.
|
||||
"""
|
||||
return await self.cosmosStore.get_nearest_matches(str(), embedding, limit, min_relevance_score, with_embeddings)
|
||||
return await self.cosmosStore.get_nearest_matches("", embedding, limit, min_relevance_score, with_embeddings)
|
||||
|
||||
async def get_nearest_match(
|
||||
self,
|
||||
@@ -282,7 +281,7 @@ class AzureCosmosDBMemoryStore(MemoryStoreBase):
|
||||
embedding: ndarray,
|
||||
min_relevance_score: float,
|
||||
with_embedding: bool,
|
||||
) -> Tuple[MemoryRecord, float]:
|
||||
) -> tuple[MemoryRecord, float]:
|
||||
"""Gets the nearest match to an embedding using vector configuration parameters.
|
||||
|
||||
Arguments:
|
||||
@@ -294,4 +293,4 @@ class AzureCosmosDBMemoryStore(MemoryStoreBase):
|
||||
Returns:
|
||||
Tuple[MemoryRecord, float] -- The record and the relevance score.
|
||||
"""
|
||||
return await self.cosmosStore.get_nearest_match(str(), embedding, min_relevance_score, with_embedding)
|
||||
return await self.cosmosStore.get_nearest_match("", embedding, min_relevance_score, with_embedding)
|
||||
|
||||
+6
-7
@@ -2,7 +2,6 @@
|
||||
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import List, Tuple
|
||||
|
||||
from numpy import ndarray
|
||||
|
||||
@@ -18,7 +17,7 @@ class AzureCosmosDBStoreApi(ABC):
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
async def get_collections(self) -> List[str]:
|
||||
async def get_collections(self) -> list[str]:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
@@ -34,7 +33,7 @@ class AzureCosmosDBStoreApi(ABC):
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
async def upsert_batch(self, collection_name: str, records: List[MemoryRecord]) -> List[str]:
|
||||
async def upsert_batch(self, collection_name: str, records: list[MemoryRecord]) -> list[str]:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
@@ -42,7 +41,7 @@ class AzureCosmosDBStoreApi(ABC):
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
async def get_batch(self, collection_name: str, keys: List[str], with_embeddings: bool) -> List[MemoryRecord]:
|
||||
async def get_batch(self, collection_name: str, keys: list[str], with_embeddings: bool) -> list[MemoryRecord]:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
@@ -50,7 +49,7 @@ class AzureCosmosDBStoreApi(ABC):
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
async def remove_batch(self, collection_name: str, keys: List[str]) -> None:
|
||||
async def remove_batch(self, collection_name: str, keys: list[str]) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
@@ -61,7 +60,7 @@ class AzureCosmosDBStoreApi(ABC):
|
||||
limit: int,
|
||||
min_relevance_score: float,
|
||||
with_embeddings: bool,
|
||||
) -> List[Tuple[MemoryRecord, float]]:
|
||||
) -> list[tuple[MemoryRecord, float]]:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
@@ -71,5 +70,5 @@ class AzureCosmosDBStoreApi(ABC):
|
||||
embedding: ndarray,
|
||||
min_relevance_score: float,
|
||||
with_embedding: bool,
|
||||
) -> Tuple[MemoryRecord, float]:
|
||||
) -> tuple[MemoryRecord, float]:
|
||||
raise NotImplementedError
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import json
|
||||
from typing import Any, Dict, List, Tuple
|
||||
from typing import Any
|
||||
|
||||
import numpy as np
|
||||
|
||||
@@ -117,7 +117,7 @@ class MongoStoreApi(AzureCosmosDBStoreApi):
|
||||
|
||||
def _get_vector_index_ivf(
|
||||
self, collection_name: str, kind: str, num_lists: int, similarity: str, dimensions: int
|
||||
) -> Dict[str, Any]:
|
||||
) -> dict[str, Any]:
|
||||
command = {
|
||||
"createIndexes": collection_name,
|
||||
"indexes": [
|
||||
@@ -137,7 +137,7 @@ class MongoStoreApi(AzureCosmosDBStoreApi):
|
||||
|
||||
def _get_vector_index_hnsw(
|
||||
self, collection_name: str, kind: str, m: int, ef_construction: int, similarity: str, dimensions: int
|
||||
) -> Dict[str, Any]:
|
||||
) -> dict[str, Any]:
|
||||
command = {
|
||||
"createIndexes": collection_name,
|
||||
"indexes": [
|
||||
@@ -156,7 +156,7 @@ class MongoStoreApi(AzureCosmosDBStoreApi):
|
||||
}
|
||||
return command
|
||||
|
||||
async def get_collections(self) -> List[str]:
|
||||
async def get_collections(self) -> list[str]:
|
||||
return self.database.list_collection_names()
|
||||
|
||||
async def delete_collection(self, collection_name: str) -> None:
|
||||
@@ -169,9 +169,9 @@ class MongoStoreApi(AzureCosmosDBStoreApi):
|
||||
result = await self.upsert_batch(collection_name, [record])
|
||||
return result[0]
|
||||
|
||||
async def upsert_batch(self, collection_name: str, records: List[MemoryRecord]) -> List[str]:
|
||||
doc_ids: List[str] = []
|
||||
cosmosRecords: List[dict] = []
|
||||
async def upsert_batch(self, collection_name: str, records: list[MemoryRecord]) -> list[str]:
|
||||
doc_ids: list[str] = []
|
||||
cosmosRecords: list[dict] = []
|
||||
for record in records:
|
||||
cosmosRecord: dict = {
|
||||
"_id": record.id,
|
||||
@@ -202,7 +202,7 @@ class MongoStoreApi(AzureCosmosDBStoreApi):
|
||||
timestamp=result.get("timestamp", None),
|
||||
)
|
||||
|
||||
async def get_batch(self, collection_name: str, keys: List[str], with_embeddings: bool) -> List[MemoryRecord]:
|
||||
async def get_batch(self, collection_name: str, keys: list[str], with_embeddings: bool) -> list[MemoryRecord]:
|
||||
if not with_embeddings:
|
||||
results = self.collection.find({"_id": {"$in": keys}}, {"embedding": 0})
|
||||
else:
|
||||
@@ -223,7 +223,7 @@ class MongoStoreApi(AzureCosmosDBStoreApi):
|
||||
async def remove(self, collection_name: str, key: str) -> None:
|
||||
self.collection.delete_one({"_id": key})
|
||||
|
||||
async def remove_batch(self, collection_name: str, keys: List[str]) -> None:
|
||||
async def remove_batch(self, collection_name: str, keys: list[str]) -> None:
|
||||
self.collection.delete_many({"_id": {"$in": keys}})
|
||||
|
||||
async def get_nearest_matches(
|
||||
@@ -233,8 +233,8 @@ class MongoStoreApi(AzureCosmosDBStoreApi):
|
||||
limit: int,
|
||||
min_relevance_score: float,
|
||||
with_embeddings: bool,
|
||||
) -> List[Tuple[MemoryRecord, float]]:
|
||||
pipeline: List[dict[str, Any]] = []
|
||||
) -> list[tuple[MemoryRecord, float]]:
|
||||
pipeline: list[dict[str, Any]] = []
|
||||
if self.kind == CosmosDBVectorSearchType.VECTOR_IVF:
|
||||
pipeline = self._get_pipeline_vector_ivf(embedding.tolist(), limit)
|
||||
elif self.kind == CosmosDBVectorSearchType.VECTOR_HNSW:
|
||||
@@ -259,8 +259,8 @@ class MongoStoreApi(AzureCosmosDBStoreApi):
|
||||
nearest_results.append((result, aggResult["similarityScore"]))
|
||||
return nearest_results
|
||||
|
||||
def _get_pipeline_vector_ivf(self, embeddings: List[float], k: int = 4) -> List[dict[str, Any]]:
|
||||
pipeline: List[dict[str, Any]] = [
|
||||
def _get_pipeline_vector_ivf(self, embeddings: list[float], k: int = 4) -> list[dict[str, Any]]:
|
||||
pipeline: list[dict[str, Any]] = [
|
||||
{
|
||||
"$search": {
|
||||
"cosmosSearch": {
|
||||
@@ -281,9 +281,9 @@ class MongoStoreApi(AzureCosmosDBStoreApi):
|
||||
return pipeline
|
||||
|
||||
def _get_pipeline_vector_hnsw(
|
||||
self, embeddings: List[float], k: int = 4, ef_search: int = 40
|
||||
) -> List[dict[str, Any]]:
|
||||
pipeline: List[dict[str, Any]] = [
|
||||
self, embeddings: list[float], k: int = 4, ef_search: int = 40
|
||||
) -> list[dict[str, Any]]:
|
||||
pipeline: list[dict[str, Any]] = [
|
||||
{
|
||||
"$search": {
|
||||
"cosmosSearch": {
|
||||
@@ -309,7 +309,7 @@ class MongoStoreApi(AzureCosmosDBStoreApi):
|
||||
embedding: np.ndarray,
|
||||
min_relevance_score: float,
|
||||
with_embedding: bool,
|
||||
) -> Tuple[MemoryRecord, float]:
|
||||
) -> tuple[MemoryRecord, float]:
|
||||
nearest_results = await self.get_nearest_matches(
|
||||
collection_name=collection_name,
|
||||
embedding=embedding,
|
||||
|
||||
+8
-8
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import json
|
||||
from typing import Any, List, Tuple
|
||||
from typing import Any
|
||||
|
||||
import numpy as np
|
||||
from azure.cosmos.aio import ContainerProxy, CosmosClient, DatabaseProxy
|
||||
@@ -58,7 +58,7 @@ class AzureCosmosDBNoSQLMemoryStore(MemoryStoreBase):
|
||||
vector_embedding_policy=self.vector_embedding_policy,
|
||||
)
|
||||
|
||||
async def get_collections(self) -> List[str]:
|
||||
async def get_collections(self) -> list[str]:
|
||||
return [container["id"] async for container in self.database.list_containers()]
|
||||
|
||||
async def delete_collection(self, collection_name: str) -> None:
|
||||
@@ -71,8 +71,8 @@ class AzureCosmosDBNoSQLMemoryStore(MemoryStoreBase):
|
||||
result = await self.upsert_batch(collection_name, [record])
|
||||
return result[0]
|
||||
|
||||
async def upsert_batch(self, collection_name: str, records: List[MemoryRecord]) -> List[str]:
|
||||
doc_ids: List[str] = []
|
||||
async def upsert_batch(self, collection_name: str, records: list[MemoryRecord]) -> list[str]:
|
||||
doc_ids: list[str] = []
|
||||
for record in records:
|
||||
cosmosRecord: dict = {
|
||||
"id": record.id,
|
||||
@@ -99,7 +99,7 @@ class AzureCosmosDBNoSQLMemoryStore(MemoryStoreBase):
|
||||
timestamp=item.get("timestamp", None),
|
||||
)
|
||||
|
||||
async def get_batch(self, collection_name: str, keys: List[str], with_embeddings: bool) -> List[MemoryRecord]:
|
||||
async def get_batch(self, collection_name: str, keys: list[str], with_embeddings: bool) -> list[MemoryRecord]:
|
||||
query = "SELECT * FROM c WHERE ARRAY_CONTAINS(@ids, c.id)"
|
||||
parameters = [{"name": "@ids", "value": keys}]
|
||||
|
||||
@@ -120,13 +120,13 @@ class AzureCosmosDBNoSQLMemoryStore(MemoryStoreBase):
|
||||
async def remove(self, collection_name: str, key: str) -> None:
|
||||
await self.container.delete_item(key, partition_key=key)
|
||||
|
||||
async def remove_batch(self, collection_name: str, keys: List[str]) -> None:
|
||||
async def remove_batch(self, collection_name: str, keys: list[str]) -> None:
|
||||
for key in keys:
|
||||
await self.container.delete_item(key, partition_key=key)
|
||||
|
||||
async def get_nearest_matches(
|
||||
self, collection_name: str, embedding: ndarray, limit: int, min_relevance_score: float, with_embeddings: bool
|
||||
) -> List[Tuple[MemoryRecord, float]]:
|
||||
) -> list[tuple[MemoryRecord, float]]:
|
||||
embedding_key = self.vector_embedding_policy["vectorEmbeddings"][0]["path"][1:]
|
||||
query = (
|
||||
"SELECT TOP {} c.id, c.{}, c.text, c.description, c.metadata, "
|
||||
@@ -155,7 +155,7 @@ class AzureCosmosDBNoSQLMemoryStore(MemoryStoreBase):
|
||||
|
||||
async def get_nearest_match(
|
||||
self, collection_name: str, embedding: ndarray, min_relevance_score: float, with_embedding: bool
|
||||
) -> Tuple[MemoryRecord, float]:
|
||||
) -> tuple[MemoryRecord, float]:
|
||||
nearest_results = await self.get_nearest_matches(
|
||||
collection_name=collection_name,
|
||||
embedding=embedding,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, List, Optional, Tuple
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from numpy import array, ndarray
|
||||
|
||||
@@ -25,7 +25,7 @@ class ChromaMemoryStore(MemoryStoreBase):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
persist_directory: Optional[str] = None,
|
||||
persist_directory: str | None = None,
|
||||
client_settings: Optional["chromadb.config.Settings"] = None,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
@@ -93,7 +93,7 @@ class ChromaMemoryStore(MemoryStoreBase):
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
async def get_collections(self) -> List[str]:
|
||||
async def get_collections(self) -> list[str]:
|
||||
"""Gets the list of collections.
|
||||
|
||||
Returns:
|
||||
@@ -159,7 +159,7 @@ class ChromaMemoryStore(MemoryStoreBase):
|
||||
)
|
||||
return record._key
|
||||
|
||||
async def upsert_batch(self, collection_name: str, records: List[MemoryRecord]) -> List[str]:
|
||||
async def upsert_batch(self, collection_name: str, records: list[MemoryRecord]) -> list[str]:
|
||||
"""Upserts a batch of records.
|
||||
|
||||
Arguments:
|
||||
@@ -191,7 +191,7 @@ class ChromaMemoryStore(MemoryStoreBase):
|
||||
f"Record with key '{key}' does not exist in collection '{collection_name}'"
|
||||
) from exc
|
||||
|
||||
async def get_batch(self, collection_name: str, keys: List[str], with_embeddings: bool) -> List[MemoryRecord]:
|
||||
async def get_batch(self, collection_name: str, keys: list[str], with_embeddings: bool) -> list[MemoryRecord]:
|
||||
"""Gets a batch of records.
|
||||
|
||||
Arguments:
|
||||
@@ -224,7 +224,7 @@ class ChromaMemoryStore(MemoryStoreBase):
|
||||
"""
|
||||
await self.remove_batch(collection_name, [key])
|
||||
|
||||
async def remove_batch(self, collection_name: str, keys: List[str]) -> None:
|
||||
async def remove_batch(self, collection_name: str, keys: list[str]) -> None:
|
||||
"""Removes a batch of records.
|
||||
|
||||
Arguments:
|
||||
@@ -245,7 +245,7 @@ class ChromaMemoryStore(MemoryStoreBase):
|
||||
limit: int,
|
||||
min_relevance_score: float = 0.0,
|
||||
with_embeddings: bool = True,
|
||||
) -> List[Tuple[MemoryRecord, float]]:
|
||||
) -> list[tuple[MemoryRecord, float]]:
|
||||
"""Gets the nearest matches to an embedding using cosine similarity.
|
||||
|
||||
Arguments:
|
||||
@@ -312,7 +312,7 @@ class ChromaMemoryStore(MemoryStoreBase):
|
||||
embedding: ndarray,
|
||||
min_relevance_score: float = 0.0,
|
||||
with_embedding: bool = True,
|
||||
) -> Tuple[MemoryRecord, float]:
|
||||
) -> tuple[MemoryRecord, float]:
|
||||
"""Gets the nearest match to an embedding using cosine similarity.
|
||||
|
||||
Arguments:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, List
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from numpy import array, linalg, ndarray
|
||||
|
||||
@@ -25,7 +25,7 @@ def camel_to_snake(camel_str):
|
||||
return snake_str
|
||||
|
||||
|
||||
def query_results_to_records(results: "QueryResult", with_embedding: bool) -> List[MemoryRecord]:
|
||||
def query_results_to_records(results: "QueryResult", with_embedding: bool) -> list[MemoryRecord]:
|
||||
# if results has only one record, it will be a list instead of a nested list
|
||||
# this is to make sure that results is always a nested list
|
||||
# {'ids': ['test_id1'], 'embeddings': [[...]], 'documents': ['sample text1'], 'metadatas': [{...}]}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
from typing import Any
|
||||
|
||||
from numpy import array, expand_dims, ndarray
|
||||
from pymilvus import Collection, CollectionSchema, DataType, FieldSchema, connections, utility
|
||||
@@ -49,7 +49,7 @@ OUTPUT_FIELDS_WO_EMBEDDING = [
|
||||
|
||||
|
||||
@experimental_function
|
||||
def memoryrecord_to_milvus_dict(mem: MemoryRecord) -> Dict[str, Any]:
|
||||
def memoryrecord_to_milvus_dict(mem: MemoryRecord) -> dict[str, Any]:
|
||||
"""Convert a memoryrecord into a dict.
|
||||
Args:
|
||||
mem (MemoryRecord): MemoryRecord to convert.
|
||||
@@ -69,7 +69,7 @@ def memoryrecord_to_milvus_dict(mem: MemoryRecord) -> Dict[str, Any]:
|
||||
|
||||
|
||||
@experimental_function
|
||||
def milvus_dict_to_memoryrecord(milvus_dict: Dict[str, Any]) -> MemoryRecord:
|
||||
def milvus_dict_to_memoryrecord(milvus_dict: dict[str, Any]) -> MemoryRecord:
|
||||
"""Convert Milvus search result dict into MemoryRecord.
|
||||
|
||||
Args:
|
||||
@@ -96,7 +96,7 @@ def milvus_dict_to_memoryrecord(milvus_dict: Dict[str, Any]) -> MemoryRecord:
|
||||
|
||||
|
||||
@experimental_function
|
||||
def create_fields(dimensions: int) -> List[FieldSchema]:
|
||||
def create_fields(dimensions: int) -> list[FieldSchema]:
|
||||
return [
|
||||
FieldSchema(
|
||||
name=SEARCH_FIELD_ID,
|
||||
@@ -147,7 +147,7 @@ class MilvusMemoryStore(MemoryStoreBase):
|
||||
def __init__(
|
||||
self,
|
||||
uri: str = "http://localhost:19530",
|
||||
token: Optional[str] = None,
|
||||
token: str | None = None,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""MilvusMemoryStore allows for searching for records using Milvus/Zilliz Cloud.
|
||||
@@ -164,13 +164,13 @@ class MilvusMemoryStore(MemoryStoreBase):
|
||||
authentication is required. Defaults to None.
|
||||
"""
|
||||
connections.connect("default", uri=uri, token=token)
|
||||
self.collections: Dict[str, Collection] = {}
|
||||
self.collections: dict[str, Collection] = {}
|
||||
|
||||
async def create_collection(
|
||||
self,
|
||||
collection_name: str,
|
||||
dimension_num: int = 1536,
|
||||
distance_type: Optional[str] = "IP",
|
||||
distance_type: str | None = "IP",
|
||||
overwrite: bool = False,
|
||||
consistency: str = "Session",
|
||||
) -> None:
|
||||
@@ -203,7 +203,7 @@ class MilvusMemoryStore(MemoryStoreBase):
|
||||
|
||||
async def get_collections(
|
||||
self,
|
||||
) -> List[str]:
|
||||
) -> list[str]:
|
||||
"""Return a list of present collections.
|
||||
|
||||
Returns:
|
||||
@@ -211,7 +211,7 @@ class MilvusMemoryStore(MemoryStoreBase):
|
||||
"""
|
||||
return utility.list_collections()
|
||||
|
||||
async def delete_collection(self, collection_name: Optional[str] = None, all: bool = False) -> None:
|
||||
async def delete_collection(self, collection_name: str | None = None, all: bool = False) -> None:
|
||||
"""Delete the specified collection.
|
||||
|
||||
If all is True, all collections in the cluster will be removed.
|
||||
@@ -258,7 +258,7 @@ class MilvusMemoryStore(MemoryStoreBase):
|
||||
)
|
||||
return res[0]
|
||||
|
||||
async def upsert_batch(self, collection_name: str, records: List[MemoryRecord], batch_size=100) -> List[str]:
|
||||
async def upsert_batch(self, collection_name: str, records: list[MemoryRecord], batch_size=100) -> list[str]:
|
||||
"""_summary_
|
||||
|
||||
Args:
|
||||
@@ -302,7 +302,7 @@ class MilvusMemoryStore(MemoryStoreBase):
|
||||
res = await self.get_batch(collection_name=collection_name, keys=[key], with_embeddings=with_embedding)
|
||||
return res[0]
|
||||
|
||||
async def get_batch(self, collection_name: str, keys: List[str], with_embeddings: bool) -> List[MemoryRecord]:
|
||||
async def get_batch(self, collection_name: str, keys: list[str], with_embeddings: bool) -> list[MemoryRecord]:
|
||||
"""Get the MemoryRecords corresponding to the keys
|
||||
|
||||
Args:
|
||||
@@ -342,7 +342,7 @@ class MilvusMemoryStore(MemoryStoreBase):
|
||||
"""
|
||||
await self.remove_batch(collection_name=collection_name, keys=[key])
|
||||
|
||||
async def remove_batch(self, collection_name: str, keys: List[str]) -> None:
|
||||
async def remove_batch(self, collection_name: str, keys: list[str]) -> None:
|
||||
"""Remove multiple records based on keys.
|
||||
|
||||
Args:
|
||||
@@ -378,7 +378,7 @@ class MilvusMemoryStore(MemoryStoreBase):
|
||||
limit: int,
|
||||
min_relevance_score: float = 0.0,
|
||||
with_embeddings: bool = False,
|
||||
) -> List[Tuple[MemoryRecord, float]]:
|
||||
) -> list[tuple[MemoryRecord, float]]:
|
||||
"""Find the nearest `limit` matches for an embedding.
|
||||
|
||||
Args:
|
||||
@@ -429,7 +429,7 @@ class MilvusMemoryStore(MemoryStoreBase):
|
||||
embedding: ndarray,
|
||||
min_relevance_score: float = 0.0,
|
||||
with_embedding: bool = False,
|
||||
) -> Tuple[MemoryRecord, float]:
|
||||
) -> tuple[MemoryRecord, float]:
|
||||
"""Find the nearest match for an embedding.
|
||||
|
||||
Args:
|
||||
|
||||
+12
-12
@@ -1,9 +1,9 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from collections.abc import Mapping
|
||||
from importlib import metadata
|
||||
from typing import Any, List, Mapping, Tuple
|
||||
from typing import Any
|
||||
|
||||
from motor import core, motor_asyncio
|
||||
from numpy import ndarray
|
||||
@@ -104,7 +104,7 @@ class MongoDBAtlasMemoryStore(MemoryStoreBase):
|
||||
|
||||
async def get_collections(
|
||||
self,
|
||||
) -> List[str]:
|
||||
) -> list[str]:
|
||||
"""Gets all collection names in the data store.
|
||||
|
||||
Returns:
|
||||
@@ -156,7 +156,7 @@ class MongoDBAtlasMemoryStore(MemoryStoreBase):
|
||||
assert update_result.acknowledged
|
||||
return record._id
|
||||
|
||||
async def upsert_batch(self, collection_name: str, records: List[MemoryRecord]) -> List[str]:
|
||||
async def upsert_batch(self, collection_name: str, records: list[MemoryRecord]) -> list[str]:
|
||||
"""Upserts a group of memory records into the data store. Does not guarantee that the collection exists.
|
||||
If the record already exists, it will be updated.
|
||||
If the record does not exist, it will be created.
|
||||
@@ -169,7 +169,7 @@ class MongoDBAtlasMemoryStore(MemoryStoreBase):
|
||||
List[str] -- The unique identifiers for the memory records.
|
||||
"""
|
||||
|
||||
upserts: List[UpdateOne] = []
|
||||
upserts: list[UpdateOne] = []
|
||||
for record in records:
|
||||
document = memory_record_to_mongo_document(record)
|
||||
upserts.append(UpdateOne(document, {"$set": document}, upsert=True))
|
||||
@@ -201,7 +201,7 @@ class MongoDBAtlasMemoryStore(MemoryStoreBase):
|
||||
|
||||
return document_to_memory_record(document, with_embedding) if document else None
|
||||
|
||||
async def get_batch(self, collection_name: str, keys: List[str], with_embeddings: bool) -> List[MemoryRecord]:
|
||||
async def get_batch(self, collection_name: str, keys: list[str], with_embeddings: bool) -> list[MemoryRecord]:
|
||||
"""Gets a batch of memory records from the data store. Does not guarantee that the collection exists.
|
||||
|
||||
Arguments:
|
||||
@@ -232,7 +232,7 @@ class MongoDBAtlasMemoryStore(MemoryStoreBase):
|
||||
raise ServiceResourceNotFoundError(f"collection {collection_name} not found")
|
||||
await self.database[collection_name].delete_one({MONGODB_FIELD_ID: key})
|
||||
|
||||
async def remove_batch(self, collection_name: str, keys: List[str]) -> None:
|
||||
async def remove_batch(self, collection_name: str, keys: list[str]) -> None:
|
||||
"""Removes a batch of memory records from the data store. Does not guarantee that the collection exists.
|
||||
|
||||
Arguments:
|
||||
@@ -244,7 +244,7 @@ class MongoDBAtlasMemoryStore(MemoryStoreBase):
|
||||
"""
|
||||
if not await self.does_collection_exist(collection_name):
|
||||
raise ServiceResourceNotFoundError(f"collection {collection_name} not found")
|
||||
deletes: List[DeleteOne] = [DeleteOne({MONGODB_FIELD_ID: key}) for key in keys]
|
||||
deletes: list[DeleteOne] = [DeleteOne({MONGODB_FIELD_ID: key}) for key in keys]
|
||||
bulk_write_result = await self.database[collection_name].bulk_write(deletes, ordered=False)
|
||||
logger.debug("%s entries deleted", bulk_write_result.deleted_count)
|
||||
|
||||
@@ -255,7 +255,7 @@ class MongoDBAtlasMemoryStore(MemoryStoreBase):
|
||||
limit: int,
|
||||
with_embeddings: bool,
|
||||
min_relevance_score: float | None = None,
|
||||
) -> List[Tuple[MemoryRecord, float]]:
|
||||
) -> list[tuple[MemoryRecord, float]]:
|
||||
"""Gets the nearest matches to an embedding of type float. Does not guarantee that the collection exists.
|
||||
|
||||
Arguments:
|
||||
@@ -269,7 +269,7 @@ class MongoDBAtlasMemoryStore(MemoryStoreBase):
|
||||
is its similarity score as a float.
|
||||
"""
|
||||
pipeline: list[dict[str, Any]] = []
|
||||
vector_search_query: List[Mapping[str, Any]] = {
|
||||
vector_search_query: list[Mapping[str, Any]] = {
|
||||
"$vectorSearch": {
|
||||
"queryVector": embedding.tolist(),
|
||||
"limit": limit,
|
||||
@@ -302,7 +302,7 @@ class MongoDBAtlasMemoryStore(MemoryStoreBase):
|
||||
embedding: ndarray,
|
||||
with_embedding: bool,
|
||||
min_relevance_score: float | None = None,
|
||||
) -> Tuple[MemoryRecord, float]:
|
||||
) -> tuple[MemoryRecord, float]:
|
||||
"""Gets the nearest match to an embedding of type float. Does not guarantee that the collection exists.
|
||||
|
||||
Arguments:
|
||||
@@ -314,7 +314,7 @@ class MongoDBAtlasMemoryStore(MemoryStoreBase):
|
||||
Returns:
|
||||
Tuple[MemoryRecord, float] -- A tuple consisting of the MemoryRecord and the similarity score as a float.
|
||||
"""
|
||||
matches: List[Tuple[MemoryRecord, float]] = await self.get_nearest_matches(
|
||||
matches: list[tuple[MemoryRecord, float]] = await self.get_nearest_matches(
|
||||
collection_name=collection_name,
|
||||
embedding=embedding,
|
||||
limit=1,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
from numpy import array
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from typing import List, NamedTuple, Optional, Tuple
|
||||
from typing import NamedTuple
|
||||
|
||||
from numpy import ndarray
|
||||
from pinecone import FetchResponse, IndexDescription, IndexList, Pinecone, ServerlessSpec
|
||||
@@ -85,8 +85,8 @@ class PineconeMemoryStore(MemoryStoreBase):
|
||||
async def create_collection(
|
||||
self,
|
||||
collection_name: str,
|
||||
dimension_num: Optional[int] = None,
|
||||
distance_type: Optional[str] = "cosine",
|
||||
dimension_num: int | None = None,
|
||||
distance_type: str | None = "cosine",
|
||||
index_spec: NamedTuple = DEFAULT_INDEX_SPEC,
|
||||
) -> None:
|
||||
"""Creates a new collection in Pinecone if it does not exist.
|
||||
@@ -114,7 +114,7 @@ class PineconeMemoryStore(MemoryStoreBase):
|
||||
)
|
||||
self.collection_names_cache.add(collection_name)
|
||||
|
||||
async def describe_collection(self, collection_name: str) -> Optional[IndexDescription]:
|
||||
async def describe_collection(self, collection_name: str) -> IndexDescription | None:
|
||||
"""Gets the description of the index.
|
||||
Arguments:
|
||||
collection_name {str} -- The name of the index to get.
|
||||
@@ -190,7 +190,7 @@ class PineconeMemoryStore(MemoryStoreBase):
|
||||
|
||||
return record._id
|
||||
|
||||
async def upsert_batch(self, collection_name: str, records: List[MemoryRecord]) -> List[str]:
|
||||
async def upsert_batch(self, collection_name: str, records: list[MemoryRecord]) -> list[str]:
|
||||
"""Upserts a batch of records.
|
||||
|
||||
Arguments:
|
||||
@@ -244,8 +244,8 @@ class PineconeMemoryStore(MemoryStoreBase):
|
||||
return parse_payload(fetch_response.vectors[key], with_embedding)
|
||||
|
||||
async def get_batch(
|
||||
self, collection_name: str, keys: List[str], with_embeddings: bool = False
|
||||
) -> List[MemoryRecord]:
|
||||
self, collection_name: str, keys: list[str], with_embeddings: bool = False
|
||||
) -> list[MemoryRecord]:
|
||||
"""Gets a batch of records.
|
||||
|
||||
Arguments:
|
||||
@@ -278,7 +278,7 @@ class PineconeMemoryStore(MemoryStoreBase):
|
||||
collection = self.pinecone.Index(collection_name)
|
||||
collection.delete([key])
|
||||
|
||||
async def remove_batch(self, collection_name: str, keys: List[str]) -> None:
|
||||
async def remove_batch(self, collection_name: str, keys: list[str]) -> None:
|
||||
"""Removes a batch of records.
|
||||
|
||||
Arguments:
|
||||
@@ -302,7 +302,7 @@ class PineconeMemoryStore(MemoryStoreBase):
|
||||
embedding: ndarray,
|
||||
min_relevance_score: float = 0.0,
|
||||
with_embedding: bool = False,
|
||||
) -> Tuple[MemoryRecord, float]:
|
||||
) -> tuple[MemoryRecord, float]:
|
||||
"""Gets the nearest match to an embedding using cosine similarity.
|
||||
|
||||
Arguments:
|
||||
@@ -330,7 +330,7 @@ class PineconeMemoryStore(MemoryStoreBase):
|
||||
limit: int,
|
||||
min_relevance_score: float = 0.0,
|
||||
with_embeddings: bool = False,
|
||||
) -> List[Tuple[MemoryRecord, float]]:
|
||||
) -> list[tuple[MemoryRecord, float]]:
|
||||
"""Gets the nearest matches to an embedding using cosine similarity.
|
||||
|
||||
Arguments:
|
||||
@@ -388,7 +388,7 @@ class PineconeMemoryStore(MemoryStoreBase):
|
||||
)
|
||||
|
||||
async def __get_batch(
|
||||
self, collection_name: str, keys: List[str], with_embeddings: bool = False
|
||||
self, collection_name: str, keys: list[str], with_embeddings: bool = False
|
||||
) -> "FetchResponse":
|
||||
index = self.pinecone.Index(collection_name)
|
||||
if len(keys) > MAX_FETCH_BATCH_SIZE:
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import atexit
|
||||
import json
|
||||
import logging
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
import numpy as np
|
||||
from numpy import ndarray
|
||||
@@ -83,7 +82,7 @@ class PostgresMemoryStore(MemoryStoreBase):
|
||||
async def create_collection(
|
||||
self,
|
||||
collection_name: str,
|
||||
dimension_num: Optional[int] = None,
|
||||
dimension_num: int | None = None,
|
||||
) -> None:
|
||||
"""Creates a new collection.
|
||||
|
||||
@@ -119,7 +118,7 @@ class PostgresMemoryStore(MemoryStoreBase):
|
||||
(),
|
||||
)
|
||||
|
||||
async def get_collections(self) -> List[str]:
|
||||
async def get_collections(self) -> list[str]:
|
||||
"""Gets the list of collections.
|
||||
|
||||
Returns:
|
||||
@@ -200,7 +199,7 @@ class PostgresMemoryStore(MemoryStoreBase):
|
||||
raise ServiceResponseException("Upsert failed")
|
||||
return result[0]
|
||||
|
||||
async def upsert_batch(self, collection_name: str, records: List[MemoryRecord]) -> List[str]:
|
||||
async def upsert_batch(self, collection_name: str, records: list[MemoryRecord]) -> list[str]:
|
||||
"""Upserts a batch of records.
|
||||
|
||||
Arguments:
|
||||
@@ -293,8 +292,8 @@ class PostgresMemoryStore(MemoryStoreBase):
|
||||
)
|
||||
|
||||
async def get_batch(
|
||||
self, collection_name: str, keys: List[str], with_embeddings: bool = False
|
||||
) -> List[MemoryRecord]:
|
||||
self, collection_name: str, keys: list[str], with_embeddings: bool = False
|
||||
) -> list[MemoryRecord]:
|
||||
"""Gets a batch of records.
|
||||
|
||||
Arguments:
|
||||
@@ -363,7 +362,7 @@ class PostgresMemoryStore(MemoryStoreBase):
|
||||
(key,),
|
||||
)
|
||||
|
||||
async def remove_batch(self, collection_name: str, keys: List[str]) -> None:
|
||||
async def remove_batch(self, collection_name: str, keys: list[str]) -> None:
|
||||
"""Removes a batch of records.
|
||||
|
||||
Arguments:
|
||||
@@ -394,7 +393,7 @@ class PostgresMemoryStore(MemoryStoreBase):
|
||||
limit: int,
|
||||
min_relevance_score: float = 0.0,
|
||||
with_embeddings: bool = False,
|
||||
) -> List[Tuple[MemoryRecord, float]]:
|
||||
) -> list[tuple[MemoryRecord, float]]:
|
||||
"""Gets the nearest matches to an embedding using cosine similarity.
|
||||
|
||||
Arguments:
|
||||
@@ -463,7 +462,7 @@ class PostgresMemoryStore(MemoryStoreBase):
|
||||
embedding: ndarray,
|
||||
min_relevance_score: float = 0.0,
|
||||
with_embedding: bool = False,
|
||||
) -> Tuple[MemoryRecord, float]:
|
||||
) -> tuple[MemoryRecord, float]:
|
||||
"""Gets the nearest match to an embedding using cosine similarity.
|
||||
|
||||
Arguments:
|
||||
@@ -491,7 +490,7 @@ class PostgresMemoryStore(MemoryStoreBase):
|
||||
results = await self.__get_collections(cur)
|
||||
return collection_name in results
|
||||
|
||||
async def __get_collections(self, cur: Cursor) -> List[str]:
|
||||
async def __get_collections(self, cur: Cursor) -> list[str]:
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT table_name
|
||||
|
||||
@@ -8,7 +8,6 @@ The QdrantMemoryStore inherits from MemoryStoreBase for persisting/retrieving da
|
||||
import asyncio
|
||||
import logging
|
||||
import uuid
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
from numpy import ndarray
|
||||
from qdrant_client import QdrantClient
|
||||
@@ -29,9 +28,9 @@ class QdrantMemoryStore(MemoryStoreBase):
|
||||
def __init__(
|
||||
self,
|
||||
vector_size: int,
|
||||
url: Optional[str] = None,
|
||||
port: Optional[int] = 6333,
|
||||
local: Optional[bool] = False,
|
||||
url: str | None = None,
|
||||
port: int | None = 6333,
|
||||
local: bool | None = False,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""Initializes a new instance of the QdrantMemoryStore class."""
|
||||
@@ -66,7 +65,7 @@ class QdrantMemoryStore(MemoryStoreBase):
|
||||
|
||||
async def get_collections(
|
||||
self,
|
||||
) -> List[str]:
|
||||
) -> list[str]:
|
||||
"""Gets the list of collections.
|
||||
|
||||
Returns:
|
||||
@@ -136,7 +135,7 @@ class QdrantMemoryStore(MemoryStoreBase):
|
||||
else:
|
||||
raise ServiceResponseException("Upsert failed")
|
||||
|
||||
async def upsert_batch(self, collection_name: str, records: List[MemoryRecord]) -> List[str]:
|
||||
async def upsert_batch(self, collection_name: str, records: list[MemoryRecord]) -> list[str]:
|
||||
tasks = []
|
||||
for record in records:
|
||||
tasks.append(
|
||||
@@ -158,7 +157,7 @@ class QdrantMemoryStore(MemoryStoreBase):
|
||||
else:
|
||||
raise ServiceResponseException("Batch upsert failed")
|
||||
|
||||
async def get(self, collection_name: str, key: str, with_embedding: bool = False) -> Optional[MemoryRecord]:
|
||||
async def get(self, collection_name: str, key: str, with_embedding: bool = False) -> MemoryRecord | None:
|
||||
result = await self._get_existing_record_by_payload_id(
|
||||
collection_name=collection_name,
|
||||
payload_id=key,
|
||||
@@ -181,8 +180,8 @@ class QdrantMemoryStore(MemoryStoreBase):
|
||||
return None
|
||||
|
||||
async def get_batch(
|
||||
self, collection_name: str, keys: List[str], with_embeddings: bool = False
|
||||
) -> List[MemoryRecord]:
|
||||
self, collection_name: str, keys: list[str], with_embeddings: bool = False
|
||||
) -> list[MemoryRecord]:
|
||||
tasks = []
|
||||
for key in keys:
|
||||
tasks.append(
|
||||
@@ -207,7 +206,7 @@ class QdrantMemoryStore(MemoryStoreBase):
|
||||
if result.status != qdrant_models.UpdateStatus.COMPLETED:
|
||||
raise ServiceResponseException("Delete failed")
|
||||
|
||||
async def remove_batch(self, collection_name: str, keys: List[str]) -> None:
|
||||
async def remove_batch(self, collection_name: str, keys: list[str]) -> None:
|
||||
tasks = []
|
||||
for key in keys:
|
||||
tasks.append(
|
||||
@@ -235,7 +234,7 @@ class QdrantMemoryStore(MemoryStoreBase):
|
||||
limit: int,
|
||||
min_relevance_score: float,
|
||||
with_embeddings: bool = False,
|
||||
) -> List[Tuple[MemoryRecord, float]]:
|
||||
) -> list[tuple[MemoryRecord, float]]:
|
||||
match_results = self._qdrantclient.search(
|
||||
collection_name=collection_name,
|
||||
query_vector=embedding,
|
||||
@@ -268,7 +267,7 @@ class QdrantMemoryStore(MemoryStoreBase):
|
||||
embedding: ndarray,
|
||||
min_relevance_score: float,
|
||||
with_embedding: bool = False,
|
||||
) -> Tuple[MemoryRecord, float]:
|
||||
) -> tuple[MemoryRecord, float]:
|
||||
result = await self.get_nearest_matches(
|
||||
collection_name=collection_name,
|
||||
embedding=embedding,
|
||||
@@ -283,7 +282,7 @@ class QdrantMemoryStore(MemoryStoreBase):
|
||||
collection_name: str,
|
||||
payload_id: str,
|
||||
with_embedding: bool = False,
|
||||
) -> Optional[qdrant_models.ScoredPoint]:
|
||||
) -> qdrant_models.ScoredPoint | None:
|
||||
"""Gets an existing record based upon payload id.
|
||||
|
||||
Arguments:
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from typing import List, Tuple
|
||||
|
||||
import numpy as np
|
||||
import redis
|
||||
@@ -137,7 +136,7 @@ class RedisMemoryStore(MemoryStoreBase):
|
||||
except Exception as e:
|
||||
raise ServiceResponseException(f"Failed to create collection {collection_name}") from e
|
||||
|
||||
async def get_collections(self) -> List[str]:
|
||||
async def get_collections(self) -> list[str]:
|
||||
"""
|
||||
Returns a list of names of all collection names present in the data store.
|
||||
|
||||
@@ -210,7 +209,7 @@ class RedisMemoryStore(MemoryStoreBase):
|
||||
except Exception as e:
|
||||
raise ServiceResponseException("Could not upsert messages.") from e
|
||||
|
||||
async def upsert_batch(self, collection_name: str, records: List[MemoryRecord]) -> List[str]:
|
||||
async def upsert_batch(self, collection_name: str, records: list[MemoryRecord]) -> list[str]:
|
||||
"""
|
||||
Upserts a group of memory records into the data store. Does not guarantee that the collection exists.
|
||||
* If the record already exists, it will be updated.
|
||||
@@ -263,8 +262,8 @@ class RedisMemoryStore(MemoryStoreBase):
|
||||
return record
|
||||
|
||||
async def get_batch(
|
||||
self, collection_name: str, keys: List[str], with_embeddings: bool = False
|
||||
) -> List[MemoryRecord]:
|
||||
self, collection_name: str, keys: list[str], with_embeddings: bool = False
|
||||
) -> list[MemoryRecord]:
|
||||
"""
|
||||
Gets a batch of memory records from the data store. Does not guarantee that the collection exists.
|
||||
|
||||
@@ -299,7 +298,7 @@ class RedisMemoryStore(MemoryStoreBase):
|
||||
|
||||
self._database.delete(get_redis_key(collection_name, key))
|
||||
|
||||
async def remove_batch(self, collection_name: str, keys: List[str]) -> None:
|
||||
async def remove_batch(self, collection_name: str, keys: list[str]) -> None:
|
||||
"""
|
||||
Removes a batch of memory records from the data store. Does not guarantee that the collection exists.
|
||||
|
||||
@@ -319,7 +318,7 @@ class RedisMemoryStore(MemoryStoreBase):
|
||||
limit: int,
|
||||
min_relevance_score: float = 0.0,
|
||||
with_embeddings: bool = False,
|
||||
) -> List[Tuple[MemoryRecord, float]]:
|
||||
) -> list[tuple[MemoryRecord, float]]:
|
||||
"""
|
||||
Get the nearest matches to an embedding using the configured similarity algorithm.
|
||||
|
||||
@@ -372,7 +371,7 @@ class RedisMemoryStore(MemoryStoreBase):
|
||||
embedding: ndarray,
|
||||
min_relevance_score: float = 0.0,
|
||||
with_embedding: bool = False,
|
||||
) -> Tuple[MemoryRecord, float]:
|
||||
) -> tuple[MemoryRecord, float]:
|
||||
"""
|
||||
Get the nearest match to an embedding using the configured similarity algorithm.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import json
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, Tuple
|
||||
from typing import Any
|
||||
|
||||
import numpy as np
|
||||
from redis import Redis
|
||||
@@ -25,7 +25,7 @@ def get_redis_key(collection_name: str, record_id: str) -> str:
|
||||
return f"{collection_name}:{record_id}"
|
||||
|
||||
|
||||
def split_redis_key(redis_key: str) -> Tuple[str, str]:
|
||||
def split_redis_key(redis_key: str) -> tuple[str, str]:
|
||||
"""
|
||||
Split a Redis key into its collection name and record ID
|
||||
|
||||
@@ -39,7 +39,7 @@ def split_redis_key(redis_key: str) -> Tuple[str, str]:
|
||||
return collection, record_id
|
||||
|
||||
|
||||
def serialize_record_to_redis(record: MemoryRecord, vector_type: np.dtype) -> Dict[str, Any]:
|
||||
def serialize_record_to_redis(record: MemoryRecord, vector_type: np.dtype) -> dict[str, Any]:
|
||||
all_metadata = {
|
||||
"is_reference": record._is_reference,
|
||||
"external_source_name": record._external_source_name or "",
|
||||
@@ -58,7 +58,7 @@ def serialize_record_to_redis(record: MemoryRecord, vector_type: np.dtype) -> Di
|
||||
return redis_mapping
|
||||
|
||||
|
||||
def deserialize_redis_to_record(fields: Dict[str, Any], vector_type: np.dtype, with_embedding: bool) -> MemoryRecord:
|
||||
def deserialize_redis_to_record(fields: dict[str, Any], vector_type: np.dtype, with_embedding: bool) -> MemoryRecord:
|
||||
metadata = json.loads(fields[b"metadata"])
|
||||
record = MemoryRecord(
|
||||
id=metadata["id"],
|
||||
|
||||
@@ -6,7 +6,6 @@ import os
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional, Tuple, Union
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
@@ -39,7 +38,7 @@ class _USearchCollection:
|
||||
|
||||
embeddings_index: Index
|
||||
embeddings_data_table: pa.Table
|
||||
embeddings_id_to_label: Dict[str, int]
|
||||
embeddings_id_to_label: dict[str, int]
|
||||
|
||||
@staticmethod
|
||||
def create_default(embeddings_index: Index) -> "_USearchCollection":
|
||||
@@ -84,13 +83,13 @@ class _CollectionFileType(Enum):
|
||||
|
||||
|
||||
# Mapping of collection file types to their file extensions.
|
||||
_collection_file_extensions: Dict[_CollectionFileType, str] = {
|
||||
_collection_file_extensions: dict[_CollectionFileType, str] = {
|
||||
_CollectionFileType.USEARCH: ".usearch",
|
||||
_CollectionFileType.PARQUET: ".parquet",
|
||||
}
|
||||
|
||||
|
||||
def memoryrecords_to_pyarrow_table(records: List[MemoryRecord]) -> pa.Table:
|
||||
def memoryrecords_to_pyarrow_table(records: list[MemoryRecord]) -> pa.Table:
|
||||
"""Convert a list of `MemoryRecord` to a PyArrow Table"""
|
||||
records_pylist = [
|
||||
{attr: getattr(record, "_" + attr) for attr in _embeddings_data_schema.names} for record in records
|
||||
@@ -98,7 +97,7 @@ def memoryrecords_to_pyarrow_table(records: List[MemoryRecord]) -> pa.Table:
|
||||
return pa.Table.from_pylist(records_pylist, schema=_embeddings_data_schema)
|
||||
|
||||
|
||||
def pyarrow_table_to_memoryrecords(table: pa.Table, vectors: Optional[ndarray] = None) -> List[MemoryRecord]:
|
||||
def pyarrow_table_to_memoryrecords(table: pa.Table, vectors: ndarray | None = None) -> list[MemoryRecord]:
|
||||
"""Convert a PyArrow Table to a list of MemoryRecords.
|
||||
|
||||
Args:
|
||||
@@ -121,7 +120,7 @@ def pyarrow_table_to_memoryrecords(table: pa.Table, vectors: Optional[ndarray] =
|
||||
class USearchMemoryStore(MemoryStoreBase):
|
||||
def __init__(
|
||||
self,
|
||||
persist_directory: Optional[os.PathLike] = None,
|
||||
persist_directory: os.PathLike | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
Create a USearchMemoryStore instance.
|
||||
@@ -140,7 +139,7 @@ class USearchMemoryStore(MemoryStoreBase):
|
||||
"""
|
||||
self._persist_directory = Path(persist_directory) if persist_directory is not None else None
|
||||
|
||||
self._collections: Dict[str, _USearchCollection] = {}
|
||||
self._collections: dict[str, _USearchCollection] = {}
|
||||
if self._persist_directory:
|
||||
self._collections = self._read_collections_from_dir()
|
||||
|
||||
@@ -168,11 +167,11 @@ class USearchMemoryStore(MemoryStoreBase):
|
||||
self,
|
||||
collection_name: str,
|
||||
ndim: int = 0,
|
||||
metric: Union[str, MetricKind, CompiledMetric] = MetricKind.IP,
|
||||
dtype: Optional[Union[str, ScalarKind]] = None,
|
||||
connectivity: Optional[int] = None,
|
||||
expansion_add: Optional[int] = None,
|
||||
expansion_search: Optional[int] = None,
|
||||
metric: str | MetricKind | CompiledMetric = MetricKind.IP,
|
||||
dtype: str | ScalarKind | None = None,
|
||||
connectivity: int | None = None,
|
||||
expansion_add: int | None = None,
|
||||
expansion_search: int | None = None,
|
||||
view: bool = False,
|
||||
) -> None:
|
||||
"""Create a new collection.
|
||||
@@ -219,7 +218,7 @@ class USearchMemoryStore(MemoryStoreBase):
|
||||
|
||||
return None
|
||||
|
||||
def _read_embeddings_table(self, path: os.PathLike) -> Tuple[pa.Table, Dict[str, int]]:
|
||||
def _read_embeddings_table(self, path: os.PathLike) -> tuple[pa.Table, dict[str, int]]:
|
||||
"""Read embeddings from the provided path and generate an ID to label mapping.
|
||||
|
||||
Args:
|
||||
@@ -229,7 +228,7 @@ class USearchMemoryStore(MemoryStoreBase):
|
||||
Tuple of embeddings table and a dictionary mapping from record ID to its label.
|
||||
"""
|
||||
embeddings_table = pq.read_table(path, schema=_embeddings_data_schema)
|
||||
embeddings_id_to_label: Dict[str, int] = {
|
||||
embeddings_id_to_label: dict[str, int] = {
|
||||
record_id: idx for idx, record_id in enumerate(embeddings_table.column("id").to_pylist())
|
||||
}
|
||||
return embeddings_table, embeddings_id_to_label
|
||||
@@ -239,7 +238,7 @@ class USearchMemoryStore(MemoryStoreBase):
|
||||
# str cast is temporarily fix for https://github.com/unum-cloud/usearch/issues/196
|
||||
return Index.restore(str(path), view=False)
|
||||
|
||||
def _read_collections_from_dir(self) -> Dict[str, _USearchCollection]:
|
||||
def _read_collections_from_dir(self) -> dict[str, _USearchCollection]:
|
||||
"""Read all collections from directory to memory.
|
||||
|
||||
Raises:
|
||||
@@ -249,7 +248,7 @@ class USearchMemoryStore(MemoryStoreBase):
|
||||
Dict[str, _USearchCollection]: Dictionary with collection names as keys and
|
||||
their _USearchCollection as values.
|
||||
"""
|
||||
collections: Dict[str, _USearchCollection] = {}
|
||||
collections: dict[str, _USearchCollection] = {}
|
||||
|
||||
for collection_name, collection_files in self._get_all_storage_files().items():
|
||||
expected_storage_files = len(_CollectionFileType)
|
||||
@@ -272,7 +271,7 @@ class USearchMemoryStore(MemoryStoreBase):
|
||||
|
||||
return collections
|
||||
|
||||
async def get_collections(self) -> List[str]:
|
||||
async def get_collections(self) -> list[str]:
|
||||
"""Get list of existing collections.
|
||||
|
||||
Returns:
|
||||
@@ -300,14 +299,14 @@ class USearchMemoryStore(MemoryStoreBase):
|
||||
async def upsert_batch(
|
||||
self,
|
||||
collection_name: str,
|
||||
records: List[MemoryRecord],
|
||||
records: list[MemoryRecord],
|
||||
*,
|
||||
compact: bool = False,
|
||||
copy: bool = True,
|
||||
threads: int = 0,
|
||||
log: Union[str, bool] = False,
|
||||
log: str | bool = False,
|
||||
batch_size: int = 0,
|
||||
) -> List[str]:
|
||||
) -> list[str]:
|
||||
"""Upsert a batch of MemoryRecords and return their IDs.
|
||||
|
||||
Args:
|
||||
@@ -384,10 +383,10 @@ class USearchMemoryStore(MemoryStoreBase):
|
||||
async def get_batch(
|
||||
self,
|
||||
collection_name: str,
|
||||
keys: List[str],
|
||||
keys: list[str],
|
||||
with_embeddings: bool,
|
||||
dtype: ScalarKind = ScalarKind.F32,
|
||||
) -> List[MemoryRecord]:
|
||||
) -> list[MemoryRecord]:
|
||||
"""Retrieve a batch of MemoryRecords using their keys."""
|
||||
collection_name = collection_name.lower()
|
||||
if collection_name not in self._collections:
|
||||
@@ -407,7 +406,7 @@ class USearchMemoryStore(MemoryStoreBase):
|
||||
await self.remove_batch(collection_name=collection_name, keys=[key])
|
||||
return None
|
||||
|
||||
async def remove_batch(self, collection_name: str, keys: List[str]) -> None:
|
||||
async def remove_batch(self, collection_name: str, keys: list[str]) -> None:
|
||||
"""Remove a batch of MemoryRecords using their keys."""
|
||||
collection_name = collection_name.lower()
|
||||
if collection_name not in self._collections:
|
||||
@@ -429,7 +428,7 @@ class USearchMemoryStore(MemoryStoreBase):
|
||||
min_relevance_score: float = 0.0,
|
||||
with_embedding: bool = True,
|
||||
exact: bool = False,
|
||||
) -> Tuple[MemoryRecord, float]:
|
||||
) -> tuple[MemoryRecord, float]:
|
||||
"""Retrieve the nearest matching MemoryRecord for the provided embedding.
|
||||
|
||||
By default it is approximately search, see `exact` param description.
|
||||
@@ -469,9 +468,9 @@ class USearchMemoryStore(MemoryStoreBase):
|
||||
*,
|
||||
threads: int = 0,
|
||||
exact: bool = False,
|
||||
log: Union[str, bool] = False,
|
||||
log: str | bool = False,
|
||||
batch_size: int = 0,
|
||||
) -> List[Tuple[MemoryRecord, float]]:
|
||||
) -> list[tuple[MemoryRecord, float]]:
|
||||
"""Get the nearest matches to a given embedding.
|
||||
|
||||
By default it is approximately search, see `exact` param description.
|
||||
@@ -500,7 +499,7 @@ class USearchMemoryStore(MemoryStoreBase):
|
||||
collection_name = collection_name.lower()
|
||||
ucollection = self._collections[collection_name]
|
||||
|
||||
result: Union[Matches, BatchMatches] = ucollection.embeddings_index.search(
|
||||
result: Matches | BatchMatches = ucollection.embeddings_index.search(
|
||||
vectors=embedding,
|
||||
count=limit,
|
||||
threads=threads,
|
||||
@@ -513,7 +512,7 @@ class USearchMemoryStore(MemoryStoreBase):
|
||||
relevance_score = 1 / (result.distances + 1)
|
||||
filtered_labels = result.keys[np.where(relevance_score >= min_relevance_score)[0]]
|
||||
|
||||
filtered_vectors: Optional[np.ndarray] = None
|
||||
filtered_vectors: np.ndarray | None = None
|
||||
if with_embeddings:
|
||||
filtered_vectors = ucollection.embeddings_index.get(filtered_labels)
|
||||
|
||||
@@ -527,7 +526,7 @@ class USearchMemoryStore(MemoryStoreBase):
|
||||
)
|
||||
]
|
||||
|
||||
def _get_all_storage_files(self) -> Dict[str, List[Path]]:
|
||||
def _get_all_storage_files(self) -> dict[str, list[Path]]:
|
||||
"""Return storage files for each collection in `self._persist_directory`.
|
||||
|
||||
Collection name is derived from file name and converted to lowercase. Files with extensions that
|
||||
@@ -543,7 +542,7 @@ class USearchMemoryStore(MemoryStoreBase):
|
||||
raise ServiceInitializationError("Persist directory is not set")
|
||||
|
||||
storage_exts = _collection_file_extensions.values()
|
||||
collection_storage_files: Dict[str, List[Path]] = {}
|
||||
collection_storage_files: dict[str, list[Path]] = {}
|
||||
for path in self._persist_directory.iterdir():
|
||||
if path.is_file() and (path.suffix in storage_exts):
|
||||
collection_name = path.stem.lower()
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import asyncio
|
||||
import logging
|
||||
from dataclasses import dataclass
|
||||
from typing import List, Tuple
|
||||
|
||||
import numpy as np
|
||||
import weaviate
|
||||
@@ -176,7 +175,7 @@ class WeaviateMemoryStore(MemoryStoreBase):
|
||||
schema["class"] = collection_name
|
||||
await asyncio.get_running_loop().run_in_executor(None, self.client.schema.create_class, schema)
|
||||
|
||||
async def get_collections(self) -> List[str]:
|
||||
async def get_collections(self) -> list[str]:
|
||||
schemas = await asyncio.get_running_loop().run_in_executor(None, self.client.schema.get)
|
||||
return [schema["class"] for schema in schemas["classes"]]
|
||||
|
||||
@@ -202,7 +201,7 @@ class WeaviateMemoryStore(MemoryStoreBase):
|
||||
vector,
|
||||
)
|
||||
|
||||
async def upsert_batch(self, collection_name: str, records: List[MemoryRecord]) -> List[str]:
|
||||
async def upsert_batch(self, collection_name: str, records: list[MemoryRecord]) -> list[str]:
|
||||
def _upsert_batch_inner():
|
||||
results = []
|
||||
with self.client.batch as batch:
|
||||
@@ -227,7 +226,7 @@ class WeaviateMemoryStore(MemoryStoreBase):
|
||||
results = await self.get_batch(collection_name, [key], with_embedding)
|
||||
return results[0] if results else None
|
||||
|
||||
async def get_batch(self, collection_name: str, keys: List[str], with_embedding: bool) -> List[MemoryRecord]:
|
||||
async def get_batch(self, collection_name: str, keys: list[str], with_embedding: bool) -> list[MemoryRecord]:
|
||||
queries = self._build_multi_get_query(collection_name, keys, with_embedding)
|
||||
|
||||
results = await asyncio.get_running_loop().run_in_executor(None, self.client.query.multi_get(queries).do)
|
||||
@@ -240,7 +239,7 @@ class WeaviateMemoryStore(MemoryStoreBase):
|
||||
|
||||
return memory_records
|
||||
|
||||
def _build_multi_get_query(self, collection_name: str, keys: List[str], with_embedding: bool):
|
||||
def _build_multi_get_query(self, collection_name: str, keys: list[str], with_embedding: bool):
|
||||
queries = []
|
||||
for i, key in enumerate(keys):
|
||||
query = self.client.query.get(collection_name, ALL_PROPERTIES).with_where(
|
||||
@@ -270,7 +269,7 @@ class WeaviateMemoryStore(MemoryStoreBase):
|
||||
async def remove(self, collection_name: str, key: str) -> None:
|
||||
await self.remove_batch(collection_name, [key])
|
||||
|
||||
async def remove_batch(self, collection_name: str, keys: List[str]) -> None:
|
||||
async def remove_batch(self, collection_name: str, keys: list[str]) -> None:
|
||||
# TODO: Use In operator when it's available
|
||||
# (https://github.com/weaviate/weaviate/issues/2387)
|
||||
# and handle max delete objects
|
||||
@@ -293,7 +292,7 @@ class WeaviateMemoryStore(MemoryStoreBase):
|
||||
limit: int,
|
||||
min_relevance_score: float,
|
||||
with_embeddings: bool,
|
||||
) -> List[Tuple[MemoryRecord, float]]:
|
||||
) -> list[tuple[MemoryRecord, float]]:
|
||||
nearVector = {
|
||||
"vector": embedding,
|
||||
"certainty": min_relevance_score,
|
||||
@@ -332,7 +331,7 @@ class WeaviateMemoryStore(MemoryStoreBase):
|
||||
embedding: np.ndarray,
|
||||
min_relevance_score: float,
|
||||
with_embedding: bool,
|
||||
) -> Tuple[MemoryRecord, float]:
|
||||
) -> tuple[MemoryRecord, float]:
|
||||
results = await self.get_nearest_matches(
|
||||
collection_name,
|
||||
embedding,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import Enum
|
||||
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Awaitable, Callable
|
||||
from collections.abc import Awaitable, Callable
|
||||
from typing import Any
|
||||
|
||||
from semantic_kernel.connectors.openapi_plugin.openapi_function_execution_parameters import (
|
||||
OpenAPIFunctionExecutionParameters,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Awaitable, Callable, List
|
||||
from collections.abc import Awaitable, Callable
|
||||
from typing import Any
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import httpx
|
||||
@@ -25,7 +25,7 @@ class OpenAPIFunctionExecutionParameters(KernelBaseModel):
|
||||
user_agent: str | None = None
|
||||
enable_dynamic_payload: bool = True
|
||||
enable_payload_namespacing: bool = False
|
||||
operations_to_exclude: List[str] = Field(default_factory=list)
|
||||
operations_to_exclude: list[str] = Field(default_factory=list)
|
||||
|
||||
def model_post_init(self, __context: Any) -> None:
|
||||
from semantic_kernel.connectors.telemetry import HTTP_USER_AGENT
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
from collections.abc import Callable, Mapping
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING, Any, Callable, Dict, Mapping, Tuple
|
||||
from typing import TYPE_CHECKING, Any
|
||||
from urllib.parse import urlencode, urljoin, urlparse, urlunparse
|
||||
|
||||
import httpx
|
||||
@@ -43,7 +42,7 @@ class RestApiOperationPayloadProperty:
|
||||
self,
|
||||
name: str,
|
||||
type: str,
|
||||
properties: RestApiOperationPayloadProperty,
|
||||
properties: "RestApiOperationPayloadProperty",
|
||||
description: str | None = None,
|
||||
is_required: bool = False,
|
||||
default_value: Any | None = None,
|
||||
@@ -63,7 +62,7 @@ class RestApiOperationPayload:
|
||||
def __init__(
|
||||
self,
|
||||
media_type: str,
|
||||
properties: list[RestApiOperationPayloadProperty],
|
||||
properties: list["RestApiOperationPayloadProperty"],
|
||||
description: str | None = None,
|
||||
schema: str | None = None,
|
||||
):
|
||||
@@ -88,8 +87,8 @@ class RestApiOperation:
|
||||
path: str,
|
||||
summary: str | None = None,
|
||||
description: str | None = None,
|
||||
params: list[RestApiOperationParameter] | None = None,
|
||||
request_body: RestApiOperationPayload | None = None,
|
||||
params: list["RestApiOperationParameter"] | None = None,
|
||||
request_body: "RestApiOperationPayload | None" = None,
|
||||
):
|
||||
self.id = id
|
||||
self.method = method.upper()
|
||||
@@ -110,7 +109,7 @@ class RestApiOperation:
|
||||
full_path = urljoin(base_path, path.lstrip("/"))
|
||||
return urlunparse(parsed_base._replace(path=full_path))
|
||||
|
||||
def build_headers(self, arguments: Dict[str, Any]) -> Dict[str, str]:
|
||||
def build_headers(self, arguments: dict[str, Any]) -> dict[str, str]:
|
||||
headers = {}
|
||||
|
||||
parameters = [p for p in self.parameters if p.location == RestApiOperationParameterLocation.HEADER]
|
||||
@@ -151,7 +150,7 @@ class RestApiOperation:
|
||||
|
||||
return urlparse(server_url_string)
|
||||
|
||||
def build_path(self, path_template: str, arguments: Dict[str, Any]) -> str:
|
||||
def build_path(self, path_template: str, arguments: dict[str, Any]) -> str:
|
||||
parameters = [p for p in self.parameters if p.location == RestApiOperationParameterLocation.PATH]
|
||||
for parameter in parameters:
|
||||
argument = arguments.get(parameter.name)
|
||||
@@ -165,7 +164,7 @@ class RestApiOperation:
|
||||
path_template = path_template.replace(f"{{{parameter.name}}}", str(argument))
|
||||
return path_template
|
||||
|
||||
def build_query_string(self, arguments: Dict[str, Any]) -> str:
|
||||
def build_query_string(self, arguments: dict[str, Any]) -> str:
|
||||
segments = []
|
||||
parameters = [p for p in self.parameters if p.location == RestApiOperationParameterLocation.QUERY]
|
||||
for parameter in parameters:
|
||||
@@ -185,10 +184,10 @@ class RestApiOperation:
|
||||
|
||||
def get_parameters(
|
||||
self,
|
||||
operation: RestApiOperation,
|
||||
operation: "RestApiOperation",
|
||||
add_payload_params_from_metadata: bool = True,
|
||||
enable_payload_spacing: bool = False,
|
||||
) -> list[RestApiOperationParameter]:
|
||||
) -> list["RestApiOperationParameter"]:
|
||||
params = list(operation.parameters)
|
||||
if operation.request_body is not None:
|
||||
params.extend(
|
||||
@@ -204,7 +203,7 @@ class RestApiOperation:
|
||||
|
||||
return params
|
||||
|
||||
def create_payload_artificial_parameter(self, operation: RestApiOperation) -> RestApiOperationParameter:
|
||||
def create_payload_artificial_parameter(self, operation: "RestApiOperation") -> "RestApiOperationParameter":
|
||||
return RestApiOperationParameter(
|
||||
name=self.PAYLOAD_ARGUMENT_NAME,
|
||||
type=(
|
||||
@@ -220,7 +219,7 @@ class RestApiOperation:
|
||||
schema=operation.request_body.schema if operation.request_body else None,
|
||||
)
|
||||
|
||||
def create_content_type_artificial_parameter(self) -> RestApiOperationParameter:
|
||||
def create_content_type_artificial_parameter(self) -> "RestApiOperationParameter":
|
||||
return RestApiOperationParameter(
|
||||
name=self.CONTENT_TYPE_ARGUMENT_NAME,
|
||||
type="string",
|
||||
@@ -239,10 +238,10 @@ class RestApiOperation:
|
||||
|
||||
def _get_parameters_from_payload_metadata(
|
||||
self,
|
||||
properties: list[RestApiOperationPayloadProperty],
|
||||
properties: list["RestApiOperationPayloadProperty"],
|
||||
enable_namespacing: bool = False,
|
||||
root_property_name: bool = None,
|
||||
) -> list[RestApiOperationParameter]:
|
||||
) -> list["RestApiOperationParameter"]:
|
||||
parameters: list[RestApiOperationParameter] = []
|
||||
for property in properties:
|
||||
parameter_name = self._get_property_name(property, root_property_name, enable_namespacing)
|
||||
@@ -264,7 +263,7 @@ class RestApiOperation:
|
||||
return parameters
|
||||
|
||||
def get_payload_parameters(
|
||||
self, operation: RestApiOperation, use_parameters_from_metadata: bool, enable_namespacing: bool
|
||||
self, operation: "RestApiOperation", use_parameters_from_metadata: bool, enable_namespacing: bool
|
||||
):
|
||||
if use_parameters_from_metadata:
|
||||
if operation.request_body is None:
|
||||
@@ -308,7 +307,6 @@ class RestApiOperationParameter:
|
||||
default_value: Any | None = None,
|
||||
schema: str | None = None,
|
||||
):
|
||||
|
||||
self.name = name
|
||||
self.type = type
|
||||
self.location = location
|
||||
@@ -424,7 +422,7 @@ class OpenApiParser:
|
||||
self,
|
||||
parsed_document: Any,
|
||||
execution_settings: "OpenAIFunctionExecutionParameters | OpenAPIFunctionExecutionParameters | None" = None,
|
||||
) -> Dict[str, RestApiOperation]:
|
||||
) -> dict[str, RestApiOperation]:
|
||||
"""Create the REST API Operations from the parsed OpenAPI document.
|
||||
|
||||
Args:
|
||||
@@ -502,7 +500,7 @@ class OpenApiRunner:
|
||||
def __init__(
|
||||
self,
|
||||
parsed_openapi_document: Mapping[str, str],
|
||||
auth_callback: Callable[[Dict[str, str]], Dict[str, str]] | None = None,
|
||||
auth_callback: Callable[[dict[str, str]], dict[str, str]] | None = None,
|
||||
http_client: httpx.AsyncClient | None = None,
|
||||
enable_dynamic_payload: bool = True,
|
||||
enable_payload_namespacing: bool = False,
|
||||
@@ -527,8 +525,8 @@ class OpenApiRunner:
|
||||
return self.build_full_url(url, operation.build_query_string(arguments))
|
||||
|
||||
def build_json_payload(
|
||||
self, payload_metadata: RestApiOperationPayload, arguments: Dict[str, Any]
|
||||
) -> Tuple[str, str]:
|
||||
self, payload_metadata: RestApiOperationPayload, arguments: dict[str, Any]
|
||||
) -> tuple[str, str]:
|
||||
"""Build the JSON payload."""
|
||||
if self.enable_dynamic_payload:
|
||||
if payload_metadata is None:
|
||||
@@ -566,7 +564,7 @@ class OpenApiRunner:
|
||||
)
|
||||
return result
|
||||
|
||||
def build_operation_payload(self, operation: RestApiOperation, arguments: KernelArguments) -> Tuple[str, str]:
|
||||
def build_operation_payload(self, operation: RestApiOperation, arguments: KernelArguments) -> tuple[str, str]:
|
||||
if operation.request_body is None and self.payload_argument_name not in arguments:
|
||||
return None, None
|
||||
return self.build_json_payload(operation.request_body, arguments)
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import logging
|
||||
import urllib
|
||||
from typing import List
|
||||
|
||||
import aiohttp
|
||||
from pydantic import ValidationError
|
||||
@@ -41,7 +40,7 @@ class BingConnector(ConnectorBase):
|
||||
)
|
||||
assert self._api_key, "API key cannot be 'None' or empty."
|
||||
|
||||
async def search(self, query: str, num_results: int = 1, offset: int = 0) -> List[str]:
|
||||
async def search(self, query: str, num_results: int = 1, offset: int = 0) -> list[str]:
|
||||
"""
|
||||
Returns the search results of the query provided by pinging the Bing web search API.
|
||||
Returns `num_results` results and ignores the first `offset`.
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import List
|
||||
|
||||
|
||||
class ConnectorBase(ABC):
|
||||
@@ -10,5 +9,5 @@ class ConnectorBase(ABC):
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
async def search(self, query: str, num_results: int = 1, offset: int = 0) -> List[str]:
|
||||
async def search(self, query: str, num_results: int = 1, offset: int = 0) -> list[str]:
|
||||
pass
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import logging
|
||||
import urllib
|
||||
from typing import List
|
||||
|
||||
import aiohttp
|
||||
|
||||
@@ -30,7 +29,7 @@ class GoogleConnector(ConnectorBase):
|
||||
if not self._search_engine_id:
|
||||
raise ServiceInitializationError("Google search engine ID cannot be null.")
|
||||
|
||||
async def search(self, query: str, num_results: int = 1, offset: int = 0) -> List[str]:
|
||||
async def search(self, query: str, num_results: int = 1, offset: int = 0) -> list[str]:
|
||||
"""
|
||||
Returns the search results of the query provided by pinging the Google Custom search API.
|
||||
Returns `num_results` results and ignores the first `offset`.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import os
|
||||
from importlib.metadata import PackageNotFoundError, version
|
||||
from typing import Any, Dict
|
||||
from typing import Any
|
||||
|
||||
from semantic_kernel.connectors.ai.open_ai.const import USER_AGENT
|
||||
|
||||
@@ -26,7 +26,7 @@ APP_INFO = (
|
||||
)
|
||||
|
||||
|
||||
def prepend_semantic_kernel_to_user_agent(headers: Dict[str, Any]):
|
||||
def prepend_semantic_kernel_to_user_agent(headers: dict[str, Any]):
|
||||
"""
|
||||
Prepend "Semantic-Kernel" to the User-Agent in the headers.
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from typing import Any, Callable, Optional
|
||||
from collections.abc import Callable
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
|
||||
@@ -16,8 +17,8 @@ class DocumentLoader:
|
||||
async def from_uri(
|
||||
url: str,
|
||||
http_client: httpx.AsyncClient,
|
||||
auth_callback: Optional[Callable[[Any], None]],
|
||||
user_agent: Optional[str] = HTTP_USER_AGENT,
|
||||
auth_callback: Callable[[Any], None] | None,
|
||||
user_agent: str | None = HTTP_USER_AGENT,
|
||||
):
|
||||
"""Load the manifest from the given URL"""
|
||||
headers = {"User-Agent": user_agent}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from collections.abc import Generator
|
||||
from functools import singledispatchmethod
|
||||
from html import unescape
|
||||
from typing import Any, Generator
|
||||
from typing import Any
|
||||
from xml.etree.ElementTree import Element, tostring
|
||||
|
||||
from defusedxml.ElementTree import XML, ParseError
|
||||
@@ -288,7 +288,7 @@ class ChatHistory(KernelBaseModel):
|
||||
raise ContentSerializationError(f"Unable to serialize ChatHistory to JSON: {e}") from e
|
||||
|
||||
@classmethod
|
||||
def restore_chat_history(cls, chat_history_json: str) -> ChatHistory:
|
||||
def restore_chat_history(cls, chat_history_json: str) -> "ChatHistory":
|
||||
"""
|
||||
Restores a ChatHistory instance from a JSON string.
|
||||
|
||||
@@ -320,7 +320,7 @@ class ChatHistory(KernelBaseModel):
|
||||
file.write(json_str)
|
||||
|
||||
@classmethod
|
||||
def load_chat_history_from_file(cls, file_path: str) -> ChatHistory:
|
||||
def load_chat_history_from_file(cls, file_path: str) -> "ChatHistory":
|
||||
"""
|
||||
Loads the ChatHistory from a file.
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from enum import Enum
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
from functools import cached_property
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Any
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import Enum
|
||||
from typing import Any, Union, overload
|
||||
@@ -163,7 +162,7 @@ class StreamingChatMessageContent(ChatMessageContent, StreamingContentMixin):
|
||||
"""Return the content of the response encoded in the encoding."""
|
||||
return self.content.encode(self.encoding if self.encoding else "utf-8") if self.content else b""
|
||||
|
||||
def __add__(self, other: StreamingChatMessageContent) -> StreamingChatMessageContent:
|
||||
def __add__(self, other: "StreamingChatMessageContent") -> "StreamingChatMessageContent":
|
||||
"""When combining two StreamingChatMessageContent instances, the content fields are combined.
|
||||
|
||||
The inner_content of the first one is used, ai_model_id and encoding should be the same,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
from html import unescape
|
||||
from xml.etree.ElementTree import Element
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import sys
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
from typing import Annotated
|
||||
else:
|
||||
from typing_extensions import Annotated
|
||||
|
||||
from typing import TYPE_CHECKING, Annotated
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from semantic_kernel.functions.kernel_arguments import KernelArguments
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import json
|
||||
import sys
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Annotated, Any
|
||||
|
||||
import aiohttp
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
from typing import Annotated
|
||||
else:
|
||||
from typing_extensions import Annotated
|
||||
|
||||
from semantic_kernel.exceptions import FunctionExecutionException
|
||||
from semantic_kernel.functions.kernel_function_decorator import kernel_function
|
||||
from semantic_kernel.kernel_pydantic import KernelBaseModel
|
||||
@@ -52,7 +46,7 @@ class HttpPlugin(KernelBaseModel):
|
||||
async def post(
|
||||
self,
|
||||
url: Annotated[str, "The URI to send the request to."],
|
||||
body: Annotated[Optional[Dict[str, Any]], "The body of the request"] = {},
|
||||
body: Annotated[dict[str, Any] | None, "The body of the request"] = {},
|
||||
) -> str:
|
||||
"""
|
||||
Sends an HTTP POST request to the specified URI and returns
|
||||
@@ -76,7 +70,7 @@ class HttpPlugin(KernelBaseModel):
|
||||
async def put(
|
||||
self,
|
||||
url: Annotated[str, "The URI to send the request to."],
|
||||
body: Annotated[Optional[Dict[str, Any]], "The body of the request"] = {},
|
||||
body: Annotated[dict[str, Any] | None, "The body of the request"] = {},
|
||||
) -> str:
|
||||
"""
|
||||
Sends an HTTP PUT request to the specified URI and returns
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import sys
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
from typing import Annotated
|
||||
else:
|
||||
from typing_extensions import Annotated
|
||||
from typing import Annotated
|
||||
|
||||
from semantic_kernel.functions.kernel_function_decorator import kernel_function
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from collections.abc import Awaitable, Callable
|
||||
from io import BufferedReader, BytesIO
|
||||
from typing import Annotated, Any, Awaitable, Callable
|
||||
from typing import Annotated, Any
|
||||
|
||||
import httpx
|
||||
from pydantic import ValidationError, field_validator
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
from enum import Enum
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
from typing import Any, Dict, Final
|
||||
from typing import Annotated, Any, Final
|
||||
|
||||
from pydantic import Field
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
from typing import Annotated
|
||||
else:
|
||||
from typing_extensions import Annotated
|
||||
|
||||
from semantic_kernel.functions.kernel_function_decorator import kernel_function
|
||||
from semantic_kernel.kernel_pydantic import KernelBaseModel
|
||||
from semantic_kernel.memory.semantic_text_memory_base import SemanticTextMemoryBase
|
||||
@@ -26,9 +20,9 @@ DEFAULT_LIMIT: Final[int] = 1
|
||||
|
||||
class TextMemoryPlugin(KernelBaseModel):
|
||||
memory: SemanticTextMemoryBase
|
||||
embeddings_kwargs: Dict[str, Any] = Field(default_factory=dict)
|
||||
embeddings_kwargs: dict[str, Any] = Field(default_factory=dict)
|
||||
|
||||
def __init__(self, memory: SemanticTextMemoryBase, embeddings_kwargs: Dict[str, Any] = {}) -> None:
|
||||
def __init__(self, memory: SemanticTextMemoryBase, embeddings_kwargs: dict[str, Any] = {}) -> None:
|
||||
"""
|
||||
Initialize a new instance of the TextMemoryPlugin
|
||||
|
||||
|
||||
@@ -1,16 +1,9 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
from typing import Union
|
||||
from typing import Annotated
|
||||
|
||||
from semantic_kernel.exceptions import FunctionExecutionException
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
from typing import Annotated
|
||||
else:
|
||||
from typing_extensions import Annotated
|
||||
|
||||
from semantic_kernel.functions.kernel_function_decorator import kernel_function
|
||||
from semantic_kernel.kernel_pydantic import KernelBaseModel
|
||||
|
||||
@@ -27,9 +20,7 @@ class WaitPlugin(KernelBaseModel):
|
||||
"""
|
||||
|
||||
@kernel_function(description="Wait for a certain number of seconds.")
|
||||
async def wait(
|
||||
self, input: Annotated[Union[float, str], "The number of seconds to wait, can be str or float."]
|
||||
) -> None:
|
||||
async def wait(self, input: Annotated[float | str, "The number of seconds to wait, can be str or float."]) -> None:
|
||||
if isinstance(input, str):
|
||||
try:
|
||||
input = float(input)
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
import sys
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
from typing import Annotated
|
||||
else:
|
||||
from typing_extensions import Annotated
|
||||
from typing import TYPE_CHECKING, Annotated
|
||||
|
||||
from semantic_kernel.functions.kernel_function_decorator import kernel_function
|
||||
|
||||
@@ -35,9 +29,9 @@ class WebSearchEnginePlugin:
|
||||
async def search(
|
||||
self,
|
||||
query: Annotated[str, "The search query"],
|
||||
num_results: Annotated[Optional[int], "The number of search results to return"] = 1,
|
||||
offset: Annotated[Optional[int], "The number of search results to skip"] = 0,
|
||||
) -> List[str]:
|
||||
num_results: Annotated[int | None, "The number of search results to return"] = 1,
|
||||
offset: Annotated[int | None, "The number of search results to skip"] = 0,
|
||||
) -> list[str]:
|
||||
"""
|
||||
Returns the search results of the query provided.
|
||||
Returns `num_results` results and ignores the first `offset`.
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
@@ -11,7 +10,7 @@ class KernelArguments(dict):
|
||||
def __init__(
|
||||
self,
|
||||
settings: (
|
||||
"PromptExecutionSettings" | list["PromptExecutionSettings"] | dict[str, "PromptExecutionSettings"] | None
|
||||
"PromptExecutionSettings | list[PromptExecutionSettings] | dict[str, PromptExecutionSettings] | None"
|
||||
) = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from abc import abstractmethod
|
||||
from collections.abc import AsyncGenerator
|
||||
from collections.abc import AsyncGenerator, Callable
|
||||
from copy import copy, deepcopy
|
||||
from inspect import isasyncgen, isgenerator
|
||||
from typing import TYPE_CHECKING, Any, Callable
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from semantic_kernel.filters.filter_types import FilterTypes
|
||||
from semantic_kernel.filters.functions.function_invocation_context import FunctionInvocationContext
|
||||
@@ -77,12 +76,12 @@ class KernelFunction(KernelBaseModel):
|
||||
description: str | None = None,
|
||||
prompt: str | None = None,
|
||||
template_format: TEMPLATE_FORMAT_TYPES = KERNEL_TEMPLATE_FORMAT_NAME,
|
||||
prompt_template: PromptTemplateBase | None = None,
|
||||
prompt_template_config: PromptTemplateConfig | None = None,
|
||||
prompt_template: "PromptTemplateBase | None " = None,
|
||||
prompt_template_config: "PromptTemplateConfig | None" = None,
|
||||
prompt_execution_settings: (
|
||||
PromptExecutionSettings | list[PromptExecutionSettings] | dict[str, PromptExecutionSettings] | None
|
||||
"PromptExecutionSettings | list[PromptExecutionSettings] | dict[str, PromptExecutionSettings] | None"
|
||||
) = None,
|
||||
) -> KernelFunctionFromPrompt:
|
||||
) -> "KernelFunctionFromPrompt":
|
||||
"""
|
||||
Create a new instance of the KernelFunctionFromPrompt class.
|
||||
"""
|
||||
@@ -105,7 +104,7 @@ class KernelFunction(KernelBaseModel):
|
||||
method: Callable[..., Any],
|
||||
plugin_name: str | None = None,
|
||||
stream_method: Callable[..., Any] | None = None,
|
||||
) -> KernelFunctionFromMethod:
|
||||
) -> "KernelFunctionFromMethod":
|
||||
"""
|
||||
Create a new instance of the KernelFunctionFromMethod class.
|
||||
"""
|
||||
@@ -138,17 +137,17 @@ class KernelFunction(KernelBaseModel):
|
||||
return self.metadata.is_prompt
|
||||
|
||||
@property
|
||||
def parameters(self) -> list[KernelParameterMetadata]:
|
||||
def parameters(self) -> list["KernelParameterMetadata"]:
|
||||
return self.metadata.parameters
|
||||
|
||||
@property
|
||||
def return_parameter(self) -> KernelParameterMetadata | None:
|
||||
def return_parameter(self) -> "KernelParameterMetadata | None":
|
||||
return self.metadata.return_parameter
|
||||
|
||||
async def __call__(
|
||||
self,
|
||||
kernel: Kernel,
|
||||
arguments: KernelArguments | None = None,
|
||||
kernel: "Kernel",
|
||||
arguments: "KernelArguments | None" = None,
|
||||
metadata: dict[str, Any] = {},
|
||||
**kwargs: Any,
|
||||
) -> FunctionResult | None:
|
||||
@@ -180,8 +179,8 @@ class KernelFunction(KernelBaseModel):
|
||||
|
||||
async def invoke(
|
||||
self,
|
||||
kernel: Kernel,
|
||||
arguments: KernelArguments | None = None,
|
||||
kernel: "Kernel",
|
||||
arguments: "KernelArguments | None" = None,
|
||||
metadata: dict[str, Any] = {},
|
||||
**kwargs: Any,
|
||||
) -> "FunctionResult | None":
|
||||
@@ -220,11 +219,11 @@ class KernelFunction(KernelBaseModel):
|
||||
|
||||
async def invoke_stream(
|
||||
self,
|
||||
kernel: Kernel,
|
||||
arguments: KernelArguments | None = None,
|
||||
kernel: "Kernel",
|
||||
arguments: "KernelArguments | None" = None,
|
||||
metadata: dict[str, Any] = {},
|
||||
**kwargs: Any,
|
||||
) -> AsyncGenerator[FunctionResult | list[StreamingContentMixin | Any], Any]:
|
||||
) -> "AsyncGenerator[FunctionResult | list[StreamingContentMixin | Any], Any]":
|
||||
"""
|
||||
Invoke a stream async function with the given arguments.
|
||||
|
||||
@@ -260,7 +259,7 @@ class KernelFunction(KernelBaseModel):
|
||||
else:
|
||||
yield function_context.result
|
||||
|
||||
def function_copy(self, plugin_name: str | None = None) -> KernelFunction:
|
||||
def function_copy(self, plugin_name: str | None = None) -> "KernelFunction":
|
||||
"""Copy the function, can also override the plugin_name.
|
||||
|
||||
Args:
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from collections.abc import Callable
|
||||
from inspect import get_annotations, isasyncgenfunction, isclass, isgeneratorfunction, signature
|
||||
from typing import Any, Callable, ForwardRef
|
||||
from typing import Any, ForwardRef
|
||||
|
||||
NoneType = type(None)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from collections.abc import Callable
|
||||
from inspect import isasyncgen, isasyncgenfunction, isawaitable, iscoroutinefunction, isgenerator, isgeneratorfunction
|
||||
from typing import Any, Callable
|
||||
from typing import Any
|
||||
|
||||
from pydantic import ValidationError
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import os
|
||||
from collections.abc import AsyncGenerator
|
||||
from html import unescape
|
||||
from typing import Any, AsyncGenerator
|
||||
from typing import Any
|
||||
|
||||
import yaml
|
||||
from pydantic import Field, ValidationError, model_validator
|
||||
@@ -274,7 +274,7 @@ through prompt_template_config or in the prompt_template."
|
||||
arguments[parameter.name] = parameter.default
|
||||
|
||||
@classmethod
|
||||
def from_yaml(cls, yaml_str: str, plugin_name: str | None = None) -> KernelFunctionFromPrompt:
|
||||
def from_yaml(cls, yaml_str: str, plugin_name: str | None = None) -> "KernelFunctionFromPrompt":
|
||||
"""Creates a new instance of the KernelFunctionFromPrompt class from a YAML string."""
|
||||
try:
|
||||
data = yaml.safe_load(yaml_str)
|
||||
@@ -299,7 +299,7 @@ through prompt_template_config or in the prompt_template."
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_directory(cls, path: str, plugin_name: str | None = None) -> KernelFunctionFromPrompt:
|
||||
def from_directory(cls, path: str, plugin_name: str | None = None) -> "KernelFunctionFromPrompt":
|
||||
"""Creates a new instance of the KernelFunctionFromPrompt class from a directory.
|
||||
|
||||
The directory needs to contain:
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, List, Optional
|
||||
from typing import Any
|
||||
|
||||
from pydantic import Field
|
||||
|
||||
@@ -12,13 +11,13 @@ from semantic_kernel.utils.validation import FUNCTION_NAME_REGEX, PLUGIN_NAME_RE
|
||||
|
||||
class KernelFunctionMetadata(KernelBaseModel):
|
||||
name: str = Field(pattern=FUNCTION_NAME_REGEX)
|
||||
plugin_name: Optional[str] = Field(None, pattern=PLUGIN_NAME_REGEX)
|
||||
description: Optional[str] = Field(default=None)
|
||||
parameters: List[KernelParameterMetadata] = Field(default_factory=list)
|
||||
plugin_name: str | None = Field(None, pattern=PLUGIN_NAME_REGEX)
|
||||
description: str | None = Field(default=None)
|
||||
parameters: list[KernelParameterMetadata] = Field(default_factory=list)
|
||||
is_prompt: bool
|
||||
is_asynchronous: Optional[bool] = Field(default=True)
|
||||
return_parameter: Optional[KernelParameterMetadata] = None
|
||||
additional_properties: Optional[dict[str, Any]] = Field(default=None)
|
||||
is_asynchronous: bool | None = Field(default=True)
|
||||
return_parameter: KernelParameterMetadata | None = None
|
||||
additional_properties: dict[str, Any] | None = Field(default=None)
|
||||
|
||||
@property
|
||||
def fully_qualified_name(self) -> str:
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Type
|
||||
from typing import Any
|
||||
|
||||
from pydantic import Field, model_validator
|
||||
|
||||
@@ -34,7 +33,7 @@ class KernelParameterMetadata(KernelBaseModel):
|
||||
|
||||
@classmethod
|
||||
def infer_schema(
|
||||
cls, type_object: Type | None, parameter_type: str | None, default_value: Any, description: str | None
|
||||
cls, type_object: type | None, parameter_type: str | None, default_value: Any, description: str | None
|
||||
) -> dict[str, Any] | None:
|
||||
schema = None
|
||||
|
||||
|
||||
@@ -1,22 +1,15 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib
|
||||
import inspect
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from collections.abc import Generator
|
||||
from collections.abc import Generator, ItemsView
|
||||
from functools import singledispatchmethod
|
||||
from glob import glob
|
||||
from types import MethodType
|
||||
from typing import TYPE_CHECKING, Any, ItemsView
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
from typing import Annotated # pragma: no cover
|
||||
else:
|
||||
from typing_extensions import Annotated # pragma: no cover
|
||||
from typing import TYPE_CHECKING, Annotated, Any
|
||||
|
||||
import httpx
|
||||
from pydantic import Field, StringConstraints
|
||||
@@ -104,8 +97,8 @@ class KernelPlugin(KernelBaseModel):
|
||||
description: str | None = None,
|
||||
functions: (
|
||||
KERNEL_FUNCTION_TYPE
|
||||
| KernelPlugin
|
||||
| list[KERNEL_FUNCTION_TYPE | KernelPlugin]
|
||||
| "KernelPlugin"
|
||||
| list[KERNEL_FUNCTION_TYPE | "KernelPlugin"]
|
||||
| dict[str, KERNEL_FUNCTION_TYPE]
|
||||
| None
|
||||
) = None,
|
||||
@@ -199,7 +192,7 @@ class KernelPlugin(KernelBaseModel):
|
||||
raise TypeError(f"Unknown type being added, type was {type(functions)}")
|
||||
|
||||
@add.register(list)
|
||||
def add_list(self, functions: list[KERNEL_FUNCTION_TYPE | KernelPlugin]) -> None:
|
||||
def add_list(self, functions: list[KERNEL_FUNCTION_TYPE | "KernelPlugin"]) -> None:
|
||||
"""Add a list of functions to the plugin."""
|
||||
for function in functions:
|
||||
if isinstance(function, KernelPlugin):
|
||||
@@ -231,7 +224,7 @@ class KernelPlugin(KernelBaseModel):
|
||||
# endregion
|
||||
# region Properties
|
||||
|
||||
def get_functions_metadata(self) -> list[KernelFunctionMetadata]:
|
||||
def get_functions_metadata(self) -> list["KernelFunctionMetadata"]:
|
||||
"""
|
||||
Get the metadata for the functions in the plugin.
|
||||
|
||||
@@ -246,7 +239,7 @@ class KernelPlugin(KernelBaseModel):
|
||||
@classmethod
|
||||
def from_object(
|
||||
cls, plugin_name: str, plugin_instance: Any | dict[str, Any], description: str | None = None
|
||||
) -> KernelPlugin:
|
||||
) -> "KernelPlugin":
|
||||
"""
|
||||
Creates a plugin that wraps the specified target object and imports it into the kernel's plugin collection
|
||||
|
||||
@@ -281,7 +274,7 @@ class KernelPlugin(KernelBaseModel):
|
||||
parent_directory: str,
|
||||
description: str | None = None,
|
||||
class_init_arguments: dict[str, dict[str, Any]] | None = None,
|
||||
) -> KernelPlugin:
|
||||
) -> "KernelPlugin":
|
||||
"""Create a plugin from a specified directory.
|
||||
|
||||
This method does not recurse into subdirectories beyond one level deep from the specified plugin directory.
|
||||
@@ -370,9 +363,9 @@ class KernelPlugin(KernelBaseModel):
|
||||
cls,
|
||||
plugin_name: str,
|
||||
openapi_document_path: str,
|
||||
execution_settings: OpenAPIFunctionExecutionParameters | None = None,
|
||||
execution_settings: "OpenAPIFunctionExecutionParameters | None" = None,
|
||||
description: str | None = None,
|
||||
) -> KernelPlugin:
|
||||
) -> "KernelPlugin":
|
||||
"""Create a plugin from an OpenAPI document.
|
||||
|
||||
Args:
|
||||
@@ -408,9 +401,9 @@ class KernelPlugin(KernelBaseModel):
|
||||
plugin_name: str,
|
||||
plugin_url: str | None = None,
|
||||
plugin_str: str | None = None,
|
||||
execution_parameters: OpenAIFunctionExecutionParameters | None = None,
|
||||
execution_parameters: "OpenAIFunctionExecutionParameters | None" = None,
|
||||
description: str | None = None,
|
||||
) -> KernelPlugin:
|
||||
) -> "KernelPlugin":
|
||||
"""Create a plugin from the Open AI manifest.
|
||||
|
||||
Args:
|
||||
@@ -474,7 +467,7 @@ class KernelPlugin(KernelBaseModel):
|
||||
py_file: str,
|
||||
description: str | None = None,
|
||||
class_init_arguments: dict[str, dict[str, Any]] | None = None,
|
||||
) -> KernelPlugin:
|
||||
) -> "KernelPlugin":
|
||||
module_name = os.path.basename(py_file).replace(".py", "")
|
||||
spec = importlib.util.spec_from_file_location(module_name, py_file)
|
||||
if not spec:
|
||||
@@ -498,13 +491,13 @@ class KernelPlugin(KernelBaseModel):
|
||||
def _validate_functions(
|
||||
functions: (
|
||||
KERNEL_FUNCTION_TYPE
|
||||
| list[KERNEL_FUNCTION_TYPE | KernelPlugin]
|
||||
| list[KERNEL_FUNCTION_TYPE | "KernelPlugin"]
|
||||
| dict[str, KERNEL_FUNCTION_TYPE]
|
||||
| KernelPlugin
|
||||
| "KernelPlugin"
|
||||
| None
|
||||
),
|
||||
plugin_name: str,
|
||||
) -> dict[str, KernelFunction]:
|
||||
) -> dict[str, "KernelFunction"]:
|
||||
"""Validates the functions and returns a dictionary of functions."""
|
||||
if not functions or not plugin_name:
|
||||
# if the plugin_name is not present, the validation will fail, so no point in parsing.
|
||||
@@ -542,7 +535,7 @@ class KernelPlugin(KernelBaseModel):
|
||||
raise ValueError(f"Invalid type for supplied functions: {functions} (type: {type(functions)})")
|
||||
|
||||
@staticmethod
|
||||
def _parse_or_copy(function: KERNEL_FUNCTION_TYPE, plugin_name: str) -> KernelFunction:
|
||||
def _parse_or_copy(function: KERNEL_FUNCTION_TYPE, plugin_name: str) -> "KernelFunction":
|
||||
"""Handle the function and return a KernelFunction instance."""
|
||||
if isinstance(function, KernelFunction):
|
||||
return function.function_copy(plugin_name=plugin_name)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
from semantic_kernel.connectors.ai.prompt_execution_settings import PromptExecutionSettings
|
||||
from semantic_kernel.functions.function_result import FunctionResult
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Callable, Union
|
||||
from collections.abc import Callable
|
||||
from typing import Any, Union
|
||||
|
||||
from semantic_kernel.functions.kernel_function import KernelFunction
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from collections.abc import AsyncGenerator, AsyncIterable
|
||||
from copy import copy
|
||||
from functools import singledispatchmethod
|
||||
from typing import TYPE_CHECKING, Any, AsyncGenerator, AsyncIterable, Literal, Type, TypeVar, Union
|
||||
from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union
|
||||
|
||||
from pydantic import Field, field_validator
|
||||
|
||||
@@ -146,7 +146,7 @@ class Kernel(KernelFilterExtension):
|
||||
|
||||
async def invoke_stream(
|
||||
self,
|
||||
function: "KernelFunction" | None = None,
|
||||
function: "KernelFunction | None" = None,
|
||||
arguments: KernelArguments | None = None,
|
||||
function_name: str | None = None,
|
||||
plugin_name: str | None = None,
|
||||
@@ -207,7 +207,7 @@ class Kernel(KernelFilterExtension):
|
||||
|
||||
async def invoke(
|
||||
self,
|
||||
function: "KernelFunction" | None = None,
|
||||
function: "KernelFunction | None" = None,
|
||||
arguments: KernelArguments | None = None,
|
||||
function_name: str | None = None,
|
||||
plugin_name: str | None = None,
|
||||
@@ -435,7 +435,7 @@ class Kernel(KernelFilterExtension):
|
||||
def add_function(
|
||||
self,
|
||||
plugin_name: str,
|
||||
function: KERNEL_FUNCTION_TYPE | None = None,
|
||||
function: "KERNEL_FUNCTION_TYPE | None" = None,
|
||||
function_name: str | None = None,
|
||||
description: str | None = None,
|
||||
prompt: str | None = None,
|
||||
@@ -505,7 +505,7 @@ class Kernel(KernelFilterExtension):
|
||||
def add_functions(
|
||||
self,
|
||||
plugin_name: str,
|
||||
functions: list[KERNEL_FUNCTION_TYPE] | dict[str, KERNEL_FUNCTION_TYPE],
|
||||
functions: "list[KERNEL_FUNCTION_TYPE] | dict[str, KERNEL_FUNCTION_TYPE]",
|
||||
) -> "KernelPlugin":
|
||||
"""
|
||||
Adds a list of functions to the specified plugin.
|
||||
@@ -744,7 +744,7 @@ class Kernel(KernelFilterExtension):
|
||||
def get_service(
|
||||
self,
|
||||
service_id: str | None = None,
|
||||
type: Type[ALL_SERVICE_TYPES] | None = None,
|
||||
type: type[ALL_SERVICE_TYPES] | None = None,
|
||||
) -> "AIServiceClientBase":
|
||||
"""Get a service by service_id and type.
|
||||
|
||||
@@ -792,7 +792,7 @@ class Kernel(KernelFilterExtension):
|
||||
return {service.service_id: service for service in self.services.values() if isinstance(service, type)} # type: ignore
|
||||
|
||||
def get_prompt_execution_settings_from_service_id(
|
||||
self, service_id: str, type: Type[ALL_SERVICE_TYPES] | None = None
|
||||
self, service_id: str, type: type[ALL_SERVICE_TYPES] | None = None
|
||||
) -> PromptExecutionSettings:
|
||||
"""Get the specific request settings from the service, instantiated with the service_id and ai_model_id."""
|
||||
service = self.get_service(service_id, type=type)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from collections.abc import Callable, Coroutine
|
||||
from functools import partial
|
||||
from typing import Any, Callable, Coroutine, Literal, TypeVar
|
||||
from typing import Any, Literal, TypeVar
|
||||
|
||||
from pydantic import Field
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user