Hi all, I'm trying to write code to integrate with the API from convai.com for creating a conversation with an AI character. The API reference is here. Specifically, I'm trying to use this part of the API: "Interact with a Character."

Interact with a Character

Important Points to Remember:

  • The API endpoint expects the request body to contain only one type of input (either text input, via userText, or audio input via file). Including both types of input or none will result in an error.

Here are some sample codes to demonstrate the request format for the endpoint -->

Request with text only:

import requests
import json
import base64

url = "https://api.convai.com/character/getResponse"

payload={
    'userText': 'What is your name ?',
    'charID': '<your character id>',
    'sessionID': '-1',
    'voiceResponse': 'True'
}

headers = {
  'CONVAI-API-KEY': '<your api key>'
}

response = requests.request("POST", url, headers=headers, data=payload)

data = response.json()

character_response = data["text"]

decode_string = base64.b64decode(data["audio"])

with open('audioResponse.wav','wb') as f:
  f.write(decode_string)

Below is the node code I have written to interact with this API. I'm getting a response back of code 400, saying that "charID" is a required field. I do have charID specified so I must be doing something wrong with the formatting. Anyone have any ideas?

extends Node
## This is a script to query convAI for AI-generated NPC dialogue.  
## You need a convAI API key for this to work; put it as a string in the
## export variable for api_key and in the ready script for Godot-AI-NPC Controller
## (if using the demo scene).

#Signal used to alert other entities of the final GPT response text
signal AI_response_generated(response)


export(String) var api_key = "REDACTED" setget set_api_key # Your API key from convai.com
export(String) var convai_session_id = "-1"
export(String) var convai_character_id = "08333140-daac-11ed-9c7d-42010a7c4003"
export(bool) var voice_response = false
var url = "https://api.convai.com/character/getResponse" 
var headers = ["Content-Type: application/json", "CONVAI-API-KEY: " + api_key]
var http_request : HTTPRequest


func _ready():
	# set up normal http request node for calls to call_GPT function
	http_request = HTTPRequest.new()
	add_child(http_request)
	http_request.connect("request_completed", self, "_on_request_completed")
	

		
func call_convAI(prompt):
	var voice_response_string : String
	
	if voice_response == true:
		voice_response_string = "True"
	else:
		voice_response_string = "False"
			
	print("calling convAI")
	var body = JSON.print({
		"userText": prompt,
		"charID": "08333140-daac-11ed-9c7d-42010a7c4003",
		"sessionID": "-1",
		"voiceResponse": "False"
	})
	
	# Now call convAI
	var error = http_request.request(url, headers, true, HTTPClient.METHOD_POST, body)
	
	if error != OK:
		push_error("Something Went Wrong!")
		print(error)
	
# This GDScript code is used to handle the response from a request.
func _on_request_completed(result, responseCode, headers, body):
	# Should recieve 200 if all is fine; if not print code
	if responseCode != 200:
		print("There was an error, response code:" + str(responseCode))
		var data = body.get_string_from_utf8()
		print(data)
		return
		
	var data = body.get_string_from_utf8()#fix_chunked_response(body.get_string_from_utf8())
	print ("Data received: %s"%data)
	var response = parse_json(data)
	var AI_generated_dialogue = response["text"]
	set_session_id(response["sessionID"])
	# Let other nodes know that AI generated dialogue is ready from Convai	
	emit_signal("AI_response_generated", AI_generated_dialogue)
a year later

I contacted Convai support for this one and they pointed to the section in the docs that specifies that the request has to be encoded as multipart/form or application/xxx-www-form-url_encoded.
After failing at getting the right string for the former, I managed to get a working request like this:

func send_prompt(prompt: String) -> Error:
	var endpoint_node: HTTPRequest = $"PromptRequests"

	var request_url: String = API_URL + "/character/getResponse"

	var headers: Array[String] = [
		"Content-Type: application/x-www-form-urlencoded",
		 _key_header,  # "CONVAI-API-KEY: <your_key>"
	]

	var request_params: Dictionary = {
		"userText": prompt, "charID": _character_id, "sessionID": "-1", "voiceResponse": "False"
	}

	var query_parts := PackedStringArray()

	for param_key in request_params.keys():
		query_parts.push_back(
			"{param}={value}".format({"param": param_key, "value": request_params[param_key]})
		)

	var request_string: String = "&".join(query_parts).format(request_params)

	headers.append("Content-Length: %s" % str(request_string.length()))

	var error: Error = endpoint_node.request(
		request_url, headers, HTTPClient.METHOD_POST, request_string
	)

	return error

I hope you still have't given up and can use this almost half a year later 🙂