#if UNITY_5_3_OR_NEWER using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using GumYum.NPC; using GumYum.NPC.Unity; namespace GumYum.NPC.Unity.Examples { /// /// Simple example showing NPC spawning and dialogue /// Attach this to a GameObject in your scene /// public class QuickstartChat : MonoBehaviour { [Header("API Configuration")] [SerializeField] private string apiKey = "your-api-key"; [SerializeField] private string apiSecret = "your-api-secret"; [SerializeField] private string universeId = "blade-runner"; [SerializeField] private int worldSeed = 42; [Header("UI References")] [SerializeField] private Text npcNameText; [SerializeField] private Text npcInfoText; [SerializeField] private InputField userInput; [SerializeField] private Button sendButton; [SerializeField] private Text chatOutput; [SerializeField] private ScrollRect scrollRect; [Header("Chat Settings")] [SerializeField] private float temperature = 0.8f; [SerializeField] private int maxTokens = 2000; [SerializeField] private bool useStreamingChat = false; private GumYumUnityClient client; private NPC currentNPC; private bool isProcessing = false; void Start() { // Initialize the client client = GumYumUnityClient.Instance; client.SetCredentials(apiKey, apiSecret); // Setup UI sendButton.onClick.AddListener(OnSendButtonClicked); userInput.onEndEdit.AddListener(OnInputEndEdit); // Subscribe to events client.OnCharacterSpawned += OnCharacterSpawned; client.OnDialogueReceived += OnDialogueReceived; client.OnDialogueChunkReceived += OnDialogueChunkReceived; client.OnRequestFailed += OnRequestFailed; // Start by spawning an NPC StartCoroutine(SpawnRandomNPC()); } private IEnumerator SpawnRandomNPC() { UpdateChatOutput("Spawning a random NPC..."); yield return client.SpawnNPCCoroutine(universeId, worldSeed, null, npc => { if (npc != null) { currentNPC = npc; UpdateNPCInfo(); UpdateChatOutput($"\n{npc.Name} has entered the chat!\n"); UpdateChatOutput( $"[{npc.GetMood()} mood, stress level: {npc.GetStressLevel()}]\n\n"); } else { UpdateChatOutput( "\nFailed to spawn NPC. Check your API credentials.\n"); } }); } private void OnCharacterSpawned(NPC npc) { Debug.Log($"Character spawned: {npc.GetInfo()}"); } private void OnDialogueReceived(string response, Dictionary context, Dictionary moodTransition) { if (!useStreamingChat) { UpdateChatOutput($"\n{currentNPC.Name}: {response}\n"); if (currentNPC.HasMoodChanged()) { UpdateChatOutput( $"[Mood changed from {currentNPC.GetPreviousMood()} to {currentNPC.GetMood()}]\n"); } } } private void OnDialogueChunkReceived(string chunk) { if (useStreamingChat) { UpdateChatOutput(chunk); } } private void OnRequestFailed(string endpoint, string error) { Debug.LogError($"Request failed - {endpoint}: {error}"); UpdateChatOutput($"\n[Error: {error}]\n"); isProcessing = false; } private void OnSendButtonClicked() { if (!isProcessing && !string.IsNullOrEmpty(userInput.text) && currentNPC != null) { SendMessage(userInput.text); } } private void OnInputEndEdit(string value) { if (Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter)) { OnSendButtonClicked(); } } private void SendMessage(string message) { isProcessing = true; // Display user message UpdateChatOutput($"\nYou: {message}\n"); // Clear input userInput.text = ""; userInput.ActivateInputField(); // Send to NPC if (useStreamingChat) { StartCoroutine(StreamChatWithNPC(message)); } else { StartCoroutine(ChatWithNPC(message)); } } private IEnumerator ChatWithNPC(string message) { yield return client.SimpleChatCoroutine(currentNPC, message, response => { isProcessing = false; if (response == null) { UpdateChatOutput("\n[Failed to get response]\n"); } UpdateNPCInfo(); }, temperature, maxTokens); } private IEnumerator StreamChatWithNPC(string message) { UpdateChatOutput($"\n{currentNPC.Name}: "); var messages = new List { new ChatMessage { Role = "user", Content = message } }; bool streamComplete = false; string fullResponse = ""; // Use streaming var task = currentNPC.Chat.CompletionsAsync(messages, temperature, maxTokens, true); // Set up streaming event handlers void OnChunk(object sender, string chunk) { fullResponse += chunk; UpdateChatOutput(chunk); } void OnStreamEnd(object sender, DialogueStreamEndedEventArgs e) { streamComplete = true; if (currentNPC.HasMoodChanged()) { UpdateChatOutput( $"\n[Mood changed from {currentNPC.GetPreviousMood()} to {currentNPC.GetMood()}]\n"); } } currentNPC.DialogueChunkReceived += OnChunk; currentNPC.DialogueStreamEnded += OnStreamEnd; // Wait for stream to complete yield return new WaitUntil(() => streamComplete || task.IsCompleted); // Clean up event handlers currentNPC.DialogueChunkReceived -= OnChunk; currentNPC.DialogueStreamEnded -= OnStreamEnd; UpdateChatOutput("\n"); UpdateNPCInfo(); isProcessing = false; } private void UpdateNPCInfo() { if (currentNPC != null) { npcNameText.text = currentNPC.Name; npcInfoText.text = $"{currentNPC.Profession} | Type {currentNPC.PersonalityType} | {currentNPC.GetLocation()}\n" + $"Mood: {currentNPC.GetMood()} | Stress: {currentNPC.GetStressLevel()}"; } } private void UpdateChatOutput(string text) { chatOutput.text += text; // Auto-scroll to bottom Canvas.ForceUpdateCanvases(); scrollRect.verticalNormalizedPosition = 0f; } private void OnDestroy() { if (client != null) { client.OnCharacterSpawned -= OnCharacterSpawned; client.OnDialogueReceived -= OnDialogueReceived; client.OnDialogueChunkReceived -= OnDialogueChunkReceived; client.OnRequestFailed -= OnRequestFailed; } } } } #endif