siddhartharya commited on
Commit
c425950
β€’
1 Parent(s): 8ba26a5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +187 -82
app.py CHANGED
@@ -19,6 +19,10 @@ import threading
19
  # Import OpenAI library
20
  import openai
21
 
 
 
 
 
22
  # Set up logging to output to the console
23
  logger = logging.getLogger(__name__)
24
  logger.setLevel(logging.INFO)
@@ -34,8 +38,8 @@ console_handler.setFormatter(formatter)
34
  # Add the handler to the logger
35
  logger.addHandler(console_handler)
36
 
37
- # Initialize models and variables
38
- logger.info("Initializing models and variables")
39
  embedding_model = SentenceTransformer('all-MiniLM-L6-v2')
40
  faiss_index = None
41
  bookmarks = []
@@ -77,7 +81,11 @@ if not GROQ_API_KEY:
77
  logger.error("GROQ_API_KEY environment variable not set.")
78
 
79
  openai.api_key = GROQ_API_KEY
80
- openai.api_base = "https://api.groq.com/openai/v1"
 
 
 
 
81
 
82
  def extract_main_content(soup):
83
  """
@@ -159,12 +167,20 @@ def generate_summary_and_assign_category(bookmark):
159
 
160
  while retry_count < max_retries:
161
  try:
 
 
 
 
 
 
 
 
 
 
 
 
162
  html_content = bookmark.get('html_content', '')
163
-
164
- # Get the HTML soup object from the bookmark
165
  soup = BeautifulSoup(html_content, 'html.parser')
166
-
167
- # Extract metadata and main content
168
  metadata = get_page_metadata(soup)
169
  main_content = extract_main_content(soup)
170
 
@@ -226,14 +242,14 @@ Category: [One category]
226
  return len(text) / 4 # Approximate token estimation
227
 
228
  prompt_tokens = estimate_tokens(prompt)
229
- max_tokens = 150 # Reduced from 200
230
  total_tokens = prompt_tokens + max_tokens
231
 
232
  # Calculate required delay
233
- tokens_per_minute = 60000 # Adjust based on your rate limit
234
  tokens_per_second = tokens_per_minute / 60
235
  required_delay = total_tokens / tokens_per_second
236
- sleep_time = max(required_delay, 1)
237
 
238
  # Call the LLM via Groq Cloud API
239
  response = openai.ChatCompletion.create(
@@ -244,6 +260,7 @@ Category: [One category]
244
  max_tokens=int(max_tokens),
245
  temperature=0.5,
246
  )
 
247
  content = response['choices'][0]['message']['content'].strip()
248
  if not content:
249
  raise ValueError("Empty response received from the model.")
@@ -281,7 +298,7 @@ Category: [One category]
281
  except openai.error.RateLimitError as e:
282
  retry_count += 1
283
  wait_time = int(e.headers.get("Retry-After", 5))
284
- logger.warning(f"Rate limit reached. Waiting for {wait_time} seconds before retrying...")
285
  time.sleep(wait_time)
286
  except Exception as e:
287
  logger.error(f"Error generating summary and assigning category: {e}", exc_info=True)
@@ -377,6 +394,7 @@ def vectorize_and_index(bookmarks_list):
377
  """
378
  Create vector embeddings for bookmarks and build FAISS index with ID mapping.
379
  """
 
380
  logger.info("Vectorizing summaries and building FAISS index")
381
  try:
382
  summaries = [bookmark['summary'] for bookmark in bookmarks_list]
@@ -386,6 +404,7 @@ def vectorize_and_index(bookmarks_list):
386
  # Assign unique IDs to each bookmark
387
  ids = np.array([bookmark['id'] for bookmark in bookmarks_list], dtype=np.int64)
388
  index.add_with_ids(np.array(embeddings).astype('float32'), ids)
 
389
  logger.info("FAISS index built successfully with IDs")
390
  return index
391
  except Exception as e:
@@ -441,7 +460,7 @@ def display_bookmarks():
441
  logger.info("HTML display generated")
442
  return cards
443
 
444
- def process_uploaded_file(file):
445
  """
446
  Process the uploaded bookmarks file.
447
  """
@@ -450,23 +469,23 @@ def process_uploaded_file(file):
450
 
451
  if file is None:
452
  logger.warning("No file uploaded")
453
- return "Please upload a bookmarks HTML file.", '', gr.update(choices=[]), display_bookmarks()
454
 
455
  try:
456
  file_content = file.decode('utf-8')
457
  except UnicodeDecodeError as e:
458
  logger.error(f"Error decoding the file: {e}", exc_info=True)
459
- return "Error decoding the file. Please ensure it's a valid HTML file.", '', gr.update(choices=[]), display_bookmarks()
460
 
461
  try:
462
  bookmarks = parse_bookmarks(file_content)
463
  except Exception as e:
464
  logger.error(f"Error parsing bookmarks: {e}", exc_info=True)
465
- return "Error parsing the bookmarks HTML file.", '', gr.update(choices=[]), display_bookmarks()
466
 
467
  if not bookmarks:
468
  logger.warning("No bookmarks found in the uploaded file")
469
- return "No bookmarks found in the uploaded file.", '', gr.update(choices=[]), display_bookmarks()
470
 
471
  # Assign unique IDs to bookmarks
472
  for idx, bookmark in enumerate(bookmarks):
@@ -474,19 +493,19 @@ def process_uploaded_file(file):
474
 
475
  # Fetch bookmark info concurrently
476
  logger.info("Fetching URL info concurrently")
477
- with ThreadPoolExecutor(max_workers=20) as executor:
478
  executor.map(fetch_url_info, bookmarks)
479
 
480
  # Process bookmarks concurrently with LLM calls
481
  logger.info("Processing bookmarks with LLM concurrently")
482
- with ThreadPoolExecutor(max_workers=5) as executor:
483
  executor.map(generate_summary_and_assign_category, bookmarks)
484
 
485
  try:
486
  faiss_index = vectorize_and_index(bookmarks)
487
  except Exception as e:
488
  logger.error(f"Error building FAISS index: {e}", exc_info=True)
489
- return "Error building search index.", '', gr.update(choices=[]), display_bookmarks()
490
 
491
  message = f"βœ… Successfully processed {len(bookmarks)} bookmarks."
492
  logger.info(message)
@@ -496,9 +515,12 @@ def process_uploaded_file(file):
496
  choices = [f"{i+1}. {bookmark['title']} (Category: {bookmark['category']})"
497
  for i, bookmark in enumerate(bookmarks)]
498
 
499
- return message, bookmark_html, gr.update(choices=choices), bookmark_html
 
 
 
500
 
501
- def delete_selected_bookmarks(selected_indices):
502
  """
503
  Delete selected bookmarks and remove their vectors from the FAISS index.
504
  """
@@ -529,16 +551,19 @@ def delete_selected_bookmarks(selected_indices):
529
  choices = [f"{i+1}. {bookmark['title']} (Category: {bookmark['category']})"
530
  for i, bookmark in enumerate(bookmarks)]
531
 
 
 
 
532
  return message, gr.update(choices=choices), display_bookmarks()
533
 
534
- def edit_selected_bookmarks_category(selected_indices, new_category):
535
  """
536
  Edit category of selected bookmarks.
537
  """
538
  if not selected_indices:
539
- return "⚠️ No bookmarks selected.", gr.update(choices=[]), display_bookmarks()
540
  if not new_category:
541
- return "⚠️ No new category selected.", gr.update(choices=[]), display_bookmarks()
542
 
543
  indices = [int(s.split('.')[0])-1 for s in selected_indices]
544
  for idx in indices:
@@ -553,7 +578,10 @@ def edit_selected_bookmarks_category(selected_indices, new_category):
553
  choices = [f"{i+1}. {bookmark['title']} (Category: {bookmark['category']})"
554
  for i, bookmark in enumerate(bookmarks)]
555
 
556
- return message, gr.update(choices=choices), display_bookmarks()
 
 
 
557
 
558
  def export_bookmarks():
559
  """
@@ -591,16 +619,25 @@ def chatbot_response(user_query, chat_history):
591
  """
592
  if not bookmarks or faiss_index is None:
593
  logger.warning("No bookmarks available for chatbot")
594
- chat_history.append((user_query, "⚠️ No bookmarks available. Please upload and process your bookmarks first."))
595
  return chat_history
596
 
597
  logger.info(f"Chatbot received query: {user_query}")
598
 
599
  try:
600
- # Encode the user query
 
 
 
 
 
 
 
 
 
 
 
601
  query_vector = embedding_model.encode([user_query]).astype('float32')
602
-
603
- # Search the FAISS index
604
  k = 5 # Number of results to return
605
  distances, ids = faiss_index.search(query_vector, k)
606
  ids = ids.flatten()
@@ -611,7 +648,7 @@ def chatbot_response(user_query, chat_history):
611
 
612
  if not matching_bookmarks:
613
  answer = "No relevant bookmarks found for your query."
614
- chat_history.append((user_query, answer))
615
  return chat_history
616
 
617
  # Format the response
@@ -638,11 +675,12 @@ Provide a concise and helpful response.
638
  total_tokens = prompt_tokens + max_tokens
639
 
640
  # Calculate required delay
641
- tokens_per_minute = 60000 # Adjust based on your rate limit
642
  tokens_per_second = tokens_per_minute / 60
643
  required_delay = total_tokens / tokens_per_second
644
- sleep_time = max(required_delay, 1)
645
 
 
646
  response = openai.ChatCompletion.create(
647
  model='llama-3.1-70b-versatile', # Using the specified model
648
  messages=[
@@ -651,12 +689,13 @@ Provide a concise and helpful response.
651
  max_tokens=int(max_tokens),
652
  temperature=0.7,
653
  )
 
654
  answer = response['choices'][0]['message']['content'].strip()
655
  logger.info("Chatbot response generated")
656
  time.sleep(sleep_time)
657
 
658
  # Append the interaction to chat history
659
- chat_history.append((user_query, answer))
660
  return chat_history
661
 
662
  except openai.error.RateLimitError as e:
@@ -667,7 +706,7 @@ Provide a concise and helpful response.
667
  except Exception as e:
668
  error_message = f"⚠️ Error processing your query: {str(e)}"
669
  logger.error(error_message, exc_info=True)
670
- chat_history.append((user_query, error_message))
671
  return chat_history
672
 
673
  def build_app():
@@ -677,53 +716,119 @@ def build_app():
677
  try:
678
  logger.info("Building Gradio app")
679
  with gr.Blocks(css="app.css") as demo:
 
 
 
680
  # General Overview
681
  gr.Markdown("""
682
- # πŸ“š SmartMarks - AI Browser Bookmarks Manager
683
- Welcome to **SmartMarks**, your intelligent assistant for managing browser bookmarks. SmartMarks leverages AI to help you organize, search, and interact with your bookmarks seamlessly.
684
- ---
685
- ## πŸš€ **How to Use SmartMarks**
686
- SmartMarks is divided into three main sections:
687
- 1. **πŸ“‚ Upload and Process Bookmarks:** Import your existing bookmarks and let SmartMarks analyze and categorize them for you.
688
- 2. **πŸ’¬ Chat with Bookmarks:** Interact with your bookmarks using natural language queries to find relevant links effortlessly.
689
- 3. **πŸ› οΈ Manage Bookmarks:** View, edit, delete, and export your bookmarks with ease.
690
- """)
 
 
 
 
 
 
 
691
 
692
  # Upload and Process Bookmarks Tab
693
  with gr.Tab("Upload and Process Bookmarks"):
694
  gr.Markdown("""
695
- ## πŸ“‚ **Upload and Process Bookmarks**
696
- ### πŸ“ **Steps:**
697
- 1. Click on the "Upload Bookmarks HTML File" button
698
- 2. Select your bookmarks file
699
- 3. Click "Process Bookmarks" to analyze and organize your bookmarks
700
- """)
 
 
 
 
 
 
 
 
 
701
 
702
  upload = gr.File(label="πŸ“ Upload Bookmarks HTML File", type='binary')
703
  process_button = gr.Button("βš™οΈ Process Bookmarks")
704
  output_text = gr.Textbox(label="βœ… Output", interactive=False)
705
  bookmark_display = gr.HTML(label="πŸ“„ Processed Bookmarks")
706
 
 
 
 
 
 
 
707
  # Chat with Bookmarks Tab
708
  with gr.Tab("Chat with Bookmarks"):
709
  gr.Markdown("""
710
- ## πŸ’¬ **Chat with Bookmarks**
711
- Ask questions about your bookmarks and get relevant results.
712
- """)
713
 
714
- chatbot = gr.Chatbot(label="πŸ’¬ Chat with SmartMarks")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
715
  user_input = gr.Textbox(
716
  label="✍️ Ask about your bookmarks",
717
  placeholder="e.g., Do I have any bookmarks about AI?"
718
  )
719
  chat_button = gr.Button("πŸ“¨ Send")
720
 
 
 
 
 
 
 
721
  # Manage Bookmarks Tab
722
  with gr.Tab("Manage Bookmarks"):
723
  gr.Markdown("""
724
- ## πŸ› οΈ **Manage Bookmarks**
725
- Select bookmarks to delete or edit their categories.
726
- """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
727
 
728
  manage_output = gr.Textbox(label="πŸ”„ Status", interactive=False)
729
  bookmark_selector = gr.CheckboxGroup(
@@ -741,38 +846,38 @@ def build_app():
741
  delete_button = gr.Button("πŸ—‘οΈ Delete Selected")
742
  edit_category_button = gr.Button("✏️ Edit Category")
743
  export_button = gr.Button("πŸ’Ύ Export")
 
744
 
745
  download_link = gr.File(label="πŸ“₯ Download Exported Bookmarks")
746
 
747
- # Set up event handlers
748
- process_button.click(
749
- process_uploaded_file,
750
- inputs=upload,
751
- outputs=[output_text, bookmark_display, bookmark_selector, bookmark_display_manage]
752
- )
753
-
754
- chat_button.click(
755
- chatbot_response,
756
- inputs=[user_input, chatbot],
757
- outputs=chatbot
758
- )
759
 
760
- delete_button.click(
761
- delete_selected_bookmarks,
762
- inputs=bookmark_selector,
763
- outputs=[manage_output, bookmark_selector, bookmark_display_manage]
764
- )
765
 
766
- edit_category_button.click(
767
- edit_selected_bookmarks_category,
768
- inputs=[bookmark_selector, new_category],
769
- outputs=[manage_output, bookmark_selector, bookmark_display_manage]
770
- )
771
 
772
- export_button.click(
773
- export_bookmarks,
774
- outputs=download_link
775
- )
 
 
 
 
 
 
776
 
777
  logger.info("Launching Gradio app")
778
  demo.launch(debug=True)
 
19
  # Import OpenAI library
20
  import openai
21
 
22
+ # Suppress only the single warning from urllib3 needed.
23
+ import urllib3
24
+ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
25
+
26
  # Set up logging to output to the console
27
  logger = logging.getLogger(__name__)
28
  logger.setLevel(logging.INFO)
 
38
  # Add the handler to the logger
39
  logger.addHandler(console_handler)
40
 
41
+ # Initialize variables and models
42
+ logger.info("Initializing variables and models")
43
  embedding_model = SentenceTransformer('all-MiniLM-L6-v2')
44
  faiss_index = None
45
  bookmarks = []
 
81
  logger.error("GROQ_API_KEY environment variable not set.")
82
 
83
  openai.api_key = GROQ_API_KEY
84
+ openai.api_base = "https://api.groq.com/openai/v1" # Ensure this is the correct base URL
85
+
86
+ # Initialize global variables for rate limiting
87
+ api_lock = threading.Lock()
88
+ last_api_call_time = 0
89
 
90
  def extract_main_content(soup):
91
  """
 
167
 
168
  while retry_count < max_retries:
169
  try:
170
+ # Rate Limiting Logic
171
+ with api_lock:
172
+ global last_api_call_time
173
+ current_time = time.time()
174
+ elapsed = current_time - last_api_call_time
175
+ if elapsed < 2:
176
+ sleep_duration = 2 - elapsed
177
+ logger.info(f"Sleeping for {sleep_duration:.2f} seconds to respect rate limits.")
178
+ time.sleep(sleep_duration)
179
+ last_api_call_time = time.time()
180
+
181
+ # Existing logic to prepare the prompt
182
  html_content = bookmark.get('html_content', '')
 
 
183
  soup = BeautifulSoup(html_content, 'html.parser')
 
 
184
  metadata = get_page_metadata(soup)
185
  main_content = extract_main_content(soup)
186
 
 
242
  return len(text) / 4 # Approximate token estimation
243
 
244
  prompt_tokens = estimate_tokens(prompt)
245
+ max_tokens = 150 # Adjusted from 200
246
  total_tokens = prompt_tokens + max_tokens
247
 
248
  # Calculate required delay
249
+ tokens_per_minute = 40000
250
  tokens_per_second = tokens_per_minute / 60
251
  required_delay = total_tokens / tokens_per_second
252
+ sleep_time = max(required_delay, 2) # Ensure at least 2 seconds
253
 
254
  # Call the LLM via Groq Cloud API
255
  response = openai.ChatCompletion.create(
 
260
  max_tokens=int(max_tokens),
261
  temperature=0.5,
262
  )
263
+
264
  content = response['choices'][0]['message']['content'].strip()
265
  if not content:
266
  raise ValueError("Empty response received from the model.")
 
298
  except openai.error.RateLimitError as e:
299
  retry_count += 1
300
  wait_time = int(e.headers.get("Retry-After", 5))
301
+ logger.warning(f"Rate limit reached. Waiting for {wait_time} seconds before retrying... (Attempt {retry_count}/{max_retries})")
302
  time.sleep(wait_time)
303
  except Exception as e:
304
  logger.error(f"Error generating summary and assigning category: {e}", exc_info=True)
 
394
  """
395
  Create vector embeddings for bookmarks and build FAISS index with ID mapping.
396
  """
397
+ global faiss_index
398
  logger.info("Vectorizing summaries and building FAISS index")
399
  try:
400
  summaries = [bookmark['summary'] for bookmark in bookmarks_list]
 
404
  # Assign unique IDs to each bookmark
405
  ids = np.array([bookmark['id'] for bookmark in bookmarks_list], dtype=np.int64)
406
  index.add_with_ids(np.array(embeddings).astype('float32'), ids)
407
+ faiss_index = index
408
  logger.info("FAISS index built successfully with IDs")
409
  return index
410
  except Exception as e:
 
460
  logger.info("HTML display generated")
461
  return cards
462
 
463
+ def process_uploaded_file(file, state_bookmarks):
464
  """
465
  Process the uploaded bookmarks file.
466
  """
 
469
 
470
  if file is None:
471
  logger.warning("No file uploaded")
472
+ return "Please upload a bookmarks HTML file.", '', state_bookmarks, display_bookmarks()
473
 
474
  try:
475
  file_content = file.decode('utf-8')
476
  except UnicodeDecodeError as e:
477
  logger.error(f"Error decoding the file: {e}", exc_info=True)
478
+ return "Error decoding the file. Please ensure it's a valid HTML file.", '', state_bookmarks, display_bookmarks()
479
 
480
  try:
481
  bookmarks = parse_bookmarks(file_content)
482
  except Exception as e:
483
  logger.error(f"Error parsing bookmarks: {e}", exc_info=True)
484
+ return "Error parsing the bookmarks HTML file.", '', state_bookmarks, display_bookmarks()
485
 
486
  if not bookmarks:
487
  logger.warning("No bookmarks found in the uploaded file")
488
+ return "No bookmarks found in the uploaded file.", '', state_bookmarks, display_bookmarks()
489
 
490
  # Assign unique IDs to bookmarks
491
  for idx, bookmark in enumerate(bookmarks):
 
493
 
494
  # Fetch bookmark info concurrently
495
  logger.info("Fetching URL info concurrently")
496
+ with ThreadPoolExecutor(max_workers=10) as executor: # Adjusted max_workers as needed
497
  executor.map(fetch_url_info, bookmarks)
498
 
499
  # Process bookmarks concurrently with LLM calls
500
  logger.info("Processing bookmarks with LLM concurrently")
501
+ with ThreadPoolExecutor(max_workers=1) as executor: # Reduced max_workers to 1 to serialize API calls
502
  executor.map(generate_summary_and_assign_category, bookmarks)
503
 
504
  try:
505
  faiss_index = vectorize_and_index(bookmarks)
506
  except Exception as e:
507
  logger.error(f"Error building FAISS index: {e}", exc_info=True)
508
+ return "Error building search index.", '', state_bookmarks, display_bookmarks()
509
 
510
  message = f"βœ… Successfully processed {len(bookmarks)} bookmarks."
511
  logger.info(message)
 
515
  choices = [f"{i+1}. {bookmark['title']} (Category: {bookmark['category']})"
516
  for i, bookmark in enumerate(bookmarks)]
517
 
518
+ # Update state
519
+ state_bookmarks = bookmarks.copy()
520
+
521
+ return message, bookmark_html, state_bookmarks, bookmark_html
522
 
523
+ def delete_selected_bookmarks(selected_indices, state_bookmarks):
524
  """
525
  Delete selected bookmarks and remove their vectors from the FAISS index.
526
  """
 
551
  choices = [f"{i+1}. {bookmark['title']} (Category: {bookmark['category']})"
552
  for i, bookmark in enumerate(bookmarks)]
553
 
554
+ # Update state
555
+ state_bookmarks = bookmarks.copy()
556
+
557
  return message, gr.update(choices=choices), display_bookmarks()
558
 
559
+ def edit_selected_bookmarks_category(selected_indices, new_category, state_bookmarks):
560
  """
561
  Edit category of selected bookmarks.
562
  """
563
  if not selected_indices:
564
+ return "⚠️ No bookmarks selected.", gr.update(choices=[]), display_bookmarks(), state_bookmarks
565
  if not new_category:
566
+ return "⚠️ No new category selected.", gr.update(choices=[]), display_bookmarks(), state_bookmarks
567
 
568
  indices = [int(s.split('.')[0])-1 for s in selected_indices]
569
  for idx in indices:
 
578
  choices = [f"{i+1}. {bookmark['title']} (Category: {bookmark['category']})"
579
  for i, bookmark in enumerate(bookmarks)]
580
 
581
+ # Update state
582
+ state_bookmarks = bookmarks.copy()
583
+
584
+ return message, gr.update(choices=choices), display_bookmarks(), state_bookmarks
585
 
586
  def export_bookmarks():
587
  """
 
619
  """
620
  if not bookmarks or faiss_index is None:
621
  logger.warning("No bookmarks available for chatbot")
622
+ chat_history.append({"role": "assistant", "content": "⚠️ No bookmarks available. Please upload and process your bookmarks first."})
623
  return chat_history
624
 
625
  logger.info(f"Chatbot received query: {user_query}")
626
 
627
  try:
628
+ # Rate Limiting Logic
629
+ with api_lock:
630
+ global last_api_call_time
631
+ current_time = time.time()
632
+ elapsed = current_time - last_api_call_time
633
+ if elapsed < 2:
634
+ sleep_duration = 2 - elapsed
635
+ logger.info(f"Sleeping for {sleep_duration:.2f} seconds to respect rate limits.")
636
+ time.sleep(sleep_duration)
637
+ last_api_call_time = time.time()
638
+
639
+ # Existing logic to encode the query and search the FAISS index
640
  query_vector = embedding_model.encode([user_query]).astype('float32')
 
 
641
  k = 5 # Number of results to return
642
  distances, ids = faiss_index.search(query_vector, k)
643
  ids = ids.flatten()
 
648
 
649
  if not matching_bookmarks:
650
  answer = "No relevant bookmarks found for your query."
651
+ chat_history.append({"role": "assistant", "content": answer})
652
  return chat_history
653
 
654
  # Format the response
 
675
  total_tokens = prompt_tokens + max_tokens
676
 
677
  # Calculate required delay
678
+ tokens_per_minute = 40000
679
  tokens_per_second = tokens_per_minute / 60
680
  required_delay = total_tokens / tokens_per_second
681
+ sleep_time = max(required_delay, 2) # Ensure at least 2 seconds
682
 
683
+ # Call the LLM via Groq Cloud API
684
  response = openai.ChatCompletion.create(
685
  model='llama-3.1-70b-versatile', # Using the specified model
686
  messages=[
 
689
  max_tokens=int(max_tokens),
690
  temperature=0.7,
691
  )
692
+
693
  answer = response['choices'][0]['message']['content'].strip()
694
  logger.info("Chatbot response generated")
695
  time.sleep(sleep_time)
696
 
697
  # Append the interaction to chat history
698
+ chat_history.append({"role": "assistant", "content": answer})
699
  return chat_history
700
 
701
  except openai.error.RateLimitError as e:
 
706
  except Exception as e:
707
  error_message = f"⚠️ Error processing your query: {str(e)}"
708
  logger.error(error_message, exc_info=True)
709
+ chat_history.append({"role": "assistant", "content": error_message})
710
  return chat_history
711
 
712
  def build_app():
 
716
  try:
717
  logger.info("Building Gradio app")
718
  with gr.Blocks(css="app.css") as demo:
719
+ # Initialize state
720
+ state_bookmarks = gr.State([])
721
+
722
  # General Overview
723
  gr.Markdown("""
724
+ # πŸ“š SmartMarks - AI Browser Bookmarks Manager
725
+
726
+ Welcome to **SmartMarks**, your intelligent assistant for managing browser bookmarks. SmartMarks leverages AI to help you organize, search, and interact with your bookmarks seamlessly.
727
+
728
+ ---
729
+
730
+ ## πŸš€ **How to Use SmartMarks**
731
+
732
+ SmartMarks is divided into three main sections:
733
+
734
+ 1. **πŸ“‚ Upload and Process Bookmarks:** Import your existing bookmarks and let SmartMarks analyze and categorize them for you.
735
+ 2. **πŸ’¬ Chat with Bookmarks:** Interact with your bookmarks using natural language queries to find relevant links effortlessly.
736
+ 3. **πŸ› οΈ Manage Bookmarks:** View, edit, delete, and export your bookmarks with ease.
737
+
738
+ Navigate through the tabs to explore each feature in detail.
739
+ """)
740
 
741
  # Upload and Process Bookmarks Tab
742
  with gr.Tab("Upload and Process Bookmarks"):
743
  gr.Markdown("""
744
+ ## πŸ“‚ **Upload and Process Bookmarks**
745
+
746
+ ### πŸ“ **Steps to Upload and Process:**
747
+
748
+ 1. **Upload Bookmarks File:**
749
+ - Click on the **"πŸ“ Upload Bookmarks HTML File"** button.
750
+ - Select your browser's exported bookmarks HTML file from your device.
751
+
752
+ 2. **Process Bookmarks:**
753
+ - After uploading, click on the **"βš™οΈ Process Bookmarks"** button.
754
+ - SmartMarks will parse your bookmarks, fetch additional information, generate summaries, and categorize each link based on predefined categories.
755
+
756
+ 3. **View Processed Bookmarks:**
757
+ - Once processing is complete, your bookmarks will be displayed in an organized and visually appealing format below.
758
+ """)
759
 
760
  upload = gr.File(label="πŸ“ Upload Bookmarks HTML File", type='binary')
761
  process_button = gr.Button("βš™οΈ Process Bookmarks")
762
  output_text = gr.Textbox(label="βœ… Output", interactive=False)
763
  bookmark_display = gr.HTML(label="πŸ“„ Processed Bookmarks")
764
 
765
+ process_button.click(
766
+ process_uploaded_file,
767
+ inputs=[upload, state_bookmarks],
768
+ outputs=[output_text, bookmark_display, state_bookmarks, bookmark_display]
769
+ )
770
+
771
  # Chat with Bookmarks Tab
772
  with gr.Tab("Chat with Bookmarks"):
773
  gr.Markdown("""
774
+ ## πŸ’¬ **Chat with Bookmarks**
 
 
775
 
776
+ ### πŸ€– **How to Interact:**
777
+
778
+ 1. **Enter Your Query:**
779
+ - 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?"
780
+
781
+ 2. **Submit Your Query:**
782
+ - Click the **"πŸ“¨ Send"** button to submit your query.
783
+
784
+ 3. **Receive AI-Driven Responses:**
785
+ - SmartMarks will analyze your query and provide relevant bookmarks that match your request, making it easier to find specific links without manual searching.
786
+
787
+ 4. **View Chat History:**
788
+ - All your queries and the corresponding AI responses are displayed in the chat history for your reference.
789
+ """)
790
+
791
+ chatbot = gr.Chatbot(label="πŸ’¬ Chat with SmartMarks", type='messages')
792
  user_input = gr.Textbox(
793
  label="✍️ Ask about your bookmarks",
794
  placeholder="e.g., Do I have any bookmarks about AI?"
795
  )
796
  chat_button = gr.Button("πŸ“¨ Send")
797
 
798
+ chat_button.click(
799
+ chatbot_response,
800
+ inputs=[user_input, chatbot],
801
+ outputs=chatbot
802
+ )
803
+
804
  # Manage Bookmarks Tab
805
  with gr.Tab("Manage Bookmarks"):
806
  gr.Markdown("""
807
+ ## πŸ› οΈ **Manage Bookmarks**
808
+
809
+ ### πŸ—‚οΈ **Features:**
810
+
811
+ 1. **View Bookmarks:**
812
+ - All your processed bookmarks are displayed here with their respective categories and summaries.
813
+
814
+ 2. **Select Bookmarks:**
815
+ - Use the checkboxes next to each bookmark to select one, multiple, or all bookmarks you wish to manage.
816
+
817
+ 3. **Delete Selected Bookmarks:**
818
+ - After selecting the desired bookmarks, click the **"πŸ—‘οΈ Delete Selected"** button to remove them from your list.
819
+
820
+ 4. **Edit Categories:**
821
+ - Select the bookmarks you want to re-categorize.
822
+ - Choose a new category from the dropdown menu labeled **"πŸ†• New Category"**.
823
+ - Click the **"✏️ Edit Category"** button to update their categories.
824
+
825
+ 5. **Export Bookmarks:**
826
+ - Click the **"πŸ’Ύ Export"** button to download your updated bookmarks as an HTML file.
827
+ - This file can be uploaded back to your browser to reflect the changes made within SmartMarks.
828
+
829
+ 6. **Refresh Bookmarks:**
830
+ - Click the **"πŸ”„ Refresh Bookmarks"** button to ensure the latest state is reflected in the display.
831
+ """)
832
 
833
  manage_output = gr.Textbox(label="πŸ”„ Status", interactive=False)
834
  bookmark_selector = gr.CheckboxGroup(
 
846
  delete_button = gr.Button("πŸ—‘οΈ Delete Selected")
847
  edit_category_button = gr.Button("✏️ Edit Category")
848
  export_button = gr.Button("πŸ’Ύ Export")
849
+ refresh_button = gr.Button("πŸ”„ Refresh Bookmarks")
850
 
851
  download_link = gr.File(label="πŸ“₯ Download Exported Bookmarks")
852
 
853
+ # Define button actions
854
+ delete_button.click(
855
+ delete_selected_bookmarks,
856
+ inputs=[bookmark_selector, state_bookmarks],
857
+ outputs=[manage_output, bookmark_selector, bookmark_display_manage]
858
+ )
 
 
 
 
 
 
859
 
860
+ edit_category_button.click(
861
+ edit_selected_bookmarks_category,
862
+ inputs=[bookmark_selector, new_category, state_bookmarks],
863
+ outputs=[manage_output, bookmark_selector, bookmark_display_manage, state_bookmarks]
864
+ )
865
 
866
+ export_button.click(
867
+ export_bookmarks,
868
+ outputs=download_link
869
+ )
 
870
 
871
+ refresh_button.click(
872
+ lambda state_bookmarks: (
873
+ [
874
+ f"{i+1}. {bookmark['title']} (Category: {bookmark['category']})" for i, bookmark in enumerate(state_bookmarks)
875
+ ],
876
+ display_bookmarks()
877
+ ),
878
+ inputs=[state_bookmarks],
879
+ outputs=[bookmark_selector, bookmark_display_manage]
880
+ )
881
 
882
  logger.info("Launching Gradio app")
883
  demo.launch(debug=True)