#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