From a69e702294b538331cfddacab1b379016fcbd841 Mon Sep 17 00:00:00 2001 From: Udayshankar Ravikumar Date: Mon, 1 Jul 2024 17:48:13 +0530 Subject: [PATCH] UGemini v1.0.0 --- README.md | 37 + .../Documentation~/README.md | 401 ++++++- .../Scripts/Data/Common/GeminiContent.cs | 37 +- .../Scripts/FunctionCallingChatManager.cs | 78 +- .../Scenes/Main.unity | 4 +- .../Scripts/MultiTurnChatManager.cs | 4 +- .../Samples~/TokenCounterSample/Scenes.meta | 8 + .../TokenCounterSample/Scenes/Main.unity | 1052 +++++++++++++++++ .../TokenCounterSample/Scenes/Main.unity.meta | 7 + .../Samples~/TokenCounterSample/Scripts.meta | 8 + .../Scripts/TokenCounterManager.cs | 32 + .../Scripts/TokenCounterManager.cs.meta | 11 + .../com.uralstech.ugemini/package.json | 7 +- UGemini/Packages/manifest.json | 2 +- 14 files changed, 1637 insertions(+), 51 deletions(-) create mode 100644 UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scenes.meta create mode 100644 UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scenes/Main.unity create mode 100644 UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scenes/Main.unity.meta create mode 100644 UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scripts.meta create mode 100644 UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scripts/TokenCounterManager.cs create mode 100644 UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scripts/TokenCounterManager.cs.meta diff --git a/README.md b/README.md index efc4f6b8..767aeff5 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,40 @@ ## UGemini A C# wrapper for the Google Gemini API. + +[![openupm](https://img.shields.io/npm/v/com.uralstech.ugemini?label=openupm®istry_uri=https://package.openupm.com)](https://openupm.com/packages/com.uralstech.ugemini/) +[![openupm](https://img.shields.io/badge/dynamic/json?color=brightgreen&label=downloads&query=%24.downloads&suffix=%2Fmonth&url=https%3A%2F%2Fpackage.openupm.com%2Fdownloads%2Fpoint%2Flast-month%2Fcom.uralstech.ugemini)](https://openupm.com/packages/com.uralstech.ugemini/) + +### Installation + +This *should* work on any reasonably modern Unity version. Built and tested in Unity 2022.3.29f1. + +#### From OpenUPM Through Unity Package Manager + +1. Open project settings +2. Select `Package Manager` +3. Add the OpenUPM package registry: + - Name: `OpenUPM` + - URL: `https://package.openupm.com` + - Scope(s) + - `com.uralstech` + - *`com.utilities` +4. Open the Unity Package Manager window (`Window` -> `Package Manager`) +5. Change the registry from `Unity` to `My Registries` +6. Add the `UGemini` and *`Utilities.Encoder.Wav` packages + +#### From GitHub Through Unity Package Manager + +1. Open the Unity Package Manager window (`Window` -> `Package Manager`) +2. Select the `+` icon and `Add package from git URL...` +3. Paste the UPM branch URL and press enter: + - `https://github.com/Uralstech/UGemini.git#upm` + +*\*Adding additional dependencies:*
+Follow the steps detailed in the OpenUPM installation method and only install the *`Utilities.Encoder.Wav` package. + +*Optional, but required if you don't want to bother with encoding your AudioClips into Base64 strings manually. + +### Documentation + +See . diff --git a/UGemini/Packages/com.uralstech.ugemini/Documentation~/README.md b/UGemini/Packages/com.uralstech.ugemini/Documentation~/README.md index 517c95ea..0fa6e72f 100644 --- a/UGemini/Packages/com.uralstech.ugemini/Documentation~/README.md +++ b/UGemini/Packages/com.uralstech.ugemini/Documentation~/README.md @@ -1,3 +1,400 @@ -## UGemini +## UGemini Documentation -The documentation will be here. \ No newline at end of file +### Setup + +Add an instance of `GeminiManager` to your scene, and set it up with your Gemini API key. You can get your API key from [*here*](https://makersuite.google.com/app/apikey). + +### Coding + +There are only two methods in `GeminiManager`: + +| Method | What it does | +| ------------- | ------------- | +| `void SetApiKey(string)` | Sets the Gemini API key through code | +| `Task Compute(TRequest, RequestEndPoint, string, bool)` | Computes a request on the Gemini API | + +All computations on the Gemini API are done through `GeminiManager.Compute`. + +In this documentation, the fields and properties of each type will not be explained. Every type has been fully documented in code, so +please check the code docstrings to learn more about each type. + +#### Beta API + +`GeminiManager` supports both the `v1` and `v1beta` Gemini API versions. As a lot of features are still unsupported in the main `v1` API, you may +need to use the beta API. You can set the `useBeta` boolean parameter in the `Compute` method to do so. + +#### Models + +`GeminiManager` has four constant model IDs: + +- `Gemini1_5Flash` - [*Gemini 1.5 Flash*](https://ai.google.dev/gemini-api/docs/models/gemini#gemini-1.5-flash) + +- `Gemini1_5Pro` - [*Gemini 1.5 Pro*](https://ai.google.dev/gemini-api/docs/models/gemini#gemini-1.5-pro) + +- `Gemini1_0Pro` - [*Gemini 1.0 Pro*](https://ai.google.dev/gemini-api/docs/models/gemini#gemini-1.0-pro) + +- `Gemini1_0ProVision` - [*Gemini 1.0 Pro Vision*](https://ai.google.dev/gemini-api/docs/models/gemini#gemini-1.0-pro-vision) + - Gemini 1.0 Pro Vision is deprecated. Use Use 1.5 Flash (`Gemini1_5Flash`) or 1.5 Pro (`Gemini1_5Pro`) instead. + + +By default, the `Compute` method uses the [*Gemini 1.5 Flash*](https://ai.google.dev/gemini-api/docs/models/gemini#gemini-1.5-flash) +model for all requests. This can be changed by either providing a string ID or one of the constants to the `model` parameter in the `Compute` method. + +#### Simple GenerateContent (Chat) Request + +This is a simple request that asks Gemini a question and logs the response to the console. + +```csharp +using Uralstech.UGemini.Chat; + +async void QueryGemini() +{ + string text = "Hello! How are you doing?"; + GeminiChatResponse response = await GeminiManager.Instance.Compute( + new GeminiChatRequest() + { + Contents = new GeminiContent[] + { + GeminiContent.GetContent(text, GeminiRole.User), + }, + }, + GeminiManager.RequestEndPoint.Chat + ); + + Debug.Log(response.Parts[0].Text); +} +``` + +That's all! We specify that we are executing a request of type `GeminiChatRequest`, and that we expect a response of type `GeminiChatResponse`, +then we specified the content of the request and the endpoint we want to execute it on, `GeminiManager.RequestEndPoint.Chat`! And voilĂ , we've +got the response in `response.Parts[0].Text`! + +Right now, there are two types of requests and endpoints that are supported: + +- `GeminiChatRequest` | `GeminiChatResponse`: + - Available in the `Uralstech.UGemini.Chat` namespace + - Meant to run on the `GeminiManager.RequestEndPoint.Chat` endpoint + - Runs a `generateContent` request on the given model + +and + +- `GeminiTokenCountRequest` | `GeminiTokenCountResponse`: + - Available in the `Uralstech.UGemini.TokenCounting` namespace + - Meant to run on the `GeminiManager.RequestEndPoint.CountTokens` endpoint + - Counts the number of tokens in the given request contents for the given model + +#### Multi-turn Chat Request + +This is a simple method that maintains the user's chat history with Gemini. + +```csharp +using Uralstech.UGemini.Chat; + +List _chatHistory = new(); + +async Task OnChat(string text) +{ + _chatHistory.Add(GeminiContent.GetContent(text, GeminiRole.User)); + GeminiChatRequest request = new() + { + Contents = _chatHistory.ToArray(), + }; + + GeminiChatResponse response = await GeminiManager.Instance.Compute(request, GeminiManager.RequestEndPoint.Chat); + + _chatHistory.Add(response.Candidates[0].Content); + return response.Parts[0].Text; +} +``` + +Here, we simply have a list of `GeminiContent` objects, which tracks the messages of the conversation. Every time `OnChat` is called, the user's request and +the model's reply are added the the list. That is all! + +#### Adding Media Content to Requests + +`GeminiContent.Parts` contains the actual contents of each chat request and response. You can add media content to the `Parts` array, but you must only have +one type of data in each part, like one part of text, one part of an image, and so on. The following samples shows data being read from a file and into a +`GeminiContent` object. + +```csharp +using Uralstech.UGemini.Chat; + +async Task GetFileContent(string filePath, GeminiContentType contentType) +{ + byte[] data; + try + { + data = await File.ReadAllBytesAsync(filePath); + } + catch (SystemException exception) + { + Debug.LogError($"Failed to load file: {exception.Message}"); + return null; + } + + return new GeminiContent() + { + Parts = new GeminiContentPart[] + { + new GeminiContentPart() + { + Text = "What's in this file?" + }, + new GeminiContentPart() + { + InlineData = new GeminiContentBlob() + { + MimeType = contentType, + Data = Convert.ToBase64String(data) + } + } + } + }; +} +``` + +Now, the `GeminiContent` returned by the method can be fed into a chat request! + +`GeminiContent` and `GeminiContentBlob` also contain static utility methods to help +create them from Unity types like `AudioClip` or `Texture2D`: + +- `GeminiContent.GetContent` + - Can convert `string` messages, `Texture2D` images and *`AudioClip` audio to `GeminiContent` objects. + +- `GeminiContentBlob.GetContentBlob` + - Can convert `Texture2D` images and *`AudioClip` audio to `GeminiContentBlob` objects. + +*Requires [*Utilities.Encoding.Wav*](https://openupm.com/packages/com.utilities.encoder.wav/). + +#### Function Calling + +First, we have to setup our tools and define our function schemas. + +```csharp +using Uralstech.UGemini.Chat; +using Uralstech.UGemini.Schema; +using Uralstech.UGemini.Tools; +using Uralstech.UGemini.Tools.Declaration; + +GeminiTool s_geminiFunctions = new GeminiTool() +{ + FunctionDeclarations = new GeminiFunctionDeclaration[] + { + new GeminiFunctionDeclaration() + { + Name = "printToConsole", + Description = "Print text to the user's console.", + Parameters = new GeminiSchema() + { + Type = GeminiSchemaDataType.Object, + Properties = new Dictionary() + { + { + "text", new GeminiSchema() + { + Type = GeminiSchemaDataType.String, + Description = "The text to print. e.g. \"Hello, World!\"", + Nullable = false, + } + }, + }, + Required = new string[] { "text" }, + } + }, + + new GeminiFunctionDeclaration() + { + Name = "changeTextColor", + Description = "Change the color of the text.", + Parameters = new GeminiSchema() + { + Type = GeminiSchemaDataType.Object, + Properties = new Dictionary() + { + { + "color", new GeminiSchema() + { + Type = GeminiSchemaDataType.String, + Description = "The color to set. e.g. \"BLUE\"", + Format = GeminiSchemaDataFormat.Enum, + Enum = new string[] + { + "RED", + "GREEN", + "BLUE", + "WHITE", + }, + Nullable = false, + } + }, + }, + Required = new string[] { "color" }, + } + } + }, +}; +``` + +For each function, we need a declaration with a name and description. The parameters are an object of type `GeminiSchema`, which defines the +schema of each of the parameters. The type is of `GeminiSchemaDataType.Object`, and contains the dictionary of parameter schemas. + +The key of the dictionary should be the parameter name, and the value should be another `GeminiSchema` object which defines the type, description, +format, etc. of the parameter. + +Finally, we have the `Required` property which tells Gemini which fields are absolutely required in each call. + +Now, we can move on to the chat. + +```csharp +[SerializeField] private Text _chatResponse; + +public async Task OnChat(string text) +{ + List contents = new() + { + GeminiContent.GetContent(text, GeminiRole.User), + }; + + GeminiChatResponse response; + GeminiFunctionCall functionCall; + do + { + response = await GeminiManager.Instance.Compute(new GeminiChatRequest() + { + Contents = contents.ToArray(), + Tools = new GeminiTool[] { s_geminiFunctions }, + ToolConfig = GeminiToolConfiguration.GetConfiguration(GeminiFunctionCallingMode.Any), + }, GeminiManager.RequestEndPoint.Chat, useBeta: true); + + functionCall = response.Parts[0].FunctionCall; + if (functionCall != null) + { + JObject functionResponse = null; + switch (functionCall.Name) + { + case "printToConsole": + Debug.Log(functionCall.Arguments["text"].ToObject()); + break; + + case "changeTextColor": + if (!TryChangeTextColor(functionCall.Arguments["color"].ToObject())) + { + functionResponse = new JObject() + { + ["result"] = "Unknown color." + }; + } + + break; + + default: + functionResponse = new JObject() + { + ["result"] = "Sorry, but that function does not exist." + }; + + break; + } + + contents.Add(GeminiContent.GetContent(functionCall)); + contents.Add(GeminiContent.GetContent(functionCall.GetResponse(functionResponse))); + } + + } while (functionCall != null); + + return response.Parts[0].Text; +} + +private bool TryChangeTextColor(string color) +{ + switch (color) + { + case "RED": + _chatResponse.color = Color.red; break; + + case "GREEN": + _chatResponse.color = Color.green; break; + + case "BLUE": + _chatResponse.color = Color.blue; break; + + case "WHITE": + _chatResponse.color = Color.white; break; + + default: + return false; + } + + Debug.Log("Changed text color!"); + return true; +} +``` + +Here, we are going through each response, checking if a function was called, and calling the requested function. +The response is a JSON object, which is optional. Note the use of `GeminiToolConfiguration.GetConfiguration`, which is a utility method +to create a `GeminiToolConfiguration` with the given `GeminiFunctionCallingMode`. Here it is `GeminiFunctionCallingMode.Any`, which means +Gemini will always call at least one function in each conversation. + +After the function is called, we respond by adding the call and response to the history. We use the `GetResponse` utility method to get a +`GeminiFunctionResponse` object with the response JSON. + +Also, note that the request is using the beta API, as function calling is, as of writing, not available in the production API. + +#### JSON Mode + +In JSON mode, Gemini will always respond in a specified JSON response schema. + +```csharp +public async Task OnChat(string text) +{ + // Note: It seems GeminiManager.Gemini1_5Flash is not very good at JSON. + GeminiChatResponse response = await GeminiManager.Instance.Compute(new GeminiChatRequest() + { + Contents = new GeminiContent[] + { + GeminiContent.GetContent(text, GeminiRole.User), + }, + SystemInstruction = GeminiContent.GetContent("You are a helpful math teacher who teacher their students mathematics in the most helpful way possible."), + GenerationConfig = new GeminiGenerationConfiguration() + { + ResponseMimeType = GeminiResponseType.Json, + ResponseSchema = new GeminiSchema() + { + Type = GeminiSchemaDataType.Array, + Description = "A list of mathematical expressions.", + Items = new GeminiSchema() + { + Type = GeminiSchemaDataType.Object, + Properties = new Dictionary() + { + { + "expression", new GeminiSchema() + { + Type = GeminiSchemaDataType.String, + } + }, + { + "explanation", new GeminiSchema() + { + Type = GeminiSchemaDataType.String, + } + }, + }, + Required = new string[] { "expression", "explanation", }, + }, + }, + } + }, GeminiManager.RequestEndPoint.Chat, GeminiManager.Gemini1_5Pro, true); + + return response.Parts[0].Text; +} +``` + +Here, we used a schema for an array of objects, which contain two parameters: `expression` and `explanation`. +We have told Gemini to split the response into the parameters, where a mathematical expression and its explanation is given. + +The `GeminiSchema` object is the same type used for function calling. + +### Samples + +For full-fledged examples of the features of this package, check out the samples in the Unity Package Manager. \ No newline at end of file diff --git a/UGemini/Packages/com.uralstech.ugemini/Runtime/Scripts/Data/Common/GeminiContent.cs b/UGemini/Packages/com.uralstech.ugemini/Runtime/Scripts/Data/Common/GeminiContent.cs index 44452c6f..d8b44172 100644 --- a/UGemini/Packages/com.uralstech.ugemini/Runtime/Scripts/Data/Common/GeminiContent.cs +++ b/UGemini/Packages/com.uralstech.ugemini/Runtime/Scripts/Data/Common/GeminiContent.cs @@ -65,15 +65,42 @@ public static GeminiContent GetContent(string message, Texture2D image, GeminiRo }, new GeminiContentPart { - InlineData = new() - { - MimeType = GeminiContentType.ImageJPEG, - Data = Convert.ToBase64String(image.EncodeToJPG()) - } + InlineData = GeminiContentBlob.GetContentBlob(image), + }, + } + }; + } + +#if UTILITIES_ENCODING_WAV_1_0_0_OR_GREATER && UTILITIES_AUDIO_1_0_0_OR_GREATER + /// + /// Creates a new from a role, message and . + /// + /// + /// Requires Utilities.Encoding.Wav. + /// + /// The role of the content creator. + /// The message. + /// The audio clip. + /// A new object. + public static GeminiContent GetContent(string message, AudioClip audio, GeminiRole role = GeminiRole.Unspecified) + { + return new() + { + Role = role, + Parts = new[] + { + new GeminiContentPart + { + Text = message, + }, + new GeminiContentPart + { + InlineData = GeminiContentBlob.GetContentBlob(audio), } } }; } +#endif /// /// Creates a new from a . diff --git a/UGemini/Packages/com.uralstech.ugemini/Samples~/FunctionCallingSample/Scripts/FunctionCallingChatManager.cs b/UGemini/Packages/com.uralstech.ugemini/Samples~/FunctionCallingSample/Scripts/FunctionCallingChatManager.cs index 32fe5be8..a9851472 100644 --- a/UGemini/Packages/com.uralstech.ugemini/Samples~/FunctionCallingSample/Scripts/FunctionCallingChatManager.cs +++ b/UGemini/Packages/com.uralstech.ugemini/Samples~/FunctionCallingSample/Scripts/FunctionCallingChatManager.cs @@ -15,57 +15,57 @@ public class FunctionCallingChatManager : MonoBehaviour { FunctionDeclarations = new GeminiFunctionDeclaration[] { - new GeminiFunctionDeclaration() - { - Name = "printToConsole", - Description = "Print text to the user's console.", - Parameters = new GeminiSchema() + new GeminiFunctionDeclaration() { - Type = GeminiSchemaDataType.Object, - Properties = new Dictionary() + Name = "printToConsole", + Description = "Print text to the user's console.", + Parameters = new GeminiSchema() { + Type = GeminiSchemaDataType.Object, + Properties = new Dictionary() { - "text", new GeminiSchema() { - Type = GeminiSchemaDataType.String, - Description = "The text to print. e.g. \"Hello, World!\"", - Nullable = false, - } + "text", new GeminiSchema() + { + Type = GeminiSchemaDataType.String, + Description = "The text to print. e.g. \"Hello, World!\"", + Nullable = false, + } + }, }, - }, - Required = new string[] { "text" }, - } - }, - - new GeminiFunctionDeclaration() - { - Name = "changeTextColor", - Description = "Change the color of the text.", - Parameters = new GeminiSchema() + Required = new string[] { "text" }, + } + }, + + new GeminiFunctionDeclaration() { - Type = GeminiSchemaDataType.Object, - Properties = new Dictionary() + Name = "changeTextColor", + Description = "Change the color of the text.", + Parameters = new GeminiSchema() { + Type = GeminiSchemaDataType.Object, + Properties = new Dictionary() { - "color", new GeminiSchema() { - Type = GeminiSchemaDataType.String, - Description = "The color to set. e.g. \"BLUE\"", - Format = GeminiSchemaDataFormat.Enum, - Enum = new string[] + "color", new GeminiSchema() { - "RED", - "GREEN", - "BLUE", - "WHITE", - }, - Nullable = false, - } + Type = GeminiSchemaDataType.String, + Description = "The color to set. e.g. \"BLUE\"", + Format = GeminiSchemaDataFormat.Enum, + Enum = new string[] + { + "RED", + "GREEN", + "BLUE", + "WHITE", + }, + Nullable = false, + } + }, }, - }, - Required = new string[] { "color" }, + Required = new string[] { "color" }, + } } - } }, }; diff --git a/UGemini/Packages/com.uralstech.ugemini/Samples~/SimpleMultiTurnChatSample/Scenes/Main.unity b/UGemini/Packages/com.uralstech.ugemini/Samples~/SimpleMultiTurnChatSample/Scenes/Main.unity index 70434e5b..5ff1ca3f 100644 --- a/UGemini/Packages/com.uralstech.ugemini/Samples~/SimpleMultiTurnChatSample/Scenes/Main.unity +++ b/UGemini/Packages/com.uralstech.ugemini/Samples~/SimpleMultiTurnChatSample/Scenes/Main.unity @@ -2225,10 +2225,10 @@ MonoBehaviour: m_Calls: [] m_FontData: m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} - m_FontSize: 33 + m_FontSize: 30 m_FontStyle: 0 m_BestFit: 0 - m_MinSize: 10 + m_MinSize: 3 m_MaxSize: 46 m_Alignment: 3 m_AlignByGeometry: 0 diff --git a/UGemini/Packages/com.uralstech.ugemini/Samples~/SimpleMultiTurnChatSample/Scripts/MultiTurnChatManager.cs b/UGemini/Packages/com.uralstech.ugemini/Samples~/SimpleMultiTurnChatSample/Scripts/MultiTurnChatManager.cs index 99501b8d..11ac8506 100644 --- a/UGemini/Packages/com.uralstech.ugemini/Samples~/SimpleMultiTurnChatSample/Scripts/MultiTurnChatManager.cs +++ b/UGemini/Packages/com.uralstech.ugemini/Samples~/SimpleMultiTurnChatSample/Scripts/MultiTurnChatManager.cs @@ -47,7 +47,7 @@ public async void OnAddFile(string filePath) return; } - _uploadedData.Add(new GeminiContentPart + _uploadedData.Add(new GeminiContentPart() { InlineData = new GeminiContentBlob() { @@ -106,6 +106,8 @@ public async void OnChat() }; GeminiChatResponse response = await GeminiManager.Instance.Compute(request, GeminiManager.RequestEndPoint.Chat, useBeta: _useBeta); + + _chatHistory.Add(response.Candidates[0].Content); AddMessage(response.Candidates[0].Content); } diff --git a/UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scenes.meta b/UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scenes.meta new file mode 100644 index 00000000..b81c1e65 --- /dev/null +++ b/UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b7f00e05c8ebabf408e1bad1e2cb0013 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scenes/Main.unity b/UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scenes/Main.unity new file mode 100644 index 00000000..c723e66c --- /dev/null +++ b/UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scenes/Main.unity @@ -0,0 +1,1052 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_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 &267045207 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 267045208} + - component: {fileID: 267045209} + - component: {fileID: 267045210} + 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 &267045208 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 267045207} + 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: 603265309} + 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!222 &267045209 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 267045207} + m_CullTransparentMesh: 1 +--- !u!114 &267045210 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 267045207} + 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.19607843, g: 0.19607843, b: 0.19607843, 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: 49 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 49 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!1 &603265307 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 603265309} + - component: {fileID: 603265311} + - component: {fileID: 603265310} + - component: {fileID: 603265308} + m_Layer: 5 + m_Name: Content + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &603265308 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 603265307} + 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: 603265310} + m_TextComponent: {fileID: 267045210} + m_Placeholder: {fileID: 1923487864} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 2 + 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!224 &603265309 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 603265307} + 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: 1923487866} + - {fileID: 267045208} + m_Father: {fileID: 1574253904} + 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: 38.53198} + m_SizeDelta: {x: -60, y: -137.06396} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &603265310 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 603265307} + 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: 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 &603265311 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 603265307} + m_CullTransparentMesh: 1 +--- !u!1 &701971618 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 701971619} + - component: {fileID: 701971621} + - component: {fileID: 701971620} + 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 &701971619 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 701971618} + 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: 1319921711} + 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 &701971620 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 701971618} + 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.19607843, g: 0.19607843, b: 0.19607843, 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: 30 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Submit +--- !u!222 &701971621 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 701971618} + m_CullTransparentMesh: 1 +--- !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 &1209011936 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1209011938} + - component: {fileID: 1209011937} + m_Layer: 0 + m_Name: GeminiManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1209011937 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1209011936} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 082da32aa2c5b8243bfe608ff858f579, type: 3} + m_Name: + m_EditorClassIdentifier: + _geminiApiKey: +--- !u!4 &1209011938 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1209011936} + 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 &1318631065 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1318631068} + - component: {fileID: 1318631067} + - component: {fileID: 1318631066} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1318631066 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1318631065} + 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 &1318631067 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1318631065} + 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 &1318631068 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1318631065} + 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 &1319921710 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1319921711} + - component: {fileID: 1319921714} + - component: {fileID: 1319921713} + - component: {fileID: 1319921712} + m_Layer: 5 + m_Name: Submit + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1319921711 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1319921710} + 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: 701971619} + m_Father: {fileID: 1574253904} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: -100.307, y: 58.463} + m_SizeDelta: {x: 140.61401, y: 56.92505} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1319921712 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1319921710} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1319921713} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1574253900} + m_TargetAssemblyTypeName: Uralstech.UGemini.Samples.TokenCounterManager, + Assembly-CSharp + m_MethodName: OnCount + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &1319921713 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1319921710} + 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 &1319921714 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1319921710} + m_CullTransparentMesh: 1 +--- !u!1 &1354659564 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1354659565} + - component: {fileID: 1354659567} + - component: {fileID: 1354659566} + m_Layer: 5 + m_Name: Tokens + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1354659565 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1354659564} + 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: 1574253904} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: -80.20044, y: 58.463013} + m_SizeDelta: {x: -220.40039, y: 56.925} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1354659566 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1354659564} + 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: 50 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 56 + m_Alignment: 3 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'Tokens: 0' +--- !u!222 &1354659567 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1354659564} + m_CullTransparentMesh: 1 +--- !u!1 &1574253899 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1574253904} + - component: {fileID: 1574253903} + - component: {fileID: 1574253902} + - component: {fileID: 1574253901} + - component: {fileID: 1574253900} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1574253900 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1574253899} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e8f2a91c69cf0e34cbbdfaf49815f1e4, type: 3} + m_Name: + m_EditorClassIdentifier: + _contentInput: {fileID: 603265308} + _response: {fileID: 1354659566} +--- !u!114 &1574253901 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1574253899} + 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 &1574253902 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1574253899} + 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: 1920, y: 1080} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0.5 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!223 &1574253903 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1574253899} + 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 &1574253904 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1574253899} + 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: 603265309} + - {fileID: 1319921711} + - {fileID: 1354659565} + 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 &1923487863 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1923487866} + - component: {fileID: 1923487865} + - component: {fileID: 1923487864} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1923487864 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1923487863} + 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.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} + 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: 49 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 49 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Enter text... +--- !u!222 &1923487865 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1923487863} + m_CullTransparentMesh: 1 +--- !u!224 &1923487866 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1923487863} + 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: 603265309} + 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!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 963194228} + - {fileID: 1574253904} + - {fileID: 1318631068} + - {fileID: 1209011938} diff --git a/UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scenes/Main.unity.meta b/UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scenes/Main.unity.meta new file mode 100644 index 00000000..27e206c3 --- /dev/null +++ b/UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scenes/Main.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 24c288206040b594898ae3f3e3abcf62 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scripts.meta b/UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scripts.meta new file mode 100644 index 00000000..51bb0cbf --- /dev/null +++ b/UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f82424718488ac74b920e34dbeca8693 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scripts/TokenCounterManager.cs b/UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scripts/TokenCounterManager.cs new file mode 100644 index 00000000..f088667d --- /dev/null +++ b/UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scripts/TokenCounterManager.cs @@ -0,0 +1,32 @@ +using UnityEngine; +using UnityEngine.UI; +using Uralstech.UGemini.TokenCounting; + +namespace Uralstech.UGemini.Samples +{ + public class TokenCounterManager : MonoBehaviour + { + [SerializeField] private InputField _contentInput; + [SerializeField] private Text _response; + + public async void OnCount() + { + string text = _contentInput.text; + if (string.IsNullOrWhiteSpace(text)) + { + Debug.LogError("Chat text should not be null or whitespace!"); + return; + } + + GeminiTokenCountResponse response = await GeminiManager.Instance.Compute(new GeminiTokenCountRequest() + { + Contents = new GeminiContent[] + { + GeminiContent.GetContent(text, GeminiRole.User), + }, + }, GeminiManager.RequestEndPoint.CountTokens, GeminiManager.Gemini1_5Flash, true); + + _response.text = $"Tokens: {response.TotalTokens}"; + } + } +} diff --git a/UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scripts/TokenCounterManager.cs.meta b/UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scripts/TokenCounterManager.cs.meta new file mode 100644 index 00000000..1731b005 --- /dev/null +++ b/UGemini/Packages/com.uralstech.ugemini/Samples~/TokenCounterSample/Scripts/TokenCounterManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e8f2a91c69cf0e34cbbdfaf49815f1e4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UGemini/Packages/com.uralstech.ugemini/package.json b/UGemini/Packages/com.uralstech.ugemini/package.json index 0bf0eac8..1eb69b0f 100644 --- a/UGemini/Packages/com.uralstech.ugemini/package.json +++ b/UGemini/Packages/com.uralstech.ugemini/package.json @@ -9,7 +9,7 @@ "AI", "Integration" ], - "version": "1.0.0-preview.4", + "version": "1.0.0", "unity": "2022.3", "hideInEditor": false, "documentationUrl": "https://github.com/Uralstech/UGemini/blob/master/UGemini/Packages/com.uralstech.ugemini/Documentation~/README.md", @@ -39,6 +39,11 @@ "displayName": "JSON Response", "description": "A sample scene showing a system where Gemini responds in a specified JSON format.", "path": "Samples~/JSONResponseSample" + }, + { + "displayName": "Token Counting", + "description": "A sample scene showing a token counting system using the \"countTokens\" endpoint.", + "path": "Samples~/TokenCounterSample" } ], "dependencies": { diff --git a/UGemini/Packages/manifest.json b/UGemini/Packages/manifest.json index 5ad7bb19..a19be1b8 100644 --- a/UGemini/Packages/manifest.json +++ b/UGemini/Packages/manifest.json @@ -6,7 +6,7 @@ "com.unity.timeline": "1.7.6", "com.unity.ugui": "1.0.0", "com.unity.visualscripting": "1.9.4", - "com.uralstech.ugemini": "1.0.0-preview.4", + "com.uralstech.ugemini": "1.0.0", "com.utilities.encoder.wav": "1.2.1", "com.unity.modules.ai": "1.0.0", "com.unity.modules.androidjni": "1.0.0",