mirror of
https://github.com/microsoft/semantic-kernel.git
synced 2026-10-12 02:19:06 +00:00
Python: major features for the Kernel Arguments, Function Result and new Prompt Templating (#5077)
### Motivation and Context <!-- Thank you for your contribution to the semantic-kernel repo! Please help reviewers and future users, providing the following information: 1. Why is this change required? 2. What problem does it solve? 3. What scenario does it contribute to? 4. If it fixes an open issue, please link to the issue here. --> Major work to replace the context with Kernel Arguments on the front-end and Function Results on the back. Updated the function decorator to a new approach, in line with dotnet. Revamps the way function are called, allowing native functions to be completely ignorant of SK, other then the decorator. This also moves things into the new folder structure in sync with dotnet. ### Description <!-- Describe your changes, the overall approach, the underlying design. These notes will help understanding how your code works. Thanks! --> Adds: - KernelArguments, a dict-like class that replaces the variables in KernelContext. Closes #4565 - FunctionResult, a class to hold the results of function executions, includes the function, the value and metadata, as well as two convenient function to get the value out of it (str and get_inner_content) the first is generic, the second specifically for KernelContent responses (from AI services). - AI Service Selector class, has a default, which is based on the order in the arguments followed by the order in the functions, can be overridden to implement your own strategy. Closes #4631 - Introduces ChatHistory and refactors the PromptTemplateConfig. Closes #4856, #4630 - Improves parsing of templates, will now all validate during creation and throw an error then, instead of some that do not check for validaty until used. - Introduces named_args block and thereby the ability to have multiple arguments for a function call in a template. Closes #5003 Updates: - kernel_function decorators, the parameter decorator was removed and instead we now use Annotated to add a description of a field and we get the type and required from the function definition. - core plugins, use the new approach to kernel_function decorators. - planners, template engines have all been updated to use the kernel and kernelarguments instead of Context. - Events have been updated, now use kernelarguments and function_result - Tokenizers support for named_args and improvements on parsing and checking. - Kernel examples and notebooks to use the latest code. - All unit and integration tests. There is more code coverage now than before. Removed: - kernelContext - kernel_function_parameter_decorator - delegate handling code for native functions - file_io_plugin and tests - SemanticFunctionConfig - ChatPromptTemplate ### Contribution Checklist <!-- Before submitting this PR, please make sure: --> - [x] The code builds clean without any errors or warnings - [x] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [x] All unit tests pass, and I have added new tests where possible - [ ] I didn't break anyone 😄 --------- Co-authored-by: Evan Mattson <[email protected]> Co-authored-by: Evan Mattson <[email protected]> Co-authored-by: Evan Mattson <[email protected]>
This commit is contained in:
co-authored by
Evan Mattson
Evan Mattson
Evan Mattson
parent
885873343e
commit
5817c2b927
@@ -79,7 +79,10 @@ jobs:
|
||||
AzureOpenAI__DeploymentName: ${{ vars.AZUREOPENAI__DEPLOYMENTNAME }}
|
||||
AzureOpenAIChat__DeploymentName: ${{ vars.AZUREOPENAI__CHAT__DEPLOYMENTNAME }}
|
||||
AzureOpenAIEmbeddings__DeploymentName: ${{ vars.AZUREOPENAIEMBEDDINGS__DEPLOYMENTNAME2 }}
|
||||
AzureOpenAIEmbeddings_EastUS__DeploymentName: ${{ vars.AZUREOPENAIEMBEDDINGS_EASTUS__DEPLOYMENTNAME}}
|
||||
AzureOpenAI__Endpoint: ${{ secrets.AZUREOPENAI__ENDPOINT }}
|
||||
AzureOpenAI_EastUS__Endpoint: ${{ secrets.AZUREOPENAI_EASTUS__ENDPOINT }}
|
||||
AzureOpenAI_EastUS__ApiKey: ${{ secrets.AZUREOPENAI_EASTUS__APIKEY }}
|
||||
AzureOpenAIEmbeddings__Endpoint: ${{ secrets.AZUREOPENAI__ENDPOINT }}
|
||||
AzureOpenAI__ApiKey: ${{ secrets.AZUREOPENAI__APIKEY }}
|
||||
AzureOpenAIEmbeddings__ApiKey: ${{ secrets.AZUREOPENAI__APIKEY }}
|
||||
@@ -142,9 +145,12 @@ jobs:
|
||||
AzureOpenAI__DeploymentName: ${{ vars.AZUREOPENAI__DEPLOYMENTNAME }}
|
||||
AzureOpenAIChat__DeploymentName: ${{ vars.AZUREOPENAI__CHAT__DEPLOYMENTNAME }}
|
||||
AzureOpenAIEmbeddings__DeploymentName: ${{ vars.AZUREOPENAIEMBEDDINGS__DEPLOYMENTNAME2 }}
|
||||
AzureOpenAIEmbeddings_EastUS__DeploymentName: ${{ vars.AZUREOPENAIEMBEDDINGS_EASTUS__DEPLOYMENTNAME}}
|
||||
AzureOpenAI__Endpoint: ${{ secrets.AZUREOPENAI__ENDPOINT }}
|
||||
AzureOpenAIEmbeddings__Endpoint: ${{ secrets.AZUREOPENAI__ENDPOINT }}
|
||||
AzureOpenAI__ApiKey: ${{ secrets.AZUREOPENAI__APIKEY }}
|
||||
AzureOpenAI_EastUS__Endpoint: ${{ secrets.AZUREOPENAI_EASTUS__ENDPOINT }}
|
||||
AzureOpenAI_EastUS__ApiKey: ${{ secrets.AZUREOPENAI_EASTUS__APIKEY }}
|
||||
AzureOpenAIEmbeddings__ApiKey: ${{ secrets.AZUREOPENAI__APIKEY }}
|
||||
Bing__ApiKey: ${{ secrets.BING__APIKEY }}
|
||||
OpenAI__ApiKey: ${{ secrets.OPENAI__APIKEY }}
|
||||
|
||||
+4
-4
@@ -2,10 +2,10 @@
|
||||
source = semantic_kernel
|
||||
omit =
|
||||
semantic_kernel/connectors/memory/*
|
||||
semantic_kernel/connectors/openapi/*
|
||||
semantic_kernel/connectors/search_engine/*
|
||||
semantic_kernel/connectors/ai/google_palm/*
|
||||
semantic_kernel/connectors/ai/hugging_face/*
|
||||
semantic_kernel/utils/settings.py
|
||||
semantic_kernel/utils/null_logger.py
|
||||
semantic_kernel/utils/logging.py
|
||||
|
||||
|
||||
|
||||
[report]
|
||||
|
||||
Vendored
-5
@@ -19,11 +19,6 @@
|
||||
"python.testing.unittestEnabled": false,
|
||||
"python.testing.pytestEnabled": true,
|
||||
"pythonTestExplorer.testFramework": "pytest",
|
||||
"pythonTestExplorer.pytestPath": "poetry",
|
||||
"pythonTestExplorer.pytestArguments": [
|
||||
"run",
|
||||
"pytest"
|
||||
],
|
||||
"[python]": {
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": "explicit",
|
||||
|
||||
+49
-14
@@ -33,14 +33,34 @@ kernel = sk.Kernel()
|
||||
|
||||
# Prepare OpenAI service using credentials stored in the `.env` file
|
||||
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))
|
||||
service_id="chat-gpt"
|
||||
kernel.add_service(
|
||||
OpenAIChatCompletion(
|
||||
service_id=service_id,
|
||||
ai_model_id="gpt-3.5-turbo",
|
||||
api_key=api_key,
|
||||
org_id=org_id
|
||||
)
|
||||
)
|
||||
|
||||
# Alternative using Azure:
|
||||
# deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()
|
||||
# kernel.add_chat_service("dv", AzureChatCompletion(deployment, endpoint, api_key))
|
||||
# kernel.add_service(
|
||||
# AzureChatCompletion(
|
||||
# service_id="dv",
|
||||
# deployment_name=deployment,
|
||||
# base_url=endpoint,
|
||||
# api_key=api_key
|
||||
# )
|
||||
# )
|
||||
|
||||
# Wrap your prompt in a function
|
||||
prompt = kernel.create_semantic_function("""
|
||||
# Define the request settings
|
||||
req_settings = kernel.get_service(service_id).get_prompt_execution_settings_class()(service_id=service_id)
|
||||
req_settings.max_tokens = 2000
|
||||
req_settings.temperature = 0.7
|
||||
req_settings.top_p = 0.8
|
||||
|
||||
prompt = """
|
||||
1) A robot may not injure a human being or, through inaction,
|
||||
allow a human being to come to harm.
|
||||
|
||||
@@ -50,37 +70,52 @@ such orders would conflict with the First Law.
|
||||
3) A robot must protect its own existence as long as such protection
|
||||
does not conflict with the First or Second Law.
|
||||
|
||||
Give me the TLDR in exactly 5 words.""")
|
||||
Give me the TLDR in exactly 5 words."""
|
||||
|
||||
prompt_template_config = sk.PromptTemplateConfig(
|
||||
template=prompt,
|
||||
name="tldr",
|
||||
template_format="semantic-kernel",
|
||||
execution_settings=req_settings,
|
||||
)
|
||||
|
||||
function = kernel.create_function_from_prompt(
|
||||
prompt_template_config=prompt_template_config,
|
||||
)
|
||||
|
||||
# Run your prompt
|
||||
# Note: functions are run asynchronously
|
||||
async def main():
|
||||
print(await prompt()) # => Robots must not harm humans.
|
||||
result = await kernel.invoke(function)
|
||||
print(result) # => Robots must not harm humans.
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
# **Semantic functions** are Prompts with input parameters
|
||||
# **Semantic Prompt Functions** are Prompts with input parameters
|
||||
|
||||
```python
|
||||
# Create a reusable function with one input parameter
|
||||
summarize = kernel.create_semantic_function("{{$input}}\n\nOne line TLDR with the fewest words.")
|
||||
# Create a reusable function summarize function
|
||||
summarize = kernel.create_function_from_prompt(
|
||||
template="{{$input}}\n\nOne line TLDR with the fewest words."
|
||||
execution_settings=req_settings,
|
||||
)
|
||||
|
||||
# Summarize the laws of thermodynamics
|
||||
print(await summarize("""
|
||||
print(await kernel.invoke(summarize, input="""
|
||||
1st Law of Thermodynamics - Energy cannot be created or destroyed.
|
||||
2nd Law of Thermodynamics - For a spontaneous process, the entropy of the universe increases.
|
||||
3rd Law of Thermodynamics - A perfect crystal at zero Kelvin has zero entropy."""))
|
||||
|
||||
# Summarize the laws of motion
|
||||
print(await summarize("""
|
||||
print(await kernel.invoke(summarize, input="""
|
||||
1. An object at rest remains at rest, and an object in motion remains in motion at constant speed and in a straight line unless acted on by an unbalanced force.
|
||||
2. The acceleration of an object depends on the mass of the object and the amount of force applied.
|
||||
3. Whenever one object exerts a force on another object, the second object exerts an equal and opposite on the first."""))
|
||||
|
||||
# Summarize the law of universal gravitation
|
||||
print(await summarize("""
|
||||
print(await kernel.invoke(summarize, input="""
|
||||
Every point mass attracts every single other point mass by a force acting along the line intersecting both points.
|
||||
The force is proportional to the product of the two masses and inversely proportional to the square of the distance between them."""))
|
||||
|
||||
@@ -100,8 +135,8 @@ Python notebooks:
|
||||
- [Getting started with Semantic Kernel](./notebooks/00-getting-started.ipynb)
|
||||
- [Loading and configuring Semantic Kernel](./notebooks/01-basic-loading-the-kernel.ipynb)
|
||||
- [Running AI prompts from file](./notebooks/02-running-prompts-from-file.ipynb)
|
||||
- [Creating Semantic Functions at runtime (i.e. inline functions)](./notebooks/03-semantic-function-inline.ipynb)
|
||||
- [Using Context Variables to Build a Chat Experience](./notebooks/04-context-variables-chat.ipynb)
|
||||
- [Creating Prompt Functions at runtime (i.e. inline functions)](./notebooks/03-prompt-function-inline.ipynb)
|
||||
- [Using Context Variables to Build a Chat Experience](./notebooks/04-kernel-arguments-chat.ipynb)
|
||||
- [Introduction to planners](./notebooks/05-using-the-planner.ipynb)
|
||||
- [Building Memory with Embeddings](./notebooks/06-memory-and-embeddings.ipynb)
|
||||
- [Using Hugging Face for Plugins](./notebooks/07-hugging-face-for-plugins.ipynb)
|
||||
|
||||
@@ -30,6 +30,25 @@
|
||||
"kernel = sk.Kernel()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Configure the service you'd like to use via the `Service` Enum."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from services import Service\n",
|
||||
"\n",
|
||||
"# Select a service to use for this notebook (available services: OpenAI, AzureOpenAI, HuggingFace)\n",
|
||||
"selectedService = Service.OpenAI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
@@ -44,30 +63,8 @@
|
||||
"OPENAI_ORG_ID=\"\"\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Use \"keyword arguments\" to instantiate an OpenAI Chat Completion service and add it to the kernel:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion\n",
|
||||
"Use \"keyword arguments\" to instantiate an OpenAI Chat Completion service and add it to the kernel:\n",
|
||||
"\n",
|
||||
"api_key, org_id = sk.openai_settings_from_dot_env()\n",
|
||||
"\n",
|
||||
"kernel.add_chat_service(\n",
|
||||
" \"chat-gpt\",\n",
|
||||
" OpenAIChatCompletion(ai_model_id=\"gpt-3.5-turbo-1106\", api_key=api_key, org_id=org_id),\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Option 2: using Azure OpenAI\n",
|
||||
"\n",
|
||||
"**Step 2**: Add your [Azure Open AI Service key](https://learn.microsoft.com/azure/cognitive-services/openai/quickstart?pivots=programming-language-studio) settings to a `.env` file in the same folder:\n",
|
||||
@@ -87,14 +84,23 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion\n",
|
||||
"service_id = None\n",
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion\n",
|
||||
"\n",
|
||||
"deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
|
||||
" api_key, org_id = sk.openai_settings_from_dot_env()\n",
|
||||
" service_id = \"chat-gpt\"\n",
|
||||
" kernel.add_service(\n",
|
||||
" OpenAIChatCompletion(service_id=service_id, ai_model_id=\"gpt-3.5-turbo-1106\", api_key=api_key, org_id=org_id),\n",
|
||||
" )\n",
|
||||
"elif selectedService == Service.AzureOpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion\n",
|
||||
"\n",
|
||||
"kernel.add_chat_service(\n",
|
||||
" \"chat_completion\",\n",
|
||||
" AzureChatCompletion(deployment_name=deployment, endpoint=endpoint, api_key=api_key),\n",
|
||||
")"
|
||||
" deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
|
||||
" service_id = \"chat_completion\"\n",
|
||||
" kernel.add_service(\n",
|
||||
" AzureChatCompletion(service_id=service_id, deployment_name=deployment, endpoint=endpoint, api_key=api_key),\n",
|
||||
" )"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -113,10 +119,27 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"plugin = kernel.import_semantic_plugin_from_directory(\"../../samples/plugins\", \"FunPlugin\")\n",
|
||||
"try:\n",
|
||||
" plugin = kernel.import_plugin_from_prompt_directory(service_id, \"../../samples/plugins\", \"FunPlugin\")\n",
|
||||
"except ValueError as e:\n",
|
||||
" # Don't fail if we try to add the plug in again\n",
|
||||
" # This is just for the sake of the example\n",
|
||||
" # Once the plugin has been added to the kernel it will fail\n",
|
||||
" # to add it again, if this cell is run multiple times without\n",
|
||||
" # restarting the kernel\n",
|
||||
" pass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"joke_function = plugin[\"Joke\"]\n",
|
||||
"\n",
|
||||
"print(await joke_function(\"time travel to dinosaur age\"))"
|
||||
"joke = await kernel.invoke(joke_function, sk.KernelArguments(input=\"time travel to dinosaur age\", style=\"super silly\"))\n",
|
||||
"print(joke)"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
@@ -34,29 +34,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import semantic_kernel as sk\n",
|
||||
"from semantic_kernel.connectors.ai.open_ai import (\n",
|
||||
" AzureChatCompletion,\n",
|
||||
" OpenAIChatCompletion,\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"You can instantiate the kernel in a few ways, depending on your use case."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Simple instance\n",
|
||||
"kernel_1 = sk.Kernel()"
|
||||
"import semantic_kernel as sk"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -66,7 +44,7 @@
|
||||
"source": [
|
||||
"When using the kernel for AI requests, the kernel needs some settings like URL and credentials to the AI models.\n",
|
||||
"\n",
|
||||
"The SDK currently supports OpenAI and Azure OpenAI, other services will be added over time.\n",
|
||||
"The SDK currently supports OpenAI and Azure OpenAI, among other connectors.\n",
|
||||
"\n",
|
||||
"If you need an Azure OpenAI key, go [here](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/quickstart?pivots=rest-api)."
|
||||
]
|
||||
@@ -77,39 +55,10 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"kernel = sk.Kernel()\n",
|
||||
"from services import Service\n",
|
||||
"\n",
|
||||
"kernel.add_chat_service( # We are adding a text service\n",
|
||||
" \"Azure_curie\", # The alias we can use in prompt templates' config.json\n",
|
||||
" AzureChatCompletion(\n",
|
||||
" deployment_name=\"my-finetuned-Curie\", # Azure OpenAI *Deployment name*\n",
|
||||
" endpoint=\"https://contoso.openai.azure.com/\", # Azure OpenAI *Endpoint*\n",
|
||||
" api_key=\"...your Azure OpenAI Key...\", # Azure OpenAI *Key*\n",
|
||||
" ),\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"kernel.add_chat_service( # We are adding a text service\n",
|
||||
" \"OpenAI_chat_gpt\", # The alias we can use in prompt templates' config.json\n",
|
||||
" OpenAIChatCompletion(\n",
|
||||
" ai_model_id=\"gpt-3.5-turbo\", # OpenAI Model Name\n",
|
||||
" api_key=\"...your OpenAI API Key...\", # OpenAI API key\n",
|
||||
" org_id=\"...your OpenAI Org ID...\", # *optional* OpenAI Organization ID\n",
|
||||
" ),\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"When working with multiple services and multiple models, the **first service** defined\n",
|
||||
"is also the \"**default**\" used in these scenarios:\n",
|
||||
"\n",
|
||||
"* a prompt configuration doesn't specify which AI service to use\n",
|
||||
"* a prompt configuration requires a service unknown to the kernel\n",
|
||||
"\n",
|
||||
"The default can be set and changed programmatically:"
|
||||
"# Select a service to use for this notebook (available services: OpenAI, AzureOpenAI, HuggingFace)\n",
|
||||
"selectedService = Service.OpenAI"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -118,7 +67,25 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"kernel.set_default_text_completion_service(\"Azure_curie\")"
|
||||
"kernel = sk.Kernel()\n",
|
||||
"\n",
|
||||
"service_id = None\n",
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion\n",
|
||||
"\n",
|
||||
" api_key, org_id = sk.openai_settings_from_dot_env()\n",
|
||||
" service_id = \"oai_chat_gpt\"\n",
|
||||
" kernel.add_service(\n",
|
||||
" OpenAIChatCompletion(service_id=service_id, ai_model_id=\"gpt-3.5-turbo-1106\", api_key=api_key, org_id=org_id),\n",
|
||||
" )\n",
|
||||
"elif selectedService == Service.AzureOpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion\n",
|
||||
"\n",
|
||||
" deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
|
||||
" service_id = \"aoai_chat_completion\"\n",
|
||||
" kernel.add_service(\n",
|
||||
" AzureChatCompletion(service_id=service_id, deployment_name=deployment, endpoint=endpoint, api_key=api_key),\n",
|
||||
" )"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
"id": "692e361b",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# How to run a semantic plugins from file\n",
|
||||
"Now that you're familiar with Kernel basics, let's see how the kernel allows you to run Semantic Plugins and Semantic Functions stored on disk. \n",
|
||||
"# How to run a prompt plugins from file\n",
|
||||
"Now that you're familiar with Kernel basics, let's see how the kernel allows you to run Prompt Plugins and Prompt Functions stored on disk. \n",
|
||||
"\n",
|
||||
"A Semantic Plugin is a collection of Semantic Functions, where each function is defined with natural language that can be provided with a text file. \n",
|
||||
"A Prompt Plugin is a collection of Semantic Functions, where each function is defined with natural language that can be provided with a text file. \n",
|
||||
"\n",
|
||||
"Refer to our [glossary](https://github.com/microsoft/semantic-kernel/blob/main/docs/GLOSSARY.md) for an in-depth guide to the terms.\n",
|
||||
"\n",
|
||||
@@ -60,14 +60,30 @@
|
||||
"```\n",
|
||||
"{\n",
|
||||
" \"schema\": 1,\n",
|
||||
" \"type\": \"completion\",\n",
|
||||
" \"description\": \"Generate a funny joke\",\n",
|
||||
" \"completion\": {\n",
|
||||
" \"max_tokens\": 500,\n",
|
||||
" \"temperature\": 0.5,\n",
|
||||
" \"top_p\": 0.5\n",
|
||||
" }\n",
|
||||
" \"execution_settings\": {\n",
|
||||
" \"default\": {\n",
|
||||
" \"max_tokens\": 1000,\n",
|
||||
" \"temperature\": 0.9,\n",
|
||||
" \"top_p\": 0.0,\n",
|
||||
" \"presence_penalty\": 0.0,\n",
|
||||
" \"frequency_penalty\": 0.0\n",
|
||||
" }\n",
|
||||
" },\n",
|
||||
" \"input_variables\": [\n",
|
||||
" {\n",
|
||||
" \"name\": \"input\",\n",
|
||||
" \"description\": \"Joke subject\",\n",
|
||||
" \"default\": \"\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"name\": \"style\",\n",
|
||||
" \"description\": \"Give a hint about the desired joke style\",\n",
|
||||
" \"default\": \"\"\n",
|
||||
" }\n",
|
||||
" ]\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
@@ -77,7 +93,7 @@
|
||||
"id": "384ff07f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Given a semantic function defined by these files, this is how to load and use a file based semantic function.\n",
|
||||
"Given a prompt function defined by these files, this is how to load and use a file based prompt function.\n",
|
||||
"\n",
|
||||
"Load and configure the kernel, as usual, loading also the AI service settings defined in the [Setup notebook](00-getting-started.ipynb):"
|
||||
]
|
||||
@@ -92,6 +108,19 @@
|
||||
"!python -m pip install semantic-kernel==0.5.1.dev0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "fdb865a7",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from services import Service\n",
|
||||
"\n",
|
||||
"# Select a service to use for this notebook (available services: OpenAI, AzureOpenAI, HuggingFace)\n",
|
||||
"selectedService = Service.OpenAI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -100,26 +129,26 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import semantic_kernel as sk\n",
|
||||
"from semantic_kernel.connectors.ai.open_ai import (\n",
|
||||
" AzureChatCompletion,\n",
|
||||
" OpenAIChatCompletion,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"kernel = sk.Kernel()\n",
|
||||
"\n",
|
||||
"useAzureOpenAI = False\n",
|
||||
"service_id = None\n",
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion\n",
|
||||
"\n",
|
||||
"# Configure AI service used by the kernel\n",
|
||||
"if useAzureOpenAI:\n",
|
||||
" deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
|
||||
" azure_chat_service = AzureChatCompletion(\n",
|
||||
" deployment_name=\"turbo\", endpoint=endpoint, api_key=api_key\n",
|
||||
" ) # set the deployment name to the value of your chat model\n",
|
||||
" kernel.add_chat_service(\"chat_completion\", azure_chat_service)\n",
|
||||
"else:\n",
|
||||
" api_key, org_id = sk.openai_settings_from_dot_env()\n",
|
||||
" oai_chat_service = OpenAIChatCompletion(ai_model_id=\"gpt-3.5-turbo\", api_key=api_key, org_id=org_id)\n",
|
||||
" kernel.add_chat_service(\"chat-gpt\", oai_chat_service)"
|
||||
" service_id = \"oai_chat_gpt\"\n",
|
||||
" kernel.add_service(\n",
|
||||
" OpenAIChatCompletion(service_id=service_id, ai_model_id=\"gpt-3.5-turbo-1106\", api_key=api_key, org_id=org_id),\n",
|
||||
" )\n",
|
||||
"elif selectedService == Service.AzureOpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion\n",
|
||||
"\n",
|
||||
" deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
|
||||
" service_id = \"aoai_chat_completion\"\n",
|
||||
" kernel.add_service(\n",
|
||||
" AzureChatCompletion(service_id=service_id, deployment_name=deployment, endpoint=endpoint, api_key=api_key),\n",
|
||||
" )"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -141,7 +170,7 @@
|
||||
"# note: using plugins from the samples folder\n",
|
||||
"plugins_directory = \"../../samples/plugins\"\n",
|
||||
"\n",
|
||||
"funFunctions = kernel.import_semantic_plugin_from_directory(plugins_directory, \"FunPlugin\")\n",
|
||||
"funFunctions = kernel.import_plugin_from_prompt_directory(service_id, plugins_directory, \"FunPlugin\")\n",
|
||||
"\n",
|
||||
"jokeFunction = funFunctions[\"Joke\"]"
|
||||
]
|
||||
@@ -162,7 +191,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"result = await jokeFunction.invoke(\"travel to dinosaur age\")\n",
|
||||
"result = await kernel.invoke(jokeFunction, sk.KernelArguments(input=\"travel to dinosaur age\", style=\"silly\"))\n",
|
||||
"print(result)"
|
||||
]
|
||||
},
|
||||
@@ -172,7 +201,7 @@
|
||||
"id": "2281a1fc",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Great, now that you know how to load a plugin from disk, let's show how you can [create and run a semantic function inline.](./03-semantic-function-inline.ipynb)"
|
||||
"Great, now that you know how to load a plugin from disk, let's show how you can [create and run a prompt function inline.](./03-prompt-function-inline.ipynb)"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -192,7 +221,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.7"
|
||||
"version": "3.10.12"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
+106
-48
@@ -6,16 +6,9 @@
|
||||
"id": "3c93ac5b",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Running Semantic Functions Inline"
|
||||
"# Running Prompt Functions Inline"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "ebcabb91",
|
||||
"metadata": {},
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
@@ -58,6 +51,19 @@
|
||||
"!python -m pip install semantic-kernel==0.5.1.dev0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "68b770df",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from services import Service\n",
|
||||
"\n",
|
||||
"# Select a service to use for this notebook (available services: OpenAI, AzureOpenAI, HuggingFace)\n",
|
||||
"selectedService = Service.OpenAI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -66,26 +72,30 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import semantic_kernel as sk\n",
|
||||
"from semantic_kernel.connectors.ai.open_ai import (\n",
|
||||
" AzureTextCompletion,\n",
|
||||
" OpenAITextCompletion,\n",
|
||||
")\n",
|
||||
"import semantic_kernel.connectors.ai.open_ai as sk_oai\n",
|
||||
"from semantic_kernel.prompt_template.input_variable import InputVariable\n",
|
||||
"\n",
|
||||
"kernel = sk.Kernel()\n",
|
||||
"\n",
|
||||
"useAzureOpenAI = False\n",
|
||||
"service_id = None\n",
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import OpenAITextCompletion\n",
|
||||
"\n",
|
||||
"# Configure AI service used by the kernel\n",
|
||||
"if useAzureOpenAI:\n",
|
||||
" deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
|
||||
" azure_text_service = AzureTextCompletion(\n",
|
||||
" deployment_name=\"text\", endpoint=endpoint, api_key=api_key\n",
|
||||
" ) # set the deployment name to the value of your text model\n",
|
||||
" kernel.add_text_completion_service(\"dv\", azure_text_service)\n",
|
||||
"else:\n",
|
||||
" api_key, org_id = sk.openai_settings_from_dot_env()\n",
|
||||
" oai_text_service = OpenAITextCompletion(ai_model_id=\"gpt-3.5-turbo-instruct\", api_key=api_key, org_id=org_id)\n",
|
||||
" kernel.add_text_completion_service(\"dv\", oai_text_service)"
|
||||
" service_id = \"oai_text_completion\"\n",
|
||||
" kernel.add_service(\n",
|
||||
" OpenAITextCompletion(\n",
|
||||
" service_id=service_id, ai_model_id=\"gpt-3.5-turbo-instruct\", api_key=api_key, org_id=org_id\n",
|
||||
" ),\n",
|
||||
" )\n",
|
||||
"elif selectedService == Service.AzureOpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import AzureTextCompletion\n",
|
||||
"\n",
|
||||
" deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
|
||||
" service_id = \"aoai_text_completion\"\n",
|
||||
" kernel.add_service(\n",
|
||||
" AzureTextCompletion(service_id=service_id, deployment_name=deployment, endpoint=endpoint, api_key=api_key),\n",
|
||||
" )"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -110,7 +120,32 @@
|
||||
"Summarize the content above.\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"summarize = kernel.create_semantic_function(prompt_template=prompt, max_tokens=2000, temperature=0.2, top_p=0.5)"
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" execution_settings = sk_oai.OpenAITextPromptExecutionSettings(\n",
|
||||
" service_id=service_id,\n",
|
||||
" ai_model_id=\"gpt-3.5-turbo-instruct\",\n",
|
||||
" max_tokens=2000,\n",
|
||||
" temperature=0.7,\n",
|
||||
" )\n",
|
||||
"elif selectedService == Service.AzureOpenAI:\n",
|
||||
" execution_settings = sk_oai.OpenAITextPromptExecutionSettings(\n",
|
||||
" service_id=service_id,\n",
|
||||
" ai_model_id=deployment,\n",
|
||||
" max_tokens=2000,\n",
|
||||
" temperature=0.7,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"prompt_template_config = sk.PromptTemplateConfig(\n",
|
||||
" template=prompt,\n",
|
||||
" name=\"summarize\",\n",
|
||||
" template_format=\"semantic-kernel\",\n",
|
||||
" input_variables=[\n",
|
||||
" InputVariable(name=\"input\", description=\"The user input\", is_required=True),\n",
|
||||
" ],\n",
|
||||
" execution_settings=execution_settings,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"summarize = kernel.create_function_from_prompt(prompt_template_config=prompt_template_config)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -158,7 +193,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"summary = await summarize(input_text)\n",
|
||||
"summary = await kernel.invoke(summarize, sk.KernelArguments(input=input_text))\n",
|
||||
"\n",
|
||||
"print(summary)"
|
||||
]
|
||||
@@ -178,7 +213,7 @@
|
||||
"id": "29b59b28",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"You can also use chat completion models (like `gpt-35-turbo` and `gpt4`) for creating plugins. Normally you would have to tweak the API to accommodate for a system and user role, but SK abstracts that away for you by using `kernel.add_chat_service` and `AzureChatCompletion` or `OpenAIChatCompletion`"
|
||||
"You can also use chat completion models (like `gpt-35-turbo` and `gpt4`) for creating plugins. Normally you would have to tweak the API to accommodate for a system and user role, but SK abstracts that away for you by using `kernel.add_service` and `AzureChatCompletion` or `OpenAIChatCompletion`"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -199,27 +234,25 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import semantic_kernel as sk\n",
|
||||
"from semantic_kernel.connectors.ai.open_ai import (\n",
|
||||
" AzureChatCompletion,\n",
|
||||
" OpenAIChatCompletion,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"kernel = sk.Kernel()\n",
|
||||
"\n",
|
||||
"useAzureOpenAI = False\n",
|
||||
"service_id = None\n",
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion\n",
|
||||
"\n",
|
||||
"# Configure AI service used by the kernel\n",
|
||||
"if useAzureOpenAI:\n",
|
||||
" deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
|
||||
" azure_chat_service = AzureChatCompletion(\n",
|
||||
" deployment_name=\"turbo\", endpoint=endpoint, api_key=api_key\n",
|
||||
" ) # set the deployment name to the value of your chat model\n",
|
||||
" kernel.add_chat_service(\"chat_completion\", azure_chat_service)\n",
|
||||
"else:\n",
|
||||
" api_key, org_id = sk.openai_settings_from_dot_env()\n",
|
||||
" oai_chat_service = OpenAIChatCompletion(ai_model_id=\"gpt-3.5-turbo\", api_key=api_key, org_id=org_id)\n",
|
||||
" kernel.add_chat_service(\"chat-gpt\", oai_chat_service)"
|
||||
" service_id = \"oai_chat_gpt\"\n",
|
||||
" kernel.add_service(\n",
|
||||
" OpenAIChatCompletion(service_id=service_id, ai_model_id=\"gpt-3.5-turbo-1106\", api_key=api_key, org_id=org_id),\n",
|
||||
" )\n",
|
||||
"elif selectedService == Service.AzureOpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion\n",
|
||||
"\n",
|
||||
" deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
|
||||
" service_id = \"aoai_chat_completion\"\n",
|
||||
" kernel.add_service(\n",
|
||||
" AzureChatCompletion(service_id=service_id, deployment_name=deployment, endpoint=endpoint, api_key=api_key),\n",
|
||||
" )"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -229,7 +262,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sk_prompt = \"\"\"\n",
|
||||
"prompt = \"\"\"\n",
|
||||
"{{$input}}\n",
|
||||
"\n",
|
||||
"Give me the TLDR in 5 words or less.\n",
|
||||
@@ -246,11 +279,36 @@
|
||||
" does not conflict with the First or Second Law.\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"tldr_function = kernel.create_semantic_function(prompt_template=sk_prompt, max_tokens=200, temperature=0, top_p=0.5)\n",
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" execution_settings = sk_oai.OpenAIChatPromptExecutionSettings(\n",
|
||||
" service_id=service_id,\n",
|
||||
" ai_model_id=\"gpt-3.5-turbo-1106\",\n",
|
||||
" max_tokens=2000,\n",
|
||||
" temperature=0.7,\n",
|
||||
" )\n",
|
||||
"elif selectedService == Service.AzureOpenAI:\n",
|
||||
" execution_settings = sk_oai.OpenAIChatPromptExecutionSettings(\n",
|
||||
" service_id=service_id,\n",
|
||||
" ai_model_id=deployment,\n",
|
||||
" max_tokens=2000,\n",
|
||||
" temperature=0.7,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"summary = await tldr_function(text)\n",
|
||||
"prompt_template_config = sk.PromptTemplateConfig(\n",
|
||||
" template=prompt,\n",
|
||||
" name=\"tldr\",\n",
|
||||
" template_format=\"semantic-kernel\",\n",
|
||||
" input_variables=[\n",
|
||||
" InputVariable(name=\"input\", description=\"The user input\", is_required=True),\n",
|
||||
" ],\n",
|
||||
" execution_settings=execution_settings,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(f\"Output: {summary}\") # Output: Robots must not harm humans."
|
||||
"tldr_function = kernel.create_function_from_prompt(prompt_template_config=prompt_template_config)\n",
|
||||
"\n",
|
||||
"summary = await kernel.invoke(tldr_function, sk.KernelArguments(input=text))\n",
|
||||
"\n",
|
||||
"print(f\"Output: {summary}\")"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -270,7 +328,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.7"
|
||||
"version": "3.10.12"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
+86
-44
@@ -6,17 +6,17 @@
|
||||
"id": "fde98ddf",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Creating a basic chat experience with context variables\n",
|
||||
"# Creating a basic chat experience with kernel arguments\n",
|
||||
"\n",
|
||||
"In this example, we show how you can build a simple chat bot by sending and updating context with your requests. \n",
|
||||
"In this example, we show how you can build a simple chat bot by sending and updating the kernel arguments with your requests. \n",
|
||||
"\n",
|
||||
"We introduce the Context Variables object which in this demo functions similarly as a key-value store that you can use when running the kernel.\n",
|
||||
"We introduce the Kernel Arguments object which in this demo functions similarly as a key-value store that you can use when running the kernel.\n",
|
||||
"\n",
|
||||
"The context is local (i.e. in your computer's RAM) and not persisted anywhere beyond the life of this Jupyter session.\n",
|
||||
"The chat history is local (i.e. in your computer's RAM) and not persisted anywhere beyond the life of this Jupyter session.\n",
|
||||
"\n",
|
||||
"In future examples, we will show how to persist the context on disk so that you can bring it into your applications. \n",
|
||||
"In future examples, we will show how to persist the chat history on disk so that you can bring it into your applications. \n",
|
||||
"\n",
|
||||
"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. "
|
||||
"In this chat scenario, as the user talks back and forth with the bot, the chat context gets populated with the history of the conversation. During each new run of the kernel, the kernel arguments and chat history can provide the AI with its variables' content. "
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -29,6 +29,19 @@
|
||||
"!python -m pip install semantic-kernel==0.5.1.dev0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "0a235b31",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from services import Service\n",
|
||||
"\n",
|
||||
"# Select a service to use for this notebook (available services: OpenAI, AzureOpenAI, HuggingFace)\n",
|
||||
"selectedService = Service.OpenAI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -37,27 +50,29 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import semantic_kernel as sk\n",
|
||||
"from semantic_kernel.connectors.ai.open_ai import (\n",
|
||||
" AzureChatCompletion,\n",
|
||||
" OpenAIChatCompletion,\n",
|
||||
")\n",
|
||||
"import semantic_kernel.connectors.ai.open_ai as sk_oai\n",
|
||||
"from semantic_kernel.prompt_template.input_variable import InputVariable\n",
|
||||
"from semantic_kernel.contents.chat_history import ChatHistory\n",
|
||||
"from semantic_kernel.functions.kernel_arguments import KernelArguments\n",
|
||||
"\n",
|
||||
"kernel = sk.Kernel()\n",
|
||||
"\n",
|
||||
"useAzureOpenAI = False\n",
|
||||
"service_id = None\n",
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion\n",
|
||||
"\n",
|
||||
"# Configure AI service used by the kernel\n",
|
||||
"if useAzureOpenAI:\n",
|
||||
" deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
|
||||
" kernel.add_chat_service(\n",
|
||||
" \"chat_completion\",\n",
|
||||
" AzureChatCompletion(deployment_name=deployment, endpoint=endpoint, api_key=api_key),\n",
|
||||
" )\n",
|
||||
"else:\n",
|
||||
" api_key, org_id = sk.openai_settings_from_dot_env()\n",
|
||||
" kernel.add_chat_service(\n",
|
||||
" \"gpt-3.5\",\n",
|
||||
" OpenAIChatCompletion(ai_model_id=\"gpt-3.5-turbo\", api_key=api_key, org_id=org_id),\n",
|
||||
" service_id = \"oai_chat_gpt\"\n",
|
||||
" kernel.add_service(\n",
|
||||
" OpenAIChatCompletion(service_id=service_id, ai_model_id=\"gpt-3.5-turbo-1106\", api_key=api_key, org_id=org_id),\n",
|
||||
" )\n",
|
||||
"elif selectedService == Service.AzureOpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion\n",
|
||||
"\n",
|
||||
" deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
|
||||
" service_id = \"aoai_chat_completion\"\n",
|
||||
" kernel.add_service(\n",
|
||||
" AzureChatCompletion(service_id=service_id, deployment_name=deployment, endpoint=endpoint, api_key=api_key),\n",
|
||||
" )"
|
||||
]
|
||||
},
|
||||
@@ -77,7 +92,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sk_prompt = \"\"\"\n",
|
||||
"prompt = \"\"\"\n",
|
||||
"ChatBot can have a conversation with you about any topic.\n",
|
||||
"It can give explicit instructions or say 'I don't know' if it does not have an answer.\n",
|
||||
"\n",
|
||||
@@ -102,13 +117,44 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"chat_function = kernel.create_semantic_function(\n",
|
||||
" prompt_template=sk_prompt,\n",
|
||||
" function_name=\"ChatBot\",\n",
|
||||
" max_tokens=2000,\n",
|
||||
" temperature=0.7,\n",
|
||||
" top_p=0.5,\n",
|
||||
")"
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" execution_settings = sk_oai.OpenAIChatPromptExecutionSettings(\n",
|
||||
" service_id=service_id,\n",
|
||||
" ai_model_id=\"gpt-3.5-turbo-1106\",\n",
|
||||
" max_tokens=2000,\n",
|
||||
" temperature=0.7,\n",
|
||||
" )\n",
|
||||
"elif selectedService == Service.AzureOpenAI:\n",
|
||||
" execution_settings = sk_oai.OpenAIChatPromptExecutionSettings(\n",
|
||||
" service_id=service_id,\n",
|
||||
" ai_model_id=deployment,\n",
|
||||
" max_tokens=2000,\n",
|
||||
" temperature=0.7,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"prompt_template_config = sk.PromptTemplateConfig(\n",
|
||||
" template=prompt,\n",
|
||||
" name=\"chat\",\n",
|
||||
" template_format=\"semantic-kernel\",\n",
|
||||
" input_variables=[\n",
|
||||
" InputVariable(name=\"input\", description=\"The user input\", is_required=True),\n",
|
||||
" InputVariable(name=\"history\", description=\"The conversation history\", is_required=True),\n",
|
||||
" ],\n",
|
||||
" execution_settings=execution_settings,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"chat_function = kernel.create_function_from_prompt(prompt_template_config=prompt_template_config)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6a0f7c01",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"chat_history = ChatHistory()\n",
|
||||
"chat_history.add_system_message(\"You are a helpful chatbot who is good about giving book recommendations.\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -117,7 +163,7 @@
|
||||
"id": "6e8a676f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Initialize your context"
|
||||
"Initialize the Kernel Arguments"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -127,8 +173,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"context = kernel.create_new_context()\n",
|
||||
"context[\"history\"] = \"\""
|
||||
"arguments = KernelArguments(user_input=\"Hi, I'm looking for book suggestions\", history=chat_history)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -147,9 +192,8 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"context[\"user_input\"] = \"Hi, I'm looking for book suggestions\"\n",
|
||||
"bot_answer = await chat_function.invoke(context=context)\n",
|
||||
"print(bot_answer)"
|
||||
"response = await kernel.invoke(chat_function, arguments)\n",
|
||||
"print(response)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -168,8 +212,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"context[\"history\"] += f\"\\nUser: {context['user_input']}\\nChatBot: {bot_answer}\\n\"\n",
|
||||
"print(context[\"history\"])"
|
||||
"chat_history.add_assistant_message(str(response))"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -191,16 +234,15 @@
|
||||
"async def chat(input_text: str) -> None:\n",
|
||||
" # Save new message in the context variables\n",
|
||||
" print(f\"User: {input_text}\")\n",
|
||||
" context[\"user_input\"] = input_text\n",
|
||||
" chat_history.add_user_message(input_text)\n",
|
||||
"\n",
|
||||
" # Process the user message and get an answer\n",
|
||||
" answer = await chat_function.invoke(context=context)\n",
|
||||
" answer = await kernel.invoke(chat_function, KernelArguments(user_input=input_text, history=chat_history))\n",
|
||||
"\n",
|
||||
" # Show the response\n",
|
||||
" print(f\"ChatBot: {answer}\")\n",
|
||||
"\n",
|
||||
" # Append the new interaction to the chat history\n",
|
||||
" context[\"history\"] += f\"\\nUser: {input_text}\\nChatBot: {answer}\\n\""
|
||||
" chat_history.add_assistant_message(str(answer))"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -259,7 +301,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(context[\"history\"])"
|
||||
"print(chat_history)"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -279,7 +321,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.7"
|
||||
"version": "3.10.12"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
@@ -26,6 +26,31 @@
|
||||
"!python -m pip install semantic-kernel==0.5.1.dev0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "7d548e40",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from services import Service\n",
|
||||
"\n",
|
||||
"# Select a service to use for this notebook (available services: OpenAI, AzureOpenAI, HuggingFace)\n",
|
||||
"selectedService = Service.OpenAI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3852961c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantic_kernel.prompt_template.input_variable import InputVariable\n",
|
||||
"from semantic_kernel.contents.chat_history import ChatHistory\n",
|
||||
"from semantic_kernel.functions.kernel_arguments import KernelArguments"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -34,27 +59,26 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import semantic_kernel as sk\n",
|
||||
"from semantic_kernel.connectors.ai.open_ai import (\n",
|
||||
" OpenAIChatCompletion,\n",
|
||||
" AzureChatCompletion,\n",
|
||||
")\n",
|
||||
"import semantic_kernel.connectors.ai.open_ai as sk_oai\n",
|
||||
"\n",
|
||||
"kernel = sk.Kernel()\n",
|
||||
"\n",
|
||||
"useAzureOpenAI = True\n",
|
||||
"service_id = None\n",
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion\n",
|
||||
"\n",
|
||||
"# Configure AI backend used by the kernel\n",
|
||||
"if useAzureOpenAI:\n",
|
||||
" deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
|
||||
" kernel.add_chat_service(\n",
|
||||
" \"chat_completion\",\n",
|
||||
" AzureChatCompletion(deployment_name=deployment, endpoint=endpoint, api_key=api_key),\n",
|
||||
" )\n",
|
||||
"else:\n",
|
||||
" api_key, org_id = sk.openai_settings_from_dot_env()\n",
|
||||
" kernel.add_chat_service(\n",
|
||||
" \"gpt-4\",\n",
|
||||
" OpenAIChatCompletion(ai_model_id=\"gpt-3.5-turbo-1106\", api_key=api_key, org_id=org_id),\n",
|
||||
" service_id = \"oai_chat_gpt\"\n",
|
||||
" kernel.add_service(\n",
|
||||
" OpenAIChatCompletion(service_id=service_id, ai_model_id=\"gpt-3.5-turbo-1106\", api_key=api_key, org_id=org_id),\n",
|
||||
" )\n",
|
||||
"elif selectedService == Service.AzureOpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion\n",
|
||||
"\n",
|
||||
" deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
|
||||
" service_id = \"aoai_chat_completion\"\n",
|
||||
" kernel.add_service(\n",
|
||||
" AzureChatCompletion(service_id=service_id, deployment_name=deployment, endpoint=endpoint, api_key=api_key),\n",
|
||||
" )"
|
||||
]
|
||||
},
|
||||
@@ -100,8 +124,8 @@
|
||||
"from semantic_kernel.core_plugins.text_plugin import TextPlugin\n",
|
||||
"\n",
|
||||
"plugins_directory = \"../../samples/plugins/\"\n",
|
||||
"summarize_plugin = kernel.import_semantic_plugin_from_directory(plugins_directory, \"SummarizePlugin\")\n",
|
||||
"writer_plugin = kernel.import_semantic_plugin_from_directory(plugins_directory, \"WriterPlugin\")\n",
|
||||
"summarize_plugin = kernel.import_plugin_from_prompt_directory(service_id, plugins_directory, \"SummarizePlugin\")\n",
|
||||
"writer_plugin = kernel.import_plugin_from_prompt_directory(service_id, plugins_directory, \"WriterPlugin\")\n",
|
||||
"text_plugin = kernel.import_plugin(TextPlugin(), \"TextPlugin\")"
|
||||
]
|
||||
},
|
||||
@@ -136,9 +160,9 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantic_kernel.planning.basic_planner import BasicPlanner\n",
|
||||
"from semantic_kernel.planners.basic_planner import BasicPlanner\n",
|
||||
"\n",
|
||||
"planner = BasicPlanner()"
|
||||
"planner = BasicPlanner(service_id)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -186,18 +210,31 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sk_prompt = \"\"\"\n",
|
||||
"prompt = \"\"\"\n",
|
||||
"{{$input}}\n",
|
||||
"\n",
|
||||
"Rewrite the above in the style of Shakespeare.\n",
|
||||
"\"\"\"\n",
|
||||
"shakespeareFunction = kernel.create_semantic_function(\n",
|
||||
" prompt_template=sk_prompt,\n",
|
||||
" function_name=\"shakespeare\",\n",
|
||||
" plugin_name=\"ShakespearePlugin\",\n",
|
||||
"\n",
|
||||
"exec_settings = sk_oai.OpenAIChatPromptExecutionSettings(\n",
|
||||
" service_id=service_id,\n",
|
||||
" max_tokens=2000,\n",
|
||||
" temperature=0.8,\n",
|
||||
")"
|
||||
")\n",
|
||||
"\n",
|
||||
"prompt_template_config = sk.PromptTemplateConfig(\n",
|
||||
" template=prompt,\n",
|
||||
" function_name=\"shakespeare\",\n",
|
||||
" plugin_name=\"ShakespearePlugin\",\n",
|
||||
" name=\"planner\",\n",
|
||||
" template_format=\"semantic-kernel\",\n",
|
||||
" input_variables=[\n",
|
||||
" InputVariable(name=\"input\", description=\"The user input\", is_required=True),\n",
|
||||
" ],\n",
|
||||
" execution_settings=exec_settings,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"shakespeare_plugin = kernel.create_function_from_prompt(prompt_template_config=prompt_template_config)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -220,7 +257,33 @@
|
||||
"She likes Shakespeare so write using his style. She speaks French so write it in French.\n",
|
||||
"Convert the text to uppercase.\"\"\"\n",
|
||||
"\n",
|
||||
"new_plan = await planner.create_plan(ask, kernel)"
|
||||
"# TODO: we cannot add an updated ask to a current plan because the underlying plugins already exist\n",
|
||||
"kernel = sk.Kernel()\n",
|
||||
"service_id = None\n",
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion\n",
|
||||
"\n",
|
||||
" api_key, org_id = sk.openai_settings_from_dot_env()\n",
|
||||
" service_id = \"oai_chat_gpt\"\n",
|
||||
" kernel.add_service(\n",
|
||||
" OpenAIChatCompletion(service_id=service_id, ai_model_id=\"gpt-3.5-turbo-1106\", api_key=api_key, org_id=org_id),\n",
|
||||
" )\n",
|
||||
"elif selectedService == Service.AzureOpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion\n",
|
||||
"\n",
|
||||
" deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
|
||||
" service_id = \"aoai_chat_completion\"\n",
|
||||
" kernel.add_service(\n",
|
||||
" AzureChatCompletion(service_id=service_id, deployment_name=deployment, endpoint=endpoint, api_key=api_key),\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"plugins_directory = \"../../samples/plugins/\"\n",
|
||||
"summarize_plugin = kernel.import_plugin_from_prompt_directory(service_id, plugins_directory, \"SummarizePlugin\")\n",
|
||||
"writer_plugin = kernel.import_plugin_from_prompt_directory(service_id, plugins_directory, \"WriterPlugin\")\n",
|
||||
"text_plugin = kernel.import_plugin(TextPlugin(), \"TextPlugin\")\n",
|
||||
"\n",
|
||||
"planner = BasicPlanner(service_id)\n",
|
||||
"new_plan = await planner.create_plan(ask, kernel, prompt)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -310,7 +373,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantic_kernel.planning import SequentialPlanner\n",
|
||||
"from semantic_kernel.planners import SequentialPlanner\n",
|
||||
"\n",
|
||||
"planner = SequentialPlanner(kernel)"
|
||||
]
|
||||
@@ -395,7 +458,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantic_kernel.planning import ActionPlanner\n",
|
||||
"from semantic_kernel.planners import ActionPlanner\n",
|
||||
"\n",
|
||||
"planner = ActionPlanner(kernel)"
|
||||
]
|
||||
@@ -416,14 +479,12 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantic_kernel.core_plugins import (\n",
|
||||
" FileIOPlugin,\n",
|
||||
" MathPlugin,\n",
|
||||
" TextPlugin,\n",
|
||||
" TimePlugin,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"kernel.import_plugin(MathPlugin(), \"math\")\n",
|
||||
"kernel.import_plugin(FileIOPlugin(), \"fileIO\")\n",
|
||||
"kernel.import_plugin(TimePlugin(), \"time\")\n",
|
||||
"kernel.import_plugin(TextPlugin(), \"text\")"
|
||||
]
|
||||
@@ -486,19 +547,6 @@
|
||||
"See a video walkthrough of Stepwise Planner [here.](https://youtu.be/DG_Ge1v0c4Q?si=T1CHaAm1vV0mWRHu)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "32839327",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantic_kernel.planning import StepwisePlanner\n",
|
||||
"from semantic_kernel.planning.stepwise_planner.stepwise_planner_config import (\n",
|
||||
" StepwisePlannerConfig,\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "e0a00bde",
|
||||
@@ -511,38 +559,6 @@
|
||||
"(https://www.microsoft.com/en-us/bing/apis/bing-web-search-api)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "92fc5de8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class WebSearchEnginePlugin:\n",
|
||||
" \"\"\"\n",
|
||||
" A search engine plugin.\n",
|
||||
" \"\"\"\n",
|
||||
"\n",
|
||||
" from semantic_kernel.orchestration.kernel_context import KernelContext\n",
|
||||
" from semantic_kernel.plugin_definition import (\n",
|
||||
" kernel_function,\n",
|
||||
" kernel_function_context_parameter,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" def __init__(self, connector) -> None:\n",
|
||||
" self._connector = connector\n",
|
||||
"\n",
|
||||
" @kernel_function(description=\"Performs a web search for a given query\", name=\"searchAsync\")\n",
|
||||
" @kernel_function_context_parameter(\n",
|
||||
" name=\"query\",\n",
|
||||
" description=\"The search query\",\n",
|
||||
" )\n",
|
||||
" async def search(self, query: str, context: KernelContext) -> str:\n",
|
||||
" query = query or context.variables.get(\"query\")[1]\n",
|
||||
" result = await self._connector.search(query, num_results=5, offset=0)\n",
|
||||
" return str(result)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -551,6 +567,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantic_kernel.connectors.search_engine import BingConnector\n",
|
||||
"from semantic_kernel.core_plugins import WebSearchEnginePlugin\n",
|
||||
"\n",
|
||||
"BING_API_KEY = sk.bing_search_settings_from_dot_env()\n",
|
||||
"connector = BingConnector(BING_API_KEY)\n",
|
||||
@@ -586,6 +603,8 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantic_kernel.planners.stepwise_planner import StepwisePlanner, StepwisePlannerConfig\n",
|
||||
"\n",
|
||||
"planner = StepwisePlanner(kernel, StepwisePlannerConfig(max_iterations=10, min_iteration_time_ms=1000))"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -139,6 +139,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5338d3ac",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -179,6 +180,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "24764c48",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
||||
@@ -1,171 +1,232 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "68e1c158",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Using Hugging Face With Plugins\n",
|
||||
"\n",
|
||||
"In this notebook, we demonstrate using Hugging Face models for Plugins using both SemanticMemory and text completions. \n",
|
||||
"\n",
|
||||
"SK supports downloading models from the Hugging Face that can perform the following tasks: text-generation, text2text-generation, summarization, and sentence-similarity. You can search for models by task at https://huggingface.co/models."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a77bdf89",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!python -m pip install semantic-kernel==0.5.1.dev0\n",
|
||||
"\n",
|
||||
"# Note that additional dependencies are required for the Hugging Face connectors:\n",
|
||||
"!python -m pip install torch==2.0.0\n",
|
||||
"!python -m pip install transformers==^4.28.1\n",
|
||||
"!python -m pip install sentence-transformers==^2.2.2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "508ad44f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import semantic_kernel as sk\n",
|
||||
"import semantic_kernel.connectors.ai.hugging_face as sk_hf"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "d8ddffc1",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"First, we will create a kernel and add both text completion and embedding services. \n",
|
||||
"\n",
|
||||
"For text completion, we are choosing GPT2. This is a text-generation model. (Note: text-generation will repeat the input in the output, text2text-generation will not.)\n",
|
||||
"For embeddings, we are using sentence-transformers/all-MiniLM-L6-v2. Vectors generated for this model are of length 384 (compared to a length of 1536 from OpenAI ADA).\n",
|
||||
"\n",
|
||||
"The following step may take a few minutes when run for the first time as the models will be downloaded to your local machine."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8f8dcbc6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"kernel = sk.Kernel()\n",
|
||||
"\n",
|
||||
"# Configure LLM service\n",
|
||||
"kernel.add_text_completion_service(\n",
|
||||
" service_id=\"gpt2\",\n",
|
||||
" service=sk_hf.HuggingFaceTextCompletion(ai_model_id=\"gpt2\", task=\"text-generation\"),\n",
|
||||
")\n",
|
||||
"kernel.add_text_embedding_generation_service(\n",
|
||||
" service_id=\"sentence-transformers/all-MiniLM-L6-v2\",\n",
|
||||
" service=sk_hf.HuggingFaceTextEmbedding(ai_model_id=\"sentence-transformers/all-MiniLM-L6-v2\"),\n",
|
||||
")\n",
|
||||
"kernel.register_memory_store(memory_store=sk.memory.VolatileMemoryStore())\n",
|
||||
"kernel.import_plugin(sk.core_plugins.TextMemoryPlugin())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "2a7e7ca4",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Add Memories and Define a plugin to use them\n",
|
||||
"\n",
|
||||
"Most models available on huggingface.co are not as powerful as OpenAI GPT-3+. Your plugins will likely need to be simpler to accommodate this."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d096504c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"await kernel.memory.save_information(collection=\"animal-facts\", id=\"info1\", text=\"Sharks are fish.\")\n",
|
||||
"await kernel.memory.save_information(collection=\"animal-facts\", id=\"info2\", text=\"Whales are mammals.\")\n",
|
||||
"await kernel.memory.save_information(collection=\"animal-facts\", id=\"info3\", text=\"Penguins are birds.\")\n",
|
||||
"await kernel.memory.save_information(collection=\"animal-facts\", id=\"info4\", text=\"Dolphins are mammals.\")\n",
|
||||
"await kernel.memory.save_information(collection=\"animal-facts\", id=\"info5\", text=\"Flies are insects.\")\n",
|
||||
"\n",
|
||||
"# Define semantic function using SK prompt template language\n",
|
||||
"my_prompt = \"\"\"I know these animal facts: {{recall $query1}} {{recall $query2}} {{recall $query3}} and \"\"\"\n",
|
||||
"\n",
|
||||
"# Create the semantic function\n",
|
||||
"my_function = kernel.create_semantic_function(prompt_template=my_prompt, max_tokens=45, temperature=0.5, top_p=0.5)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "2calf857",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Let's now see what the completion looks like! Remember, \"gpt2\" is nowhere near as large as ChatGPT, so expect a much simpler answer."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "628c843e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"context = kernel.create_new_context()\n",
|
||||
"context[sk.core_plugins.TextMemoryPlugin.COLLECTION_PARAM] = \"animal-facts\"\n",
|
||||
"context[sk.core_plugins.TextMemoryPlugin.RELEVANCE_PARAM] = \"0.3\"\n",
|
||||
"\n",
|
||||
"context[\"query1\"] = \"animal that swims\"\n",
|
||||
"context[\"query2\"] = \"animal that flies\"\n",
|
||||
"context[\"query3\"] = \"penguins are?\"\n",
|
||||
"output = await kernel.run(my_function, input_vars=context.variables)\n",
|
||||
"\n",
|
||||
"output = str(output).strip()\n",
|
||||
"\n",
|
||||
"query_result1 = await kernel.memory.search(\n",
|
||||
" collection=\"animal-facts\", query=context[\"query1\"], limit=1, min_relevance_score=0.3\n",
|
||||
")\n",
|
||||
"query_result2 = await kernel.memory.search(\n",
|
||||
" collection=\"animal-facts\", query=context[\"query2\"], limit=1, min_relevance_score=0.3\n",
|
||||
")\n",
|
||||
"query_result3 = await kernel.memory.search(\n",
|
||||
" collection=\"animal-facts\", query=context[\"query3\"], limit=1, min_relevance_score=0.3\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(f\"gpt2 completed prompt with: '{output}'\")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.12"
|
||||
}
|
||||
"cells": [
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "68e1c158",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Using Hugging Face With Plugins\n",
|
||||
"\n",
|
||||
"In this notebook, we demonstrate using Hugging Face models for Plugins using both SemanticMemory and text completions. \n",
|
||||
"\n",
|
||||
"SK supports downloading models from the Hugging Face that can perform the following tasks: text-generation, text2text-generation, summarization, and sentence-similarity. You can search for models by task at https://huggingface.co/models."
|
||||
]
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a77bdf89",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!python -m pip install semantic-kernel==0.5.1.dev0\n",
|
||||
"\n",
|
||||
"# Note that additional dependencies are required for the Hugging Face connectors:\n",
|
||||
"!python -m pip install torch==2.0.0\n",
|
||||
"!python -m pip install transformers==^4.28.1\n",
|
||||
"!python -m pip install sentence-transformers==^2.2.2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "508ad44f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import semantic_kernel as sk\n",
|
||||
"import semantic_kernel.connectors.ai.hugging_face as sk_hf"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "753ab756",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from services import Service\n",
|
||||
"\n",
|
||||
"# Select a service to use for this notebook (available services: OpenAI, AzureOpenAI, HuggingFace)\n",
|
||||
"selectedService = Service.HuggingFace"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "d8ddffc1",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"First, we will create a kernel and add both text completion and embedding services. \n",
|
||||
"\n",
|
||||
"For text completion, we are choosing GPT2. This is a text-generation model. (Note: text-generation will repeat the input in the output, text2text-generation will not.)\n",
|
||||
"For embeddings, we are using sentence-transformers/all-MiniLM-L6-v2. Vectors generated for this model are of length 384 (compared to a length of 1536 from OpenAI ADA).\n",
|
||||
"\n",
|
||||
"The following step may take a few minutes when run for the first time as the models will be downloaded to your local machine."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "8f8dcbc6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"kernel = sk.Kernel()\n",
|
||||
"\n",
|
||||
"# Configure LLM service\n",
|
||||
"if selectedService == Service.HuggingFace:\n",
|
||||
" text_service_id = \"gpt2\"\n",
|
||||
" kernel.add_service(\n",
|
||||
" service=sk_hf.HuggingFaceTextCompletion(\n",
|
||||
" service_id=text_service_id, ai_model_id=text_service_id, task=\"text-generation\"\n",
|
||||
" ),\n",
|
||||
" )\n",
|
||||
" embed_service_id = \"sentence-transformers/all-MiniLM-L6-v2\"\n",
|
||||
" embedding_svc = sk_hf.HuggingFaceTextEmbedding(service_id=embed_service_id, ai_model_id=embed_service_id)\n",
|
||||
" kernel.add_service(\n",
|
||||
" service=embedding_svc,\n",
|
||||
" )\n",
|
||||
" kernel.use_memory(storage=sk.memory.VolatileMemoryStore(), embeddings_generator=embedding_svc)\n",
|
||||
" kernel.import_plugin(sk.core_plugins.TextMemoryPlugin(), \"TextMemoryPlugin\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "2a7e7ca4",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Add Memories and Define a plugin to use them\n",
|
||||
"\n",
|
||||
"Most models available on huggingface.co are not as powerful as OpenAI GPT-3+. Your plugins will likely need to be simpler to accommodate this."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "d096504c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"await kernel.memory.save_information(collection=\"animal-facts\", id=\"info1\", text=\"Sharks are fish.\")\n",
|
||||
"await kernel.memory.save_information(collection=\"animal-facts\", id=\"info2\", text=\"Whales are mammals.\")\n",
|
||||
"await kernel.memory.save_information(collection=\"animal-facts\", id=\"info3\", text=\"Penguins are birds.\")\n",
|
||||
"await kernel.memory.save_information(collection=\"animal-facts\", id=\"info4\", text=\"Dolphins are mammals.\")\n",
|
||||
"await kernel.memory.save_information(collection=\"animal-facts\", id=\"info5\", text=\"Flies are insects.\")\n",
|
||||
"\n",
|
||||
"# Define prompt function using SK prompt template language\n",
|
||||
"my_prompt = \"\"\"I know these animal facts: {{recall $query1}} {{recall $query2}} {{recall $query3}} and \"\"\"\n",
|
||||
"\n",
|
||||
"execution_settings = sk_hf.HuggingFacePromptExecutionSettings(\n",
|
||||
" service_id=text_service_id,\n",
|
||||
" ai_model_id=text_service_id,\n",
|
||||
" max_tokens=45,\n",
|
||||
" temperature=0.5,\n",
|
||||
" top_p=0.5,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"prompt_template_config = sk.PromptTemplateConfig(\n",
|
||||
" template=my_prompt,\n",
|
||||
" name=\"text_complete\",\n",
|
||||
" template_format=\"semantic-kernel\",\n",
|
||||
" execution_settings=execution_settings,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"my_function = kernel.create_function_from_prompt(prompt_template_config=prompt_template_config)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "2calf857",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Let's now see what the completion looks like! Remember, \"gpt2\" is nowhere near as large as ChatGPT, so expect a much simpler answer."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "628c843e",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"/home/evmattso/.cache/pypoetry/virtualenvs/semantic-kernel-eoLGgW5m-py3.10/lib/python3.10/site-packages/transformers/generation/configuration_utils.py:389: UserWarning: `do_sample` is set to `False`. However, `temperature` is set to `0.5` -- this flag is only used in sample-based generation modes. You should set `do_sample=True` or unset `temperature`. This was detected when initializing the generation config instance, which means the corresponding file may hold incorrect parameterization and should be fixed.\n",
|
||||
" warnings.warn(\n",
|
||||
"/home/evmattso/.cache/pypoetry/virtualenvs/semantic-kernel-eoLGgW5m-py3.10/lib/python3.10/site-packages/transformers/generation/configuration_utils.py:394: UserWarning: `do_sample` is set to `False`. However, `top_p` is set to `0.5` -- this flag is only used in sample-based generation modes. You should set `do_sample=True` or unset `top_p`. This was detected when initializing the generation config instance, which means the corresponding file may hold incorrect parameterization and should be fixed.\n",
|
||||
" warnings.warn(\n",
|
||||
"/home/evmattso/.cache/pypoetry/virtualenvs/semantic-kernel-eoLGgW5m-py3.10/lib/python3.10/site-packages/transformers/generation/utils.py:1355: UserWarning: Using the model-agnostic default `max_length` (=20) to control the generation length. We recommend setting `max_new_tokens` to control the maximum length of the generation.\n",
|
||||
" warnings.warn(\n",
|
||||
"/home/evmattso/.cache/pypoetry/virtualenvs/semantic-kernel-eoLGgW5m-py3.10/lib/python3.10/site-packages/transformers/generation/utils.py:1363: UserWarning: Input length of input_ids is 21, but `max_length` is set to 20. This can lead to unexpected behavior. You should consider increasing `max_new_tokens`.\n",
|
||||
" warnings.warn(\n",
|
||||
"Error occurred while invoking function f_HSMshmxNdvxpFZSl: ('Hugging Face completion failed', ValueError('If `eos_token_id` is defined, make sure that `pad_token_id` is defined.'), None)\n",
|
||||
"Error occurred while invoking function f_HSMshmxNdvxpFZSl: ('Hugging Face completion failed', ValueError('If `eos_token_id` is defined, make sure that `pad_token_id` is defined.'), None)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"gpt2 completed prompt with: ''\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from semantic_kernel.functions import KernelArguments\n",
|
||||
"\n",
|
||||
"arguments = KernelArguments(\n",
|
||||
" query1=\"animal that swims\",\n",
|
||||
" query2=\"animal that flies\",\n",
|
||||
" query3=\"penguins are?\",\n",
|
||||
" collection=\"animal-facts\",\n",
|
||||
" relevance=0.3,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"output = await kernel.invoke(\n",
|
||||
" my_function,\n",
|
||||
" arguments,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"output = str(output).strip()\n",
|
||||
"\n",
|
||||
"query_result1 = await kernel.memory.search(\n",
|
||||
" collection=\"animal-facts\", query=arguments[\"query1\"], limit=1, min_relevance_score=0.3\n",
|
||||
")\n",
|
||||
"query_result2 = await kernel.memory.search(\n",
|
||||
" collection=\"animal-facts\", query=arguments[\"query2\"], limit=1, min_relevance_score=0.3\n",
|
||||
")\n",
|
||||
"query_result3 = await kernel.memory.search(\n",
|
||||
" collection=\"animal-facts\", query=arguments[\"query3\"], limit=1, min_relevance_score=0.3\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(f\"{text_service_id} completed prompt with: '{output}'\")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.12"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
|
||||
@@ -49,6 +49,19 @@
|
||||
"!python -m pip install semantic-kernel==0.5.1.dev0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "fddb5403",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from services import Service\n",
|
||||
"\n",
|
||||
"# Select a service to use for this notebook (available services: OpenAI, AzureOpenAI, HuggingFace)\n",
|
||||
"selectedService = Service.OpenAI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -57,26 +70,31 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import semantic_kernel as sk\n",
|
||||
"from semantic_kernel.connectors.ai.open_ai import (\n",
|
||||
" AzureChatCompletion,\n",
|
||||
" OpenAIChatCompletion,\n",
|
||||
")\n",
|
||||
"import semantic_kernel.connectors.ai.open_ai as sk_oai\n",
|
||||
"from semantic_kernel.prompt_template.input_variable import InputVariable\n",
|
||||
"\n",
|
||||
"kernel = sk.Kernel()\n",
|
||||
"\n",
|
||||
"useAzureOpenAI = False\n",
|
||||
"if selectedService == Service.AzureOpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion\n",
|
||||
"\n",
|
||||
"# Configure AI service used by the kernel\n",
|
||||
"if useAzureOpenAI:\n",
|
||||
" deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
|
||||
" service_id = \"aoai_chat\" # used later in the notebook\n",
|
||||
" azure_chat_service = AzureChatCompletion(\n",
|
||||
" deployment_name=\"turbo\", endpoint=endpoint, api_key=api_key\n",
|
||||
" service_id=service_id, deployment_name=\"gpt-35-turbo\", endpoint=endpoint, api_key=api_key\n",
|
||||
" ) # set the deployment name to the value of your chat model\n",
|
||||
" kernel.add_chat_service(\"chat_completion\", azure_chat_service)\n",
|
||||
"else:\n",
|
||||
" kernel.add_service(azure_chat_service)\n",
|
||||
"\n",
|
||||
"# Configure OpenAI service\n",
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion\n",
|
||||
"\n",
|
||||
" api_key, org_id = sk.openai_settings_from_dot_env()\n",
|
||||
" oai_chat_service = OpenAIChatCompletion(ai_model_id=\"gpt-3.5-turbo\", api_key=api_key, org_id=org_id)\n",
|
||||
" kernel.add_chat_service(\"chat-gpt\", oai_chat_service)"
|
||||
" service_id = \"oai_chat\" # used later in the notebook\n",
|
||||
" oai_chat_service = OpenAIChatCompletion(\n",
|
||||
" service_id=service_id, ai_model_id=\"gpt-4-turbo-1106\", api_key=api_key, org_id=org_id\n",
|
||||
" )\n",
|
||||
" kernel.add_service(oai_chat_service)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -105,7 +123,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import random\n",
|
||||
"from semantic_kernel.plugin_definition import kernel_function\n",
|
||||
"from semantic_kernel.functions import kernel_function\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class GenerateNumberPlugin:\n",
|
||||
@@ -150,23 +168,44 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sk_prompt = \"\"\"\n",
|
||||
"prompt = \"\"\"\n",
|
||||
"Write a short story about two Corgis on an adventure.\n",
|
||||
"The story must be:\n",
|
||||
"- G rated\n",
|
||||
"- Have a positive message\n",
|
||||
"- No sexism, racism or other bias/bigotry\n",
|
||||
"- Be exactly {{$input}} paragraphs long\n",
|
||||
"- Be exactly {{$input}} paragraphs long. It must be this length.\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"corgi_story = kernel.create_semantic_function(\n",
|
||||
" prompt_template=sk_prompt,\n",
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" execution_settings = sk_oai.OpenAIChatPromptExecutionSettings(\n",
|
||||
" service_id=service_id,\n",
|
||||
" ai_model_id=\"gpt-3.5-turbo-1106\",\n",
|
||||
" max_tokens=2000,\n",
|
||||
" temperature=0.7,\n",
|
||||
" )\n",
|
||||
"elif selectedService == Service.AzureOpenAI:\n",
|
||||
" execution_settings = sk_oai.OpenAIChatPromptExecutionSettings(\n",
|
||||
" service_id=service_id,\n",
|
||||
" ai_model_id=deployment,\n",
|
||||
" max_tokens=2000,\n",
|
||||
" temperature=0.7,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"prompt_template_config = sk.PromptTemplateConfig(\n",
|
||||
" template=prompt,\n",
|
||||
" name=\"story\",\n",
|
||||
" template_format=\"semantic-kernel\",\n",
|
||||
" input_variables=[\n",
|
||||
" InputVariable(name=\"input\", description=\"The user input\", is_required=True),\n",
|
||||
" ],\n",
|
||||
" execution_settings=execution_settings,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"corgi_story = kernel.create_function_from_prompt(\n",
|
||||
" function_name=\"CorgiStory\",\n",
|
||||
" plugin_name=\"CorgiPlugin\",\n",
|
||||
" description=\"Write a short story about two Corgis on an adventure\",\n",
|
||||
" max_tokens=500,\n",
|
||||
" temperature=0.5,\n",
|
||||
" top_p=0.5,\n",
|
||||
" prompt_template_config=prompt_template_config,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"generate_number_plugin = kernel.import_plugin(GenerateNumberPlugin(), \"GenerateNumberPlugin\")"
|
||||
@@ -181,7 +220,7 @@
|
||||
"source": [
|
||||
"# Run the number generator\n",
|
||||
"generate_number_three_or_higher = generate_number_plugin[\"GenerateNumberThreeOrHigher\"]\n",
|
||||
"number_result = await generate_number_three_or_higher(6)\n",
|
||||
"number_result = await generate_number_three_or_higher(kernel, input=6)\n",
|
||||
"print(number_result)"
|
||||
]
|
||||
},
|
||||
@@ -192,7 +231,15 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"story = await corgi_story.invoke(input=number_result.result)"
|
||||
"story = await corgi_story.invoke(kernel, input=number_result.value)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7245e7a2",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"_Note: depending on which model you're using, it may not respond with the proper number of paragraphs._"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -202,7 +249,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"Generating a corgi story exactly {} paragraphs long: \".format(number_result.result))\n",
|
||||
"print(f\"Generating a corgi story exactly {number_result.value} paragraphs long.\")\n",
|
||||
"print(\"=====================================================\")\n",
|
||||
"print(story)"
|
||||
]
|
||||
@@ -213,13 +260,13 @@
|
||||
"id": "8ef29d16",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Context Variables\n",
|
||||
"## Kernel Functions with Annotated Parameters\n",
|
||||
"\n",
|
||||
"That works! But let's expand on our example to make it more generic.\n",
|
||||
"\n",
|
||||
"For the native function, we'll introduce the lower limit variable. This means that a user will input two numbers and the number generator function will pick a number between the first and second input.\n",
|
||||
"\n",
|
||||
"We'll make use of the `semantic_kernel.ContextVariables` class to do hold these variables.\n"
|
||||
"We'll make use of the Python's `Annotated` class to hold these variables.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -229,27 +276,40 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import sys\n",
|
||||
"import semantic_kernel as sk\n",
|
||||
"from semantic_kernel.connectors.ai.open_ai import (\n",
|
||||
" AzureChatCompletion,\n",
|
||||
" OpenAIChatCompletion,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"if sys.version_info >= (3, 9):\n",
|
||||
" from typing import Annotated\n",
|
||||
"else:\n",
|
||||
" from typing_extensions import Annotated\n",
|
||||
"\n",
|
||||
"kernel = sk.Kernel()\n",
|
||||
"\n",
|
||||
"useAzureOpenAI = False\n",
|
||||
"if selectedService == Service.AzureOpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion\n",
|
||||
"\n",
|
||||
"# Configure AI service used by the kernel\n",
|
||||
"if useAzureOpenAI:\n",
|
||||
" deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
|
||||
" service_id = \"aoai_chat\" # used later in the notebook\n",
|
||||
" azure_chat_service = AzureChatCompletion(\n",
|
||||
" deployment_name=\"turbo\", endpoint=endpoint, api_key=api_key\n",
|
||||
" service_id=service_id, deployment_name=\"gpt-35-turbo\", endpoint=endpoint, api_key=api_key\n",
|
||||
" ) # set the deployment name to the value of your chat model\n",
|
||||
" kernel.add_chat_service(\"chat_completion\", azure_chat_service)\n",
|
||||
"else:\n",
|
||||
" kernel.add_service(azure_chat_service)\n",
|
||||
"\n",
|
||||
"# Configure OpenAI service\n",
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion\n",
|
||||
"\n",
|
||||
" api_key, org_id = sk.openai_settings_from_dot_env()\n",
|
||||
" oai_chat_service = OpenAIChatCompletion(ai_model_id=\"gpt-3.5-turbo\", api_key=api_key, org_id=org_id)\n",
|
||||
" kernel.add_chat_service(\"chat-gpt\", oai_chat_service)"
|
||||
" service_id = \"oai_chat\" # used later in the notebook\n",
|
||||
" oai_chat_service = OpenAIChatCompletion(\n",
|
||||
" service_id=service_id, ai_model_id=\"gpt-4-turbo-1106\", api_key=api_key, org_id=org_id\n",
|
||||
" )\n",
|
||||
" kernel.add_service(oai_chat_service)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -258,7 +318,7 @@
|
||||
"id": "091f45e4",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Let's start with the native function. Notice that we're also adding `@kernel_function_context_parameter` decorators to the function here to provide context about what variables need to be provided to the function, and any defaults for those inputs. Using the `@kernel_function_context_parameter` decorator provides the name, description and default values for a function's inputs to the [planner.](./05-using-the-planner.ipynb)\n"
|
||||
"Let's start with the native function. Notice that we're add the `@kernel_function` decorator that holds the name of the function as well as an optional description. The input parameters are configured as part of the function's signature, and we use the `Annotated` type to specify the required input arguments.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -269,8 +329,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import random\n",
|
||||
"from semantic_kernel.plugin_definition import kernel_function, kernel_function_context_parameter\n",
|
||||
"from semantic_kernel import KernelContext\n",
|
||||
"from semantic_kernel.functions import kernel_function\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class GenerateNumberPlugin:\n",
|
||||
@@ -279,12 +338,14 @@
|
||||
" \"\"\"\n",
|
||||
"\n",
|
||||
" @kernel_function(\n",
|
||||
" description=\"Generate a random number between min and max\",\n",
|
||||
" name=\"GenerateNumber\",\n",
|
||||
" description=\"Generate a random number between min and max\",\n",
|
||||
" )\n",
|
||||
" @kernel_function_context_parameter(name=\"min\", description=\"Minimum number of paragraphs.\")\n",
|
||||
" @kernel_function_context_parameter(name=\"max\", description=\"Maximum number of paragraphs.\", default_value=\"10\")\n",
|
||||
" def generate_number(self, context: KernelContext) -> str:\n",
|
||||
" def generate_number(\n",
|
||||
" self,\n",
|
||||
" min: Annotated[int, \"the minimum number of paragraphs\"],\n",
|
||||
" max: Annotated[int, \"the maximum number of paragraphs\"] = 10,\n",
|
||||
" ) -> Annotated[int, \"the output is a number\"]:\n",
|
||||
" \"\"\"\n",
|
||||
" Generate a number between min-max\n",
|
||||
" Example:\n",
|
||||
@@ -296,9 +357,9 @@
|
||||
" int value\n",
|
||||
" \"\"\"\n",
|
||||
" try:\n",
|
||||
" return str(random.randint(int(context[\"min\"]), int(context[\"max\"])))\n",
|
||||
" return str(random.randint(min, max))\n",
|
||||
" except ValueError as e:\n",
|
||||
" print(f\"Invalid input {context['min']} {context['max']}\")\n",
|
||||
" print(f\"Invalid input {min} and {max}\")\n",
|
||||
" raise e"
|
||||
]
|
||||
},
|
||||
@@ -329,7 +390,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sk_prompt = \"\"\"\n",
|
||||
"prompt = \"\"\"\n",
|
||||
"Write a short story about two Corgis on an adventure.\n",
|
||||
"The story must be:\n",
|
||||
"- G rated\n",
|
||||
@@ -339,43 +400,46 @@
|
||||
"- Be written in this language: {{$language}}\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"corgi_story = kernel.create_semantic_function(\n",
|
||||
" prompt_template=sk_prompt,\n",
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" execution_settings = sk_oai.OpenAIChatPromptExecutionSettings(\n",
|
||||
" service_id=service_id,\n",
|
||||
" ai_model_id=\"gpt-3.5-turbo-1106\",\n",
|
||||
" max_tokens=2000,\n",
|
||||
" temperature=0.7,\n",
|
||||
" )\n",
|
||||
"elif selectedService == Service.AzureOpenAI:\n",
|
||||
" execution_settings = sk_oai.OpenAIChatPromptExecutionSettings(\n",
|
||||
" service_id=service_id,\n",
|
||||
" ai_model_id=deployment,\n",
|
||||
" max_tokens=2000,\n",
|
||||
" temperature=0.7,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"prompt_template_config = sk.PromptTemplateConfig(\n",
|
||||
" template=prompt,\n",
|
||||
" name=\"summarize\",\n",
|
||||
" template_format=\"semantic-kernel\",\n",
|
||||
" input_variables=[\n",
|
||||
" InputVariable(name=\"paragraph_count\", description=\"The number of paragraphs\", is_required=True),\n",
|
||||
" InputVariable(name=\"language\", description=\"The language of the story\", is_required=True),\n",
|
||||
" ],\n",
|
||||
" execution_settings=execution_settings,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"corgi_story = kernel.create_function_from_prompt(\n",
|
||||
" function_name=\"CorgiStory\",\n",
|
||||
" plugin_name=\"CorgiPlugin\",\n",
|
||||
" description=\"Write a short story about two Corgis on an adventure\",\n",
|
||||
" max_tokens=500,\n",
|
||||
" temperature=0.5,\n",
|
||||
" top_p=0.5,\n",
|
||||
" prompt_template_config=prompt_template_config,\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "fdce1872",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now we can call this using our `invoke` function by passing in our `context_variables` in the `variables` parameter.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "97d8d3c9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"context_variables = sk.ContextVariables(variables={\"min\": \"1\", \"max\": \"5\", \"language\": \"Spanish\"})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "c8778bad",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Let's add a paragraph count to our context variables\n"
|
||||
"Let's generate a paragraph count.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -385,8 +449,17 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"num = await generate_number.invoke(variables=context_variables)\n",
|
||||
"context_variables[\"paragraph_count\"] = num.result"
|
||||
"result = await generate_number.invoke(kernel, min=1, max=5)\n",
|
||||
"num_paragraphs = result.value\n",
|
||||
"print(f\"Generating a corgi story {num_paragraphs} paragraphs long.\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "225a9147",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"We can now invoke our corgi_story function using the `kernel` and the keyword arguments `paragraph_count` and `language`."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -397,7 +470,8 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Pass the output to the semantic story function\n",
|
||||
"story = await corgi_story.invoke(variables=context_variables)"
|
||||
"desired_language = \"Spanish\"\n",
|
||||
"story = await corgi_story.invoke(kernel, paragraph_count=num_paragraphs, language=desired_language)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -409,11 +483,7 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\n",
|
||||
" \"Generating a corgi story exactly {} paragraphs long in {} language: \".format(\n",
|
||||
" context_variables[\"paragraph_count\"], context_variables[\"language\"]\n",
|
||||
" )\n",
|
||||
")\n",
|
||||
"print(f\"Generating a corgi story {num_paragraphs} paragraphs long in {desired_language}.\")\n",
|
||||
"print(\"=====================================================\")\n",
|
||||
"print(story)"
|
||||
]
|
||||
@@ -426,7 +496,7 @@
|
||||
"source": [
|
||||
"## Calling Native Functions within a Semantic Function\n",
|
||||
"\n",
|
||||
"One neat thing about the Semantic Kernel is that you can also call native functions from within Semantic Functions!\n",
|
||||
"One neat thing about the Semantic Kernel is that you can also call native functions from within Prompt Functions!\n",
|
||||
"\n",
|
||||
"We will make our CorgiStory semantic function call a native function `GenerateNames` which will return names for our Corgi characters.\n",
|
||||
"\n",
|
||||
@@ -441,7 +511,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import random\n",
|
||||
"from semantic_kernel.plugin_definition import kernel_function\n",
|
||||
"from semantic_kernel.functions import kernel_function\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class GenerateNamesPlugin:\n",
|
||||
@@ -484,7 +554,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sk_prompt = \"\"\"\n",
|
||||
"prompt = \"\"\"\n",
|
||||
"Write a short story about two Corgis on an adventure.\n",
|
||||
"The story must be:\n",
|
||||
"- G rated\n",
|
||||
@@ -496,6 +566,46 @@
|
||||
"\"\"\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "be72a503",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" execution_settings = sk_oai.OpenAIChatPromptExecutionSettings(\n",
|
||||
" service_id=service_id,\n",
|
||||
" ai_model_id=\"gpt-3.5-turbo-1106\",\n",
|
||||
" max_tokens=2000,\n",
|
||||
" temperature=0.7,\n",
|
||||
" )\n",
|
||||
"elif selectedService == Service.AzureOpenAI:\n",
|
||||
" execution_settings = sk_oai.OpenAIChatPromptExecutionSettings(\n",
|
||||
" service_id=service_id,\n",
|
||||
" ai_model_id=deployment,\n",
|
||||
" max_tokens=2000,\n",
|
||||
" temperature=0.7,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"prompt_template_config = sk.PromptTemplateConfig(\n",
|
||||
" template=prompt,\n",
|
||||
" name=\"corgi-new\",\n",
|
||||
" template_format=\"semantic-kernel\",\n",
|
||||
" input_variables=[\n",
|
||||
" InputVariable(name=\"paragraph_count\", description=\"The number of paragraphs\", is_required=True),\n",
|
||||
" InputVariable(name=\"language\", description=\"The language of the story\", is_required=True),\n",
|
||||
" ],\n",
|
||||
" execution_settings=execution_settings,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"corgi_story = kernel.create_function_from_prompt(\n",
|
||||
" function_name=\"CorgiStoryUpdated\",\n",
|
||||
" plugin_name=\"CorgiPluginUpdated\",\n",
|
||||
" prompt_template_config=prompt_template_config,\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -503,9 +613,8 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"context_variables = sk.ContextVariables(variables={\"min\": \"1\", \"max\": \"5\", \"language\": \"Spanish\"})\n",
|
||||
"num = await generate_number.invoke(variables=context_variables)\n",
|
||||
"context_variables[\"paragraph_count\"] = str(num.result)"
|
||||
"result = await generate_number.invoke(kernel, min=1, max=5)\n",
|
||||
"num_paragraphs = result.value"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -515,8 +624,8 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Pass the output to the semantic story function\n",
|
||||
"story = await corgi_story.invoke(variables=context_variables)"
|
||||
"desired_language = \"French\"\n",
|
||||
"story = await corgi_story.invoke(kernel, paragraph_count=num_paragraphs, language=desired_language)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -526,11 +635,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\n",
|
||||
" \"Generating a corgi story exactly {} paragraphs long in {} language: \".format(\n",
|
||||
" context_variables[\"paragraph_count\"], context_variables[\"language\"]\n",
|
||||
" )\n",
|
||||
")\n",
|
||||
"print(f\"Generating a corgi story {num_paragraphs} paragraphs long in {desired_language}.\")\n",
|
||||
"print(\"=====================================================\")\n",
|
||||
"print(story)"
|
||||
]
|
||||
@@ -545,9 +650,9 @@
|
||||
"\n",
|
||||
"A quick review of what we've learned here:\n",
|
||||
"\n",
|
||||
"- We've learned how to create native and semantic functions and register them to the kernel\n",
|
||||
"- We've seen how we can use context variables to pass in more custom variables into our prompt\n",
|
||||
"- We've seen how we can call native functions within semantic function prompts.\n"
|
||||
"- We've learned how to create native and prompt functions and register them to the kernel\n",
|
||||
"- We've seen how we can use Kernel Arguments to pass in more custom variables into our prompt\n",
|
||||
"- We've seen how we can call native functions within a prompt.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
@@ -105,14 +105,18 @@
|
||||
"# Configure AI service used by the kernel\n",
|
||||
"if useAzureOpenAI:\n",
|
||||
" deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
|
||||
" service_id = \"chat_completion\"\n",
|
||||
" azure_chat_service = AzureChatCompletion(\n",
|
||||
" deployment_name=\"turbo\", endpoint=endpoint, api_key=api_key\n",
|
||||
" service_id=service_id, deployment_name=\"turbo\", endpoint=endpoint, api_key=api_key\n",
|
||||
" ) # set the deployment name to the value of your chat model\n",
|
||||
" kernel.add_chat_service(\"chat_completion\", azure_chat_service)\n",
|
||||
" kernel.add_service(azure_chat_service)\n",
|
||||
"else:\n",
|
||||
" api_key, org_id = sk.openai_settings_from_dot_env()\n",
|
||||
" oai_chat_service = OpenAIChatCompletion(ai_model_id=\"gpt-3.5-turbo\", api_key=api_key, org_id=org_id)\n",
|
||||
" kernel.add_chat_service(\"chat-gpt\", oai_chat_service)"
|
||||
" service_id = \"chat-gpt\"\n",
|
||||
" oai_chat_service = OpenAIChatCompletion(\n",
|
||||
" service_id=service_id, ai_model_id=\"gpt-3.5-turbo\", api_key=api_key, org_id=org_id\n",
|
||||
" )\n",
|
||||
" kernel.add_service(oai_chat_service)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -135,7 +139,9 @@
|
||||
"# note: using plugins from the samples folder\n",
|
||||
"plugins_directory = \"../../samples/plugins\"\n",
|
||||
"\n",
|
||||
"groundingSemanticFunctions = kernel.import_semantic_plugin_from_directory(plugins_directory, \"GroundingPlugin\")"
|
||||
"groundingSemanticFunctions = kernel.import_plugin_from_prompt_directory(\n",
|
||||
" service_id, plugins_directory, \"GroundingPlugin\"\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -209,28 +215,6 @@
|
||||
"Now, let us start calling individual semantic functions."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "4e435b18",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Preparing the Context\n",
|
||||
"\n",
|
||||
"Semantic functions operate in a context, which provides extra parameters for their operation. For the grounding plugin, the context is expected to supply the topic for the reference checking, and some particular examples of them:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "60aa6fa0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"context = kernel.create_new_context()\n",
|
||||
"context[\"topic\"] = \"people and places\"\n",
|
||||
"context[\"example_entities\"] = \"John, Jane, mother, brother, Paris, Rome\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "071c05e4",
|
||||
@@ -248,9 +232,14 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"extraction_result = await entity_extraction(summary_text, context=context)\n",
|
||||
"extraction_result = await kernel.invoke(\n",
|
||||
" entity_extraction,\n",
|
||||
" input=summary_text,\n",
|
||||
" topic=\"people and places\",\n",
|
||||
" example_entities=\"John, Jane, mother, brother, Paris, Rome\",\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(extraction_result.result)"
|
||||
"print(extraction_result)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -271,16 +260,6 @@
|
||||
"We now use the grounding text to see if the entities we found are grounded. We start by adding the grounding text to our context:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "16cef37a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"context[\"reference_context\"] = grounding_text"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "894e38d7",
|
||||
@@ -296,9 +275,9 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"grounding_result = await reference_check(extraction_result.result, context=context)\n",
|
||||
"grounding_result = await kernel.invoke(reference_check, input=extraction_result.value, reference_context=grounding_text)\n",
|
||||
"\n",
|
||||
"print(grounding_result.result)"
|
||||
"print(grounding_result)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -309,16 +288,6 @@
|
||||
"So we now have a list of ungrounded entities (of course, this list may not be well grounded itself). Let us store this in the context:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a76aba58",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"context[\"ungrounded_entities\"] = grounding_result.result"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "35c1c329",
|
||||
@@ -336,9 +305,9 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"excision_result = await entity_excision(summary_text, context=context)\n",
|
||||
"excision_result = await kernel.invoke(entity_excision, input=summary_text, ungrounded_entities=grounding_result.value)\n",
|
||||
"\n",
|
||||
"print(excision_result.result)"
|
||||
"print(excision_result)"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -358,7 +327,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.7"
|
||||
"version": "3.10.12"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -1,404 +1,417 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "68e1c158",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Multiple Results\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "fb81bacd",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"In this notebook we show how you can in a single request, have the LLM model return multiple results per prompt. This is useful for running experiments where you want to evaluate the robustness of your prompt and the parameters of your config against a particular large language model.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a77bdf89",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!python -m pip install semantic-kernel==0.5.1.dev0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3f4bfee4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from services import Service\n",
|
||||
"\n",
|
||||
"# Select a service to use for this notebook (available services: OpenAI, AzureOpenAI, HuggingFace)\n",
|
||||
"selectedService = Service.AzureOpenAI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "508ad44f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import semantic_kernel as sk\n",
|
||||
"\n",
|
||||
"if selectedService == Service.OpenAI or selectedService == Service.AzureOpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai.prompt_execution_settings.open_ai_prompt_execution_settings import (\n",
|
||||
" OpenAITextPromptExecutionSettings,\n",
|
||||
" OpenAIChatPromptExecutionSettings,\n",
|
||||
" )\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai.prompt_execution_settings.azure_chat_prompt_execution_settings import (\n",
|
||||
" AzureChatPromptExecutionSettings,\n",
|
||||
" )\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import (\n",
|
||||
" AzureTextCompletion,\n",
|
||||
" AzureChatCompletion,\n",
|
||||
" OpenAITextCompletion,\n",
|
||||
" OpenAIChatCompletion,\n",
|
||||
" )\n",
|
||||
"if selectedService == Service.HuggingFace:\n",
|
||||
" from semantic_kernel.connectors.ai.hugging_face import HuggingFaceTextCompletion"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "d8ddffc1",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"First, we will set up the text and chat services we will be submitting prompts to.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8f8dcbc6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"kernel = sk.Kernel()\n",
|
||||
"\n",
|
||||
"# Configure Azure LLM service\n",
|
||||
"if selectedService == Service.AzureOpenAI:\n",
|
||||
" deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
|
||||
" azure_text_service = AzureTextCompletion(\n",
|
||||
" deployment_name=\"gpt-35-turbo-instruct\", endpoint=endpoint, api_key=api_key\n",
|
||||
" ) # set the deployment name to the value of your text model (e.g. gpt-35-turbo-instruct or text-davinci-003)\n",
|
||||
" azure_chat_service = AzureChatCompletion(\n",
|
||||
" deployment_name=\"gpt-35-turbo\", endpoint=endpoint, api_key=api_key\n",
|
||||
" ) # set the deployment name to the value of your chat model\n",
|
||||
"\n",
|
||||
"# Configure OpenAI service\n",
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" api_key, org_id = sk.openai_settings_from_dot_env()\n",
|
||||
" oai_text_service = OpenAITextCompletion(ai_model_id=\"gpt-3.5-turbo-instruct\", api_key=api_key, org_id=org_id)\n",
|
||||
" oai_chat_service = OpenAIChatCompletion(ai_model_id=\"gpt-3.5-turbo\", api_key=api_key, org_id=org_id)\n",
|
||||
"\n",
|
||||
"# Configure Hugging Face service\n",
|
||||
"if selectedService == Service.HuggingFace:\n",
|
||||
" hf_text_service = HuggingFaceTextCompletion(ai_model_id=\"distilgpt2\", task=\"text-generation\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "50561d82",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Next, we'll set up the completion request settings for text completion services.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "628c843e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"oai_text_prompt_execution_settings = OpenAITextPromptExecutionSettings(\n",
|
||||
" extension_data={\n",
|
||||
" \"max_tokens\": 80,\n",
|
||||
" \"temperature\": 0.7,\n",
|
||||
" \"top_p\": 1,\n",
|
||||
" \"frequency_penalty\": 0.5,\n",
|
||||
" \"presence_penalty\": 0.5,\n",
|
||||
" \"number_of_responses\": 3,\n",
|
||||
" }\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "857a9c89",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Multiple Open AI Text Completions\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e2979db8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" prompt = \"what is the purpose of a rubber duck?\"\n",
|
||||
" results = await oai_text_service.complete(prompt=prompt, settings=oai_text_prompt_execution_settings)\n",
|
||||
" i = 1\n",
|
||||
" for result in results:\n",
|
||||
" print(f\"Result {i}: {result}\")\n",
|
||||
" i += 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "4288d09f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Multiple Azure Open AI Text Completions\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5319f14d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.AzureOpenAI:\n",
|
||||
" prompt = \"provide me a list of possible meanings for the acronym 'ORLD'\"\n",
|
||||
" results = await azure_text_service.complete(prompt=prompt, settings=oai_text_prompt_execution_settings)\n",
|
||||
" i = 1\n",
|
||||
" for result in results:\n",
|
||||
" print(f\"Result {i}: {result}\")\n",
|
||||
" i += 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "eb548f9c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Multiple Hugging Face Text Completions\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "4a148709",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.HuggingFace:\n",
|
||||
" from semantic_kernel.connectors.ai.hugging_face.hf_prompt_execution_settings import (\n",
|
||||
" HuggingFacePromptExecutionSettings,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" hf_prompt_execution_settings = HuggingFacePromptExecutionSettings(\n",
|
||||
" extension_data={\"max_new_tokens\": 80, \"temperature\": 0.7, \"top_p\": 1}\n",
|
||||
" )"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "9525e4f3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.HuggingFace:\n",
|
||||
" prompt = \"The purpose of a rubber duck is\"\n",
|
||||
" results = await hf_text_service.complete(prompt=prompt, prompt_execution_settings=hf_prompt_execution_settings)\n",
|
||||
" print(\"\".join(results))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "da632e12",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Here, we're setting up the settings for Chat completions.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e5f11e46",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"oai_chat_prompt_execution_settings = OpenAIChatPromptExecutionSettings(\n",
|
||||
" max_tokens=80,\n",
|
||||
" temperature=0.7,\n",
|
||||
" top_p=1,\n",
|
||||
" frequency_penalty=0.5,\n",
|
||||
" presence_penalty=0.5,\n",
|
||||
" number_of_responses=3,\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "d6bf238e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Multiple OpenAI Chat Completions\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "dabc6a4c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" role = \"user\"\n",
|
||||
" content = (\n",
|
||||
" \"It's a beautiful day outside, birds are singing, flowers are blooming. On days like these, kids like you...\"\n",
|
||||
" )\n",
|
||||
" message = {\"role\": role, \"content\": content}\n",
|
||||
" results = await oai_chat_service.complete_chat(messages=[message], settings=oai_chat_prompt_execution_settings)\n",
|
||||
" i = 0\n",
|
||||
" for result in results:\n",
|
||||
" print(f\"Result {i}: {result[0]}\")\n",
|
||||
" i += 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "cdb8f740",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Multiple Azure OpenAI Chat Completions\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "66ba4767",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"az_oai_prompt_execution_settings = AzureChatPromptExecutionSettings(\n",
|
||||
" max_tokens=80,\n",
|
||||
" temperature=0.7,\n",
|
||||
" top_p=1,\n",
|
||||
" frequency_penalty=0.5,\n",
|
||||
" presence_penalty=0.5,\n",
|
||||
" number_of_responses=3,\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b74a64a9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.AzureOpenAI:\n",
|
||||
" role = \"user\"\n",
|
||||
" content = \"Tomorow is going to be a great day, I can feel it. I'm going to wake up early, go for a run, and then...\"\n",
|
||||
" message = {\"role\": role, \"content\": content}\n",
|
||||
" results = await azure_chat_service.complete_chat(messages=[message], settings=az_oai_prompt_execution_settings)\n",
|
||||
" i = 0\n",
|
||||
" for result in results:\n",
|
||||
" print(f\"Result {i}: {result[0]}\")\n",
|
||||
" i += 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "98c8191d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Streaming Multiple Results\n",
|
||||
"\n",
|
||||
"Here is an example pattern if you want to stream your multiple results. Note that this is not supported for Hugging Face text completions at this time.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "26a37702",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" import os\n",
|
||||
" from IPython.display import clear_output\n",
|
||||
" import time\n",
|
||||
"\n",
|
||||
" # Determine the clear command based on OS\n",
|
||||
" clear_command = \"cls\" if os.name == \"nt\" else \"clear\"\n",
|
||||
"\n",
|
||||
" prompt = \"what is the purpose of a rubber duck?\"\n",
|
||||
" stream = oai_text_service.complete_stream(prompt=prompt, settings=oai_text_prompt_execution_settings)\n",
|
||||
" number_of_responses = oai_text_prompt_execution_settings.number_of_responses\n",
|
||||
" texts = [\"\"] * number_of_responses\n",
|
||||
"\n",
|
||||
" last_clear_time = time.time()\n",
|
||||
" clear_interval = 0.5 # seconds\n",
|
||||
"\n",
|
||||
" # Note: there are some quirks with displaying the output, which sometimes flashes and disappears.\n",
|
||||
" # This could be influenced by a few factors specific to Jupyter notebooks and asynchronous processing.\n",
|
||||
" # The following code attempts to buffer the results to avoid the output flashing on/off the screen.\n",
|
||||
"\n",
|
||||
" async for results in stream:\n",
|
||||
" current_time = time.time()\n",
|
||||
"\n",
|
||||
" # Update texts with new results\n",
|
||||
" for idx, result in enumerate(results):\n",
|
||||
" if idx < number_of_responses:\n",
|
||||
" texts[idx] += result\n",
|
||||
"\n",
|
||||
" # Clear and display output at intervals\n",
|
||||
" if current_time - last_clear_time > clear_interval:\n",
|
||||
" clear_output(wait=True)\n",
|
||||
" for idx, text in enumerate(texts):\n",
|
||||
" print(f\"Result {idx + 1}: {text}\")\n",
|
||||
" last_clear_time = current_time\n",
|
||||
"\n",
|
||||
" print(\"----------------------------------------\")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.12"
|
||||
}
|
||||
"cells": [
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "68e1c158",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Multiple Results\n"
|
||||
]
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "fb81bacd",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"In this notebook we show how you can in a single request, have the LLM model return multiple results per prompt. This is useful for running experiments where you want to evaluate the robustness of your prompt and the parameters of your config against a particular large language model.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a77bdf89",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!python -m pip install semantic-kernel==0.5.1.dev0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3f4bfee4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from services import Service\n",
|
||||
"\n",
|
||||
"# Select a service to use for this notebook (available services: OpenAI, AzureOpenAI, HuggingFace)\n",
|
||||
"selectedService = Service.OpenAI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "508ad44f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import semantic_kernel as sk\n",
|
||||
"from semantic_kernel.models.ai.chat_completion.chat_history import ChatHistory\n",
|
||||
"\n",
|
||||
"if selectedService == Service.OpenAI or selectedService == Service.AzureOpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai.prompt_execution_settings.open_ai_prompt_execution_settings import (\n",
|
||||
" OpenAITextPromptExecutionSettings,\n",
|
||||
" OpenAIChatPromptExecutionSettings,\n",
|
||||
" )\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai.prompt_execution_settings.azure_chat_prompt_execution_settings import (\n",
|
||||
" AzureChatPromptExecutionSettings,\n",
|
||||
" )\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import (\n",
|
||||
" AzureTextCompletion,\n",
|
||||
" AzureChatCompletion,\n",
|
||||
" OpenAITextCompletion,\n",
|
||||
" OpenAIChatCompletion,\n",
|
||||
" )\n",
|
||||
"if selectedService == Service.HuggingFace:\n",
|
||||
" from semantic_kernel.connectors.ai.hugging_face import HuggingFaceTextCompletion"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "d8ddffc1",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"First, we will set up the text and chat services we will be submitting prompts to.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8f8dcbc6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"kernel = sk.Kernel()\n",
|
||||
"\n",
|
||||
"# Configure Azure LLM service\n",
|
||||
"if selectedService == Service.AzureOpenAI:\n",
|
||||
" deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
|
||||
" azure_text_service = AzureTextCompletion(\n",
|
||||
" service_id=\"aoai_text\", deployment_name=\"gpt-35-turbo-instruct\", endpoint=endpoint, api_key=api_key\n",
|
||||
" ) # set the deployment name to the value of your text model (e.g. gpt-35-turbo-instruct or text-davinci-003)\n",
|
||||
" azure_chat_service = AzureChatCompletion(\n",
|
||||
" service_id=\"aoai_chat\", deployment_name=\"gpt-35-turbo\", endpoint=endpoint, api_key=api_key\n",
|
||||
" ) # set the deployment name to the value of your chat model\n",
|
||||
"\n",
|
||||
"# Configure OpenAI service\n",
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" api_key, org_id = sk.openai_settings_from_dot_env()\n",
|
||||
" oai_text_service = OpenAITextCompletion(\n",
|
||||
" service_id=\"oai_text\", ai_model_id=\"gpt-3.5-turbo-instruct\", api_key=api_key, org_id=org_id\n",
|
||||
" )\n",
|
||||
" oai_chat_service = OpenAIChatCompletion(\n",
|
||||
" service_id=\"oai_chat\", ai_model_id=\"gpt-3.5-turbo\", api_key=api_key, org_id=org_id\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"# Configure Hugging Face service\n",
|
||||
"if selectedService == Service.HuggingFace:\n",
|
||||
" hf_text_service = HuggingFaceTextCompletion(service_id=\"hf_text\", ai_model_id=\"distilgpt2\", task=\"text-generation\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "50561d82",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Next, we'll set up the completion request settings for text completion services.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "628c843e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"oai_text_prompt_execution_settings = OpenAITextPromptExecutionSettings(\n",
|
||||
" service=\"oai_text\",\n",
|
||||
" extension_data={\n",
|
||||
" \"max_tokens\": 80,\n",
|
||||
" \"temperature\": 0.7,\n",
|
||||
" \"top_p\": 1,\n",
|
||||
" \"frequency_penalty\": 0.5,\n",
|
||||
" \"presence_penalty\": 0.5,\n",
|
||||
" \"number_of_responses\": 3,\n",
|
||||
" },\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "857a9c89",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Multiple Open AI Text Completions\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e2979db8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" chat = ChatHistory()\n",
|
||||
" chat.add_user_message(\"What is the purpose of a rubber duck?\")\n",
|
||||
" results = await oai_text_service.complete(chat_history=chat, settings=oai_text_prompt_execution_settings)\n",
|
||||
" i = 1\n",
|
||||
" for result in results:\n",
|
||||
" print(f\"Result {i}: {result}\")\n",
|
||||
" i += 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "4288d09f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Multiple Azure Open AI Text Completions\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5319f14d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.AzureOpenAI:\n",
|
||||
" chat = ChatHistory()\n",
|
||||
" chat.add_user_message(\"provide me a list of possible meanings for the acronym 'ORLD'\")\n",
|
||||
" results = await azure_text_service.complete(chat_history=chat, settings=oai_text_prompt_execution_settings)\n",
|
||||
" i = 1\n",
|
||||
" for result in results:\n",
|
||||
" print(f\"Result {i}: {result}\")\n",
|
||||
" i += 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "eb548f9c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Multiple Hugging Face Text Completions\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "4a148709",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.HuggingFace:\n",
|
||||
" from semantic_kernel.connectors.ai.hugging_face.hf_prompt_execution_settings import (\n",
|
||||
" HuggingFacePromptExecutionSettings,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" hf_prompt_execution_settings = HuggingFacePromptExecutionSettings(\n",
|
||||
" service_id=\"hf_text\", extension_data={\"max_new_tokens\": 80, \"temperature\": 0.7, \"top_p\": 1}\n",
|
||||
" )"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "9525e4f3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.HuggingFace:\n",
|
||||
" prompt = \"The purpose of a rubber duck is\"\n",
|
||||
" chat = ChatHistory()\n",
|
||||
" chat.add_user_message(prompt)\n",
|
||||
" results = await hf_text_service.complete(chat_history=chat, prompt_execution_settings=hf_prompt_execution_settings)\n",
|
||||
" print(\"\".join(results))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "da632e12",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Here, we're setting up the settings for Chat completions.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e5f11e46",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"oai_chat_prompt_execution_settings = OpenAIChatPromptExecutionSettings(\n",
|
||||
" service_id=\"oai_chat\",\n",
|
||||
" max_tokens=80,\n",
|
||||
" temperature=0.7,\n",
|
||||
" top_p=1,\n",
|
||||
" frequency_penalty=0.5,\n",
|
||||
" presence_penalty=0.5,\n",
|
||||
" number_of_responses=3,\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "d6bf238e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Multiple OpenAI Chat Completions\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "dabc6a4c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" chat = ChatHistory()\n",
|
||||
" chat.add_user_message(\n",
|
||||
" \"It's a beautiful day outside, birds are singing, flowers are blooming. On days like these, kids like you...\"\n",
|
||||
" )\n",
|
||||
" results = await oai_chat_service.complete_chat(chat_history=chat, settings=oai_chat_prompt_execution_settings)\n",
|
||||
" i = 0\n",
|
||||
" for result in results:\n",
|
||||
" print(f\"Result {i+1}: {str(result)}\")\n",
|
||||
" i += 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "cdb8f740",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Multiple Azure OpenAI Chat Completions\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "66ba4767",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"az_oai_prompt_execution_settings = AzureChatPromptExecutionSettings(\n",
|
||||
" service_id=\"aoai_chat\",\n",
|
||||
" max_tokens=80,\n",
|
||||
" temperature=0.7,\n",
|
||||
" top_p=1,\n",
|
||||
" frequency_penalty=0.5,\n",
|
||||
" presence_penalty=0.5,\n",
|
||||
" number_of_responses=3,\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b74a64a9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.AzureOpenAI:\n",
|
||||
" content = \"Tomorow is going to be a great day, I can feel it. I'm going to wake up early, go for a run, and then...\"\n",
|
||||
" chat = ChatHistory()\n",
|
||||
" chat.add_user_message(content)\n",
|
||||
" results = await azure_chat_service.complete_chat(chat_history=chat, settings=az_oai_prompt_execution_settings)\n",
|
||||
" i = 0\n",
|
||||
" for result in results:\n",
|
||||
" print(f\"Result {i+1}: {str(result)}\")\n",
|
||||
" i += 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "98c8191d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Streaming Multiple Results\n",
|
||||
"\n",
|
||||
"Here is an example pattern if you want to stream your multiple results. Note that this is not supported for Hugging Face text completions at this time.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "26a37702",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" import os\n",
|
||||
" from IPython.display import clear_output\n",
|
||||
" import time\n",
|
||||
"\n",
|
||||
" # Determine the clear command based on OS\n",
|
||||
" clear_command = \"cls\" if os.name == \"nt\" else \"clear\"\n",
|
||||
"\n",
|
||||
" chat = ChatHistory()\n",
|
||||
" chat.add_user_message(\"what is the purpose of a rubber duck?\")\n",
|
||||
"\n",
|
||||
" stream = oai_text_service.complete_stream(chat_history=chat, settings=oai_text_prompt_execution_settings)\n",
|
||||
" number_of_responses = oai_text_prompt_execution_settings.number_of_responses\n",
|
||||
" texts = [\"\"] * number_of_responses\n",
|
||||
"\n",
|
||||
" last_clear_time = time.time()\n",
|
||||
" clear_interval = 0.5 # seconds\n",
|
||||
"\n",
|
||||
" # Note: there are some quirks with displaying the output, which sometimes flashes and disappears.\n",
|
||||
" # This could be influenced by a few factors specific to Jupyter notebooks and asynchronous processing.\n",
|
||||
" # The following code attempts to buffer the results to avoid the output flashing on/off the screen.\n",
|
||||
"\n",
|
||||
" async for results in stream:\n",
|
||||
" current_time = time.time()\n",
|
||||
"\n",
|
||||
" # Update texts with new results\n",
|
||||
" for idx, result in enumerate(results):\n",
|
||||
" if idx < number_of_responses:\n",
|
||||
" texts[idx] += str(result)\n",
|
||||
"\n",
|
||||
" # Clear and display output at intervals\n",
|
||||
" if current_time - last_clear_time > clear_interval:\n",
|
||||
" clear_output(wait=True)\n",
|
||||
" for idx, text in enumerate(texts):\n",
|
||||
" print(f\"Result {idx + 1}: {text}\")\n",
|
||||
" last_clear_time = current_time\n",
|
||||
"\n",
|
||||
" print(\"----------------------------------------\")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.12"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
|
||||
@@ -1,331 +1,344 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "68e1c158",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Streaming Results\n",
|
||||
"\n",
|
||||
"Here is an example pattern if you want to stream your multiple results. Note that this is not supported for Hugging Face text completions at this time.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a77bdf89",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!python -m pip install semantic-kernel==0.5.1.dev0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from services import Service\n",
|
||||
"\n",
|
||||
"# Select a service to use for this notebook (available services: OpenAI, AzureOpenAI, HuggingFace)\n",
|
||||
"selectedService = Service.AzureOpenAI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "508ad44f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import semantic_kernel as sk\n",
|
||||
"\n",
|
||||
"if selectedService == Service.OpenAI or selectedService == Service.AzureOpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai.prompt_execution_settings.open_ai_prompt_execution_settings import (\n",
|
||||
" OpenAITextPromptExecutionSettings,\n",
|
||||
" OpenAIChatPromptExecutionSettings,\n",
|
||||
" )\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai.prompt_execution_settings.azure_chat_prompt_execution_settings import (\n",
|
||||
" AzureChatPromptExecutionSettings,\n",
|
||||
" )\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import (\n",
|
||||
" AzureTextCompletion,\n",
|
||||
" AzureChatCompletion,\n",
|
||||
" OpenAITextCompletion,\n",
|
||||
" OpenAIChatCompletion,\n",
|
||||
" )\n",
|
||||
"if selectedService == Service.HuggingFace:\n",
|
||||
" from semantic_kernel.connectors.ai.hugging_face import HuggingFaceTextCompletion"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "d8ddffc1",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"First, we will set up the text and chat services we will be submitting prompts to.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8f8dcbc6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"kernel = sk.Kernel()\n",
|
||||
"\n",
|
||||
"# Configure Azure LLM service\n",
|
||||
"if selectedService == Service.AzureOpenAI:\n",
|
||||
" deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
|
||||
" azure_text_service = AzureTextCompletion(\n",
|
||||
" deployment_name=\"text-davinci-003\", endpoint=endpoint, api_key=api_key\n",
|
||||
" ) # set the deployment name to the value of your text model (e.g. gpt-35-turbo-instruct or text-davinci-003)\n",
|
||||
" azure_chat_service = AzureChatCompletion(\n",
|
||||
" deployment_name=\"gpt-35-turbo\", endpoint=endpoint, api_key=api_key\n",
|
||||
" ) # set the deployment name to the value of your chat model\n",
|
||||
"\n",
|
||||
"# Configure OpenAI service\n",
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" api_key, org_id = sk.openai_settings_from_dot_env()\n",
|
||||
" oai_text_service = OpenAITextCompletion(ai_model_id=\"gpt-3.5-turbo-instruct\", api_key=api_key, org_id=org_id)\n",
|
||||
" oai_chat_service = OpenAIChatCompletion(ai_model_id=\"gpt-3.5-turbo\", api_key=api_key, org_id=org_id)\n",
|
||||
"\n",
|
||||
"# Configure Hugging Face service\n",
|
||||
"if selectedService == Service.HuggingFace:\n",
|
||||
" hf_text_service = HuggingFaceTextCompletion(ai_model_id=\"distilgpt2\", task=\"text-generation\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "50561d82",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Next, we'll set up the completion request settings for text completion services.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "628c843e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"oai_prompt_execution_settings = OpenAITextPromptExecutionSettings(\n",
|
||||
" max_tokens=150,\n",
|
||||
" temperature=0.7,\n",
|
||||
" top_p=1,\n",
|
||||
" frequency_penalty=0.5,\n",
|
||||
" presence_penalty=0.5,\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "857a9c89",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Streaming Open AI Text Completion\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e2979db8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" prompt = \"what is the purpose of a rubber duck?\"\n",
|
||||
" stream = oai_text_service.complete_stream(prompt=prompt, settings=oai_prompt_execution_settings)\n",
|
||||
" async for text in stream:\n",
|
||||
" print(text, end=\"\") # end = \"\" to avoid newlines"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "4288d09f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Streaming Azure Open AI Text Completion\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5319f14d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.AzureOpenAI:\n",
|
||||
" prompt = \"provide me a list of possible meanings for the acronym 'ORLD'\"\n",
|
||||
" stream = azure_text_service.complete_stream(prompt=prompt, settings=oai_prompt_execution_settings)\n",
|
||||
" async for text in stream:\n",
|
||||
" print(text, end=\"\") # end = \"\" to avoid newlines"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "eb548f9c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Streaming Hugging Face Text Completion\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "be7b1c2e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.HuggingFace:\n",
|
||||
" from semantic_kernel.connectors.ai.hugging_face.hf_prompt_execution_settings import (\n",
|
||||
" HuggingFacePromptExecutionSettings,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" hf_prompt_execution_settings = HuggingFacePromptExecutionSettings(\n",
|
||||
" extension_data={\n",
|
||||
" \"max_new_tokens\": 80,\n",
|
||||
" \"top_p\": 1,\n",
|
||||
" \"eos_token_id\": 11,\n",
|
||||
" \"pad_token_id\": 0,\n",
|
||||
" }\n",
|
||||
" )"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "9525e4f3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.HuggingFace:\n",
|
||||
" prompt = \"The purpose of a rubber duck is\"\n",
|
||||
" stream = hf_text_service.complete_stream(prompt=prompt, prompt_execution_settings=hf_prompt_execution_settings)\n",
|
||||
" async for text in stream:\n",
|
||||
" print(text, end=\"\") # end = \"\" to avoid newlines"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "da632e12",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Here, we're setting up the settings for Chat completions.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e5f11e46",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"oai_chat_prompt_execution_settings = OpenAIChatPromptExecutionSettings(\n",
|
||||
" max_tokens=150,\n",
|
||||
" temperature=0.7,\n",
|
||||
" top_p=1,\n",
|
||||
" frequency_penalty=0.5,\n",
|
||||
" presence_penalty=0.5,\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "d6bf238e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Streaming OpenAI Chat Completion\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "dabc6a4c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" role = \"system\"\n",
|
||||
" content = \"You are an AI assistant that helps people find information.\"\n",
|
||||
" message = {\"role\": role, \"content\": content}\n",
|
||||
" stream = oai_chat_service.complete_chat_stream(messages=[message], settings=oai_chat_prompt_execution_settings)\n",
|
||||
" async for text in stream:\n",
|
||||
" print(text, end=\"\") # end = \"\" to avoid newlines"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "cdb8f740",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Streaming Azure OpenAI Chat Completion\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "da1e9f59",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"az_oai_chat_prompt_execution_settings = AzureChatPromptExecutionSettings(\n",
|
||||
" max_tokens=150,\n",
|
||||
" temperature=0.7,\n",
|
||||
" top_p=1,\n",
|
||||
" frequency_penalty=0.5,\n",
|
||||
" presence_penalty=0.5,\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b74a64a9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.AzureOpenAI:\n",
|
||||
" role = \"system\"\n",
|
||||
" content = \"You are an AI assistant that helps people find information.\"\n",
|
||||
" message = {\"role\": role, \"content\": content}\n",
|
||||
" stream = azure_chat_service.complete_chat_stream(messages=[message], settings=az_oai_chat_prompt_execution_settings)\n",
|
||||
" async for text in stream:\n",
|
||||
" print(text, end=\"\") # end = \"\" to avoid newlines"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.12"
|
||||
}
|
||||
"cells": [
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "68e1c158",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Streaming Results\n",
|
||||
"\n",
|
||||
"Here is an example pattern if you want to stream your multiple results. Note that this is not supported for Hugging Face text completions at this time.\n"
|
||||
]
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a77bdf89",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!python -m pip install semantic-kernel==0.5.1.dev0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from services import Service\n",
|
||||
"\n",
|
||||
"# Select a service to use for this notebook (available services: OpenAI, AzureOpenAI, HuggingFace)\n",
|
||||
"selectedService = Service.AzureOpenAI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "508ad44f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import semantic_kernel as sk\n",
|
||||
"from semantic_kernel.models.ai.chat_completion.chat_history import ChatHistory\n",
|
||||
"\n",
|
||||
"if selectedService == Service.OpenAI or selectedService == Service.AzureOpenAI:\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai.prompt_execution_settings.open_ai_prompt_execution_settings import (\n",
|
||||
" OpenAITextPromptExecutionSettings,\n",
|
||||
" OpenAIChatPromptExecutionSettings,\n",
|
||||
" )\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai.prompt_execution_settings.azure_chat_prompt_execution_settings import (\n",
|
||||
" AzureChatPromptExecutionSettings,\n",
|
||||
" )\n",
|
||||
" from semantic_kernel.connectors.ai.open_ai import (\n",
|
||||
" AzureTextCompletion,\n",
|
||||
" AzureChatCompletion,\n",
|
||||
" OpenAITextCompletion,\n",
|
||||
" OpenAIChatCompletion,\n",
|
||||
" )\n",
|
||||
"if selectedService == Service.HuggingFace:\n",
|
||||
" from semantic_kernel.connectors.ai.hugging_face import HuggingFaceTextCompletion"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "d8ddffc1",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"First, we will set up the text and chat services we will be submitting prompts to.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8f8dcbc6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"kernel = sk.Kernel()\n",
|
||||
"\n",
|
||||
"# Configure Azure LLM service\n",
|
||||
"if selectedService == Service.AzureOpenAI:\n",
|
||||
" deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()\n",
|
||||
" azure_text_service = AzureTextCompletion(\n",
|
||||
" service_id=\"aoai_text\", deployment_name=\"text-davinci-003\", endpoint=endpoint, api_key=api_key\n",
|
||||
" ) # set the deployment name to the value of your text model (e.g. gpt-35-turbo-instruct or text-davinci-003)\n",
|
||||
" azure_chat_service = AzureChatCompletion(\n",
|
||||
" service_id=\"aoai_chat\", deployment_name=\"gpt-35-turbo\", endpoint=endpoint, api_key=api_key\n",
|
||||
" ) # set the deployment name to the value of your chat model\n",
|
||||
"\n",
|
||||
"# Configure OpenAI service\n",
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" api_key, org_id = sk.openai_settings_from_dot_env()\n",
|
||||
" oai_text_service = OpenAITextCompletion(\n",
|
||||
" service_id=\"oai_text\", ai_model_id=\"gpt-3.5-turbo-instruct\", api_key=api_key, org_id=org_id\n",
|
||||
" )\n",
|
||||
" oai_chat_service = OpenAIChatCompletion(\n",
|
||||
" service_id=\"oai_chat\", ai_model_id=\"gpt-3.5-turbo\", api_key=api_key, org_id=org_id\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"# Configure Hugging Face service\n",
|
||||
"if selectedService == Service.HuggingFace:\n",
|
||||
" hf_text_service = HuggingFaceTextCompletion(ai_model_id=\"distilgpt2\", task=\"text-generation\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "50561d82",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Next, we'll set up the completion request settings for text completion services.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "628c843e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"oai_prompt_execution_settings = OpenAITextPromptExecutionSettings(\n",
|
||||
" service_id=\"oai_text\",\n",
|
||||
" max_tokens=150,\n",
|
||||
" temperature=0.7,\n",
|
||||
" top_p=1,\n",
|
||||
" frequency_penalty=0.5,\n",
|
||||
" presence_penalty=0.5,\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "857a9c89",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Streaming Open AI Text Completion\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e2979db8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" chat = ChatHistory()\n",
|
||||
" chat.add_user_message(\"What is the purpose of a rubber duck?\")\n",
|
||||
" stream = oai_text_service.complete_stream(chat_history=chat, settings=oai_prompt_execution_settings)\n",
|
||||
" async for message in stream:\n",
|
||||
" print(str(message[0]), end=\"\") # end = \"\" to avoid newlines"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "4288d09f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Streaming Azure Open AI Text Completion\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5319f14d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.AzureOpenAI:\n",
|
||||
" chat = ChatHistory()\n",
|
||||
" chat.add_user_message(\"provide me a list of possible meanings for the acronym 'ORLD'\")\n",
|
||||
" stream = azure_text_service.complete_stream(chat_history=chat, settings=oai_prompt_execution_settings)\n",
|
||||
" async for message in stream:\n",
|
||||
" print(str(message[0]), end=\"\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "eb548f9c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Streaming Hugging Face Text Completion\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "be7b1c2e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.HuggingFace:\n",
|
||||
" from semantic_kernel.connectors.ai.hugging_face.hf_prompt_execution_settings import (\n",
|
||||
" HuggingFacePromptExecutionSettings,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" hf_prompt_execution_settings = HuggingFacePromptExecutionSettings(\n",
|
||||
" service_id=\"hf_text\",\n",
|
||||
" extension_data={\n",
|
||||
" \"max_new_tokens\": 80,\n",
|
||||
" \"top_p\": 1,\n",
|
||||
" \"eos_token_id\": 11,\n",
|
||||
" \"pad_token_id\": 0,\n",
|
||||
" },\n",
|
||||
" )"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "9525e4f3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.HuggingFace:\n",
|
||||
" chat = ChatHistory()\n",
|
||||
" chat.add_user_message(\"The purpose of a rubber duck is\")\n",
|
||||
" stream = hf_text_service.complete_stream(chat_history=chat, prompt_execution_settings=hf_prompt_execution_settings)\n",
|
||||
" async for text in stream:\n",
|
||||
" print(str(text[0]), end=\"\") # end = \"\" to avoid newlines"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "da632e12",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Here, we're setting up the settings for Chat completions.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e5f11e46",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"oai_chat_prompt_execution_settings = OpenAIChatPromptExecutionSettings(\n",
|
||||
" service_id=\"oai_chat\",\n",
|
||||
" max_tokens=150,\n",
|
||||
" temperature=0.7,\n",
|
||||
" top_p=1,\n",
|
||||
" frequency_penalty=0.5,\n",
|
||||
" presence_penalty=0.5,\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "d6bf238e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Streaming OpenAI Chat Completion\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "dabc6a4c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.OpenAI:\n",
|
||||
" content = \"You are an AI assistant that helps people find information.\"\n",
|
||||
" chat = ChatHistory()\n",
|
||||
" chat.add_system_message(content)\n",
|
||||
" stream = oai_chat_service.complete_chat_stream(chat_history=chat, settings=oai_chat_prompt_execution_settings)\n",
|
||||
" async for text in stream:\n",
|
||||
" print(str(text[0]), end=\"\") # end = \"\" to avoid newlines"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"id": "cdb8f740",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Streaming Azure OpenAI Chat Completion\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "da1e9f59",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"az_oai_chat_prompt_execution_settings = AzureChatPromptExecutionSettings(\n",
|
||||
" service_id=\"aoai_chat\",\n",
|
||||
" max_tokens=150,\n",
|
||||
" temperature=0.7,\n",
|
||||
" top_p=1,\n",
|
||||
" frequency_penalty=0.5,\n",
|
||||
" presence_penalty=0.5,\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b74a64a9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if selectedService == Service.AzureOpenAI:\n",
|
||||
" content = \"You are an AI assistant that helps people find information.\"\n",
|
||||
" chat = ChatHistory()\n",
|
||||
" chat.add_system_message(content)\n",
|
||||
" chat.add_user_message(\"What is the purpose of a rubber duck?\")\n",
|
||||
" stream = azure_chat_service.complete_chat_stream(chat_history=chat, settings=az_oai_chat_prompt_execution_settings)\n",
|
||||
" async for text in stream:\n",
|
||||
" print(str(text[0]), end=\"\") # end = \"\" to avoid newlines"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.12"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
|
||||
Generated
-21
@@ -2132,16 +2132,6 @@ files = [
|
||||
{file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"},
|
||||
{file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"},
|
||||
{file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"},
|
||||
{file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"},
|
||||
{file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"},
|
||||
{file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"},
|
||||
{file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"},
|
||||
{file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"},
|
||||
{file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"},
|
||||
{file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"},
|
||||
{file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"},
|
||||
{file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"},
|
||||
{file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"},
|
||||
{file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"},
|
||||
{file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"},
|
||||
{file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"},
|
||||
@@ -4019,7 +4009,6 @@ files = [
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"},
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"},
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"},
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"},
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"},
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"},
|
||||
@@ -4027,16 +4016,8 @@ files = [
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"},
|
||||
{file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"},
|
||||
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"},
|
||||
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"},
|
||||
@@ -4053,7 +4034,6 @@ files = [
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"},
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"},
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"},
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"},
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"},
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"},
|
||||
@@ -4061,7 +4041,6 @@ files = [
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"},
|
||||
{file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
|
||||
|
||||
@@ -1,30 +1,29 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import semantic_kernel as sk
|
||||
from semantic_kernel.connectors.ai.open_ai import (
|
||||
OpenAIChatCompletion,
|
||||
)
|
||||
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
|
||||
from semantic_kernel.core_plugins import (
|
||||
FileIOPlugin,
|
||||
MathPlugin,
|
||||
TextPlugin,
|
||||
TimePlugin,
|
||||
)
|
||||
from semantic_kernel.planning import ActionPlanner
|
||||
from semantic_kernel.planners import ActionPlanner
|
||||
|
||||
|
||||
async def main():
|
||||
kernel = sk.Kernel()
|
||||
api_key, org_id = sk.openai_settings_from_dot_env()
|
||||
service_id = "chat-gpt"
|
||||
kernel.add_service(
|
||||
OpenAIChatCompletion(service_id=service_id, ai_model_id="gpt-3.5-turbo", api_key=api_key, org_id=org_id)
|
||||
)
|
||||
|
||||
kernel.add_chat_service("chat-gpt", OpenAIChatCompletion("gpt-3.5-turbo", api_key, org_id))
|
||||
kernel.import_plugin(MathPlugin(), "math")
|
||||
kernel.import_plugin(FileIOPlugin(), "fileIO")
|
||||
kernel.import_plugin(TimePlugin(), "time")
|
||||
kernel.import_plugin(TextPlugin(), "text")
|
||||
|
||||
# create an instance of action planner.
|
||||
planner = ActionPlanner(kernel)
|
||||
planner = ActionPlanner(kernel, service_id)
|
||||
|
||||
# the ask for which the action planner is going to find a relevant function.
|
||||
ask = "What is the sum of 110 and 990?"
|
||||
@@ -33,7 +32,7 @@ async def main():
|
||||
plan = await planner.create_plan(goal=ask)
|
||||
|
||||
# ask the action planner to execute the identified function.
|
||||
result = await plan.invoke()
|
||||
result = await plan.invoke(kernel)
|
||||
print(result)
|
||||
"""
|
||||
Output:
|
||||
|
||||
@@ -7,9 +7,8 @@ from dotenv import load_dotenv
|
||||
|
||||
import semantic_kernel as sk
|
||||
import semantic_kernel.connectors.ai.open_ai as sk_oai
|
||||
from semantic_kernel.connectors.ai.chat_completion_client_base import (
|
||||
ChatCompletionClientBase,
|
||||
)
|
||||
from semantic_kernel.contents.chat_history import ChatHistory
|
||||
from semantic_kernel.prompt_template.input_variable import InputVariable
|
||||
from semantic_kernel.utils.settings import azure_openai_settings_from_dot_env_as_dict
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
@@ -27,10 +26,14 @@ flowery prose.
|
||||
|
||||
kernel = sk.Kernel()
|
||||
|
||||
chat_service = sk_oai.AzureChatCompletion(**azure_openai_settings_from_dot_env_as_dict(include_api_version=True))
|
||||
kernel.add_chat_service("chat-gpt", chat_service)
|
||||
service_id = "chat-gpt"
|
||||
chat_service = sk_oai.AzureChatCompletion(
|
||||
service_id=service_id, **azure_openai_settings_from_dot_env_as_dict(include_api_version=True)
|
||||
)
|
||||
kernel.add_service(chat_service)
|
||||
|
||||
## there are three ways to create the request settings in code: # noqa: E266
|
||||
## Note: the prompt_execution_settings are a dictionary with the service_id as the key and the request settings as the value. # noqa: E501
|
||||
|
||||
## 1. create the request settings from the base class: # noqa: E266
|
||||
# from semantic_kernel.connectors.ai.chat_completion_client_base import PromptExecutionSettings
|
||||
@@ -39,36 +42,36 @@ kernel.add_chat_service("chat-gpt", chat_service)
|
||||
|
||||
## 2. create the request settings directly for the service you are using: # noqa: E266
|
||||
# req_settings = sk_oai.AzureChatPromptExecutionSettings(max_tokens=2000, temperature=0.7, top_p=0.8)
|
||||
## The second method is useful when you are using a single service, and you want to have type checking on the request settings or when you are using multiple instances of the same type of service, for instance gpt-35-turbo and gpt-4, both in openai and both for chat. # noqa: E501 E266
|
||||
|
||||
## The second method is useful when you are using a single service, and you want to have type checking on the request settings or when you are using multiple instances of the same type of service, for instance gpt-35-turbo and gpt-4, both in openai and both for chat. # noqa: E501 E266
|
||||
## 3. create the request settings from the kernel based on the registered service class: # noqa: E266
|
||||
req_settings = kernel.get_prompt_execution_settings_from_service(ChatCompletionClientBase, "chat-gpt")
|
||||
req_settings = kernel.get_service(service_id).get_prompt_execution_settings_class()(service_id=service_id)
|
||||
req_settings.max_tokens = 2000
|
||||
req_settings.temperature = 0.7
|
||||
req_settings.top_p = 0.8
|
||||
## The third method is the most specific as the returned request settings class is the one that is registered for the service and has some fields already filled in, like the service_id and ai_model_id. # noqa: E501 E266
|
||||
|
||||
prompt_template_config = sk.PromptTemplateConfig(
|
||||
template=system_message
|
||||
+ """ Summarize the on-going chat history: {{$chat_history}} and respond to this statement: {{$request}}""",
|
||||
name="chat",
|
||||
input_variables=[
|
||||
InputVariable(name="request", description="The user input", is_required=True),
|
||||
InputVariable(name="chat_history", description="The history of the conversation", is_required=True),
|
||||
],
|
||||
execution_settings=req_settings,
|
||||
)
|
||||
|
||||
prompt_config = sk.PromptTemplateConfig(execution_settings=req_settings)
|
||||
history = ChatHistory()
|
||||
history.add_user_message("Hi there, who are you?")
|
||||
history.add_assistant_message("I am Mosscap, a chat bot. I'm trying to figure out what people need.")
|
||||
|
||||
prompt_template = sk.ChatPromptTemplate("{{$user_input}}", kernel.prompt_template_engine, prompt_config)
|
||||
|
||||
prompt_template.add_system_message(system_message)
|
||||
prompt_template.add_user_message("Hi there, who are you?")
|
||||
prompt_template.add_assistant_message("I am Mosscap, a chat bot. I'm trying to figure out what people need.")
|
||||
|
||||
function_config = sk.SemanticFunctionConfig(prompt_config, prompt_template)
|
||||
chat_function = kernel.register_semantic_function("ChatBot", "Chat", function_config)
|
||||
chat_function = kernel.create_function_from_prompt(prompt_template_config=prompt_template_config)
|
||||
|
||||
|
||||
async def chat() -> bool:
|
||||
context_vars = sk.ContextVariables()
|
||||
try:
|
||||
user_input = input("User:> ")
|
||||
if user_input == "":
|
||||
context_vars["user_input"] = "what is openai?"
|
||||
else:
|
||||
context_vars["user_input"] = user_input
|
||||
except KeyboardInterrupt:
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
@@ -80,16 +83,26 @@ async def chat() -> bool:
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
|
||||
stream = False
|
||||
stream = True
|
||||
if stream:
|
||||
answer = kernel.run_stream(chat_function, input_vars=context_vars)
|
||||
answer = kernel.invoke_stream(
|
||||
chat_function,
|
||||
request=user_input,
|
||||
chat_history=history,
|
||||
)
|
||||
print("Mosscap:> ", end="")
|
||||
async for message in answer:
|
||||
print(str(message[0]), end="")
|
||||
print("\n")
|
||||
return True
|
||||
answer = await kernel.run(chat_function, input_vars=context_vars)
|
||||
answer = await kernel.invoke(
|
||||
chat_function,
|
||||
request=user_input,
|
||||
chat_history=history,
|
||||
)
|
||||
print(f"Mosscap:> {answer}")
|
||||
history.add_user_message(user_input)
|
||||
history.add_assistant_message(str(answer))
|
||||
return True
|
||||
|
||||
|
||||
|
||||
@@ -4,12 +4,19 @@ import asyncio
|
||||
|
||||
import semantic_kernel as sk
|
||||
import semantic_kernel.connectors.ai.open_ai as sk_oai
|
||||
from semantic_kernel.connectors.ai.open_ai.contents.azure_streaming_chat_message_content import (
|
||||
AzureStreamingChatMessageContent,
|
||||
)
|
||||
from semantic_kernel.connectors.ai.open_ai.prompt_execution_settings.azure_chat_prompt_execution_settings import (
|
||||
AzureAISearchDataSources,
|
||||
AzureChatPromptExecutionSettings,
|
||||
AzureDataSources,
|
||||
ExtraBody,
|
||||
)
|
||||
from semantic_kernel.contents.chat_history import ChatHistory
|
||||
from semantic_kernel.functions.kernel_arguments import KernelArguments
|
||||
from semantic_kernel.prompt_template.input_variable import InputVariable
|
||||
from semantic_kernel.prompt_template.prompt_template_config import PromptTemplateConfig
|
||||
|
||||
kernel = sk.Kernel()
|
||||
|
||||
@@ -37,35 +44,44 @@ azure_ai_search_settings["fieldsMapping"] = {
|
||||
az_source = AzureAISearchDataSources(**azure_ai_search_settings)
|
||||
az_data = AzureDataSources(type="AzureCognitiveSearch", parameters=az_source)
|
||||
extra = ExtraBody(dataSources=[az_data])
|
||||
req_settings = AzureChatPromptExecutionSettings(extra_body=extra)
|
||||
prompt_config = sk.PromptTemplateConfig(execution_settings=req_settings)
|
||||
req_settings = AzureChatPromptExecutionSettings(service_id="default", extra_body=extra)
|
||||
|
||||
# When using data, set use_extensions=True and use the 2023-12-01-preview API version.
|
||||
chat_service = sk_oai.AzureChatCompletion(
|
||||
service_id="chat-gpt",
|
||||
deployment_name=deployment,
|
||||
api_key=api_key,
|
||||
endpoint=endpoint,
|
||||
api_version="2023-12-01-preview",
|
||||
use_extensions=True,
|
||||
)
|
||||
kernel.add_chat_service("chat-gpt", chat_service)
|
||||
kernel.add_service(chat_service)
|
||||
|
||||
prompt_template = sk.ChatPromptTemplate("{{$user_input}}", kernel.prompt_template_engine, prompt_config)
|
||||
prompt_template_config = PromptTemplateConfig(
|
||||
template="{{$user_input}}",
|
||||
name="chat",
|
||||
template_format="semantic-kernel",
|
||||
input_variables=[
|
||||
InputVariable(name="request", description="The user input", is_required=True),
|
||||
],
|
||||
execution_settings={"default": req_settings},
|
||||
)
|
||||
|
||||
prompt_template.add_user_message("Hi there, who are you?")
|
||||
prompt_template.add_assistant_message("I am an AI assistant here to answer your questions.")
|
||||
chat = ChatHistory()
|
||||
|
||||
function_config = sk.SemanticFunctionConfig(prompt_config, prompt_template)
|
||||
chat_function = kernel.register_semantic_function("ChatBot", "Chat", function_config)
|
||||
context = kernel.create_new_context()
|
||||
chat.add_user_message("Hi there, who are you?")
|
||||
chat.add_assistant_message("I am an AI assistant here to answer your questions.")
|
||||
|
||||
arguments = KernelArguments()
|
||||
|
||||
chat_function = kernel.create_function_from_prompt(
|
||||
plugin_name="ChatBot", function_name="Chat", prompt_template_config=prompt_template_config
|
||||
)
|
||||
|
||||
|
||||
async def chat() -> bool:
|
||||
context_vars = sk.ContextVariables()
|
||||
|
||||
try:
|
||||
user_input = input("User:> ")
|
||||
context_vars["user_input"] = user_input
|
||||
except KeyboardInterrupt:
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
@@ -80,14 +96,20 @@ async def chat() -> bool:
|
||||
# Non streaming
|
||||
# answer = await kernel.run(chat_function, input_vars=context_vars)
|
||||
# print(f"Assistant:> {answer}")
|
||||
arguments = KernelArguments(user_input=user_input, execution_settings=req_settings)
|
||||
|
||||
answer = kernel.run_stream(chat_function, input_vars=context_vars, input_context=context)
|
||||
full_message = None
|
||||
print("Assistant:> ", end="")
|
||||
async for message in answer:
|
||||
print(message, end="")
|
||||
async for message in kernel.invoke_stream(chat_function, arguments=arguments):
|
||||
print(str(message[0]), end="")
|
||||
full_message = message[0] if not full_message else full_message + message[0]
|
||||
chat.add_assistant_message(str(full_message))
|
||||
print("\n")
|
||||
|
||||
# The tool message containing cited sources is available in the context
|
||||
print(f"Tool:> {context.objects.get('tool_message')}")
|
||||
if isinstance(full_message, AzureStreamingChatMessageContent):
|
||||
chat.add_function_response_message(name="tool", content=full_message.tool_message)
|
||||
print(f"Tool:> {full_message.tool_message}")
|
||||
return True
|
||||
|
||||
|
||||
|
||||
+45
-33
@@ -2,7 +2,6 @@
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from typing import Tuple
|
||||
|
||||
import semantic_kernel as sk
|
||||
import semantic_kernel.connectors.ai.open_ai as sk_oai
|
||||
@@ -12,14 +11,15 @@ from semantic_kernel.connectors.ai.open_ai.prompt_execution_settings.azure_chat_
|
||||
AzureDataSources,
|
||||
ExtraBody,
|
||||
)
|
||||
from semantic_kernel.connectors.ai.open_ai.semantic_functions.open_ai_chat_prompt_template import (
|
||||
OpenAIChatPromptTemplate,
|
||||
)
|
||||
from semantic_kernel.connectors.ai.open_ai.utils import (
|
||||
chat_completion_with_function_call,
|
||||
chat_completion_with_tool_call,
|
||||
get_tool_call_object,
|
||||
)
|
||||
from semantic_kernel.contents.chat_history import ChatHistory
|
||||
from semantic_kernel.core_plugins.time_plugin import TimePlugin
|
||||
from semantic_kernel.functions.kernel_arguments import KernelArguments
|
||||
from semantic_kernel.prompt_template.input_variable import InputVariable
|
||||
from semantic_kernel.prompt_template.prompt_template_config import PromptTemplateConfig
|
||||
|
||||
kernel = sk.Kernel()
|
||||
|
||||
@@ -31,7 +31,7 @@ azure_ai_search_settings = sk.azure_aisearch_settings_from_dot_env_as_dict()
|
||||
az_source = AzureAISearchDataSources(**azure_ai_search_settings)
|
||||
az_data = AzureDataSources(type="AzureCognitiveSearch", parameters=az_source)
|
||||
extra = ExtraBody(dataSources=[az_data])
|
||||
req_settings = AzureChatPromptExecutionSettings(extra_body=extra)
|
||||
req_settings = AzureChatPromptExecutionSettings(service_id="chat-gpt", extra_body=extra, tool_choice="auto")
|
||||
|
||||
# For example, AI Search index may contain the following document:
|
||||
|
||||
@@ -40,21 +40,21 @@ req_settings = AzureChatPromptExecutionSettings(extra_body=extra)
|
||||
# groundbreaking phenomenon in glaciology that could potentially reshape our understanding of climate change.
|
||||
|
||||
chat_service = sk_oai.AzureChatCompletion(
|
||||
service_id="chat-gpt",
|
||||
deployment_name=deployment,
|
||||
api_key=api_key,
|
||||
endpoint=endpoint,
|
||||
api_version="2023-12-01-preview",
|
||||
use_extensions=True,
|
||||
)
|
||||
kernel.add_chat_service(
|
||||
"chat-gpt",
|
||||
kernel.add_service(
|
||||
chat_service,
|
||||
)
|
||||
|
||||
plugins_directory = os.path.join(__file__, "../../../../samples/plugins")
|
||||
# adding plugins to the kernel
|
||||
# the joke plugin in the FunPlugins is a semantic plugin and has the function calling disabled.
|
||||
kernel.import_semantic_plugin_from_directory(plugins_directory, "FunPlugin")
|
||||
kernel.import_plugin_from_prompt_directory("chat-gpt", plugins_directory, "FunPlugin")
|
||||
# the math plugin is a core plugin and has the function calling enabled.
|
||||
kernel.import_plugin(TimePlugin(), plugin_name="time")
|
||||
|
||||
@@ -63,58 +63,70 @@ kernel.import_plugin(TimePlugin(), plugin_name="time")
|
||||
# if you only want to use a specific tool, set the name of that tool in this parameter,
|
||||
# the format for that is 'PluginName-FunctionName', (i.e. 'math-Add').
|
||||
# if the model or api version do not support this you will get an error.
|
||||
req_settings.tool_choice = "auto"
|
||||
prompt_config = sk.PromptTemplateConfig(execution_settings=req_settings)
|
||||
prompt_template = OpenAIChatPromptTemplate("{{$user_input}}", kernel.prompt_template_engine, prompt_config)
|
||||
prompt_template.add_user_message("Hi there, who are you?")
|
||||
prompt_template.add_assistant_message("I am an AI assistant here to answer your questions.")
|
||||
prompt_template_config = PromptTemplateConfig(
|
||||
template="{{$user_input}}",
|
||||
name="chat",
|
||||
template_format="semantic-kernel",
|
||||
input_variables=[
|
||||
InputVariable(name="history", description="The history of the conversation", is_required=True),
|
||||
InputVariable(name="request", description="The user input", is_required=True),
|
||||
],
|
||||
execution_settings=req_settings,
|
||||
)
|
||||
|
||||
function_config = sk.SemanticFunctionConfig(prompt_config, prompt_template)
|
||||
chat_function = kernel.register_semantic_function("ChatBot", "Chat", function_config)
|
||||
history = ChatHistory()
|
||||
|
||||
history.add_user_message("Hi there, who are you?")
|
||||
history.add_assistant_message("I am an AI assistant here to answer your questions.")
|
||||
|
||||
arguments = KernelArguments()
|
||||
|
||||
chat_function = kernel.create_function_from_prompt(
|
||||
plugin_name="ChatBot", function_name="Chat", prompt_template_config=prompt_template_config
|
||||
)
|
||||
|
||||
# calling the chat, you could add a overloaded version of the settings here,
|
||||
# to enable or disable function calling or set the function calling to a specific plugin.
|
||||
# see the openai_function_calling example for how to use this with a unrelated function definition
|
||||
filter = {"exclude_plugin": ["ChatBot"]}
|
||||
functions = get_tool_call_object(kernel, filter)
|
||||
req_settings.tools = get_tool_call_object(kernel, filter)
|
||||
|
||||
|
||||
async def chat(context: sk.KernelContext) -> Tuple[bool, sk.KernelContext]:
|
||||
async def chat() -> bool:
|
||||
try:
|
||||
user_input = input("User:> ")
|
||||
context.variables["user_input"] = user_input
|
||||
except KeyboardInterrupt:
|
||||
print("\n\nExiting chat...")
|
||||
return False, None
|
||||
return False
|
||||
except EOFError:
|
||||
print("\n\nExiting chat...")
|
||||
return False, None
|
||||
return False
|
||||
|
||||
if user_input == "exit":
|
||||
print("\n\nExiting chat...")
|
||||
return False, None
|
||||
return False
|
||||
|
||||
context = await chat_completion_with_function_call(
|
||||
kernel,
|
||||
chat_plugin_name="ChatBot",
|
||||
chat_function_name="Chat",
|
||||
context=context,
|
||||
functions=functions,
|
||||
arguments = KernelArguments(request=user_input, execution_settings=req_settings)
|
||||
answer = await chat_completion_with_tool_call(
|
||||
kernel=kernel,
|
||||
arguments=arguments,
|
||||
chat_function=chat_function,
|
||||
)
|
||||
print(f"Assistant:> {context.result}")
|
||||
return True, context
|
||||
print(f"Mosscap:> {answer}")
|
||||
history.add_user_message(user_input)
|
||||
history.add_assistant_message(str(answer))
|
||||
return True
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
chatting = True
|
||||
context = kernel.create_new_context()
|
||||
print(
|
||||
"Welcome to the chat bot!\
|
||||
\n Type 'exit' to exit.\
|
||||
\n Try a time question to see the function calling in action (i.e. what day is it?)."
|
||||
)
|
||||
chatting = True
|
||||
while chatting:
|
||||
chatting, context = await chat(context)
|
||||
chatting = await chat()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
+47
-17
@@ -4,12 +4,22 @@ import asyncio
|
||||
|
||||
import semantic_kernel as sk
|
||||
import semantic_kernel.connectors.ai.open_ai as sk_oai
|
||||
from semantic_kernel.connectors.ai.open_ai.contents.azure_streaming_chat_message_content import (
|
||||
AzureStreamingChatMessageContent,
|
||||
)
|
||||
from semantic_kernel.connectors.ai.open_ai.contents.open_ai_chat_message_content import OpenAIChatMessageContent
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat_completion.tool_calls import ToolCall
|
||||
from semantic_kernel.connectors.ai.open_ai.prompt_execution_settings.azure_chat_prompt_execution_settings import (
|
||||
AzureAISearchDataSources,
|
||||
AzureChatPromptExecutionSettings,
|
||||
AzureDataSources,
|
||||
ExtraBody,
|
||||
)
|
||||
from semantic_kernel.contents.chat_history import ChatHistory
|
||||
from semantic_kernel.contents.chat_role import ChatRole
|
||||
from semantic_kernel.functions.kernel_arguments import KernelArguments
|
||||
from semantic_kernel.prompt_template.input_variable import InputVariable
|
||||
from semantic_kernel.prompt_template.prompt_template_config import PromptTemplateConfig
|
||||
|
||||
kernel = sk.Kernel()
|
||||
|
||||
@@ -42,36 +52,45 @@ azure_ai_search_settings["queryType"] = "vector"
|
||||
az_source = AzureAISearchDataSources(**azure_ai_search_settings)
|
||||
az_data = AzureDataSources(type="AzureCognitiveSearch", parameters=az_source)
|
||||
extra = ExtraBody(dataSources=[az_data])
|
||||
req_settings = AzureChatPromptExecutionSettings(extra_body=extra)
|
||||
prompt_config = sk.PromptTemplateConfig(execution_settings=req_settings)
|
||||
req_settings = AzureChatPromptExecutionSettings(service_id="default", extra_body=extra)
|
||||
|
||||
# When using data, set use_extensions=True and use the 2023-12-01-preview API version.
|
||||
chat_service = sk_oai.AzureChatCompletion(
|
||||
service_id="chat-gpt",
|
||||
deployment_name=deployment,
|
||||
api_key=api_key,
|
||||
endpoint=endpoint,
|
||||
api_version="2023-12-01-preview",
|
||||
use_extensions=True,
|
||||
)
|
||||
kernel.add_chat_service("chat-gpt", chat_service)
|
||||
kernel.add_service(chat_service)
|
||||
|
||||
prompt_template_config = PromptTemplateConfig(
|
||||
template="{{$user_input}}",
|
||||
name="chat",
|
||||
template_format="semantic-kernel",
|
||||
input_variables=[
|
||||
InputVariable(name="chat", description="The history of the conversation", is_required=True, default=""),
|
||||
InputVariable(name="request", description="The user input", is_required=True),
|
||||
],
|
||||
execution_settings={"default": req_settings},
|
||||
)
|
||||
|
||||
prompt_template = sk.ChatPromptTemplate("{{$user_input}}", kernel.prompt_template_engine, prompt_config)
|
||||
chat = ChatHistory()
|
||||
|
||||
prompt_template.add_user_message("Hi there, who are you?")
|
||||
prompt_template.add_assistant_message("I am an AI assistant here to answer your questions.")
|
||||
chat.add_user_message("Hi there, who are you?")
|
||||
chat.add_assistant_message("I am an AI assistant here to answer your questions.")
|
||||
|
||||
function_config = sk.SemanticFunctionConfig(prompt_config, prompt_template)
|
||||
chat_function = kernel.register_semantic_function("ChatBot", "Chat", function_config)
|
||||
context = kernel.create_new_context()
|
||||
arguments = KernelArguments()
|
||||
|
||||
chat_function = kernel.create_function_from_prompt(
|
||||
plugin_name="ChatBot", function_name="Chat", prompt_template_config=prompt_template_config
|
||||
)
|
||||
|
||||
|
||||
async def chat() -> bool:
|
||||
context_vars = sk.ContextVariables()
|
||||
|
||||
try:
|
||||
user_input = input("User:> ")
|
||||
context_vars["user_input"] = user_input
|
||||
except KeyboardInterrupt:
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
@@ -83,17 +102,28 @@ async def chat() -> bool:
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
|
||||
arguments = KernelArguments(user_input=user_input, execution_settings=req_settings)
|
||||
# Non streaming
|
||||
# answer = await kernel.run(chat_function, input_vars=context_vars)
|
||||
# answer = await kernel.invoke(chat_function, input_vars=context_vars)
|
||||
# print(f"Assistant:> {answer}")
|
||||
arguments = KernelArguments(user_input=user_input, execution_settings=req_settings)
|
||||
|
||||
answer = kernel.run_stream(chat_function, input_vars=context_vars, input_context=context)
|
||||
full_message = None
|
||||
print("Assistant:> ", end="")
|
||||
async for message in answer:
|
||||
print(message, end="")
|
||||
async for message in kernel.invoke_stream(chat_function, arguments=arguments):
|
||||
print(str(message[0]), end="")
|
||||
full_message = message[0] if not full_message else full_message + message[0]
|
||||
chat.add_assistant_message(str(full_message))
|
||||
print("\n")
|
||||
# The tool message containing cited sources is available in the context
|
||||
print(f"Tool:> {context.objects.get('tool_message')}")
|
||||
if isinstance(full_message, AzureStreamingChatMessageContent):
|
||||
tool_call = ToolCall(full_message.tool_message)
|
||||
chat.add_message(
|
||||
role=ChatRole.TOOL,
|
||||
content=full_message,
|
||||
metadata={OpenAIChatMessageContent.ToolIdProperty: tool_call.function.name},
|
||||
)
|
||||
print(f"Tool:> {full_message.tool_message}")
|
||||
return True
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
import semantic_kernel as sk
|
||||
import semantic_kernel.connectors.ai.open_ai as sk_oai
|
||||
from semantic_kernel.connectors.search_engine import BingConnector
|
||||
from semantic_kernel.core_plugins import WebSearchEnginePlugin
|
||||
from semantic_kernel.functions.kernel_arguments import KernelArguments
|
||||
from semantic_kernel.prompt_template.kernel_prompt_template import KernelPromptTemplate
|
||||
from semantic_kernel.prompt_template.prompt_template_config import PromptTemplateConfig
|
||||
|
||||
|
||||
async def example1(kernel: sk.Kernel, search_plugin_name: str):
|
||||
print("======== Bing and Google Search Plugins ========")
|
||||
|
||||
question = "What's the largest building in the world?"
|
||||
function = kernel.plugins[search_plugin_name]["search"]
|
||||
result = await kernel.invoke(function, query=question)
|
||||
|
||||
print(question)
|
||||
print(f"----{search_plugin_name}----")
|
||||
print(result)
|
||||
|
||||
|
||||
async def example2(kernel: sk.Kernel, service_id: str):
|
||||
print("======== Use the Search Plugin to Answer User Questions ========")
|
||||
|
||||
prompt = """
|
||||
Answer questions only when you know the facts or the information is provided.
|
||||
When you don't have sufficient information you reply with a list of commands to find the information needed.
|
||||
When answering multiple questions, use a bullet point list.
|
||||
Note: make sure single and double quotes are escaped using a backslash char.
|
||||
|
||||
[COMMANDS AVAILABLE]
|
||||
- bing.search
|
||||
|
||||
[INFORMATION PROVIDED]
|
||||
{{ $externalInformation }}
|
||||
|
||||
[EXAMPLE 1]
|
||||
Question: what's the biggest lake in Italy?
|
||||
Answer: Lake Garda, also known as Lago di Garda.
|
||||
|
||||
[EXAMPLE 2]
|
||||
Question: what's the biggest lake in Italy? What's the smallest positive number?
|
||||
Answer:
|
||||
* Lake Garda, also known as Lago di Garda.
|
||||
* The smallest positive number is 1.
|
||||
|
||||
[EXAMPLE 3]
|
||||
Question: what's Ferrari stock price? Who is the current number one female tennis player in the world?
|
||||
Answer:
|
||||
{{ '{{' }} bing.search ""what\\'s Ferrari stock price?"" {{ '}}' }}.
|
||||
{{ '{{' }} bing.search ""Who is the current number one female tennis player in the world?"" {{ '}}' }}.
|
||||
|
||||
[END OF EXAMPLES]
|
||||
|
||||
[TASK]
|
||||
Question: {{ $question }}.
|
||||
Answer:
|
||||
"""
|
||||
question = "Who is the most followed person on TikTok right now? What's the exchange rate EUR:USD?"
|
||||
print(question)
|
||||
|
||||
oracle = kernel.create_function_from_prompt(
|
||||
template=prompt,
|
||||
execution_settings=sk_oai.OpenAIChatPromptExecutionSettings(
|
||||
service_id=service_id, max_tokens=150, temperature=0, top_p=1
|
||||
),
|
||||
)
|
||||
answer = await kernel.invoke(
|
||||
oracle,
|
||||
question=question,
|
||||
externalInformation="",
|
||||
)
|
||||
|
||||
result = str(answer)
|
||||
|
||||
if "bing.search" in result:
|
||||
prompt_template = KernelPromptTemplate(PromptTemplateConfig(template=result))
|
||||
|
||||
print("--- Fetching information from Bing... ---")
|
||||
information = await prompt_template.render(kernel, KernelArguments())
|
||||
|
||||
print("Information found:\n")
|
||||
print(information)
|
||||
|
||||
answer = await kernel.invoke(oracle, question=question, externalInformation=information)
|
||||
print("\n---- Oracle's Answer ----:\n")
|
||||
print(answer)
|
||||
else:
|
||||
print("AI had all of the information, there was no need to query Bing.")
|
||||
|
||||
|
||||
async def main():
|
||||
kernel = sk.Kernel()
|
||||
|
||||
model = "gpt-3.5-turbo-1106"
|
||||
service_id = model
|
||||
|
||||
api_key, org_id = sk.openai_settings_from_dot_env()
|
||||
kernel.add_service(
|
||||
sk_oai.OpenAIChatCompletion(service_id=service_id, ai_model_id=model, api_key=api_key, org_id=org_id),
|
||||
)
|
||||
|
||||
bing_api_key = sk.bing_search_settings_from_dot_env()
|
||||
assert bing_api_key is not None
|
||||
|
||||
bing_connector = BingConnector(api_key=bing_api_key)
|
||||
bing = WebSearchEnginePlugin(bing_connector)
|
||||
kernel.import_plugin(bing, "bing")
|
||||
|
||||
await example1(kernel, "bing")
|
||||
await example2(kernel, service_id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -1,3 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import os
|
||||
|
||||
from dotenv import load_dotenv
|
||||
@@ -13,9 +15,10 @@ load_dotenv()
|
||||
async def main():
|
||||
kernel = sk.Kernel()
|
||||
deployment, key, endpoint, api_version = sk.azure_openai_settings_from_dot_env(include_api_version=True)
|
||||
kernel.add_chat_service(
|
||||
"chat-gpt",
|
||||
service_id = "chat-gpt"
|
||||
kernel.add_service(
|
||||
AzureChatCompletion(
|
||||
service_id=service_id,
|
||||
deployment_name=deployment,
|
||||
api_key=key,
|
||||
endpoint=endpoint,
|
||||
@@ -25,31 +28,40 @@ async def main():
|
||||
connector = BingConnector(api_key=os.getenv("BING_API_KEY"))
|
||||
web_plugin = kernel.import_plugin(WebSearchEnginePlugin(connector), "WebSearch")
|
||||
|
||||
prompt = "Who is Leonardo DiCaprio's current girlfriend?"
|
||||
search = web_plugin["searchAsync"]
|
||||
result = await search.invoke(prompt)
|
||||
print(result)
|
||||
print("---------------- Question 1 -----------------\n")
|
||||
|
||||
"""
|
||||
Output:
|
||||
["Celebrity Celebrity News Everything You Need to Know About Leonardo DiCaprio and Camila Morrone's
|
||||
Relationship From the beginning of their romance to today, we track their relationship here. By..."]
|
||||
"""
|
||||
query = "Which country receives the most rain per year?"
|
||||
search = web_plugin["search"]
|
||||
result = await kernel.invoke(search, query=query)
|
||||
print(f"Question: {query}\n")
|
||||
print(f"Answer: {result}\n")
|
||||
|
||||
print("---------------- Question 2 -----------------\n")
|
||||
|
||||
prompt = """
|
||||
Answer the question using only the data that is provided in the data section.
|
||||
Do not use any prior knowledge to answer the question.
|
||||
Data: {{WebSearch.SearchAsync "What is semantic kernel?"}}
|
||||
Question: What is semantic kernel?
|
||||
Data: {{WebSearch.search "What is semantic kernel?"}}
|
||||
Question: {{$question}}?
|
||||
Answer:
|
||||
"""
|
||||
|
||||
qna = kernel.create_semantic_function(prompt, temperature=0.2)
|
||||
context = kernel.create_new_context()
|
||||
context["num_results"] = "10"
|
||||
context["offset"] = "0"
|
||||
result = await qna.invoke(context=context)
|
||||
print(result)
|
||||
req_settings = kernel.get_service("chat-gpt").get_prompt_execution_settings_class()(service_id=service_id)
|
||||
req_settings.temperature = 0.2
|
||||
|
||||
prompt_template_config = sk.PromptTemplateConfig(
|
||||
template=prompt,
|
||||
name="qna",
|
||||
template_format="semantic-kernel",
|
||||
execution_settings=req_settings,
|
||||
)
|
||||
|
||||
question = "What is Semantic Kernel?"
|
||||
qna = kernel.create_function_from_prompt(prompt_template_config=prompt_template_config)
|
||||
result = await qna.invoke(kernel, question=question, num_results=10, offset=0)
|
||||
|
||||
print(f"Question: {question}\n")
|
||||
print(f"Answer: {result}\n")
|
||||
|
||||
"""
|
||||
Output:
|
||||
|
||||
@@ -4,13 +4,17 @@ import asyncio
|
||||
|
||||
import semantic_kernel as sk
|
||||
import semantic_kernel.connectors.ai.open_ai as sk_oai
|
||||
from semantic_kernel.contents.chat_history import ChatHistory
|
||||
from semantic_kernel.prompt_template.input_variable import InputVariable
|
||||
from semantic_kernel.prompt_template.prompt_template_config import PromptTemplateConfig
|
||||
|
||||
sk_prompt = """
|
||||
prompt = """
|
||||
ChatBot can have a conversation with you about any topic.
|
||||
It can give explicit instructions or say 'I don't know'
|
||||
when it doesn't know the answer.
|
||||
|
||||
{{$chat_history}}
|
||||
|
||||
User:> {{$user_input}}
|
||||
ChatBot:>
|
||||
"""
|
||||
@@ -18,20 +22,48 @@ ChatBot:>
|
||||
kernel = sk.Kernel()
|
||||
|
||||
api_key, org_id = sk.openai_settings_from_dot_env()
|
||||
kernel.add_chat_service("chat-gpt", sk_oai.OpenAIChatCompletion("gpt-3.5-turbo", api_key, org_id))
|
||||
service_id = "chat-gpt"
|
||||
kernel.add_service(
|
||||
sk_oai.OpenAIChatCompletion(service_id=service_id, ai_model_id="gpt-3.5-turbo-1106", api_key=api_key, org_id=org_id)
|
||||
)
|
||||
|
||||
prompt_config = sk.PromptTemplateConfig.from_execution_settings(max_tokens=2000, temperature=0.7, top_p=0.4)
|
||||
settings = kernel.get_service(service_id).get_prompt_execution_settings_class()(service_id=service_id)
|
||||
settings.max_tokens = 2000
|
||||
settings.temperature = 0.7
|
||||
settings.top_p = 0.8
|
||||
|
||||
prompt_template = sk.PromptTemplate(sk_prompt, kernel.prompt_template_engine, prompt_config)
|
||||
prompt_template_config = PromptTemplateConfig(
|
||||
template=prompt,
|
||||
name="chat",
|
||||
template_format="semantic-kernel",
|
||||
input_variables=[
|
||||
InputVariable(
|
||||
name="user_input",
|
||||
description="The user input",
|
||||
is_required=True,
|
||||
default="",
|
||||
),
|
||||
InputVariable(
|
||||
name="chat_history",
|
||||
description="The history of the conversation",
|
||||
is_required=True,
|
||||
),
|
||||
],
|
||||
execution_settings=settings,
|
||||
)
|
||||
|
||||
function_config = sk.SemanticFunctionConfig(prompt_config, prompt_template)
|
||||
chat_function = kernel.register_semantic_function("ChatBot", "Chat", function_config)
|
||||
chat_history = ChatHistory()
|
||||
chat_history.add_user_message("Hi there, who are you?")
|
||||
chat_history.add_assistant_message("I am Mosscap, a chat bot. I'm trying to figure out what people need")
|
||||
|
||||
chat_function = kernel.create_function_from_prompt(
|
||||
plugin_name="ChatBot", function_name="Chat", prompt_template_config=prompt_template_config
|
||||
)
|
||||
|
||||
|
||||
async def chat(context_vars: sk.ContextVariables) -> bool:
|
||||
async def chat(chat_history: ChatHistory) -> bool:
|
||||
try:
|
||||
user_input = input("User:> ")
|
||||
context_vars["user_input"] = user_input
|
||||
except KeyboardInterrupt:
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
@@ -43,20 +75,18 @@ async def chat(context_vars: sk.ContextVariables) -> bool:
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
|
||||
answer = await kernel.run(chat_function, input_vars=context_vars)
|
||||
context_vars["chat_history"] += f"\nUser:> {user_input}\nChatBot:> {answer}\n"
|
||||
answer = await kernel.invoke(chat_function, user_input=user_input, chat_history=chat_history)
|
||||
chat_history.add_user_message(user_input)
|
||||
chat_history.add_assistant_message(str(answer))
|
||||
|
||||
print(f"ChatBot:> {answer}")
|
||||
return True
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
context = sk.ContextVariables()
|
||||
context["chat_history"] = ""
|
||||
|
||||
chatting = True
|
||||
while chatting:
|
||||
chatting = await chat(context)
|
||||
chatting = await chat(chat_history)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -4,6 +4,13 @@ import asyncio
|
||||
|
||||
import semantic_kernel as sk
|
||||
import semantic_kernel.connectors.ai.open_ai as sk_oai
|
||||
from semantic_kernel.connectors.ai.chat_completion_client_base import (
|
||||
ChatCompletionClientBase,
|
||||
)
|
||||
from semantic_kernel.contents.chat_history import ChatHistory
|
||||
from semantic_kernel.functions.kernel_arguments import KernelArguments
|
||||
from semantic_kernel.prompt_template.input_variable import InputVariable
|
||||
from semantic_kernel.prompt_template.prompt_template_config import PromptTemplateConfig
|
||||
|
||||
system_message = """
|
||||
You are a chat bot. Your name is Mosscap and
|
||||
@@ -17,26 +24,49 @@ flowery prose.
|
||||
kernel = sk.Kernel()
|
||||
|
||||
api_key, org_id = sk.openai_settings_from_dot_env()
|
||||
kernel.add_chat_service("chat-gpt", sk_oai.OpenAIChatCompletion("gpt-3.5-turbo", api_key, org_id))
|
||||
kernel.add_service(
|
||||
sk_oai.OpenAIChatCompletion(service_id="chat-gpt", ai_model_id="gpt-3.5-turbo", api_key=api_key, org_id=org_id)
|
||||
)
|
||||
|
||||
prompt_config = sk.PromptTemplateConfig.from_execution_settings(max_tokens=2000, temperature=0.7, top_p=0.8)
|
||||
settings = kernel.get_prompt_execution_settings_from_service(ChatCompletionClientBase, "chat-gpt")
|
||||
settings.max_tokens = 2000
|
||||
settings.temperature = 0.7
|
||||
settings.top_p = 0.8
|
||||
|
||||
prompt_template = sk.ChatPromptTemplate("{{$user_input}}", kernel.prompt_template_engine, prompt_config)
|
||||
prompt_template_config = PromptTemplateConfig(
|
||||
template="{{$user_input}}",
|
||||
name="chat",
|
||||
template_format="semantic-kernel",
|
||||
input_variables=[
|
||||
InputVariable(
|
||||
name="user_input",
|
||||
description="The user input",
|
||||
is_required=True,
|
||||
default="",
|
||||
),
|
||||
InputVariable(
|
||||
name="chat_history",
|
||||
description="The history of the conversation",
|
||||
is_required=True,
|
||||
),
|
||||
],
|
||||
execution_settings=settings,
|
||||
)
|
||||
|
||||
prompt_template.add_system_message(system_message)
|
||||
prompt_template.add_user_message("Hi there, who are you?")
|
||||
prompt_template.add_assistant_message("I am Mosscap, a chat bot. I'm trying to figure out what people need.")
|
||||
chat = ChatHistory(system_message=system_message)
|
||||
chat.add_user_message("Hi there, who are you?")
|
||||
chat.add_assistant_message("I am Mosscap, a chat bot. I'm trying to figure out what people need")
|
||||
|
||||
function_config = sk.SemanticFunctionConfig(prompt_config, prompt_template)
|
||||
chat_function = kernel.register_semantic_function("ChatBot", "Chat", function_config)
|
||||
chat_function = kernel.create_function_from_prompt(
|
||||
plugin_name="ChatBot", function_name="Chat", prompt_template_config=prompt_template_config
|
||||
)
|
||||
|
||||
chat.add_user_message("I want to find a hotel in Seattle with free wifi and a pool.")
|
||||
|
||||
|
||||
async def chat() -> bool:
|
||||
context_vars = sk.ContextVariables()
|
||||
|
||||
try:
|
||||
user_input = input("User:> ")
|
||||
context_vars["user_input"] = user_input
|
||||
except KeyboardInterrupt:
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
@@ -48,7 +78,9 @@ async def chat() -> bool:
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
|
||||
answer = await kernel.run(chat_function, input_vars=context_vars)
|
||||
answer = await kernel.invoke(chat_function, KernelArguments(user_input=user_input, chat_history=chat))
|
||||
chat.add_user_message(user_input)
|
||||
chat.add_assistant_message(str(answer))
|
||||
print(f"Mosscap:> {answer}")
|
||||
return True
|
||||
|
||||
|
||||
@@ -2,18 +2,17 @@
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from typing import Tuple
|
||||
|
||||
import semantic_kernel as sk
|
||||
import semantic_kernel.connectors.ai.open_ai as sk_oai
|
||||
from semantic_kernel.connectors.ai.open_ai.semantic_functions.open_ai_chat_prompt_template import (
|
||||
OpenAIChatPromptTemplate,
|
||||
)
|
||||
from semantic_kernel.connectors.ai.open_ai.utils import (
|
||||
chat_completion_with_function_call,
|
||||
chat_completion_with_tool_call,
|
||||
get_tool_call_object,
|
||||
)
|
||||
from semantic_kernel.contents.chat_history import ChatHistory
|
||||
from semantic_kernel.core_plugins import MathPlugin
|
||||
from semantic_kernel.functions.kernel_arguments import KernelArguments
|
||||
from semantic_kernel.prompt_template.input_variable import InputVariable
|
||||
|
||||
system_message = """
|
||||
You are a chat bot. Your name is Mosscap and
|
||||
@@ -33,11 +32,11 @@ kernel = sk.Kernel()
|
||||
# Note: the underlying gpt-35/gpt-4 model version needs to be at least version 0613 to support tools.
|
||||
deployment_name, api_key, endpoint = sk.azure_openai_settings_from_dot_env()
|
||||
api_version = "2023-12-01-preview"
|
||||
kernel.add_chat_service(
|
||||
"chat-gpt",
|
||||
kernel.add_service(
|
||||
sk_oai.AzureChatCompletion(
|
||||
deployment_name,
|
||||
endpoint,
|
||||
service_id="chat",
|
||||
deployment_name=deployment_name,
|
||||
base_url=endpoint,
|
||||
api_key=api_key,
|
||||
api_version=api_version,
|
||||
),
|
||||
@@ -46,7 +45,7 @@ kernel.add_chat_service(
|
||||
plugins_directory = os.path.join(__file__, "../../../../samples/plugins")
|
||||
# adding plugins to the kernel
|
||||
# the joke plugin in the FunPlugins is a semantic plugin and has the function calling disabled.
|
||||
kernel.import_semantic_plugin_from_directory(plugins_directory, "FunPlugin")
|
||||
# kernel.import_plugin_from_prompt_directory("chat", plugins_directory, "FunPlugin")
|
||||
# the math plugin is a core plugin and has the function calling enabled.
|
||||
kernel.import_plugin(MathPlugin(), plugin_name="math")
|
||||
|
||||
@@ -55,62 +54,77 @@ kernel.import_plugin(MathPlugin(), plugin_name="math")
|
||||
# if you only want to use a specific function, set the name of that function in this parameter,
|
||||
# the format for that is 'PluginName-FunctionName', (i.e. 'math-Add').
|
||||
# if the model or api version do not support this you will get an error.
|
||||
prompt_config = sk.PromptTemplateConfig(
|
||||
execution_settings=sk_oai.AzureChatPromptExecutionSettings(
|
||||
service_id="chat-gpt",
|
||||
ai_model_id=deployment_name,
|
||||
max_tokens=2000,
|
||||
temperature=0.7,
|
||||
top_p=0.8,
|
||||
tool_choice="auto",
|
||||
tools=get_tool_call_object(kernel, {"exclude_plugin": ["ChatBot"]}),
|
||||
)
|
||||
execution_settings = sk_oai.AzureChatPromptExecutionSettings(
|
||||
service_id="chat",
|
||||
ai_model_id=deployment_name,
|
||||
max_tokens=2000,
|
||||
temperature=0.7,
|
||||
top_p=0.8,
|
||||
tool_choice="auto",
|
||||
tools=get_tool_call_object(kernel, {"exclude_plugin": ["ChatBot"]}),
|
||||
)
|
||||
|
||||
prompt_template = OpenAIChatPromptTemplate("{{$user_input}}", kernel.prompt_template_engine, prompt_config)
|
||||
prompt_template.add_system_message(system_message)
|
||||
prompt_template.add_user_message("Hi there, who are you?")
|
||||
prompt_template.add_assistant_message("I am Mosscap, a chat bot. I'm trying to figure out what people need.")
|
||||
prompt_template_config = sk.PromptTemplateConfig(
|
||||
template="{{$user_input}}",
|
||||
name="chat",
|
||||
template_format="semantic-kernel",
|
||||
input_variables=[
|
||||
InputVariable(name="user_input", description="The user input", is_required=True),
|
||||
InputVariable(name="history", description="The history of the conversation", is_required=True, default=""),
|
||||
],
|
||||
execution_settings={"default": execution_settings},
|
||||
)
|
||||
|
||||
function_config = sk.SemanticFunctionConfig(prompt_config, prompt_template)
|
||||
chat_function = kernel.register_semantic_function("ChatBot", "Chat", function_config)
|
||||
history = ChatHistory()
|
||||
|
||||
history.add_system_message(system_message)
|
||||
history.add_user_message("Hi there, who are you?")
|
||||
history.add_assistant_message("I am Mosscap, a chat bot. I'm trying to figure out what people need.")
|
||||
|
||||
arguments = KernelArguments()
|
||||
|
||||
chat_function = kernel.create_function_from_prompt(
|
||||
prompt_template_config=prompt_template_config,
|
||||
plugin_name="ChatBot",
|
||||
function_name="Chat",
|
||||
)
|
||||
|
||||
|
||||
async def chat(context: sk.KernelContext) -> Tuple[bool, sk.KernelContext]:
|
||||
async def chat() -> bool:
|
||||
try:
|
||||
user_input = input("User:> ")
|
||||
context.variables["user_input"] = user_input
|
||||
except KeyboardInterrupt:
|
||||
print("\n\nExiting chat...")
|
||||
return False, None
|
||||
return False
|
||||
except EOFError:
|
||||
print("\n\nExiting chat...")
|
||||
return False, None
|
||||
return False
|
||||
|
||||
if user_input == "exit":
|
||||
print("\n\nExiting chat...")
|
||||
return False, None
|
||||
|
||||
context = await chat_completion_with_function_call(
|
||||
kernel,
|
||||
return False
|
||||
arguments = KernelArguments(
|
||||
user_input=user_input, history=("\n").join([f"{msg.role}: {msg.content}" for msg in history])
|
||||
)
|
||||
result = await chat_completion_with_tool_call(
|
||||
kernel=kernel,
|
||||
arguments=arguments,
|
||||
chat_plugin_name="ChatBot",
|
||||
chat_function_name="Chat",
|
||||
context=context,
|
||||
)
|
||||
print(f"Mosscap:> {context.result}")
|
||||
return True, context
|
||||
print(f"Mosscap:> {result}")
|
||||
return True
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
chatting = True
|
||||
context = kernel.create_new_context()
|
||||
print(
|
||||
"Welcome to the chat bot!\
|
||||
\n Type 'exit' to exit.\
|
||||
\n Try a math question to see the function calling in action (i.e. what is 3+3?)."
|
||||
)
|
||||
while chatting:
|
||||
chatting, context = await chat(context)
|
||||
chatting = await chat()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
import semantic_kernel as sk
|
||||
import semantic_kernel.connectors.ai.open_ai as sk_oai
|
||||
from semantic_kernel.contents.chat_history import ChatHistory
|
||||
from semantic_kernel.functions.kernel_arguments import KernelArguments
|
||||
from semantic_kernel.prompt_template.input_variable import InputVariable
|
||||
from semantic_kernel.prompt_template.prompt_template_config import PromptTemplateConfig
|
||||
|
||||
|
||||
async def main():
|
||||
kernel = sk.Kernel()
|
||||
|
||||
useAzureOpenAI = False
|
||||
model = "gpt-35-turbo" if useAzureOpenAI else "gpt-3.5-turbo-1106"
|
||||
service_id = model
|
||||
|
||||
api_key, org_id = sk.openai_settings_from_dot_env()
|
||||
kernel.add_service(
|
||||
sk_oai.OpenAIChatCompletion(service_id=service_id, ai_model_id=model, api_key=api_key, org_id=org_id),
|
||||
)
|
||||
|
||||
template = """
|
||||
|
||||
Previous information from chat:
|
||||
{{$chat_history}}
|
||||
|
||||
User: {{$request}}
|
||||
Assistant:
|
||||
"""
|
||||
|
||||
print("--- Rendered Prompt ---")
|
||||
prompt_template_config = PromptTemplateConfig(
|
||||
template=template,
|
||||
name="chat",
|
||||
description="Chat with the assistant",
|
||||
template_format="semantic-kernel",
|
||||
input_variables=[
|
||||
InputVariable(name="chat_history", description="The conversation history", is_required=False, default=""),
|
||||
InputVariable(name="request", description="The user's request", is_required=True),
|
||||
],
|
||||
execution_settings=sk_oai.OpenAIChatPromptExecutionSettings(
|
||||
service_id=service_id, max_tokens=4000, temperature=0.2
|
||||
),
|
||||
)
|
||||
|
||||
chat = kernel.create_function_from_prompt(
|
||||
prompt_template_config=prompt_template_config,
|
||||
)
|
||||
|
||||
chat_history = ChatHistory()
|
||||
|
||||
print("User > ")
|
||||
while (user_input := input()) != "exit":
|
||||
result = await kernel.invoke(
|
||||
chat,
|
||||
KernelArguments(
|
||||
request=user_input,
|
||||
chat_history=chat_history,
|
||||
),
|
||||
)
|
||||
result = str(result)
|
||||
print(result)
|
||||
chat_history.add_user_message(user_input)
|
||||
chat_history.add_assistant_message(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -5,14 +5,17 @@ from typing import Tuple
|
||||
|
||||
import semantic_kernel as sk
|
||||
import semantic_kernel.connectors.ai.google_palm as sk_gp
|
||||
from semantic_kernel.contents.chat_history import ChatHistory
|
||||
from semantic_kernel.prompt_template.input_variable import InputVariable
|
||||
|
||||
kernel = sk.Kernel()
|
||||
apikey = sk.google_palm_settings_from_dot_env()
|
||||
palm_text_embed = sk_gp.GooglePalmTextEmbedding("models/embedding-gecko-001", apikey)
|
||||
kernel.add_text_embedding_generation_service("gecko", palm_text_embed)
|
||||
palm_chat_completion = sk_gp.GooglePalmChatCompletion("models/chat-bison-001", apikey)
|
||||
kernel.add_chat_service("models/chat-bison-001", palm_chat_completion)
|
||||
kernel.register_memory_store(memory_store=sk.memory.VolatileMemoryStore())
|
||||
kernel.add_service(palm_text_embed)
|
||||
chat_service_id = "models/chat-bison-001"
|
||||
palm_chat_completion = sk_gp.GooglePalmChatCompletion(chat_service_id, apikey)
|
||||
kernel.add_service(palm_chat_completion)
|
||||
kernel.use_memory(storage=sk.memory.VolatileMemoryStore(), embeddings_generator=palm_text_embed)
|
||||
kernel.import_plugin(sk.core_plugins.TextMemoryPlugin(), "TextMemoryPlugin")
|
||||
|
||||
|
||||
@@ -42,7 +45,7 @@ async def search_memory_examples(kernel: sk.Kernel) -> None:
|
||||
|
||||
async def setup_chat_with_memory(
|
||||
kernel: sk.Kernel,
|
||||
) -> Tuple[sk.KernelFunction, sk.KernelContext]:
|
||||
) -> Tuple[sk.KernelFunction, sk.KernelArguments]:
|
||||
"""
|
||||
When using Google PaLM to chat with memories, a chat prompt template is
|
||||
essential; otherwise, the kernel will send text prompts to the Google PaLM
|
||||
@@ -53,7 +56,7 @@ async def setup_chat_with_memory(
|
||||
Note that this is only an issue for the chat service; the text service
|
||||
does not require a chat prompt template.
|
||||
"""
|
||||
sk_prompt = """
|
||||
prompt = """
|
||||
ChatBot can have a conversation with you about any topic.
|
||||
It can give explicit instructions or say 'I don't know' if
|
||||
it does not have an answer.
|
||||
@@ -67,33 +70,46 @@ async def setup_chat_with_memory(
|
||||
|
||||
""".strip()
|
||||
|
||||
prompt_config = sk.PromptTemplateConfig.from_execution_settings(max_tokens=2000, temperature=0.7, top_p=0.8)
|
||||
prompt_template = sk.ChatPromptTemplate( # Create the chat prompt template
|
||||
"{{$user_input}}", kernel.prompt_template_engine, prompt_config
|
||||
req_settings = kernel.get_service(chat_service_id).get_prompt_execution_settings_class()(service_id=chat_service_id)
|
||||
req_settings.max_tokens = 2000
|
||||
req_settings.temperature = 0.7
|
||||
req_settings.top_p = 0.8
|
||||
|
||||
prompt_template_config = sk.PromptTemplateConfig(
|
||||
template="{{$user_input}}",
|
||||
name="chat",
|
||||
template_format="semantic-kernel",
|
||||
input_variables=[
|
||||
InputVariable(name="user_input", description="The user input", is_required=True),
|
||||
InputVariable(name="chat_history", description="The history of the conversation", is_required=True),
|
||||
],
|
||||
execution_settings=req_settings,
|
||||
)
|
||||
prompt_template.add_system_message(sk_prompt) # Add the memory as a system message
|
||||
function_config = sk.SemanticFunctionConfig(prompt_config, prompt_template)
|
||||
chat_func = kernel.register_semantic_function(None, "ChatWithMemory", function_config)
|
||||
|
||||
context = kernel.create_new_context()
|
||||
context["fact1"] = "what is my name?"
|
||||
context["fact2"] = "what is my favorite hobby?"
|
||||
context["fact3"] = "where's my family from?"
|
||||
context["fact4"] = "where did I travel last year?"
|
||||
context["fact5"] = "what do I do for work?"
|
||||
chat_func = kernel.create_function_from_prompt(
|
||||
plugin_name="chat_memory", function_name="ChatWithMemory", prompt_template_config=prompt_template_config
|
||||
)
|
||||
|
||||
context[sk.core_plugins.TextMemoryPlugin.COLLECTION_PARAM] = "aboutMe"
|
||||
context[sk.core_plugins.TextMemoryPlugin.RELEVANCE_PARAM] = 0.6
|
||||
chat_history = ChatHistory()
|
||||
chat_history.add_system_message(prompt)
|
||||
|
||||
context["chat_history"] = ""
|
||||
arguments = sk.KernelArguments(
|
||||
fact1="what is my name?",
|
||||
fact2="what is my favorite hobby?",
|
||||
fact3="where's my family from?",
|
||||
fact4="where did I travel last year?",
|
||||
fact5="what do I do for work?",
|
||||
collection="aboutMe",
|
||||
relevance=0.6,
|
||||
chat_history=chat_history,
|
||||
)
|
||||
|
||||
return chat_func, context
|
||||
return chat_func, arguments
|
||||
|
||||
|
||||
async def chat(kernel: sk.Kernel, chat_func: sk.KernelFunction, context: sk.KernelContext) -> bool:
|
||||
async def chat(kernel: sk.Kernel, chat_func: sk.KernelFunction, arguments: sk.KernelArguments) -> bool:
|
||||
try:
|
||||
user_input = input("User:> ")
|
||||
context["user_input"] = user_input
|
||||
except KeyboardInterrupt:
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
@@ -105,8 +121,10 @@ async def chat(kernel: sk.Kernel, chat_func: sk.KernelFunction, context: sk.Kern
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
|
||||
answer = await kernel.run(chat_func, input_vars=context.variables)
|
||||
context["chat_history"] += f"\nUser:> {user_input}\nChatBot:> {answer}\n"
|
||||
arguments["user_input"] = user_input
|
||||
answer = await kernel.invoke(chat_func, arguments)
|
||||
arguments["chat_history"].add_user_message(user_input)
|
||||
arguments["chat_history"].add_assistant_message(str(answer))
|
||||
|
||||
print(f"ChatBot:> {answer}")
|
||||
return True
|
||||
@@ -115,11 +133,11 @@ async def chat(kernel: sk.Kernel, chat_func: sk.KernelFunction, context: sk.Kern
|
||||
async def main() -> None:
|
||||
await populate_memory(kernel)
|
||||
await search_memory_examples(kernel)
|
||||
chat_func, context = await setup_chat_with_memory(kernel)
|
||||
chat_func, arguments = await setup_chat_with_memory(kernel)
|
||||
print("Begin chatting (type 'exit' to exit):\n")
|
||||
chatting = True
|
||||
while chatting:
|
||||
chatting = await chat(kernel, chat_func, context)
|
||||
chatting = await chat(kernel, chat_func, arguments)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -4,6 +4,8 @@ import asyncio
|
||||
|
||||
import semantic_kernel as sk
|
||||
import semantic_kernel.connectors.ai.google_palm as sk_gp
|
||||
from semantic_kernel.contents.chat_history import ChatHistory
|
||||
from semantic_kernel.prompt_template.input_variable import InputVariable
|
||||
|
||||
"""
|
||||
System messages prime the assistant with different personalities or behaviors.
|
||||
@@ -28,23 +30,39 @@ Bartholomew "Blackbeard" Thorne.
|
||||
|
||||
kernel = sk.Kernel()
|
||||
api_key = sk.google_palm_settings_from_dot_env()
|
||||
palm_chat_completion = sk_gp.GooglePalmChatCompletion("models/chat-bison-001", api_key)
|
||||
kernel.add_chat_service("models/chat-bison-001", palm_chat_completion)
|
||||
prompt_config = sk.PromptTemplateConfig.from_execution_settings(max_tokens=2000, temperature=0.7, top_p=0.8)
|
||||
prompt_template = sk.ChatPromptTemplate("{{$user_input}}", kernel.prompt_template_engine, prompt_config)
|
||||
prompt_template.add_system_message(system_message) # Add the system message for context
|
||||
prompt_template.add_user_message("Hi there, my name is Andrea, who are you?") # Include a chat history
|
||||
prompt_template.add_assistant_message("I am Blackbeard.")
|
||||
function_config = sk.SemanticFunctionConfig(prompt_config, prompt_template)
|
||||
chat_function = kernel.register_semantic_function("PiratePlugin", "Chat", function_config)
|
||||
service_id = "models/chat-bison-001"
|
||||
palm_chat_completion = sk_gp.GooglePalmChatCompletion(service_id, api_key)
|
||||
kernel.add_service(palm_chat_completion)
|
||||
|
||||
req_settings = kernel.get_service(service_id).get_prompt_execution_settings_class()(service_id=service_id)
|
||||
req_settings.max_tokens = 2000
|
||||
req_settings.temperature = 0.7
|
||||
req_settings.top_p = 0.8
|
||||
|
||||
prompt_template_config = sk.PromptTemplateConfig(
|
||||
template="{{$user_input}}",
|
||||
name="chat",
|
||||
template_format="semantic-kernel",
|
||||
input_variables=[
|
||||
InputVariable(name="user_input", description="The user input", is_required=True),
|
||||
InputVariable(name="chat_history", description="The history of the conversation", is_required=True),
|
||||
],
|
||||
execution_settings=req_settings,
|
||||
)
|
||||
|
||||
chat_func = kernel.create_function_from_prompt(
|
||||
plugin_name="PiratePlugin", function_name="Chat", prompt_template_config=prompt_template_config
|
||||
)
|
||||
|
||||
chat_history = ChatHistory()
|
||||
chat_history.add_system_message(system_message)
|
||||
chat_history.add_user_message("Hi there, who are you?")
|
||||
chat_history.add_assistant_message("I am Blackbeard.")
|
||||
|
||||
|
||||
async def chat() -> bool:
|
||||
context_vars = sk.ContextVariables()
|
||||
|
||||
try:
|
||||
user_input = input("User:> ")
|
||||
context_vars["user_input"] = user_input
|
||||
except KeyboardInterrupt:
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
@@ -56,8 +74,10 @@ async def chat() -> bool:
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
|
||||
answer = await kernel.run(chat_function, input_vars=context_vars)
|
||||
answer = await kernel.invoke(chat_func, user_input=user_input, chat_history=chat_history)
|
||||
print(f"Blackbeard:> {answer}")
|
||||
chat_history.add_user_message(user_input)
|
||||
chat_history.add_assistant_message(str(answer))
|
||||
return True
|
||||
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ async def text_completion_example_complete(kernel, api_key, user_mssg, settings)
|
||||
Complete a text prompt using the Google PaLM model and print the results.
|
||||
"""
|
||||
palm_text_completion = sk_gp.GooglePalmTextCompletion("models/text-bison-001", api_key)
|
||||
kernel.add_text_completion_service("models/text-bison-001", palm_text_completion)
|
||||
kernel.add_service(palm_text_completion)
|
||||
answer = await palm_text_completion.complete(user_mssg, settings)
|
||||
return answer
|
||||
|
||||
|
||||
@@ -15,7 +15,9 @@ load_dotenv()
|
||||
async def main():
|
||||
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))
|
||||
kernel.add_service(
|
||||
OpenAIChatCompletion(service_id="chat-gpt", ai_model_id="gpt-3.5-turbo", api_key=api_key, org_id=org_id)
|
||||
)
|
||||
|
||||
"""
|
||||
Instantiate a Google Connector
|
||||
|
||||
@@ -58,9 +58,10 @@ def setup(use_azure: bool = False):
|
||||
# Configure AI service used by the kernel
|
||||
if useAzureOpenAI:
|
||||
deployment, api_key, endpoint = sk.azure_openai_settings_from_dot_env()
|
||||
kernel.add_chat_service(
|
||||
"chat_completion",
|
||||
service_id = ("chat_completion",)
|
||||
kernel.add_service(
|
||||
AzureChatCompletion(
|
||||
service_id=service_id,
|
||||
deployment_name=deployment,
|
||||
endpoint=endpoint,
|
||||
api_key=api_key,
|
||||
@@ -70,19 +71,18 @@ def setup(use_azure: bool = False):
|
||||
)
|
||||
else:
|
||||
api_key, org_id = sk.openai_settings_from_dot_env()
|
||||
kernel.add_chat_service(
|
||||
"chat-gpt",
|
||||
OpenAIChatCompletion(ai_model_id="gpt-3.5-turbo", api_key=api_key, org_id=org_id),
|
||||
service_id = "chat-gpt"
|
||||
kernel.add_service(
|
||||
OpenAIChatCompletion(service_id=service_id, ai_model_id="gpt-3.5-turbo", api_key=api_key, org_id=org_id),
|
||||
)
|
||||
|
||||
# note: using plugins from the samples folder
|
||||
plugins_directory = "../samples/plugins/"
|
||||
|
||||
grounding_semantic_functions = kernel.import_semantic_plugin_from_directory(plugins_directory, "GroundingPlugin")
|
||||
grounding_semantic_functions = kernel.import_plugin_from_prompt_directory(
|
||||
service_id, plugins_directory, "GroundingPlugin"
|
||||
)
|
||||
|
||||
# entity_extraction = grounding_semantic_functions["ExtractEntities"]
|
||||
# reference_check = grounding_semantic_functions["ReferenceCheckEntities"]
|
||||
# entity_excision = grounding_semantic_functions["ExciseEntities"]
|
||||
return kernel, grounding_semantic_functions
|
||||
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ from typing import Tuple
|
||||
|
||||
import semantic_kernel as sk
|
||||
import semantic_kernel.connectors.ai.open_ai as sk_oai
|
||||
from semantic_kernel.contents.chat_history import ChatHistory
|
||||
from semantic_kernel.functions.kernel_arguments import KernelArguments
|
||||
|
||||
|
||||
async def populate_memory(kernel: sk.Kernel) -> None:
|
||||
@@ -31,6 +33,7 @@ async def search_memory_examples(kernel: sk.Kernel) -> None:
|
||||
print(f"Answer: {result[0].text}\n")
|
||||
|
||||
|
||||
# TODO fix this ASAP
|
||||
async def setup_chat_with_memory(
|
||||
kernel: sk.Kernel,
|
||||
) -> Tuple[sk.KernelFunction, sk.KernelContext]:
|
||||
@@ -68,10 +71,9 @@ async def setup_chat_with_memory(
|
||||
return chat_func, context
|
||||
|
||||
|
||||
async def chat(kernel: sk.Kernel, chat_func: sk.KernelFunction, context: sk.KernelContext) -> bool:
|
||||
async def chat(kernel: sk.Kernel, chat_func: sk.KernelFunction, chat_history: ChatHistory) -> bool:
|
||||
try:
|
||||
user_input = input("User:> ")
|
||||
context["user_input"] = user_input
|
||||
except KeyboardInterrupt:
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
@@ -83,8 +85,9 @@ async def chat(kernel: sk.Kernel, chat_func: sk.KernelFunction, context: sk.Kern
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
|
||||
answer = await kernel.run(chat_func, input_vars=context.variables)
|
||||
context["chat_history"] += f"\nUser:> {user_input}\nChatBot:> {answer}\n"
|
||||
answer = await kernel.invoke(chat_func, KernelArguments(user_input=user_input, chat_history=chat_history))
|
||||
chat_history.add_user_message(user_input)
|
||||
chat_history.add_assistant_message(str(answer))
|
||||
|
||||
print(f"ChatBot:> {answer}")
|
||||
return True
|
||||
@@ -94,12 +97,16 @@ async def main() -> None:
|
||||
kernel = sk.Kernel()
|
||||
|
||||
api_key, org_id = sk.openai_settings_from_dot_env()
|
||||
kernel.add_chat_service("chat-gpt", sk_oai.OpenAIChatCompletion("gpt-3.5-turbo", api_key, org_id))
|
||||
kernel.add_text_embedding_generation_service(
|
||||
"ada", sk_oai.OpenAITextEmbedding("text-embedding-ada-002", api_key, org_id)
|
||||
service_id = "chat-gpt"
|
||||
kernel.add_service(
|
||||
sk_oai.OpenAIChatCompletion(service_id=service_id, ai_model_id="gpt-3.5-turbo", api_key=api_key, org_id=org_id)
|
||||
)
|
||||
embedding_gen = sk_oai.OpenAITextEmbedding(
|
||||
service_id="ada", ai_model_id="text-embedding-ada-002", api_key=api_key, org_id=org_id
|
||||
)
|
||||
kernel.add_service(embedding_gen)
|
||||
|
||||
kernel.register_memory_store(memory_store=sk.memory.VolatileMemoryStore())
|
||||
kernel.use_memory(storage=sk.memory.VolatileMemoryStore(), embeddings_generator=embedding_gen)
|
||||
kernel.import_plugin(sk.core_plugins.TextMemoryPlugin(), "TextMemoryPlugin")
|
||||
|
||||
print("Populating memory...")
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Tuple
|
||||
|
||||
import semantic_kernel as sk
|
||||
from semantic_kernel.connectors.ai.open_ai import (
|
||||
OpenAIChatCompletion,
|
||||
OpenAITextEmbedding,
|
||||
)
|
||||
from semantic_kernel.contents.chat_history import ChatHistory
|
||||
from semantic_kernel.functions import KernelFunction
|
||||
from semantic_kernel.prompt_template.input_variable import InputVariable
|
||||
|
||||
kernel = sk.Kernel()
|
||||
|
||||
api_key, org_id = sk.openai_settings_from_dot_env()
|
||||
oai_text_embedding = OpenAITextEmbedding(
|
||||
service_id="oai_text_embed", ai_model_id="text-embedding-ada-002", api_key=api_key, org_id=org_id
|
||||
)
|
||||
service_id = "oai_chat"
|
||||
oai_chat_service = OpenAIChatCompletion(
|
||||
service_id=service_id, ai_model_id="gpt-3.5-turbo", api_key=api_key, org_id=org_id
|
||||
)
|
||||
kernel.use_memory(storage=sk.memory.VolatileMemoryStore(), embeddings_generator=oai_text_embedding)
|
||||
kernel.add_service(oai_chat_service)
|
||||
kernel.add_service(oai_text_embedding)
|
||||
|
||||
kernel.import_plugin(sk.core_plugins.TextMemoryPlugin(), "text_memory")
|
||||
|
||||
|
||||
async def populate_memory(kernel: sk.Kernel) -> None:
|
||||
await kernel.memory.save_information(collection="aboutMe", id="info1", text="My name is Andrea")
|
||||
await kernel.memory.save_information(collection="aboutMe", id="info2", text="I currently work as a tour guide")
|
||||
await kernel.memory.save_information(
|
||||
collection="aboutMe", id="info3", text="I've been living in Seattle since 2005"
|
||||
)
|
||||
await kernel.memory.save_information(
|
||||
collection="aboutMe",
|
||||
id="info4",
|
||||
text="I visited France and Italy five times since 2015",
|
||||
)
|
||||
await kernel.memory.save_information(collection="aboutMe", id="info5", text="My family is from New York")
|
||||
|
||||
|
||||
async def search_memory_examples(kernel: sk.Kernel) -> None:
|
||||
questions = [
|
||||
"what's my name",
|
||||
"where do I live?",
|
||||
"where's my family from?",
|
||||
"where have I traveled?",
|
||||
"what do I do for work",
|
||||
]
|
||||
|
||||
for question in questions:
|
||||
print(f"Question: {question}")
|
||||
result = await kernel.memory.search("aboutMe", question)
|
||||
print(f"Answer: {result[0].text}\n")
|
||||
|
||||
|
||||
async def setup_chat_with_memory(
|
||||
kernel: sk.Kernel,
|
||||
) -> Tuple[KernelFunction, sk.KernelArguments]:
|
||||
prompt = """
|
||||
ChatBot can have a conversation with you about any topic.
|
||||
It can give explicit instructions or say 'I don't know' if
|
||||
it does not have an answer.
|
||||
|
||||
Information about me, from previous conversations:
|
||||
{{$fact1}} {{recall $fact1}}
|
||||
{{$fact2}} {{recall $fact2}}
|
||||
{{$fact3}} {{recall $fact3}}
|
||||
{{$fact4}} {{recall $fact4}}
|
||||
{{$fact5}} {{recall $fact5}}
|
||||
|
||||
{{$user_input}}
|
||||
|
||||
""".strip()
|
||||
req_settings = kernel.get_service(service_id).get_prompt_execution_settings_class()(service_id=service_id)
|
||||
req_settings.max_tokens = 2000
|
||||
req_settings.temperature = 0.7
|
||||
req_settings.top_p = 0.8
|
||||
|
||||
prompt_template_config = sk.PromptTemplateConfig(
|
||||
template="{{$user_input}}",
|
||||
name="chat",
|
||||
template_format="semantic-kernel",
|
||||
input_variables=[
|
||||
InputVariable(name="user_input", description="The user input", is_required=True),
|
||||
InputVariable(name="chat_history", description="The history of the conversation", is_required=True),
|
||||
],
|
||||
execution_settings=req_settings,
|
||||
)
|
||||
|
||||
chat_func = kernel.create_function_from_prompt(
|
||||
plugin_name="chat_memory", function_name="ChatWithMemory", prompt_template_config=prompt_template_config
|
||||
)
|
||||
|
||||
chat_history = ChatHistory()
|
||||
chat_history.add_system_message(prompt)
|
||||
|
||||
arguments = sk.KernelArguments(
|
||||
fact1="what is my name?",
|
||||
fact2="what is my favorite hobby?",
|
||||
fact3="where's my family from?",
|
||||
fact4="where did I travel last year?",
|
||||
fact5="what do I do for work?",
|
||||
collection="aboutMe",
|
||||
relevance=0.6,
|
||||
chat_history=chat_history,
|
||||
)
|
||||
|
||||
return chat_func, arguments
|
||||
|
||||
|
||||
async def chat(kernel: sk.Kernel, chat_func: KernelFunction, arguments: sk.KernelArguments) -> bool:
|
||||
try:
|
||||
user_input = input("User:> ")
|
||||
print(f"User:> {user_input}")
|
||||
except KeyboardInterrupt:
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
except EOFError:
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
|
||||
if user_input == "exit":
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
|
||||
arguments["user_input"] = user_input
|
||||
answer = await kernel.invoke(chat_func, arguments)
|
||||
arguments["chat_history"].add_user_message(user_input)
|
||||
arguments["chat_history"].add_system_message(str(answer))
|
||||
|
||||
print(f"ChatBot:> {answer}")
|
||||
return True
|
||||
|
||||
|
||||
async def main():
|
||||
print("Populating memory...")
|
||||
await populate_memory(kernel)
|
||||
|
||||
print("Asking questions... (manually)")
|
||||
await search_memory_examples(kernel)
|
||||
|
||||
print("Setting up a chat (with memory!)")
|
||||
chat_func, arguments = await setup_chat_with_memory(kernel)
|
||||
|
||||
result = await chat(kernel=kernel, chat_func=chat_func, arguments=arguments)
|
||||
print(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -5,10 +5,15 @@ import os
|
||||
|
||||
import semantic_kernel as sk
|
||||
import semantic_kernel.connectors.ai.open_ai as sk_oai
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat.open_ai_chat_message import (
|
||||
OpenAIChatMessage,
|
||||
from semantic_kernel.connectors.ai.chat_completion_client_base import (
|
||||
ChatCompletionClientBase,
|
||||
)
|
||||
from semantic_kernel.contents.chat_history import ChatHistory
|
||||
from semantic_kernel.core_plugins import MathPlugin
|
||||
from semantic_kernel.functions.function_result import FunctionResult
|
||||
from semantic_kernel.functions.kernel_arguments import KernelArguments
|
||||
from semantic_kernel.prompt_template.input_variable import InputVariable
|
||||
from semantic_kernel.prompt_template.prompt_template_config import PromptTemplateConfig
|
||||
|
||||
system_message = """
|
||||
You are a chat bot. Your name is Mosscap and
|
||||
@@ -26,9 +31,9 @@ you will return a full answer to me as soon as possible.
|
||||
kernel = sk.Kernel()
|
||||
|
||||
api_key, org_id = sk.openai_settings_from_dot_env()
|
||||
kernel.add_chat_service(
|
||||
"gpt-3.5-turbo",
|
||||
kernel.add_service(
|
||||
sk_oai.OpenAIChatCompletion(
|
||||
service_id="chat",
|
||||
ai_model_id="gpt-3.5-turbo-1106",
|
||||
api_key=api_key,
|
||||
),
|
||||
@@ -37,7 +42,7 @@ kernel.add_chat_service(
|
||||
plugins_directory = os.path.join(__file__, "../../../../samples/plugins")
|
||||
# adding plugins to the kernel
|
||||
# the joke plugin in the FunPlugins is a semantic plugin and has the function calling disabled.
|
||||
kernel.import_semantic_plugin_from_directory(plugins_directory, "FunPlugin")
|
||||
kernel.import_plugin_from_prompt_directory("chat", plugins_directory, "FunPlugin")
|
||||
# the math plugin is a core plugin and has the function calling enabled.
|
||||
kernel.import_plugin(MathPlugin(), plugin_name="math")
|
||||
|
||||
@@ -74,46 +79,69 @@ tools = [
|
||||
}
|
||||
]
|
||||
|
||||
prompt_config = sk.PromptTemplateConfig.from_execution_settings(
|
||||
max_tokens=2000,
|
||||
temperature=0.7,
|
||||
top_p=0.8,
|
||||
tool_choice="auto",
|
||||
tools=tools,
|
||||
)
|
||||
prompt_template = sk.ChatPromptTemplate[OpenAIChatMessage](
|
||||
"{{$user_input}}", kernel.prompt_template_engine, prompt_config
|
||||
)
|
||||
prompt_template.add_system_message(system_message)
|
||||
prompt_template.add_user_message("Hi there, who are you?")
|
||||
prompt_template.add_assistant_message("I am Mosscap, a chat bot. I'm trying to figure out what people need.")
|
||||
|
||||
function_config = sk.SemanticFunctionConfig(prompt_config, prompt_template)
|
||||
chat_function = kernel.register_semantic_function("ChatBot", "Chat", function_config)
|
||||
# define the functions available
|
||||
async def main():
|
||||
settings = kernel.get_prompt_execution_settings_from_service(ChatCompletionClientBase, "chat")
|
||||
settings.service_id = "chat"
|
||||
settings.tools = tools
|
||||
settings.tool_choice = "auto"
|
||||
settings.max_tokens = 2000
|
||||
settings.temperature = 0.7
|
||||
settings.top_p = 0.8
|
||||
|
||||
prompt_template_config = PromptTemplateConfig(
|
||||
template="{{$user_input}}",
|
||||
name="chat",
|
||||
template_format="semantic-kernel",
|
||||
input_variables=[
|
||||
InputVariable(
|
||||
name="user_input",
|
||||
description="The history of the conversation",
|
||||
is_required=True,
|
||||
default="",
|
||||
),
|
||||
InputVariable(
|
||||
name="chat_history",
|
||||
description="The history of the conversation",
|
||||
is_required=True,
|
||||
),
|
||||
],
|
||||
execution_settings=settings,
|
||||
)
|
||||
|
||||
async def main() -> None:
|
||||
context = kernel.create_new_context()
|
||||
context.variables["user_input"] = "I want to find a hotel in Seattle with free wifi and a pool."
|
||||
chat = ChatHistory(system_message=system_message)
|
||||
chat.add_user_message("Hi there, who are you?")
|
||||
chat.add_assistant_message("I am Mosscap, a chat bot. I'm trying to figure out what people need")
|
||||
|
||||
chat_function = kernel.create_function_from_prompt(
|
||||
plugin_name="ChatBot", function_name="Chat", prompt_template_config=prompt_template_config
|
||||
)
|
||||
|
||||
response = kernel.invoke_stream(
|
||||
chat_function,
|
||||
KernelArguments(user_input="I want to find a hotel in Seattle with free wifi and a pool.", chat_history=chat),
|
||||
)
|
||||
messages = []
|
||||
tool_call = None
|
||||
response = chat_function.invoke_stream_async(context=context)
|
||||
async for message in response:
|
||||
if isinstance(message, FunctionResult):
|
||||
# There's been an error, so print it
|
||||
print(message)
|
||||
return
|
||||
current = message[0]
|
||||
messages.append(current)
|
||||
messages.append(str(current))
|
||||
if current.tool_calls:
|
||||
if tool_call is None:
|
||||
tool_call = current.tool_calls[0]
|
||||
else:
|
||||
tool_call += current.tool_calls[0]
|
||||
|
||||
if tool_call:
|
||||
print(f"Function to be called: {tool_call.function.name}")
|
||||
print(f"Function parameters: \n{tool_call.function.parse_arguments()}")
|
||||
return
|
||||
print("No function was called")
|
||||
print(f"Output was: {str(context)}")
|
||||
output = "".join([msg for msg in messages])
|
||||
print(f"Output was: {output}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -5,13 +5,11 @@ from typing import Any, Dict
|
||||
|
||||
import semantic_kernel as sk
|
||||
import semantic_kernel.connectors.ai.open_ai as sk_oai
|
||||
from semantic_kernel.connectors.ai.chat_completion_client_base import (
|
||||
ChatCompletionClientBase,
|
||||
)
|
||||
from semantic_kernel.connectors.ai.prompt_execution_settings import PromptExecutionSettings
|
||||
from semantic_kernel.connectors.ai.text_completion_client_base import (
|
||||
TextCompletionClientBase,
|
||||
)
|
||||
from semantic_kernel.contents.chat_history import ChatHistory
|
||||
from semantic_kernel.functions.kernel_arguments import KernelArguments
|
||||
from semantic_kernel.prompt_template.input_variable import InputVariable
|
||||
from semantic_kernel.prompt_template.prompt_template_config import PromptTemplateConfig
|
||||
|
||||
"""
|
||||
Logit bias enables prioritizing certain tokens within a given output.
|
||||
@@ -29,9 +27,16 @@ def _config_ban_tokens(settings: PromptExecutionSettings, keys: Dict[Any, Any]):
|
||||
return settings
|
||||
|
||||
|
||||
def _prepare_input_chat(chat: ChatHistory):
|
||||
return "".join([f"{msg.role}: {msg.content}\n" for msg in chat])
|
||||
|
||||
|
||||
async def chat_request_example(kernel, api_key, org_id):
|
||||
openai_chat_completion = sk_oai.OpenAIChatCompletion("gpt-3.5-turbo", api_key, org_id)
|
||||
kernel.add_chat_service("chat_service", openai_chat_completion)
|
||||
service_id = "chat_service"
|
||||
openai_chat_completion = sk_oai.OpenAIChatCompletion(
|
||||
service_id=service_id, ai_model_id="gpt-3.5-turbo", api_key=api_key, org_id=org_id
|
||||
)
|
||||
kernel.add_service(openai_chat_completion)
|
||||
|
||||
# Spaces and capitalization affect the token ids.
|
||||
# The following is the token ids of basketball related words.
|
||||
@@ -65,49 +70,53 @@ async def chat_request_example(kernel, api_key, org_id):
|
||||
]
|
||||
|
||||
# Model will try its best to avoid using any of the above words
|
||||
settings = kernel.get_prompt_execution_settings_from_service(ChatCompletionClientBase, "chat_service")
|
||||
settings = kernel.get_service(service_id).get_prompt_execution_settings_class()(service_id=service_id)
|
||||
settings = _config_ban_tokens(settings, keys)
|
||||
|
||||
prompt_config = sk.PromptTemplateConfig.from_execution_settings(max_tokens=2000, temperature=0.7, top_p=0.8)
|
||||
prompt_template = sk.ChatPromptTemplate("{{$user_input}}", kernel.prompt_template_engine, prompt_config)
|
||||
prompt_template_config = PromptTemplateConfig(
|
||||
template="{{$user_input}}",
|
||||
name="chat",
|
||||
template_format="semantic-kernel",
|
||||
input_variables=[
|
||||
InputVariable(
|
||||
name="user_input", description="The history of the conversation", is_required=True, default=""
|
||||
),
|
||||
],
|
||||
execution_settings=settings,
|
||||
)
|
||||
|
||||
# Setup chat with prompt
|
||||
prompt_template.add_system_message("You are a basketball expert")
|
||||
user_mssg = "I love the LA Lakers, tell me an interesting fact about LeBron James."
|
||||
prompt_template.add_user_message(user_mssg)
|
||||
function_config = sk.SemanticFunctionConfig(prompt_config, prompt_template)
|
||||
kernel.register_semantic_function("ChatBot", "Chat", function_config)
|
||||
chat = ChatHistory()
|
||||
|
||||
chat_messages = []
|
||||
messages = [{"role": "user", "content": user_mssg}]
|
||||
chat.add_user_message("Hi there, who are you?")
|
||||
chat.add_assistant_message("I am an AI assistant here to answer your questions.")
|
||||
|
||||
chat_messages.append(("user", user_mssg))
|
||||
answer = await openai_chat_completion.complete_chat(messages=messages, settings=settings)
|
||||
chat_messages.append(("assistant", str(answer[0])))
|
||||
chat_function = kernel.create_function_from_prompt(
|
||||
plugin_name="ChatBot", function_name="Chat", prompt_template_config=prompt_template_config
|
||||
)
|
||||
|
||||
user_mssg = "What are his best all-time stats?"
|
||||
messages = [{"role": "user", "content": user_mssg}]
|
||||
chat_messages.append(("user", user_mssg))
|
||||
answer = await openai_chat_completion.complete_chat(messages=messages, settings=settings)
|
||||
chat_messages.append(("assistant", str(answer[0])))
|
||||
chat.add_system_message("You are a basketball expert")
|
||||
chat.add_user_message("I love the LA Lakers, tell me an interesting fact about LeBron James.")
|
||||
|
||||
context_vars = sk.ContextVariables()
|
||||
context_vars["chat_history"] = ""
|
||||
context_vars["chat_bot_ans"] = ""
|
||||
for role, mssg in chat_messages:
|
||||
if role == "user":
|
||||
context_vars["chat_history"] += f"User:> {mssg}\n"
|
||||
elif role == "assistant":
|
||||
context_vars["chat_history"] += f"ChatBot:> {mssg}\n"
|
||||
context_vars["chat_bot_ans"] += f"{mssg}\n"
|
||||
answer = await kernel.invoke(chat_function, KernelArguments(user_input=_prepare_input_chat(chat)))
|
||||
chat.add_assistant_message(str(answer))
|
||||
|
||||
kernel.remove_chat_service("chat_service")
|
||||
return context_vars, banned_words
|
||||
chat.add_user_message("What are his best all-time stats?")
|
||||
answer = await kernel.invoke(chat_function, KernelArguments(user_input=_prepare_input_chat(chat)))
|
||||
chat.add_assistant_message(str(answer))
|
||||
|
||||
print(chat)
|
||||
|
||||
kernel.remove_all_services()
|
||||
|
||||
return chat, banned_words
|
||||
|
||||
|
||||
async def text_complete_request_example(kernel, api_key, org_id):
|
||||
openai_text_completion = sk_oai.OpenAITextCompletion("gpt-3.5-turbo-instruct", api_key, org_id)
|
||||
kernel.add_text_completion_service("text_service", openai_text_completion)
|
||||
service_id = "text_service"
|
||||
openai_text_completion = sk_oai.OpenAITextCompletion(
|
||||
service_id=service_id, ai_model_id="gpt-3.5-turbo-instruct", api_key=api_key, org_id=org_id
|
||||
)
|
||||
kernel.add_service(openai_text_completion)
|
||||
|
||||
# Spaces and capitalization affect the token ids.
|
||||
# The following is the token ids of pie related words.
|
||||
@@ -150,18 +159,37 @@ async def text_complete_request_example(kernel, api_key, org_id):
|
||||
]
|
||||
|
||||
# Model will try its best to avoid using any of the above words
|
||||
settings = kernel.get_prompt_execution_settings_from_service(TextCompletionClientBase, "text_service")
|
||||
settings = kernel.get_service(service_id).get_prompt_execution_settings_class()(service_id=service_id)
|
||||
settings = _config_ban_tokens(settings, keys)
|
||||
|
||||
user_mssg = "The best pie flavor to have in autumn is"
|
||||
answer = await openai_text_completion.complete(user_mssg, settings)
|
||||
prompt_template_config = PromptTemplateConfig(
|
||||
template="{{$user_input}}",
|
||||
name="chat",
|
||||
template_format="semantic-kernel",
|
||||
input_variables=[
|
||||
InputVariable(
|
||||
name="user_input", description="The history of the conversation", is_required=True, default=""
|
||||
),
|
||||
],
|
||||
execution_settings=settings,
|
||||
)
|
||||
|
||||
context_vars = sk.ContextVariables()
|
||||
context_vars["chat_history"] = f"User:> {user_mssg}\nChatBot:> {answer}\n"
|
||||
context_vars["chat_bot_ans"] = str(answer)
|
||||
chat = ChatHistory()
|
||||
|
||||
kernel.remove_text_completion_service("text_service")
|
||||
return context_vars, banned_words
|
||||
chat.add_user_message("The best pie flavor to have in autumn is")
|
||||
|
||||
text_function = kernel.create_function_from_prompt(
|
||||
plugin_name="TextBot", function_name="TextCompletion", prompt_template_config=prompt_template_config
|
||||
)
|
||||
|
||||
answer = await kernel.invoke(text_function, KernelArguments(user_input=_prepare_input_chat(chat)))
|
||||
chat.add_assistant_message(str(answer))
|
||||
|
||||
print(chat)
|
||||
|
||||
kernel.remove_all_services()
|
||||
|
||||
return chat, banned_words
|
||||
|
||||
|
||||
def _check_banned_words(banned_list, actual_list) -> bool:
|
||||
@@ -173,9 +201,9 @@ def _check_banned_words(banned_list, actual_list) -> bool:
|
||||
return passed
|
||||
|
||||
|
||||
def _format_output(context, banned_words) -> None:
|
||||
print(context["chat_history"])
|
||||
chat_bot_ans_words = context["chat_bot_ans"].split()
|
||||
def _format_output(chat, banned_words) -> None:
|
||||
print("--- Checking for banned words ---")
|
||||
chat_bot_ans_words = [word for msg in chat.messages if msg.role == "assistant" for word in msg.content.split()]
|
||||
if _check_banned_words(banned_words, chat_bot_ans_words):
|
||||
print("None of the banned words were found in the answer")
|
||||
|
||||
|
||||
@@ -5,30 +5,39 @@ import os
|
||||
|
||||
import semantic_kernel as sk
|
||||
import semantic_kernel.connectors.ai.open_ai as sk_oai
|
||||
from semantic_kernel.functions.kernel_arguments import KernelArguments
|
||||
|
||||
kernel = sk.Kernel()
|
||||
|
||||
useAzureOpenAI = False
|
||||
model = "gpt-35-turbo-instruct" if useAzureOpenAI else "gpt-3.5-turbo-instruct"
|
||||
service_id = model
|
||||
async def main():
|
||||
kernel = sk.Kernel()
|
||||
|
||||
# Configure AI service used by the kernel
|
||||
if useAzureOpenAI:
|
||||
deployment_name, api_key, endpoint = sk.azure_openai_settings_from_dot_env()
|
||||
kernel.add_text_completion_service(
|
||||
service_id,
|
||||
sk_oai.AzureTextCompletion(deployment_name=model, api_key=api_key, endpoint=endpoint),
|
||||
)
|
||||
else:
|
||||
api_key, org_id = sk.openai_settings_from_dot_env()
|
||||
kernel.add_text_completion_service(
|
||||
service_id,
|
||||
sk_oai.OpenAITextCompletion(ai_model_id=model, api_key=api_key, org_id=org_id),
|
||||
)
|
||||
useAzureOpenAI = False
|
||||
model = "gpt-35-turbo-instruct" if useAzureOpenAI else "gpt-3.5-turbo-instruct"
|
||||
service_id = model
|
||||
|
||||
# note: using plugins from the samples folder
|
||||
plugins_directory = os.path.join(__file__, "../../../../samples/plugins")
|
||||
plugin = kernel.import_semantic_plugin_from_directory(plugins_directory, "FunPlugin")
|
||||
# Configure AI service used by the kernel
|
||||
if useAzureOpenAI:
|
||||
deployment_name, api_key, endpoint = sk.azure_openai_settings_from_dot_env()
|
||||
kernel.add_service(
|
||||
sk_oai.AzureTextCompletion(
|
||||
service_id=service_id, deployment_name=model, api_key=api_key, endpoint=endpoint
|
||||
),
|
||||
)
|
||||
else:
|
||||
api_key, org_id = sk.openai_settings_from_dot_env()
|
||||
kernel.add_service(
|
||||
sk_oai.OpenAITextCompletion(service_id=service_id, ai_model_id=model, api_key=api_key, org_id=org_id),
|
||||
)
|
||||
|
||||
result = asyncio.run(kernel.run(plugin["Joke"], input_str="time travel to dinosaur age"))
|
||||
print(result)
|
||||
# note: using plugins from the samples folder
|
||||
plugins_directory = os.path.join(__file__, "../../../../samples/plugins")
|
||||
plugin = kernel.import_plugin_from_prompt_directory(service_id, plugins_directory, "FunPlugin")
|
||||
|
||||
arguments = KernelArguments(input="time travel to dinosaur age", style="super silly")
|
||||
|
||||
result = await kernel.invoke(plugin["Joke"], arguments)
|
||||
print(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
|
||||
@@ -13,7 +13,6 @@ from semantic_kernel.connectors.memory.azure_cognitive_search import (
|
||||
AzureCognitiveSearchMemoryStore,
|
||||
)
|
||||
from semantic_kernel.core_plugins.text_memory_plugin import TextMemoryPlugin
|
||||
from semantic_kernel.orchestration.context_variables import ContextVariables
|
||||
|
||||
COLLECTION_NAME = "generic"
|
||||
|
||||
@@ -45,19 +44,19 @@ async def main() -> None:
|
||||
vector_size = 1536
|
||||
|
||||
# Setting up OpenAI services for text completion and text embedding
|
||||
kernel.add_text_completion_service(
|
||||
"dv",
|
||||
kernel.add_service(
|
||||
AzureTextCompletion(
|
||||
# Note: text-davinci-003 is deprecated and will be replaced by
|
||||
# AzureOpenAI's gpt-35-turbo-instruct model.
|
||||
service_id="dv",
|
||||
deployment_name="gpt-35-turbo-instruct",
|
||||
endpoint=AZURE_OPENAI_ENDPOINT,
|
||||
api_key=AZURE_OPENAI_API_KEY,
|
||||
),
|
||||
)
|
||||
kernel.add_text_embedding_generation_service(
|
||||
"ada",
|
||||
kernel.add_service(
|
||||
AzureTextEmbedding(
|
||||
service_id="ada",
|
||||
deployment_name="text-embedding-ada-002",
|
||||
endpoint=AZURE_OPENAI_ENDPOINT,
|
||||
api_key=AZURE_OPENAI_API_KEY,
|
||||
@@ -99,15 +98,8 @@ Remember, just answer Grounded or Ungrounded or Unclear: """.strip()
|
||||
chat_func = kernel.create_semantic_function(sk_prompt_rag, max_tokens=1000, temperature=0.5)
|
||||
self_critique_func = kernel.create_semantic_function(sk_prompt_rag_sc, max_tokens=4, temperature=0.0)
|
||||
|
||||
answer = await kernel.run(
|
||||
answer = await kernel.invoke(
|
||||
chat_func,
|
||||
input_vars=ContextVariables(
|
||||
variables={
|
||||
"user_input": user_input,
|
||||
"collection": COLLECTION_NAME,
|
||||
"limit": "2",
|
||||
}
|
||||
),
|
||||
)
|
||||
print(f"Answer: {str(answer).strip()}")
|
||||
check = await kernel.run(self_critique_func, input_context=answer)
|
||||
|
||||
@@ -3,26 +3,27 @@
|
||||
import semantic_kernel as sk
|
||||
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
|
||||
from semantic_kernel.core_plugins import (
|
||||
FileIOPlugin,
|
||||
MathPlugin,
|
||||
TextPlugin,
|
||||
TimePlugin,
|
||||
)
|
||||
from semantic_kernel.planning import SequentialPlanner
|
||||
from semantic_kernel.planners import SequentialPlanner
|
||||
|
||||
|
||||
async def main():
|
||||
kernel = sk.Kernel()
|
||||
api_key, org_id = sk.openai_settings_from_dot_env()
|
||||
|
||||
kernel.add_chat_service("gpt-3.5", OpenAIChatCompletion("gpt-3.5-turbo", api_key=api_key, org_id=org_id))
|
||||
service_id = "gpt-3.5"
|
||||
kernel.add_service(
|
||||
OpenAIChatCompletion(service_id=service_id, ai_model_id="gpt-3.5-turbo", api_key=api_key, org_id=org_id)
|
||||
)
|
||||
kernel.import_plugin(MathPlugin(), "math")
|
||||
kernel.import_plugin(FileIOPlugin(), "fileIO")
|
||||
kernel.import_plugin(TimePlugin(), "time")
|
||||
kernel.import_plugin(TextPlugin(), "text")
|
||||
|
||||
# create an instance of sequential planner.
|
||||
planner = SequentialPlanner(kernel)
|
||||
planner = SequentialPlanner(service_id=service_id, kernel=kernel)
|
||||
|
||||
# the ask for which the sequential planner is going to find a relevant function.
|
||||
ask = "What day of the week is today, all uppercase?"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
import semantic_kernel as sk
|
||||
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
|
||||
@@ -16,13 +18,19 @@ async def main():
|
||||
|
||||
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))
|
||||
service_id = "chat-gpt"
|
||||
kernel.add_service(
|
||||
OpenAIChatCompletion(service_id=service_id, ai_model_id="gpt-3.5-turbo", api_key=api_key, org_id=org_id)
|
||||
)
|
||||
|
||||
plugin = kernel.import_semantic_plugin_from_directory("../../samples/plugins", "FunPlugin")
|
||||
plugins_directory = os.path.join(__file__, "../../../../samples/plugins")
|
||||
plugin = kernel.import_plugin_from_prompt_directory(service_id, plugins_directory, "FunPlugin")
|
||||
|
||||
joke_function = plugin["Joke"]
|
||||
|
||||
print(joke_function("time travel to dinosaur age"))
|
||||
result = await kernel.invoke(joke_function, input="time travel to dinosaur age", style="silly")
|
||||
|
||||
print(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
import semantic_kernel as sk
|
||||
import semantic_kernel.connectors.ai.open_ai as sk_oai
|
||||
from semantic_kernel.core_plugins import (
|
||||
TimePlugin,
|
||||
)
|
||||
from semantic_kernel.prompt_template.kernel_prompt_template import KernelPromptTemplate
|
||||
from semantic_kernel.prompt_template.prompt_template_config import PromptTemplateConfig
|
||||
|
||||
|
||||
async def main():
|
||||
kernel = sk.Kernel()
|
||||
|
||||
useAzureOpenAI = False
|
||||
model = "gpt-35-turbo" if useAzureOpenAI else "gpt-3.5-turbo-1106"
|
||||
service_id = model
|
||||
|
||||
api_key, org_id = sk.openai_settings_from_dot_env()
|
||||
kernel.add_service(
|
||||
sk_oai.OpenAIChatCompletion(service_id=service_id, ai_model_id=model, api_key=api_key, org_id=org_id),
|
||||
)
|
||||
|
||||
kernel.import_plugin(TimePlugin(), "time")
|
||||
|
||||
function_definition = """
|
||||
Today is: {{time.Date}}
|
||||
Current time is: {{time.Time}}
|
||||
|
||||
Answer to the following questions using JSON syntax, including the data used.
|
||||
Is it morning, afternoon, evening, or night (morning/afternoon/evening/night)?
|
||||
Is it weekend time (weekend/not weekend)?
|
||||
"""
|
||||
|
||||
print("--- Rendered Prompt ---")
|
||||
prompt_template_config = PromptTemplateConfig(template=function_definition)
|
||||
prompt_template = KernelPromptTemplate(prompt_template_config)
|
||||
rendered_prompt = await prompt_template.render(kernel, arguments=None)
|
||||
print(rendered_prompt)
|
||||
|
||||
kind_of_day = kernel.create_function_from_prompt(
|
||||
template=function_definition,
|
||||
execution_settings=sk_oai.OpenAIChatPromptExecutionSettings(service_id=service_id, max_tokens=100),
|
||||
function_name="kind_of_day",
|
||||
)
|
||||
|
||||
print("--- Prompt Function Result ---")
|
||||
result = await kernel.invoke(kind_of_day)
|
||||
print(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -1,18 +1,11 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from semantic_kernel import core_plugins, memory
|
||||
from semantic_kernel.functions.kernel_arguments import KernelArguments
|
||||
from semantic_kernel.kernel import Kernel
|
||||
from semantic_kernel.orchestration.context_variables import ContextVariables
|
||||
from semantic_kernel.orchestration.kernel_context import KernelContext
|
||||
from semantic_kernel.orchestration.kernel_function import KernelFunction
|
||||
from semantic_kernel.semantic_functions.chat_prompt_template import ChatPromptTemplate
|
||||
from semantic_kernel.semantic_functions.prompt_template import PromptTemplate
|
||||
from semantic_kernel.semantic_functions.prompt_template_config import (
|
||||
from semantic_kernel.prompt_template.prompt_template_config import (
|
||||
PromptTemplateConfig,
|
||||
)
|
||||
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 (
|
||||
@@ -46,12 +39,7 @@ __all__ = [
|
||||
"google_palm_settings_from_dot_env",
|
||||
"redis_settings_from_dot_env",
|
||||
"PromptTemplateConfig",
|
||||
"PromptTemplate",
|
||||
"ChatPromptTemplate",
|
||||
"SemanticFunctionConfig",
|
||||
"ContextVariables",
|
||||
"KernelFunction",
|
||||
"KernelContext",
|
||||
"KernelArguments",
|
||||
"memory",
|
||||
"core_plugins",
|
||||
"setup_logging",
|
||||
|
||||
@@ -30,6 +30,10 @@ class AIException(Exception):
|
||||
FunctionTypeNotSupported = 9
|
||||
# The LLM raised an error due to improper content.
|
||||
BadContentError = 10
|
||||
# No service was found.
|
||||
NoServiceFound = 11
|
||||
# The prompt is not valid
|
||||
InvalidPrompt = 12
|
||||
|
||||
# The error code.
|
||||
_error_code: ErrorCodes
|
||||
|
||||
@@ -1,30 +1,35 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import TYPE_CHECKING, Any, AsyncIterable, List, Optional
|
||||
from typing import TYPE_CHECKING, AsyncIterable, Dict, List, Optional, Type
|
||||
|
||||
from semantic_kernel.contents import ChatMessageContent
|
||||
from semantic_kernel.services.ai_service_client_base import AIServiceClientBase
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from semantic_kernel.connectors.ai.prompt_execution_settings import PromptExecutionSettings
|
||||
from semantic_kernel.models.chat.chat_message import ChatMessage
|
||||
from semantic_kernel.models.contents import ChatMessageContent, StreamingChatMessageContent
|
||||
from semantic_kernel.contents import StreamingChatMessageContent
|
||||
from semantic_kernel.contents.chat_history import ChatHistory
|
||||
|
||||
|
||||
class ChatCompletionClientBase(ABC):
|
||||
class ChatCompletionClientBase(AIServiceClientBase, ABC):
|
||||
def get_chat_message_content_class(self) -> Type[ChatMessageContent]:
|
||||
"""Get the chat message content types used by a class, default is ChatMessageContent."""
|
||||
return ChatMessageContent
|
||||
|
||||
@abstractmethod
|
||||
async def complete_chat(
|
||||
self,
|
||||
messages: List["ChatMessage"],
|
||||
chat_history: "ChatHistory",
|
||||
settings: "PromptExecutionSettings",
|
||||
logger: Optional[Any] = None,
|
||||
) -> List["ChatMessageContent"]:
|
||||
"""
|
||||
This is the method that is called from the kernel to get a response from a chat-optimized LLM.
|
||||
|
||||
Arguments:
|
||||
messages {List[ChatMessage]} -- A list of chat messages, that can be rendered into a
|
||||
set of messages, from system, user, assistant and function.
|
||||
chat_history {ChatHistory} -- A list of chats in a chat_history object, that can be
|
||||
rendered into messages from system, user, assistant and tools.
|
||||
settings {PromptExecutionSettings} -- Settings for the request.
|
||||
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.
|
||||
@@ -34,20 +39,30 @@ class ChatCompletionClientBase(ABC):
|
||||
@abstractmethod
|
||||
async def complete_chat_stream(
|
||||
self,
|
||||
messages: List["ChatMessage"],
|
||||
chat_history: "ChatHistory",
|
||||
settings: "PromptExecutionSettings",
|
||||
logger: Optional[Any] = None,
|
||||
) -> AsyncIterable[List["StreamingChatMessageContent"]]:
|
||||
"""
|
||||
This is the method that is called from the kernel to get a stream response from a chat-optimized LLM.
|
||||
|
||||
Arguments:
|
||||
messages {List[ChatMessage]} -- A list of chat messages, that can be rendered into a
|
||||
set of messages, from system, user, assistant and function.
|
||||
chat_history {ChatHistory} -- A list of chat chat_history, that can be rendered into a
|
||||
set of chat_history, from system, user, assistant and function.
|
||||
settings {PromptExecutionSettings} -- Settings for the request.
|
||||
logger {Logger} -- A logger to use for logging. (Deprecated)
|
||||
|
||||
Yields:
|
||||
A stream representing the response(s) from the LLM.
|
||||
"""
|
||||
pass
|
||||
|
||||
def _prepare_chat_history_for_request(
|
||||
self,
|
||||
chat_history: "ChatHistory",
|
||||
) -> List[Dict[str, Optional[str]]]:
|
||||
"""
|
||||
Prepare the chat history for a request, allowing customization of the key names for role/author,
|
||||
and optionally overriding the role.
|
||||
"""
|
||||
return [
|
||||
message.model_dump(exclude_none=True, exclude=["metadata", "encoding"]) for message in chat_history.messages
|
||||
]
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import TYPE_CHECKING, List
|
||||
|
||||
from semantic_kernel.services.ai_service_client_base import AIServiceClientBase
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from numpy import ndarray
|
||||
|
||||
|
||||
class EmbeddingGeneratorBase(ABC):
|
||||
class EmbeddingGeneratorBase(AIServiceClientBase, ABC):
|
||||
@abstractmethod
|
||||
async def generate_embeddings(self, texts: List[str]) -> "ndarray":
|
||||
pass
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
import logging
|
||||
import sys
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
from semantic_kernel.models.contents.chat_message_content import ChatMessageContent
|
||||
from semantic_kernel.models.contents.text_content import TextContent
|
||||
from semantic_kernel.contents.chat_message_content import ChatMessageContent
|
||||
from semantic_kernel.contents.text_content import TextContent
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
from typing import Annotated
|
||||
@@ -17,7 +17,6 @@ from google.generativeai.types import ChatResponse, MessageDict
|
||||
from pydantic import PrivateAttr, StringConstraints
|
||||
|
||||
from semantic_kernel.connectors.ai.ai_exception import AIException
|
||||
from semantic_kernel.connectors.ai.ai_service_client_base import AIServiceClientBase
|
||||
from semantic_kernel.connectors.ai.chat_completion_client_base import (
|
||||
ChatCompletionClientBase,
|
||||
)
|
||||
@@ -29,20 +28,24 @@ from semantic_kernel.connectors.ai.prompt_execution_settings import PromptExecut
|
||||
from semantic_kernel.connectors.ai.text_completion_client_base import (
|
||||
TextCompletionClientBase,
|
||||
)
|
||||
from semantic_kernel.contents.chat_history import ChatHistory
|
||||
from semantic_kernel.contents.chat_role import ChatRole
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
int_to_role = {1: ChatRole.USER, 2: ChatRole.SYSTEM, 3: ChatRole.ASSISTANT, 4: ChatRole.TOOL}
|
||||
|
||||
class GooglePalmChatCompletion(ChatCompletionClientBase, TextCompletionClientBase, AIServiceClientBase):
|
||||
|
||||
class GooglePalmChatCompletion(ChatCompletionClientBase, TextCompletionClientBase):
|
||||
api_key: Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)]
|
||||
_message_history: Optional[ChatResponse] = PrivateAttr()
|
||||
_message_history: Optional[ChatHistory] = PrivateAttr()
|
||||
service_id: Optional[str] = None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
ai_model_id: str,
|
||||
api_key: str,
|
||||
message_history: Optional[ChatResponse] = None,
|
||||
log: Optional[Any] = None,
|
||||
message_history: Optional[ChatHistory] = None,
|
||||
):
|
||||
"""
|
||||
Initializes a new instance of the GooglePalmChatCompletion class.
|
||||
@@ -52,20 +55,17 @@ class GooglePalmChatCompletion(ChatCompletionClientBase, TextCompletionClientBas
|
||||
https://developers.generativeai.google/models/language
|
||||
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[Any]} -- A logger to use for logging. (Optional)
|
||||
message_history {Optional[ChatHistory]} -- The message history to use for context. (Optional)
|
||||
"""
|
||||
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.")
|
||||
self._message_history = message_history
|
||||
|
||||
async def complete_chat(
|
||||
self,
|
||||
messages: List[Dict[str, str]],
|
||||
messages: ChatHistory,
|
||||
settings: GooglePalmPromptExecutionSettings,
|
||||
) -> List[ChatMessageContent]:
|
||||
"""
|
||||
@@ -79,7 +79,7 @@ class GooglePalmChatCompletion(ChatCompletionClientBase, TextCompletionClientBas
|
||||
Returns:
|
||||
List[ChatMessageContent] -- A list of ChatMessageContent objects representing the response(s) from the LLM.
|
||||
"""
|
||||
settings.messages = [{"author": message["role"], "content": message["content"]} for message in messages]
|
||||
settings.messages = self._prepare_chat_history_for_request(messages)
|
||||
if not settings.ai_model_id:
|
||||
settings.ai_model_id = self.ai_model_id
|
||||
response = await self._send_chat_request(settings)
|
||||
@@ -99,13 +99,16 @@ class GooglePalmChatCompletion(ChatCompletionClientBase, TextCompletionClientBas
|
||||
Returns:
|
||||
ChatMessageContent -- The created chat message content.
|
||||
"""
|
||||
metadata = {"citation_metadata": candidate.get("citation_metadata"), "filters": response.filters}
|
||||
metadata = {
|
||||
"citation_metadata": candidate.get("citation_metadata"),
|
||||
"filters": response.filters,
|
||||
"choice_index": index,
|
||||
}
|
||||
return ChatMessageContent(
|
||||
choice_index=index,
|
||||
inner_content=response,
|
||||
ai_model_id=self.ai_model_id,
|
||||
metadata=metadata,
|
||||
role=candidate.get("author"),
|
||||
role=int_to_role[int(candidate.get("author"))], # TODO: why is author coming back as '1'?
|
||||
content=candidate.get("content"),
|
||||
)
|
||||
|
||||
@@ -120,7 +123,6 @@ class GooglePalmChatCompletion(ChatCompletionClientBase, TextCompletionClientBas
|
||||
self,
|
||||
prompt: str,
|
||||
settings: GooglePalmPromptExecutionSettings,
|
||||
**kwargs,
|
||||
) -> List[TextContent]:
|
||||
"""
|
||||
This is the method that is called from the kernel to get a response from a text-optimized LLM.
|
||||
@@ -132,8 +134,6 @@ class GooglePalmChatCompletion(ChatCompletionClientBase, TextCompletionClientBas
|
||||
Returns:
|
||||
List[TextContent] -- A list of TextContent objects representing the response(s) from the LLM.
|
||||
"""
|
||||
if kwargs.get("logger"):
|
||||
logger.warning("The `logger` parameter is deprecated. Please use the `logging` module instead.")
|
||||
settings.messages = [{"author": "user", "content": prompt}]
|
||||
if not settings.ai_model_id:
|
||||
settings.ai_model_id = self.ai_model_id
|
||||
@@ -162,10 +162,7 @@ class GooglePalmChatCompletion(ChatCompletionClientBase, TextCompletionClientBas
|
||||
self,
|
||||
prompt: str,
|
||||
settings: GooglePalmPromptExecutionSettings,
|
||||
**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")
|
||||
|
||||
async def _send_chat_request(
|
||||
@@ -236,3 +233,18 @@ class GooglePalmChatCompletion(ChatCompletionClientBase, TextCompletionClientBas
|
||||
def get_prompt_execution_settings_class(self) -> "PromptExecutionSettings":
|
||||
"""Create a request settings object."""
|
||||
return GooglePalmChatPromptExecutionSettings
|
||||
|
||||
def _prepare_chat_history_for_request(
|
||||
self,
|
||||
chat_history: ChatHistory,
|
||||
) -> List[Dict[str, Optional[str]]]:
|
||||
"""
|
||||
Prepare the chat history for a request, allowing customization of the key names for role/author,
|
||||
and optionally overriding the role.
|
||||
"""
|
||||
standard_out = super()._prepare_chat_history_for_request(chat_history)
|
||||
for message in standard_out:
|
||||
message["author"] = message.pop("role")
|
||||
# The last message should always be from the user
|
||||
standard_out[-1]["author"] = "user"
|
||||
return standard_out
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
import logging
|
||||
import sys
|
||||
from typing import Any, List, Optional
|
||||
from typing import List
|
||||
|
||||
from semantic_kernel.models.contents.text_content import TextContent
|
||||
from semantic_kernel.contents.text_content import TextContent
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
from typing import Annotated
|
||||
@@ -16,7 +16,6 @@ from google.generativeai.types.text_types import TextCompletion
|
||||
from pydantic import StringConstraints
|
||||
|
||||
from semantic_kernel.connectors.ai.ai_exception import AIException
|
||||
from semantic_kernel.connectors.ai.ai_service_client_base import AIServiceClientBase
|
||||
from semantic_kernel.connectors.ai.google_palm.gp_prompt_execution_settings import (
|
||||
GooglePalmTextPromptExecutionSettings,
|
||||
)
|
||||
@@ -28,10 +27,10 @@ from semantic_kernel.connectors.ai.text_completion_client_base import (
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GooglePalmTextCompletion(TextCompletionClientBase, AIServiceClientBase):
|
||||
class GooglePalmTextCompletion(TextCompletionClientBase):
|
||||
api_key: Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)]
|
||||
|
||||
def __init__(self, ai_model_id: str, api_key: str, log: Optional[Any] = None):
|
||||
def __init__(self, ai_model_id: str, api_key: str):
|
||||
"""
|
||||
Initializes a new instance of the GooglePalmTextCompletion class.
|
||||
|
||||
@@ -40,15 +39,10 @@ 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[Any]} -- The logger instance to use. (Optional) (Deprecated)
|
||||
"""
|
||||
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(
|
||||
self, prompt: str, settings: GooglePalmTextPromptExecutionSettings, **kwargs
|
||||
) -> List[TextContent]:
|
||||
async def complete(self, prompt: str, settings: GooglePalmTextPromptExecutionSettings) -> List[TextContent]:
|
||||
"""
|
||||
This is the method that is called from the kernel to get a response from a text-optimized LLM.
|
||||
|
||||
@@ -97,7 +91,6 @@ class GooglePalmTextCompletion(TextCompletionClientBase, AIServiceClientBase):
|
||||
self,
|
||||
prompt: str,
|
||||
settings: GooglePalmTextPromptExecutionSettings,
|
||||
logger: Optional[Any] = None,
|
||||
):
|
||||
raise NotImplementedError("Google Palm API does not currently support streaming")
|
||||
|
||||
|
||||
@@ -13,13 +13,12 @@ from numpy import array, ndarray
|
||||
from pydantic import StringConstraints
|
||||
|
||||
from semantic_kernel.connectors.ai.ai_exception import AIException
|
||||
from semantic_kernel.connectors.ai.ai_service_client_base import AIServiceClientBase
|
||||
from semantic_kernel.connectors.ai.embeddings.embedding_generator_base import (
|
||||
EmbeddingGeneratorBase,
|
||||
)
|
||||
|
||||
|
||||
class GooglePalmTextEmbedding(EmbeddingGeneratorBase, AIServiceClientBase):
|
||||
class GooglePalmTextEmbedding(EmbeddingGeneratorBase):
|
||||
api_key: Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)]
|
||||
|
||||
def __init__(self, ai_model_id: str, api_key: str) -> None:
|
||||
|
||||
@@ -8,15 +8,14 @@ import torch
|
||||
from transformers import AutoTokenizer, TextIteratorStreamer, pipeline
|
||||
|
||||
from semantic_kernel.connectors.ai.ai_exception import AIException
|
||||
from semantic_kernel.connectors.ai.ai_service_client_base import AIServiceClientBase
|
||||
from semantic_kernel.connectors.ai.hugging_face.hf_prompt_execution_settings import (
|
||||
HuggingFacePromptExecutionSettings,
|
||||
)
|
||||
from semantic_kernel.connectors.ai.text_completion_client_base import (
|
||||
TextCompletionClientBase,
|
||||
)
|
||||
from semantic_kernel.models.contents.streaming_text_content import StreamingTextContent
|
||||
from semantic_kernel.models.contents.text_content import TextContent
|
||||
from semantic_kernel.contents.streaming_text_content import StreamingTextContent
|
||||
from semantic_kernel.contents.text_content import TextContent
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from semantic_kernel.connectors.ai.prompt_execution_settings import PromptExecutionSettings
|
||||
@@ -24,7 +23,7 @@ if TYPE_CHECKING:
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HuggingFaceTextCompletion(TextCompletionClientBase, AIServiceClientBase):
|
||||
class HuggingFaceTextCompletion(TextCompletionClientBase):
|
||||
task: Literal["summarization", "text-generation", "text2text-generation"]
|
||||
device: str
|
||||
generator: Any
|
||||
@@ -34,6 +33,7 @@ class HuggingFaceTextCompletion(TextCompletionClientBase, AIServiceClientBase):
|
||||
ai_model_id: str,
|
||||
task: Optional[str] = "text2text-generation",
|
||||
device: Optional[int] = -1,
|
||||
service_id: Optional[str] = None,
|
||||
model_kwargs: Optional[Dict[str, Any]] = None,
|
||||
pipeline_kwargs: Optional[Dict[str, Any]] = None,
|
||||
) -> None:
|
||||
@@ -47,6 +47,7 @@ class HuggingFaceTextCompletion(TextCompletionClientBase, AIServiceClientBase):
|
||||
-- None if using device_map instead. (If both device and device_map
|
||||
are specified, device overrides device_map. If unintended,
|
||||
it can lead to unexpected behavior.)
|
||||
service_id {Optional[str]} -- Service ID for the AI service.
|
||||
task {Optional[str]} -- Model completion task type, options are:
|
||||
- summarization: takes a long text and returns a shorter summary.
|
||||
- text-generation: takes incomplete text and returns a set of completion candidates.
|
||||
@@ -69,6 +70,7 @@ class HuggingFaceTextCompletion(TextCompletionClientBase, AIServiceClientBase):
|
||||
**pipeline_kwargs or {},
|
||||
)
|
||||
super().__init__(
|
||||
service_id=service_id,
|
||||
ai_model_id=ai_model_id,
|
||||
task=task,
|
||||
device=(f"cuda:{device}" if device >= 0 and torch.cuda.is_available() else "cpu"),
|
||||
@@ -79,7 +81,6 @@ class HuggingFaceTextCompletion(TextCompletionClientBase, AIServiceClientBase):
|
||||
self,
|
||||
prompt: str,
|
||||
settings: HuggingFacePromptExecutionSettings,
|
||||
**kwargs,
|
||||
) -> List[TextContent]:
|
||||
"""
|
||||
This is the method that is called from the kernel to get a response from a text-optimized LLM.
|
||||
@@ -91,8 +92,6 @@ class HuggingFaceTextCompletion(TextCompletionClientBase, AIServiceClientBase):
|
||||
Returns:
|
||||
List[TextContent] -- A list of TextContent objects representing the response(s) from the LLM.
|
||||
"""
|
||||
if kwargs.get("logger"):
|
||||
logger.warning("The `logger` parameter is deprecated. Please use the `logging` module instead.")
|
||||
try:
|
||||
results = self.generator(prompt, **settings.prepare_settings_dict())
|
||||
except Exception as e:
|
||||
@@ -112,7 +111,6 @@ class HuggingFaceTextCompletion(TextCompletionClientBase, AIServiceClientBase):
|
||||
self,
|
||||
prompt: str,
|
||||
settings: HuggingFacePromptExecutionSettings,
|
||||
**kwargs,
|
||||
) -> AsyncIterable[List[StreamingTextContent]]:
|
||||
"""
|
||||
Streams a text completion using a Hugging Face model.
|
||||
@@ -125,8 +123,6 @@ class HuggingFaceTextCompletion(TextCompletionClientBase, AIServiceClientBase):
|
||||
Yields:
|
||||
List[StreamingTextContent] -- List of StreamingTextContent objects.
|
||||
"""
|
||||
if kwargs.get("logger"):
|
||||
logger.warning("The `logger` parameter is deprecated. Please use the `logging` module instead.")
|
||||
if settings.num_return_sequences > 1:
|
||||
raise AIException(
|
||||
AIException.ErrorCodes.InvalidConfiguration,
|
||||
|
||||
@@ -8,7 +8,6 @@ import torch
|
||||
from numpy import array, ndarray
|
||||
|
||||
from semantic_kernel.connectors.ai.ai_exception import AIException
|
||||
from semantic_kernel.connectors.ai.ai_service_client_base import AIServiceClientBase
|
||||
from semantic_kernel.connectors.ai.embeddings.embedding_generator_base import (
|
||||
EmbeddingGeneratorBase,
|
||||
)
|
||||
@@ -16,7 +15,7 @@ from semantic_kernel.connectors.ai.embeddings.embedding_generator_base import (
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HuggingFaceTextEmbedding(EmbeddingGeneratorBase, AIServiceClientBase):
|
||||
class HuggingFaceTextEmbedding(EmbeddingGeneratorBase):
|
||||
device: str
|
||||
generator: Any
|
||||
|
||||
@@ -24,7 +23,7 @@ class HuggingFaceTextEmbedding(EmbeddingGeneratorBase, AIServiceClientBase):
|
||||
self,
|
||||
ai_model_id: str,
|
||||
device: Optional[int] = -1,
|
||||
log: Optional[Any] = None,
|
||||
service_id: Optional[str] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initializes a new instance of the HuggingFaceTextEmbedding class.
|
||||
@@ -37,11 +36,10 @@ class HuggingFaceTextEmbedding(EmbeddingGeneratorBase, AIServiceClientBase):
|
||||
|
||||
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,
|
||||
service_id=service_id,
|
||||
device=resolved_device,
|
||||
generator=sentence_transformers.SentenceTransformer(model_name_or_path=ai_model_id, device=resolved_device),
|
||||
)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from typing import Any, Dict, List, Literal, Optional
|
||||
|
||||
from pydantic import Field
|
||||
@@ -6,7 +8,7 @@ from semantic_kernel.connectors.ai.prompt_execution_settings import PromptExecut
|
||||
|
||||
|
||||
class OllamaPromptExecutionSettings(PromptExecutionSettings):
|
||||
ai_model_id: str = Field("", alias="model")
|
||||
ai_model_id: str = Field("", serialization_alias="model")
|
||||
format: Optional[Literal["json"]] = None
|
||||
options: Optional[Dict[str, Any]] = None
|
||||
stream: bool = False
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
|
||||
import json
|
||||
import logging
|
||||
from typing import AsyncIterable, Dict, List, Optional
|
||||
from typing import AsyncIterable, List, Optional
|
||||
|
||||
import aiohttp
|
||||
from pydantic import HttpUrl
|
||||
|
||||
from semantic_kernel.connectors.ai.ai_service_client_base import AIServiceClientBase
|
||||
from semantic_kernel.connectors.ai.chat_completion_client_base import (
|
||||
ChatCompletionClientBase,
|
||||
)
|
||||
@@ -18,15 +17,16 @@ from semantic_kernel.connectors.ai.ollama.utils import AsyncSession
|
||||
from semantic_kernel.connectors.ai.text_completion_client_base import (
|
||||
TextCompletionClientBase,
|
||||
)
|
||||
from semantic_kernel.models.contents.chat_message_content import ChatMessageContent
|
||||
from semantic_kernel.models.contents.streaming_chat_message_content import StreamingChatMessageContent
|
||||
from semantic_kernel.models.contents.streaming_text_content import StreamingTextContent
|
||||
from semantic_kernel.models.contents.text_content import TextContent
|
||||
from semantic_kernel.contents.chat_history import ChatHistory
|
||||
from semantic_kernel.contents.chat_message_content import ChatMessageContent
|
||||
from semantic_kernel.contents.streaming_chat_message_content import StreamingChatMessageContent
|
||||
from semantic_kernel.contents.streaming_text_content import StreamingTextContent
|
||||
from semantic_kernel.contents.text_content import TextContent
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OllamaChatCompletion(TextCompletionClientBase, ChatCompletionClientBase, AIServiceClientBase):
|
||||
class OllamaChatCompletion(TextCompletionClientBase, ChatCompletionClientBase):
|
||||
"""
|
||||
Initializes a new instance of the OllamaChatCompletion class.
|
||||
|
||||
@@ -43,23 +43,21 @@ class OllamaChatCompletion(TextCompletionClientBase, ChatCompletionClientBase, A
|
||||
|
||||
async def complete_chat(
|
||||
self,
|
||||
messages: List[Dict[str, str]],
|
||||
chat_history: ChatHistory,
|
||||
settings: OllamaChatPromptExecutionSettings,
|
||||
**kwargs,
|
||||
) -> List[ChatMessageContent]:
|
||||
"""
|
||||
This is the method that is called from the kernel to get a response from a chat-optimized LLM.
|
||||
|
||||
Arguments:
|
||||
messages {List[ChatMessage]} -- A list of chat messages, that can be rendered into a
|
||||
set of messages, from system, user, assistant and function.
|
||||
chat_history {ChatHistory} -- A chat history that contains a list of chat messages,
|
||||
that can be rendered into a set of messages, from system, user, assistant and function.
|
||||
settings {PromptExecutionSettings} -- Settings for the request.
|
||||
logger {Logger} -- A logger to use for logging. (Deprecated)
|
||||
|
||||
Returns:
|
||||
List[ChatMessageContent] -- A list of ChatMessageContent objects representing the response(s) from the LLM.
|
||||
"""
|
||||
settings.messages = messages
|
||||
settings.messages = self._prepare_chat_history_for_request(chat_history)
|
||||
settings.stream = False
|
||||
async with AsyncSession(self.session) as session:
|
||||
async with session.post(str(self.url), json=settings.prepare_settings_dict()) as response:
|
||||
@@ -76,22 +74,22 @@ class OllamaChatCompletion(TextCompletionClientBase, ChatCompletionClientBase, A
|
||||
|
||||
async def complete_chat_stream(
|
||||
self,
|
||||
messages: List[Dict[str, str]],
|
||||
chat_history: ChatHistory,
|
||||
settings: OllamaChatPromptExecutionSettings,
|
||||
**kwargs,
|
||||
) -> AsyncIterable[List[StreamingChatMessageContent]]:
|
||||
"""
|
||||
Streams a text completion using a Ollama model.
|
||||
Note that this method does not support multiple responses.
|
||||
|
||||
Arguments:
|
||||
prompt {str} -- Prompt to complete.
|
||||
chat_history {ChatHistory} -- A chat history that contains a list of chat messages,
|
||||
that can be rendered into a set of messages, from system, user, assistant and function.
|
||||
settings {OllamaChatPromptExecutionSettings} -- Request settings.
|
||||
|
||||
Yields:
|
||||
List[StreamingChatMessageContent] -- Stream of StreamingChatMessageContent objects.
|
||||
"""
|
||||
settings.messages = messages
|
||||
settings.messages = self._prepare_chat_history_for_request(chat_history)
|
||||
settings.stream = True
|
||||
async with AsyncSession(self.session) as session:
|
||||
async with session.post(str(self.url), json=settings.prepare_settings_dict()) as response:
|
||||
@@ -115,15 +113,13 @@ class OllamaChatCompletion(TextCompletionClientBase, ChatCompletionClientBase, A
|
||||
self,
|
||||
prompt: str,
|
||||
settings: OllamaChatPromptExecutionSettings,
|
||||
**kwargs,
|
||||
) -> List[TextContent]:
|
||||
"""
|
||||
This is the method that is called from the kernel to get a response from a text-optimized LLM.
|
||||
|
||||
Arguments:
|
||||
prompt {str} -- The prompt to send to the LLM.
|
||||
chat_history {ChatHistory} -- A chat history that contains the prompt to complete.
|
||||
settings {OllamaChatPromptExecutionSettings} -- Settings for the request.
|
||||
logger {Logger} -- A logger to use for logging (deprecated).
|
||||
|
||||
Returns:
|
||||
List["TextContent"] -- The completion result(s).
|
||||
@@ -146,14 +142,13 @@ class OllamaChatCompletion(TextCompletionClientBase, ChatCompletionClientBase, A
|
||||
self,
|
||||
prompt: str,
|
||||
settings: OllamaChatPromptExecutionSettings,
|
||||
**kwargs,
|
||||
) -> AsyncIterable[List[StreamingTextContent]]:
|
||||
"""
|
||||
Streams a text completion using a Ollama model.
|
||||
Note that this method does not support multiple responses.
|
||||
|
||||
Arguments:
|
||||
prompt {str} -- Prompt to complete.
|
||||
prompt {str} -- A chat history that contains the prompt to complete.
|
||||
settings {OllamaChatPromptExecutionSettings} -- Request settings.
|
||||
|
||||
Yields:
|
||||
|
||||
@@ -7,7 +7,6 @@ from typing import AsyncIterable, List, Optional
|
||||
import aiohttp
|
||||
from pydantic import HttpUrl
|
||||
|
||||
from semantic_kernel.connectors.ai.ai_service_client_base import AIServiceClientBase
|
||||
from semantic_kernel.connectors.ai.ollama.ollama_prompt_execution_settings import (
|
||||
OllamaTextPromptExecutionSettings,
|
||||
)
|
||||
@@ -15,13 +14,13 @@ from semantic_kernel.connectors.ai.ollama.utils import AsyncSession
|
||||
from semantic_kernel.connectors.ai.text_completion_client_base import (
|
||||
TextCompletionClientBase,
|
||||
)
|
||||
from semantic_kernel.models.contents.streaming_text_content import StreamingTextContent
|
||||
from semantic_kernel.models.contents.text_content import TextContent
|
||||
from semantic_kernel.contents.streaming_text_content import StreamingTextContent
|
||||
from semantic_kernel.contents.text_content import TextContent
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OllamaTextCompletion(TextCompletionClientBase, AIServiceClientBase):
|
||||
class OllamaTextCompletion(TextCompletionClientBase):
|
||||
"""
|
||||
Initializes a new instance of the OllamaTextCompletion class.
|
||||
|
||||
@@ -39,7 +38,6 @@ class OllamaTextCompletion(TextCompletionClientBase, AIServiceClientBase):
|
||||
self,
|
||||
prompt: str,
|
||||
settings: OllamaTextPromptExecutionSettings,
|
||||
**kwargs,
|
||||
) -> List[TextContent]:
|
||||
"""
|
||||
This is the method that is called from the kernel to get a response from a text-optimized LLM.
|
||||
@@ -63,7 +61,6 @@ class OllamaTextCompletion(TextCompletionClientBase, AIServiceClientBase):
|
||||
self,
|
||||
prompt: str,
|
||||
settings: OllamaTextPromptExecutionSettings,
|
||||
**kwargs,
|
||||
) -> AsyncIterable[List[StreamingTextContent]]:
|
||||
"""
|
||||
Streams a text completion using a Ollama model.
|
||||
|
||||
@@ -7,7 +7,6 @@ import aiohttp
|
||||
from numpy import array, ndarray
|
||||
from pydantic import HttpUrl
|
||||
|
||||
from semantic_kernel.connectors.ai.ai_service_client_base import AIServiceClientBase
|
||||
from semantic_kernel.connectors.ai.embeddings.embedding_generator_base import (
|
||||
EmbeddingGeneratorBase,
|
||||
)
|
||||
@@ -16,7 +15,7 @@ from semantic_kernel.connectors.ai.ollama.utils import AsyncSession
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OllamaTextEmbedding(EmbeddingGeneratorBase, AIServiceClientBase):
|
||||
class OllamaTextEmbedding(EmbeddingGeneratorBase):
|
||||
"""Ollama embeddings client.
|
||||
|
||||
Make sure to have the ollama service running either locally or remotely.
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import aiohttp
|
||||
|
||||
|
||||
|
||||
+45
-4
@@ -1,11 +1,14 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from typing import List, Optional
|
||||
from xml.etree import ElementTree
|
||||
from xml.etree.ElementTree import Element
|
||||
|
||||
from openai.types.chat import ChatCompletion
|
||||
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat.function_call import FunctionCall
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat.tool_calls import ToolCall
|
||||
from semantic_kernel.models.contents import ChatMessageContent
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat_completion.function_call import FunctionCall
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat_completion.tool_calls import ToolCall
|
||||
from semantic_kernel.contents import ChatMessageContent
|
||||
from semantic_kernel.contents.chat_role import ChatRole
|
||||
|
||||
|
||||
class OpenAIChatMessageContent(ChatMessageContent):
|
||||
@@ -27,6 +30,44 @@ class OpenAIChatMessageContent(ChatMessageContent):
|
||||
__str__: Returns the content of the response.
|
||||
"""
|
||||
|
||||
inner_content: ChatCompletion
|
||||
inner_content: Optional[ChatCompletion] = None
|
||||
function_call: Optional[FunctionCall] = None
|
||||
tool_calls: Optional[List[ToolCall]] = None
|
||||
|
||||
@staticmethod
|
||||
def ToolIdProperty():
|
||||
# Directly using the class name and the attribute name as strings
|
||||
return f"{ToolCall.__name__}.{ToolCall.id.__name__}"
|
||||
|
||||
def to_prompt(self, root_key: str) -> str:
|
||||
"""Convert the OpenAIChatMessageContent to a prompt.
|
||||
|
||||
Returns:
|
||||
str - The prompt from the ChatMessageContent.
|
||||
"""
|
||||
|
||||
root = Element(root_key)
|
||||
root.set("role", self.role.value)
|
||||
if self.function_call:
|
||||
root.set("function_call", self.function_call.model_dump_json(exclude_none=True))
|
||||
if self.tool_calls:
|
||||
root.set("tool_calls", ",".join([call.model_dump_json(exclude_none=True) for call in self.tool_calls]))
|
||||
root.text = self.content or ""
|
||||
return ElementTree.tostring(root, encoding=self.encoding or "unicode")
|
||||
|
||||
@classmethod
|
||||
def from_element(cls, element: Element) -> "ChatMessageContent":
|
||||
"""Create a new instance of OpenAIChatMessageContent from a prompt.
|
||||
|
||||
Args:
|
||||
prompt: str - The prompt to create the ChatMessageContent from.
|
||||
|
||||
Returns:
|
||||
ChatMessageContent - The new instance of ChatMessageContent.
|
||||
"""
|
||||
args = {"role": element.get("role", ChatRole.USER.value), "content": element.text}
|
||||
if function_call := element.get("function_call"):
|
||||
args["function_call"] = FunctionCall.model_validate_json(function_call)
|
||||
if tool_calls := element.get("tool_calls"):
|
||||
args["tool_calls"] = [ToolCall.model_validate_json(call) for call in tool_calls.split(",")]
|
||||
return cls(**args)
|
||||
|
||||
+3
-3
@@ -3,9 +3,9 @@ from typing import List, Optional
|
||||
|
||||
from openai.types.chat.chat_completion_chunk import ChatCompletionChunk
|
||||
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat.function_call import FunctionCall
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat.tool_calls import ToolCall
|
||||
from semantic_kernel.models.contents import StreamingChatMessageContent
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat_completion.function_call import FunctionCall
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat_completion.tool_calls import ToolCall
|
||||
from semantic_kernel.contents import StreamingChatMessageContent
|
||||
|
||||
|
||||
class OpenAIStreamingChatMessageContent(StreamingChatMessageContent):
|
||||
|
||||
+15
-9
@@ -1,9 +1,9 @@
|
||||
"""Class to hold chat messages."""
|
||||
import json
|
||||
from typing import Dict, Optional, Tuple
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from semantic_kernel.functions.kernel_arguments import KernelArguments
|
||||
from semantic_kernel.kernel_pydantic import KernelBaseModel
|
||||
from semantic_kernel.orchestration.context_variables import ContextVariables
|
||||
|
||||
|
||||
class FunctionCall(KernelBaseModel):
|
||||
@@ -24,23 +24,29 @@ class FunctionCall(KernelBaseModel):
|
||||
id=self.id or other.id,
|
||||
)
|
||||
|
||||
def parse_arguments(self) -> Dict[str, str]:
|
||||
def parse_arguments(self) -> Optional[Dict[str, Any]]:
|
||||
"""Parse the arguments into a dictionary."""
|
||||
if not self.arguments:
|
||||
return None
|
||||
try:
|
||||
return json.loads(self.arguments)
|
||||
except json.JSONDecodeError:
|
||||
return None
|
||||
|
||||
def to_context_variables(self) -> ContextVariables:
|
||||
"""Return the arguments as a ContextVariables instance."""
|
||||
def to_kernel_arguments(self) -> KernelArguments:
|
||||
"""Return the arguments as a KernelArguments instance."""
|
||||
args = self.parse_arguments()
|
||||
return ContextVariables(variables={k.lower(): str(v) for k, v in args.items()})
|
||||
if not args:
|
||||
return KernelArguments()
|
||||
return KernelArguments(**args)
|
||||
|
||||
def split_name(self) -> Tuple[str, str]:
|
||||
def split_name(self) -> List[str]:
|
||||
"""Split the name into a plugin and function name."""
|
||||
if not self.name:
|
||||
raise ValueError("Name is not set.")
|
||||
if "-" not in self.name:
|
||||
return None, self.name
|
||||
return self.name.split("-")
|
||||
return ["", self.name]
|
||||
return self.name.split("-", maxsplit=1)
|
||||
|
||||
def split_name_dict(self) -> dict:
|
||||
"""Split the name into a plugin and function name."""
|
||||
+4
-5
@@ -1,18 +1,17 @@
|
||||
"""Class to hold chat messages."""
|
||||
from typing import Optional
|
||||
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat.function_call import (
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat_completion.function_call import (
|
||||
FunctionCall,
|
||||
)
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat.tool_calls import ToolCall
|
||||
from semantic_kernel.models.chat.chat_message import ChatMessage
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat_completion.tool_calls import ToolCall
|
||||
from semantic_kernel.models.ai.chat_completion.chat_message import ChatMessage
|
||||
|
||||
|
||||
class OpenAIChatMessage(ChatMessage):
|
||||
"""Class to hold openai chat messages, which might include name and function_call fields."""
|
||||
"""Class to hold openai chat messages, which might include name, function_call and tool_calls fields."""
|
||||
|
||||
name: Optional[str] = None
|
||||
# TODO: handle tool_calls
|
||||
function_call: Optional[FunctionCall] = None
|
||||
tool_calls: Optional[ToolCall] = None
|
||||
tool_call_id: Optional[str] = None
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from typing import Literal, Optional
|
||||
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat.function_call import FunctionCall
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat_completion.function_call import FunctionCall
|
||||
from semantic_kernel.kernel_pydantic import KernelBaseModel
|
||||
|
||||
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
# # Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
# import logging
|
||||
# from typing import Any, Optional
|
||||
|
||||
# from semantic_kernel.connectors.ai.open_ai.models.chat_completion.open_ai_chat_message import (
|
||||
# OpenAIChatMessage,
|
||||
# )
|
||||
# from semantic_kernel.prompt_template.chat_prompt_template import ChatPromptTemplate
|
||||
# from semantic_kernel.prompt_template.prompt_template import PromptTemplate
|
||||
|
||||
# logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# class OpenAIChatPromptTemplate(ChatPromptTemplate[OpenAIChatMessage]):
|
||||
# def add_function_response_message(self, name: str, content: Any, tool_call_id: Optional[str] = None) -> None:
|
||||
# """Add a function response message to the chat template."""
|
||||
# self.messages.append(
|
||||
# OpenAIChatMessage(role="function", name=name, fixed_content=str(content), tool_call_id=tool_call_id)
|
||||
# )
|
||||
|
||||
# def add_tool_call_response_message(self, tool_call_id: str, content: Any) -> None:
|
||||
# """Add a tool call response message to the chat template."""
|
||||
# self.messages.append(OpenAIChatMessage(role="tool", tool_call_id=tool_call_id, fixed_content=str(content)))
|
||||
|
||||
# def add_message(self, role: str, message: Optional[str] = None, **kwargs: Any) -> None:
|
||||
# """Add a message to the chat template.
|
||||
|
||||
# Arguments:
|
||||
# role: The role of the message, one of "user", "assistant", "system", "function"
|
||||
# message: The message to add, can include templating components.
|
||||
# kwargs: can be used by inherited classes.
|
||||
# name: the name of the function that was used, to be used with role: function
|
||||
# function_call: the function call that is specified, to be used with role: assistant
|
||||
# """
|
||||
# name = kwargs.get("name")
|
||||
# if name is not None and role != "function":
|
||||
# logger.warning("name is only used with role: function, ignoring")
|
||||
# name = None
|
||||
# function_call = kwargs.get("function_call")
|
||||
# if function_call is not None:
|
||||
# if role == "assistant":
|
||||
# self.messages.append(
|
||||
# OpenAIChatMessage(
|
||||
# role=role,
|
||||
# fixed_content=message,
|
||||
# name=name,
|
||||
# function_call=function_call,
|
||||
# )
|
||||
# )
|
||||
# return
|
||||
# logger.warning("function_call is only used with role: assistant, ignoring")
|
||||
# function_call = None
|
||||
# tool_calls = kwargs.get("tool_calls")
|
||||
# if tool_calls is not None:
|
||||
# # TODO: update this when tool_calls is implemented
|
||||
# # and allow for multiple tool calls
|
||||
# ids = [tool_call.id for tool_call in tool_calls]
|
||||
# if role == "assistant":
|
||||
# self.messages.append(
|
||||
# OpenAIChatMessage(
|
||||
# role=role,
|
||||
# fixed_content=message,
|
||||
# name=name,
|
||||
# tool_calls=tool_calls[0],
|
||||
# tool_call_id=ids[0],
|
||||
# )
|
||||
# )
|
||||
# return
|
||||
# self._log.warning("tool_calls is only used with role: assistant, ignoring")
|
||||
# tool_calls = None
|
||||
# tool_call_id = kwargs.get("tool_call_id")
|
||||
# if tool_call_id is not None:
|
||||
# if role == "tool":
|
||||
# self.messages.append(
|
||||
# OpenAIChatMessage(
|
||||
# role=role,
|
||||
# fixed_content=message,
|
||||
# name=name,
|
||||
# tool_call_id=tool_call_id,
|
||||
# )
|
||||
# )
|
||||
# return
|
||||
# self._log.warning("tool_call_id is only used with role: tool, ignoring")
|
||||
# tool_call_id = None
|
||||
# self.messages.append(
|
||||
# OpenAIChatMessage(
|
||||
# role=role,
|
||||
# content_template=PromptTemplate(message, self.template_engine, self.prompt_config),
|
||||
# name=name,
|
||||
# function_call=function_call,
|
||||
# )
|
||||
# )
|
||||
-93
@@ -1,93 +0,0 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from typing import Any, Optional
|
||||
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat.open_ai_chat_message import (
|
||||
OpenAIChatMessage,
|
||||
)
|
||||
from semantic_kernel.semantic_functions.chat_prompt_template import ChatPromptTemplate
|
||||
from semantic_kernel.semantic_functions.prompt_template import PromptTemplate
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OpenAIChatPromptTemplate(ChatPromptTemplate[OpenAIChatMessage]):
|
||||
def add_function_response_message(self, name: str, content: Any, tool_call_id: Optional[str] = None) -> None:
|
||||
"""Add a function response message to the chat template."""
|
||||
self.messages.append(
|
||||
OpenAIChatMessage(role="function", name=name, fixed_content=str(content), tool_call_id=tool_call_id)
|
||||
)
|
||||
|
||||
def add_tool_call_response_message(self, tool_call_id: str, content: Any) -> None:
|
||||
"""Add a tool call response message to the chat template."""
|
||||
self.messages.append(OpenAIChatMessage(role="tool", tool_call_id=tool_call_id, fixed_content=str(content)))
|
||||
|
||||
def add_message(self, role: str, message: Optional[str] = None, **kwargs: Any) -> None:
|
||||
"""Add a message to the chat template.
|
||||
|
||||
Arguments:
|
||||
role: The role of the message, one of "user", "assistant", "system", "function"
|
||||
message: The message to add, can include templating components.
|
||||
kwargs: can be used by inherited classes.
|
||||
name: the name of the function that was used, to be used with role: function
|
||||
function_call: the function call that is specified, to be used with role: assistant
|
||||
"""
|
||||
name = kwargs.get("name")
|
||||
if name is not None and role != "function":
|
||||
logger.warning("name is only used with role: function, ignoring")
|
||||
name = None
|
||||
function_call = kwargs.get("function_call")
|
||||
if function_call is not None:
|
||||
if role == "assistant":
|
||||
self.messages.append(
|
||||
OpenAIChatMessage(
|
||||
role=role,
|
||||
fixed_content=message,
|
||||
name=name,
|
||||
function_call=function_call,
|
||||
)
|
||||
)
|
||||
return
|
||||
logger.warning("function_call is only used with role: assistant, ignoring")
|
||||
function_call = None
|
||||
tool_calls = kwargs.get("tool_calls")
|
||||
if tool_calls is not None:
|
||||
# TODO: update this when tool_calls is implemented
|
||||
# and allow for multiple tool calls
|
||||
ids = [tool_call.id for tool_call in tool_calls]
|
||||
if role == "assistant":
|
||||
self.messages.append(
|
||||
OpenAIChatMessage(
|
||||
role=role,
|
||||
fixed_content=message,
|
||||
name=name,
|
||||
tool_calls=tool_calls[0],
|
||||
tool_call_id=ids[0],
|
||||
)
|
||||
)
|
||||
return
|
||||
self._log.warning("tool_calls is only used with role: assistant, ignoring")
|
||||
tool_calls = None
|
||||
tool_call_id = kwargs.get("tool_call_id")
|
||||
if tool_call_id is not None:
|
||||
if role == "tool":
|
||||
self.messages.append(
|
||||
OpenAIChatMessage(
|
||||
role=role,
|
||||
fixed_content=message,
|
||||
name=name,
|
||||
tool_call_id=tool_call_id,
|
||||
)
|
||||
)
|
||||
return
|
||||
self._log.warning("tool_call_id is only used with role: tool, ignoring")
|
||||
tool_call_id = None
|
||||
self.messages.append(
|
||||
OpenAIChatMessage(
|
||||
role=role,
|
||||
content_template=PromptTemplate(message, self.template_engine, self.prompt_config),
|
||||
name=name,
|
||||
function_call=function_call,
|
||||
)
|
||||
)
|
||||
@@ -35,9 +35,9 @@ from semantic_kernel.connectors.ai.open_ai.services.open_ai_text_completion_base
|
||||
OpenAITextCompletionBase,
|
||||
)
|
||||
from semantic_kernel.connectors.ai.prompt_execution_settings import PromptExecutionSettings
|
||||
from semantic_kernel.contents.chat_role import ChatRole
|
||||
from semantic_kernel.contents.finish_reason import FinishReason
|
||||
from semantic_kernel.kernel_pydantic import HttpsUrl
|
||||
from semantic_kernel.models.chat.chat_role import ChatRole
|
||||
from semantic_kernel.models.chat.finish_reason import FinishReason
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -50,12 +50,12 @@ class AzureChatCompletion(AzureOpenAIConfigBase, OpenAIChatCompletionBase, OpenA
|
||||
self,
|
||||
deployment_name: str,
|
||||
base_url: Union[HttpsUrl, str],
|
||||
service_id: Optional[str] = None,
|
||||
api_version: str = DEFAULT_AZURE_API_VERSION,
|
||||
api_key: Optional[str] = None,
|
||||
ad_token: Optional[str] = None,
|
||||
ad_token_provider: Optional[AsyncAzureADTokenProvider] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an AzureChatCompletion service.
|
||||
@@ -80,8 +80,6 @@ class AzureChatCompletion(AzureOpenAIConfigBase, OpenAIChatCompletionBase, OpenA
|
||||
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) (Deprecated)
|
||||
logger: deprecated, use 'log' instead.
|
||||
"""
|
||||
|
||||
@overload
|
||||
@@ -90,11 +88,11 @@ class AzureChatCompletion(AzureOpenAIConfigBase, OpenAIChatCompletionBase, OpenA
|
||||
deployment_name: str,
|
||||
endpoint: Union[HttpsUrl, str],
|
||||
api_version: str = DEFAULT_AZURE_API_VERSION,
|
||||
service_id: Optional[str] = None,
|
||||
api_key: Optional[str] = None,
|
||||
ad_token: Optional[str] = None,
|
||||
ad_token_provider: Optional[AsyncAzureADTokenProvider] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an AzureChatCompletion service.
|
||||
@@ -117,8 +115,6 @@ class AzureChatCompletion(AzureOpenAIConfigBase, OpenAIChatCompletionBase, OpenA
|
||||
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) (Deprecated)
|
||||
logger: deprecated, use 'log' instead.
|
||||
"""
|
||||
|
||||
@overload
|
||||
@@ -126,7 +122,7 @@ class AzureChatCompletion(AzureOpenAIConfigBase, OpenAIChatCompletionBase, OpenA
|
||||
self,
|
||||
deployment_name: str,
|
||||
async_client: AsyncAzureOpenAI,
|
||||
log: Optional[Any] = None,
|
||||
service_id: Optional[str] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an AzureChatCompletion service.
|
||||
@@ -138,7 +134,6 @@ class AzureChatCompletion(AzureOpenAIConfigBase, OpenAIChatCompletionBase, OpenA
|
||||
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) (Deprecated)
|
||||
"""
|
||||
|
||||
@overload
|
||||
@@ -147,11 +142,11 @@ class AzureChatCompletion(AzureOpenAIConfigBase, OpenAIChatCompletionBase, OpenA
|
||||
deployment_name: str,
|
||||
endpoint: Union[HttpsUrl, str],
|
||||
api_version: str = DEFAULT_AZURE_API_VERSION,
|
||||
service_id: Optional[str] = None,
|
||||
api_key: Optional[str] = None,
|
||||
ad_token: Optional[str] = None,
|
||||
ad_token_provider: Optional[AsyncAzureADTokenProvider] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Any] = None,
|
||||
use_extensions: bool = False,
|
||||
) -> None:
|
||||
"""
|
||||
@@ -187,14 +182,13 @@ class AzureChatCompletion(AzureOpenAIConfigBase, OpenAIChatCompletionBase, OpenA
|
||||
endpoint: Optional[Union[HttpsUrl, str]] = None,
|
||||
base_url: Optional[Union[HttpsUrl, str]] = None,
|
||||
api_version: str = DEFAULT_AZURE_API_VERSION,
|
||||
service_id: Optional[str] = None,
|
||||
api_key: Optional[str] = None,
|
||||
ad_token: Optional[str] = None,
|
||||
ad_token_provider: Optional[AsyncAzureADTokenProvider] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
async_client: Optional[AsyncAzureOpenAI] = None,
|
||||
use_extensions: bool = False,
|
||||
log: Optional[Any] = None,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an AzureChatCompletion service.
|
||||
@@ -223,18 +217,11 @@ class AzureChatCompletion(AzureOpenAIConfigBase, OpenAIChatCompletionBase, OpenA
|
||||
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) (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 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 base_url and isinstance(base_url, str):
|
||||
base_url = HttpsUrl(base_url)
|
||||
if use_extensions and endpoint and deployment_name:
|
||||
@@ -244,6 +231,7 @@ class AzureChatCompletion(AzureOpenAIConfigBase, OpenAIChatCompletionBase, OpenA
|
||||
endpoint=endpoint if not isinstance(endpoint, str) else HttpsUrl(endpoint),
|
||||
base_url=base_url,
|
||||
api_version=api_version,
|
||||
service_id=service_id,
|
||||
api_key=api_key,
|
||||
ad_token=ad_token,
|
||||
ad_token_provider=ad_token_provider,
|
||||
@@ -267,6 +255,7 @@ class AzureChatCompletion(AzureOpenAIConfigBase, OpenAIChatCompletionBase, OpenA
|
||||
endpoint=settings.get("endpoint"),
|
||||
base_url=settings.get("base_url"),
|
||||
api_version=settings.get("api_version", DEFAULT_AZURE_API_VERSION),
|
||||
service_id=settings.get("service_id"),
|
||||
api_key=settings.get("api_key"),
|
||||
ad_token=settings.get("ad_token"),
|
||||
ad_token_provider=settings.get("ad_token_provider"),
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import json
|
||||
import logging
|
||||
from typing import Any, Awaitable, Callable, Dict, Mapping, Optional, Union
|
||||
from typing import Awaitable, Callable, Dict, Mapping, Optional, Union
|
||||
|
||||
from openai import AsyncAzureOpenAI
|
||||
from pydantic import validate_call
|
||||
@@ -33,11 +33,11 @@ class AzureOpenAIConfigBase(OpenAIHandler):
|
||||
endpoint: Optional[HttpsUrl] = None,
|
||||
base_url: Optional[HttpsUrl] = None,
|
||||
api_version: str = DEFAULT_AZURE_API_VERSION,
|
||||
service_id: Optional[str] = None,
|
||||
api_key: Optional[str] = None,
|
||||
ad_token: Optional[str] = None,
|
||||
ad_token_provider: Optional[Callable[[], Union[str, Awaitable[str]]]] = None,
|
||||
default_headers: Union[Mapping[str, str], None] = None,
|
||||
log: Optional[Any] = None,
|
||||
async_client: Optional[AsyncAzureOpenAI] = None,
|
||||
) -> None:
|
||||
"""Internal class for configuring a connection to an Azure OpenAI service.
|
||||
@@ -53,14 +53,11 @@ 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 -- 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:
|
||||
@@ -96,12 +93,14 @@ class AzureOpenAIConfigBase(OpenAIHandler):
|
||||
azure_ad_token_provider=ad_token_provider,
|
||||
default_headers=merged_headers,
|
||||
)
|
||||
|
||||
super().__init__(
|
||||
ai_model_id=deployment_name,
|
||||
client=async_client,
|
||||
ai_model_type=ai_model_type,
|
||||
)
|
||||
args = {
|
||||
"ai_model_id": deployment_name,
|
||||
"client": async_client,
|
||||
"ai_model_type": ai_model_type,
|
||||
}
|
||||
if service_id:
|
||||
args["service_id"] = service_id
|
||||
super().__init__(**args)
|
||||
|
||||
def to_dict(self) -> Dict[str, str]:
|
||||
client_settings = {
|
||||
@@ -120,6 +119,7 @@ class AzureOpenAIConfigBase(OpenAIHandler):
|
||||
"api_type",
|
||||
"org_id",
|
||||
"ai_model_type",
|
||||
"service_id",
|
||||
"client",
|
||||
},
|
||||
by_alias=True,
|
||||
|
||||
@@ -28,11 +28,11 @@ class AzureTextCompletion(AzureOpenAIConfigBase, OpenAITextCompletionBase):
|
||||
self,
|
||||
base_url: str,
|
||||
api_version: str = DEFAULT_AZURE_API_VERSION,
|
||||
service_id: Optional[str] = None,
|
||||
api_key: Optional[str] = None,
|
||||
ad_token: Optional[str] = None,
|
||||
ad_token_provider: Optional[AsyncAzureADTokenProvider] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an AzureTextCompletion service.
|
||||
@@ -55,8 +55,6 @@ 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) (Deprecated)
|
||||
logger: deprecated.
|
||||
"""
|
||||
|
||||
@overload
|
||||
@@ -65,6 +63,7 @@ class AzureTextCompletion(AzureOpenAIConfigBase, OpenAITextCompletionBase):
|
||||
deployment_name: str,
|
||||
endpoint: str,
|
||||
api_version: str = DEFAULT_AZURE_API_VERSION,
|
||||
service_id: Optional[str] = None,
|
||||
api_key: Optional[str] = None,
|
||||
ad_token: Optional[str] = None,
|
||||
ad_token_provider: Optional[AsyncAzureADTokenProvider] = None,
|
||||
@@ -92,8 +91,6 @@ 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) (Deprecated)
|
||||
logger: deprecated, use 'log' instead.
|
||||
"""
|
||||
|
||||
@overload
|
||||
@@ -101,7 +98,7 @@ class AzureTextCompletion(AzureOpenAIConfigBase, OpenAITextCompletionBase):
|
||||
self,
|
||||
deployment_name: str,
|
||||
async_client: AsyncAzureOpenAI,
|
||||
log: Optional[Any] = None,
|
||||
service_id: Optional[str] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an AzureChatCompletion service.
|
||||
@@ -113,7 +110,6 @@ 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) (Deprecated)
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -122,13 +118,12 @@ class AzureTextCompletion(AzureOpenAIConfigBase, OpenAITextCompletionBase):
|
||||
endpoint: Optional[str] = None,
|
||||
base_url: Optional[str] = None,
|
||||
api_version: str = DEFAULT_AZURE_API_VERSION,
|
||||
service_id: Optional[str] = None,
|
||||
api_key: Optional[str] = None,
|
||||
ad_token: Optional[str] = None,
|
||||
ad_token_provider: Optional[AsyncAzureADTokenProvider] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Any] = None,
|
||||
async_client: Optional[AsyncAzureOpenAI] = None,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an AzureTextCompletion service.
|
||||
@@ -151,19 +146,14 @@ 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) (Deprecated)
|
||||
logger: deprecated, use 'log' instead.
|
||||
async_client {Optional[AsyncAzureOpenAI]} -- An existing client to use.
|
||||
"""
|
||||
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,
|
||||
base_url=base_url,
|
||||
api_version=api_version,
|
||||
service_id=service_id,
|
||||
api_key=api_key,
|
||||
ad_token=ad_token,
|
||||
ad_token_provider=ad_token_provider,
|
||||
@@ -188,6 +178,7 @@ class AzureTextCompletion(AzureOpenAIConfigBase, OpenAITextCompletionBase):
|
||||
endpoint=settings.get("endpoint"),
|
||||
base_url=settings.get("base_url"),
|
||||
api_version=settings.get("api_version", DEFAULT_AZURE_API_VERSION),
|
||||
service_id=settings.get("service_id"),
|
||||
api_key=settings["api_key"],
|
||||
ad_token=settings.get("ad_token"),
|
||||
ad_token_provider=settings.get("ad_token_provider"),
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
|
||||
import logging
|
||||
from typing import Any, Dict, Mapping, Optional, overload
|
||||
from typing import Dict, Mapping, Optional, overload
|
||||
|
||||
from openai import AsyncAzureOpenAI
|
||||
from openai.lib.azure import AsyncAzureADTokenProvider
|
||||
@@ -29,7 +29,7 @@ class AzureTextEmbedding(AzureOpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
self,
|
||||
deployment_name: str,
|
||||
async_client: AsyncAzureOpenAI,
|
||||
log: Optional[Any] = None,
|
||||
service_id: Optional[str] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an AzureChatCompletion service.
|
||||
@@ -41,7 +41,6 @@ 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) (Deprecated)
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -49,13 +48,12 @@ class AzureTextEmbedding(AzureOpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
deployment_name: str,
|
||||
endpoint: Optional[str] = None,
|
||||
api_version: str = DEFAULT_AZURE_API_VERSION,
|
||||
service_id: Optional[str] = None,
|
||||
api_key: Optional[str] = None,
|
||||
ad_token: Optional[str] = None,
|
||||
ad_token_provider: Optional[AsyncAzureADTokenProvider] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Any] = None,
|
||||
async_client: Optional[AsyncAzureOpenAI] = None,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an AzureTextEmbedding service.
|
||||
@@ -81,19 +79,14 @@ 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) (Deprecated)
|
||||
:param logger: Deprecated, please use log instead. (Optional)
|
||||
:param async_client: An existing client to use. (Optional)
|
||||
|
||||
"""
|
||||
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,
|
||||
api_version=api_version,
|
||||
service_id=service_id,
|
||||
api_key=api_key,
|
||||
ad_token=ad_token,
|
||||
ad_token_provider=ad_token_provider,
|
||||
@@ -117,6 +110,7 @@ class AzureTextEmbedding(AzureOpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
endpoint=settings["endpoint"],
|
||||
api_key=settings["api_key"],
|
||||
api_version=settings.get("api_version", DEFAULT_AZURE_API_VERSION),
|
||||
service_id=settings.get("service_id"),
|
||||
ad_token=settings.get("ad_token"),
|
||||
ad_token_provider=settings.get("ad_token_provider"),
|
||||
default_headers=settings.get("default_headers"),
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import logging
|
||||
from typing import (
|
||||
Any,
|
||||
Dict,
|
||||
Mapping,
|
||||
Optional,
|
||||
@@ -31,7 +30,7 @@ class OpenAIChatCompletion(OpenAIConfigBase, OpenAIChatCompletionBase, OpenAITex
|
||||
self,
|
||||
ai_model_id: str,
|
||||
async_client: AsyncOpenAI,
|
||||
log: Optional[Any] = None,
|
||||
service_id: Optional[str] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an OpenAIChatCompletion service.
|
||||
@@ -40,7 +39,6 @@ class OpenAIChatCompletion(OpenAIConfigBase, OpenAIChatCompletionBase, OpenAITex
|
||||
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) (Deprecated)
|
||||
"""
|
||||
|
||||
@overload
|
||||
@@ -49,8 +47,8 @@ class OpenAIChatCompletion(OpenAIConfigBase, OpenAIChatCompletionBase, OpenAITex
|
||||
ai_model_id: str,
|
||||
api_key: Optional[str] = None,
|
||||
org_id: Optional[str] = None,
|
||||
service_id: Optional[str] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an OpenAIChatCompletion service.
|
||||
@@ -65,7 +63,6 @@ class OpenAIChatCompletion(OpenAIConfigBase, OpenAIChatCompletionBase, OpenAITex
|
||||
account belongs to multiple organizations.
|
||||
default_headers: The default headers mapping of string keys to
|
||||
string values for HTTP requests. (Optional)
|
||||
log -- The logger instance to use. (Optional) (Deprecated)
|
||||
"""
|
||||
|
||||
@overload
|
||||
@@ -73,8 +70,8 @@ class OpenAIChatCompletion(OpenAIConfigBase, OpenAIChatCompletionBase, OpenAITex
|
||||
self,
|
||||
ai_model_id: str,
|
||||
api_key: Optional[str] = None,
|
||||
service_id: Optional[str] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an OpenAIChatCompletion service.
|
||||
@@ -86,7 +83,6 @@ class OpenAIChatCompletion(OpenAIConfigBase, OpenAIChatCompletionBase, OpenAITex
|
||||
https://platform.openai.com/account/api-keys
|
||||
default_headers: The default headers mapping of string keys to
|
||||
string values for HTTP requests. (Optional)
|
||||
log -- The logger instance to use. (Optional) (Deprecated)
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -94,9 +90,9 @@ class OpenAIChatCompletion(OpenAIConfigBase, OpenAIChatCompletionBase, OpenAITex
|
||||
ai_model_id: str,
|
||||
api_key: Optional[str] = None,
|
||||
org_id: Optional[str] = None,
|
||||
service_id: Optional[str] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
async_client: Optional[AsyncOpenAI] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an OpenAIChatCompletion service.
|
||||
@@ -112,14 +108,12 @@ class OpenAIChatCompletion(OpenAIConfigBase, OpenAIChatCompletionBase, OpenAITex
|
||||
default_headers: The default headers mapping of string keys to
|
||||
string values for HTTP requests. (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,
|
||||
service_id=service_id,
|
||||
ai_model_type=OpenAIModelTypes.CHAT,
|
||||
default_headers=default_headers,
|
||||
async_client=async_client,
|
||||
@@ -138,5 +132,6 @@ class OpenAIChatCompletion(OpenAIConfigBase, OpenAIChatCompletionBase, OpenAITex
|
||||
ai_model_id=settings["ai_model_id"],
|
||||
api_key=settings["api_key"],
|
||||
org_id=settings.get("org_id"),
|
||||
service_id=settings.get("service_id"),
|
||||
default_headers=settings.get("default_headers"),
|
||||
)
|
||||
|
||||
+19
-15
@@ -6,6 +6,7 @@ from typing import (
|
||||
Dict,
|
||||
List,
|
||||
Optional,
|
||||
Type,
|
||||
Union,
|
||||
)
|
||||
|
||||
@@ -18,16 +19,18 @@ from semantic_kernel.connectors.ai.chat_completion_client_base import (
|
||||
ChatCompletionClientBase,
|
||||
)
|
||||
from semantic_kernel.connectors.ai.open_ai.contents import OpenAIChatMessageContent, OpenAIStreamingChatMessageContent
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat.function_call import FunctionCall
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat.tool_calls import ToolCall
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat_completion.function_call import FunctionCall
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat_completion.tool_calls import ToolCall
|
||||
from semantic_kernel.connectors.ai.open_ai.prompt_execution_settings.open_ai_prompt_execution_settings import (
|
||||
OpenAIChatPromptExecutionSettings,
|
||||
OpenAIPromptExecutionSettings,
|
||||
)
|
||||
from semantic_kernel.connectors.ai.open_ai.services.open_ai_handler import OpenAIHandler
|
||||
from semantic_kernel.connectors.ai.prompt_execution_settings import PromptExecutionSettings
|
||||
from semantic_kernel.models.chat.chat_role import ChatRole
|
||||
from semantic_kernel.models.chat.finish_reason import FinishReason
|
||||
from semantic_kernel.contents.chat_history import ChatHistory
|
||||
from semantic_kernel.contents.chat_message_content import ChatMessageContent
|
||||
from semantic_kernel.contents.chat_role import ChatRole
|
||||
from semantic_kernel.contents.finish_reason import FinishReason
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -39,24 +42,26 @@ class OpenAIChatCompletionBase(OpenAIHandler, ChatCompletionClientBase):
|
||||
"""Create a request settings object."""
|
||||
return OpenAIChatPromptExecutionSettings
|
||||
|
||||
def get_chat_message_content_class(self) -> Type[ChatMessageContent]:
|
||||
"""Get the chat message content types used by a class, default is ChatMessageContent."""
|
||||
return OpenAIChatMessageContent
|
||||
|
||||
async def complete_chat(
|
||||
self,
|
||||
messages: List[Dict[str, str]],
|
||||
chat_history: ChatHistory,
|
||||
settings: OpenAIPromptExecutionSettings,
|
||||
**kwargs,
|
||||
) -> List[OpenAIChatMessageContent]:
|
||||
"""Executes a chat completion request and returns the result.
|
||||
|
||||
Arguments:
|
||||
messages {List[Dict[str,str]]} -- The messages to use for the chat completion.
|
||||
chat_history {ChatHistory} -- The chat history to use for the chat completion.
|
||||
settings {OpenAIChatPromptExecutionSettings | AzureChatPromptExecutionSettings} -- The settings to use
|
||||
for the chat completion request.
|
||||
|
||||
Returns:
|
||||
List[OpenAIChatMessageContent | AzureChatMessageContent] -- The completion result(s).
|
||||
"""
|
||||
# TODO: replace messages with ChatHistory object with ChatMessageContent objects
|
||||
settings.messages = messages
|
||||
settings.messages = self._prepare_chat_history_for_request(chat_history)
|
||||
settings.stream = False
|
||||
if not settings.ai_model_id:
|
||||
settings.ai_model_id = self.ai_model_id
|
||||
@@ -66,14 +71,13 @@ class OpenAIChatCompletionBase(OpenAIHandler, ChatCompletionClientBase):
|
||||
|
||||
async def complete_chat_stream(
|
||||
self,
|
||||
messages: List[Dict[str, str]],
|
||||
chat_history: ChatHistory,
|
||||
settings: OpenAIPromptExecutionSettings,
|
||||
**kwargs,
|
||||
) -> AsyncIterable[List[OpenAIStreamingChatMessageContent]]:
|
||||
"""Executes a streaming chat completion request and returns the result.
|
||||
|
||||
Arguments:
|
||||
messages {List[Tuple[str,str]]} -- The messages to use for the chat completion.
|
||||
chat_history {ChatHistory} -- The chat history to use for the chat completion.
|
||||
settings {OpenAIChatPromptExecutionSettings | AzureChatPromptExecutionSettings} -- The settings to use
|
||||
for the chat completion request.
|
||||
|
||||
@@ -81,7 +85,7 @@ class OpenAIChatCompletionBase(OpenAIHandler, ChatCompletionClientBase):
|
||||
List[OpenAIStreamingChatMessageContent | AzureStreamingChatMessageContent] -- A stream of
|
||||
OpenAIStreamingChatMessages or AzureStreamingChatMessageContent when using Azure.
|
||||
"""
|
||||
settings.messages = messages
|
||||
settings.messages = self._prepare_chat_history_for_request(chat_history)
|
||||
settings.stream = True
|
||||
if not settings.ai_model_id:
|
||||
settings.ai_model_id = self.ai_model_id
|
||||
@@ -131,9 +135,9 @@ class OpenAIChatCompletionBase(OpenAIHandler, ChatCompletionClientBase):
|
||||
inner_content=chunk,
|
||||
ai_model_id=self.ai_model_id,
|
||||
metadata=metadata,
|
||||
role=ChatRole(choice.delta.role),
|
||||
role=ChatRole(choice.delta.role) if choice.delta.role else None,
|
||||
content=choice.delta.content,
|
||||
finish_reason=FinishReason(choice.finish_reason),
|
||||
finish_reason=FinishReason(choice.finish_reason) if choice.finish_reason else None,
|
||||
function_call=self._get_function_call_from_chat_choice(choice),
|
||||
tool_calls=self._get_tool_calls_from_chat_choice(choice),
|
||||
)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import json
|
||||
import logging
|
||||
from typing import Any, Dict, Mapping, Optional
|
||||
from typing import Dict, Mapping, Optional
|
||||
|
||||
from openai import AsyncOpenAI
|
||||
from pydantic import Field, validate_call
|
||||
@@ -30,9 +30,9 @@ class OpenAIConfigBase(OpenAIHandler):
|
||||
api_key: Optional[str] = Field(min_length=1),
|
||||
ai_model_type: Optional[OpenAIModelTypes] = OpenAIModelTypes.CHAT,
|
||||
org_id: Optional[str] = None,
|
||||
service_id: Optional[str] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
async_client: Optional[AsyncOpenAI] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""Initialize a client for OpenAI services.
|
||||
|
||||
@@ -52,8 +52,6 @@ class OpenAIConfigBase(OpenAIHandler):
|
||||
for HTTP requests. (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:
|
||||
@@ -70,12 +68,14 @@ class OpenAIConfigBase(OpenAIHandler):
|
||||
organization=org_id,
|
||||
default_headers=merged_headers,
|
||||
)
|
||||
|
||||
super().__init__(
|
||||
ai_model_id=ai_model_id,
|
||||
client=async_client,
|
||||
ai_model_type=ai_model_type,
|
||||
)
|
||||
args = {
|
||||
"ai_model_id": ai_model_id,
|
||||
"client": async_client,
|
||||
"ai_model_type": ai_model_type,
|
||||
}
|
||||
if service_id:
|
||||
args["service_id"] = service_id
|
||||
super().__init__(**args)
|
||||
|
||||
def to_dict(self) -> Dict[str, str]:
|
||||
"""
|
||||
@@ -94,6 +94,7 @@ class OpenAIConfigBase(OpenAIHandler):
|
||||
"total_tokens",
|
||||
"api_type",
|
||||
"ai_model_type",
|
||||
"service_id",
|
||||
"client",
|
||||
},
|
||||
by_alias=True,
|
||||
|
||||
@@ -8,10 +8,8 @@ from numpy import array, ndarray
|
||||
from openai import AsyncOpenAI, AsyncStream, BadRequestError
|
||||
from openai.types import Completion
|
||||
from openai.types.chat import ChatCompletion, ChatCompletionChunk
|
||||
from pydantic import Field
|
||||
|
||||
from semantic_kernel.connectors.ai.ai_exception import AIException
|
||||
from semantic_kernel.connectors.ai.ai_service_client_base import AIServiceClientBase
|
||||
from semantic_kernel.connectors.ai.open_ai.exceptions.content_filter_ai_exception import (
|
||||
ContentFilterAIException,
|
||||
)
|
||||
@@ -22,19 +20,19 @@ from semantic_kernel.connectors.ai.open_ai.prompt_execution_settings.open_ai_pro
|
||||
from semantic_kernel.connectors.ai.open_ai.services.open_ai_model_types import (
|
||||
OpenAIModelTypes,
|
||||
)
|
||||
from semantic_kernel.connectors.ai.prompt_execution_settings import PromptExecutionSettings
|
||||
from semantic_kernel.kernel_pydantic import KernelBaseModel
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OpenAIHandler(AIServiceClientBase, ABC):
|
||||
class OpenAIHandler(KernelBaseModel, ABC):
|
||||
"""Internal class for calls to OpenAI API's."""
|
||||
|
||||
client: AsyncOpenAI
|
||||
ai_model_type: OpenAIModelTypes = OpenAIModelTypes.CHAT
|
||||
prompt_tokens: int = Field(0, init_var=False)
|
||||
completion_tokens: int = Field(0, init_var=False)
|
||||
total_tokens: int = Field(0, init_var=False)
|
||||
prompt_tokens: int = 0
|
||||
completion_tokens: int = 0
|
||||
total_tokens: int = 0
|
||||
|
||||
async def _send_request(
|
||||
self,
|
||||
@@ -100,7 +98,3 @@ class OpenAIHandler(AIServiceClientBase, ABC):
|
||||
self.total_tokens += response.usage.total_tokens
|
||||
if hasattr(response.usage, "completion_tokens"):
|
||||
self.completion_tokens += response.usage.completion_tokens
|
||||
|
||||
def get_prompt_execution_settings_class(self) -> "PromptExecutionSettings":
|
||||
"""Return the class with the applicable request settings."""
|
||||
return OpenAIPromptExecutionSettings
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import json
|
||||
import logging
|
||||
from typing import Any, Dict, Mapping, Optional, overload
|
||||
from typing import Dict, Mapping, Optional, overload
|
||||
|
||||
from openai import AsyncOpenAI
|
||||
|
||||
@@ -27,7 +27,7 @@ class OpenAITextCompletion(OpenAITextCompletionBase, OpenAIConfigBase):
|
||||
self,
|
||||
ai_model_id: str,
|
||||
async_client: AsyncOpenAI,
|
||||
log: Optional[Any] = None,
|
||||
service_id: Optional[str] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an OpenAITextCompletion service.
|
||||
@@ -44,8 +44,8 @@ class OpenAITextCompletion(OpenAITextCompletionBase, OpenAIConfigBase):
|
||||
ai_model_id: str,
|
||||
api_key: Optional[str] = None,
|
||||
org_id: Optional[str] = None,
|
||||
service_id: Optional[str] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an OpenAITextCompletion service.
|
||||
@@ -67,8 +67,8 @@ class OpenAITextCompletion(OpenAITextCompletionBase, OpenAIConfigBase):
|
||||
self,
|
||||
ai_model_id: str,
|
||||
api_key: Optional[str] = None,
|
||||
service_id: Optional[str] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an OpenAITextCompletion service.
|
||||
@@ -87,8 +87,8 @@ class OpenAITextCompletion(OpenAITextCompletionBase, OpenAIConfigBase):
|
||||
ai_model_id: str,
|
||||
api_key: Optional[str] = None,
|
||||
org_id: Optional[str] = None,
|
||||
service_id: Optional[str] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
log: Optional[Any] = None,
|
||||
async_client: Optional[AsyncOpenAI] = None,
|
||||
) -> None:
|
||||
"""
|
||||
@@ -106,12 +106,11 @@ class OpenAITextCompletion(OpenAITextCompletionBase, OpenAIConfigBase):
|
||||
string values for HTTP requests. (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,
|
||||
service_id=service_id,
|
||||
ai_model_type=OpenAIModelTypes.TEXT,
|
||||
default_headers=default_headers,
|
||||
async_client=async_client,
|
||||
@@ -131,5 +130,6 @@ class OpenAITextCompletion(OpenAITextCompletionBase, OpenAIConfigBase):
|
||||
ai_model_id=settings["ai_model_id"],
|
||||
api_key=settings["api_key"],
|
||||
org_id=settings.get("org_id"),
|
||||
service_id=settings.get("service_id"),
|
||||
default_headers=settings.get("default_headers"),
|
||||
)
|
||||
|
||||
+1
-3
@@ -16,7 +16,7 @@ from semantic_kernel.connectors.ai.open_ai.services.open_ai_handler import (
|
||||
OpenAIHandler,
|
||||
)
|
||||
from semantic_kernel.connectors.ai.prompt_execution_settings import PromptExecutionSettings
|
||||
from semantic_kernel.models.contents import StreamingTextContent, TextContent
|
||||
from semantic_kernel.contents import StreamingTextContent, TextContent
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from semantic_kernel.connectors.ai.open_ai.prompt_execution_settings.open_ai_prompt_execution_settings import (
|
||||
@@ -35,7 +35,6 @@ class OpenAITextCompletionBase(OpenAIHandler, TextCompletionClientBase):
|
||||
self,
|
||||
prompt: str,
|
||||
settings: "OpenAIPromptExecutionSettings",
|
||||
**kwargs,
|
||||
) -> List["TextContent"]:
|
||||
"""Executes a completion request and returns the result.
|
||||
|
||||
@@ -77,7 +76,6 @@ class OpenAITextCompletionBase(OpenAIHandler, TextCompletionClientBase):
|
||||
self,
|
||||
prompt: str,
|
||||
settings: "OpenAIPromptExecutionSettings",
|
||||
**kwargs,
|
||||
) -> AsyncIterable[List["StreamingTextContent"]]:
|
||||
"""
|
||||
Executes a completion request and streams the result.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import logging
|
||||
from typing import Any, Dict, Mapping, Optional, overload
|
||||
from typing import Dict, Mapping, Optional, overload
|
||||
|
||||
from openai import AsyncOpenAI
|
||||
|
||||
@@ -26,7 +26,7 @@ class OpenAITextEmbedding(OpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
self,
|
||||
ai_model_id: str,
|
||||
async_client: AsyncOpenAI,
|
||||
log: Optional[Any] = None,
|
||||
service_id: Optional[str] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize an OpenAITextEmbedding service.
|
||||
@@ -42,9 +42,9 @@ class OpenAITextEmbedding(OpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
ai_model_id: str,
|
||||
api_key: Optional[str] = None,
|
||||
org_id: Optional[str] = None,
|
||||
service_id: Optional[str] = None,
|
||||
default_headers: Optional[Mapping[str, str]] = None,
|
||||
async_client: Optional[AsyncOpenAI] = None,
|
||||
log: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initializes a new instance of the OpenAITextCompletion class.
|
||||
@@ -66,11 +66,10 @@ class OpenAITextEmbedding(OpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
api_key=api_key,
|
||||
ai_model_type=OpenAIModelTypes.EMBEDDING,
|
||||
org_id=org_id,
|
||||
service_id=service_id,
|
||||
default_headers=default_headers,
|
||||
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 +84,6 @@ class OpenAITextEmbedding(OpenAIConfigBase, OpenAITextEmbeddingBase):
|
||||
ai_model_id=settings["ai_model_id"],
|
||||
api_key=settings["api_key"],
|
||||
org_id=settings.get("org_id"),
|
||||
service_id=settings.get("service_id"),
|
||||
default_headers=settings.get("default_headers"),
|
||||
)
|
||||
|
||||
@@ -2,28 +2,39 @@
|
||||
|
||||
import json
|
||||
import logging
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||
|
||||
from openai.types.chat import ChatCompletion
|
||||
|
||||
from semantic_kernel import Kernel, KernelContext
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat.function_call import FunctionCall
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat.tool_calls import ToolCall
|
||||
from semantic_kernel.connectors.ai.open_ai.semantic_functions.open_ai_chat_prompt_template import (
|
||||
OpenAIChatPromptTemplate,
|
||||
)
|
||||
from semantic_kernel.orchestration.context_variables import ContextVariables
|
||||
from semantic_kernel.orchestration.kernel_function import KernelFunction
|
||||
from semantic_kernel import Kernel
|
||||
from semantic_kernel.connectors.ai.chat_completion_client_base import ChatCompletionClientBase
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat_completion.function_call import FunctionCall
|
||||
from semantic_kernel.connectors.ai.open_ai.models.chat_completion.tool_calls import ToolCall
|
||||
from semantic_kernel.connectors.ai.text_completion_client_base import TextCompletionClientBase
|
||||
from semantic_kernel.contents.chat_history import ChatHistory
|
||||
from semantic_kernel.functions.function_result import FunctionResult
|
||||
from semantic_kernel.functions.kernel_arguments import KernelArguments
|
||||
from semantic_kernel.functions.kernel_function import KernelFunction
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
TYPE_MAPPER = {
|
||||
"str": "string",
|
||||
"int": "number",
|
||||
"float": "number",
|
||||
"bool": "boolean",
|
||||
"list": "array",
|
||||
"dict": "object",
|
||||
}
|
||||
|
||||
|
||||
def _describe_tool_call(function: KernelFunction) -> Dict[str, str]:
|
||||
"""Create the object used for the tool call.
|
||||
|
||||
Assumes that arguments for semantic functions are optional, for native functions required.
|
||||
"""
|
||||
func_view = function.describe()
|
||||
func_view = function.metadata
|
||||
return {
|
||||
"type": "function",
|
||||
"function": {
|
||||
@@ -34,29 +45,41 @@ def _describe_tool_call(function: KernelFunction) -> Dict[str, str]:
|
||||
"properties": {
|
||||
param.name: {
|
||||
"description": param.description,
|
||||
"type": param.type_ if param.type_ else "string",
|
||||
"type": parse_param(param.type_),
|
||||
**({"enum": param.enum} if hasattr(param, "enum") else {}), # Added support for enum
|
||||
}
|
||||
for param in func_view.parameters
|
||||
if param.expose
|
||||
},
|
||||
"required": [p.name for p in func_view.parameters if p.required],
|
||||
"required": [p.name for p in func_view.parameters if p.required and p.expose],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def parse_param(param_type: Optional[str]) -> str:
|
||||
"""Parse the parameter type."""
|
||||
if not param_type:
|
||||
return "string"
|
||||
if "," in param_type:
|
||||
param_type = param_type.split(",", maxsplit=1)[0]
|
||||
return TYPE_MAPPER.get(param_type, "string")
|
||||
|
||||
|
||||
def _describe_function(function: KernelFunction) -> Dict[str, str]:
|
||||
"""Create the object used for function_calling.
|
||||
Assumes that arguments for semantic functions are optional, for native functions required.
|
||||
"""
|
||||
func_view = function.describe()
|
||||
func_view = function.metadata
|
||||
return {
|
||||
"name": f"{func_view.plugin_name}-{func_view.name}",
|
||||
"description": func_view.description,
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
param.name: {"description": param.description, "type": param.type_} for param in func_view.parameters
|
||||
param.name: {"description": param.description, "type": param.type_}
|
||||
for param in func_view.parameters
|
||||
if param.expose
|
||||
},
|
||||
"required": [p.name for p in func_view.parameters if p.required],
|
||||
},
|
||||
@@ -132,13 +155,13 @@ def get_function_calling_object(
|
||||
if include_function and exclude_function:
|
||||
raise ValueError("Cannot use both include_function and exclude_function at the same time.")
|
||||
if include_plugin:
|
||||
include_plugin = [plugin.lower() for plugin in include_plugin]
|
||||
include_plugin = [plugin for plugin in include_plugin]
|
||||
if exclude_plugin:
|
||||
exclude_plugin = [plugin.lower() for plugin in exclude_plugin]
|
||||
exclude_plugin = [plugin for plugin in exclude_plugin]
|
||||
if include_function:
|
||||
include_function = [function.lower() for function in include_function]
|
||||
include_function = [function for function in include_function]
|
||||
if exclude_function:
|
||||
exclude_function = [function.lower() for function in exclude_function]
|
||||
exclude_function = [function for function in exclude_function]
|
||||
result = []
|
||||
for (
|
||||
plugin_name,
|
||||
@@ -154,44 +177,57 @@ def get_function_calling_object(
|
||||
return result
|
||||
|
||||
|
||||
async def execute(kernel: Kernel, func: KernelFunction, input_vars: ContextVariables) -> str:
|
||||
async def execute(kernel: Kernel, func: KernelFunction, arguments: KernelArguments) -> FunctionResult:
|
||||
"""Execute a function and return the result.
|
||||
|
||||
Args:
|
||||
kernel (Kernel): the kernel to use.
|
||||
func (KernelFunction): the function to execute.
|
||||
input_vars (ContextVariables): the input variables.
|
||||
kernel: the kernel to use.
|
||||
func: the function to execute.
|
||||
arguments: the arguments to pass to the function.
|
||||
|
||||
Returns:
|
||||
str: the result of the execution.
|
||||
"""
|
||||
result = await kernel.run(func, input_vars=input_vars)
|
||||
result = await kernel.invoke(functions=func, arguments=arguments)
|
||||
logger.info(f"Execution result: {result}")
|
||||
return str(result)
|
||||
return result
|
||||
|
||||
|
||||
async def execute_function_call(kernel: Kernel, function_call: FunctionCall) -> str:
|
||||
async def execute_function_call(kernel: Kernel, function_call: FunctionCall) -> FunctionResult:
|
||||
"""Execute a function call and return the result."""
|
||||
func = kernel.func(**function_call.split_name_dict())
|
||||
input_vars = function_call.to_context_variables()
|
||||
return await execute(kernel, func, input_vars)
|
||||
arguments = function_call.to_kernel_arguments()
|
||||
return await execute(kernel, func, arguments)
|
||||
|
||||
|
||||
async def execute_tool_call(kernel: Kernel, tool_call: ToolCall) -> str:
|
||||
async def execute_and_store_tool_call(
|
||||
kernel: Kernel,
|
||||
tool_call: ToolCall,
|
||||
chat_function: KernelFunction,
|
||||
):
|
||||
"""Execute a tool call and store the result in the chat prompt template."""
|
||||
tool_call_result = await execute_tool_call(kernel, tool_call)
|
||||
chat_function.chat_prompt_template.add_function_response_message(
|
||||
name=tool_call.function.name, content=str(tool_call_result), tool_call_id=tool_call.id
|
||||
)
|
||||
|
||||
|
||||
async def execute_tool_call(kernel: Kernel, tool_call: ToolCall) -> FunctionResult:
|
||||
"""Execute a tool call and return the result."""
|
||||
func = kernel.func(**tool_call.function.split_name_dict())
|
||||
input_vars = tool_call.function.to_context_variables()
|
||||
return await execute(kernel, func, input_vars)
|
||||
arguments = tool_call.function.to_kernel_arguments()
|
||||
return await execute(kernel, func, arguments)
|
||||
|
||||
|
||||
async def chat_completion_with_function_call(
|
||||
async def chat_completion_with_tool_call(
|
||||
kernel: Kernel,
|
||||
context: KernelContext,
|
||||
arguments: Optional[KernelArguments] = None,
|
||||
chat_plugin_name: Optional[str] = None,
|
||||
chat_function_name: Optional[str] = None,
|
||||
chat_function: Optional[KernelFunction] = None,
|
||||
chat_history: Optional[ChatHistory] = None,
|
||||
**kwargs: Dict[str, Any],
|
||||
) -> KernelContext:
|
||||
) -> FunctionResult:
|
||||
"""Perform a chat completion with auto-executing function calling.
|
||||
|
||||
This is a recursive function that will execute the chat function multiple times,
|
||||
@@ -204,44 +240,55 @@ async def chat_completion_with_function_call(
|
||||
|
||||
args:
|
||||
kernel: the kernel to use.
|
||||
context: the context to use.
|
||||
functions: the function calling object,
|
||||
make sure to use get_tool_call_object method to create it.
|
||||
Optional arguments:
|
||||
chat_plugin_name: the plugin name of the chat function.
|
||||
chat_function_name: the function name of the chat function.
|
||||
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_plugin_name and chat_function_name.
|
||||
arguments: the arguments to pass to the chat function.
|
||||
Optional arguments:
|
||||
chat_plugin_name: the plugin name of the chat function.
|
||||
chat_function_name: the function name of the chat function.
|
||||
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_plugin_name and chat_function_name.
|
||||
chat_history: the chat history to use, if not provided, will attempt to retrieve from arguments
|
||||
with key "chat_history".
|
||||
|
||||
max_function_calls: the maximum number of function calls to execute, defaults to 5.
|
||||
current_call_count: the current number of function calls executed.
|
||||
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/run_async.
|
||||
the FunctionResult with the result of the chat completion, just like a regular invoke/run_async.
|
||||
"""
|
||||
|
||||
chat_history or arguments["chat_history"]
|
||||
|
||||
# check the number of function calls
|
||||
max_function_calls = kwargs.get("max_function_calls", 5)
|
||||
current_call_count = kwargs.get("current_call_count", 0)
|
||||
# get the chat function
|
||||
if chat_function is None:
|
||||
if chat_plugin_name is None or chat_function_name is None:
|
||||
raise ValueError("Please provide either the chat_function or the chat_plugin_name and chat_function_name.")
|
||||
chat_function = kernel.func(plugin_name=chat_plugin_name, function_name=chat_function_name)
|
||||
assert isinstance(
|
||||
chat_function.chat_prompt_template, OpenAIChatPromptTemplate
|
||||
assert issubclass(
|
||||
type(chat_function.ai_service), Union[ChatCompletionClientBase, TextCompletionClientBase]
|
||||
), "Please make sure to initialize your chat function with the OpenAIChatPromptTemplate class."
|
||||
settings = chat_function.chat_prompt_template.prompt_config.execution_settings
|
||||
|
||||
settings = chat_function.prompt_execution_settings[chat_function.ai_service.service_id]
|
||||
|
||||
if not arguments:
|
||||
arguments = KernelArguments()
|
||||
arguments.execution_settings[settings.service_id] = settings
|
||||
arguments["user_input"] = ("\n").join([f"{msg.role}: {msg.content}" for msg in chat_history])
|
||||
if current_call_count >= max_function_calls:
|
||||
settings.functions = []
|
||||
context = await chat_function.invoke(
|
||||
context=context,
|
||||
result = await chat_function.invoke(
|
||||
kernel=kernel,
|
||||
arguments=arguments,
|
||||
# when the maximum number of function calls is reached, execute the chat function without Functions.
|
||||
settings=settings,
|
||||
)
|
||||
if not (results := context.objects.pop("results", None)):
|
||||
return context
|
||||
if not isinstance(result, FunctionResult) and result.value[0].tool_call is None:
|
||||
return result
|
||||
function_call = next(
|
||||
(
|
||||
fc
|
||||
for fc in (results[0].function_call or results[0].tool_calls or [None])
|
||||
for fc in (result.value[0].function_call or result.value[0].tool_calls or [None])
|
||||
if isinstance(fc, (FunctionCall, ToolCall))
|
||||
),
|
||||
None,
|
||||
@@ -251,16 +298,17 @@ async def chat_completion_with_function_call(
|
||||
result = await execute_call(kernel, function_call)
|
||||
tool_call_id = function_call.id
|
||||
else:
|
||||
return context
|
||||
return result
|
||||
# add the result to the chat prompt template
|
||||
chat_history.add_tool_message()
|
||||
chat_function.chat_prompt_template.add_function_response_message(
|
||||
name=function_call.function.name, content=str(result), tool_call_id=tool_call_id
|
||||
)
|
||||
# request another completion
|
||||
return await chat_completion_with_function_call(
|
||||
return await chat_completion_with_tool_call(
|
||||
kernel,
|
||||
arguments=arguments,
|
||||
chat_function=chat_function,
|
||||
context=context,
|
||||
max_function_calls=max_function_calls,
|
||||
current_call_count=current_call_count + 1,
|
||||
)
|
||||
|
||||
@@ -14,7 +14,7 @@ class PromptExecutionSettings(KernelBaseModel):
|
||||
prompt execution settings that each services returns by using the service.get_prompt_execution_settings() method.
|
||||
|
||||
Parameters:
|
||||
service_id (str, optional): The service ID to use for the request. Defaults to None.
|
||||
service_id (str): The service ID to use for the request.
|
||||
extension_data (Dict[str, Any], optional): Any additional data to send with the request. Defaults to None.
|
||||
kwargs (Any): Additional keyword arguments,
|
||||
these are attempted to parse into the keys of the specific prompt execution settings.
|
||||
|
||||
@@ -2,14 +2,16 @@
|
||||
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import TYPE_CHECKING, Any, AsyncIterable, List, Optional
|
||||
from typing import TYPE_CHECKING, AsyncIterable, List
|
||||
|
||||
from semantic_kernel.services.ai_service_client_base import AIServiceClientBase
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from semantic_kernel.connectors.ai.prompt_execution_settings import PromptExecutionSettings
|
||||
from semantic_kernel.models.contents import StreamingTextContent, TextContent
|
||||
from semantic_kernel.contents import StreamingTextContent, TextContent
|
||||
|
||||
|
||||
class TextCompletionClientBase(ABC):
|
||||
class TextCompletionClientBase(AIServiceClientBase, ABC):
|
||||
"""Base class for text completion AI services."""
|
||||
|
||||
@abstractmethod
|
||||
@@ -17,7 +19,6 @@ class TextCompletionClientBase(ABC):
|
||||
self,
|
||||
prompt: str,
|
||||
settings: "PromptExecutionSettings",
|
||||
logger: Optional[Any] = None,
|
||||
) -> List["TextContent"]:
|
||||
"""
|
||||
This is the method that is called from the kernel to get a response from a text-optimized LLM.
|
||||
@@ -25,7 +26,6 @@ class TextCompletionClientBase(ABC):
|
||||
Arguments:
|
||||
prompt {str} -- The prompt to send to the LLM.
|
||||
settings {PromptExecutionSettings} -- Settings for the request.
|
||||
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 +36,6 @@ class TextCompletionClientBase(ABC):
|
||||
self,
|
||||
prompt: str,
|
||||
settings: "PromptExecutionSettings",
|
||||
logger: Optional[Any] = None,
|
||||
) -> AsyncIterable[List["StreamingTextContent"]]:
|
||||
"""
|
||||
This is the method that is called from the kernel to get a stream response from a text-optimized LLM.
|
||||
@@ -44,7 +43,6 @@ class TextCompletionClientBase(ABC):
|
||||
Arguments:
|
||||
prompt {str} -- The prompt to send to the LLM.
|
||||
settings {PromptExecutionSettings} -- Settings for the request.
|
||||
logger {Logger} -- A logger to use for logging (deprecated).
|
||||
|
||||
Yields:
|
||||
A stream representing the response(s) from the LLM.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# semantic_kernel.connectors.memory.redis
|
||||
|
||||
This connector uses Redis to implement Semantic Memory. It requires the [RediSearch](https://redis.io/docs/interact/search-and-query/) module to be enabled on Redis to implement vector similarity search.
|
||||
This connector uses Redis to implement Semantic Memory. It requires the [RediSearch](https://redis.io/docs/interact/search-and-query/) module to be enabled on Redis to implement vector similarity search.
|
||||
|
||||
See the [.net README](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/src/Connectors/Connectors.Memory.Redis/README.md) for more information.
|
||||
|
||||
@@ -22,10 +22,10 @@ docker run -d --name redis-stack-server -p 6379:6379 redis/redis-stack-server:la
|
||||
kernel = sk.Kernel()
|
||||
|
||||
api_key, org_id = sk.openai_settings_from_dot_env()
|
||||
kernel.add_text_completion_service("dv", sk_oai.OpenAITextCompletion("text-davinci-003", api_key, org_id))
|
||||
kernel.add_text_embedding_generation_service("ada", sk_oai.OpenAITextEmbedding("text-embedding-ada-002", api_key, org_id))
|
||||
kernel.add_service(sk_oai.OpenAITextCompletion(service_id="dv", ai_model_id="text-davinci-003", api_key=api_key, org_id=org_id))
|
||||
embedding_generator = sk_oai.OpenAITextEmbedding(service_id="ada", ai_model_id="text-embedding-ada-002", api_key=api_key, org_id=org_id)
|
||||
kernel.add_service(embedding_generator)
|
||||
|
||||
redis_connection_string = sk.redis_settings_from_dot_env()
|
||||
kernel.register_memory_store(memory_store=RedisMemoryStore(connection_string=redis_connection_string))
|
||||
kernel.use_memory(storage=RedisMemoryStore(connection_string=redis_connection_string), embeddings_generator=embedding_generator)
|
||||
```
|
||||
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
from typing import Dict, Mapping, Optional, Union
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
from typing import Annotated
|
||||
else:
|
||||
from typing_extensions import Annotated
|
||||
from urllib.parse import urljoin
|
||||
|
||||
import aiohttp
|
||||
@@ -10,13 +16,13 @@ from openapi_core.contrib.requests import RequestsOpenAPIRequest
|
||||
from openapi_core.exceptions import OpenAPIError
|
||||
from prance import ResolvingParser
|
||||
|
||||
from semantic_kernel import Kernel, KernelContext
|
||||
from semantic_kernel.connectors.ai.open_ai.const import (
|
||||
USER_AGENT,
|
||||
)
|
||||
from semantic_kernel.connectors.telemetry import HTTP_USER_AGENT
|
||||
from semantic_kernel.orchestration.kernel_function import KernelFunction
|
||||
from semantic_kernel.plugin_definition import kernel_function, kernel_function_context_parameter
|
||||
from semantic_kernel.functions.kernel_function import KernelFunction
|
||||
from semantic_kernel.functions.kernel_function_decorator import kernel_function
|
||||
from semantic_kernel.kernel import Kernel
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -216,7 +222,7 @@ class OpenApiRunner:
|
||||
query_params: Optional[Dict[str, str]] = None,
|
||||
headers: Optional[Dict[str, str]] = None,
|
||||
request_body: Optional[Union[str, Dict[str, str]]] = None,
|
||||
) -> aiohttp.ClientResponse:
|
||||
) -> str:
|
||||
prepared_request = operation.prepare_request(
|
||||
path_params=path_params,
|
||||
query_params=query_params,
|
||||
@@ -264,22 +270,30 @@ def register_openapi_plugin(
|
||||
description=operation.summary if operation.summary else operation.description,
|
||||
name=operation_id,
|
||||
)
|
||||
@kernel_function_context_parameter(name="path_params", description="A dictionary of path parameters")
|
||||
@kernel_function_context_parameter(name="query_params", description="A dictionary of query parameters")
|
||||
@kernel_function_context_parameter(name="headers", description="A dictionary of headers")
|
||||
@kernel_function_context_parameter(name="request_body", description="A dictionary of the request body")
|
||||
async def run_openapi_operation(kernel_context: KernelContext) -> str:
|
||||
path_params = kernel_context.variables.get("path_params")
|
||||
query_params = kernel_context.variables.get("query_params")
|
||||
headers = kernel_context.variables.get("headers")
|
||||
request_body = kernel_context.variables.get("request_body")
|
||||
|
||||
async def run_openapi_operation(
|
||||
path_params: Annotated[Optional[Union[Dict, str]], "A dictionary of path parameters"] = None,
|
||||
query_params: Annotated[Optional[Union[Dict, str]], "A dictionary of query parameters"] = None,
|
||||
headers: Annotated[Optional[Union[Dict, str]], "A dictionary of headers"] = None,
|
||||
request_body: Annotated[Optional[Union[Dict, str]], "A dictionary of the request body"] = None,
|
||||
) -> str:
|
||||
response = await runner.run_operation(
|
||||
operation,
|
||||
path_params=json.loads(path_params) if path_params else None,
|
||||
query_params=json.loads(query_params) if query_params else None,
|
||||
headers=json.loads(headers) if headers else None,
|
||||
request_body=json.loads(request_body) if request_body else None,
|
||||
path_params=json.loads(path_params)
|
||||
if isinstance(path_params, str)
|
||||
else path_params
|
||||
if path_params
|
||||
else None,
|
||||
query_params=json.loads(query_params)
|
||||
if isinstance(query_params, str)
|
||||
else query_params
|
||||
if query_params
|
||||
else None,
|
||||
headers=json.loads(headers) if isinstance(headers, str) else headers if headers else None,
|
||||
request_body=json.loads(request_body)
|
||||
if isinstance(request_body, str)
|
||||
else request_body
|
||||
if request_body
|
||||
else None,
|
||||
)
|
||||
return response
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from semantic_kernel.contents.chat_message_content import ChatMessageContent
|
||||
from semantic_kernel.contents.kernel_content import KernelContent
|
||||
from semantic_kernel.contents.streaming_chat_message_content import StreamingChatMessageContent
|
||||
from semantic_kernel.contents.streaming_kernel_content import StreamingKernelContent
|
||||
from semantic_kernel.contents.streaming_text_content import StreamingTextContent
|
||||
from semantic_kernel.contents.text_content import TextContent
|
||||
|
||||
__all__ = [
|
||||
"ChatMessageContent",
|
||||
"KernelContent",
|
||||
"TextContent",
|
||||
"StreamingKernelContent",
|
||||
"StreamingChatMessageContent",
|
||||
"StreamingTextContent",
|
||||
]
|
||||
@@ -0,0 +1,291 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import json
|
||||
import logging
|
||||
import xml.etree.ElementTree as ET
|
||||
from typing import Any, Dict, Final, Iterator, List, Optional, Tuple, Type, Union
|
||||
|
||||
from semantic_kernel.contents.chat_message_content import ChatMessageContent
|
||||
from semantic_kernel.contents.chat_role import ChatRole
|
||||
from semantic_kernel.kernel_pydantic import KernelBaseModel
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
ROOT_KEY_MESSAGE: Final[str] = "message"
|
||||
|
||||
|
||||
class ChatHistory(KernelBaseModel):
|
||||
"""
|
||||
This class holds the history of chat messages from a chat conversation.
|
||||
|
||||
Note: the constructor takes a system_message parameter, which is not part
|
||||
of the class definition. This is to allow the system_message to be passed in
|
||||
as a keyword argument, but not be part of the class definition.
|
||||
|
||||
Attributes:
|
||||
messages (List[ChatMessageContent]): The list of chat messages in the history.
|
||||
"""
|
||||
|
||||
messages: List[ChatMessageContent]
|
||||
|
||||
def __init__(self, **data: Any):
|
||||
"""
|
||||
Initializes a new instance of the ChatHistory class, optionally incorporating a message and/or
|
||||
a system message at the beginning of the chat history.
|
||||
|
||||
This constructor allows for flexible initialization with chat messages and an optional messages or a
|
||||
system message. If both 'messages' (a list of ChatMessageContent instances) and 'system_message' are
|
||||
provided, the 'system_message' is prepended to the list of messages, ensuring it appears as the first
|
||||
message in the history. If only 'system_message' is provided without any 'messages', the chat history is
|
||||
initialized with the 'system_message' as its first item. If 'messages' are provided without a
|
||||
'system_message', the chat history is initialized with the provided messages as is.
|
||||
|
||||
Parameters:
|
||||
- **data: Arbitrary keyword arguments. The constructor looks for two optional keys:
|
||||
- 'messages': Optional[List[ChatMessageContent]], a list of chat messages to include in the history.
|
||||
- 'system_message' Optional[str]: An optional string representing a system-generated message to be
|
||||
included at the start of the chat history.
|
||||
|
||||
Note: The 'system_message' is not retained as part of the class's attributes; it's used during
|
||||
initialization and then discarded. The rest of the keyword arguments are passed to the superclass
|
||||
constructor and handled according to the Pydantic model's behavior.
|
||||
"""
|
||||
system_message_content = data.pop("system_message", None)
|
||||
|
||||
if system_message_content:
|
||||
system_message = ChatMessageContent(role=ChatRole.SYSTEM, content=system_message_content)
|
||||
|
||||
if "messages" in data:
|
||||
data["messages"] = [system_message] + data["messages"]
|
||||
else:
|
||||
data["messages"] = [system_message]
|
||||
if "messages" not in data:
|
||||
data["messages"] = []
|
||||
super().__init__(**data)
|
||||
|
||||
def add_system_message(self, content: str) -> None:
|
||||
"""Add a system message to the chat history."""
|
||||
self.add_message(message=self._prepare_for_add(ChatRole.SYSTEM, content))
|
||||
|
||||
def add_user_message(self, content: str) -> None:
|
||||
"""Add a user message to the chat history."""
|
||||
self.add_message(message=self._prepare_for_add(ChatRole.USER, content))
|
||||
|
||||
def add_assistant_message(self, content: str) -> None:
|
||||
"""Add an assistant message to the chat history."""
|
||||
self.add_message(message=self._prepare_for_add(ChatRole.ASSISTANT, content))
|
||||
|
||||
def add_tool_message(self, content: str, metadata: Optional[Dict[str, Any]] = None) -> None:
|
||||
"""Add a tool message to the chat history."""
|
||||
self.add_message(message=self._prepare_for_add(ChatRole.TOOL, content), metadata=metadata)
|
||||
|
||||
def add_message(
|
||||
self,
|
||||
message: Union[ChatMessageContent, Dict[str, Any]],
|
||||
encoding: Optional[str] = None,
|
||||
metadata: Optional[Dict[str, Any]] = None,
|
||||
) -> None:
|
||||
"""Add a message to the history.
|
||||
|
||||
This method accepts either a ChatMessageContent instance or a
|
||||
dictionary with the necessary information to construct a ChatMessageContent instance.
|
||||
|
||||
Args:
|
||||
message (Union[ChatMessageContent, dict]): The message to add, either as
|
||||
a pre-constructed ChatMessageContent instance or a dictionary specifying 'role' and 'content'.
|
||||
encoding (Optional[str]): The encoding of the message. Required if 'message' is a dict.
|
||||
metadata (Optional[dict[str, Any]]): Any metadata to attach to the message. Required if 'message' is a dict.
|
||||
"""
|
||||
if isinstance(message, ChatMessageContent):
|
||||
self.messages.append(message)
|
||||
return
|
||||
if "role" not in message:
|
||||
raise ValueError(f"Dictionary must contain at least the role. Got: {message}")
|
||||
if encoding:
|
||||
message["encoding"] = encoding
|
||||
if metadata:
|
||||
message["metadata"] = metadata
|
||||
self.messages.append(ChatMessageContent(**message))
|
||||
|
||||
def _prepare_for_add(self, role: ChatRole, content: str) -> Dict[str, str]:
|
||||
"""Prepare a message to be added to the history."""
|
||||
return {"role": role, "content": content}
|
||||
|
||||
def remove_message(self, message: ChatMessageContent) -> bool:
|
||||
"""Remove a message from the history.
|
||||
|
||||
Args:
|
||||
message (ChatMessageContent): The message to remove.
|
||||
|
||||
Returns:
|
||||
bool: True if the message was removed, False if the message was not found.
|
||||
"""
|
||||
try:
|
||||
self.messages.remove(message)
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
def __len__(self) -> int:
|
||||
"""Return the number of messages in the history."""
|
||||
return len(self.messages)
|
||||
|
||||
def __getitem__(self, index: int) -> ChatMessageContent:
|
||||
"""Get a message from the history using the [] operator.
|
||||
|
||||
Args:
|
||||
index (int): The index of the message to get.
|
||||
|
||||
Returns:
|
||||
ChatMessageContent: The message at the specified index.
|
||||
"""
|
||||
return self.messages[index]
|
||||
|
||||
def __contains__(self, item: ChatMessageContent) -> bool:
|
||||
"""Check if a message is in the history.
|
||||
|
||||
Args:
|
||||
item (ChatMessageContent): The message to check for.
|
||||
|
||||
Returns:
|
||||
bool: True if the message is in the history, False otherwise.
|
||||
"""
|
||||
return item in self.messages
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""Return a string representation of the history."""
|
||||
if not self.messages:
|
||||
return ""
|
||||
return "\n".join([msg.to_prompt(root_key=ROOT_KEY_MESSAGE) for msg in self.messages])
|
||||
|
||||
def __iter__(self) -> Iterator[ChatMessageContent]:
|
||||
"""Return an iterator over the messages in the history."""
|
||||
return iter(self.messages)
|
||||
|
||||
def __eq__(self, other: "ChatHistory") -> bool:
|
||||
"""Check if two ChatHistory instances are equal."""
|
||||
if not isinstance(other, ChatHistory):
|
||||
return False
|
||||
|
||||
return self.messages == other.messages
|
||||
|
||||
@classmethod
|
||||
def from_rendered_prompt(
|
||||
cls, rendered_prompt: str, chat_message_content_type: Type[ChatMessageContent] = ChatMessageContent
|
||||
) -> "ChatHistory":
|
||||
"""
|
||||
Create a ChatHistory instance from a rendered prompt.
|
||||
|
||||
Args:
|
||||
rendered_prompt (str): The rendered prompt to convert to a ChatHistory instance.
|
||||
|
||||
Returns:
|
||||
ChatHistory: The ChatHistory instance created from the rendered prompt.
|
||||
"""
|
||||
messages: List[chat_message_content_type] = []
|
||||
result, remainder = cls._render_remaining(rendered_prompt, chat_message_content_type, True)
|
||||
if result:
|
||||
messages.append(result)
|
||||
while remainder:
|
||||
result, remainder = cls._render_remaining(remainder, chat_message_content_type)
|
||||
if result:
|
||||
messages.append(result)
|
||||
return cls(messages=messages)
|
||||
|
||||
@staticmethod
|
||||
def _render_remaining(
|
||||
prompt: Optional[str],
|
||||
chat_message_content_type: Type[ChatMessageContent] = ChatMessageContent,
|
||||
first: bool = False,
|
||||
) -> Tuple[Optional[ChatMessageContent], Optional[str]]:
|
||||
"""Render the remaining messages in the history."""
|
||||
if not prompt:
|
||||
return None, None
|
||||
prompt = prompt.strip()
|
||||
start = prompt.find(f"<{ROOT_KEY_MESSAGE}")
|
||||
end_tag = f"</{ROOT_KEY_MESSAGE}>"
|
||||
single_item_end_tag = "/>"
|
||||
end = prompt.find(end_tag)
|
||||
end_of_tag = end + len(end_tag)
|
||||
if end == -1:
|
||||
end = prompt.find(single_item_end_tag)
|
||||
end_of_tag = end + len(single_item_end_tag)
|
||||
if start == -1 or end == -1:
|
||||
return chat_message_content_type(role=ChatRole.SYSTEM if first else ChatRole.USER, content=prompt), None
|
||||
if start > 0 and end > 0:
|
||||
return (
|
||||
chat_message_content_type(role=ChatRole.SYSTEM if first else ChatRole.USER, content=prompt[:start]),
|
||||
prompt[start:],
|
||||
)
|
||||
try:
|
||||
return chat_message_content_type.from_element(ET.fromstring(prompt[start:end_of_tag])), prompt[end_of_tag:]
|
||||
except ET.ParseError:
|
||||
logger.warning(f"Unable to parse prompt: {prompt[start:end_of_tag]}, returning as content")
|
||||
return (
|
||||
chat_message_content_type(
|
||||
role=ChatRole.SYSTEM if first else ChatRole.USER, content=prompt[start:end_of_tag]
|
||||
),
|
||||
prompt[end_of_tag:],
|
||||
)
|
||||
|
||||
def serialize(self) -> str:
|
||||
"""
|
||||
Serializes the ChatHistory instance to a JSON string.
|
||||
|
||||
Returns:
|
||||
str: A JSON string representation of the ChatHistory instance.
|
||||
|
||||
Raises:
|
||||
ValueError: If the ChatHistory instance cannot be serialized to JSON.
|
||||
"""
|
||||
try:
|
||||
return self.model_dump_json(indent=4)
|
||||
except TypeError as e:
|
||||
raise ValueError(f"Unable to serialize ChatHistory to JSON: {e}")
|
||||
|
||||
@classmethod
|
||||
def restore_chat_history(cls, chat_history_json: str) -> "ChatHistory":
|
||||
"""
|
||||
Restores a ChatHistory instance from a JSON string.
|
||||
|
||||
Args:
|
||||
chat_history_json (str): The JSON string to deserialize
|
||||
into a ChatHistory instance.
|
||||
|
||||
Returns:
|
||||
ChatHistory: The deserialized ChatHistory instance.
|
||||
|
||||
Raises:
|
||||
ValueError: If the JSON string is invalid or the deserialized data
|
||||
fails validation.
|
||||
"""
|
||||
try:
|
||||
return ChatHistory.model_validate_json(chat_history_json)
|
||||
except json.JSONDecodeError as e:
|
||||
raise ValueError(f"Invalid JSON format: {e}")
|
||||
|
||||
def store_chat_history_to_file(chat_history: "ChatHistory", file_path: str) -> None:
|
||||
"""
|
||||
Stores the serialized ChatHistory to a file.
|
||||
|
||||
Args:
|
||||
chat_history (ChatHistory): The ChatHistory instance to serialize and store.
|
||||
file_path (str): The path to the file where the serialized data will be stored.
|
||||
"""
|
||||
json_str = chat_history.serialize()
|
||||
with open(file_path, "w") as file:
|
||||
file.write(json_str)
|
||||
|
||||
def load_chat_history_from_file(file_path: str) -> "ChatHistory":
|
||||
"""
|
||||
Loads the ChatHistory from a file.
|
||||
|
||||
Args:
|
||||
file_path (str): The path to the file from which to load the ChatHistory.
|
||||
|
||||
Returns:
|
||||
ChatHistory: The deserialized ChatHistory instance.
|
||||
"""
|
||||
with open(file_path, "r") as file:
|
||||
json_str = file.read()
|
||||
return ChatHistory.restore_chat_history(json_str)
|
||||
+30
-3
@@ -1,8 +1,10 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from typing import Optional
|
||||
from xml.etree import ElementTree
|
||||
from xml.etree.ElementTree import Element
|
||||
|
||||
from semantic_kernel.models.chat.chat_role import ChatRole
|
||||
from semantic_kernel.models.contents.kernel_content import KernelContent
|
||||
from semantic_kernel.contents.chat_role import ChatRole
|
||||
from semantic_kernel.contents.kernel_content import KernelContent
|
||||
|
||||
|
||||
class ChatMessageContent(KernelContent):
|
||||
@@ -30,4 +32,29 @@ class ChatMessageContent(KernelContent):
|
||||
encoding: Optional[str] = None
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.content
|
||||
return self.content or ""
|
||||
|
||||
def to_prompt(self, root_key: str) -> str:
|
||||
"""Convert the ChatMessageContent to a prompt.
|
||||
|
||||
Returns:
|
||||
str - The prompt from the ChatMessageContent.
|
||||
"""
|
||||
|
||||
root = Element(root_key)
|
||||
root.set("role", self.role.value)
|
||||
root.text = self.content or ""
|
||||
return ElementTree.tostring(root, encoding=self.encoding or "unicode")
|
||||
|
||||
@classmethod
|
||||
def from_element(cls, element: Element) -> "ChatMessageContent":
|
||||
"""Create a new instance of ChatMessageContent from a prompt.
|
||||
|
||||
Args:
|
||||
prompt: str - The prompt to create the ChatMessageContent from.
|
||||
|
||||
Returns:
|
||||
ChatMessageContent - The new instance of ChatMessageContent.
|
||||
"""
|
||||
args = {"role": element.get("role", ChatRole.USER.value), "content": element.text}
|
||||
return cls(**args)
|
||||
+1
-1
@@ -12,7 +12,7 @@ class KernelContent(KernelBaseModel, ABC):
|
||||
|
||||
inner_content: Optional[Any] = None
|
||||
ai_model_id: Optional[str] = None
|
||||
metadata: Dict[str, Any] = Field(default_factory=dict)
|
||||
metadata: Optional[Dict[str, Any]] = Field(default_factory=dict)
|
||||
|
||||
@abstractmethod
|
||||
def __str__(self) -> str:
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from typing import Optional
|
||||
|
||||
from semantic_kernel.models.chat.chat_role import ChatRole
|
||||
from semantic_kernel.models.chat.finish_reason import FinishReason
|
||||
from semantic_kernel.models.contents.streaming_kernel_content import StreamingKernelContent
|
||||
from semantic_kernel.contents.chat_role import ChatRole
|
||||
from semantic_kernel.contents.finish_reason import FinishReason
|
||||
from semantic_kernel.contents.streaming_kernel_content import StreamingKernelContent
|
||||
|
||||
|
||||
class StreamingChatMessageContent(StreamingKernelContent):
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from typing import Optional
|
||||
|
||||
from semantic_kernel.models.contents.streaming_kernel_content import StreamingKernelContent
|
||||
from semantic_kernel.contents.streaming_kernel_content import StreamingKernelContent
|
||||
|
||||
|
||||
class StreamingTextContent(StreamingKernelContent):
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from typing import Optional
|
||||
|
||||
from semantic_kernel.models.contents.kernel_content import KernelContent
|
||||
from semantic_kernel.contents.kernel_content import KernelContent
|
||||
|
||||
|
||||
class TextContent(KernelContent):
|
||||
@@ -3,7 +3,6 @@
|
||||
from semantic_kernel.core_plugins.conversation_summary_plugin import (
|
||||
ConversationSummaryPlugin,
|
||||
)
|
||||
from semantic_kernel.core_plugins.file_io_plugin import FileIOPlugin
|
||||
from semantic_kernel.core_plugins.http_plugin import HttpPlugin
|
||||
from semantic_kernel.core_plugins.math_plugin import MathPlugin
|
||||
from semantic_kernel.core_plugins.text_memory_plugin import TextMemoryPlugin
|
||||
@@ -14,7 +13,6 @@ from semantic_kernel.core_plugins.web_search_engine_plugin import WebSearchEngin
|
||||
__all__ = [
|
||||
"TextMemoryPlugin",
|
||||
"TextPlugin",
|
||||
"FileIOPlugin",
|
||||
"TimePlugin",
|
||||
"HttpPlugin",
|
||||
"ConversationSummaryPlugin",
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import sys
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
from typing import Annotated
|
||||
else:
|
||||
from typing_extensions import Annotated
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from semantic_kernel.functions.kernel_arguments import KernelArguments
|
||||
from semantic_kernel.kernel import Kernel
|
||||
from semantic_kernel.orchestration.kernel_context import KernelContext
|
||||
from semantic_kernel.prompt_template.prompt_template_config import PromptTemplateConfig
|
||||
|
||||
|
||||
class ConversationSummaryPlugin:
|
||||
@@ -11,14 +19,14 @@ class ConversationSummaryPlugin:
|
||||
Semantic plugin that enables conversations summarization.
|
||||
"""
|
||||
|
||||
from semantic_kernel.plugin_definition import kernel_function
|
||||
from semantic_kernel.functions.kernel_function_decorator import kernel_function
|
||||
|
||||
# The max tokens to process in a single semantic function call.
|
||||
_max_tokens = 1024
|
||||
|
||||
_summarize_conversation_prompt_template = (
|
||||
"BEGIN CONTENT TO SUMMARIZE:\n{{"
|
||||
+ "$INPUT"
|
||||
+ "$input"
|
||||
+ "}}\nEND CONTENT TO SUMMARIZE.\nSummarize the conversation in 'CONTENT TO"
|
||||
" SUMMARIZE', identifying main points of discussion and any"
|
||||
" conclusions that were reached.\nDo not incorporate other general"
|
||||
@@ -26,28 +34,43 @@ class ConversationSummaryPlugin:
|
||||
" or tags.\n\nBEGIN SUMMARY:\n"
|
||||
)
|
||||
|
||||
def __init__(self, kernel: "Kernel"):
|
||||
self._summarizeConversationFunction = kernel.create_semantic_function(
|
||||
def __init__(
|
||||
self, kernel: "Kernel", prompt_template_config: "PromptTemplateConfig", return_key: str = "summary"
|
||||
) -> None:
|
||||
"""
|
||||
Initializes a new instance of the ConversationSummaryPlugin class.
|
||||
|
||||
:param kernel: The kernel instance.
|
||||
:param prompt_template_config: The prompt template configuration.
|
||||
:param return_key: The key to use for the return value.
|
||||
"""
|
||||
self.return_key = return_key
|
||||
self._summarizeConversationFunction = kernel.create_function_from_prompt(
|
||||
ConversationSummaryPlugin._summarize_conversation_prompt_template,
|
||||
plugin_name=ConversationSummaryPlugin.__name__,
|
||||
description=("Given a section of a conversation transcript, summarize the part of" " the conversation."),
|
||||
max_tokens=ConversationSummaryPlugin._max_tokens,
|
||||
temperature=0.1,
|
||||
top_p=0.5,
|
||||
function_name="SummarizeConversation",
|
||||
prompt_template_config=prompt_template_config,
|
||||
)
|
||||
|
||||
@kernel_function(
|
||||
description="Given a long conversation transcript, summarize the conversation.",
|
||||
name="SummarizeConversation",
|
||||
input_description="A long conversation transcript.",
|
||||
)
|
||||
async def summarize_conversation(self, input: str, context: "KernelContext") -> "KernelContext":
|
||||
async def summarize_conversation(
|
||||
self,
|
||||
input: Annotated[str, "A long conversation transcript."],
|
||||
kernel: Annotated["Kernel", "The kernel instance."],
|
||||
arguments: Annotated["KernelArguments", "Arguments used by the kernel."],
|
||||
) -> Annotated[
|
||||
"KernelArguments", "KernelArguments with the summarized conversation result in key self.return_key."
|
||||
]:
|
||||
"""
|
||||
Given a long conversation transcript, summarize the conversation.
|
||||
|
||||
:param input: A long conversation transcript.
|
||||
:param context: The KernelContext for function execution.
|
||||
:return: KernelContext with the summarized conversation result.
|
||||
:param kernel: The kernel for function execution.
|
||||
:param arguments: Arguments used by the kernel.
|
||||
:return: KernelArguments with the summarized conversation result in key self.return_key.
|
||||
"""
|
||||
from semantic_kernel.text import text_chunker
|
||||
from semantic_kernel.text.function_extension import (
|
||||
@@ -57,4 +80,7 @@ class ConversationSummaryPlugin:
|
||||
lines = text_chunker._split_text_lines(input, ConversationSummaryPlugin._max_tokens, True)
|
||||
paragraphs = text_chunker._split_text_paragraph(lines, ConversationSummaryPlugin._max_tokens)
|
||||
|
||||
return await aggregate_chunked_results(self._summarizeConversationFunction, paragraphs, context)
|
||||
arguments[self.return_key] = await aggregate_chunked_results(
|
||||
self._summarizeConversationFunction, paragraphs, kernel, arguments
|
||||
)
|
||||
return arguments
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import os
|
||||
import typing as t
|
||||
|
||||
import aiofiles
|
||||
|
||||
from semantic_kernel.kernel_pydantic import KernelBaseModel
|
||||
from semantic_kernel.plugin_definition import kernel_function, kernel_function_context_parameter
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
from semantic_kernel.orchestration.kernel_context import KernelContext
|
||||
|
||||
|
||||
class FileIOPlugin(KernelBaseModel):
|
||||
"""
|
||||
Description: Read and write from a file.
|
||||
|
||||
Usage:
|
||||
kernel.import_plugin(FileIOPlugin(), plugin_name="file")
|
||||
|
||||
Examples:
|
||||
|
||||
{{file.readAsync $path }} => "hello world"
|
||||
{{file.writeAsync}}
|
||||
"""
|
||||
|
||||
@kernel_function(
|
||||
description="Read a file",
|
||||
name="readAsync",
|
||||
input_description="Path of the source file",
|
||||
)
|
||||
async def read(self, path: str) -> str:
|
||||
"""
|
||||
Read a file
|
||||
|
||||
Example:
|
||||
{{file.readAsync $path }} => "hello world"
|
||||
Args:
|
||||
path -- The path to the file to read
|
||||
|
||||
Returns:
|
||||
The contents of the file
|
||||
"""
|
||||
|
||||
assert os.path.exists(path), f"File {path} does not exist"
|
||||
|
||||
async with aiofiles.open(path, "r", encoding="UTF-8") as fp:
|
||||
content = await fp.read()
|
||||
return content
|
||||
|
||||
@kernel_function(
|
||||
description="Write a file",
|
||||
name="writeAsync",
|
||||
)
|
||||
@kernel_function_context_parameter(name="path", description="Destination path")
|
||||
@kernel_function_context_parameter(name="content", description="File content")
|
||||
async def write(self, context: "KernelContext") -> None:
|
||||
"""
|
||||
Write a file
|
||||
|
||||
Example:
|
||||
{{file.writeAsync}}
|
||||
Args:
|
||||
Contains the 'path' for the Destination file and
|
||||
the 'content' of the file to write.
|
||||
"""
|
||||
path = context.variables.get("path")
|
||||
content = context.variables.get("content")
|
||||
|
||||
assert path, "Path is required"
|
||||
assert content, "Content is required"
|
||||
|
||||
async with aiofiles.open(path, "w") as fp:
|
||||
await fp.write(content)
|
||||
@@ -1,15 +1,18 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import json
|
||||
import typing as t
|
||||
import sys
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
import aiohttp
|
||||
|
||||
from semantic_kernel.kernel_pydantic import KernelBaseModel
|
||||
from semantic_kernel.plugin_definition import kernel_function, kernel_function_context_parameter
|
||||
if sys.version_info >= (3, 9):
|
||||
from typing import Annotated
|
||||
else:
|
||||
from typing_extensions import Annotated
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
from semantic_kernel.orchestration.kernel_context import KernelContext
|
||||
from semantic_kernel.functions.kernel_function_decorator import kernel_function
|
||||
from semantic_kernel.kernel_pydantic import KernelBaseModel
|
||||
|
||||
|
||||
class HttpPlugin(KernelBaseModel):
|
||||
@@ -28,7 +31,7 @@ class HttpPlugin(KernelBaseModel):
|
||||
"""
|
||||
|
||||
@kernel_function(description="Makes a GET request to a uri", name="getAsync")
|
||||
async def get(self, url: str) -> str:
|
||||
async def get(self, url: Annotated[str, "The URI to send the request to."]) -> str:
|
||||
"""
|
||||
Sends an HTTP GET request to the specified URI and returns
|
||||
the response body as a string.
|
||||
@@ -45,22 +48,23 @@ class HttpPlugin(KernelBaseModel):
|
||||
return await response.text()
|
||||
|
||||
@kernel_function(description="Makes a POST request to a uri", name="postAsync")
|
||||
@kernel_function_context_parameter(name="body", description="The body of the request")
|
||||
async def post(self, url: str, context: "KernelContext") -> str:
|
||||
async def post(
|
||||
self,
|
||||
url: Annotated[str, "The URI to send the request to."],
|
||||
body: Annotated[Optional[Dict[str, Any]], "The body of the request"] = {},
|
||||
) -> str:
|
||||
"""
|
||||
Sends an HTTP POST request to the specified URI and returns
|
||||
the response body as a string.
|
||||
params:
|
||||
url: The URI to send the request to.
|
||||
context: Contains the body of the request
|
||||
body: Contains the body of the request
|
||||
returns:
|
||||
The response body as a string.
|
||||
"""
|
||||
if not url:
|
||||
raise ValueError("url cannot be `None` or empty")
|
||||
|
||||
body = context.variables.get("body")
|
||||
|
||||
headers = {"Content-Type": "application/json"}
|
||||
data = json.dumps(body)
|
||||
async with aiohttp.ClientSession() as session:
|
||||
@@ -68,8 +72,11 @@ class HttpPlugin(KernelBaseModel):
|
||||
return await response.text()
|
||||
|
||||
@kernel_function(description="Makes a PUT request to a uri", name="putAsync")
|
||||
@kernel_function_context_parameter(name="body", description="The body of the request")
|
||||
async def put(self, url: str, context: "KernelContext") -> str:
|
||||
async def put(
|
||||
self,
|
||||
url: Annotated[str, "The URI to send the request to."],
|
||||
body: Annotated[Optional[Dict[str, Any]], "The body of the request"] = {},
|
||||
) -> str:
|
||||
"""
|
||||
Sends an HTTP PUT request to the specified URI and returns
|
||||
the response body as a string.
|
||||
@@ -81,8 +88,6 @@ class HttpPlugin(KernelBaseModel):
|
||||
if not url:
|
||||
raise ValueError("url cannot be `None` or empty")
|
||||
|
||||
body = context.variables.get("body")
|
||||
|
||||
headers = {"Content-Type": "application/json"}
|
||||
data = json.dumps(body)
|
||||
async with aiohttp.ClientSession() as session:
|
||||
@@ -90,7 +95,7 @@ class HttpPlugin(KernelBaseModel):
|
||||
return await response.text()
|
||||
|
||||
@kernel_function(description="Makes a DELETE request to a uri", name="deleteAsync")
|
||||
async def delete(self, url: str) -> str:
|
||||
async def delete(self, url: Annotated[str, "The URI to send the request to."]) -> str:
|
||||
"""
|
||||
Sends an HTTP DELETE request to the specified URI and returns
|
||||
the response body as a string.
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import typing as t
|
||||
import sys
|
||||
|
||||
from semantic_kernel.kernel_pydantic import KernelBaseModel
|
||||
from semantic_kernel.plugin_definition import kernel_function, kernel_function_context_parameter
|
||||
if sys.version_info >= (3, 9):
|
||||
from typing import Annotated
|
||||
else:
|
||||
from typing_extensions import Annotated
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
from semantic_kernel.orchestration.kernel_context import KernelContext
|
||||
from semantic_kernel.functions.kernel_function_decorator import kernel_function
|
||||
|
||||
|
||||
class MathPlugin(KernelBaseModel):
|
||||
class MathPlugin:
|
||||
"""
|
||||
Description: MathPlugin provides a set of functions to make Math calculations.
|
||||
|
||||
@@ -16,42 +17,32 @@ class MathPlugin(KernelBaseModel):
|
||||
kernel.import_plugin(MathPlugin(), plugin_name="math")
|
||||
|
||||
Examples:
|
||||
{{math.Add}} => Returns the sum of initial_value_text and Amount (provided in the KernelContext)
|
||||
{{math.Add}} => Returns the sum of input and amount (provided in the KernelArguments)
|
||||
{{math.Subtract}} => Returns the difference of input and amount (provided in the KernelArguments)
|
||||
"""
|
||||
|
||||
@kernel_function(
|
||||
description="Adds value to a value",
|
||||
name="Add",
|
||||
input_description="The value to add",
|
||||
)
|
||||
@kernel_function_context_parameter(
|
||||
name="Amount",
|
||||
description="Amount to add",
|
||||
type="number",
|
||||
required=True,
|
||||
)
|
||||
def add(self, initial_value_text: str, context: "KernelContext") -> str:
|
||||
"""
|
||||
Returns the Addition result of initial and amount values provided.
|
||||
|
||||
:param initial_value_text: Initial value as string to add the specified amount
|
||||
:param context: Contains the context to get the numbers from
|
||||
:return: The resulting sum as a string
|
||||
"""
|
||||
return MathPlugin.add_or_subtract(initial_value_text, context, add=True)
|
||||
@kernel_function(name="Add")
|
||||
def add(
|
||||
self,
|
||||
input: Annotated[int, "the first number to add"],
|
||||
amount: Annotated[int, "the second number to add"],
|
||||
) -> Annotated[int, "the output is a number"]:
|
||||
"""Returns the Addition result of the values provided."""
|
||||
if isinstance(input, str):
|
||||
input = int(input)
|
||||
if isinstance(amount, str):
|
||||
amount = int(amount)
|
||||
return MathPlugin.add_or_subtract(input, amount, add=True)
|
||||
|
||||
@kernel_function(
|
||||
description="Subtracts value to a value",
|
||||
name="Subtract",
|
||||
input_description="The value to subtract",
|
||||
)
|
||||
@kernel_function_context_parameter(
|
||||
name="Amount",
|
||||
description="Amount to subtract",
|
||||
type="number",
|
||||
required=True,
|
||||
)
|
||||
def subtract(self, initial_value_text: str, context: "KernelContext") -> str:
|
||||
def subtract(
|
||||
self,
|
||||
input: Annotated[int, "the first number"],
|
||||
amount: Annotated[int, "the number to subtract"],
|
||||
) -> int:
|
||||
"""
|
||||
Returns the difference of numbers provided.
|
||||
|
||||
@@ -59,10 +50,14 @@ class MathPlugin(KernelBaseModel):
|
||||
:param context: Contains the context to get the numbers from
|
||||
:return: The resulting subtraction as a string
|
||||
"""
|
||||
return MathPlugin.add_or_subtract(initial_value_text, context, add=False)
|
||||
if isinstance(input, str):
|
||||
input = int(input)
|
||||
if isinstance(amount, str):
|
||||
amount = int(amount)
|
||||
return MathPlugin.add_or_subtract(input, amount, add=False)
|
||||
|
||||
@staticmethod
|
||||
def add_or_subtract(initial_value_text: str, context: "KernelContext", add: bool) -> str:
|
||||
def add_or_subtract(input: int, amount: int, add: bool) -> int:
|
||||
"""
|
||||
Helper function to perform addition or subtraction based on the add flag.
|
||||
|
||||
@@ -71,19 +66,4 @@ class MathPlugin(KernelBaseModel):
|
||||
:param add: If True, performs addition, otherwise performs subtraction
|
||||
:return: The resulting sum or subtraction as a string
|
||||
"""
|
||||
try:
|
||||
initial_value = int(initial_value_text)
|
||||
except ValueError:
|
||||
raise ValueError(f"Initial value provided is not in numeric format: {initial_value_text}")
|
||||
|
||||
context_amount = context["Amount"]
|
||||
if context_amount is not None:
|
||||
try:
|
||||
amount = int(context_amount)
|
||||
except ValueError:
|
||||
raise ValueError("Context amount provided is not in numeric format:" f" {context_amount}")
|
||||
|
||||
result = initial_value + amount if add else initial_value - amount
|
||||
return str(result)
|
||||
else:
|
||||
raise ValueError("Context amount should not be None.")
|
||||
return input + amount if add else input - amount
|
||||
|
||||
@@ -1,88 +1,65 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
import typing as t
|
||||
from typing import ClassVar
|
||||
from typing import Final, Optional
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
from typing import Annotated
|
||||
else:
|
||||
from typing_extensions import Annotated
|
||||
from semantic_kernel.functions.kernel_function_decorator import kernel_function
|
||||
from semantic_kernel.kernel_pydantic import KernelBaseModel
|
||||
from semantic_kernel.plugin_definition import kernel_function, kernel_function_context_parameter
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
from semantic_kernel.orchestration.kernel_context import KernelContext
|
||||
from semantic_kernel.kernel import Kernel
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_COLLECTION: Final[str] = "generic"
|
||||
DEFAULT_RELEVANCE: Final[float] = 0.75
|
||||
DEFAULT_LIMIT: Final[int] = 1
|
||||
|
||||
|
||||
class TextMemoryPlugin(KernelBaseModel):
|
||||
COLLECTION_PARAM: ClassVar[str] = "collection"
|
||||
RELEVANCE_PARAM: ClassVar[str] = "relevance"
|
||||
KEY_PARAM: ClassVar[str] = "key"
|
||||
LIMIT_PARAM: ClassVar[str] = "limit"
|
||||
DEFAULT_COLLECTION: ClassVar[str] = "generic"
|
||||
DEFAULT_RELEVANCE: ClassVar[float] = "0.75"
|
||||
DEFAULT_LIMIT: ClassVar[int] = "1"
|
||||
|
||||
# @staticmethod
|
||||
@kernel_function(
|
||||
description="Recall a fact from the long term memory",
|
||||
name="recall",
|
||||
input_description="The information to retrieve",
|
||||
)
|
||||
@kernel_function_context_parameter(
|
||||
name=COLLECTION_PARAM,
|
||||
description="The collection to search for information",
|
||||
default_value=DEFAULT_COLLECTION,
|
||||
)
|
||||
@kernel_function_context_parameter(
|
||||
name=RELEVANCE_PARAM,
|
||||
description="The relevance score, from 0.0 to 1.0; 1.0 means perfect match",
|
||||
default_value=DEFAULT_RELEVANCE,
|
||||
)
|
||||
@kernel_function_context_parameter(
|
||||
name=LIMIT_PARAM,
|
||||
description="The maximum number of relevant memories to recall.",
|
||||
default_value=DEFAULT_LIMIT,
|
||||
)
|
||||
async def recall(self, ask: str, context: "KernelContext") -> str:
|
||||
async def recall(
|
||||
self,
|
||||
ask: Annotated[str, "The information to retrieve"],
|
||||
kernel: Annotated["Kernel", "The kernel"],
|
||||
collection: Annotated[Optional[str], "The collection to search for information."] = DEFAULT_COLLECTION,
|
||||
relevance: Annotated[
|
||||
Optional[float], "The relevance score, from 0.0 to 1.0; 1.0 means perfect match"
|
||||
] = DEFAULT_RELEVANCE,
|
||||
limit: Annotated[Optional[int], "The maximum number of relevant memories to recall."] = DEFAULT_LIMIT,
|
||||
) -> str:
|
||||
"""
|
||||
Recall a fact from the long term memory.
|
||||
|
||||
Example:
|
||||
context["input"] = "what is the capital of France?"
|
||||
{{memory.recall $input}} => "Paris"
|
||||
{{memory.recall $ask}} => "Paris"
|
||||
|
||||
Args:
|
||||
ask -- The question to ask the memory
|
||||
context -- Contains the 'collection' to search for information
|
||||
, the 'relevance' score to use when searching
|
||||
and the 'limit' of relevant memories to retrieve.
|
||||
collection -- The collection to search for information
|
||||
relevance -- The relevance score, from 0.0 to 1.0; 1.0 means perfect match
|
||||
limit -- The maximum number of relevant memories to recall
|
||||
|
||||
Returns:
|
||||
The nearest item from the memory store as a string or empty string if not found.
|
||||
"""
|
||||
|
||||
if context.variables is None:
|
||||
raise ValueError("The context doesn't have the variables required to know how to recall memory")
|
||||
if context.memory is None:
|
||||
if kernel.memory is None:
|
||||
raise ValueError("The context doesn't have a memory instance to search")
|
||||
|
||||
collection = context.variables.get(TextMemoryPlugin.COLLECTION_PARAM, TextMemoryPlugin.DEFAULT_COLLECTION)
|
||||
if not collection:
|
||||
raise ValueError("Memory collection not defined for TextMemoryPlugin")
|
||||
|
||||
relevance = context.variables.get(TextMemoryPlugin.RELEVANCE_PARAM, TextMemoryPlugin.DEFAULT_RELEVANCE)
|
||||
if not relevance:
|
||||
raise ValueError("Relevance value not defined for TextMemoryPlugin")
|
||||
|
||||
limit = context.variables.get(TextMemoryPlugin.LIMIT_PARAM, TextMemoryPlugin.DEFAULT_LIMIT)
|
||||
if limit is None or str(limit).strip() == "":
|
||||
raise ValueError("Limit value not defined for TextMemoryPlugin")
|
||||
|
||||
results = await context.memory.search(
|
||||
results = await kernel.memory.search(
|
||||
collection=collection,
|
||||
query=ask,
|
||||
limit=int(limit),
|
||||
min_relevance_score=float(relevance),
|
||||
limit=limit,
|
||||
min_relevance_score=relevance,
|
||||
)
|
||||
if results is None or len(results) == 0:
|
||||
logger.warning(f"Memory not found in collection: {collection}")
|
||||
@@ -93,43 +70,26 @@ class TextMemoryPlugin(KernelBaseModel):
|
||||
@kernel_function(
|
||||
description="Save information to semantic memory",
|
||||
name="save",
|
||||
input_description="The information to save",
|
||||
)
|
||||
@kernel_function_context_parameter(
|
||||
name=COLLECTION_PARAM,
|
||||
description="The collection to save the information",
|
||||
default_value=DEFAULT_COLLECTION,
|
||||
)
|
||||
@kernel_function_context_parameter(
|
||||
name=KEY_PARAM,
|
||||
description="The unique key to associate with the information",
|
||||
)
|
||||
async def save(self, text: str, context: "KernelContext") -> None:
|
||||
async def save(
|
||||
self,
|
||||
text: Annotated[str, "The information to save."],
|
||||
kernel: Annotated["Kernel", "The kernel"],
|
||||
key: Annotated[str, "The unique key to associate with the information."],
|
||||
collection: Annotated[Optional[str], "The collection to save the information."] = DEFAULT_COLLECTION,
|
||||
) -> None:
|
||||
"""
|
||||
Save a fact to the long term memory.
|
||||
|
||||
Example:
|
||||
context["input"] = "the capital of France is Paris"
|
||||
context[TextMemoryPlugin.KEY_PARAM] = "countryInfo1"
|
||||
{{memory.save $input}}
|
||||
|
||||
Args:
|
||||
text -- The text to save to the memory
|
||||
context -- Contains the 'collection' to save the information
|
||||
and unique 'key' to associate with the information
|
||||
kernel -- The kernel instance, that has a memory store
|
||||
collection -- The collection to save the information
|
||||
key -- The unique key to associate with the information
|
||||
|
||||
"""
|
||||
|
||||
if context.variables is None:
|
||||
raise ValueError("The context doesn't have the variables required to know how to recall memory")
|
||||
if context.memory is None:
|
||||
if kernel.memory is None:
|
||||
raise ValueError("The context doesn't have a memory instance to search")
|
||||
|
||||
collection = context.variables.get(TextMemoryPlugin.COLLECTION_PARAM, TextMemoryPlugin.DEFAULT_COLLECTION)
|
||||
if not collection:
|
||||
raise ValueError("Memory collection not defined for TextMemoryPlugin")
|
||||
|
||||
key = context.variables.get(TextMemoryPlugin.KEY_PARAM, None)
|
||||
if not key:
|
||||
raise ValueError("Memory key not defined for TextMemoryPlugin")
|
||||
|
||||
await context.memory.save_information(collection, text=text, id=key)
|
||||
await kernel.memory.save_information(collection, text=text, id=key)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from semantic_kernel.functions.kernel_function_decorator import kernel_function
|
||||
from semantic_kernel.kernel_pydantic import KernelBaseModel
|
||||
from semantic_kernel.plugin_definition import kernel_function
|
||||
|
||||
|
||||
class TextPlugin(KernelBaseModel):
|
||||
@@ -12,73 +12,73 @@ class TextPlugin(KernelBaseModel):
|
||||
kernel.import_plugin(TextPlugin(), plugin_name="text")
|
||||
|
||||
Examples:
|
||||
KernelContext["input"] = " hello world "
|
||||
KernelArguments["input"] = " hello world "
|
||||
{{text.trim $input}} => "hello world"
|
||||
|
||||
KernelContext["input"] = " hello world "
|
||||
KernelArguments["input"] = " hello world "
|
||||
{{text.trimStart $input} => "hello world "
|
||||
|
||||
KernelContext["input"] = " hello world "
|
||||
KernelArguments["input"] = " hello world "
|
||||
{{text.trimEnd $input} => " hello world"
|
||||
|
||||
KernelContext["input"] = "hello world"
|
||||
KernelArguments["input"] = "hello world"
|
||||
{{text.uppercase $input}} => "HELLO WORLD"
|
||||
|
||||
KernelContext["input"] = "HELLO WORLD"
|
||||
KernelArguments["input"] = "HELLO WORLD"
|
||||
{{text.lowercase $input}} => "hello world"
|
||||
"""
|
||||
|
||||
@kernel_function(description="Trim whitespace from the start and end of a string.")
|
||||
def trim(self, text: str) -> str:
|
||||
def trim(self, input: str) -> str:
|
||||
"""
|
||||
Trim whitespace from the start and end of a string.
|
||||
|
||||
Example:
|
||||
KernelContext["input"] = " hello world "
|
||||
KernelArguments["input"] = " hello world "
|
||||
{{text.trim $input}} => "hello world"
|
||||
"""
|
||||
return text.strip()
|
||||
return input.strip()
|
||||
|
||||
@kernel_function(description="Trim whitespace from the start of a string.")
|
||||
def trim_start(self, text: str) -> str:
|
||||
def trim_start(self, input: str) -> str:
|
||||
"""
|
||||
Trim whitespace from the start of a string.
|
||||
|
||||
Example:
|
||||
KernelContext["input"] = " hello world "
|
||||
{{text.trim $input}} => "hello world "
|
||||
KernelArguments["input"] = " hello world "
|
||||
{{input.trim $input}} => "hello world "
|
||||
"""
|
||||
return text.lstrip()
|
||||
return input.lstrip()
|
||||
|
||||
@kernel_function(description="Trim whitespace from the end of a string.")
|
||||
def trim_end(self, text: str) -> str:
|
||||
def trim_end(self, input: str) -> str:
|
||||
"""
|
||||
Trim whitespace from the end of a string.
|
||||
|
||||
Example:
|
||||
KernelContext["input"] = " hello world "
|
||||
{{text.trim $input}} => " hello world"
|
||||
KernelArguments["input"] = " hello world "
|
||||
{{input.trim $input}} => " hello world"
|
||||
"""
|
||||
return text.rstrip()
|
||||
return input.rstrip()
|
||||
|
||||
@kernel_function(description="Convert a string to uppercase.")
|
||||
def uppercase(self, text: str) -> str:
|
||||
def uppercase(self, input: str) -> str:
|
||||
"""
|
||||
Convert a string to uppercase.
|
||||
|
||||
Example:
|
||||
KernelContext["input"] = "hello world"
|
||||
{{text.uppercase $input}} => "HELLO WORLD"
|
||||
KernelArguments["input"] = "hello world"
|
||||
{{input.uppercase $input}} => "HELLO WORLD"
|
||||
"""
|
||||
return text.upper()
|
||||
return input.upper()
|
||||
|
||||
@kernel_function(description="Convert a string to lowercase.")
|
||||
def lowercase(self, text: str) -> str:
|
||||
def lowercase(self, input: str) -> str:
|
||||
"""
|
||||
Convert a string to lowercase.
|
||||
|
||||
Example:
|
||||
KernelContext["input"] = "HELLO WORLD"
|
||||
{{text.lowercase $input}} => "hello world"
|
||||
KernelArguments["input"] = "HELLO WORLD"
|
||||
{{input.lowercase $input}} => "hello world"
|
||||
"""
|
||||
return text.lower()
|
||||
return input.lower()
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
import datetime
|
||||
|
||||
from semantic_kernel.functions.kernel_function_decorator import kernel_function
|
||||
from semantic_kernel.kernel_pydantic import KernelBaseModel
|
||||
from semantic_kernel.plugin_definition import kernel_function
|
||||
|
||||
|
||||
class TimePlugin(KernelBaseModel):
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
from typing import Union
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
from typing import Annotated
|
||||
else:
|
||||
from typing_extensions import Annotated
|
||||
|
||||
from semantic_kernel.functions.kernel_function_decorator import kernel_function
|
||||
from semantic_kernel.kernel_pydantic import KernelBaseModel
|
||||
from semantic_kernel.plugin_definition import kernel_function
|
||||
|
||||
|
||||
class WaitPlugin(KernelBaseModel):
|
||||
@@ -14,13 +21,16 @@ class WaitPlugin(KernelBaseModel):
|
||||
kernel.import_plugin(WaitPlugin(), plugin_name="wait")
|
||||
|
||||
Examples:
|
||||
{{wait.seconds 5}} => Wait for 5 seconds
|
||||
{{wait.wait 5}} => Wait for 5 seconds
|
||||
"""
|
||||
|
||||
@kernel_function(description="Wait for a certain number of seconds.")
|
||||
async def wait(self, seconds_text: str) -> None:
|
||||
try:
|
||||
seconds = max(float(seconds_text), 0)
|
||||
except ValueError:
|
||||
raise ValueError("seconds text must be a number")
|
||||
await asyncio.sleep(seconds)
|
||||
async def wait(
|
||||
self, input: Annotated[Union[float, str], "The number of seconds to wait, can be str or float."]
|
||||
) -> None:
|
||||
if isinstance(input, str):
|
||||
try:
|
||||
input = float(input)
|
||||
except ValueError as exc:
|
||||
raise ValueError("seconds text must be a number") from exc
|
||||
await asyncio.sleep(abs(input))
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import typing as t
|
||||
import sys
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from semantic_kernel.connectors.search_engine.connector import ConnectorBase
|
||||
from semantic_kernel.plugin_definition import kernel_function, kernel_function_context_parameter
|
||||
if sys.version_info >= (3, 9):
|
||||
from typing import Annotated
|
||||
else:
|
||||
from typing_extensions import Annotated
|
||||
from semantic_kernel.functions.kernel_function_decorator import kernel_function
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
from semantic_kernel.orchestration.kernel_context import KernelContext
|
||||
if TYPE_CHECKING:
|
||||
from semantic_kernel.connectors.search_engine.connector import ConnectorBase
|
||||
|
||||
|
||||
class WebSearchEnginePlugin:
|
||||
@@ -27,28 +31,21 @@ class WebSearchEnginePlugin:
|
||||
def __init__(self, connector: "ConnectorBase") -> None:
|
||||
self._connector = connector
|
||||
|
||||
@kernel_function(description="Performs a web search for a given query", name="searchAsync")
|
||||
@kernel_function_context_parameter(
|
||||
name="num_results",
|
||||
description="The number of search results to return",
|
||||
default_value="1",
|
||||
)
|
||||
@kernel_function_context_parameter(
|
||||
name="offset",
|
||||
description="The number of search results to skip",
|
||||
default_value="0",
|
||||
)
|
||||
async def search(self, query: str, context: "KernelContext") -> str:
|
||||
@kernel_function(description="Performs a web search for a given query", name="search")
|
||||
async def search(
|
||||
self,
|
||||
query: Annotated[str, "The search query"],
|
||||
num_results: Annotated[Optional[int], "The number of search results to return"] = 1,
|
||||
offset: Annotated[Optional[int], "The number of search results to skip"] = 0,
|
||||
) -> str:
|
||||
"""
|
||||
Returns the search results of the query provided.
|
||||
Returns `num_results` results and ignores the first `offset`.
|
||||
|
||||
:param query: search query
|
||||
:param context: contains the context of count and offset parameters
|
||||
:param num_results: number of search results to return, default is 1
|
||||
:param offset: number of search results to skip, default is 0
|
||||
:return: stringified list of search results
|
||||
"""
|
||||
|
||||
_num_results = context.variables.get("num_results")
|
||||
_offset = context.variables.get("offset")
|
||||
result = await self._connector.search(query, _num_results, _offset)
|
||||
result = await self._connector.search(query, num_results, offset)
|
||||
return str(result)
|
||||
|
||||
@@ -1,16 +1,45 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import Field
|
||||
|
||||
from semantic_kernel.events.kernel_events_args import KernelEventArgs
|
||||
from semantic_kernel.functions.function_result import FunctionResult
|
||||
|
||||
|
||||
class FunctionInvokedEventArgs(KernelEventArgs):
|
||||
def __init__(self, function_view, context):
|
||||
super().__init__(function_view, context)
|
||||
self._repeat_requested = False
|
||||
"""Function Invoked Event Args.
|
||||
|
||||
@property
|
||||
def is_repeat_requested(self):
|
||||
return self._repeat_requested
|
||||
Receives relevant parts of the the execution, after (invoked) the function is executed.
|
||||
When a handler changes the arguments in the invoking event,
|
||||
the new arguments are passed to the invoked event,
|
||||
make sure to use the update_arguments function, since that also raises the flag that the arguments were updated.
|
||||
|
||||
If exception is not None, the function execution failed,
|
||||
if you want the execution of the pipeline to continue, you need to clear the exception.
|
||||
You can then also set the repeat flag to True, to repeat the function execution, possible with updated arguments.
|
||||
|
||||
Args:
|
||||
kernel_function_metadata (FunctionView): The function that is being executed.
|
||||
arguments (KernelArguments): The arguments that are being passed to the function.
|
||||
function_result (FunctionResult): The result of the function execution.
|
||||
exception (Optional: Exception): The exception that was raised during the function execution.
|
||||
|
||||
Flags:
|
||||
updated_arguments (bool): Whether the arguments were updated, default False.
|
||||
is_cancel_requested (bool): Whether the function execution has to be canceled, default False.
|
||||
is_repeat_requested (bool): Whether the function execution has to be repeated, default False.
|
||||
|
||||
Methods:
|
||||
cancel: Sets the is_cancel_requested flag to True.
|
||||
update_arguments: Updates the arguments and raises the updated_arguments flag.
|
||||
repeat: Sets the is_repeat_requested flag to True.
|
||||
"""
|
||||
|
||||
function_result: Optional[FunctionResult] = None
|
||||
exception: Optional[Exception] = None
|
||||
is_repeat_requested: bool = Field(default=False, init_var=False)
|
||||
|
||||
def repeat(self):
|
||||
self._repeat_requested = True
|
||||
self.is_repeat_requested = True
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user