Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolodiamante committed May 30, 2023
0 parents commit af539ce
Show file tree
Hide file tree
Showing 9 changed files with 394 additions and 0 deletions.
15 changes: 15 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#
# EditorConfig for consistent coding styles.
# Ref: https://editorconfig.org
#

root = true

[*]
indent_style = space
indent_size = 2
tab_width = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
14 changes: 14 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#
# Exclude these files from release archives.
#

.gitattributes export-ignore
.gitignore export-ignore


#
# Auto detect text files and perform LF normalization
# http://davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/
#
* text=auto
eol=lf
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#
# Ignore
#

*.swp
.DS_Store
21 changes: 21 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

&#169; 2023 Nicolò Diamante <[email protected]>

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
126 changes: 126 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<p align="center"><a href="#"><img src="https://github.com/nicolodiamante/zchat/assets/48920263/763a8734-3638-4dc4-b61f-20e7255c2f84" draggable="false" ondragstart="return false;" alt="Zchat Title" title="Zchat" /></a></p>

Maximise your productivity and streamline your terminal experience with Zchat (zch) - a command-line productivity tool powered by OpenAI's [ChatGPT][chatgpt] models. Quickly generate Linux commands and code snippets from natural language queries without the need to manually search the web. Leverage AI capabilities to get accurate answers directly in your terminal in a time and effort-efficient manner. Furthermore, Zchat's Git integration makes working with version control even simpler - goodbye cheat sheets and notes. Get the job done quickly and easily.

<br/><br/>

<p align="center"><a href="#"><img src="https://github.com/nicolodiamante/zchat/assets/48920263/04047772-bcc7-4884-ab09-5537f18a905d" draggable="false" ondragstart="return false;" alt="IMG show ChatGPT conbined with the Terminal" title="ChatGPt conbined with the Terminal" width="700px" /></a></p><br/>

## Create your OpenAI API Key

To use Zchat, you'll first need to obtain the API key. This can be done by generating a new secret key from your OpenAI account, which will be required for authentication. To get started, you can obtain the key by following these steps. First, log in to your [OpenAI account][open-ai-account]. Next, look for the "Create new secret key" option and click on it.

<p align="center"><a href="#"><img src="https://github.com/nicolodiamante/zchat/assets/48920263/fff3e6a7-f6ff-46f8-b320-e8bb30e1bf08" draggable="false" ondragstart="return false;" alt="IMG show how to create new secret key" title="Create new secret key" width="750px" /></a></p>

Once you have obtained your [API Key][open-ai-API], integrating ChatGPT's services with Zchat is straightforward. Note that once you have copied the API Key and closed the pop-up window, you will no longer be able to access and view the key, making it essential that you store it in a secure and safe place.
<br/><br/>

<p align="center"><a href="#"><img src="https://github.com/nicolodiamante/zchat/assets/48920263/01610502-7e24-414d-b115-de6e4992bf23" draggable="false" ondragstart="return false;" alt="IMG show an example of a OpenAI API Key" title="OpenAI API Key" width="750px" /></a></p><br/>

## Getting Started

Download the repository via curl:

```shell
sh -c "$(curl -fsSL https://raw.githubusercontent.com/nicolodiamante/zchat/HEAD/bootstrap.sh)"
```

Alternatively, clone manually:

```shell
git clone https://github.com/nicolodiamante/zchat.git ~/zchat
```

Head over into the directory and then:

```shell
cd utils && source install.sh
```

The script will search for the file zshrc, then append the file path `zchat/script` to the variable fpath and set the `OPENAI_API_KEY` variable.

```shell
# Zchat path.
fpath=(~/zchat/script $fpath)
autoload -Uz zchat
```
<br/>

### Install via [Oh My Zsh][ohmyzsh]

```shell
git clone https://github.com/nicolodiamante/zchat.git $ZSH_CUSTOM/plugins/zchat
```

- Add to your zshrc plugins array `plugins=(... zchat)`
- Paste your API Key at the `OPENAI_API_KEY` variable in your zshrc.
- Restart the shell to activate.
<br/><br/>

### Setting up dependencies

Once the installation is complete, open your zshrc file. Paste your OpenAI API Key to the `OPENAI_API_KEY` variable. By default, the script uses the GPT-3.5-turbo model. For most basic tasks, there is not much difference between GPT-4 and GPT-3.5 models. To use the latest GPT-4 model, just change the current model to `gpt-4`.

```shell
# Zchat dependencies.
export OPENAI_API_KEY=""
export OPENAI_GPT_MODEL="gpt-3.5-turbo"
```

> If you are not enrolled in the limited beta program for GPT-4, you will need to join a waiting list to use its API. Since developers have been given priority, it is unclear when non-developers will be granted access. Until that time, users should select the GPT-3.5-Turbo model as an alternative.
<br/>

## How to use Zchat

```shell
zch <description of task>
```

### Completion

- Type `zch` to initiate the completion follow by the command that will be used as a basis for your query.
- Once you have written a natural language version of what you intend to do, press "enter" to execute it.
<br/><br/><br/>

<p align="center"><a href=""><img src="https://github.com/nicolodiamante/zchat/assets/48920263/8e9effe9-a1dc-4237-a04e-9850a370716f" draggable="false" ondragstart="return false;" alt="Zchat Completion" title="chat Completion" width="560px" /></a></p>
<br/><br/>

## Notes

When you launch Zchat, it will automatically check if you are in a Git repository. If you are, it will provide relevant Git commands and guidance. If not, Zchat will help you access the right command line tools and find the best solution to complete your task.

### Resources

#### OpenAI

- [OpenAI Documentation][intro]
- [OpenAI Models][open-ai-models]
- [OpenAI Chat][chat-completions]

#### Zsh Documentations

- [Documentation Index][zsh-docs]
- [User Guide][zsh-docs-guide]

### Contribution

Thank you for considering using Zchat. Any suggestions or feedback you may have for improvement are welcome. If you encounter any issues or bugs, please report them on the [issues page][issues].<br/><br/>

<p align="center"><a href="#"><img src="https://user-images.githubusercontent.com/48920263/113406768-5a164900-93ac-11eb-94a7-09377a52bf53.png" draggable="false" ondragstart="return false;" /></a></p>

<p align="center"><a href="https://nicolodiamante.com" target="_blank"><img src="https://github.com/nicolodiamante/zchat/assets/48920263/a3c3d92a-7a5f-423d-b089-f9cb92d1f384" draggable="false" ondragstart="return false;" alt="Nicol&#242; Diamante Portfolio" title="Nicol&#242; Diamante" width="11px" /></a></p>

<p align="center"><a href="https://github.com/nicolodiamante/zchat/blob/main/LICENSE.md" target="_blank"><img src="https://github.com/nicolodiamante/zchat/assets/48920263/c4ffb2b6-6d55-4192-859f-0939aadbc37c" draggable="false" ondragstart="return false;" alt="The MIT License" title="The MIT License (MIT)" width="90px" /></a></p>

<!-- Link labels: -->
[open-ai-account]: https://chat.openai.com/auth/login
[open-ai-API]: https://beta.openai.com/account/api-keys
[chatgpt]: https://openai.com/blog/chatgpt
[open-ai-models]: https://platform.openai.com/docs/models
[intro]: https://platform.openai.com/docs/introduction
[chat-completions]: https://platform.openai.com/docs/guides/chat
[ohmyzsh]: https://github.com/robbyrussell/oh-my-zsh/
[zsh-docs]: http://zsh.sourceforge.net/Doc
[zsh-docs-guide]: http://zsh.sourceforge.net/Guide/zshguide.html
[issues]: https://github.com/nicolodiamante/zchat/issues
31 changes: 31 additions & 0 deletions bootstrap.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/bin/sh

# Determines the current user's shell.
[[ "$(basename -- "$SHELL")" == "zsh" ]] || exit 1

SOURCE=https://github.com/nicolodiamante/zchat
TARBALL="${SOURCE}/tarball/master"
TARGET="${HOME}/zchat"
TAR_CMD="tar -xzv -C "${TARGET}" --strip-components 1 --exclude .gitignore"

INSTALL=./utils/install.sh

is_executable() {
type "$1" > /dev/null 2>&1
}

# Checks which executable is available then downloads and installs.
if is_executable "git"; then
CMD="git clone ${SOURCE} ${TARGET}"
elif is_executable "curl"; then
CMD="curl -L ${TARBALL} | ${TAR_CMD}"
elif is_executable "wget"; then
CMD="wget --no-check-certificate -O - ${TARBALL} | ${TAR_CMD}"
fi

if [[ -z "$CMD" ]]; then
echo 'No git, curl or wget available. Aborting!'
else
echo 'Installing zchat...'
mkdir -p "${TARGET}" && eval "${CMD}" && cd "${TARGET}" && source "${INSTALL}"
fi
130 changes: 130 additions & 0 deletions script/zch
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#
# Zchat - Streamline your terminal experience.
# By Nicolò Diamante <[email protected]>
# https://github.com/nicolodiamante/zchat
# MIT License
#

zch() {
if ! command -v jq >/dev/null; then
echo "zchat: jq is not found on your system. Please install jq and try again."
return 1
fi

if ! command -v curl &> /dev/null && ! command -v wget &> /dev/null; then
echo ""
echo "Error: curl or wget is not installed"
zle reset-prompt
return 1
fi

if [[ -z "$OPENAI_API_KEY" ]]; then
echo "zchat: the OPENAI_API_KEY appears to be missing. Please provide a valid API key and try again."
return 1
fi

if [[ -z "$OPENAI_GPT_MODEL" ]]; then
echo "zchat: the OPENAI_GPT_MODEL appears not to be set. By default this script is set to used GPT-3.5-turbo model. For many basic tasks, the difference between GPT-4 and GPT-3.5 models is not significant. However, in more complex reasoning situations, GPT-4 is much more capable than any of previous models. If you want to use the latest model version GPT-4 you just need to change the current number to 4. Keep in mind GPT-4 is currently in a limited beta and not everyone, even if they are on a paid plan, has access to GPT-4 API."
return 1
else
chatGPT_model="$OPENAI_GPT_MODEL"
fi

zchat_get_distribution_name() {
if [[ "$(uname)" -eq "Darwin" ]]; then
echo "$(sw_vers -productName) $(sw_vers -productVersion)" 2>/dev/null
else
echo "$(cat /etc/*-release 2>/dev/null | grep PRETTY_NAME | cut -d'"' -f2)"
fi
}

zchat_get_os_prompt_injection() {
local OS=$(zchat_get_distribution_name)
if [[ -n "$OS" ]]; then
echo " for $OS"
else
echo ""
fi
}

# Request body.
user_input="$@"
model="$chatGPT_model"
temperature=0.5
top_p=0.0
presence_penalty=0.0
frequency_penalty=0.0
max_tokens=257

# Check if current directory is a Git repository.
if [[ -d .git ]]; then
message="You are Zchat, my autocomplete script, and your goal is to help me navigate my Linux system, starting from the current directory, which is a git repository. What GIT command should I copy and paste into the terminal in order to achieve the desired result of ${user_input}? Provide only a valid GIT command${OS}, and nothing else. You do not write any human-readable explanations. If you fail to answer, return 'zchat: failed to generate command'."
else
message="You are Zchat, my autocomplete script, and your task is to assist me in navigating my Linux. All the questions I'm asking will be related to this subject. Now, I'd like you to answer this: ${user_input}. Please provide a valid command${OS} as a single line of text (no code blocks, quotes, or anything else outside the command itself) that takes into consideration my current directory (using either '.' or $(pwd)) and doesn't put my system at risk in any way. It's acceptable to chain commands, but prioritize one-liners if possible. If you can't find a suitable command, answer with 'zchat: failed to generate command'."
fi

if command -v curl &> /dev/null; then
response=$(curl -s -X POST "https://api.openai.com/v1/chat/completions" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d "{
\"model\": \"$model\",
\"messages\": [{\"role\": \"user\", \"content\": \"$message\"}],
\"temperature\": $temperature,
\"top_p\": $top_p,
\"max_tokens\": $max_tokens,
\"presence_penalty\": $presence_penalty,
\"frequency_penalty\": $frequency_penalty
}")
else
response=$(wget -qO- "https://api.openai.com/v1/chat/completions" \
--header="Content-Type: application/json" \
--header="Authorization: Bearer $OPENAI_API_KEY" \
--post-data="{
\"model\": \"$model\",
\"messages\": [{\"role\": \"user\", \"content\": \"$message\"}],
\"temperature\": $temperature,
\"top_p\": $top_p,
\"max_tokens\": $max_tokens,
\"presence_penalty\": $presence_penalty,
\"frequency_penalty\": $frequency_penalty
}")
fi

# Add some colour.
autoload -Uz colors && colors
promp_default='%F{green}→%f'
promp_error='%F{red}→%f'

ERROR_MESSAGE=$(printf "%s" "$response" | jq -r '(.error.message // "") | @json' | sed 's/^"//;s/"$//')
COMMAND=$(printf "%s" "$response" | jq -r '(.choices[0].message.content // "") | @json' | sed 's/^"//;s/"$//')

# Output prompt.
if [[ -n "$ERROR_MESSAGE" ]]; then
echo "Error: $ERROR_MESSAGE"
elif [[ -n "$COMMAND" && -d .git ]]; then
if [[ "$COMMAND" =~ ^git ]]; then
print -P "$promp_default $COMMAND"
read -q "REPLY? Execute command? (y/n) "
if [[ "$REPLY" =~ ^[Yy]$ ]]; then
echo
eval "$COMMAND"
else
echo
print -P "$promp_error command not executed."
fi
else
print -P "$promp_error output does not begin with git and it will not be executed."
print -P "$COMMAND"
fi
elif [[ "$COMMAND" =~ "zchat: failed to generate command" || "$COMMAND" =~ "parse error:" ]]; then
print -P "$promp_error unable to generate a command."
print -P "$COMMAND"
elif [[ -n "$COMMAND" ]]; then
print -P "$promp_default $COMMAND"
eval "$COMMAND"
else
print -P "$promp_error unexpected response."
print -P "$COMMAND"
fi
}
48 changes: 48 additions & 0 deletions utils/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/sh

#
# Install zchat
#

# Determines the current user's shell, if `zsh` then installs.
[[ "$(basename -- "$SHELL")" == "zsh" ]] || exit 1

# Check for Homebrew, else install.
echo 'Checking for Homebrew...'
if ! command -v brew >/dev/null; then
echo 'Brew is missing! Installing it...'
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
fi

# Check for jq, else install.
if ! command -v jq >/dev/null; then
echo 'zchat: jp dependency is missing! Installing it...'
brew install jq
fi

# Defines the PATHs.
SCRIPT="${HOME}/zchat/script"
ZSHRC="${ZDOTDIR:-${XDG_CONFIG_HOME/zsh:-$HOME}}/.zshrc"

# Make script executable.
zchatat="${0:h}/script/zchat"
chmod +x $zchat

if [[ -d "$SCRIPT" && -f "$ZSHRC" ]]; then
# Appends to `zshrc`.
cat << EOF >> ${ZSHRC}
# Zchat path.
fpath=(~/zchat/script \$fpath)
autoload -Uz zchat
# Zchat dependencies.
export OPENAI_API_KEY=""
export OPENAI_GPT_MODEL="gpt-3.5-turbo"
EOF
echo 'zsh: appended zchat to zshrc.'

# Reloads shell.
source "${ZSHRC}"
else
echo 'zsh: zshrc not found!'
fi
Loading

0 comments on commit af539ce

Please sign in to comment.