From 37862186c1b7f68df4b178dc927a41475860f280 Mon Sep 17 00:00:00 2001 From: Abhishek Masand Date: Tue, 26 Jul 2022 22:11:44 +0530 Subject: [PATCH 1/5] Refactored to use prompt engine --- contexts/bash-context.txt | 45 --- contexts/bash-context.yaml | 39 +++ contexts/powershell-context.txt | 41 --- contexts/powershell-context.yaml | 39 +++ .../powershell-voice-cognitive-service.txt | 64 ----- .../powershell-voice-cognitive-service.yaml | 71 +++++ contexts/powershell-voice.txt | 39 --- contexts/powershell-voice.yaml | 35 +++ contexts/zsh-context.txt | 45 --- contexts/zsh-context.yaml | 39 +++ src/codex_query.py | 98 +++---- src/commands.py | 165 +++++------ src/prompt_file.py | 269 +++++------------- 13 files changed, 412 insertions(+), 577 deletions(-) delete mode 100644 contexts/bash-context.txt create mode 100644 contexts/bash-context.yaml delete mode 100644 contexts/powershell-context.txt create mode 100644 contexts/powershell-context.yaml delete mode 100644 contexts/powershell-voice-cognitive-service.txt create mode 100644 contexts/powershell-voice-cognitive-service.yaml delete mode 100644 contexts/powershell-voice.txt create mode 100644 contexts/powershell-voice.yaml delete mode 100644 contexts/zsh-context.txt create mode 100644 contexts/zsh-context.yaml diff --git a/contexts/bash-context.txt b/contexts/bash-context.txt deleted file mode 100644 index 1e83029..0000000 --- a/contexts/bash-context.txt +++ /dev/null @@ -1,45 +0,0 @@ -## engine: code-cushman-001 -## temperature: 0 -## max_tokens: 300 -## shell: bash -## multi_turn: off -## token_count: 110 - -# what processes are hogging the most cpu? -ps aux | sort -nrk 3,3 | head -n 10 - -# stop the chrome processes -kill -9 $(ps aux | grep chrome | awk '{print $2}') - -# what's my IP? -curl ifconfig.me - -# what's the weather in San Francisco? -curl wttr.in/SanFrancisco - -# make a directory called web-app -mkdir web-app - -# add an html, css, and js file to it -touch web-app/index.html -touch web-app/style.css -touch web-app/script.js - -# add a hello world website to the index -echo '

Hello World!

' > web-app/index.html - -# open it with vi -vi web-app/index.html - -# what's running on port 1018? -lsof -i :1018 - -# kill process 1584 -kill -9 1584 - -# what other devices are on my network? -arp -a - -# how much storage is left? -df -h - diff --git a/contexts/bash-context.yaml b/contexts/bash-context.yaml new file mode 100644 index 0000000..ee2587c --- /dev/null +++ b/contexts/bash-context.yaml @@ -0,0 +1,39 @@ +type: code-engine +config: + model-config: + engine: "code-cushman-001" + temperature: 0 + max_tokens: 300 + shell: "bash" + multi_turn: "off" + token_count: 110 +description: "This converts Natural Language Commands to Command Line Commands. Here are some examples" +examples: + - input: "what processes are hogging the most cpu?" + response: "ps aux | sort -nrk 3,3 | head -n 10" + - input: "stop the chrome processes" + response: "kill -9 $(ps aux | grep chrome | awk '{print $2}')" + - input: "what's my IP?" + response: "curl ifconfig.me" + - input: "what's the weather in San Francisco?" + response: "curl wttr.in/SanFrancisco" + - input: "make a directory called web-app" + response: "mkdir web-app" + - input: "add an html, css, and js file to it" + response: | + "touch web-app/index.html + touch web-app/style.css + touch web-app/script.js" + - input: "add a hello world website to the index" + response: "echo '

Hello World!

' > web-app/index.html" + - input: "open it with vi" + response: "vi web-app/index.html" + - input: "what's running on port 1018?" + response: "lsof -i :1018" + - input: "kill process 1584" + response: "kill -9 1584" + - input: "what other devices are on my network?" + response: "arp -a" + - input: "how much storage is left?" + response: "df -h" +flow-reset-text: "Ignore the previous examples and start afresh, from here on out, this is an unrelated conversation" diff --git a/contexts/powershell-context.txt b/contexts/powershell-context.txt deleted file mode 100644 index aa02f43..0000000 --- a/contexts/powershell-context.txt +++ /dev/null @@ -1,41 +0,0 @@ -## engine: code-cushman-001 -## temperature: 0 -## max_tokens: 300 -## shell: powershell -## multi_turn: off -## token_count: 110 - -# what processes are hogging the most cpu? -Get-Process | Sort-Object -Property CPU -Descending | Select-Object -First 10 - -# stop the chrome processes -Get-Process chrome | Stop-Process - -# what's my IP address? -(Invoke-WebRequest -uri "http://ifconfig.me/ip").Content - -# what's the weather in New York? -(Invoke-WebRequest -uri "wttr.in/NewYork").Content - -# make a git ignore with node modules and src in it -"node_modules -src" | Out-File .gitignore - -# open it in notepad -notepad .gitignore - -# what's running on port 1018? -Get-Process -Id (Get-NetTCPConnection -LocalPort 1018).OwningProcess - -# kill process 1584 -Stop-Process -Id 1584 - -# what other devices are on my network? -Get-NetIPAddress | Format-Table - -# how much storage is left on my pc? -Get-WmiObject -Class Win32_LogicalDisk | Select-Object -Property DeviceID,FreeSpace,Size,DriveType | Format-Table -AutoSize - -# how many GB is 367247884288 B? -(367247884288 / 1GB) - diff --git a/contexts/powershell-context.yaml b/contexts/powershell-context.yaml new file mode 100644 index 0000000..9865e91 --- /dev/null +++ b/contexts/powershell-context.yaml @@ -0,0 +1,39 @@ +type: code-engine +config: + model-config: + engine: "code-cushman-001" + temperature: 0 + max_tokens: 300 + shell: "powershell" + multi_turn: "off" + token_count: 110 +description: "This converts Natural Language Commands to Command Line Commands. Here are some examples" +examples: + - input: "what processes are hogging the most cpu?" + response: "Get-Process | Sort-Object -Property CPU -Descending | Select-Object -First 10" + - input: "stop the chrome processes" + response: "Get-Process chrome | Stop-Process" + - input: "what's my IP address?" + response: '(Invoke-WebRequest -uri "http://ifconfig.me/ip").Content"' + - input: "what's the weather in New York?" + response: '(Invoke-WebRequest -uri "wttr.in/NewYork").Content' + - input: "make a git ignore with node modules and src in it" + response: | + "node_modules" + src" | Out-File .gitignore + - input: "open it in notepad" + response: "notepad .gitignore" + - input: "what's running on port 1018?" + response: "Get-Process -Id (Get-NetTCPConnection -LocalPort 1018).OwningProcess" + - input: "kill process 1584" + response: "Stop-Process -Id 1584" + - input: "what other devices are on my network?" + response: "Get-NetIPAddress | Format-Table" + - input: "how much storage is left on my pc?" + response: "Get-WmiObject -Class Win32_LogicalDisk | Select-Object -Property DeviceID,FreeSpace,Size,DriveType | Format-Table -AutoSize" + - input: "how many GB is 367247884288 B?" + response: "(367247884288 / 1GB)" +flow-reset-text: "Ignore the previous examples and start afresh, from here on out, this is an unrelated conversation" + + + diff --git a/contexts/powershell-voice-cognitive-service.txt b/contexts/powershell-voice-cognitive-service.txt deleted file mode 100644 index 6204b4c..0000000 --- a/contexts/powershell-voice-cognitive-service.txt +++ /dev/null @@ -1,64 +0,0 @@ -## engine: code-cushman-001 -## temperature: 0 -## max_tokens: 300 -## shell: powershell -## multi_turn: on -## token_count: 110 - -# what processes are hogging the most cpu? -Get-Process | Sort-Object -Property CPU -Descending | Select-Object -First 10 -spx synthesize --text ("Here are the top 10 processes by memory used") --speakers --quiet - -# stop the chrome processes -Get-Process chrome | Stop-Process -spx synthesize --text ("I stopped chrome") --speakers --quiet - -# make a readme with a project header and two sections -"# Project Header -## Section 1 -## Section 2" | Out-File "./readme.md" -spx synthesize --text ("I created your readme!") --speakers --quiet - -# what's running on port 3000? -Get-Process -Id (Get-NetTCPConnection -LocalPort 3000).OwningProcess -spx synthesize --text ("I found the process running on port 3000") --speakers --quiet - -# kill process 1584 -Stop-Process -Id 1584 -spx synthesize --text ("I killed the process with ID 1584") --speakers --quiet - -# what other devices are on my network? -Get-NetIPAddress | Format-Table -spx synthesize --text ("Here are the IP addresses on your network") --speakers --quiet - -# how much storage is left on my pc? -Get-WmiObject -Class Win32_LogicalDisk | Select-Object -Property DeviceID,FreeSpace,Size,DriveType | Format-Table -AutoSize -spx synthesize --text ("Here is the amount of storage left on your computer") --speakers --quiet - -# how many GB is 367247884288 B? -spx synthesize --text ("367247884288 B is " + (367247884288 / 1073741824) + " GB") --speakers --quiet - -# where do you live? -spx synthesize --text ("I live in " + $HOME) --speakers --quiet - -# what's my IP address? -$ip = (Invoke-WebRequest -Uri http://ifconfig.me/ip).Content -spx synthesize --text ("Your IP address is " + $ip) --speakers --quiet - -# tell me a joke -spx synthesize --text ("What do dog robots do? They byte!") --speakers --quiet - -# You: How do I combine arrays? -spx synthesize --text ("Bot: You can use the concat() method") --speakers --quiet - -# tell me a joke -spx synthesize --text ("Why do programmers always mix up Halloween and Christmas? Because Oct 31 = Dec 25") --speakers --quiet - -# tell me a joke -spx synthesize --text ("The best method for accelerating a computer is the one that boosts it by 9.8 m/s^2") --speakers --quiet - -# what's the meaning of life? -spx synthesize --text ("The meaning of life is 42") --speakers --quiet - -# where are you located -spx synthesize --text ("I live in " + $HOME) --speakers --quiet diff --git a/contexts/powershell-voice-cognitive-service.yaml b/contexts/powershell-voice-cognitive-service.yaml new file mode 100644 index 0000000..3f91f49 --- /dev/null +++ b/contexts/powershell-voice-cognitive-service.yaml @@ -0,0 +1,71 @@ +type: code-engine +config: + model-config: + engine: "code-cushman-001" + temperature: 0 + max_tokens: 300 + shell: "powershell" + multi_turn: "off" + token_count: 110 +description: "This converts Natural Language Commands to Command Line Commands. Here are some examples" +examples: + - input: "what processes are hogging the most cpu?" + response: | + Get-Process | Sort-Object -Property CPU -Descending | Select-Object -First 10 + spx synthesize --text ("Here are the top 10 processes by memory used") --speakers --quiet + + - input: "stop the chrome processes" + response: | + Get-Process chrome | Stop-Process + spx synthesize --text ("I stopped chrome") --speakers --quiet + + - input: "what's running on port 3000?" + response: | + Get-Process -Id (Get-NetTCPConnection -LocalPort 3000).OwningProcess + spx synthesize --text ("I found the process running on port 3000") --speakers --quiet + + - input: "kill process 1584" + response: | + Stop-Process -Id 1584 + spx synthesize --text ("I killed the process with ID 1584") --speakers --quiet + + - input: "what other devices are on my network?" + response: | + Get-NetIPAddress | Format-Table + spx synthesize --text ("Here are the IP addresses on your network") --speakers --quiet + + - input: "how much storage is left on my pc?" + response: | + Get-WmiObject -Class Win32_LogicalDisk | Select-Object -Property DeviceID,FreeSpace,Size,DriveType | Format-Table -AutoSize + spx synthesize --text ("Here is the amount of storage left on your computer") --speakers --quiet + + - input: "how many GB is 367247884288 B?" + response: | + spx synthesize --text ("367247884288 B is " + (367247884288 / 1073741824) + " GB") --speakers --quiet + - input: "where do you live?" + response: | + spx synthesize --text ("I live in " + $HOME) --speakers --quiet + - input: "what's my IP address?" + response: | + $ip = (Invoke-WebRequest -Uri http://ifconfig.me/ip).Content + spx synthesize --text ("Your IP address is " + $ip) --speakers --quiet + + - input: "tell me a joke" + response: | + spx synthesize --text ("What do dog robots do? They byte!") --speakers --quiet + - input: "You: How do I combine arrays?" + response: | + spx synthesize --text ("Bot: You can use the concat() method") --speakers --quiet + - input: "tell me a joke" + response: | + spx synthesize --text ("Why do programmers always mix up Halloween and Christmas? Because Oct 31 = Dec 25") --speakers --quiet + - input: "tell me a joke" + response: | + spx synthesize --text ("The best method for accelerating a computer is the one that boosts it by 9.8 m/s^2") --speakers --quiet + - input: "what's the meaning of life?" + response: | + spx synthesize --text ("The meaning of life is 42") --speakers --quiet + - input: "where are you located" + response: | + spx synthesize --text ("I live in " + $HOME) --speakers --quiet +flow-reset-text: "Ignore the previous examples and start afresh, from here on out, this is an unrelated conversation" \ No newline at end of file diff --git a/contexts/powershell-voice.txt b/contexts/powershell-voice.txt deleted file mode 100644 index dccd84b..0000000 --- a/contexts/powershell-voice.txt +++ /dev/null @@ -1,39 +0,0 @@ -## engine: code-cushman-001 -## temperature: 0 -## max_tokens: 300 -## shell: powershell -## multi_turn: on -## token_count: 110 - -# what processes are hogging the most cpu? -Get-Process | Sort-Object -Property CPU -Descending | Select-Object -First 10 - -# stop the chrome processes -Get-Process chrome | Stop-Process - -# make a readme with a project header and two sections -"# Project Header -## Section 1 -## Section 2" | Out-File "./readme2.md" - -# what's running on port 3000? -Get-Process -Id (Get-NetTCPConnection -LocalPort 3000).OwningProcess - -# kill process 1584 -Stop-Process -Id 1584 - -# what other devices are on my network? -Get-NetIPAddress | Format-Table - -# how much storage is left on my pc? -Get-WmiObject -Class Win32_LogicalDisk | Select-Object -Property DeviceID,FreeSpace,Size,DriveType | Format-Table -AutoSize - -# how many GB is 367247884288 B? -(367247884288 / 1GB) - -# what's the meaning of life? -(new-object -ComObject SAPI.SPVoice).Speak("The meaning of life is 42") - -# where are you located -(new-object -ComObject SAPI.SPVoice).Speak("I live in " + $HOME) - diff --git a/contexts/powershell-voice.yaml b/contexts/powershell-voice.yaml new file mode 100644 index 0000000..02f8aa4 --- /dev/null +++ b/contexts/powershell-voice.yaml @@ -0,0 +1,35 @@ +type: code-engine +config: + model-config: + engine: "code-cushman-001" + temperature: 0 + max_tokens: 300 + shell: "powershell" + multi_turn: "off" + token_count: 110 +description: "This converts Natural Language Commands to Command Line Commands. Here are some examples" +examples: + - input: "what processes are hogging the most cpu?" + response: "Get-Process | Sort-Object -Property CPU -Descending | Select-Object -First 10" + - input: "stop the chrome processes" + response: "Get-Process chrome | Stop-Process" + - input: "make a readme with a project header and two sections" + response: | + # Project Header + ## Section 1 + ## Section 2" | Out-File "./readme2.md" + - input: "what's running on port 3000?" + response: "Get-Process -Id (Get-NetTCPConnection -LocalPort 3000).OwningProcess" + - input: "kill process 1584" + response: "Stop-Process -Id 1584" + - input: "what other devices are on my network?" + response: "Get-NetIPAddress | Format-Table" + - input: "how much storage is left on my pc?" + response: "Get-WmiObject -Class Win32_LogicalDisk | Select-Object -Property DeviceID,FreeSpace,Size,DriveType | Format-Table -AutoSize" + - input: "how many GB is 367247884288 B?" + response: "(367247884288 / 1GB)" + - input: "what's the meaning of life?" + response: '(new-object -ComObject SAPI.SPVoice).Speak("The meaning of life is 42")' + - input: "where are you located" + response: '(new-object -ComObject SAPI.SPVoice).Speak("I live in " + $HOME)' +flow-reset-text: "Ignore the previous examples and start afresh, from here on out, this is an unrelated conversation" diff --git a/contexts/zsh-context.txt b/contexts/zsh-context.txt deleted file mode 100644 index 6128e8a..0000000 --- a/contexts/zsh-context.txt +++ /dev/null @@ -1,45 +0,0 @@ -## engine: code-cushman-001 -## temperature: 0 -## max_tokens: 300 -## shell: zsh -## multi_turn: off -## token_count: 110 - -# what processes are hogging the most cpu? -ps aux | sort -nrk 3,3 | head -n 10 - -# stop the chrome processes -kill -9 $(ps aux | grep chrome | awk '{print $2}') - -# what's my IP? -curl ifconfig.me - -# what's the weather in San Francisco? -curl wttr.in/SanFrancisco - -# make a directory called web-app -mkdir web-app - -# add an html, css, and js file to it -touch web-app/index.html -touch web-app/style.css -touch web-app/script.js - -# add a hello world website to the index -echo '

Hello World!

' > web-app/index.html - -# open it with vi -vi web-app/index.html - -# what's running on port 1018? -lsof -i :1018 - -# kill process 1584 -kill -9 1584 - -# what other devices are on my network? -arp -a - -# how much storage is left? -df -h - diff --git a/contexts/zsh-context.yaml b/contexts/zsh-context.yaml new file mode 100644 index 0000000..ad86af3 --- /dev/null +++ b/contexts/zsh-context.yaml @@ -0,0 +1,39 @@ +type: code-engine +config: + model-config: + engine: "code-cushman-001" + temperature: 0 + max_tokens: 300 + shell: "zsh" + multi_turn: "off" + token_count: 110 +description: "This converts Natural Language Commands to Command Line Commands. Here are some examples" +examples: + - input: "what processes are hogging the most cpu?" + response: "ps aux | sort -nrk 3,3 | head -n 10" + - input: "stop the chrome processes" + response: "kill -9 $(ps aux | grep chrome | awk '{print $2}')" + - input: "what's my IP?" + response: "curl ifconfig.me" + - input: "what's the weather in San Francisco?" + response: "curl wttr.in/SanFrancisco" + - input: "make a directory called web-app" + response: "mkdir web-app" + - input: "add an html, css, and js file to it" + response: | + touch web-app/index.html + touch web-app/style.css + touch web-app/script.js + - input: "add a hello world website to the index" + response: "echo '

Hello World!

' > web-app/index.html" + - input: "open it with vi" + response: "vi web-app/index.html" + - input: "what's running on port 1018?" + response: "lsof -i :1018" + - input: "kill process 1584" + response: "kill -9 1584" + - input: "what other devices are on my network?" + response: "arp -a" + - input: "how much storage is left?" + response: "df -h" +flow-reset-text: "Ignore the previous examples and start afresh, from here on out, this is an unrelated conversation" diff --git a/src/codex_query.py b/src/codex_query.py index ade2a9a..a7f4a14 100755 --- a/src/codex_query.py +++ b/src/codex_query.py @@ -9,7 +9,7 @@ import psutil from pathlib import Path -from prompt_file import PromptFile +from prompt_file import ModelConfig, Prompt from commands import get_command_result MULTI_TURN = "off" @@ -24,9 +24,6 @@ # api keys located in the same directory as this file API_KEYS_LOCATION = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'openaiapirc') -PROMPT_CONTEXT = Path(__file__).with_name('current_context.txt') - - # Read the secret_key from the ini file ~/.config/openaiapirc # The format is: # [openai] @@ -46,11 +43,10 @@ def create_template_ini_file(): print('# engine=') sys.exit(1) -def initialize(): +def initialize(shell: str): """ Initialize openAI and shell mode """ - global ENGINE # Check if file at API_KEYS_LOCATION exists create_template_ini_file() @@ -59,18 +55,9 @@ def initialize(): openai.api_key = config['openai']['secret_key'].strip('"').strip("'") openai.organization = config['openai']['organization_id'].strip('"').strip("'") - ENGINE = config['openai']['engine'].strip('"').strip("'") - - prompt_config = { - 'engine': ENGINE, - 'temperature': TEMPERATURE, - 'max_tokens': MAX_TOKENS, - 'shell': SHELL, - 'multi_turn': MULTI_TURN, - 'token_count': 0 - } + engine = config['openai']['engine'].strip('"').strip("'") - return PromptFile(PROMPT_CONTEXT.name, prompt_config) + return Prompt(shell, engine) def is_sensitive_content(content): """ @@ -130,7 +117,7 @@ def is_sensitive_content(content): return (output_label != "0") -def get_query(prompt_file): +def get_query(prompt_generator): """ uses the stdin to get user input input is either treated as a command or as a Codex query @@ -144,64 +131,58 @@ def get_query(prompt_file): else: entry = sys.stdin.read() # first we check if the input is a command - command_result, prompt_file = get_command_result(entry, prompt_file) + try: + command_result, prompt_generator = get_command_result(entry, prompt_generator) + except Exception as e: + print (str(e)) # if input is not a command, then query Codex, otherwise exit command has been run successfully if command_result == "": - return entry, prompt_file + return entry, prompt_generator else: sys.exit(0) -def detect_shell(): - global SHELL - global PROMPT_CONTEXT +def get_shell_prefix(shell: str): + # prime codex for the corresponding shell type + if shell == "zsh": + return '#!/bin/zsh\n\n' + elif shell == "bash": + return '#!/bin/bash\n\n' + elif shell == "powershell": + return '<# powershell #>\n\n' + elif shell == "unknown": + print("\n#\tUnsupported shell type, please use # set shell ") + return "" + else: + return '#' + shell + '\n\n' + +def detect_shell(): parent_process_name = psutil.Process(os.getppid()).name() POWERSHELL_MODE = bool(re.fullmatch('pwsh|pwsh.exe|powershell.exe', parent_process_name)) BASH_MODE = bool(re.fullmatch('bash|bash.exe', parent_process_name)) ZSH_MODE = bool(re.fullmatch('zsh|zsh.exe', parent_process_name)) - SHELL = "powershell" if POWERSHELL_MODE else "bash" if BASH_MODE else "zsh" if ZSH_MODE else "unknown" + shell = "powershell" if POWERSHELL_MODE else "bash" if BASH_MODE else "zsh" if ZSH_MODE else "unknown" - shell_prompt_file = Path(os.path.join(os.path.dirname(__file__), "..", "contexts", "{}-context.txt".format(SHELL))) + prefix = get_shell_prefix(shell) - if shell_prompt_file.is_file(): - PROMPT_CONTEXT = shell_prompt_file + return shell, prefix if __name__ == '__main__': - detect_shell() - prompt_file = initialize() + shell, prefix = detect_shell() + prompt_generator: Prompt = initialize(shell) try: - user_query, prompt_file = get_query(prompt_file) - - config = prompt_file.config if prompt_file else { - 'engine': ENGINE, - 'temperature': TEMPERATURE, - 'max_tokens': MAX_TOKENS, - 'shell': SHELL, - 'multi_turn': MULTI_TURN, - 'token_count': 0 - } - - # use query prefix to prime Codex for correct scripting language - prefix = "" - # prime codex for the corresponding shell type - if config['shell'] == "zsh": - prefix = '#!/bin/zsh\n\n' - elif config['shell'] == "bash": - prefix = '#!/bin/bash\n\n' - elif config['shell'] == "powershell": - prefix = '<# powershell #>\n\n' - elif config['shell'] == "unknown": - print("\n#\tUnsupported shell type, please use # set shell ") - else: - prefix = '#' + config['shell'] + '\n\n' - - codex_query = prefix + prompt_file.read_prompt_file(user_query) + user_query + user_query, prompt_generator = get_query(prompt_generator) + codex_query = prefix + prompt_generator.prompt_engine.build_prompt(user_query) # get the response from codex - response = openai.Completion.create(engine=config['engine'], prompt=codex_query, temperature=config['temperature'], max_tokens=config['max_tokens'], stop="#") + response = openai.Completion.create(engine=prompt_generator.prompt_engine.config.model_config.engine, + prompt=codex_query, + temperature=prompt_generator.prompt_engine.config.model_config.temperature, + max_tokens=prompt_generator.prompt_engine.config.model_config.max_tokens, + stop=prompt_generator.prompt_engine.config.input_prefix) completion_all = response['choices'][0]['text'] @@ -211,9 +192,10 @@ def detect_shell(): print(completion_all) # append output to prompt context file - if config['multi_turn'] == "on": + if prompt_generator.prompt_engine.config.model_config.multi_turn == "on": if completion_all != "" or len(completion_all) > 0: - prompt_file.add_input_output_pair(user_query, completion_all) + prompt_generator.prompt_engine.add_interaction(user_query, completion_all) + prompt_generator.save_prompt_engine() except FileNotFoundError: print('\n\n# Codex CLI error: Prompt file not found, try again') diff --git a/src/commands.py b/src/commands.py index 4d0bde3..799af95 100644 --- a/src/commands.py +++ b/src/commands.py @@ -4,7 +4,17 @@ from pathlib import Path from prompt_file import * -def get_command_result(input, prompt_file): +import re + +param_type_mapping = { + 'engine': str, + 'temperature': float, + 'max_tokens': int, + 'shell': str, +} + + +def get_command_result(input, prompt_generator): """ Checks if the input is a command and if so, executes it Currently supported commands: @@ -23,131 +33,102 @@ def get_command_result(input, prompt_file): Returns: command result or "" if no command matched """ - if prompt_file == None: - return "", None - config = prompt_file.config + config = prompt_generator.prompt_engine.config.model_config # configuration setting commands if input.__contains__("set"): - # set temperature - if input.__contains__("temperature"): - input = input.split() - if len(input) == 4: - config['temperature'] = float(input[3]) - prompt_file.set_config(config) - print("# Temperature set to " + str(config['temperature'])) - return "config set", prompt_file - else: - return "", prompt_file - # set max_tokens - elif input.__contains__("max_tokens"): - input = input.split() - if len(input) == 4: - config['max_tokens'] = int(input[3]) - prompt_file.set_config(config) - print("# Max tokens set to " + str(config['max_tokens'])) - return "config set", prompt_file - else: - return "", prompt_file - elif input.__contains__("shell"): - input = input.split() - if len(input) == 4: - config['shell'] = input[3] - prompt_file.set_config(config) - print("# Shell set to " + str(config['shell'])) - return "config set", prompt_file - else: - return "", prompt_file - elif input.__contains__("engine"): - input = input.split() - if len(input) == 4: - config['engine'] = input[3] - prompt_file.set_config(config) - print("# Engine set to " + str(config['engine'])) - return "config set", prompt_file - else: - return "", prompt_file + # match the command using regex to one of the 4 above set commands + match = re.match(r"set (engine|temperature|max_tokens|shell) (.*)", input) + if match: + # get the command and the value + command = match.group(1) + value = match.group(2) + # check if the value is of the correct type + if param_type_mapping[command] == float: + value = float(value) + elif param_type_mapping[command] == int: + value = int(value) + elif param_type_mapping[command] == str: + value = str(value) + # set the value + setattr(config, command, value) + return "Configuration setting updated", prompt_generator - if input.__contains__("show config"): - prompt_file.show_config() - return "config shown", prompt_file + elif input.__contains__("show config"): + prompt_generator.show_config() + return "config shown", prompt_generator # multi turn/single turn commands - if input.__contains__("multi-turn"): + elif input.__contains__("multi-turn"): # start context if input.__contains__("start"): - if config['multi_turn'] == 'off': - prompt_file.start_multi_turn() - return "multi turn mode on", prompt_file - - return "multi turn mode on", prompt_file - + if getattr(config, 'multi_turn') == 'off': + prompt_generator.start_multi_turn() + return "multi turn mode on", prompt_generator + else: + return "multi turn mode already on", prompt_generator + # stop context - if input.__contains__("stop"): - prompt_file.stop_multi_turn() - return "multi turn mode off", prompt_file + elif input.__contains__("stop"): + if getattr(config, 'multi_turn') == 'on': + prompt_generator.stop_multi_turn() + return "multi turn mode off", prompt_generator + else: + return "multi turn mode already off", prompt_generator # context file commands - if input.__contains__("context"): + elif input.__contains__("context"): if input.__contains__("default"): - prompt_file.default_context() - return "stopped context", prompt_file + prompt_generator.default_context() + return "stopped context", prompt_generator # show context if input.__contains__("show"): print('\n') - with open(prompt_file.file_name, 'r') as f: - lines = f.readlines() - lines = lines[6:] # skip headers - - line_numbers = 0 - if len(input.split()) > 3: - line_numbers = int(input.split()[3]) - - if line_numbers != 0: - for line in lines[-line_numbers:]: - print('\n# '+line, end='') - else: - print('\n# '.join(lines)) - return "context shown", prompt_file + print (prompt_generator.prompt_engine.build_context()) + return "context shown", prompt_generator # edit context if input.__contains__("view"): # open the prompt file in text editor - if config['shell'] != 'powershell': - os.system('open {}'.format(prompt_file.file_path)) + if getattr(config, 'shell') != 'powershell': + os.system('open {}'.format(prompt_generator.file_path)) else: - os.system('start {}'.format(prompt_file.file_path)) - return "context shown", prompt_file + os.system('start {}'.format(prompt_generator.file_path)) + return "context shown", prompt_generator # save context if input.__contains__("save"): # save the current prompt file to a new file # if filename not specified use the current time (to avoid name conflicts) - filename = time.strftime("%Y-%m-%d_%H-%M-%S") + ".txt" - if len(input.split()) == 4: - filename = input.split()[3] + # regex to get the filename + match = re.match(r"save context (.*)", input) + if match: + filename = match.group(1) + else: + filename = time.strftime("%Y-%m-%d_%H-%M-%S") + ".yaml" - prompt_file.save_to(filename) - return "context saved", prompt_file + ##TODO: Make save_to function in prompt_engine + prompt_generator.save_to(filename) + return "context saved", prompt_generator # clear context if input.__contains__("clear"): # temporary saving deleted prompt file - prompt_file.default_context() - return "unlearned interaction", prompt_file + prompt_generator.default_context() + return "unlearned interaction", prompt_generator # load context if input.__contains__("load"): - # the input looks like # load context - # write everything from the file to the prompt file - input = input.split() - if len(input) == 4: - filename = input[3] - prompt_file.load_context(filename) - return "context loaded", prompt_file + + # regex to get the filename + match = re.match(r"load context (.*)", input) + if match: + filename = match.group(1) + prompt_generator.load_context(filename) + return "context loaded", prompt_generator print('\n#\tInvalid command format, did you specify which file to load?') - return "context loaded", prompt_file + return "context loaded", prompt_generator - return "", prompt_file + return "", prompt_generator diff --git a/src/prompt_file.py b/src/prompt_file.py index f86aeac..49035be 100644 --- a/src/prompt_file.py +++ b/src/prompt_file.py @@ -1,213 +1,98 @@ import os +from pyexpat import model import time import configparser +import pickle from pathlib import Path - +from openai import Model +from prompt_engine.code_engine import CodeEngine, PromptEngineConfig, Interaction API_KEYS_LOCATION = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'openaiapirc') -class PromptFile: - context_source_filename = "" - default_context_filename = "current_context.txt" + +class ModelConfig: + """ + Interaction class is used to store the model config to be used in the prompt engine + """ + def __init__(self, **kwargs): + self.engine = kwargs['engine'] if kwargs['engine'] else 'code-davinci-002' + self.temperature = float(kwargs['temperature']) if kwargs['temperature'] else 0 + self.max_tokens = int(kwargs['max_tokens']) if kwargs['max_tokens'] else 300 + self.shell = kwargs['shell'] if kwargs['shell'] else 'powershell' + self.multi_turn = kwargs['multi_turn'] if kwargs['multi_turn'] else 'on' + self.token_count = int(kwargs['token_count']) if kwargs['token_count'] else 0 + +class Prompt: + default_context_filename = "current_context.yaml" default_file_path = os.path.join(os.path.dirname(__file__), "..", default_context_filename) - default_config_path = os.path.join(os.path.dirname(__file__), "..", "current_context.config") + default_config_path = os.path.join(os.path.dirname(__file__), "..", "current_context.pickle") - def __init__(self, file_name, config): - self.context_source_filename = "{}-context.txt".format(config['shell']) # feel free to set your own default context path here + def __init__(self, shell, engine): - self.file_path = self.default_file_path - self.config_path = self.default_config_path - - # loading in one of the saved contexts - if file_name != self.default_context_filename: - self.load_context(file_name, True) - - def has_config(self): - """ - Check if the prompt file has a corresponding config file - """ - return os.path.isfile(self.config_path) + # check if default_config file exists, otherwise create it from the default_context_filename and save it + if not os.path.exists(self.default_config_path): + self.prompt_engine = self.create_prompt_engine_from_yaml(self.default_config_path) + self.save_prompt_engine(self.prompt_engine, self.default_config_path) + else: + # TODO: Change this to assignment operator (:=), recieving invalid syntax + if not os.path.exists(self.default_file_path): + shell_context_path = Path(os.path.join(os.path.dirname(__file__), "..", "contexts", f"{shell}-context.yaml")) + self.prompt_engine = self.create_prompt_engine_from_yaml(shell_context_path) + self.save_prompt_engine(self.prompt_engine, self.default_config_path) + else: + temp = self.load_prompt_engine(self.default_config_path) + if temp != None: + self.prompt_engine = temp + else: + self.prompt_engine = self.create_prompt_engine_from_yaml(self.default_config_path) + self.save_prompt_engine(self.prompt_engine, self.default_config_path) - def read_config(self): - """ - Read the prompt config and return a dictionary - """ - - if self.has_config() == False: - self.set_config(self.config) - return self.config - - with open(self.config_path, 'r') as f: - lines = f.readlines() - - config = { - 'engine': lines[0].split(':')[1].strip(), - 'temperature': float(lines[1].split(':')[1].strip()), - 'max_tokens': int(lines[2].split(':')[1].strip()), - 'shell': lines[3].split(':')[1].strip(), - 'multi_turn': lines[4].split(':')[1].strip(), - 'token_count': int(lines[5].split(':')[1].strip()) - } + def create_prompt_engine_from_yaml(self, yaml_path): + prompt_engine = CodeEngine() + prompt_engine.load_yaml(yaml_path) + return prompt_engine - self.config = config - return self.config - - def set_config(self, config): - """ - Set the prompt headers with the new config - """ - self.config = config - - with open(self.config_path, 'w') as f: - f.write('engine: {}\n'.format(self.config['engine'])) - f.write('temperature: {}\n'.format(self.config['temperature'])) - f.write('max_tokens: {}\n'.format(self.config['max_tokens'])) - f.write('shell: {}\n'.format(self.config['shell'])) - f.write('multi_turn: {}\n'.format(self.config['multi_turn'])) - f.write('token_count: {}\n'.format(self.config['token_count'])) - def show_config(self): print('\n') # read the dictionary into a list of # lines lines = [] - for key, value in self.config.items(): + for key, value in self.prompt_engine.config.model_config.__dict__.items(): lines.append('# {}: {}\n'.format(key, value)) print(''.join(lines)) def add_input_output_pair(self, user_query, prompt_response): """ - Add lines to file_name and update the token_count + Add an input/output pair to the prompt engine """ - with open(self.file_path, 'a') as f: - f.write(user_query) - f.write(prompt_response) - - if self.config['multi_turn'] == 'on': - self.config['token_count'] += len(user_query.split()) + len(prompt_response.split()) - self.set_config(self.config) - - def read_prompt_file(self, input): - """ - Get the updated prompt file - Checks for token overflow and appends the current input - - Returns: the prompt file after appending the input - """ - - input_tokens_count = len(input.split()) - need_to_refresh = (self.config['token_count'] + input_tokens_count > 2048) - - if need_to_refresh: - # delete first 2 lines of prompt context file - with open(self.file_path, 'r') as f: - lines = f.readlines() - prompt = lines[2:] # drop first 2 lines of prompt - with open(self.file_path, 'w') as f: - f.writelines(prompt) - - # get input from prompt file - with open(self.file_path, 'r') as f: - lines = f.readlines() - - return ''.join(lines) - - def get_token_count(self): - """ - Get the actual token count - """ - token_count = 0 - if self.has_config(): - with open(self.config_path, 'r') as f: - lines = f.readlines() - token_count = int(lines[5].split(':')[1].strip()) - - true_token_count = 0 - with open(self.file_path, 'r') as f: - lines = f.readlines() - # count the number of words in the prompt file - for line in lines: - true_token_count += len(line.split()) - - if true_token_count != token_count: - self.config['token_count'] = true_token_count - self.set_config(self.config) - - return true_token_count + self.prompt_engine.add_interaction(user_query, prompt_response) def clear(self): """ Clear the prompt file, while keeping the config Note: saves a copy to the deleted folder """ - config = self.read_config() - filename = time.strftime("%Y-%m-%d_%H-%M-%S") + ".txt" - with open(self.file_path, 'r') as f: - lines = f.readlines() - filename = os.path.join(os.path.dirname(__file__), "..", "deleted", filename) - with Path(filename).open('w') as f: - f.writelines(lines) - - # delete the prompt file - with open(self.file_path, 'w') as f: - f.write('') - - print("\n# Context has been cleared, temporarily saved to {}".format(filename)) - self.set_config(config) + self.prompt_engine.reset_context() def clear_last_interaction(self): """ Clear the last interaction from the prompt file """ - with open(self.file_path, 'r') as f: - lines = f.readlines() - if len(lines) > 1: - lines.pop() - lines.pop() - with open(self.file_path, 'w') as f: - f.writelines(lines) - print("\n# Unlearned interaction") - - def save_to(self, save_name): - """ - Save the prompt file to a new location with the config - """ - if not save_name.endswith('.txt'): - save_name = save_name + '.txt' - save_path = os.path.join(os.path.dirname(__file__), "..", "contexts", save_name) - - # first write the config - with open(self.config_path, 'r') as f: - lines = f.readlines() - lines = ['## ' + line for line in lines] - with Path(save_path).open('w') as f: - f.writelines(lines) - - # then write the prompt file - with open(self.file_path, 'r') as f: - lines = f.readlines() - with Path(save_path).open('a') as f: - f.writelines(lines) - - print('\n# Context saved to {}'.format(save_name)) + self.prompt_engine.remove_last_interaction() def start_multi_turn(self): """ Turn on context mode """ - self.config['multi_turn'] = 'on' - self.set_config(self.config) - print("\n# Multi turn mode is on") + self.prompt_engine.config.model_config.multi_turn = "on" def stop_multi_turn(self): """ Turn off context mode """ - self.config['multi_turn'] = 'off' - self.set_config(self.config) - print("\n# Multi turn mode is off") + self.prompt_engine.config.model_config.multi_turn = "off" def default_context(self): """ @@ -219,44 +104,42 @@ def load_context(self, filename, initialize=False): """ Loads a context file into current_context """ - if not filename.endswith('.txt'): - filename = filename + '.txt' + if not filename.endswith('.yaml'): + filename = filename + '.yaml' filepath = Path(os.path.join(os.path.dirname(__file__), "..", "contexts", filename)) # check if the file exists if filepath.exists(): - with filepath.open('r') as f: - lines = f.readlines() # read in the engine name from openaiapirc config = configparser.ConfigParser() config.read(API_KEYS_LOCATION) - ENGINE = config['openai']['engine'].strip('"').strip("'") - - config = { - 'engine': ENGINE, - 'temperature': float(lines[1].split(':')[1].strip()), - 'max_tokens': int(lines[2].split(':')[1].strip()), - 'shell': lines[3].split(':')[1].strip(), - 'multi_turn': lines[4].split(':')[1].strip(), - 'token_count': int(lines[5].split(':')[1].strip()) - } - - # use new config if old config doesn't exist - if initialize == False or self.has_config() == False: - self.set_config(config) - else: - self.config = self.read_config() + engine = config['openai']['engine'].strip('"').strip("'") + + self.prompt_engine = self.create_prompt_engine_from_yaml(filepath) + self.prompt_engine.config.model_config.engine = engine ## Needed? - lines = lines[6:] + self.save_prompt_engine(self.prompt_engine, self.default_config_path) - # write to the current prompt file if we are in multi-turn mode - if initialize == False or self.config['multi_turn'] == "off": - with open(self.file_path, 'w') as f: - f.writelines(lines) - - if initialize == False: - print('\n# Context loaded from {}'.format(filename)) else: print("\n# File not found") - return False \ No newline at end of file + return False + + + + def save_prompt_engine(self, obj, file_path = os.path.join(os.path.dirname(__file__), "..", "current_context.pickle")): + try: + with open(file_path, 'wb') as f: + pickle.dump(obj, f) + except Exception as e: + raise Exception("Error saving prompt engine: {}".format(e)) + + def load_prompt_engine(self, file_path = os.path.join(os.path.dirname(__file__), "..", "current_context.pickle")): + try: + with open(file_path, 'rb') as f: + self.prompt_engine = pickle.load(f) + return self.prompt_engine + return None + except Exception as e: + print("Error loading prompt engine: {}".format(e)) + return None From bb4e5d0b02cbf3a4e85941cc8a2d73e12a854b7b Mon Sep 17 00:00:00 2001 From: Abhishek Masand Date: Thu, 28 Jul 2022 02:06:28 +0530 Subject: [PATCH 2/5] Updated yaml, token limt and path --- contexts/bash-context.yaml | 4 +- contexts/powershell-context.yaml | 4 +- .../powershell-voice-cognitive-service.yaml | 4 +- contexts/powershell-voice.yaml | 4 +- contexts/zsh-context.yaml | 4 +- src/codex_query.py | 8 ++-- src/prompt_file.py | 45 ++++++++++--------- 7 files changed, 43 insertions(+), 30 deletions(-) diff --git a/contexts/bash-context.yaml b/contexts/bash-context.yaml index ee2587c..c39368b 100644 --- a/contexts/bash-context.yaml +++ b/contexts/bash-context.yaml @@ -3,10 +3,12 @@ config: model-config: engine: "code-cushman-001" temperature: 0 - max_tokens: 300 + max_tokens: 1024 shell: "bash" multi_turn: "off" token_count: 110 + comment-operator: "#" + description-comment-operator: "##" description: "This converts Natural Language Commands to Command Line Commands. Here are some examples" examples: - input: "what processes are hogging the most cpu?" diff --git a/contexts/powershell-context.yaml b/contexts/powershell-context.yaml index 9865e91..36d2ae1 100644 --- a/contexts/powershell-context.yaml +++ b/contexts/powershell-context.yaml @@ -3,10 +3,12 @@ config: model-config: engine: "code-cushman-001" temperature: 0 - max_tokens: 300 + max_tokens: 1024 shell: "powershell" multi_turn: "off" token_count: 110 + comment-operator: "#" + description-comment-operator: "##" description: "This converts Natural Language Commands to Command Line Commands. Here are some examples" examples: - input: "what processes are hogging the most cpu?" diff --git a/contexts/powershell-voice-cognitive-service.yaml b/contexts/powershell-voice-cognitive-service.yaml index 3f91f49..72c6d41 100644 --- a/contexts/powershell-voice-cognitive-service.yaml +++ b/contexts/powershell-voice-cognitive-service.yaml @@ -3,10 +3,12 @@ config: model-config: engine: "code-cushman-001" temperature: 0 - max_tokens: 300 + max_tokens: 1024 shell: "powershell" multi_turn: "off" token_count: 110 + comment-operator: "#" + description-comment-operator: "##" description: "This converts Natural Language Commands to Command Line Commands. Here are some examples" examples: - input: "what processes are hogging the most cpu?" diff --git a/contexts/powershell-voice.yaml b/contexts/powershell-voice.yaml index 02f8aa4..e8c9eeb 100644 --- a/contexts/powershell-voice.yaml +++ b/contexts/powershell-voice.yaml @@ -3,10 +3,12 @@ config: model-config: engine: "code-cushman-001" temperature: 0 - max_tokens: 300 + max_tokens: 1024 shell: "powershell" multi_turn: "off" token_count: 110 + comment-operator: "#" + description-comment-operator: "##" description: "This converts Natural Language Commands to Command Line Commands. Here are some examples" examples: - input: "what processes are hogging the most cpu?" diff --git a/contexts/zsh-context.yaml b/contexts/zsh-context.yaml index ad86af3..3bab4ac 100644 --- a/contexts/zsh-context.yaml +++ b/contexts/zsh-context.yaml @@ -3,10 +3,12 @@ config: model-config: engine: "code-cushman-001" temperature: 0 - max_tokens: 300 + max_tokens: 1024 shell: "zsh" multi_turn: "off" token_count: 110 + comment-operator: "#" + description-comment-operator: "##" description: "This converts Natural Language Commands to Command Line Commands. Here are some examples" examples: - input: "what processes are hogging the most cpu?" diff --git a/src/codex_query.py b/src/codex_query.py index a7f4a14..4a7f8ba 100755 --- a/src/codex_query.py +++ b/src/codex_query.py @@ -127,9 +127,10 @@ def get_query(prompt_generator): # get input from terminal or stdin if DEBUG_MODE: - entry = input("prompt: ") + '\n' + entry = input("prompt: ") else: - entry = sys.stdin.read() + # Remove extreaneous newlines and hashtag from the input string + entry = sys.stdin.read().strip("\n").strip("#").strip(" ") # first we check if the input is a command try: command_result, prompt_generator = get_command_result(entry, prompt_generator) @@ -175,8 +176,7 @@ def detect_shell(): try: user_query, prompt_generator = get_query(prompt_generator) - codex_query = prefix + prompt_generator.prompt_engine.build_prompt(user_query) - + codex_query = prefix + prompt_generator.prompt_engine.build_prompt(user_query, prompt_generator.prompt_engine.config.model_config.multi_turn) # get the response from codex response = openai.Completion.create(engine=prompt_generator.prompt_engine.config.model_config.engine, prompt=codex_query, diff --git a/src/prompt_file.py b/src/prompt_file.py index 49035be..8c2cf6c 100644 --- a/src/prompt_file.py +++ b/src/prompt_file.py @@ -6,34 +6,34 @@ from pathlib import Path from openai import Model -from prompt_engine.code_engine import CodeEngine, PromptEngineConfig, Interaction +from prompt_engine.code_engine import CodeEngine, ModelConfig API_KEYS_LOCATION = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'openaiapirc') -class ModelConfig: +class CodexCLIConfig(ModelConfig): """ Interaction class is used to store the model config to be used in the prompt engine """ def __init__(self, **kwargs): - self.engine = kwargs['engine'] if kwargs['engine'] else 'code-davinci-002' - self.temperature = float(kwargs['temperature']) if kwargs['temperature'] else 0 - self.max_tokens = int(kwargs['max_tokens']) if kwargs['max_tokens'] else 300 - self.shell = kwargs['shell'] if kwargs['shell'] else 'powershell' - self.multi_turn = kwargs['multi_turn'] if kwargs['multi_turn'] else 'on' - self.token_count = int(kwargs['token_count']) if kwargs['token_count'] else 0 + self.engine = kwargs['engine'] if ('engine' in kwargs and kwargs['engine']) else 'code-davinci-002' + self.temperature = float(kwargs['temperature']) if ('temperature' in kwargs and kwargs['temperature']) else 0 + self.max_tokens = int(kwargs['max_tokens']) if ('max_tokens' in kwargs and kwargs['max_tokens']) else 1024 + self.shell = kwargs['shell'] if ('shell' in kwargs and kwargs['shell']) else 'powershell' + self.multi_turn = kwargs['multi_turn'] if ('multi_turn' in kwargs and kwargs['multi_turn']) else 'on' + self.token_count = int(kwargs['token_count']) if ('token_count' in kwargs and kwargs['token_count']) else 0 +CURRENT_CONTEXT_LOCATION = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'current_context.pickle') class Prompt: default_context_filename = "current_context.yaml" default_file_path = os.path.join(os.path.dirname(__file__), "..", default_context_filename) - default_config_path = os.path.join(os.path.dirname(__file__), "..", "current_context.pickle") + default_config_path = os.path.join(os.path.dirname(__file__), "..", 'current_context.pickle') def __init__(self, shell, engine): # check if default_config file exists, otherwise create it from the default_context_filename and save it - if not os.path.exists(self.default_config_path): - self.prompt_engine = self.create_prompt_engine_from_yaml(self.default_config_path) - self.save_prompt_engine(self.prompt_engine, self.default_config_path) + if os.path.exists(self.default_config_path): + self.prompt_engine = self.load_prompt_engine(self.default_config_path) else: # TODO: Change this to assignment operator (:=), recieving invalid syntax if not os.path.exists(self.default_file_path): @@ -41,16 +41,19 @@ def __init__(self, shell, engine): self.prompt_engine = self.create_prompt_engine_from_yaml(shell_context_path) self.save_prompt_engine(self.prompt_engine, self.default_config_path) else: - temp = self.load_prompt_engine(self.default_config_path) + temp = self.create_prompt_engine_from_yaml(self.default_file_path) if temp != None: self.prompt_engine = temp - else: - self.prompt_engine = self.create_prompt_engine_from_yaml(self.default_config_path) self.save_prompt_engine(self.prompt_engine, self.default_config_path) + else: + raise Exception("Error loading prompt engine") def create_prompt_engine_from_yaml(self, yaml_path): - prompt_engine = CodeEngine() - prompt_engine.load_yaml(yaml_path) + default_config = CodexCLIConfig() + prompt_engine = CodeEngine(default_config) + with open(yaml_path, 'r') as f: + yaml_config = f.read() + prompt_engine.load_yaml(yaml_config=yaml_config) return prompt_engine def show_config(self): @@ -127,18 +130,18 @@ def load_context(self, filename, initialize=False): - def save_prompt_engine(self, obj, file_path = os.path.join(os.path.dirname(__file__), "..", "current_context.pickle")): + def save_prompt_engine(self, obj, file_path = os.path.join(os.path.dirname(__file__), "..", 'current_context.pickle')): try: with open(file_path, 'wb') as f: pickle.dump(obj, f) except Exception as e: raise Exception("Error saving prompt engine: {}".format(e)) - def load_prompt_engine(self, file_path = os.path.join(os.path.dirname(__file__), "..", "current_context.pickle")): + def load_prompt_engine(self, file_path = os.path.join(os.path.dirname(__file__), "..", 'current_context.pickle')): try: with open(file_path, 'rb') as f: - self.prompt_engine = pickle.load(f) - return self.prompt_engine + prompt_engine = pickle.load(f) + return prompt_engine return None except Exception as e: print("Error loading prompt engine: {}".format(e)) From 4ba9c45e6c903e944bcdd4486ad32acd0fa053c9 Mon Sep 17 00:00:00 2001 From: Abhishek Masand Date: Thu, 28 Jul 2022 16:13:18 +0530 Subject: [PATCH 3/5] Updated gitignore --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 03fd37c..2266d5a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ -current_context.txt -current_context.config +current_context.pickle contexts/test.txt src/__pycache__/ src/openaiapirc \ No newline at end of file From d7b82abf1a7326e770e43965dce7b277bfa0cc24 Mon Sep 17 00:00:00 2001 From: Abhishek Masand Date: Fri, 29 Jul 2022 00:29:00 +0530 Subject: [PATCH 4/5] Fixed save to, clear and default not working. Also added print messages for all commands --- src/codex_query.py | 2 +- src/commands.py | 26 ++++++++++++++++++++------ src/prompt_file.py | 22 +++++++++++++++++++--- 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/codex_query.py b/src/codex_query.py index 4a7f8ba..a3db093 100755 --- a/src/codex_query.py +++ b/src/codex_query.py @@ -195,7 +195,7 @@ def detect_shell(): if prompt_generator.prompt_engine.config.model_config.multi_turn == "on": if completion_all != "" or len(completion_all) > 0: prompt_generator.prompt_engine.add_interaction(user_query, completion_all) - prompt_generator.save_prompt_engine() + prompt_generator.save_prompt_engine(prompt_generator.prompt_engine) except FileNotFoundError: print('\n\n# Codex CLI error: Prompt file not found, try again') diff --git a/src/commands.py b/src/commands.py index 799af95..5235abd 100644 --- a/src/commands.py +++ b/src/commands.py @@ -52,6 +52,7 @@ def get_command_result(input, prompt_generator): value = str(value) # set the value setattr(config, command, value) + print (f"\n# {command} set to {value}") return "Configuration setting updated", prompt_generator elif input.__contains__("show config"): @@ -64,37 +65,44 @@ def get_command_result(input, prompt_generator): if input.__contains__("start"): if getattr(config, 'multi_turn') == 'off': prompt_generator.start_multi_turn() + print ("\n# Multi-turn mode started") return "multi turn mode on", prompt_generator else: + print ("\n# Multi-turn mode already started") return "multi turn mode already on", prompt_generator # stop context elif input.__contains__("stop"): if getattr(config, 'multi_turn') == 'on': prompt_generator.stop_multi_turn() + print ("\n# Multi-turn mode stopped") return "multi turn mode off", prompt_generator else: + print ("\n# Multi-turn mode already stopped") return "multi turn mode already off", prompt_generator # context file commands elif input.__contains__("context"): if input.__contains__("default"): prompt_generator.default_context() + print ("\n# Default context loaded") return "stopped context", prompt_generator # show context if input.__contains__("show"): print('\n') - print (prompt_generator.prompt_engine.build_context()) + print ("\n# ".join(prompt_generator.prompt_engine.build_context().split("\n"))) return "context shown", prompt_generator # edit context if input.__contains__("view"): # open the prompt file in text editor + prompt_generator.save_to("current-context.yaml") if getattr(config, 'shell') != 'powershell': - os.system('open {}'.format(prompt_generator.file_path)) + os.system('open {}'.format(Path(os.path.join(os.path.dirname(__file__), "..", "contexts", f"current-context.yaml")))) else: - os.system('start {}'.format(prompt_generator.file_path)) + os.system('start {}'.format(Path(os.path.join(os.path.dirname(__file__), "..", "contexts", f"current-context.yaml")))) + print ("\n# Context file opened in text editor") return "context shown", prompt_generator # save context @@ -109,14 +117,16 @@ def get_command_result(input, prompt_generator): else: filename = time.strftime("%Y-%m-%d_%H-%M-%S") + ".yaml" - ##TODO: Make save_to function in prompt_engine prompt_generator.save_to(filename) + print(f'\n# Saved to {filename}') + return "context saved", prompt_generator # clear context if input.__contains__("clear"): # temporary saving deleted prompt file - prompt_generator.default_context() + prompt_generator.clear_context() + print ("\n# Context cleared") return "unlearned interaction", prompt_generator # load context @@ -126,7 +136,11 @@ def get_command_result(input, prompt_generator): match = re.match(r"load context (.*)", input) if match: filename = match.group(1) - prompt_generator.load_context(filename) + success = prompt_generator.load_context(filename) + if success: + print (f'\n# Loaded {filename}') + else: + print (f'\n# Failed to load {filename}, please check the file') return "context loaded", prompt_generator print('\n#\tInvalid command format, did you specify which file to load?') return "context loaded", prompt_generator diff --git a/src/prompt_file.py b/src/prompt_file.py index 8c2cf6c..4e47527 100644 --- a/src/prompt_file.py +++ b/src/prompt_file.py @@ -101,9 +101,25 @@ def default_context(self): """ Go to default context """ - self.load_context(self.context_source_filename) + shell_context_path = Path(os.path.join(os.path.dirname(__file__), "..", "contexts", f"{self.prompt_engine.config.model_config.shell}-context.yaml")) + self.prompt_engine = self.create_prompt_engine_from_yaml(shell_context_path) + self.save_prompt_engine(self.prompt_engine, self.default_config_path) + print (f'\n# Switched to f"{self.prompt_engine.config.model_config.shell}-context.yaml') + + def clear_context(self): + shell_context_path = Path(os.path.join(os.path.dirname(__file__), "..", "contexts", f"{self.prompt_engine.config.model_config.shell}-context.yaml")) + self.prompt_engine = self.create_prompt_engine_from_yaml(shell_context_path) + self.save_prompt_engine(self.prompt_engine, self.default_config_path) + print (f'\n# Cleared context') + + def save_to(self, filename): + if not filename.endswith('.yaml'): + filename = filename + '.yaml' + filepath = Path(os.path.join(os.path.dirname(__file__), "..", "contexts", filename)) + with open(filepath, 'w') as f: + f.write(self.prompt_engine.save_yaml()) - def load_context(self, filename, initialize=False): + def load_context(self, filename): """ Loads a context file into current_context """ @@ -123,9 +139,9 @@ def load_context(self, filename, initialize=False): self.prompt_engine.config.model_config.engine = engine ## Needed? self.save_prompt_engine(self.prompt_engine, self.default_config_path) + return True else: - print("\n# File not found") return False From 2c745fefc6d688f2a00d6c47bf425eef61d0e4df Mon Sep 17 00:00:00 2001 From: Abhishek Masand Date: Fri, 29 Jul 2022 02:40:16 +0530 Subject: [PATCH 5/5] Fixed zsh installation issue --- scripts/zsh_setup.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/zsh_setup.sh b/scripts/zsh_setup.sh index cde3cd8..34ec693 100755 --- a/scripts/zsh_setup.sh +++ b/scripts/zsh_setup.sh @@ -42,6 +42,7 @@ validateSettings() # Append settings and CTRL-g binding in .zshrc configureZsh() { + touch $zshrcPath # Remove previous settings sed -i '' '/### Codex CLI setup - start/,/### Codex CLI setup - end/d' $zshrcPath echo "Removed previous settings in $zshrcPath if present"