XThomasBU
commited on
Commit
·
2c49234
1
Parent(s):
703c436
regen_tokens initial commit
Browse files- code/app.py +28 -3
- code/main.py +18 -9
- code/modules/chat_processor/helpers.py +48 -8
- code/modules/config/constants.py +4 -2
- code/templates/cooldown.html +44 -18
- code/templates/dashboard.html +25 -9
code/app.py
CHANGED
@@ -14,6 +14,8 @@ from modules.config.constants import (
|
|
14 |
CHAINLIT_URL,
|
15 |
GITHUB_REPO,
|
16 |
DOCS_WEBSITE,
|
|
|
|
|
17 |
)
|
18 |
from fastapi.middleware.cors import CORSMiddleware
|
19 |
from fastapi.staticfiles import StaticFiles
|
@@ -207,7 +209,7 @@ async def cooldown(request: Request):
|
|
207 |
user_info = await get_user_info_from_cookie(request)
|
208 |
user_details = await get_user_details(user_info["email"])
|
209 |
current_datetime = get_time()
|
210 |
-
cooldown, cooldown_end_time = check_user_cooldown(user_details, current_datetime)
|
211 |
print(f"User in cooldown: {cooldown}")
|
212 |
print(f"Cooldown end time: {cooldown_end_time}")
|
213 |
if cooldown and "admin" not in get_user_role(user_info["email"]):
|
@@ -218,9 +220,11 @@ async def cooldown(request: Request):
|
|
218 |
"username": user_info["email"],
|
219 |
"role": get_user_role(user_info["email"]),
|
220 |
"cooldown_end_time": cooldown_end_time,
|
|
|
221 |
},
|
222 |
)
|
223 |
else:
|
|
|
224 |
await update_user_info(user_details)
|
225 |
await reset_tokens_for_user(user_details)
|
226 |
return RedirectResponse("/post-signin")
|
@@ -236,12 +240,17 @@ async def post_signin(request: Request):
|
|
236 |
user_details.metadata["last_login"] = current_datetime
|
237 |
# if new user, set the number of tries
|
238 |
if "tokens_left" not in user_details.metadata:
|
239 |
-
|
|
|
|
|
|
|
|
|
|
|
240 |
|
241 |
if "last_message_time" in user_details.metadata and "admin" not in get_user_role(
|
242 |
user_info["email"]
|
243 |
):
|
244 |
-
cooldown, _ = check_user_cooldown(user_details, current_datetime)
|
245 |
if cooldown:
|
246 |
return RedirectResponse("/cooldown")
|
247 |
else:
|
@@ -259,6 +268,8 @@ async def post_signin(request: Request):
|
|
259 |
"role": role,
|
260 |
"jwt_token": jwt_token,
|
261 |
"tokens_left": user_details.metadata["tokens_left"],
|
|
|
|
|
262 |
},
|
263 |
)
|
264 |
return RedirectResponse("/")
|
@@ -309,6 +320,20 @@ async def logout(request: Request, response: Response):
|
|
309 |
return response
|
310 |
|
311 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
312 |
mount_chainlit(app=app, target="main.py", path=CHAINLIT_PATH)
|
313 |
|
314 |
if __name__ == "__main__":
|
|
|
14 |
CHAINLIT_URL,
|
15 |
GITHUB_REPO,
|
16 |
DOCS_WEBSITE,
|
17 |
+
ALL_TIME_TOKENS_ALLOCATED,
|
18 |
+
TOKENS_LEFT
|
19 |
)
|
20 |
from fastapi.middleware.cors import CORSMiddleware
|
21 |
from fastapi.staticfiles import StaticFiles
|
|
|
209 |
user_info = await get_user_info_from_cookie(request)
|
210 |
user_details = await get_user_details(user_info["email"])
|
211 |
current_datetime = get_time()
|
212 |
+
cooldown, cooldown_end_time = await check_user_cooldown(user_details, current_datetime)
|
213 |
print(f"User in cooldown: {cooldown}")
|
214 |
print(f"Cooldown end time: {cooldown_end_time}")
|
215 |
if cooldown and "admin" not in get_user_role(user_info["email"]):
|
|
|
220 |
"username": user_info["email"],
|
221 |
"role": get_user_role(user_info["email"]),
|
222 |
"cooldown_end_time": cooldown_end_time,
|
223 |
+
"tokens_left": user_details.metadata["tokens_left"],
|
224 |
},
|
225 |
)
|
226 |
else:
|
227 |
+
user_details.metadata["in_cooldown"] = False
|
228 |
await update_user_info(user_details)
|
229 |
await reset_tokens_for_user(user_details)
|
230 |
return RedirectResponse("/post-signin")
|
|
|
240 |
user_details.metadata["last_login"] = current_datetime
|
241 |
# if new user, set the number of tries
|
242 |
if "tokens_left" not in user_details.metadata:
|
243 |
+
user_details.metadata["tokens_left"] = TOKENS_LEFT # set the number of tokens left for the new user
|
244 |
+
if "all_time_tokens_allocated" not in user_details.metadata:
|
245 |
+
user_details.metadata["all_time_tokens_allocated"] = ALL_TIME_TOKENS_ALLOCATED
|
246 |
+
if "in_cooldown" not in user_details.metadata:
|
247 |
+
user_details.metadata["in_cooldown"] = False
|
248 |
+
await update_user_info(user_details)
|
249 |
|
250 |
if "last_message_time" in user_details.metadata and "admin" not in get_user_role(
|
251 |
user_info["email"]
|
252 |
):
|
253 |
+
cooldown, _ = await check_user_cooldown(user_details, current_datetime)
|
254 |
if cooldown:
|
255 |
return RedirectResponse("/cooldown")
|
256 |
else:
|
|
|
268 |
"role": role,
|
269 |
"jwt_token": jwt_token,
|
270 |
"tokens_left": user_details.metadata["tokens_left"],
|
271 |
+
"all_time_tokens_allocated": user_details.metadata["all_time_tokens_allocated"],
|
272 |
+
"total_tokens_allocated": ALL_TIME_TOKENS_ALLOCATED,
|
273 |
},
|
274 |
)
|
275 |
return RedirectResponse("/")
|
|
|
320 |
return response
|
321 |
|
322 |
|
323 |
+
@app.get("/get-tokens-left")
|
324 |
+
async def get_tokens_left(request: Request):
|
325 |
+
try:
|
326 |
+
user_info = await get_user_info_from_cookie(request)
|
327 |
+
user_details = await get_user_details(user_info["email"])
|
328 |
+
await reset_tokens_for_user(user_details)
|
329 |
+
tokens_left = user_details.metadata["tokens_left"]
|
330 |
+
return {"tokens_left": tokens_left}
|
331 |
+
except Exception as e:
|
332 |
+
print(f"Error getting tokens left: {e}")
|
333 |
+
return {"tokens_left": 0}
|
334 |
+
|
335 |
+
|
336 |
+
|
337 |
mount_chainlit(app=app, target="main.py", path=CHAINLIT_PATH)
|
338 |
|
339 |
if __name__ == "__main__":
|
code/main.py
CHANGED
@@ -20,6 +20,7 @@ from modules.chat_processor.helpers import (
|
|
20 |
update_user_info,
|
21 |
get_time,
|
22 |
check_user_cooldown,
|
|
|
23 |
)
|
24 |
import copy
|
25 |
from typing import Optional
|
@@ -224,14 +225,14 @@ class Chatbot:
|
|
224 |
await cl.Message(
|
225 |
author=SYSTEM,
|
226 |
content="LLM settings have been updated. You can continue with your Query!",
|
227 |
-
elements=[
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
],
|
235 |
).send()
|
236 |
|
237 |
async def set_starters(self):
|
@@ -372,8 +373,9 @@ class Chatbot:
|
|
372 |
# if not, return message saying they have run out of tokens
|
373 |
if user.metadata["tokens_left"] <= 0 and "admin" not in user.metadata["role"]:
|
374 |
current_datetime = get_time()
|
375 |
-
cooldown, cooldown_end_time = check_user_cooldown(user, current_datetime)
|
376 |
if cooldown:
|
|
|
377 |
# get time left in cooldown
|
378 |
# convert both to datetime objects
|
379 |
cooldown_end_time = datetime.fromisoformat(cooldown_end_time).replace(
|
@@ -481,9 +483,16 @@ class Chatbot:
|
|
481 |
# # update user info with token count
|
482 |
if "admin" not in user.metadata["role"]:
|
483 |
user.metadata["tokens_left"] = user.metadata["tokens_left"] - token_count
|
|
|
|
|
484 |
user.metadata["last_message_time"] = get_time()
|
485 |
await update_user_info(user)
|
486 |
|
|
|
|
|
|
|
|
|
|
|
487 |
await cl.Message(
|
488 |
content=answer_with_sources,
|
489 |
elements=source_elements,
|
|
|
20 |
update_user_info,
|
21 |
get_time,
|
22 |
check_user_cooldown,
|
23 |
+
reset_tokens_for_user,
|
24 |
)
|
25 |
import copy
|
26 |
from typing import Optional
|
|
|
225 |
await cl.Message(
|
226 |
author=SYSTEM,
|
227 |
content="LLM settings have been updated. You can continue with your Query!",
|
228 |
+
# elements=[
|
229 |
+
# cl.Text(
|
230 |
+
# name="settings",
|
231 |
+
# display="side",
|
232 |
+
# content=json.dumps(settings_dict, indent=4),
|
233 |
+
# language="json",
|
234 |
+
# ),
|
235 |
+
# ],
|
236 |
).send()
|
237 |
|
238 |
async def set_starters(self):
|
|
|
373 |
# if not, return message saying they have run out of tokens
|
374 |
if user.metadata["tokens_left"] <= 0 and "admin" not in user.metadata["role"]:
|
375 |
current_datetime = get_time()
|
376 |
+
cooldown, cooldown_end_time = await check_user_cooldown(user, current_datetime)
|
377 |
if cooldown:
|
378 |
+
user.metadata["in_cooldown"] = True
|
379 |
# get time left in cooldown
|
380 |
# convert both to datetime objects
|
381 |
cooldown_end_time = datetime.fromisoformat(cooldown_end_time).replace(
|
|
|
483 |
# # update user info with token count
|
484 |
if "admin" not in user.metadata["role"]:
|
485 |
user.metadata["tokens_left"] = user.metadata["tokens_left"] - token_count
|
486 |
+
user.metadata["all_time_tokens_allocated"] = user.metadata["all_time_tokens_allocated"] - token_count
|
487 |
+
await reset_tokens_for_user(user) # regenerate tokens for the user
|
488 |
user.metadata["last_message_time"] = get_time()
|
489 |
await update_user_info(user)
|
490 |
|
491 |
+
tokens_left = user.metadata["tokens_left"]
|
492 |
+
if tokens_left < 0:
|
493 |
+
tokens_left = 0
|
494 |
+
answer_with_sources += '\n\n<footer><span style="font-size: 0.8em; text-align: right; display: block;">Tokens Left: ' + str(tokens_left) + '</span></footer>\n'
|
495 |
+
|
496 |
await cl.Message(
|
497 |
content=answer_with_sources,
|
498 |
elements=source_elements,
|
code/modules/chat_processor/helpers.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
import os
|
2 |
from literalai import AsyncLiteralClient
|
3 |
from datetime import datetime, timedelta, timezone
|
4 |
-
from modules.config.constants import COOLDOWN_TIME, TOKENS_LEFT
|
5 |
from typing_extensions import TypedDict
|
6 |
import tiktoken
|
7 |
from typing import Any, Generic, List, Literal, Optional, TypeVar, Union
|
@@ -141,7 +141,7 @@ def get_time():
|
|
141 |
|
142 |
|
143 |
async def get_user_details(user_email_id):
|
144 |
-
user_info = await literal_client.api.
|
145 |
return user_info
|
146 |
|
147 |
|
@@ -155,11 +155,11 @@ async def update_user_info(user_info):
|
|
155 |
)
|
156 |
|
157 |
|
158 |
-
def check_user_cooldown(user_info, current_time):
|
159 |
|
160 |
-
# Check if no tokens left
|
161 |
tokens_left = user_info.metadata.get("tokens_left", 0)
|
162 |
-
if tokens_left > 0:
|
163 |
return False, None
|
164 |
|
165 |
user_info = convert_to_dict(user_info)
|
@@ -186,14 +186,54 @@ def check_user_cooldown(user_info, current_time):
|
|
186 |
if elapsed_time_in_seconds < COOLDOWN_TIME:
|
187 |
return True, cooldown_end_time_iso # Return in ISO 8601 format
|
188 |
|
189 |
-
|
|
|
|
|
190 |
|
|
|
191 |
|
192 |
async def reset_tokens_for_user(user_info):
|
193 |
user_info = convert_to_dict(user_info)
|
194 |
-
user_info["metadata"]
|
195 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
196 |
|
|
|
197 |
|
198 |
async def get_thread_step_info(thread_id):
|
199 |
step = await literal_client.api.get_step(thread_id)
|
|
|
1 |
import os
|
2 |
from literalai import AsyncLiteralClient
|
3 |
from datetime import datetime, timedelta, timezone
|
4 |
+
from modules.config.constants import COOLDOWN_TIME, TOKENS_LEFT, REGEN_TIME
|
5 |
from typing_extensions import TypedDict
|
6 |
import tiktoken
|
7 |
from typing import Any, Generic, List, Literal, Optional, TypeVar, Union
|
|
|
141 |
|
142 |
|
143 |
async def get_user_details(user_email_id):
|
144 |
+
user_info = await literal_client.api.get_or_create_user(identifier=user_email_id)
|
145 |
return user_info
|
146 |
|
147 |
|
|
|
155 |
)
|
156 |
|
157 |
|
158 |
+
async def check_user_cooldown(user_info, current_time):
|
159 |
|
160 |
+
# # Check if no tokens left
|
161 |
tokens_left = user_info.metadata.get("tokens_left", 0)
|
162 |
+
if tokens_left > 0 and not user_info.metadata.get("in_cooldown", False):
|
163 |
return False, None
|
164 |
|
165 |
user_info = convert_to_dict(user_info)
|
|
|
186 |
if elapsed_time_in_seconds < COOLDOWN_TIME:
|
187 |
return True, cooldown_end_time_iso # Return in ISO 8601 format
|
188 |
|
189 |
+
user.metadata["in_cooldown"] = False
|
190 |
+
# If not in cooldown, regenerate tokens
|
191 |
+
await reset_tokens_for_user(user_info)
|
192 |
|
193 |
+
return False, None
|
194 |
|
195 |
async def reset_tokens_for_user(user_info):
|
196 |
user_info = convert_to_dict(user_info)
|
197 |
+
last_message_time_str = user_info["metadata"].get("last_message_time")
|
198 |
+
|
199 |
+
last_message_time = datetime.fromisoformat(last_message_time_str).replace(
|
200 |
+
tzinfo=timezone.utc
|
201 |
+
)
|
202 |
+
current_time = datetime.fromisoformat(get_time()).replace(tzinfo=timezone.utc)
|
203 |
+
|
204 |
+
# Calculate the elapsed time since the last message
|
205 |
+
elapsed_time_in_seconds = (current_time - last_message_time).total_seconds()
|
206 |
+
|
207 |
+
# Current token count (can be negative)
|
208 |
+
current_tokens = user_info["metadata"].get("tokens_left", 0)
|
209 |
+
|
210 |
+
# Maximum tokens that can be regenerated
|
211 |
+
max_tokens = user_info["metadata"].get("max_tokens", TOKENS_LEFT)
|
212 |
+
|
213 |
+
# Calculate how many tokens should have been regenerated proportionally
|
214 |
+
if current_tokens < max_tokens:
|
215 |
+
# Determine the time required to fully regenerate tokens from current state
|
216 |
+
if current_tokens < 0:
|
217 |
+
time_to_full_regen = REGEN_TIME * (1 + abs(current_tokens) / max_tokens) # more time to regenerate if tokens left is negative
|
218 |
+
else:
|
219 |
+
time_to_full_regen = REGEN_TIME * (1 - current_tokens / max_tokens) # less time to regenerate if tokens left is positive
|
220 |
+
|
221 |
+
# Calculate the proportion of this time that has elapsed
|
222 |
+
proportion_of_time_elapsed = min(elapsed_time_in_seconds / time_to_full_regen, 1.0)
|
223 |
+
|
224 |
+
# Calculate the tokens to regenerate based on the elapsed proportion
|
225 |
+
tokens_to_regenerate = int(proportion_of_time_elapsed * (max_tokens - current_tokens))
|
226 |
+
|
227 |
+
# Ensure tokens_to_regenerate is positive and doesn't exceed the maximum
|
228 |
+
if tokens_to_regenerate > 0:
|
229 |
+
new_token_count = min(current_tokens + tokens_to_regenerate, max_tokens)
|
230 |
+
|
231 |
+
print(f"\n\n Adding {tokens_to_regenerate} tokens to the user, Time left for full credits: {time_to_full_regen - elapsed_time_in_seconds} \n\n")
|
232 |
+
|
233 |
+
# Update the user's token count
|
234 |
+
user_info["metadata"]["tokens_left"] = new_token_count
|
235 |
|
236 |
+
await update_user_info(user_info)
|
237 |
|
238 |
async def get_thread_step_info(thread_id):
|
239 |
step = await literal_client.api.get_step(thread_id)
|
code/modules/config/constants.py
CHANGED
@@ -4,8 +4,10 @@ import os
|
|
4 |
load_dotenv()
|
5 |
|
6 |
TIMEOUT = 60
|
7 |
-
COOLDOWN_TIME =
|
8 |
-
|
|
|
|
|
9 |
|
10 |
GITHUB_REPO = "https://github.com/DL4DS/dl4ds_tutor"
|
11 |
DOCS_WEBSITE = "https://dl4ds.github.io/dl4ds_tutor/"
|
|
|
4 |
load_dotenv()
|
5 |
|
6 |
TIMEOUT = 60
|
7 |
+
COOLDOWN_TIME = 180
|
8 |
+
REGEN_TIME = 300
|
9 |
+
TOKENS_LEFT = 2000
|
10 |
+
ALL_TIME_TOKENS_ALLOCATED = 1000000
|
11 |
|
12 |
GITHUB_REPO = "https://github.com/DL4DS/dl4ds_tutor"
|
13 |
DOCS_WEBSITE = "https://dl4ds.github.io/dl4ds_tutor/"
|
code/templates/cooldown.html
CHANGED
@@ -63,6 +63,13 @@
|
|
63 |
margin-bottom: 30px;
|
64 |
}
|
65 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
.button {
|
67 |
padding: 12px 0;
|
68 |
margin: 12px 0;
|
@@ -70,33 +77,33 @@
|
|
70 |
border-radius: 6px;
|
71 |
cursor: pointer;
|
72 |
width: 100%;
|
73 |
-
border: 1px solid #4285F4;
|
74 |
-
background-color: #fff;
|
75 |
-
color: #4285F4;
|
76 |
transition: background-color 0.3s ease, border-color 0.3s ease;
|
77 |
-
display: none;
|
78 |
}
|
79 |
|
80 |
.button.start-tutor {
|
81 |
-
display: none;
|
82 |
}
|
83 |
|
84 |
.button:hover {
|
85 |
background-color: #e0e0e0;
|
86 |
-
border-color: #357ae8;
|
87 |
}
|
88 |
|
89 |
.sign-out-button {
|
90 |
border: 1px solid #FF4C4C;
|
91 |
background-color: #fff;
|
92 |
color: #FF4C4C;
|
93 |
-
display: block;
|
94 |
}
|
95 |
|
96 |
.sign-out-button:hover {
|
97 |
-
background-color: #ffe6e6;
|
98 |
-
border-color: #e04343;
|
99 |
-
color: #e04343;
|
100 |
}
|
101 |
|
102 |
#countdown {
|
@@ -104,6 +111,12 @@
|
|
104 |
color: #555;
|
105 |
margin-bottom: 20px;
|
106 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
</style>
|
108 |
</head>
|
109 |
<body>
|
@@ -113,24 +126,26 @@
|
|
113 |
<p>It seems like you need to wait a bit before starting a new session.</p>
|
114 |
<p class="cooldown-message">Time remaining until the cooldown period ends:</p>
|
115 |
<p id="countdown"></p>
|
|
|
116 |
<button id="startTutorBtn" class="button start-tutor" onclick="startTutor()">Start AI Tutor</button>
|
117 |
<form action="/logout" method="get">
|
118 |
<button type="submit" class="button sign-out-button">Sign Out</button>
|
119 |
</form>
|
|
|
120 |
</div>
|
121 |
<script>
|
122 |
function startCountdown(endTime) {
|
123 |
const countdownElement = document.getElementById('countdown');
|
124 |
const startTutorBtn = document.getElementById('startTutorBtn');
|
125 |
-
const endTimeDate = new Date(endTime);
|
126 |
|
127 |
function updateCountdown() {
|
128 |
-
const now = new Date();
|
129 |
-
const timeLeft = endTimeDate.getTime() - now.getTime();
|
130 |
|
131 |
if (timeLeft <= 0) {
|
132 |
countdownElement.textContent = "Cooldown period has ended.";
|
133 |
-
startTutorBtn.style.display = "block";
|
134 |
} else {
|
135 |
const hours = Math.floor(timeLeft / 1000 / 60 / 60);
|
136 |
const minutes = Math.floor((timeLeft / 1000 / 60) % 60);
|
@@ -139,17 +154,28 @@
|
|
139 |
}
|
140 |
}
|
141 |
|
142 |
-
updateCountdown();
|
143 |
-
setInterval(updateCountdown, 1000);
|
144 |
}
|
145 |
|
146 |
function startTutor() {
|
147 |
-
// Redirect to AI Tutor session start or any other logic to start the tutor
|
148 |
window.location.href = "/start-tutor";
|
149 |
}
|
150 |
|
151 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
152 |
startCountdown("{{ cooldown_end_time }}");
|
|
|
|
|
|
|
153 |
</script>
|
154 |
</body>
|
155 |
</html>
|
|
|
63 |
margin-bottom: 30px;
|
64 |
}
|
65 |
|
66 |
+
.tokens-left {
|
67 |
+
font-size: 14px;
|
68 |
+
color: #333;
|
69 |
+
margin-bottom: 30px;
|
70 |
+
font-weight: 600;
|
71 |
+
}
|
72 |
+
|
73 |
.button {
|
74 |
padding: 12px 0;
|
75 |
margin: 12px 0;
|
|
|
77 |
border-radius: 6px;
|
78 |
cursor: pointer;
|
79 |
width: 100%;
|
80 |
+
border: 1px solid #4285F4;
|
81 |
+
background-color: #fff;
|
82 |
+
color: #4285F4;
|
83 |
transition: background-color 0.3s ease, border-color 0.3s ease;
|
84 |
+
display: none;
|
85 |
}
|
86 |
|
87 |
.button.start-tutor {
|
88 |
+
display: none;
|
89 |
}
|
90 |
|
91 |
.button:hover {
|
92 |
background-color: #e0e0e0;
|
93 |
+
border-color: #357ae8;
|
94 |
}
|
95 |
|
96 |
.sign-out-button {
|
97 |
border: 1px solid #FF4C4C;
|
98 |
background-color: #fff;
|
99 |
color: #FF4C4C;
|
100 |
+
display: block;
|
101 |
}
|
102 |
|
103 |
.sign-out-button:hover {
|
104 |
+
background-color: #ffe6e6;
|
105 |
+
border-color: #e04343;
|
106 |
+
color: #e04343;
|
107 |
}
|
108 |
|
109 |
#countdown {
|
|
|
111 |
color: #555;
|
112 |
margin-bottom: 20px;
|
113 |
}
|
114 |
+
|
115 |
+
.footer {
|
116 |
+
font-size: 12px;
|
117 |
+
color: #777;
|
118 |
+
margin-top: 20px;
|
119 |
+
}
|
120 |
</style>
|
121 |
</head>
|
122 |
<body>
|
|
|
126 |
<p>It seems like you need to wait a bit before starting a new session.</p>
|
127 |
<p class="cooldown-message">Time remaining until the cooldown period ends:</p>
|
128 |
<p id="countdown"></p>
|
129 |
+
<p class="tokens-left">Tokens Left: <span id="tokensLeft">{{ tokens_left }}</span></p>
|
130 |
<button id="startTutorBtn" class="button start-tutor" onclick="startTutor()">Start AI Tutor</button>
|
131 |
<form action="/logout" method="get">
|
132 |
<button type="submit" class="button sign-out-button">Sign Out</button>
|
133 |
</form>
|
134 |
+
<div class="footer">Reload the page to update token stats</div>
|
135 |
</div>
|
136 |
<script>
|
137 |
function startCountdown(endTime) {
|
138 |
const countdownElement = document.getElementById('countdown');
|
139 |
const startTutorBtn = document.getElementById('startTutorBtn');
|
140 |
+
const endTimeDate = new Date(endTime);
|
141 |
|
142 |
function updateCountdown() {
|
143 |
+
const now = new Date();
|
144 |
+
const timeLeft = endTimeDate.getTime() - now.getTime();
|
145 |
|
146 |
if (timeLeft <= 0) {
|
147 |
countdownElement.textContent = "Cooldown period has ended.";
|
148 |
+
startTutorBtn.style.display = "block";
|
149 |
} else {
|
150 |
const hours = Math.floor(timeLeft / 1000 / 60 / 60);
|
151 |
const minutes = Math.floor((timeLeft / 1000 / 60) % 60);
|
|
|
154 |
}
|
155 |
}
|
156 |
|
157 |
+
updateCountdown();
|
158 |
+
setInterval(updateCountdown, 1000);
|
159 |
}
|
160 |
|
161 |
function startTutor() {
|
|
|
162 |
window.location.href = "/start-tutor";
|
163 |
}
|
164 |
|
165 |
+
function updateTokensLeft() {
|
166 |
+
fetch('/get-tokens-left')
|
167 |
+
.then(response => response.json())
|
168 |
+
.then(data => {
|
169 |
+
document.getElementById('tokensLeft').textContent = data.tokens_left;
|
170 |
+
})
|
171 |
+
.catch(error => console.error('Error fetching tokens:', error));
|
172 |
+
}
|
173 |
+
|
174 |
+
// Start the countdown
|
175 |
startCountdown("{{ cooldown_end_time }}");
|
176 |
+
|
177 |
+
// Update tokens left when the page loads
|
178 |
+
updateTokensLeft();
|
179 |
</script>
|
180 |
</body>
|
181 |
</html>
|
code/templates/dashboard.html
CHANGED
@@ -27,7 +27,7 @@
|
|
27 |
border-radius: 8px;
|
28 |
width: 100%;
|
29 |
max-width: 400px;
|
30 |
-
padding:
|
31 |
box-sizing: border-box;
|
32 |
text-align: center;
|
33 |
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
|
@@ -39,35 +39,43 @@
|
|
39 |
width: 90px;
|
40 |
height: 90px;
|
41 |
border-radius: 50%;
|
42 |
-
margin-bottom:
|
43 |
border: 2px solid #ddd;
|
44 |
}
|
45 |
|
46 |
.container h1 {
|
47 |
-
margin-bottom:
|
48 |
-
font-size:
|
49 |
font-weight: 600;
|
50 |
color: #1a1a1a;
|
51 |
}
|
52 |
|
53 |
.container p {
|
54 |
-
font-size:
|
55 |
color: #4a4a4a;
|
56 |
-
margin-bottom:
|
57 |
line-height: 1.5;
|
58 |
}
|
59 |
|
60 |
.tokens-left {
|
61 |
-
font-size:
|
62 |
color: #333;
|
63 |
-
margin-bottom:
|
64 |
font-weight: 600;
|
65 |
}
|
66 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
.button {
|
68 |
padding: 12px 0;
|
69 |
margin: 12px 0;
|
70 |
-
font-size:
|
71 |
border-radius: 6px;
|
72 |
cursor: pointer;
|
73 |
width: 100%;
|
@@ -105,6 +113,12 @@
|
|
105 |
border-color: #e04343; /* Darker red for hover */
|
106 |
color: #e04343; /* Red text on hover */
|
107 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
108 |
</style>
|
109 |
</head>
|
110 |
<body>
|
@@ -113,12 +127,14 @@
|
|
113 |
<h1>Welcome, {{ username }}</h1>
|
114 |
<p>Ready to start your AI tutoring session?</p>
|
115 |
<p class="tokens-left">Tokens Left: {{ tokens_left }}</p>
|
|
|
116 |
<form action="/start-tutor" method="post">
|
117 |
<button type="submit" class="button start-button">Start AI Tutor</button>
|
118 |
</form>
|
119 |
<form action="/logout" method="get">
|
120 |
<button type="submit" class="button sign-out-button">Sign Out</button>
|
121 |
</form>
|
|
|
122 |
</div>
|
123 |
<script>
|
124 |
let token = "{{ jwt_token }}";
|
|
|
27 |
border-radius: 8px;
|
28 |
width: 100%;
|
29 |
max-width: 400px;
|
30 |
+
padding: 40px;
|
31 |
box-sizing: border-box;
|
32 |
text-align: center;
|
33 |
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
|
|
|
39 |
width: 90px;
|
40 |
height: 90px;
|
41 |
border-radius: 50%;
|
42 |
+
margin-bottom: 20px;
|
43 |
border: 2px solid #ddd;
|
44 |
}
|
45 |
|
46 |
.container h1 {
|
47 |
+
margin-bottom: 20px;
|
48 |
+
font-size: 26px;
|
49 |
font-weight: 600;
|
50 |
color: #1a1a1a;
|
51 |
}
|
52 |
|
53 |
.container p {
|
54 |
+
font-size: 15px;
|
55 |
color: #4a4a4a;
|
56 |
+
margin-bottom: 25px;
|
57 |
line-height: 1.5;
|
58 |
}
|
59 |
|
60 |
.tokens-left {
|
61 |
+
font-size: 17px;
|
62 |
color: #333;
|
63 |
+
margin-bottom: 10px;
|
64 |
font-weight: 600;
|
65 |
}
|
66 |
|
67 |
+
.all-time-tokens {
|
68 |
+
font-size: 14px; /* Reduced font size */
|
69 |
+
color: #555;
|
70 |
+
margin-bottom: 30px;
|
71 |
+
font-weight: 500;
|
72 |
+
white-space: nowrap; /* Prevents breaking to a new line */
|
73 |
+
}
|
74 |
+
|
75 |
.button {
|
76 |
padding: 12px 0;
|
77 |
margin: 12px 0;
|
78 |
+
font-size: 15px;
|
79 |
border-radius: 6px;
|
80 |
cursor: pointer;
|
81 |
width: 100%;
|
|
|
113 |
border-color: #e04343; /* Darker red for hover */
|
114 |
color: #e04343; /* Red text on hover */
|
115 |
}
|
116 |
+
|
117 |
+
.footer {
|
118 |
+
font-size: 12px;
|
119 |
+
color: #777;
|
120 |
+
margin-top: 25px;
|
121 |
+
}
|
122 |
</style>
|
123 |
</head>
|
124 |
<body>
|
|
|
127 |
<h1>Welcome, {{ username }}</h1>
|
128 |
<p>Ready to start your AI tutoring session?</p>
|
129 |
<p class="tokens-left">Tokens Left: {{ tokens_left }}</p>
|
130 |
+
<p class="all-time-tokens">All-Time Tokens Allocated: {{ all_time_tokens_allocated }} / {{ total_tokens_allocated }}</p>
|
131 |
<form action="/start-tutor" method="post">
|
132 |
<button type="submit" class="button start-button">Start AI Tutor</button>
|
133 |
</form>
|
134 |
<form action="/logout" method="get">
|
135 |
<button type="submit" class="button sign-out-button">Sign Out</button>
|
136 |
</form>
|
137 |
+
<div class="footer">Reload the page to update token stats</div>
|
138 |
</div>
|
139 |
<script>
|
140 |
let token = "{{ jwt_token }}";
|