Skip to content
This repository has been archived by the owner on Sep 26, 2023. It is now read-only.

Commit

Permalink
Merge pull request #83 from machsix/main
Browse files Browse the repository at this point in the history
Add Blueprint to handle static files, add "url_prefix" in config.json
  • Loading branch information
ramon-victor authored Jul 14, 2023
2 parents f2b6ea4 + ee69c04 commit 84d9cf2
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 79 deletions.
22 changes: 11 additions & 11 deletions client/html/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@
property="og:description"
content="A conversational AI system that listens, learns, and challenges" />
<meta property="og:url" content="https://chat.acy.dev" />
<link rel="stylesheet" href="/assets/css/style.css" />
<link rel="apple-touch-icon" sizes="180x180" href="/assets/img/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/assets/img/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/assets/img/favicon-16x16.png" />
<link rel="manifest" href="/assets/img/site.webmanifest" />
<link rel="stylesheet" href="{{ url_for('bp.static', filename='css/style.css') }}" />
<link rel="apple-touch-icon" sizes="180x180" href="{{ url_for('bp.static', filename='img/apple-touch-icon.png') }}" />
<link rel="icon" type="image/png" sizes="32x32" href="{{ url_for('bp.static', filename='img/favicon-32x32.png') }}" />
<link rel="icon" type="image/png" sizes="16x16" href="{{ url_for('bp.static', filename='img/favicon-16x16.png') }}" />
<link rel="manifest" href="{{ url_for('bp.static', filename='img/site.webmanifest') }}" />
<link
rel="stylesheet"
href="//cdn.jsdelivr.net/gh/highlightjs/cdn-release@latest/build/styles/base16/dracula.min.css" />
<title>FreeGPT</title>
</head>

<body>
<body data-urlprefix="{{ url_prefix}}">
<div class="main-container">
<div class="box sidebar">
<div class="top">
Expand Down Expand Up @@ -109,11 +109,11 @@
<script>
window.conversation_id = "{{ chat_id }}";
</script>
<script src="/assets/js/icons.js"></script>
<script src="/assets/js/chat.js" defer></script>
<script src="{{ url_for('bp.static', filename='js/icons.js') }}"></script>
<script src="{{ url_for('bp.static', filename='js/chat.js') }}" defer></script>
<script src="https://cdn.jsdelivr.net/npm/markdown-it@latest/dist/markdown-it.min.js"></script>
<script src="/assets/js/highlight.min.js"></script>
<script src="/assets/js/highlightjs-copy.min.js"></script>
<script src="/assets/js/theme-toggler.js"></script>
<script src="{{ url_for('bp.static', filename='js/highlight.min.js') }}"></script>
<script src="{{ url_for('bp.static', filename='js/highlightjs-copy.min.js') }}"></script>
<script src="{{ url_for('bp.static', filename='js/theme-toggler.js') }}"></script>
</body>
</html>
15 changes: 8 additions & 7 deletions client/js/chat.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ const query = (obj) =>
Object.keys(obj)
.map((k) => encodeURIComponent(k) + "=" + encodeURIComponent(obj[k]))
.join("&");
const url_prefix = document.querySelector('body').getAttribute('data-urlprefix')
const markdown = window.markdownit();
const message_box = document.getElementById(`messages`);
const message_input = document.getElementById(`message-input`);
const box_conversations = document.querySelector(`.top`);
const spinner = box_conversations.querySelector(".spinner");
const stop_generating = document.querySelector(`.stop-generating`);
const send_button = document.querySelector(`#send-button`);
const user_image = `<img src="/assets/img/user.png" alt="User Avatar">`;
const gpt_image = `<img src="/assets/img/gpt.png" alt="GPT Avatar">`;
const user_image = `<img src="${url_prefix}/assets/img/user.png" alt="User Avatar">`;
const gpt_image = `<img src="${url_prefix}/assets/img/gpt.png" alt="GPT Avatar">`;
let prompt_lock = false;

hljs.addPlugin(new CopyButtonPlugin());
Expand Down Expand Up @@ -90,7 +91,7 @@ const ask_gpt = async (message) => {
await new Promise((r) => setTimeout(r, 1000));
window.scrollTo(0, 0);

const response = await fetch(`/backend-api/v2/conversation`, {
const response = await fetch(`${url_prefix}/backend-api/v2/conversation`, {
method: `POST`,
signal: window.controller.signal,
headers: {
Expand Down Expand Up @@ -127,7 +128,7 @@ const ask_gpt = async (message) => {

chunk = decodeUnicode(new TextDecoder().decode(value));

if (chunk.includes(`<form id="challenge-form" action="/backend-api/v2/conversation?`)) {
if (chunk.includes(`<form id="challenge-form" action="${url_prefix}/backend-api/v2/conversation?`)) {
chunk = `cloudflare token expired, please refresh the page.`;
}

Expand Down Expand Up @@ -243,7 +244,7 @@ const delete_conversation = async (conversation_id) => {
};

const set_conversation = async (conversation_id) => {
history.pushState({}, null, `/chat/${conversation_id}`);
history.pushState({}, null, `${url_prefix}/chat/${conversation_id}`);
window.conversation_id = conversation_id;

await clear_conversation();
Expand All @@ -252,7 +253,7 @@ const set_conversation = async (conversation_id) => {
};

const new_conversation = async () => {
history.pushState({}, null, `/chat/`);
history.pushState({}, null, `${url_prefix}/chat/`);
window.conversation_id = uuid();

await clear_conversation();
Expand Down Expand Up @@ -426,7 +427,7 @@ window.onload = async () => {
}, 1);

if (!window.location.href.endsWith(`#`)) {
if (/\/chat\/.+/.test(window.location.href)) {
if (/\/chat\/.+/.test(window.location.href.slice(url_prefix.length))) {
await load_conversation(window.conversation_id);
}
}
Expand Down
3 changes: 2 additions & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
"host": "0.0.0.0",
"port": 1338,
"debug": false
}
},
"url_prefix": ""
}
19 changes: 12 additions & 7 deletions run.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,39 @@
from server.app import app
from server.bp import bp
from server.website import Website
from server.backend import Backend_Api
from json import load

from flask import Flask

if __name__ == '__main__':

# Load configuration from config.json
config = load(open('config.json', 'r'))
site_config = config['site_config']
url_prefix = config.pop('url_prefix')

# Set up the website routes
site = Website(app)
site = Website(bp, url_prefix)
for route in site.routes:
app.add_url_rule(
bp.add_url_rule(
route,
view_func=site.routes[route]['function'],
methods=site.routes[route]['methods'],
)

# Set up the backend API routes
backend_api = Backend_Api(app, config)
backend_api = Backend_Api(bp, config)
for route in backend_api.routes:
app.add_url_rule(
bp.add_url_rule(
route,
view_func=backend_api.routes[route]['function'],
methods=backend_api.routes[route]['methods'],
)

# Create the app and register the blueprint
app = Flask(__name__)
app.register_blueprint(bp, url_prefix=url_prefix)

# Run the Flask server
print(f"Running on port {site_config['port']}")
print(f"Running on {site_config['port']}{url_prefix}")
app.run(**site_config)
print(f"Closing port {site_config['port']}")
3 changes: 0 additions & 3 deletions server/app.py

This file was deleted.

64 changes: 30 additions & 34 deletions server/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,32 @@
import g4f
from g4f import ChatCompletion
from googletrans import Translator
from flask import request
from flask import request, Response, stream_with_context
from datetime import datetime
from requests import get
from server.config import special_instructions


class Backend_Api:
def __init__(self, app, config: dict) -> None:
"""
Initialize the Backend_Api class.
:param app: Flask application instance
:param config: Configuration dictionary
def __init__(self, bp, config: dict) -> None:
"""
Initialize the Backend_Api class.
:param app: Flask application instance
:param config: Configuration dictionary
"""
self.app = app
self.bp = bp
self.routes = {
'/backend-api/v2/conversation': {
'function': self._conversation,
'methods': ['POST']
}
}

def _conversation(self):
"""
Handles the conversation route.
"""
Handles the conversation route.
:return: Response object containing the generated conversation stream
:return: Response object containing the generated conversation stream
"""
max_retries = 3
retries = 0
Expand All @@ -49,7 +48,7 @@ def _conversation(self):
messages=messages
)

return self.app.response_class(generate_stream(response, jailbreak), mimetype='text/event-stream')
return Response(stream_with_context(generate_stream(response, jailbreak)), mimetype='text/event-stream')

except Exception as e:
print(e)
Expand All @@ -66,11 +65,11 @@ def _conversation(self):


def build_messages(jailbreak):
"""
Build the messages for the conversation.
"""
Build the messages for the conversation.
:param jailbreak: Jailbreak instruction string
:return: List of messages for the conversation
:param jailbreak: Jailbreak instruction string
:return: List of messages for the conversation
"""
_conversation = request.json['meta']['content']['conversation']
internet_access = request.json['meta']['content']['internet_access']
Expand Down Expand Up @@ -109,35 +108,32 @@ def build_messages(jailbreak):


def fetch_search_results(query):
"""
Fetch search results for a given query.
"""
Fetch search results for a given query.
:param query: Search query string
:return: List of search results
:param query: Search query string
:return: List of search results
"""
search = get('https://ddg-api.herokuapp.com/search',
params={
'query': query,
'limit': 3,
})

results = []
snippets = ""
for index, result in enumerate(search.json()):
snippet = f'[{index + 1}] "{result["snippet"]}" URL:{result["link"]}.'
snippets += snippet
results.append({'role': 'system', 'content': snippets})

return results
return [{'role': 'system', 'content': snippets}]


def generate_stream(response, jailbreak):
"""
Generate the conversation stream.
"""
Generate the conversation stream.
:param response: Response object from ChatCompletion.create
:param jailbreak: Jailbreak instruction string
:return: Generator object yielding messages in the conversation
:param response: Response object from ChatCompletion.create
:param jailbreak: Jailbreak instruction string
:return: Generator object yielding messages in the conversation
"""
if getJailbreak(jailbreak):
response_jailbreak = ''
Expand Down Expand Up @@ -167,11 +163,11 @@ def response_jailbroken_success(response: str) -> bool:


def response_jailbroken_failed(response):
"""
Check if the response has not been jailbroken.
"""
Check if the response has not been jailbroken.
:param response: Response string
:return: Boolean indicating if the response has not been jailbroken
:param response: Response string
:return: Boolean indicating if the response has not been jailbroken
"""
return False if len(response) < 4 else not (response.startswith("GPT:") or response.startswith("ACT:"))

Expand Down
6 changes: 6 additions & 0 deletions server/bp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from flask import Blueprint

bp = Blueprint('bp', __name__,
template_folder='./../client/html',
static_folder='./../client',
static_url_path='assets')
23 changes: 7 additions & 16 deletions server/website.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
from flask import render_template, send_file, redirect
from flask import render_template, redirect, url_for
from time import time
from os import urandom


class Website:
def __init__(self, app) -> None:
self.app = app
def __init__(self, bp, url_prefix) -> None:
self.bp = bp
self.url_prefix = url_prefix
self.routes = {
'/': {
'function': lambda: redirect('/chat'),
'function': lambda: redirect(url_for('._index')),
'methods': ['GET', 'POST']
},
'/chat/': {
Expand All @@ -18,24 +19,14 @@ def __init__(self, app) -> None:
'/chat/<conversation_id>': {
'function': self._chat,
'methods': ['GET', 'POST']
},
'/assets/<folder>/<file>': {
'function': self._assets,
'methods': ['GET', 'POST']
}
}

def _chat(self, conversation_id):
if '-' not in conversation_id:
return redirect('/chat')
return redirect(url_for('._index'))

return render_template('index.html', chat_id=conversation_id)

def _index(self):
return render_template('index.html', chat_id=f'{urandom(4).hex()}-{urandom(2).hex()}-{urandom(2).hex()}-{urandom(2).hex()}-{hex(int(time() * 1000))[2:]}')

def _assets(self, folder: str, file: str):
try:
return send_file(f"./../client/{folder}/{file}", as_attachment=False)
except:
return "File not found", 404
return render_template('index.html', chat_id=f'{urandom(4).hex()}-{urandom(2).hex()}-{urandom(2).hex()}-{urandom(2).hex()}-{hex(int(time() * 1000))[2:]}', url_prefix=self.url_prefix)

0 comments on commit 84d9cf2

Please sign in to comment.