rajeshradhakrishnan commited on
Commit
b6157a7
·
verified ·
1 Parent(s): 08f49ac

deploy at 2024-08-06 15:09:58.948539

Browse files
Files changed (10) hide show
  1. Dockerfile +10 -0
  2. LICENSE +21 -0
  3. README.md +2 -10
  4. dinkan.html +503 -0
  5. expendables.py +488 -0
  6. favicon.ico +0 -0
  7. main.py +489 -0
  8. polling.py +89 -0
  9. requirements.txt +5 -0
  10. simple.py +64 -0
Dockerfile ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10
2
+ WORKDIR /code
3
+ COPY --link --chown=1000 . .
4
+ RUN mkdir -p /tmp/cache/
5
+ RUN chmod a+rwx -R /tmp/cache/
6
+ ENV HF_HUB_CACHE=HF_HOME
7
+ RUN pip install --no-cache-dir -r requirements.txt
8
+
9
+ ENV PYTHONUNBUFFERED=1 PORT=7860
10
+ CMD ["python", "main.py"]
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Rajesh Radhakrishnan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md CHANGED
@@ -1,10 +1,2 @@
1
- ---
2
- title: Groqlet Expandables
3
- emoji: 🚀
4
- colorFrom: red
5
- colorTo: purple
6
- sdk: docker
7
- pinned: false
8
- ---
9
-
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
+ # aitemplate
2
+ research on generic ai tool use, search and code intepreter tool
 
 
 
 
 
 
 
 
dinkan.html ADDED
@@ -0,0 +1,503 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Chat Copilot</title>
7
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
8
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-icons/1.8.1/font/bootstrap-icons.min.css" rel="stylesheet">
9
+
10
+ <style>
11
+ body {
12
+ display: flex;
13
+ height: 100vh;
14
+ overflow: hidden;
15
+ }
16
+ #sidebar {
17
+ background-color: #f8f9fa;
18
+ padding: 10px;
19
+ overflow-y: auto;
20
+ height: 100vh;
21
+ }
22
+ #chat {
23
+ display: flex;
24
+ flex-direction: column;
25
+ height: 100vh;
26
+ overflow-y: hidden;
27
+ }
28
+ #chat-messages {
29
+ flex-grow: 1;
30
+ overflow-y: auto;
31
+ padding: 10px;
32
+ }
33
+ #chat-input {
34
+ padding: 10px;
35
+ border-top: 1px solid #e9ecef;
36
+ }
37
+ #documentsTab {
38
+ padding: 20px;
39
+ }
40
+ .file-upload {
41
+ display: none;
42
+ }
43
+ .file-icon {
44
+ width: 20px;
45
+ height: 20px;
46
+ }
47
+ .progress-bar {
48
+ width: 100%;
49
+ height: 100%;
50
+ background-color: #4caf50;
51
+ }
52
+ .container-fluid {
53
+ overflow-y: auto;
54
+ }
55
+ .form-label {
56
+ font-weight: bold;
57
+ }
58
+ .list-group-item {
59
+ cursor: pointer;
60
+ }
61
+ </style>
62
+ </head>
63
+ <body>
64
+ <div class="container-fluid">
65
+ <nav class="navbar navbar-expand-lg navbar-dark" style="background-color: #800080;">
66
+ <div class="container-fluid">
67
+ <a class="navbar-brand" href="#">Groqlet Expendables</a>
68
+ <div class="d-flex align-items-center">
69
+ <a class="nav-link text-white" href="#" style="margin-right: 10px;">
70
+ <i class="bi bi-plug"></i> Plugins
71
+ </a>
72
+ <img src="user-icon-url" alt="User Icon" class="rounded-circle" style="width: 30px; height: 30px;">
73
+ </div>
74
+ </div>
75
+ </nav>
76
+ <div class="row">
77
+ <!-- Sidebar -->
78
+ <div class="col-12 col-md-3" id="sidebar">
79
+ <div class="d-flex justify-content-between align-items-center mb-2">
80
+ <h4>Chat</h4>
81
+ <button class="btn btn-primary btn-sm" id="addChatBtn">+</button>
82
+ </div>
83
+ <ul class="list-group" id="chatList">
84
+ <!-- Dynamically populated agents list of chat items -->
85
+ <!-- <li class="list-group-item">
86
+ <div class="d-flex justify-content-between">
87
+ <span>Can you tell me a story?</span>
88
+ <small>11:10 PM</small>
89
+ </div>
90
+ </li> -->
91
+
92
+ </ul>
93
+ </div>
94
+ <!-- Context menu for renaming chat items -->
95
+ <div id="contextMenu" class="dropdown-menu" style="display:none; position:absolute;">
96
+ <a class="dropdown-item" href="#" id="renameItem">Rename</a>
97
+ </div>
98
+ <!-- Chat -->
99
+ <div class="col-12 col-md-9 d-flex flex-column" id="chat">
100
+ <ul class="nav nav-tabs">
101
+ <li class="nav-item">
102
+ <a class="nav-link active" data-bs-toggle="tab" href="#chatTab">Chat</a>
103
+ </li>
104
+ <li class="nav-item">
105
+ <a class="nav-link" data-bs-toggle="tab" href="#documentsTab">Documents</a>
106
+ </li>
107
+ <li class="nav-item">
108
+ <a class="nav-link" data-bs-toggle="tab" href="#plansTab">Plans</a>
109
+ </li>
110
+ <li class="nav-item">
111
+ <a class="nav-link" data-bs-toggle="tab" href="#personasTab">Personas</a>
112
+ </li>
113
+ </ul>
114
+ <div class="tab-content flex-grow-1">
115
+ <div class="tab-pane fade show active" id="chatTab">
116
+ <div id="chat-messages">
117
+ <div class="chat-message">
118
+ <strong>Copilot</strong>
119
+ <p>Hello, thank you for democratizing AI's productivity benefits with open source! How can I help you today?</p>
120
+ </div>
121
+ <div class="chat-message">
122
+ <strong>MB</strong>
123
+ <p>Can you tell me a story about a prince in a paragraph?</p>
124
+ </div>
125
+ </div>
126
+ <div id="chat-input" class="d-flex">
127
+ <input type="text" class="form-control me-2" placeholder="Type a message..." id="messageInput">
128
+ <button class="btn btn-primary" id="sendBtn">Send</button>
129
+ </div>
130
+ </div>
131
+ <div class="tab-pane fade" id="documentsTab">
132
+ <!-- Content for Documents tab -->
133
+ <div class="d-flex justify-content-between align-items-center mb-2">
134
+ <h4>Documents</h4>
135
+ <button class="btn btn-primary btn-sm" id="uploadBtn">Upload</button>
136
+ <input type="file" id="fileInput" class="file-upload">
137
+ </div>
138
+ <div class="d-flex mb-2">
139
+ <div class="form-check me-3">
140
+ <input class="form-check-input" type="radio" name="vectorDatabase" id="volatile" value="volatile">
141
+ <label class="form-check-label" for="volatile">Volatile</label>
142
+ </div>
143
+ <div class="form-check me-3">
144
+ <input class="form-check-input" type="radio" name="vectorDatabase" id="textFile" value="textFile" checked>
145
+ <label class="form-check-label" for="textFile">TextFile</label>
146
+ </div>
147
+ <div class="form-check me-3">
148
+ <input class="form-check-input" type="radio" name="vectorDatabase" id="qdrant" value="qdrant">
149
+ <label class="form-check-label" for="qdrant">Qdrant</label>
150
+ </div>
151
+ <div class="form-check">
152
+ <input class="form-check-input" type="radio" name="vectorDatabase" id="llamaindexSearch" value="llamaindexSearch">
153
+ <label class="form-check-label" for="llamaindexSearch">llamaindex Search</label>
154
+ </div>
155
+ </div>
156
+ <table class="table">
157
+ <thead>
158
+ <tr>
159
+ <th>Name</th>
160
+ <th>Created on</th>
161
+ <th>Size (bytes)</th>
162
+ <th>Access</th>
163
+ <th>Progress</th>
164
+ </tr>
165
+ </thead>
166
+ <tbody id="fileTable">
167
+ <tr>
168
+ <td><i class="bi bi-file-earmark-text file-icon"></i> reconciliation.txt</td>
169
+ <td>9:38 am</td>
170
+ <td>30,079</td>
171
+ <td>This chat</td>
172
+ <td><div class="progress"><div class="progress-bar"></div></div></td>
173
+ </tr>
174
+ </tbody>
175
+ </table>
176
+ </div>
177
+ <div class="tab-pane fade" id="plansTab">
178
+ <!-- Content for Plans tab -->
179
+ <table class="table">
180
+ <thead>
181
+ <tr>
182
+ <th>Goal</th>
183
+ <th>Created on</th>
184
+ <th>Token Count</th>
185
+ </tr>
186
+ </thead>
187
+ <tbody id="planTable">
188
+ <tr>
189
+ <td>askQuestions</td>
190
+ <td>9:38 am</td>
191
+ <td>30,079</td>
192
+ </tr>
193
+ </tbody>
194
+ </table>
195
+ </div>
196
+ <div class="tab-pane fade" id="personasTab">
197
+ <!-- Content for Personas tab -->
198
+ <div class="container-fluid p-3">
199
+ <h4>Persona</h4>
200
+ <div class="mb-3">
201
+ <label for="agentNameInput" class="form-label">Agent Name</label>
202
+ <input type="text" class="form-control" id="agentNameInput" placeholder="Enter your agent's name...">
203
+ </div>
204
+ <div class="mb-3">
205
+ <label for="metaPromptInput" class="form-label">Meta Prompt</label>
206
+ <textarea class="form-control" id="metaPromptInput" rows="3" placeholder="Enter your Meta Prompt..."></textarea>
207
+ </div>
208
+ <div class="mb-3">
209
+ <label for="prefillInput" class="form-label">Prefill</label>
210
+ <textarea class="form-control" id="prefillInput" rows="3" placeholder="Enter agent's prefill..."></textarea>
211
+ </div>
212
+ <div class="d-flex justify-content-end">
213
+ <button class="btn btn-primary" id="savePlanBtn">Save</button>
214
+ </div>
215
+ <hr>
216
+ <h5>Saved Plans</h5>
217
+ <ul class="list-group" id="savedPlansList">
218
+ <!-- Dynamically populated list of saved plans -->
219
+ </ul>
220
+ </div>
221
+ </div>
222
+ </div>
223
+ </div>
224
+
225
+ </div>
226
+ </div>
227
+
228
+ <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
229
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
230
+ <script>
231
+ let agents = [
232
+ {
233
+ "Persona": {
234
+ "agentname": "dinkan-1",
235
+ "metaprompt": "you are a helpful assistant",
236
+ "prefill": "helps me with financial Reconciliation",
237
+ "tooluse": "true",
238
+ "filesearch": "true",
239
+ "codeinterpreter": "true"
240
+ },
241
+ "Plans": [
242
+ { "name": "askquestion", "createon": "06/8/2024", "tokencount": "2048" }
243
+ ],
244
+ "Documents": [
245
+ { "file": "./reconciliation.txt", "createon": "06/8/2024", "size": "30,079", "Access": "private", "progress": "success" },
246
+ { "file": "./design.pdf", "createon": "07/8/2024", "size": "30,079", "Access": "public", "progress": "error" }
247
+ ],
248
+ "Chat": [
249
+ {"role": "system", "content":"Hello, thank you for democratizing AI's productivity benefits with open source! How can I help you today?"},
250
+ { "role": "assistant", "content": "what is the capital of India" },
251
+ { "role": "user", "content": "New Delhi is the capital of India" }
252
+ ]
253
+ },
254
+ {
255
+ "Persona": {
256
+ "agentname": "dinkan-2",
257
+ "metaprompt": "you are a helpful assistant",
258
+ "prefill": "helps me with financial Reconciliation",
259
+ "tooluse": "true",
260
+ "filesearch": "false",
261
+ "codeinterpreter": "false"
262
+ },
263
+ "Plans": [
264
+ { "name": "calculate", "createon": "07/8/2024", "tokencount": "1024" }
265
+ ],
266
+ "Documents": [
267
+ { "file": "./design.txt", "createon": "08/8/2024", "size": "30,079", "Access": "private", "progress": "success" },
268
+ { "file": "./design.pdf", "createon": "09/8/2024", "size": "30,079", "Access": "public", "progress": "error" }
269
+ ],
270
+ "Chat": [
271
+ {"role": "system", "content":"Hello, thank you for democratizing AI's productivity benefits with open source! How can I help you today?"},
272
+ { "role": "assistant", "content": "what is the capital of Kerala" },
273
+ { "role": "user", "content": "Trivandrum is the capital of India" }
274
+ ]
275
+ }
276
+ ];
277
+
278
+ let selectedAgentIndex = -1;
279
+
280
+ function populateTabs() {
281
+ if (selectedAgentIndex >= 0) {
282
+ const selectedAgent = agents[selectedAgentIndex];
283
+
284
+ // Populate Personas tab
285
+ const agentNameInput = document.getElementById('agentNameInput');
286
+ const metaPromptInput = document.getElementById('metaPromptInput');
287
+ const prefillInput = document.getElementById('prefillInput');
288
+
289
+ agentNameInput.value = agents[selectedAgentIndex].Persona.agentname;
290
+ metaPromptInput.value = agents[selectedAgentIndex].Persona.metaprompt;
291
+ prefillInput.value = agents[selectedAgentIndex].Persona.prefill;
292
+
293
+ // Populate Plans tab
294
+ // Clear and repopulate the plans table or list with selectedAgent.Plans
295
+ const planTable = document.getElementById('planTable');
296
+ planTable.innerHTML = '';
297
+ agents[selectedAgentIndex].Plans.forEach(plan => {
298
+ const newRow = `<tr>
299
+ <td>${plan.name}</td>
300
+ <td>${plan.createon}</td>
301
+ <td>${plan.tokencount}</td>
302
+ </tr>`;
303
+ planTable.insertAdjacentHTML('beforeend', newRow);
304
+ });
305
+ // Populate Documents tab
306
+ // Clear and repopulate the documents table with selectedAgent.Documents
307
+ const fileTable = document.getElementById('fileTable');
308
+ fileTable.innerHTML = '';
309
+ agents[selectedAgentIndex].Documents.forEach(doc => {
310
+ const newRow = `<tr>
311
+ <td><i class="bi bi-file-earmark-text file-icon"></i> ${doc.file}</td>
312
+ <td>${doc.createon}</td>
313
+ <td>${doc.size}</td>
314
+ <td>${doc.Access}</td>
315
+ <td><div class="progress"><div class="progress-bar"></div></div></td>
316
+ </tr>`;
317
+ fileTable.insertAdjacentHTML('beforeend', newRow);
318
+ });
319
+ // Display initial messages
320
+ //displayMessages();
321
+ }
322
+ }
323
+
324
+ function renderChatList() {
325
+ const chatList = document.getElementById('chatList');
326
+ chatList.innerHTML = ''; // Clear the existing list
327
+
328
+ agents.forEach((agent, index) => {
329
+ const newItem = document.createElement('li');
330
+ newItem.className = 'list-group-item';
331
+ newItem.innerHTML = `<div class="d-flex justify-content-between">
332
+ <span>${agent.Persona.agentname}</span>
333
+ <small>${new Date().toLocaleTimeString()}</small>
334
+ </div>`;
335
+ newItem.setAttribute('data-index', index);
336
+ newItem.setAttribute('data-messages', JSON.stringify(agent.Chat));
337
+ newItem.addEventListener('click', function() {
338
+ selectedAgentIndex = parseInt(this.getAttribute('data-index'));
339
+ displayMessages();
340
+ populateTabs();
341
+ });
342
+ newItem.addEventListener('contextmenu', function(e) {
343
+ e.preventDefault();
344
+ showContextMenu(e, newItem, index);
345
+ });
346
+ chatList.appendChild(newItem);
347
+ });
348
+ }
349
+ // Event listener for add chat button - Sidebar
350
+ document.getElementById('addChatBtn').addEventListener('click', function() {
351
+ var chatList = document.getElementById('chatList');
352
+ var newItem = document.createElement('li');
353
+ newItem.className = 'list-group-item';
354
+ newItem.innerHTML = `<div class="d-flex justify-content-between">
355
+ <span>New Agent</span>
356
+ <small>${new Date().toLocaleTimeString()}</small>
357
+ </div>`;
358
+ newItem.setAttribute('data-messages', JSON.stringify([]));
359
+ chatList.appendChild(newItem);
360
+
361
+ // Add new agent to agents array
362
+ var newAgent = {
363
+ "Persona": {
364
+ "agentname": `agent-${Date.now()}`,
365
+ "metaprompt": "you are a helpful assistant",
366
+ "prefill": "helps me with financial Reconciliation",
367
+ "tooluse": "true",
368
+ "filesearch": "false",
369
+ "codeinterpreter": "false"
370
+ },
371
+ "Plans": [],
372
+ "Documents": [],
373
+ "Chat": []
374
+ };
375
+ agents.push(newAgent);
376
+ renderChatList();
377
+ });
378
+
379
+ // Show context menu
380
+ function showContextMenu(event, listItem) {
381
+ var contextMenu = document.getElementById('contextMenu');
382
+ contextMenu.style.display = 'block';
383
+ contextMenu.style.left = event.pageX + 'px';
384
+ contextMenu.style.top = event.pageY + 'px';
385
+
386
+ document.getElementById('renameItem').onclick = function() {
387
+ var newName = prompt("Enter new name:", listItem.querySelector('span').textContent);
388
+ if (newName) {
389
+ listItem.querySelector('span').textContent = newName;
390
+ //write a code to update the agent name in agents array
391
+ agents[selectedAgentIndex].Persona.agentname = newName;
392
+ }
393
+ contextMenu.style.display = 'none';
394
+ };
395
+
396
+ document.addEventListener('click', function() {
397
+ contextMenu.style.display = 'none';
398
+ }, { once: true });
399
+ }
400
+
401
+ // Event listener for existing items
402
+ document.querySelectorAll('#chatList .list-group-item').forEach(item => {
403
+ item.addEventListener('contextmenu', function(e) {
404
+ e.preventDefault();
405
+ showContextMenu(e, item);
406
+ });
407
+ });
408
+ // Function to display messages
409
+ function displayMessages() {
410
+ const chatMessages = document.getElementById('chat-messages');
411
+ chatMessages.innerHTML = '';
412
+ agents[selectedAgentIndex].Chat.forEach(msg => {
413
+ const messageElement = document.createElement('div');
414
+ messageElement.classList.add('chat-message');
415
+ messageElement.innerHTML = `<strong>${msg.role}</strong><p>${msg.content}</p>`;
416
+ chatMessages.appendChild(messageElement);
417
+ });
418
+ }
419
+
420
+ // Event listener for sidebar items
421
+ document.querySelectorAll('#chatList .list-group-item').forEach(item => {
422
+ item.addEventListener('click', function() {
423
+ const newMessages = JSON.parse(this.getAttribute('data-messages'));
424
+ messages = [...newMessages];
425
+ displayMessages();
426
+ });
427
+ });
428
+
429
+ // Event listener for send button
430
+ document.getElementById('sendBtn').addEventListener('click', function() {
431
+ const input = document.getElementById('messageInput');
432
+ const userMessage = input.value;
433
+ if (userMessage) {
434
+ agents[selectedAgentIndex].Chat.push({ role: 'MB', content: userMessage });
435
+ if (userMessage.toLowerCase() === 'what is the capital of india') {
436
+ agents[0].Chat.push({ role: 'Copilot', content: 'New Delhi is the capital of India' });
437
+ }
438
+ displayMessages();
439
+ input.value = '';
440
+ }
441
+ });
442
+
443
+ // Event listener for upload button
444
+ document.getElementById('uploadBtn').addEventListener('click', function() {
445
+ document.getElementById('fileInput').click();
446
+ });
447
+
448
+ // Event listener for file input - Documents Tab
449
+ document.getElementById('fileInput').addEventListener('change', function(event) {
450
+ const file = event.target.files[0];
451
+ if (file) {
452
+ const newRow = `<tr>
453
+ <td><i class="bi bi-file-earmark-text file-icon"></i> ${file.name}</td>
454
+ <td>${new Date().toLocaleTimeString()}</td>
455
+ <td>${file.size}</td>
456
+ <td>This chat</td>
457
+ <td><div class="progress"><div class="progress-bar"></div></div></td>
458
+ </tr>`;
459
+ document.getElementById('fileTable').insertAdjacentHTML('beforeend', newRow);
460
+ }
461
+ });
462
+
463
+ // Event listener for save button - Personas Tab
464
+ document.getElementById('savePlanBtn').addEventListener('click', function() {
465
+ const agentname = document.getElementById('agentNameInput').value;
466
+ const metaprompt = document.getElementById('metaPromptInput').value;
467
+ const prefill = document.getElementById('prefillInput').value;
468
+
469
+ const plan = {
470
+ agentname,
471
+ metaprompt,
472
+ prefill
473
+ };
474
+
475
+ const savedPlansList = document.getElementById('savedPlansList');
476
+ const planItem = document.createElement('li');
477
+ planItem.classList.add('list-group-item');
478
+ planItem.textContent = `Agent Name: ${agentname}`;
479
+ planItem.addEventListener('click', function() {
480
+ alert(`Meta Prompt: ${plan.metaprompt}\nPrefill: ${plan.prefill}`);
481
+ });
482
+
483
+ savedPlansList.appendChild(planItem);
484
+
485
+ // Clear the inputs after saving
486
+ document.getElementById('agentNameInput').value = '';
487
+ document.getElementById('metaPromptInput').value = '';
488
+ document.getElementById('prefillInput').value = '';
489
+ });
490
+
491
+
492
+
493
+ // Initial rendering of the chat list
494
+ renderChatList();
495
+
496
+ // Populate tabs initially (if needed)
497
+ populateTabs();
498
+
499
+
500
+
501
+ </script>
502
+ </body>
503
+ </html>
expendables.py ADDED
@@ -0,0 +1,488 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ from fasthtml.common import *
3
+
4
+ bootstraplink = Link(rel="stylesheet", href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css", integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC", crossorigin="anonymous")
5
+ fontlink = Link(rel="stylesheet", href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-icons/1.8.1/font/bootstrap-icons.min.css")
6
+ favicon = Link(rel="icon", type="image/x-icon", href="https://raw.githubusercontent.com/rajeshradhakrishnanmvk/aitemplate/main/favicon.ico")
7
+
8
+ title = Title("Groqlet Expendables")
9
+ css = Style("""body {
10
+ display: flex;
11
+ height: 100vh;
12
+ overflow: hidden;
13
+ }
14
+ #sidebar {
15
+ background-color: #f8f9fa;
16
+ padding: 10px;
17
+ overflow-y: auto;
18
+ height: 100vh;
19
+ }
20
+ #chat {
21
+ display: flex;
22
+ flex-direction: column;
23
+ height: 100vh;
24
+ overflow-y: hidden;
25
+ }
26
+ #chat-messages {
27
+ flex-grow: 1;
28
+ overflow-y: auto;
29
+ padding: 10px;
30
+ }
31
+ #chat-input {
32
+ padding: 10px;
33
+ border-top: 1px solid #e9ecef;
34
+ }
35
+ #documentsTab {
36
+ padding: 20px;
37
+ }
38
+ .file-upload {
39
+ display: none;
40
+ }
41
+ .file-icon {
42
+ width: 20px;
43
+ height: 20px;
44
+ }
45
+ .progress-bar {
46
+ width: 100%;
47
+ height: 100%;
48
+ background-color: #4caf50;
49
+ }
50
+ .container-fluid {
51
+ overflow-y: auto;
52
+ }
53
+ .form-label {
54
+ font-weight: bold;
55
+ }
56
+ .list-group-item {
57
+ cursor: pointer;
58
+ }""")
59
+
60
+ app = FastHTML(hdrs=(title,favicon,bootstraplink, fontlink,css))
61
+
62
+ data = json.dumps([
63
+ {
64
+ "Persona": {
65
+ "agentname": "dinkan-1",
66
+ "metaprompt": "you are a helpful assistant",
67
+ "prefill": "helps me with financial Reconciliation",
68
+ "tooluse": "true",
69
+ "filesearch": "true",
70
+ "codeinterpreter": "true"
71
+ },
72
+ "Plans": [
73
+ { "name": "askquestion", "createon": "06/8/2024", "tokencount": "2048" }
74
+ ],
75
+ "Documents": [
76
+ { "file": "./reconciliation.txt", "createon": "06/8/2024", "size": "30,079", "Access": "private", "progress": "success" },
77
+ { "file": "./design.pdf", "createon": "07/8/2024", "size": "30,079", "Access": "public", "progress": "error" }
78
+ ],
79
+ "Chat": [
80
+ {"role": "system", "content":"Hello, thank you for democratizing AI's productivity benefits with open source! How can I help you today?"},
81
+ { "role": "assistant", "content": "what is the capital of India" },
82
+ { "role": "user", "content": "New Delhi is the capital of India" }
83
+ ]
84
+ },
85
+ {
86
+ "Persona": {
87
+ "agentname": "dinkan-2",
88
+ "metaprompt": "you are a helpful assistant",
89
+ "prefill": "helps me with financial Reconciliation",
90
+ "tooluse": "true",
91
+ "filesearch": "false",
92
+ "codeinterpreter": "false"
93
+ },
94
+ "Plans": [
95
+ { "name": "calculate", "createon": "07/8/2024", "tokencount": "1024" }
96
+ ],
97
+ "Documents": [
98
+ { "file": "./design.txt", "createon": "08/8/2024", "size": "30,079", "Access": "private", "progress": "success" },
99
+ { "file": "./design.pdf", "createon": "09/8/2024", "size": "30,079", "Access": "public", "progress": "error" }
100
+ ],
101
+ "Chat": [
102
+ {"role": "system", "content":"Hello, thank you for democratizing AI's productivity benefits with open source! How can I help you today?"},
103
+ { "role": "assistant", "content": "what is the capital of Kerala" },
104
+ { "role": "user", "content": "Trivandrum is the capital of India" }
105
+ ]
106
+ }
107
+ ])
108
+
109
+
110
+ @app.route("/")
111
+ def get():
112
+ page = (Div(
113
+ Nav(
114
+ Div(
115
+ A("Groqlet Expendables", cls="navbar-brand", href="#"),
116
+ Div(
117
+ A(
118
+ I(cls="bi bi-plug"),
119
+ "Plugins", cls="nav-link text-white", href="#", style="margin-right: 10px;"),
120
+ A(
121
+ I(cls="bi bi-gear"),
122
+ "Settings", cls="nav-link text-white", href="#", style="margin-right: 10px;"),
123
+
124
+ Img(cls="rounded-circle", src="https://media.licdn.com/dms/image/C4D03AQHwjVMduekRjw/profile-displayphoto-shrink_100_100/0/1516794061157?e=1728518400&v=beta&t=JwjApmMV83LH01mtr8jUhh5wayHWFqPEhneLEU10HRI", alt="User Icon", style="width: 30px; height: 30px;")
125
+ ,cls="d-flex align-items-center")
126
+ ,cls="container-fluid")
127
+ ,cls="navbar navbar-expand-lg navbar-dark",style="background-color: #800080;"),
128
+ Div(
129
+ Div(
130
+ Div(
131
+ H4("Agents"),
132
+ Button("+", cls="btn btn-primary btn-sm", id="addChatBtn")
133
+ , cls="d-flex justify-content-between align-items-center mb-2"),
134
+ Ul(
135
+ Li(
136
+ Div(
137
+ Span("Can you tell me a story?"),
138
+ Small("11:10 PM")
139
+ , cls="d-flex justify-content-between")
140
+ , cls="list-group-item")
141
+ , cls="list-group", id="chatList")
142
+ , cls="col-12 col-md-3", id="sidebar"),
143
+ Div(
144
+ A("Rename", cls="dropdown-item", href="#", id="renameItem")
145
+ ,id="contextMenu", cls="dropdown-menu", style="display:none; position:absolute;"),
146
+ Div(
147
+ Ul(
148
+ Li(
149
+ A("Chat", cls="nav-link active", data_bs_toggle="tab", href="#chatTab")
150
+ , cls="nav-item"),
151
+ Li(
152
+ A("Documents", cls="nav-link", data_bs_toggle="tab", href="#documentsTab")
153
+ , cls="nav-item"),
154
+ Li(
155
+ A("Plans", cls="nav-link", data_bs_toggle="tab", href="#plansTab")
156
+ , cls="nav-item"),
157
+ Li(
158
+ A("Personas", cls="nav-link", data_bs_toggle="tab", href="#personasTab")
159
+ , cls="nav-item")
160
+ , cls="nav nav-tabs"),
161
+ Div(
162
+ Div(
163
+ Div(
164
+ Div(
165
+ Strong("Copilot"),
166
+ P("Hello, thank you for democratizing AI's productivity benefits with open source! How can I help you today?")
167
+ , cls="chat-message"),
168
+ Div(
169
+ Strong("MB"),
170
+ P("Can you tell me a story about a prince in a paragraph?")
171
+ , cls="chat-message")
172
+ , id="chat-messages"),
173
+ Div(
174
+ Input(type="text", cls="form-control me-2", placeholder="Type a message...", id="messageInput"),
175
+ Button("Send", cls="btn btn-primary", id="sendBtn")
176
+ , id="chat-input", cls="d-flex")
177
+ , cls="tab-pane fade show active", id="chatTab"),
178
+ Div(
179
+ Div(
180
+ H4("Documents"),
181
+ Button("Upload", cls="btn btn-primary btn-sm", id="uploadBtn"),
182
+ Input(type="file", id="fileInput", cls="file-upload")
183
+ , cls="d-flex justify-content-between align-items-center mb-2"),
184
+ Div(
185
+ Div(
186
+ Input(cls="form-check-input", type="radio", name="vectorDatabase", id="volatile", value="volatile"),
187
+ Label("Volatile", cls="form-check-label", _for="volatile")
188
+ , cls="form-check me-3"),
189
+ Div(
190
+ Input(cls="form-check-input", type="radio", name="vectorDatabase", id="textFile", value="textFile", checked=1),
191
+ Label("TextFile", cls="form-check-label", _for="textFile")
192
+ , cls="form-check me-3"),
193
+ Div(
194
+ Input(cls="form-check-input", type="radio", name="vectorDatabase", id="qdrant", value="qdrant"),
195
+ Label( "Qdrant", cls="form-check-label", _for="qdrant")
196
+ , cls="form-check me-3"),
197
+ Div(
198
+ Input(cls="form-check-input", type="radio", name="vectorDatabase", id="llamaindexSearch", value="llamaindexSearch"),
199
+ Label("llamaindex Search", cls="form-check-label", _for="llamaindexSearch")
200
+ , cls="form-check me-3")
201
+ ,cls="d-flex mb-2"),
202
+ Table(
203
+ Thead(),
204
+ Tr(
205
+ Th("Name"),
206
+ Th("Created on"),
207
+ Th("Size (bytes)"),
208
+ Th("Access"),
209
+ Th("Progress")),
210
+ Tbody(
211
+ Tr(
212
+ Td(I(cls="bi bi-file-earmark-text file-icon"), " reconciliation.txt"),
213
+ Td("9:38 am"),
214
+ Td("30,079"),
215
+ Td("This chat"),
216
+ Td(Div(cls="progress"),Div(cls="progress-bar"))),id="fileTable"),cls="table")
217
+ ,cls="tab-pane fade", id="documentsTab"),
218
+ Div(
219
+ Table(
220
+ Thead(),
221
+ Tr(
222
+ Th("Goal"),
223
+ Th("Created on"),
224
+ Th("Token Count")),
225
+ Tbody(id="planTable"),
226
+ Tr(
227
+ Td("askQuestions"),
228
+ Td("9:38 am"),
229
+ Td("30,079")),cls="table")
230
+ , cls="tab-pane fade", id="plansTab"),
231
+ Div(
232
+ Div(
233
+ H4("Persona"),
234
+ Div(
235
+ Label("Agent Name", cls="form-label", _for="agentNameInput"),
236
+ Input(type="text", cls="form-control", id="agentNameInput", placeholder="Enter your agent's name...")
237
+ , cls="mb-3"),
238
+ Div(
239
+ Label("Meta Prompt", cls="form-label", _for="metaPromptInput"),
240
+ Textarea(cls="form-control", id="metaPromptInput", rows="3", placeholder="Enter your Meta Prompt...")
241
+ , cls="mb-3"),
242
+ Div(
243
+ Label("Prefill", cls="form-label", _for="prefillInput"),
244
+ Textarea(cls="form-control", id="prefillInput", rows="3", placeholder="Enter agent's prefill...")
245
+ , cls="mb-3"),
246
+ Div(
247
+ Button("Save", cls="btn btn-primary", id="savePlanBtn")
248
+ , cls="d-flex justify-content-end"),
249
+ Hr(),
250
+ H5("Saved Plans"),
251
+ Ul(cls="list-group", id="savedPlansList")
252
+ , cls="container-fluid p-3")
253
+ , cls="tab-pane fade", id="personasTab")
254
+
255
+ , cls="tab-content flex-grow-1")
256
+ , cls="col-12 col-md-9 d-flex flex-column", id="chat")
257
+ , cls="row")
258
+ ,cls="container-fluid"),
259
+
260
+ Script(src="https://code.jquery.com/jquery-3.6.0.min.js"),
261
+ Script(src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js", integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p",crossorigin="anonymous"),
262
+ Script(f"let agents = {data};"),
263
+ Script("""
264
+ let selectedAgentIndex = -1;
265
+
266
+ function populateTabs() {
267
+ if (selectedAgentIndex >= 0) {
268
+ const selectedAgent = agents[selectedAgentIndex];
269
+
270
+ // Populate Personas tab
271
+ const agentNameInput = document.getElementById('agentNameInput');
272
+ const metaPromptInput = document.getElementById('metaPromptInput');
273
+ const prefillInput = document.getElementById('prefillInput');
274
+
275
+ agentNameInput.value = agents[selectedAgentIndex].Persona.agentname;
276
+ metaPromptInput.value = agents[selectedAgentIndex].Persona.metaprompt;
277
+ prefillInput.value = agents[selectedAgentIndex].Persona.prefill;
278
+
279
+ // Populate Plans tab
280
+ // Clear and repopulate the plans table or list with selectedAgent.Plans
281
+ const planTable = document.getElementById('planTable');
282
+ planTable.innerHTML = '';
283
+ agents[selectedAgentIndex].Plans.forEach(plan => {
284
+ const newRow = `<tr>
285
+ <td>${plan.name}</td>
286
+ <td>${plan.createon}</td>
287
+ <td>${plan.tokencount}</td>
288
+ </tr>`;
289
+ planTable.insertAdjacentHTML('beforeend', newRow);
290
+ });
291
+ // Populate Documents tab
292
+ // Clear and repopulate the documents table with selectedAgent.Documents
293
+ const fileTable = document.getElementById('fileTable');
294
+ fileTable.innerHTML = '';
295
+ agents[selectedAgentIndex].Documents.forEach(doc => {
296
+ const newRow = `<tr>
297
+ <td><i class="bi bi-file-earmark-text file-icon"></i> ${doc.file}</td>
298
+ <td>${doc.createon}</td>
299
+ <td>${doc.size}</td>
300
+ <td>${doc.Access}</td>
301
+ <td><div class="progress"><div class="progress-bar"></div></div></td>
302
+ </tr>`;
303
+ fileTable.insertAdjacentHTML('beforeend', newRow);
304
+ });
305
+ // Display initial messages
306
+ //displayMessages();
307
+ }
308
+ }
309
+
310
+ function renderChatList() {
311
+ const chatList = document.getElementById('chatList');
312
+ chatList.innerHTML = ''; // Clear the existing list
313
+
314
+ agents.forEach((agent, index) => {
315
+ const newItem = document.createElement('li');
316
+ newItem.className = 'list-group-item';
317
+ newItem.innerHTML = `<div class="d-flex justify-content-between">
318
+ <span>${agent.Persona.agentname}</span>
319
+ <small>${new Date().toLocaleTimeString()}</small>
320
+ </div>`;
321
+ newItem.setAttribute('data-index', index);
322
+ newItem.setAttribute('data-messages', JSON.stringify(agent.Chat));
323
+ newItem.addEventListener('click', function() {
324
+ selectedAgentIndex = parseInt(this.getAttribute('data-index'));
325
+ displayMessages();
326
+ populateTabs();
327
+ });
328
+ newItem.addEventListener('contextmenu', function(e) {
329
+ e.preventDefault();
330
+ showContextMenu(e, newItem, index);
331
+ });
332
+ chatList.appendChild(newItem);
333
+ });
334
+ }
335
+ // Event listener for add chat button - Sidebar
336
+ document.getElementById('addChatBtn').addEventListener('click', function() {
337
+ var chatList = document.getElementById('chatList');
338
+ var newItem = document.createElement('li');
339
+ newItem.className = 'list-group-item';
340
+ newItem.innerHTML = `<div class="d-flex justify-content-between">
341
+ <span>New Agent</span>
342
+ <small>${new Date().toLocaleTimeString()}</small>
343
+ </div>`;
344
+ newItem.setAttribute('data-messages', JSON.stringify([]));
345
+ chatList.appendChild(newItem);
346
+
347
+ // Add new agent to agents array
348
+ var newAgent = {
349
+ "Persona": {
350
+ "agentname": `agent-${Date.now()}`,
351
+ "metaprompt": "you are a helpful assistant",
352
+ "prefill": "helps me with financial Reconciliation",
353
+ "tooluse": "true",
354
+ "filesearch": "false",
355
+ "codeinterpreter": "false"
356
+ },
357
+ "Plans": [],
358
+ "Documents": [],
359
+ "Chat": []
360
+ };
361
+ agents.push(newAgent);
362
+ renderChatList();
363
+ });
364
+
365
+ // Show context menu
366
+ function showContextMenu(event, listItem) {
367
+ var contextMenu = document.getElementById('contextMenu');
368
+ contextMenu.style.display = 'block';
369
+ contextMenu.style.left = event.pageX + 'px';
370
+ contextMenu.style.top = event.pageY + 'px';
371
+
372
+ document.getElementById('renameItem').onclick = function() {
373
+ var newName = prompt("Enter new name:", listItem.querySelector('span').textContent);
374
+ if (newName) {
375
+ listItem.querySelector('span').textContent = newName;
376
+ //write a code to update the agent name in agents array
377
+ agents[selectedAgentIndex].Persona.agentname = newName;
378
+ }
379
+ contextMenu.style.display = 'none';
380
+ };
381
+
382
+ document.addEventListener('click', function() {
383
+ contextMenu.style.display = 'none';
384
+ }, { once: true });
385
+ }
386
+
387
+ // Event listener for existing items
388
+ document.querySelectorAll('#chatList .list-group-item').forEach(item => {
389
+ item.addEventListener('contextmenu', function(e) {
390
+ e.preventDefault();
391
+ showContextMenu(e, item);
392
+ });
393
+ });
394
+ // Function to display messages
395
+ function displayMessages() {
396
+ const chatMessages = document.getElementById('chat-messages');
397
+ chatMessages.innerHTML = '';
398
+ agents[selectedAgentIndex].Chat.forEach(msg => {
399
+ const messageElement = document.createElement('div');
400
+ messageElement.classList.add('chat-message');
401
+ messageElement.innerHTML = `<strong>${msg.role}</strong><p>${msg.content}</p>`;
402
+ chatMessages.appendChild(messageElement);
403
+ });
404
+ }
405
+
406
+ // Event listener for sidebar items
407
+ document.querySelectorAll('#chatList .list-group-item').forEach(item => {
408
+ item.addEventListener('click', function() {
409
+ const newMessages = JSON.parse(this.getAttribute('data-messages'));
410
+ messages = [...newMessages];
411
+ displayMessages();
412
+ });
413
+ });
414
+
415
+ // Event listener for send button
416
+ document.getElementById('sendBtn').addEventListener('click', function() {
417
+ const input = document.getElementById('messageInput');
418
+ const userMessage = input.value;
419
+ if (userMessage) {
420
+ agents[selectedAgentIndex].Chat.push({ role: 'MB', content: userMessage });
421
+ if (userMessage.toLowerCase() === 'what is the capital of india') {
422
+ agents[0].Chat.push({ role: 'Copilot', content: 'New Delhi is the capital of India' });
423
+ }
424
+ displayMessages();
425
+ input.value = '';
426
+ }
427
+ });
428
+
429
+ // Event listener for upload button
430
+ document.getElementById('uploadBtn').addEventListener('click', function() {
431
+ document.getElementById('fileInput').click();
432
+ });
433
+
434
+ // Event listener for file input - Documents Tab
435
+ document.getElementById('fileInput').addEventListener('change', function(event) {
436
+ const file = event.target.files[0];
437
+ if (file) {
438
+ const newRow = `<tr>
439
+ <td><i class="bi bi-file-earmark-text file-icon"></i> ${file.name}</td>
440
+ <td>${new Date().toLocaleTimeString()}</td>
441
+ <td>${file.size}</td>
442
+ <td>This chat</td>
443
+ <td><div class="progress"><div class="progress-bar"></div></div></td>
444
+ </tr>`;
445
+ document.getElementById('fileTable').insertAdjacentHTML('beforeend', newRow);
446
+ }
447
+ });
448
+
449
+ // Event listener for save button - Personas Tab
450
+ document.getElementById('savePlanBtn').addEventListener('click', function() {
451
+ const agentname = document.getElementById('agentNameInput').value;
452
+ const metaprompt = document.getElementById('metaPromptInput').value;
453
+ const prefill = document.getElementById('prefillInput').value;
454
+
455
+ const plan = {
456
+ agentname,
457
+ metaprompt,
458
+ prefill
459
+ };
460
+
461
+ const savedPlansList = document.getElementById('savedPlansList');
462
+ const planItem = document.createElement('li');
463
+ planItem.classList.add('list-group-item');
464
+ planItem.textContent = `Agent Name: ${agentname}`;
465
+ planItem.addEventListener('click', function() {
466
+ alert(`Meta Prompt: ${plan.metaprompt}\nPrefill: ${plan.prefill}`);
467
+ });
468
+
469
+ savedPlansList.appendChild(planItem);
470
+
471
+ // Clear the inputs after saving
472
+ document.getElementById('agentNameInput').value = '';
473
+ document.getElementById('metaPromptInput').value = '';
474
+ document.getElementById('prefillInput').value = '';
475
+ });
476
+
477
+
478
+
479
+ // Initial rendering of the chat list
480
+ renderChatList();
481
+
482
+ // Populate tabs initially (if needed)
483
+ populateTabs();
484
+ """))
485
+ return page
486
+
487
+ serve()
488
+
favicon.ico ADDED
main.py ADDED
@@ -0,0 +1,489 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ from fasthtml.common import *
3
+ from fasthtml_hf import setup_hf_backup
4
+
5
+ bootstraplink = Link(rel="stylesheet", href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css", integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC", crossorigin="anonymous")
6
+ fontlink = Link(rel="stylesheet", href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-icons/1.8.1/font/bootstrap-icons.min.css")
7
+ favicon = Link(rel="icon", type="image/x-icon", href="https://raw.githubusercontent.com/rajeshradhakrishnanmvk/aitemplate/main/favicon.ico")
8
+
9
+ title = Title("Groqlet Expendables")
10
+ css = Style("""body {
11
+ display: flex;
12
+ height: 100vh;
13
+ overflow: hidden;
14
+ }
15
+ #sidebar {
16
+ background-color: #f8f9fa;
17
+ padding: 10px;
18
+ overflow-y: auto;
19
+ height: 100vh;
20
+ }
21
+ #chat {
22
+ display: flex;
23
+ flex-direction: column;
24
+ height: 100vh;
25
+ overflow-y: hidden;
26
+ }
27
+ #chat-messages {
28
+ flex-grow: 1;
29
+ overflow-y: auto;
30
+ padding: 10px;
31
+ }
32
+ #chat-input {
33
+ padding: 10px;
34
+ border-top: 1px solid #e9ecef;
35
+ }
36
+ #documentsTab {
37
+ padding: 20px;
38
+ }
39
+ .file-upload {
40
+ display: none;
41
+ }
42
+ .file-icon {
43
+ width: 20px;
44
+ height: 20px;
45
+ }
46
+ .progress-bar {
47
+ width: 100%;
48
+ height: 100%;
49
+ background-color: #4caf50;
50
+ }
51
+ .container-fluid {
52
+ overflow-y: auto;
53
+ }
54
+ .form-label {
55
+ font-weight: bold;
56
+ }
57
+ .list-group-item {
58
+ cursor: pointer;
59
+ }""")
60
+
61
+ app = FastHTML(hdrs=(title,favicon,bootstraplink, fontlink,css))
62
+
63
+ data = json.dumps([
64
+ {
65
+ "Persona": {
66
+ "agentname": "dinkan-1",
67
+ "metaprompt": "you are a helpful assistant",
68
+ "prefill": "helps me with financial Reconciliation",
69
+ "tooluse": "true",
70
+ "filesearch": "true",
71
+ "codeinterpreter": "true"
72
+ },
73
+ "Plans": [
74
+ { "name": "askquestion", "createon": "06/8/2024", "tokencount": "2048" }
75
+ ],
76
+ "Documents": [
77
+ { "file": "./reconciliation.txt", "createon": "06/8/2024", "size": "30,079", "Access": "private", "progress": "success" },
78
+ { "file": "./design.pdf", "createon": "07/8/2024", "size": "30,079", "Access": "public", "progress": "error" }
79
+ ],
80
+ "Chat": [
81
+ {"role": "system", "content":"Hello, thank you for democratizing AI's productivity benefits with open source! How can I help you today?"},
82
+ { "role": "assistant", "content": "what is the capital of India" },
83
+ { "role": "user", "content": "New Delhi is the capital of India" }
84
+ ]
85
+ },
86
+ {
87
+ "Persona": {
88
+ "agentname": "dinkan-2",
89
+ "metaprompt": "you are a helpful assistant",
90
+ "prefill": "helps me with financial Reconciliation",
91
+ "tooluse": "true",
92
+ "filesearch": "false",
93
+ "codeinterpreter": "false"
94
+ },
95
+ "Plans": [
96
+ { "name": "calculate", "createon": "07/8/2024", "tokencount": "1024" }
97
+ ],
98
+ "Documents": [
99
+ { "file": "./design.txt", "createon": "08/8/2024", "size": "30,079", "Access": "private", "progress": "success" },
100
+ { "file": "./design.pdf", "createon": "09/8/2024", "size": "30,079", "Access": "public", "progress": "error" }
101
+ ],
102
+ "Chat": [
103
+ {"role": "system", "content":"Hello, thank you for democratizing AI's productivity benefits with open source! How can I help you today?"},
104
+ { "role": "assistant", "content": "what is the capital of Kerala" },
105
+ { "role": "user", "content": "Trivandrum is the capital of India" }
106
+ ]
107
+ }
108
+ ])
109
+
110
+
111
+ @app.route("/")
112
+ def get():
113
+ page = (Div(
114
+ Nav(
115
+ Div(
116
+ A("Groqlet Expendables", cls="navbar-brand", href="#"),
117
+ Div(
118
+ A(
119
+ I(cls="bi bi-plug"),
120
+ "Plugins", cls="nav-link text-white", href="#", style="margin-right: 10px;"),
121
+ A(
122
+ I(cls="bi bi-gear"),
123
+ "Settings", cls="nav-link text-white", href="#", style="margin-right: 10px;"),
124
+
125
+ Img(cls="rounded-circle", src="https://media.licdn.com/dms/image/C4D03AQHwjVMduekRjw/profile-displayphoto-shrink_100_100/0/1516794061157?e=1728518400&v=beta&t=JwjApmMV83LH01mtr8jUhh5wayHWFqPEhneLEU10HRI", alt="User Icon", style="width: 30px; height: 30px;")
126
+ ,cls="d-flex align-items-center")
127
+ ,cls="container-fluid")
128
+ ,cls="navbar navbar-expand-lg navbar-dark",style="background-color: #800080;"),
129
+ Div(
130
+ Div(
131
+ Div(
132
+ H4("Agents"),
133
+ Button("+", cls="btn btn-primary btn-sm", id="addChatBtn")
134
+ , cls="d-flex justify-content-between align-items-center mb-2"),
135
+ Ul(
136
+ Li(
137
+ Div(
138
+ Span("Can you tell me a story?"),
139
+ Small("11:10 PM")
140
+ , cls="d-flex justify-content-between")
141
+ , cls="list-group-item")
142
+ , cls="list-group", id="chatList")
143
+ , cls="col-12 col-md-3", id="sidebar"),
144
+ Div(
145
+ A("Rename", cls="dropdown-item", href="#", id="renameItem")
146
+ ,id="contextMenu", cls="dropdown-menu", style="display:none; position:absolute;"),
147
+ Div(
148
+ Ul(
149
+ Li(
150
+ A("Chat", cls="nav-link active", data_bs_toggle="tab", href="#chatTab")
151
+ , cls="nav-item"),
152
+ Li(
153
+ A("Documents", cls="nav-link", data_bs_toggle="tab", href="#documentsTab")
154
+ , cls="nav-item"),
155
+ Li(
156
+ A("Plans", cls="nav-link", data_bs_toggle="tab", href="#plansTab")
157
+ , cls="nav-item"),
158
+ Li(
159
+ A("Personas", cls="nav-link", data_bs_toggle="tab", href="#personasTab")
160
+ , cls="nav-item")
161
+ , cls="nav nav-tabs"),
162
+ Div(
163
+ Div(
164
+ Div(
165
+ Div(
166
+ Strong("Copilot"),
167
+ P("Hello, thank you for democratizing AI's productivity benefits with open source! How can I help you today?")
168
+ , cls="chat-message"),
169
+ Div(
170
+ Strong("MB"),
171
+ P("Can you tell me a story about a prince in a paragraph?")
172
+ , cls="chat-message")
173
+ , id="chat-messages"),
174
+ Div(
175
+ Input(type="text", cls="form-control me-2", placeholder="Type a message...", id="messageInput"),
176
+ Button("Send", cls="btn btn-primary", id="sendBtn")
177
+ , id="chat-input", cls="d-flex")
178
+ , cls="tab-pane fade show active", id="chatTab"),
179
+ Div(
180
+ Div(
181
+ H4("Documents"),
182
+ Button("Upload", cls="btn btn-primary btn-sm", id="uploadBtn"),
183
+ Input(type="file", id="fileInput", cls="file-upload")
184
+ , cls="d-flex justify-content-between align-items-center mb-2"),
185
+ Div(
186
+ Div(
187
+ Input(cls="form-check-input", type="radio", name="vectorDatabase", id="volatile", value="volatile"),
188
+ Label("Volatile", cls="form-check-label", _for="volatile")
189
+ , cls="form-check me-3"),
190
+ Div(
191
+ Input(cls="form-check-input", type="radio", name="vectorDatabase", id="textFile", value="textFile", checked=1),
192
+ Label("TextFile", cls="form-check-label", _for="textFile")
193
+ , cls="form-check me-3"),
194
+ Div(
195
+ Input(cls="form-check-input", type="radio", name="vectorDatabase", id="qdrant", value="qdrant"),
196
+ Label( "Qdrant", cls="form-check-label", _for="qdrant")
197
+ , cls="form-check me-3"),
198
+ Div(
199
+ Input(cls="form-check-input", type="radio", name="vectorDatabase", id="llamaindexSearch", value="llamaindexSearch"),
200
+ Label("llamaindex Search", cls="form-check-label", _for="llamaindexSearch")
201
+ , cls="form-check me-3")
202
+ ,cls="d-flex mb-2"),
203
+ Table(
204
+ Thead(),
205
+ Tr(
206
+ Th("Name"),
207
+ Th("Created on"),
208
+ Th("Size (bytes)"),
209
+ Th("Access"),
210
+ Th("Progress")),
211
+ Tbody(
212
+ Tr(
213
+ Td(I(cls="bi bi-file-earmark-text file-icon"), " reconciliation.txt"),
214
+ Td("9:38 am"),
215
+ Td("30,079"),
216
+ Td("This chat"),
217
+ Td(Div(cls="progress"),Div(cls="progress-bar"))),id="fileTable"),cls="table")
218
+ ,cls="tab-pane fade", id="documentsTab"),
219
+ Div(
220
+ Table(
221
+ Thead(),
222
+ Tr(
223
+ Th("Goal"),
224
+ Th("Created on"),
225
+ Th("Token Count")),
226
+ Tbody(id="planTable"),
227
+ Tr(
228
+ Td("askQuestions"),
229
+ Td("9:38 am"),
230
+ Td("30,079")),cls="table")
231
+ , cls="tab-pane fade", id="plansTab"),
232
+ Div(
233
+ Div(
234
+ H4("Persona"),
235
+ Div(
236
+ Label("Agent Name", cls="form-label", _for="agentNameInput"),
237
+ Input(type="text", cls="form-control", id="agentNameInput", placeholder="Enter your agent's name...")
238
+ , cls="mb-3"),
239
+ Div(
240
+ Label("Meta Prompt", cls="form-label", _for="metaPromptInput"),
241
+ Textarea(cls="form-control", id="metaPromptInput", rows="3", placeholder="Enter your Meta Prompt...")
242
+ , cls="mb-3"),
243
+ Div(
244
+ Label("Prefill", cls="form-label", _for="prefillInput"),
245
+ Textarea(cls="form-control", id="prefillInput", rows="3", placeholder="Enter agent's prefill...")
246
+ , cls="mb-3"),
247
+ Div(
248
+ Button("Save", cls="btn btn-primary", id="savePlanBtn")
249
+ , cls="d-flex justify-content-end"),
250
+ Hr(),
251
+ H5("Saved Plans"),
252
+ Ul(cls="list-group", id="savedPlansList")
253
+ , cls="container-fluid p-3")
254
+ , cls="tab-pane fade", id="personasTab")
255
+
256
+ , cls="tab-content flex-grow-1")
257
+ , cls="col-12 col-md-9 d-flex flex-column", id="chat")
258
+ , cls="row")
259
+ ,cls="container-fluid"),
260
+
261
+ Script(src="https://code.jquery.com/jquery-3.6.0.min.js"),
262
+ Script(src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js", integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p",crossorigin="anonymous"),
263
+ Script(f"let agents = {data};"),
264
+ Script("""
265
+ let selectedAgentIndex = -1;
266
+
267
+ function populateTabs() {
268
+ if (selectedAgentIndex >= 0) {
269
+ const selectedAgent = agents[selectedAgentIndex];
270
+
271
+ // Populate Personas tab
272
+ const agentNameInput = document.getElementById('agentNameInput');
273
+ const metaPromptInput = document.getElementById('metaPromptInput');
274
+ const prefillInput = document.getElementById('prefillInput');
275
+
276
+ agentNameInput.value = agents[selectedAgentIndex].Persona.agentname;
277
+ metaPromptInput.value = agents[selectedAgentIndex].Persona.metaprompt;
278
+ prefillInput.value = agents[selectedAgentIndex].Persona.prefill;
279
+
280
+ // Populate Plans tab
281
+ // Clear and repopulate the plans table or list with selectedAgent.Plans
282
+ const planTable = document.getElementById('planTable');
283
+ planTable.innerHTML = '';
284
+ agents[selectedAgentIndex].Plans.forEach(plan => {
285
+ const newRow = `<tr>
286
+ <td>${plan.name}</td>
287
+ <td>${plan.createon}</td>
288
+ <td>${plan.tokencount}</td>
289
+ </tr>`;
290
+ planTable.insertAdjacentHTML('beforeend', newRow);
291
+ });
292
+ // Populate Documents tab
293
+ // Clear and repopulate the documents table with selectedAgent.Documents
294
+ const fileTable = document.getElementById('fileTable');
295
+ fileTable.innerHTML = '';
296
+ agents[selectedAgentIndex].Documents.forEach(doc => {
297
+ const newRow = `<tr>
298
+ <td><i class="bi bi-file-earmark-text file-icon"></i> ${doc.file}</td>
299
+ <td>${doc.createon}</td>
300
+ <td>${doc.size}</td>
301
+ <td>${doc.Access}</td>
302
+ <td><div class="progress"><div class="progress-bar"></div></div></td>
303
+ </tr>`;
304
+ fileTable.insertAdjacentHTML('beforeend', newRow);
305
+ });
306
+ // Display initial messages
307
+ //displayMessages();
308
+ }
309
+ }
310
+
311
+ function renderChatList() {
312
+ const chatList = document.getElementById('chatList');
313
+ chatList.innerHTML = ''; // Clear the existing list
314
+
315
+ agents.forEach((agent, index) => {
316
+ const newItem = document.createElement('li');
317
+ newItem.className = 'list-group-item';
318
+ newItem.innerHTML = `<div class="d-flex justify-content-between">
319
+ <span>${agent.Persona.agentname}</span>
320
+ <small>${new Date().toLocaleTimeString()}</small>
321
+ </div>`;
322
+ newItem.setAttribute('data-index', index);
323
+ newItem.setAttribute('data-messages', JSON.stringify(agent.Chat));
324
+ newItem.addEventListener('click', function() {
325
+ selectedAgentIndex = parseInt(this.getAttribute('data-index'));
326
+ displayMessages();
327
+ populateTabs();
328
+ });
329
+ newItem.addEventListener('contextmenu', function(e) {
330
+ e.preventDefault();
331
+ showContextMenu(e, newItem, index);
332
+ });
333
+ chatList.appendChild(newItem);
334
+ });
335
+ }
336
+ // Event listener for add chat button - Sidebar
337
+ document.getElementById('addChatBtn').addEventListener('click', function() {
338
+ var chatList = document.getElementById('chatList');
339
+ var newItem = document.createElement('li');
340
+ newItem.className = 'list-group-item';
341
+ newItem.innerHTML = `<div class="d-flex justify-content-between">
342
+ <span>New Agent</span>
343
+ <small>${new Date().toLocaleTimeString()}</small>
344
+ </div>`;
345
+ newItem.setAttribute('data-messages', JSON.stringify([]));
346
+ chatList.appendChild(newItem);
347
+
348
+ // Add new agent to agents array
349
+ var newAgent = {
350
+ "Persona": {
351
+ "agentname": `agent-${Date.now()}`,
352
+ "metaprompt": "you are a helpful assistant",
353
+ "prefill": "helps me with financial Reconciliation",
354
+ "tooluse": "true",
355
+ "filesearch": "false",
356
+ "codeinterpreter": "false"
357
+ },
358
+ "Plans": [],
359
+ "Documents": [],
360
+ "Chat": []
361
+ };
362
+ agents.push(newAgent);
363
+ renderChatList();
364
+ });
365
+
366
+ // Show context menu
367
+ function showContextMenu(event, listItem) {
368
+ var contextMenu = document.getElementById('contextMenu');
369
+ contextMenu.style.display = 'block';
370
+ contextMenu.style.left = event.pageX + 'px';
371
+ contextMenu.style.top = event.pageY + 'px';
372
+
373
+ document.getElementById('renameItem').onclick = function() {
374
+ var newName = prompt("Enter new name:", listItem.querySelector('span').textContent);
375
+ if (newName) {
376
+ listItem.querySelector('span').textContent = newName;
377
+ //write a code to update the agent name in agents array
378
+ agents[selectedAgentIndex].Persona.agentname = newName;
379
+ }
380
+ contextMenu.style.display = 'none';
381
+ };
382
+
383
+ document.addEventListener('click', function() {
384
+ contextMenu.style.display = 'none';
385
+ }, { once: true });
386
+ }
387
+
388
+ // Event listener for existing items
389
+ document.querySelectorAll('#chatList .list-group-item').forEach(item => {
390
+ item.addEventListener('contextmenu', function(e) {
391
+ e.preventDefault();
392
+ showContextMenu(e, item);
393
+ });
394
+ });
395
+ // Function to display messages
396
+ function displayMessages() {
397
+ const chatMessages = document.getElementById('chat-messages');
398
+ chatMessages.innerHTML = '';
399
+ agents[selectedAgentIndex].Chat.forEach(msg => {
400
+ const messageElement = document.createElement('div');
401
+ messageElement.classList.add('chat-message');
402
+ messageElement.innerHTML = `<strong>${msg.role}</strong><p>${msg.content}</p>`;
403
+ chatMessages.appendChild(messageElement);
404
+ });
405
+ }
406
+
407
+ // Event listener for sidebar items
408
+ document.querySelectorAll('#chatList .list-group-item').forEach(item => {
409
+ item.addEventListener('click', function() {
410
+ const newMessages = JSON.parse(this.getAttribute('data-messages'));
411
+ messages = [...newMessages];
412
+ displayMessages();
413
+ });
414
+ });
415
+
416
+ // Event listener for send button
417
+ document.getElementById('sendBtn').addEventListener('click', function() {
418
+ const input = document.getElementById('messageInput');
419
+ const userMessage = input.value;
420
+ if (userMessage) {
421
+ agents[selectedAgentIndex].Chat.push({ role: 'MB', content: userMessage });
422
+ if (userMessage.toLowerCase() === 'what is the capital of india') {
423
+ agents[0].Chat.push({ role: 'Copilot', content: 'New Delhi is the capital of India' });
424
+ }
425
+ displayMessages();
426
+ input.value = '';
427
+ }
428
+ });
429
+
430
+ // Event listener for upload button
431
+ document.getElementById('uploadBtn').addEventListener('click', function() {
432
+ document.getElementById('fileInput').click();
433
+ });
434
+
435
+ // Event listener for file input - Documents Tab
436
+ document.getElementById('fileInput').addEventListener('change', function(event) {
437
+ const file = event.target.files[0];
438
+ if (file) {
439
+ const newRow = `<tr>
440
+ <td><i class="bi bi-file-earmark-text file-icon"></i> ${file.name}</td>
441
+ <td>${new Date().toLocaleTimeString()}</td>
442
+ <td>${file.size}</td>
443
+ <td>This chat</td>
444
+ <td><div class="progress"><div class="progress-bar"></div></div></td>
445
+ </tr>`;
446
+ document.getElementById('fileTable').insertAdjacentHTML('beforeend', newRow);
447
+ }
448
+ });
449
+
450
+ // Event listener for save button - Personas Tab
451
+ document.getElementById('savePlanBtn').addEventListener('click', function() {
452
+ const agentname = document.getElementById('agentNameInput').value;
453
+ const metaprompt = document.getElementById('metaPromptInput').value;
454
+ const prefill = document.getElementById('prefillInput').value;
455
+
456
+ const plan = {
457
+ agentname,
458
+ metaprompt,
459
+ prefill
460
+ };
461
+
462
+ const savedPlansList = document.getElementById('savedPlansList');
463
+ const planItem = document.createElement('li');
464
+ planItem.classList.add('list-group-item');
465
+ planItem.textContent = `Agent Name: ${agentname}`;
466
+ planItem.addEventListener('click', function() {
467
+ alert(`Meta Prompt: ${plan.metaprompt}\nPrefill: ${plan.prefill}`);
468
+ });
469
+
470
+ savedPlansList.appendChild(planItem);
471
+
472
+ // Clear the inputs after saving
473
+ document.getElementById('agentNameInput').value = '';
474
+ document.getElementById('metaPromptInput').value = '';
475
+ document.getElementById('prefillInput').value = '';
476
+ });
477
+
478
+
479
+
480
+ // Initial rendering of the chat list
481
+ renderChatList();
482
+
483
+ // Populate tabs initially (if needed)
484
+ populateTabs();
485
+ """))
486
+ return page
487
+ setup_hf_backup(app)
488
+ serve()
489
+
polling.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dotenv import load_dotenv, find_dotenv
2
+ from fasthtml.common import *
3
+ from groq import Groq
4
+
5
+ # Set up the app, including daisyui and tailwind for the chat component
6
+ tlink = Script(src="https://cdn.tailwindcss.com"),
7
+ dlink = Link(rel="stylesheet", href="https://cdn.jsdelivr.net/npm/daisyui@4.11.1/dist/full.min.css")
8
+ app = FastHTML(hdrs=(tlink, dlink, picolink))
9
+
10
+ load_dotenv(find_dotenv()) #os.environ["GROQ_API_KEY"]
11
+ client = Groq()
12
+ sp = """You are a helpful and concise assistant."""
13
+ messages = []
14
+
15
+ # Chat message component, polling if message is still being generated
16
+ def ChatMessage(msg_idx):
17
+ msg = messages[msg_idx]
18
+ text = "..." if msg['content'] == "" else msg['content']
19
+ bubble_class = f"chat-bubble-{'primary' if msg['role'] == 'user' else 'secondary'}"
20
+ chat_class = f"chat-{'end' if msg['role'] == 'user' else 'start'}"
21
+ generating = 'generating' in messages[msg_idx] and messages[msg_idx]['generating']
22
+ print(generating)
23
+ stream_args = {"hx_trigger":"every 0.1s", "hx_swap":"outerHTML", "hx_get":f"/chat_message/{msg_idx}"}
24
+ return Div(Div(msg['role'], cls="chat-header"),
25
+ Div(text, cls=f"chat-bubble {bubble_class}"),
26
+ cls=f"chat {chat_class}", id=f"chat-message-{msg_idx}",
27
+ **stream_args if generating else {})
28
+
29
+ # Route that gets polled while streaming
30
+ @app.get("/chat_message/{msg_idx}")
31
+ def get_chat_message(msg_idx:int):
32
+ if msg_idx >= len(messages): return ""
33
+ return ChatMessage(msg_idx)
34
+
35
+ # The input field for the user message. Also used to clear the
36
+ # input field after sending a message via an OOB swap
37
+ def ChatInput():
38
+ return Input(type="text", name='msg', id='msg-input',
39
+ placeholder="Type a message",
40
+ cls="input input-bordered w-full", hx_swap_oob='true')
41
+
42
+ # The main screen
43
+ @app.route("/")
44
+ def get():
45
+ page = Body(H1('Agentic Bot 1002'),
46
+ Div(*[ChatMessage(msg) for msg in messages],
47
+ id="chatlist", cls="chat-box h-[73vh] overflow-y-auto"),
48
+ Form(Group(ChatInput(), Button("Send", cls="btn btn-primary")),
49
+ hx_post="/", hx_target="#chatlist", hx_swap="beforeend",
50
+ cls="flex space-x-2 mt-2",
51
+ ), cls="p-4 max-w-lg mx-auto")
52
+ return Title('Agentic Bot 1002'), page
53
+
54
+ # Run the chat model in a separate thread
55
+ @threaded
56
+ def get_response(r, idx): #.choices[0].delta.content
57
+ for chunk in r:
58
+ if chunk.choices[0].delta.content is not None:
59
+ messages[idx]["content"] += chunk.choices[0].delta.content
60
+ messages[idx]["generating"] = False
61
+
62
+ # Handle the form submission
63
+ @app.post("/")
64
+ def post(msg:str):
65
+ messages.append({"role":"system", "content":sp})
66
+ idx = len(messages)
67
+ messages.append({"role":"user", "content":msg})
68
+ # r = cli(messages, sp=sp, stream=True) # Send message to chat model (with streaming)
69
+ # Remove 'generating' key-value pair if it exists
70
+ for entry in messages:
71
+ if 'generating' in entry:
72
+ del entry['generating']
73
+ stream = client.chat.completions.create(
74
+ messages=messages,
75
+ model="llama3-8b-8192",
76
+ temperature=0.5,
77
+ max_tokens=1024,
78
+ top_p=1,
79
+ stop=None,
80
+ stream=True,
81
+ )
82
+ messages.append({"role":"assistant", "generating":True, "content":""}) # Response initially blank
83
+ get_response(stream, idx+1) # Start a new thread to fill in content
84
+ return (ChatMessage(idx), # The user's message
85
+ ChatMessage(idx+1), # The chatbot's response
86
+ ChatInput()) # And clear the input field via an OOB swap
87
+
88
+
89
+ if __name__ == '__main__': uvicorn.run("polling:app", host='0.0.0.0', port=8000, reload=True)
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ python-fasthtml
2
+ fasthtml-hf
3
+ uvicorn>=0.29
4
+ groq
5
+ python-dotenv
simple.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fasthtml.common import *
2
+ from groq import Groq
3
+ from dotenv import load_dotenv, find_dotenv
4
+
5
+ # Set up the app, including daisyui and tailwind for the chat component
6
+ tlink = Script(src="https://cdn.tailwindcss.com"),
7
+ dlink = Link(rel="stylesheet", href="https://cdn.jsdelivr.net/npm/daisyui@4.11.1/dist/full.min.css")
8
+ app = FastHTML(hdrs=(tlink, dlink, picolink))
9
+
10
+ load_dotenv(find_dotenv()) #os.environ["GROQ_API_KEY"]
11
+ client = Groq()
12
+ sp = """You are a helpful and concise assistant."""
13
+ messages = []
14
+
15
+
16
+ # Chat message component (renders a chat bubble)
17
+ def ChatMessage(msg):
18
+ bubble_class = f"chat-bubble-{'primary' if msg['role'] == 'user' else 'secondary'}"
19
+ chat_class = f"chat-{'end' if msg['role'] == 'user' else 'start'}"
20
+ return Div(Div(msg['role'], cls="chat-header"),
21
+ Div(msg['content'], cls=f"chat-bubble {bubble_class}"),
22
+ cls=f"chat {chat_class}")
23
+
24
+ # The input field for the user message. Also used to clear the
25
+ # input field after sending a message via an OOB swap
26
+ def ChatInput():
27
+ return Input(type="text", name='msg', id='msg-input',
28
+ placeholder="Type a message",
29
+ cls="input input-bordered w-full", hx_swap_oob='true')
30
+
31
+ # The main screen
32
+ @app.route("/")
33
+ def get():
34
+ page = Body(H1('Agentic Bot 1001'),
35
+ Div(*[ChatMessage(msg) for msg in messages],
36
+ id="chatlist", cls="chat-box h-[73vh] overflow-y-auto"),
37
+ Form(Group(ChatInput(), Button("Send", cls="btn btn-primary")),
38
+ hx_post="/", hx_target="#chatlist", hx_swap="beforeend",
39
+ cls="flex space-x-2 mt-2",
40
+ ), cls="p-4 max-w-lg mx-auto")
41
+ return Title('Agentic Bot 1001'), page
42
+
43
+ # Handle the form submission
44
+ @app.post("/")
45
+ def post(msg:str):
46
+ messages.append({"role":"system", "content":sp})
47
+ messages.append({"role":"user", "content":msg})
48
+ #r = cli(messages, sp=sp) # get response from chat model
49
+ chat_completion = client.chat.completions.create(
50
+ messages=messages,
51
+ model="llama3-8b-8192",
52
+ temperature=0.5,
53
+ max_tokens=1024,
54
+ top_p=1,
55
+ stop=None,
56
+ stream=False,
57
+ )
58
+ messages.append({"role":"assistant", "content":chat_completion.choices[0].message.content})
59
+ return (ChatMessage(messages[-2]), # The user's message
60
+ ChatMessage(messages[-1]), # The chatbot's response
61
+ ChatInput()) # And clear the input field via an OOB swap
62
+
63
+
64
+ if __name__ == '__main__': uvicorn.run("simple:app", host='0.0.0.0', port=8000, reload=True)