siddhartharya commited on
Commit
b47d5fe
Β·
verified Β·
1 Parent(s): 370367a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +118 -126
app.py CHANGED
@@ -193,8 +193,10 @@ def generate_summary(bookmark):
193
  bookmark['summary'] = bookmark.get('title', 'No summary available.')
194
  return bookmark
195
 
196
- # Function to parse bookmarks from HTML
197
  def parse_bookmarks(file_content):
 
 
 
198
  logger.info("Parsing bookmarks")
199
  try:
200
  soup = BeautifulSoup(file_content, 'html.parser')
@@ -210,8 +212,10 @@ def parse_bookmarks(file_content):
210
  logger.error("Error parsing bookmarks: %s", e)
211
  raise
212
 
213
- # Asynchronous function to fetch URL info
214
  async def fetch_url_info(session, bookmark):
 
 
 
215
  url = bookmark['url']
216
  if url in fetch_cache:
217
  bookmark.update(fetch_cache[url])
@@ -230,8 +234,7 @@ async def fetch_url_info(session, bookmark):
230
  else:
231
  bookmark['dead_link'] = False
232
  content = await response.text()
233
- bookmark['html_content'] = content # Store HTML content for summary generation
234
- soup = BeautifulSoup(content, 'html.parser')
235
  bookmark['description'] = '' # Will be set by generate_summary function
236
  logger.info(f"Fetched information for {url}")
237
  except Exception as e:
@@ -251,8 +254,10 @@ async def fetch_url_info(session, bookmark):
251
  }
252
  return bookmark
253
 
254
- # Asynchronous processing of bookmarks
255
  async def process_bookmarks_async(bookmarks_list):
 
 
 
256
  logger.info("Processing bookmarks asynchronously")
257
  try:
258
  async with aiohttp.ClientSession() as session:
@@ -266,8 +271,10 @@ async def process_bookmarks_async(bookmarks_list):
266
  logger.error(f"Error in asynchronous processing of bookmarks: {e}")
267
  raise
268
 
269
- # Assign category to a bookmark
270
  def assign_category(bookmark):
 
 
 
271
  if bookmark.get('dead_link'):
272
  bookmark['category'] = 'Dead Link'
273
  logger.info(f"Assigned category 'Dead Link' to bookmark: {bookmark.get('url')}")
@@ -314,8 +321,10 @@ def assign_category(bookmark):
314
  logger.info(f"No matching category found for bookmark: {bookmark.get('url')}")
315
  return bookmark
316
 
317
- # Vectorize summaries and build FAISS index
318
  def vectorize_and_index(bookmarks_list):
 
 
 
319
  logger.info("Vectorizing summaries and building FAISS index")
320
  try:
321
  summaries = [bookmark['summary'] for bookmark in bookmarks_list]
@@ -329,12 +338,14 @@ def vectorize_and_index(bookmarks_list):
329
  logger.error(f"Error in vectorizing and indexing: {e}")
330
  raise
331
 
332
- # Generate HTML display for bookmarks
333
  def display_bookmarks():
 
 
 
334
  logger.info("Generating HTML display for bookmarks")
335
  cards = ''
336
  for i, bookmark in enumerate(bookmarks):
337
- index = i + 1 # Start index at 1
338
  status = "❌ Dead Link" if bookmark.get('dead_link') else "βœ… Active"
339
  title = bookmark['title']
340
  url = bookmark['url']
@@ -342,7 +353,6 @@ def display_bookmarks():
342
  summary = bookmark.get('summary', '')
343
  category = bookmark.get('category', 'Uncategorized')
344
 
345
- # Apply inline styles using CSS variables
346
  if bookmark.get('dead_link'):
347
  card_style = "border: 2px solid var(--error-color);"
348
  text_style = "color: var(--error-color);"
@@ -365,35 +375,46 @@ def display_bookmarks():
365
  logger.info("HTML display generated")
366
  return cards
367
 
368
- # Process the uploaded file
369
  def process_uploaded_file(file):
 
 
 
 
 
 
 
 
 
 
370
  global bookmarks, faiss_index
371
  logger.info("Processing uploaded file")
 
372
  if file is None:
373
  logger.warning("No file uploaded")
374
- return "Please upload a bookmarks HTML file.", '', gr.update(choices=[]), display_bookmarks()
 
375
  try:
376
  file_content = file.decode('utf-8')
377
  except UnicodeDecodeError as e:
378
  logger.error(f"Error decoding the file: {e}")
379
- return "Error decoding the file. Please ensure it's a valid HTML file.", '', gr.update(choices=[]), display_bookmarks()
380
 
381
  try:
382
  bookmarks = parse_bookmarks(file_content)
383
  except Exception as e:
384
  logger.error(f"Error parsing bookmarks: {e}")
385
- return "Error parsing the bookmarks HTML file.", '', gr.update(choices=[]), display_bookmarks()
386
 
387
  if not bookmarks:
388
  logger.warning("No bookmarks found in the uploaded file")
389
- return "No bookmarks found in the uploaded file.", '', gr.update(choices=[]), display_bookmarks()
390
 
391
  # Asynchronously fetch bookmark info
392
  try:
393
  asyncio.run(process_bookmarks_async(bookmarks))
394
  except Exception as e:
395
  logger.error(f"Error processing bookmarks asynchronously: {e}")
396
- return "Error processing bookmarks.", '', gr.update(choices=[]), display_bookmarks()
397
 
398
  # Generate summaries and assign categories
399
  for bookmark in bookmarks:
@@ -404,73 +425,85 @@ def process_uploaded_file(file):
404
  faiss_index, embeddings = vectorize_and_index(bookmarks)
405
  except Exception as e:
406
  logger.error(f"Error building FAISS index: {e}")
407
- return "Error building search index.", '', gr.update(choices=[]), display_bookmarks()
408
 
409
  message = f"βœ… Successfully processed {len(bookmarks)} bookmarks."
410
  logger.info(message)
411
  bookmark_html = display_bookmarks()
412
 
413
- # Update bookmark_selector choices
414
- choices = [f"{i+1}. {bookmark['title']} (Category: {bookmark['category']})" for i, bookmark in enumerate(bookmarks)]
415
- bookmark_selector_update = gr.update(choices=choices, value=[])
416
 
417
- # Update bookmark_display_manage
418
- bookmark_display_manage_update = display_bookmarks()
419
-
420
- return message, bookmark_html, bookmark_selector_update, bookmark_display_manage_update
 
 
 
421
 
422
- # Delete selected bookmarks
423
  def delete_selected_bookmarks(selected_indices):
 
 
 
424
  global bookmarks, faiss_index
425
  if not selected_indices:
426
- return "⚠️ No bookmarks selected.", gr.update(choices=[]), display_bookmarks()
 
427
  indices = [int(s.split('.')[0])-1 for s in selected_indices]
428
  indices = sorted(indices, reverse=True)
429
  for idx in indices:
430
  if 0 <= idx < len(bookmarks):
431
  logger.info(f"Deleting bookmark at index {idx + 1}")
432
  bookmarks.pop(idx)
 
433
  if bookmarks:
434
  faiss_index, embeddings = vectorize_and_index(bookmarks)
435
  else:
436
  faiss_index = None
 
437
  message = "πŸ—‘οΈ Selected bookmarks deleted successfully."
438
  logger.info(message)
439
- # Update bookmark_selector choices
440
- choices = [f"{i+1}. {bookmark['title']} (Category: {bookmark['category']})" for i, bookmark in enumerate(bookmarks)]
441
- bookmark_selector_update = gr.update(choices=choices, value=[])
442
- # Update bookmarks display
443
  bookmarks_html = display_bookmarks()
 
444
  return message, bookmark_selector_update, bookmarks_html
445
 
446
- # Edit category of selected bookmarks
447
  def edit_selected_bookmarks_category(selected_indices, new_category):
 
 
 
448
  if not selected_indices:
449
- return "⚠️ No bookmarks selected.", '', gr.update()
450
  if not new_category:
451
- return "⚠️ No new category selected.", '', gr.update()
 
452
  indices = [int(s.split('.')[0])-1 for s in selected_indices]
453
  for idx in indices:
454
  if 0 <= idx < len(bookmarks):
455
  bookmarks[idx]['category'] = new_category
456
  logger.info(f"Updated category for bookmark {idx + 1} to {new_category}")
 
457
  message = "✏️ Category updated for selected bookmarks."
458
  logger.info(message)
459
- # Update bookmark_selector choices
460
- choices = [f"{i+1}. {bookmark['title']} (Category: {bookmark['category']})" for i, bookmark in enumerate(bookmarks)]
461
- bookmark_selector_update = gr.update(choices=choices, value=[])
462
- # Update bookmarks display
463
  bookmarks_html = display_bookmarks()
 
464
  return message, bookmark_selector_update, bookmarks_html
465
 
466
- # Export bookmarks to HTML
467
  def export_bookmarks():
 
 
 
468
  if not bookmarks:
469
  logger.warning("No bookmarks to export")
470
  return "⚠️ No bookmarks to export."
 
471
  try:
472
  logger.info("Exporting bookmarks to HTML")
473
- # Create an HTML content similar to the imported bookmarks file
474
  soup = BeautifulSoup("<!DOCTYPE NETSCAPE-Bookmark-file-1><Title>Bookmarks</Title><H1>Bookmarks</H1>", 'html.parser')
475
  dl = soup.new_tag('DL')
476
  for bookmark in bookmarks:
@@ -481,7 +514,6 @@ def export_bookmarks():
481
  dl.append(dt)
482
  soup.append(dl)
483
  html_content = str(soup)
484
- # Encode the HTML content to base64 for download
485
  b64 = base64.b64encode(html_content.encode()).decode()
486
  href = f'data:text/html;base64,{b64}'
487
  logger.info("Bookmarks exported successfully")
@@ -490,11 +522,13 @@ def export_bookmarks():
490
  logger.error(f"Error exporting bookmarks: {e}")
491
  return "⚠️ Error exporting bookmarks."
492
 
493
- # Chatbot response using Groq Cloud API
494
  def chatbot_response(user_query):
 
 
 
495
  if not GROQ_API_KEY:
496
  logger.warning("GROQ_API_KEY not set.")
497
- return "⚠️ API key not set. Please set the GROQ_API_KEY environment variable in the Hugging Face Space settings."
498
 
499
  if not bookmarks:
500
  logger.warning("No bookmarks available for chatbot")
@@ -503,26 +537,23 @@ def chatbot_response(user_query):
503
  logger.info(f"Chatbot received query: {user_query}")
504
 
505
  try:
506
- # Limit the number of bookmarks to prevent exceeding token limits
507
- max_bookmarks = 50 # Adjust as needed
508
  bookmark_data = ""
509
  for idx, bookmark in enumerate(bookmarks[:max_bookmarks]):
510
  bookmark_data += f"{idx+1}. Title: {bookmark['title']}\nURL: {bookmark['url']}\nSummary: {bookmark['summary']}\n\n"
511
 
512
- # Construct the prompt
513
  prompt = f"""
514
- You are an assistant that helps users find relevant bookmarks from their collection based on their queries.
515
 
516
- User Query:
517
- {user_query}
518
 
519
- Bookmarks:
520
- {bookmark_data}
521
 
522
- Please identify the most relevant bookmarks that match the user's query. Provide a concise list including the index, title, URL, and a brief summary.
523
- """
524
 
525
- # Call the Groq Cloud API via the OpenAI client
526
  response = openai.ChatCompletion.create(
527
  model='llama3-8b-8192',
528
  messages=[
@@ -533,7 +564,6 @@ Please identify the most relevant bookmarks that match the user's query. Provide
533
  temperature=0.7,
534
  )
535
 
536
- # Extract the response text
537
  answer = response['choices'][0]['message']['content'].strip()
538
  logger.info("Chatbot response generated using Groq Cloud API")
539
  return answer
@@ -541,11 +571,12 @@ Please identify the most relevant bookmarks that match the user's query. Provide
541
  except Exception as e:
542
  error_message = f"⚠️ Error processing your query: {str(e)}"
543
  logger.error(error_message)
544
- print(error_message) # Ensure error appears in Hugging Face Spaces logs
545
  return error_message
546
 
547
- # Build the Gradio app
548
  def build_app():
 
 
 
549
  try:
550
  logger.info("Building Gradio app")
551
  with gr.Blocks(css="app.css") as demo:
@@ -553,7 +584,7 @@ def build_app():
553
  gr.Markdown("""
554
  # πŸ“š SmartMarks - AI Browser Bookmarks Manager
555
 
556
- 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.
557
 
558
  ---
559
 
@@ -564,8 +595,6 @@ def build_app():
564
  1. **πŸ“‚ Upload and Process Bookmarks:** Import your existing bookmarks and let SmartMarks analyze and categorize them for you.
565
  2. **πŸ’¬ Chat with Bookmarks:** Interact with your bookmarks using natural language queries to find relevant links effortlessly.
566
  3. **πŸ› οΈ Manage Bookmarks:** View, edit, delete, and export your bookmarks with ease.
567
-
568
- Navigate through the tabs to explore each feature in detail.
569
  """)
570
 
571
  # Upload and Process Bookmarks Tab
@@ -573,33 +602,21 @@ def build_app():
573
  gr.Markdown("""
574
  ## πŸ“‚ **Upload and Process Bookmarks**
575
 
576
- ### πŸ“ **Steps to Upload and Process:**
577
-
578
- 1. **πŸ”½ Upload Bookmarks File:**
579
- - Click on the **"Upload Bookmarks HTML File"** button.
580
- - Select your browser's exported bookmarks HTML file from your device.
581
-
582
- 2. **βš™οΈ Process Bookmarks:**
583
- - After uploading, click on the **"Process Bookmarks"** button.
584
- - SmartMarks will parse your bookmarks, fetch additional information, generate summaries, and categorize each link based on predefined categories.
585
-
586
- 3. **πŸ“„ View Processed Bookmarks:**
587
- - Once processing is complete, your bookmarks will be displayed in an organized and visually appealing format below.
588
  """)
589
 
590
  upload = gr.File(label="πŸ“ Upload Bookmarks HTML File", type='binary')
591
  process_button = gr.Button("βš™οΈ Process Bookmarks")
592
  output_text = gr.Textbox(label="βœ… Output", interactive=False)
593
- bookmark_display = gr.HTML(label="πŸ“„ Bookmarks")
594
-
595
- # Initialize Manage Bookmarks components
596
- bookmark_selector = gr.CheckboxGroup(label="βœ… Select Bookmarks", choices=[])
597
- bookmark_display_manage = gr.HTML(label="πŸ“„ Manage Bookmarks Display")
598
 
599
  process_button.click(
600
  process_uploaded_file,
601
  inputs=upload,
602
- outputs=[output_text, bookmark_display, bookmark_selector, bookmark_display_manage]
603
  )
604
 
605
  # Chat with Bookmarks Tab
@@ -607,21 +624,15 @@ def build_app():
607
  gr.Markdown("""
608
  ## πŸ’¬ **Chat with Bookmarks**
609
 
610
- ### πŸ€– **How to Interact:**
611
-
612
- 1. **✍️ Enter Your Query:**
613
- - 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?"
614
-
615
- 2. **πŸ“¨ Submit Your Query:**
616
- - Click the **"Send"** button to submit your query.
617
-
618
- 3. **πŸ“ˆ Receive AI-Driven Responses:**
619
- - SmartMarks will analyze your query and provide relevant bookmarks that match your request, making it easier to find specific links without manual searching.
620
  """)
621
 
622
- user_input = gr.Textbox(label="✍️ Ask about your bookmarks", placeholder="e.g., Do I have any bookmarks about GenerativeAI?")
623
- chat_output = gr.Textbox(label="πŸ’¬ Chatbot Response", interactive=False)
 
 
624
  chat_button = gr.Button("πŸ“¨ Send")
 
625
 
626
  chat_button.click(
627
  chatbot_response,
@@ -634,39 +645,28 @@ def build_app():
634
  gr.Markdown("""
635
  ## πŸ› οΈ **Manage Bookmarks**
636
 
637
- ### πŸ—‚οΈ **Features:**
638
-
639
- 1. **πŸ‘οΈ View Bookmarks:**
640
- - All your processed bookmarks are displayed here with their respective categories and summaries.
641
-
642
- 2. **βœ… Select Bookmarks:**
643
- - Use the checkboxes next to each bookmark to select one, multiple, or all bookmarks you wish to manage.
644
-
645
- 3. **πŸ—‘οΈ Delete Selected Bookmarks:**
646
- - After selecting the desired bookmarks, click the **"Delete Selected Bookmarks"** button to remove them from your list.
647
-
648
- 4. **✏️ Edit Categories:**
649
- - Select the bookmarks you want to re-categorize.
650
- - Choose a new category from the dropdown menu labeled **"New Category"**.
651
- - Click the **"Edit Category of Selected Bookmarks"** button to update their categories.
652
-
653
- 5. **πŸ’Ύ Export Bookmarks:**
654
- - Click the **"Export Bookmarks"** button to download your updated bookmarks as an HTML file.
655
- - This file can be uploaded back to your browser to reflect the changes made within SmartMarks.
656
  """)
657
 
658
- manage_output = gr.Textbox(label="πŸ”„ Manage Output", interactive=False)
659
- bookmark_display_manage = gr.HTML(label="πŸ“„ Manage Bookmarks Display")
660
- bookmark_selector = gr.CheckboxGroup(label="βœ… Select Bookmarks", choices=[])
 
 
 
 
 
 
 
661
 
662
- new_category_input = gr.Dropdown(label="πŸ†• New Category", choices=CATEGORIES, value="Uncategorized")
663
  with gr.Row():
664
- delete_button = gr.Button("πŸ—‘οΈ Delete Selected Bookmarks")
665
- edit_category_button = gr.Button("✏️ Edit Category of Selected Bookmarks")
666
- export_button = gr.Button("πŸ’Ύ Export Bookmarks")
667
- download_link = gr.HTML(label="πŸ“₯ Download Exported Bookmarks")
 
 
668
 
669
- # Define button actions
670
  delete_button.click(
671
  delete_selected_bookmarks,
672
  inputs=bookmark_selector,
@@ -675,23 +675,15 @@ def build_app():
675
 
676
  edit_category_button.click(
677
  edit_selected_bookmarks_category,
678
- inputs=[bookmark_selector, new_category_input],
679
  outputs=[manage_output, bookmark_selector, bookmark_display_manage]
680
  )
681
 
682
  export_button.click(
683
  export_bookmarks,
684
- inputs=None,
685
  outputs=download_link
686
  )
687
 
688
- # Initialize display after processing bookmarks
689
- process_button.click(
690
- process_uploaded_file,
691
- inputs=upload,
692
- outputs=[output_text, bookmark_display, bookmark_selector, bookmark_display_manage]
693
- )
694
-
695
  logger.info("Launching Gradio app")
696
  demo.launch(debug=True)
697
  except Exception as e:
 
193
  bookmark['summary'] = bookmark.get('title', 'No summary available.')
194
  return bookmark
195
 
 
196
  def parse_bookmarks(file_content):
197
+ """
198
+ Parse bookmarks from HTML file.
199
+ """
200
  logger.info("Parsing bookmarks")
201
  try:
202
  soup = BeautifulSoup(file_content, 'html.parser')
 
212
  logger.error("Error parsing bookmarks: %s", e)
213
  raise
214
 
 
215
  async def fetch_url_info(session, bookmark):
216
+ """
217
+ Fetch information about a URL asynchronously.
218
+ """
219
  url = bookmark['url']
220
  if url in fetch_cache:
221
  bookmark.update(fetch_cache[url])
 
234
  else:
235
  bookmark['dead_link'] = False
236
  content = await response.text()
237
+ bookmark['html_content'] = content
 
238
  bookmark['description'] = '' # Will be set by generate_summary function
239
  logger.info(f"Fetched information for {url}")
240
  except Exception as e:
 
254
  }
255
  return bookmark
256
 
 
257
  async def process_bookmarks_async(bookmarks_list):
258
+ """
259
+ Process all bookmarks asynchronously.
260
+ """
261
  logger.info("Processing bookmarks asynchronously")
262
  try:
263
  async with aiohttp.ClientSession() as session:
 
271
  logger.error(f"Error in asynchronous processing of bookmarks: {e}")
272
  raise
273
 
 
274
  def assign_category(bookmark):
275
+ """
276
+ Assign a category to a bookmark based on its content.
277
+ """
278
  if bookmark.get('dead_link'):
279
  bookmark['category'] = 'Dead Link'
280
  logger.info(f"Assigned category 'Dead Link' to bookmark: {bookmark.get('url')}")
 
321
  logger.info(f"No matching category found for bookmark: {bookmark.get('url')}")
322
  return bookmark
323
 
 
324
  def vectorize_and_index(bookmarks_list):
325
+ """
326
+ Create vector embeddings for bookmarks and build FAISS index.
327
+ """
328
  logger.info("Vectorizing summaries and building FAISS index")
329
  try:
330
  summaries = [bookmark['summary'] for bookmark in bookmarks_list]
 
338
  logger.error(f"Error in vectorizing and indexing: {e}")
339
  raise
340
 
 
341
  def display_bookmarks():
342
+ """
343
+ Generate HTML display for bookmarks.
344
+ """
345
  logger.info("Generating HTML display for bookmarks")
346
  cards = ''
347
  for i, bookmark in enumerate(bookmarks):
348
+ index = i + 1
349
  status = "❌ Dead Link" if bookmark.get('dead_link') else "βœ… Active"
350
  title = bookmark['title']
351
  url = bookmark['url']
 
353
  summary = bookmark.get('summary', '')
354
  category = bookmark.get('category', 'Uncategorized')
355
 
 
356
  if bookmark.get('dead_link'):
357
  card_style = "border: 2px solid var(--error-color);"
358
  text_style = "color: var(--error-color);"
 
375
  logger.info("HTML display generated")
376
  return cards
377
 
 
378
  def process_uploaded_file(file):
379
+ """
380
+ Process the uploaded bookmarks file.
381
+ """
382
+ global bookmarks, faiss_index
383
+ logger.info("Processing uploade
384
+
385
+ def process_uploaded_file(file):
386
+ """
387
+ Process the uploaded bookmarks file.
388
+ """
389
  global bookmarks, faiss_index
390
  logger.info("Processing uploaded file")
391
+
392
  if file is None:
393
  logger.warning("No file uploaded")
394
+ return "Please upload a bookmarks HTML file.", ''
395
+
396
  try:
397
  file_content = file.decode('utf-8')
398
  except UnicodeDecodeError as e:
399
  logger.error(f"Error decoding the file: {e}")
400
+ return "Error decoding the file. Please ensure it's a valid HTML file.", ''
401
 
402
  try:
403
  bookmarks = parse_bookmarks(file_content)
404
  except Exception as e:
405
  logger.error(f"Error parsing bookmarks: {e}")
406
+ return "Error parsing the bookmarks HTML file.", ''
407
 
408
  if not bookmarks:
409
  logger.warning("No bookmarks found in the uploaded file")
410
+ return "No bookmarks found in the uploaded file.", ''
411
 
412
  # Asynchronously fetch bookmark info
413
  try:
414
  asyncio.run(process_bookmarks_async(bookmarks))
415
  except Exception as e:
416
  logger.error(f"Error processing bookmarks asynchronously: {e}")
417
+ return "Error processing bookmarks.", ''
418
 
419
  # Generate summaries and assign categories
420
  for bookmark in bookmarks:
 
425
  faiss_index, embeddings = vectorize_and_index(bookmarks)
426
  except Exception as e:
427
  logger.error(f"Error building FAISS index: {e}")
428
+ return "Error building search index.", ''
429
 
430
  message = f"βœ… Successfully processed {len(bookmarks)} bookmarks."
431
  logger.info(message)
432
  bookmark_html = display_bookmarks()
433
 
434
+ return message, bookmark_html
 
 
435
 
436
+ def update_bookmark_selector():
437
+ """
438
+ Update the bookmark selector choices for the Manage Bookmarks tab.
439
+ """
440
+ choices = [f"{i+1}. {bookmark['title']} (Category: {bookmark['category']})"
441
+ for i, bookmark in enumerate(bookmarks)]
442
+ return gr.update(choices=choices, value=[])
443
 
 
444
  def delete_selected_bookmarks(selected_indices):
445
+ """
446
+ Delete selected bookmarks.
447
+ """
448
  global bookmarks, faiss_index
449
  if not selected_indices:
450
+ return "⚠️ No bookmarks selected.", gr.update(choices=[]), ''
451
+
452
  indices = [int(s.split('.')[0])-1 for s in selected_indices]
453
  indices = sorted(indices, reverse=True)
454
  for idx in indices:
455
  if 0 <= idx < len(bookmarks):
456
  logger.info(f"Deleting bookmark at index {idx + 1}")
457
  bookmarks.pop(idx)
458
+
459
  if bookmarks:
460
  faiss_index, embeddings = vectorize_and_index(bookmarks)
461
  else:
462
  faiss_index = None
463
+
464
  message = "πŸ—‘οΈ Selected bookmarks deleted successfully."
465
  logger.info(message)
466
+
467
+ # Update display and selector
468
+ bookmark_selector_update = update_bookmark_selector()
 
469
  bookmarks_html = display_bookmarks()
470
+
471
  return message, bookmark_selector_update, bookmarks_html
472
 
 
473
  def edit_selected_bookmarks_category(selected_indices, new_category):
474
+ """
475
+ Edit category of selected bookmarks.
476
+ """
477
  if not selected_indices:
478
+ return "⚠️ No bookmarks selected.", gr.update(choices=[]), ''
479
  if not new_category:
480
+ return "⚠️ No new category selected.", gr.update(choices=[]), ''
481
+
482
  indices = [int(s.split('.')[0])-1 for s in selected_indices]
483
  for idx in indices:
484
  if 0 <= idx < len(bookmarks):
485
  bookmarks[idx]['category'] = new_category
486
  logger.info(f"Updated category for bookmark {idx + 1} to {new_category}")
487
+
488
  message = "✏️ Category updated for selected bookmarks."
489
  logger.info(message)
490
+
491
+ # Update display and selector
492
+ bookmark_selector_update = update_bookmark_selector()
 
493
  bookmarks_html = display_bookmarks()
494
+
495
  return message, bookmark_selector_update, bookmarks_html
496
 
 
497
  def export_bookmarks():
498
+ """
499
+ Export bookmarks to HTML file.
500
+ """
501
  if not bookmarks:
502
  logger.warning("No bookmarks to export")
503
  return "⚠️ No bookmarks to export."
504
+
505
  try:
506
  logger.info("Exporting bookmarks to HTML")
 
507
  soup = BeautifulSoup("<!DOCTYPE NETSCAPE-Bookmark-file-1><Title>Bookmarks</Title><H1>Bookmarks</H1>", 'html.parser')
508
  dl = soup.new_tag('DL')
509
  for bookmark in bookmarks:
 
514
  dl.append(dt)
515
  soup.append(dl)
516
  html_content = str(soup)
 
517
  b64 = base64.b64encode(html_content.encode()).decode()
518
  href = f'data:text/html;base64,{b64}'
519
  logger.info("Bookmarks exported successfully")
 
522
  logger.error(f"Error exporting bookmarks: {e}")
523
  return "⚠️ Error exporting bookmarks."
524
 
 
525
  def chatbot_response(user_query):
526
+ """
527
+ Generate chatbot response using Groq Cloud API.
528
+ """
529
  if not GROQ_API_KEY:
530
  logger.warning("GROQ_API_KEY not set.")
531
+ return "⚠️ API key not set. Please set the GROQ_API_KEY environment variable."
532
 
533
  if not bookmarks:
534
  logger.warning("No bookmarks available for chatbot")
 
537
  logger.info(f"Chatbot received query: {user_query}")
538
 
539
  try:
540
+ max_bookmarks = 50
 
541
  bookmark_data = ""
542
  for idx, bookmark in enumerate(bookmarks[:max_bookmarks]):
543
  bookmark_data += f"{idx+1}. Title: {bookmark['title']}\nURL: {bookmark['url']}\nSummary: {bookmark['summary']}\n\n"
544
 
 
545
  prompt = f"""
546
+ You are an assistant that helps users find relevant bookmarks from their collection based on their queries.
547
 
548
+ User Query:
549
+ {user_query}
550
 
551
+ Bookmarks:
552
+ {bookmark_data}
553
 
554
+ Please identify the most relevant bookmarks that match the user's query. Provide a concise list including the index, title, URL, and a brief summary.
555
+ """
556
 
 
557
  response = openai.ChatCompletion.create(
558
  model='llama3-8b-8192',
559
  messages=[
 
564
  temperature=0.7,
565
  )
566
 
 
567
  answer = response['choices'][0]['message']['content'].strip()
568
  logger.info("Chatbot response generated using Groq Cloud API")
569
  return answer
 
571
  except Exception as e:
572
  error_message = f"⚠️ Error processing your query: {str(e)}"
573
  logger.error(error_message)
 
574
  return error_message
575
 
 
576
  def build_app():
577
+ """
578
+ Build and launch the Gradio app.
579
+ """
580
  try:
581
  logger.info("Building Gradio app")
582
  with gr.Blocks(css="app.css") as demo:
 
584
  gr.Markdown("""
585
  # πŸ“š SmartMarks - AI Browser Bookmarks Manager
586
 
587
+ Welcome to **SmartMarks**, your intelligent assistant for managing browser bookmarks. SmartMarks leverages AI to help you organize, search, and interact with your bookmarks seamlessly.
588
 
589
  ---
590
 
 
595
  1. **πŸ“‚ Upload and Process Bookmarks:** Import your existing bookmarks and let SmartMarks analyze and categorize them for you.
596
  2. **πŸ’¬ Chat with Bookmarks:** Interact with your bookmarks using natural language queries to find relevant links effortlessly.
597
  3. **πŸ› οΈ Manage Bookmarks:** View, edit, delete, and export your bookmarks with ease.
 
 
598
  """)
599
 
600
  # Upload and Process Bookmarks Tab
 
602
  gr.Markdown("""
603
  ## πŸ“‚ **Upload and Process Bookmarks**
604
 
605
+ ### πŸ“ **Steps:**
606
+ 1. Click on the "Upload Bookmarks HTML File" button
607
+ 2. Select your bookmarks file
608
+ 3. Click "Process Bookmarks" to analyze and organize your bookmarks
 
 
 
 
 
 
 
 
609
  """)
610
 
611
  upload = gr.File(label="πŸ“ Upload Bookmarks HTML File", type='binary')
612
  process_button = gr.Button("βš™οΈ Process Bookmarks")
613
  output_text = gr.Textbox(label="βœ… Output", interactive=False)
614
+ bookmark_display = gr.HTML(label="πŸ“„ Processed Bookmarks")
 
 
 
 
615
 
616
  process_button.click(
617
  process_uploaded_file,
618
  inputs=upload,
619
+ outputs=[output_text, bookmark_display]
620
  )
621
 
622
  # Chat with Bookmarks Tab
 
624
  gr.Markdown("""
625
  ## πŸ’¬ **Chat with Bookmarks**
626
 
627
+ Ask questions about your bookmarks and get relevant results.
 
 
 
 
 
 
 
 
 
628
  """)
629
 
630
+ user_input = gr.Textbox(
631
+ label="✍️ Ask about your bookmarks",
632
+ placeholder="e.g., Do I have any bookmarks about AI?"
633
+ )
634
  chat_button = gr.Button("πŸ“¨ Send")
635
+ chat_output = gr.Textbox(label="πŸ’¬ Response", interactive=False)
636
 
637
  chat_button.click(
638
  chatbot_response,
 
645
  gr.Markdown("""
646
  ## πŸ› οΈ **Manage Bookmarks**
647
 
648
+ Select bookmarks to delete or edit their categories.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
649
  """)
650
 
651
+ manage_output = gr.Textbox(label="πŸ”„ Status", interactive=False)
652
+ bookmark_selector = gr.CheckboxGroup(
653
+ label="βœ… Select Bookmarks",
654
+ choices=[]
655
+ )
656
+ new_category = gr.Dropdown(
657
+ label="πŸ†• New Category",
658
+ choices=CATEGORIES,
659
+ value="Uncategorized"
660
+ )
661
 
 
662
  with gr.Row():
663
+ delete_button = gr.Button("πŸ—‘οΈ Delete Selected")
664
+ edit_category_button = gr.Button("✏️ Edit Category")
665
+ export_button = gr.Button("πŸ’Ύ Export")
666
+
667
+ bookmark_display_manage = gr.HTML(label="πŸ“„ Bookmarks")
668
+ download_link = gr.HTML(label="πŸ“₯ Download")
669
 
 
670
  delete_button.click(
671
  delete_selected_bookmarks,
672
  inputs=bookmark_selector,
 
675
 
676
  edit_category_button.click(
677
  edit_selected_bookmarks_category,
678
+ inputs=[bookmark_selector, new_category],
679
  outputs=[manage_output, bookmark_selector, bookmark_display_manage]
680
  )
681
 
682
  export_button.click(
683
  export_bookmarks,
 
684
  outputs=download_link
685
  )
686
 
 
 
 
 
 
 
 
687
  logger.info("Launching Gradio app")
688
  demo.launch(debug=True)
689
  except Exception as e: