-
Notifications
You must be signed in to change notification settings - Fork 3.4k
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
GPT-3.5 #1365
base: master
Are you sure you want to change the base?
GPT-3.5 #1365
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,8 @@ | ||
#!/bin/sh | ||
#!/bin/zsh | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should not be part of the pull request. |
||
|
||
echo "Installation script is deprecated!" | ||
echo "For installation instruction please visit https://github.com/nvbn/thefuck" | ||
echo "" | ||
echo "To install from sources run:" | ||
echo "python setup.py build && python setup.py install" | ||
python setup.py build && python setup.py install | ||
Comment on lines
+5
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If a user comes to this point they know how to install things in their Python environment (or virtual environment). There's no intention of recommending anything at this point. Also, this should not be part of the pull request. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,3 +9,4 @@ pypandoc | |
pytest-benchmark | ||
pytest-docker-pexpect | ||
twine | ||
openai | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The introduction of a new hard dependency has huge consequences downstream. Not to mention this is a dependency for something optional. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,7 +31,7 @@ | |
' ({}.{} detected).'.format(*version)) | ||
sys.exit(-1) | ||
|
||
VERSION = '3.32' | ||
VERSION = '3.33' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A new release is always decoupled of specific changes. |
||
|
||
install_requires = ['psutil', 'colorama', 'six'] | ||
extras_require = {':python_version<"3.4"': ['pathlib2'], | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,6 +37,25 @@ def _add_arguments(self): | |
'-h', '--help', | ||
action='store_true', | ||
help='show this help message and exit') | ||
self._parser.add_argument( | ||
'-c', '--chatgpt', | ||
type=int, | ||
default=1, | ||
help='number of ChatGPT suggestions. set to 0 to disable ChatGPT' | ||
) | ||
# todo Secret parameters only revealed with `thefuck --help --chatgpt` | ||
# self._parser.add_argument( | ||
# '-t', '--chatgpt-token', | ||
# type=int, | ||
# default=400, | ||
# help='maximum ChatGPT tokens per query' | ||
# ) | ||
# self._parser.add_argument( | ||
# '-m', '--chatgpt-model', | ||
# type=str, | ||
# default="gpt-3.5-turbo", | ||
# help='ChatGPT model' | ||
# ) | ||
Comment on lines
+46
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Commented code is dead code. Commented code should never be committed. |
||
self._add_conflicting_arguments() | ||
self._parser.add_argument( | ||
'-d', '--debug', | ||
|
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,77 @@ | ||||||||||
import platform | ||||||||||
import openai | ||||||||||
import re | ||||||||||
import os | ||||||||||
from thefuck import logs | ||||||||||
from thefuck.conf import settings | ||||||||||
|
||||||||||
|
||||||||||
def _check_chatgpt(api_key: str = None) -> bool: | ||||||||||
openai.api_key = os.getenv("THEFUCK_OPENAI_TOKEN") or os.getenv("OPENAI_API_KEY") | ||||||||||
if settings["chatgpt"] > 0 and (api_key or openai.api_key): | ||||||||||
return True | ||||||||||
return False | ||||||||||
Comment on lines
+11
to
+13
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
|
||||||||||
|
||||||||||
enabled_by_default = _check_chatgpt() | ||||||||||
logs.debug(f"ChatGPT enabled: {enabled_by_default}") | ||||||||||
|
||||||||||
MAX_NUMBER = settings["chatgpt"] or 1 | ||||||||||
MAX_TOKENS = settings["chatgpt_token"] or 400 | ||||||||||
MODEL = settings["chatgpt_model"] or "gpt-3.5-turbo" | ||||||||||
|
||||||||||
|
||||||||||
def match(command): | ||||||||||
return _check_chatgpt() | ||||||||||
|
||||||||||
|
||||||||||
def get_new_command(command): | ||||||||||
result = _query_chatgpt( | ||||||||||
command=command.script, | ||||||||||
error=command.output, | ||||||||||
explanation=False, | ||||||||||
) | ||||||||||
logs.debug(f"chatgpt result: {result}") | ||||||||||
return result | ||||||||||
|
||||||||||
|
||||||||||
def _query_chatgpt( | ||||||||||
command: str, | ||||||||||
error: str, | ||||||||||
explanation: bool, # can be used to include explanations but not used yet | ||||||||||
number: int = MAX_NUMBER, | ||||||||||
model: str = MODEL, | ||||||||||
max_tokens: int = MAX_TOKENS, | ||||||||||
api_key: str = None, | ||||||||||
Comment on lines
+39
to
+45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nowhere else in The Fuck's code there's use of such syntax. This code would be very alien to the existing code base and therefore awckward to maintain, to say the least. |
||||||||||
): | ||||||||||
if api_key: | ||||||||||
openai.api_key = api_key | ||||||||||
elif openai.api_key is None: | ||||||||||
return [] | ||||||||||
|
||||||||||
os_env = f"{platform.platform()}" | ||||||||||
prompt = f""" | ||||||||||
OS: `{os_env}` | ||||||||||
Command: `{command}` | ||||||||||
Error: `{error}` | ||||||||||
Suggest {"one command" if number == 1 else f"{number} commands"} {"with" if explanation else "without"} explanation. | ||||||||||
Commands:""" | ||||||||||
|
||||||||||
logs.debug("chatgpt: " + prompt) | ||||||||||
|
||||||||||
try: | ||||||||||
response = openai.ChatCompletion.create( | ||||||||||
model=model, | ||||||||||
messages=[ | ||||||||||
{"role": "user", "content": prompt}, | ||||||||||
], | ||||||||||
max_tokens=max_tokens, | ||||||||||
) | ||||||||||
content = response["choices"][0]["message"]["content"] | ||||||||||
contents = [item.strip() for item in content.split("\n") if item.strip() != ""] | ||||||||||
pattern = re.compile(r"^\d+\.\ *") | ||||||||||
cleaned_contents = [re.sub(pattern, "", item).strip('`') for item in contents] | ||||||||||
return cleaned_contents | ||||||||||
Comment on lines
+73
to
+74
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Return a generator instead. That's how The Fuck is designed. |
||||||||||
except Exception as e: | ||||||||||
logs.debug(f"chatgpt error: {e}") | ||||||||||
return [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is very different from any other user interaction with The Fuck.