Projects STRLCPY stackexplain Commits e5b5766b
🤬
  • Stylized things more, added ability to log in to OpenAI

  • Loading...
  • shobrook committed 1 year ago
    e5b5766b
    1 parent 2ed642de
  • ■ ■ ■ ■ ■
    stackexplain/__main__.py
     1 +# Local
    1 2  from stackexplain import main
    2 3   
    3 4   
    skipped 3 lines
  • ■ ■ ■ ■ ■
    stackexplain/stackexplain.py
     1 +# Standard library
    1 2  import sys
    2 3   
     4 +# Local
    3 5  import utilities.chatgpt as gpt
    4 6  import utilities.parsers as parsers
    5 7  import utilities.printers as printers
    6 8  import utilities.code_execution as code_exec
     9 + 
     10 + 
     11 +######
     12 +# MAIN
     13 +######
    7 14   
    8 15   
    9 16  def main():
    skipped 20 lines
    30 37   print()
    31 38   
    32 39   with printers.LoadingMessage(): # Context-based loading message
     40 + import time
     41 + time.sleep(3)
    33 42   explanation = gpt.get_chatgpt_explanation(language, error_message)
    34  - 
    35  - # TODO: Add syntax highlighting to code
    36 43   
    37 44   printers.print_error_explanation(explanation)
    38 45   
  • ■ ■ ■ ■ ■ ■
    stackexplain/utilities/chatgpt.py
     1 +# Standard library
     2 +import json
     3 +import os.path as path
     4 + 
     5 +# Third party
    1 6  from revChatGPT.revChatGPT import Chatbot
    2 7   
    3  -# TEMP: Have user fill this out
    4  -config = {}
     8 +# Local
     9 +from utilities.printers import prompt_user_for_credentials
     10 + 
     11 +CONFIG_FP = path.join(path.expanduser("~"), ".stackexplain.json")
    5 12   
    6 13   
    7 14  #########
    skipped 2 lines
    10 17   
    11 18   
    12 19  def construct_query(language, error_message):
     20 + # TODO: Create an class for mapping languages to exec commands
    13 21   language = "java" if language == "javac" else language
    14 22   language = "python" if language == "python3" else language
    15 23   language = "go" if language == "go run" else language
    16 24   
    17  - # TODO: Create an enum for mapping languages to exec commands
    18 25   query = f"Explain this {language} error message in brief and simple terms:"
    19 26   query += "\n```"
    20 27   query += f"\n{error_message}"
    skipped 8 lines
    29 36   
    30 37   
    31 38  def is_user_registered():
    32  - return True # TODO
     39 + return path.exists(CONFIG_FP)
    33 40   
    34 41   
    35 42  def register_openai_credentials():
    36  - pass # TODO
     43 + email, password = prompt_user_for_credentials()
     44 + config = {"email": email, "password": password}
     45 + 
     46 + with open(CONFIG_FP, "w") as config_file:
     47 + json.dump(config, config_file)
    37 48   
    38 49   
    39 50  def get_chatgpt_explanation(language, error_message):
     51 + config = json.load(open(CONFIG_FP))
    40 52   query = construct_query(language, error_message)
    41  - chatbot = Chatbot(config, conversation_id=None)
    42  - return chatbot.get_chat_response(query)["message"].strip()
     53 + chatbot = Chatbot(config)
     54 + return chatbot.get_chat_response(query).strip()
    43 55   
  • ■ ■ ■ ■ ■ ■
    stackexplain/utilities/code_execution.py
     1 +# Standard library
    1 2  import os
    2 3  from queue import Queue
    3 4  from subprocess import PIPE, Popen
    4 5  from threading import Thread
    5 6   
     7 +# Local
    6 8  from utilities.parsers import get_code_exec_command, get_error_message
    7 9   
    8 10   
    skipped 19 lines
    28 30   Pulls output from shared queue and prints to terminal.
    29 31   """
    30 32   
     33 + print()
    31 34   for line in iter(get, None):
    32 35   line = line.replace("\n", "")
    33 36   print(line)
    skipped 55 lines
  • ■ ■ ■ ■ ■
    stackexplain/utilities/parsers.py
     1 +# Standard library
    1 2  import re
    2 3   
    3 4   
    skipped 33 lines
    37 38   
    38 39   
    39 40  def get_error_message(error, language):
    40  - """Filters the stack trace from stderr and returns only the error message."""
     41 + """
     42 + Filters the stack trace from stderr and returns only the error message.
     43 + """
     44 + 
    41 45   if error == '' or error is None:
    42 46   return None
    43 47   elif language == "python3":
    skipped 27 lines
  • ■ ■ ■ ■ ■ ■
    stackexplain/utilities/printers.py
     1 +# Standard library
    1 2  import sys
    2 3  from itertools import cycle
    3 4  from shutil import get_terminal_size
    skipped 1 lines
    5 6  from time import sleep
    6 7  from random import random
    7 8   
     9 +# Third party
     10 +from pygments import highlight
     11 +from pygments.lexers import get_lexer_by_name
     12 +from pygments.formatters import Terminal256Formatter
     13 + 
     14 +CODE_IDENTIFIER = "```"
     15 +CODE_INDENT = " "
     16 + 
    8 17  # ASCII color codes
    9  -GREEN = '\033[92m'
    10  -GRAY = '\033[90m'
    11  -CYAN = '\033[36m'
    12  -RED = '\033[31m'
    13  -YELLOW = '\033[33m'
    14  -END = '\033[0m'
    15  -UNDERLINE = '\033[4m'
    16  -BOLD = '\033[1m'
     18 +GREEN = "\033[92m"
     19 +GRAY = "\033[90m"
     20 +CYAN = "\033[36m"
     21 +RED = "\033[31m"
     22 +YELLOW = "\033[33m"
     23 +END = "\033[0m"
     24 +UNDERLINE = "\033[4m"
     25 +BOLD = "\033[1m"
     26 + 
     27 + 
     28 +#########
     29 +# HELPERS
     30 +#########
     31 + 
     32 + 
     33 +def slow_print(text, delay=0.01):
     34 + for word in text:
     35 + sys.stdout.write(word)
     36 + sys.stdout.flush() # Defeat buffering
     37 + 
     38 + sleep(delay)
    17 39   
    18 40   
    19 41  ######
    skipped 1 lines
    21 43  ######
    22 44   
    23 45   
    24  -def register_openai_credentials():
    25  - pass # TODO
    26  - 
    27  - 
    28 46  def print_help_message():
    29 47   pass # TODO
    30 48   
    skipped 3 lines
    34 52   print(f"\n{RED}Sorry, stackexplain doesn't support this file type.\n{END}")
    35 53   
    36 54   
     55 +def prompt_user_for_credentials():
     56 + print(f"{BOLD}Please enter your OpenAI credentials.{END}\n")
     57 + email = input("Email address: ")
     58 + password = input("Password: ")
     59 + 
     60 + return email, password
     61 + 
     62 + 
    37 63  class LoadingMessage:
    38 64   def __init__(self, timeout=0.1):
    39 65   """
    skipped 6 lines
    46 72   """
    47 73   
    48 74   self.steps = ["⢿", "⣻", "⣽", "⣾", "⣷", "⣯", "⣟", "⡿"]
    49  - self.message = "Asking ChatGPT to explain your error"
    50  - # self.end = ""
     75 + self.message = f"{BOLD}{CYAN}Asking ChatGPT to explain your error{END}"
     76 + self.end = f"{BOLD}{CYAN}🤖 ChatGPT's Explanation:{END}"
    51 77   self.timeout = timeout
    52 78   
    53 79   self._thread = Thread(target=self._animate, daemon=True)
    skipped 7 lines
    61 87   self.done = True
    62 88   cols = get_terminal_size((80, 20)).columns
    63 89   
    64  - print("\r" + " " * cols, end="", flush=True)
    65  - # print(f"\r{self.end}", flush=True)
     90 + print(f"\r{' ' * cols}", end="", flush=True)
     91 + print(f"\r{self.end}\n", flush=True)
    66 92   
    67 93   def _animate(self):
    68 94   for step in cycle(self.steps):
    69 95   if self.done:
    70 96   break
    71 97   
    72  - print(f"\r{step} {self.message}", flush=True, end="")
     98 + print(f"\r{CYAN}{step}{END} {self.message}", flush=True, end="")
    73 99   
    74 100   sleep(self.timeout)
    75 101   
    skipped 1 lines
    77 103   self.start()
    78 104   
    79 105   def __exit__(self, exc_type, exc_value, tb):
    80  - # handle exceptions with those variables ^
    81 106   self.stop()
    82 107   
    83 108   
    84 109  def print_error_explanation(explanation):
    85  - for word in f"{explanation}\n":
    86  - sys.stdout.write(word)
    87  - sys.stdout.flush() # Defeat buffering
    88  - sleep(0.01)
     110 + for i, text in enumerate(explanation.split(CODE_IDENTIFIER)):
     111 + if not i % 2:
     112 + # TODO: Handle bolds
     113 + slow_print(text)
     114 + 
     115 + continue
     116 + 
     117 + code = highlight(
     118 + text,
     119 + lexer=get_lexer_by_name("python"),
     120 + formatter=Terminal256Formatter(style="solarized-dark")
     121 + )
     122 + for line in code.strip().split("\n"):
     123 + slow_print(f"{CODE_INDENT}{line}", delay=0.001)
     124 + print()
     125 + 
     126 + print("\n")
    89 127   
Please wait...
Page is in error, reload to recover