siddhartharya commited on
Commit
64b94b7
Β·
verified Β·
1 Parent(s): d8fbcd1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +232 -124
app.py CHANGED
@@ -2,10 +2,6 @@
2
 
3
  import gradio as gr
4
  from bs4 import BeautifulSoup
5
- import requests
6
- from sentence_transformers import SentenceTransformer
7
- import faiss
8
- import numpy as np
9
  import asyncio
10
  import aiohttp
11
  import re
@@ -13,6 +9,9 @@ import base64
13
  import logging
14
  import os
15
  import sys
 
 
 
16
 
17
  # Import OpenAI library
18
  import openai
@@ -36,7 +35,6 @@ logger.addHandler(console_handler)
36
  logger.info("Initializing models and variables")
37
  embedding_model = SentenceTransformer('all-MiniLM-L6-v2')
38
  faiss_index = None
39
- bookmarks = []
40
  fetch_cache = {}
41
 
42
  # Define the categories
@@ -234,10 +232,10 @@ def vectorize_and_index(bookmarks):
234
  raise
235
 
236
  # Generate HTML display for bookmarks
237
- def display_bookmarks():
238
  logger.info("Generating HTML display for bookmarks")
239
  cards = ''
240
- for i, bookmark in enumerate(bookmarks):
241
  index = i + 1 # Start index at 1
242
  status = "❌ Dead Link" if bookmark.get('dead_link') else "βœ… Active"
243
  title = bookmark['title']
@@ -246,16 +244,16 @@ def display_bookmarks():
246
  summary = bookmark.get('summary', '')
247
  category = bookmark.get('category', 'Uncategorized')
248
 
249
- # Apply inline styles for dead links
250
  if bookmark.get('dead_link'):
251
- card_style = "border: 2px solid #D32F2F;"
252
- text_style = "color: #D32F2F;"
253
  else:
254
- card_style = "border: 2px solid #4CAF50;"
255
- text_style = "color: #000000;"
256
 
257
  card_html = f'''
258
- <div class="card" style="{card_style}; padding: 10px; margin: 10px; border-radius: 5px;">
259
  <div class="card-content">
260
  <h3 style="{text_style}">{index}. {title} {status}</h3>
261
  <p style="{text_style}"><strong>Category:</strong> {category}</p>
@@ -270,34 +268,64 @@ def display_bookmarks():
270
  return cards
271
 
272
  # Process the uploaded file
273
- def process_uploaded_file(file):
274
- global bookmarks, faiss_index
275
  logger.info("Processing uploaded file")
276
  if file is None:
277
  logger.warning("No file uploaded")
278
- return "Please upload a bookmarks HTML file.", '', gr.update(choices=[]), display_bookmarks()
 
 
 
 
 
 
 
279
  try:
280
  file_content = file.decode('utf-8')
281
  except UnicodeDecodeError as e:
282
  logger.error(f"Error decoding the file: {e}")
283
- return "Error decoding the file. Please ensure it's a valid HTML file.", '', gr.update(choices=[]), display_bookmarks()
 
 
 
 
 
 
284
 
285
  try:
286
  bookmarks = parse_bookmarks(file_content)
287
  except Exception as e:
288
  logger.error(f"Error parsing bookmarks: {e}")
289
- return "Error parsing the bookmarks HTML file.", '', gr.update(choices=[]), display_bookmarks()
 
 
 
 
 
 
290
 
291
  if not bookmarks:
292
  logger.warning("No bookmarks found in the uploaded file")
293
- return "No bookmarks found in the uploaded file.", '', gr.update(choices=[]), display_bookmarks()
 
 
 
 
 
 
294
 
295
  # Asynchronously fetch bookmark info
296
  try:
297
  asyncio.run(process_bookmarks_async(bookmarks))
298
  except Exception as e:
299
  logger.error(f"Error processing bookmarks asynchronously: {e}")
300
- return "Error processing bookmarks.", '', gr.update(choices=[]), display_bookmarks()
 
 
 
 
 
 
301
 
302
  # Generate summaries and assign categories
303
  for bookmark in bookmarks:
@@ -308,67 +336,125 @@ def process_uploaded_file(file):
308
  faiss_index, embeddings = vectorize_and_index(bookmarks)
309
  except Exception as e:
310
  logger.error(f"Error building FAISS index: {e}")
311
- return "Error building search index.", '', gr.update(choices=[]), display_bookmarks()
 
 
 
 
 
 
312
 
313
  message = f"βœ… Successfully processed {len(bookmarks)} bookmarks."
314
  logger.info(message)
315
- bookmark_html = display_bookmarks()
316
 
317
- # Update bookmark_selector choices
318
  choices = [f"{i+1}. {bookmark['title']} (Category: {bookmark['category']})" for i, bookmark in enumerate(bookmarks)]
319
- bookmark_selector_update = gr.update(choices=choices, value=[])
320
 
321
- # Update bookmark_display_manage
322
- bookmark_display_manage_update = display_bookmarks()
323
 
324
- return message, bookmark_html, bookmark_selector_update, bookmark_display_manage_update
 
 
 
 
 
 
325
 
326
  # Delete selected bookmarks
327
- def delete_selected_bookmarks(selected_indices):
328
- global bookmarks, faiss_index
329
  if not selected_indices:
330
- return "⚠️ No bookmarks selected.", gr.update(choices=[]), display_bookmarks()
331
- indices = [int(s.split('.')[0])-1 for s in selected_indices]
 
 
 
 
 
 
 
 
 
 
 
 
332
  indices = sorted(indices, reverse=True)
333
  for idx in indices:
334
- if 0 <= idx < len(bookmarks):
335
- logger.info(f"Deleting bookmark at index {idx + 1}")
336
- bookmarks.pop(idx)
337
  if bookmarks:
338
  faiss_index, embeddings = vectorize_and_index(bookmarks)
339
  else:
340
  faiss_index = None
 
341
  message = "πŸ—‘οΈ Selected bookmarks deleted successfully."
342
  logger.info(message)
343
- # Update bookmark_selector choices
 
 
 
 
344
  choices = [f"{i+1}. {bookmark['title']} (Category: {bookmark['category']})" for i, bookmark in enumerate(bookmarks)]
345
- bookmark_selector_update = gr.update(choices=choices, value=[])
346
- # Update bookmarks display
347
- bookmarks_html = display_bookmarks()
348
- return message, bookmark_selector_update, bookmarks_html
 
349
 
350
  # Edit category of selected bookmarks
351
- def edit_selected_bookmarks_category(selected_indices, new_category):
352
  if not selected_indices:
353
- return "⚠️ No bookmarks selected.", '', gr.update()
 
 
 
 
 
 
354
  if not new_category:
355
- return "⚠️ No new category selected.", '', gr.update()
356
- indices = [int(s.split('.')[0])-1 for s in selected_indices]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
  for idx in indices:
358
- if 0 <= idx < len(bookmarks):
359
- bookmarks[idx]['category'] = new_category
360
- logger.info(f"Updated category for bookmark {idx + 1} to {new_category}")
361
  message = "✏️ Category updated for selected bookmarks."
362
  logger.info(message)
363
- # Update bookmark_selector choices
 
 
 
 
364
  choices = [f"{i+1}. {bookmark['title']} (Category: {bookmark['category']})" for i, bookmark in enumerate(bookmarks)]
365
- bookmark_selector_update = gr.update(choices=choices, value=[])
366
- # Update bookmarks display
367
- bookmarks_html = display_bookmarks()
368
- return message, bookmark_selector_update, bookmarks_html
 
369
 
370
  # Export bookmarks to HTML
371
- def export_bookmarks():
 
372
  if not bookmarks:
373
  logger.warning("No bookmarks to export")
374
  return "⚠️ No bookmarks to export."
@@ -395,11 +481,12 @@ def export_bookmarks():
395
  return "⚠️ Error exporting bookmarks."
396
 
397
  # Chatbot response using Groq Cloud API
398
- def chatbot_response(user_query):
399
  if not GROQ_API_KEY:
400
  logger.warning("GROQ_API_KEY not set.")
401
  return "⚠️ API key not set. Please set the GROQ_API_KEY environment variable in the Hugging Face Space settings."
402
 
 
403
  if not bookmarks:
404
  logger.warning("No bookmarks available for chatbot")
405
  return "⚠️ No bookmarks available. Please upload and process your bookmarks first."
@@ -453,7 +540,7 @@ Please identify the most relevant bookmarks that match the user's query. Provide
453
  def build_app():
454
  try:
455
  logger.info("Building Gradio app")
456
- with gr.Blocks(css="""
457
  .card {
458
  box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
459
  transition: 0.3s;
@@ -462,147 +549,168 @@ def build_app():
462
  box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2);
463
  }
464
  """) as demo:
 
 
 
 
465
  # General Overview
466
  gr.Markdown("""
467
- # πŸ“š SmartMarks - AI Browser Bookmarks Manager
 
 
468
 
469
- Welcome to **SmartMarks**, your intelligent assistant for managing browser bookmarks. SmartMarks leverages AI to help you organize, search, and interact with your bookmarks seamlessly. Whether you're looking to categorize your links, retrieve information quickly, or maintain an updated list, SmartMarks has you covered.
470
 
471
- ---
472
 
473
- ## πŸš€ **How to Use SmartMarks**
474
 
475
- SmartMarks is divided into three main sections:
 
 
476
 
477
- 1. **πŸ“‚ Upload and Process Bookmarks:** Import your existing bookmarks and let SmartMarks analyze and categorize them for you.
478
- 2. **πŸ’¬ Chat with Bookmarks:** Interact with your bookmarks using natural language queries to find relevant links effortlessly.
479
- 3. **πŸ› οΈ Manage Bookmarks:** View, edit, delete, and export your bookmarks with ease.
480
 
481
- Navigate through the tabs to explore each feature in detail.
482
- """)
 
483
 
484
  # Upload and Process Bookmarks Tab
485
  with gr.Tab("Upload and Process Bookmarks"):
486
  gr.Markdown("""
487
- ## πŸ“‚ **Upload and Process Bookmarks**
488
 
489
- ### πŸ“ **Steps to Upload and Process:**
490
 
491
- 1. **πŸ”½ Upload Bookmarks File:**
492
- - Click on the **"Upload Bookmarks HTML File"** button.
493
- - Select your browser's exported bookmarks HTML file from your device.
494
 
495
- 2. **βš™οΈ Process Bookmarks:**
496
- - After uploading, click on the **"Process Bookmarks"** button.
497
- - SmartMarks will parse your bookmarks, fetch additional information, generate summaries, and categorize each link based on predefined categories.
498
 
499
- 3. **πŸ“„ View Processed Bookmarks:**
500
- - Once processing is complete, your bookmarks will be displayed in an organized and visually appealing format below.
501
- """)
502
 
503
  upload = gr.File(label="πŸ“ Upload Bookmarks HTML File", type='binary')
504
  process_button = gr.Button("βš™οΈ Process Bookmarks")
505
  output_text = gr.Textbox(label="βœ… Output", interactive=False)
506
  bookmark_display = gr.HTML(label="πŸ“„ Bookmarks")
507
 
508
- # Initialize Manage Bookmarks components
509
- bookmark_selector = gr.CheckboxGroup(label="βœ… Select Bookmarks", choices=[])
510
- bookmark_display_manage = gr.HTML(label="πŸ“„ Manage Bookmarks Display")
511
-
512
  process_button.click(
513
  process_uploaded_file,
514
- inputs=upload,
515
- outputs=[output_text, bookmark_display, bookmark_selector, bookmark_display_manage]
516
  )
517
 
518
  # Chat with Bookmarks Tab
519
  with gr.Tab("Chat with Bookmarks"):
520
  gr.Markdown("""
521
- ## πŸ’¬ **Chat with Bookmarks**
522
 
523
- ### πŸ€– **How to Interact:**
524
 
525
- 1. **✍️ Enter Your Query:**
526
- - In the **"Ask about your bookmarks"** textbox, type your question or keyword related to your bookmarks. For example, "Do I have any bookmarks about GenerativeAI?"
527
 
528
- 2. **πŸ“¨ Submit Your Query:**
529
- - Click the **"Send"** button to submit your query.
530
 
531
- 3. **πŸ“ˆ Receive AI-Driven Responses:**
532
- - SmartMarks will analyze your query and provide relevant bookmarks that match your request, making it easier to find specific links without manual searching.
533
- """)
534
 
535
- user_input = gr.Textbox(label="✍️ Ask about your bookmarks", placeholder="e.g., Do I have any bookmarks about GenerativeAI?")
536
- chat_output = gr.Textbox(label="πŸ’¬ Chatbot Response", interactive=False)
537
- chat_button = gr.Button("πŸ“¨ Send")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
538
 
 
539
  chat_button.click(
540
  chatbot_response,
541
- inputs=user_input,
542
- outputs=chat_output
543
  )
544
 
545
  # Manage Bookmarks Tab
546
  with gr.Tab("Manage Bookmarks"):
547
  gr.Markdown("""
548
- ## πŸ› οΈ **Manage Bookmarks**
549
 
550
- ### πŸ—‚οΈ **Features:**
551
 
552
- 1. **πŸ‘οΈ View Bookmarks:**
553
- - All your processed bookmarks are displayed here with their respective categories and summaries.
554
 
555
- 2. **βœ… Select Bookmarks:**
556
- - Use the checkboxes next to each bookmark to select one, multiple, or all bookmarks you wish to manage.
557
 
558
- 3. **πŸ—‘οΈ Delete Selected Bookmarks:**
559
- - After selecting the desired bookmarks, click the **"Delete Selected Bookmarks"** button to remove them from your list.
560
 
561
- 4. **✏️ Edit Categories:**
562
- - Select the bookmarks you want to re-categorize.
563
- - Choose a new category from the dropdown menu labeled **"New Category"**.
564
- - Click the **"Edit Category of Selected Bookmarks"** button to update their categories.
565
 
566
- 5. **πŸ’Ύ Export Bookmarks:**
567
- - Click the **"Export Bookmarks"** button to download your updated bookmarks as an HTML file.
568
- - This file can be uploaded back to your browser to reflect the changes made within SmartMarks.
569
- """)
570
 
571
  manage_output = gr.Textbox(label="πŸ”„ Manage Output", interactive=False)
572
- bookmark_display_manage = gr.HTML(label="πŸ“„ Manage Bookmarks Display")
573
- bookmark_selector = gr.CheckboxGroup(label="βœ… Select Bookmarks", choices=[])
574
-
575
  new_category_input = gr.Dropdown(label="πŸ†• New Category", choices=CATEGORIES, value="Uncategorized")
576
  with gr.Row():
577
  delete_button = gr.Button("πŸ—‘οΈ Delete Selected Bookmarks")
578
  edit_category_button = gr.Button("✏️ Edit Category of Selected Bookmarks")
579
  export_button = gr.Button("πŸ’Ύ Export Bookmarks")
580
  download_link = gr.HTML(label="πŸ“₯ Download Exported Bookmarks")
 
581
 
582
  # Define button actions
583
  delete_button.click(
584
  delete_selected_bookmarks,
585
- inputs=bookmark_selector,
586
- outputs=[manage_output, bookmark_selector, bookmark_display_manage]
587
  )
588
 
589
  edit_category_button.click(
590
  edit_selected_bookmarks_category,
591
- inputs=[bookmark_selector, new_category_input],
592
- outputs=[manage_output, bookmark_selector, bookmark_display_manage]
593
  )
594
 
595
  export_button.click(
596
  export_bookmarks,
597
- inputs=None,
598
  outputs=download_link
599
  )
600
 
601
- # Initialize display after processing bookmarks
602
- process_button.click(
603
- process_uploaded_file,
604
- inputs=upload,
605
- outputs=[output_text, bookmark_display, bookmark_selector, bookmark_display_manage]
 
 
 
 
606
  )
607
 
608
  logger.info("Launching Gradio app")
 
2
 
3
  import gradio as gr
4
  from bs4 import BeautifulSoup
 
 
 
 
5
  import asyncio
6
  import aiohttp
7
  import re
 
9
  import logging
10
  import os
11
  import sys
12
+ from sentence_transformers import SentenceTransformer
13
+ import faiss
14
+ import numpy as np
15
 
16
  # Import OpenAI library
17
  import openai
 
35
  logger.info("Initializing models and variables")
36
  embedding_model = SentenceTransformer('all-MiniLM-L6-v2')
37
  faiss_index = None
 
38
  fetch_cache = {}
39
 
40
  # Define the categories
 
232
  raise
233
 
234
  # Generate HTML display for bookmarks
235
+ def display_bookmarks(bookmarks_list):
236
  logger.info("Generating HTML display for bookmarks")
237
  cards = ''
238
+ for i, bookmark in enumerate(bookmarks_list):
239
  index = i + 1 # Start index at 1
240
  status = "❌ Dead Link" if bookmark.get('dead_link') else "βœ… Active"
241
  title = bookmark['title']
 
244
  summary = bookmark.get('summary', '')
245
  category = bookmark.get('category', 'Uncategorized')
246
 
247
+ # Assign CSS classes based on bookmark status
248
  if bookmark.get('dead_link'):
249
+ card_classes = "card dead-link"
250
+ text_style = "color: #D32F2F;" # Red color for dead links
251
  else:
252
+ card_classes = "card active-link"
253
+ text_style = "color: #000000;" # Black color for active links
254
 
255
  card_html = f'''
256
+ <div class="{card_classes}" style="border: 2px solid; padding: 10px; margin: 10px; border-radius: 5px;">
257
  <div class="card-content">
258
  <h3 style="{text_style}">{index}. {title} {status}</h3>
259
  <p style="{text_style}"><strong>Category:</strong> {category}</p>
 
268
  return cards
269
 
270
  # Process the uploaded file
271
+ def process_uploaded_file(file, state_bookmarks):
 
272
  logger.info("Processing uploaded file")
273
  if file is None:
274
  logger.warning("No file uploaded")
275
+ return (
276
+ "⚠️ Please upload a bookmarks HTML file.",
277
+ "",
278
+ [],
279
+ "",
280
+ state_bookmarks # Return the unchanged state
281
+ )
282
+
283
  try:
284
  file_content = file.decode('utf-8')
285
  except UnicodeDecodeError as e:
286
  logger.error(f"Error decoding the file: {e}")
287
+ return (
288
+ "⚠️ Error decoding the file. Please ensure it's a valid HTML file.",
289
+ "",
290
+ [],
291
+ "",
292
+ state_bookmarks # Return the unchanged state
293
+ )
294
 
295
  try:
296
  bookmarks = parse_bookmarks(file_content)
297
  except Exception as e:
298
  logger.error(f"Error parsing bookmarks: {e}")
299
+ return (
300
+ "⚠️ Error parsing the bookmarks HTML file.",
301
+ "",
302
+ [],
303
+ "",
304
+ state_bookmarks # Return the unchanged state
305
+ )
306
 
307
  if not bookmarks:
308
  logger.warning("No bookmarks found in the uploaded file")
309
+ return (
310
+ "⚠️ No bookmarks found in the uploaded file.",
311
+ "",
312
+ [],
313
+ "",
314
+ state_bookmarks # Return the unchanged state
315
+ )
316
 
317
  # Asynchronously fetch bookmark info
318
  try:
319
  asyncio.run(process_bookmarks_async(bookmarks))
320
  except Exception as e:
321
  logger.error(f"Error processing bookmarks asynchronously: {e}")
322
+ return (
323
+ "⚠️ Error processing bookmarks.",
324
+ "",
325
+ [],
326
+ "",
327
+ state_bookmarks # Return the unchanged state
328
+ )
329
 
330
  # Generate summaries and assign categories
331
  for bookmark in bookmarks:
 
336
  faiss_index, embeddings = vectorize_and_index(bookmarks)
337
  except Exception as e:
338
  logger.error(f"Error building FAISS index: {e}")
339
+ return (
340
+ "⚠️ Error building search index.",
341
+ "",
342
+ [],
343
+ "",
344
+ state_bookmarks # Return the unchanged state
345
+ )
346
 
347
  message = f"βœ… Successfully processed {len(bookmarks)} bookmarks."
348
  logger.info(message)
349
+ bookmark_html = display_bookmarks(bookmarks)
350
 
351
+ # Prepare Manage Bookmarks tab outputs
352
  choices = [f"{i+1}. {bookmark['title']} (Category: {bookmark['category']})" for i, bookmark in enumerate(bookmarks)]
353
+ bookmarks_html_manage = display_bookmarks(bookmarks)
354
 
355
+ # Update the shared state
356
+ updated_state = bookmarks.copy()
357
 
358
+ return (
359
+ message,
360
+ bookmark_html,
361
+ choices,
362
+ bookmarks_html_manage,
363
+ updated_state # Return the updated state
364
+ )
365
 
366
  # Delete selected bookmarks
367
+ def delete_selected_bookmarks(selected_indices, state_bookmarks):
 
368
  if not selected_indices:
369
+ return "⚠️ No bookmarks selected.", gr.update(choices=[]), ""
370
+
371
+ bookmarks = state_bookmarks.copy()
372
+ indices = []
373
+ for s in selected_indices:
374
+ try:
375
+ idx = int(s.split('.')[0]) - 1
376
+ if 0 <= idx < len(bookmarks):
377
+ indices.append(idx)
378
+ else:
379
+ logger.warning(f"Index out of range: {idx + 1}")
380
+ except ValueError:
381
+ logger.error(f"Invalid selection format: {s}")
382
+
383
  indices = sorted(indices, reverse=True)
384
  for idx in indices:
385
+ logger.info(f"Deleting bookmark at index {idx + 1}")
386
+ bookmarks.pop(idx)
387
+
388
  if bookmarks:
389
  faiss_index, embeddings = vectorize_and_index(bookmarks)
390
  else:
391
  faiss_index = None
392
+
393
  message = "πŸ—‘οΈ Selected bookmarks deleted successfully."
394
  logger.info(message)
395
+
396
+ # Regenerate HTML display
397
+ bookmarks_html = display_bookmarks(bookmarks)
398
+
399
+ # Update choices for selection
400
  choices = [f"{i+1}. {bookmark['title']} (Category: {bookmark['category']})" for i, bookmark in enumerate(bookmarks)]
401
+
402
+ # Update the shared state
403
+ updated_state = bookmarks.copy()
404
+
405
+ return message, gr.update(choices=choices), bookmarks_html, updated_state
406
 
407
  # Edit category of selected bookmarks
408
+ def edit_selected_bookmarks_category(selected_indices, new_category, state_bookmarks):
409
  if not selected_indices:
410
+ return (
411
+ "⚠️ No bookmarks selected.",
412
+ gr.update(choices=[f"{i+1}. {bookmark['title']} (Category: {bookmark['category']})" for i, bookmark in enumerate(state_bookmarks)]),
413
+ display_bookmarks(state_bookmarks),
414
+ state_bookmarks
415
+ )
416
+
417
  if not new_category:
418
+ return (
419
+ "⚠️ No new category selected.",
420
+ gr.update(choices=[f"{i+1}. {bookmark['title']} (Category: {bookmark['category']})" for i, bookmark in enumerate(state_bookmarks)]),
421
+ display_bookmarks(state_bookmarks),
422
+ state_bookmarks
423
+ )
424
+
425
+ bookmarks = state_bookmarks.copy()
426
+ indices = []
427
+ for s in selected_indices:
428
+ try:
429
+ idx = int(s.split('.')[0]) - 1
430
+ if 0 <= idx < len(bookmarks):
431
+ indices.append(idx)
432
+ else:
433
+ logger.warning(f"Index out of range: {idx + 1}")
434
+ except ValueError:
435
+ logger.error(f"Invalid selection format: {s}")
436
+
437
  for idx in indices:
438
+ bookmarks[idx]['category'] = new_category
439
+ logger.info(f"Updated category for bookmark {idx + 1} to {new_category}")
440
+
441
  message = "✏️ Category updated for selected bookmarks."
442
  logger.info(message)
443
+
444
+ # Regenerate HTML display
445
+ bookmarks_html = display_bookmarks(bookmarks)
446
+
447
+ # Update choices for selection
448
  choices = [f"{i+1}. {bookmark['title']} (Category: {bookmark['category']})" for i, bookmark in enumerate(bookmarks)]
449
+
450
+ # Update the shared state
451
+ updated_state = bookmarks.copy()
452
+
453
+ return message, gr.update(choices=choices), bookmarks_html, updated_state
454
 
455
  # Export bookmarks to HTML
456
+ def export_bookmarks(state_bookmarks):
457
+ bookmarks = state_bookmarks
458
  if not bookmarks:
459
  logger.warning("No bookmarks to export")
460
  return "⚠️ No bookmarks to export."
 
481
  return "⚠️ Error exporting bookmarks."
482
 
483
  # Chatbot response using Groq Cloud API
484
+ def chatbot_response(user_query, state_bookmarks):
485
  if not GROQ_API_KEY:
486
  logger.warning("GROQ_API_KEY not set.")
487
  return "⚠️ API key not set. Please set the GROQ_API_KEY environment variable in the Hugging Face Space settings."
488
 
489
+ bookmarks = state_bookmarks
490
  if not bookmarks:
491
  logger.warning("No bookmarks available for chatbot")
492
  return "⚠️ No bookmarks available. Please upload and process your bookmarks first."
 
540
  def build_app():
541
  try:
542
  logger.info("Building Gradio app")
543
+ with gr.Blocks(theme=gr.themes.Default(), css="""
544
  .card {
545
  box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
546
  transition: 0.3s;
 
549
  box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2);
550
  }
551
  """) as demo:
552
+ # Shared states
553
+ state_bookmarks = gr.State([])
554
+ chat_history = gr.State([]) # Optional, if you want to maintain chat history
555
+
556
  # General Overview
557
  gr.Markdown("""
558
+ # πŸ“š SmartMarks - AI Browser Bookmarks Manager
559
+
560
+ Welcome to **SmartMarks**, your intelligent assistant for managing browser bookmarks. SmartMarks leverages AI to help you organize, search, and interact with your bookmarks seamlessly. Whether you're looking to categorize your links, retrieve information quickly, or maintain an updated list, SmartMarks has you covered.
561
 
562
+ ---
563
 
564
+ ## πŸš€ **How to Use SmartMarks**
565
 
566
+ SmartMarks is divided into three main sections:
567
 
568
+ 1. **πŸ“‚ Upload and Process Bookmarks:** Import your existing bookmarks and let SmartMarks analyze and categorize them for you.
569
+ 2. **πŸ’¬ Chat with Bookmarks:** Interact with your bookmarks using natural language queries to find relevant links effortlessly.
570
+ 3. **πŸ› οΈ Manage Bookmarks:** View, edit, delete, and export your bookmarks with ease.
571
 
572
+ Navigate through the tabs to explore each feature in detail.
573
+ """)
 
574
 
575
+ # Define Manage Bookmarks components outside the tab for global access
576
+ bookmark_selector = gr.CheckboxGroup(label="βœ… Select Bookmarks", choices=[])
577
+ bookmark_display_manage = gr.HTML(label="πŸ“„ Manage Bookmarks Display")
578
 
579
  # Upload and Process Bookmarks Tab
580
  with gr.Tab("Upload and Process Bookmarks"):
581
  gr.Markdown("""
582
+ ## πŸ“‚ **Upload and Process Bookmarks**
583
 
584
+ ### πŸ“ **Steps to Upload and Process:**
585
 
586
+ 1. **πŸ”½ Upload Bookmarks File:**
587
+ - Click on the **"πŸ“ Upload Bookmarks HTML File"** button.
588
+ - Select your browser's exported bookmarks HTML file from your device.
589
 
590
+ 2. **βš™οΈ Process Bookmarks:**
591
+ - After uploading, click on the **"βš™οΈ Process Bookmarks"** button.
592
+ - SmartMarks will parse your bookmarks, fetch additional information, generate summaries, and categorize each link based on predefined categories.
593
 
594
+ 3. **πŸ“„ View Processed Bookmarks:**
595
+ - Once processing is complete, your bookmarks will be displayed in an organized and visually appealing format below.
596
+ """)
597
 
598
  upload = gr.File(label="πŸ“ Upload Bookmarks HTML File", type='binary')
599
  process_button = gr.Button("βš™οΈ Process Bookmarks")
600
  output_text = gr.Textbox(label="βœ… Output", interactive=False)
601
  bookmark_display = gr.HTML(label="πŸ“„ Bookmarks")
602
 
 
 
 
 
603
  process_button.click(
604
  process_uploaded_file,
605
+ inputs=[upload, state_bookmarks],
606
+ outputs=[output_text, bookmark_display, bookmark_selector, bookmark_display_manage, state_bookmarks]
607
  )
608
 
609
  # Chat with Bookmarks Tab
610
  with gr.Tab("Chat with Bookmarks"):
611
  gr.Markdown("""
612
+ ## πŸ’¬ **Chat with Bookmarks**
613
 
614
+ ### πŸ€– **How to Interact:**
615
 
616
+ 1. **✍️ Enter Your Query:**
617
+ - In the **"✍️ Ask about your bookmarks"** textbox, type your question or keyword related to your bookmarks. For example, "Do I have any bookmarks about GenerativeAI?"
618
 
619
+ 2. **πŸ“¨ Submit Your Query:**
620
+ - Click the **"πŸ“¨ Send"** button to submit your query.
621
 
622
+ 3. **πŸ“ˆ Receive AI-Driven Responses:**
623
+ - SmartMarks will analyze your query and provide relevant bookmarks that match your request, making it easier to find specific links without manual searching.
624
+ """)
625
 
626
+ with gr.Row():
627
+ chat_history_display = gr.Chatbot(label="πŸ—¨οΈ Chat History")
628
+ with gr.Column(scale=1):
629
+ chat_input = gr.Textbox(
630
+ label="✍️ Ask about your bookmarks",
631
+ placeholder="e.g., Do I have any bookmarks about GenerativeAI?",
632
+ lines=1,
633
+ interactive=True
634
+ )
635
+ chat_button = gr.Button("πŸ“¨ Send")
636
+
637
+ # When user presses Enter in chat_input
638
+ chat_input.submit(
639
+ chatbot_response,
640
+ inputs=[chat_input, state_bookmarks],
641
+ outputs=chat_history_display
642
+ )
643
 
644
+ # When user clicks Send button
645
  chat_button.click(
646
  chatbot_response,
647
+ inputs=[chat_input, state_bookmarks],
648
+ outputs=chat_history_display
649
  )
650
 
651
  # Manage Bookmarks Tab
652
  with gr.Tab("Manage Bookmarks"):
653
  gr.Markdown("""
654
+ ## πŸ› οΈ **Manage Bookmarks**
655
 
656
+ ### πŸ—‚οΈ **Features:**
657
 
658
+ 1. **πŸ‘οΈ View Bookmarks:**
659
+ - All your processed bookmarks are displayed here with their respective categories and summaries.
660
 
661
+ 2. **βœ… Select Bookmarks:**
662
+ - Use the checkboxes next to each bookmark to select one, multiple, or all bookmarks you wish to manage.
663
 
664
+ 3. **πŸ—‘οΈ Delete Selected Bookmarks:**
665
+ - After selecting the desired bookmarks, click the **"πŸ—‘οΈ Delete Selected Bookmarks"** button to remove them from your list.
666
 
667
+ 4. **✏️ Edit Categories:**
668
+ - Select the bookmarks you want to re-categorize.
669
+ - Choose a new category from the dropdown menu labeled **"πŸ†• New Category"**.
670
+ - Click the **"✏️ Edit Category of Selected Bookmarks"** button to update their categories.
671
 
672
+ 5. **πŸ’Ύ Export Bookmarks:**
673
+ - Click the **"πŸ’Ύ Export Bookmarks"** button to download your updated bookmarks as an HTML file.
674
+ - This file can be uploaded back to your browser to reflect the changes made within SmartMarks.
675
+ """)
676
 
677
  manage_output = gr.Textbox(label="πŸ”„ Manage Output", interactive=False)
 
 
 
678
  new_category_input = gr.Dropdown(label="πŸ†• New Category", choices=CATEGORIES, value="Uncategorized")
679
  with gr.Row():
680
  delete_button = gr.Button("πŸ—‘οΈ Delete Selected Bookmarks")
681
  edit_category_button = gr.Button("✏️ Edit Category of Selected Bookmarks")
682
  export_button = gr.Button("πŸ’Ύ Export Bookmarks")
683
  download_link = gr.HTML(label="πŸ“₯ Download Exported Bookmarks")
684
+ refresh_button = gr.Button("πŸ”„ Refresh Bookmarks")
685
 
686
  # Define button actions
687
  delete_button.click(
688
  delete_selected_bookmarks,
689
+ inputs=[bookmark_selector, state_bookmarks],
690
+ outputs=[manage_output, bookmark_selector, bookmark_display_manage, state_bookmarks]
691
  )
692
 
693
  edit_category_button.click(
694
  edit_selected_bookmarks_category,
695
+ inputs=[bookmark_selector, new_category_input, state_bookmarks],
696
+ outputs=[manage_output, bookmark_selector, bookmark_display_manage, state_bookmarks]
697
  )
698
 
699
  export_button.click(
700
  export_bookmarks,
701
+ inputs=[state_bookmarks],
702
  outputs=download_link
703
  )
704
 
705
+ refresh_button.click(
706
+ lambda bookmarks: (
707
+ [
708
+ f"{i+1}. {bookmark['title']} (Category: {bookmark['category']})" for i, bookmark in enumerate(bookmarks)
709
+ ],
710
+ display_bookmarks(bookmarks)
711
+ ),
712
+ inputs=[state_bookmarks],
713
+ outputs=[bookmark_selector, bookmark_display_manage]
714
  )
715
 
716
  logger.info("Launching Gradio app")