Sample code for 30+ languages & platforms
PureBasic

Conversation with Streaming Responses

See more AI Examples

Demonstrates an AI conversation with receiving streaming responses.

Chilkat PureBasic Downloads

PureBasic
IncludeFile "CkAi.pb"
IncludeFile "CkStringBuilder.pb"

Procedure ChilkatExample()

    success.i = 0

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

    ai.i = CkAi::ckCreate()
    If ai.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

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

    ; Use your provider's API key.
    CkAi::setCkApiKey(ai, "MY_API_KEY")

    ; Choose a model.
    CkAi::setCkModel(ai, "gemini-2.5-flash")

    ; Indicate streaming mode is to be used.
    CkAi::setCkStreaming(ai, 1)

    ; 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.s = "You are a creative storyteller"
    developerMsg.s = ""
    conversationName.s = "test_conversation"
    CkAi::ckNewConvo(ai,conversationName,systemMsg,developerMsg)

    ; Add a text input.
    CkAi::ckInputAddText(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::ckAsk(ai,"text")
    If success = 0
        Debug CkAi::ckLastErrorText(ai)
        CkAi::ckDispose(ai)
        ProcedureReturn
    EndIf

    sbEventName.i = CkStringBuilder::ckCreate()
    If sbEventName.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    sbDelta.i = CkStringBuilder::ckCreate()
    If sbDelta.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    sbFullResponse.i = CkStringBuilder::ckCreate()
    If sbFullResponse.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    finished.i = 0
    abortFlag.i = 0
    maxWaitMs.i = 5000

    While Not finished

        result.i = CkAi::ckPollAi(ai,abortFlag)
        If result = 1
            ; We have output waiting.  It should be instantly available.  The maxWaitMs is just-in-case.
            success = CkAi::ckNextAiEvent(ai,maxWaitMs,sbEventName,sbDelta)
            If success = 0
                Debug CkAi::ckLastErrorText(ai)
                CkAi::ckDispose(ai)
                CkStringBuilder::ckDispose(sbEventName)
                CkStringBuilder::ckDispose(sbDelta)
                CkStringBuilder::ckDispose(sbFullResponse)
                ProcedureReturn
            EndIf

            ; Some AI providers send many "empty" events.  Just ignore them.
            If Not CkStringBuilder::ckContentsEqual(sbEventName,"empty",1)

                ; The delta contains the new output.  This could be emitted to a display or the terminal
                ; as real-time output.
                If CkStringBuilder::ckContentsEqual(sbEventName,"delta",1)
                    ; This example will emit each delta to its own line.
                    Debug CkStringBuilder::ckGetAsString(sbDelta)

                    ; Accumulate the delta's so we can show the full response later.
                    CkStringBuilder::ckAppendSb(sbFullResponse,sbDelta)
                Else
                    ; A streaming AI response is always terminated by a single "null_terminator" event.
                    finished = CkStringBuilder::ckContentsEqual(sbEventName,"null_terminator",1)
                EndIf

            EndIf

        Else
            If result = 0
                ; Nothing is immediately available. Sleep for 1/10 of a second before polling again.
                CkAi::ckSleepMs(ai,100)
            Else
                ; Something failed..
                Debug CkAi::ckLastErrorText(ai)
                finished = 1
            EndIf

        EndIf

    Wend

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

    ; Show the accumulated (full) response.
    Debug "----"
    Debug CkStringBuilder::ckGetAsString(sbFullResponse)
    Debug "----"

    ; ----------------------------------------------------------------------------------------------------------
    ; For the 2nd request in this conversation, ask for a shorter version of the story.
    CkAi::ckInputAddText(ai,"Rewrite the story, but this time make it shorter, about one third as long.")
    success = CkAi::ckAsk(ai,"text")
    If success = 0
        Debug CkAi::ckLastErrorText(ai)
        CkAi::ckDispose(ai)
        CkStringBuilder::ckDispose(sbEventName)
        CkStringBuilder::ckDispose(sbDelta)
        CkStringBuilder::ckDispose(sbFullResponse)
        ProcedureReturn
    EndIf

    CkStringBuilder::ckClear(sbFullResponse)
    finished = 0

    While Not finished

        result.i = CkAi::ckPollAi(ai,abortFlag)
        If result = 1
            ; We have output waiting.  It should be instantly available.  The maxWaitMs is just-in-case.
            success = CkAi::ckNextAiEvent(ai,maxWaitMs,sbEventName,sbDelta)
            If success = 0
                Debug CkAi::ckLastErrorText(ai)
                CkAi::ckDispose(ai)
                CkStringBuilder::ckDispose(sbEventName)
                CkStringBuilder::ckDispose(sbDelta)
                CkStringBuilder::ckDispose(sbFullResponse)
                ProcedureReturn
            EndIf

            ; Some AI providers send many "empty" events.  Just ignore them.
            If Not CkStringBuilder::ckContentsEqual(sbEventName,"empty",1)

                ; The delta contains the new output.  This could be emitted to a display or the terminal
                ; as real-time output.
                If CkStringBuilder::ckContentsEqual(sbEventName,"delta",1)
                    ; This example will emit each delta to its own line.
                    Debug CkStringBuilder::ckGetAsString(sbDelta)

                    ; Accumulate the delta's so we can show the full response later.
                    CkStringBuilder::ckAppendSb(sbFullResponse,sbDelta)
                Else
                    ; A streaming AI response is always terminated by a single "null_terminator" event.
                    finished = CkStringBuilder::ckContentsEqual(sbEventName,"null_terminator",1)
                EndIf

            EndIf

        Else
            If result = 0
                ; Nothing is immediately available. Sleep for 1/10 of a second before polling again.
                CkAi::ckSleepMs(ai,100)
            Else
                ; Something failed..
                Debug CkAi::ckLastErrorText(ai)
                finished = 1
            EndIf

        EndIf

    Wend

    Debug "----"
    Debug CkStringBuilder::ckGetAsString(sbFullResponse)


    CkAi::ckDispose(ai)
    CkStringBuilder::ckDispose(sbEventName)
    CkStringBuilder::ckDispose(sbDelta)
    CkStringBuilder::ckDispose(sbFullResponse)


    ProcedureReturn
EndProcedure