171 lines
4.9 KiB
GDScript
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()
|