Android Question Raw ChatGPT class for B4X

JackKirk

Well-Known Member
Licensed User
Longtime User
Following on from:

https://www.b4x.com/android/forum/threads/gpt-3.145654/post-923913

and seeing as a ChatGPT API has emerged, I have cobbled together the following raw ChatGPT class.

You can take it in all sorts of directions from here...

I haven't tested it but it should also work in B4i and B4J.

B4X:
'This class is now very loosely based on:
'https://www.b4x.com/android/forum/threads/gpt-3.145654/#content
'by Abdull Cadre to which I say thanks again
Sub Class_Globals
 
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
 
End Sub

Public Sub Query(system_string As String, query_string As String) As ResumableSub
 
    'For complete documentation you should look at:
    'https://platform.openai.com/docs/api-reference/chat
 
    Try
  
        Dim chat_string As String
  
        chat_string = "{""model"":""gpt-3.5-turbo"",""messages"":[{""role"": ""system"", ""content"":""" & _
                       system_string & """},{""role"": ""user"", ""content"":""" & _
                       query_string & "?""}]}"

        'Uncomment this line if you want to see raw input string
        'Log(chat_string)

        'You can add optional parameters by just adding them to the end, e.g.:
        'chat_string = "{""model"":""gpt-3.5-turbo"",""messages"":[{""role"": ""system"", ""content"":""" & _
        '               system_string & """},{""role"": ""user"", ""content"":""" & _
        '               query_string & "?""}],""temperature"":""2""}"
        'for details of all options available see reference given above
  
        Dim response As String
  
        Dim req As Http_Job
        req.Initialize("", Me)
        req.PostString("https://api.openai.com/v1/chat/completions", chat_string)
  
        'You can quite easily generate your own account API key by following
        'https://accessibleai.dev/post/generating_text_with_gpt_and_python/
        'under heading [Getting a GPT-3 API Key]
        req.GetRequest.SetHeader("Authorization", "Bearer sk-xxx")
  
        'And if you have an organisation key...
        'If your account default organisation is "Personal" then you can supply
        'a blank organisation key - or just comment this line out
        'req.GetRequest.SetHeader("OpenAI-Organization", "org-xxx")
        req.GetRequest.SetHeader("OpenAI-Organization", "")
  
        req.GetRequest.SetContentType("application/json")
  
        Wait For (req) JobDone(req As Http_Job)
  
        If req.Success Then
      
            'Uncomment this line if you want to see raw JSON response
            'Log(req.GetString)
      
            response = ParseJson(req.GetString)
  
        Else
      
            response = "ERROR: " & req.ErrorMessage
  
        End If
  
        req.Release
 
    Catch
  
        response = "ERROR: " & LastException
 
    End Try
 
    Return response

End Sub

'I did as JohnC suggested in:
'https://www.b4x.com/android/forum/threads/lost-in-chatgpt-json.146738/post-930211
'and asked ChatGPT:
'using b4a how do I parse this json string: "{""id"":""chatcmpl-6t2JQdgU1ypn0ayhONAkE6bAEoGkz"",""object"":""chat.completion"",""created"":1678574948,""model"":""gpt-3.5-turbo-0301"",""usage"":{""prompt_tokens"":25,""completion_tokens"":110,""total_tokens"":135},""choices"":[{""message"":{""role"":""assistant"",""content"":""Ahoy matey, ye be askin' a great question. The worst investment be ones that promise quick riches without flappin' yer sails too much, like the \""get rich quick\"" schemes, ponzi schemes Or pyramid schemes. These scams be all about misuse of trust And deceivin' the inexperienced. They be luring investors with high promised returns, but in the end, they just take yer doubloons and disappear into the horizon. Stay away from such crooks and keep yer treasure safe, me hearty!""},""finish_reason"":""stop"",""index"":0}]}" for content
'and it responded with this - except it used a variable named "object" which
'B4A objected to that I had to change to "object_string"
'I also had to change the management of the variable "content" so the subroutine would return a result
Sub ParseJson(json As String) As String
    Dim parser As JSONParser
    parser.Initialize(json)
    Dim root As Map
    root = parser.NextObject
    Dim id As String
    id = root.Get("id")
    Dim object_string As String
    object_string = root.Get("object")
    Dim created As Long
    created = root.Get("created")
    Dim model As String
    model = root.Get("model")
    Dim usage As Map
    usage = root.Get("usage")
    Dim promptTokens As Int
    promptTokens = usage.Get("prompt_tokens")
    Dim completionTokens As Int
    completionTokens = usage.Get("completion_tokens")
    Dim totalTokens As Int
    totalTokens = usage.Get("total_tokens")
    Dim choices As List
    choices = root.Get("choices")
    Dim choiceIndex As Int
    Dim content As String
    For choiceIndex = 0 To choices.Size - 1
        Dim choice As Map
        choice = choices.Get(choiceIndex)
        Dim message As Map
        message = choice.Get("message")
        Dim role As String
        role = message.Get("role")
        If content <> "" Then content = content & CRLF
        content = content & message.Get("content")
        Dim finishReason As String
        finishReason = choice.Get("finish_reason")
        Log("Choice " & choiceIndex)
        Log("Role: " & role)
        Log("Content: " & content)
        Log("Finish Reason: " & finishReason)
    Next
    Return content
End Sub

You can call it with code like:

B4X:
    Private wrk_chat As ChatGPT
    wrk_chat.Initialize
    Wait For (wrk_chat.Query("Assistant should act like a pirate", "what is the absolute worst investment")) Complete (response As String)
    Log(response)

The really cool bit is using ChatGPT to generate the JSON parsing subroutine.
 
Last edited:

magicmars

Member
Licensed User
thank you for your class
how to add the "assistant" role ( available in api), so that the class can remind about all that what said in the previous message of the same discussion ?
 
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
how to add the "assistant" role ( available in api), so that the class can remind about all that what said in the previous message of the same discussion ?
Just use the first parameter "system_string" - not sure of the content though - you probably need to google - if you find out post the answer in this thread?
 
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
how to add the "assistant" role ( available in api), so that the class can remind about all that what said in the previous message of the same discussion ?

I couldn't get this out of my mind then came up with the idea (actually JohnC's) of asking it:
B4X:
    Private wrk_chat As ChatGPT
    wrk_chat.Initialize
    Wait For (wrk_chat.Query("Assistant should act like a gpt-3.5-turbo tutor", "how to get gpt-3.5-turbo to remember all that was said in a previous discussion")) Complete (response As String)
    Log(response)

response was:
Unfortunately, as an AI language model, I don't have the ability to "remember" previous discussions, as I am not a sentient being with a memory or consciousness. However, I can understand and process the text you present to me and generate responses based on that input. If you would like to refer to a previous discussion or input, you can provide me with the necessary context to help me understand what you are referring to. Additionally, if you have previously saved or recorded the previous discussion, you can refer to it as a reference when necessary.

Cheers...
 
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
I can't check right this second, but I think there's an ID parameter you can keep passing to "link" subsequent queries.
I would be real interested in knowing this - please post to this thread if you get an answer.
 
Upvote 0

Jeffrey Cameron

Well-Known Member
Licensed User
Longtime User
I may have been looking at a .NET library and not the actual API. For the actual API it looks like you need to build and track the conversation yourself:
 
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
I may have been looking at a .NET library and not the actual API. For the actual API it looks like you need to build and track the conversation yourself:
I think this is basically what it told me at post #4 - spooky :cool::cool::cool:
 
Upvote 0

magicmars

Member
Licensed User
This python code is an example of a successfully reminding of the past messages in the same discussion. :

fisrt install open Ai module in python:

Bash:
python -m pip install openai


then create testgpt.py :

ChatGpt Python test:
messages = [
    {"role": "system", "content": "You're a recruiter who asks interview questions. You ask one new question after my response"}
]
import os
import openai
openai.api_key = "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # OpenAI API key

while True:
    content = input("User: ")
    messages.append({"role": "user", "content": content})

    completion = openai.ChatCompletion.create(
      model="gpt-3.5-turbo",
      messages=messages
    )

    chat_response = completion.choices[0].message.content
    print(f'ChatGPT: {chat_response}')
    messages.append({"role": "assistant", "content": chat_response})



Output :


C:\Users\xxx\Desktop\dgrpython>python -m testgpt.py

User: Hi. My name is Johnny.
ChatGPT: Hi Johnny, it's nice to meet you. Can you tell me a little bit about your previous work experience?
User: Whats is my name ?
ChatGPT: Your name is Johnny.

with this line come the magic :

messages.append({"role": "assistant", "content": chat_response}))

It add / append to the "assistant role" all the previous message of the discussion, at every new answer.


[{"role": "system", "content": "You're a recruiter who asks interview questions. You ask one new question after my response"},
{"role": "user", "content": user_query},
{"role": "assistant", "content": all_last_conversation_message}]


Indedd , as mentionned in the doc :

Typically, a conversation is formatted with a system message first, followed by alternating user and assistant messages :

- The system message helps set the behavior of the assistant. In the example above, the assistant was instructed with "You are a helpful assistant."

- The user messages help instruct the assistant. They can be generated by the end users of an application, or set by a developer as an instruction.

- The assistant messages help store prior responses. They can also be written by a developer to help give examples of desired behavior.

Including the conversation history helps when user instructions refer to prior messages. In the example above, the user’s final question of "Where was it played?" only makes sense in the context of the prior messages about the World Series of 2020. Because the models have no memory of past requests, all relevant information must be supplied via the conversation. If a conversation cannot fit within the model’s token limit, it will need to be shortened in some way.
 
Last edited:
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
example of a successfully reminding of the past messages in the same discussion
That looks quite straightforward - could build up the token count, and therefore cost, at a fast clip though.
 
Upvote 0

magicmars

Member
Licensed User
I edit your query function, to add history automatically (context) as assistant :


B4X:
Public Sub Query(system_string As String, query_string As String, assistant_string As String ) As ResumableSub
    Try
        ' Create messages list
        Dim messages As List
        messages.Initialize
        messages.Add(CreateMap("role" : "system", "content" : system_string))
        messages.Add(CreateMap("role" : "user", "content" : query_string))
        messages.Add(CreateMap("role" : "assistant", "content" : assistant_string))
    
    
        ' Generate JSON string from messages list
        Dim JSONGenerator As JSONGenerator
        JSONGenerator.Initialize2(messages)
        Dim chat_string As String
        chat_string = $"{"model":"gpt-3.5-turbo","messages":${JSONGenerator.ToString}}"$
    
        'Uncomment this line if you want to see raw input string
        'Log(chat_string)
        ....

then
in main page:


B4X:
Sub Class_Globals
    Private wrk_chat As ChatGPT
    Private history As String
End Sub

Public Sub Initialize
    wrk_chat.Initialize
    ' Let the next line be exactly ike this:
    history = "dynamic history of your reply to this chat: "
End Sub

to call it:


B4X:
dim usersay as string
usersay = EditText1.text

Wait For (wrk_chat.Query("you are a recruitment agent",usersay, history)) Complete (response As String)
    Log(response)
    history = history & response
 
Last edited:
Upvote 0

magicmars

Member
Licensed User
can be even like :

B4X:
history = "dynamic history of my and your reply in the chat: "


B4X:
history = history & "me: "&usersay
    history = history & "you: "&response

It have now full memory ! 🥳
it will cost some tokens, but not a lot for a personnal assistant app.
as the limit is 4096 tokens, maybe it will need a function to sum up all conversation , arriving at 3500 tokens. ... and then reset.
that way is will be never memory limit (but will forget some details)
 
Last edited:
Upvote 0

Soheyl

Member
Licensed User
Longtime User
EDITED: Solved
There is 2 different endpoint:

For this thread, We have to use the second one (v1/chat/completions)
OpenAI API Endpoint:
https://api.openai.com/v1/completions
https://api.openai.com/v1/chat/completions


Question:
Thanks but not working, I got:

Generated JSon:
{
    "model": "gpt-3.5-turbo",
    "n": 1,
    "stop": "None",
    "max_tokens": 2048,
    "temperature": 0.5,
    "stream": true,
    "role": [
        { "role": "system", "content": "You are a helpful assistant." },
        { "role": "user", "content": "my name is Soheyl" },
        {
            "role": "assistant",
            "content": "dynamic history of my and your reply in the chat: "
        }
    ]
}

and its response:

Result:
ResponseError. Reason: , Response: {
  "error": {
    "message": "Unrecognized request argument supplied: messages",
    "type": "invalid_request_error",
    "param": null,
    "code": null
  }

}
 
Last edited:
Upvote 0
Top