Skip to content

add context from system in prompt (MACOS) #31

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 50 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
c0affa2
docs: add troubleshooting section
manekinekko Sep 27, 2021
0323f21
Merge pull request #2 from manekinekko/patch-1
tom-doerr Sep 27, 2021
2116eb1
Fix installation instructions
tom-doerr Sep 27, 2021
6ff76af
Merge branch 'main' of github.com:tom-doerr/zsh_codex into main
tom-doerr Sep 27, 2021
9201458
Remove items
tom-doerr Sep 27, 2021
80a91f2
Update instructions
tom-doerr Sep 27, 2021
544a240
Change heading
tom-doerr Sep 27, 2021
456d375
Troubleshooting fatal destination path doc
johnkegd Sep 27, 2021
2a26bd6
Merge pull request #3 from johnkegd/main
tom-doerr Sep 27, 2021
25754a2
Capitalize words
tom-doerr Sep 27, 2021
8051b78
Install instructions for use without oh-my-zsh
clotodex Oct 11, 2021
a6e6b1e
Merge pull request #6 from clotodex/main
tom-doerr Oct 11, 2021
8bd5c4a
Update file
tom-doerr Oct 11, 2021
2539595
Switch to configparser
tom-doerr Nov 7, 2021
fd423ff
Increase num tokens
tom-doerr Nov 21, 2021
311d0e8
Change badge style
tom-doerr Nov 23, 2021
804a386
Change color
tom-doerr Jan 18, 2022
ccf0e9e
Change colors
tom-doerr Jan 18, 2022
1a16850
Update model name
tom-doerr Jan 23, 2022
ef54286
Add traffic stats
tom-doerr Jan 24, 2022
6d6517f
Change link
tom-doerr Jan 24, 2022
b8d8052
Switch to insert mode
tom-doerr Mar 27, 2022
ecef53f
Switch to insert mode
tom-doerr Mar 27, 2022
a390605
Add usage exampmles
tom-doerr Mar 27, 2022
d4261d3
Add link
tom-doerr Mar 29, 2022
f2c1ed9
Add break
tom-doerr Mar 29, 2022
c604241
Capitalize link
tom-doerr Mar 29, 2022
31444c1
Fix the git clone command for the plugin
RafaelMoreira1180778 Mar 29, 2022
eceb9a1
Merge pull request #11 from RafaelMoreira1180778/fix#git-clone
tom-doerr Mar 29, 2022
c2352e6
Change heading
tom-doerr May 25, 2022
9308dd6
Add coffee link
tom-doerr May 25, 2022
aa5a80e
Merge branch 'main' of github.com:tom-doerr/zsh_codex into main
tom-doerr May 25, 2022
e345027
Add line
tom-doerr May 25, 2022
55c4d95
Add Fig as an installation method to the README
ibayramli Jun 16, 2022
8c52b82
Update README.md
tom-doerr Jun 17, 2022
4eae6e2
Merge pull request #18 from ibayramli/fig
tom-doerr Jun 17, 2022
456db1a
Update readme
tom-doerr Nov 11, 2022
95de2b0
Update README.md
fbarez Dec 13, 2022
7858a61
Merge pull request #21 from fbarez/main
tom-doerr Dec 14, 2022
165987b
Update README.md
tom-doerr Jun 16, 2023
9eafdd6
support gpt-3.5-turbo model
akinazuki Jun 24, 2023
67e57a7
select model via configuration file
akinazuki Jun 24, 2023
4300781
fix type
akinazuki Jun 24, 2023
14a6080
Merge pull request #28 from akinazuki/main
tom-doerr Jul 11, 2023
d06cf23
Add default model
tom-doerr Jul 13, 2023
929172e
Update create_completion.py
MustCodeAl Aug 9, 2023
713f99c
Update create_completion.py
MustCodeAl Aug 9, 2023
a49ab9b
Update create_completion.py
MustCodeAl Aug 9, 2023
052a4ee
Update create_completion.py
MustCodeAl Aug 9, 2023
dec4f22
Update create_completion.py
MustCodeAl Aug 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 68 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,27 @@
<p align="center">
<a href="https://github.com/tom-doerr/zsh_codex/stargazers"
><img
src="https://img.shields.io/github/stars/tom-doerr/zsh_codex"
src="https://img.shields.io/github/stars/tom-doerr/zsh_codex?colorA=2c2837&colorB=c9cbff&style=for-the-badge&logo=starship style=flat-square"
alt="Repository's starts"
/></a>
<a href="https://github.com/tom-doerr/zsh_codex/issues"
><img
src="https://img.shields.io/github/issues-raw/tom-doerr/zsh_codex"
src="https://img.shields.io/github/issues-raw/tom-doerr/zsh_codex?colorA=2c2837&colorB=f2cdcd&style=for-the-badge&logo=starship style=flat-square"
alt="Issues"
/></a>
<a href="https://github.com/tom-doerr/zsh_codex/blob/main/LICENSE"
><img
src="https://img.shields.io/github/license/tom-doerr/zsh_codex"
src="https://img.shields.io/github/license/tom-doerr/zsh_codex?colorA=2c2837&colorB=b5e8e0&style=for-the-badge&logo=starship style=flat-square"
alt="License"
/><br />
<a href="https://github.com/tom-doerr/zsh_codex/commits/main"
><img
src="https://img.shields.io/github/last-commit/tom-doerr/zsh_codex/main"
src="https://img.shields.io/github/last-commit/tom-doerr/zsh_codex/main?colorA=2c2837&colorB=ddb6f2&style=for-the-badge&logo=starship style=flat-square"
alt="Latest commit"
/></a>
<a href="https://github.com/tom-doerr/zsh_codex"
><img
src="https://img.shields.io/github/repo-size/tom-doerr/zsh_codex"
src="https://img.shields.io/github/repo-size/tom-doerr/zsh_codex?colorA=2c2837&colorB=89DCEB&style=for-the-badge&logo=starship style=flat-square"
alt="GitHub repository size"
/></a>
</p>
Expand All @@ -47,26 +47,84 @@ To use this plugin you need to get access to OpenAI's [Codex API](https://openai


## How do I install it?
### Manual Installation
1. Install the OpenAI package.
```
pip3 install openai
```

1. Download the ZSH plugin.
2. Download the ZSH plugin.

```
$ git clone https://github.com/tom-doerr/zsh_codex.git ~/.oh-my-zsh/plugins/
git clone https://github.com/tom-doerr/zsh_codex.git ~/.oh-my-zsh/custom/plugins/zsh_codex
```

2. Add the following to your `.zshrc` file.
3. Add the following to your `.zshrc` file.

Using oh-my-zsh:
```
plugins=(zsh_codex)
bindkey '^X' create_completion
```
Without oh-my-zsh:
```
# in your/custom/path you need to have a "plugins" folder and in there you clone the repository as zsh_codex
export ZSH_CUSTOM="your/custom/path"
source "$ZSH_CUSTOM/plugins/zsh_codex/zsh_codex.plugin.zsh"
bindkey '^X' create_completion
```

3. Create a file called `openaiapirc` in `~/.config` with your ORGANIZATION_ID and SECRET_KEY.
4. Create a file called `openaiapirc` in `~/.config` with your ORGANIZATION_ID and SECRET_KEY.

```
[openai]
organization_id = ...
secret_key = ...
```

4. Run `zsh`, start typing and complete it using `^X`!
5. Run `zsh`, start typing and complete it using `^X`!

### Fig Installation

<a href="https://fig.io/plugins/other/zsh_codex_tom-doerr" target="_blank"><img src="https://fig.io/badges/install-with-fig.svg" /></a>

## Troubleshooting

### Unhandled ZLE widget 'create_completion'

```
zsh-syntax-highlighting: unhandled ZLE widget 'create_completion'
zsh-syntax-highlighting: (This is sometimes caused by doing `bindkey <keys> create_completion` without creating the 'create_completion' widget with `zle -N` or `zle -C`.)
```

Add the line
```
zle -N create_completion
```
before you call `bindkey` but after loading the plugin (`plugins=(zsh_codex)`).

### Already exists and is not an empty directory
```
fatal: destination path '~.oh-my-zsh/custom/plugins'
```
Try to download the ZSH plugin again.
```
git clone https://github.com/tom-doerr/zsh_codex.git ~/.oh-my-zsh/custom/plugins/zsh_codex
```
---
<p align="center">
<a href="https://www.buymeacoffee.com/TomDoerr" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy Me A Coffee" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a>
</p>

## More usage examples
<p align="center">
<img src='https://github.com/tom-doerr/bins/raw/main/zsh_codex/update_insert/all.gif'>
<p align="center">
</p>
</p>

-------------------------------------------------------------------

[Fish Version](https://github.com/tom-doerr/codex.fish)

[Traffic Statistics](https://tom-doerr.github.io/github_repo_stats_data/tom-doerr/zsh_codex/latest-report/report.html)
168 changes: 122 additions & 46 deletions create_completion.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,50 @@
#!/usr/bin/env python3

import asyncio
import openai
import sys
import os
import configparser
import platform
import subprocess
import json
import time

STREAM = False


# Get config dir from environment or default to ~/.config
CONFIG_DIR = os.getenv('XDG_CONFIG_HOME', os.path.expanduser('~/.config'))
API_KEYS_LOCATION = os.path.join(CONFIG_DIR, 'openaiapirc')


CACHE_DIR = os.path.join(CONFIG_DIR, 'cache/zsh_codex')
os.makedirs(CACHE_DIR, exist_ok=True)
SYSTEM_INFO_CACHE_FILE = os.path.join(CACHE_DIR, 'system_info.json')
INSTALLED_PACKAGES_CACHE_FILE = os.path.join(CACHE_DIR, 'installed_packages.json')
CACHE_EXPIRATION_TIME = 60 * 60 * 24 # 24 hours







def load_or_save_to_cache(filename, default_func):
if os.path.exists(filename):
with open(filename, 'r') as f:
data = json.load(f)
if time.time() - data['timestamp'] < CACHE_EXPIRATION_TIME:
return data['value']

data = {
'value': default_func(),
'timestamp': time.time()
}
with open(filename, 'w') as f:
json.dump(data, f)

return data['value']

# Read the organization_id and secret_key from the ini file ~/.config/openaiapirc
# The format is:
# [openai]
Expand All @@ -20,8 +54,7 @@
# If you don't see your organization ID in the file you can get it from the
# OpenAI web site: https://openai.com/organizations


def create_template_ini_file():
async def create_template_ini_file():
"""
If the ini file does not exist create it and add the organization_id and
secret_key
Expand All @@ -31,61 +64,104 @@ def create_template_ini_file():
f.write('[openai]\n')
f.write('organization_id=\n')
f.write('secret_key=\n')
f.write('model=gpt-4-0314\n')

print('OpenAI API config file created at {}'.format(API_KEYS_LOCATION))
print('Please edit it and add your organization ID and secret key')
print('If you do not yet have an organization ID and secret key, you\n'
'need to register for OpenAI Codex: \n'
'https://openai.com/blog/openai-codex/')
sys.exit(1)


try:
with open(API_KEYS_LOCATION) as f:
config = f.read()
async def initialize_openai_api():
"""
Initialize the OpenAI API
"""
# Check if file at API_KEYS_LOCATION exists
await create_template_ini_file()
config = configparser.ConfigParser()
config.read(API_KEYS_LOCATION)

config = '\n' + config
# Reading the values works even when there are spaces around the = sign.
organization_id = config.split('organization_id')[1].split('=')[1].split('\n')[0].strip()
secret_key = config.split('secret_key')[1].split('=')[1].split('\n')[0].strip()
except:
print("Unable to read openaiapirc at {}".format(API_KEYS_LOCATION))
create_template_ini_file()
openai.organization_id = config['openai']['organization_id'].strip('"').strip("'")
openai.api_key = config['openai']['secret_key'].strip('"').strip("'")

if 'model' in config['openai']:
model = config['openai']['model'].strip('"').strip("'")
else:
model = 'gpt-4'

# Remove the quotes if there are any.
if organization_id[0] == '"' and organization_id[-1] == '"':
organization_id = organization_id[1:-1]
return model

if secret_key[0] == '"' and secret_key[-1] == '"':
secret_key = secret_key[1:-1]

openai.api_key = secret_key
openai.organization = organization_id
# model = initialize_openai_api()
model = asyncio.run(initialize_openai_api())

# Read the input prompt from stdin.
input_prompt = '#!/bin/zsh\n\n' + sys.stdin.read()


response = openai.Completion.create(engine='davinci-codex', prompt=input_prompt, temperature=0.5, max_tokens=32, stream=STREAM)
# completion = response['choices'][0]['text']
if STREAM:
while True:
next_response = next(response)
print("next_response:", next_response)
# next_response['choices'][0]['finish_reason']
print(" next_response['choices'][0]['finish_reason']:", next_response['choices'][0]['finish_reason'])
completion = next_response['choices'][0]['text']
print("completion:", completion)
# print(next(response))
else:
completion_all = response['choices'][0]['text']
completion_list = completion_all.split('\n')
if completion_all[:2] == '\n\n':
print(completion_all)
elif completion_list[0]:
print(completion_list[0])
elif len(completion_list) == 1:
print('')
else:
print('\n' + completion_list[1])
cursor_position_char = int(sys.argv[1])


async def get_system_info():
"""
Gather system information
"""

def default_func():
return {
"os": platform.system(),
"os_version": platform.version(),
"architecture": platform.architecture()[0],
"processor": platform.processor()
}

return load_or_save_to_cache(SYSTEM_INFO_CACHE_FILE, default_func)


system_info = asyncio.run(get_system_info())


# last ten recent packages
async def get_installed_packages():
# Get list of installed packages
def default_func():
try:
if system_info['os'] == 'Linux':
command = "dpkg --get-selections | head -n 5"
return subprocess.check_output(command, shell=True).decode('utf-8')
elif system_info['os'] == 'Darwin':
command = "brew list -1t 2> /dev/null | head -n 5"
return subprocess.check_output(command, shell=True).decode('utf-8')
else:
return "Unsupported OS for package listing"
except subprocess.CalledProcessError as e:
return f"Error getting installed packages: {str(e)}"

return load_or_save_to_cache(INSTALLED_PACKAGES_CACHE_FILE, default_func)



installed_packages = asyncio.run(get_installed_packages())

# Get current working directory
current_directory = os.getcwd()
# Read the input prompt from stdin.
buffer = sys.stdin.read()
prompt_prefix = '#!/bin/zsh\n\n' + buffer[:cursor_position_char]
prompt_suffix = buffer[cursor_position_char:]
full_command = prompt_prefix + prompt_suffix
response = openai.ChatCompletion.create(model=model, messages=[
{
"role": 'system',
"content": "You are a zsh shell expert, please help me complete the following command, you should only output the completed command, no need to include any other explanation",
},
{
"role": 'user',
"content": f"I'm using a {system_info['os']} system with version {system_info['os_version']} on a {system_info['architecture']} architecture with a {system_info['processor']} processor. The current directory is {current_directory}. Here are some of my installed packages:\n{installed_packages}",
},
{
"role": 'user',
"content": full_command,
}
])
completed_command = response['choices'][0]['message']['content']

sys.stdout.write(f"\n{completed_command}")
13 changes: 9 additions & 4 deletions zsh_codex.plugin.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@
create_completion() {
# Get the text typed until now.
text=${BUFFER}
completion=$(echo -n "$text" | $ZSH_CUSTOM/plugins/zsh_codex/create_completion.py)
#echo $cursor_line $cursor_col
completion=$(echo -n "$text" | $ZSH_CUSTOM/plugins/zsh_codex/create_completion.py $CURSOR)
text_before_cursor=${text:0:$CURSOR}
text_after_cursor=${text:$CURSOR}
# Add completion to the current buffer.
BUFFER="${text}${completion}"
# Put the cursor at the end of the line.
CURSOR=${#BUFFER}
#BUFFER="${text}${completion}"
BUFFER="${text_before_cursor}${completion}${text_after_cursor}"
prefix_and_completion="${text_before_cursor}${completion}"
# Put the cursor at the end of the completion
CURSOR=${#prefix_and_completion}
}

# Bind the create_completion function to a key.
Expand Down