添加项目文件。

This commit is contained in:
yangwx
2025-03-12 20:02:52 +08:00
parent 4d34907fa7
commit 3ccd6d9a39
32 changed files with 1833 additions and 0 deletions

View 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>
/// OnPropertyChangedTrigger a property changed event.
/// </summary>
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}