diff --git a/README.md b/README.md
index 76c353c..900220d 100755
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-
+
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. 🚀🧠
+
+
+# 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
-
- """
- 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.")