chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
namespace HuggingFaceImageTextDemo;
|
||||
|
||||
partial class FormMain
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components is not null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.flowLayoutPanel1 = new FlowLayoutPanel();
|
||||
this.textBox1 = new TextBox();
|
||||
this.lblImageDescription = new Label();
|
||||
this.folderBrowserDialog1 = new FolderBrowserDialog();
|
||||
this.lblImagesFolder = new Label();
|
||||
this.btRefresh = new Button();
|
||||
this.button1 = new Button();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// flowLayoutPanel1
|
||||
//
|
||||
this.flowLayoutPanel1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
|
||||
this.flowLayoutPanel1.Location = new Point(12, 52);
|
||||
this.flowLayoutPanel1.Name = "flowLayoutPanel1";
|
||||
this.flowLayoutPanel1.Size = new Size(743, 514);
|
||||
this.flowLayoutPanel1.TabIndex = 0;
|
||||
//
|
||||
// textBox1
|
||||
//
|
||||
this.textBox1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Right;
|
||||
this.textBox1.Font = new Font("Segoe UI", 14.25F, FontStyle.Regular, GraphicsUnit.Point, 0);
|
||||
this.textBox1.ForeColor = Color.DarkGreen;
|
||||
this.textBox1.Location = new Point(761, 145);
|
||||
this.textBox1.Multiline = true;
|
||||
this.textBox1.Name = "textBox1";
|
||||
this.textBox1.Size = new Size(306, 421);
|
||||
this.textBox1.TabIndex = 4;
|
||||
this.textBox1.Text = "Click in any of the images to generate an AI description";
|
||||
//
|
||||
// lblImageDescription
|
||||
//
|
||||
this.lblImageDescription.Anchor = AnchorStyles.Top | AnchorStyles.Right;
|
||||
this.lblImageDescription.AutoSize = true;
|
||||
this.lblImageDescription.Font = new Font("Segoe UI", 15.75F, FontStyle.Regular, GraphicsUnit.Point, 0);
|
||||
this.lblImageDescription.Location = new Point(756, 112);
|
||||
this.lblImageDescription.Name = "lblImageDescription";
|
||||
this.lblImageDescription.Size = new Size(220, 30);
|
||||
this.lblImageDescription.TabIndex = 5;
|
||||
this.lblImageDescription.Text = "Generated Description";
|
||||
this.lblImageDescription.TextAlign = ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// folderBrowserDialog1
|
||||
//
|
||||
this.folderBrowserDialog1.Description = "Select a folder with images";
|
||||
this.folderBrowserDialog1.ShowNewFolderButton = false;
|
||||
this.folderBrowserDialog1.UseDescriptionForTitle = true;
|
||||
//
|
||||
// lblImagesFolder
|
||||
//
|
||||
this.lblImagesFolder.AutoSize = true;
|
||||
this.lblImagesFolder.Font = new Font("Segoe UI", 15.75F, FontStyle.Regular, GraphicsUnit.Point, 0);
|
||||
this.lblImagesFolder.Location = new Point(12, 14);
|
||||
this.lblImagesFolder.Name = "lblImagesFolder";
|
||||
this.lblImagesFolder.Size = new Size(250, 30);
|
||||
this.lblImagesFolder.TabIndex = 1;
|
||||
this.lblImagesFolder.Text = "Images folder: -- Select --";
|
||||
this.lblImagesFolder.TextAlign = ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// btRefresh
|
||||
//
|
||||
this.btRefresh.Anchor = AnchorStyles.Top | AnchorStyles.Right;
|
||||
this.btRefresh.Font = new Font("Segoe UI", 11.25F, FontStyle.Regular, GraphicsUnit.Point, 0);
|
||||
this.btRefresh.Location = new Point(934, 12);
|
||||
this.btRefresh.Name = "btRefresh";
|
||||
this.btRefresh.Size = new Size(133, 27);
|
||||
this.btRefresh.TabIndex = 3;
|
||||
this.btRefresh.Text = "Refresh Images";
|
||||
this.btRefresh.UseVisualStyleBackColor = true;
|
||||
this.btRefresh.Click += this.btRefresh_Click;
|
||||
//
|
||||
// button1
|
||||
//
|
||||
this.button1.Anchor = AnchorStyles.Top | AnchorStyles.Right;
|
||||
this.button1.Font = new Font("Segoe UI", 11.25F, FontStyle.Regular, GraphicsUnit.Point, 0);
|
||||
this.button1.Location = new Point(795, 12);
|
||||
this.button1.Name = "button1";
|
||||
this.button1.Size = new Size(133, 27);
|
||||
this.button1.TabIndex = 2;
|
||||
this.button1.Text = "Change Folder";
|
||||
this.button1.UseVisualStyleBackColor = true;
|
||||
this.button1.Click += this.btChangeFolder_Click;
|
||||
//
|
||||
// FormMain
|
||||
//
|
||||
this.AutoScaleDimensions = new SizeF(7F, 15F);
|
||||
this.AutoScaleMode = AutoScaleMode.Font;
|
||||
this.ClientSize = new Size(1079, 578);
|
||||
this.Controls.Add(this.button1);
|
||||
this.Controls.Add(this.btRefresh);
|
||||
this.Controls.Add(this.lblImagesFolder);
|
||||
this.Controls.Add(this.lblImageDescription);
|
||||
this.Controls.Add(this.textBox1);
|
||||
this.Controls.Add(this.flowLayoutPanel1);
|
||||
this.Name = "FormMain";
|
||||
this.Text = "ImageToText Sample";
|
||||
this.Load += this.FormMain_Load;
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private FlowLayoutPanel flowLayoutPanel1;
|
||||
private TextBox textBox1;
|
||||
private Label lblImageDescription;
|
||||
private FolderBrowserDialog folderBrowserDialog1;
|
||||
private Label lblImagesFolder;
|
||||
private Button btRefresh;
|
||||
private Button button1;
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Drawing.Imaging;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.ImageToText;
|
||||
|
||||
namespace HuggingFaceImageTextDemo;
|
||||
|
||||
#pragma warning disable SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates.
|
||||
|
||||
/// <summary>
|
||||
/// Main form of the application.
|
||||
/// </summary>
|
||||
public partial class FormMain : Form
|
||||
{
|
||||
private readonly Kernel _kernel;
|
||||
private readonly IImageToTextService _imageToTextService;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FormMain"/> class.
|
||||
/// </summary>
|
||||
public FormMain()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this._kernel = Kernel.CreateBuilder()
|
||||
.AddHuggingFaceImageToText("Salesforce/blip-image-captioning-base")
|
||||
.Build();
|
||||
|
||||
this._imageToTextService = this._kernel.GetRequiredService<IImageToTextService>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Main form load event.
|
||||
/// </summary>
|
||||
/// <param name="sender">The form main.</param>
|
||||
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
|
||||
private void FormMain_Load(object sender, EventArgs e)
|
||||
{
|
||||
this.ChangeFolder();
|
||||
this.Focus();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the folder and refreshes the images.
|
||||
/// </summary>
|
||||
private void ChangeFolder()
|
||||
{
|
||||
if (this.folderBrowserDialog1.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
this.lblImagesFolder.Text = $"Images folder: {this.folderBrowserDialog1.SelectedPath}";
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(this.folderBrowserDialog1.SelectedPath))
|
||||
{
|
||||
MessageBox.Show("A folder needs to be selected.");
|
||||
|
||||
this.ChangeFolder();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.RefreshImages();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes the images in the flow layout panel.
|
||||
/// </summary>
|
||||
private void RefreshImages()
|
||||
{
|
||||
var imageDirectory = this.folderBrowserDialog1.SelectedPath;
|
||||
|
||||
var extensions = new List<string> { "*.jpg", "*.jpeg", "*.png", "*.gif", "*.bmp", "*.tiff", "*.ico", "*.svg" };
|
||||
var myImagePaths = new List<string>();
|
||||
foreach (var extension in extensions)
|
||||
{
|
||||
myImagePaths.AddRange(Directory.GetFiles(imageDirectory, extension, SearchOption.AllDirectories));
|
||||
}
|
||||
|
||||
this.flowLayoutPanel1.Controls.Clear();
|
||||
foreach (var imagePath in myImagePaths)
|
||||
{
|
||||
PictureBox pictureBox = new();
|
||||
using var fs = new FileStream(imagePath, FileMode.Open, FileAccess.Read);
|
||||
pictureBox.Image = new Bitmap(Image.FromStream(fs));
|
||||
pictureBox.SizeMode = PictureBoxSizeMode.Zoom;
|
||||
pictureBox.Height = 300;
|
||||
pictureBox.Width = 300;
|
||||
pictureBox.Click += this.PictureBoxOnClickAsync;
|
||||
pictureBox.Tag = imagePath;
|
||||
this.flowLayoutPanel1.Controls.Add(pictureBox);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the Click event of the PictureBox control.
|
||||
/// </summary>
|
||||
/// <param name="sender">The picture box.</param>
|
||||
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
|
||||
#pragma warning disable VSTHRD100 // Avoid async void methods
|
||||
private async void PictureBoxOnClickAsync(object? sender, EventArgs e)
|
||||
{
|
||||
this.textBox1.Text = "Processing...";
|
||||
var pictureBox = ((PictureBox)sender!);
|
||||
ImageContent imageContent = CreateImageContentFromPictureBox(pictureBox);
|
||||
string text;
|
||||
try
|
||||
{
|
||||
text = (await this._imageToTextService.GetTextContentAsync(imageContent).ConfigureAwait(false)).Text!;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
text = ex.Message;
|
||||
}
|
||||
|
||||
this.UpdateImageDescription(text);
|
||||
}
|
||||
#pragma warning restore VSTHRD100 // Avoid async void methods
|
||||
|
||||
/// <summary>
|
||||
/// Updates the description in the text box.
|
||||
/// </summary>
|
||||
/// <param name="description">The description.</param>
|
||||
private void UpdateImageDescription(string description)
|
||||
{
|
||||
// Ensure the following UI update is executed on the UI thread
|
||||
if (this.textBox1.InvokeRequired)
|
||||
{
|
||||
this.textBox1.Invoke(() =>
|
||||
{
|
||||
this.textBox1.Text = description;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
this.textBox1.Text = description;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="ImageContent"/> from a <see cref="PictureBox"/>.
|
||||
/// </summary>
|
||||
/// <param name="pictureBox">The target <see cref="PictureBox"/>.</param>
|
||||
/// <returns>Returns a <see cref="ImageContent"/>.</returns>
|
||||
private static ImageContent CreateImageContentFromPictureBox(PictureBox pictureBox)
|
||||
=> new(ConvertImageToReadOnlyMemory(pictureBox), GetMimeType(pictureBox.Tag?.ToString()!));
|
||||
|
||||
/// <summary>
|
||||
/// Gets the image binary array from a <see cref="PictureBox"/>.
|
||||
/// </summary>
|
||||
/// <param name="pictureBox">The target <see cref="PictureBox"/>.</param>
|
||||
/// <returns>Returns image binary array.</returns>
|
||||
private static ReadOnlyMemory<byte> ConvertImageToReadOnlyMemory(PictureBox pictureBox)
|
||||
{
|
||||
var image = pictureBox.Image;
|
||||
var fileName = pictureBox.Tag!.ToString()!;
|
||||
|
||||
using var memoryStream = new MemoryStream();
|
||||
|
||||
// Save the image to the MemoryStream, using PNG format for example
|
||||
image.Save(memoryStream, GetImageFormat(fileName));
|
||||
|
||||
// Optionally, reset the position of the MemoryStream to the beginning
|
||||
memoryStream.Position = 0;
|
||||
|
||||
// Convert the MemoryStream's buffer to ReadOnlyMemory<byte>
|
||||
// Note: ToArray creates a copy of the buffer; if you're concerned about performance or memory usage,
|
||||
// you might look into more efficient methods depending on your use case.
|
||||
return new ReadOnlyMemory<byte>(memoryStream.ToArray());
|
||||
}
|
||||
|
||||
private void btRefresh_Click(object sender, EventArgs e)
|
||||
{
|
||||
this.RefreshImages();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the MIME type of the specific image file extension
|
||||
/// </summary>
|
||||
/// <param name="fileName">The file name with extension</param>
|
||||
/// <returns>The MIME type of the specific image file extension</returns>
|
||||
private static string GetMimeType(string fileName)
|
||||
{
|
||||
return Path.GetExtension(fileName) switch
|
||||
{
|
||||
".jpg" or ".jpeg" => "image/jpeg",
|
||||
".png" => "image/png",
|
||||
".gif" => "image/gif",
|
||||
".bmp" => "image/bmp",
|
||||
".tiff" => "image/tiff",
|
||||
".ico" => "image/x-icon",
|
||||
".svg" => "image/svg+xml",
|
||||
_ => throw new NotSupportedException("Unsupported image format.")
|
||||
};
|
||||
}
|
||||
|
||||
private static ImageFormat GetImageFormat(string fileName)
|
||||
{
|
||||
return Path.GetExtension(fileName) switch
|
||||
{
|
||||
".jpg" or ".jpeg" => ImageFormat.Jpeg,
|
||||
".png" => ImageFormat.Png,
|
||||
".gif" => ImageFormat.Gif,
|
||||
".bmp" => ImageFormat.Bmp,
|
||||
".tiff" => ImageFormat.Tiff,
|
||||
".ico" => ImageFormat.Icon,
|
||||
".svg" => ImageFormat.MemoryBmp,
|
||||
_ => throw new NotSupportedException("Unsupported image format.")
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the Change Folder button click event.
|
||||
/// </summary>
|
||||
/// <param name="sender">The clicked button.</param>
|
||||
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
|
||||
private void btChangeFolder_Click(object sender, EventArgs e)
|
||||
{
|
||||
this.ChangeFolder();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="folderBrowserDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
</root>
|
||||
@@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<EnableWindowsTargeting>true</EnableWindowsTargeting>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Connectors\Connectors.HuggingFace\Connectors.HuggingFace.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\SemanticKernel.Abstractions\SemanticKernel.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\SemanticKernel.Core\SemanticKernel.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
namespace HuggingFaceImageTextDemo;
|
||||
|
||||
internal static class Program
|
||||
{
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
public static void Main()
|
||||
{
|
||||
// To customize application configuration such as set high DPI settings or default font,
|
||||
// see https://aka.ms/applicationconfiguration.
|
||||
ApplicationConfiguration.Initialize();
|
||||
Application.Run(new FormMain());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
## HuggingFace ImageToText Service Example
|
||||
|
||||
This demonstration is simple WindowsForm Sample application that go thru an **images folder provided at the initialization**, searching for all image files. These images are then displayed in the initial window as soon as the application launches.
|
||||
|
||||
The application provides an interactive feature where you can click on each image. Upon clicking, the application employs the Semantic Kernel's HuggingFace ImageToText Service to fetch a descriptive analysis of the clicked image.
|
||||
|
||||
A critical aspect of the implementation is how the application captures the binary content of the image and sends a request to the Service, awaiting the descriptive text. This process is a key highlight, showcasing the seamless integration and powerful capabilities of our latest software enhancement.
|
||||
|
||||
Required packages to use ImageToText HuggingFace Service:
|
||||
|
||||
- Microsoft.SemanticKernel
|
||||
- Microsoft.SemanticKernel.Connectors.HuggingFace
|
||||
|
||||
The following code snippet below shows the most important pieces of code on how to use the ImageToText Service (Hugging Face implementation) to retrieve the descriptive text of an image:
|
||||
|
||||
```csharp
|
||||
// Initializes the Kernel
|
||||
var kernel = Kernel.CreateBuilder()
|
||||
.AddHuggingFaceImageToText("Salesforce/blip-image-captioning-base")
|
||||
.Build();
|
||||
|
||||
// Gets the ImageToText Service
|
||||
var service = this._kernel.GetRequiredService<IImageToTextService>();
|
||||
```
|
||||
|
||||
Once one of the images is selected, the binary data of the image is retrieved and sent to the ImageToText Service. The service then returns the descriptive text of the image. The following code snippet demonstrates how to use the ImageToText Service to retrieve the descriptive text of an image:
|
||||
|
||||
```csharp
|
||||
// Get the binary content of a JPEG image:
|
||||
var imageBinary = File.ReadAllBytes("path/to/file.jpg");
|
||||
|
||||
// Prepare the image to be sent to the LLM
|
||||
var imageContent = new ImageContent(imageBinary) { MimeType = "image/jpeg" };
|
||||
|
||||
// Retrieves the image description
|
||||
var textContent = await service.GetTextContentAsync(imageContent);
|
||||
```
|
||||
Reference in New Issue
Block a user