FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin for Harbour/xHarbour AI - New Class TGrok
Posts: 44158
Joined: Thu Oct 06, 2005 05:47 PM
AI - New Class TGrok
Posted: Fri May 23, 2025 11:11 AM
As xAI has finally published a public API, we have implemented a new Class TGrok for Harbour and FWH.

Included in next FWH build.

Class TGrok
#include "FiveWin.ch"
#include "hbcurl.ch"

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

CLASS TGrok
    
    DATA   cKey   INIT ""
    DATA   cModel INIT "grok-3-latest"
    DATA   cPrompt
    DATA   cResponse
    DATA   cUrl
    DATA   hCurl
    DATA   nError INIT 0
    DATA   nHttpCode INIT 0
    DATA   nTemperature INIT 0.5

    METHOD New( cKey, cModel )
    METHOD Send( cPrompt )
    METHOD SendStream( cPrompt, bCallback )      
    METHOD SendImage( cImageFileName, cPrompt )    
    METHOD SendImageURL( cImageUrl, cPrompt )
    METHOD End()    
    METHOD GetValue()    
    DESTRUCTOR Destroy()

ENDCLASS        

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

METHOD New( cKey, cModel ) CLASS TGrok

   if Empty( cKey )
      ::cKey = GetEnv( "XAI_API_KEY" )
      if Empty( ::cKey )
         MsgAlert( "XAI_API_KEY not found" )
      endif  
   else
      ::cKey = cKey    
   endif

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

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

METHOD End() CLASS TGrok

   if ::hCurl != nil
      curl_easy_cleanup( ::hCurl )
      ::hCurl = nil
   endif   

return nil    

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

PROCEDURE Destroy() CLASS TGrok

   if ::hCurl != nil
      ::End()
   endif

return    

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

METHOD GetValue() CLASS TGrok

   local hResponse, uValue 
   
   hb_jsonDecode( ::cResponse, @hResponse )

   TRY 
      uValue = hResponse[ "choices" ][ 1 ][ "message" ][ "content" ]
   CATCH
      uValue = hResponse[ "error" ]
   END   

return uValue

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

METHOD Send( cPrompt ) CLASS TGrok 

   LOCAL aHeaders, cJson, hRequest := { => }, hSystemMessage := { => }, hUserMessage := { => }

   if ! Empty( cPrompt )
      ::cPrompt = cPrompt
   endif   

   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. )

   hRequest[ "model" ]    = ::cModel
   hSystemMessage[ "content" ] = "You are Grok, created by xAI."
   hSystemMessage[ "role" ]    = "system"
   hUserMessage[ "content" ]   = ::cPrompt
   hUserMessage[ "role" ]      = "user"
   hRequest[ "messages" ]      = { hSystemMessage, hUserMessage }
   hRequest[ "temperature" ]   = ::nTemperature
   hRequest[ "stream" ]        = .F.

   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 SendStream( cPrompt, bCallback ) CLASS TGrok

   local aHeaders, cJson, hRequest := { => }, hSystemMessage := { => }, hUserMessage := { => }

   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_SSL_VERIFYPEER, .F. )

   hRequest[ "model" ]    = ::cModel
   hSystemMessage[ "content" ] = "You are Grok, created by xAI."
   hSystemMessage[ "role" ]    = "system"
   hUserMessage[ "role" ]      = "user"
   hUserMessage[ "content" ]   = cPrompt
   hRequest[ "messages" ]      = { hSystemMessage, hUserMessage }
   hRequest[ "temperature" ]   = ::nTemperature
   hRequest[ "stream" ]        = .T.

   cJson = hb_jsonEncode( hRequest )
   curl_easy_setopt( ::hCurl, HB_CURLOPT_POSTFIELDS, cJson )

   curl_easy_setopt( ::hCurl, HB_CURLOPT_WRITEFUNCTION, bCallback )

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

   if ::nError != HB_CURLE_OK
      ::cResponse := "Error code " + Str( ::nError )
   endif
    
return ::cResponse

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

METHOD SendImage( cImageFileName, cPrompt ) CLASS TGrok

   local aHeaders, cJson, cBase64Image, hSystemMessage := { => }, hUserMessage := { => }

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

   DEFAULT cPrompt := "What is in this image?"

   cBase64Image = hb_base64Encode( memoRead( cImageFileName ) )

   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. )

   hSystemMessage[ "role" ] = "system"
   hSystemMessage[ "content" ] = "You are Grok, created by xAI."
   hUserMessage[ "role" ] = "user"
   hUserMessage[ "content" ] = { ;
        { "type" => "text", "text" => cPrompt }, ;
        { "type" => "image_url", ;
          "image_url" => { "url" => "data:image/jpeg;base64," + cBase64Image } } }

   cJson = hb_jsonEncode( { "model" => ::cModel, ;
                            "messages" => { hSystemMessage, hUserMessage }, ;
                            "temperature" => ::nTemperature, ;
                            "stream" => .F. } )

   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, cPrompt ) CLASS TGrok

   local aHeaders, cJson, hRequest := { => }, hSystemMessage := { => }, hUserMessage := { => }

   DEFAULT cPrompt := "What is in this image?"

   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. )

   hRequest[ "model" ] = ::cModel
   hRequest[ "temperature" ] = ::nTemperature
   hRequest[ "stream" ] = .F.
   hSystemMessage[ "role" ] = "system"
   hSystemMessage[ "content" ] = "You are Grok, created by xAI."
   hUserMessage[ "role" ] = "user"
   hUserMessage[ "content" ] = { ;
       { "type" => "text", "text" => cPrompt }, ;
       { "type" => "image_url", "image_url" => { "url" => cImageUrl } } }
   hRequest[ "messages" ] = { hSystemMessage, hUserMessage }

   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

//----------------------------------------------------------------------------//
samples\grok1.prg
// Remember to set from CMD: set XAI_API_KEY=sk-... 

#include "FiveWin.ch"

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

function Main()

    local oGrok := TGrok():New()

    oGrok:Send( "Tell me France capital" )

    MsgInfo( oGrok:GetValue() )

return nil    

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

Antonio Linares
www.fivetechsoft.com

Continue the discussion