317 lines
11 KiB
C#
317 lines
11 KiB
C#
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 _remoteHost = "192.168.1.6"; //current record;
|
||
private string _remotePort = "11434"; //current record;
|
||
private string _currentPath;
|
||
private Chat chat; //build interactive chat model object.
|
||
private OllamaApiClient _ollama; //OllamaAPI object.
|
||
#endregion
|
||
|
||
#region Property
|
||
public string RemoteHost
|
||
{
|
||
get { return _remoteHost; }
|
||
set { _remoteHost = value; }
|
||
}
|
||
public string RemotePort
|
||
{
|
||
get { return _remotePort; }
|
||
set { _remotePort = value; }
|
||
}
|
||
|
||
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://192.168.1.6: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;
|
||
}
|
||
}
|
||
|
||
public void ConnectRemotelyOllamaServer() {
|
||
_ollama = new OllamaApiClient(new Uri("http://192.168.1.6:11434"));
|
||
//获取本地可用的模型列表
|
||
ModelList = (ObservableCollection<string>)GetModelList();
|
||
|
||
}
|
||
/// <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
|
||
}
|
||
} |