diff --git a/gui/config/config.json.sample b/gui/config/config.json.sample new file mode 100644 index 0000000..5e4c6f5 --- /dev/null +++ b/gui/config/config.json.sample @@ -0,0 +1,13 @@ +{ + "database": + { + "dbtype": "PostgreSQL", + "ip": "localhost", + "password": "password", + "user": "admin", + "port": "5432" + "database": "PostgreSQL", + }, + "apikey": "sk-abc***" +} + diff --git a/gui/database/postgresql.py b/gui/database/postgresql.py new file mode 100644 index 0000000..2aae6c6 --- /dev/null +++ b/gui/database/postgresql.py @@ -0,0 +1,72 @@ +import psycopg2 +import os + +class Postgres: + def __init__(self, ip, port, username, password, database): + self.db_ip = ip + self.db_port = port + self.db_username = username + self.db_password = password + self.db_name = database + + self.conn = psycopg2.connect( + host=self.db_ip, + port=self.db_port, + user=self.db_username, + password=self.db_password, + database=self.db_name + ) + self.tables = [] + self.tableschema = {} + self.get_schema() + + def __str__(self): + return f'PostgreSQL Server: {self.db_ip}:{self.db_port} as {self.db_username} on database {self.db_name}' + + def get_schema(self) -> dict: + fetch = self.fetchall("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';") + for item in fetch: + self.tables.append(item[0]) + + for table in self.tables: + fetch = self.fetchall(f"SELECT column_name, data_type FROM information_schema.columns WHERE table_name = '{table}';") + self.tableschema.update({table: fetch}) + + return self.tableschema + + def fetchall(self, query: str): + cur = self.conn.cursor() + cur.execute(query) + result = cur.fetchall() + cur.close() + return result + + def fetchone(self, query: str): + cur = self.conn.cursor() + cur.execute(query) + result = cur.fetchone() + cur.close() + return result + + def fetchmany(self, query: str, size: int): + cur = self.conn.cursor() + cur.execute(query) + result = cur.fetchmany(size) + cur.close() + return result + + def execute(self, query: str): + cur = self.conn.cursor() + cur.execute(query) + self.conn.commit() + cur.close() + + def executemany(self, query: str, values): + cur = self.conn.cursor() + cur.executemany(query, values) + self.conn.commit() + cur.close() + + def close(self): + self.conn.close() + diff --git a/gui/modules/aisql.py b/gui/modules/aisql.py new file mode 100644 index 0000000..0544c41 --- /dev/null +++ b/gui/modules/aisql.py @@ -0,0 +1,67 @@ +import openai + + +class AI: + def __init__(self, api_key): + self.api_key = api_key + openai.api_key = self.api_key + self.convertlog = [] + + def humantosql(self, text: str, dbtype: str, tableschema: list) -> str: + if not self.convertlog: + self.convertlog = [{"role": "system", + "content": f"You convert Human Language to SQL. Only answer as an Valid SQL Statement. Always modify your previous answer and do not create something new. You are using this Database: {dbtype}. For better context here are the tables and columns: {tableschema}"}] + + prompt = {"role": "user", "content": text} + self.convertlog.append(prompt) + self.response = openai.ChatCompletion.create( + model="gpt-4", + messages=self.convertlog + ) + self.response = self.response['choices'][0]['message']['content'] + self.convertlog.append({"role": "assistant", "content": self.response}) + + if self.validate(self.response) is True: + return self.response + else: + valid = self.humantosql("Only answer as a Valid SQL-Statement don't add any additional text", dbtype, + tableschema) + return valid + + def decide(self, sql: str) -> str: + prompt = [{"role": "system", + "content": "You have to decide which function it should use. Answer with [FETCHALL] to fetch all, [FETCHONE] to fetch only one, [FETCHMANY=N] to fetchmany with N being the range, [EXECUTE] to just execute, [EXECUTEMANY=N] to execute many with N being the range"}, + {"role": "user", "content": sql}] + + response = openai.ChatCompletion.create( + model="gpt-4", + messages=prompt + ) + + response = response['choices'][0]['message']['content'] + + return response + + def validate(self, sql: str) -> bool: + prompt = [{"role": "system", + "content": "You check if the User Input is a valid SQL-Statement. You also return False if there is any kind of text before and after the statement. You only return True or False. Most important: ONLY ANSWER True OR False."}, + {"role": "user", "content": sql}] + + valid = openai.ChatCompletion.create( + model="gpt-4", + messages=prompt + ) + valid = valid['choices'][0]['message']['content'] + if valid == "True": + return True + else: + return False + + def test_key(self) -> bool: + openai.api_key = str(self.api_key) + try: + openai.Engine.list() + return True + except Exception as e: + print(e) + return False