diff --git a/Editor/LLMBuildProcessor.cs b/Editor/LLMBuildProcessor.cs index d0362ead..2e17bf84 100644 --- a/Editor/LLMBuildProcessor.cs +++ b/Editor/LLMBuildProcessor.cs @@ -8,17 +8,18 @@ namespace LLMUnity { - public class LLMBuildProcessor : IPreprocessBuildWithReport, IPostprocessBuildWithReport + public class LLMBuildProcessor : MonoBehaviour, IPreprocessBuildWithReport, IPostprocessBuildWithReport { public int callbackOrder => 0; static string tempDir = Path.Combine(Application.temporaryCachePath, "LLMBuildProcessor", Path.GetFileName(LLMUnitySetup.libraryPath)); - static string foldersMovedCache = Path.Combine(tempDir, "moved.json"); + static List movedPairs = new List(); + static string movedCache = Path.Combine(tempDir, "moved.json"); [InitializeOnLoadMethod] private static void InitializeOnLoad() { if (!Directory.Exists(tempDir)) Directory.CreateDirectory(tempDir); - else ResetLibraryPlatforms(); + else ResetMoves(); } // CALLED BEFORE THE BUILD @@ -26,8 +27,9 @@ public void OnPreprocessBuild(BuildReport report) { // Start listening for errors when build starts Application.logMessageReceived += OnBuildError; - List platforms = GetLibraryPlatformsToHide(report.summary.platform); - HideLibraryPlatforms(platforms); + HideLibraryPlatforms(report.summary.platform); + HideModels(); + if (movedPairs.Count > 0) AssetDatabase.Refresh(); } // CALLED DURING BUILD TO CHECK FOR ERRORS @@ -49,29 +51,10 @@ public void OnPostprocessBuild(BuildReport report) public void BuildCompleted() { Application.logMessageReceived -= OnBuildError; - ResetLibraryPlatforms(); + ResetMoves(); } - static List GetLibraryPlatformsToHide(BuildTarget platform) - { - List platforms = new List(){ "windows", "macos", "linux" }; - switch (platform) - { - case BuildTarget.StandaloneWindows: - case BuildTarget.StandaloneWindows64: - platforms.Remove("windows"); - break; - case BuildTarget.StandaloneLinux64: - platforms.Remove("linux"); - break; - case BuildTarget.StandaloneOSX: - platforms.Remove("macos"); - break; - } - return platforms; - } - - static bool MovePath(string source, string target, List foldersMoved = null) + static bool MovePath(string source, string target) { bool moved = false; if (File.Exists(source)) @@ -84,45 +67,77 @@ static bool MovePath(string source, string target, List folder Directory.Move(source, target); moved = true; } - if (moved && foldersMoved != null) foldersMoved.Add(new FoldersMovedPair {source = source, target = target}); + if (moved) + { + movedPairs.Add(new MovedPair {source = source, target = target}); + File.WriteAllText(movedCache, JsonUtility.ToJson(new FoldersMovedWrapper { movedPairs = movedPairs })); + } return moved; } - static void HideLibraryPlatforms(List platforms) + static void MoveAssetAndMeta(string source, string target) + { + MovePath(source + ".meta", target + ".meta"); + MovePath(source, target); + } + + static void HideLibraryPlatforms(BuildTarget buildPlatform) { - List foldersMoved = new List(); + List platforms = new List(){ "windows", "macos", "linux", "android" }; + switch (buildPlatform) + { + case BuildTarget.StandaloneWindows: + case BuildTarget.StandaloneWindows64: + platforms.Remove("windows"); + break; + case BuildTarget.StandaloneLinux64: + platforms.Remove("linux"); + break; + case BuildTarget.StandaloneOSX: + platforms.Remove("macos"); + break; + case BuildTarget.Android: + platforms.Remove("android"); + break; + } + foreach (string dirname in Directory.GetDirectories(LLMUnitySetup.libraryPath)) { foreach (string platform in platforms) { if (Path.GetFileName(dirname).StartsWith(platform)) { - string movePath = Path.Combine(tempDir, Path.GetFileName(dirname)); - MovePath(dirname + ".meta", movePath + ".meta", foldersMoved); - MovePath(dirname, movePath, foldersMoved); - File.WriteAllText(foldersMovedCache, JsonUtility.ToJson(new FoldersMovedWrapper { foldersMoved = foldersMoved })); + MoveAssetAndMeta(dirname, Path.Combine(tempDir, Path.GetFileName(dirname))); } } } - if (foldersMoved.Count > 0) AssetDatabase.Refresh(); } - static void ResetLibraryPlatforms() + static void HideModels() + { + foreach (LLM llm in FindObjectsOfType()) + { + if (!llm.downloadOnBuild) continue; + if (llm.modelURL != "") MoveAssetAndMeta(LLMUnitySetup.GetAssetPath(llm.model), Path.Combine(tempDir, Path.GetFileName(llm.model))); + if (llm.loraURL != "") MoveAssetAndMeta(LLMUnitySetup.GetAssetPath(llm.lora), Path.Combine(tempDir, Path.GetFileName(llm.lora))); + } + } + + static void ResetMoves() { - if (!File.Exists(foldersMovedCache)) return; - List foldersMoved = JsonUtility.FromJson(File.ReadAllText(foldersMovedCache)).foldersMoved; - if (foldersMoved == null) return; + if (!File.Exists(movedCache)) return; + List movedPairs = JsonUtility.FromJson(File.ReadAllText(movedCache)).movedPairs; + if (movedPairs == null) return; bool refresh = false; - foreach (var pair in foldersMoved) refresh |= MovePath(pair.target, pair.source); + foreach (var pair in movedPairs) refresh |= MovePath(pair.target, pair.source); if (refresh) AssetDatabase.Refresh(); - - File.Delete(foldersMovedCache); + File.Delete(movedCache); } } [Serializable] - public struct FoldersMovedPair + public struct MovedPair { public string source; public string target; @@ -131,6 +146,6 @@ public struct FoldersMovedPair [Serializable] public class FoldersMovedWrapper { - public List foldersMoved; + public List movedPairs; } } diff --git a/Editor/LLMEditor.cs b/Editor/LLMEditor.cs index 39e30dc9..cb778f9c 100644 --- a/Editor/LLMEditor.cs +++ b/Editor/LLMEditor.cs @@ -35,7 +35,7 @@ public void AddModelLoaders(SerializedObject llmScriptSO, LLM llmScript) int newIndex = EditorGUILayout.Popup("Model", llmScript.SelectedModel, options); if (newIndex != llmScript.SelectedModel) { - LLMUnitySetup.DownloadModel(llmScript, newIndex); + llmScript.DownloadDefaultModel(newIndex); } if (GUILayout.Button("Load model", GUILayout.Width(buttonWidth))) @@ -45,7 +45,7 @@ public void AddModelLoaders(SerializedObject llmScriptSO, LLM llmScript) string path = EditorUtility.OpenFilePanelWithFilters("Select a gguf model file", "", new string[] { "Model Files", "gguf" }); if (!string.IsNullOrEmpty(path)) { - llmScript.SelectedModel = 0; + llmScript.ResetSelectedModel(); llmScript.SetModel(path); } }; @@ -86,11 +86,14 @@ public void AddModelAddonLoaders(SerializedObject llmScriptSO, LLM llmScript, bo public void AddModelSettings(SerializedObject llmScriptSO) { List attributeClasses = new List { typeof(ModelAttribute) }; + List excludeAttributeClasses = new List { typeof(ModelDownloadAttribute), typeof(ModelDownloadAdvancedAttribute) }; + if (llmScriptSO.FindProperty("downloadOnBuild").boolValue) excludeAttributeClasses.Remove(typeof(ModelDownloadAttribute)); if (llmScriptSO.FindProperty("advancedOptions").boolValue) { attributeClasses.Add(typeof(ModelAdvancedAttribute)); + if (llmScriptSO.FindProperty("downloadOnBuild").boolValue) excludeAttributeClasses.Remove(typeof(ModelDownloadAdvancedAttribute)); } - ShowPropertiesOfClass("", llmScriptSO, attributeClasses, false); + ShowPropertiesOfClass("", llmScriptSO, attributeClasses, false, excludeAttributeClasses); Space(); } diff --git a/Editor/PropertyEditor.cs b/Editor/PropertyEditor.cs index 7229804a..e5175a87 100644 --- a/Editor/PropertyEditor.cs +++ b/Editor/PropertyEditor.cs @@ -94,10 +94,23 @@ public List GetPropertiesOfClass(SerializedObject so, List attributeClasses, bool addSpace = true) + public void ShowPropertiesOfClass(string title, SerializedObject so, List attributeClasses, bool addSpace = true, List excludeAttributeClasses = null) { // display a property if it belongs to a certain class and/or has a specific attribute class List properties = GetPropertiesOfClass(so, attributeClasses); + if (excludeAttributeClasses != null) + { + List excludeProperties = GetPropertiesOfClass(so, excludeAttributeClasses); + List removeProperties = new List(); + foreach (SerializedProperty excprop in excludeProperties) + { + foreach (SerializedProperty prop in properties) + { + if (prop.displayName == excprop.displayName) removeProperties.Add(prop); + } + } + foreach (SerializedProperty prop in removeProperties) properties.Remove(prop); + } if (properties.Count == 0) return; if (title != "") EditorGUILayout.LabelField(title, EditorStyles.boldLabel); foreach (SerializedProperty prop in properties) @@ -141,7 +154,7 @@ public Attribute GetPropertyAttribute(SerializedProperty prop, Type attributeCla { foreach (Attribute attr in fieldInfo.GetCustomAttributes(attributeClass, true)) { - if (attr.GetType() == attributeClass) + if (attributeClass.IsAssignableFrom(attr.GetType())) return attr; } } diff --git a/Runtime/LLM.cs b/Runtime/LLM.cs index 74e51e33..76e31ab4 100644 --- a/Runtime/LLM.cs +++ b/Runtime/LLM.cs @@ -68,12 +68,20 @@ public class LLM : MonoBehaviour [LLMAdvanced] public bool asynchronousStartup = true; /// select to not destroy the LLM GameObject when loading a new Scene. [LLMAdvanced] public bool dontDestroyOnLoad = true; + /// toggle to enable model download on build + [Model] public bool downloadOnBuild = false; /// the path of the model being used (relative to the Assets/StreamingAssets folder). /// Models with .gguf format are allowed. [Model] public string model = ""; + /// the URL of the model to use. + /// Models with .gguf format are allowed. + [ModelDownload] public string modelURL = ""; /// the path of the LORA model being used (relative to the Assets/StreamingAssets folder). /// Models with .bin format are allowed. [ModelAdvanced] public string lora = ""; + /// the URL of the LORA to use. + /// Models with .bin format are allowed. + [ModelDownloadAdvanced] public string loraURL = ""; /// Size of the prompt context (0 = context size of the model). /// This is the number of tokens the model can take as input when generating responses. [ModelAdvanced] public int contextSize = 0; @@ -81,7 +89,8 @@ public class LLM : MonoBehaviour [ModelAdvanced] public int batchSize = 512; /// a base prompt to use as a base for all LLMCharacter objects [TextArea(5, 10), ChatAdvanced] public string basePrompt = ""; - + /// Boolean set to true if the server has started and is ready to receive requests, false otherwise. + public bool modelsDownloaded { get; protected set; } = false; /// Boolean set to true if the server has started and is ready to receive requests, false otherwise. public bool started { get; protected set; } = false; /// Boolean set to true if the server has failed to start. @@ -90,6 +99,7 @@ public class LLM : MonoBehaviour /// \cond HIDE public int SelectedModel = 0; [HideInInspector] public float modelProgress = 1; + [HideInInspector] public float loraProgress = 1; [HideInInspector] public float modelCopyProgress = 1; [HideInInspector] public bool modelHide = true; @@ -101,38 +111,109 @@ public class LLM : MonoBehaviour StreamWrapper logStreamWrapper = null; Thread llmThread = null; List streamWrappers = new List(); + List> modelProgressCallbacks = new List>(); + List> loraProgressCallbacks = new List>(); public void SetModelProgress(float progress) { modelProgress = progress; + foreach (Callback modelProgressCallback in modelProgressCallbacks) modelProgressCallback?.Invoke(progress); + } + + public void SetLoraProgress(float progress) + { + loraProgress = progress; + foreach (Callback loraProgressCallback in loraProgressCallbacks) loraProgressCallback?.Invoke(progress); } /// \endcond - async Task CopyAsset(string path) + string CopyAsset(string path) { #if UNITY_EDITOR if (!EditorApplication.isPlaying) { modelCopyProgress = 0; - path = await LLMUnitySetup.AddAsset(path, LLMUnitySetup.GetAssetPath()); + path = LLMUnitySetup.AddAsset(path, LLMUnitySetup.GetAssetPath()); modelCopyProgress = 1; } #endif return path; } + public void ResetSelectedModel() + { + SelectedModel = 0; + modelURL = ""; + model = ""; + } + + public async Task DownloadDefaultModel(int optionIndex) + { + // download default model and disable model editor properties until the model is set + if (optionIndex == 0) + { + ResetSelectedModel(); + return; + } + SelectedModel = optionIndex; + string modelUrl = LLMUnitySetup.modelOptions[optionIndex].Item2; + modelURL = modelUrl; + string modelName = Path.GetFileName(modelUrl).Split("?")[0]; + await DownloadModel(modelUrl, modelName); + } + + public async Task DownloadModel(string modelUrl, string modelName, bool overwrite = false, bool setTemplate = true) + { + modelProgress = 0; + string modelPath = LLMUnitySetup.GetAssetPath(modelName); + await LLMUnitySetup.DownloadFile(modelUrl, modelPath, overwrite, (string path) => SetModel(path, setTemplate), SetModelProgress); + } + + public async Task DownloadLora(string loraUrl, string loraName, bool overwrite = false) + { + loraProgress = 0; + string loraPath = LLMUnitySetup.GetAssetPath(loraName); + await LLMUnitySetup.DownloadFile(loraUrl, loraPath, overwrite, SetLora, SetLoraProgress); + } + + public async Task DownloadModels(bool overwrite = false) + { + if (modelURL != "") await DownloadModel(modelURL, model, overwrite, false); + if (loraURL != "") await DownloadLora(loraURL, lora, overwrite); + } + + public async Task AndroidExtractModels() + { + if (!downloadOnBuild || modelURL == "") await LLMUnitySetup.AndroidExtractFile(model); + if (!downloadOnBuild || loraURL == "") await LLMUnitySetup.AndroidExtractFile(lora); + } + + public async Task WaitUntilModelsDownloaded(Callback modelProgressCallback = null, Callback loraProgressCallback = null) + { + if (modelProgressCallback != null) modelProgressCallbacks.Add(modelProgressCallback); + if (loraProgressCallback != null) loraProgressCallbacks.Add(loraProgressCallback); + while (!modelsDownloaded) await Task.Yield(); + if (modelProgressCallback != null) modelProgressCallbacks.Remove(modelProgressCallback); + if (loraProgressCallback != null) loraProgressCallbacks.Remove(loraProgressCallback); + } + + public async Task WaitUntilReady() + { + while (!started) await Task.Yield(); + } + /// /// Allows to set the model used by the LLM. /// The model provided is copied to the Assets/StreamingAssets folder that allows it to also work in the build. /// Models supported are in .gguf format. /// /// path to model to use (.gguf format) - public async Task SetModel(string path) + public void SetModel(string path, bool setTemplate = true) { // set the model and enable the model editor properties - model = await CopyAsset(path); - SetTemplate(ChatTemplate.FromGGUF(LLMUnitySetup.GetAssetPath(model))); + model = CopyAsset(path); + if (setTemplate) SetTemplate(ChatTemplate.FromGGUF(LLMUnitySetup.GetAssetPath(model))); #if UNITY_EDITOR if (!EditorApplication.isPlaying) EditorUtility.SetDirty(this); #endif @@ -144,9 +225,9 @@ public async Task SetModel(string path) /// Models supported are in .bin format. /// /// path to LORA model to use (.bin format) - public async Task SetLora(string path) + public void SetLora(string path) { - lora = await CopyAsset(path); + lora = CopyAsset(path); #if UNITY_EDITOR if (!EditorApplication.isPlaying) EditorUtility.SetDirty(this); #endif @@ -159,7 +240,7 @@ public async Task SetLora(string path) public void SetTemplate(string templateName) { chatTemplate = templateName; - llmlib?.LLM_SetTemplate(LLMObject, chatTemplate); + if (started) llmlib?.LLM_SetTemplate(LLMObject, chatTemplate); } /// @@ -196,10 +277,13 @@ protected virtual string GetLlamaccpArguments() } } + int numThreadsToUse = numThreads; + if (Application.platform == RuntimePlatform.Android && numThreads <= 0) numThreadsToUse = LLMUnitySetup.AndroidGetNumBigCores(); + int slots = GetNumClients(); string arguments = $"-m \"{modelPath}\" -c {contextSize} -b {batchSize} --log-disable -np {slots}"; if (remote) arguments += $" --port {port} --host 0.0.0.0"; - if (numThreads > 0) arguments += $" -t {numThreads}"; + if (numThreadsToUse > 0) arguments += $" -t {numThreadsToUse}"; if (loraPath != "") arguments += $" --lora \"{loraPath}\""; arguments += $" -ngl {numGPULayers}"; return arguments; @@ -212,8 +296,13 @@ protected virtual string GetLlamaccpArguments() public async void Awake() { if (!enabled) return; - if (asynchronousStartup) await Task.Run(() => StartLLMServer()); - else StartLLMServer(); + if (downloadOnBuild) await DownloadModels(); + modelsDownloaded = true; + if (Application.platform == RuntimePlatform.Android) await AndroidExtractModels(); + string arguments = GetLlamaccpArguments(); + if (arguments == null) return; + if (asynchronousStartup) await Task.Run(() => StartLLMServer(arguments)); + else StartLLMServer(arguments); if (dontDestroyOnLoad) DontDestroyOnLoad(transform.root.gameObject); if (basePrompt != "") await SetBasePrompt(basePrompt); } @@ -231,12 +320,10 @@ private void StopLogging() DestroyStreamWrapper(logStreamWrapper); } - private void StartLLMServer() + private void StartLLMServer(string arguments) { started = false; failed = false; - string arguments = GetLlamaccpArguments(); - if (arguments == null) return; bool useGPU = numGPULayers > 0; LLMUnitySetup.Log($"Server command: {arguments}"); diff --git a/Runtime/LLMCharacter.cs b/Runtime/LLMCharacter.cs index 8d36ead9..7fb45489 100644 --- a/Runtime/LLMCharacter.cs +++ b/Runtime/LLMCharacter.cs @@ -319,10 +319,10 @@ public async Task LoadTemplate() /// Set the grammar file of the LLMCharacter /// /// path to the grammar file - public async void SetGrammar(string path) + public void SetGrammar(string path) { #if UNITY_EDITOR - if (!EditorApplication.isPlaying) path = await LLMUnitySetup.AddAsset(path, LLMUnitySetup.GetAssetPath()); + if (!EditorApplication.isPlaying) path = LLMUnitySetup.AddAsset(path, LLMUnitySetup.GetAssetPath()); #endif grammar = path; InitGrammar(); diff --git a/Runtime/LLMLib.cs b/Runtime/LLMLib.cs index 45fc4260..95cd5576 100644 --- a/Runtime/LLMLib.cs +++ b/Runtime/LLMLib.cs @@ -104,6 +104,8 @@ public static IntPtr LoadLibrary(string libraryName) handle = Linux.dlopen(libraryName); else if (Application.platform == RuntimePlatform.OSXEditor || Application.platform == RuntimePlatform.OSXPlayer) handle = Mac.dlopen(libraryName); + else if (Application.platform == RuntimePlatform.Android) + handle = Android.dlopen(libraryName); else throw new PlatformNotSupportedException($"Current platform is unknown, unable to load library '{libraryName}'."); @@ -122,6 +124,8 @@ public static IntPtr GetSymbol(IntPtr library, string symbolName) handle = Linux.dlsym(library, symbolName); else if (Application.platform == RuntimePlatform.OSXEditor || Application.platform == RuntimePlatform.OSXPlayer) handle = Mac.dlsym(library, symbolName); + else if (Application.platform == RuntimePlatform.Android) + handle = Android.dlsym(library, symbolName); else throw new PlatformNotSupportedException($"Current platform is unknown, unable to load symbol '{symbolName}' from library {library}."); @@ -139,6 +143,8 @@ public static void FreeLibrary(IntPtr library) Linux.dlclose(library); else if (Application.platform == RuntimePlatform.OSXEditor || Application.platform == RuntimePlatform.OSXPlayer) Mac.dlclose(library); + else if (Application.platform == RuntimePlatform.Android) + Android.dlclose(library); else throw new PlatformNotSupportedException($"Current platform is unknown, unable to close library '{library}'."); } @@ -231,6 +237,22 @@ private static class Win32 [DllImport(SystemLibrary, SetLastError = true, CharSet = CharSet.Ansi)] public static extern void FreeLibrary(IntPtr hModule); } + + private static class Android + { + public static IntPtr dlopen(string path) => dlopen(path, 1); + // LoadLibrary for Android + [DllImport("__Internal")] + public static extern IntPtr dlopen(string filename, int flags); + + // GetSymbol for Android + [DllImport("__Internal")] + public static extern IntPtr dlsym(IntPtr handle, string symbol); + + // FreeLibrary for Android + [DllImport("__Internal")] + public static extern int dlclose(IntPtr handle); + } } public class LLMLib @@ -334,6 +356,10 @@ public static List PossibleArchitectures(bool gpu = false) architectures.Add("x64-no_acc"); } } + else if (Application.platform == RuntimePlatform.Android) + { + architectures.Add("android"); + } else { string error = "Unknown OS"; @@ -376,6 +402,10 @@ public static string GetArchitecturePath(string arch) { filename = $"macos-{arch}/libundreamai_macos-{arch}.dylib"; } + else if (Application.platform == RuntimePlatform.Android) + { + return "libundreamai_android_plugin.so"; + } else { string error = "Unknown OS"; diff --git a/Runtime/LLMUnitySetup.cs b/Runtime/LLMUnitySetup.cs index 74022dbc..bc9d9fb1 100644 --- a/Runtime/LLMUnitySetup.cs +++ b/Runtime/LLMUnitySetup.cs @@ -4,10 +4,11 @@ using System.IO; using UnityEngine; using System.Threading.Tasks; -using System.Net; using System; using System.IO.Compression; using System.Collections.Generic; +using System.Runtime.InteropServices; +using UnityEngine.Networking; /// @defgroup llm LLM /// @defgroup template Chat Templates @@ -44,6 +45,8 @@ public class LocalRemoteAttribute : PropertyAttribute {} public class RemoteAttribute : PropertyAttribute {} public class LocalAttribute : PropertyAttribute {} public class ModelAttribute : PropertyAttribute {} + public class ModelDownloadAttribute : ModelAttribute {} + public class ModelDownloadAdvancedAttribute : ModelAdvancedAttribute {} public class ModelAdvancedAttribute : PropertyAttribute {} public class ChatAttribute : PropertyAttribute {} public class ChatAdvancedAttribute : PropertyAttribute {} @@ -150,7 +153,8 @@ public static void SetDebugMode(DebugModeType newDebugMode) public static string GetAssetPath(string relPath = "") { // Path to store llm server binaries and models - return Path.Combine(Application.streamingAssetsPath, relPath).Replace('\\', '/'); + string assetsDir = Application.platform == RuntimePlatform.Android ? Application.persistentDataPath : Application.streamingAssetsPath; + return Path.Combine(assetsDir, relPath).Replace('\\', '/'); } #if UNITY_EDITOR @@ -160,103 +164,98 @@ static async Task InitializeOnLoad() await DownloadLibrary(); LoadDebugMode(); } + #else [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] void InitializeOnLoad() { LoadDebugMode(); } + #endif -#if UNITY_EDITOR - [HideInInspector] public static float libraryProgress = 1; + static Dictionary downloadClients = new Dictionary(); - public class DownloadStatus + public static void CancelDownload(string savePath) { - Callback progresscallback; - - public DownloadStatus(Callback progresscallback = null) - { - this.progresscallback = progresscallback; - } - - public void DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) - { - progresscallback?.Invoke(e.ProgressPercentage / 100.0f); - } + if (!downloadClients.ContainsKey(savePath)) return; + downloadClients[savePath].CancelDownloadAsync(); + downloadClients.Remove(savePath); } public static async Task DownloadFile( string fileUrl, string savePath, bool overwrite = false, - TaskCallback callback = null, Callback progresscallback = null, - bool async = true + Callback callback = null, Callback progressCallback = null ) { - // download a file to the specified path if (File.Exists(savePath) && !overwrite) { Log($"File already exists at: {savePath}"); } else { - Log($"Downloading {fileUrl}..."); + Log($"Downloading {fileUrl} to {savePath}..."); string tmpPath = Path.Combine(Application.temporaryCachePath, Path.GetFileName(savePath)); - WebClient client = new WebClient(); - DownloadStatus downloadStatus = new DownloadStatus(progresscallback); - client.DownloadProgressChanged += downloadStatus.DownloadProgressChanged; - if (async) - { - await client.DownloadFileTaskAsync(fileUrl, tmpPath); - } - else - { - client.DownloadFile(fileUrl, tmpPath); - } - + ResumingWebClient client = new ResumingWebClient(); + downloadClients[savePath] = client; + await client.DownloadFileTaskAsyncResume(new Uri(fileUrl), tmpPath, !overwrite, progressCallback); + downloadClients.Remove(savePath); +#if UNITY_EDITOR AssetDatabase.StartAssetEditing(); +#endif Directory.CreateDirectory(Path.GetDirectoryName(savePath)); File.Move(tmpPath, savePath); +#if UNITY_EDITOR AssetDatabase.StopAssetEditing(); +#endif Log($"Download complete!"); } - progresscallback?.Invoke(1f); - if (callback != null) await callback.Invoke(savePath); + progressCallback?.Invoke(1f); + callback?.Invoke(savePath); } - public static async Task AddAsset(string assetPath, string basePath) + public static async Task AndroidExtractFile(string assetName, bool overwrite = false, int chunkSize = 1024*1024) { - if (!File.Exists(assetPath)) + string source = "jar:file://" + Application.dataPath + "!/assets/" + assetName; + string target = GetAssetPath(assetName); + if (!overwrite && File.Exists(target)) { - LogError($"{assetPath} does not exist!"); - return null; + Debug.Log($"File {target} already exists"); + return; } - // add an asset to the basePath directory if it is not already there and return the relative path - string basePathSlash = basePath.Replace('\\', '/'); - string fullPath = Path.GetFullPath(assetPath).Replace('\\', '/'); - Directory.CreateDirectory(basePathSlash); - if (!fullPath.StartsWith(basePathSlash)) + + Debug.Log($"Extracting {source} to {target}"); + + // UnityWebRequest to read the file from StreamingAssets + UnityWebRequest www = UnityWebRequest.Get(source); + // Send the request and await its completion + var operation = www.SendWebRequest(); + + while (!operation.isDone) await Task.Delay(1); + if (www.result != UnityWebRequest.Result.Success) { - // if the asset is not in the assets dir copy it over - fullPath = Path.Combine(basePathSlash, Path.GetFileName(assetPath)); - Log($"copying {assetPath} to {fullPath}"); - AssetDatabase.StartAssetEditing(); - await Task.Run(() => + Debug.LogError("Failed to load file from StreamingAssets: " + www.error); + } + else + { + byte[] buffer = new byte[chunkSize]; + using (Stream responseStream = new MemoryStream(www.downloadHandler.data)) + using (FileStream fileStream = new FileStream(target, FileMode.Create, FileAccess.Write)) { - foreach (string filename in new string[] {fullPath, fullPath + ".meta"}) + int bytesRead; + while ((bytesRead = await responseStream.ReadAsync(buffer, 0, buffer.Length)) > 0) { - if (File.Exists(fullPath)) - File.Delete(fullPath); + await fileStream.WriteAsync(buffer, 0, bytesRead); } - File.Copy(assetPath, fullPath); - }); - AssetDatabase.StopAssetEditing(); - Log("copying complete!"); + } } - return fullPath.Substring(basePathSlash.Length + 1); } +#if UNITY_EDITOR + [HideInInspector] public static float libraryProgress = 1; + private static async Task DownloadLibrary() { if (libraryProgress < 1) return; @@ -276,19 +275,210 @@ private static void SetLibraryProgress(float progress) libraryProgress = progress; } - public static void DownloadModel(LLM llm, int optionIndex) + public static string AddAsset(string assetPath, string basePath) + { + if (!File.Exists(assetPath)) + { + LogError($"{assetPath} does not exist!"); + return null; + } + // add an asset to the basePath directory if it is not already there and return the relative path + string basePathSlash = basePath.Replace('\\', '/'); + string fullPath = Path.GetFullPath(assetPath).Replace('\\', '/'); + Directory.CreateDirectory(basePathSlash); + if (!fullPath.StartsWith(basePathSlash)) + { + // if the asset is not in the assets dir copy it over + fullPath = Path.Combine(basePathSlash, Path.GetFileName(assetPath)); + AssetDatabase.StartAssetEditing(); + foreach (string filename in new string[] {fullPath, fullPath + ".meta"}) + { + if (File.Exists(filename)) File.Delete(filename); + } + CreateSymlink(assetPath, fullPath); + AssetDatabase.StopAssetEditing(); + } + return fullPath.Substring(basePathSlash.Length + 1); + } + + public static void CreateSymlink(string sourcePath, string targetPath) { - // download default model and disable model editor properties until the model is set - llm.SelectedModel = optionIndex; - string modelUrl = modelOptions[optionIndex].Item2; - if (modelUrl == null) return; - llm.modelProgress = 0; - string modelName = Path.GetFileName(modelUrl).Split("?")[0]; - string modelPath = GetAssetPath(modelName); - Task downloadTask = DownloadFile(modelUrl, modelPath, false, llm.SetModel, llm.SetModelProgress); + bool isDirectory = Directory.Exists(sourcePath); + if (!isDirectory && !File.Exists(sourcePath)) throw new FileNotFoundException($"Source path does not exist: {sourcePath}"); + + bool success; +#if UNITY_STANDALONE_WIN + success = CreateSymbolicLink(targetPath, sourcePath, (int)isDirectory); +#else + success = symlink(sourcePath, targetPath) == 0; +#endif + if (!success) throw new IOException($"Failed to create symbolic link: {targetPath}"); } + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + private static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, int dwFlags); + + [DllImport("libc", SetLastError = true)] + private static extern int symlink(string oldpath, string newpath); + #endif /// \endcond + public static int GetMaxFreqKHz(int cpuId) + { + string[] paths = new string[] + { + $"/sys/devices/system/cpu/cpufreq/stats/cpu{cpuId}/time_in_state", + $"/sys/devices/system/cpu/cpu{cpuId}/cpufreq/stats/time_in_state", + $"/sys/devices/system/cpu/cpu{cpuId}/cpufreq/cpuinfo_max_freq" + }; + + foreach (var path in paths) + { + if (!File.Exists(path)) continue; + + int maxFreqKHz = 0; + using (StreamReader sr = new StreamReader(path)) + { + string line; + while ((line = sr.ReadLine()) != null) + { + string[] parts = line.Split(' '); + if (parts.Length > 0 && int.TryParse(parts[0], out int freqKHz)) + { + if (freqKHz > maxFreqKHz) + { + maxFreqKHz = freqKHz; + } + } + } + } + if (maxFreqKHz != 0) return maxFreqKHz; + } + return -1; + } + + public static bool IsSmtCpu(int cpuId) + { + string[] paths = new string[] + { + $"/sys/devices/system/cpu/cpu{cpuId}/topology/core_cpus_list", + $"/sys/devices/system/cpu/cpu{cpuId}/topology/thread_siblings_list" + }; + + foreach (var path in paths) + { + if (!File.Exists(path)) continue; + using (StreamReader sr = new StreamReader(path)) + { + string line; + while ((line = sr.ReadLine()) != null) + { + if (line.Contains(",") || line.Contains("-")) + { + return true; + } + } + } + } + return false; + } + + /// + /// Calculates the number of big cores in Android similarly to ncnn (https://github.com/Tencent/ncnn) + /// + /// + public static int AndroidGetNumBigCores() + { + int maxFreqKHzMin = int.MaxValue; + int maxFreqKHzMax = 0; + List cpuMaxFreqKHz = new List(); + List cpuIsSmtCpu = new List(); + + try + { + string cpuPath = "/sys/devices/system/cpu/"; + int coreIndex; + if (Directory.Exists(cpuPath)) + { + foreach (string cpuDir in Directory.GetDirectories(cpuPath)) + { + string dirName = Path.GetFileName(cpuDir); + if (!dirName.StartsWith("cpu")) continue; + if (!int.TryParse(dirName.Substring(3), out coreIndex)) continue; + + int maxFreqKHz = GetMaxFreqKHz(coreIndex); + cpuMaxFreqKHz.Add(maxFreqKHz); + if (maxFreqKHz > maxFreqKHzMax) maxFreqKHzMax = maxFreqKHz; + if (maxFreqKHz < maxFreqKHzMin) maxFreqKHzMin = maxFreqKHz; + cpuIsSmtCpu.Add(IsSmtCpu(coreIndex)); + } + } + } + catch (Exception e) + { + Debug.LogError(e.Message); + } + + int numBigCores = 0; + int numCores = SystemInfo.processorCount; + int maxFreqKHzMedium = (maxFreqKHzMin + maxFreqKHzMax) / 2; + if (maxFreqKHzMedium == maxFreqKHzMax) numBigCores = numCores; + else + { + for (int i = 0; i < cpuMaxFreqKHz.Count; i++) + { + if (cpuIsSmtCpu[i] || cpuMaxFreqKHz[i] >= maxFreqKHzMedium) numBigCores++; + } + } + + if (numBigCores == 0) numBigCores = SystemInfo.processorCount / 2; + else numBigCores = Math.Min(numBigCores, SystemInfo.processorCount); + + return numBigCores; + } + + /// + /// Calculates the number of big cores in Android similarly to Unity (https://docs.unity3d.com/2022.3/Documentation/Manual/android-thread-configuration.html) + /// + /// + public static int AndroidGetNumBigCoresCapacity() + { + List capacities = new List(); + int minCapacity = int.MaxValue; + try + { + string cpuPath = "/sys/devices/system/cpu/"; + int coreIndex; + if (Directory.Exists(cpuPath)) + { + foreach (string cpuDir in Directory.GetDirectories(cpuPath)) + { + string dirName = Path.GetFileName(cpuDir); + if (!dirName.StartsWith("cpu")) continue; + if (!int.TryParse(dirName.Substring(3), out coreIndex)) continue; + + string capacityPath = Path.Combine(cpuDir, "cpu_capacity"); + if (!File.Exists(capacityPath)) break; + + int capacity = int.Parse(File.ReadAllText(capacityPath).Trim()); + capacities.Add(capacity); + if (minCapacity > capacity) minCapacity = capacity; + } + } + } + catch (Exception e) + { + Debug.LogError(e.Message); + } + + int numBigCores = 0; + foreach (int capacity in capacities) + { + if (capacity >= 2 * minCapacity) numBigCores++; + } + + if (numBigCores == 0 || numBigCores > SystemInfo.processorCount) numBigCores = SystemInfo.processorCount; + return numBigCores; + } } } diff --git a/Runtime/ResumingWebClient.cs b/Runtime/ResumingWebClient.cs new file mode 100644 index 00000000..b6e8d4d5 --- /dev/null +++ b/Runtime/ResumingWebClient.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Threading; +using System.Threading.Tasks; + +namespace LLMUnity +{ + public class ResumingWebClient : WebClient + { + private const int timeoutMs = 30 * 1000; + private SynchronizationContext _context; + private const int DefaultDownloadBufferLength = 65536; + List requests = new List(); + + public ResumingWebClient() + { + _context = SynchronizationContext.Current ?? new SynchronizationContext(); + } + + private long GetRemoteFileSizeAsync(Uri address) + { + WebRequest request = GetWebRequest(address); + request.Method = "HEAD"; + WebResponse response = request.GetResponse(); + return response.ContentLength; + } + + public Task DownloadFileTaskAsyncResume(Uri address, string fileName, bool resume = false, Callback progressCallback = null) + { + var tcs = new TaskCompletionSource(address); + FileStream? fs = null; + long bytesToSkip = 0; + + try + { + FileMode filemode = FileMode.Create; + if (resume) + { + var fileInfo = new FileInfo(fileName); + if (fileInfo.Exists) bytesToSkip = fileInfo.Length; + } + + WebRequest request = GetWebRequest(address); + if (request is HttpWebRequest webRequest && bytesToSkip > 0) + { + long remoteFileSize = GetRemoteFileSizeAsync(address); + if (bytesToSkip >= remoteFileSize) + { + LLMUnitySetup.Log($"File is already fully downloaded: {fileName}"); + tcs.TrySetResult(true); + return tcs.Task; + } + + filemode = FileMode.Append; + LLMUnitySetup.Log($"File exists at {fileName}, skipping {bytesToSkip} bytes"); + webRequest.AddRange(bytesToSkip); + webRequest.ReadWriteTimeout = timeoutMs; + } + + fs = new FileStream(fileName, filemode, FileAccess.Write); + DownloadBitsAsync(request, fs, bytesToSkip, progressCallback, tcs); + } + catch (Exception e) + { + fs?.Close(); + tcs.TrySetException(e); + } + + return tcs.Task; + } + + public void CancelDownloadAsync() + { + LLMUnitySetup.Log("Cancellation requested, aborting download."); + foreach (WebRequest request in requests) AbortRequest(request); + requests.Clear(); + } + + public void AbortRequest(WebRequest request) + { + try + { + request?.Abort(); + } + catch (Exception e) + { + LLMUnitySetup.LogError($"Error aborting request: {e.Message}"); + } + } + + private async void DownloadBitsAsync(WebRequest request, Stream writeStream, long bytesToSkip = 0, Callback progressCallback = null, TaskCompletionSource tcs = null) + { + try + { + requests.Add(request); + WebResponse response = await request.GetResponseAsync().ConfigureAwait(false); + + long contentLength = response.ContentLength; + byte[] copyBuffer = new byte[contentLength == -1 || contentLength > DefaultDownloadBufferLength ? DefaultDownloadBufferLength : contentLength]; + + long TotalBytesToReceive = Math.Max(contentLength, 0) + bytesToSkip; + long BytesReceived = bytesToSkip; + + using (writeStream) + using (Stream readStream = response.GetResponseStream()) + { + if (readStream != null) + { + while (true) + { + int bytesRead = await readStream.ReadAsync(new Memory(copyBuffer)).ConfigureAwait(false); + if (bytesRead == 0) + { + break; + } + + BytesReceived += bytesRead; + if (BytesReceived != TotalBytesToReceive) + { + PostProgressChanged(progressCallback, BytesReceived, TotalBytesToReceive); + } + + await writeStream.WriteAsync(new ReadOnlyMemory(copyBuffer, 0, bytesRead)).ConfigureAwait(false); + } + } + + if (TotalBytesToReceive < 0) + { + TotalBytesToReceive = BytesReceived; + } + PostProgressChanged(progressCallback, BytesReceived, TotalBytesToReceive); + } + tcs.TrySetResult(true); + } + catch (Exception e) + { + tcs.TrySetException(e); + LLMUnitySetup.LogError(e.Message); + AbortRequest(request); + tcs.TrySetResult(false); + } + finally + { + writeStream?.Close(); + requests.Remove(request); + } + } + + private void PostProgressChanged(Callback progressCallback, long BytesReceived, long TotalBytesToReceive) + { + if (progressCallback != null && BytesReceived > 0) + { + float progressPercentage = TotalBytesToReceive < 0 ? 0 : TotalBytesToReceive == 0 ? 1 : (float)BytesReceived / TotalBytesToReceive; + _context.Post(_ => progressCallback?.Invoke(progressPercentage), null); + } + } + } +} diff --git a/Runtime/ResumingWebClient.cs.meta b/Runtime/ResumingWebClient.cs.meta new file mode 100644 index 00000000..369fc67e --- /dev/null +++ b/Runtime/ResumingWebClient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 00e47c7cca64b8c57ba4b7b6b2c2c5b8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/AndroidDemo.meta b/Samples~/AndroidDemo.meta new file mode 100644 index 00000000..9b3afc06 --- /dev/null +++ b/Samples~/AndroidDemo.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4259a324b4c9af10a95ced582b171297 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/AndroidDemo/AndroidDemo.cs b/Samples~/AndroidDemo/AndroidDemo.cs new file mode 100644 index 00000000..681f6dfb --- /dev/null +++ b/Samples~/AndroidDemo/AndroidDemo.cs @@ -0,0 +1,97 @@ +using UnityEngine; +using LLMUnity; +using UnityEngine.UI; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace LLMUnitySamples +{ + public class AndroidDemo : MonoBehaviour + { + public LLM llm; + public LLMCharacter llmCharacter; + + public GameObject ChatPanel; + public InputField playerText; + public Text AIText; + + public GameObject DownloadPanel; + public Scrollbar progressBar; + public Text progressText; + int cores; + + async void Start() + { + playerText.onSubmit.AddListener(onInputFieldSubmit); + playerText.interactable = false; + await ShowDownloadScreen(); + await WarmUp(); + } + + async Task ShowDownloadScreen() + { + ChatPanel.SetActive(false); + DownloadPanel.SetActive(true); + await llm.WaitUntilModelDownloaded(SetProgress); + DownloadPanel.SetActive(false); + ChatPanel.SetActive(true); + } + + async Task WarmUp() + { + llm.SetTemplate("alpaca"); + cores = LLMUnitySetup.AndroidGetNumBigCores(); + AIText.text += $"Warming up the model...\nWill use {cores} cores"; + await llmCharacter.Warmup(); + AIText.text = $"Ready when you are ({cores} cores)!"; + AIReplyComplete(); + } + + void SetProgress(float progress) + { + progressText.text = ((int)(progress * 100)).ToString() + "%"; + progressBar.size = progress; + } + + void onInputFieldSubmit(string message) + { + playerText.interactable = false; + AIText.text = "..."; + _ = llmCharacter.Chat(message, SetAIText, AIReplyComplete); + } + + public void SetAIText(string text) + { + AIText.text = text; + } + + public void AIReplyComplete() + { + playerText.interactable = true; + playerText.Select(); + playerText.text = ""; + } + + public void CancelRequests() + { + llmCharacter.CancelRequests(); + AIReplyComplete(); + } + + public void ExitGame() + { + Debug.Log("Exit button clicked"); + Application.Quit(); + } + + bool onValidateWarning = true; + void OnValidate() + { + if (onValidateWarning && !llmCharacter.remote && llmCharacter.llm != null && llmCharacter.llm.model == "") + { + Debug.LogWarning($"Please select a model in the {llmCharacter.llm.gameObject.name} GameObject!"); + onValidateWarning = false; + } + } + } +} diff --git a/Samples~/AndroidDemo/AndroidDemo.cs.meta b/Samples~/AndroidDemo/AndroidDemo.cs.meta new file mode 100644 index 00000000..3409ae47 --- /dev/null +++ b/Samples~/AndroidDemo/AndroidDemo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 708542fec6999ea3ebd7c69404932bb3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/AndroidDemo/Scene.unity b/Samples~/AndroidDemo/Scene.unity new file mode 100644 index 00000000..81f310b9 --- /dev/null +++ b/Samples~/AndroidDemo/Scene.unity @@ -0,0 +1,2263 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.44657832, g: 0.49641222, b: 0.57481664, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &107963744 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 107963746} + - component: {fileID: 107963747} + m_Layer: 0 + m_Name: AndroidDemo + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &107963746 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 107963744} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &107963747 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 107963744} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 708542fec6999ea3ebd7c69404932bb3, type: 3} + m_Name: + m_EditorClassIdentifier: + llm: {fileID: 1047848254} + llmCharacter: {fileID: 498662973} + ChatPanel: {fileID: 1084608230} + playerText: {fileID: 1966107897} + AIText: {fileID: 887085510} + DownloadPanel: {fileID: 332743750} + progressBar: {fileID: 332743752} + progressText: {fileID: 381203299} +--- !u!1 &158550913 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 158550917} + - component: {fileID: 158550916} + - component: {fileID: 158550915} + - component: {fileID: 158550914} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &158550914 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 158550913} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &158550915 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 158550913} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 1 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 720, y: 720} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0.5 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!223 &158550916 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 158550913} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_VertexColorAlwaysGammaSpace: 0 + m_AdditionalShaderChannelsFlag: 0 + m_UpdateRectTransformForStandalone: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &158550917 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 158550913} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 268891590} + - {fileID: 332743751} + - {fileID: 1084608231} + - {fileID: 1308766010} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!1 &268891589 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 268891590} + - component: {fileID: 268891592} + - component: {fileID: 268891591} + m_Layer: 5 + m_Name: Panel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &268891590 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 268891589} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1.01, y: 1.01, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 158550917} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &268891591 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 268891589} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &268891592 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 268891589} + m_CullTransparentMesh: 1 +--- !u!1 &332743750 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 332743751} + - component: {fileID: 332743754} + - component: {fileID: 332743753} + - component: {fileID: 332743752} + m_Layer: 5 + m_Name: DownloadPanel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &332743751 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 332743750} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1688602497} + - {fileID: 1705264488} + - {fileID: 381203298} + m_Father: {fileID: 158550917} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: -34.8} + m_SizeDelta: {x: 160, y: 18} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &332743752 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 332743750} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2a4db7a114972834c8e4117be1d82ba3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 0.31764707, g: 0.6431373, b: 0.31764707, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 659217392} + m_HandleRect: {fileID: 659217391} + m_Direction: 0 + m_Value: 0 + m_Size: 0 + m_NumberOfSteps: 0 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &332743753 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 332743750} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.5207577, g: 0.5207577, b: 0.5207577, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &332743754 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 332743750} + m_CullTransparentMesh: 1 +--- !u!1 &381203297 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 381203298} + - component: {fileID: 381203300} + - component: {fileID: 381203299} + m_Layer: 5 + m_Name: Progress + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &381203298 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 381203297} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 332743751} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 5, y: 0} + m_SizeDelta: {x: 79.6491, y: 19.2105} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &381203299 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 381203297} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 1 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 0% +--- !u!222 &381203300 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 381203297} + m_CullTransparentMesh: 1 +--- !u!1 &433287079 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 433287080} + - component: {fileID: 433287082} + - component: {fileID: 433287081} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &433287080 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 433287079} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 724531320} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &433287081 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 433287079} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 16 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'Stop + +' +--- !u!222 &433287082 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 433287079} + m_CullTransparentMesh: 1 +--- !u!1 &498662970 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 498662972} + - component: {fileID: 498662973} + m_Layer: 0 + m_Name: LLMCharacter + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &498662972 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 498662970} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 1024.2354, y: 495.014, z: -3.4752133} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &498662973 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 498662970} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3f6c87a428fd5d0be9bbc686bdc8c3c2, type: 3} + m_Name: + m_EditorClassIdentifier: + advancedOptions: 0 + remote: 0 + llm: {fileID: 1047848254} + host: localhost + port: 13333 + save: + saveCache: 0 + debugPrompt: 0 + stream: 1 + grammar: + cachePrompt: 1 + seed: 0 + numPredict: 256 + temperature: 0.2 + topK: 40 + topP: 0.9 + minP: 0.05 + repeatPenalty: 1.1 + presencePenalty: 0 + frequencyPenalty: 0 + tfsZ: 1 + typicalP: 1 + repeatLastN: 64 + penalizeNl: 1 + penaltyPrompt: + mirostat: 0 + mirostatTau: 5 + mirostatEta: 0.1 + nProbs: 0 + ignoreEos: 0 + nKeep: -1 + stop: [] + playerName: user + AIName: assistant + prompt: A chat between a curious human and an artificial intelligence assistant. + The assistant gives helpful, detailed, and polite answers to the human's questions. + setNKeepToPrompt: 1 + chat: [] + grammarString: +--- !u!1 &659217390 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 659217391} + - component: {fileID: 659217393} + - component: {fileID: 659217392} + m_Layer: 5 + m_Name: Handle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &659217391 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 659217390} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1705264488} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &659217392 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 659217390} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &659217393 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 659217390} + m_CullTransparentMesh: 1 +--- !u!1 &724531319 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 724531320} + - component: {fileID: 724531323} + - component: {fileID: 724531322} + - component: {fileID: 724531321} + m_Layer: 5 + m_Name: StopButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &724531320 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 724531319} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 433287080} + m_Father: {fileID: 1084608231} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 10.624025, y: -80.006996} + m_SizeDelta: {x: 107.0426, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &724531321 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 724531319} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 724531322} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 107963747} + m_TargetAssemblyTypeName: LLMUnitySamples.AndroidDemo, Assembly-CSharp + m_MethodName: CancelRequests + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 0 +--- !u!114 &724531322 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 724531319} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.31764707, g: 0.6431373, b: 0.31764707, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &724531323 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 724531319} + m_CullTransparentMesh: 1 +--- !u!1 &726528676 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 726528679} + - component: {fileID: 726528678} + - component: {fileID: 726528677} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &726528677 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 726528676} + m_Enabled: 1 +--- !u!20 &726528678 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 726528676} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &726528679 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 726528676} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &856480601 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 856480602} + - component: {fileID: 856480604} + - component: {fileID: 856480603} + m_Layer: 5 + m_Name: Player title + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &856480602 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 856480601} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1084608231} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 10.624025, y: 62.99302} + m_SizeDelta: {x: 160, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &856480603 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 856480601} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 1 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Player +--- !u!222 &856480604 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 856480601} + m_CullTransparentMesh: 1 +--- !u!1 &887085508 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 887085509} + - component: {fileID: 887085511} + - component: {fileID: 887085510} + - component: {fileID: 887085512} + m_Layer: 5 + m_Name: AIText + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &887085509 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 887085508} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 2091685447} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -20, y: -20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &887085510 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 887085508} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 16 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &887085511 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 887085508} + m_CullTransparentMesh: 1 +--- !u!210 &887085512 +SortingGroup: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 887085508} + m_Enabled: 1 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 1 + m_SortAtRoot: 0 +--- !u!1 &909474451 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 909474453} + - component: {fileID: 909474452} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &909474452 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 909474451} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &909474453 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 909474451} + serializedVersion: 2 + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &1047848253 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1047848255} + - component: {fileID: 1047848254} + m_Layer: 0 + m_Name: LLM + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1047848254 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1047848253} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a50e3140c3ecaaf1c848dbf141cc2074, type: 3} + m_Name: + m_EditorClassIdentifier: + advancedOptions: 0 + remote: 0 + port: 13333 + numThreads: 2 + numGPULayers: 0 + debug: 0 + parallelPrompts: -1 + asynchronousStartup: 1 + dontDestroyOnLoad: 1 + model: Phi-3-mini-4k-instruct-q4.gguf + downloadOnBuild: 1 + modelURL: https://huggingface.co/microsoft/Phi-3-mini-4k-instruct-gguf/resolve/main/Phi-3-mini-4k-instruct-q4.gguf?download=true + lora: + contextSize: 0 + batchSize: 512 + basePrompt: + SelectedModel: 3 + modelProgress: 1 + modelCopyProgress: 1 + modelHide: 1 + chatTemplate: phi-3 +--- !u!4 &1047848255 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1047848253} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1059033619 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1059033620} + - component: {fileID: 1059033622} + - component: {fileID: 1059033621} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1059033620 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1059033619} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1966107896} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1059033621 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1059033619} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 16 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Enter text... +--- !u!222 &1059033622 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1059033619} + m_CullTransparentMesh: 1 +--- !u!1 &1084608230 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1084608231} + m_Layer: 5 + m_Name: ChatPanel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1084608231 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1084608230} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1966107896} + - {fileID: 2091685447} + - {fileID: 856480602} + - {fileID: 1342801405} + - {fileID: 724531320} + m_Father: {fileID: 158550917} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 87.00699} + m_SizeDelta: {x: 400, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1171567417 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1171567418} + - component: {fileID: 1171567420} + - component: {fileID: 1171567419} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1171567418 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1171567417} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1308766010} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 2} + m_SizeDelta: {x: 25, y: 25} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1171567419 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1171567417} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\xD7" +--- !u!222 &1171567420 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1171567417} + m_CullTransparentMesh: 1 +--- !u!1 &1308766009 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1308766010} + - component: {fileID: 1308766013} + - component: {fileID: 1308766012} + - component: {fileID: 1308766011} + m_Layer: 5 + m_Name: ExitButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1308766010 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1308766009} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1171567418} + m_Father: {fileID: 158550917} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 35, y: 35} + m_Pivot: {x: 1, y: 1} +--- !u!114 &1308766011 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1308766009} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1308766012} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 107963747} + m_TargetAssemblyTypeName: LLMUnitySamples.AndroidDemo, Assembly-CSharp + m_MethodName: ExitGame + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 1 +--- !u!114 &1308766012 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1308766009} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.24722636, g: 0.24722636, b: 0.24722636, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10913, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1308766013 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1308766009} + m_CullTransparentMesh: 1 +--- !u!1 &1342801404 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1342801405} + - component: {fileID: 1342801407} + - component: {fileID: 1342801406} + m_Layer: 5 + m_Name: AI title + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1342801405 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1342801404} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1084608231} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 5.6240253, y: -133.00699} + m_SizeDelta: {x: 160, y: 29.6652} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1342801406 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1342801404} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 1 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: AI +--- !u!222 &1342801407 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1342801404} + m_CullTransparentMesh: 1 +--- !u!1 &1609985808 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1609985809} + - component: {fileID: 1609985811} + - component: {fileID: 1609985810} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1609985809 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1609985808} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1966107896} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1609985810 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1609985808} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 16 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &1609985811 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1609985808} + m_CullTransparentMesh: 1 +--- !u!1 &1688602496 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1688602497} + - component: {fileID: 1688602499} + - component: {fileID: 1688602498} + m_Layer: 5 + m_Name: Title + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1688602497 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1688602496} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 332743751} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -0.000025749, y: 15.999993} + m_SizeDelta: {x: 160, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1688602498 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1688602496} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 16 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 1 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Downloading model... +--- !u!222 &1688602499 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1688602496} + m_CullTransparentMesh: 1 +--- !u!1 &1705264487 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1705264488} + m_Layer: 5 + m_Name: Sliding Area + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1705264488 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1705264487} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 659217391} + m_Father: {fileID: 332743751} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.0000038146973} + m_SizeDelta: {x: 0, y: -20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1966107895 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1966107896} + - component: {fileID: 1966107899} + - component: {fileID: 1966107898} + - component: {fileID: 1966107897} + m_Layer: 5 + m_Name: PlayerInput + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1966107896 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1966107895} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1059033620} + - {fileID: 1609985809} + m_Father: {fileID: 1084608231} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: -0.000022888184} + m_SizeDelta: {x: 400, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1966107897 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1966107895} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1966107898} + m_TextComponent: {fileID: 1609985810} + m_Placeholder: {fileID: 1059033621} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 1 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnSubmit: + m_PersistentCalls: + m_Calls: [] + m_OnDidEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 +--- !u!114 &1966107898 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1966107895} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.31764707, g: 0.6431373, b: 0.31764707, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1966107899 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1966107895} + m_CullTransparentMesh: 1 +--- !u!1 &2015159264 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2015159267} + - component: {fileID: 2015159266} + - component: {fileID: 2015159265} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &2015159265 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2015159264} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_SendPointerHoverToParent: 1 + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &2015159266 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2015159264} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &2015159267 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2015159264} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &2091685446 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2091685447} + - component: {fileID: 2091685449} + - component: {fileID: 2091685448} + m_Layer: 5 + m_Name: AIImage + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2091685447 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2091685446} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 887085509} + m_Father: {fileID: 1084608231} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: -197.7609} + m_SizeDelta: {x: 400, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &2091685448 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2091685446} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.53662825, g: 0.53662825, b: 0.9029823, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &2091685449 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2091685446} + m_CullTransparentMesh: 1 +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 726528679} + - {fileID: 909474453} + - {fileID: 158550917} + - {fileID: 2015159267} + - {fileID: 1047848255} + - {fileID: 498662972} + - {fileID: 107963746} diff --git a/Samples~/AndroidDemo/Scene.unity.meta b/Samples~/AndroidDemo/Scene.unity.meta new file mode 100644 index 00000000..124260ce --- /dev/null +++ b/Samples~/AndroidDemo/Scene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 15abb96f71f7fc08db7606aa88332b00 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/SimpleInteraction/Scene.unity b/Samples~/SimpleInteraction/Scene.unity index 9e41c779..ab87b112 100644 --- a/Samples~/SimpleInteraction/Scene.unity +++ b/Samples~/SimpleInteraction/Scene.unity @@ -221,9 +221,9 @@ MonoBehaviour: m_UiScaleMode: 1 m_ReferencePixelsPerUnit: 100 m_ScaleFactor: 1 - m_ReferenceResolution: {x: 1280, y: 720} + m_ReferenceResolution: {x: 720, y: 720} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 0.5 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -1041,14 +1041,15 @@ MonoBehaviour: port: 13333 numThreads: -1 numGPULayers: 0 - debug: 0 + debug: 1 parallelPrompts: -1 asynchronousStartup: 1 dontDestroyOnLoad: 1 - model: + model: smol_llama-220m-openhermes.q4_k_m.gguf lora: contextSize: 0 batchSize: 512 + basePrompt: SelectedModel: 0 modelProgress: 1 modelCopyProgress: 1 diff --git a/Samples~/SimpleInteraction/SimpleInteraction.cs b/Samples~/SimpleInteraction/SimpleInteraction.cs index 9c088c3b..95d22133 100644 --- a/Samples~/SimpleInteraction/SimpleInteraction.cs +++ b/Samples~/SimpleInteraction/SimpleInteraction.cs @@ -9,11 +9,21 @@ public class SimpleInteraction : MonoBehaviour public LLMCharacter llmCharacter; public InputField playerText; public Text AIText; + int cores; void Start() { playerText.onSubmit.AddListener(onInputFieldSubmit); - playerText.Select(); + playerText.interactable = false; + cores = LLMUnitySetup.AndroidGetNumBigCores(); + AIText.text = $"Warming up the model...\nWill use {cores} cores"; + _ = llmCharacter.Warmup(WarmupDone); + } + + void WarmupDone() + { + AIText.text = $"Ready when you are ({cores} cores)!"; + AIReplyComplete(); } void onInputFieldSubmit(string message) diff --git a/Tests/Runtime/TestLLM.cs b/Tests/Runtime/TestLLM.cs index 60947fcc..e997a327 100644 --- a/Tests/Runtime/TestLLM.cs +++ b/Tests/Runtime/TestLLM.cs @@ -32,8 +32,8 @@ public async Task Init() string modelUrl = "https://huggingface.co/afrideva/smol_llama-220M-openhermes-GGUF/resolve/main/smol_llama-220m-openhermes.q4_k_m.gguf?download=true"; string modelPath = "LLMUnityTests/smol_llama-220m-openhermes.q4_k_m.gguf"; string fullModelPath = LLMUnitySetup.GetAssetPath(modelPath); - _ = LLMUnitySetup.DownloadFile(modelUrl, fullModelPath, false, null, null, false); - await llm.SetModel(fullModelPath); + await LLMUnitySetup.DownloadFile(modelUrl, fullModelPath, false, null, null); + llm.SetModel(fullModelPath); llm.parallelPrompts = 1; llm.SetTemplate("alpaca"); llm.asynchronousStartup = false;