|
| 1 | +using System.ClientModel; |
1 | 2 | using System.CommandLine;
|
2 | 3 | using System.CommandLine.NamingConventionBinder;
|
3 | 4 | using System.Text;
|
| 5 | +using Azure.AI.OpenAI; |
4 | 6 | using Karambolo.PO;
|
5 | 7 | using OpenAI.Chat;
|
6 | 8 | using PlatformPlatform.DeveloperCli.Installation;
|
@@ -298,35 +300,61 @@ private sealed class OpenAiTranslationService
|
298 | 300 | private readonly ChatClient _client;
|
299 | 301 | public readonly Gpt4OUsageStatistics UsageStatistics = new();
|
300 | 302 |
|
301 |
| - private OpenAiTranslationService(string apiKey) |
| 303 | + private OpenAiTranslationService(ChatClient chatClient) |
302 | 304 | {
|
303 |
| - _client = new ChatClient(ModelName, apiKey); |
| 305 | + _client = chatClient; |
304 | 306 | }
|
305 | 307 |
|
306 | 308 | public static OpenAiTranslationService Create()
|
307 | 309 | {
|
308 |
| - var apiKey = GetApiKey(); |
309 |
| - return new OpenAiTranslationService(apiKey); |
| 310 | + var (apiKey, endpoint) = GetApiKeyAndEndpoint(); |
| 311 | + |
| 312 | + ChatClient chatClient; |
| 313 | + if (endpoint is null) |
| 314 | + { |
| 315 | + // Use standard OpenAI client for default endpoint |
| 316 | + chatClient = new ChatClient(ModelName, apiKey); |
| 317 | + } |
| 318 | + else |
| 319 | + { |
| 320 | + // Use Azure OpenAI client for custom endpoints |
| 321 | + var azureClient = new AzureOpenAIClient(new Uri(endpoint), new ApiKeyCredential(apiKey)); |
| 322 | + chatClient = azureClient.GetChatClient(ModelName); |
| 323 | + } |
| 324 | + |
| 325 | + return new OpenAiTranslationService(chatClient); |
310 | 326 | }
|
311 | 327 |
|
312 |
| - private static string GetApiKey() |
| 328 | + private static (string apiKey, string? endpoint) GetApiKeyAndEndpoint() |
313 | 329 | {
|
314 | 330 | const string apiKeySecretName = "OpenAIApiKey";
|
| 331 | + const string endpointSecretName = "OpenAIEndpoint"; |
| 332 | + |
315 | 333 | var apiKey = SecretHelper.GetSecret(apiKeySecretName);
|
316 |
| - if (!string.IsNullOrWhiteSpace(apiKey)) |
| 334 | + var endpoint = SecretHelper.GetSecret(endpointSecretName); |
| 335 | + |
| 336 | + if (apiKey is not null) |
317 | 337 | {
|
318 |
| - return apiKey; |
| 338 | + return (apiKey, endpoint); |
319 | 339 | }
|
320 | 340 |
|
321 |
| - AnsiConsole.MarkupLine("OpenAPI Key is missing."); |
322 |
| - apiKey = AnsiConsole.Ask<string>("[yellow]Please enter your OpenAPI Key.[/]"); |
323 |
| - if (!string.IsNullOrWhiteSpace(apiKey)) |
| 341 | + AnsiConsole.MarkupLine("OpenAI Key is missing."); |
| 342 | + apiKey = AnsiConsole.Prompt( |
| 343 | + new TextPrompt<string>("[yellow]Enter your OpenAI Key. Use a standard OpenAI key (sk-...) or an Azure OpenAI key ([a-z0-9]{32})[/]") |
| 344 | + .Validate(key => key.Length >= 32 ? ValidationResult.Success() : ValidationResult.Error("Open AI Keys starts with 'sk-' and must be at least 51 characters long and Azure Open AI key must be 32 characters long."))); |
| 345 | + |
| 346 | + if (!apiKey.StartsWith("sk-")) |
324 | 347 | {
|
325 |
| - SecretHelper.SetSecret(apiKeySecretName, apiKey); |
326 |
| - return apiKey; |
| 348 | + AnsiConsole.MarkupLine("[green]API Key is not a standard OpenAI key. Azure OpenAI key detected.[/]"); |
| 349 | + endpoint = AnsiConsole.Prompt( |
| 350 | + new TextPrompt<string>("[yellow]Please enter the Azure OpenAI endpoint URL (e.g. https://<your-resource-name>.openai.azure.com)[/]") |
| 351 | + .Validate(url => Uri.TryCreate(url, UriKind.Absolute, out _))); |
| 352 | + SecretHelper.SetSecret(endpointSecretName, endpoint); |
327 | 353 | }
|
328 | 354 |
|
329 |
| - throw new InvalidOperationException("Invalid OpenAPI Key provided."); |
| 355 | + SecretHelper.SetSecret(apiKeySecretName, apiKey); |
| 356 | + |
| 357 | + return (apiKey, endpoint); |
330 | 358 | }
|
331 | 359 |
|
332 | 360 | public async Task<POSingularEntry> Translate(
|
|
0 commit comments