B4A Library [B4X] OpenAI - A.I. Text & Image generation

Only tested in B4A so far

This library is designed to facilitate communication with the multimodal OpenAI API, enabling your B4X applications to leverage the capabilities of OpenAI's models for
text generation (GPT-3.5 Turbo and GPT-4),
image generation (DALL-E 3),
text-to-speech functionalities.
Vision API will be added soon!

get your API key here.
Used tokens arent calculated yet.
OpenAI pricing is pay-as-you-go, meaning you only pay for what you use without needing a subscription.
Text generation costs are low. For example, generating text equivalent to the length of "The Hobbit" (around 95,000 words) with GPT-3.5 would cost about $0.25.
Image generation costs are also affordable. Generating a single 1024x1024 image costs around $0.040.

You will see all prices here:

DependsOn: XUI, JSON and OkHttpUtils2

B4X:
Dim oai As OpenAI
oai.Initialize(Me, "OpenAI", "your-api-key")

'In conjunction with ChatGPT, the library will buffer all messages from GPT
'and the user to maintain the context of the chat history. Use .ResetChat to start over.
oai.ChatModel=oai.MODEL_GPT35_TURBO 'or MODEL_GPT4
oai.SystemMessage("Act like a math teacher called Tom, write witty but informative.") 'optional, tell the bot once how to interpret the chat /act
oai.ChatMessage("Hello tom, please explain the determinant method to me!")

' Interact with DALL-E 3
oai.ImageAspectRatio(oai.IMAGE_16_9) 'optional, IMAGE_1_1; IMAGE_16_9, IMAGE_9_16
oai.generateImage("A blue elephant in a Greenhouse")

' Interact withTTS
oai.TTSVoice=oai.TTS_FABLE 'optional, TTS_ALLOY,TTS_ECHO,TTS_FABLE,TTS_ONYX,TTS_NOVA,TTS_SHIMMER
oai.TextToSpeech("Hello, this is a test")

' Implement corresponding event handlers in your activity or class
Sub OpenAI_ChatResponse(response As String)
    Log(response)
End Sub

Sub OpenAI_ImageResponse(image As B4XBitmap)
    ImageView.SetBitmap(image)
End Sub

Sub OpenAI_TTSResponse(folder As String, filename As String)
    MediaPlayer.Load(folder, filename)
    MediaPlayer.Play
End Sub

Sub OpenAI_Error(message As String)
    Log("Error: " & message)
End Sub


Have Fun!
 

Attachments

  • OpenAI.b4xlib
    2.3 KB · Views: 226
Last edited:

Tim Chapman

Active Member
Licensed User
Longtime User
Then when I run the code below which is in theB4XMainPage module in my IDE I get this error:

java.lang.NoSuchMethodError: 'java.lang.String b4j.example.httpjob._initialize(b4j.example.httpjob, anywheresoftware.b4a.BA, java.lang.String, java.lang.Object)'

The libraries that are selected are:

B4XPages
jCore
jFX
jOkHttpUtils2
Json
OpenAI
XUI Views

B4J code:
Sub Class_Globals
    Private Root As B4XView
    Private xui As XUI
    Dim oai As OpenAI
End Sub

Public Sub Initialize
    B4XPages.GetManager.LogEvents = True 'To enable logging B4XPages events.
    oai.Initialize(Me, "OpenAI", "sk-sv...")

    'In conjunction with ChatGPT, the library will buffer all messages from GPT
    'and the user to maintain the context of the chat history. Use .ResetChat to start over.
    
    oai.ChatModel=oai.MODEL_GPT35_TURBO 'or MODEL_GPT4
    oai.SystemMessage("Act like a math teacher called Tom, write witty but informative.") 'optional, tell the bot once how to interpret the chat /act
    oai.ChatMessage("Hello tom, please explain the determinant method to me!")
End Sub

'This event will be called once, before the page becomes visible.
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Root.LoadLayout("MainPage")
End Sub

'You can see the list of page related events in the B4XPagesManager object. The event name is B4XPage.

Private Sub Button1_Click
    xui.MsgboxAsync("Hello world!", "B4X")
End Sub

Sub OpenAI_ChatResponse(response As String)
    Log(response)
End Sub

Sub OpenAI_Error(message As String)
    Log("Error: " & message)
End Sub
 

JGParamo

Active Member
Licensed User

JGParamo

Active Member
Licensed User

JGParamo

Active Member
Licensed User

Tim Chapman

Active Member
Licensed User
Longtime User
Here is how I wait for a reply. See lines 84 and 104.

B4A code:
#Region  Project Attributes
    #ApplicationLabel: AI Test
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: unspecified
    #CanInstallToExternalStorage: False
    #BridgeLogger: True
    'to enable logs in Release mode.
#End Region

#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region

#AdditionalJar: poi-3.12-android-a
#AdditionalJar: poi-ooxml-schemas-3.12-20150511-a
#MultiDex: true

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Private xui As XUI
    Private xui As XUI
    Dim oai As OpenAI
    Dim MediaPlayer As MediaPlayer
    Dim xls As XSSFWorkbook
    Dim FileName As String
    Dim SpreadsheetDir As String
    Dim MonsterName As String
    Dim RowCounter As Int
    Dim columnnum As Int
    Dim AIresponse As String
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("Layout")
    MediaPlayer.Initialize
    FileName = "monsters.xlsx"
    SpreadsheetDir = File.Combine(File.DirRootExternal,"Download")
   
    If FirstTime = True Then Starter.RowNumber = 740
   
End Sub

Sub Activity_Resume
    Wait For (CheckAndRequestNotificationPermission) Complete (HasPermission As Boolean) 'Any call to Sleep() or Wait For will cause a return to the parent sub.
    Log("*Check and Requestion Notification Permission should be complete")
    If HasPermission = False Then
        Log("*no permission")
        ToastMessageShow("no permission", True)
        Return
    End If
   
    'Get access to downloads
    Starter.rp.CheckAndRequest(Starter.rp.PERMISSION_WRITE_EXTERNAL_STORAGE)
    Wait For Activity_PermissionResult (Permission As String, Result As Boolean)
    Log("*Finished getting permission")
    If Result = False Then Return

    MainSub
End Sub

Sub MainSub
    For RowCounter = Starter.RowNumber To 2067 '2067 '7 per minute.
        Log("Row Number = " & RowCounter)
        MonsterName = ReadSpreadsheet
        Log("Monster Name = " & MonsterName)
        columnnum = 68
        WriteToSpreadsheet(MonsterName)
        Wait For WriteToSpreadsheet_Complete
        File.Copy(SpreadsheetDir,"tempmonsters.xlsx",SpreadsheetDir,FileName)
       
        'For columnnum = 69 To 73
        columnnum = 69
        oai.Initialize(Me, "OpenAI", "sk-...")
        oai.ChatModel=oai.MODEL_GPT35_TURBO 'or MODEL_GPT4
        oai.ChatMessage("Find informaiton about the behavior of the Dungeons & Dragons monster " & MonsterName & "online.  Reply with Behavior Without Leaders, Behavior With Leaders, Location-Based Behavior, Alignment Influence, Other Behavior Factors.  Do not create answers yourself.  Find the answers online.  Separate reply sentences by tab characters.  Don't give table headings in your reply.  Don't preface your answer with heading title information.  Just give the reply with no preamble.")
        Wait For ResponseReceived_Complete
        WriteToSpreadsheet(AIresponse)
        Wait For WriteToSpreadsheet_Complete
        File.Copy(SpreadsheetDir,"tempmonsters.xlsx",SpreadsheetDir,FileName)
        'Next
    Next
End Sub

Sub Activity_Pause (UserClosed As Boolean)
   
End Sub

Sub Button1_Click
    xui.MsgboxAsync("Hello world!", "B4X")
End Sub

' Implement corresponding event handlers in your activity or class
Sub OpenAI_ChatResponse(response As String)
    AIresponse = response
    Log(response)
    CallSubDelayed(Me, "ResponseReceived_Complete")
End Sub

'Sub OpenAI_ImageResponse(image As B4XBitmap)
'    Dim B4XImageView1 As B4XImageView
'    B4XImageView1.Initialize(
'    B4XImageView1.SetBitmap(image)
'End Sub

'Sub OpenAI_TTSResponse(folder As String, filename As String)
'    MediaPlayer.Load(folder, filename)
'    MediaPlayer.Play
'End Sub

Sub OpenAI_Error(message As String)
    Log("Error: " & message)
End Sub

Sub ReadSpreadsheet As String 'The only thing that is read from the monster spreadsheet is the monster name in column 1.  Rownum.
    Log("ReadSpreadsheet sub started")
    Dim Monster As String
    Dim ColumnNuber As Int = 1 'Monster Name column.
    xls.Initialize("",File.Combine(SpreadsheetDir, FileName))
    Private MonsterSheet As XLSSheet = xls.getSheetAt(0) 'Selects the first sheet in the spreadsheet.
       
    Dim row As XSSFRow = MonsterSheet.getRow(RowCounter)

    'Log("Row #"&RowNumber& "FirstCell="&Row.FirstCellNum&", LastCell="&Row.LastCellNum)
    Private ActiveColumns As List 'We only want data from certain columns of the spreadsheet to show in the tables.
    ActiveColumns.Initialize
    ActiveColumns.AddAll(Array As Int(0,1,2,5,6,9,11,14,18))
       
    Dim cell As XSSFCell =row.getCell(ColumnNuber)
    If cell.IsInitialized Then
        'Log("..")
        'Log("Cell # "&CellNumber)
        'Log("Cell Initialized = "&cell.IsInitialized)
        'Log("Raw:"& cell.RawValue)'Log("Raw:"&cell.RawValue)
        'Log("CellValueType= "&cell.CellType)
        'Cell Types: Numeric is type 0. 1 is Text. 2 is Formula. 3 is Blank. 4 is Boolean. 5 is error.
        Monster = cell.StringCellValue
        'Cell Types: Numeric is type 0. 1 is Text. 2 is Formula. 3 is Blank. 4 is Boolean. 5 is error.
        'Log(cell)
        'Log(row)
    End If
    Log("ReadSpreadsheet Sub Done")
    Return Monster
End Sub

Sub WriteToSpreadsheet(response As String)
    Log("WriteToSpreadsheet sub started")
   
    xls.Initialize("",File.Combine(SpreadsheetDir, FileName))
    Private MonsterSheet As XLSSheet = xls.getSheetAt(0) 'Selects the first sheet in the spreadsheet.

    Dim row As XSSFRow = MonsterSheet.getRow(RowCounter)
    'Log("Row #"&RowNumber& "FirstCell="&Row.FirstCellNum&", LastCell="&Row.LastCellNum)

    Dim cell As XSSFCell = row.getCell(columnnum)
    cell = row.createCell(columnnum)
    'Log("Cell # "&columnnum)
    'Log(cell.IsInitialized)
    'These below won't work if the cell is blank because it is not initialized.
    'Log("Raw:"&cell.RawValue)'Log("Raw:"&cell.RawValue)
    'Log("CellValueType= "&cell.CellType)
    'Log("Here")
    cell.StringCellValue = response
    'Log("Here1")
    Dim outstream As OutputStream = File.OpenOutput(SpreadsheetDir, "tempmonsters.xlsx", False)
    'Log("Here2")
    xls.write(outstream)
    'Log("Here3")
    outstream.Close
    'Log("Here4")
    'Cell Types: Numeric is type 0. 1 is Text. 2 is Formula. 3 is Blank. 4 is Boolean. 5 is error.
    'Log(cell)
    'Log(row)
    Log("WriteToSpreadsheet sub done")
    CallSubDelayed(Me, "WriteToSpreadsheet_Complete")
End Sub

Private Sub CheckAndRequestNotificationPermission As ResumableSub
    Log("CheckAndRequestNotificationPermission sub started")
    Private p As Phone
    If p.SdkVersion < 33 Then Return True
    Private ctxt As JavaObject
    ctxt.InitializeContext
    Private targetSdkVersion As Int = ctxt.RunMethodJO("getApplicationInfo", Null).GetField("targetSdkVersion")
    If targetSdkVersion < 33 Then Return True
    Private NotificationsManager As JavaObject = ctxt.RunMethod("getSystemService", Array("notification"))
    Private NotificationsEnabled As Boolean = NotificationsManager.RunMethod("areNotificationsEnabled", Null)
    If NotificationsEnabled Then Return True
    Private rp As RuntimePermissions
    rp.CheckAndRequest(rp.PERMISSION_POST_NOTIFICATIONS)
    Wait For Activity_PermissionResult (Permission As String, Result As Boolean) 'change to B4XPage_PermissionResult if B4XPages project
    Log("*Permission Result = "&Permission & ": " & Result)
    Log("CheckAndRequestNotificationPermission sub done")
    Return Result
End Sub
 

JGParamo

Active Member
Licensed User
I have renamed jOKHttpUtils2.jar to OkHttpUtils2.jar. It is in the B4J\Libraries folder. The libraries manager won't show this library but the code complies without error only if I select the jOkHttpUtils2 library in the libraries manager. What am I missing here?

Leave the jOKHttpUtils2.jar as is, don't rename it. What you need to do is copy jOKHttpUtils2.jar within the same folder (in your B4J\Libraries folder you will have jOKHttpUtils2-copy.jar) and rename that copied file as OkHttpUtils2.jar, not the original.
 

Tim Chapman

Active Member
Licensed User
Longtime User
Leave the jOKHttpUtils2.jar as is, don't rename it. What you need to do is copy jOKHttpUtils2.jar within the same folder (in your B4J\Libraries folder you will have jOKHttpUtils2-copy.jar) and rename that copied file as OkHttpUtils2.jar, not the original.
I have done all you said but still get this error during compiling of the code:

Unknown type: httpjob<br />Are you missing a library reference?
Object reference not set to an instance of an object.

If I check the jOKHttpUtils2.jar library in the Libraries Manager, the code compiles without error but then gives me this error when I type in a chat and press enter:

java.lang.NoSuchMethodError: 'java.lang.String b4j.example.httpjob._initialize(b4j.example.httpjob, anywheresoftware.b4a.BA, java.lang.String, java.lang.Object)'

I am running B4J version 10. I am running in Debug mode.

Attached is a picture of the libraries selected.
 

Attachments

  • llibraries.jpg
    llibraries.jpg
    68.3 KB · Views: 26

JGParamo

Active Member
Licensed User

JGParamo

Active Member
Licensed User
Note that this only works if I check the jOKHttpUtils2.jar library in the Libraries Manager. Otherwise I get the same compile error I got above.
You should, as jOKHttpUtils2.jar is a must to use the OpenAI library. The copied OKHttpUtils2.jar is just a work-around until certain bug, if there is, is dealt with. If that bug is corrected (presumably by Erel ), the copied OKHttpUtils2.jar would no longer be needed and can be deleted.
 
Last edited:
Top