Spaces:
Running
Running
siddhartharya
commited on
Update app.py
Browse files
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
|
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
|
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.", ''
|
|
|
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.", ''
|
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.", ''
|
386 |
|
387 |
if not bookmarks:
|
388 |
logger.warning("No bookmarks found in the uploaded file")
|
389 |
-
return "No bookmarks found in the uploaded file.", ''
|
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.", ''
|
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.", ''
|
408 |
|
409 |
message = f"β
Successfully processed {len(bookmarks)} bookmarks."
|
410 |
logger.info(message)
|
411 |
bookmark_html = display_bookmarks()
|
412 |
|
413 |
-
|
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 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
|
|
|
|
|
|
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=[]),
|
|
|
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 |
-
|
440 |
-
|
441 |
-
bookmark_selector_update =
|
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.",
|
450 |
if not new_category:
|
451 |
-
return "β οΈ No new category selected.",
|
|
|
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 |
-
|
460 |
-
|
461 |
-
bookmark_selector_update =
|
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
|
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 |
-
|
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.
|
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
|
577 |
-
|
578 |
-
|
579 |
-
|
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
|
603 |
)
|
604 |
|
605 |
# Chat with Bookmarks Tab
|
@@ -607,21 +624,15 @@ def build_app():
|
|
607 |
gr.Markdown("""
|
608 |
## π¬ **Chat with Bookmarks**
|
609 |
|
610 |
-
|
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(
|
623 |
-
|
|
|
|
|
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 |
-
|
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="π
|
659 |
-
|
660 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
665 |
-
edit_category_button = gr.Button("βοΈ Edit Category
|
666 |
-
export_button = gr.Button("πΎ Export
|
667 |
-
|
|
|
|
|
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,
|
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:
|