From 5e617943683b7cafde98f8b1cb263abcbd68a62e Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 16 Oct 2024 23:21:31 -0700 Subject: [PATCH 01/17] RAG Search + notes --- .gitignore | Bin 10772 -> 10787 bytes App_Function_Libraries/DB/RAG_QA_Chat_DB.py | 366 ++++++++++++++++++ App_Function_Libraries/Gradio_Related.py | 4 +- .../RAG/RAG_QA_Chat_Notes.py | 221 +++++++++++ README.md | 6 +- 5 files changed, 593 insertions(+), 4 deletions(-) create mode 100644 App_Function_Libraries/DB/RAG_QA_Chat_DB.py create mode 100644 App_Function_Libraries/RAG/RAG_QA_Chat_Notes.py diff --git a/.gitignore b/.gitignore index e194842789767c5a92fcef2f1cb4b90642d1017c..21d4e6e0946d8080d95852b7d4a0bf8d7ee51770 100644 GIT binary patch delta 23 ecmbOdvN&Xeh!%fQVtRaGVtjH&Vu@Z#5*Gkzj|fEo delta 7 OcmZ1+G9_e#h!y}13Ifgm diff --git a/App_Function_Libraries/DB/RAG_QA_Chat_DB.py b/App_Function_Libraries/DB/RAG_QA_Chat_DB.py new file mode 100644 index 00000000..6b749975 --- /dev/null +++ b/App_Function_Libraries/DB/RAG_QA_Chat_DB.py @@ -0,0 +1,366 @@ +#DB Imports +import logging +import re +import sqlite3 +from contextlib import contextmanager +from datetime import datetime + + + +# Set up logging +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +# Database schema +SCHEMA_SQL = ''' +-- Table for storing chat messages +CREATE TABLE IF NOT EXISTS rag_qa_chats ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + conversation_id TEXT NOT NULL, + timestamp DATETIME NOT NULL, + role TEXT NOT NULL, + content TEXT NOT NULL +); + +-- Table for storing conversation metadata +CREATE TABLE IF NOT EXISTS conversation_metadata ( + conversation_id TEXT PRIMARY KEY, + created_at DATETIME NOT NULL, + last_updated DATETIME NOT NULL, + title TEXT NOT NULL +); + +-- Table for storing keywords +CREATE TABLE IF NOT EXISTS rag_qa_keywords ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + keyword TEXT NOT NULL UNIQUE +); + +-- Table for linking keywords to conversations +CREATE TABLE IF NOT EXISTS rag_qa_conversation_keywords ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + conversation_id TEXT NOT NULL, + keyword_id INTEGER NOT NULL, + FOREIGN KEY (conversation_id) REFERENCES conversation_metadata(conversation_id), + FOREIGN KEY (keyword_id) REFERENCES rag_qa_keywords(id) +); + +-- Table for storing keyword collections +CREATE TABLE IF NOT EXISTS rag_qa_keyword_collections ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL UNIQUE, + parent_id INTEGER, + FOREIGN KEY (parent_id) REFERENCES rag_qa_keyword_collections(id) +); + +-- Table for linking keywords to collections +CREATE TABLE IF NOT EXISTS rag_qa_collection_keywords ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + collection_id INTEGER NOT NULL, + keyword_id INTEGER NOT NULL, + FOREIGN KEY (collection_id) REFERENCES rag_qa_keyword_collections(id), + FOREIGN KEY (keyword_id) REFERENCES rag_qa_keywords(id) +); + +-- Indexes for improved query performance +CREATE INDEX IF NOT EXISTS idx_rag_qa_chats_conversation_id ON rag_qa_chats(conversation_id); +CREATE INDEX IF NOT EXISTS idx_rag_qa_chats_timestamp ON rag_qa_chats(timestamp); +CREATE INDEX IF NOT EXISTS idx_rag_qa_keywords_keyword ON rag_qa_keywords(keyword); +CREATE INDEX IF NOT EXISTS idx_rag_qa_conversation_keywords_conversation_id ON rag_qa_conversation_keywords(conversation_id); +CREATE INDEX IF NOT EXISTS idx_rag_qa_conversation_keywords_keyword_id ON rag_qa_conversation_keywords(keyword_id); +CREATE INDEX IF NOT EXISTS idx_rag_qa_keyword_collections_parent_id ON rag_qa_keyword_collections(parent_id); +CREATE INDEX IF NOT EXISTS idx_rag_qa_collection_keywords_collection_id ON rag_qa_collection_keywords(collection_id); +CREATE INDEX IF NOT EXISTS idx_rag_qa_collection_keywords_keyword_id ON rag_qa_collection_keywords(keyword_id); + +-- Full-text search virtual table for chat content +CREATE VIRTUAL TABLE IF NOT EXISTS rag_qa_chats_fts USING fts5(conversation_id, timestamp, role, content); + +-- Trigger to keep the FTS table up to date +CREATE TRIGGER IF NOT EXISTS rag_qa_chats_ai AFTER INSERT ON rag_qa_chats BEGIN + INSERT INTO rag_qa_chats_fts(conversation_id, timestamp, role, content) VALUES (new.conversation_id, new.timestamp, new.role, new.content); +END; +''' + +# Database connection management +@contextmanager +def get_db_connection(): + conn = sqlite3.connect('rag_qa_chat.db') + try: + yield conn + finally: + conn.close() + +@contextmanager +def transaction(): + with get_db_connection() as conn: + try: + conn.execute('BEGIN TRANSACTION') + yield conn + conn.commit() + except Exception: + conn.rollback() + raise + +def execute_query(query, params=None, transaction_conn=None): + if transaction_conn: + cursor = transaction_conn.cursor() + if params: + cursor.execute(query, params) + else: + cursor.execute(query) + return cursor.fetchall() + else: + with get_db_connection() as conn: + cursor = conn.cursor() + if params: + cursor.execute(query, params) + else: + cursor.execute(query) + conn.commit() + return cursor.fetchall() + +def create_tables(): + with get_db_connection() as conn: + conn.executescript(SCHEMA_SQL) + logger.info("All RAG QA Chat tables created successfully") + +# Initialize the database +create_tables() + + + + +# Input validation +def validate_keyword(keyword): + if not isinstance(keyword, str): + raise ValueError("Keyword must be a string") + if not keyword.strip(): + raise ValueError("Keyword cannot be empty or just whitespace") + if len(keyword) > 100: + raise ValueError("Keyword is too long (max 100 characters)") + if not re.match(r'^[a-zA-Z0-9\s\-_]+$', keyword): + raise ValueError("Keyword contains invalid characters") + return keyword.strip() + + +def validate_collection_name(name): + if not isinstance(name, str): + raise ValueError("Collection name must be a string") + if not name.strip(): + raise ValueError("Collection name cannot be empty or just whitespace") + if len(name) > 100: + raise ValueError("Collection name is too long (max 100 characters)") + if not re.match(r'^[a-zA-Z0-9\s\-_]+$', name): + raise ValueError("Collection name contains invalid characters") + return name.strip() + + +# Core functions +def add_keyword(keyword): + try: + validated_keyword = validate_keyword(keyword) + query = "INSERT OR IGNORE INTO rag_qa_keywords (keyword) VALUES (?)" + execute_query(query, (validated_keyword,)) + logger.info(f"Keyword '{validated_keyword}' added successfully") + except ValueError as e: + logger.error(f"Invalid keyword: {e}") + raise + except Exception as e: + logger.error(f"Error adding keyword '{keyword}': {e}") + raise + + +def create_keyword_collection(name, parent_id=None): + try: + validated_name = validate_collection_name(name) + query = "INSERT INTO rag_qa_keyword_collections (name, parent_id) VALUES (?, ?)" + execute_query(query, (validated_name, parent_id)) + logger.info(f"Keyword collection '{validated_name}' created successfully") + except ValueError as e: + logger.error(f"Invalid collection name: {e}") + raise + except Exception as e: + logger.error(f"Error creating keyword collection '{name}': {e}") + raise + + +def add_keyword_to_collection(collection_name, keyword): + try: + validated_collection_name = validate_collection_name(collection_name) + validated_keyword = validate_keyword(keyword) + + with transaction() as conn: + add_keyword(validated_keyword) + + query = ''' + INSERT INTO rag_qa_collection_keywords (collection_id, keyword_id) + SELECT c.id, k.id + FROM rag_qa_keyword_collections c, rag_qa_keywords k + WHERE c.name = ? AND k.keyword = ? + ''' + execute_query(query, (validated_collection_name, validated_keyword), conn) + + logger.info(f"Keyword '{validated_keyword}' added to collection '{validated_collection_name}' successfully") + except ValueError as e: + logger.error(f"Invalid input: {e}") + raise + except Exception as e: + logger.error(f"Error adding keyword '{keyword}' to collection '{collection_name}': {e}") + raise + + +def add_keywords_to_conversation(conversation_id, keywords): + if not isinstance(keywords, (list, tuple)): + raise ValueError("Keywords must be a list or tuple") + try: + with transaction() as conn: + for keyword in keywords: + validated_keyword = validate_keyword(keyword) + + query = "INSERT OR IGNORE INTO rag_qa_keywords (keyword) VALUES (?)" + execute_query(query, (validated_keyword,), conn) + + query = ''' + INSERT INTO rag_qa_conversation_keywords (conversation_id, keyword_id) + SELECT ?, id FROM rag_qa_keywords WHERE keyword = ? + ''' + execute_query(query, (conversation_id, validated_keyword), conn) + + logger.info(f"Keywords added to conversation '{conversation_id}' successfully") + except ValueError as e: + logger.error(f"Invalid keyword: {e}") + raise + except Exception as e: + logger.error(f"Error adding keywords to conversation '{conversation_id}': {e}") + raise + + +def get_keywords_for_conversation(conversation_id): + try: + query = ''' + SELECT k.keyword + FROM rag_qa_keywords k + JOIN rag_qa_conversation_keywords ck ON k.id = ck.keyword_id + WHERE ck.conversation_id = ? + ''' + result = execute_query(query, (conversation_id,)) + keywords = [row[0] for row in result] + logger.info(f"Retrieved {len(keywords)} keywords for conversation '{conversation_id}'") + return keywords + except Exception as e: + logger.error(f"Error getting keywords for conversation '{conversation_id}': {e}") + raise + + +def get_keywords_for_collection(collection_name): + try: + query = ''' + SELECT k.keyword + FROM rag_qa_keywords k + JOIN rag_qa_collection_keywords ck ON k.id = ck.keyword_id + JOIN rag_qa_keyword_collections c ON ck.collection_id = c.id + WHERE c.name = ? + ''' + result = execute_query(query, (collection_name,)) + keywords = [row[0] for row in result] + logger.info(f"Retrieved {len(keywords)} keywords for collection '{collection_name}'") + return keywords + except Exception as e: + logger.error(f"Error getting keywords for collection '{collection_name}': {e}") + raise + + +def save_message(conversation_id, role, content): + try: + query = "INSERT INTO rag_qa_chats (conversation_id, timestamp, role, content) VALUES (?, ?, ?, ?)" + timestamp = datetime.now().isoformat() + execute_query(query, (conversation_id, timestamp, role, content)) + logger.info(f"Message saved for conversation '{conversation_id}'") + except Exception as e: + logger.error(f"Error saving message for conversation '{conversation_id}': {e}") + raise + + +def start_new_conversation(title="Untitled Conversation"): + try: + conversation_id = datetime.now().isoformat() + query = "INSERT INTO conversation_metadata (conversation_id, created_at, last_updated, title) VALUES (?, ?, ?, ?)" + now = datetime.now() + execute_query(query, (conversation_id, now, now, title)) + logger.info(f"New conversation '{conversation_id}' started with title '{title}'") + return conversation_id + except Exception as e: + logger.error(f"Error starting new conversation: {e}") + raise + + +# Pagination helper function +def get_paginated_results(query, params=None, page=1, page_size=20): + try: + offset = (page - 1) * page_size + paginated_query = f"{query} LIMIT ? OFFSET ?" + if params: + params = tuple(params) + (page_size, offset) + else: + params = (page_size, offset) + + result = execute_query(paginated_query, params) + + count_query = f"SELECT COUNT(*) FROM ({query})" + total_count = execute_query(count_query, params[:-2] if params else None)[0][0] + + total_pages = (total_count + page_size - 1) // page_size + + logger.info(f"Retrieved page {page} of {total_pages} (total items: {total_count})") + return result, total_pages, total_count + except Exception as e: + logger.error(f"Error retrieving paginated results: {e}") + raise + + +def get_all_collections(page=1, page_size=20): + try: + query = "SELECT name FROM rag_qa_keyword_collections" + results, total_pages, total_count = get_paginated_results(query, page=page, page_size=page_size) + collections = [row[0] for row in results] + logger.info(f"Retrieved {len(collections)} keyword collections (page {page} of {total_pages})") + return collections, total_pages, total_count + except Exception as e: + logger.error(f"Error getting collections: {e}") + raise + + +def search_conversations_by_keywords(keywords, page=1, page_size=20): + try: + placeholders = ','.join(['?' for _ in keywords]) + query = f''' + SELECT DISTINCT cm.conversation_id, cm.title + FROM conversation_metadata cm + JOIN rag_qa_conversation_keywords ck ON cm.conversation_id = ck.conversation_id + JOIN rag_qa_keywords k ON ck.keyword_id = k.id + WHERE k.keyword IN ({placeholders}) + ''' + results, total_pages, total_count = get_paginated_results(query, keywords, page, page_size) + logger.info( + f"Found {total_count} conversations matching keywords: {', '.join(keywords)} (page {page} of {total_pages})") + return results, total_pages, total_count + except Exception as e: + logger.error(f"Error searching conversations by keywords {keywords}: {e}") + raise + + +def load_chat_history(conversation_id, page=1, page_size=50): + try: + query = "SELECT role, content FROM rag_qa_chats WHERE conversation_id = ? ORDER BY timestamp" + results, total_pages, total_count = get_paginated_results(query, (conversation_id,), page, page_size) + history = [(msg[1] if msg[0] == 'human' else None, msg[1] if msg[0] == 'ai' else None) for msg in results] + logger.info( + f"Loaded {len(history)} messages for conversation '{conversation_id}' (page {page} of {total_pages})") + return history, total_pages, total_count + except Exception as e: + logger.error(f"Error loading chat history for conversation '{conversation_id}': {e}") + raise + +# +# End of RAQ_QA_Chat_DB.py +#################################################################################################### \ No newline at end of file diff --git a/App_Function_Libraries/Gradio_Related.py b/App_Function_Libraries/Gradio_Related.py index 91ec99d2..d1423171 100644 --- a/App_Function_Libraries/Gradio_Related.py +++ b/App_Function_Libraries/Gradio_Related.py @@ -68,6 +68,7 @@ from App_Function_Libraries.Gradio_UI.Evaluations_Benchmarks_tab import create_geval_tab, create_infinite_bench_tab #from App_Function_Libraries.Local_LLM.Local_LLM_huggingface import create_huggingface_tab from App_Function_Libraries.Local_LLM.Local_LLM_ollama import create_ollama_tab +from App_Function_Libraries.RAG.RAG_QA_Chat_Notes import create_rag_qa_chat_notes_tab # ####################################################################################################################### @@ -289,12 +290,13 @@ def launch_ui(share_public=None, server_mode=False): create_search_tab() create_search_summaries_tab() + with gr.TabItem("RAG Chat+Notes"): + create_rag_qa_chat_notes_tab() with gr.TabItem("RAG Search"): create_rag_tab() create_rag_qa_chat_tab() - with gr.TabItem("Chat with an LLM"): create_chat_interface() create_chat_interface_stacked() diff --git a/App_Function_Libraries/RAG/RAG_QA_Chat_Notes.py b/App_Function_Libraries/RAG/RAG_QA_Chat_Notes.py new file mode 100644 index 00000000..23ea49b2 --- /dev/null +++ b/App_Function_Libraries/RAG/RAG_QA_Chat_Notes.py @@ -0,0 +1,221 @@ +# RAG_QA_Chat_Notes.py +# Description: This file contains the code for the RAG QA Chat Notes tab in the RAG QA Chat application. +# +# Imports +import logging +# External Imports +import gradio as gr +# +# Local Imports +from App_Function_Libraries.DB.RAG_QA_Chat_DB import save_message, add_keywords_to_conversation, \ + search_conversations_by_keywords, load_chat_history +# +#################################################################################################### +# +# Functions +def create_rag_qa_chat_notes_tab(): + with gr.TabItem("RAG QA Chat"): + gr.Markdown("# RAG QA Chat") + + state = gr.State({ + "conversation_id": None, + "page": 1, + "context_source": "All Files in the Database" + }) + + with gr.Row(): + with gr.Column(scale=1): + context_source = gr.Radio( + ["All Files in the Database", "Search Database", "Upload File"], + label="Context Source", + value="All Files in the Database" + ) + existing_file = gr.Dropdown(label="Select Existing File", choices=[], interactive=True) + file_page = gr.State(value=1) + with gr.Row(): + page_number = gr.Number(value=1, label="Page", precision=0) + page_size = gr.Number(value=20, label="Items per page", precision=0) + total_pages = gr.Number(label="Total Pages", interactive=False) + with gr.Row(): + prev_page_btn = gr.Button("Previous Page") + next_page_btn = gr.Button("Next Page") + page_info = gr.HTML("Page 1") + + search_query = gr.Textbox(label="Search Query", visible=False) + search_button = gr.Button("Search", visible=False) + search_results = gr.Dropdown(label="Search Results", choices=[], visible=False) + file_upload = gr.File( + label="Upload File", + visible=False, + file_types=["txt", "pdf", "epub", "md", "rtf", "json", "csv"] + ) + convert_to_text = gr.Checkbox(label="Convert to plain text", visible=False) + keywords = gr.Textbox(label="Keywords (comma-separated)", visible=False) + with gr.Column(scale=1): + api_choice = gr.Dropdown( + choices=["Local-LLM", "OpenAI", "Anthropic", "Cohere", "Groq", "DeepSeek", "Mistral", "OpenRouter", + "Llama.cpp", "Kobold", "Ooba", "Tabbyapi", "VLLM", "ollama", "HuggingFace"], + label="Select API for RAG", + value="OpenAI" + ) + use_query_rewriting = gr.Checkbox(label="Use Query Rewriting", value=True) + + load_conversation = gr.Dropdown(label="Load Conversation", choices=[]) + new_conversation = gr.Button("New Conversation") + conversation_title = gr.Textbox(label="Conversation Title", + placeholder="Enter a title for the new conversation") + + with gr.Row(): + page_number = gr.Number(value=1, label="Page", precision=0) + page_size = gr.Number(value=20, label="Items per page", precision=0) + total_pages = gr.Number(label="Total Pages", interactive=False) + + with gr.Row(): + with gr.Column(scale=2): + chatbot = gr.Chatbot(height=500) + msg = gr.Textbox(label="Enter your message") + submit = gr.Button("Submit") + clear_chat = gr.Button("Clear Chat History") + + with gr.Column(scale=1): + notes = gr.TextArea(label="Notes", placeholder="Enter your notes here...", lines=20) + save_notes = gr.Button("Save Notes") + clear_notes = gr.Button("Clear Notes") + + + + loading_indicator = gr.HTML(visible=False) + + def rag_qa_chat_wrapper(message, history, state, context_source, existing_file, search_results, file_upload, + convert_to_text, keywords, api_choice, use_query_rewriting): + try: + conversation_id = state["conversation_id"] + if not conversation_id: + conversation_id = start_new_conversation() + state = update_state(state, conversation_id=conversation_id) + + save_message(conversation_id, 'human', message) + + if keywords: + add_keywords_to_conversation(conversation_id, keywords.split(',')) + + # Here you would implement your actual RAG logic + # For this example, we'll just echo the message + response = f"RAG QA Chat: You said '{message}'" + + save_message(conversation_id, 'ai', response) + + new_history = history + [(message, response)] + + logging.info(f"Successfully processed message for conversation '{conversation_id}'") + return new_history, "", gr.update(visible=False), state + + except Exception as e: + logging.error(f"Error in rag_qa_chat_wrapper: {e}") + gr.Error("An unexpected error occurred. Please try again later.") + return history, "", gr.update(visible=False), state + + def load_conversation_history(selected_conversation_id, page, page_size, state): + if selected_conversation_id: + history, total_pages, _ = load_chat_history(selected_conversation_id, page, page_size) + return history, total_pages, update_state(state, conversation_id=selected_conversation_id, page=page) + return [], 1, state + + def start_new_conversation(title, state): + new_conversation_id = start_new_conversation(title if title else "Untitled Conversation") + return [], update_state(state, conversation_id=new_conversation_id, page=1) + + def update_state(state, **kwargs): + new_state = state.copy() + new_state.update(kwargs) + return new_state + + def update_page(direction, current_page, total_pages): + new_page = max(1, min(current_page + direction, total_pages)) + return new_page + + def update_context_source(choice): + return { + existing_file: gr.update(visible=choice == "Existing File"), + prev_page_btn: gr.update(visible=choice == "Existing File"), + next_page_btn: gr.update(visible=choice == "Existing File"), + page_info: gr.update(visible=choice == "Existing File"), + search_query: gr.update(visible=choice == "Search Database"), + search_button: gr.update(visible=choice == "Search Database"), + search_results: gr.update(visible=choice == "Search Database"), + file_upload: gr.update(visible=choice == "Upload File"), + convert_to_text: gr.update(visible=choice == "Upload File"), + keywords: gr.update(visible=choice == "Upload File") + } + + def perform_search(query): + try: + results = search_conversations_by_keywords(query.split()) + return gr.update(choices=[f"{title} (ID: {id})" for id, title in results[0]]) + except Exception as e: + logging.error(f"Error performing search: {e}") + gr.Error(f"Error performing search: {str(e)}") + return gr.update(choices=[]) + + def clear_chat_history(): + return [], "" + + def save_notes_function(notes): + # Implement saving notes functionality here + logging.info("Notes saved successfully!") + return notes + + def clear_notes_function(): + return "" + + # Event handlers + submit.click( + rag_qa_chat_wrapper, + inputs=[msg, chatbot, state, context_source, existing_file, search_results, file_upload, + convert_to_text, keywords, api_choice, use_query_rewriting], + outputs=[chatbot, msg, loading_indicator, state] + ) + + load_conversation.change( + load_conversation_history, + inputs=[load_conversation, page_number, page_size, state], + outputs=[chatbot, total_pages, state] + ) + + new_conversation.click( + start_new_conversation, + inputs=[conversation_title, state], + outputs=[chatbot, state] + ) + + # Event handlers + prev_page_btn.click( + update_page, + inputs=[gr.Number(-1, visible=False), page_number, total_pages], + outputs=[page_number] + ) + next_page_btn.click( + update_page, + inputs=[gr.Number(1, visible=False), page_number, total_pages], + outputs=[page_number] + ) + + context_source.change(update_context_source, context_source, + [existing_file, prev_page_btn, next_page_btn, page_info, search_query, search_button, + search_results, file_upload, convert_to_text, keywords]) + + search_button.click(perform_search, inputs=[search_query], outputs=[search_results]) + + clear_chat.click(clear_chat_history, outputs=[chatbot, msg]) + + save_notes.click(save_notes_function, inputs=[notes], outputs=[notes]) + clear_notes.click(clear_notes_function, outputs=[notes]) + + return (context_source, existing_file, search_query, search_button, search_results, file_upload, + convert_to_text, keywords, api_choice, use_query_rewriting, chatbot, msg, submit, clear_chat, + notes, save_notes, clear_notes, load_conversation, new_conversation, conversation_title, + prev_page_btn, next_page_btn, page_number, page_size, total_pages) + +# +# End of Rag_QA_Chat_Notes.py +#################################################################################################### \ No newline at end of file diff --git a/README.md b/README.md index 5223f342..6c4c3dce 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ - Build up a personal knowledge archive, then turn around and use the LLM to help you learn it at a pace your comfortable with. - Also writing tools! Grammar/Style checker, Tone Analyzer, Writing editor(feedback), and more. - Full Character Chat Support - Create/Edit & Import/Export Character Cards, and chat with them. -#### The original scripts by `the-crypt-keeper` are available here: [scripts here](https://github.com/the-crypt-keeper/tldw/tree/main/tldw-original-scripts) +#### The original scripts by `the-crypt-keeper` for transcribing and summarizing youtube videos are available here: [scripts here](https://github.com/the-crypt-keeper/tldw/tree/main/tldw-original-scripts) ---------- @@ -58,7 +58,7 @@ - the `Dockerfile` in the main directory is the Nvidia base-image-based one. So you can use your GPU if you want with it. -### What is tl/dw? +### Overview of what tl/dw currenlty is
What is this? - Click-Here @@ -142,7 +142,7 @@ All features are designed to run **locally** on your device, ensuring privacy an ---------- -### What is this (tl/dw)? +### More Detailed explanation of this project (tl/dw)
**What is this Project? (Extended) - Click-Here** From 1e3a3bf7e7b36fe0c931a0e5a4858a119f7ae0c4 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 16 Oct 2024 23:23:45 -0700 Subject: [PATCH 02/17] Update Local_LLM_Inference_Engine_Lib.py --- .../Local_LLM/Local_LLM_Inference_Engine_Lib.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/App_Function_Libraries/Local_LLM/Local_LLM_Inference_Engine_Lib.py b/App_Function_Libraries/Local_LLM/Local_LLM_Inference_Engine_Lib.py index c5533625..6b67eff2 100644 --- a/App_Function_Libraries/Local_LLM/Local_LLM_Inference_Engine_Lib.py +++ b/App_Function_Libraries/Local_LLM/Local_LLM_Inference_Engine_Lib.py @@ -39,25 +39,25 @@ # LLM models information llm_models = { - "1": { + "Mistral-7B-Instruct-v0.2-Q8.llamafile": { "name": "Mistral-7B-Instruct-v0.2-Q8.llamafile", "url": "https://huggingface.co/Mozilla/Mistral-7B-Instruct-v0.2-llamafile/resolve/main/mistral-7b-instruct-v0.2.Q8_0.llamafile?download=true", "filename": "mistral-7b-instruct-v0.2.Q8_0.llamafile", "hash": "1ee6114517d2f770425c880e5abc443da36b193c82abec8e2885dd7ce3b9bfa6" }, - "2": { + "Samantha-Mistral-Instruct-7B-Bulleted-Notes-Q8.gguf": { "name": "Samantha-Mistral-Instruct-7B-Bulleted-Notes-Q8.gguf", "url": "https://huggingface.co/cognitivetech/samantha-mistral-instruct-7b-bulleted-notes-GGUF/resolve/main/samantha-mistral-instruct-7b-bulleted-notes.Q8_0.gguf?download=true", "filename": "samantha-mistral-instruct-7b-bulleted-notes.Q8_0.gguf", "hash": "6334c1ab56c565afd86535271fab52b03e67a5e31376946bce7bf5c144e847e4" }, - "3": { + "Phi-3-mini-128k-instruct-Q8_0.gguf": { "name": "Phi-3-mini-128k-instruct-Q8_0.gguf", "url": "https://huggingface.co/gaianet/Phi-3-mini-128k-instruct-GGUF/resolve/main/Phi-3-mini-128k-instruct-Q8_0.gguf?download=true", "filename": "Phi-3-mini-128k-instruct-Q8_0.gguf", "hash": "6817b66d1c3c59ab06822e9732f0e594eea44e64cae2110906eac9d17f75d193" }, - "4": { + "Meta-Llama-3-8B-Instruct.Q8_0.llamafile": { "name": "Meta-Llama-3-8B-Instruct.Q8_0.llamafile", "url": "https://huggingface.co/Mozilla/Meta-Llama-3-8B-Instruct-llamafile/resolve/main/Meta-Llama-3-8B-Instruct.Q8_0.llamafile?download=true", "filename": "Meta-Llama-3-8B-Instruct.Q8_0.llamafile", From 73d32729952ef55e625dbe32def419a55fc2e903 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 16 Oct 2024 23:35:34 -0700 Subject: [PATCH 03/17] Update RAG_QA_Chat_Notes.py --- App_Function_Libraries/RAG/RAG_QA_Chat_Notes.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/App_Function_Libraries/RAG/RAG_QA_Chat_Notes.py b/App_Function_Libraries/RAG/RAG_QA_Chat_Notes.py index 23ea49b2..bd3551a9 100644 --- a/App_Function_Libraries/RAG/RAG_QA_Chat_Notes.py +++ b/App_Function_Libraries/RAG/RAG_QA_Chat_Notes.py @@ -9,6 +9,9 @@ # Local Imports from App_Function_Libraries.DB.RAG_QA_Chat_DB import save_message, add_keywords_to_conversation, \ search_conversations_by_keywords, load_chat_history +from App_Function_Libraries.RAG.RAG_QA_Chat import rag_qa_chat + + # #################################################################################################### # @@ -100,8 +103,9 @@ def rag_qa_chat_wrapper(message, history, state, context_source, existing_file, add_keywords_to_conversation(conversation_id, keywords.split(',')) # Here you would implement your actual RAG logic - # For this example, we'll just echo the message - response = f"RAG QA Chat: You said '{message}'" + # FIXME + response = rag_qa_chat(message: str, history: List[Tuple[str, str]], context: Union[str, IO[str]], + api_choice: str) -> Tuple[List[Tuple[str, str]], str]: save_message(conversation_id, 'ai', response) From 1d5a7ce0a399b0db4533ae5e74bb341dc2e6fdd4 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 17 Oct 2024 12:29:55 -0700 Subject: [PATCH 04/17] RAG Chat Notes page --- App_Function_Libraries/DB/RAG_QA_Chat_DB.py | 135 +++++++++++++++--- App_Function_Libraries/Gradio_Related.py | 5 +- .../{RAG => Gradio_UI}/RAG_QA_Chat_Notes.py | 107 ++++++++------ App_Function_Libraries/RAG/RAG_QA_Chat.py | 4 +- .../Windows_Install_Update.bat | 2 + README.md | 3 + requirements.txt | 4 +- 7 files changed, 191 insertions(+), 69 deletions(-) rename App_Function_Libraries/{RAG => Gradio_UI}/RAG_QA_Chat_Notes.py (65%) diff --git a/App_Function_Libraries/DB/RAG_QA_Chat_DB.py b/App_Function_Libraries/DB/RAG_QA_Chat_DB.py index 6b749975..bd30cc9f 100644 --- a/App_Function_Libraries/DB/RAG_QA_Chat_DB.py +++ b/App_Function_Libraries/DB/RAG_QA_Chat_DB.py @@ -1,11 +1,20 @@ -#DB Imports +# RAG_QA_Chat_DB.py +# Description: This file contains the database operations for the RAG QA Chat + Notes system. +# +# Imports import logging import re import sqlite3 from contextlib import contextmanager from datetime import datetime - - +# +# External Imports +# +# Local Imports +# +######################################################################################################################## +# +# Functions: # Set up logging logging.basicConfig(level=logging.INFO) @@ -62,6 +71,24 @@ FOREIGN KEY (keyword_id) REFERENCES rag_qa_keywords(id) ); +-- Table for storing notes +CREATE TABLE IF NOT EXISTS rag_qa_notes ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + conversation_id TEXT NOT NULL, + content TEXT NOT NULL, + timestamp DATETIME NOT NULL, + FOREIGN KEY (conversation_id) REFERENCES conversation_metadata(conversation_id) +); + +-- Table for linking notes to keywords +CREATE TABLE IF NOT EXISTS rag_qa_note_keywords ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + note_id INTEGER NOT NULL, + keyword_id INTEGER NOT NULL, + FOREIGN KEY (note_id) REFERENCES rag_qa_notes(id), + FOREIGN KEY (keyword_id) REFERENCES rag_qa_keywords(id) +); + -- Indexes for improved query performance CREATE INDEX IF NOT EXISTS idx_rag_qa_chats_conversation_id ON rag_qa_chats(conversation_id); CREATE INDEX IF NOT EXISTS idx_rag_qa_chats_timestamp ON rag_qa_chats(timestamp); @@ -127,9 +154,6 @@ def create_tables(): # Initialize the database create_tables() - - - # Input validation def validate_keyword(keyword): if not isinstance(keyword, str): @@ -142,7 +166,6 @@ def validate_keyword(keyword): raise ValueError("Keyword contains invalid characters") return keyword.strip() - def validate_collection_name(name): if not isinstance(name, str): raise ValueError("Collection name must be a string") @@ -154,7 +177,6 @@ def validate_collection_name(name): raise ValueError("Collection name contains invalid characters") return name.strip() - # Core functions def add_keyword(keyword): try: @@ -169,7 +191,6 @@ def add_keyword(keyword): logger.error(f"Error adding keyword '{keyword}': {e}") raise - def create_keyword_collection(name, parent_id=None): try: validated_name = validate_collection_name(name) @@ -183,7 +204,6 @@ def create_keyword_collection(name, parent_id=None): logger.error(f"Error creating keyword collection '{name}': {e}") raise - def add_keyword_to_collection(collection_name, keyword): try: validated_collection_name = validate_collection_name(collection_name) @@ -208,7 +228,6 @@ def add_keyword_to_collection(collection_name, keyword): logger.error(f"Error adding keyword '{keyword}' to collection '{collection_name}': {e}") raise - def add_keywords_to_conversation(conversation_id, keywords): if not isinstance(keywords, (list, tuple)): raise ValueError("Keywords must be a list or tuple") @@ -234,7 +253,6 @@ def add_keywords_to_conversation(conversation_id, keywords): logger.error(f"Error adding keywords to conversation '{conversation_id}': {e}") raise - def get_keywords_for_conversation(conversation_id): try: query = ''' @@ -251,7 +269,6 @@ def get_keywords_for_conversation(conversation_id): logger.error(f"Error getting keywords for conversation '{conversation_id}': {e}") raise - def get_keywords_for_collection(collection_name): try: query = ''' @@ -269,6 +286,89 @@ def get_keywords_for_collection(collection_name): logger.error(f"Error getting keywords for collection '{collection_name}': {e}") raise +def save_notes(conversation_id, content): + """Save notes to the database.""" + try: + query = "INSERT INTO rag_qa_notes (conversation_id, content, timestamp) VALUES (?, ?, ?)" + timestamp = datetime.now().isoformat() + execute_query(query, (conversation_id, content, timestamp)) + logger.info(f"Notes saved for conversation '{conversation_id}'") + except Exception as e: + logger.error(f"Error saving notes for conversation '{conversation_id}': {e}") + raise + +def get_notes(conversation_id): + """Retrieve notes for a given conversation.""" + try: + query = "SELECT content FROM rag_qa_notes WHERE conversation_id = ?" + result = execute_query(query, (conversation_id,)) + notes = [row[0] for row in result] + logger.info(f"Retrieved {len(notes)} notes for conversation '{conversation_id}'") + return notes + except Exception as e: + logger.error(f"Error getting notes for conversation '{conversation_id}': {e}") + raise + +def clear_notes(conversation_id): + """Clear all notes for a given conversation.""" + try: + query = "DELETE FROM rag_qa_notes WHERE conversation_id = ?" + execute_query(query, (conversation_id,)) + logger.info(f"Cleared notes for conversation '{conversation_id}'") + except Exception as e: + logger.error(f"Error clearing notes for conversation '{conversation_id}': {e}") + raise + +def add_keywords_to_note(note_id, keywords): + """Associate keywords with a note.""" + try: + with transaction() as conn: + for keyword in keywords: + validated_keyword = validate_keyword(keyword) + + # Insert the keyword into the rag_qa_keywords table if it doesn't exist + query = "INSERT OR IGNORE INTO rag_qa_keywords (keyword) VALUES (?)" + execute_query(query, (validated_keyword,), conn) + + # Retrieve the keyword ID + query = "SELECT id FROM rag_qa_keywords WHERE keyword = ?" + keyword_id = execute_query(query, (validated_keyword,), conn)[0][0] + + # Link the note and keyword + query = "INSERT INTO rag_qa_note_keywords (note_id, keyword_id) VALUES (?, ?)" + execute_query(query, (note_id, keyword_id), conn) + + logger.info(f"Keywords added to note ID '{note_id}' successfully") + except Exception as e: + logger.error(f"Error adding keywords to note ID '{note_id}': {e}") + raise + +def get_keywords_for_note(note_id): + """Retrieve keywords associated with a given note.""" + try: + query = ''' + SELECT k.keyword + FROM rag_qa_keywords k + JOIN rag_qa_note_keywords nk ON k.id = nk.keyword_id + WHERE nk.note_id = ? + ''' + result = execute_query(query, (note_id,)) + keywords = [row[0] for row in result] + logger.info(f"Retrieved {len(keywords)} keywords for note ID '{note_id}'") + return keywords + except Exception as e: + logger.error(f"Error getting keywords for note ID '{note_id}': {e}") + raise + +def clear_keywords_from_note(note_id): + """Clear all keywords from a given note.""" + try: + query = "DELETE FROM rag_qa_note_keywords WHERE note_id = ?" + execute_query(query, (note_id,)) + logger.info(f"Cleared keywords for note ID '{note_id}'") + except Exception as e: + logger.error(f"Error clearing keywords for note ID '{note_id}': {e}") + raise def save_message(conversation_id, role, content): try: @@ -280,7 +380,6 @@ def save_message(conversation_id, role, content): logger.error(f"Error saving message for conversation '{conversation_id}': {e}") raise - def start_new_conversation(title="Untitled Conversation"): try: conversation_id = datetime.now().isoformat() @@ -293,7 +392,6 @@ def start_new_conversation(title="Untitled Conversation"): logger.error(f"Error starting new conversation: {e}") raise - # Pagination helper function def get_paginated_results(query, params=None, page=1, page_size=20): try: @@ -317,7 +415,6 @@ def get_paginated_results(query, params=None, page=1, page_size=20): logger.error(f"Error retrieving paginated results: {e}") raise - def get_all_collections(page=1, page_size=20): try: query = "SELECT name FROM rag_qa_keyword_collections" @@ -329,7 +426,6 @@ def get_all_collections(page=1, page_size=20): logger.error(f"Error getting collections: {e}") raise - def search_conversations_by_keywords(keywords, page=1, page_size=20): try: placeholders = ','.join(['?' for _ in keywords]) @@ -348,7 +444,6 @@ def search_conversations_by_keywords(keywords, page=1, page_size=20): logger.error(f"Error searching conversations by keywords {keywords}: {e}") raise - def load_chat_history(conversation_id, page=1, page_size=50): try: query = "SELECT role, content FROM rag_qa_chats WHERE conversation_id = ? ORDER BY timestamp" @@ -362,5 +457,5 @@ def load_chat_history(conversation_id, page=1, page_size=50): raise # -# End of RAQ_QA_Chat_DB.py -#################################################################################################### \ No newline at end of file +# End of RAG_QA_Chat_DB.py +#################################################################################################### diff --git a/App_Function_Libraries/Gradio_Related.py b/App_Function_Libraries/Gradio_Related.py index d1423171..fb5a8aec 100644 --- a/App_Function_Libraries/Gradio_Related.py +++ b/App_Function_Libraries/Gradio_Related.py @@ -19,8 +19,7 @@ from App_Function_Libraries.Gradio_UI.Arxiv_tab import create_arxiv_tab from App_Function_Libraries.Gradio_UI.Audio_ingestion_tab import create_audio_processing_tab from App_Function_Libraries.Gradio_UI.Book_Ingestion_tab import create_import_book_tab -from App_Function_Libraries.Gradio_UI.Character_Chat_tab import create_character_card_interaction_tab, \ - create_character_card_interaction_tab, create_character_chat_mgmt_tab, create_custom_character_card_tab, \ +from App_Function_Libraries.Gradio_UI.Character_Chat_tab import create_character_card_interaction_tab, create_character_chat_mgmt_tab, create_custom_character_card_tab, \ create_character_card_validation_tab, create_export_characters_tab from App_Function_Libraries.Gradio_UI.Character_interaction_tab import create_narrator_controlled_conversation_tab, \ create_multiple_character_chat_tab @@ -68,7 +67,7 @@ from App_Function_Libraries.Gradio_UI.Evaluations_Benchmarks_tab import create_geval_tab, create_infinite_bench_tab #from App_Function_Libraries.Local_LLM.Local_LLM_huggingface import create_huggingface_tab from App_Function_Libraries.Local_LLM.Local_LLM_ollama import create_ollama_tab -from App_Function_Libraries.RAG.RAG_QA_Chat_Notes import create_rag_qa_chat_notes_tab +from App_Function_Libraries.Gradio_UI.RAG_QA_Chat_Notes import create_rag_qa_chat_notes_tab # ####################################################################################################################### diff --git a/App_Function_Libraries/RAG/RAG_QA_Chat_Notes.py b/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py similarity index 65% rename from App_Function_Libraries/RAG/RAG_QA_Chat_Notes.py rename to App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py index bd3551a9..09752ecb 100644 --- a/App_Function_Libraries/RAG/RAG_QA_Chat_Notes.py +++ b/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py @@ -8,10 +8,9 @@ # # Local Imports from App_Function_Libraries.DB.RAG_QA_Chat_DB import save_message, add_keywords_to_conversation, \ - search_conversations_by_keywords, load_chat_history + search_conversations_by_keywords, load_chat_history, save_notes, get_notes, clear_notes, \ + add_keywords_to_note, execute_query, start_new_conversation from App_Function_Libraries.RAG.RAG_QA_Chat import rag_qa_chat - - # #################################################################################################### # @@ -82,30 +81,29 @@ def create_rag_qa_chat_notes_tab(): with gr.Column(scale=1): notes = gr.TextArea(label="Notes", placeholder="Enter your notes here...", lines=20) - save_notes = gr.Button("Save Notes") - clear_notes = gr.Button("Clear Notes") - - + keywords_for_notes = gr.Textbox(label="Keywords for Notes (comma-separated)", + placeholder="Enter keywords for the note", visible=True) + save_notes_btn = gr.Button("Save Notes") # Renamed to avoid conflict + clear_notes_btn = gr.Button("Clear Notes") # Renamed to avoid conflict loading_indicator = gr.HTML(visible=False) def rag_qa_chat_wrapper(message, history, state, context_source, existing_file, search_results, file_upload, convert_to_text, keywords, api_choice, use_query_rewriting): try: - conversation_id = state["conversation_id"] + conversation_id = state.value["conversation_id"] if not conversation_id: - conversation_id = start_new_conversation() + conversation_id = start_new_conversation("Untitled Conversation") # Provide a title or handle accordingly state = update_state(state, conversation_id=conversation_id) save_message(conversation_id, 'human', message) if keywords: - add_keywords_to_conversation(conversation_id, keywords.split(',')) + add_keywords_to_conversation(conversation_id, [kw.strip() for kw in keywords.split(',')]) - # Here you would implement your actual RAG logic - # FIXME - response = rag_qa_chat(message: str, history: List[Tuple[str, str]], context: Union[str, IO[str]], - api_choice: str) -> Tuple[List[Tuple[str, str]], str]: + # Implement your actual RAG logic here + response = "response"#rag_qa_chat(message, conversation_id, context_source, existing_file, search_results, + #file_upload, convert_to_text, api_choice, use_query_rewriting) save_message(conversation_id, 'ai', response) @@ -121,29 +119,31 @@ def rag_qa_chat_wrapper(message, history, state, context_source, existing_file, def load_conversation_history(selected_conversation_id, page, page_size, state): if selected_conversation_id: - history, total_pages, _ = load_chat_history(selected_conversation_id, page, page_size) - return history, total_pages, update_state(state, conversation_id=selected_conversation_id, page=page) - return [], 1, state + history, total_pages_val, _ = load_chat_history(selected_conversation_id, page, page_size) + notes_content = get_notes(selected_conversation_id) # Retrieve notes here + updated_state = update_state(state, conversation_id=selected_conversation_id, page=page) + return history, total_pages_val, updated_state, "\n".join(notes_content) + return [], 1, state, "" - def start_new_conversation(title, state): + def start_new_conversation_wrapper(title, state): new_conversation_id = start_new_conversation(title if title else "Untitled Conversation") return [], update_state(state, conversation_id=new_conversation_id, page=1) def update_state(state, **kwargs): - new_state = state.copy() + new_state = state.value.copy() new_state.update(kwargs) return new_state - def update_page(direction, current_page, total_pages): - new_page = max(1, min(current_page + direction, total_pages)) + def update_page(direction, current_page, total_pages_val): + new_page = max(1, min(current_page + direction, total_pages_val)) return new_page def update_context_source(choice): return { - existing_file: gr.update(visible=choice == "Existing File"), - prev_page_btn: gr.update(visible=choice == "Existing File"), - next_page_btn: gr.update(visible=choice == "Existing File"), - page_info: gr.update(visible=choice == "Existing File"), + existing_file: gr.update(visible=choice == "Select Existing File"), + prev_page_btn: gr.update(visible=choice == "Search Database"), + next_page_btn: gr.update(visible=choice == "Search Database"), + page_info: gr.update(visible=choice == "Search Database"), search_query: gr.update(visible=choice == "Search Database"), search_button: gr.update(visible=choice == "Search Database"), search_results: gr.update(visible=choice == "Search Database"), @@ -154,7 +154,7 @@ def update_context_source(choice): def perform_search(query): try: - results = search_conversations_by_keywords(query.split()) + results = search_conversations_by_keywords([kw.strip() for kw in query.split()]) return gr.update(choices=[f"{title} (ID: {id})" for id, title in results[0]]) except Exception as e: logging.error(f"Error performing search: {e}") @@ -164,12 +164,32 @@ def perform_search(query): def clear_chat_history(): return [], "" - def save_notes_function(notes): - # Implement saving notes functionality here - logging.info("Notes saved successfully!") - return notes + def save_notes_function(notes_content, keywords_content): + """Save the notes and associated keywords to the database.""" + conversation_id = state.value["conversation_id"] + if conversation_id and notes_content: + # Save the note + save_notes(conversation_id, notes_content) + + # Get the last inserted note ID + query = "SELECT id FROM rag_qa_notes WHERE conversation_id = ? ORDER BY timestamp DESC LIMIT 1" + note_id = execute_query(query, (conversation_id,))[0][0] + + if keywords_content: + add_keywords_to_note(note_id, [kw.strip() for kw in keywords_content.split(',')]) + + logging.info("Notes and keywords saved successfully!") + return notes_content + else: + logging.warning("No conversation ID or notes to save.") + return "" def clear_notes_function(): + """Clear notes for the current conversation.""" + conversation_id = state.value["conversation_id"] + if conversation_id: + clear_notes(conversation_id) + logging.info("Notes cleared successfully!") return "" # Event handlers @@ -183,43 +203,44 @@ def clear_notes_function(): load_conversation.change( load_conversation_history, inputs=[load_conversation, page_number, page_size, state], - outputs=[chatbot, total_pages, state] + outputs=[chatbot, total_pages, state, notes] ) new_conversation.click( - start_new_conversation, + start_new_conversation_wrapper, inputs=[conversation_title, state], outputs=[chatbot, state] ) - # Event handlers + # Pagination Event handlers prev_page_btn.click( update_page, - inputs=[gr.Number(-1, visible=False), page_number, total_pages], + inputs=[-1, page_number, total_pages], outputs=[page_number] ) next_page_btn.click( update_page, - inputs=[gr.Number(1, visible=False), page_number, total_pages], + inputs=[1, page_number, total_pages], outputs=[page_number] ) - context_source.change(update_context_source, context_source, - [existing_file, prev_page_btn, next_page_btn, page_info, search_query, search_button, - search_results, file_upload, convert_to_text, keywords]) + context_source.change(update_context_source, inputs=[context_source], + outputs=[existing_file, prev_page_btn, next_page_btn, page_info, + search_query, search_button, search_results, + file_upload, convert_to_text, keywords]) search_button.click(perform_search, inputs=[search_query], outputs=[search_results]) clear_chat.click(clear_chat_history, outputs=[chatbot, msg]) - save_notes.click(save_notes_function, inputs=[notes], outputs=[notes]) - clear_notes.click(clear_notes_function, outputs=[notes]) + save_notes_btn.click(save_notes_function, inputs=[notes, keywords_for_notes], outputs=[notes]) + clear_notes_btn.click(clear_notes_function, outputs=[notes]) return (context_source, existing_file, search_query, search_button, search_results, file_upload, convert_to_text, keywords, api_choice, use_query_rewriting, chatbot, msg, submit, clear_chat, - notes, save_notes, clear_notes, load_conversation, new_conversation, conversation_title, + notes, save_notes_btn, clear_notes_btn, load_conversation, new_conversation, conversation_title, prev_page_btn, next_page_btn, page_number, page_size, total_pages) # -# End of Rag_QA_Chat_Notes.py -#################################################################################################### \ No newline at end of file +# End of RAG_QA_Chat_Notes.py +#################################################################################################### diff --git a/App_Function_Libraries/RAG/RAG_QA_Chat.py b/App_Function_Libraries/RAG/RAG_QA_Chat.py index 24c60e52..fd3926cd 100644 --- a/App_Function_Libraries/RAG/RAG_QA_Chat.py +++ b/App_Function_Libraries/RAG/RAG_QA_Chat.py @@ -1,5 +1,5 @@ -# Podcast_tab.py -# Description: Gradio UI for ingesting podcasts into the database +# RAG_QA_Chat.py +# Description: Functions supporting the RAG QA Chat functionality # # Imports # diff --git a/Helper_Scripts/Installer_Scripts/Windows_Install_Update.bat b/Helper_Scripts/Installer_Scripts/Windows_Install_Update.bat index 3d545d27..ae02bc0c 100644 --- a/Helper_Scripts/Installer_Scripts/Windows_Install_Update.bat +++ b/Helper_Scripts/Installer_Scripts/Windows_Install_Update.bat @@ -155,6 +155,8 @@ powershell -Command "Expand-Archive -Path 'ffmpeg.zip' -DestinationPath 'ffmpeg' move ffmpeg\ffmpeg-master-latest-win64-gpl\bin\ffmpeg.exe . rmdir /s /q ffmpeg del ffmpeg.zip +mkdir .\Bin +move ffmpeg .\Bin\ goto :eof :cleanup diff --git a/README.md b/README.md index 6c4c3dce..2e79761f 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,9 @@ - **Windows:** `wget https://raw.githubusercontent.com/rmusser01/tldw/main/Helper_Scripts/Installer_Scripts/Windows_Install_Update.bat && wget https://raw.githubusercontent.com/rmusser01/tldw/main/Helper_Scripts/Installer_Scripts/Windows_Run_tldw.bat` - Then double-click the downloaded batch file `Windows_Install_Update.bat` to install it, and `Windows_Run_tldw.bat` to run it. - You should now have a web browser tab opened to `http://127.0.0.1:7860/` with the GUI for the app. + - If you don't have CUDA installed on your system and available in your system path, go here: https://github.com/Purfview/whisper-standalone-win/releases/download/Faster-Whisper-XXL/Faster-Whisper-XXL_r192.3.4_windows.7z + - Extract the two files named `cudnn_ops_infer64_8.dll` and `cudnn_cnn_infer64_8.dll` from the 7z file to the `tldw` directory, and then run the `Windows_Run_tldw.bat` file. + - This will allow you to use the faster whisper models with the app. Otherwise, you won't be able to perform transcription. - **Docker:** - There's a docker build for GPU use(Needs Nvidia CUDA Controller(?): https://github.com/rmusser01/tldw/blob/main/Helper_Scripts/Dockerfiles/tldw-nvidia_amd64_Dockerfile - and plain CPU use: https://github.com/rmusser01/tldw/blob/main/Helper_Scripts/Dockerfiles/tldw_Debian_cpu-Dockerfile diff --git a/requirements.txt b/requirements.txt index caae64a1..50ef360e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,8 @@ faster_whisper fire FlashRank fugashi -gradio +# well fuck gradio. again. +gradio==4.44.1 jieba Jinja2 joblib @@ -28,6 +29,7 @@ pandas Pillow playwright psycopg2 +psutil #psycopg2-binary pyannote.audio PyAudio From bf403f940c28a745aa36decad467bdf91b06d785 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 17 Oct 2024 12:32:08 -0700 Subject: [PATCH 05/17] Update RAG_QA_Chat_Notes.py --- App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py b/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py index 09752ecb..74964a0c 100644 --- a/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py +++ b/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py @@ -214,13 +214,14 @@ def clear_notes_function(): # Pagination Event handlers prev_page_btn.click( - update_page, - inputs=[-1, page_number, total_pages], + lambda current_page, total_pages_val: update_page(-1, current_page, total_pages_val), + inputs=[page_number, total_pages], outputs=[page_number] ) + next_page_btn.click( - update_page, - inputs=[1, page_number, total_pages], + lambda current_page, total_pages_val: update_page(1, current_page, total_pages_val), + inputs=[page_number, total_pages], outputs=[page_number] ) From ce621ba771e6cc01fe5953a83aeab73ccd742368 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 17 Oct 2024 12:34:46 -0700 Subject: [PATCH 06/17] Update RAG_QA_Chat_Notes.py --- App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py b/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py index 74964a0c..242ec60f 100644 --- a/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py +++ b/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py @@ -67,11 +67,6 @@ def create_rag_qa_chat_notes_tab(): conversation_title = gr.Textbox(label="Conversation Title", placeholder="Enter a title for the new conversation") - with gr.Row(): - page_number = gr.Number(value=1, label="Page", precision=0) - page_size = gr.Number(value=20, label="Items per page", precision=0) - total_pages = gr.Number(label="Total Pages", interactive=False) - with gr.Row(): with gr.Column(scale=2): chatbot = gr.Chatbot(height=500) From ad07a9ee3806063eafe55a83911354b7bb191759 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 17 Oct 2024 12:36:39 -0700 Subject: [PATCH 07/17] Update RAG_QA_Chat_Notes.py --- App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py b/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py index 242ec60f..f805441c 100644 --- a/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py +++ b/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py @@ -22,15 +22,15 @@ def create_rag_qa_chat_notes_tab(): state = gr.State({ "conversation_id": None, "page": 1, - "context_source": "All Files in the Database" + "context_source": "Entire Media Database", }) with gr.Row(): with gr.Column(scale=1): context_source = gr.Radio( - ["All Files in the Database", "Search Database", "Upload File"], + ["Entire Media Database", "Search Database", "Upload File"], label="Context Source", - value="All Files in the Database" + value="Entire Media Database" ) existing_file = gr.Dropdown(label="Select Existing File", choices=[], interactive=True) file_page = gr.State(value=1) From 28161ebde191e68d71dad47c106efd5c42326838 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 17 Oct 2024 17:52:25 -0700 Subject: [PATCH 08/17] Bugfix and an attempt at working around Gradio's bug for the Demo page.... App works fine local, but shits itself on huggingface spaces. --- .../Benchmarks_Evaluations/ms_g_eval.py | 2 +- App_Function_Libraries/DB/RAG_QA_Chat_DB.py | 24 +++++++ App_Function_Libraries/Gradio_Related.py | 67 +++++++++---------- .../Gradio_UI/RAG_QA_Chat_Notes.py | 1 + App_Function_Libraries/Gradio_UI/Utilities.py | 6 +- .../Local_LLM_Inference_Engine_Lib.py | 3 - 6 files changed, 62 insertions(+), 41 deletions(-) diff --git a/App_Function_Libraries/Benchmarks_Evaluations/ms_g_eval.py b/App_Function_Libraries/Benchmarks_Evaluations/ms_g_eval.py index 0ea424d7..a1738798 100644 --- a/App_Function_Libraries/Benchmarks_Evaluations/ms_g_eval.py +++ b/App_Function_Libraries/Benchmarks_Evaluations/ms_g_eval.py @@ -259,7 +259,7 @@ def run_geval(transcript: str, summary: str, api_key: str, api_name: str = None, def create_geval_tab(): - with gr.Tab("G-Eval"): + with gr.Tab("G-Eval", id="g-eval"): gr.Markdown("# G-Eval Summarization Evaluation") with gr.Row(): with gr.Column(): diff --git a/App_Function_Libraries/DB/RAG_QA_Chat_DB.py b/App_Function_Libraries/DB/RAG_QA_Chat_DB.py index bd30cc9f..972122be 100644 --- a/App_Function_Libraries/DB/RAG_QA_Chat_DB.py +++ b/App_Function_Libraries/DB/RAG_QA_Chat_DB.py @@ -2,11 +2,15 @@ # Description: This file contains the database operations for the RAG QA Chat + Notes system. # # Imports +import configparser import logging import re import sqlite3 from contextlib import contextmanager from datetime import datetime + +from App_Function_Libraries.Utils.Utils import get_project_relative_path, get_database_path + # # External Imports # @@ -15,7 +19,27 @@ ######################################################################################################################## # # Functions: +# FIXME - Setup properly and test/add documentation for its existence... +# Construct the path to the config file +config_path = get_project_relative_path('Config_Files/config.txt') + +# Read the config file +config = configparser.ConfigParser() +config.read(config_path) + +# Get the SQLite path from the config, or use the default if not specified +rag_qa_path = config.get('Database', 'rag_qa_db_path', fallback=get_database_path('RAG_QA_Chat.db')) + +# Get the backup path from the config, or use the default if not specified +rag_chat_backup_path = config.get('Database', 'backup_path', fallback='rag_database_backups') +rag_chat_backup_path = get_project_relative_path(rag_chat_backup_path) + +# Set the final paths +rag_qa_db_path = rag_qa_path +rag_qa_backup_dir = rag_chat_backup_path +print(f"RAG QA Chat Database path: {rag_qa_db_path}") +print(f"RAG QA Chat DB Backup directory: {rag_qa_backup_dir}") # Set up logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) diff --git a/App_Function_Libraries/Gradio_Related.py b/App_Function_Libraries/Gradio_Related.py index fb5a8aec..7f6243f0 100644 --- a/App_Function_Libraries/Gradio_Related.py +++ b/App_Function_Libraries/Gradio_Related.py @@ -270,7 +270,7 @@ def launch_ui(share_public=None, server_mode=False): gr.Markdown(f"# tl/dw: Your LLM-powered Research Multi-tool") gr.Markdown(f"(Using {db_type.capitalize()} Database)") with gr.Tabs(): - with gr.TabItem("Transcription / Summarization / Ingestion"): + with gr.TabItem("Transcription / Summarization / Ingestion", id="ingestion-grouping"): with gr.Tabs(): create_video_transcription_tab() create_audio_processing_tab() @@ -285,18 +285,18 @@ def launch_ui(share_public=None, server_mode=False): create_live_recording_tab() create_arxiv_tab() - with gr.TabItem("Text Search "): + with gr.TabItem("Text Search", id="text search"): create_search_tab() create_search_summaries_tab() - with gr.TabItem("RAG Chat+Notes"): + with gr.TabItem("RAG Chat+Notes", id="RAG Chat Notes group"): create_rag_qa_chat_notes_tab() - with gr.TabItem("RAG Search"): + with gr.TabItem("RAG Search", id="RAG Search grou"): create_rag_tab() create_rag_qa_chat_tab() - with gr.TabItem("Chat with an LLM"): + with gr.TabItem("Chat with an LLM", id="LLM Chat group"): create_chat_interface() create_chat_interface_stacked() create_chat_interface_multi_api() @@ -306,7 +306,7 @@ def launch_ui(share_public=None, server_mode=False): chat_workflows_tab() - with gr.TabItem("Character Chat"): + with gr.TabItem("Character Chat", id="character chat group"): with gr.Tabs(): create_character_card_interaction_tab() create_character_chat_mgmt_tab() @@ -317,7 +317,7 @@ def launch_ui(share_public=None, server_mode=False): create_export_characters_tab() - with gr.TabItem("View DB Items"): + with gr.TabItem("View DB Items", id="view db items group"): # This one works create_view_all_with_versions_tab() # This one is WIP @@ -325,7 +325,7 @@ def launch_ui(share_public=None, server_mode=False): create_prompt_view_tab() - with gr.TabItem("Prompts"): + with gr.TabItem("Prompts", id='view prompts group'): create_prompt_view_tab() create_prompt_search_tab() create_prompt_edit_tab() @@ -333,7 +333,7 @@ def launch_ui(share_public=None, server_mode=False): create_prompt_suggestion_tab() - with gr.TabItem("Manage / Edit Existing Items"): + with gr.TabItem("Manage / Edit Existing Items", id="manage group"): create_media_edit_tab() create_manage_items_tab() create_media_edit_and_clone_tab() @@ -341,32 +341,31 @@ def launch_ui(share_public=None, server_mode=False): #create_compare_transcripts_tab() - with gr.TabItem("Embeddings Management"): + with gr.TabItem("Embeddings Management", id="embeddings group"): create_embeddings_tab() create_view_embeddings_tab() create_purge_embeddings_tab() - with gr.TabItem("Writing Tools"): - with gr.Tabs(): - from App_Function_Libraries.Gradio_UI.Writing_tab import create_document_feedback_tab - create_document_feedback_tab() - from App_Function_Libraries.Gradio_UI.Writing_tab import create_grammar_style_check_tab - create_grammar_style_check_tab() - from App_Function_Libraries.Gradio_UI.Writing_tab import create_tone_adjustment_tab - create_tone_adjustment_tab() - from App_Function_Libraries.Gradio_UI.Writing_tab import create_creative_writing_tab - create_creative_writing_tab() - from App_Function_Libraries.Gradio_UI.Writing_tab import create_mikupad_tab - create_mikupad_tab() - - - with gr.TabItem("Keywords"): + with gr.TabItem("Writing Tools", id="writing_tools group"): + from App_Function_Libraries.Gradio_UI.Writing_tab import create_document_feedback_tab + create_document_feedback_tab() + from App_Function_Libraries.Gradio_UI.Writing_tab import create_grammar_style_check_tab + create_grammar_style_check_tab() + from App_Function_Libraries.Gradio_UI.Writing_tab import create_tone_adjustment_tab + create_tone_adjustment_tab() + from App_Function_Libraries.Gradio_UI.Writing_tab import create_creative_writing_tab + create_creative_writing_tab() + from App_Function_Libraries.Gradio_UI.Writing_tab import create_mikupad_tab + create_mikupad_tab() + + + with gr.TabItem("Keywords", id="keywords group"): create_view_keywords_tab() create_add_keyword_tab() create_delete_keyword_tab() create_export_keywords_tab() - with gr.TabItem("Import"): + with gr.TabItem("Import", id="import group"): create_import_item_tab() create_import_obsidian_vault_tab() create_import_single_prompt_tab() @@ -374,40 +373,40 @@ def launch_ui(share_public=None, server_mode=False): create_mediawiki_import_tab() create_mediawiki_config_tab() - with gr.TabItem("Export"): + with gr.TabItem("Export", id="export group"): create_export_tab() - with gr.TabItem("Backup Management"): + with gr.TabItem("Backup Management", id="backup group"): create_backup_tab() create_view_backups_tab() create_restore_backup_tab() - with gr.TabItem("Utilities"): + with gr.TabItem("Utilities", id="util group"): create_utilities_yt_video_tab() create_utilities_yt_audio_tab() create_utilities_yt_timestamp_tab() - with gr.TabItem("Local LLM"): + with gr.TabItem("Local LLM", id="local llm group"): create_chat_with_llamafile_tab() create_ollama_tab() #create_huggingface_tab() - with gr.TabItem("Trashcan"): + with gr.TabItem("Trashcan", id="trashcan group"): create_search_and_mark_trash_tab() create_view_trash_tab() create_delete_trash_tab() create_empty_trash_tab() - with gr.TabItem("Evaluations"): + with gr.TabItem("Evaluations", id="eval"): create_geval_tab() create_infinite_bench_tab() # FIXME #create_mmlu_pro_tab() - with gr.TabItem("Introduction/Help"): + with gr.TabItem("Introduction/Help", id="introduction group"): create_introduction_tab() - with gr.TabItem("Config Editor"): + with gr.TabItem("Config Editor", id="config group"): create_config_editor_tab() # Launch the interface diff --git a/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py b/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py index f805441c..de03932d 100644 --- a/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py +++ b/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py @@ -62,6 +62,7 @@ def create_rag_qa_chat_notes_tab(): ) use_query_rewriting = gr.Checkbox(label="Use Query Rewriting", value=True) + # FIXME - add load conversations button load_conversation = gr.Dropdown(label="Load Conversation", choices=[]) new_conversation = gr.Button("New Conversation") conversation_title = gr.Textbox(label="Conversation Title", diff --git a/App_Function_Libraries/Gradio_UI/Utilities.py b/App_Function_Libraries/Gradio_UI/Utilities.py index 4a4ba3bd..f87a18fb 100644 --- a/App_Function_Libraries/Gradio_UI/Utilities.py +++ b/App_Function_Libraries/Gradio_UI/Utilities.py @@ -10,7 +10,7 @@ def create_utilities_yt_video_tab(): - with gr.Tab("YouTube Video Downloader"): + with gr.Tab("YouTube Video Downloader", id='youtube_dl'): with gr.Row(): with gr.Column(): gr.Markdown( @@ -28,7 +28,7 @@ def create_utilities_yt_video_tab(): ) def create_utilities_yt_audio_tab(): - with gr.Tab("YouTube Audio Downloader"): + with gr.Tab("YouTube Audio Downloader", id="youtube audio downloader"): with gr.Row(): with gr.Column(): gr.Markdown( @@ -48,7 +48,7 @@ def create_utilities_yt_audio_tab(): ) def create_utilities_yt_timestamp_tab(): - with gr.Tab("YouTube Timestamp URL Generator"): + with gr.Tab("YouTube Timestamp URL Generator", id="timestamp-gen"): gr.Markdown("## Generate YouTube URL with Timestamp") with gr.Row(): with gr.Column(): diff --git a/App_Function_Libraries/Local_LLM/Local_LLM_Inference_Engine_Lib.py b/App_Function_Libraries/Local_LLM/Local_LLM_Inference_Engine_Lib.py index 6b67eff2..0546903b 100644 --- a/App_Function_Libraries/Local_LLM/Local_LLM_Inference_Engine_Lib.py +++ b/App_Function_Libraries/Local_LLM/Local_LLM_Inference_Engine_Lib.py @@ -286,9 +286,6 @@ def start_llamafile( if numa_checked: command.append('--numa') - if server_timeout_value is not None: - command.extend(['--to', str(server_timeout_value)]) - if host_checked and host_value: command.extend(['--host', host_value]) From bf1de2e0caf61f6360bba58ac679a9b674c740fb Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 17 Oct 2024 17:59:18 -0700 Subject: [PATCH 09/17] Update RAG_QA_Chat_DB.py --- App_Function_Libraries/DB/RAG_QA_Chat_DB.py | 77 ++++++++++----------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/App_Function_Libraries/DB/RAG_QA_Chat_DB.py b/App_Function_Libraries/DB/RAG_QA_Chat_DB.py index 972122be..4e93789d 100644 --- a/App_Function_Libraries/DB/RAG_QA_Chat_DB.py +++ b/App_Function_Libraries/DB/RAG_QA_Chat_DB.py @@ -6,6 +6,7 @@ import logging import re import sqlite3 +import uuid from contextlib import contextmanager from datetime import datetime @@ -19,7 +20,6 @@ ######################################################################################################################## # # Functions: -# FIXME - Setup properly and test/add documentation for its existence... # Construct the path to the config file config_path = get_project_relative_path('Config_Files/config.txt') @@ -28,18 +28,13 @@ config.read(config_path) # Get the SQLite path from the config, or use the default if not specified -rag_qa_path = config.get('Database', 'rag_qa_db_path', fallback=get_database_path('RAG_QA_Chat.db')) - -# Get the backup path from the config, or use the default if not specified -rag_chat_backup_path = config.get('Database', 'backup_path', fallback='rag_database_backups') -rag_chat_backup_path = get_project_relative_path(rag_chat_backup_path) - -# Set the final paths -rag_qa_db_path = rag_qa_path -rag_qa_backup_dir = rag_chat_backup_path +if config.has_section('Database') and config.has_option('Database', 'rag_qa_db_path'): + rag_qa_db_path = config.get('Database', 'rag_qa_db_path') +else: + rag_qa_db_path = get_database_path('RAG_QA_Chat.db') print(f"RAG QA Chat Database path: {rag_qa_db_path}") -print(f"RAG QA Chat DB Backup directory: {rag_qa_backup_dir}") + # Set up logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) @@ -135,7 +130,7 @@ # Database connection management @contextmanager def get_db_connection(): - conn = sqlite3.connect('rag_qa_chat.db') + conn = sqlite3.connect(rag_qa_db_path) try: yield conn finally: @@ -145,16 +140,15 @@ def get_db_connection(): def transaction(): with get_db_connection() as conn: try: - conn.execute('BEGIN TRANSACTION') yield conn conn.commit() except Exception: conn.rollback() raise -def execute_query(query, params=None, transaction_conn=None): - if transaction_conn: - cursor = transaction_conn.cursor() +def execute_query(query, params=None, conn=None): + if conn: + cursor = conn.cursor() if params: cursor.execute(query, params) else: @@ -202,11 +196,11 @@ def validate_collection_name(name): return name.strip() # Core functions -def add_keyword(keyword): +def add_keyword(keyword, conn=None): try: validated_keyword = validate_keyword(keyword) query = "INSERT OR IGNORE INTO rag_qa_keywords (keyword) VALUES (?)" - execute_query(query, (validated_keyword,)) + execute_query(query, (validated_keyword,), conn) logger.info(f"Keyword '{validated_keyword}' added successfully") except ValueError as e: logger.error(f"Invalid keyword: {e}") @@ -234,7 +228,7 @@ def add_keyword_to_collection(collection_name, keyword): validated_keyword = validate_keyword(keyword) with transaction() as conn: - add_keyword(validated_keyword) + add_keyword(validated_keyword, conn) query = ''' INSERT INTO rag_qa_collection_keywords (collection_id, keyword_id) @@ -259,9 +253,7 @@ def add_keywords_to_conversation(conversation_id, keywords): with transaction() as conn: for keyword in keywords: validated_keyword = validate_keyword(keyword) - - query = "INSERT OR IGNORE INTO rag_qa_keywords (keyword) VALUES (?)" - execute_query(query, (validated_keyword,), conn) + add_keyword(validated_keyword, conn) query = ''' INSERT INTO rag_qa_conversation_keywords (conversation_id, keyword_id) @@ -349,14 +341,15 @@ def add_keywords_to_note(note_id, keywords): with transaction() as conn: for keyword in keywords: validated_keyword = validate_keyword(keyword) - - # Insert the keyword into the rag_qa_keywords table if it doesn't exist - query = "INSERT OR IGNORE INTO rag_qa_keywords (keyword) VALUES (?)" - execute_query(query, (validated_keyword,), conn) + add_keyword(validated_keyword, conn) # Retrieve the keyword ID query = "SELECT id FROM rag_qa_keywords WHERE keyword = ?" - keyword_id = execute_query(query, (validated_keyword,), conn)[0][0] + result = execute_query(query, (validated_keyword,), conn) + if result: + keyword_id = result[0][0] + else: + raise Exception(f"Keyword '{validated_keyword}' not found after insertion") # Link the note and keyword query = "INSERT INTO rag_qa_note_keywords (note_id, keyword_id) VALUES (?, ?)" @@ -396,9 +389,14 @@ def clear_keywords_from_note(note_id): def save_message(conversation_id, role, content): try: - query = "INSERT INTO rag_qa_chats (conversation_id, timestamp, role, content) VALUES (?, ?, ?, ?)" timestamp = datetime.now().isoformat() + query = "INSERT INTO rag_qa_chats (conversation_id, timestamp, role, content) VALUES (?, ?, ?, ?)" execute_query(query, (conversation_id, timestamp, role, content)) + + # Update last_updated in conversation_metadata + update_query = "UPDATE conversation_metadata SET last_updated = ? WHERE conversation_id = ?" + execute_query(update_query, (timestamp, conversation_id)) + logger.info(f"Message saved for conversation '{conversation_id}'") except Exception as e: logger.error(f"Error saving message for conversation '{conversation_id}': {e}") @@ -406,9 +404,9 @@ def save_message(conversation_id, role, content): def start_new_conversation(title="Untitled Conversation"): try: - conversation_id = datetime.now().isoformat() + conversation_id = str(uuid.uuid4()) query = "INSERT INTO conversation_metadata (conversation_id, created_at, last_updated, title) VALUES (?, ?, ?, ?)" - now = datetime.now() + now = datetime.now().isoformat() execute_query(query, (conversation_id, now, now, title)) logger.info(f"New conversation '{conversation_id}' started with title '{title}'") return conversation_id @@ -422,14 +420,16 @@ def get_paginated_results(query, params=None, page=1, page_size=20): offset = (page - 1) * page_size paginated_query = f"{query} LIMIT ? OFFSET ?" if params: - params = tuple(params) + (page_size, offset) + paginated_params = params + (page_size, offset) else: - params = (page_size, offset) + paginated_params = (page_size, offset) - result = execute_query(paginated_query, params) + result = execute_query(paginated_query, paginated_params) - count_query = f"SELECT COUNT(*) FROM ({query})" - total_count = execute_query(count_query, params[:-2] if params else None)[0][0] + count_query = f"SELECT COUNT(*) FROM ({query}) AS total" + count_params = params if params else () + + total_count = execute_query(count_query, count_params)[0][0] total_pages = (total_count + page_size - 1) // page_size @@ -460,7 +460,7 @@ def search_conversations_by_keywords(keywords, page=1, page_size=20): JOIN rag_qa_keywords k ON ck.keyword_id = k.id WHERE k.keyword IN ({placeholders}) ''' - results, total_pages, total_count = get_paginated_results(query, keywords, page, page_size) + results, total_pages, total_count = get_paginated_results(query, tuple(keywords), page, page_size) logger.info( f"Found {total_count} conversations matching keywords: {', '.join(keywords)} (page {page} of {total_pages})") return results, total_pages, total_count @@ -472,10 +472,9 @@ def load_chat_history(conversation_id, page=1, page_size=50): try: query = "SELECT role, content FROM rag_qa_chats WHERE conversation_id = ? ORDER BY timestamp" results, total_pages, total_count = get_paginated_results(query, (conversation_id,), page, page_size) - history = [(msg[1] if msg[0] == 'human' else None, msg[1] if msg[0] == 'ai' else None) for msg in results] logger.info( - f"Loaded {len(history)} messages for conversation '{conversation_id}' (page {page} of {total_pages})") - return history, total_pages, total_count + f"Loaded {len(results)} messages for conversation '{conversation_id}' (page {page} of {total_pages})") + return results, total_pages, total_count except Exception as e: logger.error(f"Error loading chat history for conversation '{conversation_id}': {e}") raise From 4479810fb8f64e7ae9ea998212b277dd7635980c Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 17 Oct 2024 18:01:22 -0700 Subject: [PATCH 10/17] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2e79761f..8ecbd3b3 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ ## All Automated. All Local. All Yours. -### [Public Demo on HuggingFace Spaces](https://huggingface.co/spaces/oceansweep/Vid-Summarizer/?__theme=dark) +### [Public Demo on HuggingFace Spaces](https://huggingface.co/spaces/oceansweep/Vid-Summarizer/?__theme=dark) - Demo is broken due to a bug in Huggingface spaces/Gradio - **Please Note:** YouTube blocks requests from the demo. You have to provide a logged-in session cookie to bypass it :frowning_face: - Placeholder content is included for the demo. HuggingFace API is also setup in it, so you can select that as your API.) From e4dc41c9e5162459ded9f740b2799f503ad40603 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 17 Oct 2024 18:21:44 -0700 Subject: [PATCH 11/17] well maybe this will work around the gradio bug btw fuck gradio --- App_Function_Libraries/Gradio_Related.py | 55 +++++++++---------- App_Function_Libraries/Gradio_UI/Arxiv_tab.py | 2 +- .../Gradio_UI/Audio_ingestion_tab.py | 2 +- .../Gradio_UI/Backup_Functionality.py | 6 +- .../Gradio_UI/Book_Ingestion_tab.py | 2 +- .../Gradio_UI/Character_Chat_tab.py | 15 ++--- .../Gradio_UI/Character_interaction_tab.py | 4 +- .../Gradio_UI/Chat_Workflows.py | 2 +- App_Function_Libraries/Gradio_UI/Chat_ui.py | 14 ++--- .../Gradio_UI/Config_tab.py | 2 +- .../Gradio_UI/Embeddings_tab.py | 6 +- .../Gradio_UI/Evaluations_Benchmarks_tab.py | 4 +- .../Gradio_UI/Explain_summarize_tab.py | 2 +- .../Gradio_UI/Import_Functionality.py | 8 +-- .../Gradio_UI/Introduction_tab.py | 2 +- App_Function_Libraries/Gradio_UI/Keywords.py | 8 +-- .../Gradio_UI/Live_Recording.py | 2 +- .../Gradio_UI/Llamafile_tab.py | 2 +- .../Gradio_UI/MMLU_Pro_tab.py | 2 +- .../Gradio_UI/Media_edit.py | 8 +-- .../Gradio_UI/Media_wiki_tab.py | 2 +- .../Gradio_UI/PDF_ingestion_tab.py | 4 +- .../Gradio_UI/Plaintext_tab_import.py | 2 +- .../Gradio_UI/Podcast_tab.py | 4 +- .../Gradio_UI/Prompt_Suggestion_tab.py | 2 +- .../Gradio_UI/RAG_Chat_tab.py | 2 +- .../Gradio_UI/RAG_QA_Chat_Notes.py | 2 +- .../Gradio_UI/RAG_QA_Chat_tab.py | 2 +- .../Gradio_UI/Re_summarize_tab.py | 2 +- .../Gradio_UI/Search_Tab.py | 6 +- .../Gradio_UI/Transcript_comparison.py | 2 +- App_Function_Libraries/Gradio_UI/Trash.py | 8 +-- App_Function_Libraries/Gradio_UI/Utilities.py | 6 +- .../Gradio_UI/Video_transcription_tab.py | 2 +- .../Gradio_UI/View_DB_Items_tab.py | 6 +- App_Function_Libraries/Gradio_UI/View_tab.py | 2 +- .../Gradio_UI/Website_scraping_tab.py | 2 +- .../Gradio_UI/Writing_tab.py | 10 ++-- 38 files changed, 107 insertions(+), 107 deletions(-) diff --git a/App_Function_Libraries/Gradio_Related.py b/App_Function_Libraries/Gradio_Related.py index 7f6243f0..7ca2095c 100644 --- a/App_Function_Libraries/Gradio_Related.py +++ b/App_Function_Libraries/Gradio_Related.py @@ -270,7 +270,7 @@ def launch_ui(share_public=None, server_mode=False): gr.Markdown(f"# tl/dw: Your LLM-powered Research Multi-tool") gr.Markdown(f"(Using {db_type.capitalize()} Database)") with gr.Tabs(): - with gr.TabItem("Transcription / Summarization / Ingestion", id="ingestion-grouping"): + with gr.TabItem("Transcription / Summarization / Ingestion", id="ingestion-grouping", visible=True): with gr.Tabs(): create_video_transcription_tab() create_audio_processing_tab() @@ -285,18 +285,18 @@ def launch_ui(share_public=None, server_mode=False): create_live_recording_tab() create_arxiv_tab() - with gr.TabItem("Text Search", id="text search"): + with gr.TabItem("Text Search", id="text search", visible=True): create_search_tab() create_search_summaries_tab() - with gr.TabItem("RAG Chat+Notes", id="RAG Chat Notes group"): + with gr.TabItem("RAG Chat+Notes", id="RAG Chat Notes group", visible=True): create_rag_qa_chat_notes_tab() - with gr.TabItem("RAG Search", id="RAG Search grou"): + with gr.TabItem("RAG Search", id="RAG Search group", visible=True): create_rag_tab() create_rag_qa_chat_tab() - with gr.TabItem("Chat with an LLM", id="LLM Chat group"): + with gr.TabItem("Chat with an LLM", id="LLM Chat group", visible=True): create_chat_interface() create_chat_interface_stacked() create_chat_interface_multi_api() @@ -306,18 +306,17 @@ def launch_ui(share_public=None, server_mode=False): chat_workflows_tab() - with gr.TabItem("Character Chat", id="character chat group"): - with gr.Tabs(): - create_character_card_interaction_tab() - create_character_chat_mgmt_tab() - create_custom_character_card_tab() - create_character_card_validation_tab() - create_multiple_character_chat_tab() - create_narrator_controlled_conversation_tab() - create_export_characters_tab() + with gr.TabItem("Character Chat", id="character chat group", visible=True): + create_character_card_interaction_tab() + create_character_chat_mgmt_tab() + create_custom_character_card_tab() + create_character_card_validation_tab() + create_multiple_character_chat_tab() + create_narrator_controlled_conversation_tab() + create_export_characters_tab() - with gr.TabItem("View DB Items", id="view db items group"): + with gr.TabItem("View DB Items", id="view db items group", visible=True): # This one works create_view_all_with_versions_tab() # This one is WIP @@ -325,7 +324,7 @@ def launch_ui(share_public=None, server_mode=False): create_prompt_view_tab() - with gr.TabItem("Prompts", id='view prompts group'): + with gr.TabItem("Prompts", id='view prompts group', visible=True): create_prompt_view_tab() create_prompt_search_tab() create_prompt_edit_tab() @@ -333,7 +332,7 @@ def launch_ui(share_public=None, server_mode=False): create_prompt_suggestion_tab() - with gr.TabItem("Manage / Edit Existing Items", id="manage group"): + with gr.TabItem("Manage / Edit Existing Items", id="manage group", visible=True): create_media_edit_tab() create_manage_items_tab() create_media_edit_and_clone_tab() @@ -341,12 +340,12 @@ def launch_ui(share_public=None, server_mode=False): #create_compare_transcripts_tab() - with gr.TabItem("Embeddings Management", id="embeddings group"): + with gr.TabItem("Embeddings Management", id="embeddings group", visible=True): create_embeddings_tab() create_view_embeddings_tab() create_purge_embeddings_tab() - with gr.TabItem("Writing Tools", id="writing_tools group"): + with gr.TabItem("Writing Tools", id="writing_tools group", visible=True): from App_Function_Libraries.Gradio_UI.Writing_tab import create_document_feedback_tab create_document_feedback_tab() from App_Function_Libraries.Gradio_UI.Writing_tab import create_grammar_style_check_tab @@ -359,13 +358,13 @@ def launch_ui(share_public=None, server_mode=False): create_mikupad_tab() - with gr.TabItem("Keywords", id="keywords group"): + with gr.TabItem("Keywords", id="keywords group", visible=True): create_view_keywords_tab() create_add_keyword_tab() create_delete_keyword_tab() create_export_keywords_tab() - with gr.TabItem("Import", id="import group"): + with gr.TabItem("Import", id="import group", visible=True): create_import_item_tab() create_import_obsidian_vault_tab() create_import_single_prompt_tab() @@ -373,37 +372,37 @@ def launch_ui(share_public=None, server_mode=False): create_mediawiki_import_tab() create_mediawiki_config_tab() - with gr.TabItem("Export", id="export group"): + with gr.TabItem("Export", id="export group", visible=True): create_export_tab() - with gr.TabItem("Backup Management", id="backup group"): + with gr.TabItem("Backup Management", id="backup group", visible=True): create_backup_tab() create_view_backups_tab() create_restore_backup_tab() - with gr.TabItem("Utilities", id="util group"): + with gr.TabItem("Utilities", id="util group", visible=True): create_utilities_yt_video_tab() create_utilities_yt_audio_tab() create_utilities_yt_timestamp_tab() - with gr.TabItem("Local LLM", id="local llm group"): + with gr.TabItem("Local LLM", id="local llm group", visible=True): create_chat_with_llamafile_tab() create_ollama_tab() #create_huggingface_tab() - with gr.TabItem("Trashcan", id="trashcan group"): + with gr.TabItem("Trashcan", id="trashcan group", visible=True): create_search_and_mark_trash_tab() create_view_trash_tab() create_delete_trash_tab() create_empty_trash_tab() - with gr.TabItem("Evaluations", id="eval"): + with gr.TabItem("Evaluations", id="eval", visible=True): create_geval_tab() create_infinite_bench_tab() # FIXME #create_mmlu_pro_tab() - with gr.TabItem("Introduction/Help", id="introduction group"): + with gr.TabItem("Introduction/Help", id="introduction group", visible=True): create_introduction_tab() with gr.TabItem("Config Editor", id="config group"): diff --git a/App_Function_Libraries/Gradio_UI/Arxiv_tab.py b/App_Function_Libraries/Gradio_UI/Arxiv_tab.py index 3c052e8d..530edefc 100644 --- a/App_Function_Libraries/Gradio_UI/Arxiv_tab.py +++ b/App_Function_Libraries/Gradio_UI/Arxiv_tab.py @@ -20,7 +20,7 @@ # Functions: def create_arxiv_tab(): - with gr.TabItem("Arxiv Search & Ingest"): + with gr.TabItem("Arxiv Search & Ingest", visible=True): gr.Markdown("# arXiv Search, Browse, Download, and Ingest") gr.Markdown("#### Thank you to arXiv for use of its open access interoperability.") with gr.Row(): diff --git a/App_Function_Libraries/Gradio_UI/Audio_ingestion_tab.py b/App_Function_Libraries/Gradio_UI/Audio_ingestion_tab.py index c2f64663..0a785631 100644 --- a/App_Function_Libraries/Gradio_UI/Audio_ingestion_tab.py +++ b/App_Function_Libraries/Gradio_UI/Audio_ingestion_tab.py @@ -20,7 +20,7 @@ # Functions: def create_audio_processing_tab(): - with gr.TabItem("Audio File Transcription + Summarization"): + with gr.TabItem("Audio File Transcription + Summarization", visible=True): gr.Markdown("# Transcribe & Summarize Audio Files from URLs or Local Files!") with gr.Row(): with gr.Column(): diff --git a/App_Function_Libraries/Gradio_UI/Backup_Functionality.py b/App_Function_Libraries/Gradio_UI/Backup_Functionality.py index 6400dd79..672975da 100644 --- a/App_Function_Libraries/Gradio_UI/Backup_Functionality.py +++ b/App_Function_Libraries/Gradio_UI/Backup_Functionality.py @@ -34,7 +34,7 @@ def restore_backup(backup_name: str) -> str: def create_backup_tab(): - with gr.Tab("Create Backup"): + with gr.Tab("Create Backup", visible=True): gr.Markdown("# Create a backup of the database") gr.Markdown("This will create a backup of the database in the backup directory(the default backup directory is `/tldw_DB_Backups/')") with gr.Row(): @@ -46,7 +46,7 @@ def create_backup_tab(): def create_view_backups_tab(): - with gr.TabItem("View Backups"): + with gr.TabItem("View Backups", visible=True): gr.Markdown("# Browse available backups") with gr.Row(): with gr.Column(): @@ -57,7 +57,7 @@ def create_view_backups_tab(): def create_restore_backup_tab(): - with gr.TabItem("Restore Backup"): + with gr.TabItem("Restore Backup", visible=True): gr.Markdown("# Restore a backup of the database") with gr.Column(): backup_input = gr.Textbox(label="Backup Filename") diff --git a/App_Function_Libraries/Gradio_UI/Book_Ingestion_tab.py b/App_Function_Libraries/Gradio_UI/Book_Ingestion_tab.py index d4e1b298..28e60b09 100644 --- a/App_Function_Libraries/Gradio_UI/Book_Ingestion_tab.py +++ b/App_Function_Libraries/Gradio_UI/Book_Ingestion_tab.py @@ -22,7 +22,7 @@ def create_import_book_tab(): - with gr.TabItem("Ebook(epub) Files"): + with gr.TabItem("Ebook(epub) Files", visible=True): with gr.Row(): with gr.Column(): gr.Markdown("# Import .epub files") diff --git a/App_Function_Libraries/Gradio_UI/Character_Chat_tab.py b/App_Function_Libraries/Gradio_UI/Character_Chat_tab.py index 882de6db..e5836d4b 100644 --- a/App_Function_Libraries/Gradio_UI/Character_Chat_tab.py +++ b/App_Function_Libraries/Gradio_UI/Character_Chat_tab.py @@ -254,7 +254,7 @@ def export_all_characters(): # Gradio tabs def create_character_card_interaction_tab(): - with gr.TabItem("Chat with a Character Card"): + with gr.TabItem("Chat with a Character Card", visible=True): gr.Markdown("# Chat with a Character Card") with gr.Row(): with gr.Column(scale=1): @@ -1025,7 +1025,7 @@ def answer_for_me( def create_character_chat_mgmt_tab(): - with gr.TabItem("Character and Chat Management"): + with gr.TabItem("Character and Chat Management", visible=True): gr.Markdown("# Character and Chat Management") with gr.Row(): @@ -1063,12 +1063,12 @@ def create_character_chat_mgmt_tab(): conversation_mapping = gr.State({}) with gr.Tabs(): - with gr.TabItem("Edit"): + with gr.TabItem("Edit", visible=True): chat_content = gr.TextArea(label="Chat/Character Content (JSON)", lines=20, max_lines=50) save_button = gr.Button("Save Changes") delete_button = gr.Button("Delete Conversation/Character", variant="stop") - with gr.TabItem("Preview"): + with gr.TabItem("Preview", visible=True): chat_preview = gr.HTML(label="Chat/Character Preview") result_message = gr.Markdown("") @@ -1380,7 +1380,7 @@ def import_multiple_characters(files): ) def create_custom_character_card_tab(): - with gr.TabItem("Create a New Character Card"): + with gr.TabItem("Create a New Character Card", visible=True): gr.Markdown("# Create a New Character Card (v2)") with gr.Row(): @@ -1630,7 +1630,7 @@ def download_character_card_as_image( #v1 def create_character_card_validation_tab(): - with gr.TabItem("Validate Character Card"): + with gr.TabItem("Validate Character Card", visible=True): gr.Markdown("# Validate Character Card (v2)") gr.Markdown("Upload a character card (PNG, WEBP, or JSON) to validate whether it conforms to the Character Card V2 specification.") @@ -1786,7 +1786,7 @@ def validate_v2_card(card_data): def create_export_characters_tab(): - with gr.TabItem("Export Characters"): + with gr.TabItem("Export Characters", visible=True): gr.Markdown("# Export Characters") gr.Markdown("Export character cards individually as JSON files or all together as a ZIP file.") @@ -1808,6 +1808,7 @@ def create_export_characters_tab(): export_output = gr.File(label="Exported Character(s)", interactive=False) export_status = gr.Markdown("") +# FIXME def export_single_character_wrapper(character_selection): file_path, status_message = export_single_character(character_selection) if file_path: diff --git a/App_Function_Libraries/Gradio_UI/Character_interaction_tab.py b/App_Function_Libraries/Gradio_UI/Character_interaction_tab.py index 1d2b3a57..0e629def 100644 --- a/App_Function_Libraries/Gradio_UI/Character_interaction_tab.py +++ b/App_Function_Libraries/Gradio_UI/Character_interaction_tab.py @@ -253,7 +253,7 @@ def character_interaction(character1: str, character2: str, api_endpoint: str, a def create_multiple_character_chat_tab(): - with gr.TabItem("Multi-Character Chat"): + with gr.TabItem("Multi-Character Chat", visible=True): characters, conversation, current_character, other_character = character_interaction_setup() with gr.Blocks() as character_interaction: @@ -393,7 +393,7 @@ def take_turn_with_error_handling(conversation, current_index, char1, char2, cha # From `Fuzzlewumper` on Reddit. def create_narrator_controlled_conversation_tab(): - with gr.TabItem("Narrator-Controlled Conversation"): + with gr.TabItem("Narrator-Controlled Conversation", visible=True): gr.Markdown("# Narrator-Controlled Conversation") with gr.Row(): diff --git a/App_Function_Libraries/Gradio_UI/Chat_Workflows.py b/App_Function_Libraries/Gradio_UI/Chat_Workflows.py index 198acc0a..8ad2ad22 100644 --- a/App_Function_Libraries/Gradio_UI/Chat_Workflows.py +++ b/App_Function_Libraries/Gradio_UI/Chat_Workflows.py @@ -24,7 +24,7 @@ def chat_workflows_tab(): - with gr.TabItem("Chat Workflows"): + with gr.TabItem("Chat Workflows", visible=True): gr.Markdown("# Workflows using LLMs") chat_history = gr.State([]) media_content = gr.State({}) diff --git a/App_Function_Libraries/Gradio_UI/Chat_ui.py b/App_Function_Libraries/Gradio_UI/Chat_ui.py index fed68304..1ccd7426 100644 --- a/App_Function_Libraries/Gradio_UI/Chat_ui.py +++ b/App_Function_Libraries/Gradio_UI/Chat_ui.py @@ -206,7 +206,7 @@ def create_chat_interface(): font-size: 14px !important; } """ - with gr.TabItem("Remote LLM Chat (Horizontal)"): + with gr.TabItem("Remote LLM Chat (Horizontal)", visible=True): gr.Markdown("# Chat with a designated LLM Endpoint, using your selected item as starting context") chat_history = gr.State([]) media_content = gr.State({}) @@ -417,7 +417,7 @@ def create_chat_interface_stacked(): font-size: 14px !important; } """ - with gr.TabItem("Remote LLM Chat - Stacked"): + with gr.TabItem("Remote LLM Chat - Stacked", visible=True): gr.Markdown("# Stacked Chat") chat_history = gr.State([]) media_content = gr.State({}) @@ -580,7 +580,7 @@ def create_chat_interface_multi_api(): overflow-y: auto; } """ - with gr.TabItem("One Prompt - Multiple APIs"): + with gr.TabItem("One Prompt - Multiple APIs", visible=True): gr.Markdown("# One Prompt but Multiple APIs Chat Interface") with gr.Row(): @@ -759,7 +759,7 @@ def create_chat_interface_four(): } """ - with gr.TabItem("Four Independent API Chats"): + with gr.TabItem("Four Independent API Chats", visible=True): gr.Markdown("# Four Independent API Chat Interfaces") with gr.Row(): @@ -956,7 +956,7 @@ def chat_wrapper_single(message, chat_history, chatbot, api_endpoint, api_key, t # FIXME - Finish implementing functions + testing/valdidation def create_chat_management_tab(): - with gr.TabItem("Chat Management"): + with gr.TabItem("Chat Management", visible=True): gr.Markdown("# Chat Management") with gr.Row(): @@ -967,12 +967,12 @@ def create_chat_management_tab(): conversation_mapping = gr.State({}) with gr.Tabs(): - with gr.TabItem("Edit"): + with gr.TabItem("Edit", visible=True): chat_content = gr.TextArea(label="Chat Content (JSON)", lines=20, max_lines=50) save_button = gr.Button("Save Changes") delete_button = gr.Button("Delete Conversation", variant="stop") - with gr.TabItem("Preview"): + with gr.TabItem("Preview", visible=True): chat_preview = gr.HTML(label="Chat Preview") result_message = gr.Markdown("") diff --git a/App_Function_Libraries/Gradio_UI/Config_tab.py b/App_Function_Libraries/Gradio_UI/Config_tab.py index 39a3c618..cf6631e5 100644 --- a/App_Function_Libraries/Gradio_UI/Config_tab.py +++ b/App_Function_Libraries/Gradio_UI/Config_tab.py @@ -25,7 +25,7 @@ def save_config_from_text(text): def create_config_editor_tab(): - with gr.TabItem("Edit Config"): + with gr.TabItem("Edit Config", visible=True): gr.Markdown("# Edit Configuration File") with gr.Row(): diff --git a/App_Function_Libraries/Gradio_UI/Embeddings_tab.py b/App_Function_Libraries/Gradio_UI/Embeddings_tab.py index 7f5a3bf0..a12e1032 100644 --- a/App_Function_Libraries/Gradio_UI/Embeddings_tab.py +++ b/App_Function_Libraries/Gradio_UI/Embeddings_tab.py @@ -22,7 +22,7 @@ # Functions: def create_embeddings_tab(): - with gr.TabItem("Create Embeddings"): + with gr.TabItem("Create Embeddings", visible=True): gr.Markdown("# Create Embeddings for All Content") with gr.Row(): @@ -185,7 +185,7 @@ def create_all_embeddings(provider, hf_model, openai_model, custom_model, api_ur def create_view_embeddings_tab(): - with gr.TabItem("View/Update Embeddings"): + with gr.TabItem("View/Update Embeddings", visible=True): gr.Markdown("# View and Update Embeddings") item_mapping = gr.State({}) with gr.Row(): @@ -475,7 +475,7 @@ def create_new_embedding_for_item(selected_item, provider, hf_model, openai_mode def create_purge_embeddings_tab(): - with gr.TabItem("Purge Embeddings"): + with gr.TabItem("Purge Embeddings", visible=True): gr.Markdown("# Purge Embeddings") with gr.Row(): diff --git a/App_Function_Libraries/Gradio_UI/Evaluations_Benchmarks_tab.py b/App_Function_Libraries/Gradio_UI/Evaluations_Benchmarks_tab.py index d7783a63..4e27d784 100644 --- a/App_Function_Libraries/Gradio_UI/Evaluations_Benchmarks_tab.py +++ b/App_Function_Libraries/Gradio_UI/Evaluations_Benchmarks_tab.py @@ -6,7 +6,7 @@ from App_Function_Libraries.Benchmarks_Evaluations.ms_g_eval import run_geval def create_geval_tab(): - with gr.Tab("G-Eval"): + with gr.Tab("G-Eval", visible=True): gr.Markdown("# G-Eval Summarization Evaluation") with gr.Row(): with gr.Column(): @@ -31,7 +31,7 @@ def create_geval_tab(): def create_infinite_bench_tab(): - with gr.Tab("Infinite Bench"): + with gr.Tab("Infinite Bench", visible=True): gr.Markdown("# Infinite Bench Evaluation (Coming Soon)") with gr.Row(): with gr.Column(): diff --git a/App_Function_Libraries/Gradio_UI/Explain_summarize_tab.py b/App_Function_Libraries/Gradio_UI/Explain_summarize_tab.py index 4fd8c4a0..6f549b6b 100644 --- a/App_Function_Libraries/Gradio_UI/Explain_summarize_tab.py +++ b/App_Function_Libraries/Gradio_UI/Explain_summarize_tab.py @@ -24,7 +24,7 @@ # Functions: def create_summarize_explain_tab(): - with gr.TabItem("Analyze Text"): + with gr.TabItem("Analyze Text", visible=True): gr.Markdown("# Analyze / Explain / Summarize Text without ingesting it into the DB") with gr.Row(): with gr.Column(): diff --git a/App_Function_Libraries/Gradio_UI/Import_Functionality.py b/App_Function_Libraries/Gradio_UI/Import_Functionality.py index a25c3fcf..b73d974c 100644 --- a/App_Function_Libraries/Gradio_UI/Import_Functionality.py +++ b/App_Function_Libraries/Gradio_UI/Import_Functionality.py @@ -159,7 +159,7 @@ def parse_obsidian_note(file_path): } def create_import_single_prompt_tab(): - with gr.TabItem("Import a Prompt"): + with gr.TabItem("Import a Prompt", visible=True): gr.Markdown("# Import a prompt into the database") with gr.Row(): @@ -213,7 +213,7 @@ def update_prompt_dropdown(): ) def create_import_item_tab(): - with gr.TabItem("Import Markdown/Text Files"): + with gr.TabItem("Import Markdown/Text Files", visible=True): gr.Markdown("# Import a markdown file or text file into the database") gr.Markdown("...and have it tagged + summarized") with gr.Row(): @@ -246,7 +246,7 @@ def create_import_item_tab(): def create_import_multiple_prompts_tab(): - with gr.TabItem("Import Multiple Prompts"): + with gr.TabItem("Import Multiple Prompts", visible=True): gr.Markdown("# Import multiple prompts into the database") gr.Markdown("Upload a zip file containing multiple prompt files (txt or md)") @@ -326,7 +326,7 @@ def update_prompt_dropdown(): def create_import_obsidian_vault_tab(): - with gr.TabItem("Import Obsidian Vault"): + with gr.TabItem("Import Obsidian Vault", visible=True): gr.Markdown("## Import Obsidian Vault") with gr.Row(): with gr.Column(): diff --git a/App_Function_Libraries/Gradio_UI/Introduction_tab.py b/App_Function_Libraries/Gradio_UI/Introduction_tab.py index 5e831009..9daa53cd 100644 --- a/App_Function_Libraries/Gradio_UI/Introduction_tab.py +++ b/App_Function_Libraries/Gradio_UI/Introduction_tab.py @@ -16,7 +16,7 @@ def create_introduction_tab(): - with (gr.TabItem("Introduction")): + with gr.TabItem("Introduction", visible=True): db_config = get_db_config() db_type = db_config['type'] gr.Markdown(f"# tldw: Your LLM-powered Research Multi-tool (Using {db_type.capitalize()} Database)") diff --git a/App_Function_Libraries/Gradio_UI/Keywords.py b/App_Function_Libraries/Gradio_UI/Keywords.py index 3a6579e8..b2c7a213 100644 --- a/App_Function_Libraries/Gradio_UI/Keywords.py +++ b/App_Function_Libraries/Gradio_UI/Keywords.py @@ -19,7 +19,7 @@ def create_export_keywords_tab(): - with gr.Tab("Export Keywords"): + with gr.TabItem("Export Keywords", visible=True): with gr.Row(): with gr.Column(): export_keywords_button = gr.Button("Export Keywords") @@ -33,7 +33,7 @@ def create_export_keywords_tab(): ) def create_view_keywords_tab(): - with gr.TabItem("View Keywords"): + with gr.TabItem("View Keywords", visible=True): gr.Markdown("# Browse Keywords") with gr.Column(): browse_output = gr.Markdown() @@ -42,7 +42,7 @@ def create_view_keywords_tab(): def create_add_keyword_tab(): - with gr.TabItem("Add Keywords"): + with gr.TabItem("Add Keywords", visible=True): with gr.Row(): with gr.Column(): gr.Markdown("# Add Keywords to the Database") @@ -54,7 +54,7 @@ def create_add_keyword_tab(): def create_delete_keyword_tab(): - with gr.Tab("Delete Keywords"): + with gr.Tab("Delete Keywords", visible=True): with gr.Row(): with gr.Column(): gr.Markdown("# Delete Keywords from the Database") diff --git a/App_Function_Libraries/Gradio_UI/Live_Recording.py b/App_Function_Libraries/Gradio_UI/Live_Recording.py index 94f2c4c8..b19c3664 100644 --- a/App_Function_Libraries/Gradio_UI/Live_Recording.py +++ b/App_Function_Libraries/Gradio_UI/Live_Recording.py @@ -22,7 +22,7 @@ "distil-large-v2", "distil-medium.en", "distil-small.en"] def create_live_recording_tab(): - with gr.Tab("Live Recording and Transcription"): + with gr.Tab("Live Recording and Transcription", visible=True): gr.Markdown("# Live Audio Recording and Transcription") with gr.Row(): with gr.Column(): diff --git a/App_Function_Libraries/Gradio_UI/Llamafile_tab.py b/App_Function_Libraries/Gradio_UI/Llamafile_tab.py index 0b1164d1..d8b256fa 100644 --- a/App_Function_Libraries/Gradio_UI/Llamafile_tab.py +++ b/App_Function_Libraries/Gradio_UI/Llamafile_tab.py @@ -74,7 +74,7 @@ def download_preset_model(selected_model: str) -> Tuple[str, str]: logging.error(f"Error downloading model: {e}") return f"Failed to download model: {e}", "" - with gr.TabItem("Local LLM with Llamafile"): + with gr.TabItem("Local LLM with Llamafile", visible=True): gr.Markdown("# Settings for Llamafile") with gr.Row(): diff --git a/App_Function_Libraries/Gradio_UI/MMLU_Pro_tab.py b/App_Function_Libraries/Gradio_UI/MMLU_Pro_tab.py index e7a1c293..345e860a 100644 --- a/App_Function_Libraries/Gradio_UI/MMLU_Pro_tab.py +++ b/App_Function_Libraries/Gradio_UI/MMLU_Pro_tab.py @@ -78,7 +78,7 @@ def run_benchmark_from_ui(url, api_key, model, timeout, category, parallel, verb def create_mmlu_pro_tab(): """Create the Gradio UI tab for MMLU-Pro Benchmark.""" - with gr.Tab("MMLU-Pro Benchmark"): + with gr.TabItem("MMLU-Pro Benchmark", visible=True): gr.Markdown("## Run MMLU-Pro Benchmark") with gr.Row(): diff --git a/App_Function_Libraries/Gradio_UI/Media_edit.py b/App_Function_Libraries/Gradio_UI/Media_edit.py index 0473e824..0912736b 100644 --- a/App_Function_Libraries/Gradio_UI/Media_edit.py +++ b/App_Function_Libraries/Gradio_UI/Media_edit.py @@ -16,7 +16,7 @@ def create_media_edit_tab(): - with gr.TabItem("Edit Existing Items"): + with gr.TabItem("Edit Existing Items", visible=True): gr.Markdown("# Search and Edit Media Items") with gr.Row(): @@ -89,7 +89,7 @@ def update_media_with_keywords(selected_item, item_mapping, content, prompt, sum def create_media_edit_and_clone_tab(): - with gr.TabItem("Clone and Edit Existing Items"): + with gr.TabItem("Clone and Edit Existing Items", visible=True): gr.Markdown("# Search, Edit, and Clone Existing Items") with gr.Row(): @@ -199,7 +199,7 @@ def save_cloned_item(selected_item, item_mapping, content, prompt, summary, new_ def create_prompt_edit_tab(): - with gr.TabItem("Add & Edit Prompts"): + with gr.TabItem("Add & Edit Prompts", visible=True): with gr.Row(): with gr.Column(): prompt_dropdown = gr.Dropdown( @@ -239,7 +239,7 @@ def create_prompt_edit_tab(): def create_prompt_clone_tab(): - with gr.TabItem("Clone and Edit Prompts"): + with gr.TabItem("Clone and Edit Prompts", visible=True): with gr.Row(): with gr.Column(): gr.Markdown("# Clone and Edit Prompts") diff --git a/App_Function_Libraries/Gradio_UI/Media_wiki_tab.py b/App_Function_Libraries/Gradio_UI/Media_wiki_tab.py index dba547ab..9a1aeb93 100644 --- a/App_Function_Libraries/Gradio_UI/Media_wiki_tab.py +++ b/App_Function_Libraries/Gradio_UI/Media_wiki_tab.py @@ -229,7 +229,7 @@ def save_config(updated_config): def create_mediawiki_config_tab(): - with gr.TabItem("MediaWiki Import Configuration"): + with gr.TabItem("MediaWiki Import Configuration", visible=True): gr.Markdown("# MediaWiki Import Configuration (Broken currently/doesn't work)") with gr.Row(): with gr.Column(): diff --git a/App_Function_Libraries/Gradio_UI/PDF_ingestion_tab.py b/App_Function_Libraries/Gradio_UI/PDF_ingestion_tab.py index 0b9ae318..25c5ba6e 100644 --- a/App_Function_Libraries/Gradio_UI/PDF_ingestion_tab.py +++ b/App_Function_Libraries/Gradio_UI/PDF_ingestion_tab.py @@ -21,7 +21,7 @@ # Functions: def create_pdf_ingestion_tab(): - with gr.TabItem("PDF Ingestion"): + with gr.TabItem("PDF Ingestion", visible=True): # TODO - Add functionality to extract metadata from pdf as part of conversion process in marker gr.Markdown("# Ingest PDF Files and Extract Metadata") with gr.Row(): @@ -136,7 +136,7 @@ def test_pdf_ingestion(pdf_file): return f"Error ingesting PDF: {str(e)}", "" def create_pdf_ingestion_test_tab(): - with gr.TabItem("Test PDF Ingestion"): + with gr.TabItem("Test PDF Ingestion", visible=True): with gr.Row(): with gr.Column(): pdf_file_input = gr.File(label="Upload PDF for testing") diff --git a/App_Function_Libraries/Gradio_UI/Plaintext_tab_import.py b/App_Function_Libraries/Gradio_UI/Plaintext_tab_import.py index c4796998..f16c12f8 100644 --- a/App_Function_Libraries/Gradio_UI/Plaintext_tab_import.py +++ b/App_Function_Libraries/Gradio_UI/Plaintext_tab_import.py @@ -23,7 +23,7 @@ # Functions: def create_plain_text_import_tab(): - with gr.TabItem("Import Plain text & .docx Files"): + with gr.TabItem("Import Plain text & .docx Files", visible=True): with gr.Row(): with gr.Column(): gr.Markdown("# Import Markdown(`.md`)/Text(`.txt`)/rtf & `.docx` Files") diff --git a/App_Function_Libraries/Gradio_UI/Podcast_tab.py b/App_Function_Libraries/Gradio_UI/Podcast_tab.py index 19f89cae..d31051f8 100644 --- a/App_Function_Libraries/Gradio_UI/Podcast_tab.py +++ b/App_Function_Libraries/Gradio_UI/Podcast_tab.py @@ -17,8 +17,8 @@ def create_podcast_tab(): - with gr.TabItem("Podcast"): - gr.Markdown("# Podcast Transcription and Ingestion") + with gr.TabItem("Podcast", visible=True): + gr.Markdown("# Podcast Transcription and Ingestion", visible=True) with gr.Row(): with gr.Column(): podcast_url_input = gr.Textbox(label="Podcast URL", placeholder="Enter the podcast URL here") diff --git a/App_Function_Libraries/Gradio_UI/Prompt_Suggestion_tab.py b/App_Function_Libraries/Gradio_UI/Prompt_Suggestion_tab.py index ce3810c2..98861d40 100644 --- a/App_Function_Libraries/Gradio_UI/Prompt_Suggestion_tab.py +++ b/App_Function_Libraries/Gradio_UI/Prompt_Suggestion_tab.py @@ -18,7 +18,7 @@ # Gradio tab for prompt suggestion and testing def create_prompt_suggestion_tab(): - with gr.TabItem("Prompt Suggestion/Creation"): + with gr.TabItem("Prompt Suggestion/Creation", visible=True): gr.Markdown("# Generate and Test AI Prompts with the Metaprompt Approach") with gr.Row(): diff --git a/App_Function_Libraries/Gradio_UI/RAG_Chat_tab.py b/App_Function_Libraries/Gradio_UI/RAG_Chat_tab.py index c8b64346..4e4ba46c 100644 --- a/App_Function_Libraries/Gradio_UI/RAG_Chat_tab.py +++ b/App_Function_Libraries/Gradio_UI/RAG_Chat_tab.py @@ -16,7 +16,7 @@ # Functions: def create_rag_tab(): - with gr.TabItem("RAG Search"): + with gr.TabItem("RAG Search", visible=True): gr.Markdown("# Retrieval-Augmented Generation (RAG) Search") with gr.Row(): diff --git a/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py b/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py index de03932d..37d80f1f 100644 --- a/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py +++ b/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py @@ -16,7 +16,7 @@ # # Functions def create_rag_qa_chat_notes_tab(): - with gr.TabItem("RAG QA Chat"): + with gr.TabItem("RAG QA Chat", visible=True): gr.Markdown("# RAG QA Chat") state = gr.State({ diff --git a/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_tab.py b/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_tab.py index e682d273..3b3cfd13 100644 --- a/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_tab.py +++ b/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_tab.py @@ -25,7 +25,7 @@ # Functions: def create_rag_qa_chat_tab(): - with gr.TabItem("RAG QA Chat"): + with gr.TabItem("RAG QA Chat", visible=True): gr.Markdown("# RAG QA Chat") with gr.Row(): diff --git a/App_Function_Libraries/Gradio_UI/Re_summarize_tab.py b/App_Function_Libraries/Gradio_UI/Re_summarize_tab.py index 5a231f4b..2a51b0b8 100644 --- a/App_Function_Libraries/Gradio_UI/Re_summarize_tab.py +++ b/App_Function_Libraries/Gradio_UI/Re_summarize_tab.py @@ -23,7 +23,7 @@ # Functions: def create_resummary_tab(): - with gr.TabItem("Re-Summarize"): + with gr.TabItem("Re-Summarize", visible=True): gr.Markdown("# Re-Summarize Existing Content") with gr.Row(): with gr.Column(): diff --git a/App_Function_Libraries/Gradio_UI/Search_Tab.py b/App_Function_Libraries/Gradio_UI/Search_Tab.py index 39885b27..2ad075b8 100644 --- a/App_Function_Libraries/Gradio_UI/Search_Tab.py +++ b/App_Function_Libraries/Gradio_UI/Search_Tab.py @@ -80,7 +80,7 @@ def format_as_html(content, title): """ def create_search_tab(): - with gr.TabItem("Search / Detailed View"): + with gr.TabItem("Search / Detailed View", visible=True): gr.Markdown("# Search across all ingested items in the Database") with gr.Row(): with gr.Column(scale=1): @@ -150,7 +150,7 @@ def display_search_results(query): def create_search_summaries_tab(): - with gr.TabItem("Search/View Title+Summary "): + with gr.TabItem("Search/View Title+Summary", visible=True): gr.Markdown("# Search across all ingested items in the Database and review their summaries") gr.Markdown("Search by Title / URL / Keyword / or Content via SQLite Full-Text-Search") with gr.Row(): @@ -207,7 +207,7 @@ def go_to_previous_search_page(query, search_type, current_page, entries_per_pag def create_prompt_search_tab(): - with gr.TabItem("Search Prompts"): + with gr.TabItem("Search Prompts", visible=True): gr.Markdown("# Search and View Prompt Details") gr.Markdown("Currently has all of the https://github.com/danielmiessler/fabric prompts already available") with gr.Row(): diff --git a/App_Function_Libraries/Gradio_UI/Transcript_comparison.py b/App_Function_Libraries/Gradio_UI/Transcript_comparison.py index 46333fef..3e8625ae 100644 --- a/App_Function_Libraries/Gradio_UI/Transcript_comparison.py +++ b/App_Function_Libraries/Gradio_UI/Transcript_comparison.py @@ -46,7 +46,7 @@ def compare_transcripts(media_id, transcript1_id, transcript2_id): def create_compare_transcripts_tab(): - with gr.TabItem("Compare Transcripts"): + with gr.TabItem("Compare Transcripts", visible=True): gr.Markdown("# Compare Transcripts") with gr.Row(): diff --git a/App_Function_Libraries/Gradio_UI/Trash.py b/App_Function_Libraries/Gradio_UI/Trash.py index 625f3a82..aa9581c2 100644 --- a/App_Function_Libraries/Gradio_UI/Trash.py +++ b/App_Function_Libraries/Gradio_UI/Trash.py @@ -69,7 +69,7 @@ def mark_item_as_trash(media_id: int) -> str: def create_search_and_mark_trash_tab(): - with gr.TabItem("Search and Mark as Trash"): + with gr.TabItem("Search and Mark as Trash", visible=True): gr.Markdown("# Search for Items and Mark as Trash") search_input = gr.Textbox(label="Search Query") @@ -105,14 +105,14 @@ def mark_selected_as_trash(selected_item): def create_view_trash_tab(): - with gr.TabItem("View Trash"): + with gr.TabItem("View Trash", visible=True): view_button = gr.Button("View Trash") trash_list = gr.Textbox(label="Trashed Items") view_button.click(list_trash, inputs=[], outputs=trash_list) def create_delete_trash_tab(): - with gr.TabItem("Delete DB Item"): + with gr.TabItem("Delete DB Item", visible=True): gr.Markdown("# Delete Items from Databases") media_id_input = gr.Number(label="Media ID") @@ -128,7 +128,7 @@ def create_delete_trash_tab(): def create_empty_trash_tab(): - with gr.TabItem("Empty Trash"): + with gr.TabItem("Empty Trash", visible=True): days_input = gr.Slider(minimum=15, maximum=90, step=5, label="Delete items older than (days)") empty_button = gr.Button("Empty Trash") empty_output = gr.Textbox(label="Result") diff --git a/App_Function_Libraries/Gradio_UI/Utilities.py b/App_Function_Libraries/Gradio_UI/Utilities.py index f87a18fb..02020718 100644 --- a/App_Function_Libraries/Gradio_UI/Utilities.py +++ b/App_Function_Libraries/Gradio_UI/Utilities.py @@ -10,7 +10,7 @@ def create_utilities_yt_video_tab(): - with gr.Tab("YouTube Video Downloader", id='youtube_dl'): + with gr.TabItem("YouTube Video Downloader", id='youtube_dl', visible=True): with gr.Row(): with gr.Column(): gr.Markdown( @@ -28,7 +28,7 @@ def create_utilities_yt_video_tab(): ) def create_utilities_yt_audio_tab(): - with gr.Tab("YouTube Audio Downloader", id="youtube audio downloader"): + with gr.TabItem("YouTube Audio Downloader", id="youtube audio downloader", visible=True): with gr.Row(): with gr.Column(): gr.Markdown( @@ -48,7 +48,7 @@ def create_utilities_yt_audio_tab(): ) def create_utilities_yt_timestamp_tab(): - with gr.Tab("YouTube Timestamp URL Generator", id="timestamp-gen"): + with gr.TabItem("YouTube Timestamp URL Generator", id="timestamp-gen", visible=True): gr.Markdown("## Generate YouTube URL with Timestamp") with gr.Row(): with gr.Column(): diff --git a/App_Function_Libraries/Gradio_UI/Video_transcription_tab.py b/App_Function_Libraries/Gradio_UI/Video_transcription_tab.py index ef5323f7..548cf821 100644 --- a/App_Function_Libraries/Gradio_UI/Video_transcription_tab.py +++ b/App_Function_Libraries/Gradio_UI/Video_transcription_tab.py @@ -32,7 +32,7 @@ # Functions: def create_video_transcription_tab(): - with ((gr.TabItem("Video Transcription + Summarization"))): + with gr.TabItem("Video Transcription + Summarization", visible=True): gr.Markdown("# Transcribe & Summarize Videos from URLs") with gr.Row(): gr.Markdown("""Follow this project at [tldw - GitHub](https://github.com/rmusser01/tldw)""") diff --git a/App_Function_Libraries/Gradio_UI/View_DB_Items_tab.py b/App_Function_Libraries/Gradio_UI/View_DB_Items_tab.py index 870b1d59..5c577ea6 100644 --- a/App_Function_Libraries/Gradio_UI/View_DB_Items_tab.py +++ b/App_Function_Libraries/Gradio_UI/View_DB_Items_tab.py @@ -18,7 +18,7 @@ # Functions def create_prompt_view_tab(): - with gr.TabItem("View Prompt Database"): + with gr.TabItem("View Prompt Database", visible=True): gr.Markdown("# View Prompt Database Entries") with gr.Row(): with gr.Column(): @@ -150,7 +150,7 @@ def extract_prompt_and_summary(content: str): def create_view_all_with_versions_tab(): - with gr.TabItem("View All Items"): + with gr.TabItem("View All Items", visible=True): gr.Markdown("# View All Database Entries with Version Selection") with gr.Row(): with gr.Column(scale=1): @@ -281,7 +281,7 @@ def update_version_content(selected_item, item_mapping, selected_version): def create_viewing_tab(): - with gr.TabItem("View Database Entries"): + with gr.TabItem("View Database Entries", visible=True): gr.Markdown("# View Database Entries") with gr.Row(): with gr.Column(): diff --git a/App_Function_Libraries/Gradio_UI/View_tab.py b/App_Function_Libraries/Gradio_UI/View_tab.py index 816bf6fd..d701a995 100644 --- a/App_Function_Libraries/Gradio_UI/View_tab.py +++ b/App_Function_Libraries/Gradio_UI/View_tab.py @@ -22,7 +22,7 @@ # FIXME - Doesn't work. also need ot merge this tab wtih Edit Existing Items tab.... def create_manage_items_tab(): - with gr.TabItem("Edit/Manage DB Items"): + with gr.TabItem("Edit/Manage DB Items", visible=True): search_input = gr.Textbox(label="Search for Media (title or ID)") search_button = gr.Button("Search") media_selector = gr.Dropdown(label="Select Media", choices=[], interactive=True) diff --git a/App_Function_Libraries/Gradio_UI/Website_scraping_tab.py b/App_Function_Libraries/Gradio_UI/Website_scraping_tab.py index 6d6e5d04..6640943c 100644 --- a/App_Function_Libraries/Gradio_UI/Website_scraping_tab.py +++ b/App_Function_Libraries/Gradio_UI/Website_scraping_tab.py @@ -249,7 +249,7 @@ async def scrape_with_retry(url: str, max_retries: int = 3, retry_delay: float = def create_website_scraping_tab(): - with gr.TabItem("Website Scraping"): + with gr.TabItem("Website Scraping", visible=True): gr.Markdown("# Scrape Websites & Summarize Articles") with gr.Row(): with gr.Column(): diff --git a/App_Function_Libraries/Gradio_UI/Writing_tab.py b/App_Function_Libraries/Gradio_UI/Writing_tab.py index d52789f8..e6220682 100644 --- a/App_Function_Libraries/Gradio_UI/Writing_tab.py +++ b/App_Function_Libraries/Gradio_UI/Writing_tab.py @@ -41,7 +41,7 @@ def grammar_style_check(input_text, custom_prompt, api_name, api_key, system_pro def create_grammar_style_check_tab(): - with gr.TabItem("Grammar and Style Check"): + with gr.TabItem("Grammar and Style Check", visible=True): with gr.Row(): with gr.Column(): gr.Markdown("# Grammar and Style Check") @@ -98,7 +98,7 @@ def create_grammar_style_check_tab(): def create_tone_adjustment_tab(): - with gr.TabItem("Tone Analyzer & Editor"): + with gr.TabItem("Tone Analyzer & Editor", visible=True): with gr.Row(): with gr.Column(): input_text = gr.Textbox(label="Input Text", lines=10) @@ -174,7 +174,7 @@ def generate_feedback_history_html(history): # FIXME def create_document_feedback_tab(): - with gr.TabItem("Writing Feedback"): + with gr.TabItem("Writing Feedback", visible=True): with gr.Row(): with gr.Column(scale=2): input_text = gr.Textbox(label="Your Writing", lines=10) @@ -364,13 +364,13 @@ def compare_feedback(text, selected_personas, api_name, api_key): def create_creative_writing_tab(): - with gr.TabItem("Creative Writing Assistant"): + with gr.TabItem("Creative Writing Assistant", visible=True): gr.Markdown("# Utility to be added...") def create_mikupad_tab(): - with gr.TabItem("Mikupad"): + with gr.TabItem("Mikupad", visible=True): gr.Markdown("I Wish. Gradio won't embed it successfully...") # From 091d37b966f8c5fa321cd896f4d3e7dea3993196 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 17 Oct 2024 18:42:03 -0700 Subject: [PATCH 12/17] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2e79761f..e83f7913 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ ## All Automated. All Local. All Yours. -### [Public Demo on HuggingFace Spaces](https://huggingface.co/spaces/oceansweep/Vid-Summarizer/?__theme=dark) +### [Public Demo on HuggingFace Spaces](https://huggingface.co/spaces/oceansweep/Vid-Summarizer/?__theme=dark) - Public demo is currently broken due to a bug in gradio/HF Spaces. - **Please Note:** YouTube blocks requests from the demo. You have to provide a logged-in session cookie to bypass it :frowning_face: - Placeholder content is included for the demo. HuggingFace API is also setup in it, so you can select that as your API.) From afef9e1ccc9f926ca9363dea92927450031229c0 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 18 Oct 2024 18:45:44 -0700 Subject: [PATCH 13/17] uhhh --- .gitignore | Bin 10787 -> 10807 bytes App_Function_Libraries/DB/RAG_QA_Chat_DB.py | 166 ++++- App_Function_Libraries/Gradio_Related.py | 12 +- .../Gradio_UI/Character_Chat_tab.py | 10 +- .../Gradio_UI/RAG_QA_Chat_Notes.py | 243 ------- .../Gradio_UI/RAG_QA_Chat_tab.py | 631 ++++++++++++++++-- App_Function_Libraries/RAG/RAG_QA_Chat.py | 6 + HF/Dockerfile | 48 -- HF/HF_Dockerfile | 78 +++ HF/requirements.txt | 61 -- 10 files changed, 835 insertions(+), 420 deletions(-) delete mode 100644 App_Function_Libraries/Gradio_UI/RAG_QA_Chat_Notes.py delete mode 100644 HF/Dockerfile create mode 100644 HF/HF_Dockerfile delete mode 100644 HF/requirements.txt diff --git a/.gitignore b/.gitignore index 21d4e6e0946d8080d95852b7d4a0bf8d7ee51770..94994ce9c42c061712cbd7df4ece9df1d8396748 100644 GIT binary patch delta 28 jcmZ1+vOQ#jvX+QTVo73BVsUD*eo List[Tuple[int, str]]: logging.error(f"Error fetching existing files: {str(e)}") raise +###################################################### +# +# Notes + + + # # End of RAG_QA_Chat.py ######################################################################################################################## diff --git a/HF/Dockerfile b/HF/Dockerfile deleted file mode 100644 index 698dde4a..00000000 --- a/HF/Dockerfile +++ /dev/null @@ -1,48 +0,0 @@ -FROM nvidia/cuda:12.5.1-cudnn-devel-ubuntu22.04 - -ARG DEBIAN_FRONTEND=noninteractive - -ENV PYTHONUNBUFFERED=1 - -RUN apt-get update && apt-get install -y \ - build-essential \ - python3.9 \ - python3-pip \ - git \ - ffmpeg \ - libcudnn8 \ - libcudnn8-dev \ - sudo - -# Set up a new user named "user" with user ID 1099 -RUN useradd -m -u 1099 user - -WORKDIR /app - -COPY ./requirements.txt /app/requirements.txt - -# Set up CUDA libraries -RUN export LD_LIBRARY_PATH=`python3 -c 'import os; import nvidia.cublas.lib; import nvidia.cudnn.lib; import torch; print(os.path.dirname(nvidia.cublas.lib.__file__) + ":" + os.path.dirname(nvidia.cudnn.lib.__file__) + ":" + os.path.dirname(torch.__file__) +"/lib")'`:$LD_LIBRARY_PATH - -RUN pip3 install --no-cache-dir --upgrade -r /app/requirements.txt - -# Copy the current directory contents into the container at /app -COPY . /app - -# Create necessary directories and set permissions -RUN mkdir -p /app/Results/Audio_Processing /app/Results/Video_Downloads && \ - chown -R user:user /app - -# Switch to the "user" user -USER user - -# Set environment variables -ENV PYTHONUNBUFFERED=1 \ - GRADIO_ALLOW_FLAGGING=never \ - GRADIO_NUM_PORTS=1 \ - GRADIO_SERVER_NAME=0.0.0.0 \ - GRADIO_THEME=huggingface \ - SYSTEM=spaces - -# Command to run the application -CMD ["python3", "app.py"] diff --git a/HF/HF_Dockerfile b/HF/HF_Dockerfile new file mode 100644 index 00000000..784e7700 --- /dev/null +++ b/HF/HF_Dockerfile @@ -0,0 +1,78 @@ +# Use Nvidia CUDA runtime as the base image +FROM nvidia/cuda:12.6.1-cudnn-runtime-ubuntu24.04 + +# Set build arguments for repository configuration +ARG REPO_URL=https://github.com/rmusser01/tldw.git +ARG BRANCH=main +ARG GPU_SUPPORT=cpu + +# Install system dependencies +RUN apt-get update && apt-get install -y \ + ffmpeg \ + libsqlite3-dev \ + build-essential \ + git \ + python3 \ + python-is-python3 \ # Fixed trailing space + python3-pyaudio \ + portaudio19-dev \ + python3-pip \ + python3-venv \ + libpq-dev \ + python3-dev \ + && rm -rf /var/lib/apt/lists/* + +# Create a new user named "user9" with user ID 1009 +RUN useradd -m -u 1009 user9 + +# Switch to the "user9" user +USER user9 + +# Set environment variables for the user's home directory and PATH +ENV HOME=/home/user9 \ + PATH=/home/user9/.local/bin:$PATH + +# Set the working directory to the user's app directory +WORKDIR $HOME/app + +# Clone the repository into the working directory +RUN git clone -b ${BRANCH} ${REPO_URL} . + +# Set correct ownership and permissions for the app directory +RUN chmod -R u+rwX,go+rX,go-w /home/user9/app + +# Create and activate a virtual environment +RUN python3 -m venv venv +ENV PATH="$HOME/app/venv/bin:$PATH" + +# Upgrade pip and install wheel as the non-root user +RUN pip install --no-cache-dir --upgrade pip wheel + +# Install CUDA libraries +RUN pip install --no-cache-dir nvidia-cublas-cu12 nvidia-cudnn-cu12 + +# Install PyTorch based on GPU support +RUN if [ "$GPU_SUPPORT" = "cuda" ]; then \ + pip install torch==2.2.2 torchvision==0.17.2 torchaudio==2.2.2 --index-url https://download.pytorch.org/whl/cu123; \ + elif [ "$GPU_SUPPORT" = "amd" ]; then \ + pip install torch-directml; \ + else \ + pip install torch==2.2.2 torchvision==0.17.2 torchaudio==2.2.2 --index-url https://download.pytorch.org/whl/cpu; \ + fi + +# Install other Python dependencies +RUN pip install --no-cache-dir -r requirements.txt + +# Update config.txt for CPU if needed +RUN if [ "$GPU_SUPPORT" = "cpu" ]; then \ + sed -i 's/cuda/cpu/' ./Config_Files/config.txt; \ + fi + +# Expose port 7860 to the outside world +EXPOSE 7860 + +# Set environment variable for Gradio to listen on all interfaces +ENV GRADIO_SERVER_NAME="0.0.0.0" + +# Define the default command to run the application +CMD ["python", "summarize.py", "-gui"] \ No newline at end of file diff --git a/HF/requirements.txt b/HF/requirements.txt deleted file mode 100644 index 93e8a663..00000000 --- a/HF/requirements.txt +++ /dev/null @@ -1,61 +0,0 @@ -arxiv -beautifulsoup4 -bert_score -chardet -chromadb -docx2txt -EbookLib -elasticsearch -fastapi -faster_whisper -fire -FlashRank -fugashi -gradio -jieba -Jinja2 -joblib -langchain -langdetect -mwparserfromhell -mwxml -nltk -numpy -onnxruntime -openai -pandas -Pillow -playwright -psycopg2 -pyannote.audio -PyAudio -pydub -pymupdf -pypandoc -pypandoc_binary -pytest -python-dotenv -PyYAML -Requests -rouge_score -sacrebleu -scikit_learn -sentence_transformers -SQLAlchemy -streamlit -tenacity -textstat -tiktoken -toml -tqdm -trafilatura -transformers -urllib3 -yt_dlp -datasets -tqdm ---index-url https://download.pytorch.org/whl/cu124 ---extra-index-url https://pypi.org/simple -torch -torchaudio -torchvision From 22165d6116b5151eb09c3b81ab1e2736628556c3 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 18 Oct 2024 19:08:58 -0700 Subject: [PATCH 14/17] Search works --- .../Gradio_UI/RAG_QA_Chat_tab.py | 2 +- App_Function_Libraries/RAG/RAG_QA_Chat.py | 54 +++++++------------ 2 files changed, 21 insertions(+), 35 deletions(-) diff --git a/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_tab.py b/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_tab.py index d591a453..c96dc2fc 100644 --- a/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_tab.py +++ b/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_tab.py @@ -490,7 +490,7 @@ def rag_qa_chat_wrapper(message, history, context_source, existing_file, search_ except Exception as e: logging.error(f"Unexpected error in rag_qa_chat_wrapper: {e}", exc_info=True) gr.Error("An unexpected error occurred. Please try again later.") - yield history, "", gr.update(visible=False), state_value + yield new_history, "", gr.update(visible=False), state_value def clear_chat_history(): return [], "" diff --git a/App_Function_Libraries/RAG/RAG_QA_Chat.py b/App_Function_Libraries/RAG/RAG_QA_Chat.py index 0ccb4ab7..aa1d1700 100644 --- a/App_Function_Libraries/RAG/RAG_QA_Chat.py +++ b/App_Function_Libraries/RAG/RAG_QA_Chat.py @@ -13,56 +13,42 @@ # # Local Imports from App_Function_Libraries.DB.DB_Manager import db, search_db, DatabaseError, get_media_content -from App_Function_Libraries.RAG.RAG_Library_2 import generate_answer +from App_Function_Libraries.RAG.RAG_Library_2 import generate_answer, enhanced_rag_pipeline from App_Function_Libraries.Metrics.metrics_logger import log_counter, log_histogram # ######################################################################################################################## # # Functions: -def rag_qa_chat(message: str, history: List[Tuple[str, str]], context: Union[str, IO[str]], api_choice: str) -> Tuple[List[Tuple[str, str]], str]: +def rag_qa_chat(query, history, context, api_choice): log_counter("rag_qa_chat_attempt", labels={"api_choice": api_choice}) start_time = time.time() + try: - # Prepare the context based on the selected source - if hasattr(context, 'read'): - # Handle uploaded file - context_text = context.read() - if isinstance(context_text, bytes): - context_text = context_text.decode('utf-8') - log_counter("rag_qa_chat_uploaded_file") - elif isinstance(context, str) and context.startswith("media_id:"): - # Handle existing file or search result - media_id = int(context.split(":")[1]) - context_text = get_media_content(media_id) - log_counter("rag_qa_chat_existing_media", labels={"media_id": media_id}) - else: - context_text = str(context) + if isinstance(context, str): log_counter("rag_qa_chat_string_context") - - # Prepare the full context including chat history - full_context = "\n".join([f"Human: {h[0]}\nAI: {h[1]}" for h in history]) - full_context += f"\n\nContext: {context_text}\n\nHuman: {message}\nAI:" - - # Generate response using the selected API - response = generate_answer(api_choice, full_context, message) + # Use the answer and context directly from enhanced_rag_pipeline + result = enhanced_rag_pipeline(query, api_choice) + answer = result['answer'] + else: + log_counter("rag_qa_chat_no_context") + # If no context is provided, call generate_answer directly + answer = generate_answer(api_choice, "", query) # Update history - history.append((message, response)) + new_history = history + [(query, answer)] - chat_duration = time.time() - start_time - log_histogram("rag_qa_chat_duration", chat_duration, labels={"api_choice": api_choice}) + # Metrics + duration = time.time() - start_time + log_histogram("rag_qa_chat_duration", duration, labels={"api_choice": api_choice}) log_counter("rag_qa_chat_success", labels={"api_choice": api_choice}) - return history, "" - except DatabaseError as e: - log_counter("rag_qa_chat_database_error", labels={"error": str(e)}) - logging.error(f"Database error in rag_qa_chat: {str(e)}") - return history, f"An error occurred while accessing the database: {str(e)}" + return new_history, answer except Exception as e: - log_counter("rag_qa_chat_unexpected_error", labels={"error": str(e)}) - logging.error(f"Unexpected error in rag_qa_chat: {str(e)}") - return history, f"An unexpected error occurred: {str(e)}" + log_counter("rag_qa_chat_error", labels={"api_choice": api_choice, "error": str(e)}) + logging.error(f"Error in rag_qa_chat: {str(e)}") + return history + [(query, "An error occurred while processing your request.")], "An error occurred while processing your request." + From 477dfe8f9e9cb67c35cd887d9ab2e404d30c038e Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 18 Oct 2024 19:27:49 -0700 Subject: [PATCH 15/17] Fuck yes. We have notes --- App_Function_Libraries/Gradio_UI/RAG_QA_Chat_tab.py | 12 ++++++++---- .../Gradio_UI/Website_scraping_tab.py | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_tab.py b/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_tab.py index c96dc2fc..99fb24b3 100644 --- a/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_tab.py +++ b/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_tab.py @@ -6,6 +6,7 @@ import logging import json import os +import uuid from datetime import datetime # # External Imports @@ -43,10 +44,10 @@ def create_rag_qa_chat_tab(): gr.Markdown("# RAG QA Chat") state = gr.State({ - "conversation_id": None, # No conversation ID initially + "conversation_id": str(uuid.uuid4()), "page": 1, "context_source": "Entire Media Database", - "conversation_messages": [], # Store messages before saving + "conversation_messages": [], }) note_state = gr.State({"note_id": None}) @@ -286,8 +287,11 @@ def save_conversation_function(conversation_title_text, keywords_text, state_val ) def start_new_conversation_wrapper(title, state_value): - # Reset the state without saving to the database - updated_state = update_state(state_value, conversation_id=None, page=1, conversation_messages=[]) + # Generate a new UUID for the new conversation + new_conversation_id = str(uuid.uuid4()) + # Reset the state with the new conversation_id + updated_state = update_state(state_value, conversation_id=new_conversation_id, page=1, + conversation_messages=[]) # Clear the chat history return [], updated_state diff --git a/App_Function_Libraries/Gradio_UI/Website_scraping_tab.py b/App_Function_Libraries/Gradio_UI/Website_scraping_tab.py index 6640943c..f02b1a1e 100644 --- a/App_Function_Libraries/Gradio_UI/Website_scraping_tab.py +++ b/App_Function_Libraries/Gradio_UI/Website_scraping_tab.py @@ -249,7 +249,7 @@ async def scrape_with_retry(url: str, max_retries: int = 3, retry_delay: float = def create_website_scraping_tab(): - with gr.TabItem("Website Scraping", visible=True): + with gr.TabItem("Website Scraping", visible=True): gr.Markdown("# Scrape Websites & Summarize Articles") with gr.Row(): with gr.Column(): From 2f559be895a5e06ceaf1e1c7cd898d88386fa0ed Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 18 Oct 2024 19:39:08 -0700 Subject: [PATCH 16/17] wew --- App_Function_Libraries/DB/RAG_QA_Chat_DB.py | 80 +++++++++++ .../Gradio_UI/RAG_QA_Chat_tab.py | 129 +++++++++++++++++- .../Gradio_UI/Website_scraping_tab.py | 2 +- 3 files changed, 207 insertions(+), 4 deletions(-) diff --git a/App_Function_Libraries/DB/RAG_QA_Chat_DB.py b/App_Function_Libraries/DB/RAG_QA_Chat_DB.py index c0164cee..bec2ec2c 100644 --- a/App_Function_Libraries/DB/RAG_QA_Chat_DB.py +++ b/App_Function_Libraries/DB/RAG_QA_Chat_DB.py @@ -637,6 +637,86 @@ def delete_conversation(conversation_id): # End of Chat-related functions ################################################### + +################################################### +# +# Functions to export DB data + +def fetch_all_conversations(): + try: + # Fetch all conversation IDs and titles + query = "SELECT conversation_id, title FROM conversation_metadata ORDER BY last_updated DESC" + results = execute_query(query) + conversations = [] + for row in results: + conversation_id, title = row + # Fetch all messages for this conversation + messages = load_all_chat_history(conversation_id) + conversations.append((conversation_id, title, messages)) + logger.info(f"Fetched all conversations: {len(conversations)} found.") + return conversations + except Exception as e: + logger.error(f"Error fetching all conversations: {e}") + raise + +def load_all_chat_history(conversation_id): + try: + query = "SELECT role, content FROM rag_qa_chats WHERE conversation_id = ? ORDER BY timestamp" + results = execute_query(query, (conversation_id,)) + messages = [(row[0], row[1]) for row in results] + return messages + except Exception as e: + logger.error(f"Error loading chat history for conversation '{conversation_id}': {e}") + raise + +def fetch_all_notes(): + try: + query = "SELECT id, title, content FROM rag_qa_notes ORDER BY timestamp DESC" + results = execute_query(query) + notes = [(row[0], row[1], row[2]) for row in results] + logger.info(f"Fetched all notes: {len(notes)} found.") + return notes + except Exception as e: + logger.error(f"Error fetching all notes: {e}") + raise + +def fetch_conversations_by_ids(conversation_ids): + try: + if not conversation_ids: + return [] + placeholders = ','.join(['?'] * len(conversation_ids)) + query = f"SELECT conversation_id, title FROM conversation_metadata WHERE conversation_id IN ({placeholders})" + results = execute_query(query, conversation_ids) + conversations = [] + for row in results: + conversation_id, title = row + # Fetch all messages for this conversation + messages = load_all_chat_history(conversation_id) + conversations.append((conversation_id, title, messages)) + logger.info(f"Fetched {len(conversations)} conversations by IDs.") + return conversations + except Exception as e: + logger.error(f"Error fetching conversations by IDs: {e}") + raise + +def fetch_notes_by_ids(note_ids): + try: + if not note_ids: + return [] + placeholders = ','.join(['?'] * len(note_ids)) + query = f"SELECT id, title, content FROM rag_qa_notes WHERE id IN ({placeholders})" + results = execute_query(query, note_ids) + notes = [(row[0], row[1], row[2]) for row in results] + logger.info(f"Fetched {len(notes)} notes by IDs.") + return notes + except Exception as e: + logger.error(f"Error fetching notes by IDs: {e}") + raise + +# +# End of Export functions +################################################### + # # End of RAG_QA_Chat_DB.py #################################################################################################### diff --git a/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_tab.py b/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_tab.py index 99fb24b3..5957b233 100644 --- a/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_tab.py +++ b/App_Function_Libraries/Gradio_UI/RAG_QA_Chat_tab.py @@ -29,7 +29,8 @@ get_notes_by_keyword_collection, update_note, clear_keywords_from_note, get_notes, get_keywords_for_note, delete_conversation, delete_note, execute_query, - add_keywords_to_conversation, + add_keywords_to_conversation, fetch_all_notes, fetch_all_conversations, fetch_conversations_by_ids, + fetch_notes_by_ids, ) from App_Function_Libraries.PDF.PDF_Ingestion_Lib import extract_text_and_format_from_pdf from App_Function_Libraries.RAG.RAG_Library_2 import generate_answer, enhanced_rag_pipeline @@ -776,8 +777,130 @@ def load_selected_note(selected_note, state_value): ) return gr.update(value=''), gr.update(value=''), gr.update(value=''), state_value - # Return components if needed - # ... + +def create_export_data_tab(): + with gr.TabItem("Export Data"): + gr.Markdown("# Export Data") + + export_option = gr.Radio( + ["Export All", "Export Selected"], + label="Export Option", + value="Export All" + ) + + conversations_checklist = gr.CheckboxGroup( + choices=[], + label="Select Conversations", + visible=False + ) + + notes_checklist = gr.CheckboxGroup( + choices=[], + label="Select Notes", + visible=False + ) + + export_button = gr.Button("Export") + download_link = gr.File(label="Download Exported Data", visible=False) + status_message = gr.HTML() + + # Function to update visibility and populate checklists + def update_visibility(export_option_value): + if export_option_value == "Export Selected": + # Fetch conversations and notes to populate the checklists + conversations = fetch_all_conversations() + notes = fetch_all_notes() + + conversation_choices = [f"{title} (ID: {conversation_id})" for conversation_id, title, _ in conversations] + note_choices = [f"{title} (ID: {note_id})" for note_id, title, _ in notes] + + return ( + gr.update(visible=True, choices=conversation_choices), + gr.update(visible=True, choices=note_choices) + ) + else: + return ( + gr.update(visible=False), + gr.update(visible=False) + ) + + export_option.change( + update_visibility, + inputs=[export_option], + outputs=[conversations_checklist, notes_checklist] + ) + + import zipfile + import io + def update_visibility(export_option_value): + if export_option_value == "Export Selected": + # Fetch conversations and notes to populate the checklists + conversations = fetch_all_conversations() + notes = fetch_all_notes() + + conversation_choices = [f"{title} (ID: {conversation_id})" for conversation_id, title, _ in + conversations] + note_choices = [f"{title} (ID: {note_id})" for note_id, title, _ in notes] + + return ( + gr.update(visible=True, choices=conversation_choices), + gr.update(visible=True, choices=note_choices) + ) + else: + return ( + gr.update(visible=False), + gr.update(visible=False) + ) + + export_option.change( + update_visibility, + inputs=[export_option], + outputs=[conversations_checklist, notes_checklist] + ) + + def export_data_function(export_option, selected_conversations, selected_notes): + try: + zip_buffer = io.BytesIO() + + with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file: + if export_option == "Export All": + # Fetch all conversations and notes + conversations = fetch_all_conversations() + notes = fetch_all_notes() + else: + # Fetch selected conversations and notes + conversation_ids = [int(item.split(' (ID: ')[1][:-1]) for item in selected_conversations] + note_ids = [int(item.split(' (ID: ')[1][:-1]) for item in selected_notes] + conversations = fetch_conversations_by_ids(conversation_ids) + notes = fetch_notes_by_ids(note_ids) + + # Export conversations + for conversation in conversations: + conversation_id, title, _ = conversation + filename = f"conversation_{conversation_id}_{title.replace(' ', '_')}.md" + zip_file.writestr(filename, conversation) + + # Export notes + for note in notes: + note_id, title, _ = note + filename = f"note_{note_id}_{title.replace(' ', '_')}.md" + zip_file.writestr(filename, note) + + zip_buffer.seek(0) + return zip_buffer, gr.update(visible=True), gr.update( + value="

Export successful!

") + except Exception as e: + logging.error(f"Error exporting data: {str(e)}") + return None, gr.update(visible=False), gr.update(value=f"

Error: {str(e)}

") + + export_button.click( + export_data_function, + inputs=[export_option, conversations_checklist, notes_checklist], + outputs=[download_link, download_link, status_message] + ) + + + def update_conversation_title(conversation_id, new_title): """Update the title of a conversation.""" diff --git a/App_Function_Libraries/Gradio_UI/Website_scraping_tab.py b/App_Function_Libraries/Gradio_UI/Website_scraping_tab.py index f02b1a1e..5a791433 100644 --- a/App_Function_Libraries/Gradio_UI/Website_scraping_tab.py +++ b/App_Function_Libraries/Gradio_UI/Website_scraping_tab.py @@ -250,7 +250,7 @@ async def scrape_with_retry(url: str, max_retries: int = 3, retry_delay: float = def create_website_scraping_tab(): with gr.TabItem("Website Scraping", visible=True): - gr.Markdown("# Scrape Websites & Summarize Articles") + gr.Markdown("# Scrape Websites & Summarize Articles") with gr.Row(): with gr.Column(): scrape_method = gr.Radio( From 528490302215485d8c6cfb59319e8f3b06ef47a1 Mon Sep 17 00:00:00 2001 From: Robert Date: Sat, 19 Oct 2024 16:12:14 -0700 Subject: [PATCH 17/17] partial fix + config.txt update EMBEDDINGS MOVED FROM 'onnx_models' to 'embedding_models' So be sure to copy/paste them, otherwise you'll have two copies of the embedding models used --- .gitignore | Bin 10807 -> 10914 bytes App_Function_Libraries/RAG/RAG_Library_2.py | 28 +++++++-------- App_Function_Libraries/RAG/RAG_QA_Chat.py | 4 +-- Config_Files/config.txt | 36 ++++++++++++-------- 4 files changed, 38 insertions(+), 30 deletions(-) diff --git a/.gitignore b/.gitignore index 94994ce9c42c061712cbd7df4ece9df1d8396748..97a4df3bd74096475f14b697b786080463671aa7 100644 GIT binary patch delta 68 zcmdlUvM6+exz^Jmz+xk;%hDVcfc@wxdasX4`5`YwqjiAjmYsm1z9iOJce1(WBg JD+ppJ0|11z8KeLJ delta 7 OcmZ1!x; Dict[str, Any]: +def enhanced_rag_pipeline(query: str, api_choice: str, keywords: str = None, apply_re_ranking=True) -> Dict[str, Any]: log_counter("enhanced_rag_pipeline_attempt", labels={"api_choice": api_choice}) start_time = time.time() try: @@ -150,30 +150,30 @@ def enhanced_rag_pipeline(query: str, api_choice: str, keywords: str = None) -> # Combine results all_results = vector_results + fts_results - apply_re_ranking = True if apply_re_ranking: logging.debug(f"\nenhanced_rag_pipeline - Applying Re-Ranking") # FIXME - add option to use re-ranking at call time # FIXME - specify model + add param to modify at call time # FIXME - add option to set a custom top X results # You can specify a model if necessary, e.g., model_name="ms-marco-MiniLM-L-12-v2" - ranker = Ranker() + if all_results: + ranker = Ranker() - # Prepare passages for re-ranking - passages = [{"id": i, "text": result['content']} for i, result in enumerate(all_results)] - rerank_request = RerankRequest(query=query, passages=passages) + # Prepare passages for re-ranking + passages = [{"id": i, "text": result['content']} for i, result in enumerate(all_results)] + rerank_request = RerankRequest(query=query, passages=passages) - # Rerank the results - reranked_results = ranker.rerank(rerank_request) + # Rerank the results + reranked_results = ranker.rerank(rerank_request) - # Sort results based on the re-ranking score - reranked_results = sorted(reranked_results, key=lambda x: x['score'], reverse=True) + # Sort results based on the re-ranking score + reranked_results = sorted(reranked_results, key=lambda x: x['score'], reverse=True) - # Log reranked results - logging.debug(f"\n\nenhanced_rag_pipeline - Reranked results: {reranked_results}") + # Log reranked results + logging.debug(f"\n\nenhanced_rag_pipeline - Reranked results: {reranked_results}") - # Update all_results based on reranking - all_results = [all_results[result['id']] for result in reranked_results] + # Update all_results based on reranking + all_results = [all_results[result['id']] for result in reranked_results] # Extract content from results (top 10) context = "\n".join([result['content'] for result in all_results[:10]]) # Limit to top 10 results diff --git a/App_Function_Libraries/RAG/RAG_QA_Chat.py b/App_Function_Libraries/RAG/RAG_QA_Chat.py index aa1d1700..5ec3af07 100644 --- a/App_Function_Libraries/RAG/RAG_QA_Chat.py +++ b/App_Function_Libraries/RAG/RAG_QA_Chat.py @@ -20,7 +20,7 @@ # # Functions: -def rag_qa_chat(query, history, context, api_choice): +def rag_qa_chat(query, history, context, api_choice, keywords=None, apply_re_ranking=False): log_counter("rag_qa_chat_attempt", labels={"api_choice": api_choice}) start_time = time.time() @@ -28,7 +28,7 @@ def rag_qa_chat(query, history, context, api_choice): if isinstance(context, str): log_counter("rag_qa_chat_string_context") # Use the answer and context directly from enhanced_rag_pipeline - result = enhanced_rag_pipeline(query, api_choice) + result = enhanced_rag_pipeline(query, api_choice, keywords, apply_re_ranking) answer = result['answer'] else: log_counter("rag_qa_chat_no_context") diff --git a/Config_Files/config.txt b/Config_Files/config.txt index 46d24c7c..a0b079af 100644 --- a/Config_Files/config.txt +++ b/Config_Files/config.txt @@ -8,7 +8,7 @@ groq_model = llama3-70b-8192 openai_api_key = openai_model = gpt-4o huggingface_api_key = -huggingface_model = CohereForAI/c4ai-command-r-plus +huggingface_model = mistralai/Mistral-Nemo-Instruct-2407 openrouter_api_key = openrouter_model = mistralai/mistral-7b-instruct:free deepseek_api_key = @@ -20,20 +20,20 @@ custom_openai_api_ip = [Local-API] kobold_api_IP = http://127.0.0.1:5001/api/v1/generate -kobold_api_key = +kobold_api_key = llama_api_IP = http://127.0.0.1:8080/completion -llama_api_key = -ooba_api_key = +llama_api_key = +ooba_api_key = ooba_api_IP = http://127.0.0.1:5000/v1/chat/completions tabby_api_IP = http://127.0.0.1:5000/v1/chat/completions -tabby_api_key = +tabby_api_key = vllm_api_IP = http://127.0.0.1:8000/v1/chat/completions -vllm_model = -ollama_api_IP = http://127.0.0.1:11434/api/generate -ollama_api_key = -ollama_model = +vllm_model = +ollama_api_IP = http://127.0.0.1:11434/v1/chat/completions +ollama_api_key = +ollama_model = llama3 aphrodite_api_IP = http://127.0.0.1:8080/completion -aphrodite_api_key = +aphrodite_api_key = [Processing] processing_choice = cuda @@ -56,10 +56,13 @@ elasticsearch_port = 9200 # Additionally you can use elasticsearch as the database type, just replace `sqlite` with `elasticsearch` for `type` and provide the `elasticsearch_host` and `elasticsearch_port` of your configured ES instance. chroma_db_path = Databases/chroma_db prompts_db_path = Databases/prompts.db +rag_qa_db_path = Databases/rag_qa.db [Embeddings] embedding_provider = openai embedding_model = text-embedding-3-small +onnx_model_path = ./App_Function_Libraries/models/onnx_models/ +model_dir = ./App_Function_Libraries/models/embedding_models embedding_api_url = http://localhost:8080/v1/embeddings embedding_api_key = your_api_key_here chunk_size = 400 @@ -78,6 +81,14 @@ adaptive = false multi_level = false language = english +[Metrics] +log_file_path = +#os.getenv("tldw_LOG_FILE_PATH", "tldw_app_logs.json") +max_bytes = +#int(os.getenv("tldw_LOG_MAX_BYTES", 10 * 1024 * 1024)) # 10 MB +backup_count = 5 +#int(os.getenv("tldw_LOG_BACKUP_COUNT", 5)) + #[Comments] #OpenAI Models: @@ -98,7 +109,4 @@ language = english # open-mistral-7b # open-mixtral-8x7b # open-mixtral-8x22b -# open-codestral-mamba - - - +# open-codestral-mamba \ No newline at end of file