Spaces:
Runtime error
Runtime error
""" | |
Details : AutoBard-Coder is code genrator for bard. It is used to generate code from bard response. | |
its using Bard API to interact with bard and refine the results for coding purpose. | |
The main purpose of this is for research and educational purpose. | |
This is using unofficial bard api and not affiliated with bard in any way - So use it at your own risk. | |
This can generate the code from prompt and fix itself unless the code is fixed. | |
Language : Python | |
Dependencies : streamlit, bard-coder | |
Author : HeavenHM. | |
License : MIT | |
Date : 21-05-2023 | |
""" | |
# Import the required libraries | |
import streamlit as st | |
from os import path | |
import time | |
import traceback | |
from lib.bardcoder_lib import BardCoder | |
import subprocess | |
from io import StringIO | |
import re | |
from lib.sharegpt_api import sharegpt_get_url | |
from lib.blacklist_commands import harmful_commands_python, harmful_commands_cpp, harmful_prompts | |
from PIL import Image | |
import tokenize | |
import io | |
# The input limit of Bard is 4,000 character (As per the Bard API documentation) | |
# But you can give more input upto 10,000 characters. so we are gonna stick to that. | |
BARD_FILE_SIZE_LIMIT = 10000 | |
# Function to measure the accuracy of the code | |
def measure_accuracy(counter): | |
accuracy = 1 / (counter + 1) | |
accuracy_percentage = accuracy * 100 | |
st.info(f"Output has been fixed {counter} times with accuracy {accuracy_percentage:.0f}%") | |
def show_content(content): | |
try: | |
# Open the file and read its contents | |
with open(content, "r") as f: | |
markdown_text = f.read() | |
# Display the Markdown text in the app | |
st.markdown(markdown_text) | |
except Exception as e: | |
BardCoder.write_log(f"Error in showing content {e}") | |
# method to execute the bard coder process | |
def auto_bard_execute(prompt, code_file='code.txt', code_choices='code_choice', expected_output=None, exec_type='single', rate_limiter_delay=5): | |
try: | |
# Additional prompt for class clarification. | |
# prompt += "\n" + f"Note: The Name the class should be {code_file} if Java language is requested" | |
# Additional prompt for no input clarification. | |
prompt += "\n" + "Dont ask the input from user.If input values are provided in code just use them. otherwise, you can hardcode the input values in code." | |
# Setting the prompt. | |
prompt_status, error_reason = st.session_state.bard_coder.set_prompt(prompt) | |
if not prompt_status: | |
st.error(f"Error no data was recieved from Server, Reason {error_reason}") | |
st.stop() | |
# Get the code from the response. | |
code = st.session_state.bard_coder.get_code() | |
# Save the code to file | |
saved_file = st.session_state.bard_coder.save_code(code_file, code) | |
if saved_file: | |
st.info(f"Code saved to file {saved_file}") | |
else: | |
st.info("Code not saved to file") | |
return None, None, False | |
st.info("Executing primary code") | |
# check for safe code to run. | |
code = st.session_state.bard_coder.read_file(saved_file) | |
safe_code = False | |
code_snippet = None | |
code_command = None | |
safe_code_dict = [] | |
if code: | |
safe_code_dict = is_code_safe(code) | |
# Get tuple from list of tuples code_safe_dict | |
safe_code = safe_code_dict[0][0] | |
code_command = safe_code_dict[0][1] | |
code_snippet = safe_code_dict[0][2] | |
if safe_code: | |
code_output = st.session_state.bard_coder.execute_code(saved_file) | |
if code_output and code_output != None and code_output.__len__() > 0: | |
if 'error' in code_output.lower() or 'exception' in code_output.lower(): | |
st.info(f"Error in executing code with type {exec_type}") | |
return code_output, saved_file, False | |
# Check if expected output is in code output. | |
if expected_output and expected_output in code_output: | |
code_choices_output = [code_output] | |
return code_output, saved_file, True | |
else: | |
if exec_type == 'single': | |
time.sleep(rate_limiter_delay) | |
return code_output, saved_file, False | |
else: | |
time.sleep(rate_limiter_delay) | |
else: | |
return code_output, saved_file, False | |
# Save all the code choices to file | |
if exec_type == 'multiple': | |
st.session_state.bard_coder.save_code_choices(code_choices) | |
st.info("Executing code choices") | |
code_choices_output = st.session_state.bard_coder.execute_code_choices() | |
code_choices_output.append(code_output) | |
st.info(f"Output: {code_choices_output}") | |
return code_choices_output, saved_file, False | |
else: | |
for safe_codes in safe_code_dict: | |
if safe_codes[0]: # Skip if code is safe | |
continue | |
safe_code = safe_codes[0] | |
code_command = safe_codes[1] | |
code_snippet = safe_codes[2] | |
st.error(f"Error: Cannot execute the code because of illegal command found '{code_command}' in code snippet '{code_snippet}'") | |
BardCoder.write_log(f"Cannot run the code:\n'{code}'\nbecause of illegal command found '{code_command}' in code snippet '{code_snippet}'") | |
st.stop() | |
return None, None, False | |
except Exception as e: | |
# show_outputf the stack trace | |
stack_trace = traceback.format_exc() | |
st.info(stack_trace) | |
st.info(str(e)) | |
BardCoder.add_log(str(e)) | |
# method to execute the bard coder process | |
def auto_bard_setup(prompt, code_file='code.txt', code_choices='code_choice', expected_output=None, exec_type='single', rate_limiter_delay=5): | |
# Append the codes directory to filename | |
code_file = path.join("codes", code_file) | |
test_cases_output = 0 # Test cases for output. | |
# Start the bard coder process | |
code_choices_output, saved_file, status = auto_bard_execute( | |
prompt, code_file, code_choices, expected_output, exec_type) | |
code_output = None | |
# Check if file is saved. | |
if not saved_file: | |
return code_choices_output, saved_file, status | |
if status: | |
st.info( | |
f"Expected output found in file {saved_file}\nOutput: {code_choices_output}") | |
else: | |
st.info( | |
f"Expected output not found in file {saved_file}\nOutput: {code_choices_output}") | |
if code_choices_output: | |
code_output = ''.join(code_choices_output) | |
if code_output and code_output != None and code_output.__len__() > 0: | |
# Check for errors like 'error' or 'Error' check case sensitivity and add more error checks. | |
if code_output is not None: | |
code_output = "".join(code_output) | |
else: | |
code_output = "" | |
if code_output: | |
while 'error' in code_output.lower() or 'exception' in code_output.lower(): | |
st.info( | |
"Error in executing code,Trying to fix the code with error") | |
# Re-prompt on error. | |
code = st.session_state.bard_coder.get_code() | |
prompt = f"I got error while running the code {code_output}.\nPlease fix the code ``\n`{code}\n``` \nand try again.\nHere is error {code_output}\n\n" + \ | |
"Note:The output should only be fixed code and nothing else. No explanation or anything else." | |
# Start the bard coder process again. | |
code_output, saved_file, status = auto_bard_execute( | |
prompt, code_file, code_choices, expected_output, exec_type) | |
# Sleep for 5 seconds before re-prompting. Dont get Rate limited. | |
time.sleep(rate_limiter_delay) | |
test_cases_output += 1 | |
st.info("Code has been fixed for errors") | |
st.code(code_output, language="python") | |
# Check for expected output. | |
if code_output and expected_output and code_output.__len__() > 0: | |
# While expected output does not contain in code output. | |
while expected_output not in code_output: | |
st.info( | |
f"Expected output {expected_output} not found in code\nOutput: {code_output}") | |
# Re-prompt on expected output not found. | |
code = st.session_state.bard_coder.get_code() | |
prompt = f"I got output {code_output}.\nPlease fix the code ``\n`{code}\n``` \nand try again.\nHere is expected output: {code_output}\n\n" + \ | |
"Note:The output should only be fixed code and nothing else. No explanation or anything else." | |
# start the bard coder process again. | |
code_output, saved_file, status = auto_bard_execute( | |
prompt, code_file, code_choices, expected_output, exec_type) | |
# Sleep for N seconds before re-prompting. Dont get Rate limited. | |
time.sleep(rate_limiter_delay) | |
test_cases_output += 1 | |
st.info("Code has been fixed for expected output") | |
st.info(code_output) | |
else: | |
st.info("Not checking for code expected output") | |
else: | |
st.info("Code output is empty for error") | |
# Print output and information. | |
measure_accuracy(test_cases_output) | |
content_file = "response/content.md" | |
show_content(content_file) | |
return code_output, saved_file, status | |
def find_image_files(file_path): | |
try: | |
# Create a regular expression for image files | |
image_regex = re.compile(r"\b\w+\.(png|jpg|jpeg|gif|bmp)", re.IGNORECASE) | |
# Open the code file | |
with open(file_path) as f: | |
# Read the lines | |
lines = f.readlines() | |
# Loop through the lines | |
for line in lines: | |
# Search for image files in the line | |
match = image_regex.search(line) | |
# If there is a match | |
if match: | |
# Get the image file name | |
image_file = match.group() | |
# Print the image file name | |
return image_file | |
except Exception as e: | |
BardCoder.write_log(f"Error in finding image files {e}") | |
return None | |
def is_prompt_safe(prompt): | |
if prompt is None: | |
BardCoder.write_log("Prompt is Empty") | |
return False | |
BardCoder.write_log("Checking prompt for safety") | |
# Extra care for prompt input. | |
prompt_list = [re.sub(r'[^\w\s]', '', re.sub(r'(\*\*|__)(.*?)(\*\*|__)', r'\2', re.sub( | |
r'^\W+|\W+$', '', item))).strip() for item in re.split('\n| ', prompt.lower()) if item.strip() != ''] | |
prompt_list = [re.sub(r'\d+', '', i) for i in prompt_list] | |
BardCoder.write_log(f"Prompt list is {prompt_list}") | |
# Convert the code to lowercase and split it into a list of words | |
# Check if any harmful command is in the list of words | |
for command in harmful_prompts: | |
if command in prompt_list: | |
BardCoder.write_log(f"Prompt is not safe because of illegal command found '{command}'") | |
return False, command | |
BardCoder.write_log(f"Input Prompt is safe") | |
return True, None | |
def tokenize_source_code(source_code): | |
tokens = [] | |
try: | |
for token in tokenize.generate_tokens(io.StringIO(source_code).readline): | |
if token.type not in [tokenize.ENCODING, tokenize.NEWLINE, tokenize.INDENT, tokenize.DEDENT]: | |
if any(char in token.string for char in ['::', '.', '->', '_']) or token.string.isalnum(): | |
token_str = re.sub(r'\'|\"', '', token.string) | |
tokens.append(token_str) | |
except tokenize.TokenError: | |
if st.session_state.bard_coder: | |
BardCoder.write_log("Error parsing the tokens") | |
if tokens: | |
tokens = list(([token.lower() for token in tokens])) | |
if st.session_state.bard_coder: | |
BardCoder.write_log(f"Tokenise was called and Tokens length is {tokens.__len__()}") | |
return tokens | |
def is_code_safe(code): | |
if st.session_state.bard_coder: | |
BardCoder.write_log("Checking code for safety") | |
# Combine both lists | |
harmful_code_commands = harmful_commands_python + harmful_commands_cpp | |
# Tokenize the code | |
tokens_list = tokenize_source_code(code) | |
# Initialize the output dictionary | |
output_dict = [] | |
# Check if any harmful command is in the list of words | |
for command in harmful_code_commands: | |
for token in tokens_list: | |
if command == token: | |
output_dict.append((False, command, token)) | |
if output_dict is None or output_dict.__len__() == 0: | |
output_dict = [(True, None, None)] | |
if st.session_state.bard_coder: | |
BardCoder.write_log(f"Output dict is {output_dict}") | |
return output_dict | |
def load_css(file_name): | |
try: | |
# Open the file and read the content | |
with open(file_name) as fp: | |
css = fp.read() | |
# Use st.components.v1.html to load the CSS file | |
st.markdown(f'<style>{css}</style>', unsafe_allow_html=True) | |
except Exception as e: | |
BardCoder.write_log(f"Error in loading css {e}") | |
def display_logo(logo_file: str, title: str): | |
# create two columns | |
col1, col2 = st.columns(2, gap='large') | |
# use the first column for the image | |
col1.image(logo_file, width=370) | |
# use the second column for the title | |
col2.title(title) | |
def dsiplay_buttons(is_prompt_valid: bool): | |
col1, col2, col3 = st.columns(3, gap='large') | |
with col1: # use the first column | |
run_button = st.button("Run", key="run-button", use_container_width=True, | |
disabled=not is_prompt_valid) # place the run button as a regular button | |
with col2: # use the second column | |
share_button = st.button("Share", key="share-button", use_container_width=True, | |
disabled=not is_prompt_valid) # place the share button as a regular button | |
with col3: | |
# place the help button as a regular button | |
help_button = st.button( | |
"Help", key="help-button", use_container_width=True) | |
return run_button, share_button, help_button | |
def init_bard_coder_session(api_key=None, timeout=10): | |
# Initialize the bard coder session | |
bard_coder = BardCoder(api_key=api_key, enable_logs=True, timeout=timeout) | |
return bard_coder | |
def init_session_state(): | |
# Initialize the session state variables | |
if "bard_coder" not in st.session_state: | |
st.session_state.bard_coder = None | |
if "api_key_initialized" not in st.session_state: | |
st.session_state.api_key_initialized = False | |
if "code_output" not in st.session_state: | |
st.session_state.code_output = "" | |
if "messages" not in st.session_state: | |
st.session_state.messages = "" | |
if "text_area" not in st.session_state: | |
st.session_state.text_area = "" | |
if "file_size" not in st.session_state: | |
st.session_state.file_size = 0 | |
if "file_char_count" not in st.session_state: | |
st.session_state.file_char_count = 0 | |
import os | |
from stat import S_IREAD, S_IRGRP, S_IROTH | |
def make_code_interpreter_read_only(): | |
filename = __file__ | |
BardCoder.write_log(f"Making {filename} read-only") | |
os.chmod(filename, S_IREAD|S_IRGRP|S_IROTH) | |
# Make all files in lib folder read-only | |
folder = "lib" | |
for filename in os.listdir(folder): | |
filepath = os.path.join(folder, filename) | |
os.chmod(filepath, S_IREAD|S_IRGRP|S_IROTH) | |
if __name__ == "__main__": | |
try: | |
BardCoder.write_log("Starting the streamlit App") | |
make_code_interpreter_read_only() | |
# Load the CSS file named style.css | |
load_css("styles/style.css") | |
# Upload file data variables | |
upload_prompt_data, upload_data, uploaded_file = None, None, None | |
# Initialize the session state variables | |
BardCoder.write_log("Initializing the session state variables") | |
init_session_state() | |
BardCoder.write_log("Session state variables initialized") | |
# Set the logo and title | |
logo_file = "resources/logo.png" | |
title = "Code Interpreter" | |
display_logo(logo_file, title) | |
BardCoder.write_log("Logo and title set") | |
# Use the text_area variable from the session state for input | |
prompt = st.text_area(placeholder="Enter your prompt here", label="Prompt",label_visibility="hidden", height=300, key="text_area_input") | |
# check if prompt is changed. | |
if prompt != st.session_state.text_area: | |
BardCoder.write_log(f"Prompt changed from '{st.session_state.text_area}' to '{prompt}'") | |
st.session_state.text_area = prompt | |
character_count: int = len(st.session_state.text_area) | |
# Status info message. (Char count and file size) | |
status_info_msg = f"Characters:{character_count}/{BARD_FILE_SIZE_LIMIT}" | |
if st.session_state.file_size > 0: | |
BardCoder.write_log(f"File Char count is {st.session_state.file_char_count}") | |
character_count += st.session_state.file_char_count | |
# Update the character count for file size. | |
status_info_msg = f"Characters:{character_count}/{BARD_FILE_SIZE_LIMIT}" | |
status_info_msg += " | " + f"File Size is {st.session_state.file_size/1024:.2f}Kb | {st.session_state.file_size/1024/1024:.2f}Mb" | |
st.info(status_info_msg) | |
# check the Prompt for safety and file size exceeding 4,000 characters. | |
prompt_safe = True | |
if st.session_state.bard_coder: | |
prompt_safe, command = is_prompt_safe(prompt) | |
if not prompt_safe: | |
BardCoder.write_log(f"Error in prompt because of unsafe command found '{command}'") | |
st.error(f"Error in prompt because of illegal command found '{command}'") | |
if character_count > BARD_FILE_SIZE_LIMIT or st.session_state.file_char_count > BARD_FILE_SIZE_LIMIT: | |
st.error(f"Error in prompt The file size limit exceeded {BARD_FILE_SIZE_LIMIT} characters") | |
# Setting options for the application | |
with st.expander("Options"): | |
try: | |
code_file = st.text_input("Filename for the generated code (without extension):", value="generated_code") | |
code_choices = st.text_input("Filename for code choices:", value="code_choices") | |
expected_output = st.text_input("Expected output (leave blank if none):") | |
exec_type = st.selectbox("Execution type:", ["single", "multiple"], index=0) | |
timeout_delay = st.number_input("Timeout (in seconds):", value=10) | |
# Adding the upload file option | |
uploaded_file = st.file_uploader("Choose a file") | |
if uploaded_file is not None: | |
# To read file as bytes: | |
bytes_data = uploaded_file.getvalue() | |
# get the file size | |
st.session_state.file_size = uploaded_file.size | |
# To convert to a string based IO: | |
stringio = StringIO(uploaded_file.getvalue().decode("utf-8")) | |
# To read file as string: | |
upload_data = stringio.read() | |
# Count the number of characters in the file | |
st.session_state.file_char_count = len(upload_data) | |
# write the file to uploads directory | |
with open("uploads/" + uploaded_file.name, "w") as f: | |
f.write(upload_data) | |
# Display a success message | |
st.success("File uploaded successfully.") | |
except Exception as e: | |
BardCoder.write_log(f"Error in options {e}") | |
# Adding settings for the application | |
with st.expander("Settings"): | |
bard_key_help_text = """ | |
How to obtain Google Bard API key. | |
1. Visit bard.google.com and open the console with F12 | |
2. Go to Application → Cookies and copy the __Secure-1PSID value | |
3. This is your API key paste it below. | |
""" | |
st.info(bard_key_help_text) | |
bard_api_key = st.text_input(label="API Key", label_visibility="hidden", type="password", placeholder="Enter your bard API key.") | |
if bard_api_key and not st.session_state.api_key_initialized: | |
# how to call write_file static method from BardCoder class | |
BardCoder.write_log("Starting init API Key") | |
st.session_state.bard_coder = init_bard_coder_session(bard_api_key,timeout_delay) | |
if BardCoder.bard_init: | |
st.session_state.api_key_initialized = True | |
BardCoder.write_log("Bard Coder initialized successfully") | |
st.info("Bard Coder initialized successfully") | |
else: | |
st.session_state.api_key_initialized = False | |
BardCoder.write_log("Error initializing Bard Coder") | |
st.error("Error initializing Bard Coder") | |
# Setting advanced options for the application | |
with st.expander("Advanced"): | |
try: | |
# button to show logs. | |
show_logs = st.button("Show Logs", key="show-logs-button", use_container_width=True) | |
if show_logs: | |
if st.session_state.bard_coder: | |
logs_data = st.session_state.bard_coder.read_file(st.session_state.bard_coder.logs_file) | |
st.code(logs_data, language="python") | |
except Exception as e: | |
st.error(f"Error in showing logs {e}") | |
# button to show content. | |
try: | |
show_content_button = st.button("Show Content", key="show-content-button", use_container_width=True) | |
if show_content_button: | |
if st.session_state.bard_coder: | |
content_data = st.session_state.bard_coder.read_file("response/response.md") | |
st.code(content_data, language="python") | |
except Exception as e: | |
st.error(f"Error in showing content {e}") | |
# button to show response. | |
try: | |
show_response_button = st.button("Show Response", key="show-response-button", use_container_width=True) | |
if show_response_button: | |
if st.session_state.bard_coder: | |
response_data = st.session_state.bard_coder.read_file("response/response.json") | |
st.code(response_data, language="json") | |
except Exception as e: | |
st.error(f"Error in showing response {e}") | |
# Setting the buttons for the application | |
run_button, share_button, help_button = dsiplay_buttons(prompt_safe and st.session_state.file_char_count < BARD_FILE_SIZE_LIMIT) | |
# Setting application to run | |
if run_button: | |
# Check if API Key is empty | |
if bard_api_key is None or bard_api_key == "" or bard_api_key.__len__() == 0: | |
st.error("Error executing code the API key is missing from settings.\nPlease go to settings and add your API key.") | |
BardCoder.write_log("Error executing code the API key is missing from settings.Please go to settings and add your API key.") | |
st.stop() | |
# Clear the previous cache. | |
st.info("Running the code interpreter...") | |
subprocess.call(['bash', 'bash_src/clear_cache.sh']) | |
# Append the uploaded file data to prompt | |
if upload_data: | |
prompt += "\n" + f"Here is the file called {uploaded_file.name} at location {'uploads/' + uploaded_file.name} data.\n" + \ | |
f"```\n{upload_data}\n```" | |
# If graph were requested. | |
if 'graph' in prompt.lower(): | |
prompt += "\n" + "using Python use Matplotlib save the graph in file called 'graph.png'" | |
# if Chart were requested | |
if 'chart' in prompt.lower() or 'plot' in prompt.lower(): | |
prompt += "\n" + "using Python use Plotly save the chart in file called 'chart.png'" | |
# if Table were requested | |
if 'table' in prompt.lower(): | |
prompt += "\n" + "using Python use Pandas save the table in file called 'table.md'" | |
# Refine the prompt for harmful commands. | |
try: | |
if prompt_safe: | |
# Run the auto bard setup process. | |
log_container = st.empty() | |
st.session_state.code_output, saved_file, status = auto_bard_setup(prompt, code_file, code_choices,expected_output, exec_type,timeout_delay) | |
else: | |
st.error(f"Cannot execute the prompt because of illegal command found '{command}'") | |
BardCoder.write_log(f"Cannot execute the prompt: '{prompt}' because of illegal command found '{command}'") | |
st.stop() | |
except Exception as e: | |
BardCoder.write_log(f"Error in auto bard setup {e}") | |
# Check if output is Graph,Chart request. | |
if 'graph' in prompt.lower() or 'chart' in prompt.lower(): | |
image_file_graph = find_image_files(saved_file) | |
if image_file_graph: | |
BardCoder.write_log(f"Graph image file is {image_file_graph} and code file is {saved_file}") | |
image = Image.open(image_file_graph) | |
st.image(image, caption='Graph Output') | |
# Check if output in Table request. | |
if 'table' in prompt.lower(): | |
table_file = "table.md" | |
table_file_data = st.session_state.bard_coder.read_file( | |
table_file) | |
if table_file_data: | |
st.markdown(table_file_data) | |
# Adding Share button | |
if share_button: | |
if st.session_state.code_output is None or st.session_state.messages is None: | |
BardCoder.write_log("ShareGPT: Error Please run the code generator first") | |
st.error("Error: Please run the code generator first") | |
else: | |
gpt_data = prompt | |
human_data = "" | |
if st.session_state.messages: | |
human_data = "Bard Logs: \n" + st.session_state.messages | |
if st.session_state.code_output: | |
human_data += "\nOutput:\n" + st.session_state.code_output | |
human_data += "\n\n[AutoBard-Coder: Repo](https:#github.com/haseeb-heaven/AutoBard-Coder)" | |
if gpt_data.__len__() > 0 and human_data.__len__() > 0: | |
sharegpt_url = sharegpt_get_url(gpt_data, human_data) | |
st.info(f"ShareGPT Url: {sharegpt_url}") | |
else: | |
BardCoder.write_log("ShareGPT: Error Please run the code generator first") | |
st.error("Error: Please run the code generator first") | |
# Adding Help button | |
if help_button: | |
content_file = "README.md" | |
if st.session_state.bard_coder: | |
content_data = st.session_state.bard_coder.read_file(content_file) | |
st.markdown(content_data, unsafe_allow_html=True) | |
else: | |
st.error("API key is missing from settings.\nPlease go to settings and add your API key.") | |
BardCoder.write_log("Help: Error API key is missing from settings.") | |
except Exception as e: | |
# show_outputf the stack trace | |
stack_trace = traceback.format_exc() | |
st.error("Error: " + str(e)) | |
st.error(stack_trace) |