mirror of
https://github.com/microsoft/semantic-kernel.git
synced 2026-10-12 02:19:06 +00:00
Python: Uses Python standard logging (#4115)
### Motivation and Context This replaces passing Logger instances as arguments around with the preferred Python way of having each module define a module-wide `logger` instance at the top of the module. Fixes #3711 ### Description Removes any `log` argument and argument documentation. Replaces usage of those `log` arguments with the module-wide `logger` instance. ### Contribution Checklist - [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 😄 --------- Co-authored-by: Eduard van Valkenburg <[email protected]>
This commit is contained in:
co-authored by
Eduard van Valkenburg
parent
24a099965e
commit
d3dd5c8e7e
@@ -56,17 +56,6 @@
|
||||
"kernel_1 = sk.Kernel()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Instance with a custom logger\n",
|
||||
"my_logger = sk.NullLogger()\n",
|
||||
"kernel_2 = sk.Kernel(log=my_logger)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import logging
|
||||
|
||||
import semantic_kernel as sk
|
||||
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
|
||||
from semantic_kernel.utils.logging import setup_logging
|
||||
|
||||
|
||||
async def main():
|
||||
setup_logging()
|
||||
|
||||
# Set the logging level for semantic_kernel.kernel to DEBUG.
|
||||
logging.getLogger("kernel").setLevel(logging.DEBUG)
|
||||
|
||||
kernel = sk.Kernel()
|
||||
|
||||
api_key, org_id = sk.openai_settings_from_dot_env()
|
||||
|
||||
kernel.add_chat_service(
|
||||
"chat-gpt", OpenAIChatCompletion("gpt-3.5-turbo", api_key, org_id)
|
||||
)
|
||||
|
||||
skill = kernel.import_semantic_skill_from_directory(
|
||||
"../../samples/skills", "FunSkill"
|
||||
)
|
||||
|
||||
joke_function = skill["Joke"]
|
||||
|
||||
print(joke_function("time travel to dinosaur age"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import asyncio
|
||||
|
||||
asyncio.run(main())
|
||||
@@ -13,6 +13,7 @@ from semantic_kernel.semantic_functions.prompt_template_config import (
|
||||
from semantic_kernel.semantic_functions.semantic_function_config import (
|
||||
SemanticFunctionConfig,
|
||||
)
|
||||
from semantic_kernel.utils.logging import setup_logging
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
from semantic_kernel.utils.settings import (
|
||||
azure_aisearch_settings_from_dot_env,
|
||||
@@ -51,4 +52,5 @@ __all__ = [
|
||||
"SKContext",
|
||||
"memory",
|
||||
"core_skills",
|
||||
"setup_logging",
|
||||
]
|
||||
|
||||
@@ -1,30 +1,19 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from abc import ABC
|
||||
from logging import Logger
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import Field, constr, field_validator
|
||||
from pydantic import constr
|
||||
|
||||
from semantic_kernel.sk_pydantic import SKBaseModel
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
|
||||
class AIServiceClientBase(SKBaseModel, ABC):
|
||||
"""Base class for all AI Services.
|
||||
|
||||
Has a ai_model_id and a logger, any other fields have to be defined by the subclasses.
|
||||
Has a ai_model_id, any other fields have to be defined by the subclasses.
|
||||
|
||||
The ai_model_id can refer to a specific model, like 'gpt-35-turbo' for OpenAI,
|
||||
or can just be a string that is used to identify the service.
|
||||
"""
|
||||
|
||||
ai_model_id: constr(strip_whitespace=True, min_length=1)
|
||||
log: Optional[Logger] = Field(default_factory=NullLogger)
|
||||
|
||||
@field_validator("log")
|
||||
@classmethod
|
||||
def validate_log(cls, v):
|
||||
if v is None:
|
||||
return NullLogger()
|
||||
return v
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from logging import Logger
|
||||
from typing import TYPE_CHECKING, AsyncGenerator, List, Optional, Union
|
||||
from typing import TYPE_CHECKING, Any, AsyncGenerator, List, Optional, Union
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from semantic_kernel.connectors.ai.chat_request_settings import ChatRequestSettings
|
||||
@@ -15,7 +14,7 @@ class ChatCompletionClientBase(ABC):
|
||||
self,
|
||||
messages: List["ChatMessage"],
|
||||
settings: "ChatRequestSettings",
|
||||
logger: Optional[Logger] = None,
|
||||
logger: Optional[Any] = None,
|
||||
) -> Union[str, List[str]]:
|
||||
"""
|
||||
This is the method that is called from the kernel to get a response from a chat-optimized LLM.
|
||||
@@ -24,7 +23,7 @@ class ChatCompletionClientBase(ABC):
|
||||
messages {List[ChatMessage]} -- A list of chat messages, that can be rendered into a
|
||||
set of messages, from system, user, assistant and function.
|
||||
settings {ChatRequestSettings} -- Settings for the request.
|
||||
logger {Logger} -- A logger to use for logging.
|
||||
logger {Logger} -- A logger to use for logging. (Deprecated)
|
||||
|
||||
Returns:
|
||||
Union[str, List[str]] -- A string or list of strings representing the response(s) from the LLM.
|
||||
@@ -36,7 +35,7 @@ class ChatCompletionClientBase(ABC):
|
||||
self,
|
||||
messages: List["ChatMessage"],
|
||||
settings: "ChatRequestSettings",
|
||||
logger: Optional[Logger] = None,
|
||||
logger: Optional[Any] = None,
|
||||
) -> AsyncGenerator[Union[str, List[str]], None]:
|
||||
"""
|
||||
This is the method that is called from the kernel to get a stream response from a chat-optimized LLM.
|
||||
@@ -45,7 +44,7 @@ class ChatCompletionClientBase(ABC):
|
||||
messages {List[ChatMessage]} -- A list of chat messages, that can be rendered into a
|
||||
set of messages, from system, user, assistant and function.
|
||||
settings {ChatRequestSettings} -- Settings for the request.
|
||||
logger {Logger} -- A logger to use for logging.
|
||||
logger {Logger} -- A logger to use for logging. (Deprecated)
|
||||
|
||||
Yields:
|
||||
A stream representing the response(s) from the LLM.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
from typing import List, Optional, Tuple, Union
|
||||
import logging
|
||||
from typing import Any, List, Optional, Tuple, Union
|
||||
|
||||
import google.generativeai as palm
|
||||
from google.generativeai.types import ChatResponse, ExampleOptions, MessagePromptOptions
|
||||
@@ -20,6 +20,8 @@ from semantic_kernel.connectors.ai.text_completion_client_base import (
|
||||
TextCompletionClientBase,
|
||||
)
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GooglePalmChatCompletion(
|
||||
ChatCompletionClientBase, TextCompletionClientBase, AIServiceClientBase
|
||||
@@ -32,7 +34,7 @@ class GooglePalmChatCompletion(
|
||||
ai_model_id: str,
|
||||
api_key: str,
|
||||
message_history: Optional[ChatResponse] = None,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
):
|
||||
"""
|
||||
Initializes a new instance of the GooglePalmChatCompletion class.
|
||||
@@ -43,13 +45,16 @@ class GooglePalmChatCompletion(
|
||||
api_key {str} -- GooglePalm API key, see
|
||||
https://developers.generativeai.google/products/palm
|
||||
message_history {Optional[ChatResponse]} -- The message history to use for context. (Optional)
|
||||
log {Optional[Logger]} -- The logger instance to use. (Optional)
|
||||
log {Optional[Any]} -- A logger to use for logging. (Optional)
|
||||
"""
|
||||
super().__init__(
|
||||
ai_model_id=ai_model_id,
|
||||
api_key=api_key,
|
||||
log=log,
|
||||
)
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
self._message_history = message_history
|
||||
|
||||
async def complete_chat_async(
|
||||
@@ -89,8 +94,12 @@ class GooglePalmChatCompletion(
|
||||
self,
|
||||
prompt: str,
|
||||
request_settings: CompleteRequestSettings,
|
||||
logger: Optional[Logger] = None,
|
||||
**kwargs,
|
||||
) -> Union[str, List[str]]:
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
prompt_to_message = [("user", prompt)]
|
||||
chat_settings = ChatRequestSettings(
|
||||
temperature=request_settings.temperature,
|
||||
@@ -118,8 +127,12 @@ class GooglePalmChatCompletion(
|
||||
self,
|
||||
prompt: str,
|
||||
request_settings: CompleteRequestSettings,
|
||||
logger: Optional[Logger] = None,
|
||||
**kwargs,
|
||||
):
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
raise NotImplementedError(
|
||||
"Google Palm API does not currently support streaming"
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
from typing import List, Optional, Union
|
||||
import logging
|
||||
from typing import Any, List, Optional, Union
|
||||
|
||||
import google.generativeai as palm
|
||||
from pydantic import constr
|
||||
@@ -15,11 +15,13 @@ from semantic_kernel.connectors.ai.text_completion_client_base import (
|
||||
TextCompletionClientBase,
|
||||
)
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GooglePalmTextCompletion(TextCompletionClientBase, AIServiceClientBase):
|
||||
api_key: constr(strip_whitespace=True, min_length=1)
|
||||
|
||||
def __init__(self, ai_model_id: str, api_key: str, log: Optional[Logger] = None):
|
||||
def __init__(self, ai_model_id: str, api_key: str, log: Optional[Any] = None):
|
||||
"""
|
||||
Initializes a new instance of the GooglePalmTextCompletion class.
|
||||
|
||||
@@ -28,16 +30,24 @@ class GooglePalmTextCompletion(TextCompletionClientBase, AIServiceClientBase):
|
||||
https://developers.generativeai.google/models/language
|
||||
api_key {str} -- GooglePalm API key, see
|
||||
https://developers.generativeai.google/products/palm
|
||||
log {Optional[Logger]} -- The logger instance to use. (Optional)
|
||||
log {Optional[Any]} -- The logger instance to use. (Optional) (Deprecated)
|
||||
"""
|
||||
super().__init__(ai_model_id=ai_model_id, api_key=api_key, log=log)
|
||||
super().__init__(ai_model_id=ai_model_id, api_key=api_key)
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
|
||||
async def complete_async(
|
||||
self,
|
||||
prompt: str,
|
||||
request_settings: CompleteRequestSettings,
|
||||
logger: Optional[Logger] = None,
|
||||
**kwargs,
|
||||
) -> Union[str, List[str]]:
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
response = await self._send_completion_request(prompt, request_settings)
|
||||
|
||||
if request_settings.number_of_responses > 1:
|
||||
@@ -48,8 +58,12 @@ class GooglePalmTextCompletion(TextCompletionClientBase, AIServiceClientBase):
|
||||
self,
|
||||
prompt: str,
|
||||
request_settings: CompleteRequestSettings,
|
||||
logger: Optional[Logger] = None,
|
||||
**kwargs,
|
||||
):
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
raise NotImplementedError(
|
||||
"Google Palm API does not currently support streaming"
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
import logging
|
||||
from threading import Thread
|
||||
from typing import Any, Dict, List, Literal, Optional, Union
|
||||
|
||||
@@ -16,6 +16,8 @@ from semantic_kernel.connectors.ai.text_completion_client_base import (
|
||||
TextCompletionClientBase,
|
||||
)
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HuggingFaceTextCompletion(TextCompletionClientBase, AIServiceClientBase):
|
||||
task: Literal["summarization", "text-generation", "text2text-generation"]
|
||||
@@ -27,7 +29,7 @@ class HuggingFaceTextCompletion(TextCompletionClientBase, AIServiceClientBase):
|
||||
ai_model_id: str,
|
||||
task: Optional[str] = "text2text-generation",
|
||||
device: Optional[int] = -1,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
model_kwargs: Optional[Dict[str, Any]] = None,
|
||||
pipeline_kwargs: Optional[Dict[str, Any]] = None,
|
||||
) -> None:
|
||||
@@ -46,7 +48,7 @@ class HuggingFaceTextCompletion(TextCompletionClientBase, AIServiceClientBase):
|
||||
- text-generation: takes incomplete text and returns a set of completion candidates.
|
||||
- text2text-generation (default): takes an input prompt and returns a completion.
|
||||
text2text-generation is the default as it behaves more like GPT-3+.
|
||||
log {Optional[Logger]} -- Logger instance.
|
||||
log -- Logger instance. (Deprecated)
|
||||
model_kwargs {Optional[Dict[str, Any]]} -- Additional dictionary of keyword arguments
|
||||
passed along to the model's `from_pretrained(..., **model_kwargs)` function.
|
||||
pipeline_kwargs {Optional[Dict[str, Any]]} -- Additional keyword arguments passed along
|
||||
@@ -68,15 +70,22 @@ class HuggingFaceTextCompletion(TextCompletionClientBase, AIServiceClientBase):
|
||||
model_kwargs=model_kwargs,
|
||||
**pipeline_kwargs or {},
|
||||
),
|
||||
log=log,
|
||||
)
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
|
||||
async def complete_async(
|
||||
self,
|
||||
prompt: str,
|
||||
request_settings: CompleteRequestSettings,
|
||||
logger: Optional[Logger] = None,
|
||||
**kwargs,
|
||||
) -> Union[str, List[str]]:
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
try:
|
||||
generation_config = transformers.GenerationConfig(
|
||||
temperature=request_settings.temperature,
|
||||
@@ -113,7 +122,7 @@ class HuggingFaceTextCompletion(TextCompletionClientBase, AIServiceClientBase):
|
||||
self,
|
||||
prompt: str,
|
||||
request_settings: CompleteRequestSettings,
|
||||
logger: Optional[Logger] = None,
|
||||
**kwargs,
|
||||
):
|
||||
"""
|
||||
Streams a text completion using a Hugging Face model.
|
||||
@@ -126,6 +135,10 @@ class HuggingFaceTextCompletion(TextCompletionClientBase, AIServiceClientBase):
|
||||
Yields:
|
||||
str -- Completion result.
|
||||
"""
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
if request_settings.number_of_responses > 1:
|
||||
raise AIException(
|
||||
AIException.ErrorCodes.InvalidConfiguration,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
from typing import List, Optional
|
||||
import logging
|
||||
from typing import Any, List, Optional
|
||||
|
||||
import sentence_transformers
|
||||
import torch
|
||||
@@ -13,6 +13,8 @@ from semantic_kernel.connectors.ai.embeddings.embedding_generator_base import (
|
||||
EmbeddingGeneratorBase,
|
||||
)
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HuggingFaceTextEmbedding(EmbeddingGeneratorBase, AIServiceClientBase):
|
||||
device: str
|
||||
@@ -22,7 +24,7 @@ class HuggingFaceTextEmbedding(EmbeddingGeneratorBase, AIServiceClientBase):
|
||||
self,
|
||||
ai_model_id: str,
|
||||
device: Optional[int] = -1,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initializes a new instance of the HuggingFaceTextEmbedding class.
|
||||
@@ -31,16 +33,19 @@ class HuggingFaceTextEmbedding(EmbeddingGeneratorBase, AIServiceClientBase):
|
||||
ai_model_id {str} -- Hugging Face model card string, see
|
||||
https://huggingface.co/sentence-transformers
|
||||
device {Optional[int]} -- Device to run the model on, -1 for CPU, 0+ for GPU.
|
||||
log {Optional[Logger]} -- Logger instance.
|
||||
log -- The logger instance to use. (Optional) (Deprecated)
|
||||
|
||||
Note that this model will be downloaded from the Hugging Face model hub.
|
||||
"""
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
resolved_device = (
|
||||
f"cuda:{device}" if device >= 0 and torch.cuda.is_available() else "cpu"
|
||||
)
|
||||
super().__init__(
|
||||
ai_model_id=ai_model_id,
|
||||
log=log,
|
||||
device=resolved_device,
|
||||
generator=sentence_transformers.SentenceTransformer(
|
||||
model_name_or_path=ai_model_id, device=resolved_device
|
||||
@@ -58,7 +63,7 @@ class HuggingFaceTextEmbedding(EmbeddingGeneratorBase, AIServiceClientBase):
|
||||
ndarray -- Embeddings for the texts.
|
||||
"""
|
||||
try:
|
||||
self.log.info(f"Generating embeddings for {len(texts)} texts")
|
||||
logger.info(f"Generating embeddings for {len(texts)} texts")
|
||||
embeddings = self.generator.encode(texts)
|
||||
return array(embeddings)
|
||||
except Exception as e:
|
||||
|
||||
+13
-9
@@ -1,6 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
import logging
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat.function_call import FunctionCall
|
||||
@@ -16,6 +16,8 @@ from semantic_kernel.template_engine.protocols.prompt_templating_engine import (
|
||||
PromptTemplatingEngine,
|
||||
)
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OpenAIChatPromptTemplate(ChatPromptTemplate):
|
||||
def add_function_response_message(self, name: str, content: Any) -> None:
|
||||
@@ -38,16 +40,14 @@ class OpenAIChatPromptTemplate(ChatPromptTemplate):
|
||||
"""
|
||||
name = kwargs.get("name")
|
||||
if name is not None and role != "function":
|
||||
self._log.warning("name is only used with role: function, ignoring")
|
||||
logger.warning("name is only used with role: function, ignoring")
|
||||
name = None
|
||||
function_call = kwargs.get("function_call")
|
||||
if function_call is not None and role != "assistant":
|
||||
self._log.warning(
|
||||
"function_call is only used with role: assistant, ignoring"
|
||||
)
|
||||
logger.warning("function_call is only used with role: assistant, ignoring")
|
||||
function_call = None
|
||||
if function_call and not isinstance(function_call, FunctionCall):
|
||||
self._log.warning(
|
||||
logger.warning(
|
||||
"function_call is not a FunctionCall, ignoring: %s", function_call
|
||||
)
|
||||
function_call = None
|
||||
@@ -69,7 +69,7 @@ class OpenAIChatPromptTemplate(ChatPromptTemplate):
|
||||
template: str,
|
||||
template_engine: PromptTemplatingEngine,
|
||||
prompt_config: PromptTemplateConfig,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> "OpenAIChatPromptTemplate":
|
||||
"""Restore a ChatPromptTemplate from a list of role and message pairs.
|
||||
|
||||
@@ -77,7 +77,11 @@ class OpenAIChatPromptTemplate(ChatPromptTemplate):
|
||||
that takes precedence over the first message in the list of messages,
|
||||
if that is a system message.
|
||||
"""
|
||||
chat_template = cls(template, template_engine, prompt_config, log)
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
chat_template = cls(template, template_engine, prompt_config)
|
||||
if (
|
||||
prompt_config.completion.chat_system_prompt
|
||||
and messages[0]["role"] == "system"
|
||||
@@ -87,7 +91,7 @@ class OpenAIChatPromptTemplate(ChatPromptTemplate):
|
||||
existing_system_message["message"]
|
||||
!= prompt_config.completion.chat_system_prompt
|
||||
):
|
||||
chat_template._log.info(
|
||||
logger.info(
|
||||
"Overriding system prompt with chat_system_prompt, old system message: %s, new system message: %s",
|
||||
existing_system_message["message"],
|
||||
prompt_config.completion.chat_system_prompt,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
|
||||
import logging
|
||||
from dataclasses import asdict
|
||||
from logging import Logger
|
||||
from typing import (
|
||||
Any,
|
||||
AsyncGenerator,
|
||||
@@ -39,6 +39,8 @@ from semantic_kernel.connectors.ai.open_ai.services.open_ai_text_completion_base
|
||||
from semantic_kernel.connectors.ai.open_ai.utils import _parse_message
|
||||
from semantic_kernel.sk_pydantic import HttpsUrl
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AzureChatCompletion(
|
||||
AzureOpenAIConfigBase, OpenAIChatCompletionBase, OpenAITextCompletionBase
|
||||
@@ -55,7 +57,7 @@ class AzureChatCompletion(
|
||||
ad_token: Optional[str] = None,
|
||||
ad_token_provider: Optional[AsyncAzureADTokenProvider] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an AzureChatCompletion service.
|
||||
@@ -80,7 +82,7 @@ class AzureChatCompletion(
|
||||
The default value is False.
|
||||
default_headers: The default headers mapping of string keys to
|
||||
string values for HTTP requests. (Optional)
|
||||
log: The logger instance to use. (Optional)
|
||||
log: The logger instance to use. (Optional) (Deprecated)
|
||||
logger: deprecated, use 'log' instead.
|
||||
"""
|
||||
|
||||
@@ -94,7 +96,7 @@ class AzureChatCompletion(
|
||||
ad_token: Optional[str] = None,
|
||||
ad_token_provider: Optional[AsyncAzureADTokenProvider] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an AzureChatCompletion service.
|
||||
@@ -117,7 +119,7 @@ class AzureChatCompletion(
|
||||
The default value is False.
|
||||
default_headers: The default headers mapping of string keys to
|
||||
string values for HTTP requests. (Optional)
|
||||
log: The logger instance to use. (Optional)
|
||||
log: The logger instance to use. (Optional) (Deprecated)
|
||||
logger: deprecated, use 'log' instead.
|
||||
"""
|
||||
|
||||
@@ -126,7 +128,7 @@ class AzureChatCompletion(
|
||||
self,
|
||||
deployment_name: str,
|
||||
async_client: AsyncAzureOpenAI,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an AzureChatCompletion service.
|
||||
@@ -138,7 +140,7 @@ class AzureChatCompletion(
|
||||
Resource Management > Deployments in the Azure portal or, alternatively,
|
||||
under Management > Deployments in Azure OpenAI Studio.
|
||||
async_client {AsyncAzureOpenAI} -- An existing client to use.
|
||||
log: The logger instance to use. (Optional)
|
||||
log: The logger instance to use. (Optional) (Deprecated)
|
||||
"""
|
||||
|
||||
@overload
|
||||
@@ -151,7 +153,7 @@ class AzureChatCompletion(
|
||||
ad_token: Optional[str] = None,
|
||||
ad_token_provider: Optional[AsyncAzureADTokenProvider] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
use_extensions: bool = False,
|
||||
) -> None:
|
||||
"""
|
||||
@@ -191,10 +193,10 @@ class AzureChatCompletion(
|
||||
ad_token: Optional[str] = None,
|
||||
ad_token_provider: Optional[AsyncAzureADTokenProvider] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Logger] = None,
|
||||
logger: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
async_client: Optional[AsyncAzureOpenAI] = None,
|
||||
use_extensions: bool = False,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an AzureChatCompletion service.
|
||||
@@ -223,15 +225,21 @@ class AzureChatCompletion(
|
||||
The default value is False.
|
||||
default_headers: The default headers mapping of string keys to
|
||||
string values for HTTP requests. (Optional)
|
||||
log: The logger instance to use. (Optional)
|
||||
logger: deprecated, use 'log' instead.
|
||||
log: The logger instance to use. (Optional) (Deprecated)
|
||||
logger: deprecated.
|
||||
async_client {Optional[AsyncAzureOpenAI]} -- An existing client to use. (Optional)
|
||||
use_extensions: Whether to use extensions, for example when chatting with data. (Optional)
|
||||
When True, base_url is overwritten to '{endpoint}/openai/deployments/{deployment_name}/extensions'.
|
||||
The default value is False.
|
||||
"""
|
||||
if logger:
|
||||
logger.warning("The 'logger' argument is deprecated, use 'log' instead.")
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The 'logger' argument is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
|
||||
if use_extensions:
|
||||
base_url = f"{str(endpoint).rstrip('/')}/openai/deployments/{deployment_name}/extensions"
|
||||
@@ -249,7 +257,6 @@ class AzureChatCompletion(
|
||||
ad_token=ad_token,
|
||||
ad_token_provider=ad_token_provider,
|
||||
default_headers=default_headers,
|
||||
log=log or logger,
|
||||
ai_model_type=OpenAIModelTypes.CHAT,
|
||||
async_client=async_client,
|
||||
)
|
||||
@@ -262,7 +269,7 @@ class AzureChatCompletion(
|
||||
Arguments:
|
||||
settings: A dictionary of settings for the service.
|
||||
should contains keys: deployment_name, endpoint, api_key
|
||||
and optionally: api_version, ad_auth, default_headers, log
|
||||
and optionally: api_version, ad_auth, default_headers
|
||||
"""
|
||||
return AzureChatCompletion(
|
||||
deployment_name=settings.get("deployment_name"),
|
||||
@@ -273,14 +280,13 @@ class AzureChatCompletion(
|
||||
ad_token=settings.get("ad_token"),
|
||||
ad_token_provider=settings.get("ad_token_provider"),
|
||||
default_headers=settings.get("default_headers"),
|
||||
log=settings.get("log"),
|
||||
)
|
||||
|
||||
async def complete_chat_with_data_async(
|
||||
self,
|
||||
messages: List[Dict[str, str]],
|
||||
request_settings: "ChatRequestSettings",
|
||||
logger: Optional[Logger] = None,
|
||||
logger: Optional[Any] = None,
|
||||
functions: Optional[List[Dict[str, Any]]] = None,
|
||||
) -> Union[
|
||||
Tuple[str, str],
|
||||
@@ -293,7 +299,7 @@ class AzureChatCompletion(
|
||||
Arguments:
|
||||
messages {List[Tuple[str,str]]} -- The messages to use for the chat completion.
|
||||
request_settings {ChatRequestSettings} -- The settings to use for the chat completion request.
|
||||
logger {Optional[Logger]} -- The logger instance to use. (Optional)
|
||||
logger -- The logger instance to use. (Optional)
|
||||
functions {Optional[List[Dict[str, Any]]]} -- The functions to use for the chat completion. (Optional)
|
||||
|
||||
Returns:
|
||||
@@ -317,14 +323,14 @@ class AzureChatCompletion(
|
||||
self,
|
||||
messages: List[Dict[str, str]],
|
||||
settings: "ChatRequestSettings",
|
||||
logger: Optional[Logger] = None,
|
||||
logger: Optional[Any] = None,
|
||||
) -> AsyncGenerator[Union[str, List[str]], None]:
|
||||
"""Executes a chat completion request with data and returns the result.
|
||||
|
||||
Arguments:
|
||||
messages {List[Tuple[str,str]]} -- The messages to use for the chat completion.
|
||||
settings {ChatRequestSettings} -- The settings to use for the chat completion request.
|
||||
logger {Optional[Logger]} -- The logger instance to use. (Optional)
|
||||
logger -- The logger instance to use. (Optional)
|
||||
|
||||
Returns:
|
||||
Union[str, List[str]] -- The completion result(s).
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import json
|
||||
from logging import Logger
|
||||
import logging
|
||||
from typing import Any, Awaitable, Callable, Dict, Mapping, Optional, Union
|
||||
|
||||
from openai import AsyncAzureOpenAI
|
||||
@@ -19,6 +19,8 @@ from semantic_kernel.connectors.ai.open_ai.services.open_ai_handler import (
|
||||
from semantic_kernel.connectors.telemetry import APP_INFO
|
||||
from semantic_kernel.sk_pydantic import HttpsUrl
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AzureOpenAIConfigBase(OpenAIHandler):
|
||||
"""Internal class for configuring a connection to an Azure OpenAI service."""
|
||||
@@ -35,7 +37,7 @@ class AzureOpenAIConfigBase(OpenAIHandler):
|
||||
ad_token: Optional[str] = None,
|
||||
ad_token_provider: Optional[Callable[[], Union[str, Awaitable[str]]]] = None,
|
||||
default_headers: Union[Mapping[str, str], None] = None,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
async_client: Optional[AsyncAzureOpenAI] = None,
|
||||
) -> None:
|
||||
"""Internal class for configuring a connection to an Azure OpenAI service.
|
||||
@@ -51,12 +53,16 @@ class AzureOpenAIConfigBase(OpenAIHandler):
|
||||
ad_token_provider {Optional[Callable[[], Union[str, Awaitable[str]]]]} -- A callable
|
||||
or coroutine function providing Azure AD tokens. (Optional)
|
||||
default_headers {Union[Mapping[str, str], None]} -- Default headers for HTTP requests. (Optional)
|
||||
log {Optional[Logger]} -- Logger instance for logging purposes. (Optional)
|
||||
log -- Logger instance for logging purposes. (Optional) (Deprecated)
|
||||
async_client {Optional[AsyncAzureOpenAI]} -- An existing client to use. (Optional)
|
||||
|
||||
The `validate_call` decorator is used with a configuration that allows arbitrary types.
|
||||
This is necessary for types like `HttpsUrl` and `OpenAIModelTypes`.
|
||||
"""
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
# Merge APP_INFO into the headers if it exists
|
||||
merged_headers = default_headers.copy() if default_headers else {}
|
||||
if APP_INFO:
|
||||
@@ -95,7 +101,6 @@ class AzureOpenAIConfigBase(OpenAIHandler):
|
||||
|
||||
super().__init__(
|
||||
ai_model_id=deployment_name,
|
||||
log=log,
|
||||
client=async_client,
|
||||
ai_model_type=ai_model_type,
|
||||
)
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
|
||||
from logging import Logger
|
||||
from typing import Dict, Mapping, Optional, overload
|
||||
import logging
|
||||
from typing import Any, Dict, Mapping, Optional, overload
|
||||
|
||||
from openai import AsyncAzureOpenAI
|
||||
from openai.lib.azure import AsyncAzureADTokenProvider
|
||||
@@ -18,6 +17,8 @@ from semantic_kernel.connectors.ai.open_ai.services.open_ai_text_completion_base
|
||||
OpenAITextCompletionBase,
|
||||
)
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AzureTextCompletion(AzureOpenAIConfigBase, OpenAITextCompletionBase):
|
||||
"""Azure Text Completion class."""
|
||||
@@ -31,7 +32,7 @@ class AzureTextCompletion(AzureOpenAIConfigBase, OpenAITextCompletionBase):
|
||||
ad_token: Optional[str] = None,
|
||||
ad_token_provider: Optional[AsyncAzureADTokenProvider] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an AzureTextCompletion service.
|
||||
@@ -54,8 +55,8 @@ class AzureTextCompletion(AzureOpenAIConfigBase, OpenAITextCompletionBase):
|
||||
The default value is False.
|
||||
default_headers: The default headers mapping of string keys to
|
||||
string values for HTTP requests. (Optional)
|
||||
log: The logger instance to use. (Optional)
|
||||
logger: deprecated, use 'log' instead.
|
||||
log: The logger instance to use. (Optional) (Deprecated)
|
||||
logger: deprecated.
|
||||
"""
|
||||
|
||||
@overload
|
||||
@@ -68,7 +69,7 @@ class AzureTextCompletion(AzureOpenAIConfigBase, OpenAITextCompletionBase):
|
||||
ad_token: Optional[str] = None,
|
||||
ad_token_provider: Optional[AsyncAzureADTokenProvider] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an AzureTextCompletion service.
|
||||
@@ -91,7 +92,7 @@ class AzureTextCompletion(AzureOpenAIConfigBase, OpenAITextCompletionBase):
|
||||
The default value is False.
|
||||
default_headers: The default headers mapping of string keys to
|
||||
string values for HTTP requests. (Optional)
|
||||
log: The logger instance to use. (Optional)
|
||||
log: The logger instance to use. (Optional) (Deprecated)
|
||||
logger: deprecated, use 'log' instead.
|
||||
"""
|
||||
|
||||
@@ -100,7 +101,7 @@ class AzureTextCompletion(AzureOpenAIConfigBase, OpenAITextCompletionBase):
|
||||
self,
|
||||
deployment_name: str,
|
||||
async_client: AsyncAzureOpenAI,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an AzureChatCompletion service.
|
||||
@@ -112,7 +113,7 @@ class AzureTextCompletion(AzureOpenAIConfigBase, OpenAITextCompletionBase):
|
||||
Resource Management > Deployments in the Azure portal or, alternatively,
|
||||
under Management > Deployments in Azure OpenAI Studio.
|
||||
async_client {AsyncAzureOpenAI} -- An existing client to use.
|
||||
log: The logger instance to use. (Optional)
|
||||
log: The logger instance to use. (Optional) (Deprecated)
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -125,9 +126,9 @@ class AzureTextCompletion(AzureOpenAIConfigBase, OpenAITextCompletionBase):
|
||||
ad_token: Optional[str] = None,
|
||||
ad_token_provider: Optional[AsyncAzureADTokenProvider] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Logger] = None,
|
||||
logger: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
async_client: Optional[AsyncAzureOpenAI] = None,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an AzureTextCompletion service.
|
||||
@@ -150,12 +151,16 @@ class AzureTextCompletion(AzureOpenAIConfigBase, OpenAITextCompletionBase):
|
||||
The default value is False.
|
||||
default_headers: The default headers mapping of string keys to
|
||||
string values for HTTP requests. (Optional)
|
||||
log: The logger instance to use. (Optional)
|
||||
log: The logger instance to use. (Optional) (Deprecated)
|
||||
logger: deprecated, use 'log' instead.
|
||||
async_client {Optional[AsyncAzureOpenAI]} -- An existing client to use.
|
||||
"""
|
||||
if logger:
|
||||
logger.warning("The 'logger' argument is deprecated, use 'log' instead.")
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
if kwargs.get("logger"):
|
||||
logger.warning("The 'logger' argument is deprecated.")
|
||||
super().__init__(
|
||||
deployment_name=deployment_name,
|
||||
endpoint=endpoint,
|
||||
@@ -165,7 +170,6 @@ class AzureTextCompletion(AzureOpenAIConfigBase, OpenAITextCompletionBase):
|
||||
ad_token=ad_token,
|
||||
ad_token_provider=ad_token_provider,
|
||||
default_headers=default_headers,
|
||||
log=log or logger,
|
||||
ai_model_type=OpenAIModelTypes.TEXT,
|
||||
async_client=async_client,
|
||||
)
|
||||
@@ -178,7 +182,7 @@ class AzureTextCompletion(AzureOpenAIConfigBase, OpenAITextCompletionBase):
|
||||
Arguments:
|
||||
settings: A dictionary of settings for the service.
|
||||
should contains keys: deployment_name, endpoint, api_key
|
||||
and optionally: api_version, ad_auth, log
|
||||
and optionally: api_version, ad_auth
|
||||
"""
|
||||
|
||||
return AzureTextCompletion(
|
||||
@@ -190,5 +194,4 @@ class AzureTextCompletion(AzureOpenAIConfigBase, OpenAITextCompletionBase):
|
||||
ad_token=settings.get("ad_token"),
|
||||
ad_token_provider=settings.get("ad_token_provider"),
|
||||
default_headers=settings.get("default_headers"),
|
||||
log=settings.get("log"),
|
||||
)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
|
||||
from logging import Logger
|
||||
from typing import Dict, Mapping, Optional, overload
|
||||
import logging
|
||||
from typing import Any, Dict, Mapping, Optional, overload
|
||||
|
||||
from openai import AsyncAzureOpenAI
|
||||
from openai.lib.azure import AsyncAzureADTokenProvider
|
||||
@@ -18,6 +18,8 @@ from semantic_kernel.connectors.ai.open_ai.services.open_ai_text_embedding_base
|
||||
OpenAITextEmbeddingBase,
|
||||
)
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AzureTextEmbedding(AzureOpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
"""Azure Text Embedding class."""
|
||||
@@ -27,7 +29,7 @@ class AzureTextEmbedding(AzureOpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
self,
|
||||
deployment_name: str,
|
||||
async_client: AsyncAzureOpenAI,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an AzureChatCompletion service.
|
||||
@@ -39,7 +41,7 @@ class AzureTextEmbedding(AzureOpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
Resource Management > Deployments in the Azure portal or, alternatively,
|
||||
under Management > Deployments in Azure OpenAI Studio.
|
||||
async_client {AsyncAzureOpenAI} -- An existing client to use.
|
||||
log: The logger instance to use. (Optional)
|
||||
log: The logger instance to use. (Optional) (Deprecated)
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -51,9 +53,9 @@ class AzureTextEmbedding(AzureOpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
ad_token: Optional[str] = None,
|
||||
ad_token_provider: Optional[AsyncAzureADTokenProvider] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Logger] = None,
|
||||
logger: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
async_client: Optional[AsyncAzureOpenAI] = None,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an AzureTextEmbedding service.
|
||||
@@ -79,13 +81,17 @@ class AzureTextEmbedding(AzureOpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
(Optional) The default value is False.
|
||||
:param default_headers: The default headers mapping of string keys to
|
||||
string values for HTTP requests. (Optional)
|
||||
:param log: The logger instance to use. (Optional)
|
||||
:param log: The logger instance to use. (Optional) (Deprecated)
|
||||
:param logger: Deprecated, please use log instead. (Optional)
|
||||
:param async_client: An existing client to use. (Optional)
|
||||
|
||||
"""
|
||||
if logger:
|
||||
logger.warning("The 'logger' argument is deprecated, use 'log' instead.")
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
if kwargs.get("logger"):
|
||||
logger.warning("The 'logger' argument is deprecated.")
|
||||
super().__init__(
|
||||
deployment_name=deployment_name,
|
||||
endpoint=endpoint,
|
||||
@@ -94,7 +100,6 @@ class AzureTextEmbedding(AzureOpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
ad_token=ad_token,
|
||||
ad_token_provider=ad_token_provider,
|
||||
default_headers=default_headers,
|
||||
log=log or logger,
|
||||
ai_model_type=OpenAIModelTypes.EMBEDDING,
|
||||
async_client=async_client,
|
||||
)
|
||||
@@ -107,7 +112,7 @@ class AzureTextEmbedding(AzureOpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
Arguments:
|
||||
settings: A dictionary of settings for the service.
|
||||
should contains keys: deployment_name, endpoint, api_key
|
||||
and optionally: api_version, ad_auth, log
|
||||
and optionally: api_version, ad_auth
|
||||
"""
|
||||
return AzureTextEmbedding(
|
||||
deployment_name=settings["deployment_name"],
|
||||
@@ -117,5 +122,4 @@ class AzureTextEmbedding(AzureOpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
ad_token=settings.get("ad_token"),
|
||||
ad_token_provider=settings.get("ad_token_provider"),
|
||||
default_headers=settings.get("default_headers"),
|
||||
log=settings.get("log"),
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
from typing import Dict, Mapping, Optional, overload
|
||||
import logging
|
||||
from typing import Any, Dict, Mapping, Optional, overload
|
||||
|
||||
from openai import AsyncOpenAI
|
||||
|
||||
@@ -18,6 +18,8 @@ from semantic_kernel.connectors.ai.open_ai.services.open_ai_text_completion_base
|
||||
OpenAITextCompletionBase,
|
||||
)
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OpenAIChatCompletion(
|
||||
OpenAIConfigBase, OpenAIChatCompletionBase, OpenAITextCompletionBase
|
||||
@@ -29,7 +31,7 @@ class OpenAIChatCompletion(
|
||||
self,
|
||||
ai_model_id: str,
|
||||
async_client: AsyncOpenAI,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an OpenAIChatCompletion service.
|
||||
@@ -38,7 +40,7 @@ class OpenAIChatCompletion(
|
||||
ai_model_id {str} -- OpenAI model name, see
|
||||
https://platform.openai.com/docs/models
|
||||
async_client {AsyncOpenAI} -- An existing client to use.
|
||||
log: The logger instance to use. (Optional)
|
||||
log: The logger instance to use. (Optional) (Deprecated)
|
||||
"""
|
||||
|
||||
@overload
|
||||
@@ -48,7 +50,7 @@ class OpenAIChatCompletion(
|
||||
api_key: Optional[str] = None,
|
||||
org_id: Optional[str] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an OpenAIChatCompletion service.
|
||||
@@ -63,7 +65,7 @@ class OpenAIChatCompletion(
|
||||
account belongs to multiple organizations.
|
||||
default_headers: The default headers mapping of string keys to
|
||||
string values for HTTP requests. (Optional)
|
||||
log {Optional[Logger]} -- The logger instance to use. (Optional)
|
||||
log -- The logger instance to use. (Optional) (Deprecated)
|
||||
"""
|
||||
|
||||
@overload
|
||||
@@ -72,7 +74,7 @@ class OpenAIChatCompletion(
|
||||
ai_model_id: str,
|
||||
api_key: Optional[str] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an OpenAIChatCompletion service.
|
||||
@@ -84,7 +86,7 @@ class OpenAIChatCompletion(
|
||||
https://platform.openai.com/account/api-keys
|
||||
default_headers: The default headers mapping of string keys to
|
||||
string values for HTTP requests. (Optional)
|
||||
log {Optional[Logger]} -- The logger instance to use. (Optional)
|
||||
log -- The logger instance to use. (Optional) (Deprecated)
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -93,8 +95,8 @@ class OpenAIChatCompletion(
|
||||
api_key: Optional[str] = None,
|
||||
org_id: Optional[str] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Logger] = None,
|
||||
async_client: Optional[AsyncOpenAI] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an OpenAIChatCompletion service.
|
||||
@@ -109,16 +111,19 @@ class OpenAIChatCompletion(
|
||||
account belongs to multiple organizations.
|
||||
default_headers: The default headers mapping of string keys to
|
||||
string values for HTTP requests. (Optional)
|
||||
log {Optional[Logger]} -- The logger instance to use. (Optional)
|
||||
async_client {Optional[AsyncOpenAI]} -- An existing client to use. (Optional)
|
||||
log -- The logger instance to use. (Optional) (Deprecated)
|
||||
"""
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
super().__init__(
|
||||
ai_model_id=ai_model_id,
|
||||
api_key=api_key,
|
||||
org_id=org_id,
|
||||
ai_model_type=OpenAIModelTypes.CHAT,
|
||||
default_headers=default_headers,
|
||||
log=log,
|
||||
async_client=async_client,
|
||||
)
|
||||
|
||||
@@ -136,5 +141,4 @@ class OpenAIChatCompletion(
|
||||
api_key=settings["api_key"],
|
||||
org_id=settings.get("org_id"),
|
||||
default_headers=settings.get("default_headers"),
|
||||
log=settings.get("log"),
|
||||
)
|
||||
|
||||
+20
-12
@@ -1,6 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
import logging
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
@@ -22,24 +22,29 @@ from semantic_kernel.connectors.ai.open_ai.utils import _parse_message
|
||||
if TYPE_CHECKING:
|
||||
from semantic_kernel.connectors.ai.chat_request_settings import ChatRequestSettings
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OpenAIChatCompletionBase(OpenAIHandler, ChatCompletionClientBase):
|
||||
async def complete_chat_async(
|
||||
self,
|
||||
messages: List[Dict[str, str]],
|
||||
settings: "ChatRequestSettings",
|
||||
logger: Optional[Logger] = None,
|
||||
**kwargs,
|
||||
) -> Union[str, List[str]]:
|
||||
"""Executes a chat completion request and returns the result.
|
||||
|
||||
Arguments:
|
||||
messages {List[Tuple[str,str]]} -- The messages to use for the chat completion.
|
||||
settings {ChatRequestSettings} -- The settings to use for the chat completion request.
|
||||
logger {Optional[Logger]} -- The logger instance to use. (Optional)
|
||||
|
||||
Returns:
|
||||
Union[str, List[str]] -- The completion result(s).
|
||||
"""
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
response = await self._send_request(
|
||||
messages=messages, request_settings=settings, stream=False
|
||||
)
|
||||
@@ -54,7 +59,7 @@ class OpenAIChatCompletionBase(OpenAIHandler, ChatCompletionClientBase):
|
||||
messages: List[Dict[str, str]],
|
||||
functions: List[Dict[str, Any]],
|
||||
request_settings: "ChatRequestSettings",
|
||||
logger: Optional[Logger] = None,
|
||||
**kwargs,
|
||||
) -> Union[
|
||||
Tuple[Optional[str], Optional[FunctionCall]],
|
||||
List[Tuple[Optional[str], Optional[FunctionCall]]],
|
||||
@@ -65,12 +70,14 @@ class OpenAIChatCompletionBase(OpenAIHandler, ChatCompletionClientBase):
|
||||
messages {List[Tuple[str,str]]} -- The messages to use for the chat completion.
|
||||
functions {List[Dict[str, Any]]} -- The functions to use for the chat completion.
|
||||
settings {ChatRequestSettings} -- The settings to use for the chat completion request.
|
||||
logger {Optional[Logger]} -- The logger instance to use. (Optional)
|
||||
|
||||
Returns:
|
||||
Union[str, List[str]] -- The completion result(s).
|
||||
"""
|
||||
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
response = await self._send_request(
|
||||
messages=messages,
|
||||
request_settings=request_settings,
|
||||
@@ -79,28 +86,29 @@ class OpenAIChatCompletionBase(OpenAIHandler, ChatCompletionClientBase):
|
||||
)
|
||||
|
||||
if len(response.choices) == 1:
|
||||
return _parse_message(response.choices[0].message, self.log)
|
||||
return _parse_message(response.choices[0].message)
|
||||
else:
|
||||
return [
|
||||
_parse_message(choice.message, self.log) for choice in response.choices
|
||||
]
|
||||
return [_parse_message(choice.message) for choice in response.choices]
|
||||
|
||||
async def complete_chat_stream_async(
|
||||
self,
|
||||
messages: List[Dict[str, str]],
|
||||
settings: "ChatRequestSettings",
|
||||
logger: Optional[Logger] = None,
|
||||
**kwargs,
|
||||
) -> AsyncGenerator[Union[str, List[str]], None]:
|
||||
"""Executes a chat completion request and returns the result.
|
||||
|
||||
Arguments:
|
||||
messages {List[Tuple[str,str]]} -- The messages to use for the chat completion.
|
||||
settings {ChatRequestSettings} -- The settings to use for the chat completion request.
|
||||
logger {Optional[Logger]} -- The logger instance to use. (Optional)
|
||||
|
||||
Returns:
|
||||
Union[str, List[str]] -- The completion result(s).
|
||||
"""
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
response = await self._send_request(
|
||||
messages=messages, request_settings=settings, stream=True
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import json
|
||||
from logging import Logger
|
||||
import logging
|
||||
from typing import Any, Dict, Mapping, Optional
|
||||
|
||||
from openai import AsyncOpenAI
|
||||
@@ -19,6 +19,8 @@ from semantic_kernel.connectors.ai.open_ai.services.open_ai_model_types import (
|
||||
)
|
||||
from semantic_kernel.connectors.telemetry import APP_INFO
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OpenAIConfigBase(OpenAIHandler):
|
||||
@validate_call(config=dict(arbitrary_types_allowed=True))
|
||||
@@ -30,7 +32,7 @@ class OpenAIConfigBase(OpenAIHandler):
|
||||
org_id: Optional[str] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
async_client: Optional[AsyncOpenAI] = None,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""Initialize a client for OpenAI services.
|
||||
|
||||
@@ -48,10 +50,12 @@ class OpenAIConfigBase(OpenAIHandler):
|
||||
unless the account belongs to multiple organizations.
|
||||
default_headers {Optional[Mapping[str, str]]} -- Default headers
|
||||
for HTTP requests. (Optional)
|
||||
log {Optional[Logger]} -- Logger instance for logging purposes. (Optional)
|
||||
|
||||
"""
|
||||
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
# Merge APP_INFO into the headers if it exists
|
||||
merged_headers = default_headers.copy() if default_headers else {}
|
||||
if APP_INFO:
|
||||
@@ -72,7 +76,6 @@ class OpenAIConfigBase(OpenAIHandler):
|
||||
super().__init__(
|
||||
ai_model_id=ai_model_id,
|
||||
client=async_client,
|
||||
log=log,
|
||||
ai_model_type=ai_model_type,
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Any, Dict, List, Optional, Union
|
||||
|
||||
@@ -19,6 +20,8 @@ from semantic_kernel.connectors.ai.open_ai.services.open_ai_model_types import (
|
||||
OpenAIModelTypes,
|
||||
)
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OpenAIHandler(AIServiceClientBase, ABC):
|
||||
"""Internal class for calls to OpenAI API's."""
|
||||
@@ -78,7 +81,7 @@ class OpenAIHandler(AIServiceClientBase, ABC):
|
||||
ex,
|
||||
) from ex
|
||||
if not isinstance(response, AsyncStream):
|
||||
self.log.info(f"OpenAI usage: {response.usage}")
|
||||
logger.info(f"OpenAI usage: {response.usage}")
|
||||
self.prompt_tokens += response.usage.prompt_tokens
|
||||
self.completion_tokens += response.usage.completion_tokens
|
||||
self.total_tokens += response.usage.total_tokens
|
||||
@@ -185,7 +188,7 @@ class OpenAIHandler(AIServiceClientBase, ABC):
|
||||
# TODO: the openai response is cast to a list[float], could be used instead of nparray
|
||||
raw_embeddings.extend([array(x.embedding) for x in response.data])
|
||||
if response.usage:
|
||||
self.log.info(f"OpenAI usage: {response.usage}")
|
||||
logger.info(f"OpenAI usage: {response.usage}")
|
||||
self.prompt_tokens += response.usage.prompt_tokens
|
||||
self.total_tokens += response.usage.total_tokens
|
||||
return array(raw_embeddings)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
from typing import Dict, Mapping, Optional, overload
|
||||
import logging
|
||||
from typing import Any, Dict, Mapping, Optional, overload
|
||||
|
||||
from openai import AsyncOpenAI
|
||||
|
||||
@@ -15,6 +15,8 @@ from semantic_kernel.connectors.ai.open_ai.services.open_ai_text_completion_base
|
||||
OpenAITextCompletionBase,
|
||||
)
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OpenAITextCompletion(OpenAITextCompletionBase, OpenAIConfigBase):
|
||||
"""OpenAI Text Completion class."""
|
||||
@@ -24,7 +26,7 @@ class OpenAITextCompletion(OpenAITextCompletionBase, OpenAIConfigBase):
|
||||
self,
|
||||
ai_model_id: str,
|
||||
async_client: AsyncOpenAI,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an OpenAITextCompletion service.
|
||||
@@ -33,7 +35,6 @@ class OpenAITextCompletion(OpenAITextCompletionBase, OpenAIConfigBase):
|
||||
ai_model_id {str} -- OpenAI model name, see
|
||||
https://platform.openai.com/docs/models
|
||||
async_client {AsyncOpenAI} -- An existing client to use.
|
||||
log: The logger instance to use. (Optional)
|
||||
"""
|
||||
|
||||
@overload
|
||||
@@ -43,7 +44,7 @@ class OpenAITextCompletion(OpenAITextCompletionBase, OpenAIConfigBase):
|
||||
api_key: Optional[str] = None,
|
||||
org_id: Optional[str] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an OpenAITextCompletion service.
|
||||
@@ -58,7 +59,6 @@ class OpenAITextCompletion(OpenAITextCompletionBase, OpenAIConfigBase):
|
||||
account belongs to multiple organizations.
|
||||
default_headers: The default headers mapping of string keys to
|
||||
string values for HTTP requests. (Optional)
|
||||
log {Optional[Logger]} -- The logger instance to use. (Optional)
|
||||
"""
|
||||
|
||||
@overload
|
||||
@@ -67,7 +67,7 @@ class OpenAITextCompletion(OpenAITextCompletionBase, OpenAIConfigBase):
|
||||
ai_model_id: str,
|
||||
api_key: Optional[str] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an OpenAITextCompletion service.
|
||||
@@ -79,7 +79,6 @@ class OpenAITextCompletion(OpenAITextCompletionBase, OpenAIConfigBase):
|
||||
https://platform.openai.com/account/api-keys (Optional)
|
||||
default_headers: The default headers mapping of string keys to
|
||||
string values for HTTP requests. (Optional)
|
||||
log {Optional[Logger]} -- The logger instance to use. (Optional)
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -88,7 +87,7 @@ class OpenAITextCompletion(OpenAITextCompletionBase, OpenAIConfigBase):
|
||||
api_key: Optional[str] = None,
|
||||
org_id: Optional[str] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
async_client: Optional[AsyncOpenAI] = None,
|
||||
) -> None:
|
||||
"""
|
||||
@@ -104,14 +103,16 @@ class OpenAITextCompletion(OpenAITextCompletionBase, OpenAIConfigBase):
|
||||
account belongs to multiple organizations.
|
||||
default_headers: The default headers mapping of string keys to
|
||||
string values for HTTP requests. (Optional)
|
||||
log {Optional[Logger]} -- The logger instance to use. (Optional)
|
||||
async_client {Optional[AsyncOpenAI]} -- An existing client to use. (Optional)
|
||||
"""
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
super().__init__(
|
||||
ai_model_id=ai_model_id,
|
||||
api_key=api_key,
|
||||
org_id=org_id,
|
||||
log=log,
|
||||
ai_model_type=OpenAIModelTypes.TEXT,
|
||||
default_headers=default_headers,
|
||||
async_client=async_client,
|
||||
@@ -131,5 +132,4 @@ class OpenAITextCompletion(OpenAITextCompletionBase, OpenAIConfigBase):
|
||||
api_key=settings["api_key"],
|
||||
org_id=settings.get("org_id"),
|
||||
default_headers=settings.get("default_headers"),
|
||||
log=settings.get("log"),
|
||||
)
|
||||
|
||||
+14
-6
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
from typing import TYPE_CHECKING, AsyncGenerator, List, Optional, Union
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, AsyncGenerator, List, Union
|
||||
|
||||
from openai.types.completion import Completion
|
||||
|
||||
@@ -15,24 +15,29 @@ if TYPE_CHECKING:
|
||||
CompleteRequestSettings,
|
||||
)
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OpenAITextCompletionBase(TextCompletionClientBase, OpenAIHandler):
|
||||
async def complete_async(
|
||||
self,
|
||||
prompt: str,
|
||||
settings: "CompleteRequestSettings",
|
||||
logger: Optional[Logger] = None,
|
||||
**kwargs,
|
||||
) -> Union[str, List[str]]:
|
||||
"""Executes a completion request and returns the result.
|
||||
|
||||
Arguments:
|
||||
prompt {str} -- The prompt to use for the completion request.
|
||||
settings {CompleteRequestSettings} -- The settings to use for the completion request.
|
||||
logger {Optional[Logger]} -- The logger instance to use. (Optional)
|
||||
|
||||
Returns:
|
||||
Union[str, List[str]] -- The completion result(s).
|
||||
"""
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
response = await self._send_request(
|
||||
prompt=prompt, request_settings=settings, stream=False
|
||||
)
|
||||
@@ -49,7 +54,7 @@ class OpenAITextCompletionBase(TextCompletionClientBase, OpenAIHandler):
|
||||
self,
|
||||
prompt: str,
|
||||
settings: "CompleteRequestSettings",
|
||||
logger: Optional[Logger] = None,
|
||||
**kwargs,
|
||||
) -> AsyncGenerator[Union[str, List[str]], None]:
|
||||
"""
|
||||
Executes a completion request and streams the result.
|
||||
@@ -58,11 +63,14 @@ class OpenAITextCompletionBase(TextCompletionClientBase, OpenAIHandler):
|
||||
Arguments:
|
||||
prompt {str} -- The prompt to use for the completion request.
|
||||
settings {CompleteRequestSettings} -- The settings to use for the completion request.
|
||||
logger {Optional[Logger]} -- The logger instance to use. (Optional)
|
||||
|
||||
Returns:
|
||||
Union[str, List[str]] -- The completion result(s).
|
||||
"""
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
response = await self._send_request(
|
||||
prompt=prompt, request_settings=settings, stream=True
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
from typing import Dict, Mapping, Optional, overload
|
||||
import logging
|
||||
from typing import Any, Dict, Mapping, Optional, overload
|
||||
|
||||
from openai import AsyncOpenAI
|
||||
|
||||
@@ -15,6 +15,8 @@ from semantic_kernel.connectors.ai.open_ai.services.open_ai_text_embedding_base
|
||||
OpenAITextEmbeddingBase,
|
||||
)
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OpenAITextEmbedding(OpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
"""OpenAI Text Embedding class."""
|
||||
@@ -24,7 +26,7 @@ class OpenAITextEmbedding(OpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
self,
|
||||
ai_model_id: str,
|
||||
async_client: AsyncOpenAI,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an OpenAITextEmbedding service.
|
||||
@@ -33,7 +35,6 @@ class OpenAITextEmbedding(OpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
ai_model_id {str} -- OpenAI model name, see
|
||||
https://platform.openai.com/docs/models
|
||||
async_client {AsyncOpenAI} -- An existing client to use.
|
||||
log: The logger instance to use. (Optional)
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -42,8 +43,8 @@ class OpenAITextEmbedding(OpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
api_key: Optional[str] = None,
|
||||
org_id: Optional[str] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Logger] = None,
|
||||
async_client: Optional[AsyncOpenAI] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initializes a new instance of the OpenAITextCompletion class.
|
||||
@@ -58,7 +59,6 @@ class OpenAITextEmbedding(OpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
account belongs to multiple organizations.
|
||||
default_headers {Optional[Mapping[str,str]]}: The default headers mapping of string keys to
|
||||
string values for HTTP requests. (Optional)
|
||||
log {Optional[Logger]} -- The logger instance to use. (Optional)
|
||||
async_client {Optional[AsyncOpenAI]} -- An existing client to use. (Optional)
|
||||
"""
|
||||
super().__init__(
|
||||
@@ -67,9 +67,12 @@ class OpenAITextEmbedding(OpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
ai_model_type=OpenAIModelTypes.EMBEDDING,
|
||||
org_id=org_id,
|
||||
default_headers=default_headers,
|
||||
log=log,
|
||||
async_client=async_client,
|
||||
)
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, settings: Dict[str, str]) -> "OpenAITextEmbedding":
|
||||
@@ -85,5 +88,4 @@ class OpenAITextEmbedding(OpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
api_key=settings["api_key"],
|
||||
org_id=settings.get("org_id"),
|
||||
default_headers=settings.get("default_headers"),
|
||||
log=settings.get("log"),
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
import logging
|
||||
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||
|
||||
from openai.types.chat import ChatCompletion
|
||||
@@ -12,6 +12,8 @@ from semantic_kernel.connectors.ai.open_ai.semantic_functions.open_ai_chat_promp
|
||||
)
|
||||
from semantic_kernel.orchestration.sk_function_base import SKFunctionBase
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _describe_function(function: SKFunctionBase) -> Dict[str, str]:
|
||||
"""Create the object used for function_calling.
|
||||
@@ -101,14 +103,17 @@ def get_function_calling_object(
|
||||
|
||||
|
||||
async def execute_function_call(
|
||||
kernel: Kernel, function_call: FunctionCall, log: Optional[Logger] = None
|
||||
kernel: Kernel, function_call: FunctionCall, log: Optional[Any] = None
|
||||
) -> str:
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
result = await kernel.run_async(
|
||||
kernel.func(**function_call.split_name_dict()),
|
||||
input_vars=function_call.to_context_variables(),
|
||||
)
|
||||
if log:
|
||||
log.info(f"Function call result: {result}")
|
||||
logger.info(f"Function call result: {result}")
|
||||
return str(result)
|
||||
|
||||
|
||||
@@ -120,7 +125,7 @@ async def chat_completion_with_function_call(
|
||||
chat_function_name: Optional[str] = None,
|
||||
chat_function: Optional[SKFunctionBase] = None,
|
||||
*,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
**kwargs: Dict[str, Any],
|
||||
) -> SKContext:
|
||||
"""Perform a chat completion with auto-executing function calling.
|
||||
@@ -144,13 +149,16 @@ async def chat_completion_with_function_call(
|
||||
chat_function: the chat function, if not provided, it will be retrieved from the kernel.
|
||||
make sure to provide either the chat_function or the chat_skill_name and chat_function_name.
|
||||
|
||||
log: the logger to use.
|
||||
max_function_calls: the maximum number of function calls to execute, defaults to 5.
|
||||
current_call_count: the current number of function calls executed.
|
||||
|
||||
returns:
|
||||
the context with the result of the chat completion, just like a regular invoke_async/run_async.
|
||||
"""
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
# check the number of function calls
|
||||
max_function_calls = kwargs.get("max_function_calls", 5)
|
||||
current_call_count = kwargs.get("current_call_count", 0)
|
||||
@@ -171,7 +179,7 @@ async def chat_completion_with_function_call(
|
||||
# if there is no function_call or if the content is not a FunctionCall object, return the context
|
||||
if function_call is None or not isinstance(function_call, FunctionCall):
|
||||
return context
|
||||
result = await execute_function_call(kernel, function_call, log=log)
|
||||
result = await execute_function_call(kernel, function_call)
|
||||
# add the result to the chat prompt template
|
||||
chat_function._chat_prompt_template.add_function_response_message(
|
||||
name=function_call.name, content=str(result)
|
||||
@@ -182,14 +190,13 @@ async def chat_completion_with_function_call(
|
||||
chat_function=chat_function,
|
||||
functions=functions,
|
||||
context=context,
|
||||
log=log,
|
||||
max_function_calls=max_function_calls,
|
||||
current_call_count=current_call_count + 1,
|
||||
)
|
||||
|
||||
|
||||
def _parse_message(
|
||||
message: ChatCompletion, logger: Optional[Logger] = None, with_data: bool = False
|
||||
message: ChatCompletion, with_data: bool = False, **kwargs
|
||||
) -> Union[
|
||||
Tuple[Optional[str], Optional[FunctionCall]],
|
||||
Tuple[Optional[str], Optional[str], Optional[FunctionCall]],
|
||||
@@ -203,6 +210,10 @@ def _parse_message(
|
||||
Returns:
|
||||
Tuple[Optional[str], Optional[Dict]] -- The parsed message.
|
||||
"""
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
content = message.content if hasattr(message, "content") else None
|
||||
function_call = message.function_call if hasattr(message, "function_call") else None
|
||||
if function_call:
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from logging import Logger
|
||||
from typing import TYPE_CHECKING, AsyncGenerator, List, Optional, Union
|
||||
from typing import TYPE_CHECKING, Any, AsyncGenerator, List, Optional, Union
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from semantic_kernel.connectors.ai.complete_request_settings import (
|
||||
@@ -19,7 +18,7 @@ class TextCompletionClientBase(ABC):
|
||||
self,
|
||||
prompt: str,
|
||||
settings: "CompleteRequestSettings",
|
||||
logger: Optional[Logger] = None,
|
||||
logger: Optional[Any] = None,
|
||||
) -> Union[str, List[str]]:
|
||||
"""
|
||||
This is the method that is called from the kernel to get a response from a text-optimized LLM.
|
||||
@@ -27,7 +26,6 @@ class TextCompletionClientBase(ABC):
|
||||
Arguments:
|
||||
prompt {str} -- The prompt to send to the LLM.
|
||||
settings {CompleteRequestSettings} -- Settings for the request.
|
||||
logger {Logger} -- A logger to use for logging.
|
||||
|
||||
Returns:
|
||||
Union[str, List[str]] -- A string or list of strings representing the response(s) from the LLM.
|
||||
@@ -38,7 +36,7 @@ class TextCompletionClientBase(ABC):
|
||||
self,
|
||||
prompt: str,
|
||||
settings: "CompleteRequestSettings",
|
||||
logger: Optional[Logger] = None,
|
||||
logger: Optional[Any] = None,
|
||||
) -> AsyncGenerator[Union[str, List[str]], None]:
|
||||
"""
|
||||
This is the method that is called from the kernel to get a stream response from a text-optimized LLM.
|
||||
@@ -46,7 +44,6 @@ class TextCompletionClientBase(ABC):
|
||||
Arguments:
|
||||
prompt {str} -- The prompt to send to the LLM.
|
||||
settings {CompleteRequestSettings} -- Settings for the request.
|
||||
logger {Logger} -- A logger to use for logging.
|
||||
|
||||
Yields:
|
||||
A stream representing the response(s) from the LLM.
|
||||
|
||||
+8
-6
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
import uuid
|
||||
from logging import Logger
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
from azure.core.credentials import AzureKeyCredential, TokenCredential
|
||||
@@ -27,13 +27,13 @@ from semantic_kernel.connectors.memory.azure_cognitive_search.utils import (
|
||||
)
|
||||
from semantic_kernel.memory.memory_record import MemoryRecord
|
||||
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AzureCognitiveSearchMemoryStore(MemoryStoreBase):
|
||||
_search_index_client: SearchIndexClient = None
|
||||
_vector_size: int = None
|
||||
_logger: Logger = None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -42,7 +42,7 @@ class AzureCognitiveSearchMemoryStore(MemoryStoreBase):
|
||||
admin_key: Optional[str] = None,
|
||||
azure_credentials: Optional[AzureKeyCredential] = None,
|
||||
token_credentials: Optional[TokenCredential] = None,
|
||||
logger: Optional[Logger] = None,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""Initializes a new instance of the AzureCognitiveSearchMemoryStore class.
|
||||
|
||||
@@ -54,12 +54,15 @@ class AzureCognitiveSearchMemoryStore(MemoryStoreBase):
|
||||
azure_credentials {Optional[AzureKeyCredential]} -- Azure Cognitive Search credentials (default: {None}).
|
||||
token_credentials {Optional[TokenCredential]} -- Azure Cognitive Search token credentials
|
||||
(default: {None}).
|
||||
logger {Optional[Logger]} -- The logger to use (default: {None}).
|
||||
|
||||
Instantiate using Async Context Manager:
|
||||
async with AzureCognitiveSearchMemoryStore(<...>) as memory:
|
||||
await memory.<...>
|
||||
"""
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
try:
|
||||
pass
|
||||
except ImportError:
|
||||
@@ -68,7 +71,6 @@ class AzureCognitiveSearchMemoryStore(MemoryStoreBase):
|
||||
"Please install Azure Cognitive Search client"
|
||||
)
|
||||
|
||||
self._logger = logger or NullLogger()
|
||||
self._vector_size = vector_size
|
||||
self._search_index_client = get_search_index_async_client(
|
||||
search_endpoint, admin_key, azure_credentials, token_credentials
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, List, Optional, Tuple
|
||||
|
||||
from numpy import array, ndarray
|
||||
@@ -12,23 +12,23 @@ from semantic_kernel.connectors.memory.chroma.utils import (
|
||||
)
|
||||
from semantic_kernel.memory.memory_record import MemoryRecord
|
||||
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import chromadb
|
||||
import chromadb.config
|
||||
from chromadb.api.models.Collection import Collection
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ChromaMemoryStore(MemoryStoreBase):
|
||||
_client: "chromadb.Client"
|
||||
_logger: Logger
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
persist_directory: Optional[str] = None,
|
||||
client_settings: Optional["chromadb.config.Settings"] = None,
|
||||
logger: Optional[Logger] = None,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""
|
||||
ChromaMemoryStore provides an interface to store and retrieve data using ChromaDB.
|
||||
@@ -62,6 +62,10 @@ class ChromaMemoryStore(MemoryStoreBase):
|
||||
"Please install it with `pip install chromadb`."
|
||||
)
|
||||
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
if client_settings:
|
||||
self._client_settings = client_settings
|
||||
else:
|
||||
@@ -74,7 +78,6 @@ class ChromaMemoryStore(MemoryStoreBase):
|
||||
self._persist_directory = persist_directory
|
||||
self._default_query_includes = ["embeddings", "metadatas", "documents"]
|
||||
|
||||
self._logger = logger or NullLogger()
|
||||
self._default_embedding_function = "DisableChromaEmbeddingFunction"
|
||||
|
||||
async def create_collection_async(self, collection_name: str) -> None:
|
||||
@@ -285,7 +288,7 @@ class ChromaMemoryStore(MemoryStoreBase):
|
||||
List[Tuple[MemoryRecord, float]] -- The records and their relevance scores.
|
||||
"""
|
||||
if with_embeddings is False:
|
||||
self._logger.warning(
|
||||
logger.warning(
|
||||
"Chroma returns distance score not cosine similarity score.\
|
||||
So embeddings are automatically queried from database for calculation."
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, List
|
||||
|
||||
from numpy import array, linalg, ndarray
|
||||
@@ -9,6 +10,8 @@ from semantic_kernel.memory.memory_record import MemoryRecord
|
||||
if TYPE_CHECKING:
|
||||
from chromadb.api.types import QueryResult
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def camel_to_snake(camel_str):
|
||||
snake_str = ""
|
||||
@@ -83,7 +86,7 @@ def query_results_to_records(
|
||||
|
||||
|
||||
def chroma_compute_similarity_scores(
|
||||
embedding: ndarray, embedding_array: ndarray, logger=None
|
||||
embedding: ndarray, embedding_array: ndarray, **kwargs
|
||||
) -> ndarray:
|
||||
"""Computes the cosine similarity scores between a query embedding and a group of embeddings.
|
||||
Arguments:
|
||||
@@ -92,6 +95,10 @@ def chroma_compute_similarity_scores(
|
||||
Returns:
|
||||
ndarray -- The cosine similarity scores.
|
||||
"""
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
query_norm = linalg.norm(embedding)
|
||||
collection_norm = linalg.norm(embedding_array, axis=1)
|
||||
|
||||
@@ -106,7 +113,7 @@ def chroma_compute_similarity_scores(
|
||||
similarity_scores[valid_indices] = embedding.dot(
|
||||
embedding_array[valid_indices].T
|
||||
) / (query_norm * collection_norm[valid_indices])
|
||||
if not valid_indices.all() and logger:
|
||||
if not valid_indices.all():
|
||||
logger.warning(
|
||||
"Some vectors in the embedding collection are zero vectors."
|
||||
"Ignoring cosine similarity score computation for those vectors."
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
import logging
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
from numpy import array, expand_dims, ndarray
|
||||
@@ -8,7 +8,8 @@ from pymilvus.milvus_client import milvus_client
|
||||
|
||||
from semantic_kernel.memory.memory_record import MemoryRecord
|
||||
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def memoryrecord_to_milvus_dict(mem: MemoryRecord) -> dict:
|
||||
@@ -65,7 +66,7 @@ class MilvusMemoryStore(MemoryStoreBase):
|
||||
self,
|
||||
uri: str = "http://localhost:19530",
|
||||
token: Optional[str] = None,
|
||||
logger: Optional[Logger] = None,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""MilvusMemoryStore allows for searching for records using Milvus/Zilliz Cloud.
|
||||
|
||||
@@ -79,11 +80,13 @@ class MilvusMemoryStore(MemoryStoreBase):
|
||||
"http://localhost:19530".
|
||||
token (Optional[str], optional): The token to connect to the cluster if
|
||||
authentication is required. Defaults to None.
|
||||
logger (Optional[Logger], optional): Logger to use. Defaults to None.
|
||||
"""
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
self._uri = uri
|
||||
self._token = (token,)
|
||||
self._logger = logger or NullLogger()
|
||||
self._client = milvus_client.MilvusClient(
|
||||
uri=uri,
|
||||
token=token,
|
||||
@@ -215,9 +218,7 @@ class MilvusMemoryStore(MemoryStoreBase):
|
||||
"""
|
||||
# Check if the collection exists.
|
||||
if collection_name not in self._client.list_collections():
|
||||
self._logger.debug(
|
||||
f"Collection {collection_name} does not exist, cannot insert."
|
||||
)
|
||||
logger.debug(f"Collection {collection_name} does not exist, cannot insert.")
|
||||
raise Exception(
|
||||
f"Collection {collection_name} does not exist, cannot insert."
|
||||
)
|
||||
@@ -232,7 +233,7 @@ class MilvusMemoryStore(MemoryStoreBase):
|
||||
collection_name=collection_name, data=insert_list, batch_size=batch_size
|
||||
)
|
||||
except Exception as e:
|
||||
self._logger.debug(f"Upsert failed due to: {e}")
|
||||
logger.debug(f"Upsert failed due to: {e}")
|
||||
raise e
|
||||
|
||||
async def get_async(
|
||||
@@ -272,9 +273,7 @@ class MilvusMemoryStore(MemoryStoreBase):
|
||||
"""
|
||||
# Check if the collection exists
|
||||
if collection_name not in self._client.list_collections():
|
||||
self._logger.debug(
|
||||
f"Collection {collection_name} does not exist, cannot get."
|
||||
)
|
||||
logger.debug(f"Collection {collection_name} does not exist, cannot get.")
|
||||
raise Exception("Collection {collection_name} does not exist, cannot get.")
|
||||
try:
|
||||
gets = self._client.get(
|
||||
@@ -284,7 +283,7 @@ class MilvusMemoryStore(MemoryStoreBase):
|
||||
)
|
||||
return [milvus_dict_to_memoryrecord(get) for get in gets]
|
||||
except Exception as e:
|
||||
self._logger.debug(f"Get failed due to: {e}")
|
||||
logger.debug(f"Get failed due to: {e}")
|
||||
raise e
|
||||
|
||||
async def remove_async(self, collection_name: str, key: str) -> None:
|
||||
@@ -308,9 +307,7 @@ class MilvusMemoryStore(MemoryStoreBase):
|
||||
e: Failure to remove key.
|
||||
"""
|
||||
if collection_name not in self._client.list_collections():
|
||||
self._logger.debug(
|
||||
f"Collection {collection_name} does not exist, cannot remove."
|
||||
)
|
||||
logger.debug(f"Collection {collection_name} does not exist, cannot remove.")
|
||||
raise Exception(
|
||||
f"Collection {collection_name} does not exist, cannot remove."
|
||||
)
|
||||
@@ -320,7 +317,7 @@ class MilvusMemoryStore(MemoryStoreBase):
|
||||
pks=keys,
|
||||
)
|
||||
except Exception as e:
|
||||
self._logger.debug(f"Remove failed due to: {e}")
|
||||
logger.debug(f"Remove failed due to: {e}")
|
||||
raise e
|
||||
|
||||
def _search(self, collection_name, data, limit, distance_metric):
|
||||
@@ -342,7 +339,7 @@ class MilvusMemoryStore(MemoryStoreBase):
|
||||
)[0]
|
||||
return results, distance_metric
|
||||
except Exception as e:
|
||||
self._logger.debug(f"Search failed with IP, testing L2: {e}")
|
||||
logger.debug(f"Search failed with IP, testing L2: {e}")
|
||||
try:
|
||||
distance_metric = distance_pairs[distance_metric.lower()]
|
||||
results = self._client.search(
|
||||
@@ -354,7 +351,7 @@ class MilvusMemoryStore(MemoryStoreBase):
|
||||
)[0]
|
||||
return results, distance_metric
|
||||
except Exception as e:
|
||||
self._logger.debug(f"Search failed with L2: {e}")
|
||||
logger.debug(f"Search failed with L2: {e}")
|
||||
raise e
|
||||
|
||||
async def get_nearest_matches_async(
|
||||
@@ -383,9 +380,7 @@ class MilvusMemoryStore(MemoryStoreBase):
|
||||
"""
|
||||
# Check if collection exists
|
||||
if collection_name not in self._client.list_collections():
|
||||
self._logger.debug(
|
||||
f"Collection {collection_name} does not exist, cannot search."
|
||||
)
|
||||
logger.debug(f"Collection {collection_name} does not exist, cannot search.")
|
||||
raise Exception(
|
||||
f"Collection {collection_name} does not exist, cannot search."
|
||||
)
|
||||
@@ -425,7 +420,7 @@ class MilvusMemoryStore(MemoryStoreBase):
|
||||
output_fields=[EMBEDDING_FIELD],
|
||||
)
|
||||
except Exception as e:
|
||||
self._logger.debug(f"Get embeddings in search failed due to: {e}.")
|
||||
logger.debug(f"Get embeddings in search failed due to: {e}.")
|
||||
raise e
|
||||
|
||||
vectors = {res[ID_FIELD]: res[EMBEDDING_FIELD] for res in vectors}
|
||||
|
||||
+11
-8
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from __future__ import annotations
|
||||
|
||||
from logging import Logger
|
||||
import logging
|
||||
from typing import Any, List, Mapping, Optional, Tuple
|
||||
|
||||
from motor import MotorCommandCursor, core, motor_asyncio
|
||||
@@ -19,17 +19,17 @@ from semantic_kernel.connectors.memory.mongodb_atlas.utils import (
|
||||
)
|
||||
from semantic_kernel.memory.memory_record import MemoryRecord
|
||||
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
from semantic_kernel.utils.settings import mongodb_atlas_settings_from_dot_env
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MongoDBAtlasMemoryStore(MemoryStoreBase):
|
||||
"""Memory Store for MongoDB Atlas Vector Search Connections"""
|
||||
|
||||
__slots__ = ("_mongo_client", "_logger", "__database_name")
|
||||
__slots__ = ("_mongo_client", "__database_name")
|
||||
|
||||
_mongo_client: motor_asyncio.AsyncIOMotorClient
|
||||
_logger: Logger
|
||||
__database_name: str
|
||||
__index_name: str
|
||||
|
||||
@@ -38,14 +38,17 @@ class MongoDBAtlasMemoryStore(MemoryStoreBase):
|
||||
index_name: Optional[str] = None,
|
||||
connection_string: Optional[str] = None,
|
||||
database_name: Optional[str] = None,
|
||||
logger: Optional[Logger] = None,
|
||||
read_preference: Optional[ReadPreference] = ReadPreference.PRIMARY,
|
||||
**kwargs,
|
||||
):
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
self._mongo_client = motor_asyncio.AsyncIOMotorClient(
|
||||
connection_string or mongodb_atlas_settings_from_dot_env(),
|
||||
read_preference=read_preference,
|
||||
)
|
||||
self._logger = logger or NullLogger()
|
||||
self.__database_name = database_name or DEFAULT_DB_NAME
|
||||
self.__index_name = index_name or DEFAULT_SEARCH_INDEX_NAME
|
||||
|
||||
@@ -161,7 +164,7 @@ class MongoDBAtlasMemoryStore(MemoryStoreBase):
|
||||
].bulk_write(upserts, ordered=False)
|
||||
|
||||
# Assert the number matched and the number upserted equal the total batch updated
|
||||
self._logger.debug(
|
||||
logger.debug(
|
||||
"matched_count=%s, upserted_count=%s",
|
||||
bulk_update_result.matched_count,
|
||||
bulk_update_result.upserted_count,
|
||||
@@ -241,7 +244,7 @@ class MongoDBAtlasMemoryStore(MemoryStoreBase):
|
||||
bulk_write_result = await self.database[collection_name].bulk_write(
|
||||
deletes, ordered=False
|
||||
)
|
||||
self._logger.debug("%s entries deleted", bulk_write_result.deleted_count)
|
||||
logger.debug("%s entries deleted", bulk_write_result.deleted_count)
|
||||
|
||||
async def get_nearest_matches_async(
|
||||
self,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
import logging
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
import pinecone
|
||||
@@ -13,7 +13,6 @@ from semantic_kernel.connectors.memory.pinecone.utils import (
|
||||
)
|
||||
from semantic_kernel.memory.memory_record import MemoryRecord
|
||||
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
# Limitations set by Pinecone at https://docs.pinecone.io/docs/limits
|
||||
MAX_DIMENSIONALITY = 20000
|
||||
@@ -23,11 +22,12 @@ MAX_QUERY_WITH_METADATA_BATCH_SIZE = 1000
|
||||
MAX_FETCH_BATCH_SIZE = 1000
|
||||
MAX_DELETE_BATCH_SIZE = 1000
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PineconeMemoryStore(MemoryStoreBase):
|
||||
"""A memory store that uses Pinecone as the backend."""
|
||||
|
||||
_logger: Logger
|
||||
_pinecone_api_key: str
|
||||
_pinecone_environment: str
|
||||
_default_dimensionality: int
|
||||
@@ -37,7 +37,7 @@ class PineconeMemoryStore(MemoryStoreBase):
|
||||
api_key: str,
|
||||
environment: str,
|
||||
default_dimensionality: int,
|
||||
logger: Optional[Logger] = None,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""Initializes a new instance of the PineconeMemoryStore class.
|
||||
|
||||
@@ -45,8 +45,11 @@ class PineconeMemoryStore(MemoryStoreBase):
|
||||
pinecone_api_key {str} -- The Pinecone API key.
|
||||
pinecone_environment {str} -- The Pinecone environment.
|
||||
default_dimensionality {int} -- The default dimensionality to use for new collections.
|
||||
logger {Optional[Logger]} -- The logger to use. (default: {None})
|
||||
"""
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
if default_dimensionality > MAX_DIMENSIONALITY:
|
||||
raise ValueError(
|
||||
f"Dimensionality of {default_dimensionality} exceeds "
|
||||
@@ -55,7 +58,6 @@ class PineconeMemoryStore(MemoryStoreBase):
|
||||
self._pinecone_api_key = api_key
|
||||
self._pinecone_environment = environment
|
||||
self._default_dimensionality = default_dimensionality
|
||||
self._logger = logger or NullLogger()
|
||||
|
||||
pinecone.init(
|
||||
api_key=self._pinecone_api_key, environment=self._pinecone_environment
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import atexit
|
||||
import json
|
||||
from logging import Logger
|
||||
import logging
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
import numpy as np
|
||||
@@ -13,12 +13,13 @@ from psycopg_pool import ConnectionPool
|
||||
|
||||
from semantic_kernel.memory.memory_record import MemoryRecord
|
||||
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
# Limitation based on pgvector documentation https://github.com/pgvector/pgvector#what-if-i-want-to-index-vectors-with-more-than-2000-dimensions
|
||||
MAX_DIMENSIONALITY = 2000
|
||||
DEFAULT_SCHEMA = "public"
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PostgresMemoryStore(MemoryStoreBase):
|
||||
"""A memory store that uses Postgres with pgvector as the backend."""
|
||||
@@ -27,7 +28,6 @@ class PostgresMemoryStore(MemoryStoreBase):
|
||||
_connection_pool: ConnectionPool
|
||||
_default_dimensionality: int
|
||||
_schema: str
|
||||
_logger: Logger
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -36,7 +36,7 @@ class PostgresMemoryStore(MemoryStoreBase):
|
||||
min_pool: int,
|
||||
max_pool: int,
|
||||
schema: str = DEFAULT_SCHEMA,
|
||||
logger: Optional[Logger] = None,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""Initializes a new instance of the PostgresMemoryStore class.
|
||||
|
||||
@@ -48,9 +48,11 @@ class PostgresMemoryStore(MemoryStoreBase):
|
||||
schema {str} -- The schema to use. (default: {"public"})\n
|
||||
timezone_offset {Optional[str]} -- The timezone offset to use. (default: {None})
|
||||
Expected format '-7:00'. Uses the local timezone offset when not provided.\n
|
||||
logger {Optional[Logger]} -- The logger to use. (default: {None})
|
||||
"""
|
||||
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
self._check_dimensionality(default_dimensionality)
|
||||
|
||||
self._connection_string = connection_string
|
||||
@@ -60,7 +62,6 @@ class PostgresMemoryStore(MemoryStoreBase):
|
||||
)
|
||||
self._schema = schema
|
||||
atexit.register(self._connection_pool.close)
|
||||
self._logger = logger or NullLogger()
|
||||
|
||||
async def create_collection_async(
|
||||
self,
|
||||
|
||||
@@ -5,8 +5,8 @@ QdrantMemoryStore provides functionality to add Qdrant vector database to suppor
|
||||
The QdrantMemoryStore inherits from MemoryStoreBase for persisting/retrieving data from a Qdrant Vector Database.
|
||||
"""
|
||||
import asyncio
|
||||
import logging
|
||||
import uuid
|
||||
from logging import Logger
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
from numpy import ndarray
|
||||
@@ -15,26 +15,26 @@ from qdrant_client import models as qdrant_models
|
||||
|
||||
from semantic_kernel.memory.memory_record import MemoryRecord
|
||||
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class QdrantMemoryStore(MemoryStoreBase):
|
||||
_qdrantclient: QdrantClient
|
||||
_logger: Logger
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
vector_size: int,
|
||||
url: Optional[str] = None,
|
||||
port: Optional[int] = 6333,
|
||||
logger: Optional[Logger] = None,
|
||||
local: Optional[bool] = False,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""Initializes a new instance of the QdrantMemoryStore class.
|
||||
|
||||
Arguments:
|
||||
logger {Optional[Logger]} -- The logger to use. (default: {None})
|
||||
"""
|
||||
"""Initializes a new instance of the QdrantMemoryStore class."""
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
if local:
|
||||
if url:
|
||||
self._qdrantclient = QdrantClient(location=url)
|
||||
@@ -43,7 +43,6 @@ class QdrantMemoryStore(MemoryStoreBase):
|
||||
else:
|
||||
self._qdrantclient = QdrantClient(url=url, port=port)
|
||||
|
||||
self._logger = logger or NullLogger()
|
||||
self._default_vector_size = vector_size
|
||||
|
||||
async def create_collection_async(self, collection_name: str) -> None:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
from typing import List, Optional, Tuple
|
||||
import logging
|
||||
from typing import List, Tuple
|
||||
|
||||
import numpy as np
|
||||
import redis
|
||||
@@ -19,7 +19,8 @@ from semantic_kernel.connectors.memory.redis.utils import (
|
||||
)
|
||||
from semantic_kernel.memory.memory_record import MemoryRecord
|
||||
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RedisMemoryStore(MemoryStoreBase):
|
||||
@@ -27,7 +28,6 @@ class RedisMemoryStore(MemoryStoreBase):
|
||||
|
||||
_database: "redis.Redis"
|
||||
_ft: "redis.Redis.ft"
|
||||
_logger: Logger
|
||||
# Without RedisAI, it is currently not possible to retrieve index-specific vector attributes to have
|
||||
# fully independent collections.
|
||||
_query_dialect: int
|
||||
@@ -45,7 +45,7 @@ class RedisMemoryStore(MemoryStoreBase):
|
||||
vector_type: str = "FLOAT32",
|
||||
vector_index_algorithm: str = "HNSW",
|
||||
query_dialect: int = 2,
|
||||
logger: Optional[Logger] = None,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""
|
||||
RedisMemoryStore is an abstracted interface to interact with a Redis node connection.
|
||||
@@ -59,15 +59,17 @@ class RedisMemoryStore(MemoryStoreBase):
|
||||
vector_type {str} -- Vector type, defaults to FLOAT32
|
||||
vector_index_algorithm {str} -- Indexing algorithm for vectors, defaults to HNSW
|
||||
query_dialect {int} -- Query dialect, must be 2 or greater for vector similarity searching, defaults to 2
|
||||
logger {Optional[Logger]} -- Logger, defaults to None
|
||||
|
||||
"""
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
if vector_size <= 0:
|
||||
raise ValueError("Vector dimension must be a positive integer")
|
||||
|
||||
self._database = redis.Redis.from_url(connection_string)
|
||||
self._ft = self._database.ft
|
||||
self._logger = logger or NullLogger()
|
||||
|
||||
self._query_dialect = query_dialect
|
||||
self._vector_distance_metric = vector_distance_metric
|
||||
@@ -80,7 +82,7 @@ class RedisMemoryStore(MemoryStoreBase):
|
||||
"""
|
||||
Closes the Redis database connection
|
||||
"""
|
||||
self._logger.info("Closing Redis connection")
|
||||
logger.info("Closing Redis connection")
|
||||
self._database.close()
|
||||
|
||||
async def create_collection_async(self, collection_name: str) -> None:
|
||||
@@ -94,7 +96,7 @@ class RedisMemoryStore(MemoryStoreBase):
|
||||
"""
|
||||
|
||||
if await self.does_collection_exist_async(collection_name):
|
||||
self._logger.info(f'Collection "{collection_name}" already exists.')
|
||||
logger.info(f'Collection "{collection_name}" already exists.')
|
||||
else:
|
||||
index_def = IndexDefinition(
|
||||
prefix=f"{collection_name}:", index_type=IndexType.HASH
|
||||
@@ -119,7 +121,7 @@ class RedisMemoryStore(MemoryStoreBase):
|
||||
definition=index_def, fields=schema
|
||||
)
|
||||
except Exception as e:
|
||||
self._logger.error(e)
|
||||
logger.error(e)
|
||||
raise e
|
||||
|
||||
async def get_collections_async(self) -> List[str]:
|
||||
@@ -181,7 +183,7 @@ class RedisMemoryStore(MemoryStoreBase):
|
||||
"""
|
||||
|
||||
if not await self.does_collection_exist_async(collection_name):
|
||||
self._logger.error(f'Collection "{collection_name}" does not exist')
|
||||
logger.error(f'Collection "{collection_name}" does not exist')
|
||||
raise Exception(f'Collection "{collection_name}" does not exist')
|
||||
|
||||
# Typical Redis key structure: collection_name:{some identifier}
|
||||
@@ -196,7 +198,7 @@ class RedisMemoryStore(MemoryStoreBase):
|
||||
)
|
||||
return record._key
|
||||
except Exception as e:
|
||||
self._logger.error(e)
|
||||
logger.error(e)
|
||||
raise e
|
||||
|
||||
async def upsert_batch_async(
|
||||
@@ -241,7 +243,7 @@ class RedisMemoryStore(MemoryStoreBase):
|
||||
"""
|
||||
|
||||
if not await self.does_collection_exist_async(collection_name):
|
||||
self._logger.error(f'Collection "{collection_name}" does not exist')
|
||||
logger.error(f'Collection "{collection_name}" does not exist')
|
||||
raise Exception(f'Collection "{collection_name}" does not exist')
|
||||
|
||||
internal_key = get_redis_key(collection_name, key)
|
||||
@@ -289,7 +291,7 @@ class RedisMemoryStore(MemoryStoreBase):
|
||||
key {str} -- ID associated with the memory to remove
|
||||
"""
|
||||
if not await self.does_collection_exist_async(collection_name):
|
||||
self._logger.error(f'Collection "{collection_name}" does not exist')
|
||||
logger.error(f'Collection "{collection_name}" does not exist')
|
||||
raise Exception(f'Collection "{collection_name}" does not exist')
|
||||
|
||||
self._database.delete(get_redis_key(collection_name, key))
|
||||
@@ -303,7 +305,7 @@ class RedisMemoryStore(MemoryStoreBase):
|
||||
keys {List[str]} -- IDs associated with the memory records to remove
|
||||
"""
|
||||
if not await self.does_collection_exist_async(collection_name):
|
||||
self._logger.error(f'Collection "{collection_name}" does not exist')
|
||||
logger.error(f'Collection "{collection_name}" does not exist')
|
||||
raise Exception(f'Collection "{collection_name}" does not exist')
|
||||
|
||||
self._database.delete(*[get_redis_key(collection_name, key) for key in keys])
|
||||
@@ -331,7 +333,7 @@ class RedisMemoryStore(MemoryStoreBase):
|
||||
order, or an empty list if no relevant matches are found
|
||||
"""
|
||||
if not await self.does_collection_exist_async(collection_name):
|
||||
self._logger.error(f'Collection "{collection_name}" does not exist')
|
||||
logger.error(f'Collection "{collection_name}" does not exist')
|
||||
raise Exception(f'Collection "{collection_name}" does not exist')
|
||||
|
||||
# Perform a k-nearest neighbors query, score by similarity
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import itertools
|
||||
import logging
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from logging import Logger
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional, Tuple, Union
|
||||
|
||||
@@ -24,7 +24,8 @@ from usearch.index import (
|
||||
|
||||
from semantic_kernel.memory.memory_record import MemoryRecord
|
||||
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -126,7 +127,7 @@ class USearchMemoryStore(MemoryStoreBase):
|
||||
def __init__(
|
||||
self,
|
||||
persist_directory: Optional[os.PathLike] = None,
|
||||
logger: Optional[Logger] = None,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""
|
||||
Create a USearchMemoryStore instance.
|
||||
@@ -142,9 +143,11 @@ class USearchMemoryStore(MemoryStoreBase):
|
||||
Args:
|
||||
persist_directory (Optional[os.PathLike], default=None): Directory for loading and saving collections.
|
||||
If None, collections are not loaded nor saved.
|
||||
logger (Optional[Logger], default=None): Logger for diagnostics. If None, a NullLogger is used.
|
||||
"""
|
||||
self._logger = logger or NullLogger()
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
self._persist_directory = (
|
||||
Path(persist_directory) if persist_directory is not None else None
|
||||
)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from dataclasses import dataclass
|
||||
from logging import Logger
|
||||
from typing import List, Optional, Tuple
|
||||
from typing import List, Tuple
|
||||
|
||||
import numpy as np
|
||||
import weaviate
|
||||
@@ -11,7 +11,8 @@ from weaviate.embedded import EmbeddedOptions
|
||||
|
||||
from semantic_kernel.memory.memory_record import MemoryRecord
|
||||
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
SCHEMA = {
|
||||
"class": "MemoryRecord",
|
||||
@@ -115,8 +116,11 @@ class WeaviateMemoryStore(MemoryStoreBase):
|
||||
"""
|
||||
return {key.lstrip("_"): value for key, value in sk_dict.items()}
|
||||
|
||||
def __init__(self, config: WeaviateConfig, logger: Optional[Logger] = None):
|
||||
self._logger = logger or NullLogger()
|
||||
def __init__(self, config: WeaviateConfig, **kwargs):
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
self.config = config
|
||||
self.client = self._initialize_client()
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@ from semantic_kernel.connectors.ai.open_ai.const import (
|
||||
from semantic_kernel.connectors.telemetry import HTTP_USER_AGENT
|
||||
from semantic_kernel.orchestration.sk_function_base import SKFunctionBase
|
||||
from semantic_kernel.skill_definition import sk_function, sk_function_context_parameter
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PreparedRestApiRequest:
|
||||
@@ -40,7 +41,11 @@ class PreparedRestApiRequest:
|
||||
f"request_body={self.request_body})"
|
||||
)
|
||||
|
||||
def validate_request(self, spec: Spec, logger: logging.Logger = NullLogger()):
|
||||
def validate_request(self, spec: Spec, **kwargs):
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
request = requests.Request(
|
||||
self.method,
|
||||
self.url,
|
||||
@@ -159,8 +164,11 @@ class RestApiOperation:
|
||||
|
||||
|
||||
class OpenApiParser:
|
||||
def __init__(self, logger: logging.Logger = NullLogger()):
|
||||
self.logger = logger
|
||||
def __init__(self, **kwargs):
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
|
||||
"""
|
||||
Import an OpenAPI file.
|
||||
@@ -214,9 +222,7 @@ class OpenApiRunner:
|
||||
def __init__(
|
||||
self,
|
||||
parsed_openapi_document: Mapping[str, str],
|
||||
logger: logging.Logger = NullLogger(),
|
||||
):
|
||||
self.logger = logger
|
||||
self.spec = Spec.from_dict(parsed_openapi_document)
|
||||
|
||||
async def run_operation(
|
||||
@@ -233,7 +239,7 @@ class OpenApiRunner:
|
||||
headers=headers,
|
||||
request_body=request_body,
|
||||
)
|
||||
is_valid = prepared_request.validate_request(spec=self.spec, logger=self.logger)
|
||||
is_valid = prepared_request.validate_request(spec=self.spec)
|
||||
if not is_valid:
|
||||
return None
|
||||
|
||||
@@ -262,12 +268,10 @@ def register_openapi_skill(
|
||||
skill_name: str,
|
||||
openapi_document: str,
|
||||
) -> Dict[str, SKFunctionBase]:
|
||||
parser = OpenApiParser(logger=kernel.logger)
|
||||
parser = OpenApiParser()
|
||||
parsed_doc = parser.parse(openapi_document)
|
||||
operations = parser.create_rest_api_operations(parsed_doc)
|
||||
openapi_runner = OpenApiRunner(
|
||||
parsed_openapi_document=parsed_doc, logger=kernel.logger
|
||||
)
|
||||
openapi_runner = OpenApiRunner(parsed_openapi_document=parsed_doc)
|
||||
|
||||
skill = {}
|
||||
|
||||
@@ -310,8 +314,6 @@ def register_openapi_skill(
|
||||
return run_openapi_operation
|
||||
|
||||
for operation_id, operation in operations.items():
|
||||
kernel.logger.info(
|
||||
f"Registering OpenAPI operation: {skill_name}.{operation_id}"
|
||||
)
|
||||
logger.info(f"Registering OpenAPI operation: {skill_name}.{operation_id}")
|
||||
skill[operation_id] = create_run_operation_function(openapi_runner, operation)
|
||||
return kernel.import_skill(skill, skill_name)
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
import urllib
|
||||
from logging import Logger
|
||||
from typing import List, Optional
|
||||
from typing import List
|
||||
|
||||
import aiohttp
|
||||
|
||||
from semantic_kernel.connectors.search_engine.connector import ConnectorBase
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BingConnector(ConnectorBase):
|
||||
@@ -17,9 +18,12 @@ class BingConnector(ConnectorBase):
|
||||
|
||||
_api_key: str
|
||||
|
||||
def __init__(self, api_key: str, logger: Optional[Logger] = None) -> None:
|
||||
def __init__(self, api_key: str, **kwargs) -> None:
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
self._api_key = api_key
|
||||
self._logger = logger if logger else NullLogger()
|
||||
|
||||
if not self._api_key:
|
||||
raise ValueError(
|
||||
@@ -57,7 +61,7 @@ class BingConnector(ConnectorBase):
|
||||
if offset < 0:
|
||||
raise ValueError("offset must be greater than 0.")
|
||||
|
||||
self._logger.info(
|
||||
logger.info(
|
||||
f"Received request for bing web search with \
|
||||
params:\nquery: {query}\nnum_results: {num_results}\noffset: {offset}"
|
||||
)
|
||||
@@ -65,7 +69,7 @@ class BingConnector(ConnectorBase):
|
||||
_base_url = "https://api.bing.microsoft.com/v7.0/search"
|
||||
_request_url = f"{_base_url}?q={urllib.parse.quote_plus(query)}&count={num_results}&offset={offset}"
|
||||
|
||||
self._logger.info(f"Sending GET request to {_request_url}")
|
||||
logger.info(f"Sending GET request to {_request_url}")
|
||||
|
||||
headers = {"Ocp-Apim-Subscription-Key": self._api_key}
|
||||
|
||||
@@ -76,9 +80,9 @@ class BingConnector(ConnectorBase):
|
||||
if response.status == 200:
|
||||
data = await response.json()
|
||||
pages = data["webPages"]["value"]
|
||||
self._logger.info(pages)
|
||||
logger.info(pages)
|
||||
result = list(map(lambda x: x["snippet"], pages))
|
||||
self._logger.info(result)
|
||||
logger.info(result)
|
||||
return result
|
||||
else:
|
||||
return []
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
import urllib
|
||||
from logging import Logger
|
||||
from typing import List, Optional
|
||||
from typing import List
|
||||
|
||||
import aiohttp
|
||||
|
||||
from semantic_kernel.connectors.search_engine.connector import ConnectorBase
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GoogleConnector(ConnectorBase):
|
||||
@@ -17,14 +18,14 @@ class GoogleConnector(ConnectorBase):
|
||||
|
||||
_api_key: str
|
||||
_search_engine_id: str
|
||||
_logger: Logger
|
||||
|
||||
def __init__(
|
||||
self, api_key: str, search_engine_id: str, logger: Optional[Logger] = None
|
||||
) -> None:
|
||||
def __init__(self, api_key: str, search_engine_id: str, **kwargs) -> None:
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
self._api_key = api_key
|
||||
self._search_engine_id = search_engine_id
|
||||
self._logger = logger if logger else NullLogger()
|
||||
|
||||
if not self._api_key:
|
||||
raise ValueError("Google Custom Search API key cannot be null.")
|
||||
@@ -63,7 +64,7 @@ class GoogleConnector(ConnectorBase):
|
||||
if offset < 0:
|
||||
raise ValueError("offset must be greater than 0.")
|
||||
|
||||
self._logger.info(
|
||||
logger.info(
|
||||
f"Received request for google search with \
|
||||
params:\nquery: {query}\nnum_results: {num_results}\noffset: {offset}"
|
||||
)
|
||||
@@ -75,19 +76,19 @@ class GoogleConnector(ConnectorBase):
|
||||
f"&num={num_results}&start={offset}"
|
||||
)
|
||||
|
||||
self._logger.info("Sending GET request to Google Search API.")
|
||||
logger.info("Sending GET request to Google Search API.")
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(_request_url, raise_for_status=True) as response:
|
||||
if response.status == 200:
|
||||
data = await response.json()
|
||||
self._logger.info("Request successful.")
|
||||
self._logger.info(f"API Response: {data}")
|
||||
logger.info("Request successful.")
|
||||
logger.info(f"API Response: {data}")
|
||||
items = data["items"]
|
||||
result = [x["snippet"] for x in items]
|
||||
return result
|
||||
else:
|
||||
self._logger.error(
|
||||
logger.error(
|
||||
f"Request to Google Search API failed with status code: {response.status}."
|
||||
)
|
||||
return []
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import json
|
||||
import logging
|
||||
import typing as t
|
||||
from typing import ClassVar
|
||||
|
||||
@@ -9,6 +10,8 @@ from semantic_kernel.skill_definition import sk_function, sk_function_context_pa
|
||||
if t.TYPE_CHECKING:
|
||||
from semantic_kernel.orchestration.sk_context import SKContext
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TextMemorySkill(SKBaseModel):
|
||||
COLLECTION_PARAM: ClassVar[str] = "collection"
|
||||
@@ -90,8 +93,7 @@ class TextMemorySkill(SKBaseModel):
|
||||
min_relevance_score=float(relevance),
|
||||
)
|
||||
if results is None or len(results) == 0:
|
||||
if context.log is not None:
|
||||
context.log.warning(f"Memory not found in collection: {collection}")
|
||||
logger.warning(f"Memory not found in collection: {collection}")
|
||||
return ""
|
||||
|
||||
return results[0].text if limit == 1 else json.dumps([r.text for r in results])
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
import glob
|
||||
import importlib
|
||||
import inspect
|
||||
import logging
|
||||
import os
|
||||
from logging import Logger
|
||||
from typing import Any, Callable, Dict, List, Optional, Type, TypeVar, Union
|
||||
from uuid import uuid4
|
||||
|
||||
@@ -53,14 +53,14 @@ from semantic_kernel.template_engine.prompt_template_engine import PromptTemplat
|
||||
from semantic_kernel.template_engine.protocols.prompt_templating_engine import (
|
||||
PromptTemplatingEngine,
|
||||
)
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
from semantic_kernel.utils.validation import validate_function_name, validate_skill_name
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Kernel:
|
||||
_log: Logger
|
||||
_skill_collection: SkillCollectionBase
|
||||
_prompt_template_engine: PromptTemplatingEngine
|
||||
_memory: SemanticTextMemoryBase
|
||||
@@ -70,16 +70,17 @@ class Kernel:
|
||||
skill_collection: Optional[SkillCollectionBase] = None,
|
||||
prompt_template_engine: Optional[PromptTemplatingEngine] = None,
|
||||
memory: Optional[SemanticTextMemoryBase] = None,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
self._log = log if log else NullLogger()
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
self._skill_collection = (
|
||||
skill_collection if skill_collection else SkillCollection(self._log)
|
||||
skill_collection if skill_collection else SkillCollection()
|
||||
)
|
||||
self._prompt_template_engine = (
|
||||
prompt_template_engine
|
||||
if prompt_template_engine
|
||||
else PromptTemplateEngine(self._log)
|
||||
prompt_template_engine if prompt_template_engine else PromptTemplateEngine()
|
||||
)
|
||||
self._memory = memory if memory else NullMemory()
|
||||
|
||||
@@ -102,10 +103,6 @@ class Kernel:
|
||||
self._function_invoking_handlers = {}
|
||||
self._function_invoked_handlers = {}
|
||||
|
||||
@property
|
||||
def logger(self) -> Logger:
|
||||
return self._log
|
||||
|
||||
@property
|
||||
def memory(self) -> SemanticTextMemoryBase:
|
||||
return self._memory
|
||||
@@ -157,7 +154,7 @@ class Kernel:
|
||||
validate_skill_name(skill_name)
|
||||
validate_function_name(function_name)
|
||||
|
||||
function = SKFunction.from_native_method(sk_function, skill_name, self.logger)
|
||||
function = SKFunction.from_native_method(sk_function, skill_name)
|
||||
|
||||
if self.skills.has_function(skill_name, function_name):
|
||||
raise KernelException(
|
||||
@@ -222,7 +219,6 @@ class Kernel:
|
||||
variables,
|
||||
self._memory,
|
||||
self._skill_collection.read_only_skill_collection,
|
||||
self._log,
|
||||
)
|
||||
else:
|
||||
raise ValueError("No functions passed to run")
|
||||
@@ -237,7 +233,7 @@ class Kernel:
|
||||
|
||||
except Exception as ex:
|
||||
# TODO: "critical exceptions"
|
||||
self._log.error(
|
||||
logger.error(
|
||||
"Something went wrong in stream function. During function invocation:"
|
||||
f" '{stream_function.skill_name}.{stream_function.name}'. Error"
|
||||
f" description: '{str(ex)}'"
|
||||
@@ -286,7 +282,6 @@ class Kernel:
|
||||
variables,
|
||||
self._memory,
|
||||
self._skill_collection.read_only_skill_collection,
|
||||
self._log,
|
||||
)
|
||||
|
||||
pipeline_step = 0
|
||||
@@ -298,7 +293,7 @@ class Kernel:
|
||||
)
|
||||
|
||||
if context.error_occurred:
|
||||
self._log.error(
|
||||
logger.error(
|
||||
f"Something went wrong in pipeline step {pipeline_step}. "
|
||||
f"Error description: '{context.last_error_description}'"
|
||||
)
|
||||
@@ -315,7 +310,7 @@ class Kernel:
|
||||
and function_invoking_args.is_cancel_requested
|
||||
):
|
||||
cancel_message = "Execution was cancelled on function invoking event of pipeline step"
|
||||
self._log.info(
|
||||
logger.info(
|
||||
f"{cancel_message} {pipeline_step}: {func.skill_name}.{func.name}."
|
||||
)
|
||||
return context
|
||||
@@ -325,7 +320,7 @@ class Kernel:
|
||||
and function_invoking_args.is_skip_requested
|
||||
):
|
||||
skip_message = "Execution was skipped on function invoking event of pipeline step"
|
||||
self._log.info(
|
||||
logger.info(
|
||||
f"{skip_message} {pipeline_step}: {func.skill_name}.{func.name}."
|
||||
)
|
||||
break
|
||||
@@ -335,7 +330,7 @@ class Kernel:
|
||||
)
|
||||
|
||||
if context.error_occurred:
|
||||
self._log.error(
|
||||
logger.error(
|
||||
f"Something went wrong in pipeline step {pipeline_step}. "
|
||||
f"During function invocation: '{func.skill_name}.{func.name}'. "
|
||||
f"Error description: '{context.last_error_description}'"
|
||||
@@ -351,7 +346,7 @@ class Kernel:
|
||||
and function_invoked_args.is_cancel_requested
|
||||
):
|
||||
cancel_message = "Execution was cancelled on function invoked event of pipeline step"
|
||||
self._log.info(
|
||||
logger.info(
|
||||
f"{cancel_message} {pipeline_step}: {func.skill_name}.{func.name}."
|
||||
)
|
||||
return context
|
||||
@@ -360,7 +355,7 @@ class Kernel:
|
||||
and function_invoked_args.is_repeat_requested
|
||||
):
|
||||
repeat_message = "Execution was repeated on function invoked event of pipeline step"
|
||||
self._log.info(
|
||||
logger.info(
|
||||
f"{repeat_message} {pipeline_step}: {func.skill_name}.{func.name}."
|
||||
)
|
||||
continue
|
||||
@@ -368,7 +363,7 @@ class Kernel:
|
||||
break
|
||||
|
||||
except Exception as ex:
|
||||
self._log.error(
|
||||
logger.error(
|
||||
f"Something went wrong in pipeline step {pipeline_step}. "
|
||||
f"During function invocation: '{func.skill_name}.{func.name}'. "
|
||||
f"Error description: '{str(ex)}'"
|
||||
@@ -422,7 +417,6 @@ class Kernel:
|
||||
ContextVariables() if not variables else variables,
|
||||
self._memory,
|
||||
self.skills,
|
||||
self._log,
|
||||
)
|
||||
|
||||
def on_function_invoking(
|
||||
@@ -450,9 +444,9 @@ class Kernel:
|
||||
) -> Dict[str, SKFunctionBase]:
|
||||
if skill_name.strip() == "":
|
||||
skill_name = SkillCollection.GLOBAL_SKILL
|
||||
self._log.debug(f"Importing skill {skill_name} into the global namespace")
|
||||
logger.debug(f"Importing skill {skill_name} into the global namespace")
|
||||
else:
|
||||
self._log.debug(f"Importing skill {skill_name}")
|
||||
logger.debug(f"Importing skill {skill_name}")
|
||||
|
||||
functions = []
|
||||
|
||||
@@ -466,11 +460,9 @@ class Kernel:
|
||||
if not hasattr(candidate, "__sk_function__"):
|
||||
continue
|
||||
|
||||
functions.append(
|
||||
SKFunction.from_native_method(candidate, skill_name, self.logger)
|
||||
)
|
||||
functions.append(SKFunction.from_native_method(candidate, skill_name))
|
||||
|
||||
self.logger.debug(f"Methods imported: {len(functions)}")
|
||||
logger.debug(f"Methods imported: {len(functions)}")
|
||||
|
||||
# Uniqueness check on function names
|
||||
function_names = [f.name for f in functions]
|
||||
|
||||
@@ -1,28 +1,27 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from copy import deepcopy
|
||||
from logging import Logger
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
from typing import Dict, List, Tuple
|
||||
|
||||
from numpy import array, linalg, ndarray
|
||||
|
||||
from semantic_kernel.memory.memory_record import MemoryRecord
|
||||
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class VolatileMemoryStore(MemoryStoreBase):
|
||||
_store: Dict[str, Dict[str, MemoryRecord]]
|
||||
_logger: Logger
|
||||
|
||||
def __init__(self, logger: Optional[Logger] = None) -> None:
|
||||
def __init__(self, **kwargs) -> None:
|
||||
"""Initializes a new instance of the VolatileMemoryStore class."""
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
self._store = {}
|
||||
self._logger = logger or NullLogger()
|
||||
"""Initializes a new instance of the VolatileMemoryStore class.
|
||||
|
||||
Arguments:
|
||||
logger {Optional[Logger]} -- The logger to use. (default: {None})
|
||||
"""
|
||||
|
||||
async def create_collection_async(self, collection_name: str) -> None:
|
||||
"""Creates a new collection if it does not exist.
|
||||
@@ -313,7 +312,7 @@ class VolatileMemoryStore(MemoryStoreBase):
|
||||
embedding_array[valid_indices].T
|
||||
) / (query_norm * collection_norm[valid_indices])
|
||||
if not valid_indices.all():
|
||||
self._logger.warning(
|
||||
logger.warning(
|
||||
"Some vectors in the embedding collection are zero vectors."
|
||||
"Ignoring cosine similarity score computation for those vectors."
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
import logging
|
||||
from typing import Any, Dict, Generic, Literal, Optional, Tuple, Union
|
||||
|
||||
from pydantic import Field, PrivateAttr
|
||||
@@ -19,6 +19,8 @@ from semantic_kernel.skill_definition.read_only_skill_collection_base import (
|
||||
ReadOnlySkillCollectionBase,
|
||||
)
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SKContext(SKBaseModel, Generic[SemanticTextMemoryT]):
|
||||
"""Semantic Kernel context."""
|
||||
@@ -33,14 +35,13 @@ class SKContext(SKBaseModel, Generic[SemanticTextMemoryT]):
|
||||
_error_occurred: bool = PrivateAttr(False)
|
||||
_last_exception: Optional[Exception] = PrivateAttr(None)
|
||||
_last_error_description: str = PrivateAttr("")
|
||||
_logger: Logger = PrivateAttr()
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
variables: ContextVariables,
|
||||
memory: SemanticTextMemoryBase,
|
||||
skill_collection: Union[ReadOnlySkillCollection, None],
|
||||
logger: Optional[Logger] = None,
|
||||
**kwargs,
|
||||
# TODO: cancellation token?
|
||||
) -> None:
|
||||
"""
|
||||
@@ -50,10 +51,11 @@ class SKContext(SKBaseModel, Generic[SemanticTextMemoryT]):
|
||||
variables {ContextVariables} -- The context variables.
|
||||
memory {SemanticTextMemoryBase} -- The semantic text memory.
|
||||
skill_collection {ReadOnlySkillCollectionBase} -- The skill collection.
|
||||
logger {Logger} -- The logger.
|
||||
"""
|
||||
# Local import to avoid circular dependency
|
||||
from semantic_kernel import NullLogger
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
|
||||
if skill_collection is None:
|
||||
skill_collection = ReadOnlySkillCollection()
|
||||
@@ -61,7 +63,6 @@ class SKContext(SKBaseModel, Generic[SemanticTextMemoryT]):
|
||||
super().__init__(
|
||||
variables=variables, memory=memory, skill_collection=skill_collection
|
||||
)
|
||||
self._logger = logger or NullLogger()
|
||||
|
||||
def fail(self, error_description: str, exception: Optional[Exception] = None):
|
||||
"""
|
||||
@@ -147,16 +148,6 @@ class SKContext(SKBaseModel, Generic[SemanticTextMemoryT]):
|
||||
"""
|
||||
self.skill_collection = value
|
||||
|
||||
@property
|
||||
def log(self) -> Logger:
|
||||
"""
|
||||
The logger.
|
||||
|
||||
Returns:
|
||||
Logger -- The logger.
|
||||
"""
|
||||
return self._logger
|
||||
|
||||
def __setitem__(self, key: str, value: Any) -> None:
|
||||
"""
|
||||
Sets a context variable.
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import platform
|
||||
import sys
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from enum import Enum
|
||||
from logging import Logger
|
||||
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional
|
||||
|
||||
from semantic_kernel.connectors.ai.chat_completion_client_base import (
|
||||
@@ -35,7 +35,6 @@ from semantic_kernel.skill_definition.parameter_view import ParameterView
|
||||
from semantic_kernel.skill_definition.read_only_skill_collection_base import (
|
||||
ReadOnlySkillCollectionBase,
|
||||
)
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from semantic_kernel.orchestration.sk_context import SKContext
|
||||
@@ -43,6 +42,8 @@ if TYPE_CHECKING:
|
||||
if platform.system() == "Windows" and sys.version_info >= (3, 8, 0):
|
||||
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SKFunction(SKFunctionBase):
|
||||
"""
|
||||
@@ -54,7 +55,6 @@ class SKFunction(SKFunctionBase):
|
||||
_delegate_type: DelegateTypes
|
||||
_function: Callable[..., Any]
|
||||
_skill_collection: Optional[ReadOnlySkillCollectionBase]
|
||||
_log: Logger
|
||||
_ai_service: Optional[TextCompletionClientBase]
|
||||
_ai_request_settings: CompleteRequestSettings
|
||||
_chat_service: Optional[ChatCompletionClientBase]
|
||||
@@ -63,6 +63,10 @@ class SKFunction(SKFunctionBase):
|
||||
|
||||
@staticmethod
|
||||
def from_native_method(method, skill_name="", log=None) -> "SKFunction":
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
if method is None:
|
||||
raise ValueError("Method cannot be `None`")
|
||||
|
||||
@@ -110,7 +114,6 @@ class SKFunction(SKFunctionBase):
|
||||
skill_name=skill_name,
|
||||
function_name=method.__sk_function_name__,
|
||||
is_semantic=False,
|
||||
log=log,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -118,8 +121,12 @@ class SKFunction(SKFunctionBase):
|
||||
skill_name: str,
|
||||
function_name: str,
|
||||
function_config: SemanticFunctionConfig,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> "SKFunction":
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
if function_config is None:
|
||||
raise ValueError("Function configuration cannot be `None`")
|
||||
|
||||
@@ -149,7 +156,7 @@ class SKFunction(SKFunctionBase):
|
||||
else None
|
||||
)
|
||||
if request_settings.function_call is not None and functions is None:
|
||||
log.warning("Function call is not None, but functions is None")
|
||||
logger.warning("Function call is not None, but functions is None")
|
||||
try:
|
||||
if functions and hasattr(client, "complete_chat_with_functions_async"):
|
||||
if (
|
||||
@@ -277,7 +284,6 @@ class SKFunction(SKFunctionBase):
|
||||
skill_name=skill_name,
|
||||
function_name=function_name,
|
||||
is_semantic=True,
|
||||
log=log,
|
||||
chat_prompt_template=function_config.prompt_template
|
||||
if function_config.has_chat_prompt
|
||||
else None,
|
||||
@@ -320,11 +326,15 @@ class SKFunction(SKFunctionBase):
|
||||
skill_name: str,
|
||||
function_name: str,
|
||||
is_semantic: bool,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
delegate_stream_function: Optional[Callable[..., Any]] = None,
|
||||
**kwargs: Dict[str, Any],
|
||||
) -> None:
|
||||
super().__init__()
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
self._delegate_type = delegate_type
|
||||
self._function = delegate_function
|
||||
self._parameters = parameters
|
||||
@@ -332,7 +342,6 @@ class SKFunction(SKFunctionBase):
|
||||
self._skill_name = skill_name
|
||||
self._name = function_name
|
||||
self._is_semantic = is_semantic
|
||||
self._log = log if log is not None else NullLogger()
|
||||
self._stream_function = delegate_stream_function
|
||||
self._skill_collection = None
|
||||
self._ai_service = None
|
||||
@@ -395,15 +404,18 @@ class SKFunction(SKFunctionBase):
|
||||
context: Optional["SKContext"] = None,
|
||||
memory: Optional[SemanticTextMemoryBase] = None,
|
||||
settings: Optional[CompleteRequestSettings] = None,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> "SKContext":
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
return self.invoke(
|
||||
input=input,
|
||||
variables=variables,
|
||||
context=context,
|
||||
memory=memory,
|
||||
settings=settings,
|
||||
log=log,
|
||||
)
|
||||
|
||||
def invoke(
|
||||
@@ -413,16 +425,20 @@ class SKFunction(SKFunctionBase):
|
||||
context: Optional["SKContext"] = None,
|
||||
memory: Optional[SemanticTextMemoryBase] = None,
|
||||
settings: Optional[CompleteRequestSettings] = None,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> "SKContext":
|
||||
from semantic_kernel.orchestration.sk_context import SKContext
|
||||
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
|
||||
if context is None:
|
||||
context = SKContext(
|
||||
variables=ContextVariables("") if variables is None else variables,
|
||||
skill_collection=self._skill_collection,
|
||||
memory=memory if memory is not None else NullMemory.instance,
|
||||
logger=log if log is not None else self._log,
|
||||
)
|
||||
else:
|
||||
# If context is passed, we need to merge the variables
|
||||
@@ -464,17 +480,21 @@ class SKFunction(SKFunctionBase):
|
||||
context: Optional["SKContext"] = None,
|
||||
memory: Optional[SemanticTextMemoryBase] = None,
|
||||
settings: Optional[CompleteRequestSettings] = None,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
**kwargs: Dict[str, Any],
|
||||
) -> "SKContext":
|
||||
from semantic_kernel.orchestration.sk_context import SKContext
|
||||
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
|
||||
if context is None:
|
||||
context = SKContext(
|
||||
variables=ContextVariables("") if variables is None else variables,
|
||||
skill_collection=self._skill_collection,
|
||||
memory=memory if memory is not None else NullMemory.instance,
|
||||
logger=log if log is not None else self._log,
|
||||
)
|
||||
else:
|
||||
# If context is passed, we need to merge the variables
|
||||
@@ -539,7 +559,7 @@ class SKFunction(SKFunctionBase):
|
||||
if self._is_semantic:
|
||||
return
|
||||
|
||||
self._log.error("The function is not semantic")
|
||||
logger.error("The function is not semantic")
|
||||
raise KernelException(
|
||||
KernelException.ErrorCodes.InvalidFunctionType,
|
||||
"Invalid operation, the method requires a semantic function",
|
||||
@@ -549,7 +569,7 @@ class SKFunction(SKFunctionBase):
|
||||
if not self._is_semantic:
|
||||
return
|
||||
|
||||
self._log.error("The function is not native")
|
||||
logger.error("The function is not native")
|
||||
raise KernelException(
|
||||
KernelException.ErrorCodes.InvalidFunctionType,
|
||||
"Invalid operation, the method requires a native function",
|
||||
@@ -562,7 +582,6 @@ class SKFunction(SKFunctionBase):
|
||||
context: Optional["SKContext"] = None,
|
||||
memory: Optional[SemanticTextMemoryBase] = None,
|
||||
settings: Optional[CompleteRequestSettings] = None,
|
||||
log: Optional[Logger] = None,
|
||||
):
|
||||
from semantic_kernel.orchestration.sk_context import SKContext
|
||||
|
||||
@@ -571,7 +590,6 @@ class SKFunction(SKFunctionBase):
|
||||
variables=ContextVariables("") if variables is None else variables,
|
||||
skill_collection=self._skill_collection,
|
||||
memory=memory if memory is not None else NullMemory.instance,
|
||||
logger=log if log is not None else self._log,
|
||||
)
|
||||
else:
|
||||
# If context is passed, we need to merge the variables
|
||||
@@ -647,8 +665,8 @@ class SKFunction(SKFunctionBase):
|
||||
|
||||
context.skills = self._skill_collection
|
||||
|
||||
def _trace_function_type_Call(self, type: Enum, log: Logger) -> None:
|
||||
log.debug(f"Executing function type {type}: {type.name}")
|
||||
def _trace_function_type_Call(self, type: Enum) -> None:
|
||||
logger.debug(f"Executing function type {type}: {type.name}")
|
||||
|
||||
"""
|
||||
Async code wrapper to allow running async code inside external
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from abc import abstractmethod
|
||||
from logging import Logger
|
||||
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional
|
||||
|
||||
from semantic_kernel.connectors.ai.complete_request_settings import (
|
||||
@@ -103,7 +102,6 @@ class SKFunctionBase(SKBaseModel):
|
||||
context: Optional["SKContext"] = None,
|
||||
memory: Optional[SemanticTextMemoryBase] = None,
|
||||
settings: Optional[CompleteRequestSettings] = None,
|
||||
log: Optional[Logger] = None,
|
||||
) -> "SKContext":
|
||||
"""
|
||||
Invokes the function with an explicit string input
|
||||
@@ -113,7 +111,6 @@ class SKFunctionBase(SKBaseModel):
|
||||
context {SKContext} -- The context to use
|
||||
memory: {SemanticTextMemoryBase} -- The memory to use
|
||||
settings {CompleteRequestSettings} -- LLM completion settings
|
||||
log {Logger} -- Application logger
|
||||
Returns:
|
||||
SKContext -- The updated context, potentially a new one if
|
||||
context switching is implemented.
|
||||
@@ -128,7 +125,6 @@ class SKFunctionBase(SKBaseModel):
|
||||
context: Optional["SKContext"] = None,
|
||||
memory: Optional[SemanticTextMemoryBase] = None,
|
||||
settings: Optional[CompleteRequestSettings] = None,
|
||||
log: Optional[Logger] = None,
|
||||
**kwargs: Dict[str, Any],
|
||||
) -> "SKContext":
|
||||
"""
|
||||
@@ -139,7 +135,6 @@ class SKFunctionBase(SKBaseModel):
|
||||
context {SKContext} -- The context to use
|
||||
memory: {SemanticTextMemoryBase} -- The memory to use
|
||||
settings {CompleteRequestSettings} -- LLM completion settings
|
||||
log {Logger} -- Application logger
|
||||
Returns:
|
||||
SKContext -- The updated context, potentially a new one if
|
||||
context switching is implemented.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
import itertools
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from logging import Logger
|
||||
from textwrap import dedent
|
||||
from typing import List, Optional
|
||||
|
||||
@@ -20,7 +20,8 @@ from semantic_kernel.planning.planning_exception import PlanningException
|
||||
from semantic_kernel.skill_definition import sk_function, sk_function_context_parameter
|
||||
from semantic_kernel.skill_definition.function_view import FunctionView
|
||||
from semantic_kernel.skill_definition.parameter_view import ParameterView
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ActionPlanner:
|
||||
@@ -40,22 +41,24 @@ class ActionPlanner:
|
||||
|
||||
_kernel: Kernel
|
||||
_prompt_template: str
|
||||
_logger: Logger
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
kernel: Kernel,
|
||||
config: Optional[ActionPlannerConfig] = None,
|
||||
prompt: Optional[str] = None,
|
||||
logger: Optional[Logger] = None,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
if kernel is None:
|
||||
raise PlanningException(
|
||||
PlanningException.ErrorCodes.InvalidConfiguration,
|
||||
"Kernel cannot be `None`.",
|
||||
)
|
||||
|
||||
self._logger = logger if logger else NullLogger()
|
||||
self.config = config or ActionPlannerConfig()
|
||||
|
||||
__cur_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
@@ -85,7 +88,7 @@ class ActionPlanner:
|
||||
PlanningException.ErrorCodes.InvalidGoal, "Goal cannot be `None`."
|
||||
)
|
||||
|
||||
self._logger.info(f"Finding the best function for achieving the goal: {goal}")
|
||||
logger.info(f"Finding the best function for achieving the goal: {goal}")
|
||||
|
||||
self._context.variables.update(goal)
|
||||
|
||||
@@ -95,20 +98,20 @@ class ActionPlanner:
|
||||
generated_plan_raw_str = str(generated_plan_raw)
|
||||
|
||||
if not generated_plan_raw or not generated_plan_raw_str:
|
||||
self._logger.error("No plan has been generated.")
|
||||
logger.error("No plan has been generated.")
|
||||
raise PlanningException(
|
||||
PlanningException.ErrorCodes.CreatePlanError,
|
||||
"No plan has been generated.",
|
||||
)
|
||||
|
||||
self._logger.info(f"Plan generated by ActionPlanner:\n{generated_plan_raw_str}")
|
||||
logger.info(f"Plan generated by ActionPlanner:\n{generated_plan_raw_str}")
|
||||
|
||||
# Ignore additional text around JSON recursively
|
||||
json_regex = r"\{(?:[^{}]|(?R))*\}"
|
||||
generated_plan_str = regex.search(json_regex, generated_plan_raw_str)
|
||||
|
||||
if not generated_plan_str:
|
||||
self._logger.error("No valid plan has been generated.")
|
||||
logger.error("No valid plan has been generated.")
|
||||
raise PlanningException(
|
||||
PlanningException.ErrorCodes.InvalidPlan,
|
||||
"No valid plan has been generated.",
|
||||
@@ -121,19 +124,19 @@ class ActionPlanner:
|
||||
try:
|
||||
generated_plan = json.loads(generated_plan_str)
|
||||
except json.decoder.JSONDecodeError as e:
|
||||
self._logger.error("Encountered an error while parsing Plan JSON.")
|
||||
self._logger.error(e)
|
||||
logger.error("Encountered an error while parsing Plan JSON.")
|
||||
logger.error(e)
|
||||
raise PlanningException(
|
||||
PlanningException.ErrorCodes.InvalidPlan,
|
||||
"Encountered an error while parsing Plan JSON.",
|
||||
)
|
||||
|
||||
self._logger.info(
|
||||
logger.info(
|
||||
f"Python dictionary of plan generated by ActionPlanner:\n{generated_plan}"
|
||||
)
|
||||
|
||||
if not generated_plan["plan"]:
|
||||
self._logger.error("Suitable plan not generated by ActionPlanner.")
|
||||
logger.error("Suitable plan not generated by ActionPlanner.")
|
||||
raise PlanningException(
|
||||
PlanningException.ErrorCodes.CreatePlanError,
|
||||
"Suitable plan not generated by ActionPlanner.",
|
||||
@@ -141,14 +144,12 @@ class ActionPlanner:
|
||||
|
||||
if not generated_plan["plan"]["function"]:
|
||||
# no suitable function identified, returning plan with no steps
|
||||
self._logger.warn(
|
||||
"No suitable function has been identified by ActionPlanner."
|
||||
)
|
||||
logger.warn("No suitable function has been identified by ActionPlanner.")
|
||||
plan = Plan(description=goal)
|
||||
elif "." in generated_plan["plan"]["function"]:
|
||||
skill, fun = generated_plan["plan"]["function"].split(".")
|
||||
function_ref = self._context.skills.get_function(skill, fun)
|
||||
self._logger.info(
|
||||
logger.info(
|
||||
f"ActionPlanner has picked {skill}.{fun}. Reference to this function"
|
||||
f" found in context: {function_ref}"
|
||||
)
|
||||
@@ -157,7 +158,7 @@ class ActionPlanner:
|
||||
function_ref = self._context.skills.get_function(
|
||||
generated_plan["plan"]["function"]
|
||||
)
|
||||
self._logger.info(
|
||||
logger.info(
|
||||
f"ActionPlanner has picked {generated_plan['plan']['function']}. "
|
||||
" Reference to this function found in context:"
|
||||
f" {function_ref}"
|
||||
@@ -165,7 +166,7 @@ class ActionPlanner:
|
||||
plan = Plan(description=goal, function=function_ref)
|
||||
|
||||
for key, val in generated_plan["plan"]["parameters"].items():
|
||||
self._logger.info(f"Parameter {key}: {val}")
|
||||
logger.info(f"Parameter {key}: {val}")
|
||||
if val:
|
||||
plan.parameters[key] = str(val)
|
||||
plan.state[key] = str(val)
|
||||
@@ -279,7 +280,7 @@ class ActionPlanner:
|
||||
|
||||
available_functions_str = "\n".join(available_functions)
|
||||
|
||||
self._logger.info(f"List of available functions:\n{available_functions_str}")
|
||||
logger.info(f"List of available functions:\n{available_functions_str}")
|
||||
|
||||
return available_functions_str
|
||||
|
||||
@@ -297,7 +298,7 @@ class ActionPlanner:
|
||||
"""
|
||||
|
||||
if not function.description:
|
||||
self._logger.warn(
|
||||
logger.warn(
|
||||
f"{function.skill_name}.{function.name} is missing a description"
|
||||
)
|
||||
description = f"// Function {function.skill_name}.{function.name}."
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import re
|
||||
import threading
|
||||
from logging import Logger
|
||||
from typing import Any, Callable, ClassVar, List, Optional, Union
|
||||
|
||||
from pydantic import PrivateAttr
|
||||
@@ -26,7 +26,8 @@ from semantic_kernel.skill_definition.read_only_skill_collection import (
|
||||
from semantic_kernel.skill_definition.read_only_skill_collection_base import (
|
||||
ReadOnlySkillCollectionBase,
|
||||
)
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Plan(SKFunctionBase):
|
||||
@@ -136,9 +137,13 @@ class Plan(SKFunctionBase):
|
||||
context: Optional[SKContext] = None,
|
||||
settings: Optional[CompleteRequestSettings] = None,
|
||||
memory: Optional[SemanticTextMemoryBase] = None,
|
||||
logger: Optional[Logger] = None,
|
||||
**kwargs,
|
||||
# TODO: cancellation_token: CancellationToken,
|
||||
) -> SKContext:
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
if input is not None and input != "":
|
||||
self._state.update(input)
|
||||
|
||||
@@ -147,7 +152,6 @@ class Plan(SKFunctionBase):
|
||||
variables=self._state,
|
||||
skill_collection=ReadOnlySkillCollection(),
|
||||
memory=memory or NullMemory(),
|
||||
logger=logger if logger is not None else NullLogger(),
|
||||
)
|
||||
|
||||
if self._function is not None:
|
||||
@@ -155,7 +159,7 @@ class Plan(SKFunctionBase):
|
||||
context=context, settings=settings
|
||||
)
|
||||
if result.error_occurred:
|
||||
result.log.error(
|
||||
logger.error(
|
||||
"Something went wrong in plan step {0}.{1}:'{2}'".format(
|
||||
self._skill_name, self._name, result.last_error_description
|
||||
)
|
||||
@@ -178,8 +182,12 @@ class Plan(SKFunctionBase):
|
||||
context: Optional[SKContext] = None,
|
||||
settings: Optional[CompleteRequestSettings] = None,
|
||||
memory: Optional[SemanticTextMemoryBase] = None,
|
||||
logger: Optional[Logger] = None,
|
||||
**kwargs,
|
||||
) -> SKContext:
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
if input is not None and input != "":
|
||||
self._state.update(input)
|
||||
|
||||
@@ -188,13 +196,12 @@ class Plan(SKFunctionBase):
|
||||
variables=self._state,
|
||||
skill_collection=ReadOnlySkillCollection(),
|
||||
memory=memory or NullMemory(),
|
||||
logger=logger,
|
||||
)
|
||||
|
||||
if self._function is not None:
|
||||
result = self._function.invoke(context=context, settings=settings)
|
||||
if result.error_occurred:
|
||||
result.log.error(
|
||||
logger.error(
|
||||
result.last_exception,
|
||||
"Something went wrong in plan step {0}.{1}:'{2}'".format(
|
||||
self.skill_name, self.name, context.last_error_description
|
||||
@@ -308,7 +315,6 @@ class Plan(SKFunctionBase):
|
||||
variables=variables,
|
||||
memory=context.memory,
|
||||
skill_collection=context.skills,
|
||||
logger=context.log,
|
||||
)
|
||||
result = await step.invoke_async(context=func_context)
|
||||
result_value = result.result
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import itertools
|
||||
import logging
|
||||
from typing import AsyncIterable, List
|
||||
|
||||
from semantic_kernel.kernel_exception import KernelException
|
||||
@@ -12,6 +13,8 @@ from semantic_kernel.planning.sequential_planner.sequential_planner_config impor
|
||||
)
|
||||
from semantic_kernel.skill_definition.function_view import FunctionView
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SequentialPlannerFunctionViewExtension:
|
||||
@staticmethod
|
||||
@@ -180,7 +183,7 @@ class SequentialPlannerSKContextExtension:
|
||||
None,
|
||||
)
|
||||
if function is not None:
|
||||
context.log.debug(
|
||||
logger.debug(
|
||||
"Found relevant function. Relevance Score: {0}, Function: {1}".format(
|
||||
memory_entry.relevance,
|
||||
SequentialPlannerFunctionViewExtension.to_fully_qualified_name(
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import asyncio
|
||||
import itertools
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from typing import TYPE_CHECKING, Dict, List
|
||||
@@ -31,6 +32,7 @@ from semantic_kernel.skill_definition.sk_function_decorator import sk_function
|
||||
if TYPE_CHECKING:
|
||||
from semantic_kernel.orchestration.sk_function_base import SKFunctionBase
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
CUR_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||
PROMPT_CONFIG_FILE_PATH = os.path.join(CUR_DIR, "Skills/StepwiseStep/config.json")
|
||||
@@ -99,7 +101,6 @@ class StepwisePlanner:
|
||||
self._native_functions = self._kernel.import_skill(self, RESTRICTED_SKILL_NAME)
|
||||
|
||||
self._context = kernel.create_new_context()
|
||||
self._logger = self._kernel.logger
|
||||
|
||||
def create_plan(self, goal: str) -> Plan:
|
||||
if is_null_or_empty(goal):
|
||||
@@ -154,13 +155,13 @@ class StepwisePlanner:
|
||||
)
|
||||
|
||||
action_text = llm_response.result.strip()
|
||||
self._logger.debug(f"Response: {action_text}")
|
||||
logger.debug(f"Response: {action_text}")
|
||||
|
||||
next_step = self.parse_result(action_text)
|
||||
steps_taken.append(next_step)
|
||||
|
||||
if not is_null_or_empty(next_step.final_answer):
|
||||
self._logger.debug(f"Final Answer: {next_step.final_answer}")
|
||||
logger.debug(f"Final Answer: {next_step.final_answer}")
|
||||
|
||||
context.variables.update(next_step.final_answer)
|
||||
updated_scratch_pad = self.create_scratch_pad(question, steps_taken)
|
||||
@@ -171,11 +172,11 @@ class StepwisePlanner:
|
||||
|
||||
return context
|
||||
|
||||
self._logger.debug("Thoughts: {next_step.thought}")
|
||||
logger.debug("Thoughts: {next_step.thought}")
|
||||
|
||||
if not is_null_or_empty(next_step.action):
|
||||
self._logger.info(f"Action: {next_step.action}. Iteration: {i+1}.")
|
||||
self._logger.debug(
|
||||
logger.info(f"Action: {next_step.action}. Iteration: {i+1}.")
|
||||
logger.debug(
|
||||
f"Action: {next_step.action}({next_step.action_variables}). Iteration: {i+1}.",
|
||||
)
|
||||
|
||||
@@ -194,13 +195,11 @@ class StepwisePlanner:
|
||||
next_step.observation = (
|
||||
f"Error invoking action {next_step.action}: {str(e)}"
|
||||
)
|
||||
self._logger.warning(
|
||||
f"Error invoking action {next_step.action}"
|
||||
)
|
||||
logger.warning(f"Error invoking action {next_step.action}")
|
||||
|
||||
self._logger.debug(f"Observation: {next_step.observation}")
|
||||
logger.debug(f"Observation: {next_step.observation}")
|
||||
else:
|
||||
self._logger.info("Action: No action to take")
|
||||
logger.info("Action: No action to take")
|
||||
|
||||
# sleep 3 seconds
|
||||
await asyncio.sleep(self.config.min_iteration_time_ms / 1000)
|
||||
@@ -306,7 +305,7 @@ class StepwisePlanner:
|
||||
|
||||
for i in reversed(range(len(steps_taken))):
|
||||
if len(scratch_pad_lines) / 4.0 > (self.config.max_tokens * 0.75):
|
||||
self._logger.debug(
|
||||
logger.debug(
|
||||
f"Scratchpad is too long, truncating. Skipping {i + 1} steps."
|
||||
)
|
||||
break
|
||||
@@ -330,7 +329,7 @@ class StepwisePlanner:
|
||||
scratch_pad = "\n".join(scratch_pad_lines).strip()
|
||||
|
||||
if not (is_null_or_empty(scratch_pad.strip())):
|
||||
self._logger.debug(f"Scratchpad: {scratch_pad}")
|
||||
logger.debug(f"Scratchpad: {scratch_pad}")
|
||||
|
||||
return scratch_pad
|
||||
|
||||
@@ -362,17 +361,15 @@ class StepwisePlanner:
|
||||
result = await function.invoke_async(context=action_context)
|
||||
|
||||
if result.error_occurred:
|
||||
self._logger.error(f"Error occurred: {result.last_exception}")
|
||||
logger.error(f"Error occurred: {result.last_exception}")
|
||||
return f"Error occurred: {result.last_exception}"
|
||||
|
||||
self._logger.debug(
|
||||
f"Invoked {target_function.name}. Result: {result.result}"
|
||||
)
|
||||
logger.debug(f"Invoked {target_function.name}. Result: {result.result}")
|
||||
|
||||
return result.result
|
||||
|
||||
except Exception as e:
|
||||
self._logger.error(
|
||||
logger.error(
|
||||
e,
|
||||
f"Something went wrong in system step: {target_function.skill_name}.{target_function.name}. Error: {e}",
|
||||
)
|
||||
|
||||
@@ -1,31 +1,36 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from typing import Awaitable, Callable, TypeVar
|
||||
from typing import Any, Awaitable, Callable, Optional, TypeVar
|
||||
|
||||
from semantic_kernel.reliability.retry_mechanism_base import RetryMechanismBase
|
||||
from semantic_kernel.sk_pydantic import SKBaseModel
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PassThroughWithoutRetry(RetryMechanismBase, SKBaseModel):
|
||||
"""A retry mechanism that does not retry."""
|
||||
|
||||
async def execute_with_retry_async(
|
||||
self, action: Callable[[], Awaitable[T]], log: logging.Logger
|
||||
self, action: Callable[[], Awaitable[T]], log: Optional[Any] = None
|
||||
) -> Awaitable[T]:
|
||||
"""Executes the given action with retry logic.
|
||||
|
||||
Arguments:
|
||||
action {Callable[[], Awaitable[T]]} -- The action to retry on exception.
|
||||
log {logging.Logger} -- The logger to use.
|
||||
|
||||
Returns:
|
||||
Awaitable[T] -- An awaitable that will return the result of the action.
|
||||
"""
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
try:
|
||||
await action()
|
||||
except Exception as e:
|
||||
log.warning(e, "Error executing action, not retrying")
|
||||
logger.warning(e, "Error executing action, not retrying")
|
||||
raise
|
||||
|
||||
@@ -2,23 +2,28 @@
|
||||
|
||||
import logging
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Awaitable, Callable, TypeVar
|
||||
from typing import Any, Awaitable, Callable, Optional, TypeVar
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RetryMechanismBase(ABC):
|
||||
@abstractmethod
|
||||
async def execute_with_retry_async(
|
||||
self, action: Callable[[], Awaitable[T]], log: logging.Logger
|
||||
self, action: Callable[[], Awaitable[T]], log: Optional[Any] = None
|
||||
) -> Awaitable[T]:
|
||||
"""Executes the given action with retry logic.
|
||||
|
||||
Arguments:
|
||||
action {Callable[[], Awaitable[T]]} -- The action to retry on exception.
|
||||
log {logging.Logger} -- The logger to use.
|
||||
|
||||
Returns:
|
||||
Awaitable[T] -- An awaitable that will return the result of the action.
|
||||
"""
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
pass
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from logging import Logger
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, Any, Dict, Generic, List, Optional, TypeVar
|
||||
|
||||
from semantic_kernel.models.chat.chat_message import ChatMessage
|
||||
@@ -18,6 +18,8 @@ if TYPE_CHECKING:
|
||||
|
||||
ChatMessageT = TypeVar("ChatMessageT", bound=ChatMessage)
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ChatPromptTemplate(PromptTemplate, Generic[ChatMessageT]):
|
||||
_messages: List[ChatMessageT]
|
||||
@@ -27,9 +29,13 @@ class ChatPromptTemplate(PromptTemplate, Generic[ChatMessageT]):
|
||||
template: str,
|
||||
template_engine: PromptTemplatingEngine,
|
||||
prompt_config: PromptTemplateConfig,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
super().__init__(template, template_engine, prompt_config, log)
|
||||
super().__init__(template, template_engine, prompt_config)
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
self._messages = []
|
||||
if self._prompt_config.completion.chat_system_prompt:
|
||||
self.add_system_message(self._prompt_config.completion.chat_system_prompt)
|
||||
@@ -95,7 +101,7 @@ class ChatPromptTemplate(PromptTemplate, Generic[ChatMessageT]):
|
||||
template: str,
|
||||
template_engine: PromptTemplatingEngine,
|
||||
prompt_config: PromptTemplateConfig,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> "ChatPromptTemplate":
|
||||
"""Restore a ChatPromptTemplate from a list of role and message pairs.
|
||||
|
||||
@@ -103,7 +109,11 @@ class ChatPromptTemplate(PromptTemplate, Generic[ChatMessageT]):
|
||||
that takes precedence over the first message in the list of messages,
|
||||
if that is a system message.
|
||||
"""
|
||||
chat_template = cls(template, template_engine, prompt_config, log)
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
chat_template = cls(template, template_engine, prompt_config)
|
||||
if (
|
||||
prompt_config.completion.chat_system_prompt
|
||||
and messages[0]["role"] == "system"
|
||||
@@ -113,7 +123,7 @@ class ChatPromptTemplate(PromptTemplate, Generic[ChatMessageT]):
|
||||
existing_system_message["message"]
|
||||
!= prompt_config.completion.chat_system_prompt
|
||||
):
|
||||
chat_template._log.info(
|
||||
logger.info(
|
||||
"Overriding system prompt with chat_system_prompt, old system message: %s, new system message: %s",
|
||||
existing_system_message["message"],
|
||||
prompt_config.completion.chat_system_prompt,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, Any, List, Optional
|
||||
|
||||
from semantic_kernel.semantic_functions.prompt_template_base import PromptTemplateBase
|
||||
from semantic_kernel.semantic_functions.prompt_template_config import (
|
||||
@@ -13,16 +13,16 @@ from semantic_kernel.template_engine.blocks.var_block import VarBlock
|
||||
from semantic_kernel.template_engine.protocols.prompt_templating_engine import (
|
||||
PromptTemplatingEngine,
|
||||
)
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from semantic_kernel.orchestration.sk_context import SKContext
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PromptTemplate(PromptTemplateBase):
|
||||
_template: str
|
||||
_template_engine: PromptTemplatingEngine
|
||||
_log: Logger
|
||||
_prompt_config: PromptTemplateConfig
|
||||
|
||||
def __init__(
|
||||
@@ -30,12 +30,15 @@ class PromptTemplate(PromptTemplateBase):
|
||||
template: str,
|
||||
template_engine: PromptTemplatingEngine,
|
||||
prompt_config: PromptTemplateConfig,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
self._template = template
|
||||
self._template_engine = template_engine
|
||||
self._prompt_config = prompt_config
|
||||
self._log = log if log is not None else NullLogger()
|
||||
|
||||
def get_parameters(self) -> List[ParameterView]:
|
||||
seen = set()
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
from typing import TYPE_CHECKING, ClassVar, Dict, Optional, Tuple
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, Any, ClassVar, Dict, Optional, Tuple
|
||||
|
||||
from pydantic import ConfigDict, Field, PrivateAttr
|
||||
from pydantic import ConfigDict, Field
|
||||
|
||||
from semantic_kernel.kernel_exception import KernelException
|
||||
from semantic_kernel.orchestration.sk_function import SKFunction
|
||||
@@ -12,25 +12,29 @@ from semantic_kernel.skill_definition.functions_view import FunctionsView
|
||||
from semantic_kernel.skill_definition.read_only_skill_collection_base import (
|
||||
ReadOnlySkillCollectionBase,
|
||||
)
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from semantic_kernel.orchestration.sk_function_base import SKFunctionBase
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ReadOnlySkillCollection(ReadOnlySkillCollectionBase):
|
||||
GLOBAL_SKILL: ClassVar[str] = constants.GLOBAL_SKILL
|
||||
data: Dict[str, Dict[str, SKFunction]] = Field(default_factory=dict)
|
||||
_log: Logger = PrivateAttr(default_factory=NullLogger)
|
||||
model_config = ConfigDict(frozen=False)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
data: Dict[str, Dict[str, SKFunction]] = None,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
super().__init__(data=data or {})
|
||||
self._log = log or NullLogger()
|
||||
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
|
||||
def has_function(self, skill_name: Optional[str], function_name: str) -> bool:
|
||||
s_name, f_name = self._normalize_names(skill_name, function_name, True)
|
||||
@@ -61,7 +65,7 @@ class ReadOnlySkillCollection(ReadOnlySkillCollectionBase):
|
||||
if self.has_semantic_function(s_name, f_name):
|
||||
return self.data[s_name][f_name]
|
||||
|
||||
self._log.error(f"Function not available: {s_name}.{f_name}")
|
||||
logger.error(f"Function not available: {s_name}.{f_name}")
|
||||
raise KernelException(
|
||||
KernelException.ErrorCodes.FunctionNotAvailable,
|
||||
f"Function not available: {s_name}.{f_name}",
|
||||
@@ -74,7 +78,7 @@ class ReadOnlySkillCollection(ReadOnlySkillCollectionBase):
|
||||
if self.has_native_function(s_name, f_name):
|
||||
return self.data[s_name][f_name]
|
||||
|
||||
self._log.error(f"Function not available: {s_name}.{f_name}")
|
||||
logger.error(f"Function not available: {s_name}.{f_name}")
|
||||
raise KernelException(
|
||||
KernelException.ErrorCodes.FunctionNotAvailable,
|
||||
f"Function not available: {s_name}.{f_name}",
|
||||
@@ -101,7 +105,7 @@ class ReadOnlySkillCollection(ReadOnlySkillCollectionBase):
|
||||
if self.has_function(s_name, f_name):
|
||||
return self.data[s_name][f_name]
|
||||
|
||||
self._log.error(f"Function not available: {s_name}.{f_name}")
|
||||
logger.error(f"Function not available: {s_name}.{f_name}")
|
||||
raise KernelException(
|
||||
KernelException.ErrorCodes.FunctionNotAvailable,
|
||||
f"Function not available: {s_name}.{f_name}",
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
ClassVar,
|
||||
Dict,
|
||||
Optional,
|
||||
Union,
|
||||
)
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, Any, ClassVar, Dict, Optional, Union
|
||||
|
||||
from pydantic import Field, PrivateAttr
|
||||
from pydantic import Field
|
||||
|
||||
from semantic_kernel.orchestration.sk_function import SKFunction
|
||||
from semantic_kernel.skill_definition import constants
|
||||
@@ -21,25 +15,29 @@ from semantic_kernel.skill_definition.read_only_skill_collection_base import (
|
||||
ReadOnlySkillCollectionBase,
|
||||
)
|
||||
from semantic_kernel.skill_definition.skill_collection_base import SkillCollectionBase
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from semantic_kernel.orchestration.sk_function_base import SKFunctionBase
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SkillCollection(SkillCollectionBase):
|
||||
GLOBAL_SKILL: ClassVar[str] = constants.GLOBAL_SKILL
|
||||
read_only_skill_collection_: ReadOnlySkillCollection = Field(
|
||||
alias="read_only_skill_collection"
|
||||
)
|
||||
_log: Logger = PrivateAttr()
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
skill_collection: Union[Dict[str, Dict[str, SKFunction]], None] = None,
|
||||
read_only_skill_collection_: Optional[ReadOnlySkillCollection] = None,
|
||||
) -> None:
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
if skill_collection and read_only_skill_collection_:
|
||||
raise ValueError(
|
||||
"Only one of `skill_collection` and `read_only_skill_collection` can be"
|
||||
@@ -52,7 +50,6 @@ class SkillCollection(SkillCollectionBase):
|
||||
else:
|
||||
read_only_skill_collection = read_only_skill_collection_
|
||||
super().__init__(read_only_skill_collection=read_only_skill_collection)
|
||||
self._log = log or NullLogger()
|
||||
|
||||
@property
|
||||
def read_only_skill_collection(self) -> ReadOnlySkillCollectionBase:
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
from typing import Optional, Tuple
|
||||
|
||||
from pydantic import PrivateAttr
|
||||
import logging
|
||||
from typing import Any, Optional, Tuple
|
||||
|
||||
from semantic_kernel.sk_pydantic import SKBaseModel
|
||||
from semantic_kernel.template_engine.blocks.block_types import BlockTypes
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Block(SKBaseModel):
|
||||
content: Optional[str] = None
|
||||
_log: Optional[Logger] = PrivateAttr(default_factory=NullLogger)
|
||||
|
||||
def __init__(
|
||||
self, content: Optional[str] = None, log: Optional[Logger] = None
|
||||
self, content: Optional[str] = None, log: Optional[Any] = None
|
||||
) -> None:
|
||||
super().__init__(content=content)
|
||||
self._log = log or NullLogger()
|
||||
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
|
||||
def is_valid(self) -> Tuple[bool, str]:
|
||||
raise NotImplementedError("Subclasses must implement this method.")
|
||||
@@ -26,7 +28,3 @@ class Block(SKBaseModel):
|
||||
@property
|
||||
def type(self) -> BlockTypes:
|
||||
return BlockTypes.UNDEFINED
|
||||
|
||||
@property
|
||||
def log(self) -> Logger:
|
||||
return self._log
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
from typing import List, Optional, Tuple
|
||||
import logging
|
||||
from typing import Any, List, Optional, Tuple
|
||||
|
||||
import pydantic as pdt
|
||||
|
||||
@@ -14,6 +14,8 @@ from semantic_kernel.template_engine.blocks.block_types import BlockTypes
|
||||
from semantic_kernel.template_engine.blocks.function_id_block import FunctionIdBlock
|
||||
from semantic_kernel.template_engine.code_tokenizer import CodeTokenizer
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CodeBlock(Block):
|
||||
_tokens: List[Block] = pdt.PrivateAttr()
|
||||
@@ -23,11 +25,16 @@ class CodeBlock(Block):
|
||||
self,
|
||||
content: str,
|
||||
tokens: Optional[List[Block]] = None,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
):
|
||||
super().__init__(content=content and content.strip(), log=log)
|
||||
super().__init__(content=content and content.strip())
|
||||
|
||||
self._tokens = tokens or CodeTokenizer(log=self.log).tokenize(content)
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
|
||||
self._tokens = tokens or CodeTokenizer().tokenize(content)
|
||||
self._validated = False
|
||||
|
||||
@property
|
||||
@@ -40,13 +47,13 @@ class CodeBlock(Block):
|
||||
for token in self._tokens:
|
||||
is_valid, error_msg = token.is_valid()
|
||||
if not is_valid:
|
||||
self.log.error(error_msg)
|
||||
logger.error(error_msg)
|
||||
return False, error_msg
|
||||
|
||||
if len(self._tokens) > 1:
|
||||
if self._tokens[0].type != BlockTypes.FUNCTION_ID:
|
||||
error_msg = f"Unexpected second token found: {self._tokens[1].content}"
|
||||
self.log.error(error_msg)
|
||||
logger.error(error_msg)
|
||||
return False, error_msg
|
||||
|
||||
if (
|
||||
@@ -54,12 +61,12 @@ class CodeBlock(Block):
|
||||
and self._tokens[1].type != BlockTypes.VARIABLE
|
||||
):
|
||||
error_msg = "Functions support only one parameter"
|
||||
self.log.error(error_msg)
|
||||
logger.error(error_msg)
|
||||
return False, error_msg
|
||||
|
||||
if len(self._tokens) > 2:
|
||||
error_msg = f"Unexpected second token found: {self._tokens[1].content}"
|
||||
self.log.error(error_msg)
|
||||
logger.error(error_msg)
|
||||
return False, error_msg
|
||||
|
||||
self._validated = True
|
||||
@@ -72,7 +79,7 @@ class CodeBlock(Block):
|
||||
if not is_valid:
|
||||
raise ValueError(error)
|
||||
|
||||
self.log.debug(f"Rendering code: `{self.content}`")
|
||||
logger.debug(f"Rendering code: `{self.content}`")
|
||||
|
||||
if self._tokens[0].type in (BlockTypes.VALUE, BlockTypes.VARIABLE):
|
||||
return self._tokens[0].render(context.variables)
|
||||
@@ -90,18 +97,18 @@ class CodeBlock(Block):
|
||||
|
||||
if not function:
|
||||
error_msg = f"Function `{f_block.content}` not found"
|
||||
self.log.error(error_msg)
|
||||
logger.error(error_msg)
|
||||
raise ValueError(error_msg)
|
||||
|
||||
variables_clone = context.variables.clone()
|
||||
|
||||
if len(self._tokens) > 1:
|
||||
self.log.debug(f"Passing variable/value: `{self._tokens[1].content}`")
|
||||
logger.debug(f"Passing variable/value: `{self._tokens[1].content}`")
|
||||
input_value = self._tokens[1].render(variables_clone)
|
||||
variables_clone.update(input_value)
|
||||
|
||||
result = await function.invoke_async(
|
||||
variables=variables_clone, memory=context.memory, log=self.log
|
||||
variables=variables_clone, memory=context.memory
|
||||
)
|
||||
|
||||
if result.error_occurred:
|
||||
@@ -110,7 +117,7 @@ class CodeBlock(Block):
|
||||
f"{result.last_exception.__class__.__name__}: "
|
||||
f"{result.last_error_description}"
|
||||
)
|
||||
self.log.error(error_msg)
|
||||
logger.error(error_msg)
|
||||
raise ValueError(error_msg)
|
||||
|
||||
return result.result
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
import logging
|
||||
from re import match as re_match
|
||||
from typing import Optional, Tuple
|
||||
from typing import Any, Optional, Tuple
|
||||
|
||||
import pydantic as pdt
|
||||
|
||||
@@ -10,17 +10,24 @@ from semantic_kernel.orchestration.context_variables import ContextVariables
|
||||
from semantic_kernel.template_engine.blocks.block import Block
|
||||
from semantic_kernel.template_engine.blocks.block_types import BlockTypes
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FunctionIdBlock(Block):
|
||||
_skill_name: str = pdt.PrivateAttr()
|
||||
_function_name: str = pdt.PrivateAttr()
|
||||
|
||||
def __init__(self, content: Optional[str] = None, log: Optional[Logger] = None):
|
||||
super().__init__(content=content and content.strip(), log=log)
|
||||
def __init__(self, content: Optional[str] = None, log: Optional[Any] = None):
|
||||
super().__init__(content=content and content.strip())
|
||||
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
|
||||
function_name_parts = self.content.split(".")
|
||||
if len(function_name_parts) > 2:
|
||||
self.log.error(f"Invalid function name `{self.content}`")
|
||||
logger.error(f"Invalid function name `{self.content}`")
|
||||
raise ValueError(
|
||||
"A function name can contain at most one dot separating "
|
||||
"the skill name from the function name"
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
from typing import Optional, Tuple
|
||||
import logging
|
||||
from typing import Any, Optional, Tuple
|
||||
|
||||
from semantic_kernel.orchestration.context_variables import ContextVariables
|
||||
from semantic_kernel.template_engine.blocks.block import Block
|
||||
from semantic_kernel.template_engine.blocks.block_types import BlockTypes
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TextBlock(Block):
|
||||
@classmethod
|
||||
@@ -15,10 +17,14 @@ class TextBlock(Block):
|
||||
text: Optional[str] = None,
|
||||
start_index: Optional[int] = None,
|
||||
stop_index: Optional[int] = None,
|
||||
log: Optional[Logger] = None,
|
||||
log: Optional[Any] = None,
|
||||
):
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
if text is None:
|
||||
return cls(content="", log=log)
|
||||
return cls(content="")
|
||||
if start_index is not None and stop_index is not None:
|
||||
if start_index > stop_index:
|
||||
raise ValueError(
|
||||
@@ -35,7 +41,7 @@ class TextBlock(Block):
|
||||
elif stop_index is not None:
|
||||
text = text[:stop_index]
|
||||
|
||||
return cls(content=text, log=log)
|
||||
return cls(content=text)
|
||||
|
||||
@property
|
||||
def type(self) -> BlockTypes:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
from typing import Optional, Tuple
|
||||
import logging
|
||||
from typing import Any, Optional, Tuple
|
||||
|
||||
import pydantic as pdt
|
||||
|
||||
@@ -10,18 +10,25 @@ from semantic_kernel.template_engine.blocks.block import Block
|
||||
from semantic_kernel.template_engine.blocks.block_types import BlockTypes
|
||||
from semantic_kernel.template_engine.blocks.symbols import Symbols
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ValBlock(Block):
|
||||
_first: str = pdt.PrivateAttr()
|
||||
_last: str = pdt.PrivateAttr()
|
||||
_value: str = pdt.PrivateAttr()
|
||||
|
||||
def __init__(self, content: Optional[str] = None, log: Optional[Logger] = None):
|
||||
super().__init__(content=content and content.strip(), log=log)
|
||||
def __init__(self, content: Optional[str] = None, log: Optional[Any] = None):
|
||||
super().__init__(content=content and content.strip())
|
||||
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
|
||||
if len(self.content) < 2:
|
||||
err = "A value must have single quotes or double quotes on both sides"
|
||||
self.log.error(err)
|
||||
logger.error(err)
|
||||
self._value = ""
|
||||
self._first = "\0"
|
||||
self._last = "\0"
|
||||
@@ -38,14 +45,14 @@ class ValBlock(Block):
|
||||
def is_valid(self) -> Tuple[bool, str]:
|
||||
if len(self.content) < 2:
|
||||
error_msg = "A value must have single quotes or double quotes on both sides"
|
||||
self.log.error(error_msg)
|
||||
logger.error(error_msg)
|
||||
return False, error_msg
|
||||
|
||||
if self._first != Symbols.DBL_QUOTE and self._first != Symbols.SGL_QUOTE:
|
||||
error_msg = (
|
||||
"A value must be wrapped in either single quotes or double quotes"
|
||||
)
|
||||
self.log.error(error_msg)
|
||||
logger.error(error_msg)
|
||||
return False, error_msg
|
||||
|
||||
if self._first != self._last:
|
||||
@@ -53,7 +60,7 @@ class ValBlock(Block):
|
||||
"A value must be defined using either single quotes or "
|
||||
"double quotes, not both"
|
||||
)
|
||||
self.log.error(error_msg)
|
||||
logger.error(error_msg)
|
||||
return False, error_msg
|
||||
|
||||
return True, ""
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
import logging
|
||||
from re import match as re_match
|
||||
from typing import Optional, Tuple
|
||||
from typing import Any, Optional, Tuple
|
||||
|
||||
import pydantic as pdt
|
||||
|
||||
@@ -11,16 +11,23 @@ from semantic_kernel.template_engine.blocks.block import Block
|
||||
from semantic_kernel.template_engine.blocks.block_types import BlockTypes
|
||||
from semantic_kernel.template_engine.blocks.symbols import Symbols
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class VarBlock(Block):
|
||||
_name: str = pdt.PrivateAttr()
|
||||
|
||||
def __init__(self, content: Optional[str] = None, log: Optional[Logger] = None):
|
||||
super().__init__(content=content and content.strip(), log=log)
|
||||
def __init__(self, content: Optional[str] = None, log: Optional[Any] = None):
|
||||
super().__init__(content=content and content.strip())
|
||||
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
|
||||
if len(self.content) < 2:
|
||||
err = "The variable name is empty"
|
||||
self.log.error(err)
|
||||
logger.error(err)
|
||||
self._name = ""
|
||||
return
|
||||
|
||||
@@ -44,17 +51,17 @@ class VarBlock(Block):
|
||||
f"A variable must start with the symbol {Symbols.VAR_PREFIX} "
|
||||
"and have a name"
|
||||
)
|
||||
self.log.error(error_msg)
|
||||
logger.error(error_msg)
|
||||
return False, error_msg
|
||||
|
||||
if self.content[0] != Symbols.VAR_PREFIX:
|
||||
error_msg = f"A variable must start with the symbol {Symbols.VAR_PREFIX}"
|
||||
self.log.error(error_msg)
|
||||
logger.error(error_msg)
|
||||
return False, error_msg
|
||||
|
||||
if len(self.content) < 2:
|
||||
error_msg = "The variable name is empty"
|
||||
self.log.error(error_msg)
|
||||
logger.error(error_msg)
|
||||
return False, error_msg
|
||||
|
||||
if not re_match(r"^[a-zA-Z0-9_]*$", self.name):
|
||||
@@ -62,7 +69,7 @@ class VarBlock(Block):
|
||||
f"The variable name '{self.name}' contains invalid characters. "
|
||||
"Only alphanumeric chars and underscore are allowed."
|
||||
)
|
||||
self.log.error(error_msg)
|
||||
logger.error(error_msg)
|
||||
return False, error_msg
|
||||
|
||||
return True, ""
|
||||
@@ -73,11 +80,11 @@ class VarBlock(Block):
|
||||
|
||||
if not self.name:
|
||||
error_msg = "Variable rendering failed, the variable name is empty"
|
||||
self.log.error(error_msg)
|
||||
logger.error(error_msg)
|
||||
raise ValueError(error_msg)
|
||||
|
||||
value = variables.get(self.name, None)
|
||||
if not value:
|
||||
self.log.warning(f"Variable `{Symbols.VAR_PREFIX}{self.name}` not found")
|
||||
logger.warning(f"Variable `{Symbols.VAR_PREFIX}{self.name}` not found")
|
||||
|
||||
return value or ""
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
from typing import List, Optional
|
||||
|
||||
from pydantic import PrivateAttr
|
||||
import logging
|
||||
from typing import Any, List, Optional
|
||||
|
||||
from semantic_kernel.sk_pydantic import SKBaseModel
|
||||
from semantic_kernel.template_engine.blocks.block import Block
|
||||
@@ -12,7 +10,8 @@ from semantic_kernel.template_engine.blocks.function_id_block import FunctionIdB
|
||||
from semantic_kernel.template_engine.blocks.symbols import Symbols
|
||||
from semantic_kernel.template_engine.blocks.val_block import ValBlock
|
||||
from semantic_kernel.template_engine.blocks.var_block import VarBlock
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# BNF parsed by CodeTokenizer:
|
||||
@@ -24,15 +23,13 @@ from semantic_kernel.utils.null_logger import NullLogger
|
||||
# [function-call] ::= [function-id] | [function-id] [parameter]
|
||||
# [parameter] ::= [variable] | [value]
|
||||
class CodeTokenizer(SKBaseModel):
|
||||
_log: Optional[Logger] = PrivateAttr(default_factory=NullLogger)
|
||||
|
||||
def __init__(self, log: Logger = None):
|
||||
def __init__(self, log: Optional[Any] = None):
|
||||
super().__init__()
|
||||
self._log = log or NullLogger()
|
||||
|
||||
@property
|
||||
def log(self) -> Logger:
|
||||
return self._log
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
|
||||
def tokenize(self, text: str) -> List[Block]:
|
||||
# Remove spaces, which are ignored anyway
|
||||
@@ -58,11 +55,11 @@ class CodeTokenizer(SKBaseModel):
|
||||
# 1 char only edge case
|
||||
if len(text) == 1:
|
||||
if next_char == Symbols.VAR_PREFIX:
|
||||
blocks.append(VarBlock(text, self.log))
|
||||
blocks.append(VarBlock(text))
|
||||
elif next_char in (Symbols.DBL_QUOTE, Symbols.SGL_QUOTE):
|
||||
blocks.append(ValBlock(text, self.log))
|
||||
blocks.append(ValBlock(text))
|
||||
else:
|
||||
blocks.append(FunctionIdBlock(text, self.log))
|
||||
blocks.append(FunctionIdBlock(text))
|
||||
|
||||
return blocks
|
||||
|
||||
@@ -104,7 +101,7 @@ class CodeTokenizer(SKBaseModel):
|
||||
|
||||
# When we reach the end of the value, we add the block
|
||||
if current_char == text_value_delimiter:
|
||||
blocks.append(ValBlock("".join(current_token_content), self.log))
|
||||
blocks.append(ValBlock("".join(current_token_content)))
|
||||
current_token_content.clear()
|
||||
current_token_type = None
|
||||
space_separator_found = False
|
||||
@@ -115,12 +112,10 @@ class CodeTokenizer(SKBaseModel):
|
||||
# Note: there might be multiple consecutive spaces
|
||||
if self._is_blank_space(current_char):
|
||||
if current_token_type == BlockTypes.VARIABLE:
|
||||
blocks.append(VarBlock("".join(current_token_content), self.log))
|
||||
blocks.append(VarBlock("".join(current_token_content)))
|
||||
current_token_content.clear()
|
||||
elif current_token_type == BlockTypes.FUNCTION_ID:
|
||||
blocks.append(
|
||||
FunctionIdBlock("".join(current_token_content), self.log)
|
||||
)
|
||||
blocks.append(FunctionIdBlock("".join(current_token_content)))
|
||||
current_token_content.clear()
|
||||
|
||||
space_separator_found = True
|
||||
@@ -150,11 +145,11 @@ class CodeTokenizer(SKBaseModel):
|
||||
current_token_content.append(next_char)
|
||||
|
||||
if current_token_type == BlockTypes.VALUE:
|
||||
blocks.append(ValBlock("".join(current_token_content), self.log))
|
||||
blocks.append(ValBlock("".join(current_token_content)))
|
||||
elif current_token_type == BlockTypes.VARIABLE:
|
||||
blocks.append(VarBlock("".join(current_token_content), self.log))
|
||||
blocks.append(VarBlock("".join(current_token_content)))
|
||||
elif current_token_type == BlockTypes.FUNCTION_ID:
|
||||
blocks.append(FunctionIdBlock("".join(current_token_content), self.log))
|
||||
blocks.append(FunctionIdBlock("".join(current_token_content)))
|
||||
else:
|
||||
raise ValueError("Tokens must be separated by one space least")
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from pydantic import PrivateAttr
|
||||
@@ -11,24 +11,24 @@ from semantic_kernel.template_engine.blocks.block import Block
|
||||
from semantic_kernel.template_engine.blocks.block_types import BlockTypes
|
||||
from semantic_kernel.template_engine.protocols.text_renderer import TextRenderer
|
||||
from semantic_kernel.template_engine.template_tokenizer import TemplateTokenizer
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from semantic_kernel.orchestration.sk_context import SKContext
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PromptTemplateEngine(SKBaseModel):
|
||||
_log: Optional[Logger] = PrivateAttr(default_factory=NullLogger)
|
||||
_tokenizer: TemplateTokenizer = PrivateAttr()
|
||||
|
||||
def __init__(self, logger: Optional[Logger] = None) -> None:
|
||||
def __init__(self, **kwargs) -> None:
|
||||
super().__init__()
|
||||
self._log = logger or NullLogger()
|
||||
self._tokenizer = TemplateTokenizer(log=self.log)
|
||||
|
||||
@property
|
||||
def log(self) -> Logger:
|
||||
return self._log
|
||||
if kwargs.get("logger"):
|
||||
logger.warning(
|
||||
"The `logger` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
self._tokenizer = TemplateTokenizer()
|
||||
|
||||
def extract_blocks(
|
||||
self, template_text: Optional[str] = None, validate: bool = True
|
||||
@@ -43,7 +43,7 @@ class PromptTemplateEngine(SKBaseModel):
|
||||
:return: A list of all the blocks, ie the template tokenized in
|
||||
text, variables and function calls
|
||||
"""
|
||||
self.log.debug(f"Extracting blocks from template: {template_text}")
|
||||
logger.debug(f"Extracting blocks from template: {template_text}")
|
||||
blocks = self._tokenizer.tokenize(template_text)
|
||||
|
||||
if validate:
|
||||
@@ -64,7 +64,7 @@ class PromptTemplateEngine(SKBaseModel):
|
||||
:param context: Access into the current kernel execution context
|
||||
:return: The prompt template ready to be used for an AI request
|
||||
"""
|
||||
self.log.debug(f"Rendering string template: {template_text}")
|
||||
logger.debug(f"Rendering string template: {template_text}")
|
||||
blocks = self.extract_blocks(template_text)
|
||||
return await self.render_blocks_async(blocks, context)
|
||||
|
||||
@@ -80,7 +80,7 @@ class PromptTemplateEngine(SKBaseModel):
|
||||
"""
|
||||
from semantic_kernel.template_engine.protocols.code_renderer import CodeRenderer
|
||||
|
||||
self.log.debug(f"Rendering list of {len(blocks)} blocks")
|
||||
logger.debug(f"Rendering list of {len(blocks)} blocks")
|
||||
rendered_blocks = []
|
||||
for block in blocks:
|
||||
if isinstance(block, TextRenderer):
|
||||
@@ -92,10 +92,10 @@ class PromptTemplateEngine(SKBaseModel):
|
||||
"unexpected block type, the block doesn't have a rendering "
|
||||
"protocol assigned to it"
|
||||
)
|
||||
self.log.error(error)
|
||||
logger.error(error)
|
||||
raise ValueError(error)
|
||||
|
||||
self.log.debug(f"Rendered prompt: {''.join(rendered_blocks)}")
|
||||
logger.debug(f"Rendered prompt: {''.join(rendered_blocks)}")
|
||||
return "".join(rendered_blocks)
|
||||
|
||||
def render_variables(
|
||||
@@ -112,7 +112,7 @@ class PromptTemplateEngine(SKBaseModel):
|
||||
"""
|
||||
from semantic_kernel.template_engine.blocks.text_block import TextBlock
|
||||
|
||||
self.log.debug("Rendering variables")
|
||||
logger.debug("Rendering variables")
|
||||
|
||||
rendered_blocks = []
|
||||
for block in blocks:
|
||||
@@ -121,9 +121,7 @@ class PromptTemplateEngine(SKBaseModel):
|
||||
continue
|
||||
if not isinstance(block, TextRenderer):
|
||||
raise ValueError("TextBlock must implement TextRenderer protocol")
|
||||
rendered_blocks.append(
|
||||
TextBlock.from_text(block.render(variables), log=self.log)
|
||||
)
|
||||
rendered_blocks.append(TextBlock.from_text(block.render(variables)))
|
||||
|
||||
return rendered_blocks
|
||||
|
||||
@@ -142,7 +140,7 @@ class PromptTemplateEngine(SKBaseModel):
|
||||
from semantic_kernel.template_engine.blocks.text_block import TextBlock
|
||||
from semantic_kernel.template_engine.protocols.code_renderer import CodeRenderer
|
||||
|
||||
self.log.debug("Rendering code")
|
||||
logger.debug("Rendering code")
|
||||
|
||||
rendered_blocks = []
|
||||
for block in blocks:
|
||||
@@ -152,9 +150,7 @@ class PromptTemplateEngine(SKBaseModel):
|
||||
if not isinstance(block, CodeRenderer):
|
||||
raise ValueError("CodeBlock must implement CodeRenderer protocol")
|
||||
rendered_blocks.append(
|
||||
TextBlock.from_text(
|
||||
await block.render_code_async(execution_context), log=self.log
|
||||
)
|
||||
TextBlock.from_text(await block.render_code_async(execution_context))
|
||||
)
|
||||
|
||||
return rendered_blocks
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
from typing import List, Optional
|
||||
import logging
|
||||
from typing import Any, List, Optional
|
||||
|
||||
from pydantic import PrivateAttr
|
||||
|
||||
@@ -12,7 +12,8 @@ from semantic_kernel.template_engine.blocks.code_block import CodeBlock
|
||||
from semantic_kernel.template_engine.blocks.symbols import Symbols
|
||||
from semantic_kernel.template_engine.blocks.text_block import TextBlock
|
||||
from semantic_kernel.template_engine.code_tokenizer import CodeTokenizer
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# BNF parsed by TemplateTokenizer:
|
||||
@@ -24,17 +25,15 @@ from semantic_kernel.utils.null_logger import NullLogger
|
||||
# [text-block] ::= [any-char] | [any-char] [text-block]
|
||||
# [any-char] ::= any char
|
||||
class TemplateTokenizer(SKBaseModel):
|
||||
_log: Optional[Logger] = PrivateAttr(default_factory=NullLogger)
|
||||
_code_tokenizer: CodeTokenizer = PrivateAttr()
|
||||
|
||||
def __init__(self, log: Logger = None):
|
||||
def __init__(self, log: Optional[Any] = None):
|
||||
super().__init__()
|
||||
self._log = log or NullLogger()
|
||||
self._code_tokenizer = CodeTokenizer(log=self.log)
|
||||
|
||||
@property
|
||||
def log(self) -> Logger:
|
||||
return self._log
|
||||
if log:
|
||||
logger.warning(
|
||||
"The `log` parameter is deprecated. Please use the `logging` module instead."
|
||||
)
|
||||
self._code_tokenizer = CodeTokenizer()
|
||||
|
||||
def tokenize(self, text: str) -> List[Block]:
|
||||
# An empty block consists of 4 chars: "{{}}"
|
||||
@@ -47,11 +46,11 @@ class TemplateTokenizer(SKBaseModel):
|
||||
|
||||
# Render None/empty to ""
|
||||
if not text or text == "":
|
||||
return [TextBlock.from_text("", log=self.log)]
|
||||
return [TextBlock.from_text("")]
|
||||
|
||||
# If the template is "empty" return it as a text block
|
||||
if len(text) < MIN_CODE_BLOCK_LENGTH:
|
||||
return [TextBlock.from_text(text, log=self.log)]
|
||||
return [TextBlock.from_text(text)]
|
||||
|
||||
blocks = []
|
||||
end_of_last_block = 0
|
||||
@@ -114,7 +113,6 @@ class TemplateTokenizer(SKBaseModel):
|
||||
text,
|
||||
end_of_last_block,
|
||||
block_start_pos,
|
||||
log=self.log,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -130,11 +128,7 @@ class TemplateTokenizer(SKBaseModel):
|
||||
if len(content_without_delimiters) == 0:
|
||||
# If what is left is empty, consider the raw block
|
||||
# a TextBlock
|
||||
blocks.append(
|
||||
TextBlock.from_text(
|
||||
content_with_delimiters, log=self.log
|
||||
)
|
||||
)
|
||||
blocks.append(TextBlock.from_text(content_with_delimiters))
|
||||
else:
|
||||
code_blocks = self._code_tokenizer.tokenize(
|
||||
content_without_delimiters
|
||||
@@ -169,7 +163,6 @@ class TemplateTokenizer(SKBaseModel):
|
||||
CodeBlock(
|
||||
content_without_delimiters,
|
||||
code_blocks,
|
||||
self.log,
|
||||
)
|
||||
)
|
||||
else:
|
||||
@@ -183,9 +176,7 @@ class TemplateTokenizer(SKBaseModel):
|
||||
|
||||
# If there is something left after the last block, capture it as a TextBlock
|
||||
if end_of_last_block < len(text):
|
||||
blocks.append(
|
||||
TextBlock.from_text(text, end_of_last_block, len(text), log=self.log)
|
||||
)
|
||||
blocks.append(TextBlock.from_text(text, end_of_last_block, len(text)))
|
||||
|
||||
return blocks
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
def setup_logging():
|
||||
# Setup a detailed logging format.
|
||||
logging.basicConfig(
|
||||
format="[%(asctime)s - %(name)s:%(lineno)d - %(levelname)s] %(message)s",
|
||||
datefmt="%Y-%m-%d %H:%M:%S",
|
||||
)
|
||||
@@ -1,9 +1,11 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from functools import wraps
|
||||
from logging import Logger
|
||||
from logging import Logger, getLogger
|
||||
from typing import Any, Callable
|
||||
|
||||
logger: Logger = getLogger(__name__)
|
||||
|
||||
|
||||
def _nullify(fn) -> Callable[[Any], None]:
|
||||
"""General wrapper to not call wrapped function"""
|
||||
@@ -35,6 +37,12 @@ class NullLogger(Logger, metaclass=_NullerMeta):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(None)
|
||||
logger.warning(
|
||||
(
|
||||
"NullLogger is deprecated and will be removed in a future release,",
|
||||
"the same goes for all 'log' and 'logger' arguments.",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
__all__ = ["NullLogger"]
|
||||
|
||||
@@ -30,7 +30,6 @@ def test_azure_chat_completion_init() -> None:
|
||||
endpoint = "https://test-endpoint.com"
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
# Test successful initialization
|
||||
azure_chat_completion = AzureChatCompletion(
|
||||
@@ -38,7 +37,6 @@ def test_azure_chat_completion_init() -> None:
|
||||
endpoint=endpoint,
|
||||
api_key=api_key,
|
||||
api_version=api_version,
|
||||
log=logger,
|
||||
)
|
||||
|
||||
assert azure_chat_completion.client is not None
|
||||
@@ -52,7 +50,6 @@ def test_azure_chat_completion_init_base_url() -> None:
|
||||
base_url = "https://test-endpoint.com/openai/deployment/test_deployment"
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
# Custom header for testing
|
||||
default_headers = {"X-Unit-Test": "test-guid"}
|
||||
@@ -62,7 +59,6 @@ def test_azure_chat_completion_init_base_url() -> None:
|
||||
base_url=base_url,
|
||||
api_key=api_key,
|
||||
api_version=api_version,
|
||||
log=logger,
|
||||
default_headers=default_headers,
|
||||
)
|
||||
|
||||
@@ -80,7 +76,6 @@ def test_azure_chat_completion_init_with_empty_deployment_name() -> None:
|
||||
endpoint = "https://test-endpoint.com"
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
with pytest.raises(ValidationError, match="ai_model_id"):
|
||||
AzureChatCompletion(
|
||||
@@ -88,7 +83,6 @@ def test_azure_chat_completion_init_with_empty_deployment_name() -> None:
|
||||
endpoint=endpoint,
|
||||
api_key=api_key,
|
||||
api_version=api_version,
|
||||
log=logger,
|
||||
)
|
||||
|
||||
|
||||
@@ -97,7 +91,6 @@ def test_azure_chat_completion_init_with_empty_api_key() -> None:
|
||||
endpoint = "https://test-endpoint.com"
|
||||
# api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
with pytest.raises(AIException, match="api_key"):
|
||||
AzureChatCompletion(
|
||||
@@ -105,7 +98,6 @@ def test_azure_chat_completion_init_with_empty_api_key() -> None:
|
||||
endpoint=endpoint,
|
||||
api_key="",
|
||||
api_version=api_version,
|
||||
log=logger,
|
||||
)
|
||||
|
||||
|
||||
@@ -114,7 +106,6 @@ def test_azure_chat_completion_init_with_empty_endpoint() -> None:
|
||||
# endpoint = "https://test-endpoint.com"
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
with pytest.raises(ValidationError, match="url"):
|
||||
AzureChatCompletion(
|
||||
@@ -122,7 +113,6 @@ def test_azure_chat_completion_init_with_empty_endpoint() -> None:
|
||||
endpoint="",
|
||||
api_key=api_key,
|
||||
api_version=api_version,
|
||||
log=logger,
|
||||
)
|
||||
|
||||
|
||||
@@ -131,7 +121,6 @@ def test_azure_chat_completion_init_with_invalid_endpoint() -> None:
|
||||
endpoint = "http://test-endpoint.com"
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
with pytest.raises(ValidationError, match="url"):
|
||||
AzureChatCompletion(
|
||||
@@ -139,7 +128,6 @@ def test_azure_chat_completion_init_with_invalid_endpoint() -> None:
|
||||
endpoint=endpoint,
|
||||
api_key=api_key,
|
||||
api_version=api_version,
|
||||
log=logger,
|
||||
)
|
||||
|
||||
|
||||
@@ -148,7 +136,6 @@ def test_azure_chat_completion_init_with_base_url() -> None:
|
||||
base_url = "http://test-endpoint.com/openai/deployment/test_deployment"
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
with pytest.raises(ValidationError, match="url"):
|
||||
AzureChatCompletion(
|
||||
@@ -156,7 +143,6 @@ def test_azure_chat_completion_init_with_base_url() -> None:
|
||||
base_url=base_url,
|
||||
api_key=api_key,
|
||||
api_version=api_version,
|
||||
log=logger,
|
||||
)
|
||||
|
||||
|
||||
@@ -167,7 +153,7 @@ async def test_azure_chat_completion_call_with_parameters(mock_create) -> None:
|
||||
endpoint = "https://test-endpoint.com"
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
prompt = "hello world"
|
||||
messages_in = [{"role": "user", "content": prompt}]
|
||||
messages_out = [{"role": "user", "content": prompt}]
|
||||
@@ -178,7 +164,6 @@ async def test_azure_chat_completion_call_with_parameters(mock_create) -> None:
|
||||
endpoint=endpoint,
|
||||
api_version=api_version,
|
||||
api_key=api_key,
|
||||
log=logger,
|
||||
)
|
||||
await azure_chat_completion.complete_chat_async(
|
||||
messages=messages_in, settings=complete_request_settings
|
||||
@@ -207,7 +192,7 @@ async def test_azure_chat_completion_call_with_parameters_and_Logit_Bias_Defined
|
||||
endpoint = "https://test-endpoint.com"
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
prompt = "hello world"
|
||||
messages = [{"role": "user", "content": prompt}]
|
||||
complete_request_settings = ChatRequestSettings()
|
||||
@@ -220,7 +205,6 @@ async def test_azure_chat_completion_call_with_parameters_and_Logit_Bias_Defined
|
||||
endpoint=endpoint,
|
||||
api_key=api_key,
|
||||
api_version=api_version,
|
||||
log=logger,
|
||||
)
|
||||
|
||||
await azure_chat_completion.complete_chat_async(
|
||||
@@ -251,7 +235,7 @@ async def test_azure_chat_completion_call_with_parameters_and_Stop_Defined(
|
||||
endpoint = "https://test-endpoint.com"
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
prompt = "hello world"
|
||||
messages = [{"role": "user", "content": prompt}]
|
||||
complete_request_settings = ChatRequestSettings()
|
||||
@@ -264,7 +248,6 @@ async def test_azure_chat_completion_call_with_parameters_and_Stop_Defined(
|
||||
endpoint=endpoint,
|
||||
api_key=api_key,
|
||||
api_version=api_version,
|
||||
log=logger,
|
||||
)
|
||||
|
||||
await azure_chat_completion.complete_async(prompt, complete_request_settings)
|
||||
@@ -290,14 +273,12 @@ def test_azure_chat_completion_serialize() -> None:
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
default_headers = {"X-Test": "test"}
|
||||
logger = Logger("test_logger")
|
||||
|
||||
settings = {
|
||||
"deployment_name": deployment_name,
|
||||
"endpoint": endpoint,
|
||||
"api_key": api_key,
|
||||
"api_version": api_version,
|
||||
"log": logger,
|
||||
"default_headers": default_headers,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
import pytest
|
||||
@@ -23,7 +22,6 @@ def test_azure_text_completion_init() -> None:
|
||||
endpoint = "https://test-endpoint.com"
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
# Test successful initialization
|
||||
azure_text_completion = AzureTextCompletion(
|
||||
@@ -31,7 +29,6 @@ def test_azure_text_completion_init() -> None:
|
||||
endpoint=endpoint,
|
||||
api_key=api_key,
|
||||
api_version=api_version,
|
||||
log=logger,
|
||||
)
|
||||
|
||||
assert azure_text_completion.client is not None
|
||||
@@ -45,7 +42,6 @@ def test_azure_text_completion_init_with_custom_header() -> None:
|
||||
endpoint = "https://test-endpoint.com"
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
# Custom header for testing
|
||||
default_headers = {"X-Unit-Test": "test-guid"}
|
||||
@@ -56,7 +52,6 @@ def test_azure_text_completion_init_with_custom_header() -> None:
|
||||
endpoint=endpoint,
|
||||
api_key=api_key,
|
||||
api_version=api_version,
|
||||
log=logger,
|
||||
default_headers=default_headers,
|
||||
)
|
||||
|
||||
@@ -74,7 +69,6 @@ def test_azure_text_completion_init_with_empty_deployment_name() -> None:
|
||||
endpoint = "https://test-endpoint.com"
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
with pytest.raises(ValidationError, match="ai_model_id"):
|
||||
AzureTextCompletion(
|
||||
@@ -82,7 +76,6 @@ def test_azure_text_completion_init_with_empty_deployment_name() -> None:
|
||||
endpoint=endpoint,
|
||||
api_key=api_key,
|
||||
api_version=api_version,
|
||||
log=logger,
|
||||
)
|
||||
|
||||
|
||||
@@ -91,7 +84,6 @@ def test_azure_text_completion_init_with_empty_api_key() -> None:
|
||||
endpoint = "https://test-endpoint.com"
|
||||
# api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
with pytest.raises(AIException, match="api_key"):
|
||||
AzureTextCompletion(
|
||||
@@ -99,7 +91,6 @@ def test_azure_text_completion_init_with_empty_api_key() -> None:
|
||||
endpoint=endpoint,
|
||||
api_key="",
|
||||
api_version=api_version,
|
||||
log=logger,
|
||||
)
|
||||
|
||||
|
||||
@@ -108,7 +99,6 @@ def test_azure_text_completion_init_with_empty_endpoint() -> None:
|
||||
# endpoint = "https://test-endpoint.com"
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
with pytest.raises(ValidationError, match="endpoint"):
|
||||
AzureTextCompletion(
|
||||
@@ -116,7 +106,6 @@ def test_azure_text_completion_init_with_empty_endpoint() -> None:
|
||||
endpoint="",
|
||||
api_key=api_key,
|
||||
api_version=api_version,
|
||||
log=logger,
|
||||
)
|
||||
|
||||
|
||||
@@ -125,7 +114,6 @@ def test_azure_text_completion_init_with_invalid_endpoint() -> None:
|
||||
endpoint = "http://test-endpoint.com"
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
with pytest.raises(ValidationError, match="https"):
|
||||
AzureTextCompletion(
|
||||
@@ -133,7 +121,6 @@ def test_azure_text_completion_init_with_invalid_endpoint() -> None:
|
||||
endpoint=endpoint,
|
||||
api_key=api_key,
|
||||
api_version=api_version,
|
||||
log=logger,
|
||||
)
|
||||
|
||||
|
||||
@@ -144,7 +131,7 @@ async def test_azure_text_completion_call_with_parameters(mock_create) -> None:
|
||||
endpoint = "https://test-endpoint.com"
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
prompt = "hello world"
|
||||
complete_request_settings = CompleteRequestSettings()
|
||||
azure_text_completion = AzureTextCompletion(
|
||||
@@ -152,7 +139,6 @@ async def test_azure_text_completion_call_with_parameters(mock_create) -> None:
|
||||
endpoint=endpoint,
|
||||
api_key=api_key,
|
||||
api_version=api_version,
|
||||
log=logger,
|
||||
)
|
||||
|
||||
await azure_text_completion.complete_async(prompt, complete_request_settings)
|
||||
@@ -182,7 +168,7 @@ async def test_azure_text_completion_call_with_parameters_logit_bias_not_none(
|
||||
endpoint = "https://test-endpoint.com"
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
prompt = "hello world"
|
||||
complete_request_settings = CompleteRequestSettings()
|
||||
|
||||
@@ -194,7 +180,6 @@ async def test_azure_text_completion_call_with_parameters_logit_bias_not_none(
|
||||
endpoint=endpoint,
|
||||
api_key=api_key,
|
||||
api_version=api_version,
|
||||
log=logger,
|
||||
)
|
||||
|
||||
await azure_text_completion.complete_async(prompt, complete_request_settings)
|
||||
@@ -221,14 +206,12 @@ def test_azure_text_completion_serialize() -> None:
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
default_headers = {"X-Test": "test"}
|
||||
logger = Logger("test_logger")
|
||||
|
||||
settings = {
|
||||
"deployment_name": deployment_name,
|
||||
"endpoint": endpoint,
|
||||
"api_key": api_key,
|
||||
"api_version": api_version,
|
||||
"log": logger,
|
||||
"default_headers": default_headers,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
from unittest.mock import AsyncMock, call, patch
|
||||
|
||||
import pytest
|
||||
@@ -22,7 +21,6 @@ def test_azure_text_embedding_init() -> None:
|
||||
endpoint = "https://test-endpoint.com"
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
# Test successful initialization
|
||||
azure_text_embedding = AzureTextEmbedding(
|
||||
@@ -30,7 +28,6 @@ def test_azure_text_embedding_init() -> None:
|
||||
endpoint=endpoint,
|
||||
api_key=api_key,
|
||||
api_version=api_version,
|
||||
logger=logger,
|
||||
)
|
||||
|
||||
assert azure_text_embedding.client is not None
|
||||
@@ -44,7 +41,6 @@ def test_azure_text_embedding_init_with_empty_deployment_name() -> None:
|
||||
endpoint = "https://test-endpoint.com"
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
with pytest.raises(ValidationError, match="ai_model_id"):
|
||||
AzureTextEmbedding(
|
||||
@@ -52,7 +48,6 @@ def test_azure_text_embedding_init_with_empty_deployment_name() -> None:
|
||||
endpoint=endpoint,
|
||||
api_key=api_key,
|
||||
api_version=api_version,
|
||||
logger=logger,
|
||||
)
|
||||
|
||||
|
||||
@@ -61,7 +56,6 @@ def test_azure_text_embedding_init_with_empty_api_key() -> None:
|
||||
endpoint = "https://test-endpoint.com"
|
||||
# api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
with pytest.raises(AIException, match="api_key"):
|
||||
AzureTextEmbedding(
|
||||
@@ -69,7 +63,6 @@ def test_azure_text_embedding_init_with_empty_api_key() -> None:
|
||||
endpoint=endpoint,
|
||||
api_key="",
|
||||
api_version=api_version,
|
||||
logger=logger,
|
||||
)
|
||||
|
||||
|
||||
@@ -78,7 +71,6 @@ def test_azure_text_embedding_init_with_empty_endpoint() -> None:
|
||||
# endpoint = "https://test-endpoint.com"
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
with pytest.raises(ValidationError, match="endpoint"):
|
||||
AzureTextEmbedding(
|
||||
@@ -86,7 +78,6 @@ def test_azure_text_embedding_init_with_empty_endpoint() -> None:
|
||||
endpoint="",
|
||||
api_key=api_key,
|
||||
api_version=api_version,
|
||||
logger=logger,
|
||||
)
|
||||
|
||||
|
||||
@@ -95,7 +86,6 @@ def test_azure_text_embedding_init_with_invalid_endpoint() -> None:
|
||||
endpoint = "http://test-endpoint.com"
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
with pytest.raises(ValidationError, match="https"):
|
||||
AzureTextEmbedding(
|
||||
@@ -103,7 +93,6 @@ def test_azure_text_embedding_init_with_invalid_endpoint() -> None:
|
||||
endpoint=endpoint,
|
||||
api_key=api_key,
|
||||
api_version=api_version,
|
||||
logger=logger,
|
||||
)
|
||||
|
||||
|
||||
@@ -112,7 +101,6 @@ def test_azure_text_embedding_init_with_from_dict() -> None:
|
||||
endpoint = "https://test-endpoint.com"
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
default_headers = {"test_header": "test_value"}
|
||||
|
||||
settings = {
|
||||
@@ -120,7 +108,6 @@ def test_azure_text_embedding_init_with_from_dict() -> None:
|
||||
"endpoint": endpoint,
|
||||
"api_key": api_key,
|
||||
"api_version": api_version,
|
||||
"log": logger,
|
||||
"default_headers": default_headers,
|
||||
}
|
||||
|
||||
@@ -146,7 +133,6 @@ async def test_azure_text_embedding_calls_with_parameters(mock_create) -> None:
|
||||
endpoint = "https://test-endpoint.com"
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
texts = ["hello world", "goodbye world"]
|
||||
|
||||
azure_text_embedding = AzureTextEmbedding(
|
||||
@@ -154,7 +140,6 @@ async def test_azure_text_embedding_calls_with_parameters(mock_create) -> None:
|
||||
endpoint=endpoint,
|
||||
api_key=api_key,
|
||||
api_version=api_version,
|
||||
logger=logger,
|
||||
)
|
||||
|
||||
await azure_text_embedding.generate_embeddings_async(texts)
|
||||
@@ -172,7 +157,6 @@ async def test_azure_text_embedding_calls_with_batches(mock_create) -> None:
|
||||
endpoint = "https://test-endpoint.com"
|
||||
api_key = "test_api_key"
|
||||
api_version = "2023-03-15-preview"
|
||||
logger = Logger("test_logger")
|
||||
texts = [i for i in range(0, 5)]
|
||||
|
||||
azure_text_embedding = AzureTextEmbedding(
|
||||
@@ -180,7 +164,6 @@ async def test_azure_text_embedding_calls_with_batches(mock_create) -> None:
|
||||
endpoint=endpoint,
|
||||
api_key=api_key,
|
||||
api_version=api_version,
|
||||
log=logger,
|
||||
)
|
||||
|
||||
await azure_text_embedding.generate_embeddings_async(texts, batch_size=3)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
@@ -17,13 +16,11 @@ from semantic_kernel.connectors.ai.open_ai.services.open_ai_chat_completion impo
|
||||
def test_open_ai_chat_completion_init() -> None:
|
||||
ai_model_id = "test_model_id"
|
||||
api_key = "test_api_key"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
# Test successful initialization
|
||||
open_ai_chat_completion = OpenAIChatCompletion(
|
||||
ai_model_id=ai_model_id,
|
||||
api_key=api_key,
|
||||
log=logger,
|
||||
)
|
||||
|
||||
assert open_ai_chat_completion.ai_model_id == ai_model_id
|
||||
@@ -33,14 +30,12 @@ def test_open_ai_chat_completion_init() -> None:
|
||||
def test_open_ai_chat_completion_init_with_default_header() -> None:
|
||||
ai_model_id = "test_model_id"
|
||||
api_key = "test_api_key"
|
||||
logger = Logger("test_logger")
|
||||
default_headers = {"X-Unit-Test": "test-guid"}
|
||||
|
||||
# Test successful initialization
|
||||
open_ai_chat_completion = OpenAIChatCompletion(
|
||||
ai_model_id=ai_model_id,
|
||||
api_key=api_key,
|
||||
log=logger,
|
||||
default_headers=default_headers,
|
||||
)
|
||||
|
||||
@@ -56,39 +51,33 @@ def test_open_ai_chat_completion_init_with_default_header() -> None:
|
||||
def test_open_ai_chat_completion_init_with_empty_model_id() -> None:
|
||||
# ai_model_id = "test_model_id"
|
||||
api_key = "test_api_key"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
with pytest.raises(ValidationError, match="ai_model_id"):
|
||||
OpenAIChatCompletion(
|
||||
ai_model_id="",
|
||||
api_key=api_key,
|
||||
log=logger,
|
||||
)
|
||||
|
||||
|
||||
def test_open_ai_chat_completion_init_with_empty_api_key() -> None:
|
||||
ai_model_id = "test_model_id"
|
||||
# api_key = "test_api_key"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
with pytest.raises(ValidationError, match="api_key"):
|
||||
OpenAIChatCompletion(
|
||||
ai_model_id=ai_model_id,
|
||||
api_key="",
|
||||
log=logger,
|
||||
)
|
||||
|
||||
|
||||
def test_open_ai_chat_completion_serialize() -> None:
|
||||
ai_model_id = "test_model_id"
|
||||
api_key = "test_api_key"
|
||||
logger = Logger("test_logger")
|
||||
default_headers = {"X-Unit-Test": "test-guid"}
|
||||
|
||||
settings = {
|
||||
"ai_model_id": ai_model_id,
|
||||
"api_key": api_key,
|
||||
"log": logger,
|
||||
"default_headers": default_headers,
|
||||
}
|
||||
|
||||
@@ -108,13 +97,11 @@ def test_open_ai_chat_completion_serialize_with_org_id() -> None:
|
||||
ai_model_id = "test_model_id"
|
||||
api_key = "test_api_key"
|
||||
org_id = "test_org_id"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
settings = {
|
||||
"ai_model_id": ai_model_id,
|
||||
"api_key": api_key,
|
||||
"org_id": org_id,
|
||||
"log": logger,
|
||||
}
|
||||
|
||||
open_ai_chat_completion = OpenAIChatCompletion.from_dict(settings)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
@@ -14,13 +13,11 @@ from semantic_kernel.connectors.ai.open_ai.services.open_ai_text_completion impo
|
||||
def test_open_ai_text_completion_init() -> None:
|
||||
ai_model_id = "test_model_id"
|
||||
api_key = "test_api_key"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
# Test successful initialization
|
||||
open_ai_text_completion = OpenAITextCompletion(
|
||||
ai_model_id=ai_model_id,
|
||||
api_key=api_key,
|
||||
log=logger,
|
||||
)
|
||||
|
||||
assert open_ai_text_completion.ai_model_id == ai_model_id
|
||||
@@ -30,14 +27,12 @@ def test_open_ai_text_completion_init() -> None:
|
||||
def test_open_ai_text_completion_init_with_default_header() -> None:
|
||||
ai_model_id = "test_model_id"
|
||||
api_key = "test_api_key"
|
||||
logger = Logger("test_logger")
|
||||
default_headers = {"X-Unit-Test": "test-guid"}
|
||||
|
||||
# Test successful initialization
|
||||
open_ai_text_completion = OpenAITextCompletion(
|
||||
ai_model_id=ai_model_id,
|
||||
api_key=api_key,
|
||||
log=logger,
|
||||
default_headers=default_headers,
|
||||
)
|
||||
|
||||
@@ -51,39 +46,33 @@ def test_open_ai_text_completion_init_with_default_header() -> None:
|
||||
def test_open_ai_text_completion_init_with_empty_model_id() -> None:
|
||||
# ai_model_id = "test_model_id"
|
||||
api_key = "test_api_key"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
with pytest.raises(ValidationError, match="ai_model_id"):
|
||||
OpenAITextCompletion(
|
||||
ai_model_id="",
|
||||
api_key=api_key,
|
||||
log=logger,
|
||||
)
|
||||
|
||||
|
||||
def test_open_ai_text_completion_init_with_empty_api_key() -> None:
|
||||
ai_model_id = "test_model_id"
|
||||
# api_key = "test_api_key"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
with pytest.raises(ValidationError, match="api_key"):
|
||||
OpenAITextCompletion(
|
||||
ai_model_id=ai_model_id,
|
||||
api_key="",
|
||||
log=logger,
|
||||
)
|
||||
|
||||
|
||||
def test_open_ai_text_completion_serialize() -> None:
|
||||
ai_model_id = "test_model_id"
|
||||
api_key = "test_api_key"
|
||||
logger = Logger("test_logger")
|
||||
default_headers = {"X-Unit-Test": "test-guid"}
|
||||
|
||||
settings = {
|
||||
"ai_model_id": ai_model_id,
|
||||
"api_key": api_key,
|
||||
"log": logger,
|
||||
"default_headers": default_headers,
|
||||
}
|
||||
|
||||
@@ -101,13 +90,11 @@ def test_open_ai_text_completion_serialize_with_org_id() -> None:
|
||||
ai_model_id = "test_model_id"
|
||||
api_key = "test_api_key"
|
||||
org_id = "test_org_id"
|
||||
logger = Logger("test_logger")
|
||||
|
||||
settings = {
|
||||
"ai_model_id": ai_model_id,
|
||||
"api_key": api_key,
|
||||
"org_id": org_id,
|
||||
"log": logger,
|
||||
}
|
||||
|
||||
open_ai_text_completion = OpenAITextCompletion.from_dict(settings)
|
||||
|
||||
@@ -49,7 +49,7 @@ async def test_can_call_get_available_functions_with_no_functions_async():
|
||||
memory.search_async.return_value = async_enumerable
|
||||
|
||||
# Arrange GetAvailableFunctionsAsync parameters
|
||||
context = SKContext(variables, memory, skills.read_only_skill_collection, Mock())
|
||||
context = SKContext(variables, memory, skills.read_only_skill_collection)
|
||||
config = SequentialPlannerConfig()
|
||||
semantic_query = "test"
|
||||
|
||||
@@ -195,7 +195,6 @@ async def test_can_call_get_available_functions_with_functions_and_relevancy_asy
|
||||
memory=memory,
|
||||
skill_collection=skills,
|
||||
)
|
||||
context._logger = Mock()
|
||||
config = SequentialPlannerConfig(relevancy_threshold=0.78)
|
||||
semantic_query = "test"
|
||||
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
|
||||
from pytest import raises
|
||||
|
||||
from semantic_kernel.template_engine.blocks.block import Block
|
||||
from semantic_kernel.template_engine.blocks.block_types import BlockTypes
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
|
||||
def test_init():
|
||||
block = Block(content="test content", log=NullLogger())
|
||||
block = Block(content="test content")
|
||||
assert block.content == "test content"
|
||||
assert isinstance(block.log, Logger)
|
||||
|
||||
|
||||
def test_type_property():
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from logging import Logger
|
||||
from unittest.mock import Mock
|
||||
|
||||
from pytest import mark, raises
|
||||
@@ -21,7 +20,6 @@ from semantic_kernel.template_engine.blocks.var_block import VarBlock
|
||||
class TestCodeBlock:
|
||||
def setup_method(self):
|
||||
self.skills = Mock(spec=ReadOnlySkillCollectionBase)
|
||||
self.log = Mock(spec=Logger)
|
||||
|
||||
@mark.asyncio
|
||||
async def test_it_throws_if_a_function_doesnt_exist(self):
|
||||
@@ -29,11 +27,12 @@ class TestCodeBlock:
|
||||
variables=ContextVariables(),
|
||||
memory=NullMemory(),
|
||||
skill_collection=self.skills,
|
||||
logger=self.log,
|
||||
)
|
||||
# Make it so our self.skills mock's `has_function` method returns False
|
||||
self.skills.has_function.return_value = False
|
||||
target = CodeBlock(content="functionName", log=self.log)
|
||||
target = CodeBlock(
|
||||
content="functionName",
|
||||
)
|
||||
|
||||
with raises(ValueError):
|
||||
await target.render_code_async(context)
|
||||
@@ -44,7 +43,6 @@ class TestCodeBlock:
|
||||
variables=ContextVariables(),
|
||||
memory=NullMemory(),
|
||||
skill_collection=self.skills,
|
||||
logger=self.log,
|
||||
)
|
||||
|
||||
def invoke(_):
|
||||
@@ -63,16 +61,28 @@ class TestCodeBlock:
|
||||
self.skills.has_function.return_value = True
|
||||
self.skills.get_function.return_value = function
|
||||
|
||||
target = CodeBlock(content="functionName", log=self.log)
|
||||
target = CodeBlock(
|
||||
content="functionName",
|
||||
)
|
||||
|
||||
with raises(ValueError):
|
||||
await target.render_code_async(context)
|
||||
|
||||
def test_it_has_the_correct_type(self):
|
||||
assert CodeBlock(content="", log=self.log).type == BlockTypes.CODE
|
||||
assert (
|
||||
CodeBlock(
|
||||
content="",
|
||||
).type
|
||||
== BlockTypes.CODE
|
||||
)
|
||||
|
||||
def test_it_trims_spaces(self):
|
||||
assert CodeBlock(content=" aa ", log=self.log).content == "aa"
|
||||
assert (
|
||||
CodeBlock(
|
||||
content=" aa ",
|
||||
).content
|
||||
== "aa"
|
||||
)
|
||||
|
||||
def test_it_checks_validity_of_internal_blocks(self):
|
||||
valid_block1 = FunctionIdBlock(content="x")
|
||||
@@ -81,10 +91,12 @@ class TestCodeBlock:
|
||||
invalid_block = VarBlock(content="!notvalid")
|
||||
|
||||
code_block1 = CodeBlock(
|
||||
tokens=[valid_block1, valid_block2], content="", log=self.log
|
||||
tokens=[valid_block1, valid_block2],
|
||||
content="",
|
||||
)
|
||||
code_block2 = CodeBlock(
|
||||
tokens=[valid_block1, invalid_block], content="", log=self.log
|
||||
tokens=[valid_block1, invalid_block],
|
||||
content="",
|
||||
)
|
||||
|
||||
is_valid1, _ = code_block1.is_valid()
|
||||
@@ -99,11 +111,21 @@ class TestCodeBlock:
|
||||
val_block = ValBlock(content="'value'")
|
||||
var_block = VarBlock(content="$var")
|
||||
|
||||
code_block1 = CodeBlock(tokens=[func_id, val_block], content="", log=self.log)
|
||||
code_block2 = CodeBlock(tokens=[func_id, var_block], content="", log=self.log)
|
||||
code_block3 = CodeBlock(tokens=[func_id, func_id], content="", log=self.log)
|
||||
code_block1 = CodeBlock(
|
||||
tokens=[func_id, val_block],
|
||||
content="",
|
||||
)
|
||||
code_block2 = CodeBlock(
|
||||
tokens=[func_id, var_block],
|
||||
content="",
|
||||
)
|
||||
code_block3 = CodeBlock(
|
||||
tokens=[func_id, func_id],
|
||||
content="",
|
||||
)
|
||||
code_block4 = CodeBlock(
|
||||
tokens=[func_id, var_block, var_block], content="", log=self.log
|
||||
tokens=[func_id, var_block, var_block],
|
||||
content="",
|
||||
)
|
||||
|
||||
is_valid1, _ = code_block1.is_valid()
|
||||
@@ -127,10 +149,11 @@ class TestCodeBlock:
|
||||
variables=variables,
|
||||
memory=NullMemory(),
|
||||
skill_collection=None,
|
||||
logger=self.log,
|
||||
)
|
||||
|
||||
code_block = CodeBlock(content="$varName", log=self.log)
|
||||
code_block = CodeBlock(
|
||||
content="$varName",
|
||||
)
|
||||
result = await code_block.render_code_async(context)
|
||||
|
||||
assert result == "foo"
|
||||
@@ -144,11 +167,11 @@ class TestCodeBlock:
|
||||
variables=variables,
|
||||
memory=NullMemory(),
|
||||
skill_collection=None,
|
||||
logger=self.log,
|
||||
)
|
||||
|
||||
code_block = CodeBlock(
|
||||
tokens=[VarBlock(content="$varName")], content="", log=self.log
|
||||
tokens=[VarBlock(content="$varName")],
|
||||
content="",
|
||||
)
|
||||
result = await code_block.render_code_async(context)
|
||||
|
||||
@@ -160,10 +183,11 @@ class TestCodeBlock:
|
||||
variables=ContextVariables(),
|
||||
memory=NullMemory(),
|
||||
skill_collection=None,
|
||||
logger=self.log,
|
||||
)
|
||||
|
||||
code_block = CodeBlock(content="'ciao'", log=self.log)
|
||||
code_block = CodeBlock(
|
||||
content="'ciao'",
|
||||
)
|
||||
result = await code_block.render_code_async(context)
|
||||
|
||||
assert result == "ciao"
|
||||
@@ -174,11 +198,11 @@ class TestCodeBlock:
|
||||
variables=ContextVariables(),
|
||||
memory=NullMemory(),
|
||||
skill_collection=None,
|
||||
logger=self.log,
|
||||
)
|
||||
|
||||
code_block = CodeBlock(
|
||||
tokens=[ValBlock(content="'arrivederci'")], content="", log=self.log
|
||||
tokens=[ValBlock(content="'arrivederci'")],
|
||||
content="",
|
||||
)
|
||||
result = await code_block.render_code_async(context)
|
||||
|
||||
@@ -192,12 +216,11 @@ class TestCodeBlock:
|
||||
variables["var1"] = "uno"
|
||||
variables["var2"] = "due"
|
||||
|
||||
# Create a context with the variables, memory, skill collection, and logger
|
||||
# Create a context with the variables, memory, and skill collection
|
||||
context = SKContext.model_construct(
|
||||
variables=variables,
|
||||
memory=NullMemory(),
|
||||
skill_collection=self.skills,
|
||||
logger=self.log,
|
||||
)
|
||||
|
||||
# Create a FunctionIdBlock with the function name
|
||||
@@ -234,7 +257,10 @@ class TestCodeBlock:
|
||||
self.skills.get_function.return_value = function
|
||||
|
||||
# Create a CodeBlock with the FunctionIdBlock and render it with the context
|
||||
code_block = CodeBlock(tokens=[func_id], content="", log=self.log)
|
||||
code_block = CodeBlock(
|
||||
tokens=[func_id],
|
||||
content="",
|
||||
)
|
||||
await code_block.render_code_async(context)
|
||||
|
||||
# Check that the canary values match the original context variables
|
||||
@@ -257,12 +283,11 @@ class TestCodeBlock:
|
||||
variables = ContextVariables()
|
||||
variables[VAR_NAME] = VAR_VALUE
|
||||
|
||||
# Create a context with the variables, memory, skill collection, and logger
|
||||
# Create a context with the variables, memory, and skill collection
|
||||
context = SKContext.model_construct(
|
||||
variables=variables,
|
||||
memory=NullMemory(),
|
||||
skill_collection=self.skills,
|
||||
logger=self.log,
|
||||
)
|
||||
|
||||
# Create a FunctionIdBlock with the function name and a
|
||||
@@ -295,7 +320,10 @@ class TestCodeBlock:
|
||||
|
||||
# Create a CodeBlock with the FunctionIdBlock and VarBlock,
|
||||
# and render it with the context
|
||||
code_block = CodeBlock(tokens=[func_id, var_block], content="", log=self.log)
|
||||
code_block = CodeBlock(
|
||||
tokens=[func_id, var_block],
|
||||
content="",
|
||||
)
|
||||
result = await code_block.render_code_async(context)
|
||||
|
||||
# Check that the result matches the custom variable value
|
||||
@@ -308,12 +336,11 @@ class TestCodeBlock:
|
||||
# Define a value to be used in the test
|
||||
VALUE = "value"
|
||||
|
||||
# Create a context with empty variables, memory, skill collection, and logger
|
||||
# Create a context with empty variables, memory, and skill collection
|
||||
context = SKContext.model_construct(
|
||||
variables=ContextVariables(),
|
||||
memory=NullMemory(),
|
||||
skill_collection=self.skills,
|
||||
logger=self.log,
|
||||
)
|
||||
|
||||
# Create a FunctionIdBlock with the function name and a ValBlock with the value
|
||||
@@ -345,7 +372,10 @@ class TestCodeBlock:
|
||||
|
||||
# Create a CodeBlock with the FunctionIdBlock and ValBlock,
|
||||
# and render it with the context
|
||||
code_block = CodeBlock(tokens=[func_id, val_block], content="", log=self.log)
|
||||
code_block = CodeBlock(
|
||||
tokens=[func_id, val_block],
|
||||
content="",
|
||||
)
|
||||
result = await code_block.render_code_async(context)
|
||||
|
||||
# Check that the result matches the value
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
|
||||
from pytest import mark, raises
|
||||
|
||||
@@ -10,11 +9,8 @@ from semantic_kernel.template_engine.blocks.function_id_block import FunctionIdB
|
||||
|
||||
|
||||
def test_init():
|
||||
function_id_block = FunctionIdBlock(
|
||||
content="skill.function", log=Logger("test_logger")
|
||||
)
|
||||
function_id_block = FunctionIdBlock(content="skill.function")
|
||||
assert function_id_block.content == "skill.function"
|
||||
assert isinstance(function_id_block.log, Logger)
|
||||
|
||||
|
||||
def test_type_property():
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
|
||||
from pytest import raises
|
||||
|
||||
@@ -10,53 +9,37 @@ from semantic_kernel.template_engine.blocks.text_block import TextBlock
|
||||
|
||||
|
||||
def test_init():
|
||||
text_block = TextBlock.from_text(text="test text", log=Logger("test_logger"))
|
||||
text_block = TextBlock.from_text(text="test text")
|
||||
assert text_block.content == "test text"
|
||||
assert isinstance(text_block.log, Logger)
|
||||
|
||||
|
||||
def test_init_with_just_start_index():
|
||||
text_block = TextBlock.from_text(
|
||||
text="test text", start_index=2, log=Logger("test_logger")
|
||||
)
|
||||
text_block = TextBlock.from_text(text="test text", start_index=2)
|
||||
assert text_block.content == "st text"
|
||||
assert isinstance(text_block.log, Logger)
|
||||
|
||||
|
||||
def test_init_with_just_stop_index():
|
||||
text_block = TextBlock.from_text(
|
||||
text="test text", stop_index=2, log=Logger("test_logger")
|
||||
)
|
||||
text_block = TextBlock.from_text(text="test text", stop_index=2)
|
||||
assert text_block.content == "te"
|
||||
assert isinstance(text_block.log, Logger)
|
||||
|
||||
|
||||
def test_init_with_start_index_greater_than_stop_index():
|
||||
with raises(ValueError):
|
||||
TextBlock.from_text(
|
||||
text="test text", start_index=2, stop_index=1, log=Logger("test_logger")
|
||||
)
|
||||
TextBlock.from_text(text="test text", start_index=2, stop_index=1)
|
||||
|
||||
|
||||
def test_init_with_start_stop_indices():
|
||||
text_block = TextBlock.from_text(
|
||||
text="test text", start_index=0, stop_index=4, log=Logger("test_logger")
|
||||
)
|
||||
text_block = TextBlock.from_text(text="test text", start_index=0, stop_index=4)
|
||||
assert text_block.content == "test"
|
||||
assert isinstance(text_block.log, Logger)
|
||||
|
||||
|
||||
def test_init_with_start_index_less_than_zero():
|
||||
with raises(ValueError):
|
||||
TextBlock.from_text(
|
||||
text="test text", start_index=-1, stop_index=1, log=Logger("test_logger")
|
||||
)
|
||||
TextBlock.from_text(text="test text", start_index=-1, stop_index=1)
|
||||
|
||||
|
||||
def test_init_with_negative_stop_index():
|
||||
text_block = TextBlock.from_text(
|
||||
text="test text", stop_index=-1, log=Logger("test_logger")
|
||||
)
|
||||
text_block = TextBlock.from_text(text="test text", stop_index=-1)
|
||||
assert text_block.content == "test tex"
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
|
||||
from semantic_kernel.orchestration.context_variables import ContextVariables
|
||||
from semantic_kernel.template_engine.blocks.block_types import BlockTypes
|
||||
@@ -8,9 +7,8 @@ from semantic_kernel.template_engine.blocks.val_block import ValBlock
|
||||
|
||||
|
||||
def test_init():
|
||||
val_block = ValBlock(content="'test value'", log=Logger("test_logger"))
|
||||
val_block = ValBlock(content="'test value'")
|
||||
assert val_block.content == "'test value'"
|
||||
assert isinstance(val_block.log, Logger)
|
||||
|
||||
|
||||
def test_type_property():
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from logging import Logger
|
||||
|
||||
from pytest import mark, raises
|
||||
|
||||
@@ -11,9 +10,8 @@ from semantic_kernel.template_engine.blocks.var_block import VarBlock
|
||||
|
||||
|
||||
def test_init():
|
||||
var_block = VarBlock(content="$test_var", log=Logger("test_logger"))
|
||||
var_block = VarBlock(content="$test_var")
|
||||
assert var_block.content == "$test_var"
|
||||
assert isinstance(var_block.log, Logger)
|
||||
|
||||
|
||||
def test_type_property():
|
||||
|
||||
@@ -14,7 +14,6 @@ from semantic_kernel.skill_definition.read_only_skill_collection import (
|
||||
)
|
||||
from semantic_kernel.template_engine.blocks.block_types import BlockTypes
|
||||
from semantic_kernel.template_engine.prompt_template_engine import PromptTemplateEngine
|
||||
from semantic_kernel.utils.null_logger import NullLogger
|
||||
|
||||
|
||||
@fixture
|
||||
@@ -34,7 +33,7 @@ def skills():
|
||||
|
||||
@fixture
|
||||
def context(variables, skills):
|
||||
return SKContext(variables, NullMemory(), skills, NullLogger())
|
||||
return SKContext(variables, NullMemory(), skills)
|
||||
|
||||
|
||||
def test_it_renders_variables(
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import logging
|
||||
import typing as t
|
||||
|
||||
import pytest
|
||||
@@ -126,9 +125,9 @@ def sk_factory() -> t.Callable[[t.Type[_Serializable]], _Serializable]:
|
||||
TextBlock: TextBlock(content="baz"),
|
||||
ValBlock: ValBlock(content="qux"),
|
||||
VarBlock: VarBlock(content="quux"),
|
||||
CodeTokenizer: CodeTokenizer(log=logging.getLogger("test")),
|
||||
PromptTemplateEngine: PromptTemplateEngine(logger=logging.getLogger("test")),
|
||||
TemplateTokenizer: TemplateTokenizer(log=logging.getLogger("test")),
|
||||
CodeTokenizer: CodeTokenizer(),
|
||||
PromptTemplateEngine: PromptTemplateEngine(),
|
||||
TemplateTokenizer: TemplateTokenizer(),
|
||||
ParameterView: ParameterView(
|
||||
name="foo",
|
||||
description="bar",
|
||||
|
||||
Reference in New Issue
Block a user