Page 1 of 1

Error al compilar ejemplos Gemini# con xHb

Posted: Wed Feb 26, 2025 5:42 am
by Enrrique Vertiz
Saludos

Compilando los ejemplos de FWH 25.01 con xHarbour 10288 en samples, compilan varios pero todos los gemini#.prg, me dan el error abajo adjunto

Image

Y los ollama# no me funcionan ... algo me falta ?

Re: Error al compilar ejemplos Gemini# con xHb

Posted: Wed Feb 26, 2025 6:56 am
by Antonio Linares
Estimado Enrique,

Estamos terminando de adaptar los cambios más recientes de la Clase TGemini a xHarbour

Hoy al comenzar el webinar os daremos la versión más reciente de todas las Clases de Inteligencia Artificial para Harbour y xHarbour

Re: Error al compilar ejemplos Gemini# con xHb

Posted: Wed Feb 26, 2025 7:33 am
by Antonio Linares
Class TGemini para Harbour y xHarbour

Code: Select all | Expand

#include "FiveWin.ch"
#include "hbcurl.ch"

#ifdef __XHARBOUR__
   #define hb_hHasKey( h, k ) HHasKey( h, k )
#endif   

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

CLASS TGemini

   DATA   cKey   INIT ""
   DATA   cModel INIT "gemini-2.0-flash"
   DATA   cResponse
   DATA   cUrl   INIT "https://generativelanguage.googleapis.com/v1beta/models"
   DATA   cUploadUrl INIT "https://generativelanguage.googleapis.com/upload/v1beta/files"
   DATA   hCurl
   DATA   nError INIT 0
   DATA   nHttpCode INIT 0
   DATA   nTemperature INIT 0

   METHOD New( cKey, cModel )
   METHOD Send( uContent, cPrompt, bCallback )
   METHOD End()
   METHOD GetValue()
   METHOD UploadFile( cFileName, lDeleteAfter )
   METHOD GetTokens( cBuffer ) 

ENDCLASS

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

METHOD New( cKey, cModel ) CLASS TGemini

   if Empty( cKey )
      ::cKey = GetEnv( "GEMINI_API_KEY" )
   else
      ::cKey = cKey
   endif

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

   if Val( SubStr( Curl_Version_Info()[ 1 ], 1, RAt( ".", Curl_Version_Info()[ 1 ] ) - 1 ) ) - 8.10 > 0.2
      MsgAlert( "Please use an updated curl DLL" )
   endif    

   ::hCurl = curl_easy_init()

return Self

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

METHOD End() CLASS TGemini

   curl_easy_cleanup( ::hCurl )
   ::hCurl = nil

return nil

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

METHOD GetValue() CLASS TGemini

   local hResponse, uValue

   if ! Empty( ::cResponse )
      hb_jsonDecode( ::cResponse, @hResponse )
   endif

   if hb_isHash( hResponse )
      if hb_hHasKey( hResponse, "error" )
         uValue = "API Error: " + hResponse[ "error" ][ "message" ] + " (Code: " + hb_ntos( hResponse[ "error" ][ "code" ] ) + ")"
      elseif hb_hHasKey( hResponse, "candidates" ) .and. Len( hResponse[ "candidates" ] ) > 0
         TRY
            uValue = hResponse[ "candidates" ][ 1 ][ "content" ][ "parts" ][ 1 ][ "text" ]
         CATCH
            uValue = "Error: Unexpected response structure"
         END
      else
         uValue = "Error: No candidates in response"
      endif
   else
      uValue = "Error: Invalid response format"
   endif

return uValue

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

METHOD Send( uContent, cPrompt, bCallback ) CLASS TGemini

   local aHeaders, cJson, hRequest := {=>}, hContents := { => }, hGenerationConfig
   local cFileUri, cMimeType, lIsFile := .F., cUrlEndpoint
   local aFiles, nI, aParts := {}, cFileNameToUpload, cTempFile

   if Empty( cPrompt )
      cPrompt = "what is this or solve this"
   endif

   if hb_isArray( uContent )
      aFiles = uContent
      for nI = 1 to Len( aFiles )
         if hb_isChar( aFiles[ nI ] ) .and. File( aFiles[ nI ] )
            cFileNameToUpload = aFiles[ nI ]
            cTempFile = nil
            if Lower( Right( aFiles[ nI ], 3 ) ) == "prg"
               cTempFile = hb_FNameMerge( hb_FNameDir( aFiles[ nI ] ), hb_FNameName( aFiles[ nI ] ), "txt" )
               hb_FCopy( aFiles[ nI ], cTempFile )
               cFileNameToUpload = cTempFile
            elseif Lower( Right( aFiles[ nI ], 2 ) ) == "ch"
               cTempFile = hb_FNameMerge( hb_FNameDir( aFiles[ nI ] ), hb_FNameName( aFiles[ nI ] ), "txt" )
               hb_FCopy( aFiles[ nI ], cTempFile )
               cFileNameToUpload = cTempFile
            endif
            cFileUri = ::UploadFile( cFileNameToUpload, !Empty( cTempFile ) )
            if Empty( cFileUri )
               if !Empty( cTempFile ) .and. File( cTempFile )
                  hb_FileDelete( cTempFile )
               endif
               return "Error uploading file: " + aFiles[ nI ]
            endif
            do case
               case Lower( Right( aFiles[ nI ], 3 ) ) == "png"
                  cMimeType = "image/png"
               case Lower( Right( aFiles[ nI ], 3 ) ) $ "jpg|jpeg"
                  cMimeType = "image/jpeg"
               case Lower( Right( aFiles[ nI ], 3 ) ) == "pdf"
                  cMimeType = "application/pdf"
               case Lower( Right( aFiles[ nI ], 3 ) ) == "txt"
                  cMimeType = "text/plain"
               case Lower( Right( aFiles[ nI ], 3 ) ) == "csv"
                  cMimeType = "text/csv"
               case Lower( Right( aFiles[ nI ], 3 ) ) == "prg"
                  cMimeType = "text/plain"
               case Lower( Right( aFiles[ nI ], 2 ) ) == "ch"
                  cMimeType = "text/plain"
               otherwise
                  if !Empty( cTempFile ) .and. File( cTempFile )
                     hb_FileDelete( cTempFile )
                  endif
                  return "Unsupported file type: " + aFiles[ nI ]
            endcase
            AAdd( aParts, { "fileData" => { "fileUri" => cFileUri, "mimeType" => cMimeType } } )
            if !Empty( cTempFile ) .and. File( cTempFile )
               hb_FileDelete( cTempFile )
            endif
         else
            return "Invalid file in array: " + aFiles[ nI ]
         endif
      next
      lIsFile = .T.
   elseif hb_isChar( uContent ) .and. File( uContent )
      lIsFile = .T.
      cFileNameToUpload = uContent
      cTempFile = nil
      if Lower( Right( uContent, 3 ) ) == "prg"
         cTempFile = hb_FNameMerge( hb_FNameDir( uContent ), hb_FNameName( uContent ), "txt" )
         hb_FCopy( uContent, cTempFile )
         cFileNameToUpload = cTempFile
      elseif Lower( Right( uContent, 2 ) ) == "ch"
         cTempFile = hb_FNameMerge( hb_FNameDir( uContent ), hb_FNameName( uContent ), "txt" )
         hb_FCopy( uContent, cTempFile )
         cFileNameToUpload = cTempFile
      endif
      cFileUri = ::UploadFile( cFileNameToUpload, !Empty( cTempFile ) )
      if Empty( cFileUri )
         if !Empty( cTempFile ) .and. File( cTempFile )
            hb_FileDelete( cTempFile )
         endif
         return ""
      endif
      do case
         case Lower( Right( uContent, 3 ) ) == "png"
            cMimeType = "image/png"
         case Lower( Right( uContent, 3 ) ) $ "jpg|jpeg"
            cMimeType = "image/jpeg"
         case Lower( Right( uContent, 3 ) ) == "pdf"
            cMimeType = "application/pdf"
         case Lower( Right( uContent, 3 ) ) == "txt"
            cMimeType = "text/plain"
         case Lower( Right( uContent, 3 ) ) == "csv"
            cMimeType = "text/csv"
         case Lower( Right( uContent, 3 ) ) == "prg"
            cMimeType = "text/plain"
         case Lower( Right( uContent, 2 ) ) == "ch"
            cMimeType = "text/plain"
         otherwise
            if !Empty( cTempFile ) .and. File( cTempFile )
               hb_FileDelete( cTempFile )
            endif
            return "Unsupported file type"
      endcase
      AAdd( aParts, { "fileData" => { "fileUri" => cFileUri, "mimeType" => cMimeType } } )
      if !Empty( cTempFile ) .and. File( cTempFile )
         hb_FileDelete( cTempFile )
      endif
   endif

   cUrlEndpoint = iif( hb_isBlock( bCallback ), ":streamGenerateContent", ":generateContent" )
   curl_easy_setopt( ::hCurl, HB_CURLOPT_POST, .T. )
   curl_easy_setopt( ::hCurl, HB_CURLOPT_URL, ::cUrl + "/" + ::cModel + cUrlEndpoint + "?key=" + ::cKey )

   aHeaders := { "Content-Type: application/json" }
   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. )

   hContents[ "role" ] = "user"
   if lIsFile
      hRequest[ "contents" ] = { { "role" => "user", "parts" => aParts } }
      if ! Empty( cPrompt )
         AAdd( hRequest[ "contents" ], { "role" => "user", "parts" => { { "text" => cPrompt } } } )
      endif
   else
      hContents[ "parts" ] = { { "text" => iif( hb_isChar( uContent ), uContent, cPrompt ) } }
      hRequest[ "contents" ] = { hContents }
   endif

   hGenerationConfig = { "temperature" => ::nTemperature,;
                         "topK" => 40, "topP" => 0.95, "maxOutputTokens" => 8192,;
                         "responseMimeType" => "text/plain" }
   hRequest[ "generationConfig" ] = hGenerationConfig

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

   if hb_isBlock( bCallback )
      curl_easy_setopt( ::hCurl, HB_CURLOPT_WRITEFUNCTION, bCallback )
   endif

   ::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 = "CURL Error code " + Str( ::nError )
   endif

return ::cResponse

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

METHOD UploadFile( cFileName, lDeleteAfter ) CLASS TGemini

   local pCurl, aPost := {}, hHash

   if hb_isPointer( pCurl := curl_easy_init() )

      curl_easy_setopt( pCurl, HB_CURLOPT_CUSTOMREQUEST, "POST" )
      curl_easy_setopt( pCurl, HB_CURLOPT_URL, ::cUploadUrl + "?key=" + ::cKey )
      curl_easy_setopt( pCurl, HB_CURLOPT_FOLLOWLOCATION, .T. )
      curl_easy_setopt( pCurl, HB_CURLOPT_DL_BUFF_SETUP )
      curl_easy_setopt( pCurl, HB_CURLOPT_SSL_VERIFYPEER, .F. )

      AAdd( aPost, { "file", hb_jsonEncode( { "display_name" => cFileName } ) } )
      AAdd( aPost, { nil, cFileName } )

      curl_easy_setopt( pCurl, HB_CURLOPT_MIMEPOST, aPost )

      if ( ::nError := curl_easy_perform( pCurl ) ) == HB_CURLE_OK
         hHash = hb_jsonDecode( ::cResponse := curl_easy_dl_buff_get( pCurl ) )
      else
         MsgAlert( "curl error: " + AllTrim( Str( ::nError ) ) )
      endif

      curl_easy_cleanup( pCurl )
   endif

   if hb_isHash( hHash )
      #ifndef __XHARBOUR__
         if hb_hHasKey( hHash, "file" ) .and. hb_hHasKey( hHash[ "file" ], "uri" )
      #else
         if HHasKey( hHash, "file" ) .and. HHasKey( hHash[ "file" ], "uri" )      
      #endif      
        return hHash[ "file" ][ "uri" ]
      endif
   endif

   if lDeleteAfter .and. File( cFileName )
      hb_FileDelete( cFileName )
   endif

return ""

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

METHOD GetTokens( cBuffer ) CLASS TGemini

   local hResponse, cValue := ""

   if Left( cBuffer, 1 ) == ","
      cBuffer = SubStr( cBuffer, 2 )
   endif

   hb_jsonDecode( cBuffer, @hResponse )

   if ! Empty( hResponse )
      if ValType( hResponse ) == "A"  // Streaming response (array of chunks)
         if hb_hHasKey( hResponse[ 1 ], "error" )
            cValue = "API Error: " + hResponse[ 1 ][ "error" ][ "message" ] + " (Code: " + hb_ntos( hResponse[ 1 ][ "error" ][ "code" ] ) + ")"
         elseif hb_hHasKey( hResponse[ 1 ], "candidates" ) .and. Len( hResponse[ 1 ][ "candidates" ] ) > 0
            TRY
               cValue = hResponse[ 1 ][ "candidates" ][ 1 ][ "content" ][ "parts" ][ 1 ][ "text" ]
            CATCH
               cValue = "Error: Unexpected streaming response structure"
            END
         else
            cValue = "Error: No candidates in streaming response"
         endif
      elseif hb_isHash( hResponse )  // Non-streaming response
         if hb_hHasKey( hResponse, "error" )
            cValue = "API Error: " + hResponse[ "error" ][ "message" ] + " (Code: " + hb_ntos( hResponse[ "error" ][ "code" ] ) + ")"
         elseif hb_hHasKey( hResponse, "candidates" ) .and. Len( hResponse[ "candidates" ] ) > 0
            TRY
               cValue = hResponse[ "candidates" ][ 1 ][ "content" ][ "parts" ][ 1 ][ "text" ]
            CATCH
               cValue = "Error: Unexpected response structure"
            END
         else
            cValue = "Error: No candidates in response"
         endif
      else
         cValue = "Error: Invalid response format in streaming buffer"
      endif
   endif

return cValue

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

#ifdef __XHARBOUR__
   
function HB_FNAMEDIR( cFileName )
   local nLastSlash := Max( RAt( "\", cFileName ), RAt( "/", cFileName ) )
   if nLastSlash > 0
      return Left( cFileName, nLastSlash )
   endif
return ""

function HB_FNAMENAME( cFileName )
   local cName := cFileName
   local nLastSlash := Max( RAt( "\", cFileName ), RAt( "/", cFileName ) )
   local nLastDot

   if nLastSlash > 0
      cName = SubStr( cFileName, nLastSlash + 1 )
   endif

   nLastDot = RAt( ".", cName )
   if nLastDot > 0
      cName = Left( cName, nLastDot - 1 )
   endif

return cName

function HB_FCOPY( cSource, cDest )

   local hSource, hDest, nBytes, nRead, aBuffer := {}

   if hb_isPointer( hSource := FOpen( cSource, "rb" ) )
      if hb_isPointer( hDest := FOpen( cDest, "wb" ) )
         while ! hb_feof( hSource )
            nRead := FRead( aBuffer, 1, 1024, hSource )
            FWrite( aBuffer, 1, nRead, hDest )
         end
         FClose( hDest )
      endif
      FClose( hSource )
   endif

return nil   

function HB_FILEDELETE( cFileName )

   if File( cFileName )
      return FErase( cFileName )
   endif

return nil

#endif

Re: Error al compilar ejemplos Gemini# con xHb

Posted: Wed Feb 26, 2025 1:29 pm
by Enrrique Vertiz
Saludos Antonio

Copie el codigo y lo grabe como tgemini.prg en la carpeta clases, lo aumente en el Buildx.bat y ahora me sale el siguiente error

Image

Re: Error al compilar ejemplos Gemini# con xHb

Posted: Wed Feb 26, 2025 3:39 pm
by Antonio Linares
Enrique,

Vamos a distribuir un build actualizado de FWH 25.01

El error que te sale es porque está intentando usar el PRG como si fuese un OBJ

gracias!