mscraftsman / generative-ai

Gemini AI SDK for .NET and ASP.NET Core enables developers to use Google's state-of-the-art generative AI models to build AI-powered features and applications.
https://mscraftsman.github.io/generative-ai/
Apache License 2.0
55 stars 11 forks source link

Unknown error due to some settings #7

Closed doggy8088 closed 7 months ago

doggy8088 commented 7 months ago

The following code will produce Response status code does not indicate success: 400 (Bad Request). error. I have no idea.

async Task Main()
{
    var googleAI = new GoogleAI(apiKey: Util.GetPassword("GEMINI_API_KEY"));
    var model = googleAI.GenerativeModel(model: Model.GeminiPro,
        generationConfig: new GenerationConfig()
        {
            TopK = 1,
            TopP = 1,
            Temperature = 0.9f
        },
        safetySettings: new List<SafetySetting>()
        {
            new SafetySetting() { Category = HarmCategory.HarmCategoryHarassment, Threshold = HarmBlockThreshold.BlockOnlyHigh },
            new SafetySetting() { Category = HarmCategory.HarmCategoryHateSpeech, Threshold = HarmBlockThreshold.BlockOnlyHigh },
            new SafetySetting() { Category = HarmCategory.HarmCategorySexuallyExplicit, Threshold = HarmBlockThreshold.BlockOnlyHigh },
            new SafetySetting() { Category = HarmCategory.HarmCategoryDangerousContent, Threshold = HarmBlockThreshold.BlockOnlyHigh }
        });

    var count = await model.CountTokens("Hello World");
    count.Dump();
}

LINQPad Query: https://share.linqpad.net/entk5npb.linq

doggy8088 commented 7 months ago

I know the root cause now. The generationConfig and the safetySettings affected its request payload. That's invalid.

Here is what I think. The technical details should be hidden from the library user. The model should be reuse between generatecontent and counttokens. So maybe we can change CountTokens a bit that remove these two parts of the payload (generationConfig and the safetySettings) from the request automatically?

At this moment, I have to write two different model object to handle two different API methods:

var modelCountTokens = googleAI.GenerativeModel(model: Model.GeminiPro);

var modelGenerateContent = googleAI.GenerativeModel(model: Model.GeminiPro,
    generationConfig: new GenerationConfig()
    {
        TopK = 1,
        TopP = 1,
        Temperature = 0.9f
    },
    safetySettings: new List<SafetySetting>()
    {
        new SafetySetting() { Category = HarmCategory.HarmCategoryHarassment, Threshold = HarmBlockThreshold.BlockOnlyHigh },
        new SafetySetting() { Category = HarmCategory.HarmCategoryHateSpeech, Threshold = HarmBlockThreshold.BlockOnlyHigh },
        new SafetySetting() { Category = HarmCategory.HarmCategorySexuallyExplicit, Threshold = HarmBlockThreshold.BlockOnlyHigh },
        new SafetySetting() { Category = HarmCategory.HarmCategoryDangerousContent, Threshold = HarmBlockThreshold.BlockOnlyHigh }
    });
jochenkirstaetter commented 7 months ago

Is this related to #8 while using SafetySettings associated with PaLM 2 models?

jochenkirstaetter commented 7 months ago

New version 0.9.1 should make it clearer.

Plus, there is the official documentation about Safety settings in Gemini that apply.

Hope this helps. Closing the issue (for now).

doggy8088 commented 7 months ago

The current (v0.9.1) usage is much better. I just move the generationConfig and safetySettings settings to the GenerateContent() method.

var response = await model.GenerateContent(prompt,
    generationConfig: new GenerationConfig()
    {
        TopK = 1,
        TopP = 1,
        Temperature = 0.9f
    },
    safetySettings: new List<SafetySetting>()
    {
        new SafetySetting() { Category = HarmCategory.HarmCategoryHarassment, Threshold = HarmBlockThreshold.BlockOnlyHigh },
        new SafetySetting() { Category = HarmCategory.HarmCategoryHateSpeech, Threshold = HarmBlockThreshold.BlockOnlyHigh },
        new SafetySetting() { Category = HarmCategory.HarmCategorySexuallyExplicit, Threshold = HarmBlockThreshold.BlockOnlyHigh },
        new SafetySetting() { Category = HarmCategory.HarmCategoryDangerousContent, Threshold = HarmBlockThreshold.BlockOnlyHigh }
    });
jochenkirstaetter commented 7 months ago

Cool, thanks for the feedback. Actually, you can use both locations to specify GenerationConfig and SafetySettings.

The ones you configure at the model level apply to all requests following whereas the attributes you pass into a request are for that request only. See GenerateContent(string) as an example.

Hmm, just noticed that same is currently missing with GenerateContent(request). That method should have the following block.

            request.GenerationConfig ??= _generationConfig;
            request.SafetySettings ??= _safetySettings;
            request.Tools ??= _tools;

Going to add this and to GenerateContentStream, too.