Skip to content

Commit b38aebf

Browse files
committed
feat(ai): overhaul AI service and model management with per-repository model selection
- Refactor `AI.Service`: replace `AutoFetchAvailableModels` flag with explicit `AvailableModels` list; add `AddModel`, `RemoveModel`, `FetchModelsFromServer`, and `Clone` methods - Add `PreferredAIModel` to `RepositorySettings` for per-repository model override - Refactor `Repository.cs`: replace `GetPreferredOpenAIServices()` with `GetAllOpenAIServices()`, `GetOpenAIConfig()`, and `ResolveAIService()` for cleaner service/model resolution - Update `RepositoryConfigure`: add model selector dropdown alongside service selector with dynamic model list based on selected service - Update AI invocation in `CommitMessageToolBox` and `WorkingCopy` to show nested service→model context menus when no preferred service is configured - Revamp Preferences AI panel: replace text input + auto-fetch checkbox with list-based model management (add, remove, edit, fetch from server) - Add `FetchAIModels` dialog window for fetching and selecting models from AI server with loading indicator and checkbox list - Add reusable `TextInput` dialog window for simple text input prompts - Remove auto-fetch of available models on application startup (`UpdateAvailableAIModels` now no-op) - Remove `JsonSerialization.JsonIgnore` from `AvailableModels` and update `Service` model binding - Rename locale keys from `Text.Configure.OpenAI*` to `Text.Configure.AI*` with new keys for default service/model selection and model management UI - Update all 16 locale files (en_US, zh_CN, zh_TW, de_DE, el_GR, es_ES, fr_FR, he_IL, id_ID, it_IT, ja_JP, ko_KR, pt_BR, ru_RU, ta_IN, uk_UA) with new localization strings - Auto-close AI assistant window after applying a commit message
1 parent 9fea665 commit b38aebf

34 files changed

Lines changed: 797 additions & 186 deletions

src/AI/Service.cs

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
using System;
1+
using System;
22
using System.ClientModel;
33
using System.Collections.Generic;
4-
using System.Text.Json.Serialization;
54
using Azure.AI.OpenAI;
65
using CommunityToolkit.Mvvm.ComponentModel;
76
using OpenAI;
@@ -35,54 +34,71 @@ public bool ReadApiKeyFromEnv
3534
set;
3635
} = false;
3736

38-
[JsonIgnore]
3937
public List<string> AvailableModels
4038
{
41-
get;
42-
private set;
43-
} = [];
39+
get => _availableModels;
40+
set => SetProperty(ref _availableModels, value);
41+
}
4442

4543
public string Model
4644
{
4745
get => _model;
4846
set => SetProperty(ref _model, value);
4947
}
5048

51-
public bool AutoFetchAvailableModels
52-
{
53-
get => _autoFetchAvailableModels;
54-
set => SetProperty(ref _autoFetchAvailableModels, value);
55-
}
56-
5749
public string AdditionalPrompt
5850
{
5951
get;
6052
set;
6153
} = string.Empty;
6254

63-
public void FetchAvailableModels()
55+
public void AddModel(string model)
6456
{
65-
if (!_autoFetchAvailableModels)
57+
if (!_availableModels.Contains(model))
6658
{
67-
if (!string.IsNullOrEmpty(Model))
68-
AvailableModels = [Model];
69-
return;
59+
var newList = new List<string>(_availableModels) { model };
60+
AvailableModels = newList;
7061
}
62+
}
7163

64+
public void RemoveModel(string model)
65+
{
66+
if (_availableModels.Contains(model))
67+
{
68+
var newList = new List<string>(_availableModels);
69+
newList.Remove(model);
70+
AvailableModels = newList;
71+
}
72+
}
73+
74+
public List<string> FetchModelsFromServer()
75+
{
7276
var allModels = GetOpenAIClient().GetOpenAIModelClient().GetModels();
73-
AvailableModels = new List<string>();
77+
var result = new List<string>();
7478
foreach (var model in allModels.Value)
75-
AvailableModels.Add(model.Id);
76-
77-
if (AvailableModels.Count > 0 && (string.IsNullOrEmpty(Model) || !AvailableModels.Contains(Model)))
78-
Model = AvailableModels[0];
79+
result.Add(model.Id);
80+
return result;
7981
}
8082

8183
public ChatClient GetChatClient()
8284
{
8385
return !string.IsNullOrEmpty(Model) ? GetOpenAIClient().GetChatClient(Model) : null;
8486
}
8587

88+
public Service Clone()
89+
{
90+
return new Service
91+
{
92+
Name = Name,
93+
Server = Server,
94+
ApiKey = ApiKey,
95+
ReadApiKeyFromEnv = ReadApiKeyFromEnv,
96+
Model = Model,
97+
AdditionalPrompt = AdditionalPrompt,
98+
AvailableModels = new List<string>(AvailableModels),
99+
};
100+
}
101+
86102
private OpenAIClient GetOpenAIClient()
87103
{
88104
var credential = new ApiKeyCredential(ReadApiKeyFromEnv ? Environment.GetEnvironmentVariable(ApiKey) : ApiKey);
@@ -93,6 +109,6 @@ private OpenAIClient GetOpenAIClient()
93109

94110
private string _name = string.Empty;
95111
private string _model = string.Empty;
96-
private bool _autoFetchAvailableModels = true;
112+
private List<string> _availableModels = [];
97113
}
98114
}

src/App.axaml.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,6 @@ private void TryLaunchAsNormal(IClassicDesktopStyleApplicationLifetime desktop)
482482

483483
var pref = ViewModels.Preferences.Instance;
484484
pref.SetCanModify();
485-
pref.UpdateAvailableAIModels();
486485

487486
_launcher = new ViewModels.Launcher(startupRepo);
488487
desktop.MainWindow = new Views.Launcher() { DataContext = _launcher };

src/Models/RepositorySettings.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,13 @@ public string PreferredOpenAIService
4646
{
4747
get;
4848
set;
49-
} = "---";
49+
} = "";
50+
51+
public string PreferredAIModel
52+
{
53+
get;
54+
set;
55+
} = string.Empty;
5056

5157
public AvaloniaList<CommitTemplate> CommitTemplates
5258
{

src/Resources/Locales/de_DE.axaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -242,9 +242,9 @@ $1, $2, … Werte der Eingabe-Steuerelemente</x:String>
242242
<x:String x:Key="Text.Configure.IssueTracker.Share" xml:space="preserve">Diese Regel per .issuetracker-Datei teilen</x:String>
243243
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate" xml:space="preserve">Ergebnis-URL:</x:String>
244244
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">Verwende bitte $1, $2, um auf Regex-Gruppenwerte zuzugreifen.</x:String>
245-
<x:String x:Key="Text.Configure.OpenAI" xml:space="preserve">OPEN AI</x:String>
246-
<x:String x:Key="Text.Configure.OpenAI.Preferred" xml:space="preserve">Bevorzugter Dienst:</x:String>
247-
<x:String x:Key="Text.Configure.OpenAI.Preferred.Tip" xml:space="preserve">Der ausgewählte ‚Bevorzugte Dienst‘ wird nur in diesem Repository gesetzt und verwendet. Wenn keiner gesetzt ist und mehrere Dienste verfügbar sind, wird ein Kontextmenü zur Auswahl angezeigt.</x:String>
245+
<x:String x:Key="Text.Configure.AI" xml:space="preserve">OPEN AI</x:String>
246+
<x:String x:Key="Text.Configure.AI.DefaultService" xml:space="preserve">Bevorzugter Dienst:</x:String>
247+
<x:String x:Key="Text.Configure.AI.DefaultService.Tip" xml:space="preserve">Der ausgewählte ‚Bevorzugte Dienst‘ wird nur in diesem Repository gesetzt und verwendet. Wenn keiner gesetzt ist und mehrere Dienste verfügbar sind, wird ein Kontextmenü zur Auswahl angezeigt.</x:String>
248248
<x:String x:Key="Text.Configure.Proxy" xml:space="preserve">HTTP-Proxy</x:String>
249249
<x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">HTTP-Proxy für dieses Repository</x:String>
250250
<x:String x:Key="Text.Configure.User" xml:space="preserve">Benutzername</x:String>

src/Resources/Locales/el_GR.axaml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -264,9 +264,9 @@
264264
<x:String x:Key="Text.Configure.IssueTracker.Share" xml:space="preserve">Κοινή χρήση αυτού του κανόνα στο αρχείο .issuetracker</x:String>
265265
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate" xml:space="preserve">URL αποτελέσματος:</x:String>
266266
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">Χρησιμοποιήστε $1, $2 για πρόσβαση στις τιμές των ομάδων της κανονικής έκφρασης.</x:String>
267-
<x:String x:Key="Text.Configure.OpenAI" xml:space="preserve">AI</x:String>
268-
<x:String x:Key="Text.Configure.OpenAI.Preferred" xml:space="preserve">Προτιμώμενη υπηρεσία:</x:String>
269-
<x:String x:Key="Text.Configure.OpenAI.Preferred.Tip" xml:space="preserve">Αν οριστεί η «Προτιμώμενη υπηρεσία», το SourceGit θα τη χρησιμοποιεί μόνο σε αυτό το αποθετήριο. Διαφορετικά, αν υπάρχουν περισσότερες από μία διαθέσιμες υπηρεσίες, θα εμφανίζεται μενού για να επιλέξετε μία.</x:String>
267+
<x:String x:Key="Text.Configure.AI" xml:space="preserve">AI</x:String>
268+
<x:String x:Key="Text.Configure.AI.DefaultService" xml:space="preserve">Προτιμώμενη υπηρεσία:</x:String>
269+
<x:String x:Key="Text.Configure.AI.DefaultService.Tip" xml:space="preserve">Αν οριστεί η «Προτιμώμενη υπηρεσία», το SourceGit θα τη χρησιμοποιεί μόνο σε αυτό το αποθετήριο. Διαφορετικά, αν υπάρχουν περισσότερες από μία διαθέσιμες υπηρεσίες, θα εμφανίζεται μενού για να επιλέξετε μία.</x:String>
270270
<x:String x:Key="Text.Configure.Proxy" xml:space="preserve">HTTP Proxy</x:String>
271271
<x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">HTTP proxy που χρησιμοποιεί αυτό το αποθετήριο</x:String>
272272
<x:String x:Key="Text.Configure.User" xml:space="preserve">Όνομα χρήστη</x:String>
@@ -633,7 +633,6 @@
633633
<x:String x:Key="Text.Preferences.AI.AdditionalPrompt" xml:space="preserve">Επιπλέον prompt (χρησιμοποιήστε `-` για να απαριθμήσετε τις απαιτήσεις σας)</x:String>
634634
<x:String x:Key="Text.Preferences.AI.ApiKey" xml:space="preserve">Κλειδί API</x:String>
635635
<x:String x:Key="Text.Preferences.AI.Model" xml:space="preserve">Μοντέλο</x:String>
636-
<x:String x:Key="Text.Preferences.AI.Model.AutoFetchAvailableModels" xml:space="preserve">Αυτόματη ανάκτηση διαθέσιμων model-ids</x:String>
637636
<x:String x:Key="Text.Preferences.AI.Name" xml:space="preserve">Όνομα</x:String>
638637
<x:String x:Key="Text.Preferences.AI.ReadApiKeyFromEnv" xml:space="preserve">Η τιμή που εισήχθη είναι το όνομα για φόρτωση του κλειδιού API από το ENV</x:String>
639638
<x:String x:Key="Text.Preferences.AI.Server" xml:space="preserve">Διακομιστής</x:String>

src/Resources/Locales/en_US.axaml

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<x:String x:Key="Text.About.Menu" xml:space="preserve">About SourceGit</x:String>
44
<x:String x:Key="Text.About.ReleaseDate" xml:space="preserve">Release Date: {0}</x:String>
55
<x:String x:Key="Text.About.ReleaseNotes" xml:space="preserve">Release Notes</x:String>
6+
<x:String x:Key="Text.Add" xml:space="preserve">Add</x:String>
67
<x:String x:Key="Text.About.SubTitle" xml:space="preserve">Opensource &amp; Free Git GUI Client</x:String>
78
<x:String x:Key="Text.AddToIgnore" xml:space="preserve">Add File(s) To Ignore</x:String>
89
<x:String x:Key="Text.AddToIgnore.Pattern" xml:space="preserve">Pattern:</x:String>
@@ -269,9 +270,12 @@
269270
<x:String x:Key="Text.Configure.IssueTracker.Share" xml:space="preserve">Share this rule in .issuetracker file</x:String>
270271
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate" xml:space="preserve">Result URL:</x:String>
271272
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">Please use $1, $2 to access regex groups values.</x:String>
272-
<x:String x:Key="Text.Configure.OpenAI" xml:space="preserve">AI</x:String>
273-
<x:String x:Key="Text.Configure.OpenAI.Preferred" xml:space="preserve">Preferred Service:</x:String>
274-
<x:String x:Key="Text.Configure.OpenAI.Preferred.Tip" xml:space="preserve">If the 'Preferred Service' is set, SourceGit will only use it in this repository. Otherwise, if there is more than one service available, a context menu to choose one of them will be shown.</x:String>
273+
<x:String x:Key="Text.Configure.AI" xml:space="preserve">AI</x:String>
274+
<x:String x:Key="Text.Configure.AI.DefaultService" xml:space="preserve">Default Service:</x:String>
275+
<x:String x:Key="Text.Configure.AI.PreferredModel" xml:space="preserve">Default Model:</x:String>
276+
<x:String x:Key="Text.Configure.AI.DefaultService.Tip" xml:space="preserve">If set, SourceGit will use this service and model directly for AI commit message generation in this repository. Otherwise, a selection menu will be shown.</x:String>
277+
<x:String x:Key="Text.Configure.AI.DefaultService.None" xml:space="preserve">(None)</x:String>
278+
<x:String x:Key="Text.Configure.AI.PreferredModel.None" xml:space="preserve">(None)</x:String>
275279
<x:String x:Key="Text.Configure.Proxy" xml:space="preserve">HTTP Proxy</x:String>
276280
<x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">HTTP proxy used by this repository</x:String>
277281
<x:String x:Key="Text.Configure.User" xml:space="preserve">User Name</x:String>
@@ -655,10 +659,15 @@
655659
<x:String x:Key="Text.Preferences.AI.AdditionalPrompt" xml:space="preserve">Additional Prompt (Use `-` to list your requirements)</x:String>
656660
<x:String x:Key="Text.Preferences.AI.ApiKey" xml:space="preserve">API Key</x:String>
657661
<x:String x:Key="Text.Preferences.AI.Model" xml:space="preserve">Model</x:String>
658-
<x:String x:Key="Text.Preferences.AI.Model.AutoFetchAvailableModels" xml:space="preserve">Fetch available model-ids automatically</x:String>
662+
<x:String x:Key="Text.Preferences.AI.Model.AddModel" xml:space="preserve">Add Model</x:String>
663+
<x:String x:Key="Text.Preferences.AI.Model.FetchModels" xml:space="preserve">Fetch Models</x:String>
664+
<x:String x:Key="Text.Preferences.AI.Model.Fetching" xml:space="preserve">Fetching models...</x:String>
665+
<x:String x:Key="Text.Preferences.AI.Model.RemoveModel" xml:space="preserve">Remove Model</x:String>
666+
<x:String x:Key="Text.Preferences.AI.Model.SelectModels" xml:space="preserve">Select Models</x:String>
659667
<x:String x:Key="Text.Preferences.AI.Name" xml:space="preserve">Name</x:String>
660668
<x:String x:Key="Text.Preferences.AI.ReadApiKeyFromEnv" xml:space="preserve">Entered value is the name to load API key from ENV</x:String>
661669
<x:String x:Key="Text.Preferences.AI.Server" xml:space="preserve">Server</x:String>
670+
<x:String x:Key="Text.Preferences.AI.Services" xml:space="preserve">AI Services</x:String>
662671
<x:String x:Key="Text.Preferences.Appearance" xml:space="preserve">APPEARANCE</x:String>
663672
<x:String x:Key="Text.Preferences.Appearance.DefaultFont" xml:space="preserve">Default Font</x:String>
664673
<x:String x:Key="Text.Preferences.Appearance.EditorTabWidth" xml:space="preserve">Editor Tab Width</x:String>

src/Resources/Locales/es_ES.axaml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@
2121
<x:String x:Key="Text.AddWorktree.WhatToCheckout" xml:space="preserve">Qué Checkout:</x:String>
2222
<x:String x:Key="Text.AddWorktree.WhatToCheckout.CreateNew" xml:space="preserve">Crear Nueva Rama</x:String>
2323
<x:String x:Key="Text.AddWorktree.WhatToCheckout.Existing" xml:space="preserve">Rama Existente</x:String>
24-
<x:String x:Key="Text.AIAssistant" xml:space="preserve">Asistente OpenAI</x:String>
24+
<x:String x:Key="Text.AIAssistant" xml:space="preserve">Asistente AI</x:String>
2525
<x:String x:Key="Text.AIAssistant.Model" xml:space="preserve">Modelo</x:String>
2626
<x:String x:Key="Text.AIAssistant.Regen" xml:space="preserve">RE-GENERAR</x:String>
27-
<x:String x:Key="Text.AIAssistant.Tip" xml:space="preserve">Usar OpenAI para generar mensaje de commit</x:String>
27+
<x:String x:Key="Text.AIAssistant.Tip" xml:space="preserve">Usar AI para generar mensaje de commit</x:String>
2828
<x:String x:Key="Text.AIAssistant.Use" xml:space="preserve">Usar</x:String>
2929
<x:String x:Key="Text.App.Hide" xml:space="preserve">Ocultar SourceGit</x:String>
3030
<x:String x:Key="Text.App.HideOthers" xml:space="preserve">Ocultar Otros</x:String>
@@ -273,9 +273,9 @@
273273
<x:String x:Key="Text.Configure.IssueTracker.Share" xml:space="preserve">Compartir esta regla en el archivo .issuetracker</x:String>
274274
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate" xml:space="preserve">URL Resultante:</x:String>
275275
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">Por favor, use $1, $2 para acceder a los valores de los grupos regex.</x:String>
276-
<x:String x:Key="Text.Configure.OpenAI" xml:space="preserve">OPEN AI</x:String>
277-
<x:String x:Key="Text.Configure.OpenAI.Preferred" xml:space="preserve">Servicio Preferido:</x:String>
278-
<x:String x:Key="Text.Configure.OpenAI.Preferred.Tip" xml:space="preserve">Si el 'Servicio Preferido' está establecido, SourceGit sólo lo usará en este repositorio. De lo contrario, si hay más de un servicio disponible, se mostrará un menú de contexto para elegir uno.</x:String>
276+
<x:String x:Key="Text.Configure.AI" xml:space="preserve">OPEN AI</x:String>
277+
<x:String x:Key="Text.Configure.AI.DefaultService" xml:space="preserve">Servicio Preferido:</x:String>
278+
<x:String x:Key="Text.Configure.AI.DefaultService.Tip" xml:space="preserve">Si el 'Servicio Preferido' está establecido, SourceGit sólo lo usará en este repositorio. De lo contrario, si hay más de un servicio disponible, se mostrará un menú de contexto para elegir uno.</x:String>
279279
<x:String x:Key="Text.Configure.Proxy" xml:space="preserve">Proxy HTTP</x:String>
280280
<x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">Proxy HTTP utilizado por este repositorio</x:String>
281281
<x:String x:Key="Text.Configure.User" xml:space="preserve">Nombre del Usuario</x:String>
@@ -648,7 +648,6 @@
648648
<x:String x:Key="Text.Preferences.AI.AdditionalPrompt" xml:space="preserve">Prompt adicional (Usa `-` para listar tus requerimientos)</x:String>
649649
<x:String x:Key="Text.Preferences.AI.ApiKey" xml:space="preserve">Clave API</x:String>
650650
<x:String x:Key="Text.Preferences.AI.Model" xml:space="preserve">Modelo</x:String>
651-
<x:String x:Key="Text.Preferences.AI.Model.AutoFetchAvailableModels" xml:space="preserve">Traer automáticamente los model-ids disponibles</x:String>
652651
<x:String x:Key="Text.Preferences.AI.Name" xml:space="preserve">Nombre</x:String>
653652
<x:String x:Key="Text.Preferences.AI.ReadApiKeyFromEnv" xml:space="preserve">El valor ingresado es el nombre de la clave API a cargar desde ENV</x:String>
654653
<x:String x:Key="Text.Preferences.AI.Server" xml:space="preserve">Servidor</x:String>

src/Resources/Locales/fr_FR.axaml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -262,9 +262,9 @@
262262
<x:String x:Key="Text.Configure.IssueTracker.Share" xml:space="preserve">Partager cette règle dans le fichier .issuetracker</x:String>
263263
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate" xml:space="preserve">URL résultant:</x:String>
264264
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">Veuillez utiliser $1, $2 pour accéder aux valeurs des groupes regex.</x:String>
265-
<x:String x:Key="Text.Configure.OpenAI" xml:space="preserve">IA</x:String>
266-
<x:String x:Key="Text.Configure.OpenAI.Preferred" xml:space="preserve">Service préféré:</x:String>
267-
<x:String x:Key="Text.Configure.OpenAI.Preferred.Tip" xml:space="preserve">Si le 'Service préféré' est défini, SourceGit l'utilisera seulement dans ce repository. Sinon, si plus d'un service est disponible, un menu contextuel permettant de choisir l'un d'eux sera affiché.</x:String>
265+
<x:String x:Key="Text.Configure.AI" xml:space="preserve">IA</x:String>
266+
<x:String x:Key="Text.Configure.AI.DefaultService" xml:space="preserve">Service préféré:</x:String>
267+
<x:String x:Key="Text.Configure.AI.DefaultService.Tip" xml:space="preserve">Si le 'Service préféré' est défini, SourceGit l'utilisera seulement dans ce repository. Sinon, si plus d'un service est disponible, un menu contextuel permettant de choisir l'un d'eux sera affiché.</x:String>
268268
<x:String x:Key="Text.Configure.Proxy" xml:space="preserve">Proxy HTTP</x:String>
269269
<x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">Proxy HTTP utilisé par ce dépôt</x:String>
270270
<x:String x:Key="Text.Configure.User" xml:space="preserve">Nom d'utilisateur</x:String>
@@ -627,7 +627,6 @@
627627
<x:String x:Key="Text.Preferences.AI.AdditionalPrompt" xml:space="preserve">Prompt supplémentaire (utilisez `-` pour lister vos exigences)</x:String>
628628
<x:String x:Key="Text.Preferences.AI.ApiKey" xml:space="preserve">Clé d'API</x:String>
629629
<x:String x:Key="Text.Preferences.AI.Model" xml:space="preserve">Modèle</x:String>
630-
<x:String x:Key="Text.Preferences.AI.Model.AutoFetchAvailableModels" xml:space="preserve">Récupérer automatiquement les modèles disponibles</x:String>
631630
<x:String x:Key="Text.Preferences.AI.Name" xml:space="preserve">Nom</x:String>
632631
<x:String x:Key="Text.Preferences.AI.ReadApiKeyFromEnv" xml:space="preserve">La valeur saisie est le nom pour charger la clé API depuis l'ENV</x:String>
633632
<x:String x:Key="Text.Preferences.AI.Server" xml:space="preserve">Serveur</x:String>

0 commit comments

Comments
 (0)