4using System.Collections.Generic;
6using System.Threading.Tasks;
20 public string filename;
24 public bool embeddingOnly;
25 public int embeddingLength;
26 public bool includeInBuild;
27 public int contextLength;
29 static List<string> embeddingOnlyArchs =
new List<string> {
"bert",
"nomic-bert",
"jina-bert-v2",
"t5",
"t5encoder",
"gemma-embedding" };
40 if (File.Exists(assetPath) &&
LLMUnitySetup.IsSubPath(assetPath, basePath))
44 return Path.GetFileName(path);
54 public ModelEntry(
string path,
bool lora =
false,
string label =
null,
string url =
null)
57 this.label = label ==
null ? Path.GetFileName(filename) : label;
61 includeInBuild =
true;
63 embeddingOnly =
false;
71 contextLength = reader.
GetIntField($
"{arch}.context_length");
72 embeddingLength = reader.
GetIntField($
"{arch}.embedding_length");
74 embeddingOnly = embeddingOnlyArchs.Contains(arch);
86 entry.path = entry.filename;
93 public class LLMManagerStore
95 public bool downloadOnStart;
96 public List<ModelEntry> modelEntries;
101 [DefaultExecutionOrder(-2)]
108 public static bool downloadOnStart =
false;
109 public static List<ModelEntry> modelEntries =
new List<ModelEntry>();
110 static List<LLM> llms =
new List<LLM>();
112 public static float downloadProgress = 1;
113 public static List<Action<float>> downloadProgressCallbacks =
new List<Action<float>>();
114 static Task<bool> SetupTask;
115 static readonly
object lockObject =
new object();
116 static long totalSize;
117 static long currFileSize;
118 static long completedSize;
126 downloadProgress = (completedSize + progress * currFileSize) / totalSize;
127 foreach (Action<float> downloadProgressCallback
in downloadProgressCallbacks) downloadProgressCallback?.Invoke(downloadProgress);
138 if (SetupTask ==
null) SetupTask =
SetupOnce();
152 List<StringPair> downloads =
new List<StringPair>();
153 foreach (
ModelEntry modelEntry
in modelEntries)
155 string target =
LLMUnitySetup.GetAssetPath(modelEntry.filename);
156 if (File.Exists(target))
continue;
158 if (!downloadOnStart ||
string.IsNullOrEmpty(modelEntry.url))
161 if (!File.Exists(target))
LLMUnitySetup.LogError($
"Model {modelEntry.filename} could not be found!");
165 target =
LLMUnitySetup.GetDownloadAssetPath(modelEntry.filename);
166 downloads.Add(
new StringPair { source = modelEntry.url, target = target });
169 if (downloads.Count == 0)
return true;
173 downloadProgress = 0;
178 Dictionary<string, long> fileSizes =
new Dictionary<string, long>();
179 foreach (StringPair pair
in downloads)
181 long size = client.GetURLFileSize(pair.source);
182 fileSizes[pair.source] = size;
186 foreach (StringPair pair
in downloads)
188 currFileSize = fileSizes[pair.source];
190 await
LLMUnitySetup.AndroidExtractFile(Path.GetFileName(pair.target));
191 completedSize += currFileSize;
194 completedSize = totalSize;
199 LLMUnitySetup.LogError($
"Error downloading the models: {ex.Message}");
212 string filename = Path.GetFileName(path);
216 if (entry.filename == filename || entry.path == fullPath)
return entry;
229 if (entry ==
null)
return "";
242 public static int Num(
bool lora)
247 if (entry.lora == lora) num++;
295 downloadOnStart = store.downloadOnStart;
296 modelEntries = store.modelEntries;
297 LLMUnitySetup.DebugMode = (
LLMUnitySetup.DebugModeType)store.debugMode;
301 static string LLMManagerPref =
"LLMManager";
303 [HideInInspector]
public static float modelProgress = 1;
304 [HideInInspector]
public static float loraProgress = 1;
306 [InitializeOnLoadMethod]
307 static void InitializeOnLoad()
319 int indexToInsert = modelEntries.Count;
322 if (modelEntries.Count > 0 && modelEntries[0].lora) indexToInsert = 0;
325 for (
int i = modelEntries.Count - 1; i >= 0; i--)
327 if (!modelEntries[i].lora)
329 indexToInsert = i + 1;
335 modelEntries.Insert(indexToInsert, entry);
337 return entry.filename;
348 public static string AddEntry(
string path,
bool lora =
false,
string label =
null,
string url =
null)
361 public static async Task<string>
Download(
string url,
bool lora =
false,
bool log =
false,
string label =
null)
365 if (entry.url == url)
367 if (log)
LLMUnitySetup.Log($
"Found existing entry for {url}");
368 return entry.filename;
372 string modelName = Path.GetFileName(url).Split(
"?")[0];
374 if (entryPath !=
null)
376 if (log)
LLMUnitySetup.Log($
"Found existing entry for {modelName}");
377 return entryPath.filename;
381 float preModelProgress = modelProgress;
382 float preLoraProgress = loraProgress;
398 modelProgress = preModelProgress;
399 loraProgress = preLoraProgress;
400 LLMUnitySetup.LogError($
"Error downloading the model from URL '{url}': " + ex.Message);
403 return AddEntry(modelPath, lora, label, url);
414 public static string Load(
string path,
bool lora =
false,
bool log =
false,
string label =
null)
419 if (log)
LLMUnitySetup.Log($
"Found existing entry for {entry.filename}");
420 return entry.filename;
432 public static async Task<string>
DownloadModel(
string url,
bool log =
false,
string label =
null)
434 return await
Download(url,
false, log, label);
444 public static async Task<string>
DownloadLora(
string url,
bool log =
false,
string label =
null)
446 return await
Download(url,
true, log, label);
456 public static string LoadModel(
string path,
bool log =
false,
string label =
null)
458 return Load(path,
false, log, label);
468 public static string LoadLora(
string path,
bool log =
false,
string label =
null)
470 return Load(path,
true, log, label);
478 public static void SetURL(
string filename,
string url)
490 if (entry ==
null)
return;
512 if (entry ==
null)
return;
513 entry.includeInBuild = includeInBuild;
523 downloadOnStart = value;
529 if (entry.url ==
null || entry.url ==
"") warn =
true;
531 if (warn)
LLMUnitySetup.LogWarning(
"Some models do not have a URL and will be copied in the build. To resolve this fill in the URL field in the expanded view of the LLM Model list.");
540 public static void Remove(
string filename)
551 if (entry ==
null)
return;
552 modelEntries.Remove(entry);
554 foreach (
LLM llm
in llms)
556 if (!entry.lora && llm.
model == entry.filename) llm.model =
"";
557 else if (entry.lora) llm.
RemoveLora(entry.filename);
567 modelProgress = progress;
576 loraProgress = progress;
584 string json = JsonUtility.ToJson(
new LLMManagerStore
586 modelEntries = modelEntries,
587 downloadOnStart = downloadOnStart,
589 PlayerPrefs.SetString(LLMManagerPref, json);
598 string pref = PlayerPrefs.GetString(LLMManagerPref);
599 if (pref ==
null || pref ==
"")
return;
600 LLMManagerStore store = JsonUtility.FromJson<LLMManagerStore>(pref);
601 downloadOnStart = store.downloadOnStart;
602 modelEntries = store.modelEntries;
610 List<ModelEntry> modelEntriesBuild =
new List<ModelEntry>();
611 foreach (
ModelEntry modelEntry
in modelEntries)
613 if (!modelEntry.includeInBuild)
continue;
616 string json = JsonUtility.ToJson(
new LLMManagerStore
618 modelEntries = modelEntriesBuild,
619 downloadOnStart = downloadOnStart,
629 public static void Build(Action<string, string> copyCallback)
633 foreach (
ModelEntry modelEntry
in modelEntries)
635 string target =
LLMUnitySetup.GetAssetPath(modelEntry.filename);
636 if (!modelEntry.includeInBuild || File.Exists(target))
continue;
637 if (!downloadOnStart ||
string.IsNullOrEmpty(modelEntry.url)) copyCallback(modelEntry.path, target);
Class implementing the GGUF reader.
int GetIntField(string key)
Allows to retrieve an integer GGUF field.
string GetStringField(string key)
Allows to retrieve a string GGUF field.
Class implementing the LLM model manager.
static void SaveToDisk()
Saves the model manager to disk for the build.
static void SetIncludeInBuild(ModelEntry entry, bool includeInBuild)
Sets whether to include a model to the build.
static void SetLoraProgress(float progress)
Sets the LORA download progress.
static void Unregister(LLM llm)
Removes a LLM from the model manager.
static async Task< string > Download(string url, bool lora=false, bool log=false, string label=null)
Downloads a model and adds a model entry to the model manager.
static string GetAssetPath(string filename)
Gets the asset path based on whether the application runs locally in the editor or in a build.
static int NumModels()
Returns the number of LLM models.
static ModelEntry Get(string path)
Gets the model entry for a model path.
static Task< bool > Setup()
Setup of the models.
static int Num(bool lora)
Returns the number of LLM/LORA models.
static void Register(LLM llm)
Registers a LLM to the model manager.
static void SetURL(string filename, string url)
Sets the URL for a model.
static void SetModelProgress(float progress)
Sets the LLM download progress.
static void Save()
Serialises and saves the model manager.
static string AddEntry(string path, bool lora=false, string label=null, string url=null)
Creates and adds a model entry to the model manager.
static void Load()
Deserialises and loads the model manager.
static void SetDownloadOnStart(bool value)
Sets whether to download files on start.
static void SetIncludeInBuild(string filename, bool includeInBuild)
Sets whether to include a model to the build.
static int NumLoras()
Returns the number of LORA models.
static async Task< string > DownloadModel(string url, bool log=false, string label=null)
Downloads a LLM model from disk and adds a model entry to the model manager.
static string LoadModel(string path, bool log=false, string label=null)
Loads a LLM model from disk and adds a model entry to the model manager.
static void Remove(string filename)
Removes a model from the model manager.
static void LoadFromDisk()
Loads the model manager from a file.
static void SetDownloadProgress(float progress)
Sets the model download progress in all registered callbacks.
static string Load(string path, bool lora=false, bool log=false, string label=null)
Loads a model from disk and adds a model entry to the model manager.
static string AddEntry(ModelEntry entry)
Adds a model entry to the model manager.
static async Task< bool > SetupOnce()
Task performing the setup of the models.
static async Task< string > DownloadLora(string url, bool log=false, string label=null)
Downloads a Lora model from disk and adds a model entry to the model manager.
static void Remove(ModelEntry entry)
Removes a model from the model manager.
static string LoadLora(string path, bool log=false, string label=null)
Loads a LORA model from disk and adds a model entry to the model manager.
static void Build(Action< string, string > copyCallback)
Saves the model manager to disk along with models that are not (or can't) be downloaded for the build...
static void SetURL(ModelEntry entry, string url)
Sets the URL for a model.
Class implementing helper functions for setup and process management.
static string LLMManagerPath
Path of file with build information for runtime.
static string modelDownloadPath
Model download path.
Unity MonoBehaviour component that manages a local LLM server instance. Handles model loading,...
void RemoveLora(string path)
Removes a specific LORA adapter.
string model
LLM model file path (.gguf format)
Class implementing a LLM model entry.
ModelEntry(string path, bool lora=false, string label=null, string url=null)
Constructs a LLM model entry.
static string GetFilenameOrRelativeAssetPath(string path)
Returns the relative asset path if it is in the AssetPath folder (StreamingAssets or persistentPath),...
ModelEntry OnlyRequiredFields()
Returns only the required fields for bundling the model in the build.
Class implementing a resumable Web client.