npc-clients-godot/examples/NpcChatExample.gd

171 lines
4.9 KiB
GDScript

extends Control
## Simple example of chatting with an NPC
##
## This example shows how to:
## - Spawn an NPC
## - Send messages using chat_with_history
## - Handle streaming responses
@export var api_base_url: String = "https://npc.gumyum.com"
@export var api_key: String = "gumyum-pk-your-public-key"
@export var api_secret: String = "gumyum-sk-your-secret-key"
@export var universe_id: String = "kingdom"
@export var enable_streaming: bool = true
var current_npc: GumYumNPC
var is_waiting_response: bool = false
@onready var chat_input: LineEdit = $VBoxContainer/ChatInput
@onready var chat_display: RichTextLabel = $VBoxContainer/ChatDisplay
@onready var npc_name_label: Label = $VBoxContainer/NPCInfo/NameLabel
@onready var npc_mood_label: Label = $VBoxContainer/NPCInfo/MoodLabel
@onready var send_button: Button = $VBoxContainer/SendButton
func _ready():
# Connect UI signals
send_button.pressed.connect(_on_send_pressed)
chat_input.text_submitted.connect(_on_text_submitted)
# Initialize GumYum client
_setup_client()
# Spawn an NPC when ready
_spawn_random_npc()
func _setup_client():
# Set up authentication
GumyumClient.base_url = api_base_url
GumyumClient.api_key = api_key
GumyumClient.api_secret = api_secret
# Optional: Enable debug mode
GumyumClient.debug_mode = true
chat_display.append_bbcode("[color=green]Connected to GumYum API[/color]\n")
func _spawn_random_npc():
chat_display.append_bbcode("[color=yellow]Spawning NPC...[/color]\n")
# Use the npcs manager to spawn
# The response will be a GumYumNPC object
GumyumClient.npcs.spawn(universe_id, 42, null, _on_npc_spawned) # universe # seed (consistent with docs) # Random NPC (null)
func _on_npc_spawned(npc: GumYumNPC):
if npc == null:
push_error("Failed to spawn NPC")
chat_display.append_bbcode("[color=red]Failed to spawn NPC![/color]\n")
return
current_npc = npc
# Connect to NPC's dialogue signals
npc.dialogue_received.connect(_on_dialogue_received)
npc.dialogue_stream_started.connect(_on_stream_started)
npc.dialogue_chunk_received.connect(_on_stream_chunk)
npc.dialogue_stream_ended.connect(_on_stream_ended)
# Update UI
npc_name_label.text = "Name: " + npc.name
npc_mood_label.text = "Mood: " + npc.get_mood()
# Announce spawn
chat_display.append_bbcode("\n[b][color=cyan]" + npc.name + " appears![/color][/b]\n")
chat_display.append_bbcode("[i]A " + npc.profession + " approaches you.[/i]\n\n")
# Enable chat
chat_input.editable = true
send_button.disabled = false
func _on_send_pressed():
_send_message()
func _on_text_submitted(_text: String):
_send_message()
func _send_message():
var message = chat_input.text.strip_edges()
if message.is_empty() or is_waiting_response:
return
# Clear input
chat_input.text = ""
# Add user message to display
chat_display.append_bbcode("[b]You:[/b] " + message + "\n")
# Disable input while processing
is_waiting_response = true
chat_input.editable = false
send_button.disabled = true
# Send message using NPC's chat_with_history
current_npc.chat_with_history(
message, # message text
0.8, # temperature
2000, # max_tokens
enable_streaming, # streaming
_on_dialogue_received if not enable_streaming else Callable()
)
func _on_dialogue_received(response):
# Handle the API response format
if response.has("error"):
chat_display.append_bbcode("[color=red]Error: " + response.error + "[/color]\n")
elif response.has("choices") and response.choices.size() > 0:
var content = response.choices[0]["message"]["content"]
chat_display.append_bbcode("[b][color=cyan]" + current_npc.name + ":[/color][/b] ")
chat_display.append_bbcode(content + "\n\n")
# Check for mood transition in response
if response.has("mood_transition"):
var new_mood = response.mood_transition.get("new_mood", "")
if new_mood:
npc_mood_label.text = "Mood: " + new_mood
chat_display.append_bbcode("[i][color=gray](mood: " + new_mood + ")[/color][/i]\n")
# Re-enable input
is_waiting_response = false
chat_input.editable = true
send_button.disabled = false
chat_input.grab_focus()
var stream_buffer: String = ""
func _on_stream_started():
stream_buffer = ""
chat_display.append_bbcode("[b][color=cyan]" + current_npc.name + ":[/color][/b] ")
func _on_stream_chunk(chunk: String):
stream_buffer += chunk
# Clear and rewrite the current line with updated buffer
# Note: This is a simple approach - you may want more sophisticated handling
chat_display.append_bbcode(chunk)
func _on_stream_ended(_full_response: String, _context: Dictionary, mood_transition: Dictionary):
chat_display.append_bbcode("\n\n")
# Handle mood change
if mood_transition and not mood_transition.is_empty():
var new_mood = mood_transition.get("new_mood", "")
if new_mood:
npc_mood_label.text = "Mood: " + new_mood
chat_display.append_bbcode("[i][color=gray](mood: " + new_mood + ")[/color][/i]\n")
# Re-enable input
is_waiting_response = false
chat_input.editable = true
send_button.disabled = false
chat_input.grab_focus()