自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

跨平臺`ChatGpt` 客戶端

開發(fā) 前端
實現(xiàn)發(fā)送前需要將之前的最近五條數(shù)據(jù)得到跟隨當前數(shù)據(jù)一塊發(fā)送,為了讓其ChatGpt可以聯(lián)系上下文,這樣回復的內(nèi)容更準確,聊天的數(shù)據(jù)使用Sqlite本地存儲,為了輕量使用ORM采用FreeSql,界面仿制微信的百分之八十的還原度,基本上一直,而且源碼完全開源。

一款基于Avalonia?實現(xiàn)的跨平臺ChatGpt?客戶端 ,通過對接ChatGpt?官方提供的ChatGpt 3.5模型實現(xiàn)聊天對話

實現(xiàn)創(chuàng)建ChatGpt?的項目名稱 ,項目類型是Avalonia MVVM ,

添加項目需要使用的Nuget包

<ItemGroup>
<PackageReference Include="Avalonia" Version="11.0.0-preview5" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.0-preview5" />
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.0-preview5" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.0-preview5" />
<PackageReference Include="FreeSql.Provider.Sqlite" Version="3.2.690" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
<PackageReference Include="XamlNameReferenceGenerator" Version="1.6.1" />
<PackageReference Include="Avalonia.Svg.Skia" Version="11.0.0-preview5" />
</ItemGroup>

ViewLocator.cs代碼修改

using System;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using ChatGPT.ViewModels;

namespace ChatGPT;

public class ViewLocator : IDataTemplate
{
public Control? Build(object? data)
{
if (data is null)
return null;

var name = data.GetType().FullName!.Replace("ViewModel", "View");
var type = Type.GetType(name);

if (type != null)
{
return (Control)Activator.CreateInstance(type)!;
}

return new TextBlock { Text = name };
}

public bool Match(object? data)
{
return data is ViewModelBase;
}
}

創(chuàng)建MainApp.cs文件

using Microsoft.Extensions.DependencyInjection;

namespace ChatGPT;

public static class MainApp
{
private static IServiceProvider ServiceProvider;

public static ServiceCollection CreateServiceCollection()
{
return new ServiceCollection();
}

public static IServiceProvider Build(this IServiceCollection services)
{
return ServiceProvider = services.BuildServiceProvider();
}

public static T GetService<T>()
{
if (ServiceProvider is null)
{
throw new ArgumentNullException(nameof(ServiceProvider));
}
return ServiceProvider.GetService<T>();
}

public static IEnumerable<T> GetServices<T>()
{
if (ServiceProvider is null)
{
throw new ArgumentNullException(nameof(ServiceProvider));
}
return ServiceProvider.GetServices<T>();
}

public static object? GetService(Type type)
{
if (ServiceProvider is null)
{
throw new ArgumentNullException(nameof(ServiceProvider));
}
return ServiceProvider.GetService(type);
}
}

創(chuàng)建GlobalUsing.cs文件 全局引用

global using System.Reactive;
global using Avalonia;
global using Avalonia.Controls;
global using ChatGPT.ViewModels;
global using Avalonia;
global using Avalonia.Controls.ApplicationLifetimes;
global using Avalonia.Markup.Xaml;
global using ChatGPT.ViewModels;
global using ChatGPT.Views;
global using System;
global using System.Collections.Generic;
global using ReactiveUI;

修改App.axaml代碼文件

<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ChatGPT"
xmlns:converter="clr-namespace:ChatGPT.Converter"
RequestedThemeVariant="Light"
x:Class="ChatGPT.App">
<Application.Resources>
<converter:HeightConverter x:Key="HeightConverter" />
</Application.Resources>
<Application.DataTemplates>
<local:ViewLocator/>
</Application.DataTemplates>

<Application.Styles>
<FluentTheme DensityStyle="Compact"/>
</Application.Styles>

</Application>

修改App.axaml.cs代碼文件

using Avalonia.Platform;
using Avalonia.Svg.Skia;
using ChatGPT.Options;
using Microsoft.Extensions.DependencyInjection;

namespace ChatGPT;

public partial class App : Application
{
public override void Initialize()
{
GC.KeepAlive(typeof(SvgImageExtension).Assembly);
GC.KeepAlive(typeof(Avalonia.Svg.Skia.Svg).Assembly);

var services = MainApp.CreateServiceCollection();

services.AddHttpClient("chatGpt")
.ConfigureHttpClient(options =>
{
var chatGptOptions = MainApp.GetService<ChatGptOptions>();
if (!string.IsNullOrWhiteSpace(chatGptOptions?.Token))
{
options.DefaultRequestHeaders.Add("Authorization",
"Bearer " + chatGptOptions?.Token.TrimStart().TrimEnd());
}
});

services.AddSingleton<ChatGptOptions>(ChatGptOptions.NewChatGptOptions());

services.AddSingleton(new FreeSql.FreeSqlBuilder()
.UseConnectionString(FreeSql.DataType.Sqlite,
"Data Source=chatGpt.db;Pooling=true;Min Pool Size=1")
.UseAutoSyncStructure(true) //自動同步實體結構到數(shù)據(jù)庫
.Build());

services.Build();

AvaloniaXamlLoader.Load(this);
}

public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = new MainWindow
{
DataContext = new MainViewModel()
};
}

var notifyIcon = new TrayIcon();
notifyIcon.Menu ??= new NativeMenu();
notifyIcon.ToolTipText = "ChatGPT";

var assets = AvaloniaLocator.Current.GetService<IAssetLoader>();

notifyIcon.Icon = new WindowIcon(assets.Open(new Uri("avares://ChatGPT/Assets/chatgpt.ico")));
var exit = new NativeMenuItem()
{
Header = "退出ChatGPT"
};

exit.Click += (sender, args) => Environment.Exit(0);
notifyIcon.Menu.Add(exit);

base.OnFrameworkInitializationCompleted();
}
}

修改MainWindow.axaml文件

<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:ChatGPT.ViewModels"
xmlns:pages="clr-namespace:ChatGPT.Pages"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ChatGPT.Views.MainWindow"
ExtendClientAreaToDecorationsHint="True"
ExtendClientAreaChromeHints="NoChrome"
ExtendClientAreaTitleBarHeightHint="-1"
Height="{Binding Height}"
MinHeight="500"
MinWidth="800"
Width="1060"
Name="Main">

<Design.DataContext>
<viewModels:MainViewModel />
</Design.DataContext>

<StackPanel Name="StackPanel" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<WrapPanel Name="WrapPanel" VerticalAlignment="Stretch" Height="{Binding ElementName=StackPanel, Path=Height}">
<StackPanel MaxWidth="55" Width="55">
<DockPanel Background="#2E2E2E" Height="{Binding Height}">
<StackPanel DockPanel.Dock="Top">
<StackPanel Margin="0,32,0,0"></StackPanel>
<StackPanel Margin="8">
<Image Source="/Assets/avatar.png"></Image>
</StackPanel>
<StackPanel Name="ChatStackPanel" Margin="15">
<Image Source="/Assets/chat-1.png"></Image>
</StackPanel>
</StackPanel>

<StackPanel Margin="5" VerticalAlignment="Bottom" DockPanel.Dock="Bottom">
<StackPanel VerticalAlignment="Bottom" Name="FunctionStackPanel">
<Menu HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<MenuItem HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<MenuItem.Header>
<Image Margin="5" Height="20" Width="20" Source="/Assets/function.png"></Image>
</MenuItem.Header>
<MenuItem Click="Setting_OnClick" Name="Setting" Header="設置" />
</MenuItem>
</Menu>
</StackPanel>
</StackPanel>
</DockPanel>
</StackPanel>

<Border Width="250" MaxWidth="250" BorderBrush="#D3D3D3" BorderThickness="0,0,1,0">
<StackPanel>
<pages:ChatShowView Name="ChatShowView"/>
</StackPanel>
</Border>

<StackPanel>
<StackPanel Height="{Binding Height}" HorizontalAlignment="Center" VerticalAlignment="Center">
<pages:SendChat DataContext="{Binding SendChatViewModel}"></pages:SendChat>
</StackPanel>
</StackPanel>
</WrapPanel>
</StackPanel>
</Window>

修改MainWindow.axaml.cs文件

using Avalonia.Interactivity;
using ChatGPT.Pages;

namespace ChatGPT.Views;

public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();

var observer = Observer.Create<Rect>(rect =>
{
if (ViewModel is null) return;

ViewModel.SendChatViewModel.Height = (int)rect.Height;
ViewModel.SendChatViewModel.Width = (int)rect.Width - 305;
ViewModel.Height = (int)rect.Height;
ViewModel.SendChatViewModel.ShowChatPanelHeight =
(int)rect.Height - ViewModel.SendChatViewModel.SendPanelHeight - 60;
});

this.GetObservable(BoundsProperty).Subscribe(observer);

ChatShowView = this.Find<ChatShowView>(nameof(ChatShowView));

ChatShowView.OnClick += view =>
{
ViewModel.SendChatViewModel.ChatShow = view;
};
}

private MainViewModel ViewModel => DataContext as MainViewModel;

private void Setting_OnClick(object? sender, RoutedEventArgs e)
{
var setting = new Setting
{
DataContext = ViewModel.SettingViewModel
};
setting.Show();
}
}

提供部分代碼 所有源碼都是開源,鏈接防止最下面

效果圖

圖片

SendChat.axaml.cs中提供了請求ChatGpt 3.5的實現(xiàn)

using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
using Avalonia.Controls.Notifications;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
using ChatGPT.Model;
using Notification = Avalonia.Controls.Notifications.Notification;

namespace ChatGPT.Pages;

public partial class SendChat : UserControl
{
private readonly HttpClient http;

private WindowNotificationManager? _manager;

public SendChat()
{
http = MainApp.GetService<IHttpClientFactory>().CreateClient("chatGpt");
InitializeComponent();
DataContextChanged += async (sender, args) =>
{
if (DataContext is not SendChatViewModel model) return;
if (model.ChatShow != null)
{
var freeSql = MainApp.GetService<IFreeSql>();
try
{
var values = await freeSql.Select<ChatMessage>()
.Where(x => x.ChatShowKey == model.ChatShow.Key)
.OrderBy(x => x.CreatedTime)
.ToListAsync();

foreach (var value in values)
{
model.messages.Add(value);
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
else
{
model.ChatShowAction += async () =>
{
var freeSql = MainApp.GetService<IFreeSql>();

var values = await freeSql.Select<ChatMessage>()
.Where(x => x.Key == model.ChatShow.Key)
.OrderBy(x => x.CreatedTime)
.ToListAsync();

foreach (var value in values)
{
model.messages.Add(value);
}
};
}
};
}

private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}

protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
var topLevel = TopLevel.GetTopLevel(this);
_manager = new WindowNotificationManager(topLevel) { MaxItems = 3 };
}

private void Close_OnClick(object? sender, RoutedEventArgs e)
{
var window = TopLevel.GetTopLevel(this) as Window;
window.ShowInTaskbar = false;
window.WindowState = WindowState.Minimized;
}

private SendChatViewModel ViewModel => DataContext as SendChatViewModel;

private void Thumb_OnDragDelta(object? sender, VectorEventArgs e)
{
var thumb = (Thumb)sender;
var wrapPanel = (WrapPanel)thumb.Parent;
wrapPanel.Width += e.Vector.X;
wrapPanel.Height += e.Vector.Y;
}

private void SendBorder_OnPointerEntered(object? sender, PointerEventArgs e)
{
}

private async void SendMessage_OnClick(object? sender, RoutedEventArgs e)
{
await SendMessageAsync();
}

private void Minimize_OnClick(object? sender, RoutedEventArgs e)
{
var window = TopLevel.GetTopLevel(this) as Window;
window.WindowState = WindowState.Minimized;
}

private void Maximize_OnClick(object? sender, RoutedEventArgs e)
{
var window = TopLevel.GetTopLevel(this) as Window;
window.WindowState = window.WindowState switch
{
WindowState.Maximized => WindowState.Normal,
WindowState.Normal => WindowState.Maximized,
_ => window.WindowState
};
}

private async void SendTextBox_OnKeyDown(object? sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
await SendMessageAsync();
}
}

private async Task SendMessageAsync()
{
try
{
if (ViewModel?.ChatShow?.Key == null)
{
_manager?.Show(new Notification("提示", "請先選擇一個對話框!", NotificationType.Warning));
return;
}

// 獲取當前程序集 assets圖片
// var uri = new Uri("avares://ChatGPT/Assets/avatar.png");
// // 通過uri獲取Stream
// var bitmap = new Bitmap(AvaloniaLocator.Current.GetService<IAssetLoader>().Open(uri));

var model = new ChatMessage
{
ChatShowKey = ViewModel.ChatShow.Key,
// Avatar = bitmap,
Title = "token",
Content = ViewModel.Message,
CreatedTime = DateTime.Now,
IsChatGPT = false
};

// 添加到消息列表
ViewModel.messages.Add(model);

// 清空輸入框
ViewModel.Message = string.Empty;

// 獲取消息記錄用于AI聯(lián)系上下文分析 來自Token的代碼
var message = ViewModel.messages
.OrderByDescending(x => x.CreatedTime) // 拿到最近的5條消息
.Take(5)
.OrderBy(x => x.CreatedTime) // 按時間排序
.Select(x => x.IsChatGPT
? new
{
role = "assistant",
content = x.Content
}
: new
{
role = "user",
content = x.Content
}
)
.ToList();

// 請求ChatGpt 3.5最新模型 來自Token的代碼
var responseMessage = await http.PostAsJsonAsync("https://api.openai.com/v1/chat/completions", new
{
model = "gpt-3.5-turbo",
temperature = 0,
max_tokens = 2560,
user = "token",
messages = message
});

// 獲取返回的消息 來自Token的代碼
var response = await responseMessage.Content.ReadFromJsonAsync<GetChatGPTDto>();

// 獲取當前程序集 assets圖片
// uri = new Uri("avares://ChatGPT/Assets/chatgpt.ico");

var chatGptMessage = new ChatMessage
{
ChatShowKey = ViewModel.ChatShow.Key,
// Avatar = new Bitmap(AvaloniaLocator.Current.GetService<IAssetLoader>().Open(uri)),
Title = "ChatGPT",
Content = response.choices[0].message.content,
IsChatGPT = true,
CreatedTime = DateTime.Now
};
// 添加到消息列表 來自Token的代碼
ViewModel.messages.Add(chatGptMessage);

var freeSql = MainApp.GetService<IFreeSql>();
await freeSql
.Insert(model)
.ExecuteAffrowsAsync();

await freeSql
.Insert(chatGptMessage)
.ExecuteAffrowsAsync();
}
catch (Exception e)
{
// 異常處理
_manager?.Show(new Notification("提示", "在請求AI服務時出現(xiàn)錯誤!請聯(lián)系管理員!", NotificationType.Error));
}
}
}

實現(xiàn)發(fā)送前需要將之前的最近五條數(shù)據(jù)得到跟隨當前數(shù)據(jù)一塊發(fā)送,為了讓其ChatGpt可以聯(lián)系上下文,這樣回復的內(nèi)容更準確,聊天的數(shù)據(jù)使用Sqlite本地存儲,為了輕量使用ORM采用FreeSql,界面仿制微信的百分之八十的還原度,基本上一直,而且源碼完全開源。

來自token的分享

GitHub開源地址: https://github.com/239573049/ChatGpt.Desktop

責任編輯:武曉燕 來源: token的技術分享
相關推薦

2016-11-29 13:03:46

微信客戶端跨平臺組件

2009-12-25 15:12:01

WPF平臺

2009-04-22 18:42:13

Vmware虛擬化英特爾

2011-08-17 10:10:59

2021-09-22 15:46:29

虛擬桌面瘦客戶端胖客戶端

2010-08-01 16:20:29

Android

2011-07-07 13:21:56

UI設計

2010-05-31 10:11:32

瘦客戶端

2011-10-26 13:17:05

2011-03-02 14:36:24

Filezilla客戶端

2010-12-21 11:03:15

獲取客戶端證書

2011-03-24 13:00:31

配置nagios客戶端

2009-06-08 15:18:34

EJB遠程客戶端JVM

2011-03-21 14:53:36

Nagios監(jiān)控Linux

2009-03-04 10:27:50

客戶端組件桌面虛擬化Xendesktop

2011-04-06 14:24:20

Nagios監(jiān)控Linux

2013-05-09 09:33:59

2011-05-12 11:26:00

客戶端虛擬化平臺

2012-10-11 17:02:02

IBMdw

2012-11-28 11:05:42

IBMdW
點贊
收藏

51CTO技術棧公眾號