Skip to content
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
2 changes: 1 addition & 1 deletion src/dotnet-openai/App.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ static CommandApp Create(IServiceCollection collection, [NotNull] out ITypeRegis
var configuration = services.GetRequiredService<IConfiguration>();
var store = services.GetRequiredService<ICredentialStore>();

var apikey = store.Get("https://api.openai.com", "_CURRENT_")?.Password
var apikey = store.Get(ThisAssembly.Constants.ServiceUri, "_CURRENT_")?.Password
?? configuration["OPENAI_API_KEY"]
?? "";

Expand Down
1 change: 1 addition & 0 deletions src/dotnet-openai/Auth/AuthAppExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public static ICommandApp UseAuth(this ICommandApp app)
{
config.AddBranch("auth", group =>
{
group.AddCommand<ListCommand>("list");
group.AddCommand<LoginCommand>("login");
group.AddCommand<LogoutCommand>("logout");
group.AddCommand<StatusCommand>("status");
Expand Down
69 changes: 69 additions & 0 deletions src/dotnet-openai/Auth/ListCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System.ComponentModel;
using GitCredentialManager;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Spectre.Console;
using Spectre.Console.Cli;

namespace Devlooped.OpenAI.Auth;

[Description("Lists projects that have been authenticated and can be used with the login command")]
[Service]
public class ListCommand(IAnsiConsole console, IConfiguration configuration, ICredentialStore store, CancellationTokenSource cts) : Command<ListCommand.ListSettings>
{
public override int Execute(CommandContext context, ListSettings settings)
{
var currentKey = store.Get(ThisAssembly.Constants.ServiceUri, "_CURRENT_")?.Password
?? configuration["OPENAI_API_KEY"]
?? "";

var projects = store
.GetAccounts(ThisAssembly.Constants.ServiceUri)
.Where(x => x != "_CURRENT_")
.Select(x => new { Project = x, Token = store.Get(ThisAssembly.Constants.ServiceUri, x)?.Password });

if (settings.Json)
{
if (settings.ShowToken)
return console.RenderJson(projects, settings, cts.Token);
else
return console.RenderJson(projects.Select(x => x.Project), settings, cts.Token);
}

// render as a table otherwise
var table = new Table()
.Border(TableBorder.Rounded)
.AddColumn("[lime]Project[/]");

if (settings.ShowToken)
{
table.AddColumn("[lime]Token[/]");
foreach (var project in projects)
{
table.AddRow([project.Token == currentKey ? $"[bold]{project.Project}[/]" : project.Project, project.Token ?? ""]);
}
}
else
{
foreach (var project in projects)
{
table.AddRow(project.Token == currentKey ? $"[bold]{project.Project}[/]" : project.Project);
}
}

if (table.Rows.Count == 0)
console.MarkupLine("[red]No projects have been authenticated yet.[/]");
else
console.Write(table);

return 0;
}

public class ListSettings : JsonCommandSettings
{
[Description("Display the auth token of each project")]
[DefaultValue(false)]
[CommandOption("--show-token")]
public bool ShowToken { get; set; }
}
}
6 changes: 3 additions & 3 deletions src/dotnet-openai/Auth/LoginCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class LoginCommand(IAnsiConsole console, ICredentialStore store) : Comman
{
public override int Execute(CommandContext context, LoginSettings settings)
{
var token = store.Get("https://api.openai.com", settings.Project)?.Password;
var token = store.Get(ThisAssembly.Constants.ServiceUri, settings.Project)?.Password;

if (settings.WithToken)
{
Expand All @@ -43,9 +43,9 @@ public override int Execute(CommandContext context, LoginSettings settings)
return -2;
}

store.AddOrUpdate("https://api.openai.com", settings.Project, token);
store.AddOrUpdate(ThisAssembly.Constants.ServiceUri, settings.Project, token);
// Last login sets the current one.
store.AddOrUpdate("https://api.openai.com", "_CURRENT_", token);
store.AddOrUpdate(ThisAssembly.Constants.ServiceUri, "_CURRENT_", token);

return 0;
}
Expand Down
4 changes: 2 additions & 2 deletions src/dotnet-openai/Auth/LogoutCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ public class LogoutCommand(ICredentialStore store, IAnsiConsole console) : Comma
{
public override int Execute(CommandContext context)
{
foreach (var account in store.GetAccounts("https://api.openai.com"))
foreach (var account in store.GetAccounts(ThisAssembly.Constants.ServiceUri))
{
store.Remove("https://api.openai.com", account);
store.Remove(ThisAssembly.Constants.ServiceUri, account);
if (account != "_CURRENT_")
console.MarkupLine($" :check_mark: Logged out {account}");
}
Expand Down
15 changes: 13 additions & 2 deletions src/dotnet-openai/Auth/StatusCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class StatusCommand(IAnsiConsole console, IConfiguration configuration, I
{
public override async Task<int> ExecuteAsync(CommandContext context, StatusSettings settings)
{
var apikey = store.Get("https://api.openai.com", "_CURRENT_")?.Password
var apikey = store.Get(ThisAssembly.Constants.ServiceUri, "_CURRENT_")?.Password
?? configuration["OPENAI_API_KEY"]
?? "";

Expand All @@ -30,7 +30,18 @@ public override async Task<int> ExecuteAsync(CommandContext context, StatusSetti
{
await client.GetOpenAIModelClient().GetModelsAsync();

console.MarkupLine($" :check_mark_button: Logged in to api.openai.com");
console.Markup($" :check_mark_button: Logged in to api.openai.com");
if (store.GetAccounts(ThisAssembly.Constants.ServiceUri)
.Where(x => store.Get(ThisAssembly.Constants.ServiceUri, x)?.Password == apikey)
.FirstOrDefault() is { } project)
{
console.MarkupLine($" ([bold]{project}[/])");
}
else
{
console.MarkupLine(" ([grey]OPENAI_API_KEY[/])");
}

if (settings.ShowToken)
console.MarkupLine($" :check_mark_button: Token: {apikey}");

Expand Down
2 changes: 1 addition & 1 deletion src/dotnet-openai/Auth/TokenCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class TokenCommand(IConfiguration configuration, ICredentialStore store,
{
public override int Execute(CommandContext context)
{
var apikey = store.Get("https://api.openai.com", "_CURRENT_")?.Password
var apikey = store.Get(ThisAssembly.Constants.ServiceUri, "_CURRENT_")?.Password
?? configuration["OPENAI_API_KEY"]
?? "";

Expand Down
2 changes: 2 additions & 0 deletions src/dotnet-openai/Docs/auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ OPTIONS:
-h, --help Prints help information

COMMANDS:
list Lists projects that have been authenticated and can be
used with the login command
login <project> Authenticate to OpenAI.

Supports API key autentication using the Git Credential
Expand Down
3 changes: 2 additions & 1 deletion src/dotnet-openai/dotnet-openai.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
Expand Down Expand Up @@ -51,6 +51,7 @@
<ProjectProperty Include="PackageId" />
<ProjectProperty Include="PackageVersion" />
<ProjectProperty Include="SLEET_FEED_URL" />
<Constant Include="ServiceUri" Value="https://api.openai.com/" />
</ItemGroup>

<ItemGroup>
Expand Down