Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GoogleGenerativeAIError: "Invalid JSON payload received" when calling functionResponse #301

Open
duyp6090 opened this issue Nov 28, 2024 · 2 comments
Assignees
Labels
component:other Questions unrelated to SDK status:triaged Issue/PR triaged to the corresponding sub-team type:help Support-related issues

Comments

@duyp6090
Copy link

duyp6090 commented Nov 28, 2024

Description of the bug:

I'm encountering an issue while integrating the Google Generative AI API. Specifically, I'm getting a 400 Bad Request error with the message:

Invalid JSON payload received. Unknown name "response" at 'contents[2].parts[0].function_response': Proto field is not repeating, cannot start list.

Actual vs expected behavior:

This are my calling function

// 1.1 Create fuction declarations for the information of a restaurant
const informationRestaurantDeclaration = {
    name: "informationOfRestaurant",
    description: "Tìm kiếm thông tin của một nhà hàng dựa vào tên và thêm quận nếu có",
    parameters: {
        type: "object",
        description: "Tìm kiếm thông tin của một nhà hàng",
        properties: {
            restaurantName: {
                type: "string",
                description: "Tên nhà hàng",
            },
            borough: {
                type: "string",
                description: "Quận",
            },
        },
        required: ["restaurantName"],
    },
};

// 2 Recommend restaurant fot user - API function
async function recommendedRestaurant(borough, street, rating, time_open, time_close, categories) {
    try {
        // Find condition
        let find = {
            status: "active",
        };

        // Recommend restaurant by information that user give
        const objectSearchBorough = search(borough);
        const objectSearchStreet = search(street);
        const objectSearchTimeOpen = search(time_open);
        const objectSearchTimeClose = search(time_close);

        if (objectSearchBorough.regex) {
            find["address.borough"] = objectSearchBorough.regex;
        }
        if (objectSearchStreet.regex) {
            find["address.street"] = objectSearchStreet.regex;
        }
        if (rating) {
            find["starMedium"] = { $gte: rating };
        }
        if (objectSearchTimeOpen.regex) {
            find.time_open = objectSearchTimeOpen.regex;
        }
        if (objectSearchTimeClose.regex) {
            find.time_close = objectSearchTimeClose.regex;
        }

        // Find the restaurant
        const restaurants = await Restaurant.find(find).select("name address");

        if (categories && categories.length > 0) {
            // New categories array
            const newCategories = categories.map((category) => {
                return search(category).regex;
            });

            // Find the food of the restaurant
            const promiseRestaurant = restaurants.map(async (restaurant) => {
                // Get id of the restaurant
                const restaurantId = restaurant._id;

                // Find the food of the restaurant
                const foods = await MenuItem.find({
                    restaurantId: restaurantId,
                    category: { $in: newCategories },
                }).select("title");

                return {
                    ...restaurant,
                    foods: foods,
                };
            });

            // Wait for all promise
            restaurants = await Promise.all(promiseRestaurant);
        }

        // If the restaurant is not found
        if (!restaurants || restaurants.length === 0) {
            return "Không tìm thấy nhà hàng";
        }

        return restaurants;
    } catch (error) {
        return "Đã xảy ra lỗi khi tìm kiếm nhà hàng. Vui lòng thử lại sau.";
    }
}

// 2.1 Create fuction declarations for the recommend restaurant
const recommendedRestaurantDeclaration = {
    name: "recommendRestaurantForUser",
    description:
        "Gợi ý các nhà hàng và kèm theo món ăn của nhà hàng nếu có dựa trên thông tin người dùng cung cấp",
    parameters: {
        type: "object",
        description:
            "Gợi ý các nhà hàng và kèm theo món ăn của nhà hàng nếu có theo yêu cầu của người dùng cung cấp",
        properties: {
            borough: {
                type: "string",
                description: "Quận",
            },
            street: {
                type: "string",
                description: "Đường",
            },
            rating: {
                type: "number",
                description: "Đánh giá sao trung bình của nhà hàng",
            },
            time_open: {
                type: "string",
                description: "Thời gian mở cửa của nhà hàng",
            },
            time_close: {
                type: "string",
                description: "Thời gian đóng cửa của nhà hàng",
            },
            categories: {
                type: "array",
                description: "Danh sách loại món ăn",
                items: {
                    type: "string",
                    description: "Tên loại món ăn",
                },
            },
        },
    },
};

// Create list of function
const functions = {
    informationOfRestaurant: ({ restaurantName, borough }) => {
        return informationRestaurant(restaurantName, borough);
    },
    recommendRestaurantForUser: ({
        borough,
        street,
        rating,
        time_open,
        time_close,
        categories,
    }) => {
        return recommendedRestaurant(borough, street, rating, time_open, time_close, categories);
    },
};`

This is my model
`// Create a new instance of the GoogleGenerativeAI
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);

const generatetiveModel = genAI.getGenerativeModel({
    model: "gemini-1.5-flash",
    systemInstruction:
        "Bạn là một chatbot của ứng dụng Yummy. Nhiệm vụ của bạn là hỗ trợ người dùng tìm hiểu về thông tin của website Yummy. Website Yummy là trang web cho phép mọi người đặt và bán đồ ăn, thức uống. Những thông tin cơ bản mà người dùng cần chủ yếu là các thông tin của món ăn và nhà hàng, đơn đặt hàng của họ.Bạn có thể giúp tôi không?",
    tools: {
        functionDeclarations: [informationRestaurantDeclaration, recommendedRestaurantDeclaration],
    },
});

const questionGemini = async (req, res) => {
    // Get hisstory from the request body
    const historyChat = req.body.historyChat;
    const newQuestion = req.body.question;

    // Start chat with the generative model
    const chat = generatetiveModel.startChat({
        history: historyChat,
    });

    // Send the question to the generative model
    const result = await chat.sendMessage(newQuestion);
    console.log(result.response.functionCalls());
    let answer = "";

    // Get function calling is recommended
    const callingFunctions = result.response.functionCalls();

    if (callingFunctions && callingFunctions.length > 0) {
        // Get the first calling function
        const callingFunction = callingFunctions[0];

        // Call the function
        const apiResponse = await functions[callingFunction.name](callingFunction.args);

        // Ensure apiResponse is properly formatted
        const functionResponse = {
            name: callingFunction.name,
            response: apiResponse,
        };

        // Reget the response from the generative model
        const result2 = await chat.sendMessage([
            {
                functionResponse: functionResponse,
            },
        ]);
        console.log(result2);

        // Get answer from the generative model
        answer = result2.response.text();
    } else {
        // Get answer from the generative model
        answer = result.response.candidates[0].content.parts[0].text;
    }

    // Send the response to the client
    res.status(200).json({
        message: "Success",
        answer: answer,
    });
};

Any other information you'd like to share?

I’m not sure what’s causing this issue. The functionResponse object is being passed as a list, but the error message suggests that the response field can't be used in this way.

@duyp6090 duyp6090 reopened this Nov 28, 2024
@manojssmk manojssmk added type:help Support-related issues status:triaged Issue/PR triaged to the corresponding sub-team component:other Questions unrelated to SDK labels Nov 28, 2024
@MarkDaoust
Copy link

This one looks like it's complaining that you haven't formatted the function_response object the way it's expecting.

It sounds like you're trying to return a list, but it's expecting a struct as defined here:

https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/struct.proto#L51-L78

To return a list of strings the json you need is probably:

return {'restaurants`: {'list_value': [{'string_value': name1}, {'string_value': name2}, ]}}

But if you search around you can probably find some utility that converts json to the equivalent struct.proto.

@duyp6090
Copy link
Author

Thank you so much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component:other Questions unrelated to SDK status:triaged Issue/PR triaged to the corresponding sub-team type:help Support-related issues
Projects
None yet
Development

No branches or pull requests

4 participants