Spaces:
Running
Running
Upload 21 files
Browse files- app.py +48 -0
- application/__pycache__/chat_inference.cpython-311.pyc +0 -0
- application/chat_inference.py +63 -0
- application/static/css/style.css +317 -0
- application/static/js/components/chat.js +43 -0
- application/static/js/components/initialize.js +112 -0
- application/static/js/components/navbar.js +68 -0
- application/static/js/components/renderSymbols.js +43 -0
- application/static/js/components/request.js +38 -0
- application/static/js/components/uiManager.js +98 -0
- application/static/js/script.js +14 -0
- application/templates/index.html +53 -0
- application/utils/__init__.py +0 -0
- application/utils/__pycache__/__init__.cpython-311.pyc +0 -0
- application/utils/__pycache__/chat_completion_api.cpython-311.pyc +0 -0
- application/utils/__pycache__/convs_handler.cpython-311.pyc +0 -0
- application/utils/chat_completion_api.py +50 -0
- application/utils/convs_handler.py +26 -0
- config.py +24 -0
- pipeline.json +100 -0
- requirements.txt +2 -0
app.py
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from config import Flask,pipeline_dict,Response,convHandler
|
2 |
+
from application.chat_inference import ChatInference
|
3 |
+
from flask import render_template,request
|
4 |
+
|
5 |
+
app = Flask(__name__, template_folder='application/templates', static_folder='application/static')
|
6 |
+
|
7 |
+
chat_inference = ChatInference()
|
8 |
+
|
9 |
+
@app.route('/')
|
10 |
+
def home():
|
11 |
+
return render_template('index.html')
|
12 |
+
|
13 |
+
@app.route('/completions',methods=['POST'])
|
14 |
+
def completeions():
|
15 |
+
data = request.json
|
16 |
+
models = pipeline_dict['api']['models']
|
17 |
+
if(data.get('model',None) not in models):
|
18 |
+
return "Model Not Found", 404
|
19 |
+
model_info = models[data['model']]
|
20 |
+
data.update(
|
21 |
+
{
|
22 |
+
"base_url": model_info['api_url'],
|
23 |
+
"type": model_info['type']
|
24 |
+
}
|
25 |
+
)
|
26 |
+
return chat_inference.chat(data=data,handle_stream=pipeline_dict['handle_stream'],user=request.remote_addr)
|
27 |
+
|
28 |
+
@app.route('/convs')
|
29 |
+
def get_conv():
|
30 |
+
print(request.remote_addr)
|
31 |
+
return convHandler.get_conv(request.remote_addr)
|
32 |
+
|
33 |
+
@app.route('/create', methods=['POST'])
|
34 |
+
def create_conv():
|
35 |
+
sysPrompt = request.json.get('system_prompt', '')
|
36 |
+
return convHandler.create_conv(ip=request.remote_addr,sysPrompt=sysPrompt)
|
37 |
+
@app.route('/fetch', methods=['POST'])
|
38 |
+
def fetch():
|
39 |
+
convId = request.json.get('convId')
|
40 |
+
return convHandler.fetch_conv(convId=convId,ip=request.remote_addr)
|
41 |
+
@app.route('/update')
|
42 |
+
def update():
|
43 |
+
return convHandler.update_conv(request.remote_addr, request.json)
|
44 |
+
@app.route('/models')
|
45 |
+
def models():
|
46 |
+
return list(pipeline_dict['api']['models'].keys())
|
47 |
+
|
48 |
+
app.run(host='0.0.0.0',port=5000,debug=False)
|
application/__pycache__/chat_inference.cpython-311.pyc
ADDED
Binary file (4.29 kB). View file
|
|
application/chat_inference.py
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from application.utils.chat_completion_api import ChatCompletionAPI
|
2 |
+
from config import Response,pipeline_dict,convs_dict
|
3 |
+
import os
|
4 |
+
class ChatInference:
|
5 |
+
def __init__(self):
|
6 |
+
self.chatCompletionAPI = ChatCompletionAPI()
|
7 |
+
|
8 |
+
def validate(self,data,user):
|
9 |
+
try:
|
10 |
+
pipeline = pipeline_dict['api']['models']
|
11 |
+
model = data['model']
|
12 |
+
self.headers = pipeline[model]['headers']
|
13 |
+
self.updateHeaders = {}
|
14 |
+
for header in self.headers:
|
15 |
+
if(header=="config"):
|
16 |
+
for configHeader in self.headers[header]:
|
17 |
+
if(configHeader=="Authorization"):
|
18 |
+
auth = self.headers[header][configHeader].split(' ')
|
19 |
+
self.updateHeaders[configHeader] = f"{auth[0]} {eval(auth[1])}"
|
20 |
+
elif(configHeader=="comment"):
|
21 |
+
pass
|
22 |
+
else:
|
23 |
+
self.updateHeaders[configHeader] = f"{eval(self.headers[header][configHeader])}"
|
24 |
+
else:
|
25 |
+
self.updateHeaders[header] = self.headers[header]
|
26 |
+
prompt = data['prompt']
|
27 |
+
max_tokens = data.get('max_token', 1024)
|
28 |
+
temperature = max(0, min(data.get('temperature', 0.7), 2))
|
29 |
+
top_p = max(0.1, min(data.get('top_p', 0.9), 1))
|
30 |
+
system = data.get('system_prompt','')
|
31 |
+
convId = data['convId']
|
32 |
+
|
33 |
+
if(len(convs_dict[user][convId]['messages'])==1):
|
34 |
+
#convs_dict[user][convId]['messages'].append({"role":"system", "content": system})
|
35 |
+
convs_dict[user]['metadata'].insert(0,{"convId": convId, "title": prompt[:23]})
|
36 |
+
convs_dict[user][convId]['title'] = prompt[:30]
|
37 |
+
if(pipeline[model]['type'] == 'image-text-to-text'):
|
38 |
+
convs_dict[user][convId]['messages'].append({"role": "user", "content": [{"type":"text","text":prompt}]})
|
39 |
+
else:
|
40 |
+
convs_dict[user][convId]['messages'].append({"role":"user","content":prompt})
|
41 |
+
transformed = {
|
42 |
+
"model": model,
|
43 |
+
"prompt": prompt,
|
44 |
+
"messages": convs_dict[user][convId]['messages'],
|
45 |
+
"max_tokens": max_tokens,
|
46 |
+
"temperature": temperature,
|
47 |
+
"top_p": top_p,
|
48 |
+
"stream": True
|
49 |
+
}
|
50 |
+
data.update(transformed)
|
51 |
+
return data
|
52 |
+
except KeyError:
|
53 |
+
return 400
|
54 |
+
|
55 |
+
def chat(self,data,handle_stream,user):
|
56 |
+
data = self.validate(data=data,user=user)
|
57 |
+
if(data==400):
|
58 |
+
return "Required Parameters are Missing!", 400
|
59 |
+
|
60 |
+
return self.chatCompletionAPI.make_request(json=data,url=data['base_url'],handle_stream=handle_stream,messages=data['messages'], headers=self.updateHeaders)
|
61 |
+
|
62 |
+
|
63 |
+
|
application/static/css/style.css
ADDED
@@ -0,0 +1,317 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
::-webkit-scrollbar {
|
2 |
+
width: 12px;
|
3 |
+
}
|
4 |
+
|
5 |
+
::-webkit-scrollbar-track {
|
6 |
+
background: transparent;
|
7 |
+
}
|
8 |
+
|
9 |
+
::-webkit-scrollbar-thumb {
|
10 |
+
background: rgb(43, 43, 43);
|
11 |
+
border-radius: 6px;
|
12 |
+
}
|
13 |
+
|
14 |
+
::-webkit-scrollbar-thumb:hover {
|
15 |
+
background: rgb(119, 119, 119);
|
16 |
+
}
|
17 |
+
html,body{
|
18 |
+
padding: 0;
|
19 |
+
margin: 0;
|
20 |
+
background-color: rgb(2,2,8);
|
21 |
+
width: 100vw;
|
22 |
+
height: 100vh;
|
23 |
+
overflow: hidden;
|
24 |
+
scrollbar-width: thin;
|
25 |
+
scrollbar-color: rgb(41, 41, 41) transparent;
|
26 |
+
font-family: 'Inter';
|
27 |
+
|
28 |
+
}
|
29 |
+
nav{
|
30 |
+
position: fixed;
|
31 |
+
width: 100vw;
|
32 |
+
height: 8vh;
|
33 |
+
z-index: 100;
|
34 |
+
display: flex;
|
35 |
+
}
|
36 |
+
.hamburger{
|
37 |
+
display: flex;
|
38 |
+
flex-direction: column;
|
39 |
+
gap: 1.5vh;
|
40 |
+
width: 20vh;
|
41 |
+
color: white;
|
42 |
+
margin: 1vw;
|
43 |
+
cursor: pointer;
|
44 |
+
position: absolute;
|
45 |
+
z-index: 101;
|
46 |
+
}
|
47 |
+
.line1{
|
48 |
+
background-color: rgb(122, 122, 122);
|
49 |
+
width: 7vh;
|
50 |
+
height: 0.5vh;
|
51 |
+
}
|
52 |
+
.line2{
|
53 |
+
background-color: rgb(104, 104, 104);
|
54 |
+
width: 4vh;
|
55 |
+
height: 0.5vh;
|
56 |
+
}
|
57 |
+
|
58 |
+
.hamburger:hover .line1{
|
59 |
+
transform: translateX(-30px);
|
60 |
+
transition: transform 1s ease;
|
61 |
+
}
|
62 |
+
.hamburger:hover .line2{
|
63 |
+
transform: translateX(30px);
|
64 |
+
transition: transform 1s ease;
|
65 |
+
}
|
66 |
+
.menu{
|
67 |
+
height: 100vh;
|
68 |
+
width: 0px;
|
69 |
+
background-color: rgba(20, 20, 20,0.5);
|
70 |
+
border-radius: 10px;
|
71 |
+
position: fixed;
|
72 |
+
top: 0;
|
73 |
+
left: 0;
|
74 |
+
display: flex;
|
75 |
+
flex-direction: column;
|
76 |
+
overflow-y: auto;
|
77 |
+
}
|
78 |
+
.newChat{
|
79 |
+
margin-top: 8vh;
|
80 |
+
margin-left: 1vw;
|
81 |
+
background: linear-gradient(to right,rgb(206, 206, 206), rgb(87, 87, 87));
|
82 |
+
background-clip: text;
|
83 |
+
color: transparent;
|
84 |
+
font-size: large;
|
85 |
+
cursor: pointer;
|
86 |
+
font-weight: 400;
|
87 |
+
position: relative;
|
88 |
+
font-size: large;
|
89 |
+
}
|
90 |
+
.newChat:hover{
|
91 |
+
transform: scale(0.95);
|
92 |
+
transition: transform 0.7s ease;
|
93 |
+
}
|
94 |
+
.prevChatsCont{
|
95 |
+
color: rgb(172, 171, 171);
|
96 |
+
margin-left: 1vw;
|
97 |
+
font-weight: 300;
|
98 |
+
display: flex;
|
99 |
+
flex-direction: column;
|
100 |
+
gap: 1vh;
|
101 |
+
position: relative;
|
102 |
+
font-size: medium;
|
103 |
+
|
104 |
+
}
|
105 |
+
.prevChat{
|
106 |
+
min-height: 5vh;
|
107 |
+
cursor: pointer;
|
108 |
+
width: 90%;
|
109 |
+
display: flex;
|
110 |
+
align-items: center;
|
111 |
+
padding-left: 5%;
|
112 |
+
border-radius: 10px;
|
113 |
+
overflow: hidden;
|
114 |
+
padding-top: 1%;
|
115 |
+
padding-bottom: 1%;
|
116 |
+
position: relative;
|
117 |
+
}
|
118 |
+
.prevChat:hover{
|
119 |
+
background-color: rgba(70,70, 70,1);
|
120 |
+
transform: translateY(5px);
|
121 |
+
transition: transform 0.8s ease;
|
122 |
+
}
|
123 |
+
.chatsTxt{
|
124 |
+
color: #fdffdf;
|
125 |
+
margin-left: 1vw;
|
126 |
+
font-size: 14px;
|
127 |
+
margin-top: 4vh;
|
128 |
+
margin-bottom: 3vh;
|
129 |
+
z-index: 100;
|
130 |
+
overflow: hidden;
|
131 |
+
min-height: 5vh;
|
132 |
+
display: flex;
|
133 |
+
align-items: center;
|
134 |
+
|
135 |
+
}
|
136 |
+
|
137 |
+
.container {
|
138 |
+
width: 99.5%;
|
139 |
+
max-width: 99.5%;
|
140 |
+
height: 91.5vh;
|
141 |
+
position: absolute;
|
142 |
+
z-index: 50;
|
143 |
+
top: 8vh;
|
144 |
+
display: flex;
|
145 |
+
flex-direction: column;
|
146 |
+
justify-content: flex-end;
|
147 |
+
z-index: 1;
|
148 |
+
}
|
149 |
+
|
150 |
+
.inputs {
|
151 |
+
width: 70%;
|
152 |
+
display: flex;
|
153 |
+
flex-direction: row;
|
154 |
+
justify-content: space-between;
|
155 |
+
align-items: center;
|
156 |
+
background-color: rgba(51, 51, 51, 0.4);
|
157 |
+
padding: 10px;
|
158 |
+
border-top-right-radius: 50px;
|
159 |
+
border-bottom-left-radius: 20px;
|
160 |
+
border-top-left-radius: 20px;
|
161 |
+
border-bottom-right-radius: 50px;
|
162 |
+
font-size: large;
|
163 |
+
position: relative;
|
164 |
+
margin-top: auto;
|
165 |
+
align-self: center;
|
166 |
+
margin-bottom: 1.5vh;
|
167 |
+
}
|
168 |
+
|
169 |
+
.textBox{
|
170 |
+
width: 90%;
|
171 |
+
background: none;
|
172 |
+
outline: none;
|
173 |
+
border: none;
|
174 |
+
color: rgb(161, 161, 161);
|
175 |
+
padding: 7px;
|
176 |
+
}
|
177 |
+
.sendBtn{
|
178 |
+
background-color: white;
|
179 |
+
border: none;
|
180 |
+
color: black;
|
181 |
+
font-size: x-large;
|
182 |
+
cursor: pointer;
|
183 |
+
border-radius: 50%;
|
184 |
+
width: 6vh;
|
185 |
+
height: 6vh;
|
186 |
+
}
|
187 |
+
.messages {
|
188 |
+
overflow-y: auto;
|
189 |
+
color: white;
|
190 |
+
padding: 10px;
|
191 |
+
display: flex;
|
192 |
+
flex-direction: column;
|
193 |
+
position: relative;
|
194 |
+
}
|
195 |
+
.user{
|
196 |
+
margin-left: auto;
|
197 |
+
max-width: 60%;
|
198 |
+
background-color: rgba(51, 51, 51, 0.4);
|
199 |
+
padding: 0.5vh 1.5vh 0.5vh 1.5vh;
|
200 |
+
text-align: left;
|
201 |
+
font-weight: 300;
|
202 |
+
border-radius: 10px;
|
203 |
+
box-shadow: 3px 3px rgb(36, 36, 36) inset;
|
204 |
+
font-size: medium;
|
205 |
+
line-height: 130%;
|
206 |
+
}
|
207 |
+
.user p{
|
208 |
+
color: #c5c5c5;
|
209 |
+
}
|
210 |
+
.ai{
|
211 |
+
text-align: left;
|
212 |
+
width: 70%;
|
213 |
+
margin-left: auto;
|
214 |
+
margin-right: auto;
|
215 |
+
margin-top: 2vh;
|
216 |
+
}
|
217 |
+
.ai p {
|
218 |
+
opacity: 0.95;
|
219 |
+
font-size: medium;
|
220 |
+
font-weight: 300;
|
221 |
+
line-height: 1.6;
|
222 |
+
color: #cfcfcf;
|
223 |
+
}
|
224 |
+
.user p, .ai p{
|
225 |
+
padding:0;
|
226 |
+
}
|
227 |
+
.subHeading,.heading{
|
228 |
+
padding: 1vh;
|
229 |
+
border-radius: 10px;
|
230 |
+
display: inline-block;
|
231 |
+
margin-bottom: 2vh;
|
232 |
+
margin-top: 2vh;
|
233 |
+
}
|
234 |
+
.subHeading{
|
235 |
+
background-color: rgba(51, 51, 51, 0.7);
|
236 |
+
}
|
237 |
+
.heading{
|
238 |
+
background-color: rgba(119, 16, 238, 0.55);
|
239 |
+
box-shadow: 6px 6px rgb(32, 32, 32) ;
|
240 |
+
|
241 |
+
}
|
242 |
+
code{
|
243 |
+
border-radius: 15px;
|
244 |
+
}
|
245 |
+
.models{
|
246 |
+
position: relative;
|
247 |
+
margin: auto;
|
248 |
+
padding: 10px ;
|
249 |
+
outline: none;
|
250 |
+
background-color: rgb(43, 43, 43);
|
251 |
+
color: rgb(177, 177, 177);
|
252 |
+
border: none;
|
253 |
+
border-radius: 10px;
|
254 |
+
}
|
255 |
+
.models:hover{
|
256 |
+
background-color: #383838;
|
257 |
+
}
|
258 |
+
.models option{
|
259 |
+
background-color: rgb(34, 34, 34);
|
260 |
+
color: #afafaf;
|
261 |
+
padding: 10px;
|
262 |
+
}
|
263 |
+
.alert{
|
264 |
+
position: absolute;
|
265 |
+
top: 50%;
|
266 |
+
left: 50%;
|
267 |
+
transform: translate(-50%,-50%);
|
268 |
+
width: 320px;
|
269 |
+
height: 300px;
|
270 |
+
display: flex;
|
271 |
+
flex-direction: column;
|
272 |
+
color: #d8d8d8;
|
273 |
+
background-color: #222222;
|
274 |
+
box-shadow: 6px 6px rgb(41, 41, 41) ;
|
275 |
+
justify-content: center;
|
276 |
+
z-index: 100;
|
277 |
+
}
|
278 |
+
.alert p{
|
279 |
+
float: left;
|
280 |
+
padding: 10px;
|
281 |
+
font-family: 'Inter';
|
282 |
+
font-weight: 300;
|
283 |
+
font-size: 15px;
|
284 |
+
color: #cfcfcf;
|
285 |
+
opacity: 0.9;
|
286 |
+
}
|
287 |
+
.closeAlert{
|
288 |
+
margin-left: auto;
|
289 |
+
margin-right: 10px;
|
290 |
+
margin-top: 10px;
|
291 |
+
background-color: rgb(247, 102, 102);
|
292 |
+
padding: 10px;
|
293 |
+
cursor: pointer;
|
294 |
+
border-radius: 10px;
|
295 |
+
color: #ffffff;
|
296 |
+
}
|
297 |
+
.note{
|
298 |
+
text-align: center;
|
299 |
+
background-color: rgba(119, 16, 238, 0.55);
|
300 |
+
box-shadow: 6px 6px rgb(32, 32, 32) ;
|
301 |
+
margin: auto;
|
302 |
+
width: 70px;
|
303 |
+
}
|
304 |
+
|
305 |
+
@media screen and (max-width: 780px){
|
306 |
+
.menu{
|
307 |
+
background-color: rgba(20, 20, 20);
|
308 |
+
}
|
309 |
+
.inputs{
|
310 |
+
width: 85%;
|
311 |
+
}
|
312 |
+
}
|
313 |
+
|
314 |
+
/* TO do .....*/
|
315 |
+
.textCustomization{
|
316 |
+
display: none;
|
317 |
+
}
|
application/static/js/components/chat.js
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import requests from "./request.js";
|
2 |
+
|
3 |
+
class Chat{
|
4 |
+
constructor(uiManager){
|
5 |
+
this.uiManager = uiManager;
|
6 |
+
}
|
7 |
+
async chat(){
|
8 |
+
let payload = {
|
9 |
+
"model": this.uiManager.initializer.model,
|
10 |
+
"prompt": this.uiManager.userP.innerText.trim(),
|
11 |
+
"convId": this.uiManager.initializer.convId,
|
12 |
+
"system": this.uiManager.initializer.systemPrompt,
|
13 |
+
"temperature": 0.7,
|
14 |
+
"top_p": 0.9
|
15 |
+
};
|
16 |
+
try {
|
17 |
+
if(this.uiManager.initializer.convId==null){
|
18 |
+
await this.uiManager.initializer.createConv();
|
19 |
+
payload["convId"] = this.uiManager.initializer.convId;
|
20 |
+
}
|
21 |
+
this.uiManager.textBox.value='';
|
22 |
+
this.uiManager.sendBtn.disabled = true;
|
23 |
+
const response = await requests.request('POST','/completions',{"Content-Type": "application/json"},JSON.stringify(payload),true);
|
24 |
+
for await (const chunk of response){
|
25 |
+
this.uiManager.aiP.innerHTML+=chunk;
|
26 |
+
this.uiManager.renderSymbols.renderAll(this.uiManager.aiP)
|
27 |
+
};
|
28 |
+
} catch (error) {
|
29 |
+
this.uiManager.sendBtn.disabled = false;
|
30 |
+
this.uiManager.aiP.innerHTML+= `<span class="error" style="color: red;">${error}</span>`;
|
31 |
+
return
|
32 |
+
}
|
33 |
+
this.uiManager.renderSymbols.renderCode(this.uiManager.aiP);
|
34 |
+
if(this.uiManager.initializer.convTitle==null){
|
35 |
+
this.uiManager.initializer.convTitle = this.uiManager.userP.innerText.substring(0,23);
|
36 |
+
this.uiManager.addChat();
|
37 |
+
}
|
38 |
+
this.uiManager.sendBtn.disabled = false;
|
39 |
+
|
40 |
+
}
|
41 |
+
}
|
42 |
+
|
43 |
+
export default Chat
|
application/static/js/components/initialize.js
ADDED
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import requests from "./request.js";
|
2 |
+
class Initialize{
|
3 |
+
constructor(uiManager){
|
4 |
+
this.convId;
|
5 |
+
this.convTitle;
|
6 |
+
this.uiManager = uiManager;
|
7 |
+
this.systemPrompt = `your response syntax should be: ***for heading*** \n ** for sub heading **`;
|
8 |
+
this.model = null;
|
9 |
+
}
|
10 |
+
|
11 |
+
async initialize(model=null){
|
12 |
+
this.convTitle=null;
|
13 |
+
this.convId=null;
|
14 |
+
this.uiManager.messagesDiv.innerHTML = '';
|
15 |
+
this.uiManager.prevChatsCont.innerHTML = '';
|
16 |
+
await this.fetchConvs();
|
17 |
+
document.querySelectorAll('.prevChat').forEach((elem)=>{
|
18 |
+
elem.addEventListener('click', ()=>{
|
19 |
+
this.reInitialize(elem.id)
|
20 |
+
})
|
21 |
+
})
|
22 |
+
if(model!=null){
|
23 |
+
this.model = model;
|
24 |
+
} else{
|
25 |
+
await this.fetchModels()
|
26 |
+
}
|
27 |
+
}
|
28 |
+
|
29 |
+
async reInitialize(id){
|
30 |
+
this.convTitle=null;
|
31 |
+
this.convId=null;
|
32 |
+
this.uiManager.messagesDiv.innerHTML = '';
|
33 |
+
await this.fetchConv(id);
|
34 |
+
}
|
35 |
+
|
36 |
+
async fetchConv(id){
|
37 |
+
try {
|
38 |
+
const response = await requests.request('POST','/fetch',{"Content-Type": "application/json"},JSON.stringify({"convId": id}),false);
|
39 |
+
if(!response.ok){
|
40 |
+
alert('error while fetching conversations')
|
41 |
+
return
|
42 |
+
}
|
43 |
+
let data = await response.json();
|
44 |
+
this.convTitle = data['title']
|
45 |
+
data = data['messages']
|
46 |
+
for(let i=0;i<data.length;i++){
|
47 |
+
const dict = data[i];
|
48 |
+
if(dict['role']=='user'){
|
49 |
+
this.uiManager.appendUserMsg(dict['content'])
|
50 |
+
}
|
51 |
+
else if(dict['role']=='assistant'){
|
52 |
+
this.uiManager.appendAiMsg(dict['content']);
|
53 |
+
this.uiManager.renderSymbols.renderAll(this.uiManager.aiP);
|
54 |
+
}
|
55 |
+
}
|
56 |
+
} catch (error) {
|
57 |
+
alert(`an error occured ${error}`)
|
58 |
+
console.log(error)
|
59 |
+
}
|
60 |
+
}
|
61 |
+
async fetchConvs(){
|
62 |
+
try {
|
63 |
+
const response = await requests.request('GET','/convs',{"Content-Type": "application/json"},null,false);
|
64 |
+
if(!response.ok){
|
65 |
+
alert('error while fetching conversations')
|
66 |
+
return
|
67 |
+
}
|
68 |
+
const data = await response.json();
|
69 |
+
for(let i=0;i<data.length;i++){
|
70 |
+
const prevChat = document.createElement('div');
|
71 |
+
const dict = data[i];
|
72 |
+
prevChat.id = dict['convId'];
|
73 |
+
prevChat.className = 'prevChat';
|
74 |
+
prevChat.innerText = dict['title'];
|
75 |
+
this.uiManager.prevChatsCont.appendChild(prevChat)
|
76 |
+
|
77 |
+
}
|
78 |
+
} catch (error) {
|
79 |
+
alert(`an error ocuured ${error}`)
|
80 |
+
}
|
81 |
+
}
|
82 |
+
async createConv(){
|
83 |
+
const response = await requests.request('POST', '/create', {"Content-Type": "application/json"},JSON.stringify({"system_prompt": this.systemPrompt}),false)
|
84 |
+
if(!response.ok){
|
85 |
+
alert('error while creating new Conversation')
|
86 |
+
return
|
87 |
+
}
|
88 |
+
const data = await response.json()
|
89 |
+
this.convId = data['convId']
|
90 |
+
}
|
91 |
+
async fetchModels(){
|
92 |
+
const response = await requests.request('GET', '/models', {"Content-Type": "application/json"},null,false)
|
93 |
+
if(!response.ok){
|
94 |
+
alert('error while fetching models')
|
95 |
+
return
|
96 |
+
}
|
97 |
+
const data = await response.json();
|
98 |
+
this.model = data[0];
|
99 |
+
this.uiManager.models.innerHTML = '';
|
100 |
+
for(let i=0; i<data.length;i++){
|
101 |
+
const opt = document.createElement('option')
|
102 |
+
opt.innerText = data[i];
|
103 |
+
this.uiManager.models.appendChild(opt)
|
104 |
+
}
|
105 |
+
this.uiManager.models.addEventListener('change', (e)=>{
|
106 |
+
const selected = e.target.value;
|
107 |
+
this.initialize(selected)
|
108 |
+
})
|
109 |
+
|
110 |
+
}
|
111 |
+
}
|
112 |
+
export default Initialize
|
application/static/js/components/navbar.js
ADDED
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
class Navbar {
|
2 |
+
constructor(UIManager) {
|
3 |
+
this.uiManager = UIManager;
|
4 |
+
this.menu = this.uiManager.menu;
|
5 |
+
this.hamburger = this.uiManager.hamburger;
|
6 |
+
this.container = this.uiManager.container;
|
7 |
+
this.state = true; // true = open, false = closed
|
8 |
+
this.menuWidth = 0;
|
9 |
+
this.containerWidth = this.container.clientWidth;
|
10 |
+
this.NAV_AREA_LARGE = 20; // % of window width
|
11 |
+
this.NAV_AREA_MEDIUM = 25; // % of window width
|
12 |
+
this.NAV_AREA_SMALL = 60; // % of window width
|
13 |
+
this.ANIMATION_STEP = 5; // pixels per frame
|
14 |
+
}
|
15 |
+
|
16 |
+
calculateNavArea() {
|
17 |
+
if (window.innerWidth > 785) {
|
18 |
+
return window.innerWidth < 1100
|
19 |
+
? window.innerWidth * (this.NAV_AREA_MEDIUM / 100)
|
20 |
+
: window.innerWidth * (this.NAV_AREA_LARGE / 100);
|
21 |
+
}
|
22 |
+
return window.innerWidth * (this.NAV_AREA_SMALL / 100);
|
23 |
+
}
|
24 |
+
|
25 |
+
toggleState() {
|
26 |
+
if (this.state) {
|
27 |
+
this.nav.close();
|
28 |
+
} else {
|
29 |
+
this.nav.open();
|
30 |
+
}
|
31 |
+
this.state = !this.state;
|
32 |
+
}
|
33 |
+
|
34 |
+
animateNav(action) {
|
35 |
+
if (action === 'open' && this.menuWidth < this.navArea) {
|
36 |
+
this.menuWidth += this.ANIMATION_STEP;
|
37 |
+
} else if (action === 'close' && this.menuWidth > 0) {
|
38 |
+
this.menuWidth -= this.ANIMATION_STEP;
|
39 |
+
} else {
|
40 |
+
return; // Stop animation
|
41 |
+
}
|
42 |
+
|
43 |
+
this.menu.style.width = `${this.menuWidth}px`;
|
44 |
+
if(window.innerWidth>775){
|
45 |
+
this.container.style.width = `${this.containerWidth - this.menuWidth}px`;
|
46 |
+
this.container.style.left = `${this.menuWidth}px`;
|
47 |
+
}
|
48 |
+
requestAnimationFrame(() => this.animateNav(action));
|
49 |
+
}
|
50 |
+
|
51 |
+
run() {
|
52 |
+
this.navArea = this.calculateNavArea();
|
53 |
+
this.nav = {
|
54 |
+
open: () => this.animateNav('open'),
|
55 |
+
close: () => this.animateNav('close'),
|
56 |
+
};
|
57 |
+
|
58 |
+
if (window.innerWidth <= 785) {
|
59 |
+
this.state = false;
|
60 |
+
} else {
|
61 |
+
this.nav.open();
|
62 |
+
}
|
63 |
+
|
64 |
+
this.hamburger.addEventListener('click', () => this.toggleState());
|
65 |
+
}
|
66 |
+
}
|
67 |
+
|
68 |
+
export default Navbar
|
application/static/js/components/renderSymbols.js
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
class RenderSymbols{
|
2 |
+
constructor(){
|
3 |
+
|
4 |
+
}
|
5 |
+
renderAll(elem){
|
6 |
+
this.renderText(elem);
|
7 |
+
this.renderCode(elem);
|
8 |
+
this.renderMath(elem)
|
9 |
+
}
|
10 |
+
renderMath(elem) {
|
11 |
+
let content = elem.innerHTML;
|
12 |
+
MathJax.typesetPromise([elem])
|
13 |
+
.then(() => {
|
14 |
+
|
15 |
+
})
|
16 |
+
.catch((err) => {
|
17 |
+
|
18 |
+
});
|
19 |
+
}
|
20 |
+
renderText(elem){
|
21 |
+
elem.innerHTML = elem.innerHTML.replace(/<br\s*\/?>/g, '\n');
|
22 |
+
elem.innerHTML = elem.innerHTML.replace(/\*\*\*(.*?)\*\*\*/g, '<span class="heading">$1</span>');
|
23 |
+
elem.innerHTML = elem.innerHTML.replace(/\*\*(.*?)\*\*/g, '<span class="subHeading">$1</span>');
|
24 |
+
elem.innerHTML = elem.innerHTML.replace(/\n/g, '<br>');
|
25 |
+
}
|
26 |
+
renderCode(element) {
|
27 |
+
let content = element.innerHTML;
|
28 |
+
if (content.includes("```") && content.split("```").length >= 3) {
|
29 |
+
content = content.replace(/```(\w*)<br>([\s\S]*?)```/g, (match, language, code) => {
|
30 |
+
code = code.replace(/<br>/g, '\n').trim();
|
31 |
+
language = language.trim() || 'text';
|
32 |
+
return `<pre class="code-block"><code class="language-${language}">${code}</code></pre>`;
|
33 |
+
});
|
34 |
+
|
35 |
+
element.innerHTML = content;
|
36 |
+
element.querySelectorAll('code:not(.hljs)').forEach(block => {
|
37 |
+
hljs.highlightElement(block);
|
38 |
+
});
|
39 |
+
}
|
40 |
+
}
|
41 |
+
|
42 |
+
}
|
43 |
+
export default RenderSymbols
|
application/static/js/components/request.js
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
class Request{
|
2 |
+
constructor(){
|
3 |
+
|
4 |
+
}
|
5 |
+
async request(method,url,headers={},payload=null,stream=false){
|
6 |
+
try {
|
7 |
+
const response = await fetch(url,{
|
8 |
+
method: method,
|
9 |
+
headers: headers,
|
10 |
+
body: payload
|
11 |
+
})
|
12 |
+
if(stream && response.ok){
|
13 |
+
return this.handleStream(response)
|
14 |
+
} else{
|
15 |
+
return response
|
16 |
+
}
|
17 |
+
} catch (error) {
|
18 |
+
return error
|
19 |
+
}
|
20 |
+
|
21 |
+
}
|
22 |
+
|
23 |
+
async *handleStream(response){
|
24 |
+
const reader = response.body.getReader();
|
25 |
+
const decoder = new TextDecoder();
|
26 |
+
while(true){
|
27 |
+
const {done,value} = await reader.read()
|
28 |
+
if(done){
|
29 |
+
break
|
30 |
+
}
|
31 |
+
const chunk = decoder.decode(value,{stream:true})
|
32 |
+
yield chunk
|
33 |
+
}
|
34 |
+
}
|
35 |
+
}
|
36 |
+
|
37 |
+
const requests = new Request()
|
38 |
+
export default requests
|
application/static/js/components/uiManager.js
ADDED
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import Initialize from "./initialize.js";
|
2 |
+
import Chat from "./chat.js";
|
3 |
+
import RenderSymbols from "./renderSymbols.js";
|
4 |
+
class UIManager{
|
5 |
+
constructor(){
|
6 |
+
this.initializer = new Initialize(this);
|
7 |
+
this.chat = new Chat(this);
|
8 |
+
this.renderSymbols = new RenderSymbols();
|
9 |
+
this.menu = document.getElementById('menu');
|
10 |
+
this.hamburger = document.getElementById('hamburger');
|
11 |
+
this.messagesDiv = document.getElementById('messages');
|
12 |
+
this.container = document.getElementById('container')
|
13 |
+
this.prevChatsCont = document.getElementById('prevChatsCont');
|
14 |
+
this.textBox = document.getElementById('textBox');
|
15 |
+
this.sendBtn = document.getElementById('sendBtn');
|
16 |
+
this.newChat = document.getElementById('newChat');
|
17 |
+
this.models = document.getElementById('models');
|
18 |
+
this.initialized = false;
|
19 |
+
this.aiDiv;
|
20 |
+
this.userDiv;
|
21 |
+
this.aiP;
|
22 |
+
this.userP;
|
23 |
+
}
|
24 |
+
async run(){
|
25 |
+
await this.initializer.initialize();
|
26 |
+
this.handleTextBoxHeight();
|
27 |
+
this.events();
|
28 |
+
}
|
29 |
+
events(){
|
30 |
+
this.sendBtn.addEventListener('click',()=>{
|
31 |
+
this.send();
|
32 |
+
})
|
33 |
+
window.addEventListener('keydown',(e)=>{
|
34 |
+
if(e.key=='Enter' && !this.sendBtn.disabled){
|
35 |
+
this.send();
|
36 |
+
}
|
37 |
+
})
|
38 |
+
this.newChat.addEventListener('click', async ()=>{
|
39 |
+
await this.initializer.initialize();
|
40 |
+
})
|
41 |
+
document.getElementById('closeAlert').onclick = ()=>{
|
42 |
+
document.getElementById('alert').style.display = 'none'
|
43 |
+
}
|
44 |
+
}
|
45 |
+
async send(){
|
46 |
+
this.appendUserMsg();
|
47 |
+
this.appendAiMsg();
|
48 |
+
await this.chat.chat();
|
49 |
+
}
|
50 |
+
|
51 |
+
appendUserMsg(msg=false){
|
52 |
+
this.userDiv = document.createElement('div');
|
53 |
+
this.userDiv.className = 'user';
|
54 |
+
this.userP = document.createElement('p');
|
55 |
+
if(msg){
|
56 |
+
this.userP.innerText = msg;
|
57 |
+
} else{
|
58 |
+
this.userP.innerText = this.textBox.value;
|
59 |
+
}
|
60 |
+
this.userDiv.appendChild(this.userP);
|
61 |
+
this.messagesDiv.appendChild(this.userDiv);
|
62 |
+
}
|
63 |
+
appendAiMsg(msg=false){
|
64 |
+
this.aiDiv = document.createElement('div');
|
65 |
+
this.aiDiv.className = 'ai';
|
66 |
+
this.aiP = document.createElement('p');
|
67 |
+
if(msg){
|
68 |
+
this.aiP.innerText=msg;
|
69 |
+
}
|
70 |
+
this.aiDiv.appendChild(this.aiP);
|
71 |
+
this.messagesDiv.appendChild(this.aiDiv);
|
72 |
+
}
|
73 |
+
handleTextBoxHeight() {
|
74 |
+
this.textBox.oninput = () => {
|
75 |
+
//this.textBox.value = this.textBox.value.trim();
|
76 |
+
this.textBox.style.height = 'auto';
|
77 |
+
if (this.textBox.scrollHeight <= 150) {
|
78 |
+
if(this.textBox.scrollHeight>60){
|
79 |
+
this.textBox.style.height = `${this.textBox.scrollHeight}px`;
|
80 |
+
}
|
81 |
+
} else {
|
82 |
+
this.textBox.style.height = '150px';
|
83 |
+
}
|
84 |
+
};
|
85 |
+
}
|
86 |
+
addChat(){
|
87 |
+
const prevChat = document.createElement('div');
|
88 |
+
prevChat.innerText = this.initializer.convTitle;
|
89 |
+
prevChat.className = 'prevChat';
|
90 |
+
prevChat.id = this.initializer.convId;
|
91 |
+
this.prevChatsCont.prepend(prevChat);
|
92 |
+
prevChat.style.backgroundColor = 'rgb(53, 53, 53)';
|
93 |
+
prevChat.addEventListener('click', ()=>{
|
94 |
+
this.initializer.reInitialize(prevChat.id);
|
95 |
+
})
|
96 |
+
}
|
97 |
+
}
|
98 |
+
export default UIManager
|
application/static/js/script.js
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import UIManager from "./components/uiManager.js";
|
2 |
+
import Navbar from "./components/navbar.js";
|
3 |
+
class App{
|
4 |
+
constructor(){
|
5 |
+
this.uiManager = new UIManager()
|
6 |
+
this.navbar = new Navbar(this.uiManager);
|
7 |
+
}
|
8 |
+
run(){
|
9 |
+
this.uiManager.run();
|
10 |
+
this.navbar.run();
|
11 |
+
}
|
12 |
+
}
|
13 |
+
const app = new App()
|
14 |
+
app.run();
|
application/templates/index.html
ADDED
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
5 |
+
<meta charset="UTF-8">
|
6 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
7 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
8 |
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;700&display=swap" rel="stylesheet">
|
9 |
+
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;500;700&display=swap" rel="stylesheet">
|
10 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/atom-one-dark.min.css">
|
11 |
+
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
|
12 |
+
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
|
13 |
+
<title>Chat Completion Demo</title>
|
14 |
+
</head>
|
15 |
+
<body>
|
16 |
+
<nav>
|
17 |
+
<select name="" id="models" class="models">
|
18 |
+
</select>
|
19 |
+
<div class="hamburger" id="hamburger">
|
20 |
+
<div class="line1"></div>
|
21 |
+
<div class="line2"></div>
|
22 |
+
</div>
|
23 |
+
<div class="menu" id="menu">
|
24 |
+
<div class="newChat" id="newChat">+ New Chat</div>
|
25 |
+
<p class="chatsTxt">chats</p>
|
26 |
+
<div class="prevChatsCont" id="prevChatsCont">
|
27 |
+
</div>
|
28 |
+
</div>
|
29 |
+
|
30 |
+
</nav>
|
31 |
+
<div class="container" id="container">
|
32 |
+
<div class="messages" id="messages">
|
33 |
+
</div>
|
34 |
+
<div class="inputs">
|
35 |
+
<textarea name="" id="textBox" class="textBox" placeholder="Enter your message..."></textarea>
|
36 |
+
<button id="sendBtn" class="sendBtn"><i class="fa-solid fa-arrow-up"></i></button>
|
37 |
+
</div>
|
38 |
+
</div>
|
39 |
+
<div class="alert" id="alert">
|
40 |
+
<div class="closeAlert" id="closeAlert">X</div>
|
41 |
+
<p class="note">Note</p>
|
42 |
+
<p>You can easily use your own API provider to run this application; just update the pipeline.json file</p>
|
43 |
+
<p>The file/image attachment feature for the vision model has not been implemented yet.</p>
|
44 |
+
</div>
|
45 |
+
<div class="textCustomization">
|
46 |
+
<div class="colors"></div>
|
47 |
+
<div class="fontSize"></div>
|
48 |
+
<div class="background"></div>
|
49 |
+
</div>
|
50 |
+
<script src="{{ url_for('static', filename='js/script.js') }}" type="module"></script>
|
51 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js"></script>
|
52 |
+
</body>
|
53 |
+
</html>
|
application/utils/__init__.py
ADDED
File without changes
|
application/utils/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (168 Bytes). View file
|
|
application/utils/__pycache__/chat_completion_api.cpython-311.pyc
ADDED
Binary file (2.91 kB). View file
|
|
application/utils/__pycache__/convs_handler.cpython-311.pyc
ADDED
Binary file (1.79 kB). View file
|
|
application/utils/chat_completion_api.py
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import requests,json
|
2 |
+
from config import Response
|
3 |
+
class ChatCompletionAPI():
|
4 |
+
def __init__(self):
|
5 |
+
pass
|
6 |
+
def make_request(
|
7 |
+
self,
|
8 |
+
method='POST',
|
9 |
+
stream=True,
|
10 |
+
handle_stream=False,
|
11 |
+
json=None,
|
12 |
+
url=None,
|
13 |
+
messages=None,
|
14 |
+
headers=None ):
|
15 |
+
self.headers = headers
|
16 |
+
self.messages = messages
|
17 |
+
response = requests.request(
|
18 |
+
url=url,
|
19 |
+
json=json,
|
20 |
+
stream=stream,
|
21 |
+
headers=self.headers,
|
22 |
+
method=method)
|
23 |
+
self.ai = ''
|
24 |
+
if(response.status_code!=200):
|
25 |
+
return f'an error occured\napi status_code: {response.status_code}\napi response: {response.text}',500
|
26 |
+
if(handle_stream):
|
27 |
+
return self.handle_stream(response=response)
|
28 |
+
else:
|
29 |
+
self.ai = response.text
|
30 |
+
self.messages.append({"role":"assistant","content":self.ai})
|
31 |
+
return ai
|
32 |
+
|
33 |
+
def handle_stream(self,response):
|
34 |
+
def generator():
|
35 |
+
for data in response.iter_lines():
|
36 |
+
data = data.decode()
|
37 |
+
data = data[6:]
|
38 |
+
|
39 |
+
try:
|
40 |
+
data = json.loads(data)
|
41 |
+
chunk = data['choices'][0]['delta']['content']
|
42 |
+
self.ai+=chunk
|
43 |
+
yield chunk
|
44 |
+
except json.JSONDecodeError:
|
45 |
+
pass
|
46 |
+
except Exception as e:
|
47 |
+
yield str(data)
|
48 |
+
return
|
49 |
+
self.messages.append({"role":"assistant","content":self.ai})
|
50 |
+
return Response(generator())
|
application/utils/convs_handler.py
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import uuid
|
2 |
+
class ConvHandler:
|
3 |
+
def __init__(self,convs_dict):
|
4 |
+
self.convs_dict = convs_dict;
|
5 |
+
|
6 |
+
def get_conv(self,ip):
|
7 |
+
if(ip not in self.convs_dict):
|
8 |
+
self.convs_dict[ip] = {"metadata": []}
|
9 |
+
return self.convs_dict[ip]['metadata']
|
10 |
+
|
11 |
+
def create_conv(self,ip,sysPrompt):
|
12 |
+
user = self.convs_dict.get(ip,False)
|
13 |
+
if(user==False):
|
14 |
+
return f"user not found. {self.convs_dict}", 404
|
15 |
+
convId = str(uuid.uuid4())
|
16 |
+
user[convId] = {
|
17 |
+
"messages": [{"role":"system", "content": sysPrompt}],
|
18 |
+
"title": "New Chat"
|
19 |
+
}
|
20 |
+
return {"convId": convId}
|
21 |
+
|
22 |
+
def fetch_conv(self,ip,convId):
|
23 |
+
user = self.convs_dict.get(ip,False)
|
24 |
+
if(user==False):
|
25 |
+
return f"user not found. {self.convs_dict}", 404
|
26 |
+
return user[convId]
|
config.py
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from flask import Flask,request,render_template,request,Response,jsonify
|
2 |
+
from application.utils.convs_handler import ConvHandler
|
3 |
+
import json
|
4 |
+
|
5 |
+
pipeline_path = './pipeline.json'
|
6 |
+
|
7 |
+
with open(pipeline_path, 'r') as file:
|
8 |
+
pipeline_dict = json.load(file)
|
9 |
+
|
10 |
+
convs_dict = {
|
11 |
+
#format---> ip:{
|
12 |
+
# convId:{
|
13 |
+
# messages = [],
|
14 |
+
# }
|
15 |
+
# ...
|
16 |
+
# metadata (a list containing all convId and title in dict format) = [
|
17 |
+
# {
|
18 |
+
# "convID",
|
19 |
+
# "convTitle"
|
20 |
+
# }...]
|
21 |
+
#
|
22 |
+
}
|
23 |
+
|
24 |
+
convHandler = ConvHandler(convs_dict=convs_dict)
|
pipeline.json
ADDED
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"api": {
|
3 |
+
"models": {
|
4 |
+
"Qwen2.5-Coder-32B-Instruct": {
|
5 |
+
"type": "Text Generation",
|
6 |
+
"api_url": "https://api-inference.huggingface.co/models/Qwen/Qwen2.5-Coder-32B-Instruct/v1/chat/completions",
|
7 |
+
"headers": {
|
8 |
+
"Content-Type": "application/json",
|
9 |
+
"x-use-cache": "false",
|
10 |
+
"config": {
|
11 |
+
"comment": "This section runs Python code. It retrieves the API key from your environment using 'os'. You can use this for Authorization headers or replace it with another type of headers, like 'ApiKey'.",
|
12 |
+
"Authorization": "Bearer os.environ.get('auth')"
|
13 |
+
}
|
14 |
+
}
|
15 |
+
},
|
16 |
+
|
17 |
+
"QwQ-32B-Preview": {
|
18 |
+
"type": "Text Generation",
|
19 |
+
"api_url": "https://api-inference.huggingface.co/models/Qwen/QwQ-32B-Preview/v1/chat/completions",
|
20 |
+
"headers": {
|
21 |
+
"Content-Type": "application/json",
|
22 |
+
"x-use-cache": "false",
|
23 |
+
"config": {
|
24 |
+
"comment": "This section runs Python code. It retrieves the API key from your environment using 'os'. You can use this for Authorization headers or replace it with another type of headers, like 'ApiKey'.",
|
25 |
+
"Authorization": "Bearer os.environ.get('auth')"
|
26 |
+
}
|
27 |
+
}
|
28 |
+
},
|
29 |
+
|
30 |
+
"SmallThinker-3B-Preview": {
|
31 |
+
"type": "Text Generation",
|
32 |
+
"api_url": "https://api-inference.huggingface.co/models/PowerInfer/SmallThinker-3B-Preview/v1/chat/completions",
|
33 |
+
"headers": {
|
34 |
+
"Content-Type": "application/json",
|
35 |
+
"x-use-cache": "false",
|
36 |
+
"config": {
|
37 |
+
"comment": "This section runs Python code. It retrieves the API key from your environment using 'os'. You can use this for Authorization headers or replace it with another type of headers, like 'ApiKey'.",
|
38 |
+
"Authorization": "Bearer os.environ.get('auth')"
|
39 |
+
}
|
40 |
+
}
|
41 |
+
},
|
42 |
+
|
43 |
+
"Mistral-Nemo-Instruct-2407": {
|
44 |
+
"type": "Text Generation",
|
45 |
+
"api_url": "https://api-inference.huggingface.co/models/mistralai/Mistral-Nemo-Instruct-2407/v1/chat/completions",
|
46 |
+
"headers": {
|
47 |
+
"Content-Type": "application/json",
|
48 |
+
"x-use-cache": "false",
|
49 |
+
"config": {
|
50 |
+
"comment": "This section runs Python code. It retrieves the API key from your environment using 'os'. You can use this for Authorization headers or replace it with another type of headers, like 'ApiKey'.",
|
51 |
+
"Authorization": "Bearer os.environ.get('auth')"
|
52 |
+
}
|
53 |
+
}
|
54 |
+
},
|
55 |
+
|
56 |
+
"Phi-3.5-mini-instruct": {
|
57 |
+
"type": "Text Generation",
|
58 |
+
"api_url": "https://api-inference.huggingface.co/models/microsoft/Phi-3.5-mini-instruct/v1/chat/completions",
|
59 |
+
"headers": {
|
60 |
+
"Content-Type": "application/json",
|
61 |
+
"x-use-cache": "false",
|
62 |
+
"config": {
|
63 |
+
"comment": "This section runs Python code. It retrieves the API key from your environment using 'os'. You can use this for Authorization headers or replace it with another type of headers, like 'ApiKey'.",
|
64 |
+
"Authorization": "Bearer os.environ.get('auth')"
|
65 |
+
}
|
66 |
+
}
|
67 |
+
},
|
68 |
+
|
69 |
+
"Llama-3.2-11B-Vision-Instruct": {
|
70 |
+
"type": "image-text-to-text",
|
71 |
+
"api_url": "https://api-inference.huggingface.co/models/meta-llama/Llama-3.2-11B-Vision-Instruct/v1/chat/completions",
|
72 |
+
"headers": {
|
73 |
+
"Content-Type": "application/json",
|
74 |
+
"x-use-cache": "false",
|
75 |
+
"config": {
|
76 |
+
"comment": "This section runs Python code. It retrieves the API key from your environment using 'os'. You can use this for Authorization headers or replace it with another type of headers, like 'ApiKey'.",
|
77 |
+
"Authorization": "Bearer os.environ.get('auth')"
|
78 |
+
}
|
79 |
+
}
|
80 |
+
},
|
81 |
+
|
82 |
+
|
83 |
+
"Meta-Llama-3-8B-Instruct": {
|
84 |
+
"type": "Text Generation",
|
85 |
+
"api_url": "https://api-inference.huggingface.co/models/meta-llama/Meta-Llama-3-8B-Instruct/v1/chat/completions",
|
86 |
+
"headers": {
|
87 |
+
"Content-Type": "application/json",
|
88 |
+
"x-use-cache": "false",
|
89 |
+
"config": {
|
90 |
+
"comment": "This section runs Python code. It retrieves the API key from your environment using 'os'. You can use this for Authorization headers or replace it with another type of headers, like 'ApiKey'.",
|
91 |
+
"Authorization": "Bearer os.environ.get('auth')"
|
92 |
+
}
|
93 |
+
}
|
94 |
+
}
|
95 |
+
|
96 |
+
|
97 |
+
}
|
98 |
+
},
|
99 |
+
"handle_stream": true
|
100 |
+
}
|
requirements.txt
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
Flask
|
2 |
+
requests
|