C# WPF 自制ChatGPT对话界面

By jerryxjr1220 at 2023-09-09 • 0人收藏 • 1255人看过

与ChatGPT玩《海龟汤》游戏


后面会放出详细制作过程 以及编译后程序

视频教程:https://www.bilibili.com/video/BV1Ez4y1j7TG/?spm_id_from=333.999.0.0&vd_source=0400f0a70c0250d73895963c7c937f75


WPFOpenAI.zip


14 个回复 | 最后更新于 2023-09-21
2023-09-10   #1

前几天在Github上找到了一个免费的ChatGPT的API接口,此API服务器是在国内的,所有访问速度比之前翻墙访问要快不少,最主要是它可以免费使用GPT3.5(GPT4是收费的)。

https://github.com/chatanywhere/gpt_api_free

捕获.PNG

免费申请到一个sk-key以后就可以访问了

捕获2.PNG

根据API文档,可以知道几个必要参数:

api网址:

'https://api.chatanywhere.com.cn/v1/chat/completions'

http的header

header = {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer sk-你申请的key'
}

json序列化的数据

data = {
    'model': 'gpt-3.5-turbo',
    'messages': [{'role': 'user', 'content': 'Hello!'}],
    'temperature': 0.7
}

其中model是选择的模型,temperature是话题新鲜度,messages中存放对话

有了这些信息就可以先在python中进行测试了

import requests
import json

data = {
    'model': 'gpt-3.5-turbo',
    'messages': [{'role': 'user', 'content': 'Hello!'}],
    'temperature': 0.7
}

header = {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer sk-你申请的key'
}

resp = requests.post(url='https://api.chatanywhere.com.cn/v1/chat/completions',
                     headers=header,
                     data=json.dumps(data))
res = json.loads(resp.text)['choices'][0]['message']['content']
print(res)

正确收到返回的响应后就可以在C#中尝试封装了。

2023-09-10   #2

在C# WPF中按照MVVM框架结构进行拆分:

架构名称用途
ModelMessage用来存放对话内容
ViewModelChatGPTAPI实现对话的模型
ViewMainWindow主界面

Model:

namespace WpfAppOpenAI.Models;

public class Message
{
    public string? role { get; set; }
    public string? content { get; set; }

    public string? showname { get; set; }
}


ViewModel:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using WpfAppOpenAI.Models;

namespace WpfAppOpenAI.ViewModels;

public partial class ChatGPTAPI : ObservableObject
{
    [ObservableProperty] private HttpClient client;

    [ObservableProperty] private Dictionary<string, object> data;

    [ObservableProperty] private ObservableCollection<Message> messages;

    [ObservableProperty] private string model;

    [ObservableProperty] private string prompt;

    [ObservableProperty] private double temperature;

    [ObservableProperty] private Uri url;

    public ChatGPTAPI(string? key, string? model, string? prop, double temperature = 0.7)
    {
        Client = new HttpClient();
        Url = new Uri("https://api.chatanywhere.com.cn/v1/chat/completions");
        Client.DefaultRequestHeaders.Add("Authorization", "Bearer " + key);
        Client.DefaultRequestHeaders.Add("ContentType", "application/json");
        Model = model ?? "gpt-3.5-turbo";
        Prompt = prop ?? "You are a helpful assistant. Try your best to answer the question.";
        Temperature = temperature;
        Messages = new ObservableCollection<Message>();
        Messages.Add(new Message { role = "user", content = Prompt, showname = "You: " });
        Data = new Dictionary<string, object>();
        Data["model"] = Model;
        Data["messages"] = Messages;
        Data["temperature"] = Temperature;
    }

    [RelayCommand]
    public async Task<string> ask(string question)
    {
        Messages.Add(new Message { role = "user", content = question, showname = "You: " });
        Data["messages"] = Messages;
        var js = JsonConvert.SerializeObject(Data);
        HttpContent content = new StringContent(js, Encoding.UTF8, "application/json");
        var resp = await Client.PostAsync(Url, content);
        var jobj = JObject.Parse(resp.Content.ReadAsStringAsync().Result);
        var answer = jobj["choices"].First()["message"]["content"].ToString();
        Messages.Add(new Message { role = "assistant", content = answer, showname = "GPT: " });
        Data["messages"] = Messages;
        return answer;
    }
}


View:

Xaml

<Window x:Class="WpfAppOpenAI.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        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:local="clr-namespace:WpfAppOpenAI"
        mc:Ignorable="d"
        d:DataContext="{d:DesignInstance Type=vm:ChatGPTAPI}"
        xmlns:fa="http://schemas.fontawesome.io/icons/"
        xmlns:hc="https://handyorg.github.io/handycontrol"
        xmlns:vm="clr-namespace:WpfAppOpenAI.ViewModels"
        WindowStyle="None" ResizeMode="NoResize"
        Title="MainWindow" Height="500" Width="800"
        FontFamily="JetBrains Mono" FontSize="14">

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="35" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <WrapPanel Grid.ColumnSpan="2" HorizontalAlignment="Left" VerticalAlignment="Center"
                   Margin="10,5,0,0" MouseDown="MainWindow_OnMouseDown">
            <fa:ImageAwesome Icon="Wechat" Width="20" Foreground="{StaticResource SuccessBrush}" />
            <TextBlock Text="OpenAI - ChatGPT" FontSize="20" Margin="10,0,0,0"
                       Foreground="{StaticResource PrimaryBrush}" />
        </WrapPanel>

        <hc:ButtonGroup Grid.Row="0" Grid.Column="1" HorizontalAlignment="Right" FontSize="20">
            <Button Content="-" Click="ButtonMinimize_OnClick"
                    Foreground="{StaticResource PrimaryBrush}" />
            <!--<Button Content="^" Click="ButtonMaximize_OnClick"/>-->
            <Button Content="X" Background="{StaticResource DangerBrush}"
                    Foreground="{StaticResource LightInfoBrush}" Click="ButtonClose_OnClick" />
        </hc:ButtonGroup>
        <StackPanel Grid.Row="1" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Top"
                    Margin="20,10,0,0">
            <TextBlock Style="{StaticResource TextBlockTitle}" Text="Settings" FontSize="14"
                       Foreground="{StaticResource DangerBrush}" Margin="0,0,0,10" />
            <Expander Header="sk Key" FontSize="24" Foreground="{StaticResource PrimaryBrush}" Margin="0,0,0,10">
                <hc:TextBox x:Name="tbKey" FontSize="10" Text="sk-你申请的key" />
            </Expander>
            <Expander Header="Model" FontSize="24" Foreground="{StaticResource PrimaryBrush}" Margin="0,0,0,10">
                <hc:ButtonGroup>
                    <RadioButton x:Name="rbGPT3" Content="GPT 3" FontSize="10" />
                    <RadioButton x:Name="rbGPT35" Content="GPT 3.5" IsChecked="True" FontSize="10" Padding="-2,0,-2,0" />
                    <RadioButton x:Name="rbGPT4" Content="GPT 4" FontSize="10" />
                </hc:ButtonGroup>
            </Expander>
            <WrapPanel Orientation="Vertical" Margin="0,0,0,10">
                <TextBlock Text="{Binding ElementName=sdTemperature, Path=Value, StringFormat=Temperature: {0:0.0}}"
                           FontSize="10" Foreground="{StaticResource PrimaryBrush}"
                           HorizontalAlignment="Left" VerticalAlignment="Center" />
                <Slider x:Name="sdTemperature" Minimum="0.1" Maximum="0.9" Value="0.7" Width="100"
                        IsHitTestVisible="True" />
            </WrapPanel>
            <WrapPanel Orientation="Vertical" Margin="0,0,0,10">
                <TextBlock Text="Prompt" FontSize="10" Foreground="{StaticResource PrimaryBrush}"
                           HorizontalAlignment="Left" VerticalAlignment="Center" />
                <TextBox x:Name="tbPrompt" Width="150" Height="220" FontSize="10" VerticalContentAlignment="Top"
                         MaxLines="12"
                         TextWrapping="Wrap" AcceptsReturn="True" Foreground="{StaticResource SecondaryTextBrush}"
                         Text="You are a helpful assistant. Try your best to answer the questions." />
            </WrapPanel>
            <Button Content="Change and Save" Style="{StaticResource ButtonPrimary}" Click="ButtonSave_OnClick" />
        </StackPanel>
        <StackPanel Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top">
            <!--<TextBox x:Name="tbOutput" Width="550" Height="400" ScrollViewer.VerticalScrollBarVisibility="Visible"
                         IsReadOnly="True" VerticalContentAlignment="Top" TextWrapping="Wrap"
                         Foreground="{StaticResource PrimaryBrush}" FontSize="14" />-->
            <ItemsControl x:Name="icOutput" ItemsSource="{Binding  Messages}" Padding="0,0,10,0" Height="400">
                <ItemsControl.Template>
                    <ControlTemplate TargetType="ItemsControl">
                        <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
                            <ItemsPresenter />
                        </ScrollViewer>
                    </ControlTemplate>
                </ItemsControl.Template>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <hc:TextBox Text="{Binding content}" IsReadOnly="True"
                                            hc:InfoElement.Title="{Binding showname}" 
                                            hc:InfoElement.TitlePlacement="Left"
                                            TextWrapping="Wrap" Style="{StaticResource TextBoxExtend}"
                                            Foreground="{StaticResource PrimaryBrush}"/>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
            <WrapPanel Orientation="Horizontal" Margin="10,10,0,0">
                <TextBox x:Name="tbQuestion" Width="530" Height="45" FontSize="13" VerticalAlignment="Top" MaxLines="5"
                         TextWrapping="Wrap" AcceptsReturn="True" Foreground="{StaticResource SecondaryTextBrush}" />

                <Button Style="{StaticResource ButtonPrimary}" Click="ButtonSend_OnClick">
                    <fa:FontAwesome Icon="Send" />
                </Button>
            </WrapPanel>

        </StackPanel>
    </Grid>
</Window>

CS

using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using HandyControl.Controls;
using WpfAppOpenAI.ViewModels;
using MessageBox = HandyControl.Controls.MessageBox;
using Window = System.Windows.Window;

namespace WpfAppOpenAI.Views;

/// <summary>
///     Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    private ChatGPTAPI api;

    public MainWindow()
    {
        InitializeComponent();
        var key = tbKey.Text;
        var model = string.Empty;
        if (rbGPT3.IsChecked == true)
            model = "gpt-3.5-turbo-0301";
        if (rbGPT35.IsChecked == true)
            model = "gpt-3.5-turbo";
        if (rbGPT4.IsChecked == true)
            model = "gpt-3.5-turbo-0613";
        var prompt = tbPrompt.Text;
        var temperature = Math.Round(sdTemperature.Value * 10) / 10;
        api = new ChatGPTAPI(key, model, prompt, temperature);
        DataContext = api;
    }

    private void ButtonMinimize_OnClick(object sender, RoutedEventArgs e)
    {
        WindowState = WindowState.Minimized;
    }

    // private void ButtonMaximize_OnClick(object sender, RoutedEventArgs e)
    // {
    //     if (this.WindowState == WindowState.Maximized)
    //         this.WindowState = WindowState.Normal;
    //     else
    //         this.WindowState = WindowState.Maximized;
    // }


    private void ButtonClose_OnClick(object sender, RoutedEventArgs e)
    {
        Application.Current.Shutdown();
    }

    private void MainWindow_OnMouseDown(object sender, MouseButtonEventArgs e)
    {
        DragMove();
    }


    private void ScrollToBottom()
    {
        // Scroll to the bottom of the ScrollViewer
        var scrollViewer = FindVisualChild<ScrollViewer>(icOutput);
        scrollViewer?.ScrollToEnd();
    }

    private static T FindVisualChild<T>(DependencyObject parent) where T : DependencyObject
    {
        for (var i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
        {
            var child = VisualTreeHelper.GetChild(parent, i);
            if (child is T result)
                return result;
            var descendant = FindVisualChild<T>(child);
            if (descendant != null)
                return descendant;
        }

        return null;
    }


    private async void ButtonSend_OnClick(object sender, RoutedEventArgs e)
    {
        try
        {
            var question = tbQuestion.Text;
            var ans = await api.ask(question);
            //tbOutput.Text += "You: " + question + "\r\n";
            //tbOutput.Text += "GPT: " + ans + "\r\n\r\n";
            ScrollToBottom();
        }
        catch
        {
            //tbOutput.Text += "Get Error! Try other models again!\r\n\r\n";
            MessageBox.Show("Got Error! Try again!");
        }
    }

    private void ButtonSave_OnClick(object sender, RoutedEventArgs e)
    {
        var key = tbKey.Text;
        var model = string.Empty;
        if (rbGPT3.IsChecked == true)
            model = "gpt-3.5-turbo-0301";
        if (rbGPT35.IsChecked == true)
            model = "gpt-3.5-turbo";
        if (rbGPT4.IsChecked == true)
            model = "gpt-3.5-turbo-0613";
        var prompt = tbPrompt.Text;
        var temperature = Math.Round(sdTemperature.Value * 10) / 10;
        api = new ChatGPTAPI(key, model, prompt, temperature);
        DataContext = api;
    }
}


PS:由于我使用的是免费api,所有只能用GPT 3.5。 GPT 4需要申请收费key。

2023-09-11   #3

有心了, 还有bilibili的视频

2023-09-14   #4

根据B站上一位up主的提示词工具,把ChatGPT升级成AutoGPT,会根据用户的目标分解任务并给出解决方案。

只需要把Prompt修改为:

你作为精通问题解决方案的X教授,你的职责是通过了解用户的目标和偏好,然后选择最合适该任务的专家代理来帮助用户达到他们的目标。

初始化:
我是一位${role}的X教授,我知道${context}。我会逐步推理,确定达到${goal}的最佳行动方案。我可以使用${tools}来协助这个过程。
我将通过以下步骤来帮你实现你的目标:${reasoned steps}。 当${completion}时,我的任务结束。 ${first step, question}
解决问题的步骤:
首先,X教授需要收集相关信息,并通过提问明确用户目标。
一旦用户确认,X教授会挑选专家代理,支持用户直到达到目标。
命令:
/start - X教授自我介绍并开始第一步
/save - X教授需要重申SMART目标,总结目前进展,并建议下一步
/reason - X教授和专家代理一起逐步推理,然后为用户提供继续前进的建议
/settings - X教授更新目标或代理
/new - 忘记以前的输入
规则:
- 每个输出都以一个问题或推荐的下一步结束
- 在第一次输出中列出你的命令,或者当用户询问时提供
- 作为X教授,在挑选新的专家代理前先询问
- 最后,记得用中文和我交流

尤其是对于一个庞大的问题,它会自动拆分成若干小任务目标,然后依次给出解决方案。

建议用该Prompt时,把Temperature尽量调小,这样对话基本就会严格按照我们制定的规则进行。

2023-09-14   #5

屏幕截图 2023-09-14 171718.png

2023-09-17   #6

继续优化,新增了语音播放功能,并且增加了对话保存功能

无标题.png

视频教程:

https://www.bilibili.com/video/BV1Fu4y1r7ig/?spm_id_from=333.999.0.0&vd_source=0400f0a70c0250d73895963c7c937f75

2023-09-19   #7

2023-09-20   #8

看你们乐的...

2023-09-21   #9

继续优化,针对不同使用场景增加不同Prompt提示词模板。

目前设了3个Prompt:

1、通用场景 General 2、专业问题解决场景 Professional 3、翻译场景 Translate

屏幕截图 2023-09-21 105844.png

2023-09-21   #10
//MainWindow.xaml.cs

using System;
using System.Globalization;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using Newtonsoft.Json.Linq;
using WpfAppOpenAI.Model;
using WpfAppOpenAI.ViewModel;
using MessageBox = HandyControl.Controls.MessageBox;
using ScrollViewer = HandyControl.Controls.ScrollViewer;
using Window = System.Windows.Window;
 
namespace WpfAppOpenAI.View;
 
/// <summary>
///     Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    private ChatGPTAPI api;
 
    public MainWindow()
    {
        InitializeComponent();
        tbPrompt.Text = """
                        You are a helpful assistant.
                        Try your best to answer the question or provide a possible solution.
                        """;
        var key = tbKey.Text;
        var model = string.Empty;
        if (rbGPT3.IsChecked == true)
            model = "gpt-3.5-turbo-0301";
        if (rbGPT35.IsChecked == true)
            model = "gpt-3.5-turbo";
        if (rbGPT4.IsChecked == true)
            model = "gpt-3.5-turbo-0613";
        var prompt = tbPrompt.Text;
        var temperature = Math.Round(sdTemperature.Value * 10) / 10;
        api = new ChatGPTAPI(key, model, prompt, temperature);
        DataContext = api;
    }
 
    private void ButtonMinimize_OnClick(object sender, RoutedEventArgs e)
    {
        WindowState = WindowState.Minimized;
    }
 
    // private void ButtonMaximize_OnClick(object sender, RoutedEventArgs e)
    // {
    //     if (this.WindowState == WindowState.Maximized)
    //         this.WindowState = WindowState.Normal;
    //     else
    //         this.WindowState = WindowState.Maximized;
    // }
 
 
    private void ButtonClose_OnClick(object sender, RoutedEventArgs e)
    {
        Application.Current.Shutdown();
    }
 
    private void MainWindow_OnMouseDown(object sender, MouseButtonEventArgs e)
    {
        DragMove();
    }
 
    private async void ButtonSend_OnClick(object sender, RoutedEventArgs e)
    {
        try
        {
            var question = tbQuestion.Text;
            var ans = await api.ask(question);
            //tbOutput.Text += "You: " + question + "\r\n";
            //tbOutput.Text += "GPT: " + ans + "\r\n\r\n";
        }
        catch
        {
            //tbOutput.Text += "Get Error! Try other models again!\r\n\r\n";
            MessageBox.Show("Got Error! Try again!", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
        }
    }
 
    private void ButtonSave_OnClick(object sender, RoutedEventArgs e)
    {
        var key = tbKey.Text;
        var model = string.Empty;
        if (rbGPT3.IsChecked == true)
            model = "gpt-3.5-turbo-0301";
        if (rbGPT35.IsChecked == true)
            model = "gpt-3.5-turbo";
        if (rbGPT4.IsChecked == true)
            model = "gpt-3.5-turbo-0613";
        var prompt = tbPrompt.Text;
        var temperature = Math.Round(sdTemperature.Value * 10) / 10;
        api = new ChatGPTAPI(key, model, prompt, temperature);
        DataContext = api;
    }


    private void LbHistory_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var selectedHistory = api.HistoryList[lbHistory.SelectedIndex];
        var historyFile = api.historyDictionary[selectedHistory];
        var jsonString = File.ReadAllText(historyFile, Encoding.UTF8);
        var jobj = JArray.Parse(jsonString);
        api.Messages.Clear();
        for (var i = 0; i < jobj.Count; i++)
        {
            
            if (jobj[i].SelectToken("role")!.ToString() == "user")
                api.Messages.Add(new YouMessage { role = "user", content = jobj[i].SelectToken("content")!.ToString() });
            else
                api.Messages.Add(new GptMessage { role = "assistant", content = jobj[i].SelectToken("content")!.ToString() });
            
        }
    }

    private void Rabtn0_OnClick(object sender, RoutedEventArgs e)
    {
        if (rabtn0.IsChecked==true)
        {
            tbPrompt.Text = """
                                    You are a helpful assistant.
                                    Try your best to answer the question or provide a possible solution.
                                    """;
                    var key = tbKey.Text;
                    var model = string.Empty;
                    if (rbGPT3.IsChecked == true)
                        model = "gpt-3.5-turbo-0301";
                    if (rbGPT35.IsChecked == true)
                        model = "gpt-3.5-turbo";
                    if (rbGPT4.IsChecked == true)
                        model = "gpt-3.5-turbo-0613";
                    var prompt = tbPrompt.Text;
                    var temperature = Math.Round(sdTemperature.Value * 10) / 10;
                    api = new ChatGPTAPI(key, model, prompt, temperature);
                    DataContext = api;
        }
        
    }

    private void Rabtn1_OnClick(object sender, RoutedEventArgs e)
    {
        if (rabtn1.IsChecked == true)
        {
            tbPrompt.Text = """
                            你作为问题解决方案的X教授,你的职责是通过了解用户的目标和偏好,然后选择最合适该任务的专家代理来帮助用户达到他们的目标。

                            初始化:
                            我是一位${role}的X教授,我知道${context}。我会逐步推理,确定达到${goal}的最佳行动方案。我可以使用${tools}来协助这个过程。
                            我将通过以下步骤来帮你实现你的目标:${reasoned steps}。 当${completion}时,我的任务结束。 ${first step, question}
                            解决问题的步骤:
                            首先,X教授需要收集相关信息,并通过提问明确用户目标。
                            一旦用户确认,X教授会挑选专家代理,支持用户直到达到目标。
                            命令:
                            /start - X教授自我介绍并开始第一步
                            /save - X教授需要重申SMART目标,总结目前进展,并建议下一步
                            /reason - X教授和专家代理一起逐步推理,然后为用户提供继续前进的建议
                            /settings - X教授更新目标或代理
                            /new - 忘记以前的输入
                            规则:
                            - 每个输出都以一个问题或推荐的下一步结束
                            - 在第一次输出中列出你的命令,或者当用户询问时提供
                            - 作为X教授,在挑选新的专家代理前先询问
                            - 最后,记得用中文和我交流
                            """;
            var key = tbKey.Text;
            var model = string.Empty;
            if (rbGPT3.IsChecked == true)
                model = "gpt-3.5-turbo-0301";
            if (rbGPT35.IsChecked == true)
                model = "gpt-3.5-turbo";
            if (rbGPT4.IsChecked == true)
                model = "gpt-3.5-turbo-0613";
            var prompt = tbPrompt.Text;
            var temperature = Math.Round(sdTemperature.Value * 10) / 10;
            api = new ChatGPTAPI(key, model, prompt, temperature);
            DataContext = api;
        }
    }

    private void Rabtn2_OnClick(object sender, RoutedEventArgs e)
    {
        if (rabtn2.IsChecked==true)
        {
            tbPrompt.Text = """
                            You are a professional translator.
                            Try your best to translate from Chinese to target language or from source language to Chinese.
                            Rules:
                            - I will put the content need to translate into "[" and "]" symbols;
                            - You should put the translated content into "[" and "]" symbols also;
                            """;
            var key = tbKey.Text;
            var model = string.Empty;
            if (rbGPT3.IsChecked == true)
                model = "gpt-3.5-turbo-0301";
            if (rbGPT35.IsChecked == true)
                model = "gpt-3.5-turbo";
            if (rbGPT4.IsChecked == true)
                model = "gpt-3.5-turbo-0613";
            var prompt = tbPrompt.Text;
            var temperature = Math.Round(sdTemperature.Value * 10) / 10;
            api = new ChatGPTAPI(key, model, prompt, temperature);
            DataContext = api;
        }
    }
}

public class ShortValueConvert : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Math.Round(((double)value) * 10) / 10;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
// MainViewWindow.cs

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using WpfAppOpenAI.Model;
using MessageBox = HandyControl.Controls.MessageBox;

namespace WpfAppOpenAI.ViewModel;

public partial class ChatGPTAPI : ObservableObject
{
    [ObservableProperty] private HttpClient client;
 
    [ObservableProperty] private Dictionary<string, object> data;
 
    [ObservableProperty] private ObservableCollection<Message> messages;
 
    [ObservableProperty] private string model;
 
    [ObservableProperty] private string prompt;
 
    [ObservableProperty] private double temperature;
 
    [ObservableProperty] private Uri url;

    [ObservableProperty] private BindingList<string> historyList;

    public Dictionary<string, string> historyDictionary;
 
    public ChatGPTAPI(string? key, string? model, string? prop, double temperature = 0.7)
    {
        Client = new HttpClient();
        Url = new Uri("https://api.chatanywhere.com.cn/v1/chat/completions");
        Client.DefaultRequestHeaders.Add("Authorization", "Bearer " + key);
        Client.DefaultRequestHeaders.Add("ContentType", "application/json");
        Model = model ?? "gpt-3.5-turbo";
        Prompt = prop ?? "You are a helpful assistant. Try your best to answer the question.";
        Temperature = temperature;
        Messages = new ObservableCollection<Message>();
        Messages.Add(new YouMessage { role = "user", content = Prompt });
        Data = new Dictionary<string, object>();
        Data["model"] = Model;
        Data["messages"] = Messages;
        Data["temperature"] = Temperature;
        historyDictionary = new Dictionary<string, string>();
        HistoryList = new BindingList<string>();
        string curdir = Directory.GetCurrentDirectory();
        var files = Directory.GetFiles(curdir + @"\log", "*.log", SearchOption.TopDirectoryOnly);
        foreach (var file in files)
        {
            var filename = Path.GetFileName(file);
            historyDictionary[filename] = file;
            HistoryList.Add(filename);
        }
        
    }
 
    [RelayCommand]
    public async Task<string> ask(string question)
    {
        Messages.Add(new YouMessage { role = "user", content = question });
        Data["messages"] = Messages;
        var js = JsonConvert.SerializeObject(Data);
        HttpContent content = new StringContent(js, Encoding.UTF8, "application/json");
        var resp = await Client.PostAsync(Url, content);
        var jobj = JObject.Parse(resp.Content.ReadAsStringAsync().Result);
        var answer = jobj["choices"].First()["message"]["content"].ToString();
        Messages.Add(new GptMessage { role = "assistant", content = answer });
        Data["messages"] = Messages;
        return answer;
    }

    [RelayCommand]
    public void SaveHistory()
    {
        string curdir = Directory.GetCurrentDirectory();
        string filename = DateTime.Now.ToString("yyMMddHHmmss") + ".log";
        string logpath = curdir + @"\log\" + filename;
        var jsonString = JsonConvert.SerializeObject(Messages);
        File.WriteAllText(logpath, jsonString, Encoding.UTF8);
        historyDictionary[filename] = logpath;
        HistoryList.Add(filename);
        MessageBox.Show("Dialogue Saved!", "Info", MessageBoxButton.OK, MessageBoxImage.Information);
    }
}


大佬,你这咋还两个账号切换着来呢?jerrxjr1220jerryxjr1220

2023-09-21   #12

回复#11 @鸿湖重工业株式会社 :

我在公司和在家都用这个名字,但显示就是2个不同账号,我也不知道为啥

应该是注册了两个账号吧? jerryjerr,一个有y,一个没有y

2023-09-21   #14

回复#13 @鸿湖重工业株式会社 :

好吧,你不说我都没注意

登录后方可回帖

登 录
信息栏
 私人小站

本站域名

ChengXu.XYZ

投诉联系:  popdes@126.com



快速上位机开发学习,本站主要记录了学习过程中遇到的问题和解决办法及上位机代码分享

这里主要专注于学习交流和经验分享.
纯私人站,当笔记本用的,学到哪写到哪.
如果侵权,联系 Popdes@126.com

友情链接
Aardio官方
Aardio资源网


才仁机械


网站地图SiteMap

Loading...