npc-clients-godot/examples/QuickstartChat.gd

182 lines
4.9 KiB
GDScript

# Quickstart: Chat UI with NPCs (with Streaming Support)
# Save as QuickstartChat.gd and attach to a Control node
extends Control
@onready var chat_display = RichTextLabel.new()
@onready var input_field = LineEdit.new()
@onready var send_button = Button.new()
@onready var streaming_toggle = CheckBox.new()
var current_npc: GumYumNPC
var is_streaming: bool = false
func _ready():
# Setup UI
setup_ui()
# Configure API
GumyumClient.api_key = "gumyum-pk-your-public-key"
GumyumClient.api_secret = "gumyum-sk-your-secret-key"
GumyumClient.base_url = "https://npc.gumyum.com"
# Spawn a random NPC
add_system_message("Connecting to GumYum API...")
GumyumClient.npcs.spawn("kingdom", 42, null, _on_npc_spawned) # universe # seed # npc_id (null = random)
func setup_ui():
# Create a VBox container
var vbox = VBoxContainer.new()
vbox.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
add_child(vbox)
# Title
var title = Label.new()
title.text = "GumYum NPC Chat (Quickstart)"
title.add_theme_font_size_override("font_size", 24)
vbox.add_child(title)
# Streaming toggle
streaming_toggle.text = "Enable streaming (typewriter effect)"
streaming_toggle.toggled.connect(_on_streaming_toggled)
vbox.add_child(streaming_toggle)
# Chat display (scrollable)
chat_display.bbcode_enabled = true
chat_display.scroll_following = true
chat_display.custom_minimum_size = Vector2(0, 400)
vbox.add_child(chat_display)
# Input container
var hbox = HBoxContainer.new()
vbox.add_child(hbox)
# Input field
input_field.placeholder_text = "Type your message..."
input_field.size_flags_horizontal = Control.SIZE_EXPAND_FILL
input_field.text_submitted.connect(_on_text_submitted)
hbox.add_child(input_field)
# Send button
send_button.text = "Send"
send_button.pressed.connect(_on_send_pressed)
hbox.add_child(send_button)
func _on_npc_spawned(npc: GumYumNPC):
if npc == null:
add_system_message("[color=red]Failed to spawn NPC![/color]")
return
current_npc = npc
# Connect streaming signals for this NPC
current_npc.dialogue_stream_started.connect(_on_stream_started)
current_npc.dialogue_chunk_received.connect(_on_chunk_received)
current_npc.dialogue_stream_ended.connect(_on_stream_ended)
add_system_message(
"[color=green]Connected to " + npc.name + " the " + npc.profession + "[/color]"
)
input_field.editable = true
send_button.disabled = false
input_field.grab_focus()
func _on_streaming_toggled(button_pressed: bool):
add_system_message(
"[color=yellow]Streaming " + ("enabled" if button_pressed else "disabled") + "[/color]"
)
func _on_text_submitted(text: String):
send_message(text)
func _on_send_pressed():
send_message(input_field.text)
func send_message(text: String):
if text.is_empty() or current_npc == null or is_streaming:
return
add_player_message(text)
input_field.text = ""
# Disable input while processing
input_field.editable = false
send_button.disabled = true
# Check if streaming is enabled
var use_streaming = streaming_toggle.button_pressed
# Send to NPC with or without streaming
current_npc.chat_with_history(text, 0.8, 1500, use_streaming, _on_chat_response) # temperature # max_tokens # streaming based on toggle
# Set streaming flag if streaming is enabled
if use_streaming:
is_streaming = true
func _on_chat_response(response):
if response.has("error"):
add_system_message("[color=red]Error: " + response.error + "[/color]")
# Re-enable input on error
is_streaming = false
input_field.editable = true
send_button.disabled = false
input_field.grab_focus()
elif not streaming_toggle.button_pressed:
# Non-streaming response
if response.has("choices") and response.choices.size() > 0:
var content = response.choices[0]["message"]["content"]
add_npc_message(content)
# Re-enable input
input_field.editable = true
send_button.disabled = false
input_field.grab_focus()
# Streaming-specific functions
func _on_stream_started():
# Show NPC is typing
chat_display.append_text("[b][color=cyan]" + current_npc.name + ":[/color][/b] ")
func _on_chunk_received(chunk: String):
# Append each chunk as it arrives
chat_display.append_text(chunk)
# Auto-scroll to bottom
chat_display.scroll_to_line(chat_display.get_line_count() - 1)
func _on_stream_ended(_full_response: String, _context: Dictionary, mood_transition: Dictionary):
chat_display.append_text("\n\n")
# Check for mood changes
if mood_transition.has("new_mood"):
chat_display.append_text("[i](mood: " + mood_transition.new_mood + ")[/i]\n\n")
# Re-enable input
is_streaming = false
input_field.editable = true
send_button.disabled = false
input_field.grab_focus()
func add_player_message(text: String):
chat_display.append_text("[b]You:[/b] " + text + "\n\n")
func add_npc_message(text: String):
chat_display.append_text(
"[b][color=cyan]" + current_npc.name + ":[/color][/b] " + text + "\n\n"
)
func add_system_message(text: String):
chat_display.append_text("[i]" + text + "[/i]\n\n")