MaxSSD / OpenAI-GUI

Graphical user interface (GUI) for interacting with various OpenAI models. With this GUI, you can easily run various language and machine learning models, such as GPT-3 and DALL-E, without needing to use the command line.
MIT License
31 stars 8 forks source link

To save the theme........ #5

Open PySimpleGUI opened 1 year ago

PySimpleGUI commented 1 year ago

If you want to make the theme be saved and restored so that the last chosen theme will be used the next time, then you need to change 1 line of code and add 1 line.

First, change the call to sg.theme to be like this one when you startup the program:

if __name__ == '__main__':
    sg.theme(sg.user_settings_get_entry('-theme-', 'dark green 7'))
    main()

And add this line of code above your popup:

            sg.user_settings_set_entry('-theme-', theme_chosen)
            sg.popup(f"Chosen Theme: {str(theme_chosen)}", keep_on_top=True)
MaxSSD commented 1 year ago

I just pushed commit to test branch because it doesnt quite work, It somehow is better to call sg.theme in the window from what I tried.

Also I had an idea to add image creation based on an uploaded image. and I'm having trouble integrating the history of file dialog like in this example. Or would it be better to go with the tk way of creating Browse filedialog function?

Preview: Capture8

PySimpleGUI commented 1 year ago

I use that technique very frequently, like the in Demo Browser.

I also removed the timeout on your read as it was taking up CPU time needlessly.

And added a copy to clipboard at the end of tyhoue openAi function so didn't need to do anything but a paste.

    sg.clipboard_set(result)

Oh and I clear the output every time an answer is requested.

        if event == 'Answer':
            prompt_in = values['prompt'].rstrip()
            window['prompt'].update(prompt_in)
            window['-OUTPUT-'].update('')
            openAi(prompt_in, engines, max_tokens)

Feel free to open an issue on GitHub and we'll give you a hand with filebrowse.

PySimpleGUI commented 1 year ago

Setting a minimum size for the window keeps those buttons at the bottom from getting cutoff:

    window = sg.Window('OpenAI GUI', layout, resizable=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT, icon=icon, finalize=True)
    window.set_min_size(window.size)
PySimpleGUI commented 1 year ago

Maybe it's easier to do a diff. I don't want to push anything. I'm just messing around....

import logging
import PySimpleGUI as sg
import openai
import os
import sys
import requests
import urllib.request
from PIL import Image
from io import BytesIO
from api_key import key
import webbrowser

# @https://beta.openai.com/docs/engines/gpt-3

logger = logging.getLogger()
logging.basicConfig(filename='answers.txt', level=logging.INFO)

max_tokens_list = (256, 2000, 8000)
models = ("text-davinci-003", "text-davinci-002", "text-curie-001", "text-babbage-001", "text-ada-001")
icon = b'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'

# Defines the modules() and openAi() functions which are used to select the engine and generate a response.
def modules(engines):
    return engines if engines in models else None

def select_max_tokens(max_tokens):
    return max_tokens if max_tokens in max_tokens_list else None

def picture_size(size):
    sizing = None
    if size == "256x256":
        sizing = "256x256"
    elif size == "512x512":
        sizing = "512x512"
    elif size == "1024x1024":
        sizing = "1024x1024"
    return sizing

def openAi(prompt_in, engines, max_tokens):
    sg.popup_quick_message('Responding...')
    max_tokens = select_max_tokens(256)
    completion = openai.Completion.create(engine=modules(engines), prompt=prompt_in, temperature=0, max_tokens=select_max_tokens(max_tokens), top_p=1.0)
    result = completion.choices[0].text
    if len(result) < 150:
        print(result)
        logger.info(result)
    else:
        sg.popup_quick_message('Responding to answers.txt')
        print(result)
        with open('answers.txt', 'a+') as f:
            f.write(result)
    sg.clipboard_set(result)

def dalle(prompt_ins, size):
    response = openai.Image.create(
        prompt=prompt_ins,
        n=1,
        size=picture_size(size)
    )
    image_url = response['data'][0]['url']
    webUrl = urllib.request.urlopen(image_url)
    img = Image.open(webUrl)
    sg.Popup('Displaying and saving image...', keep_on_top=True)
    file_name = os.path.basename(prompt_ins)[:255] + '.png'
    img.show()
    img.save(file_name)

def make_window(theme):
    sg.theme(theme)
    max_tokens = select_max_tokens(256)
    # GUI layout.
    layout = [
        [sg.Text("OpenAIGUI",  expand_x=True, justification="center", font=("Helvetica", 13), relief=sg.RELIEF_RIDGE)],
        [sg.TabGroup([[
            sg.Tab("OpenAi", [
                [sg.Radio("Choose model", "RADIO1", default=True, key="modules"), sg.Combo(models, default_value=models[0], key="engines", readonly=True)],
                [sg.Radio("Choose max token", "RADIO1", key="select_max_tokens"), sg.Combo(max_tokens_list, key="max_tokens")],
                [sg.Text("Enter your question or statement below:",
                         font=('_ 14'))],
                [sg.Pane([sg.Column([[sg.Multiline(key="prompt", size=(77, 20), expand_x=True, expand_y=True, enter_submits=True, focus=True, font='Courier 12')]]),
                sg.Column([[sg.Multiline(size=(60, 15), font="Courier 12", expand_x=True, expand_y=True, write_only=True, reroute_stdout=True, reroute_stderr=True, echo_stdout_stderr=True, autoscroll=True, auto_refresh=True, key='-OUTPUT-')]])], expand_x=True, expand_y=True)],
                [sg.Button("Answer", bind_return_key=True), sg.Button('Open file'), sg.Button("Clear"), sg.Button("Quit")]]),
            sg.Tab("Dall-E", [
                    [sg.Text("Suggest impression:", font=("Arial", 9, 'bold'))],
                    [sg.Radio("Choose picture size", "RADIO1", key="picture_size"), sg.Combo(
                        ["256x256", "512x512", "1024x1024"], key="size")],
                    [sg.Multiline(key="promptdalle", size=(77, 20), expand_x=True, expand_y=True)],
                    [sg.Button("Create image"), sg.Button("Clear"), sg.Button("Quit")]]),
            sg.Tab("Theme", [
                    [sg.Text("Choose theme:")],
                    [sg.Listbox(values=sg.theme_list(), size=(20, 12), key="-THEME LISTBOX-", enable_events=True)],
                    [sg.Button("Set Theme")]]),
            sg.Tab("About", [
                    [sg.Text(
                        "text-davinci-003 - Upgraded davinci-002. GPT3 chatbot model.")],
                    [sg.Text(
                        "text-davinci-002 - Code review, complex intent, cause and effect, summarization for audience")],
                    [sg.Text(
                        "code-davinci-edit-001 - Edit endpoint is particularly useful for editing code.")],
                    [sg.Text(
                        "text-curie-001 - Language translation, complex classification, text sentiment, summarization")],
                    [sg.Text(
                        "text-babbage-001 - Moderate classification, semantic search classification")],
                    [sg.Text(
                        "text-ada-001 - Parsing text, simple classification, address correction, keywords")]])]], key="-TAB GROUP-", expand_x=True, expand_y=True),
         sg.Sizegrip()]]
    # Gui window and layout sizing.
    window = sg.Window('OpenAI GUI', layout, resizable=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT, icon=icon, finalize=True)
    window.set_min_size(window.size)
    return window

# GUI window that runs the main() function to interact with the user.
def main():
    window = make_window(sg.theme())
    # Event loop.
    while True:
        event, values = window.read(timeout=None)
        if event == sg.WINDOW_CLOSED or event == 'Quit' or event == 'Exit':
            break
        max_tokens = select_max_tokens(377)
        if values is not None:
            engines = values['engines'] if values['engines'] == 'Choose model' else values['engines']
        if values is not None:
            max_tokens = values['max_tokens'] if values['max_tokens'] == 'Choose max token' else values['max_tokens']
        if values is not None:
            size = values['size'] if values['size'] == 'Choose picture size' else values['size']
        if event == 'Answer':
            prompt_in = values['prompt'].rstrip()
            window['prompt'].update(prompt_in)
            window['-OUTPUT-'].update('')
            openAi(prompt_in, engines, max_tokens)
        elif event == 'Create image':
            prompt_ins = values['promptdalle']
            dalle(prompt_ins, size)
        elif event == 'Open file':
            os.startfile('answers.txt', 'open')
        elif event == 'Clear':
            window['prompt'].update('')
        elif event == "Set Theme":
            theme_chosen = values['-THEME LISTBOX-'][0]
            window.close()
            window = make_window(theme_chosen)
            sg.user_settings_set_entry('-theme-', theme_chosen)
            sg.popup(f"Chosen Theme: {str(theme_chosen)}", keep_on_top=True)

        if event == 'Edit Me':
            sg.execute_editor(__file__)
        elif event == 'Version':
            sg.popup_scrolled(__file__, sg.get_versions(), location=window.current_location(), keep_on_top=True, non_blocking=True)

    window.close()
    sys.exit(0)

if __name__ == '__main__':
    sg.theme(sg.user_settings_get_entry('-theme-', 'dark green 7'))
    main()
PySimpleGUI commented 1 year ago

BTW, I learned something from your code, of course....

I wasn't aware of this awesome os call. Thank you for introducing me to something new that I'm SURE I'll be using. I may extend the PySimpleGUI Exec APIs by including a call that's similar.

os.startfile('answers.txt', 'open')
MaxSSD commented 1 year ago

I just pushed a bit edited version of the code you suggested, works fine and indeed takes less cpu %.

Added an sg.Slider for the tokens choice and value error handling.

Preview: image

MaxSSD commented 1 year ago

BTW, I learned something from your code, of course....

I wasn't aware of this awesome os call. Thank you for introducing me to something new that I'm SURE I'll be using. I may extend the PySimpleGUI Exec APIs by including a call that's similar.

os.startfile('answers.txt', 'open')

That's really cool mate, I did not look at what calls you are using but I hope it'll make the library faster 🤙