From 4c03cd488f044dd3c03df8452399bfe31f743ddc Mon Sep 17 00:00:00 2001 From: Thomas Simonini Date: Tue, 19 Sep 2023 10:50:08 +0200 Subject: [PATCH 001/161] Initial commit --- LICENSE | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 2 + 2 files changed, 203 insertions(+) create mode 100644 LICENSE create mode 100644 README.md diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 00000000..e15a1749 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# sharp-transformers +A Unity plugin for using Transformers models in Unity. From d8fee0f41c57b43ede9ccc5c5d523600a96445a9 Mon Sep 17 00:00:00 2001 From: Thomas Simonini Date: Tue, 19 Sep 2023 11:01:25 +0200 Subject: [PATCH 002/161] =?UTF-8?q?Add=20the=20first=20version=20of=20Shar?= =?UTF-8?q?p=20Transformers=20=F0=9F=A5=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 +- Runtime.meta | 8 + Runtime/Tokenizers 1.meta | 8 + Runtime/Tokenizers 1/Decoders.meta | 8 + Runtime/Tokenizers 1/Decoders/Decoders.cs | 359 ++++++++++++++++++ .../Tokenizers 1/Decoders/Decoders.cs.meta | 11 + Runtime/Tokenizers 1/Normalizers.meta | 8 + .../Tokenizers 1/Normalizers/Normalizers.cs | 319 ++++++++++++++++ .../Normalizers/Normalizers.cs.meta | 11 + .../Normalizers/NormalizersUtils.cs | 34 ++ .../Normalizers/NormalizersUtils.cs.meta | 11 + Runtime/Tokenizers 1/PostProcessors.meta | 8 + .../PostProcessors/PostProcessors.cs | 150 ++++++++ .../PostProcessors/PostProcessors.cs.meta | 11 + Runtime/Tokenizers 1/PreTokenizers.meta | 8 + .../PreTokenizers/PreTokenizers.cs | 148 ++++++++ .../PreTokenizers/PreTokenizers.cs.meta | 11 + Runtime/Tokenizers 1/Processors.meta | 8 + Runtime/Tokenizers 1/Processors/Processors.cs | 46 +++ .../Processors/Processors.cs.meta | 11 + Runtime/Tokenizers 1/Tokenizers.meta | 8 + Runtime/Tokenizers 1/Tokenizers/Tokenizers.cs | 293 ++++++++++++++ .../Tokenizers/Tokenizers.cs.meta | 11 + .../Tokenizers/TokenizersUtils.cs | 34 ++ .../Tokenizers/TokenizersUtils.cs.meta | 11 + package.json | 17 + package.json.meta | 7 + 27 files changed, 1565 insertions(+), 2 deletions(-) create mode 100644 Runtime.meta create mode 100644 Runtime/Tokenizers 1.meta create mode 100644 Runtime/Tokenizers 1/Decoders.meta create mode 100644 Runtime/Tokenizers 1/Decoders/Decoders.cs create mode 100644 Runtime/Tokenizers 1/Decoders/Decoders.cs.meta create mode 100644 Runtime/Tokenizers 1/Normalizers.meta create mode 100644 Runtime/Tokenizers 1/Normalizers/Normalizers.cs create mode 100644 Runtime/Tokenizers 1/Normalizers/Normalizers.cs.meta create mode 100644 Runtime/Tokenizers 1/Normalizers/NormalizersUtils.cs create mode 100644 Runtime/Tokenizers 1/Normalizers/NormalizersUtils.cs.meta create mode 100644 Runtime/Tokenizers 1/PostProcessors.meta create mode 100644 Runtime/Tokenizers 1/PostProcessors/PostProcessors.cs create mode 100644 Runtime/Tokenizers 1/PostProcessors/PostProcessors.cs.meta create mode 100644 Runtime/Tokenizers 1/PreTokenizers.meta create mode 100644 Runtime/Tokenizers 1/PreTokenizers/PreTokenizers.cs create mode 100644 Runtime/Tokenizers 1/PreTokenizers/PreTokenizers.cs.meta create mode 100644 Runtime/Tokenizers 1/Processors.meta create mode 100644 Runtime/Tokenizers 1/Processors/Processors.cs create mode 100644 Runtime/Tokenizers 1/Processors/Processors.cs.meta create mode 100644 Runtime/Tokenizers 1/Tokenizers.meta create mode 100644 Runtime/Tokenizers 1/Tokenizers/Tokenizers.cs create mode 100644 Runtime/Tokenizers 1/Tokenizers/Tokenizers.cs.meta create mode 100644 Runtime/Tokenizers 1/Tokenizers/TokenizersUtils.cs create mode 100644 Runtime/Tokenizers 1/Tokenizers/TokenizersUtils.cs.meta create mode 100644 package.json create mode 100644 package.json.meta diff --git a/README.md b/README.md index e15a1749..783b83be 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,6 @@ -# sharp-transformers -A Unity plugin for using Transformers models in Unity. +# Sharp Transformers 💪 +A Unity plugin of utilities to **run Transformer 🤗 models in Unity games**. + +Sharp transformers is designed to be **functionally equivalent to Hugging Face’s [transformers python library]**(https://github.com/huggingface/transformers/tree/main). + + diff --git a/Runtime.meta b/Runtime.meta new file mode 100644 index 00000000..12f807bc --- /dev/null +++ b/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ee34b6c1a13a3ce40bb28c59b8233afb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Tokenizers 1.meta b/Runtime/Tokenizers 1.meta new file mode 100644 index 00000000..d39e2588 --- /dev/null +++ b/Runtime/Tokenizers 1.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f155bd1e6d684224b8b1bdb62a54b146 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Tokenizers 1/Decoders.meta b/Runtime/Tokenizers 1/Decoders.meta new file mode 100644 index 00000000..9270db52 --- /dev/null +++ b/Runtime/Tokenizers 1/Decoders.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dfaa37218e5057f439ccd4bb28d51771 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Tokenizers 1/Decoders/Decoders.cs b/Runtime/Tokenizers 1/Decoders/Decoders.cs new file mode 100644 index 00000000..1ab1b820 --- /dev/null +++ b/Runtime/Tokenizers 1/Decoders/Decoders.cs @@ -0,0 +1,359 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using System.Text; +using System.Text.RegularExpressions; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Linq; +using NormalizersUtils; + + +namespace Decoders_ +{ + class Decoder_ + { + public JObject Config; + public List AddedTokens; + public string EndOfWordSuffix; + public string TrimOffsets; + + + /// + /// Creates an instance of `Decoder`. + /// + /// The configuration object. + public Decoder_(JObject config) + { + Config = config; + AddedTokens = new List(); + EndOfWordSuffix = null; + TrimOffsets = null; // config.trim_offsets + } + + + /// + /// Creates a decoder instance based on the provided configuration. + /// + /// The configuration object. + /// A decoder instance. + /// If an unknown decoder type is provided. + public static Decoder_ FromConfig(JObject config) + { + string configType = config["type"].ToString(); + + switch (configType) + { + /*case "WordPiece": + return new WordPieceDecoder(config);*/ + case "Sequence": + return new DecoderSequence(config); + default: + throw new Exception("Unknown Decoder type"); + } + } + + + /// + /// Apply the decoder to a list of tokens. + /// + /// The list of tokens. + /// The decoded list of tokens. + /// If the `decode_chain` method is not implemented in the subclass. + public virtual List DecodeChain(List tokens) + { + throw new Exception("`decode_chain` should be implemented in subclass."); + } + + /// + /// Method to be implemented in subclass to apply post-processing on the given tokens. + /// + /// The list of tokens. + /// The decoded string. + public virtual List Decode(List tokens) + { + return tokens; //string.Join("", DecodeChain(tokens)); + } + + + /// + /// Alias for Decode method + /// + /// The list of tokens. + /// The decoded string. + public List Call(List tokens) + { + return Decode(tokens); + } + } + + + + /// + /// A decoder that decodes a list of WordPiece tokens into a single string. + /// + /*class WordPieceDecoder : Decoder + { + + public JObject Config; + public string Prefix; + public bool Cleanup; + + /// + /// Creates a new instance of WordPieceDecoder. + /// + /// The configuration object. + public WordPieceDecoder(JObject config, string prefix) : base(config) + { + Config = config; + Prefix = prefix; + // Whether to cleanup the decoded string. + Cleanup = (bool)config["cleanup"]; + + /*Clean up a list of simple English tokenization artifacts like spaces before punctuations and abbreviated forms + AddedTokens = new List(); + EndOfWordSuffix = null; + TrimOffsets = null; // config.trim_offsets + + } + + + /// + /// DecodeChain + /// + /// + /// + public List DecodeChain(List tokens) + { + List decodedTokens = new List(); + + for (int i = 0; i < tokens.Count; i++) + { + string token = tokens[i]; + + if (i != 0) + { + if (token.StartsWith(this.config.prefix)) // You will need to replace 'config.prefix' with the appropriate value + { + // NOTE: .Replace() is intended; only replace first occurrence + token = token.Replace(this.config.prefix, ""); + } + else + { + token = " " + token; + } + } + + if (this.Cleanup) + { + token = CleanUpTokenization(token); + } + + decodedTokens.Add(token); + } + + return decodedTokens; + } + +}*/ + + class ReplaceDecoder : Decoder_ + { + public ReplaceDecoder(JObject config) : base(config) + { + } + public override List DecodeChain(List tokens) + { + string pattern = Utils.createPattern(this.Config["pattern"]); + + if (pattern == null) + { + return tokens; + } + + // Iterate through each token in tokens array. Replacing all occurences of specified pattern + // with the content defined the configuration and returning a new array with modified tokens. + // We use LINQ's Select method to transform each element of the tokens list. + return tokens.Select(token => token.Replace(pattern, this.Config["content"].Value())).ToList(); + } + } + + + /// + /// Fuse all tokens into one big string + /// Usually it's the last decoding step but this + /// decoder exist in case some decoders need to happen after that step + /// + class FuseDecoder : Decoder_ + { + public FuseDecoder(JObject config) : base(config) + { + } + + public override List DecodeChain(List tokens) + { + return new List { string.Concat(tokens) }; + } + } + + + /// + /// Handle tokens that represent bytes in hexadecimal format + /// and convert them back into their corresponding string representations + /// + class ByteFallback : Decoder_ + { + public ByteFallback(JObject config) : base(config) + { + } + + private readonly UTF8Encoding uTF8Encoding = new UTF8Encoding(); + + public override List DecodeChain(List tokens) + { + var newTokens = new List(); + var previousByteTokens = new List(); + + foreach (var token in tokens) + { + byte? bytes = null; + // We check if a token is in the <0xXX> format (where XX is a hexadecimal byte) and try to parse it to a byte + if (token.Length == 6 && token.StartsWith("<0x") && token.EndsWith(">")) + { + if (byte.TryParse(token.Substring(3, 2), System.Globalization.NumberStyles.HexNumber, null, out byte byteValue)) + { + bytes = byteValue; + } + } + // If successful we add it to previousByteTokens + if (bytes != null) + { + previousByteTokens.Add(bytes.Value); + } + else + { + // If a token is not in the byte format, we check if there are any bytes in previousByteTokens, decode them into a string, add it to newTokens, and clear previousByteTokens. + if (previousByteTokens.Count > 0) + { + var decodedString = uTF8Encoding.GetString(previousByteTokens.ToArray()); + newTokens.Add(decodedString); + previousByteTokens.Clear(); + } + + newTokens.Add(token); + } + } + + if (previousByteTokens.Count > 0) + { + var decodedString = uTF8Encoding.GetString(previousByteTokens.ToArray()); + newTokens.Add(decodedString); + previousByteTokens.Clear(); + } + + return newTokens; + } + + } + + /// + /// Strip character from the beginning and end of tokens. + /// + class StripDecoder : Decoder_ + { + private readonly string content; + private readonly int start; + private readonly int stop; + + public StripDecoder(JObject config) : base(config) + { + + this.content = this.Config["content"].Value(); + this.start = this.Config["start"].Value(); + this.stop = this.Config["stop"].Value(); + } + + public override List Decode(List tokens) + { + return tokens.Select(token => + { + int startCut = 0; + for (int i = 0; i < start; ++i) + { + if (token[i] == content[0]) + { + startCut = i + 1; + continue; + } + else + { + break; + } + } + + int stopCut = token.Length; + for (int i = 0; i < stop; ++i) + { + int index = token.Length - i - 1; + if (token[index] == content[0]) + { + stopCut = index; + continue; + } + else + { + break; + } + } + + return token.Substring(startCut, stopCut - startCut); + }).ToList(); + } +} + + + /// + /// Apply a sequence of decoders + /// + class DecoderSequence : Decoder_ + { + public List Decoders; + public JObject Config; + + public DecoderSequence(JObject config) : base(config) + { + if (config == null) + { + throw new ArgumentNullException(nameof(config)); + } + if (config["decoders"] == null) + { + throw new ArgumentException("No decoders in Sequence"); + } + + Decoders = new List(); + + foreach (JObject decoderConfig in config["decoders"]) + { + + var decoder = Decoder_.FromConfig(decoderConfig); + + if (decoder != null) + { + Decoders.Add(decoder); + } + } + } + + /// + /// Use this method to apply each decoder to the tokens + /// + /// + /// + public List DecodeChain(List tokens) + { + return this.Decoders.Aggregate(tokens, (currentTokens, decoder) => decoder.DecodeChain(currentTokens)); + } + } +} diff --git a/Runtime/Tokenizers 1/Decoders/Decoders.cs.meta b/Runtime/Tokenizers 1/Decoders/Decoders.cs.meta new file mode 100644 index 00000000..d6c75849 --- /dev/null +++ b/Runtime/Tokenizers 1/Decoders/Decoders.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1dd3b44cc9f949b4cae51dd57cd82a2e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Tokenizers 1/Normalizers.meta b/Runtime/Tokenizers 1/Normalizers.meta new file mode 100644 index 00000000..62a15813 --- /dev/null +++ b/Runtime/Tokenizers 1/Normalizers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fad6f750d7f60fb4a8f58df2a7d98ef7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Tokenizers 1/Normalizers/Normalizers.cs b/Runtime/Tokenizers 1/Normalizers/Normalizers.cs new file mode 100644 index 00000000..aff73483 --- /dev/null +++ b/Runtime/Tokenizers 1/Normalizers/Normalizers.cs @@ -0,0 +1,319 @@ +using UnityEngine; +using Unity.Sentis; + +using System; +using System.Text; +using System.Text.RegularExpressions; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +using NormalizersUtils; + + +namespace Normalizers +{ + /// + /// A base class for text normalization. + /// + public abstract class Normalizer + { + public JObject Config; + + // Constructor initializes Config property with the value of the config + // parameter + public Normalizer(JObject config) + { + Config = config; + } + + /// + /// Factory method for creating normalizers from config objects. + /// Returns A Normalizer object. + /// + /// The configuration object for the normalizer. + /// + public static Normalizer FromConfig(JObject config) + { + if (config == null) + return null; + + string configType = config["type"].ToString(); + switch (configType) + { + case "BertNormalizer": + return new BertNormalizer(config); + case "Sequence": + return new NormalizerSequence(config); + case "Replace": + return new Replace(config); + case "Prepend": + return new Prepend(config); + default: + throw new Exception($"Unknown Normalizer type: {configType}"); + } + } + + /// + /// Normalize the input text. + /// + /// The normalized text. + /// + public virtual string Normalize(string text) + { + throw new Exception("Normalize should be implemented in subclass."); + } + + /// + /// Alias for Normalizer.Normalize + /// + /// The normalized text. + /// + public string Call(string text) + { + return Normalize(text); // Call the Normalize method + } + } + + + /// + /// A BertNormalizer class (inherited from Normalizer) for text normalization. + /// + class BertNormalizer : Normalizer + { + public BertNormalizer(JObject config) : base(config) + { + + } + + /// + /// Adds whitespace around any CJK (Chinese, Japanese, or Korean) character in the input text. + /// + /// The input text to tokenize. + /// The tokenized text with whitespace added around CJK characters. + public string TokenizeChineseChars(string text) + { + // Adds whitespace around any CJK character. + StringBuilder output = new StringBuilder(); + + for (int i = 0; i < text.Length; i++) + { + char character = text[i]; + // Used to convert the character to its Unicode code point. + int unicodeCodePoint = Char.ConvertToUtf32(character.ToString(), 0); + + if (IsChineseChar(unicodeCodePoint)) + { + output.Append(" "); + output.Append(character); + output.Append(" "); + } + else + { + output.Append(character); + } + + } + return output.ToString(); + } + + /// + /// Checks whether the given Unicode codepoint represents a CJK (Chinese, Japanese, or Korean) character. + /// + /// A "chinese character" is defined as anything in the CJK Unicode block: + /// https://en.wikipedia.org/wiki/CJK_Unified_Ideographs_(Unicode_block) + /// + /// Note that the CJK Unicode block is NOT all Japanese and Korean characters, despite its name. + /// The modern Korean Hangul alphabet is a different block, as is Japanese Hiragana and Katakana. + /// Those alphabets are used to write space-separated words, so they are not treated specially + /// and are handled like all other languages. + /// + /// + /// The Unicode codepoint to check. + /// True if the codepoint represents a CJK character, false otherwise. + public bool IsChineseChar(int unicodeCodePoint) + { + return (unicodeCodePoint >= 0x4E00 && unicodeCodePoint <= 0x9FFF) || + (unicodeCodePoint >= 0x3400 && unicodeCodePoint <= 0x4DBF) || + (unicodeCodePoint >= 0x20000 && unicodeCodePoint <= 0x2A6DF) || + (unicodeCodePoint >= 0x2A700 && unicodeCodePoint <= 0x2B73F) || + (unicodeCodePoint >= 0x2B740 && unicodeCodePoint <= 0x2B81F) || + (unicodeCodePoint >= 0x2B820 && unicodeCodePoint <= 0x2CEAF) || + (unicodeCodePoint >= 0xF900 && unicodeCodePoint <= 0xFAFF) || + (unicodeCodePoint >= 0x2F800 && unicodeCodePoint <= 0x2FA1F); + } + + /// + /// Strips accents from the given text. + /// + /// The text to strip accents from. + /// The text with accents removed. + public string StripAccents(string text) + { + // Normalize used is NFD: NFD (Normalization Form Canonical Decomposition): + // Characters are decomposed into their constituent parts. + // For example, a character with a diacritic is split into a base character and a + // separate diacritic character. + // ## NFD is NormalizationForm.FormD + // Then we replace accents (regex) with "" + return Regex.Replace(text.Normalize(NormalizationForm.FormD), @"[\u0300-\u036f]", ""); + } + + /// + /// Normalizes the given text based on the configuration. + /// + /// The text to normalize. + /// The normalized text. + public new string Normalize(string text) + { + // TODO use rest of config + + + // In C# we need to check first if it's null or not + bool? handleChineseCharsValue = (bool?)Config["handle_chinese_chars"]; + bool? handleLowercaseValue = (bool?)Config["lowercase"]; + bool? handleStripAccentsValue = (bool?)Config["strip_accents"]; + + if (handleChineseCharsValue == true) + text = this.TokenizeChineseChars(text); + + if (handleLowercaseValue == true) + { + // Lowercase + text = text.ToLower(); + + // If not explicitly set to false == true + if (handleStripAccentsValue == null || handleStripAccentsValue == true) + text = this.StripAccents(text); + } + // If lowercase is false but strip accents is true + else if (handleLowercaseValue == true) + { + text = this.StripAccents(text); + } + return text; + } + } + + + + class NormalizerSequence : Normalizer + { + public List Normalizers; + public JObject Config; + + /// + /// Create a new instance of NormalizerSequence + /// + /// The configuration object + /// + /// + public NormalizerSequence(JObject config): base(config) + { + string jsonString = config.ToString(); + + if (config == null) + { + throw new ArgumentNullException(nameof(config)); + } + if (config["normalizers"] == null) + { + throw new ArgumentException("No normalizers in Sequence"); + } + + Normalizers = new List(); + + foreach (JObject normalizerConfig in config["normalizers"]) + { + var normalizer = Normalizer.FromConfig(normalizerConfig); + + //var normalizer = new Normalizer.FromConfig(normalizerConfig); + if (normalizer != null) + { + //string normalizerString = normalizerConfig.Value(); + Normalizers.Add(normalizer); + } + } + } + + + /// + /// Apply a sequence of Normalizes to the input text. + /// + /// The text to normalize + /// The normalized text + /// + public string Normalize(string text) + { + if (text == null) + { + throw new ArgumentNullException(nameof(text)); + } + + foreach (var normalizer in Normalizers) + { + text = normalizer.Normalize(text); + } + return text; + } + } + + /// + /// A Normalizer that prepends a string to the input string + /// This is a nice day => _This is a nice day + /// + class Prepend : Normalizer + { + public Prepend(JObject config) : base(config) + { + + } + + /// + /// Prepends the input string + /// + /// The text to normalize + /// The normalized text + public override string Normalize(string text) + { + string text_ = this.Config["prepend"].Value() + text; + return text_; + } + } + + + /// + /// Replace normalizer that replaces occurrences of a pattern + /// with a given string or regular expression. + /// + class Replace : Normalizer + { + public Replace(JObject config) : base(config) + { + + } + + /// + /// Normalize the input text by replacing the pattern with the content. + /// For instance in Llama 2 we replace " " with _ + /// + /// Input text to be normalized + /// The normalized text after replacing the pattern with the content. + public override string Normalize(string text) + { + string pattern = Utils.createPattern(this.Config["pattern"]); + + if (pattern == null) + { + return text; + } + + text = text.Replace(pattern, this.Config["content"].Value()); + + return text; + } + } +} \ No newline at end of file diff --git a/Runtime/Tokenizers 1/Normalizers/Normalizers.cs.meta b/Runtime/Tokenizers 1/Normalizers/Normalizers.cs.meta new file mode 100644 index 00000000..e6066465 --- /dev/null +++ b/Runtime/Tokenizers 1/Normalizers/Normalizers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 283388f2c6f5e2a43b888d135bce4ec9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Tokenizers 1/Normalizers/NormalizersUtils.cs b/Runtime/Tokenizers 1/Normalizers/NormalizersUtils.cs new file mode 100644 index 00000000..6d5898cc --- /dev/null +++ b/Runtime/Tokenizers 1/Normalizers/NormalizersUtils.cs @@ -0,0 +1,34 @@ +using UnityEngine; + +using System; +using System.Collections; +using System.Collections.Generic; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + + +namespace NormalizersUtils +{ + public static class Utils + { + public static string createPattern(JToken pattern, bool invert = true) + { + // Execute when pattern.Regex is defined + if (pattern["Regex"] != null) + { + // Todo + return null; + } + else if (pattern["String"] != null) + { + return pattern["String"].Value(); + } + else + { + throw new Exception($"Unknown pattern type: {pattern}"); + return null; + } + } + } +} \ No newline at end of file diff --git a/Runtime/Tokenizers 1/Normalizers/NormalizersUtils.cs.meta b/Runtime/Tokenizers 1/Normalizers/NormalizersUtils.cs.meta new file mode 100644 index 00000000..8c11f339 --- /dev/null +++ b/Runtime/Tokenizers 1/Normalizers/NormalizersUtils.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9c845d6e172ac0244b6694ef44561927 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Tokenizers 1/PostProcessors.meta b/Runtime/Tokenizers 1/PostProcessors.meta new file mode 100644 index 00000000..cc82bf74 --- /dev/null +++ b/Runtime/Tokenizers 1/PostProcessors.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ff3a9ed5fc14c6e4ca0ad60d88cac601 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Tokenizers 1/PostProcessors/PostProcessors.cs b/Runtime/Tokenizers 1/PostProcessors/PostProcessors.cs new file mode 100644 index 00000000..b7d86490 --- /dev/null +++ b/Runtime/Tokenizers 1/PostProcessors/PostProcessors.cs @@ -0,0 +1,150 @@ +using UnityEngine; +using Unity.Sentis; +using Unity.Sentis.Layers; + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using System.Linq; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + + +namespace PostProcessors +{ + public abstract class PostProcessor + { + public JObject Config; + + public PostProcessor(JObject config) + { + Config = config; + } + + /// + /// Factory method to create a PostProcessor object from a configuration object. + /// + /// Configuration object representing a PostProcessor. + /// A PostProcessor object created from the given configuration. + /// + public static PostProcessor FromConfig(JObject config) + { + if (config == null) + { + return null; + } + + string configType = config["type"].ToString(); + + switch (configType) + { + case "TemplateProcessing": + return new TemplateProcessing(config); + default: + throw new Exception("Unknown PostProcessor type"); + } + } + + + /// + /// Method to be implemented in subclass to apply post-processing on the given tokens. + /// + /// The input tokens to be post-processed. + /// The post-processed tokens. + public virtual List PostProcess(List tokens, List tokensPair = null) + { + throw new Exception("PostProcess should be implemented in subclass."); + } + + + /// + /// Alias for PostProcess + /// + /// The text or array of texts to post-process. + /// An array of post-processed tokens. + public virtual List Call(List tokens, List tokensPair = null) + { + return PostProcess(tokens); + } + } + + /// + /// Post processor that replaces special tokens in a template with actual tokens. + /// + class TemplateProcessing : PostProcessor + { + public JObject Config; + + // The template for a single sequence of tokens. + public JArray Single; + + //public List Single; + + // The template for a pair of sequences of tokens. + public JArray Pair; + + //public List Pair; + + /// + /// Creates a new instance of TemplateProcessing + /// + /// + public TemplateProcessing(JObject config) : base(config) + { + Config = config; + Single = (JArray)config["single"]; + Pair = (JArray)config["pair"]; + } + + // The function's purpose is to replace special tokens and sequence identifiers with actual tokens. + public override List PostProcess(List tokens, List tokensPair = null) + { + // Check the type of sequence (based on if tokensPair is provided or not) + // If tokensPair is null => assign Single to Type + // Else assign Pair to Type + JArray Type = tokensPair == null ? Single : Pair; + + // Create an empty List to store the resulting tokens after processing + List ToReturn = new List(); + + // The function iterates over each item in the Type List + foreach (JToken item in Type) + { + JObject itemJson = (JObject)item; + + // If the curent item has a property called "Special Token" + // it means that this item is a special token. + if (itemJson.ContainsKey("SpecialToken")) + { + // We extracts the id of the special token and adds it to the toReturn List. + // We need to parse the JSON string and extract the id here + string specialTokenId = (string)itemJson["SpecialToken"]["id"]; + ToReturn.Add(specialTokenId); + } + + // If the current item has a property called "Sequence" it means that this item + // represents a sequence identifier (like 'A' or 'B') + else if (itemJson.ContainsKey("Sequence")) + { + string sequenceId = (string)itemJson["Sequence"]["id"]; + if (sequenceId == "A") + { + // Add the elements of another collection to the list + // Equivalent to merge in JS + // Merge sequence tokens + ToReturn.AddRange(tokens); + } + else if (sequenceId == "B") + { + // Merge tokens_pair + ToReturn.AddRange(tokensPair); + } + } + } + return ToReturn; + } + } +} \ No newline at end of file diff --git a/Runtime/Tokenizers 1/PostProcessors/PostProcessors.cs.meta b/Runtime/Tokenizers 1/PostProcessors/PostProcessors.cs.meta new file mode 100644 index 00000000..fe5e0e12 --- /dev/null +++ b/Runtime/Tokenizers 1/PostProcessors/PostProcessors.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b8764350c45eda044b8590b67708d9a0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Tokenizers 1/PreTokenizers.meta b/Runtime/Tokenizers 1/PreTokenizers.meta new file mode 100644 index 00000000..056533ce --- /dev/null +++ b/Runtime/Tokenizers 1/PreTokenizers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b35b4bc4c790ddc40b31fd2731127547 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Tokenizers 1/PreTokenizers/PreTokenizers.cs b/Runtime/Tokenizers 1/PreTokenizers/PreTokenizers.cs new file mode 100644 index 00000000..a099ca46 --- /dev/null +++ b/Runtime/Tokenizers 1/PreTokenizers/PreTokenizers.cs @@ -0,0 +1,148 @@ +using UnityEngine; +using Unity.Sentis; +using Unity.Sentis.Layers; + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using System.Linq; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + + +namespace PreTokenizers +{ + /// + /// A callable class representing a pre-tokenizer used in tokenization. Subclasses + /// should implement the `pre_tokenize_text` method to define the specific pre-tokenization logic. + /// + public class PreTokenizer + { + public JObject Config; + + + public PreTokenizer(JObject config) + { + Config = config; + } + + /// + /// Factory method that returns an instance of a subclass of `PreTokenizer` based on the provided configuration. + /// + /// A configuration object for the pre-tokenizer. + /// An instance of a subclass of `PreTokenizer`. + /// If the provided configuration object does not correspond to any known pre-tokenizer. + public static PreTokenizer FromConfig(JObject config) + { + if (config == null) + return null; + + string configType = config["type"].ToString(); + switch (configType) + { + + case "BertPreTokenizer": + return new BertPreTokenizer(config); + default: + throw new Exception($"Unknown PreTokenizer type: {configType}"); + } + } + + /// + /// Method that should be implemented by subclasses to define the specific pre-tokenization logic. + /// + /// The text to pre-tokenize. + /// The pre-tokenized text. + /// + public virtual List PreTokenizeText(string text) + { + throw new Exception("PreTokenizeText should be implemented in subclass."); + } + + /// + /// Tokenizes the given text into pre-tokens. + /// + /// The text or array of texts to pre-tokenize. + /// A list of pre-tokens + public List PreTokenize(object text) + { + + List result = new List(); + + if (text is string textString) + { + // Else if 'text' is not a list, tokenize it directly using 'pre_tokenize_text' + //result.Add(PreTokenizeText(textString)); + result.AddRange(PreTokenizeText(textString)); + } + else if (text is List textList) + { + // If 'text' is List select each element and tokenize it using 'pre_tokenize_text' + //result = textList.Select(x => PreTokenizeText(x)).ToList(); + result = textList.SelectMany(x => PreTokenizeText(x)).ToList(); + } + else + { + throw new ArgumentException("Unsupported parameter type"); + } + // Flatten the 'result' list of lists and return a flat list + //return result.SelectMany(x => x).ToList(); + return result; + } + + + /// + /// Alias for PreTokenizer.PreTokenize + /// + /// The text or array of texts to pre-tokenize. + /// An array of pre-tokens. + public List Call(string text) + { + return PreTokenize(text); + } + } + + + class BertPreTokenizer : PreTokenizer + { + private readonly Regex pattern; + + /// + /// A PreTokenizer that splits text into wordpieces using a basic tokenization scheme + /// similar to that used in the original implementation of BERT. + /// + + public BertPreTokenizer(JObject config) : base(config) + { + // Construct a pattern which matches the rust implementation: + // https://github.com/huggingface/tokenizers/blob/b4fcc9ce6e4ad5806e82826f816acfdfdc4fcc67/tokenizers/src/pre_tokenizers/bert.rs#L11 + // Equivalent to removing whitespace and splitting on punctuation (both \p{P} and other ASCII characters) + string punctuationRegex = "\\p{P}"; + this.pattern = new Regex($"[^\\s{punctuationRegex}]+|[{punctuationRegex}]", RegexOptions.Compiled | RegexOptions.Multiline); + + } + + /// + /// Tokenizes a single text using the BERT pre-tokenization scheme. + /// We use Array instead of list (for test purposes) + /// + /// The text to tokenize. + /// An array of tokens. + /// TODO: See how we can optimize it + public override List PreTokenizeText(string text) + { + var matches = this.pattern.Matches(text.Trim()); + var tokens = new List(); + + foreach (Match match in matches) + { + tokens.Add(match.Value); + } + + return tokens; + } + } +} \ No newline at end of file diff --git a/Runtime/Tokenizers 1/PreTokenizers/PreTokenizers.cs.meta b/Runtime/Tokenizers 1/PreTokenizers/PreTokenizers.cs.meta new file mode 100644 index 00000000..a16abfa2 --- /dev/null +++ b/Runtime/Tokenizers 1/PreTokenizers/PreTokenizers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 246eac9077f2a1e4495389919d3cf007 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Tokenizers 1/Processors.meta b/Runtime/Tokenizers 1/Processors.meta new file mode 100644 index 00000000..bf2c2c8e --- /dev/null +++ b/Runtime/Tokenizers 1/Processors.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2b7b3327e92aa3741b37995a0d0b6e62 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Tokenizers 1/Processors/Processors.cs b/Runtime/Tokenizers 1/Processors/Processors.cs new file mode 100644 index 00000000..89d43d24 --- /dev/null +++ b/Runtime/Tokenizers 1/Processors/Processors.cs @@ -0,0 +1,46 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + + +public class Processors : MonoBehaviour +{ + // Start is called before the first frame update + void Start() + { + + } + + +} + +/* +/// +/// Base class for feature extractors. +/// +public abstract class FeatureExtractor +{ + public JObject Config; + + /// + /// Constructs a new FeatureExtractor instance. + /// + /// + public FeatureExtractor(JObject config) + { + Config = config; + } +} + +class WhisperFeatureExtractor: FeatureExtractor +{ + public JObject config; + + public WhisperFeatureExtractor(JObject config) : base(config) + { + Config = config; + + } +}*/ \ No newline at end of file diff --git a/Runtime/Tokenizers 1/Processors/Processors.cs.meta b/Runtime/Tokenizers 1/Processors/Processors.cs.meta new file mode 100644 index 00000000..0eeb6285 --- /dev/null +++ b/Runtime/Tokenizers 1/Processors/Processors.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1537782cb945e7446bac869d93f3d05e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Tokenizers 1/Tokenizers.meta b/Runtime/Tokenizers 1/Tokenizers.meta new file mode 100644 index 00000000..af184795 --- /dev/null +++ b/Runtime/Tokenizers 1/Tokenizers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 50d9fbcf8d5c3ec4a83bc04ff97d77b2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Tokenizers 1/Tokenizers/Tokenizers.cs b/Runtime/Tokenizers 1/Tokenizers/Tokenizers.cs new file mode 100644 index 00000000..65b3a54d --- /dev/null +++ b/Runtime/Tokenizers 1/Tokenizers/Tokenizers.cs @@ -0,0 +1,293 @@ +using UnityEngine; +using Unity.Sentis; +using Unity.Sentis.Layers; + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using System.Linq; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +using Normalizers; +using PostProcessors; +using Decoders_; +using PreTokenizers; + + +namespace Tokenizers +{ + public abstract class TokenizerModel + { + public JObject Config; + public JObject TokenizerData; + public List Vocab; + public Dictionary TokensToIds; + public int? UnkTokenId; // Thanks to int?, the variable can hold an integer value or be null + public string UnkToken; + public string EndOfWordSuffix; + public bool FuseUnk; + + public int UnknownTokenId { get; set; } = -1; + public string UnknownToken { get; set; } + public bool FuseUnknown { get; set; } = false; + + public TokenizerModel(JObject config) + { + Config = config; + Vocab = new List(); + + // Dict of tokens to ids Dict + TokensToIds = new Dictionary(); + + UnkTokenId = null; + UnkToken = null; + EndOfWordSuffix = null; + + // Whether to fuse unknown tokens when encoding (default to false) + FuseUnk = false; + } + + // Overload if we have multiple parameters + public TokenizerModel(JObject config, JObject tokenizerData) + { + Config = config; + TokenizerData = tokenizerData; + Vocab = new List(); + + // Dict of tokens to ids Dict + TokensToIds = new Dictionary(); + + UnkTokenId = null; + UnkToken = null; + EndOfWordSuffix = null; + + // Whether to fuse unknown tokens when encoding (default to false) + FuseUnk = false; + } + + + /// + /// Instantiates a new TokenizerModel instance based on the configuration object provided. + /// + /// The configuration object for the TokenizerModel. + /// A new instance of a TokenizerModel. + /// Will throw an error if the TokenizerModel type in the config is not recognized. + public static TokenizerModel FromConfig(JObject config, JObject tokenizerData) + { + string configType = config["type"].ToString(); + switch (configType) + { + case "WordPiece": + return new WordPieceTokenizer(config); + default: + throw new Exception($"Unknown TokenizerModel type: {configType}"); + } + } + + /// + /// Internal function to call the TokenizerModel instance. + /// + /// The tokens to encode. + /// + public List Call(List tokens) + { + return Encode(tokens); + } + + + /// + /// Encodes a list of tokens into a list of token IDs. + /// + /// The tokens to encode. + /// The encoded tokens. + public virtual List Encode(List tokens) + { + throw new Exception("Encode should be implemented in subclass"); + } + + + /// + /// Converts a list of tokens into a list of token IDs. + /// + /// The tokens to convert. + /// The converted token IDs. + public List ConvertTokensToIds(List tokens) + { + // Create an array of token IDs by mapping each token to its corresponding ID + List ids = new List(); + + //Debug.Log("Dictionary Contents:"); + foreach (var kvp in TokensToIds) + { + Debug.Log($"Key: {kvp.Key}, Value: {kvp.Value}"); + } + + // token.Select: applies an operation to each token in tokens + ids = tokens.Select(t => TokensToIds.TryGetValue(t, out int id) ? id : UnknownTokenId).ToList(); + + + + if (FuseUnk == false) + { + //ids = Fuse(ids, UnkTokenId); + ids = TokenizersUtils.Utils.Fuse(ids, UnkTokenId ?? -1); + } + + return ids; + } + + + /// + /// Converts a list of token IDs into a list of tokens. + /// + /// The token IDs to convert. + /// The converted tokens. + public List ConvertIdsToTokens(List ids) + { + /* + Select is used instead of map to transform the list of IDs into a list of tokens. + The conditional operator (? :) is used to check if the ID is within the valid range of the vocab array. If it is, the code retrieves the corresponding token using this.vocab[i]. If the token is null, it uses this.unk_token as the default value. + The resulting list of tokens is returned. + */ + List tokens = ids.Select(i => Vocab.Count > i ? Vocab[i] ?? UnkToken : UnkToken).ToList(); + return tokens; + } + + + public List Fuse(List arr, int value) + { + List fused = new List(); + int i = 0; + while (i < arr.Count) + { + fused.Add(arr[i]); + if (arr[i] != value) + { + i++; + continue; + } + + while (i < arr.Count && arr[i] == value) + { + i++; + } + } + + return fused; + } + } + + + class WordPieceTokenizer : TokenizerModel + { + public JObject Config; + public List Vocab; + public Dictionary TokensToIds; + public int? UnkTokenId; // Thanks to int?, the variable can hold an integer value or be null + public string UnkToken; + public string ContinuingSubwordPrefix; + + public WordPieceTokenizer(JObject config) : base(config) + { + Config = config; + + // Parse the JSON data located at config["vocab"] into a Dictionary named vocab. + // Each key-value pair in the JSON will be represented as an entry in the dictionary. + JObject vocabJson = config["vocab"].ToObject(); + + // A mapping of tokens to ids. + TokensToIds = vocabJson.ToObject>(); + + // Id of the unknown token + UnkTokenId = (int)config["vocab"]["[UNK]"]; + + // The unknown token string. + UnkToken = (string)config["unk_token"]; + + ContinuingSubwordPrefix = (string)config["continuing_subword_prefix"]; + } + + + /// + /// Encodes an array of tokens using WordPiece encoding. + /// + /// The tokens to encode. + /// An array of encoded tokens. + public List Encode(List tokens) + { + // Initialize a List to store the encoded tokens + var OutputTokens = new List(); + + foreach (var token in tokens) + { + // Convert the token into an array of characters + var Chars = token.ToCharArray(); + + // Initialize a flag to track whether the token is unknown + var IsUnknown = false; + + // Initialize the starting index for substring search + var Start = 0; + + // Initialize an List to store subtokens of the token + var SubTokens = new List(); + + while (Start < Chars.Length) + { + var End = Chars.Length; + + // Initialize a variable to store the current substring + string CurrentSubstring = null; + + while (Start < End) + { + // Get a substring from the character array + var Substr = new string(Chars.Skip(Start).Take(End - Start).ToArray()); + + if (Start > 0) + { + // Add a prefix to the substring if not the first character + Substr = ContinuingSubwordPrefix + Substr; + } + + // Check if the substring is in the vocabulary + if (TokensToIds.ContainsKey(Substr)) + { + // Store the current substring + CurrentSubstring = Substr; + break; + } + // Decrease the end index for substring search + --End; + } + if (CurrentSubstring == null) + { + // Set the flag to indicate that the token is unknown + IsUnknown = true; + break; + } + // Add the current substring to the subtokens List + SubTokens.Add(CurrentSubstring); + // Move the start index to the end index for the next iteration + Start = End; + } + if (IsUnknown) + { + // If token is unknown, add the unknown token to the output List + OutputTokens.Add(UnkToken); + } + else + { + // If token is not unknown, add the subtokens to the output List + OutputTokens.AddRange(SubTokens); + } + } + // Return the List of encoded tokens + return OutputTokens; + } + } +} \ No newline at end of file diff --git a/Runtime/Tokenizers 1/Tokenizers/Tokenizers.cs.meta b/Runtime/Tokenizers 1/Tokenizers/Tokenizers.cs.meta new file mode 100644 index 00000000..cb260fb6 --- /dev/null +++ b/Runtime/Tokenizers 1/Tokenizers/Tokenizers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eedb6ea96035cb042ac0de141a387438 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Tokenizers 1/Tokenizers/TokenizersUtils.cs b/Runtime/Tokenizers 1/Tokenizers/TokenizersUtils.cs new file mode 100644 index 00000000..42e3656a --- /dev/null +++ b/Runtime/Tokenizers 1/Tokenizers/TokenizersUtils.cs @@ -0,0 +1,34 @@ +using UnityEngine; + +using System.Collections; +using System.Collections.Generic; +using System.Linq; + + +namespace TokenizersUtils +{ + public static class Utils + { + public static List Fuse(List arr, int value) + { + List fused = new List(); + int i = 0; + while (i < arr.Count) + { + fused.Add(arr[i]); + if (arr[i] != value) + { + i++; + continue; + } + + while (i < arr.Count && arr[i] == value) + { + i++; + } + } + + return fused; + } + } +} \ No newline at end of file diff --git a/Runtime/Tokenizers 1/Tokenizers/TokenizersUtils.cs.meta b/Runtime/Tokenizers 1/Tokenizers/TokenizersUtils.cs.meta new file mode 100644 index 00000000..a10ddbf1 --- /dev/null +++ b/Runtime/Tokenizers 1/Tokenizers/TokenizersUtils.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 11ba52b374864af4aa62c82b4f3d92b1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package.json b/package.json new file mode 100644 index 00000000..62ed3ad3 --- /dev/null +++ b/package.json @@ -0,0 +1,17 @@ +{ + "name": "com.huggingface.sharp-transformers", + "displayName": "Hugging Face Sharp Transformers", + "version": "0.0.1", + "unity": "2020.3", + "description": "A Unity plugin for using Transformers models in Unity.", + "keywords": ["huggingface", "llm", "AI"], + "author": { + "name": "Thomas Simonini", + "email": "thomas.simonini@huggingface.co", + "url": "https://github.com/huggingface/sharp-transformers" + }, + "dependencies": { + "com.unity.nuget.newtonsoft-json": "3.2.1", + "com.unity.sentis": "1.1.0" + } +} \ No newline at end of file diff --git a/package.json.meta b/package.json.meta new file mode 100644 index 00000000..0882735f --- /dev/null +++ b/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 5d09fabafa75bd14aba7b139d2379b45 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From 4756671859978fd441f3162d838267f35450f2c6 Mon Sep 17 00:00:00 2001 From: Thomas Simonini Date: Tue, 19 Sep 2023 11:08:16 +0200 Subject: [PATCH 003/161] Remove Sentis from dependencies Sentis is for now a preview package, so we can't install it from dependencies --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 62ed3ad3..741ebb85 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,6 @@ "url": "https://github.com/huggingface/sharp-transformers" }, "dependencies": { - "com.unity.nuget.newtonsoft-json": "3.2.1", - "com.unity.sentis": "1.1.0" + "com.unity.nuget.newtonsoft-json": "3.2.1" } } \ No newline at end of file From 331bd713d3bfdfbf0812a89d37c805aed24656d5 Mon Sep 17 00:00:00 2001 From: Thomas Simonini Date: Tue, 19 Sep 2023 11:14:32 +0200 Subject: [PATCH 004/161] Add the meta files --- README.md.meta | 7 +++++++ package.json | 16 ---------------- 2 files changed, 7 insertions(+), 16 deletions(-) create mode 100644 README.md.meta delete mode 100644 package.json diff --git a/README.md.meta b/README.md.meta new file mode 100644 index 00000000..99d2061f --- /dev/null +++ b/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b0ec1865350d9eb4e8f442d1d2d6a24c +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package.json b/package.json deleted file mode 100644 index 741ebb85..00000000 --- a/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "com.huggingface.sharp-transformers", - "displayName": "Hugging Face Sharp Transformers", - "version": "0.0.1", - "unity": "2020.3", - "description": "A Unity plugin for using Transformers models in Unity.", - "keywords": ["huggingface", "llm", "AI"], - "author": { - "name": "Thomas Simonini", - "email": "thomas.simonini@huggingface.co", - "url": "https://github.com/huggingface/sharp-transformers" - }, - "dependencies": { - "com.unity.nuget.newtonsoft-json": "3.2.1" - } -} \ No newline at end of file From cd13ed65211224f6e6c2b858da9aef9984bf9034 Mon Sep 17 00:00:00 2001 From: Thomas Simonini Date: Tue, 19 Sep 2023 11:17:31 +0200 Subject: [PATCH 005/161] Add package.json --- package.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 package.json diff --git a/package.json b/package.json new file mode 100644 index 00000000..741ebb85 --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "com.huggingface.sharp-transformers", + "displayName": "Hugging Face Sharp Transformers", + "version": "0.0.1", + "unity": "2020.3", + "description": "A Unity plugin for using Transformers models in Unity.", + "keywords": ["huggingface", "llm", "AI"], + "author": { + "name": "Thomas Simonini", + "email": "thomas.simonini@huggingface.co", + "url": "https://github.com/huggingface/sharp-transformers" + }, + "dependencies": { + "com.unity.nuget.newtonsoft-json": "3.2.1" + } +} \ No newline at end of file From 654788de969a49be480fe8bb604c32e51ee556eb Mon Sep 17 00:00:00 2001 From: Thomas Simonini Date: Tue, 19 Sep 2023 11:46:37 +0200 Subject: [PATCH 006/161] Update namespace We created HuggingFace.SharpTransformers namespace. This ensure a clean import --- Runtime/Tokenizers 1/Processors.meta | 8 ---- Runtime/Tokenizers 1/Processors/Processors.cs | 46 ------------------- .../Processors/Processors.cs.meta | 11 ----- .../{Tokenizers 1.meta => Tokenizers.meta} | 2 +- .../Decoders.meta | 0 .../Decoders/Decoders.cs | 13 ++++-- .../Decoders/Decoders.cs.meta | 0 .../Normalizers.meta | 0 .../Normalizers/Normalizers.cs | 4 +- .../Normalizers/Normalizers.cs.meta | 0 .../Normalizers/NormalizersUtils.cs | 2 +- .../Normalizers/NormalizersUtils.cs.meta | 0 .../PostProcessors.meta | 0 .../PostProcessors/PostProcessors.cs | 2 +- .../PostProcessors/PostProcessors.cs.meta | 0 .../PreTokenizers.meta | 0 .../PreTokenizers/PreTokenizers.cs | 2 +- .../PreTokenizers/PreTokenizers.cs.meta | 0 .../Tokenizers.meta | 0 .../Tokenizers/Tokenizers.cs | 10 ++-- .../Tokenizers/Tokenizers.cs.meta | 0 .../Tokenizers/TokenizersUtils.cs | 0 .../Tokenizers/TokenizersUtils.cs.meta | 0 23 files changed, 19 insertions(+), 81 deletions(-) delete mode 100644 Runtime/Tokenizers 1/Processors.meta delete mode 100644 Runtime/Tokenizers 1/Processors/Processors.cs delete mode 100644 Runtime/Tokenizers 1/Processors/Processors.cs.meta rename Runtime/{Tokenizers 1.meta => Tokenizers.meta} (77%) rename Runtime/{Tokenizers 1 => Tokenizers}/Decoders.meta (100%) rename Runtime/{Tokenizers 1 => Tokenizers}/Decoders/Decoders.cs (99%) rename Runtime/{Tokenizers 1 => Tokenizers}/Decoders/Decoders.cs.meta (100%) rename Runtime/{Tokenizers 1 => Tokenizers}/Normalizers.meta (100%) rename Runtime/{Tokenizers 1 => Tokenizers}/Normalizers/Normalizers.cs (99%) rename Runtime/{Tokenizers 1 => Tokenizers}/Normalizers/Normalizers.cs.meta (100%) rename Runtime/{Tokenizers 1 => Tokenizers}/Normalizers/NormalizersUtils.cs (92%) rename Runtime/{Tokenizers 1 => Tokenizers}/Normalizers/NormalizersUtils.cs.meta (100%) rename Runtime/{Tokenizers 1 => Tokenizers}/PostProcessors.meta (100%) rename Runtime/{Tokenizers 1 => Tokenizers}/PostProcessors/PostProcessors.cs (98%) rename Runtime/{Tokenizers 1 => Tokenizers}/PostProcessors/PostProcessors.cs.meta (100%) rename Runtime/{Tokenizers 1 => Tokenizers}/PreTokenizers.meta (100%) rename Runtime/{Tokenizers 1 => Tokenizers}/PreTokenizers/PreTokenizers.cs (98%) rename Runtime/{Tokenizers 1 => Tokenizers}/PreTokenizers/PreTokenizers.cs.meta (100%) rename Runtime/{Tokenizers 1 => Tokenizers}/Tokenizers.meta (100%) rename Runtime/{Tokenizers 1 => Tokenizers}/Tokenizers/Tokenizers.cs (97%) rename Runtime/{Tokenizers 1 => Tokenizers}/Tokenizers/Tokenizers.cs.meta (100%) rename Runtime/{Tokenizers 1 => Tokenizers}/Tokenizers/TokenizersUtils.cs (100%) rename Runtime/{Tokenizers 1 => Tokenizers}/Tokenizers/TokenizersUtils.cs.meta (100%) diff --git a/Runtime/Tokenizers 1/Processors.meta b/Runtime/Tokenizers 1/Processors.meta deleted file mode 100644 index bf2c2c8e..00000000 --- a/Runtime/Tokenizers 1/Processors.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 2b7b3327e92aa3741b37995a0d0b6e62 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Tokenizers 1/Processors/Processors.cs b/Runtime/Tokenizers 1/Processors/Processors.cs deleted file mode 100644 index 89d43d24..00000000 --- a/Runtime/Tokenizers 1/Processors/Processors.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - - -public class Processors : MonoBehaviour -{ - // Start is called before the first frame update - void Start() - { - - } - - -} - -/* -/// -/// Base class for feature extractors. -/// -public abstract class FeatureExtractor -{ - public JObject Config; - - /// - /// Constructs a new FeatureExtractor instance. - /// - /// - public FeatureExtractor(JObject config) - { - Config = config; - } -} - -class WhisperFeatureExtractor: FeatureExtractor -{ - public JObject config; - - public WhisperFeatureExtractor(JObject config) : base(config) - { - Config = config; - - } -}*/ \ No newline at end of file diff --git a/Runtime/Tokenizers 1/Processors/Processors.cs.meta b/Runtime/Tokenizers 1/Processors/Processors.cs.meta deleted file mode 100644 index 0eeb6285..00000000 --- a/Runtime/Tokenizers 1/Processors/Processors.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 1537782cb945e7446bac869d93f3d05e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Tokenizers 1.meta b/Runtime/Tokenizers.meta similarity index 77% rename from Runtime/Tokenizers 1.meta rename to Runtime/Tokenizers.meta index d39e2588..ed9e7a0d 100644 --- a/Runtime/Tokenizers 1.meta +++ b/Runtime/Tokenizers.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: f155bd1e6d684224b8b1bdb62a54b146 +guid: cea6c6340e93848499966a81102c9e95 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Runtime/Tokenizers 1/Decoders.meta b/Runtime/Tokenizers/Decoders.meta similarity index 100% rename from Runtime/Tokenizers 1/Decoders.meta rename to Runtime/Tokenizers/Decoders.meta diff --git a/Runtime/Tokenizers 1/Decoders/Decoders.cs b/Runtime/Tokenizers/Decoders/Decoders.cs similarity index 99% rename from Runtime/Tokenizers 1/Decoders/Decoders.cs rename to Runtime/Tokenizers/Decoders/Decoders.cs index 1ab1b820..8b62f73b 100644 --- a/Runtime/Tokenizers 1/Decoders/Decoders.cs +++ b/Runtime/Tokenizers/Decoders/Decoders.cs @@ -1,16 +1,19 @@ +using System; using System.Collections; using System.Collections.Generic; -using UnityEngine; using System.Text; using System.Text.RegularExpressions; +using System.Linq; + +using UnityEngine; + using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using System; -using System.Linq; -using NormalizersUtils; + +using HuggingFace.SharpTransformers.NormalizersUtils; -namespace Decoders_ +namespace HuggingFace.SharpTransformers.Decoders { class Decoder_ { diff --git a/Runtime/Tokenizers 1/Decoders/Decoders.cs.meta b/Runtime/Tokenizers/Decoders/Decoders.cs.meta similarity index 100% rename from Runtime/Tokenizers 1/Decoders/Decoders.cs.meta rename to Runtime/Tokenizers/Decoders/Decoders.cs.meta diff --git a/Runtime/Tokenizers 1/Normalizers.meta b/Runtime/Tokenizers/Normalizers.meta similarity index 100% rename from Runtime/Tokenizers 1/Normalizers.meta rename to Runtime/Tokenizers/Normalizers.meta diff --git a/Runtime/Tokenizers 1/Normalizers/Normalizers.cs b/Runtime/Tokenizers/Normalizers/Normalizers.cs similarity index 99% rename from Runtime/Tokenizers 1/Normalizers/Normalizers.cs rename to Runtime/Tokenizers/Normalizers/Normalizers.cs index aff73483..7cc87f18 100644 --- a/Runtime/Tokenizers 1/Normalizers/Normalizers.cs +++ b/Runtime/Tokenizers/Normalizers/Normalizers.cs @@ -11,10 +11,10 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using NormalizersUtils; +using HuggingFace.SharpTransformers.NormalizersUtils; -namespace Normalizers +namespace HuggingFace.SharpTransformers.Normalizers { /// /// A base class for text normalization. diff --git a/Runtime/Tokenizers 1/Normalizers/Normalizers.cs.meta b/Runtime/Tokenizers/Normalizers/Normalizers.cs.meta similarity index 100% rename from Runtime/Tokenizers 1/Normalizers/Normalizers.cs.meta rename to Runtime/Tokenizers/Normalizers/Normalizers.cs.meta diff --git a/Runtime/Tokenizers 1/Normalizers/NormalizersUtils.cs b/Runtime/Tokenizers/Normalizers/NormalizersUtils.cs similarity index 92% rename from Runtime/Tokenizers 1/Normalizers/NormalizersUtils.cs rename to Runtime/Tokenizers/Normalizers/NormalizersUtils.cs index 6d5898cc..65810a3c 100644 --- a/Runtime/Tokenizers 1/Normalizers/NormalizersUtils.cs +++ b/Runtime/Tokenizers/Normalizers/NormalizersUtils.cs @@ -8,7 +8,7 @@ using Newtonsoft.Json.Linq; -namespace NormalizersUtils +namespace HuggingFace.SharpTransformers.NormalizersUtils { public static class Utils { diff --git a/Runtime/Tokenizers 1/Normalizers/NormalizersUtils.cs.meta b/Runtime/Tokenizers/Normalizers/NormalizersUtils.cs.meta similarity index 100% rename from Runtime/Tokenizers 1/Normalizers/NormalizersUtils.cs.meta rename to Runtime/Tokenizers/Normalizers/NormalizersUtils.cs.meta diff --git a/Runtime/Tokenizers 1/PostProcessors.meta b/Runtime/Tokenizers/PostProcessors.meta similarity index 100% rename from Runtime/Tokenizers 1/PostProcessors.meta rename to Runtime/Tokenizers/PostProcessors.meta diff --git a/Runtime/Tokenizers 1/PostProcessors/PostProcessors.cs b/Runtime/Tokenizers/PostProcessors/PostProcessors.cs similarity index 98% rename from Runtime/Tokenizers 1/PostProcessors/PostProcessors.cs rename to Runtime/Tokenizers/PostProcessors/PostProcessors.cs index b7d86490..b9f514fd 100644 --- a/Runtime/Tokenizers 1/PostProcessors/PostProcessors.cs +++ b/Runtime/Tokenizers/PostProcessors/PostProcessors.cs @@ -13,7 +13,7 @@ using Newtonsoft.Json.Linq; -namespace PostProcessors +namespace HuggingFace.SharpTransformers.PostProcessors { public abstract class PostProcessor { diff --git a/Runtime/Tokenizers 1/PostProcessors/PostProcessors.cs.meta b/Runtime/Tokenizers/PostProcessors/PostProcessors.cs.meta similarity index 100% rename from Runtime/Tokenizers 1/PostProcessors/PostProcessors.cs.meta rename to Runtime/Tokenizers/PostProcessors/PostProcessors.cs.meta diff --git a/Runtime/Tokenizers 1/PreTokenizers.meta b/Runtime/Tokenizers/PreTokenizers.meta similarity index 100% rename from Runtime/Tokenizers 1/PreTokenizers.meta rename to Runtime/Tokenizers/PreTokenizers.meta diff --git a/Runtime/Tokenizers 1/PreTokenizers/PreTokenizers.cs b/Runtime/Tokenizers/PreTokenizers/PreTokenizers.cs similarity index 98% rename from Runtime/Tokenizers 1/PreTokenizers/PreTokenizers.cs rename to Runtime/Tokenizers/PreTokenizers/PreTokenizers.cs index a099ca46..0c3d4847 100644 --- a/Runtime/Tokenizers 1/PreTokenizers/PreTokenizers.cs +++ b/Runtime/Tokenizers/PreTokenizers/PreTokenizers.cs @@ -13,7 +13,7 @@ using Newtonsoft.Json.Linq; -namespace PreTokenizers +namespace HuggingFace.SharpTransformers.PreTokenizers { /// /// A callable class representing a pre-tokenizer used in tokenization. Subclasses diff --git a/Runtime/Tokenizers 1/PreTokenizers/PreTokenizers.cs.meta b/Runtime/Tokenizers/PreTokenizers/PreTokenizers.cs.meta similarity index 100% rename from Runtime/Tokenizers 1/PreTokenizers/PreTokenizers.cs.meta rename to Runtime/Tokenizers/PreTokenizers/PreTokenizers.cs.meta diff --git a/Runtime/Tokenizers 1/Tokenizers.meta b/Runtime/Tokenizers/Tokenizers.meta similarity index 100% rename from Runtime/Tokenizers 1/Tokenizers.meta rename to Runtime/Tokenizers/Tokenizers.meta diff --git a/Runtime/Tokenizers 1/Tokenizers/Tokenizers.cs b/Runtime/Tokenizers/Tokenizers/Tokenizers.cs similarity index 97% rename from Runtime/Tokenizers 1/Tokenizers/Tokenizers.cs rename to Runtime/Tokenizers/Tokenizers/Tokenizers.cs index 65b3a54d..ccd68112 100644 --- a/Runtime/Tokenizers 1/Tokenizers/Tokenizers.cs +++ b/Runtime/Tokenizers/Tokenizers/Tokenizers.cs @@ -12,13 +12,13 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using Normalizers; -using PostProcessors; -using Decoders_; -using PreTokenizers; +using HuggingFace.SharpTransformers.Normalizers; +using HuggingFace.SharpTransformers.PostProcessors; +using HuggingFace.SharpTransformers.Decoders; +using HuggingFace.SharpTransformers.PreTokenizers; -namespace Tokenizers +namespace HuggingFace.SharpTransformers.Tokenizers { public abstract class TokenizerModel { diff --git a/Runtime/Tokenizers 1/Tokenizers/Tokenizers.cs.meta b/Runtime/Tokenizers/Tokenizers/Tokenizers.cs.meta similarity index 100% rename from Runtime/Tokenizers 1/Tokenizers/Tokenizers.cs.meta rename to Runtime/Tokenizers/Tokenizers/Tokenizers.cs.meta diff --git a/Runtime/Tokenizers 1/Tokenizers/TokenizersUtils.cs b/Runtime/Tokenizers/Tokenizers/TokenizersUtils.cs similarity index 100% rename from Runtime/Tokenizers 1/Tokenizers/TokenizersUtils.cs rename to Runtime/Tokenizers/Tokenizers/TokenizersUtils.cs diff --git a/Runtime/Tokenizers 1/Tokenizers/TokenizersUtils.cs.meta b/Runtime/Tokenizers/Tokenizers/TokenizersUtils.cs.meta similarity index 100% rename from Runtime/Tokenizers 1/Tokenizers/TokenizersUtils.cs.meta rename to Runtime/Tokenizers/Tokenizers/TokenizersUtils.cs.meta From 4c01b06ec27f5848650ca601f7f20a9de50ee670 Mon Sep 17 00:00:00 2001 From: Thomas Simonini Date: Tue, 19 Sep 2023 12:04:10 +0200 Subject: [PATCH 007/161] Add assembly definition for HuggingFace.SharpTransformers --- Runtime/HuggingFace.SharpTransformers.asmdef | 3 +++ Runtime/HuggingFace.SharpTransformers.asmdef.meta | 7 +++++++ 2 files changed, 10 insertions(+) create mode 100644 Runtime/HuggingFace.SharpTransformers.asmdef create mode 100644 Runtime/HuggingFace.SharpTransformers.asmdef.meta diff --git a/Runtime/HuggingFace.SharpTransformers.asmdef b/Runtime/HuggingFace.SharpTransformers.asmdef new file mode 100644 index 00000000..f0bd709c --- /dev/null +++ b/Runtime/HuggingFace.SharpTransformers.asmdef @@ -0,0 +1,3 @@ +{ + "name": "HuggingFace.SharpTransformers" +} diff --git a/Runtime/HuggingFace.SharpTransformers.asmdef.meta b/Runtime/HuggingFace.SharpTransformers.asmdef.meta new file mode 100644 index 00000000..f27e4a98 --- /dev/null +++ b/Runtime/HuggingFace.SharpTransformers.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e498adf2b0e1d8b47871ffa1278544a0 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From 971b2c2ebbbe36c6138190476961885c4272a4ec Mon Sep 17 00:00:00 2001 From: Thomas Simonini Date: Tue, 19 Sep 2023 12:16:42 +0200 Subject: [PATCH 008/161] Remove sentis requirements --- Runtime/Tokenizers/Normalizers/Normalizers.cs | 1 - Runtime/Tokenizers/PostProcessors/PostProcessors.cs | 2 -- Runtime/Tokenizers/PreTokenizers/PreTokenizers.cs | 2 -- Runtime/Tokenizers/Tokenizers/Tokenizers.cs | 2 -- 4 files changed, 7 deletions(-) diff --git a/Runtime/Tokenizers/Normalizers/Normalizers.cs b/Runtime/Tokenizers/Normalizers/Normalizers.cs index 7cc87f18..a46f34f7 100644 --- a/Runtime/Tokenizers/Normalizers/Normalizers.cs +++ b/Runtime/Tokenizers/Normalizers/Normalizers.cs @@ -1,5 +1,4 @@ using UnityEngine; -using Unity.Sentis; using System; using System.Text; diff --git a/Runtime/Tokenizers/PostProcessors/PostProcessors.cs b/Runtime/Tokenizers/PostProcessors/PostProcessors.cs index b9f514fd..3a45dc02 100644 --- a/Runtime/Tokenizers/PostProcessors/PostProcessors.cs +++ b/Runtime/Tokenizers/PostProcessors/PostProcessors.cs @@ -1,6 +1,4 @@ using UnityEngine; -using Unity.Sentis; -using Unity.Sentis.Layers; using System; using System.Collections; diff --git a/Runtime/Tokenizers/PreTokenizers/PreTokenizers.cs b/Runtime/Tokenizers/PreTokenizers/PreTokenizers.cs index 0c3d4847..7e9a3a4d 100644 --- a/Runtime/Tokenizers/PreTokenizers/PreTokenizers.cs +++ b/Runtime/Tokenizers/PreTokenizers/PreTokenizers.cs @@ -1,6 +1,4 @@ using UnityEngine; -using Unity.Sentis; -using Unity.Sentis.Layers; using System; using System.Collections; diff --git a/Runtime/Tokenizers/Tokenizers/Tokenizers.cs b/Runtime/Tokenizers/Tokenizers/Tokenizers.cs index ccd68112..1e81f369 100644 --- a/Runtime/Tokenizers/Tokenizers/Tokenizers.cs +++ b/Runtime/Tokenizers/Tokenizers/Tokenizers.cs @@ -1,6 +1,4 @@ using UnityEngine; -using Unity.Sentis; -using Unity.Sentis.Layers; using System; using System.Collections; From 7bc8aea61b829af9bda4af331884134e544a483e Mon Sep 17 00:00:00 2001 From: Thomas Simonini Date: Tue, 19 Sep 2023 13:43:12 +0200 Subject: [PATCH 009/161] Set classes to public since protection level block the access of these --- Runtime/Tokenizers/Normalizers/Normalizers.cs | 6 +++--- Runtime/Tokenizers/PostProcessors/PostProcessors.cs | 2 +- Runtime/Tokenizers/PreTokenizers/PreTokenizers.cs | 2 +- Runtime/Tokenizers/Tokenizers/Tokenizers.cs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Runtime/Tokenizers/Normalizers/Normalizers.cs b/Runtime/Tokenizers/Normalizers/Normalizers.cs index a46f34f7..fd061a24 100644 --- a/Runtime/Tokenizers/Normalizers/Normalizers.cs +++ b/Runtime/Tokenizers/Normalizers/Normalizers.cs @@ -81,7 +81,7 @@ public string Call(string text) /// /// A BertNormalizer class (inherited from Normalizer) for text normalization. /// - class BertNormalizer : Normalizer + public class BertNormalizer : Normalizer { public BertNormalizer(JObject config) : base(config) { @@ -199,7 +199,7 @@ public string StripAccents(string text) - class NormalizerSequence : Normalizer + public class NormalizerSequence : Normalizer { public List Normalizers; public JObject Config; @@ -264,7 +264,7 @@ public string Normalize(string text) /// A Normalizer that prepends a string to the input string /// This is a nice day => _This is a nice day /// - class Prepend : Normalizer + public class Prepend : Normalizer { public Prepend(JObject config) : base(config) { diff --git a/Runtime/Tokenizers/PostProcessors/PostProcessors.cs b/Runtime/Tokenizers/PostProcessors/PostProcessors.cs index 3a45dc02..a9513ebf 100644 --- a/Runtime/Tokenizers/PostProcessors/PostProcessors.cs +++ b/Runtime/Tokenizers/PostProcessors/PostProcessors.cs @@ -72,7 +72,7 @@ public virtual List Call(List tokens, List tokensPair = /// /// Post processor that replaces special tokens in a template with actual tokens. /// - class TemplateProcessing : PostProcessor + public class TemplateProcessing : PostProcessor { public JObject Config; diff --git a/Runtime/Tokenizers/PreTokenizers/PreTokenizers.cs b/Runtime/Tokenizers/PreTokenizers/PreTokenizers.cs index 7e9a3a4d..42b6d033 100644 --- a/Runtime/Tokenizers/PreTokenizers/PreTokenizers.cs +++ b/Runtime/Tokenizers/PreTokenizers/PreTokenizers.cs @@ -104,7 +104,7 @@ public List Call(string text) } - class BertPreTokenizer : PreTokenizer + public class BertPreTokenizer : PreTokenizer { private readonly Regex pattern; diff --git a/Runtime/Tokenizers/Tokenizers/Tokenizers.cs b/Runtime/Tokenizers/Tokenizers/Tokenizers.cs index 1e81f369..ddf53190 100644 --- a/Runtime/Tokenizers/Tokenizers/Tokenizers.cs +++ b/Runtime/Tokenizers/Tokenizers/Tokenizers.cs @@ -180,7 +180,7 @@ public List Fuse(List arr, int value) } - class WordPieceTokenizer : TokenizerModel + public class WordPieceTokenizer : TokenizerModel { public JObject Config; public List Vocab; From 595d76b730131b6f9385621b674b451f4abe7346 Mon Sep 17 00:00:00 2001 From: Thomas Simonini Date: Tue, 19 Sep 2023 15:57:00 +0200 Subject: [PATCH 010/161] Update Tokenizers --- Runtime/Tokenizers/Tokenizers/Tokenizers.cs | 57 +++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/Runtime/Tokenizers/Tokenizers/Tokenizers.cs b/Runtime/Tokenizers/Tokenizers/Tokenizers.cs index ddf53190..95b71333 100644 --- a/Runtime/Tokenizers/Tokenizers/Tokenizers.cs +++ b/Runtime/Tokenizers/Tokenizers/Tokenizers.cs @@ -287,5 +287,62 @@ public List Encode(List tokens) // Return the List of encoded tokens return OutputTokens; } + + /// + /// Converts a list of token IDs into a list of tokens. + /// + /// The token IDs to convert. + /// The converted tokens. + public List ConvertIdsToTokens(List ids) + { + /* + Select is used instead of map to transform the list of IDs into a list of tokens. + The conditional operator (? :) is used to check if the ID is within the valid range of the vocab array. If it is, the code retrieves the corresponding token using this.vocab[i]. If the token is null, it uses this.unk_token as the default value. + The resulting list of tokens is returned. + */ + List tokens = ids.Select(i => Vocab.Count > i ? Vocab[i] ?? UnkToken : UnkToken).ToList(); + return tokens; + } + + public List ConvertTokensToIds(List tokens) + { + // Create an array of token IDs by mapping each token to its corresponding ID + List ids = new List(); + + // token.Select: applies an operation to each token in tokens + ids = tokens.Select(t => TokensToIds.TryGetValue(t, out int id) ? id : UnknownTokenId).ToList(); + + + + if (FuseUnk == false) + { + //ids = Fuse(ids, UnkTokenId); + ids = Fuse(ids, UnkTokenId ?? -1); + } + + return ids; + } + + public List Fuse(List arr, int value) + { + List fused = new List(); + int i = 0; + while (i < arr.Count) + { + fused.Add(arr[i]); + if (arr[i] != value) + { + i++; + continue; + } + + while (i < arr.Count && arr[i] == value) + { + i++; + } + } + + return fused; + } } } \ No newline at end of file From 9a482d64a687173d52be0d97afe654702298ad53 Mon Sep 17 00:00:00 2001 From: Thomas Simonini Date: Wed, 20 Sep 2023 13:49:22 +0200 Subject: [PATCH 011/161] Update README.md --- README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/README.md b/README.md index 783b83be..b863567c 100644 --- a/README.md +++ b/README.md @@ -3,4 +3,32 @@ A Unity plugin of utilities to **run Transformer 🤗 models in Unity games**. Sharp transformers is designed to be **functionally equivalent to Hugging Face’s [transformers python library]**(https://github.com/huggingface/transformers/tree/main). +If you like this library, **don't hesitate to ⭐ star this repository**. This helps us for discoverability 🤗. +## Install with Unity + +In your Unity Project: +1. Go to "Window" > "Package Manager" to open the Package Manager. +2. Click the "+" in the upper left-hand corner and select "Add package from git URL". +3. Enter the URL of this repository and click "Add": https://github.com/huggingface/sharp-transformers.git + +## Quick Tour + +We published a tutorial where you're to build this smart robot that can understand player orders and perform them using a Sentence Similarity Model. + +Jammo the Robot + + +The Tutorial 👉 +The Demo (Windows Executable) 👉 https://singularite.itch.io/jammo-the-robot-with-unity-sentis + +## Supported tasks + +- For now **only BERT models for embedding are supported** but we plan to support more models in the future see roadmap + +## Roadmap 🗺️ + +- [X] Bert Tokenizer +- [ ] Llama 2 Tokenizers (BPE) +- [ ] Whisper Tokenizers and PostProcessing +- [ ] STT Tokenizers From 9e7dfe427d0e61ee64b70c8c96d79f295e366a4f Mon Sep 17 00:00:00 2001 From: Thomas Simonini Date: Wed, 20 Sep 2023 13:51:15 +0200 Subject: [PATCH 012/161] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b863567c..fb0a07ad 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,8 @@ We published a tutorial where you're to build this smart robot that can underst Jammo the Robot -The Tutorial 👉 +The Tutorial 👉 https://open.substack.com/pub/thomassimonini/p/create-an-ai-robot-npc-using-hugging?r=dq5fg&utm_campaign=post&utm_medium=web + The Demo (Windows Executable) 👉 https://singularite.itch.io/jammo-the-robot-with-unity-sentis ## Supported tasks From 577bfe23c286a605f58d328ea991aa4d4d06f4c8 Mon Sep 17 00:00:00 2001 From: Thomas Simonini Date: Thu, 21 Sep 2023 12:34:01 +0200 Subject: [PATCH 013/161] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fb0a07ad..7a2d5346 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Sharp Transformers 💪 +# Sharp Transformers A Unity plugin of utilities to **run Transformer 🤗 models in Unity games**. Sharp transformers is designed to be **functionally equivalent to Hugging Face’s [transformers python library]**(https://github.com/huggingface/transformers/tree/main). From eae7afbc68677c5e49788db800ec410898ceea95 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Wed, 24 Jan 2024 13:02:08 +0200 Subject: [PATCH 014/161] initial experiment --- Runtime/EmbeddingManager.cs | 126 +++++++++++++++++++++++++++++++ Runtime/EmbeddingManager.cs.meta | 11 +++ Runtime/LLMClient.cs | 32 ++++++-- Runtime/LLMInterface.cs | 6 ++ Samples~/ChatBot/Scene.unity | 4 +- 5 files changed, 170 insertions(+), 9 deletions(-) create mode 100644 Runtime/EmbeddingManager.cs create mode 100644 Runtime/EmbeddingManager.cs.meta diff --git a/Runtime/EmbeddingManager.cs b/Runtime/EmbeddingManager.cs new file mode 100644 index 00000000..82ac2a8f --- /dev/null +++ b/Runtime/EmbeddingManager.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using UnityEngine; + +public enum SimilarityType +{ + Cosine, + L2 +} + +public class EmbeddingManager +{ + private List<(string, float[])> embeddings; + private Func> embeddingFunction; + private SimilarityType similarityType; + + public EmbeddingManager(Func> embeddingFunction, SimilarityType similarityType = SimilarityType.L2) + { + this.embeddings = new List<(string, float[])>(); + this.embeddingFunction = embeddingFunction; + this.similarityType = similarityType; + } + + public async Task AddString(string inputString) + { + embeddings.Add((inputString, await embeddingFunction(inputString))); + } + + public async Task> RetrieveMostSimilarStrings(string queryString, int numResults) + { + float[] queryEmbedding = await embeddingFunction(queryString); + List> similarities = new List>(); + + for (int i = 0; i < embeddings.Count; i++) + { + float similarity = CalculateSimilarity(queryEmbedding, embeddings[i].Item2); + similarities.Add(new Tuple<(string, float[]), float>(embeddings[i], similarity)); + } + + similarities.Sort((a, b) => b.Item2.CompareTo(a.Item2)); + + List results = new List(); + for (int i = 0; i < Math.Min(numResults, similarities.Count); i++) + { + results.Add(similarities[i].Item1.Item1); + } + + return results; + } + + private float CalculateSimilarity(float[] vectorA, float[] vectorB) + { + if (similarityType == SimilarityType.Cosine) + { + return CalculateCosineSimilarity(vectorA, vectorB); + } + else if (similarityType == SimilarityType.L2) + { + return CalculateL2Distance(vectorA, vectorB); + } + else + { + throw new NotSupportedException("Unsupported similarity type"); + } + } + + private float CalculateCosineSimilarity(float[] vectorA, float[] vectorB) + { + // Assuming vectors are of the same length + float dotProduct = 0; + float magnitudeA = 0; + float magnitudeB = 0; + + for (int i = 0; i < vectorA.Length; i++) + { + dotProduct += vectorA[i] * vectorB[i]; + magnitudeA += vectorA[i] * vectorA[i]; + magnitudeB += vectorB[i] * vectorB[i]; + } + + float similarity = dotProduct / (float)(Math.Sqrt(magnitudeA) * Math.Sqrt(magnitudeB)); + return similarity; + } + + private float CalculateL2Distance(float[] vectorA, float[] vectorB) + { + float sumOfSquares = 0; + + for (int i = 0; i < vectorA.Length; i++) + { + float diff = vectorA[i] - vectorB[i]; + sumOfSquares += diff * diff; + } + + return Mathf.Sqrt(sumOfSquares); + } + + public void SaveEmbeddingsToFile(string filePath) + { + using (StreamWriter writer = new StreamWriter(filePath)) + { + for (int i = 0; i < embeddings.Count; i++) + { + writer.WriteLine($"{embeddings[i].Item1}|{string.Join(",", embeddings[i].Item2)}"); + } + } + } + + public void LoadEmbeddingsFromFile(string filePath) + { + embeddings.Clear(); + + using (StreamReader reader = new StreamReader(filePath)) + { + while (!reader.EndOfStream) + { + string line = reader.ReadLine(); + string[] parts = line.Split('|'); + embeddings.Add((parts[0], parts[1].Split(',').Select(float.Parse).ToArray())); + } + } + } +} diff --git a/Runtime/EmbeddingManager.cs.meta b/Runtime/EmbeddingManager.cs.meta new file mode 100644 index 00000000..3c2961ca --- /dev/null +++ b/Runtime/EmbeddingManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c8e8b8f5c23ce011fbe3c033c7812057 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/LLMClient.cs b/Runtime/LLMClient.cs index b78c1483..49777996 100644 --- a/Runtime/LLMClient.cs +++ b/Runtime/LLMClient.cs @@ -5,13 +5,13 @@ namespace LLMUnity { - public class ClientAttribute : PropertyAttribute { } - public class ServerAttribute : PropertyAttribute { } - public class ModelAttribute : PropertyAttribute { } - public class ChatAttribute : PropertyAttribute { } - public class ClientAdvancedAttribute : PropertyAttribute { } - public class ServerAdvancedAttribute : PropertyAttribute { } - public class ModelAdvancedAttribute : PropertyAttribute { } + public class ClientAttribute : PropertyAttribute {} + public class ServerAttribute : PropertyAttribute {} + public class ModelAttribute : PropertyAttribute {} + public class ChatAttribute : PropertyAttribute {} + public class ClientAdvancedAttribute : PropertyAttribute {} + public class ServerAdvancedAttribute : PropertyAttribute {} + public class ModelAdvancedAttribute : PropertyAttribute {} [DefaultExecutionOrder(-1)] public class LLMClient : MonoBehaviour @@ -139,6 +139,12 @@ public List TokenizeContent(TokenizeResult result) return result.tokens; } + public List EmbeddingContent(EmbeddingResult result) + { + // get the tokens from a tokenize result received from the endpoint + return result.embedding; + } + public async Task Chat(string question, Callback callback = null, EmptyCallback completionCallback = null, bool addToHistory = true) { // handle a chat message by the user @@ -176,6 +182,18 @@ public async Task Tokenize(string question, Callback> callback = null) await PostRequest>(json, "tokenize", TokenizeContent, callback); } + public async Task> Embedding(string question, Callback> callback = null) + { + // handle the tokenization of a message by the user + // ChatRequest embeddingRequest = new ChatRequest(); + // embeddingRequest.prompt = question; + TokenizeRequest embeddingRequest = new TokenizeRequest(); + embeddingRequest.content = question; + string json = JsonUtility.ToJson(embeddingRequest); + List embedding = await PostRequest>(json, "embedding", EmbeddingContent, callback); + return embedding; + } + private void SetNKeep(List tokens) { // set the tokens to keep diff --git a/Runtime/LLMInterface.cs b/Runtime/LLMInterface.cs index 5584cc8b..ec394ecc 100644 --- a/Runtime/LLMInterface.cs +++ b/Runtime/LLMInterface.cs @@ -102,6 +102,12 @@ public struct TokenizeResult public List tokens; } + [Serializable] + public struct EmbeddingResult + { + public List embedding; + } + [Serializable] public struct ServerStatus { diff --git a/Samples~/ChatBot/Scene.unity b/Samples~/ChatBot/Scene.unity index ccca69d8..84f6ae3d 100644 --- a/Samples~/ChatBot/Scene.unity +++ b/Samples~/ChatBot/Scene.unity @@ -444,7 +444,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: a50e3140c3ecaaf1c848dbf141cc2074, type: 3} m_Name: m_EditorClassIdentifier: - advancedOptions: 0 + advancedOptions: 1 host: localhost port: 13333 stream: 1 @@ -462,7 +462,7 @@ MonoBehaviour: numGPULayers: 0 parallelPrompts: -1 debug: 0 - model: + model: mistral-7b-instruct-v0.1.Q4_K_M.gguf lora: contextSize: 512 batchSize: 512 From 6d04e925590e41e8f09612c1f82f6a67a601d45b Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Wed, 24 Jan 2024 21:19:35 +0200 Subject: [PATCH 015/161] initial working method with Sentis --- Runtime/SentenceSimilarity.cs | 131 ++++++++++ Runtime/SentenceSimilarity.cs.meta | 11 + Runtime/SentenceSimilarityUtils.cs | 323 ++++++++++++++++++++++++ Runtime/SentenceSimilarityUtils.cs.meta | 11 + Runtime/undream.llmunity.Runtime.asmdef | 7 +- 5 files changed, 482 insertions(+), 1 deletion(-) create mode 100644 Runtime/SentenceSimilarity.cs create mode 100644 Runtime/SentenceSimilarity.cs.meta create mode 100644 Runtime/SentenceSimilarityUtils.cs create mode 100644 Runtime/SentenceSimilarityUtils.cs.meta diff --git a/Runtime/SentenceSimilarity.cs b/Runtime/SentenceSimilarity.cs new file mode 100644 index 00000000..030ab35f --- /dev/null +++ b/Runtime/SentenceSimilarity.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using System.Linq; + +using UnityEngine; +using Unity.Sentis; +using Unity.Sentis.Layers; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +using SentenceSimilarityUtils; +using UnityEditor; + + +public class SentenceSimilarity : MonoBehaviour +{ + ModelAsset modelAsset; + public Model runtimeModel; + public IWorker worker; + public ITensorAllocator allocator; + public Ops ops; + + + /// + /// Load the model on awake + /// + public void Awake() + { + // Load the ONNX model + // modelAsset = Resources.Load("StreamingAssets/model.onnx") as ModelAsset; + + // runtimeModel = ModelLoader.Load("Assets/Models/model.onnx"); + runtimeModel = ModelLoader.Load("Assets/StreamingAssets/model.sentis"); + + // Create an engine and set the backend as GPU //GPUCompute + worker = WorkerFactory.CreateWorker(BackendType.CPU, runtimeModel); + + // Create an allocator. + allocator = new TensorCachingAllocator(); + + // Create an operator + ops = WorkerFactory.CreateOps(BackendType.GPUCompute, allocator); + } + + void OnDisable() + { + // Tell the GPU we're finished with the memory the engine used + worker.Dispose(); + } + + /// + /// Encode the input + /// + /// + /// + /// + /// + public TensorFloat Encode(List input, IWorker worker, Ops ops) + { + // Step 1: Tokenize the sentences + Dictionary inputSentencesTokensTensor = SentenceSimilarityUtils_.TokenizeInput(input); + + // Step 2: Compute embedding and get the output + worker.Execute(inputSentencesTokensTensor); + + // Step 3: Get the output from the neural network + TensorFloat outputTensor = worker.PeekOutput("last_hidden_state") as TensorFloat; + + // Step 4: Perform pooling + TensorFloat MeanPooledTensor = SentenceSimilarityUtils_.MeanPooling(inputSentencesTokensTensor["attention_mask"], outputTensor, ops); + + // Step 5: Normalize the results + TensorFloat NormedTensor = SentenceSimilarityUtils_.L2Norm(MeanPooledTensor, ops); + + return NormedTensor; + } + + /// + /// We calculate the similarity scores between the input sequence (what the user typed) and the comparison + /// sequences (the robot action list) + /// This similarity score is simply the cosine similarity. It is calculated as the cosine of the angle between two vectors. + /// It is particularly useful when your texts are not the same length + /// + /// + /// + /// + public TensorFloat SentenceSimilarityScores(TensorFloat InputSequence, TensorFloat ComparisonSequences) + { + TensorFloat SentenceSimilarityScores_ = ops.MatMul2D(InputSequence, ComparisonSequences, false, true); + return SentenceSimilarityScores_; + } + + /// + /// Get the most similar action and its index given the player input + /// + /// + /// + /// + public Tuple RankSimilarityScores(string inputSentence, string[] comparisonSentences) + { + // Step 1: Transform string and string[] to lists + List InputSentences = new List(); + List ComparisonSentences = new List(); + + InputSentences.Add(inputSentence); + ComparisonSentences = comparisonSentences.ToList(); + + // Step 2: Encode the input sentences and comparison sentences + TensorFloat NormEmbedSentences = Encode(InputSentences, worker, ops); + TensorFloat NormEmbedComparisonSentences = Encode(ComparisonSentences, worker, ops); + + // Calculate the similarity score of the player input with each action + TensorFloat scores = SentenceSimilarityScores(NormEmbedSentences, NormEmbedComparisonSentences); + scores.MakeReadable(); // Be able to read this tensor + + // Helper to return only best score and index + TensorInt scoreIndex = ops.ArgMax(scores, 1, true); + scoreIndex.MakeReadable(); + + int scoreIndexInt = scoreIndex[0]; + scores.MakeReadable(); + float score = scores[scoreIndexInt]; + + // Return the similarity score and the action index + return Tuple.Create(scoreIndexInt, score); + } +} diff --git a/Runtime/SentenceSimilarity.cs.meta b/Runtime/SentenceSimilarity.cs.meta new file mode 100644 index 00000000..89d91f19 --- /dev/null +++ b/Runtime/SentenceSimilarity.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bf302ca4cc187e9219e08f41f3f99b7a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SentenceSimilarityUtils.cs b/Runtime/SentenceSimilarityUtils.cs new file mode 100644 index 00000000..e1679c3d --- /dev/null +++ b/Runtime/SentenceSimilarityUtils.cs @@ -0,0 +1,323 @@ +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using System.Linq; + +using UnityEngine; +using Unity.Sentis; +using Unity.Sentis.Layers; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +using HuggingFace.SharpTransformers.Normalizers; +using HuggingFace.SharpTransformers.PreTokenizers; +using HuggingFace.SharpTransformers.Tokenizers; +using HuggingFace.SharpTransformers.PostProcessors; + + +namespace SentenceSimilarityUtils +{ + public static class SentenceSimilarityUtils_ + { + /// + /// Load the Tokenizer JSON + /// This JSON contains the information about how the input should be processed + /// before being feed to the Transformer model + /// + /// + public static JObject LoadTokenizerJson() + { + string tokenizerJsonContent = File.ReadAllText("Assets/StreamingAssets/tokenizer.json"); + + JObject tokenizerJsonData = JsonConvert.DeserializeObject(tokenizerJsonContent); + + // We don't need config so we just return tokenizer json data + return tokenizerJsonData; + } + + + /// + /// Tokenize the sentences + /// + /// + /// Tuple of 3 lists: + /// - TokenIds + /// - Attention Mask + /// - TokenTypeIds + static Tuple>, List>, List>> Tokenize(List candidates) + { + List> sentences = new List>(); + List> tokenIds = new List>(); + List> attentionMask = new List>(); + + /// Step 1: Get the tokenizer and tokenizerConfig JSON + /// Load JSON files and put elements in a two config objects + JObject tokenizerJsonData = LoadTokenizerJson(); + + /// Step 2: Create the Normalizer Object + BertNormalizer bertNorm = new BertNormalizer(JObject.FromObject(tokenizerJsonData["normalizer"])); + + /// Step 3: Create the PreTokenization Object + BertPreTokenizer bertPreTok = new BertPreTokenizer(JObject.FromObject(tokenizerJsonData["pre_tokenizer"])); + + /// Step 4: Create the WordPieceTokenizer + WordPieceTokenizer wordPieceTokenizer = new WordPieceTokenizer(JObject.FromObject(tokenizerJsonData["model"])); + + /// Step 5: Create the TemplateProcessing + TemplateProcessing templateProcessing = new TemplateProcessing(JObject.FromObject(tokenizerJsonData["post_processor"])); + + foreach (string text in candidates) + { + // Normalize the sentence + string normalized = bertNorm.Normalize(text); + + // Pretokenize the sentence + List pretokenized = bertPreTok.PreTokenize(normalized); + + // Tokenize with WordPieceTokenizer + List tokenized = wordPieceTokenizer.Encode(pretokenized); + + // Template Process + List processed = templateProcessing.PostProcess(tokenized); + + // Tokens to Ids + List ids = wordPieceTokenizer.ConvertTokensToIds(processed); + + // Add ids to List> + sentences.Add(ids); + } + + int max_length = (int)tokenizerJsonData["truncation"]["max_length"]; + + Tuple>, List>> tuple_ = PaddingOrTruncate(true, true, sentences, max_length, JObject.FromObject(tokenizerJsonData["padding"])); + + attentionMask = tuple_.Item1; + tokenIds = tuple_.Item2; + + List> TokenTypeIds = new List>(); + TokenTypeIds = AddTokenTypes(tokenIds); + + return Tuple.Create(tokenIds, attentionMask, TokenTypeIds); + } + + + /// + /// Perform Mean Pooling + /// + /// Attention Mask Tensor + /// Output Tensor + /// Ops on tensor + /// + public static TensorFloat MeanPooling(Tensor AttentionMaskTensor, TensorFloat outputTensor, Ops ops) + { + if (AttentionMaskTensor == null || outputTensor == null) + { + Debug.LogError("AttentionMaskTensor or outputTensor is null."); + } + + // Create an attention mask and + // add a new dimension (to make the mask compatible for element wise multiplication with token embeddings) + TensorFloat AttentionMaskTensorFloat = ops.Cast(AttentionMaskTensor, DataType.Float) as TensorFloat; + Tensor InputMaskExpanded = AttentionMaskTensorFloat.ShallowReshape(AttentionMaskTensorFloat.shape.Unsqueeze(-1)); + TensorFloat InputMaskExpandedFloat = ops.Cast(InputMaskExpanded, DataType.Float) as TensorFloat; + + TensorShape outputShape = outputTensor.shape; + + // Expand to 384 => [2, 6, 384] + InputMaskExpandedFloat = ops.Expand(InputMaskExpandedFloat, outputShape) as TensorFloat; + + // torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(input_mask_expanded.sum(1), min=1e-9) + TensorFloat temp_ = ops.Mul(outputTensor, InputMaskExpandedFloat); + TensorFloat MeanPooledTensor = ops.ReduceMean(temp_, new int[] { 1 }, false); + + return MeanPooledTensor; + } + + + /// + /// L2 Normalization + /// + /// + /// Ops on tensor + /// + public static TensorFloat L2Norm(TensorFloat MeanPooledTensor, Ops ops) + { + // L2 NORMALIZATION + // Compute L2 norm along axis 1 (dim=1) + TensorFloat l2Norms = ops.ReduceL2(MeanPooledTensor, new int[] { 1 }, true); + + // Broadcast the L2 norms to the original shape + TensorFloat l2NormsBroadcasted = ops.Expand(l2Norms, MeanPooledTensor.shape) as TensorFloat; + + // Divide sentence_embeddings by their L2 norms to achieve normalization + TensorFloat NormalizedEmbeddings = ops.Div(MeanPooledTensor, l2NormsBroadcasted); + + return NormalizedEmbeddings; + } + + + /// + /// Tokenize the input to be fed to the Transformer model + /// + /// + /// + public static Dictionary TokenizeInput(List sentences) + { + List> TokenIds = new List>(); + List> AttentionMask = new List>(); + List> TokenTypeIds = new List>(); + + Tuple>, List>, List>> FinalTuple = Tokenize(sentences); + + TokenIds = FinalTuple.Item1; + AttentionMask = FinalTuple.Item2; + TokenTypeIds = FinalTuple.Item3; + + // Flatten the nested list into a one-dimensional array + List flattenedData = new List(); + foreach (var innerList in TokenIds) + { + flattenedData.AddRange(innerList); + } + int[] data = flattenedData.ToArray(); + + // Create a 3D tensor shape + TensorShape shape = new TensorShape(TokenIds.Count, TokenIds[0].Count); + + // Create a new tensor from the array + TensorInt TokenIdsTensor = new TensorInt(shape, data); + + // Flatten the nested list into a one-dimensional array + List flattenedData2 = new List(); + foreach (var innerList in AttentionMask) + { + flattenedData2.AddRange(innerList); + } + int[] data2 = flattenedData2.ToArray(); + + // Create a 3D tensor shape + TensorShape shape2 = new TensorShape(AttentionMask.Count, AttentionMask[0].Count); + + // Create a new tensor from the array + TensorInt AttentionMaskTensor = new TensorInt(shape2, data2); + + // Flatten the nested list into a one-dimensional array + List flattenedData3 = new List(); + foreach (var innerList in TokenTypeIds) + { + flattenedData3.AddRange(innerList); + } + int[] data3 = flattenedData3.ToArray(); + + // Create a 3D tensor shape + TensorShape shape3 = new TensorShape(TokenTypeIds.Count, TokenTypeIds[0].Count); + + // Create a new tensor from the array + TensorInt TokenTypeIdsTensor = new TensorInt(shape3, data3); + + Dictionary inputTensors = new Dictionary() { + { "input_ids", TokenIdsTensor }, + {"token_type_ids", TokenTypeIdsTensor }, + { "attention_mask", AttentionMaskTensor } + }; + + return inputTensors; + } + + + /// + /// Padding or Truncate Tensor + /// + /// + /// + /// + /// + /// + /// + static Tuple>, List>> PaddingOrTruncate(bool padding, bool truncation, List> tokens, int max_length, JObject config) + { + // TODO allow user to change + string padding_side = "right"; + + int pad_token_id = 0; // TODO Change (int)config["pad_token"] + + List> attentionMask = new List>(); + + int maxLengthOfBatch = tokens.Max(x => x.Count); + + max_length = maxLengthOfBatch; + + // TODO Check the logic + /*if (max_length == null) + { + max_length = maxLengthOfBatch; + } + + max_length = Math.Min(max_length.Value, model_max_length);*/ + + if (padding || truncation) + { + for (int i = 0; i < tokens.Count; ++i) + { + if (tokens[i].Count == max_length) + { + attentionMask.Add(Enumerable.Repeat(1, tokens[i].Count).ToList()); + continue; + } + else if (tokens[i].Count > max_length) + { + if (truncation) + { + tokens[i] = tokens[i].Take(max_length).ToList(); + } + attentionMask.Add(Enumerable.Repeat(1, tokens[i].Count).ToList()); + } + else + { + if (padding) + { + int diff = max_length - tokens[i].Count; + + if (padding_side == "right") + { + attentionMask.Add(Enumerable.Repeat(1, tokens[i].Count) + .Concat(Enumerable.Repeat(0, diff)).ToList()); + tokens[i].AddRange(Enumerable.Repeat(pad_token_id, diff)); + } + else + { + attentionMask.Add(Enumerable.Repeat(0, diff) + .Concat(Enumerable.Repeat(1, tokens[i].Count)).ToList()); + tokens[i].InsertRange(0, Enumerable.Repeat(pad_token_id, diff)); + } + } + else + { + attentionMask.Add(Enumerable.Repeat(1, tokens[i].Count).ToList()); + } + } + } + } + else + { + attentionMask = tokens.Select(x => Enumerable.Repeat(1, x.Count).ToList()).ToList(); + } + return Tuple.Create(attentionMask, tokens); + } + + + /// + /// For now it's just copy inputIds and set all elements to 0 + /// + /// + static List> AddTokenTypes(List> inputIds) + { + return inputIds.Select(innerList => innerList.Select(_ => 0).ToList()).ToList(); + + } + } +} diff --git a/Runtime/SentenceSimilarityUtils.cs.meta b/Runtime/SentenceSimilarityUtils.cs.meta new file mode 100644 index 00000000..460525e5 --- /dev/null +++ b/Runtime/SentenceSimilarityUtils.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8ed8e3df26a92c8edaf889c36efa3b75 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/undream.llmunity.Runtime.asmdef b/Runtime/undream.llmunity.Runtime.asmdef index 140aec56..297361d2 100644 --- a/Runtime/undream.llmunity.Runtime.asmdef +++ b/Runtime/undream.llmunity.Runtime.asmdef @@ -1,3 +1,8 @@ { - "name": "undream.llmunity.Runtime" + "name": "undream.llmunity.Runtime", + "rootNamespace": "", + "references": [ + "Unity.Sentis", + "HuggingFace.SharpTransformers" + ] } \ No newline at end of file From ff374ecfa39e883ea5cf5ccfde6395c29e708148 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Thu, 25 Jan 2024 11:47:26 +0200 Subject: [PATCH 016/161] embedding model implementation --- Runtime/EmbeddingModel.cs | 282 +++++++++++++++ ...ilarity.cs.meta => EmbeddingModel.cs.meta} | 2 +- Runtime/SentenceSimilarity.cs | 131 ------- Runtime/SentenceSimilarityUtils.cs | 323 ------------------ Runtime/SentenceSimilarityUtils.cs.meta | 11 - 5 files changed, 283 insertions(+), 466 deletions(-) create mode 100644 Runtime/EmbeddingModel.cs rename Runtime/{SentenceSimilarity.cs.meta => EmbeddingModel.cs.meta} (83%) delete mode 100644 Runtime/SentenceSimilarity.cs delete mode 100644 Runtime/SentenceSimilarityUtils.cs delete mode 100644 Runtime/SentenceSimilarityUtils.cs.meta diff --git a/Runtime/EmbeddingModel.cs b/Runtime/EmbeddingModel.cs new file mode 100644 index 00000000..033a1dd2 --- /dev/null +++ b/Runtime/EmbeddingModel.cs @@ -0,0 +1,282 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using UnityEngine; +using Unity.Sentis; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +using UnityEditor; +using HuggingFace.SharpTransformers.Normalizers; +using HuggingFace.SharpTransformers.PreTokenizers; +using HuggingFace.SharpTransformers.Tokenizers; +using HuggingFace.SharpTransformers.PostProcessors; +using System.IO; + +public class EmbeddingModel : MonoBehaviour +{ + Model runtimeModel; + IWorker worker; + ITensorAllocator allocator; + Ops ops; + JObject tokenizerJsonData; + BertNormalizer bertNorm; + BertPreTokenizer bertPreTok; + WordPieceTokenizer wordPieceTokenizer; + TemplateProcessing templateProcessing; + + public EmbeddingModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU) + { + runtimeModel = ModelLoader.Load(modelPath); + string tokenizerJsonContent = File.ReadAllText(tokenizerPath); + tokenizerJsonData = JsonConvert.DeserializeObject(tokenizerJsonContent); + + worker = WorkerFactory.CreateWorker(BackendType.CPU, runtimeModel); + allocator = new TensorCachingAllocator(); + ops = WorkerFactory.CreateOps(backend, allocator); + + bertNorm = new BertNormalizer(JObject.FromObject(tokenizerJsonData["normalizer"])); + bertPreTok = new BertPreTokenizer(JObject.FromObject(tokenizerJsonData["pre_tokenizer"])); + wordPieceTokenizer = new WordPieceTokenizer(JObject.FromObject(tokenizerJsonData["model"])); + templateProcessing = new TemplateProcessing(JObject.FromObject(tokenizerJsonData["post_processor"])); + } + + public void Destroy() + { + worker.Dispose(); + ops.Dispose(); + } + + public TensorFloat Encode(List input) + { + // Step 1: Tokenize the sentences + Dictionary inputSentencesTokensTensor = TokenizeInput(input); + // Step 2: Compute embedding and get the output + worker.Execute(inputSentencesTokensTensor); + // Step 3: Get the output from the neural network + TensorFloat outputTensor = worker.PeekOutput("last_hidden_state") as TensorFloat; + // Step 4: Perform pooling + TensorFloat MeanPooledTensor = MeanPooling(inputSentencesTokensTensor["attention_mask"], outputTensor, ops); + // Step 5: Normalize the results + TensorFloat NormedTensor = L2Norm(MeanPooledTensor, ops); + return NormedTensor; + } + + public float[] SimilarityScores(TensorFloat InputSequence, TensorFloat ComparisonSequences) + { + TensorFloat scoresTensor = ops.MatMul2D(InputSequence, ComparisonSequences, false, true); + scoresTensor.MakeReadable(); + int cols = ComparisonSequences.shape[0]; + float[] scores = new float[cols]; + for (int j = 0; j < cols; j++) + scores[j] = scoresTensor[0, j]; + return scores; + } + + public float[][] SimilarityScoresMultiple(TensorFloat InputSequence, TensorFloat ComparisonSequences) + { + TensorFloat scoresTensor = ops.MatMul2D(InputSequence, ComparisonSequences, false, true); + scoresTensor.MakeReadable(); + int rows = InputSequence.shape[0]; + int cols = ComparisonSequences.shape[0]; + float[][] scores = new float[rows][]; + for (int i = 0; i < rows; i++) + { + scores[i] = new float[cols]; + for (int j = 0; j < cols; j++) + scores[i][j] = scoresTensor[i, j]; + } + return scores; + } + + Tuple>, List>, List>> Tokenize(List candidates) + { + List> sentences = new List>(); + List> tokenIds = new List>(); + List> attentionMask = new List>(); + foreach (string text in candidates) + { + // Normalize the sentence + string normalized = bertNorm.Normalize(text); + // Pretokenize the sentence + List pretokenized = bertPreTok.PreTokenize(normalized); + // Tokenize with WordPieceTokenizer + List tokenized = wordPieceTokenizer.Encode(pretokenized); + // Template Process + List processed = templateProcessing.PostProcess(tokenized); + // Tokens to Ids + List ids = wordPieceTokenizer.ConvertTokensToIds(processed); + // Add ids to List> + sentences.Add(ids); + } + + int max_length = (int)tokenizerJsonData["truncation"]["max_length"]; + Tuple>, List>> tuple_ = PaddingOrTruncate(true, true, sentences, max_length, JObject.FromObject(tokenizerJsonData["padding"])); + attentionMask = tuple_.Item1; + tokenIds = tuple_.Item2; + + List> TokenTypeIds = new List>(); + TokenTypeIds = AddTokenTypes(tokenIds); + return Tuple.Create(tokenIds, attentionMask, TokenTypeIds); + } + + public static TensorFloat MeanPooling(Tensor AttentionMaskTensor, TensorFloat outputTensor, Ops ops) + { + if (AttentionMaskTensor == null || outputTensor == null) + { + Debug.LogError("AttentionMaskTensor or outputTensor is null."); + } + + // Create an attention mask and + // add a new dimension (to make the mask compatible for element wise multiplication with token embeddings) + TensorFloat AttentionMaskTensorFloat = ops.Cast(AttentionMaskTensor, DataType.Float) as TensorFloat; + Tensor InputMaskExpanded = AttentionMaskTensorFloat.ShallowReshape(AttentionMaskTensorFloat.shape.Unsqueeze(-1)); + TensorFloat InputMaskExpandedFloat = ops.Cast(InputMaskExpanded, DataType.Float) as TensorFloat; + + TensorShape outputShape = outputTensor.shape; + // Expand to 384 => [2, 6, 384] + InputMaskExpandedFloat = ops.Expand(InputMaskExpandedFloat, outputShape) as TensorFloat; + // torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(input_mask_expanded.sum(1), min=1e-9) + TensorFloat temp_ = ops.Mul(outputTensor, InputMaskExpandedFloat); + TensorFloat MeanPooledTensor = ops.ReduceMean(temp_, new int[] { 1 }, false); + + return MeanPooledTensor; + } + + public static TensorFloat L2Norm(TensorFloat MeanPooledTensor, Ops ops) + { + // L2 NORMALIZATION + // Compute L2 norm along axis 1 (dim=1) + TensorFloat l2Norms = ops.ReduceL2(MeanPooledTensor, new int[] { 1 }, true); + // Broadcast the L2 norms to the original shape + TensorFloat l2NormsBroadcasted = ops.Expand(l2Norms, MeanPooledTensor.shape) as TensorFloat; + // Divide sentence_embeddings by their L2 norms to achieve normalization + TensorFloat NormalizedEmbeddings = ops.Div(MeanPooledTensor, l2NormsBroadcasted); + return NormalizedEmbeddings; + } + + public Dictionary TokenizeInput(List sentences) + { + List> TokenIds = new List>(); + List> AttentionMask = new List>(); + List> TokenTypeIds = new List>(); + + Tuple>, List>, List>> FinalTuple = Tokenize(sentences); + TokenIds = FinalTuple.Item1; + AttentionMask = FinalTuple.Item2; + TokenTypeIds = FinalTuple.Item3; + + // Flatten the nested list into a one-dimensional array + List flattenedData = new List(); + foreach (var innerList in TokenIds) + { + flattenedData.AddRange(innerList); + } + int[] data = flattenedData.ToArray(); + // Create a 3D tensor shape + TensorShape shape = new TensorShape(TokenIds.Count, TokenIds[0].Count); + // Create a new tensor from the array + TensorInt TokenIdsTensor = new TensorInt(shape, data); + // Flatten the nested list into a one-dimensional array + List flattenedData2 = new List(); + foreach (var innerList in AttentionMask) + { + flattenedData2.AddRange(innerList); + } + int[] data2 = flattenedData2.ToArray(); + // Create a 3D tensor shape + TensorShape shape2 = new TensorShape(AttentionMask.Count, AttentionMask[0].Count); + // Create a new tensor from the array + TensorInt AttentionMaskTensor = new TensorInt(shape2, data2); + // Flatten the nested list into a one-dimensional array + List flattenedData3 = new List(); + foreach (var innerList in TokenTypeIds) + { + flattenedData3.AddRange(innerList); + } + int[] data3 = flattenedData3.ToArray(); + // Create a 3D tensor shape + TensorShape shape3 = new TensorShape(TokenTypeIds.Count, TokenTypeIds[0].Count); + // Create a new tensor from the array + TensorInt TokenTypeIdsTensor = new TensorInt(shape3, data3); + Dictionary inputTensors = new Dictionary() + { + { "input_ids", TokenIdsTensor }, + {"token_type_ids", TokenTypeIdsTensor }, + { "attention_mask", AttentionMaskTensor } + }; + return inputTensors; + } + + static Tuple>, List>> PaddingOrTruncate(bool padding, bool truncation, List> tokens, int max_length, JObject config) + { + // TODO allow user to change + string padding_side = "right"; + int pad_token_id = 0; // TODO Change (int)config["pad_token"] + List> attentionMask = new List>(); + int maxLengthOfBatch = tokens.Max(x => x.Count); + max_length = maxLengthOfBatch; + + // TODO Check the logic + /*if (max_length == null) + { + max_length = maxLengthOfBatch; + } + max_length = Math.Min(max_length.Value, model_max_length);*/ + + if (padding || truncation) + { + for (int i = 0; i < tokens.Count; ++i) + { + if (tokens[i].Count == max_length) + { + attentionMask.Add(Enumerable.Repeat(1, tokens[i].Count).ToList()); + continue; + } + else if (tokens[i].Count > max_length) + { + if (truncation) + { + tokens[i] = tokens[i].Take(max_length).ToList(); + } + attentionMask.Add(Enumerable.Repeat(1, tokens[i].Count).ToList()); + } + else + { + if (padding) + { + int diff = max_length - tokens[i].Count; + + if (padding_side == "right") + { + attentionMask.Add(Enumerable.Repeat(1, tokens[i].Count) + .Concat(Enumerable.Repeat(0, diff)).ToList()); + tokens[i].AddRange(Enumerable.Repeat(pad_token_id, diff)); + } + else + { + attentionMask.Add(Enumerable.Repeat(0, diff) + .Concat(Enumerable.Repeat(1, tokens[i].Count)).ToList()); + tokens[i].InsertRange(0, Enumerable.Repeat(pad_token_id, diff)); + } + } + else + { + attentionMask.Add(Enumerable.Repeat(1, tokens[i].Count).ToList()); + } + } + } + } + else + { + attentionMask = tokens.Select(x => Enumerable.Repeat(1, x.Count).ToList()).ToList(); + } + return Tuple.Create(attentionMask, tokens); + } + + static List> AddTokenTypes(List> inputIds) + { + return inputIds.Select(innerList => innerList.Select(_ => 0).ToList()).ToList(); + } +} diff --git a/Runtime/SentenceSimilarity.cs.meta b/Runtime/EmbeddingModel.cs.meta similarity index 83% rename from Runtime/SentenceSimilarity.cs.meta rename to Runtime/EmbeddingModel.cs.meta index 89d91f19..2abaa9b6 100644 --- a/Runtime/SentenceSimilarity.cs.meta +++ b/Runtime/EmbeddingModel.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: bf302ca4cc187e9219e08f41f3f99b7a +guid: 4818b8a60323a13d5a17d506564641ab MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Runtime/SentenceSimilarity.cs b/Runtime/SentenceSimilarity.cs deleted file mode 100644 index 030ab35f..00000000 --- a/Runtime/SentenceSimilarity.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Text; -using System.Text.RegularExpressions; -using System.Linq; - -using UnityEngine; -using Unity.Sentis; -using Unity.Sentis.Layers; - -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -using SentenceSimilarityUtils; -using UnityEditor; - - -public class SentenceSimilarity : MonoBehaviour -{ - ModelAsset modelAsset; - public Model runtimeModel; - public IWorker worker; - public ITensorAllocator allocator; - public Ops ops; - - - /// - /// Load the model on awake - /// - public void Awake() - { - // Load the ONNX model - // modelAsset = Resources.Load("StreamingAssets/model.onnx") as ModelAsset; - - // runtimeModel = ModelLoader.Load("Assets/Models/model.onnx"); - runtimeModel = ModelLoader.Load("Assets/StreamingAssets/model.sentis"); - - // Create an engine and set the backend as GPU //GPUCompute - worker = WorkerFactory.CreateWorker(BackendType.CPU, runtimeModel); - - // Create an allocator. - allocator = new TensorCachingAllocator(); - - // Create an operator - ops = WorkerFactory.CreateOps(BackendType.GPUCompute, allocator); - } - - void OnDisable() - { - // Tell the GPU we're finished with the memory the engine used - worker.Dispose(); - } - - /// - /// Encode the input - /// - /// - /// - /// - /// - public TensorFloat Encode(List input, IWorker worker, Ops ops) - { - // Step 1: Tokenize the sentences - Dictionary inputSentencesTokensTensor = SentenceSimilarityUtils_.TokenizeInput(input); - - // Step 2: Compute embedding and get the output - worker.Execute(inputSentencesTokensTensor); - - // Step 3: Get the output from the neural network - TensorFloat outputTensor = worker.PeekOutput("last_hidden_state") as TensorFloat; - - // Step 4: Perform pooling - TensorFloat MeanPooledTensor = SentenceSimilarityUtils_.MeanPooling(inputSentencesTokensTensor["attention_mask"], outputTensor, ops); - - // Step 5: Normalize the results - TensorFloat NormedTensor = SentenceSimilarityUtils_.L2Norm(MeanPooledTensor, ops); - - return NormedTensor; - } - - /// - /// We calculate the similarity scores between the input sequence (what the user typed) and the comparison - /// sequences (the robot action list) - /// This similarity score is simply the cosine similarity. It is calculated as the cosine of the angle between two vectors. - /// It is particularly useful when your texts are not the same length - /// - /// - /// - /// - public TensorFloat SentenceSimilarityScores(TensorFloat InputSequence, TensorFloat ComparisonSequences) - { - TensorFloat SentenceSimilarityScores_ = ops.MatMul2D(InputSequence, ComparisonSequences, false, true); - return SentenceSimilarityScores_; - } - - /// - /// Get the most similar action and its index given the player input - /// - /// - /// - /// - public Tuple RankSimilarityScores(string inputSentence, string[] comparisonSentences) - { - // Step 1: Transform string and string[] to lists - List InputSentences = new List(); - List ComparisonSentences = new List(); - - InputSentences.Add(inputSentence); - ComparisonSentences = comparisonSentences.ToList(); - - // Step 2: Encode the input sentences and comparison sentences - TensorFloat NormEmbedSentences = Encode(InputSentences, worker, ops); - TensorFloat NormEmbedComparisonSentences = Encode(ComparisonSentences, worker, ops); - - // Calculate the similarity score of the player input with each action - TensorFloat scores = SentenceSimilarityScores(NormEmbedSentences, NormEmbedComparisonSentences); - scores.MakeReadable(); // Be able to read this tensor - - // Helper to return only best score and index - TensorInt scoreIndex = ops.ArgMax(scores, 1, true); - scoreIndex.MakeReadable(); - - int scoreIndexInt = scoreIndex[0]; - scores.MakeReadable(); - float score = scores[scoreIndexInt]; - - // Return the similarity score and the action index - return Tuple.Create(scoreIndexInt, score); - } -} diff --git a/Runtime/SentenceSimilarityUtils.cs b/Runtime/SentenceSimilarityUtils.cs deleted file mode 100644 index e1679c3d..00000000 --- a/Runtime/SentenceSimilarityUtils.cs +++ /dev/null @@ -1,323 +0,0 @@ -using System; -using System.IO; -using System.Collections; -using System.Collections.Generic; -using System.Text; -using System.Text.RegularExpressions; -using System.Linq; - -using UnityEngine; -using Unity.Sentis; -using Unity.Sentis.Layers; - -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -using HuggingFace.SharpTransformers.Normalizers; -using HuggingFace.SharpTransformers.PreTokenizers; -using HuggingFace.SharpTransformers.Tokenizers; -using HuggingFace.SharpTransformers.PostProcessors; - - -namespace SentenceSimilarityUtils -{ - public static class SentenceSimilarityUtils_ - { - /// - /// Load the Tokenizer JSON - /// This JSON contains the information about how the input should be processed - /// before being feed to the Transformer model - /// - /// - public static JObject LoadTokenizerJson() - { - string tokenizerJsonContent = File.ReadAllText("Assets/StreamingAssets/tokenizer.json"); - - JObject tokenizerJsonData = JsonConvert.DeserializeObject(tokenizerJsonContent); - - // We don't need config so we just return tokenizer json data - return tokenizerJsonData; - } - - - /// - /// Tokenize the sentences - /// - /// - /// Tuple of 3 lists: - /// - TokenIds - /// - Attention Mask - /// - TokenTypeIds - static Tuple>, List>, List>> Tokenize(List candidates) - { - List> sentences = new List>(); - List> tokenIds = new List>(); - List> attentionMask = new List>(); - - /// Step 1: Get the tokenizer and tokenizerConfig JSON - /// Load JSON files and put elements in a two config objects - JObject tokenizerJsonData = LoadTokenizerJson(); - - /// Step 2: Create the Normalizer Object - BertNormalizer bertNorm = new BertNormalizer(JObject.FromObject(tokenizerJsonData["normalizer"])); - - /// Step 3: Create the PreTokenization Object - BertPreTokenizer bertPreTok = new BertPreTokenizer(JObject.FromObject(tokenizerJsonData["pre_tokenizer"])); - - /// Step 4: Create the WordPieceTokenizer - WordPieceTokenizer wordPieceTokenizer = new WordPieceTokenizer(JObject.FromObject(tokenizerJsonData["model"])); - - /// Step 5: Create the TemplateProcessing - TemplateProcessing templateProcessing = new TemplateProcessing(JObject.FromObject(tokenizerJsonData["post_processor"])); - - foreach (string text in candidates) - { - // Normalize the sentence - string normalized = bertNorm.Normalize(text); - - // Pretokenize the sentence - List pretokenized = bertPreTok.PreTokenize(normalized); - - // Tokenize with WordPieceTokenizer - List tokenized = wordPieceTokenizer.Encode(pretokenized); - - // Template Process - List processed = templateProcessing.PostProcess(tokenized); - - // Tokens to Ids - List ids = wordPieceTokenizer.ConvertTokensToIds(processed); - - // Add ids to List> - sentences.Add(ids); - } - - int max_length = (int)tokenizerJsonData["truncation"]["max_length"]; - - Tuple>, List>> tuple_ = PaddingOrTruncate(true, true, sentences, max_length, JObject.FromObject(tokenizerJsonData["padding"])); - - attentionMask = tuple_.Item1; - tokenIds = tuple_.Item2; - - List> TokenTypeIds = new List>(); - TokenTypeIds = AddTokenTypes(tokenIds); - - return Tuple.Create(tokenIds, attentionMask, TokenTypeIds); - } - - - /// - /// Perform Mean Pooling - /// - /// Attention Mask Tensor - /// Output Tensor - /// Ops on tensor - /// - public static TensorFloat MeanPooling(Tensor AttentionMaskTensor, TensorFloat outputTensor, Ops ops) - { - if (AttentionMaskTensor == null || outputTensor == null) - { - Debug.LogError("AttentionMaskTensor or outputTensor is null."); - } - - // Create an attention mask and - // add a new dimension (to make the mask compatible for element wise multiplication with token embeddings) - TensorFloat AttentionMaskTensorFloat = ops.Cast(AttentionMaskTensor, DataType.Float) as TensorFloat; - Tensor InputMaskExpanded = AttentionMaskTensorFloat.ShallowReshape(AttentionMaskTensorFloat.shape.Unsqueeze(-1)); - TensorFloat InputMaskExpandedFloat = ops.Cast(InputMaskExpanded, DataType.Float) as TensorFloat; - - TensorShape outputShape = outputTensor.shape; - - // Expand to 384 => [2, 6, 384] - InputMaskExpandedFloat = ops.Expand(InputMaskExpandedFloat, outputShape) as TensorFloat; - - // torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(input_mask_expanded.sum(1), min=1e-9) - TensorFloat temp_ = ops.Mul(outputTensor, InputMaskExpandedFloat); - TensorFloat MeanPooledTensor = ops.ReduceMean(temp_, new int[] { 1 }, false); - - return MeanPooledTensor; - } - - - /// - /// L2 Normalization - /// - /// - /// Ops on tensor - /// - public static TensorFloat L2Norm(TensorFloat MeanPooledTensor, Ops ops) - { - // L2 NORMALIZATION - // Compute L2 norm along axis 1 (dim=1) - TensorFloat l2Norms = ops.ReduceL2(MeanPooledTensor, new int[] { 1 }, true); - - // Broadcast the L2 norms to the original shape - TensorFloat l2NormsBroadcasted = ops.Expand(l2Norms, MeanPooledTensor.shape) as TensorFloat; - - // Divide sentence_embeddings by their L2 norms to achieve normalization - TensorFloat NormalizedEmbeddings = ops.Div(MeanPooledTensor, l2NormsBroadcasted); - - return NormalizedEmbeddings; - } - - - /// - /// Tokenize the input to be fed to the Transformer model - /// - /// - /// - public static Dictionary TokenizeInput(List sentences) - { - List> TokenIds = new List>(); - List> AttentionMask = new List>(); - List> TokenTypeIds = new List>(); - - Tuple>, List>, List>> FinalTuple = Tokenize(sentences); - - TokenIds = FinalTuple.Item1; - AttentionMask = FinalTuple.Item2; - TokenTypeIds = FinalTuple.Item3; - - // Flatten the nested list into a one-dimensional array - List flattenedData = new List(); - foreach (var innerList in TokenIds) - { - flattenedData.AddRange(innerList); - } - int[] data = flattenedData.ToArray(); - - // Create a 3D tensor shape - TensorShape shape = new TensorShape(TokenIds.Count, TokenIds[0].Count); - - // Create a new tensor from the array - TensorInt TokenIdsTensor = new TensorInt(shape, data); - - // Flatten the nested list into a one-dimensional array - List flattenedData2 = new List(); - foreach (var innerList in AttentionMask) - { - flattenedData2.AddRange(innerList); - } - int[] data2 = flattenedData2.ToArray(); - - // Create a 3D tensor shape - TensorShape shape2 = new TensorShape(AttentionMask.Count, AttentionMask[0].Count); - - // Create a new tensor from the array - TensorInt AttentionMaskTensor = new TensorInt(shape2, data2); - - // Flatten the nested list into a one-dimensional array - List flattenedData3 = new List(); - foreach (var innerList in TokenTypeIds) - { - flattenedData3.AddRange(innerList); - } - int[] data3 = flattenedData3.ToArray(); - - // Create a 3D tensor shape - TensorShape shape3 = new TensorShape(TokenTypeIds.Count, TokenTypeIds[0].Count); - - // Create a new tensor from the array - TensorInt TokenTypeIdsTensor = new TensorInt(shape3, data3); - - Dictionary inputTensors = new Dictionary() { - { "input_ids", TokenIdsTensor }, - {"token_type_ids", TokenTypeIdsTensor }, - { "attention_mask", AttentionMaskTensor } - }; - - return inputTensors; - } - - - /// - /// Padding or Truncate Tensor - /// - /// - /// - /// - /// - /// - /// - static Tuple>, List>> PaddingOrTruncate(bool padding, bool truncation, List> tokens, int max_length, JObject config) - { - // TODO allow user to change - string padding_side = "right"; - - int pad_token_id = 0; // TODO Change (int)config["pad_token"] - - List> attentionMask = new List>(); - - int maxLengthOfBatch = tokens.Max(x => x.Count); - - max_length = maxLengthOfBatch; - - // TODO Check the logic - /*if (max_length == null) - { - max_length = maxLengthOfBatch; - } - - max_length = Math.Min(max_length.Value, model_max_length);*/ - - if (padding || truncation) - { - for (int i = 0; i < tokens.Count; ++i) - { - if (tokens[i].Count == max_length) - { - attentionMask.Add(Enumerable.Repeat(1, tokens[i].Count).ToList()); - continue; - } - else if (tokens[i].Count > max_length) - { - if (truncation) - { - tokens[i] = tokens[i].Take(max_length).ToList(); - } - attentionMask.Add(Enumerable.Repeat(1, tokens[i].Count).ToList()); - } - else - { - if (padding) - { - int diff = max_length - tokens[i].Count; - - if (padding_side == "right") - { - attentionMask.Add(Enumerable.Repeat(1, tokens[i].Count) - .Concat(Enumerable.Repeat(0, diff)).ToList()); - tokens[i].AddRange(Enumerable.Repeat(pad_token_id, diff)); - } - else - { - attentionMask.Add(Enumerable.Repeat(0, diff) - .Concat(Enumerable.Repeat(1, tokens[i].Count)).ToList()); - tokens[i].InsertRange(0, Enumerable.Repeat(pad_token_id, diff)); - } - } - else - { - attentionMask.Add(Enumerable.Repeat(1, tokens[i].Count).ToList()); - } - } - } - } - else - { - attentionMask = tokens.Select(x => Enumerable.Repeat(1, x.Count).ToList()).ToList(); - } - return Tuple.Create(attentionMask, tokens); - } - - - /// - /// For now it's just copy inputIds and set all elements to 0 - /// - /// - static List> AddTokenTypes(List> inputIds) - { - return inputIds.Select(innerList => innerList.Select(_ => 0).ToList()).ToList(); - - } - } -} diff --git a/Runtime/SentenceSimilarityUtils.cs.meta b/Runtime/SentenceSimilarityUtils.cs.meta deleted file mode 100644 index 460525e5..00000000 --- a/Runtime/SentenceSimilarityUtils.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8ed8e3df26a92c8edaf889c36efa3b75 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: From 99bb9d662963d16a16a3afdca343ccc3c3035c2f Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 26 Jan 2024 08:13:20 +0200 Subject: [PATCH 017/161] add LICENSE.meta --- LICENSE.meta | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 LICENSE.meta diff --git a/LICENSE.meta b/LICENSE.meta new file mode 100644 index 00000000..b3e9e43c --- /dev/null +++ b/LICENSE.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: dcf626c12805336acb575da02262f447 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From f578df66c69f49a77d852453d2f5b39dc74546ca Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 26 Jan 2024 09:31:50 +0200 Subject: [PATCH 018/161] fix "hides inherited" warnings --- Runtime/Tokenizers/Decoders/Decoders.cs | 3 +- Runtime/Tokenizers/Normalizers/Normalizers.cs | 35 ++++++++----------- .../Normalizers/NormalizersUtils.cs | 3 +- .../PostProcessors/PostProcessors.cs | 2 -- Runtime/Tokenizers/Tokenizers/Tokenizers.cs | 14 +++----- 5 files changed, 20 insertions(+), 37 deletions(-) diff --git a/Runtime/Tokenizers/Decoders/Decoders.cs b/Runtime/Tokenizers/Decoders/Decoders.cs index 8b62f73b..b89e5a4d 100644 --- a/Runtime/Tokenizers/Decoders/Decoders.cs +++ b/Runtime/Tokenizers/Decoders/Decoders.cs @@ -322,7 +322,6 @@ public override List Decode(List tokens) class DecoderSequence : Decoder_ { public List Decoders; - public JObject Config; public DecoderSequence(JObject config) : base(config) { @@ -354,7 +353,7 @@ public DecoderSequence(JObject config) : base(config) /// /// /// - public List DecodeChain(List tokens) + public new List DecodeChain(List tokens) { return this.Decoders.Aggregate(tokens, (currentTokens, decoder) => decoder.DecodeChain(currentTokens)); } diff --git a/Runtime/Tokenizers/Normalizers/Normalizers.cs b/Runtime/Tokenizers/Normalizers/Normalizers.cs index fd061a24..8f6a2551 100644 --- a/Runtime/Tokenizers/Normalizers/Normalizers.cs +++ b/Runtime/Tokenizers/Normalizers/Normalizers.cs @@ -85,7 +85,6 @@ public class BertNormalizer : Normalizer { public BertNormalizer(JObject config) : base(config) { - } /// @@ -114,35 +113,34 @@ public string TokenizeChineseChars(string text) { output.Append(character); } - } return output.ToString(); } /// /// Checks whether the given Unicode codepoint represents a CJK (Chinese, Japanese, or Korean) character. - /// + /// /// A "chinese character" is defined as anything in the CJK Unicode block: /// https://en.wikipedia.org/wiki/CJK_Unified_Ideographs_(Unicode_block) - /// + /// /// Note that the CJK Unicode block is NOT all Japanese and Korean characters, despite its name. /// The modern Korean Hangul alphabet is a different block, as is Japanese Hiragana and Katakana. /// Those alphabets are used to write space-separated words, so they are not treated specially /// and are handled like all other languages. - /// + /// /// /// The Unicode codepoint to check. /// True if the codepoint represents a CJK character, false otherwise. public bool IsChineseChar(int unicodeCodePoint) { return (unicodeCodePoint >= 0x4E00 && unicodeCodePoint <= 0x9FFF) || - (unicodeCodePoint >= 0x3400 && unicodeCodePoint <= 0x4DBF) || - (unicodeCodePoint >= 0x20000 && unicodeCodePoint <= 0x2A6DF) || - (unicodeCodePoint >= 0x2A700 && unicodeCodePoint <= 0x2B73F) || - (unicodeCodePoint >= 0x2B740 && unicodeCodePoint <= 0x2B81F) || - (unicodeCodePoint >= 0x2B820 && unicodeCodePoint <= 0x2CEAF) || - (unicodeCodePoint >= 0xF900 && unicodeCodePoint <= 0xFAFF) || - (unicodeCodePoint >= 0x2F800 && unicodeCodePoint <= 0x2FA1F); + (unicodeCodePoint >= 0x3400 && unicodeCodePoint <= 0x4DBF) || + (unicodeCodePoint >= 0x20000 && unicodeCodePoint <= 0x2A6DF) || + (unicodeCodePoint >= 0x2A700 && unicodeCodePoint <= 0x2B73F) || + (unicodeCodePoint >= 0x2B740 && unicodeCodePoint <= 0x2B81F) || + (unicodeCodePoint >= 0x2B820 && unicodeCodePoint <= 0x2CEAF) || + (unicodeCodePoint >= 0xF900 && unicodeCodePoint <= 0xFAFF) || + (unicodeCodePoint >= 0x2F800 && unicodeCodePoint <= 0x2FA1F); } /// @@ -198,11 +196,9 @@ public string StripAccents(string text) } - public class NormalizerSequence : Normalizer { public List Normalizers; - public JObject Config; /// /// Create a new instance of NormalizerSequence @@ -210,7 +206,7 @@ public class NormalizerSequence : Normalizer /// The configuration object /// /// - public NormalizerSequence(JObject config): base(config) + public NormalizerSequence(JObject config) : base(config) { string jsonString = config.ToString(); @@ -224,7 +220,7 @@ public NormalizerSequence(JObject config): base(config) } Normalizers = new List(); - + foreach (JObject normalizerConfig in config["normalizers"]) { var normalizer = Normalizer.FromConfig(normalizerConfig); @@ -238,14 +234,13 @@ public NormalizerSequence(JObject config): base(config) } } - /// /// Apply a sequence of Normalizes to the input text. /// /// The text to normalize /// The normalized text /// - public string Normalize(string text) + public new string Normalize(string text) { if (text == null) { @@ -268,7 +263,6 @@ public class Prepend : Normalizer { public Prepend(JObject config) : base(config) { - } /// @@ -292,7 +286,6 @@ class Replace : Normalizer { public Replace(JObject config) : base(config) { - } /// @@ -315,4 +308,4 @@ public override string Normalize(string text) return text; } } -} \ No newline at end of file +} diff --git a/Runtime/Tokenizers/Normalizers/NormalizersUtils.cs b/Runtime/Tokenizers/Normalizers/NormalizersUtils.cs index 65810a3c..25a6e2d4 100644 --- a/Runtime/Tokenizers/Normalizers/NormalizersUtils.cs +++ b/Runtime/Tokenizers/Normalizers/NormalizersUtils.cs @@ -27,8 +27,7 @@ public static string createPattern(JToken pattern, bool invert = true) else { throw new Exception($"Unknown pattern type: {pattern}"); - return null; } } } -} \ No newline at end of file +} diff --git a/Runtime/Tokenizers/PostProcessors/PostProcessors.cs b/Runtime/Tokenizers/PostProcessors/PostProcessors.cs index a9513ebf..5506f8f1 100644 --- a/Runtime/Tokenizers/PostProcessors/PostProcessors.cs +++ b/Runtime/Tokenizers/PostProcessors/PostProcessors.cs @@ -74,8 +74,6 @@ public virtual List Call(List tokens, List tokensPair = /// public class TemplateProcessing : PostProcessor { - public JObject Config; - // The template for a single sequence of tokens. public JArray Single; diff --git a/Runtime/Tokenizers/Tokenizers/Tokenizers.cs b/Runtime/Tokenizers/Tokenizers/Tokenizers.cs index 95b71333..dcd6a2e8 100644 --- a/Runtime/Tokenizers/Tokenizers/Tokenizers.cs +++ b/Runtime/Tokenizers/Tokenizers/Tokenizers.cs @@ -179,14 +179,8 @@ public List Fuse(List arr, int value) } } - public class WordPieceTokenizer : TokenizerModel { - public JObject Config; - public List Vocab; - public Dictionary TokensToIds; - public int? UnkTokenId; // Thanks to int?, the variable can hold an integer value or be null - public string UnkToken; public string ContinuingSubwordPrefix; public WordPieceTokenizer(JObject config) : base(config) @@ -215,7 +209,7 @@ public WordPieceTokenizer(JObject config) : base(config) /// /// The tokens to encode. /// An array of encoded tokens. - public List Encode(List tokens) + public new List Encode(List tokens) { // Initialize a List to store the encoded tokens var OutputTokens = new List(); @@ -293,7 +287,7 @@ public List Encode(List tokens) /// /// The token IDs to convert. /// The converted tokens. - public List ConvertIdsToTokens(List ids) + public new List ConvertIdsToTokens(List ids) { /* Select is used instead of map to transform the list of IDs into a list of tokens. @@ -304,7 +298,7 @@ The resulting list of tokens is returned. return tokens; } - public List ConvertTokensToIds(List tokens) + public new List ConvertTokensToIds(List tokens) { // Create an array of token IDs by mapping each token to its corresponding ID List ids = new List(); @@ -323,7 +317,7 @@ public List ConvertTokensToIds(List tokens) return ids; } - public List Fuse(List arr, int value) + public new List Fuse(List arr, int value) { List fused = new List(); int i = 0; From 7cf4a1a66eb5b46d51ebe22b69ea6f5441a9a0a7 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 26 Jan 2024 09:56:30 +0200 Subject: [PATCH 019/161] adapt README.md to include the changelog from the original repo --- README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.md b/README.md index 7a2d5346..744cc3d2 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,22 @@ +# sharp-transformers +## Description +Sharp Transformers is a unity plugin developed by Hugging Face. +The original code can be found here:
+https://github.com/huggingface/sharp-transformers/tree/577bfe23c286a605f58d328ea991aa4d4d06f4c8 + +## License +Sharp Transformers is distributed under Apache-2.0 license, see the [LICENSE file](LICENSE). + +## Local Modifications +- adapt README.md to include the changelog from the original repo +- fix "hides inherited" warnings in Unity +- add missing LICENSE.meta + +## Original Readme +The original readme is appended here: + +----- + # Sharp Transformers A Unity plugin of utilities to **run Transformer 🤗 models in Unity games**. From 82fd1e66fd71f9e7b1c4831c8e2928e1b5594c1d Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 26 Jan 2024 10:03:37 +0200 Subject: [PATCH 020/161] EmbeddingModel not MonoBehaviour --- Runtime/EmbeddingModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Runtime/EmbeddingModel.cs b/Runtime/EmbeddingModel.cs index 033a1dd2..b380b38b 100644 --- a/Runtime/EmbeddingModel.cs +++ b/Runtime/EmbeddingModel.cs @@ -14,7 +14,7 @@ using HuggingFace.SharpTransformers.PostProcessors; using System.IO; -public class EmbeddingModel : MonoBehaviour +public class EmbeddingModel { Model runtimeModel; IWorker worker; From 19b4416660d5e9c8b1a8e134c1c77f899df732b7 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 26 Jan 2024 10:04:14 +0200 Subject: [PATCH 021/161] add dependencies to sentis and newtonsoft-json --- package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package.json b/package.json index fb134178..b99dd304 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,10 @@ "unity": "2022.3", "unityRelease": "16f1", "documentationUrl": "https://github.com/amakropoulos/LLMUnity", + "dependencies": { + "com.unity.sentis": "1.2.0-exp.2", + "com.unity.nuget.newtonsoft-json": "3.2.1" + }, "keywords": [ "llm", "large language model", From a4091969e72f2edac2db00f6b649fed28b929914 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 26 Jan 2024 10:15:01 +0200 Subject: [PATCH 022/161] add meta file for sharp-transformers --- sharp-transformers.meta | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 sharp-transformers.meta diff --git a/sharp-transformers.meta b/sharp-transformers.meta new file mode 100644 index 00000000..aa20a1f2 --- /dev/null +++ b/sharp-transformers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3c15f77a5ac89b7b1aa9e6d28ae2b8dd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From d6d7dc9d25555742220b3b120ecf976e0686a3ae Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 26 Jan 2024 10:26:24 +0200 Subject: [PATCH 023/161] enhance third-party notices and add sharp-transformers --- Third Party Notices.md | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/Third Party Notices.md b/Third Party Notices.md index 88593fc5..51b38c81 100644 --- a/Third Party Notices.md +++ b/Third Party Notices.md @@ -1,25 +1,39 @@ -This package contains third-party software components governed by the license(s) indicated below: - -Component Name: llama.cpp +# THIRD-PARTY SOFTWARE NOTICES AND INFORMATION -License Type: "MIT" +This package contains third-party software components governed by the license(s) indicated below: -[llama.cpp License](https://github.com/ggerganov/llama.cpp/blob/master/LICENSE) +## Component Name: llama.cpp -Component Name: llamafile +Developer: llama.cpp
+Origin: [link](https://github.com/ggerganov/llama.cpp)
+License Type: "MIT"
+License: [link](https://github.com/ggerganov/llama.cpp/blob/master/LICENSE) -License Type: "Apache 2.0" +## Component Name: llamafile -[llamafile License](https://github.com/Mozilla-Ocho/llamafile/blob/main/LICENSE) +Developer: Mozilla Ocho
+Origin: [link](https://github.com/Mozilla-Ocho/llamafile)
+License Type: "Apache 2.0"
+License: [link](https://github.com/Mozilla-Ocho/llamafile/blob/main/LICENSE) -Component Name: "mistralai/Mistral-7B-Instruct-v0.2" +## Component Name: "mistralai/Mistral-7B-Instruct-v0.2" -License Type: "Apache 2.0" +Developer: Mistral AI
+Origin: [link](https://huggingface.co/mistralai/Mistral-7B-Instruct-v0.2)
+License Type: "Apache 2.0"
+License: [link](https://huggingface.co/mistralai/Mistral-7B-Instruct-v0.2/blob/main/README.md) -[mistralai/Mistral-7B-Instruct-v0.2 License](https://huggingface.co/mistralai/Mistral-7B-Instruct-v0.2/blob/main/README.md) +## Component Name: TheBloke/Mistral-7B-Instruct-v0.2-GGUF -Component Name: TheBloke/Mistral-7B-Instruct-v0.2-GGUF +Developer: TheBloke
+Origin: [link](https://huggingface.co/TheBloke/Mistral-7B-Instruct-v0.2-GGUF)
+License Type: "Apache 2.0"
+License: [link](https://huggingface.co/TheBloke/Mistral-7B-Instruct-v0.2-GGUF/blob/main/README.md) -License Type: "Apache 2.0" +## Component Name: sharp-transformers -[TheBloke/Mistral-7B-Instruct-v0.2-GGUF License](https://huggingface.co/TheBloke/Mistral-7B-Instruct-v0.2-GGUF/blob/main/README.md) +Developer: Hugging Face
+Origin: [link](https://github.com/huggingface/sharp-transformers)
+License Type: "Apache 2.0"
+License: [link](https://github.com/huggingface/sharp-transformers/blob/main/LICENSE)
+Modifications: [link](sharp-transformers/README.md) From f143066b9b4b198d17ae84d75376a0c4e1eea565 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 26 Jan 2024 11:01:28 +0200 Subject: [PATCH 024/161] embedding model cloeanup --- Runtime/EmbeddingModel.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Runtime/EmbeddingModel.cs b/Runtime/EmbeddingModel.cs index b380b38b..d2b55cad 100644 --- a/Runtime/EmbeddingModel.cs +++ b/Runtime/EmbeddingModel.cs @@ -44,8 +44,9 @@ public EmbeddingModel(string modelPath, string tokenizerPath, BackendType backen public void Destroy() { - worker.Dispose(); + allocator.Dispose(); ops.Dispose(); + worker.Dispose(); } public TensorFloat Encode(List input) @@ -60,6 +61,9 @@ public TensorFloat Encode(List input) TensorFloat MeanPooledTensor = MeanPooling(inputSentencesTokensTensor["attention_mask"], outputTensor, ops); // Step 5: Normalize the results TensorFloat NormedTensor = L2Norm(MeanPooledTensor, ops); + // Cleanup + foreach (var val in inputSentencesTokensTensor.Values) val.Dispose(); + inputSentencesTokensTensor.Clear(); return NormedTensor; } From 9cc6c45238ded50ec8227f20781f67c2a841504d Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 26 Jan 2024 12:59:43 +0200 Subject: [PATCH 025/161] Concat, Split and additional Encode functions --- Runtime/EmbeddingModel.cs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Runtime/EmbeddingModel.cs b/Runtime/EmbeddingModel.cs index d2b55cad..86aea958 100644 --- a/Runtime/EmbeddingModel.cs +++ b/Runtime/EmbeddingModel.cs @@ -49,6 +49,35 @@ public void Destroy() worker.Dispose(); } + public Tensor Concat(Tensor[] tensors, int axis = 0) + { + return ops.Concat(tensors, axis); + } + + public TensorFloat Concat(TensorFloat[] tensors, int axis = 0) + { + return (TensorFloat)ops.Concat(tensors, axis); + } + + public Tensor[] Split(Tensor tensor, int axis = 0) + { + if (tensor.shape.rank != 2) throw new Exception("Tensor does not have a rank of 2."); + TensorFloat[] tensors = new TensorFloat[tensor.shape[0]]; + for (int i = 0; i < tensor.shape[axis]; i++) + tensors[i] = (TensorFloat)ops.Split(tensor, axis, i, i + 1); + return tensors; + } + + public TensorFloat Encode(string input) + { + return Encode(new List { input }); + } + + public TensorFloat Encode(string[] input) + { + return Encode(new List(input)); + } + public TensorFloat Encode(List input) { // Step 1: Tokenize the sentences From bd096d1d4e122b273e3f85ef0f0bc906ac970030 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 26 Jan 2024 13:00:17 +0200 Subject: [PATCH 026/161] embedding manager based on embedding model --- Runtime/EmbeddingManager.cs | 129 +++++++----------------------------- 1 file changed, 24 insertions(+), 105 deletions(-) diff --git a/Runtime/EmbeddingManager.cs b/Runtime/EmbeddingManager.cs index 82ac2a8f..f3e14876 100644 --- a/Runtime/EmbeddingManager.cs +++ b/Runtime/EmbeddingManager.cs @@ -1,126 +1,45 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Threading.Tasks; -using UnityEngine; - -public enum SimilarityType -{ - Cosine, - L2 -} +using Unity.Sentis; public class EmbeddingManager { - private List<(string, float[])> embeddings; - private Func> embeddingFunction; - private SimilarityType similarityType; - - public EmbeddingManager(Func> embeddingFunction, SimilarityType similarityType = SimilarityType.L2) - { - this.embeddings = new List<(string, float[])>(); - this.embeddingFunction = embeddingFunction; - this.similarityType = similarityType; - } - - public async Task AddString(string inputString) - { - embeddings.Add((inputString, await embeddingFunction(inputString))); - } - - public async Task> RetrieveMostSimilarStrings(string queryString, int numResults) - { - float[] queryEmbedding = await embeddingFunction(queryString); - List> similarities = new List>(); - - for (int i = 0; i < embeddings.Count; i++) - { - float similarity = CalculateSimilarity(queryEmbedding, embeddings[i].Item2); - similarities.Add(new Tuple<(string, float[]), float>(embeddings[i], similarity)); - } - - similarities.Sort((a, b) => b.Item2.CompareTo(a.Item2)); - - List results = new List(); - for (int i = 0; i < Math.Min(numResults, similarities.Count); i++) - { - results.Add(similarities[i].Item1.Item1); - } - - return results; - } + private EmbeddingModel embeddingModel; + private Dictionary embeddings; - private float CalculateSimilarity(float[] vectorA, float[] vectorB) + public EmbeddingManager(EmbeddingModel embeddingModel) { - if (similarityType == SimilarityType.Cosine) - { - return CalculateCosineSimilarity(vectorA, vectorB); - } - else if (similarityType == SimilarityType.L2) - { - return CalculateL2Distance(vectorA, vectorB); - } - else - { - throw new NotSupportedException("Unsupported similarity type"); - } - } - - private float CalculateCosineSimilarity(float[] vectorA, float[] vectorB) - { - // Assuming vectors are of the same length - float dotProduct = 0; - float magnitudeA = 0; - float magnitudeB = 0; - - for (int i = 0; i < vectorA.Length; i++) - { - dotProduct += vectorA[i] * vectorB[i]; - magnitudeA += vectorA[i] * vectorA[i]; - magnitudeB += vectorB[i] * vectorB[i]; - } - - float similarity = dotProduct / (float)(Math.Sqrt(magnitudeA) * Math.Sqrt(magnitudeB)); - return similarity; + embeddings = new Dictionary(); + this.embeddingModel = embeddingModel; } - private float CalculateL2Distance(float[] vectorA, float[] vectorB) + public TensorFloat Add(string inputString) { - float sumOfSquares = 0; - - for (int i = 0; i < vectorA.Length; i++) - { - float diff = vectorA[i] - vectorB[i]; - sumOfSquares += diff * diff; - } - - return Mathf.Sqrt(sumOfSquares); + embeddings[inputString] = embeddingModel.Encode(inputString); + return embeddings[inputString]; } - public void SaveEmbeddingsToFile(string filePath) + public TensorFloat[] Add(string[] inputStrings) { - using (StreamWriter writer = new StreamWriter(filePath)) - { - for (int i = 0; i < embeddings.Count; i++) - { - writer.WriteLine($"{embeddings[i].Item1}|{string.Join(",", embeddings[i].Item2)}"); - } - } + TensorFloat[] inputEmbeddings = (TensorFloat[])embeddingModel.Split(embeddingModel.Encode(inputStrings)); + for (int i = 0; i < inputStrings.Length; i++) embeddings[inputStrings[i]] = inputEmbeddings[i]; + return inputEmbeddings; } - public void LoadEmbeddingsFromFile(string filePath) + public List RetrieveSimilar(string queryString, int numResults) { - embeddings.Clear(); - - using (StreamReader reader = new StreamReader(filePath)) + TensorFloat queryEmbedding = embeddingModel.Encode(queryString); + TensorFloat storeEmbedding = embeddingModel.Concat(embeddings.Values.ToArray()); + float[] scores = embeddingModel.SimilarityScores(queryEmbedding, storeEmbedding); + var sortedLists = embeddings.Keys.Zip(scores, (first, second) => new { First = first, Second = second }) + .OrderByDescending(item => item.Second) + .ToList(); + List results = new List(); + for (int i = 0; i < Math.Min(numResults, sortedLists.Count); i++) { - while (!reader.EndOfStream) - { - string line = reader.ReadLine(); - string[] parts = line.Split('|'); - embeddings.Add((parts[0], parts[1].Split(',').Select(float.Parse).ToArray())); - } + results.Add(sortedLists[i].First); } + return results; } } From 53b454966fd943ac436fb1c2c9873fb43c6c2686 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 26 Jan 2024 15:55:18 +0200 Subject: [PATCH 027/161] generalise embedder and search --- Runtime/{EmbeddingModel.cs => Embedder.cs} | 10 ++- ...eddingManager.cs.meta => Embedder.cs.meta} | 2 +- Runtime/EmbeddingManager.cs | 45 ------------ Runtime/Search.cs | 68 +++++++++++++++++++ ...{EmbeddingModel.cs.meta => Search.cs.meta} | 2 +- 5 files changed, 78 insertions(+), 49 deletions(-) rename Runtime/{EmbeddingModel.cs => Embedder.cs} (98%) rename Runtime/{EmbeddingManager.cs.meta => Embedder.cs.meta} (83%) delete mode 100644 Runtime/EmbeddingManager.cs create mode 100644 Runtime/Search.cs rename Runtime/{EmbeddingModel.cs.meta => Search.cs.meta} (83%) diff --git a/Runtime/EmbeddingModel.cs b/Runtime/Embedder.cs similarity index 98% rename from Runtime/EmbeddingModel.cs rename to Runtime/Embedder.cs index 86aea958..b64c758e 100644 --- a/Runtime/EmbeddingModel.cs +++ b/Runtime/Embedder.cs @@ -14,7 +14,13 @@ using HuggingFace.SharpTransformers.PostProcessors; using System.IO; -public class EmbeddingModel + +public abstract class Embedder +{ + public abstract T Encode(string input); +} + +public class EmbeddingModel : Embedder { Model runtimeModel; IWorker worker; @@ -68,7 +74,7 @@ public Tensor[] Split(Tensor tensor, int axis = 0) return tensors; } - public TensorFloat Encode(string input) + public override TensorFloat Encode(string input) { return Encode(new List { input }); } diff --git a/Runtime/EmbeddingManager.cs.meta b/Runtime/Embedder.cs.meta similarity index 83% rename from Runtime/EmbeddingManager.cs.meta rename to Runtime/Embedder.cs.meta index 3c2961ca..1f5d40cd 100644 --- a/Runtime/EmbeddingManager.cs.meta +++ b/Runtime/Embedder.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: c8e8b8f5c23ce011fbe3c033c7812057 +guid: 3ecc363da4be40d7faffc48eaf542530 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Runtime/EmbeddingManager.cs b/Runtime/EmbeddingManager.cs deleted file mode 100644 index f3e14876..00000000 --- a/Runtime/EmbeddingManager.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Unity.Sentis; - -public class EmbeddingManager -{ - private EmbeddingModel embeddingModel; - private Dictionary embeddings; - - public EmbeddingManager(EmbeddingModel embeddingModel) - { - embeddings = new Dictionary(); - this.embeddingModel = embeddingModel; - } - - public TensorFloat Add(string inputString) - { - embeddings[inputString] = embeddingModel.Encode(inputString); - return embeddings[inputString]; - } - - public TensorFloat[] Add(string[] inputStrings) - { - TensorFloat[] inputEmbeddings = (TensorFloat[])embeddingModel.Split(embeddingModel.Encode(inputStrings)); - for (int i = 0; i < inputStrings.Length; i++) embeddings[inputStrings[i]] = inputEmbeddings[i]; - return inputEmbeddings; - } - - public List RetrieveSimilar(string queryString, int numResults) - { - TensorFloat queryEmbedding = embeddingModel.Encode(queryString); - TensorFloat storeEmbedding = embeddingModel.Concat(embeddings.Values.ToArray()); - float[] scores = embeddingModel.SimilarityScores(queryEmbedding, storeEmbedding); - var sortedLists = embeddings.Keys.Zip(scores, (first, second) => new { First = first, Second = second }) - .OrderByDescending(item => item.Second) - .ToList(); - List results = new List(); - for (int i = 0; i < Math.Min(numResults, sortedLists.Count); i++) - { - results.Add(sortedLists[i].First); - } - return results; - } -} diff --git a/Runtime/Search.cs b/Runtime/Search.cs new file mode 100644 index 00000000..df7c2a65 --- /dev/null +++ b/Runtime/Search.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Unity.Sentis; + +public abstract class Search where E : Embedder +{ + protected E embedder; + protected Dictionary embeddings; + + public Search(E embedder) + { + embeddings = new Dictionary(); + this.embedder = embedder; + } + + public T Add(string inputString) + { + embeddings[inputString] = embedder.Encode(inputString); + return embeddings[inputString]; + } + + public T[] Add(string[] inputStrings) + { + T[] inputEmbeddings = new T[inputStrings.Length]; + for (int i = 0; i < inputStrings.Length; i++) + { + inputEmbeddings[i] = Add(inputStrings[i]); + } + return inputEmbeddings; + } + + public List GetKNN(string[] inputStrings, float[] scores, int k = -1) + { + var sortedLists = inputStrings.Zip(scores, (first, second) => new { First = first, Second = second }) + .OrderByDescending(item => item.Second) + .ToList(); + List results = new List(); + int kmax = k == -1 ? sortedLists.Count : Math.Min(k, sortedLists.Count); + for (int i = 0; i < kmax; i++) + { + results.Add(sortedLists[i].First); + } + return results; + } + + public abstract List RetrieveSimilar(string queryString, int k); +} + +public class ModelSearch : Search +{ + public ModelSearch(EmbeddingModel embedder) : base(embedder) { } + + public new TensorFloat[] Add(string[] inputStrings) + { + TensorFloat[] inputEmbeddings = (TensorFloat[])embedder.Split(embedder.Encode(inputStrings)); + for (int i = 0; i < inputStrings.Length; i++) embeddings[inputStrings[i]] = inputEmbeddings[i]; + return inputEmbeddings; + } + + public override List RetrieveSimilar(string queryString, int k) + { + TensorFloat queryEmbedding = embedder.Encode(queryString); + TensorFloat storeEmbedding = embedder.Concat(embeddings.Values.ToArray()); + float[] scores = embedder.SimilarityScores(queryEmbedding, storeEmbedding); + return GetKNN(embeddings.Keys.ToArray(), scores, k); + } +} diff --git a/Runtime/EmbeddingModel.cs.meta b/Runtime/Search.cs.meta similarity index 83% rename from Runtime/EmbeddingModel.cs.meta rename to Runtime/Search.cs.meta index 2abaa9b6..d2bd4240 100644 --- a/Runtime/EmbeddingModel.cs.meta +++ b/Runtime/Search.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 4818b8a60323a13d5a17d506564641ab +guid: c37aa63e3758f73af8b5f5dc9099a215 MonoImporter: externalObjects: {} serializedVersion: 2 From f9c6461e093176fb605471d2677fc883d1f0e74b Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Sat, 27 Jan 2024 17:13:46 +0200 Subject: [PATCH 028/161] add original csharp implementation of usearch --- usearch/NativeMethods.cs | 130 +++++++++++++++ usearch/USearchException.cs | 8 + usearch/USearchIndex.cs | 323 ++++++++++++++++++++++++++++++++++++ usearch/USearchTypes.cs | 71 ++++++++ 4 files changed, 532 insertions(+) create mode 100644 usearch/NativeMethods.cs create mode 100644 usearch/USearchException.cs create mode 100644 usearch/USearchIndex.cs create mode 100644 usearch/USearchTypes.cs diff --git a/usearch/NativeMethods.cs b/usearch/NativeMethods.cs new file mode 100644 index 00000000..035518ba --- /dev/null +++ b/usearch/NativeMethods.cs @@ -0,0 +1,130 @@ +using System.Runtime.InteropServices; + +using usearch_index_t = System.IntPtr; +using usearch_key_t = System.UInt64; +using usearch_distance_t = System.Single; +using usearch_error_t = System.IntPtr; +using size_t = System.UIntPtr; +using void_ptr_t = System.IntPtr; + +namespace Cloud.Unum.USearch; + +internal static class NativeMethods +{ + private const string LibraryName = "libusearch_c"; + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern usearch_index_t usearch_init(ref IndexOptions options, out usearch_error_t error); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern void usearch_free(usearch_index_t index, out usearch_error_t error); + + [DllImport(LibraryName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void usearch_save(usearch_index_t index, [MarshalAs(UnmanagedType.LPStr)] string path, out usearch_error_t error); + + [DllImport(LibraryName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void usearch_load(usearch_index_t index, [MarshalAs(UnmanagedType.LPStr)] string path, out usearch_error_t error); + + [DllImport(LibraryName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void usearch_view(usearch_index_t index, [MarshalAs(UnmanagedType.LPStr)] string path, out usearch_error_t error); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_size(usearch_index_t index, out usearch_error_t error); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_capacity(usearch_index_t index, out usearch_error_t error); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_dimensions(usearch_index_t index, out usearch_error_t error); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_connectivity(usearch_index_t index, out usearch_error_t error); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern void usearch_reserve(usearch_index_t index, size_t capacity, out usearch_error_t error); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern void usearch_add( + usearch_index_t index, + usearch_key_t key, + [In] float[] vector, + ScalarKind vector_kind, + out usearch_error_t error + ); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern void usearch_add( + usearch_index_t index, + usearch_key_t key, + [In] double[] vector, + ScalarKind vector_kind, + out usearch_error_t error + ); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + public static extern bool usearch_contains(usearch_index_t index, usearch_key_t key, out usearch_error_t error); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_count(usearch_index_t index, usearch_key_t key, out usearch_error_t error); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_search( + usearch_index_t index, + void_ptr_t query_vector, + ScalarKind query_kind, + size_t count, + [Out] usearch_key_t[] found_keys, + [Out] usearch_distance_t[] found_distances, + out usearch_error_t error + ); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_search( + usearch_index_t index, + [In] float[] query_vector, + ScalarKind query_kind, + size_t count, + [Out] usearch_key_t[] found_keys, + [Out] usearch_distance_t[] found_distances, + out usearch_error_t error + ); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_search( + usearch_index_t index, + [In] double[] query_vector, + ScalarKind query_kind, + size_t count, + [Out] usearch_key_t[] found_keys, + [Out] usearch_distance_t[] found_distances, + out usearch_error_t error + ); + + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_get( + usearch_index_t index, + usearch_key_t key, + size_t count, + [Out] float[] vector, + ScalarKind vector_kind, + out usearch_error_t error + ); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_get( + usearch_index_t index, + usearch_key_t key, + size_t count, + [Out] double[] vector, + ScalarKind vector_kind, + out usearch_error_t error + ); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_remove(usearch_index_t index, usearch_key_t key, out usearch_error_t error); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_rename(usearch_index_t index, usearch_key_t key_from, usearch_key_t key_to, out usearch_error_t error); +} diff --git a/usearch/USearchException.cs b/usearch/USearchException.cs new file mode 100644 index 00000000..2f38b5b5 --- /dev/null +++ b/usearch/USearchException.cs @@ -0,0 +1,8 @@ +using System; + +namespace Cloud.Unum.USearch; + +public class USearchException : Exception +{ + public USearchException(string message) : base(message) { } +} diff --git a/usearch/USearchIndex.cs b/usearch/USearchIndex.cs new file mode 100644 index 00000000..7fa222ba --- /dev/null +++ b/usearch/USearchIndex.cs @@ -0,0 +1,323 @@ +using System; +using System.Runtime.InteropServices; +using static Cloud.Unum.USearch.NativeMethods; + +namespace Cloud.Unum.USearch; + +public class USearchIndex : IDisposable +{ + private IntPtr _index; + private bool _disposedValue = false; + private ulong _cachedDimensions; + + public USearchIndex( + MetricKind metricKind, + ScalarKind quantization, + ulong dimensions, + ulong connectivity = 0, + ulong expansionAdd = 0, + ulong expansionSearch = 0, + bool multi = false + //CustomDistanceFunction? customMetric = null + ) + { + IndexOptions initOptions = new() + { + metric_kind = metricKind, + metric = default, + quantization = quantization, + dimensions = dimensions, + connectivity = connectivity, + expansion_add = expansionAdd, + expansion_search = expansionSearch, + multi = multi + }; + + this._index = usearch_init(ref initOptions, out IntPtr error); + HandleError(error); + this._cachedDimensions = dimensions; + } + + public USearchIndex(IndexOptions options) + { + this._index = usearch_init(ref options, out IntPtr error); + HandleError(error); + this._cachedDimensions = options.dimensions; + } + + public USearchIndex(string path, bool view = false) + { + IndexOptions initOptions = new(); + this._index = usearch_init(ref initOptions, out IntPtr error); + Debug.Log(initOptions.metric_kind); + HandleError(error); + + if (view) + { + usearch_view(this._index, path, out error); + } + else + { + usearch_load(this._index, path, out error); + } + + HandleError(error); + + this._cachedDimensions = this.Dimensions(); + } + + public void Save(string path) + { + usearch_save(this._index, path, out IntPtr error); + HandleError(error); + } + + public ulong Size() + { + ulong size = (ulong)usearch_size(this._index, out IntPtr error); + HandleError(error); + return size; + } + + public ulong Capacity() + { + ulong capacity = (ulong)usearch_capacity(this._index, out IntPtr error); + HandleError(error); + return capacity; + } + + public ulong Dimensions() + { + ulong dimensions = (ulong)usearch_dimensions(this._index, out IntPtr error); + HandleError(error); + return dimensions; + } + + public ulong Connectivity() + { + ulong connectivity = (ulong)usearch_connectivity(this._index, out IntPtr error); + HandleError(error); + return connectivity; + } + + public bool Contains(ulong key) + { + bool result = usearch_contains(this._index, key, out IntPtr error); + HandleError(error); + return result; + } + + public int Count(ulong key) + { + int count = checked((int)usearch_count(this._index, key, out IntPtr error)); + HandleError(error); + return count; + } + + private void IncreaseCapacity(ulong size) + { + usearch_reserve(this._index, (UIntPtr)(this.Size() + size), out IntPtr error); + HandleError(error); + } + + private void CheckIncreaseCapacity(ulong size_increase) + { + ulong size_demand = this.Size() + size_increase; + if (this.Capacity() < size_demand) + { + this.IncreaseCapacity(size_increase); + } + } + + public void Add(ulong key, float[] vector) + { + this.CheckIncreaseCapacity(1); + usearch_add(this._index, key, vector, ScalarKind.Float32, out IntPtr error); + HandleError(error); + } + + public void Add(ulong key, double[] vector) + { + this.CheckIncreaseCapacity(1); + usearch_add(this._index, key, vector, ScalarKind.Float64, out IntPtr error); + HandleError(error); + } + + public void Add(ulong[] keys, float[][] vectors) + { + this.CheckIncreaseCapacity((ulong)vectors.Length); + for (int i = 0; i < vectors.Length; i++) + { + usearch_add(this._index, keys[i], vectors[i], ScalarKind.Float32, out IntPtr error); + HandleError(error); + } + } + + public void Add(ulong[] keys, double[][] vectors) + { + this.CheckIncreaseCapacity((ulong)vectors.Length); + for (int i = 0; i < vectors.Length; i++) + { + usearch_add(this._index, keys[i], vectors[i], ScalarKind.Float64, out IntPtr error); + HandleError(error); + } + } + + public int Get(ulong key, out float[] vector) + { + vector = new float[this._cachedDimensions]; + int foundVectorsCount = checked((int)usearch_get(this._index, key, (UIntPtr)1, vector, ScalarKind.Float32, out IntPtr error)); + HandleError(error); + if (foundVectorsCount < 1) + { + vector = null; + } + + return foundVectorsCount; + } + + public int Get(ulong key, int count, out float[][] vectors) + { + var flattenVectors = new float[count * (int)this._cachedDimensions]; + int foundVectorsCount = checked((int)usearch_get(this._index, key, (UIntPtr)count, flattenVectors, ScalarKind.Float32, out IntPtr error)); + HandleError(error); + if (foundVectorsCount < 1) + { + vectors = null; + } + else + { + vectors = new float[foundVectorsCount][]; + for (int i = 0; i < foundVectorsCount; i++) + { + vectors[i] = new float[this._cachedDimensions]; + Array.Copy(flattenVectors, i * (int)this._cachedDimensions, vectors[i], 0, (int)this._cachedDimensions); + } + } + + return foundVectorsCount; + } + + public int Get(ulong key, out double[] vector) + { + vector = new double[this._cachedDimensions]; + int foundVectorsCount = checked((int)usearch_get(this._index, key, (UIntPtr)1, vector, ScalarKind.Float64, out IntPtr error)); + HandleError(error); + if (foundVectorsCount < 1) + { + vector = null; + } + + return foundVectorsCount; + } + + public int Get(ulong key, int count, out double[][] vectors) + { + var flattenVectors = new double[count * (int)this._cachedDimensions]; + int foundVectorsCount = checked((int)usearch_get(this._index, key, (UIntPtr)count, flattenVectors, ScalarKind.Float64, out IntPtr error)); + HandleError(error); + if (foundVectorsCount < 1) + { + vectors = null; + } + else + { + vectors = new double[foundVectorsCount][]; + for (int i = 0; i < foundVectorsCount; i++) + { + vectors[i] = new double[this._cachedDimensions]; + Array.Copy(flattenVectors, i * (int)this._cachedDimensions, vectors[i], 0, (int)this._cachedDimensions); + } + } + + return foundVectorsCount; + } + + private int Search(T[] queryVector, int count, out ulong[] keys, out float[] distances, ScalarKind scalarKind) + { + keys = new ulong[count]; + distances = new float[count]; + + GCHandle handle = GCHandle.Alloc(queryVector, GCHandleType.Pinned); + int matches = 0; + try + { + IntPtr queryVectorPtr = handle.AddrOfPinnedObject(); + matches = checked((int)usearch_search(this._index, queryVectorPtr, scalarKind, (UIntPtr)count, keys, distances, out IntPtr error)); + HandleError(error); + } + finally + { + handle.Free(); + } + + if (matches < count) + { + Array.Resize(ref keys, (int)matches); + Array.Resize(ref distances, (int)matches); + } + + return matches; + } + + public int Search(float[] queryVector, int count, out ulong[] keys, out float[] distances) + { + return this.Search(queryVector, count, out keys, out distances, ScalarKind.Float32); + } + + public int Search(double[] queryVector, int count, out ulong[] keys, out float[] distances) + { + return this.Search(queryVector, count, out keys, out distances, ScalarKind.Float64); + } + + public int Remove(ulong key) + { + int removedCount = checked((int)usearch_remove(this._index, key, out IntPtr error)); + HandleError(error); + return removedCount; + } + + public int Rename(ulong keyFrom, ulong keyTo) + { + int foundVectorsCount = checked((int)usearch_rename(this._index, keyFrom, keyTo, out IntPtr error)); + HandleError(error); + return foundVectorsCount; + } + + private static void HandleError(IntPtr error) + { + if (error != IntPtr.Zero) + { + throw new USearchException($"USearch operation failed: {Marshal.PtrToStringAnsi(error)}"); + } + } + + private void FreeIndex() + { + if (this._index != IntPtr.Zero) + { + usearch_free(this._index, out IntPtr error); + HandleError(error); + this._index = IntPtr.Zero; + } + } + + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!this._disposedValue) + { + this.FreeIndex(); + this._disposedValue = true; + } + } + + ~USearchIndex() => this.Dispose(false); + + +} diff --git a/usearch/USearchTypes.cs b/usearch/USearchTypes.cs new file mode 100644 index 00000000..2757ff8c --- /dev/null +++ b/usearch/USearchTypes.cs @@ -0,0 +1,71 @@ +using System; +using System.Runtime.InteropServices; + +namespace Cloud.Unum.USearch; + +public enum MetricKind : uint +{ + Unknown = 0, + Cos, + Ip, + L2sq, + Haversine, + Pearson, + Jaccard, + Hamming, + Tanimoto, + Sorensen, +} + +public enum ScalarKind : uint +{ + Unknown = 0, + Float32, + Float64, + Float16, + Int8, + Byte1, +} + +// TODO: implement custom metric delegate +// Microsoft guides links: +// 1) https://learn.microsoft.com/en-us/dotnet/standard/native-interop/best-practices +// 2) https://learn.microsoft.com/en-us/dotnet/framework/interop/marshalling-a-delegate-as-a-callback-method +// public delegate float CustomMetricFunction(IntPtr a, IntPtr b); + +[StructLayout(LayoutKind.Sequential)] +public struct IndexOptions +{ + public MetricKind metric_kind; + public IntPtr metric; + public ScalarKind quantization; + public ulong dimensions; + public ulong connectivity; + public ulong expansion_add; + public ulong expansion_search; + + [MarshalAs(UnmanagedType.Bool)] + public bool multi; + + public IndexOptions( + MetricKind metricKind = MetricKind.Unknown, + IntPtr metric = default, + ScalarKind quantization = ScalarKind.Unknown, + ulong dimensions = 0, + ulong connectivity = 0, + ulong expansionAdd = 0, + ulong expansionSearch = 0, + bool multi = false + ) + { + this.metric_kind = metricKind; + this.metric = default; // TODO: Use actual metric param, when support is added for custom metric delegate + this.quantization = quantization; + this.dimensions = dimensions; + this.connectivity = connectivity; + this.expansion_add = expansionAdd; + this.expansion_search = expansionSearch; + this.multi = multi; + } +} + From 96cfb9bccd45baad41e82b62962887704d1f224c Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Sat, 27 Jan 2024 17:14:37 +0200 Subject: [PATCH 029/161] use namespaces in Unity format --- usearch/NativeMethods.cs | 241 +++++++++--------- usearch/USearchException.cs | 9 +- usearch/USearchIndex.cs | 488 ++++++++++++++++++------------------ usearch/USearchTypes.cs | 120 ++++----- 4 files changed, 430 insertions(+), 428 deletions(-) diff --git a/usearch/NativeMethods.cs b/usearch/NativeMethods.cs index 035518ba..67e81a05 100644 --- a/usearch/NativeMethods.cs +++ b/usearch/NativeMethods.cs @@ -7,124 +7,125 @@ using size_t = System.UIntPtr; using void_ptr_t = System.IntPtr; -namespace Cloud.Unum.USearch; - -internal static class NativeMethods +namespace Cloud.Unum.USearch { - private const string LibraryName = "libusearch_c"; - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] - public static extern usearch_index_t usearch_init(ref IndexOptions options, out usearch_error_t error); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] - public static extern void usearch_free(usearch_index_t index, out usearch_error_t error); - - [DllImport(LibraryName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - public static extern void usearch_save(usearch_index_t index, [MarshalAs(UnmanagedType.LPStr)] string path, out usearch_error_t error); - - [DllImport(LibraryName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - public static extern void usearch_load(usearch_index_t index, [MarshalAs(UnmanagedType.LPStr)] string path, out usearch_error_t error); - - [DllImport(LibraryName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] - public static extern void usearch_view(usearch_index_t index, [MarshalAs(UnmanagedType.LPStr)] string path, out usearch_error_t error); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] - public static extern size_t usearch_size(usearch_index_t index, out usearch_error_t error); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] - public static extern size_t usearch_capacity(usearch_index_t index, out usearch_error_t error); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] - public static extern size_t usearch_dimensions(usearch_index_t index, out usearch_error_t error); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] - public static extern size_t usearch_connectivity(usearch_index_t index, out usearch_error_t error); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] - public static extern void usearch_reserve(usearch_index_t index, size_t capacity, out usearch_error_t error); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] - public static extern void usearch_add( - usearch_index_t index, - usearch_key_t key, - [In] float[] vector, - ScalarKind vector_kind, - out usearch_error_t error - ); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] - public static extern void usearch_add( - usearch_index_t index, - usearch_key_t key, - [In] double[] vector, - ScalarKind vector_kind, - out usearch_error_t error - ); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] - [return: MarshalAs(UnmanagedType.I1)] - public static extern bool usearch_contains(usearch_index_t index, usearch_key_t key, out usearch_error_t error); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] - public static extern size_t usearch_count(usearch_index_t index, usearch_key_t key, out usearch_error_t error); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] - public static extern size_t usearch_search( - usearch_index_t index, - void_ptr_t query_vector, - ScalarKind query_kind, - size_t count, - [Out] usearch_key_t[] found_keys, - [Out] usearch_distance_t[] found_distances, - out usearch_error_t error - ); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] - public static extern size_t usearch_search( - usearch_index_t index, - [In] float[] query_vector, - ScalarKind query_kind, - size_t count, - [Out] usearch_key_t[] found_keys, - [Out] usearch_distance_t[] found_distances, - out usearch_error_t error - ); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] - public static extern size_t usearch_search( - usearch_index_t index, - [In] double[] query_vector, - ScalarKind query_kind, - size_t count, - [Out] usearch_key_t[] found_keys, - [Out] usearch_distance_t[] found_distances, - out usearch_error_t error - ); - - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] - public static extern size_t usearch_get( - usearch_index_t index, - usearch_key_t key, - size_t count, - [Out] float[] vector, - ScalarKind vector_kind, - out usearch_error_t error - ); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] - public static extern size_t usearch_get( - usearch_index_t index, - usearch_key_t key, - size_t count, - [Out] double[] vector, - ScalarKind vector_kind, - out usearch_error_t error - ); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] - public static extern size_t usearch_remove(usearch_index_t index, usearch_key_t key, out usearch_error_t error); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] - public static extern size_t usearch_rename(usearch_index_t index, usearch_key_t key_from, usearch_key_t key_to, out usearch_error_t error); -} + internal static class NativeMethods + { + private const string LibraryName = "libusearch_c"; + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern usearch_index_t usearch_init(ref IndexOptions options, out usearch_error_t error); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern void usearch_free(usearch_index_t index, out usearch_error_t error); + + [DllImport(LibraryName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void usearch_save(usearch_index_t index, [MarshalAs(UnmanagedType.LPStr)] string path, out usearch_error_t error); + + [DllImport(LibraryName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void usearch_load(usearch_index_t index, [MarshalAs(UnmanagedType.LPStr)] string path, out usearch_error_t error); + + [DllImport(LibraryName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void usearch_view(usearch_index_t index, [MarshalAs(UnmanagedType.LPStr)] string path, out usearch_error_t error); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_size(usearch_index_t index, out usearch_error_t error); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_capacity(usearch_index_t index, out usearch_error_t error); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_dimensions(usearch_index_t index, out usearch_error_t error); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_connectivity(usearch_index_t index, out usearch_error_t error); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern void usearch_reserve(usearch_index_t index, size_t capacity, out usearch_error_t error); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern void usearch_add( + usearch_index_t index, + usearch_key_t key, + [In] float[] vector, + ScalarKind vector_kind, + out usearch_error_t error + ); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern void usearch_add( + usearch_index_t index, + usearch_key_t key, + [In] double[] vector, + ScalarKind vector_kind, + out usearch_error_t error + ); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + public static extern bool usearch_contains(usearch_index_t index, usearch_key_t key, out usearch_error_t error); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_count(usearch_index_t index, usearch_key_t key, out usearch_error_t error); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_search( + usearch_index_t index, + void_ptr_t query_vector, + ScalarKind query_kind, + size_t count, + [Out] usearch_key_t[] found_keys, + [Out] usearch_distance_t[] found_distances, + out usearch_error_t error + ); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_search( + usearch_index_t index, + [In] float[] query_vector, + ScalarKind query_kind, + size_t count, + [Out] usearch_key_t[] found_keys, + [Out] usearch_distance_t[] found_distances, + out usearch_error_t error + ); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_search( + usearch_index_t index, + [In] double[] query_vector, + ScalarKind query_kind, + size_t count, + [Out] usearch_key_t[] found_keys, + [Out] usearch_distance_t[] found_distances, + out usearch_error_t error + ); + + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_get( + usearch_index_t index, + usearch_key_t key, + size_t count, + [Out] float[] vector, + ScalarKind vector_kind, + out usearch_error_t error + ); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_get( + usearch_index_t index, + usearch_key_t key, + size_t count, + [Out] double[] vector, + ScalarKind vector_kind, + out usearch_error_t error + ); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_remove(usearch_index_t index, usearch_key_t key, out usearch_error_t error); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + public static extern size_t usearch_rename(usearch_index_t index, usearch_key_t key_from, usearch_key_t key_to, out usearch_error_t error); + } +} \ No newline at end of file diff --git a/usearch/USearchException.cs b/usearch/USearchException.cs index 2f38b5b5..5f5f258d 100644 --- a/usearch/USearchException.cs +++ b/usearch/USearchException.cs @@ -1,8 +1,9 @@ using System; -namespace Cloud.Unum.USearch; - -public class USearchException : Exception +namespace Cloud.Unum.USearch { - public USearchException(string message) : base(message) { } + public class USearchException : Exception + { + public USearchException(string message) : base(message) {} + } } diff --git a/usearch/USearchIndex.cs b/usearch/USearchIndex.cs index 7fa222ba..e6d0161e 100644 --- a/usearch/USearchIndex.cs +++ b/usearch/USearchIndex.cs @@ -2,322 +2,322 @@ using System.Runtime.InteropServices; using static Cloud.Unum.USearch.NativeMethods; -namespace Cloud.Unum.USearch; - -public class USearchIndex : IDisposable +namespace Cloud.Unum.USearch { - private IntPtr _index; - private bool _disposedValue = false; - private ulong _cachedDimensions; - - public USearchIndex( - MetricKind metricKind, - ScalarKind quantization, - ulong dimensions, - ulong connectivity = 0, - ulong expansionAdd = 0, - ulong expansionSearch = 0, - bool multi = false - //CustomDistanceFunction? customMetric = null - ) - { - IndexOptions initOptions = new() - { - metric_kind = metricKind, - metric = default, - quantization = quantization, - dimensions = dimensions, - connectivity = connectivity, - expansion_add = expansionAdd, - expansion_search = expansionSearch, - multi = multi - }; - - this._index = usearch_init(ref initOptions, out IntPtr error); - HandleError(error); - this._cachedDimensions = dimensions; - } - - public USearchIndex(IndexOptions options) + public class USearchIndex : IDisposable { - this._index = usearch_init(ref options, out IntPtr error); - HandleError(error); - this._cachedDimensions = options.dimensions; - } - - public USearchIndex(string path, bool view = false) - { - IndexOptions initOptions = new(); - this._index = usearch_init(ref initOptions, out IntPtr error); - Debug.Log(initOptions.metric_kind); - HandleError(error); - - if (view) + private IntPtr _index; + private bool _disposedValue = false; + private ulong _cachedDimensions; + + public USearchIndex( + MetricKind metricKind, + ScalarKind quantization, + ulong dimensions, + ulong connectivity = 0, + ulong expansionAdd = 0, + ulong expansionSearch = 0, + bool multi = false + //CustomDistanceFunction? customMetric = null + ) { - usearch_view(this._index, path, out error); + IndexOptions initOptions = new() + { + metric_kind = metricKind, + metric = default, + quantization = quantization, + dimensions = dimensions, + connectivity = connectivity, + expansion_add = expansionAdd, + expansion_search = expansionSearch, + multi = multi + }; + + this._index = usearch_init(ref initOptions, out IntPtr error); + HandleError(error); + this._cachedDimensions = dimensions; } - else + + public USearchIndex(IndexOptions options) { - usearch_load(this._index, path, out error); + this._index = usearch_init(ref options, out IntPtr error); + HandleError(error); + this._cachedDimensions = options.dimensions; } - HandleError(error); - - this._cachedDimensions = this.Dimensions(); - } - - public void Save(string path) - { - usearch_save(this._index, path, out IntPtr error); - HandleError(error); - } - - public ulong Size() - { - ulong size = (ulong)usearch_size(this._index, out IntPtr error); - HandleError(error); - return size; - } - - public ulong Capacity() - { - ulong capacity = (ulong)usearch_capacity(this._index, out IntPtr error); - HandleError(error); - return capacity; - } - - public ulong Dimensions() - { - ulong dimensions = (ulong)usearch_dimensions(this._index, out IntPtr error); - HandleError(error); - return dimensions; - } - - public ulong Connectivity() - { - ulong connectivity = (ulong)usearch_connectivity(this._index, out IntPtr error); - HandleError(error); - return connectivity; - } + public USearchIndex(string path, bool view = false) + { + IndexOptions initOptions = new(); + this._index = usearch_init(ref initOptions, out IntPtr error); + HandleError(error); - public bool Contains(ulong key) - { - bool result = usearch_contains(this._index, key, out IntPtr error); - HandleError(error); - return result; - } + if (view) + { + usearch_view(this._index, path, out error); + } + else + { + usearch_load(this._index, path, out error); + } - public int Count(ulong key) - { - int count = checked((int)usearch_count(this._index, key, out IntPtr error)); - HandleError(error); - return count; - } + HandleError(error); - private void IncreaseCapacity(ulong size) - { - usearch_reserve(this._index, (UIntPtr)(this.Size() + size), out IntPtr error); - HandleError(error); - } + this._cachedDimensions = this.Dimensions(); + } - private void CheckIncreaseCapacity(ulong size_increase) - { - ulong size_demand = this.Size() + size_increase; - if (this.Capacity() < size_demand) + public void Save(string path) { - this.IncreaseCapacity(size_increase); + usearch_save(this._index, path, out IntPtr error); + HandleError(error); } - } - public void Add(ulong key, float[] vector) - { - this.CheckIncreaseCapacity(1); - usearch_add(this._index, key, vector, ScalarKind.Float32, out IntPtr error); - HandleError(error); - } + public ulong Size() + { + ulong size = (ulong)usearch_size(this._index, out IntPtr error); + HandleError(error); + return size; + } - public void Add(ulong key, double[] vector) - { - this.CheckIncreaseCapacity(1); - usearch_add(this._index, key, vector, ScalarKind.Float64, out IntPtr error); - HandleError(error); - } + public ulong Capacity() + { + ulong capacity = (ulong)usearch_capacity(this._index, out IntPtr error); + HandleError(error); + return capacity; + } - public void Add(ulong[] keys, float[][] vectors) - { - this.CheckIncreaseCapacity((ulong)vectors.Length); - for (int i = 0; i < vectors.Length; i++) + public ulong Dimensions() { - usearch_add(this._index, keys[i], vectors[i], ScalarKind.Float32, out IntPtr error); + ulong dimensions = (ulong)usearch_dimensions(this._index, out IntPtr error); HandleError(error); + return dimensions; } - } - public void Add(ulong[] keys, double[][] vectors) - { - this.CheckIncreaseCapacity((ulong)vectors.Length); - for (int i = 0; i < vectors.Length; i++) + public ulong Connectivity() { - usearch_add(this._index, keys[i], vectors[i], ScalarKind.Float64, out IntPtr error); + ulong connectivity = (ulong)usearch_connectivity(this._index, out IntPtr error); HandleError(error); + return connectivity; } - } - public int Get(ulong key, out float[] vector) - { - vector = new float[this._cachedDimensions]; - int foundVectorsCount = checked((int)usearch_get(this._index, key, (UIntPtr)1, vector, ScalarKind.Float32, out IntPtr error)); - HandleError(error); - if (foundVectorsCount < 1) + public bool Contains(ulong key) { - vector = null; + bool result = usearch_contains(this._index, key, out IntPtr error); + HandleError(error); + return result; } - return foundVectorsCount; - } + public int Count(ulong key) + { + int count = checked((int)usearch_count(this._index, key, out IntPtr error)); + HandleError(error); + return count; + } - public int Get(ulong key, int count, out float[][] vectors) - { - var flattenVectors = new float[count * (int)this._cachedDimensions]; - int foundVectorsCount = checked((int)usearch_get(this._index, key, (UIntPtr)count, flattenVectors, ScalarKind.Float32, out IntPtr error)); - HandleError(error); - if (foundVectorsCount < 1) + private void IncreaseCapacity(ulong size) { - vectors = null; + usearch_reserve(this._index, (UIntPtr)(this.Size() + size), out IntPtr error); + HandleError(error); } - else + + private void CheckIncreaseCapacity(ulong size_increase) { - vectors = new float[foundVectorsCount][]; - for (int i = 0; i < foundVectorsCount; i++) + ulong size_demand = this.Size() + size_increase; + if (this.Capacity() < size_demand) { - vectors[i] = new float[this._cachedDimensions]; - Array.Copy(flattenVectors, i * (int)this._cachedDimensions, vectors[i], 0, (int)this._cachedDimensions); + this.IncreaseCapacity(size_increase); } } - return foundVectorsCount; - } - - public int Get(ulong key, out double[] vector) - { - vector = new double[this._cachedDimensions]; - int foundVectorsCount = checked((int)usearch_get(this._index, key, (UIntPtr)1, vector, ScalarKind.Float64, out IntPtr error)); - HandleError(error); - if (foundVectorsCount < 1) + public void Add(ulong key, float[] vector) { - vector = null; + this.CheckIncreaseCapacity(1); + usearch_add(this._index, key, vector, ScalarKind.Float32, out IntPtr error); + HandleError(error); } - return foundVectorsCount; - } + public void Add(ulong key, double[] vector) + { + this.CheckIncreaseCapacity(1); + usearch_add(this._index, key, vector, ScalarKind.Float64, out IntPtr error); + HandleError(error); + } - public int Get(ulong key, int count, out double[][] vectors) - { - var flattenVectors = new double[count * (int)this._cachedDimensions]; - int foundVectorsCount = checked((int)usearch_get(this._index, key, (UIntPtr)count, flattenVectors, ScalarKind.Float64, out IntPtr error)); - HandleError(error); - if (foundVectorsCount < 1) + public void Add(ulong[] keys, float[][] vectors) { - vectors = null; + this.CheckIncreaseCapacity((ulong)vectors.Length); + for (int i = 0; i < vectors.Length; i++) + { + usearch_add(this._index, keys[i], vectors[i], ScalarKind.Float32, out IntPtr error); + HandleError(error); + } } - else + + public void Add(ulong[] keys, double[][] vectors) { - vectors = new double[foundVectorsCount][]; - for (int i = 0; i < foundVectorsCount; i++) + this.CheckIncreaseCapacity((ulong)vectors.Length); + for (int i = 0; i < vectors.Length; i++) { - vectors[i] = new double[this._cachedDimensions]; - Array.Copy(flattenVectors, i * (int)this._cachedDimensions, vectors[i], 0, (int)this._cachedDimensions); + usearch_add(this._index, keys[i], vectors[i], ScalarKind.Float64, out IntPtr error); + HandleError(error); } } - return foundVectorsCount; - } + public int Get(ulong key, out float[] vector) + { + vector = new float[this._cachedDimensions]; + int foundVectorsCount = checked((int)usearch_get(this._index, key, (UIntPtr)1, vector, ScalarKind.Float32, out IntPtr error)); + HandleError(error); + if (foundVectorsCount < 1) + { + vector = null; + } - private int Search(T[] queryVector, int count, out ulong[] keys, out float[] distances, ScalarKind scalarKind) - { - keys = new ulong[count]; - distances = new float[count]; + return foundVectorsCount; + } - GCHandle handle = GCHandle.Alloc(queryVector, GCHandleType.Pinned); - int matches = 0; - try + public int Get(ulong key, int count, out float[][] vectors) { - IntPtr queryVectorPtr = handle.AddrOfPinnedObject(); - matches = checked((int)usearch_search(this._index, queryVectorPtr, scalarKind, (UIntPtr)count, keys, distances, out IntPtr error)); + var flattenVectors = new float[count * (int)this._cachedDimensions]; + int foundVectorsCount = checked((int)usearch_get(this._index, key, (UIntPtr)count, flattenVectors, ScalarKind.Float32, out IntPtr error)); HandleError(error); + if (foundVectorsCount < 1) + { + vectors = null; + } + else + { + vectors = new float[foundVectorsCount][]; + for (int i = 0; i < foundVectorsCount; i++) + { + vectors[i] = new float[this._cachedDimensions]; + Array.Copy(flattenVectors, i * (int)this._cachedDimensions, vectors[i], 0, (int)this._cachedDimensions); + } + } + + return foundVectorsCount; } - finally + + public int Get(ulong key, out double[] vector) { - handle.Free(); + vector = new double[this._cachedDimensions]; + int foundVectorsCount = checked((int)usearch_get(this._index, key, (UIntPtr)1, vector, ScalarKind.Float64, out IntPtr error)); + HandleError(error); + if (foundVectorsCount < 1) + { + vector = null; + } + + return foundVectorsCount; } - if (matches < count) + public int Get(ulong key, int count, out double[][] vectors) { - Array.Resize(ref keys, (int)matches); - Array.Resize(ref distances, (int)matches); + var flattenVectors = new double[count * (int)this._cachedDimensions]; + int foundVectorsCount = checked((int)usearch_get(this._index, key, (UIntPtr)count, flattenVectors, ScalarKind.Float64, out IntPtr error)); + HandleError(error); + if (foundVectorsCount < 1) + { + vectors = null; + } + else + { + vectors = new double[foundVectorsCount][]; + for (int i = 0; i < foundVectorsCount; i++) + { + vectors[i] = new double[this._cachedDimensions]; + Array.Copy(flattenVectors, i * (int)this._cachedDimensions, vectors[i], 0, (int)this._cachedDimensions); + } + } + + return foundVectorsCount; } - return matches; - } + private int Search(T[] queryVector, int count, out ulong[] keys, out float[] distances, ScalarKind scalarKind) + { + keys = new ulong[count]; + distances = new float[count]; - public int Search(float[] queryVector, int count, out ulong[] keys, out float[] distances) - { - return this.Search(queryVector, count, out keys, out distances, ScalarKind.Float32); - } + GCHandle handle = GCHandle.Alloc(queryVector, GCHandleType.Pinned); + int matches = 0; + try + { + IntPtr queryVectorPtr = handle.AddrOfPinnedObject(); + matches = checked((int)usearch_search(this._index, queryVectorPtr, scalarKind, (UIntPtr)count, keys, distances, out IntPtr error)); + HandleError(error); + } + finally + { + handle.Free(); + } - public int Search(double[] queryVector, int count, out ulong[] keys, out float[] distances) - { - return this.Search(queryVector, count, out keys, out distances, ScalarKind.Float64); - } + if (matches < count) + { + Array.Resize(ref keys, (int)matches); + Array.Resize(ref distances, (int)matches); + } - public int Remove(ulong key) - { - int removedCount = checked((int)usearch_remove(this._index, key, out IntPtr error)); - HandleError(error); - return removedCount; - } + return matches; + } - public int Rename(ulong keyFrom, ulong keyTo) - { - int foundVectorsCount = checked((int)usearch_rename(this._index, keyFrom, keyTo, out IntPtr error)); - HandleError(error); - return foundVectorsCount; - } + public int Search(float[] queryVector, int count, out ulong[] keys, out float[] distances) + { + return this.Search(queryVector, count, out keys, out distances, ScalarKind.Float32); + } - private static void HandleError(IntPtr error) - { - if (error != IntPtr.Zero) + public int Search(double[] queryVector, int count, out ulong[] keys, out float[] distances) { - throw new USearchException($"USearch operation failed: {Marshal.PtrToStringAnsi(error)}"); + return this.Search(queryVector, count, out keys, out distances, ScalarKind.Float64); } - } - private void FreeIndex() - { - if (this._index != IntPtr.Zero) + public int Remove(ulong key) { - usearch_free(this._index, out IntPtr error); + int removedCount = checked((int)usearch_remove(this._index, key, out IntPtr error)); HandleError(error); - this._index = IntPtr.Zero; + return removedCount; } - } - public void Dispose() - { - this.Dispose(true); - GC.SuppressFinalize(this); - } + public int Rename(ulong keyFrom, ulong keyTo) + { + int foundVectorsCount = checked((int)usearch_rename(this._index, keyFrom, keyTo, out IntPtr error)); + HandleError(error); + return foundVectorsCount; + } - protected virtual void Dispose(bool disposing) - { - if (!this._disposedValue) + private static void HandleError(IntPtr error) { - this.FreeIndex(); - this._disposedValue = true; + if (error != IntPtr.Zero) + { + throw new USearchException($"USearch operation failed: {Marshal.PtrToStringAnsi(error)}"); + } + } + + private void FreeIndex() + { + if (this._index != IntPtr.Zero) + { + usearch_free(this._index, out IntPtr error); + HandleError(error); + this._index = IntPtr.Zero; + } } - } - ~USearchIndex() => this.Dispose(false); + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + protected virtual void Dispose(bool disposing) + { + if (!this._disposedValue) + { + this.FreeIndex(); + this._disposedValue = true; + } + } + + ~USearchIndex() => this.Dispose(false); -} + + } +} \ No newline at end of file diff --git a/usearch/USearchTypes.cs b/usearch/USearchTypes.cs index 2757ff8c..65e1f2a7 100644 --- a/usearch/USearchTypes.cs +++ b/usearch/USearchTypes.cs @@ -1,71 +1,71 @@ using System; using System.Runtime.InteropServices; -namespace Cloud.Unum.USearch; - -public enum MetricKind : uint +namespace Cloud.Unum.USearch { - Unknown = 0, - Cos, - Ip, - L2sq, - Haversine, - Pearson, - Jaccard, - Hamming, - Tanimoto, - Sorensen, -} + public enum MetricKind : uint + { + Unknown = 0, + Cos, + Ip, + L2sq, + Haversine, + Pearson, + Jaccard, + Hamming, + Tanimoto, + Sorensen, + } -public enum ScalarKind : uint -{ - Unknown = 0, - Float32, - Float64, - Float16, - Int8, - Byte1, -} + public enum ScalarKind : uint + { + Unknown = 0, + Float32, + Float64, + Float16, + Int8, + Byte1, + } -// TODO: implement custom metric delegate -// Microsoft guides links: -// 1) https://learn.microsoft.com/en-us/dotnet/standard/native-interop/best-practices -// 2) https://learn.microsoft.com/en-us/dotnet/framework/interop/marshalling-a-delegate-as-a-callback-method -// public delegate float CustomMetricFunction(IntPtr a, IntPtr b); + // TODO: implement custom metric delegate + // Microsoft guides links: + // 1) https://learn.microsoft.com/en-us/dotnet/standard/native-interop/best-practices + // 2) https://learn.microsoft.com/en-us/dotnet/framework/interop/marshalling-a-delegate-as-a-callback-method + // public delegate float CustomMetricFunction(IntPtr a, IntPtr b); -[StructLayout(LayoutKind.Sequential)] -public struct IndexOptions -{ - public MetricKind metric_kind; - public IntPtr metric; - public ScalarKind quantization; - public ulong dimensions; - public ulong connectivity; - public ulong expansion_add; - public ulong expansion_search; + [StructLayout(LayoutKind.Sequential)] + public struct IndexOptions + { + public MetricKind metric_kind; + public IntPtr metric; + public ScalarKind quantization; + public ulong dimensions; + public ulong connectivity; + public ulong expansion_add; + public ulong expansion_search; - [MarshalAs(UnmanagedType.Bool)] - public bool multi; + [MarshalAs(UnmanagedType.Bool)] + public bool multi; - public IndexOptions( - MetricKind metricKind = MetricKind.Unknown, - IntPtr metric = default, - ScalarKind quantization = ScalarKind.Unknown, - ulong dimensions = 0, - ulong connectivity = 0, - ulong expansionAdd = 0, - ulong expansionSearch = 0, - bool multi = false - ) - { - this.metric_kind = metricKind; - this.metric = default; // TODO: Use actual metric param, when support is added for custom metric delegate - this.quantization = quantization; - this.dimensions = dimensions; - this.connectivity = connectivity; - this.expansion_add = expansionAdd; - this.expansion_search = expansionSearch; - this.multi = multi; + public IndexOptions( + MetricKind metricKind = MetricKind.Unknown, + IntPtr metric = default, + ScalarKind quantization = ScalarKind.Unknown, + ulong dimensions = 0, + ulong connectivity = 0, + ulong expansionAdd = 0, + ulong expansionSearch = 0, + bool multi = false + ) + { + this.metric_kind = metricKind; + this.metric = default; // TODO: Use actual metric param, when support is added for custom metric delegate + this.quantization = quantization; + this.dimensions = dimensions; + this.connectivity = connectivity; + this.expansion_add = expansionAdd; + this.expansion_search = expansionSearch; + this.multi = multi; + } } } - From e228ba326a1b3c99411adc3e9c0bc8b61a1a4bd1 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Sat, 27 Jan 2024 17:17:01 +0200 Subject: [PATCH 030/161] init metadata from path --- usearch/USearchIndex.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/usearch/USearchIndex.cs b/usearch/USearchIndex.cs index e6d0161e..a7ebbcd2 100644 --- a/usearch/USearchIndex.cs +++ b/usearch/USearchIndex.cs @@ -48,7 +48,9 @@ public USearchIndex(IndexOptions options) public USearchIndex(string path, bool view = false) { IndexOptions initOptions = new(); - this._index = usearch_init(ref initOptions, out IntPtr error); + usearch_metadata(path, ref initOptions, out IntPtr error); + HandleError(error); + this._index = usearch_init(ref initOptions, out error); HandleError(error); if (view) @@ -317,7 +319,5 @@ protected virtual void Dispose(bool disposing) } ~USearchIndex() => this.Dispose(false); - - } -} \ No newline at end of file +} From 73b5124d49e3e24b5d244aa6d1b4647c94f370a7 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Sat, 27 Jan 2024 18:29:10 +0200 Subject: [PATCH 031/161] serialise and store/load index options --- usearch/USearchIndex.cs | 66 +++++++++++++++++++++++++++++++---------- usearch/USearchTypes.cs | 1 + 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/usearch/USearchIndex.cs b/usearch/USearchIndex.cs index a7ebbcd2..544a9296 100644 --- a/usearch/USearchIndex.cs +++ b/usearch/USearchIndex.cs @@ -1,5 +1,7 @@ using System; +using System.IO; using System.Runtime.InteropServices; +using System.Runtime.Serialization.Formatters.Binary; using static Cloud.Unum.USearch.NativeMethods; namespace Cloud.Unum.USearch @@ -9,6 +11,7 @@ public class USearchIndex : IDisposable private IntPtr _index; private bool _disposedValue = false; private ulong _cachedDimensions; + private IndexOptions _initOptions; public USearchIndex( MetricKind metricKind, @@ -18,7 +21,7 @@ public USearchIndex( ulong expansionAdd = 0, ulong expansionSearch = 0, bool multi = false - //CustomDistanceFunction? customMetric = null + //CustomDistanceFunction? customMetric = null ) { IndexOptions initOptions = new() @@ -32,27 +35,20 @@ public USearchIndex( expansion_search = expansionSearch, multi = multi }; - - this._index = usearch_init(ref initOptions, out IntPtr error); - HandleError(error); - this._cachedDimensions = dimensions; + Init(initOptions); } public USearchIndex(IndexOptions options) { - this._index = usearch_init(ref options, out IntPtr error); - HandleError(error); - this._cachedDimensions = options.dimensions; + Init(options); } public USearchIndex(string path, bool view = false) { - IndexOptions initOptions = new(); - usearch_metadata(path, ref initOptions, out IntPtr error); - HandleError(error); - this._index = usearch_init(ref initOptions, out error); - HandleError(error); + IndexOptions initOptions = LoadIndexOptions(path + ".index_options"); + Init(initOptions); + IntPtr error; if (view) { usearch_view(this._index, path, out error); @@ -61,16 +57,56 @@ public USearchIndex(string path, bool view = false) { usearch_load(this._index, path, out error); } - HandleError(error); + } - this._cachedDimensions = this.Dimensions(); + public void Init(IndexOptions options) + { + _initOptions = options; + this._index = usearch_init(ref options, out IntPtr error); + HandleError(error); + this._cachedDimensions = options.dimensions; } public void Save(string path) { usearch_save(this._index, path, out IntPtr error); HandleError(error); + SaveIndexOptions(path + ".index_options"); + } + + public void SaveIndexOptions(string path) + { + try + { + using (FileStream fileStream = new FileStream(path, FileMode.Create)) + { + BinaryFormatter formatter = new BinaryFormatter(); + formatter.Serialize(fileStream, _initOptions); + } + } + catch (Exception ex) + { + Console.WriteLine($"Error serializing struct: {ex.Message}"); + } + } + + public IndexOptions LoadIndexOptions(string path) + { + IndexOptions initOptions = default; + try + { + using (FileStream fileStream = new FileStream(path, FileMode.Open)) + { + BinaryFormatter formatter = new BinaryFormatter(); + initOptions = (IndexOptions)formatter.Deserialize(fileStream); + } + } + catch (Exception ex) + { + Console.WriteLine($"Error deserializing struct: {ex.Message}"); + } + return initOptions; } public ulong Size() diff --git a/usearch/USearchTypes.cs b/usearch/USearchTypes.cs index 65e1f2a7..c780181b 100644 --- a/usearch/USearchTypes.cs +++ b/usearch/USearchTypes.cs @@ -33,6 +33,7 @@ public enum ScalarKind : uint // 2) https://learn.microsoft.com/en-us/dotnet/framework/interop/marshalling-a-delegate-as-a-callback-method // public delegate float CustomMetricFunction(IntPtr a, IntPtr b); + [Serializable] [StructLayout(LayoutKind.Sequential)] public struct IndexOptions { From 737ddb731e8340490048d8d91cc36085f9387b0a Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Sat, 27 Jan 2024 18:31:06 +0200 Subject: [PATCH 032/161] add usearch libraries --- usearch/libusearch_c.dll | Bin 0 -> 113152 bytes usearch/libusearch_c.dylib | Bin 0 -> 274240 bytes usearch/libusearch_c.so | Bin 0 -> 246968 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 usearch/libusearch_c.dll create mode 100644 usearch/libusearch_c.dylib create mode 100644 usearch/libusearch_c.so diff --git a/usearch/libusearch_c.dll b/usearch/libusearch_c.dll new file mode 100644 index 0000000000000000000000000000000000000000..849cc3529e2bace0cfced2064be3d82e95996270 GIT binary patch literal 113152 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

{cT*n#jD%z_UEnr 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 fWwD+A6P9DDRh;I3W~1ic)gW%qNAb|5MDoLC4fD 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

  • 4oHRJOp z*S4e=oM-vMU-i%Ob7Rxm^KP?#ZSS%zmFHQxw%~#Hp*!mPDlg18*x)WbU+@uh6%cW6 zK5l#q&fQ0tpMn$GFFV4Sd2W1W+tRaq$+49Lj>UO$UT(aba71IP#`P|fbu5o9pMBOV zr~{lckKkPEV6wq&-SuqMrpl|@;(FB>&yIV>v$UBOBy$JsIKafa8}8^&wQc$`%cs$tiBj8&e;85>WPI8)+87L&CN z=`#LA)9$Lkdl}f#FuWZzhPU~hOv0vuc~wmc9H9PVTALqOUnFq*@HjgS6V+C$P#AAB zuHfs<(af0Du&52fO-yFBVQp{VE7sX;&1%-ote|QuwzW!*j>xR$xtZbp*0Nr%W=-n~ z1G`I-Zf4KxjhYI9yR?YiO5(K0Oor{eiq%4KAb~NGC@38enX#DN^6V}^GahBgI`_(K z>r|E}jp{wT{ojhUa+i2d%?bjLcOrQ`uQ87j><#O_XU4d;wnNePy4l*GQ`y>{m$mFb zmJZMxudxHj>`_0y0-1Si;Q>zUV{79W1B1M?G}L<)5B$Y8+W;Flnqe$ zhxY`kuTLmTdaGe%vW8a-gjDkmljA9Z54ScC$S-+7x>mP724ZM$O>Df}jHL!b0DkV% z$5My2qX&A7WiV9*z~Ld*$5@((6BPMOxFz82bc*o;hqQ^yOqn@;h!U)4d?gws6t?l`k}2tJ++Qty@81_E)3Io#<)J5 zz-FrcloJ?{Xsbs3$7BOxd_WXq+~*+soxM7MU1f?U4RRd{czM(oWgP)X#sQ3155uT* z+tK)TePcH!KMWRCzZ&{&-0Ju-qFO!L#Z_4xN}b3z5+8jtCM~Svq8B`kZ>`n%Zptq~ z<-0AvOe&v~rt+0Flt|~ROzM2T;9y|X@t?Aj5i#m23+sWz#n!&pL(on5wO~88uro2O z_w=xr{z&iX-|^C)>plG{FTK>-_j*bh>Y!uk=|c-j=n^Dy9?z7%o_L>Jc6s1h2G7jLZ%jt1dAOQ%6g2a1 zV`6|c6&i5k2UDs3@+@)&BM#c9vS4=;QCkOiSvp*c(ni#W-KoD;1xkBu!qjM6&=tVYSMA5 z{8RNmTHmg!XPNM3<0i(btLM{BOzqNPt6i=}Dw~Acw$(&fJgwiTCO2ZuteJ)VvHP*9 zlH{?eEOTti7#=WD&0ob8^BZa=f@ynPs?0quMGCH>#zH|J9h3UJ$)jUZW%igrL zNjLw9qe+ve){=Ro85fDan`qaPqxR5raxK|Zsu-xoF~T}YXmP2J9E8Co!um+)mT-M* z)~b^QBnv}1M{uvBPU)~CuhnC3E)r?RT_wXE?=N9oC5+RA=P&V5+e`RNyl(v^ zs-l4S@T=w=R4b!x{3KX8J_#jg&FJ|_yn?0B`bijjpz)J1XPlA@$Kj%a-j{l-(w2H- zk6dP#dZSj4PhaZ&*YuOXJyRCqv<2ONDL;uSjAyf-U5Cv#Fui~$KCenf_` zSImO#NtEi(uwdKSL-*FAaP03bj7Ki#xQvfgn_%pII;hk=&GbN2&EWrEY7Zg_B8-SP zjhast{8*SMAD|2W4w%)Nz!j7SfbwMnrRyhw#TiEq&h_-6y@z{1Db;((Io(I{bA2vK z@9I(7^l|$*GmPl|hmF8BD>eXR)=D2n*H7Y)t<^5*(S*TNt!*N?3hEQUGkcU4fI}{| zr6H6gfQa3b0NmiMe?EPg_PkaIJrx?Y=yU+h7+hkTU<~Y{yiWkH>`~gR%|7~y*F7_W39~@!L4!T~ zBxd#QCvk?VPc6-KK4-}1Z0*g)PvX*E{UkmFH)#=5bhpT;>9$xr=_k>g94^$8{x6R) zZlE_s(|sm-j?383+e(fko<3+=wv z&k}`cKVa-QvWS5XCBCXW=?)y=DJ9e(g{o0!*!m76W}UP?G3~X{E7m{T693q1`luIe z`hmpelhRfH*k9Z9BZ-42rK`U~!e0Fs+x1Nvd}@Excf9(ioRn_rzsjrsp_9^0{Ug2l z|Bp>i`A?wG-Zb_HHn}~~PICA4lN8>u``DMF`|XL-&>gh?0MYMaxLD_fd6L4(k?7V$ zi@Pv7q;`_=ql`Z;Ch71w4)@D&`&zX16jle^AFtzOoRc8raF%ZKiY746nd`j9VMk^^ zUD5y9Ud2)OL156!s5QKBt$gg5z2$^B!w0y_i=Xe4SwV(TIZ-neg>}aoFGT;l{Mxj} z#1|$_(XwA(;{_Ieo?oQ7VTHHwYr`5ZsIVewo9MzQ{R`&P_c{Q|Ko#Zw`oPrlCdC$3 z-#aOfNcVVTc2<}1I<#eP)2%}$?rVw;A!KcANM{>AAAXzMcaq8}dBXL#9B#UG;KUD` zq66>VrkL~}@RQ>*w+ zX)A>+xJ%a(a(l834!mIG`ld-EM&d)FaKrk_K1u0VV%sj4i{*k798;eV*v=)rbfbx| z@~?BkS?!nr{Hk*8f{{(ObS!3yn6U6!<}{Jn*FO#+aHX14|30yVclp>T`yDqy%=a}o zV3W0=zwlV{o>FJ$>Yc{#MebdA{-O|2}nsdVv9adp(Y1*9xz%S?)BRBX@2H+W*>3sy2fBBD(KrR5B4gfXhhn?Ke3z4i8bxg3tfvV!h z`)!^Xy4=S5U1#HQ^@fmwKEe6BPX{OQJCW~ZsO~oss7vh ztpD%-Nd1K;)sM(HHbSE)bI5Fk_&r^=Eg(= zGSyzLJi06KoO`CFmXG%S)b#n&T!u-gZd`Ekpm$w{i2?DvIm7Igm{&&b9gt}zQr*UL zHHg){nf2^QXzCt#Vk9tN0v&Rpd5*eSFkxB>+TSB?=9$<-S3G}&9y%a*CoOCo&_S;o zO@L^O@k}f87dB4j8iDkf+Fcrxx#L3}2Ej<`m>H!Wm-y%iG^cvWpXkuL7@L*|| zxsGZ#m$?#bu(u}eKaE0ZI&&j?3XO?V_&9S((l=xAz9(pjp})*`|No+{H6))Vqgnq1 zV_XqxPAVoD6R{?=N-<%YUG$6m2L++kS=bMq|J^PPQJqbnPY?LjMaJ9mZ%>yNN_cqp-<(*xzrm6{F6)4fWh{SSd)xd$~$20(lR?PXZ>DCz@gr%qp_E&#vUqwH%_z>uCS_qjCag~bKcU0t!^i66&$F-LqJ!y z+B(Q(j^}XO5oe=^{ze7O&8@m)=iWl1&yAJM@HJ_JvdqP8XLa@KG9Vs$qgv&b*H}%} zkZTMC)i>okl;XmeXt~bkEU13pUf)A6g%e#U^+fEYsY9kK`zKS!R_eI`0+6HT#7zwD zX6~!tazxxVhkTzz4sB6e_q6Dc7Cd-sA0B&yGVGc$aYyVIQwI(-RnegCWs2?T6eyhU z9ynIte=~K${_}Y*ZBdXK?tOZzN45!PDcc@ytl>VR=lR!yx}0{)k*-xzqa!z&4zbfP zlnzPzwAU&+ zptw&P|FT;Xjyef)bwRSpE1oz<&0S3Fp^Q8MF1Q1NtE>389|xk5C>PwX0Z76Qz;K-s z|L^zi+IX!+jI+OmsI0Nq%#{!Dr+Z}=H`+`KY?-D16FTCzO(cs-`gTi{e_VE`g$WD} z>Ff501@j^ETHSlY_^1)C2-$-x5;yt^x$ccx3=p?^=(Z0M@ordfiE(3U1gW~caiw9K z5xQH~P%-y$>5ARbQJt^HF02}I0alErTgQ4-OKEP|;#3{$ksO?yEE_83UU7?JeH~RK zu%m`ITY%k-S*C+|?^sGL9gAH&$(Bu%M+IJ8lFp0_a!M{NN9l4|Z<+^z;T!R=SPw@l zkM(TiF~fRuOtEQm_UQ)Yp6oV-Vji~%cd-7n&V#zrY@#WqTb3}3y>-Z zg)RJSd*1ZFlkf(eI74^hi2F7-2x(DiCJ&(k%%Fe^M_i=!3h6EI#72KR&W6qGsv(gpsKh`sB})J8-Po-PP&Cg9ucul9u|0e z7Ny)Xld)*$2~!FeYK|}8G6yO(1oY9SDOnsZ{upWMkbt}gx z-0&w$rZR8$$Z0Y?)`BcbufP=L|j`PJAoscPiAra#sSbIZs^e&OITfBw74JIh*P=aO4@c|CH1 zaUM3_&=j{O6_3Ytu2`3sm5z^^I-5#M=TL*W0g*Nc!gwxsqRlHHq?*#Drg-yw|Pu!IBS69=qj-Xhi+fXiVbKxB6b3Gm6$l@U$WDl zO%P`R*oQgr=7)&*`2_DX7XUvZR^=wRgBoC4vl#82=BDTXbI0-^JSU9!m-Dgieb912lh64arYP`*z=Y)CeZn9jSLr2p^)UqZ*1hB#qI9Uund@bAoQ$x>@vv+tUN?U2QV{&GRgSk1I1fR}ZrnW9jV&YyB(nhRX`mU-Yi9?6F zr5k?n=tR9?esN1PumuJ>SNW=vaM;OBIT7jxZI01Ci zk2ASzR^bFjwC$j&OE7zn>fFZl>{#@TmKu{>ES<^`Dvakbtwp&WMapRgbs&&VnB}TU zM;COiw*|M#cu~#`m+KY;*3AN@o0mw@rS7rl>U-MMsY~8e^Tfp>hQ$lEsS`#73p}Ok zM&H#-gb%Y!7Qp6OTy$v zNACUvFPv>-v8BBcU1gixxLC_|zFG$|k9sSuEoP;qJB3@88uHrH@@Tsm;1ey7BN~Ty zL9$MGw9EnlOPehMSZdJ{nL3DhGEyr1d^}#v6^Z7q+eNEan2e}tpw5I@+2XExPH5F* zh|XfQ2R2#8dDxlJiIOS8+lv2bIyPqn)+MoNtN<39$@~z#8GMy9SY4M(dpQOY|L&meR8Zt-6LWSuC zbI=7uGbehW8Xa#GSUm~V3r5B)swaE*6|+YLb`;sVCD;wsCr+$WH-*-w-7^A>qJ2Zu zvafKhvmvYn)u?Pq(pA+ktEmo(F^JyNhGMzkl6CI#)~tD#8*ad2lNB4$`Dl^ooXs_& zr<4wCBdXb`@e2%JgQ5WTHX~e?y28bvjr#|ND9_{(fo;pgyeM306>(yTiUqm!JJ_IwyDNo zgTOVk#*i}PGt_x*E@d3eeWgK-qcJ9kLWqohmrEf6zz&{D+Z;W~1c5-d#|;)G7%aK$ zmkkIJpqth)R>=&zf}-(1{01B4iE2|1oEU5t2kvj-zN-^$L6hU>%CVr@n{ytH?T#|x=VV2KNR1a+a8}hqzu7@q2W>(cw zVMNO((92tfUNkdsVfbBIe~y_->?PD>SJWf3$HH>L7I!QsX9PBiSv9IuH&Vf4*$No1 zG#`wlX=1YAeBKBqi^uI`!D*$t=3rRqF!E9_bHQw z5tN4ZkRV&Y0#-GUZO+SMJWE-%LE|9IXtHOIYI|Kq?N@-7YqH7BCVPP838=+XT|Nix zOLnt8$Pk9|(IPR&y0L-d(jKNQp%UyPXbQ-sK;qjVX&+&NEFTc$}2+;K4?imKE*-}!6m)%Z$dF^EulVPld9k^0FP{`Hmsl|z zOnF1tV`0NdBgVfZD2g=um5!LhG2R*D;l~+RR!ZS>AWF$-AsVyFSS+0D57G1jSsXjTsZYb^E5We@_$&v@%xPI)M z7o~cyML;jIa(IuG)*Ir7e`#g8sua^LF{J6r@@789o0a2}g4I)$(o|)2@=vN(7wI?h zy!kBH(39hy{6?M^sYc}Z6g`pS*~+(|dig9{&Mur5R4-V8e1UXXtZZdi&|cBrv_ZxE zz7K`&))5omq4y~Eo-T<>HbVP2BQOm~-HVk$ax~nmip@McLbO5mCHsXMh(kkwzQ;bz zT_cGuTwn-`5u3vaUCjuVH^r~FjvdJsjzl)#q$&B5BaQq+2{J^&%)!m*uCn%N8lc4E z_9aY^MhVeGvce2W8*wFi$Z^9#%Via|G8bIBR0xciOZ%G1W{Y@+E)5Jwo+l`Xh`w#}7RIY9pn4h3{@eCC2_60v` z*N1}TIgB)7i}=MAp-(u1vx(C=hyC^MDjG3SLac!R*X^h>wP6ajp7@QN%*DPnC}<=| zD&ny@7t_c=ofk<&i{M64wNQFw1CINnhbSKP$AQA#PUI?LR3GDj_IKGlzbbNOzS%J- z8Hg0Y4Bh{RxMbAL>GHUufe&fm5pwv#2)t;8vGHxBZ+oh&-NinZn)bGCA{ zS`HO0oD6NHkqp2eTqyeME-~2_7ihKxGBeDBK_4bXj(ga;wyl> z8Le=(Hi~CIJmMRwb!Q8gq$zEFb?u6@47ZYDw5rB+?gg2n-^6e34LXJO)Z7y@2oA%Z z+EhB*{$}DjjG8x_?N|OoWw~YK+jJsE%uvin z*J4oHB>>sPfg3Jqj_q_w1-38bY8!B`;bRlSMjD8n+Xit}b>gcze>@Nu61F8%_U|`<;a1J;otXfewm$H5 z1Peh`;N2DAfEA20b;P`EVTKqN1yx)yTm@}gRZ952NogVBHq^3~p`N%-2-dEUksUPk zur2>XH@WH70U)nip3(u@Um@c)RMxa>(0F3ngT~ko*=KRFNShXc@0u^#VlxPQ*J2SA zv(h*FJT1W~j5H>Ai<)C6ngG|1KDcNE7j}J!fY`W-mKWUovdQnxnMRJz>`<8sk z!*j)}={-bL-c5UB^R9h0_5^YAg+SVBdsn|C2GI8BRVkA3@+s=@6F0S3+|8RhjO3WrnZ8(k{tgXx7TcokV*{TA|VJd|*-XpX^+v44Iie76XXmGRW zy3F|CN73DmRS&taKg0P+0pZ9BToEiLbWzT8;CHfwr)p~lpI0!jO$9o*V1x-Ahlr6rl=9WRTFnJie}f4fWQ(hRSyqoR=W24K;{X3qXJ6QZ?F<7au~&71 zn<7djkB(JOs1S(rrHalg=-=3nAIGXkZ8!bWN~qh!Yw!kYK@|LzL~Uvgw$iV2M;dO0 zZ-ZcqTZ>U46EWGzyjwjXtj2_6@!xh=HiKGWmGtFHU@VJWOB5mxM12##+K_wIGnT}1 zrVbe)&|5hb%}kqPCWC4-5sUn|FYXZ`p>^ue&Qr+Nf!#(~9zlYp@0zdY*TX|UubLin zleCw)OI$1gyk0VO$j4M6iL^HM$eed+f2Ag(*keYtT4Bnzb1P-Ao`Y>sh2a6qYK8|9 z>r$X^843KZc!kHrTd`x9O^>;t6Zx4Nb3ruT@Zg>A@Ntrg*cg3Ftl6%v?39_b7d|wq zkzpWo8q0-+(um-*bS`8bGW-Oa3Atjxw0W=4#D%u=UZKP@Raib$IZby49|mC^Rdxr% zlc|#n16%FHXYmC)6$xP2>F!Jh8ZP<=J(FzZNle2f5`Rga7_wLyKLb12AxSSf;&O_n zu~QGp_*dqwJH%Ux<gtztC^k`S*Hu5W@)Z`7QyisvckB;`=`3 zd_Wv95$Yr{9HD&9%Hkk6ulG%;$DnFBk^xy8Iqj#wotw0Q*Ux4 zBIX^~C~qyqXqIR(n>R5}bTacsJ#kGvC(uUyfi2CJF*(j5grh%u3l-GuLpX-WBKxc4 z;z_Fs7EZ8?w{&q=C3nohC}!qAmOX|CjY<%m&RoYb>dicAVj@hm;r$|B*2*SYQh6-) z#+*II*+eTU5NV77nx0=Tfh~1;P9y8lpjpxO2*`k^g}WkcKATWe+&`3Du4*;vYk2Zh z5P*02`JEXV*FI%Hq{hd4H~1!XY(A*a_U5Pz z`tSTzV;epJ6~`7H4RtJjKOL&fjsfkV^>VX+FNZcLGr^AEJz0GK)ebm~7LenA4?Qnj zZ=tjh_68Wk_7TnZ1PsS>My%~)16cgz0|0#hX5v@%Hd^hFqt#fC53;l2@j(%zy8v+f z-yTM69nUcdF7!Dz^>~h3iaX<=gUFZ^87v0dsbSXe7$P`dy;<*@)V}$EqMDgu#`A+= z9%_4YB-Fn6y>7$Y4(@v!=9f4q)hq7Xf2Wl$W6g=(%GxE7tj|Z=azgLeQKqN0OU&V& zxqh9Wn=R5;_i9%ZH^(+k?H>dV-=wvh2yJu#z=cP;VtGnJRs?o#6dKd5(bN2T}rTSNiK=*^2V->&z$|7)Vz7` z;XSbx&kR~0$kzj zRk?hYRJh}V%(J5S6JPKh9R&ibOGq{AcV}^v+>dT7y`l7`(wj^FzVw?n`y;ng)hhTp?*&2VEh#GX~?(A zQMt$rYEF0R7iLrIM>WOH2B=JVZF*WPw4dtp;-+PKgtp&!bLma#9a!>*jEpR*i#Gs8 zX{agKIFA!k?}awR?=hX8H_-{#FA{dg`ti+}Kg&aUvd`0pd?ZNJ1f$P)i1x?)PTNZtqKdwOmj zG1(*6{Y%~Pv*!~3e&CTkh{vb5INuulL&9o(t!r2EzIi7+J)Gao@D*& zsM+@b{)D#vUznHvwO^*f6#|&LMV~f*e_z8rCIf(R35zXK%8P>*!JiI;Hkh|$ezuUw zMt+HTx=_27n!oEporVOjzYme$_rP+S+1F5GiubSm7fLZl5|1RdsbiVkU(De@QxAUIE za~97*Jm>MG)H8LUpVzaU;8+x7fcT_u>l$$!UnL+MO8Qn5mjatH?#F`C?YPeEF4X9?0DPd%3u+i6WDZN6aNA-*JSt_9J%=3{Nc6t%(!Je zpl13Sbea3;Bfq00MR&xT{)gr`U$By#`kntkXICIh5r3%B2?z2o2!xK8aYJr&Z=Mt4 zaG&FQa;+1Y;wUc2eGoLLClb5g_v8kDXoC|enZhxtd!~-w;x~k~BYvA(KS%Sa|BY^- z#^-t+`3cZ?aQdFyGV#lisO#4Gq}t?4>{gueYxFvIjf6ton1E zDg9fwJL{wa?eNOSk5K@zdIK@%P=x*lTGU`(LWNd%?GP=0NDc97a;8{6sSg{=)MfaRl)!FSCdC$dH*w9sZ~JG+S9Q?Huc#OKslw?qNuCARY3Em8gP z5*vFau1HH<)-!QQT4G&~#L2T%=UGnV`_t1~n>@w)T+;1xk@q>T+vgm89_W602Qunv zzAhS~PUKPHxgGG!J# zt1#z#5@i!YIH6POznBKzvuwtQy8R z!TmShOi)o2Z{YJIQ?s4OD7O1E;%g`xY^+@$--hK3<@jG&!LWpATWPr}qh3Gh<_12- z|3iu4A%8{kW~*?u&>Sbk9J4B@W+!^AU!eHd-Cy;0ZE`kfszI_|nO*aDoQCBlj7_7DIEBql zN04I{}6EOz}MRA|v$vbN}2&BJ71S(<-G@eXC_4g@F zqZ{AI2+*QGw4QbfT$Q-yZ@Azw`^v~*Om3R_;)faYis1g*Q5C^=eZgOt(%_S>ACOwW z;o(C}+puH5K;|Jp%1L~H&9QNbSTm zB{b@f9ys;N$c46jJ`%6%RDyJ!8lOWWh79QgwC-#85ye0n!}#mE&MroEzhE|%IFY+2 zI!uH)PW^k0@ykrfm?<<*Z3Xw&_?$4wAfILCofHp*?#$2i7w<5|1HMTg;|1kJcb^9B z$3G#RNGYcL2sIkqU+VkuI;S2)XNao?tg8ri`5N98iG*IbGBV~21@bu9=&kocudm7h zG^c)V-3QLELFc3gaafqNOmELR8zwayt}i}Z`&xNJi!aC|mElKODADJdF9pzbP>c`y zndv1){o&u5BqzG7U%XMUBLi~KTmu^5viwXeg43sc)OY22Xoq=2A(UvM&|5_7wgKk`OMYPb(0U>K3jF;RRuo85t&^l;ZR4+B zP>@jrm6eb4k1Q|p_bV@{2myQO=5bD>BIkGFg+SpRf2g9!pSjJ+jQK-%l?bU%E$HmJ zk&PW!(0le0Dk^Dv1xB4rx;wu*!6Tf%g!rtWael}6>Ti*qC^y?F<_e~miCU?JuZM#^ z@P}d*g(tYwFi@CKG^G0fsqrG#(S4Ut6H@QX$*E+KQ@qiLOUHNlMt|rPfAL3mpL0#5 zW>iK}x-Rk;uMhaHXqO;<1IV1N7m2}8z&yGBvj=oz7yLK#(&Y;_sWmN8v^sm) z$&3dwxh_T$-Y-I8AQz!Mcc1A*k51??I|fW0nNHUWwWIxJy6K)Rje@ZUru{PIGuI&` z@BhB!=Z?0nncU46i@1*Y2xFJ<%#Oe%ZbB zCzD%_Vg^N73)H{%`ig$*=~H~eNP+b24q_n!FlueQC^d>v=Lj{Bo~`XzLCqN}fH z?Ri|7JR8ip*y7XC_$2U@xKJ5W*kb;-xIWVM7Wn+->)`WBLFcg)T0}Ei#M(gQ!k7js z@dTnTy}Z$P2?p=Y`DV&rykVB6O4_m!kskGYRig7C8Z_+ao--|Gn{>bn1 zn<;^5AR7~^1pZc_mGJvtZgPQ5&Naz-@s)1!Vv;M6_5~Cz$n=L7RBCd$Fa@C#Mu7}} z!HKL$mtptMGyH&}T>B2&=|g|n3J@F0E7e7wv-HGH15@5S-Ty$)&b+HNht4eB5G>-^ z)#cw1^j1Z@Doua9YI@XPdP%K z>WlvDH2iC_NnfGcdHSku&tFuYL$@3G3H(}CQPIQZv2q!Y((t3Q0V$(R-4N7g{V_aB z(w};AX8iMWFAT@4g$zsX(gtaY%}n*L@BDOqEXL8e~bc7C9_;q6hjpUF&h#&+*-VE7@Wvs{0Q| zvT^L8YRD>71SfRJA!4o*-PzyC+?+PT<)%4HTRR9zX!JMxv)TMK z8lP-e>6i2Rg8yMUHDi0q=9QQZ={WUmb$;Z0@B{Yy68R`sX~1j!7s)!TD>)1{HI7Ul ziERiePao{oOzkzYtfiV*w}gvdC4DsV@pj;oqOBhuS`wIv(wk%y5`T*j9o?AV_TR4f zd0-yx!V^qaXeBBSf6qx$#yj zq2j+`3{uj-)fcfrvrBg3TBIw&ZIO|A1y=s|PM<%yM-}hzybOyee<=t~+ z6Q|SdJY~>o4RJ@e8~No}aYsE8cTU)dJ1gzTW`rFzE+b8UJ!RcRcNLVbxWP3Otj+0yq!VcMfe z?j8ri)dfb+)2J~{Y(vNAiqPv<8|2hXOT)m-C4tZ$C%We}e?N=C@B(-CX%Gd47r3*} z9Q#YM(bup_ymK30{9R2I#fAWCpJl=j!s7vbcd=qtf#dB5QBeFMz1OeS1d~zoh3<1q zeAg^?gu|;fo5ZgZ!0zPU+x)<;NVoa@my|^ZVzFNPP9Xf90@24>kmH1(dqOf|!{h?B zDX}ydW915ci;U4C6n$3t?s&+XQYbQoWM-67Rce1Z8|uCJM0MmicRc0gkH0D0g`blU zQ5wdEr}Fe(*co4AlQboHN!f1FFKm(~3?*IQtye95^z7gIYT9u72mJF)DPxI!PDo9+ zS=NgaG!;Mz7f_Dp;>Em7F*R`TJr z#0PsMPM)WJ$cB4+dYQ?{Kl|B9|7_*RL=09XDHZ|?iDK}WoX)6!FRO+@zTs>Yp&Ls&s|TQ{QOw zG`o3#VteYf-F;<@$llMhFaHwI?$~^Ohyo-n1FZTHI@r5G_`Ovicjp0Lo>g6pV zFZGZ8CLfx1KRf~~gH*pRK|(RTZL z=x7R?Q99_hw=@p{Vn(Ode4!sfUVw7way@}Q!{lIOKX%Kk&hg5;Ay|~BL}G~XE8rnHIM#IxcVwx*o#*Y=Ys&XTMz4={sukh+h;EvC}5`ZHs z&1f*i#c#2{%@{?hO3$a50i@geq;=~v{r zYy?F76#L0^Ch}Z?J{|N6g4#M)Q;6@dznAe_f;hg3-!d&+dPgV6g1=WSPyDAOkMx5z zjBb5p?H7J3mv2t^p&TAFLq;xZMQIncNTsJ9v=ZvMhk0Vh^4+(Toc`jN@4m}avUr=X zVJTock*kx7+)YmOAd6hWvTKoh?O??_ zW_|m${BQ4{hKYu7##{*OL<4Q@h#E>HLA#WoO{qdSX-R`T9 zufIRRxJ3n1QWaFDUZvv^31Dcz5wq4K|`?#_(@z1bf+GFGjp(gHGb*reRdU+kKssFsMTw>meZyP{ERQS*7x^6B0_afYf#Lty*uYPoyDaB~xLN?(A1{QH%{rC!7mzBC<_Z-%uN8Kij{0D-^ zXW48f{#_qU(T7Hpt9oU#+Y}9~F5w;6?WaXSo8{y_D80{$m$ur9?b$jzNRMaOirY<+ z75_lGbh`a*&&>k4()+AOgEiEehH!Cqu0CJ}X|DXDfEkRT{KD zUS}&VGD&vQ=?!9~_gV4s5?is20Az>4UA@I@A9d%#OStBi%6sL)qQ966Iq|v7kfl9a>vg~#-4!OuDn7k* z!?0){V}gcRIK;5`>PAzG*n9Kvv9F$E+1m!TM1m+a#f4@tXlkV(P?NLl(=cuyO~E9s zCRcSgE|j`S#qG8NqlBsA>Gt3vq*D;Ji~=l?2Pm}6l5Yj9z+8O}e-g~LB$a8BaFGx?e}7cRfCZ!XNE9Vp8z6By+s zmcUM;2Yv4oZM||~o<-XVTcMc<#S%R!Sm}LM-0RGjV=HcUD{i#UlOR@l9~Cou|MS^) z_HH$$?d(13!yI?^Zg=ZeYKjZJ+1p#Id9(L&W$&XYWS?cR?sMUi|12(?{-4E#8Fnb9 zxa?hGpC^sF()%2WUgttr(#>)!o^GEf(TURgthmQqSYlxPYj9!XXXC=36W;t}F1(+w zXrdvwrFB5(PF0WQSadBhpOR~JxAQi%E=*%%2fOo0pM%gV7q;34R=5o;v(J-8 zSLuCL+$$Ga`ShQlf7&7MIrE(a@u%<{v-ds3PGhWBTHdp>_lOE2_DMN+qoZ3D6!y-s zB)4+99h}ESK8(7Fiq6x7Me1{KdYucW{AY3D3R|(b49J3iJuX~kEBdP$cXdOp81St*LY)Ij`!sfIsS)*1AhrG;4nYM|}6 zYLhWFOL`RJQHtTyJ}D)#%v4-$!=+kf`_Vc(?mhT3GTmfNDv&1XO`jD%-e@bf5hHEI zCfYBMHrtB4_2J`g#Wrds3Z>Hftax>+tvDiPb4AwD=@w%9DY-uMRA2WF1RK1q&x#+l zd}$+&xfL&Wna1TtZ++-Zy2;5_>3vqbGS6^E_39$?G)Rn;sE^^G{ghlE_C%h!q@mA> zms(b@gz~D^gb(IKHWm>MrN^OS7a-m3O=zwwPf>hJjUzhlI`VG7XwN&b$mTWch1j`6cF2U@K7*%|Vc; zESQ_)P8UwZYmGa0vtEolw)=)Vw)=)Vw)>Woe9O~YePfBk8U6a!Mkm^KDu)^aceKgH zO}-ot{){I4p-<%2a3h0@@2)w`;BZXmXV-vN?9sUu;S2L+L~bBzE5Qf0l$yiy6_Ia} zox=-lgN%LL-?g?vcf;<+PFoRb4urP&qw!PgcTKFgqfyN@txX(#z9KX3=PLH2&Hgh= zIDfIRmeZ?~GV%7$;yxpPI43adP5GjQIB-MRof92f)``sKs_jEZpXUrm7B0_Dc$|}o z7+?3|tS~MHW!7Incfcn7V{r@U z-7ywV4-U#aA+x;k*I`2rL--X1PWTyZu{hxeOZeiClq>8(Ki~ad>MxANe6WS>M z0Z?~}c0=CsM_c>*GdId#C_F9@p2As}#ylrHB_0Sn9gNVz)6qLlYg%_`_yD#jj}1SC z|ILZwT?+~cB>!$2!=~dA#9~;;;W?qVN7;G-ZoV@C7IF zgA)di3$FOLA+Ivu(@)7;VD$5jb!uYAsl4Gx?bq0!FgqpTrv%aH=L6w-K^V^ZX=$h| z!bnZZep+-zuN2DDqAtrK^m9Vd+3e!l`oW08;(%F4egGW9OPtY@8V^oRK( z!SLXGf7c5Y9M+pcrZs%ZDE))}4-DJV+g#hU>(J4zK<4&97;1B%ll6v9UNLmCfr6et zw5C*BLoZWmXL=1th|Pfk&pW|mHEHv!KiFZmd%c(cS&( z#vz_C@DaG=f^Jl68e1iU;3uc0?4K}`dk8*{;KqO(d56BJ||52v*`1^ zNB=bXydOaA`Gn6#pGO$M|EABsgg(oD-ZyS z`Op3|`g{*S{}lSXj*RDg7(c=fMeoDSe(m3;r|a_g~@| z`lrnAmw)X~qtBwAz0v0iu=H1zpVy54OX>6Gul`x|c`5-6 z{uKKBC4gG_snyf9b&Ikwp2*S_o+vBAfcR@o0wk zRrCu^crt580?6U@Y7Khv8$?2M>ps)HUPmEq0hR1;YpTCi=LD)x5x}X*PJ!RU!qmT0r(oLDuSR?5)b5dF9^zXe`L&H zb2M7#ll_sK^8fEeLCFWnHVTTbL0oV%ESK5nWdr2 z&El7MDLw4djL)pLU#09p)Ecj(uC`_Y{0mZ_NQhICR4N202NL z986;5tI&fma=ykqd^s4o?sl`)=MP^kjGSp$`CU4fj*;!!5g9;?u(PoOYp+d`0E#1R9putt^*a< z5hn@ALw|2kvC2b*6FHBAF6d~YpNs`h)D0)@ovM0i$>pMBl8fqW5-5(j;Q2*7gn$M?+ z3*x0TI?1HkL!pbE`e>F@e5`hT1y!9L2yyuik#XW#-~fwrR(>EfLnh|(>_jW(4>oMy zksT&^23qrp8BMmwFwrU23`gV{(D0=?4UGMWLnMTQVMmP^QE8Igv#&%hGoi%%M56;{QO;khjK41wKQ~Z9hwOCoP^DadM3KOl?&f zTKP8f)J1F)a3O{bm($GFjD%(J9up=I;@||T<124wry!F}y2HL7MFWL)%_W!}`5Hg?y`&hp)Vl%E9q%0VjpB7YghozRc-pU~5E zme?vf@8)ZG>2y9t>@O$cW{LdP6oD2L$f**IuC!}fZbM_hSI$0!!nZk2cp9N>&94~+ z1Ucf;lZ&0=HP?kT%IENfxlnZ^9 zuw7M>2Ut3RRiG!^L*LHu1x;K>N@^I=4jyF*cGbb@BMqu2{!72Pj(K*vLnrI_%sXAM z!IKrkZ+f;Z#^gf41chOo1mA5_P{NYDXC;W30 zj2S?4^iAsx8mT09=Fju%^dVH4=R}4MdeFQU#9#d~`Rln#Fea*~f)4t^ zVG}f_5p#9CA3q6iwZRZeVjEsLfymQ>M9R$Z(H4SbrnR7fAUu!rcyZXn{)EOHW&PKS zST#VCnTgrPvj?q7^J^|OJjiKg?Z>VH9wI{&u`gc4@x!0z7cs6C#MBulA^<5;&a?(O z2P}=V(^q70kdGPhSqvH8R~_W^ccGzeC@;}>CmeZLg~LmimfMJF-f>*O_vHVmQ)S`%ME*|rcOac<`rhKx zuj+SMM_KqZC-Tj#t0RF2vI4~~`WiNp%J%SW`7`}mnM}>kbHhjm@(aXoMNa5#?nMBU z(onkWlztMv8FGGFL&C)(XR-&yxP<>v0&eDsPzuVpU^w&<)mDl^i`WRGJL)l;P3_LGGfxu( zy$({_2q9T!5JS#xIh-!WL~Nh|RxRTcBQE$qMG2v;B8EQjU3Ve+jEiKRc@*a$WI1%G z-bqA5H-=saa1_6Lq+!&Cm;0-gB$d#CPbZM$gV+}5Vyuo>#=xd-PpmQri`~2V+0h@D5_{uD9 zKpA*B>LTC;@^gF-7?O>Y9q(|uHlf0^f#-yXa6c#`bN^fiF?iq zgf>=$HsS-5#hj5-mIF2}%2F`g^=2#s?>Z1RWN0-=|el(D%d+8HO;Gc&xz9j#yi zH4Kzpc7OPD^~bwvKi}pg=XdG5sic~VN{hE~9@((Uh50xrhTc}7T&iPaG~VWTN=0Z- z;$`Hg{158IoMoX){n7XPsUs!&Z#upOVp4o0#H7e8I0V7f^^kZ}oi6bgL*aLy$pEvt z&xkb72?=d^CVXBXazkcCahvbHe^&NTb4BKUv!nn|1lEJ_0`wciiH+s3=2~E)I36MI zyIEk|Z>-`_7L<XkdU%TyEqA}Mz|>=Y`4Qs|aB41y9F6)K{tpzU zVa+w-Bfzl0*+*)=Y7}S|27(QkID0LrmKR?^4eE74eA@+XT}7sgl013pqT($=ufz+4 zpkAYTsPy`Q4-DRJ5LeOj~AZ5dH_#kldCSPckfBB*BN zGaPp|b6L|MglJ+rQ=lS#=O*Ovs~S-14#v-*tC|Q`9Cbf>5{<;sE%ALClTbWBcDg{^ z)uy(4)7TAqT51_|%-b3csZSR2!EoOxH5GnDq6p4T1Wamr5C0(F65E(dnWjs-ew;5V zqd|4QVuV)d!THYW29LxFI2L%g05u)|miDx_AAFil0p=U4W3LC58$g{1( z?_TaR#VLGK37Yww(3Cu<@C`*AiR#pZbSPJ!GfJNHr^N6hcC0J$^vwYm@xzQnVhp21 ziJIQEuA)ScQlY=4vn7c$@E1Ybe(_8Ag?y#Jgm+t`_kSLd^bs-oRt@A?g9c=8Q@R&) z$Xnz?QFF)KwhvOG)%RKA2l)x`zIb1r;lkCqLUd?p0gph)gsdPMZF%UWG}T@4gz6R! zL*==^7nJ%+{u~vH{EIwNmI#&(z^?B&qviv%CGhkaQji{y?@2}YpXBGDmG(TQIF<8v zZ7h4xoGU4P4j@=Ztc7MOhONajwC#M!pLtxo+<3T?z*hJn1jgT%nd57?|5O^5XUSTB z@fHT77iUm8f_^~w`atGJ=ZoWNpFu&f$5#Mw?)eN_{pvj0?^i`xvR5AUFK`}sacK$ z&G$&fGAClvM7p6!hRvL99>KVnHMCv}lZwcb%~UG2{Wq4-<6{6>dUSyLO6%5aBsqio z*GR?BLmqKJ`2-JYE(^O3YyP9ptWZkvPoLEz^i$;{n)m}M9siGf1|bp@vP9cQ2o`A0(QrC9@G`;W=IHy^yoZ&Pu*S?2tPHQLaYO1Z}DfY_iwn|YD^n0&!f`_ zIj$YJ2jOxQQ!GoJcHGDU#RvSpNgv5^{yVUX2JQn@5)K-Yjtsrw`-ol|c0#$dS(z;l z((r1HeEjs`EM&|l;hL$sWZz zG8n?8E{QZ@VhR9j)tZI{1}P}SRD|b(yGMmPfBhe%g25@{AfM!j485U_UuIZK(ueh_ zywtEZ{7NKZ$-^J{*8-K7b;Vp+7q5a4McVfh1IizMCYMzI_-E`Aak)|cZ1fy=h3F5N zED|&ahaqBdmrJw9`6CNi#vh26QK_b>n;?U-(0hibp{eZxged<_yB;~(SX%$?L}Pa| zXM+^j*yuZ29kgHV`*nW7-G@+r%ybpDCBqMCJ_v;K+eaVq`_`b~uz3-(XWxBK)-w`J z>{D}2j|b^}IMS%rWDty)Lo+ae<&_;6)CrA`wpjh$O5Yk*Fl)j^v>FJTsAb^995gJw zu4|>F!q-^<2=MqCR>TaW7y~m-9uzDQ;tyrztE$T@0~XBKv5yT%#x|w62sRFa!Fl}G zubUak5`fDe;fK^`H&QiIo8h-WXjUG++UJzyGUsi>lwprh;g#Qh<*=*^62F(TCGy#0 zv7>WgvF8sG>{~20OSF)9xTiy==te@qMDFi*zu|PZJ=)D<{E$=l>CVx>`opL8%Hj`# zcG0Vmj~enM4EF#-8Z9QO;h;3_1O7~rU;O`T?`y!LsILBJlU;};hNy_BXqSo_EvB0g zASjkVvXDRsD<2vW-7Lw5M6$`c*@R$uZ4^W(MC1FaU|(wEM_bz38mn!oVvQ9PE7e%7 zFIue8YX3p8jY^ePlKKD6{n*UR&TckK(CCwSp4~HZ=H7F^&OP^>d+(h47RV6ajfCKb z5GB4NuH5Wra|4B&1cr6ZuJvET)BqbQEC*l3NsJ-=8ZnyBx(EHaYXazrtgznH*C!7C z1YwbhL24$aCH2*G%8er2CrKp>(0+F$mVE)1?%&7f%7Ugh54u$zG za;qS#%AW2ko^y`=%`b>?p1HXa5vgA@2FFD5r*F}8@&z5thRcQ{-hZ4;^CeGpevP?2 z?}Z=Qf~sC3OyRVlF=zW!7Xsr8lD82UQwv0g&UtXbF5Lar#}~G*ITf$hbz0cRCch`t z@5!G{f%?Mejh7;Cgn0owMDMmeu?`vi_cv{O2!3|uiN69Iy>13fojo6?J=IlwHaT|s zc3N>`Vew*#fi-`VrMTvocwPRT=e3mgI5Ge5XX^e$L+d!OHu$df^h0Y=^+H?whM-p>GyyV$ggiU#n zCC-fnoASmLZvGvUJeywVdIT!(K`%+RP2KDM4%X@_IH8*uY44toOP)LU3pOG51TP?~ zmaZF5r~bz75B?Jo$t*5i00qB<%UtHbrfAchJMpe)Gw&H(5IaXd`A60QOz>|O!t(n> zeAbf7g_w2;4XvvX6EkEYm2#QO;uLLWp^-dEVAK*Ng3dyDC?P`v+t-(FB#YrWc5L2f zMHlR+C#+a)ayD@h&Od>vm^FRRf8j8pTd8-4YO${d1#1^=N&^GuCLMeZ3Bf6s?W!j1 zKyQb94euDf0Pz^_7-57CzKu9te?AkIMJ_537RQxmFtCV&`5fc}aL>{g<1(&J%&G$O}C+WzYk$}GF7~F`F(~zw&`(tY*6=i_-hYxI{ zvp_)IZKJfN+ zj0pC}QuKkY_7rA#yoP#&8S*C%p66gU0JlFL!(DXyqmkGZ_D6Tx(6B#_Ajd=6{#c!g z3j30+e;~_)Yk&MQ8I|zWvp-g$Q-#|f%T{3UFtN$VN@Nf{qYT`BFDx4 z`1BfdvCqZ+*obB~w?FET2MsSqw?EzjnV9X5^&_I$ANQa?cTE7j*zJ$|5jukXQ6Mt* z6|g^^fI-OCKM2zL2cX9OD7GDg{b4EVQ?mwQf1IA!pZ&4bYGQw!ww#JGK>OnZu#L|C z*as`UU;AS ze@>wF4^$wne^~hX2M6;x$OjPXAGnKde;h$~Ve21&Lt^~{IUdsX$EV2Pm(2cn6j>fz z`y)&3`6}8U@1t1Z_Q&f>F?g8UAKyLN^ZBoTTmcCYv;DELr)LQ7zj}QcNxLxnWAbNx z)f(OYc&)c5PWz)4O&4kX14O?-`@@FP55D~|lco%gas6Y}Z;q4wv3e1@*ymz@B%#^O z?T?Qy)A3?-`@;h=G20*3|MW!Je|2^Vt$(1+W4AxfLFy6gkG&v78T$&@AD5C*O6wm4 zY5fCGV}HDGq$mFUS2teXr)CYr{gyO0?2o1B16}PO z_mKVZ8tReOKR9@vgWUjP{R4N=?TiN79Ew+5T8oOwumQ{&?gc zebpM>{31}Z+|=qqv}}gkIg?nPWH#APIR%)#s1ic zW;eG#>W~KwFGjaN-U6AJ?T_^zM6*BcL4WR=0D7_8ANM141pA{vWb7+oe>?$$kgb0Z zr1cL#jr~!4=ost|%e+1{YasT=>F@Pte{6l<#Qr!fkBTxt`{M(!jn4kq2P?f_`(rh# zWl-&pyM8j{?T<&G5f9A%xbgo{e>?v6N8!JFhM@g%6^7ji_J=RGuVX~8KmL3W_D3!% zkk&uC7+A!?d=Byf#QF#BqT3%w&|TR22cVh#K~5A3$Teqk3i`QR+r=fF6l}0Y9T+$^Ko{q^SRSAi$ zJyBdz)heTJevRduSA)hSRXg+BMD9y&+)edr;*yF!iG^@aqm==zVJ>} zcPYC~@0#)sWc=ERDA@Y*@u3nmh)eICsvWVq{)!$zD!`j8yL#_bKNLlvfZUgw&O24z zyO3AU<6|uTMRz{@iZG2H9y46>v+lm{xutiiw1dynN8Nqisg{czRI$_|d8cyWYqc&5 zQiOM^TFb!-_Awm%9?;j}*Z;kTyi?gpndsL$)eb6*xp%5R{f((FN6-RFgh`yDYlpuz`>S_f2!K^~~=kVw)4RVO@9!8srIKsBy@2YDvJm-9$b z<9-T!tn)18T>sAKo8JQuy?>_657I9&gd+b_xzYm?adIy6KlMw*i|&6)c^dC zrx-_&|EZ5UxkB1(qehSJe@f2+{zF#%^lR9jL zKdGlR{-g?kpxUH@lRqiDi9e}N3Xmo8CpB*LEwhNVhm=1lJ9%J&xP8;qpVWnK@^;*V zkF3M|NmY?Qsa)nKk2{n)W`9!o(?62_q~PGR{vq@&aE zhJUC&|4~N0$Z_y*cuzx3sq{Lv7BzKn`KKYTQa18u@c-Um8ovJkl>YgDVfW>@ms&mP zN!+WHOL&z!5Bx_O{XL+@HF`NdQ5>WHSJDfI^=;@?!UgOQ*0(PLCk&##otQ;@T$0|k zXMarkb`7{LPJKJ^b)CNb%4Cui+#Bpb^zB1nf674&`u6Rwnd;l4Kw&WS?G>mpjh-bH zwPAf5BjA@)-)@2DVcCrR>)SW|c@XsN1>cHM-_HKO{`GA?IP#0pw>Q9U|FY`akG(vs zZ|nWHem?s4pHT0|rf+wH0@t_4qA$j-Z|}btW6xmvZ#@Qmd;41h*S8B^;T#)T-#!l^ zzIc7RowU#)u5YKHro!~?)qi3-w(=76?Z3Rp?hkiF)3<-k>if;E48UQ18)o2uj$9bR z`t}oGfkD)_|K~iRZ!i60O!{^&xGqk8`+r{0>D%S$@#))ZMGj)nwMB1y&s#t-2@6;-~Q2a1JSoDzd3aD?MYX1?(G zZ5OPdp{{RlM@@z4+asT4I(Ew*=-aDyv-|b9k37FU2mD9#+rI;~VSW26q;D^HW>EF* zbIug{_PbBTq;KB}u8ULOKIdtjzI}LneEN2Z$UzMH_QSt7)weH12O120`zBP`@ci~y zX+KHZlLOJW@B7^#=-a;YW7M~owD+%Xw}2zR7=8Oku-m_^`u6L)hV|_)Lf`%f^?q#n zcG?ppfoVUwD-9pdxblTcG( z`u5hxnT~CL4EpwGJK6mh+(*{8UuE_EW>+y_xV~M`JX@7}N^trMwsEgJgd=zl;c%Xw zqD?rP9p{2tb{A}ViS|k*t$WK-_|j3@$~BI5bfy(e|NH3XKeH_;pS(Y=K>g!_=CvPS zl4j)mP5J*)il)E&U*E(w&_X)3v3Zh$6Hu%OU_*eQ?MUI~nd-~y+v}gx1Yi47!8)u! zW9M)y?b2y>VwdG^mK)>&yDyU{_33-Qlkt8YohP$-L?Mn)##|51x*JIckv-Kllg_<< z=}6J^a_kdr{vONP?uE_4cWKAMM3KF3v4qPIu{=S!C%((goAIM&CS(Ha<7!UzC9Uv*$=bb0rFL8dBeL z3FkAz}H85NQ!!3 zFkAz}H85NQ!!>aHYM|{5Rqezt?Mzi|#jgPO^vlJ)A3v9PmUs!9G^&r@@L&|Xzj;SKOWbye4UmEzi<-D5BJ*3^0J zOBb_{2vhEDoS-bNSyfZJy2f5t=Bf4s?5lvDpsZe@EUXVwLO!prHn3)b{!y9ZLHgzP zU@hgL+}_|V3)TkejObvcm#1Ryr*5%}%a5NTes=5*vtzquCw5LsTqM|vJ@9t5N6p30 zk6#CVEpVwrKRelL6!tJtg~MpO7`R}x-Q7)nP= zm*P`;Bk?o4Mre?5hoHc%0K3Ynyp`qtYgYtuoDf}+($8gY6~!)Knt;a&s62G_acP}5 zQ01vcPXIrHY3qVuTc7EB;@L{@G`f#AD5J;wmZ!S9w#*asimqX=s12ZRRRp}=i>j;Y zf(W_DTjTLn)vUBv`TVtYbyX{>y_4)jc$IgJy{gXcsit0o+ZsE%E%Hg78Thi=K%m|q zM91==msfkrRw1m&4J(gnxH8t`E2_}LtE*WuHMQkls`_YjeV$;Ts?lCv<%3YDs;!~$ z3p^{U%4F$%RdoncR%yS8(PRRrs*Z$3@Q|FJ4G*(CsFegV-n+e>_IPhFW?EFRqClp7@MwO4I1#) z)mNi$@*27LV)p`fxwpatoZI8~duv!*eJ4j%ADpkM1nGAkj@@p}SJg8x11)ip;2oE$ zs)jfULpgI-Ve|=5{}BDCoDCqvO+H_J(1Ttg_-c_C0UNybGLPR=Rux=h_fT_C={X5v z*9oALU+=H3VqFm(tIl3SgB(&?jShsaRav#N@*-B-_SFF@7zQZwt2nzJd@@Z8q0`Dd zbwT&aU}1UjVuw33yDG;G25msrz2)wp)9DN&5+S~6^zzu_SC|rrJ-%slhICY9PIZH~ z>UepgIr3m4}szSz(5Wb?H_vP}v zCTVsXfga;8SwL;IL<;ZG2GS%FDSTJ~Mf^zN&Dw^Ni4dO1%k1l-MhNfG1?oTlVcD1Q zBhasq?=_^^ZKUwp0%)r?QuqPZKkvWV4x~*)lgS9_X|oqr7g|yg;(MY-iY@(2ZT1&u zxwXlLC`3pSP^fef`JdIV>;T&GXri*)2WW| zc%5qhj-oW3JM}-QGp7FM))|VD+n%6Et+spSx5xZq?pxQdM>x8!%w<4nn=$?Si|(8A z=8ZEsyj{FM@*UFS`>xhqppDhxH)jC?od)^}o?p!C3!}eNRSFRKH|qb+nGx-$D0^o| z|24tHi2Ot5z7y?7`H%i<$_4!>KZWWl+AkaLqy6x@&(0y6iLOKr*gxT@9mr;qkX~r< z@>xO|4rL#y{o(zShF=q&LqDo3JZrBe?L%(pf#3DnU43s5qzONMS&~k$oSAq@2MomD z0<-+K9`z9J_ubi}jzNJA08Rp&vAsv#4nwd4a2Mb?D`ru7vA5aR@)Wj&;vc{-eg5d`C*TG0B}3t5qkb{k6JleQO57U903Zy7F%Ch zPQrV@2LN{g?gTslxDW6sU?)9eeqssoyB6R0R05`8Z+$yKd_Rzad~ZL{qm~0Me+zRC zfDZ!h2HXX>A8;SwA;1HG${0MuUsf*QF8IW10z3-16L1n7IXY18U2r(O1Mm=hMK4GB zm;VdTfJZS`u^siW1@8TKpdPAmMy>UzKenziqM?H)`2ZzI*gYY=& zeFtF5xj6FVT$JNHJOeI2zgNvY5BYLno&)W86tD!a2y-9RfcvH*KEY|2&j1`h9q|Bn zUD~Ve0(|gWy=n(N1HJ<|V`i^<1h5(~1wH#f9`XU0lHaRl1I_>}0IYWQs>=bl1Ns3U z1Y8ez0B{>%(VSlOLBO?u?SLsoz3MA~GXT2)s{xM!ZduT)ra?UJ0-OjqqqtYi0jvfr zqUS}uYAHPf1_8GNZUlS~a68}uz&605#h9xBTno4#aC=FwdI)eIAWd!@1snr7>B?R; z9dJ3|48UqY7vOfla=?9njeti1w*VF`>s4C;*8)BYxCL-8;4Z)efa9;~Rl5O;0IldJ z%K^s$ZULMG_#j{|;H2ff>JoYetfc3wQEu?_A;5`%2d+W60gK8}ZouW&qTGNp0=;Sr z;P~qiF9qoWZUo%-ZL}M~CZu;F@_!@B0l54oya!ynzE|A`xa$_oUjZKaZm&8%74NsA z{Q$?q3s{hze*%6W_%nnDJn%5e1GxPO)ED~MjCSM;@WDTz{D6mELiquU-U6Qx9@1?$ z`r)J`RXs}Z1XayOe_Nh{c~Za`C#vdlf+wl!A@ql$lQ9~NMZKS*s&>F#fCYeS$Ea!} z;m3j=;P%ro=Xx5-hk4T_fYswwbsymJvsE>J9PsC;Y7^k0b5*q+u;>DWr+(&C)rsg| zMRQekJo?w#LRGB>ELy0ld(poRU8bsI&O-YvQPonwNmsyD2Hbb0svZHXUJm+aBYnV9 zz%5s+Y8&9%Yw#X$d@1sa{<+1Yst=HyTA`}lfV;|6brKBQA}`7TcmS{saLaY7YW+I+ z{|3wf18(`Qs&1#}t?&ay&-bIgs9(3K>N|kdfVAK9z~gXBIT7@ph3yWw>rbkB7;w^G z0nzUvYS?ADevx8nOtYMsGBT;fq9_QWpqNVKCdfzhVyK(Qx>{atLamja8brxiZChj5NjzEsRrHM-uldnLg$-EOB16&7i z4VrN2z|F|%RWH)uW&l?L9QpI6i{iR~dvu0ATshG*;2MED1l)OmbWz+bxKD!o)TYr2 z+(h6Y;@Cyu9tF;B2)7rw8Nk(O!W{r^n;~2`aE}6ai>;5IH39Vpd8|!$9B@Sj+$7*C zfg1}NbWvV%feS)bYvV2ft_8Sy7K(?f1n#II+*;tqL9RcW$O96+7T{hf)YE$axNZY( zCvYkA^!2h2xFq1TdFcdhB5>MzISgErAzTvjupPKlH1#qbxE%}i^c=wLHsJDs>onj> zfIDiyRRcH9rO$H{aASbe=J^ib90uGD;ED{mUBFcWH&0W~9l$+c2=@+f?Z9by=m>DT z4B=A1$NPc1MnlgI+{DZD`O5|_7dS0F^1eC45NCe2Ajrs!P~+I=V9VQ3KXmWJX@#JfjL-ZB2iyD`Y;uPGib!Yu)= z9k}-xM({sy+o4mG0n$a`uv=L<0(~M;$j3>*wE%bc8t5KWxe0Hjrfo>bJ8?u};fPTX z%z4QPR|3p^rZQy&USuOkJHkIu!F3{~jDpWW@G&BIA;p@ToanazJ~M~K;%Og2yzzJU zs2Hl)MRkyZe53=njxea1bqNU#sY&@ySK~1q@3!Mz74`kuscE+*%uXG5YvSxwd$ZM< zn!d$0E7h@K#H`eubt4-`r8;J%rsEZYAn5GWq}j;{cbZ~r!-9f5wI#`^2YtQj-MF_V zVj#{>%}uy%RBFGdTd6%n`H`L|KPoM; z!NO}EDTmr)e)2>_BfWV?L$7)XWPx%8@yM2jy?1S|>Px|cljzMwxPno{ghk1T&spdO?MGo75jJI0ulhLhz{Ac* z*b7EdkSmgXA|&J>UO#}atu4LkOz68xvCL;q5(RQ4C$=-@cCvg>_fYHzM!Nfh--FIh z^~3T)-ROrb3wh9kDa=uX*|;5gI`zL$m@`=4DHdVu(8=GquUGvgp8LZ5_X(8t91$iT zVVZscJ3^P%B?%N}0m4wfu0)ulZM|wms0>txPFaQyRt8b$1qiV6FMM|F*h@^b{Z@xO90InhO>WS#FtC+}d?mlz?|w|FmO z{f&B_i}FeG4fSvhY-Xzp#Xovo%uDUGB#t=Av^EN<38~K&p}jjl=~ZvQz4al`oKK}k zw_KMvH`Tr%bsQfXil2T4y>4CN25MG{w;u7*KkZdNqFqc%E zvBlPGy*2T+1j_Gv$crX?XS5afbUE95*2E7b2hcb<4*fW33+AA3Z&lGrsLWQB89YRF+j%1T z59X?haZeZF$d2y>j_&Cqn3M`z5jZpjy9h^i{(cQ^25=jZ-YdX$RgJ@*SF@S+JmxVvGJz^bgB{V zcL-+P4mymF`ef-1ydOHDeQJd zUs|P!S0sQMs>(3979{5)`Zjc!^$Dta5!J`vK$z9DK^Jqfdj5=aw7#B$ps^ms_b00A zT~s#cvRb|bFKcyc(jtFrS~zENiJ1z3K@7U?i>_3cmNWSr%u%Gf&5HS=*wTI8G~K-9 z)n@4~jF4^)ib(T`X(Lp%ochEgP(aLN`#dPv&_k0Gt|2&^c#`A?$*KHgRXrJlvh}|a z7xf(`127mRzKc#oY#kCH`N>6yPji+NF_(B1^^42HOWP~Kj^19(AOwou+iQr-%mM&X`; zO|TEr_K&GamnD~`GUbZdH4bFu!N2sVcR~JGH-J`Oz6zjvm5v~@rjZmbKdD}o`J}Fu zB;LugG#@pN&f-9QHGVfGo*Mhb|))Q|%fH3Kk zRP{pQ&EoL%=ji)#eyS_+RTA}c!eomxnfeLIsiX{5eS!K(0_d6blZO+je-tMt-oO-% zMaVGa#eu$k0A~>W3G&JMI{us?+jcfHYZr0_TyNaY5RuNY|d1TAHvyqi(Tzm@b4bL^^f~PYV^PrAz}S zT2>5W+d%6fx?d7TYqOD7Ho~7JXSQ}WIrK;Z}<=$XZgpVhQP1H`|29}fc z+k8wKbz~0?trpOlIBjrf9RRJy>4QTn9m?>&OOBlu$ly#0n!i@nZ{VKzVO_#iY+|Pf zk1cqYjd$G$UZ|9qemYEweuQgdO) z><=o}7SL?MI%qvas`VDojD^pH&T}D#E8fNn8PDzqtw*mCw3Z$lt%>OCT`L8xbB>Lc zAGF2?1+5QZ;2%R7cY&6xNzi&Sep+N-wPC{k4($E7mUv3)19{)Yyg)*oRFsKt_aoc^ zrB@B$-jr{PF#0YqFfLjcDu*%#6G!$fs=A2c;vzn3!UR(_a4U(APDL5|_>a6RJn0rsb2#3-f$_s$(%5mo7_9$AridwxR-akl(|yS&*8(DAlo$;c*`d&t%Vj z(BFsle+_9F>(#JcGdH!#0xQdG%3%Q?SM1OycdF_}%IiG6eahqq>@BhOlMk-?$W)Ha z=k~;2$gwe&UiEqm4b~}`;F3J7oihu{87|5^?K!k)e@TV5a>b4E3H*rPkF>oplAe~` zZ9(how~lyrg0eFSOuB#6i2Elf+tNmCouC{!g%GEXczlAg`*hsyICI29c=xqcit+=y z4Z(KW5&2oW4Uu29+wkt6b{hh3oM1z2P`9SxJ>Z3JC)lvHWlN$B2HRUBY)4a-kCSct zQf4H^FvW0)??%F$VJ* zxJmiC?NTKNMZ1@4p|h3?PZIy(DtN7@!B4-D8HcM;^l}V)-gXm zf$mQEy6wL$ire-hi&D?hoE)kqM*qf9wmU~Dn@8F19YxR9GX#PEjIymyW*AXO>lrZo z5Q2Wmn=G~mEXofoeRY1?^C#G_&2Pgf+Yd)6&7*9;7^Q3-wICFOVx@d!Ye{`?nxanQ zX%KGQJr-nJc|E~)%c;tz$+pkNC?AfYf4sA?#-rrk7-9Qtg!17C9#2*~g-N?V8OWa} z+prw-9NhwU!Fx8_`qPyyqirpxEBjBjZ9iRkV~h=ZlBNlKf|)_jukrp@+InzC(# z?eA&IAChcOoTThXw%vV_^5az7jVDo@@i`#6)na?fqWs)q`=v#B-(ve!f^uVm4Q2=4 zpWTySdo)e?i`Dj*H06zvwx`pSeWPse0du15#WV_$IvW(qY(KRqYizf%e2m>|v3@dE z=^Tp}AC9%*b}OBhiLhfIPP9HVPWj()Dfn+22ju(o_j$f~-eTP~R%sh+!~bt6hi}jy z3FkAz}HSm?Lfz}`L;*|>cl`iaX z;f}cmXv&VR?71Au=RCvn0>kq%!*iv0#tr~>1;jI!0Ql9y0amHm)kq&+;KCFyy9x?u zvkf-vvwy5>3y7&zcDclR+G9kQeE+Xrw)IZw=HwJiC$OvJTn;gj$F7ao=RlVL$|_o@ zz=i2*c3}#hT|5`Kb@4kvR%yX}BwbjRW7kLlu{^=9oi}kP@h#W!XPM7*tXtD1$gs6+ zdhS(u{uMtx(Od|BmgVRc&%1s6{lCR?D4!fX{6Aa+!!__Fu7SpR<~`aWut~rc0b2!Z6R=&t4gos_>=sbDL!>XDT|kF`xdOTbEEUi%V3U9?0=5d+ zCSbdO9RhX=*e#%Pr$}EwyMPV>a|Lt>SSp}jz$O7(1Z)+sO~7^mI|S?$uvsILju+cUE=CTBP<%B*LPnKxu*WjL}g z5NMu$q<_+jtjdR~@jZ>_2@15H@AEeoiU2bO{z8Gz6nI*1rSQuIUg{6DUz+ei1Kug{ zZ9<j1P`11um@ji}_;b#cE%W7dS zXg?-hhXj6{2!Az4EB8XdB>MFNZx{H-1pZC~exJanxe{1Nwx1DqzlUNABI;SZ{z2#{^zeLcNbY5h5 zSbM^*lK6LlKUqF#;HSWU9rfwBn)B5+#JjT~YA4Vxr2laI`2tV-_RZ*cfhRgHauR@x z_N3AEHEdsC_<$aNP~a7;$s?kU1r^CJ(L6F3gI9@rK zC@f2Njz0YN1U~mv9-e&< zgE)@^Z&p9Ai0}#xG`P+a`I!oNPw962o70hY_hZH8bS@X+U7zX0HvrG_nac@FUl`=; zi11CKyw|YQvG-z(IeicC6X4J#rw{`ZE>t_aZU>&|xK{9V*`7|k`BdQjNgRKJ2tNjb zm*}(_=*$G3==crw`3Uf4^|qJMNmELDIDN^7A4dp3Zmc;S@<~JaDG~a=ELR=ytbV@5 z>+LO(|Gg3Dd?doB74ZDfHwJWl7YYWoW0PpdNgS;_20YPsEavnjzkLf6A;jmMCvp5k zBK&;diB75LcaqMxfhRg?OZ0U9Bf`53{Bs6Gz}E#$Etmp4)x%yf&x7dfS}O2%Q9lxY zGsB}_9OVVg5aEBr=z||NbG+>D*I^=w^51FbM?VCf@~@=w@bqmhU9SUg*6zI#@TXzo zit3F#=g}qgw0Xc2{Z{Pmp^JSd4)_ZZzWX3UGrtaW_k_TAp2NeleVo8s&;c18!Jjoe zno=Y1ZP)Pd?+N_-z*Bi0qP_6Qu4H7)tXxxoXYDwd(~&-PHVSV%PuJd3gIA9-e&@hd1p4?-KPR`SV@i89%&@ zK)AX&P(HC!xv&RH^cW{%BPWj0q|5mrK0|2ePCbv)$ra`QnV-urkg;+Z`13l3hx`=%QS#fpz?RNmHIdVZdcilX}5Vc-)V@D#qIjfY<( z^7AzmoWd6v`pZm)PgCq-JVo`g>ssK=^0^Lp*1kd!pzlxV>J;=91AQff=s+KPhlk7M zKuH0fdXj)<%QHv>=kX%hASJMnHB>oMRdUB_9xo~7J=N8pt@-tOcxlCH}gy#6~4?X>}TqT?6+WepFm zya&8l{r5z`kIoeJAox>`r)z;{^(^W^_OAzlH>3Yl1pMCx{kF}#T+G)F@>-n5)3uBI zgALgAqQJLS@cN2DSIRv`y! zI2r8i=iyrn{e2_wY~1`K54cr?zfXpr#_9h{;QuA?{;N4&w#$`M1^p}a`FTU&?btHS zE?#UU6ABFDPoW4%^LrEUtX+=qfM`~BJpsH~ySx|ykB#n(e%dLV&M6}KGjn)(J6`2< z$yW$n-vplZ3xl1z40y_Cx1n5r75Gv^efp-0@F(zerH`41fv0+I`5RA90Od&$zBQ9) zQ0k52Fdk95E`xo#CBis$j|iXZ=IPRRk#vo_#Jt`vh=5;|67RVws+A(oW$zGW_N^CI9^15fFe zzQGBTuNb;+1D?j09E1FP40uYnV=FJOw41&&)4aV}fv50oWjy>IPF`7&%keEY^71|{ z@VkJg{B-=8BR&-PKMK4{=&J#Ne+_tQ$5PSn@W`&SW^wxVukm!rM+9B-fH&)pH;C~5 z=XrjlkE?EhZ_Vd;*^cG2dAcnIyJQ4Qb}TWBQ`ay&>|#T`-3L6; zH_D%v1>U}n6Bfgya;a0~|9p;rjb~FS0-oBX(;yFZ zgS>rA;Qa>uHlvV-cU{BjNO|(6z;_t)GL;gtU`hJA)4~g*YLT*bx zxe4<*ol-;o8w9>{I&WX;2lsh_Zz|{MvTu`-?)gQ$y|x+nZ58m8&rZX*@E-8g-yLEe z>8C9B*zdyd;z0vWUckfK(|LaA`#-wQ2cGErg}or<IbM|GT{wMPMi0N|Wc7eAGeP*NxZ(Ah7=WzPcr}Hx4 z&GNZMgwLJF>AxWQ`$ND}ew1F0huO%k0}Kzl-q4OGEavGN`(u{Cr-^w3IgUIGyjgyp z65(@i=J{v7HIee^OU%Px06gP=!#wsJflm{9`z<2>Hvn%J_gc^#0smt`r}TF`KiheA zD4zjO{Jhi9zs_6A@l6K4x*T}QXXg(%9p;M@8F*aayG8!xxc{NV3%&i5#- z+lN!us@!#6cEA`rASauh!-*5va5@^DI_A69nVF6A%-lEw&|QZU@NoK7@#4wu%xTrN zwX5p=ZhFUPnc(X@K4i$b*i%^MbWX!TZ*-2D)2GSV;$UWGeNEMM^Z<#}Bk%=UY#0)@qkbHGykbyd(CKy9-ISc38_&UZT(&0n0S zEzsg%PDOo9SrBLM70y}VnqTH~fyF$FoeNQRO~G|-lR34nmK~eN&mg1*CZ5mXERUxO z-?fD3hZ$IqX_~HwBM$X!6XKf8GIX1&avaY|-5{7gH!dx(gSfeiucS4n8l=?ksboYc{SyF?q`bMZorAdb1z zIP{K)etAk+98W2!h=!+K_5g%ZH>21 zal6ZF-7BkWS3qGbhc;N}_S82jWwkyW4TtH`}@&YZ>0 zCGI7&W*0f#N=49HU7b6(sBm_kJ1ZkAV+z@A{o6PQwPdkgrO_W4-6v&`32z`!Q%i;x z8^w*O^*`{kacPKkWvZtbb54CzcY^HD>aO7>nIcu|dMM}6Kr^SpLaGX#z>c25wS+7Y zuF5ZM8eK6VmYmKCA1)-3nIi&orMA|MnT4!O*_n0k!ZLLHM&;1t0Ba+mG*(yn_@Uro z88OqE7~ex>&C7H)ghj~e$6m{EI&*~Oj|mEjj=nd|JxAD>qRR*RY)w7Sh5B6a;whnl z9jc5o(}CmceV!W6N^iiqXmN15dsfXFHyH`gt7f^8NRE2}f9WD7WYzV&9_Ll=7*@y<-79}O_$r)rCFDZ<`&+JfmoiJflrw^SuePy6_HO+#si9j)} z#->uHF$|_wuH~|}pQ#niBq6bgPOeYG=!Hq4U_S5P5wpzBIoA$*@%H8N_&Y{jFu-!# z$MS4IkJzh8>d7qAvES}xO#HZmm8e+v3MgPqI2oI5aWHF&TN6l5iMh)VTo*VaGioy% z&ki@%eP*m9QMMRBszQSs$H zN_~@*g+^P}=pj`bdiV8SV`qyb(|FX#GB2ztd5?^}=`sA6NlD#Q82Sd5RA^Nng7amuwM4MKa{EAsiiP+1^<+zyTkV9Uzw`OIqk`E+? zQ6&DR*4t7Zo$VAS_rUgGDtX5_j>$=25FHsjnA>wR#cE~O)K%`m@f0wl+m(cHHMqw>6nG8smE~G2!*iL zUza(>T}bn3G+*YX1=T`Ve(jtU2+9U0ti@sG$>Cl++l{rjCCpsP%rQz+?ZklY9hXSq zh94~E1z1X}@X+EA?MbL9=f<>dXvoagP8kY?UW!dx@AF_W6iGy^Th@{?0$G~jz1^5Z z7Ml}@$Qw-m)hS$T0H4NZGh-rdjGKCC8nIfKDyk7}5G49d7N*lbqOA&# zzcw{RBo$gJV=HBmm&$nk#yg#)V@ongV;RL|Gl%91X+oWp<(2iG04?%Wdp&hty`BYY zGBmW-t-*A>j}NU?T3*P=Wae3X`UqphSh9a?Lr07$=!H^@EKQ5uY%njcLJwQ%B^gY1 zuBMAc>F}ogovY7FE-!|WL=xPyqN*Vi+=7)553Rwk@q01bRZ;8IH&>ivyN3qXm}-a{ zR{<|fbu-0Ww_z$YEM`u{8cm&Mt`8F*eoSL{F^9qSXSw-?u26)&rH*5qZe2VLR#$8# zi!6~zLXpIdWahKUC0&nX;n8(+q*ltrC|gvj!FB+yqw2(IM%MKBB?1$nQLX7Hx>1}g zqg4lE6+m(K;4ssHw`(vd_?CGJT##W|c^@_4q9UX2!f-GN-Pxsv_vF_cQY%VkxOFMU&=K3sTQyqc9ut zus+gQ6=q56wFR?|r8oL>oCim6}cQ#Uuav(^9oN54nbF5DZ2p zkF+^K?l-{RYx=05M#>S{@ib#-1^aX%#CBXYtXb{TvFb5t7TQE(Qi3C^f?<7(&o7l% zV_?&0>KRfO&@X%qo{cSM7ya0Qg)K<3dUZUZspCPZzGKwM24KyjQmLYkS>-Bsg{P`-( zoMNcJCdC?qf~M!$<2X_~*vDyPX1SfdI&AFr8uxslKBi;Krl)>oWw3A7vd%F5mKACt z&EEF-tCNT#7U9XS(tHcRHqnHJ1=1-2u)O` zDby{4{Hp-W$MDstEC<{Sl&^-X0c?_}DXR})cA{*Je&IUlPltRSzxTpV^C2{&9+!7Pcj^Rb&a+==5M~k`-TaFNu3NGR96Q>nPu>j$+B&Y34H<}9eTj+ z1-bKB;#mQQ8SbSu_)56ky$If;eCW}6dHDR;q47F8h4`M=%clb12(r!{{WA-#$-w(} zl~UQ&l<{75ZXcnB4tav6}cWYHM^4 zZoI>nKOTx8?)=q3C4=o%%)o8N%33_qO`W$)$sos@N(S>}l@X{Vr!`83w^F#!sw@XJ z`GjQ3%EW@J8>PWu&!}?mTAYTwXC5+<4UlA6_Q0(!;@1W#VPIG?E9&YLxFPfT;KNJ0 zK|WS^CJ2ykZ{c=Y*&%Kuv>Or-?!-gb4BTns?-lVSoEQqpZ>)yrS$O_LRcmGX-Qq^V zJA~tL8PAwL+~q6D_{sPiNAUzC>^OrzliP7}H7(zKk!+f1`*$n@3Z2-o$StY!T-GQ2f*JGsfQx9A$9?e(Y+|L*g&(CG#P1 z8*rnIZx`_;^oI!Z7-=G+gtr^wx7@`8NGQXJXykF8T@ro|PulcbMSKZM`$_+PLwtD- zxrB{*vSsw?@+U?4i6Oo`|5w5jWk3Oq_4km7A4)}b907OBf{OTd0VVhiZm9e+zC6cR z!dHmtG?y{`J$R>$zik9Rs6oO9?3&29mHZ>IFXBcUe}*{tNy4#)1SzccdJ7M!_=)2o zLgzde$J;oA!$wJ1Bq-xcI2w_)@k8fB=kkc6I%IZ3 z`Iqs>8RE KGDI*uD*qo)Q1k!* literal 0 HcmV?d00001 From fe7102e05fb5537067c8125d7eb996cc8ea9fd19 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Sat, 27 Jan 2024 18:31:30 +0200 Subject: [PATCH 033/161] add meta files --- usearch.meta | 8 ++++++++ usearch/NativeMethods.cs.meta | 11 +++++++++++ usearch/USearchException.cs.meta | 11 +++++++++++ usearch/USearchIndex.cs.meta | 11 +++++++++++ usearch/USearchTypes.cs.meta | 11 +++++++++++ usearch/libusearch_c.dll.meta | 27 ++++++++++++++++++++++++++ usearch/libusearch_c.dylib.meta | 33 ++++++++++++++++++++++++++++++++ usearch/libusearch_c.so.meta | 27 ++++++++++++++++++++++++++ 8 files changed, 139 insertions(+) create mode 100644 usearch.meta create mode 100644 usearch/NativeMethods.cs.meta create mode 100644 usearch/USearchException.cs.meta create mode 100644 usearch/USearchIndex.cs.meta create mode 100644 usearch/USearchTypes.cs.meta create mode 100644 usearch/libusearch_c.dll.meta create mode 100644 usearch/libusearch_c.dylib.meta create mode 100644 usearch/libusearch_c.so.meta diff --git a/usearch.meta b/usearch.meta new file mode 100644 index 00000000..a5b28490 --- /dev/null +++ b/usearch.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0f156db2be1ffd029bb3bd936ce17fc6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/usearch/NativeMethods.cs.meta b/usearch/NativeMethods.cs.meta new file mode 100644 index 00000000..cc761285 --- /dev/null +++ b/usearch/NativeMethods.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 74da544909921463e8668ed39eecc74a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/usearch/USearchException.cs.meta b/usearch/USearchException.cs.meta new file mode 100644 index 00000000..cbcd128d --- /dev/null +++ b/usearch/USearchException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4b06aed1037c8d223bb087c535d813e1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/usearch/USearchIndex.cs.meta b/usearch/USearchIndex.cs.meta new file mode 100644 index 00000000..23e2b385 --- /dev/null +++ b/usearch/USearchIndex.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1e1a090548d0594b6bdac282576e5eab +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/usearch/USearchTypes.cs.meta b/usearch/USearchTypes.cs.meta new file mode 100644 index 00000000..0014ff94 --- /dev/null +++ b/usearch/USearchTypes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 167cfaf6d3e1a437fb8424e3c87d10ba +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/usearch/libusearch_c.dll.meta b/usearch/libusearch_c.dll.meta new file mode 100644 index 00000000..4b553d09 --- /dev/null +++ b/usearch/libusearch_c.dll.meta @@ -0,0 +1,27 @@ +fileFormatVersion: 2 +guid: f65d821ca1336470898ffb7fc6639422 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/usearch/libusearch_c.dylib.meta b/usearch/libusearch_c.dylib.meta new file mode 100644 index 00000000..7dd14cc1 --- /dev/null +++ b/usearch/libusearch_c.dylib.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 7ec1d45a7b535a393a062db93afd340f +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 1 + settings: + DefaultValueInitialized: true + - first: + Standalone: OSXUniversal + second: + enabled: 1 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/usearch/libusearch_c.so.meta b/usearch/libusearch_c.so.meta new file mode 100644 index 00000000..d4a98f1f --- /dev/null +++ b/usearch/libusearch_c.so.meta @@ -0,0 +1,27 @@ +fileFormatVersion: 2 +guid: 86f442d36fdc6978f907b4f82181b116 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: From b0cd287eff82775613c77a532d8995d7ca82d7df Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Mon, 29 Jan 2024 09:22:42 +0200 Subject: [PATCH 034/161] expose load buffer options --- usearch/NativeMethods.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/usearch/NativeMethods.cs b/usearch/NativeMethods.cs index 67e81a05..ea5bc775 100644 --- a/usearch/NativeMethods.cs +++ b/usearch/NativeMethods.cs @@ -25,9 +25,15 @@ internal static class NativeMethods [DllImport(LibraryName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void usearch_load(usearch_index_t index, [MarshalAs(UnmanagedType.LPStr)] string path, out usearch_error_t error); + [DllImport(LibraryName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void usearch_load_buffer(usearch_index_t index, void_ptr_t buffer, size_t length, out usearch_error_t error); + [DllImport(LibraryName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void usearch_view(usearch_index_t index, [MarshalAs(UnmanagedType.LPStr)] string path, out usearch_error_t error); + [DllImport(LibraryName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void usearch_view_buffer(usearch_index_t index, void_ptr_t buffer, size_t length, out usearch_error_t error); + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] public static extern size_t usearch_size(usearch_index_t index, out usearch_error_t error); @@ -128,4 +134,4 @@ out usearch_error_t error [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] public static extern size_t usearch_rename(usearch_index_t index, usearch_key_t key_from, usearch_key_t key_to, out usearch_error_t error); } -} \ No newline at end of file +} From e7f54b6a930a794619a5941a0d3cee6dc7672c2a Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Mon, 29 Jan 2024 09:23:23 +0200 Subject: [PATCH 035/161] save index in zip file --- usearch/USearchIndex.cs | 136 ++++++++++++++++++++++++++++++---------- 1 file changed, 102 insertions(+), 34 deletions(-) diff --git a/usearch/USearchIndex.cs b/usearch/USearchIndex.cs index 544a9296..6b0d258d 100644 --- a/usearch/USearchIndex.cs +++ b/usearch/USearchIndex.cs @@ -1,7 +1,9 @@ using System; using System.IO; +using System.IO.Compression; using System.Runtime.InteropServices; using System.Runtime.Serialization.Formatters.Binary; +using UnityEngine; using static Cloud.Unum.USearch.NativeMethods; namespace Cloud.Unum.USearch @@ -11,24 +13,23 @@ public class USearchIndex : IDisposable private IntPtr _index; private bool _disposedValue = false; private ulong _cachedDimensions; - private IndexOptions _initOptions; + private IndexOptions _indexOptions; + public USearchIndex( - MetricKind metricKind, - ScalarKind quantization, ulong dimensions, - ulong connectivity = 0, - ulong expansionAdd = 0, - ulong expansionSearch = 0, + MetricKind metricKind = MetricKind.Cos, + ulong connectivity = 32, + ulong expansionAdd = 40, + ulong expansionSearch = 16, bool multi = false - //CustomDistanceFunction? customMetric = null ) { IndexOptions initOptions = new() { metric_kind = metricKind, metric = default, - quantization = quantization, + quantization = ScalarKind.Float32, dimensions = dimensions, connectivity = connectivity, expansion_add = expansionAdd, @@ -38,41 +39,112 @@ public USearchIndex( Init(initOptions); } - public USearchIndex(IndexOptions options) + public USearchIndex(string path, string name = "") { - Init(options); + Load(path); } - public USearchIndex(string path, bool view = false) + public void Init(IndexOptions options) { - IndexOptions initOptions = LoadIndexOptions(path + ".index_options"); - Init(initOptions); + _indexOptions = options; + this._index = usearch_init(ref options, out IntPtr error); + HandleError(error); + this._cachedDimensions = options.dimensions; + } + + private static string GetIndexFilename(string name = "") + { + return name == "" ? "index" : name + ".index"; + } - IntPtr error; - if (view) + private static string GetIndexOptionsFilename(string name = "") + { + return name == "" ? "indexOptions" : name + ".indexOptions"; + } + + private void Load(string path, string name = "") + { + try { - usearch_view(this._index, path, out error); + using (FileStream zipFileStream = new FileStream(path, FileMode.Open)) + using (ZipArchive zipArchive = new ZipArchive(zipFileStream, ZipArchiveMode.Read)) + { + var entry = zipArchive.GetEntry(GetIndexOptionsFilename(name)); + using (Stream fileStream = entry.Open()) + { + LoadIndexOptions(fileStream); + } + + entry = zipArchive.GetEntry(GetIndexFilename(name)); + using (Stream entryStream = entry.Open()) + using (MemoryStream memoryStream = new MemoryStream()) + { + entryStream.CopyTo(memoryStream); + // Access the length and create a buffer + byte[] managedBuffer = new byte[memoryStream.Length]; + memoryStream.Position = 0; // Reset the position to the beginning + memoryStream.Read(managedBuffer, 0, managedBuffer.Length); + + GCHandle handle = GCHandle.Alloc(managedBuffer, GCHandleType.Pinned); + try + { + IntPtr unmanagedBuffer = handle.AddrOfPinnedObject(); + usearch_load_buffer(_index, unmanagedBuffer, (UIntPtr)managedBuffer.Length, out IntPtr error); + HandleError(error); + } + finally + { + handle.Free(); + } + } + } } - else + catch (Exception ex) { - usearch_load(this._index, path, out error); + Debug.LogError($"Error loading the search index: {ex.Message}"); } - HandleError(error); } - public void Init(IndexOptions options) + public void Save(string path, string name = "", FileMode mode = FileMode.Create) { - _initOptions = options; - this._index = usearch_init(ref options, out IntPtr error); + string indexPath = path + GetIndexFilename(name); + string indexOptionsPath = path + GetIndexOptionsFilename(name); + usearch_save(_index, indexPath, out IntPtr error); HandleError(error); - this._cachedDimensions = options.dimensions; + SaveIndexOptions(indexOptionsPath); + try + { + using (FileStream zipFileStream = new FileStream(path, mode)) + using (ZipArchive zipArchive = new ZipArchive(zipFileStream, ZipArchiveMode.Create)) + { + zipArchive.CreateEntryFromFile(indexPath, GetIndexFilename(name)); + zipArchive.CreateEntryFromFile(indexOptionsPath, GetIndexOptionsFilename(name)); + } + } + catch (Exception ex) + { + Debug.LogError($"Error adding file to the zip archive: {ex.Message}"); + } + File.Delete(indexPath); + File.Delete(indexOptionsPath); } - public void Save(string path) + public IndexOptions GetIndexOptions() { - usearch_save(this._index, path, out IntPtr error); - HandleError(error); - SaveIndexOptions(path + ".index_options"); + return _indexOptions; + } + + public void SaveIndexOptions(Stream fileStream) + { + BinaryFormatter formatter = new BinaryFormatter(); + formatter.Serialize(fileStream, _indexOptions); + } + + public void LoadIndexOptions(Stream fileStream) + { + BinaryFormatter formatter = new BinaryFormatter(); + IndexOptions indexOptions = (IndexOptions)formatter.Deserialize(fileStream); + Init(indexOptions); } public void SaveIndexOptions(string path) @@ -81,8 +153,7 @@ public void SaveIndexOptions(string path) { using (FileStream fileStream = new FileStream(path, FileMode.Create)) { - BinaryFormatter formatter = new BinaryFormatter(); - formatter.Serialize(fileStream, _initOptions); + SaveIndexOptions(fileStream); } } catch (Exception ex) @@ -91,22 +162,19 @@ public void SaveIndexOptions(string path) } } - public IndexOptions LoadIndexOptions(string path) + public void LoadIndexOptions(string path) { - IndexOptions initOptions = default; try { using (FileStream fileStream = new FileStream(path, FileMode.Open)) { - BinaryFormatter formatter = new BinaryFormatter(); - initOptions = (IndexOptions)formatter.Deserialize(fileStream); + LoadIndexOptions(fileStream); } } catch (Exception ex) { Console.WriteLine($"Error deserializing struct: {ex.Message}"); } - return initOptions; } public ulong Size() From 419026d4cf25acd76b266ce723f74b419c45a8b4 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Mon, 29 Jan 2024 09:25:24 +0200 Subject: [PATCH 036/161] pass name to load --- usearch/USearchIndex.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usearch/USearchIndex.cs b/usearch/USearchIndex.cs index 6b0d258d..5405213b 100644 --- a/usearch/USearchIndex.cs +++ b/usearch/USearchIndex.cs @@ -41,7 +41,7 @@ public USearchIndex( public USearchIndex(string path, string name = "") { - Load(path); + Load(path, name); } public void Init(IndexOptions options) From 5110f321992a5f405ec6fd0c1fb0e757598b3b0b Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Thu, 1 Feb 2024 20:19:03 +0200 Subject: [PATCH 037/161] add asmdef for usearch --- usearch/Cloud.Unum.USearch.asmdef | 3 +++ usearch/Cloud.Unum.USearch.asmdef.meta | 7 +++++++ 2 files changed, 10 insertions(+) create mode 100644 usearch/Cloud.Unum.USearch.asmdef create mode 100644 usearch/Cloud.Unum.USearch.asmdef.meta diff --git a/usearch/Cloud.Unum.USearch.asmdef b/usearch/Cloud.Unum.USearch.asmdef new file mode 100644 index 00000000..adf4461e --- /dev/null +++ b/usearch/Cloud.Unum.USearch.asmdef @@ -0,0 +1,3 @@ +{ + "name": "Cloud.Unum.USearch" +} diff --git a/usearch/Cloud.Unum.USearch.asmdef.meta b/usearch/Cloud.Unum.USearch.asmdef.meta new file mode 100644 index 00000000..a593d1a3 --- /dev/null +++ b/usearch/Cloud.Unum.USearch.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e0f17c78281e4206582b61d677a5897c +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From 739778e3a5a9c97b7ea0ea3b7ce8081e21770428 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Thu, 1 Feb 2024 22:54:06 +0200 Subject: [PATCH 038/161] add usearch to Runtime asmdef --- Runtime/undream.llmunity.Runtime.asmdef | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Runtime/undream.llmunity.Runtime.asmdef b/Runtime/undream.llmunity.Runtime.asmdef index 297361d2..ebc73035 100644 --- a/Runtime/undream.llmunity.Runtime.asmdef +++ b/Runtime/undream.llmunity.Runtime.asmdef @@ -3,6 +3,7 @@ "rootNamespace": "", "references": [ "Unity.Sentis", - "HuggingFace.SharpTransformers" + "HuggingFace.SharpTransformers", + "Cloud.Unum.USearch" ] } \ No newline at end of file From 429afc2a5c02f444e341f1c48a61d33f565861ba Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Thu, 1 Feb 2024 22:54:53 +0200 Subject: [PATCH 039/161] implement ANNSearch --- Runtime/Search.cs | 66 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/Runtime/Search.cs b/Runtime/Search.cs index df7c2a65..a82a1218 100644 --- a/Runtime/Search.cs +++ b/Runtime/Search.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using Unity.Sentis; +using Cloud.Unum.USearch; public abstract class Search where E : Embedder { @@ -14,10 +15,13 @@ public Search(E embedder) this.embedder = embedder; } + public abstract void Insert(string inputString, T encoding); + public T Add(string inputString) { - embeddings[inputString] = embedder.Encode(inputString); - return embeddings[inputString]; + T embedding = embedder.Encode(inputString); + Insert(inputString, embedding); + return embedding; } public T[] Add(string[] inputStrings) @@ -49,12 +53,19 @@ public List GetKNN(string[] inputStrings, float[] scores, int k = -1) public class ModelSearch : Search { - public ModelSearch(EmbeddingModel embedder) : base(embedder) { } + public ModelSearch(EmbeddingModel embedder) : base(embedder) {} + + public override void Insert(string inputString, TensorFloat encoding){ + embeddings[inputString] = encoding; + } public new TensorFloat[] Add(string[] inputStrings) { TensorFloat[] inputEmbeddings = (TensorFloat[])embedder.Split(embedder.Encode(inputStrings)); - for (int i = 0; i < inputStrings.Length; i++) embeddings[inputStrings[i]] = inputEmbeddings[i]; + for (int i = 0; i < inputStrings.Length; i++) + { + Insert(inputStrings[i], inputEmbeddings[i]); + } return inputEmbeddings; } @@ -66,3 +77,50 @@ public override List RetrieveSimilar(string queryString, int k) return GetKNN(embeddings.Keys.ToArray(), scores, k); } } + +public class ANNModelSearch : ModelSearch +{ + USearchIndex index; + protected Dictionary TextToUSearch; + protected Dictionary USearchToText; + ulong nextKey; + + public ANNModelSearch( + EmbeddingModel embedder, + ulong dimensions, + MetricKind metricKind = MetricKind.Cos, + ulong connectivity = 32, + ulong expansionAdd = 40, + ulong expansionSearch = 16, + bool multi = false + ) : this(embedder, new USearchIndex(dimensions, metricKind, connectivity, expansionAdd, expansionSearch, multi)) {} + + public ANNModelSearch( + EmbeddingModel embedder, + USearchIndex index + ) : base(embedder) { + this.index = index; + TextToUSearch = new Dictionary(); + USearchToText = new Dictionary(); + nextKey = 0; + } + + public override void Insert(string inputString, TensorFloat encoding){ + if (TextToUSearch.ContainsKey(inputString)) return; + ulong key = nextKey++; + TextToUSearch[inputString] = key; + USearchToText[key] = inputString; + index.Add(key, encoding.ToReadOnlyArray()); + } + + public override List RetrieveSimilar(string queryString, int k) + { + float[] queryEmbedding = embedder.Encode(queryString).ToReadOnlyArray(); + index.Search(queryEmbedding, k, out ulong[] keys, out float[] distances); + List result = new List(); + for(int i=0; i Date: Fri, 2 Feb 2024 13:32:40 +0200 Subject: [PATCH 040/161] allow different output layers --- Runtime/Embedder.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Runtime/Embedder.cs b/Runtime/Embedder.cs index b64c758e..5a3fb97d 100644 --- a/Runtime/Embedder.cs +++ b/Runtime/Embedder.cs @@ -31,6 +31,10 @@ public class EmbeddingModel : Embedder BertPreTokenizer bertPreTok; WordPieceTokenizer wordPieceTokenizer; TemplateProcessing templateProcessing; + List outputLayerNames = new List(){ + "last_hidden_state", + "sentence_embedding" + }; public EmbeddingModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU) { @@ -91,7 +95,9 @@ public TensorFloat Encode(List input) // Step 2: Compute embedding and get the output worker.Execute(inputSentencesTokensTensor); // Step 3: Get the output from the neural network - TensorFloat outputTensor = worker.PeekOutput("last_hidden_state") as TensorFloat; + List validOutputs = runtimeModel.outputs.Intersect(outputLayerNames).ToList(); + if (validOutputs.Count() != 1) throw new Exception("Could not determine output layer!"); + TensorFloat outputTensor = worker.PeekOutput(validOutputs[0]) as TensorFloat; // Step 4: Perform pooling TensorFloat MeanPooledTensor = MeanPooling(inputSentencesTokensTensor["attention_mask"], outputTensor, ops); // Step 5: Normalize the results @@ -151,7 +157,8 @@ Tuple>, List>, List>> Tokenize(List c } int max_length = (int)tokenizerJsonData["truncation"]["max_length"]; - Tuple>, List>> tuple_ = PaddingOrTruncate(true, true, sentences, max_length, JObject.FromObject(tokenizerJsonData["padding"])); + // Tuple>, List>> tuple_ = PaddingOrTruncate(true, true, sentences, max_length, JObject.FromObject(tokenizerJsonData["padding"])); + Tuple>, List>> tuple_ = PaddingOrTruncate(true, true, sentences, max_length); attentionMask = tuple_.Item1; tokenIds = tuple_.Item2; @@ -248,7 +255,7 @@ public Dictionary TokenizeInput(List sentences) return inputTensors; } - static Tuple>, List>> PaddingOrTruncate(bool padding, bool truncation, List> tokens, int max_length, JObject config) + static Tuple>, List>> PaddingOrTruncate(bool padding, bool truncation, List> tokens, int max_length) { // TODO allow user to change string padding_side = "right"; From 719086bce45fd50f9904256d4a58d72157d8271b Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 2 Feb 2024 15:25:48 +0200 Subject: [PATCH 041/161] specify output layer and mean pooling, model cards --- Runtime/Embedder.cs | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/Runtime/Embedder.cs b/Runtime/Embedder.cs index 5a3fb97d..78329998 100644 --- a/Runtime/Embedder.cs +++ b/Runtime/Embedder.cs @@ -31,12 +31,10 @@ public class EmbeddingModel : Embedder BertPreTokenizer bertPreTok; WordPieceTokenizer wordPieceTokenizer; TemplateProcessing templateProcessing; - List outputLayerNames = new List(){ - "last_hidden_state", - "sentence_embedding" - }; + string outputLayerName; + bool useMeanPooling; - public EmbeddingModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU) + public EmbeddingModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU, string outputLayerName="last_hidden_state", bool useMeanPooling=true) { runtimeModel = ModelLoader.Load(modelPath); string tokenizerJsonContent = File.ReadAllText(tokenizerPath); @@ -50,6 +48,8 @@ public EmbeddingModel(string modelPath, string tokenizerPath, BackendType backen bertPreTok = new BertPreTokenizer(JObject.FromObject(tokenizerJsonData["pre_tokenizer"])); wordPieceTokenizer = new WordPieceTokenizer(JObject.FromObject(tokenizerJsonData["model"])); templateProcessing = new TemplateProcessing(JObject.FromObject(tokenizerJsonData["post_processor"])); + this.outputLayerName = outputLayerName; + this.useMeanPooling = useMeanPooling; } public void Destroy() @@ -95,11 +95,12 @@ public TensorFloat Encode(List input) // Step 2: Compute embedding and get the output worker.Execute(inputSentencesTokensTensor); // Step 3: Get the output from the neural network - List validOutputs = runtimeModel.outputs.Intersect(outputLayerNames).ToList(); - if (validOutputs.Count() != 1) throw new Exception("Could not determine output layer!"); - TensorFloat outputTensor = worker.PeekOutput(validOutputs[0]) as TensorFloat; + TensorFloat outputTensor = worker.PeekOutput(outputLayerName) as TensorFloat; // Step 4: Perform pooling - TensorFloat MeanPooledTensor = MeanPooling(inputSentencesTokensTensor["attention_mask"], outputTensor, ops); + TensorFloat MeanPooledTensor = outputTensor; + if (useMeanPooling){ + MeanPooledTensor = MeanPooling(inputSentencesTokensTensor["attention_mask"], outputTensor, ops); + } // Step 5: Normalize the results TensorFloat NormedTensor = L2Norm(MeanPooledTensor, ops); // Cleanup @@ -326,3 +327,15 @@ static List> AddTokenTypes(List> inputIds) return inputIds.Select(innerList => innerList.Select(_ => 0).ToList()).ToList(); } } + +public class BGEModel: EmbeddingModel +{ + public BGEModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU): + base(modelPath, tokenizerPath, backend, "sentence_embedding", false){} +} + +public class MiniLMModel: EmbeddingModel +{ + public MiniLMModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU): + base(modelPath, tokenizerPath, backend, "last_hidden_state", true){} +} \ No newline at end of file From 9ea01cf32cf5234c2feb5e7bb962ef5122e8acf6 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 2 Feb 2024 16:31:36 +0200 Subject: [PATCH 042/161] add namespace, implement Count method --- Runtime/Search.cs | 202 +++++++++++++++++++++++++--------------------- 1 file changed, 108 insertions(+), 94 deletions(-) diff --git a/Runtime/Search.cs b/Runtime/Search.cs index a82a1218..7740804a 100644 --- a/Runtime/Search.cs +++ b/Runtime/Search.cs @@ -4,123 +4,137 @@ using Unity.Sentis; using Cloud.Unum.USearch; -public abstract class Search where E : Embedder -{ - protected E embedder; - protected Dictionary embeddings; - public Search(E embedder) +namespace LLMUnity +{ + public abstract class Search where E : Embedder { - embeddings = new Dictionary(); - this.embedder = embedder; - } + protected E embedder; + protected Dictionary embeddings; - public abstract void Insert(string inputString, T encoding); + public abstract void Insert(string inputString, T encoding); + public abstract List RetrieveSimilar(string queryString, int k); - public T Add(string inputString) - { - T embedding = embedder.Encode(inputString); - Insert(inputString, embedding); - return embedding; - } - - public T[] Add(string[] inputStrings) - { - T[] inputEmbeddings = new T[inputStrings.Length]; - for (int i = 0; i < inputStrings.Length; i++) + public Search(E embedder) { - inputEmbeddings[i] = Add(inputStrings[i]); + embeddings = new Dictionary(); + this.embedder = embedder; } - return inputEmbeddings; - } - public List GetKNN(string[] inputStrings, float[] scores, int k = -1) - { - var sortedLists = inputStrings.Zip(scores, (first, second) => new { First = first, Second = second }) - .OrderByDescending(item => item.Second) - .ToList(); - List results = new List(); - int kmax = k == -1 ? sortedLists.Count : Math.Min(k, sortedLists.Count); - for (int i = 0; i < kmax; i++) + public T Add(string inputString) { - results.Add(sortedLists[i].First); + T embedding = embedder.Encode(inputString); + Insert(inputString, embedding); + return embedding; } - return results; - } - public abstract List RetrieveSimilar(string queryString, int k); -} + public T[] Add(string[] inputStrings) + { + T[] inputEmbeddings = new T[inputStrings.Length]; + for (int i = 0; i < inputStrings.Length; i++) + { + inputEmbeddings[i] = Add(inputStrings[i]); + } + return inputEmbeddings; + } -public class ModelSearch : Search -{ - public ModelSearch(EmbeddingModel embedder) : base(embedder) {} + public List GetKNN(string[] inputStrings, float[] scores, int k = -1) + { + var sortedLists = inputStrings.Zip(scores, (first, second) => new { First = first, Second = second }) + .OrderByDescending(item => item.Second) + .ToList(); + List results = new List(); + int kmax = k == -1 ? sortedLists.Count : Math.Min(k, sortedLists.Count); + for (int i = 0; i < kmax; i++) + { + results.Add(sortedLists[i].First); + } + return results; + } - public override void Insert(string inputString, TensorFloat encoding){ - embeddings[inputString] = encoding; + public int Count() + { + return embeddings.Count; + } } - public new TensorFloat[] Add(string[] inputStrings) + public class ModelSearch : Search { - TensorFloat[] inputEmbeddings = (TensorFloat[])embedder.Split(embedder.Encode(inputStrings)); - for (int i = 0; i < inputStrings.Length; i++) + public ModelSearch(EmbeddingModel embedder) : base(embedder) {} + + public override void Insert(string inputString, TensorFloat encoding){ + embeddings[inputString] = encoding; + } + + public new TensorFloat[] Add(string[] inputStrings) + { + TensorFloat[] inputEmbeddings = (TensorFloat[])embedder.Split(embedder.Encode(inputStrings)); + for (int i = 0; i < inputStrings.Length; i++) + { + Insert(inputStrings[i], inputEmbeddings[i]); + } + return inputEmbeddings; + } + + public override List RetrieveSimilar(string queryString, int k) { - Insert(inputStrings[i], inputEmbeddings[i]); + TensorFloat queryEmbedding = embedder.Encode(queryString); + TensorFloat storeEmbedding = embedder.Concat(embeddings.Values.ToArray()); + float[] scores = embedder.SimilarityScores(queryEmbedding, storeEmbedding); + return GetKNN(embeddings.Keys.ToArray(), scores, k); } - return inputEmbeddings; } - public override List RetrieveSimilar(string queryString, int k) + public class ANNModelSearch : ModelSearch { - TensorFloat queryEmbedding = embedder.Encode(queryString); - TensorFloat storeEmbedding = embedder.Concat(embeddings.Values.ToArray()); - float[] scores = embedder.SimilarityScores(queryEmbedding, storeEmbedding); - return GetKNN(embeddings.Keys.ToArray(), scores, k); - } -} + USearchIndex index; + protected Dictionary TextToUSearch; + protected Dictionary USearchToText; + ulong nextKey; + + public ANNModelSearch( + EmbeddingModel embedder, + ulong dimensions, + MetricKind metricKind = MetricKind.Cos, + ulong connectivity = 32, + ulong expansionAdd = 40, + ulong expansionSearch = 16, + bool multi = false + ) : this(embedder, new USearchIndex(dimensions, metricKind, connectivity, expansionAdd, expansionSearch, multi)) {} + + public ANNModelSearch( + EmbeddingModel embedder, + USearchIndex index + ) : base(embedder) { + this.index = index; + TextToUSearch = new Dictionary(); + USearchToText = new Dictionary(); + nextKey = 0; + } -public class ANNModelSearch : ModelSearch -{ - USearchIndex index; - protected Dictionary TextToUSearch; - protected Dictionary USearchToText; - ulong nextKey; - - public ANNModelSearch( - EmbeddingModel embedder, - ulong dimensions, - MetricKind metricKind = MetricKind.Cos, - ulong connectivity = 32, - ulong expansionAdd = 40, - ulong expansionSearch = 16, - bool multi = false - ) : this(embedder, new USearchIndex(dimensions, metricKind, connectivity, expansionAdd, expansionSearch, multi)) {} - - public ANNModelSearch( - EmbeddingModel embedder, - USearchIndex index - ) : base(embedder) { - this.index = index; - TextToUSearch = new Dictionary(); - USearchToText = new Dictionary(); - nextKey = 0; - } + public override void Insert(string inputString, TensorFloat encoding){ + if (TextToUSearch.ContainsKey(inputString)) return; + ulong key = nextKey++; + TextToUSearch[inputString] = key; + USearchToText[key] = inputString; + index.Add(key, encoding.ToReadOnlyArray()); + } - public override void Insert(string inputString, TensorFloat encoding){ - if (TextToUSearch.ContainsKey(inputString)) return; - ulong key = nextKey++; - TextToUSearch[inputString] = key; - USearchToText[key] = inputString; - index.Add(key, encoding.ToReadOnlyArray()); - } + public override List RetrieveSimilar(string queryString, int k) + { + float[] queryEmbedding = embedder.Encode(queryString).ToReadOnlyArray(); + index.Search(queryEmbedding, k, out ulong[] keys, out float[] distances); + List result = new List(); + for(int i=0; i RetrieveSimilar(string queryString, int k) - { - float[] queryEmbedding = embedder.Encode(queryString).ToReadOnlyArray(); - index.Search(queryEmbedding, k, out ulong[] keys, out float[] distances); - List result = new List(); - for(int i=0; i Date: Fri, 2 Feb 2024 16:32:05 +0200 Subject: [PATCH 043/161] add namespace --- Runtime/Embedder.cs | 537 ++++++++++++++++++++++---------------------- 1 file changed, 271 insertions(+), 266 deletions(-) diff --git a/Runtime/Embedder.cs b/Runtime/Embedder.cs index 78329998..d9751a60 100644 --- a/Runtime/Embedder.cs +++ b/Runtime/Embedder.cs @@ -14,328 +14,333 @@ using HuggingFace.SharpTransformers.PostProcessors; using System.IO; - -public abstract class Embedder -{ - public abstract T Encode(string input); -} - -public class EmbeddingModel : Embedder +namespace LLMUnity { - Model runtimeModel; - IWorker worker; - ITensorAllocator allocator; - Ops ops; - JObject tokenizerJsonData; - BertNormalizer bertNorm; - BertPreTokenizer bertPreTok; - WordPieceTokenizer wordPieceTokenizer; - TemplateProcessing templateProcessing; - string outputLayerName; - bool useMeanPooling; - - public EmbeddingModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU, string outputLayerName="last_hidden_state", bool useMeanPooling=true) + public abstract class Embedder { - runtimeModel = ModelLoader.Load(modelPath); - string tokenizerJsonContent = File.ReadAllText(tokenizerPath); - tokenizerJsonData = JsonConvert.DeserializeObject(tokenizerJsonContent); - - worker = WorkerFactory.CreateWorker(BackendType.CPU, runtimeModel); - allocator = new TensorCachingAllocator(); - ops = WorkerFactory.CreateOps(backend, allocator); - - bertNorm = new BertNormalizer(JObject.FromObject(tokenizerJsonData["normalizer"])); - bertPreTok = new BertPreTokenizer(JObject.FromObject(tokenizerJsonData["pre_tokenizer"])); - wordPieceTokenizer = new WordPieceTokenizer(JObject.FromObject(tokenizerJsonData["model"])); - templateProcessing = new TemplateProcessing(JObject.FromObject(tokenizerJsonData["post_processor"])); - this.outputLayerName = outputLayerName; - this.useMeanPooling = useMeanPooling; + public abstract T Encode(string input); } - public void Destroy() + public class EmbeddingModel : Embedder { - allocator.Dispose(); - ops.Dispose(); - worker.Dispose(); - } + Model runtimeModel; + IWorker worker; + ITensorAllocator allocator; + Ops ops; + JObject tokenizerJsonData; + BertNormalizer bertNorm; + BertPreTokenizer bertPreTok; + WordPieceTokenizer wordPieceTokenizer; + TemplateProcessing templateProcessing; + string outputLayerName; + bool useMeanPooling; + + public EmbeddingModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU, string outputLayerName = "last_hidden_state", bool useMeanPooling = true) + { + runtimeModel = ModelLoader.Load(modelPath); + string tokenizerJsonContent = File.ReadAllText(tokenizerPath); + tokenizerJsonData = JsonConvert.DeserializeObject(tokenizerJsonContent); + + worker = WorkerFactory.CreateWorker(BackendType.CPU, runtimeModel); + allocator = new TensorCachingAllocator(); + ops = WorkerFactory.CreateOps(backend, allocator); + + bertNorm = new BertNormalizer(JObject.FromObject(tokenizerJsonData["normalizer"])); + bertPreTok = new BertPreTokenizer(JObject.FromObject(tokenizerJsonData["pre_tokenizer"])); + wordPieceTokenizer = new WordPieceTokenizer(JObject.FromObject(tokenizerJsonData["model"])); + templateProcessing = new TemplateProcessing(JObject.FromObject(tokenizerJsonData["post_processor"])); + this.outputLayerName = outputLayerName; + this.useMeanPooling = useMeanPooling; + } - public Tensor Concat(Tensor[] tensors, int axis = 0) - { - return ops.Concat(tensors, axis); - } + public void Destroy() + { + allocator.Dispose(); + ops.Dispose(); + worker.Dispose(); + } - public TensorFloat Concat(TensorFloat[] tensors, int axis = 0) - { - return (TensorFloat)ops.Concat(tensors, axis); - } + public Tensor Concat(Tensor[] tensors, int axis = 0) + { + return ops.Concat(tensors, axis); + } - public Tensor[] Split(Tensor tensor, int axis = 0) - { - if (tensor.shape.rank != 2) throw new Exception("Tensor does not have a rank of 2."); - TensorFloat[] tensors = new TensorFloat[tensor.shape[0]]; - for (int i = 0; i < tensor.shape[axis]; i++) - tensors[i] = (TensorFloat)ops.Split(tensor, axis, i, i + 1); - return tensors; - } + public TensorFloat Concat(TensorFloat[] tensors, int axis = 0) + { + return (TensorFloat)ops.Concat(tensors, axis); + } - public override TensorFloat Encode(string input) - { - return Encode(new List { input }); - } + public Tensor[] Split(Tensor tensor, int axis = 0) + { + if (tensor.shape.rank != 2) throw new Exception("Tensor does not have a rank of 2."); + TensorFloat[] tensors = new TensorFloat[tensor.shape[0]]; + for (int i = 0; i < tensor.shape[axis]; i++) + tensors[i] = (TensorFloat)ops.Split(tensor, axis, i, i + 1); + return tensors; + } - public TensorFloat Encode(string[] input) - { - return Encode(new List(input)); - } + public override TensorFloat Encode(string input) + { + return Encode(new List { input }); + } - public TensorFloat Encode(List input) - { - // Step 1: Tokenize the sentences - Dictionary inputSentencesTokensTensor = TokenizeInput(input); - // Step 2: Compute embedding and get the output - worker.Execute(inputSentencesTokensTensor); - // Step 3: Get the output from the neural network - TensorFloat outputTensor = worker.PeekOutput(outputLayerName) as TensorFloat; - // Step 4: Perform pooling - TensorFloat MeanPooledTensor = outputTensor; - if (useMeanPooling){ - MeanPooledTensor = MeanPooling(inputSentencesTokensTensor["attention_mask"], outputTensor, ops); + public TensorFloat Encode(string[] input) + { + return Encode(new List(input)); } - // Step 5: Normalize the results - TensorFloat NormedTensor = L2Norm(MeanPooledTensor, ops); - // Cleanup - foreach (var val in inputSentencesTokensTensor.Values) val.Dispose(); - inputSentencesTokensTensor.Clear(); - return NormedTensor; - } - public float[] SimilarityScores(TensorFloat InputSequence, TensorFloat ComparisonSequences) - { - TensorFloat scoresTensor = ops.MatMul2D(InputSequence, ComparisonSequences, false, true); - scoresTensor.MakeReadable(); - int cols = ComparisonSequences.shape[0]; - float[] scores = new float[cols]; - for (int j = 0; j < cols; j++) - scores[j] = scoresTensor[0, j]; - return scores; - } + public TensorFloat Encode(List input) + { + // Step 1: Tokenize the sentences + Dictionary inputSentencesTokensTensor = TokenizeInput(input); + // Step 2: Compute embedding and get the output + worker.Execute(inputSentencesTokensTensor); + // Step 3: Get the output from the neural network + TensorFloat outputTensor = worker.PeekOutput(outputLayerName) as TensorFloat; + // Step 4: Perform pooling + TensorFloat MeanPooledTensor = outputTensor; + if (useMeanPooling) + { + MeanPooledTensor = MeanPooling(inputSentencesTokensTensor["attention_mask"], outputTensor, ops); + } + // Step 5: Normalize the results + TensorFloat NormedTensor = L2Norm(MeanPooledTensor, ops); + // Cleanup + foreach (var val in inputSentencesTokensTensor.Values) val.Dispose(); + inputSentencesTokensTensor.Clear(); + return NormedTensor; + } - public float[][] SimilarityScoresMultiple(TensorFloat InputSequence, TensorFloat ComparisonSequences) - { - TensorFloat scoresTensor = ops.MatMul2D(InputSequence, ComparisonSequences, false, true); - scoresTensor.MakeReadable(); - int rows = InputSequence.shape[0]; - int cols = ComparisonSequences.shape[0]; - float[][] scores = new float[rows][]; - for (int i = 0; i < rows; i++) + public float[] SimilarityScores(TensorFloat InputSequence, TensorFloat ComparisonSequences) { - scores[i] = new float[cols]; + TensorFloat scoresTensor = ops.MatMul2D(InputSequence, ComparisonSequences, false, true); + scoresTensor.MakeReadable(); + int cols = ComparisonSequences.shape[0]; + float[] scores = new float[cols]; for (int j = 0; j < cols; j++) - scores[i][j] = scoresTensor[i, j]; + scores[j] = scoresTensor[0, j]; + return scores; } - return scores; - } - Tuple>, List>, List>> Tokenize(List candidates) - { - List> sentences = new List>(); - List> tokenIds = new List>(); - List> attentionMask = new List>(); - foreach (string text in candidates) + public float[][] SimilarityScoresMultiple(TensorFloat InputSequence, TensorFloat ComparisonSequences) { - // Normalize the sentence - string normalized = bertNorm.Normalize(text); - // Pretokenize the sentence - List pretokenized = bertPreTok.PreTokenize(normalized); - // Tokenize with WordPieceTokenizer - List tokenized = wordPieceTokenizer.Encode(pretokenized); - // Template Process - List processed = templateProcessing.PostProcess(tokenized); - // Tokens to Ids - List ids = wordPieceTokenizer.ConvertTokensToIds(processed); - // Add ids to List> - sentences.Add(ids); + TensorFloat scoresTensor = ops.MatMul2D(InputSequence, ComparisonSequences, false, true); + scoresTensor.MakeReadable(); + int rows = InputSequence.shape[0]; + int cols = ComparisonSequences.shape[0]; + float[][] scores = new float[rows][]; + for (int i = 0; i < rows; i++) + { + scores[i] = new float[cols]; + for (int j = 0; j < cols; j++) + scores[i][j] = scoresTensor[i, j]; + } + return scores; } - int max_length = (int)tokenizerJsonData["truncation"]["max_length"]; - // Tuple>, List>> tuple_ = PaddingOrTruncate(true, true, sentences, max_length, JObject.FromObject(tokenizerJsonData["padding"])); - Tuple>, List>> tuple_ = PaddingOrTruncate(true, true, sentences, max_length); - attentionMask = tuple_.Item1; - tokenIds = tuple_.Item2; + Tuple>, List>, List>> Tokenize(List candidates) + { + List> sentences = new List>(); + List> tokenIds = new List>(); + List> attentionMask = new List>(); + foreach (string text in candidates) + { + // Normalize the sentence + string normalized = bertNorm.Normalize(text); + // Pretokenize the sentence + List pretokenized = bertPreTok.PreTokenize(normalized); + // Tokenize with WordPieceTokenizer + List tokenized = wordPieceTokenizer.Encode(pretokenized); + // Template Process + List processed = templateProcessing.PostProcess(tokenized); + // Tokens to Ids + List ids = wordPieceTokenizer.ConvertTokensToIds(processed); + // Add ids to List> + sentences.Add(ids); + } - List> TokenTypeIds = new List>(); - TokenTypeIds = AddTokenTypes(tokenIds); - return Tuple.Create(tokenIds, attentionMask, TokenTypeIds); - } + int max_length = (int)tokenizerJsonData["truncation"]["max_length"]; + // Tuple>, List>> tuple_ = PaddingOrTruncate(true, true, sentences, max_length, JObject.FromObject(tokenizerJsonData["padding"])); + Tuple>, List>> tuple_ = PaddingOrTruncate(true, true, sentences, max_length); + attentionMask = tuple_.Item1; + tokenIds = tuple_.Item2; - public static TensorFloat MeanPooling(Tensor AttentionMaskTensor, TensorFloat outputTensor, Ops ops) - { - if (AttentionMaskTensor == null || outputTensor == null) - { - Debug.LogError("AttentionMaskTensor or outputTensor is null."); + List> TokenTypeIds = new List>(); + TokenTypeIds = AddTokenTypes(tokenIds); + return Tuple.Create(tokenIds, attentionMask, TokenTypeIds); } - // Create an attention mask and - // add a new dimension (to make the mask compatible for element wise multiplication with token embeddings) - TensorFloat AttentionMaskTensorFloat = ops.Cast(AttentionMaskTensor, DataType.Float) as TensorFloat; - Tensor InputMaskExpanded = AttentionMaskTensorFloat.ShallowReshape(AttentionMaskTensorFloat.shape.Unsqueeze(-1)); - TensorFloat InputMaskExpandedFloat = ops.Cast(InputMaskExpanded, DataType.Float) as TensorFloat; - - TensorShape outputShape = outputTensor.shape; - // Expand to 384 => [2, 6, 384] - InputMaskExpandedFloat = ops.Expand(InputMaskExpandedFloat, outputShape) as TensorFloat; - // torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(input_mask_expanded.sum(1), min=1e-9) - TensorFloat temp_ = ops.Mul(outputTensor, InputMaskExpandedFloat); - TensorFloat MeanPooledTensor = ops.ReduceMean(temp_, new int[] { 1 }, false); + public static TensorFloat MeanPooling(Tensor AttentionMaskTensor, TensorFloat outputTensor, Ops ops) + { + if (AttentionMaskTensor == null || outputTensor == null) + { + Debug.LogError("AttentionMaskTensor or outputTensor is null."); + } - return MeanPooledTensor; - } + // Create an attention mask and + // add a new dimension (to make the mask compatible for element wise multiplication with token embeddings) + TensorFloat AttentionMaskTensorFloat = ops.Cast(AttentionMaskTensor, DataType.Float) as TensorFloat; + Tensor InputMaskExpanded = AttentionMaskTensorFloat.ShallowReshape(AttentionMaskTensorFloat.shape.Unsqueeze(-1)); + TensorFloat InputMaskExpandedFloat = ops.Cast(InputMaskExpanded, DataType.Float) as TensorFloat; - public static TensorFloat L2Norm(TensorFloat MeanPooledTensor, Ops ops) - { - // L2 NORMALIZATION - // Compute L2 norm along axis 1 (dim=1) - TensorFloat l2Norms = ops.ReduceL2(MeanPooledTensor, new int[] { 1 }, true); - // Broadcast the L2 norms to the original shape - TensorFloat l2NormsBroadcasted = ops.Expand(l2Norms, MeanPooledTensor.shape) as TensorFloat; - // Divide sentence_embeddings by their L2 norms to achieve normalization - TensorFloat NormalizedEmbeddings = ops.Div(MeanPooledTensor, l2NormsBroadcasted); - return NormalizedEmbeddings; - } + TensorShape outputShape = outputTensor.shape; + // Expand to 384 => [2, 6, 384] + InputMaskExpandedFloat = ops.Expand(InputMaskExpandedFloat, outputShape) as TensorFloat; + // torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(input_mask_expanded.sum(1), min=1e-9) + TensorFloat temp_ = ops.Mul(outputTensor, InputMaskExpandedFloat); + TensorFloat MeanPooledTensor = ops.ReduceMean(temp_, new int[] { 1 }, false); - public Dictionary TokenizeInput(List sentences) - { - List> TokenIds = new List>(); - List> AttentionMask = new List>(); - List> TokenTypeIds = new List>(); - - Tuple>, List>, List>> FinalTuple = Tokenize(sentences); - TokenIds = FinalTuple.Item1; - AttentionMask = FinalTuple.Item2; - TokenTypeIds = FinalTuple.Item3; - - // Flatten the nested list into a one-dimensional array - List flattenedData = new List(); - foreach (var innerList in TokenIds) - { - flattenedData.AddRange(innerList); + return MeanPooledTensor; } - int[] data = flattenedData.ToArray(); - // Create a 3D tensor shape - TensorShape shape = new TensorShape(TokenIds.Count, TokenIds[0].Count); - // Create a new tensor from the array - TensorInt TokenIdsTensor = new TensorInt(shape, data); - // Flatten the nested list into a one-dimensional array - List flattenedData2 = new List(); - foreach (var innerList in AttentionMask) + + public static TensorFloat L2Norm(TensorFloat MeanPooledTensor, Ops ops) { - flattenedData2.AddRange(innerList); + // L2 NORMALIZATION + // Compute L2 norm along axis 1 (dim=1) + TensorFloat l2Norms = ops.ReduceL2(MeanPooledTensor, new int[] { 1 }, true); + // Broadcast the L2 norms to the original shape + TensorFloat l2NormsBroadcasted = ops.Expand(l2Norms, MeanPooledTensor.shape) as TensorFloat; + // Divide sentence_embeddings by their L2 norms to achieve normalization + TensorFloat NormalizedEmbeddings = ops.Div(MeanPooledTensor, l2NormsBroadcasted); + return NormalizedEmbeddings; } - int[] data2 = flattenedData2.ToArray(); - // Create a 3D tensor shape - TensorShape shape2 = new TensorShape(AttentionMask.Count, AttentionMask[0].Count); - // Create a new tensor from the array - TensorInt AttentionMaskTensor = new TensorInt(shape2, data2); - // Flatten the nested list into a one-dimensional array - List flattenedData3 = new List(); - foreach (var innerList in TokenTypeIds) + + public Dictionary TokenizeInput(List sentences) { - flattenedData3.AddRange(innerList); + List> TokenIds = new List>(); + List> AttentionMask = new List>(); + List> TokenTypeIds = new List>(); + + Tuple>, List>, List>> FinalTuple = Tokenize(sentences); + TokenIds = FinalTuple.Item1; + AttentionMask = FinalTuple.Item2; + TokenTypeIds = FinalTuple.Item3; + + // Flatten the nested list into a one-dimensional array + List flattenedData = new List(); + foreach (var innerList in TokenIds) + { + flattenedData.AddRange(innerList); + } + int[] data = flattenedData.ToArray(); + // Create a 3D tensor shape + TensorShape shape = new TensorShape(TokenIds.Count, TokenIds[0].Count); + // Create a new tensor from the array + TensorInt TokenIdsTensor = new TensorInt(shape, data); + // Flatten the nested list into a one-dimensional array + List flattenedData2 = new List(); + foreach (var innerList in AttentionMask) + { + flattenedData2.AddRange(innerList); + } + int[] data2 = flattenedData2.ToArray(); + // Create a 3D tensor shape + TensorShape shape2 = new TensorShape(AttentionMask.Count, AttentionMask[0].Count); + // Create a new tensor from the array + TensorInt AttentionMaskTensor = new TensorInt(shape2, data2); + // Flatten the nested list into a one-dimensional array + List flattenedData3 = new List(); + foreach (var innerList in TokenTypeIds) + { + flattenedData3.AddRange(innerList); + } + int[] data3 = flattenedData3.ToArray(); + // Create a 3D tensor shape + TensorShape shape3 = new TensorShape(TokenTypeIds.Count, TokenTypeIds[0].Count); + // Create a new tensor from the array + TensorInt TokenTypeIdsTensor = new TensorInt(shape3, data3); + Dictionary inputTensors = new Dictionary() + { + { "input_ids", TokenIdsTensor }, + {"token_type_ids", TokenTypeIdsTensor }, + { "attention_mask", AttentionMaskTensor } + }; + return inputTensors; } - int[] data3 = flattenedData3.ToArray(); - // Create a 3D tensor shape - TensorShape shape3 = new TensorShape(TokenTypeIds.Count, TokenTypeIds[0].Count); - // Create a new tensor from the array - TensorInt TokenTypeIdsTensor = new TensorInt(shape3, data3); - Dictionary inputTensors = new Dictionary() - { - { "input_ids", TokenIdsTensor }, - {"token_type_ids", TokenTypeIdsTensor }, - { "attention_mask", AttentionMaskTensor } - }; - return inputTensors; - } - static Tuple>, List>> PaddingOrTruncate(bool padding, bool truncation, List> tokens, int max_length) - { - // TODO allow user to change - string padding_side = "right"; - int pad_token_id = 0; // TODO Change (int)config["pad_token"] - List> attentionMask = new List>(); - int maxLengthOfBatch = tokens.Max(x => x.Count); - max_length = maxLengthOfBatch; - - // TODO Check the logic - /*if (max_length == null) + static Tuple>, List>> PaddingOrTruncate(bool padding, bool truncation, List> tokens, int max_length) { + // TODO allow user to change + string padding_side = "right"; + int pad_token_id = 0; // TODO Change (int)config["pad_token"] + List> attentionMask = new List>(); + int maxLengthOfBatch = tokens.Max(x => x.Count); max_length = maxLengthOfBatch; - } - max_length = Math.Min(max_length.Value, model_max_length);*/ - if (padding || truncation) - { - for (int i = 0; i < tokens.Count; ++i) + // TODO Check the logic + /*if (max_length == null) { - if (tokens[i].Count == max_length) - { - attentionMask.Add(Enumerable.Repeat(1, tokens[i].Count).ToList()); - continue; - } - else if (tokens[i].Count > max_length) + max_length = maxLengthOfBatch; + } + max_length = Math.Min(max_length.Value, model_max_length);*/ + + if (padding || truncation) + { + for (int i = 0; i < tokens.Count; ++i) { - if (truncation) + if (tokens[i].Count == max_length) { - tokens[i] = tokens[i].Take(max_length).ToList(); + attentionMask.Add(Enumerable.Repeat(1, tokens[i].Count).ToList()); + continue; } - attentionMask.Add(Enumerable.Repeat(1, tokens[i].Count).ToList()); - } - else - { - if (padding) + else if (tokens[i].Count > max_length) { - int diff = max_length - tokens[i].Count; - - if (padding_side == "right") - { - attentionMask.Add(Enumerable.Repeat(1, tokens[i].Count) - .Concat(Enumerable.Repeat(0, diff)).ToList()); - tokens[i].AddRange(Enumerable.Repeat(pad_token_id, diff)); - } - else + if (truncation) { - attentionMask.Add(Enumerable.Repeat(0, diff) - .Concat(Enumerable.Repeat(1, tokens[i].Count)).ToList()); - tokens[i].InsertRange(0, Enumerable.Repeat(pad_token_id, diff)); + tokens[i] = tokens[i].Take(max_length).ToList(); } + attentionMask.Add(Enumerable.Repeat(1, tokens[i].Count).ToList()); } else { - attentionMask.Add(Enumerable.Repeat(1, tokens[i].Count).ToList()); + if (padding) + { + int diff = max_length - tokens[i].Count; + + if (padding_side == "right") + { + attentionMask.Add(Enumerable.Repeat(1, tokens[i].Count) + .Concat(Enumerable.Repeat(0, diff)).ToList()); + tokens[i].AddRange(Enumerable.Repeat(pad_token_id, diff)); + } + else + { + attentionMask.Add(Enumerable.Repeat(0, diff) + .Concat(Enumerable.Repeat(1, tokens[i].Count)).ToList()); + tokens[i].InsertRange(0, Enumerable.Repeat(pad_token_id, diff)); + } + } + else + { + attentionMask.Add(Enumerable.Repeat(1, tokens[i].Count).ToList()); + } } } } + else + { + attentionMask = tokens.Select(x => Enumerable.Repeat(1, x.Count).ToList()).ToList(); + } + return Tuple.Create(attentionMask, tokens); } - else + + static List> AddTokenTypes(List> inputIds) { - attentionMask = tokens.Select(x => Enumerable.Repeat(1, x.Count).ToList()).ToList(); + return inputIds.Select(innerList => innerList.Select(_ => 0).ToList()).ToList(); } - return Tuple.Create(attentionMask, tokens); } - static List> AddTokenTypes(List> inputIds) + public class BGEModel : EmbeddingModel { - return inputIds.Select(innerList => innerList.Select(_ => 0).ToList()).ToList(); + public BGEModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU) : + base(modelPath, tokenizerPath, backend, "sentence_embedding", false) + {} } -} -public class BGEModel: EmbeddingModel -{ - public BGEModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU): - base(modelPath, tokenizerPath, backend, "sentence_embedding", false){} + public class MiniLMModel : EmbeddingModel + { + public MiniLMModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU) : + base(modelPath, tokenizerPath, backend, "last_hidden_state", true) + {} + } } - -public class MiniLMModel: EmbeddingModel -{ - public MiniLMModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU): - base(modelPath, tokenizerPath, backend, "last_hidden_state", true){} -} \ No newline at end of file From 676bbb75104248735c23d0aadf27ac8d05044fb9 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 2 Feb 2024 16:32:34 +0200 Subject: [PATCH 044/161] basic dialogue class --- Runtime/Dialogue.cs | 104 +++++++++++++++++++++++++++++++++++++++ Runtime/Dialogue.cs.meta | 11 +++++ 2 files changed, 115 insertions(+) create mode 100644 Runtime/Dialogue.cs create mode 100644 Runtime/Dialogue.cs.meta diff --git a/Runtime/Dialogue.cs b/Runtime/Dialogue.cs new file mode 100644 index 00000000..fcaf0957 --- /dev/null +++ b/Runtime/Dialogue.cs @@ -0,0 +1,104 @@ +using System.Collections.Generic; +using System; +using System.Linq; + +namespace LLMUnity +{ + public class Dialogue + { + public string Title { get; private set; } + + char[] delimiters; + Dictionary sentences; + Dictionary phrases; + Dictionary> characterPhrases; + Dictionary> phraseSentences; + Dictionary sentencePhrase; + int nextSentenceId; + int nextPhraseId; + + public Dialogue(string title = "") + { + Title = title; + sentences = new Dictionary(); + phrases = new Dictionary(); + characterPhrases = new Dictionary>(); + phraseSentences = new Dictionary>(); + sentencePhrase = new Dictionary(); + nextSentenceId = 0; + nextPhraseId = 0; + SetDelimiters(new char[] { '.', '!', ':', ';', '?', '\n', '\r', }); + } + + public void SetDelimiters(char[] delimiters) + { + this.delimiters = delimiters; + } + + public static void Add(Dictionary> dict, K key, V value) + { + if (!dict.ContainsKey(key)) + { + dict[key] = new List(); + } + dict[key].Add(value); + } + + int AddSentence(int phraseId, string sentence) + { + int sentenceId = nextSentenceId++; + sentences[sentenceId] = sentence; + sentencePhrase[sentenceId] = phraseId; + return sentenceId; + } + + public void AddPhrase(string name, string phrase) + { + int phraseId = nextPhraseId++; + phrases[phraseId] = phrase; + string[] sentences = phrase.Split(delimiters, StringSplitOptions.RemoveEmptyEntries); + for (int i = 0; i < sentences.Length; i++) + { + string sentence = sentences[i].Trim(); + int sentenceId = AddSentence(phraseId, sentence); + Add(phraseSentences, phraseId, sentenceId); + } + Add(characterPhrases, name, phraseId); + } + + public List GetCharacterPhrases(string name) + { + if (!characterPhrases.ContainsKey(name)) + { + return null; + } + List result = new List(); + foreach (int phraseId in characterPhrases[name]) + { + result.Add(phrases[phraseId]); + } + return result; + } + + public List GetCharacterSentences(string name) + { + if (!characterPhrases.ContainsKey(name)) + { + return null; + } + List result = new List(); + foreach (int phraseId in characterPhrases[name]) + { + foreach (int sentenceId in phraseSentences[phraseId]) + { + result.Add(sentences[sentenceId]); + } + } + return result; + } + public List GetSentences() + { + return sentences.Values.ToList(); + } + } +} diff --git a/Runtime/Dialogue.cs.meta b/Runtime/Dialogue.cs.meta new file mode 100644 index 00000000..5adb2f3d --- /dev/null +++ b/Runtime/Dialogue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ab22d17a835f69af0bb5c3e6544b1f45 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 50f0dcfb6e2c39b1dca08db44e810063229b61fe Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 2 Feb 2024 17:37:23 +0200 Subject: [PATCH 045/161] add dimensions in the embedding model --- Runtime/Embedder.cs | 8 +++++--- Runtime/Search.cs | 3 +-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Runtime/Embedder.cs b/Runtime/Embedder.cs index d9751a60..2fb41212 100644 --- a/Runtime/Embedder.cs +++ b/Runtime/Embedder.cs @@ -34,8 +34,9 @@ public class EmbeddingModel : Embedder TemplateProcessing templateProcessing; string outputLayerName; bool useMeanPooling; + public int Dimensions { get; private set; } - public EmbeddingModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU, string outputLayerName = "last_hidden_state", bool useMeanPooling = true) + public EmbeddingModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU, string outputLayerName = "last_hidden_state", bool useMeanPooling = true, int dimensions=384) { runtimeModel = ModelLoader.Load(modelPath); string tokenizerJsonContent = File.ReadAllText(tokenizerPath); @@ -51,6 +52,7 @@ public EmbeddingModel(string modelPath, string tokenizerPath, BackendType backen templateProcessing = new TemplateProcessing(JObject.FromObject(tokenizerJsonData["post_processor"])); this.outputLayerName = outputLayerName; this.useMeanPooling = useMeanPooling; + Dimensions = dimensions; } public void Destroy() @@ -333,14 +335,14 @@ static List> AddTokenTypes(List> inputIds) public class BGEModel : EmbeddingModel { public BGEModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU) : - base(modelPath, tokenizerPath, backend, "sentence_embedding", false) + base(modelPath, tokenizerPath, backend, "sentence_embedding", false, 384) {} } public class MiniLMModel : EmbeddingModel { public MiniLMModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU) : - base(modelPath, tokenizerPath, backend, "last_hidden_state", true) + base(modelPath, tokenizerPath, backend, "last_hidden_state", true, 384) {} } } diff --git a/Runtime/Search.cs b/Runtime/Search.cs index 7740804a..a430f02b 100644 --- a/Runtime/Search.cs +++ b/Runtime/Search.cs @@ -94,13 +94,12 @@ public class ANNModelSearch : ModelSearch public ANNModelSearch( EmbeddingModel embedder, - ulong dimensions, MetricKind metricKind = MetricKind.Cos, ulong connectivity = 32, ulong expansionAdd = 40, ulong expansionSearch = 16, bool multi = false - ) : this(embedder, new USearchIndex(dimensions, metricKind, connectivity, expansionAdd, expansionSearch, multi)) {} + ) : this(embedder, new USearchIndex((ulong) embedder.Dimensions, metricKind, connectivity, expansionAdd, expansionSearch, multi)) {} public ANNModelSearch( EmbeddingModel embedder, From 5a5957a4bdced71c901ea78ff2d737afff064747 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 2 Feb 2024 17:39:32 +0200 Subject: [PATCH 046/161] add Hamlet search sample --- Samples~/HamletSearch.meta | 8 + Samples~/HamletSearch/HamletSearch.cs | 113 + Samples~/HamletSearch/HamletSearch.cs.meta | 11 + Samples~/HamletSearch/Scene.unity | 364 + Samples~/HamletSearch/Scene.unity.meta | 7 + .../HamletSearch/hamlet_project_gutenberg.txt | 7085 +++++++++++++++++ .../hamlet_project_gutenberg.txt.meta | 7 + 7 files changed, 7595 insertions(+) create mode 100644 Samples~/HamletSearch.meta create mode 100644 Samples~/HamletSearch/HamletSearch.cs create mode 100644 Samples~/HamletSearch/HamletSearch.cs.meta create mode 100644 Samples~/HamletSearch/Scene.unity create mode 100644 Samples~/HamletSearch/Scene.unity.meta create mode 100644 Samples~/HamletSearch/hamlet_project_gutenberg.txt create mode 100644 Samples~/HamletSearch/hamlet_project_gutenberg.txt.meta diff --git a/Samples~/HamletSearch.meta b/Samples~/HamletSearch.meta new file mode 100644 index 00000000..70471888 --- /dev/null +++ b/Samples~/HamletSearch.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3c278e343da0969a8a8b587005df198c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/HamletSearch/HamletSearch.cs b/Samples~/HamletSearch/HamletSearch.cs new file mode 100644 index 00000000..52162f8e --- /dev/null +++ b/Samples~/HamletSearch/HamletSearch.cs @@ -0,0 +1,113 @@ +using System.Collections.Generic; +using UnityEngine; +using System.Diagnostics; +using Debug = UnityEngine.Debug; +using System.Text.RegularExpressions; +using LLMUnity; + +class HamletSearch : MonoBehaviour +{ + EmbeddingModel embedder; + ANNModelSearch search; + public bool fullPlay; + public TextAsset gutenbergText; + + public void OnEnable() + { + embedder = new BGEModel("Assets/StreamingAssets/bge-small-en-v1.5.sentis", "Assets/StreamingAssets/bge-small-en-v1.5.tokenizer.json"); + } + + void Start() + { + List dialogues = ReadGutenbergFile(gutenbergText.text); + search = new ANNModelSearch(embedder); + + Stopwatch stopwatch = new Stopwatch(); + float elapsed_total = 0; + + List dialoguesToDo = fullPlay ? dialogues : new List { dialogues[2] }; + foreach (Dialogue dialogue in dialoguesToDo) + { + stopwatch.Reset(); stopwatch.Start(); + search.Add(dialogue.GetSentences().ToArray()); + stopwatch.Stop(); + + float elapsed = (float)stopwatch.Elapsed.TotalMilliseconds / 1000f; + Debug.Log($"{dialogue.Title} embed time: {elapsed} secs"); + elapsed_total += elapsed; + } + Debug.Log($"embedded {search.Count()} sentences in {elapsed_total} secs"); + + stopwatch.Reset(); stopwatch.Start(); + List similar = search.RetrieveSimilar("should i exist?", 5); + stopwatch.Stop(); + Debug.Log($"search time: {stopwatch.Elapsed.TotalMilliseconds / 1000f} secs"); + + Debug.Log("Similar sentences:"); + for (int i = 0; i < similar.Count; i++) + { + Debug.Log($" {i + 1}: {similar[i]}"); + } + } + + public List ReadGutenbergFile(string text) + { + List dialogues = new List(); + string skipPattern = @"\[.*?\]"; + string namePattern = "^[A-Z and]+\\.$"; + Regex nameRegex = new Regex(namePattern); + + string act = null; + string name = null; + string message = ""; + bool add = false; + Dialogue dialogue = null; + + string[] lines = text.Split("\n"); + for (int i = 0; i < lines.Length; i++) + { + string line = lines[i]; + + if (line.Contains("***")) add = !add; + if (!add) continue; + + line = line.Replace("\r", ""); + line = Regex.Replace(line, skipPattern, ""); + if (line == "") continue; + + if (line.StartsWith("ACT")) + { + if (dialogue != null && message != "") + { + dialogue.AddPhrase(name, message); + } + act = line.Replace(".", ""); + dialogue = new Dialogue(act); + dialogues.Add(dialogue); + name = null; + message = ""; + } + else if (nameRegex.IsMatch(line)) + { + if (name != null && message != "") + { + dialogue.AddPhrase(name, message); + } + message = ""; + name = line.Replace(".", ""); + } + else if (name != null) + { + if (message != "") message += " "; + message += line; + } + + } + return dialogues; + } + + public void OnDisable() + { + embedder.Destroy(); + } +} diff --git a/Samples~/HamletSearch/HamletSearch.cs.meta b/Samples~/HamletSearch/HamletSearch.cs.meta new file mode 100644 index 00000000..965e28e5 --- /dev/null +++ b/Samples~/HamletSearch/HamletSearch.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8813eb3f4b7c900538f904cbd42e0a7f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/HamletSearch/Scene.unity b/Samples~/HamletSearch/Scene.unity new file mode 100644 index 00000000..25a1e1ef --- /dev/null +++ b/Samples~/HamletSearch/Scene.unity @@ -0,0 +1,364 @@ +%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: 705507994} + 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: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + 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 &705507993 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 705507995} + - component: {fileID: 705507994} + 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 &705507994 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 705507993} + 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: 1 + 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 &705507995 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 705507993} + 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 &963194225 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 963194228} + - component: {fileID: 963194227} + - component: {fileID: 963194226} + 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 &963194226 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 +--- !u!20 &963194227 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + 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 &963194228 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + 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 &1842083044 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1842083046} + - component: {fileID: 1842083045} + m_Layer: 0 + m_Name: HamletSearch + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1842083045 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1842083044} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8813eb3f4b7c900538f904cbd42e0a7f, type: 3} + m_Name: + m_EditorClassIdentifier: + fullPlay: 0 + gutenbergText: {fileID: 4900000, guid: be0ffe8c7b44139218ffd530749f1644, type: 3} +--- !u!4 &1842083046 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1842083044} + 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!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 963194228} + - {fileID: 705507995} + - {fileID: 1842083046} diff --git a/Samples~/HamletSearch/Scene.unity.meta b/Samples~/HamletSearch/Scene.unity.meta new file mode 100644 index 00000000..b9ebd2dd --- /dev/null +++ b/Samples~/HamletSearch/Scene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 13f79d4da7ad9cd7bac548564f7e63d6 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/HamletSearch/hamlet_project_gutenberg.txt b/Samples~/HamletSearch/hamlet_project_gutenberg.txt new file mode 100644 index 00000000..e9d06d7e --- /dev/null +++ b/Samples~/HamletSearch/hamlet_project_gutenberg.txt @@ -0,0 +1,7085 @@ +The Project Gutenberg eBook of Hamlet, Prince of Denmark + +This ebook is for the use of anyone anywhere in the United States and +most other parts of the world at no cost and with almost no restrictions +whatsoever. You may copy it, give it away or re-use it under the terms +of the Project Gutenberg License included with this ebook or online +at www.gutenberg.org. If you are not located in the United States, +you will have to check the laws of the country where you are located +before using this eBook. + +Title: Hamlet, Prince of Denmark + + +Author: William Shakespeare + +Release date: November 1, 1998 [eBook #1524] + Most recently updated: November 11, 2023 + +Language: English + + + +*** START OF THE PROJECT GUTENBERG EBOOK HAMLET, PRINCE OF DENMARK *** + + + + +cover + + + + +THE TRAGEDY OF HAMLET, PRINCE OF DENMARK + +by William Shakespeare + + + + +Contents + + ACT I + Scene I. Elsinore. A platform before the Castle + Scene II. Elsinore. A room of state in the Castle + Scene III. A room in Polonius’s house + Scene IV. The platform + Scene V. A more remote part of the Castle + + ACT II + Scene I. A room in Polonius’s house + Scene II. A room in the Castle + + ACT III + Scene I. A room in the Castle + Scene II. A hall in the Castle + Scene III. A room in the Castle + Scene IV. Another room in the Castle + + ACT IV + Scene I. A room in the Castle + Scene II. Another room in the Castle + Scene III. Another room in the Castle + Scene IV. A plain in Denmark + Scene V. Elsinore. A room in the Castle + Scene VI. Another room in the Castle + Scene VII. Another room in the Castle + + ACT V + Scene I. A churchyard + Scene II. A hall in the Castle + + + + +Dramatis Personæ + +HAMLET, Prince of Denmark +CLAUDIUS, King of Denmark, Hamlet’s uncle +The GHOST of the late king, Hamlet’s father +GERTRUDE, the Queen, Hamlet’s mother, now wife of Claudius +POLONIUS, Lord Chamberlain +LAERTES, Son to Polonius +OPHELIA, Daughter to Polonius +HORATIO, Friend to Hamlet +FORTINBRAS, Prince of Norway +VOLTEMAND, Courtier +CORNELIUS, Courtier +ROSENCRANTZ, Courtier +GUILDENSTERN, Courtier +MARCELLUS, Officer +BARNARDO, Officer +FRANCISCO, a Soldier +OSRIC, Courtier +REYNALDO, Servant to Polonius +Players +A Gentleman, Courtier +A Priest +Two Clowns, Grave-diggers +A Captain +English Ambassadors. +Lords, Ladies, Officers, Soldiers, Sailors, Messengers, and Attendants + +SCENE. Elsinore. + + + + +ACT I + +SCENE I. Elsinore. A platform before the Castle. + + +Enter Francisco and Barnardo, two sentinels. + +BARNARDO. +Who’s there? + +FRANCISCO. +Nay, answer me. Stand and unfold yourself. + +BARNARDO. +Long live the King! + +FRANCISCO. +Barnardo? + +BARNARDO. +He. + +FRANCISCO. +You come most carefully upon your hour. + +BARNARDO. +’Tis now struck twelve. Get thee to bed, Francisco. + +FRANCISCO. +For this relief much thanks. ’Tis bitter cold, +And I am sick at heart. + +BARNARDO. +Have you had quiet guard? + +FRANCISCO. +Not a mouse stirring. + +BARNARDO. +Well, good night. +If you do meet Horatio and Marcellus, +The rivals of my watch, bid them make haste. + +Enter Horatio and Marcellus. + +FRANCISCO. +I think I hear them. Stand, ho! Who is there? + +HORATIO. +Friends to this ground. + +MARCELLUS. +And liegemen to the Dane. + +FRANCISCO. +Give you good night. + +MARCELLUS. +O, farewell, honest soldier, who hath reliev’d you? + +FRANCISCO. +Barnardo has my place. Give you good-night. + +[_Exit._] + +MARCELLUS. +Holla, Barnardo! + +BARNARDO. +Say, what, is Horatio there? + +HORATIO. +A piece of him. + +BARNARDO. +Welcome, Horatio. Welcome, good Marcellus. + +MARCELLUS. +What, has this thing appear’d again tonight? + +BARNARDO. +I have seen nothing. + +MARCELLUS. +Horatio says ’tis but our fantasy, +And will not let belief take hold of him +Touching this dreaded sight, twice seen of us. +Therefore I have entreated him along +With us to watch the minutes of this night, +That if again this apparition come +He may approve our eyes and speak to it. + +HORATIO. +Tush, tush, ’twill not appear. + +BARNARDO. +Sit down awhile, +And let us once again assail your ears, +That are so fortified against our story, +What we two nights have seen. + +HORATIO. +Well, sit we down, +And let us hear Barnardo speak of this. + +BARNARDO. +Last night of all, +When yond same star that’s westward from the pole, +Had made his course t’illume that part of heaven +Where now it burns, Marcellus and myself, +The bell then beating one— + +MARCELLUS. +Peace, break thee off. Look where it comes again. + +Enter Ghost. + +BARNARDO. +In the same figure, like the King that’s dead. + +MARCELLUS. +Thou art a scholar; speak to it, Horatio. + +BARNARDO. +Looks it not like the King? Mark it, Horatio. + +HORATIO. +Most like. It harrows me with fear and wonder. + +BARNARDO +It would be spoke to. + +MARCELLUS. +Question it, Horatio. + +HORATIO. +What art thou that usurp’st this time of night, +Together with that fair and warlike form +In which the majesty of buried Denmark +Did sometimes march? By heaven I charge thee speak. + +MARCELLUS. +It is offended. + +BARNARDO. +See, it stalks away. + +HORATIO. +Stay! speak, speak! I charge thee speak! + +[_Exit Ghost._] + +MARCELLUS. +’Tis gone, and will not answer. + +BARNARDO. +How now, Horatio! You tremble and look pale. +Is not this something more than fantasy? +What think you on’t? + +HORATIO. +Before my God, I might not this believe +Without the sensible and true avouch +Of mine own eyes. + +MARCELLUS. +Is it not like the King? + +HORATIO. +As thou art to thyself: +Such was the very armour he had on +When he th’ambitious Norway combated; +So frown’d he once, when in an angry parle +He smote the sledded Polacks on the ice. +’Tis strange. + +MARCELLUS. +Thus twice before, and jump at this dead hour, +With martial stalk hath he gone by our watch. + +HORATIO. +In what particular thought to work I know not; +But in the gross and scope of my opinion, +This bodes some strange eruption to our state. + +MARCELLUS. +Good now, sit down, and tell me, he that knows, +Why this same strict and most observant watch +So nightly toils the subject of the land, +And why such daily cast of brazen cannon +And foreign mart for implements of war; +Why such impress of shipwrights, whose sore task +Does not divide the Sunday from the week. +What might be toward, that this sweaty haste +Doth make the night joint-labourer with the day: +Who is’t that can inform me? + +HORATIO. +That can I; +At least, the whisper goes so. Our last King, +Whose image even but now appear’d to us, +Was, as you know, by Fortinbras of Norway, +Thereto prick’d on by a most emulate pride, +Dar’d to the combat; in which our valiant Hamlet, +For so this side of our known world esteem’d him, +Did slay this Fortinbras; who by a seal’d compact, +Well ratified by law and heraldry, +Did forfeit, with his life, all those his lands +Which he stood seiz’d of, to the conqueror; +Against the which, a moiety competent +Was gaged by our King; which had return’d +To the inheritance of Fortinbras, +Had he been vanquisher; as by the same cov’nant +And carriage of the article design’d, +His fell to Hamlet. Now, sir, young Fortinbras, +Of unimproved mettle, hot and full, +Hath in the skirts of Norway, here and there, +Shark’d up a list of lawless resolutes, +For food and diet, to some enterprise +That hath a stomach in’t; which is no other, +As it doth well appear unto our state, +But to recover of us by strong hand +And terms compulsatory, those foresaid lands +So by his father lost. And this, I take it, +Is the main motive of our preparations, +The source of this our watch, and the chief head +Of this post-haste and rummage in the land. + +BARNARDO. +I think it be no other but e’en so: +Well may it sort that this portentous figure +Comes armed through our watch so like the King +That was and is the question of these wars. + +HORATIO. +A mote it is to trouble the mind’s eye. +In the most high and palmy state of Rome, +A little ere the mightiest Julius fell, +The graves stood tenantless and the sheeted dead +Did squeak and gibber in the Roman streets; +As stars with trains of fire and dews of blood, +Disasters in the sun; and the moist star, +Upon whose influence Neptune’s empire stands, +Was sick almost to doomsday with eclipse. +And even the like precurse of fierce events, +As harbingers preceding still the fates +And prologue to the omen coming on, +Have heaven and earth together demonstrated +Unto our climatures and countrymen. + +Re-enter Ghost. + +But, soft, behold! Lo, where it comes again! +I’ll cross it, though it blast me. Stay, illusion! +If thou hast any sound, or use of voice, +Speak to me. +If there be any good thing to be done, +That may to thee do ease, and grace to me, +Speak to me. +If thou art privy to thy country’s fate, +Which, happily, foreknowing may avoid, +O speak! +Or if thou hast uphoarded in thy life +Extorted treasure in the womb of earth, +For which, they say, you spirits oft walk in death, +Speak of it. Stay, and speak! + +[_The cock crows._] + +Stop it, Marcellus! + +MARCELLUS. +Shall I strike at it with my partisan? + +HORATIO. +Do, if it will not stand. + +BARNARDO. +’Tis here! + +HORATIO. +’Tis here! + +[_Exit Ghost._] + +MARCELLUS. +’Tis gone! +We do it wrong, being so majestical, +To offer it the show of violence, +For it is as the air, invulnerable, +And our vain blows malicious mockery. + +BARNARDO. +It was about to speak, when the cock crew. + +HORATIO. +And then it started, like a guilty thing +Upon a fearful summons. I have heard +The cock, that is the trumpet to the morn, +Doth with his lofty and shrill-sounding throat +Awake the god of day; and at his warning, +Whether in sea or fire, in earth or air, +Th’extravagant and erring spirit hies +To his confine. And of the truth herein +This present object made probation. + +MARCELLUS. +It faded on the crowing of the cock. +Some say that ever ’gainst that season comes +Wherein our Saviour’s birth is celebrated, +The bird of dawning singeth all night long; +And then, they say, no spirit dare stir abroad, +The nights are wholesome, then no planets strike, +No fairy takes, nor witch hath power to charm; +So hallow’d and so gracious is the time. + +HORATIO. +So have I heard, and do in part believe it. +But look, the morn in russet mantle clad, +Walks o’er the dew of yon high eastward hill. +Break we our watch up, and by my advice, +Let us impart what we have seen tonight +Unto young Hamlet; for upon my life, +This spirit, dumb to us, will speak to him. +Do you consent we shall acquaint him with it, +As needful in our loves, fitting our duty? + +MARCELLUS. +Let’s do’t, I pray, and I this morning know +Where we shall find him most conveniently. + +[_Exeunt._] + + SCENE II. Elsinore. A room of state in the Castle. + +Enter Claudius King of Denmark, Gertrude the Queen, Hamlet, Polonius, +Laertes, Voltemand, +Cornelius, Lords and Attendant. + +KING. +Though yet of Hamlet our dear brother’s death +The memory be green, and that it us befitted +To bear our hearts in grief, and our whole kingdom +To be contracted in one brow of woe; +Yet so far hath discretion fought with nature +That we with wisest sorrow think on him, +Together with remembrance of ourselves. +Therefore our sometime sister, now our queen, +Th’imperial jointress to this warlike state, +Have we, as ’twere with a defeated joy, +With one auspicious and one dropping eye, +With mirth in funeral, and with dirge in marriage, +In equal scale weighing delight and dole, +Taken to wife; nor have we herein barr’d +Your better wisdoms, which have freely gone +With this affair along. For all, our thanks. +Now follows, that you know young Fortinbras, +Holding a weak supposal of our worth, +Or thinking by our late dear brother’s death +Our state to be disjoint and out of frame, +Colleagued with this dream of his advantage, +He hath not fail’d to pester us with message, +Importing the surrender of those lands +Lost by his father, with all bonds of law, +To our most valiant brother. So much for him. +Now for ourself and for this time of meeting: +Thus much the business is: we have here writ +To Norway, uncle of young Fortinbras, +Who, impotent and bed-rid, scarcely hears +Of this his nephew’s purpose, to suppress +His further gait herein; in that the levies, +The lists, and full proportions are all made +Out of his subject: and we here dispatch +You, good Cornelius, and you, Voltemand, +For bearers of this greeting to old Norway, +Giving to you no further personal power +To business with the King, more than the scope +Of these dilated articles allow. +Farewell; and let your haste commend your duty. + +CORNELIUS and VOLTEMAND. +In that, and all things, will we show our duty. + +KING. +We doubt it nothing: heartily farewell. + +[_Exeunt Voltemand and Cornelius._] + +And now, Laertes, what’s the news with you? +You told us of some suit. What is’t, Laertes? +You cannot speak of reason to the Dane, +And lose your voice. What wouldst thou beg, Laertes, +That shall not be my offer, not thy asking? +The head is not more native to the heart, +The hand more instrumental to the mouth, +Than is the throne of Denmark to thy father. +What wouldst thou have, Laertes? + +LAERTES. +Dread my lord, +Your leave and favour to return to France, +From whence though willingly I came to Denmark +To show my duty in your coronation; +Yet now I must confess, that duty done, +My thoughts and wishes bend again toward France, +And bow them to your gracious leave and pardon. + +KING. +Have you your father’s leave? What says Polonius? + +POLONIUS. +He hath, my lord, wrung from me my slow leave +By laboursome petition; and at last +Upon his will I seal’d my hard consent. +I do beseech you give him leave to go. + +KING. +Take thy fair hour, Laertes; time be thine, +And thy best graces spend it at thy will! +But now, my cousin Hamlet, and my son— + +HAMLET. +[_Aside._] A little more than kin, and less than kind. + +KING. +How is it that the clouds still hang on you? + +HAMLET. +Not so, my lord, I am too much i’ the sun. + +QUEEN. +Good Hamlet, cast thy nighted colour off, +And let thine eye look like a friend on Denmark. +Do not for ever with thy vailed lids +Seek for thy noble father in the dust. +Thou know’st ’tis common, all that lives must die, +Passing through nature to eternity. + +HAMLET. +Ay, madam, it is common. + +QUEEN. +If it be, +Why seems it so particular with thee? + +HAMLET. +Seems, madam! Nay, it is; I know not seems. +’Tis not alone my inky cloak, good mother, +Nor customary suits of solemn black, +Nor windy suspiration of forc’d breath, +No, nor the fruitful river in the eye, +Nor the dejected haviour of the visage, +Together with all forms, moods, shows of grief, +That can denote me truly. These indeed seem, +For they are actions that a man might play; +But I have that within which passeth show; +These but the trappings and the suits of woe. + +KING. +’Tis sweet and commendable in your nature, Hamlet, +To give these mourning duties to your father; +But you must know, your father lost a father, +That father lost, lost his, and the survivor bound +In filial obligation, for some term +To do obsequious sorrow. But to persevere +In obstinate condolement is a course +Of impious stubbornness. ’Tis unmanly grief, +It shows a will most incorrect to heaven, +A heart unfortified, a mind impatient, +An understanding simple and unschool’d; +For what we know must be, and is as common +As any the most vulgar thing to sense, +Why should we in our peevish opposition +Take it to heart? Fie, ’tis a fault to heaven, +A fault against the dead, a fault to nature, +To reason most absurd, whose common theme +Is death of fathers, and who still hath cried, +From the first corse till he that died today, +‘This must be so.’ We pray you throw to earth +This unprevailing woe, and think of us +As of a father; for let the world take note +You are the most immediate to our throne, +And with no less nobility of love +Than that which dearest father bears his son +Do I impart toward you. For your intent +In going back to school in Wittenberg, +It is most retrograde to our desire: +And we beseech you bend you to remain +Here in the cheer and comfort of our eye, +Our chiefest courtier, cousin, and our son. + +QUEEN. +Let not thy mother lose her prayers, Hamlet. +I pray thee stay with us; go not to Wittenberg. + +HAMLET. +I shall in all my best obey you, madam. + +KING. +Why, ’tis a loving and a fair reply. +Be as ourself in Denmark. Madam, come; +This gentle and unforc’d accord of Hamlet +Sits smiling to my heart; in grace whereof, +No jocund health that Denmark drinks today +But the great cannon to the clouds shall tell, +And the King’s rouse the heaven shall bruit again, +Re-speaking earthly thunder. Come away. + +[_Exeunt all but Hamlet._] + +HAMLET. +O that this too too solid flesh would melt, +Thaw, and resolve itself into a dew! +Or that the Everlasting had not fix’d +His canon ’gainst self-slaughter. O God! O God! +How weary, stale, flat, and unprofitable +Seem to me all the uses of this world! +Fie on’t! Oh fie! ’tis an unweeded garden +That grows to seed; things rank and gross in nature +Possess it merely. That it should come to this! +But two months dead—nay, not so much, not two: +So excellent a king; that was to this +Hyperion to a satyr; so loving to my mother, +That he might not beteem the winds of heaven +Visit her face too roughly. Heaven and earth! +Must I remember? Why, she would hang on him +As if increase of appetite had grown +By what it fed on; and yet, within a month— +Let me not think on’t—Frailty, thy name is woman! +A little month, or ere those shoes were old +With which she followed my poor father’s body +Like Niobe, all tears.—Why she, even she— +O God! A beast that wants discourse of reason +Would have mourn’d longer,—married with mine uncle, +My father’s brother; but no more like my father +Than I to Hercules. Within a month, +Ere yet the salt of most unrighteous tears +Had left the flushing in her galled eyes, +She married. O most wicked speed, to post +With such dexterity to incestuous sheets! +It is not, nor it cannot come to good. +But break, my heart, for I must hold my tongue. + +Enter Horatio, Marcellus and Barnardo. + +HORATIO. +Hail to your lordship! + +HAMLET. +I am glad to see you well: +Horatio, or I do forget myself. + +HORATIO. +The same, my lord, +And your poor servant ever. + +HAMLET. +Sir, my good friend; +I’ll change that name with you: +And what make you from Wittenberg, Horatio?— +Marcellus? + +MARCELLUS. +My good lord. + +HAMLET. +I am very glad to see you.—Good even, sir.— +But what, in faith, make you from Wittenberg? + +HORATIO. +A truant disposition, good my lord. + +HAMLET. +I would not hear your enemy say so; +Nor shall you do my ear that violence, +To make it truster of your own report +Against yourself. I know you are no truant. +But what is your affair in Elsinore? +We’ll teach you to drink deep ere you depart. + +HORATIO. +My lord, I came to see your father’s funeral. + +HAMLET. +I prithee do not mock me, fellow-student. +I think it was to see my mother’s wedding. + +HORATIO. +Indeed, my lord, it follow’d hard upon. + +HAMLET. +Thrift, thrift, Horatio! The funeral bak’d meats +Did coldly furnish forth the marriage tables. +Would I had met my dearest foe in heaven +Or ever I had seen that day, Horatio. +My father,—methinks I see my father. + +HORATIO. +Where, my lord? + +HAMLET. +In my mind’s eye, Horatio. + +HORATIO. +I saw him once; he was a goodly king. + +HAMLET. +He was a man, take him for all in all, +I shall not look upon his like again. + +HORATIO. +My lord, I think I saw him yesternight. + +HAMLET. +Saw? Who? + +HORATIO. +My lord, the King your father. + +HAMLET. +The King my father! + +HORATIO. +Season your admiration for a while +With an attent ear, till I may deliver +Upon the witness of these gentlemen +This marvel to you. + +HAMLET. +For God’s love let me hear. + +HORATIO. +Two nights together had these gentlemen, +Marcellus and Barnardo, on their watch +In the dead waste and middle of the night, +Been thus encounter’d. A figure like your father, +Armed at point exactly, cap-à-pie, +Appears before them, and with solemn march +Goes slow and stately by them: thrice he walk’d +By their oppress’d and fear-surprised eyes, +Within his truncheon’s length; whilst they, distill’d +Almost to jelly with the act of fear, +Stand dumb, and speak not to him. This to me +In dreadful secrecy impart they did, +And I with them the third night kept the watch, +Where, as they had deliver’d, both in time, +Form of the thing, each word made true and good, +The apparition comes. I knew your father; +These hands are not more like. + +HAMLET. +But where was this? + +MARCELLUS. +My lord, upon the platform where we watch. + +HAMLET. +Did you not speak to it? + +HORATIO. +My lord, I did; +But answer made it none: yet once methought +It lifted up it head, and did address +Itself to motion, like as it would speak. +But even then the morning cock crew loud, +And at the sound it shrunk in haste away, +And vanish’d from our sight. + +HAMLET. +’Tis very strange. + +HORATIO. +As I do live, my honour’d lord, ’tis true; +And we did think it writ down in our duty +To let you know of it. + +HAMLET. +Indeed, indeed, sirs, but this troubles me. +Hold you the watch tonight? + +MARCELLUS and BARNARDO. +We do, my lord. + +HAMLET. +Arm’d, say you? + +Both. +Arm’d, my lord. + +HAMLET. +From top to toe? + +BOTH. +My lord, from head to foot. + +HAMLET. +Then saw you not his face? + +HORATIO. +O yes, my lord, he wore his beaver up. + +HAMLET. +What, look’d he frowningly? + +HORATIO. +A countenance more in sorrow than in anger. + +HAMLET. +Pale, or red? + +HORATIO. +Nay, very pale. + +HAMLET. +And fix’d his eyes upon you? + +HORATIO. +Most constantly. + +HAMLET. +I would I had been there. + +HORATIO. +It would have much amaz’d you. + +HAMLET. +Very like, very like. Stay’d it long? + +HORATIO. +While one with moderate haste might tell a hundred. + +MARCELLUS and BARNARDO. +Longer, longer. + +HORATIO. +Not when I saw’t. + +HAMLET. +His beard was grizzled, no? + +HORATIO. +It was, as I have seen it in his life, +A sable silver’d. + +HAMLET. +I will watch tonight; +Perchance ’twill walk again. + +HORATIO. +I warrant you it will. + +HAMLET. +If it assume my noble father’s person, +I’ll speak to it, though hell itself should gape +And bid me hold my peace. I pray you all, +If you have hitherto conceal’d this sight, +Let it be tenable in your silence still; +And whatsoever else shall hap tonight, +Give it an understanding, but no tongue. +I will requite your loves. So, fare ye well. +Upon the platform ’twixt eleven and twelve, +I’ll visit you. + +ALL. +Our duty to your honour. + +HAMLET. +Your loves, as mine to you: farewell. + +[_Exeunt Horatio, Marcellus and Barnardo._] + +My father’s spirit in arms! All is not well; +I doubt some foul play: would the night were come! +Till then sit still, my soul: foul deeds will rise, +Though all the earth o’erwhelm them, to men’s eyes. + +[_Exit._] + + SCENE III. A room in Polonius’s house. + +Enter Laertes and Ophelia. + +LAERTES. +My necessaries are embark’d. Farewell. +And, sister, as the winds give benefit +And convoy is assistant, do not sleep, +But let me hear from you. + +OPHELIA. +Do you doubt that? + +LAERTES. +For Hamlet, and the trifling of his favour, +Hold it a fashion and a toy in blood; +A violet in the youth of primy nature, +Forward, not permanent, sweet, not lasting; +The perfume and suppliance of a minute; +No more. + +OPHELIA. +No more but so? + +LAERTES. +Think it no more. +For nature crescent does not grow alone +In thews and bulk; but as this temple waxes, +The inward service of the mind and soul +Grows wide withal. Perhaps he loves you now, +And now no soil nor cautel doth besmirch +The virtue of his will; but you must fear, +His greatness weigh’d, his will is not his own; +For he himself is subject to his birth: +He may not, as unvalu’d persons do, +Carve for himself; for on his choice depends +The sanctity and health of this whole state; +And therefore must his choice be circumscrib’d +Unto the voice and yielding of that body +Whereof he is the head. Then if he says he loves you, +It fits your wisdom so far to believe it +As he in his particular act and place +May give his saying deed; which is no further +Than the main voice of Denmark goes withal. +Then weigh what loss your honour may sustain +If with too credent ear you list his songs, +Or lose your heart, or your chaste treasure open +To his unmaster’d importunity. +Fear it, Ophelia, fear it, my dear sister; +And keep you in the rear of your affection, +Out of the shot and danger of desire. +The chariest maid is prodigal enough +If she unmask her beauty to the moon. +Virtue itself ’scapes not calumnious strokes: +The canker galls the infants of the spring +Too oft before their buttons be disclos’d, +And in the morn and liquid dew of youth +Contagious blastments are most imminent. +Be wary then, best safety lies in fear. +Youth to itself rebels, though none else near. + +OPHELIA. +I shall th’effect of this good lesson keep +As watchman to my heart. But good my brother, +Do not as some ungracious pastors do, +Show me the steep and thorny way to heaven; +Whilst like a puff’d and reckless libertine +Himself the primrose path of dalliance treads, +And recks not his own rede. + +LAERTES. +O, fear me not. +I stay too long. But here my father comes. + +Enter Polonius. + +A double blessing is a double grace; +Occasion smiles upon a second leave. + +POLONIUS. +Yet here, Laertes? Aboard, aboard, for shame. +The wind sits in the shoulder of your sail, +And you are stay’d for. There, my blessing with you. + +[_Laying his hand on Laertes’s head._] + +And these few precepts in thy memory +Look thou character. Give thy thoughts no tongue, +Nor any unproportion’d thought his act. +Be thou familiar, but by no means vulgar. +Those friends thou hast, and their adoption tried, +Grapple them unto thy soul with hoops of steel; +But do not dull thy palm with entertainment +Of each new-hatch’d, unfledg’d comrade. Beware +Of entrance to a quarrel; but being in, +Bear’t that th’opposed may beware of thee. +Give every man thine ear, but few thy voice: +Take each man’s censure, but reserve thy judgement. +Costly thy habit as thy purse can buy, +But not express’d in fancy; rich, not gaudy: +For the apparel oft proclaims the man; +And they in France of the best rank and station +Are of a most select and generous chief in that. +Neither a borrower nor a lender be: +For loan oft loses both itself and friend; +And borrowing dulls the edge of husbandry. +This above all: to thine own self be true; +And it must follow, as the night the day, +Thou canst not then be false to any man. +Farewell: my blessing season this in thee. + +LAERTES. +Most humbly do I take my leave, my lord. + +POLONIUS. +The time invites you; go, your servants tend. + +LAERTES. +Farewell, Ophelia, and remember well +What I have said to you. + +OPHELIA. +’Tis in my memory lock’d, +And you yourself shall keep the key of it. + +LAERTES. +Farewell. + +[_Exit._] + +POLONIUS. +What is’t, Ophelia, he hath said to you? + +OPHELIA. +So please you, something touching the Lord Hamlet. + +POLONIUS. +Marry, well bethought: +’Tis told me he hath very oft of late +Given private time to you; and you yourself +Have of your audience been most free and bounteous. +If it be so,—as so ’tis put on me, +And that in way of caution,—I must tell you +You do not understand yourself so clearly +As it behoves my daughter and your honour. +What is between you? Give me up the truth. + +OPHELIA. +He hath, my lord, of late made many tenders +Of his affection to me. + +POLONIUS. +Affection! Pooh! You speak like a green girl, +Unsifted in such perilous circumstance. +Do you believe his tenders, as you call them? + +OPHELIA. +I do not know, my lord, what I should think. + +POLONIUS. +Marry, I’ll teach you; think yourself a baby; +That you have ta’en these tenders for true pay, +Which are not sterling. Tender yourself more dearly; +Or,—not to crack the wind of the poor phrase, +Running it thus,—you’ll tender me a fool. + +OPHELIA. +My lord, he hath importun’d me with love +In honourable fashion. + +POLONIUS. +Ay, fashion you may call it; go to, go to. + +OPHELIA. +And hath given countenance to his speech, my lord, +With almost all the holy vows of heaven. + +POLONIUS. +Ay, springes to catch woodcocks. I do know, +When the blood burns, how prodigal the soul +Lends the tongue vows: these blazes, daughter, +Giving more light than heat, extinct in both, +Even in their promise, as it is a-making, +You must not take for fire. From this time +Be something scanter of your maiden presence; +Set your entreatments at a higher rate +Than a command to parley. For Lord Hamlet, +Believe so much in him that he is young; +And with a larger tether may he walk +Than may be given you. In few, Ophelia, +Do not believe his vows; for they are brokers, +Not of that dye which their investments show, +But mere implorators of unholy suits, +Breathing like sanctified and pious bawds, +The better to beguile. This is for all: +I would not, in plain terms, from this time forth +Have you so slander any moment leisure +As to give words or talk with the Lord Hamlet. +Look to’t, I charge you; come your ways. + +OPHELIA. +I shall obey, my lord. + +[_Exeunt._] + + SCENE IV. The platform. + +Enter Hamlet, Horatio and Marcellus. + +HAMLET. +The air bites shrewdly; it is very cold. + +HORATIO. +It is a nipping and an eager air. + +HAMLET. +What hour now? + +HORATIO. +I think it lacks of twelve. + +MARCELLUS. +No, it is struck. + +HORATIO. +Indeed? I heard it not. It then draws near the season +Wherein the spirit held his wont to walk. + +[_A flourish of trumpets, and ordnance shot off within._] + +What does this mean, my lord? + +HAMLET. +The King doth wake tonight and takes his rouse, +Keeps wassail, and the swaggering upspring reels; +And as he drains his draughts of Rhenish down, +The kettle-drum and trumpet thus bray out +The triumph of his pledge. + +HORATIO. +Is it a custom? + +HAMLET. +Ay marry is’t; +And to my mind, though I am native here, +And to the manner born, it is a custom +More honour’d in the breach than the observance. +This heavy-headed revel east and west +Makes us traduc’d and tax’d of other nations: +They clepe us drunkards, and with swinish phrase +Soil our addition; and indeed it takes +From our achievements, though perform’d at height, +The pith and marrow of our attribute. +So oft it chances in particular men +That for some vicious mole of nature in them, +As in their birth, wherein they are not guilty, +Since nature cannot choose his origin, +By their o’ergrowth of some complexion, +Oft breaking down the pales and forts of reason; +Or by some habit, that too much o’erleavens +The form of plausive manners;—that these men, +Carrying, I say, the stamp of one defect, +Being Nature’s livery or Fortune’s star,— +His virtues else,—be they as pure as grace, +As infinite as man may undergo, +Shall in the general censure take corruption +From that particular fault. The dram of evil +Doth all the noble substance of a doubt +To his own scandal. + +HORATIO. +Look, my lord, it comes! + +Enter Ghost. + +HAMLET. +Angels and ministers of grace defend us! +Be thou a spirit of health or goblin damn’d, +Bring with thee airs from heaven or blasts from hell, +Be thy intents wicked or charitable, +Thou com’st in such a questionable shape +That I will speak to thee. I’ll call thee Hamlet, +King, father, royal Dane. O, answer me! +Let me not burst in ignorance; but tell +Why thy canoniz’d bones, hearsed in death, +Have burst their cerements; why the sepulchre, +Wherein we saw thee quietly inurn’d, +Hath op’d his ponderous and marble jaws +To cast thee up again! What may this mean, +That thou, dead corse, again in complete steel, +Revisit’st thus the glimpses of the moon, +Making night hideous, and we fools of nature +So horridly to shake our disposition +With thoughts beyond the reaches of our souls? +Say, why is this? Wherefore? What should we do? + +[_Ghost beckons Hamlet._] + +HORATIO. +It beckons you to go away with it, +As if it some impartment did desire +To you alone. + +MARCELLUS. +Look with what courteous action +It waves you to a more removed ground. +But do not go with it. + +HORATIO. +No, by no means. + +HAMLET. +It will not speak; then will I follow it. + +HORATIO. +Do not, my lord. + +HAMLET. +Why, what should be the fear? +I do not set my life at a pin’s fee; +And for my soul, what can it do to that, +Being a thing immortal as itself? +It waves me forth again. I’ll follow it. + +HORATIO. +What if it tempt you toward the flood, my lord, +Or to the dreadful summit of the cliff +That beetles o’er his base into the sea, +And there assume some other horrible form +Which might deprive your sovereignty of reason, +And draw you into madness? Think of it. +The very place puts toys of desperation, +Without more motive, into every brain +That looks so many fathoms to the sea +And hears it roar beneath. + +HAMLET. +It waves me still. +Go on, I’ll follow thee. + +MARCELLUS. +You shall not go, my lord. + +HAMLET. +Hold off your hands. + +HORATIO. +Be rul’d; you shall not go. + +HAMLET. +My fate cries out, +And makes each petty artery in this body +As hardy as the Nemean lion’s nerve. + +[_Ghost beckons._] + +Still am I call’d. Unhand me, gentlemen. + +[_Breaking free from them._] + +By heaven, I’ll make a ghost of him that lets me. +I say, away!—Go on, I’ll follow thee. + +[_Exeunt Ghost and Hamlet._] + +HORATIO. +He waxes desperate with imagination. + +MARCELLUS. +Let’s follow; ’tis not fit thus to obey him. + +HORATIO. +Have after. To what issue will this come? + +MARCELLUS. +Something is rotten in the state of Denmark. + +HORATIO. +Heaven will direct it. + +MARCELLUS. +Nay, let’s follow him. + +[_Exeunt._] + + SCENE V. A more remote part of the Castle. + +Enter Ghost and Hamlet. + +HAMLET. +Whither wilt thou lead me? Speak, I’ll go no further. + +GHOST. +Mark me. + +HAMLET. +I will. + +GHOST. +My hour is almost come, +When I to sulph’rous and tormenting flames +Must render up myself. + +HAMLET. +Alas, poor ghost! + +GHOST. +Pity me not, but lend thy serious hearing +To what I shall unfold. + +HAMLET. +Speak, I am bound to hear. + +GHOST. +So art thou to revenge, when thou shalt hear. + +HAMLET. +What? + +GHOST. +I am thy father’s spirit, +Doom’d for a certain term to walk the night, +And for the day confin’d to fast in fires, +Till the foul crimes done in my days of nature +Are burnt and purg’d away. But that I am forbid +To tell the secrets of my prison-house, +I could a tale unfold whose lightest word +Would harrow up thy soul; freeze thy young blood, +Make thy two eyes like stars start from their spheres, +Thy knotted and combined locks to part, +And each particular hair to stand on end +Like quills upon the fretful porpentine. +But this eternal blazon must not be +To ears of flesh and blood. List, list, O, list! +If thou didst ever thy dear father love— + +HAMLET. +O God! + +GHOST. +Revenge his foul and most unnatural murder. + +HAMLET. +Murder! + +GHOST. +Murder most foul, as in the best it is; +But this most foul, strange, and unnatural. + +HAMLET. +Haste me to know’t, that I, with wings as swift +As meditation or the thoughts of love +May sweep to my revenge. + +GHOST. +I find thee apt; +And duller shouldst thou be than the fat weed +That rots itself in ease on Lethe wharf, +Wouldst thou not stir in this. Now, Hamlet, hear. +’Tis given out that, sleeping in my orchard, +A serpent stung me; so the whole ear of Denmark +Is by a forged process of my death +Rankly abus’d; but know, thou noble youth, +The serpent that did sting thy father’s life +Now wears his crown. + +HAMLET. +O my prophetic soul! +Mine uncle! + +GHOST. +Ay, that incestuous, that adulterate beast, +With witchcraft of his wit, with traitorous gifts,— +O wicked wit, and gifts, that have the power +So to seduce!—won to his shameful lust +The will of my most seeming-virtuous queen. +O Hamlet, what a falling off was there, +From me, whose love was of that dignity +That it went hand in hand even with the vow +I made to her in marriage; and to decline +Upon a wretch whose natural gifts were poor +To those of mine. But virtue, as it never will be mov’d, +Though lewdness court it in a shape of heaven; +So lust, though to a radiant angel link’d, +Will sate itself in a celestial bed +And prey on garbage. +But soft! methinks I scent the morning air; +Brief let me be. Sleeping within my orchard, +My custom always of the afternoon, +Upon my secure hour thy uncle stole +With juice of cursed hebenon in a vial, +And in the porches of my ears did pour +The leperous distilment, whose effect +Holds such an enmity with blood of man +That swift as quicksilver it courses through +The natural gates and alleys of the body; +And with a sudden vigour it doth posset +And curd, like eager droppings into milk, +The thin and wholesome blood. So did it mine; +And a most instant tetter bark’d about, +Most lazar-like, with vile and loathsome crust +All my smooth body. +Thus was I, sleeping, by a brother’s hand, +Of life, of crown, of queen at once dispatch’d: +Cut off even in the blossoms of my sin, +Unhous’led, disappointed, unanel’d; +No reckoning made, but sent to my account +With all my imperfections on my head. +O horrible! O horrible! most horrible! +If thou hast nature in thee, bear it not; +Let not the royal bed of Denmark be +A couch for luxury and damned incest. +But howsoever thou pursu’st this act, +Taint not thy mind, nor let thy soul contrive +Against thy mother aught; leave her to heaven, +And to those thorns that in her bosom lodge, +To prick and sting her. Fare thee well at once! +The glow-worm shows the matin to be near, +And ’gins to pale his uneffectual fire. +Adieu, adieu, adieu. Remember me. + +[_Exit._] + +HAMLET. +O all you host of heaven! O earth! What else? +And shall I couple hell? O, fie! Hold, my heart; +And you, my sinews, grow not instant old, +But bear me stiffly up. Remember thee? +Ay, thou poor ghost, while memory holds a seat +In this distracted globe. Remember thee? +Yea, from the table of my memory +I’ll wipe away all trivial fond records, +All saws of books, all forms, all pressures past, +That youth and observation copied there; +And thy commandment all alone shall live +Within the book and volume of my brain, +Unmix’d with baser matter. Yes, by heaven! +O most pernicious woman! +O villain, villain, smiling damned villain! +My tables. Meet it is I set it down, +That one may smile, and smile, and be a villain! +At least I am sure it may be so in Denmark. + +[_Writing._] + +So, uncle, there you are. Now to my word; +It is ‘Adieu, adieu, remember me.’ +I have sworn’t. + +HORATIO and MARCELLUS. +[_Within._] My lord, my lord. + +MARCELLUS. +[_Within._] Lord Hamlet. + +HORATIO. +[_Within._] Heaven secure him. + +HAMLET. +So be it! + +MARCELLUS. +[_Within._] Illo, ho, ho, my lord! + +HAMLET. +Hillo, ho, ho, boy! Come, bird, come. + +Enter Horatio and Marcellus. + +MARCELLUS. +How is’t, my noble lord? + +HORATIO. +What news, my lord? + +HAMLET. +O, wonderful! + +HORATIO. +Good my lord, tell it. + +HAMLET. +No, you’ll reveal it. + +HORATIO. +Not I, my lord, by heaven. + +MARCELLUS. +Nor I, my lord. + +HAMLET. +How say you then, would heart of man once think it?— +But you’ll be secret? + +HORATIO and MARCELLUS. +Ay, by heaven, my lord. + +HAMLET. +There’s ne’er a villain dwelling in all Denmark +But he’s an arrant knave. + +HORATIO. +There needs no ghost, my lord, come from the grave +To tell us this. + +HAMLET. +Why, right; you are i’ the right; +And so, without more circumstance at all, +I hold it fit that we shake hands and part: +You, as your business and desire shall point you,— +For every man hath business and desire, +Such as it is;—and for my own poor part, +Look you, I’ll go pray. + +HORATIO. +These are but wild and whirling words, my lord. + +HAMLET. +I’m sorry they offend you, heartily; +Yes faith, heartily. + +HORATIO. +There’s no offence, my lord. + +HAMLET. +Yes, by Saint Patrick, but there is, Horatio, +And much offence too. Touching this vision here, +It is an honest ghost, that let me tell you. +For your desire to know what is between us, +O’ermaster’t as you may. And now, good friends, +As you are friends, scholars, and soldiers, +Give me one poor request. + +HORATIO. +What is’t, my lord? We will. + +HAMLET. +Never make known what you have seen tonight. + +HORATIO and MARCELLUS. +My lord, we will not. + +HAMLET. +Nay, but swear’t. + +HORATIO. +In faith, my lord, not I. + +MARCELLUS. +Nor I, my lord, in faith. + +HAMLET. +Upon my sword. + +MARCELLUS. +We have sworn, my lord, already. + +HAMLET. +Indeed, upon my sword, indeed. + +GHOST. +[_Cries under the stage._] Swear. + +HAMLET. +Ha, ha boy, sayst thou so? Art thou there, truepenny? +Come on, you hear this fellow in the cellarage. +Consent to swear. + +HORATIO. +Propose the oath, my lord. + +HAMLET. +Never to speak of this that you have seen. +Swear by my sword. + +GHOST. +[_Beneath._] Swear. + +HAMLET. +_Hic et ubique?_ Then we’ll shift our ground. +Come hither, gentlemen, +And lay your hands again upon my sword. +Never to speak of this that you have heard. +Swear by my sword. + +GHOST. +[_Beneath._] Swear. + +HAMLET. +Well said, old mole! Canst work i’ th’earth so fast? +A worthy pioner! Once more remove, good friends. + +HORATIO. +O day and night, but this is wondrous strange. + +HAMLET. +And therefore as a stranger give it welcome. +There are more things in heaven and earth, Horatio, +Than are dreamt of in your philosophy. But come, +Here, as before, never, so help you mercy, +How strange or odd soe’er I bear myself,— +As I perchance hereafter shall think meet +To put an antic disposition on— +That you, at such times seeing me, never shall, +With arms encumber’d thus, or this head-shake, +Or by pronouncing of some doubtful phrase, +As ‘Well, we know’, or ‘We could and if we would’, +Or ‘If we list to speak’; or ‘There be and if they might’, +Or such ambiguous giving out, to note +That you know aught of me:—this not to do. +So grace and mercy at your most need help you, +Swear. + +GHOST. +[_Beneath._] Swear. + +HAMLET. +Rest, rest, perturbed spirit. So, gentlemen, +With all my love I do commend me to you; +And what so poor a man as Hamlet is +May do t’express his love and friending to you, +God willing, shall not lack. Let us go in together, +And still your fingers on your lips, I pray. +The time is out of joint. O cursed spite, +That ever I was born to set it right. +Nay, come, let’s go together. + +[_Exeunt._] + + + + +ACT II + +SCENE I. A room in Polonius’s house. + + +Enter Polonius and Reynaldo. + +POLONIUS. +Give him this money and these notes, Reynaldo. + +REYNALDO. +I will, my lord. + +POLONIUS. +You shall do marvellous wisely, good Reynaldo, +Before you visit him, to make inquiry +Of his behaviour. + +REYNALDO. +My lord, I did intend it. + +POLONIUS. +Marry, well said; very well said. Look you, sir, +Enquire me first what Danskers are in Paris; +And how, and who, what means, and where they keep, +What company, at what expense; and finding +By this encompassment and drift of question, +That they do know my son, come you more nearer +Than your particular demands will touch it. +Take you as ’twere some distant knowledge of him, +As thus, ‘I know his father and his friends, +And in part him’—do you mark this, Reynaldo? + +REYNALDO. +Ay, very well, my lord. + +POLONIUS. +‘And in part him, but,’ you may say, ‘not well; +But if’t be he I mean, he’s very wild; +Addicted so and so;’ and there put on him +What forgeries you please; marry, none so rank +As may dishonour him; take heed of that; +But, sir, such wanton, wild, and usual slips +As are companions noted and most known +To youth and liberty. + +REYNALDO. +As gaming, my lord? + +POLONIUS. +Ay, or drinking, fencing, swearing, +Quarrelling, drabbing. You may go so far. + +REYNALDO. +My lord, that would dishonour him. + +POLONIUS. +Faith no, as you may season it in the charge. +You must not put another scandal on him, +That he is open to incontinency; +That’s not my meaning: but breathe his faults so quaintly +That they may seem the taints of liberty; +The flash and outbreak of a fiery mind, +A savageness in unreclaimed blood, +Of general assault. + +REYNALDO. +But my good lord— + +POLONIUS. +Wherefore should you do this? + +REYNALDO. +Ay, my lord, I would know that. + +POLONIUS. +Marry, sir, here’s my drift, +And I believe it is a fetch of warrant. +You laying these slight sullies on my son, +As ’twere a thing a little soil’d i’ th’ working, +Mark you, +Your party in converse, him you would sound, +Having ever seen in the prenominate crimes +The youth you breathe of guilty, be assur’d +He closes with you in this consequence; +‘Good sir,’ or so; or ‘friend,’ or ‘gentleman’— +According to the phrase or the addition +Of man and country. + +REYNALDO. +Very good, my lord. + +POLONIUS. +And then, sir, does he this,— +He does—What was I about to say? +By the mass, I was about to say something. Where did I leave? + +REYNALDO. +At ‘closes in the consequence.’ +At ‘friend or so,’ and ‘gentleman.’ + +POLONIUS. +At ‘closes in the consequence’ ay, marry! +He closes with you thus: ‘I know the gentleman, +I saw him yesterday, or t’other day, +Or then, or then, with such and such; and, as you say, +There was he gaming, there o’ertook in’s rouse, +There falling out at tennis’: or perchance, +‘I saw him enter such a house of sale’— +_Videlicet_, a brothel, or so forth. See you now; +Your bait of falsehood takes this carp of truth; +And thus do we of wisdom and of reach, +With windlasses, and with assays of bias, +By indirections find directions out. +So by my former lecture and advice +Shall you my son. You have me, have you not? + +REYNALDO. +My lord, I have. + +POLONIUS. +God b’ wi’ you, fare you well. + +REYNALDO. +Good my lord. + +POLONIUS. +Observe his inclination in yourself. + +REYNALDO. +I shall, my lord. + +POLONIUS. +And let him ply his music. + +REYNALDO. +Well, my lord. + +POLONIUS. +Farewell. + +[_Exit Reynaldo._] + +Enter Ophelia. + +How now, Ophelia, what’s the matter? + +OPHELIA. +Alas, my lord, I have been so affrighted. + +POLONIUS. +With what, in the name of God? + +OPHELIA. +My lord, as I was sewing in my chamber, +Lord Hamlet, with his doublet all unbrac’d, +No hat upon his head, his stockings foul’d, +Ungart’red, and down-gyved to his ankle, +Pale as his shirt, his knees knocking each other, +And with a look so piteous in purport +As if he had been loosed out of hell +To speak of horrors, he comes before me. + +POLONIUS. +Mad for thy love? + +OPHELIA. +My lord, I do not know, but truly I do fear it. + +POLONIUS. +What said he? + +OPHELIA. +He took me by the wrist and held me hard; +Then goes he to the length of all his arm; +And with his other hand thus o’er his brow, +He falls to such perusal of my face +As he would draw it. Long stay’d he so, +At last,—a little shaking of mine arm, +And thrice his head thus waving up and down, +He rais’d a sigh so piteous and profound +As it did seem to shatter all his bulk +And end his being. That done, he lets me go, +And with his head over his shoulder turn’d +He seem’d to find his way without his eyes, +For out o’ doors he went without their help, +And to the last bended their light on me. + +POLONIUS. +Come, go with me. I will go seek the King. +This is the very ecstasy of love, +Whose violent property fordoes itself, +And leads the will to desperate undertakings, +As oft as any passion under heaven +That does afflict our natures. I am sorry,— +What, have you given him any hard words of late? + +OPHELIA. +No, my good lord; but as you did command, +I did repel his letters and denied +His access to me. + +POLONIUS. +That hath made him mad. +I am sorry that with better heed and judgement +I had not quoted him. I fear’d he did but trifle, +And meant to wreck thee. But beshrew my jealousy! +It seems it is as proper to our age +To cast beyond ourselves in our opinions +As it is common for the younger sort +To lack discretion. Come, go we to the King. +This must be known, which, being kept close, might move +More grief to hide than hate to utter love. + +[_Exeunt._] + + SCENE II. A room in the Castle. + +Enter King, Queen, Rosencrantz, Guildenstern and Attendants. + +KING. +Welcome, dear Rosencrantz and Guildenstern. +Moreover that we much did long to see you, +The need we have to use you did provoke +Our hasty sending. Something have you heard +Of Hamlet’s transformation; so I call it, +Since nor th’exterior nor the inward man +Resembles that it was. What it should be, +More than his father’s death, that thus hath put him +So much from th’understanding of himself, +I cannot dream of. I entreat you both +That, being of so young days brought up with him, +And since so neighbour’d to his youth and humour, +That you vouchsafe your rest here in our court +Some little time, so by your companies +To draw him on to pleasures and to gather, +So much as from occasion you may glean, +Whether aught to us unknown afflicts him thus +That, open’d, lies within our remedy. + +QUEEN. +Good gentlemen, he hath much talk’d of you, +And sure I am, two men there are not living +To whom he more adheres. If it will please you +To show us so much gentry and good will +As to expend your time with us awhile, +For the supply and profit of our hope, +Your visitation shall receive such thanks +As fits a king’s remembrance. + +ROSENCRANTZ. +Both your majesties +Might, by the sovereign power you have of us, +Put your dread pleasures more into command +Than to entreaty. + +GUILDENSTERN. +We both obey, +And here give up ourselves, in the full bent, +To lay our service freely at your feet +To be commanded. + +KING. +Thanks, Rosencrantz and gentle Guildenstern. + +QUEEN. +Thanks, Guildenstern and gentle Rosencrantz. +And I beseech you instantly to visit +My too much changed son. Go, some of you, +And bring these gentlemen where Hamlet is. + +GUILDENSTERN. +Heavens make our presence and our practices +Pleasant and helpful to him. + +QUEEN. +Ay, amen. + +[_Exeunt Rosencrantz, Guildenstern and some Attendants._] + +Enter Polonius. + +POLONIUS. +Th’ambassadors from Norway, my good lord, +Are joyfully return’d. + +KING. +Thou still hast been the father of good news. + +POLONIUS. +Have I, my lord? Assure you, my good liege, +I hold my duty, as I hold my soul, +Both to my God and to my gracious King: +And I do think,—or else this brain of mine +Hunts not the trail of policy so sure +As it hath us’d to do—that I have found +The very cause of Hamlet’s lunacy. + +KING. +O speak of that, that do I long to hear. + +POLONIUS. +Give first admittance to th’ambassadors; +My news shall be the fruit to that great feast. + +KING. +Thyself do grace to them, and bring them in. + +[_Exit Polonius._] + +He tells me, my sweet queen, that he hath found +The head and source of all your son’s distemper. + +QUEEN. +I doubt it is no other but the main, +His father’s death and our o’erhasty marriage. + +KING. +Well, we shall sift him. + +Enter Polonius with Voltemand and Cornelius. + +Welcome, my good friends! +Say, Voltemand, what from our brother Norway? + +VOLTEMAND. +Most fair return of greetings and desires. +Upon our first, he sent out to suppress +His nephew’s levies, which to him appear’d +To be a preparation ’gainst the Polack; +But better look’d into, he truly found +It was against your Highness; whereat griev’d, +That so his sickness, age, and impotence +Was falsely borne in hand, sends out arrests +On Fortinbras; which he, in brief, obeys, +Receives rebuke from Norway; and in fine, +Makes vow before his uncle never more +To give th’assay of arms against your Majesty. +Whereon old Norway, overcome with joy, +Gives him three thousand crowns in annual fee, +And his commission to employ those soldiers +So levied as before, against the Polack: +With an entreaty, herein further shown, +[_Gives a paper._] +That it might please you to give quiet pass +Through your dominions for this enterprise, +On such regards of safety and allowance +As therein are set down. + +KING. +It likes us well; +And at our more consider’d time we’ll read, +Answer, and think upon this business. +Meantime we thank you for your well-took labour. +Go to your rest, at night we’ll feast together:. +Most welcome home. + +[_Exeunt Voltemand and Cornelius._] + +POLONIUS. +This business is well ended. +My liege and madam, to expostulate +What majesty should be, what duty is, +Why day is day, night night, and time is time +Were nothing but to waste night, day and time. +Therefore, since brevity is the soul of wit, +And tediousness the limbs and outward flourishes, +I will be brief. Your noble son is mad. +Mad call I it; for to define true madness, +What is’t but to be nothing else but mad? +But let that go. + +QUEEN. +More matter, with less art. + +POLONIUS. +Madam, I swear I use no art at all. +That he is mad, ’tis true: ’tis true ’tis pity; +And pity ’tis ’tis true. A foolish figure, +But farewell it, for I will use no art. +Mad let us grant him then. And now remains +That we find out the cause of this effect, +Or rather say, the cause of this defect, +For this effect defective comes by cause. +Thus it remains, and the remainder thus. Perpend, +I have a daughter—have whilst she is mine— +Who in her duty and obedience, mark, +Hath given me this. Now gather, and surmise. +[_Reads._] +_To the celestial, and my soul’s idol, the most beautified Ophelia_— +That’s an ill phrase, a vile phrase; ‘beautified’ is a vile +phrase: but you shall hear. +[_Reads._] +_these; in her excellent white bosom, these, &c._ + +QUEEN. +Came this from Hamlet to her? + +POLONIUS. +Good madam, stay awhile; I will be faithful. +[_Reads._] + _Doubt thou the stars are fire, + Doubt that the sun doth move, + Doubt truth to be a liar, + But never doubt I love. +O dear Ophelia, I am ill at these numbers. I have not art to reckon my +groans. But that I love thee best, O most best, believe it. Adieu. + Thine evermore, most dear lady, whilst this machine is to him, + HAMLET._ +This in obedience hath my daughter show’d me; +And more above, hath his solicitings, +As they fell out by time, by means, and place, +All given to mine ear. + +KING. +But how hath she receiv’d his love? + +POLONIUS. +What do you think of me? + +KING. +As of a man faithful and honourable. + +POLONIUS. +I would fain prove so. But what might you think, +When I had seen this hot love on the wing, +As I perceiv’d it, I must tell you that, +Before my daughter told me, what might you, +Or my dear Majesty your queen here, think, +If I had play’d the desk or table-book, +Or given my heart a winking, mute and dumb, +Or look’d upon this love with idle sight, +What might you think? No, I went round to work, +And my young mistress thus I did bespeak: +‘Lord Hamlet is a prince, out of thy star. +This must not be.’ And then I precepts gave her, +That she should lock herself from his resort, +Admit no messengers, receive no tokens. +Which done, she took the fruits of my advice, +And he, repulsed,—a short tale to make— +Fell into a sadness, then into a fast, +Thence to a watch, thence into a weakness, +Thence to a lightness, and, by this declension, +Into the madness wherein now he raves, +And all we wail for. + +KING. +Do you think ’tis this? + +QUEEN. +It may be, very likely. + +POLONIUS. +Hath there been such a time, I’d fain know that, +That I have positively said ‘’Tis so,’ +When it prov’d otherwise? + +KING. +Not that I know. + +POLONIUS. +Take this from this, if this be otherwise. +[_Points to his head and shoulder._] +If circumstances lead me, I will find +Where truth is hid, though it were hid indeed +Within the centre. + +KING. +How may we try it further? + +POLONIUS. +You know sometimes he walks four hours together +Here in the lobby. + +QUEEN. +So he does indeed. + +POLONIUS. +At such a time I’ll loose my daughter to him. +Be you and I behind an arras then, +Mark the encounter. If he love her not, +And be not from his reason fall’n thereon, +Let me be no assistant for a state, +But keep a farm and carters. + +KING. +We will try it. + +Enter Hamlet, reading. + +QUEEN. +But look where sadly the poor wretch comes reading. + +POLONIUS. +Away, I do beseech you, both away +I’ll board him presently. O, give me leave. + +[_Exeunt King, Queen and Attendants._] + +How does my good Lord Hamlet? + +HAMLET. +Well, God-a-mercy. + +POLONIUS. +Do you know me, my lord? + +HAMLET. +Excellent well. You are a fishmonger. + +POLONIUS. +Not I, my lord. + +HAMLET. +Then I would you were so honest a man. + +POLONIUS. +Honest, my lord? + +HAMLET. +Ay sir, to be honest, as this world goes, is to be one man picked out +of ten thousand. + +POLONIUS. +That’s very true, my lord. + +HAMLET. +For if the sun breed maggots in a dead dog, being a good kissing +carrion,— +Have you a daughter? + +POLONIUS. +I have, my lord. + +HAMLET. +Let her not walk i’ th’ sun. Conception is a blessing, but not as your +daughter may conceive. Friend, look to’t. + +POLONIUS. +How say you by that? [_Aside._] Still harping on my daughter. Yet he +knew me not at first; he said I was a fishmonger. He is far gone, far +gone. And truly in my youth I suffered much extremity for love; very +near this. I’ll speak to him again.—What do you read, my lord? + +HAMLET. +Words, words, words. + +POLONIUS. +What is the matter, my lord? + +HAMLET. +Between who? + +POLONIUS. +I mean the matter that you read, my lord. + +HAMLET. +Slanders, sir. For the satirical slave says here that old men have grey +beards; that their faces are wrinkled; their eyes purging thick amber +and plum-tree gum; and that they have a plentiful lack of wit, together +with most weak hams. All which, sir, though I most powerfully and +potently believe, yet I hold it not honesty to have it thus set down. +For you yourself, sir, should be old as I am, if like a crab you could +go backward. + +POLONIUS. +[_Aside._] Though this be madness, yet there is method in’t.— +Will you walk out of the air, my lord? + +HAMLET. +Into my grave? + +POLONIUS. +Indeed, that is out o’ the air. [_Aside._] How pregnant sometimes his +replies are! A happiness that often madness hits on, which reason and +sanity could not so prosperously be delivered of. I will leave him and +suddenly contrive the means of meeting between him and my daughter. +My honourable lord, I will most humbly take my leave of you. + +HAMLET. +You cannot, sir, take from me anything that I will more willingly part +withal, except my life, except my life, except my life. + +POLONIUS. +Fare you well, my lord. + +HAMLET. +These tedious old fools. + +Enter Rosencrantz and Guildenstern. + +POLONIUS. +You go to seek the Lord Hamlet; there he is. + +ROSENCRANTZ. +[_To Polonius._] God save you, sir. + +[_Exit Polonius._] + +GUILDENSTERN. +My honoured lord! + +ROSENCRANTZ. +My most dear lord! + +HAMLET. +My excellent good friends! How dost thou, Guildenstern? Ah, +Rosencrantz. Good lads, how do ye both? + +ROSENCRANTZ. +As the indifferent children of the earth. + +GUILDENSTERN. +Happy in that we are not over-happy; +On Fortune’s cap we are not the very button. + +HAMLET. +Nor the soles of her shoe? + +ROSENCRANTZ. +Neither, my lord. + +HAMLET. +Then you live about her waist, or in the middle of her favours? + +GUILDENSTERN. +Faith, her privates we. + +HAMLET. +In the secret parts of Fortune? O, most true; she is a strumpet. What’s +the news? + +ROSENCRANTZ. +None, my lord, but that the world’s grown honest. + +HAMLET. +Then is doomsday near. But your news is not true. Let me question more +in particular. What have you, my good friends, deserved at the hands of +Fortune, that she sends you to prison hither? + +GUILDENSTERN. +Prison, my lord? + +HAMLET. +Denmark’s a prison. + +ROSENCRANTZ. +Then is the world one. + +HAMLET. +A goodly one; in which there are many confines, wards, and dungeons, +Denmark being one o’ th’ worst. + +ROSENCRANTZ. +We think not so, my lord. + +HAMLET. +Why, then ’tis none to you; for there is nothing either good or bad but +thinking makes it so. To me it is a prison. + +ROSENCRANTZ. +Why, then your ambition makes it one; ’tis too narrow for your mind. + +HAMLET. +O God, I could be bounded in a nutshell, and count myself a king of +infinite space, were it not that I have bad dreams. + +GUILDENSTERN. +Which dreams, indeed, are ambition; for the very substance of the +ambitious is merely the shadow of a dream. + +HAMLET. +A dream itself is but a shadow. + +ROSENCRANTZ. +Truly, and I hold ambition of so airy and light a quality that it is +but a shadow’s shadow. + +HAMLET. +Then are our beggars bodies, and our monarchs and outstretch’d heroes +the beggars’ shadows. Shall we to th’ court? For, by my fay, I cannot +reason. + +ROSENCRANTZ and GUILDENSTERN. +We’ll wait upon you. + +HAMLET. +No such matter. I will not sort you with the rest of my servants; for, +to speak to you like an honest man, I am most dreadfully attended. But, +in the beaten way of friendship, what make you at Elsinore? + +ROSENCRANTZ. +To visit you, my lord, no other occasion. + +HAMLET. +Beggar that I am, I am even poor in thanks; but I thank you. And sure, +dear friends, my thanks are too dear a halfpenny. Were you not sent +for? Is it your own inclining? Is it a free visitation? Come, deal +justly with me. Come, come; nay, speak. + +GUILDENSTERN. +What should we say, my lord? + +HAMLET. +Why, anything. But to the purpose. You were sent for; and there is a +kind of confession in your looks, which your modesties have not craft +enough to colour. I know the good King and Queen have sent for you. + +ROSENCRANTZ. +To what end, my lord? + +HAMLET. +That you must teach me. But let me conjure you, by the rights of our +fellowship, by the consonancy of our youth, by the obligation of our +ever-preserved love, and by what more dear a better proposer could +charge you withal, be even and direct with me, whether you were sent +for or no. + +ROSENCRANTZ. +[_To Guildenstern._] What say you? + +HAMLET. +[_Aside._] Nay, then I have an eye of you. If you love me, hold not +off. + +GUILDENSTERN. +My lord, we were sent for. + +HAMLET. +I will tell you why; so shall my anticipation prevent your discovery, +and your secrecy to the King and Queen moult no feather. I have of +late, but wherefore I know not, lost all my mirth, forgone all custom +of exercises; and indeed, it goes so heavily with my disposition that +this goodly frame the earth, seems to me a sterile promontory; this +most excellent canopy the air, look you, this brave o’erhanging +firmament, this majestical roof fretted with golden fire, why, it +appears no other thing to me than a foul and pestilent congregation of +vapours. What a piece of work is man, how noble in reason, how infinite +in faculties, in form and moving, how express and admirable; in action +how like an angel, in apprehension, how like a god: the beauty of the +world, the paragon of animals. And yet, to me, what is this +quintessence of dust? Man delights not me; no, nor woman neither, +though by your smiling you seem to say so. + +ROSENCRANTZ. +My lord, there was no such stuff in my thoughts. + +HAMLET. +Why did you laugh then, when I said ‘Man delights not me’? + +ROSENCRANTZ. +To think, my lord, if you delight not in man, what Lenten entertainment +the players shall receive from you. We coted them on the way, and +hither are they coming to offer you service. + +HAMLET. +He that plays the king shall be welcome,—his Majesty shall have tribute +of me; the adventurous knight shall use his foil and target; the lover +shall not sigh gratis, the humorous man shall end his part in peace; +the clown shall make those laugh whose lungs are tickle o’ th’ sere; +and the lady shall say her mind freely, or the blank verse shall halt +for’t. What players are they? + +ROSENCRANTZ. +Even those you were wont to take such delight in—the tragedians of the +city. + +HAMLET. +How chances it they travel? Their residence, both in reputation and +profit, was better both ways. + +ROSENCRANTZ. +I think their inhibition comes by the means of the late innovation. + +HAMLET. +Do they hold the same estimation they did when I was in the city? Are +they so followed? + +ROSENCRANTZ. +No, indeed, they are not. + +HAMLET. +How comes it? Do they grow rusty? + +ROSENCRANTZ. +Nay, their endeavour keeps in the wonted pace; but there is, sir, an +aerie of children, little eyases, that cry out on the top of question, +and are most tyrannically clapped for’t. These are now the fashion, and +so berattle the common stages—so they call them—that many wearing +rapiers are afraid of goose-quills and dare scarce come thither. + +HAMLET. +What, are they children? Who maintains ’em? How are they escoted? Will +they pursue the quality no longer than they can sing? Will they not say +afterwards, if they should grow themselves to common players—as it is +most like, if their means are no better—their writers do them wrong to +make them exclaim against their own succession? + +ROSENCRANTZ. +Faith, there has been much to do on both sides; and the nation holds it +no sin to tarre them to controversy. There was for a while, no money +bid for argument unless the poet and the player went to cuffs in the +question. + +HAMLET. +Is’t possible? + +GUILDENSTERN. +O, there has been much throwing about of brains. + +HAMLET. +Do the boys carry it away? + +ROSENCRANTZ. +Ay, that they do, my lord. Hercules and his load too. + +HAMLET. +It is not very strange; for my uncle is King of Denmark, and those that +would make mouths at him while my father lived, give twenty, forty, +fifty, a hundred ducats apiece for his picture in little. ’Sblood, +there is something in this more than natural, if philosophy could find +it out. + +[_Flourish of trumpets within._] + +GUILDENSTERN. +There are the players. + +HAMLET. +Gentlemen, you are welcome to Elsinore. Your hands, come. The +appurtenance of welcome is fashion and ceremony. Let me comply with you +in this garb, lest my extent to the players, which I tell you must show +fairly outward, should more appear like entertainment than yours. You +are welcome. But my uncle-father and aunt-mother are deceived. + +GUILDENSTERN. +In what, my dear lord? + +HAMLET. +I am but mad north-north-west. When the wind is southerly, I know a +hawk from a handsaw. + +Enter Polonius. + +POLONIUS. +Well be with you, gentlemen. + +HAMLET. +Hark you, Guildenstern, and you too, at each ear a hearer. That great +baby you see there is not yet out of his swaddling clouts. + +ROSENCRANTZ. +Happily he’s the second time come to them; for they say an old man is +twice a child. + +HAMLET. +I will prophesy he comes to tell me of the players. Mark it.—You say +right, sir: for a Monday morning ’twas so indeed. + +POLONIUS. +My lord, I have news to tell you. + +HAMLET. +My lord, I have news to tell you. When Roscius was an actor in Rome— + +POLONIUS. +The actors are come hither, my lord. + +HAMLET. +Buzz, buzz. + +POLONIUS. +Upon my honour. + +HAMLET. +Then came each actor on his ass— + +POLONIUS. +The best actors in the world, either for tragedy, comedy, history, +pastoral, pastoral-comical, historical-pastoral, tragical-historical, +tragical-comical-historical-pastoral, scene individable, or poem +unlimited. Seneca cannot be too heavy, nor Plautus too light, for the +law of writ and the liberty. These are the only men. + +HAMLET. +O Jephthah, judge of Israel, what a treasure hadst thou! + +POLONIUS. +What treasure had he, my lord? + +HAMLET. +Why— + ’One fair daughter, and no more, + The which he loved passing well.’ + +POLONIUS. +[_Aside._] Still on my daughter. + +HAMLET. +Am I not i’ th’ right, old Jephthah? + +POLONIUS. +If you call me Jephthah, my lord, I have a daughter that I love passing +well. + +HAMLET. +Nay, that follows not. + +POLONIUS. +What follows then, my lord? + +HAMLET. +Why, + As by lot, God wot, +and then, you know, + It came to pass, as most like it was. +The first row of the pious chanson will show you more. For look where +my abridgement comes. + +Enter four or five Players. + +You are welcome, masters, welcome all. I am glad to see thee well. +Welcome, good friends. O, my old friend! Thy face is valanc’d since I +saw thee last. Com’st thou to beard me in Denmark? What, my young lady +and mistress! By’r lady, your ladyship is nearer to heaven than when I +saw you last, by the altitude of a chopine. Pray God your voice, like a +piece of uncurrent gold, be not cracked within the ring. Masters, you +are all welcome. We’ll e’en to’t like French falconers, fly at anything +we see. We’ll have a speech straight. Come, give us a taste of your +quality. Come, a passionate speech. + +FIRST PLAYER. +What speech, my lord? + +HAMLET. +I heard thee speak me a speech once, but it was never acted, or if it +was, not above once, for the play, I remember, pleased not the million, +’twas caviare to the general. But it was—as I received it, and others, +whose judgements in such matters cried in the top of mine—an excellent +play, well digested in the scenes, set down with as much modesty as +cunning. I remember one said there were no sallets in the lines to make +the matter savoury, nor no matter in the phrase that might indite the +author of affectation, but called it an honest method, as wholesome as +sweet, and by very much more handsome than fine. One speech in it, I +chiefly loved. ’Twas Aeneas’ tale to Dido, and thereabout of it +especially where he speaks of Priam’s slaughter. If it live in your +memory, begin at this line, let me see, let me see: + _The rugged Pyrrhus, like th’ Hyrcanian beast,—_ +It is not so: it begins with Pyrrhus— + _The rugged Pyrrhus, he whose sable arms, + Black as his purpose, did the night resemble + When he lay couched in the ominous horse, + Hath now this dread and black complexion smear’d + With heraldry more dismal. Head to foot + Now is he total gules, horridly trick’d + With blood of fathers, mothers, daughters, sons, + Bak’d and impasted with the parching streets, + That lend a tyrannous and a damned light + To their vile murders. Roasted in wrath and fire, + And thus o’ersized with coagulate gore, + With eyes like carbuncles, the hellish Pyrrhus + Old grandsire Priam seeks._ +So, proceed you. + +POLONIUS. +’Fore God, my lord, well spoken, with good accent and good discretion. + +FIRST PLAYER. + _Anon he finds him, + Striking too short at Greeks. His antique sword, + Rebellious to his arm, lies where it falls, + Repugnant to command. Unequal match’d, + Pyrrhus at Priam drives, in rage strikes wide; + But with the whiff and wind of his fell sword + Th’unnerved father falls. Then senseless Ilium, + Seeming to feel this blow, with flaming top + Stoops to his base, and with a hideous crash + Takes prisoner Pyrrhus’ ear. For lo, his sword, + Which was declining on the milky head + Of reverend Priam, seem’d i’ th’air to stick. + So, as a painted tyrant, Pyrrhus stood, + And like a neutral to his will and matter, + Did nothing. + But as we often see against some storm, + A silence in the heavens, the rack stand still, + The bold winds speechless, and the orb below + As hush as death, anon the dreadful thunder + Doth rend the region; so after Pyrrhus’ pause, + Aroused vengeance sets him new a-work, + And never did the Cyclops’ hammers fall + On Mars’s armour, forg’d for proof eterne, + With less remorse than Pyrrhus’ bleeding sword + Now falls on Priam. + Out, out, thou strumpet Fortune! All you gods, + In general synod, take away her power; + Break all the spokes and fellies from her wheel, + And bowl the round nave down the hill of heaven, + As low as to the fiends._ + +POLONIUS. +This is too long. + +HAMLET. +It shall to the barber’s, with your beard.—Prithee say on. +He’s for a jig or a tale of bawdry, or he sleeps. +Say on; come to Hecuba. + +FIRST PLAYER. + _But who, O who, had seen the mobled queen,—_ + +HAMLET. +‘The mobled queen’? + +POLONIUS. +That’s good! ‘Mobled queen’ is good. + +FIRST PLAYER. + _Run barefoot up and down, threat’ning the flames + With bisson rheum. A clout upon that head + Where late the diadem stood, and for a robe, + About her lank and all o’erteemed loins, + A blanket, in th’alarm of fear caught up— + Who this had seen, with tongue in venom steep’d, + ’Gainst Fortune’s state would treason have pronounc’d. + But if the gods themselves did see her then, + When she saw Pyrrhus make malicious sport + In mincing with his sword her husband’s limbs, + The instant burst of clamour that she made,— + Unless things mortal move them not at all,— + Would have made milch the burning eyes of heaven, + And passion in the gods._ + +POLONIUS. +Look, where he has not turn’d his colour, and has tears in’s eyes. Pray +you, no more. + +HAMLET. +’Tis well. I’ll have thee speak out the rest of this soon.—Good my +lord, will you see the players well bestowed? Do you hear, let them be +well used; for they are the abstracts and brief chronicles of the time. +After your death you were better have a bad epitaph than their ill +report while you live. + +POLONIUS. +My lord, I will use them according to their desert. + +HAMLET. +God’s bodikin, man, much better. Use every man after his desert, and who +should ’scape whipping? Use them after your own honour and dignity. The +less they deserve, the more merit is in your bounty. Take them in. + +POLONIUS. +Come, sirs. + +HAMLET. +Follow him, friends. We’ll hear a play tomorrow. + +[_Exeunt Polonius with all the Players but the First._] + +Dost thou hear me, old friend? Can you play _The Murder of Gonzago_? + +FIRST PLAYER. +Ay, my lord. + +HAMLET. +We’ll ha’t tomorrow night. You could for a need study a speech of some +dozen or sixteen lines, which I would set down and insert in’t, could +you not? + +FIRST PLAYER. +Ay, my lord. + +HAMLET. +Very well. Follow that lord, and look you mock him not. + +[_Exit First Player._] + +[_To Rosencrantz and Guildenstern_] My good friends, I’ll leave you +till night. You are welcome to Elsinore. + +ROSENCRANTZ. +Good my lord. + +[_Exeunt Rosencrantz and Guildenstern._] + +HAMLET. +Ay, so, God b’ wi’ ye. Now I am alone. +O what a rogue and peasant slave am I! +Is it not monstrous that this player here, +But in a fiction, in a dream of passion, +Could force his soul so to his own conceit +That from her working all his visage wan’d; +Tears in his eyes, distraction in’s aspect, +A broken voice, and his whole function suiting +With forms to his conceit? And all for nothing! +For Hecuba? +What’s Hecuba to him, or he to Hecuba, +That he should weep for her? What would he do, +Had he the motive and the cue for passion +That I have? He would drown the stage with tears +And cleave the general ear with horrid speech; +Make mad the guilty, and appal the free, +Confound the ignorant, and amaze indeed, +The very faculties of eyes and ears. Yet I, +A dull and muddy-mettled rascal, peak +Like John-a-dreams, unpregnant of my cause, +And can say nothing. No, not for a king +Upon whose property and most dear life +A damn’d defeat was made. Am I a coward? +Who calls me villain, breaks my pate across? +Plucks off my beard and blows it in my face? +Tweaks me by the nose, gives me the lie i’ th’ throat +As deep as to the lungs? Who does me this? +Ha! ’Swounds, I should take it: for it cannot be +But I am pigeon-liver’d, and lack gall +To make oppression bitter, or ere this +I should have fatted all the region kites +With this slave’s offal. Bloody, bawdy villain! +Remorseless, treacherous, lecherous, kindless villain! +Oh vengeance! +Why, what an ass am I! This is most brave, +That I, the son of a dear father murder’d, +Prompted to my revenge by heaven and hell, +Must, like a whore, unpack my heart with words +And fall a-cursing like a very drab, +A scullion! Fie upon’t! Foh! +About, my brain! I have heard +That guilty creatures sitting at a play, +Have by the very cunning of the scene, +Been struck so to the soul that presently +They have proclaim’d their malefactions. +For murder, though it have no tongue, will speak +With most miraculous organ. I’ll have these players +Play something like the murder of my father +Before mine uncle. I’ll observe his looks; +I’ll tent him to the quick. If he but blench, +I know my course. The spirit that I have seen +May be the devil, and the devil hath power +T’assume a pleasing shape, yea, and perhaps +Out of my weakness and my melancholy, +As he is very potent with such spirits, +Abuses me to damn me. I’ll have grounds +More relative than this. The play’s the thing +Wherein I’ll catch the conscience of the King. + +[_Exit._] + + + + +ACT III + +SCENE I. A room in the Castle. + + +Enter King, Queen, Polonius, Ophelia, Rosencrantz and Guildenstern. + +KING. +And can you by no drift of circumstance +Get from him why he puts on this confusion, +Grating so harshly all his days of quiet +With turbulent and dangerous lunacy? + +ROSENCRANTZ. +He does confess he feels himself distracted, +But from what cause he will by no means speak. + +GUILDENSTERN. +Nor do we find him forward to be sounded, +But with a crafty madness keeps aloof +When we would bring him on to some confession +Of his true state. + +QUEEN. +Did he receive you well? + +ROSENCRANTZ. +Most like a gentleman. + +GUILDENSTERN. +But with much forcing of his disposition. + +ROSENCRANTZ. +Niggard of question, but of our demands, +Most free in his reply. + +QUEEN. +Did you assay him to any pastime? + +ROSENCRANTZ. +Madam, it so fell out that certain players +We o’er-raught on the way. Of these we told him, +And there did seem in him a kind of joy +To hear of it. They are about the court, +And, as I think, they have already order +This night to play before him. + +POLONIUS. +’Tis most true; +And he beseech’d me to entreat your Majesties +To hear and see the matter. + +KING. +With all my heart; and it doth much content me +To hear him so inclin’d. +Good gentlemen, give him a further edge, +And drive his purpose on to these delights. + +ROSENCRANTZ. +We shall, my lord. + +[_Exeunt Rosencrantz and Guildenstern._] + +KING. +Sweet Gertrude, leave us too, +For we have closely sent for Hamlet hither, +That he, as ’twere by accident, may here +Affront Ophelia. +Her father and myself, lawful espials, +Will so bestow ourselves that, seeing unseen, +We may of their encounter frankly judge, +And gather by him, as he is behav’d, +If’t be th’affliction of his love or no +That thus he suffers for. + +QUEEN. +I shall obey you. +And for your part, Ophelia, I do wish +That your good beauties be the happy cause +Of Hamlet’s wildness: so shall I hope your virtues +Will bring him to his wonted way again, +To both your honours. + +OPHELIA. +Madam, I wish it may. + +[_Exit Queen._] + +POLONIUS. +Ophelia, walk you here.—Gracious, so please you, +We will bestow ourselves.—[_To Ophelia._] Read on this book, +That show of such an exercise may colour +Your loneliness.—We are oft to blame in this, +’Tis too much prov’d, that with devotion’s visage +And pious action we do sugar o’er +The devil himself. + +KING. +[_Aside._] O ’tis too true! +How smart a lash that speech doth give my conscience! +The harlot’s cheek, beautied with plastering art, +Is not more ugly to the thing that helps it +Than is my deed to my most painted word. +O heavy burden! + +POLONIUS. +I hear him coming. Let’s withdraw, my lord. + +[_Exeunt King and Polonius._] + +Enter Hamlet. + +HAMLET. +To be, or not to be, that is the question: +Whether ’tis nobler in the mind to suffer +The slings and arrows of outrageous fortune, +Or to take arms against a sea of troubles, +And by opposing end them? To die—to sleep, +No more; and by a sleep to say we end +The heart-ache, and the thousand natural shocks +That flesh is heir to: ’tis a consummation +Devoutly to be wish’d. To die, to sleep. +To sleep, perchance to dream—ay, there’s the rub, +For in that sleep of death what dreams may come, +When we have shuffled off this mortal coil, +Must give us pause. There’s the respect +That makes calamity of so long life. +For who would bear the whips and scorns of time, +The oppressor’s wrong, the proud man’s contumely, +The pangs of dispriz’d love, the law’s delay, +The insolence of office, and the spurns +That patient merit of the unworthy takes, +When he himself might his quietus make +With a bare bodkin? Who would these fardels bear, +To grunt and sweat under a weary life, +But that the dread of something after death, +The undiscover’d country, from whose bourn +No traveller returns, puzzles the will, +And makes us rather bear those ills we have +Than fly to others that we know not of? +Thus conscience does make cowards of us all, +And thus the native hue of resolution +Is sicklied o’er with the pale cast of thought, +And enterprises of great pith and moment, +With this regard their currents turn awry +And lose the name of action. Soft you now, +The fair Ophelia! Nymph, in thy orisons +Be all my sins remember’d. + +OPHELIA. +Good my lord, +How does your honour for this many a day? + +HAMLET. +I humbly thank you; well, well, well. + +OPHELIA. +My lord, I have remembrances of yours +That I have longed long to re-deliver. +I pray you, now receive them. + +HAMLET. +No, not I. +I never gave you aught. + +OPHELIA. +My honour’d lord, you know right well you did, +And with them words of so sweet breath compos’d +As made the things more rich; their perfume lost, +Take these again; for to the noble mind +Rich gifts wax poor when givers prove unkind. +There, my lord. + +HAMLET. +Ha, ha! Are you honest? + +OPHELIA. +My lord? + +HAMLET. +Are you fair? + +OPHELIA. +What means your lordship? + +HAMLET. +That if you be honest and fair, your honesty should admit no discourse +to your beauty. + +OPHELIA. +Could beauty, my lord, have better commerce than with honesty? + +HAMLET. +Ay, truly; for the power of beauty will sooner transform honesty from +what it is to a bawd than the force of honesty can translate beauty +into his likeness. This was sometime a paradox, but now the time gives +it proof. I did love you once. + +OPHELIA. +Indeed, my lord, you made me believe so. + +HAMLET. +You should not have believed me; for virtue cannot so inoculate our old +stock but we shall relish of it. I loved you not. + +OPHELIA. +I was the more deceived. + +HAMLET. +Get thee to a nunnery. Why wouldst thou be a breeder of sinners? I am +myself indifferent honest; but yet I could accuse me of such things +that it were better my mother had not borne me. I am very proud, +revengeful, ambitious, with more offences at my beck than I have +thoughts to put them in, imagination to give them shape, or time to act +them in. What should such fellows as I do crawling between earth and +heaven? We are arrant knaves all, believe none of us. Go thy ways to a +nunnery. Where’s your father? + +OPHELIA. +At home, my lord. + +HAMLET. +Let the doors be shut upon him, that he may play the fool nowhere but +in’s own house. Farewell. + +OPHELIA. +O help him, you sweet heavens! + +HAMLET. +If thou dost marry, I’ll give thee this plague for thy dowry. Be thou +as chaste as ice, as pure as snow, thou shalt not escape calumny. Get +thee to a nunnery, go: farewell. Or if thou wilt needs marry, marry a +fool; for wise men know well enough what monsters you make of them. To +a nunnery, go; and quickly too. Farewell. + +OPHELIA. +O heavenly powers, restore him! + +HAMLET. +I have heard of your paintings too, well enough. God hath given you one +face, and you make yourselves another. You jig, you amble, and you +lisp, and nickname God’s creatures, and make your wantonness your +ignorance. Go to, I’ll no more on’t, it hath made me mad. I say, we +will have no more marriages. Those that are married already, all but +one, shall live; the rest shall keep as they are. To a nunnery, go. + +[_Exit._] + +OPHELIA. +O, what a noble mind is here o’erthrown! +The courtier’s, soldier’s, scholar’s, eye, tongue, sword, +Th’expectancy and rose of the fair state, +The glass of fashion and the mould of form, +Th’observ’d of all observers, quite, quite down! +And I, of ladies most deject and wretched, +That suck’d the honey of his music vows, +Now see that noble and most sovereign reason, +Like sweet bells jangled out of tune and harsh, +That unmatch’d form and feature of blown youth +Blasted with ecstasy. O woe is me, +T’have seen what I have seen, see what I see. + +Enter King and Polonius. + +KING. +Love? His affections do not that way tend, +Nor what he spake, though it lack’d form a little, +Was not like madness. There’s something in his soul +O’er which his melancholy sits on brood, +And I do doubt the hatch and the disclose +Will be some danger, which for to prevent, +I have in quick determination +Thus set it down: he shall with speed to England +For the demand of our neglected tribute: +Haply the seas and countries different, +With variable objects, shall expel +This something settled matter in his heart, +Whereon his brains still beating puts him thus +From fashion of himself. What think you on’t? + +POLONIUS. +It shall do well. But yet do I believe +The origin and commencement of his grief +Sprung from neglected love. How now, Ophelia? +You need not tell us what Lord Hamlet said, +We heard it all. My lord, do as you please, +But if you hold it fit, after the play, +Let his queen mother all alone entreat him +To show his grief, let her be round with him, +And I’ll be plac’d, so please you, in the ear +Of all their conference. If she find him not, +To England send him; or confine him where +Your wisdom best shall think. + +KING. +It shall be so. +Madness in great ones must not unwatch’d go. + +[_Exeunt._] + + SCENE II. A hall in the Castle. + +Enter Hamlet and certain Players. + +HAMLET. +Speak the speech, I pray you, as I pronounced it to you, trippingly on +the tongue. But if you mouth it, as many of your players do, I had as +lief the town-crier spoke my lines. Nor do not saw the air too much +with your hand, thus, but use all gently; for in the very torrent, +tempest, and, as I may say, whirlwind of passion, you must acquire and +beget a temperance that may give it smoothness. O, it offends me to the +soul to hear a robustious periwig-pated fellow tear a passion to +tatters, to very rags, to split the ears of the groundlings, who, for +the most part, are capable of nothing but inexplicable dumb shows and +noise. I would have such a fellow whipped for o’erdoing Termagant. It +out-Herods Herod. Pray you avoid it. + +FIRST PLAYER. +I warrant your honour. + +HAMLET. +Be not too tame neither; but let your own discretion be your tutor. +Suit the action to the word, the word to the action, with this special +observance, that you o’erstep not the modesty of nature; for anything +so overdone is from the purpose of playing, whose end, both at the +first and now, was and is, to hold as ’twere the mirror up to nature; +to show virtue her own feature, scorn her own image, and the very age +and body of the time his form and pressure. Now, this overdone, or come +tardy off, though it make the unskilful laugh, cannot but make the +judicious grieve; the censure of the which one must in your allowance +o’erweigh a whole theatre of others. O, there be players that I have +seen play—and heard others praise, and that highly—not to speak it +profanely, that, neither having the accent of Christians, nor the gait +of Christian, pagan, nor man, have so strutted and bellowed that I have +thought some of Nature’s journeymen had made men, and not made them +well, they imitated humanity so abominably. + +FIRST PLAYER. +I hope we have reform’d that indifferently with us, sir. + +HAMLET. +O reform it altogether. And let those that play your clowns speak no +more than is set down for them. For there be of them that will +themselves laugh, to set on some quantity of barren spectators to laugh +too, though in the meantime some necessary question of the play be then +to be considered. That’s villainous, and shows a most pitiful ambition +in the fool that uses it. Go make you ready. + +[_Exeunt Players._] + +Enter Polonius, Rosencrantz and Guildenstern. + +How now, my lord? +Will the King hear this piece of work? + +POLONIUS. +And the Queen too, and that presently. + +HAMLET. +Bid the players make haste. + +[_Exit Polonius._] + +Will you two help to hasten them? + +ROSENCRANTZ and GUILDENSTERN. +We will, my lord. + +[_Exeunt Rosencrantz and Guildenstern._] + +HAMLET. +What ho, Horatio! + +Enter Horatio. + +HORATIO. +Here, sweet lord, at your service. + +HAMLET. +Horatio, thou art e’en as just a man +As e’er my conversation cop’d withal. + +HORATIO. +O my dear lord. + +HAMLET. +Nay, do not think I flatter; +For what advancement may I hope from thee, +That no revenue hast, but thy good spirits +To feed and clothe thee? Why should the poor be flatter’d? +No, let the candied tongue lick absurd pomp, +And crook the pregnant hinges of the knee +Where thrift may follow fawning. Dost thou hear? +Since my dear soul was mistress of her choice, +And could of men distinguish, her election +Hath seal’d thee for herself. For thou hast been +As one, in suffering all, that suffers nothing, +A man that Fortune’s buffets and rewards +Hast ta’en with equal thanks. And blessed are those +Whose blood and judgement are so well co-mingled +That they are not a pipe for Fortune’s finger +To sound what stop she please. Give me that man +That is not passion’s slave, and I will wear him +In my heart’s core, ay, in my heart of heart, +As I do thee. Something too much of this. +There is a play tonight before the King. +One scene of it comes near the circumstance +Which I have told thee, of my father’s death. +I prithee, when thou see’st that act a-foot, +Even with the very comment of thy soul +Observe mine uncle. If his occulted guilt +Do not itself unkennel in one speech, +It is a damned ghost that we have seen; +And my imaginations are as foul +As Vulcan’s stithy. Give him heedful note; +For I mine eyes will rivet to his face; +And after we will both our judgements join +In censure of his seeming. + +HORATIO. +Well, my lord. +If he steal aught the whilst this play is playing, +And ’scape detecting, I will pay the theft. + +HAMLET. +They are coming to the play. I must be idle. +Get you a place. + +Danish march. A flourish. Enter King, Queen, Polonius, Ophelia, +Rosencrantz, Guildenstern and others. + +KING. +How fares our cousin Hamlet? + +HAMLET. +Excellent, i’ faith; of the chameleon’s dish: I eat the air, +promise-crammed: you cannot feed capons so. + +KING. +I have nothing with this answer, Hamlet; these words are not mine. + +HAMLET. +No, nor mine now. [_To Polonius._] My lord, you play’d once i’ +th’university, you say? + +POLONIUS. +That did I, my lord, and was accounted a good actor. + +HAMLET. +What did you enact? + +POLONIUS. +I did enact Julius Caesar. I was kill’d i’ th’ Capitol. Brutus killed +me. + +HAMLET. +It was a brute part of him to kill so capital a calf there. Be the +players ready? + +ROSENCRANTZ. +Ay, my lord; they stay upon your patience. + +QUEEN. +Come hither, my dear Hamlet, sit by me. + +HAMLET. +No, good mother, here’s metal more attractive. + +POLONIUS. +[_To the King._] O ho! do you mark that? + +HAMLET. +Lady, shall I lie in your lap? + +[_Lying down at Ophelia’s feet._] + +OPHELIA. +No, my lord. + +HAMLET. +I mean, my head upon your lap? + +OPHELIA. +Ay, my lord. + +HAMLET. +Do you think I meant country matters? + +OPHELIA. +I think nothing, my lord. + +HAMLET. +That’s a fair thought to lie between maids’ legs. + +OPHELIA. +What is, my lord? + +HAMLET. +Nothing. + +OPHELIA. +You are merry, my lord. + +HAMLET. +Who, I? + +OPHELIA. +Ay, my lord. + +HAMLET. +O God, your only jig-maker! What should a man do but be merry? For look +you how cheerfully my mother looks, and my father died within’s two +hours. + +OPHELIA. +Nay, ’tis twice two months, my lord. + +HAMLET. +So long? Nay then, let the devil wear black, for I’ll have a suit of +sables. O heavens! die two months ago, and not forgotten yet? Then +there’s hope a great man’s memory may outlive his life half a year. But +by’r lady, he must build churches then; or else shall he suffer not +thinking on, with the hobby-horse, whose epitaph is ‘For, O, for O, the +hobby-horse is forgot!’ + +Trumpets sound. The dumb show enters. + +_Enter a King and a Queen very lovingly; the Queen embracing him and he +her. She kneels, and makes show of protestation unto him. He takes her +up, and declines his head upon her neck. Lays him down upon a bank of +flowers. She, seeing him asleep, leaves him. Anon comes in a fellow, +takes off his crown, kisses it, pours poison in the King’s ears, and +exits. The Queen returns, finds the King dead, and makes passionate +action. The Poisoner with some three or four Mutes, comes in again, +seeming to lament with her. The dead body is carried away. The Poisoner +woos the Queen with gifts. She seems loth and unwilling awhile, but in +the end accepts his love._ + +[_Exeunt._] + +OPHELIA. +What means this, my lord? + +HAMLET. +Marry, this is miching mallecho; it means mischief. + +OPHELIA. +Belike this show imports the argument of the play. + +Enter Prologue. + +HAMLET. +We shall know by this fellow: the players cannot keep counsel; they’ll +tell all. + +OPHELIA. +Will they tell us what this show meant? + +HAMLET. +Ay, or any show that you’ll show him. Be not you ashamed to show, he’ll +not shame to tell you what it means. + +OPHELIA. +You are naught, you are naught: I’ll mark the play. + +PROLOGUE. + _For us, and for our tragedy, + Here stooping to your clemency, + We beg your hearing patiently._ + +HAMLET. +Is this a prologue, or the posy of a ring? + +OPHELIA. +’Tis brief, my lord. + +HAMLET. +As woman’s love. + +Enter a King and a Queen. + +PLAYER KING. +Full thirty times hath Phoebus’ cart gone round +Neptune’s salt wash and Tellus’ orbed ground, +And thirty dozen moons with borrow’d sheen +About the world have times twelve thirties been, +Since love our hearts, and Hymen did our hands +Unite commutual in most sacred bands. + +PLAYER QUEEN. +So many journeys may the sun and moon +Make us again count o’er ere love be done. +But, woe is me, you are so sick of late, +So far from cheer and from your former state, +That I distrust you. Yet, though I distrust, +Discomfort you, my lord, it nothing must: +For women’s fear and love holds quantity, +In neither aught, or in extremity. +Now what my love is, proof hath made you know, +And as my love is siz’d, my fear is so. +Where love is great, the littlest doubts are fear; +Where little fears grow great, great love grows there. + +PLAYER KING. +Faith, I must leave thee, love, and shortly too: +My operant powers their functions leave to do: +And thou shalt live in this fair world behind, +Honour’d, belov’d, and haply one as kind +For husband shalt thou— + +PLAYER QUEEN. +O confound the rest. +Such love must needs be treason in my breast. +In second husband let me be accurst! +None wed the second but who kill’d the first. + +HAMLET. +[_Aside._] Wormwood, wormwood. + +PLAYER QUEEN. +The instances that second marriage move +Are base respects of thrift, but none of love. +A second time I kill my husband dead, +When second husband kisses me in bed. + +PLAYER KING. +I do believe you think what now you speak; +But what we do determine, oft we break. +Purpose is but the slave to memory, +Of violent birth, but poor validity: +Which now, like fruit unripe, sticks on the tree, +But fall unshaken when they mellow be. +Most necessary ’tis that we forget +To pay ourselves what to ourselves is debt. +What to ourselves in passion we propose, +The passion ending, doth the purpose lose. +The violence of either grief or joy +Their own enactures with themselves destroy. +Where joy most revels, grief doth most lament; +Grief joys, joy grieves, on slender accident. +This world is not for aye; nor ’tis not strange +That even our loves should with our fortunes change, +For ’tis a question left us yet to prove, +Whether love lead fortune, or else fortune love. +The great man down, you mark his favourite flies, +The poor advanc’d makes friends of enemies; +And hitherto doth love on fortune tend: +For who not needs shall never lack a friend, +And who in want a hollow friend doth try, +Directly seasons him his enemy. +But orderly to end where I begun, +Our wills and fates do so contrary run +That our devices still are overthrown. +Our thoughts are ours, their ends none of our own. +So think thou wilt no second husband wed, +But die thy thoughts when thy first lord is dead. + +PLAYER QUEEN. +Nor earth to me give food, nor heaven light, +Sport and repose lock from me day and night, +To desperation turn my trust and hope, +An anchor’s cheer in prison be my scope, +Each opposite that blanks the face of joy, +Meet what I would have well, and it destroy! +Both here and hence pursue me lasting strife, +If, once a widow, ever I be wife. + +HAMLET. +[_To Ophelia._] If she should break it now. + +PLAYER KING. +’Tis deeply sworn. Sweet, leave me here awhile. +My spirits grow dull, and fain I would beguile +The tedious day with sleep. +[_Sleeps._] + +PLAYER QUEEN. +Sleep rock thy brain, +And never come mischance between us twain. + +[_Exit._] + +HAMLET. +Madam, how like you this play? + +QUEEN. +The lady protests too much, methinks. + +HAMLET. +O, but she’ll keep her word. + +KING. +Have you heard the argument? Is there no offence in’t? + +HAMLET. +No, no, they do but jest, poison in jest; no offence i’ th’ world. + +KING. +What do you call the play? + +HAMLET. +_The Mousetrap._ Marry, how? Tropically. This play is the image of a +murder done in Vienna. Gonzago is the Duke’s name, his wife Baptista: +you shall see anon; ’tis a knavish piece of work: but what o’ that? +Your majesty, and we that have free souls, it touches us not. Let the +gall’d jade wince; our withers are unwrung. + +Enter Lucianus. + +This is one Lucianus, nephew to the King. + +OPHELIA. +You are a good chorus, my lord. + +HAMLET. +I could interpret between you and your love, if I could see the puppets +dallying. + +OPHELIA. +You are keen, my lord, you are keen. + +HAMLET. +It would cost you a groaning to take off my edge. + +OPHELIA. +Still better, and worse. + +HAMLET. +So you mistake your husbands.—Begin, murderer. Pox, leave thy damnable +faces, and begin. Come, the croaking raven doth bellow for revenge. + +LUCIANUS. +Thoughts black, hands apt, drugs fit, and time agreeing, +Confederate season, else no creature seeing; +Thou mixture rank, of midnight weeds collected, +With Hecate’s ban thrice blasted, thrice infected, +Thy natural magic and dire property +On wholesome life usurp immediately. + +[_Pours the poison into the sleeper’s ears._] + +HAMLET. +He poisons him i’ th’garden for’s estate. His name’s Gonzago. The story +is extant, and written in very choice Italian. You shall see anon how +the murderer gets the love of Gonzago’s wife. + +OPHELIA. +The King rises. + +HAMLET. +What, frighted with false fire? + +QUEEN. +How fares my lord? + +POLONIUS. +Give o’er the play. + +KING. +Give me some light. Away. + +All. +Lights, lights, lights. + +[_Exeunt all but Hamlet and Horatio._] + +HAMLET. + Why, let the strucken deer go weep, + The hart ungalled play; + For some must watch, while some must sleep, + So runs the world away. +Would not this, sir, and a forest of feathers, if the rest of my +fortunes turn Turk with me; with two Provincial roses on my razed +shoes, get me a fellowship in a cry of players, sir? + +HORATIO. +Half a share. + +HAMLET. +A whole one, I. + For thou dost know, O Damon dear, + This realm dismantled was + Of Jove himself, and now reigns here + A very, very—pajock. + +HORATIO. +You might have rhymed. + +HAMLET. +O good Horatio, I’ll take the ghost’s word for a thousand pound. Didst +perceive? + +HORATIO. +Very well, my lord. + +HAMLET. +Upon the talk of the poisoning? + +HORATIO. +I did very well note him. + +HAMLET. +Ah, ha! Come, some music. Come, the recorders. + For if the king like not the comedy, + Why then, belike he likes it not, perdie. +Come, some music. + +Enter Rosencrantz and Guildenstern. + +GUILDENSTERN. +Good my lord, vouchsafe me a word with you. + +HAMLET. +Sir, a whole history. + +GUILDENSTERN. +The King, sir— + +HAMLET. +Ay, sir, what of him? + +GUILDENSTERN. +Is in his retirement, marvellous distempered. + +HAMLET. +With drink, sir? + +GUILDENSTERN. +No, my lord; rather with choler. + +HAMLET. +Your wisdom should show itself more richer to signify this to the +doctor, for me to put him to his purgation would perhaps plunge him +into far more choler. + +GUILDENSTERN. +Good my lord, put your discourse into some frame, and start not so +wildly from my affair. + +HAMLET. +I am tame, sir, pronounce. + +GUILDENSTERN. +The Queen your mother, in most great affliction of spirit, hath sent me +to you. + +HAMLET. +You are welcome. + +GUILDENSTERN. +Nay, good my lord, this courtesy is not of the right breed. If it shall +please you to make me a wholesome answer, I will do your mother’s +commandment; if not, your pardon and my return shall be the end of my +business. + +HAMLET. +Sir, I cannot. + +GUILDENSTERN. +What, my lord? + +HAMLET. +Make you a wholesome answer. My wit’s diseased. But, sir, such answer +as I can make, you shall command; or rather, as you say, my mother. +Therefore no more, but to the matter. My mother, you say,— + +ROSENCRANTZ. +Then thus she says: your behaviour hath struck her into amazement and +admiration. + +HAMLET. +O wonderful son, that can so stonish a mother! But is there no sequel +at the heels of this mother’s admiration? + +ROSENCRANTZ. +She desires to speak with you in her closet ere you go to bed. + +HAMLET. +We shall obey, were she ten times our mother. Have you any further +trade with us? + +ROSENCRANTZ. +My lord, you once did love me. + +HAMLET. +And so I do still, by these pickers and stealers. + +ROSENCRANTZ. +Good my lord, what is your cause of distemper? You do surely bar the +door upon your own liberty if you deny your griefs to your friend. + +HAMLET. +Sir, I lack advancement. + +ROSENCRANTZ. +How can that be, when you have the voice of the King himself for your +succession in Denmark? + +HAMLET. +Ay, sir, but while the grass grows—the proverb is something musty. + +Re-enter the Players with recorders. + +O, the recorders. Let me see one.—To withdraw with you, why do you go +about to recover the wind of me, as if you would drive me into a toil? + +GUILDENSTERN. +O my lord, if my duty be too bold, my love is too unmannerly. + +HAMLET. +I do not well understand that. Will you play upon this pipe? + +GUILDENSTERN. +My lord, I cannot. + +HAMLET. +I pray you. + +GUILDENSTERN. +Believe me, I cannot. + +HAMLET. +I do beseech you. + +GUILDENSTERN. +I know no touch of it, my lord. + +HAMLET. +’Tis as easy as lying: govern these ventages with your finger and +thumb, give it breath with your mouth, and it will discourse most +eloquent music. Look you, these are the stops. + +GUILDENSTERN. +But these cannot I command to any utterance of harmony. I have not the +skill. + +HAMLET. +Why, look you now, how unworthy a thing you make of me! You would play +upon me; you would seem to know my stops; you would pluck out the heart +of my mystery; you would sound me from my lowest note to the top of my +compass; and there is much music, excellent voice, in this little +organ, yet cannot you make it speak. ’Sblood, do you think I am easier +to be played on than a pipe? Call me what instrument you will, though +you can fret me, you cannot play upon me. + +Enter Polonius. + +God bless you, sir. + +POLONIUS. +My lord, the Queen would speak with you, and presently. + +HAMLET. +Do you see yonder cloud that’s almost in shape of a camel? + +POLONIUS. +By the mass, and ’tis like a camel indeed. + +HAMLET. +Methinks it is like a weasel. + +POLONIUS. +It is backed like a weasel. + +HAMLET. +Or like a whale. + +POLONIUS. +Very like a whale. + +HAMLET. +Then will I come to my mother by and by.—They fool me to the top of my +bent.—I will come by and by. + +POLONIUS. +I will say so. + +[_Exit._] + +HAMLET. +By and by is easily said. Leave me, friends. + +[_Exeunt all but Hamlet._] + +’Tis now the very witching time of night, +When churchyards yawn, and hell itself breathes out +Contagion to this world. Now could I drink hot blood, +And do such bitter business as the day +Would quake to look on. Soft now, to my mother. +O heart, lose not thy nature; let not ever +The soul of Nero enter this firm bosom: +Let me be cruel, not unnatural. +I will speak daggers to her, but use none; +My tongue and soul in this be hypocrites. +How in my words somever she be shent, +To give them seals never, my soul, consent. + +[_Exit._] + + SCENE III. A room in the Castle. + +Enter King, Rosencrantz and Guildenstern. + +KING. +I like him not, nor stands it safe with us +To let his madness range. Therefore prepare you, +I your commission will forthwith dispatch, +And he to England shall along with you. +The terms of our estate may not endure +Hazard so near us as doth hourly grow +Out of his lunacies. + +GUILDENSTERN. +We will ourselves provide. +Most holy and religious fear it is +To keep those many many bodies safe +That live and feed upon your Majesty. + +ROSENCRANTZ. +The single and peculiar life is bound +With all the strength and armour of the mind, +To keep itself from ’noyance; but much more +That spirit upon whose weal depend and rest +The lives of many. The cease of majesty +Dies not alone; but like a gulf doth draw +What’s near it with it. It is a massy wheel +Fix’d on the summit of the highest mount, +To whose huge spokes ten thousand lesser things +Are mortis’d and adjoin’d; which when it falls, +Each small annexment, petty consequence, +Attends the boist’rous ruin. Never alone +Did the King sigh, but with a general groan. + +KING. +Arm you, I pray you, to this speedy voyage; +For we will fetters put upon this fear, +Which now goes too free-footed. + +ROSENCRANTZ and GUILDENSTERN. +We will haste us. + +[_Exeunt Rosencrantz and Guildenstern._] + +Enter Polonius. + +POLONIUS. +My lord, he’s going to his mother’s closet. +Behind the arras I’ll convey myself +To hear the process. I’ll warrant she’ll tax him home, +And as you said, and wisely was it said, +’Tis meet that some more audience than a mother, +Since nature makes them partial, should o’erhear +The speech of vantage. Fare you well, my liege, +I’ll call upon you ere you go to bed, +And tell you what I know. + +KING. +Thanks, dear my lord. + +[_Exit Polonius._] + +O, my offence is rank, it smells to heaven; +It hath the primal eldest curse upon’t,— +A brother’s murder! Pray can I not, +Though inclination be as sharp as will: +My stronger guilt defeats my strong intent, +And, like a man to double business bound, +I stand in pause where I shall first begin, +And both neglect. What if this cursed hand +Were thicker than itself with brother’s blood, +Is there not rain enough in the sweet heavens +To wash it white as snow? Whereto serves mercy +But to confront the visage of offence? +And what’s in prayer but this twofold force, +To be forestalled ere we come to fall, +Or pardon’d being down? Then I’ll look up. +My fault is past. But O, what form of prayer +Can serve my turn? Forgive me my foul murder! +That cannot be; since I am still possess’d +Of those effects for which I did the murder,— +My crown, mine own ambition, and my queen. +May one be pardon’d and retain th’offence? +In the corrupted currents of this world +Offence’s gilded hand may shove by justice, +And oft ’tis seen the wicked prize itself +Buys out the law. But ’tis not so above; +There is no shuffling, there the action lies +In his true nature, and we ourselves compell’d +Even to the teeth and forehead of our faults, +To give in evidence. What then? What rests? +Try what repentance can. What can it not? +Yet what can it, when one cannot repent? +O wretched state! O bosom black as death! +O limed soul, that struggling to be free, +Art more engag’d! Help, angels! Make assay: +Bow, stubborn knees; and heart with strings of steel, +Be soft as sinews of the new-born babe. +All may be well. + +[_Retires and kneels._] + +Enter Hamlet. + +HAMLET. +Now might I do it pat, now he is praying. +And now I’ll do’t. And so he goes to heaven; +And so am I reveng’d. That would be scann’d: +A villain kills my father, and for that +I, his sole son, do this same villain send +To heaven. O, this is hire and salary, not revenge. +He took my father grossly, full of bread, +With all his crimes broad blown, as flush as May; +And how his audit stands, who knows save heaven? +But in our circumstance and course of thought, +’Tis heavy with him. And am I then reveng’d, +To take him in the purging of his soul, +When he is fit and season’d for his passage? No. +Up, sword, and know thou a more horrid hent: +When he is drunk asleep; or in his rage, +Or in th’incestuous pleasure of his bed, +At gaming, swearing; or about some act +That has no relish of salvation in’t, +Then trip him, that his heels may kick at heaven, +And that his soul may be as damn’d and black +As hell, whereto it goes. My mother stays. +This physic but prolongs thy sickly days. + +[_Exit._] + +The King rises and advances. + +KING. +My words fly up, my thoughts remain below. +Words without thoughts never to heaven go. + +[_Exit._] + + SCENE IV. Another room in the Castle. + +Enter Queen and Polonius. + +POLONIUS. +He will come straight. Look you lay home to him, +Tell him his pranks have been too broad to bear with, +And that your Grace hath screen’d and stood between +Much heat and him. I’ll silence me e’en here. +Pray you be round with him. + +HAMLET. +[_Within._] Mother, mother, mother. + +QUEEN. +I’ll warrant you, Fear me not. +Withdraw, I hear him coming. + +[_Polonius goes behind the arras._] + +Enter Hamlet. + +HAMLET. +Now, mother, what’s the matter? + +QUEEN. +Hamlet, thou hast thy father much offended. + +HAMLET. +Mother, you have my father much offended. + +QUEEN. +Come, come, you answer with an idle tongue. + +HAMLET. +Go, go, you question with a wicked tongue. + +QUEEN. +Why, how now, Hamlet? + +HAMLET. +What’s the matter now? + +QUEEN. +Have you forgot me? + +HAMLET. +No, by the rood, not so. +You are the Queen, your husband’s brother’s wife, +And, would it were not so. You are my mother. + +QUEEN. +Nay, then I’ll set those to you that can speak. + +HAMLET. +Come, come, and sit you down, you shall not budge. +You go not till I set you up a glass +Where you may see the inmost part of you. + +QUEEN. +What wilt thou do? Thou wilt not murder me? +Help, help, ho! + +POLONIUS. +[_Behind._] What, ho! help, help, help! + +HAMLET. +How now? A rat? [_Draws._] +Dead for a ducat, dead! + +[_Makes a pass through the arras._] + +POLONIUS. +[_Behind._] O, I am slain! + +[_Falls and dies._] + +QUEEN. +O me, what hast thou done? + +HAMLET. +Nay, I know not. Is it the King? + +[_Draws forth Polonius._] + +QUEEN. +O what a rash and bloody deed is this! + +HAMLET. +A bloody deed. Almost as bad, good mother, +As kill a king and marry with his brother. + +QUEEN. +As kill a king? + +HAMLET. +Ay, lady, ’twas my word.— +[_To Polonius._] Thou wretched, rash, intruding fool, farewell! +I took thee for thy better. Take thy fortune, +Thou find’st to be too busy is some danger.— +Leave wringing of your hands. Peace, sit you down, +And let me wring your heart, for so I shall, +If it be made of penetrable stuff; +If damned custom have not braz’d it so, +That it is proof and bulwark against sense. + +QUEEN. +What have I done, that thou dar’st wag thy tongue +In noise so rude against me? + +HAMLET. +Such an act +That blurs the grace and blush of modesty, +Calls virtue hypocrite, takes off the rose +From the fair forehead of an innocent love, +And sets a blister there. Makes marriage vows +As false as dicers’ oaths. O such a deed +As from the body of contraction plucks +The very soul, and sweet religion makes +A rhapsody of words. Heaven’s face doth glow, +Yea this solidity and compound mass, +With tristful visage, as against the doom, +Is thought-sick at the act. + +QUEEN. +Ay me, what act, +That roars so loud, and thunders in the index? + +HAMLET. +Look here upon this picture, and on this, +The counterfeit presentment of two brothers. +See what a grace was seated on this brow, +Hyperion’s curls, the front of Jove himself, +An eye like Mars, to threaten and command, +A station like the herald Mercury +New lighted on a heaven-kissing hill: +A combination and a form indeed, +Where every god did seem to set his seal, +To give the world assurance of a man. +This was your husband. Look you now what follows. +Here is your husband, like a mildew’d ear +Blasting his wholesome brother. Have you eyes? +Could you on this fair mountain leave to feed, +And batten on this moor? Ha! have you eyes? +You cannot call it love; for at your age +The hey-day in the blood is tame, it’s humble, +And waits upon the judgement: and what judgement +Would step from this to this? Sense sure you have, +Else could you not have motion; but sure that sense +Is apoplex’d, for madness would not err +Nor sense to ecstacy was ne’er so thrall’d +But it reserv’d some quantity of choice +To serve in such a difference. What devil was’t +That thus hath cozen’d you at hoodman-blind? +Eyes without feeling, feeling without sight, +Ears without hands or eyes, smelling sans all, +Or but a sickly part of one true sense +Could not so mope. O shame! where is thy blush? +Rebellious hell, +If thou canst mutine in a matron’s bones, +To flaming youth let virtue be as wax, +And melt in her own fire. Proclaim no shame +When the compulsive ardour gives the charge, +Since frost itself as actively doth burn, +And reason panders will. + +QUEEN. +O Hamlet, speak no more. +Thou turn’st mine eyes into my very soul, +And there I see such black and grained spots +As will not leave their tinct. + +HAMLET. +Nay, but to live +In the rank sweat of an enseamed bed, +Stew’d in corruption, honeying and making love +Over the nasty sty. + +QUEEN. +O speak to me no more; +These words like daggers enter in mine ears; +No more, sweet Hamlet. + +HAMLET. +A murderer and a villain; +A slave that is not twentieth part the tithe +Of your precedent lord. A vice of kings, +A cutpurse of the empire and the rule, +That from a shelf the precious diadem stole +And put it in his pocket! + +QUEEN. +No more. + +HAMLET. +A king of shreds and patches!— + +Enter Ghost. + +Save me and hover o’er me with your wings, +You heavenly guards! What would your gracious figure? + +QUEEN. +Alas, he’s mad. + +HAMLET. +Do you not come your tardy son to chide, +That, laps’d in time and passion, lets go by +The important acting of your dread command? +O say! + +GHOST. +Do not forget. This visitation +Is but to whet thy almost blunted purpose. +But look, amazement on thy mother sits. +O step between her and her fighting soul. +Conceit in weakest bodies strongest works. +Speak to her, Hamlet. + +HAMLET. +How is it with you, lady? + +QUEEN. +Alas, how is’t with you, +That you do bend your eye on vacancy, +And with the incorporal air do hold discourse? +Forth at your eyes your spirits wildly peep, +And, as the sleeping soldiers in the alarm, +Your bedded hairs, like life in excrements, +Start up and stand an end. O gentle son, +Upon the heat and flame of thy distemper +Sprinkle cool patience. Whereon do you look? + +HAMLET. +On him, on him! Look you how pale he glares, +His form and cause conjoin’d, preaching to stones, +Would make them capable.—Do not look upon me, +Lest with this piteous action you convert +My stern effects. Then what I have to do +Will want true colour; tears perchance for blood. + +QUEEN. +To whom do you speak this? + +HAMLET. +Do you see nothing there? + +QUEEN. +Nothing at all; yet all that is I see. + +HAMLET. +Nor did you nothing hear? + +QUEEN. +No, nothing but ourselves. + +HAMLET. +Why, look you there! look how it steals away! +My father, in his habit as he liv’d! +Look where he goes even now out at the portal. + +[_Exit Ghost._] + +QUEEN. +This is the very coinage of your brain. +This bodiless creation ecstasy +Is very cunning in. + +HAMLET. +Ecstasy! +My pulse as yours doth temperately keep time, +And makes as healthful music. It is not madness +That I have utter’d. Bring me to the test, +And I the matter will re-word; which madness +Would gambol from. Mother, for love of grace, +Lay not that flattering unction to your soul +That not your trespass, but my madness speaks. +It will but skin and film the ulcerous place, +Whilst rank corruption, mining all within, +Infects unseen. Confess yourself to heaven, +Repent what’s past, avoid what is to come; +And do not spread the compost on the weeds, +To make them ranker. Forgive me this my virtue; +For in the fatness of these pursy times +Virtue itself of vice must pardon beg, +Yea, curb and woo for leave to do him good. + +QUEEN. +O Hamlet, thou hast cleft my heart in twain. + +HAMLET. +O throw away the worser part of it, +And live the purer with the other half. +Good night. But go not to mine uncle’s bed. +Assume a virtue, if you have it not. +That monster custom, who all sense doth eat, +Of habits evil, is angel yet in this, +That to the use of actions fair and good +He likewise gives a frock or livery +That aptly is put on. Refrain tonight, +And that shall lend a kind of easiness +To the next abstinence. The next more easy; +For use almost can change the stamp of nature, +And either curb the devil, or throw him out +With wondrous potency. Once more, good night, +And when you are desirous to be bles’d, +I’ll blessing beg of you. For this same lord +[_Pointing to Polonius._] +I do repent; but heaven hath pleas’d it so, +To punish me with this, and this with me, +That I must be their scourge and minister. +I will bestow him, and will answer well +The death I gave him. So again, good night. +I must be cruel, only to be kind: +Thus bad begins, and worse remains behind. +One word more, good lady. + +QUEEN. +What shall I do? + +HAMLET. +Not this, by no means, that I bid you do: +Let the bloat King tempt you again to bed, +Pinch wanton on your cheek, call you his mouse, +And let him, for a pair of reechy kisses, +Or paddling in your neck with his damn’d fingers, +Make you to ravel all this matter out, +That I essentially am not in madness, +But mad in craft. ’Twere good you let him know, +For who that’s but a queen, fair, sober, wise, +Would from a paddock, from a bat, a gib, +Such dear concernings hide? Who would do so? +No, in despite of sense and secrecy, +Unpeg the basket on the house’s top, +Let the birds fly, and like the famous ape, +To try conclusions, in the basket creep +And break your own neck down. + +QUEEN. +Be thou assur’d, if words be made of breath, +And breath of life, I have no life to breathe +What thou hast said to me. + +HAMLET. +I must to England, you know that? + +QUEEN. +Alack, +I had forgot. ’Tis so concluded on. + +HAMLET. +There’s letters seal’d: and my two schoolfellows, +Whom I will trust as I will adders fang’d,— +They bear the mandate, they must sweep my way +And marshal me to knavery. Let it work; +For ’tis the sport to have the enginer +Hoist with his own petard, and ’t shall go hard +But I will delve one yard below their mines +And blow them at the moon. O, ’tis most sweet, +When in one line two crafts directly meet. +This man shall set me packing. +I’ll lug the guts into the neighbour room. +Mother, good night. Indeed, this counsellor +Is now most still, most secret, and most grave, +Who was in life a foolish prating knave. +Come, sir, to draw toward an end with you. +Good night, mother. + +[_Exit Hamlet dragging out Polonius._] + + + + +ACT IV + +SCENE I. A room in the Castle. + + +Enter King, Queen, Rosencrantz and Guildenstern. + +KING. +There’s matter in these sighs. These profound heaves +You must translate; ’tis fit we understand them. +Where is your son? + +QUEEN. +Bestow this place on us a little while. + +[_To Rosencrantz and Guildenstern, who go out._] + +Ah, my good lord, what have I seen tonight! + +KING. +What, Gertrude? How does Hamlet? + +QUEEN. +Mad as the sea and wind, when both contend +Which is the mightier. In his lawless fit +Behind the arras hearing something stir, +Whips out his rapier, cries ‘A rat, a rat!’ +And in this brainish apprehension kills +The unseen good old man. + +KING. +O heavy deed! +It had been so with us, had we been there. +His liberty is full of threats to all; +To you yourself, to us, to everyone. +Alas, how shall this bloody deed be answer’d? +It will be laid to us, whose providence +Should have kept short, restrain’d, and out of haunt +This mad young man. But so much was our love +We would not understand what was most fit, +But like the owner of a foul disease, +To keep it from divulging, let it feed +Even on the pith of life. Where is he gone? + +QUEEN. +To draw apart the body he hath kill’d, +O’er whom his very madness, like some ore +Among a mineral of metals base, +Shows itself pure. He weeps for what is done. + +KING. +O Gertrude, come away! +The sun no sooner shall the mountains touch +But we will ship him hence, and this vile deed +We must with all our majesty and skill +Both countenance and excuse.—Ho, Guildenstern! + +Re-enter Rosencrantz and Guildenstern. + +Friends both, go join you with some further aid: +Hamlet in madness hath Polonius slain, +And from his mother’s closet hath he dragg’d him. +Go seek him out, speak fair, and bring the body +Into the chapel. I pray you haste in this. + +[_Exeunt Rosencrantz and Guildenstern._] + +Come, Gertrude, we’ll call up our wisest friends, +And let them know both what we mean to do +And what’s untimely done, so haply slander, +Whose whisper o’er the world’s diameter, +As level as the cannon to his blank, +Transports his poison’d shot, may miss our name, +And hit the woundless air. O, come away! +My soul is full of discord and dismay. + +[_Exeunt._] + + SCENE II. Another room in the Castle. + +Enter Hamlet. + +HAMLET. +Safely stowed. + +ROSENCRANTZ and GUILDENSTERN. +[_Within._] Hamlet! Lord Hamlet! + +HAMLET. +What noise? Who calls on Hamlet? O, here they come. + +Enter Rosencrantz and Guildenstern. + +ROSENCRANTZ. +What have you done, my lord, with the dead body? + +HAMLET. +Compounded it with dust, whereto ’tis kin. + +ROSENCRANTZ. +Tell us where ’tis, that we may take it thence, +And bear it to the chapel. + +HAMLET. +Do not believe it. + +ROSENCRANTZ. +Believe what? + +HAMLET. +That I can keep your counsel, and not mine own. Besides, to be demanded +of a sponge—what replication should be made by the son of a king? + +ROSENCRANTZ. +Take you me for a sponge, my lord? + +HAMLET. +Ay, sir; that soaks up the King’s countenance, his rewards, his +authorities. But such officers do the King best service in the end: he +keeps them, like an ape, in the corner of his jaw; first mouthed, to be +last swallowed: when he needs what you have gleaned, it is but +squeezing you, and, sponge, you shall be dry again. + +ROSENCRANTZ. +I understand you not, my lord. + +HAMLET. +I am glad of it. A knavish speech sleeps in a foolish ear. + +ROSENCRANTZ. +My lord, you must tell us where the body is and go with us to the King. + +HAMLET. +The body is with the King, but the King is not with the body. The King +is a thing— + +GUILDENSTERN. +A thing, my lord! + +HAMLET. +Of nothing. Bring me to him. Hide fox, and all after. + +[_Exeunt._] + + SCENE III. Another room in the Castle. + +Enter King, attended. + +KING. +I have sent to seek him and to find the body. +How dangerous is it that this man goes loose! +Yet must not we put the strong law on him: +He’s lov’d of the distracted multitude, +Who like not in their judgement, but their eyes; +And where ’tis so, th’offender’s scourge is weigh’d, +But never the offence. To bear all smooth and even, +This sudden sending him away must seem +Deliberate pause. Diseases desperate grown +By desperate appliance are reliev’d, +Or not at all. + +Enter Rosencrantz. + +How now? What hath befall’n? + +ROSENCRANTZ. +Where the dead body is bestow’d, my lord, +We cannot get from him. + +KING. +But where is he? + +ROSENCRANTZ. +Without, my lord, guarded, to know your pleasure. + +KING. +Bring him before us. + +ROSENCRANTZ. +Ho, Guildenstern! Bring in my lord. + +Enter Hamlet and Guildenstern. + +KING. +Now, Hamlet, where’s Polonius? + +HAMLET. +At supper. + +KING. +At supper? Where? + +HAMLET. +Not where he eats, but where he is eaten. A certain convocation of +politic worms are e’en at him. Your worm is your only emperor for diet. +We fat all creatures else to fat us, and we fat ourselves for maggots. +Your fat king and your lean beggar is but variable service,—two dishes, +but to one table. That’s the end. + +KING. +Alas, alas! + +HAMLET. +A man may fish with the worm that hath eat of a king, and eat of the +fish that hath fed of that worm. + +KING. +What dost thou mean by this? + +HAMLET. +Nothing but to show you how a king may go a progress through the guts +of a beggar. + +KING. +Where is Polonius? + +HAMLET. +In heaven. Send thither to see. If your messenger find him not there, +seek him i’ th’other place yourself. But indeed, if you find him not +within this month, you shall nose him as you go up the stairs into the +lobby. + +KING. +[_To some Attendants._] Go seek him there. + +HAMLET. +He will stay till you come. + +[_Exeunt Attendants._] + +KING. +Hamlet, this deed, for thine especial safety,— +Which we do tender, as we dearly grieve +For that which thou hast done,—must send thee hence +With fiery quickness. Therefore prepare thyself; +The bark is ready, and the wind at help, +Th’associates tend, and everything is bent +For England. + +HAMLET. +For England? + +KING. +Ay, Hamlet. + +HAMLET. +Good. + +KING. +So is it, if thou knew’st our purposes. + +HAMLET. +I see a cherub that sees them. But, come; for England! Farewell, dear +mother. + +KING. +Thy loving father, Hamlet. + +HAMLET. +My mother. Father and mother is man and wife; man and wife is one +flesh; and so, my mother. Come, for England. + +[_Exit._] + +KING. +Follow him at foot. Tempt him with speed aboard; +Delay it not; I’ll have him hence tonight. +Away, for everything is seal’d and done +That else leans on th’affair. Pray you make haste. + +[_Exeunt Rosencrantz and Guildenstern._] + +And England, if my love thou hold’st at aught,— +As my great power thereof may give thee sense, +Since yet thy cicatrice looks raw and red +After the Danish sword, and thy free awe +Pays homage to us,—thou mayst not coldly set +Our sovereign process, which imports at full, +By letters conjuring to that effect, +The present death of Hamlet. Do it, England; +For like the hectic in my blood he rages, +And thou must cure me. Till I know ’tis done, +Howe’er my haps, my joys were ne’er begun. + +[_Exit._] + + SCENE IV. A plain in Denmark. + +Enter Fortinbras and Forces marching. + +FORTINBRAS. +Go, Captain, from me greet the Danish king. +Tell him that by his license, Fortinbras +Craves the conveyance of a promis’d march +Over his kingdom. You know the rendezvous. +If that his Majesty would aught with us, +We shall express our duty in his eye; +And let him know so. + +CAPTAIN. +I will do’t, my lord. + +FORTINBRAS. +Go softly on. + +[_Exeunt all but the Captain._] + +Enter Hamlet, Rosencrantz, Guildenstern &c. + +HAMLET. +Good sir, whose powers are these? + +CAPTAIN. +They are of Norway, sir. + +HAMLET. +How purpos’d, sir, I pray you? + +CAPTAIN. +Against some part of Poland. + +HAMLET. +Who commands them, sir? + +CAPTAIN. +The nephew to old Norway, Fortinbras. + +HAMLET. +Goes it against the main of Poland, sir, +Or for some frontier? + +CAPTAIN. +Truly to speak, and with no addition, +We go to gain a little patch of ground +That hath in it no profit but the name. +To pay five ducats, five, I would not farm it; +Nor will it yield to Norway or the Pole +A ranker rate, should it be sold in fee. + +HAMLET. +Why, then the Polack never will defend it. + +CAPTAIN. +Yes, it is already garrison’d. + +HAMLET. +Two thousand souls and twenty thousand ducats +Will not debate the question of this straw! +This is th’imposthume of much wealth and peace, +That inward breaks, and shows no cause without +Why the man dies. I humbly thank you, sir. + +CAPTAIN. +God b’ wi’ you, sir. + +[_Exit._] + +ROSENCRANTZ. +Will’t please you go, my lord? + +HAMLET. +I’ll be with you straight. Go a little before. + +[_Exeunt all but Hamlet._] + +How all occasions do inform against me, +And spur my dull revenge. What is a man +If his chief good and market of his time +Be but to sleep and feed? A beast, no more. +Sure he that made us with such large discourse, +Looking before and after, gave us not +That capability and godlike reason +To fust in us unus’d. Now whether it be +Bestial oblivion, or some craven scruple +Of thinking too precisely on th’event,— +A thought which, quarter’d, hath but one part wisdom +And ever three parts coward,—I do not know +Why yet I live to say this thing’s to do, +Sith I have cause, and will, and strength, and means +To do’t. Examples gross as earth exhort me, +Witness this army of such mass and charge, +Led by a delicate and tender prince, +Whose spirit, with divine ambition puff’d, +Makes mouths at the invisible event, +Exposing what is mortal and unsure +To all that fortune, death, and danger dare, +Even for an eggshell. Rightly to be great +Is not to stir without great argument, +But greatly to find quarrel in a straw +When honour’s at the stake. How stand I then, +That have a father kill’d, a mother stain’d, +Excitements of my reason and my blood, +And let all sleep, while to my shame I see +The imminent death of twenty thousand men +That, for a fantasy and trick of fame, +Go to their graves like beds, fight for a plot +Whereon the numbers cannot try the cause, +Which is not tomb enough and continent +To hide the slain? O, from this time forth, +My thoughts be bloody or be nothing worth. + +[_Exit._] + + SCENE V. Elsinore. A room in the Castle. + +Enter Queen, Horatio and a Gentleman. + +QUEEN. +I will not speak with her. + +GENTLEMAN. +She is importunate, indeed distract. +Her mood will needs be pitied. + +QUEEN. +What would she have? + +GENTLEMAN. +She speaks much of her father; says she hears +There’s tricks i’ th’ world, and hems, and beats her heart, +Spurns enviously at straws, speaks things in doubt, +That carry but half sense. Her speech is nothing, +Yet the unshaped use of it doth move +The hearers to collection; they aim at it, +And botch the words up fit to their own thoughts, +Which, as her winks, and nods, and gestures yield them, +Indeed would make one think there might be thought, +Though nothing sure, yet much unhappily. +’Twere good she were spoken with, for she may strew +Dangerous conjectures in ill-breeding minds. + +QUEEN. +Let her come in. + +[_Exit Gentleman._] + +To my sick soul, as sin’s true nature is, +Each toy seems prologue to some great amiss. +So full of artless jealousy is guilt, +It spills itself in fearing to be spilt. + +Enter Ophelia. + +OPHELIA. +Where is the beauteous Majesty of Denmark? + +QUEEN. +How now, Ophelia? + +OPHELIA. +[_Sings._] + How should I your true love know + From another one? + By his cockle hat and staff + And his sandal shoon. + +QUEEN. +Alas, sweet lady, what imports this song? + +OPHELIA. +Say you? Nay, pray you mark. +[_Sings._] + He is dead and gone, lady, + He is dead and gone, + At his head a grass green turf, + At his heels a stone. + +QUEEN. +Nay, but Ophelia— + +OPHELIA. +Pray you mark. +[_Sings._] + White his shroud as the mountain snow. + +Enter King. + +QUEEN. +Alas, look here, my lord! + +OPHELIA. +[_Sings._] + Larded all with sweet flowers; + Which bewept to the grave did not go + With true-love showers. + +KING. +How do you, pretty lady? + +OPHELIA. +Well, God dild you! They say the owl was a baker’s daughter. Lord, we +know what we are, but know not what we may be. God be at your table! + +KING. +Conceit upon her father. + +OPHELIA. +Pray you, let’s have no words of this; but when they ask you what it +means, say you this: +[_Sings._] + Tomorrow is Saint Valentine’s day, + All in the morning betime, + And I a maid at your window, + To be your Valentine. + + Then up he rose and donn’d his clothes, + And dupp’d the chamber door, + Let in the maid, that out a maid + Never departed more. + +KING. +Pretty Ophelia! + +OPHELIA. +Indeed la, without an oath, I’ll make an end on’t. +[_Sings._] + By Gis and by Saint Charity, + Alack, and fie for shame! + Young men will do’t if they come to’t; + By Cock, they are to blame. + + Quoth she, before you tumbled me, + You promis’d me to wed. + So would I ha’ done, by yonder sun, + An thou hadst not come to my bed. + +KING. +How long hath she been thus? + +OPHELIA. +I hope all will be well. We must be patient. But I cannot choose but +weep, to think they would lay him i’ th’ cold ground. My brother shall +know of it. And so I thank you for your good counsel. Come, my coach! +Good night, ladies; good night, sweet ladies; good night, good night. + +[_Exit._] + +KING. +Follow her close; give her good watch, I pray you. + +[_Exit Horatio._] + +O, this is the poison of deep grief; it springs +All from her father’s death. O Gertrude, Gertrude, +When sorrows come, they come not single spies, +But in battalions. First, her father slain; +Next, your son gone; and he most violent author +Of his own just remove; the people muddied, +Thick, and unwholesome in their thoughts and whispers +For good Polonius’ death; and we have done but greenly +In hugger-mugger to inter him. Poor Ophelia +Divided from herself and her fair judgement, +Without the which we are pictures or mere beasts. +Last, and as much containing as all these, +Her brother is in secret come from France, +Feeds on his wonder, keeps himself in clouds, +And wants not buzzers to infect his ear +With pestilent speeches of his father’s death, +Wherein necessity, of matter beggar’d, +Will nothing stick our person to arraign +In ear and ear. O my dear Gertrude, this, +Like to a murdering piece, in many places +Gives me superfluous death. + +[_A noise within._] + +QUEEN. +Alack, what noise is this? + +KING. +Where are my Switzers? Let them guard the door. + +Enter a Gentleman. + +What is the matter? + +GENTLEMAN. +Save yourself, my lord. +The ocean, overpeering of his list, +Eats not the flats with more impetuous haste +Than young Laertes, in a riotous head, +O’erbears your offices. The rabble call him lord, +And, as the world were now but to begin, +Antiquity forgot, custom not known, +The ratifiers and props of every word, +They cry ‘Choose we! Laertes shall be king!’ +Caps, hands, and tongues applaud it to the clouds, +‘Laertes shall be king, Laertes king.’ + +QUEEN. +How cheerfully on the false trail they cry. +O, this is counter, you false Danish dogs. + +[_A noise within._] + +KING. +The doors are broke. + +Enter Laertes, armed; Danes following. + +LAERTES. +Where is this king?—Sirs, stand you all without. + +Danes. +No, let’s come in. + +LAERTES. +I pray you, give me leave. + +DANES. +We will, we will. + +[_They retire without the door._] + +LAERTES. +I thank you. Keep the door. O thou vile king, +Give me my father. + +QUEEN. +Calmly, good Laertes. + +LAERTES. +That drop of blood that’s calm proclaims me bastard; +Cries cuckold to my father, brands the harlot +Even here between the chaste unsmirched brow +Of my true mother. + +KING. +What is the cause, Laertes, +That thy rebellion looks so giant-like?— +Let him go, Gertrude. Do not fear our person. +There’s such divinity doth hedge a king, +That treason can but peep to what it would, +Acts little of his will.—Tell me, Laertes, +Why thou art thus incens’d.—Let him go, Gertrude:— +Speak, man. + +LAERTES. +Where is my father? + +KING. +Dead. + +QUEEN. +But not by him. + +KING. +Let him demand his fill. + +LAERTES. +How came he dead? I’ll not be juggled with. +To hell, allegiance! Vows, to the blackest devil! +Conscience and grace, to the profoundest pit! +I dare damnation. To this point I stand, +That both the worlds, I give to negligence, +Let come what comes; only I’ll be reveng’d +Most throughly for my father. + +KING. +Who shall stay you? + +LAERTES. +My will, not all the world. +And for my means, I’ll husband them so well, +They shall go far with little. + +KING. +Good Laertes, +If you desire to know the certainty +Of your dear father’s death, is’t writ in your revenge +That, sweepstake, you will draw both friend and foe, +Winner and loser? + +LAERTES. +None but his enemies. + +KING. +Will you know them then? + +LAERTES. +To his good friends thus wide I’ll ope my arms; +And, like the kind life-rendering pelican, +Repast them with my blood. + +KING. +Why, now you speak +Like a good child and a true gentleman. +That I am guiltless of your father’s death, +And am most sensibly in grief for it, +It shall as level to your judgement ’pear +As day does to your eye. + +DANES. +[_Within._] Let her come in. + +LAERTES. +How now! What noise is that? + +Re-enter Ophelia, fantastically dressed with straws and flowers. + +O heat, dry up my brains. Tears seven times salt, +Burn out the sense and virtue of mine eye. +By heaven, thy madness shall be paid by weight, +Till our scale turn the beam. O rose of May! +Dear maid, kind sister, sweet Ophelia! +O heavens, is’t possible a young maid’s wits +Should be as mortal as an old man’s life? +Nature is fine in love, and where ’tis fine, +It sends some precious instance of itself +After the thing it loves. + +OPHELIA. +[_Sings._] + They bore him barefac’d on the bier, + Hey non nonny, nonny, hey nonny + And on his grave rain’d many a tear.— + Fare you well, my dove! + +LAERTES. +Hadst thou thy wits, and didst persuade revenge, +It could not move thus. + +OPHELIA. +You must sing ‘Down a-down, and you call him a-down-a.’ O, how the +wheel becomes it! It is the false steward that stole his master’s +daughter. + +LAERTES. +This nothing’s more than matter. + +OPHELIA. +There’s rosemary, that’s for remembrance; pray love, remember. And +there is pansies, that’s for thoughts. + +LAERTES. +A document in madness, thoughts and remembrance fitted. + +OPHELIA. +There’s fennel for you, and columbines. There’s rue for you; and here’s +some for me. We may call it herb of grace o’ Sundays. O you must wear +your rue with a difference. There’s a daisy. I would give you some +violets, but they wither’d all when my father died. They say he made a +good end. +[_Sings._] + For bonny sweet Robin is all my joy. + +LAERTES. +Thought and affliction, passion, hell itself +She turns to favour and to prettiness. + +OPHELIA. +[_Sings._] + And will he not come again? + And will he not come again? + No, no, he is dead, + Go to thy death-bed, + He never will come again. + + His beard was as white as snow, + All flaxen was his poll. + He is gone, he is gone, + And we cast away moan. + God ha’ mercy on his soul. + +And of all Christian souls, I pray God. God b’ wi’ ye. + +[_Exit._] + +LAERTES. +Do you see this, O God? + +KING. +Laertes, I must commune with your grief, +Or you deny me right. Go but apart, +Make choice of whom your wisest friends you will, +And they shall hear and judge ’twixt you and me. +If by direct or by collateral hand +They find us touch’d, we will our kingdom give, +Our crown, our life, and all that we call ours +To you in satisfaction; but if not, +Be you content to lend your patience to us, +And we shall jointly labour with your soul +To give it due content. + +LAERTES. +Let this be so; +His means of death, his obscure burial,— +No trophy, sword, nor hatchment o’er his bones, +No noble rite, nor formal ostentation,— +Cry to be heard, as ’twere from heaven to earth, +That I must call’t in question. + +KING. +So you shall. +And where th’offence is let the great axe fall. +I pray you go with me. + +[_Exeunt._] + + SCENE VI. Another room in the Castle. + +Enter Horatio and a Servant. + +HORATIO. +What are they that would speak with me? + +SERVANT. +Sailors, sir. They say they have letters for you. + +HORATIO. +Let them come in. + +[_Exit Servant._] + +I do not know from what part of the world +I should be greeted, if not from Lord Hamlet. + +Enter Sailors. + +FIRST SAILOR. +God bless you, sir. + +HORATIO. +Let him bless thee too. + +FIRST SAILOR. +He shall, sir, and’t please him. There’s a letter for you, sir. It +comes from th’ambassador that was bound for England; if your name be +Horatio, as I am let to know it is. + +HORATIO. +[_Reads._] ‘Horatio, when thou shalt have overlooked this, give these +fellows some means to the King. They have letters for him. Ere we were +two days old at sea, a pirate of very warlike appointment gave us +chase. Finding ourselves too slow of sail, we put on a compelled +valour, and in the grapple I boarded them. On the instant they got +clear of our ship, so I alone became their prisoner. They have dealt +with me like thieves of mercy. But they knew what they did; I am to do +a good turn for them. Let the King have the letters I have sent, and +repair thou to me with as much haste as thou wouldst fly death. I have +words to speak in thine ear will make thee dumb; yet are they much too +light for the bore of the matter. These good fellows will bring thee +where I am. Rosencrantz and Guildenstern hold their course for England: +of them I have much to tell thee. Farewell. + He that thou knowest thine, + HAMLET.’ + +Come, I will give you way for these your letters, +And do’t the speedier, that you may direct me +To him from whom you brought them. + +[_Exeunt._] + + SCENE VII. Another room in the Castle. + +Enter King and Laertes. + +KING. +Now must your conscience my acquittance seal, +And you must put me in your heart for friend, +Sith you have heard, and with a knowing ear, +That he which hath your noble father slain +Pursu’d my life. + +LAERTES. +It well appears. But tell me +Why you proceeded not against these feats, +So crimeful and so capital in nature, +As by your safety, wisdom, all things else, +You mainly were stirr’d up. + +KING. +O, for two special reasons, +Which may to you, perhaps, seem much unsinew’d, +But yet to me they are strong. The Queen his mother +Lives almost by his looks; and for myself,— +My virtue or my plague, be it either which,— +She’s so conjunctive to my life and soul, +That, as the star moves not but in his sphere, +I could not but by her. The other motive, +Why to a public count I might not go, +Is the great love the general gender bear him, +Who, dipping all his faults in their affection, +Would like the spring that turneth wood to stone, +Convert his gyves to graces; so that my arrows, +Too slightly timber’d for so loud a wind, +Would have reverted to my bow again, +And not where I had aim’d them. + +LAERTES. +And so have I a noble father lost, +A sister driven into desperate terms, +Whose worth, if praises may go back again, +Stood challenger on mount of all the age +For her perfections. But my revenge will come. + +KING. +Break not your sleeps for that. You must not think +That we are made of stuff so flat and dull +That we can let our beard be shook with danger, +And think it pastime. You shortly shall hear more. +I lov’d your father, and we love ourself, +And that, I hope, will teach you to imagine— + +Enter a Messenger. + +How now? What news? + +MESSENGER. +Letters, my lord, from Hamlet. +This to your Majesty; this to the Queen. + +KING. +From Hamlet! Who brought them? + +MESSENGER. +Sailors, my lord, they say; I saw them not. +They were given me by Claudio. He receiv’d them +Of him that brought them. + +KING. +Laertes, you shall hear them. +Leave us. + +[_Exit Messenger._] + +[_Reads._] ‘High and mighty, you shall know I am set naked on your +kingdom. Tomorrow shall I beg leave to see your kingly eyes. When I +shall, first asking your pardon thereunto, recount the occasions of my +sudden and more strange return. + HAMLET.’ + +What should this mean? Are all the rest come back? +Or is it some abuse, and no such thing? + +LAERTES. +Know you the hand? + +KING. +’Tis Hamlet’s character. ‘Naked!’ +And in a postscript here he says ‘alone.’ +Can you advise me? + +LAERTES. +I am lost in it, my lord. But let him come, +It warms the very sickness in my heart +That I shall live and tell him to his teeth, +‘Thus diest thou.’ + +KING. +If it be so, Laertes,— +As how should it be so? How otherwise?— +Will you be rul’d by me? + +LAERTES. +Ay, my lord; +So you will not o’errule me to a peace. + +KING. +To thine own peace. If he be now return’d, +As checking at his voyage, and that he means +No more to undertake it, I will work him +To an exploit, now ripe in my device, +Under the which he shall not choose but fall; +And for his death no wind shall breathe, +But even his mother shall uncharge the practice +And call it accident. + +LAERTES. +My lord, I will be rul’d; +The rather if you could devise it so +That I might be the organ. + +KING. +It falls right. +You have been talk’d of since your travel much, +And that in Hamlet’s hearing, for a quality +Wherein they say you shine. Your sum of parts +Did not together pluck such envy from him +As did that one, and that, in my regard, +Of the unworthiest siege. + +LAERTES. +What part is that, my lord? + +KING. +A very riband in the cap of youth, +Yet needful too, for youth no less becomes +The light and careless livery that it wears +Than settled age his sables and his weeds, +Importing health and graveness. Two months since +Here was a gentleman of Normandy,— +I’ve seen myself, and serv’d against, the French, +And they can well on horseback, but this gallant +Had witchcraft in’t. He grew unto his seat, +And to such wondrous doing brought his horse, +As had he been incorps’d and demi-natur’d +With the brave beast. So far he topp’d my thought +That I in forgery of shapes and tricks, +Come short of what he did. + +LAERTES. +A Norman was’t? + +KING. +A Norman. + +LAERTES. +Upon my life, Lamord. + +KING. +The very same. + +LAERTES. +I know him well. He is the brooch indeed +And gem of all the nation. + +KING. +He made confession of you, +And gave you such a masterly report +For art and exercise in your defence, +And for your rapier most especially, +That he cried out ’twould be a sight indeed +If one could match you. The scrimers of their nation +He swore had neither motion, guard, nor eye, +If you oppos’d them. Sir, this report of his +Did Hamlet so envenom with his envy +That he could nothing do but wish and beg +Your sudden coming o’er to play with him. +Now, out of this,— + +LAERTES. +What out of this, my lord? + +KING. +Laertes, was your father dear to you? +Or are you like the painting of a sorrow, +A face without a heart? + +LAERTES. +Why ask you this? + +KING. +Not that I think you did not love your father, +But that I know love is begun by time, +And that I see, in passages of proof, +Time qualifies the spark and fire of it. +There lives within the very flame of love +A kind of wick or snuff that will abate it; +And nothing is at a like goodness still, +For goodness, growing to a pleurisy, +Dies in his own too much. That we would do, +We should do when we would; for this ‘would’ changes, +And hath abatements and delays as many +As there are tongues, are hands, are accidents; +And then this ‘should’ is like a spendthrift sigh +That hurts by easing. But to the quick o’ th’ulcer: +Hamlet comes back: what would you undertake +To show yourself your father’s son in deed, +More than in words? + +LAERTES. +To cut his throat i’ th’ church. + +KING. +No place, indeed, should murder sanctuarize; +Revenge should have no bounds. But good Laertes, +Will you do this, keep close within your chamber. +Hamlet return’d shall know you are come home: +We’ll put on those shall praise your excellence, +And set a double varnish on the fame +The Frenchman gave you, bring you in fine together +And wager on your heads. He, being remiss, +Most generous, and free from all contriving, +Will not peruse the foils; so that with ease, +Or with a little shuffling, you may choose +A sword unbated, and in a pass of practice, +Requite him for your father. + +LAERTES. +I will do’t. +And for that purpose I’ll anoint my sword. +I bought an unction of a mountebank +So mortal that, but dip a knife in it, +Where it draws blood no cataplasm so rare, +Collected from all simples that have virtue +Under the moon, can save the thing from death +This is but scratch’d withal. I’ll touch my point +With this contagion, that if I gall him slightly, +It may be death. + +KING. +Let’s further think of this, +Weigh what convenience both of time and means +May fit us to our shape. If this should fail, +And that our drift look through our bad performance. +’Twere better not assay’d. Therefore this project +Should have a back or second, that might hold +If this did blast in proof. Soft, let me see. +We’ll make a solemn wager on your cunnings,— +I ha’t! When in your motion you are hot and dry, +As make your bouts more violent to that end, +And that he calls for drink, I’ll have prepar’d him +A chalice for the nonce; whereon but sipping, +If he by chance escape your venom’d stuck, +Our purpose may hold there. + +Enter Queen. + +How now, sweet Queen? + +QUEEN. +One woe doth tread upon another’s heel, +So fast they follow. Your sister’s drown’d, Laertes. + +LAERTES. +Drown’d! O, where? + +QUEEN. +There is a willow grows aslant a brook, +That shows his hoary leaves in the glassy stream. +There with fantastic garlands did she make +Of crow-flowers, nettles, daisies, and long purples, +That liberal shepherds give a grosser name, +But our cold maids do dead men’s fingers call them. +There on the pendant boughs her coronet weeds +Clamb’ring to hang, an envious sliver broke, +When down her weedy trophies and herself +Fell in the weeping brook. Her clothes spread wide, +And mermaid-like, awhile they bore her up, +Which time she chaunted snatches of old tunes, +As one incapable of her own distress, +Or like a creature native and indued +Unto that element. But long it could not be +Till that her garments, heavy with their drink, +Pull’d the poor wretch from her melodious lay +To muddy death. + +LAERTES. +Alas, then she is drown’d? + +QUEEN. +Drown’d, drown’d. + +LAERTES. +Too much of water hast thou, poor Ophelia, +And therefore I forbid my tears. But yet +It is our trick; nature her custom holds, +Let shame say what it will. When these are gone, +The woman will be out. Adieu, my lord, +I have a speech of fire, that fain would blaze, +But that this folly douts it. + +[_Exit._] + +KING. +Let’s follow, Gertrude; +How much I had to do to calm his rage! +Now fear I this will give it start again; +Therefore let’s follow. + +[_Exeunt._] + + + + +ACT V + +SCENE I. A churchyard. + + +Enter two Clowns with spades, &c. + +FIRST CLOWN. +Is she to be buried in Christian burial, when she wilfully seeks her +own salvation? + +SECOND CLOWN. +I tell thee she is, and therefore make her grave straight. The crowner +hath sat on her, and finds it Christian burial. + +FIRST CLOWN. +How can that be, unless she drowned herself in her own defence? + +SECOND CLOWN. +Why, ’tis found so. + +FIRST CLOWN. +It must be _se offendendo_, it cannot be else. For here lies the point: +if I drown myself wittingly, it argues an act: and an act hath three +branches. It is to act, to do, and to perform: argal, she drowned +herself wittingly. + +SECOND CLOWN. +Nay, but hear you, goodman delver,— + +FIRST CLOWN. +Give me leave. Here lies the water; good. Here stands the man; good. If +the man go to this water and drown himself, it is, will he nill he, he +goes,—mark you that. But if the water come to him and drown him, he +drowns not himself. Argal, he that is not guilty of his own death +shortens not his own life. + +SECOND CLOWN. +But is this law? + +FIRST CLOWN. +Ay, marry, is’t, crowner’s quest law. + +SECOND CLOWN. +Will you ha’ the truth on’t? If this had not been a gentlewoman, she +should have been buried out o’ Christian burial. + +FIRST CLOWN. +Why, there thou say’st. And the more pity that great folk should have +countenance in this world to drown or hang themselves more than their +even Christian. Come, my spade. There is no ancient gentlemen but +gardeners, ditchers, and grave-makers: they hold up Adam’s profession. + +SECOND CLOWN. +Was he a gentleman? + +FIRST CLOWN. +He was the first that ever bore arms. + +SECOND CLOWN. +Why, he had none. + +FIRST CLOWN. +What, art a heathen? How dost thou understand the Scripture? The +Scripture says Adam digg’d. Could he dig without arms? I’ll put another +question to thee. If thou answerest me not to the purpose, confess +thyself— + +SECOND CLOWN. +Go to. + +FIRST CLOWN. +What is he that builds stronger than either the mason, the shipwright, +or the carpenter? + +SECOND CLOWN. +The gallows-maker; for that frame outlives a thousand tenants. + +FIRST CLOWN. +I like thy wit well in good faith, the gallows does well. But how does +it well? It does well to those that do ill. Now, thou dost ill to say +the gallows is built stronger than the church; argal, the gallows may +do well to thee. To’t again, come. + +SECOND CLOWN. +Who builds stronger than a mason, a shipwright, or a carpenter? + +FIRST CLOWN. +Ay, tell me that, and unyoke. + +SECOND CLOWN. +Marry, now I can tell. + +FIRST CLOWN. +To’t. + +SECOND CLOWN. +Mass, I cannot tell. + +Enter Hamlet and Horatio, at a distance. + +FIRST CLOWN. +Cudgel thy brains no more about it, for your dull ass will not mend his +pace with beating; and when you are asked this question next, say ‘a +grave-maker’. The houses he makes last till doomsday. Go, get thee to +Yaughan; fetch me a stoup of liquor. + +[_Exit Second Clown._] + +[_Digs and sings._] + + In youth when I did love, did love, + Methought it was very sweet; + To contract, O, the time for, a, my behove, + O methought there was nothing meet. + +HAMLET. +Has this fellow no feeling of his business, that he sings at +grave-making? + +HORATIO. +Custom hath made it in him a property of easiness. + +HAMLET. +’Tis e’en so; the hand of little employment hath the daintier sense. + +FIRST CLOWN. +[_Sings._] + But age with his stealing steps + Hath claw’d me in his clutch, + And hath shipp’d me into the land, + As if I had never been such. + +[_Throws up a skull._] + +HAMLET. +That skull had a tongue in it, and could sing once. How the knave jowls +it to th’ ground, as if ’twere Cain’s jawbone, that did the first +murder! This might be the pate of a politician which this ass now +o’er-offices, one that would circumvent God, might it not? + +HORATIO. +It might, my lord. + +HAMLET. +Or of a courtier, which could say ‘Good morrow, sweet lord! How dost +thou, good lord?’ This might be my lord such-a-one, that praised my +lord such-a-one’s horse when he meant to beg it, might it not? + +HORATIO. +Ay, my lord. + +HAMLET. +Why, e’en so: and now my Lady Worm’s; chapless, and knocked about the +mazard with a sexton’s spade. Here’s fine revolution, an we had the +trick to see’t. Did these bones cost no more the breeding but to play +at loggets with ’em? Mine ache to think on’t. + +FIRST CLOWN. +[_Sings._] + A pickaxe and a spade, a spade, + For and a shrouding-sheet; + O, a pit of clay for to be made + For such a guest is meet. + +[_Throws up another skull._] + +HAMLET. +There’s another. Why may not that be the skull of a lawyer? Where be +his quiddits now, his quillets, his cases, his tenures, and his tricks? +Why does he suffer this rude knave now to knock him about the sconce +with a dirty shovel, and will not tell him of his action of battery? +Hum. This fellow might be in’s time a great buyer of land, with his +statutes, his recognizances, his fines, his double vouchers, his +recoveries. Is this the fine of his fines, and the recovery of his +recoveries, to have his fine pate full of fine dirt? Will his vouchers +vouch him no more of his purchases, and double ones too, than the +length and breadth of a pair of indentures? The very conveyances of his +lands will scarcely lie in this box; and must the inheritor himself +have no more, ha? + +HORATIO. +Not a jot more, my lord. + +HAMLET. +Is not parchment made of sheep-skins? + +HORATIO. +Ay, my lord, and of calf-skins too. + +HAMLET. +They are sheep and calves which seek out assurance in that. I will +speak to this fellow.—Whose grave’s this, sir? + +FIRST CLOWN. +Mine, sir. +[_Sings._] + O, a pit of clay for to be made + For such a guest is meet. + +HAMLET. +I think it be thine indeed, for thou liest in’t. + +FIRST CLOWN. +You lie out on’t, sir, and therefore ’tis not yours. +For my part, I do not lie in’t, yet it is mine. + +HAMLET. +Thou dost lie in’t, to be in’t and say it is thine. ’Tis for the dead, +not for the quick; therefore thou liest. + +FIRST CLOWN. +’Tis a quick lie, sir; ’t will away again from me to you. + +HAMLET. +What man dost thou dig it for? + +FIRST CLOWN. +For no man, sir. + +HAMLET. +What woman then? + +FIRST CLOWN. +For none neither. + +HAMLET. +Who is to be buried in’t? + +FIRST CLOWN. +One that was a woman, sir; but, rest her soul, she’s dead. + +HAMLET. +How absolute the knave is! We must speak by the card, or equivocation +will undo us. By the Lord, Horatio, these three years I have taken note +of it, the age is grown so picked that the toe of the peasant comes so +near the heel of the courtier he galls his kibe.—How long hast thou +been a grave-maker? + +FIRST CLOWN. +Of all the days i’ th’ year, I came to’t that day that our last King +Hamlet o’ercame Fortinbras. + +HAMLET. +How long is that since? + +FIRST CLOWN. +Cannot you tell that? Every fool can tell that. It was the very day +that young Hamlet was born,—he that is mad, and sent into England. + +HAMLET. +Ay, marry, why was he sent into England? + +FIRST CLOWN. +Why, because he was mad; he shall recover his wits there; or if he do +not, it’s no great matter there. + +HAMLET. +Why? + +FIRST CLOWN. +’Twill not be seen in him there; there the men are as mad as he. + +HAMLET. +How came he mad? + +FIRST CLOWN. +Very strangely, they say. + +HAMLET. +How strangely? + +FIRST CLOWN. +Faith, e’en with losing his wits. + +HAMLET. +Upon what ground? + +FIRST CLOWN. +Why, here in Denmark. I have been sexton here, man and boy, thirty +years. + +HAMLET. +How long will a man lie i’ th’earth ere he rot? + +FIRST CLOWN. +Faith, if he be not rotten before he die,—as we have many pocky corses +nowadays that will scarce hold the laying in,—he will last you some +eight year or nine year. A tanner will last you nine year. + +HAMLET. +Why he more than another? + +FIRST CLOWN. +Why, sir, his hide is so tann’d with his trade that he will keep out +water a great while. And your water is a sore decayer of your whoreson +dead body. Here’s a skull now; this skull hath lain in the earth +three-and-twenty years. + +HAMLET. +Whose was it? + +FIRST CLOWN. +A whoreson, mad fellow’s it was. Whose do you think it was? + +HAMLET. +Nay, I know not. + +FIRST CLOWN. +A pestilence on him for a mad rogue! A pour’d a flagon of Rhenish on my +head once. This same skull, sir, was Yorick’s skull, the King’s jester. + +HAMLET. +This? + +FIRST CLOWN. +E’en that. + +HAMLET. +Let me see. [_Takes the skull._] Alas, poor Yorick. I knew him, +Horatio, a fellow of infinite jest, of most excellent fancy. He hath +borne me on his back a thousand times; and now, how abhorred in my +imagination it is! My gorge rises at it. Here hung those lips that I +have kiss’d I know not how oft. Where be your gibes now? your gambols? +your songs? your flashes of merriment, that were wont to set the table +on a roar? Not one now, to mock your own grinning? Quite chop-fallen? +Now get you to my lady’s chamber, and tell her, let her paint an inch +thick, to this favour she must come. Make her laugh at that.—Prithee, +Horatio, tell me one thing. + +HORATIO. +What’s that, my lord? + +HAMLET. +Dost thou think Alexander looked o’ this fashion i’ th’earth? + +HORATIO. +E’en so. + +HAMLET. +And smelt so? Pah! + +[_Throws down the skull._] + +HORATIO. +E’en so, my lord. + +HAMLET. +To what base uses we may return, Horatio! Why may not imagination trace +the noble dust of Alexander till he find it stopping a bung-hole? + +HORATIO. +’Twere to consider too curiously to consider so. + +HAMLET. +No, faith, not a jot. But to follow him thither with modesty enough, +and likelihood to lead it; as thus. Alexander died, Alexander was +buried, Alexander returneth into dust; the dust is earth; of earth we +make loam; and why of that loam whereto he was converted might they not +stop a beer-barrel? +Imperious Caesar, dead and turn’d to clay, +Might stop a hole to keep the wind away. +O, that that earth which kept the world in awe +Should patch a wall t’expel the winter’s flaw. +But soft! but soft! aside! Here comes the King. + +Enter priests, &c, in procession; the corpse of Ophelia, Laertes and +Mourners following; King, Queen, their Trains, &c. + +The Queen, the courtiers. Who is that they follow? +And with such maimed rites? This doth betoken +The corse they follow did with desperate hand +Fordo it own life. ’Twas of some estate. +Couch we awhile and mark. + +[_Retiring with Horatio._] + +LAERTES. +What ceremony else? + +HAMLET. +That is Laertes, a very noble youth. Mark. + +LAERTES. +What ceremony else? + +PRIEST. +Her obsequies have been as far enlarg’d +As we have warranties. Her death was doubtful; +And but that great command o’ersways the order, +She should in ground unsanctified have lodg’d +Till the last trumpet. For charitable prayers, +Shards, flints, and pebbles should be thrown on her. +Yet here she is allowed her virgin rites, +Her maiden strewments, and the bringing home +Of bell and burial. + +LAERTES. +Must there no more be done? + +PRIEST. +No more be done. +We should profane the service of the dead +To sing sage requiem and such rest to her +As to peace-parted souls. + +LAERTES. +Lay her i’ th’earth, +And from her fair and unpolluted flesh +May violets spring. I tell thee, churlish priest, +A minist’ring angel shall my sister be +When thou liest howling. + +HAMLET. +What, the fair Ophelia? + +QUEEN. +[_Scattering flowers._] Sweets to the sweet. Farewell. +I hop’d thou shouldst have been my Hamlet’s wife; +I thought thy bride-bed to have deck’d, sweet maid, +And not have strew’d thy grave. + +LAERTES. +O, treble woe +Fall ten times treble on that cursed head +Whose wicked deed thy most ingenious sense +Depriv’d thee of. Hold off the earth a while, +Till I have caught her once more in mine arms. +[_Leaps into the grave._] +Now pile your dust upon the quick and dead, +Till of this flat a mountain you have made, +To o’ertop old Pelion or the skyish head +Of blue Olympus. + +HAMLET. +[_Advancing._] +What is he whose grief +Bears such an emphasis? whose phrase of sorrow +Conjures the wand’ring stars, and makes them stand +Like wonder-wounded hearers? This is I, +Hamlet the Dane. +[_Leaps into the grave._] + +LAERTES. +[_Grappling with him._] The devil take thy soul! + +HAMLET. +Thou pray’st not well. +I prithee take thy fingers from my throat; +For though I am not splenative and rash, +Yet have I in me something dangerous, +Which let thy wiseness fear. Away thy hand! + +KING. +Pluck them asunder. + +QUEEN. +Hamlet! Hamlet! + +All. +Gentlemen! + +HORATIO. +Good my lord, be quiet. + +[_The Attendants part them, and they come out of the grave._] + +HAMLET. +Why, I will fight with him upon this theme +Until my eyelids will no longer wag. + +QUEEN. +O my son, what theme? + +HAMLET. +I lov’d Ophelia; forty thousand brothers +Could not, with all their quantity of love, +Make up my sum. What wilt thou do for her? + +KING. +O, he is mad, Laertes. + +QUEEN. +For love of God forbear him! + +HAMLET. +’Swounds, show me what thou’lt do: +Woul’t weep? woul’t fight? woul’t fast? woul’t tear thyself? +Woul’t drink up eisel? eat a crocodile? +I’ll do’t. Dost thou come here to whine? +To outface me with leaping in her grave? +Be buried quick with her, and so will I. +And if thou prate of mountains, let them throw +Millions of acres on us, till our ground, +Singeing his pate against the burning zone, +Make Ossa like a wart. Nay, an thou’lt mouth, +I’ll rant as well as thou. + +QUEEN. +This is mere madness: +And thus awhile the fit will work on him; +Anon, as patient as the female dove, +When that her golden couplets are disclos’d, +His silence will sit drooping. + +HAMLET. +Hear you, sir; +What is the reason that you use me thus? +I lov’d you ever. But it is no matter. +Let Hercules himself do what he may, +The cat will mew, and dog will have his day. + +[_Exit._] + +KING. +I pray thee, good Horatio, wait upon him. + +[_Exit Horatio._] + +[_To Laertes_] +Strengthen your patience in our last night’s speech; +We’ll put the matter to the present push.— +Good Gertrude, set some watch over your son. +This grave shall have a living monument. +An hour of quiet shortly shall we see; +Till then in patience our proceeding be. + +[_Exeunt._] + + SCENE II. A hall in the Castle. + +Enter Hamlet and Horatio. + +HAMLET. +So much for this, sir. Now let me see the other; +You do remember all the circumstance? + +HORATIO. +Remember it, my lord! + +HAMLET. +Sir, in my heart there was a kind of fighting +That would not let me sleep. Methought I lay +Worse than the mutinies in the bilboes. Rashly, +And prais’d be rashness for it,—let us know, +Our indiscretion sometime serves us well, +When our deep plots do pall; and that should teach us +There’s a divinity that shapes our ends, +Rough-hew them how we will. + +HORATIO. +That is most certain. + +HAMLET. +Up from my cabin, +My sea-gown scarf’d about me, in the dark +Grop’d I to find out them; had my desire, +Finger’d their packet, and in fine, withdrew +To mine own room again, making so bold, +My fears forgetting manners, to unseal +Their grand commission; where I found, Horatio, +Oh royal knavery! an exact command, +Larded with many several sorts of reasons, +Importing Denmark’s health, and England’s too, +With ho! such bugs and goblins in my life, +That on the supervise, no leisure bated, +No, not to stay the grinding of the axe, +My head should be struck off. + +HORATIO. +Is’t possible? + +HAMLET. +Here’s the commission, read it at more leisure. +But wilt thou hear me how I did proceed? + +HORATIO. +I beseech you. + +HAMLET. +Being thus benetted round with villanies,— +Or I could make a prologue to my brains, +They had begun the play,—I sat me down, +Devis’d a new commission, wrote it fair: +I once did hold it, as our statists do, +A baseness to write fair, and labour’d much +How to forget that learning; but, sir, now +It did me yeoman’s service. Wilt thou know +The effect of what I wrote? + +HORATIO. +Ay, good my lord. + +HAMLET. +An earnest conjuration from the King, +As England was his faithful tributary, +As love between them like the palm might flourish, +As peace should still her wheaten garland wear +And stand a comma ’tween their amities, +And many such-like ‘as’es of great charge, +That on the view and know of these contents, +Without debatement further, more or less, +He should the bearers put to sudden death, +Not shriving-time allow’d. + +HORATIO. +How was this seal’d? + +HAMLET. +Why, even in that was heaven ordinant. +I had my father’s signet in my purse, +Which was the model of that Danish seal: +Folded the writ up in the form of the other, +Subscrib’d it: gave’t th’impression; plac’d it safely, +The changeling never known. Now, the next day +Was our sea-fight, and what to this was sequent +Thou know’st already. + +HORATIO. +So Guildenstern and Rosencrantz go to’t. + +HAMLET. +Why, man, they did make love to this employment. +They are not near my conscience; their defeat +Does by their own insinuation grow. +’Tis dangerous when the baser nature comes +Between the pass and fell incensed points +Of mighty opposites. + +HORATIO. +Why, what a king is this! + +HAMLET. +Does it not, thinks’t thee, stand me now upon,— +He that hath kill’d my king, and whor’d my mother, +Popp’d in between th’election and my hopes, +Thrown out his angle for my proper life, +And with such cozenage—is’t not perfect conscience +To quit him with this arm? And is’t not to be damn’d +To let this canker of our nature come +In further evil? + +HORATIO. +It must be shortly known to him from England +What is the issue of the business there. + +HAMLET. +It will be short. The interim is mine; +And a man’s life’s no more than to say ‘One’. +But I am very sorry, good Horatio, +That to Laertes I forgot myself; +For by the image of my cause I see +The portraiture of his. I’ll court his favours. +But sure the bravery of his grief did put me +Into a tow’ring passion. + +HORATIO. +Peace, who comes here? + +Enter Osric. + +OSRIC. +Your lordship is right welcome back to Denmark. + +HAMLET. +I humbly thank you, sir. Dost know this waterfly? + +HORATIO. +No, my good lord. + +HAMLET. +Thy state is the more gracious; for ’tis a vice to know him. He hath +much land, and fertile; let a beast be lord of beasts, and his crib +shall stand at the king’s mess; ’tis a chough; but, as I say, spacious +in the possession of dirt. + +OSRIC. +Sweet lord, if your lordship were at leisure, I should impart a thing +to you from his Majesty. + +HAMLET. +I will receive it with all diligence of spirit. Put your bonnet to his +right use; ’tis for the head. + +OSRIC. +I thank your lordship, ’tis very hot. + +HAMLET. +No, believe me, ’tis very cold, the wind is northerly. + +OSRIC. +It is indifferent cold, my lord, indeed. + +HAMLET. +Methinks it is very sultry and hot for my complexion. + +OSRIC. +Exceedingly, my lord; it is very sultry,—as ’twere—I cannot tell how. +But, my lord, his Majesty bade me signify to you that he has laid a +great wager on your head. Sir, this is the matter,— + +HAMLET. +I beseech you, remember,— + +[_Hamlet moves him to put on his hat._] + +OSRIC. +Nay, in good faith; for mine ease, in good faith. Sir, here is newly +come to court Laertes; believe me, an absolute gentleman, full of most +excellent differences, of very soft society and great showing. Indeed, +to speak feelingly of him, he is the card or calendar of gentry; for +you shall find in him the continent of what part a gentleman would see. + +HAMLET. +Sir, his definement suffers no perdition in you, though I know, to +divide him inventorially would dizzy th’arithmetic of memory, and yet +but yaw neither, in respect of his quick sail. But, in the verity of +extolment, I take him to be a soul of great article and his infusion of +such dearth and rareness as, to make true diction of him, his semblable +is his mirror and who else would trace him his umbrage, nothing more. + +OSRIC. +Your lordship speaks most infallibly of him. + +HAMLET. +The concernancy, sir? Why do we wrap the gentleman in our more rawer +breath? + +OSRIC. +Sir? + +HORATIO. +Is’t not possible to understand in another tongue? You will do’t, sir, +really. + +HAMLET. +What imports the nomination of this gentleman? + +OSRIC. +Of Laertes? + +HORATIO. +His purse is empty already, all’s golden words are spent. + +HAMLET. +Of him, sir. + +OSRIC. +I know you are not ignorant,— + +HAMLET. +I would you did, sir; yet in faith if you did, it would not much +approve me. Well, sir? + +OSRIC. +You are not ignorant of what excellence Laertes is,— + +HAMLET. +I dare not confess that, lest I should compare with him in excellence; +but to know a man well were to know himself. + +OSRIC. +I mean, sir, for his weapon; but in the imputation laid on him, by them +in his meed he’s unfellowed. + +HAMLET. +What’s his weapon? + +OSRIC. +Rapier and dagger. + +HAMLET. +That’s two of his weapons. But well. + +OSRIC. +The King, sir, hath wager’d with him six Barbary horses, against the +which he has imponed, as I take it, six French rapiers and poniards, +with their assigns, as girdle, hangers, and so. Three of the carriages, +in faith, are very dear to fancy, very responsive to the hilts, most +delicate carriages, and of very liberal conceit. + +HAMLET. +What call you the carriages? + +HORATIO. +I knew you must be edified by the margin ere you had done. + +OSRIC. +The carriages, sir, are the hangers. + +HAMLET. +The phrase would be more german to the matter if we could carry cannon +by our sides. I would it might be hangers till then. But on. Six +Barbary horses against six French swords, their assigns, and three +liberal conceited carriages: that’s the French bet against the Danish. +Why is this all imponed, as you call it? + +OSRIC. +The King, sir, hath laid that in a dozen passes between you and him, he +shall not exceed you three hits. He hath laid on twelve for nine. And +it would come to immediate trial if your lordship would vouchsafe the +answer. + +HAMLET. +How if I answer no? + +OSRIC. +I mean, my lord, the opposition of your person in trial. + +HAMLET. +Sir, I will walk here in the hall. If it please his Majesty, it is the +breathing time of day with me. Let the foils be brought, the gentleman +willing, and the King hold his purpose, I will win for him if I can; if +not, I will gain nothing but my shame and the odd hits. + +OSRIC. +Shall I re-deliver you e’en so? + +HAMLET. +To this effect, sir; after what flourish your nature will. + +OSRIC. +I commend my duty to your lordship. + +HAMLET. +Yours, yours. + +[_Exit Osric._] + +He does well to commend it himself, there are no tongues else for’s +turn. + +HORATIO. +This lapwing runs away with the shell on his head. + +HAMLET. +He did comply with his dug before he suck’d it. Thus has he,—and many +more of the same bevy that I know the drossy age dotes on,— only got +the tune of the time and outward habit of encounter; a kind of yeasty +collection, which carries them through and through the most fanned and +winnowed opinions; and do but blow them to their trial, the bubbles are +out. + +Enter a Lord. + +LORD. +My lord, his Majesty commended him to you by young Osric, who brings +back to him that you attend him in the hall. He sends to know if your +pleasure hold to play with Laertes or that you will take longer time. + +HAMLET. +I am constant to my purposes, they follow the King’s pleasure. If his +fitness speaks, mine is ready. Now or whensoever, provided I be so able +as now. + +LORD. +The King and Queen and all are coming down. + +HAMLET. +In happy time. + +LORD. +The Queen desires you to use some gentle entertainment to Laertes +before you fall to play. + +HAMLET. +She well instructs me. + +[_Exit Lord._] + +HORATIO. +You will lose this wager, my lord. + +HAMLET. +I do not think so. Since he went into France, I have been in continual +practice. I shall win at the odds. But thou wouldst not think how ill +all’s here about my heart: but it is no matter. + +HORATIO. +Nay, good my lord. + +HAMLET. +It is but foolery; but it is such a kind of gain-giving as would +perhaps trouble a woman. + +HORATIO. +If your mind dislike anything, obey it. I will forestall their repair +hither, and say you are not fit. + +HAMLET. +Not a whit, we defy augury. There’s a special providence in the fall of +a sparrow. If it be now, ’tis not to come; if it be not to come, it +will be now; if it be not now, yet it will come. The readiness is all. +Since no man has aught of what he leaves, what is’t to leave betimes? + +Enter King, Queen, Laertes, Lords, Osric and Attendants with foils &c. + +KING. +Come, Hamlet, come, and take this hand from me. + +[_The King puts Laertes’s hand into Hamlet’s._] + +HAMLET. +Give me your pardon, sir. I have done you wrong; +But pardon’t as you are a gentleman. +This presence knows, and you must needs have heard, +How I am punish’d with sore distraction. +What I have done +That might your nature, honour, and exception +Roughly awake, I here proclaim was madness. +Was’t Hamlet wrong’d Laertes? Never Hamlet. +If Hamlet from himself be ta’en away, +And when he’s not himself does wrong Laertes, +Then Hamlet does it not, Hamlet denies it. +Who does it, then? His madness. If’t be so, +Hamlet is of the faction that is wrong’d; +His madness is poor Hamlet’s enemy. +Sir, in this audience, +Let my disclaiming from a purpos’d evil +Free me so far in your most generous thoughts +That I have shot my arrow o’er the house +And hurt my brother. + +LAERTES. +I am satisfied in nature, +Whose motive in this case should stir me most +To my revenge. But in my terms of honour +I stand aloof, and will no reconcilement +Till by some elder masters of known honour +I have a voice and precedent of peace +To keep my name ungor’d. But till that time +I do receive your offer’d love like love, +And will not wrong it. + +HAMLET. +I embrace it freely, +And will this brother’s wager frankly play.— +Give us the foils; come on. + +LAERTES. +Come, one for me. + +HAMLET. +I’ll be your foil, Laertes; in mine ignorance +Your skill shall like a star i’ th’ darkest night, +Stick fiery off indeed. + +LAERTES. +You mock me, sir. + +HAMLET. +No, by this hand. + +KING. +Give them the foils, young Osric. Cousin Hamlet, +You know the wager? + +HAMLET. +Very well, my lord. +Your Grace has laid the odds o’ the weaker side. + +KING. +I do not fear it. I have seen you both; +But since he is better’d, we have therefore odds. + +LAERTES. +This is too heavy. Let me see another. + +HAMLET. +This likes me well. These foils have all a length? + +[_They prepare to play._] + +OSRIC. +Ay, my good lord. + +KING. +Set me the stoups of wine upon that table. +If Hamlet give the first or second hit, +Or quit in answer of the third exchange, +Let all the battlements their ordnance fire; +The King shall drink to Hamlet’s better breath, +And in the cup an union shall he throw +Richer than that which four successive kings +In Denmark’s crown have worn. Give me the cups; +And let the kettle to the trumpet speak, +The trumpet to the cannoneer without, +The cannons to the heavens, the heavens to earth, +‘Now the King drinks to Hamlet.’ Come, begin. +And you, the judges, bear a wary eye. + +HAMLET. +Come on, sir. + +LAERTES. +Come, my lord. + +[_They play._] + +HAMLET. +One. + +LAERTES. +No. + +HAMLET. +Judgement. + +OSRIC. +A hit, a very palpable hit. + +LAERTES. +Well; again. + +KING. +Stay, give me drink. Hamlet, this pearl is thine; +Here’s to thy health. + +[_Trumpets sound, and cannon shot off within._] + +Give him the cup. + +HAMLET. +I’ll play this bout first; set it by awhile. + +[_They play._] + +Come. Another hit; what say you? + +LAERTES. +A touch, a touch, I do confess. + +KING. +Our son shall win. + +QUEEN. +He’s fat, and scant of breath. +Here, Hamlet, take my napkin, rub thy brows. +The Queen carouses to thy fortune, Hamlet. + +HAMLET. +Good madam. + +KING. +Gertrude, do not drink. + +QUEEN. +I will, my lord; I pray you pardon me. + +KING. +[_Aside._] It is the poison’d cup; it is too late. + +HAMLET. +I dare not drink yet, madam. By and by. + +QUEEN. +Come, let me wipe thy face. + +LAERTES. +My lord, I’ll hit him now. + +KING. +I do not think’t. + +LAERTES. +[_Aside._] And yet ’tis almost ’gainst my conscience. + +HAMLET. +Come for the third, Laertes. You do but dally. +I pray you pass with your best violence. +I am afeard you make a wanton of me. + +LAERTES. +Say you so? Come on. + +[_They play._] + +OSRIC. +Nothing neither way. + +LAERTES. +Have at you now. + +[_Laertes wounds Hamlet; then, in scuffling, they change rapiers, and +Hamlet wounds Laertes._] + +KING. +Part them; they are incens’d. + +HAMLET. +Nay, come again! + +[_The Queen falls._] + +OSRIC. +Look to the Queen there, ho! + +HORATIO. +They bleed on both sides. How is it, my lord? + +OSRIC. +How is’t, Laertes? + +LAERTES. +Why, as a woodcock to my own springe, Osric. +I am justly kill’d with mine own treachery. + +HAMLET. +How does the Queen? + +KING. +She swoons to see them bleed. + +QUEEN. +No, no, the drink, the drink! O my dear Hamlet! +The drink, the drink! I am poison’d. + +[_Dies._] + +HAMLET. +O villany! Ho! Let the door be lock’d: +Treachery! Seek it out. + +[_Laertes falls._] + +LAERTES. +It is here, Hamlet. Hamlet, thou art slain. +No medicine in the world can do thee good. +In thee there is not half an hour of life; +The treacherous instrument is in thy hand, +Unbated and envenom’d. The foul practice +Hath turn’d itself on me. Lo, here I lie, +Never to rise again. Thy mother’s poison’d. +I can no more. The King, the King’s to blame. + +HAMLET. +The point envenom’d too! +Then, venom, to thy work. + +[_Stabs the King._] + +OSRIC and LORDS. +Treason! treason! + +KING. +O yet defend me, friends. I am but hurt. + +HAMLET. +Here, thou incestuous, murderous, damned Dane, +Drink off this potion. Is thy union here? +Follow my mother. + +[_King dies._] + +LAERTES. +He is justly serv’d. +It is a poison temper’d by himself. +Exchange forgiveness with me, noble Hamlet. +Mine and my father’s death come not upon thee, +Nor thine on me. + +[_Dies._] + +HAMLET. +Heaven make thee free of it! I follow thee. +I am dead, Horatio. Wretched Queen, adieu. +You that look pale and tremble at this chance, +That are but mutes or audience to this act, +Had I but time,—as this fell sergeant, death, +Is strict in his arrest,—O, I could tell you,— +But let it be. Horatio, I am dead, +Thou liv’st; report me and my cause aright +To the unsatisfied. + +HORATIO. +Never believe it. +I am more an antique Roman than a Dane. +Here’s yet some liquor left. + +HAMLET. +As th’art a man, +Give me the cup. Let go; by Heaven, I’ll have’t. +O good Horatio, what a wounded name, +Things standing thus unknown, shall live behind me. +If thou didst ever hold me in thy heart, +Absent thee from felicity awhile, +And in this harsh world draw thy breath in pain, +To tell my story. + +[_March afar off, and shot within._] + +What warlike noise is this? + +OSRIC. +Young Fortinbras, with conquest come from Poland, +To the ambassadors of England gives +This warlike volley. + +HAMLET. +O, I die, Horatio. +The potent poison quite o’er-crows my spirit: +I cannot live to hear the news from England, +But I do prophesy th’election lights +On Fortinbras. He has my dying voice. +So tell him, with the occurrents more and less, +Which have solicited. The rest is silence. + +[_Dies._] + +HORATIO. +Now cracks a noble heart. Good night, sweet prince, +And flights of angels sing thee to thy rest. +Why does the drum come hither? + +[_March within._] + +Enter Fortinbras, the English Ambassadors and others. + +FORTINBRAS. +Where is this sight? + +HORATIO. +What is it you would see? +If aught of woe or wonder, cease your search. + +FORTINBRAS. +This quarry cries on havoc. O proud death, +What feast is toward in thine eternal cell, +That thou so many princes at a shot +So bloodily hast struck? + +FIRST AMBASSADOR. +The sight is dismal; +And our affairs from England come too late. +The ears are senseless that should give us hearing, +To tell him his commandment is fulfill’d, +That Rosencrantz and Guildenstern are dead. +Where should we have our thanks? + +HORATIO. +Not from his mouth, +Had it th’ability of life to thank you. +He never gave commandment for their death. +But since, so jump upon this bloody question, +You from the Polack wars, and you from England +Are here arriv’d, give order that these bodies +High on a stage be placed to the view, +And let me speak to th’ yet unknowing world +How these things came about. So shall you hear +Of carnal, bloody and unnatural acts, +Of accidental judgements, casual slaughters, +Of deaths put on by cunning and forc’d cause, +And, in this upshot, purposes mistook +Fall’n on the inventors’ heads. All this can I +Truly deliver. + +FORTINBRAS. +Let us haste to hear it, +And call the noblest to the audience. +For me, with sorrow I embrace my fortune. +I have some rights of memory in this kingdom, +Which now to claim my vantage doth invite me. + +HORATIO. +Of that I shall have also cause to speak, +And from his mouth whose voice will draw on more. +But let this same be presently perform’d, +Even while men’s minds are wild, lest more mischance +On plots and errors happen. + +FORTINBRAS. +Let four captains +Bear Hamlet like a soldier to the stage, +For he was likely, had he been put on, +To have prov’d most royally; and for his passage, +The soldiers’ music and the rites of war +Speak loudly for him. +Take up the bodies. Such a sight as this +Becomes the field, but here shows much amiss. +Go, bid the soldiers shoot. + +[_A dead march._] + +[_Exeunt, bearing off the bodies, after which a peal of ordnance is +shot off._] + + + + + + + *** END OF THE PROJECT GUTENBERG EBOOK HAMLET, PRINCE OF DENMARK *** + + + + +Updated editions will replace the previous one—the old editions will +be renamed. + +Creating the works from print editions not protected by U.S. copyright +law means that no one owns a United States copyright in these works, +so the Foundation (and you!) can copy and distribute it in the United +States without permission and without paying copyright +royalties. Special rules, set forth in the General Terms of Use part +of this license, apply to copying and distributing Project +Gutenberg™ electronic works to protect the PROJECT GUTENBERG™ +concept and trademark. Project Gutenberg is a registered trademark, +and may not be used if you charge for an eBook, except by following +the terms of the trademark license, including paying royalties for use +of the Project Gutenberg trademark. If you do not charge anything for +copies of this eBook, complying with the trademark license is very +easy. You may use this eBook for nearly any purpose such as creation +of derivative works, reports, performances and research. Project +Gutenberg eBooks may be modified and printed and given away—you may +do practically ANYTHING in the United States with eBooks not protected +by U.S. copyright law. Redistribution is subject to the trademark +license, especially commercial redistribution. + + +START: FULL LICENSE + +THE FULL PROJECT GUTENBERG LICENSE + +PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK + +To protect the Project Gutenberg™ mission of promoting the free +distribution of electronic works, by using or distributing this work +(or any other work associated in any way with the phrase “Project +Gutenberg”), you agree to comply with all the terms of the Full +Project Gutenberg™ License available with this file or online at +www.gutenberg.org/license. + +Section 1. General Terms of Use and Redistributing Project Gutenberg™ +electronic works + +1.A. By reading or using any part of this Project Gutenberg™ +electronic work, you indicate that you have read, understand, agree to +and accept all the terms of this license and intellectual property +(trademark/copyright) agreement. If you do not agree to abide by all +the terms of this agreement, you must cease using and return or +destroy all copies of Project Gutenberg™ electronic works in your +possession. If you paid a fee for obtaining a copy of or access to a +Project Gutenberg™ electronic work and you do not agree to be bound +by the terms of this agreement, you may obtain a refund from the person +or entity to whom you paid the fee as set forth in paragraph 1.E.8. + +1.B. “Project Gutenberg” is a registered trademark. It may only be +used on or associated in any way with an electronic work by people who +agree to be bound by the terms of this agreement. There are a few +things that you can do with most Project Gutenberg™ electronic works +even without complying with the full terms of this agreement. See +paragraph 1.C below. There are a lot of things you can do with Project +Gutenberg™ electronic works if you follow the terms of this +agreement and help preserve free future access to Project Gutenberg™ +electronic works. See paragraph 1.E below. + +1.C. The Project Gutenberg Literary Archive Foundation (“the +Foundation” or PGLAF), owns a compilation copyright in the collection +of Project Gutenberg™ electronic works. Nearly all the individual +works in the collection are in the public domain in the United +States. If an individual work is unprotected by copyright law in the +United States and you are located in the United States, we do not +claim a right to prevent you from copying, distributing, performing, +displaying or creating derivative works based on the work as long as +all references to Project Gutenberg are removed. Of course, we hope +that you will support the Project Gutenberg™ mission of promoting +free access to electronic works by freely sharing Project Gutenberg™ +works in compliance with the terms of this agreement for keeping the +Project Gutenberg™ name associated with the work. You can easily +comply with the terms of this agreement by keeping this work in the +same format with its attached full Project Gutenberg™ License when +you share it without charge with others. + +1.D. The copyright laws of the place where you are located also govern +what you can do with this work. Copyright laws in most countries are +in a constant state of change. If you are outside the United States, +check the laws of your country in addition to the terms of this +agreement before downloading, copying, displaying, performing, +distributing or creating derivative works based on this work or any +other Project Gutenberg™ work. The Foundation makes no +representations concerning the copyright status of any work in any +country other than the United States. + +1.E. Unless you have removed all references to Project Gutenberg: + +1.E.1. The following sentence, with active links to, or other +immediate access to, the full Project Gutenberg™ License must appear +prominently whenever any copy of a Project Gutenberg™ work (any work +on which the phrase “Project Gutenberg” appears, or with which the +phrase “Project Gutenberg” is associated) is accessed, displayed, +performed, viewed, copied or distributed: + + This eBook is for the use of anyone anywhere in the United States and most + other parts of the world at no cost and with almost no restrictions + whatsoever. You may copy it, give it away or re-use it under the terms + of the Project Gutenberg License included with this eBook or online + at www.gutenberg.org. If you + are not located in the United States, you will have to check the laws + of the country where you are located before using this eBook. + +1.E.2. If an individual Project Gutenberg™ electronic work is +derived from texts not protected by U.S. copyright law (does not +contain a notice indicating that it is posted with permission of the +copyright holder), the work can be copied and distributed to anyone in +the United States without paying any fees or charges. If you are +redistributing or providing access to a work with the phrase “Project +Gutenberg” associated with or appearing on the work, you must comply +either with the requirements of paragraphs 1.E.1 through 1.E.7 or +obtain permission for the use of the work and the Project Gutenberg™ +trademark as set forth in paragraphs 1.E.8 or 1.E.9. + +1.E.3. If an individual Project Gutenberg™ electronic work is posted +with the permission of the copyright holder, your use and distribution +must comply with both paragraphs 1.E.1 through 1.E.7 and any +additional terms imposed by the copyright holder. Additional terms +will be linked to the Project Gutenberg™ License for all works +posted with the permission of the copyright holder found at the +beginning of this work. + +1.E.4. Do not unlink or detach or remove the full Project Gutenberg™ +License terms from this work, or any files containing a part of this +work or any other work associated with Project Gutenberg™. + +1.E.5. Do not copy, display, perform, distribute or redistribute this +electronic work, or any part of this electronic work, without +prominently displaying the sentence set forth in paragraph 1.E.1 with +active links or immediate access to the full terms of the Project +Gutenberg™ License. + +1.E.6. You may convert to and distribute this work in any binary, +compressed, marked up, nonproprietary or proprietary form, including +any word processing or hypertext form. However, if you provide access +to or distribute copies of a Project Gutenberg™ work in a format +other than “Plain Vanilla ASCII” or other format used in the official +version posted on the official Project Gutenberg™ website +(www.gutenberg.org), you must, at no additional cost, fee or expense +to the user, provide a copy, a means of exporting a copy, or a means +of obtaining a copy upon request, of the work in its original “Plain +Vanilla ASCII” or other form. Any alternate format must include the +full Project Gutenberg™ License as specified in paragraph 1.E.1. + +1.E.7. Do not charge a fee for access to, viewing, displaying, +performing, copying or distributing any Project Gutenberg™ works +unless you comply with paragraph 1.E.8 or 1.E.9. + +1.E.8. You may charge a reasonable fee for copies of or providing +access to or distributing Project Gutenberg™ electronic works +provided that: + + • You pay a royalty fee of 20% of the gross profits you derive from + the use of Project Gutenberg™ works calculated using the method + you already use to calculate your applicable taxes. The fee is owed + to the owner of the Project Gutenberg™ trademark, but he has + agreed to donate royalties under this paragraph to the Project + Gutenberg Literary Archive Foundation. Royalty payments must be paid + within 60 days following each date on which you prepare (or are + legally required to prepare) your periodic tax returns. Royalty + payments should be clearly marked as such and sent to the Project + Gutenberg Literary Archive Foundation at the address specified in + Section 4, “Information about donations to the Project Gutenberg + Literary Archive Foundation.” + + • You provide a full refund of any money paid by a user who notifies + you in writing (or by e-mail) within 30 days of receipt that s/he + does not agree to the terms of the full Project Gutenberg™ + License. You must require such a user to return or destroy all + copies of the works possessed in a physical medium and discontinue + all use of and all access to other copies of Project Gutenberg™ + works. + + • You provide, in accordance with paragraph 1.F.3, a full refund of + any money paid for a work or a replacement copy, if a defect in the + electronic work is discovered and reported to you within 90 days of + receipt of the work. + + • You comply with all other terms of this agreement for free + distribution of Project Gutenberg™ works. + + +1.E.9. If you wish to charge a fee or distribute a Project +Gutenberg™ electronic work or group of works on different terms than +are set forth in this agreement, you must obtain permission in writing +from the Project Gutenberg Literary Archive Foundation, the manager of +the Project Gutenberg™ trademark. Contact the Foundation as set +forth in Section 3 below. + +1.F. + +1.F.1. Project Gutenberg volunteers and employees expend considerable +effort to identify, do copyright research on, transcribe and proofread +works not protected by U.S. copyright law in creating the Project +Gutenberg™ collection. Despite these efforts, Project Gutenberg™ +electronic works, and the medium on which they may be stored, may +contain “Defects,” such as, but not limited to, incomplete, inaccurate +or corrupt data, transcription errors, a copyright or other +intellectual property infringement, a defective or damaged disk or +other medium, a computer virus, or computer codes that damage or +cannot be read by your equipment. + +1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except for the “Right +of Replacement or Refund” described in paragraph 1.F.3, the Project +Gutenberg Literary Archive Foundation, the owner of the Project +Gutenberg™ trademark, and any other party distributing a Project +Gutenberg™ electronic work under this agreement, disclaim all +liability to you for damages, costs and expenses, including legal +fees. YOU AGREE THAT YOU HAVE NO REMEDIES FOR NEGLIGENCE, STRICT +LIABILITY, BREACH OF WARRANTY OR BREACH OF CONTRACT EXCEPT THOSE +PROVIDED IN PARAGRAPH 1.F.3. YOU AGREE THAT THE FOUNDATION, THE +TRADEMARK OWNER, AND ANY DISTRIBUTOR UNDER THIS AGREEMENT WILL NOT BE +LIABLE TO YOU FOR ACTUAL, DIRECT, INDIRECT, CONSEQUENTIAL, PUNITIVE OR +INCIDENTAL DAMAGES EVEN IF YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH +DAMAGE. + +1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you discover a +defect in this electronic work within 90 days of receiving it, you can +receive a refund of the money (if any) you paid for it by sending a +written explanation to the person you received the work from. If you +received the work on a physical medium, you must return the medium +with your written explanation. The person or entity that provided you +with the defective work may elect to provide a replacement copy in +lieu of a refund. If you received the work electronically, the person +or entity providing it to you may choose to give you a second +opportunity to receive the work electronically in lieu of a refund. If +the second copy is also defective, you may demand a refund in writing +without further opportunities to fix the problem. + +1.F.4. Except for the limited right of replacement or refund set forth +in paragraph 1.F.3, this work is provided to you ‘AS-IS’, WITH NO +OTHER WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PURPOSE. + +1.F.5. Some states do not allow disclaimers of certain implied +warranties or the exclusion or limitation of certain types of +damages. If any disclaimer or limitation set forth in this agreement +violates the law of the state applicable to this agreement, the +agreement shall be interpreted to make the maximum disclaimer or +limitation permitted by the applicable state law. The invalidity or +unenforceability of any provision of this agreement shall not void the +remaining provisions. + +1.F.6. INDEMNITY - You agree to indemnify and hold the Foundation, the +trademark owner, any agent or employee of the Foundation, anyone +providing copies of Project Gutenberg™ electronic works in +accordance with this agreement, and any volunteers associated with the +production, promotion and distribution of Project Gutenberg™ +electronic works, harmless from all liability, costs and expenses, +including legal fees, that arise directly or indirectly from any of +the following which you do or cause to occur: (a) distribution of this +or any Project Gutenberg™ work, (b) alteration, modification, or +additions or deletions to any Project Gutenberg™ work, and (c) any +Defect you cause. + +Section 2. Information about the Mission of Project Gutenberg™ + +Project Gutenberg™ is synonymous with the free distribution of +electronic works in formats readable by the widest variety of +computers including obsolete, old, middle-aged and new computers. It +exists because of the efforts of hundreds of volunteers and donations +from people in all walks of life. + +Volunteers and financial support to provide volunteers with the +assistance they need are critical to reaching Project Gutenberg™’s +goals and ensuring that the Project Gutenberg™ collection will +remain freely available for generations to come. In 2001, the Project +Gutenberg Literary Archive Foundation was created to provide a secure +and permanent future for Project Gutenberg™ and future +generations. To learn more about the Project Gutenberg Literary +Archive Foundation and how your efforts and donations can help, see +Sections 3 and 4 and the Foundation information page at www.gutenberg.org. + +Section 3. Information about the Project Gutenberg Literary Archive Foundation + +The Project Gutenberg Literary Archive Foundation is a non-profit +501(c)(3) educational corporation organized under the laws of the +state of Mississippi and granted tax exempt status by the Internal +Revenue Service. The Foundation’s EIN or federal tax identification +number is 64-6221541. Contributions to the Project Gutenberg Literary +Archive Foundation are tax deductible to the full extent permitted by +U.S. federal laws and your state’s laws. + +The Foundation’s business office is located at 809 North 1500 West, +Salt Lake City, UT 84116, (801) 596-1887. Email contact links and up +to date contact information can be found at the Foundation’s website +and official page at www.gutenberg.org/contact + +Section 4. Information about Donations to the Project Gutenberg +Literary Archive Foundation + +Project Gutenberg™ depends upon and cannot survive without widespread +public support and donations to carry out its mission of +increasing the number of public domain and licensed works that can be +freely distributed in machine-readable form accessible by the widest +array of equipment including outdated equipment. Many small donations +($1 to $5,000) are particularly important to maintaining tax exempt +status with the IRS. + +The Foundation is committed to complying with the laws regulating +charities and charitable donations in all 50 states of the United +States. Compliance requirements are not uniform and it takes a +considerable effort, much paperwork and many fees to meet and keep up +with these requirements. We do not solicit donations in locations +where we have not received written confirmation of compliance. To SEND +DONATIONS or determine the status of compliance for any particular state +visit www.gutenberg.org/donate. + +While we cannot and do not solicit contributions from states where we +have not met the solicitation requirements, we know of no prohibition +against accepting unsolicited donations from donors in such states who +approach us with offers to donate. + +International donations are gratefully accepted, but we cannot make +any statements concerning tax treatment of donations received from +outside the United States. U.S. laws alone swamp our small staff. + +Please check the Project Gutenberg web pages for current donation +methods and addresses. Donations are accepted in a number of other +ways including checks, online payments and credit card donations. To +donate, please visit: www.gutenberg.org/donate. + +Section 5. General Information About Project Gutenberg™ electronic works + +Professor Michael S. Hart was the originator of the Project +Gutenberg™ concept of a library of electronic works that could be +freely shared with anyone. For forty years, he produced and +distributed Project Gutenberg™ eBooks with only a loose network of +volunteer support. + +Project Gutenberg™ eBooks are often created from several printed +editions, all of which are confirmed as not protected by copyright in +the U.S. unless a copyright notice is included. Thus, we do not +necessarily keep eBooks in compliance with any particular paper +edition. + +Most people start at our website which has the main PG search +facility: www.gutenberg.org. + +This website includes information about Project Gutenberg™, +including how to make donations to the Project Gutenberg Literary +Archive Foundation, how to help produce our new eBooks, and how to +subscribe to our email newsletter to hear about new eBooks. + + diff --git a/Samples~/HamletSearch/hamlet_project_gutenberg.txt.meta b/Samples~/HamletSearch/hamlet_project_gutenberg.txt.meta new file mode 100644 index 00000000..e850bd5e --- /dev/null +++ b/Samples~/HamletSearch/hamlet_project_gutenberg.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: be0ffe8c7b44139218ffd530749f1644 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From d15148943ed0807ea7f07cac21141d12907728fe Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 2 Feb 2024 17:42:22 +0200 Subject: [PATCH 047/161] fix formatting --- Runtime/Embedder.cs | 2 +- Runtime/Search.cs | 18 +++++++++++------- .../Runtime/Tokenizers/Decoders/Decoders.cs | 10 +++++----- .../PostProcessors/PostProcessors.cs | 10 +++++----- .../Tokenizers/PreTokenizers/PreTokenizers.cs | 2 +- .../Tokenizers/Tokenizers/Tokenizers.cs | 2 +- .../Tokenizers/Tokenizers/TokenizersUtils.cs | 2 +- 7 files changed, 25 insertions(+), 21 deletions(-) diff --git a/Runtime/Embedder.cs b/Runtime/Embedder.cs index 2fb41212..dea53470 100644 --- a/Runtime/Embedder.cs +++ b/Runtime/Embedder.cs @@ -36,7 +36,7 @@ public class EmbeddingModel : Embedder bool useMeanPooling; public int Dimensions { get; private set; } - public EmbeddingModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU, string outputLayerName = "last_hidden_state", bool useMeanPooling = true, int dimensions=384) + public EmbeddingModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU, string outputLayerName = "last_hidden_state", bool useMeanPooling = true, int dimensions = 384) { runtimeModel = ModelLoader.Load(modelPath); string tokenizerJsonContent = File.ReadAllText(tokenizerPath); diff --git a/Runtime/Search.cs b/Runtime/Search.cs index a430f02b..afb1ef8d 100644 --- a/Runtime/Search.cs +++ b/Runtime/Search.cs @@ -62,7 +62,8 @@ public class ModelSearch : Search { public ModelSearch(EmbeddingModel embedder) : base(embedder) {} - public override void Insert(string inputString, TensorFloat encoding){ + public override void Insert(string inputString, TensorFloat encoding) + { embeddings[inputString] = encoding; } @@ -99,19 +100,21 @@ public ANNModelSearch( ulong expansionAdd = 40, ulong expansionSearch = 16, bool multi = false - ) : this(embedder, new USearchIndex((ulong) embedder.Dimensions, metricKind, connectivity, expansionAdd, expansionSearch, multi)) {} + ) : this(embedder, new USearchIndex((ulong)embedder.Dimensions, metricKind, connectivity, expansionAdd, expansionSearch, multi)) {} public ANNModelSearch( EmbeddingModel embedder, USearchIndex index - ) : base(embedder) { + ) : base(embedder) + { this.index = index; TextToUSearch = new Dictionary(); USearchToText = new Dictionary(); nextKey = 0; } - public override void Insert(string inputString, TensorFloat encoding){ + public override void Insert(string inputString, TensorFloat encoding) + { if (TextToUSearch.ContainsKey(inputString)) return; ulong key = nextKey++; TextToUSearch[inputString] = key; @@ -124,7 +127,8 @@ public override List RetrieveSimilar(string queryString, int k) float[] queryEmbedding = embedder.Encode(queryString).ToReadOnlyArray(); index.Search(queryEmbedding, k, out ulong[] keys, out float[] distances); List result = new List(); - for(int i=0; i RetrieveSimilar(string queryString, int k) public new int Count() { Console.Write(index.Size()); - return (int) index.Size(); + return (int)index.Size(); } } -} \ No newline at end of file +} diff --git a/sharp-transformers/Runtime/Tokenizers/Decoders/Decoders.cs b/sharp-transformers/Runtime/Tokenizers/Decoders/Decoders.cs index b89e5a4d..f9fdfaa3 100644 --- a/sharp-transformers/Runtime/Tokenizers/Decoders/Decoders.cs +++ b/sharp-transformers/Runtime/Tokenizers/Decoders/Decoders.cs @@ -257,7 +257,7 @@ public override List DecodeChain(List tokens) return newTokens; } - + } /// @@ -273,8 +273,8 @@ public StripDecoder(JObject config) : base(config) { this.content = this.Config["content"].Value(); - this.start = this.Config["start"].Value(); - this.stop = this.Config["stop"].Value(); + this.start = this.Config["start"].Value(); + this.stop = this.Config["stop"].Value(); } public override List Decode(List tokens) @@ -313,7 +313,7 @@ public override List Decode(List tokens) return token.Substring(startCut, stopCut - startCut); }).ToList(); } -} + } /// @@ -338,7 +338,7 @@ public DecoderSequence(JObject config) : base(config) foreach (JObject decoderConfig in config["decoders"]) { - + var decoder = Decoder_.FromConfig(decoderConfig); if (decoder != null) diff --git a/sharp-transformers/Runtime/Tokenizers/PostProcessors/PostProcessors.cs b/sharp-transformers/Runtime/Tokenizers/PostProcessors/PostProcessors.cs index 5506f8f1..0e6c777d 100644 --- a/sharp-transformers/Runtime/Tokenizers/PostProcessors/PostProcessors.cs +++ b/sharp-transformers/Runtime/Tokenizers/PostProcessors/PostProcessors.cs @@ -76,14 +76,14 @@ public class TemplateProcessing : PostProcessor { // The template for a single sequence of tokens. public JArray Single; - + //public List Single; // The template for a pair of sequences of tokens. public JArray Pair; - + //public List Pair; - + /// /// Creates a new instance of TemplateProcessing /// @@ -120,7 +120,7 @@ public override List PostProcess(List tokens, List token string specialTokenId = (string)itemJson["SpecialToken"]["id"]; ToReturn.Add(specialTokenId); } - + // If the current item has a property called "Sequence" it means that this item // represents a sequence identifier (like 'A' or 'B') else if (itemJson.ContainsKey("Sequence")) @@ -143,4 +143,4 @@ public override List PostProcess(List tokens, List token return ToReturn; } } -} \ No newline at end of file +} diff --git a/sharp-transformers/Runtime/Tokenizers/PreTokenizers/PreTokenizers.cs b/sharp-transformers/Runtime/Tokenizers/PreTokenizers/PreTokenizers.cs index 42b6d033..429a2de8 100644 --- a/sharp-transformers/Runtime/Tokenizers/PreTokenizers/PreTokenizers.cs +++ b/sharp-transformers/Runtime/Tokenizers/PreTokenizers/PreTokenizers.cs @@ -143,4 +143,4 @@ public override List PreTokenizeText(string text) return tokens; } } -} \ No newline at end of file +} diff --git a/sharp-transformers/Runtime/Tokenizers/Tokenizers/Tokenizers.cs b/sharp-transformers/Runtime/Tokenizers/Tokenizers/Tokenizers.cs index dcd6a2e8..035baa0c 100644 --- a/sharp-transformers/Runtime/Tokenizers/Tokenizers/Tokenizers.cs +++ b/sharp-transformers/Runtime/Tokenizers/Tokenizers/Tokenizers.cs @@ -339,4 +339,4 @@ The resulting list of tokens is returned. return fused; } } -} \ No newline at end of file +} diff --git a/sharp-transformers/Runtime/Tokenizers/Tokenizers/TokenizersUtils.cs b/sharp-transformers/Runtime/Tokenizers/Tokenizers/TokenizersUtils.cs index 42e3656a..fb9b2d80 100644 --- a/sharp-transformers/Runtime/Tokenizers/Tokenizers/TokenizersUtils.cs +++ b/sharp-transformers/Runtime/Tokenizers/Tokenizers/TokenizersUtils.cs @@ -31,4 +31,4 @@ public static List Fuse(List arr, int value) return fused; } } -} \ No newline at end of file +} From 1641e9a504f9a470f9c14286e72eae07da74f357 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 2 Feb 2024 18:46:45 +0200 Subject: [PATCH 048/161] assert num embeddings, no TextToUSearch, insert lock --- Runtime/Search.cs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/Runtime/Search.cs b/Runtime/Search.cs index afb1ef8d..25741c2d 100644 --- a/Runtime/Search.cs +++ b/Runtime/Search.cs @@ -70,6 +70,10 @@ public override void Insert(string inputString, TensorFloat encoding) public new TensorFloat[] Add(string[] inputStrings) { TensorFloat[] inputEmbeddings = (TensorFloat[])embedder.Split(embedder.Encode(inputStrings)); + if (inputStrings.Length != inputEmbeddings.Length) + { + throw new Exception($"Number of computed embeddings ({inputEmbeddings.Length}) different than inputs ({inputStrings.Length})"); + } for (int i = 0; i < inputStrings.Length; i++) { Insert(inputStrings[i], inputEmbeddings[i]); @@ -89,9 +93,9 @@ public override List RetrieveSimilar(string queryString, int k) public class ANNModelSearch : ModelSearch { USearchIndex index; - protected Dictionary TextToUSearch; - protected Dictionary USearchToText; + Dictionary USearchToText; ulong nextKey; + object insertLock = new object(); public ANNModelSearch( EmbeddingModel embedder, @@ -108,18 +112,19 @@ USearchIndex index ) : base(embedder) { this.index = index; - TextToUSearch = new Dictionary(); USearchToText = new Dictionary(); nextKey = 0; } public override void Insert(string inputString, TensorFloat encoding) { - if (TextToUSearch.ContainsKey(inputString)) return; - ulong key = nextKey++; - TextToUSearch[inputString] = key; - USearchToText[key] = inputString; - index.Add(key, encoding.ToReadOnlyArray()); + if (USearchToText.ContainsValue(inputString)) return; + lock (insertLock) + { + ulong key = nextKey++; + USearchToText[key] = inputString; + index.Add(key, encoding.ToReadOnlyArray()); + } } public override List RetrieveSimilar(string queryString, int k) @@ -136,7 +141,6 @@ public override List RetrieveSimilar(string queryString, int k) public new int Count() { - Console.Write(index.Size()); return (int)index.Size(); } } From e5f82b54bdb05c7124d4dd8d35593fbb0753ccd9 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 2 Feb 2024 19:01:05 +0200 Subject: [PATCH 049/161] add metrics --- Samples~/HamletSearch/HamletSearch.cs | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/Samples~/HamletSearch/HamletSearch.cs b/Samples~/HamletSearch/HamletSearch.cs index 52162f8e..357e9ec7 100644 --- a/Samples~/HamletSearch/HamletSearch.cs +++ b/Samples~/HamletSearch/HamletSearch.cs @@ -4,6 +4,7 @@ using Debug = UnityEngine.Debug; using System.Text.RegularExpressions; using LLMUnity; +using System.Linq; class HamletSearch : MonoBehaviour { @@ -14,32 +15,39 @@ class HamletSearch : MonoBehaviour public void OnEnable() { - embedder = new BGEModel("Assets/StreamingAssets/bge-small-en-v1.5.sentis", "Assets/StreamingAssets/bge-small-en-v1.5.tokenizer.json"); + embedder = new BGEModel( + "Assets/StreamingAssets/bge-small-en-v1.5.sentis", + "Assets/StreamingAssets/bge-small-en-v1.5.tokenizer.json" + ); } void Start() { List dialogues = ReadGutenbergFile(gutenbergText.text); + List dialoguesToDo = fullPlay ? dialogues : new List { dialogues[2] }; search = new ANNModelSearch(embedder); Stopwatch stopwatch = new Stopwatch(); float elapsed_total = 0; + int numSentences = 0; - List dialoguesToDo = fullPlay ? dialogues : new List { dialogues[2] }; foreach (Dialogue dialogue in dialoguesToDo) { + string[] sentences = dialogue.GetSentences().ToArray(); + numSentences += sentences.Length; + stopwatch.Reset(); stopwatch.Start(); - search.Add(dialogue.GetSentences().ToArray()); + search.Add(sentences); stopwatch.Stop(); float elapsed = (float)stopwatch.Elapsed.TotalMilliseconds / 1000f; - Debug.Log($"{dialogue.Title} embed time: {elapsed} secs"); elapsed_total += elapsed; + Debug.Log($"{dialogue.Title} embed time: {elapsed} secs"); } - Debug.Log($"embedded {search.Count()} sentences in {elapsed_total} secs"); + Debug.Log($"embedded {numSentences} sentences in {elapsed_total} secs"); stopwatch.Reset(); stopwatch.Start(); - List similar = search.RetrieveSimilar("should i exist?", 5); + List similar = search.RetrieveSimilar("should i exist?", 10); stopwatch.Stop(); Debug.Log($"search time: {stopwatch.Elapsed.TotalMilliseconds / 1000f} secs"); @@ -62,6 +70,8 @@ public List ReadGutenbergFile(string text) string message = ""; bool add = false; Dialogue dialogue = null; + int numWords = 0; + int numLines = 0; string[] lines = text.Split("\n"); for (int i = 0; i < lines.Length; i++) @@ -74,6 +84,8 @@ public List ReadGutenbergFile(string text) line = line.Replace("\r", ""); line = Regex.Replace(line, skipPattern, ""); if (line == "") continue; + numWords += line.Split(new[] { ' ', '\t' }, System.StringSplitOptions.RemoveEmptyEntries).Length; + numLines++; if (line.StartsWith("ACT")) { @@ -101,8 +113,8 @@ public List ReadGutenbergFile(string text) if (message != "") message += " "; message += line; } - } + Debug.Log($"{numLines} lines, {numWords} words"); return dialogues; } From 13381d8d8ef96d47386059dc3cc1d148a1173b60 Mon Sep 17 00:00:00 2001 From: Antonios Makropoulos Date: Fri, 2 Feb 2024 19:21:47 +0200 Subject: [PATCH 050/161] make TensorFloat readable for GPU support --- Runtime/Search.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Runtime/Search.cs b/Runtime/Search.cs index 25741c2d..9734fc72 100644 --- a/Runtime/Search.cs +++ b/Runtime/Search.cs @@ -119,6 +119,7 @@ USearchIndex index public override void Insert(string inputString, TensorFloat encoding) { if (USearchToText.ContainsValue(inputString)) return; + encoding.MakeReadable(); lock (insertLock) { ulong key = nextKey++; @@ -129,8 +130,9 @@ public override void Insert(string inputString, TensorFloat encoding) public override List RetrieveSimilar(string queryString, int k) { - float[] queryEmbedding = embedder.Encode(queryString).ToReadOnlyArray(); - index.Search(queryEmbedding, k, out ulong[] keys, out float[] distances); + TensorFloat encoding = embedder.Encode(queryString); + encoding.MakeReadable(); + index.Search(encoding.ToReadOnlyArray(), k, out ulong[] keys, out float[] distances); List result = new List(); for (int i = 0; i < keys.Length; i++) { From 7a98bd39897828423c15b0fff4dd7b99409ae60f Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 2 Feb 2024 19:24:23 +0200 Subject: [PATCH 051/161] add sample to package.json --- package.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/package.json b/package.json index 07414263..79785b85 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,11 @@ "displayName": "ServerClient", "description": "Example with two AIs using LLMUnity.", "path": "Samples~/ServerClient" + }, + { + "displayName": "HamletSearch", + "description": "Example demonstrating search of relevant text with embeddings.", + "path": "Samples~/HamletSearch" } ], "author": { From b3d1a57b7cbf81f37f6fbd52ce8e115b46791eb4 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Mon, 5 Feb 2024 18:04:26 +0200 Subject: [PATCH 052/161] add function for list --- Runtime/Search.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Runtime/Search.cs b/Runtime/Search.cs index 9734fc72..ae670db0 100644 --- a/Runtime/Search.cs +++ b/Runtime/Search.cs @@ -81,6 +81,11 @@ public override void Insert(string inputString, TensorFloat encoding) return inputEmbeddings; } + public TensorFloat[] Add(List inputStrings) + { + return Add(inputStrings.ToArray()); + } + public override List RetrieveSimilar(string queryString, int k) { TensorFloat queryEmbedding = embedder.Encode(queryString); From 77bea585b0f4892419b152924872a3efb0d51406 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Mon, 5 Feb 2024 18:04:53 +0200 Subject: [PATCH 053/161] reorganise and split class functionality --- Runtime/Dialogue.cs | 235 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 183 insertions(+), 52 deletions(-) diff --git a/Runtime/Dialogue.cs b/Runtime/Dialogue.cs index fcaf0957..a602b25a 100644 --- a/Runtime/Dialogue.cs +++ b/Runtime/Dialogue.cs @@ -4,101 +4,232 @@ namespace LLMUnity { + public class Sentence + { + public int phraseId; + public int startIndex; + public int endIndex; + + public Sentence(int phraseId, int startIndex, int endIndex) + { + this.phraseId = phraseId; + this.startIndex = startIndex; + this.endIndex = endIndex; + } + } + + public class SentenceSplitter + { + public static char[] DefaultDelimiters = new char[] { '.', '!', ':', ';', '?', '\n', '\r', }; + char[] delimiters; + bool trimSentences = true; + + public SentenceSplitter(char[] delimiters, bool trimSentences = true) + { + this.delimiters = delimiters; + this.trimSentences = trimSentences; + } + + public SentenceSplitter() : this(SentenceSplitter.DefaultDelimiters, true) {} + + public List<(int, int)> Split(string input) + { + List<(int, int)> indices = new List<(int, int)>(); + int startIndex = 0; + bool sawDelimiter = true; + for (int i = 0; i < input.Length; i++) + { + if (sawDelimiter && trimSentences) + { + while (char.IsWhiteSpace(input[i]) && i < input.Length - 1) i++; + startIndex = i; + sawDelimiter = false; + } + if (delimiters.Contains(input[i]) || i == input.Length - 1) + { + int endIndex = i; + if (i == input.Length - 1 && trimSentences) + { + while (char.IsWhiteSpace(input[endIndex]) && endIndex > startIndex) endIndex--; + } + if (endIndex > startIndex || !trimSentences || (trimSentences && !char.IsWhiteSpace(input[startIndex]) && !delimiters.Contains(input[startIndex]))) + { + indices.Add((startIndex, endIndex)); + } + startIndex = i + 1; + sawDelimiter = true; + } + } + return indices; + } + } + public class Dialogue { public string Title { get; private set; } + public string Actor { get; private set; } - char[] delimiters; - Dictionary sentences; Dictionary phrases; - Dictionary> characterPhrases; - Dictionary> phraseSentences; - Dictionary sentencePhrase; - int nextSentenceId; + Dictionary> phraseSentences; int nextPhraseId; + SentenceSplitter sentenceSplitter; - public Dialogue(string title = "") + public Dialogue(string actor = "", string title = "") { + Actor = actor; Title = title; - sentences = new Dictionary(); phrases = new Dictionary(); - characterPhrases = new Dictionary>(); - phraseSentences = new Dictionary>(); - sentencePhrase = new Dictionary(); - nextSentenceId = 0; + phraseSentences = new Dictionary>(); nextPhraseId = 0; - SetDelimiters(new char[] { '.', '!', ':', ';', '?', '\n', '\r', }); - } - - public void SetDelimiters(char[] delimiters) - { - this.delimiters = delimiters; + sentenceSplitter = new SentenceSplitter(); } - public static void Add(Dictionary> dict, K key, V value) + public void SetSentenceSplitting(char[] delimiters, bool trimSentences = true) { - if (!dict.ContainsKey(key)) + if (nextPhraseId > 0) throw new Exception("Sentence splitting can't change when there are phrases in the Dialogue"); + if (delimiters == null) { - dict[key] = new List(); + sentenceSplitter = null; + } + else + { + sentenceSplitter = new SentenceSplitter(delimiters, trimSentences); } - dict[key].Add(value); } - int AddSentence(int phraseId, string sentence) + public void SetNoSentenceSplitting() { - int sentenceId = nextSentenceId++; - sentences[sentenceId] = sentence; - sentencePhrase[sentenceId] = phraseId; - return sentenceId; + SetSentenceSplitting(null); } - public void AddPhrase(string name, string phrase) + public void Add(string text) { int phraseId = nextPhraseId++; - phrases[phraseId] = phrase; - string[] sentences = phrase.Split(delimiters, StringSplitOptions.RemoveEmptyEntries); - for (int i = 0; i < sentences.Length; i++) + phrases[phraseId] = text; + if (sentenceSplitter == null) { - string sentence = sentences[i].Trim(); - int sentenceId = AddSentence(phraseId, sentence); - Add(phraseSentences, phraseId, sentenceId); + phraseSentences[phraseId] = new List { new Sentence(phraseId, 0, text.Length - 1) }; } - Add(characterPhrases, name, phraseId); + else + { + phraseSentences[phraseId] = new List(); + List<(int, int)> subindices = sentenceSplitter.Split(text); + foreach ((int startIndex, int endIndex) in subindices) + { + phraseSentences[phraseId].Add(new Sentence(phraseId, startIndex, endIndex)); + } + } + } + + public List GetPhrases() + { + return phrases.Values.ToList(); } - public List GetCharacterPhrases(string name) + public List GetSentences() { - if (!characterPhrases.ContainsKey(name)) + List allSentences = new List(); + foreach ((int phraseId, List sentences) in phraseSentences) { - return null; + string phrase = phrases[phraseId]; + foreach (Sentence sentence in sentences) + { + allSentences.Add(phrase.Substring(sentence.startIndex, sentence.endIndex - sentence.startIndex + 1)); + } } - List result = new List(); - foreach (int phraseId in characterPhrases[name]) + return allSentences; + } + + public void Clear() + { + phrases.Clear(); + foreach (List sentences in phraseSentences.Values) sentences.Clear(); + } + } + + public class DialogueManager + { + Dictionary> dialogues; + char[] delimiters = SentenceSplitter.DefaultDelimiters; + bool trimSentences = true; + + public DialogueManager() + { + dialogues = new Dictionary>(); + } + + public void SetSentenceSplitting(char[] delimiters, bool trimSentences = true) + { + this.delimiters = delimiters; + this.trimSentences = trimSentences; + } + + public void SetNoSentenceSplitting() + { + SetSentenceSplitting(null); + } + + public void Add(string actor, string title, string text) + { + if (!dialogues.ContainsKey(actor) || !dialogues[actor].ContainsKey(title)) { - result.Add(phrases[phraseId]); + Dialogue dialogue = new Dialogue(actor, title); + dialogue.SetSentenceSplitting(delimiters, trimSentences); + if (!dialogues.ContainsKey(actor)) + { + dialogues[actor] = new Dictionary(); + } + dialogues[actor][title] = dialogue; } - return result; + dialogues[actor][title].Add(text); } - public List GetCharacterSentences(string name) + public void Add(string actor, string text) { - if (!characterPhrases.ContainsKey(name)) + Add(actor, "", text); + } + + public List GetPhrases(string actor = null, string title = null) + { + List phrases = new List(); + foreach ((string actorName, Dictionary actorDialogues) in dialogues) { - return null; + foreach ((string titleName, Dialogue dialogue) in actorDialogues) + { + if ((actor == null || actor == actorName) && (title == null || title == titleName)) + { + phrases.AddRange(dialogue.GetPhrases()); + } + } } - List result = new List(); - foreach (int phraseId in characterPhrases[name]) + return phrases; + } + + public List GetSentences(string actor = null, string title = null) + { + List sentences = new List(); + foreach ((string actorName, Dictionary actorDialogues) in dialogues) { - foreach (int sentenceId in phraseSentences[phraseId]) + foreach ((string titleName, Dialogue dialogue) in actorDialogues) { - result.Add(sentences[sentenceId]); + if ((actor == null || actor == actorName) && (title == null || title == titleName)) + { + sentences.AddRange(dialogue.GetSentences()); + } } } - return result; + return sentences; } - public List GetSentences() + + public void Clear() { - return sentences.Values.ToList(); + foreach (Dictionary actorDialogues in dialogues.Values) + { + foreach (Dialogue dialogue in actorDialogues.Values) + { + dialogue.Clear(); + } + } } } } From 051507210e5712b6d54626d2e731f3818219d20e Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Mon, 5 Feb 2024 18:05:35 +0200 Subject: [PATCH 054/161] re-implement sample based on re-gorganised classes --- Samples~/HamletSearch/HamletSearch.cs | 42 +++++++++++++++------------ 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/Samples~/HamletSearch/HamletSearch.cs b/Samples~/HamletSearch/HamletSearch.cs index 357e9ec7..8ad0236f 100644 --- a/Samples~/HamletSearch/HamletSearch.cs +++ b/Samples~/HamletSearch/HamletSearch.cs @@ -5,6 +5,7 @@ using System.Text.RegularExpressions; using LLMUnity; using System.Linq; +using Unity.VisualScripting; class HamletSearch : MonoBehaviour { @@ -23,28 +24,32 @@ public void OnEnable() void Start() { - List dialogues = ReadGutenbergFile(gutenbergText.text); - List dialoguesToDo = fullPlay ? dialogues : new List { dialogues[2] }; + Dictionary> hamlet = ReadGutenbergFile(gutenbergText.text); + DialogueManager dialogueManager = new DialogueManager(); search = new ANNModelSearch(embedder); - Stopwatch stopwatch = new Stopwatch(); - float elapsed_total = 0; - int numSentences = 0; - foreach (Dialogue dialogue in dialoguesToDo) + int numSentences = 0; + float elapsedTotal = 0; + foreach ((string act, List<(string, string)> messages) in hamlet) { - string[] sentences = dialogue.GetSentences().ToArray(); - numSentences += sentences.Length; + if (!fullPlay && act != "ACT III") continue; + foreach ((string actor, string message) in messages) + dialogueManager.Add(actor, act, message); + messages.Clear(); + + List sentences = dialogueManager.GetSentences(null, act); + numSentences += sentences.Count; stopwatch.Reset(); stopwatch.Start(); search.Add(sentences); stopwatch.Stop(); - float elapsed = (float)stopwatch.Elapsed.TotalMilliseconds / 1000f; - elapsed_total += elapsed; - Debug.Log($"{dialogue.Title} embed time: {elapsed} secs"); + elapsedTotal += (float)stopwatch.Elapsed.TotalMilliseconds / 1000f; + Debug.Log($"act {act} embedded {sentences.Count} sentences in {stopwatch.Elapsed.TotalMilliseconds / 1000f} secs"); } - Debug.Log($"embedded {numSentences} sentences in {elapsed_total} secs"); + Debug.Log($"embedded {numSentences} sentences in {elapsedTotal} secs"); + Debug.Log(search.Count()); stopwatch.Reset(); stopwatch.Start(); List similar = search.RetrieveSimilar("should i exist?", 10); @@ -58,9 +63,8 @@ void Start() } } - public List ReadGutenbergFile(string text) + public Dictionary> ReadGutenbergFile(string text) { - List dialogues = new List(); string skipPattern = @"\[.*?\]"; string namePattern = "^[A-Z and]+\\.$"; Regex nameRegex = new Regex(namePattern); @@ -72,6 +76,7 @@ public List ReadGutenbergFile(string text) Dialogue dialogue = null; int numWords = 0; int numLines = 0; + Dictionary> messages = new Dictionary>(); string[] lines = text.Split("\n"); for (int i = 0; i < lines.Length; i++) @@ -91,11 +96,10 @@ public List ReadGutenbergFile(string text) { if (dialogue != null && message != "") { - dialogue.AddPhrase(name, message); + messages[act].Add((name, message)); } act = line.Replace(".", ""); - dialogue = new Dialogue(act); - dialogues.Add(dialogue); + messages[act] = new List<(string, string)>(); name = null; message = ""; } @@ -103,7 +107,7 @@ public List ReadGutenbergFile(string text) { if (name != null && message != "") { - dialogue.AddPhrase(name, message); + messages[act].Add((name, message)); } message = ""; name = line.Replace(".", ""); @@ -115,7 +119,7 @@ public List ReadGutenbergFile(string text) } } Debug.Log($"{numLines} lines, {numWords} words"); - return dialogues; + return messages; } public void OnDisable() From fee404c473ae5f0bc6b2da1be4c98e507fa2e7c3 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Tue, 6 Feb 2024 09:08:03 +0200 Subject: [PATCH 055/161] batch processing of sentences --- Runtime/Search.cs | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/Runtime/Search.cs b/Runtime/Search.cs index ae670db0..342e7496 100644 --- a/Runtime/Search.cs +++ b/Runtime/Search.cs @@ -67,23 +67,31 @@ public override void Insert(string inputString, TensorFloat encoding) embeddings[inputString] = encoding; } - public new TensorFloat[] Add(string[] inputStrings) + public TensorFloat[] Add(string[] inputStrings, int batchSize = 64) { - TensorFloat[] inputEmbeddings = (TensorFloat[])embedder.Split(embedder.Encode(inputStrings)); - if (inputStrings.Length != inputEmbeddings.Length) + return Add(new List(inputStrings), batchSize); + } + + public TensorFloat[] Add(List inputStrings, int batchSize = 64) + { + List inputEmbeddings = new List(); + for (int i = 0; i < inputStrings.Count; i += batchSize) { - throw new Exception($"Number of computed embeddings ({inputEmbeddings.Length}) different than inputs ({inputStrings.Length})"); + int takeCount = Math.Min(batchSize, inputStrings.Count - i); + List batch = new List(inputStrings.GetRange(i, takeCount)); + inputEmbeddings.AddRange((TensorFloat[])embedder.Split(embedder.Encode(batch))); + Console.WriteLine(takeCount); } - for (int i = 0; i < inputStrings.Length; i++) + + if (inputStrings.Count != inputEmbeddings.Count) + { + throw new Exception($"Number of computed embeddings ({inputEmbeddings.Count}) different than inputs ({inputStrings.Count})"); + } + for (int i = 0; i < inputStrings.Count; i++) { Insert(inputStrings[i], inputEmbeddings[i]); } - return inputEmbeddings; - } - - public TensorFloat[] Add(List inputStrings) - { - return Add(inputStrings.ToArray()); + return inputEmbeddings.ToArray(); } public override List RetrieveSimilar(string queryString, int k) From 4068f03ff65fd558a8f1b9262d7275b9944f2f21 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Tue, 6 Feb 2024 10:31:42 +0200 Subject: [PATCH 056/161] rename GetPhrases, remove Clear --- Runtime/Dialogue.cs | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/Runtime/Dialogue.cs b/Runtime/Dialogue.cs index a602b25a..26ff74b1 100644 --- a/Runtime/Dialogue.cs +++ b/Runtime/Dialogue.cs @@ -139,12 +139,6 @@ public List GetSentences() } return allSentences; } - - public void Clear() - { - phrases.Clear(); - foreach (List sentences in phraseSentences.Values) sentences.Clear(); - } } public class DialogueManager @@ -189,7 +183,7 @@ public void Add(string actor, string text) Add(actor, "", text); } - public List GetPhrases(string actor = null, string title = null) + public List Get(string actor = null, string title = null) { List phrases = new List(); foreach ((string actorName, Dictionary actorDialogues) in dialogues) @@ -220,16 +214,5 @@ public List GetSentences(string actor = null, string title = null) } return sentences; } - - public void Clear() - { - foreach (Dictionary actorDialogues in dialogues.Values) - { - foreach (Dialogue dialogue in actorDialogues.Values) - { - dialogue.Clear(); - } - } - } } } From 1c1c11029c4f77357817b29e64638865dc711cd4 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Tue, 6 Feb 2024 14:13:49 +0200 Subject: [PATCH 057/161] key-value based implementation --- Runtime/Search.cs | 158 ++++++++++++++++++++++++++++++---------------- 1 file changed, 102 insertions(+), 56 deletions(-) diff --git a/Runtime/Search.cs b/Runtime/Search.cs index 342e7496..1367c6f3 100644 --- a/Runtime/Search.cs +++ b/Runtime/Search.cs @@ -7,40 +7,46 @@ namespace LLMUnity { - public abstract class Search where E : Embedder + public abstract class ModelSearchBase { - protected E embedder; - protected Dictionary embeddings; + protected EmbeddingModel embedder; + protected Dictionary embeddings; - public abstract void Insert(string inputString, T encoding); - public abstract List RetrieveSimilar(string queryString, int k); - - public Search(E embedder) + public ModelSearchBase(EmbeddingModel embedder) { - embeddings = new Dictionary(); + embeddings = new Dictionary(); this.embedder = embedder; } - public T Add(string inputString) + public TensorFloat Encode(string inputString) { - T embedding = embedder.Encode(inputString); - Insert(inputString, embedding); - return embedding; + return embedder.Encode(inputString); } - public T[] Add(string[] inputStrings) + public TensorFloat[] Encode(List inputStrings, int batchSize = 64) { - T[] inputEmbeddings = new T[inputStrings.Length]; - for (int i = 0; i < inputStrings.Length; i++) + List inputEmbeddings = new List(); + for (int i = 0; i < inputStrings.Count; i += batchSize) { - inputEmbeddings[i] = Add(inputStrings[i]); + int takeCount = Math.Min(batchSize, inputStrings.Count - i); + List batch = new List(inputStrings.GetRange(i, takeCount)); + inputEmbeddings.AddRange((TensorFloat[])embedder.Split(embedder.Encode(batch))); } - return inputEmbeddings; + if (inputStrings.Count != inputEmbeddings.Count) + { + throw new Exception($"Number of computed embeddings ({inputEmbeddings.Count}) different than inputs ({inputStrings.Count})"); + } + return inputEmbeddings.ToArray(); } - public List GetKNN(string[] inputStrings, float[] scores, int k = -1) + + public string[] Search(string queryString, int k) { - var sortedLists = inputStrings.Zip(scores, (first, second) => new { First = first, Second = second }) + TensorFloat queryEmbedding = embedder.Encode(queryString); + TensorFloat storeEmbedding = embedder.Concat(embeddings.Values.ToArray()); + float[] scores = embedder.SimilarityScores(queryEmbedding, storeEmbedding); + + var sortedLists = embeddings.Keys.Zip(scores, (first, second) => new { First = first, Second = second }) .OrderByDescending(item => item.Second) .ToList(); List results = new List(); @@ -49,7 +55,7 @@ public List GetKNN(string[] inputStrings, float[] scores, int k = -1) { results.Add(sortedLists[i].First); } - return results; + return results.ToArray(); } public int Count() @@ -58,15 +64,22 @@ public int Count() } } - public class ModelSearch : Search + public class ModelSearch : ModelSearchBase { public ModelSearch(EmbeddingModel embedder) : base(embedder) {} - public override void Insert(string inputString, TensorFloat encoding) + protected void Insert(string inputString, TensorFloat encoding) { embeddings[inputString] = encoding; } + public TensorFloat Add(string inputString) + { + TensorFloat embedding = Encode(inputString); + Insert(inputString, embedding); + return embedding; + } + public TensorFloat[] Add(string[] inputStrings, int batchSize = 64) { return Add(new List(inputStrings), batchSize); @@ -74,41 +87,69 @@ public TensorFloat[] Add(string[] inputStrings, int batchSize = 64) public TensorFloat[] Add(List inputStrings, int batchSize = 64) { - List inputEmbeddings = new List(); - for (int i = 0; i < inputStrings.Count; i += batchSize) + TensorFloat[] inputEmbeddings = Encode(inputStrings, batchSize); + for (int i = 0; i < inputStrings.Count; i++) { - int takeCount = Math.Min(batchSize, inputStrings.Count - i); - List batch = new List(inputStrings.GetRange(i, takeCount)); - inputEmbeddings.AddRange((TensorFloat[])embedder.Split(embedder.Encode(batch))); - Console.WriteLine(takeCount); + Insert(inputStrings[i], inputEmbeddings[i]); } + return inputEmbeddings.ToArray(); + } + } - if (inputStrings.Count != inputEmbeddings.Count) - { - throw new Exception($"Number of computed embeddings ({inputEmbeddings.Count}) different than inputs ({inputStrings.Count})"); - } + public class ModelKeySearch : ModelSearchBase + { + protected Dictionary valueToKey; + + public ModelKeySearch(EmbeddingModel embedder) : base(embedder) + { + valueToKey = new Dictionary(); + } + + public virtual void Insert(int key, string value, TensorFloat encoding) + { + Console.WriteLine("damn"); + embeddings[value] = encoding; + valueToKey[value] = key; + } + + public TensorFloat Add(int key, string inputString) + { + TensorFloat embedding = Encode(inputString); + Insert(key, inputString, embedding); + return embedding; + } + + public TensorFloat[] Add(int[] keys, string[] inputStrings, int batchSize = 64) + { + return Add(new List(keys), new List(inputStrings), batchSize); + } + + public TensorFloat[] Add(List keys, List inputStrings, int batchSize = 64) + { + TensorFloat[] inputEmbeddings = Encode(inputStrings, batchSize); for (int i = 0; i < inputStrings.Count; i++) { - Insert(inputStrings[i], inputEmbeddings[i]); + Insert(keys[i], inputStrings[i], inputEmbeddings[i]); } return inputEmbeddings.ToArray(); } - public override List RetrieveSimilar(string queryString, int k) + public int[] SearchKey(string queryString, int k) { - TensorFloat queryEmbedding = embedder.Encode(queryString); - TensorFloat storeEmbedding = embedder.Concat(embeddings.Values.ToArray()); - float[] scores = embedder.SimilarityScores(queryEmbedding, storeEmbedding); - return GetKNN(embeddings.Keys.ToArray(), scores, k); + string[] results = Search(queryString, k); + int[] keys = new int[results.Length]; + for (int i = 0; i < results.Length; i++) + { + keys[i] = valueToKey[results[i]]; + } + return keys; } } - public class ANNModelSearch : ModelSearch + public class ANNModelSearch : ModelKeySearch { USearchIndex index; - Dictionary USearchToText; - ulong nextKey; - object insertLock = new object(); + protected Dictionary keyToValue; public ANNModelSearch( EmbeddingModel embedder, @@ -125,33 +166,38 @@ USearchIndex index ) : base(embedder) { this.index = index; - USearchToText = new Dictionary(); - nextKey = 0; + keyToValue = new Dictionary(); } - public override void Insert(string inputString, TensorFloat encoding) + public override void Insert(int key, string value, TensorFloat encoding) { - if (USearchToText.ContainsValue(inputString)) return; + Console.WriteLine("noice"); encoding.MakeReadable(); - lock (insertLock) + index.Add((ulong)key, encoding.ToReadOnlyArray()); + keyToValue[key] = value; + } + + public new string[] Search(string queryString, int k) + { + int[] results = SearchKey(queryString, k); + string[] values = new string[results.Length]; + for (int i = 0; i < results.Length; i++) { - ulong key = nextKey++; - USearchToText[key] = inputString; - index.Add(key, encoding.ToReadOnlyArray()); + values[i] = keyToValue[results[i]]; } + return values; } - public override List RetrieveSimilar(string queryString, int k) + public new int[] SearchKey(string queryString, int k) { TensorFloat encoding = embedder.Encode(queryString); encoding.MakeReadable(); index.Search(encoding.ToReadOnlyArray(), k, out ulong[] keys, out float[] distances); - List result = new List(); + + int[] intKeys = new int[keys.Length]; for (int i = 0; i < keys.Length; i++) - { - result.Add(USearchToText[keys[i]]); - } - return result; + intKeys[i] = (int)keys[i]; + return intKeys; } public new int Count() From f06e6fcc40b202d90ec2ba701ca69577bc08d6bd Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Tue, 6 Feb 2024 14:15:27 +0200 Subject: [PATCH 058/161] adapt sample to key-value implementation --- Samples~/HamletSearch/HamletSearch.cs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Samples~/HamletSearch/HamletSearch.cs b/Samples~/HamletSearch/HamletSearch.cs index 8ad0236f..f2f0f1c7 100644 --- a/Samples~/HamletSearch/HamletSearch.cs +++ b/Samples~/HamletSearch/HamletSearch.cs @@ -20,6 +20,10 @@ public void OnEnable() "Assets/StreamingAssets/bge-small-en-v1.5.sentis", "Assets/StreamingAssets/bge-small-en-v1.5.tokenizer.json" ); + // embedder = new BGEModel( + // "Assets/StreamingAssets/bge-base-en-v1.5.sentis", + // "Assets/StreamingAssets/bge-base-en-v1.5.tokenizer.json" + // ); } void Start() @@ -39,10 +43,14 @@ void Start() messages.Clear(); List sentences = dialogueManager.GetSentences(null, act); - numSentences += sentences.Count; + List keys = new List(); + for (int i = 0; i < sentences.Count; i++) + { + keys.Add(numSentences++); + } stopwatch.Reset(); stopwatch.Start(); - search.Add(sentences); + search.Add(keys, sentences); stopwatch.Stop(); elapsedTotal += (float)stopwatch.Elapsed.TotalMilliseconds / 1000f; @@ -52,12 +60,12 @@ void Start() Debug.Log(search.Count()); stopwatch.Reset(); stopwatch.Start(); - List similar = search.RetrieveSimilar("should i exist?", 10); + string[] similar = search.Search("should i be?", 10); stopwatch.Stop(); Debug.Log($"search time: {stopwatch.Elapsed.TotalMilliseconds / 1000f} secs"); Debug.Log("Similar sentences:"); - for (int i = 0; i < similar.Count; i++) + for (int i = 0; i < similar.Length; i++) { Debug.Log($" {i + 1}: {similar[i]}"); } From 836300b4313f1b73beca673093afa45c6ee2cd5b Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Tue, 6 Feb 2024 15:49:36 +0200 Subject: [PATCH 059/161] virtual and override methods --- Runtime/Search.cs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/Runtime/Search.cs b/Runtime/Search.cs index 1367c6f3..35795af2 100644 --- a/Runtime/Search.cs +++ b/Runtime/Search.cs @@ -39,8 +39,7 @@ public TensorFloat[] Encode(List inputStrings, int batchSize = 64) return inputEmbeddings.ToArray(); } - - public string[] Search(string queryString, int k) + public virtual string[] Search(string queryString, int k) { TensorFloat queryEmbedding = embedder.Encode(queryString); TensorFloat storeEmbedding = embedder.Concat(embeddings.Values.ToArray()); @@ -58,7 +57,7 @@ public string[] Search(string queryString, int k) return results.ToArray(); } - public int Count() + public virtual int Count() { return embeddings.Count; } @@ -107,24 +106,23 @@ public ModelKeySearch(EmbeddingModel embedder) : base(embedder) public virtual void Insert(int key, string value, TensorFloat encoding) { - Console.WriteLine("damn"); embeddings[value] = encoding; valueToKey[value] = key; } - public TensorFloat Add(int key, string inputString) + public virtual TensorFloat Add(int key, string inputString) { TensorFloat embedding = Encode(inputString); Insert(key, inputString, embedding); return embedding; } - public TensorFloat[] Add(int[] keys, string[] inputStrings, int batchSize = 64) + public virtual TensorFloat[] Add(int[] keys, string[] inputStrings, int batchSize = 64) { return Add(new List(keys), new List(inputStrings), batchSize); } - public TensorFloat[] Add(List keys, List inputStrings, int batchSize = 64) + public virtual TensorFloat[] Add(List keys, List inputStrings, int batchSize = 64) { TensorFloat[] inputEmbeddings = Encode(inputStrings, batchSize); for (int i = 0; i < inputStrings.Count; i++) @@ -134,7 +132,7 @@ public TensorFloat[] Add(List keys, List inputStrings, int batchSiz return inputEmbeddings.ToArray(); } - public int[] SearchKey(string queryString, int k) + public virtual int[] SearchKey(string queryString, int k) { string[] results = Search(queryString, k); int[] keys = new int[results.Length]; @@ -151,6 +149,8 @@ public class ANNModelSearch : ModelKeySearch USearchIndex index; protected Dictionary keyToValue; + public ANNModelSearch(EmbeddingModel embedder) : this(embedder, MetricKind.Cos, 32, 40, 16) {} + public ANNModelSearch( EmbeddingModel embedder, MetricKind metricKind = MetricKind.Cos, @@ -171,13 +171,12 @@ USearchIndex index public override void Insert(int key, string value, TensorFloat encoding) { - Console.WriteLine("noice"); encoding.MakeReadable(); index.Add((ulong)key, encoding.ToReadOnlyArray()); keyToValue[key] = value; } - public new string[] Search(string queryString, int k) + public override string[] Search(string queryString, int k) { int[] results = SearchKey(queryString, k); string[] values = new string[results.Length]; @@ -188,7 +187,7 @@ public override void Insert(int key, string value, TensorFloat encoding) return values; } - public new int[] SearchKey(string queryString, int k) + public override int[] SearchKey(string queryString, int k) { TensorFloat encoding = embedder.Encode(queryString); encoding.MakeReadable(); @@ -200,7 +199,7 @@ public override void Insert(int key, string value, TensorFloat encoding) return intKeys; } - public new int Count() + public override int Count() { return (int)index.Size(); } From fb1ef13987902cb5a288a02e6a37ab7af88f38fa Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Tue, 6 Feb 2024 15:50:23 +0200 Subject: [PATCH 060/161] dialogue filtering, search, and counts --- Runtime/Dialogue.cs | 211 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 166 insertions(+), 45 deletions(-) diff --git a/Runtime/Dialogue.cs b/Runtime/Dialogue.cs index 26ff74b1..0c5e7309 100644 --- a/Runtime/Dialogue.cs +++ b/Runtime/Dialogue.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using System; using System.Linq; +using System.Diagnostics; +using Debug = UnityEngine.Debug; namespace LLMUnity { @@ -18,6 +20,20 @@ public Sentence(int phraseId, int startIndex, int endIndex) } } + public class Phrase + { + public string text; + public List sentenceIds; + + public Phrase(string text) : this(text, new List()) {} + + public Phrase(string text, List sentenceIds) + { + this.text = text; + this.sentenceIds = sentenceIds; + } + } + public class SentenceSplitter { public static char[] DefaultDelimiters = new char[] { '.', '!', ':', ';', '?', '\n', '\r', }; @@ -69,24 +85,30 @@ public class Dialogue public string Title { get; private set; } public string Actor { get; private set; } - Dictionary phrases; - Dictionary> phraseSentences; - int nextPhraseId; + List phrases; + List sentences; SentenceSplitter sentenceSplitter; + ModelKeySearch search; + + public Dialogue(string actor = "", string title = "", EmbeddingModel embedder = null) : this(actor, title, embedder, typeof(ANNModelSearch)) {} - public Dialogue(string actor = "", string title = "") + public Dialogue(string actor = "", string title = "", EmbeddingModel embedder = null, Type modelSearchType = null) { Actor = actor; Title = title; - phrases = new Dictionary(); - phraseSentences = new Dictionary>(); - nextPhraseId = 0; + phrases = new List(); + sentences = new List(); sentenceSplitter = new SentenceSplitter(); + search = null; + if (embedder != null && modelSearchType != null) + { + search = (ModelKeySearch)Activator.CreateInstance(modelSearchType, embedder); + } } public void SetSentenceSplitting(char[] delimiters, bool trimSentences = true) { - if (nextPhraseId > 0) throw new Exception("Sentence splitting can't change when there are phrases in the Dialogue"); + if (sentences.Count > 0) throw new Exception("Sentence splitting can't change when there are phrases in the Dialogue"); if (delimiters == null) { sentenceSplitter = null; @@ -102,43 +124,86 @@ public void SetNoSentenceSplitting() SetSentenceSplitting(null); } + public string GetPhrase(Sentence sentence) + { + return phrases[sentence.phraseId].text; + } + + public string GetSentence(Sentence sentence) + { + return GetPhrase(sentence).Substring(sentence.startIndex, sentence.endIndex - sentence.startIndex + 1); + } + public void Add(string text) { - int phraseId = nextPhraseId++; - phrases[phraseId] = text; - if (sentenceSplitter == null) - { - phraseSentences[phraseId] = new List { new Sentence(phraseId, 0, text.Length - 1) }; - } - else + + List<(int, int)> subindices; + if (sentenceSplitter == null) subindices = new List<(int, int)> { (0, text.Length - 1) }; + else subindices = sentenceSplitter.Split(text); + + int phraseId = phrases.Count; + Phrase phrase = new Phrase(text); + phrases.Add(phrase); + foreach ((int startIndex, int endIndex) in subindices) { - phraseSentences[phraseId] = new List(); - List<(int, int)> subindices = sentenceSplitter.Split(text); - foreach ((int startIndex, int endIndex) in subindices) - { - phraseSentences[phraseId].Add(new Sentence(phraseId, startIndex, endIndex)); - } + int sentenceId = sentences.Count; + Sentence sentence = new Sentence(phraseId, startIndex, endIndex); + + sentences.Add(sentence); + phrase.sentenceIds.Add(sentenceId); + search?.Add(sentenceId, GetSentence(sentence)); } } public List GetPhrases() { - return phrases.Values.ToList(); + List phraseTexts = new List(); + foreach (Phrase phrase in phrases) phraseTexts.Add(phrase.text); + return phraseTexts; } public List GetSentences() { List allSentences = new List(); - foreach ((int phraseId, List sentences) in phraseSentences) + foreach (Sentence sentence in sentences) { - string phrase = phrases[phraseId]; - foreach (Sentence sentence in sentences) - { - allSentences.Add(phrase.Substring(sentence.startIndex, sentence.endIndex - sentence.startIndex + 1)); - } + allSentences.Add(GetSentence(sentence)); } return allSentences; } + + public string[] Search(string queryString, int k, bool returnSentences = false) + { + if (search == null) throw new Exception("No search method defined!"); + int[] keys = search.SearchKey(queryString, k); + string[] result = new string[keys.Length]; + for (int i = 0; i < keys.Length; i++) + { + Sentence sentence = sentences[keys[i]]; + result[i] = returnSentences ? GetSentence(sentence) : GetPhrase(sentence); + } + return result; + } + + public string[] SearchPhrases(string queryString, int k) + { + return Search(queryString, k, false); + } + + public string[] SearchSentences(string queryString, int k) + { + return Search(queryString, k, true); + } + + public int NumPhrases() + { + return phrases.Count; + } + + public int NumSentences() + { + return sentences.Count; + } } public class DialogueManager @@ -146,10 +211,16 @@ public class DialogueManager Dictionary> dialogues; char[] delimiters = SentenceSplitter.DefaultDelimiters; bool trimSentences = true; + EmbeddingModel embedder; + Type modelSearchType; - public DialogueManager() + public DialogueManager(EmbeddingModel embedder = null) : this(embedder, typeof(ANNModelSearch)) {} + + public DialogueManager(EmbeddingModel embedder = null, Type modelSearchType = null) { dialogues = new Dictionary>(); + this.embedder = embedder; + this.modelSearchType = modelSearchType; } public void SetSentenceSplitting(char[] delimiters, bool trimSentences = true) @@ -167,7 +238,7 @@ public void Add(string actor, string title, string text) { if (!dialogues.ContainsKey(actor) || !dialogues[actor].ContainsKey(title)) { - Dialogue dialogue = new Dialogue(actor, title); + Dialogue dialogue = new Dialogue(actor, title, embedder, modelSearchType); dialogue.SetSentenceSplitting(delimiters, trimSentences); if (!dialogues.ContainsKey(actor)) { @@ -180,39 +251,89 @@ public void Add(string actor, string title, string text) public void Add(string actor, string text) { - Add(actor, "", text); + Add(actor, null, text); } - public List Get(string actor = null, string title = null) + public List Filter(string actor = null, string title = null) { - List phrases = new List(); + List filtering = new List(); foreach ((string actorName, Dictionary actorDialogues) in dialogues) { foreach ((string titleName, Dialogue dialogue) in actorDialogues) { if ((actor == null || actor == actorName) && (title == null || title == titleName)) { - phrases.AddRange(dialogue.GetPhrases()); + filtering.Add(dialogue); } } } - return phrases; + return filtering; + } + + public List Get(string actor = null, string title = null, bool returnSentences = false) + { + List dialogues = Filter(actor, title); + List result = new List(); + foreach (Dialogue dialogue in dialogues) + { + result.AddRange(returnSentences ? dialogue.GetSentences() : dialogue.GetPhrases()); + } + return result; + } + + public List GetPhrases(string actor = null, string title = null) + { + return Get(actor, title, false); } public List GetSentences(string actor = null, string title = null) { - List sentences = new List(); - foreach ((string actorName, Dictionary actorDialogues) in dialogues) + return Get(actor, title, true); + } + + public string[] Search(string queryString, int k, string actor = null, string title = null, bool returnSentences = false) + { + if (embedder == null) throw new Exception("No search method defined!"); + + List dialogues = Filter(actor, title); + List result = new List(); + foreach (Dialogue dialogue in dialogues) { - foreach ((string titleName, Dialogue dialogue) in actorDialogues) - { - if ((actor == null || actor == actorName) && (title == null || title == titleName)) - { - sentences.AddRange(dialogue.GetSentences()); - } - } + result.AddRange(dialogue.Search(queryString, k, returnSentences)); + } + return result.ToArray(); + } + + public string[] SearchPhrases(string queryString, int k, string actor = null, string title = null) + { + return Search(queryString, k, actor, title, false); + } + + public string[] SearchSentences(string queryString, int k, string actor = null, string title = null) + { + return Search(queryString, k, actor, title, true); + } + + public int NumPhrases(string actor = null, string title = null) + { + int num = 0; + List dialogues = Filter(actor, title); + foreach (Dialogue dialogue in dialogues) + { + num += dialogue.NumPhrases(); + } + return num; + } + + public int NumSentences(string actor = null, string title = null) + { + int num = 0; + List dialogues = Filter(actor, title); + foreach (Dialogue dialogue in dialogues) + { + num += dialogue.NumSentences(); } - return sentences; + return num; } } } From d4d2b2eb7e0e147be69e326e71231ca1fdf377dd Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Tue, 6 Feb 2024 15:51:01 +0200 Subject: [PATCH 061/161] adapt sample --- Samples~/HamletSearch/HamletSearch.cs | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/Samples~/HamletSearch/HamletSearch.cs b/Samples~/HamletSearch/HamletSearch.cs index f2f0f1c7..a12f52f8 100644 --- a/Samples~/HamletSearch/HamletSearch.cs +++ b/Samples~/HamletSearch/HamletSearch.cs @@ -4,13 +4,10 @@ using Debug = UnityEngine.Debug; using System.Text.RegularExpressions; using LLMUnity; -using System.Linq; -using Unity.VisualScripting; class HamletSearch : MonoBehaviour { EmbeddingModel embedder; - ANNModelSearch search; public bool fullPlay; public TextAsset gutenbergText; @@ -29,38 +26,24 @@ public void OnEnable() void Start() { Dictionary> hamlet = ReadGutenbergFile(gutenbergText.text); - DialogueManager dialogueManager = new DialogueManager(); - search = new ANNModelSearch(embedder); + DialogueManager dialogueManager = new DialogueManager(embedder); Stopwatch stopwatch = new Stopwatch(); - int numSentences = 0; float elapsedTotal = 0; foreach ((string act, List<(string, string)> messages) in hamlet) { if (!fullPlay && act != "ACT III") continue; + stopwatch.Reset(); stopwatch.Start(); foreach ((string actor, string message) in messages) dialogueManager.Add(actor, act, message); - messages.Clear(); - - List sentences = dialogueManager.GetSentences(null, act); - List keys = new List(); - for (int i = 0; i < sentences.Count; i++) - { - keys.Add(numSentences++); - } - - stopwatch.Reset(); stopwatch.Start(); - search.Add(keys, sentences); - stopwatch.Stop(); elapsedTotal += (float)stopwatch.Elapsed.TotalMilliseconds / 1000f; - Debug.Log($"act {act} embedded {sentences.Count} sentences in {stopwatch.Elapsed.TotalMilliseconds / 1000f} secs"); + Debug.Log($"act {act} embedded {dialogueManager.GetSentences(null, act).Count} sentences in {stopwatch.Elapsed.TotalMilliseconds / 1000f} secs"); } - Debug.Log($"embedded {numSentences} sentences in {elapsedTotal} secs"); - Debug.Log(search.Count()); + Debug.Log($"embedded {dialogueManager.NumPhrases()} phrases, {dialogueManager.NumSentences()} sentences in {elapsedTotal} secs"); stopwatch.Reset(); stopwatch.Start(); - string[] similar = search.Search("should i be?", 10); + string[] similar = dialogueManager.Search("should i be?", 10); stopwatch.Stop(); Debug.Log($"search time: {stopwatch.Elapsed.TotalMilliseconds / 1000f} secs"); From c95a45bd753cf531885aee4d95cef1f356de436e Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Wed, 7 Feb 2024 11:37:20 +0200 Subject: [PATCH 062/161] add similarity distances function --- Runtime/Embedder.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Runtime/Embedder.cs b/Runtime/Embedder.cs index dea53470..3900ea4c 100644 --- a/Runtime/Embedder.cs +++ b/Runtime/Embedder.cs @@ -140,6 +140,14 @@ public float[][] SimilarityScoresMultiple(TensorFloat InputSequence, TensorFloat return scores; } + public float[] SimilarityDistances(TensorFloat InputSequence, TensorFloat ComparisonSequences) + { + float[] scores = SimilarityScores(InputSequence, ComparisonSequences); + float[] distances = new float[scores.Length]; + for (int i = 0; i < scores.Length; i++) distances[i] = 1 - scores[i]; + return distances; + } + Tuple>, List>, List>> Tokenize(List candidates) { List> sentences = new List>(); From fcff02a0b1c3d55f267677efa564b7abda1ece60 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Wed, 7 Feb 2024 11:38:22 +0200 Subject: [PATCH 063/161] add functions for encoded input and output distances --- Runtime/Search.cs | 84 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 72 insertions(+), 12 deletions(-) diff --git a/Runtime/Search.cs b/Runtime/Search.cs index 35795af2..b8bc78d4 100644 --- a/Runtime/Search.cs +++ b/Runtime/Search.cs @@ -39,22 +39,38 @@ public TensorFloat[] Encode(List inputStrings, int batchSize = 64) return inputEmbeddings.ToArray(); } + public virtual string[] Search(TensorFloat encoding, int k) + { + return Search(encoding, k, out float[] distances); + } + public virtual string[] Search(string queryString, int k) { - TensorFloat queryEmbedding = embedder.Encode(queryString); + return Search(queryString, k, out float[] distances); + } + + public virtual string[] Search(TensorFloat encoding, int k, out float[] distances) + { TensorFloat storeEmbedding = embedder.Concat(embeddings.Values.ToArray()); - float[] scores = embedder.SimilarityScores(queryEmbedding, storeEmbedding); + float[] unsortedDistances = embedder.SimilarityDistances(encoding, storeEmbedding); - var sortedLists = embeddings.Keys.Zip(scores, (first, second) => new { First = first, Second = second }) - .OrderByDescending(item => item.Second) + var sortedLists = embeddings.Keys.Zip(unsortedDistances, (first, second) => new { First = first, Second = second }) + .OrderBy(item => item.Second) .ToList(); - List results = new List(); int kmax = k == -1 ? sortedLists.Count : Math.Min(k, sortedLists.Count); + string[] results = new string[kmax]; + distances = new float[kmax]; for (int i = 0; i < kmax; i++) { - results.Add(sortedLists[i].First); + results[i] = sortedLists[i].First; + distances[i] = sortedLists[i].Second; } - return results.ToArray(); + return results; + } + + public virtual string[] Search(string queryString, int k, out float[] distances) + { + return Search(embedder.Encode(queryString), k, out distances); } public virtual int Count() @@ -132,9 +148,9 @@ public virtual TensorFloat[] Add(List keys, List inputStrings, int return inputEmbeddings.ToArray(); } - public virtual int[] SearchKey(string queryString, int k) + public virtual int[] SearchKey(TensorFloat embedding, int k, out float[] distances) { - string[] results = Search(queryString, k); + string[] results = Search(embedding, k, out distances); int[] keys = new int[results.Length]; for (int i = 0; i < results.Length; i++) { @@ -142,6 +158,21 @@ public virtual int[] SearchKey(string queryString, int k) } return keys; } + + public virtual int[] SearchKey(string queryString, int k, out float[] distances) + { + return SearchKey(Encode(queryString), k, out distances); + } + + public virtual int[] SearchKey(TensorFloat encoding, int k) + { + return SearchKey(encoding, k, out float[] distances); + } + + public virtual int[] SearchKey(string queryString, int k) + { + return SearchKey(queryString, k, out float[] distances); + } } public class ANNModelSearch : ModelKeySearch @@ -176,9 +207,19 @@ public override void Insert(int key, string value, TensorFloat encoding) keyToValue[key] = value; } + public override string[] Search(TensorFloat encoding, int k) + { + return Search(encoding, k, out float[] distances); + } + public override string[] Search(string queryString, int k) { - int[] results = SearchKey(queryString, k); + return Search(queryString, k, out float[] distances); + } + + public override string[] Search(TensorFloat encoding, int k, out float[] distances) + { + int[] results = SearchKey(encoding, k, out distances); string[] values = new string[results.Length]; for (int i = 0; i < results.Length; i++) { @@ -187,11 +228,25 @@ public override string[] Search(string queryString, int k) return values; } + public override string[] Search(string queryString, int k, out float[] distances) + { + return Search(embedder.Encode(queryString), k, out distances); + } + + public override int[] SearchKey(TensorFloat encoding, int k) + { + return SearchKey(encoding, k, out float[] distances); + } + public override int[] SearchKey(string queryString, int k) { - TensorFloat encoding = embedder.Encode(queryString); + return SearchKey(queryString, k, out float[] distances); + } + + public override int[] SearchKey(TensorFloat encoding, int k, out float[] distances) + { encoding.MakeReadable(); - index.Search(encoding.ToReadOnlyArray(), k, out ulong[] keys, out float[] distances); + index.Search(encoding.ToReadOnlyArray(), k, out ulong[] keys, out distances); int[] intKeys = new int[keys.Length]; for (int i = 0; i < keys.Length; i++) @@ -199,6 +254,11 @@ public override int[] SearchKey(string queryString, int k) return intKeys; } + public override int[] SearchKey(string queryString, int k, out float[] distances) + { + return SearchKey(embedder.Encode(queryString), k, out distances); + } + public override int Count() { return (int)index.Size(); From 814dcf87bf0985ce2e2fcbaa43f454f2bce979b5 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Wed, 7 Feb 2024 11:39:07 +0200 Subject: [PATCH 064/161] expose distances, search in parallel across threads --- Runtime/Dialogue.cs | 84 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 14 deletions(-) diff --git a/Runtime/Dialogue.cs b/Runtime/Dialogue.cs index 0c5e7309..4211aba8 100644 --- a/Runtime/Dialogue.cs +++ b/Runtime/Dialogue.cs @@ -1,8 +1,9 @@ using System.Collections.Generic; using System; using System.Linq; -using System.Diagnostics; -using Debug = UnityEngine.Debug; +using System.Collections.Concurrent; +using System.Threading.Tasks; +using Unity.Sentis; namespace LLMUnity { @@ -172,10 +173,15 @@ public List GetSentences() return allSentences; } - public string[] Search(string queryString, int k, bool returnSentences = false) + public string[] Search(string queryString, int k, out float[] distances, bool returnSentences = false) + { + return Search(search.Encode(queryString), k, out distances, returnSentences); + } + + public string[] Search(TensorFloat encoding, int k, out float[] distances, bool returnSentences = false) { if (search == null) throw new Exception("No search method defined!"); - int[] keys = search.SearchKey(queryString, k); + int[] keys = search.SearchKey(encoding, k, out distances); string[] result = new string[keys.Length]; for (int i = 0; i < keys.Length; i++) { @@ -185,14 +191,34 @@ public string[] Search(string queryString, int k, bool returnSentences = false) return result; } + public string[] Search(TensorFloat encoding, int k, bool returnSentences = false) + { + return Search(encoding, k, out float[] distances, returnSentences); + } + + public string[] Search(string queryString, int k, bool returnSentences = false) + { + return Search(queryString, k, out float[] distances, returnSentences); + } + + public string[] SearchPhrases(string queryString, int k, out float[] distances) + { + return Search(queryString, k, out distances, false); + } + public string[] SearchPhrases(string queryString, int k) { - return Search(queryString, k, false); + return SearchPhrases(queryString, k, out float[] distances); + } + + public string[] SearchSentences(string queryString, int k, out float[] distances) + { + return Search(queryString, k, out distances, true); } public string[] SearchSentences(string queryString, int k) { - return Search(queryString, k, true); + return SearchSentences(queryString, k, out float[] distances); } public int NumPhrases() @@ -291,27 +317,57 @@ public List GetSentences(string actor = null, string title = null) return Get(actor, title, true); } - public string[] Search(string queryString, int k, string actor = null, string title = null, bool returnSentences = false) + public string[] Search(string queryString, int k, out float[] distances, string actor = null, string title = null, bool returnSentences = false) { if (embedder == null) throw new Exception("No search method defined!"); - List dialogues = Filter(actor, title); - List result = new List(); - foreach (Dialogue dialogue in dialogues) + ConcurrentBag<(string, float)> resultPairs = new ConcurrentBag<(string, float)>(); + + var encoding = embedder.Encode(queryString); + Parallel.ForEach(dialogues, dialogue => { - result.AddRange(dialogue.Search(queryString, k, returnSentences)); + string[] searchResults = dialogue.Search(encoding, k, out float[] searchDistances, returnSentences); + for (int i = 0; i < searchResults.Length; i++) + { + resultPairs.Add((searchResults[i], searchDistances[i])); + } + }); + + var sortedLists = resultPairs.OrderBy(item => item.Item2).ToList(); + int kmax = k == -1 ? sortedLists.Count : Math.Min(k, sortedLists.Count); + string[] results = new string[kmax]; + distances = new float[kmax]; + for (int i = 0; i < kmax; i++) + { + results[i] = sortedLists[i].Item1; + distances[i] = sortedLists[i].Item2; } - return result.ToArray(); + return results; + } + + public string[] Search(string queryString, int k, string actor = null, string title = null, bool returnSentences = false) + { + return Search(queryString, k, out float[] distances, actor, title, returnSentences); + } + + public string[] SearchPhrases(string queryString, int k, out float[] distances, string actor = null, string title = null) + { + return Search(queryString, k, out distances, actor, title, false); } public string[] SearchPhrases(string queryString, int k, string actor = null, string title = null) { - return Search(queryString, k, actor, title, false); + return SearchPhrases(queryString, k, out float[] distances, actor, title); + } + + public string[] SearchSentences(string queryString, int k, out float[] distances, string actor = null, string title = null) + { + return Search(queryString, k, out distances, actor, title, true); } public string[] SearchSentences(string queryString, int k, string actor = null, string title = null) { - return Search(queryString, k, actor, title, true); + return SearchSentences(queryString, k, out float[] distances, actor, title); } public int NumPhrases(string actor = null, string title = null) From eabb2baecfd712b37fb2fd16aadd7000d13abf8b Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Wed, 7 Feb 2024 11:42:05 +0200 Subject: [PATCH 065/161] remove commented out part --- Samples~/HamletSearch/HamletSearch.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Samples~/HamletSearch/HamletSearch.cs b/Samples~/HamletSearch/HamletSearch.cs index a12f52f8..6819073e 100644 --- a/Samples~/HamletSearch/HamletSearch.cs +++ b/Samples~/HamletSearch/HamletSearch.cs @@ -17,10 +17,6 @@ public void OnEnable() "Assets/StreamingAssets/bge-small-en-v1.5.sentis", "Assets/StreamingAssets/bge-small-en-v1.5.tokenizer.json" ); - // embedder = new BGEModel( - // "Assets/StreamingAssets/bge-base-en-v1.5.sentis", - // "Assets/StreamingAssets/bge-base-en-v1.5.tokenizer.json" - // ); } void Start() From df3de7d4bba60a0bc31c9a6181b75c8da7acc62f Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Wed, 7 Feb 2024 20:44:39 +0200 Subject: [PATCH 066/161] model manager functionality --- Runtime/Embedder.cs | 131 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 108 insertions(+), 23 deletions(-) diff --git a/Runtime/Embedder.cs b/Runtime/Embedder.cs index 3900ea4c..8b63821e 100644 --- a/Runtime/Embedder.cs +++ b/Runtime/Embedder.cs @@ -13,15 +13,84 @@ using HuggingFace.SharpTransformers.Tokenizers; using HuggingFace.SharpTransformers.PostProcessors; using System.IO; +using System.Runtime.Serialization; +using System.IO.Compression; namespace LLMUnity { - public abstract class Embedder + [DataContract] + public class EmbeddingModelSkeleton { - public abstract T Encode(string input); + [DataMember] + public string ModelPath { get; protected set; } + [DataMember] + public string TokenizerPath { get; protected set; } + [DataMember] + public BackendType Backend { get; protected set; } + [DataMember] + public string OutputLayerName { get; protected set; } + [DataMember] + public bool UseMeanPooling { get; protected set; } + [DataMember] + public int Dimensions { get; protected set; } + + public EmbeddingModelSkeleton(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU, string outputLayerName = "last_hidden_state", bool useMeanPooling = true, int dimensions = 384) + { + ModelPath = modelPath; + TokenizerPath = tokenizerPath; + Backend = backend; + OutputLayerName = outputLayerName; + UseMeanPooling = useMeanPooling; + Dimensions = dimensions; + } + + public static string GetEmbeddingModelPath(string dirname) + { + return Path.Combine(dirname, "EmbeddingModel.json"); + } + + public virtual void Save(ZipArchive archive, string dirname = "") + { + Saver.Save(this, archive, GetEmbeddingModelPath(dirname)); + } + + public static EmbeddingModelSkeleton Load(ZipArchive archive, string dirname = "") + { + return Saver.Load(archive, GetEmbeddingModelPath(dirname)); + } + + public override int GetHashCode() + { + unchecked + { + int hash = 17; + hash = hash * 23 + (ModelPath != null ? ModelPath.GetHashCode() : 0); + hash = hash * 23 + (TokenizerPath != null ? TokenizerPath.GetHashCode() : 0); + hash = hash * 23 + Backend.GetHashCode(); + hash = hash * 23 + (OutputLayerName != null ? OutputLayerName.GetHashCode() : 0); + hash = hash * 23 + UseMeanPooling.GetHashCode(); + hash = hash * 23 + Dimensions; + return hash; + } + } + + public override bool Equals(object obj) + { + if (obj == null || !(obj is EmbeddingModelSkeleton)) + return false; + + EmbeddingModelSkeleton other = (EmbeddingModelSkeleton)obj; + return ModelPath == other.ModelPath && + TokenizerPath == other.TokenizerPath && + Backend == other.Backend && + OutputLayerName == other.OutputLayerName && + UseMeanPooling == other.UseMeanPooling && + Dimensions == other.Dimensions; + } } - public class EmbeddingModel : Embedder + [DataContract] + public class EmbeddingModel : EmbeddingModelSkeleton { Model runtimeModel; IWorker worker; @@ -32,11 +101,9 @@ public class EmbeddingModel : Embedder BertPreTokenizer bertPreTok; WordPieceTokenizer wordPieceTokenizer; TemplateProcessing templateProcessing; - string outputLayerName; - bool useMeanPooling; - public int Dimensions { get; private set; } - public EmbeddingModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU, string outputLayerName = "last_hidden_state", bool useMeanPooling = true, int dimensions = 384) + public EmbeddingModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU, string outputLayerName = "last_hidden_state", bool useMeanPooling = true, int dimensions = 384) : + base(modelPath, tokenizerPath, backend, outputLayerName, useMeanPooling, dimensions) { runtimeModel = ModelLoader.Load(modelPath); string tokenizerJsonContent = File.ReadAllText(tokenizerPath); @@ -50,9 +117,6 @@ public EmbeddingModel(string modelPath, string tokenizerPath, BackendType backen bertPreTok = new BertPreTokenizer(JObject.FromObject(tokenizerJsonData["pre_tokenizer"])); wordPieceTokenizer = new WordPieceTokenizer(JObject.FromObject(tokenizerJsonData["model"])); templateProcessing = new TemplateProcessing(JObject.FromObject(tokenizerJsonData["post_processor"])); - this.outputLayerName = outputLayerName; - this.useMeanPooling = useMeanPooling; - Dimensions = dimensions; } public void Destroy() @@ -81,7 +145,7 @@ public Tensor[] Split(Tensor tensor, int axis = 0) return tensors; } - public override TensorFloat Encode(string input) + public TensorFloat Encode(string input) { return Encode(new List { input }); } @@ -98,10 +162,10 @@ public TensorFloat Encode(List input) // Step 2: Compute embedding and get the output worker.Execute(inputSentencesTokensTensor); // Step 3: Get the output from the neural network - TensorFloat outputTensor = worker.PeekOutput(outputLayerName) as TensorFloat; + TensorFloat outputTensor = worker.PeekOutput(OutputLayerName) as TensorFloat; // Step 4: Perform pooling TensorFloat MeanPooledTensor = outputTensor; - if (useMeanPooling) + if (UseMeanPooling) { MeanPooledTensor = MeanPooling(inputSentencesTokensTensor["attention_mask"], outputTensor, ops); } @@ -338,19 +402,40 @@ static List> AddTokenTypes(List> inputIds) { return inputIds.Select(innerList => innerList.Select(_ => 0).ToList()).ToList(); } - } - public class BGEModel : EmbeddingModel - { - public BGEModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU) : - base(modelPath, tokenizerPath, backend, "sentence_embedding", false, 384) - {} + public new static EmbeddingModel Load(ZipArchive archive, string name = "EmbeddingModel.json") + { + EmbeddingModelSkeleton skeleton = EmbeddingModelSkeleton.Load(archive, name); + return ModelManager.Model(skeleton); + } } - public class MiniLMModel : EmbeddingModel + public class ModelManager { - public MiniLMModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU) : - base(modelPath, tokenizerPath, backend, "last_hidden_state", true, 384) - {} + static Dictionary models = new Dictionary(); + + public static EmbeddingModel Model(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU, string outputLayerName = "last_hidden_state", bool useMeanPooling = true, int dimensions = 384) + { + return Model(new EmbeddingModelSkeleton(modelPath, tokenizerPath, backend, outputLayerName, useMeanPooling, dimensions)); + } + + public static EmbeddingModel Model(EmbeddingModelSkeleton skeleton) + { + if (!models.ContainsKey(skeleton)) + { + models[skeleton] = new EmbeddingModel(skeleton.ModelPath, skeleton.TokenizerPath, skeleton.Backend, skeleton.OutputLayerName, skeleton.UseMeanPooling, skeleton.Dimensions); + } + return models[skeleton]; + } + + public static EmbeddingModel BGEModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU) + { + return Model(new EmbeddingModelSkeleton(modelPath, tokenizerPath, backend, "sentence_embedding", false, 384)); + } + + public static EmbeddingModel MiniLMModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU) + { + return Model(new EmbeddingModelSkeleton(modelPath, tokenizerPath, backend, "last_hidden_state", true, 384)); + } } } From 2f1c0796f0574289e3f1137bd96a64d5e4ae5e6d Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Wed, 7 Feb 2024 20:46:14 +0200 Subject: [PATCH 067/161] save and load functionality --- Runtime/Dialogue.cs | 171 +++++++++++++++++++++++++++++++++++++--- Runtime/Search.cs | 126 ++++++++++++++++++++++++++++- usearch/USearchIndex.cs | 84 ++++++++++++-------- 3 files changed, 336 insertions(+), 45 deletions(-) diff --git a/Runtime/Dialogue.cs b/Runtime/Dialogue.cs index 4211aba8..94170167 100644 --- a/Runtime/Dialogue.cs +++ b/Runtime/Dialogue.cs @@ -4,13 +4,20 @@ using System.Collections.Concurrent; using System.Threading.Tasks; using Unity.Sentis; +using System.Runtime.Serialization; +using System.IO; +using System.IO.Compression; namespace LLMUnity { + [DataContract] public class Sentence { + [DataMember] public int phraseId; + [DataMember] public int startIndex; + [DataMember] public int endIndex; public Sentence(int phraseId, int startIndex, int endIndex) @@ -21,9 +28,12 @@ public Sentence(int phraseId, int startIndex, int endIndex) } } + [DataContract] public class Phrase { + [DataMember] public string text; + [DataMember] public List sentenceIds; public Phrase(string text) : this(text, new List()) {} @@ -35,10 +45,13 @@ public Phrase(string text, List sentenceIds) } } + [DataContract] public class SentenceSplitter { public static char[] DefaultDelimiters = new char[] { '.', '!', ':', ';', '?', '\n', '\r', }; + [DataMember] char[] delimiters; + [DataMember] bool trimSentences = true; public SentenceSplitter(char[] delimiters, bool trimSentences = true) @@ -47,7 +60,7 @@ public SentenceSplitter(char[] delimiters, bool trimSentences = true) this.trimSentences = trimSentences; } - public SentenceSplitter() : this(SentenceSplitter.DefaultDelimiters, true) {} + public SentenceSplitter() : this(DefaultDelimiters, true) {} public List<(int, int)> Split(string input) { @@ -81,13 +94,19 @@ public SentenceSplitter() : this(SentenceSplitter.DefaultDelimiters, true) {} } } + [DataContract] public class Dialogue { + [DataMember] public string Title { get; private set; } + [DataMember] public string Actor { get; private set; } + [DataMember] List phrases; + [DataMember] List sentences; + [DataMember] SentenceSplitter sentenceSplitter; ModelKeySearch search; @@ -125,6 +144,16 @@ public void SetNoSentenceSplitting() SetSentenceSplitting(null); } + public void SetSearch(ModelKeySearch search) + { + this.search = search; + } + + public void SetEmbedder(EmbeddingModel embedder) + { + search.SetEmbedder(embedder); + } + public string GetPhrase(Sentence sentence) { return phrases[sentence.phraseId].text; @@ -137,7 +166,6 @@ public string GetSentence(Sentence sentence) public void Add(string text) { - List<(int, int)> subindices; if (sentenceSplitter == null) subindices = new List<(int, int)> { (0, text.Length - 1) }; else subindices = sentenceSplitter.Split(text); @@ -230,15 +258,57 @@ public int NumSentences() { return sentences.Count; } + + public void Save(string filePath, string dirname="") + { + using (FileStream stream = new FileStream(filePath, FileMode.Create)) + using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Create)) + { + Save(archive, dirname); + } + } + + public static string GetDialoguePath(string dirname){ + return Path.Combine(dirname, "Dialogue.json"); + } + + public void Save(ZipArchive archive, string dirname) + { + Saver.Save(this, archive, GetDialoguePath(dirname)); + search.Save(archive, dirname); + } + + public static Dialogue Load(string filePath, string dirname) + { + using (FileStream stream = new FileStream(filePath, FileMode.Open)) + using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read)) + { + return Load(archive, dirname); + } + } + + public static Dialogue Load(ZipArchive archive, string dirname) + { + Dialogue dialogue = Saver.Load(archive, GetDialoguePath(dirname)); + ModelKeySearch search = (ModelKeySearch) ModelSearchBase.CastLoad(archive, dirname); + dialogue.SetSearch(search); + return dialogue; + } } + [DataContract] public class DialogueManager { Dictionary> dialogues; + [DataMember] char[] delimiters = SentenceSplitter.DefaultDelimiters; + [DataMember] bool trimSentences = true; + [DataMember] EmbeddingModel embedder; Type modelSearchType; + [DataMember] + string modelSearchTypeName; public DialogueManager(EmbeddingModel embedder = null) : this(embedder, typeof(ANNModelSearch)) {} @@ -247,6 +317,7 @@ public DialogueManager(EmbeddingModel embedder = null, Type modelSearchType = nu dialogues = new Dictionary>(); this.embedder = embedder; this.modelSearchType = modelSearchType; + this.modelSearchTypeName = modelSearchType.FullName; } public void SetSentenceSplitting(char[] delimiters, bool trimSentences = true) @@ -260,6 +331,15 @@ public void SetNoSentenceSplitting() SetSentenceSplitting(null); } + public void AddDialogue(string actor, string title, Dialogue dialogue) + { + if (!dialogues.ContainsKey(actor)) + { + dialogues[actor] = new Dictionary(); + } + dialogues[actor][title] = dialogue; + } + public void Add(string actor, string title, string text) { if (!dialogues.ContainsKey(actor) || !dialogues[actor].ContainsKey(title)) @@ -324,14 +404,16 @@ public string[] Search(string queryString, int k, out float[] distances, string ConcurrentBag<(string, float)> resultPairs = new ConcurrentBag<(string, float)>(); var encoding = embedder.Encode(queryString); - Parallel.ForEach(dialogues, dialogue => - { - string[] searchResults = dialogue.Search(encoding, k, out float[] searchDistances, returnSentences); - for (int i = 0; i < searchResults.Length; i++) + Task.Run(() => + {Parallel.ForEach(dialogues, dialogue => { - resultPairs.Add((searchResults[i], searchDistances[i])); - } - }); + string[] searchResults = dialogue.Search(encoding, k, out float[] searchDistances, returnSentences); + for (int i = 0; i < searchResults.Length; i++) + { + resultPairs.Add((searchResults[i], searchDistances[i])); + } + }); + }).Wait(); var sortedLists = resultPairs.OrderBy(item => item.Item2).ToList(); int kmax = k == -1 ? sortedLists.Count : Math.Min(k, sortedLists.Count); @@ -391,5 +473,76 @@ public int NumSentences(string actor = null, string title = null) } return num; } + + public static string GetDialogueManagerPath(string dirname){ + return Path.Combine(dirname, "DialogueManager.json"); + } + public static string GetDialoguesPath(string dirname){ + return Path.Combine(dirname, "Dialogues.json"); + } + + public void Save(string filePath, string dirname="") + { + using (FileStream stream = new FileStream(filePath, FileMode.Create)) + using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Create)) + { + Save(archive, dirname); + } + } + + public void Save(ZipArchive archive, string dirname="") + { + Saver.Save(this, archive, GetDialogueManagerPath(dirname)); + + embedder.Save(archive, dirname); + + List dialogueDirs = new List(); + foreach ((string actorName, Dictionary actorDialogues) in dialogues) + { + foreach ((string titleName, Dialogue dialogue) in actorDialogues) + { + string basedir = $"{dirname}/Dialogues/{Saver.EscapeFileName(actorName)}/{Saver.EscapeFileName(titleName)}"; + dialogue.Save(archive, basedir); + dialogueDirs.Add(basedir); + } + } + + ZipArchiveEntry dialoguesEntry = archive.CreateEntry(GetDialoguesPath(dirname)); + using (StreamWriter writer = new StreamWriter(dialoguesEntry.Open())) + { + writer.Write(string.Join("\n", dialogueDirs)); + } + } + + public static DialogueManager Load(string filePath, string dirname="") + { + using (FileStream stream = new FileStream(filePath, FileMode.Open)) + using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read)) + { + DialogueManager dialogueManager = Saver.Load(archive, GetDialogueManagerPath(dirname)); + dialogueManager.modelSearchType = Type.GetType(dialogueManager.modelSearchTypeName); + + dialogueManager.embedder = EmbeddingModel.Load(archive, dirname); + + ZipArchiveEntry dialoguesEntry = archive.GetEntry(GetDialoguesPath(dirname)); + List dialogueDirs = new List(); + dialogueManager.dialogues = new Dictionary>(); + using (StreamReader reader = new StreamReader(dialoguesEntry.Open())) + { + string line; + while ((line = reader.ReadLine()) != null) + { + dialogueDirs.Add(line); + } + } + + foreach (string basedir in dialogueDirs) + { + Dialogue dialogue = Dialogue.Load(archive, basedir); + dialogueManager.AddDialogue(dialogue.Actor, dialogue.Title, dialogue); + } + return dialogueManager; + } + } } } diff --git a/Runtime/Search.cs b/Runtime/Search.cs index b8bc78d4..ab62775e 100644 --- a/Runtime/Search.cs +++ b/Runtime/Search.cs @@ -3,13 +3,19 @@ using System.Linq; using Unity.Sentis; using Cloud.Unum.USearch; +using System.Runtime.Serialization; +using System.IO; +using System.IO.Compression; +using System.Reflection; namespace LLMUnity { - public abstract class ModelSearchBase + [DataContract] + public class ModelSearchBase { protected EmbeddingModel embedder; + [DataMember] protected Dictionary embeddings; public ModelSearchBase(EmbeddingModel embedder) @@ -18,6 +24,11 @@ public ModelSearchBase(EmbeddingModel embedder) this.embedder = embedder; } + public void SetEmbedder(EmbeddingModel embedder) + { + this.embedder = embedder; + } + public TensorFloat Encode(string inputString) { return embedder.Encode(inputString); @@ -77,8 +88,66 @@ public virtual int Count() { return embeddings.Count; } + + public virtual void Save(string filePath, string dirname) + { + using (FileStream stream = new FileStream(filePath, FileMode.Create)) + using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Create)) + { + Save(archive, dirname); + } + } + + public static string GetSearchTypePath(string dirname){ + return Path.Combine(dirname, "SearchType.txt"); + } + + public static string GetSearchPath(string dirname){ + return Path.Combine(dirname, "Search.json"); + } + + public virtual void Save(ZipArchive archive, string dirname) + { + ZipArchiveEntry typeEntry = archive.CreateEntry(GetSearchTypePath(dirname)); + using (StreamWriter writer = new StreamWriter(typeEntry.Open())) + { + writer.Write(GetType().FullName); + } + Saver.Save(this, archive, GetSearchPath(dirname)); + embedder.Save(archive, dirname); + } + + public static ModelSearchBase CastLoad(ZipArchive archive, string dirname) + { + ZipArchiveEntry typeEntry = archive.GetEntry(GetSearchTypePath(dirname)); + Type modelSearchType; + using (StreamReader reader = new StreamReader(typeEntry.Open())) + { + modelSearchType = Type.GetType(reader.ReadLine()); + } + MethodInfo methodInfo = modelSearchType.GetMethod("Load", new Type[] { typeof(ZipArchive), typeof(string) }); + return (ModelSearchBase) Convert.ChangeType(methodInfo.Invoke(null, new object[]{archive, dirname}), modelSearchType); + } + + public static T Load(string filePath, string dirname) where T: ModelSearchBase + { + using (FileStream stream = new FileStream(filePath, FileMode.Open)) + using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read)) + { + return Load(archive, dirname); + } + } + + public static T Load(ZipArchive archive, string dirname) where T: ModelSearchBase + { + T search = Saver.Load(archive, GetSearchPath(dirname)); + EmbeddingModel embedder = EmbeddingModel.Load(archive, dirname); + search.SetEmbedder(embedder); + return search; + } } + [DataContract] public class ModelSearch : ModelSearchBase { public ModelSearch(EmbeddingModel embedder) : base(embedder) {} @@ -109,10 +178,22 @@ public TensorFloat[] Add(List inputStrings, int batchSize = 64) } return inputEmbeddings.ToArray(); } + + public static ModelSearch Load(string filePath, string dirname) + { + return Load(filePath, dirname); + } + + public static ModelSearch Load(ZipArchive archive, string dirname) + { + return Load(archive, dirname); + } } + [DataContract] public class ModelKeySearch : ModelSearchBase { + [DataMember] protected Dictionary valueToKey; public ModelKeySearch(EmbeddingModel embedder) : base(embedder) @@ -173,11 +254,23 @@ public virtual int[] SearchKey(string queryString, int k) { return SearchKey(queryString, k, out float[] distances); } + + public static ModelKeySearch Load(string filePath, string dirname) + { + return Load(filePath, dirname); + } + + public static ModelKeySearch Load(ZipArchive archive, string dirname) + { + return Load(archive, dirname); + } } + [DataContract] public class ANNModelSearch : ModelKeySearch { USearchIndex index; + [DataMember] protected Dictionary keyToValue; public ANNModelSearch(EmbeddingModel embedder) : this(embedder, MetricKind.Cos, 32, 40, 16) {} @@ -200,6 +293,10 @@ USearchIndex index keyToValue = new Dictionary(); } + public void SetIndex(USearchIndex index){ + this.index = index; + } + public override void Insert(int key, string value, TensorFloat encoding) { encoding.MakeReadable(); @@ -263,5 +360,32 @@ public override int Count() { return (int)index.Size(); } + + public static string GetIndexPath(string dirname){ + return Path.Combine(dirname, "USearch"); + } + + public override void Save(ZipArchive archive, string dirname) + { + base.Save(archive, dirname); + index.Save(archive, GetIndexPath(dirname)); + } + + public new static ANNModelSearch Load(string filePath, string dirname) + { + using (FileStream stream = new FileStream(filePath, FileMode.Open)) + using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read)) + { + return Load(archive, dirname); + } + } + + public new static ANNModelSearch Load(ZipArchive archive, string dirname) + { + ANNModelSearch search = Load(archive, dirname); + USearchIndex index = new USearchIndex(archive, GetIndexPath(dirname)); + search.SetIndex(index); + return search; + } } } diff --git a/usearch/USearchIndex.cs b/usearch/USearchIndex.cs index 5405213b..8691820e 100644 --- a/usearch/USearchIndex.cs +++ b/usearch/USearchIndex.cs @@ -44,6 +44,11 @@ public USearchIndex(string path, string name = "") Load(path, name); } + public USearchIndex(ZipArchive zipArchive, string name = "") + { + Load(zipArchive, name); + } + public void Init(IndexOptions options) { _indexOptions = options; @@ -62,40 +67,45 @@ private static string GetIndexOptionsFilename(string name = "") return name == "" ? "indexOptions" : name + ".indexOptions"; } - private void Load(string path, string name = "") + public void Load(string path, string name = "") + { + using (FileStream zipFileStream = new FileStream(path, FileMode.Open)) + using (ZipArchive zipArchive = new ZipArchive(zipFileStream, ZipArchiveMode.Read)) + { + Load(zipArchive, name); + } + } + + public void Load(ZipArchive zipArchive, string name = "") { try { - using (FileStream zipFileStream = new FileStream(path, FileMode.Open)) - using (ZipArchive zipArchive = new ZipArchive(zipFileStream, ZipArchiveMode.Read)) + var entry = zipArchive.GetEntry(GetIndexOptionsFilename(name)); + using (Stream fileStream = entry.Open()) { - var entry = zipArchive.GetEntry(GetIndexOptionsFilename(name)); - using (Stream fileStream = entry.Open()) + LoadIndexOptions(fileStream); + } + + entry = zipArchive.GetEntry(GetIndexFilename(name)); + using (Stream entryStream = entry.Open()) + using (MemoryStream memoryStream = new MemoryStream()) + { + entryStream.CopyTo(memoryStream); + // Access the length and create a buffer + byte[] managedBuffer = new byte[memoryStream.Length]; + memoryStream.Position = 0; // Reset the position to the beginning + memoryStream.Read(managedBuffer, 0, managedBuffer.Length); + + GCHandle handle = GCHandle.Alloc(managedBuffer, GCHandleType.Pinned); + try { - LoadIndexOptions(fileStream); + IntPtr unmanagedBuffer = handle.AddrOfPinnedObject(); + usearch_load_buffer(_index, unmanagedBuffer, (UIntPtr)managedBuffer.Length, out IntPtr error); + HandleError(error); } - - entry = zipArchive.GetEntry(GetIndexFilename(name)); - using (Stream entryStream = entry.Open()) - using (MemoryStream memoryStream = new MemoryStream()) + finally { - entryStream.CopyTo(memoryStream); - // Access the length and create a buffer - byte[] managedBuffer = new byte[memoryStream.Length]; - memoryStream.Position = 0; // Reset the position to the beginning - memoryStream.Read(managedBuffer, 0, managedBuffer.Length); - - GCHandle handle = GCHandle.Alloc(managedBuffer, GCHandleType.Pinned); - try - { - IntPtr unmanagedBuffer = handle.AddrOfPinnedObject(); - usearch_load_buffer(_index, unmanagedBuffer, (UIntPtr)managedBuffer.Length, out IntPtr error); - HandleError(error); - } - finally - { - handle.Free(); - } + handle.Free(); } } } @@ -107,19 +117,23 @@ private void Load(string path, string name = "") public void Save(string path, string name = "", FileMode mode = FileMode.Create) { - string indexPath = path + GetIndexFilename(name); - string indexOptionsPath = path + GetIndexOptionsFilename(name); + using (FileStream zipFileStream = new FileStream(path, mode)) + using (ZipArchive zipArchive = new ZipArchive(zipFileStream, ZipArchiveMode.Create)){ + Save(zipArchive, name); + } + } + + public void Save(ZipArchive zipArchive, string name = "") + { + string indexPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + string indexOptionsPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); usearch_save(_index, indexPath, out IntPtr error); HandleError(error); SaveIndexOptions(indexOptionsPath); try { - using (FileStream zipFileStream = new FileStream(path, mode)) - using (ZipArchive zipArchive = new ZipArchive(zipFileStream, ZipArchiveMode.Create)) - { - zipArchive.CreateEntryFromFile(indexPath, GetIndexFilename(name)); - zipArchive.CreateEntryFromFile(indexOptionsPath, GetIndexOptionsFilename(name)); - } + zipArchive.CreateEntryFromFile(indexPath, GetIndexFilename(name)); + zipArchive.CreateEntryFromFile(indexOptionsPath, GetIndexOptionsFilename(name)); } catch (Exception ex) { From fa18ef054fc957ce3a66fb31381ad4d1d1012360 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Wed, 7 Feb 2024 20:46:35 +0200 Subject: [PATCH 068/161] add save/load to sample --- Samples~/HamletSearch/HamletSearch.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Samples~/HamletSearch/HamletSearch.cs b/Samples~/HamletSearch/HamletSearch.cs index 6819073e..732df6cb 100644 --- a/Samples~/HamletSearch/HamletSearch.cs +++ b/Samples~/HamletSearch/HamletSearch.cs @@ -4,6 +4,7 @@ using Debug = UnityEngine.Debug; using System.Text.RegularExpressions; using LLMUnity; +using System; class HamletSearch : MonoBehaviour { @@ -13,7 +14,7 @@ class HamletSearch : MonoBehaviour public void OnEnable() { - embedder = new BGEModel( + embedder = ModelManager.BGEModel( "Assets/StreamingAssets/bge-small-en-v1.5.sentis", "Assets/StreamingAssets/bge-small-en-v1.5.tokenizer.json" ); @@ -38,6 +39,9 @@ void Start() } Debug.Log($"embedded {dialogueManager.NumPhrases()} phrases, {dialogueManager.NumSentences()} sentences in {elapsedTotal} secs"); + dialogueManager.Save("test.zip"); + dialogueManager = DialogueManager.Load("test.zip"); + stopwatch.Reset(); stopwatch.Start(); string[] similar = dialogueManager.Search("should i be?", 10); stopwatch.Stop(); From 44bd488e661bacce29d52157354b6cbc0f229e60 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Thu, 8 Feb 2024 08:45:07 +0200 Subject: [PATCH 069/161] add saver Utils --- Runtime/Utils.cs | 62 +++++++++++++++++++++++++++++++++++++++++++ Runtime/Utils.cs.meta | 11 ++++++++ 2 files changed, 73 insertions(+) create mode 100644 Runtime/Utils.cs create mode 100644 Runtime/Utils.cs.meta diff --git a/Runtime/Utils.cs b/Runtime/Utils.cs new file mode 100644 index 00000000..14fd508c --- /dev/null +++ b/Runtime/Utils.cs @@ -0,0 +1,62 @@ +using System.IO; +using System.IO.Compression; +using System.Runtime.Serialization.Json; + +namespace LLMUnity +{ + public class Saver + { + public static void Save(object saveObject, string filePath, string name, FileMode mode = FileMode.Create) + { + using (FileStream stream = new FileStream(filePath, mode)) + using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Create)) + { + Save(saveObject, archive, name); + } + } + + public static void Save(object saveObject, ZipArchive archive, string name) + { + ZipArchiveEntry mainEntry = archive.CreateEntry(name); + using (Stream entryStream = mainEntry.Open()) + { + DataContractJsonSerializer serializer = new DataContractJsonSerializer(saveObject.GetType()); + serializer.WriteObject(entryStream, saveObject); + } + } + + public static T Load(string filePath, string name) + { + using (FileStream stream = new FileStream(filePath, FileMode.Open)) + using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read)) + { + return Load(archive, name); + } + } + + public static T Load(ZipArchive archive, string name) + { + ZipArchiveEntry baseEntry = archive.GetEntry(name); + using (Stream entryStream = baseEntry.Open()) + { + DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T)); + T obj = (T)serializer.ReadObject(entryStream); + return obj; + } + } + + public static string EscapeFileName(string fileName) + { + foreach (char invalidChar in Path.GetInvalidFileNameChars()) + { + fileName = fileName.Replace(invalidChar, '_'); + } + return fileName; + } + + public static string RemoveExtension(string name) + { + return Path.Combine(Path.GetDirectoryName(name), Path.GetFileNameWithoutExtension(name)); + } + } +} diff --git a/Runtime/Utils.cs.meta b/Runtime/Utils.cs.meta new file mode 100644 index 00000000..daa0a3b9 --- /dev/null +++ b/Runtime/Utils.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8a07f3848766af35ead6bd355897c7d2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 50294cc2928c1283774cd0183895933623fd3871 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Thu, 8 Feb 2024 16:59:09 +0200 Subject: [PATCH 070/161] add save/load to file --- Runtime/Embedder.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Runtime/Embedder.cs b/Runtime/Embedder.cs index 8b63821e..b0768625 100644 --- a/Runtime/Embedder.cs +++ b/Runtime/Embedder.cs @@ -49,11 +49,21 @@ public static string GetEmbeddingModelPath(string dirname) return Path.Combine(dirname, "EmbeddingModel.json"); } + public virtual void Save(string path, string dirname = "") + { + Saver.Save(this, path, GetEmbeddingModelPath(dirname)); + } + public virtual void Save(ZipArchive archive, string dirname = "") { Saver.Save(this, archive, GetEmbeddingModelPath(dirname)); } + public static EmbeddingModelSkeleton Load(string path, string dirname = "") + { + return Saver.Load(path, GetEmbeddingModelPath(dirname)); + } + public static EmbeddingModelSkeleton Load(ZipArchive archive, string dirname = "") { return Saver.Load(archive, GetEmbeddingModelPath(dirname)); From 9026d45211e538cc056c4724c2472c3c91ffc7d0 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Thu, 8 Feb 2024 17:00:28 +0200 Subject: [PATCH 071/161] set test folder structure --- Tests.meta | 8 ++++++++ Tests/Runtime.meta | 8 ++++++++ Tests/Runtime/undream.llmunity.Runtime.Tests.asmdef | 11 +++++++++++ .../undream.llmunity.Runtime.Tests.asmdef.meta | 7 +++++++ package.json | 3 +++ 5 files changed, 37 insertions(+) create mode 100644 Tests.meta create mode 100644 Tests/Runtime.meta create mode 100644 Tests/Runtime/undream.llmunity.Runtime.Tests.asmdef create mode 100644 Tests/Runtime/undream.llmunity.Runtime.Tests.asmdef.meta diff --git a/Tests.meta b/Tests.meta new file mode 100644 index 00000000..90ff7360 --- /dev/null +++ b/Tests.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f6bf1d5705e381662b78c7092af69a74 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/Runtime.meta b/Tests/Runtime.meta new file mode 100644 index 00000000..53eec156 --- /dev/null +++ b/Tests/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8453e0b4acf36f955a3cb282096c49fb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/Runtime/undream.llmunity.Runtime.Tests.asmdef b/Tests/Runtime/undream.llmunity.Runtime.Tests.asmdef new file mode 100644 index 00000000..cf7f3893 --- /dev/null +++ b/Tests/Runtime/undream.llmunity.Runtime.Tests.asmdef @@ -0,0 +1,11 @@ +{ + "name": "undream.llmunity.Runtime.Tests", + "references": [ + "Unity.Sentis", + "undream.llmunity.Runtime" + ], + "optionalUnityReferences": [ + "TestAssemblies" + ] +} + diff --git a/Tests/Runtime/undream.llmunity.Runtime.Tests.asmdef.meta b/Tests/Runtime/undream.llmunity.Runtime.Tests.asmdef.meta new file mode 100644 index 00000000..2987f1e0 --- /dev/null +++ b/Tests/Runtime/undream.llmunity.Runtime.Tests.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e24b8c7d32156a9ee9a0f7796a734ef3 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package.json b/package.json index 79785b85..6c9a19df 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,9 @@ "com.unity.sentis": "1.2.0-exp.2", "com.unity.nuget.newtonsoft-json": "3.2.1" }, + "testables": [ + "undream.llmunity.Runtime.Tests" + ], "keywords": [ "llm", "large language model", From fbf811671e88c82d2e46fd94223f8600a457bd38 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Thu, 8 Feb 2024 17:01:08 +0200 Subject: [PATCH 072/161] add EmbeddingModelSkeleton tests --- Tests/Runtime/TestEmbedder.cs | 42 +++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 Tests/Runtime/TestEmbedder.cs diff --git a/Tests/Runtime/TestEmbedder.cs b/Tests/Runtime/TestEmbedder.cs new file mode 100644 index 00000000..0ea3b30c --- /dev/null +++ b/Tests/Runtime/TestEmbedder.cs @@ -0,0 +1,42 @@ +using NUnit.Framework; +using LLMUnity; +using Unity.Sentis; +using System.IO; + + +namespace LLMUnityTests +{ + public class TestEmbeddingModelSkeleton + { + [Test] + public void TestEquality() + { + EmbeddingModelSkeleton skeleton1 = new EmbeddingModelSkeleton("model", "config", BackendType.CPU, "last_hidden_state", true, 384); + EmbeddingModelSkeleton skeleton2 = new EmbeddingModelSkeleton("model", "config", BackendType.CPU, "last_hidden_state", true, 384); + Assert.AreEqual(skeleton1, skeleton2); + Assert.AreEqual(skeleton1.GetHashCode(), skeleton2.GetHashCode()); + Assert.That(skeleton1.Equals(skeleton2)); + + skeleton2 = new EmbeddingModelSkeleton("model", "config", BackendType.GPUCompute, "last_hidden_state", true, 384); + Assert.AreNotEqual(skeleton1, skeleton2); + Assert.AreNotEqual(skeleton1.GetHashCode(), skeleton2.GetHashCode()); + Assert.That(!skeleton1.Equals(skeleton2)); + + skeleton2 = new EmbeddingModelSkeleton("model2", "config", BackendType.CPU, "last_hidden_state", true, 384); + Assert.AreNotEqual(skeleton1, skeleton2); + Assert.AreNotEqual(skeleton1.GetHashCode(), skeleton2.GetHashCode()); + Assert.That(!skeleton1.Equals(skeleton2)); + } + + [Test] + public void TestSaveLoad() + { + EmbeddingModelSkeleton skeleton1 = new EmbeddingModelSkeleton("model", "config", BackendType.CPU, "last_hidden_state", true, 384); + string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + skeleton1.Save(path); + EmbeddingModelSkeleton skeleton2 = EmbeddingModelSkeleton.Load(path); + Assert.AreEqual(skeleton1, skeleton2); + File.Delete(path); + } + } +} From 0ca66b09443fedaef581f34be7bfe4b94bf31d17 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Thu, 8 Feb 2024 17:01:25 +0200 Subject: [PATCH 073/161] add TestEmbedder.cs meta --- Tests/Runtime/TestEmbedder.cs.meta | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 Tests/Runtime/TestEmbedder.cs.meta diff --git a/Tests/Runtime/TestEmbedder.cs.meta b/Tests/Runtime/TestEmbedder.cs.meta new file mode 100644 index 00000000..bcf53097 --- /dev/null +++ b/Tests/Runtime/TestEmbedder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f500a058b577aed68a1acab1bc445120 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From cf6064df7a030ff5fe8911291a2409551b15b0f1 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Thu, 8 Feb 2024 18:11:39 +0200 Subject: [PATCH 074/161] add Count method in model manager --- Runtime/Embedder.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Runtime/Embedder.cs b/Runtime/Embedder.cs index b0768625..a9b327de 100644 --- a/Runtime/Embedder.cs +++ b/Runtime/Embedder.cs @@ -447,5 +447,10 @@ public static EmbeddingModel MiniLMModel(string modelPath, string tokenizerPath, { return Model(new EmbeddingModelSkeleton(modelPath, tokenizerPath, backend, "last_hidden_state", true, 384)); } + + public static int Count() + { + return models.Count(); + } } } From 3056058a1b13d1ea67b879b3255908ba90b76c28 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Thu, 8 Feb 2024 18:12:21 +0200 Subject: [PATCH 075/161] tests for EmbeddingModel and ModelManager --- Tests/Runtime/TestEmbedder.cs | 102 ++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/Tests/Runtime/TestEmbedder.cs b/Tests/Runtime/TestEmbedder.cs index 0ea3b30c..06aba3ee 100644 --- a/Tests/Runtime/TestEmbedder.cs +++ b/Tests/Runtime/TestEmbedder.cs @@ -2,6 +2,7 @@ using LLMUnity; using Unity.Sentis; using System.IO; +using UnityEngine; namespace LLMUnityTests @@ -39,4 +40,105 @@ public void TestSaveLoad() File.Delete(path); } } + + public class TestEmbeddingModel + { + EmbeddingModel model; + string modelPath; + string tokenizerPath; + + public bool ApproxEqual(float x1, float x2, float tolerance = 0.00001f) + { + return Mathf.Abs(x1 - x2) < tolerance; + } + + [SetUp] + public void SetUp() + { + modelPath = Path.Combine(Application.streamingAssetsPath, "bge-small-en-v1.5.sentis"); + tokenizerPath = Path.Combine(Application.streamingAssetsPath, "bge-small-en-v1.5.tokenizer.json"); + model = new EmbeddingModel(modelPath, tokenizerPath, BackendType.CPU, "sentence_embedding", false, 384); + } + + [Test] + public void TestEquality() + { + EmbeddingModelSkeleton skeleton1 = new EmbeddingModelSkeleton("model", "config", BackendType.CPU, "last_hidden_state", true, 384); + EmbeddingModelSkeleton skeleton2 = new EmbeddingModelSkeleton("model", "config", BackendType.CPU, "last_hidden_state", true, 384); + Assert.AreEqual(skeleton1, skeleton2); + Assert.AreEqual(skeleton1.GetHashCode(), skeleton2.GetHashCode()); + Assert.That(skeleton1.Equals(skeleton2)); + + skeleton2 = new EmbeddingModelSkeleton("model", "config", BackendType.GPUCompute, "last_hidden_state", true, 384); + Assert.AreNotEqual(skeleton1, skeleton2); + Assert.AreNotEqual(skeleton1.GetHashCode(), skeleton2.GetHashCode()); + Assert.That(!skeleton1.Equals(skeleton2)); + + skeleton2 = new EmbeddingModelSkeleton("model2", "config", BackendType.CPU, "last_hidden_state", true, 384); + Assert.AreNotEqual(skeleton1, skeleton2); + Assert.AreNotEqual(skeleton1.GetHashCode(), skeleton2.GetHashCode()); + Assert.That(!skeleton1.Equals(skeleton2)); + } + + [Test] + public void TestEncode() + { + float[] encoding = model.Encode("how is the weather today?").ToReadOnlyArray(); + Debug.Log(encoding[0]); + Debug.Log(encoding[383]); + Assert.That(ApproxEqual(encoding[0], -0.029100293293595314f)); + Assert.That(ApproxEqual(encoding[383], 0.017599990591406822f)); + } + + [Test] + public void TestConcatSplit() + { + float[] x1 = new float[] { 0, 1, 2, 3, 4, 5 }; + float[] x2 = new float[] { 6, 7, 8, 9, 10, 11 }; + Tensor[] tensors = new Tensor[2]; + tensors[0] = new TensorFloat(new TensorShape(1, x1.Length), x1); + tensors[1] = new TensorFloat(new TensorShape(1, x2.Length), x2); + Tensor tensorsConcat = model.Concat(tensors); + Assert.That(tensorsConcat.shape[0] == 2); + Assert.That(tensorsConcat.shape[1] == 6); + TensorFloat[] tensorsSplit = (TensorFloat[])model.Split(tensorsConcat); + float[] x1Back = tensorsSplit[0].ToReadOnlyArray(); + float[] x2Back = tensorsSplit[1].ToReadOnlyArray(); + Assert.AreEqual(x1, x1Back); + Assert.AreEqual(x2, x2Back); + } + + [Test] + public void TestSimilarity() + { + TensorFloat sentence1 = model.Encode("how is the weather today?"); + TensorFloat sentence2 = model.Encode("is it raining?"); + float trueSimilarity = 0.79276246f; + float[] similarity = model.SimilarityScores(sentence1, sentence2); + float[] distance = model.SimilarityDistances(sentence1, sentence2); + Assert.That(ApproxEqual(similarity[0], trueSimilarity)); + Assert.That(ApproxEqual(distance[0], 1 - trueSimilarity)); + } + + [Test] + public void TestModelManager() + { + EmbeddingModel bge1 = ModelManager.BGEModel(modelPath, tokenizerPath); + Assert.AreEqual(ModelManager.Count(), 1); + EmbeddingModel bge2 = ModelManager.BGEModel(modelPath, tokenizerPath); + Assert.AreEqual(ModelManager.Count(), 1); + EmbeddingModel lm1 = ModelManager.MiniLMModel(modelPath, tokenizerPath); + Assert.AreEqual(ModelManager.Count(), 2); + EmbeddingModel lm2 = ModelManager.Model(modelPath, tokenizerPath, BackendType.CPU, "last_hidden_state", true, 384); + Assert.AreEqual(ModelManager.Count(), 2); + Assert.AreEqual(bge1, bge2); + Assert.AreEqual(lm1, lm2); + } + + [TearDown] + public void TearDown() + { + model.Destroy(); + } + } } From 93b1e922acdfdcd3f7ee7694bba63b9b7b37a9f9 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Thu, 8 Feb 2024 18:20:02 +0200 Subject: [PATCH 076/161] remove debug messages --- Tests/Runtime/TestEmbedder.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Tests/Runtime/TestEmbedder.cs b/Tests/Runtime/TestEmbedder.cs index 06aba3ee..119d3c4f 100644 --- a/Tests/Runtime/TestEmbedder.cs +++ b/Tests/Runtime/TestEmbedder.cs @@ -84,8 +84,6 @@ public void TestEquality() public void TestEncode() { float[] encoding = model.Encode("how is the weather today?").ToReadOnlyArray(); - Debug.Log(encoding[0]); - Debug.Log(encoding[383]); Assert.That(ApproxEqual(encoding[0], -0.029100293293595314f)); Assert.That(ApproxEqual(encoding[383], 0.017599990591406822f)); } From 08b094389b67cd0738226f83f9773c25aa58209f Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Thu, 8 Feb 2024 21:02:34 +0200 Subject: [PATCH 077/161] implement embedding dictionary with float[], dot product --- Runtime/Dialogue.cs | 8 +-- Runtime/Search.cs | 115 +++++++++++++++++++++++++++++--------------- 2 files changed, 81 insertions(+), 42 deletions(-) diff --git a/Runtime/Dialogue.cs b/Runtime/Dialogue.cs index 94170167..7e257e25 100644 --- a/Runtime/Dialogue.cs +++ b/Runtime/Dialogue.cs @@ -206,7 +206,7 @@ public string[] Search(string queryString, int k, out float[] distances, bool re return Search(search.Encode(queryString), k, out distances, returnSentences); } - public string[] Search(TensorFloat encoding, int k, out float[] distances, bool returnSentences = false) + public string[] Search(float[] encoding, int k, out float[] distances, bool returnSentences = false) { if (search == null) throw new Exception("No search method defined!"); int[] keys = search.SearchKey(encoding, k, out distances); @@ -219,7 +219,7 @@ public string[] Search(TensorFloat encoding, int k, out float[] distances, bool return result; } - public string[] Search(TensorFloat encoding, int k, bool returnSentences = false) + public string[] Search(float[] encoding, int k, bool returnSentences = false) { return Search(encoding, k, out float[] distances, returnSentences); } @@ -403,7 +403,9 @@ public string[] Search(string queryString, int k, out float[] distances, string List dialogues = Filter(actor, title); ConcurrentBag<(string, float)> resultPairs = new ConcurrentBag<(string, float)>(); - var encoding = embedder.Encode(queryString); + TensorFloat encodingTensor = embedder.Encode(queryString); + encodingTensor.MakeReadable(); + float[] encoding = encodingTensor.ToReadOnlyArray(); Task.Run(() => {Parallel.ForEach(dialogues, dialogue => { diff --git a/Runtime/Search.cs b/Runtime/Search.cs index ab62775e..345d4e87 100644 --- a/Runtime/Search.cs +++ b/Runtime/Search.cs @@ -16,11 +16,11 @@ public class ModelSearchBase { protected EmbeddingModel embedder; [DataMember] - protected Dictionary embeddings; + protected Dictionary embeddings; public ModelSearchBase(EmbeddingModel embedder) { - embeddings = new Dictionary(); + embeddings = new Dictionary(); this.embedder = embedder; } @@ -29,19 +29,24 @@ public void SetEmbedder(EmbeddingModel embedder) this.embedder = embedder; } - public TensorFloat Encode(string inputString) + public float[] Encode(string inputString) { - return embedder.Encode(inputString); + TensorFloat encoding = embedder.Encode(inputString); + encoding.MakeReadable(); + return encoding.ToReadOnlyArray(); } - public TensorFloat[] Encode(List inputStrings, int batchSize = 64) + public float[][] Encode(List inputStrings, int batchSize = 64) { - List inputEmbeddings = new List(); + List inputEmbeddings = new List(); for (int i = 0; i < inputStrings.Count; i += batchSize) { int takeCount = Math.Min(batchSize, inputStrings.Count - i); List batch = new List(inputStrings.GetRange(i, takeCount)); - inputEmbeddings.AddRange((TensorFloat[])embedder.Split(embedder.Encode(batch))); + foreach (TensorFloat tensor in embedder.Split(embedder.Encode(batch))){ + tensor.MakeReadable(); + inputEmbeddings.Add(tensor.ToReadOnlyArray()); + } } if (inputStrings.Count != inputEmbeddings.Count) { @@ -50,7 +55,7 @@ public TensorFloat[] Encode(List inputStrings, int batchSize = 64) return inputEmbeddings.ToArray(); } - public virtual string[] Search(TensorFloat encoding, int k) + public virtual string[] Search(float[] encoding, int k) { return Search(encoding, k, out float[] distances); } @@ -59,11 +64,37 @@ public virtual string[] Search(string queryString, int k) { return Search(queryString, k, out float[] distances); } + + public static float DotProduct(float[] vector1, float[] vector2) + { + if (vector1.Length != vector2.Length) + { + throw new ArgumentException("Vector lengths must be equal for dot product calculation"); + } + float result = 0; + for (int i = 0; i < vector1.Length; i++) + { + result += vector1[i] * vector2[i]; + } + return result; + } + + public static float InverseDotProduct(float[] vector1, float[] vector2){ + return 1 - DotProduct(vector1, vector2); + } + + public static float[] InverseDotProduct(float[] vector1, float[][] vector2){ + float[] results =new float[vector2.Length]; + for (int i = 0; i < vector2.Length; i++) + { + results[i] = InverseDotProduct(vector1, vector2[i]); + } + return results; + } - public virtual string[] Search(TensorFloat encoding, int k, out float[] distances) + public virtual string[] Search(float[] encoding, int k, out float[] distances) { - TensorFloat storeEmbedding = embedder.Concat(embeddings.Values.ToArray()); - float[] unsortedDistances = embedder.SimilarityDistances(encoding, storeEmbedding); + float[] unsortedDistances = InverseDotProduct(encoding, embeddings.Values.ToArray()); var sortedLists = embeddings.Keys.Zip(unsortedDistances, (first, second) => new { First = first, Second = second }) .OrderBy(item => item.Second) @@ -81,7 +112,7 @@ public virtual string[] Search(TensorFloat encoding, int k, out float[] distance public virtual string[] Search(string queryString, int k, out float[] distances) { - return Search(embedder.Encode(queryString), k, out distances); + return Search(Encode(queryString), k, out distances); } public virtual int Count() @@ -117,6 +148,15 @@ public virtual void Save(ZipArchive archive, string dirname) embedder.Save(archive, dirname); } + public static ModelSearchBase CastLoad(string filePath, string dirname) + { + using (FileStream stream = new FileStream(filePath, FileMode.Open)) + using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read)) + { + return CastLoad(archive, dirname); + } + } + public static ModelSearchBase CastLoad(ZipArchive archive, string dirname) { ZipArchiveEntry typeEntry = archive.GetEntry(GetSearchTypePath(dirname)); @@ -152,31 +192,31 @@ public class ModelSearch : ModelSearchBase { public ModelSearch(EmbeddingModel embedder) : base(embedder) {} - protected void Insert(string inputString, TensorFloat encoding) + protected void Insert(string inputString, float[] encoding) { embeddings[inputString] = encoding; } - public TensorFloat Add(string inputString) + public float[] Add(string inputString) { - TensorFloat embedding = Encode(inputString); + float[] embedding = Encode(inputString); Insert(inputString, embedding); return embedding; } - public TensorFloat[] Add(string[] inputStrings, int batchSize = 64) + public float[][] Add(string[] inputStrings, int batchSize = 64) { return Add(new List(inputStrings), batchSize); } - public TensorFloat[] Add(List inputStrings, int batchSize = 64) + public float[][] Add(List inputStrings, int batchSize = 64) { - TensorFloat[] inputEmbeddings = Encode(inputStrings, batchSize); + float[][] inputEmbeddings = Encode(inputStrings, batchSize); for (int i = 0; i < inputStrings.Count; i++) { Insert(inputStrings[i], inputEmbeddings[i]); } - return inputEmbeddings.ToArray(); + return inputEmbeddings; } public static ModelSearch Load(string filePath, string dirname) @@ -201,27 +241,27 @@ public ModelKeySearch(EmbeddingModel embedder) : base(embedder) valueToKey = new Dictionary(); } - public virtual void Insert(int key, string value, TensorFloat encoding) + public virtual void Insert(int key, string value, float[] encoding) { embeddings[value] = encoding; valueToKey[value] = key; } - public virtual TensorFloat Add(int key, string inputString) + public virtual float[] Add(int key, string inputString) { - TensorFloat embedding = Encode(inputString); + float[] embedding = Encode(inputString); Insert(key, inputString, embedding); return embedding; } - public virtual TensorFloat[] Add(int[] keys, string[] inputStrings, int batchSize = 64) + public virtual float[][] Add(int[] keys, string[] inputStrings, int batchSize = 64) { return Add(new List(keys), new List(inputStrings), batchSize); } - public virtual TensorFloat[] Add(List keys, List inputStrings, int batchSize = 64) + public virtual float[][] Add(List keys, List inputStrings, int batchSize = 64) { - TensorFloat[] inputEmbeddings = Encode(inputStrings, batchSize); + float[][] inputEmbeddings = Encode(inputStrings, batchSize); for (int i = 0; i < inputStrings.Count; i++) { Insert(keys[i], inputStrings[i], inputEmbeddings[i]); @@ -229,7 +269,7 @@ public virtual TensorFloat[] Add(List keys, List inputStrings, int return inputEmbeddings.ToArray(); } - public virtual int[] SearchKey(TensorFloat embedding, int k, out float[] distances) + public virtual int[] SearchKey(float[] embedding, int k, out float[] distances) { string[] results = Search(embedding, k, out distances); int[] keys = new int[results.Length]; @@ -245,7 +285,7 @@ public virtual int[] SearchKey(string queryString, int k, out float[] distances) return SearchKey(Encode(queryString), k, out distances); } - public virtual int[] SearchKey(TensorFloat encoding, int k) + public virtual int[] SearchKey(float[] encoding, int k) { return SearchKey(encoding, k, out float[] distances); } @@ -297,14 +337,13 @@ public void SetIndex(USearchIndex index){ this.index = index; } - public override void Insert(int key, string value, TensorFloat encoding) + public override void Insert(int key, string value, float[] encoding) { - encoding.MakeReadable(); - index.Add((ulong)key, encoding.ToReadOnlyArray()); + index.Add((ulong)key, encoding); keyToValue[key] = value; } - public override string[] Search(TensorFloat encoding, int k) + public override string[] Search(float[] encoding, int k) { return Search(encoding, k, out float[] distances); } @@ -314,7 +353,7 @@ public override string[] Search(string queryString, int k) return Search(queryString, k, out float[] distances); } - public override string[] Search(TensorFloat encoding, int k, out float[] distances) + public override string[] Search(float[] encoding, int k, out float[] distances) { int[] results = SearchKey(encoding, k, out distances); string[] values = new string[results.Length]; @@ -327,10 +366,10 @@ public override string[] Search(TensorFloat encoding, int k, out float[] distanc public override string[] Search(string queryString, int k, out float[] distances) { - return Search(embedder.Encode(queryString), k, out distances); + return Search(Encode(queryString), k, out distances); } - public override int[] SearchKey(TensorFloat encoding, int k) + public override int[] SearchKey(float[] encoding, int k) { return SearchKey(encoding, k, out float[] distances); } @@ -340,11 +379,9 @@ public override int[] SearchKey(string queryString, int k) return SearchKey(queryString, k, out float[] distances); } - public override int[] SearchKey(TensorFloat encoding, int k, out float[] distances) + public override int[] SearchKey(float[] encoding, int k, out float[] distances) { - encoding.MakeReadable(); - index.Search(encoding.ToReadOnlyArray(), k, out ulong[] keys, out distances); - + index.Search(encoding, k, out ulong[] keys, out distances); int[] intKeys = new int[keys.Length]; for (int i = 0; i < keys.Length; i++) intKeys[i] = (int)keys[i]; @@ -353,7 +390,7 @@ public override int[] SearchKey(TensorFloat encoding, int k, out float[] distanc public override int[] SearchKey(string queryString, int k, out float[] distances) { - return SearchKey(embedder.Encode(queryString), k, out distances); + return SearchKey(Encode(queryString), k, out distances); } public override int Count() From 9b712d31b51c0834907cef6992f2622ad832a5a6 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Thu, 8 Feb 2024 21:03:17 +0200 Subject: [PATCH 078/161] add usearch to test asmdef --- Tests/Runtime/undream.llmunity.Runtime.Tests.asmdef | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tests/Runtime/undream.llmunity.Runtime.Tests.asmdef b/Tests/Runtime/undream.llmunity.Runtime.Tests.asmdef index cf7f3893..45369fd6 100644 --- a/Tests/Runtime/undream.llmunity.Runtime.Tests.asmdef +++ b/Tests/Runtime/undream.llmunity.Runtime.Tests.asmdef @@ -2,7 +2,8 @@ "name": "undream.llmunity.Runtime.Tests", "references": [ "Unity.Sentis", - "undream.llmunity.Runtime" + "undream.llmunity.Runtime", + "Cloud.Unum.USearch" ], "optionalUnityReferences": [ "TestAssemblies" From b71831d732644284c0718772891a1407e4f45224 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Thu, 8 Feb 2024 21:03:37 +0200 Subject: [PATCH 079/161] tests for search classes --- Tests/Runtime/TestSearch.cs | 145 +++++++++++++++++++++++++++++++ Tests/Runtime/TestSearch.cs.meta | 11 +++ 2 files changed, 156 insertions(+) create mode 100644 Tests/Runtime/TestSearch.cs create mode 100644 Tests/Runtime/TestSearch.cs.meta diff --git a/Tests/Runtime/TestSearch.cs b/Tests/Runtime/TestSearch.cs new file mode 100644 index 00000000..2ad28515 --- /dev/null +++ b/Tests/Runtime/TestSearch.cs @@ -0,0 +1,145 @@ +using NUnit.Framework; +using LLMUnity; +using Unity.Sentis; +using System.IO; +using UnityEngine; +using System.Collections.Generic; + +namespace LLMUnityTests +{ + public class TestSearch + { + EmbeddingModel model; + string modelPath; + string tokenizerPath; + string weather = "how is the weather today?"; + string raining = "is it raining?"; + string random = "something completely random"; + + public bool ApproxEqual(float x1, float x2, float tolerance = 0.00001f) + { + return Mathf.Abs(x1 - x2) < tolerance; + } + + [SetUp] + public void SetUp() + { + modelPath = Path.Combine(Application.streamingAssetsPath, "bge-small-en-v1.5.sentis"); + tokenizerPath = Path.Combine(Application.streamingAssetsPath, "bge-small-en-v1.5.tokenizer.json"); + model = new EmbeddingModel(modelPath, tokenizerPath, BackendType.CPU, "sentence_embedding", false, 384); + } + + public void TestEncode(ModelSearchBase search) + { + string inputString = weather; + List inputStrings = new List() { weather, weather }; + float[] encoding = search.Encode(inputString); + float[][] encodings = search.Encode(inputStrings); + foreach (float[] encodingArray in new List() { encoding, encodings[0], encodings[1] }) + { + Assert.That(ApproxEqual(encodingArray[0], -0.029100293293595314f)); + Assert.That(ApproxEqual(encodingArray[383], 0.017599990591406822f)); + } + } + + public void TestSaveLoad(ModelSearchBase search, string example) + { + string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + search.Save(path, ""); + var loadedSearch = ModelSearchBase.CastLoad(path, ""); + Assert.AreEqual(search.GetType(), loadedSearch.GetType()); + Assert.AreEqual(search.Count(), loadedSearch.Count()); + Assert.AreEqual(loadedSearch.Search(example, 1)[0], example); + File.Delete(path); + } + + public void TestAdd(ModelSearch search) + { + search.Add(weather); + Assert.AreEqual(search.Count(), 1); + search.Add(new List() { raining, random }); + search.Add(weather); + Assert.AreEqual(search.Count(), 3); + } + + public void TestKeyAdd(ModelKeySearch search) + { + search.Add(1, weather); + Assert.AreEqual(search.Count(), 1); + search.Add(new List() { 2, 3 }, new List() { raining, random }); + Assert.AreEqual(search.Count(), 3); + } + + public void TestSearchFunctions(ModelSearchBase search) + { + string[] result = search.Search(weather, 2, out float[] distances); + Assert.AreEqual(result.Length, 2); + Assert.AreEqual(distances.Length, 2); + Assert.AreEqual(result[0], weather); + Assert.AreEqual(result[1], raining); + Assert.That(ApproxEqual(distances[0], 0)); + float trueSimilarity = 0.79276246f; + Assert.That(ApproxEqual(distances[1], 1 - trueSimilarity)); + + if (search.GetType() == typeof(ModelKeySearch)) + { + TestSearchKey((ModelKeySearch)search); + } + } + + public void TestSearchKey(ModelKeySearch search) + { + int[] result = search.SearchKey(weather, 2, out float[] distances); + Assert.AreEqual(result.Length, 2); + Assert.AreEqual(distances.Length, 2); + Assert.AreEqual(result[0], 1); + Assert.AreEqual(result[1], 2); + Assert.That(ApproxEqual(distances[0], 0)); + float trueSimilarity = 0.79276246f; + Assert.That(ApproxEqual(distances[1], 1 - trueSimilarity)); + } + + public void FullTest(ModelSearchBase search) + { + TestEncode(search); + if (search.GetType() == typeof(ModelSearch)) + { + TestAdd((ModelSearch)search); + } + else + { + TestKeyAdd((ModelKeySearch)search); + } + TestSearchFunctions(search); + TestSaveLoad(search, weather); + TestSearchFunctions(search); + } + + [Test] + public void FullTestModelSearch() + { + ModelSearch search = new ModelSearch(model); + FullTest(search); + } + + [Test] + public void FullTestModelKeySearch() + { + ModelKeySearch search = new ModelKeySearch(model); + FullTest(search); + } + + [Test] + public void FullTestANNModelSearch() + { + ANNModelSearch search = new ANNModelSearch(model); + FullTest(search); + } + + [TearDown] + public void TearDown() + { + model.Destroy(); + } + } +} diff --git a/Tests/Runtime/TestSearch.cs.meta b/Tests/Runtime/TestSearch.cs.meta new file mode 100644 index 00000000..a1719084 --- /dev/null +++ b/Tests/Runtime/TestSearch.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 83f08e5d3be141b12964ca1b7d5e05b3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 8f041e2508faa6905ce7a04ea3c6379cacd0ea0f Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Thu, 8 Feb 2024 21:05:40 +0200 Subject: [PATCH 080/161] time save, load functions --- Samples~/HamletSearch/HamletSearch.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Samples~/HamletSearch/HamletSearch.cs b/Samples~/HamletSearch/HamletSearch.cs index 732df6cb..67cc6e54 100644 --- a/Samples~/HamletSearch/HamletSearch.cs +++ b/Samples~/HamletSearch/HamletSearch.cs @@ -39,8 +39,13 @@ void Start() } Debug.Log($"embedded {dialogueManager.NumPhrases()} phrases, {dialogueManager.NumSentences()} sentences in {elapsedTotal} secs"); + stopwatch.Reset(); stopwatch.Start(); dialogueManager.Save("test.zip"); + Debug.Log($"saving took {stopwatch.Elapsed.TotalMilliseconds / 1000f} secs"); + + stopwatch.Reset(); stopwatch.Start(); dialogueManager = DialogueManager.Load("test.zip"); + Debug.Log($"loading took {stopwatch.Elapsed.TotalMilliseconds / 1000f} secs"); stopwatch.Reset(); stopwatch.Start(); string[] similar = dialogueManager.Search("should i be?", 10); From 039610d237c2a3ff7cebc696dff88790a32eb2a0 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 9 Feb 2024 10:02:12 +0200 Subject: [PATCH 081/161] function to retrieve text from indices --- Runtime/Dialogue.cs | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/Runtime/Dialogue.cs b/Runtime/Dialogue.cs index 7e257e25..74c70923 100644 --- a/Runtime/Dialogue.cs +++ b/Runtime/Dialogue.cs @@ -92,6 +92,16 @@ public SentenceSplitter() : this(DefaultDelimiters, true) {} } return indices; } + + public static string[] IndicesToSentences(string input, List<(int, int)> indices) + { + string[] sentences = new string[indices.Count]; + for (int i = 0; i < indices.Count; i++) + { + sentences[i] = input.Substring(indices[i].Item1, indices[i].Item2 - indices[i].Item1 + 1); + } + return sentences; + } } [DataContract] @@ -259,7 +269,7 @@ public int NumSentences() return sentences.Count; } - public void Save(string filePath, string dirname="") + public void Save(string filePath, string dirname = "") { using (FileStream stream = new FileStream(filePath, FileMode.Create)) using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Create)) @@ -268,7 +278,8 @@ public void Save(string filePath, string dirname="") } } - public static string GetDialoguePath(string dirname){ + public static string GetDialoguePath(string dirname) + { return Path.Combine(dirname, "Dialogue.json"); } @@ -290,7 +301,7 @@ public static Dialogue Load(string filePath, string dirname) public static Dialogue Load(ZipArchive archive, string dirname) { Dialogue dialogue = Saver.Load(archive, GetDialoguePath(dirname)); - ModelKeySearch search = (ModelKeySearch) ModelSearchBase.CastLoad(archive, dirname); + ModelKeySearch search = (ModelKeySearch)ModelSearchBase.CastLoad(archive, dirname); dialogue.SetSearch(search); return dialogue; } @@ -407,7 +418,8 @@ public string[] Search(string queryString, int k, out float[] distances, string encodingTensor.MakeReadable(); float[] encoding = encodingTensor.ToReadOnlyArray(); Task.Run(() => - {Parallel.ForEach(dialogues, dialogue => + { + Parallel.ForEach(dialogues, dialogue => { string[] searchResults = dialogue.Search(encoding, k, out float[] searchDistances, returnSentences); for (int i = 0; i < searchResults.Length; i++) @@ -476,14 +488,16 @@ public int NumSentences(string actor = null, string title = null) return num; } - public static string GetDialogueManagerPath(string dirname){ + public static string GetDialogueManagerPath(string dirname) + { return Path.Combine(dirname, "DialogueManager.json"); } - public static string GetDialoguesPath(string dirname){ + public static string GetDialoguesPath(string dirname) + { return Path.Combine(dirname, "Dialogues.json"); } - public void Save(string filePath, string dirname="") + public void Save(string filePath, string dirname = "") { using (FileStream stream = new FileStream(filePath, FileMode.Create)) using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Create)) @@ -492,7 +506,7 @@ public void Save(string filePath, string dirname="") } } - public void Save(ZipArchive archive, string dirname="") + public void Save(ZipArchive archive, string dirname = "") { Saver.Save(this, archive, GetDialogueManagerPath(dirname)); @@ -516,7 +530,7 @@ public void Save(ZipArchive archive, string dirname="") } } - public static DialogueManager Load(string filePath, string dirname="") + public static DialogueManager Load(string filePath, string dirname = "") { using (FileStream stream = new FileStream(filePath, FileMode.Open)) using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read)) From 56be5db037480ad03d454eb1f67c42b3ec0e1a32 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 9 Feb 2024 10:02:34 +0200 Subject: [PATCH 082/161] tests for SentenceSplitter --- Tests/Runtime/TestDialogue.cs | 81 ++++++++++++++++++++++++++++++ Tests/Runtime/TestDialogue.cs.meta | 11 ++++ 2 files changed, 92 insertions(+) create mode 100644 Tests/Runtime/TestDialogue.cs create mode 100644 Tests/Runtime/TestDialogue.cs.meta diff --git a/Tests/Runtime/TestDialogue.cs b/Tests/Runtime/TestDialogue.cs new file mode 100644 index 00000000..1079168f --- /dev/null +++ b/Tests/Runtime/TestDialogue.cs @@ -0,0 +1,81 @@ +using NUnit.Framework; +using LLMUnity; +using System; +using System.Collections.Generic; + +namespace LLMUnityTests +{ + public class TestSentenceSplitter + { + [Test] + public void TestSplit() + { + SentenceSplitter splitter = new SentenceSplitter(); + SentenceSplitter splitterNoTrim = new SentenceSplitter(SentenceSplitter.DefaultDelimiters, false); + SentenceSplitter splitterQuestion = new SentenceSplitter(new char[] { '?' }, true); + SentenceSplitter splitterQuestionNoTrim = new SentenceSplitter(new char[] { '?' }, false); + + string[] sentences = new string[]{ + "hi.", + "how are you today?", + "the weather is nice!", + "perfect" + }; ; + string text = String.Join("", sentences); + + string[] sentencesSpace = (string[])sentences.Clone(); + sentencesSpace[0] = " " + sentencesSpace[0]; + sentencesSpace[1] = " " + sentencesSpace[1]; + sentencesSpace[3] = sentencesSpace[3] + " "; + string textSpace = String.Join("", sentencesSpace); + + string[] sentencesMultiSpace = (string[])sentences.Clone(); + sentencesMultiSpace[0] = " " + sentencesMultiSpace[0]; + sentencesMultiSpace[1] = " " + sentencesMultiSpace[1] + " "; + sentencesMultiSpace[3] = sentencesMultiSpace[3] + " "; + string textMultiSpace = String.Join("", sentencesMultiSpace); + + string[] sentencesBack, sentencesGT; + + //splitter + sentencesBack = SentenceSplitter.IndicesToSentences(text, splitter.Split(text)); + Assert.AreEqual(sentences, sentencesBack); + + sentencesBack = SentenceSplitter.IndicesToSentences(textSpace, splitter.Split(textSpace)); + Assert.AreEqual(sentences, sentencesBack); + + sentencesBack = SentenceSplitter.IndicesToSentences(textMultiSpace, splitter.Split(textMultiSpace)); + Assert.AreEqual(sentences, sentencesBack); + + //splitterNoTrim + sentencesBack = SentenceSplitter.IndicesToSentences(text, splitterNoTrim.Split(text)); + Assert.AreEqual(sentences, sentencesBack); + + sentencesBack = SentenceSplitter.IndicesToSentences(textSpace, splitterNoTrim.Split(textSpace)); + Assert.AreEqual(sentencesSpace, sentencesBack); + + //splitterQuestion + sentencesGT = new string[] { sentences[0] + sentences[1], sentences[2] + sentences[3] }; + sentencesBack = SentenceSplitter.IndicesToSentences(text, splitterQuestion.Split(text)); + Assert.AreEqual(sentencesGT, sentencesBack); + + sentencesGT = new string[] { sentences[0] + " " + sentences[1], sentences[2] + sentences[3] }; + sentencesBack = SentenceSplitter.IndicesToSentences(textSpace, splitterQuestion.Split(textSpace)); + Assert.AreEqual(sentencesGT, sentencesBack); + + sentencesGT = new string[] { sentences[0] + " " + sentences[1], sentences[2] + sentences[3] }; + sentencesBack = SentenceSplitter.IndicesToSentences(textMultiSpace, splitterQuestion.Split(textMultiSpace)); + Assert.AreEqual(sentencesGT, sentencesBack); + + //splitterQuestionNoTrim + sentencesGT = new string[] { sentences[0] + sentences[1], sentences[2] + sentences[3] }; + sentencesBack = SentenceSplitter.IndicesToSentences(text, splitterQuestionNoTrim.Split(text)); + Assert.AreEqual(sentencesGT, sentencesBack); + + sentencesGT = new string[] { sentencesSpace[0] + sentencesSpace[1], sentencesSpace[2] + sentencesSpace[3] }; + sentencesBack = SentenceSplitter.IndicesToSentences(textSpace, splitterQuestionNoTrim.Split(textSpace)); + Assert.AreEqual(sentencesGT, sentencesBack); + + } + } +} diff --git a/Tests/Runtime/TestDialogue.cs.meta b/Tests/Runtime/TestDialogue.cs.meta new file mode 100644 index 00000000..f9761287 --- /dev/null +++ b/Tests/Runtime/TestDialogue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ed5b8cf0501e02fb59b5d4ec2d712cb0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 45c921b061d22fd57e116b546524a6698eb3b1a3 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 9 Feb 2024 17:58:28 +0200 Subject: [PATCH 083/161] iterative search until number of phrases has been reached --- Runtime/Dialogue.cs | 44 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/Runtime/Dialogue.cs b/Runtime/Dialogue.cs index 74c70923..a851827b 100644 --- a/Runtime/Dialogue.cs +++ b/Runtime/Dialogue.cs @@ -219,14 +219,46 @@ public string[] Search(string queryString, int k, out float[] distances, bool re public string[] Search(float[] encoding, int k, out float[] distances, bool returnSentences = false) { if (search == null) throw new Exception("No search method defined!"); - int[] keys = search.SearchKey(encoding, k, out distances); - string[] result = new string[keys.Length]; - for (int i = 0; i < keys.Length; i++) + + if (returnSentences) { - Sentence sentence = sentences[keys[i]]; - result[i] = returnSentences ? GetSentence(sentence) : GetPhrase(sentence); + int[] keys = search.SearchKey(encoding, k, out distances); + string[] result = new string[keys.Length]; + for (int i = 0; i < keys.Length; i++) + { + Sentence sentence = sentences[keys[i]]; + result[i] = returnSentences ? GetSentence(sentence) : GetPhrase(sentence); + } + return result; + } + else + { + List phraseKeys; + List phraseDistances; + int currK = k; + do + { + int[] keys = search.SearchKey(encoding, currK, out float[] iterDistances); + phraseDistances = new List(); + phraseKeys = new List(); + for (int i = 0; i < keys.Length; i++) + { + int phraseId = sentences[keys[i]].phraseId; + if (phraseKeys.Contains(phraseId)) continue; + phraseKeys.Add(phraseId); + phraseDistances.Add(iterDistances[i]); + } + if (currK >= search.Count()) break; + currK *= 2; + } + while (phraseKeys.Count() < k); + + distances = phraseDistances.ToArray(); + string[] result = new string[phraseKeys.Count]; + for (int i = 0; i < phraseKeys.Count; i++) + result[i] = phrases[phraseKeys[i]].text; + return result; } - return result; } public string[] Search(float[] encoding, int k, bool returnSentences = false) From db8afc65333f64146b017d2c35a7dd0b16809bce Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 9 Feb 2024 18:04:51 +0200 Subject: [PATCH 084/161] Dialogue tests --- Tests/Runtime/TestDialogue.cs | 137 +++++++++++++++++++++++++++++++++- 1 file changed, 135 insertions(+), 2 deletions(-) diff --git a/Tests/Runtime/TestDialogue.cs b/Tests/Runtime/TestDialogue.cs index 1079168f..31410bc5 100644 --- a/Tests/Runtime/TestDialogue.cs +++ b/Tests/Runtime/TestDialogue.cs @@ -1,7 +1,9 @@ using NUnit.Framework; using LLMUnity; using System; -using System.Collections.Generic; +using System.IO; +using UnityEngine; +using Cloud.Unum.USearch; namespace LLMUnityTests { @@ -20,7 +22,7 @@ public void TestSplit() "how are you today?", "the weather is nice!", "perfect" - }; ; + }; string text = String.Join("", sentences); string[] sentencesSpace = (string[])sentences.Clone(); @@ -78,4 +80,135 @@ public void TestSplit() } } + public class TestDialogue + { + EmbeddingModel model; + string modelPath; + string tokenizerPath; + string[] sentences = new string[]{ + "hi.", + "how are you today?", + "how is the weather today?", + "is it raining?" + }; + + [SetUp] + public void SetUp() + { + modelPath = Path.Combine(Application.streamingAssetsPath, "bge-small-en-v1.5.sentis"); + tokenizerPath = Path.Combine(Application.streamingAssetsPath, "bge-small-en-v1.5.tokenizer.json"); + model = new EmbeddingModel(modelPath, tokenizerPath, Unity.Sentis.BackendType.CPU, "sentence_embedding", false, 384); + } + + [TearDown] + public void TearDown() + { + model.Destroy(); + } + + [Test] + public void TestAdd() + { + Dialogue dialogue = new Dialogue("", "", model); + foreach (string sentence in sentences) + dialogue.Add(sentence); + Assert.AreEqual(dialogue.GetPhrases().ToArray(), sentences); + Assert.AreEqual(dialogue.GetSentences().ToArray(), sentences); + Assert.AreEqual(dialogue.NumPhrases(), sentences.Length); + Assert.AreEqual(dialogue.NumSentences(), sentences.Length); + + string[] phrases = new string[] { sentences[0] + " " + sentences[1], sentences[2] + sentences[3] }; + dialogue = new Dialogue("", "", model); + foreach (string phrase in phrases) + dialogue.Add(phrase); + Assert.AreEqual(dialogue.GetPhrases().ToArray(), phrases); + Assert.AreEqual(dialogue.GetSentences().ToArray(), sentences); + Assert.AreEqual(dialogue.NumPhrases(), phrases.Length); + Assert.AreEqual(dialogue.NumSentences(), sentences.Length); + } + + public bool ApproxEqual(float x1, float x2, float tolerance = 0.00001f) + { + return Mathf.Abs(x1 - x2) < tolerance; + } + + [Test] + public void TestSearch() + { + Dialogue dialogue = new Dialogue("", "", model); + foreach (string sentence in sentences) + dialogue.Add(sentence); + string[] result; + string[] resultGT; + float trueSimilarity = 0.79276246f; + + result = dialogue.Search(sentences[3], 2); + resultGT = new string[] { sentences[3], sentences[2] }; + Assert.AreEqual(result, resultGT); + + result = dialogue.Search(sentences[3], 2, out float[] distances); + Assert.AreEqual(result, resultGT); + Assert.AreEqual(distances.Length, 2); + Assert.That(ApproxEqual(distances[0], 0)); + Assert.That(ApproxEqual(distances[1], 1 - trueSimilarity)); + + string[] phrases = new string[]{ + sentences[0] + sentences[1], + sentences[2], + sentences[2] + sentences[2] + sentences[2] + sentences[2] + + sentences[3] + sentences[3] + sentences[3] + sentences[3] + }; + dialogue = new Dialogue("", "", model); + foreach (string phrase in phrases) + dialogue.Add(phrase); + + result = dialogue.SearchSentences(sentences[3], 5, out distances); + resultGT = new string[] { sentences[3], sentences[3], sentences[3], sentences[3], sentences[2] }; + Assert.AreEqual(result, resultGT); + Assert.AreEqual(distances.Length, 5); + for (int i = 0; i < 4; i++) + Assert.That(ApproxEqual(distances[i], 0)); + Assert.That(ApproxEqual(distances[4], 1 - trueSimilarity)); + + float trueSimilarity2 = 0.7036853f; + result = dialogue.SearchPhrases(sentences[3], 4, out distances); + resultGT = new string[] { phrases[2], phrases[1], phrases[0] }; + Assert.AreEqual(result, resultGT); + Assert.AreEqual(distances.Length, 3); + Assert.That(ApproxEqual(distances[0], 0)); + Assert.That(ApproxEqual(distances[1], 1 - trueSimilarity)); + Debug.Log(distances[2]); + Assert.That(ApproxEqual(distances[2], 1 - trueSimilarity2)); + } + + [Test] + public void TestSaveLoad() + { + Dialogue dialogue = new Dialogue("", "", model); + foreach (string sentence in sentences) + dialogue.Add(sentence); + + string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + dialogue.Save(path, "test"); + var loadedDialogue = Dialogue.Load(path, "test"); + File.Delete(path); + + Assert.AreEqual(dialogue.NumSentences(), loadedDialogue.NumSentences()); + Assert.AreEqual(dialogue.NumPhrases(), loadedDialogue.NumPhrases()); + + string[] result; + string[] resultGT; + float trueSimilarity = 0.79276246f; + + result = dialogue.Search(sentences[3], 2); + resultGT = new string[] { sentences[3], sentences[2] }; + Assert.AreEqual(result, resultGT); + + result = dialogue.Search(sentences[3], 2, out float[] distances); + Assert.AreEqual(result, resultGT); + Assert.AreEqual(distances.Length, 2); + Assert.That(ApproxEqual(distances[0], 0)); + Assert.That(ApproxEqual(distances[1], 1 - trueSimilarity)); + } + } } From 58d0996888f6447d7b13dcea58d6f313770c9f2a Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 9 Feb 2024 19:39:02 +0200 Subject: [PATCH 085/161] remove ModelKeySearch for simplicity --- Runtime/Search.cs | 154 ++++++++++++++++++---------------------------- 1 file changed, 59 insertions(+), 95 deletions(-) diff --git a/Runtime/Search.cs b/Runtime/Search.cs index 345d4e87..8c04af69 100644 --- a/Runtime/Search.cs +++ b/Runtime/Search.cs @@ -43,7 +43,8 @@ public float[][] Encode(List inputStrings, int batchSize = 64) { int takeCount = Math.Min(batchSize, inputStrings.Count - i); List batch = new List(inputStrings.GetRange(i, takeCount)); - foreach (TensorFloat tensor in embedder.Split(embedder.Encode(batch))){ + foreach (TensorFloat tensor in embedder.Split(embedder.Encode(batch))) + { tensor.MakeReadable(); inputEmbeddings.Add(tensor.ToReadOnlyArray()); } @@ -64,7 +65,7 @@ public virtual string[] Search(string queryString, int k) { return Search(queryString, k, out float[] distances); } - + public static float DotProduct(float[] vector1, float[] vector2) { if (vector1.Length != vector2.Length) @@ -79,12 +80,14 @@ public static float DotProduct(float[] vector1, float[] vector2) return result; } - public static float InverseDotProduct(float[] vector1, float[] vector2){ + public static float InverseDotProduct(float[] vector1, float[] vector2) + { return 1 - DotProduct(vector1, vector2); } - public static float[] InverseDotProduct(float[] vector1, float[][] vector2){ - float[] results =new float[vector2.Length]; + public static float[] InverseDotProduct(float[] vector1, float[][] vector2) + { + float[] results = new float[vector2.Length]; for (int i = 0; i < vector2.Length; i++) { results[i] = InverseDotProduct(vector1, vector2[i]); @@ -129,11 +132,13 @@ public virtual void Save(string filePath, string dirname) } } - public static string GetSearchTypePath(string dirname){ + public static string GetSearchTypePath(string dirname) + { return Path.Combine(dirname, "SearchType.txt"); } - public static string GetSearchPath(string dirname){ + public static string GetSearchPath(string dirname) + { return Path.Combine(dirname, "Search.json"); } @@ -166,10 +171,10 @@ public static ModelSearchBase CastLoad(ZipArchive archive, string dirname) modelSearchType = Type.GetType(reader.ReadLine()); } MethodInfo methodInfo = modelSearchType.GetMethod("Load", new Type[] { typeof(ZipArchive), typeof(string) }); - return (ModelSearchBase) Convert.ChangeType(methodInfo.Invoke(null, new object[]{archive, dirname}), modelSearchType); + return (ModelSearchBase)Convert.ChangeType(methodInfo.Invoke(null, new object[] { archive, dirname }), modelSearchType); } - public static T Load(string filePath, string dirname) where T: ModelSearchBase + public static T Load(string filePath, string dirname) where T : ModelSearchBase { using (FileStream stream = new FileStream(filePath, FileMode.Open)) using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read)) @@ -178,7 +183,7 @@ public static T Load(string filePath, string dirname) where T: ModelSearchBas } } - public static T Load(ZipArchive archive, string dirname) where T: ModelSearchBase + public static T Load(ZipArchive archive, string dirname) where T : ModelSearchBase { T search = Saver.Load(archive, GetSearchPath(dirname)); EmbeddingModel embedder = EmbeddingModel.Load(archive, dirname); @@ -219,6 +224,11 @@ public float[][] Add(List inputStrings, int batchSize = 64) return inputEmbeddings; } + public bool Remove(string inputString) + { + return embeddings.Remove(inputString); + } + public static ModelSearch Load(string filePath, string dirname) { return Load(filePath, dirname); @@ -230,21 +240,43 @@ public static ModelSearch Load(ZipArchive archive, string dirname) } } + [DataContract] - public class ModelKeySearch : ModelSearchBase + public class ANNModelSearch : ModelSearchBase { + USearchIndex index; [DataMember] - protected Dictionary valueToKey; + protected SortedDictionary keyToValue; + + public ANNModelSearch(EmbeddingModel embedder) : this(embedder, MetricKind.Cos, 32, 40, 16) {} + + public ANNModelSearch( + EmbeddingModel embedder, + MetricKind metricKind = MetricKind.Cos, + ulong connectivity = 32, + ulong expansionAdd = 40, + ulong expansionSearch = 16, + bool multi = false + ) : this(embedder, new USearchIndex((ulong)embedder.Dimensions, metricKind, connectivity, expansionAdd, expansionSearch, multi)) {} + + public ANNModelSearch( + EmbeddingModel embedder, + USearchIndex index + ) : base(embedder) + { + this.index = index; + keyToValue = new SortedDictionary(); + } - public ModelKeySearch(EmbeddingModel embedder) : base(embedder) + public void SetIndex(USearchIndex index) { - valueToKey = new Dictionary(); + this.index = index; } - public virtual void Insert(int key, string value, float[] encoding) + public void Insert(int key, string value, float[] encoding) { - embeddings[value] = encoding; - valueToKey[value] = key; + index.Add((ulong)key, encoding); + keyToValue[key] = value; } public virtual float[] Add(int key, string inputString) @@ -269,78 +301,9 @@ public virtual float[][] Add(List keys, List inputStrings, int batc return inputEmbeddings.ToArray(); } - public virtual int[] SearchKey(float[] embedding, int k, out float[] distances) - { - string[] results = Search(embedding, k, out distances); - int[] keys = new int[results.Length]; - for (int i = 0; i < results.Length; i++) - { - keys[i] = valueToKey[results[i]]; - } - return keys; - } - - public virtual int[] SearchKey(string queryString, int k, out float[] distances) + public bool Remove(int key) { - return SearchKey(Encode(queryString), k, out distances); - } - - public virtual int[] SearchKey(float[] encoding, int k) - { - return SearchKey(encoding, k, out float[] distances); - } - - public virtual int[] SearchKey(string queryString, int k) - { - return SearchKey(queryString, k, out float[] distances); - } - - public static ModelKeySearch Load(string filePath, string dirname) - { - return Load(filePath, dirname); - } - - public static ModelKeySearch Load(ZipArchive archive, string dirname) - { - return Load(archive, dirname); - } - } - - [DataContract] - public class ANNModelSearch : ModelKeySearch - { - USearchIndex index; - [DataMember] - protected Dictionary keyToValue; - - public ANNModelSearch(EmbeddingModel embedder) : this(embedder, MetricKind.Cos, 32, 40, 16) {} - - public ANNModelSearch( - EmbeddingModel embedder, - MetricKind metricKind = MetricKind.Cos, - ulong connectivity = 32, - ulong expansionAdd = 40, - ulong expansionSearch = 16, - bool multi = false - ) : this(embedder, new USearchIndex((ulong)embedder.Dimensions, metricKind, connectivity, expansionAdd, expansionSearch, multi)) {} - - public ANNModelSearch( - EmbeddingModel embedder, - USearchIndex index - ) : base(embedder) - { - this.index = index; - keyToValue = new Dictionary(); - } - - public void SetIndex(USearchIndex index){ - this.index = index; - } - - public override void Insert(int key, string value, float[] encoding) - { - index.Add((ulong)key, encoding); - keyToValue[key] = value; + return index.Remove((ulong)key) > 0 && keyToValue.Remove(key); } public override string[] Search(float[] encoding, int k) @@ -369,17 +332,17 @@ public override string[] Search(string queryString, int k, out float[] distances return Search(Encode(queryString), k, out distances); } - public override int[] SearchKey(float[] encoding, int k) + public int[] SearchKey(float[] encoding, int k) { return SearchKey(encoding, k, out float[] distances); } - public override int[] SearchKey(string queryString, int k) + public int[] SearchKey(string queryString, int k) { return SearchKey(queryString, k, out float[] distances); } - public override int[] SearchKey(float[] encoding, int k, out float[] distances) + public int[] SearchKey(float[] encoding, int k, out float[] distances) { index.Search(encoding, k, out ulong[] keys, out distances); int[] intKeys = new int[keys.Length]; @@ -388,7 +351,7 @@ public override int[] SearchKey(float[] encoding, int k, out float[] distances) return intKeys; } - public override int[] SearchKey(string queryString, int k, out float[] distances) + public int[] SearchKey(string queryString, int k, out float[] distances) { return SearchKey(Encode(queryString), k, out distances); } @@ -398,7 +361,8 @@ public override int Count() return (int)index.Size(); } - public static string GetIndexPath(string dirname){ + public static string GetIndexPath(string dirname) + { return Path.Combine(dirname, "USearch"); } @@ -408,7 +372,7 @@ public override void Save(ZipArchive archive, string dirname) index.Save(archive, GetIndexPath(dirname)); } - public new static ANNModelSearch Load(string filePath, string dirname) + public static ANNModelSearch Load(string filePath, string dirname) { using (FileStream stream = new FileStream(filePath, FileMode.Open)) using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read)) @@ -417,7 +381,7 @@ public override void Save(ZipArchive archive, string dirname) } } - public new static ANNModelSearch Load(ZipArchive archive, string dirname) + public static ANNModelSearch Load(ZipArchive archive, string dirname) { ANNModelSearch search = Load(archive, dirname); USearchIndex index = new USearchIndex(archive, GetIndexPath(dirname)); From f4cbbd0054cba0b592b8bbd50cae1f7b0681911f Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 9 Feb 2024 19:39:39 +0200 Subject: [PATCH 086/161] remove ModelKeySearch from Dialogue, add Remove function --- Runtime/Dialogue.cs | 78 ++++++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/Runtime/Dialogue.cs b/Runtime/Dialogue.cs index a851827b..76495f19 100644 --- a/Runtime/Dialogue.cs +++ b/Runtime/Dialogue.cs @@ -113,26 +113,28 @@ public class Dialogue public string Actor { get; private set; } [DataMember] - List phrases; + SortedDictionary phrases; [DataMember] - List sentences; + SortedDictionary sentences; + [DataMember] + int nextPhraseId = 0; + [DataMember] + int nextSentenceId = 0; [DataMember] SentenceSplitter sentenceSplitter; - ModelKeySearch search; - - public Dialogue(string actor = "", string title = "", EmbeddingModel embedder = null) : this(actor, title, embedder, typeof(ANNModelSearch)) {} + ANNModelSearch search; - public Dialogue(string actor = "", string title = "", EmbeddingModel embedder = null, Type modelSearchType = null) + public Dialogue(string actor = "", string title = "", EmbeddingModel embedder = null) { Actor = actor; Title = title; - phrases = new List(); - sentences = new List(); + phrases = new SortedDictionary(); + sentences = new SortedDictionary(); sentenceSplitter = new SentenceSplitter(); search = null; - if (embedder != null && modelSearchType != null) + if (embedder != null) { - search = (ModelKeySearch)Activator.CreateInstance(modelSearchType, embedder); + search = new ANNModelSearch(embedder); } } @@ -154,7 +156,7 @@ public void SetNoSentenceSplitting() SetSentenceSplitting(null); } - public void SetSearch(ModelKeySearch search) + public void SetSearch(ANNModelSearch search) { this.search = search; } @@ -180,31 +182,56 @@ public void Add(string text) if (sentenceSplitter == null) subindices = new List<(int, int)> { (0, text.Length - 1) }; else subindices = sentenceSplitter.Split(text); - int phraseId = phrases.Count; + int phraseId = nextPhraseId++; Phrase phrase = new Phrase(text); - phrases.Add(phrase); + phrases[phraseId] = phrase; foreach ((int startIndex, int endIndex) in subindices) { - int sentenceId = sentences.Count; + int sentenceId = nextSentenceId++; Sentence sentence = new Sentence(phraseId, startIndex, endIndex); - - sentences.Add(sentence); + sentences[sentenceId] = sentence; phrase.sentenceIds.Add(sentenceId); search?.Add(sentenceId, GetSentence(sentence)); } } + public int Remove(string text) + { + List removePhraseIds = new List(); + foreach (var phrasePair in phrases) + { + Phrase phrase = phrasePair.Value; + if (phrase.text == text) + { + foreach (int sentenceId in phrase.sentenceIds) + { + sentences.Remove(sentenceId); + search?.Remove(sentenceId); + } + removePhraseIds.Add(phrasePair.Key); + } + } + foreach (int phraseId in removePhraseIds) + { + phrases.Remove(phraseId); + } + return removePhraseIds.Count; + } + public List GetPhrases() { List phraseTexts = new List(); - foreach (Phrase phrase in phrases) phraseTexts.Add(phrase.text); + foreach (Phrase phrase in phrases.Values) + { + phraseTexts.Add(phrase.text); + } return phraseTexts; } public List GetSentences() { List allSentences = new List(); - foreach (Sentence sentence in sentences) + foreach (Sentence sentence in sentences.Values) { allSentences.Add(GetSentence(sentence)); } @@ -333,7 +360,7 @@ public static Dialogue Load(string filePath, string dirname) public static Dialogue Load(ZipArchive archive, string dirname) { Dialogue dialogue = Saver.Load(archive, GetDialoguePath(dirname)); - ModelKeySearch search = (ModelKeySearch)ModelSearchBase.CastLoad(archive, dirname); + ANNModelSearch search = ANNModelSearch.Load(archive, dirname); dialogue.SetSearch(search); return dialogue; } @@ -349,18 +376,10 @@ public class DialogueManager bool trimSentences = true; [DataMember] EmbeddingModel embedder; - Type modelSearchType; - [DataMember] - string modelSearchTypeName; - - public DialogueManager(EmbeddingModel embedder = null) : this(embedder, typeof(ANNModelSearch)) {} - - public DialogueManager(EmbeddingModel embedder = null, Type modelSearchType = null) + public DialogueManager(EmbeddingModel embedder = null) { dialogues = new Dictionary>(); this.embedder = embedder; - this.modelSearchType = modelSearchType; - this.modelSearchTypeName = modelSearchType.FullName; } public void SetSentenceSplitting(char[] delimiters, bool trimSentences = true) @@ -387,7 +406,7 @@ public void Add(string actor, string title, string text) { if (!dialogues.ContainsKey(actor) || !dialogues[actor].ContainsKey(title)) { - Dialogue dialogue = new Dialogue(actor, title, embedder, modelSearchType); + Dialogue dialogue = new Dialogue(actor, title, embedder); dialogue.SetSentenceSplitting(delimiters, trimSentences); if (!dialogues.ContainsKey(actor)) { @@ -568,7 +587,6 @@ public static DialogueManager Load(string filePath, string dirname = "") using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read)) { DialogueManager dialogueManager = Saver.Load(archive, GetDialogueManagerPath(dirname)); - dialogueManager.modelSearchType = Type.GetType(dialogueManager.modelSearchTypeName); dialogueManager.embedder = EmbeddingModel.Load(archive, dirname); From d7b4368032276732cd465daf1582396cc4f10111 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 9 Feb 2024 19:40:06 +0200 Subject: [PATCH 087/161] remove ModelKeySearch from tests --- Tests/Runtime/TestSearch.cs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/Tests/Runtime/TestSearch.cs b/Tests/Runtime/TestSearch.cs index 2ad28515..73fb9945 100644 --- a/Tests/Runtime/TestSearch.cs +++ b/Tests/Runtime/TestSearch.cs @@ -60,14 +60,22 @@ public void TestAdd(ModelSearch search) search.Add(new List() { raining, random }); search.Add(weather); Assert.AreEqual(search.Count(), 3); + search.Remove(weather); + Assert.AreEqual(search.Count(), 2); + search.Add(weather); + Assert.AreEqual(search.Count(), 3); } - public void TestKeyAdd(ModelKeySearch search) + public void TestKeyAdd(ANNModelSearch search) { search.Add(1, weather); Assert.AreEqual(search.Count(), 1); search.Add(new List() { 2, 3 }, new List() { raining, random }); Assert.AreEqual(search.Count(), 3); + search.Remove(2); + Assert.AreEqual(search.Count(), 2); + search.Add(2, raining); + Assert.AreEqual(search.Count(), 3); } public void TestSearchFunctions(ModelSearchBase search) @@ -81,13 +89,13 @@ public void TestSearchFunctions(ModelSearchBase search) float trueSimilarity = 0.79276246f; Assert.That(ApproxEqual(distances[1], 1 - trueSimilarity)); - if (search.GetType() == typeof(ModelKeySearch)) + if (search.GetType() == typeof(ANNModelSearch)) { - TestSearchKey((ModelKeySearch)search); + TestSearchKey((ANNModelSearch)search); } } - public void TestSearchKey(ModelKeySearch search) + public void TestSearchKey(ANNModelSearch search) { int[] result = search.SearchKey(weather, 2, out float[] distances); Assert.AreEqual(result.Length, 2); @@ -108,7 +116,7 @@ public void FullTest(ModelSearchBase search) } else { - TestKeyAdd((ModelKeySearch)search); + TestKeyAdd((ANNModelSearch)search); } TestSearchFunctions(search); TestSaveLoad(search, weather); @@ -122,13 +130,6 @@ public void FullTestModelSearch() FullTest(search); } - [Test] - public void FullTestModelKeySearch() - { - ModelKeySearch search = new ModelKeySearch(model); - FullTest(search); - } - [Test] public void FullTestANNModelSearch() { From 0e2e3128921d3f42ab2a2a92dbe7e5be68832828 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 9 Feb 2024 19:40:43 +0200 Subject: [PATCH 088/161] add tests for remove in dialogues --- Tests/Runtime/TestDialogue.cs | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/Tests/Runtime/TestDialogue.cs b/Tests/Runtime/TestDialogue.cs index 31410bc5..02771bcb 100644 --- a/Tests/Runtime/TestDialogue.cs +++ b/Tests/Runtime/TestDialogue.cs @@ -3,7 +3,6 @@ using System; using System.IO; using UnityEngine; -using Cloud.Unum.USearch; namespace LLMUnityTests { @@ -117,14 +116,40 @@ public void TestAdd() Assert.AreEqual(dialogue.NumPhrases(), sentences.Length); Assert.AreEqual(dialogue.NumSentences(), sentences.Length); - string[] phrases = new string[] { sentences[0] + " " + sentences[1], sentences[2] + sentences[3] }; + dialogue.Remove(sentences[1]); + string[] sentencesGT = new string[] { sentences[0], sentences[2], sentences[3] }; + Assert.AreEqual(dialogue.GetPhrases().ToArray(), sentencesGT); + Assert.AreEqual(dialogue.GetSentences().ToArray(), sentencesGT); + Assert.AreEqual(dialogue.NumPhrases(), sentencesGT.Length); + Assert.AreEqual(dialogue.NumSentences(), sentencesGT.Length); + + dialogue.Add(sentences[1]); + dialogue.Add(sentences[1]); + dialogue.Remove(sentences[1]); + Assert.AreEqual(dialogue.GetPhrases().ToArray(), sentencesGT); + Assert.AreEqual(dialogue.GetSentences().ToArray(), sentencesGT); + Assert.AreEqual(dialogue.NumPhrases(), sentencesGT.Length); + Assert.AreEqual(dialogue.NumSentences(), sentencesGT.Length); + + string[] phrases = new string[] { sentences[0] + " " + sentences[1], sentences[1] + sentences[2], sentences[2] + sentences[3] }; dialogue = new Dialogue("", "", model); foreach (string phrase in phrases) dialogue.Add(phrase); - Assert.AreEqual(dialogue.GetPhrases().ToArray(), phrases); + dialogue.Remove(phrases[1]); + string[] phrasesGT = new string[] { phrases[0], phrases[2] }; + Assert.AreEqual(dialogue.GetPhrases().ToArray(), new string[] { phrases[0], phrases[2] }); Assert.AreEqual(dialogue.GetSentences().ToArray(), sentences); - Assert.AreEqual(dialogue.NumPhrases(), phrases.Length); - Assert.AreEqual(dialogue.NumSentences(), sentences.Length); + Assert.AreEqual(dialogue.NumPhrases(), 2); + Assert.AreEqual(dialogue.NumSentences(), 4); + + dialogue.Add(phrases[1]); + phrasesGT = new string[] { phrases[0], phrases[2], phrases[1] }; + sentencesGT = new string[] { sentences[0], sentences[1], sentences[2], sentences[3], sentences[1], sentences[2] }; + + Assert.AreEqual(dialogue.GetPhrases().ToArray(), phrasesGT); + Assert.AreEqual(dialogue.GetSentences().ToArray(), sentencesGT); + Assert.AreEqual(dialogue.NumPhrases(), phrasesGT.Length); + Assert.AreEqual(dialogue.NumSentences(), sentencesGT.Length); } public bool ApproxEqual(float x1, float x2, float tolerance = 0.00001f) From 5be4ce18299571742e09baba0875f17524346f0a Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 9 Feb 2024 20:54:17 +0200 Subject: [PATCH 089/161] add Remove function in DialogueManager, use string[] instead of List when getting --- Runtime/Dialogue.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/Runtime/Dialogue.cs b/Runtime/Dialogue.cs index 76495f19..c269462f 100644 --- a/Runtime/Dialogue.cs +++ b/Runtime/Dialogue.cs @@ -422,6 +422,17 @@ public void Add(string actor, string text) Add(actor, null, text); } + public int Remove(string actor, string title, string text) + { + List dialogues = Filter(actor, title); + int removed = 0; + foreach (Dialogue dialogue in dialogues) + { + removed += dialogue.Remove(text); + } + return removed; + } + public List Filter(string actor = null, string title = null) { List filtering = new List(); @@ -438,7 +449,7 @@ public List Filter(string actor = null, string title = null) return filtering; } - public List Get(string actor = null, string title = null, bool returnSentences = false) + public string[] Get(string actor = null, string title = null, bool returnSentences = false) { List dialogues = Filter(actor, title); List result = new List(); @@ -446,15 +457,15 @@ public List Get(string actor = null, string title = null, bool returnSen { result.AddRange(returnSentences ? dialogue.GetSentences() : dialogue.GetPhrases()); } - return result; + return result.ToArray(); } - public List GetPhrases(string actor = null, string title = null) + public string[] GetPhrases(string actor = null, string title = null) { return Get(actor, title, false); } - public List GetSentences(string actor = null, string title = null) + public string[] GetSentences(string actor = null, string title = null) { return Get(actor, title, true); } From 1d0468585f0b09c11bfdd5bbcbddc523451b1aa2 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 9 Feb 2024 20:54:44 +0200 Subject: [PATCH 090/161] add tests for dialogue manager --- Tests/Runtime/TestDialogue.cs | 119 ++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/Tests/Runtime/TestDialogue.cs b/Tests/Runtime/TestDialogue.cs index 02771bcb..911f265e 100644 --- a/Tests/Runtime/TestDialogue.cs +++ b/Tests/Runtime/TestDialogue.cs @@ -3,6 +3,7 @@ using System; using System.IO; using UnityEngine; +using System.Collections.Generic; namespace LLMUnityTests { @@ -79,6 +80,7 @@ public void TestSplit() } } + public class TestDialogue { EmbeddingModel model; @@ -236,4 +238,121 @@ public void TestSaveLoad() Assert.That(ApproxEqual(distances[1], 1 - trueSimilarity)); } } + + public class TestDialogueManager + { + EmbeddingModel model; + string modelPath; + string tokenizerPath; + List<(string, string, string)> phrases = new List<(string, string, string)>(){ + ("Hamlet", "ACT I", "To be, or not to be, that is the question. Whether tis nobler in the mind to suffer."), + ("Hamlet", "ACT I", "Or to take arms against a sea of troubles, and by opposing end them? To die—to sleep."), + ("Hamlet", "ACT II", "I humbly thank you; well, well, well."), + ("Ophelia", "ACT II", "Good my lord."), + ("Ophelia", "ACT II", "How does your honour for this many a day?") + }; + + [SetUp] + public void SetUp() + { + modelPath = Path.Combine(Application.streamingAssetsPath, "bge-small-en-v1.5.sentis"); + tokenizerPath = Path.Combine(Application.streamingAssetsPath, "bge-small-en-v1.5.tokenizer.json"); + model = new EmbeddingModel(modelPath, tokenizerPath, Unity.Sentis.BackendType.CPU, "sentence_embedding", false, 384); + } + + [TearDown] + public void TearDown() + { + model.Destroy(); + } + + [Test] + public void TestAdd() + { + DialogueManager manager = new DialogueManager(model); + foreach (var phrase in phrases) + manager.Add(phrase.Item1, phrase.Item2, phrase.Item3); + Assert.AreEqual(manager.NumPhrases(), 5); + Assert.AreEqual(manager.NumSentences(), 8); + Assert.AreEqual(manager.NumPhrases("Hamlet"), 3); + Assert.AreEqual(manager.NumSentences("Hamlet"), 6); + Assert.AreEqual(manager.NumPhrases("Ophelia"), 2); + Assert.AreEqual(manager.NumSentences("Ophelia"), 2); + Assert.AreEqual(manager.NumPhrases(null, "ACT I"), 2); + Assert.AreEqual(manager.NumSentences(null, "ACT I"), 4); + Assert.AreEqual(manager.NumPhrases(null, "ACT II"), 3); + Assert.AreEqual(manager.NumSentences(null, "ACT II"), 4); + Assert.AreEqual(manager.NumPhrases("Hamlet", "ACT I"), 2); + Assert.AreEqual(manager.NumSentences("Hamlet", "ACT II"), 2); + + Assert.AreEqual(manager.GetPhrases("Hamlet", "ACT II"), new string[] { phrases[2].Item3 }); + string[] sentencesGT = phrases[2].Item3.Split(";"); + sentencesGT[0] += ";"; + sentencesGT[1] = sentencesGT[1].Trim(); + Assert.AreEqual(manager.GetSentences("Hamlet", "ACT II"), sentencesGT); + + manager.Add(phrases[3].Item1, phrases[3].Item2, phrases[3].Item3); + Assert.AreEqual(manager.NumPhrases("Ophelia"), 3); + Assert.AreEqual(manager.NumSentences("Ophelia"), 3); + manager.Remove(null, null, phrases[2].Item3); + Assert.AreEqual(manager.NumPhrases("Hamlet"), 2); + Assert.AreEqual(manager.NumSentences("Hamlet"), 4); + manager.Remove(null, null, phrases[3].Item3); + Assert.AreEqual(manager.NumPhrases("Ophelia"), 1); + Assert.AreEqual(manager.NumSentences("Ophelia"), 1); + manager.Add("Ophelia", phrases[0].Item2, phrases[0].Item3); + manager.Remove("Hamlet", null, phrases[0].Item3); + Assert.AreEqual(manager.NumPhrases("Ophelia"), 2); + Assert.AreEqual(manager.NumSentences("Ophelia"), 3); + Assert.AreEqual(manager.NumPhrases("Hamlet"), 1); + Assert.AreEqual(manager.NumSentences("Hamlet"), 2); + + sentencesGT = phrases[1].Item3.Split("?"); + sentencesGT[0] += "?"; + sentencesGT[1] = sentencesGT[1].Trim(); + Assert.AreEqual(manager.GetSentences("Hamlet"), sentencesGT); + Assert.AreEqual(manager.GetPhrases("Ophelia"), new string[] { phrases[4].Item3, phrases[0].Item3 }); + } + + [Test] + public void TestSaveLoad() + { + string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + + DialogueManager manager = new DialogueManager(model); + manager.Save(path); + DialogueManager loadedManager = DialogueManager.Load(path); + + foreach (var phrase in phrases) + manager.Add(phrase.Item1, phrase.Item2, phrase.Item3); + manager.Save(path); + loadedManager = DialogueManager.Load(path); + File.Delete(path); + + Assert.AreEqual(manager.NumSentences(), loadedManager.NumSentences()); + Assert.AreEqual(manager.NumPhrases(), loadedManager.NumPhrases()); + + manager.Remove(null, null, phrases[2].Item3); + Assert.AreEqual(manager.NumPhrases("Hamlet"), 2); + Assert.AreEqual(manager.NumSentences("Hamlet"), 4); + } + + [Test] + public void TestSearch() + { + DialogueManager manager = new DialogueManager(model); + foreach (var phrase in phrases) + manager.Add(phrase.Item1, phrase.Item2, phrase.Item3); + manager.Add("Ophelia", phrases[0].Item2, phrases[0].Item3); + + string[] results = manager.SearchPhrases(phrases[0].Item3, 2); + Assert.AreEqual(results, new string[] { phrases[0].Item3, phrases[0].Item3 }); + + results = manager.SearchPhrases(phrases[0].Item3, 2, "Hamlet"); + Assert.AreEqual(results[0], phrases[0].Item3); + Assert.AreNotEqual(results[1], phrases[0].Item3); + results = manager.SearchPhrases(phrases[1].Item3, 1, "Ophelia"); + Assert.AreNotEqual(results[0], phrases[1].Item3); + } + } } From fc280657edf6cf373d3d35c73def02d244170b63 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Fri, 9 Feb 2024 20:55:35 +0200 Subject: [PATCH 091/161] adapt sample to change in Get --- Samples~/HamletSearch/HamletSearch.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Samples~/HamletSearch/HamletSearch.cs b/Samples~/HamletSearch/HamletSearch.cs index 67cc6e54..fabc3f24 100644 --- a/Samples~/HamletSearch/HamletSearch.cs +++ b/Samples~/HamletSearch/HamletSearch.cs @@ -35,7 +35,7 @@ void Start() dialogueManager.Add(actor, act, message); elapsedTotal += (float)stopwatch.Elapsed.TotalMilliseconds / 1000f; - Debug.Log($"act {act} embedded {dialogueManager.GetSentences(null, act).Count} sentences in {stopwatch.Elapsed.TotalMilliseconds / 1000f} secs"); + Debug.Log($"act {act} embedded {dialogueManager.GetSentences(null, act).Length} sentences in {stopwatch.Elapsed.TotalMilliseconds / 1000f} secs"); } Debug.Log($"embedded {dialogueManager.NumPhrases()} phrases, {dialogueManager.NumSentences()} sentences in {elapsedTotal} secs"); From 6ccf61d549934a24e38b54fe6d8c2616b2b72d9d Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Sun, 11 Feb 2024 18:26:58 +0200 Subject: [PATCH 092/161] move the GetAssetPath to the LLMUnitySetup --- Runtime/LLM.cs | 18 +++++++++--------- Runtime/LLMClient.cs | 11 ++--------- Runtime/LLMUnitySetup.cs | 6 ++++++ 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/Runtime/LLM.cs b/Runtime/LLM.cs index 0fe02372..8338e7ab 100644 --- a/Runtime/LLM.cs +++ b/Runtime/LLM.cs @@ -28,11 +28,11 @@ public class LLM : LLMClient [HideInInspector] public string modelUrl = "https://huggingface.co/TheBloke/Mistral-7B-Instruct-v0.2-GGUF/resolve/main/mistral-7b-instruct-v0.2.Q4_K_M.gguf?download=true"; private static readonly string serverZipUrl = "https://github.com/Mozilla-Ocho/llamafile/releases/download/0.6/llamafile-0.6.zip"; - private static readonly string server = Path.Combine(GetAssetPath(Path.GetFileNameWithoutExtension(serverZipUrl)), "bin/llamafile"); + private static readonly string server = Path.Combine(LLMUnitySetup.GetAssetPath(Path.GetFileNameWithoutExtension(serverZipUrl)), "bin/llamafile"); private static readonly string apeARMUrl = "https://cosmo.zip/pub/cosmos/bin/ape-arm64.elf"; - private static readonly string apeARM = GetAssetPath("ape-arm64.elf"); + private static readonly string apeARM = LLMUnitySetup.GetAssetPath("ape-arm64.elf"); private static readonly string apeX86_64Url = "https://cosmo.zip/pub/cosmos/bin/ape-x86_64.elf"; - private static readonly string apeX86_64 = GetAssetPath("ape-x86_64.elf"); + private static readonly string apeX86_64 = LLMUnitySetup.GetAssetPath("ape-x86_64.elf"); [HideInInspector] public static float binariesProgress = 1; [HideInInspector] public float modelProgress = 1; @@ -65,7 +65,7 @@ private static async Task SetupBinaries() string serverZip = Path.Combine(Application.temporaryCachePath, "llamafile.zip"); await LLMUnitySetup.DownloadFile(serverZipUrl, serverZip, true, false, null, SetBinariesProgress); binariesDone += 1; - LLMUnitySetup.ExtractZip(serverZip, GetAssetPath()); + LLMUnitySetup.ExtractZip(serverZip, LLMUnitySetup.GetAssetPath()); File.Delete(serverZip); binariesDone += 1; } @@ -82,7 +82,7 @@ public void DownloadModel() // download default model and disable model editor properties until the model is set modelProgress = 0; string modelName = Path.GetFileName(modelUrl).Split("?")[0]; - string modelPath = GetAssetPath(modelName); + string modelPath = LLMUnitySetup.GetAssetPath(modelName); Task downloadTask = LLMUnitySetup.DownloadFile(modelUrl, modelPath, false, false, SetModel, SetModelProgress); } @@ -95,7 +95,7 @@ public async Task SetModel(string path) { // set the model and enable the model editor properties modelCopyProgress = 0; - model = await LLMUnitySetup.AddAsset(path, GetAssetPath()); + model = await LLMUnitySetup.AddAsset(path, LLMUnitySetup.GetAssetPath()); EditorUtility.SetDirty(this); modelCopyProgress = 1; } @@ -104,7 +104,7 @@ public async Task SetLora(string path) { // set the lora and enable the model editor properties modelCopyProgress = 0; - lora = await LLMUnitySetup.AddAsset(path, GetAssetPath()); + lora = await LLMUnitySetup.AddAsset(path, LLMUnitySetup.GetAssetPath()); EditorUtility.SetDirty(this); modelCopyProgress = 1; } @@ -231,13 +231,13 @@ private void StartLLMServer() // Start the LLM server in a cross-platform way if (model == "") throw new Exception("No model file provided!"); - string modelPath = GetAssetPath(model); + string modelPath = LLMUnitySetup.GetAssetPath(model); if (!File.Exists(modelPath)) throw new Exception($"File {modelPath} not found!"); string loraPath = ""; if (lora != "") { - loraPath = GetAssetPath(lora); + loraPath = LLMUnitySetup.GetAssetPath(lora); if (!File.Exists(loraPath)) throw new Exception($"File {loraPath} not found!"); } diff --git a/Runtime/LLMClient.cs b/Runtime/LLMClient.cs index 58be8420..de51721f 100644 --- a/Runtime/LLMClient.cs +++ b/Runtime/LLMClient.cs @@ -135,13 +135,6 @@ public async Task SetPrompt(string newPrompt, bool clearChat = true) nKeep = -1; await InitPrompt(clearChat); } - - protected static string GetAssetPath(string relPath = "") - { - // Path to store llm server binaries and models - return Path.Combine(Application.streamingAssetsPath, relPath).Replace('\\', '/'); - } - private async Task InitNKeep() { if (setNKeepToPrompt && nKeep == -1) @@ -163,7 +156,7 @@ private void InitGrammar() { if (grammar != null && grammar != "") { - grammarString = File.ReadAllText(GetAssetPath(grammar)); + grammarString = File.ReadAllText(LLMUnitySetup.GetAssetPath(grammar)); } } @@ -175,7 +168,7 @@ private void SetNKeep(List tokens) public async void SetGrammar(string path) { - grammar = await LLMUnitySetup.AddAsset(path, GetAssetPath()); + grammar = await LLMUnitySetup.AddAsset(path, LLMUnitySetup.GetAssetPath()); } private string RoleString(string role) diff --git a/Runtime/LLMUnitySetup.cs b/Runtime/LLMUnitySetup.cs index 4fa214a1..fd19b6f2 100644 --- a/Runtime/LLMUnitySetup.cs +++ b/Runtime/LLMUnitySetup.cs @@ -73,6 +73,12 @@ public static void makeExecutable(string path) } } + public static string GetAssetPath(string relPath = "") + { + // Path to store llm server binaries and models + return Path.Combine(Application.streamingAssetsPath, relPath).Replace('\\', '/'); + } + #if UNITY_EDITOR public class DownloadStatus { From 1d39030a81c5d7ef72fc148ce838ee81ae5e37da Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Sun, 11 Feb 2024 18:27:55 +0200 Subject: [PATCH 093/161] add embedding GameObject UI and download model functionality --- Editor/EmbeddingEditor.cs | 35 ++++++++ .../EmbeddingEditor.cs.meta | 2 +- Runtime/{Embedder.cs => Embedding.cs} | 87 +++++++++++++++++++ Runtime/Embedding.cs.meta | 11 +++ 4 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 Editor/EmbeddingEditor.cs rename Runtime/Embedder.cs.meta => Editor/EmbeddingEditor.cs.meta (83%) rename Runtime/{Embedder.cs => Embedding.cs} (83%) create mode 100644 Runtime/Embedding.cs.meta diff --git a/Editor/EmbeddingEditor.cs b/Editor/EmbeddingEditor.cs new file mode 100644 index 00000000..d302a21d --- /dev/null +++ b/Editor/EmbeddingEditor.cs @@ -0,0 +1,35 @@ +using UnityEditor; + +namespace LLMUnity +{ + [CustomEditor(typeof(Embedding))] + public class EmbeddingEditor : Editor + { + + void ShowProgress(float progress, string progressText) + { + if (progress != 1) EditorGUI.ProgressBar(EditorGUILayout.GetControlRect(), progress, progressText); + } + + public override void OnInspectorGUI() + { + Embedding embdeddingScript = (Embedding)target; + SerializedObject embdeddingScriptSO = new SerializedObject(embdeddingScript); + embdeddingScriptSO.Update(); + + embdeddingScriptSO.ApplyModifiedProperties(); + string[] options = new string[embdeddingScript.options.Length]; + for (int i = 0; i < embdeddingScript.options.Length; i++) + { + options[i] = embdeddingScript.options[i].Item1; + } + + int newIndex = EditorGUILayout.Popup("Model", embdeddingScript.SelectedOption, options); + if (newIndex != embdeddingScript.SelectedOption) + { + embdeddingScript.SelectModel(newIndex); + } + ShowProgress(embdeddingScript.downloadProgress, "Downloading model"); + } + } +} diff --git a/Runtime/Embedder.cs.meta b/Editor/EmbeddingEditor.cs.meta similarity index 83% rename from Runtime/Embedder.cs.meta rename to Editor/EmbeddingEditor.cs.meta index 1f5d40cd..64f05585 100644 --- a/Runtime/Embedder.cs.meta +++ b/Editor/EmbeddingEditor.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 3ecc363da4be40d7faffc48eaf542530 +guid: 2e1f1aacc96ed15478ebb263a2200751 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Runtime/Embedder.cs b/Runtime/Embedding.cs similarity index 83% rename from Runtime/Embedder.cs rename to Runtime/Embedding.cs index a9b327de..4ea5d995 100644 --- a/Runtime/Embedder.cs +++ b/Runtime/Embedding.cs @@ -15,6 +15,8 @@ using System.IO; using System.Runtime.Serialization; using System.IO.Compression; +using System.Reflection; +using System.Threading.Tasks; namespace LLMUnity { @@ -438,6 +440,21 @@ public static EmbeddingModel Model(EmbeddingModelSkeleton skeleton) return models[skeleton]; } + public static async Task<(string, string)> DownloadUndreamAI(string modelUrl, Callback progresscallback = null) + { + string modelBasename = Path.GetFileName(modelUrl).Split("?")[0]; + string modelName = modelBasename.Replace(".zip", ""); + string dirname = LLMUnitySetup.GetAssetPath(modelName); + if (!Directory.Exists(dirname)) + { + string modelZip = Path.Combine(Application.temporaryCachePath, modelBasename); + await LLMUnitySetup.DownloadFile(modelUrl, modelZip, true, false, null, progresscallback); + LLMUnitySetup.ExtractZip(modelZip, dirname); + File.Delete(modelZip); + } + return (Path.Combine(dirname, modelName + ".sentis"), Path.Combine(dirname, modelName + ".tokenizer.json")); + } + public static EmbeddingModel BGEModel(string modelPath, string tokenizerPath, BackendType backend = BackendType.CPU) { return Model(new EmbeddingModelSkeleton(modelPath, tokenizerPath, backend, "sentence_embedding", false, 384)); @@ -448,9 +465,79 @@ public static EmbeddingModel MiniLMModel(string modelPath, string tokenizerPath, return Model(new EmbeddingModelSkeleton(modelPath, tokenizerPath, backend, "last_hidden_state", true, 384)); } + public static async Task BGESmallModel(BackendType backend = BackendType.CPU, Callback progresscallback = null) + { + string modelUrl = "https://huggingface.co/undreamai/bge-small-en-v1.5-sentis/resolve/main/bge-small-en-v1.5.zip?download=true"; + (string modelPath, string tokenizerPath) = await DownloadUndreamAI(modelUrl, progresscallback); + return BGEModel(modelPath, tokenizerPath, backend); + } + + public static async Task BGEBaseModel(BackendType backend = BackendType.CPU, Callback progresscallback = null) + { + string modelUrl = "https://huggingface.co/undreamai/bge-base-en-v1.5-sentis/resolve/main/bge-base-en-v1.5.zip?download=true"; + (string modelPath, string tokenizerPath) = await DownloadUndreamAI(modelUrl, progresscallback); + return BGEModel(modelPath, tokenizerPath, backend); + } + + public static async Task MiniLMModel(BackendType backend = BackendType.CPU, Callback progresscallback = null) + { + string modelUrl = "https://huggingface.co/undreamai/all-MiniLM-L6-v2-sentis/resolve/main/all-MiniLM-L6-v2.zip?download=true"; + (string modelPath, string tokenizerPath) = await DownloadUndreamAI(modelUrl, progresscallback); + return MiniLMModel(modelPath, tokenizerPath, backend); + } + public static int Count() { return models.Count(); } } + + public class Embedding : MonoBehaviour + { + public string Model = ""; + public bool GPU = false; + public int SelectedOption; + + [HideInInspector] public float downloadProgress = 1; + [HideInInspector] public EmbeddingModel embedding = null; + public readonly (string, string)[] options = new (string, string)[]{ + ("None", null), + ("bge-small-en-v1.5", "BGESmallModel"), + ("bge-base-en-v1.5", "BGEBaseModel"), + ("all-MiniLM-L6-v2", "MiniLMModel") + }; + + public void Awake() + { + SelectModel(SelectedOption); + } + + public async void SelectModel(int optionIndex) + { + SelectedOption = optionIndex; + string methodName = options[SelectedOption].Item2; + if (methodName != null) + { + Type type = typeof(ModelManager); + MethodInfo method = type.GetMethod(methodName); + object[] arguments = { GPU? BackendType.GPUCompute: BackendType.CPU, (Callback) SetDownloadProgress }; + embedding = await (Task) method.Invoke(null, arguments); + } + } + + public void SetDownloadProgress(float progress) + { + downloadProgress = progress; + } + + public EmbeddingModel GetModel() + { + return embedding; + } + + public void OnDestroy() + { + embedding?.Destroy(); + } + } } diff --git a/Runtime/Embedding.cs.meta b/Runtime/Embedding.cs.meta new file mode 100644 index 00000000..81c82128 --- /dev/null +++ b/Runtime/Embedding.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 66e2adadc5fb3e3a5862391f8dd49844 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 40bd84548961030ab36a93f5d95eab18105e9757 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Sun, 11 Feb 2024 18:28:32 +0200 Subject: [PATCH 094/161] update sample with the Embedding GameObject --- Samples~/HamletSearch/HamletSearch.cs | 24 ++++++++---------------- Samples~/HamletSearch/Scene.unity | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/Samples~/HamletSearch/HamletSearch.cs b/Samples~/HamletSearch/HamletSearch.cs index fabc3f24..01c812db 100644 --- a/Samples~/HamletSearch/HamletSearch.cs +++ b/Samples~/HamletSearch/HamletSearch.cs @@ -4,26 +4,23 @@ using Debug = UnityEngine.Debug; using System.Text.RegularExpressions; using LLMUnity; -using System; class HamletSearch : MonoBehaviour { - EmbeddingModel embedder; + public Embedding embedding; public bool fullPlay; public TextAsset gutenbergText; - public void OnEnable() - { - embedder = ModelManager.BGEModel( - "Assets/StreamingAssets/bge-small-en-v1.5.sentis", - "Assets/StreamingAssets/bge-small-en-v1.5.tokenizer.json" - ); - } - void Start() { + EmbeddingModel model = embedding.GetModel(); + if (model == null) + { + throw new System.Exception("Please select an embedding model in the HamletSearch GameObject!"); + } + Dictionary> hamlet = ReadGutenbergFile(gutenbergText.text); - DialogueManager dialogueManager = new DialogueManager(embedder); + DialogueManager dialogueManager = new DialogueManager(model); Stopwatch stopwatch = new Stopwatch(); float elapsedTotal = 0; @@ -117,9 +114,4 @@ void Start() Debug.Log($"{numLines} lines, {numWords} words"); return messages; } - - public void OnDisable() - { - embedder.Destroy(); - } } diff --git a/Samples~/HamletSearch/Scene.unity b/Samples~/HamletSearch/Scene.unity index 25a1e1ef..d6edc468 100644 --- a/Samples~/HamletSearch/Scene.unity +++ b/Samples~/HamletSearch/Scene.unity @@ -319,6 +319,7 @@ GameObject: m_Component: - component: {fileID: 1842083046} - component: {fileID: 1842083045} + - component: {fileID: 1842083047} m_Layer: 0 m_Name: HamletSearch m_TagString: Untagged @@ -338,6 +339,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 8813eb3f4b7c900538f904cbd42e0a7f, type: 3} m_Name: m_EditorClassIdentifier: + embedding: {fileID: 1842083047} fullPlay: 0 gutenbergText: {fileID: 4900000, guid: be0ffe8c7b44139218ffd530749f1644, type: 3} --- !u!4 &1842083046 @@ -355,6 +357,21 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1842083047 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1842083044} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 66e2adadc5fb3e3a5862391f8dd49844, type: 3} + m_Name: + m_EditorClassIdentifier: + Model: + GPU: 0 + SelectedOption: 1 --- !u!1660057539 &9223372036854775807 SceneRoots: m_ObjectHideFlags: 0 From 2181a0734e51e9ed274420434f6ee42df92e85b8 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Mon, 12 Feb 2024 11:21:39 +0200 Subject: [PATCH 095/161] rename Search -> SearchMethods, Dialogue -> SearchEngine, DialogueManager -> Dialogue --- Runtime/Dialogue.cs | 472 +++-------------------- Runtime/Search.cs | 474 +++++++++++------------- Runtime/SearchMethods.cs | 392 ++++++++++++++++++++ Runtime/SearchMethods.cs.meta | 11 + Samples~/HamletSearch/HamletSearch.cs | 4 +- Tests/Runtime/TestDialogue.cs | 243 +----------- Tests/Runtime/TestSearch.cs | 296 ++++++++++----- Tests/Runtime/TestSearchMethods.cs | 146 ++++++++ Tests/Runtime/TestSearchMethods.cs.meta | 11 + 9 files changed, 1037 insertions(+), 1012 deletions(-) create mode 100644 Runtime/SearchMethods.cs create mode 100644 Runtime/SearchMethods.cs.meta create mode 100644 Tests/Runtime/TestSearchMethods.cs create mode 100644 Tests/Runtime/TestSearchMethods.cs.meta diff --git a/Runtime/Dialogue.cs b/Runtime/Dialogue.cs index c269462f..cebb86e5 100644 --- a/Runtime/Dialogue.cs +++ b/Runtime/Dialogue.cs @@ -10,375 +10,20 @@ namespace LLMUnity { - [DataContract] - public class Sentence - { - [DataMember] - public int phraseId; - [DataMember] - public int startIndex; - [DataMember] - public int endIndex; - - public Sentence(int phraseId, int startIndex, int endIndex) - { - this.phraseId = phraseId; - this.startIndex = startIndex; - this.endIndex = endIndex; - } - } - - [DataContract] - public class Phrase - { - [DataMember] - public string text; - [DataMember] - public List sentenceIds; - - public Phrase(string text) : this(text, new List()) {} - - public Phrase(string text, List sentenceIds) - { - this.text = text; - this.sentenceIds = sentenceIds; - } - } - - [DataContract] - public class SentenceSplitter - { - public static char[] DefaultDelimiters = new char[] { '.', '!', ':', ';', '?', '\n', '\r', }; - [DataMember] - char[] delimiters; - [DataMember] - bool trimSentences = true; - - public SentenceSplitter(char[] delimiters, bool trimSentences = true) - { - this.delimiters = delimiters; - this.trimSentences = trimSentences; - } - - public SentenceSplitter() : this(DefaultDelimiters, true) {} - - public List<(int, int)> Split(string input) - { - List<(int, int)> indices = new List<(int, int)>(); - int startIndex = 0; - bool sawDelimiter = true; - for (int i = 0; i < input.Length; i++) - { - if (sawDelimiter && trimSentences) - { - while (char.IsWhiteSpace(input[i]) && i < input.Length - 1) i++; - startIndex = i; - sawDelimiter = false; - } - if (delimiters.Contains(input[i]) || i == input.Length - 1) - { - int endIndex = i; - if (i == input.Length - 1 && trimSentences) - { - while (char.IsWhiteSpace(input[endIndex]) && endIndex > startIndex) endIndex--; - } - if (endIndex > startIndex || !trimSentences || (trimSentences && !char.IsWhiteSpace(input[startIndex]) && !delimiters.Contains(input[startIndex]))) - { - indices.Add((startIndex, endIndex)); - } - startIndex = i + 1; - sawDelimiter = true; - } - } - return indices; - } - - public static string[] IndicesToSentences(string input, List<(int, int)> indices) - { - string[] sentences = new string[indices.Count]; - for (int i = 0; i < indices.Count; i++) - { - sentences[i] = input.Substring(indices[i].Item1, indices[i].Item2 - indices[i].Item1 + 1); - } - return sentences; - } - } - [DataContract] public class Dialogue { - [DataMember] - public string Title { get; private set; } - [DataMember] - public string Actor { get; private set; } - - [DataMember] - SortedDictionary phrases; - [DataMember] - SortedDictionary sentences; - [DataMember] - int nextPhraseId = 0; - [DataMember] - int nextSentenceId = 0; - [DataMember] - SentenceSplitter sentenceSplitter; - ANNModelSearch search; - - public Dialogue(string actor = "", string title = "", EmbeddingModel embedder = null) - { - Actor = actor; - Title = title; - phrases = new SortedDictionary(); - sentences = new SortedDictionary(); - sentenceSplitter = new SentenceSplitter(); - search = null; - if (embedder != null) - { - search = new ANNModelSearch(embedder); - } - } - - public void SetSentenceSplitting(char[] delimiters, bool trimSentences = true) - { - if (sentences.Count > 0) throw new Exception("Sentence splitting can't change when there are phrases in the Dialogue"); - if (delimiters == null) - { - sentenceSplitter = null; - } - else - { - sentenceSplitter = new SentenceSplitter(delimiters, trimSentences); - } - } - - public void SetNoSentenceSplitting() - { - SetSentenceSplitting(null); - } - - public void SetSearch(ANNModelSearch search) - { - this.search = search; - } - - public void SetEmbedder(EmbeddingModel embedder) - { - search.SetEmbedder(embedder); - } - - public string GetPhrase(Sentence sentence) - { - return phrases[sentence.phraseId].text; - } - - public string GetSentence(Sentence sentence) - { - return GetPhrase(sentence).Substring(sentence.startIndex, sentence.endIndex - sentence.startIndex + 1); - } - - public void Add(string text) - { - List<(int, int)> subindices; - if (sentenceSplitter == null) subindices = new List<(int, int)> { (0, text.Length - 1) }; - else subindices = sentenceSplitter.Split(text); - - int phraseId = nextPhraseId++; - Phrase phrase = new Phrase(text); - phrases[phraseId] = phrase; - foreach ((int startIndex, int endIndex) in subindices) - { - int sentenceId = nextSentenceId++; - Sentence sentence = new Sentence(phraseId, startIndex, endIndex); - sentences[sentenceId] = sentence; - phrase.sentenceIds.Add(sentenceId); - search?.Add(sentenceId, GetSentence(sentence)); - } - } - - public int Remove(string text) - { - List removePhraseIds = new List(); - foreach (var phrasePair in phrases) - { - Phrase phrase = phrasePair.Value; - if (phrase.text == text) - { - foreach (int sentenceId in phrase.sentenceIds) - { - sentences.Remove(sentenceId); - search?.Remove(sentenceId); - } - removePhraseIds.Add(phrasePair.Key); - } - } - foreach (int phraseId in removePhraseIds) - { - phrases.Remove(phraseId); - } - return removePhraseIds.Count; - } - - public List GetPhrases() - { - List phraseTexts = new List(); - foreach (Phrase phrase in phrases.Values) - { - phraseTexts.Add(phrase.text); - } - return phraseTexts; - } - - public List GetSentences() - { - List allSentences = new List(); - foreach (Sentence sentence in sentences.Values) - { - allSentences.Add(GetSentence(sentence)); - } - return allSentences; - } - - public string[] Search(string queryString, int k, out float[] distances, bool returnSentences = false) - { - return Search(search.Encode(queryString), k, out distances, returnSentences); - } - - public string[] Search(float[] encoding, int k, out float[] distances, bool returnSentences = false) - { - if (search == null) throw new Exception("No search method defined!"); - - if (returnSentences) - { - int[] keys = search.SearchKey(encoding, k, out distances); - string[] result = new string[keys.Length]; - for (int i = 0; i < keys.Length; i++) - { - Sentence sentence = sentences[keys[i]]; - result[i] = returnSentences ? GetSentence(sentence) : GetPhrase(sentence); - } - return result; - } - else - { - List phraseKeys; - List phraseDistances; - int currK = k; - do - { - int[] keys = search.SearchKey(encoding, currK, out float[] iterDistances); - phraseDistances = new List(); - phraseKeys = new List(); - for (int i = 0; i < keys.Length; i++) - { - int phraseId = sentences[keys[i]].phraseId; - if (phraseKeys.Contains(phraseId)) continue; - phraseKeys.Add(phraseId); - phraseDistances.Add(iterDistances[i]); - } - if (currK >= search.Count()) break; - currK *= 2; - } - while (phraseKeys.Count() < k); - - distances = phraseDistances.ToArray(); - string[] result = new string[phraseKeys.Count]; - for (int i = 0; i < phraseKeys.Count; i++) - result[i] = phrases[phraseKeys[i]].text; - return result; - } - } - - public string[] Search(float[] encoding, int k, bool returnSentences = false) - { - return Search(encoding, k, out float[] distances, returnSentences); - } - - public string[] Search(string queryString, int k, bool returnSentences = false) - { - return Search(queryString, k, out float[] distances, returnSentences); - } - - public string[] SearchPhrases(string queryString, int k, out float[] distances) - { - return Search(queryString, k, out distances, false); - } - - public string[] SearchPhrases(string queryString, int k) - { - return SearchPhrases(queryString, k, out float[] distances); - } - - public string[] SearchSentences(string queryString, int k, out float[] distances) - { - return Search(queryString, k, out distances, true); - } - - public string[] SearchSentences(string queryString, int k) - { - return SearchSentences(queryString, k, out float[] distances); - } - - public int NumPhrases() - { - return phrases.Count; - } - - public int NumSentences() - { - return sentences.Count; - } - - public void Save(string filePath, string dirname = "") - { - using (FileStream stream = new FileStream(filePath, FileMode.Create)) - using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Create)) - { - Save(archive, dirname); - } - } - - public static string GetDialoguePath(string dirname) - { - return Path.Combine(dirname, "Dialogue.json"); - } - - public void Save(ZipArchive archive, string dirname) - { - Saver.Save(this, archive, GetDialoguePath(dirname)); - search.Save(archive, dirname); - } - - public static Dialogue Load(string filePath, string dirname) - { - using (FileStream stream = new FileStream(filePath, FileMode.Open)) - using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read)) - { - return Load(archive, dirname); - } - } - - public static Dialogue Load(ZipArchive archive, string dirname) - { - Dialogue dialogue = Saver.Load(archive, GetDialoguePath(dirname)); - ANNModelSearch search = ANNModelSearch.Load(archive, dirname); - dialogue.SetSearch(search); - return dialogue; - } - } - - [DataContract] - public class DialogueManager - { - Dictionary> dialogues; + Dictionary> dialogueParts; [DataMember] char[] delimiters = SentenceSplitter.DefaultDelimiters; [DataMember] bool trimSentences = true; [DataMember] EmbeddingModel embedder; - public DialogueManager(EmbeddingModel embedder = null) + + public Dialogue(EmbeddingModel embedder) { - dialogues = new Dictionary>(); + dialogueParts = new Dictionary>(); this.embedder = embedder; } @@ -393,28 +38,19 @@ public void SetNoSentenceSplitting() SetSentenceSplitting(null); } - public void AddDialogue(string actor, string title, Dialogue dialogue) - { - if (!dialogues.ContainsKey(actor)) - { - dialogues[actor] = new Dictionary(); - } - dialogues[actor][title] = dialogue; - } - public void Add(string actor, string title, string text) { - if (!dialogues.ContainsKey(actor) || !dialogues[actor].ContainsKey(title)) + if (!dialogueParts.ContainsKey(actor) || !dialogueParts[actor].ContainsKey(title)) { - Dialogue dialogue = new Dialogue(actor, title, embedder); - dialogue.SetSentenceSplitting(delimiters, trimSentences); - if (!dialogues.ContainsKey(actor)) + SearchEngine search = new SearchEngine(embedder); + search.SetSentenceSplitting(delimiters, trimSentences); + if (!dialogueParts.ContainsKey(actor)) { - dialogues[actor] = new Dictionary(); + dialogueParts[actor] = new Dictionary(); } - dialogues[actor][title] = dialogue; + dialogueParts[actor][title] = search; } - dialogues[actor][title].Add(text); + dialogueParts[actor][title].Add(text); } public void Add(string actor, string text) @@ -424,21 +60,21 @@ public void Add(string actor, string text) public int Remove(string actor, string title, string text) { - List dialogues = Filter(actor, title); + List dialogueParts = Filter(actor, title); int removed = 0; - foreach (Dialogue dialogue in dialogues) + foreach (SearchEngine dialogue in dialogueParts) { removed += dialogue.Remove(text); } return removed; } - public List Filter(string actor = null, string title = null) + public List Filter(string actor = null, string title = null) { - List filtering = new List(); - foreach ((string actorName, Dictionary actorDialogues) in dialogues) + List filtering = new List(); + foreach ((string actorName, Dictionary actorDialogues) in dialogueParts) { - foreach ((string titleName, Dialogue dialogue) in actorDialogues) + foreach ((string titleName, SearchEngine dialogue) in actorDialogues) { if ((actor == null || actor == actorName) && (title == null || title == titleName)) { @@ -451,9 +87,9 @@ public List Filter(string actor = null, string title = null) public string[] Get(string actor = null, string title = null, bool returnSentences = false) { - List dialogues = Filter(actor, title); + List dialogueParts = Filter(actor, title); List result = new List(); - foreach (Dialogue dialogue in dialogues) + foreach (SearchEngine dialogue in dialogueParts) { result.AddRange(returnSentences ? dialogue.GetSentences() : dialogue.GetPhrases()); } @@ -472,8 +108,7 @@ public string[] GetSentences(string actor = null, string title = null) public string[] Search(string queryString, int k, out float[] distances, string actor = null, string title = null, bool returnSentences = false) { - if (embedder == null) throw new Exception("No search method defined!"); - List dialogues = Filter(actor, title); + List dialogueParts = Filter(actor, title); ConcurrentBag<(string, float)> resultPairs = new ConcurrentBag<(string, float)>(); TensorFloat encodingTensor = embedder.Encode(queryString); @@ -481,7 +116,7 @@ public string[] Search(string queryString, int k, out float[] distances, string float[] encoding = encodingTensor.ToReadOnlyArray(); Task.Run(() => { - Parallel.ForEach(dialogues, dialogue => + Parallel.ForEach(dialogueParts, dialogue => { string[] searchResults = dialogue.Search(encoding, k, out float[] searchDistances, returnSentences); for (int i = 0; i < searchResults.Length; i++) @@ -531,8 +166,8 @@ public string[] SearchSentences(string queryString, int k, string actor = null, public int NumPhrases(string actor = null, string title = null) { int num = 0; - List dialogues = Filter(actor, title); - foreach (Dialogue dialogue in dialogues) + List dialogueParts = Filter(actor, title); + foreach (SearchEngine dialogue in dialogueParts) { num += dialogue.NumPhrases(); } @@ -542,21 +177,22 @@ public int NumPhrases(string actor = null, string title = null) public int NumSentences(string actor = null, string title = null) { int num = 0; - List dialogues = Filter(actor, title); - foreach (Dialogue dialogue in dialogues) + List dialogueParts = Filter(actor, title); + foreach (SearchEngine dialogue in dialogueParts) { num += dialogue.NumSentences(); } return num; } - public static string GetDialogueManagerPath(string dirname) + public static string GetDialoguePath(string dirname) { - return Path.Combine(dirname, "DialogueManager.json"); + return Path.Combine(dirname, "Dialogue.json"); } - public static string GetDialoguesPath(string dirname) + + public static string GetDialogueEntriesPath(string dirname) { - return Path.Combine(dirname, "Dialogues.json"); + return Path.Combine(dirname, "DialogueEntries.csv"); } public void Save(string filePath, string dirname = "") @@ -570,55 +206,63 @@ public void Save(string filePath, string dirname = "") public void Save(ZipArchive archive, string dirname = "") { - Saver.Save(this, archive, GetDialogueManagerPath(dirname)); + Saver.Save(this, archive, GetDialoguePath(dirname)); embedder.Save(archive, dirname); - List dialogueDirs = new List(); - foreach ((string actorName, Dictionary actorDialogues) in dialogues) + List dialoguePartLines = new List(); + foreach ((string actorName, Dictionary actorDialogues) in dialogueParts) { - foreach ((string titleName, Dialogue dialogue) in actorDialogues) + foreach ((string titleName, SearchEngine dialogue) in actorDialogues) { string basedir = $"{dirname}/Dialogues/{Saver.EscapeFileName(actorName)}/{Saver.EscapeFileName(titleName)}"; dialogue.Save(archive, basedir); - dialogueDirs.Add(basedir); + + dialoguePartLines.Add(actorName); + dialoguePartLines.Add(titleName); + dialoguePartLines.Add(basedir); } } - ZipArchiveEntry dialoguesEntry = archive.CreateEntry(GetDialoguesPath(dirname)); + ZipArchiveEntry dialoguesEntry = archive.CreateEntry(GetDialogueEntriesPath(dirname)); using (StreamWriter writer = new StreamWriter(dialoguesEntry.Open())) { - writer.Write(string.Join("\n", dialogueDirs)); + foreach (string line in dialoguePartLines) + { + writer.WriteLine(line); + } } } - public static DialogueManager Load(string filePath, string dirname = "") + public static Dialogue Load(string filePath, string dirname = "") { using (FileStream stream = new FileStream(filePath, FileMode.Open)) using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read)) { - DialogueManager dialogueManager = Saver.Load(archive, GetDialogueManagerPath(dirname)); + Dialogue dialogue = Saver.Load(archive, GetDialoguePath(dirname)); - dialogueManager.embedder = EmbeddingModel.Load(archive, dirname); + dialogue.embedder = EmbeddingModel.Load(archive, dirname); - ZipArchiveEntry dialoguesEntry = archive.GetEntry(GetDialoguesPath(dirname)); + ZipArchiveEntry dialoguesEntry = archive.GetEntry(GetDialogueEntriesPath(dirname)); List dialogueDirs = new List(); - dialogueManager.dialogues = new Dictionary>(); + dialogue.dialogueParts = new Dictionary>(); using (StreamReader reader = new StreamReader(dialoguesEntry.Open())) { string line; while ((line = reader.ReadLine()) != null) { - dialogueDirs.Add(line); + string actor = line; + string title = reader.ReadLine(); + string basedir = reader.ReadLine(); + + if (!dialogue.dialogueParts.ContainsKey(actor)) + { + dialogue.dialogueParts[actor] = new Dictionary(); + } + dialogue.dialogueParts[actor][title] = SearchEngine.Load(archive, basedir); } } - - foreach (string basedir in dialogueDirs) - { - Dialogue dialogue = Dialogue.Load(archive, basedir); - dialogueManager.AddDialogue(dialogue.Actor, dialogue.Title, dialogue); - } - return dialogueManager; + return dialogue; } } } diff --git a/Runtime/Search.cs b/Runtime/Search.cs index 8c04af69..958fe7b4 100644 --- a/Runtime/Search.cs +++ b/Runtime/Search.cs @@ -1,378 +1,338 @@ -using System; using System.Collections.Generic; +using System; using System.Linq; -using Unity.Sentis; -using Cloud.Unum.USearch; using System.Runtime.Serialization; using System.IO; using System.IO.Compression; -using System.Reflection; - namespace LLMUnity { [DataContract] - public class ModelSearchBase + public class Sentence { - protected EmbeddingModel embedder; [DataMember] - protected Dictionary embeddings; + public int phraseId; + [DataMember] + public int startIndex; + [DataMember] + public int endIndex; - public ModelSearchBase(EmbeddingModel embedder) + public Sentence(int phraseId, int startIndex, int endIndex) { - embeddings = new Dictionary(); - this.embedder = embedder; + this.phraseId = phraseId; + this.startIndex = startIndex; + this.endIndex = endIndex; } + } - public void SetEmbedder(EmbeddingModel embedder) + [DataContract] + public class Phrase + { + [DataMember] + public string text; + [DataMember] + public List sentenceIds; + + public Phrase(string text) : this(text, new List()) {} + + public Phrase(string text, List sentenceIds) { - this.embedder = embedder; + this.text = text; + this.sentenceIds = sentenceIds; } + } - public float[] Encode(string inputString) + [DataContract] + public class SentenceSplitter + { + public static char[] DefaultDelimiters = new char[] { '.', '!', ':', ';', '?', '\n', '\r', }; + [DataMember] + char[] delimiters; + [DataMember] + bool trimSentences = true; + + public SentenceSplitter(char[] delimiters, bool trimSentences = true) { - TensorFloat encoding = embedder.Encode(inputString); - encoding.MakeReadable(); - return encoding.ToReadOnlyArray(); + this.delimiters = delimiters; + this.trimSentences = trimSentences; } - public float[][] Encode(List inputStrings, int batchSize = 64) + public SentenceSplitter() : this(DefaultDelimiters, true) {} + + public List<(int, int)> Split(string input) { - List inputEmbeddings = new List(); - for (int i = 0; i < inputStrings.Count; i += batchSize) + List<(int, int)> indices = new List<(int, int)>(); + int startIndex = 0; + bool sawDelimiter = true; + for (int i = 0; i < input.Length; i++) { - int takeCount = Math.Min(batchSize, inputStrings.Count - i); - List batch = new List(inputStrings.GetRange(i, takeCount)); - foreach (TensorFloat tensor in embedder.Split(embedder.Encode(batch))) + if (sawDelimiter && trimSentences) { - tensor.MakeReadable(); - inputEmbeddings.Add(tensor.ToReadOnlyArray()); + while (char.IsWhiteSpace(input[i]) && i < input.Length - 1) i++; + startIndex = i; + sawDelimiter = false; + } + if (delimiters.Contains(input[i]) || i == input.Length - 1) + { + int endIndex = i; + if (i == input.Length - 1 && trimSentences) + { + while (char.IsWhiteSpace(input[endIndex]) && endIndex > startIndex) endIndex--; + } + if (endIndex > startIndex || !trimSentences || (trimSentences && !char.IsWhiteSpace(input[startIndex]) && !delimiters.Contains(input[startIndex]))) + { + indices.Add((startIndex, endIndex)); + } + startIndex = i + 1; + sawDelimiter = true; } } - if (inputStrings.Count != inputEmbeddings.Count) - { - throw new Exception($"Number of computed embeddings ({inputEmbeddings.Count}) different than inputs ({inputStrings.Count})"); - } - return inputEmbeddings.ToArray(); + return indices; } - public virtual string[] Search(float[] encoding, int k) + public static string[] IndicesToSentences(string input, List<(int, int)> indices) { - return Search(encoding, k, out float[] distances); - } - - public virtual string[] Search(string queryString, int k) - { - return Search(queryString, k, out float[] distances); - } - - public static float DotProduct(float[] vector1, float[] vector2) - { - if (vector1.Length != vector2.Length) + string[] sentences = new string[indices.Count]; + for (int i = 0; i < indices.Count; i++) { - throw new ArgumentException("Vector lengths must be equal for dot product calculation"); + sentences[i] = input.Substring(indices[i].Item1, indices[i].Item2 - indices[i].Item1 + 1); } - float result = 0; - for (int i = 0; i < vector1.Length; i++) - { - result += vector1[i] * vector2[i]; - } - return result; + return sentences; } + } - public static float InverseDotProduct(float[] vector1, float[] vector2) + [DataContract] + public class SearchEngine + { + [DataMember] + SortedDictionary phrases; + [DataMember] + SortedDictionary sentences; + [DataMember] + int nextPhraseId = 0; + [DataMember] + int nextSentenceId = 0; + [DataMember] + SentenceSplitter sentenceSplitter; + ANNModelSearch searchMethod; + + public SearchEngine(EmbeddingModel embedder) { - return 1 - DotProduct(vector1, vector2); + phrases = new SortedDictionary(); + sentences = new SortedDictionary(); + sentenceSplitter = new SentenceSplitter(); + searchMethod = new ANNModelSearch(embedder); } - public static float[] InverseDotProduct(float[] vector1, float[][] vector2) + public void SetSentenceSplitting(char[] delimiters, bool trimSentences = true) { - float[] results = new float[vector2.Length]; - for (int i = 0; i < vector2.Length; i++) + if (sentences.Count > 0) throw new Exception("Sentence splitting can't change when there are phrases in the Search"); + if (delimiters == null) { - results[i] = InverseDotProduct(vector1, vector2[i]); + sentenceSplitter = null; } - return results; - } - - public virtual string[] Search(float[] encoding, int k, out float[] distances) - { - float[] unsortedDistances = InverseDotProduct(encoding, embeddings.Values.ToArray()); - - var sortedLists = embeddings.Keys.Zip(unsortedDistances, (first, second) => new { First = first, Second = second }) - .OrderBy(item => item.Second) - .ToList(); - int kmax = k == -1 ? sortedLists.Count : Math.Min(k, sortedLists.Count); - string[] results = new string[kmax]; - distances = new float[kmax]; - for (int i = 0; i < kmax; i++) + else { - results[i] = sortedLists[i].First; - distances[i] = sortedLists[i].Second; + sentenceSplitter = new SentenceSplitter(delimiters, trimSentences); } - return results; } - public virtual string[] Search(string queryString, int k, out float[] distances) + public void SetNoSentenceSplitting() { - return Search(Encode(queryString), k, out distances); + SetSentenceSplitting(null); } - public virtual int Count() + public void SetSearchMethod(ANNModelSearch searchMethod) { - return embeddings.Count; + this.searchMethod = searchMethod; } - public virtual void Save(string filePath, string dirname) + public void SetEmbedder(EmbeddingModel embedder) { - using (FileStream stream = new FileStream(filePath, FileMode.Create)) - using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Create)) - { - Save(archive, dirname); - } + searchMethod.SetEmbedder(embedder); } - public static string GetSearchTypePath(string dirname) + public string GetPhrase(Sentence sentence) { - return Path.Combine(dirname, "SearchType.txt"); + return phrases[sentence.phraseId].text; } - public static string GetSearchPath(string dirname) + public string GetSentence(Sentence sentence) { - return Path.Combine(dirname, "Search.json"); + return GetPhrase(sentence).Substring(sentence.startIndex, sentence.endIndex - sentence.startIndex + 1); } - public virtual void Save(ZipArchive archive, string dirname) + public void Add(string text) { - ZipArchiveEntry typeEntry = archive.CreateEntry(GetSearchTypePath(dirname)); - using (StreamWriter writer = new StreamWriter(typeEntry.Open())) + List<(int, int)> subindices; + if (sentenceSplitter == null) subindices = new List<(int, int)> { (0, text.Length - 1) }; + else subindices = sentenceSplitter.Split(text); + + int phraseId = nextPhraseId++; + Phrase phrase = new Phrase(text); + phrases[phraseId] = phrase; + foreach ((int startIndex, int endIndex) in subindices) { - writer.Write(GetType().FullName); + int sentenceId = nextSentenceId++; + Sentence sentence = new Sentence(phraseId, startIndex, endIndex); + sentences[sentenceId] = sentence; + phrase.sentenceIds.Add(sentenceId); + searchMethod?.Add(sentenceId, GetSentence(sentence)); } - Saver.Save(this, archive, GetSearchPath(dirname)); - embedder.Save(archive, dirname); } - public static ModelSearchBase CastLoad(string filePath, string dirname) + public int Remove(string text) { - using (FileStream stream = new FileStream(filePath, FileMode.Open)) - using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read)) + List removePhraseIds = new List(); + foreach (var phrasePair in phrases) { - return CastLoad(archive, dirname); + Phrase phrase = phrasePair.Value; + if (phrase.text == text) + { + foreach (int sentenceId in phrase.sentenceIds) + { + sentences.Remove(sentenceId); + searchMethod?.Remove(sentenceId); + } + removePhraseIds.Add(phrasePair.Key); + } } - } - - public static ModelSearchBase CastLoad(ZipArchive archive, string dirname) - { - ZipArchiveEntry typeEntry = archive.GetEntry(GetSearchTypePath(dirname)); - Type modelSearchType; - using (StreamReader reader = new StreamReader(typeEntry.Open())) + foreach (int phraseId in removePhraseIds) { - modelSearchType = Type.GetType(reader.ReadLine()); + phrases.Remove(phraseId); } - MethodInfo methodInfo = modelSearchType.GetMethod("Load", new Type[] { typeof(ZipArchive), typeof(string) }); - return (ModelSearchBase)Convert.ChangeType(methodInfo.Invoke(null, new object[] { archive, dirname }), modelSearchType); + return removePhraseIds.Count; } - public static T Load(string filePath, string dirname) where T : ModelSearchBase + public List GetPhrases() { - using (FileStream stream = new FileStream(filePath, FileMode.Open)) - using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read)) + List phraseTexts = new List(); + foreach (Phrase phrase in phrases.Values) { - return Load(archive, dirname); + phraseTexts.Add(phrase.text); } + return phraseTexts; } - public static T Load(ZipArchive archive, string dirname) where T : ModelSearchBase - { - T search = Saver.Load(archive, GetSearchPath(dirname)); - EmbeddingModel embedder = EmbeddingModel.Load(archive, dirname); - search.SetEmbedder(embedder); - return search; - } - } - - [DataContract] - public class ModelSearch : ModelSearchBase - { - public ModelSearch(EmbeddingModel embedder) : base(embedder) {} - - protected void Insert(string inputString, float[] encoding) - { - embeddings[inputString] = encoding; - } - - public float[] Add(string inputString) + public List GetSentences() { - float[] embedding = Encode(inputString); - Insert(inputString, embedding); - return embedding; - } - - public float[][] Add(string[] inputStrings, int batchSize = 64) - { - return Add(new List(inputStrings), batchSize); - } - - public float[][] Add(List inputStrings, int batchSize = 64) - { - float[][] inputEmbeddings = Encode(inputStrings, batchSize); - for (int i = 0; i < inputStrings.Count; i++) + List allSentences = new List(); + foreach (Sentence sentence in sentences.Values) { - Insert(inputStrings[i], inputEmbeddings[i]); + allSentences.Add(GetSentence(sentence)); } - return inputEmbeddings; - } - - public bool Remove(string inputString) - { - return embeddings.Remove(inputString); + return allSentences; } - public static ModelSearch Load(string filePath, string dirname) + public string[] Search(string queryString, int k, out float[] distances, bool returnSentences = false) { - return Load(filePath, dirname); + return Search(searchMethod.Encode(queryString), k, out distances, returnSentences); } - public static ModelSearch Load(ZipArchive archive, string dirname) + public string[] Search(float[] encoding, int k, out float[] distances, bool returnSentences = false) { - return Load(archive, dirname); - } - } - - - [DataContract] - public class ANNModelSearch : ModelSearchBase - { - USearchIndex index; - [DataMember] - protected SortedDictionary keyToValue; - - public ANNModelSearch(EmbeddingModel embedder) : this(embedder, MetricKind.Cos, 32, 40, 16) {} - - public ANNModelSearch( - EmbeddingModel embedder, - MetricKind metricKind = MetricKind.Cos, - ulong connectivity = 32, - ulong expansionAdd = 40, - ulong expansionSearch = 16, - bool multi = false - ) : this(embedder, new USearchIndex((ulong)embedder.Dimensions, metricKind, connectivity, expansionAdd, expansionSearch, multi)) {} - - public ANNModelSearch( - EmbeddingModel embedder, - USearchIndex index - ) : base(embedder) - { - this.index = index; - keyToValue = new SortedDictionary(); - } - - public void SetIndex(USearchIndex index) - { - this.index = index; - } - - public void Insert(int key, string value, float[] encoding) - { - index.Add((ulong)key, encoding); - keyToValue[key] = value; - } - - public virtual float[] Add(int key, string inputString) - { - float[] embedding = Encode(inputString); - Insert(key, inputString, embedding); - return embedding; - } - - public virtual float[][] Add(int[] keys, string[] inputStrings, int batchSize = 64) - { - return Add(new List(keys), new List(inputStrings), batchSize); - } - - public virtual float[][] Add(List keys, List inputStrings, int batchSize = 64) - { - float[][] inputEmbeddings = Encode(inputStrings, batchSize); - for (int i = 0; i < inputStrings.Count; i++) + if (returnSentences) { - Insert(keys[i], inputStrings[i], inputEmbeddings[i]); + int[] keys = searchMethod.SearchKey(encoding, k, out distances); + string[] result = new string[keys.Length]; + for (int i = 0; i < keys.Length; i++) + { + Sentence sentence = sentences[keys[i]]; + result[i] = returnSentences ? GetSentence(sentence) : GetPhrase(sentence); + } + return result; } - return inputEmbeddings.ToArray(); - } + else + { + List phraseKeys; + List phraseDistances; + int currK = k; + do + { + int[] keys = searchMethod.SearchKey(encoding, currK, out float[] iterDistances); + phraseDistances = new List(); + phraseKeys = new List(); + for (int i = 0; i < keys.Length; i++) + { + int phraseId = sentences[keys[i]].phraseId; + if (phraseKeys.Contains(phraseId)) continue; + phraseKeys.Add(phraseId); + phraseDistances.Add(iterDistances[i]); + } + if (currK >= searchMethod.Count()) break; + currK *= 2; + } + while (phraseKeys.Count() < k); - public bool Remove(int key) - { - return index.Remove((ulong)key) > 0 && keyToValue.Remove(key); + distances = phraseDistances.ToArray(); + string[] result = new string[phraseKeys.Count]; + for (int i = 0; i < phraseKeys.Count; i++) + result[i] = phrases[phraseKeys[i]].text; + return result; + } } - public override string[] Search(float[] encoding, int k) + public string[] Search(float[] encoding, int k, bool returnSentences = false) { - return Search(encoding, k, out float[] distances); + return Search(encoding, k, out float[] distances, returnSentences); } - public override string[] Search(string queryString, int k) + public string[] Search(string queryString, int k, bool returnSentences = false) { - return Search(queryString, k, out float[] distances); + return Search(queryString, k, out float[] distances, returnSentences); } - public override string[] Search(float[] encoding, int k, out float[] distances) + public string[] SearchPhrases(string queryString, int k, out float[] distances) { - int[] results = SearchKey(encoding, k, out distances); - string[] values = new string[results.Length]; - for (int i = 0; i < results.Length; i++) - { - values[i] = keyToValue[results[i]]; - } - return values; + return Search(queryString, k, out distances, false); } - public override string[] Search(string queryString, int k, out float[] distances) + public string[] SearchPhrases(string queryString, int k) { - return Search(Encode(queryString), k, out distances); + return SearchPhrases(queryString, k, out float[] distances); } - public int[] SearchKey(float[] encoding, int k) + public string[] SearchSentences(string queryString, int k, out float[] distances) { - return SearchKey(encoding, k, out float[] distances); + return Search(queryString, k, out distances, true); } - public int[] SearchKey(string queryString, int k) + public string[] SearchSentences(string queryString, int k) { - return SearchKey(queryString, k, out float[] distances); + return SearchSentences(queryString, k, out float[] distances); } - public int[] SearchKey(float[] encoding, int k, out float[] distances) + public int NumPhrases() { - index.Search(encoding, k, out ulong[] keys, out distances); - int[] intKeys = new int[keys.Length]; - for (int i = 0; i < keys.Length; i++) - intKeys[i] = (int)keys[i]; - return intKeys; + return phrases.Count; } - public int[] SearchKey(string queryString, int k, out float[] distances) + public int NumSentences() { - return SearchKey(Encode(queryString), k, out distances); + return sentences.Count; } - public override int Count() + public void Save(string filePath, string dirname = "") { - return (int)index.Size(); + using (FileStream stream = new FileStream(filePath, FileMode.Create)) + using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Create)) + { + Save(archive, dirname); + } } - public static string GetIndexPath(string dirname) + public static string GetSearchPath(string dirname) { - return Path.Combine(dirname, "USearch"); + return Path.Combine(dirname, "SearchEngine.json"); } - public override void Save(ZipArchive archive, string dirname) + public void Save(ZipArchive archive, string dirname) { - base.Save(archive, dirname); - index.Save(archive, GetIndexPath(dirname)); + Saver.Save(this, archive, GetSearchPath(dirname)); + searchMethod.Save(archive, dirname); } - public static ANNModelSearch Load(string filePath, string dirname) + public static SearchEngine Load(string filePath, string dirname) { using (FileStream stream = new FileStream(filePath, FileMode.Open)) using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read)) @@ -381,11 +341,11 @@ public static ANNModelSearch Load(string filePath, string dirname) } } - public static ANNModelSearch Load(ZipArchive archive, string dirname) + public static SearchEngine Load(ZipArchive archive, string dirname) { - ANNModelSearch search = Load(archive, dirname); - USearchIndex index = new USearchIndex(archive, GetIndexPath(dirname)); - search.SetIndex(index); + SearchEngine search = Saver.Load(archive, GetSearchPath(dirname)); + ANNModelSearch searchMethod = ANNModelSearch.Load(archive, dirname); + search.SetSearchMethod(searchMethod); return search; } } diff --git a/Runtime/SearchMethods.cs b/Runtime/SearchMethods.cs new file mode 100644 index 00000000..374282e1 --- /dev/null +++ b/Runtime/SearchMethods.cs @@ -0,0 +1,392 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Unity.Sentis; +using Cloud.Unum.USearch; +using System.Runtime.Serialization; +using System.IO; +using System.IO.Compression; +using System.Reflection; + + +namespace LLMUnity +{ + [DataContract] + public class SearchMethod + { + protected EmbeddingModel embedder; + [DataMember] + protected Dictionary embeddings; + + public SearchMethod(EmbeddingModel embedder) + { + embeddings = new Dictionary(); + this.embedder = embedder; + } + + public void SetEmbedder(EmbeddingModel embedder) + { + this.embedder = embedder; + } + + public float[] Encode(string inputString) + { + TensorFloat encoding = embedder.Encode(inputString); + encoding.MakeReadable(); + return encoding.ToReadOnlyArray(); + } + + public float[][] Encode(List inputStrings, int batchSize = 64) + { + List inputEmbeddings = new List(); + for (int i = 0; i < inputStrings.Count; i += batchSize) + { + int takeCount = Math.Min(batchSize, inputStrings.Count - i); + List batch = new List(inputStrings.GetRange(i, takeCount)); + foreach (TensorFloat tensor in embedder.Split(embedder.Encode(batch))) + { + tensor.MakeReadable(); + inputEmbeddings.Add(tensor.ToReadOnlyArray()); + } + } + if (inputStrings.Count != inputEmbeddings.Count) + { + throw new Exception($"Number of computed embeddings ({inputEmbeddings.Count}) different than inputs ({inputStrings.Count})"); + } + return inputEmbeddings.ToArray(); + } + + public virtual string[] Search(float[] encoding, int k) + { + return Search(encoding, k, out float[] distances); + } + + public virtual string[] Search(string queryString, int k) + { + return Search(queryString, k, out float[] distances); + } + + public static float DotProduct(float[] vector1, float[] vector2) + { + if (vector1.Length != vector2.Length) + { + throw new ArgumentException("Vector lengths must be equal for dot product calculation"); + } + float result = 0; + for (int i = 0; i < vector1.Length; i++) + { + result += vector1[i] * vector2[i]; + } + return result; + } + + public static float InverseDotProduct(float[] vector1, float[] vector2) + { + return 1 - DotProduct(vector1, vector2); + } + + public static float[] InverseDotProduct(float[] vector1, float[][] vector2) + { + float[] results = new float[vector2.Length]; + for (int i = 0; i < vector2.Length; i++) + { + results[i] = InverseDotProduct(vector1, vector2[i]); + } + return results; + } + + public virtual string[] Search(float[] encoding, int k, out float[] distances) + { + float[] unsortedDistances = InverseDotProduct(encoding, embeddings.Values.ToArray()); + + var sortedLists = embeddings.Keys.Zip(unsortedDistances, (first, second) => new { First = first, Second = second }) + .OrderBy(item => item.Second) + .ToList(); + int kmax = k == -1 ? sortedLists.Count : Math.Min(k, sortedLists.Count); + string[] results = new string[kmax]; + distances = new float[kmax]; + for (int i = 0; i < kmax; i++) + { + results[i] = sortedLists[i].First; + distances[i] = sortedLists[i].Second; + } + return results; + } + + public virtual string[] Search(string queryString, int k, out float[] distances) + { + return Search(Encode(queryString), k, out distances); + } + + public virtual int Count() + { + return embeddings.Count; + } + + public virtual void Save(string filePath, string dirname) + { + using (FileStream stream = new FileStream(filePath, FileMode.Create)) + using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Create)) + { + Save(archive, dirname); + } + } + + public static string GetSearchTypePath(string dirname) + { + return Path.Combine(dirname, "SearchType.txt"); + } + + public static string GetSearchPath(string dirname) + { + return Path.Combine(dirname, "Search.json"); + } + + public virtual void Save(ZipArchive archive, string dirname) + { + ZipArchiveEntry typeEntry = archive.CreateEntry(GetSearchTypePath(dirname)); + using (StreamWriter writer = new StreamWriter(typeEntry.Open())) + { + writer.Write(GetType().FullName); + } + Saver.Save(this, archive, GetSearchPath(dirname)); + embedder.Save(archive, dirname); + } + + public static SearchMethod CastLoad(string filePath, string dirname) + { + using (FileStream stream = new FileStream(filePath, FileMode.Open)) + using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read)) + { + return CastLoad(archive, dirname); + } + } + + public static SearchMethod CastLoad(ZipArchive archive, string dirname) + { + ZipArchiveEntry typeEntry = archive.GetEntry(GetSearchTypePath(dirname)); + Type modelSearchType; + using (StreamReader reader = new StreamReader(typeEntry.Open())) + { + modelSearchType = Type.GetType(reader.ReadLine()); + } + MethodInfo methodInfo = modelSearchType.GetMethod("Load", new Type[] { typeof(ZipArchive), typeof(string) }); + return (SearchMethod)Convert.ChangeType(methodInfo.Invoke(null, new object[] { archive, dirname }), modelSearchType); + } + + public static T Load(string filePath, string dirname) where T : SearchMethod + { + using (FileStream stream = new FileStream(filePath, FileMode.Open)) + using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read)) + { + return Load(archive, dirname); + } + } + + public static T Load(ZipArchive archive, string dirname) where T : SearchMethod + { + T search = Saver.Load(archive, GetSearchPath(dirname)); + EmbeddingModel embedder = EmbeddingModel.Load(archive, dirname); + search.SetEmbedder(embedder); + return search; + } + } + + [DataContract] + public class ModelSearch : SearchMethod + { + public ModelSearch(EmbeddingModel embedder) : base(embedder) {} + + protected void Insert(string inputString, float[] encoding) + { + embeddings[inputString] = encoding; + } + + public float[] Add(string inputString) + { + float[] embedding = Encode(inputString); + Insert(inputString, embedding); + return embedding; + } + + public float[][] Add(string[] inputStrings, int batchSize = 64) + { + return Add(new List(inputStrings), batchSize); + } + + public float[][] Add(List inputStrings, int batchSize = 64) + { + float[][] inputEmbeddings = Encode(inputStrings, batchSize); + for (int i = 0; i < inputStrings.Count; i++) + { + Insert(inputStrings[i], inputEmbeddings[i]); + } + return inputEmbeddings; + } + + public bool Remove(string inputString) + { + return embeddings.Remove(inputString); + } + + public static ModelSearch Load(string filePath, string dirname) + { + return Load(filePath, dirname); + } + + public static ModelSearch Load(ZipArchive archive, string dirname) + { + return Load(archive, dirname); + } + } + + + [DataContract] + public class ANNModelSearch : SearchMethod + { + USearchIndex index; + [DataMember] + protected SortedDictionary keyToValue; + + public ANNModelSearch(EmbeddingModel embedder) : this(embedder, MetricKind.Cos, 32, 40, 16) {} + + public ANNModelSearch( + EmbeddingModel embedder, + MetricKind metricKind = MetricKind.Cos, + ulong connectivity = 32, + ulong expansionAdd = 40, + ulong expansionSearch = 16, + bool multi = false + ) : this(embedder, new USearchIndex((ulong)embedder.Dimensions, metricKind, connectivity, expansionAdd, expansionSearch, multi)) {} + + public ANNModelSearch( + EmbeddingModel embedder, + USearchIndex index + ) : base(embedder) + { + this.index = index; + keyToValue = new SortedDictionary(); + } + + public void SetIndex(USearchIndex index) + { + this.index = index; + } + + public void Insert(int key, string value, float[] encoding) + { + index.Add((ulong)key, encoding); + keyToValue[key] = value; + } + + public virtual float[] Add(int key, string inputString) + { + float[] embedding = Encode(inputString); + Insert(key, inputString, embedding); + return embedding; + } + + public virtual float[][] Add(int[] keys, string[] inputStrings, int batchSize = 64) + { + return Add(new List(keys), new List(inputStrings), batchSize); + } + + public virtual float[][] Add(List keys, List inputStrings, int batchSize = 64) + { + float[][] inputEmbeddings = Encode(inputStrings, batchSize); + for (int i = 0; i < inputStrings.Count; i++) + { + Insert(keys[i], inputStrings[i], inputEmbeddings[i]); + } + return inputEmbeddings.ToArray(); + } + + public bool Remove(int key) + { + return index.Remove((ulong)key) > 0 && keyToValue.Remove(key); + } + + public override string[] Search(float[] encoding, int k) + { + return Search(encoding, k, out float[] distances); + } + + public override string[] Search(string queryString, int k) + { + return Search(queryString, k, out float[] distances); + } + + public override string[] Search(float[] encoding, int k, out float[] distances) + { + int[] results = SearchKey(encoding, k, out distances); + string[] values = new string[results.Length]; + for (int i = 0; i < results.Length; i++) + { + values[i] = keyToValue[results[i]]; + } + return values; + } + + public override string[] Search(string queryString, int k, out float[] distances) + { + return Search(Encode(queryString), k, out distances); + } + + public int[] SearchKey(float[] encoding, int k) + { + return SearchKey(encoding, k, out float[] distances); + } + + public int[] SearchKey(string queryString, int k) + { + return SearchKey(queryString, k, out float[] distances); + } + + public int[] SearchKey(float[] encoding, int k, out float[] distances) + { + index.Search(encoding, k, out ulong[] keys, out distances); + int[] intKeys = new int[keys.Length]; + for (int i = 0; i < keys.Length; i++) + intKeys[i] = (int)keys[i]; + return intKeys; + } + + public int[] SearchKey(string queryString, int k, out float[] distances) + { + return SearchKey(Encode(queryString), k, out distances); + } + + public override int Count() + { + return (int)index.Size(); + } + + public static string GetIndexPath(string dirname) + { + return Path.Combine(dirname, "USearch"); + } + + public override void Save(ZipArchive archive, string dirname) + { + base.Save(archive, dirname); + index.Save(archive, GetIndexPath(dirname)); + } + + public static ANNModelSearch Load(string filePath, string dirname) + { + using (FileStream stream = new FileStream(filePath, FileMode.Open)) + using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read)) + { + return Load(archive, dirname); + } + } + + public static ANNModelSearch Load(ZipArchive archive, string dirname) + { + ANNModelSearch search = Load(archive, dirname); + USearchIndex index = new USearchIndex(archive, GetIndexPath(dirname)); + search.SetIndex(index); + return search; + } + } +} diff --git a/Runtime/SearchMethods.cs.meta b/Runtime/SearchMethods.cs.meta new file mode 100644 index 00000000..c8a1b0d6 --- /dev/null +++ b/Runtime/SearchMethods.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cb8f978a275ad2792b7d17a9501d9c9d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/HamletSearch/HamletSearch.cs b/Samples~/HamletSearch/HamletSearch.cs index 01c812db..955ced11 100644 --- a/Samples~/HamletSearch/HamletSearch.cs +++ b/Samples~/HamletSearch/HamletSearch.cs @@ -20,7 +20,7 @@ void Start() } Dictionary> hamlet = ReadGutenbergFile(gutenbergText.text); - DialogueManager dialogueManager = new DialogueManager(model); + Dialogue dialogueManager = new Dialogue(model); Stopwatch stopwatch = new Stopwatch(); float elapsedTotal = 0; @@ -41,7 +41,7 @@ void Start() Debug.Log($"saving took {stopwatch.Elapsed.TotalMilliseconds / 1000f} secs"); stopwatch.Reset(); stopwatch.Start(); - dialogueManager = DialogueManager.Load("test.zip"); + dialogueManager = Dialogue.Load("test.zip"); Debug.Log($"loading took {stopwatch.Elapsed.TotalMilliseconds / 1000f} secs"); stopwatch.Reset(); stopwatch.Start(); diff --git a/Tests/Runtime/TestDialogue.cs b/Tests/Runtime/TestDialogue.cs index 911f265e..24bb4bf0 100644 --- a/Tests/Runtime/TestDialogue.cs +++ b/Tests/Runtime/TestDialogue.cs @@ -1,244 +1,11 @@ using NUnit.Framework; using LLMUnity; -using System; using System.IO; using UnityEngine; using System.Collections.Generic; namespace LLMUnityTests { - public class TestSentenceSplitter - { - [Test] - public void TestSplit() - { - SentenceSplitter splitter = new SentenceSplitter(); - SentenceSplitter splitterNoTrim = new SentenceSplitter(SentenceSplitter.DefaultDelimiters, false); - SentenceSplitter splitterQuestion = new SentenceSplitter(new char[] { '?' }, true); - SentenceSplitter splitterQuestionNoTrim = new SentenceSplitter(new char[] { '?' }, false); - - string[] sentences = new string[]{ - "hi.", - "how are you today?", - "the weather is nice!", - "perfect" - }; - string text = String.Join("", sentences); - - string[] sentencesSpace = (string[])sentences.Clone(); - sentencesSpace[0] = " " + sentencesSpace[0]; - sentencesSpace[1] = " " + sentencesSpace[1]; - sentencesSpace[3] = sentencesSpace[3] + " "; - string textSpace = String.Join("", sentencesSpace); - - string[] sentencesMultiSpace = (string[])sentences.Clone(); - sentencesMultiSpace[0] = " " + sentencesMultiSpace[0]; - sentencesMultiSpace[1] = " " + sentencesMultiSpace[1] + " "; - sentencesMultiSpace[3] = sentencesMultiSpace[3] + " "; - string textMultiSpace = String.Join("", sentencesMultiSpace); - - string[] sentencesBack, sentencesGT; - - //splitter - sentencesBack = SentenceSplitter.IndicesToSentences(text, splitter.Split(text)); - Assert.AreEqual(sentences, sentencesBack); - - sentencesBack = SentenceSplitter.IndicesToSentences(textSpace, splitter.Split(textSpace)); - Assert.AreEqual(sentences, sentencesBack); - - sentencesBack = SentenceSplitter.IndicesToSentences(textMultiSpace, splitter.Split(textMultiSpace)); - Assert.AreEqual(sentences, sentencesBack); - - //splitterNoTrim - sentencesBack = SentenceSplitter.IndicesToSentences(text, splitterNoTrim.Split(text)); - Assert.AreEqual(sentences, sentencesBack); - - sentencesBack = SentenceSplitter.IndicesToSentences(textSpace, splitterNoTrim.Split(textSpace)); - Assert.AreEqual(sentencesSpace, sentencesBack); - - //splitterQuestion - sentencesGT = new string[] { sentences[0] + sentences[1], sentences[2] + sentences[3] }; - sentencesBack = SentenceSplitter.IndicesToSentences(text, splitterQuestion.Split(text)); - Assert.AreEqual(sentencesGT, sentencesBack); - - sentencesGT = new string[] { sentences[0] + " " + sentences[1], sentences[2] + sentences[3] }; - sentencesBack = SentenceSplitter.IndicesToSentences(textSpace, splitterQuestion.Split(textSpace)); - Assert.AreEqual(sentencesGT, sentencesBack); - - sentencesGT = new string[] { sentences[0] + " " + sentences[1], sentences[2] + sentences[3] }; - sentencesBack = SentenceSplitter.IndicesToSentences(textMultiSpace, splitterQuestion.Split(textMultiSpace)); - Assert.AreEqual(sentencesGT, sentencesBack); - - //splitterQuestionNoTrim - sentencesGT = new string[] { sentences[0] + sentences[1], sentences[2] + sentences[3] }; - sentencesBack = SentenceSplitter.IndicesToSentences(text, splitterQuestionNoTrim.Split(text)); - Assert.AreEqual(sentencesGT, sentencesBack); - - sentencesGT = new string[] { sentencesSpace[0] + sentencesSpace[1], sentencesSpace[2] + sentencesSpace[3] }; - sentencesBack = SentenceSplitter.IndicesToSentences(textSpace, splitterQuestionNoTrim.Split(textSpace)); - Assert.AreEqual(sentencesGT, sentencesBack); - - } - } - - public class TestDialogue - { - EmbeddingModel model; - string modelPath; - string tokenizerPath; - string[] sentences = new string[]{ - "hi.", - "how are you today?", - "how is the weather today?", - "is it raining?" - }; - - [SetUp] - public void SetUp() - { - modelPath = Path.Combine(Application.streamingAssetsPath, "bge-small-en-v1.5.sentis"); - tokenizerPath = Path.Combine(Application.streamingAssetsPath, "bge-small-en-v1.5.tokenizer.json"); - model = new EmbeddingModel(modelPath, tokenizerPath, Unity.Sentis.BackendType.CPU, "sentence_embedding", false, 384); - } - - [TearDown] - public void TearDown() - { - model.Destroy(); - } - - [Test] - public void TestAdd() - { - Dialogue dialogue = new Dialogue("", "", model); - foreach (string sentence in sentences) - dialogue.Add(sentence); - Assert.AreEqual(dialogue.GetPhrases().ToArray(), sentences); - Assert.AreEqual(dialogue.GetSentences().ToArray(), sentences); - Assert.AreEqual(dialogue.NumPhrases(), sentences.Length); - Assert.AreEqual(dialogue.NumSentences(), sentences.Length); - - dialogue.Remove(sentences[1]); - string[] sentencesGT = new string[] { sentences[0], sentences[2], sentences[3] }; - Assert.AreEqual(dialogue.GetPhrases().ToArray(), sentencesGT); - Assert.AreEqual(dialogue.GetSentences().ToArray(), sentencesGT); - Assert.AreEqual(dialogue.NumPhrases(), sentencesGT.Length); - Assert.AreEqual(dialogue.NumSentences(), sentencesGT.Length); - - dialogue.Add(sentences[1]); - dialogue.Add(sentences[1]); - dialogue.Remove(sentences[1]); - Assert.AreEqual(dialogue.GetPhrases().ToArray(), sentencesGT); - Assert.AreEqual(dialogue.GetSentences().ToArray(), sentencesGT); - Assert.AreEqual(dialogue.NumPhrases(), sentencesGT.Length); - Assert.AreEqual(dialogue.NumSentences(), sentencesGT.Length); - - string[] phrases = new string[] { sentences[0] + " " + sentences[1], sentences[1] + sentences[2], sentences[2] + sentences[3] }; - dialogue = new Dialogue("", "", model); - foreach (string phrase in phrases) - dialogue.Add(phrase); - dialogue.Remove(phrases[1]); - string[] phrasesGT = new string[] { phrases[0], phrases[2] }; - Assert.AreEqual(dialogue.GetPhrases().ToArray(), new string[] { phrases[0], phrases[2] }); - Assert.AreEqual(dialogue.GetSentences().ToArray(), sentences); - Assert.AreEqual(dialogue.NumPhrases(), 2); - Assert.AreEqual(dialogue.NumSentences(), 4); - - dialogue.Add(phrases[1]); - phrasesGT = new string[] { phrases[0], phrases[2], phrases[1] }; - sentencesGT = new string[] { sentences[0], sentences[1], sentences[2], sentences[3], sentences[1], sentences[2] }; - - Assert.AreEqual(dialogue.GetPhrases().ToArray(), phrasesGT); - Assert.AreEqual(dialogue.GetSentences().ToArray(), sentencesGT); - Assert.AreEqual(dialogue.NumPhrases(), phrasesGT.Length); - Assert.AreEqual(dialogue.NumSentences(), sentencesGT.Length); - } - - public bool ApproxEqual(float x1, float x2, float tolerance = 0.00001f) - { - return Mathf.Abs(x1 - x2) < tolerance; - } - - [Test] - public void TestSearch() - { - Dialogue dialogue = new Dialogue("", "", model); - foreach (string sentence in sentences) - dialogue.Add(sentence); - string[] result; - string[] resultGT; - float trueSimilarity = 0.79276246f; - - result = dialogue.Search(sentences[3], 2); - resultGT = new string[] { sentences[3], sentences[2] }; - Assert.AreEqual(result, resultGT); - - result = dialogue.Search(sentences[3], 2, out float[] distances); - Assert.AreEqual(result, resultGT); - Assert.AreEqual(distances.Length, 2); - Assert.That(ApproxEqual(distances[0], 0)); - Assert.That(ApproxEqual(distances[1], 1 - trueSimilarity)); - - string[] phrases = new string[]{ - sentences[0] + sentences[1], - sentences[2], - sentences[2] + sentences[2] + sentences[2] + sentences[2] + - sentences[3] + sentences[3] + sentences[3] + sentences[3] - }; - dialogue = new Dialogue("", "", model); - foreach (string phrase in phrases) - dialogue.Add(phrase); - - result = dialogue.SearchSentences(sentences[3], 5, out distances); - resultGT = new string[] { sentences[3], sentences[3], sentences[3], sentences[3], sentences[2] }; - Assert.AreEqual(result, resultGT); - Assert.AreEqual(distances.Length, 5); - for (int i = 0; i < 4; i++) - Assert.That(ApproxEqual(distances[i], 0)); - Assert.That(ApproxEqual(distances[4], 1 - trueSimilarity)); - - float trueSimilarity2 = 0.7036853f; - result = dialogue.SearchPhrases(sentences[3], 4, out distances); - resultGT = new string[] { phrases[2], phrases[1], phrases[0] }; - Assert.AreEqual(result, resultGT); - Assert.AreEqual(distances.Length, 3); - Assert.That(ApproxEqual(distances[0], 0)); - Assert.That(ApproxEqual(distances[1], 1 - trueSimilarity)); - Debug.Log(distances[2]); - Assert.That(ApproxEqual(distances[2], 1 - trueSimilarity2)); - } - - [Test] - public void TestSaveLoad() - { - Dialogue dialogue = new Dialogue("", "", model); - foreach (string sentence in sentences) - dialogue.Add(sentence); - - string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); - dialogue.Save(path, "test"); - var loadedDialogue = Dialogue.Load(path, "test"); - File.Delete(path); - - Assert.AreEqual(dialogue.NumSentences(), loadedDialogue.NumSentences()); - Assert.AreEqual(dialogue.NumPhrases(), loadedDialogue.NumPhrases()); - - string[] result; - string[] resultGT; - float trueSimilarity = 0.79276246f; - - result = dialogue.Search(sentences[3], 2); - resultGT = new string[] { sentences[3], sentences[2] }; - Assert.AreEqual(result, resultGT); - - result = dialogue.Search(sentences[3], 2, out float[] distances); - Assert.AreEqual(result, resultGT); - Assert.AreEqual(distances.Length, 2); - Assert.That(ApproxEqual(distances[0], 0)); - Assert.That(ApproxEqual(distances[1], 1 - trueSimilarity)); - } - } - public class TestDialogueManager { EmbeddingModel model; @@ -269,7 +36,7 @@ public void TearDown() [Test] public void TestAdd() { - DialogueManager manager = new DialogueManager(model); + Dialogue manager = new Dialogue(model); foreach (var phrase in phrases) manager.Add(phrase.Item1, phrase.Item2, phrase.Item3); Assert.AreEqual(manager.NumPhrases(), 5); @@ -319,14 +86,14 @@ public void TestSaveLoad() { string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); - DialogueManager manager = new DialogueManager(model); + Dialogue manager = new Dialogue(model); manager.Save(path); - DialogueManager loadedManager = DialogueManager.Load(path); + Dialogue loadedManager = Dialogue.Load(path); foreach (var phrase in phrases) manager.Add(phrase.Item1, phrase.Item2, phrase.Item3); manager.Save(path); - loadedManager = DialogueManager.Load(path); + loadedManager = Dialogue.Load(path); File.Delete(path); Assert.AreEqual(manager.NumSentences(), loadedManager.NumSentences()); @@ -340,7 +107,7 @@ public void TestSaveLoad() [Test] public void TestSearch() { - DialogueManager manager = new DialogueManager(model); + Dialogue manager = new Dialogue(model); foreach (var phrase in phrases) manager.Add(phrase.Item1, phrase.Item2, phrase.Item3); manager.Add("Ophelia", phrases[0].Item2, phrases[0].Item3); diff --git a/Tests/Runtime/TestSearch.cs b/Tests/Runtime/TestSearch.cs index 73fb9945..a6d4a949 100644 --- a/Tests/Runtime/TestSearch.cs +++ b/Tests/Runtime/TestSearch.cs @@ -1,146 +1,240 @@ using NUnit.Framework; using LLMUnity; -using Unity.Sentis; +using System; using System.IO; using UnityEngine; -using System.Collections.Generic; namespace LLMUnityTests { - public class TestSearch + public class TestSentenceSplitter + { + [Test] + public void TestSplit() + { + SentenceSplitter splitter = new SentenceSplitter(); + SentenceSplitter splitterNoTrim = new SentenceSplitter(SentenceSplitter.DefaultDelimiters, false); + SentenceSplitter splitterQuestion = new SentenceSplitter(new char[] { '?' }, true); + SentenceSplitter splitterQuestionNoTrim = new SentenceSplitter(new char[] { '?' }, false); + + string[] sentences = new string[]{ + "hi.", + "how are you today?", + "the weather is nice!", + "perfect" + }; + string text = String.Join("", sentences); + + string[] sentencesSpace = (string[])sentences.Clone(); + sentencesSpace[0] = " " + sentencesSpace[0]; + sentencesSpace[1] = " " + sentencesSpace[1]; + sentencesSpace[3] = sentencesSpace[3] + " "; + string textSpace = String.Join("", sentencesSpace); + + string[] sentencesMultiSpace = (string[])sentences.Clone(); + sentencesMultiSpace[0] = " " + sentencesMultiSpace[0]; + sentencesMultiSpace[1] = " " + sentencesMultiSpace[1] + " "; + sentencesMultiSpace[3] = sentencesMultiSpace[3] + " "; + string textMultiSpace = String.Join("", sentencesMultiSpace); + + string[] sentencesBack, sentencesGT; + + //splitter + sentencesBack = SentenceSplitter.IndicesToSentences(text, splitter.Split(text)); + Assert.AreEqual(sentences, sentencesBack); + + sentencesBack = SentenceSplitter.IndicesToSentences(textSpace, splitter.Split(textSpace)); + Assert.AreEqual(sentences, sentencesBack); + + sentencesBack = SentenceSplitter.IndicesToSentences(textMultiSpace, splitter.Split(textMultiSpace)); + Assert.AreEqual(sentences, sentencesBack); + + //splitterNoTrim + sentencesBack = SentenceSplitter.IndicesToSentences(text, splitterNoTrim.Split(text)); + Assert.AreEqual(sentences, sentencesBack); + + sentencesBack = SentenceSplitter.IndicesToSentences(textSpace, splitterNoTrim.Split(textSpace)); + Assert.AreEqual(sentencesSpace, sentencesBack); + + //splitterQuestion + sentencesGT = new string[] { sentences[0] + sentences[1], sentences[2] + sentences[3] }; + sentencesBack = SentenceSplitter.IndicesToSentences(text, splitterQuestion.Split(text)); + Assert.AreEqual(sentencesGT, sentencesBack); + + sentencesGT = new string[] { sentences[0] + " " + sentences[1], sentences[2] + sentences[3] }; + sentencesBack = SentenceSplitter.IndicesToSentences(textSpace, splitterQuestion.Split(textSpace)); + Assert.AreEqual(sentencesGT, sentencesBack); + + sentencesGT = new string[] { sentences[0] + " " + sentences[1], sentences[2] + sentences[3] }; + sentencesBack = SentenceSplitter.IndicesToSentences(textMultiSpace, splitterQuestion.Split(textMultiSpace)); + Assert.AreEqual(sentencesGT, sentencesBack); + + //splitterQuestionNoTrim + sentencesGT = new string[] { sentences[0] + sentences[1], sentences[2] + sentences[3] }; + sentencesBack = SentenceSplitter.IndicesToSentences(text, splitterQuestionNoTrim.Split(text)); + Assert.AreEqual(sentencesGT, sentencesBack); + + sentencesGT = new string[] { sentencesSpace[0] + sentencesSpace[1], sentencesSpace[2] + sentencesSpace[3] }; + sentencesBack = SentenceSplitter.IndicesToSentences(textSpace, splitterQuestionNoTrim.Split(textSpace)); + Assert.AreEqual(sentencesGT, sentencesBack); + + } + } + + public class TestDialogue { EmbeddingModel model; string modelPath; string tokenizerPath; - string weather = "how is the weather today?"; - string raining = "is it raining?"; - string random = "something completely random"; - - public bool ApproxEqual(float x1, float x2, float tolerance = 0.00001f) - { - return Mathf.Abs(x1 - x2) < tolerance; - } + string[] sentences = new string[]{ + "hi.", + "how are you today?", + "how is the weather today?", + "is it raining?" + }; [SetUp] public void SetUp() { modelPath = Path.Combine(Application.streamingAssetsPath, "bge-small-en-v1.5.sentis"); tokenizerPath = Path.Combine(Application.streamingAssetsPath, "bge-small-en-v1.5.tokenizer.json"); - model = new EmbeddingModel(modelPath, tokenizerPath, BackendType.CPU, "sentence_embedding", false, 384); + model = new EmbeddingModel(modelPath, tokenizerPath, Unity.Sentis.BackendType.CPU, "sentence_embedding", false, 384); } - public void TestEncode(ModelSearchBase search) + [TearDown] + public void TearDown() { - string inputString = weather; - List inputStrings = new List() { weather, weather }; - float[] encoding = search.Encode(inputString); - float[][] encodings = search.Encode(inputStrings); - foreach (float[] encodingArray in new List() { encoding, encodings[0], encodings[1] }) - { - Assert.That(ApproxEqual(encodingArray[0], -0.029100293293595314f)); - Assert.That(ApproxEqual(encodingArray[383], 0.017599990591406822f)); - } + model.Destroy(); } - public void TestSaveLoad(ModelSearchBase search, string example) + [Test] + public void TestAdd() { - string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); - search.Save(path, ""); - var loadedSearch = ModelSearchBase.CastLoad(path, ""); - Assert.AreEqual(search.GetType(), loadedSearch.GetType()); - Assert.AreEqual(search.Count(), loadedSearch.Count()); - Assert.AreEqual(loadedSearch.Search(example, 1)[0], example); - File.Delete(path); - } + SearchEngine searchEngine = new SearchEngine(model); + foreach (string sentence in sentences) + searchEngine.Add(sentence); + Assert.AreEqual(searchEngine.GetPhrases().ToArray(), sentences); + Assert.AreEqual(searchEngine.GetSentences().ToArray(), sentences); + Assert.AreEqual(searchEngine.NumPhrases(), sentences.Length); + Assert.AreEqual(searchEngine.NumSentences(), sentences.Length); - public void TestAdd(ModelSearch search) - { - search.Add(weather); - Assert.AreEqual(search.Count(), 1); - search.Add(new List() { raining, random }); - search.Add(weather); - Assert.AreEqual(search.Count(), 3); - search.Remove(weather); - Assert.AreEqual(search.Count(), 2); - search.Add(weather); - Assert.AreEqual(search.Count(), 3); + searchEngine.Remove(sentences[1]); + string[] sentencesGT = new string[] { sentences[0], sentences[2], sentences[3] }; + Assert.AreEqual(searchEngine.GetPhrases().ToArray(), sentencesGT); + Assert.AreEqual(searchEngine.GetSentences().ToArray(), sentencesGT); + Assert.AreEqual(searchEngine.NumPhrases(), sentencesGT.Length); + Assert.AreEqual(searchEngine.NumSentences(), sentencesGT.Length); + + searchEngine.Add(sentences[1]); + searchEngine.Add(sentences[1]); + searchEngine.Remove(sentences[1]); + Assert.AreEqual(searchEngine.GetPhrases().ToArray(), sentencesGT); + Assert.AreEqual(searchEngine.GetSentences().ToArray(), sentencesGT); + Assert.AreEqual(searchEngine.NumPhrases(), sentencesGT.Length); + Assert.AreEqual(searchEngine.NumSentences(), sentencesGT.Length); + + string[] phrases = new string[] { sentences[0] + " " + sentences[1], sentences[1] + sentences[2], sentences[2] + sentences[3] }; + searchEngine = new SearchEngine(model); + foreach (string phrase in phrases) + searchEngine.Add(phrase); + searchEngine.Remove(phrases[1]); + string[] phrasesGT = new string[] { phrases[0], phrases[2] }; + Assert.AreEqual(searchEngine.GetPhrases().ToArray(), new string[] { phrases[0], phrases[2] }); + Assert.AreEqual(searchEngine.GetSentences().ToArray(), sentences); + Assert.AreEqual(searchEngine.NumPhrases(), 2); + Assert.AreEqual(searchEngine.NumSentences(), 4); + + searchEngine.Add(phrases[1]); + phrasesGT = new string[] { phrases[0], phrases[2], phrases[1] }; + sentencesGT = new string[] { sentences[0], sentences[1], sentences[2], sentences[3], sentences[1], sentences[2] }; + + Assert.AreEqual(searchEngine.GetPhrases().ToArray(), phrasesGT); + Assert.AreEqual(searchEngine.GetSentences().ToArray(), sentencesGT); + Assert.AreEqual(searchEngine.NumPhrases(), phrasesGT.Length); + Assert.AreEqual(searchEngine.NumSentences(), sentencesGT.Length); } - public void TestKeyAdd(ANNModelSearch search) + public bool ApproxEqual(float x1, float x2, float tolerance = 0.00001f) { - search.Add(1, weather); - Assert.AreEqual(search.Count(), 1); - search.Add(new List() { 2, 3 }, new List() { raining, random }); - Assert.AreEqual(search.Count(), 3); - search.Remove(2); - Assert.AreEqual(search.Count(), 2); - search.Add(2, raining); - Assert.AreEqual(search.Count(), 3); + return Mathf.Abs(x1 - x2) < tolerance; } - public void TestSearchFunctions(ModelSearchBase search) + [Test] + public void TestSearch() { - string[] result = search.Search(weather, 2, out float[] distances); - Assert.AreEqual(result.Length, 2); - Assert.AreEqual(distances.Length, 2); - Assert.AreEqual(result[0], weather); - Assert.AreEqual(result[1], raining); - Assert.That(ApproxEqual(distances[0], 0)); + SearchEngine searchEngine = new SearchEngine(model); + foreach (string sentence in sentences) + searchEngine.Add(sentence); + string[] result; + string[] resultGT; float trueSimilarity = 0.79276246f; - Assert.That(ApproxEqual(distances[1], 1 - trueSimilarity)); - if (search.GetType() == typeof(ANNModelSearch)) - { - TestSearchKey((ANNModelSearch)search); - } - } + result = searchEngine.Search(sentences[3], 2); + resultGT = new string[] { sentences[3], sentences[2] }; + Assert.AreEqual(result, resultGT); - public void TestSearchKey(ANNModelSearch search) - { - int[] result = search.SearchKey(weather, 2, out float[] distances); - Assert.AreEqual(result.Length, 2); + result = searchEngine.Search(sentences[3], 2, out float[] distances); + Assert.AreEqual(result, resultGT); Assert.AreEqual(distances.Length, 2); - Assert.AreEqual(result[0], 1); - Assert.AreEqual(result[1], 2); Assert.That(ApproxEqual(distances[0], 0)); - float trueSimilarity = 0.79276246f; Assert.That(ApproxEqual(distances[1], 1 - trueSimilarity)); - } - public void FullTest(ModelSearchBase search) - { - TestEncode(search); - if (search.GetType() == typeof(ModelSearch)) - { - TestAdd((ModelSearch)search); - } - else - { - TestKeyAdd((ANNModelSearch)search); - } - TestSearchFunctions(search); - TestSaveLoad(search, weather); - TestSearchFunctions(search); - } + string[] phrases = new string[]{ + sentences[0] + sentences[1], + sentences[2], + sentences[2] + sentences[2] + sentences[2] + sentences[2] + + sentences[3] + sentences[3] + sentences[3] + sentences[3] + }; + searchEngine = new SearchEngine(model); + foreach (string phrase in phrases) + searchEngine.Add(phrase); - [Test] - public void FullTestModelSearch() - { - ModelSearch search = new ModelSearch(model); - FullTest(search); + result = searchEngine.SearchSentences(sentences[3], 5, out distances); + resultGT = new string[] { sentences[3], sentences[3], sentences[3], sentences[3], sentences[2] }; + Assert.AreEqual(result, resultGT); + Assert.AreEqual(distances.Length, 5); + for (int i = 0; i < 4; i++) + Assert.That(ApproxEqual(distances[i], 0)); + Assert.That(ApproxEqual(distances[4], 1 - trueSimilarity)); + + float trueSimilarity2 = 0.7036853f; + result = searchEngine.SearchPhrases(sentences[3], 4, out distances); + resultGT = new string[] { phrases[2], phrases[1], phrases[0] }; + Assert.AreEqual(result, resultGT); + Assert.AreEqual(distances.Length, 3); + Assert.That(ApproxEqual(distances[0], 0)); + Assert.That(ApproxEqual(distances[1], 1 - trueSimilarity)); + Debug.Log(distances[2]); + Assert.That(ApproxEqual(distances[2], 1 - trueSimilarity2)); } [Test] - public void FullTestANNModelSearch() + public void TestSaveLoad() { - ANNModelSearch search = new ANNModelSearch(model); - FullTest(search); - } + SearchEngine searchEngine = new SearchEngine(model); + foreach (string sentence in sentences) + searchEngine.Add(sentence); - [TearDown] - public void TearDown() - { - model.Destroy(); + string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + searchEngine.Save(path, "test"); + var loadedDialogue = SearchEngine.Load(path, "test"); + File.Delete(path); + + Assert.AreEqual(searchEngine.NumSentences(), loadedDialogue.NumSentences()); + Assert.AreEqual(searchEngine.NumPhrases(), loadedDialogue.NumPhrases()); + + string[] result; + string[] resultGT; + float trueSimilarity = 0.79276246f; + + result = searchEngine.Search(sentences[3], 2); + resultGT = new string[] { sentences[3], sentences[2] }; + Assert.AreEqual(result, resultGT); + + result = searchEngine.Search(sentences[3], 2, out float[] distances); + Assert.AreEqual(result, resultGT); + Assert.AreEqual(distances.Length, 2); + Assert.That(ApproxEqual(distances[0], 0)); + Assert.That(ApproxEqual(distances[1], 1 - trueSimilarity)); } } -} +} \ No newline at end of file diff --git a/Tests/Runtime/TestSearchMethods.cs b/Tests/Runtime/TestSearchMethods.cs new file mode 100644 index 00000000..22d57e73 --- /dev/null +++ b/Tests/Runtime/TestSearchMethods.cs @@ -0,0 +1,146 @@ +using NUnit.Framework; +using LLMUnity; +using Unity.Sentis; +using System.IO; +using UnityEngine; +using System.Collections.Generic; + +namespace LLMUnityTests +{ + public class TestSearch + { + EmbeddingModel model; + string modelPath; + string tokenizerPath; + string weather = "how is the weather today?"; + string raining = "is it raining?"; + string random = "something completely random"; + + public bool ApproxEqual(float x1, float x2, float tolerance = 0.00001f) + { + return Mathf.Abs(x1 - x2) < tolerance; + } + + [SetUp] + public void SetUp() + { + modelPath = Path.Combine(Application.streamingAssetsPath, "bge-small-en-v1.5.sentis"); + tokenizerPath = Path.Combine(Application.streamingAssetsPath, "bge-small-en-v1.5.tokenizer.json"); + model = new EmbeddingModel(modelPath, tokenizerPath, BackendType.CPU, "sentence_embedding", false, 384); + } + + public void TestEncode(SearchMethod search) + { + string inputString = weather; + List inputStrings = new List() { weather, weather }; + float[] encoding = search.Encode(inputString); + float[][] encodings = search.Encode(inputStrings); + foreach (float[] encodingArray in new List() { encoding, encodings[0], encodings[1] }) + { + Assert.That(ApproxEqual(encodingArray[0], -0.029100293293595314f)); + Assert.That(ApproxEqual(encodingArray[383], 0.017599990591406822f)); + } + } + + public void TestSaveLoad(SearchMethod search, string example) + { + string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + search.Save(path, ""); + var loadedSearch = SearchMethod.CastLoad(path, ""); + Assert.AreEqual(search.GetType(), loadedSearch.GetType()); + Assert.AreEqual(search.Count(), loadedSearch.Count()); + Assert.AreEqual(loadedSearch.Search(example, 1)[0], example); + File.Delete(path); + } + + public void TestAdd(ModelSearch search) + { + search.Add(weather); + Assert.AreEqual(search.Count(), 1); + search.Add(new List() { raining, random }); + search.Add(weather); + Assert.AreEqual(search.Count(), 3); + search.Remove(weather); + Assert.AreEqual(search.Count(), 2); + search.Add(weather); + Assert.AreEqual(search.Count(), 3); + } + + public void TestKeyAdd(ANNModelSearch search) + { + search.Add(1, weather); + Assert.AreEqual(search.Count(), 1); + search.Add(new List() { 2, 3 }, new List() { raining, random }); + Assert.AreEqual(search.Count(), 3); + search.Remove(2); + Assert.AreEqual(search.Count(), 2); + search.Add(2, raining); + Assert.AreEqual(search.Count(), 3); + } + + public void TestSearchFunctions(SearchMethod search) + { + string[] result = search.Search(weather, 2, out float[] distances); + Assert.AreEqual(result.Length, 2); + Assert.AreEqual(distances.Length, 2); + Assert.AreEqual(result[0], weather); + Assert.AreEqual(result[1], raining); + Assert.That(ApproxEqual(distances[0], 0)); + float trueSimilarity = 0.79276246f; + Assert.That(ApproxEqual(distances[1], 1 - trueSimilarity)); + + if (search.GetType() == typeof(ANNModelSearch)) + { + TestSearchKey((ANNModelSearch)search); + } + } + + public void TestSearchKey(ANNModelSearch search) + { + int[] result = search.SearchKey(weather, 2, out float[] distances); + Assert.AreEqual(result.Length, 2); + Assert.AreEqual(distances.Length, 2); + Assert.AreEqual(result[0], 1); + Assert.AreEqual(result[1], 2); + Assert.That(ApproxEqual(distances[0], 0)); + float trueSimilarity = 0.79276246f; + Assert.That(ApproxEqual(distances[1], 1 - trueSimilarity)); + } + + public void FullTest(SearchMethod search) + { + TestEncode(search); + if (search.GetType() == typeof(ModelSearch)) + { + TestAdd((ModelSearch)search); + } + else + { + TestKeyAdd((ANNModelSearch)search); + } + TestSearchFunctions(search); + TestSaveLoad(search, weather); + TestSearchFunctions(search); + } + + [Test] + public void FullTestModelSearch() + { + ModelSearch search = new ModelSearch(model); + FullTest(search); + } + + [Test] + public void FullTestANNModelSearch() + { + ANNModelSearch search = new ANNModelSearch(model); + FullTest(search); + } + + [TearDown] + public void TearDown() + { + model.Destroy(); + } + } +} diff --git a/Tests/Runtime/TestSearchMethods.cs.meta b/Tests/Runtime/TestSearchMethods.cs.meta new file mode 100644 index 00000000..c6ef4a35 --- /dev/null +++ b/Tests/Runtime/TestSearchMethods.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c7658d2e8374e36f9a73664b2fd252a3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 43d4d7d285731bcfd12242ac8c43adcab358c61d Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Mon, 12 Feb 2024 11:49:00 +0200 Subject: [PATCH 096/161] change argument order in Add method --- Runtime/Dialogue.cs | 9 ++---- Samples~/HamletSearch/HamletSearch.cs | 2 +- Tests/Runtime/TestDialogue.cs | 40 +++++++++++++-------------- 3 files changed, 23 insertions(+), 28 deletions(-) diff --git a/Runtime/Dialogue.cs b/Runtime/Dialogue.cs index cebb86e5..96285ff8 100644 --- a/Runtime/Dialogue.cs +++ b/Runtime/Dialogue.cs @@ -38,7 +38,7 @@ public void SetNoSentenceSplitting() SetSentenceSplitting(null); } - public void Add(string actor, string title, string text) + public void Add(string actor, string text, string title="") { if (!dialogueParts.ContainsKey(actor) || !dialogueParts[actor].ContainsKey(title)) { @@ -53,12 +53,7 @@ public void Add(string actor, string title, string text) dialogueParts[actor][title].Add(text); } - public void Add(string actor, string text) - { - Add(actor, null, text); - } - - public int Remove(string actor, string title, string text) + public int Remove(string actor, string text, string title=null) { List dialogueParts = Filter(actor, title); int removed = 0; diff --git a/Samples~/HamletSearch/HamletSearch.cs b/Samples~/HamletSearch/HamletSearch.cs index 955ced11..e3982512 100644 --- a/Samples~/HamletSearch/HamletSearch.cs +++ b/Samples~/HamletSearch/HamletSearch.cs @@ -29,7 +29,7 @@ void Start() if (!fullPlay && act != "ACT III") continue; stopwatch.Reset(); stopwatch.Start(); foreach ((string actor, string message) in messages) - dialogueManager.Add(actor, act, message); + dialogueManager.Add(actor, message, act); elapsedTotal += (float)stopwatch.Elapsed.TotalMilliseconds / 1000f; Debug.Log($"act {act} embedded {dialogueManager.GetSentences(null, act).Length} sentences in {stopwatch.Elapsed.TotalMilliseconds / 1000f} secs"); diff --git a/Tests/Runtime/TestDialogue.cs b/Tests/Runtime/TestDialogue.cs index 24bb4bf0..64a64414 100644 --- a/Tests/Runtime/TestDialogue.cs +++ b/Tests/Runtime/TestDialogue.cs @@ -12,11 +12,11 @@ public class TestDialogueManager string modelPath; string tokenizerPath; List<(string, string, string)> phrases = new List<(string, string, string)>(){ - ("Hamlet", "ACT I", "To be, or not to be, that is the question. Whether tis nobler in the mind to suffer."), - ("Hamlet", "ACT I", "Or to take arms against a sea of troubles, and by opposing end them? To die—to sleep."), - ("Hamlet", "ACT II", "I humbly thank you; well, well, well."), - ("Ophelia", "ACT II", "Good my lord."), - ("Ophelia", "ACT II", "How does your honour for this many a day?") + ("Hamlet", "To be, or not to be, that is the question. Whether tis nobler in the mind to suffer.", "ACT I"), + ("Hamlet", "Or to take arms against a sea of troubles, and by opposing end them? To die—to sleep.", "ACT I"), + ("Hamlet", "I humbly thank you; well, well, well.", "ACT II"), + ("Ophelia", "Good my lord.", "ACT II"), + ("Ophelia", "How does your honour for this many a day?", "ACT II") }; [SetUp] @@ -52,8 +52,8 @@ public void TestAdd() Assert.AreEqual(manager.NumPhrases("Hamlet", "ACT I"), 2); Assert.AreEqual(manager.NumSentences("Hamlet", "ACT II"), 2); - Assert.AreEqual(manager.GetPhrases("Hamlet", "ACT II"), new string[] { phrases[2].Item3 }); - string[] sentencesGT = phrases[2].Item3.Split(";"); + Assert.AreEqual(manager.GetPhrases("Hamlet", "ACT II"), new string[] { phrases[2].Item2 }); + string[] sentencesGT = phrases[2].Item2.Split(";"); sentencesGT[0] += ";"; sentencesGT[1] = sentencesGT[1].Trim(); Assert.AreEqual(manager.GetSentences("Hamlet", "ACT II"), sentencesGT); @@ -61,24 +61,24 @@ public void TestAdd() manager.Add(phrases[3].Item1, phrases[3].Item2, phrases[3].Item3); Assert.AreEqual(manager.NumPhrases("Ophelia"), 3); Assert.AreEqual(manager.NumSentences("Ophelia"), 3); - manager.Remove(null, null, phrases[2].Item3); + manager.Remove(null, phrases[2].Item2); Assert.AreEqual(manager.NumPhrases("Hamlet"), 2); Assert.AreEqual(manager.NumSentences("Hamlet"), 4); - manager.Remove(null, null, phrases[3].Item3); + manager.Remove(null, phrases[3].Item2); Assert.AreEqual(manager.NumPhrases("Ophelia"), 1); Assert.AreEqual(manager.NumSentences("Ophelia"), 1); manager.Add("Ophelia", phrases[0].Item2, phrases[0].Item3); - manager.Remove("Hamlet", null, phrases[0].Item3); + manager.Remove("Hamlet", phrases[0].Item2); Assert.AreEqual(manager.NumPhrases("Ophelia"), 2); Assert.AreEqual(manager.NumSentences("Ophelia"), 3); Assert.AreEqual(manager.NumPhrases("Hamlet"), 1); Assert.AreEqual(manager.NumSentences("Hamlet"), 2); - sentencesGT = phrases[1].Item3.Split("?"); + sentencesGT = phrases[1].Item2.Split("?"); sentencesGT[0] += "?"; sentencesGT[1] = sentencesGT[1].Trim(); Assert.AreEqual(manager.GetSentences("Hamlet"), sentencesGT); - Assert.AreEqual(manager.GetPhrases("Ophelia"), new string[] { phrases[4].Item3, phrases[0].Item3 }); + Assert.AreEqual(manager.GetPhrases("Ophelia"), new string[] { phrases[4].Item2, phrases[0].Item2 }); } [Test] @@ -99,7 +99,7 @@ public void TestSaveLoad() Assert.AreEqual(manager.NumSentences(), loadedManager.NumSentences()); Assert.AreEqual(manager.NumPhrases(), loadedManager.NumPhrases()); - manager.Remove(null, null, phrases[2].Item3); + manager.Remove(null, phrases[2].Item2); Assert.AreEqual(manager.NumPhrases("Hamlet"), 2); Assert.AreEqual(manager.NumSentences("Hamlet"), 4); } @@ -112,14 +112,14 @@ public void TestSearch() manager.Add(phrase.Item1, phrase.Item2, phrase.Item3); manager.Add("Ophelia", phrases[0].Item2, phrases[0].Item3); - string[] results = manager.SearchPhrases(phrases[0].Item3, 2); - Assert.AreEqual(results, new string[] { phrases[0].Item3, phrases[0].Item3 }); + string[] results = manager.SearchPhrases(phrases[0].Item2, 2); + Assert.AreEqual(results, new string[] { phrases[0].Item2, phrases[0].Item2 }); - results = manager.SearchPhrases(phrases[0].Item3, 2, "Hamlet"); - Assert.AreEqual(results[0], phrases[0].Item3); - Assert.AreNotEqual(results[1], phrases[0].Item3); - results = manager.SearchPhrases(phrases[1].Item3, 1, "Ophelia"); - Assert.AreNotEqual(results[0], phrases[1].Item3); + results = manager.SearchPhrases(phrases[0].Item2, 2, "Hamlet"); + Assert.AreEqual(results[0], phrases[0].Item2); + Assert.AreNotEqual(results[1], phrases[0].Item2); + results = manager.SearchPhrases(phrases[1].Item2, 1, "Ophelia"); + Assert.AreNotEqual(results[0], phrases[1].Item2); } } } From b8c4024a5e2f94cad73808cd3cfec89dd72ef750 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Mon, 12 Feb 2024 16:35:25 +0200 Subject: [PATCH 097/161] always use sentence trimming, delimiters as string, simplify search for up to 1 dialogue part --- Runtime/Dialogue.cs | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/Runtime/Dialogue.cs b/Runtime/Dialogue.cs index 96285ff8..453fd1af 100644 --- a/Runtime/Dialogue.cs +++ b/Runtime/Dialogue.cs @@ -15,35 +15,22 @@ public class Dialogue { Dictionary> dialogueParts; [DataMember] - char[] delimiters = SentenceSplitter.DefaultDelimiters; - [DataMember] - bool trimSentences = true; + string delimiters; [DataMember] EmbeddingModel embedder; - public Dialogue(EmbeddingModel embedder) + public Dialogue(EmbeddingModel embedder, string delimiters = SentenceSplitter.DefaultDelimiters) { dialogueParts = new Dictionary>(); this.embedder = embedder; - } - - public void SetSentenceSplitting(char[] delimiters, bool trimSentences = true) - { this.delimiters = delimiters; - this.trimSentences = trimSentences; - } - - public void SetNoSentenceSplitting() - { - SetSentenceSplitting(null); } - public void Add(string actor, string text, string title="") + public void Add(string actor, string text, string title = "") { if (!dialogueParts.ContainsKey(actor) || !dialogueParts[actor].ContainsKey(title)) { - SearchEngine search = new SearchEngine(embedder); - search.SetSentenceSplitting(delimiters, trimSentences); + SearchEngine search = new SearchEngine(embedder, delimiters); if (!dialogueParts.ContainsKey(actor)) { dialogueParts[actor] = new Dictionary(); @@ -53,7 +40,7 @@ public void Add(string actor, string text, string title="") dialogueParts[actor][title].Add(text); } - public int Remove(string actor, string text, string title=null) + public int Remove(string actor, string text, string title = null) { List dialogueParts = Filter(actor, title); int removed = 0; @@ -104,11 +91,21 @@ public string[] GetSentences(string actor = null, string title = null) public string[] Search(string queryString, int k, out float[] distances, string actor = null, string title = null, bool returnSentences = false) { List dialogueParts = Filter(actor, title); - ConcurrentBag<(string, float)> resultPairs = new ConcurrentBag<(string, float)>(); + if (dialogueParts.Count == 0) + { + distances = null; + return null; + } + if (dialogueParts.Count == 1) + { + return dialogueParts[0].Search(queryString, k, out distances, returnSentences); + } TensorFloat encodingTensor = embedder.Encode(queryString); encodingTensor.MakeReadable(); float[] encoding = encodingTensor.ToReadOnlyArray(); + + ConcurrentBag<(string, float)> resultPairs = new ConcurrentBag<(string, float)>(); Task.Run(() => { Parallel.ForEach(dialogueParts, dialogue => From db8a5a4b67c1166f89a385b99cd9b9527151aac5 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Mon, 12 Feb 2024 16:35:54 +0200 Subject: [PATCH 098/161] always use sentence trimming, delimiters as string --- Runtime/Search.cs | 40 ++++++++-------------------------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/Runtime/Search.cs b/Runtime/Search.cs index 958fe7b4..a7b48175 100644 --- a/Runtime/Search.cs +++ b/Runtime/Search.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System; using System.Linq; using System.Runtime.Serialization; using System.IO; @@ -45,20 +44,15 @@ public Phrase(string text, List sentenceIds) [DataContract] public class SentenceSplitter { - public static char[] DefaultDelimiters = new char[] { '.', '!', ':', ';', '?', '\n', '\r', }; + public const string DefaultDelimiters = ".!:;?\n\r"; [DataMember] - char[] delimiters; - [DataMember] - bool trimSentences = true; + string delimiters; - public SentenceSplitter(char[] delimiters, bool trimSentences = true) + public SentenceSplitter(string delimiters = DefaultDelimiters) { this.delimiters = delimiters; - this.trimSentences = trimSentences; } - public SentenceSplitter() : this(DefaultDelimiters, true) {} - public List<(int, int)> Split(string input) { List<(int, int)> indices = new List<(int, int)>(); @@ -66,7 +60,7 @@ public SentenceSplitter() : this(DefaultDelimiters, true) {} bool sawDelimiter = true; for (int i = 0; i < input.Length; i++) { - if (sawDelimiter && trimSentences) + if (sawDelimiter) { while (char.IsWhiteSpace(input[i]) && i < input.Length - 1) i++; startIndex = i; @@ -75,11 +69,11 @@ public SentenceSplitter() : this(DefaultDelimiters, true) {} if (delimiters.Contains(input[i]) || i == input.Length - 1) { int endIndex = i; - if (i == input.Length - 1 && trimSentences) + if (i == input.Length - 1) { while (char.IsWhiteSpace(input[endIndex]) && endIndex > startIndex) endIndex--; } - if (endIndex > startIndex || !trimSentences || (trimSentences && !char.IsWhiteSpace(input[startIndex]) && !delimiters.Contains(input[startIndex]))) + if (endIndex > startIndex || (!char.IsWhiteSpace(input[startIndex]) && !delimiters.Contains(input[startIndex]))) { indices.Add((startIndex, endIndex)); } @@ -116,32 +110,14 @@ public class SearchEngine SentenceSplitter sentenceSplitter; ANNModelSearch searchMethod; - public SearchEngine(EmbeddingModel embedder) + public SearchEngine(EmbeddingModel embedder, string delimiters = SentenceSplitter.DefaultDelimiters) { phrases = new SortedDictionary(); sentences = new SortedDictionary(); - sentenceSplitter = new SentenceSplitter(); + sentenceSplitter = delimiters == null ? null : new SentenceSplitter(delimiters); searchMethod = new ANNModelSearch(embedder); } - public void SetSentenceSplitting(char[] delimiters, bool trimSentences = true) - { - if (sentences.Count > 0) throw new Exception("Sentence splitting can't change when there are phrases in the Search"); - if (delimiters == null) - { - sentenceSplitter = null; - } - else - { - sentenceSplitter = new SentenceSplitter(delimiters, trimSentences); - } - } - - public void SetNoSentenceSplitting() - { - SetSentenceSplitting(null); - } - public void SetSearchMethod(ANNModelSearch searchMethod) { this.searchMethod = searchMethod; From 2b170488c1bbec631a1f471aed7656dc3d4ce64e Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Mon, 12 Feb 2024 16:36:25 +0200 Subject: [PATCH 099/161] adapt tests to delimiters and trimming --- Tests/Runtime/TestSearch.cs | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/Tests/Runtime/TestSearch.cs b/Tests/Runtime/TestSearch.cs index a6d4a949..c15a1cda 100644 --- a/Tests/Runtime/TestSearch.cs +++ b/Tests/Runtime/TestSearch.cs @@ -12,9 +12,7 @@ public class TestSentenceSplitter public void TestSplit() { SentenceSplitter splitter = new SentenceSplitter(); - SentenceSplitter splitterNoTrim = new SentenceSplitter(SentenceSplitter.DefaultDelimiters, false); - SentenceSplitter splitterQuestion = new SentenceSplitter(new char[] { '?' }, true); - SentenceSplitter splitterQuestionNoTrim = new SentenceSplitter(new char[] { '?' }, false); + SentenceSplitter splitterQuestion = new SentenceSplitter("?"); string[] sentences = new string[]{ "hi.", @@ -48,13 +46,6 @@ public void TestSplit() sentencesBack = SentenceSplitter.IndicesToSentences(textMultiSpace, splitter.Split(textMultiSpace)); Assert.AreEqual(sentences, sentencesBack); - //splitterNoTrim - sentencesBack = SentenceSplitter.IndicesToSentences(text, splitterNoTrim.Split(text)); - Assert.AreEqual(sentences, sentencesBack); - - sentencesBack = SentenceSplitter.IndicesToSentences(textSpace, splitterNoTrim.Split(textSpace)); - Assert.AreEqual(sentencesSpace, sentencesBack); - //splitterQuestion sentencesGT = new string[] { sentences[0] + sentences[1], sentences[2] + sentences[3] }; sentencesBack = SentenceSplitter.IndicesToSentences(text, splitterQuestion.Split(text)); @@ -67,16 +58,6 @@ public void TestSplit() sentencesGT = new string[] { sentences[0] + " " + sentences[1], sentences[2] + sentences[3] }; sentencesBack = SentenceSplitter.IndicesToSentences(textMultiSpace, splitterQuestion.Split(textMultiSpace)); Assert.AreEqual(sentencesGT, sentencesBack); - - //splitterQuestionNoTrim - sentencesGT = new string[] { sentences[0] + sentences[1], sentences[2] + sentences[3] }; - sentencesBack = SentenceSplitter.IndicesToSentences(text, splitterQuestionNoTrim.Split(text)); - Assert.AreEqual(sentencesGT, sentencesBack); - - sentencesGT = new string[] { sentencesSpace[0] + sentencesSpace[1], sentencesSpace[2] + sentencesSpace[3] }; - sentencesBack = SentenceSplitter.IndicesToSentences(textSpace, splitterQuestionNoTrim.Split(textSpace)); - Assert.AreEqual(sentencesGT, sentencesBack); - } } @@ -237,4 +218,4 @@ public void TestSaveLoad() Assert.That(ApproxEqual(distances[1], 1 - trueSimilarity)); } } -} \ No newline at end of file +} From 0b92a67f21f4a4b6bb09dedc5a534571b76ca2d0 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Mon, 12 Feb 2024 18:26:38 +0200 Subject: [PATCH 100/161] set knn to 1 by default, add all sentences of a phrase in a batch --- Runtime/Dialogue.cs | 10 +++++----- Runtime/Search.cs | 14 ++++++++------ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Runtime/Dialogue.cs b/Runtime/Dialogue.cs index 453fd1af..53ca9066 100644 --- a/Runtime/Dialogue.cs +++ b/Runtime/Dialogue.cs @@ -26,7 +26,7 @@ public Dialogue(EmbeddingModel embedder, string delimiters = SentenceSplitter.De this.delimiters = delimiters; } - public void Add(string actor, string text, string title = "") + public void Add(string text, string actor="", string title = "") { if (!dialogueParts.ContainsKey(actor) || !dialogueParts[actor].ContainsKey(title)) { @@ -40,7 +40,7 @@ public void Add(string actor, string text, string title = "") dialogueParts[actor][title].Add(text); } - public int Remove(string actor, string text, string title = null) + public int Remove(string text, string actor=null, string title = null) { List dialogueParts = Filter(actor, title); int removed = 0; @@ -130,7 +130,7 @@ public string[] Search(string queryString, int k, out float[] distances, string return results; } - public string[] Search(string queryString, int k, string actor = null, string title = null, bool returnSentences = false) + public string[] Search(string queryString, int k=1, string actor = null, string title = null, bool returnSentences = false) { return Search(queryString, k, out float[] distances, actor, title, returnSentences); } @@ -140,7 +140,7 @@ public string[] SearchPhrases(string queryString, int k, out float[] distances, return Search(queryString, k, out distances, actor, title, false); } - public string[] SearchPhrases(string queryString, int k, string actor = null, string title = null) + public string[] SearchPhrases(string queryString, int k=1, string actor = null, string title = null) { return SearchPhrases(queryString, k, out float[] distances, actor, title); } @@ -150,7 +150,7 @@ public string[] SearchSentences(string queryString, int k, out float[] distances return Search(queryString, k, out distances, actor, title, true); } - public string[] SearchSentences(string queryString, int k, string actor = null, string title = null) + public string[] SearchSentences(string queryString, int k=1, string actor = null, string title = null) { return SearchSentences(queryString, k, out float[] distances, actor, title); } diff --git a/Runtime/Search.cs b/Runtime/Search.cs index a7b48175..c690fe7e 100644 --- a/Runtime/Search.cs +++ b/Runtime/Search.cs @@ -147,14 +147,16 @@ public void Add(string text) int phraseId = nextPhraseId++; Phrase phrase = new Phrase(text); phrases[phraseId] = phrase; + List sentenceTexts = new List(); foreach ((int startIndex, int endIndex) in subindices) { int sentenceId = nextSentenceId++; Sentence sentence = new Sentence(phraseId, startIndex, endIndex); sentences[sentenceId] = sentence; phrase.sentenceIds.Add(sentenceId); - searchMethod?.Add(sentenceId, GetSentence(sentence)); + sentenceTexts.Add(GetSentence(sentence)); } + searchMethod.Add(phrase.sentenceIds, sentenceTexts); } public int Remove(string text) @@ -168,7 +170,7 @@ public int Remove(string text) foreach (int sentenceId in phrase.sentenceIds) { sentences.Remove(sentenceId); - searchMethod?.Remove(sentenceId); + searchMethod.Remove(sentenceId); } removePhraseIds.Add(phrasePair.Key); } @@ -248,12 +250,12 @@ public string[] Search(float[] encoding, int k, out float[] distances, bool retu } } - public string[] Search(float[] encoding, int k, bool returnSentences = false) + public string[] Search(float[] encoding, int k=1, bool returnSentences = false) { return Search(encoding, k, out float[] distances, returnSentences); } - public string[] Search(string queryString, int k, bool returnSentences = false) + public string[] Search(string queryString, int k=1, bool returnSentences = false) { return Search(queryString, k, out float[] distances, returnSentences); } @@ -263,7 +265,7 @@ public string[] SearchPhrases(string queryString, int k, out float[] distances) return Search(queryString, k, out distances, false); } - public string[] SearchPhrases(string queryString, int k) + public string[] SearchPhrases(string queryString, int k=1) { return SearchPhrases(queryString, k, out float[] distances); } @@ -273,7 +275,7 @@ public string[] SearchSentences(string queryString, int k, out float[] distances return Search(queryString, k, out distances, true); } - public string[] SearchSentences(string queryString, int k) + public string[] SearchSentences(string queryString, int k=1) { return SearchSentences(queryString, k, out float[] distances); } From b42bc9d1db9a2ac324c38045e867b17ef6d3205f Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Mon, 12 Feb 2024 18:28:08 +0200 Subject: [PATCH 101/161] adapt order in add/remve in tests --- Tests/Runtime/TestDialogue.cs | 44 +++++++++++++++++------------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/Tests/Runtime/TestDialogue.cs b/Tests/Runtime/TestDialogue.cs index 64a64414..d2bf80e0 100644 --- a/Tests/Runtime/TestDialogue.cs +++ b/Tests/Runtime/TestDialogue.cs @@ -12,11 +12,11 @@ public class TestDialogueManager string modelPath; string tokenizerPath; List<(string, string, string)> phrases = new List<(string, string, string)>(){ - ("Hamlet", "To be, or not to be, that is the question. Whether tis nobler in the mind to suffer.", "ACT I"), - ("Hamlet", "Or to take arms against a sea of troubles, and by opposing end them? To die—to sleep.", "ACT I"), - ("Hamlet", "I humbly thank you; well, well, well.", "ACT II"), - ("Ophelia", "Good my lord.", "ACT II"), - ("Ophelia", "How does your honour for this many a day?", "ACT II") + ("To be, or not to be, that is the question. Whether tis nobler in the mind to suffer.", "Hamlet", "ACT I"), + ("Or to take arms against a sea of troubles, and by opposing end them? To die—to sleep.", "Hamlet", "ACT I"), + ("I humbly thank you; well, well, well.", "Hamlet", "ACT II"), + ("Good my lord.", "Ophelia", "ACT II"), + ("How does your honour for this many a day?", "Ophelia", "ACT II") }; [SetUp] @@ -52,8 +52,8 @@ public void TestAdd() Assert.AreEqual(manager.NumPhrases("Hamlet", "ACT I"), 2); Assert.AreEqual(manager.NumSentences("Hamlet", "ACT II"), 2); - Assert.AreEqual(manager.GetPhrases("Hamlet", "ACT II"), new string[] { phrases[2].Item2 }); - string[] sentencesGT = phrases[2].Item2.Split(";"); + Assert.AreEqual(manager.GetPhrases("Hamlet", "ACT II"), new string[] { phrases[2].Item1 }); + string[] sentencesGT = phrases[2].Item1.Split(";"); sentencesGT[0] += ";"; sentencesGT[1] = sentencesGT[1].Trim(); Assert.AreEqual(manager.GetSentences("Hamlet", "ACT II"), sentencesGT); @@ -61,24 +61,24 @@ public void TestAdd() manager.Add(phrases[3].Item1, phrases[3].Item2, phrases[3].Item3); Assert.AreEqual(manager.NumPhrases("Ophelia"), 3); Assert.AreEqual(manager.NumSentences("Ophelia"), 3); - manager.Remove(null, phrases[2].Item2); + manager.Remove(phrases[2].Item1); Assert.AreEqual(manager.NumPhrases("Hamlet"), 2); Assert.AreEqual(manager.NumSentences("Hamlet"), 4); - manager.Remove(null, phrases[3].Item2); + manager.Remove(phrases[3].Item1); Assert.AreEqual(manager.NumPhrases("Ophelia"), 1); Assert.AreEqual(manager.NumSentences("Ophelia"), 1); - manager.Add("Ophelia", phrases[0].Item2, phrases[0].Item3); - manager.Remove("Hamlet", phrases[0].Item2); + manager.Add(phrases[0].Item1, "Ophelia", phrases[0].Item3); + manager.Remove(phrases[0].Item1, "Hamlet"); Assert.AreEqual(manager.NumPhrases("Ophelia"), 2); Assert.AreEqual(manager.NumSentences("Ophelia"), 3); Assert.AreEqual(manager.NumPhrases("Hamlet"), 1); Assert.AreEqual(manager.NumSentences("Hamlet"), 2); - sentencesGT = phrases[1].Item2.Split("?"); + sentencesGT = phrases[1].Item1.Split("?"); sentencesGT[0] += "?"; sentencesGT[1] = sentencesGT[1].Trim(); Assert.AreEqual(manager.GetSentences("Hamlet"), sentencesGT); - Assert.AreEqual(manager.GetPhrases("Ophelia"), new string[] { phrases[4].Item2, phrases[0].Item2 }); + Assert.AreEqual(manager.GetPhrases("Ophelia"), new string[] { phrases[4].Item1, phrases[0].Item1 }); } [Test] @@ -99,7 +99,7 @@ public void TestSaveLoad() Assert.AreEqual(manager.NumSentences(), loadedManager.NumSentences()); Assert.AreEqual(manager.NumPhrases(), loadedManager.NumPhrases()); - manager.Remove(null, phrases[2].Item2); + manager.Remove(phrases[2].Item1); Assert.AreEqual(manager.NumPhrases("Hamlet"), 2); Assert.AreEqual(manager.NumSentences("Hamlet"), 4); } @@ -110,16 +110,16 @@ public void TestSearch() Dialogue manager = new Dialogue(model); foreach (var phrase in phrases) manager.Add(phrase.Item1, phrase.Item2, phrase.Item3); - manager.Add("Ophelia", phrases[0].Item2, phrases[0].Item3); + manager.Add(phrases[0].Item1, "Ophelia", phrases[0].Item3); - string[] results = manager.SearchPhrases(phrases[0].Item2, 2); - Assert.AreEqual(results, new string[] { phrases[0].Item2, phrases[0].Item2 }); + string[] results = manager.SearchPhrases(phrases[0].Item1, 2); + Assert.AreEqual(results, new string[] { phrases[0].Item1, phrases[0].Item1 }); - results = manager.SearchPhrases(phrases[0].Item2, 2, "Hamlet"); - Assert.AreEqual(results[0], phrases[0].Item2); - Assert.AreNotEqual(results[1], phrases[0].Item2); - results = manager.SearchPhrases(phrases[1].Item2, 1, "Ophelia"); - Assert.AreNotEqual(results[0], phrases[1].Item2); + results = manager.SearchPhrases(phrases[0].Item1, 2, "Hamlet"); + Assert.AreEqual(results[0], phrases[0].Item1); + Assert.AreNotEqual(results[1], phrases[0].Item1); + results = manager.SearchPhrases(phrases[1].Item1, 1, "Ophelia"); + Assert.AreNotEqual(results[0], phrases[1].Item1); } } } From 2ea2f491181d3f71183f257db7f898176bbbe5ee Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Mon, 12 Feb 2024 18:28:38 +0200 Subject: [PATCH 102/161] text interaction with hamlet --- Samples~/HamletSearch/HamletSearch.cs | 98 ++- Samples~/HamletSearch/Scene.unity | 885 +++++++++++++++++++++++++- 2 files changed, 955 insertions(+), 28 deletions(-) diff --git a/Samples~/HamletSearch/HamletSearch.cs b/Samples~/HamletSearch/HamletSearch.cs index e3982512..dce2e256 100644 --- a/Samples~/HamletSearch/HamletSearch.cs +++ b/Samples~/HamletSearch/HamletSearch.cs @@ -4,56 +4,100 @@ using Debug = UnityEngine.Debug; using System.Text.RegularExpressions; using LLMUnity; +using System.IO; +using UnityEngine.UI; +using Unity.VisualScripting; class HamletSearch : MonoBehaviour { + public InputField playerText; + public Text AIText; public Embedding embedding; - public bool fullPlay; public TextAsset gutenbergText; + Dialogue dialogue; + void Start() { + StartCoroutine(InitDialogue()); + } + + IEnumerator InitDialogue() + { + playerText.interactable = false; + EmbeddingModel model = embedding.GetModel(); if (model == null) { throw new System.Exception("Please select an embedding model in the HamletSearch GameObject!"); } - Dictionary> hamlet = ReadGutenbergFile(gutenbergText.text); - Dialogue dialogueManager = new Dialogue(model); - Stopwatch stopwatch = new Stopwatch(); - - float elapsedTotal = 0; - foreach ((string act, List<(string, string)> messages) in hamlet) + string sampleDir = Path.GetDirectoryName(Directory.GetFiles(Application.dataPath, "HamletSearch.cs", SearchOption.AllDirectories)[0]); + string filename = Path.Combine(sampleDir, "embeddings.zip"); + if (File.Exists(filename)) { - if (!fullPlay && act != "ACT III") continue; - stopwatch.Reset(); stopwatch.Start(); - foreach ((string actor, string message) in messages) - dialogueManager.Add(actor, message, act); + playerText.text = "Loading dialogues..."; + yield return null; + dialogue = Dialogue.Load(filename); + } + else + { + playerText.text = "Creating embeddings..."; + yield return null; + dialogue = CreateEmbeddings(filename); + } + + playerText.interactable = true; + InitPlayerText(); + } - elapsedTotal += (float)stopwatch.Elapsed.TotalMilliseconds / 1000f; - Debug.Log($"act {act} embedded {dialogueManager.GetSentences(null, act).Length} sentences in {stopwatch.Elapsed.TotalMilliseconds / 1000f} secs"); + void InitPlayerText() + { + playerText.onSubmit.AddListener(onInputFieldSubmit); + playerText.onValueChanged.AddListener(onValueChanged); + playerText.Select(); + playerText.text = ""; + } + + void onValueChanged(string newText) + { + // Get rid of newline character added when we press enter + if (Input.GetKey(KeyCode.Return)) + { + if (playerText.text.Trim() == "") + playerText.text = ""; } - Debug.Log($"embedded {dialogueManager.NumPhrases()} phrases, {dialogueManager.NumSentences()} sentences in {elapsedTotal} secs"); + } - stopwatch.Reset(); stopwatch.Start(); - dialogueManager.Save("test.zip"); - Debug.Log($"saving took {stopwatch.Elapsed.TotalMilliseconds / 1000f} secs"); + void onInputFieldSubmit(string message) + { + playerText.interactable = false; + AIText.text = dialogue.Search(message)[0]; + playerText.interactable = true; + playerText.Select(); + playerText.text = ""; + } - stopwatch.Reset(); stopwatch.Start(); - dialogueManager = Dialogue.Load("test.zip"); - Debug.Log($"loading took {stopwatch.Elapsed.TotalMilliseconds / 1000f} secs"); + Dialogue CreateEmbeddings(string filename) + { + Dialogue dialogue; - stopwatch.Reset(); stopwatch.Start(); - string[] similar = dialogueManager.Search("should i be?", 10); - stopwatch.Stop(); - Debug.Log($"search time: {stopwatch.Elapsed.TotalMilliseconds / 1000f} secs"); + Dictionary> hamlet = ReadGutenbergFile(gutenbergText.text); + dialogue = new Dialogue(embedding.GetModel()); - Debug.Log("Similar sentences:"); - for (int i = 0; i < similar.Length; i++) + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Start(); + foreach ((string act, List<(string, string)> messages) in hamlet) { - Debug.Log($" {i + 1}: {similar[i]}"); + foreach ((string actor, string message) in messages) + { + if (actor == "HAMLET") dialogue.Add(message); + } } + Debug.Log($"embedded {dialogue.NumPhrases()} phrases, {dialogue.NumSentences()} sentences in {stopwatch.Elapsed.TotalMilliseconds / 1000f} secs"); + + dialogue.Save(filename); + return dialogue; } public Dictionary> ReadGutenbergFile(string text) diff --git a/Samples~/HamletSearch/Scene.unity b/Samples~/HamletSearch/Scene.unity index d6edc468..02c20071 100644 --- a/Samples~/HamletSearch/Scene.unity +++ b/Samples~/HamletSearch/Scene.unity @@ -123,6 +123,240 @@ NavMeshSettings: debug: m_Flags: 0 m_NavMeshData: {fileID: 0} +--- !u!1 &51303809 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 51303810} + - component: {fileID: 51303812} + - component: {fileID: 51303811} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &51303810 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 51303809} + 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: 1736746841} + 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 &51303811 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 51303809} + 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 &51303812 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 51303809} + m_CullTransparentMesh: 1 +--- !u!1 &102275135 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 102275136} + - component: {fileID: 102275138} + - component: {fileID: 102275137} + 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 &102275136 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 102275135} + 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: 1532498605} + 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: 21, y: 150} + m_SizeDelta: {x: 160, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &102275137 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 102275135} + 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 &102275138 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 102275135} + m_CullTransparentMesh: 1 +--- !u!1 &584920166 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 584920167} + - component: {fileID: 584920169} + - component: {fileID: 584920168} + m_Layer: 5 + m_Name: AIImage + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &584920167 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 584920166} + 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: 957066421} + m_Father: {fileID: 1532498605} + 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.375977, y: -110.75391} + m_SizeDelta: {x: 400, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &584920168 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 584920166} + 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 &584920169 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 584920166} + m_CullTransparentMesh: 1 --- !u!1 &705507993 GameObject: m_ObjectHideFlags: 0 @@ -217,6 +451,173 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &745605586 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 745605587} + - component: {fileID: 745605589} + - component: {fileID: 745605588} + m_Layer: 5 + m_Name: Panel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &745605587 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 745605586} + 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: 1532498605} + 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 &745605588 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 745605586} + 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 &745605589 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 745605586} + m_CullTransparentMesh: 1 +--- !u!1 &957066420 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 957066421} + - component: {fileID: 957066424} + - component: {fileID: 957066423} + - component: {fileID: 957066422} + m_Layer: 5 + m_Name: AIText + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &957066421 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 957066420} + 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: 584920167} + 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!210 &957066422 +SortingGroup: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 957066420} + m_Enabled: 1 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 1 + m_SortAtRoot: 0 +--- !u!114 &957066423 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 957066420} + 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 &957066424 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 957066420} + m_CullTransparentMesh: 1 --- !u!1 &963194225 GameObject: m_ObjectHideFlags: 0 @@ -309,6 +710,484 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1091921148 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1091921149} + - component: {fileID: 1091921151} + - component: {fileID: 1091921150} + 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 &1091921149 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1091921148} + 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: 1736746841} + 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 &1091921150 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1091921148} + 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 &1091921151 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1091921148} + m_CullTransparentMesh: 1 +--- !u!1 &1427556278 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1427556279} + - component: {fileID: 1427556281} + - component: {fileID: 1427556280} + 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 &1427556279 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1427556278} + 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: 1532498605} + 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: 16, y: -46} + m_SizeDelta: {x: 160, y: 29.6652} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1427556280 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1427556278} + 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 &1427556281 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1427556278} + m_CullTransparentMesh: 1 +--- !u!1 &1532498601 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1532498605} + - component: {fileID: 1532498604} + - component: {fileID: 1532498603} + - component: {fileID: 1532498602} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1532498602 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1532498601} + 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 &1532498603 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1532498601} + 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: 1280, y: 720} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!223 &1532498604 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1532498601} + 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 &1532498605 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1532498601} + 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: 745605587} + - {fileID: 1736746841} + - {fileID: 584920167} + - {fileID: 102275136} + - {fileID: 1427556279} + 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 &1736746840 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1736746841} + - component: {fileID: 1736746844} + - component: {fileID: 1736746843} + - component: {fileID: 1736746842} + m_Layer: 5 + m_Name: PlayerInput + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1736746841 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1736746840} + 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: 51303810} + - {fileID: 1091921149} + m_Father: {fileID: 1532498605} + 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.375977, y: 87.00699} + m_SizeDelta: {x: 400, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1736746842 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1736746840} + 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: 1736746843} + m_TextComponent: {fileID: 1091921150} + m_Placeholder: {fileID: 51303811} + 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 &1736746843 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1736746840} + 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 &1736746844 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1736746840} + m_CullTransparentMesh: 1 +--- !u!1 &1745045320 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1745045323} + - component: {fileID: 1745045322} + - component: {fileID: 1745045321} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1745045321 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1745045320} + 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 &1745045322 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1745045320} + 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 &1745045323 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1745045320} + 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 &1842083044 GameObject: m_ObjectHideFlags: 0 @@ -339,8 +1218,9 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 8813eb3f4b7c900538f904cbd42e0a7f, type: 3} m_Name: m_EditorClassIdentifier: + playerText: {fileID: 1736746842} + AIText: {fileID: 957066423} embedding: {fileID: 1842083047} - fullPlay: 0 gutenbergText: {fileID: 4900000, guid: be0ffe8c7b44139218ffd530749f1644, type: 3} --- !u!4 &1842083046 Transform: @@ -372,10 +1252,13 @@ MonoBehaviour: Model: GPU: 0 SelectedOption: 1 + downloadProgress: 1 --- !u!1660057539 &9223372036854775807 SceneRoots: m_ObjectHideFlags: 0 m_Roots: - {fileID: 963194228} - {fileID: 705507995} + - {fileID: 1532498605} + - {fileID: 1745045323} - {fileID: 1842083046} From 0c70a920b499a01ee9f99d6ccc7a9b852e185dc5 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Tue, 13 Feb 2024 07:01:26 +0200 Subject: [PATCH 103/161] search for the samples dir instead of the file --- Samples~/HamletSearch/HamletSearch.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Samples~/HamletSearch/HamletSearch.cs b/Samples~/HamletSearch/HamletSearch.cs index dce2e256..7133b8ea 100644 --- a/Samples~/HamletSearch/HamletSearch.cs +++ b/Samples~/HamletSearch/HamletSearch.cs @@ -32,7 +32,7 @@ IEnumerator InitDialogue() throw new System.Exception("Please select an embedding model in the HamletSearch GameObject!"); } - string sampleDir = Path.GetDirectoryName(Directory.GetFiles(Application.dataPath, "HamletSearch.cs", SearchOption.AllDirectories)[0]); + string sampleDir = Directory.GetDirectories(Application.dataPath, "HamletSearch", SearchOption.AllDirectories)[0]; string filename = Path.Combine(sampleDir, "embeddings.zip"); if (File.Exists(filename)) { From 75fa8356c9e09d4444835419cc6c96cddfd8522c Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Tue, 13 Feb 2024 12:27:59 +0200 Subject: [PATCH 104/161] selectable characters, fix content fit --- Samples~/HamletSearch/HamletSearch.cs | 77 +- Samples~/HamletSearch/Scene.unity | 1548 +++++++++++++++++++++++-- 2 files changed, 1472 insertions(+), 153 deletions(-) diff --git a/Samples~/HamletSearch/HamletSearch.cs b/Samples~/HamletSearch/HamletSearch.cs index 7133b8ea..1ddcd1b9 100644 --- a/Samples~/HamletSearch/HamletSearch.cs +++ b/Samples~/HamletSearch/HamletSearch.cs @@ -6,84 +6,95 @@ using LLMUnity; using System.IO; using UnityEngine.UI; -using Unity.VisualScripting; class HamletSearch : MonoBehaviour { - public InputField playerText; + public Dropdown CharacterSelect; + public InputField PlayerText; public Text AIText; - public Embedding embedding; - public TextAsset gutenbergText; + public Embedding Embedding; + public TextAsset GutenbergText; + string Character; Dialogue dialogue; void Start() { StartCoroutine(InitDialogue()); + CharacterSelect.onValueChanged.AddListener(DropdownChange); } IEnumerator InitDialogue() { - playerText.interactable = false; + PlayerText.interactable = false; - EmbeddingModel model = embedding.GetModel(); + EmbeddingModel model = Embedding.GetModel(); if (model == null) { - throw new System.Exception("Please select an embedding model in the HamletSearch GameObject!"); + throw new System.Exception("Please select an Embedding model in the HamletSearch GameObject!"); } string sampleDir = Directory.GetDirectories(Application.dataPath, "HamletSearch", SearchOption.AllDirectories)[0]; - string filename = Path.Combine(sampleDir, "embeddings.zip"); + string filename = Path.Combine(sampleDir, "Embeddings.zip"); if (File.Exists(filename)) { - playerText.text = "Loading dialogues..."; + PlayerText.text = "Loading dialogues..."; yield return null; dialogue = Dialogue.Load(filename); } else { - playerText.text = "Creating embeddings..."; + PlayerText.text = "Creating Embeddings..."; yield return null; dialogue = CreateEmbeddings(filename); } - playerText.interactable = true; + PlayerText.interactable = true; InitPlayerText(); } void InitPlayerText() { - playerText.onSubmit.AddListener(onInputFieldSubmit); - playerText.onValueChanged.AddListener(onValueChanged); - playerText.Select(); - playerText.text = ""; + DropdownChange(CharacterSelect.value); + PlayerText.onSubmit.AddListener(OnInputFieldSubmit); + PlayerText.onValueChanged.AddListener(OnValueChanged); + PlayerText.Select(); + PlayerText.text = ""; } - void onValueChanged(string newText) + void OnValueChanged(string newText) { // Get rid of newline character added when we press enter if (Input.GetKey(KeyCode.Return)) { - if (playerText.text.Trim() == "") - playerText.text = ""; + if (PlayerText.text.Trim() == "") + PlayerText.text = ""; } } - void onInputFieldSubmit(string message) + void OnInputFieldSubmit(string message) { - playerText.interactable = false; - AIText.text = dialogue.Search(message)[0]; - playerText.interactable = true; - playerText.Select(); - playerText.text = ""; + PlayerText.interactable = false; + AIText.text = dialogue.Search(message, 1, Character)[0]; + // if you want only Hamlet, you could instead do: + // AIText.text = dialogue.Search(message)[0]; + PlayerText.interactable = true; + PlayerText.Select(); + PlayerText.text = ""; + } + + void DropdownChange(int selection) + { + Character = CharacterSelect.options[selection].text.ToUpper(); + Debug.Log($"{Character}: {dialogue.NumPhrases(Character)} phrases available"); } Dialogue CreateEmbeddings(string filename) { Dialogue dialogue; - Dictionary> hamlet = ReadGutenbergFile(gutenbergText.text); - dialogue = new Dialogue(embedding.GetModel()); + Dictionary> hamlet = ReadGutenbergFile(GutenbergText.text); + dialogue = new Dialogue(Embedding.GetModel()); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); @@ -91,7 +102,9 @@ Dialogue CreateEmbeddings(string filename) { foreach ((string actor, string message) in messages) { - if (actor == "HAMLET") dialogue.Add(message); + dialogue.Add(message, actor); + // if you want only Hamlet, you could instead do: + // if (actor == "HAMLET") dialogue.Add(message); } } Debug.Log($"embedded {dialogue.NumPhrases()} phrases, {dialogue.NumSentences()} sentences in {stopwatch.Elapsed.TotalMilliseconds / 1000f} secs"); @@ -108,6 +121,7 @@ Dialogue CreateEmbeddings(string filename) string act = null; string name = null; + string name2 = null; string message = ""; bool add = false; Dialogue dialogue = null; @@ -134,10 +148,12 @@ Dialogue CreateEmbeddings(string filename) if (dialogue != null && message != "") { messages[act].Add((name, message)); + if (name2 != null) messages[act].Add((name2, message)); } act = line.Replace(".", ""); messages[act] = new List<(string, string)>(); name = null; + name2 = null; message = ""; } else if (nameRegex.IsMatch(line)) @@ -145,9 +161,16 @@ Dialogue CreateEmbeddings(string filename) if (name != null && message != "") { messages[act].Add((name, message)); + if (name2 != null) messages[act].Add((name2, message)); } message = ""; name = line.Replace(".", ""); + if (name.Contains("and")) + { + string[] names = name.Split(" and "); + name = names[0]; + name2 = names[1]; + } } else if (name != null) { diff --git a/Samples~/HamletSearch/Scene.unity b/Samples~/HamletSearch/Scene.unity index 02c20071..dc354936 100644 --- a/Samples~/HamletSearch/Scene.unity +++ b/Samples~/HamletSearch/Scene.unity @@ -236,7 +236,7 @@ RectTransform: 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: 21, y: 150} + m_AnchoredPosition: {x: 0, y: 180} m_SizeDelta: {x: 160, y: 30} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &102275137 @@ -281,7 +281,7 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 102275135} m_CullTransparentMesh: 1 ---- !u!1 &584920166 +--- !u!1 &191351079 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -289,57 +289,938 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 584920167} - - component: {fileID: 584920169} - - component: {fileID: 584920168} + - component: {fileID: 191351080} + - component: {fileID: 191351082} + - component: {fileID: 191351081} m_Layer: 5 - m_Name: AIImage + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &191351080 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 191351079} + 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: 1532498605} + 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: -235} + m_SizeDelta: {x: 246.7487, y: 54.6133} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &191351081 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 191351079} + 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.6313726, g: 0.6313726, b: 0.6313726, 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: The AI replies with phrases from Hamlet for the selected character. +--- !u!222 &191351082 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 191351079} + m_CullTransparentMesh: 1 +--- !u!1 &272611074 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 272611075} + - component: {fileID: 272611078} + - component: {fileID: 272611077} + - component: {fileID: 272611076} + m_Layer: 5 + m_Name: Character Dropdown + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &272611075 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 272611074} + 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: 863813045} + - {fileID: 1386761193} + - {fileID: 441863968} + m_Father: {fileID: 1532498605} + 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: -12.999996} + m_SizeDelta: {x: 180, y: 36} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &272611076 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 272611074} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0d0b652f32a2cc243917e4028fa0f046, 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: 272611077} + m_Template: {fileID: 441863968} + m_CaptionText: {fileID: 863813046} + m_CaptionImage: {fileID: 0} + m_ItemText: {fileID: 2050714466} + m_ItemImage: {fileID: 0} + m_Value: 0 + m_Options: + m_Options: + - m_Text: Hamlet + m_Image: {fileID: 0} + - m_Text: King + m_Image: {fileID: 0} + - m_Text: Queen + m_Image: {fileID: 0} + - m_Text: Ghost + m_Image: {fileID: 0} + - m_Text: Polonius + m_Image: {fileID: 0} + - m_Text: Laertes + m_Image: {fileID: 0} + - m_Text: Ophelia + m_Image: {fileID: 0} + - m_Text: Horatio + m_Image: {fileID: 0} + - m_Text: Rosencrantz + m_Image: {fileID: 0} + - m_Text: Guildenstern + m_Image: {fileID: 0} + - m_Text: Fortinbras + m_Image: {fileID: 0} + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_AlphaFadeSpeed: 0.15 +--- !u!114 &272611077 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 272611074} + 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.21176471, g: 0.21176471, b: 0.40784314, 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 &272611078 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 272611074} + m_CullTransparentMesh: 1 +--- !u!1 &379533024 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 379533025} + - component: {fileID: 379533027} + - component: {fileID: 379533026} + - component: {fileID: 379533028} + m_Layer: 5 + m_Name: Content + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &379533025 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 379533024} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.99, y: 0.99, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1343354786} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 1} +--- !u!114 &379533026 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 379533024} + 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: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 1 + m_LineSpacing: 1 + m_Text: +--- !u!222 &379533027 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 379533024} + m_CullTransparentMesh: 1 +--- !u!114 &379533028 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 379533024} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalFit: 0 + m_VerticalFit: 2 +--- !u!1 &418740776 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 418740777} + - component: {fileID: 418740779} + - component: {fileID: 418740778} + m_Layer: 5 + m_Name: Item Background + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &418740777 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 418740776} + 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: 448418189} + 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 &418740778 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 418740776} + 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.9607843, g: 0.9607843, b: 0.9607843, 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: 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 &418740779 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 418740776} + m_CullTransparentMesh: 1 +--- !u!1 &441863967 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 441863968} + - component: {fileID: 441863971} + - component: {fileID: 441863970} + - component: {fileID: 441863969} + m_Layer: 5 + m_Name: Template + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &441863968 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 441863967} + 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: 700531766} + - {fileID: 514039264} + m_Father: {fileID: 272611075} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 2} + m_SizeDelta: {x: 0, y: 150} + m_Pivot: {x: 0.5, y: 1} +--- !u!114 &441863969 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 441863967} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1aa08ab6e0800fa44ae55d278d1423e3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Content: {fileID: 1006328273} + m_Horizontal: 0 + m_Vertical: 1 + m_MovementType: 2 + m_Elasticity: 0.1 + m_Inertia: 0 + m_DecelerationRate: 0.135 + m_ScrollSensitivity: 20 + m_Viewport: {fileID: 700531766} + m_HorizontalScrollbar: {fileID: 0} + m_VerticalScrollbar: {fileID: 514039265} + m_HorizontalScrollbarVisibility: 0 + m_VerticalScrollbarVisibility: 2 + m_HorizontalScrollbarSpacing: 0 + m_VerticalScrollbarSpacing: -3 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &441863970 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 441863967} + 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.21176471, g: 0.21176471, b: 0.40784314, 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 &441863971 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 441863967} + m_CullTransparentMesh: 1 +--- !u!1 &448418188 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 448418189} + - component: {fileID: 448418190} + m_Layer: 5 + m_Name: Item + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &448418189 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 448418188} + 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: 418740777} + - {fileID: 1564078633} + - {fileID: 2050714465} + m_Father: {fileID: 1006328273} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 22} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &448418190 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 448418188} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9085046f02f69544eb97fd06b6048fe2, 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.21176471, g: 0.21176471, b: 0.40784314, a: 1} + m_HighlightedColor: {r: 0.29874426, g: 0.29874426, b: 0.6132254, a: 1} + m_PressedColor: {r: 0.21056549, g: 0.21056549, b: 0.46012622, a: 1} + m_SelectedColor: {r: 0.29803923, g: 0.29803923, b: 0.6117647, 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: 418740778} + toggleTransition: 1 + graphic: {fileID: 1564078634} + m_Group: {fileID: 0} + onValueChanged: + m_PersistentCalls: + m_Calls: [] + m_IsOn: 1 +--- !u!1 &514039263 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 514039264} + - component: {fileID: 514039267} + - component: {fileID: 514039266} + - component: {fileID: 514039265} + m_Layer: 5 + m_Name: Scrollbar + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &514039264 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 514039263} + 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: 647783086} + m_Father: {fileID: 441863968} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 20, y: 0} + m_Pivot: {x: 1, y: 1} +--- !u!114 &514039265 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 514039263} + 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: 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: 1169965870} + m_HandleRect: {fileID: 1169965869} + m_Direction: 2 + m_Value: 0 + m_Size: 1 + m_NumberOfSteps: 0 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &514039266 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 514039263} + 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.21176471, g: 0.21176471, b: 0.40784314, 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 &514039267 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 514039263} + m_CullTransparentMesh: 1 +--- !u!1 &647783085 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 647783086} + 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 &647783086 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 647783085} + 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: 1169965869} + m_Father: {fileID: 514039264} + 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!1 &654183275 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 654183276} + - component: {fileID: 654183279} + - component: {fileID: 654183278} + - component: {fileID: 654183277} + m_Layer: 5 + m_Name: AI Scroll View + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &654183276 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 654183275} + 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: 1290703737} + - {fileID: 1343354786} + m_Father: {fileID: 1532498605} + 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: -109.99999} + m_SizeDelta: {x: 500, y: 150} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &654183277 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 654183275} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1aa08ab6e0800fa44ae55d278d1423e3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Content: {fileID: 379533025} + m_Horizontal: 0 + m_Vertical: 1 + m_MovementType: 2 + m_Elasticity: 0.1 + m_Inertia: 0 + m_DecelerationRate: 0.135 + m_ScrollSensitivity: 20 + m_Viewport: {fileID: 1343354786} + m_HorizontalScrollbar: {fileID: 0} + m_VerticalScrollbar: {fileID: 0} + m_HorizontalScrollbarVisibility: 2 + m_VerticalScrollbarVisibility: 2 + m_HorizontalScrollbarSpacing: -3 + m_VerticalScrollbarSpacing: -3 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &654183278 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 654183275} + 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: 0.392} + 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 &654183279 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 654183275} + m_CullTransparentMesh: 1 +--- !u!1 &700531765 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 700531766} + - component: {fileID: 700531769} + - component: {fileID: 700531768} + - component: {fileID: 700531767} + m_Layer: 5 + m_Name: Viewport m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &584920167 +--- !u!224 &700531766 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 584920166} + m_GameObject: {fileID: 700531765} 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: 957066421} - m_Father: {fileID: 1532498605} + - {fileID: 1006328273} + m_Father: {fileID: 441863968} 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.375977, y: -110.75391} - m_SizeDelta: {x: 400, y: 100} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &584920168 + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -18, y: 0} + m_Pivot: {x: 0, y: 1} +--- !u!114 &700531767 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 700531765} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_ShowMaskGraphic: 0 +--- !u!114 &700531768 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 584920166} + m_GameObject: {fileID: 700531765} 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_Color: {r: 0.21176471, g: 0.21176471, b: 0.40784314, 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_Sprite: {fileID: 10917, guid: 0000000000000000f000000000000000, type: 0} m_Type: 1 m_PreserveAspect: 0 m_FillCenter: 1 @@ -349,13 +1230,13 @@ MonoBehaviour: m_FillOrigin: 0 m_UseSpriteMesh: 0 m_PixelsPerUnitMultiplier: 1 ---- !u!222 &584920169 +--- !u!222 &700531769 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 584920166} + m_GameObject: {fileID: 700531765} m_CullTransparentMesh: 1 --- !u!1 &705507993 GameObject: @@ -526,7 +1407,7 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 745605586} m_CullTransparentMesh: 1 ---- !u!1 &957066420 +--- !u!1 &863813044 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -534,62 +1415,49 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 957066421} - - component: {fileID: 957066424} - - component: {fileID: 957066423} - - component: {fileID: 957066422} + - component: {fileID: 863813045} + - component: {fileID: 863813047} + - component: {fileID: 863813046} m_Layer: 5 - m_Name: AIText + m_Name: Label m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &957066421 +--- !u!224 &863813045 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 957066420} + m_GameObject: {fileID: 863813044} 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: 584920167} + m_Father: {fileID: 272611075} 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_AnchoredPosition: {x: -7.5, y: -0.5} + m_SizeDelta: {x: -35, y: -13} m_Pivot: {x: 0.5, y: 0.5} ---- !u!210 &957066422 -SortingGroup: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 957066420} - m_Enabled: 1 - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 1 - m_SortAtRoot: 0 ---- !u!114 &957066423 +--- !u!114 &863813046 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 957066420} + m_GameObject: {fileID: 863813044} 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_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 @@ -598,25 +1466,25 @@ MonoBehaviour: m_Calls: [] m_FontData: m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} - m_FontSize: 16 + m_FontSize: 20 m_FontStyle: 0 m_BestFit: 0 - m_MinSize: 10 + m_MinSize: 2 m_MaxSize: 40 - m_Alignment: 0 + m_Alignment: 4 m_AlignByGeometry: 0 m_RichText: 1 m_HorizontalOverflow: 0 m_VerticalOverflow: 0 m_LineSpacing: 1 - m_Text: ---- !u!222 &957066424 + m_Text: Hamlet +--- !u!222 &863813047 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 957066420} + m_GameObject: {fileID: 863813044} m_CullTransparentMesh: 1 --- !u!1 &963194225 GameObject: @@ -701,16 +1569,281 @@ Transform: m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 963194225} - serializedVersion: 2 + m_GameObject: {fileID: 963194225} + 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 &1006328272 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1006328273} + m_Layer: 5 + m_Name: Content + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1006328273 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1006328272} + 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: 448418189} + m_Father: {fileID: 700531766} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 28} + m_Pivot: {x: 0.5, y: 1} +--- !u!1 &1091921148 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1091921149} + - component: {fileID: 1091921151} + - component: {fileID: 1091921150} + 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 &1091921149 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1091921148} + 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: 1736746841} + 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 &1091921150 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1091921148} + 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 &1091921151 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1091921148} + m_CullTransparentMesh: 1 +--- !u!1 &1169965868 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1169965869} + - component: {fileID: 1169965871} + - component: {fileID: 1169965870} + m_Layer: 5 + m_Name: Handle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1169965869 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1169965868} + 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: 647783086} + 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: 20, y: 20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1169965870 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1169965868} + 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 &1169965871 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1169965868} + m_CullTransparentMesh: 1 +--- !u!1 &1290703736 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1290703737} + - component: {fileID: 1290703739} + - component: {fileID: 1290703738} + m_Layer: 5 + m_Name: Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1290703737 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1290703736} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 1, z: -10} + 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_Father: {fileID: 654183276} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1091921148 + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0.000015258789} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1290703738 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1290703736} + 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.5372549, g: 0.5372549, b: 0.9019608, 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 &1290703739 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1290703736} + m_CullTransparentMesh: 1 +--- !u!1 &1343354785 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -718,78 +1851,89 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1091921149} - - component: {fileID: 1091921151} - - component: {fileID: 1091921150} + - component: {fileID: 1343354786} + - component: {fileID: 1343354789} + - component: {fileID: 1343354788} + - component: {fileID: 1343354787} m_Layer: 5 - m_Name: Text (Legacy) + m_Name: Viewport m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &1091921149 +--- !u!224 &1343354786 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1091921148} + m_GameObject: {fileID: 1343354785} 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: 1736746841} + m_Children: + - {fileID: 379533025} + m_Father: {fileID: 654183276} 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 &1091921150 +--- !u!114 &1343354787 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1091921148} + m_GameObject: {fileID: 1343354785} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_ShowMaskGraphic: 0 +--- !u!114 &1343354788 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1343354785} + 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_Color: {r: 0.5372549, g: 0.5372549, b: 0.9019608, 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 &1091921151 + m_Sprite: {fileID: 10917, 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 &1343354789 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1091921148} + m_GameObject: {fileID: 1343354785} m_CullTransparentMesh: 1 ---- !u!1 &1427556278 +--- !u!1 &1386761192 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -797,45 +1941,45 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1427556279} - - component: {fileID: 1427556281} - - component: {fileID: 1427556280} + - component: {fileID: 1386761193} + - component: {fileID: 1386761195} + - component: {fileID: 1386761194} m_Layer: 5 - m_Name: AI title + m_Name: Arrow m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &1427556279 +--- !u!224 &1386761193 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1427556278} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_GameObject: {fileID: 1386761192} + 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: 1532498605} + m_Father: {fileID: 272611075} 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: 16, y: -46} - m_SizeDelta: {x: 160, y: 29.6652} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -15, y: 0} + m_SizeDelta: {x: 20, y: 20} m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1427556280 +--- !u!114 &1386761194 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1427556278} + m_GameObject: {fileID: 1386761192} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} @@ -846,27 +1990,23 @@ MonoBehaviour: 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 &1427556281 + m_Sprite: {fileID: 10915, 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 &1386761195 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1427556278} + m_GameObject: {fileID: 1386761192} m_CullTransparentMesh: 1 --- !u!1 &1532498601 GameObject: @@ -964,9 +2104,10 @@ RectTransform: m_Children: - {fileID: 745605587} - {fileID: 1736746841} - - {fileID: 584920167} + - {fileID: 654183276} - {fileID: 102275136} - - {fileID: 1427556279} + - {fileID: 272611075} + - {fileID: 191351080} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} @@ -974,6 +2115,81 @@ RectTransform: m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0, y: 0} +--- !u!1 &1564078632 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1564078633} + - component: {fileID: 1564078635} + - component: {fileID: 1564078634} + m_Layer: 5 + m_Name: Item Checkmark + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1564078633 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1564078632} + 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: 448418189} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 10, y: 0} + m_SizeDelta: {x: 20, y: 20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1564078634 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1564078632} + 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: 10901, 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 &1564078635 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1564078632} + m_CullTransparentMesh: 1 --- !u!1 &1736746840 GameObject: m_ObjectHideFlags: 0 @@ -1011,8 +2227,8 @@ RectTransform: 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.375977, y: 87.00699} - m_SizeDelta: {x: 400, y: 100} + m_AnchoredPosition: {x: 0, y: 117.006996} + m_SizeDelta: {x: 500, y: 100} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &1736746842 MonoBehaviour: @@ -1218,10 +2434,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 8813eb3f4b7c900538f904cbd42e0a7f, type: 3} m_Name: m_EditorClassIdentifier: - playerText: {fileID: 1736746842} - AIText: {fileID: 957066423} - embedding: {fileID: 1842083047} - gutenbergText: {fileID: 4900000, guid: be0ffe8c7b44139218ffd530749f1644, type: 3} + CharacterSelect: {fileID: 272611076} + PlayerText: {fileID: 1736746842} + AIText: {fileID: 379533026} + Embedding: {fileID: 1842083047} + GutenbergText: {fileID: 4900000, guid: be0ffe8c7b44139218ffd530749f1644, type: 3} --- !u!4 &1842083046 Transform: m_ObjectHideFlags: 0 @@ -1253,6 +2470,85 @@ MonoBehaviour: GPU: 0 SelectedOption: 1 downloadProgress: 1 +--- !u!1 &2050714464 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2050714465} + - component: {fileID: 2050714467} + - component: {fileID: 2050714466} + m_Layer: 5 + m_Name: Item Label + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2050714465 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2050714464} + 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: 448418189} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 5, y: -0.5} + m_SizeDelta: {x: -30, y: -3} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &2050714466 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2050714464} + 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: 3 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Option A +--- !u!222 &2050714467 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2050714464} + m_CullTransparentMesh: 1 --- !u!1660057539 &9223372036854775807 SceneRoots: m_ObjectHideFlags: 0 From b08896f9657be0f66b983ea9386b2c2df03ca7f5 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Tue, 13 Feb 2024 15:19:30 +0200 Subject: [PATCH 105/161] allow quantisation and set it to float16 by default --- Runtime/Dialogue.cs | 25 ++++++++++++++++++++++--- Runtime/Search.cs | 11 ++++++++++- Runtime/SearchMethods.cs | 8 ++++---- Tests/Runtime/TestSearch.cs | 2 +- Tests/Runtime/TestSearchMethods.cs | 2 +- usearch/USearchIndex.cs | 3 ++- 6 files changed, 40 insertions(+), 11 deletions(-) diff --git a/Runtime/Dialogue.cs b/Runtime/Dialogue.cs index 53ca9066..9be8cd4a 100644 --- a/Runtime/Dialogue.cs +++ b/Runtime/Dialogue.cs @@ -7,6 +7,8 @@ using System.Runtime.Serialization; using System.IO; using System.IO.Compression; +using Cloud.Unum.USearch; +using UnityEngine; namespace LLMUnity { @@ -18,19 +20,36 @@ public class Dialogue string delimiters; [DataMember] EmbeddingModel embedder; + [DataMember] + ScalarKind quantization; - public Dialogue(EmbeddingModel embedder, string delimiters = SentenceSplitter.DefaultDelimiters) + public Dialogue( + EmbeddingModel embedder, + string delimiters = SentenceSplitter.DefaultDelimiters, + ScalarKind quantization = ScalarKind.Float16 + ) { dialogueParts = new Dictionary>(); this.embedder = embedder; this.delimiters = delimiters; + this.quantization = quantization; + } + + public EmbeddingModel GetEmbedder() + { + return embedder; + } + + public void SetEmbedder(EmbeddingModel model) + { + embedder = model; } public void Add(string text, string actor="", string title = "") { if (!dialogueParts.ContainsKey(actor) || !dialogueParts[actor].ContainsKey(title)) { - SearchEngine search = new SearchEngine(embedder, delimiters); + SearchEngine search = new SearchEngine(embedder, delimiters, quantization); if (!dialogueParts.ContainsKey(actor)) { dialogueParts[actor] = new Dictionary(); @@ -233,7 +252,7 @@ public static Dialogue Load(string filePath, string dirname = "") { Dialogue dialogue = Saver.Load(archive, GetDialoguePath(dirname)); - dialogue.embedder = EmbeddingModel.Load(archive, dirname); + dialogue.SetEmbedder(EmbeddingModel.Load(archive, dirname)); ZipArchiveEntry dialoguesEntry = archive.GetEntry(GetDialogueEntriesPath(dirname)); List dialogueDirs = new List(); diff --git a/Runtime/Search.cs b/Runtime/Search.cs index c690fe7e..49f8531e 100644 --- a/Runtime/Search.cs +++ b/Runtime/Search.cs @@ -3,6 +3,7 @@ using System.Runtime.Serialization; using System.IO; using System.IO.Compression; +using Cloud.Unum.USearch; namespace LLMUnity { @@ -110,7 +111,15 @@ public class SearchEngine SentenceSplitter sentenceSplitter; ANNModelSearch searchMethod; - public SearchEngine(EmbeddingModel embedder, string delimiters = SentenceSplitter.DefaultDelimiters) + public SearchEngine( + EmbeddingModel embedder, + string delimiters = SentenceSplitter.DefaultDelimiters, + ScalarKind quantization = ScalarKind.Float16, + MetricKind metricKind = MetricKind.Cos, + ulong connectivity = 32, + ulong expansionAdd = 40, + ulong expansionSearch = 16 + ) { phrases = new SortedDictionary(); sentences = new SortedDictionary(); diff --git a/Runtime/SearchMethods.cs b/Runtime/SearchMethods.cs index 374282e1..6fba2b5b 100644 --- a/Runtime/SearchMethods.cs +++ b/Runtime/SearchMethods.cs @@ -248,16 +248,16 @@ public class ANNModelSearch : SearchMethod [DataMember] protected SortedDictionary keyToValue; - public ANNModelSearch(EmbeddingModel embedder) : this(embedder, MetricKind.Cos, 32, 40, 16) {} + public ANNModelSearch(EmbeddingModel embedder) : this(embedder, ScalarKind.Float16, MetricKind.Cos, 32, 40, 16) {} public ANNModelSearch( EmbeddingModel embedder, + ScalarKind quantization = ScalarKind.Float16, MetricKind metricKind = MetricKind.Cos, ulong connectivity = 32, ulong expansionAdd = 40, - ulong expansionSearch = 16, - bool multi = false - ) : this(embedder, new USearchIndex((ulong)embedder.Dimensions, metricKind, connectivity, expansionAdd, expansionSearch, multi)) {} + ulong expansionSearch = 16 + ) : this(embedder, new USearchIndex((ulong)embedder.Dimensions, metricKind, quantization, connectivity, expansionAdd, expansionSearch, false)) {} public ANNModelSearch( EmbeddingModel embedder, diff --git a/Tests/Runtime/TestSearch.cs b/Tests/Runtime/TestSearch.cs index c15a1cda..50aea343 100644 --- a/Tests/Runtime/TestSearch.cs +++ b/Tests/Runtime/TestSearch.cs @@ -134,7 +134,7 @@ public void TestAdd() Assert.AreEqual(searchEngine.NumSentences(), sentencesGT.Length); } - public bool ApproxEqual(float x1, float x2, float tolerance = 0.00001f) + public bool ApproxEqual(float x1, float x2, float tolerance = 0.0001f) { return Mathf.Abs(x1 - x2) < tolerance; } diff --git a/Tests/Runtime/TestSearchMethods.cs b/Tests/Runtime/TestSearchMethods.cs index 22d57e73..840ac002 100644 --- a/Tests/Runtime/TestSearchMethods.cs +++ b/Tests/Runtime/TestSearchMethods.cs @@ -16,7 +16,7 @@ public class TestSearch string raining = "is it raining?"; string random = "something completely random"; - public bool ApproxEqual(float x1, float x2, float tolerance = 0.00001f) + public bool ApproxEqual(float x1, float x2, float tolerance = 0.0001f) { return Mathf.Abs(x1 - x2) < tolerance; } diff --git a/usearch/USearchIndex.cs b/usearch/USearchIndex.cs index 8691820e..daed7948 100644 --- a/usearch/USearchIndex.cs +++ b/usearch/USearchIndex.cs @@ -19,6 +19,7 @@ public class USearchIndex : IDisposable public USearchIndex( ulong dimensions, MetricKind metricKind = MetricKind.Cos, + ScalarKind quantization = ScalarKind.Float16, ulong connectivity = 32, ulong expansionAdd = 40, ulong expansionSearch = 16, @@ -29,7 +30,7 @@ public USearchIndex( { metric_kind = metricKind, metric = default, - quantization = ScalarKind.Float32, + quantization = quantization, dimensions = dimensions, connectivity = connectivity, expansion_add = expansionAdd, From e58e3b4d7d6efa347bec2e01e455a321e8afd996 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Tue, 13 Feb 2024 15:20:11 +0200 Subject: [PATCH 106/161] load only some characters --- Samples~/HamletSearch/HamletSearch.cs | 22 +++++++++++++--------- Samples~/HamletSearch/Scene.unity | 6 ------ 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/Samples~/HamletSearch/HamletSearch.cs b/Samples~/HamletSearch/HamletSearch.cs index 1ddcd1b9..df80f5f3 100644 --- a/Samples~/HamletSearch/HamletSearch.cs +++ b/Samples~/HamletSearch/HamletSearch.cs @@ -28,12 +28,6 @@ IEnumerator InitDialogue() { PlayerText.interactable = false; - EmbeddingModel model = Embedding.GetModel(); - if (model == null) - { - throw new System.Exception("Please select an Embedding model in the HamletSearch GameObject!"); - } - string sampleDir = Directory.GetDirectories(Application.dataPath, "HamletSearch", SearchOption.AllDirectories)[0]; string filename = Path.Combine(sampleDir, "Embeddings.zip"); if (File.Exists(filename)) @@ -91,10 +85,20 @@ void DropdownChange(int selection) Dialogue CreateEmbeddings(string filename) { - Dialogue dialogue; + EmbeddingModel model = Embedding.GetModel(); + if (model == null) + { + throw new System.Exception("Please select an Embedding model in the HamletSearch GameObject!"); + } Dictionary> hamlet = ReadGutenbergFile(GutenbergText.text); - dialogue = new Dialogue(Embedding.GetModel()); + Dialogue dialogue = new Dialogue(model); + + List characters = new List(); + foreach (var option in CharacterSelect.options) + { + characters.Add(option.text.ToUpper()); + } Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); @@ -102,7 +106,7 @@ Dialogue CreateEmbeddings(string filename) { foreach ((string actor, string message) in messages) { - dialogue.Add(message, actor); + if (characters.Contains(actor)) dialogue.Add(message, actor); // if you want only Hamlet, you could instead do: // if (actor == "HAMLET") dialogue.Add(message); } diff --git a/Samples~/HamletSearch/Scene.unity b/Samples~/HamletSearch/Scene.unity index dc354936..3541128b 100644 --- a/Samples~/HamletSearch/Scene.unity +++ b/Samples~/HamletSearch/Scene.unity @@ -466,12 +466,6 @@ MonoBehaviour: m_Image: {fileID: 0} - m_Text: Horatio m_Image: {fileID: 0} - - m_Text: Rosencrantz - m_Image: {fileID: 0} - - m_Text: Guildenstern - m_Image: {fileID: 0} - - m_Text: Fortinbras - m_Image: {fileID: 0} m_OnValueChanged: m_PersistentCalls: m_Calls: [] From e0c254291625a8e053f31f3c03b880f28b244097 Mon Sep 17 00:00:00 2001 From: Antonis Makropoulos Date: Tue, 13 Feb 2024 15:20:31 +0200 Subject: [PATCH 107/161] add embeddings --- Samples~/HamletSearch/Embeddings.zip | Bin 0 -> 2004719 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Samples~/HamletSearch/Embeddings.zip diff --git a/Samples~/HamletSearch/Embeddings.zip b/Samples~/HamletSearch/Embeddings.zip new file mode 100644 index 0000000000000000000000000000000000000000..d4ccdd3e03e5d5449c5065e9fcb2a8ba0306d27d GIT binary patch literal 2004719 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®*K6~+ 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 z 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⩔&NN)*t?&Fm*S=7>XJ^dD9P8Wz_9zfY#FO`e6hR* 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

    l}P7mhSwIEro+#d_4MN8)F34E{~_ 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

    1F~J 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�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