Sample code for 30+ languages & platforms
Delphi DLL

Conversation with Streaming Responses

See more AI Examples

Demonstrates an AI conversation with receiving streaming responses.

Chilkat Delphi DLL Downloads

Delphi DLL
uses
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
    Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Ai, StringBuilder;

...

procedure TForm1.Button1Click(Sender: TObject);
var
success: Boolean;
ai: HCkAi;
systemMsg: PWideChar;
developerMsg: PWideChar;
conversationName: PWideChar;
sbEventName: HCkStringBuilder;
sbDelta: HCkStringBuilder;
sbFullResponse: HCkStringBuilder;
finished: Boolean;
abortFlag: Boolean;
maxWaitMs: Integer;
result: Integer;
result: Integer;

begin
success := False;

// This example assumes the Chilkat API to have been previously unlocked.
// See Global Unlock Sample for sample code.

ai := CkAi_Create();

// The provider can be "openai", "google", "claude", "deepseek", "xai", or "perplexity".
// Support for additional providers will be added in future versions of Chilkat.
CkAi_putProvider(ai,'google');

// Use your provider's API key.
CkAi_putApiKey(ai,'MY_API_KEY');

// Choose a model.
CkAi_putModel(ai,'gemini-2.5-flash');

// Indicate streaming mode is to be used.
CkAi_putStreaming(ai,True);

// Create a new conversation to be maintained locally in memory.
// If the conversation is the first to be created, it is also automatically selected.
systemMsg := 'You are a creative storyteller';
developerMsg := '';
conversationName := 'test_conversation';
CkAi_NewConvo(ai,conversationName,systemMsg,developerMsg);

// Add a text input.
CkAi_InputAddText(ai,'Write a detailed story about a turtle who decides to run a bakery.  Describe the setting, the kinds of pastries, how the turtle feels, and include at least three paragraphs.');

// Ask the AI for text output.
success := CkAi_Ask(ai,'text');
if (success = False) then
  begin
    Memo1.Lines.Add(CkAi__lastErrorText(ai));
    Exit;
  end;

sbEventName := CkStringBuilder_Create();
sbDelta := CkStringBuilder_Create();
sbFullResponse := CkStringBuilder_Create();
finished := False;
abortFlag := False;
maxWaitMs := 5000;

while not finished do
  begin

    result := CkAi_PollAi(ai,abortFlag);
    if (result = 1) then
      begin
        // We have output waiting.  It should be instantly available.  The maxWaitMs is just-in-case.
        success := CkAi_NextAiEvent(ai,maxWaitMs,sbEventName,sbDelta);
        if (success = False) then
          begin
            Memo1.Lines.Add(CkAi__lastErrorText(ai));
            Exit;
          end;

        // Some AI providers send many "empty" events.  Just ignore them.
        if (not CkStringBuilder_ContentsEqual(sbEventName,'empty',True)) then
          begin

            // The delta contains the new output.  This could be emitted to a display or the terminal
            // as real-time output.
            if (CkStringBuilder_ContentsEqual(sbEventName,'delta',True)) then
              begin
                // This example will emit each delta to its own line.
                Memo1.Lines.Add(CkStringBuilder__getAsString(sbDelta));

                // Accumulate the delta's so we can show the full response later.
                CkStringBuilder_AppendSb(sbFullResponse,sbDelta);
              end
            else
              begin
                // A streaming AI response is always terminated by a single "null_terminator" event.
                finished := CkStringBuilder_ContentsEqual(sbEventName,'null_terminator',True);
              end;
          end;
      end
    else
      begin
        if (result = 0) then
          begin
            // Nothing is immediately available. Sleep for 1/10 of a second before polling again.
            CkAi_SleepMs(ai,100);
          end
        else
          begin
            // Something failed..
            Memo1.Lines.Add(CkAi__lastErrorText(ai));
            finished := True;
          end;
      end;
  end;

// -------------------------------------------------------------
// The response is in markdown format.
// Also see Markdown to HTML Conversion Examples.
// -------------------------------------------------------------

// Show the accumulated (full) response.
Memo1.Lines.Add('----');
Memo1.Lines.Add(CkStringBuilder__getAsString(sbFullResponse));
Memo1.Lines.Add('----');

// ----------------------------------------------------------------------------------------------------------
// For the 2nd request in this conversation, ask for a shorter version of the story.
CkAi_InputAddText(ai,'Rewrite the story, but this time make it shorter, about one third as long.');
success := CkAi_Ask(ai,'text');
if (success = False) then
  begin
    Memo1.Lines.Add(CkAi__lastErrorText(ai));
    Exit;
  end;

CkStringBuilder_Clear(sbFullResponse);
finished := False;

while not finished do
  begin

    result := CkAi_PollAi(ai,abortFlag);
    if (result = 1) then
      begin
        // We have output waiting.  It should be instantly available.  The maxWaitMs is just-in-case.
        success := CkAi_NextAiEvent(ai,maxWaitMs,sbEventName,sbDelta);
        if (success = False) then
          begin
            Memo1.Lines.Add(CkAi__lastErrorText(ai));
            Exit;
          end;

        // Some AI providers send many "empty" events.  Just ignore them.
        if (not CkStringBuilder_ContentsEqual(sbEventName,'empty',True)) then
          begin

            // The delta contains the new output.  This could be emitted to a display or the terminal
            // as real-time output.
            if (CkStringBuilder_ContentsEqual(sbEventName,'delta',True)) then
              begin
                // This example will emit each delta to its own line.
                Memo1.Lines.Add(CkStringBuilder__getAsString(sbDelta));

                // Accumulate the delta's so we can show the full response later.
                CkStringBuilder_AppendSb(sbFullResponse,sbDelta);
              end
            else
              begin
                // A streaming AI response is always terminated by a single "null_terminator" event.
                finished := CkStringBuilder_ContentsEqual(sbEventName,'null_terminator',True);
              end;
          end;
      end
    else
      begin
        if (result = 0) then
          begin
            // Nothing is immediately available. Sleep for 1/10 of a second before polling again.
            CkAi_SleepMs(ai,100);
          end
        else
          begin
            // Something failed..
            Memo1.Lines.Add(CkAi__lastErrorText(ai));
            finished := True;
          end;
      end;
  end;

Memo1.Lines.Add('----');
Memo1.Lines.Add(CkStringBuilder__getAsString(sbFullResponse));

CkAi_Dispose(ai);
CkStringBuilder_Dispose(sbEventName);
CkStringBuilder_Dispose(sbDelta);
CkStringBuilder_Dispose(sbFullResponse);

end;