yasirme commited on
Commit
1daa44a
·
verified ·
1 Parent(s): 5f0e217

Upload 21 files

Browse files
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