XThomasBU commited on
Commit
2c49234
1 Parent(s): 703c436

regen_tokens initial commit

Browse files
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
- await reset_tokens_for_user(user_details)
 
 
 
 
 
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
- cl.Text(
229
- name="settings",
230
- display="side",
231
- content=json.dumps(settings_dict, indent=4),
232
- language="json",
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.get_user(identifier=user_email_id)
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
- return False, None
 
 
190
 
 
191
 
192
  async def reset_tokens_for_user(user_info):
193
  user_info = convert_to_dict(user_info)
194
- user_info["metadata"]["tokens_left"] = TOKENS_LEFT
195
- await update_user_info(user_info)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 = 60
8
- TOKENS_LEFT = 3000
 
 
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; /* Button border color */
74
- background-color: #fff; /* Button background color */
75
- color: #4285F4; /* Button text color */
76
  transition: background-color 0.3s ease, border-color 0.3s ease;
77
- display: none; /* Initially hidden */
78
  }
79
 
80
  .button.start-tutor {
81
- display: none; /* Initially hidden */
82
  }
83
 
84
  .button:hover {
85
  background-color: #e0e0e0;
86
- border-color: #357ae8; /* Darker blue for hover */
87
  }
88
 
89
  .sign-out-button {
90
  border: 1px solid #FF4C4C;
91
  background-color: #fff;
92
  color: #FF4C4C;
93
- display: block; /* Ensure this button is always visible */
94
  }
95
 
96
  .sign-out-button:hover {
97
- background-color: #ffe6e6; /* Light red on hover */
98
- border-color: #e04343; /* Darker red for hover */
99
- color: #e04343; /* Red text on hover */
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); // Parse the cooldown end time
126
 
127
  function updateCountdown() {
128
- const now = new Date(); // Get the current time
129
- const timeLeft = endTimeDate.getTime() - now.getTime(); // Calculate the remaining time in milliseconds
130
 
131
  if (timeLeft <= 0) {
132
  countdownElement.textContent = "Cooldown period has ended.";
133
- startTutorBtn.style.display = "block"; // Show the start tutor button
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(); // Initial call to set the countdown
143
- setInterval(updateCountdown, 1000); // Update the countdown every second
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
- // Pass the cooldown_end_time to the script in ISO format with 'Z' to indicate UTC
 
 
 
 
 
 
 
 
 
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: 50px;
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: 25px;
43
  border: 2px solid #ddd;
44
  }
45
 
46
  .container h1 {
47
- margin-bottom: 15px;
48
- font-size: 24px;
49
  font-weight: 600;
50
  color: #1a1a1a;
51
  }
52
 
53
  .container p {
54
- font-size: 16px;
55
  color: #4a4a4a;
56
- margin-bottom: 30px;
57
  line-height: 1.5;
58
  }
59
 
60
  .tokens-left {
61
- font-size: 16px;
62
  color: #333;
63
- margin-bottom: 30px;
64
  font-weight: 600;
65
  }
66
 
 
 
 
 
 
 
 
 
67
  .button {
68
  padding: 12px 0;
69
  margin: 12px 0;
70
- font-size: 14px;
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 }}";