Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add function calling example and logic apps workflow #212

Merged
merged 1 commit into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ tfplan
*.crt
*.pub
id_rsa
.vscode/

python/expense-classification-guidance/.env

python/expense-classification-guidance/.idea/
Expand All @@ -389,3 +389,5 @@ sandbox/usecases/rag/dotnet/.env
sandbox/notebooks/prompt-engineering/dotnet/.env

sandbox/prompt-engineering/notebooks/prompt-engineering/dotnet/.env

.vscode/settings.json
6 changes: 6 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"recommendations": [
"ms-azuretools.vscode-azurefunctions",
"ms-python.python"
]
}
39 changes: 39 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch (web)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/dotnet/recommendation-service/bin/Debug/net7.0/GBB.Miyagi.RecommendationService.dll",
"args": [
"--verbose"
],
"cwd": "${workspaceFolder}/dotnet/recommendation-service",
"stopAtEntry": false,
"serverReadyAction": {
"action": "openExternally",
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
},
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"sourceFileMap": {
"/Views": "${workspaceFolder}/Views"
}
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
},
{
"name": "Attach to Python Functions",
"type": "python",
"request": "attach",
"port": 9091,
"preLaunchTask": "func: host start"
}
]
}
69 changes: 69 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/dotnet/recommendation-service/GBB.Miyagi.RecommendationService.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/dotnet/recommendation-service/GBB.Miyagi.RecommendationService.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"--project",
"${workspaceFolder}/dotnet/recommendation-service/GBB.Miyagi.RecommendationService.csproj"
],
"problemMatcher": "$msCompile"
},
{
"type": "func",
"label": "func: host start",
"command": "host start",
"problemMatcher": "$func-python-watch",
"isBackground": true,
"dependsOn": "pip install (functions)",
"options": {
"cwd": "${workspaceFolder}/sandbox\\agents\\plugins"
}
},
{
"label": "pip install (functions)",
"type": "shell",
"osx": {
"command": "${config:azureFunctions.pythonVenv}/bin/python -m pip install -r requirements.txt"
},
"windows": {
"command": "${config:azureFunctions.pythonVenv}\\Scripts\\python -m pip install -r requirements.txt"
},
"linux": {
"command": "${config:azureFunctions.pythonVenv}/bin/python -m pip install -r requirements.txt"
},
"problemMatcher": [],
"options": {
"cwd": "${workspaceFolder}/sandbox\\agents\\plugins"
}
}
]
}
3 changes: 2 additions & 1 deletion sandbox/agents/assistants-api/azure-openai/.env.sample
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
OPENAI_API_KEY=<your-api-key>
OPENAI_MODEL_NAME=<your-model-name>
OPENAI_ENDPOINT=<your-endpoint>
OPENAI_ENDPOINT=<your-endpoint>
DATA_COLLECTION_LOGIC_APPS_URI=<your-logic-app-workflow-uri>
110 changes: 110 additions & 0 deletions sandbox/agents/assistants-api/azure-openai/azure_ai_util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# azure_ai_utils.py
import io
import matplotlib.pyplot as plt
from typing import Iterable
from pathlib import Path
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type

# Import AzureOpenAI and assistant-related Message classes
from openai import AzureOpenAI
from openai.types.beta.threads.message_content_image_file import MessageContentImageFile
from openai.types.beta.threads.message_content_text import MessageContentText
from openai.types.beta.threads.messages import MessageFile


class NotCompletedException(Exception):
"""Custom exception for handling incomplete run statuses."""
pass


class AzureAIUtils:
"""
A utility class for various Azure AI operations including
message formatting, file uploading, and lifecycle status checking.
"""

def __init__(self, client: AzureOpenAI):
"""
Initialize the utility class with an AzureOpenAI client.

Parameters:
client (AzureOpenAI): An instance of the AzureOpenAI client.
"""
self.client = client

def format_response(self, messages: Iterable[MessageFile]) -> None:
"""
Formats and prints the content of messages from AzureOpenAI.

Parameters:
messages (Iterable[MessageFile]): An iterable of MessageFile objects.
"""
message_list = []

for message in messages:
message_list.append(message)
if message.role == "user":
break

message_list.reverse()

for message in message_list:
for item in message.content:
if isinstance(item, MessageContentText):
print(f"{message.role}:\n{item.text.value}\n")
elif isinstance(item, MessageContentImageFile):
try:
response_content = self.client.files.content(
item.image_file.file_id
)
data_in_bytes = response_content.read()
readable_buffer = io.BytesIO(data_in_bytes)
image = plt.imread(readable_buffer, format="jpeg")
plt.imshow(image)
plt.axis("off")
plt.show()
except Exception as e:
print(f"Exception: {e}")

def upload_file(self, path: Path):
"""
Uploads a file to AzureOpenAI.

Parameters:
path (Path): The path to the file to be uploaded.

Returns:
FileObject: The file object created in AzureOpenAI.
"""
with path.open("rb") as f:
return self.client.files.create(file=f, purpose="assistants")

@retry(
stop=stop_after_attempt(15),
wait=wait_exponential(multiplier=1.5, min=4, max=20),
retry=retry_if_exception_type(NotCompletedException),
)
def get_run_lifecycle_status(self, thread_id, run_id):
"""
Retrieves and prints the lifecycle status of a run and
retries based on specific conditions.

Parameters:
thread_id: The ID of the thread.
run_id: The ID of the run.

Returns:
The run object if its status is 'completed', 'failed', 'expired', or 'cancelled'.

Raises:
NotCompletedException: If the run is not yet completed.
"""
run = self.client.beta.threads.runs.retrieve(thread_id=thread_id, run_id=run_id)
print(f"Run status: {run.status}")
if run.status in ["completed", "failed", "expired", "cancelled"]:
print(f"Run info: {run}")
return run
elif run.status == "requires_action":
pass # Handle cases that require action differently
else:
raise NotCompletedException("Run not completed yet")
Loading