diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..eaf91e2 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/Wox.Plugin.ChatGPT-master.iml b/.idea/Wox.Plugin.ChatGPT-master.iml new file mode 100644 index 0000000..3a160da --- /dev/null +++ b/.idea/Wox.Plugin.ChatGPT-master.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..4a0bb6d --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,22 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..e155b6f --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..1aa2bf3 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 5666919..cdfd582 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Alternatively you can run the script directly via `python app.py [QUERY]` ## Configuration - `api_key:` Your OpenAI API key - `model:` Used model (default: `gpt-3.5-turbo`, check https://platform.openai.com/docs/models/) - - `max_tokens:` Maximum amount of returned tokens (longer = more expensive; default: `32`) + - `max_tokens:` Maximum amount of returned tokens (longer = more expensive; default: `512`) - `temperature:` Increase randomness (default: `0.15`) - `stream:`: Stream response or wait for entire processed text (default: `True`) - `price_per_token:` Used for estimating costs (default: `0.002 / 1000` based on gpt-3.5-turbo) diff --git a/app.py b/app.py index 425d1d8..02b5d87 100644 --- a/app.py +++ b/app.py @@ -5,12 +5,15 @@ import time import threading import sys +import traceback import webbrowser import psutil from markdown import markdown +from history import QueryDB + config = { - "api_key": "insert-your-openai-api-key-here", + "api_key": "insert-api-key-here", "model": "gpt-3.5-turbo", # check https://platform.openai.com/docs/models/ for other models "max_tokens": 512, # maximum amount of returned tokens "temperature": 0.15, # increases randomness @@ -22,7 +25,8 @@ "stop_after_one_request": False, "done": False, "completion_text": "", - "input_prompt": "" + "input_prompt": "", + "last_history_id": False, } openai.api_key = config["api_key"] app = Flask(__name__, template_folder=".") @@ -45,7 +49,7 @@ def shutdown_flask(): for p in psutil.process_iter(): if p.name().startswith("python"): # might need to exchange for sys.executable if len(p.cmdline()) > 2 and p.cmdline()[1] == "app.py": - time.sleep(0.5) + time.sleep(1.5) p.kill() @@ -81,8 +85,10 @@ def openai_call_thread(): stream=config["stream"]) except Exception as exc: config["done"] = True - config["status"] = f"Error: {exc}" + traceback_lines = traceback.format_exc().splitlines() + config["status"] = f"{traceback_lines[-1]}" shutdown_flask() + return if config["stream"]: for event in response: @@ -116,6 +122,11 @@ def openai_call_thread(): if not config["stop_after_one_request"]: config["session_spent_text"] += f" (session: {round(config['session_spent'], 5)}$)" + # record query history + with QueryDB() as query_db: + query_db.insert_query(config) + config["last_history_id"] = query_db.cursor.lastrowid + # convert markdown to html config["completion_text"] = markdown(config["completion_text"]) @@ -135,17 +146,38 @@ def openai_call(prompt: str = None): return jsonify(status="Started API call in thread", config={key: val for key, val in config.items() if key not in ["api_key", "completion_text"]}, - result=None) + result=config.get("response")) @app.route('/update') def update(): """Routine to fetch data, started with setInterval(getResults, interval) in index.html""" - global config return jsonify(status="Update interval running", config={key: val for key, val in config.items() if key not in ["api_key", "completion_text"]}, - result=config["completion_text"]) + result=config.get("completion_text")) + + +@app.route('/get_history') +def get_history(): + with QueryDB() as query_db: + query_history = query_db.get_all() + return jsonify(status="Get history queries", + data=query_history) + + +@app.route('/get_query/') +def get_query(query_id: int): + global config + with QueryDB() as query_db: + query = query_db.get_by_id(query_id-1) + return jsonify(status="Get query by id", data=query) + + +@app.route('/close_process', methods=['GET']) +def close_process(): + shutdown_flask() + return jsonify(status='thread killed') if __name__ == "__main__": @@ -156,3 +188,5 @@ def update(): webbrowser.open("http://127.0.0.1:5000") app.run(host="127.0.0.1", port=5000, debug=False) + + diff --git a/history.py b/history.py new file mode 100644 index 0000000..15b8f67 --- /dev/null +++ b/history.py @@ -0,0 +1,40 @@ +import json +import sqlite3 + + +class QueryDB: + def __enter__(self): + self.conn = sqlite3.connect('database.db') + self.cursor = self.conn.cursor() + self.cursor.execute("CREATE TABLE IF NOT EXISTS queries " + "(id INTEGER PRIMARY KEY," + "input TEXT," + "result TEXT," + "cost REAL," + "config JSON," + "status TEXT)") + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.conn.close() + + def insert_query(self, config): + clean_config = {k: v for k, v in config.items() if k != "api_key"} + self.cursor.execute("INSERT INTO queries (input, result, cost, config, status) " + "VALUES (?, ?, ?, ?, ?)", + (clean_config['input_prompt'], + clean_config['completion_text'], + clean_config['session_spent_text'], + json.dumps(clean_config), + clean_config['status'])) + self.conn.commit() + + def get_all(self): + self.cursor.execute("SELECT * FROM queries ORDER BY id DESC") + results = self.cursor.fetchall() + return results + + def get_by_id(self, query_id): + self.cursor.execute("SELECT * FROM queries WHERE id = ?", (query_id+1,)) + query = self.cursor.fetchone() + return query diff --git a/index.html b/index.html index 89db374..0a7c2ef 100644 --- a/index.html +++ b/index.html @@ -8,13 +8,10 @@ background-color: rgba(52, 53, 65); color: rgba(236, 236, 241, 100%); font-family: Arial, Helvetica, sans-serif; + margin: 0; } .header { - display: flex; - justify-content: center; - flex-direction: row; - margin: 20vh auto 4rem; font-size: 2.25rem; font-weight: 600; line-height: 2.5rem; @@ -37,10 +34,6 @@ } .centered { - display: flex; - justify-content: center; - margin-right: auto; - margin-left: auto; } .vertical-margin { @@ -49,9 +42,6 @@ } .card { - justify-content: center; - margin-right: auto; - margin-left: auto; border-radius: 0.375rem; border: 0 solid #d9d9e3; box-sizing: border-box; @@ -76,31 +66,80 @@ } + ChatGPT API -
ChatGPT API
-
-

Input:   - -

-
-
-
- Status:  -
-
- Cost:  -
-
- +
+
+
    +
    + +
    +
    ChatGPT API
    +
    +

    Input:   + +

    +
    +
    +
    + Status:  +
    +
    + Cost:  +
    +
    + +
    +
    - + + + \ No newline at end of file diff --git a/main.py b/main.py index 1181690..1d54cd9 100644 --- a/main.py +++ b/main.py @@ -4,7 +4,6 @@ class ChatGPTPlugin(Wox): - # query is default function to receive realtime keystrokes from wox launcher def query(self, query): results = [] @@ -22,7 +21,10 @@ def query(self, query): return results def take_action(self, query): - subprocess.Popen(["python", "app.py", query]).wait() + # subprocess.Popen(["python", "app.py", query]).wait() + + ## no cmd window + subprocess.Popen(["python", "app.py", query], creationflags=subprocess.CREATE_NO_WINDOW).wait() if __name__ == "__main__": diff --git a/requirements.txt b/requirements.txt index 56d47f5..d75113b 100644 Binary files a/requirements.txt and b/requirements.txt differ