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

Added dashboard and otel viewing commands #324

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 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
20 changes: 20 additions & 0 deletions ai-cli.sln
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Telemetry", "Telemetry", "{
src\telemetry\NuGet.config = src\telemetry\NuGet.config
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{13B3E651-BF79-4138-A73D-FD41F773E0F4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "extensions", "extensions", "{A5154519-2271-45E8-8761-816440870E40}"
EndProject
catherine-m-zhang marked this conversation as resolved.
Show resolved Hide resolved
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "otel_viewer_extension", "src\extensions\otel_viewer_extension\otel_viewer_extension.csproj", "{B153ED12-2028-49A9-AD7F-9D67DA0ECA32}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -181,6 +187,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
{B153ED12-2028-49A9-AD7F-9D67DA0ECA32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
catherine-m-zhang marked this conversation as resolved.
Show resolved Hide resolved
{B153ED12-2028-49A9-AD7F-9D67DA0ECA32}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B153ED12-2028-49A9-AD7F-9D67DA0ECA32}.Debug|x64.ActiveCfg = Debug|Any CPU
{B153ED12-2028-49A9-AD7F-9D67DA0ECA32}.Debug|x64.Build.0 = Debug|Any CPU
{B153ED12-2028-49A9-AD7F-9D67DA0ECA32}.Debug|x86.ActiveCfg = Debug|Any CPU
{B153ED12-2028-49A9-AD7F-9D67DA0ECA32}.Debug|x86.Build.0 = Debug|Any CPU
{B153ED12-2028-49A9-AD7F-9D67DA0ECA32}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B153ED12-2028-49A9-AD7F-9D67DA0ECA32}.Release|Any CPU.Build.0 = Release|Any CPU
{B153ED12-2028-49A9-AD7F-9D67DA0ECA32}.Release|x64.ActiveCfg = Release|Any CPU
{B153ED12-2028-49A9-AD7F-9D67DA0ECA32}.Release|x64.Build.0 = Release|Any CPU
{B153ED12-2028-49A9-AD7F-9D67DA0ECA32}.Release|x86.ActiveCfg = Release|Any CPU
{B153ED12-2028-49A9-AD7F-9D67DA0ECA32}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -195,6 +213,8 @@ 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}
{A5154519-2271-45E8-8761-816440870E40} = {13B3E651-BF79-4138-A73D-FD41F773E0F4}
{B153ED12-2028-49A9-AD7F-9D67DA0ECA32} = {A5154519-2271-45E8-8761-816440870E40}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {002655B1-E1E1-4F2A-8D53-C9CD55136AE2}
Expand Down
23 changes: 23 additions & 0 deletions src/ai/.x/help/chat.assistant.trace.get
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
CHAT ASSISTANT GET

The `ai chat assistant trace get` command retrieves the trace data from a specific request.

USAGE: ai chat assistant trace get [...]

GET
--request-id ID
--request-id ID --output-file FILEPATH
--request-id ID --dashboard true (Note: dashboard must be running to use this option)

EXAMPLE

ai chat assistant get trace --request-id 25abac2c-9949-481f-83dd-db06d2993e85

ai tool dashboard start
ai chat assistant get trace --request-id 25abac2c-9949-481f-83dd-db06d2993e85 --dashboard true

SEE ALSO

ai help chat examples
ai help chat assistant examples
ai help find topics chat assistant
11 changes: 11 additions & 0 deletions src/ai/.x/help/tool.dashboard
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
TOOL DASHBOARD

The 'ai tool dashboard' command controls the .NET Aspire Dashboard docker container.
NOTE: Make sure Docker is running prior to using the command.

USAGE: ai tool dashboard start
ai chat dashboard stop

SEE ALSO

ai help chat assistant get trace
19 changes: 10 additions & 9 deletions src/ai/ai-cli.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,16 @@
<PackageReference Include="Azure.AI.OpenAI" Version="2.0.0-beta.2" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\common\common.csproj" />
<ProjectReference Include="..\extensions\helper_functions_extension\helper_functions_extension.csproj" />
<ProjectReference Include="..\extensions\speech_extension\speech-extension.csproj" />
<ProjectReference Include="..\extensions\template_extension\template_extension.csproj" />
<ProjectReference Include="..\extensions\testframework\YamlTestFramework.csproj" />
<ProjectReference Include="..\telemetry\aria\telemetry.aria.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\common\common.csproj" />
catherine-m-zhang marked this conversation as resolved.
Show resolved Hide resolved
<ProjectReference Include="..\extensions\helper_functions_extension\helper_functions_extension.csproj" />
<ProjectReference Include="..\extensions\otel_viewer_extension\otel_viewer_extension.csproj" />
<ProjectReference Include="..\extensions\speech_extension\speech-extension.csproj" />
<ProjectReference Include="..\extensions\template_extension\template_extension.csproj" />
<ProjectReference Include="..\extensions\testframework\YamlTestFramework.csproj" />
<ProjectReference Include="..\telemetry\aria\telemetry.aria.csproj" />
</ItemGroup>

<Import Project="BuildCommon.targets" />
<Import Project="BuildCommon.targets" />

</Project>
23 changes: 23 additions & 0 deletions src/ai/commands/chat_command.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
using OpenAI.Assistants;
using OpenAI.Files;
using OpenAI.VectorStores;
using Azure.AI.Details.Common.CLI.Extensions.Otel;

#pragma warning disable AOAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
Expand Down Expand Up @@ -91,6 +92,8 @@ private void DoCommand(string command)
case "chat.assistant.file.list": DoChatAssistantFileList().Wait(); break;
case "chat.assistant.file.delete": DoChatAssistantFileDelete().Wait(); break;

case "chat.assistant.trace.get": DoChatAssistantTraceGet().Wait(); break;

default:
_values.AddThrowError("WARNING:", $"'{command.Replace('.', ' ')}' NOT YET IMPLEMENTED!!");
break;
Expand Down Expand Up @@ -1581,6 +1584,26 @@ private async Task<bool> DoChatAssistantFileDelete()
if (!_quiet) Console.WriteLine($"{message} Done!");
return true;
}
private async Task<bool> DoChatAssistantTraceGet() {
catherine-m-zhang marked this conversation as resolved.
Show resolved Hide resolved
var requestId = _values["chat.trace.request.id"];
var dashboard = _values.GetOrDefault("chat.trace.dashboard", false);
var filePath = _values.GetOrDefault("chat.trace.output.file", "");

if (string.IsNullOrEmpty(requestId))
{
_values.AddThrowError("ERROR:", $"Retrieving trace; requires request id.");
}
Console.WriteLine("Attempting to fetch trace data...");
var data = await OtelData.GetTrace(requestId);
Console.WriteLine(data);
if (!string.IsNullOrEmpty(filePath)) {
await OtelData.WriteDataToFile(data, filePath);
}
if (dashboard) {
await OtelData.ExportToDashboard(data);
}
return true;
}

private List<string> ExpandFindFiles(List<string> files)
{
Expand Down
9 changes: 9 additions & 0 deletions src/ai/commands/parsers/chat_command_parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ private static readonly (string name, bool valuesRequired)[] _commands = {
("chat.assistant.file.list", false),
("chat.assistant.file", true),

("chat.assistant.trace.get", true),
catherine-m-zhang marked this conversation as resolved.
Show resolved Hide resolved

("chat.assistant", true),
("chat", true),
};
Expand Down Expand Up @@ -71,6 +73,7 @@ private static IEnumerable<INamedValueTokenParser> GetCommandParsers(ICommandVal
case "chat.assistant.file.upload": return _chatAssistantFileUploadCommandParsers;
case "chat.assistant.file.delete": return _chatAssistantFileDeleteCommandParsers;
case "chat.assistant.file.list": return _chatAssistantFileListCommandParsers;
case "chat.assistant.trace.get": return _chatAssistantTraceGetCommandParsers;
}

foreach (var command in _commands)
Expand Down Expand Up @@ -284,6 +287,12 @@ public CommonChatNamedValueTokenParsers() : base(
new CommonChatNamedValueTokenParsers(),
new Any1ValueNamedValueTokenParser(null, "chat.assistant.file.id", "0001"),
};
private static INamedValueTokenParser[] _chatAssistantTraceGetCommandParsers = {
new CommonChatNamedValueTokenParsers(),
new Any1ValueNamedValueTokenParser(null, "chat.trace.request.id", "0011;0101"),
new Any1ValueNamedValueTokenParser(null, "chat.trace.output.file", "0001"),
new TrueFalseNamedValueTokenParser("chat.trace.dashboard", "001"),
};

#endregion
}
Expand Down
12 changes: 9 additions & 3 deletions src/ai/commands/parsers/tool_command_parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,23 @@ public static bool ParseCommandValues(INamedValueTokens tokens, ICommandValues v
{
return ParseCommandValues("tool", GetCommandParsers(values), tokens, values);
}

private static readonly (string name, bool valuesRequired)[] _commands = {
("tool", true)
("tool.dashboard.start", false),
("tool.dashboard.stop", false),
("tool.dashboard", false),
("tool", true),

};

private static readonly string[] _partialCommands = {
"tool"
};

private static IEnumerable<INamedValueTokenParser> GetCommandParsers(ICommandValues values)
{
var commandName = values.GetCommand();

foreach (var command in _commands)
{
if (commandName == command.name)
Expand Down Expand Up @@ -72,6 +77,7 @@ public CommonToolNamedValueTokenParsers() : base(

};


#endregion
}
}
10 changes: 9 additions & 1 deletion src/ai/commands/tool_command.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;

using Azure.AI.Details.Common.CLI.Extensions.Otel;
namespace Azure.AI.Details.Common.CLI
{
public class ToolCommand : Command
Expand All @@ -40,6 +40,12 @@ internal bool RunCommand()

return _values.GetOrDefault("passed", true);
}
private void StartDashboard() {
catherine-m-zhang marked this conversation as resolved.
Show resolved Hide resolved
Dashboard.StartDashboard();
}
private void StopDashboard() {
Dashboard.StopDashboard();
}

private bool RunToolCommand()
{
Expand All @@ -53,6 +59,8 @@ private void DoCommand(string command)

switch (command)
{
case "tool.dashboard.start": StartDashboard(); break;
case "tool.dashboard.stop": StopDashboard(); break;
default:
_values.AddThrowError("WARNING:", $"'{command.Replace('.', ' ')}' NOT YET IMPLEMENTED!!");
break;
Expand Down
5 changes: 4 additions & 1 deletion src/common/details/commands/parsers/command_parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public static bool DispatchParseCommand(INamedValueTokens tokens, ICommandValues

var parsed = Program.DispatchParseCommand(tokens, values);
if (parsed || values.DisplayHelpRequested()) return parsed;

var test = command.Split('.')[0];
catherine-m-zhang marked this conversation as resolved.
Show resolved Hide resolved
switch (command.Split('.')[0])
{
case "-?":
Expand Down Expand Up @@ -83,6 +83,9 @@ protected static bool ParseCommand(string commandName, IEnumerable<INamedValueTo

protected static bool ParseCommands(IEnumerable<(string commandName, bool valuesRequired)> commands, IEnumerable<string> partials, INamedValueTokens tokens, ICommandValues values, Func<ICommandValues, IEnumerable<INamedValueTokenParser>> parsers)
{
var one = ParseCommandName(commands, partials, tokens, values);
catherine-m-zhang marked this conversation as resolved.
Show resolved Hide resolved
var two = ParseCommandDefaults(values.GetCommand()!, parsers(values), tokens, values);
var three = ParseAllCommandValues(parsers(values), tokens, values);
return ParseCommandName(commands, partials, tokens, values) &&
ParseCommandDefaults(values.GetCommand()!, parsers(values), tokens, values) &&
ParseAllCommandValues(parsers(values), tokens, values);
Expand Down
52 changes: 52 additions & 0 deletions src/extensions/otel_viewer_extension/AnyValueConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenTelemetry.Proto.Common.V1;
using Azure.AI.Details.Common.CLI;

namespace Azure.AI.Details.Common.CLI.Extensions.Otel
{
public class AnyValueConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(AnyValue);
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject item = JObject.Load(reader);
var anyValue = new AnyValue();

// Check and set the string value
if (item["hasStringValue"]?.Value<bool>() == true)
{
anyValue.StringValue = item["stringValue"]?.Value<string>();
}
if (item["hasBoolValue"]?.Value<bool>() == true)
{
anyValue.BoolValue = (bool)item["boolValue"]?.Value<bool>();
}
if (item["hasIntValue"]?.Value<bool>() == true)
{
anyValue.IntValue = (int)item["intValue"]?.Value<int>();
}
if (item["hasDoubleValue"]?.Value<bool>() == true)
{
anyValue.DoubleValue = (double)item["doubleValue"]?.Value<double>();
}
return anyValue;
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}


}
76 changes: 76 additions & 0 deletions src/extensions/otel_viewer_extension/Dashboard.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using System;
using System.Diagnostics;
using Azure.AI.Details.Common.CLI;

namespace Azure.AI.Details.Common.CLI.Extensions.Otel
{
public class Dashboard
{
// Execute a command in the command prompt and return the output
private static string ExecuteCommand(string command)
{
ProcessStartInfo processStartInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
catherine-m-zhang marked this conversation as resolved.
Show resolved Hide resolved
Arguments = $"/c {command}",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
};

using (Process process = new Process())
{
process.StartInfo = processStartInfo;
process.Start();
process.WaitForExit();
return process.StandardOutput.ReadToEnd();
}
}
public static void StartDashboard()
{

// Commands for the terminal
string dockerStartCommand = "docker run --rm -it -p 18888:18888 -p 4317:18889 -d --name aspire-dashboard mcr.microsoft.com/dotnet/aspire-dashboard:8.0.0";
string dockerLogsCommand = "docker logs aspire-dashboard";

try
{
// Start the Docker container
string startResult = ExecuteCommand(dockerStartCommand);
Console.WriteLine(startResult);

// Optionally wait a bit before fetching logs if needed
System.Threading.Thread.Sleep(3000);

// Get logs from the Docker container
string logsResult = ExecuteCommand(dockerLogsCommand);
Console.WriteLine(logsResult);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred: " + ex.Message);
}
}
public static void StopDashboard()
{
string dockerStopCommand = "docker stop aspire-dashboard";
try
{
// Stop the Docker container
string stopResult = ExecuteCommand(dockerStopCommand);
Console.WriteLine("Docker Stop Command Output:");
Console.WriteLine(stopResult);
}
catch (Exception ex)
{
Console.WriteLine("An error occurred when stopping the dashboard: " + ex.Message);
}
}
public static bool IsRunning()
{
string checkCommand = "docker ps --filter \"name=aspire-dashboard\" --format \"{{.Names}}\"";
string result = ExecuteCommand(checkCommand);
return result.Contains("aspire-dashboard");
}
}
}
Loading