Skip to content

Commit

Permalink
added UI
Browse files Browse the repository at this point in the history
  • Loading branch information
adhishthite committed May 3, 2023
1 parent 8c5b2d6 commit fec6b26
Show file tree
Hide file tree
Showing 7 changed files with 464 additions and 0 deletions.
66 changes: 66 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import requests
from typing import Optional

from flask import Flask, render_template, request, redirect, url_for, flash, jsonify

from chat_gpt import ChatGPT

app = Flask(__name__)
app.secret_key = 'supersecretkey'
chat_gpt: Optional[ChatGPT] = None


@app.route('/')
def setup():
return render_template('setup.html')


@app.route('/setup', methods=['POST'])
def setup_submit():
global chat_gpt
api_key = request.form['api_key']
model_id = request.form['model_id']
context = request.form['context']

if not test_api(api_key):
return jsonify({'status': 'error', 'message': 'Failed to connect to OpenAI API'})

chat_gpt = ChatGPT(model_id, api_key, context)
chat_gpt.add_system_message(f"{context}. Respond precisely. Do not give more information than necessary.")

try:
chat_gpt.gpt_conversation()
return jsonify({'status': 'success', 'message': 'Connection successful'})
except Exception as e:
return jsonify({'status': 'error', 'message': str(e)})


def test_api(api_key: str) -> bool:
headers = {
'Authorization': f'Bearer {api_key}',
}
response = requests.get('https://api.openai.com/v1/models', headers=headers)
return response.status_code == 200


@app.route('/chat')
def chat():
if chat_gpt is None:
return redirect(url_for('setup'))
return render_template('chat.html')


@app.route('/send_message', methods=['POST'])
def send_message():
user_input = request.form['message']
chat_gpt.add_user_message(user_input)
response = chat_gpt.gpt_conversation()

if response['status'] == 'success':
return jsonify({'status': 'success', 'message': response['message']})
else:
return jsonify({'status': 'error', 'message': response['message']})


if __name__ == '__main__':
app.run(debug=True, port=8801)
58 changes: 58 additions & 0 deletions chat_gpt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import openai
from openai.error import AuthenticationError, InvalidRequestError, RateLimitError

# Constants
PRICE_MAP: dict = {
"gpt-3.5-turbo": 0.002,
"gpt-4": 0.06,
}


class ChatGPT:
def __init__(self, model_id: str, api_key: str, context: str):
self.model_id = model_id
self.api_key = api_key
self.context = context
self.conversation = []
self.cost = 0.0

openai.api_key = api_key

def add_system_message(self, message: str) -> None:
self.conversation.append({'role': 'system', 'content': message})

def add_user_message(self, message: str) -> None:
self.conversation.append({'role': 'user', 'content': message})

def gpt_conversation(self) -> dict:
try:
response = openai.ChatCompletion.create(
model=self.model_id,
messages=self.conversation
)

self.conversation.append(
{
'role': response.choices[0].message.role,
'content': response.choices[0].message.content,
}
)

total_tokens = response.usage.total_tokens
self.calculate_price_from_tokens(total_tokens)

return {'status': 'success', 'message': response.choices[0].message.content.strip()}

except InvalidRequestError as exc:
return {'status': 'error', 'message': f"Invalid request. Error: {exc}"}
except RateLimitError as exc:
return {'status': 'error', 'message': f"Rate limit exceeded. Error: {exc}"}
except Exception as exc:
return {'status': 'error', 'message': f"Unexpected error. Error: {exc}"}

def calculate_price_from_tokens(self, total_tokens: int) -> float:
price_per_1000 = PRICE_MAP[self.model_id]
price = (total_tokens / 1000) * price_per_1000
self.cost += price

return round(price, 4)
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ openai
rich
cchardet
keyboard
Flask
85 changes: 85 additions & 0 deletions static/scripts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
$(document).ready(function () {
$("#setup_form").on("submit", function (event) {
event.preventDefault();
const formData = $(this).serialize(); // Serialize the form data before disabling the fields
toggleFormFields(true); // Disable the form fields
$.ajax({
url: "/setup",
method: "POST",
data: formData,
success: function (response) {
if (response.status === "success") {
// Display success alert
$("#message").html('<div class="alert alert-success" role="alert">' + response.message + '</div>');
// Redirect to chat page
window.location.href = "/chat";
} else {
$("#message").html('<div class="alert alert-danger" role="alert">' + response.message + '</div>');
toggleFormFields(false); // Enable the form fields
}
},
error: function () {
$("#message").html('<div class="alert alert-danger" role="alert">An error occurred while processing the request.</div>');
toggleFormFields(false); // Enable the form fields
}
});
});

$("#send_button").on("click", function () {
var userMessage = $("#user_message").val().trim();
if (userMessage !== "") {
$("#user_message").val("");
$("#chatlog").append('<div class="user-message">You: ' + escapeHtml(userMessage) + '</div>');
scrollToBottom(); // Scroll to the bottom after appending user message
$.ajax({
url: "/send_message", // Change this line to use the correct endpoint
method: "POST",
data: { message: userMessage },
success: function (response) {
if (response.status === "success") {
if (response.message) {
$("#chatlog").append('<div class="assistant-message">ChatGPT: ' + escapeHtml(response.message) + '</div>');
} else {
$("#chatlog").append('<div class="error-message">Error: Received an empty response.</div>');
}
scrollToBottom(); // Scroll to the bottom after appending assistant message
} else {
if (response.message) {
$("#chatlog").append('<div class="error-message">Error: ' + escapeHtml(response.message) + '</div>');
} else {
$("#chatlog").append('<div class="error-message">Error: An unknown error occurred.</div>');
}
scrollToBottom(); // Scroll to the bottom after appending error message
}
}
});
}
});

$("#user_message").on("keypress", function (event) {
if (event.which == 13 && !event.shiftKey) {
event.preventDefault();
$("#send_button").click();
}
});
});

function toggleFormFields(disable) {
$("#setup_form input, #setup_form select, #setup_form button").prop("disabled", disable);
}

function escapeHtml(text) {
return text
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/(?:\r\n|\r|\n)/g, '<br>') // Replace newline characters with <br>
.replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;') // Replace tab characters with four non-breaking spaces
.replace(/ +/g, function (match) {
return match.split('').map(() => '&nbsp;').join('');
}); // Replace consecutive spaces with non-breaking spaces
}

function scrollToBottom() {
const chatlog = document.getElementById("chatlog");
chatlog.scrollTop = chatlog.scrollHeight;
}
167 changes: 167 additions & 0 deletions static/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
:root {
--user-bg-color: #1e88e5;
--assistant-bg-color: #f5f5f5;
--error-bg-color: #e53935;
--primary-text-color: #212121;
--error-text-color: #fff;
--message-margin: 20px;
--border-radius: 8px;
--font-family: 'Roboto', sans-serif;
--container-bg: #e0e0e0;
--gradient-start: #455a64;
--gradient-end: #607d8b;
--input-border-color: #bdbdbd;
--button-color: #1976d2;
--button-hover-color: #1565c0;
}

html, body {
height: 100%;
margin: 0;
padding: 0;
}

body {
font-family: var(--font-family);
background-color: var(--container-bg);
background-image: linear-gradient(120deg, var(--gradient-start), var(--gradient-end));
}

.container {
width: 100%;
max-width: 100%;
max-height: 100vh;
padding: 20px; /* Add padding */
box-sizing: border-box; /* Add box-sizing to prevent the container from overflowing */
margin: 0;
height: calc(100vh - 40px); /* Subtract the footer height */
display: flex;
flex-direction: column;
background-color: #ffffff;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}

h1 {
text-align: center;
margin-bottom: 50px;
color: var(--primary-text-color);
}

.form-group {
margin-bottom: 20px;
}

label {
display: block;
color: var(--primary-text-color);
}

input[type="text"], textarea, select {
width: 100%;
padding: 8px 12px;
box-sizing: border-box;
border: 1px solid var(--input-border-color);
border-radius: var(--border-radius);
background-color: #ffffff;
}

button[type="submit"], .btn-primary {
background-color: var(--button-color);
color: white;
padding: 8px 16px;
border: none;
border-radius: var(--border-radius);
cursor: pointer;
transition: background-color 0.3s;
}

button[type="submit"]:hover,
.btn-primary:hover {
background-color: var(--button-hover-color);
}

.chatbox {
width: 100%;
background-color: white;
border: 1px solid var(--input-border-color);
border-radius: var(--border-radius);
}

.chatlog {
overflow-y: scroll;
padding: 20px;
border-bottom: 1px solid var(--input-border-color);
height: calc(100% - 82px);
}

.input-group {
border-top: 2px solid #f8f9fa;
}

.card {
flex-grow: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}

.card-body {
display: flex;
flex-direction: column;
height: calc(100% - 50px);
overflow: hidden;
}

.chatlog {
flex-grow: 1;
overflow-y: scroll;
}

.user-message,
.assistant-message,
.error-message {
border-radius: 5px;
padding: 10px;
margin-bottom: 10px;
}

.message {
margin-right: var(--message-margin);
margin-left: var(--message-margin);
border-radius: var(--border-radius);
padding: 12px 16px;
line-height: 1.5;
font-size: 16px;
max-width: 80%;
word-wrap: break-word;
margin-bottom: 10px;
}

.user-message {
background-color: var(--user-bg-color);
color: var(--error-text-color);
align-self: flex-end;
}

.assistant-message {
background-color: var(--assistant-bg-color);
color: var(--primary-text-color);
align-self: flex-start;
}

.error-message {
background-color: var(--error-bg-color);
color: var(--error-text-color);
align-self: center;
}

.footer {
position: absolute;
bottom: 0;
width: 100%;
text-align: center;
padding: 10px 0;
background-color: #455a64; /* Updated background color */
color: #fff; /* Updated text color */
height: 40px; /* Add a fixed height for the footer */
}
Loading

0 comments on commit fec6b26

Please sign in to comment.