Class TOpenAI_ChatGPT by Charles Kwon

Post Reply
User avatar
Antonio Linares
Site Admin
Posts: 42259
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Class TOpenAI_ChatGPT by Charles Kwon

Post by Antonio Linares »

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

#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
    https://forums.fivetechsupport.com/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
Ruth
Posts: 172
Joined: Fri Dec 07, 2007 1:26 pm
Contact:

Re: Class TOpenAI_ChatGPT by Charles Kwon

Post by Ruth »

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

Post by CharlesKwon »

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
Ruth
Posts: 172
Joined: Fri Dec 07, 2007 1:26 pm
Contact:

Re: Class TOpenAI_ChatGPT by Charles Kwon

Post by Ruth »

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
Post Reply