diff --git a/README.md b/README.md index 76c353c..900220d 100755 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@
- NeoGPT Gif +

NeoGPT 🚀

[![GitHub license](https://img.shields.io/github/license/neokd/NeoGPT)](https://github.com/neokd/NeoGPT/blob/main/LICENSE) @@ -9,9 +9,18 @@
-# Overview -NeoGPT is an AI assistant that runs locally on your machine. It transforms your workspace into a powerful environment with features like code interpretation, multi-RAG support, vision models, and LLM support. NeoGPT is designed to enhance your productivity and streamline your workflow. 🚀🧠 +
+ + Documentation + | + Discord + + Intro Image +
+ +# Introduction +NeoGPT is an AI assistant that transforms your local workspace into a powerhouse of productivity from your CLI. With features like code interpretation, multi-RAG support, vision models, and LLM integration, NeoGPT redefines how you work and create. Join the revolution and experience a new era of efficiency with NeoGPT. diff --git a/docs/assets/intro.png b/docs/assets/intro.png new file mode 100644 index 0000000..abc593e Binary files /dev/null and b/docs/assets/intro.png differ diff --git a/installers/install.sh b/installers/install.sh index 10767d0..fbfb83f 100755 --- a/installers/install.sh +++ b/installers/install.sh @@ -59,7 +59,7 @@ if [ "$continue_installation" == "y" ]; then echo -e "${NC}Run the following command to start NeoGPT:${NC}" echo -e "${YELLOW}python main.py --build${NC}" - echo -e "${NC} Refer docs at https://neokd.github.io/NeoGPT/ for more details.${NC}" + echo -e "${NC} Refer docs at https://docs.neogpt.dev/ for more details.${NC}" else echo -e "${YELLOW}Alright! If you change your mind, I'm here to help.${NC}" diff --git a/neogpt/agents/examples/calculate.py b/neogpt/agents/examples/calculate.py deleted file mode 100755 index e716d45..0000000 --- a/neogpt/agents/examples/calculate.py +++ /dev/null @@ -1,43 +0,0 @@ -import math - -from flask import Flask, request - -app = Flask(__name__) - - -@app.route("/calculate", methods=["GET", "POST"]) -def calculate(): - if request.method == "GET": - return """ -

Calculator

- -
- Operation:
-

- num1:
-

- num2:
-

- -
""" - else: - operation = request.form["operation"] - num1 = float(request.form["num1"]) - num2 = float(request.form["num2"]) - - if operation == "add": - result = num1 + num2 - elif operation == "subtract": - result = num1 - num2 - elif operation == "multiply": - result = num1 * num2 - elif operation == "divide": - result = num1 / num2 - else: - result = "Invalid operation" - - return f"""

Result: {result}

""" - - -if __name__ == "__main__": - app.run() diff --git a/neogpt/agents/examples/file_uploader.py b/neogpt/agents/examples/file_uploader.py deleted file mode 100755 index f4e3608..0000000 --- a/neogpt/agents/examples/file_uploader.py +++ /dev/null @@ -1,45 +0,0 @@ -from io import BytesIO - -import pandas as pd -import streamlit as st -from pdfminer.high_level import extract_text - -# Initialize the app -st.title("File Uploader") - -# Create a file uploader -with st.form("Upload File"): - file_upload = st.file_uploader("Select a file to upload:") - - # Check if a file is uploaded - if file_upload is not None: - # Display the file information - st.subheader("File Information") - filename = file_upload.name - size = file_upload.size - st.write(f"Filename: {filename}") - st.write(f"Size: {size} bytes") - - # Read the file content as bytes - content = file_upload.read() - - # Check file extension - file_extension = filename.split(".")[-1].lower() - - # Display the file content based on file extension - st.subheader("File Content") - - if file_extension == "pdf": - # Extract text from PDF using pdfminer.six - pdf_text = extract_text(BytesIO(content)) - st.text_area("Content:", pdf_text, height=300) - elif file_extension in ["xls", "xlsx"]: - # Read Excel file using pandas - excel_df = pd.read_excel(BytesIO(content)) - st.write("Preview of Excel Data:") - st.write(excel_df) - else: - # For other file types, display raw content - st.text_area("Content:", content.decode("utf-8"), height=300) - - st.form_submit_button("Upload") diff --git a/neogpt/agents/examples/password.py b/neogpt/agents/examples/password.py deleted file mode 100755 index 9fa3abe..0000000 --- a/neogpt/agents/examples/password.py +++ /dev/null @@ -1,63 +0,0 @@ -# Import required libraries -import random -import string -from datetime import datetime - -import streamlit as st - -st.title("Strong Password Generator") -# Set default values for sliders -password_length = 12 -num_digits = 3 -num_uppercase = 2 -num_lowercase = 2 -num_symbols = 1 - -# Get user input from sliders -password_slider = st.slider("Password Length", 8, 20, password_length) -num_slider_digits = st.slider("Number of Digits", 0, 5, num_digits) -num_slider_uppercase = st.slider("Number of Uppercase Letters", 0, 5, num_uppercase) -num_slider_lowercase = st.slider("Number of Lowercase Letters", 0, 5, num_lowercase) -num_slider_symbols = st.slider("Number of Symbols", 0, 5, num_symbols) - - -def generate_password(): - # Define character sets for each type of character - digits = string.digits - uppercase = string.ascii_uppercase - lowercase = string.ascii_lowercase - symbols = string.punctuation - - # Calculate the number of characters to generate based on user input - num_digit = int(num_slider_digits) - num_uppercase = int(num_slider_uppercase) - num_lowercase = int(num_slider_lowercase) - num_symbols = int(num_slider_symbols) - total_length = ( - password_slider - num_digit - num_uppercase - num_lowercase - num_symbols - ) - - # Generate the password using random characters from each set - password = ( - "".join(random.choices(digits, k=num_digit)) - + "".join(random.choices(uppercase, k=num_uppercase)) - + "".join(random.choices(lowercase, k=num_lowercase)) - + "".join(random.choices(symbols, k=num_symbols)) - ) - - # Convert the password to a list for shuffling - password_list = list(password) - - # Shuffle the characters within each character set - random.shuffle(password_list) - - # Convert the list back to a string - shuffled_password = "".join(password_list) - - return shuffled_password - - -# Generate and display the password -if st.button("Generate Password"): - generated_password = generate_password() - st.write(f"Generated Password: {generated_password}") diff --git a/neogpt/agents/examples/password_generator.py b/neogpt/agents/examples/password_generator.py deleted file mode 100755 index 0022129..0000000 --- a/neogpt/agents/examples/password_generator.py +++ /dev/null @@ -1,36 +0,0 @@ -import secrets - -import streamlit as st - - -def generate_password(length): - password = ( - ( - secrets.token_hex(length) - + secrets.token_hex(length) - + secrets.token_hex(length) - ) - .replace("\n", "") - .strip() - ) - return password - - -if __name__ == "__main__": - st.title("Strong Password Generator") - st.write("Enter the desired password length:") - - # Get the user input for password length - length_input = st.text_input(label="Enter length") - - if length_input: - # Check if the input is not empty - length = int(length_input) - - if length < 8: - st.write("Password length should be at least 8 characters.") - else: - password = generate_password(length) - st.write(f"Generated Password: {password}") - else: - st.write("Please enter a valid password length.") diff --git a/neogpt/agents/examples/sentiment.py b/neogpt/agents/examples/sentiment.py deleted file mode 100755 index 3f422fd..0000000 --- a/neogpt/agents/examples/sentiment.py +++ /dev/null @@ -1,39 +0,0 @@ -# Import required libraries -import streamlit as st -from textblob import TextBlob -from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer - -# Define the app layout with input boxes and dropdowns for model selection -st.set_page_config(page_title="Sentiment Analysis", layout="wide") -st.title("Sentiment Analysis") -st.subheader("Enter text to analyze sentiment") - -text_input = st.text_area("Text Input", value="", max_chars=200) -model_select = st.selectbox("Select a model:", ["TextBlob", "VADER"], index=0) -submit_button = st.button("Submit") - - -# Define the function to implement the sentiment analysis task using the selected model -def analyze_sentiment(text, model): - if model == "TextBlob": - blob = TextBlob(text) - return blob.sentiment.polarity - elif model == "VADER": - analyzer = SentimentIntensityAnalyzer() - return analyzer.polarity_scores(text)["compound"] - - -# Implement the sentiment analysis task using the selected model when the submit button is clicked -if submit_button: - if text_input: - sentiment = analyze_sentiment(text_input, model_select) - st.subheader("Sentiment Analysis Result") - if sentiment >= 0.5: - result = "Positive" - elif sentiment <= -0.5: - result = "Negative" - else: - result = "Neutral" - st.write(result) - else: - st.write("Please enter text to analyze sentiment") diff --git a/neogpt/agents/examples/snake.py b/neogpt/agents/examples/snake.py deleted file mode 100755 index d61c15b..0000000 --- a/neogpt/agents/examples/snake.py +++ /dev/null @@ -1,97 +0,0 @@ -import random -import time - -import pygame - -pygame.init() - -window_width = 800 -window_height = 600 - -screen = pygame.display.set_mode((window_width, window_height)) -pygame.display.set_caption("Snake Game") - -snake_width = 10 -snake_height = 10 -head_position = [300, 250] -move_direction = "right" -snake_length = 1 -snake_segments = [head_position.copy()] - -apple_position = [ - random.randrange(1, (window_width // 10)) * 10, - random.randrange(1, (window_height // 10)) * 10, -] - -clock = pygame.time.Clock() - - -def draw_snake(snake_segments): - for segment in snake_segments: - pygame.draw.rect( - screen, - (0, 0, 255), - pygame.Rect(segment[0], segment[1], snake_width, snake_height), - ) - - -def draw_apple(apple_position): - pygame.draw.rect( - screen, - (255, 0, 0), - pygame.Rect(apple_position[0], apple_position[1], snake_width, snake_height), - ) - - -while True: - for event in pygame.event.get(): - if event.type == pygame.QUIT: - pygame.quit() - quit() - elif event.type == pygame.KEYDOWN: - if event.key == pygame.K_LEFT: - move_direction = "left" - elif event.key == pygame.K_RIGHT: - move_direction = "right" - elif event.key == pygame.K_UP: - move_direction = "up" - elif event.key == pygame.K_DOWN: - move_direction = "down" - - if move_direction == "right": - head_position[0] += 10 - elif move_direction == "left": - head_position[0] -= 10 - elif move_direction == "up": - head_position[1] -= 10 - elif move_direction == "down": - head_position[1] += 10 - - # Check if the snake hits the wall - if ( - head_position[0] < 0 - or head_position[0] >= window_width - or head_position[1] < 0 - or head_position[1] >= window_height - ): - pygame.quit() - quit() - - snake_segments.insert(0, list(head_position)) - - if head_position == apple_position: - apple_position = [ - random.randrange(1, (window_width // 10)) * 10, - random.randrange(1, (window_height // 10)) * 10, - ] - snake_length += 1 - else: - snake_segments.pop() - - screen.fill((0, 0, 0)) - draw_apple(apple_position) - draw_snake(snake_segments) - - pygame.display.update() - - clock.tick(15) # Adjust the speed of the snake diff --git a/neogpt/agents/examples/streamlit_visualization.py b/neogpt/agents/examples/streamlit_visualization.py deleted file mode 100755 index f14e089..0000000 --- a/neogpt/agents/examples/streamlit_visualization.py +++ /dev/null @@ -1,49 +0,0 @@ -# filename: streamlit_visualization.py - -import matplotlib.pyplot as plt -import numpy as np -import streamlit as st -from sklearn.datasets import load_iris -from sklearn.linear_model import LogisticRegression -from sklearn.metrics import accuracy_score, classification_report - -# Load the iris dataset -iris = load_iris() -X = iris["data"] -y = iris["target"] - -# Create a logistic regression model and fit it to the data -model = LogisticRegression(max_iter=1000) -model.fit(X, y) -st.set_option("deprecation.showPyplotGlobalUse", False) -st.title("Iris Dataset Visualization") -# Make predictions on the test set -y_pred = model.predict(X) - - -# Calculate the accuracy of the model -accuracy = accuracy_score(y, y_pred) -print("Accuracy:", accuracy) - -# Get the classification report -classification_report_text = classification_report(y, y_pred) -print("\nClassification Report:\n", classification_report_text) - -st.write("Classification Report:\n", classification_report_text) - -# Create a scatter plot of the features and target variable -plt.scatter(X[:, 0], X[:, 1], c=y) -plt.xlabel("Sepal Length (cm)") -plt.ylabel("Sepal Width (cm)") -plt.title("Iris Dataset Visualization") -# plt.show() -st.subheader("Scatter Plot") -st.pyplot() - -# Create a histogram of the target variable -plt.hist(y, bins=[0, 1, 2], align="left", rwidth=0.8) -plt.xlabel("Target Variable") -plt.title("Iris Dataset Visualization") -plt.show() -st.subheader("Histogram") -st.pyplot() diff --git a/neogpt/agents/examples/terminal_snake.py b/neogpt/agents/examples/terminal_snake.py deleted file mode 100755 index f68ed04..0000000 --- a/neogpt/agents/examples/terminal_snake.py +++ /dev/null @@ -1,51 +0,0 @@ -import curses -import random - -s = curses.initscr() -curses.curs_set(0) -sh, sw = s.getmaxyx() -w = curses.newwin(sh, sw, 0, 0) -w.keypad(1) -w.timeout(100) - -snk_x = sw // 4 -snk_y = sh // 2 -snake = [[snk_y, snk_x], [snk_y, snk_x - 1], [snk_y, snk_x - 2]] - -food = [sh // 2, sw // 2] -w.addch(int(food[0]), int(food[1]), curses.ACS_PI) - -key = curses.KEY_RIGHT - -while True: - next_key = w.getch() - key = key if next_key == -1 else next_key - - if snake[0][0] in [0, sh] or snake[0][1] in [0, sw] or snake[0] in snake[1:]: - curses.endwin() - quit() - - new_head = [snake[0][0], snake[0][1]] - - if key == curses.KEY_DOWN: - new_head[0] += 1 - if key == curses.KEY_UP: - new_head[0] -= 1 - if key == curses.KEY_LEFT: - new_head[1] -= 1 - if key == curses.KEY_RIGHT: - new_head[1] += 1 - - snake.insert(0, new_head) - - if snake[0] == food: - food = None - while food is None: - nf = [random.randint(1, sh - 1), random.randint(1, sw - 1)] - food = nf if nf not in snake else None - w.addch(food[0], food[1], curses.ACS_PI) - else: - tail = snake.pop() - w.addch(int(tail[0]), int(tail[1]), " ") - - w.addch(int(snake[0][0]), int(snake[0][1]), curses.ACS_CKBOARD) diff --git a/neogpt/agents/examples/translator_app.py b/neogpt/agents/examples/translator_app.py deleted file mode 100755 index 24a519d..0000000 --- a/neogpt/agents/examples/translator_app.py +++ /dev/null @@ -1,23 +0,0 @@ -# filename: translator_app.py -import streamlit as st -from googletrans import LANGUAGES, Translator - - -def translate_text(text, target_language): - translator = Translator() - translation = translator.translate(text, dest=target_language) - return translation.text - - -if __name__ == "__main__": - st.title("Basic Translator App") - st.subheader("Enter text to translate:") - - text = st.text_area(label="Text", value="", height=200, max_chars=200) - - target_language = st.selectbox("Select target language:", list(LANGUAGES.values())) - - if st.button("Translate"): - translated_text = translate_text(text, target_language) - st.write("Translated Text:") - st.write(translated_text) diff --git a/neogpt/utils/magic_commands.py b/neogpt/utils/magic_commands.py index 08b2389..d78366c 100755 --- a/neogpt/utils/magic_commands.py +++ b/neogpt/utils/magic_commands.py @@ -213,7 +213,47 @@ def magic_commands(user_input, chain): conversation_navigator(chain) return True - # If the user inputs '/help', print the list of available commands + # If the user inputs '/search [keyword]', search the chat history for the keyword + elif user_input.startswith("/search"): + # Extract the keyword from the command + keyword = user_input.split(" ", 1)[1].strip().replace("'", "").replace('"', "") + # Create a flag to indicate if any messages are found + found = False + for message in chain.combine_documents_chain.memory.chat_memory.messages: + if keyword in message.content: + if isinstance(message, HumanMessage): + cprint( + f" [bright_yellow]{get_username()} [/bright_yellow]{message.content}" + ) + else: + cprint(f" [bright_blue]NeoGPT: [/bright_blue]{message.content}") + found = True + if not found: + cprint(f"No messages found with the keyword '{keyword}'.") + return True + + elif user_input.startswith("/copycode") or user_input.startswith("/cc"): + # Find previous code block in chat history + code_block = "" + import re + for message in reversed(chain.combine_documents_chain.memory.chat_memory.messages): + if "```" in message.content: + # Extract the code block from the message + code_pattern = re.compile(r"```([^\n]*)\n(.*?)```", re.DOTALL) + code_match = code_pattern.search(message.content) + if code_match: + code_block = code_match.group(2) + break + if code_block: + pyperclip.copy(code_block) + cprint("\n[bold green]📋 Code block copied to clipboard![/bold green]") + notify("NeoGPT", "Code block copied to clipboard!") + return True + else: + cprint("🚫 No code block found in the chat history. Please try again.") + return True + + # If the user inputs '/help', print the list of available commands elif user_input == "/help" or user_input == "/": cprint("\n[bold magenta]📖 Available commands: [/bold magenta]") cprint("🔄 /reset - Reset the chat session") @@ -232,28 +272,11 @@ def magic_commands(user_input, chain): ) cprint("📜 /conversations - List available previously saved conversations.") cprint("📚 /source - Prints the source directory") + cprint("🔍 /search [keyword] - Search the chat history for the keyword") + cprint("📋 /copycode or /cc - Copy the last code block to the clipboard") return True - # If the user inputs '/search [keyword]', search the chat history for the keyword - elif user_input.startswith("/search"): - # Extract the keyword from the command - keyword = user_input.split(" ", 1)[1].strip().replace("'", "").replace('"', "") - # Create a flag to indicate if any messages are found - found = False - for message in chain.combine_documents_chain.memory.chat_memory.messages: - if keyword in message.content: - if isinstance(message, HumanMessage): - cprint( - f" [bright_yellow]{get_username()} [/bright_yellow]{message.content}" - ) - else: - cprint(f" [bright_blue]NeoGPT: [/bright_blue]{message.content}") - found = True - if not found: - cprint(f"No messages found with the keyword '{keyword}'.") - return True - # If the command is not recognized, print an error message else: cprint("Invalid magic command. Please try again.")