添加项目文件。
This commit is contained in:
261
ViewModels/ChatMdViewModel.cs
Normal file
261
ViewModels/ChatMdViewModel.cs
Normal file
@@ -0,0 +1,261 @@
|
||||
using Markdig.Wpf;
|
||||
using OllamaSharp;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using YwxApp.AiChat.Commands;
|
||||
|
||||
namespace YwxApp.AiChat.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// 0、Current class:
|
||||
/// </summary>
|
||||
public class ChatMdViewModel : INotifyPropertyChanged
|
||||
{
|
||||
#region Field | Property | Collection | Command
|
||||
|
||||
#region Field
|
||||
private string? _inputText; //User input text.
|
||||
private Chat? chat; //Build interactive chat.
|
||||
private ShareOllamaObject _ollama; //share Ollama object.
|
||||
private CancellationTokenSource _cancellationTokenSource; //Termination chat Token
|
||||
|
||||
private bool _useExtensions = true; //whether enable Markdown extensions function.
|
||||
private string _markdownContent; //Markdown context.
|
||||
|
||||
private MarkdownViewer markdownViewer; //Markdwon viewer.
|
||||
private bool _isAutoScrolling = false; //whather enable scroll
|
||||
|
||||
private double _textWidth; // MarkdownViewer width
|
||||
#endregion
|
||||
|
||||
#region Property : Support property changed notify.
|
||||
//InputText:
|
||||
public string? InputText
|
||||
{
|
||||
get => _inputText;
|
||||
set
|
||||
{
|
||||
_inputText = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
public string MarkdownContent
|
||||
{
|
||||
get => _markdownContent;
|
||||
set
|
||||
{
|
||||
_markdownContent = value;
|
||||
// Notify property changed if needed
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public double TextWidth
|
||||
{
|
||||
get => _textWidth;
|
||||
set
|
||||
{
|
||||
_textWidth = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Collection:
|
||||
#endregion
|
||||
|
||||
#region Command: Builde Command: generate response command
|
||||
public ICommand? SubmitQuestionCommand { get; }
|
||||
//stop current chat
|
||||
public ICommand? StopCurrentChatCommand { get; }
|
||||
//new chat
|
||||
public ICommand? NewSessionCommand { get; }
|
||||
//scroll to MarkdownViewer end command
|
||||
public ICommand ScrollToEndCommand { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor : Initialize
|
||||
public ChatMdViewModel()
|
||||
{
|
||||
// initialize object
|
||||
markdownViewer = new MarkdownViewer();
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
//generate command
|
||||
SubmitQuestionCommand = new ParameterlessCommand(async () => OnSubmitQuestion());
|
||||
StopCurrentChatCommand = new ParameterlessCommand(OnStopCurrentChat);
|
||||
NewSessionCommand = new ParameterlessCommand(OnNewSessionCommand);
|
||||
|
||||
//markdown reletive command
|
||||
ScrollToEndCommand = new ScrollViewerCommand(OnScrollToEnd);
|
||||
|
||||
OnLoadRecord();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region other method
|
||||
|
||||
#region other
|
||||
//setting Ollama
|
||||
public void SetOllama(ShareOllamaObject ollama)
|
||||
{
|
||||
_ollama = ollama;
|
||||
}
|
||||
//check chat state
|
||||
private bool CheckChatState()
|
||||
{
|
||||
if (_ollama.Ollama == null || _ollama.OllamaEnabled == false)
|
||||
{
|
||||
MarkdownContent += "server not open...";
|
||||
return false;
|
||||
}
|
||||
if (_ollama.Ollama.SelectedModel == null)
|
||||
{
|
||||
MarkdownContent += "model not select...";
|
||||
return false;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(InputText))
|
||||
{
|
||||
MarkdownContent += "text is null ...";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//trigger sroll to end
|
||||
private void OnScrollToEnd(object parameter)
|
||||
{
|
||||
var scrollViewer = parameter as ScrollViewer;
|
||||
if (scrollViewer != null && _isAutoScrolling)
|
||||
{
|
||||
scrollViewer.ScrollToEnd();
|
||||
TextWidth = scrollViewer.Width;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Mardown command binding method
|
||||
//loaded history record
|
||||
public void OnLoadRecord()
|
||||
{
|
||||
OutText(File.ReadAllText($"{Environment.CurrentDirectory}//Data//" +
|
||||
$"{DateTime.Today.ToString("yyyyMMdd")}//{DateTime.Today.ToString("yyyyMMdd")}_0.txt"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region command method
|
||||
/// <summary>
|
||||
/// Submit question: Submit problem to the AI and get the output result
|
||||
/// </summary>
|
||||
private async void OnSubmitQuestion()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Checks whether the string is empty, empty, or contains only whitespace characters
|
||||
if (CheckChatState())
|
||||
{
|
||||
_isAutoScrolling = true; //enable auto scroll
|
||||
//ToggleExtensions();
|
||||
string input = InputText;
|
||||
InputText = string.Empty;
|
||||
string output = string.Empty;
|
||||
OutText($"{Environment.NewLine}");
|
||||
OutText($"## 【User】{Environment.NewLine}");
|
||||
OutText($">{input}{Environment.NewLine}");
|
||||
OutText($"## 【AI】{Environment.NewLine}");
|
||||
//
|
||||
output += ($"{Environment.NewLine}");
|
||||
output += ($"## 【User】{Environment.NewLine}");
|
||||
output += ($">{input}{Environment.NewLine}");
|
||||
output += ($"## 【AI】{Environment.NewLine}");
|
||||
|
||||
if (input.Equals("/clearContext"))
|
||||
{
|
||||
chat = new Chat(_ollama.Ollama);
|
||||
_ollama.RecordIndex++;
|
||||
return;
|
||||
}
|
||||
#region Start answer :Mode two => chat mode
|
||||
if (chat == null)
|
||||
{
|
||||
chat = new Chat(_ollama.Ollama);
|
||||
_ollama.RecordIndex++;
|
||||
}
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
await foreach (var answerToken in chat.SendAsync(input, _cancellationTokenSource.Token))
|
||||
{
|
||||
|
||||
OutText(answerToken);
|
||||
output += (answerToken);
|
||||
await Task.Delay(20);
|
||||
Debug.Print(answerToken);
|
||||
}
|
||||
OutText($"{Environment.NewLine}");
|
||||
_ollama.WriteDataToFileAsync(output);
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OutText($"Error: {ex.Message}{Environment.NewLine}");
|
||||
}
|
||||
_isAutoScrolling = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// New build chat.
|
||||
/// </summary>
|
||||
private void OnNewSessionCommand()
|
||||
{
|
||||
OnStopCurrentChat();
|
||||
if (chat != null)
|
||||
{
|
||||
chat.SendAsync("/clearContext");
|
||||
if (_ollama != null)
|
||||
chat = new Chat(_ollama.Ollama);
|
||||
}
|
||||
OutText($"{string.Empty}{Environment.NewLine}");
|
||||
}
|
||||
/// <summary>
|
||||
/// stop chat.
|
||||
/// </summary>
|
||||
private void OnStopCurrentChat()
|
||||
{
|
||||
_cancellationTokenSource?.Cancel();
|
||||
Task.Delay(100);
|
||||
OutText($"{string.Empty}{Environment.NewLine}");
|
||||
MarkdownContent = string.Empty;
|
||||
}
|
||||
/// <summary>
|
||||
/// output Text to Markdown.
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
public void OutText(string text)
|
||||
{
|
||||
MarkdownContent += text;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Method that trigger a property changed event.
|
||||
/// <summary>
|
||||
/// OnPropertyChanged:Trigger a property changed event.
|
||||
/// </summary>
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user