Skip to content

Commit

Permalink
add models of Gemini 1.5 and Gemini 1.0 Ultra
Browse files Browse the repository at this point in the history
  • Loading branch information
jochenkirstaetter committed Mar 27, 2024
1 parent 167e726 commit 13e7692
Show file tree
Hide file tree
Showing 7 changed files with 1,518 additions and 4 deletions.
6 changes: 6 additions & 0 deletions src/Mscc.GenerativeAI.Google/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
### Fixed

## 0.9.2

### Changed

- bump version

## 0.9.1

### Changed
Expand Down
6 changes: 6 additions & 0 deletions src/Mscc.GenerativeAI.Web/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
### Fixed

## 0.9.2

### Changed

- bump version

## 0.9.1

### Changed
Expand Down
10 changes: 9 additions & 1 deletion src/Mscc.GenerativeAI/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Feature suggestion: Retry mechanism ([#2](https://github.com/mscraftsman/generative-ai/issues/2))
- Feature suggestion: Add logs with LogLevel using the Standard logging in .NET ([#6](https://github.com/mscraftsman/generative-ai/issues/6))
- implement Automatic Function Call (AFC)

### Changed
### Fixed

## 0.9.2

### Added

- models of Gemini 1.5 and Gemini 1.0 Ultra
- tests for Gemini 1.5 and Gemini 1.0 Ultra

## 0.9.1

### Added
Expand All @@ -29,7 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- improve creation of generative model in Google AI class
- SafetySettings can be easier and less error-prone. ([#8](https://github.com/mscraftsman/generative-ai/issues/8))
- remove _useHeaderApiKey ([#10](https://github.com/mscraftsman/generative-ai/issues/10])
- remove _useHeaderApiKey ([#10](https://github.com/mscraftsman/generative-ai/issues/10]))

## 0.9.0

Expand Down
4 changes: 3 additions & 1 deletion src/Mscc.GenerativeAI/Constants/Model.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ public static class Model
public const string Gemini10ProVision = "gemini-1.0-pro-vision";
// public const string Gemini10ProVision001 = "gemini-1.0-pro-vision-001";
public const string GeminiProVisionLatest = "gemini-1.0-pro-vision-latest";
public const string Gemini15Pro = "gemini-1.5-pro";
public const string GeminiUltra = GeminiUltraLatest;
public const string GeminiUltraLatest = "gemini-1.0-ultra-latest";
public const string Gemini15Pro = Gemini15ProLatest;
public const string Gemini15ProLatest = "gemini-1.5-pro-latest";
// public const string Gemini15ProVision = "gemini-1.5-pro-vision";
public const string BisonText001 = "text-bison-001";
Expand Down
2 changes: 0 additions & 2 deletions tests/Mscc.GenerativeAI/GenerativeAI_Should.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
#if NET472_OR_GREATER || NETSTANDARD2_0
using System.Collections.Generic;
#endif
using FluentAssertions;
using Mscc.GenerativeAI;
using System.Text;
using Xunit;
using Xunit.Abstractions;

Expand Down
238 changes: 238 additions & 0 deletions tests/Mscc.GenerativeAI/GoogleAi_Gemini15Pro_Should.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
#if NET472_OR_GREATER || NETSTANDARD2_0
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
#endif
using FluentAssertions;
using Mscc.GenerativeAI;
using Xunit;
using Xunit.Abstractions;

namespace Test.Mscc.GenerativeAI
{
[Collection(nameof(ConfigurationFixture))]
public class GoogleAi_Gemini15Pro_Should
{
private readonly ITestOutputHelper output;
private readonly ConfigurationFixture fixture;
private readonly string model = Model.Gemini15Pro;

public GoogleAi_Gemini15Pro_Should(ITestOutputHelper output, ConfigurationFixture fixture)
{
this.output = output;
this.fixture = fixture;
}

[Fact]
public void Initialize_Gemini15Pro()
{
// Arrange

// Act
var model = new GenerativeModel(apiKey: fixture.ApiKey, model: this.model);

// Assert
model.Should().NotBeNull();
model.Name.Should().Be(Model.Gemini15Pro.SanitizeModelName());
}

[Fact]
public async void Generate_Text_From_Image()
{
// Arrange
var model = new GenerativeModel(apiKey: fixture.ApiKey, model: this.model);
var request = new GenerateContentRequest { Contents = new List<Content>() };
var base64image = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==";
var parts = new List<IPart>
{
new TextData { Text = "What is this picture about?" },
new InlineData { MimeType = "image/jpeg", Data = base64image }
};
request.Contents.Add(new Content { Role = Role.User, Parts = parts });

// Act
var response = await model.GenerateContent(request);

// Assert
response.Should().NotBeNull();
response.Candidates.Should().NotBeNull().And.HaveCount(1);
response.Candidates.FirstOrDefault().Content.Should().NotBeNull();
response.Candidates.FirstOrDefault().Content.Parts.Should().NotBeNull().And.HaveCountGreaterThanOrEqualTo(1);
response.Text.Should().Contain("red");
output.WriteLine(response?.Text);
}

[Fact]
public async void Describe_Image_From_InlineData()
{
// Arrange
var prompt = "Parse the time and city from the airport board shown in this image into a list, in Markdown";
var model = new GenerativeModel(apiKey: fixture.ApiKey, model: this.model);
// Images
var board = await TestExtensions.ReadImageFileBase64Async("https://ai.google.dev/static/docs/images/timetable.png");
var request = new GenerateContentRequest(prompt);
request.Contents[0].Parts.Add(
new InlineData { MimeType = "image/png", Data = board }
);

// Act
var response = await model.GenerateContent(request);

// Assert
response.Should().NotBeNull();
response.Candidates.Should().NotBeNull().And.HaveCount(1);
response.Candidates.FirstOrDefault().Content.Should().NotBeNull();
response.Candidates.FirstOrDefault().Content.Parts.Should().NotBeNull().And.HaveCountGreaterThanOrEqualTo(1);
output.WriteLine(response?.Text);
}

[Theory]
[InlineData("scones.jpg", "image/jpeg", "What is this picture?", "blueberries")]
[InlineData("cat.jpg", "image/jpeg", "Describe this image", "snow")]
[InlineData("cat.jpg", "image/jpeg", "Is it a cat?", "Yes")]
//[InlineData("animals.mp4", "video/mp4", "What's in the video?", "Zootopia")]
public async void Generate_Text_From_ImageFile(string filename, string mimetype, string prompt, string expected)
{
// Arrange
var model = new GenerativeModel(apiKey: fixture.ApiKey, model: this.model);
var base64image = Convert.ToBase64String(File.ReadAllBytes(Path.Combine(Environment.CurrentDirectory, "payload", filename)));
var parts = new List<IPart>
{
new TextData { Text = prompt },
new InlineData { MimeType = mimetype, Data = base64image }
};
var generationConfig = new GenerationConfig()
{
Temperature = 0.4f, TopP = 1, TopK = 32, MaxOutputTokens = 1024
};

// Act
var response = await model.GenerateContent(parts, generationConfig);

// Assert
response.Should().NotBeNull();
response.Candidates.Should().NotBeNull().And.HaveCount(1);
response.Candidates.FirstOrDefault().Content.Should().NotBeNull();
response.Candidates.FirstOrDefault().Content.Parts.Should().NotBeNull().And.HaveCountGreaterThanOrEqualTo(1);
response.Text.Should().Contain(expected);
output.WriteLine(response?.Text);
}

[Theory]
[InlineData("scones.jpg", "What is this picture?", "blueberries")]
[InlineData("cat.jpg", "Describe this image", "snow")]
[InlineData("cat.jpg", "Is it a feline?", "Yes")]
//[InlineData("animals.mp4", "video/mp4", "What's in the video?", "Zootopia")]
public async void Describe_AddMedia_From_ImageFile(string filename, string prompt, string expected)
{
// Arrange
var model = new GenerativeModel(apiKey: fixture.ApiKey, model: this.model);
var request = new GenerateContentRequest(prompt)
{
GenerationConfig = new GenerationConfig()
{
Temperature = 0.4f, TopP = 1, TopK = 32, MaxOutputTokens = 1024
}
};
request.AddMedia(Path.Combine(Environment.CurrentDirectory, "payload", filename));

// Act
var response = await model.GenerateContent(request);

// Assert
response.Should().NotBeNull();
response.Candidates.Should().NotBeNull().And.HaveCount(1);
response.Candidates.FirstOrDefault().Content.Should().NotBeNull();
response.Candidates.FirstOrDefault().Content.Parts.Should().NotBeNull().And.HaveCountGreaterThanOrEqualTo(1);
response.Text.Should().Contain(expected);
output.WriteLine(response?.Text);
}

[Fact]
public async void Describe_AddMedia_From_Url()
{
// Arrange
var prompt = "Parse the time and city from the airport board shown in this image into a list, in Markdown";
var model = new GenerativeModel(apiKey: fixture.ApiKey, model: this.model);
var request = new GenerateContentRequest(prompt);
await request.AddMedia("https://ai.google.dev/static/docs/images/timetable.png");

// Act
var response = await model.GenerateContent(request);

// Assert
response.Should().NotBeNull();
response.Candidates.Should().NotBeNull().And.HaveCount(1);
response.Candidates.FirstOrDefault().Content.Should().NotBeNull();
response.Candidates.FirstOrDefault().Content.Parts.Should().NotBeNull().And.HaveCountGreaterThanOrEqualTo(1);
output.WriteLine(response?.Text);
}

[Fact]
public async void Describe_AddMedia_From_UrlRemote()
{
// Arrange
var prompt = "Parse the time and city from the airport board shown in this image into a list, in Markdown";
var model = new GenerativeModel(apiKey: fixture.ApiKey, model: this.model);
var request = new GenerateContentRequest(prompt);
await request.AddMedia("https://ai.google.dev/static/docs/images/timetable.png", true);

// Act
var response = await model.GenerateContent(request);

// Assert
response.Should().NotBeNull();
response.Candidates.Should().NotBeNull().And.HaveCount(1);
response.Candidates.FirstOrDefault().Content.Should().NotBeNull();
response.Candidates.FirstOrDefault().Content.Parts.Should().NotBeNull().And.HaveCountGreaterThanOrEqualTo(1);
output.WriteLine(response?.Text);
}

[Fact(Skip = "Bad Request due to FileData part")]
public async void Describe_Image_From_FileData()
{
// Arrange
var prompt = "Parse the time and city from the airport board shown in this image into a list, in Markdown";
var model = new GenerativeModel(apiKey: fixture.ApiKey, model: this.model);
var request = new GenerateContentRequest(prompt);
request.Contents[0].Parts.Add(new FileData
{
FileUri = "https://ai.google.dev/static/docs/images/timetable.png",
MimeType = "image/png"
});

// Act
var response = await model.GenerateContent(request);

// Assert
response.Should().NotBeNull();
response.Candidates.Should().NotBeNull().And.HaveCount(1);
response.Candidates.FirstOrDefault().Content.Should().NotBeNull();
response.Candidates.FirstOrDefault().Content.Parts.Should().NotBeNull().And.HaveCountGreaterThanOrEqualTo(1);
output.WriteLine(response?.Text);
}

[Fact(Skip = "URL scheme not supported")]
public async void Multimodal_Video_Input()
{
// Arrange
var model = new GenerativeModel(apiKey: fixture.ApiKey, model: this.model);
var video = await TestExtensions.ReadImageFileBase64Async("gs://cloud-samples-data/video/animals.mp4");
var request = new GenerateContentRequest("What's in the video?");
request.Contents[0].Role = Role.User;
request.Contents[0].Parts.Add(new InlineData { MimeType = "video/mp4", Data = video });

// Act
var response = await model.GenerateContent(request);

// Assert
response.Should().NotBeNull();
response.Candidates.Should().NotBeNull().And.HaveCount(1);
response.Candidates.FirstOrDefault().Content.Should().NotBeNull();
response.Candidates.FirstOrDefault().Content.Parts.Should().NotBeNull().And.HaveCountGreaterThanOrEqualTo(1);
response.Text.Should().Contain("Zootopia");
output.WriteLine(response?.Text);
}
}
}
Loading

0 comments on commit 13e7692

Please sign in to comment.