Skip to content

Commit

Permalink
Python: Restructure samples into new folders to make things more clea…
Browse files Browse the repository at this point in the history
…r. (microsoft#6116)

### Motivation and Context

All previous samples were either in kernel syntax or a separate
notebooks folder. The goal is to make the samples easier to understand
and have a better structure.

<!-- 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.
-->

### Description

The PR restructures the kernel syntax examples into new folders:
concepts (with subfolders for previous syntax examples), demos,
getting_started, and learn_resources.
- Closes microsoft#6119 
- Adds a new concept/function example for understanding kernel
arguments.
- Updates the bookings plugin

<!-- Describe your changes, the overall approach, the underlying design.
These notes will help understanding how your code works. Thanks! -->

### Contribution Checklist

<!-- Before submitting this PR, please make sure: -->

- [X] The code builds clean without any errors or warnings
- [X] The PR follows the [SK Contribution
Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md)
and the [pre-submission formatting
script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts)
raises no violations
- [X] All unit tests pass, and I have added new tests where possible
- [X] I didn't break anyone 😄
  • Loading branch information
moonbox3 authored May 4, 2024
1 parent 65bb59d commit 09508dc
Show file tree
Hide file tree
Showing 200 changed files with 256 additions and 46 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ The fastest way to learn how to use Semantic Kernel is with our C# and Python Ju
demonstrate how to use Semantic Kernel with code snippets that you can run with a push of a button.

- [Getting Started with C# notebook](dotnet/notebooks/00-getting-started.ipynb)
- [Getting Started with Python notebook](python/notebooks/00-getting-started.ipynb)
- [Getting Started with Python notebook](python/samples/getting_started/00-getting-started.ipynb)

Once you've finished the getting started notebooks, you can then check out the main walkthroughs
on our Learn site. Each sample comes with a completed C# and Python project that you can run locally.
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
8 changes: 4 additions & 4 deletions python/DEV_SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ AZURE_OPENAI_API_KEY=""
We suggest adding a copy of the `.env` file under these folders:

- [python/tests](tests)
- [./notebooks](./notebooks).
- [./samples/getting_started](./samples/getting_started).

## System setup

Expand Down Expand Up @@ -133,12 +133,12 @@ Alternatively, you can run them using VSCode Tasks. Open the command palette

## Tools and scripts

## Implementation Decisions
## Implementation Decisions

### Asynchronous programming

It's important to note that most of this library is written with asynchronous in mind. The
developer should always assume everything is asynchronous. One can use the function signature
It's important to note that most of this library is written with asynchronous in mind. The
developer should always assume everything is asynchronous. One can use the function signature
with either `async def` or `def` to understand if something is asynchronous or not.

## Pydantic and Serialization
Expand Down
24 changes: 12 additions & 12 deletions python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,18 +148,18 @@ get started with the Semantic Kernel.

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 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)
- [Combining native functions and semantic functions](./notebooks/08-native-function-inline.ipynb)
- [Groundedness Checking with Semantic Kernel](./notebooks/09-groundedness-checking.ipynb)
- [Returning multiple results per prompt](./notebooks/10-multiple-results-per-prompt.ipynb)
- [Streaming completions with Semantic Kernel](./notebooks/11-streaming-completions.ipynb)
- [Getting started with Semantic Kernel](./samples/getting_started/00-getting-started.ipynb)
- [Loading and configuring Semantic Kernel](./samples/getting_started/01-basic-loading-the-kernel.ipynb)
- [Running AI prompts from file](./samples/getting_started/02-running-prompts-from-file.ipynb)
- [Creating Prompt Functions at runtime (i.e. inline functions)](./samples/getting_started/03-prompt-function-inline.ipynb)
- [Using Context Variables to Build a Chat Experience](./samples/getting_started/04-kernel-arguments-chat.ipynb)
- [Introduction to planners](./samples/getting_started/05-using-the-planner.ipynb)
- [Building Memory with Embeddings](./samples/getting_started/06-memory-and-embeddings.ipynb)
- [Using Hugging Face for Plugins](./samples/getting_started/07-hugging-face-for-plugins.ipynb)
- [Combining native functions and semantic functions](./samples/getting_started/08-native-function-inline.ipynb)
- [Groundedness Checking with Semantic Kernel](./samples/getting_started/09-groundedness-checking.ipynb)
- [Returning multiple results per prompt](./samples/getting_started/10-multiple-results-per-prompt.ipynb)
- [Streaming completions with Semantic Kernel](./samples/getting_started/11-streaming-completions.ipynb)

# SK Frequently Asked Questions

Expand Down
19 changes: 19 additions & 0 deletions python/samples/concepts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Semantic Kernel Concepts by Feature

This section contains code snippets that demonstrate the usage of Semantic Kernel features.

| Features | Description |
| -------- | ----------- |
| AutoFunctionCalling | Using `Auto Function Calling` to allow function call capable models to invoke Kernel Functions automatically |
| ChatCompletion | Using [`ChatCompletion`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/connectors/ai/chat_completion_client_base.py) messaging capable service with models |
| Functions | Invoking [`Method`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/functions/kernel_function_from_method.py) or [`Prompt`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/functions/kernel_function_from_prompt.py) functions with [`Kernel`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/kernel.py) |
| Grounding | An example of how to perform LLM grounding |
| Logging | Showing how to set up logging |
| Memory | Using [`Memory`](https://github.com/microsoft/semantic-kernel/tree/main/dotnet/src/SemanticKernel.Abstractions/Memory) AI concepts |
| On Your Data | Examples of using AzureOpenAI [`On Your Data`](https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/use-your-data?tabs=mongo-db) |
| Planners | Showing the uses of [`Planners`](https://github.com/microsoft/semantic-kernel/tree/main/python/semantic_kernel/planners) |
| Plugins | Different ways of creating and using [`Plugins`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/functions/kernel_plugin.py) |
| PromptTemplates | Using [`Templates`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/prompt_template/prompt_template_base.py) with parametrization for `Prompt` rendering |
| RAG | Different ways of `RAG` (Retrieval-Augmented Generation) |
| Search | Using search services information |
| TextGeneration | Using [`TextGeneration`](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/connectors/ai/text_completion_client_base.py) capable service with models |
72 changes: 72 additions & 0 deletions python/samples/concepts/functions/kernel_arguments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Copyright (c) Microsoft. All rights reserved.

from __future__ import annotations

import asyncio
import datetime
import locale
from typing import Annotated

from semantic_kernel.functions.kernel_arguments import KernelArguments
from semantic_kernel.functions.kernel_function_decorator import kernel_function
from semantic_kernel.kernel import Kernel

# This example shows how to use kernel arguments when invoking functions.


class StaticTextPlugin:
"""A plugin for generating static text."""

@kernel_function(name="uppercase", description="Convert text to uppercase")
def uppercase(
self, text: Annotated[str, "The input text"]
) -> Annotated[str, "The output is the text in uppercase"]:
"""Convert text to uppercase.
Args:
text (str): The text to convert to uppercase.
Returns:
str: The text in uppercase.
"""
return text.upper()

@kernel_function(name="append_day", description="Append the day variable")
def append_day(
self, input: Annotated[str, "The input text"], day: Annotated[str, "The day to append"]
) -> Annotated[str, "The output is the text with the day appended"]:
"""Append the day variable.
Args:
input (str): The input text to append the day to.
day (str): The day to append.
Returns:
str: The text with the day appended.
"""
return f"{input} {day}"


def get_day_of_week_for_locale():
"""Get the day of the week for the current locale."""
locale.setlocale(locale.LC_TIME, "")
return datetime.datetime.now().strftime("%A")


async def main():
kernel = Kernel()

text_plugin = kernel.add_plugin(StaticTextPlugin(), "TextPlugin")
arguments = KernelArguments(input="Today is:", day=get_day_of_week_for_locale())

result = await kernel.invoke(text_plugin["append_day"], arguments)

# The result returned is of type FunctionResult. Printing the result calls the __str__ method.
print(result)

# Note: if you need access to the result metadata, you can do the following
# metadata = result.metadata


if __name__ == "__main__":
asyncio.run(main())
File renamed without changes.
File renamed without changes.
129 changes: 129 additions & 0 deletions python/samples/demos/booking_restaurant/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# Restaurant - Demo Application

This sample provides a practical demonstration of how to leverage features from the [Semantic Kernel](https://learn.microsoft.com/en-us/semantic-kernel) to build a console application. Specifically, the application utilizes the [Business Schedule and Booking API](https://www.microsoft.com/en-us/microsoft-365/business/scheduling-and-booking-app) through Microsoft Graph to enable a Large Language Model (LLM) to book restaurant appointments efficiently. This guide will walk you through the necessary steps to integrate these technologies seamlessly.

## Prerequisites

- Python 3.10, 3.11, or 3.12.
- [Microsoft 365 Business License](https://www.microsoft.com/en-us/microsoft-365/business/compare-all-microsoft-365-business-products) to use [Business Schedule and Booking API](https://www.microsoft.com/en-us/microsoft-365/business/scheduling-and-booking-app).
- [Azure Entra Id](https://www.microsoft.com/en-us/security/business/identity-access/microsoft-entra-id) administrator account to register an application and set the necessary credentials and permissions.

### Function Calling Enabled Models

This sample uses function calling capable models and has been tested with the following models:

| Model type | Model name/id | Model version | Supported |
| --------------- | ------------------------- | ------------------: | --------- |
| Chat Completion | gpt-3.5-turbo | 0125 ||
| Chat Completion | gpt-3.5-turbo-1106 | 1106 ||
| Chat Completion | gpt-3.5-turbo-0613 | 0613 ||
| Chat Completion | gpt-3.5-turbo-0301 | 0301 ||
| Chat Completion | gpt-3.5-turbo-16k | 0613 ||
| Chat Completion | gpt-4 | 0613 ||
| Chat Completion | gpt-4-0613 | 0613 ||
| Chat Completion | gpt-4-0314 | 0314 ||
| Chat Completion | gpt-4-turbo | 2024-04-09 ||
| Chat Completion | gpt-4-turbo-2024-04-09 | 2024-04-09 ||
| Chat Completion | gpt-4-turbo-preview | 0125-preview ||
| Chat Completion | gpt-4-0125-preview | 0125-preview ||
| Chat Completion | gpt-4-vision-preview | 1106-vision-preview ||
| Chat Completion | gpt-4-1106-vision-preview | 1106-vision-preview ||

ℹ️ OpenAI Models older than 0613 version do not support function calling.

ℹ️ When using Azure OpenAI, ensure that the model name of your deployment matches any of the above supported models names.

## Configuring the sample

Please make sure your .env file contains the following:

- "BOOKING_SAMPLE_CLIENT_ID"
- "BOOKING_SAMPLE_TENANT_ID"
- "BOOKING_SAMPLE_CLIENT_SECRET"

### Create an App Registration in Azure Active Directory

1. Go to the [Azure Portal](https://portal.azure.com/).
2. Select the Azure Active Directory service.
3. Select App registrations and click on New registration.
4. Fill in the required fields and click on Register.
5. Copy the Application **(client) Id** for later use.
6. Save Directory **(tenant) Id** for later use..
7. Click on Certificates & secrets and create a new client secret. (Any name and expiration date will work)
8. Copy the **client secret** value for later use.
9. Click on API permissions and add the following permissions:
- Microsoft Graph
- Application permissions
- BookingsAppointment.ReadWrite.All
- Delegated permissions
- OpenId permissions
- offline_access
- profile
- openid

### Create Or Use a Booking Service and Business

1. Go to the [Bookings Homepage](https://outlook.office.com/bookings) website.
2. Create a new Booking Page and add a Service to the Booking (Skip if you don't ).
3. Access [Graph Explorer](https://developer.microsoft.com/en-us/graph/graph-explorer)
4. Run the following query to get the Booking Business Id:
```http
GET https://graph.microsoft.com/v1.0/solutions/bookingBusinesses
```
5. Copy the **Booking Business Id** for later use.
6. Run the following query and replace it with your **Booking Business Id** to get the Booking Service Id
```http
GET https://graph.microsoft.com/v1.0/solutions/bookingBusinesses/{bookingBusiness-id}/services
```
7. Copy the **Booking Service Id** for later use.

## Running the sample

Either run the sample in an IDE, like VSCode, or via the command line.

### Example of a conversation

> **User** > Please book a restaurant for me.
> **Assistant** > Sure, I can help you with that. Could you please provide me with the following information:
>
> 1. Name of the restaurant you would like to book.
> 2. Date and time of the reservation.
> 3. Number of people in your party.
> 4. Your name.
> 5. Your email address.
> 6. Your phone number.
>
> Once I have all this information, I will proceed with the booking.
> **User** > I would like to book a table at the restaurant "The French Laundry" on the 15th of March at 7:00 PM for 4 people. My name is John Doe, my email address is [email protected], and my phone number is 123-456-7890.
> **System** > Do you want to book a table at The French Laundry on 15/03/2023 19:00:00 for 4 people?
> **System** > Please confirm by typing 'yes' or 'no'.
> **User** > yes
> **Assistant** > Great! I have successfully booked a table for you at "The French Laundry" on the 15th of March at 7:00 PM for 4 people.
>
> Your reservation has been made under the name John Doe.
>
> If you have any further questions or need to make any changes to your reservation, please let me know.
> **User** > List my current bookings
> **Assistant** > You currently have one booking:
>
> - Restaurant: The French Laundry
> - Date and Time: 15th of March at 7:00 PM
> - Party Size: 4 people
>
> If you need any further assistance or if there's anything else I can help you with, please let me know.
> **User** > Cancel my booking
> **System** > `[Cancelling a reservation for 4 at The French Laundry on 2023-03-15 at 19:00:00]`
> **Assistant** > I have successfully canceled your booking at "The French Laundry" on the 15th of March at 7:00 PM for 4 people.
>
> If you have any other questions or need further assistance, please let me know.
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ async def book_table(
Returns:
str: The status of the booking.
"""
print(f"System > Do you want to book a table at {restaurant} on {date_time} for {party_size} people?")
print("System > Please confirm by typing 'yes' or 'no'.")
confirmation = input("User:> ")
if confirmation.lower() != "yes":
return "Booking aborted by the user."
request_body = BookingAppointment(
odata_type="#microsoft.graph.bookingAppointment",
customer_time_zone=self.customer_timezone,
Expand Down Expand Up @@ -107,7 +112,7 @@ async def book_table(
self.booking_business_id
).appointments.post(request_body)

return response.id
return f"Booking successful! Your reservation ID is {response.id}."

@kernel_function(name="list_revervations", description="List all reservations")
async def list_reservations(self) -> Annotated[str, "The list of reservations"]:
Expand All @@ -126,26 +131,18 @@ async def list_reservations(self) -> Annotated[str, "The list of reservations"]:
async def cancel_reservation(
self,
reservation_id: Annotated[str, "The ID of the reservation"],
restaurant: Annotated[str, "The name of the restaurant"],
date: Annotated[str, "The date of the reservation"],
time: Annotated[str, "The time of the reservation"],
party_size: Annotated[int, "The number of people in the party"],
) -> Annotated[str, "The cancellation status of the reservation"]:
"""Cancel a reservation."""

# The graph API is throwing a 500 (instead of a 400), so commenting this out for now until we
# can understand how to get it working.
# Filed issue: https://github.com/microsoftgraph/msgraph-sdk-python/issues/659

# # First cancel the reservation
# request_body = CancelPostRequestBody(
# comment="Your appointment has been successfully cancelled. Please call us again.",
# )

# await self.graph_client.solutions.booking_businesses.by_booking_business_id(
# self.booking_business_id
# ).appointments.by_booking_appointment_id(reservation.id).cancel.post(request_body)

# # Then delete the reservation
# _ = (
# await self.graph_client.solutions.booking_businesses.by_booking_business_id(self.booking_business_id)
# .appointments.by_booking_appointment_id(reservation.id)
# .delete()
# )
return "Reservation canceled!"
print(f"System > [Cancelling a reservation for {party_size} at {restaurant} on {date} at {time}]")

_ = (
await self.graph_client.solutions.booking_businesses.by_booking_business_id(self.booking_business_id)
.appointments.by_booking_appointment_id(reservation_id)
.delete()
)
return "Cancellation successful!"
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import asyncio

from azure.identity import ClientSecretCredential
from bookings_plugin.bookings_plugin import BookingsPlugin
from dotenv import dotenv_values
from msgraph import GraphServiceClient
from resources.bookings_plugin.bookings_plugin import BookingsPlugin

from semantic_kernel.connectors.ai.chat_completion_client_base import ChatCompletionClientBase
from semantic_kernel.connectors.ai.open_ai.prompt_execution_settings.open_ai_prompt_execution_settings import (
Expand All @@ -18,13 +18,6 @@
from semantic_kernel.kernel import Kernel
from semantic_kernel.utils.settings import booking_sample_settings_from_dot_env_as_dict, openai_settings_from_dot_env

# To be able to run this sample, you must do the following:
# 1. Create an Microsoft Entra App ID and Client Secret in Azure Portal
# 2. Add the client ID, tenant ID, and client secret to a .env file in the root of the project
# using the following format: BOOKING_SAMPLE_CLIENT_ID="", BOOKING_SAMPLE_TENANT_ID="",
# BOOKING_SAMPLE_CLIENT_SECRET="".
# 3. Create a booking business ID and service ID and give the app permissions based on your App Id and secret.

kernel = Kernel()

service_id = "open_ai"
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 comments on commit 09508dc

Please sign in to comment.