feature: add per-repository setting for prefered OpenAI service

* If there is only one OpenAI service available, discard the setting of prefered OpenAI service. Instead, use it directly
* If there are multiple OpenAI service available, try to find the prefered one or show a context menu for users to choose the one they want to use

Signed-off-by: leo <longshuang@msn.cn>
This commit is contained in:
leo 2024-10-28 21:31:40 +08:00
parent 48725a7937
commit 498d2b54ae
No known key found for this signature in database
7 changed files with 90 additions and 4 deletions

View file

@ -130,6 +130,12 @@ namespace SourceGit.Models
set; set;
} = false; } = false;
public string PreferedOpenAIService
{
get;
set;
} = "---";
public void PushCommitMessage(string message) public void PushCommitMessage(string message)
{ {
var existIdx = CommitMessages.IndexOf(message); var existIdx = CommitMessages.IndexOf(message);

View file

@ -155,6 +155,9 @@
<x:String x:Key="Text.Configure.IssueTracker.RuleName" xml:space="preserve">Rule Name:</x:String> <x:String x:Key="Text.Configure.IssueTracker.RuleName" xml:space="preserve">Rule Name:</x:String>
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate" xml:space="preserve">Result URL:</x:String> <x:String x:Key="Text.Configure.IssueTracker.URLTemplate" xml:space="preserve">Result URL:</x:String>
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">Please use $1, $2 to access regex groups values.</x:String> <x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">Please use $1, $2 to access regex groups values.</x:String>
<x:String x:Key="Text.Configure.OpenAI" xml:space="preserve">OPEN AI</x:String>
<x:String x:Key="Text.Configure.OpenAI.Prefered" xml:space="preserve">Prefered Service:</x:String>
<x:String x:Key="Text.Configure.OpenAI.Prefered.Tip" xml:space="preserve">If the 'Prefered 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>
<x:String x:Key="Text.Configure.Proxy" xml:space="preserve">HTTP Proxy</x:String> <x:String x:Key="Text.Configure.Proxy" xml:space="preserve">HTTP Proxy</x:String>
<x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">HTTP proxy used by this repository</x:String> <x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">HTTP proxy used by this repository</x:String>
<x:String x:Key="Text.Configure.User" xml:space="preserve">User Name</x:String> <x:String x:Key="Text.Configure.User" xml:space="preserve">User Name</x:String>

View file

@ -158,6 +158,9 @@
<x:String x:Key="Text.Configure.IssueTracker.RuleName" xml:space="preserve">规则名 </x:String> <x:String x:Key="Text.Configure.IssueTracker.RuleName" xml:space="preserve">规则名 </x:String>
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate" xml:space="preserve">为ISSUE生成的URL链接 </x:String> <x:String x:Key="Text.Configure.IssueTracker.URLTemplate" xml:space="preserve">为ISSUE生成的URL链接 </x:String>
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">可在URL中使用$1$2等变量填入正则表达式匹配的内容</x:String> <x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">可在URL中使用$1$2等变量填入正则表达式匹配的内容</x:String>
<x:String x:Key="Text.Configure.OpenAI" xml:space="preserve">OPEN AI</x:String>
<x:String x:Key="Text.Configure.OpenAI.Prefered" xml:space="preserve">启用特定服务 </x:String>
<x:String x:Key="Text.Configure.OpenAI.Prefered.Tip" xml:space="preserve">当【启用特定服务】被设置时SourceGit将在本仓库中仅使用该服务。否则将弹出可用的OpenAI服务列表供用户选择。</x:String>
<x:String x:Key="Text.Configure.Proxy" xml:space="preserve">HTTP代理</x:String> <x:String x:Key="Text.Configure.Proxy" xml:space="preserve">HTTP代理</x:String>
<x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">HTTP网络代理</x:String> <x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">HTTP网络代理</x:String>
<x:String x:Key="Text.Configure.User" xml:space="preserve">用户名</x:String> <x:String x:Key="Text.Configure.User" xml:space="preserve">用户名</x:String>

View file

@ -158,6 +158,9 @@
<x:String x:Key="Text.Configure.IssueTracker.RuleName" xml:space="preserve">規則名稱:</x:String> <x:String x:Key="Text.Configure.IssueTracker.RuleName" xml:space="preserve">規則名稱:</x:String>
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate" xml:space="preserve">為 Issue 產生的網址連結:</x:String> <x:String x:Key="Text.Configure.IssueTracker.URLTemplate" xml:space="preserve">為 Issue 產生的網址連結:</x:String>
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">可在網址中使用 $1、$2 等變數填入正則表示式相符的內容</x:String> <x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">可在網址中使用 $1、$2 等變數填入正則表示式相符的內容</x:String>
<x:String x:Key="Text.Configure.OpenAI" xml:space="preserve">OPEN AI</x:String>
<x:String x:Key="Text.Configure.OpenAI.Prefered" xml:space="preserve">启用特定服务 </x:String>
<x:String x:Key="Text.Configure.OpenAI.Prefered.Tip" xml:space="preserve">当【启用特定服务】被设置时SourceGit将在本仓库中仅使用该服务。否则将弹出可用的OpenAI服务列表供用户选择。</x:String>
<x:String x:Key="Text.Configure.Proxy" xml:space="preserve">HTTP 代理</x:String> <x:String x:Key="Text.Configure.Proxy" xml:space="preserve">HTTP 代理</x:String>
<x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">HTTP 網路代理</x:String> <x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">HTTP 網路代理</x:String>
<x:String x:Key="Text.Configure.User" xml:space="preserve">使用者名稱</x:String> <x:String x:Key="Text.Configure.User" xml:space="preserve">使用者名稱</x:String>

View file

@ -1,4 +1,5 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using Avalonia.Collections; using Avalonia.Collections;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
@ -108,6 +109,18 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _selectedIssueTrackerRule, value); set => SetProperty(ref _selectedIssueTrackerRule, value);
} }
public List<string> AvailableOpenAIServices
{
get;
private set;
}
public string PreferedOpenAIService
{
get => _repo.Settings.PreferedOpenAIService;
set => _repo.Settings.PreferedOpenAIService = value;
}
public RepositoryConfigure(Repository repo) public RepositoryConfigure(Repository repo)
{ {
_repo = repo; _repo = repo;
@ -116,6 +129,13 @@ namespace SourceGit.ViewModels
foreach (var remote in _repo.Remotes) foreach (var remote in _repo.Remotes)
Remotes.Add(remote.Name); Remotes.Add(remote.Name);
AvailableOpenAIServices = new List<string>() { "---" };
foreach (var service in Preference.Instance.OpenAIServices)
AvailableOpenAIServices.Add(service.Name);
if (AvailableOpenAIServices.IndexOf(PreferedOpenAIService) == -1)
PreferedOpenAIService = "---";
_cached = new Commands.Config(repo.FullPath).ListAll(); _cached = new Commands.Config(repo.FullPath).ListAll();
if (_cached.TryGetValue("user.name", out var name)) if (_cached.TryGetValue("user.name", out var name))
UserName = name; UserName = name;

View file

@ -8,7 +8,6 @@ using Avalonia.Platform.Storage;
using Avalonia.Threading; using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using SourceGit.Models;
namespace SourceGit.ViewModels namespace SourceGit.ViewModels
{ {
@ -884,7 +883,7 @@ namespace SourceGit.ViewModels
var menu = new ContextMenu(); var menu = new ContextMenu();
var ai = null as MenuItem; var ai = null as MenuItem;
var services = Preference.Instance.OpenAIServices; var services = GetPreferedOpenAIServices();
if (services.Count > 0) if (services.Count > 0)
{ {
ai = new MenuItem(); ai = new MenuItem();
@ -1251,7 +1250,7 @@ namespace SourceGit.ViewModels
return null; return null;
} }
var services = Preference.Instance.OpenAIServices; var services = GetPreferedOpenAIServices();
if (services.Count == 0) if (services.Count == 0)
{ {
App.RaiseException(_repo.FullPath, "Bad configuration for OpenAI"); App.RaiseException(_repo.FullPath, "Bad configuration for OpenAI");
@ -1440,6 +1439,25 @@ namespace SourceGit.ViewModels
return false; return false;
} }
private IList<Models.OpenAIService> GetPreferedOpenAIServices()
{
var services = Preference.Instance.OpenAIServices;
if (services == null || services.Count == 0)
return [];
if (services.Count == 1)
return services;
var prefered = _repo.Settings.PreferedOpenAIService;
foreach (var service in services)
{
if (service.Name.Equals(prefered, StringComparison.Ordinal))
return [service];
}
return services;
}
private Repository _repo = null; private Repository _repo = null;
private bool _isLoadingData = false; private bool _isLoadingData = false;
private bool _isStaging = false; private bool _isStaging = false;

View file

@ -340,6 +340,39 @@
</ContentControl> </ContentControl>
</Grid> </Grid>
</TabItem> </TabItem>
<TabItem>
<TabItem.Header>
<TextBlock Classes="tab_header" Text="{DynamicResource Text.Configure.OpenAI}"/>
</TabItem.Header>
<Grid Margin="16,4,16,8" RowDefinitions="32,Auto" ColumnDefinitions="Auto,*">
<TextBlock Grid.Row="0" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0"
Text="{DynamicResource Text.Configure.OpenAI.Prefered}"/>
<ComboBox Grid.Row="0" Grid.Column="1"
Height="28" Padding="8,0"
VerticalAlignment="Center" HorizontalAlignment="Stretch"
ItemsSource="{Binding AvailableOpenAIServices}"
SelectedItem="{Binding PreferedOpenAIService, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Height="20" VerticalAlignment="Center">
<Path Width="12" Height="12" Data="{StaticResource Icons.AIAssist}" Fill="{DynamicResource Brush.FG1}"/>
<TextBlock Margin="6,0,0,0" Text="{Binding}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock Grid.Row="1" Grid.Column="1"
Margin="0,6,0,0"
Text="{DynamicResource Text.Configure.OpenAI.Prefered.Tip}"
TextWrapping="Wrap"
Foreground="{DynamicResource Brush.FG2}"/>
</Grid>
</TabItem>
</TabControl> </TabControl>
</Grid> </Grid>
</v:ChromelessWindow> </v:ChromelessWindow>