Files
YwxApp.AiChat/ViewModels/ShareOllamaObject.cs
2025-03-12 20:02:52 +08:00

298 lines
10 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using OllamaSharp;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
using System.Windows;
namespace YwxApp.AiChat.ViewModels
{
/// <summary>
/// 0、Current class:
/// </summary>
public class ShareOllamaObject
{
#region Field | Property | Collection | Command
#region Field
private bool _ollamaEnabled = false; //ollama connected state
private string _ollamaAppPath; //ollama app path.
private int recordIndex = 0; //current record index.
private string _currentPath; //current record;
private Chat chat; //build interactive chat model object.
private OllamaApiClient _ollama; //OllamaAPI object.
#endregion
#region Property
public string OllamaAppPath
{
get { return _ollamaAppPath; }
set { _ollamaAppPath = value; }
}
public bool OllamaEnabled
{
get { return _ollamaEnabled; }
set { _ollamaEnabled = value; }
}
public OllamaApiClient Ollama
{
get { return _ollama; }
set { _ollama = value; }
}
public Chat Chat
{
get { return chat; }
set { chat = value; }
}
public string CurrentPath
{
get => _currentPath;
}
public int RecordIndex
{
get => recordIndex;
set
{
recordIndex = value;
_currentPath = $"{Environment.CurrentDirectory}//Data//{DateTime.Today.ToString("yyyyMMdd")}" +
$"//{DateTime.Today.ToString("yyyyMMdd")}_{recordIndex}.txt";
}
}
#endregion
#region Collection
public ObservableCollection<string> ModelList { get; set; }
#endregion
#endregion
#region Constructor
public ShareOllamaObject()
{
RecordIndex = 0;
WriteDataToFileAsync("");
Init(OllamaAppPath, "llama3.2:9b");
}
#endregion
#region other method
/// <summary>
/// initialite method
/// </summary>
private void Init(string appPath, string modelName)
{
OllamaAppPath = appPath;
try
{
// 设置默认设备为GPU
Environment.SetEnvironmentVariable("OLLAMA_DEFAULT_DEVICE", "gpu");
//判断路径是否存在
if (OllamaAppPath == string.Empty || OllamaAppPath == null) OllamaAppPath = @"ollama app.exe";
//路径存在获取应用名
if (File.Exists(OllamaAppPath)) OllamaAppPath = Path.GetFileName(OllamaAppPath);
//获取环境Ollama环境变量用于找到 ollama app.exe
var filePath = FindExeInPath(OllamaAppPath);
//如果路径存在启动Ollama
if (File.Exists(filePath)) CheckStartProcess(OllamaAppPath);
//连接Ollama并设置初始模型
_ollama = new OllamaApiClient(new Uri("http://localhost:11434"));
//获取本地可用的模型列表
ModelList = (ObservableCollection<string>)GetModelList();
var tmepModelName = ModelList.FirstOrDefault(name => name.ToLower().Contains("llama3.2"));
if (tmepModelName != null) _ollama.SelectedModel = tmepModelName;
else if (ModelList.Count > 0) _ollama.SelectedModel = ModelList[ModelList.Count - 1];
if (ModelList.FirstOrDefault(name => name.Equals(modelName)) != null) _ollama.SelectedModel = modelName;
//Ollama服务启用成功
OllamaEnabled = true;
}
catch (Exception)
{
OllamaEnabled = false;
}
}
/// <summary>
/// update the model selected by Ollama
/// </summary>
public void UpdataSelectedModel(string model)
{
Ollama.SelectedModel = model;
OllamaEnabled = true;
}
/// <summary>
/// Start Ollama app and relevant server.
/// </summary>
public async void StartOllama(string appPath, string modelName)
{
Init(appPath, modelName); await Task.Delay(1);
}
/// <summary>
/// get model list
/// </summary>
public Collection<string> GetModelList()
{
var models = _ollama.ListLocalModelsAsync();
var modelList = new ObservableCollection<string>();
foreach (var model in models.Result)
{
modelList.Add(model.Name);
}
return modelList;
}
#endregion
#region starting or closeing method of Ollama(server).
/// <summary>
/// Finds whether the specified application name is configured in the system environment.
/// If it exists, return the full path, otherwise return null
/// </summary>
public static string FindExeInPath(string exeName)
{
// get environment variable "Path" value
var pathVariable = Environment.GetEnvironmentVariable("PATH");
// Split string
string[] paths = pathVariable.Split(Path.PathSeparator);
foreach (string path in paths)
{
string fullPath = Path.Combine(path, exeName);
if (File.Exists(fullPath))
{
return fullPath;
}
}
return null;
}
/// <summary>
///Startup program Specifies a program, enters a program name, and determines whether the program is running.
/// If it is running, exit directly, otherwise run the program according to the input path.
/// </summary>
public static void CheckStartProcess(string processPath)
{
string processName = Path.GetFileName(processPath);
CheckStartProcess(processName, processPath);
}
/// <summary>
/// Startup program Specifies a program, enters a program name, and determines whether the program is running.
/// If it is running, exit directly, otherwise run the program according to the input path.
/// </summary>
public static void CheckStartProcess(string processName, string processPath)
{
// Check whather the program is running
if (!IsProcessRunning(processName))
{
Console.WriteLine($"{processName} is not running. Starting the process...");
StartProcess(processPath);
}
else Console.WriteLine($"{processName} is already running.");
}
/// <summary>
/// Enter the program path to start the program
/// </summary>
public static void StartProcess(string processPath)
{
try
{
Process.Start(processPath);
Console.WriteLine("Process started successfully.");
}
catch (Exception ex)
{
Console.WriteLine($"Error starting process: {ex.Message}");
}
}
/// <summary>
/// Check whather the process is running
/// </summary>
public static bool IsProcessRunning(string processName)
{
Process[] processes = Process.GetProcessesByName(processName);
return processes.Length > 0;
}
/// <summary>
/// close the process with the specify name.
/// </summary>
/// <param name="processName"></param>
public static void CloseProcess(string processName)
{
try
{
foreach (var process in Process.GetProcessesByName(processName))
{
process.Kill();
process.WaitForExit();
Application.Current.Shutdown();
}
}
catch (Exception ex)
{
MessageBox.Show($"无法关闭【{processName}】进程: {ex.Message}");
}
}
/// <summary>
/// get current process name
/// </summary>
public static string GetProgramName()
{
Assembly assembly = Assembly.GetExecutingAssembly();
return assembly.GetName().Name;
}
#endregion
#region File save
/// <summary>
/// Save record
/// </summary>
public void WriteDataToFileAsync(string data, int retryCount = 5, int delayMilliseconds = 500)
{
//Get the directory where the file located.
string directoryPath = Path.GetDirectoryName(CurrentPath);
// if directory exists't ,create directory(include all must directory).
if (!string.IsNullOrEmpty(directoryPath) && !Directory.Exists(directoryPath))
{
Directory.CreateDirectory(directoryPath);
}
for (int i = 0; i < retryCount; i++)
{
try
{
using (FileStream fs = new FileStream(CurrentPath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
using (StreamWriter writer = new StreamWriter(fs, Encoding.UTF8))
{
writer.WriteAsync(data);
}
return; // successful writed exit the loop.
}
catch (IOException ex)
{
if (i == retryCount - 1)
{
throw; //If the maximum number of retries is reached , a exception is thrown
}
Task.Delay(delayMilliseconds); // Wait a while and try again
}
catch (Exception ex)
{
throw; //other exception is thrown
}
}
}
#endregion
}
}