トップへ(mam-mam.net/)

DelphiでGemini APIを使用してAIに画像を解析してもらう(TNetHTTPClient)

DelphiでGemini APIを使用してAIに画像を解析してもらう(TNetHTTPClient)

DelphiでGemini API 無料版を使用してAIに画像を送って解析してもらう方法をサンプルソースコードで解説します。
Gemini API 無料版を使用して会話する場合はこちら(TNetHTTPClient使用)又はこちら(TRESTClient使用)

Gemini APIキーの取得

Googleのアカウントを取得しログインします。 次に Google AI Studio にアクセスします。
https://aistudio.google.com/
左下の「Get API key」をクリックし、右上の「API キーを作成」をクリックするとAPIキーを作成することができます。

取得したGemini APIキーは Gemini Free Tier(無料版)ですので1日の回数や1分間の回数制限などがあります。
また無料版は会話の内容を学習に使われる可能性がありますので注意が必要です。
お支払方法を設定すると有料版に切り替わるようです。

Gemini APIに送るJSON

Gemini APIに送るJSONは以下のような形式になります。

{
  "contents":[
    {
      "parts":[
        {"text":"この画像には何が写っていますか?"},
        {"inlineData":
          {"mimeType":"image\/jpeg","data":"Base64エンコードした画像ファイル"}
        }
      ]
    }
  ]
}

フォームデザイン

IDEから[ファイル]⇒[新規作成]⇒[VLC フォーム アプリケーション - Delphi]を選択して新規プロジェクトを作成します。
TImage × 1個、TMemo × 2個、TButton × 2個、TOpenDialog × 1個、TNetHTTPClient × 1個をドラッグ&ドロップします。

ソースコード

以下ソースコードを貼り付けた後、デザインビューの左ペインのオブジェクトインスペクタのイベントから
Form1.OnCreate に FormCreate、Button1.OnClick に Button1Click 、Button2.OnClick に Button2Click を設定します。

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls,
  Vcl.Imaging.Jpeg, Vcl.Imaging.PngImage, System.Net.URLClient,
  System.Net.HttpClient, System.Net.HttpClientComponent;

type
  TForm1 = class(TForm)
    OpenDialog1: TOpenDialog;
    Image1: TImage;
    Memo1: TMemo;
    Button1: TButton;
    Button2: TButton;
    Memo2: TMemo;
    NetHTTPClient1: TNetHTTPClient;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
    img:String;
    mime:String;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

const
  //API Key を設定する
  ApiKey:String='ここに上記で取得したAPIキーを貼り付けます';


implementation

{$R *.dfm}

uses System.NetEncoding, //TNetEncoding.Base64用
     Rest.Types, System.JSON, System.JSON.Readers,
     System.JSON.Builders,System.JSON.Serializers;

procedure TForm1.Button1Click(Sender: TObject);
var strm:TMemoryStream;
    bt:TBytes;
begin
  if not OpenDialog1.Execute then exit;
  Image1.Picture.LoadFromFile(OpenDialog1.FileName);
  if UpperCase(ExtractFileExt(OpenDialog1.FileName))='JPG' then
    mime:='image/jpeg'
  else
    mime:='image/png';

  strm:=TMemoryStream.Create;
  try
    strm.LoadFromFile(OpenDialog1.FileName);
    strm.Position:=0;
    SetLength(bt,strm.Size);
    strm.Read(bt[0],strm.Size);
  finally
    strm.Free
  end;
  img:=TNetEncoding.Base64.EncodeBytesToString(bt);
  img:=StringReplace(img,#13#10,'',[rfReplaceAll]);
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  Body,Parts,inlineData,js:TJsonObject;
  ContArr,JA1:TJsonArray;

  ASource:TStringStream;
  res:IHTTPResponse;
  JsonStr: String;

  sr:TStringReader;
  JsonTr:TJsonTextReader;
  JsonIt:TJSONIterator;
  st:String;
begin
  if Trim(Memo1.Text)='' then Exit;
  if img='' then Exit;
  

  Body := TJSONObject.Create; // body.ToJSON = '{}'の雛型
  try
    ContArr := TJSONArray.Create; // { "contents":[] 用 }
      Parts:=TJsonObject.Create;
        JA1:=TJSONArray.Create;
        JA1.Add(TJsonObject.Create.AddPair('text',Memo1.Text));
          inlineData:=TJsonObject.Create;
          js:=TJsonObject.Create;
          js.AddPair('mimeType',mime);
          js.AddPair('data',img);
          inlineData.AddPair('inlineData',js);
        Ja1.Add(inlineData);
      Parts.AddPair('parts',JA1);

      ContArr.Add(Parts);
    Body.AddPair('contents',ContArr);
    Body.AddPair('systemInstruction',
      TJSONObject.Create.AddPair('parts',
        TJSONArray.Create(
          TJSONObject.Create.AddPair(
            'text',
            'マークアップを使わずプレーンテキストで返答してください。')
        )
      )
    );
    JsonStr:=Trim(Body.ToJSON());
  finally
    Body.Free; //親オブジェクトが子オブジェクトを破棄するので親だけ破棄
  end;

  ASource := TStringStream.Create(JsonStr, TEncoding.UTF8);
  try
    NetHTTPClient1.ContentType:='application/json';
    res:=NetHTTPClient1.Post(
      'https://generativelanguage.googleapis.com/v1beta/models/'+
      'gemini-3.1-flash-lite:generateContent?key='+ApiKey,
      ASource, nil, nil
    );
  finally
    ASource.Free;
  end;

  sr:=TStringReader.Create(res.ContentAsString(TEncoding.UTF8));
  JsonTr:=TJsonTextReader.Create(sr);
  JsonIt:=TJsonIterator.Create(JsonTr);
  try
  JsonIt.Next('candidates');
    JsonIt.Recurse;//配列の中に入る
    JsonIt.Next;
      JsonIt.Recurse;//連想配列の中に入る
      JsonIt.Next('content');
        JsonIt.Recurse;//連想配列の中に入る
        JsonIt.Next('parts');
          JsonIt.Recurse;//配列の中に入る
          while JsonIt.Next do
          begin
            JsonIt.Recurse;//連想配列の中に入る
            JsonIt.Next('text');
              st:=AdjustLineBreaks(JsonIt.AsString);
            JsonIt.Return;
          end;
          JsonIt.Return;
        JsonIt.Return;
      JsonIt.Return;
    JsonIt.Return;
  finally
    JsonIt.Free;
    JsonTr.Free;
    sr.Free;
  end;
  Memo2.Lines.Add(st);
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  OpenDialog1.Filter:='画像|*.jpg;*.png';
  Image1.Proportional:=True;
  Image1.Stretch:=True;
  Memo1.Clear;
  Memo2.Clear;
  Button1.Caption:='画像読み込み';
  Button2.Caption:='画像について質問';
end;

end.

実行

IDEから[実行]⇒[実行]を選択するとコンパイルされて実行されます。
Button1を押して解析対象画像を選択します。次にMemo1にAIへ解析内容や質問を入力しButton2をクリックするとMemo2にGemini AIから応答があります。