helloparthshah commited on
Commit
148a917
·
1 Parent(s): 9d67598

Fixing the UI

Browse files
Files changed (2) hide show
  1. main.py +44 -238
  2. src/manager/manager.py +7 -6
main.py CHANGED
@@ -4,7 +4,8 @@ import gradio as gr
4
  import base64
5
  from src.manager.manager import GeminiManager, Mode
6
  from enum import Enum
7
- import os, base64
 
8
  from dotenv import load_dotenv
9
  from fastapi import FastAPI, Request, Depends
10
  from fastapi.responses import RedirectResponse, JSONResponse, FileResponse
@@ -13,14 +14,15 @@ from starlette.middleware.sessions import SessionMiddleware
13
  from authlib.integrations.starlette_client import OAuth
14
  import requests
15
  from src.manager.manager import GeminiManager
 
16
 
17
  # 1. Load environment --------------------------------------------------
18
  load_dotenv()
19
- AUTH0_DOMAIN = os.getenv("AUTH0_DOMAIN")
20
- AUTH0_CLIENT_ID = os.getenv("AUTH0_CLIENT_ID")
21
  AUTH0_CLIENT_SECRET = os.getenv("AUTH0_CLIENT_SECRET")
22
- AUTH0_AUDIENCE = os.getenv("AUTH0_AUDIENCE")
23
- SESSION_SECRET_KEY = os.getenv("SESSION_SECRET_KEY", "replaceme")
24
 
25
  # 2. Auth0 client ------------------------------------------------------
26
  oauth = OAuth()
@@ -54,18 +56,22 @@ app.add_middleware(
54
 
55
  # 4. Auth routes -------------------------------------------------------
56
  # Dependency to get the current user
 
 
57
  def get_user(request: Request):
58
  user = request.session.get('user')
59
  if user:
60
  return user['name']
61
  return None
62
 
 
63
  @app.get('/')
64
- def public(request: Request, user = Depends(get_user)):
65
  if user:
66
- return RedirectResponse("/gradio")
67
  else:
68
- return RedirectResponse("/main")
 
69
 
70
  @app.get("/login")
71
  async def login(request: Request):
@@ -73,6 +79,7 @@ async def login(request: Request):
73
  print("Session data:", dict(request.session))
74
  return await oauth.auth0.authorize_redirect(request, request.url_for("auth"), audience=AUTH0_AUDIENCE, prompt="login")
75
 
 
76
  @app.get("/auth")
77
  async def auth(request: Request):
78
  try:
@@ -82,6 +89,7 @@ async def auth(request: Request):
82
  except Exception as e:
83
  return JSONResponse({"error": str(e)}, status_code=500)
84
 
 
85
  @app.get("/logout")
86
  async def logout(request: Request):
87
  auth0_logout_url = (
@@ -91,11 +99,13 @@ async def logout(request: Request):
91
  )
92
  return RedirectResponse(auth0_logout_url)
93
 
 
94
  @app.get("/post-logout")
95
  async def post_logout(request: Request):
96
  request.session.clear()
97
  return RedirectResponse("/")
98
 
 
99
  @app.get("/manifest.json")
100
  async def manifest():
101
  return JSONResponse({
@@ -106,6 +116,7 @@ async def manifest():
106
  "display": "standalone"
107
  })
108
 
 
109
  @app.get("/api/login-status")
110
  async def api_login_status(request: Request):
111
  if "user" in request.session:
@@ -124,7 +135,6 @@ _header_html = f"""
124
  flex-direction: row;
125
  align-items: center;
126
  justify-content: flex-start;
127
- width: 30%;
128
  ">
129
  <img src="data:image/png;base64,{_logo_b64}" width="40" class="logo"/>
130
  <h1>
@@ -136,121 +146,6 @@ css = """
136
  .logo {
137
  margin-right: 20px;
138
  }
139
- .login-status {
140
- font-weight: bold;
141
- margin-right: 20px;
142
- padding: 8px;
143
- border-radius: 4px;
144
- background-color: #f0f0f0;
145
- }
146
-
147
- /* Profile style improvements */
148
- .profile-container {
149
- position: relative;
150
- display: inline-block;
151
- float: right;
152
- margin-right: 20px;
153
- z-index: 9999; /* Ensure this is higher than any other elements */
154
- }
155
-
156
- #profile-name {
157
- background-color: transparent; /* Transparent background */
158
- color: #f97316; /* Orange text */
159
- font-weight: bold;
160
- padding: 10px 14px;
161
- border-radius: 6px;
162
- cursor: pointer;
163
- user-select: none;
164
- display: inline-flex;
165
- align-items: center;
166
- justify-content: center;
167
- min-width: 40px;
168
- min-height: 40px;
169
- border: 2px solid #f97316; /* Add border */
170
- }
171
-
172
- #profile-menu {
173
- position: fixed; /* Changed from absolute to fixed for better overlay */
174
- right: auto; /* Let JS position it precisely */
175
- top: auto; /* Let JS position it precisely */
176
- background-color: transparent;
177
- border: 1px solid transparent;
178
- border-radius: 8px;
179
- box-shadow: 0 4px 12px rgba(0,0,0,0.15);
180
- z-index: 10000; /* Very high z-index to ensure it's on top */
181
- overflow: visible;
182
- width: 160px;
183
- }
184
-
185
- #profile-menu.hidden {
186
- display: none;
187
- }
188
-
189
- #profile-menu button {
190
- background-color: #f97316; /* Orange background */
191
- border: none;
192
- color: white; /* White text */
193
- font-size: 16px;
194
- border-radius: 8px;
195
- text-align: left;
196
- width: 100%;
197
- padding: 12px 16px;
198
- cursor: pointer;
199
- transition: background-color 0.2s ease;
200
- display: block;
201
- }
202
-
203
- #profile-menu button:hover {
204
- background-color: #ea580c; /* Darker orange on hover */
205
- }
206
-
207
- #profile-menu button .icon {
208
- margin-right: 8px;
209
- color: white; /* White icon color */
210
- }
211
-
212
- /* Fix dropdown issues */
213
- input[type="text"], select {
214
- color: black !important;
215
- }
216
-
217
- /* Optional: limit dropdown scroll if options are long */
218
- .gr-dropdown .gr-dropdown-options {
219
- max-height: 200px;
220
- overflow-y: auto;
221
- }
222
-
223
- /* User avatar styles */
224
- .user-avatar {
225
- width: 100%;
226
- height: 100%;
227
- display: flex;
228
- align-items: center;
229
- justify-content: center;
230
- font-weight: bold;
231
- text-transform: uppercase;
232
- font-size: 20px; /* Larger font size */
233
- color: #f97316; /* Orange color */
234
- }
235
-
236
- /* Fix for gradio interface */
237
- .gradio-container {
238
- overflow: visible !important;
239
- }
240
-
241
- /* Fix other container issues that might cause scrolling */
242
- body, html {
243
- overflow-x: hidden; /* Prevent horizontal scrolling */
244
- }
245
-
246
- #gradio-app, .gradio-container .overflow-hidden {
247
- overflow: visible !important; /* Override any overflow hidden that might interfere */
248
- }
249
-
250
- /* Ensure dropdown appears above everything */
251
- .profile-container * {
252
- z-index: 9999;
253
- }
254
  """
255
 
256
 
@@ -270,17 +165,16 @@ def run_model(message, history):
270
  for messages in model_manager.run(history):
271
  yield "", messages
272
 
 
273
  with gr.Blocks() as login:
274
- btn = gr.Button("Login")
275
- _js_redirect = """
276
- () => {
277
- url = '/login' + window.location.search;
278
- window.open(url, '_blank');
279
- }
280
- """
281
- btn.click(None, js=_js_redirect)
282
 
283
- app = gr.mount_gradio_app(app, login, path="/main")
 
 
 
 
 
284
 
285
  with gr.Blocks(css=css, fill_width=True, fill_height=True) as demo:
286
  model_manager = GeminiManager(
@@ -293,30 +187,22 @@ with gr.Blocks(css=css, fill_width=True, fill_height=True) as demo:
293
 
294
  with gr.Column(scale=1):
295
  with gr.Row(scale=0):
296
- gr.Markdown(_header_html)
 
 
297
 
298
- with gr.Column(scale=1, min_width=250):
299
- profile_html = gr.HTML(value="""
300
- <div class="profile-container">
301
- <div id="profile-name" class="user-avatar">G</div>
302
- <div id="profile-menu" class="hidden">
303
- <button id="login-btn" onclick="window.location.href='/login'"><span class="icon">🔐</span> Login</button>
304
- <button id="logout-btn" onclick="window.location.href='/logout'"><span class="icon">🚪</span> Logout</button>
305
- </div>
306
- </div>
307
- """)
308
- with gr.Column():
309
- model_dropdown = gr.Dropdown(
310
- choices=[mode.name for mode in Mode],
311
- value=model_manager.get_current_modes,
312
- interactive=True,
313
- type="index",
314
- multiselect=True,
315
- label="Select Modes",
316
- )
317
-
318
- model_dropdown.change(
319
- fn=update_model, inputs=model_dropdown, outputs=[])
320
  with gr.Row(scale=1):
321
  chatbot = gr.Chatbot(
322
  avatar_images=("HASHIRU_2.png", "HASHIRU.png"),
@@ -335,92 +221,12 @@ with gr.Blocks(css=css, fill_width=True, fill_height=True) as demo:
335
  editable=True,
336
  multimodal=True,)
337
 
338
- demo.load(None, None, None, js="""
339
- async () => {
340
- const profileBtn = document.getElementById("profile-name");
341
- const profileMenu = document.getElementById("profile-menu");
342
- const loginBtn = document.getElementById("login-btn");
343
- const logoutBtn = document.getElementById("logout-btn");
344
-
345
- // Position menu and handle positioning
346
- function positionMenu() {
347
- const btnRect = profileBtn.getBoundingClientRect();
348
- profileMenu.style.position = "fixed";
349
- profileMenu.style.top = (btnRect.bottom + 5) + "px";
350
- profileMenu.style.left = (btnRect.right - profileMenu.offsetWidth) + "px"; // Align with right edge
351
- }
352
-
353
- // Close menu when clicking outside
354
- document.addEventListener('click', (event) => {
355
- if (!profileBtn.contains(event.target) && !profileMenu.contains(event.target)) {
356
- profileMenu.classList.add("hidden");
357
- }
358
- });
359
-
360
- // Toggle menu
361
- profileBtn.onclick = (e) => {
362
- e.stopPropagation();
363
- positionMenu(); // Position before showing
364
- profileMenu.classList.toggle("hidden");
365
-
366
- // If showing menu, make sure it's positioned correctly
367
- if (!profileMenu.classList.contains("hidden")) {
368
- setTimeout(positionMenu, 0); // Reposition after render
369
- }
370
- }
371
-
372
- // Handle window resize
373
- window.addEventListener('resize', () => {
374
- if (!profileMenu.classList.contains("hidden")) {
375
- positionMenu();
376
- }
377
- });
378
-
379
- // Get initial letter for avatar
380
- function getInitial(name) {
381
- if (name && name.length > 0) {
382
- return name.charAt(0);
383
- }
384
- return "?";
385
- }
386
-
387
- try {
388
- const res = await fetch('/api/login-status', { credentials: 'include' });
389
- const data = await res.json();
390
-
391
- if (!data.status.includes("Logged out")) {
392
- const name = data.status.replace("Logged in: ", "");
393
- profileBtn.innerHTML = `<div class="user-avatar">${getInitial(name)}</div>`;
394
- profileBtn.title = name;
395
- loginBtn.style.display = "none";
396
- logoutBtn.style.display = "block";
397
- } else {
398
- profileBtn.innerHTML = `<div class="user-avatar">G</div>`;
399
- profileBtn.title = "Guest";
400
- loginBtn.style.display = "block";
401
- logoutBtn.style.display = "none";
402
- }
403
- } catch (error) {
404
- console.error("Error fetching login status:", error);
405
- profileBtn.innerHTML = `<div class="user-avatar">?</div>`;
406
- profileBtn.title = "Login status unknown";
407
- }
408
- }
409
- """)
410
-
411
- app = gr.mount_gradio_app(app, demo, path="/gradio",auth_dependency=get_user)
412
 
413
  if __name__ == "__main__":
414
  import uvicorn
415
- import argparse
416
-
417
- parser = argparse.ArgumentParser()
418
- parser.add_argument('--no-auth', action='store_true')
419
- args = parser.parse_args()
420
- no_auth = args.no_auth
421
-
422
  if no_auth:
423
  demo.launch()
424
  else:
425
  uvicorn.run(app, host="0.0.0.0", port=7860)
426
-
 
4
  import base64
5
  from src.manager.manager import GeminiManager, Mode
6
  from enum import Enum
7
+ import os
8
+ import base64
9
  from dotenv import load_dotenv
10
  from fastapi import FastAPI, Request, Depends
11
  from fastapi.responses import RedirectResponse, JSONResponse, FileResponse
 
14
  from authlib.integrations.starlette_client import OAuth
15
  import requests
16
  from src.manager.manager import GeminiManager
17
+ import argparse
18
 
19
  # 1. Load environment --------------------------------------------------
20
  load_dotenv()
21
+ AUTH0_DOMAIN = os.getenv("AUTH0_DOMAIN")
22
+ AUTH0_CLIENT_ID = os.getenv("AUTH0_CLIENT_ID")
23
  AUTH0_CLIENT_SECRET = os.getenv("AUTH0_CLIENT_SECRET")
24
+ AUTH0_AUDIENCE = os.getenv("AUTH0_AUDIENCE")
25
+ SESSION_SECRET_KEY = os.getenv("SESSION_SECRET_KEY", "replace-me")
26
 
27
  # 2. Auth0 client ------------------------------------------------------
28
  oauth = OAuth()
 
56
 
57
  # 4. Auth routes -------------------------------------------------------
58
  # Dependency to get the current user
59
+
60
+
61
  def get_user(request: Request):
62
  user = request.session.get('user')
63
  if user:
64
  return user['name']
65
  return None
66
 
67
+
68
  @app.get('/')
69
+ def public(request: Request, user=Depends(get_user)):
70
  if user:
71
+ return RedirectResponse("/hashiru")
72
  else:
73
+ return RedirectResponse("/login-page")
74
+
75
 
76
  @app.get("/login")
77
  async def login(request: Request):
 
79
  print("Session data:", dict(request.session))
80
  return await oauth.auth0.authorize_redirect(request, request.url_for("auth"), audience=AUTH0_AUDIENCE, prompt="login")
81
 
82
+
83
  @app.get("/auth")
84
  async def auth(request: Request):
85
  try:
 
89
  except Exception as e:
90
  return JSONResponse({"error": str(e)}, status_code=500)
91
 
92
+
93
  @app.get("/logout")
94
  async def logout(request: Request):
95
  auth0_logout_url = (
 
99
  )
100
  return RedirectResponse(auth0_logout_url)
101
 
102
+
103
  @app.get("/post-logout")
104
  async def post_logout(request: Request):
105
  request.session.clear()
106
  return RedirectResponse("/")
107
 
108
+
109
  @app.get("/manifest.json")
110
  async def manifest():
111
  return JSONResponse({
 
116
  "display": "standalone"
117
  })
118
 
119
+
120
  @app.get("/api/login-status")
121
  async def api_login_status(request: Request):
122
  if "user" in request.session:
 
135
  flex-direction: row;
136
  align-items: center;
137
  justify-content: flex-start;
 
138
  ">
139
  <img src="data:image/png;base64,{_logo_b64}" width="40" class="logo"/>
140
  <h1>
 
146
  .logo {
147
  margin-right: 20px;
148
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  """
150
 
151
 
 
165
  for messages in model_manager.run(history):
166
  yield "", messages
167
 
168
+
169
  with gr.Blocks() as login:
170
+ btn = gr.Button("Login", link="/login")
 
 
 
 
 
 
 
171
 
172
+ app = gr.mount_gradio_app(app, login, path="/login-page")
173
+
174
+ parser = argparse.ArgumentParser()
175
+ parser.add_argument('--no-auth', action='store_true')
176
+ args, unknown = parser.parse_known_args()
177
+ no_auth = args.no_auth
178
 
179
  with gr.Blocks(css=css, fill_width=True, fill_height=True) as demo:
180
  model_manager = GeminiManager(
 
187
 
188
  with gr.Column(scale=1):
189
  with gr.Row(scale=0):
190
+ with gr.Column(scale=0):
191
+ gr.Markdown(_header_html)
192
+ gr.Button("Logout", link="/logout")
193
 
194
+ with gr.Column(scale=1):
195
+ model_dropdown = gr.Dropdown(
196
+ choices=[mode.name for mode in Mode],
197
+ value=model_manager.get_current_modes,
198
+ interactive=True,
199
+ type="index",
200
+ multiselect=True,
201
+ label="Select Modes",
202
+ )
203
+
204
+ model_dropdown.change(
205
+ fn=update_model, inputs=model_dropdown, outputs=[])
 
 
 
 
 
 
 
 
 
 
206
  with gr.Row(scale=1):
207
  chatbot = gr.Chatbot(
208
  avatar_images=("HASHIRU_2.png", "HASHIRU.png"),
 
221
  editable=True,
222
  multimodal=True,)
223
 
224
+ app = gr.mount_gradio_app(app, demo, path="/hashiru", auth_dependency=get_user)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
225
 
226
  if __name__ == "__main__":
227
  import uvicorn
228
+
 
 
 
 
 
 
229
  if no_auth:
230
  demo.launch()
231
  else:
232
  uvicorn.run(app, host="0.0.0.0", port=7860)
 
src/manager/manager.py CHANGED
@@ -305,12 +305,13 @@ class GeminiManager:
305
  yield messages
306
 
307
  # Attach the function call response to the messages
308
- if response.candidates[0].content and response.candidates[0].content.parts:
309
- # messages.append(response.candidates[0].content)
310
- messages.append({
311
- "role": "function_call",
312
- "content": repr(response.candidates[0].content),
313
- })
 
314
 
315
  # Invoke the function calls if any and attach the response to the messages
316
  if response.function_calls:
 
305
  yield messages
306
 
307
  # Attach the function call response to the messages
308
+ for candidate in response.candidates:
309
+ if candidate.content and candidate.content.parts:
310
+ # messages.append(response.candidates[0].content)
311
+ messages.append({
312
+ "role": "function_call",
313
+ "content": repr(candidate.content),
314
+ })
315
 
316
  # Invoke the function calls if any and attach the response to the messages
317
  if response.function_calls: