Spaces:
Runtime error
Runtime error
deploy at 2024-08-06 15:09:58.948539
Browse files- Dockerfile +10 -0
- LICENSE +21 -0
- README.md +2 -10
- dinkan.html +503 -0
- expendables.py +488 -0
- favicon.ico +0 -0
- main.py +489 -0
- polling.py +89 -0
- requirements.txt +5 -0
- 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 |
-
|
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)
|