4using System.Collections.Generic;
6using System.Threading.Tasks;
20 public string filename;
23 public string chatTemplate;
25 public bool embeddingOnly;
26 public int embeddingLength;
27 public bool includeInBuild;
28 public int contextLength;
30 static List<string> embeddingOnlyArchs =
new List<string> {
"bert",
"nomic-bert",
"jina-bert-v2",
"t5",
"t5encoder"};
41 if (File.Exists(assetPath) &&
LLMUnitySetup.IsSubPath(assetPath, basePath))
45 return Path.GetFileName(path);
55 public ModelEntry(
string path,
bool lora =
false,
string label =
null,
string url =
null)
58 this.label = label ==
null ? Path.GetFileName(filename) : label;
62 includeInBuild =
true;
65 embeddingOnly =
false;
73 contextLength = reader.
GetIntField($
"{arch}.context_length");
74 embeddingLength = reader.
GetIntField($
"{arch}.embedding_length");
76 embeddingOnly = embeddingOnlyArchs.Contains(arch);
89 entry.path = entry.filename;
96 public class LLMManagerStore
98 public bool downloadOnStart;
99 public List<ModelEntry> modelEntries;
103 [DefaultExecutionOrder(-2)]
110 public static bool downloadOnStart =
false;
111 public static List<ModelEntry> modelEntries =
new List<ModelEntry>();
112 static List<LLM> llms =
new List<LLM>();
114 public static float downloadProgress = 1;
115 public static List<Callback<float>> downloadProgressCallbacks =
new List<Callback<float>>();
116 static Task<bool> SetupTask;
117 static readonly
object lockObject =
new object();
118 static long totalSize;
119 static long currFileSize;
120 static long completedSize;
128 downloadProgress = (completedSize + progress * currFileSize) / totalSize;
129 foreach (Callback<float> downloadProgressCallback
in downloadProgressCallbacks) downloadProgressCallback?.Invoke(downloadProgress);
140 if (SetupTask ==
null) SetupTask =
SetupOnce();
154 List<StringPair> downloads =
new List<StringPair>();
155 foreach (
ModelEntry modelEntry
in modelEntries)
157 string target =
LLMUnitySetup.GetAssetPath(modelEntry.filename);
158 if (File.Exists(target))
continue;
160 if (!downloadOnStart ||
string.IsNullOrEmpty(modelEntry.url))
163 if (!File.Exists(target))
LLMUnitySetup.LogError($
"Model {modelEntry.filename} could not be found!");
167 target =
LLMUnitySetup.GetDownloadAssetPath(modelEntry.filename);
168 downloads.Add(
new StringPair {source = modelEntry.url, target = target});
171 if (downloads.Count == 0)
return true;
175 downloadProgress = 0;
180 Dictionary<string, long> fileSizes =
new Dictionary<string, long>();
181 foreach (StringPair pair
in downloads)
183 long size = client.GetURLFileSize(pair.source);
184 fileSizes[pair.source] = size;
188 foreach (StringPair pair
in downloads)
190 currFileSize = fileSizes[pair.source];
192 await
LLMUnitySetup.AndroidExtractFile(Path.GetFileName(pair.target));
193 completedSize += currFileSize;
196 completedSize = totalSize;
201 LLMUnitySetup.LogError($
"Error downloading the models: {ex.Message}");
212 public static void SetTemplate(
string filename,
string chatTemplate)
224 if (entry ==
null)
return;
225 entry.chatTemplate = chatTemplate;
226 foreach (
LLM llm
in llms)
228 if (llm !=
null && llm.
model == entry.filename) llm.
SetTemplate(chatTemplate);
242 string filename = Path.GetFileName(path);
246 if (entry.filename == filename || entry.path == fullPath)
return entry;
259 if (entry ==
null)
return "";
272 public static int Num(
bool lora)
277 if (entry.lora == lora) num++;
325 downloadOnStart = store.downloadOnStart;
326 modelEntries = store.modelEntries;
330 static string LLMManagerPref =
"LLMManager";
332 [HideInInspector]
public static float modelProgress = 1;
333 [HideInInspector]
public static float loraProgress = 1;
335 [InitializeOnLoadMethod]
336 static void InitializeOnLoad()
348 int indexToInsert = modelEntries.Count;
351 if (modelEntries.Count > 0 && modelEntries[0].lora) indexToInsert = 0;
354 for (
int i = modelEntries.Count - 1; i >= 0; i--)
356 if (!modelEntries[i].lora)
358 indexToInsert = i + 1;
364 modelEntries.Insert(indexToInsert, entry);
366 return entry.filename;
377 public static string AddEntry(
string path,
bool lora =
false,
string label =
null,
string url =
null)
390 public static async Task<string>
Download(
string url,
bool lora =
false,
bool log =
false,
string label =
null)
394 if (entry.url == url)
396 if (log)
LLMUnitySetup.Log($
"Found existing entry for {url}");
397 return entry.filename;
401 string modelName = Path.GetFileName(url).Split(
"?")[0];
403 if (entryPath !=
null)
405 if (log)
LLMUnitySetup.Log($
"Found existing entry for {modelName}");
406 return entryPath.filename;
410 float preModelProgress = modelProgress;
411 float preLoraProgress = loraProgress;
427 modelProgress = preModelProgress;
428 loraProgress = preLoraProgress;
429 LLMUnitySetup.LogError($
"Error downloading the model from URL '{url}': " + ex.Message);
432 return AddEntry(modelPath, lora, label, url);
443 public static string Load(
string path,
bool lora =
false,
bool log =
false,
string label =
null)
448 if (log)
LLMUnitySetup.Log($
"Found existing entry for {entry.filename}");
449 return entry.filename;
461 public static async Task<string>
DownloadModel(
string url,
bool log =
false,
string label =
null)
463 return await
Download(url,
false, log, label);
473 public static async Task<string>
DownloadLora(
string url,
bool log =
false,
string label =
null)
475 return await
Download(url,
true, log, label);
485 public static string LoadModel(
string path,
bool log =
false,
string label =
null)
487 return Load(path,
false, log, label);
497 public static string LoadLora(
string path,
bool log =
false,
string label =
null)
499 return Load(path,
true, log, label);
507 public static void SetURL(
string filename,
string url)
519 if (entry ==
null)
return;
541 if (entry ==
null)
return;
542 entry.includeInBuild = includeInBuild;
552 downloadOnStart = value;
558 if (entry.url ==
null || entry.url ==
"") warn =
true;
560 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.");
569 public static void Remove(
string filename)
580 if (entry ==
null)
return;
581 modelEntries.Remove(entry);
583 foreach (
LLM llm
in llms)
585 if (!entry.lora && llm.
model == entry.filename) llm.model =
"";
586 else if (entry.lora) llm.
RemoveLora(entry.filename);
596 modelProgress = progress;
605 loraProgress = progress;
613 string json = JsonUtility.ToJson(
new LLMManagerStore { modelEntries = modelEntries, downloadOnStart = downloadOnStart },
true);
614 PlayerPrefs.SetString(LLMManagerPref, json);
623 string pref = PlayerPrefs.GetString(LLMManagerPref);
624 if (pref ==
null || pref ==
"")
return;
625 LLMManagerStore store = JsonUtility.FromJson<LLMManagerStore>(pref);
626 downloadOnStart = store.downloadOnStart;
627 modelEntries = store.modelEntries;
635 List<ModelEntry> modelEntriesBuild =
new List<ModelEntry>();
636 foreach (
ModelEntry modelEntry
in modelEntries)
638 if (!modelEntry.includeInBuild)
continue;
641 string json = JsonUtility.ToJson(
new LLMManagerStore { modelEntries = modelEntriesBuild, downloadOnStart = downloadOnStart },
true);
649 public static void Build(ActionCallback copyCallback)
653 foreach (
ModelEntry modelEntry
in modelEntries)
655 string target =
LLMUnitySetup.GetAssetPath(modelEntry.filename);
656 if (!modelEntry.includeInBuild || File.Exists(target))
continue;
657 if (!downloadOnStart ||
string.IsNullOrEmpty(modelEntry.url)) copyCallback(modelEntry.path, target);
Class implementing the skeleton of a chat template.
static string FromGGUF(string path)
Determines the chat template name from a GGUF file. It reads the GGUF file and then determines the ch...
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 SetTemplate(ModelEntry entry, string chatTemplate)
Sets the chat template for a model and distributes it to all LLMs using it.
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 Build(ActionCallback copyCallback)
Saves the model manager to disk along with models that are not (or can't) be downloaded for the build...
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 SetTemplate(string filename, string chatTemplate)
Sets the chat template for a model and distributes it to all LLMs using it.
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 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.
Class implementing the LLM server.
void RemoveLora(string path)
Allows to remove a LORA model from the LLM. Models supported are in .gguf format.
string model
the LLM model to use. Models with .gguf format are allowed.
void SetTemplate(string templateName, bool setDirty=true)
Set the chat template for the LLM.
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.