using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using LangChain.Chains.LLM;
using LangChain.Memory;
using LangChain.Prompts;
using LangChain.Providers;
using LangChain.Providers.DeepSeek;
using LangChain.Providers.DeepSeek.Predefined;
using LangChain.Providers.OpenAI;
using LangChain.Providers.OpenAI.Predefined;
using LangChain.Schema;
using Markdig;
using Markdig.Wpf.ColorCode;
using tryAGI.OpenAI;
//using static LangChain.Chains.Chain;
namespace WPFUI.Test
{
public partial class ChatDialogueViewModel : ObservableObject
{
static readonly DeepSeekConfiguration config = new DeepSeekConfiguration()
{
ApiKey = "sk-3a3126167f1343228b1a5745bcd0bf01",
Endpoint = "https://api.deepseek.com",
ChatSettings = new() { UseStreaming = true }
};
private ScrollViewer scrollViewer;
///
/// 当前AI的回复
///
[ObservableProperty]
public partial Message? CurrentRespone { get; set; } = Message.Ai(string.Empty);
///
/// 发送给AI的消息,包括上下文记录
///
private Message? CurrentRequest { get; set; } = Message.Empty;
public MarkdownPipeline Pipeline { get; set; } = new MarkdownPipelineBuilder().UseAdvancedExtensions().UseColorCodeWpf().Build();
public ChatDialogueViewModel()
{
ChatHistory ??= new ObservableCollection();
}
///
/// 用户输入
///
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(SendCommand))]
public partial string UserInput { get; set; }
private bool CanSend()
{
return !string.IsNullOrEmpty(UserInput);
}
[RelayCommand]
private async void PromptChat()
{
try
{
var deepseekLLM = new DeepSeekChatModel(new DeepSeekProvider(config));
var prompt = new PromptTemplate(new PromptTemplateInput(
template: "Revit二次开发中,使用变量doc和uidoc两个变量,构造一个保证可以执行的C#代码块,添加相应注释,不需要方法签名和using命名空间,但使用时需要完整的命名空间。实现{需求}的功能", inputVariables: ["需求"]));
deepseekLLM.RequestSent += DeepseekLLM_RequestSent;
var chain = new LlmChain(new LlmChainInput(deepseekLLM, prompt));
var result = await chain.CallAsync(new ChainValues(new Dictionary
{
{ "需求", UserInput}
})).ConfigureAwait(true);
// The result is an object with a `text` property.
var respones = result.Value["text"].ToString();
}
catch (Exception ex)
{
}
}
///
/// 历史聊天记录
///
public ObservableCollection ChatHistory { get; set; }
[RelayCommand(CanExecute = nameof(CanSend), IncludeCancelCommand = true)]
private async Task SendAsync(object obj, CancellationToken cancellationToken)
{
try
{
if (obj is ScrollViewer scroll)
{
scrollViewer = scroll;
}
ChatHistory.Add(Message.Human(UserInput));
//UserInput.Content=string.Empty;
#region DeepSeek
var deepseekLLM = new DeepSeekChatModel(new DeepSeekProvider(config));
deepseekLLM.ResponseReceived += DeepseekLLM_ResponseReceived;
deepseekLLM.DeltaReceived += DeepseekLLM_DeltaReceived;
//deepseekLLM.RequestSent += DeepseekLLM_RequestSent;
CurrentRequest += Message.Human(UserInput);
UserInput = string.Empty;
/*var result = */
await deepseekLLM.GenerateAsync(CurrentRequest, cancellationToken: cancellationToken);
#endregion
// Since the LLMChain is a single-input, single-output chain, we can also call it with `run`.
// This takes in a string and returns the `text` property.
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private async static Task RunChainAsync()
{
try
{
var client = new OpenAiClient("sk-3a3126167f1343228b1a5745bcd0bf01");
OpenAiProvider provider = new OpenAiProvider(client);
var llm = new OpenAiLatestFastChatModel(provider);
var embeddingModel = new TextEmbeddingV3SmallModel(provider);
var prompt = new PromptTemplate(new PromptTemplateInput(
template: "Revit二次开发中,使用变量doc和uidoc两个变量,构造一个保证可以执行的C#代码块,添加相应注释,不需要方法签名和using命名空间,但使用时需要完整的命名空间。实现{需求}的功能", inputVariables: ["需求"]));
var chain = new LlmChain(new LlmChainInput(llm, prompt));
var result2 = await chain.RunAsync("彩色长筒靴");
Console.WriteLine(result2);
var chatPrompt = ChatPromptTemplate.FromPromptMessages([
SystemMessagePromptTemplate.FromTemplate(
"You are a helpful assistant that translates {input_language} to {output_language}."),
HumanMessagePromptTemplate.FromTemplate("{text}")
]);
var chainB = new LlmChain(new LlmChainInput(llm, chatPrompt)
{
Verbose = true
});
var resultB = await chainB.CallAsync(new ChainValues(new Dictionary(3)
{
{"input_language", "English"},
{"output_language", "French"},
{"text", "I love programming"},
}));
Console.WriteLine(resultB.Value["text"]);
}
catch (Exception ex)
{
}
}
private void DeepseekLLM_RequestSent(object sender, ChatRequest e)
{
Debug.WriteLine("-------------RequestSent-------------");
foreach (var mes in e.Messages)
{
Debug.WriteLine($"{mes}");
}
//Debug.WriteLine("-------------RequestSent-------------");
//Debug.WriteLine($"发送者{sender}");
//scrollViewer.Dispatcher.Invoke(() =>
//{
// ChatHistory.Add(CurrentRespone);
//});
}
//接收完毕
private void DeepseekLLM_ResponseReceived(object sender, ChatResponse e)
{
//Debug.WriteLine("-------------ResponseReceived-------------");
Application.Current.Dispatcher.Invoke(() =>
{
//Debug.WriteLine($"发送者:{sender};使用量:{e.Usage}");
CurrentRequest += e.LastMessage;
CurrentRespone = Message.Ai(string.Empty);
//最后一条完整的消息
//Debug.WriteLine($"{ChatHistory}");
//ChatHistory.Add(e.LastMessage);
//Respones.Content += e.Content;
});
}
//partial void OnCurrentResponeChanged(Message? value)
//{
//}
//接收Delta
private void DeepseekLLM_DeltaReceived(object sender, ChatResponseDelta e)
{
if (string.IsNullOrEmpty(e.Content))
{
return;
}
scrollViewer.Dispatcher.Invoke(() =>
{
ChatHistory.Remove(CurrentRespone);
//Debug.WriteLine("-------------DeltaReceived-------------");
Debug.WriteLine($"{e.Content}");
CurrentRespone += Message.Ai(e.Content);
ChatHistory.Add(CurrentRespone);
Task.Delay(1);
//ChatHistory.
//判断滚动条是否在底部
if (scrollViewer.VerticalOffset == scrollViewer.ExtentHeight - scrollViewer.ViewportHeight)
{
scrollViewer?.ScrollToEnd();
}
//Respones.Content += e.Content;
});
}
[RelayCommand]
private void NewSession()
{
ChatHistory?.Clear();
CurrentRequest = Message.Empty;
}
}
}