Class TOpenAI_ChatGPT by Charles Kwon

Class TOpenAI_ChatGPT by Charles Kwon

Postby Antonio Linares » Tue Jan 30, 2024 10:04 pm

Many thanks to master Charles Kwon

This code is adapted for gpt-3.5-turbo from one published by Reinaldo on the forums. Hats off to Reinaldo for publishing it.

Code: Select all  Expand view
#include "Fivewin.ch"
#include "hbcurl.ch"


FUNCTION Main()
    LOCAL oApi
    LOCAL cKey := ""  // you have get a APIKEY from https://platform.openai.com/api-keys

    oApi := TOpenAI_ChatGPT():New( cKey )

    oApi:prompt := "what is harbour-project?"
    oApi:Send()

    ?oApi:Response()


RETURN NIL    


/*

    Orignal code from : Reinaldo
    viewtopic.php?f=3&t=43171&start=0&hilit=openai


    This code is adapted for gpt-3.5-turbo from one published by Reinaldo on the forums. Hats off to Reinaldo for publishing it.
   


    Modify : Charles KWON ( charleskwonohjun@gmail.com ) , www.charleskwon.com


Here's what I added

1.
  Changed to allow you to pass in OpenAI's key value when calling CLASS.
  oApi := TOpenAI_ChatGPT():New( cKey )

 
2.
 According to the OpenAI development documentation,
 We need to pass the following value in the message,
 so I added it like this      

        hb_HSet( h, "model", ::model )
   
        hb_HSet( hMessage, "role", "user" )
        hb_HSet( hMessage, "content", ::prompt )



*/



CLASS TOpenAI_ChatGPT

    DATA cKey AS CHARACTER INIT ""
    DATA hCurl
    DATA httpcode
    DATA nError             INIT 0
 
    DATA Response
    DATA Prompt

    DATA model              INIT "gpt-3.5-turbo"
    DATA cUrl               INIT "https://api.openai.com/v1/chat/completions"
    DATA max_tokens         INIT 2048
    DATA temperature        INIT 0
    DATA top_p              INIT 1
    DATA frequency_penalty  INIT 0.00
    DATA presence_penalty   INIT 0.00
 
    DATA cLogFile        INIT "TOpenAI.log"
    DATA nMaxLogSize     INIT 32768
    DATA lDebug          INIT .F.
 
    METHOD New()
    METHOD End()
    METHOD Send()
    METHOD Reset()
 
    //parses response fetching ICD10 codes coded by OpenAI.
    METHOD GetICD10sFromResponse()
 
 ENDCLASS
 
 // Changed to allow you to pass in OpenAI's key value when calling CLASS.
 //
 //------------------------------------------------------------------------------------------------
 
 METHOD New( cKey ) CLASS TOpenAI_ChatGPT

    ::cKey := cKey
    ::hCurl := curl_easy_init()
 
 RETURN Self
 
// According to the OpenAI development documentation,
// We need to pass the following value in the message,
// so I added it like this      
//
//hb_HSet( h, "model", ::model )
   
//hb_HSet( hMessage, "role", "user" )
//hb_HSet( hMessage, "content", ::prompt )

//h["messages"] := {hMessage}


 METHOD Send() CLASS TOpenAI_ChatGPT
    LOCAL aheaders
    Local httpcode
    Local cJson
    Local h := { => }
    LOCAL 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. )


   // According to the OpenAI development documentation,
   // We need to pass the following value in the message,
   // so I added it like this  
   
 
    hb_HSet( h, "model", ::model )
   
    hb_HSet( hMessage, "role", "user" )
    hb_HSet( hMessage, "content", ::prompt )
 
    h["messages"] := {hMessage}


   
 
    cJson := hb_jsonEncode( h )  
    curl_easy_setopt( ::hcurl, HB_CURLOPT_POSTFIELDS, cJson ) //cPostFields )
 
    ::nError := curl_easy_perform( ::hCurl )
    curl_easy_getinfo( ::hCurl, HB_CURLINFO_RESPONSE_CODE, @httpcode )
 
    ::httpcode := httpcode
 
    IF ::nError == HB_CURLE_OK
       ::Response = curl_easy_dl_buff_get( ::hCurl )
       IF ::lDebug

       ENDIF
    ELSE
 
    ENDIF
 
RETURN ::Response            
 
 //------------------------------------------------------------------------------------------------
 METHOD Reset() CLASS TOpenAI_ChatGPT
     
    curl_easy_reset( ::hCurl )
    ::nError := HB_CURLE_OK
    ::Response := Nil
 
 return NIL
 
 
 
 //------------------------------------------------------------------------------------------------
 METHOD End() CLASS TOpenAI_ChatGPT

    curl_easy_cleanup( ::hCurl )
    ::hCurl := Nil  
 
 return NIL
 
 
 /*------------------------------------------------------------------------------------------------
 -------------------------------------------------------------------------------------------------*/

 METHOD GetICD10sFromResponse() CLASS TOpenAI_ChatGPT
    LOCAL aICD10s := {}
    LOCAL aParsed, iter, acodelines, code
    LOCAL a := {}
    LOCAL aKeys
    LOCAL hResponse := hb_jsonDecode( ::Response )
 
    if ::lDebug
 
      // LogData( ::cLogFile, { "hb_isHash( hResponse )", hb_isHash( hResponse ), ;
      //                      "hb_HHasKey( hResponse, 'choices' )", hb_HHasKey( hResponse, "choices" ) } )
       aKeys := HGetKeys( hResponse )
       //LogData( ::cLogFile, aKeys, ::nMaxLogSize )
 
    ENDIF
 
 
    IF hb_isHash( hResponse ) .AND. ;
       hb_HHasKey( hResponse, "choices" )
 
       if HB_ISARRAY( hResponse[ "choices" ] )
          a := hResponse[ "choices" ]
       endif
 
       FOR iter := 1 TO LEN( a )
 
          IF hb_HHasKey( a[ iter ], "text" )
         
             acodelines := hb_ATokens( a[ iter ][ "text" ], CRLF )
 
             FOR EACH Code IN acodelines
 
                aParsed := hb_ATokens( Code, "-" )
                AADD( aIcd10s, aParsed )
 
             NEXT
 
          ENDIF
 
       NEXT iter
 
    ENDIF
 
 RETURN aICD10s
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: Class TOpenAI_ChatGPT by Charles Kwon

Postby Ruth » Wed Jan 31, 2024 10:18 am

Dear friends,

how wonderful :-)
one question please ... could someone suggest to me a safe way of storing cKey in this context?
on openai they suggest an environment variable...is this a good approach? or is it even necessary to bother?

thank you for your expertice and kind regards
ruth
User avatar
Ruth
 
Posts: 135
Joined: Fri Dec 07, 2007 1:26 pm

Re: Class TOpenAI_ChatGPT by Charles Kwon

Postby CharlesKwon » Thu Feb 01, 2024 12:27 am

Hello

According to OpenAI's API protocol, the API communicates with the endpoint, and the communication protocol is https. In other words, there is no risk of leakage of cKey because the communication is encrypted.

However, if you want to use encryption to protect your key locally, you can encrypt and store your key and decrypt the key before calling OpenAI. Luckily, fivewin already has encrypt() and decrypt() functions.

Regards,
Charles KWON

Ruth wrote:Dear friends,

how wonderful :-)
one question please ... could someone suggest to me a safe way of storing cKey in this context?
on openai they suggest an environment variable...is this a good approach? or is it even necessary to bother?

thank you for your expertice and kind regards
ruth
User avatar
CharlesKwon
 
Posts: 28
Joined: Sun Nov 02, 2014 7:03 am

Re: Class TOpenAI_ChatGPT by Charles Kwon

Postby Ruth » Thu Feb 01, 2024 6:52 am

Dear Mr. Kwon,

thanks a lot for your answer. And also thank you for pointing me to the encrypt() and decrypt() functions ... they seem very useful in several scenarios.

thanks again and kind regards
ruth
User avatar
Ruth
 
Posts: 135
Joined: Fri Dec 07, 2007 1:26 pm


Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 66 guests

cron