Skip to content

Commit

Permalink
added c# azure ai inference sample for chat w/ streaming and updated … (
Browse files Browse the repository at this point in the history
#328)

* added c# azure ai inference sample for chat w/ streaming and updated python sample a bit to use matching env vars

* can't have .csproj's in the template directory... i should know better.

* fixed for real

* enable inferencing via azure ai inference sdk using `ai chat` after `ai init inference`...

* updated with github capabilities w/ azure.ai.inference sdk and related
  • Loading branch information
robch authored Aug 14, 2024
1 parent 1f4bdf3 commit bc1b9f2
Show file tree
Hide file tree
Showing 35 changed files with 627 additions and 44 deletions.
15 changes: 15 additions & 0 deletions ai-cli.sln
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Telemetry", "Telemetry", "{
src\telemetry\NuGet.config = src\telemetry\NuGet.config
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "inference_extension", "src\extensions\inference_extension\inference_extension.csproj", "{7BF26AB6-8931-46CB-A330-D83DF55AB4E8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -181,6 +183,18 @@ Global
{306A3CD6-91C2-450B-9995-79701CE63FE2}.Release|x64.Build.0 = Release|Any CPU
{306A3CD6-91C2-450B-9995-79701CE63FE2}.Release|x86.ActiveCfg = Release|Any CPU
{306A3CD6-91C2-450B-9995-79701CE63FE2}.Release|x86.Build.0 = Release|Any CPU
{7BF26AB6-8931-46CB-A330-D83DF55AB4E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7BF26AB6-8931-46CB-A330-D83DF55AB4E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7BF26AB6-8931-46CB-A330-D83DF55AB4E8}.Debug|x64.ActiveCfg = Debug|Any CPU
{7BF26AB6-8931-46CB-A330-D83DF55AB4E8}.Debug|x64.Build.0 = Debug|Any CPU
{7BF26AB6-8931-46CB-A330-D83DF55AB4E8}.Debug|x86.ActiveCfg = Debug|Any CPU
{7BF26AB6-8931-46CB-A330-D83DF55AB4E8}.Debug|x86.Build.0 = Debug|Any CPU
{7BF26AB6-8931-46CB-A330-D83DF55AB4E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7BF26AB6-8931-46CB-A330-D83DF55AB4E8}.Release|Any CPU.Build.0 = Release|Any CPU
{7BF26AB6-8931-46CB-A330-D83DF55AB4E8}.Release|x64.ActiveCfg = Release|Any CPU
{7BF26AB6-8931-46CB-A330-D83DF55AB4E8}.Release|x64.Build.0 = Release|Any CPU
{7BF26AB6-8931-46CB-A330-D83DF55AB4E8}.Release|x86.ActiveCfg = Release|Any CPU
{7BF26AB6-8931-46CB-A330-D83DF55AB4E8}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -195,6 +209,7 @@ Global
{9499C018-FA08-4133-93B3-FC0F3863A6CC} = {C8AFF891-D6AA-4B8F-BC21-10404DF4B355}
{CED7C805-0435-4BF7-A42F-9F3BBF14A18F} = {644B75F1-C768-4DB3-BAF2-C69A1F36DD28}
{306A3CD6-91C2-450B-9995-79701CE63FE2} = {975EBC5A-506D-49B5-AA7F-70D3119F009D}
{7BF26AB6-8931-46CB-A330-D83DF55AB4E8} = {644B75F1-C768-4DB3-BAF2-C69A1F36DD28}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {002655B1-E1E1-4F2A-8D53-C9CD55136AE2}
Expand Down
1 change: 1 addition & 0 deletions src/ai/.x/config/chat.default.config
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
@default.deployment
@default.search.connection
@default.assistant
@default.model
@default.log
@default.path
@default.output
Expand Down
1 change: 1 addition & 0 deletions src/ai/.x/config/chat.default.model
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[email protected]
1 change: 1 addition & 0 deletions src/ai/.x/config/connection.from.endpoint
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
service.config.region=@region
service.config.endpoint.uri=@endpoint
[email protected]
service.config.key=@key
Empty file added src/ai/.x/config/endpoint.type
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<EnableDefaultCompileItems>true</EnableDefaultCompileItems>
<OutputType>Exe</OutputType>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Azure.Identity" Version="1.12.0" />
<PackageReference Include="Azure.AI.Inference" Version="1.0.0-beta.1" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
//

using Azure;
using Azure.Identity;
using Azure.AI.Inference;
using System;

public class {ClassName}
{
public {ClassName}(string aiChatEndpoint, string aiChatAPIKey, string? aiChatModel, string systemPrompt)
{
_systemPrompt = systemPrompt;
_aiChatModel = aiChatModel;

_client = string.IsNullOrEmpty(aiChatAPIKey)
? new ChatCompletionsClient(new Uri(aiChatEndpoint), new DefaultAzureCredential())
: new ChatCompletionsClient(new Uri(aiChatEndpoint), new AzureKeyCredential(aiChatAPIKey));
_messages = new List<ChatRequestMessage>();

ClearConversation();
}

public void ClearConversation()
{
_messages.Clear();
_messages.Add(new ChatRequestSystemMessage(_systemPrompt));
}

public async Task<string> GetChatCompletionsStreamingAsync(string userPrompt, Action<StreamingChatCompletionsUpdate>? callback = null)
{
_messages.Add(new ChatRequestUserMessage(userPrompt));
var options = new ChatCompletionsOptions(_messages);
if (!string.IsNullOrEmpty(_aiChatModel))
{
options.Model = _aiChatModel;
}

var responseContent = string.Empty;
var response = await _client.CompleteStreamingAsync(options);
await foreach (var update in response)
{
var content = update.ContentUpdate;

if (update.FinishReason == CompletionsFinishReason.ContentFiltered)
{
content = $"{content}\nWARNING: Content filtered!";
}

if (string.IsNullOrEmpty(content)) continue;

responseContent += content;
if (callback != null) callback(update);
}

_messages.Add(new ChatRequestAssistantMessage() { Content = responseContent });
return responseContent;
}

private string _systemPrompt;
private string? _aiChatModel;
private ChatCompletionsClient _client;
private List<ChatRequestMessage> _messages;
}
42 changes: 42 additions & 0 deletions src/ai/.x/templates/aml-chat-streaming-cs/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
//

using System;

public class Program
{
public static async Task Main(string[] args)
{
var aiChatAPIKey = Environment.GetEnvironmentVariable("AZURE_AI_CHAT_API_KEY") ?? "<insert your OpenAI API key here>";
var aiChatEndpoint = Environment.GetEnvironmentVariable("AZURE_AI_CHAT_ENDPOINT") ?? "<insert your OpenAI endpoint here>";
var aiChatModel = Environment.GetEnvironmentVariable("AZURE_AI_CHAT_MODEL"); // null is fine
var systemPrompt = Environment.GetEnvironmentVariable("SYSTEM_PROMPT") ?? "You are a helpful AI assistant.";

if (string.IsNullOrEmpty(aiChatAPIKey) || aiChatAPIKey.StartsWith("<insert") ||
string.IsNullOrEmpty(aiChatEndpoint) || aiChatEndpoint.StartsWith("<insert") ||
string.IsNullOrEmpty(systemPrompt) || systemPrompt.StartsWith("<insert"))
{
Console.WriteLine("To use Azure AI Inference, set the following environment variables:");
Console.WriteLine("- AZURE_AI_CHAT_API_KEY\n- AZURE_AI_CHAT_ENDPOINT\n- AZURE_AI_CHAT_MODEL (optional)\n- SYSTEM_PROMPT (optional)");
Environment.Exit(1);
}

var chat = new {ClassName}(aiChatEndpoint, aiChatAPIKey, aiChatModel, systemPrompt);

while (true)
{
Console.Write("User: ");
var userPrompt = Console.ReadLine();
if (string.IsNullOrEmpty(userPrompt) || userPrompt == "exit") break;

Console.Write("\nAssistant: ");
var response = await chat.GetChatCompletionsStreamingAsync(userPrompt, update => {
var text = update.ContentUpdate;
Console.Write(text);
});
Console.WriteLine("\n");
}
}
}
6 changes: 6 additions & 0 deletions src/ai/.x/templates/aml-chat-streaming-cs/_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"_LongName": "Azure AI Inference Chat Completions (Streaming)",
"_ShortName": "az-inference-chat-streaming",
"_Language": "C#",
"ClassName": "AzureAIInferenceChatCompletionsStreaming"
}
6 changes: 3 additions & 3 deletions src/ai/.x/templates/aml-chat-streaming-py/_.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"_LongName": "AzureML Chat Completions (Streaming)",
"_ShortName": "aml-chat-streaming",
"_LongName": "Azure AI Inference Chat Completions (Streaming)",
"_ShortName": "az-inference-chat-streaming",
"_Language": "Python",
"ClassName": "AzureMLChatCompletionsStreaming"
"ClassName": "AzureAIInferenceChatCompletionsStreaming"
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
from azure.core.credentials import AzureKeyCredential

class {ClassName}:
def __init__(self, chat_endpoint, chat_api_key, chat_system_prompt):
def __init__(self, chat_endpoint, chat_api_key, chat_model, chat_system_prompt):
self.chat_system_prompt = chat_system_prompt
self.chat_model = chat_model
self.client = ChatCompletionsClient(endpoint=chat_endpoint, credential=AzureKeyCredential(chat_api_key))
self.clear_conversation()

Expand All @@ -19,11 +20,15 @@ def get_chat_completions(self, user_input, callback):
complete_content = ''
response = self.client.complete(
messages=self.messages,
model=self.chat_model,
stream=True,
)

for update in response:

if update.choices is None or len(update.choices) == 0:
continue

content = update.choices[0].delta.content or ""
if content is None: continue

Expand Down
16 changes: 9 additions & 7 deletions src/ai/.x/templates/aml-chat-streaming-py/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,23 @@
import sys

def main():
chat_api_key = os.getenv("AZURE_AI_INFERENCE_CHAT_API_KEY", '<insert your Azure AI Inference API key here>')
chat_endpoint = os.getenv("AZURE_AI_INFERENCE_CHAT_ENDPOINT", '<insert your Azure AI Inference endpoint here>')
chat_system_prompt = os.getenv('AZURE_AI_INFERENCE_CHAT_SYSTEM_PROMPT', 'You are a helpful AI assistant.')
chat_api_key = os.getenv("AZURE_AI_CHAT_API_KEY", '<insert your Azure AI Inference API key here>')
chat_endpoint = os.getenv("AZURE_AI_CHAT_ENDPOINT", '<insert your Azure AI Inference endpoint here>')
chat_model = os.getenv('AZURE_AI_CHAT_MODEL', '')
chat_system_prompt = os.getenv('SYSTEM_PROMPT', 'You are a helpful AI assistant.')

ok = all([chat_api_key, chat_endpoint, chat_system_prompt]) and \
all([not s.startswith('<insert') for s in [chat_api_key, chat_endpoint, chat_system_prompt]])
if not ok:
print(
'To use Azure AI Chat Streaming, set the following environment variables:' +
'\n- AZURE_AI_INFERENCE_CHAT_API_KEY' +
'\n- AZURE_AI_INFERENCE_CHAT_ENDPOINT' +
'\n- AZURE_AI_INFERENCE_CHAT_SYSTEM_PROMPT (optional)')
'\n- AZURE_AI_CHAT_API_KEY' +
'\n- AZURE_AI_CHAT_ENDPOINT' +
'\n- AZURE_AI_CHAT_MODEL (optional)' +
'\n- SYSTEM_PROMPT (optional)')
sys.exit(1)

chat = {ClassName}(chat_endpoint, chat_api_key, chat_system_prompt)
chat = {ClassName}(chat_endpoint, chat_api_key, chat_model, chat_system_prompt)

while True:
user_input = input('User: ')
Expand Down
1 change: 1 addition & 0 deletions src/ai/ai-cli.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
<ItemGroup>
<ProjectReference Include="..\common\common.csproj" />
<ProjectReference Include="..\extensions\helper_functions_extension\helper_functions_extension.csproj" />
<ProjectReference Include="..\extensions\inference_extension\inference_extension.csproj" />
<ProjectReference Include="..\extensions\speech_extension\speech-extension.csproj" />
<ProjectReference Include="..\extensions\template_extension\template_extension.csproj" />
<ProjectReference Include="..\extensions\testframework\YamlTestFramework.csproj" />
Expand Down
Loading

0 comments on commit bc1b9f2

Please sign in to comment.