FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin for Harbour/xHarbour OpenAI vision API from FWH
Posts: 44162
Joined: Thu Oct 06, 2005 05:47 PM
OpenAI vision API from FWH
Posted: Fri Jan 03, 2025 09:51 PM
Working fine! :-)

Using https://platform.openai.com/docs/guides/vision examples.

openai1.prg
Code (fw): Select all Collapse
#include "FiveWin.ch"
#include "c:\harbour\contrib\hbcurl\hbcurl.ch"

//----------------------------------------------------------------------------//

function Main()

    local oChatgpt := TOpenAI():New()

    oChatgpt:SendImageURL( "https://forums.fivetechsupport.com/styles/prosilver/imageset/site_logo.gif" )

    MsgInfo( oChatgpt:GetValue() )

    oChatgpt:End()

return nil    

//----------------------------------------------------------------------------//

CLASS TOpenAI
    
    DATA   cKey   INIT ""
    DATA   cModel INIT "gpt-4o-mini"
    DATA   cResponse
    DATA   cUrl
    DATA   hCurl
    DATA   nError INIT 0
    DATA   nHttpCode INIT 0

    METHOD New( cKey, cModel )
    METHOD SendImageURL( cImageUrl )
    METHOD End()    
    METHOD GetValue( cHKey )    

ENDCLASS        

//----------------------------------------------------------------------------//

METHOD New( cKey, cModel ) CLASS TOpenAI

    if Empty( cKey )
       ::cKey = GetEnv( "OPENAI_API_KEY" )
    endif

    if ! Empty( cModel )
       ::cModel = cModel
    endif
    
    ::cUrl = "https://api.openai.com/v1/chat/completions"
    ::hCurl = curl_easy_init()
    
return Self    

//----------------------------------------------------------------------------//

METHOD End() CLASS TOpenAI

    curl_easy_cleanup( ::hCurl )
    ::hCurl = nil

return nil    

//----------------------------------------------------------------------------//

METHOD GetValue( cHKey ) CLASS TOpenAI

    local aKeys := hb_AParams(), cKey
    local uValue := hb_jsonDecode( ::cResponse )

    hb_default( @cHKey, "content" )

    if cHKey == "content"
       uValue = uValue[ "choices" ][ 1 ][ "message" ][ "content" ]
    endif

    TRY
       for each cKey in aKeys
          if ValType( uValue[ cKey ] ) == "A"
             uValue = uValue[ cKey ][ 1 ][ "choices" ][ 1 ][ "message" ][ "content" ]
          else
             uValue = uValue[ cKey ]
          endif
       next
    CATCH
       XBrowser( uValue )
    END

return uValue

//----------------------------------------------------------------------------//

METHOD SendImageURL( cImageUrl ) CLASS TOpenAI

    local aHeaders, cJson, hRequest := { => }, hMessage := { => }

    curl_easy_setopt( ::hCurl, HB_CURLOPT_POST, .T. )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_URL, ::cUrl )

    aHeaders := { "Content-Type: application/json", ;
                  "Authorization: Bearer " + ::cKey }

    curl_easy_setopt( ::hCurl, HB_CURLOPT_HTTPHEADER, aHeaders )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_USERNAME, "" )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_DL_BUFF_SETUP )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_SSL_VERIFYPEER, .F. )

    hb_HSet( hRequest, "model", ::cModel )
    hb_HSet( hMessage, "role", "user" )

    hb_HSet( hMessage, "content", { ;
        { "type" => "text", "text" => "What's in this image?" }, ;
        { "type" => "image_url", "image_url" => { "url" => cImageUrl } } } )

    hRequest[ "messages" ] = { hMessage }

    cJson = hb_jsonEncode( hRequest )

    curl_easy_setopt( ::hCurl, HB_CURLOPT_POSTFIELDS, cJson )

    ::nError = curl_easy_perform( ::hCurl )
    curl_easy_getinfo( ::hCurl, HB_CURLINFO_RESPONSE_CODE, @::nHttpCode )

    if ::nError == HB_CURLE_OK
       ::cResponse = curl_easy_dl_buff_get( ::hCurl )
    else
       ::cResponse := "Error code " + Str( ::nError )
    endif

return ::cResponse

//----------------------------------------------------------------------------//
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 44162
Joined: Thu Oct 06, 2005 05:47 PM
Re: OpenAI vision API from FWH
Posted: Fri Jan 03, 2025 10:21 PM
Class TOpenAI Method SendImage( cImageFileName ) // Please notice BMPs are not allowed

openai1.prg
Code (fw): Select all Collapse
#include "FiveWin.ch"
#include "c:\harbour\contrib\hbcurl\hbcurl.ch"

//----------------------------------------------------------------------------//

function Main()

    local oChatgpt := TOpenAI():New()

    // oChatgpt:SendImageURL( "https://forums.fivetechsupport.com/styles/prosilver/imageset/site_logo.gif" )
    oChatgpt:SendImage( "../bitmaps/logo/fivepowergm5.jpg" )

    MsgInfo( oChatgpt:GetValue() )

    oChatgpt:End()

return nil    

//----------------------------------------------------------------------------//

CLASS TOpenAI
    
    DATA   cKey   INIT ""
    DATA   cModel INIT "gpt-4o-mini"
    DATA   cResponse
    DATA   cUrl
    DATA   hCurl
    DATA   nError INIT 0
    DATA   nHttpCode INIT 0

    METHOD New( cKey, cModel )
    METHOD SendImage( cImageFileName )    
    METHOD SendImageURL( cImageUrl )
    METHOD End()    
    METHOD GetValue( cHKey )    

ENDCLASS        

//----------------------------------------------------------------------------//

METHOD New( cKey, cModel ) CLASS TOpenAI

    if Empty( cKey )
       ::cKey = GetEnv( "OPENAI_API_KEY" )
    endif

    if ! Empty( cModel )
       ::cModel = cModel
    endif
    
    ::cUrl = "https://api.openai.com/v1/chat/completions"
    ::hCurl = curl_easy_init()
    
return Self    

//----------------------------------------------------------------------------//

METHOD End() CLASS TOpenAI

    curl_easy_cleanup( ::hCurl )
    ::hCurl = nil

return nil    

//----------------------------------------------------------------------------//

METHOD GetValue( cHKey ) CLASS TOpenAI

    local aKeys := hb_AParams(), cKey
    local uValue := hb_jsonDecode( ::cResponse )

    hb_default( @cHKey, "content" )

    if cHKey == "content"
       uValue = uValue[ "choices" ][ 1 ][ "message" ][ "content" ]
    endif

    TRY
       for each cKey in aKeys
          if ValType( uValue[ cKey ] ) == "A"
             uValue = uValue[ cKey ][ 1 ][ "choices" ][ 1 ][ "message" ][ "content" ]
          else
             uValue = uValue[ cKey ]
          endif
       next
    CATCH
       XBrowser( uValue )
    END

return uValue

//----------------------------------------------------------------------------//

METHOD SendImage( cImageFileName ) CLASS TOpenAI

    local aHeaders, cJson, cBase64Image, hMessage := { => }

    if ! File( cImageFileName )
       MsgAlert( "Image " + cImageFileName + " not found" )
       return nil
    endif

    cBase64Image := hb_base64Encode( memoRead( cImageFileName ) )

    curl_easy_setopt( ::hCurl, HB_CURLOPT_POST, .T. )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_URL, "https://api.openai.com/v1/chat/completions" )

    aHeaders := { "Content-Type: application/json", ;
                  "Authorization: Bearer " + ::cKey }

    curl_easy_setopt( ::hCurl, HB_CURLOPT_HTTPHEADER, aHeaders )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_USERNAME, "" )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_DL_BUFF_SETUP )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_SSL_VERIFYPEER, .F. )

    hb_HSet( hMessage, "role", "user" )
    hb_HSet( hMessage, "content", { ;
        { "type" => "text", "text" => "What is in this image?" }, ;
        { "type" => "image_url", ;
          "image_url" => { "url" => "data:image/jpeg;base64," + cBase64Image } } } )

    cJson := hb_jsonEncode( { "model" => ::cModel, ;
                              "messages" => { hMessage } } )

    curl_easy_setopt( ::hCurl, HB_CURLOPT_POSTFIELDS, cJson )

    ::nError = curl_easy_perform( ::hCurl )
    curl_easy_getinfo( ::hCurl, HB_CURLINFO_RESPONSE_CODE, @::nHttpCode )

    if ::nError == HB_CURLE_OK
       ::cResponse = curl_easy_dl_buff_get( ::hCurl )
    else
       ::cResponse := "Error code " + Str( ::nError )
    endif

return ::cResponse

//----------------------------------------------------------------------------//

METHOD SendImageURL( cImageUrl ) CLASS TOpenAI

    local aHeaders, cJson, hRequest := { => }, hMessage := { => }

    curl_easy_setopt( ::hCurl, HB_CURLOPT_POST, .T. )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_URL, ::cUrl )

    aHeaders := { "Content-Type: application/json", ;
                  "Authorization: Bearer " + ::cKey }

    curl_easy_setopt( ::hCurl, HB_CURLOPT_HTTPHEADER, aHeaders )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_USERNAME, "" )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_DL_BUFF_SETUP )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_SSL_VERIFYPEER, .F. )

    hb_HSet( hRequest, "model", ::cModel )
    hb_HSet( hMessage, "role", "user" )

    hb_HSet( hMessage, "content", { ;
        { "type" => "text", "text" => "What's in this image?" }, ;
        { "type" => "image_url", "image_url" => { "url" => cImageUrl } } } )

    hRequest[ "messages" ] = { hMessage }

    cJson = hb_jsonEncode( hRequest )

    curl_easy_setopt( ::hCurl, HB_CURLOPT_POSTFIELDS, cJson )

    ::nError = curl_easy_perform( ::hCurl )
    curl_easy_getinfo( ::hCurl, HB_CURLINFO_RESPONSE_CODE, @::nHttpCode )

    if ::nError == HB_CURLE_OK
       ::cResponse = curl_easy_dl_buff_get( ::hCurl )
    else
       ::cResponse := "Error code " + Str( ::nError )
    endif

return ::cResponse

//----------------------------------------------------------------------------//
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 44162
Joined: Thu Oct 06, 2005 05:47 PM
Re: OpenAI vision API from FWH
Posted: Fri Jan 03, 2025 10:43 PM
METHOD Send( cPrompt ) CLASS TOpenAI implemented

Before running this example please set your OpenAI user key from your CMD window:
set OPENAI_API_KEY=sk-...

openai1.prg
Code (fw): Select all Collapse
#include "FiveWin.ch"
#include "c:\harbour\contrib\hbcurl\hbcurl.ch"

//----------------------------------------------------------------------------//

function Main()

    local oChatgpt := TOpenAI():New()

    // oChatgpt:SendImageURL( "https://forums.fivetechsupport.com/styles/prosilver/imageset/site_logo.gif" )
    // oChatgpt:SendImage( "../bitmaps/logo/fivepowergm5.jpg" )
    oChatgpt:Send( "What is the capital of France ?" )

    MsgInfo( oChatgpt:GetValue() )

    oChatgpt:End()

return nil    

//----------------------------------------------------------------------------//

CLASS TOpenAI
    
    DATA   cKey   INIT ""
    DATA   cModel INIT "gpt-4o-mini"
    DATA   cResponse
    DATA   cUrl
    DATA   hCurl
    DATA   nError INIT 0
    DATA   nHttpCode INIT 0

    METHOD New( cKey, cModel )
    METHOD Send( cPrompt )    
    METHOD SendImage( cImageFileName )    
    METHOD SendImageURL( cImageUrl )
    METHOD End()    
    METHOD GetValue( cHKey )    

ENDCLASS        

//----------------------------------------------------------------------------//

METHOD New( cKey, cModel ) CLASS TOpenAI

    if Empty( cKey )
       ::cKey = GetEnv( "OPENAI_API_KEY" )
    endif

    if ! Empty( cModel )
       ::cModel = cModel
    endif
    
    ::cUrl = "https://api.openai.com/v1/chat/completions"
    ::hCurl = curl_easy_init()
    
return Self    

//----------------------------------------------------------------------------//

METHOD End() CLASS TOpenAI

    curl_easy_cleanup( ::hCurl )
    ::hCurl = nil

return nil    

//----------------------------------------------------------------------------//

METHOD GetValue( cHKey ) CLASS TOpenAI

    local aKeys := hb_AParams(), cKey
    local uValue := hb_jsonDecode( ::cResponse )

    hb_default( @cHKey, "content" )

    if cHKey == "content"
       uValue = uValue[ "choices" ][ 1 ][ "message" ][ "content" ]
    endif

    TRY
       for each cKey in aKeys
          if ValType( uValue[ cKey ] ) == "A"
             uValue = uValue[ cKey ][ 1 ][ "choices" ][ 1 ][ "message" ][ "content" ]
          else
             uValue = uValue[ cKey ]
          endif
       next
    CATCH
       XBrowser( uValue )
    END

return uValue

//----------------------------------------------------------------------------//

METHOD Send( cPrompt ) CLASS TOpenAI 

    LOCAL aHeaders, cJson, hRequest := { => }, hMessage := { => }

    curl_easy_setopt( ::hCurl, HB_CURLOPT_POST, .T. )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_URL, ::cUrl )

    aHeaders := { "Content-Type: application/json", ;
                  "Authorization: Bearer " + ::cKey }

    curl_easy_setopt(::hCurl, HB_CURLOPT_HTTPHEADER, aHeaders)
    curl_easy_setopt(::hCurl, HB_CURLOPT_USERNAME, '')
    curl_easy_setopt(::hCurl, HB_CURLOPT_DL_BUFF_SETUP)
    curl_easy_setopt(::hCurl, HB_CURLOPT_SSL_VERIFYPEER, .F.)

    hb_HSet( hRequest, "model", ::cModel )
    hb_HSet( hMessage, "role", "user" )
    hb_HSet( hMessage, "content", cPrompt )

    hRequest[ "messages" ] = { hMessage }
    cJson = hb_jsonEncode( hRequest )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_POSTFIELDS, cJson )
    ::nError = curl_easy_perform( ::hCurl )
    curl_easy_getinfo( ::hCurl, HB_CURLINFO_RESPONSE_CODE, @::nHttpCode )

    if ::nError == HB_CURLE_OK
       ::cResponse = curl_easy_dl_buff_get( ::hCurl )
    else
       ::cResponse := "Error code " + Str( ::nError )
    endif
 
return ::cResponse

//----------------------------------------------------------------------------//

METHOD SendImage( cImageFileName ) CLASS TOpenAI

    local aHeaders, cJson, cBase64Image, hMessage := { => }

    if ! File( cImageFileName )
       MsgAlert( "Image " + cImageFileName + " not found" )
       return nil
    endif

    cBase64Image := hb_base64Encode( memoRead( cImageFileName ) )

    curl_easy_setopt( ::hCurl, HB_CURLOPT_POST, .T. )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_URL, "https://api.openai.com/v1/chat/completions" )

    aHeaders := { "Content-Type: application/json", ;
                  "Authorization: Bearer " + ::cKey }

    curl_easy_setopt( ::hCurl, HB_CURLOPT_HTTPHEADER, aHeaders )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_USERNAME, "" )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_DL_BUFF_SETUP )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_SSL_VERIFYPEER, .F. )

    hb_HSet( hMessage, "role", "user" )
    hb_HSet( hMessage, "content", { ;
        { "type" => "text", "text" => "What is in this image?" }, ;
        { "type" => "image_url", ;
          "image_url" => { "url" => "data:image/jpeg;base64," + cBase64Image } } } )

    cJson := hb_jsonEncode( { "model" => ::cModel, ;
                              "messages" => { hMessage } } )

    curl_easy_setopt( ::hCurl, HB_CURLOPT_POSTFIELDS, cJson )

    ::nError = curl_easy_perform( ::hCurl )
    curl_easy_getinfo( ::hCurl, HB_CURLINFO_RESPONSE_CODE, @::nHttpCode )

    if ::nError == HB_CURLE_OK
       ::cResponse = curl_easy_dl_buff_get( ::hCurl )
    else
       ::cResponse = "Error code " + Str( ::nError )
    endif

return ::cResponse

//----------------------------------------------------------------------------//

METHOD SendImageURL( cImageUrl ) CLASS TOpenAI

    local aHeaders, cJson, hRequest := { => }, hMessage := { => }

    curl_easy_setopt( ::hCurl, HB_CURLOPT_POST, .T. )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_URL, ::cUrl )

    aHeaders := { "Content-Type: application/json", ;
                  "Authorization: Bearer " + ::cKey }

    curl_easy_setopt( ::hCurl, HB_CURLOPT_HTTPHEADER, aHeaders )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_USERNAME, "" )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_DL_BUFF_SETUP )
    curl_easy_setopt( ::hCurl, HB_CURLOPT_SSL_VERIFYPEER, .F. )

    hb_HSet( hRequest, "model", ::cModel )
    hb_HSet( hMessage, "role", "user" )

    hb_HSet( hMessage, "content", { ;
        { "type" => "text", "text" => "What's in this image?" }, ;
        { "type" => "image_url", "image_url" => { "url" => cImageUrl } } } )

    hRequest[ "messages" ] = { hMessage }

    cJson = hb_jsonEncode( hRequest )

    curl_easy_setopt( ::hCurl, HB_CURLOPT_POSTFIELDS, cJson )

    ::nError = curl_easy_perform( ::hCurl )
    curl_easy_getinfo( ::hCurl, HB_CURLINFO_RESPONSE_CODE, @::nHttpCode )

    if ::nError == HB_CURLE_OK
       ::cResponse = curl_easy_dl_buff_get( ::hCurl )
    else
       ::cResponse = "Error code " + Str( ::nError )
    endif

return ::cResponse

//----------------------------------------------------------------------------//
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 44162
Joined: Thu Oct 06, 2005 05:47 PM
Re: OpenAI vision API from FWH
Posted: Fri Jan 03, 2025 10:48 PM
Next: our first AI Agent demo ;-)
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 1283
Joined: Fri Feb 10, 2006 02:34 PM
Re: OpenAI vision API from FWH
Posted: Mon Jan 06, 2025 08:12 AM

Hi,

Great !

C.

Salutacions, saludos, regards

"...programar es fácil, hacer programas es difícil..."

UT Page -> https://carles9000.github.io/
Forum UT -> https://discord.gg/bq8a9yGMWh
HIX -> https://github.com/carles9000/hix
Posts: 6984
Joined: Fri Oct 07, 2005 07:07 PM
Re: OpenAI vision API from FWH
Posted: Mon Jan 06, 2025 09:32 AM

Dear Antonio,

Thank you very much for your research work.

A few days ago, I saw an advertisement for the Jetson Nano Orin. Do you think it would be possible to use this hardware to run a custom LMM and then send requests using FIVEWIN?

For example:

Emails are read via a local tool (e.g., Outlook or a custom email parser) and provided in a structured form (e.g., text files or via an API).

Summary:

The language model analyzes the content of the emails and generates a short summary (e.g., "New reservation for room 12 from January 10th to 12th.").

Presentation:

The summarized information could be displayed in a user-friendly interface, e.g., in a FIVEWIN application.

Additional Features:

  • Keyword Detection: Highlighting important terms such as names, reservation dates, or invoice inquiries.

  • Categorization: Sorting emails by topics (e.g., bookings, complaints, inquiries).

Best regards,

Otto

Posts: 44162
Joined: Thu Oct 06, 2005 05:47 PM
Re: OpenAI vision API from FWH
Posted: Mon Jan 06, 2025 10:16 AM
Dear Otto,

Nvidia's Jetson Nano Orin uses Linux (a special ubuntu version) so I have just asked copilot if ollama may be installed on it:
Yes, it is possible to use Ollama on the Jetson Nano Orin. Ollama is an open-source tool that allows you to run large language models (LLMs) locally on Jetson devices, including the Jetson Nano Orin.

To install Ollama on your Jetson Nano Orin, you can follow these steps:

1. **Preparation**:
- Ensure you have JetPack 6.0 installed on your device.
- Download the SD card image from the official NVIDIA website.

2. **Native Installation**:
- Use the official Ollama installer:
```bash
curl -fsSL https://ollama.com/install.sh | sh
```
- This will create a service to run `ollama serve` at startup, allowing you to use the `ollama` command immediately.

3. **Using Docker Containers**:
- You can run Ollama inside a Docker container to avoid changes to your existing system:
```bash
docker run --runtime nvidia --rm --network=host -v ~/ollama:/ollama -e OLLAMA_MODELS=/ollama dustynv/ollama:r36.2.0
```

By following these steps, you can fully utilize the capabilities of your Jetson Nano Orin to run large language models efficiently.
We can use ollama from Harbour :)
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 44162
Joined: Thu Oct 06, 2005 05:47 PM
Re: OpenAI vision API from FWH
Posted: Mon Jan 06, 2025 10:19 AM
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 114
Joined: Fri Jul 21, 2006 07:15 PM
Re: OpenAI vision API from FWH
Posted: Tue Jan 07, 2025 12:38 PM
Hello all.

I am trying build exe from openai1.prg but experiencing I am linking errors: (unresolved external)
openai1.obj : error LNK2001: símbolo externo não resolvido _HB_FUN_CURL_EASY_INIT
openai1.obj : error LNK2001: símbolo externo não resolvido _HB_FUN_CURL_EASY_CLEANUP
openai1.obj : error LNK2001: símbolo externo não resolvido _HB_FUN_CURL_EASY_SETOPT
openai1.obj : error LNK2001: símbolo externo não resolvido _HB_FUN_CURL_EASY_PERFORM
openai1.obj : error LNK2001: símbolo externo não resolvido _HB_FUN_CURL_EASY_GETINFO
openai1.obj : error LNK2001: símbolo externo não resolvido _HB_FUN_CURL_EASY_DL_BUFF_GET
Harbour 32 and MSVC 2022.

Which libs is missing?

Thanks in advance.
FWH / xHarbour / BCC / MySql

Visual Studio / Harbour / DotNet Maui / C#
Posts: 44162
Joined: Thu Oct 06, 2005 05:47 PM
Re: OpenAI vision API from FWH
Posted: Tue Jan 07, 2025 02:16 PM

hbcurl.lib and libcurl.lib

regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 114
Joined: Fri Jul 21, 2006 07:15 PM
Re: OpenAI vision API from FWH
Posted: Wed Jan 08, 2025 12:49 PM
Antonio Linares wrote: hbcurl.lib and libcurl.lib
Thanks!
FWH / xHarbour / BCC / MySql

Visual Studio / Harbour / DotNet Maui / C#

Continue the discussion