Return always JSON response using assistant API

Hi There,
I am currently using node js openai package, and create assistant in playground and feed some JSON format files to it.
It works great when i search something and GPT response back in descriptive manner.
However like completion API there is a method function_call which force API to use that function to response back in specific format.
How i can achieve this in assistant API, i want to return JSON response always.
For example:

await openai.beta.threads.runs.submitToolOutputs(
                    thread.id,
                    run.id,
                    {
                      tool_outputs: [
                        {
                          tool_call_id: toolCall?.id,
                          output: JSON.stringify({'first_name': args.first_name, 'last_name' : args.last_name}),
                        },
                      ],
                    },
                );

I am using this code to submit my tool output.
But finally appending response like this.

if (messageValue && messageValue.text && messageValue.text.value) {
                console.log(messageValue.text.value)
                socket.emit('message', {
                    role: 'ai',
                    content: JSON.parse(messageValue.text.value)
                });
            }

I did not find any valuable help regarding this on net, Kindly put me in the right direction.

Thanks

1 Like

hay did u forget to add the semicolon
like this
;

> if (messageValue && messageValue.text && messageValue.text.value) {
  const jsonResponse = JSON.parse(messageValue.text.value);


  console.log(jsonResponse);

  socket.emit('message', {
    role: 'ai',
    content: jsonResponse,
  });
}

semicolons are used to do like a check list of what does what and when to do this and other functions i like to think of it like the exact function then moving to next till deactivates function is active. right now you’re close but missing the check list. Easy fixes

@michael.simpson555 Its not related to semicolon, but its a good practice to always end your statement.
My Main concern is that how i can get the always JSON formatted response.
I do not want to use prompt thing, because prompt did not always 100% right, wo i have to use function calling with assistant api, we have our own data which we want to train with assistant api.
But i am not sure here how i can get back the formatted response.
Thanks

To ensure that the response is always in JSON format, you need to structure your tool output like
this

`await openai.beta.threads.runs.submitToolOutputs(
    thread.id,
    run.id,
    {
        tool_outputs: [
            {
                tool_call_id: toolCall?.id,
                output: JSON.stringify({'first_name': args.first_name, 'last_name' : args.last_name}),
            },
        ],
    },
);
`

mit work but I don’t know cuz im not looking at the whole code using JSON.parse to convert the received response back into a JavaScript object. This is also correct and aligns with your goal of working with JSON.

if (messageValue && messageValue.text && messageValue.text.value) {
    console.log(messageValue.text.value)
    socket.emit('message', {
        role: 'ai',
        content: JSON.parse(messageValue.text.value)
    });
}

and u must fine tune it

Hi @michael.simpson555
I am trying to get the structured response and currently using GPT 3.5.
Here is my code:

import OpenAI from "openai";
import dotenv from "dotenv";

dotenv.config();
const openai = new OpenAI({apiKey: process.env.OPENAI_API_KEY});

const setTalentDataJson = {
    "name": "setTalentInfo",
    "description": "Get the tagline and languages of a talent.",
    "parameters": {
        "type": "object",
        "properties": {
            "tagline": {
                "type": "string",
                "description": "The tagline of the talent."
            },
            "languages": {
                "type": "string",
                "description": "The language of the talent."
            },
            "bio": {
                "type": "string",
                "description": "The bio of the talent."
            }
        },
        // "required": ["tagline", "languages"]
    }
};

const getTalentDataJson = {
    "name": "getTalentInfo",
    "description": "Get the tagline and languages of a talent.",
    "parameters": {
        "type": "object",
        "properties": {
            "tagline": {
                "type": "string",
                "description": "The tagline of the talent."
            },
            "languages": {
                "type": "string",
                "description": "The language of the talent."
            }
        },
        // "required": ["tagline", "languages"]
    }
};

const getTalentInfo = async ( tagline, languages)  => {
    const talent_data = {
        "first_name": "John",
        "last_name": "Doe",
        "tagline": "Instructional Designer",
        "bio": "Hi, I'm an Instructional Designer with over 7 years of experience developing end-to-end training solutions. I can help you in all stages of the process: assessing the needs of your learners, creating a strategy to train them more effectively, developing custom e-learning modules and selecting the right LMS for your organization.",
        "location": "Canada",
        "languages": [
            "English",
            "French",
            "Spanish"
        ]
    };
    return talent_data
};

const setTalentInfo = async (tagline, languages, bio) => {
    const talent_data = {
        "tagline": tagline,
        "languages": languages,
        "bio": bio
    };
    return talent_data;
};

async function callGpt(model, systemPrompt, userPrompt) {
    let messages = [
        {role: "system", content: systemPrompt},
        {role: "user", content: userPrompt}
    ];

    console.log('---------- Request -------------');
    console.log(messages);

    const response = await openai.chat.completions.create({
        model: model,
        messages: messages,
        functions: [getTalentDataJson]
    });

    let responseMessage = response.choices[0].message;
    console.log("Got Response: ", responseMessage);
    messages.push(responseMessage);

    if(responseMessage.function_call?.name === 'getTalentInfo') {
        const args = JSON.parse(responseMessage.function_call.arguments);
        const talent = await getTalentInfo(args.tagline, args.languages);

        const talent_data = {"first_name": talent.first_name, "last_name": talent.last_name, "tagline": talent.tagline, "bio": talent.bio, "languages": talent.languages};
        const talent_return_data = await setTalentInfo(talent.tagline, talent.languages, talent.bio);
        
        messages.push({role: "function", name: "getTalentInfo", content: JSON.stringify(talent_return_data)});

        const response2 = await openai.chat.completions.create({
            model: "gpt-3.5-turbo-1106",
            messages: messages,
            functions: [setTalentDataJson],
            function_call: {
                name: "setTalentInfo",
                arguments: JSON.stringify(talent_return_data)
            }
        });

        console.log( response2.choices[0].message)

        if (response2.function_call && response2.function_call.name === 'setTalentInfo') {
            console.log("Response 2", response2.choices[0].message);
            return JSON.parse(response2.function_call.arguments);
        } else {
            console.error("Error in processing the response from OpenAI GPT-3.5-turbo.");
            // Handle the error or provide a default value
            return null;
        }
    }
}

const result = await callGpt("gpt-3.5-turbo-1106",
        "You are a highly experienced talent recruiter. You help people find the right human resource for their needs.",
        "I am looking for Instructional designer who speaks french");

console.log("Result", result);

Whenever function triggers it always return the structured data which i have defined in setTalentData.
Like whatever data search by function call it always return the predefined data like in setTalentData
In this case i want to return tagline, languages, bio. But it did not return the bio, its only return the tagline and languages.
Looking forward

the problem lies in how the setTalentInfo function is structured. The talent_data object in the setTalentInfo function only contains tagline and languages . To include the bio in the response, you should modify the talent_data object to include the bio field as well. like so `

import OpenAI from “openai”;
import dotenv from “dotenv”;

dotenv.config();
const openai = new OpenAI({apiKey: process.env.OPENAI_API_KEY});

const setTalentDataJson = {
“name”: “setTalentInfo”,
“description”: “Get the tagline, languages, and bio of a talent.”,
“parameters”: {
“type”: “object”,
“properties”: {
“tagline”: {
“type”: “string”,
“description”: “The tagline of the talent.”
},
“languages”: {
“type”: “string”,
“description”: “The language of the talent.”
},
“bio”: {
“type”: “string”,
“description”: “The bio of the talent.”
}
},
}
};

const getTalentDataJson = {
“name”: “getTalentInfo”,
“description”: “Get the tagline, languages, and bio of a talent.”,
“parameters”: {
“type”: “object”,
“properties”: {
“tagline”: {
“type”: “string”,
“description”: “The tagline of the talent.”
},
“languages”: {
“type”: “string”,
“description”: “The language of the talent.”
}
},
}
};

const getTalentInfo = async (tagline, languages) => {
const talent_data = {
“first_name”: “John”,
“last_name”: “Doe”,
“tagline”: “Instructional Designer”,
“bio”: “Hi, I’m an Instructional Designer with over 7 years of experience developing end-to-end training solutions. I can help you in all stages of the process: assessing the needs of your learners, creating a strategy to train them more effectively, developing custom e-learning modules and selecting the right LMS for your organization.”,
“location”: “Canada”,
“languages”: [
“English”,
“French”,
“Spanish”
]
};
return talent_data;
};

const setTalentInfo = async (tagline, languages, bio) => {
const talent_data = {
“tagline”: tagline,
“languages”: languages,
“bio”: bio
};
return talent_data;
};

async function callGpt(model, systemPrompt, userPrompt) {
let messages = [
{role: “system”, content: systemPrompt},
{role: “user”, content: userPrompt}
];

console.log('---------- Request -------------');
console.log(messages);

const response = await openai.chat.completions.create({
    model: model,
    messages: messages,
    functions: [getTalentDataJson]
});

let responseMessage = response.choices[0].message;
console.log("Got Response: ", responseMessage);
messages.push(responseMessage);

if(responseMessage.function_call?.name === 'getTalentInfo') {
    const args = JSON.parse(responseMessage.function_call.arguments);
    const talent = await getTalentInfo(args.tagline, args.languages);

    const talent_data = {"first_name": talent.first_name, "last_name": talent.last_name, "tagline": talent.tagline, "bio": talent.bio, "languages": talent.languages};
    const talent_return_data = await setTalentInfo(talent.tagline, talent.languages, talent.bio);
    
    messages.push({role: "function", name: "getTalentInfo", content: JSON.stringify(talent_return_data)});
    const response2 = await openai.chat.completions.create({
        model: "gpt-3.5-turbo-1106",
        messages: messages,
        functions: [setTalentDataJson],
        function_call: {
            name: "setTalentInfo",
            arguments: JSON.stringify(talent_return_data)
        }
    });
    console.log(response2.choices[0].message);
    if (response2.function_call && response2.function_call.name === 'setTalentInfo') {
        console.log("Response 2", response2.choices[0].message);
        return JSON.parse(response2.function_call.arguments);
    } else {
        console.error("Error in processing the response from OpenAI GPT-3.5-turbo.");
        // Handle the error or provide a default value
        return null;
    }
}

}

const result = await callGpt(“gpt-3.5-turbo-1106”,
“You are a highly experienced talent recruiter. You help people find the right human resource for their needs.”,
“I am looking for an Instructional designer who speaks French”);

console.log(“Result”, result);

Make sure to include the bio field in the returned object. With this change, when you call this function it should work if its coded right

@michael.simpson555
I am currently using OpenAI API in php, But when tool call happened and send response back to completion API it throws this error.
Uncaught OpenAI\Exceptions\ErrorException: Additional properties are not allowed (‘functionCall’, ‘toolCalls’ were unexpected) - ‘messages.2’

Here is my loop code,

foreach ($response->choices as $result) {
        $responseMessage = (object) $result->message;
        array_push($messages, $responseMessage);

        if($result->finishReason == 'tool_calls' && $result->message->toolCalls[0]->function->name == 'getTalentInfo') {
            $first_response_args = json_decode($result->message->toolCalls[0]->function->arguments, true);
            $talent_response_algolia = getTalentInfo($first_response_args, $userPrompt);
            array_push($messages, ['tool_call_id' => $result->message->toolCalls[0]->id, 'role' => 'tool', 'name' => 'setTalentInfo', 'content' => json_encode($talent_response_algolia)]);

            // $function_messages = [
            //     ['role' => 'function', 'name' => "setTalentInfo", 'content' => json_encode($talent_response_algolia)]
            // ];


            $messages[2]->content = 'testing';
            // print_r($messages);
            // die;
            $response2 = $client->chat()->create([
                'model' => 'gpt-3.5-turbo-1106',
                'messages' => $messages,
                'tools' => [$setTalentDataJson],
                'tool_choice' => [
                    "type" => "function",
                    "function" => [
                        "name" => "setTalentInfo",
                        "arguments" => json_encode($talent_response_algolia)
                    ]
                ]
            ]);
            print_r($response2);
            die;
        } else {
            $responseMessage->openaiResponseType = 'true';
            return $responseMessage;
        }
    }

The getTalentInfo returns the array which then i parse with json_encode function.
But when i pass the message to response2 it throws the above error.
I have tried setting content with some dummy text but no luck,
Someone try the same approach in this article

where he set the content to empty string.
But in my case i am still facing the same issue.
Here is my message[2] data.

[2] => OpenAI\Responses\Chat\CreateResponseMessage Object
        (
            [role] => assistant
            [content] => testing
            [toolCalls] => Array
                (
                    [0] => OpenAI\Responses\Chat\CreateResponseToolCall Object
                        (
                            [id] => call_gTlwumEIgAwE5oicLiDg8AZB
                            [type] => function
                            [function] => OpenAI\Responses\Chat\CreateResponseToolCallFunction Object
                                (
                                    [name] => getTalentInfo
                                    [arguments] => {"tagline":"Instructional Designer","languages":"French"}
                                )

                        )

                )

            [functionCall] => 
        )

let me know how i can resolve this.
Thanks