Python: cleanup/sync/fixes (for examples, docs, tests, notebooks) (#317)

### Motivation and Context

The `python-preview` branch is under active development and many
docs/tests/examples are getting a bit out of sync. There are also a few
small cleanup chores/refactors to make _usage_ easier (e.g., to make
examples cleaner). I've grouped these small fixes (plus a few bug fixes)
into this "cleanup" PR.

### Description

This PR does the following:

1. Updates the out-of-date example in `README.md`
2. Fixes all 5 of the notebooks we support right now (1,2,3,4, and 6;
notebook 5 is planner, I've blanked out most of the code there so we
don't confuse people, especially as the planner API is changing)
3. Fixes a bug w/ `stop_sequences` in `(Azure)OpenAITextCompletion`
4. Fixes a bug introduced in our upgrades to the embeddings cosine-sim
check (we should add more thorough tests here)
5. Cleans up tests
6. Ensures end-to-end tests are all runnable 
7. Fixes up the `kernel_extensions` to work more naturally (so that end
users can use them directly on the `kernel` object and get good
type-hinting)
This commit is contained in:
Jordan Henkel
2023-04-13 16:12:36 -07:00
committed by Devis Lucato
parent cf7a4a731d
commit 407fb36e59
30 changed files with 493 additions and 503 deletions
+4
View File
@@ -0,0 +1,4 @@
OPENAI_API_KEY=""
OPENAI_ORG_ID=""
AZURE_OPENAI_API_KEY=""
AZURE_OPENAI_ENDPOINT=""
+23 -8
View File
@@ -2,7 +2,10 @@
## Installation
Install the Poetry package manager and create a project virtual environment.
First, navigate to the directory containing this README using your chosen shell.
You will need to have Python 3.10 installed.
Install the Poetry package manager and create a project virtual environment. (Note: we require at least Poetry 1.2.0 and Python 3.10.)
```bash
# Install poetry package
@@ -17,7 +20,7 @@ Make sure you have an
[Open AI API Key](https://openai.com/api/) or
[Azure Open AI service key](https://learn.microsoft.com/azure/cognitive-services/openai/quickstart?pivots=rest-api)
Copy those keys into a `.env` file in this repo
Copy those keys into a `.env` file in this repo (see the `.env.example` file):
```
OPENAI_API_KEY=""
@@ -30,19 +33,24 @@ AZURE_OPENAI_ENDPOINT=""
```python
import semantic_kernel as sk
import semantic_kernel.ai.open_ai as sk_oai
kernel = sk.create_kernel()
# This requires a `.env` file in your current
# directory (see above)
api_key, org_id = sk.openai_settings_from_dot_env()
kernel.config.add_openai_completion_backend(
"davinci-002", "text-davinci-002", api_key, org_id
kernel.config.add_text_backend(
"davinci-002", sk_oai.OpenAITextCompletion(
"text-davinci-002", api_key, org_id
)
)
sk_prompt = """
{{$input}}
Give me the TLDR in 5 words.
Give me the TLDR in exactly 5 words.
"""
text_to_summarize = """
@@ -56,8 +64,7 @@ text_to_summarize = """
does not conflict with the First or Second Law.
"""
tldr_function = sk.extensions.create_semantic_function(
kernel,
tldr_function = kernel.create_semantic_function(
sk_prompt,
max_tokens=200,
temperature=0,
@@ -68,5 +75,13 @@ summary = await kernel.run_on_str_async(text_to_summarize, tldr_function)
output = str(summary.variables).strip()
print("Output: " + output)
# Output: Protect humans, follow orders, survive.
# Output: Robots must not harm humans.
```
Hint: if you want to run this via a file, say `my_sk_example.py`, you will
need to import `asyncio` and replace the `await kernel.run_on_str_async(...)`
call with `asyncio.run(kernel.run_on_str_async(...))`.
Hint: if you want to try this directly in your terminal, run `python3 -m asyncio`
and then paste the code above into the Python REPL. (This is to enable the
top-level `await` syntax.)
+4 -5
View File
@@ -1,10 +1,9 @@
# Copyright (c) Microsoft. All rights reserved.
import semantic_kernel.memory as memory
from semantic_kernel.kernel_base import KernelBase
from semantic_kernel import core_skills, memory
from semantic_kernel.kernel import Kernel
from semantic_kernel.kernel_builder import KernelBuilder
from semantic_kernel.kernel_config import KernelConfig
from semantic_kernel.kernel_extensions import KernelExtensions as extensions
from semantic_kernel.memory.null_memory import NullMemory
from semantic_kernel.orchestration.context_variables import ContextVariables
from semantic_kernel.orchestration.sk_context import SKContext
@@ -24,7 +23,7 @@ from semantic_kernel.utils.settings import (
)
def create_kernel() -> KernelBase:
def create_kernel() -> Kernel:
return KernelBuilder.create_kernel()
@@ -36,7 +35,6 @@ __all__ = [
"create_kernel",
"openai_settings_from_dot_env",
"azure_openai_settings_from_dot_env",
"extensions",
"PromptTemplateConfig",
"PromptTemplate",
"ChatPromptTemplate",
@@ -45,4 +43,5 @@ __all__ = [
"SKFunctionBase",
"SKContext",
"memory",
"core_skills",
]
@@ -19,7 +19,7 @@ class AzureChatCompletion(OpenAIChatCompletion):
deployment_name: str,
endpoint: str,
api_key: str,
api_version: str,
api_version: str = "2023-03-15-preview",
logger: Optional[Logger] = None,
) -> None:
Verify.not_empty(deployment_name, "You must provide a deployment name")
@@ -19,7 +19,7 @@ class AzureTextCompletion(OpenAITextCompletion):
deployment_name: str,
endpoint: str,
api_key: str,
api_version: str,
api_version: str = "2022-12-01",
logger: Optional[Logger] = None,
) -> None:
Verify.not_empty(deployment_name, "You must provide a deployment name")
@@ -19,7 +19,7 @@ class AzureTextEmbedding(OpenAITextEmbedding):
deployment_name: str,
endpoint: str,
api_key: str,
api_version: str,
api_version: str = "2022-12-01",
logger: Optional[Logger] = None,
) -> None:
Verify.not_empty(deployment_name, "You must provide a deployment name")
@@ -106,7 +106,8 @@ class OpenAITextCompletion(TextCompletionClientBase):
max_tokens=request_settings.max_tokens,
stop=(
request_settings.stop_sequences
if len(request_settings.stop_sequences) > 0
if request_settings.stop_sequences is not None
and len(request_settings.stop_sequences) > 0
else None
),
)
+5 -1
View File
@@ -13,6 +13,7 @@ from semantic_kernel.diagnostics.verify import Verify
from semantic_kernel.kernel_base import KernelBase
from semantic_kernel.kernel_config import KernelConfig
from semantic_kernel.kernel_exception import KernelException
from semantic_kernel.kernel_extensions import KernelExtensions
from semantic_kernel.memory.semantic_text_memory_base import SemanticTextMemoryBase
from semantic_kernel.orchestration.context_variables import ContextVariables
from semantic_kernel.orchestration.sk_context import SKContext
@@ -31,7 +32,7 @@ from semantic_kernel.template_engine.protocols.prompt_templating_engine import (
)
class Kernel(KernelBase):
class Kernel(KernelBase, KernelExtensions):
_log: Logger
_config: KernelConfig
_skill_collection: SkillCollectionBase
@@ -52,6 +53,9 @@ class Kernel(KernelBase):
self._prompt_template_engine = prompt_template_engine
self._memory = memory
def kernel(self) -> KernelBase:
return self
@property
def config(self) -> KernelConfig:
return self._config
+2 -3
View File
@@ -5,7 +5,6 @@ from typing import Callable, Optional
from semantic_kernel.diagnostics.verify import Verify
from semantic_kernel.kernel import Kernel
from semantic_kernel.kernel_base import KernelBase
from semantic_kernel.kernel_config import KernelConfig
from semantic_kernel.kernel_extensions import KernelExtensions
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
@@ -56,7 +55,7 @@ class KernelBuilder:
self._config = config_func(self._config)
return self
def build(self) -> KernelBase:
def build(self) -> Kernel:
instance = Kernel(
SkillCollection(self._log),
PromptTemplateEngine(self._log),
@@ -75,7 +74,7 @@ class KernelBuilder:
config: Optional[KernelConfig] = None,
log: Optional[Logger] = None,
memory: Optional[SemanticTextMemoryBase] = None,
) -> KernelBase:
) -> Kernel:
builder = KernelBuilder(KernelConfig(), NullMemory(), NullLogger())
if config is not None:
@@ -1,54 +1,20 @@
# Copyright (c) Microsoft. All rights reserved.
from typing import TYPE_CHECKING, List, Optional
from semantic_kernel.ai.embeddings.embedding_generator_base import (
EmbeddingGeneratorBase,
)
from semantic_kernel.kernel_base import KernelBase
from semantic_kernel.kernel_extensions.inline_function_definitions import (
create_semantic_function,
)
from semantic_kernel.kernel_extensions.memory_configuration import use_memory
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
if TYPE_CHECKING:
from semantic_kernel.orchestration.sk_function_base import SKFunctionBase
from semantic_kernel.kernel_extensions.import_skills import ImportSkills
from semantic_kernel.kernel_extensions.inline_definition import InlineDefinition
from semantic_kernel.kernel_extensions.memory_configuration import MemoryConfiguration
class KernelExtensions:
@staticmethod
def create_semantic_function(
kernel: KernelBase,
prompt_template: str,
function_name: Optional[str] = None,
skill_name: Optional[str] = None,
description: Optional[str] = None,
max_tokens: int = 256,
temperature: float = 0.0,
top_p: float = 1.0,
presence_penalty: float = 0.0,
frequency_penalty: float = 0.0,
stop_sequences: Optional[List[str]] = None,
) -> "SKFunctionBase":
return create_semantic_function(
kernel,
prompt_template,
function_name,
skill_name,
description,
max_tokens,
temperature,
top_p,
presence_penalty,
frequency_penalty,
stop_sequences,
)
class KernelExtensions(
ImportSkills,
InlineDefinition,
MemoryConfiguration,
):
"""
This class is a container for all the kernel extensions.
@staticmethod
def use_memory(
kernel: KernelBase,
storage: MemoryStoreBase,
embeddings_generator: Optional[EmbeddingGeneratorBase] = None,
) -> None:
use_memory(kernel, storage, embeddings_generator)
The kernel extensions are a set of functions that can be
used to extend the functionality of the kernel. The way this
is written intends to somewhat replicate C#'s extensions
methods (while preserving some amount of type checking).
"""
@@ -0,0 +1,10 @@
# Copyright (c) Microsoft. All rights reserved.
from typing import Protocol
from semantic_kernel.kernel_base import KernelBase
class ExtendsKernel(Protocol):
def kernel(self) -> KernelBase:
...
@@ -1,60 +0,0 @@
# Copyright (c) Microsoft. All rights reserved.
import glob
import os
from typing import Dict
from semantic_kernel.diagnostics.verify import Verify
from semantic_kernel.kernel_base import KernelBase
from semantic_kernel.orchestration.sk_function_base import SKFunctionBase
from semantic_kernel.semantic_functions.prompt_template import PromptTemplate
from semantic_kernel.semantic_functions.prompt_template_config import (
PromptTemplateConfig,
)
from semantic_kernel.semantic_functions.semantic_function_config import (
SemanticFunctionConfig,
)
def import_semantic_skill_from_directory(
kernel: KernelBase, parent_directory: str, skill_directory_name: str
) -> Dict[str, SKFunctionBase]:
CONFIG_FILE = "config.json"
PROMPT_FILE = "skprompt.txt"
Verify.valid_skill_name(skill_directory_name)
skill_directory = os.path.join(parent_directory, skill_directory_name)
skill_directory = os.path.abspath(skill_directory)
Verify.directory_exists(skill_directory)
skill = {}
directories = glob.glob(skill_directory + "/*/")
for directory in directories:
dir_name = os.path.dirname(directory)
function_name = os.path.basename(dir_name)
prompt_path = os.path.join(directory, PROMPT_FILE)
# Continue only if the prompt template exists
if not os.path.exists(prompt_path):
continue
config = PromptTemplateConfig()
config_path = os.path.join(directory, CONFIG_FILE)
with open(config_path, "r") as config_file:
config = config.from_json(config_file.read())
# Load Prompt Template
with open(prompt_path, "r") as prompt_file:
template = PromptTemplate(
prompt_file.read(), kernel.prompt_template_engine, config
)
# Prepare lambda wrapping AI logic
function_config = SemanticFunctionConfig(config, template)
skill[function_name] = kernel.register_semantic_function(
skill_directory_name, function_name, function_config
)
return skill
@@ -0,0 +1,63 @@
# Copyright (c) Microsoft. All rights reserved.
import glob
import os
from typing import Dict
from semantic_kernel.diagnostics.verify import Verify
from semantic_kernel.kernel_extensions.extends_kernel import ExtendsKernel
from semantic_kernel.orchestration.sk_function_base import SKFunctionBase
from semantic_kernel.semantic_functions.prompt_template import PromptTemplate
from semantic_kernel.semantic_functions.prompt_template_config import (
PromptTemplateConfig,
)
from semantic_kernel.semantic_functions.semantic_function_config import (
SemanticFunctionConfig,
)
class ImportSkills(ExtendsKernel):
def import_semantic_skill_from_directory(
self, parent_directory: str, skill_directory_name: str
) -> Dict[str, SKFunctionBase]:
CONFIG_FILE = "config.json"
PROMPT_FILE = "skprompt.txt"
kernel = self.kernel()
Verify.valid_skill_name(skill_directory_name)
skill_directory = os.path.join(parent_directory, skill_directory_name)
skill_directory = os.path.abspath(skill_directory)
Verify.directory_exists(skill_directory)
skill = {}
directories = glob.glob(skill_directory + "/*/")
for directory in directories:
dir_name = os.path.dirname(directory)
function_name = os.path.basename(dir_name)
prompt_path = os.path.join(directory, PROMPT_FILE)
# Continue only if the prompt template exists
if not os.path.exists(prompt_path):
continue
config = PromptTemplateConfig()
config_path = os.path.join(directory, CONFIG_FILE)
with open(config_path, "r") as config_file:
config = config.from_json(config_file.read())
# Load Prompt Template
with open(prompt_path, "r") as prompt_file:
template = PromptTemplate(
prompt_file.read(), kernel.prompt_template_engine, config
)
# Prepare lambda wrapping AI logic
function_config = SemanticFunctionConfig(config, template)
skill[function_name] = kernel.register_semantic_function(
skill_directory_name, function_name, function_config
)
return skill
@@ -0,0 +1,70 @@
# Copyright (c) Microsoft. All rights reserved.
from typing import TYPE_CHECKING, List, Optional
from uuid import uuid4
from semantic_kernel.diagnostics.verify import Verify
from semantic_kernel.kernel_extensions.extends_kernel import ExtendsKernel
from semantic_kernel.semantic_functions.prompt_template import PromptTemplate
from semantic_kernel.semantic_functions.prompt_template_config import (
PromptTemplateConfig,
)
from semantic_kernel.semantic_functions.semantic_function_config import (
SemanticFunctionConfig,
)
if TYPE_CHECKING:
from semantic_kernel.orchestration.sk_function_base import SKFunctionBase
class InlineDefinition(ExtendsKernel):
def create_semantic_function(
self,
prompt_template: str,
function_name: Optional[str] = None,
skill_name: Optional[str] = None,
description: Optional[str] = None,
max_tokens: int = 256,
temperature: float = 0.0,
top_p: float = 1.0,
presence_penalty: float = 0.0,
frequency_penalty: float = 0.0,
stop_sequences: Optional[List[str]] = None,
) -> "SKFunctionBase":
kernel = self.kernel()
function_name = (
function_name
if function_name is not None
else f"f_{str(uuid4()).replace('-', '_')}"
)
config = PromptTemplateConfig(
description=(
description
if description is not None
else "Generic function, unknown purpose"
),
type="completion",
completion=PromptTemplateConfig.CompletionConfig(
temperature,
top_p,
presence_penalty,
frequency_penalty,
max_tokens,
stop_sequences if stop_sequences is not None else [],
),
)
Verify.valid_function_name(function_name)
if skill_name is not None:
Verify.valid_skill_name(skill_name)
template = PromptTemplate(
prompt_template, kernel.prompt_template_engine, config
)
function_config = SemanticFunctionConfig(config, template)
return kernel.register_semantic_function(
skill_name, function_name, function_config
)
@@ -1,63 +0,0 @@
# Copyright (c) Microsoft. All rights reserved.
from typing import TYPE_CHECKING, List, Optional
from uuid import uuid4
from semantic_kernel.diagnostics.verify import Verify
from semantic_kernel.kernel_base import KernelBase
from semantic_kernel.semantic_functions.prompt_template import PromptTemplate
from semantic_kernel.semantic_functions.prompt_template_config import (
PromptTemplateConfig,
)
from semantic_kernel.semantic_functions.semantic_function_config import (
SemanticFunctionConfig,
)
if TYPE_CHECKING:
from semantic_kernel.orchestration.sk_function_base import SKFunctionBase
def create_semantic_function(
kernel: KernelBase,
prompt_template: str,
function_name: Optional[str] = None,
skill_name: Optional[str] = None,
description: Optional[str] = None,
max_tokens: int = 256,
temperature: float = 0.0,
top_p: float = 1.0,
presence_penalty: float = 0.0,
frequency_penalty: float = 0.0,
stop_sequences: Optional[List[str]] = None,
) -> "SKFunctionBase":
function_name = (
function_name
if function_name is not None
else f"f_{str(uuid4()).replace('-', '_')}"
)
config = PromptTemplateConfig(
description=(
description
if description is not None
else "Generic function, unknown purpose"
),
type="completion",
completion=PromptTemplateConfig.CompletionConfig(
temperature,
top_p,
presence_penalty,
frequency_penalty,
max_tokens,
stop_sequences if stop_sequences is not None else [],
),
)
Verify.valid_function_name(function_name)
if skill_name is not None:
Verify.valid_skill_name(skill_name)
template = PromptTemplate(prompt_template, kernel.prompt_template_engine, config)
function_config = SemanticFunctionConfig(config, template)
return kernel.register_semantic_function(skill_name, function_name, function_config)
@@ -6,31 +6,34 @@ from semantic_kernel.ai.embeddings.embedding_generator_base import (
EmbeddingGeneratorBase,
)
from semantic_kernel.diagnostics.verify import Verify
from semantic_kernel.kernel_base import KernelBase
from semantic_kernel.kernel_extensions.extends_kernel import ExtendsKernel
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
from semantic_kernel.memory.semantic_text_memory import SemanticTextMemory
def use_memory(
kernel: KernelBase,
storage: MemoryStoreBase,
embeddings_generator: Optional[EmbeddingGeneratorBase] = None,
) -> None:
if embeddings_generator is None:
backend_label = kernel.config.get_embedding_backend_service_id()
Verify.not_empty(backend_label, "The embedding backend label is empty")
class MemoryConfiguration(ExtendsKernel):
def use_memory(
self,
storage: MemoryStoreBase,
embeddings_generator: Optional[EmbeddingGeneratorBase] = None,
) -> None:
kernel = self.kernel()
embeddings_backend = kernel.config.get_ai_backend(
EmbeddingGeneratorBase, backend_label
)
Verify.not_null(
embeddings_backend,
f"AI configuration is missing for: {backend_label}",
)
if embeddings_generator is None:
backend_label = kernel.config.get_embedding_backend_service_id()
Verify.not_empty(backend_label, "The embedding backend label is empty")
embeddings_generator = embeddings_backend(kernel)
embeddings_backend = kernel.config.get_ai_backend(
EmbeddingGeneratorBase, backend_label
)
Verify.not_null(
embeddings_backend,
f"AI configuration is missing for: {backend_label}",
)
Verify.not_null(storage, "The storage instance provided is None")
Verify.not_null(embeddings_generator, "The embedding generator is None")
embeddings_generator = embeddings_backend(kernel)
kernel.register_memory(SemanticTextMemory(storage, embeddings_generator))
Verify.not_null(storage, "The storage instance provided is None")
Verify.not_null(embeddings_generator, "The embedding generator is None")
kernel.register_memory(SemanticTextMemory(storage, embeddings_generator))
@@ -33,6 +33,13 @@ class VolatileMemoryStore(VolatileDataStore, MemoryStoreBase):
)
embedding_array = embedding_array.reshape(embedding_array.shape[0], -1)
# If the query embedding has shape (1, embedding_size),
# reshape it to (embedding_size,)
if len(embedding.shape) == 2:
embedding = embedding.reshape(
embedding.shape[1],
)
# Use numpy to get the cosine similarity between the query
# embedding and all the embeddings in the collection
similarity_scores = self.compute_similarity_scores(embedding, embedding_array)
+2 -2
View File
@@ -29,8 +29,8 @@ Give me the TLDR in 5 words.
"""
# Create the semantic function
tldr_function = sk.extensions.create_semantic_function(
kernel, sk_prompt, max_tokens=200, temperature=0, top_p=0.5
tldr_function = kernel.create_semantic_function(
sk_prompt, max_tokens=200, temperature=0, top_p=0.5
)
# User input
+5 -5
View File
@@ -34,10 +34,7 @@ function_config = sk.SemanticFunctionConfig(prompt_config, prompt_template)
chat_function = kernel.register_semantic_function("ChatBot", "Chat", function_config)
async def chat() -> bool:
context = sk.ContextVariables()
context["chat_history"] = ""
async def chat(context: sk.ContextVariables) -> bool:
try:
user_input = input("User:> ")
context["user_input"] = user_input
@@ -60,9 +57,12 @@ async def chat() -> bool:
async def main() -> None:
context = sk.ContextVariables()
context["chat_history"] = ""
chatting = True
while chatting:
chatting = await chat()
chatting = await chat(context)
if __name__ == "__main__":
+10 -13
View File
@@ -1,16 +1,13 @@
# Copyright (c) Microsoft. All rights reserved.
# TODO: fix/complete the memory integration
import asyncio
from typing import Tuple
import semantic_kernel as sk
import semantic_kernel.ai.open_ai as sk_oai
from semantic_kernel.core_skills import TextMemorySkill
def build_kernel() -> sk.KernelBase:
def build_kernel() -> sk.Kernel:
# Setup kernel with OpenAI completion and embedding backends
api_key, org_id = sk.openai_settings_from_dot_env()
@@ -32,12 +29,12 @@ def build_kernel() -> sk.KernelBase:
.build()
)
kernel.import_skill(TextMemorySkill())
kernel.import_skill(sk.core_skills.TextMemorySkill())
return kernel
async def populate_memory(kernel: sk.KernelBase) -> None:
async def populate_memory(kernel: sk.Kernel) -> None:
# Add some documents to the semantic memory
await kernel.memory.save_information_async(
"aboutMe", id="info1", text="My name is Andrea"
@@ -56,7 +53,7 @@ async def populate_memory(kernel: sk.KernelBase) -> None:
)
async def search_memory_examples(kernel: sk.KernelBase) -> None:
async def search_memory_examples(kernel: sk.Kernel) -> None:
questions = [
"what's my name",
"where do I live?",
@@ -72,7 +69,7 @@ async def search_memory_examples(kernel: sk.KernelBase) -> None:
async def setup_chat_with_memory(
kernel: sk.KernelBase,
kernel: sk.Kernel,
) -> Tuple[sk.SKFunctionBase, sk.SKContext]:
sk_prompt = """
ChatBot can have a conversation with you about any topic.
@@ -91,8 +88,8 @@ async def setup_chat_with_memory(
User: {{$user_input}}
ChatBot: """.strip()
chat_func = sk.extensions.create_semantic_function(
kernel, sk_prompt, max_tokens=200, temperature=0.8
chat_func = kernel.create_semantic_function(
sk_prompt, max_tokens=200, temperature=0.8
)
context = kernel.create_new_context()
@@ -102,8 +99,8 @@ async def setup_chat_with_memory(
context["fact4"] = "where have I traveled?"
context["fact5"] = "what do I do for work?"
context[TextMemorySkill.COLLECTION_PARAM] = "aboutMe"
context[TextMemorySkill.RELEVANCE_PARAM] = 0.8
context[sk.core_skills.TextMemorySkill.COLLECTION_PARAM] = "aboutMe"
context[sk.core_skills.TextMemorySkill.RELEVANCE_PARAM] = 0.8
context["chat_history"] = ""
@@ -111,7 +108,7 @@ async def setup_chat_with_memory(
async def chat(
kernel: sk.KernelBase, chat_func: sk.SKFunctionBase, context: sk.SKContext
kernel: sk.Kernel, chat_func: sk.SKFunctionBase, context: sk.SKContext
) -> bool:
try:
user_input = input("User:> ")
@@ -0,0 +1,34 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
import semantic_kernel as sk
import semantic_kernel.ai.open_ai as sk_oai
kernel = sk.create_kernel()
useAzureOpenAI = False
model = "text-davinci-002"
service_id = model
# Configure AI backend used by the kernel
if useAzureOpenAI:
api_key, endpoint = sk.azure_openai_settings_from_dot_env()
kernel.config.add_text_backend(
service_id, sk_oai.AzureTextCompletion(model, api_key, endpoint)
)
else:
api_key, org_id = sk.openai_settings_from_dot_env()
kernel.config.add_text_backend(
service_id, sk_oai.OpenAITextCompletion(model, api_key, org_id)
)
# note: using skills from the samples folder
skills_directory = os.path.join(__file__, "../../../../samples/skills")
skill = kernel.import_semantic_skill_from_directory(skills_directory, "FunSkill")
result = asyncio.run(
kernel.run_on_str_async("time travel to dinosaur age", skill["Joke"])
)
print(result)
@@ -4,12 +4,9 @@ import os
import semantic_kernel as sk
import semantic_kernel.ai.open_ai as sk_oai
from semantic_kernel.kernel_extensions.import_semantic_skill_from_directory import (
import_semantic_skill_from_directory,
)
def test_can_be_imported():
def test_skill_can_be_imported():
# create a kernel
kernel = sk.create_kernel()
api_key = "test-api-key"
@@ -20,10 +17,10 @@ def test_can_be_imported():
)
# import skills
skills_directory = os.path.join(os.path.dirname(__file__), "test_skills")
skills_directory = os.path.join(os.path.dirname(__file__), "../..", "test_skills")
# path to skills directory
skill_config_dict = import_semantic_skill_from_directory(
kernel, skills_directory, "TestSkill"
skill_config_dict = kernel.import_semantic_skill_from_directory(
skills_directory, "TestSkill"
)
assert skill_config_dict is not None
@@ -1,5 +1,5 @@
import numpy as np
from pytest import raises, mark
from pytest import mark, raises
from semantic_kernel.memory import VolatileMemoryStore
@@ -24,8 +24,17 @@
"metadata": {},
"outputs": [],
"source": [
"from init import *\n",
"import semantic_kernel as sk"
"!python -m pip install ../../../python"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import semantic_kernel as sk\n",
"import semantic_kernel.ai.open_ai as sk_oai"
]
},
{
@@ -42,7 +51,7 @@
"outputs": [],
"source": [
"# Simple instance\n",
"kernel_1 = sk.KernelBuilder.create_kernel()"
"kernel_1 = sk.create_kernel()"
]
},
{
@@ -92,20 +101,24 @@
"metadata": {},
"outputs": [],
"source": [
"kernel = sk.KernelBuilder.create_kernel()\n",
"kernel = sk.create_kernel()\n",
"\n",
"kernel.config.add_azure_openai_completion_backend(\n",
" \"Azure_curie\", # alias used in the prompt templates' config.json\n",
" \"my-finetuned-Curie\", # Azure OpenAI *Deployment ID*\n",
" \"https://contoso.openai.azure.com/\", # Azure OpenAI *Endpoint*\n",
" \"...your Azure OpenAI Key...\" # Azure OpenAI *Key*\n",
"kernel.config.add_text_backend( # We are adding a text backend\n",
" \"Azure_curie\", # The alias we can use in prompt templates' config.json\n",
" sk_oai.AzureTextCompletion(\n",
" \"my-finetuned-Curie\", # Azure OpenAI *Deployment ID*\n",
" \"https://contoso.openai.azure.com/\", # Azure OpenAI *Endpoint*\n",
" \"...your Azure OpenAI Key...\" # Azure OpenAI *Key*\n",
" )\n",
")\n",
"\n",
"kernel.config.add_openai_completion_backend(\n",
" \"OpenAI_davinci\", # alias used in the prompt templates' config.json\n",
" \"text-davinci-003\", # OpenAI Model Name\n",
" \"...your OpenAI API Key...\", # OpenAI API key\n",
" \"...your OpenAI Org ID...\" # *optional* OpenAI Organization ID\n",
"kernel.config.add_text_backend( # We are adding a text backend\n",
" \"OpenAI_davinci\", # The alias we can use in prompt templates' config.json\n",
" sk_oai.OpenAITextCompletion(\n",
" \"text-davinci-003\", # OpenAI Model Name\n",
" \"...your OpenAI API Key...\", # OpenAI API key\n",
" \"...your OpenAI Org ID...\" # *optional* OpenAI Organization ID\n",
" )\n",
")"
]
},
@@ -128,7 +141,7 @@
"metadata": {},
"outputs": [],
"source": [
"kernel.config.set_default_completion_backend(\"Azure_curie\");"
"kernel.config.set_default_text_backend(\"Azure_curie\")"
]
},
{
@@ -155,7 +168,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.9"
"version": "3.10.10"
},
"polyglot_notebook": {
"kernelInfo": {
@@ -77,6 +77,16 @@
"Load and configure the kernel, as usual, loading also the AI backend settings defined in the [Setup notebook](0-AI-settings.ipynb):"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "365cfc01",
"metadata": {},
"outputs": [],
"source": [
"!python -m pip install ../../../python"
]
},
{
"cell_type": "code",
"execution_count": null,
@@ -84,21 +94,26 @@
"metadata": {},
"outputs": [],
"source": [
"from init import *\n",
"import semantic_kernel as sk\n",
"import semantic_kernel.ai.open_ai as sk_oai\n",
"\n",
"kernel = sk.KernelBuilder.create_kernel()\n",
"kernel = sk.create_kernel()\n",
"\n",
"useAzureOpenAI = False\n",
"model = \"text-davinci-002\"\n",
"service_id = model\n",
"\n",
"# Configure AI backend used by the kernel\n",
"if useAzureOpenAI:\n",
" api_key, endpoint = azure_openai_settings_from_dot_env()\n",
" kernel.config.add_azure_openai_completion_backend(\"davinci\", model, endpoint, api_key, overwrite = True)\n",
" api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
" kernel.config.add_text_backend(\n",
" service_id, sk_oai.AzureTextCompletion(model, api_key, endpoint)\n",
" )\n",
"else:\n",
" api_key, org_id = openai_settings_from_dot_env()\n",
" kernel.config.add_openai_completion_backend(\"davinci\", model, api_key, org_id, overwrite=True)\n"
" api_key, org_id = sk.openai_settings_from_dot_env()\n",
" kernel.config.add_text_backend(\n",
" service_id, sk_oai.OpenAITextCompletion(model, api_key, org_id)\n",
" )"
]
},
{
@@ -117,10 +132,8 @@
"outputs": [],
"source": [
"# note: using skills from the samples folder\n",
"from semantic_kernel.kernel_extensions.import_semantic_skill_from_directory import import_semantic_skill_from_directory\n",
"\n",
"skills_directory = \"../../skills\"\n",
"skill = import_semantic_skill_from_directory(kernel, skills_directory, \"FunSkill\")"
"skill = kernel.import_semantic_skill_from_directory(skills_directory, \"FunSkill\")"
]
},
{
@@ -138,7 +151,7 @@
"metadata": {},
"outputs": [],
"source": [
"result = await (kernel.run_on_str_async(\"time travel to dinosaur age\", skill[\"Joke\"]))\n",
"result = await kernel.run_on_str_async(\"time travel to dinosaur age\", skill[\"Joke\"])\n",
"\n",
"print(result)"
]
@@ -168,7 +181,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.9"
"version": "3.10.10"
}
},
"nbformat": 4,
@@ -38,6 +38,16 @@
"Prepare a semantic kernel instance first, loading also the AI backend settings defined in the [Setup notebook](0-AI-settings.ipynb):"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1da651d4",
"metadata": {},
"outputs": [],
"source": [
"!python -m pip install ../../../python"
]
},
{
"cell_type": "code",
"execution_count": null,
@@ -45,22 +55,26 @@
"metadata": {},
"outputs": [],
"source": [
"from init import *\n",
"import semantic_kernel as sk\n",
"from semantic_kernel.kernel_extensions.inline_function_definitions import create_semantic_function\n",
"import semantic_kernel.ai.open_ai as sk_oai\n",
"\n",
"kernel = sk.KernelBuilder.create_kernel()\n",
"kernel = sk.create_kernel()\n",
"\n",
"useAzureOpenAI = False\n",
"model = \"text-davinci-002\"\n",
"service_id = model\n",
"\n",
"# Configure AI backend used by the kernel\n",
"if useAzureOpenAI:\n",
" api_key, endpoint = azure_openai_settings_from_dot_env()\n",
" kernel.config.add_azure_openai_completion_backend(\"davinci\", model, endpoint, api_key, overwrite=True)\n",
" api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
" kernel.config.add_text_backend(\n",
" service_id, sk_oai.AzureTextCompletion(model, api_key, endpoint)\n",
" )\n",
"else:\n",
" api_key, org_id = openai_settings_from_dot_env()\n",
" kernel.config.add_openai_completion_backend(\"davinci\", model, api_key, org_id, overwrite = True)"
" api_key, org_id = sk.openai_settings_from_dot_env()\n",
" kernel.config.add_text_backend(\n",
" service_id, sk_oai.OpenAITextCompletion(model, api_key, org_id)\n",
" )"
]
},
{
@@ -218,7 +232,7 @@
"Summarize the content above.\n",
"\"\"\"\n",
"\n",
"summary_function = create_semantic_function(kernel, sk_prompt, max_tokens=2000, temperature=0.2, top_p=0.5)\n",
"summary_function = kernel.create_semantic_function(sk_prompt, max_tokens=2000, temperature=0.2, top_p=0.5)\n",
"\n",
"summary = await kernel.run_on_str_async(input_text, summary_function)\n",
"\n",
@@ -245,10 +259,11 @@
"source": [
"kernel = sk.create_kernel()\n",
"\n",
"api_key, org_id = openai_settings_from_dot_env()\n",
"api_key, org_id = sk.openai_settings_from_dot_env()\n",
"\n",
"kernel.config.add_openai_completion_backend(\n",
" \"davinci\", \"text-davinci-003\", api_key, org_id, overwrite=True)\n",
"kernel.config.add_text_backend(\n",
" \"davinci\", sk_oai.OpenAITextCompletion(\"text-davinci-003\", api_key, org_id)\n",
")\n",
"\n",
"sk_prompt = \"\"\"\n",
"{{$input}}\n",
@@ -267,8 +282,7 @@
" does not conflict with the First or Second Law.\n",
"\"\"\"\n",
"\n",
"tldr_function = sk.extensions.create_semantic_function(\n",
" kernel,\n",
"tldr_function = kernel.create_semantic_function(\n",
" sk_prompt,\n",
" max_tokens=200,\n",
" temperature=0,\n",
@@ -279,8 +293,16 @@
"output = str(summary.variables).strip()\n",
"print(\"Output: \" + output)\n",
"\n",
"# Output: Protect humans, follow orders, survive."
"# Output: Robots must not harm humans."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d05d8ffb",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
@@ -299,7 +321,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.9"
"version": "3.10.10"
}
},
"nbformat": 4,
@@ -18,6 +18,16 @@
"In this chat scenario, as the user talks back and forth with the bot, the context gets populated with the history of the conversation. During each new run of the kernel, the context can provide the AI with its variables' content. "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "92f69b34",
"metadata": {},
"outputs": [],
"source": [
"!python -m pip install ../../../python"
]
},
{
"cell_type": "code",
"execution_count": null,
@@ -25,21 +35,26 @@
"metadata": {},
"outputs": [],
"source": [
"from init import *\n",
"import semantic_kernel as sk\n",
"import semantic_kernel.ai.open_ai as sk_oai\n",
"\n",
"kernel = sk.KernelBuilder.create_kernel()\n",
"kernel = sk.create_kernel()\n",
"\n",
"useAzureOpenAI = False\n",
"model = \"text-davinci-003\"\n",
"model = \"text-davinci-002\"\n",
"service_id = model\n",
"\n",
"# Configure AI backend used by the kernel\n",
"if (useAzureOpenAI):\n",
" api_key, endpoint = azure_openai_settings_from_dot_env()\n",
" kernel.config.add_azure_openai_completion_backend(\"davinci\", model, endpoint, api_key, overwrite=True)\n",
"if useAzureOpenAI:\n",
" api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
" kernel.config.add_text_backend(\n",
" service_id, sk_oai.AzureTextCompletion(model, api_key, endpoint)\n",
" )\n",
"else:\n",
" api_key, org_id = openai_settings_from_dot_env()\n",
" kernel.config.add_openai_completion_backend(\"davinci\", model, api_key, org_id, overwrite=True)"
" api_key, org_id = sk.openai_settings_from_dot_env()\n",
" kernel.config.add_text_backend(\n",
" service_id, sk_oai.OpenAITextCompletion(model, api_key, org_id)\n",
" )"
]
},
{
@@ -63,7 +78,7 @@
"\n",
"{{$history}}\n",
"Human: {{$human_input}}\n",
"ChatBot:\";\n",
"ChatBot:\n",
"\"\"\"\n",
"\n",
"prompt_config = sk.PromptTemplateConfig.from_completion_parameters(\n",
@@ -86,7 +101,6 @@
"outputs": [],
"source": [
"prompt_template = sk.PromptTemplate(sk_prompt, kernel.prompt_template_engine, prompt_config)\n",
"\n",
"function_config = sk.SemanticFunctionConfig(prompt_config, prompt_template)\n",
"chat_function = kernel.register_semantic_function(\"ChatBot\", \"Chat\", function_config)"
]
@@ -107,9 +121,7 @@
"outputs": [],
"source": [
"context = sk.ContextVariables()\n",
"\n",
"history = \"\"\n",
"context.set(\"history\", history)"
"context[\"history\"] = \"\""
]
},
{
@@ -127,10 +139,8 @@
"metadata": {},
"outputs": [],
"source": [
"human_input = \"Hi, I'm looking for book suggestions\"\n",
"context.set(\"human_input\", human_input)\n",
"\n",
"bot_answer = await kernel.run_on_str_async(context, chat_function)\n",
"context[\"human_input\"] = \"Hi, I'm looking for book suggestions\"\n",
"bot_answer = await kernel.run_on_vars_async(context, chat_function)\n",
"print(bot_answer)"
]
},
@@ -149,10 +159,8 @@
"metadata": {},
"outputs": [],
"source": [
"history += \"\\nHuman: {human_input}\\nMelody: {bot_answer}\\n\"\n",
"context.update(history);\n",
"\n",
"print(context)"
"context[\"history\"] += f\"\\nHuman: {context['human_input']}\\nChatBot: {bot_answer}\\n\"\n",
"print(context[\"history\"])"
]
},
{
@@ -170,21 +178,18 @@
"metadata": {},
"outputs": [],
"source": [
"history = \"\"\n",
"async def chat(input_text: str) -> str:\n",
" global history\n",
"async def chat(input_text: str) -> None:\n",
" # Save new message in the context variables\n",
" context.set(\"human_input\", input_text)\n",
" context[\"human_input\"] = input_text\n",
"\n",
" # Process the user message and get an answer\n",
" answer = await kernel.run_on_str_async(context, chat_function)\n",
"\n",
" # Append the new interaction to the chat history\n",
" history = history + f\"\\nHuman: {input_text}\\nMelody: {answer}\\n\"\n",
" context.set(\"history\", history)\n",
" answer = await kernel.run_on_vars_async(context, chat_function)\n",
"\n",
" # Show the response\n",
" print(context)"
" print(answer)\n",
"\n",
" # Append the new interaction to the chat history\n",
" context[\"history\"] += f\"\\nHuman: {input_text}\\nChatBot: {answer}\\n\""
]
},
{
@@ -244,7 +249,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.9"
"version": "3.10.10"
}
},
"nbformat": 4,
@@ -14,6 +14,16 @@
"Read more about it [here](https://aka.ms/sk/concepts/planner)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "04e5cf15",
"metadata": {},
"outputs": [],
"source": [
"!python -m pip install ../../../python"
]
},
{
"cell_type": "code",
"execution_count": null,
@@ -21,21 +31,26 @@
"metadata": {},
"outputs": [],
"source": [
"from init import *\n",
"import semantic_kernel as sk\n",
"import semantic_kernel.ai.open_ai as sk_oai\n",
"\n",
"kernel = sk.KernelBuilder.create_kernel()\n",
"kernel = sk.create_kernel()\n",
"\n",
"useAzureOpenAI = False\n",
"model = \"text-davinci-002\"\n",
"service_id = model\n",
"\n",
"# Configure AI backend used by the kernel\n",
"if (useAzureOpenAI):\n",
" api_key, endpoint = azure_openai_settings_from_dot_env()\n",
" kernel.config.add_azure_openai_completion_backend(\"davinci\", model, endpoint, api_key)\n",
"if useAzureOpenAI:\n",
" api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
" kernel.config.add_text_backend(\n",
" service_id, sk_oai.AzureTextCompletion(model, api_key, endpoint)\n",
" )\n",
"else:\n",
" api_key, org_id = openai_settings_from_dot_env()\n",
" kernel.config.add_openai_completion_backend(\"davinci\", model, api_key, org_id)"
" api_key, org_id = sk.openai_settings_from_dot_env()\n",
" kernel.config.add_text_backend(\n",
" service_id, sk_oai.OpenAITextCompletion(model, api_key, org_id)\n",
" )"
]
},
{
@@ -54,11 +69,7 @@
"metadata": {},
"outputs": [],
"source": [
"from semantic_kernel.core_skills import PlannerSkill\n",
"from semantic_kernel.kernel_extensions.import_semantic_skill_from_directory import import_semantic_skill_from_directory\n",
"\n",
"# Load native skill into the kernel registry, sharing its functions with prompt templates\n",
"planner = kernel.import_skill(PlannerSkill(kernel))"
"# TODO: implement in Python"
]
},
{
@@ -86,9 +97,7 @@
"metadata": {},
"outputs": [],
"source": [
"skills_directory = \"../../skills\"\n",
"skill = import_semantic_skill_from_directory(kernel, skills_directory, \"SummarizeSkill\")\n",
"skill = import_semantic_skill_from_directory(kernel, skills_directory, \"WriterSkill\")"
"# TODO: implement in Python"
]
},
{
@@ -106,11 +115,7 @@
"metadata": {},
"outputs": [],
"source": [
"ask = \"Tomorrow is Valentine's day. I need to come up with a few date ideas and e-mail them to my significant other.\";\n",
"originalPlan = await kernel.run_on_str_async(ask, planner[\"CreatePlan\"])\n",
"\n",
"print(\"Original plan:\\n\");\n",
"print(originalPlan.variales.to_plan().plan_string);"
"# TODO: implement in Python"
]
},
{
@@ -138,12 +143,7 @@
"metadata": {},
"outputs": [],
"source": [
"sk_prompt = \"\"\"\n",
"{{$input}}\n",
"\n",
"Rewrite the above in the style of Shakespeare.\n",
"\"\"\"\n",
"shakespeareFunction = kernel.CreateSemanticFunction(sk_prompt, \"shakespeare\", \"ShakespeareSkill\", max_tokens: 2000, temperature: 0.2, top_p: 0.5);"
"# TODO: implement in Python"
]
},
{
@@ -161,29 +161,7 @@
"metadata": {},
"outputs": [],
"source": [
"ask = \"\"\"Tomorrow is Valentine's day. I need to come up with a few date ideas.\n",
" She likes Shakespeare so write using his style. E-mail these ideas to my significant other\"\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f0549fbb",
"metadata": {},
"outputs": [],
"source": [
"new_plan = await kernel.run_on_str_async(ask, planner[\"CreatePlan\"]);"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "dfe479d6",
"metadata": {},
"outputs": [],
"source": [
"print(\"Updated plan:\\n\");\n",
"print(new_plan.variales.to_plan().plan_string);"
"# TODO: implement in Python"
]
},
{
@@ -203,36 +181,7 @@
"metadata": {},
"outputs": [],
"source": [
"execution_results = new_plan"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "eddf13ea",
"metadata": {},
"outputs": [],
"source": [
"step = 1\n",
"maxSteps = 10\n",
"while (not execution_results.variales.to_plan().is_complete and step < maxSteps):\n",
" results = await kernel.run_on_str_async(execution_results.variables, planner[\"ExecutePlan\"])\n",
" if (results.variabes.to_plan().is_successful):\n",
" print(\"Step {step} - Execution results:\\n\")\n",
" print(results.variables.to_plan().plan_string)\n",
"\n",
" if (results.variables.to_plan().is_complete):\n",
" print(\"Step {step} - COMPLETE!\")\n",
" print(results.variables.to_plan().result)\n",
" break\n",
" else:\n",
" print(\"Step {step} - Execution failed:\")\n",
" print(results.variables.to_plan().result)\n",
" break\n",
" \n",
" execution_results = results\n",
" step += 1\n",
" print(\"\")"
"# TODO: implement in Python"
]
}
],
@@ -252,7 +201,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.9"
"version": "3.10.10"
}
},
"nbformat": 4,
@@ -20,6 +20,16 @@
"To do this, we dive into the key concept of `Semantic Memory` in the Semantic Kernel. "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a77bdf89",
"metadata": {},
"outputs": [],
"source": [
"!python -m pip install ../../../python"
]
},
{
"cell_type": "code",
"execution_count": null,
@@ -27,11 +37,10 @@
"metadata": {},
"outputs": [],
"source": [
"from init import *\n",
"from typing import Tuple\n",
"\n",
"import semantic_kernel as sk\n",
"from semantic_kernel.kernel_extensions.inline_function_definitions import create_semantic_function\n",
"from semantic_kernel.core_skills import TextMemorySkill\n",
"from typing import Tuple"
"import semantic_kernel.ai.open_ai as sk_oai"
]
},
{
@@ -52,36 +61,30 @@
"metadata": {},
"outputs": [],
"source": [
"def build_kernel(useAzureOpenAI=False) -> sk.KernelBase:\n",
"def build_kernel() -> sk.Kernel:\n",
" # Setup kernel with OpenAI completion and embedding backends\n",
"\n",
" if (useAzureOpenAI):\n",
" api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
" else:\n",
" api_key, org_id = sk.openai_settings_from_dot_env()\n",
" api_key, org_id = sk.openai_settings_from_dot_env()\n",
"\n",
" kernel = (\n",
" sk.kernel_builder()\n",
" .configure(\n",
" lambda c: c.add_azure_openai_completion_backend(\n",
" \"davinci-002\", \"text-davinci-002\", endpoint, api_key, overwrite=True\n",
" ) if (useAzureOpenAI) else c.add_openai_completion_backend(\n",
" \"davinci-002\", \"text-davinci-002\", api_key, org_id, overwrite=True\n",
" lambda c: c.add_text_backend(\n",
" \"davinci-003\",\n",
" sk_oai.OpenAITextCompletion(\"text-davinci-003\", api_key, org_id),\n",
" )\n",
" )\n",
" .configure(\n",
" lambda c: c.add_azure_openai_embeddings_backend(\n",
" \"ada-002\", \"text-embedding-ada-002\", endpoint, api_key, overwrite=True\n",
" ) if (useAzureOpenAI) else c.add_open_ai_embeddings_backend(\n",
" \"ada-002\", \"text-embedding-ada-002\", api_key, org_id, overwrite=True\n",
" lambda c: c.add_embedding_backend(\n",
" \"ada-002\",\n",
" sk_oai.OpenAITextEmbedding(\"text-embedding-ada-002\", api_key, org_id),\n",
" )\n",
" )\n",
" .with_memory_storage(sk.memory.VolatileMemoryStore())\n",
" .build()\n",
" )\n",
"\n",
" kernel.import_skill(TextMemorySkill())\n",
" \n",
" kernel.import_skill(sk.core_skills.TextMemorySkill())\n",
"\n",
" return kernel"
]
},
@@ -111,24 +114,22 @@
"metadata": {},
"outputs": [],
"source": [
"async def populate_memory(kernel: sk.KernelBase) -> None:\n",
"\n",
" memory_collection_name = \"aboutMe\"\n",
" # Add some documents to the kernel's memory\n",
"async def populate_memory(kernel: sk.Kernel) -> None:\n",
" # Add some documents to the semantic memory\n",
" await kernel.memory.save_information_async(\n",
" memory_collection_name, id=\"info1\", text=\"My name is Andrea\"\n",
" \"aboutMe\", id=\"info1\", text=\"My name is Andrea\"\n",
" )\n",
" await kernel.memory.save_information_async(\n",
" memory_collection_name, id=\"info2\", text=\"I currently work as a tour guide\"\n",
" \"aboutMe\", id=\"info2\", text=\"I currently work as a tour guide\"\n",
" )\n",
" await kernel.memory.save_information_async(\n",
" memory_collection_name, id=\"info3\", text=\"I've been living in Seattle since 2005\"\n",
" \"aboutMe\", id=\"info3\", text=\"I've been living in Seattle since 2005\"\n",
" )\n",
" await kernel.memory.save_information_async(\n",
" memory_collection_name, id=\"info4\", text=\"I visited France and Italy five times since 2015\"\n",
" \"aboutMe\", id=\"info4\", text=\"I visited France and Italy five times since 2015\"\n",
" )\n",
" await kernel.memory.save_information_async(\n",
" memory_collection_name, id=\"info5\", text=\"My family is from New York\"\n",
" \"aboutMe\", id=\"info5\", text=\"My family is from New York\"\n",
" )"
]
},
@@ -147,7 +148,7 @@
"metadata": {},
"outputs": [],
"source": [
"async def search_memory_examples(kernel: sk.KernelBase) -> None:\n",
"async def search_memory_examples(kernel: sk.Kernel) -> None:\n",
" questions = [\n",
" \"what's my name\",\n",
" \"where do I live?\",\n",
@@ -190,7 +191,7 @@
"outputs": [],
"source": [
"async def setup_chat_with_memory(\n",
" kernel: sk.KernelBase,\n",
" kernel: sk.Kernel,\n",
") -> Tuple[sk.SKFunctionBase, sk.SKContext]:\n",
" sk_prompt = \"\"\"\n",
" ChatBot can have a conversation with you about any topic.\n",
@@ -206,11 +207,11 @@
"\n",
" Chat:\n",
" {{$chat_history}}\n",
" User: {{$human_input}}\n",
" ChatBot: \"\"\"\n",
" User: {{$user_input}}\n",
" ChatBot: \"\"\".strip()\n",
"\n",
" chat_func = create_semantic_function(\n",
" kernel, sk_prompt, max_tokens=200, temperature=0.8\n",
" chat_func = kernel.create_semantic_function(\n",
" sk_prompt, max_tokens=200, temperature=0.8\n",
" )\n",
"\n",
" context = kernel.create_new_context()\n",
@@ -220,8 +221,8 @@
" context[\"fact4\"] = \"where have I traveled?\"\n",
" context[\"fact5\"] = \"what do I do for work?\"\n",
"\n",
" context[TextMemorySkill.COLLECTION_PARAM] = \"aboutMe\"\n",
" context[TextMemorySkill.RELEVANCE_PARAM] = 0.8\n",
" context[sk.core_skills.TextMemorySkill.COLLECTION_PARAM] = \"aboutMe\"\n",
" context[sk.core_skills.TextMemorySkill.RELEVANCE_PARAM] = 0.8\n",
"\n",
" context[\"chat_history\"] = \"\"\n",
"\n",
@@ -252,11 +253,11 @@
"outputs": [],
"source": [
"async def chat(\n",
" kernel: sk.KernelBase, chat_func: sk.SKFunctionBase, context: sk.SKContext\n",
" kernel: sk.Kernel, chat_func: sk.SKFunctionBase, context: sk.SKContext\n",
") -> bool:\n",
" try:\n",
" human_input = input(\"Human:>\")\n",
" context[\"human_input\"] = human_input\n",
" user_input = input(\"User:> \")\n",
" context[\"user_input\"] = user_input\n",
" except KeyboardInterrupt:\n",
" print(\"\\n\\nExiting chat...\")\n",
" return False\n",
@@ -264,14 +265,14 @@
" print(\"\\n\\nExiting chat...\")\n",
" return False\n",
"\n",
" if human_input == \"exit\":\n",
" if user_input == \"exit\":\n",
" print(\"\\n\\nExiting chat...\")\n",
" return False\n",
"\n",
" answer = await kernel.run_on_vars_async(context.variables, chat_func)\n",
" context[\"chat_history\"] += f\"\\nHuman:>{human_input}\\nChatBot:>{answer}\\n\"\n",
" context[\"chat_history\"] += f\"\\nUser:> {user_input}\\nChatBot:> {answer}\\n\"\n",
"\n",
" print(answer)\n",
" print(f\"ChatBot:> {answer}\")\n",
" return True"
]
},
@@ -286,22 +287,25 @@
"\n",
"print(\"Populating memory...\")\n",
"await populate_memory(kernel)\n",
"\n",
"print(\"Asking questions... (manually)\")\n",
"await search_memory_examples(kernel)\n",
"\n",
"print(\"Setting up a chat (with memory!)\")\n",
"chat_func, context = await setup_chat_with_memory(kernel)\n",
"print(\"Begin chatting (type 'exit' to exit):\")\n",
"\n",
"print(\"Begin chatting (type 'exit' to exit):\\n\")\n",
"chatting = True\n",
"while chatting:\n",
" chatting = await chat(kernel, chat_func, context)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "0a51542b",
"metadata": {},
"source": [
"# TODO: NEED TO IMPLEMENT EMBEDDING SEARCH\n",
"### Adding documents to your memory\n",
"\n",
"Many times in your applications you'll want to bring in external documents into your memory. Let's see how we can do this using our VolatileMemoryStore.\n",
@@ -429,7 +433,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.9"
"version": "3.10.10"
}
},
"nbformat": 4,
-62
View File
@@ -1,62 +0,0 @@
# Copyright (c) Microsoft. All rights reserved.
from typing import Optional, Tuple
def openai_settings_from_dot_env() -> Tuple[str, Optional[str]]:
"""
Reads the OpenAI API key and organization ID from the .env file.
Returns:
Tuple[str, str]: The OpenAI API key, the OpenAI organization ID
"""
api_key, org_id = None, None
with open(".env", "r") as f:
lines = f.readlines()
for line in lines:
if line.startswith("OPENAI_API_KEY"):
parts = line.split("=")[1:]
api_key = "=".join(parts).strip().strip('"')
break
if line.startswith("OPENAI_ORG_ID"):
parts = line.split("=")[1:]
org_id = "=".join(parts).strip().strip('"')
break
assert api_key is not None, "OpenAI API key not found in .env file"
# It's okay if the org ID is not found (not required)
return api_key, org_id
def azure_openai_settings_from_dot_env() -> Tuple[str, str]:
"""
Reads the Azure OpenAI API key and endpoint from the .env file.
Returns:
Tuple[str, str]: The Azure OpenAI API key, the endpoint
"""
api_key, endpoint = None, None
with open(".env", "r") as f:
lines = f.readlines()
for line in lines:
if line.startswith("AZURE_OPENAI_API_KEY"):
parts = line.split("=")[1:]
api_key = "=".join(parts).strip().strip('"')
break
if line.startswith("AZURE_OPENAI_ENDPOINT"):
parts = line.split("=")[1:]
endpoint = "=".join(parts).strip().strip('"')
break
# Azure requires both the API key and the endpoint URL.
assert api_key is not None, "Azure OpenAI API key not found in .env file"
assert endpoint is not None, "Azure OpenAI endpoint not found in .env file"
return api_key, endpoint