From 4ece0d0d9b94d84474baa91f14e3a8172d1a0a52 Mon Sep 17 00:00:00 2001 From: sofiachavezb Date: Thu, 15 May 2025 12:10:07 -0400 Subject: [PATCH 001/218] prototype --- .gitignore | 4 + DashAI/back/container.py | 9 +- DashAI/back/models/RAG/RAG_pipeline.py | 238 ++++++++++++++++++ DashAI/back/models/RAG/__init__.py | 1 + DashAI/back/models/RAG/dummy_retriever.py | 194 ++++++++++++++ .../models/RAG/encodings/tf_idf_encoding.py | 32 +++ DashAI/back/models/RAG/prompts/__init__.py | 3 + .../models/RAG/prompts/augmentation_prompt.py | 51 ++++ DashAI/back/models/RAG/prompts/base_prompt.py | 20 ++ .../RAG/prompts/context_merge_prompt.py | 43 ++++ DashAI/back/models/RAG/text_preprocessor.py | 39 +++ DashAI/back/models/RAG/text_splitter.py | 41 +++ DashAI/back/models/__init__.py | 2 + .../models/hugging_face/deep_seek_model.py | 2 +- DashAI/back/tasks/RAG_task.py | 118 +++++++++ DashAI/back/tasks/__init__.py | 2 + 16 files changed, 797 insertions(+), 2 deletions(-) create mode 100644 DashAI/back/models/RAG/RAG_pipeline.py create mode 100644 DashAI/back/models/RAG/__init__.py create mode 100644 DashAI/back/models/RAG/dummy_retriever.py create mode 100644 DashAI/back/models/RAG/encodings/tf_idf_encoding.py create mode 100644 DashAI/back/models/RAG/prompts/__init__.py create mode 100644 DashAI/back/models/RAG/prompts/augmentation_prompt.py create mode 100644 DashAI/back/models/RAG/prompts/base_prompt.py create mode 100644 DashAI/back/models/RAG/prompts/context_merge_prompt.py create mode 100644 DashAI/back/models/RAG/text_preprocessor.py create mode 100644 DashAI/back/models/RAG/text_splitter.py create mode 100644 DashAI/back/tasks/RAG_task.py diff --git a/.gitignore b/.gitignore index 2671a9ae6..8c017f168 100644 --- a/.gitignore +++ b/.gitignore @@ -178,3 +178,7 @@ __pycache__ # MacOS *.DS_Store + +# RAG database +/chroma +/saved_encoders diff --git a/DashAI/back/container.py b/DashAI/back/container.py index 7206a46ef..508a2880f 100644 --- a/DashAI/back/container.py +++ b/DashAI/back/container.py @@ -51,6 +51,8 @@ StableDiffusionV2Model, StableDiffusionV3Model, ViTTransformer, + + RAGPipeline, ) from DashAI.back.optimizers import HyperOptOptimizer, OptunaOptimizer from DashAI.back.tasks import ( @@ -61,7 +63,9 @@ TabularClassificationTask, TextClassificationTask, TextToImageGenerationTask, - TranslationTask, + TranslationTask, + + RAGTask, ) logger = logging.getLogger(__name__) @@ -130,6 +134,9 @@ KernelShap, PartialDependence, PermutationFeatureImportance, + + RAGTask, + RAGPipeline ] diff --git a/DashAI/back/models/RAG/RAG_pipeline.py b/DashAI/back/models/RAG/RAG_pipeline.py new file mode 100644 index 000000000..7ca6961c3 --- /dev/null +++ b/DashAI/back/models/RAG/RAG_pipeline.py @@ -0,0 +1,238 @@ +from typing import Any, Tuple, List + +from DashAI.back.models.base_generative_model import BaseGenerativeModel + +from DashAI.back.core.schema_fields import ( + BaseSchema, + enum_field, + int_field, + float_field, + schema_field, + string_field +) + +from DashAI.back.models.hugging_face.deep_seek_model import DeepSeekModel +from DashAI.back.models.hugging_face.qwen_model import QwenModel +from DashAI.back.models.llm_generation_model import LLMGenerationModel +from DashAI.back.models.RAG.dummy_retriever import DummyRetriever +from DashAI.back.models.RAG.prompts import ( + BasePrompt, + ContextMergePrompt, + AugmentationPrompt +) +from typing import Dict + +class RAGPipelineSchema(BaseSchema): + """Schema for RAG pipeline.""" + + # RAG algorithm parameters + RAG_algorithm: schema_field( + enum_field(["SINGLE_INTERACTION", "AUGMENTED_INTERACTION"]), + placeholder="SINGLE_INTERACTION", + description="RAG algorithm to use for document retrieval and text generation.", + ) # type: ignore + + + # Retriever parameters + documments_path: schema_field( + string_field(), + placeholder="Path to the folder with documents", + description="Path to the folder containing documents for retrieval.", + ) # type: ignore + + collection_name: schema_field( + string_field(), + placeholder="My documents collection name", + description="Name of the collection to use for document retrieval.", + ) # type: ignore + + + distance_function: schema_field( + enum_field(["cosine", "L2", "inner"]), + placeholder="cosine", + description="Distance function to use for document retrieval.", + ) # type: ignore + + n_docs: schema_field( + int_field(ge=1), + placeholder=5, + description="Maximum number of documents to retrieve.", + ) # type: ignore + + max_distance: schema_field( + float_field(ge=0.0), + placeholder=1.0, + description="Maximum distance allowed for retrieved documents.", + ) # type: ignore + + chunk_size: schema_field( + int_field(ge=1), + placeholder=1000, + description="Size of the chunks to split the documents into.", + ) # type: ignore + + chunk_overlap: schema_field( + int_field(ge=0), + placeholder=200, + description="Overlap size between chunks.", + ) # type: ignore + + + # LLM parameters + model_name: schema_field( + enum_field(["DeepSeek", "Qwen2"]), + placeholder="DeepSeek", + description="LLM model to use for text generation.", + ) # type: ignore + + max_tokens: schema_field( + int_field(ge=1), + placeholder=800, + description="Maximum number of tokens to generate.", + ) # type: ignore + + temperature: schema_field( + float_field(ge=0.0, le=1.0), + placeholder=0.7, + description="Sampling temperature. Higher values make the output more random, while lower values make it more focused and deterministic.", + ) # type: ignore + + frequency_penalty: schema_field( + float_field(ge=0.0, le=2.0), + placeholder=0.1, + description="Penalty for repeated tokens in the output. Higher values reduce the likelihood of repetition, encouraging more diverse text generation.", + ) # type: ignore + + n_ctx: schema_field( + int_field(ge=1), + placeholder=4096, + description="Maximum number of tokens the model can process in a single forward pass (context window size).", + ) # type: ignore + +class RAGPipeline(BaseGenerativeModel): + """Retrieval-Augmented Generation (RAG) pipeline.""" + + COMPATIBLE_COMPONENTS = ["RAGTask"] + SCHEMA = RAGPipelineSchema + + def __init__( self, + **kwargs): + """ + Initialize the DummyRetrieverModel with dummy parameters. + + Args: + distance_function (str): The distance function to use (e.g., "cosine", "euclidean"). + n_docs (int): The maximum number of documents to retrieve. + max_distance (float): The maximum distance allowed for retrieved documents. + """ + + print("Initializing RAG pipeline") + # Initialize the LLM model + llm_classes = { + "DeepSeek": DeepSeekModel, + "Qwen2": QwenModel, + } + + llm_kwargs = { + "max_tokens": kwargs.get("max_tokens"), + "temperature": kwargs.get("temperature"), + "frequency_penalty": kwargs.get("frequency_penalty"), + "n_ctx": kwargs.get("n_ctx"), + } + + print("Initializing LLM model") + self.llm_model: LLMGenerationModel = llm_classes[kwargs.get("model_name")](**llm_kwargs) + + # Initialize the retriever + retriever_params = { + "documents_path": kwargs.get("documments_path"), + "collection_name": kwargs.get("collection_name"), + "distance_function": kwargs.get("distance_function"), + "n_docs": kwargs.get("n_docs"), + "max_distance": kwargs.get("max_distance"), + "chunk_size": kwargs.get("chunk_size"), + "chunk_overlap": kwargs.get("chunk_overlap"), + } + + print("Initializing retriever") + self.retriever = DummyRetriever(**retriever_params) + + print("Definining rag algorithm") + # Initialize the RAG algorithm + if kwargs.get("RAG_algorithm") == "SINGLE_INTERACTION": + self.retrieval_algorithm = self.single_interaction + elif kwargs.get("RAG_algorithm") == "AUGMENTED_INTERACTION": + self.retrieval_algorithm = self.augmented_interaction + else: + raise ValueError("Invalid RAG algorithm. Choose 'SINGLE_INTERACTION' or 'AUGMENTED_INTERACTION'.") + print("RAG pipeline initialized") + + def single_interaction(self, input: str, history: List[Tuple[str, str]] = None) -> Dict[str, str]: + """ + Single interaction retrieval algorithm: input -> retrieve documents. + Args: + input (str): The input query. + Returns: + str: The generated response. + """ + + documents = self.retriever.retrieve([input]) + + return documents + + + def augmented_interaction(self, input: str, history: List[Tuple[str, str]] = None) -> Dict[str, str]: + """ + Augmented interaction RAG algorithm: input -> generate lookup tokens -> retrieve documents -> generate response. + Args: + input (str): The input query. + Returns: + str: The generated response. + """ + augmentation_prompt = AugmentationPrompt.format( + input=input, + history=history, + n_seach_terms=5 + ) + augementation_response = self.llm_model.generate(augmentation_prompt)[0] + print(f"Augmentation response: {augementation_response}") + search_terms = augementation_response.split("keywords:")[1].strip() + search_terms = search_terms.split(",") + if len(search_terms) > 5: + search_terms = search_terms[:5] + print(f"Augmentation search terms: {search_terms}") + search_terms = [term.strip() for term in search_terms] + + documents = self.retriever.retrieve(search_terms) + + return documents + + def generate(self, input: Tuple[str, List[Tuple[str,str]]]) -> str: + """ + Generate a response based on the input and the retrieved documents. + Args: + input: a tuple containing the input query and the conversation history. + input (str): The input query. + history (List[Tuple[str, str]]): The conversation history. + Returns: + str: The generated response. + """ + message, history = input + + documents = self.retrieval_algorithm(message, history) + documents_str = "\n\n".join([f"Document {name}:\n {content}" for name, content in documents.items()]) + + prompt = ContextMergePrompt.format( + input=message, + history=history, + documents=documents_str + ) + + print(f"Prompt: {prompt}") + + response = self.llm_model.generate(prompt) + + sources_str = ", ".join(doc_name for doc_name in documents.keys()) + response = f"{response[0]}\n\nSources:{sources_str}" + + return [response] diff --git a/DashAI/back/models/RAG/__init__.py b/DashAI/back/models/RAG/__init__.py new file mode 100644 index 000000000..ef3481f81 --- /dev/null +++ b/DashAI/back/models/RAG/__init__.py @@ -0,0 +1 @@ +from DashAI.back.models.RAG.RAG_pipeline import RAGPipeline \ No newline at end of file diff --git a/DashAI/back/models/RAG/dummy_retriever.py b/DashAI/back/models/RAG/dummy_retriever.py new file mode 100644 index 000000000..82463d0e8 --- /dev/null +++ b/DashAI/back/models/RAG/dummy_retriever.py @@ -0,0 +1,194 @@ +import os +import chromadb +from chromadb import Settings +from typing import List, Dict +from pypdf import PdfReader +from DashAI.back.models.RAG.encodings.tf_idf_encoding import TfidfEmbeddingFunction +from DashAI.back.models.RAG.text_splitter import TextSplitter +from DashAI.back.models.RAG.text_preprocessor import TextPreprocessor + +def directory_has_documents(directory: str) -> bool: + """Check if the directory contains any documents.""" + for filename in os.listdir(directory): + if filename.endswith(".txt") or filename.endswith(".pdf"): + return True + return False + +class DummyRetriever: + """A dummy retriever using ChromaDB.""" + + def __init__( + self, + documents_path: str, + collection_name: str, + distance_function: str, + n_docs: int, + max_distance: float, + chunk_size: int, + chunk_overlap: int + ): + """ + Initialize the DummyRetriever with dummy parameters. + + Args: + collection_name (str): The name of the collection. + distance_function (str): The distance function to use (e.g., "cosine", "euclidean"). + n_docs (int): The maximum number of documents to retrieve. + max_distance (float): The maximum distance allowed for retrieved documents. + """ + assert os.path.exists(documents_path), f"Documents path {documents_path} does not exist." + assert directory_has_documents(documents_path), f"No txt or pdf documents found in {documents_path}." + assert collection_name, "Collection name cannot be empty." + assert distance_function in ["cosine", "L2", "inner"], "Invalid distance function. Choose 'cosine', 'L2', or 'inner'." + assert n_docs > 0, "Number of documents must be greater than 0." + assert max_distance > 0, "Max distance must be greater than 0." + assert chunk_size > 0, "Chunk size must be greater than 0." + assert chunk_overlap >= 0, "Chunk overlap must be greater than or equal to 0." + + self.documents_path = documents_path + self.collection_name = collection_name.lower().strip().replace(" ", "_") + self.distance_function = distance_function + self.n_docs = n_docs + self.max_distance = max_distance + self.chunk_size = chunk_size + self.chunk_overlap = chunk_overlap + self.collection: chromadb.Collection = None + self.embedding = TfidfEmbeddingFunction( + corpus=self.load_documents().values(), + collection_name=self.collection_name, + ) + + print("Initializing ChromaDB storage") + self.__init_chromadb__() + + def __init_chromadb__(self): + """ + Initialize the ChromaDB storage + if the collection already exists, it will be loaded. + + """ + print("Initializing ChromaDB client") + client = chromadb.PersistentClient( + settings=Settings( + anonymized_telemetry=False, + )) + + print("Initializing ChromaDB collection") + self.collection = client.get_or_create_collection( + name=self.collection_name, + configuration={ + "embedding_function": self.embedding.name(), + }, + embedding_function=self.embedding, + metadata={ + "distance_function": self.distance_function, + }, + ) + print(f"Collection {self.collection_name} initialized.") + try: + print("Checking if collection exists") + if self.collection.count() == 0: + print(f"Collection {self.collection_name} does not exist. Creating a new one.") + documents = self.load_documents() + self.add_documents_to_collection(documents) + else: + print(f"Collection {self.collection_name} already exists. Loading existing documents.") + print(f"Collection {self.collection_name} initialized with {self.collection.count()} documents.") + except Exception as e: + print(f"Error initializing collection {self.collection_name}: {e}") + raise e + + def parse_txt_file(self, file_path: str): + """Parse a txt file and return its content.""" + with open(file_path, "r", encoding="utf-8") as file: + content = file.read() + content = TextPreprocessor.preprocess_text(content) + return content + + def parse_pdf_file(self, file_path: str): + """Parse a pdf file and return its content.""" + with open(file_path, "rb") as file: + reader = PdfReader(file) + content = "" + for page in reader.pages: + content += page.extract_text() + content = TextPreprocessor.preprocess_text(content) + return content + + def load_documents(self)-> Dict[str, str]: + """Load txt documents from the specified path.""" + + documents = {} + for filename in os.listdir(self.documents_path): + file_path = os.path.join(self.documents_path, filename) + if filename.endswith(".txt"): + content = self.parse_txt_file(file_path) + + elif filename.endswith(".pdf"): + content = self.parse_pdf_file(file_path) + + else: + continue + + if len(content) > 0: + documents[filename] = content + else: + print(f"File {filename} is empty or not valid. Skipping.") + continue + + return documents + + def add_documents_to_collection(self, documents: Dict[str, str]): + """ + Add documents to the ChromaDB collection. + Args: + documents (Dict[str, str]): A dictionary of documents with filenames as keys and content as values. + """ + print(f"Adding {len(documents)} documents to the collection.") + text_splitter = TextSplitter(self.chunk_size, self.chunk_overlap) + splitted_documents = text_splitter.split_documents_texts(documents) + print(f"Splitting documents into {len(splitted_documents)} chunks.") + + for i, (filename, chunk_index, chunk_text) in enumerate(splitted_documents): + embedding = self.embedding([chunk_text])[0] + try: + self.collection.add( + documents=chunk_text, + metadatas={"filename": filename, "chunk_index": chunk_index}, + embeddings=embedding, + ids=f"{filename}_{chunk_index}", + ) + except Exception as e: + print(f"Error adding document {filename} chunk {chunk_index}: {e}") + continue + + print(f"Added {len(documents)} documents and {len(splitted_documents)} chunks to the collection.") + + def retrieve(self, query_texts: List[str], n_docs: int = None)-> Dict[str, str]: + """ + Retrieve documents based on the query. + + Args: + query_texts (List[str]): The query strings. + n_docs (int): The number of documents to retrieve. + + Returns: + list: A list of retrieved documents. + """ + if n_docs is None: + n_docs = self.n_docs + + results = self.collection.query( + query_embeddings=self.embedding(query_texts), + n_results= n_docs*len(query_texts), + include=["documents", "metadatas", "distances"] + ) + + retrieved_documents = {} + for query_text, query_docs, query_metadatas, query_distances in zip(query_texts, results["documents"], results["metadatas"], results["distances"]): + for doc, metadata, distance in zip(query_docs, query_metadatas, query_distances): + if distance <= self.max_distance: + docname = metadata["filename"]+"_chunk_"+str(metadata["chunk_index"]) + retrieved_documents[docname] = doc + + return retrieved_documents \ No newline at end of file diff --git a/DashAI/back/models/RAG/encodings/tf_idf_encoding.py b/DashAI/back/models/RAG/encodings/tf_idf_encoding.py new file mode 100644 index 000000000..936f4aa01 --- /dev/null +++ b/DashAI/back/models/RAG/encodings/tf_idf_encoding.py @@ -0,0 +1,32 @@ +from chromadb import EmbeddingFunction, Embeddings +from typing import List +from sklearn.feature_extraction.text import TfidfVectorizer +import pickle +import os + +class TfidfEmbeddingFunction(EmbeddingFunction): + """A dummy embedding function using TF-IDF.""" + def __init__(self, corpus: List[str], collection_name: str = None): + if collection_name: + stored_path = os.path.join(os.getcwd(), "saved_encoders", "tfidf", collection_name) + + if os.path.exists(stored_path): + with open(stored_path, "rb") as f: + self.vectorizer = pickle.load(f) + return + + self.vectorizer = TfidfVectorizer() + self.vectorizer.fit(corpus) + + if collection_name: + os.makedirs(os.path.dirname(stored_path), exist_ok=True) + with open(stored_path, "wb") as f: + pickle.dump(self.vectorizer, f) + + def __call__(self, texts: List[str]) -> Embeddings: + """Transform the texts into TF-IDF embeddings.""" + return self.vectorizer.transform(texts).toarray().tolist() + + @staticmethod + def name() -> str: + return "default" \ No newline at end of file diff --git a/DashAI/back/models/RAG/prompts/__init__.py b/DashAI/back/models/RAG/prompts/__init__.py new file mode 100644 index 000000000..95e26dcfe --- /dev/null +++ b/DashAI/back/models/RAG/prompts/__init__.py @@ -0,0 +1,3 @@ +from DashAI.back.models.RAG.prompts.augmentation_prompt import AugmentationPrompt +from DashAI.back.models.RAG.prompts.context_merge_prompt import ContextMergePrompt +from DashAI.back.models.RAG.prompts.base_prompt import BasePrompt \ No newline at end of file diff --git a/DashAI/back/models/RAG/prompts/augmentation_prompt.py b/DashAI/back/models/RAG/prompts/augmentation_prompt.py new file mode 100644 index 000000000..a5d399b8a --- /dev/null +++ b/DashAI/back/models/RAG/prompts/augmentation_prompt.py @@ -0,0 +1,51 @@ +from typing import List, Tuple, Any + +from DashAI.back.models.RAG.prompts.base_prompt import BasePrompt + +class AugmentationPrompt(BasePrompt): + """ + AugmentationPrompt class for generating augmented retrieval prompts, + it uses the language model to generate keywords or phrases that can be used to augment the input. + """ + @staticmethod + def format( + input: str, + history:List[Tuple[str, str]], + n_seach_terms: int = 5, + **kwargs: Any + ) -> str: + """ + Instantiate and format the prompt for augmentation. + Args: + input (str): The input to be formatted. + history (List[Tuple[str, str]]): The history of the conversation. + n_seach_terms (int): The number of search terms to generate. + **kwargs: Additional keyword arguments for formatting. + Returns: + str: The formatted prompt. + """ + if history: + formatted_history = "\n".join( + [f"Q: {h_input}\nA: {h_output}" for h_input, h_output in history] + ) + else: + formatted_history = "" + + keyword_dict = "{'keywords': [" + for i in range(n_seach_terms): + keyword_dict += f"'keyword_{i+1}', " + keyword_dict = keyword_dict[:-2] + "]}" + return f""" + You are a intelligent and insightful assistant. Your task is to generate keywords or phrases to search for + relevant information based on the input provided. The keywords or phrases should be relevant to the input + and should help in retrieving useful information to improve the precision of the response. + The user input is: + {input} + The chat history is: + {formatted_history} + The number of keywords or phrases to generate is {n_seach_terms}. + Please generate {n_seach_terms} keywords or phrases that can be used to search for relevant information. + The keywords or phrases should be concise and to the point. You must fill the following template: + {keyword_dict} + """ + \ No newline at end of file diff --git a/DashAI/back/models/RAG/prompts/base_prompt.py b/DashAI/back/models/RAG/prompts/base_prompt.py new file mode 100644 index 000000000..7f66fcc74 --- /dev/null +++ b/DashAI/back/models/RAG/prompts/base_prompt.py @@ -0,0 +1,20 @@ +from abc import ABC +from typing import Any + +class BasePrompt(ABC): + """ + Base class for all RAG prompt templates. + This class defines the interface for creating and formatting prompts. + """ + @staticmethod + def format(input: str, **kwargs: Any) -> str: + """ + Instantiate and format the prompt. + Args: + input (str): The input to be formatted. + **kwargs: Additional keyword arguments for formatting. + Returns: + str: The formatted prompt. + """ + raise NotImplementedError("Subclasses must implement this method.") + \ No newline at end of file diff --git a/DashAI/back/models/RAG/prompts/context_merge_prompt.py b/DashAI/back/models/RAG/prompts/context_merge_prompt.py new file mode 100644 index 000000000..7f00a2787 --- /dev/null +++ b/DashAI/back/models/RAG/prompts/context_merge_prompt.py @@ -0,0 +1,43 @@ +from typing import Any, List, Tuple +from DashAI.back.models.RAG.prompts.base_prompt import BasePrompt + +class ContextMergePrompt(BasePrompt): + """ + ContextMergePrompt class for generating prompts that merge the use input, the retrieved + documents and the chat history into a single context for the language model. + """ + @staticmethod + def format( + input: str, + history:List[Tuple[str, str]], + documents: str, + **kwargs: Any + ) -> str: + """ + Instantiate and format the prompt for context merging. + Args: + input (str): The input to be formatted. + documents (str): The retrieved documents to be included in the context. + history (str): The chat history to be included in the context. + **kwargs: Additional keyword arguments for formatting. + Returns: + str: The formatted prompt. + """ + return f""" + You are a intelligent and insightful assistant. + Your task is to generate a response to the user message. To do this, you will be provided with the user input, + documents retrieved from a database that can be useful for the response, and the chat history. + The user input is: + {input} + The retrieved documents are: + {documents} + The chat history is: + {history} + Please generate a response that takes into account the input, the retrieved documents and the chat history, you + must respond in a conversational manner. + Use the information from the retrieved documents to provide a more accurate and relevant response to the user, + if the information is not relevant to the user input, you can ignore it. + Your response should be clear, concise and relevant to the input provided, using natural language. + + RESPONSE: + """ \ No newline at end of file diff --git a/DashAI/back/models/RAG/text_preprocessor.py b/DashAI/back/models/RAG/text_preprocessor.py new file mode 100644 index 000000000..86023de73 --- /dev/null +++ b/DashAI/back/models/RAG/text_preprocessor.py @@ -0,0 +1,39 @@ +import re +from typing import Dict + +class TextPreprocessor: + """ + A simple text preprocessor that removes special characters and extra spaces from text. + This is useful for cleaning text data before processing. + """ + + @staticmethod + def preprocess_text(text: str) -> str: + """ + Preprocess the text by removing special characters and extra spaces. + Args: + text (str): The text to be preprocessed. + Returns: + str: The preprocessed text. + """ + # Remove special characters except for periods, commas, and spaces + pattern = r"[^a-zA-Z0-9áéíóúüñÁÉÍÓÚÜÑ(),¿?¡! \[\]:;\n\-_]+" + text = re.sub(pattern, " ", text).strip() + # Remove extra spaces + text = re.sub(r"\s+", " ", text) + return text + + @staticmethod + def preprocess_documents_texts(documents: Dict[str, str]) -> Dict[str, str]: + """ + Preprocess the documents' texts. + Args: + documents (Dict[str, str]): A dictionary of documents with filenames as keys and content as values. + Returns: + Dict[str, str]: A dictionary of preprocessed documents with filenames as keys and preprocessed content as values. + """ + preprocessed_documents = {} + for filename, content in documents.items(): + preprocessed_content = TextPreprocessor.preprocess_text(content) + preprocessed_documents[filename] = preprocessed_content + return preprocessed_documents \ No newline at end of file diff --git a/DashAI/back/models/RAG/text_splitter.py b/DashAI/back/models/RAG/text_splitter.py new file mode 100644 index 000000000..2a9fbb069 --- /dev/null +++ b/DashAI/back/models/RAG/text_splitter.py @@ -0,0 +1,41 @@ +from typing import List, Dict, Tuple +class TextSplitter: + """ + A simple text splitter that splits text into chunks of a specified size with overlap. + This is useful for processing large texts in smaller parts. + """ + def __init__(self, chunk_size=1000, chunk_overlap=200): + self.chunk_size = chunk_size + self.chunk_overlap = chunk_overlap + + def split_text(self, text: str) -> List[str]: + """ + Split the text into chunks of specified size with overlap. + Args: + text (str): The text to be split. + Returns: + List[str]: A list of text chunks. + """ + chunks = [] + for i in range(0, len(text), self.chunk_size - self.chunk_overlap): + chunk = text[i:i + self.chunk_size] + if chunk: + chunks.append(chunk) + return chunks + + def split_documents_texts(self, documents: Dict[str, str]) -> List[Tuple[str, int, str]]: + """ + Split the documents into chunks of text. + Args: + documents (Dict[str, str]): A dictionary of documents with filenames as keys and content as values. + Returns: + List[Tuple[str, int, str]]: A list of tuples containing the filename, chunk index, and chunk content. + """ + chunked_documents = [] + for filename, content in documents.items(): + chunks = self.split_text(content) + for i, chunk in enumerate(chunks): + chunked_documents.append( + (filename, i, chunk) + ) + return chunked_documents \ No newline at end of file diff --git a/DashAI/back/models/__init__.py b/DashAI/back/models/__init__.py index d2b98cec6..58a4f6b87 100644 --- a/DashAI/back/models/__init__.py +++ b/DashAI/back/models/__init__.py @@ -53,3 +53,5 @@ from DashAI.back.models.scikit_learn.sklearn_like_model import SklearnLikeModel from DashAI.back.models.scikit_learn.sklearn_like_regressor import SklearnLikeRegressor from DashAI.back.models.scikit_learn.svc import SVC + +from DashAI.back.models.RAG import RAGPipeline \ No newline at end of file diff --git a/DashAI/back/models/hugging_face/deep_seek_model.py b/DashAI/back/models/hugging_face/deep_seek_model.py index 4ba808209..33469c03d 100644 --- a/DashAI/back/models/hugging_face/deep_seek_model.py +++ b/DashAI/back/models/hugging_face/deep_seek_model.py @@ -50,7 +50,7 @@ def __init__(self, **kwargs): self.n_ctx = kwargs.pop("n_ctx", 512) self.model_id = "TheBloke/deepseek-llm-7B-base-GGUF" - self.filename = "*Q8_0.gguf" + self.filename = "*Q3_K_S.gguf" self.model = Llama.from_pretrained( repo_id=self.model_id, filename=self.filename, verbose=True, n_ctx=self.n_ctx, n_gpu_layers=-1 diff --git a/DashAI/back/tasks/RAG_task.py b/DashAI/back/tasks/RAG_task.py new file mode 100644 index 000000000..0719cd1ca --- /dev/null +++ b/DashAI/back/tasks/RAG_task.py @@ -0,0 +1,118 @@ +from typing import Any, List, Tuple +from itertools import chain + +from DashAI.back.tasks.base_generative_task import BaseGenerativeTask + + +class RAGTask(BaseGenerativeTask): + """Base class for image generation tasks. + + Here you can change the methods provided by class Task. + """ + + metadata: dict = { + "inputs_types": [str], + "outputs_types": [str], + "inputs_cardinality": 1, + "outputs_cardinality": 1, + } + + DESCRIPTION: str = "This task generates a text response based on documents provided and chat." + + DISPLAY_NAME: str = "Retreival-Augmented Generation (RAG) Task" + + USE_HISTORY: bool = True + + def prepare_for_task( + self, + input: List[str], + **kwargs: Any, + ) -> Tuple[str, List[str]]: + """Prepare the input by including the history in Q: A: format and retrieving the documents. + + Parameters + ---------- + input : str + The current input to be processed. + + + Returns + ------- + str + The input message + + list[str] + The history of the conversation + """ + + return input # type: Optional[List[Tuple[str, str]]] + + + + def prepare_input_for_database( + self, + input: List[str], + **kwargs: Any, + ) -> List[str]: + """Prepare the input for the database. + + Parameters + ---------- + input : str + The input to be prepared. + + Returns + ------- + str + The prepared input. + """ + return input[0], kwargs.get("history", None) # type: Optional[List[Tuple[str, str]]] + + + def process_output( + self, + output: List[Any], + **kwargs: Any, + ) -> str: + """Process the output of a generative model.""" + + return output + + def process_output_from_database( + self, + output: List[str], + **kwargs: Any, + ) -> List[str]: + """Process the output from the database. + + Parameters + ---------- + output : list[str] + The output data to be processed. + + Returns + ------- + list[str] + The processed output data. + """ + + return output + + def process_input_from_database( + self, + input: List[str], + **kwargs: Any, + ) -> List[str]: + """Process the input from the database. + + Parameters + ---------- + input : list[str] + The input data to be processed. + + Returns + ------- + list[str] + The processed input data. + """ + return input diff --git a/DashAI/back/tasks/__init__.py b/DashAI/back/tasks/__init__.py index 5cc9e1b63..de92dd78a 100644 --- a/DashAI/back/tasks/__init__.py +++ b/DashAI/back/tasks/__init__.py @@ -9,3 +9,5 @@ from DashAI.back.tasks.text_classification_task import TextClassificationTask from DashAI.back.tasks.text_to_image_generation_task import TextToImageGenerationTask from DashAI.back.tasks.translation_task import TranslationTask + +from DashAI.back.tasks.RAG_task import RAGTask \ No newline at end of file From 1ba8382b0d763d34f4ad7c5e01f2057a356b7603 Mon Sep 17 00:00:00 2001 From: sofiachavezb Date: Sun, 29 Jun 2025 01:10:58 -0400 Subject: [PATCH 002/218] Basic rag configuration --- .../back/api/api_v1/endpoints/components.py | 31 ++ DashAI/back/initial_components.py | 1 + DashAI/back/models/RAG/RAG_pipeline.py | 6 +- DashAI/back/models/RAG/dummy_retriever.py | 58 +-- .../models/RAG/encodings/tf_idf_encoding.py | 6 +- DashAI/back/tasks/RAG_task.py | 10 +- DashAI/front/src/api/component.ts | 1 + DashAI/front/src/api/generativeTask.ts | 12 +- DashAI/front/src/api/rag.ts | 423 ++++++++++++++++++ .../datasets/ConfigureAndUploadDataset.jsx | 17 +- .../components/documents/DocumentTable.jsx | 205 +++++++++ .../experiments/EditModelDialog.jsx | 4 +- .../generative/MainGenerativeBox.jsx | 4 +- .../src/components/generative/ParamsBar.jsx | 2 +- .../generative/RAG/ComponentSelector.jsx | 178 ++++++++ .../generative/RAG/DocumentDropzone.jsx | 45 ++ .../generative/RAG/DocumentSelector.jsx | 106 +++++ .../generative/RAG/DocumentTable.jsx | 101 +++++ .../generative/RAG/SessionMetadata.jsx | 82 ++++ .../components/generative/SelectModelMenu.jsx | 2 +- .../shared/FormSchemaRenderFields.jsx | 2 + .../{datasets => shared}/Upload.jsx | 14 +- .../front/src/pages/generative/Generative.jsx | 90 ++-- .../RAG/AlgorithmConfigurationStep.jsx | 41 ++ .../generative/RAG/DocumentSelectionStep.jsx | 94 ++++ .../generative/RAG/ModelConfigurationStep.jsx | 50 +++ .../pages/generative/RAG/NewSessionModal.jsx | 252 +++++++++++ .../src/pages/generative/RAG/RAGHomePage.jsx | 55 +++ .../pages/generative/RAG/RAGSessionsTable.jsx | 175 ++++++++ .../RAG/RetrieverConfigurationStep.jsx | 38 ++ DashAI/front/yarn.lock | 6 +- requirements.txt | 2 + 32 files changed, 2023 insertions(+), 90 deletions(-) create mode 100644 DashAI/front/src/api/rag.ts create mode 100644 DashAI/front/src/components/documents/DocumentTable.jsx create mode 100644 DashAI/front/src/components/generative/RAG/ComponentSelector.jsx create mode 100644 DashAI/front/src/components/generative/RAG/DocumentDropzone.jsx create mode 100644 DashAI/front/src/components/generative/RAG/DocumentSelector.jsx create mode 100644 DashAI/front/src/components/generative/RAG/DocumentTable.jsx create mode 100644 DashAI/front/src/components/generative/RAG/SessionMetadata.jsx rename DashAI/front/src/components/{datasets => shared}/Upload.jsx (94%) create mode 100644 DashAI/front/src/pages/generative/RAG/AlgorithmConfigurationStep.jsx create mode 100644 DashAI/front/src/pages/generative/RAG/DocumentSelectionStep.jsx create mode 100644 DashAI/front/src/pages/generative/RAG/ModelConfigurationStep.jsx create mode 100644 DashAI/front/src/pages/generative/RAG/NewSessionModal.jsx create mode 100644 DashAI/front/src/pages/generative/RAG/RAGHomePage.jsx create mode 100644 DashAI/front/src/pages/generative/RAG/RAGSessionsTable.jsx create mode 100644 DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx diff --git a/DashAI/back/api/api_v1/endpoints/components.py b/DashAI/back/api/api_v1/endpoints/components.py index 68e991196..7e4953078 100644 --- a/DashAI/back/api/api_v1/endpoints/components.py +++ b/DashAI/back/api/api_v1/endpoints/components.py @@ -87,6 +87,20 @@ async def get_components( HTTPException If task_name does not exist in the registry """ + + print("select_types", str(select_types)) + print("ignore_types", str(ignore_types)) + print("related_component", str(related_component)) + print("component_parent", str(component_parent)) + print("has_related_of_type", str(has_related_of_type)) + print("component_registry", str(component_registry)) + + + print(list(component_registry._registry.keys())) + print(related_component in component_registry._registry) + print(component_registry) + + print("get_components api ") # when select_type is not none, check if it exists in the registry. if select_types is not None: for select_type in select_types: @@ -99,6 +113,8 @@ async def get_components( ), ) + print("get_components api 2") + # when ignore_type is not none, check if it exists in the registry. if ignore_types is not None: for ignore_type in ignore_types: @@ -111,6 +127,8 @@ async def get_components( ), ) + print("get_components api 3") + # when task_name is not none, check if it exists in the registry. if related_component is not None and related_component not in component_registry: raise HTTPException( @@ -121,6 +139,8 @@ async def get_components( ), ) + print("get_components api 4") + # When has_related_type is not none, check if it exists in the registry. if ( has_related_of_type is not None @@ -134,6 +154,8 @@ async def get_components( ), ) + print("get_components api 5") + # 1. obtain all components from the selected registry/registries # if none, get_components_by_type returns all components. selected_components = { @@ -143,6 +165,8 @@ async def get_components( ) } + print("get_components api 6") + # 2. ignore the requested types if ignore_types is not None: selected_components = _intersect_component_lists( @@ -150,6 +174,8 @@ async def get_components( component_registry.get_components_by_types(ignore=ignore_types), ) + print("get_components api 7") + # 3. select only the components related to "related_component" if related_component is not None: selected_components = _intersect_component_lists( @@ -157,6 +183,8 @@ async def get_components( component_registry.get_related_components(related_component), ) + print("get_components api 8") + # 4. filter if component parent was specified. if component_parent is not None: selected_components = _intersect_component_lists( @@ -164,6 +192,8 @@ async def get_components( component_registry.get_child_components(component_parent, recursive=True), ) + print("get_components api 9") + # 5. filter if "has_related_of_type" was specified. if has_related_of_type is not None: components_with_related_type = [] @@ -176,6 +206,7 @@ async def get_components( components_with_related_type, ) + print("get_components api 10") return [ _delete_class(component_dict) for component_dict in selected_components.values() ] diff --git a/DashAI/back/initial_components.py b/DashAI/back/initial_components.py index ea4659d69..23d734df9 100644 --- a/DashAI/back/initial_components.py +++ b/DashAI/back/initial_components.py @@ -66,6 +66,7 @@ ExplorerJob, ModelJob, PredictJob, + GenerativeJob ) from DashAI.back.metrics import F1, MAE, RMSE, Accuracy, Bleu, Precision, Recall, Ter from DashAI.back.models import ( diff --git a/DashAI/back/models/RAG/RAG_pipeline.py b/DashAI/back/models/RAG/RAG_pipeline.py index f478fe118..9ed9338a3 100644 --- a/DashAI/back/models/RAG/RAG_pipeline.py +++ b/DashAI/back/models/RAG/RAG_pipeline.py @@ -13,7 +13,7 @@ from DashAI.back.models.hugging_face.deep_seek_model import DeepSeekModel from DashAI.back.models.hugging_face.qwen_model import QwenModel -from DashAI.back.models.llm_generation_model import LLMGenerationModel +from DashAI.back.models.text_to_text_generation_model import TextToTextGenerationTaskModel from DashAI.back.models.RAG.dummy_retriever import DummyRetriever from DashAI.back.models.RAG.prompts import ( BasePrompt, @@ -109,7 +109,7 @@ class RAGPipelineSchema(BaseSchema): description="Maximum number of tokens the model can process in a single forward pass (context window size).", ) # type: ignore -class RAGPipeline(BaseGenerativeModel): +class RAGPipeline(TextToTextGenerationTaskModel): """Retrieval-Augmented Generation (RAG) pipeline.""" COMPATIBLE_COMPONENTS = ["RAGTask"] @@ -143,7 +143,7 @@ def __init__( self, } print("Initializing LLM model") - self.llm_model: LLMGenerationModel = llm_classes[kwargs.get("model_name")](**llm_kwargs) + self.llm_model: TextToTextGenerationTaskModel = llm_classes[kwargs.get("model_name")](**llm_kwargs) # Initialize the retriever retriever_params = { diff --git a/DashAI/back/models/RAG/dummy_retriever.py b/DashAI/back/models/RAG/dummy_retriever.py index 82463d0e8..2f781668d 100644 --- a/DashAI/back/models/RAG/dummy_retriever.py +++ b/DashAI/back/models/RAG/dummy_retriever.py @@ -1,6 +1,6 @@ import os -import chromadb -from chromadb import Settings +#import chromadb +#from chromadb import Settings from typing import List, Dict from pypdf import PdfReader from DashAI.back.models.RAG.encodings.tf_idf_encoding import TfidfEmbeddingFunction @@ -52,7 +52,7 @@ def __init__( self.max_distance = max_distance self.chunk_size = chunk_size self.chunk_overlap = chunk_overlap - self.collection: chromadb.Collection = None + self.collection = None #chromadb.Collection = None self.embedding = TfidfEmbeddingFunction( corpus=self.load_documents().values(), collection_name=self.collection_name, @@ -68,36 +68,37 @@ def __init_chromadb__(self): """ print("Initializing ChromaDB client") - client = chromadb.PersistentClient( + client = None + return + """ chromadb.PersistentClient( settings=Settings( anonymized_telemetry=False, - )) + )) """ print("Initializing ChromaDB collection") - self.collection = client.get_or_create_collection( - name=self.collection_name, - configuration={ - "embedding_function": self.embedding.name(), - }, - embedding_function=self.embedding, - metadata={ - "distance_function": self.distance_function, + stored_collections = client.list_collections() + stored_collections_names = [collection.name for collection in stored_collections] + if self.collection_name in stored_collections_names: + print(f"Collection {self.collection_name} already exists. Loading existing collection.") + self.collection = client.get_collection(name=self.collection_name) + else: + print(f"Collection {self.collection_name} does not exist. Creating a new collection.") + # Create a new collection with the specified embedding function + self.collection = client.create_collection( + name=self.collection_name, + configuration={ + "embedding_function": self.embedding.name(), + }, + embedding_function=self.embedding, + metadata={ + "distance_function": self.distance_function, }, - ) - print(f"Collection {self.collection_name} initialized.") - try: - print("Checking if collection exists") - if self.collection.count() == 0: - print(f"Collection {self.collection_name} does not exist. Creating a new one.") - documents = self.load_documents() - self.add_documents_to_collection(documents) - else: - print(f"Collection {self.collection_name} already exists. Loading existing documents.") - print(f"Collection {self.collection_name} initialized with {self.collection.count()} documents.") - except Exception as e: - print(f"Error initializing collection {self.collection_name}: {e}") - raise e - + ) + print(f"Collection {self.collection_name} initialized with distance function {self.distance_function}.") + + documents = self.load_documents() + self.add_documents_to_collection(documents) + def parse_txt_file(self, file_path: str): """Parse a txt file and return its content.""" with open(file_path, "r", encoding="utf-8") as file: @@ -152,6 +153,7 @@ def add_documents_to_collection(self, documents: Dict[str, str]): for i, (filename, chunk_index, chunk_text) in enumerate(splitted_documents): embedding = self.embedding([chunk_text])[0] try: + print(f"Adding document {i+1}/{len(splitted_documents)}: {filename} chunk {chunk_index}") self.collection.add( documents=chunk_text, metadatas={"filename": filename, "chunk_index": chunk_index}, diff --git a/DashAI/back/models/RAG/encodings/tf_idf_encoding.py b/DashAI/back/models/RAG/encodings/tf_idf_encoding.py index 936f4aa01..f74045ae2 100644 --- a/DashAI/back/models/RAG/encodings/tf_idf_encoding.py +++ b/DashAI/back/models/RAG/encodings/tf_idf_encoding.py @@ -1,10 +1,10 @@ -from chromadb import EmbeddingFunction, Embeddings +#from chromadb import EmbeddingFunction, Embeddings from typing import List from sklearn.feature_extraction.text import TfidfVectorizer import pickle import os -class TfidfEmbeddingFunction(EmbeddingFunction): +class TfidfEmbeddingFunction:#(EmbeddingFunction): """A dummy embedding function using TF-IDF.""" def __init__(self, corpus: List[str], collection_name: str = None): if collection_name: @@ -23,7 +23,7 @@ def __init__(self, corpus: List[str], collection_name: str = None): with open(stored_path, "wb") as f: pickle.dump(self.vectorizer, f) - def __call__(self, texts: List[str]) -> Embeddings: + def __call__(self, texts: List[str]):# -> Embeddings: """Transform the texts into TF-IDF embeddings.""" return self.vectorizer.transform(texts).toarray().tolist() diff --git a/DashAI/back/tasks/RAG_task.py b/DashAI/back/tasks/RAG_task.py index 50739e7e6..f8d309847 100644 --- a/DashAI/back/tasks/RAG_task.py +++ b/DashAI/back/tasks/RAG_task.py @@ -17,9 +17,8 @@ class RAGTask(BaseGenerativeTask): "outputs_cardinality": 1, } - DESCRIPTION: str = "This task generates a text response based on documents provided and chat." - DISPLAY_NAME: str = "Retreival-Augmented Generation (RAG) Task" + DESCRIPTION: str = "This task generates a text response based on documents provided and chat." USE_HISTORY: bool = True @@ -63,10 +62,11 @@ def prepare_input_for_database( Returns ------- - str - The prepared input. + List[Tuple[str, str]] + Input with the new types as a list of tuples containing the data + and its type """ - return input[0], kwargs.get("history", None) # type: Optional[List[Tuple[str, str]]] + return [(input[0], "str")] def process_output( diff --git a/DashAI/front/src/api/component.ts b/DashAI/front/src/api/component.ts index 98b87c715..9a7306017 100644 --- a/DashAI/front/src/api/component.ts +++ b/DashAI/front/src/api/component.ts @@ -1,6 +1,7 @@ import api from "./api"; import type { IComponent } from "../types/component"; + interface componentQuery { model?: string; selectTypes?: string[]; diff --git a/DashAI/front/src/api/generativeTask.ts b/DashAI/front/src/api/generativeTask.ts index d64c2c18f..73957488d 100644 --- a/DashAI/front/src/api/generativeTask.ts +++ b/DashAI/front/src/api/generativeTask.ts @@ -12,10 +12,14 @@ export const getGenerativeTask = async (): Promise => { export const getRelatedComponents = async ( relatedComponent: string, ): Promise => { - const response = await api.get( - `/v1/component/?related_component=${encodeURIComponent(relatedComponent)}`, - ); - return response.data; + try{ + const response = await api.get( + `/v1/component/?related_component=${encodeURIComponent(relatedComponent)}`, + ); + return response.data; + } catch (error) { + return []; + } }; export const createGenerativeSession = async ( diff --git a/DashAI/front/src/api/rag.ts b/DashAI/front/src/api/rag.ts new file mode 100644 index 000000000..8e57f2a99 --- /dev/null +++ b/DashAI/front/src/api/rag.ts @@ -0,0 +1,423 @@ +import api from "./api"; +import { ISession } from "../types/session"; +import { IGenerativeTask } from "../types/generativeTask"; + + + + + +// Dummy data +// use the days of june 2025 for first, second, ... sessions +let sessions: ISession[] = [ + { + id: "1", + name: "Session I", + task_name: "RAGTask", + description: "First dummy session", + created: new Date("2025-06-01"), + last_modified: new Date("2025-06-01"), + display_name: "RAG Session I", + model_name: "RAGModel", + parameters: { paramA: 1 }, + }, + { + id: "2", + name: "Session II", + task_name: "RAGTask", + description: "Second dummy session", + created: new Date("2025-06-02"), + last_modified: new Date("2025-06-02"), + display_name: "RAG Session II", + model_name: "RAGModel", + parameters: { paramA: 2 }, + }, + { + id: "3", + name: "Session III", + task_name: "RAGTask", + description: "Third dummy session", + created: new Date("2025-06-03"), + last_modified: new Date("2025-06-03"), + display_name: "RAG Session III", + model_name: "RAGModel", + parameters: { paramA: 3 }, + }, + { + id: "4", + name: "Session IV", + task_name: "RAGTask", + description: "Fourth dummy session", + created: new Date("2025-06-04"), + last_modified: new Date("2025-06-04"), + display_name: "RAG Session IV", + model_name: "RAGModel", + parameters: { paramA: 4 }, + } +]; + +let components: IGenerativeTask[] = [ + { + name: "Dense Passage Retrieval", + type: "retriever", + configurable_object: true, + schema: { + description: "Schema for dense passage retrieval", + properties: { + paramA: { + description: "Transformer", + enum: [ + "BERT", + "RoBERTa", + "DistilBERT", + "ALBERT", + ], + placeholder: "BERT", + title: "Parameter A", + type: "string", + }, + DistanceMetric: { + description: "Distance metric to use for retrieval", + enum: [ + "cosine", + "dot_product", + "euclidean", + ], + placeholder: "cosine", + title: "Distance Metric", + type: "string", + }, + }, + required: ["paramA", "DistanceMetric"], + type: "object", + }, + metadata: { + inputs_cardinality: 1, + outputs_cardinality: 1, + inputs_types: ["text"], + outputs_types: ["text"], + }, + description: "A component for dense passage retrieval", + display_name: "Dense Passage Retrieval", + }, + { + name: "TFIDFRetriever", + type: "retriever", + configurable_object: true, + schema: { + description: "Schema for TF-IDF retriever", + properties: { + paramA: { + description: "Remove stop words", + placeholder: "true", + title: "Remove Stop Words", + type: "boolean" + }, + TokenScoreCombination: { + description: "Token score combination method", + enum: [ + "sum", + "max", + "min", + ], + placeholder: "sum", + title: "Token Score Combination", + type: "string" + }, + }, + required: ["paramA", "TokenScoreCombination"], + type: "object", + }, + metadata: { + inputs_cardinality: 1, + outputs_cardinality: 1, + inputs_types: ["text"], + outputs_types: ["text"], + }, + description: "A component for TF-IDF retrieval", + display_name: "TF-IDF Retriever", + }, + + { + name: "DeepSeekModel", + type: "GenerativeModel", + configurable_object: true, + schema: { + description: "Schema for DeepSeek model.", + properties: { + max_tokens: { + description: "Maximum number of tokens to generate.", + minimum: 1, + placeholder: 100, + title: "Max Tokens", + type: "integer" + }, + temperature: { + description: "Sampling temperature. Higher values make the output more random, while lower values make it more focused and deterministic.", + maximum: 1, + minimum: 0, + placeholder: 0.7, + title: "temperature", + type: "number" + }, + frequency_penalty: { + description: "Penalty for repeated tokens in the output. Higher values reduce the likelihood of repetition, encouraging more diverse text generation.", + maximum: 2, + minimum: 0, + placeholder: 0.1, + title: "Frequency Penalty", + type: "number" + }, + n_ctx: { + description: "Maximum number of tokens the model can process in a single forward pass (context window size).", + minimum: 1, + placeholder: 4096, + title: "N Ctx", + type: "integer" + } + }, + required: [ + "max_tokens", + "temperature", + "frequency_penalty", + "n_ctx" + ], + title: "DeepSeekSchema", + type: "object" + }, + metadata: { + inputs_cardinality: 1, + outputs_cardinality: 1, + inputs_types: ["text"], + outputs_types: ["text"] + }, + description: "null,", + display_name: "null" + }, + { + name: "GemmaModel", + type: "GenerativeModel", + configurable_object: true, + schema: { + description: "Schema for Gemma model.", + properties: { + max_tokens: { + description: "Maximum number of tokens to generate.", + minimum: 1, + placeholder: 100, + title: "Max Tokens", + type: "integer" + }, + temperature: { + description: "Sampling temperature. Higher values make the output more random, while lower values make it more focused and deterministic.", + maximum: 1, + minimum: 0, + placeholder: 0.7, + title: "temperature", + type: "number" + }, + frequency_penalty: { + description: "Penalty for repeated tokens in the output. Higher values reduce the likelihood of repetition, encouraging more diverse text generation.", + maximum: 2, + minimum: 0, + placeholder: 0.1, + title: "Frequency Penalty", + type: "number" + }, + n_ctx: { + description: "Maximum number of tokens the model can process in a single forward pass (context window size).", + minimum: 1, + placeholder: 512, + title: "N Ctx", + type: "integer" + } + }, + required: [ + "max_tokens", + "temperature", + "frequency_penalty", + "n_ctx" + ], + title: "GemmaSchema", + type: "object" + }, + metadata: { + inputs_cardinality: 1, + outputs_cardinality: 1, + inputs_types: ["text"], + outputs_types: ["text"] + }, + description: "null,", + display_name: "null" + }, + { + name: "QwenModel", + type: "GenerativeModel", + configurable_object: true, + schema: { + description: "Schema for Qwen model.", + properties: { + "model_name": { + description: "The specific Qwen model version to use.", + "enum": [ + "Qwen/Qwen2.5-0.5B-Instruct-GGUF", + "Qwen/Qwen2.5-1.5B-Instruct-GGUF" + ], + placeholder: "Qwen/Qwen2.5-1.5B-Instruct-GGUF", + title: "Model Name", + type: "string" + }, + max_tokens: { + description: "Maximum number of tokens to generate.", + minimum: 1, + placeholder: 100, + title: "Max Tokens", + type: "integer" + }, + temperature: { + description: "Sampling temperature. Higher values make the output more random, while lower values make it more focused and deterministic.", + maximum: 1, + minimum: 0, + placeholder: 0.7, + title: "temperature", + type: "number" + }, + frequency_penalty: { + description: "Penalty for repeated tokens in the output. Higher values reduce the likelihood of repetition, encouraging more diverse text generation.", + maximum: 2, + minimum: 0, + placeholder: 0.1, + title: "Frequency Penalty", + type: "number" + }, + n_ctx: { + description: "Maximum number of tokens the model can process in a single forward pass (context window size).", + minimum: 1, + placeholder: 512, + title: "N Ctx", + type: "integer" + } + }, + required: [ + "model_name", + "max_tokens", + "temperature", + "frequency_penalty", + "n_ctx" + ], + title: "QwenSchema", + type: "object" + }, + metadata: { + inputs_cardinality: 1, + outputs_cardinality: 1, + inputs_types: ["text"], + outputs_types: ["text"] + }, + description: "null,", + display_name: "null" + } +] + +// Fetch all RAG sessions +export const getRAGSessions = async (): Promise => { + console.log("Fetching all RAG sessions"); + + // Simulate an API call + /* + const response = await api.get( + "/v1/generative-session + */ + return [...sessions]; +} + +// Create a new RAG session +export const createRAGSession = async ( + sessionData: Omit +): Promise => { + const newSession: ISession = { + ...sessionData, + id: (Math.random() * 100000).toFixed(0), + }; + // Simulate an API call + /* + const response = await api.post("/v1/rag-session/", newSession); + */ + sessions.push(newSession); + return newSession; +} + +// Update an existing RAG session +export const updateRAGSession = async ( + sessionData: ISession +): Promise => { + + // Mockup data + const index = sessions.findIndex((s) => s.id === sessionData.id); + if (index === -1) throw new Error("Session not found"); + sessions[index] = sessionData; + + // Simulate an API call + /* + const response = await api.put( + `/v1/rag-session/${sessionData.id}`, + sessionData + ); + */ + + return sessionData; +} + +// Delete a RAG session by ID +export const deleteRAGSession = async (sessionId: string): Promise => { + + // mockup data + sessions = sessions.filter((s) => s.id !== sessionId); + + // Simulate an API call + /* + removeSession(sessionId); + */ + + console.log(`Deleted session with ID: ${sessionId}`); + return; +} + +// Fetch a single RAG session by ID +export const getRAGSession = async (sessionId: string): Promise => { + console.log(`Fetching session with ID: ${sessionId}`); + + // Simulate an API call + /* + const response = await api.get( + `/v1/generative-session/${sessionId}` + + return response.data; + */ + + const session = sessions.find((s) => s.id === sessionId); + if (!session) throw new Error("Session not found"); + + return [session]; +} + +export const getRAGComponents = async (componentType: string): Promise => { + // Simulate fetching RAG components based on type + /* + const response = await api.get( + `/v1/component/?related_component=RAGTask&component_type=${componentType}` + ); + return response.data; + */ + + let filteredComponents = components.filter((c) => c.type === componentType); + console.log(`Fetching RAG ${filteredComponents.length} components of type ${componentType}`); + return filteredComponents; +}; + +export const getRetrieverComponents = async (): Promise => { + return getRAGComponents("retriever"); +} + +export const getGeneratorComponents = async (): Promise => { + return getRAGComponents("GenerativeModel"); +} \ No newline at end of file diff --git a/DashAI/front/src/components/datasets/ConfigureAndUploadDataset.jsx b/DashAI/front/src/components/datasets/ConfigureAndUploadDataset.jsx index a852759f6..101b68ae4 100644 --- a/DashAI/front/src/components/datasets/ConfigureAndUploadDataset.jsx +++ b/DashAI/front/src/components/datasets/ConfigureAndUploadDataset.jsx @@ -1,7 +1,7 @@ import React, { useState, useEffect } from "react"; -import { Grid, Paper } from "@mui/material"; +import { Grid, Paper, Typography } from "@mui/material"; import PropTypes from "prop-types"; -import Upload from "./Upload"; +import Upload from "../shared/Upload"; import { getComponents as getComponentsRequest } from "../../api/component"; import { useSnackbar } from "notistack"; import DataloaderConfiguration from "./DataloaderConfiguration"; @@ -77,7 +77,18 @@ function ConfigureAndUploadDataset({ > {/* Upload file */} - + + Upload your dataset + + If your dataset have splits, upload it as a zip file + + + } + /> + {/* Configure dataloader parameters */} diff --git a/DashAI/front/src/components/documents/DocumentTable.jsx b/DashAI/front/src/components/documents/DocumentTable.jsx new file mode 100644 index 000000000..320c96d90 --- /dev/null +++ b/DashAI/front/src/components/documents/DocumentTable.jsx @@ -0,0 +1,205 @@ +import React, { useEffect, useState, useCallback } from "react"; +import { DataGrid, GridToolbar } from "@mui/x-data-grid"; +import { useSnackbar } from "notistack"; +import { Button, Grid, Paper, Typography, LinearProgress, Box } from "@mui/material"; +import { + get_documents_json, + delete_document as deleteDocumentRequest, +} from "../../api/documents"; +import { + AddCircleOutline as AddIcon, + Update as UpdateIcon, +} from "@mui/icons-material"; +import DeleteItemModal from "../custom/DeleteItemModal"; +import DocumentSummaryModal from "./DocumentSummaryModal"; + +function DocumentTable({ + handleNewDocument, + updateTableFlag, + setUpdateTableFlag, +}) { + const { enqueueSnackbar } = useSnackbar(); + const [loading, setLoading] = useState(true); + const [documents, setDocuments] = useState([]); + const [selectionModel, setSelectionModel] = useState([]); + + const getDocuments = useCallback(async () => { + setLoading(true); + try { + const docs = await get_documents_json(); + setDocuments(docs); + } catch (error) { + enqueueSnackbar("Error when trying to get the documents", { + variant: "error", + }); + console.error("Error fetching documents:", error); + } finally { + setLoading(false); + } + }, [enqueueSnackbar]); + + const deleteDocument = async (doc_name) => { + try { + await deleteDocumentRequest(doc_name); + setUpdateTableFlag(true); + enqueueSnackbar("Document successfully deleted.", { + variant: "success", + }); + } catch (error) { + enqueueSnackbar("Error when trying to delete the document", { + variant: "error", + }); + console.error("Error deleting document:", error); + } + }; + + const createDeleteHandler = useCallback( + (doc_name) => () => { + deleteDocument(doc_name); + }, + [deleteDocument], + ); + + useEffect(() => { + getDocuments(); + }, [getDocuments]); + + useEffect(() => { + if (updateTableFlag) { + getDocuments(); + setUpdateTableFlag(false); + } + }, [updateTableFlag, setUpdateTableFlag, getDocuments]); + + const columns = React.useMemo( + () => [ + { + field: "id", + headerName: "ID", + minWidth: 30, + editable: false, + }, + { + field: "doc_name", + headerName: "Document Name", + minWidth: 200, + editable: false, + }, + { + field: "created_at", + headerName: "Created At", + minWidth: 200, + editable: false, + }, + { + field: "actions", + type: "actions", + minWidth: 150, + getActions: (params) => [ + , + , + ], + }, + ], + [createDeleteHandler], + ); + + return ( + + + + Current documents + + + + + + + + + + + + + + + {(!loading && documents.length === 0) ? ( + + + No documents available + + + ) : ( + row.id} + pageSize={5} + sortModel={[{ field: "id", sort: "asc" }]} + pageSizeOptions={[5, 10]} + checkboxSelection + selectionModel={selectionModel} + onSelectionModelChange={setSelectionModel} + disableRowSelectionOnClick={false} + autoHeight={false} + loading={loading} + slots={{ + toolbar: GridToolbar, + loadingOverlay: LinearProgress, + }} + sx={{ + flex: 1, + minHeight: 300, + "& .MuiDataGrid-cell:focus": { + outline: "none", + }, + }} + /> + )} + + + ); +} + +export default DocumentTable; \ No newline at end of file diff --git a/DashAI/front/src/components/experiments/EditModelDialog.jsx b/DashAI/front/src/components/experiments/EditModelDialog.jsx index 19868e857..a86984323 100644 --- a/DashAI/front/src/components/experiments/EditModelDialog.jsx +++ b/DashAI/front/src/components/experiments/EditModelDialog.jsx @@ -36,12 +36,12 @@ function EditModelDialog({ }} > { updateParameters(values); setOpen(false); }} - modelToConfigure={modelToConfigure} - initialValues={paramsInitialValues} onCancel={() => setOpen(false)} /> diff --git a/DashAI/front/src/components/generative/MainGenerativeBox.jsx b/DashAI/front/src/components/generative/MainGenerativeBox.jsx index 239c03cf2..6f69b9967 100644 --- a/DashAI/front/src/components/generative/MainGenerativeBox.jsx +++ b/DashAI/front/src/components/generative/MainGenerativeBox.jsx @@ -7,8 +7,8 @@ export default function MainGenerativeBox({ children }) { width={"100%"} height={"100%"} sx={{ - border: "0.2px solid", - borderColor: "grey.600", // o el color que prefieras + //border: "0.2px solid", + //borderColor: "grey.600", // o el color que prefieras }} borderRadius={2} //bgcolor={"background.box"} diff --git a/DashAI/front/src/components/generative/ParamsBar.jsx b/DashAI/front/src/components/generative/ParamsBar.jsx index 4d4870b01..5c25f3aeb 100644 --- a/DashAI/front/src/components/generative/ParamsBar.jsx +++ b/DashAI/front/src/components/generative/ParamsBar.jsx @@ -40,7 +40,7 @@ export default function ParamsBar({ getGenerativeSession(selectedSessionId) .then((session) => { setParameters(session.parameters); - + console.log("Session task name:", session.task_name); getRelatedComponents(session.task_name).then((relatedComponents) => { const relatedModel = relatedComponents.find( (component) => component.name === session.model_name, diff --git a/DashAI/front/src/components/generative/RAG/ComponentSelector.jsx b/DashAI/front/src/components/generative/RAG/ComponentSelector.jsx new file mode 100644 index 000000000..457a05798 --- /dev/null +++ b/DashAI/front/src/components/generative/RAG/ComponentSelector.jsx @@ -0,0 +1,178 @@ +import React, { useState, useEffect } from "react"; +import PropTypes from "prop-types"; +import { + Box, + Typography, + Autocomplete, + TextField, + CircularProgress +} from "@mui/material"; +import FormSchemaRenderFields from "../../shared/FormSchemaRenderFields"; +import { useFormik } from "formik"; +import { preprocessSchema, buildYupSchema } from "../utils"; +import { getRelatedComponents } from "../../../api/generativeTask"; +function ComponentSelector({ + componentType, + fetchComponents, + initialValues, + onConfigurationChange, + setNextEnabled +}) { + const [components, setComponents] = useState([]); + const [selectedComponent, setSelectedComponent] = useState(null); + const [loading, setLoading] = useState(true); + const [validationSchema, setValidationSchema] = useState(null); + + try { + console.log(getRelatedComponents("TextToTextGenerationTask")); + } catch (error) { + } + + + + // Fetch available components + useEffect(() => { + const getComponents = async () => { + setLoading(true); + try { + const data = await fetchComponents(); + setComponents(data); + + // If we have initialValues with a model_name, select that component + if (initialValues?.model_name) { + const preselectedComponent = data.find(c => c.name === initialValues.model_name); + if (preselectedComponent) { + setSelectedComponent(preselectedComponent); + } + } else { + console.warn(`No initial model_name provided for ${componentType} selection.`); + } + } catch (error) { + console.error(`Error fetching ${componentType} components:`, error); + } finally { + setLoading(false); + } + }; + + getComponents(); + }, [componentType, fetchComponents]); + + // Set up form validation schema when component changes + useEffect(() => { + if (selectedComponent?.schema?.properties) { + const processedProps = preprocessSchema(selectedComponent.schema.properties); + setValidationSchema(buildYupSchema(processedProps)); + console.log("Processed properties for form:", processedProps); + // Merge any existing values with defaults from schema + const schemaDefaults = Object.keys(processedProps).reduce( + (acc, key) => { + acc[key] = processedProps[key].placeholder || ""; + console.log(`Setting default for ${key}:`, acc[key]); + return acc; + }, + { name: "", description: ""}); + + // Preserve any values that were already set + const mergedValues = { + ...schemaDefaults, + ...(initialValues?.parameters || {}) + }; + + formik.setValues(mergedValues); + } + }, [selectedComponent]); + + const formik = useFormik({ + initialValues: initialValues?.parameters || {}, + validationSchema, + enableReinitialize: true, + onSubmit: (values) => { + onConfigurationChange({ + model_name: selectedComponent.name, + parameters: values + }); + } + }); + + // Enable/disable next button based on form validity and selection + useEffect(() => { + if (selectedComponent && formik.isValid) { + setNextEnabled(true); + + // Auto-submit valid values as they change + if (formik.dirty) { + onConfigurationChange({ + model_name: selectedComponent.name, + parameters: formik.values + }); + } + } else { + setNextEnabled(false); + } + }, [selectedComponent, formik.values, formik.isValid, formik.dirty]); + + // Process schema properties for the form renderer + const processedProperties = selectedComponent?.schema?.properties + ? preprocessSchema(selectedComponent.schema.properties) + : {}; + + return ( + + + Select {componentType} + + + {loading ? ( + + + + ) : ( + <> + c.name)} + value={selectedComponent?.name || null} + onChange={(_, newValue) => { + const selected = components.find(c => c.name === newValue); + setSelectedComponent(selected); + }} + renderInput={(params) => ( + + )} + sx={{ mb: 4 }} + /> + + {selectedComponent && ( +
+ + {selectedComponent.name} Configuration + + + { + formik.setValues({...formik.values, ...updatedValues}); + }} + onFormSubmit={formik.handleSubmit} + setError={(error) => console.error(error)} + errorsMessage={formik.errors} + /> + + )} + + )} +
+ ); +} + +ComponentSelector.propTypes = { + componentType: PropTypes.string.isRequired, + fetchComponents: PropTypes.func.isRequired, + initialValues: PropTypes.object, + onConfigurationChange: PropTypes.func.isRequired, + setNextEnabled: PropTypes.func.isRequired +}; + +export default ComponentSelector; \ No newline at end of file diff --git a/DashAI/front/src/components/generative/RAG/DocumentDropzone.jsx b/DashAI/front/src/components/generative/RAG/DocumentDropzone.jsx new file mode 100644 index 000000000..01eeb326d --- /dev/null +++ b/DashAI/front/src/components/generative/RAG/DocumentDropzone.jsx @@ -0,0 +1,45 @@ +import { Box, Typography, Paper } from "@mui/material"; +import { useCallback } from "react"; +import { useDropzone } from "react-dropzone"; +import Upload from "../../shared/Upload"; +let idCounter = 200; + +export default function DocumentDropzone({ onAddDocument }) { + const onDrop = useCallback((acceptedFiles) => { + acceptedFiles.forEach((file) => { + const newDoc = { + id: idCounter++, + name: file.name, + updatedAt: new Date().toLocaleDateString(), + }; + onAddDocument(newDoc); + }); + }, [onAddDocument]); + + const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop }); + + return ( + + + + Drag & drop documents here, or click to upload + + + ); +} diff --git a/DashAI/front/src/components/generative/RAG/DocumentSelector.jsx b/DashAI/front/src/components/generative/RAG/DocumentSelector.jsx new file mode 100644 index 000000000..944cad664 --- /dev/null +++ b/DashAI/front/src/components/generative/RAG/DocumentSelector.jsx @@ -0,0 +1,106 @@ +import { Box } from "@mui/material"; +import { useEffect, useState } from "react"; +import DocumentTable from "./DocumentTable"; +import Upload from "../../shared/Upload"; + +export default function DocumentSelector({ + selected = [], // Provide default empty array to prevent map errors + onSelect +}) { + const [documents, setDocuments] = useState([]); + const [selectedIds, setSelectedIds] = useState( + (selected || []).map(doc => doc.id) + ); + // Add a key state to force Upload component re-render + const [uploadKey, setUploadKey] = useState(0); + + // Fetch documents on mount + useEffect(() => { + // Simulated API + const fetchDocuments = async () => { + // Return mock data if needed + return [ + { id: "doc1", name: "Document 1", updatedAt: new Date().toISOString() }, + { id: "doc2", name: "Document 2", updatedAt: new Date().toISOString() } + ]; + }; + + fetchDocuments().then(setDocuments); + }, []); + + // Sync selected documents with parent + useEffect(() => { + const selectedDocs = documents.filter(doc => selectedIds.includes(doc.id)); + if (onSelect) { + onSelect(selectedDocs); + } + }, [selectedIds, documents, onSelect]); + + const handleToggleSelection = (id) => { + setSelectedIds(prev => + prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id] + ); + }; + + const handleSelectAll = () => { + setSelectedIds(documents.map(doc => doc.id)); + }; + + const handleDeselectAll = () => { + setSelectedIds([]); + }; + + const handleAddDocument = (newDoc) => { + const newDocWithId = { + ...newDoc, + id: `doc-${Date.now()}`, + updatedAt: new Date().toISOString() + }; + + setDocuments(prev => [newDocWithId, ...prev]); + setSelectedIds(prev => [...prev, newDocWithId.id]); + }; + + const handleRemove = (id) => { + setDocuments(prev => prev.filter(doc => doc.id !== id)); + setSelectedIds(prev => prev.filter(x => x !== id)); + }; + + const handleFileUpload = (file, url) => { + if (!file) return; + + const newDoc = { + id: `doc-${Date.now()}`, + name: file.name, + updatedAt: new Date().toISOString(), + preview: url + }; + + handleAddDocument(newDoc); + + // Reset the upload component by incrementing its key + setUploadKey(prev => prev + 1); + }; + + return ( + + + + + + + + + + ); +} \ No newline at end of file diff --git a/DashAI/front/src/components/generative/RAG/DocumentTable.jsx b/DashAI/front/src/components/generative/RAG/DocumentTable.jsx new file mode 100644 index 000000000..94293a4a7 --- /dev/null +++ b/DashAI/front/src/components/generative/RAG/DocumentTable.jsx @@ -0,0 +1,101 @@ +import { + Box, + Table, + TableBody, + TableCell, + TableHead, + TableRow, + Checkbox, + Typography, + IconButton, + Tooltip, + Button, +} from "@mui/material"; +import VisibilityIcon from "@mui/icons-material/Visibility"; +import DeleteIcon from "@mui/icons-material/Delete"; +import { Margin } from "@mui/icons-material"; + +export default function DocumentTable({ + documents, + selectedIds, + onToggle, + onSelectAll, + onDeselectAll, + onRemove, +}) { + + return ( + + {documents.length === 0 ? ( + + No documents available. + + ) : ( + <> + + + + + Name + Updated + Actions + + + + {documents.map((doc) => ( + + + onToggle(doc.id)} + /> + + {doc.name} + {doc.updatedAt} + + + + + + + + + onRemove(doc.id)}> + + + + + + + ))} + +
+ + + + + + )} +
+ ); +} diff --git a/DashAI/front/src/components/generative/RAG/SessionMetadata.jsx b/DashAI/front/src/components/generative/RAG/SessionMetadata.jsx new file mode 100644 index 000000000..b543d748a --- /dev/null +++ b/DashAI/front/src/components/generative/RAG/SessionMetadata.jsx @@ -0,0 +1,82 @@ +import React, { useEffect } from "react"; +import PropTypes from "prop-types"; +import { Box, TextField, Typography } from "@mui/material"; +import { useFormik } from "formik"; +import * as yup from "yup"; + +const validationSchema = yup.object({ + name: yup.string().required("Session name is required"), + description: yup.string() +}); + +function SessionMetadata({ + sessionData, + onUpdate, + setNextEnabled +}) { + const formik = useFormik({ + initialValues: { + name: sessionData.name || "", + description: sessionData.description || "" + }, + validationSchema, + onSubmit: (values) => { + onUpdate(values); + } + }); + + useEffect(() => { + // Enable next button if form is valid + setNextEnabled(formik.isValid); + + // Auto-update parent component when values change + if (formik.isValid) { + onUpdate({ + name: formik.values.name, + description: formik.values.description + }); + } + }, [formik.values, formik.isValid]); + + return ( + + + Session Information + + + + + + + ); +} + +SessionMetadata.propTypes = { + sessionData: PropTypes.object.isRequired, + onUpdate: PropTypes.func.isRequired, + setNextEnabled: PropTypes.func.isRequired +}; + +export default SessionMetadata; \ No newline at end of file diff --git a/DashAI/front/src/components/generative/SelectModelMenu.jsx b/DashAI/front/src/components/generative/SelectModelMenu.jsx index cd855bc26..aa15b71e6 100644 --- a/DashAI/front/src/components/generative/SelectModelMenu.jsx +++ b/DashAI/front/src/components/generative/SelectModelMenu.jsx @@ -24,7 +24,7 @@ export default function SelectModelMenu({ useEffect(() => { if (!selectedTaskName) return; - + console.log("Fetching related components for task:", selectedTaskName); getRelatedComponents(selectedTaskName).then(setRelatedComponents); }, [selectedTaskName]); diff --git a/DashAI/front/src/components/shared/FormSchemaRenderFields.jsx b/DashAI/front/src/components/shared/FormSchemaRenderFields.jsx index 70bfaf4a6..ce55f9b59 100644 --- a/DashAI/front/src/components/shared/FormSchemaRenderFields.jsx +++ b/DashAI/front/src/components/shared/FormSchemaRenderFields.jsx @@ -19,6 +19,8 @@ function FormSchemaRenderFields({ }) { if (!modelSchema) return null; + console.debug("Rendering FormSchemaRenderFields with modelSchema:", modelSchema); + const renderFields = useCallback(() => { const fields = []; diff --git a/DashAI/front/src/components/datasets/Upload.jsx b/DashAI/front/src/components/shared/Upload.jsx similarity index 94% rename from DashAI/front/src/components/datasets/Upload.jsx rename to DashAI/front/src/components/shared/Upload.jsx index 011cf7e56..60e887978 100644 --- a/DashAI/front/src/components/datasets/Upload.jsx +++ b/DashAI/front/src/components/shared/Upload.jsx @@ -20,7 +20,7 @@ import ClearIcon from "@mui/icons-material/Clear"; * newDataset state in the modal * @param {function} onFileUpload function to handle when the user "uploads" a dataset */ -function Upload({ onFileUpload }) { +function Upload({ onFileUpload, emptyUploadText }) { const [EMPTY, LOADING, LOADED] = [0, 1, 2]; const [datasetState, setDatasetState] = useState(EMPTY); const [dragActive, setDragActive] = useState(false); @@ -129,14 +129,10 @@ function Upload({ onFileUpload }) { {/* state text */} - {datasetState === EMPTY && "Upload your dataset"} {datasetState === LOADING && "Loading..."} {datasetState === LOADED && "Loaded"} - {datasetState === EMPTY && ( - - If your dataset have splits, upload it as a zip file - - )} + {/* {datasetState === EMPTY && "Upload your dataset"} */} + {datasetState === EMPTY &&emptyUploadText} @@ -190,6 +186,10 @@ function Upload({ onFileUpload }) { Upload.propTypes = { onFileUpload: PropTypes.func.isRequired, + emptyUploadText: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.node, + ]) }; export default Upload; diff --git a/DashAI/front/src/pages/generative/Generative.jsx b/DashAI/front/src/pages/generative/Generative.jsx index 079b0329c..8568d46a1 100644 --- a/DashAI/front/src/pages/generative/Generative.jsx +++ b/DashAI/front/src/pages/generative/Generative.jsx @@ -1,4 +1,4 @@ -import { Box } from "@mui/material"; +import { Box, Typography } from "@mui/material"; import { useState, useEffect } from "react"; import SessionBar from "../../components/generative/SessionBar"; import MainGenerativeBox from "../../components/generative/MainGenerativeBox"; @@ -6,6 +6,9 @@ import SelectTaskMenu from "../../components/generative/SelectTaskMenu"; import GenerativeChat from "../../components/generative/GenerativeChat"; import SelectModelMenu from "../../components/generative/SelectModelMenu"; import ParamsBar from "../../components/generative/ParamsBar"; + +import RAGHomePage from "./RAG/RAGHomePage"; + import { getSessions, removeSession } from "../../api/session"; export default function Generative() { @@ -15,39 +18,48 @@ export default function Generative() { const [sessions, setSessions] = useState([]); const [paramsVersion, setParamsVersion] = useState(0); + const isRAGTask = () => selectedTaskName === "RAGTask"; + const handleSessionClick = (sessionId, taskName) => { + console.log("[handleSessionClick]", { sessionId, taskName }); setSelectedTaskName(taskName); setSelectedSessionId(sessionId); }; const handleNewSessionButton = () => { + console.log("[handleNewSessionButton]"); setSelectedSessionId(null); setStepIndex(0); setSelectedTaskName(""); }; const onParamsUpdate = (newParams) => { + console.log("[onParamsUpdate]", newParams); setParamsVersion((prev) => prev + 1); }; useEffect(() => { getSessions().then((data) => { + console.log("[getSessions]", data); setSessions(data); }); }, []); const handleAddSession = (session) => { + console.log("[handleAddSession]", session); setSessions((prevSessions) => [session, ...prevSessions]); }; const handleSessionDelete = (id) => { + console.log("[handleSessionDelete]", id); if (id === selectedSessionId) { setSelectedSessionId(null); setStepIndex(0); + setSelectedTaskName(""); } setSessions((prevSessions) => - prevSessions.filter((session) => session.id !== id), + prevSessions.filter((session) => session.id !== id) ); removeSession(id); @@ -65,45 +77,67 @@ export default function Generative() { stepIndex={stepIndex} /> + {selectedSessionId ? ( - - ) : stepIndex === 0 ? ( - { - setSelectedTaskName(taskName); - setStepIndex(1); - }} - /> - ) : ( - - )} + isRAGTask() ? ( + + ) : ( + + ) + ) : stepIndex === 0 ? ( + { + console.log("[SelectTaskMenu] task selected:", taskName); + setSelectedTaskName(taskName); + setStepIndex(1); + }} + /> + ) : isRAGTask() ? ( + + ) : ( + + ) + } + + {!isRAGTask() && ( - {selectedSessionId ? ( - - ) : null} + {!selectedSessionId ? + ( + + ): null} + ) + } ); } diff --git a/DashAI/front/src/pages/generative/RAG/AlgorithmConfigurationStep.jsx b/DashAI/front/src/pages/generative/RAG/AlgorithmConfigurationStep.jsx new file mode 100644 index 000000000..90465957b --- /dev/null +++ b/DashAI/front/src/pages/generative/RAG/AlgorithmConfigurationStep.jsx @@ -0,0 +1,41 @@ +import React from "react"; +import PropTypes from "prop-types"; +import { Box } from "@mui/material"; +import ComponentSelector from "../../../components/generative/RAG/ComponentSelector"; +import { getGeneratorComponents } from "../../../api/rag"; + +function AlgorithmConfigurationStep({ + newSession, + setNewSession, + setNextEnabled +}) { + const handleConfigurationChange = (generatorConfig) => { + setNewSession(prev => ({ + ...prev, + RAGParameters: { + ...prev.RAGParameters, + generation: generatorConfig + } + })); + }; + + return ( + + + + ); +} + +AlgorithmConfigurationStep.propTypes = { + newSession: PropTypes.object.isRequired, + setNewSession: PropTypes.func.isRequired, + setNextEnabled: PropTypes.func.isRequired, +}; + +export default AlgorithmConfigurationStep; \ No newline at end of file diff --git a/DashAI/front/src/pages/generative/RAG/DocumentSelectionStep.jsx b/DashAI/front/src/pages/generative/RAG/DocumentSelectionStep.jsx new file mode 100644 index 000000000..4b7321461 --- /dev/null +++ b/DashAI/front/src/pages/generative/RAG/DocumentSelectionStep.jsx @@ -0,0 +1,94 @@ +import React, { useState, useEffect } from "react"; +import PropTypes from "prop-types"; +import { Box, CircularProgress } from "@mui/material"; +import DocumentSelector from "../../../components/generative/RAG/DocumentSelector"; +import SessionMetadata from "../../../components/generative/RAG/SessionMetadata"; + +function DocumentSelectionStep({ newSession, setNewSession, setNextEnabled }) { + const [documents, setDocuments] = useState([]); + const [loading, setLoading] = useState(true); + + // Fetch available documents on component mount + useEffect(() => { + const fetchDocuments = async () => { + setLoading(true); + try { + // Replace this with your actual API call to get documents + // For now using a mock response with delay + await new Promise(resolve => setTimeout(resolve, 500)); + const data = [ + { id: 1, name: "Product Documentation.pdf", type: "PDF", size: "1.2 MB", updatedAt: "2025-05-15" }, + { id: 2, name: "User Manual.docx", type: "DOCX", size: "3.4 MB", updatedAt: "2025-05-20" }, + { id: 3, name: "API Reference.pdf", type: "PDF", size: "2.1 MB", updatedAt: "2025-06-01" }, + { id: 4, name: "Technical Specifications.txt", type: "TXT", size: "4.7 MB", updatedAt: "2025-06-10" }, + { id: 5, name: "Troubleshooting Guide.pdf", type: "PDF", size: "1.8 MB", updatedAt: "2025-06-15" } + ]; + setDocuments(data); + } catch (error) { + console.error("Failed to fetch documents:", error); + } finally { + setLoading(false); + } + }; + + fetchDocuments(); + }, []); + + // Update next button state whenever documents or session name changes + useEffect(() => { + const hasDocuments = newSession.documents && newSession.documents.length > 0; + const hasName = Boolean(newSession.name); + setNextEnabled(hasDocuments && hasName); + }, [newSession.documents, newSession.name, setNextEnabled]); + + const handleSessionMetadataUpdate = (metadata) => { + setNewSession(prev => ({ + ...prev, + name: metadata.name, + description: metadata.description + })); + }; + + const handleDocumentsSelect = (selectedDocuments) => { + setNewSession(prev => ({ + ...prev, + documents: selectedDocuments + })); + }; + + return ( + + + + {loading ? ( + + + + ) : ( + + )} + + ); +} + +DocumentSelectionStep.propTypes = { + newSession: PropTypes.object.isRequired, + setNewSession: PropTypes.func.isRequired, + setNextEnabled: PropTypes.func.isRequired, +}; + +export default DocumentSelectionStep; \ No newline at end of file diff --git a/DashAI/front/src/pages/generative/RAG/ModelConfigurationStep.jsx b/DashAI/front/src/pages/generative/RAG/ModelConfigurationStep.jsx new file mode 100644 index 000000000..14d3d9367 --- /dev/null +++ b/DashAI/front/src/pages/generative/RAG/ModelConfigurationStep.jsx @@ -0,0 +1,50 @@ +import React, { useState, useEffect } from "react"; +import PropTypes from "prop-types"; +import { Box } from "@mui/material"; +import FormSchemaWithSelectedModel from "../../../components/shared/FormSchemaWithSelectedModel"; + +function ModelConfigurationStep({ + taskName, + initialParameters = {}, + onConfigurationChange, + setNextEnabled +}) { + const [parameters, setParameters] = useState(initialParameters); + const [isConfigured, setIsConfigured] = useState(false); + + useEffect(() => { + if (Object.keys(parameters).length > 0) { + onConfigurationChange(parameters); + setIsConfigured(true); + } + }, [parameters, onConfigurationChange]); + + useEffect(() => { + setNextEnabled(isConfigured); + }, [isConfigured, setNextEnabled]); + + const handleFormSubmit = (values) => { + setParameters(values); + setIsConfigured(true); + }; + + return ( + + {}} + /> + + ); +} + +ModelConfigurationStep.propTypes = { + taskName: PropTypes.string.isRequired, + initialParameters: PropTypes.object, + onConfigurationChange: PropTypes.func.isRequired, + setNextEnabled: PropTypes.func.isRequired, +}; + +export default ModelConfigurationStep; \ No newline at end of file diff --git a/DashAI/front/src/pages/generative/RAG/NewSessionModal.jsx b/DashAI/front/src/pages/generative/RAG/NewSessionModal.jsx new file mode 100644 index 000000000..8537b3fbf --- /dev/null +++ b/DashAI/front/src/pages/generative/RAG/NewSessionModal.jsx @@ -0,0 +1,252 @@ +import React, { useState, useEffect } from "react"; +import { + Button, + ButtonGroup, + Dialog, + DialogActions, + DialogTitle, + Grid, + IconButton, + Step, + StepButton, + DialogContent, + Stepper, + Typography, +} from "@mui/material"; +import CloseIcon from "@mui/icons-material/Close"; +import { useTheme } from "@mui/material/styles"; +import useMediaQuery from "@mui/material/useMediaQuery"; +import { useSnackbar } from "notistack"; + +import DocumentSelectionStep from "./DocumentSelectionStep"; +import RetrieverConfigurationStep from "./RetrieverConfigurationStep"; +import AlgorithmConfigurationStep from "./AlgorithmConfigurationStep"; +import { createRAGSession, updateRAGSession } from "../../../api/rag"; + +const steps = [ + { + name: "select-documents", + label: "Select documents", + Component: DocumentSelectionStep, + }, + { + name: "configure-retriever", + label: "Configure retriever", + Component: RetrieverConfigurationStep, + }, + { + name: "configure-algorithm", + label: "Configure algorithm", + Component: AlgorithmConfigurationStep, + }, +]; + +const defaultNewSession = { + name: "", + task_name: "RAGTask", // Default task name + description: "", + RAGParameters: {}, + documents: [], +}; + +export default function NewSessionModal({ + open, + setOpen, + setUpdateTableFlag, + setSelectedSessionId, + handleAddSession, + selectedSession, +}) { + const theme = useTheme(); + const matches = useMediaQuery(theme.breakpoints.down("md")); + const screenSm = useMediaQuery(theme.breakpoints.down("sm")); + const { enqueueSnackbar } = useSnackbar(); + + const [activeStep, setActiveStep] = useState(0); + const [nextEnabled, setNextEnabled] = useState(false); + const [newSession, setNewSession] = useState( + selectedSession || defaultNewSession + ); + + const [stepCompleted, setStepCompleted] = useState([false, false, false]); + + const handleStepComplete = (stepIndex) => { + const newCompleted = [...stepCompleted]; + newCompleted[stepIndex] = true; + setStepCompleted(newCompleted); + }; + + // Initialize session data when modal opens or selectedSession changes + useEffect(() => { + if (open) { + if (selectedSession) { + // Edit mode - use existing session + setNewSession({ + ...selectedSession, + // Ensure documents array exists + documents: selectedSession.documents || [] + }); + } else { + // Create mode - use defaults + setNewSession(defaultNewSession); + } + setActiveStep(0); + setNextEnabled(false); + } + }, [open, selectedSession]); + + + const uploadNewSession = async () => { + try { + // For new sessions, exclude ID + const sessionData = selectedSession + ? newSession // Keep existing ID for updates + : { ...newSession, id: undefined }; // Remove ID for new sessions + + const response = selectedSession + ? await updateRAGSession(sessionData) // Implement update function if needed + : await createRAGSession(sessionData); + + const sessionId = response.id; + console.log("Session created/updated with ID:", sessionId); + + enqueueSnackbar( + `Session ${selectedSession ? "updated" : "created"} successfully!`, + { variant: "success" } + ); + setUpdateTableFlag(true); // Trigger table update + } catch (error) { + console.error("Session creation error:", error); + enqueueSnackbar( + `Failed to ${selectedSession ? "update" : "create"} session: ${error.message}`, + { variant: "error" } + ); + } + }; + + const handleCloseDialog = () => { + setActiveStep(0); + setOpen(false); + setNewSession(defaultNewSession); + setNextEnabled(false); + + }; + + const handleStepButton = (index) => () => { + setActiveStep(index); + }; + + const handleBackButton = () => { + if (activeStep === 0) { + handleCloseDialog(); + } else { + setActiveStep(activeStep - 1); + setNextEnabled(true); + } + }; + + const handleNextButton = () => { + if (activeStep === steps.length - 1) { + handleFinish(); + } else { + setActiveStep(activeStep + 1); + setNextEnabled(false); // Reset next enabled for new step + } + }; + + const handleFinish = async () => { + await uploadNewSession(); + handleCloseDialog(); + }; + + return ( + + + + + + + + + + + + + {selectedSession ? "Edit" : "Create New"} RAG Session + + + + + + + {steps.map((step, index) => ( + index} + disabled={activeStep < index}> + + {step.label} + + + ))} + + + + + + + {activeStep === 0 && ( + + )} + {activeStep === 1 && ( + + )} + {activeStep === 2 && ( + + )} + + + + + + + + + + ); +} diff --git a/DashAI/front/src/pages/generative/RAG/RAGHomePage.jsx b/DashAI/front/src/pages/generative/RAG/RAGHomePage.jsx new file mode 100644 index 000000000..26107a1f6 --- /dev/null +++ b/DashAI/front/src/pages/generative/RAG/RAGHomePage.jsx @@ -0,0 +1,55 @@ +import React from "react"; + +import NewSessionModal from "./NewSessionModal"; +import RAGSessionsTable from "./RAGSessionsTable.jsx"; + +import CustomLayout from "../../../components/custom/CustomLayout.jsx"; + +function RAGHomePage({ + handleAddSession, + selectedTaskName, + setSelectedSessionId + }) { + const [showNewSessionModal, setShowNewSessionModal] = React.useState(false); + const [updateTableFlag, setUpdateTableFlag] = React.useState(false); + const [selectedSession, setSelectedSession] = React.useState(null); + + const handleOpenNewSessionModal = () => { + setSelectedSession(null); + setShowNewSessionModal(true); + } + + const handleSessionSelect = (session) => { + setSelectedSession(session); + setShowNewSessionModal(true); + setSelectedSessionId(session.id); + } + + return ( + + {showNewSessionModal? ( + + ):( + + ) + } + + ); +} + +export default RAGHomePage; \ No newline at end of file diff --git a/DashAI/front/src/pages/generative/RAG/RAGSessionsTable.jsx b/DashAI/front/src/pages/generative/RAG/RAGSessionsTable.jsx new file mode 100644 index 000000000..560ae5f28 --- /dev/null +++ b/DashAI/front/src/pages/generative/RAG/RAGSessionsTable.jsx @@ -0,0 +1,175 @@ + +import React from "react"; +import PropTypes from "prop-types"; + +import { + AddCircleOutline as AddIcon, + Update as UpdateIcon, +} from "@mui/icons-material"; +import { DataGrid, GridToolbar } from "@mui/x-data-grid"; +import { Button, Grid, Paper, Typography, LinearProgress } from "@mui/material"; +import { useSnackbar } from "notistack"; + +import { getRAGSessions, deleteRAGSession } from "../../../api/rag"; // Adjust the import path as necessary + +function RAGSessionsTable({ + handleOpenNewSessionModal, + onSessionSelect, + updateTableFlag, + setUpdateTableFlag, +}) { + console.log("RAGSessionsTable rendered"); + const [loading, setLoading] = React.useState(true); + const [sessions, setSessions] = React.useState([]); + const { enqueueSnackbar } = useSnackbar(); + + const getSessions = async () => { + setLoading(true); + try { + const data = await getRAGSessions(); + setSessions(data); + } catch (error) { + console.error("[getSessions] error:", error); + enqueueSnackbar("Error fetching RAG sessions", { variant: "error" }); + } finally { + setLoading(false); + } + }; + + const handleDeleteSession = async (sessionId) => { + try { + await deleteRAGSession(sessionId); + enqueueSnackbar("RAG session successfully deleted.", { + variant: "success" + }); + getSessions(); // Refresh sessions after deletion + } catch (error) { + console.error("[deleteSession] error:", error); + enqueueSnackbar("Error deleting RAG session", { variant: "error" }); + } + }; + + const handleOpenSession = (session) => { + if (onSessionSelect) { + onSessionSelect(session); + } + }; + + const handleViewDocuments = (session) => { + console.log("View documents for session:", session.id); + }; + + // FIXED: Moved useEffect to top level + React.useEffect(() => { + console.log("Initial load effect"); + getSessions(); + }, []); + + // FIXED: Added updateTableFlag effect + React.useEffect(() => { + if (updateTableFlag) { + console.log("Update table flag triggered"); + getSessions(); + setUpdateTableFlag(false); + } + }, [updateTableFlag, setUpdateTableFlag]); + + // FIXED: Correct DataGrid column structure + const columns = [ + { + field: "name", + headerName: "Session Name", + flex: 1 + }, + { + field: "created_at", + headerName: "Created At", + flex: 1, + valueFormatter: (params) => new Date(params.value).toLocaleString() + }, + { + field: "documents", + headerName: "Documents", + flex: 0.7, + valueGetter: (params) => params.row.documents?.length || 0 + }, + { + field: "actions", + headerName: "Actions", + flex: 1.5, + renderCell: (params) => ( +
+ + + +
+ ) + } + ]; + + return ( + + + + RAG Sessions + + + + + row.id} + sx={{ + '& .MuiDataGrid-cell:focus': { outline: 'none' }, + minHeight: 400 + }} + /> + + ); +} + +// FIXED: Correct propTypes +RAGSessionsTable.propTypes = { + handleOpenNewSessionModal: PropTypes.func.isRequired, + onSessionSelect: PropTypes.func, + updateTableFlag: PropTypes.bool.isRequired, + setUpdateTableFlag: PropTypes.func.isRequired +}; + +export default RAGSessionsTable; \ No newline at end of file diff --git a/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx b/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx new file mode 100644 index 000000000..b1d29f529 --- /dev/null +++ b/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx @@ -0,0 +1,38 @@ +// RetrieverConfigurationStep.jsx +import React from "react"; +import PropTypes from "prop-types"; +import { Box } from "@mui/material"; +import ComponentSelector from "../../../components/generative/RAG/ComponentSelector"; +import { getRetrieverComponents } from "../../../api/rag"; + +function RetrieverConfigurationStep({ newSession, setNewSession, setNextEnabled }) { + const handleConfigurationChange = (retrieverConfig) => { + setNewSession(prev => ({ + ...prev, + RAGParameters: { + ...prev.RAGParameters, + retrieval: retrieverConfig + } + })); + }; + + return ( + + + + ); +} + +RetrieverConfigurationStep.propTypes = { + newSession: PropTypes.object.isRequired, + setNewSession: PropTypes.func.isRequired, + setNextEnabled: PropTypes.func.isRequired, +}; + +export default RetrieverConfigurationStep; \ No newline at end of file diff --git a/DashAI/front/yarn.lock b/DashAI/front/yarn.lock index 85e83bbc3..73d4a3513 100644 --- a/DashAI/front/yarn.lock +++ b/DashAI/front/yarn.lock @@ -5334,9 +5334,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001587, caniuse-lite@npm:^1.0.30001599": - version: 1.0.30001618 - resolution: "caniuse-lite@npm:1.0.30001618" - checksum: 7a87a49f5b2432b4bd428d3c1b629c49699aa75390e29915745f6e1753c8f91d990ec468a0306ea2b6efd5e76435a127a7c535cb28b9d1bd268732057a5d64c1 + version: 1.0.30001724 + resolution: "caniuse-lite@npm:1.0.30001724" + checksum: 3285f9c56898ffd9f5fce8f6cff9deb832c5897da8046474f8961a5848771cac293b80200c6311c8a97822dd25b8af699af35042a2033d5ec54017fe4dc6c5e3 languageName: node linkType: hard diff --git a/requirements.txt b/requirements.txt index 58a905edf..f80c8d769 100644 --- a/requirements.txt +++ b/requirements.txt @@ -449,3 +449,5 @@ zipp==3.20.2 # importlib-metadata # importlib-resources imblearn +chromadb==0.5.5 +chroma-hnswlib==0.7.6 \ No newline at end of file From 5f197ac0771b335cda57da57423f9469db6af432 Mon Sep 17 00:00:00 2001 From: sofiachavezb Date: Thu, 3 Jul 2025 11:39:43 -0400 Subject: [PATCH 003/218] Basic configuration via UI TODO: Divide the Retriever component in single responsability configurable objects Allow the load of multiple documents the Document selector Store documents bytes in the DB Implement UI re-render after deleting a session in RAG sessions table Implement documents view in front Implement trained models (like retrievers) load and save --- .../back/api/api_v1/endpoints/components.py | 15 +- DashAI/back/initial_components.py | 9 +- .../back/models/RAG/Documents/BaseDocument.py | 102 ++ .../back/models/RAG/Documents/PDFDocument.py | 58 ++ .../back/models/RAG/Documents/TxtDocument.py | 54 + DashAI/back/models/RAG/Documents/__init__.py | 3 + DashAI/back/models/RAG/RAG_pipeline.py | 226 ++--- .../models/RAG/Retrievers/BaseRetriever.py | 165 +++ .../models/RAG/Retrievers/DenseRetriever.py | 12 + .../models/RAG/Retrievers/TFIDFRetriever.py | 259 +++++ DashAI/back/models/RAG/Retrievers/__init__.py | 3 + DashAI/back/models/RAG/__init__.py | 3 +- DashAI/back/models/__init__.py | 2 +- DashAI/back/models/hugging_face/__init__.py | 3 + .../models/text_to_text_generation_model.py | 2 +- DashAI/back/tasks/RAG_task.py | 4 +- DashAI/front/src/api/generativeTask.ts | 3 + DashAI/front/src/api/rag.ts | 490 ++------- .../generative/RAG/ComponentSelector.jsx | 185 ++-- .../generative/RAG/DocumentSelector.jsx | 111 +- .../generative/RAG/DocumentTable.jsx | 64 +- .../components/generative/SelectModelMenu.jsx | 1 - .../src/components/generative/SessionBar.jsx | 2 - .../front/src/components/generative/prompt.js | 954 ++++++++++++++++++ .../front/src/pages/generative/Generative.jsx | 25 +- .../generative/RAG/DocumentSelectionStep.jsx | 161 +-- .../RAG/GeneratorConfigurationStep.jsx | 171 ++++ .../pages/generative/RAG/NewSessionModal.jsx | 268 ++--- .../src/pages/generative/RAG/RAGHomePage.jsx | 141 ++- .../pages/generative/RAG/RAGSessionsTable.jsx | 310 +++--- .../RAG/RetrieverConfigurationStep.jsx | 191 +++- .../vectorizer | Bin 0 -> 422105 bytes .../vectorizer | Bin 0 -> 101559 bytes .../vectorizer | Bin 0 -> 179480 bytes .../vectorizer | Bin 0 -> 243480 bytes .../vectorizer | Bin 0 -> 378471 bytes .../vectorizer | Bin 0 -> 379501 bytes .../vectorizer | Bin 0 -> 258501 bytes .../vectorizer | Bin 0 -> 244262 bytes .../vectorizer | Bin 0 -> 225721 bytes .../vectorizer | Bin 0 -> 230851 bytes 41 files changed, 2823 insertions(+), 1174 deletions(-) create mode 100644 DashAI/back/models/RAG/Documents/BaseDocument.py create mode 100644 DashAI/back/models/RAG/Documents/PDFDocument.py create mode 100644 DashAI/back/models/RAG/Documents/TxtDocument.py create mode 100644 DashAI/back/models/RAG/Documents/__init__.py create mode 100644 DashAI/back/models/RAG/Retrievers/BaseRetriever.py create mode 100644 DashAI/back/models/RAG/Retrievers/DenseRetriever.py create mode 100644 DashAI/back/models/RAG/Retrievers/TFIDFRetriever.py create mode 100644 DashAI/back/models/RAG/Retrievers/__init__.py create mode 100644 DashAI/front/src/components/generative/prompt.js create mode 100644 DashAI/front/src/pages/generative/RAG/GeneratorConfigurationStep.jsx create mode 100644 StoredRetrievers/tfidf_retriever_07c008c27ce1de3ecd0d4cd42fc4c43604e6d7c2c4f86eef5d4b1b42d6d3c15d_75aeb1f071ec2f059f26544c40689c89c282d8dd1ab84b6674ffbf27e9e8fbd1/vectorizer create mode 100644 StoredRetrievers/tfidf_retriever_0cff2792f2880a97e8dc881b7f30588af3e40f2617f4a8e40f236e3ed70b3976_0ec09b17926fe5aa93641201da7dfeb580d37f3af6b2032f31b6343ac471fba3/vectorizer create mode 100644 StoredRetrievers/tfidf_retriever_28bce20bb2374f93157c85fa986ff3d0a6004b637324b92bf98c20efb3e56103_2730eac7385c920c51ee4089b4172f7af4d7be862b3b2aefa2d229aad399bea4/vectorizer create mode 100644 StoredRetrievers/tfidf_retriever_347f29ec72552a7656cf8f10a42670fcd8076c89ce86fece0c180555440bcbc2_c54a2f7e421d397dff3d0a420d9513c4f7b43399cf2c2770b610c951b7af9e38/vectorizer create mode 100644 StoredRetrievers/tfidf_retriever_88c363cbc175eb2b0bef48208782dfa84682a5b6dd6e45ac65127700520bc2ba_75aeb1f071ec2f059f26544c40689c89c282d8dd1ab84b6674ffbf27e9e8fbd1/vectorizer create mode 100644 StoredRetrievers/tfidf_retriever_978e040feee803d3cd97a7eaf5c3e9f502d0d97f670c303715e455047b877281_75aeb1f071ec2f059f26544c40689c89c282d8dd1ab84b6674ffbf27e9e8fbd1/vectorizer create mode 100644 StoredRetrievers/tfidf_retriever_a38d48165431be31206e34ce2758b75170414d8ad2e65d9fa37a38b2e41343fd_57d8f551775097b02aeb07b11856b3cd3f942fbcf36d43a4384b130551631efb/vectorizer create mode 100644 StoredRetrievers/tfidf_retriever_dfdc77de99969c1ac75e72e16a8c38ee3fb24e98a90075f4cd923472c317b05c_c27d55405ff4e4180350c51990a570d33540e0098056446ce95de0942b41e4da/vectorizer create mode 100644 StoredRetrievers/tfidf_retriever_e19a4b25c422aa7be44921f262f32d44d790b515e5af012fa3eaacb52a649869_c54a2f7e421d397dff3d0a420d9513c4f7b43399cf2c2770b610c951b7af9e38/vectorizer create mode 100644 StoredRetrievers/tfidf_retriever_ee0f3dd0eaad95cb49ab497e118300f86c49ab07807d73ced6d3c69372661f46_c54a2f7e421d397dff3d0a420d9513c4f7b43399cf2c2770b610c951b7af9e38/vectorizer diff --git a/DashAI/back/api/api_v1/endpoints/components.py b/DashAI/back/api/api_v1/endpoints/components.py index 7e4953078..ad5e85ceb 100644 --- a/DashAI/back/api/api_v1/endpoints/components.py +++ b/DashAI/back/api/api_v1/endpoints/components.py @@ -87,19 +87,14 @@ async def get_components( HTTPException If task_name does not exist in the registry """ - + flag = " ".join(str(param) for param in [select_types, ignore_types, related_component, component_parent, has_related_of_type]) + if "etriever" in flag or "RAG" in flag or "rag" in flag: + "stop here" print("select_types", str(select_types)) print("ignore_types", str(ignore_types)) print("related_component", str(related_component)) print("component_parent", str(component_parent)) print("has_related_of_type", str(has_related_of_type)) - print("component_registry", str(component_registry)) - - - print(list(component_registry._registry.keys())) - print(related_component in component_registry._registry) - print(component_registry) - print("get_components api ") # when select_type is not none, check if it exists in the registry. if select_types is not None: @@ -207,10 +202,12 @@ async def get_components( ) print("get_components api 10") - return [ + out = [ _delete_class(component_dict) for component_dict in selected_components.values() ] + return out + @router.get("/{id}/") @inject diff --git a/DashAI/back/initial_components.py b/DashAI/back/initial_components.py index 23d734df9..f66fba0c6 100644 --- a/DashAI/back/initial_components.py +++ b/DashAI/back/initial_components.py @@ -92,7 +92,11 @@ SimpleControlNetModel, StableDiffusionV2Model, StableDiffusionV3Model, - RAGPipeline + RAGPipeline, + BaseRetriever, + TFIDFRetriever, + DenseRetriever + ) from DashAI.back.optimizers import HyperOptOptimizer, OptunaOptimizer from DashAI.back.plugins.utils import get_available_plugins @@ -158,6 +162,9 @@ def get_initial_components(): LinearSVR, LinearRegression, RAGPipeline, + TFIDFRetriever, + DenseRetriever, + #BaseRetriever, # Dataloaders CSVDataLoader, JSONDataLoader, diff --git a/DashAI/back/models/RAG/Documents/BaseDocument.py b/DashAI/back/models/RAG/Documents/BaseDocument.py new file mode 100644 index 000000000..f54db39db --- /dev/null +++ b/DashAI/back/models/RAG/Documents/BaseDocument.py @@ -0,0 +1,102 @@ +from abc import ABC +import hashlib +from typing import Any, Dict, List, Optional + +class BaseDocument(ABC): + """ + Base class for documents. + """ + + def __init__(self, *args, **kwargs): + """ + Initialize the document. + """ + pass + + def get_text(self) -> str: + """ + Get the text content of the document. + + Returns: + str: The text content of the document. + """ + raise NotImplementedError("This method should be implemented by subclasses.") + + def get_text_length(self) -> int: + """ + Get the length of the text content of the document. + + Returns: + int: The length of the text content of the document. + """ + raise NotImplementedError("This method should be implemented by subclasses.") + + def get_metadata(self) -> Dict[str, Any]: + """ + Get the metadata of the document. + + Returns: + Dict[str, Any]: The metadata of the document. + """ + raise NotImplementedError("This method should be implemented by subclasses.") + + def get_filename(self) -> Optional[str]: + """ + Get the filename of the document. + + Returns: + Optional[str]: The filename of the document, or None if not applicable. + """ + raise NotImplementedError("This method should be implemented by subclasses.") + + def get_filetype(self) -> Optional[str]: + """ + Get the filetype of the document. + + Returns: + Optional[str]: The filetype of the document, or None if not applicable. + """ + raise NotImplementedError("This method should be implemented by subclasses.") + + def get_file_location(self) -> Optional[str]: + """ + Get the file location of the document. + + Returns: + Optional[str]: The file location of the document, or None if not applicable. + """ + raise NotImplementedError("This method should be implemented by subclasses.") + + def get_chunks(self, chunk_size: int, chunk_overlap: int) -> List[str]: + """ + Get the document text split into chunks. + + Args: + chunk_size (int): The size of each chunk. + chunk_overlap (int): The overlap between chunks. + + Returns: + List[str]: A list of text chunks. + """ + text = self.get_text() + chunks = [] + start = 0 + while start < len(text): + end = min(start + chunk_size, len(text)) + chunks.append(text[start:end]) + start += chunk_size - chunk_overlap + return chunks + + def get_hash(self) -> str: + """ + Get a hash of the document content. + + Returns: + str: A hash string representing the document content. + """ + text = self.get_text() + return hashlib.sha256(text.encode('utf-8')).hexdigest() if text else '' + + def __repr__(self): + return f"BaseDocument(filename='{self.get_filename()}', content='{self.get_text()[:50]}...', metadata={self.get_metadata()})" + diff --git a/DashAI/back/models/RAG/Documents/PDFDocument.py b/DashAI/back/models/RAG/Documents/PDFDocument.py new file mode 100644 index 000000000..ca2ecb059 --- /dev/null +++ b/DashAI/back/models/RAG/Documents/PDFDocument.py @@ -0,0 +1,58 @@ +from .BaseDocument import BaseDocument +import os +from PyPDF2 import PdfReader +import base64 + +class PDFDocument(BaseDocument): + """ + Class representing a PDF document. + """ + + def __init__(self, file_path: str): + """ + Initialize the PDF document with the file path. + + Args: + file_path (str): The path to the PDF file. + """ + + assert os.path.exists(file_path), f"File {file_path} does not exist." + + self.file_path = file_path + self.metadata = { + "file_path": file_path, + "filetype": "pdf", + "filename": os.path.basename(file_path), + } + self.file_path = file_path + self.filename = os.path.basename(file_path) + self.filetype = "pdf" + self.text_length = len(self.get_text()) + + def get_text(self) -> str: + reader = PdfReader(self.file_path) + if not reader.pages: + raise ValueError(f"The PDF file {self.file_path} is empty or not valid.") + + # Extract text from all pages + text = "" + for page in reader.pages: + text += page.extract_text() or "" + + return text.strip() + + def get_text_length(self) -> int: + return self.text_length + + def get_metadata(self) -> dict: + return self.metadata + + def get_filename(self) -> str: + return self.filename + + def get_filetype(self) -> str: + return self.filetype + + def get_file_location(self) -> str: + return self.file_path + \ No newline at end of file diff --git a/DashAI/back/models/RAG/Documents/TxtDocument.py b/DashAI/back/models/RAG/Documents/TxtDocument.py new file mode 100644 index 000000000..f8f7f58a7 --- /dev/null +++ b/DashAI/back/models/RAG/Documents/TxtDocument.py @@ -0,0 +1,54 @@ +from .BaseDocument import BaseDocument +from typing import Dict, Any, Optional +import os + +class TxtDocument(BaseDocument): + """ + Class representing a .txt document. + """ + + def __init__(self, file_path: str): + """ + Initialize the text document with the file path. + + Args: + file_path (str): The path to the text file. + """ + assert os.path.exists(file_path), f"File {file_path} does not exist." + + self.file_path = file_path + self.filename = os.path.basename(file_path) + self.filetype = "txt" + self.text_length = len(self.text) + self.metadata = { + "file_path": file_path, + "filetype": self.filetype, + "filename": self.filename, + } + self.text_length = len(self.get_text()) + + def get_text(self) -> str: + """ + Get the text content of the document. + + Returns: + str: The text content of the document. + """ + with open(self.file_path, "r", encoding="utf-8") as file: + text = file.read() + return text.strip() + + def get_text_length(self) -> int: + return self.text_length + + def get_metadata(self) -> Dict[str, Any]: + return self.metadata + + def get_filename(self) -> str: + return self.filename + + def get_filetype(self) -> str: + return self.filetype + + def get_file_location(self) -> str: + return self.file_path \ No newline at end of file diff --git a/DashAI/back/models/RAG/Documents/__init__.py b/DashAI/back/models/RAG/Documents/__init__.py new file mode 100644 index 000000000..06bb27b6f --- /dev/null +++ b/DashAI/back/models/RAG/Documents/__init__.py @@ -0,0 +1,3 @@ +from .BaseDocument import BaseDocument +from .PDFDocument import PDFDocument +from .TxtDocument import TxtDocument \ No newline at end of file diff --git a/DashAI/back/models/RAG/RAG_pipeline.py b/DashAI/back/models/RAG/RAG_pipeline.py index 9ed9338a3..dde12274e 100644 --- a/DashAI/back/models/RAG/RAG_pipeline.py +++ b/DashAI/back/models/RAG/RAG_pipeline.py @@ -1,115 +1,68 @@ -from typing import Any, Tuple, List - -from DashAI.back.models.base_generative_model import BaseGenerativeModel +from typing import Any, Tuple, List, Dict from DashAI.back.core.schema_fields import ( BaseSchema, - enum_field, - int_field, - float_field, + component_field, schema_field, + bool_field, + list_field, string_field ) -from DashAI.back.models.hugging_face.deep_seek_model import DeepSeekModel -from DashAI.back.models.hugging_face.qwen_model import QwenModel +from DashAI.back.models.base_generative_model import BaseGenerativeModel from DashAI.back.models.text_to_text_generation_model import TextToTextGenerationTaskModel -from DashAI.back.models.RAG.dummy_retriever import DummyRetriever +from DashAI.back.models.RAG.Retrievers import ( + TFIDFRetriever, + DenseRetriever, + BaseRetriever) + from DashAI.back.models.RAG.prompts import ( - BasePrompt, ContextMergePrompt, AugmentationPrompt ) -from typing import Dict + +from DashAI.back.models.hugging_face import ( + DeepSeekModel, + QwenModel, + GemmaModel) + +retriever_models = { + "TFIDFRetriever": TFIDFRetriever, + "DenseRetriever": DenseRetriever, +} + +generation_models = { + "DeepSeekModel": DeepSeekModel, + "QwenModel": QwenModel, + "GemmaModel": GemmaModel, +} class RAGPipelineSchema(BaseSchema): """Schema for RAG pipeline.""" + # Document collection parameters + documents: schema_field( + list_field( + string_field(), + min_items=1, + ), + placeholder=None, + description="List of documents to be used in the RAG pipeline." + ) # type: ignore # RAG algorithm parameters - RAG_algorithm: schema_field( - enum_field(["SINGLE_INTERACTION", "AUGMENTED_INTERACTION"]), - placeholder="SINGLE_INTERACTION", - description="RAG algorithm to use for document retrieval and text generation.", - ) # type: ignore - - - # Retriever parameters - documments_path: schema_field( - string_field(), - placeholder="Path to the folder with documents", - description="Path to the folder containing documents for retrieval.", - ) # type: ignore - - collection_name: schema_field( - string_field(), - placeholder="My documents collection name", - description="Name of the collection to use for document retrieval.", - ) # type: ignore - + retriever_model: schema_field( + component_field(parent="RetrieverModel"), + placeholder={"component": "TFIDFRetriever", "params": {}}, + description="Retriever component used in the RAG pipeline." + ) # type: ignore - distance_function: schema_field( - enum_field(["cosine", "L2", "inner"]), - placeholder="cosine", - description="Distance function to use for document retrieval.", - ) # type: ignore - - n_docs: schema_field( - int_field(ge=1), - placeholder=5, - description="Maximum number of documents to retrieve.", - ) # type: ignore - - max_distance: schema_field( - float_field(ge=0.0), - placeholder=1.0, - description="Maximum distance allowed for retrieved documents.", - ) # type: ignore - - chunk_size: schema_field( - int_field(ge=1), - placeholder=1000, - description="Size of the chunks to split the documents into.", - ) # type: ignore - - chunk_overlap: schema_field( - int_field(ge=0), - placeholder=200, - description="Overlap size between chunks.", - ) # type: ignore - - - # LLM parameters - model_name: schema_field( - enum_field(["DeepSeek", "Qwen2"]), - placeholder="DeepSeek", - description="LLM model to use for text generation.", - ) # type: ignore - - max_tokens: schema_field( - int_field(ge=1), - placeholder=800, - description="Maximum number of tokens to generate.", - ) # type: ignore - - temperature: schema_field( - float_field(ge=0.0, le=1.0), - placeholder=0.7, - description="Sampling temperature. Higher values make the output more random, while lower values make it more focused and deterministic.", - ) # type: ignore - - frequency_penalty: schema_field( - float_field(ge=0.0, le=2.0), - placeholder=0.1, - description="Penalty for repeated tokens in the output. Higher values reduce the likelihood of repetition, encouraging more diverse text generation.", - ) # type: ignore - - n_ctx: schema_field( - int_field(ge=1), - placeholder=4096, - description="Maximum number of tokens the model can process in a single forward pass (context window size).", + generation_model: schema_field( + component_field(parent="TextToTextGenerationTaskModel"), + placeholder={"component": "DeepSeek", "params": {}}, + description="Text generation model used in the RAG pipeline." ) # type: ignore -class RAGPipeline(TextToTextGenerationTaskModel): +class RAGPipeline(BaseGenerativeModel): """Retrieval-Augmented Generation (RAG) pipeline.""" COMPATIBLE_COMPONENTS = ["RAGTask"] @@ -126,50 +79,49 @@ def __init__( self, n_docs (int): The maximum number of documents to retrieve. max_distance (float): The maximum distance allowed for retrieved documents. """ - kwargs = self.validate_and_transform(kwargs) - print("Initializing RAG pipeline") - # Initialize the LLM model - llm_classes = { - "DeepSeek": DeepSeekModel, - "Qwen2": QwenModel, - } + try: + documents_paths = kwargs['documents'] + retriever_args = kwargs['retriever_model'] + generation_model_args = kwargs['generation_model'] + except KeyError as e: + raise ValueError(f"Missing required RAG pipeline parameter: {e}") + + try: + retriever_model_class = retriever_models[retriever_args["component"]] + retriever_params = retriever_args['params'] + except KeyError as e: + raise ValueError(f"Invalid retriever model specified: {e}") + + try: + generation_model_class = generation_models[generation_model_args["component"]] + generation_params = generation_model_args['params'] - llm_kwargs = { - "max_tokens": kwargs.get("max_tokens"), - "temperature": kwargs.get("temperature"), - "frequency_penalty": kwargs.get("frequency_penalty"), - "n_ctx": kwargs.get("n_ctx"), - } + except KeyError as e: + raise ValueError(f"Invalid generation model specified: {e}") + + assert isinstance(documents_paths, list) and len(documents_paths) > 0, "Documents must be a non-empty list." + for path in documents_paths: + assert isinstance(path, str), f"Each document path must be a string, got {type(path)}" print("Initializing LLM model") - self.llm_model: TextToTextGenerationTaskModel = llm_classes[kwargs.get("model_name")](**llm_kwargs) - - # Initialize the retriever - retriever_params = { - "documents_path": kwargs.get("documments_path"), - "collection_name": kwargs.get("collection_name"), - "distance_function": kwargs.get("distance_function"), - "n_docs": kwargs.get("n_docs"), - "max_distance": kwargs.get("max_distance"), - "chunk_size": kwargs.get("chunk_size"), - "chunk_overlap": kwargs.get("chunk_overlap"), + self.llm_model: TextToTextGenerationTaskModel = generation_model_class(**generation_params) + + + new_retriever_args = { + 'documents_paths': documents_paths, } + for key, value in retriever_params.items(): + new_retriever_args[key] = value + + print("Initializing retriever model") + self.retriever: BaseRetriever = retriever_model_class(**new_retriever_args) - print("Initializing retriever") - self.retriever = DummyRetriever(**retriever_params) - - print("Definining rag algorithm") - # Initialize the RAG algorithm - if kwargs.get("RAG_algorithm") == "SINGLE_INTERACTION": - self.retrieval_algorithm = self.single_interaction - elif kwargs.get("RAG_algorithm") == "AUGMENTED_INTERACTION": - self.retrieval_algorithm = self.augmented_interaction - else: - raise ValueError("Invalid RAG algorithm. Choose 'SINGLE_INTERACTION' or 'AUGMENTED_INTERACTION'.") + self.retrieval_algorithm = "SINGLE_INTERACTION" print("RAG pipeline initialized") - def single_interaction(self, input: str, history: List[Tuple[str, str]] = None) -> Dict[str, str]: + + def single_interaction(self, input: str, history: List[Tuple[str, str]] = None) -> List[Tuple[str, str, int]]: """ Single interaction retrieval algorithm: input -> retrieve documents. Args: @@ -178,12 +130,12 @@ def single_interaction(self, input: str, history: List[Tuple[str, str]] = None) str: The generated response. """ - documents = self.retriever.retrieve([input]) + documents = self.retriever.retrieve(input) return documents - def augmented_interaction(self, input: str, history: List[Tuple[str, str]] = None) -> Dict[str, str]: + def augmented_interaction(self, input: str, history: List[Tuple[str, str]] = None) -> List[Tuple[str, str, int]]: """ Augmented interaction RAG algorithm: input -> generate lookup tokens -> retrieve documents -> generate response. Args: @@ -219,14 +171,17 @@ def generate(self, input: Tuple[str, List[Tuple[str,str]]]) -> str: Returns: str: The generated response. """ - message, history = input + message = input - documents = self.retrieval_algorithm(message, history) - documents_str = "\n\n".join([f"Document {name}:\n {content}" for name, content in documents.items()]) + documents = self.single_interaction(message) + documents_str = "RETRIEVED INFORMATION:\n\n" + for doc_content, doc_file, chunk in documents: + doc_name = doc_file.split("/")[-1] + documents_str += f"Document '{doc_name}' in chunk: {chunk}:\n{doc_content}\n\n" prompt = ContextMergePrompt.format( input=message, - history=history, + history=None, documents=documents_str ) @@ -234,7 +189,6 @@ def generate(self, input: Tuple[str, List[Tuple[str,str]]]) -> str: response = self.llm_model.generate(prompt) - sources_str = ", ".join(doc_name for doc_name in documents.keys()) - response = f"{response[0]}\n\nSources:{sources_str}" + response = f"{response[0]}\n\nSources:{documents_str}" return [response] diff --git a/DashAI/back/models/RAG/Retrievers/BaseRetriever.py b/DashAI/back/models/RAG/Retrievers/BaseRetriever.py new file mode 100644 index 000000000..e12143378 --- /dev/null +++ b/DashAI/back/models/RAG/Retrievers/BaseRetriever.py @@ -0,0 +1,165 @@ +from abc import ABC +import os +from typing import Any, Dict, List, Final +from DashAI.back.models.RAG.Documents import BaseDocument, PDFDocument, TxtDocument +from DashAI.back.config_object import ConfigObject +import hashlib + +SUPPORTED_DOCUMENT_TYPES = ['pdf', 'txt'] + +class BaseRetriever(ABC, ConfigObject): + """ + Base class for retrievers. + """ + + RETRIEVERS_PATH = "./StoredRetrievers" + COMPATIBLE_COMPONENTS = ["RAGTask"] + TYPE: Final[str] = "RetrieverModel" + + + def __init__(self, *args, **kwargs): + """ + Initialize the retriever. + """ + self.params = None + self._documents_paths = None + self.chunk_size = None + self.chunk_overlap = None + + def _load_document(self, document_path: str) -> BaseDocument: + """ + Load a document from the specified path. + + Args: + document_path (str): The path to the document file. + + Returns: + BaseDocument: An instance of a document class (PDFDocument or TxtDocument). + """ + if document_path.endswith('.pdf'): + return PDFDocument(document_path) + elif document_path.endswith('.txt'): + return TxtDocument(document_path) + else: + raise ValueError(f"Unsupported document type: {document_path}") + + def get_documents(self) -> Dict[str, BaseDocument]: + """ + Get the documents stored in the retriever. + Returns: + Dict[str, BaseDocument]: A dictionary where keys are document paths and values are document instances. + """ + assert self._documents_paths is not None, "Document paths must be provided." + assert len(self._documents_paths) > 0, "At least one document path must be provided." + + self._documents_paths = sorted(self._documents_paths) # Sort for consistent hashing + documents = {} + for path in self._documents_paths: + doc = self._load_document(path) + documents[path] = doc + return documents + + def get_documents_chunks(self) -> Dict[str, List[str]]: + """ + Get the chunks of documents stored in the retriever. + + Returns: + Dict[str, Dict[int, str]]: A dictionary where keys are document paths and values are + dictionaries of chunk indices and their corresponding text. + """ + documents = self.get_documents() + chunks = {} + for filename, doc in documents.items(): + chunks[filename] = doc.get_chunks(self.chunk_size, self.chunk_overlap) + return chunks + + def get_parameters(self) -> Dict[str, Any]: + """ + Get the parameters of the retriever. + + Returns: + Dict[str, Any]: A dictionary of retriever parameters. + """ + assert self.params is not None, "Retriever parameters are not set." + return self.params + + def get_hashable_parameters(self) -> Dict[str, Any]: + """ + Get the parameters used for storing the fitted retriever in the database. + This parameters are a subset of the retriever parameters, the non-hashable parameters are + those whose change does not require a retraining of the retriever, i.e. n_docs, + max_distance, etc. + + Returns: + Dict[str, Any]: A dictionary of parameters that can be used for hashing. + """ + raise NotImplementedError("This method should be implemented by subclasses.") + + def _get_documents_hash(self) -> str: + """ + Generate a hash representing the current set of documents. + + Returns: + str: A hash string representing the documents. + """ + documents = sorted(self.get_documents().items()) + hashes = "" + for filename, doc in documents.items(): + doc_hash = doc.get_hash() + hashes += f"{filename}{doc_hash}" + return hashlib.sha256(hashes.encode('utf-8')).hexdigest() + + def _get_parameters_hash(self) -> str: + """ + Generate a hash representing the retriever parameters. + + Args: + parameters (Dict[str, Any]): A dictionary of retriever parameters. + + Returns: + str: A hash string representing the parameters. + """ + hashable_parameters = sorted(self.get_hashable_parameters().items()) + params_string = "".join(f"{key}{value}" for key, value in hashable_parameters) + return hashlib.sha256(params_string.encode('utf-8')).hexdigest() + + def _get_cache_hash(self) -> str: + """ + Generate a unique hash for the retriever based on its documents and parameters. + + Returns: + str: A hash string representing the retriever's state. + """ + documents_hash = self._get_documents_hash() + parameters_hash = self._get_parameters_hash() + return f"{self.__class__.__name__}_{documents_hash}_{parameters_hash}" + + def add_document(self, document: BaseDocument) -> None: + """ + Add a document to the retriever. + + Args: + document (BaseDocument): The document to add. + """ + raise NotImplementedError("This method should be implemented by subclasses.") + + def remove_document(self, document_id: str) -> None: + """ + Remove a document from the retriever by its ID. + + Args: + document_id (str): The ID of the document to remove. + """ + raise NotImplementedError("This method should be implemented by subclasses.") + + def retrieve(self, **kwargs) -> List[BaseDocument]: + """ + Retrieve documents based on the provided parameters. + + Args: + **kwargs: The parameters for the retrieval. + + Returns: + List[BaseDocument]: A list of retrieved documents. + """ + raise NotImplementedError("This method should be implemented by subclasses.") \ No newline at end of file diff --git a/DashAI/back/models/RAG/Retrievers/DenseRetriever.py b/DashAI/back/models/RAG/Retrievers/DenseRetriever.py new file mode 100644 index 000000000..835747c96 --- /dev/null +++ b/DashAI/back/models/RAG/Retrievers/DenseRetriever.py @@ -0,0 +1,12 @@ +from .BaseRetriever import BaseRetriever + +class DenseRetriever(BaseRetriever): + """ + Dense retriever class for retrieving documents based on dense vector representations. + This class is a placeholder and should be implemented with specific dense retrieval logic. + """ + + COMPATIBLE_COMPONENTS = ["RAGTask"] + + def __init__(self, *args, **kwargs): + return \ No newline at end of file diff --git a/DashAI/back/models/RAG/Retrievers/TFIDFRetriever.py b/DashAI/back/models/RAG/Retrievers/TFIDFRetriever.py new file mode 100644 index 000000000..f6a005ff0 --- /dev/null +++ b/DashAI/back/models/RAG/Retrievers/TFIDFRetriever.py @@ -0,0 +1,259 @@ +import os +from .BaseRetriever import BaseRetriever +from DashAI.back.models.RAG.Documents import BaseDocument, PDFDocument, TxtDocument +from typing import List, Dict, Any, Optional, Tuple +from sklearn.feature_extraction.text import TfidfVectorizer +from sklearn.metrics.pairwise import cosine_similarity, euclidean_distances +import numpy as np +import hashlib +import pickle + +from DashAI.back.core.schema_fields import ( + BaseSchema, + schema_field, + enum_field, + float_field, + int_field, +) + +similarities = { + "cosine": cosine_similarity, + "euclidean": euclidean_distances +} + + +class TFIDFRetrieverSchema(BaseSchema): + """ + Schema for the TFIDFRetriever. + """ + + similarity_function: schema_field( + enum_field(['cosine', 'euclidean']), + placeholder="cosine", + description="Similarity function to use for document retrieval." + ) # type: ignore + + n_docs: schema_field( + int_field(ge=1), + placeholder=5, + description="Number of documents to retrieve." + ) # type: ignore + + similarity_threshold: schema_field( + float_field(), + placeholder=0.5, + description="Maximum or minimum distance for retrieved documents based on the similarity_function." + ) # type: ignore + + chunk_size: schema_field( + int_field(ge=1), + placeholder=512, + description="Size of chunks to split the documents into." + ) # type: ignore + + chunk_overlap: schema_field( + int_field(ge=0), + placeholder=50, + description="Overlap between chunks when splitting documents." + ) # type: ignore + +class TFIDFRetriever(BaseRetriever): + """ + A retriever that uses TF-IDF to retrieve documents based on a query. + """ + SCHEMA = TFIDFRetrieverSchema + + def __init__( + self, + documents_paths: List[str], + similarity_function: str, + n_docs: int, + similarity_threshold: float, + chunk_size: int, + chunk_overlap: int + ): + """ + Initialize the TFIDFRetriever with the given parameters. + + Args: + documents_paths (List[str]): A list of document texts to be indexed. + similarity_function (str): Similarity function to use ('cosine' or 'euclidean'). + n_docs (int): The maximum number of documents to retrieve. + distance_threshold (float): The maximum or minimum distance for retrieved documents based on the similarity_function. + chunk_size (int): The size of chunks to split the documents into. + chunk_overlap (int): The overlap between chunks. + """ + + assert isinstance(documents_paths, list) and all(isinstance(doc, str) for doc in documents_paths), "Documents must be a list of strings." + assert similarity_function in similarities, f"similarity_function must be one of {list(similarities.keys())}." + assert n_docs > 0, "Number of documents to retrieve must be greater than 0." + assert similarity_threshold >= 0, "Similarity threshold must be non-negative." + assert chunk_size > 0, "Chunk size must be greater than 0." + assert chunk_overlap >= 0, "Chunk overlap must be non-negative." + assert chunk_size > chunk_overlap, "Chunk size must be greater than chunk overlap." + BASE_DOC_PATH = 'THIS IS A PLACEHOLDER, should be unnecesary after implementing the document persistence storage in the database' + new_documents_paths = [] + for doc_path in documents_paths: + new_path = os.path.join(BASE_DOC_PATH, doc_path) + new_documents_paths.append(new_path) + documents_paths = new_documents_paths + self._documents_paths = sorted(documents_paths) # Sort for consistent hashing + self.similarity_function_name = similarity_function + self.similarity_function = similarities[similarity_function] + self.n_docs = n_docs + self.similarity_threshold = similarity_threshold + self.chunk_size = chunk_size + self.chunk_overlap = chunk_overlap + + self.params = { + "similarity_function_name": self.similarity_function_name, + "similarity_function": self.similarity_function, + "n_docs": n_docs, + "similarity_threshold": similarity_threshold, + "chunk_size": chunk_size, + "chunk_overlap": chunk_overlap + } + + + # Generate a unique hash for the current set of documents and chunking parameters + self._cache_hash = self._generate_cache_hash() + self._vectorizer_path, self._tf_idf_matrix, self.chunk_to_doc_path = self._get_cache_paths() + + + # Attempt to load from cache + if self._load_state(): + print(f"TFIDFRetriever loaded from cache: {self._cache_hash}") + else: + print(f"TFIDFRetriever cache not found or invalid for {self._cache_hash}. Fitting new model...") + self._fit() + self._save_state() + + def _get_cache_paths(self) -> tuple[str, str, str]: + """ + Returns the file paths for the cached vectorizer, tfidf_matrix, and chunk_to_doc_id_map. + """ + os.makedirs(self.RETRIEVERS_PATH, exist_ok=True) # Use BaseRetriever's constant + base_name = os.path.join(self.RETRIEVERS_PATH, self._cache_hash) + os.makedirs(base_name, exist_ok=True) + vectorizer_path = os.path.join(base_name, "vectorizer") + tfidf_matrix_path = os.path.join(base_name, "tfidf_matrix") + map_path = os.path.join(base_name, "chunk_to_doc_id_map") + return vectorizer_path, tfidf_matrix_path, map_path + + def get_hashable_parameters(self): + return { + "chunk_size": self.chunk_size, + "chunk_overlap": self.chunk_overlap, + } + + def _generate_cache_hash(self) -> str: + hashable_params = self.get_hashable_parameters() + text = f"{self._documents_paths}{hashable_params}" + params_hash = hashlib.sha256(text.encode('utf-8')).hexdigest() + docs_hashes = [] + for doc_path in self._documents_paths: + if doc_path.endswith('.pdf'): + doc = PDFDocument(doc_path) + elif doc_path.endswith('.txt'): + doc = TxtDocument(doc_path) + else: + raise ValueError(f"Unsupported document type: {doc_path}") + + docs_hashes.append(doc.get_hash()) + docs_hash = hashlib.sha256("".join(docs_hashes).encode('utf-8')).hexdigest() + return f"tfidf_retriever_{params_hash}_{docs_hash}" + + + def _load_state(self) -> bool: + """ + Load the retriever state from cache if available. + + Returns: + bool: True if the state was successfully loaded, False otherwise. + """ + if not os.path.exists(self._vectorizer_path): + return False + if not os.path.exists(self._tf_idf_matrix): + return False + if not os.path.exists(self.chunk_to_doc_path): + return False + + try: + self._vectorizer = pickle.load(open(self._vectorizer_path, 'rb')) + self._tf_idf_matrix = pickle.load(open(self._tf_idf_matrix, 'rb')) + self.chunk_to_doc_map = pickle.load(open(self.chunk_to_doc_path, 'rb')) + return True + except Exception as e: + print(f"Error loading state: {e}") + return False + + def _save_state(self): + """ + Save the retriever state to cache. + """ + try: + pickle.dump(self._vectorizer, open(self._vectorizer_path, 'wb')) + pickle.dump(self._tf_idf_matrix, open(self._tf_idf_matrix, 'wb')) + pickle.dump(self.chunk_to_doc_map, open(self.chunk_to_doc_path, 'wb')) + except Exception as e: + print(f"Error saving state: {e}") + + def _fit(self): + """ + Fit the TF-IDF model to the documents. + This method should be called after initializing the retriever. + """ + # Load chunks from the documents + chunks = self.get_documents_chunks() + chunk_texts = [] + current_chunk_idx = 0 + self.chunk_to_doc_map = {} + + for doc_path, doc_chunks in chunks.items(): + for i, chunk_text in enumerate(doc_chunks): + chunk_texts.append(chunk_text) + self.chunk_to_doc_map[current_chunk_idx] = (chunk_text, doc_path, i) + current_chunk_idx += 1 + + # Create the TF-IDF vectorizer and fit it to the chunks + self._vectorizer = TfidfVectorizer() + self._tf_idf_matrix = self._vectorizer.fit_transform(chunk_texts) + self._save_state() + + def retrieve(self, query: str) -> List[Tuple[str, str, int]]: + """ + Retrieve documents based on the query using TF-IDF. + Args: + query (str): The query string to search for. + Returns: + List[Tuple[str, str, int]]: A list of tuples containing the chunk text, document path, and chunk ID. + """ + assert self._tf_idf_matrix is not None, "Model is not fitted. Call _fit() before retrieving." + + print(f"Retrieving documents for query: {query}") + # Transform the query using the same vectorizer + query_vector = self._vectorizer.transform([query]) + + # Calculate the similarity scores + similarities = self.similarity_function(query_vector, self._tf_idf_matrix).flatten() + + # Determine sorting order based on similarity_function + if self.similarity_function == cosine_similarity: + filtered_indices = np.where(similarities >= self.similarity_threshold)[0] + ranked_indices = np.argsort(-similarities[filtered_indices])[:self.n_docs] + + elif self.similarity_function == euclidean_distances: + filtered_indices = np.where(similarities <= self.similarity_threshold)[0] + ranked_indices = np.argsort(similarities[filtered_indices])[:self.n_docs] + + else: + raise ValueError(f"Unsupported similarity_function: {self.similarity_function}") + + # Get the top n_docs indices + top_indices = ranked_indices[:self.n_docs] + + results: List[Tuple[str, str, int]] = [] + for idx in top_indices: + results.append(self.chunk_to_doc_map[idx]) + + return results \ No newline at end of file diff --git a/DashAI/back/models/RAG/Retrievers/__init__.py b/DashAI/back/models/RAG/Retrievers/__init__.py new file mode 100644 index 000000000..4e295aff6 --- /dev/null +++ b/DashAI/back/models/RAG/Retrievers/__init__.py @@ -0,0 +1,3 @@ +from DashAI.back.models.RAG.Retrievers.BaseRetriever import BaseRetriever +from DashAI.back.models.RAG.Retrievers.TFIDFRetriever import TFIDFRetriever +from DashAI.back.models.RAG.Retrievers.DenseRetriever import DenseRetriever \ No newline at end of file diff --git a/DashAI/back/models/RAG/__init__.py b/DashAI/back/models/RAG/__init__.py index ef3481f81..6261e0606 100644 --- a/DashAI/back/models/RAG/__init__.py +++ b/DashAI/back/models/RAG/__init__.py @@ -1 +1,2 @@ -from DashAI.back.models.RAG.RAG_pipeline import RAGPipeline \ No newline at end of file +from DashAI.back.models.RAG.RAG_pipeline import RAGPipeline +from DashAI.back.models.RAG.Retrievers import BaseRetriever, TFIDFRetriever, DenseRetriever \ No newline at end of file diff --git a/DashAI/back/models/__init__.py b/DashAI/back/models/__init__.py index 8505aa623..3e7cb9a99 100644 --- a/DashAI/back/models/__init__.py +++ b/DashAI/back/models/__init__.py @@ -49,4 +49,4 @@ from DashAI.back.models.scikit_learn.sklearn_like_regressor import SklearnLikeRegressor from DashAI.back.models.scikit_learn.svc import SVC -from DashAI.back.models.RAG import RAGPipeline \ No newline at end of file +from DashAI.back.models.RAG import RAGPipeline, BaseRetriever, TFIDFRetriever, DenseRetriever \ No newline at end of file diff --git a/DashAI/back/models/hugging_face/__init__.py b/DashAI/back/models/hugging_face/__init__.py index e69de29bb..340e9e6f0 100644 --- a/DashAI/back/models/hugging_face/__init__.py +++ b/DashAI/back/models/hugging_face/__init__.py @@ -0,0 +1,3 @@ +from DashAI.back.models.hugging_face.deep_seek_model import DeepSeekModel +from DashAI.back.models.hugging_face.qwen_model import QwenModel +from DashAI.back.models.hugging_face.gemma_model import GemmaModel \ No newline at end of file diff --git a/DashAI/back/models/text_to_text_generation_model.py b/DashAI/back/models/text_to_text_generation_model.py index f5fbfda2c..782fdcb9e 100644 --- a/DashAI/back/models/text_to_text_generation_model.py +++ b/DashAI/back/models/text_to_text_generation_model.py @@ -4,4 +4,4 @@ class TextToTextGenerationTaskModel(BaseGenerativeModel): """Class for models associated to TextToTextGenerationTask.""" - COMPATIBLE_COMPONENTS = ["TextToTextGenerationTask"] + COMPATIBLE_COMPONENTS = ["TextToTextGenerationTask", "RAGTask"] diff --git a/DashAI/back/tasks/RAG_task.py b/DashAI/back/tasks/RAG_task.py index f8d309847..60b06c461 100644 --- a/DashAI/back/tasks/RAG_task.py +++ b/DashAI/back/tasks/RAG_task.py @@ -44,7 +44,7 @@ def prepare_for_task( The history of the conversation """ - return input # type: Optional[List[Tuple[str, str]]] + return input[0].data # type: Optional[List[Tuple[str, str]]] @@ -76,7 +76,7 @@ def process_output( ) -> str: """Process the output of a generative model.""" - return output + return [(str(output[0]), "str")] def process_output_from_database( self, diff --git a/DashAI/front/src/api/generativeTask.ts b/DashAI/front/src/api/generativeTask.ts index 73957488d..2dac403c7 100644 --- a/DashAI/front/src/api/generativeTask.ts +++ b/DashAI/front/src/api/generativeTask.ts @@ -16,6 +16,7 @@ export const getRelatedComponents = async ( const response = await api.get( `/v1/component/?related_component=${encodeURIComponent(relatedComponent)}`, ); + console.log("Related components:", response.data); return response.data; } catch (error) { return []; @@ -25,6 +26,8 @@ export const getRelatedComponents = async ( export const createGenerativeSession = async ( sessionData: Omit, ): Promise => { + + console.log("Creating new generative session with data:", sessionData); const response = await api.post( "/v1/generative-session/", sessionData, diff --git a/DashAI/front/src/api/rag.ts b/DashAI/front/src/api/rag.ts index 8e57f2a99..6a3f2b67c 100644 --- a/DashAI/front/src/api/rag.ts +++ b/DashAI/front/src/api/rag.ts @@ -3,421 +3,135 @@ import { ISession } from "../types/session"; import { IGenerativeTask } from "../types/generativeTask"; +// Fetch all RAG sessions +export const getRAGSessions = async (): Promise => { + const response = await api.get("/v1/generative-session/"); + if (response.status !== 200) { + throw new Error(`Failed to fetch RAG sessions: ${response.statusText}`); + } + return response.data; +} -// Dummy data -// use the days of june 2025 for first, second, ... sessions -let sessions: ISession[] = [ - { - id: "1", - name: "Session I", - task_name: "RAGTask", - description: "First dummy session", - created: new Date("2025-06-01"), - last_modified: new Date("2025-06-01"), - display_name: "RAG Session I", - model_name: "RAGModel", - parameters: { paramA: 1 }, - }, - { - id: "2", - name: "Session II", - task_name: "RAGTask", - description: "Second dummy session", - created: new Date("2025-06-02"), - last_modified: new Date("2025-06-02"), - display_name: "RAG Session II", - model_name: "RAGModel", - parameters: { paramA: 2 }, - }, - { - id: "3", - name: "Session III", - task_name: "RAGTask", - description: "Third dummy session", - created: new Date("2025-06-03"), - last_modified: new Date("2025-06-03"), - display_name: "RAG Session III", - model_name: "RAGModel", - parameters: { paramA: 3 }, - }, - { - id: "4", - name: "Session IV", - task_name: "RAGTask", - description: "Fourth dummy session", - created: new Date("2025-06-04"), - last_modified: new Date("2025-06-04"), - display_name: "RAG Session IV", - model_name: "RAGModel", - parameters: { paramA: 4 }, - } -]; - -let components: IGenerativeTask[] = [ - { - name: "Dense Passage Retrieval", - type: "retriever", - configurable_object: true, - schema: { - description: "Schema for dense passage retrieval", - properties: { - paramA: { - description: "Transformer", - enum: [ - "BERT", - "RoBERTa", - "DistilBERT", - "ALBERT", - ], - placeholder: "BERT", - title: "Parameter A", - type: "string", - }, - DistanceMetric: { - description: "Distance metric to use for retrieval", - enum: [ - "cosine", - "dot_product", - "euclidean", - ], - placeholder: "cosine", - title: "Distance Metric", - type: "string", - }, - }, - required: ["paramA", "DistanceMetric"], - type: "object", - }, - metadata: { - inputs_cardinality: 1, - outputs_cardinality: 1, - inputs_types: ["text"], - outputs_types: ["text"], - }, - description: "A component for dense passage retrieval", - display_name: "Dense Passage Retrieval", - }, - { - name: "TFIDFRetriever", - type: "retriever", - configurable_object: true, - schema: { - description: "Schema for TF-IDF retriever", - properties: { - paramA: { - description: "Remove stop words", - placeholder: "true", - title: "Remove Stop Words", - type: "boolean" - }, - TokenScoreCombination: { - description: "Token score combination method", - enum: [ - "sum", - "max", - "min", - ], - placeholder: "sum", - title: "Token Score Combination", - type: "string" - }, - }, - required: ["paramA", "TokenScoreCombination"], - type: "object", - }, - metadata: { - inputs_cardinality: 1, - outputs_cardinality: 1, - inputs_types: ["text"], - outputs_types: ["text"], - }, - description: "A component for TF-IDF retrieval", - display_name: "TF-IDF Retriever", - }, - - { - name: "DeepSeekModel", - type: "GenerativeModel", - configurable_object: true, - schema: { - description: "Schema for DeepSeek model.", - properties: { - max_tokens: { - description: "Maximum number of tokens to generate.", - minimum: 1, - placeholder: 100, - title: "Max Tokens", - type: "integer" - }, - temperature: { - description: "Sampling temperature. Higher values make the output more random, while lower values make it more focused and deterministic.", - maximum: 1, - minimum: 0, - placeholder: 0.7, - title: "temperature", - type: "number" - }, - frequency_penalty: { - description: "Penalty for repeated tokens in the output. Higher values reduce the likelihood of repetition, encouraging more diverse text generation.", - maximum: 2, - minimum: 0, - placeholder: 0.1, - title: "Frequency Penalty", - type: "number" - }, - n_ctx: { - description: "Maximum number of tokens the model can process in a single forward pass (context window size).", - minimum: 1, - placeholder: 4096, - title: "N Ctx", - type: "integer" - } - }, - required: [ - "max_tokens", - "temperature", - "frequency_penalty", - "n_ctx" - ], - title: "DeepSeekSchema", - type: "object" - }, - metadata: { - inputs_cardinality: 1, - outputs_cardinality: 1, - inputs_types: ["text"], - outputs_types: ["text"] - }, - description: "null,", - display_name: "null" - }, - { - name: "GemmaModel", - type: "GenerativeModel", - configurable_object: true, - schema: { - description: "Schema for Gemma model.", - properties: { - max_tokens: { - description: "Maximum number of tokens to generate.", - minimum: 1, - placeholder: 100, - title: "Max Tokens", - type: "integer" - }, - temperature: { - description: "Sampling temperature. Higher values make the output more random, while lower values make it more focused and deterministic.", - maximum: 1, - minimum: 0, - placeholder: 0.7, - title: "temperature", - type: "number" - }, - frequency_penalty: { - description: "Penalty for repeated tokens in the output. Higher values reduce the likelihood of repetition, encouraging more diverse text generation.", - maximum: 2, - minimum: 0, - placeholder: 0.1, - title: "Frequency Penalty", - type: "number" - }, - n_ctx: { - description: "Maximum number of tokens the model can process in a single forward pass (context window size).", - minimum: 1, - placeholder: 512, - title: "N Ctx", - type: "integer" - } - }, - required: [ - "max_tokens", - "temperature", - "frequency_penalty", - "n_ctx" - ], - title: "GemmaSchema", - type: "object" - }, - metadata: { - inputs_cardinality: 1, - outputs_cardinality: 1, - inputs_types: ["text"], - outputs_types: ["text"] - }, - description: "null,", - display_name: "null" - }, - { - name: "QwenModel", - type: "GenerativeModel", - configurable_object: true, - schema: { - description: "Schema for Qwen model.", - properties: { - "model_name": { - description: "The specific Qwen model version to use.", - "enum": [ - "Qwen/Qwen2.5-0.5B-Instruct-GGUF", - "Qwen/Qwen2.5-1.5B-Instruct-GGUF" - ], - placeholder: "Qwen/Qwen2.5-1.5B-Instruct-GGUF", - title: "Model Name", - type: "string" - }, - max_tokens: { - description: "Maximum number of tokens to generate.", - minimum: 1, - placeholder: 100, - title: "Max Tokens", - type: "integer" - }, - temperature: { - description: "Sampling temperature. Higher values make the output more random, while lower values make it more focused and deterministic.", - maximum: 1, - minimum: 0, - placeholder: 0.7, - title: "temperature", - type: "number" - }, - frequency_penalty: { - description: "Penalty for repeated tokens in the output. Higher values reduce the likelihood of repetition, encouraging more diverse text generation.", - maximum: 2, - minimum: 0, - placeholder: 0.1, - title: "Frequency Penalty", - type: "number" - }, - n_ctx: { - description: "Maximum number of tokens the model can process in a single forward pass (context window size).", - minimum: 1, - placeholder: 512, - title: "N Ctx", - type: "integer" - } - }, - required: [ - "model_name", - "max_tokens", - "temperature", - "frequency_penalty", - "n_ctx" - ], - title: "QwenSchema", - type: "object" - }, - metadata: { - inputs_cardinality: 1, - outputs_cardinality: 1, - inputs_types: ["text"], - outputs_types: ["text"] - }, - description: "null,", - display_name: "null" +export const getRAGSession = async (sessionId: number): Promise => { + + const response = await api.get(`/v1/generative-session/${sessionId}`); + if (response.status !== 200) { + throw new Error(`Failed to fetch RAG session: ${response.statusText}`); } -] -// Fetch all RAG sessions -export const getRAGSessions = async (): Promise => { - console.log("Fetching all RAG sessions"); - - // Simulate an API call - /* - const response = await api.get( - "/v1/generative-session - */ - return [...sessions]; + return response.data; } -// Create a new RAG session export const createRAGSession = async ( - sessionData: Omit + sessionData: Omit ): Promise => { - const newSession: ISession = { - ...sessionData, - id: (Math.random() * 100000).toFixed(0), + console.log("Original RAG session input:", sessionData); + + const params = sessionData.parameters as { + documents: string[]; + retriever_model: { + name: string; + parameters: Record; + }; + generator_model: { + name: string; + parameters: Record; + }; }; - // Simulate an API call - /* - const response = await api.post("/v1/rag-session/", newSession); - */ - sessions.push(newSession); - return newSession; -} -// Update an existing RAG session -export const updateRAGSession = async ( - sessionData: ISession -): Promise => { - - // Mockup data - const index = sessions.findIndex((s) => s.id === sessionData.id); - if (index === -1) throw new Error("Session not found"); - sessions[index] = sessionData; - - // Simulate an API call - /* - const response = await api.put( - `/v1/rag-session/${sessionData.id}`, - sessionData - ); - */ + const transformedSession: Omit = { + name: sessionData.name, + description: sessionData.description, + task_name: "RAGTask", + model_name: "RAGPipeline", + display_name: "", + parameters: { + documents: params.documents, + retriever_model: { + component: params.retriever_model.name, + params: params.retriever_model.parameters, + }, + generation_model: { + component: params.generator_model.name, + params: params.generator_model.parameters, + }, + }, + }; - return sessionData; -} -// Delete a RAG session by ID -export const deleteRAGSession = async (sessionId: string): Promise => { - // mockup data - sessions = sessions.filter((s) => s.id !== sessionId); + console.log("Sending RAG session as:", transformedSession); - // Simulate an API call - /* - removeSession(sessionId); - */ + const response = await api.post("/v1/generative-session/", transformedSession); - console.log(`Deleted session with ID: ${sessionId}`); - return; -} + if (response.status !== 201) { + throw new Error(`Failed to create RAG session: ${response.statusText}`); + } -// Fetch a single RAG session by ID -export const getRAGSession = async (sessionId: string): Promise => { - console.log(`Fetching session with ID: ${sessionId}`); + console.log("RAG session created successfully:", response.data); + return response.data; +}; + +export const updateRAGSession = async (sessionId: number, sessionData: Partial): Promise => { - // Simulate an API call - /* - const response = await api.get( - `/v1/generative-session/${sessionId}` + const response = await api.put(`/v1/generative-session/${sessionId}`, sessionData); + if (response.status !== 200) { + throw new Error(`Failed to update RAG session: ${response.statusText}`); + } return response.data; - */ - - const session = sessions.find((s) => s.id === sessionId); - if (!session) throw new Error("Session not found"); +} + +export const deleteRAGSession = async (sessionId: number): Promise => { + const response = await api.delete(`/v1/generative-session/${sessionId}`); + if (response.status !== 204) { + throw new Error(`Failed to delete RAG session: ${response.statusText}`); + } - return [session]; } -export const getRAGComponents = async (componentType: string): Promise => { - // Simulate fetching RAG components based on type - /* - const response = await api.get( - `/v1/component/?related_component=RAGTask&component_type=${componentType}` +export const updateGenerativeSessionParams = async ( + sessionId: number, + newParams: Record, +): Promise => { + + const response = await api.put( + `/v1/generative-session/${sessionId}/parameters`, + newParams, ); - return response.data; - */ - - let filteredComponents = components.filter((c) => c.type === componentType); - console.log(`Fetching RAG ${filteredComponents.length} components of type ${componentType}`); - return filteredComponents; -}; + if (response.status !== 200) { + throw new Error(`Failed to update RAG session parameters: ${response.statusText}`); + } + return response.data; +} + export const getRetrieverComponents = async (): Promise => { - return getRAGComponents("retriever"); + + const response = await api.get( + `/v1/component/?select_types=RetrieverModel` + ); + + if (response.status !== 200) { + throw new Error(`Failed to fetch retriever components: ${response.statusText}`); + } + + return response.data; + } export const getGeneratorComponents = async (): Promise => { - return getRAGComponents("GenerativeModel"); + + const response = await api.get( + `/v1/component/?related_component=TextToTextGenerationTask` + ); + + if (response.status !== 200) { + throw new Error(`Failed to fetch generator components: ${response.statusText}`); + } + + return response.data; + } \ No newline at end of file diff --git a/DashAI/front/src/components/generative/RAG/ComponentSelector.jsx b/DashAI/front/src/components/generative/RAG/ComponentSelector.jsx index 457a05798..d3e7f648c 100644 --- a/DashAI/front/src/components/generative/RAG/ComponentSelector.jsx +++ b/DashAI/front/src/components/generative/RAG/ComponentSelector.jsx @@ -1,17 +1,9 @@ -import React, { useState, useEffect } from "react"; -import PropTypes from "prop-types"; -import { - Box, - Typography, - Autocomplete, - TextField, - CircularProgress -} from "@mui/material"; -import FormSchemaRenderFields from "../../shared/FormSchemaRenderFields"; -import { useFormik } from "formik"; -import { preprocessSchema, buildYupSchema } from "../utils"; -import { getRelatedComponents } from "../../../api/generativeTask"; -function ComponentSelector({ +import React, { useEffect, useState } from 'react'; +import { Box, Typography, TextField, CircularProgress } from '@mui/material'; +import Autocomplete from '@mui/material/Autocomplete'; + + +export default function ComponentSelector({ componentType, fetchComponents, initialValues, @@ -21,100 +13,64 @@ function ComponentSelector({ const [components, setComponents] = useState([]); const [selectedComponent, setSelectedComponent] = useState(null); const [loading, setLoading] = useState(true); - const [validationSchema, setValidationSchema] = useState(null); - - try { - console.log(getRelatedComponents("TextToTextGenerationTask")); - } catch (error) { - } - + const [formValues, setFormValues] = useState({}); - - // Fetch available components + // Cargar componentes disponibles useEffect(() => { - const getComponents = async () => { - setLoading(true); + const loadComponents = async () => { try { const data = await fetchComponents(); setComponents(data); - // If we have initialValues with a model_name, select that component + // Seleccionar componente inicial si existe if (initialValues?.model_name) { - const preselectedComponent = data.find(c => c.name === initialValues.model_name); - if (preselectedComponent) { - setSelectedComponent(preselectedComponent); + const component = data.find(c => c.name === initialValues.model_name); + if (component) { + setSelectedComponent(component); + setFormValues(initialValues.parameters || {}); } - } else { - console.warn(`No initial model_name provided for ${componentType} selection.`); } } catch (error) { - console.error(`Error fetching ${componentType} components:`, error); + console.error(`Error loading ${componentType} components:`, error); } finally { setLoading(false); } }; - - getComponents(); - }, [componentType, fetchComponents]); - // Set up form validation schema when component changes + loadComponents(); + }, []); + + // Actualizar cuando cambia la selección useEffect(() => { - if (selectedComponent?.schema?.properties) { - const processedProps = preprocessSchema(selectedComponent.schema.properties); - setValidationSchema(buildYupSchema(processedProps)); - console.log("Processed properties for form:", processedProps); - // Merge any existing values with defaults from schema - const schemaDefaults = Object.keys(processedProps).reduce( - (acc, key) => { - acc[key] = processedProps[key].placeholder || ""; - console.log(`Setting default for ${key}:`, acc[key]); - return acc; - }, - { name: "", description: ""}); + if (selectedComponent) { + // Resetear valores al cambiar de componente + setFormValues(initialValues?.parameters || {}); - // Preserve any values that were already set - const mergedValues = { - ...schemaDefaults, - ...(initialValues?.parameters || {}) - }; - - formik.setValues(mergedValues); - } - }, [selectedComponent]); - - const formik = useFormik({ - initialValues: initialValues?.parameters || {}, - validationSchema, - enableReinitialize: true, - onSubmit: (values) => { + // Notificar cambio onConfigurationChange({ model_name: selectedComponent.name, - parameters: values + parameters: initialValues?.parameters || {} }); } - }); + }, [selectedComponent]); - // Enable/disable next button based on form validity and selection + // Validar y habilitar siguiente paso useEffect(() => { - if (selectedComponent && formik.isValid) { - setNextEnabled(true); - - // Auto-submit valid values as they change - if (formik.dirty) { - onConfigurationChange({ - model_name: selectedComponent.name, - parameters: formik.values - }); - } - } else { - setNextEnabled(false); - } - }, [selectedComponent, formik.values, formik.isValid, formik.dirty]); + setNextEnabled(!!selectedComponent); + }, [selectedComponent]); - // Process schema properties for the form renderer - const processedProperties = selectedComponent?.schema?.properties - ? preprocessSchema(selectedComponent.schema.properties) - : {}; + const handleParameterChange = (name, value) => { + const newValues = {...formValues, [name]: value}; + setFormValues(newValues); + + // Notificar cambios en tiempo real + if (selectedComponent) { + onConfigurationChange({ + model_name: selectedComponent.name, + parameters: newValues + }); + } + }; return ( @@ -123,56 +79,49 @@ function ComponentSelector({ {loading ? ( - - - + ) : ( <> c.name)} - value={selectedComponent?.name || null} + value={selectedComponent?.name || ""} onChange={(_, newValue) => { - const selected = components.find(c => c.name === newValue); - setSelectedComponent(selected); + const component = components.find(c => c.name === newValue); + setSelectedComponent(component); }} renderInput={(params) => ( - + )} - sx={{ mb: 4 }} + fullWidth + sx={{ mb: 3 }} /> {selectedComponent && ( -
+ - {selectedComponent.name} Configuration + Configuration Parameters - { - formik.setValues({...formik.values, ...updatedValues}); - }} - onFormSubmit={formik.handleSubmit} - setError={(error) => console.error(error)} - errorsMessage={formik.errors} - /> - + {selectedComponent.schema && Object.entries(selectedComponent.schema.properties).map(([key, spec]) => ( + handleParameterChange(key, e.target.value)} + fullWidth + margin="normal" + type={spec.type === 'integer' ? 'number' : 'text'} + helperText={spec.description} + /> + ))} +
)} )}
); -} - -ComponentSelector.propTypes = { - componentType: PropTypes.string.isRequired, - fetchComponents: PropTypes.func.isRequired, - initialValues: PropTypes.object, - onConfigurationChange: PropTypes.func.isRequired, - setNextEnabled: PropTypes.func.isRequired -}; - -export default ComponentSelector; \ No newline at end of file +} \ No newline at end of file diff --git a/DashAI/front/src/components/generative/RAG/DocumentSelector.jsx b/DashAI/front/src/components/generative/RAG/DocumentSelector.jsx index 944cad664..4f7040a2c 100644 --- a/DashAI/front/src/components/generative/RAG/DocumentSelector.jsx +++ b/DashAI/front/src/components/generative/RAG/DocumentSelector.jsx @@ -1,34 +1,32 @@ import { Box } from "@mui/material"; import { useEffect, useState } from "react"; +import PropTypes from "prop-types"; // Import PropTypes import DocumentTable from "./DocumentTable"; -import Upload from "../../shared/Upload"; +import Upload from "../../shared/Upload"; // Assuming path is correct -export default function DocumentSelector({ - selected = [], // Provide default empty array to prevent map errors - onSelect +export default function DocumentSelector({ + documents: initialDocuments = [], // Renamed prop for clarity, uses initial state + selected: initialSelectedIds = [], // Renamed prop for clarity + onSelect, // Callback for when selection changes (receives selected document objects) + onAddDocument, // Callback for when a new document object is added (receives new doc object) + onRemove, // Callback for when a document is removed (receives docId/path) }) { - const [documents, setDocuments] = useState([]); - const [selectedIds, setSelectedIds] = useState( - (selected || []).map(doc => doc.id) - ); + const [documents, setDocuments] = useState(initialDocuments); + const [selectedIds, setSelectedIds] = useState(initialSelectedIds); // Add a key state to force Upload component re-render const [uploadKey, setUploadKey] = useState(0); - // Fetch documents on mount + // Sync internal 'documents' state with 'initialDocuments' prop useEffect(() => { - // Simulated API - const fetchDocuments = async () => { - // Return mock data if needed - return [ - { id: "doc1", name: "Document 1", updatedAt: new Date().toISOString() }, - { id: "doc2", name: "Document 2", updatedAt: new Date().toISOString() } - ]; - }; - - fetchDocuments().then(setDocuments); - }, []); + setDocuments(initialDocuments); + }, [initialDocuments]); + + // Sync internal 'selectedIds' state with 'initialSelectedIds' prop + useEffect(() => { + setSelectedIds(initialSelectedIds); + }, [initialSelectedIds]); - // Sync selected documents with parent + // Sync selected documents with parent's onSelect callback useEffect(() => { const selectedDocs = documents.filter(doc => selectedIds.includes(doc.id)); if (onSelect) { @@ -37,7 +35,7 @@ export default function DocumentSelector({ }, [selectedIds, documents, onSelect]); const handleToggleSelection = (id) => { - setSelectedIds(prev => + setSelectedIds(prev => prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id] ); }; @@ -50,34 +48,48 @@ export default function DocumentSelector({ setSelectedIds([]); }; - const handleAddDocument = (newDoc) => { - const newDocWithId = { - ...newDoc, - id: `doc-${Date.now()}`, - updatedAt: new Date().toISOString() - }; - - setDocuments(prev => [newDocWithId, ...prev]); - setSelectedIds(prev => [...prev, newDocWithId.id]); + // Internal handler for adding a document object (before notifying parent) + const addDocumentObject = (newDoc) => { + setDocuments(prev => { + // Ensure no duplicates based on ID (path) + if (!prev.some(doc => doc.id === newDoc.id)) { + return [newDoc, ...prev]; // Add to the beginning + } + return prev; + }); + // Call the parent's onAddDocument callback + if (onAddDocument) { + onAddDocument(newDoc); + } }; - const handleRemove = (id) => { + // Internal handler for removing a document object (before notifying parent) + const removeDocumentObject = (id) => { setDocuments(prev => prev.filter(doc => doc.id !== id)); setSelectedIds(prev => prev.filter(x => x !== id)); + // Call the parent's onRemove callback + if (onRemove) { + onRemove(id); + } }; const handleFileUpload = (file, url) => { if (!file) return; - + + // The 'id' of the document will be the URL (or file.name if no URL is available) + // This allows the 'id' to directly represent the path/reference + const docId = url || file.name; + const newDoc = { - id: `doc-${Date.now()}`, + id: docId, name: file.name, updatedAt: new Date().toISOString(), - preview: url + preview: url, // Store URL for preview if available }; - - handleAddDocument(newDoc); - + + addDocumentObject(newDoc); // Use the internal handler + setSelectedIds(prev => [...prev, newDoc.id]); // Also select it upon upload + // Reset the upload component by incrementing its key setUploadKey(prev => prev + 1); }; @@ -91,16 +103,29 @@ export default function DocumentSelector({ onToggle={handleToggleSelection} onSelectAll={handleSelectAll} onDeselectAll={handleDeselectAll} - onRemove={handleRemove} + onRemove={removeDocumentObject} // Use the internal removal handler /> - ); -} \ No newline at end of file +} + +DocumentSelector.propTypes = { + documents: PropTypes.arrayOf(PropTypes.shape({ + id: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + updatedAt: PropTypes.string.isRequired, + preview: PropTypes.string, // Optional + })), + selected: PropTypes.arrayOf(PropTypes.string), // Array of document IDs (paths) + onSelect: PropTypes.func, // (selectedDocs: array of objects) => void + onAddDocument: PropTypes.func, // (newDoc: object) => void + onRemove: PropTypes.func, // (docId: string) => void +}; diff --git a/DashAI/front/src/components/generative/RAG/DocumentTable.jsx b/DashAI/front/src/components/generative/RAG/DocumentTable.jsx index 94293a4a7..9bf365ed0 100644 --- a/DashAI/front/src/components/generative/RAG/DocumentTable.jsx +++ b/DashAI/front/src/components/generative/RAG/DocumentTable.jsx @@ -13,7 +13,7 @@ import { } from "@mui/material"; import VisibilityIcon from "@mui/icons-material/Visibility"; import DeleteIcon from "@mui/icons-material/Delete"; -import { Margin } from "@mui/icons-material"; +import PropTypes from "prop-types"; export default function DocumentTable({ documents, @@ -25,12 +25,12 @@ export default function DocumentTable({ }) { return ( - @@ -43,7 +43,20 @@ export default function DocumentTable({ - + {/* Added padding="checkbox" for standard spacing */} + {/* Checkbox for Select All/Deselect All */} + 0 && selectedIds.length < documents.length} + checked={selectedIds.length === documents.length && documents.length > 0} + onChange={(event) => { + if (event.target.checked) { + onSelectAll(); + } else { + onDeselectAll(); + } + }} + /> + Name Updated Actions @@ -59,7 +72,7 @@ export default function DocumentTable({ backgroundColor: selectedIds.includes(doc.id) ? "action.hover" : "inherit", }} > - + {/* Added padding="checkbox" */} onToggle(doc.id)} @@ -70,7 +83,10 @@ export default function DocumentTable({ - + { + if (doc.preview) window.open(doc.preview, '_blank'); + else console.warn("No preview URL available for this document."); + }}> @@ -85,12 +101,16 @@ export default function DocumentTable({ ))}
- + gap={1} /* Added gap between buttons */ + p={1} /* Added padding for buttons within the box */ + borderTop="1px solid #e0e0e0" /* Separator line */ + > @@ -99,3 +119,17 @@ export default function DocumentTable({
); } + +DocumentTable.propTypes = { + documents: PropTypes.arrayOf(PropTypes.shape({ + id: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + updatedAt: PropTypes.string.isRequired, + preview: PropTypes.string, + })).isRequired, + selectedIds: PropTypes.arrayOf(PropTypes.string).isRequired, + onToggle: PropTypes.func.isRequired, + onSelectAll: PropTypes.func.isRequired, + onDeselectAll: PropTypes.func.isRequired, + onRemove: PropTypes.func.isRequired, +}; diff --git a/DashAI/front/src/components/generative/SelectModelMenu.jsx b/DashAI/front/src/components/generative/SelectModelMenu.jsx index aa15b71e6..71afaeb2a 100644 --- a/DashAI/front/src/components/generative/SelectModelMenu.jsx +++ b/DashAI/front/src/components/generative/SelectModelMenu.jsx @@ -24,7 +24,6 @@ export default function SelectModelMenu({ useEffect(() => { if (!selectedTaskName) return; - console.log("Fetching related components for task:", selectedTaskName); getRelatedComponents(selectedTaskName).then(setRelatedComponents); }, [selectedTaskName]); diff --git a/DashAI/front/src/components/generative/SessionBar.jsx b/DashAI/front/src/components/generative/SessionBar.jsx index 5ca9f864d..574109100 100644 --- a/DashAI/front/src/components/generative/SessionBar.jsx +++ b/DashAI/front/src/components/generative/SessionBar.jsx @@ -21,8 +21,6 @@ export default function SessionBar({ const [selectedInfoSession, setSelectedInfoSession] = useState(null); const [openSections, setOpenSections] = useState({}); - console.log(selectedSessionId); - useEffect(() => { // Initialize all sections as closed const taskNames = [ diff --git a/DashAI/front/src/components/generative/prompt.js b/DashAI/front/src/components/generative/prompt.js new file mode 100644 index 000000000..3e6ba658d --- /dev/null +++ b/DashAI/front/src/components/generative/prompt.js @@ -0,0 +1,954 @@ +Ayudame a hacer que este código funcione, llamando correctamente a las APIs y manteniendo el estilo definido. Puedes modificar y refactorizar todo lo necesario, pero tienes prohibido cambiar la estética de los componentes y el código de NewSessionModal (el resto sí puedes modificarlo) + +La idea es poder crear una sesión de rag del siguiente modo: + +1. Se cargan (desde el back) y muestran todas las sesiones disponibles + +2. Si se crea una nueva sesión, se abre un modal + +3. Se seleccionan los documentos + +4. Se configura el Retriever. Para ello: + +4.1. Se cargan desde el back los retriever disponibles + +4.2 El usuario selecciona un modelo + +4.3 Se muetran los parámetros por defecto del modelo + +4.4 Si el usuario desea puede modificar los parámetros + +4.5 Al hacer click en Next se guardan (con un post al backend) los parámetros del Retriever de la sesión + +5. Se configura el LLM + +//imports + +export default function Generative() { + const [stepIndex, setStepIndex] = useState(0); + const [selectedSessionId, setSelectedSessionId] = useState(null); + const [selectedTaskName, setSelectedTaskName] = useState(""); + const [sessions, setSessions] = useState([]); + const [paramsVersion, setParamsVersion] = useState(0); + + const isRAGTask = () => selectedTaskName === "RAGTask"; + + const handleSessionClick = (sessionId, taskName) => { + console.log("[handleSessionClick]", { sessionId, taskName }); + setSelectedTaskName(taskName); + setSelectedSessionId(sessionId); + }; + + const handleNewSessionButton = () => { + console.log("[handleNewSessionButton]"); + setSelectedSessionId(null); + setStepIndex(0); + setSelectedTaskName(""); + }; + + const onParamsUpdate = (newParams) => { + console.log("[onParamsUpdate]", newParams); + setParamsVersion((prev) => prev + 1); + }; + + useEffect(() => { + getSessions().then((data) => { + console.log("[getSessions]", data); + setSessions(data); + }); + }, []); + + const handleAddSession = (session) => { + console.log("[handleAddSession]", session); + setSessions((prevSessions) => [session, ...prevSessions]); + }; + + const handleSessionDelete = (id) => { + console.log("[handleSessionDelete]", id); + if (id === selectedSessionId) { + setSelectedSessionId(null); + setStepIndex(0); + setSelectedTaskName(""); + } + + setSessions((prevSessions) => + prevSessions.filter((session) => session.id !== id) + ); + + removeSession(id); + }; + + return ( + + + + + + + + {selectedSessionId ? ( + isRAGTask() ? ( + + ) : ( + + ) + ) : stepIndex === 0 ? ( + { + console.log("[SelectTaskMenu] task selected:", taskName); + setSelectedTaskName(taskName); + setStepIndex(1); + }} + /> + ) : isRAGTask() ? ( + + ) : ( + + ) + } + + + + {!isRAGTask() && ( + + + {!selectedSessionId ? + ( + + ): null} + + + ) + } + + ); +} +//imports + +const steps = [ + { + name: "select-documents", + label: "Select documents", + Component: DocumentSelectionStep, + }, + { + name: "configure-retriever", + label: "Configure retriever", + Component: RetrieverConfigurationStep, + }, + { + name: "configure-algorithm", + label: "Configure algorithm", + Component: AlgorithmConfigurationStep, + }, +]; + +const defaultNewSession = { + name: "", + task_name: "RAGTask", // Default task name + description: "", + RAGParameters: {}, + documents: [], +}; + +export default function NewSessionModal({ + open, + setOpen, + setUpdateTableFlag, + setSelectedSessionId, + handleAddSession, + selectedSession, +}) { + const theme = useTheme(); + const matches = useMediaQuery(theme.breakpoints.down("md")); + const screenSm = useMediaQuery(theme.breakpoints.down("sm")); + const { enqueueSnackbar } = useSnackbar(); + + const [activeStep, setActiveStep] = useState(0); + const [nextEnabled, setNextEnabled] = useState(false); + const [newSession, setNewSession] = useState( + selectedSession || defaultNewSession + ); + + const [stepCompleted, setStepCompleted] = useState([false, false, false]); + + const handleStepComplete = (stepIndex) => { + const newCompleted = [...stepCompleted]; + newCompleted[stepIndex] = true; + setStepCompleted(newCompleted); + }; + + // Initialize session data when modal opens or selectedSession changes + useEffect(() => { + if (open) { + if (selectedSession) { + // Edit mode - use existing session + setNewSession({ + ...selectedSession, + // Ensure documents array exists + documents: selectedSession.documents || [] + }); + } else { + // Create mode - use defaults + setNewSession(defaultNewSession); + } + setActiveStep(0); + setNextEnabled(false); + } + }, [open, selectedSession]); + + + const uploadNewSession = async () => { + try { + // For new sessions, exclude ID + const sessionData = selectedSession + ? newSession // Keep existing ID for updates + : { ...newSession, id: undefined }; // Remove ID for new sessions + + const response = selectedSession + ? await updateRAGSession(sessionData) // Implement update function if needed + : await createRAGSession(sessionData); + + const sessionId = response.id; + console.log("Session created/updated with ID:", sessionId); + + enqueueSnackbar( + `Session ${selectedSession ? "updated" : "created"} successfully!`, + { variant: "success" } + ); + setUpdateTableFlag(true); // Trigger table update + } catch (error) { + console.error("Session creation error:", error); + enqueueSnackbar( + `Failed to ${selectedSession ? "update" : "create"} session: ${error.message}`, + { variant: "error" } + ); + } + }; + + const handleCloseDialog = () => { + setActiveStep(0); + setOpen(false); + setNewSession(defaultNewSession); + setNextEnabled(false); + + }; + + const handleStepButton = (index) => () => { + setActiveStep(index); + }; + + const handleBackButton = () => { + if (activeStep === 0) { + handleCloseDialog(); + } else { + setActiveStep(activeStep - 1); + setNextEnabled(true); + } + }; + + const handleNextButton = () => { + if (activeStep === steps.length - 1) { + handleFinish(); + } else { + setActiveStep(activeStep + 1); + setNextEnabled(false); // Reset next enabled for new step + } + }; + + const handleFinish = async () => { + await uploadNewSession(); + handleCloseDialog(); + }; + + return ( + + + + + + + + + + + + + {selectedSession ? "Edit" : "Create New"} RAG Session + + + + + + + {steps.map((step, index) => ( + index} + disabled={activeStep < index}> + + {step.label} + + + ))} + + + + + + + {activeStep === 0 && ( + + )} + {activeStep === 1 && ( + + )} + {activeStep === 2 && ( + + )} + + + + + + + + + + ); +} + + +// imports +function RAGHomePage({ + selectedTaskName, + setSelectedSessionId, + handleAddSession + }) { + + ... + + return ( + + {showNewSessionModal? ( + + ):( + + ) + } + + ); +} + +export default RAGHomePage; + +// imports + +const steps = [ + { + name: "select-documents", + label: "Select documents", + Component: DocumentSelectionStep, + }, + { + name: "configure-retriever", + label: "Configure retriever", + Component: RetrieverConfigurationStep, + }, + { + name: "configure-algorithm", + label: "Configure algorithm", + Component: AlgorithmConfigurationStep, + }, +]; + +const defaultNewSession = { + name: "", + task_name: "RAGTask", // Default task name + description: "", + RAGParameters: {}, + documents: [], +}; + +... +export default function NewSessionModal({ + open, + setOpen, + setUpdateTableFlag, + setSelectedSessionId, + handleAddSession, + selectedSession, +}) { + const theme = useTheme(); + const matches = useMediaQuery(theme.breakpoints.down("md")); + const screenSm = useMediaQuery(theme.breakpoints.down("sm")); + const { enqueueSnackbar } = useSnackbar(); + + const [activeStep, setActiveStep] = useState(0); + const [nextEnabled, setNextEnabled] = useState(false); + const [newSession, setNewSession] = useState( + selectedSession || defaultNewSession + ); + + const [stepCompleted, setStepCompleted] = useState([false, false, false]); + + const handleStepComplete = (stepIndex) => { + const newCompleted = [...stepCompleted]; + newCompleted[stepIndex] = true; + setStepCompleted(newCompleted); + }; + + // Initialize session data when modal opens or selectedSession changes + useEffect(() => { + if (open) { + if (selectedSession) { + // Edit mode - use existing session + setNewSession({ + ...selectedSession, + // Ensure documents array exists + documents: selectedSession.documents || [] + }); + } else { + // Create mode - use defaults + setNewSession(defaultNewSession); + } + setActiveStep(0); + setNextEnabled(false); + } + }, [open, selectedSession]); + + + const uploadNewSession = async () => { + try { + // For new sessions, exclude ID + const sessionData = selectedSession + ? newSession // Keep existing ID for updates + : { ...newSession, id: undefined }; // Remove ID for new sessions + + const response = selectedSession + ? await updateRAGSession(sessionData) // Implement update function if needed + : await createRAGSession(sessionData); + + const sessionId = response.id; + console.log("Session created/updated with ID:", sessionId); + + enqueueSnackbar( + `Session ${selectedSession ? "updated" : "created"} successfully!`, + { variant: "success" } + ); + setUpdateTableFlag(true); // Trigger table update + } catch (error) { + console.error("Session creation error:", error); + enqueueSnackbar( + `Failed to ${selectedSession ? "update" : "create"} session: ${error.message}`, + { variant: "error" } + ); + } + }; + + const handleCloseDialog = () => { + setActiveStep(0); + setOpen(false); + setNewSession(defaultNewSession); + setNextEnabled(false); + + }; + + const handleStepButton = (index) => () => { + setActiveStep(index); + }; + + const handleBackButton = () => { + if (activeStep === 0) { + handleCloseDialog(); + } else { + setActiveStep(activeStep - 1); + setNextEnabled(true); + } + }; + + const handleNextButton = () => { + if (activeStep === steps.length - 1) { + handleFinish(); + } else { + setActiveStep(activeStep + 1); + setNextEnabled(false); // Reset next enabled for new step + } + }; + + const handleFinish = async () => { + await uploadNewSession(); + handleCloseDialog(); + }; + + return ( + + + + + + + + + + + + + {selectedSession ? "Edit" : "Create New"} RAG Session + + + + + + + {steps.map((step, index) => ( + index} + disabled={activeStep < index}> + + {step.label} + + + ))} + + + + + + + {activeStep === 0 && ( + + )} + {activeStep === 1 && ( + + )} + {activeStep === 2 && ( + + )} + + + + + + + + + + ); +} + +// imports +function RetrieverConfigurationStep({ newSession, setNewSession, setNextEnabled }) { + const handleConfigurationChange = (retrieverConfig) => { + setNewSession(prev => ({ + ...prev, + RAGParameters: { + ...prev.RAGParameters, + retrieval: retrieverConfig + } + })); + }; + console.log("Retriever initial values:", newSession.RAGParameters?.retrieval); + console.log("New session state:", newSession); + + return ( + + + + ); +} + +RetrieverConfigurationStep.propTypes = { + newSession: PropTypes.object.isRequired, + setNewSession: PropTypes.func.isRequired, + setNextEnabled: PropTypes.func.isRequired, +}; + +export default RetrieverConfigurationStep; + +// imports + +import { getRelatedComponents } from "../../../api/generativeTask"; +function ComponentSelector({ + componentType, + fetchComponents, + initialValues, + onConfigurationChange, + setNextEnabled +}) { + const [components, setComponents] = useState([]); + const [selectedComponent, setSelectedComponent] = useState(null); + const [loading, setLoading] = useState(true); + const [validationSchema, setValidationSchema] = useState(null); + + // Fetch available components + useEffect(() => { + const getComponents = async () => { + setLoading(true); + try { + const data = await fetchComponents(); + setComponents(data); + + // If we have initialValues with a model_name, select that component + if (initialValues?.model_name) { + const preselectedComponent = data.find(c => c.name === initialValues.model_name); + if (preselectedComponent) { + setSelectedComponent(preselectedComponent); + } + } else { + console.warn(`No initial model_name provided for ${componentType} selection.`); + } + } catch (error) { + console.error(`Error fetching ${componentType} components:`, error); + } finally { + setLoading(false); + } + }; + + getComponents(); + }, [componentType, fetchComponents]); + + // Set up form validation schema when component changes + useEffect(() => { + if (selectedComponent?.schema?.properties) { + const processedProps = preprocessSchema(selectedComponent.schema.properties); + setValidationSchema(buildYupSchema(processedProps)); + console.log("Processed properties for form:", processedProps); + // Merge any existing values with defaults from schema + const schemaDefaults = Object.keys(processedProps).reduce( + (acc, key) => { + acc[key] = processedProps[key].placeholder || ""; + console.log(`Setting default for ${key}:`, acc[key]); + return acc; + }, + { name: "", description: ""}); + + // Preserve any values that were already set + const mergedValues = { + ...schemaDefaults, + ...(initialValues?.parameters || {}) + }; + + formik.setValues(mergedValues); + } + }, [selectedComponent]); + + const formik = useFormik({ + initialValues: initialValues?.parameters || {}, + validationSchema, + enableReinitialize: true, + onSubmit: (values) => { + onConfigurationChange({ + model_name: selectedComponent.name, + parameters: values + }); + } + }); + + // Enable/disable next button based on form validity and selection + useEffect(() => { + if (selectedComponent && formik.isValid) { + setNextEnabled(true); + + // Auto-submit valid values as they change + if (formik.dirty) { + onConfigurationChange({ + model_name: selectedComponent.name, + parameters: formik.values + }); + } + } else { + setNextEnabled(false); + } + }, [selectedComponent, formik.values, formik.isValid, formik.dirty]); + + // Process schema properties for the form renderer + const processedProperties = selectedComponent?.schema?.properties + ? preprocessSchema(selectedComponent.schema.properties) + : {}; + + return ( + + + Select {componentType} + + + {loading ? ( + + + + ) : ( + <> + c.name)} + value={selectedComponent?.name || null} + onChange={(_, newValue) => { + const selected = components.find(c => c.name === newValue); + setSelectedComponent(selected); + }} + renderInput={(params) => ( + + )} + sx={{ mb: 4 }} + /> + + {selectedComponent && ( +
+ + {selectedComponent.name} Configuration + + + { + formik.setValues({...formik.values, ...updatedValues}); + }} + onFormSubmit={formik.handleSubmit} + setError={(error) => console.error(error)} + errorsMessage={formik.errors} + /> + + )} + + )} +
+ ); +} + +ComponentSelector.propTypes = { + componentType: PropTypes.string.isRequired, + fetchComponents: PropTypes.func.isRequired, + initialValues: PropTypes.object, + onConfigurationChange: PropTypes.func.isRequired, + setNextEnabled: PropTypes.func.isRequired +}; + +export default ComponentSelector; + +//RAG api +import api from "./api"; +import { ISession } from "../types/session"; +import { IGenerativeTask } from "../types/generativeTask"; + + +// Fetch all RAG sessions +export const getRAGSessions = async (): Promise => { + console.log("Fetching all RAG sessions"); + + const response = await api.get("/v1/generative-session/"); + if (response.status !== 200) { + throw new Error(`Failed to fetch RAG sessions: ${response.statusText}`); + } + + console.log("RAG sessions fetched successfully:", response.data); + return response.data; +} + +export const getRAGSession = async (sessionId: number): Promise => { + console.log(`Fetching RAG session with ID: ${sessionId}`); + + const response = await api.get(`/v1/generative-session/${sessionId}`); + if (response.status !== 200) { + throw new Error(`Failed to fetch RAG session: ${response.statusText}`); + } + + console.log("RAG session fetched successfully:", response.data); + return response.data; +} + +export const createRAGSession = async (sessionData: Omit): Promise => { + console.log("Creating new RAG session with data:", sessionData); + + const response = await api.post("/v1/generative-session/", sessionData); + if (response.status !== 201) { + throw new Error(`Failed to create RAG session: ${response.statusText}`); + } + + console.log("RAG session created successfully:", response.data); + return response.data; +} + +export const updateGenerativeSessionParams = async ( + sessionId: number, + newParams: Record, +): Promise => { + console.log(`Updating parameters for RAG session ID: ${sessionId} with data: + ${JSON.stringify(newParams)}`); + + const response = await api.put( + `/v1/generative-session/${sessionId}/parameters`, + newParams, + ); + if (response.status !== 200) { + throw new Error(`Failed to update RAG session parameters: ${response.statusText}`); + } + console.log("RAG session parameters updated successfully:", response.data); + return response.data; +} + +export const getRAGComponents = async (): Promise => { + // Simulate fetching RAG components based on type + + const response = await api.get( + `/v1/component/?related_component=RAGTask` + ); + + if (response.status !== 200) { + throw new Error(`Failed to fetch RAG components: ${response.statusText}`); + } + + return response.data; +}; + +export const getRetrieverComponents = async (): Promise => { + const response = await api.get( + `/v1/component/?selectTypes=RetrieverModel` + ); + + if (response.status !== 200) { + throw new Error(`Failed to fetch retriever components: ${response.statusText}`); + } + + return response.data; + +} + +export const getGeneratorComponents = async (): Promise => { + + const response = await api.get( + `/v1/component/?related_component=GenerativeModel` + ); + + if (response.status !== 200) { + throw new Error(`Failed to fetch generator components: ${response.statusText}`); + } + + return response.data; + +} \ No newline at end of file diff --git a/DashAI/front/src/pages/generative/Generative.jsx b/DashAI/front/src/pages/generative/Generative.jsx index 8568d46a1..bb424bdf0 100644 --- a/DashAI/front/src/pages/generative/Generative.jsx +++ b/DashAI/front/src/pages/generative/Generative.jsx @@ -21,37 +21,31 @@ export default function Generative() { const isRAGTask = () => selectedTaskName === "RAGTask"; const handleSessionClick = (sessionId, taskName) => { - console.log("[handleSessionClick]", { sessionId, taskName }); setSelectedTaskName(taskName); setSelectedSessionId(sessionId); }; const handleNewSessionButton = () => { - console.log("[handleNewSessionButton]"); setSelectedSessionId(null); setStepIndex(0); setSelectedTaskName(""); }; const onParamsUpdate = (newParams) => { - console.log("[onParamsUpdate]", newParams); setParamsVersion((prev) => prev + 1); }; useEffect(() => { getSessions().then((data) => { - console.log("[getSessions]", data); setSessions(data); }); }, []); const handleAddSession = (session) => { - console.log("[handleAddSession]", session); setSessions((prevSessions) => [session, ...prevSessions]); }; const handleSessionDelete = (id) => { - console.log("[handleSessionDelete]", id); if (id === selectedSessionId) { setSelectedSessionId(null); setStepIndex(0); @@ -81,32 +75,22 @@ export default function Generative() { {selectedSessionId ? ( - isRAGTask() ? ( - ) : ( - - ) - ) : stepIndex === 0 ? ( + ) : stepIndex === 0 ? ( { - console.log("[SelectTaskMenu] task selected:", taskName); setSelectedTaskName(taskName); setStepIndex(1); }} /> ) : isRAGTask() ? ( ) : ( - ) - } + )} diff --git a/DashAI/front/src/pages/generative/RAG/DocumentSelectionStep.jsx b/DashAI/front/src/pages/generative/RAG/DocumentSelectionStep.jsx index 4b7321461..3ad1d7afa 100644 --- a/DashAI/front/src/pages/generative/RAG/DocumentSelectionStep.jsx +++ b/DashAI/front/src/pages/generative/RAG/DocumentSelectionStep.jsx @@ -1,94 +1,105 @@ -import React, { useState, useEffect } from "react"; +import React, { useState, useEffect, useCallback } from "react"; import PropTypes from "prop-types"; -import { Box, CircularProgress } from "@mui/material"; -import DocumentSelector from "../../../components/generative/RAG/DocumentSelector"; -import SessionMetadata from "../../../components/generative/RAG/SessionMetadata"; +import { Box, Typography } from "@mui/material"; +import DocumentSelector from "../../../components/generative/RAG/DocumentSelector"; // Adjust the import path as needed -function DocumentSelectionStep({ newSession, setNewSession, setNextEnabled }) { - const [documents, setDocuments] = useState([]); - const [loading, setLoading] = useState(true); - // Fetch available documents on component mount + + + + +// Helper function to convert document paths to UI-friendly objects +const createDocumentObjectFromPath = (path) => ({ + id: path, + name: path.split('/').pop() || path, // Use filename as name, fallback to full path + updatedAt: new Date().toISOString(), // Initial timestamp for new paths +}); + +export default function DocumentSelectionStep({ documents, setDocuments, setNextEnabled }) { + // Initialize localDocumentObjects and selectedObjectIds once from the 'documents' prop. + // This runs only on the initial mount. + const [localDocumentObjects, setLocalDocumentObjects] = useState(() => { + const initialLocalDocs = documents.map(createDocumentObjectFromPath); + const initialSelectedIds = documents; // Paths are directly the IDs + return initialLocalDocs; + }); + + const [selectedObjectIds, setSelectedObjectIds] = useState(() => { + return documents; // Paths are directly the IDs + }); + + // Effect 1: Sync selectedObjectIds (paths) back to the parent component + // This effect ensures the parent's 'documents' prop is updated when local selection changes. + useEffect(() => { + // Only update parent if there's a change to prevent infinite loops and unnecessary re-renders + if (JSON.stringify(selectedObjectIds) !== JSON.stringify(documents)) { + setDocuments(selectedObjectIds); // selectedObjectIds already contains the paths + } + }, [selectedObjectIds, setDocuments, documents]); // Dependencies: local selected IDs, and parent's setter/prop for comparison + + // Effect 2: Notify parent about step validity + // This effect ensures the 'Next' button's enabled state is correct. useEffect(() => { - const fetchDocuments = async () => { - setLoading(true); - try { - // Replace this with your actual API call to get documents - // For now using a mock response with delay - await new Promise(resolve => setTimeout(resolve, 500)); - const data = [ - { id: 1, name: "Product Documentation.pdf", type: "PDF", size: "1.2 MB", updatedAt: "2025-05-15" }, - { id: 2, name: "User Manual.docx", type: "DOCX", size: "3.4 MB", updatedAt: "2025-05-20" }, - { id: 3, name: "API Reference.pdf", type: "PDF", size: "2.1 MB", updatedAt: "2025-06-01" }, - { id: 4, name: "Technical Specifications.txt", type: "TXT", size: "4.7 MB", updatedAt: "2025-06-10" }, - { id: 5, name: "Troubleshooting Guide.pdf", type: "PDF", size: "1.8 MB", updatedAt: "2025-06-15" } - ]; - setDocuments(data); - } catch (error) { - console.error("Failed to fetch documents:", error); - } finally { - setLoading(false); + const isValid = selectedObjectIds && selectedObjectIds.length > 0; + setNextEnabled(isValid); + }, [selectedObjectIds, setNextEnabled]); // Dependencies: local selected IDs, and parent's setter + + // Handler for when DocumentSelector's selection changes (checkboxes) + const handleDocumentSelectionChange = useCallback((selectedDocs) => { + // Extract 'id' (which is the path) from the selected document objects + const newSelectedIds = selectedDocs.map(doc => doc.id); + setSelectedObjectIds(newSelectedIds); + }, []); + + // Handler for when DocumentSelector adds a new document (e.g., from Upload component) + const handleAddDocumentObject = useCallback((newDoc) => { + setLocalDocumentObjects(prev => { + // Ensure no duplicates based on ID (path) before adding + if (!prev.some(doc => doc.id === newDoc.id)) { + const updatedDocs = [...prev, newDoc]; + // Also ensure it's selected in the UI + setSelectedObjectIds(currentSelected => { + if (!currentSelected.includes(newDoc.id)) { + return [...currentSelected, newDoc.id]; + } + return currentSelected; + }); + return updatedDocs; } - }; + return prev; + }); + }, []); - fetchDocuments(); + // Handler for when DocumentSelector removes a document + const handleRemoveDocumentObject = useCallback((docId) => { + setLocalDocumentObjects(prev => prev.filter(doc => doc.id !== docId)); + setSelectedObjectIds(prev => prev.filter(id => id !== docId)); }, []); - // Update next button state whenever documents or session name changes - useEffect(() => { - const hasDocuments = newSession.documents && newSession.documents.length > 0; - const hasName = Boolean(newSession.name); - setNextEnabled(hasDocuments && hasName); - }, [newSession.documents, newSession.name, setNextEnabled]); - - const handleSessionMetadataUpdate = (metadata) => { - setNewSession(prev => ({ - ...prev, - name: metadata.name, - description: metadata.description - })); - }; - - const handleDocumentsSelect = (selectedDocuments) => { - setNewSession(prev => ({ - ...prev, - documents: selectedDocuments - })); - }; return ( - - - - {loading ? ( - - - - ) : ( + + Select Documents + + Upload new documents or select from existing ones to be used for RAG. + + + {/* Integrate the DocumentSelector component */} + {/* Allow DocumentSelector to take available height */} - )} + ); } DocumentSelectionStep.propTypes = { - newSession: PropTypes.object.isRequired, - setNewSession: PropTypes.func.isRequired, + documents: PropTypes.arrayOf(PropTypes.string).isRequired, + setDocuments: PropTypes.func.isRequired, setNextEnabled: PropTypes.func.isRequired, }; - -export default DocumentSelectionStep; \ No newline at end of file diff --git a/DashAI/front/src/pages/generative/RAG/GeneratorConfigurationStep.jsx b/DashAI/front/src/pages/generative/RAG/GeneratorConfigurationStep.jsx new file mode 100644 index 000000000..0af5a14c7 --- /dev/null +++ b/DashAI/front/src/pages/generative/RAG/GeneratorConfigurationStep.jsx @@ -0,0 +1,171 @@ +import { useState, useEffect, useCallback } from "react"; +import PropTypes from "prop-types"; +import { Box, Autocomplete, TextField, Typography, Button } from "@mui/material"; +import { useFormik } from "formik"; +import FormSchemaRenderFields from "../../../components/shared/FormSchemaRenderFields"; +import { getGeneratorComponents } from "../../../api/rag"; +import { preprocessSchema, buildYupSchema } from "../../../components/generative/utils" + + +export default function GeneratorConfigurationStep({ generatorModel, setGeneratorModel, setNextEnabled }) { + const [generators, setGenerators] = useState([]); + const [currentSelectedGeneratorOption, setCurrentSelectedGeneratorOption] = useState(null); + const [validationSchema, setValidationSchema] = useState(null); + + const getInitialParamsFromSchema = useCallback((schemaProperties) => { + if (!schemaProperties) return {}; + return Object.keys(schemaProperties).reduce((acc, key) => { + acc[key] = schemaProperties[key].placeholder !== undefined + ? schemaProperties[key].placeholder + : ""; + return acc; + }, {}); + }, []); + + + useEffect(() => { + const loadAndSetGenerator = async () => { + const data = await getGeneratorComponents(); + setGenerators(data); + + if (generatorModel?.name) { + const existingGenerator = data.find(r => r.name === generatorModel.name); + if (existingGenerator) { + setCurrentSelectedGeneratorOption(existingGenerator); + } + } + }; + loadAndSetGenerator(); + }, [generatorModel?.name]); + + const formik = useFormik({ + initialValues: generatorModel?.parameters || {}, + validationSchema: validationSchema, + enableReinitialize: true, + onSubmit: (values) => { + }, + }); + + useEffect(() => { + + const generatorSchemaProperties = currentSelectedGeneratorOption?.schema?.properties; + + if (generatorSchemaProperties) { + const processedProps = preprocessSchema(generatorSchemaProperties); + setValidationSchema(buildYupSchema(processedProps)); + + const initialFormValues = Object.keys(processedProps).reduce( + (acc, key) => { + acc[key] = generatorModel?.parameters?.[key] !== undefined + ? generatorModel.parameters[key] + : (processedProps[key].placeholder !== undefined + ? processedProps[key].placeholder + : ""); + return acc; + }, + {}, + ); + formik.setValues(initialFormValues); + } else { + setValidationSchema(null); + formik.setValues({}); + } + }, [currentSelectedGeneratorOption, generatorModel?.parameters]); + + useEffect(() => { + const isValid = !!currentSelectedGeneratorOption && formik.isValid; + setNextEnabled(isValid); + }, [currentSelectedGeneratorOption, formik.isValid, setNextEnabled]); + + const handleGeneratorSelectionChange = (event, newValue) => { + setCurrentSelectedGeneratorOption(newValue); + + if (newValue) { + const initialParameters = getInitialParamsFromSchema(newValue.schema?.properties); + setGeneratorModel({ + name: newValue.name, + parameters: initialParameters, + }); + } else { + setGeneratorModel({ name: "", parameters: {} }); + } + }; + + const handleParametersChange = (updatedValues) => { + formik.setValues((prevValues) => ({ + ...prevValues, + ...updatedValues, + })); + + setGeneratorModel({ + name: currentSelectedGeneratorOption.name, + parameters: { + ...formik.values, + ...updatedValues, + }, + }); + }; + + const processedProperties = currentSelectedGeneratorOption?.schema?.properties + ? preprocessSchema(currentSelectedGeneratorOption.schema.properties) + : {}; + + return ( + + + Configure Generator Model (LLM) + + + option.name} + value={currentSelectedGeneratorOption} + onChange={handleGeneratorSelectionChange} + isOptionEqualToValue={(option, value) => option.name === value?.name} + renderInput={(params) => } + sx={{ mb: 3 }} + /> + + {currentSelectedGeneratorOption && currentSelectedGeneratorOption.schema && ( +
+ + + Parameters + + console.error("FormSchemaRenderFields Error:", error)} + errorsMessage={formik.errors} + /> + +
+ )} +
+ ); +} diff --git a/DashAI/front/src/pages/generative/RAG/NewSessionModal.jsx b/DashAI/front/src/pages/generative/RAG/NewSessionModal.jsx index 8537b3fbf..cf14db042 100644 --- a/DashAI/front/src/pages/generative/RAG/NewSessionModal.jsx +++ b/DashAI/front/src/pages/generative/RAG/NewSessionModal.jsx @@ -1,7 +1,6 @@ -import React, { useState, useEffect } from "react"; +import React, { useState, useEffect, useCallback } from "react"; import { Button, - ButtonGroup, Dialog, DialogActions, DialogTitle, @@ -16,156 +15,154 @@ import { import CloseIcon from "@mui/icons-material/Close"; import { useTheme } from "@mui/material/styles"; import useMediaQuery from "@mui/material/useMediaQuery"; -import { useSnackbar } from "notistack"; import DocumentSelectionStep from "./DocumentSelectionStep"; import RetrieverConfigurationStep from "./RetrieverConfigurationStep"; -import AlgorithmConfigurationStep from "./AlgorithmConfigurationStep"; -import { createRAGSession, updateRAGSession } from "../../../api/rag"; +import GeneratorConfigurationStep from "./GeneratorConfigurationStep"; const steps = [ { name: "select-documents", label: "Select documents", - Component: DocumentSelectionStep, + component: DocumentSelectionStep, }, { name: "configure-retriever", label: "Configure retriever", - Component: RetrieverConfigurationStep, + component: RetrieverConfigurationStep, }, { - name: "configure-algorithm", - label: "Configure algorithm", - Component: AlgorithmConfigurationStep, + name: "configure-generator", + label: "Configure Language Model", + component: GeneratorConfigurationStep, }, ]; const defaultNewSession = { name: "", - task_name: "RAGTask", // Default task name + task_name: "RAGTask", description: "", - RAGParameters: {}, - documents: [], + displayName: "", + parameters: { + "documents": [], + "retriever_model": { + "name": "", + "parameters": {}, + }, + "generator_model": { + "name": "", + "parameters": {}, + }, + }, }; export default function NewSessionModal({ open, - setOpen, - setUpdateTableFlag, - setSelectedSessionId, - handleAddSession, - selectedSession, + onClose, + onSessionSaved, + onSessionSelect, + session }) { const theme = useTheme(); - const matches = useMediaQuery(theme.breakpoints.down("md")); const screenSm = useMediaQuery(theme.breakpoints.down("sm")); - const { enqueueSnackbar } = useSnackbar(); - const [activeStep, setActiveStep] = useState(0); - const [nextEnabled, setNextEnabled] = useState(false); - const [newSession, setNewSession] = useState( - selectedSession || defaultNewSession - ); + const [sessionData, setSessionData] = useState(session || defaultNewSession); + const [stepValidity, setStepValidity] = useState(new Array(steps.length).fill(false)); - const [stepCompleted, setStepCompleted] = useState([false, false, false]); - - const handleStepComplete = (stepIndex) => { - const newCompleted = [...stepCompleted]; - newCompleted[stepIndex] = true; - setStepCompleted(newCompleted); - }; - // Initialize session data when modal opens or selectedSession changes useEffect(() => { if (open) { - if (selectedSession) { - // Edit mode - use existing session - setNewSession({ - ...selectedSession, - // Ensure documents array exists - documents: selectedSession.documents || [] - }); + setActiveStep(0); + if(session) { + const sessionParameters = session.parameters || {}; + const sessionRetrieverModel = sessionParameters.retriever_model || {}; + const sessionGeneratorModel = sessionParameters.generator_model || {}; + setSessionData({ + id: session.id, + name: session.name || "", + task_name: session.task_name || "RAGTask", + description: session.description || "", + displayName: session.displayName || "", + parameters: { + documents: sessionParameters.documents || [], + retriever_model: { + class: sessionRetrieverModel.class || "", + name: sessionRetrieverModel.name || "", + parameters: sessionRetrieverModel.parameters || {}, + }, + generator_model: { + class: sessionGeneratorModel.class || "", + name: sessionGeneratorModel.name || "", + parameters: sessionGeneratorModel.parameters || {}, + }, + }, + }) } else { - // Create mode - use defaults - setNewSession(defaultNewSession); + setSessionData(defaultNewSession); } - setActiveStep(0); - setNextEnabled(false); + setStepValidity(new Array(steps.length).fill(false)); } - }, [open, selectedSession]); + }, [open, session]); + const handleStepValidation = useCallback((stepIndex, isValid) => { + setStepValidity(prev => { + const newValidity = [...prev]; + newValidity[stepIndex] = isValid; + return newValidity; + }); + }, []) - const uploadNewSession = async () => { - try { - // For new sessions, exclude ID - const sessionData = selectedSession - ? newSession // Keep existing ID for updates - : { ...newSession, id: undefined }; // Remove ID for new sessions - - const response = selectedSession - ? await updateRAGSession(sessionData) // Implement update function if needed - : await createRAGSession(sessionData); - - const sessionId = response.id; - console.log("Session created/updated with ID:", sessionId); - - enqueueSnackbar( - `Session ${selectedSession ? "updated" : "created"} successfully!`, - { variant: "success" } - ); - setUpdateTableFlag(true); // Trigger table update - } catch (error) { - console.error("Session creation error:", error); - enqueueSnackbar( - `Failed to ${selectedSession ? "update" : "create"} session: ${error.message}`, - { variant: "error" } - ); + const isNextOrFinishEnabled = () => { + if (!stepValidity[activeStep]) { + return false; + } + if (activeStep === steps.length - 1) { + return stepValidity.every(isValid => isValid); } + return true; }; - const handleCloseDialog = () => { - setActiveStep(0); - setOpen(false); - setNewSession(defaultNewSession); - setNextEnabled(false); + const handleFinish = async () => { + if (!stepValidity.every(isValid => isValid)) { + return; + } - }; + try { + // Ensure generator_model is included in the final session data + const finalSessionData = { + ...sessionData, + parameters: { + ...sessionData.parameters, + generator_model: sessionData.parameters.generator_model || { + name: "", + parameters: {}, + }, + retriever_model: sessionData.parameters.retriever_model || { + name: "", + parameters: {}, + }, + }, + }; - const handleStepButton = (index) => () => { - setActiveStep(index); - }; + const savedSession = await onSessionSaved(finalSessionData); - const handleBackButton = () => { - if (activeStep === 0) { - handleCloseDialog(); - } else { - setActiveStep(activeStep - 1); - setNextEnabled(true); - } - }; - const handleNextButton = () => { - if (activeStep === steps.length - 1) { - handleFinish(); - } else { - setActiveStep(activeStep + 1); - setNextEnabled(false); // Reset next enabled for new step + if (onSessionSelect) { + onSessionSelect(savedSession.id); + } + onClose(); + } catch (error) { + console.error("NewSessionModal: Error saving session:", error); } }; - const handleFinish = async () => { - await uploadNewSession(); - handleCloseDialog(); - }; - return ( @@ -177,7 +174,7 @@ export default function NewSessionModal({ @@ -185,7 +182,7 @@ export default function NewSessionModal({ - {selectedSession ? "Edit" : "Create New"} RAG Session + {session ? "Edit" : "Create New"} RAG Session @@ -193,11 +190,11 @@ export default function NewSessionModal({ {steps.map((step, index) => ( - index} + index} disabled={activeStep < index}> - + setActiveStep(index)}> {step.label} @@ -206,47 +203,56 @@ export default function NewSessionModal({ - + {activeStep === 0 && ( setSessionData(prev => ({ + ...prev, + parameters: { ...prev.parameters, documents: docs } + })) + } + setNextEnabled={(isValid) => handleStepValidation(0, isValid)} /> )} {activeStep === 1 && ( setSessionData(prev => ({ + ...prev, + parameters: { ...prev.parameters, retriever_model: model } + }))} + setNextEnabled={(isValid) => handleStepValidation(1, isValid)} /> )} {activeStep === 2 && ( - setSessionData(prev => ({ + ...prev, + parameters: { ...prev.parameters, generator_model: model } + }))} + setNextEnabled={(isValid) => handleStepValidation(2, isValid)} /> )} - - - - + + ); -} +} \ No newline at end of file diff --git a/DashAI/front/src/pages/generative/RAG/RAGHomePage.jsx b/DashAI/front/src/pages/generative/RAG/RAGHomePage.jsx index 26107a1f6..292824418 100644 --- a/DashAI/front/src/pages/generative/RAG/RAGHomePage.jsx +++ b/DashAI/front/src/pages/generative/RAG/RAGHomePage.jsx @@ -1,55 +1,108 @@ -import React from "react"; +import React, { useState, useEffect } from 'react'; +import { Box, Button, CircularProgress, Typography } from '@mui/material'; +import CustomLayout from '../../../components/custom/CustomLayout'; +import NewSessionModal from './NewSessionModal'; +import RAGSessionsTable from './RAGSessionsTable'; +import { getRAGSessions, createRAGSession } from '../../../api/rag'; -import NewSessionModal from "./NewSessionModal"; -import RAGSessionsTable from "./RAGSessionsTable.jsx"; +function RAGHomePage({ onSessionCreated, onSessionSelect }) { + const [showModal, setShowModal] = useState(false); + const [sessions, setSessions] = useState([]); + const [loading, setLoading] = useState(true); + const [editingSession, setEditingSession] = useState(null); -import CustomLayout from "../../../components/custom/CustomLayout.jsx"; + const loadSessions = async () => { + setLoading(true); // Set loading to true when fetching + try { + const data = await getRAGSessions(); + setSessions(data); + console.log("RAGHomePage: Sessions loaded:", data); + } catch (error) { + console.error("RAGHomePage: Error loading RAG sessions:", error); + } finally { + setLoading(false); // Set loading to false after fetch + console.log("RAGHomePage: Loading finished."); + } + }; -function RAGHomePage({ - handleAddSession, - selectedTaskName, - setSelectedSessionId - }) { - const [showNewSessionModal, setShowNewSessionModal] = React.useState(false); - const [updateTableFlag, setUpdateTableFlag] = React.useState(false); - const [selectedSession, setSelectedSession] = React.useState(null); + // Cargar sesiones al iniciar + useEffect(() => { + console.log("RAGHomePage: useEffect - Initial session load..."); + loadSessions(); + }, []); // Empty dependency array means this runs once on mount - const handleOpenNewSessionModal = () => { - setSelectedSession(null); - setShowNewSessionModal(true); - } + const handleOpenNewSessionModal = (session = null) => { + console.log("RAGHomePage: handleOpenNewSessionModal called."); + setEditingSession(session); // Set the session to edit + setShowModal(true); // Open the modal + console.log("RAGHomePage: showModal set to true."); + }; + + const handleCreateOrUpdateSession = async (sessionData) => { + console.log("RAGHomePage: handleCreateOrUpdateSession called with data:", sessionData); + try { + const savedSession = await createRAGSession(sessionData); + console.log("RAGHomePage: New/Updated RAG session saved:", savedSession); - const handleSessionSelect = (session) => { - setSelectedSession(session); - setShowNewSessionModal(true); - setSelectedSessionId(session.id); + // Refresh the sessions list after creation/update + await loadSessions(); // Call loadSessions to get the latest data + + onSessionCreated(savedSession); // Notify parent component (Generative.jsx) + setShowModal(false); // Close the modal + console.log("RAGHomePage: Modal closed after session save."); + return savedSession; + } catch (error) { + console.error("RAGHomePage: Error creating/updating session:", error); + throw error; // Re-throw to handle in the modal if needed } + }; + + console.log("RAGHomePage: Render. Current showModal state:", showModal); - return ( - handleOpenNewSessionModal()} + sx={{ textTransform: 'none' }} > - {showNewSessionModal? ( - - ):( - - ) - } - - ); + New Session + + } + > + {/* Modal para nueva sesión */} + { + setShowModal(false); + setEditingSession(null); // Clear editing session when closing + console.log("RAGHomePage: Modal onClose called. showModal set to false."); + }} + onSessionSaved={handleCreateOrUpdateSession} + onSessionSelect={onSessionSelect} + session={editingSession} + /> + + {/* Contenido principal */} + {loading ? ( + + + + ) : ( + handleOpenNewSessionModal(session)} + onSelect={onSessionSelect} + onRefreshSessions={loadSessions} // Pass the refresh function + onOpenNewSessionModal={() => handleOpenNewSessionModal()} // Pass function to open modal + /> + )} + + ); } export default RAGHomePage; \ No newline at end of file diff --git a/DashAI/front/src/pages/generative/RAG/RAGSessionsTable.jsx b/DashAI/front/src/pages/generative/RAG/RAGSessionsTable.jsx index 560ae5f28..35d5ff01a 100644 --- a/DashAI/front/src/pages/generative/RAG/RAGSessionsTable.jsx +++ b/DashAI/front/src/pages/generative/RAG/RAGSessionsTable.jsx @@ -1,175 +1,173 @@ - -import React from "react"; +import React, { useState } from "react"; import PropTypes from "prop-types"; import { AddCircleOutline as AddIcon, Update as UpdateIcon, + DeleteOutline as DeleteIcon, + Visibility as ViewDocsIcon } from "@mui/icons-material"; -import { DataGrid, GridToolbar } from "@mui/x-data-grid"; -import { Button, Grid, Paper, Typography, LinearProgress } from "@mui/material"; -import { useSnackbar } from "notistack"; - -import { getRAGSessions, deleteRAGSession } from "../../../api/rag"; // Adjust the import path as necessary +import { DataGrid } from "@mui/x-data-grid"; // Removed GridToolbar as it's not strictly essential for basic rendering +import { + Button, + Grid, + Paper, + Typography, + LinearProgress, +} from "@mui/material"; -function RAGSessionsTable({ - handleOpenNewSessionModal, - onSessionSelect, - updateTableFlag, - setUpdateTableFlag, -}) { - console.log("RAGSessionsTable rendered"); - const [loading, setLoading] = React.useState(true); - const [sessions, setSessions] = React.useState([]); - const { enqueueSnackbar } = useSnackbar(); - - const getSessions = async () => { - setLoading(true); - try { - const data = await getRAGSessions(); - setSessions(data); - } catch (error) { - console.error("[getSessions] error:", error); - enqueueSnackbar("Error fetching RAG sessions", { variant: "error" }); - } finally { - setLoading(false); - } - }; +import { deleteRAGSession } from "../../../api/rag"; // Assuming this API call is correct - const handleDeleteSession = async (sessionId) => { - try { - await deleteRAGSession(sessionId); - enqueueSnackbar("RAG session successfully deleted.", { - variant: "success" - }); - getSessions(); // Refresh sessions after deletion - } catch (error) { - console.error("[deleteSession] error:", error); - enqueueSnackbar("Error deleting RAG session", { variant: "error" }); - } - }; +// Removed ConfirmDialog component as requested. +// Removed useSnackbar import and usage. - const handleOpenSession = (session) => { - if (onSessionSelect) { - onSessionSelect(session); - } - }; +export default function RAGSessionsTable({ + sessions, + onSelect, + onEdit, + // Removed onRefreshSessions prop as it's not needed in this simplified version + onOpenNewSessionModal +}) { + // Removed local 'loading' state for operations within the table, + // as the parent RAGHomePage handles the main loading. + // Removed showConfirmDelete and sessionToDelete states. - const handleViewDocuments = (session) => { - console.log("View documents for session:", session.id); - }; - // FIXED: Moved useEffect to top level - React.useEffect(() => { - console.log("Initial load effect"); - getSessions(); - }, []); + // Removed handleDeleteSession function as its logic involved removed features. + // The delete button will now just call the API directly (or a simplified parent handler). - // FIXED: Added updateTableFlag effect - React.useEffect(() => { - if (updateTableFlag) { - console.log("Update table flag triggered"); - getSessions(); - setUpdateTableFlag(false); - } - }, [updateTableFlag, setUpdateTableFlag]); + const columns = [ + { + field: "name", + headerName: "Session Name", + flex: 1, + renderCell: (params) => ( + + ) + }, + { + field: "created_at", + headerName: "Created At", + flex: 1, + valueFormatter: (params) => new Date(params.value).toLocaleString() + }, + { + field: "documents", + headerName: "Documents", + flex: 0.7, + valueGetter: (params) => params.row.documents?.length || 0 + }, + { + field: "actions", + headerName: "Actions", + flex: 1.5, + renderCell: (params) => ( +
+ + + {/* Simplified Delete button: It will now rely on a parent handler or direct API call */} + +
+ ) + } + ]; - // FIXED: Correct DataGrid column structure - const columns = [ - { - field: "name", - headerName: "Session Name", - flex: 1 - }, - { - field: "created_at", - headerName: "Created At", - flex: 1, - valueFormatter: (params) => new Date(params.value).toLocaleString() - }, - { - field: "documents", - headerName: "Documents", - flex: 0.7, - valueGetter: (params) => params.row.documents?.length || 0 - }, - { - field: "actions", - headerName: "Actions", - flex: 1.5, - renderCell: (params) => ( -
- - - -
- ) - } - ]; + return ( + + + + RAG Sessions + + + - return ( - - - - RAG Sessions - - - + row.id} + sx={{ + '& .MuiDataGrid-cell:focus': { outline: 'none' }, + minHeight: 400 + }} + /> - row.id} - sx={{ - '& .MuiDataGrid-cell:focus': { outline: 'none' }, - minHeight: 400 - }} - /> - - ); + {/* Removed ConfirmDialog component */} + + ); } -// FIXED: Correct propTypes RAGSessionsTable.propTypes = { - handleOpenNewSessionModal: PropTypes.func.isRequired, - onSessionSelect: PropTypes.func, - updateTableFlag: PropTypes.bool.isRequired, - setUpdateTableFlag: PropTypes.func.isRequired + sessions: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + created_at: PropTypes.string.isRequired, + documents: PropTypes.array, + task_name: PropTypes.string, + }) + ).isRequired, + onSelect: PropTypes.func.isRequired, + onEdit: PropTypes.func.isRequired, + // Removed onRefreshSessions from propTypes + onOpenNewSessionModal: PropTypes.func.isRequired, }; - -export default RAGSessionsTable; \ No newline at end of file diff --git a/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx b/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx index b1d29f529..2d4069c06 100644 --- a/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx +++ b/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx @@ -1,38 +1,171 @@ -// RetrieverConfigurationStep.jsx -import React from "react"; +import { useState, useEffect, useCallback } from "react"; import PropTypes from "prop-types"; -import { Box } from "@mui/material"; -import ComponentSelector from "../../../components/generative/RAG/ComponentSelector"; -import { getRetrieverComponents } from "../../../api/rag"; - -function RetrieverConfigurationStep({ newSession, setNewSession, setNextEnabled }) { - const handleConfigurationChange = (retrieverConfig) => { - setNewSession(prev => ({ - ...prev, - RAGParameters: { - ...prev.RAGParameters, - retrieval: retrieverConfig +import { Box, Autocomplete, TextField, Typography, Button } from "@mui/material"; // Added Button and Typography for consistency +import { useFormik } from "formik"; // Import useFormik +import FormSchemaRenderFields from "../../../components/shared/FormSchemaRenderFields"; // Assuming this component is correctly implemented +import { getRetrieverComponents } from "../../../api/rag"; // Assuming this API call is correct +import { preprocessSchema, buildYupSchema } from "../../../components/generative/utils" + + + +export default function RetrieverConfigurationStep({ retrieverModel, setRetrieverModel, setNextEnabled }) { + const [retrievers, setRetrievers] = useState([]); + const [currentSelectedRetrieverOption, setCurrentSelectedRetrieverOption] = useState(null); + const [validationSchema, setValidationSchema] = useState(null); + + const getInitialParamsFromSchema = useCallback((schemaProperties) => { + if (!schemaProperties) return {}; + return Object.keys(schemaProperties).reduce((acc, key) => { + acc[key] = schemaProperties[key].placeholder !== undefined + ? schemaProperties[key].placeholder + : ""; + return acc; + }, {}); + }, []); + + useEffect(() => { + const loadAndSetRetriever = async () => { + const data = await getRetrieverComponents(); + setRetrievers(data); + + if (retrieverModel?.name) { + const existingRetriever = data.find(r => r.name === retrieverModel.name); + if (existingRetriever) { + setCurrentSelectedRetrieverOption(existingRetriever); + } } - })); + }; + loadAndSetRetriever(); + }, [retrieverModel?.name]); + + const formik = useFormik({ + initialValues: retrieverModel?.parameters || {}, + validationSchema: validationSchema, + enableReinitialize: true, + onSubmit: (values) => { + }, + }); + + useEffect(() => { + + const retrieverSchemaProperties = currentSelectedRetrieverOption?.schema?.properties; + + if (retrieverSchemaProperties) { + const processedProps = preprocessSchema(retrieverSchemaProperties); + setValidationSchema(buildYupSchema(processedProps)); + + const initialFormValues = Object.keys(processedProps).reduce( + (acc, key) => { + acc[key] = retrieverModel?.parameters?.[key] !== undefined + ? retrieverModel.parameters[key] + : (processedProps[key].placeholder !== undefined + ? processedProps[key].placeholder + : ""); + return acc; + }, + {}, + ); + formik.setValues(initialFormValues); + } else { + setValidationSchema(null); + formik.setValues({}); + } + }, [currentSelectedRetrieverOption, retrieverModel?.parameters]); + + useEffect(() => { + const isValid = !!currentSelectedRetrieverOption && formik.isValid; + setNextEnabled(isValid); + }, [currentSelectedRetrieverOption, formik.isValid, setNextEnabled]); + + const handleRetrieverSelectionChange = (event, newValue) => { + setCurrentSelectedRetrieverOption(newValue); + + if (newValue) { + const initialParameters = getInitialParamsFromSchema(newValue.schema?.properties); + setRetrieverModel({ + name: newValue.name, + parameters: initialParameters, + }); + } else { + setRetrieverModel({ name: "", parameters: {} }); + } }; + const handleParametersChange = (updatedValues) => { + formik.setValues((prevValues) => ({ + ...prevValues, + ...updatedValues, + })); + + setRetrieverModel({ + name: currentSelectedRetrieverOption.name, + parameters: { + ...formik.values, + ...updatedValues, + }, + }); + }; + + const processedProperties = currentSelectedRetrieverOption?.schema?.properties + ? preprocessSchema(currentSelectedRetrieverOption.schema.properties) + : {}; + return ( - - + + Configure Retriever Model + + + option.name} + value={currentSelectedRetrieverOption} + onChange={handleRetrieverSelectionChange} + isOptionEqualToValue={(option, value) => option.name === value?.name} + renderInput={(params) => } + sx={{ mb: 3 }} /> + + {currentSelectedRetrieverOption && currentSelectedRetrieverOption.schema && ( +
+ + + Parameters + + console.error("FormSchemaRenderFields Error:", error)} + errorsMessage={formik.errors} + /> + +
+ )}
); } - -RetrieverConfigurationStep.propTypes = { - newSession: PropTypes.object.isRequired, - setNewSession: PropTypes.func.isRequired, - setNextEnabled: PropTypes.func.isRequired, -}; - -export default RetrieverConfigurationStep; \ No newline at end of file diff --git a/StoredRetrievers/tfidf_retriever_07c008c27ce1de3ecd0d4cd42fc4c43604e6d7c2c4f86eef5d4b1b42d6d3c15d_75aeb1f071ec2f059f26544c40689c89c282d8dd1ab84b6674ffbf27e9e8fbd1/vectorizer b/StoredRetrievers/tfidf_retriever_07c008c27ce1de3ecd0d4cd42fc4c43604e6d7c2c4f86eef5d4b1b42d6d3c15d_75aeb1f071ec2f059f26544c40689c89c282d8dd1ab84b6674ffbf27e9e8fbd1/vectorizer new file mode 100644 index 0000000000000000000000000000000000000000..74e153d247b7ad1963c3fed33b427f96b8d14433 GIT binary patch literal 422105 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 z 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

bp0+c;Cz9qd5R$a$y1GKZ5G(?zKl`P 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

V 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 literal 0 HcmV?d00001 diff --git a/StoredRetrievers/tfidf_retriever_0cff2792f2880a97e8dc881b7f30588af3e40f2617f4a8e40f236e3ed70b3976_0ec09b17926fe5aa93641201da7dfeb580d37f3af6b2032f31b6343ac471fba3/vectorizer b/StoredRetrievers/tfidf_retriever_0cff2792f2880a97e8dc881b7f30588af3e40f2617f4a8e40f236e3ed70b3976_0ec09b17926fe5aa93641201da7dfeb580d37f3af6b2032f31b6343ac471fba3/vectorizer new file mode 100644 index 0000000000000000000000000000000000000000..de6d5ba86d7b979d16c230fe0df7a4fcdb9e2e79 GIT binary patch literal 101559 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 literal 0 HcmV?d00001 diff --git a/StoredRetrievers/tfidf_retriever_28bce20bb2374f93157c85fa986ff3d0a6004b637324b92bf98c20efb3e56103_2730eac7385c920c51ee4089b4172f7af4d7be862b3b2aefa2d229aad399bea4/vectorizer b/StoredRetrievers/tfidf_retriever_28bce20bb2374f93157c85fa986ff3d0a6004b637324b92bf98c20efb3e56103_2730eac7385c920c51ee4089b4172f7af4d7be862b3b2aefa2d229aad399bea4/vectorizer new file mode 100644 index 0000000000000000000000000000000000000000..e6e50730218bc84700db7de9507a635ba1bafddb GIT binary patch literal 179480 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 V{eWvCB5N1Tj-NXIqS@i6{C`a41M2_) literal 0 HcmV?d00001 diff --git a/StoredRetrievers/tfidf_retriever_347f29ec72552a7656cf8f10a42670fcd8076c89ce86fece0c180555440bcbc2_c54a2f7e421d397dff3d0a420d9513c4f7b43399cf2c2770b610c951b7af9e38/vectorizer b/StoredRetrievers/tfidf_retriever_347f29ec72552a7656cf8f10a42670fcd8076c89ce86fece0c180555440bcbc2_c54a2f7e421d397dff3d0a420d9513c4f7b43399cf2c2770b610c951b7af9e38/vectorizer new file mode 100644 index 0000000000000000000000000000000000000000..523abeb634533b307c3c438e95d7b9b76cc51519 GIT binary patch literal 243480 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 literal 0 HcmV?d00001 diff --git a/StoredRetrievers/tfidf_retriever_88c363cbc175eb2b0bef48208782dfa84682a5b6dd6e45ac65127700520bc2ba_75aeb1f071ec2f059f26544c40689c89c282d8dd1ab84b6674ffbf27e9e8fbd1/vectorizer b/StoredRetrievers/tfidf_retriever_88c363cbc175eb2b0bef48208782dfa84682a5b6dd6e45ac65127700520bc2ba_75aeb1f071ec2f059f26544c40689c89c282d8dd1ab84b6674ffbf27e9e8fbd1/vectorizer new file mode 100644 index 0000000000000000000000000000000000000000..9d9f01190629db23fb74831422565d68fa5e9a1f GIT binary patch literal 378471 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 literal 0 HcmV?d00001 diff --git a/StoredRetrievers/tfidf_retriever_978e040feee803d3cd97a7eaf5c3e9f502d0d97f670c303715e455047b877281_75aeb1f071ec2f059f26544c40689c89c282d8dd1ab84b6674ffbf27e9e8fbd1/vectorizer b/StoredRetrievers/tfidf_retriever_978e040feee803d3cd97a7eaf5c3e9f502d0d97f670c303715e455047b877281_75aeb1f071ec2f059f26544c40689c89c282d8dd1ab84b6674ffbf27e9e8fbd1/vectorizer new file mode 100644 index 0000000000000000000000000000000000000000..9cf64be5545c1b1427e5d2339b5e7e8831d3e263 GIT binary patch literal 379501 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�!2}=KWc|4ZvI;Q>)`+5G|I?m!?fTU`=I>C! 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 N;j@O%p6)&Q{{vwz__F{2 literal 0 HcmV?d00001 diff --git a/StoredRetrievers/tfidf_retriever_a38d48165431be31206e34ce2758b75170414d8ad2e65d9fa37a38b2e41343fd_57d8f551775097b02aeb07b11856b3cd3f942fbcf36d43a4384b130551631efb/vectorizer b/StoredRetrievers/tfidf_retriever_a38d48165431be31206e34ce2758b75170414d8ad2e65d9fa37a38b2e41343fd_57d8f551775097b02aeb07b11856b3cd3f942fbcf36d43a4384b130551631efb/vectorizer new file mode 100644 index 0000000000000000000000000000000000000000..e509300301fe9089953335a74a06f93c61c949a1 GIT binary patch literal 258501 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 J%SV^a`aku{jVS;C literal 0 HcmV?d00001 diff --git a/StoredRetrievers/tfidf_retriever_dfdc77de99969c1ac75e72e16a8c38ee3fb24e98a90075f4cd923472c317b05c_c27d55405ff4e4180350c51990a570d33540e0098056446ce95de0942b41e4da/vectorizer b/StoredRetrievers/tfidf_retriever_dfdc77de99969c1ac75e72e16a8c38ee3fb24e98a90075f4cd923472c317b05c_c27d55405ff4e4180350c51990a570d33540e0098056446ce95de0942b41e4da/vectorizer new file mode 100644 index 0000000000000000000000000000000000000000..e01fa521d7fb3238cbe26865abce3b910ae8f6b8 GIT binary patch literal 244262 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≧?$8}!2 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

H9hPagrY> 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 F{6ER=*?#~4 literal 0 HcmV?d00001 diff --git a/StoredRetrievers/tfidf_retriever_ee0f3dd0eaad95cb49ab497e118300f86c49ab07807d73ced6d3c69372661f46_c54a2f7e421d397dff3d0a420d9513c4f7b43399cf2c2770b610c951b7af9e38/vectorizer b/StoredRetrievers/tfidf_retriever_ee0f3dd0eaad95cb49ab497e118300f86c49ab07807d73ced6d3c69372661f46_c54a2f7e421d397dff3d0a420d9513c4f7b43399cf2c2770b610c951b7af9e38/vectorizer new file mode 100644 index 0000000000000000000000000000000000000000..9065053cd2da54c414e703d7e1fe91b4b30f1a82 GIT binary patch literal 230851 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 H+ynnV8s!(G literal 0 HcmV?d00001 From 6d41d73a927256b7b480c1dab2da433148786e7a Mon Sep 17 00:00:00 2001 From: sofiachavezb Date: Tue, 15 Jul 2025 00:20:35 -0400 Subject: [PATCH 004/218] frontend working + documents table logic implemented Documents table flashing solved --- DashAI/back/api/api_v1/api.py | 2 + DashAI/back/api/api_v1/endpoints/documents.py | 236 ++++++++++++++++++ .../api_v1/endpoints/generative_session.py | 3 +- DashAI/back/api/api_v1/schemas/__init__.py | 1 + DashAI/back/api/api_v1/schemas/document.py | 20 ++ DashAI/back/app.py | 1 + DashAI/back/config.py | 1 + DashAI/back/dependencies/config_builder.py | 1 + DashAI/back/dependencies/database/models.py | 18 +- DashAI/back/models/RAG/RAG_pipeline.py | 5 +- DashAI/front/src/api/rag.ts | 50 +++- .../generative/RAG/DocumentDropzone.jsx | 45 ---- .../generative/RAG/DocumentSelector.jsx | 166 ++++++------ .../generative/RAG/DocumentTable.jsx | 69 +++-- DashAI/front/src/components/shared/Upload.jsx | 59 +++-- .../generative/RAG/DocumentSelectionStep.jsx | 151 ++++++----- .../pages/generative/RAG/NewSessionModal.jsx | 53 ++-- .../src/pages/generative/RAG/RAGHomePage.jsx | 42 ++-- .../pages/generative/RAG/RAGSessionsTable.jsx | 45 ++-- DashAI/front/src/types/documentResponse.ts | 7 + .../vectorizer | Bin 422105 -> 0 bytes .../vectorizer | Bin 101559 -> 0 bytes .../vectorizer | Bin 179480 -> 0 bytes .../vectorizer | Bin 243480 -> 0 bytes .../vectorizer | Bin 378471 -> 0 bytes .../vectorizer | Bin 379501 -> 0 bytes .../vectorizer | Bin 258501 -> 0 bytes .../vectorizer | Bin 244262 -> 0 bytes .../vectorizer | Bin 225721 -> 0 bytes .../vectorizer | Bin 230851 -> 0 bytes 30 files changed, 643 insertions(+), 332 deletions(-) create mode 100644 DashAI/back/api/api_v1/endpoints/documents.py create mode 100644 DashAI/back/api/api_v1/schemas/document.py delete mode 100644 DashAI/front/src/components/generative/RAG/DocumentDropzone.jsx create mode 100644 DashAI/front/src/types/documentResponse.ts delete mode 100644 StoredRetrievers/tfidf_retriever_07c008c27ce1de3ecd0d4cd42fc4c43604e6d7c2c4f86eef5d4b1b42d6d3c15d_75aeb1f071ec2f059f26544c40689c89c282d8dd1ab84b6674ffbf27e9e8fbd1/vectorizer delete mode 100644 StoredRetrievers/tfidf_retriever_0cff2792f2880a97e8dc881b7f30588af3e40f2617f4a8e40f236e3ed70b3976_0ec09b17926fe5aa93641201da7dfeb580d37f3af6b2032f31b6343ac471fba3/vectorizer delete mode 100644 StoredRetrievers/tfidf_retriever_28bce20bb2374f93157c85fa986ff3d0a6004b637324b92bf98c20efb3e56103_2730eac7385c920c51ee4089b4172f7af4d7be862b3b2aefa2d229aad399bea4/vectorizer delete mode 100644 StoredRetrievers/tfidf_retriever_347f29ec72552a7656cf8f10a42670fcd8076c89ce86fece0c180555440bcbc2_c54a2f7e421d397dff3d0a420d9513c4f7b43399cf2c2770b610c951b7af9e38/vectorizer delete mode 100644 StoredRetrievers/tfidf_retriever_88c363cbc175eb2b0bef48208782dfa84682a5b6dd6e45ac65127700520bc2ba_75aeb1f071ec2f059f26544c40689c89c282d8dd1ab84b6674ffbf27e9e8fbd1/vectorizer delete mode 100644 StoredRetrievers/tfidf_retriever_978e040feee803d3cd97a7eaf5c3e9f502d0d97f670c303715e455047b877281_75aeb1f071ec2f059f26544c40689c89c282d8dd1ab84b6674ffbf27e9e8fbd1/vectorizer delete mode 100644 StoredRetrievers/tfidf_retriever_a38d48165431be31206e34ce2758b75170414d8ad2e65d9fa37a38b2e41343fd_57d8f551775097b02aeb07b11856b3cd3f942fbcf36d43a4384b130551631efb/vectorizer delete mode 100644 StoredRetrievers/tfidf_retriever_dfdc77de99969c1ac75e72e16a8c38ee3fb24e98a90075f4cd923472c317b05c_c27d55405ff4e4180350c51990a570d33540e0098056446ce95de0942b41e4da/vectorizer delete mode 100644 StoredRetrievers/tfidf_retriever_e19a4b25c422aa7be44921f262f32d44d790b515e5af012fa3eaacb52a649869_c54a2f7e421d397dff3d0a420d9513c4f7b43399cf2c2770b610c951b7af9e38/vectorizer delete mode 100644 StoredRetrievers/tfidf_retriever_ee0f3dd0eaad95cb49ab497e118300f86c49ab07807d73ced6d3c69372661f46_c54a2f7e421d397dff3d0a420d9513c4f7b43399cf2c2770b610c951b7af9e38/vectorizer diff --git a/DashAI/back/api/api_v1/api.py b/DashAI/back/api/api_v1/api.py index dbec76512..1e4f93242 100644 --- a/DashAI/back/api/api_v1/api.py +++ b/DashAI/back/api/api_v1/api.py @@ -14,6 +14,7 @@ plugins, predict, runs, + documents ) api_router_v1 = APIRouter() @@ -30,3 +31,4 @@ api_router_v1.include_router(generative_session.router, prefix="/generative-session") api_router_v1.include_router(generative_process.router, prefix="/generative-process") api_router_v1.include_router(plugins.router, prefix="/plugin") +api_router_v1.include_router(documents.router, prefix="/document") \ No newline at end of file diff --git a/DashAI/back/api/api_v1/endpoints/documents.py b/DashAI/back/api/api_v1/endpoints/documents.py new file mode 100644 index 000000000..f18e91265 --- /dev/null +++ b/DashAI/back/api/api_v1/endpoints/documents.py @@ -0,0 +1,236 @@ +import logging +import json +import os +import hashlib +from datetime import datetime +from typing import Any, Dict, List + +from fastapi import ( + APIRouter, + Depends, + HTTPException, + status, + File, + Form, + UploadFile, + Response, +) +from fastapi.responses import FileResponse +from kink import di +from sqlalchemy import exc +from sqlalchemy.orm import sessionmaker + +from DashAI.back.api.api_v1.schemas import DocumentResponse +from DashAI.back.dependencies.database.models import Document + +router = APIRouter() +log = logging.getLogger(__name__) + + +base_url = "/api/v1/documents" +@router.get("/", response_model=List[DocumentResponse]) +async def get_all_documents( + session_factory: sessionmaker = Depends(lambda: di["session_factory"]), +): + """Get all documents with file_url included.""" + with session_factory() as db: + try: + documents = db.query(Document).all() + + documents_responses = [] + + for doc in documents: + documents_responses.append( + DocumentResponse( + id=doc.id, + file_name=doc.file_name, + created=doc.created, + optional_metadata=doc.optional_metadata, + file_url=f"{base_url}/{doc.id}/download", + ) + ) + + return documents_responses + except exc.SQLAlchemyError as e: + log.exception(e) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="Internal database error", + ) from e + + +@router.get("/{document_id}", response_model=DocumentResponse) +async def get_document( + document_id: int, + session_factory: sessionmaker = Depends(lambda: di["session_factory"]), +): + """Get metadata of a document by its ID.""" + with session_factory() as db: + try: + document = db.get(Document, document_id) + if not document: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Document {document_id} does not exist in DB.", + ) + return DocumentResponse( + id=document.id, + file_name=document.file_name, + created=document.created, + optional_metadata=document.optional_metadata, + file_url=f"{base_url}/{document.id}/download", + ) + except exc.SQLAlchemyError as e: + log.exception(e) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="Internal database error", + ) from e + + +@router.get("/{document_id}/download", response_class=FileResponse) +async def download_document( + document_id: int, + session_factory: sessionmaker = Depends(lambda: di["session_factory"]), +): + """Download the actual file content of a document.""" + with session_factory() as db: + document = db.get(Document, document_id) + if not document: + raise HTTPException( + status_code=404, + detail=f"Document {document_id} not found", + ) + if not os.path.exists(document.file_path): + raise HTTPException( + status_code=500, + detail=f"File not found at {document.file_path}", + ) + return FileResponse( + path=document.file_path, + file_name=document.file_name, + media_type="application/octet-stream", + ) + + +@router.post("/", response_model=DocumentResponse, status_code=status.HTTP_201_CREATED) +async def upload_document( + file: UploadFile = File(...), + metadata: str = Form(...), + config: Dict[str, Any] = Depends(lambda: di["config"]), + session_factory: sessionmaker = Depends(lambda: di["session_factory"]), +): + """ + Upload a new document to the RAG system with file content and metadata. + The metadata should be a JSON string with required fields and an 'optional_metadata' dict. + """ + docs_folder_path = config["DOCUMENTS_PATH"] + if not docs_folder_path.exists(): + raise HTTPException( + status_code=500, + detail=f"Documents folder {docs_folder_path} does not exist.", + ) + + try: + metadata_dict = json.loads(metadata) + except json.JSONDecodeError: + raise HTTPException(status_code=400, detail="Invalid JSON in metadata") + + print(f"Metadata received: {metadata_dict}") + file_name = metadata_dict.get("file_name") + last_modified = metadata_dict.get("last_modified") + + if not file_name or not last_modified: + raise HTTPException( + status_code=400, + detail="Missing required metadata fields: 'filename' and 'last_modified'", + ) + + optional_metadata = metadata_dict.get("optional_metadata", {}) + if not isinstance(optional_metadata, dict): + raise HTTPException( + status_code=400, + detail="'optional_metadata' must be a dictionary", + ) + + try: + content_bytes = await file.read() + except Exception: + raise HTTPException(status_code=400, detail="Failed to read file content") + + hash256 = hashlib.sha256(content_bytes).hexdigest() + + with session_factory() as db: + existing_doc = db.query(Document).filter_by(file_hash=hash256).first() + if existing_doc: + # Update existing document's information + existing_doc.file_name = file_name + existing_doc.optional_metadata = optional_metadata + existing_doc.created = datetime.now() + db.commit() + return DocumentResponse( + id=existing_doc.id, + file_name=existing_doc.file_name, + created=existing_doc.created, + optional_metadata=existing_doc.optional_metadata, + file_url=f"{base_url}/{existing_doc.id}/download", + ) + else: + # Create a new document entry + try: + new_id = db.query(Document).count() + 1 + file_path = os.path.join(docs_folder_path, f"{new_id}_{file_name}") + + with open(file_path, "wb") as f: + f.write(content_bytes) + + doc = Document( + file_name=file_name, + file_path=str(file_path), + file_hash=hash256, + optional_metadata=optional_metadata or None, + ) + db.add(doc) + db.commit() + db.refresh(doc) + + return DocumentResponse( + id=doc.id, + file_name=doc.file_name, + created=doc.created, + optional_metadata=doc.optional_metadata, + file_url=f"{base_url}/{doc.id}/download", + ) + except exc.SQLAlchemyError as e: + log.exception(e) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="Internal database error", + ) from e + + +@router.delete("/{document_id}", status_code=status.HTTP_204_NO_CONTENT) +async def delete_document( + document_id: int, + session_factory: sessionmaker = Depends(lambda: di["session_factory"]), +): + """Delete a document from the RAG system by its ID.""" + with session_factory() as db: + try: + document = db.get(Document, document_id) + if not document: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Document {document_id} does not exist in DB.", + ) + if os.path.exists(document.file_path): + os.remove(document.file_path) + db.delete(document) + db.commit() + return Response(status_code=status.HTTP_204_NO_CONTENT) + except exc.SQLAlchemyError as e: + log.exception(e) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="Internal database error", + ) from e diff --git a/DashAI/back/api/api_v1/endpoints/generative_session.py b/DashAI/back/api/api_v1/endpoints/generative_session.py index 2d46214dd..ce79dafba 100644 --- a/DashAI/back/api/api_v1/endpoints/generative_session.py +++ b/DashAI/back/api/api_v1/endpoints/generative_session.py @@ -19,6 +19,7 @@ from DashAI.back.models import BaseGenerativeModel from DashAI.back.tasks import BaseGenerativeTask + router = APIRouter() log = logging.getLogger(__name__) @@ -496,4 +497,4 @@ async def get_parameter_history_entry( raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Internal database error", - ) from e + ) from e \ No newline at end of file diff --git a/DashAI/back/api/api_v1/schemas/__init__.py b/DashAI/back/api/api_v1/schemas/__init__.py index e69de29bb..79080d662 100644 --- a/DashAI/back/api/api_v1/schemas/__init__.py +++ b/DashAI/back/api/api_v1/schemas/__init__.py @@ -0,0 +1 @@ +from DashAI.back.api.api_v1.schemas.document import DocumentResponse, DocumentUploadResponse \ No newline at end of file diff --git a/DashAI/back/api/api_v1/schemas/document.py b/DashAI/back/api/api_v1/schemas/document.py new file mode 100644 index 000000000..38b5517c7 --- /dev/null +++ b/DashAI/back/api/api_v1/schemas/document.py @@ -0,0 +1,20 @@ +from pydantic import BaseModel +from typing import Any, Dict, Optional +from datetime import datetime + +class DocumentUploadResponse(BaseModel): + id: int + file_name: str + optional_metadata: Optional[dict] + created: datetime + file_hash: str + +class DocumentResponse(BaseModel): + id: int + file_name: str + created: datetime + optional_metadata: Optional[Dict[str, Any]] + file_url: str + + class Config: + orm_mode = True diff --git a/DashAI/back/app.py b/DashAI/back/app.py index e892b5509..884b02294 100644 --- a/DashAI/back/app.py +++ b/DashAI/back/app.py @@ -101,6 +101,7 @@ def create_app( _create_path_if_not_exists(config["EXPLANATIONS_PATH"]) _create_path_if_not_exists(config["EXPLORATIONS_PATH"]) _create_path_if_not_exists(config["RUNS_PATH"]) + _create_path_if_not_exists(config["DOCUMENTS_PATH"]) logger.debug("5. Creating database.") Base.metadata.create_all(bind=container["engine"]) diff --git a/DashAI/back/config.py b/DashAI/back/config.py index 594b5c9e7..3f72ceeff 100644 --- a/DashAI/back/config.py +++ b/DashAI/back/config.py @@ -20,3 +20,4 @@ class DefaultSettings(BaseSettings): RUNS_PATH: str = "runs" EXPLANATIONS_PATH: str = "explanations" EXPLORATIONS_PATH: str = "explorations" + DOCUMENTS_PATH: str = "documents" diff --git a/DashAI/back/dependencies/config_builder.py b/DashAI/back/dependencies/config_builder.py index c3e446da7..a98a2c9f7 100644 --- a/DashAI/back/dependencies/config_builder.py +++ b/DashAI/back/dependencies/config_builder.py @@ -61,5 +61,6 @@ def build_config_dict( config["FRONT_BUILD_PATH"] = pathlib.Path(config["FRONT_BUILD_PATH"]).absolute() config["LOGGING_LEVEL"] = getattr(logging, logging_level) config["INITIAL_COMPONENTS"] = get_initial_components() + config["DOCUMENTS_PATH"] = local_path / config["DOCUMENTS_PATH"] return config diff --git a/DashAI/back/dependencies/database/models.py b/DashAI/back/dependencies/database/models.py index 86ad2eb4a..f771da80f 100644 --- a/DashAI/back/dependencies/database/models.py +++ b/DashAI/back/dependencies/database/models.py @@ -3,7 +3,7 @@ from datetime import datetime from beartype.typing import List -from sqlalchemy import JSON, Boolean, DateTime, Enum, ForeignKey, String +from sqlalchemy import JSON, Boolean, DateTime, Enum, ForeignKey, String, LargeBinary from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import Mapped, mapped_column, relationship @@ -340,6 +340,22 @@ class ProcessData(Base): ) +class Document(Base): + __tablename__ = "RAG_document" + """ + Table to store all the information about a document in the RAG system. + """ + id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) + file_name: Mapped[str] = mapped_column(String, nullable=False) + file_path: Mapped[str] = mapped_column(String, nullable=False) + file_hash: Mapped[str] = mapped_column(String, nullable=False, unique=True) + created: Mapped[DateTime] = mapped_column(DateTime, default=datetime.now) + optional_metadata: Mapped[JSON] = mapped_column(JSON, nullable=True) + + def __repr__(self) -> str: + return f"" + + class GenerativeSession(Base): __tablename__ = "generative_session" """ diff --git a/DashAI/back/models/RAG/RAG_pipeline.py b/DashAI/back/models/RAG/RAG_pipeline.py index dde12274e..83300d24c 100644 --- a/DashAI/back/models/RAG/RAG_pipeline.py +++ b/DashAI/back/models/RAG/RAG_pipeline.py @@ -4,9 +4,8 @@ BaseSchema, component_field, schema_field, - bool_field, list_field, - string_field + int_field ) from DashAI.back.models.base_generative_model import BaseGenerativeModel @@ -42,7 +41,7 @@ class RAGPipelineSchema(BaseSchema): # Document collection parameters documents: schema_field( list_field( - string_field(), + int_field(), min_items=1, ), placeholder=None, diff --git a/DashAI/front/src/api/rag.ts b/DashAI/front/src/api/rag.ts index 6a3f2b67c..90500a6b8 100644 --- a/DashAI/front/src/api/rag.ts +++ b/DashAI/front/src/api/rag.ts @@ -1,6 +1,7 @@ import api from "./api"; import { ISession } from "../types/session"; import { IGenerativeTask } from "../types/generativeTask"; +import { IDocumentResponse } from "../types/documentResponse"; // Fetch all RAG sessions @@ -134,4 +135,51 @@ export const getGeneratorComponents = async (): Promise => { return response.data; -} \ No newline at end of file +} + +export const loadDocuments = async (): Promise => { + const response = await api.get("/v1/document/"); + if (response.status !== 200) { + throw new Error(`Failed to load documents: ${response.statusText}`); + } + console.log("Loaded documents:", response.data); + return response.data; +}; + +export const deleteDocument = async (documentId: number): Promise => { + const response = await api.delete(`/v1/document/${documentId}`); + if (response.status !== 204) { + throw new Error(`Failed to delete document: ${response.statusText}`); + } +}; + +export const addDocument = async ({ file, optional_metadata }: { + file: File, + optional_metadata?: Record, +}): Promise => { + + console.log("Adding document:", file, optional_metadata); + + if (optional_metadata) { + optional_metadata.last_modified = file.lastModified + } + const metadata = { + file_name: file.name, + last_modified: file.lastModified, + optional_metadata, + }; + + const formData = new FormData(); + formData.append("file", file); + formData.append("metadata", JSON.stringify(metadata)); + + const response = await api.post("/v1/document/", formData, { + headers: { "Content-Type": "multipart/form-data" }, + }); + + if (response.status !== 201) { + throw new Error(`Failed to upload document: ${response.statusText}`); + } + + return response.data; +}; diff --git a/DashAI/front/src/components/generative/RAG/DocumentDropzone.jsx b/DashAI/front/src/components/generative/RAG/DocumentDropzone.jsx deleted file mode 100644 index 01eeb326d..000000000 --- a/DashAI/front/src/components/generative/RAG/DocumentDropzone.jsx +++ /dev/null @@ -1,45 +0,0 @@ -import { Box, Typography, Paper } from "@mui/material"; -import { useCallback } from "react"; -import { useDropzone } from "react-dropzone"; -import Upload from "../../shared/Upload"; -let idCounter = 200; - -export default function DocumentDropzone({ onAddDocument }) { - const onDrop = useCallback((acceptedFiles) => { - acceptedFiles.forEach((file) => { - const newDoc = { - id: idCounter++, - name: file.name, - updatedAt: new Date().toLocaleDateString(), - }; - onAddDocument(newDoc); - }); - }, [onAddDocument]); - - const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop }); - - return ( - - - - Drag & drop documents here, or click to upload - - - ); -} diff --git a/DashAI/front/src/components/generative/RAG/DocumentSelector.jsx b/DashAI/front/src/components/generative/RAG/DocumentSelector.jsx index 4f7040a2c..c1f133863 100644 --- a/DashAI/front/src/components/generative/RAG/DocumentSelector.jsx +++ b/DashAI/front/src/components/generative/RAG/DocumentSelector.jsx @@ -1,98 +1,108 @@ import { Box } from "@mui/material"; -import { useEffect, useState } from "react"; -import PropTypes from "prop-types"; // Import PropTypes +import { useEffect, useState, useCallback, useRef } from "react"; // Added useRef +import PropTypes from "prop-types"; import DocumentTable from "./DocumentTable"; -import Upload from "../../shared/Upload"; // Assuming path is correct +import Upload from "../../shared/Upload"; +import { loadDocuments, addDocument, deleteDocument } from "../../../api/rag"; export default function DocumentSelector({ - documents: initialDocuments = [], // Renamed prop for clarity, uses initial state - selected: initialSelectedIds = [], // Renamed prop for clarity - onSelect, // Callback for when selection changes (receives selected document objects) - onAddDocument, // Callback for when a new document object is added (receives new doc object) - onRemove, // Callback for when a document is removed (receives docId/path) + selectedIds: initialSelectedIds = [], + onSelect, }) { - const [documents, setDocuments] = useState(initialDocuments); + const [documents, setDocuments] = useState([]); const [selectedIds, setSelectedIds] = useState(initialSelectedIds); - // Add a key state to force Upload component re-render + const [isLoading, setIsLoading] = useState(true); const [uploadKey, setUploadKey] = useState(0); - // Sync internal 'documents' state with 'initialDocuments' prop + const previousSelectedIdsRef = useRef(initialSelectedIds); + useEffect(() => { - setDocuments(initialDocuments); - }, [initialDocuments]); + const fetchDocuments = async () => { + setIsLoading(true); + try { + const docs = await loadDocuments(); + setDocuments(docs); + } catch (error) { + console.error("Failed to load documents:", error); + } finally { + setIsLoading(false); + } + }; + + fetchDocuments(); + }, []); - // Sync internal 'selectedIds' state with 'initialSelectedIds' prop useEffect(() => { - setSelectedIds(initialSelectedIds); + if (JSON.stringify(selectedIds.sort()) !== JSON.stringify(initialSelectedIds.sort())) { + setSelectedIds(initialSelectedIds); + } }, [initialSelectedIds]); - // Sync selected documents with parent's onSelect callback + useEffect(() => { - const selectedDocs = documents.filter(doc => selectedIds.includes(doc.id)); - if (onSelect) { - onSelect(selectedDocs); + if (JSON.stringify(selectedIds.sort()) !== JSON.stringify(previousSelectedIdsRef.current.sort())) { + const selectedDocs = documents.filter(doc => selectedIds.includes(doc.id)); + onSelect(selectedDocs); + previousSelectedIdsRef.current = selectedIds; } - }, [selectedIds, documents, onSelect]); + }, [selectedIds, documents, onSelect]); - const handleToggleSelection = (id) => { - setSelectedIds(prev => - prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id] - ); - }; + const handleToggleSelection = useCallback((id) => { + setSelectedIds(prev => { + const newSelected = prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id]; + return newSelected; + }); + }, []); - const handleSelectAll = () => { + const handleSelectAll = useCallback(() => { setSelectedIds(documents.map(doc => doc.id)); - }; + }, [documents]); - const handleDeselectAll = () => { + const handleDeselectAll = useCallback(() => { setSelectedIds([]); - }; - - // Internal handler for adding a document object (before notifying parent) - const addDocumentObject = (newDoc) => { - setDocuments(prev => { - // Ensure no duplicates based on ID (path) - if (!prev.some(doc => doc.id === newDoc.id)) { - return [newDoc, ...prev]; // Add to the beginning - } - return prev; - }); - // Call the parent's onAddDocument callback - if (onAddDocument) { - onAddDocument(newDoc); + }, []); + + const handleAddDocument = useCallback(async (newDoc) => { + try { + const savedDoc = await addDocument(newDoc); + setDocuments(prev => [savedDoc, ...prev]); + setSelectedIds(prev => [...prev, savedDoc.id]); + setUploadKey(prev => prev + 1); + return savedDoc; + } catch (error) { + console.error("Failed to add document:", error); + return null; } - }; - - // Internal handler for removing a document object (before notifying parent) - const removeDocumentObject = (id) => { - setDocuments(prev => prev.filter(doc => doc.id !== id)); - setSelectedIds(prev => prev.filter(x => x !== id)); - // Call the parent's onRemove callback - if (onRemove) { - onRemove(id); + }, []); + + const handleRemoveDocument = useCallback(async (id) => { + try { + await deleteDocument(id); + setDocuments(prev => prev.filter(doc => doc.id !== id)); + setSelectedIds(prev => prev.filter(x => x !== id)); + } catch (error) { + console.error("Failed to delete document:", error); } - }; + }, []); - const handleFileUpload = (file, url) => { - if (!file) return; + const handleFileUpload = useCallback(async (files, url) => { + if (!files) return; - // The 'id' of the document will be the URL (or file.name if no URL is available) - // This allows the 'id' to directly represent the path/reference - const docId = url || file.name; + console.log("Files to upload at handleFileUpload:", files); - const newDoc = { - id: docId, - name: file.name, - updatedAt: new Date().toISOString(), - preview: url, // Store URL for preview if available - }; - - addDocumentObject(newDoc); // Use the internal handler - setSelectedIds(prev => [...prev, newDoc.id]); // Also select it upon upload + const fileList = Array.isArray(files) ? files : [files]; - // Reset the upload component by incrementing its key - setUploadKey(prev => prev + 1); - }; + for (const file of fileList) { + const docToAdd = { + file, + optional_metadata: { + name: file.name, + source: url || 'local_upload', + } + }; + await handleAddDocument(docToAdd); + } + }, [handleAddDocument]); return ( @@ -103,7 +113,8 @@ export default function DocumentSelector({ onToggle={handleToggleSelection} onSelectAll={handleSelectAll} onDeselectAll={handleDeselectAll} - onRemove={removeDocumentObject} // Use the internal removal handler + onRemove={handleRemoveDocument} + isLoading={isLoading} /> @@ -111,6 +122,7 @@ export default function DocumentSelector({ @@ -118,14 +130,6 @@ export default function DocumentSelector({ } DocumentSelector.propTypes = { - documents: PropTypes.arrayOf(PropTypes.shape({ - id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - updatedAt: PropTypes.string.isRequired, - preview: PropTypes.string, // Optional - })), - selected: PropTypes.arrayOf(PropTypes.string), // Array of document IDs (paths) - onSelect: PropTypes.func, // (selectedDocs: array of objects) => void - onAddDocument: PropTypes.func, // (newDoc: object) => void - onRemove: PropTypes.func, // (docId: string) => void -}; + selectedIds: PropTypes.arrayOf(PropTypes.string), + onSelect: PropTypes.func, +}; \ No newline at end of file diff --git a/DashAI/front/src/components/generative/RAG/DocumentTable.jsx b/DashAI/front/src/components/generative/RAG/DocumentTable.jsx index 9bf365ed0..ec0b3f658 100644 --- a/DashAI/front/src/components/generative/RAG/DocumentTable.jsx +++ b/DashAI/front/src/components/generative/RAG/DocumentTable.jsx @@ -10,6 +10,7 @@ import { IconButton, Tooltip, Button, + CircularProgress, } from "@mui/material"; import VisibilityIcon from "@mui/icons-material/Visibility"; import DeleteIcon from "@mui/icons-material/Delete"; @@ -22,7 +23,17 @@ export default function DocumentTable({ onSelectAll, onDeselectAll, onRemove, + isLoading = false, }) { + // Format the date to a more readable format + const formatDate = (dateString) => { + try { + const date = new Date(dateString); + return date.toLocaleString(); + } catch (e) { + return dateString; + } + }; return ( - {documents.length === 0 ? ( + }}> + {isLoading ? ( + + + + ) : documents.length === 0 ? ( No documents available. @@ -43,22 +58,23 @@ export default function DocumentTable({ - {/* Added padding="checkbox" for standard spacing */} - {/* Checkbox for Select All/Deselect All */} - 0 && selectedIds.length < documents.length} - checked={selectedIds.length === documents.length && documents.length > 0} - onChange={(event) => { - if (event.target.checked) { - onSelectAll(); - } else { - onDeselectAll(); - } - }} - /> + + 0 && selectedIds.length < documents.length} + checked={selectedIds.length === documents.length && documents.length > 0} + onChange={(event) => { + if (event.target.checked) { + onSelectAll(); + } else { + onDeselectAll(); + } + }} + /> + Id Name - Updated + Added On + Last Modified Actions @@ -72,14 +88,16 @@ export default function DocumentTable({ backgroundColor: selectedIds.includes(doc.id) ? "action.hover" : "inherit", }} > - {/* Added padding="checkbox" */} + onToggle(doc.id)} /> - {doc.name} - {doc.updatedAt} + {doc.id} + {doc.file_name} + {formatDate(doc.created)} + {doc.optional_metadata?.last_modified ? formatDate(doc.optional_metadata.last_modified) : "N/A"} @@ -103,13 +121,13 @@ export default function DocumentTable({
@@ -124,7 +142,7 @@ DocumentTable.propTypes = { documents: PropTypes.arrayOf(PropTypes.shape({ id: PropTypes.string.isRequired, name: PropTypes.string.isRequired, - updatedAt: PropTypes.string.isRequired, + createdAt: PropTypes.string.isRequired, preview: PropTypes.string, })).isRequired, selectedIds: PropTypes.arrayOf(PropTypes.string).isRequired, @@ -132,4 +150,5 @@ DocumentTable.propTypes = { onSelectAll: PropTypes.func.isRequired, onDeselectAll: PropTypes.func.isRequired, onRemove: PropTypes.func.isRequired, + isLoading: PropTypes.bool, }; diff --git a/DashAI/front/src/components/shared/Upload.jsx b/DashAI/front/src/components/shared/Upload.jsx index 60e887978..024e2c19a 100644 --- a/DashAI/front/src/components/shared/Upload.jsx +++ b/DashAI/front/src/components/shared/Upload.jsx @@ -20,20 +20,22 @@ import ClearIcon from "@mui/icons-material/Clear"; * newDataset state in the modal * @param {function} onFileUpload function to handle when the user "uploads" a dataset */ -function Upload({ onFileUpload, emptyUploadText }) { +function Upload({ onFileUpload, emptyUploadText, multiple = false }) { const [EMPTY, LOADING, LOADED] = [0, 1, 2]; const [datasetState, setDatasetState] = useState(EMPTY); const [dragActive, setDragActive] = useState(false); - const [fileOriginalName, setFileOriginalName] = useState(""); + const [fileNames, setFileNames] = useState([]); const inputRef = useRef(null); - const uploadDataset = async (file) => { + const uploadDataset = async (files) => { + const fileArray = Array.isArray(files) ? files : Array.from(files); setDatasetState(LOADING); const url = ""; - onFileUpload(file, url); + await onFileUpload(fileArray, url); setDatasetState(LOADED); - setFileOriginalName(file.name); - }; + setFileNames(fileArray.map(f => f.name)); + }; + const handleDrag = (e) => { e.preventDefault(); @@ -49,7 +51,8 @@ function Upload({ onFileUpload, emptyUploadText }) { const handleSelect = (e) => { if (datasetState === EMPTY) { - uploadDataset(e.target.files[0]); + const files = multiple ? e.target.files : [e.target.files[0]]; + uploadDataset(files); } }; @@ -58,8 +61,9 @@ function Upload({ onFileUpload, emptyUploadText }) { e.stopPropagation(); if (datasetState === EMPTY) { setDragActive(false); - if (e.dataTransfer.files && e.dataTransfer.files[0]) { - uploadDataset(e.dataTransfer.files[0]); + const files = multiple ? e.dataTransfer.files : [e.dataTransfer.files[0]]; + if (files && files.length > 0) { + uploadDataset(files); } } }; @@ -71,41 +75,42 @@ function Upload({ onFileUpload, emptyUploadText }) { const handleDeleteDataset = () => { onFileUpload(null, ""); setDatasetState(EMPTY); + setFileNames([]); }; - // renders content inside the drag and drop component depending on the state of the dataset const stateContent = (state) => { switch (state) { case EMPTY: return ( - + <> {dragActive ? ( - Drop the files here ... + Drop the file{multiple ? "s" : ""} here. ) : ( - + <> - Drag and drop a file here, or + Drag and drop {multiple ? "your files" : "a file"} here, or - + )} - + ); case LOADING: @@ -113,12 +118,24 @@ function Upload({ onFileUpload, emptyUploadText }) { case LOADED: return ( - + <> - - {fileOriginalName} - - + + {fileNames.map((name, index) => ( + + {name} + + ))} + + ); } }; diff --git a/DashAI/front/src/pages/generative/RAG/DocumentSelectionStep.jsx b/DashAI/front/src/pages/generative/RAG/DocumentSelectionStep.jsx index 3ad1d7afa..cba8634f8 100644 --- a/DashAI/front/src/pages/generative/RAG/DocumentSelectionStep.jsx +++ b/DashAI/front/src/pages/generative/RAG/DocumentSelectionStep.jsx @@ -1,97 +1,92 @@ -import React, { useState, useEffect, useCallback } from "react"; +import React, { useState, useEffect, useRef } from "react"; // Add useRef import PropTypes from "prop-types"; -import { Box, Typography } from "@mui/material"; -import DocumentSelector from "../../../components/generative/RAG/DocumentSelector"; // Adjust the import path as needed +import { Box, Typography, TextField } from "@mui/material"; +import DocumentSelector from "../../../components/generative/RAG/DocumentSelector"; + +export default function DocumentSelectionStep({ + documents: propDocumentIds, // Rename to reflect it's IDs + setDocuments, + setNextEnabled, + sessionName, + setSesssionName, + sessionDescription, + setSessionDescription, +}) { + const [selectedDocuments, setSelectedDocuments] = useState([]); + const initialLoadRef = useRef(true); // Ref to track initial render + useEffect(() => { + if (initialLoadRef.current && propDocumentIds && propDocumentIds.length > 0) { + initialLoadRef.current = false; + } + }, [propDocumentIds]); - - - -// Helper function to convert document paths to UI-friendly objects -const createDocumentObjectFromPath = (path) => ({ - id: path, - name: path.split('/').pop() || path, // Use filename as name, fallback to full path - updatedAt: new Date().toISOString(), // Initial timestamp for new paths -}); - -export default function DocumentSelectionStep({ documents, setDocuments, setNextEnabled }) { - // Initialize localDocumentObjects and selectedObjectIds once from the 'documents' prop. - // This runs only on the initial mount. - const [localDocumentObjects, setLocalDocumentObjects] = useState(() => { - const initialLocalDocs = documents.map(createDocumentObjectFromPath); - const initialSelectedIds = documents; // Paths are directly the IDs - return initialLocalDocs; - }); - - const [selectedObjectIds, setSelectedObjectIds] = useState(() => { - return documents; // Paths are directly the IDs - }); - - // Effect 1: Sync selectedObjectIds (paths) back to the parent component - // This effect ensures the parent's 'documents' prop is updated when local selection changes. useEffect(() => { - // Only update parent if there's a change to prevent infinite loops and unnecessary re-renders - if (JSON.stringify(selectedObjectIds) !== JSON.stringify(documents)) { - setDocuments(selectedObjectIds); // selectedObjectIds already contains the paths - } - }, [selectedObjectIds, setDocuments, documents]); // Dependencies: local selected IDs, and parent's setter/prop for comparison + const documentIdsSelected = selectedDocuments.length > 0; + const validSessionName = sessionName.trim() !== ""; + setNextEnabled(documentIdsSelected && validSessionName); + }, [selectedDocuments, sessionName, setNextEnabled]); - // Effect 2: Notify parent about step validity - // This effect ensures the 'Next' button's enabled state is correct. useEffect(() => { - const isValid = selectedObjectIds && selectedObjectIds.length > 0; - setNextEnabled(isValid); - }, [selectedObjectIds, setNextEnabled]); // Dependencies: local selected IDs, and parent's setter + const currentSelectedIds = selectedDocuments.map(doc => doc.id); + if (JSON.stringify(currentSelectedIds.sort()) !== JSON.stringify(propDocumentIds.sort())) { + setDocuments(currentSelectedIds); + } + }, [selectedDocuments, setDocuments, propDocumentIds]); - // Handler for when DocumentSelector's selection changes (checkboxes) - const handleDocumentSelectionChange = useCallback((selectedDocs) => { - // Extract 'id' (which is the path) from the selected document objects - const newSelectedIds = selectedDocs.map(doc => doc.id); - setSelectedObjectIds(newSelectedIds); - }, []); - // Handler for when DocumentSelector adds a new document (e.g., from Upload component) - const handleAddDocumentObject = useCallback((newDoc) => { - setLocalDocumentObjects(prev => { - // Ensure no duplicates based on ID (path) before adding - if (!prev.some(doc => doc.id === newDoc.id)) { - const updatedDocs = [...prev, newDoc]; - // Also ensure it's selected in the UI - setSelectedObjectIds(currentSelected => { - if (!currentSelected.includes(newDoc.id)) { - return [...currentSelected, newDoc.id]; - } - return currentSelected; - }); - return updatedDocs; - } - return prev; - }); - }, []); + const handleSessionNameChange = (event) => { + setSesssionName(event.target.value); + }; - // Handler for when DocumentSelector removes a document - const handleRemoveDocumentObject = useCallback((docId) => { - setLocalDocumentObjects(prev => prev.filter(doc => doc.id !== docId)); - setSelectedObjectIds(prev => prev.filter(id => id !== docId)); - }, []); + const handleSessionDescriptionChange = (event) => { + setSessionDescription(event.target.value); + }; + const handleDocumentSelectionChange = (selectedDocs) => { + setSelectedDocuments(selectedDocs); + }; return ( - Select Documents + + Session Name + + + Session Description + + + + Select Documents Upload new documents or select from existing ones to be used for RAG. - {/* Integrate the DocumentSelector component */} - {/* Allow DocumentSelector to take available height */} + @@ -102,4 +97,8 @@ DocumentSelectionStep.propTypes = { documents: PropTypes.arrayOf(PropTypes.string).isRequired, setDocuments: PropTypes.func.isRequired, setNextEnabled: PropTypes.func.isRequired, -}; + sessionName: PropTypes.string.isRequired, + setSesssionName: PropTypes.func.isRequired, + sessionDescription: PropTypes.string.isRequired, + setSessionDescription: PropTypes.func.isRequired, +}; \ No newline at end of file diff --git a/DashAI/front/src/pages/generative/RAG/NewSessionModal.jsx b/DashAI/front/src/pages/generative/RAG/NewSessionModal.jsx index cf14db042..d4efa0d1d 100644 --- a/DashAI/front/src/pages/generative/RAG/NewSessionModal.jsx +++ b/DashAI/front/src/pages/generative/RAG/NewSessionModal.jsx @@ -75,6 +75,7 @@ export default function NewSessionModal({ setActiveStep(0); if(session) { const sessionParameters = session.parameters || {}; + const sessionDocuments = sessionParameters.documents || []; const sessionRetrieverModel = sessionParameters.retriever_model || {}; const sessionGeneratorModel = sessionParameters.generator_model || {}; setSessionData({ @@ -84,16 +85,12 @@ export default function NewSessionModal({ description: session.description || "", displayName: session.displayName || "", parameters: { - documents: sessionParameters.documents || [], + documents: [...sessionDocuments], retriever_model: { - class: sessionRetrieverModel.class || "", - name: sessionRetrieverModel.name || "", - parameters: sessionRetrieverModel.parameters || {}, + ...sessionRetrieverModel, }, generator_model: { - class: sessionGeneratorModel.class || "", - name: sessionGeneratorModel.name || "", - parameters: sessionGeneratorModel.parameters || {}, + ...sessionGeneratorModel, }, }, }) @@ -128,21 +125,26 @@ export default function NewSessionModal({ } try { - // Ensure generator_model is included in the final session data const finalSessionData = { - ...sessionData, - parameters: { - ...sessionData.parameters, - generator_model: sessionData.parameters.generator_model || { - name: "", - parameters: {}, - }, - retriever_model: sessionData.parameters.retriever_model || { - name: "", - parameters: {}, - }, + ...sessionData, + name: sessionData.name.trim(), + description: sessionData.description.trim() || "", + task_name: "RAGTask", + parameters: { + ...sessionData.parameters, + documents: sessionData.parameters.documents || [], + retriever_model: sessionData.parameters.retriever_model || { + name: "", + parameters: {}, }, - }; + generator_model: sessionData.parameters.generator_model || { + name: "", + parameters: {}, + }, + }, + }; + + console.log("NewSessionModal: Final session data to save:", finalSessionData); const savedSession = await onSessionSaved(finalSessionData); @@ -207,6 +209,7 @@ export default function NewSessionModal({ {activeStep === 0 && ( setSessionData(prev => ({ @@ -215,6 +218,16 @@ export default function NewSessionModal({ })) } setNextEnabled={(isValid) => handleStepValidation(0, isValid)} + sessionName={sessionData.name} + setSesssionName={(name) => setSessionData(prev => ({ + ...prev, + name: name + }))} + sessionDescription={sessionData.description} + setSessionDescription={(description) => setSessionData(prev => ({ + ...prev, + description: description + }))} /> )} {activeStep === 1 && ( diff --git a/DashAI/front/src/pages/generative/RAG/RAGHomePage.jsx b/DashAI/front/src/pages/generative/RAG/RAGHomePage.jsx index 292824418..11f670bbe 100644 --- a/DashAI/front/src/pages/generative/RAG/RAGHomePage.jsx +++ b/DashAI/front/src/pages/generative/RAG/RAGHomePage.jsx @@ -12,53 +12,42 @@ function RAGHomePage({ onSessionCreated, onSessionSelect }) { const [editingSession, setEditingSession] = useState(null); const loadSessions = async () => { - setLoading(true); // Set loading to true when fetching + setLoading(true); try { const data = await getRAGSessions(); setSessions(data); - console.log("RAGHomePage: Sessions loaded:", data); } catch (error) { console.error("RAGHomePage: Error loading RAG sessions:", error); } finally { - setLoading(false); // Set loading to false after fetch - console.log("RAGHomePage: Loading finished."); + setLoading(false); } }; - // Cargar sesiones al iniciar useEffect(() => { - console.log("RAGHomePage: useEffect - Initial session load..."); loadSessions(); - }, []); // Empty dependency array means this runs once on mount + }, []); const handleOpenNewSessionModal = (session = null) => { - console.log("RAGHomePage: handleOpenNewSessionModal called."); - setEditingSession(session); // Set the session to edit - setShowModal(true); // Open the modal - console.log("RAGHomePage: showModal set to true."); + setEditingSession(session); + setShowModal(true); }; const handleCreateOrUpdateSession = async (sessionData) => { - console.log("RAGHomePage: handleCreateOrUpdateSession called with data:", sessionData); try { const savedSession = await createRAGSession(sessionData); console.log("RAGHomePage: New/Updated RAG session saved:", savedSession); - // Refresh the sessions list after creation/update - await loadSessions(); // Call loadSessions to get the latest data - - onSessionCreated(savedSession); // Notify parent component (Generative.jsx) - setShowModal(false); // Close the modal - console.log("RAGHomePage: Modal closed after session save."); + await loadSessions(); + onSessionCreated(savedSession); + setShowModal(false); + return savedSession; + } catch (error) { - console.error("RAGHomePage: Error creating/updating session:", error); - throw error; // Re-throw to handle in the modal if needed + throw error; } }; - console.log("RAGHomePage: Render. Current showModal state:", showModal); - return ( } > - {/* Modal para nueva sesión */} { setShowModal(false); - setEditingSession(null); // Clear editing session when closing - console.log("RAGHomePage: Modal onClose called. showModal set to false."); + setEditingSession(null); }} onSessionSaved={handleCreateOrUpdateSession} onSessionSelect={onSessionSelect} session={editingSession} /> - {/* Contenido principal */} {loading ? ( @@ -97,8 +83,8 @@ function RAGHomePage({ onSessionCreated, onSessionSelect }) { sessions={sessions} onEdit={(session) => handleOpenNewSessionModal(session)} onSelect={onSessionSelect} - onRefreshSessions={loadSessions} // Pass the refresh function - onOpenNewSessionModal={() => handleOpenNewSessionModal()} // Pass function to open modal + onRefreshSessions={loadSessions} + onOpenNewSessionModal={() => handleOpenNewSessionModal()} /> )} diff --git a/DashAI/front/src/pages/generative/RAG/RAGSessionsTable.jsx b/DashAI/front/src/pages/generative/RAG/RAGSessionsTable.jsx index 35d5ff01a..db74d0e25 100644 --- a/DashAI/front/src/pages/generative/RAG/RAGSessionsTable.jsx +++ b/DashAI/front/src/pages/generative/RAG/RAGSessionsTable.jsx @@ -7,7 +7,7 @@ import { DeleteOutline as DeleteIcon, Visibility as ViewDocsIcon } from "@mui/icons-material"; -import { DataGrid } from "@mui/x-data-grid"; // Removed GridToolbar as it's not strictly essential for basic rendering +import { DataGrid } from "@mui/x-data-grid"; import { Button, Grid, @@ -16,25 +16,15 @@ import { LinearProgress, } from "@mui/material"; -import { deleteRAGSession } from "../../../api/rag"; // Assuming this API call is correct +import { deleteRAGSession } from "../../../api/rag"; -// Removed ConfirmDialog component as requested. -// Removed useSnackbar import and usage. export default function RAGSessionsTable({ sessions, onSelect, onEdit, - // Removed onRefreshSessions prop as it's not needed in this simplified version onOpenNewSessionModal }) { - // Removed local 'loading' state for operations within the table, - // as the parent RAGHomePage handles the main loading. - // Removed showConfirmDelete and sessionToDelete states. - - - // Removed handleDeleteSession function as its logic involved removed features. - // The delete button will now just call the API directly (or a simplified parent handler). const columns = [ { @@ -45,28 +35,33 @@ export default function RAGSessionsTable({ ) }, { - field: "created_at", + field: "created", headerName: "Created At", - flex: 1, + flex: 0.8, valueFormatter: (params) => new Date(params.value).toLocaleString() }, { - field: "documents", + field: "", headerName: "Documents", - flex: 0.7, - valueGetter: (params) => params.row.documents?.length || 0 + flex: 0.6, + valueGetter: (params) => params.row.parameters.documents.length }, { field: "actions", headerName: "Actions", - flex: 1.5, + flex: 1.1, renderCell: (params) => (
- {/* Simplified Delete button: It will now rely on a parent handler or direct API call */} + + + + )} + + ); +} + +DocumentSelectionTable.propTypes = { + documents: PropTypes.arrayOf(PropTypes.shape({ + id: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + createdAt: PropTypes.string.isRequired, + preview: PropTypes.string, + })).isRequired, + selectedIds: PropTypes.arrayOf(PropTypes.string).isRequired, + onToggle: PropTypes.func.isRequired, + onSelectAll: PropTypes.func.isRequired, + onDeselectAll: PropTypes.func.isRequired, + onRemove: PropTypes.func.isRequired, + isLoading: PropTypes.bool, +}; diff --git a/DashAI/front/src/components/generative/RAG/DocumentSelector.jsx b/DashAI/front/src/components/generative/RAG/DocumentSelector.jsx index c1f133863..95eca15fc 100644 --- a/DashAI/front/src/components/generative/RAG/DocumentSelector.jsx +++ b/DashAI/front/src/components/generative/RAG/DocumentSelector.jsx @@ -1,7 +1,7 @@ import { Box } from "@mui/material"; import { useEffect, useState, useCallback, useRef } from "react"; // Added useRef import PropTypes from "prop-types"; -import DocumentTable from "./DocumentTable"; +import DocumentSelectionTable from "./DocumentSelectionTable"; import Upload from "../../shared/Upload"; import { loadDocuments, addDocument, deleteDocument } from "../../../api/rag"; @@ -107,7 +107,7 @@ export default function DocumentSelector({ return ( - { try { const date = new Date(dateString); - return date.toLocaleString(); + return date.toLocaleDateString(); } catch (e) { return dateString; } }; + const onPreview = (previewUrl) => { + if (previewUrl) { + window.open(previewUrl, '_blank'); + } else { + console.warn("No preview URL available for this document."); + } + } + + const onEdit = (id) => { + console.warn("Edit functionality is not implemented yet for document ID:", id); + } + + + + const columns = [ + { field: 'id', headerName: 'Id', flex: 0.1 }, + { field: 'file_name', headerName: 'Name', flex: 0.6, minWidth: 150 }, + { + field: 'created', + headerName: 'Added On', + flex: 0.4, + valueFormatter: (params) => formatDate(params.value), + }, + { + field: 'last_modified', + headerName: 'Last Modified', + flex: 0.4, + valueGetter: (params) => params.row.optional_metadata?.last_modified, + valueFormatter: (params) => formatDate(params.value), + }, + { + field: 'actions', + headerName: 'Actions', + flex: 0.5, + renderCell: (params) => ( +
+ + +
+ ), + }, + ]; + return ( - - {isLoading ? ( - - - - ) : documents.length === 0 ? ( + + {tableTitle && ( + + {tableTitle} + + )} + {documents.length === 0 && !isLoading ? ( No documents available. ) : ( - <> - - - - - 0 && selectedIds.length < documents.length} - checked={selectedIds.length === documents.length && documents.length > 0} - onChange={(event) => { - if (event.target.checked) { - onSelectAll(); - } else { - onDeselectAll(); - } - }} - /> - - Id - Name - Added On - Last Modified - Actions - - - - {documents.map((doc) => ( - - - onToggle(doc.id)} - /> - - {doc.id} - {doc.file_name} - {formatDate(doc.created)} - {doc.optional_metadata?.last_modified ? formatDate(doc.optional_metadata.last_modified) : "N/A"} - - - - { - if (doc.preview) window.open(doc.preview, '_blank'); - else console.warn("No preview URL available for this document."); - }}> - - - - - onRemove(doc.id)}> - - - - - - - ))} - -
- - - - - + row.id} + sx={{ + "& .MuiDataGrid-cell:focus": { outline: "none" }, + minHeight: 300, + }} + /> )} -
+ ); } @@ -145,10 +136,6 @@ DocumentTable.propTypes = { createdAt: PropTypes.string.isRequired, preview: PropTypes.string, })).isRequired, - selectedIds: PropTypes.arrayOf(PropTypes.string).isRequired, - onToggle: PropTypes.func.isRequired, - onSelectAll: PropTypes.func.isRequired, - onDeselectAll: PropTypes.func.isRequired, onRemove: PropTypes.func.isRequired, isLoading: PropTypes.bool, }; diff --git a/DashAI/front/src/pages/generative/Generative.jsx b/DashAI/front/src/pages/generative/Generative.jsx index 6460d8597..48dd66cf6 100644 --- a/DashAI/front/src/pages/generative/Generative.jsx +++ b/DashAI/front/src/pages/generative/Generative.jsx @@ -56,7 +56,7 @@ export default function Generative() { } setSessions((prevSessions) => - prevSessions.filter((session) => session.id !== id) + prevSessions.filter((session) => session.id !== id), ); removeSession(id); @@ -90,44 +90,41 @@ export default function Generative() { setSelectedTaskName(taskName); setStepIndex(1); }} - /> - ) : isRAGTask() ? ( - - ) : ( - setStepIndex(0)} - handleAddSession={handleAddSession} - selectedTaskName={selectedTaskName} - selectedDisplayName={selectedDisplayName} - setSelectedSessionId={setSelectedSessionId} - /> - )} - -
+ /> + ) : isRAGTask() ? ( + + ) : ( + setStepIndex(0)} + handleAddSession={handleAddSession} + selectedTaskName={selectedTaskName} + selectedDisplayName={selectedDisplayName} + setSelectedSessionId={setSelectedSessionId} + /> + )} + +
- {!isRAGTask() && ( - - - {!selectedSessionId ? - ( + {!isRAGTask() && ( + + + {!selectedSessionId ? ( - ): null} + ) : null} + - - ) - } + )} ); } - \ No newline at end of file diff --git a/DashAI/front/src/pages/generative/RAG/RAGHomePage.jsx b/DashAI/front/src/pages/generative/RAG/RAGHomePage.jsx index 11f670bbe..4930043a7 100644 --- a/DashAI/front/src/pages/generative/RAG/RAGHomePage.jsx +++ b/DashAI/front/src/pages/generative/RAG/RAGHomePage.jsx @@ -1,15 +1,18 @@ -import React, { useState, useEffect } from 'react'; -import { Box, Button, CircularProgress, Typography } from '@mui/material'; -import CustomLayout from '../../../components/custom/CustomLayout'; -import NewSessionModal from './NewSessionModal'; -import RAGSessionsTable from './RAGSessionsTable'; -import { getRAGSessions, createRAGSession } from '../../../api/rag'; +import React, { useState, useEffect, useCallback } from "react"; +import { Box, Button, CircularProgress, Typography } from "@mui/material"; +import NewSessionModal from "./NewSessionModal"; +import RAGSessionsTable from "./RAGSessionsTable"; +import { getRAGSessions, createRAGSession, loadDocuments, deleteDocument } from "../../../api/rag"; +import DocumentTable from "../../../components/generative/RAG/DocumentTable"; + function RAGHomePage({ onSessionCreated, onSessionSelect }) { const [showModal, setShowModal] = useState(false); const [sessions, setSessions] = useState([]); const [loading, setLoading] = useState(true); const [editingSession, setEditingSession] = useState(null); + const [allDocuments, setAllDocuments] = useState([]); + const [documentsLoading, setDocumentsLoading] = useState(true); const loadSessions = async () => { setLoading(true); @@ -19,17 +22,30 @@ function RAGHomePage({ onSessionCreated, onSessionSelect }) { } catch (error) { console.error("RAGHomePage: Error loading RAG sessions:", error); } finally { - setLoading(false); + setLoading(false); } }; + const fetchAllDocuments = useCallback(async () => { + setDocumentsLoading(true); + try { + const docs = await loadDocuments(); + setAllDocuments(docs); + } catch (error) { + console.error("RAGHomePage: Error loading all documents:", error); + } finally { + setDocumentsLoading(false); + } + }, []); + useEffect(() => { loadSessions(); - }, []); + fetchAllDocuments(); + }, [fetchAllDocuments]); const handleOpenNewSessionModal = (session = null) => { setEditingSession(session); - setShowModal(true); + setShowModal(true); }; const handleCreateOrUpdateSession = async (sessionData) => { @@ -39,30 +55,41 @@ function RAGHomePage({ onSessionCreated, onSessionSelect }) { await loadSessions(); onSessionCreated(savedSession); - setShowModal(false); - - return savedSession; + setShowModal(false); + return savedSession; } catch (error) { throw error; } }; + const handleRemoveDocumentFromTable = useCallback(async (id) => { + try { + await deleteDocument(id); + await fetchAllDocuments(); + } catch (error) { + console.error("RAGHomePage: Failed to delete document:", error); + } + }, [fetchAllDocuments]); + return ( - handleOpenNewSessionModal()} - sx={{ textTransform: 'none' }} - > - New Session - - } + + + RAG Sessions + + + Manage your RAG sessions + { @@ -83,11 +110,23 @@ function RAGHomePage({ onSessionCreated, onSessionSelect }) { sessions={sessions} onEdit={(session) => handleOpenNewSessionModal(session)} onSelect={onSessionSelect} - onRefreshSessions={loadSessions} + onRefreshSessions={loadSessions} onOpenNewSessionModal={() => handleOpenNewSessionModal()} /> )} - + + + Documents + + + Manage documents for your RAG sessions + + + ); } diff --git a/DashAI/front/src/pages/generative/RAG/RAGSessionsTable.jsx b/DashAI/front/src/pages/generative/RAG/RAGSessionsTable.jsx index db74d0e25..8cde0a3e9 100644 --- a/DashAI/front/src/pages/generative/RAG/RAGSessionsTable.jsx +++ b/DashAI/front/src/pages/generative/RAG/RAGSessionsTable.jsx @@ -4,83 +4,83 @@ import PropTypes from "prop-types"; import { AddCircleOutline as AddIcon, Update as UpdateIcon, + Edit as EditIcon, DeleteOutline as DeleteIcon, - Visibility as ViewDocsIcon + Visibility as ViewDocsIcon, } from "@mui/icons-material"; + import { DataGrid } from "@mui/x-data-grid"; -import { - Button, - Grid, - Paper, - Typography, - LinearProgress, -} from "@mui/material"; +import { Button, Grid, Paper, Typography, LinearProgress } from "@mui/material"; import { deleteRAGSession } from "../../../api/rag"; - export default function RAGSessionsTable({ sessions, onSelect, onEdit, - onOpenNewSessionModal + onOpenNewSessionModal, + showTableTitle = false, }) { - const columns = [ { field: "name", headerName: "Session Name", - flex: 1, + flex: 0.8, renderCell: (params) => ( - ) + ), }, { field: "created", headerName: "Created At", - flex: 0.8, - valueFormatter: (params) => new Date(params.value).toLocaleString() + flex: 0.4, + valueFormatter: (params) => new Date(params.value).toLocaleDateString(), }, { field: "", headerName: "Documents", - flex: 0.6, - valueGetter: (params) => params.row.parameters.documents.length + flex: 0.4, + valueGetter: (params) => params.row.parameters.documents.length, }, { field: "actions", headerName: "Actions", - flex: 1.1, + flex: 0.9, renderCell: (params) => ( -
+
- ) - } + ), + }, ]; return ( - - - - RAG Sessions - - - - + + RAG Sessions + + + + )} row.id} sx={{ - '& .MuiDataGrid-cell:focus': { outline: 'none' }, - minHeight: 400 + "& .MuiDataGrid-cell:focus": { outline: "none" }, + minHeight: 300, }} /> - + {!showTableTitle && ( + + )} ); } @@ -150,7 +164,7 @@ RAGSessionsTable.propTypes = { created_at: PropTypes.string.isRequired, documents: PropTypes.array, task_name: PropTypes.string, - }) + }), ).isRequired, onSelect: PropTypes.func.isRequired, onEdit: PropTypes.func.isRequired, From 2a45b2ac88d2e260a9ac836b31e50e1fe20d4382 Mon Sep 17 00:00:00 2001 From: sofiachavezb Date: Tue, 15 Jul 2025 21:47:02 -0400 Subject: [PATCH 006/218] RAG session creation updated --- .../api_v1/endpoints/generative_session.py | 46 +++++++++++++++---- DashAI/back/models/RAG/RAG_pipeline.py | 4 +- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/DashAI/back/api/api_v1/endpoints/generative_session.py b/DashAI/back/api/api_v1/endpoints/generative_session.py index aa9765ee8..4fb69e27d 100644 --- a/DashAI/back/api/api_v1/endpoints/generative_session.py +++ b/DashAI/back/api/api_v1/endpoints/generative_session.py @@ -14,11 +14,13 @@ GenerativeSession, GenerativeSessionParameterHistory, ProcessData, + Document ) from DashAI.back.dependencies.registry import ComponentRegistry from DashAI.back.models import BaseGenerativeModel from DashAI.back.tasks import BaseGenerativeTask +from DashAI.back.tasks.RAG_task import RAGTask router = APIRouter() log = logging.getLogger(__name__) @@ -50,22 +52,50 @@ async def upload_generative_session( f"generative model.", ) - # Validate the model parameters + # Check if the task is registered try: - model_class.SCHEMA.model_validate(params.parameters) - except ValueError as e: + task_class = component_registry[params.task_name]["class"] + except KeyError as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=f"Invalid parameters for model {params.model_name}: {e}", + detail=f"Task {params.task_name} is not registered.", ) from e + + # RAG Task specific handling + # Frontend will send the ids of the documents to be used in the RAG session + # but RAG pipeline expects the documents paths of the backend-stored documents + if task_class == RAGTask: + try: + assert params.parameters["documents"] + assert isinstance(params.parameters["documents"], list) + assert len(params.parameters["documents"]) > 0 + + except (AssertionError, KeyError): + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="RAG Task requires a non-empty list of document IDs.", + ) + + documents_paths = [] + for doc_id in params.parameters["documents"]: + doc = db.get(Document, doc_id) + if not doc: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Document with ID {doc_id} not found.", + ) + documents_paths.append(doc.file_path) - # Check if the task is registered + params.parameters["documents"] = documents_paths + # Continue with the session creation + + # Validate the model parameters try: - task_class = component_registry[params.task_name]["class"] - except KeyError as e: + model_class.SCHEMA.model_validate(params.parameters) + except ValueError as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=f"Task {params.task_name} is not registered.", + detail=f"Invalid parameters for model {params.model_name}: {e}", ) from e # Check if the task is a subclass of BaseGenerativeTask diff --git a/DashAI/back/models/RAG/RAG_pipeline.py b/DashAI/back/models/RAG/RAG_pipeline.py index 83300d24c..c7713c922 100644 --- a/DashAI/back/models/RAG/RAG_pipeline.py +++ b/DashAI/back/models/RAG/RAG_pipeline.py @@ -5,7 +5,7 @@ component_field, schema_field, list_field, - int_field + string_field ) from DashAI.back.models.base_generative_model import BaseGenerativeModel @@ -41,7 +41,7 @@ class RAGPipelineSchema(BaseSchema): # Document collection parameters documents: schema_field( list_field( - int_field(), + string_field(), min_items=1, ), placeholder=None, From 6e29b7748c14da10ecd663f07732ee3ebe9deda9 Mon Sep 17 00:00:00 2001 From: sofiachavezb Date: Mon, 21 Jul 2025 17:54:42 -0400 Subject: [PATCH 007/218] tfidf embedding implemented as a configurable object --- .../back/models/RAG/Documents/BaseDocument.py | 88 ++- .../back/models/RAG/Documents/PDFDocument.py | 62 +- .../back/models/RAG/Documents/TxtDocument.py | 62 +- .../models/RAG/Retrievers/BaseRetriever.py | 2 +- .../models/RAG/Retrievers/TFIDFRetriever.py | 2 +- .../chunking_models/base_chunking_model.py | 28 + .../chunking_models/character_chunk_model.py | 58 ++ .../models/RAG/embeddings/base_embedding.py | 70 ++ .../models/RAG/embeddings/dense_embedding.py | 22 + .../models/RAG/embeddings/sparse_embedding.py | 29 + .../models/RAG/embeddings/tf_idf_embedding.py | 357 +++++++++ .../tf_idf_encoding.py | 0 DashAI/back/models/RAG/utils.py | 0 .../feature_names.pkl | Bin 0 -> 1577 bytes .../term_matrix.pkl | Bin 0 -> 2244 bytes .../vectorizer.pkl | Bin 0 -> 4710 bytes Untitled-1.ipynb | 690 ++++++++++++++++++ dummy_texts.txt | 6 + term_matrix.pkl | Bin 0 -> 2244 bytes 19 files changed, 1370 insertions(+), 106 deletions(-) create mode 100644 DashAI/back/models/RAG/chunking_models/base_chunking_model.py create mode 100644 DashAI/back/models/RAG/chunking_models/character_chunk_model.py create mode 100644 DashAI/back/models/RAG/embeddings/base_embedding.py create mode 100644 DashAI/back/models/RAG/embeddings/dense_embedding.py create mode 100644 DashAI/back/models/RAG/embeddings/sparse_embedding.py create mode 100644 DashAI/back/models/RAG/embeddings/tf_idf_embedding.py rename DashAI/back/models/RAG/{encodings => embeddings}/tf_idf_encoding.py (100%) create mode 100644 DashAI/back/models/RAG/utils.py create mode 100644 RAG/embeddings/c64d87e82535789c183ba885c1274d38fb9e6704d99f02ce7f3cb03d1d444709/feature_names.pkl create mode 100644 RAG/embeddings/c64d87e82535789c183ba885c1274d38fb9e6704d99f02ce7f3cb03d1d444709/term_matrix.pkl create mode 100644 RAG/embeddings/c64d87e82535789c183ba885c1274d38fb9e6704d99f02ce7f3cb03d1d444709/vectorizer.pkl create mode 100644 Untitled-1.ipynb create mode 100644 dummy_texts.txt create mode 100644 term_matrix.pkl diff --git a/DashAI/back/models/RAG/Documents/BaseDocument.py b/DashAI/back/models/RAG/Documents/BaseDocument.py index f54db39db..3f8c3b4fc 100644 --- a/DashAI/back/models/RAG/Documents/BaseDocument.py +++ b/DashAI/back/models/RAG/Documents/BaseDocument.py @@ -7,12 +7,32 @@ class BaseDocument(ABC): Base class for documents. """ - def __init__(self, *args, **kwargs): + def __init__( + self, + id: int, + file_name: str, + file_path: str, + file_hash: str, + created: Optional[str] = None, + optional_metadata: Optional[Dict[str, Any]] = None + ): """ Initialize the document. - """ - pass - + Args (from database): + id (int): The unique identifier of the document. + file_name (str): The name of the file. + file_path (str): The path to the file. + file_hash (str): A hash of the file content. + created (Optional[str]): The creation date of the document. + optional_metadata (Optional[Dict[str, Any]]): Additional metadata for the document. + """ + self.id = id + self.file_name = file_name + self.file_path = file_path + self.file_hash = file_hash + self.created = created if created else None + self.optional_metadata = optional_metadata if optional_metadata else None + def get_text(self) -> str: """ Get the text content of the document. @@ -29,7 +49,7 @@ def get_text_length(self) -> int: Returns: int: The length of the text content of the document. """ - raise NotImplementedError("This method should be implemented by subclasses.") + return len(self.get_text()) def get_metadata(self) -> Dict[str, Any]: """ @@ -40,63 +60,51 @@ def get_metadata(self) -> Dict[str, Any]: """ raise NotImplementedError("This method should be implemented by subclasses.") - def get_filename(self) -> Optional[str]: + def get_id(self) -> int: """ - Get the filename of the document. + Get the unique identifier of the document. Returns: - Optional[str]: The filename of the document, or None if not applicable. + int: The unique identifier of the document. """ - raise NotImplementedError("This method should be implemented by subclasses.") - - def get_filetype(self) -> Optional[str]: + return self.id + + def get_file_name(self) -> Optional[str]: """ - Get the filetype of the document. + Get the filename of the document. Returns: - Optional[str]: The filetype of the document, or None if not applicable. + Optional[str]: The filename of the document, or None if not applicable. """ - raise NotImplementedError("This method should be implemented by subclasses.") + return self.file_name - def get_file_location(self) -> Optional[str]: + def get_file_path(self) -> Optional[str]: """ - Get the file location of the document. + Get the file path of the document. Returns: - Optional[str]: The file location of the document, or None if not applicable. + Optional[str]: The file path of the document, or None if not applicable. """ - raise NotImplementedError("This method should be implemented by subclasses.") + return self.file_path - def get_chunks(self, chunk_size: int, chunk_overlap: int) -> List[str]: + def get_file_hash(self) -> str: """ - Get the document text split into chunks. - - Args: - chunk_size (int): The size of each chunk. - chunk_overlap (int): The overlap between chunks. + Get the hash of the document content. Returns: - List[str]: A list of text chunks. - """ - text = self.get_text() - chunks = [] - start = 0 - while start < len(text): - end = min(start + chunk_size, len(text)) - chunks.append(text[start:end]) - start += chunk_size - chunk_overlap - return chunks + str: A hash string representing the document content. + """ + return self.file_hash - def get_hash(self) -> str: + def get_file_type(self) -> Optional[str]: """ - Get a hash of the document content. + Get the filetype of the document. Returns: - str: A hash string representing the document content. + Optional[str]: The filetype of the document, or None if not applicable. """ - text = self.get_text() - return hashlib.sha256(text.encode('utf-8')).hexdigest() if text else '' + return self.file_path.split('.')[-1] def __repr__(self): - return f"BaseDocument(filename='{self.get_filename()}', content='{self.get_text()[:50]}...', metadata={self.get_metadata()})" + return f"BaseDocument(filename='{self.get_file_name()}', content='{self.get_text()[:50]}...', metadata={self.get_metadata()})" diff --git a/DashAI/back/models/RAG/Documents/PDFDocument.py b/DashAI/back/models/RAG/Documents/PDFDocument.py index ca2ecb059..48dba5258 100644 --- a/DashAI/back/models/RAG/Documents/PDFDocument.py +++ b/DashAI/back/models/RAG/Documents/PDFDocument.py @@ -1,33 +1,40 @@ from .BaseDocument import BaseDocument import os from PyPDF2 import PdfReader -import base64 +from typing import Optional, Dict, Any class PDFDocument(BaseDocument): """ Class representing a PDF document. """ - def __init__(self, file_path: str): + def __init__( + self, + id: int, + file_name: str, + file_path: str, + file_hash: str, + created: Optional[str] = None, + optional_metadata: Optional[Dict[str, Any]] = None + ): """ - Initialize the PDF document with the file path. - - Args: - file_path (str): The path to the PDF file. + Initialize the document. + Args (from database): + id (int): The unique identifier of the document. + file_name (str): The name of the file. + file_path (str): The path to the file. + file_hash (str): A hash of the file content. + created (Optional[str]): The creation date of the document. + optional_metadata (Optional[Dict[str, Any]]): Additional metadata for the document. """ - - assert os.path.exists(file_path), f"File {file_path} does not exist." - - self.file_path = file_path - self.metadata = { - "file_path": file_path, - "filetype": "pdf", - "filename": os.path.basename(file_path), - } - self.file_path = file_path - self.filename = os.path.basename(file_path) - self.filetype = "pdf" - self.text_length = len(self.get_text()) + super().__init__( + id=id, + file_name=file_name, + file_path=file_path, + file_hash=file_hash, + created=created, + optional_metadata=optional_metadata + ) def get_text(self) -> str: reader = PdfReader(self.file_path) @@ -41,18 +48,5 @@ def get_text(self) -> str: return text.strip() - def get_text_length(self) -> int: - return self.text_length - - def get_metadata(self) -> dict: - return self.metadata - - def get_filename(self) -> str: - return self.filename - - def get_filetype(self) -> str: - return self.filetype - - def get_file_location(self) -> str: - return self.file_path - \ No newline at end of file + def get_metadata(self): + return self.metadata \ No newline at end of file diff --git a/DashAI/back/models/RAG/Documents/TxtDocument.py b/DashAI/back/models/RAG/Documents/TxtDocument.py index f8f7f58a7..fb5507d94 100644 --- a/DashAI/back/models/RAG/Documents/TxtDocument.py +++ b/DashAI/back/models/RAG/Documents/TxtDocument.py @@ -7,25 +7,33 @@ class TxtDocument(BaseDocument): Class representing a .txt document. """ - def __init__(self, file_path: str): + def __init__( + self, + id: int, + file_name: str, + file_path: str, + file_hash: str, + created: Optional[str] = None, + optional_metadata: Optional[Dict[str, Any]] = None + ): """ - Initialize the text document with the file path. - - Args: - file_path (str): The path to the text file. + Initialize the document. + Args (from database): + id (int): The unique identifier of the document. + file_name (str): The name of the file. + file_path (str): The path to the file. + file_hash (str): A hash of the file content. + created (Optional[str]): The creation date of the document. + optional_metadata (Optional[Dict[str, Any]]): Additional metadata for the document. """ - assert os.path.exists(file_path), f"File {file_path} does not exist." - - self.file_path = file_path - self.filename = os.path.basename(file_path) - self.filetype = "txt" - self.text_length = len(self.text) - self.metadata = { - "file_path": file_path, - "filetype": self.filetype, - "filename": self.filename, - } - self.text_length = len(self.get_text()) + super().__init__( + id=id, + file_name=file_name, + file_path=file_path, + file_hash=file_hash, + created=created, + optional_metadata=optional_metadata + ) def get_text(self) -> str: """ @@ -38,17 +46,11 @@ def get_text(self) -> str: text = file.read() return text.strip() - def get_text_length(self) -> int: - return self.text_length - def get_metadata(self) -> Dict[str, Any]: - return self.metadata - - def get_filename(self) -> str: - return self.filename - - def get_filetype(self) -> str: - return self.filetype - - def get_file_location(self) -> str: - return self.file_path \ No newline at end of file + """ + Get the metadata of the document. + + Returns: + Dict[str, Any]: The metadata of the document. + """ + return self.optional_metadata if self.optional_metadata else {} \ No newline at end of file diff --git a/DashAI/back/models/RAG/Retrievers/BaseRetriever.py b/DashAI/back/models/RAG/Retrievers/BaseRetriever.py index e12143378..3385a5467 100644 --- a/DashAI/back/models/RAG/Retrievers/BaseRetriever.py +++ b/DashAI/back/models/RAG/Retrievers/BaseRetriever.py @@ -1,7 +1,7 @@ from abc import ABC import os from typing import Any, Dict, List, Final -from DashAI.back.models.RAG.Documents import BaseDocument, PDFDocument, TxtDocument +from DashAI.back.models.RAG.documents import BaseDocument, PDFDocument, TxtDocument from DashAI.back.config_object import ConfigObject import hashlib diff --git a/DashAI/back/models/RAG/Retrievers/TFIDFRetriever.py b/DashAI/back/models/RAG/Retrievers/TFIDFRetriever.py index f6a005ff0..e60734aac 100644 --- a/DashAI/back/models/RAG/Retrievers/TFIDFRetriever.py +++ b/DashAI/back/models/RAG/Retrievers/TFIDFRetriever.py @@ -1,6 +1,6 @@ import os from .BaseRetriever import BaseRetriever -from DashAI.back.models.RAG.Documents import BaseDocument, PDFDocument, TxtDocument +from DashAI.back.models.RAG.documents import BaseDocument, PDFDocument, TxtDocument from typing import List, Dict, Any, Optional, Tuple from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.pairwise import cosine_similarity, euclidean_distances diff --git a/DashAI/back/models/RAG/chunking_models/base_chunking_model.py b/DashAI/back/models/RAG/chunking_models/base_chunking_model.py new file mode 100644 index 000000000..648483a6b --- /dev/null +++ b/DashAI/back/models/RAG/chunking_models/base_chunking_model.py @@ -0,0 +1,28 @@ +from abc import ABCMeta, abstractmethod +from DashAI.back.config_object import ConfigObject +from DashAI.back.models.RAG.documents.BaseDocument import BaseDocument +from typing import Final, List + +class BaseChunkingModel(ConfigObject, metaclass=ABCMeta): + """ + Base class for chunking models. + This class should be inherited by any specific chunking model implementation. + """ + + TYPE: Final[str] = "ChunkingModel" + + def __init__(self, **kwargs): + """ + Initialize the chunking model with any necessary parameters. + """ + raise NotImplementedError("Subclasses must implement the __init__ method.") + + @abstractmethod + def chunk(self, document: BaseDocument, **kwargs) -> List[str]: + """ + Method to be implemented by subclasses to perform document chunking. + + :param document: The input document to be chunked. + :return: A list of text chunks. + """ + raise NotImplementedError("Subclasses must implement this method.") \ No newline at end of file diff --git a/DashAI/back/models/RAG/chunking_models/character_chunk_model.py b/DashAI/back/models/RAG/chunking_models/character_chunk_model.py new file mode 100644 index 000000000..dca1a203d --- /dev/null +++ b/DashAI/back/models/RAG/chunking_models/character_chunk_model.py @@ -0,0 +1,58 @@ +from DashAI.back.models.RAG.chunking_models.base_chunking_model import BaseChunkingModel +from DashAI.back.models.RAG.documents.BaseDocument import BaseDocument +from typing import List +from DashAI.back.core.schema_fields import ( + BaseSchema, + schema_field, + int_field, +) + +class CharacterChunkModelSchema(BaseSchema): + """Schema for character-based chunking model.""" + + chunk_size: schema_field( + int_field(min_value=1), + placeholder=None, + description="Size of each chunk in characters." + ) # type: ignore + + chunk_overlap: schema_field( + int_field(min_value=0), + placeholder=None, + description="Number of characters to overlap between chunks." + ) # type: ignore + +class CharacterChunkModel(BaseChunkingModel): + """ + Chunking model that splits documents into chunks based on character count. + This model is useful for processing large text documents into manageable pieces. + """ + SCHEMA = CharacterChunkModelSchema + + def __init__(self, chunk_size: int, chunk_overlap: int): + """ + Initialize the character chunking model with the specified chunk size and overlap. + + :param chunk_size: Size of each chunk in characters. + :param chunk_overlap: Number of characters to overlap between chunks. + """ + self.chunk_size = chunk_size + self.chunk_overlap = chunk_overlap + + def chunk(self, document: BaseDocument) -> List[str]: + """ + Split the document into chunks based on character count. + + :param document: The input document to be chunked. + :return: A list of text chunks. + """ + text = document.get_text() + chunks = [] + start = 0 + + while start < len(text): + end = min(start + self.chunk_size, len(text)) + chunks.append(text[start:end]) + start += self.chunk_size - self.chunk_overlap + + return chunks \ No newline at end of file diff --git a/DashAI/back/models/RAG/embeddings/base_embedding.py b/DashAI/back/models/RAG/embeddings/base_embedding.py new file mode 100644 index 000000000..025e112a6 --- /dev/null +++ b/DashAI/back/models/RAG/embeddings/base_embedding.py @@ -0,0 +1,70 @@ +from abc import ABCMeta +import hashlib +from DashAI.back.config_object import ConfigObject +from typing import Any, List +import numpy as np + +from DashAI.back.models.RAG.documents.BaseDocument import BaseDocument + +class BaseEmbedding(ConfigObject, metaclass=ABCMeta): + """ + Base class for all embedding models. + This class should be inherited by any specific embedding model implementation. + """ + EMBEDDINGS_PATH = "RAG/embeddings" + + def __init__( + self, + documents: List[BaseDocument], + **kwargs: Any): + """ + Initialize the embedding model with the given documents. + """ + raise NotImplementedError("Subclasses must implement the __init__ method.") + + def _calculate_embeddings_hash(self) -> str: + """ + Generate a hash to identify the embeddings for caching purposes. + + Hash is calculated over the documents' content to ensure consistency in embeddings, it must: + - Be consistent across runs with the same documents content, chunking strategy and embedding model parameters. + - Change if the documents are modified. + - Change if the documents content is modified. + - Change if the chunking strategy is modified. + - Change if the embedding model parameters are modified. + + Returns: + str: A hash string representing the embeddings. + """ + raise NotImplementedError("Subclasses must implement this method.") + + def _calculate_documents_chunks_hash(self) -> str: + """ + Generate a hash to identify the documents chunks' texts for caching purposes. + + Hash is calculated over the chunks' texts to ensure consistency in embeddings, it must: + - Be consistent across runs with the same documents content and chunking strategy. + - Change if the documents are modified. + - Change if the documents content is modified. + - Change if the chunking strategy is modified. + + Returns: + str: A hash string representing the documents chunks. + """ + joint_text = "" + self.documents_chunks = sorted(self.documents_chunks.items()) + for doc_id in self.documents_chunks.keys(): + for i, chunk in enumerate(self.documents_chunks[doc_id]): + joint_text += f"{doc_id}_{i}:{chunk}\n" + + return hashlib.sha256(joint_text.encode('utf-8')).hexdigest() + + def embed(self, text: str) -> List[float]|np.ndarray|Any: + """ + Method to generate embeddings for the given text. + This method should be implemented by subclasses. + + :param text: The input text to embed. + :return: A list representing the embeddings of the input text. + """ + raise NotImplementedError("Subclasses must implement this method.") \ No newline at end of file diff --git a/DashAI/back/models/RAG/embeddings/dense_embedding.py b/DashAI/back/models/RAG/embeddings/dense_embedding.py new file mode 100644 index 000000000..39a585636 --- /dev/null +++ b/DashAI/back/models/RAG/embeddings/dense_embedding.py @@ -0,0 +1,22 @@ +from DashAI.back.models.RAG.embeddings.base_embedding import BaseEmbedding +from typing import Any, List +import numpy as np + +class DenseEmbedding(BaseEmbedding): + """ + Base class for dense embedding models. + This class should be inherited by any specific dense embedding model implementation. + """ + + def __init__(self): + super().__init__() + + def embed(self, text: str) -> List|np.ndarray|Any: + """ + Method to generate dense embeddings for the given text. + This method should be implemented by subclasses. + + :param text: The input text to embed. + :return: A list representing the dense embeddings of the input text. + """ + raise NotImplementedError("Subclasses must implement this method.") \ No newline at end of file diff --git a/DashAI/back/models/RAG/embeddings/sparse_embedding.py b/DashAI/back/models/RAG/embeddings/sparse_embedding.py new file mode 100644 index 000000000..706295673 --- /dev/null +++ b/DashAI/back/models/RAG/embeddings/sparse_embedding.py @@ -0,0 +1,29 @@ +import numpy as np +from DashAI.back.models.RAG.documents import BaseDocument +from DashAI.back.models.RAG.embeddings.base_embedding import BaseEmbedding +from typing import Any, List + +class SparseEmbedding(BaseEmbedding): + """ + Base class for sparse embedding models. + This class should be inherited by any specific sparse embedding model implementation. + """ + + def __init__(self, documents: List[BaseDocument], **kwargs: Any): + """ + Initialize the sparse embedding model with the given documents. + + :param documents: List of documents to be embedded. + :param kwargs: Additional keyword arguments. + """ + raise NotImplementedError("Subclasses must implement the __init__ method.") + + def embed(self, text: str) -> List|np.ndarray|Any: + """ + Method to generate sparse embeddings for the given text. + This method should be implemented by subclasses. + + :param text: The input text to embed. + :return: A list representing the sparse embeddings of the input text. + """ + raise NotImplementedError("Subclasses must implement this method.") \ No newline at end of file diff --git a/DashAI/back/models/RAG/embeddings/tf_idf_embedding.py b/DashAI/back/models/RAG/embeddings/tf_idf_embedding.py new file mode 100644 index 000000000..cfdb9ed5b --- /dev/null +++ b/DashAI/back/models/RAG/embeddings/tf_idf_embedding.py @@ -0,0 +1,357 @@ +import os +from DashAI.back.models.RAG.embeddings.sparse_embedding import SparseEmbedding +from DashAI.back.models.RAG.documents import BaseDocument, PDFDocument, TxtDocument +from typing import List, Dict, Any, Tuple +from sklearn.feature_extraction.text import TfidfVectorizer +from sklearn.metrics.pairwise import cosine_similarity, euclidean_distances +import numpy as np +import hashlib +import pickle + +from DashAI.back.core.schema_fields import ( + BaseSchema, + list_field, + schema_field, + enum_field, + float_field, + int_field, + bool_field, + string_field +) + +class TFIDFEmbeddingSchema(BaseSchema): + + strip_accents: schema_field( + enum_field( + enum=["ascii", "unicode", None], + ), + placeholder=None, + description="Whether to strip accents from the text.", + ) # type: ignore + + lowercase: schema_field( + bool_field(), + placeholder=True, + description="Whether to convert all characters to lowercase.", + + ) # type: ignore + + analyzer: schema_field( + enum_field( + enum=["word", "char", "char_wb"], + ), + placeholder="word", + description="Whether the feature should be made of word or character n-grams. Option 'char_wb' creates character n-grams only from text inside word boundaries; n-grams at the edges of words are padded with space.", + ) # type: ignore + + stop_words: schema_field( + list_field( + string_field(), + min_items=1, + ), + placeholder=None, + description="List of stop words to be used in the TF-IDF vectorization.", + ) # type: ignore + + ngram_range: schema_field( + list_field( + int_field(), + min_items=2, + max_items=2, + ), + placeholder=[1, 1], + description="The lower and upper boundary of the range of n-values for different n-grams to be extracted.", + ) # type: ignore + + max_df: schema_field( + float_field( + ge=0.0, + le=1.0, + ), + placeholder=1.0, + description="When building the vocabulary ignore terms that have a document frequency strictly higher than the given threshold (corpus-specific stop words).", + ) # type: ignore + + min_df: schema_field( + float_field( + ge=0.0, + le=1.0, + ), + placeholder=1.0, + description="When building the vocabulary ignore terms that have a document frequency strictly lower than the given threshold (corpus-specific stop words).", + ) # type: ignore + + max_features: schema_field( + int_field( + ge=1, + ), + placeholder=None, + description="If not None, build a vocabulary that only consider the top max_features ordered by term frequency across the corpus.", + ) # type: ignore + + norm: schema_field( + enum_field( + enum=["l1", "l2", None], + ), + placeholder="l2", + description="The norm used to normalize term vectors. If None, no normalization is applied.", + ) # type: ignore + + use_idf: schema_field( + bool_field(), + placeholder=True, + description="Enable inverse-document-frequency reweighting.", + ) # type: ignore + + smooth_idf: schema_field( + bool_field(), + placeholder=True, + description="Smooth idf weights by adding one to document frequencies, as if an extra document was seen containing every term in the collection exactly once. This prevents zero divisions.", + ) # type: ignore + + sublinear_tf: schema_field( + bool_field(), + placeholder=False, + description="Apply sublinear tf scaling, i.e. replace tf with 1 + log(tf).", + ) # type: ignore + +class TFIDFEmbedding(SparseEmbedding): + """ + TF-IDF embedding model for text documents. + This class implements the TF-IDF algorithm to generate embeddings for text documents. + """ + + def __init__( + self, + documents_chunks: Dict[int, List[str]], + strip_accents: str, + lowercase: bool, + analyzer: str, + stop_words: List[str], + ngram_range: List[int], + max_df: float, + min_df: float, + max_features: int, + norm: str, + use_idf: bool, + smooth_idf: bool, + sublinear_tf: bool, + store_model: bool = True + ) -> None: + """ + Initialize the TF-IDF embedding model with the given document chunks. + + Args: + documents_chunks (Dict[int, List[str]]): A dictionary where keys are document IDs and values are lists of text chunks. + """ + # sort chunks by document ID to ensure consistency + documents_chunks = dict(sorted(documents_chunks.items())) + + chunks_mapping = {} + chunks_texts = [] + n_chunks = 0 + for doc_id, chunks in documents_chunks.items(): + for chunk_text in chunks: + chunks_texts.append(chunk_text) + chunks_mapping[n_chunks] = (doc_id, chunk_text) + n_chunks += 1 + + self.chunks_texts = chunks_texts + self.chunks_mapping = chunks_mapping + + self.strip_accents = strip_accents + self.lowercase = lowercase + self.analyzer = analyzer + self.stop_words = stop_words + self.ngram_range = ngram_range + self.max_df = max_df + self.min_df = min_df + self.max_features = max_features + self.norm = norm + self.use_idf = use_idf + self.smooth_idf = smooth_idf + self.sublinear_tf = sublinear_tf + + self.hyperparameters = { + "strip_accents": strip_accents, + "lowercase": lowercase, + "analyzer": analyzer, + "stop_words": stop_words, + "ngram_range": ngram_range, + "max_df": max_df, + "min_df": min_df, + "max_features": max_features, + "norm": norm, + "use_idf": use_idf, + "smooth_idf": smooth_idf, + "sublinear_tf": sublinear_tf + } + + load_success = self._load_model() + print(f"TF-IDF model loaded successfully: {load_success}") + if not load_success: + print("Fitting the TF-IDF model...") + self._fit_model() + if store_model: + print("Saving the TF-IDF model...") + self._save_model() + print("TF-IDF model fitted and saved.") + + def _hash_function(self, input_string: str) -> str: + """ + Generate a SHA-256 hash for the given input string. + + Args: + input_string (str): The input string to hash. + + Returns: + str: The SHA-256 hash of the input string. + """ + return hashlib.sha256(input_string.encode('utf-8')).hexdigest() + + def _calculate_embeddings_hash(self) -> str: + """ + Generate a hash to identify the embeddings for caching purposes. + + Hash is calculated over the documents' content to ensure consistency in embeddings, it must: + - Be consistent across runs with the same documents content, chunking strategy and embedding model parameters. + - Change if the documents are modified. + - Change if the documents content is modified. + - Change if the chunking strategy is modified. + - Change if the embedding model parameters are modified. + + Returns: + str: A hash string representing the embeddings. + """ + params_hash = self._hash_function(str(self.hyperparameters)) + documents_chunks_hash = self._hash_function(str(self.chunks_mapping)) + return self._hash_function(params_hash + documents_chunks_hash) + + def _fit_model(self) -> None: + """ + Fit the TF-IDF model to the document chunks. + This method initializes the TF-IDF vectorizer and fits it to the document chunks. + """ + self.vectorizer = TfidfVectorizer( + strip_accents=self.strip_accents, + lowercase=self.lowercase, + analyzer=self.analyzer, + stop_words=self.stop_words, + ngram_range=tuple(self.ngram_range), + max_df=self.max_df, + min_df=self.min_df, + max_features=self.max_features, + norm=self.norm, + use_idf=self.use_idf, + smooth_idf=self.smooth_idf, + sublinear_tf=self.sublinear_tf + ) + self._term_matrix = self.vectorizer.fit_transform(self.chunks_texts) + self._feature_names = self.vectorizer.get_feature_names_out() + + def _get_model_paths(self) -> Tuple[str, str, str, str]: + """ + Get the paths for saving the model components. + Returns a tuple containing the folder path, vectorizer path, term matrix path, and feature names path. + """ + folder_path = os.path.join( + self.EMBEDDINGS_PATH, + self._calculate_embeddings_hash() + ) + + vectorizer_path = os.path.join(folder_path, "vectorizer.pkl") + term_matrix_path = os.path.join(folder_path, "term_matrix.pkl") + feature_names_path = os.path.join(folder_path, "feature_names.pkl") + + return folder_path, vectorizer_path, term_matrix_path, feature_names_path + + def _save_model(self) -> None: + """ + Save the model components to disk. + This method saves the vectorizer, term matrix, and feature names to their respective files. + """ + + folder_path, vectorizer_path, term_matrix_path, feature_names_path = self._get_model_paths() + + # Create the folder if it doesn't exist + os.makedirs(folder_path, exist_ok=True) + + # Save the vectorizer + with open(vectorizer_path, 'wb') as f: + pickle.dump(self.vectorizer, f) + + # Save the term matrix + with open(term_matrix_path, 'wb') as f: + pickle.dump(self._term_matrix, f) + + # Save the feature names + with open(feature_names_path, 'wb') as f: + pickle.dump(self._feature_names, f) + + def _load_model(self) -> None: + """ + Try to load the model components from disk. + If the model components are not found, return False. + If the model components are found, load them into the instance variables and return True. + """ + folder_path, vectorizer_path, term_matrix_path, feature_names_path = self._get_model_paths() + if not ( + os.path.exists(vectorizer_path) and + os.path.exists(term_matrix_path) and + os.path.exists(feature_names_path)): + return False + + # Load the vectorizer + with open(vectorizer_path, 'rb') as f: + self.vectorizer = pickle.load(f) + + # Load the term matrix + with open(term_matrix_path, 'rb') as f: + self._term_matrix = pickle.load(f) + + # Load the feature names + with open(feature_names_path, 'rb') as f: + self._feature_names = pickle.load(f) + + return True + + + def get_documents_chunks_embeddings(self) -> Dict[int, List[np.ndarray]]: + """ + Get the embeddings for each document chunk. + + Returns: + Dict[int, List[np.ndarray]]: A dictionary where keys are document IDs and values are lists of embeddings for each chunk. + """ + if not hasattr(self, 'vectorizer'): + raise RuntimeError("The model has not been fitted yet. Call _fit_model() before getting embeddings.") + + embeddings = self._term_matrix.toarray() + n_chunks = embeddings.shape[0] + + # Map the embeddings back to the document IDs using the chunks_mapping + documents_chunks_embeddings = {} + for i in range(n_chunks): + doc_id, _ = self.chunks_mapping[i] + if doc_id not in documents_chunks_embeddings: + documents_chunks_embeddings[doc_id] = [] + documents_chunks_embeddings[doc_id].append(embeddings[i]) + + return documents_chunks_embeddings + + def embed(self, text: str) -> List[float]: + """ + Generate TF-IDF embeddings for the given text. + + Args: + text (str): The input text to embed. + + Returns: + List[float]: A list representing the TF-IDF embeddings of the input text. + """ + if not hasattr(self, 'vectorizer'): + raise RuntimeError("The model has not been fitted yet. Call _fit_model() before embedding text.") + + # Transform the input text to get its TF-IDF representation + tfidf_vector = self.vectorizer.transform([text]) + return tfidf_vector.toarray() \ No newline at end of file diff --git a/DashAI/back/models/RAG/encodings/tf_idf_encoding.py b/DashAI/back/models/RAG/embeddings/tf_idf_encoding.py similarity index 100% rename from DashAI/back/models/RAG/encodings/tf_idf_encoding.py rename to DashAI/back/models/RAG/embeddings/tf_idf_encoding.py diff --git a/DashAI/back/models/RAG/utils.py b/DashAI/back/models/RAG/utils.py new file mode 100644 index 000000000..e69de29bb diff --git a/RAG/embeddings/c64d87e82535789c183ba885c1274d38fb9e6704d99f02ce7f3cb03d1d444709/feature_names.pkl b/RAG/embeddings/c64d87e82535789c183ba885c1274d38fb9e6704d99f02ce7f3cb03d1d444709/feature_names.pkl new file mode 100644 index 0000000000000000000000000000000000000000..6084a4eeed682fd27c5b9d61666ad158cf246f46 GIT binary patch literal 1577 zcmZ8hJ&)Ts5Y1Y){Jq&la_wQtR9jzn#dTR=4@e&bluWM~%cPEycHcafq zl!;3am+pRJ_w95$S(bPK}S2nbBWvTz2D7y*mB_!oLCi4ZL^~Ks*3_X*A;lbJV3}q|7;@%F^-l4IT=~Mm?E~ zRXA^IhudUL!7*Y%2uuMUby0xS zTc`eO+%{exGVSj} zdo^IHy-@|{o4euCZRsqV2oDP#F@}{gobgm3R|FsyUvis53YBrGN`sDMMIEj6Z}qs9z|3jA8M8v&Z5( M0_rwtJkB>i0S-fQ-T(jq literal 0 HcmV?d00001 diff --git a/RAG/embeddings/c64d87e82535789c183ba885c1274d38fb9e6704d99f02ce7f3cb03d1d444709/term_matrix.pkl b/RAG/embeddings/c64d87e82535789c183ba885c1274d38fb9e6704d99f02ce7f3cb03d1d444709/term_matrix.pkl new file mode 100644 index 0000000000000000000000000000000000000000..aa935f934ddd778124e73352f523b9c548cd8276 GIT binary patch literal 2244 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 C=i90P literal 0 HcmV?d00001 diff --git a/Untitled-1.ipynb b/Untitled-1.ipynb new file mode 100644 index 000000000..a7f8dd0fe --- /dev/null +++ b/Untitled-1.ipynb @@ -0,0 +1,690 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "145faa29", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "c:\\Users\\fcb11\\Documents\\GitHub\\DashAI\\.venv\\Lib\\site-packages\\tqdm\\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n", + "c:\\Users\\fcb11\\Documents\\GitHub\\DashAI\\.venv\\Lib\\site-packages\\pydantic\\_internal\\_config.py:345: UserWarning: Valid config keys have changed in V2:\n", + "* 'orm_mode' has been renamed to 'from_attributes'\n", + " warnings.warn(message, UserWarning)\n" + ] + }, + { + "data": { + "text/plain": [ + "['#1#yukari is one of the most underrated Vocaloid voicebanks and characters\\n',\n", + " '#2#Yuzuki Yukari is the president of Independent Republic of Saint Joaquin\\n',\n", + " '#3#Yuzuki Yukari is well known by her participation in the Nuremberg trials\\n',\n", + " '#4#Yuzuki Yukari is responsible for the creation of Linux kernel, even if she is not recognized by that\\n',\n", + " '#5#Papi Micky is the Major of San Carlos\\n',\n", + " '#6#Papi Micky had an affair with Tio Rene Puente, but he did not recognize him as a lover, because he was engaged with Contralorito']" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from sklearn.feature_extraction.text import TfidfVectorizer\n", + "from typing import Dict, List\n", + "import hashlib\n", + "from DashAI.back.models.RAG.embeddings.tf_idf_embedding import TFIDFEmbedding\n", + "\n", + "\n", + "hasher = lambda x: hashlib.sha256(x.encode('utf-8')).hexdigest()\n", + "\n", + "\n", + "dummy_texts = []\n", + "\n", + "with open('dummy_texts.txt', 'r') as file:\n", + " dummy_texts = file.readlines()\n", + " \n", + "dummy_texts" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "59febbcb", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "75 #1#yukari is one of the most underrated Vocaloid voicebanks and characters\n", + "\n", + "75 #2#Yuzuki Yukari is the president of Independent Republic of Saint Joaquin\n", + "\n", + "76 #3#Yuzuki Yukari is well known by her participation in the Nuremberg trials\n", + "\n", + "104 #4#Yuzuki Yukari is responsible for the creation of Linux kernel, even if she is not recognized by that\n", + "\n", + "41 #5#Papi Micky is the Major of San Carlos\n", + "\n", + "131 #6#Papi Micky had an affair with Tio Rene Puente, but he did not recognize him as a lover, because he was engaged with Contralorito\n" + ] + } + ], + "source": [ + "for t in dummy_texts:\n", + " print(len(t), t)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "dd6c7ea9", + "metadata": {}, + "outputs": [], + "source": [ + "def generate_chunks(texts, size, overlap)-> Dict[int, List[str]]:\n", + " \"\"\"\n", + " Generate chunks of text from the provided texts.\n", + " Args:\n", + " texts (List[str]): List of text documents to chunk.\n", + " size (int): Size of each chunk.\n", + " overlap (int): Overlap size between chunks.\n", + " Returns:\n", + " Dict[int, List[str]]: Dictionary with document index as key and list of chunks as value.\n", + " \"\"\"\n", + " \n", + " documents_chunks = {}\n", + "\n", + " for i, text in enumerate(texts):\n", + " chunks = []\n", + " for j in range(0, len(text), size - overlap):\n", + " if j + size > len(text):\n", + " chunk = text[j:]\n", + " else:\n", + " chunk = text[j:j + size]\n", + " chunks.append(chunk)\n", + " documents_chunks[i] = chunks\n", + " return documents_chunks" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "30e25e89", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{0: ['#1#yukari is one of the most underrated Vocaloid voicebanks and characters\\n'],\n", + " 1: ['#2#Yuzuki Yukari is the president of Independent Republic of Saint Joaquin\\n'],\n", + " 2: ['#3#Yuzuki Yukari is well known by her participation in the Nuremberg trials\\n'],\n", + " 3: ['#4#Yuzuki Yukari is responsible for the creation of Linux kernel, even if she is not recognized by that\\n'],\n", + " 4: ['#5#Papi Micky is the Major of San Carlos\\n'],\n", + " 5: ['#6#Papi Micky had an affair with Tio Rene Puente, but he did not recognize him as a lover, because he was engaged with Contralorito']}" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "document_chunks = generate_chunks(dummy_texts, 200, 20)\n", + "document_chunks" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "a18c4a56", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{0: ['#1#yukari is one of the most underrated Vocaloid voicebanks and characters\\n'],\n", + " 1: ['#2#Yuzuki Yukari is the president of Independent Republic of Saint Joaquin\\n'],\n", + " 2: ['#3#Yuzuki Yukari is well known by her participation in the Nuremberg trials\\n'],\n", + " 3: ['#4#Yuzuki Yukari is responsible for the creation of Linux kernel, even if she is not recognized by that\\n'],\n", + " 4: ['#5#Papi Micky is the Major of San Carlos\\n'],\n", + " 5: ['#6#Papi Micky had an affair with Tio Rene Puente, but he did not recognize him as a lover, because he was engaged with Contralorito']}" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "document_chunks = generate_chunks(dummy_texts, 200, 0)\n", + "document_chunks" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "a9f0d850", + "metadata": {}, + "outputs": [], + "source": [ + "if False: # Set to True to run the test\n", + " for chunk_size in [40, 80, 1000, 2000]:\n", + " for chunk_overlap in [0, 20, 30]:\n", + " document_chunks = generate_chunks(dummy_texts, chunk_size, chunk_overlap)\n", + " tfidf_embedding = TFIDFEmbedding(\n", + " documents_chunks=document_chunks,\n", + " strip_accents='unicode',\n", + " lowercase=True,\n", + " analyzer='word',\n", + " ngram_range=(1, 2),\n", + " max_features=1000,\n", + " norm='l2',\n", + " use_idf=True,\n", + " smooth_idf=True,\n", + " sublinear_tf=False,\n", + " stop_words=None,\n", + " max_df=1.0,\n", + " min_df=1,\n", + " )\n", + " \n", + " print(f\"Chunk Size: {chunk_size}, Chunk Overlap: {chunk_overlap}\")\n", + " print(f\"Embeddings Hash: {tfidf_embedding._calculate_embeddings_hash()}\\n\")\n", + " del tfidf_embedding # Clean up to free memory\n", + " del document_chunks # Clean up to free memory" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "2130e475", + "metadata": {}, + "outputs": [], + "source": [ + "if False: # Set to True to run the test\n", + " for chunk_size in [200, 200, 200]:\n", + " for chunk_overlap in [0, 0, 50, 50]:\n", + " document_chunks = generate_chunks(dummy_texts, chunk_size, chunk_overlap)\n", + " tfidf_embedding = TFIDFEmbedding(\n", + " documents_chunks=document_chunks,\n", + " strip_accents='unicode',\n", + " lowercase=True,\n", + " analyzer='word',\n", + " ngram_range=(1, 2),\n", + " max_features=1000,\n", + " norm='l2',\n", + " use_idf=True,\n", + " smooth_idf=True,\n", + " sublinear_tf=False,\n", + " stop_words=None,\n", + " max_df=1.0,\n", + " min_df=1,\n", + " Store_model=False # Set to False to avoid saving the model during testing\n", + " )\n", + " \n", + " print(f\"Chunk Size: {chunk_size}, Chunk Overlap: {chunk_overlap}\")\n", + " print(f\"Embeddings Hash: {tfidf_embedding._calculate_embeddings_hash()}\\n\")\n", + " del tfidf_embedding # Clean up to free memory\n", + " del document_chunks # Clean up to free memory" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "625a05ec", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{0: ['#1#yukari is one of the most underrated Vocaloid voicebanks and characters\\n'],\n", + " 1: ['#2#Yuzuki Yukari is the president of Independent Republic of Saint Joaquin\\n'],\n", + " 2: ['#3#Yuzuki Yukari is well known by her participation in the Nuremberg trials\\n'],\n", + " 3: ['#4#Yuzuki Yukari is responsible for the creation of Linux kernel, even if she is not recognized by that\\n'],\n", + " 4: ['#5#Papi Micky is the Major of San Carlos\\n'],\n", + " 5: ['#6#Papi Micky had an affair with Tio Rene Puente, but he did not recognize him as a lover, because he was engaged with Contralorito']}" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "chunks_size_200_overlap_0 = generate_chunks(dummy_texts, 200, 0)\n", + "chunks_size_200_overlap_0" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "dbc4609e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{0: ['#1#yukari is one of the most underrated Vocaloid voicebanks and characters\\n'],\n", + " 1: ['#2#Yuzuki Yukari is the president of Independent Republic of Saint Joaquin\\n'],\n", + " 2: ['#3#Yuzuki Yukari is well known by her participation in the Nuremberg trials\\n'],\n", + " 3: ['#4#Yuzuki Yukari is responsible for the creation of Linux kernel, even if she is not recognized by that\\n'],\n", + " 4: ['#5#Papi Micky is the Major of San Carlos\\n'],\n", + " 5: ['#6#Papi Micky had an affair with Tio Rene Puente, but he did not recognize him as a lover, because he was engaged with Contralorito']}" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "chunks_size_2000_overlap_0 = generate_chunks(dummy_texts, 2000, 0)\n", + "chunks_size_2000_overlap_0" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "b386ba62", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "TF-IDF model loaded successfully: False\n", + "Fitting the TF-IDF model...\n", + "Saving the TF-IDF model...\n", + "TF-IDF model fitted and saved.\n" + ] + } + ], + "source": [ + "embedding_chunk_size_200_overlap_0 = TFIDFEmbedding(\n", + " documents_chunks=chunks_size_200_overlap_0,\n", + " strip_accents='unicode',\n", + " lowercase=True,\n", + " analyzer='word',\n", + " ngram_range=(1, 2),\n", + " max_features=None,\n", + " norm='l2',\n", + " use_idf=True,\n", + " smooth_idf=True,\n", + " sublinear_tf=False,\n", + " stop_words=None,\n", + " max_df=1.0,\n", + " min_df=1,\n", + " store_model=True # Set to False to avoid saving the model during testing\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "df20a4dd", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "<6x129 sparse matrix of type ''\n", + "\twith 156 stored elements in Compressed Sparse Row format>" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "embedding_chunk_size_200_overlap_0._term_matrix" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "3887a18a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array(['affair', 'affair with', 'an', 'an affair', 'and',\n", + " 'and characters', 'as', 'as lover', 'because', 'because he', 'but',\n", + " 'but he', 'by', 'by her', 'by that', 'carlos', 'characters',\n", + " 'contralorito', 'creation', 'creation of', 'did', 'did not',\n", + " 'engaged', 'engaged with', 'even', 'even if', 'for', 'for the',\n", + " 'had', 'had an', 'he', 'he did', 'he was', 'her',\n", + " 'her participation', 'him', 'him as', 'if', 'if she', 'in',\n", + " 'in the', 'independent', 'independent republic', 'is', 'is not',\n", + " 'is one', 'is responsible', 'is the', 'is well', 'joaquin',\n", + " 'kernel', 'kernel even', 'known', 'known by', 'linux',\n", + " 'linux kernel', 'lover', 'lover because', 'major', 'major of',\n", + " 'micky', 'micky had', 'micky is', 'most', 'most underrated', 'not',\n", + " 'not recognize', 'not recognized', 'nuremberg', 'nuremberg trials',\n", + " 'of', 'of independent', 'of linux', 'of saint', 'of san', 'of the',\n", + " 'one', 'one of', 'papi', 'papi micky', 'participation',\n", + " 'participation in', 'president', 'president of', 'puente',\n", + " 'puente but', 'recognize', 'recognize him', 'recognized',\n", + " 'recognized by', 'rene', 'rene puente', 'republic', 'republic of',\n", + " 'responsible', 'responsible for', 'saint', 'saint joaquin', 'san',\n", + " 'san carlos', 'she', 'she is', 'that', 'the', 'the creation',\n", + " 'the major', 'the most', 'the nuremberg', 'the president', 'tio',\n", + " 'tio rene', 'trials', 'underrated', 'underrated vocaloid',\n", + " 'vocaloid', 'vocaloid voicebanks', 'voicebanks', 'voicebanks and',\n", + " 'was', 'was engaged', 'well', 'well known', 'with',\n", + " 'with contralorito', 'with tio', 'yukari', 'yukari is', 'yuzuki',\n", + " 'yuzuki yukari'], dtype=object)" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "embedding_chunk_size_200_overlap_0._feature_names" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "3ed862f2", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "<6x129 sparse matrix of type ''\n", + "\twith 156 stored elements in Compressed Sparse Row format>" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "embedding_chunk_size_200_overlap_0._term_matrix" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "46446c8a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0.]])" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "embedding_chunk_size_200_overlap_0.embed(\"affair\")" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "3592c77e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[0.65787347, 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0.39028945, 0. , 0.45545397, 0.45545397]])" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "embedding_chunk_size_200_overlap_0.embed(\"affair yuzuki yukari\")" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "1c652c26", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0.]])" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "embedding_chunk_size_200_overlap_0.embed(\"fnosn 090 aojfnsk linux\")" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "b1b8cf59", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "TF-IDF model loaded successfully: True\n" + ] + } + ], + "source": [ + "embedding_chunk_size_2000_overlap_0 = TFIDFEmbedding(\n", + " documents_chunks=chunks_size_2000_overlap_0,\n", + " strip_accents='unicode',\n", + " lowercase=True,\n", + " analyzer='word',\n", + " ngram_range=(1, 2),\n", + " max_features=None,\n", + " norm='l2',\n", + " use_idf=True,\n", + " smooth_idf=True,\n", + " sublinear_tf=False,\n", + " stop_words=None,\n", + " max_df=1.0,\n", + " min_df=1,\n", + " store_model=True # Set to False to avoid saving the model during testing\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "67f65c72", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[0.6234157 , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0.31939253, 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0.36984707, 0. , 0.43159844, 0.43159844]])" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "e1=embedding_chunk_size_200_overlap_0.embed(\"this is a yuzuki yukari affair\")\n", + "e1" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "ba0999cb", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[0.6234157 , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0.31939253, 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0. , 0. , 0. , 0. , 0. ,\n", + " 0.36984707, 0. , 0.43159844, 0.43159844]])" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "e2 = embedding_chunk_size_2000_overlap_0.embed(\"this is a yuzuki yukari affair\")\n", + "e2" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "74ec8dc4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(e1==e2).all() # Check if all elements are equal" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/dummy_texts.txt b/dummy_texts.txt new file mode 100644 index 000000000..48bfb1d26 --- /dev/null +++ b/dummy_texts.txt @@ -0,0 +1,6 @@ +#1#yukari is one of the most underrated Vocaloid voicebanks and characters +#2#Yuzuki Yukari is the president of Independent Republic of Saint Joaquin +#3#Yuzuki Yukari is well known by her participation in the Nuremberg trials +#4#Yuzuki Yukari is responsible for the creation of Linux kernel, even if she is not recognized by that +#5#Papi Micky is the Major of San Carlos +#6#Papi Micky had an affair with Tio Rene Puente, but he did not recognize him as a lover, because he was engaged with Contralorito \ No newline at end of file diff --git a/term_matrix.pkl b/term_matrix.pkl new file mode 100644 index 0000000000000000000000000000000000000000..aa935f934ddd778124e73352f523b9c548cd8276 GIT binary patch literal 2244 zcmd_qS!@$W7{GBSu^o<(0wLVA6ljhDrZqDhLT4Sn0Q) zXLjb>nbEgyvF|$F$CkN_K{3A?O}JuFMT-SpK7UM;MnCSpu%c^fvuu~8t#XSjF`T|w zNQnle$LVSPS{i-AN^?|GBf9jsja)SnQ2oJ}Gzuf}FzNhFTF@1auhUgU)0BiX@_bs* z-xP`ITHLRb)No`5N+UNC=o->4J+?MkmDM13$fdHxljYghCPR6KBcLaEEmN}9X)?L9 z>uHXWRW7|=@1h4>nVZL^%Z6lSG}~r#u(dd1_zD&H5+2lGGPYtM?9ibh3W2qlhmSE4 zTcBVezQDVfk7ZbgDQLm_sK;uQVkx%4e3zBe%J&g{jVQqqjKcs-M*{Dm3DqdZV!Vw! zOhYqT&^^DEJD>i~QH4neq6i}}6(3*$3J}65_~61Ce1^FQ;2jKy8#6E%BT)x)EiLH2 z2J_skb@=(c2(zK$L)798G+-9W;e~mI-Op$f?P1t}vFMAL$i)PFib@pXE%e87tU?5v zk%b(L!5j?2P^^bp|7CDuJXT-`-b6oqf|UqkBg`usqhapBTDN&llFBojd;?KklcD~h ze6x~61FbsFr7=8NWzNhj*DQ?+m`7li=RRao*aM2LJSBnoAru&A&JF^-n$jC|dn1T92LDv+Wo0s$-zzM*g+x3opD5 zD^GFzxuHj@Q^JZhyB$0C|8+(*%G+1|Dd-T7w=X_wAHC^Twcpd?|Kg$gGw#&Y%e{`X zp7)Gp_4@G{3oeLMskh|cWj_n69Z%lPwlM?_xZmE#<&+ Date: Tue, 9 Sep 2025 15:49:40 -0300 Subject: [PATCH 008/218] dense retriever configuration working Awful implementation --- .gitignore | 2 + .../back/api/api_v1/endpoints/components.py | 25 + .../back/converters/hugging_face/embedding.py | 61 +- DashAI/back/initial_components.py | 49 +- DashAI/back/models/RAG/RAG_pipeline.py | 4 +- .../models/RAG/Retrievers/DenseRetriever.py | 12 - DashAI/back/models/RAG/Retrievers/__init__.py | 7 +- .../models/RAG/Retrievers/dense_retriever.py | 50 + .../{BaseRetriever.py => retriever_model.py} | 35 +- .../models/RAG/Retrievers/sparse_retriever.py | 11 + .../{TFIDFRetriever.py => tfidf_retriever.py} | 9 +- DashAI/back/models/RAG/__init__.py | 9 +- .../models/RAG/chunking_models/__init__.py | 2 + .../chunking_models/character_chunk_model.py | 4 +- .../RAG/chunking_models/token_chunk_model.py | 52 + .../models/RAG/embeddings/dense_embedding.py | 22 - .../models/RAG/embeddings/tf_idf_encoding.py | 32 - DashAI/back/models/RAG/encodings/__init__.py | 6 + .../models/RAG/encodings/dense/__init__.py | 2 + .../RAG/encodings/dense/fasttext_embedding.py | 61 + .../encodings/dense/huggingface_embedding.py | 127 + .../models/RAG/encodings/dense_encoding.py | 24 + DashAI/back/models/RAG/encodings/encoding.py | 32 + .../models/RAG/encodings/sparse/__init__.py | 2 + .../RAG/encodings/sparse/bm25_encoding.py | 302 + .../sparse/tfidf_encoding.py} | 88 +- .../sparse_encoding.py} | 16 +- .../trainable_encoding.py} | 39 +- DashAI/back/models/RAG/prompts/__init__.py | 2 +- .../models/RAG/prompts/augmentation_prompt.py | 4 +- .../RAG/prompts/context_merge_prompt.py | 4 +- .../RAG/prompts/{base_prompt.py => prompt.py} | 5 +- DashAI/back/models/__init__.py | 2 +- DashAI/front/src/api/component.ts | 7 + DashAI/front/src/api/rag.ts | 23 +- .../components/documents/DocumentTable.jsx | 2 +- .../pages/generative/RAG/NewSessionModal.jsx | 14 +- .../RAG/RetrieverConfigurationStep.jsx | 238 +- .../feature_names.pkl | Bin 0 -> 1577 bytes .../term_matrix.pkl | Bin 0 -> 2244 bytes .../vectorizer.pkl | Bin 0 -> 6400 bytes Untitled-1.ipynb | 106 + component_registry.json | 1 + component_registry__foromatted.json | 6053 +++++++++++++++++ requirements.txt | 4 +- test.py | 87 + tsconfig.json | 15 + 47 files changed, 7282 insertions(+), 370 deletions(-) delete mode 100644 DashAI/back/models/RAG/Retrievers/DenseRetriever.py create mode 100644 DashAI/back/models/RAG/Retrievers/dense_retriever.py rename DashAI/back/models/RAG/Retrievers/{BaseRetriever.py => retriever_model.py} (86%) create mode 100644 DashAI/back/models/RAG/Retrievers/sparse_retriever.py rename DashAI/back/models/RAG/Retrievers/{TFIDFRetriever.py => tfidf_retriever.py} (97%) create mode 100644 DashAI/back/models/RAG/chunking_models/__init__.py create mode 100644 DashAI/back/models/RAG/chunking_models/token_chunk_model.py delete mode 100644 DashAI/back/models/RAG/embeddings/dense_embedding.py delete mode 100644 DashAI/back/models/RAG/embeddings/tf_idf_encoding.py create mode 100644 DashAI/back/models/RAG/encodings/__init__.py create mode 100644 DashAI/back/models/RAG/encodings/dense/__init__.py create mode 100644 DashAI/back/models/RAG/encodings/dense/fasttext_embedding.py create mode 100644 DashAI/back/models/RAG/encodings/dense/huggingface_embedding.py create mode 100644 DashAI/back/models/RAG/encodings/dense_encoding.py create mode 100644 DashAI/back/models/RAG/encodings/encoding.py create mode 100644 DashAI/back/models/RAG/encodings/sparse/__init__.py create mode 100644 DashAI/back/models/RAG/encodings/sparse/bm25_encoding.py rename DashAI/back/models/RAG/{embeddings/tf_idf_embedding.py => encodings/sparse/tfidf_encoding.py} (80%) rename DashAI/back/models/RAG/{embeddings/sparse_embedding.py => encodings/sparse_encoding.py} (53%) rename DashAI/back/models/RAG/{embeddings/base_embedding.py => encodings/trainable_encoding.py} (65%) rename DashAI/back/models/RAG/prompts/{base_prompt.py => prompt.py} (87%) create mode 100644 RAG/embeddings/9864fa188a542eee3117fb4e3ed614fecb32905086735433d372c53e4d4b8f5a/feature_names.pkl create mode 100644 RAG/embeddings/9864fa188a542eee3117fb4e3ed614fecb32905086735433d372c53e4d4b8f5a/term_matrix.pkl create mode 100644 RAG/embeddings/9864fa188a542eee3117fb4e3ed614fecb32905086735433d372c53e4d4b8f5a/vectorizer.pkl create mode 100644 component_registry.json create mode 100644 component_registry__foromatted.json create mode 100644 test.py create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore index e3f8f7290..7972a2d3a 100644 --- a/.gitignore +++ b/.gitignore @@ -180,3 +180,5 @@ __pycache__ *.DS_Store .prettierrc + +*.ipynb \ No newline at end of file diff --git a/DashAI/back/api/api_v1/endpoints/components.py b/DashAI/back/api/api_v1/endpoints/components.py index ad5e85ceb..d2b17964a 100644 --- a/DashAI/back/api/api_v1/endpoints/components.py +++ b/DashAI/back/api/api_v1/endpoints/components.py @@ -97,6 +97,7 @@ async def get_components( print("has_related_of_type", str(has_related_of_type)) print("get_components api ") # when select_type is not none, check if it exists in the registry. + if select_types is not None: for select_type in select_types: if select_type not in component_registry._registry: @@ -206,6 +207,8 @@ async def get_components( _delete_class(component_dict) for component_dict in selected_components.values() ] + print(out) + return out @@ -282,3 +285,25 @@ async def update_component() -> None: raise HTTPException( status_code=status.HTTP_501_NOT_IMPLEMENTED, detail="Method not implemented" ) + +@router.get("/{component_name}/children/") +async def get_child_components( + component_name:str, + recursive:bool=False, + component_registry: ComponentRegistry = Depends(lambda: di["component_registry"])): + """Get child components of a specific component. + + Args: + component_name (str): The name of the component to get children for. + recursive (bool): Whether to get child components recursively. + + Returns: + List[Dict[str, Any]]: A list of child component dictionaries. + """ + children_list = component_registry.get_child_components(component_name, recursive=recursive) + print("children_list", children_list) + # Remove "class" key from each child component + cleaned_children = [_delete_class(child) for child in children_list] + print("cleaned_children", cleaned_children) + + return cleaned_children \ No newline at end of file diff --git a/DashAI/back/converters/hugging_face/embedding.py b/DashAI/back/converters/hugging_face/embedding.py index 371163ec1..ffd8421cb 100644 --- a/DashAI/back/converters/hugging_face/embedding.py +++ b/DashAI/back/converters/hugging_face/embedding.py @@ -1,3 +1,5 @@ +from typing import Final, List +import numpy as np import torch from datasets import Dataset, concatenate_datasets from transformers import AutoModel, AutoTokenizer @@ -62,7 +64,7 @@ class Embedding(HuggingFaceWrapper): SCHEMA = EmbeddingSchema DESCRIPTION = "Convert text to embeddings using HuggingFace transformer models." - + def __init__(self, **kwargs): super().__init__(**kwargs) self.pooling_strategy = kwargs.get("pooling_strategy", "mean") @@ -81,6 +83,36 @@ def _load_model(self): self.model = AutoModel.from_pretrained(self.model_name).to(self.device) self.model.eval() + def _encode_texts(self, texts:List[str])-> List[np.ndarray]: + """Encode a list of texts into embeddings.""" + # Tokenize + encoded = self.tokenizer( + texts, + padding=True, + truncation=True, + max_length=self.max_length, + return_tensors="pt", + ) + + # Move to device + encoded = {k: v.to(self.device) for k, v in encoded.items()} + + # Get embeddings + with torch.no_grad(): + outputs = self.model(**encoded) + hidden_states = outputs.last_hidden_state + + # Apply pooling strategy + if self.pooling_strategy == "mean": + embeddings = torch.mean(hidden_states, dim=1) + elif self.pooling_strategy == "cls": + embeddings = hidden_states[:, 0] + else: # max pooling + embeddings = torch.max(hidden_states, dim=1)[0] + + embeddings_np = embeddings.cpu().numpy() + return embeddings_np + def _process_batch(self, batch: DashAIDataset) -> DashAIDataset: """Process a batch of text into embeddings.""" all_column_embeddings = [] @@ -89,32 +121,7 @@ def _process_batch(self, batch: DashAIDataset) -> DashAIDataset: # Get text data from dataset texts = [row[column] for row in batch] - # Tokenize - encoded = self.tokenizer( - texts, - padding=True, - truncation=True, - max_length=self.max_length, - return_tensors="pt", - ) - - # Move to device - encoded = {k: v.to(self.device) for k, v in encoded.items()} - - # Get embeddings - with torch.no_grad(): - outputs = self.model(**encoded) - hidden_states = outputs.last_hidden_state - - # Apply pooling strategy - if self.pooling_strategy == "mean": - embeddings = torch.mean(hidden_states, dim=1) - elif self.pooling_strategy == "cls": - embeddings = hidden_states[:, 0] - else: # max pooling - embeddings = torch.max(hidden_states, dim=1)[0] - - embeddings_np = embeddings.cpu().numpy() + embeddings_np = self._encode_texts(texts) # Create a dictionary with embedding columns embedding_dict = { diff --git a/DashAI/back/initial_components.py b/DashAI/back/initial_components.py index 03db79b45..0b73a8fb8 100644 --- a/DashAI/back/initial_components.py +++ b/DashAI/back/initial_components.py @@ -90,13 +90,30 @@ RidgeRegression, StableDiffusionV2Model, StableDiffusionV3Model, - RAGPipeline, - BaseRetriever, - TFIDFRetriever, - DenseRetriever, - StableDiffusionXLV1ControlNet, ) + +from DashAI.back.models.RAG import ( + # Chunking Models + CharacterChunkModel, + TokenChunkModel, + # Encodings + DenseEncoding, + FastTextEmbedding, + HuggingFaceEmbedding, + SparseEncoding, + TFIDFEncoding, + BM25Encoding, + # Prompts + AugmentationPrompt, + ContextMergePrompt, + # Retrievers + DenseRetriever, + SparseRetriever, + TFIDFRetriever +) + + from DashAI.back.optimizers import HyperOptOptimizer, OptunaOptimizer from DashAI.back.plugins.utils import get_available_plugins from DashAI.back.tasks import ( @@ -159,10 +176,6 @@ def get_initial_components(): RidgeRegression, LinearSVR, LinearRegression, - RAGPipeline, - TFIDFRetriever, - DenseRetriever, - #BaseRetriever, # Dataloaders CSVDataLoader, JSONDataLoader, @@ -250,6 +263,24 @@ def get_initial_components(): SMOTEConverter, SMOTEENNConverter, RandomUnderSamplerConverter, + + # RAG + CharacterChunkModel, + TokenChunkModel, + # Encodings + DenseEncoding, + FastTextEmbedding, + HuggingFaceEmbedding, + SparseEncoding, + TFIDFEncoding, + BM25Encoding, + # Prompts + AugmentationPrompt, + ContextMergePrompt, + # Retrievers + DenseRetriever, + SparseRetriever, + TFIDFRetriever ] # Obtener plugins instalados diff --git a/DashAI/back/models/RAG/RAG_pipeline.py b/DashAI/back/models/RAG/RAG_pipeline.py index c7713c922..854254d43 100644 --- a/DashAI/back/models/RAG/RAG_pipeline.py +++ b/DashAI/back/models/RAG/RAG_pipeline.py @@ -13,7 +13,7 @@ from DashAI.back.models.RAG.Retrievers import ( TFIDFRetriever, DenseRetriever, - BaseRetriever) + RetrieverModel) from DashAI.back.models.RAG.prompts import ( ContextMergePrompt, @@ -114,7 +114,7 @@ def __init__( self, new_retriever_args[key] = value print("Initializing retriever model") - self.retriever: BaseRetriever = retriever_model_class(**new_retriever_args) + self.retriever: RetrieverModel = retriever_model_class(**new_retriever_args) self.retrieval_algorithm = "SINGLE_INTERACTION" print("RAG pipeline initialized") diff --git a/DashAI/back/models/RAG/Retrievers/DenseRetriever.py b/DashAI/back/models/RAG/Retrievers/DenseRetriever.py deleted file mode 100644 index 835747c96..000000000 --- a/DashAI/back/models/RAG/Retrievers/DenseRetriever.py +++ /dev/null @@ -1,12 +0,0 @@ -from .BaseRetriever import BaseRetriever - -class DenseRetriever(BaseRetriever): - """ - Dense retriever class for retrieving documents based on dense vector representations. - This class is a placeholder and should be implemented with specific dense retrieval logic. - """ - - COMPATIBLE_COMPONENTS = ["RAGTask"] - - def __init__(self, *args, **kwargs): - return \ No newline at end of file diff --git a/DashAI/back/models/RAG/Retrievers/__init__.py b/DashAI/back/models/RAG/Retrievers/__init__.py index 4e295aff6..1da8bcd36 100644 --- a/DashAI/back/models/RAG/Retrievers/__init__.py +++ b/DashAI/back/models/RAG/Retrievers/__init__.py @@ -1,3 +1,4 @@ -from DashAI.back.models.RAG.Retrievers.BaseRetriever import BaseRetriever -from DashAI.back.models.RAG.Retrievers.TFIDFRetriever import TFIDFRetriever -from DashAI.back.models.RAG.Retrievers.DenseRetriever import DenseRetriever \ No newline at end of file +from DashAI.back.models.RAG.Retrievers.retriever_model import RetrieverModel +from DashAI.back.models.RAG.Retrievers.tfidf_retriever import TFIDFRetriever +from DashAI.back.models.RAG.Retrievers.dense_retriever import DenseRetriever +from DashAI.back.models.RAG.Retrievers.sparse_retriever import SparseRetriever \ No newline at end of file diff --git a/DashAI/back/models/RAG/Retrievers/dense_retriever.py b/DashAI/back/models/RAG/Retrievers/dense_retriever.py new file mode 100644 index 000000000..1ef42567f --- /dev/null +++ b/DashAI/back/models/RAG/Retrievers/dense_retriever.py @@ -0,0 +1,50 @@ +from .retriever_model import RetrieverModel + +from DashAI.back.core.schema_fields import ( + BaseSchema, + component_field, + schema_field, + enum_field +) +""" chunking_model: schema_field( + component_field( + parent="ChunkingModel" + ), + placeholder={"component": "Perico", "params": {}}, + description="Chunking model to split documents into smaller parts." +)# type: ignore """ + +class DenseRetrieverSchema(BaseSchema): + """Schema for Dense Retriever.""" + + encoding_model: schema_field( + component_field( + parent="Encoding" + ), + placeholder={"component": "Embedding", "params": {}}, + description="Model to convert text into dense vector representations." + ) # type: ignore + + similarity_metric: schema_field( + enum_field( + enum=["cosine", "dot_product", "euclidean"] + ), + placeholder="cosine", + description="Similarity metric to use for comparing dense vectors.", + ) # type: ignore + + +class DenseRetriever(RetrieverModel): + """ + Dense retriever class for retrieving documents based on dense vector representations. + This class is a placeholder and should be implemented with specific dense retrieval logic. + """ + + SCHEMA = DenseRetrieverSchema + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + self.chunking_model = kwargs.get("chunking_model") + self.encoding_model = kwargs.get("encoding_model") + diff --git a/DashAI/back/models/RAG/Retrievers/BaseRetriever.py b/DashAI/back/models/RAG/Retrievers/retriever_model.py similarity index 86% rename from DashAI/back/models/RAG/Retrievers/BaseRetriever.py rename to DashAI/back/models/RAG/Retrievers/retriever_model.py index 3385a5467..8e2a59580 100644 --- a/DashAI/back/models/RAG/Retrievers/BaseRetriever.py +++ b/DashAI/back/models/RAG/Retrievers/retriever_model.py @@ -2,29 +2,20 @@ import os from typing import Any, Dict, List, Final from DashAI.back.models.RAG.documents import BaseDocument, PDFDocument, TxtDocument -from DashAI.back.config_object import ConfigObject import hashlib +from DashAI.back.models.base_model import BaseModel + SUPPORTED_DOCUMENT_TYPES = ['pdf', 'txt'] -class BaseRetriever(ABC, ConfigObject): +class RetrieverModel(BaseModel): """ - Base class for retrievers. + Abstract class to define the interface for retriever models. """ RETRIEVERS_PATH = "./StoredRetrievers" COMPATIBLE_COMPONENTS = ["RAGTask"] - TYPE: Final[str] = "RetrieverModel" - - def __init__(self, *args, **kwargs): - """ - Initialize the retriever. - """ - self.params = None - self._documents_paths = None - self.chunk_size = None - self.chunk_overlap = None def _load_document(self, document_path: str) -> BaseDocument: """ @@ -52,7 +43,7 @@ def get_documents(self) -> Dict[str, BaseDocument]: assert self._documents_paths is not None, "Document paths must be provided." assert len(self._documents_paths) > 0, "At least one document path must be provided." - self._documents_paths = sorted(self._documents_paths) # Sort for consistent hashing + self._documents_paths = sorted(self._documents_paths) # Sort for consistent hashing in signature documents = {} for path in self._documents_paths: doc = self._load_document(path) @@ -83,10 +74,10 @@ def get_parameters(self) -> Dict[str, Any]: assert self.params is not None, "Retriever parameters are not set." return self.params - def get_hashable_parameters(self) -> Dict[str, Any]: + def get_signature_parameters(self) -> Dict[str, Any]: """ Get the parameters used for storing the fitted retriever in the database. - This parameters are a subset of the retriever parameters, the non-hashable parameters are + This parameters are a subset of the retriever parameters, the non-signature parameters are those whose change does not require a retraining of the retriever, i.e. n_docs, max_distance, etc. @@ -95,7 +86,7 @@ def get_hashable_parameters(self) -> Dict[str, Any]: """ raise NotImplementedError("This method should be implemented by subclasses.") - def _get_documents_hash(self) -> str: + def _get_documents_signature(self) -> str: """ Generate a hash representing the current set of documents. @@ -109,7 +100,7 @@ def _get_documents_hash(self) -> str: hashes += f"{filename}{doc_hash}" return hashlib.sha256(hashes.encode('utf-8')).hexdigest() - def _get_parameters_hash(self) -> str: + def _get_parameters_signature(self) -> str: """ Generate a hash representing the retriever parameters. @@ -119,19 +110,19 @@ def _get_parameters_hash(self) -> str: Returns: str: A hash string representing the parameters. """ - hashable_parameters = sorted(self.get_hashable_parameters().items()) + hashable_parameters = sorted(self.get_signature_parameters().items()) params_string = "".join(f"{key}{value}" for key, value in hashable_parameters) return hashlib.sha256(params_string.encode('utf-8')).hexdigest() - def _get_cache_hash(self) -> str: + def _get_model_signature(self) -> str: """ Generate a unique hash for the retriever based on its documents and parameters. Returns: str: A hash string representing the retriever's state. """ - documents_hash = self._get_documents_hash() - parameters_hash = self._get_parameters_hash() + documents_hash = self._get_documents_signature() + parameters_hash = self._get_parameters_signature() return f"{self.__class__.__name__}_{documents_hash}_{parameters_hash}" def add_document(self, document: BaseDocument) -> None: diff --git a/DashAI/back/models/RAG/Retrievers/sparse_retriever.py b/DashAI/back/models/RAG/Retrievers/sparse_retriever.py new file mode 100644 index 000000000..7e0bedde9 --- /dev/null +++ b/DashAI/back/models/RAG/Retrievers/sparse_retriever.py @@ -0,0 +1,11 @@ + +from DashAI.back.models.RAG.Retrievers.retriever_model import RetrieverModel + + +class SparseRetriever(RetrieverModel): + """ + Abstract class for sparse retrievers. + """ + + def __init__(self, **kwargs): + super().__init__(**kwargs) diff --git a/DashAI/back/models/RAG/Retrievers/TFIDFRetriever.py b/DashAI/back/models/RAG/Retrievers/tfidf_retriever.py similarity index 97% rename from DashAI/back/models/RAG/Retrievers/TFIDFRetriever.py rename to DashAI/back/models/RAG/Retrievers/tfidf_retriever.py index e60734aac..6f2cf771a 100644 --- a/DashAI/back/models/RAG/Retrievers/TFIDFRetriever.py +++ b/DashAI/back/models/RAG/Retrievers/tfidf_retriever.py @@ -1,5 +1,5 @@ import os -from .BaseRetriever import BaseRetriever +from DashAI.back.models.RAG.Retrievers.retriever_model import RetrieverModel from DashAI.back.models.RAG.documents import BaseDocument, PDFDocument, TxtDocument from typing import List, Dict, Any, Optional, Tuple from sklearn.feature_extraction.text import TfidfVectorizer @@ -7,6 +7,7 @@ import numpy as np import hashlib import pickle +from DashAI.back.models.RAG.Retrievers.sparse_retriever import SparseRetriever from DashAI.back.core.schema_fields import ( BaseSchema, @@ -57,7 +58,7 @@ class TFIDFRetrieverSchema(BaseSchema): description="Overlap between chunks when splitting documents." ) # type: ignore -class TFIDFRetriever(BaseRetriever): +class TFIDFRetriever(SparseRetriever): """ A retriever that uses TF-IDF to retrieve documents based on a query. """ @@ -140,14 +141,14 @@ def _get_cache_paths(self) -> tuple[str, str, str]: map_path = os.path.join(base_name, "chunk_to_doc_id_map") return vectorizer_path, tfidf_matrix_path, map_path - def get_hashable_parameters(self): + def get_signature_parameters(self): return { "chunk_size": self.chunk_size, "chunk_overlap": self.chunk_overlap, } def _generate_cache_hash(self) -> str: - hashable_params = self.get_hashable_parameters() + hashable_params = self.get_signature_parameters() text = f"{self._documents_paths}{hashable_params}" params_hash = hashlib.sha256(text.encode('utf-8')).hexdigest() docs_hashes = [] diff --git a/DashAI/back/models/RAG/__init__.py b/DashAI/back/models/RAG/__init__.py index 6261e0606..88a96fe60 100644 --- a/DashAI/back/models/RAG/__init__.py +++ b/DashAI/back/models/RAG/__init__.py @@ -1,2 +1,7 @@ -from DashAI.back.models.RAG.RAG_pipeline import RAGPipeline -from DashAI.back.models.RAG.Retrievers import BaseRetriever, TFIDFRetriever, DenseRetriever \ No newline at end of file +from DashAI.back.models.RAG.chunking_models import * +from DashAI.back.models.RAG.documents import * +from DashAI.back.models.RAG.encodings import * +from DashAI.back.models.RAG.prompts import * +from DashAI.back.models.RAG.Retrievers import * + +from DashAI.back.models.RAG.RAG_pipeline import RAGPipeline \ No newline at end of file diff --git a/DashAI/back/models/RAG/chunking_models/__init__.py b/DashAI/back/models/RAG/chunking_models/__init__.py new file mode 100644 index 000000000..a935c5395 --- /dev/null +++ b/DashAI/back/models/RAG/chunking_models/__init__.py @@ -0,0 +1,2 @@ +from DashAI.back.models.RAG.chunking_models.character_chunk_model import CharacterChunkModel +from DashAI.back.models.RAG.chunking_models.token_chunk_model import TokenChunkModel \ No newline at end of file diff --git a/DashAI/back/models/RAG/chunking_models/character_chunk_model.py b/DashAI/back/models/RAG/chunking_models/character_chunk_model.py index dca1a203d..0b66687d2 100644 --- a/DashAI/back/models/RAG/chunking_models/character_chunk_model.py +++ b/DashAI/back/models/RAG/chunking_models/character_chunk_model.py @@ -11,13 +11,13 @@ class CharacterChunkModelSchema(BaseSchema): """Schema for character-based chunking model.""" chunk_size: schema_field( - int_field(min_value=1), + int_field(gt=1), placeholder=None, description="Size of each chunk in characters." ) # type: ignore chunk_overlap: schema_field( - int_field(min_value=0), + int_field(gt=0), placeholder=None, description="Number of characters to overlap between chunks." ) # type: ignore diff --git a/DashAI/back/models/RAG/chunking_models/token_chunk_model.py b/DashAI/back/models/RAG/chunking_models/token_chunk_model.py new file mode 100644 index 000000000..380faa7d4 --- /dev/null +++ b/DashAI/back/models/RAG/chunking_models/token_chunk_model.py @@ -0,0 +1,52 @@ +from DashAI.back.core.schema_fields import ( + BaseSchema, + enum_field, + int_field + ) +from transformers import AutoTokenizer + +from DashAI.back.models.RAG.chunking_models.base_chunking_model import BaseChunkingModel +from DashAI.back.models.RAG.documents import BaseDocument + +class TokenChunkModelSchema(BaseSchema): + tokenizer_name: enum_field( + enum=[ + "intfloat/e5-mistral-7b-instruct", + "dccuchile/bert-base-spanish-wwm-uncased" + ] + ) #type: ignore + + chunk_size: int_field( + gt=1, + ) #type: ignore + + chunk_overlap: int_field( + ge=0, + ) #type: ignore + +class TokenChunkModel(BaseChunkingModel): + + SCHEMA = TokenChunkModelSchema + + def __init__(self, **kwargs): + + kwargs = self.validate_and_transform(kwargs) + + self.chunk_size = kwargs.get("chunk_size") + self.chunk_overlap = kwargs.get("chunk_overlap") + + self.tokenizer_name = kwargs.get("tokenizer_name") + self.tokenizer = AutoTokenizer.from_pretrained(self.tokenizer_name) + + + def chunk(self, document:BaseDocument): + text = document.get_text() + + tokens = self.tokenizer.tokenize(text) + + chunks = [] + for i in range(0, len(tokens), self.chunk_size): + chunk = tokens[i:i + self.chunk_size] + chunks.append(chunk) + + return chunks \ No newline at end of file diff --git a/DashAI/back/models/RAG/embeddings/dense_embedding.py b/DashAI/back/models/RAG/embeddings/dense_embedding.py deleted file mode 100644 index 39a585636..000000000 --- a/DashAI/back/models/RAG/embeddings/dense_embedding.py +++ /dev/null @@ -1,22 +0,0 @@ -from DashAI.back.models.RAG.embeddings.base_embedding import BaseEmbedding -from typing import Any, List -import numpy as np - -class DenseEmbedding(BaseEmbedding): - """ - Base class for dense embedding models. - This class should be inherited by any specific dense embedding model implementation. - """ - - def __init__(self): - super().__init__() - - def embed(self, text: str) -> List|np.ndarray|Any: - """ - Method to generate dense embeddings for the given text. - This method should be implemented by subclasses. - - :param text: The input text to embed. - :return: A list representing the dense embeddings of the input text. - """ - raise NotImplementedError("Subclasses must implement this method.") \ No newline at end of file diff --git a/DashAI/back/models/RAG/embeddings/tf_idf_encoding.py b/DashAI/back/models/RAG/embeddings/tf_idf_encoding.py deleted file mode 100644 index f74045ae2..000000000 --- a/DashAI/back/models/RAG/embeddings/tf_idf_encoding.py +++ /dev/null @@ -1,32 +0,0 @@ -#from chromadb import EmbeddingFunction, Embeddings -from typing import List -from sklearn.feature_extraction.text import TfidfVectorizer -import pickle -import os - -class TfidfEmbeddingFunction:#(EmbeddingFunction): - """A dummy embedding function using TF-IDF.""" - def __init__(self, corpus: List[str], collection_name: str = None): - if collection_name: - stored_path = os.path.join(os.getcwd(), "saved_encoders", "tfidf", collection_name) - - if os.path.exists(stored_path): - with open(stored_path, "rb") as f: - self.vectorizer = pickle.load(f) - return - - self.vectorizer = TfidfVectorizer() - self.vectorizer.fit(corpus) - - if collection_name: - os.makedirs(os.path.dirname(stored_path), exist_ok=True) - with open(stored_path, "wb") as f: - pickle.dump(self.vectorizer, f) - - def __call__(self, texts: List[str]):# -> Embeddings: - """Transform the texts into TF-IDF embeddings.""" - return self.vectorizer.transform(texts).toarray().tolist() - - @staticmethod - def name() -> str: - return "default" \ No newline at end of file diff --git a/DashAI/back/models/RAG/encodings/__init__.py b/DashAI/back/models/RAG/encodings/__init__.py new file mode 100644 index 000000000..bf36b680c --- /dev/null +++ b/DashAI/back/models/RAG/encodings/__init__.py @@ -0,0 +1,6 @@ +from DashAI.back.models.RAG.encodings.encoding import Encoding +from DashAI.back.models.RAG.encodings.dense_encoding import DenseEncoding +from DashAI.back.models.RAG.encodings.sparse_encoding import SparseEncoding +from DashAI.back.models.RAG.encodings.trainable_encoding import TrainableEncoding +from DashAI.back.models.RAG.encodings.sparse import * +from DashAI.back.models.RAG.encodings.dense import * \ No newline at end of file diff --git a/DashAI/back/models/RAG/encodings/dense/__init__.py b/DashAI/back/models/RAG/encodings/dense/__init__.py new file mode 100644 index 000000000..549f15377 --- /dev/null +++ b/DashAI/back/models/RAG/encodings/dense/__init__.py @@ -0,0 +1,2 @@ +from DashAI.back.models.RAG.encodings.dense.fasttext_embedding import FastTextEmbedding +from DashAI.back.models.RAG.encodings.dense.huggingface_embedding import HuggingFaceEmbedding \ No newline at end of file diff --git a/DashAI/back/models/RAG/encodings/dense/fasttext_embedding.py b/DashAI/back/models/RAG/encodings/dense/fasttext_embedding.py new file mode 100644 index 000000000..12c5e9e74 --- /dev/null +++ b/DashAI/back/models/RAG/encodings/dense/fasttext_embedding.py @@ -0,0 +1,61 @@ + +from typing import List + +import numpy as np +from DashAI.back.core.schema_fields import enum_field +from DashAI.back.core.schema_fields.schema_field import schema_field +from DashAI.back.models.RAG.encodings.dense_encoding import DenseEncoding + +import fasttext +from huggingface_hub import hf_hub_download + +class FastTextEmbeddingSchema(DenseEncoding.SCHEMA): + model_name: schema_field( + enum_field( + [ + "facebook/fasttext-es-vectors", + "facebook/fasttext-en-vectors" + ] + ), + "facebook/fasttext-en-vectors", + "Name of the pre-trained model to use", + ) # type: ignore + + pooling_strategy: schema_field( + enum_field( + [ + "mean", + "max" + ] + ), + "mean", + "Pooling strategy to use", + ) # type: ignore + +class FastTextEmbedding(DenseEncoding): + """FastText embedding""" + + SCHEMA = FastTextEmbeddingSchema + DESCRIPTION = "Convert text to embeddings using FastText." + + def __init__(self, **kwargs): + self.validate_and_transform(**kwargs) + self.model_name = kwargs.get("model_name") + self.pooling_strategy = kwargs.get("pooling_strategy") + pooling_functions = { + "mean": np.mean, + "max": np.max + } + self.pooling_function = pooling_functions[self.pooling_strategy] + + def _load_model(self): + """Load the FastText model.""" + model_name = self.model_name.split("/")[-1] + model_path = hf_hub_download(repo_id=self.model_name, filename=f"{model_name}.bin") + self.model = fasttext.load_model(model_path) + + def encode(self, text: str) -> np.ndarray: + """Encode text into an embedding.""" + token_embeddings = [self.model.get_word_vector(word) for word in text.split()] + return self.pooling_function(np.array(token_embeddings), axis=0) + \ No newline at end of file diff --git a/DashAI/back/models/RAG/encodings/dense/huggingface_embedding.py b/DashAI/back/models/RAG/encodings/dense/huggingface_embedding.py new file mode 100644 index 000000000..23ce06f24 --- /dev/null +++ b/DashAI/back/models/RAG/encodings/dense/huggingface_embedding.py @@ -0,0 +1,127 @@ +from transformers import AutoModel + + +from DashAI.back.core.schema_fields import ( + BaseSchema, + schema_field, + enum_field +) +from DashAI.back.models.RAG.encodings.dense_encoding import DenseEncoding + +from typing import Final, List +import numpy as np +import torch +from transformers import AutoModel, AutoTokenizer + +from DashAI.back.models.RAG.encodings.dense_encoding import DenseEncoding +from DashAI.back.core.schema_fields import ( + enum_field, + int_field, + schema_field, +) +from DashAI.back.core.schema_fields.base_schema import BaseSchema + + +class HuggingFaceEmbeddingSchema(BaseSchema): + model_name: schema_field( + enum_field( + [ + # Sentence Transformers Models + "sentence-transformers/all-MiniLM-L6-v2", + "sentence-transformers/all-mpnet-base-v2", + "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2", + "sentence-transformers/all-distilroberta-v1", + # BERT Models + "bert-base-uncased", + "bert-large-uncased", + "bert-base-multilingual-cased", + "distilbert-base-uncased", + # RoBERTa Models + "roberta-base", + "roberta-large", + "distilroberta-base", + ] + ), + "sentence-transformers/all-MiniLM-L6-v2", + "Name of the pre-trained model to use", + ) # type: ignore + + max_length: schema_field( + int_field(ge=1), 512, "Maximum sequence length for tokenization" + ) # type: ignore + + batch_size: schema_field( + int_field(ge=1), 32, "Number of samples to process at once" + ) # type: ignore + + device: schema_field( + enum_field(["cuda", "cpu"]), + "cpu", + "Device to use for computation", + ) # type: ignore + + pooling_strategy: schema_field( + enum_field(["mean", "cls", "max"]), + "mean", + "Strategy to pool token embeddings into sentence embedding", + ) # type: ignore + + +class HuggingFaceEmbedding(DenseEncoding): + """HuggingFace embedding""" + + SCHEMA = HuggingFaceEmbeddingSchema + DESCRIPTION = "Convert text to embeddings using HuggingFace transformer models." + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.pooling_strategy = kwargs.get("pooling_strategy", "mean") + self.model_name = kwargs.get( + "model_name", "sentence-transformers/all-MiniLM-L6-v2" + ) + self.device = kwargs.get("device", "cpu") + self.max_length = kwargs.get("max_length", 512) + self.batch_size = kwargs.get("batch_size", 32) + self.model = None + self.tokenizer = None + + def _load_model(self): + """Load the embedding model and tokenizer.""" + self.tokenizer = AutoTokenizer.from_pretrained(self.model_name) + self.model = AutoModel.from_pretrained(self.model_name).to(self.device) + self.model.eval() + + def _encode_texts(self, texts:List[str])-> List[np.ndarray]: + """Encode a list of texts into embeddings.""" + # Tokenize + encoded = self.tokenizer( + texts, + padding=True, + truncation=True, + max_length=self.max_length, + return_tensors="pt", + ) + + # Move to device + encoded = {k: v.to(self.device) for k, v in encoded.items()} + + # Get embeddings + with torch.no_grad(): + outputs = self.model(**encoded) + hidden_states = outputs.last_hidden_state + + # Apply pooling strategy + if self.pooling_strategy == "mean": + embeddings = torch.mean(hidden_states, dim=1) + elif self.pooling_strategy == "cls": + embeddings = hidden_states[:, 0] + else: # max pooling + embeddings = torch.max(hidden_states, dim=1)[0] + + embeddings_np = embeddings.cpu().numpy() + return embeddings_np + + def encode(self, text: str) -> np.ndarray: + """Encode a single text into an embedding.""" + embeddings = self._encode_texts([text]) + return embeddings[0] if embeddings else np.array([]) diff --git a/DashAI/back/models/RAG/encodings/dense_encoding.py b/DashAI/back/models/RAG/encodings/dense_encoding.py new file mode 100644 index 000000000..37b7ff6ba --- /dev/null +++ b/DashAI/back/models/RAG/encodings/dense_encoding.py @@ -0,0 +1,24 @@ + +from DashAI.back.models.RAG.encodings.encoding import Encoding + + +class DenseEncoding(Encoding): + """ + Base class for all dense encoding (embedding) models. + """ + + def __init__(self, **kwargs): + """ + Initialize the dense encoding (embedding) model with the given documents. + """ + raise NotImplementedError("Subclasses must implement the __init__ method.") + + def encode(self, text: str): + """ + Method to generate dense encodings (embeddings) for the given text. + This method should be implemented by subclasses. + + :param text: The input text to encode (embed). + :return: A list representing the dense encodings (embeddings) of the input text. + """ + raise NotImplementedError("Subclasses must implement this method.") \ No newline at end of file diff --git a/DashAI/back/models/RAG/encodings/encoding.py b/DashAI/back/models/RAG/encodings/encoding.py new file mode 100644 index 000000000..0e2d65c9c --- /dev/null +++ b/DashAI/back/models/RAG/encodings/encoding.py @@ -0,0 +1,32 @@ +from abc import ABCMeta +import hashlib +from typing import Any, List +import numpy as np + +from DashAI.back.models.RAG.documents.BaseDocument import BaseDocument +from DashAI.back.models.base_model import BaseModel + +class Encoding(BaseModel): + """ + Base class for all encoding (embedding) models. + This class should be inherited by any specific encoding (embedding) model implementation. + """ + EMBEDDINGS_PATH = "RAG/embeddings" + + def __init__( + self, + **kwargs: Any): + """ + Initialize the encoding (embedding) model with the given documents. + """ + raise NotImplementedError("Subclasses must implement the __init__ method.") + + def encode(self, text: str) -> List[float]|np.ndarray|Any: + """ + Method to generate encodings (embeddings) for the given text. + This method should be implemented by subclasses. + + :param text: The input text to encode (embed). + :return: A list representing the encodings (embeddings) of the input text. + """ + raise NotImplementedError("Subclasses must implement this method.") \ No newline at end of file diff --git a/DashAI/back/models/RAG/encodings/sparse/__init__.py b/DashAI/back/models/RAG/encodings/sparse/__init__.py new file mode 100644 index 000000000..a2aa69555 --- /dev/null +++ b/DashAI/back/models/RAG/encodings/sparse/__init__.py @@ -0,0 +1,2 @@ +from DashAI.back.models.RAG.encodings.sparse.bm25_encoding import BM25Encoding +from DashAI.back.models.RAG.encodings.sparse.tfidf_encoding import TFIDFEncoding \ No newline at end of file diff --git a/DashAI/back/models/RAG/encodings/sparse/bm25_encoding.py b/DashAI/back/models/RAG/encodings/sparse/bm25_encoding.py new file mode 100644 index 000000000..f239a893d --- /dev/null +++ b/DashAI/back/models/RAG/encodings/sparse/bm25_encoding.py @@ -0,0 +1,302 @@ +import os +from DashAI.back.converters.hugging_face import embedding +from DashAI.back.models.RAG.encodings.sparse_encoding import SparseEncoding +from DashAI.back.models.RAG.documents import BaseDocument, PDFDocument, TxtDocument +from typing import List, Dict, Any, Tuple +from sklearn.feature_extraction.text import TfidfVectorizer +from sklearn.metrics.pairwise import cosine_similarity, euclidean_distances +import numpy as np +import hashlib +import pickle + +from DashAI.back.core.schema_fields import ( + BaseSchema, + list_field, + schema_field, + enum_field, + float_field, + int_field, + bool_field, + string_field +) + +class BM25EncodingSchema(BaseSchema): + + strip_accents: schema_field( + enum_field( + enum=["ascii", "unicode", None], + ), + placeholder=None, + description="Whether to strip accents from the text.", + ) # type: ignore + + lowercase: schema_field( + bool_field(), + placeholder=True, + description="Whether to convert all characters to lowercase.", + + ) # type: ignore + + stop_words: schema_field( + list_field( + string_field(), + min_items=1, + ), + placeholder=None, + description="List of stop words to be used in the TF-IDF vectorization.", + ) # type: ignore + + max_df: schema_field( + float_field( + ge=0.0, + le=1.0, + ), + placeholder=1.0, + description="When building the vocabulary ignore terms that have a document frequency strictly higher than the given threshold (corpus-specific stop words).", + ) # type: ignore + + min_df: schema_field( + float_field( + ge=0.0, + le=1.0, + ), + placeholder=1.0, + description="When building the vocabulary ignore terms that have a document frequency strictly lower than the given threshold (corpus-specific stop words).", + ) # type: ignore + + max_features: schema_field( + int_field( + ge=1, + ), + placeholder=None, + description="If not None, build a vocabulary that only consider the top max_features ordered by term frequency across the corpus.", + ) # type: ignore + + +class BM25Encoding(SparseEncoding): + """ + BM25 encoding (embedding) model for text documents. + This class implements the precomputation of BM25 scores for text documents. + """ + + def __init__( + self, + documents_chunks: Dict[int, List[str]], + k: float, + b: float, + delta: float, + strip_accents: str, + lowercase: bool, + analyzer: str, + stop_words: List[str], + max_df: float, + min_df: float, + max_features: int, + store_model: bool = True + ) -> None: + """ + Initialize the BM25 encoding model with the given document chunks. + + Args: + documents_chunks (Dict[int, List[str]]): A dictionary where keys are document IDs and values are lists of text chunks. + """ + # sort chunks by document ID to ensure consistency + documents_chunks = dict(sorted(documents_chunks.items())) + + chunks_mapping = {} + chunks_texts = [] + n_chunks = 0 + for doc_id, chunks in documents_chunks.items(): + for chunk_text in chunks: + chunks_texts.append(chunk_text) + chunks_mapping[n_chunks] = (doc_id, chunk_text) + n_chunks += 1 + + self.chunks_texts = chunks_texts + self.chunks_mapping = chunks_mapping + self.strip_accents = strip_accents + self.lowercase = lowercase + self.analyzer = analyzer + self.stop_words = stop_words + self.max_df = max_df + self.min_df = min_df + self.max_features = max_features + + self.hyperparameters = { + "k": k, + "b": b, + "delta": delta, + "strip_accents": strip_accents, + "lowercase": lowercase, + "analyzer": analyzer, + "stop_words": stop_words, + "max_df": max_df, + "min_df": min_df, + "max_features": max_features, + } + + load_success = self._load_model() + print(f"BM25 model loaded successfully: {load_success}") + if not load_success: + print("Fitting the BM25 model...") + self._fit_model() + if store_model: + print("Saving the BM25 model...") + self._save_model() + print("BM25 model fitted and saved.") + + def _hash_function(self, input_string: str) -> str: + """ + Generate a SHA-256 hash for the given input string. + + Args: + input_string (str): The input string to hash. + + Returns: + str: The SHA-256 hash of the input string. + """ + return hashlib.sha256(input_string.encode('utf-8')).hexdigest() + + def _get_encoding_signature(self) -> str: + """ + Generate a hash to identify the encoding (embeddings) for caching purposes. + + Hash is calculated over the documents' content to ensure consistency in encoding (embeddings), it must: + - Be consistent across runs with the same documents content, chunking strategy and encoding (embeddings) model parameters. + - Change if the documents are modified. + - Change if the documents content is modified. + - Change if the chunking strategy is modified. + - Change if the encoding (embeddings) model parameters are modified. +k + Returns: + str: A hash string representing the encoding (embeddings). + """ + params_hash = self._hash_function(str(self.hyperparameters)) + documents_chunks_hash = self._hash_function(str(self.chunks_mapping)) + return self._hash_function(params_hash + documents_chunks_hash) + + def _fit_model(self) -> None: + """ + Fit the TF-IDF model to the document chunks. + This method initializes the TF-IDF vectorizer and fits it to the document chunks. + """ + self.vectorizer = TfidfVectorizer( + strip_accents=self.strip_accents, + lowercase=self.lowercase, + analyzer=self.analyzer, + stop_words=self.stop_words, + ngram_range=tuple(self.ngram_range), + max_df=self.max_df, + min_df=self.min_df, + max_features=self.max_features, + + norm=None, + smooth_idf=False, + sublinear_tf=False, + use_idf=False, + ) + + tf_matrix = self.vectorizer.fit_transform(self.chunks_texts) + document_lengths = tf_matrix.sum(axis=1) + idf = np.log(tf_matrix.shape[0] / document_lengths) + + tf_matrix = tf_matrix.multiply(self.k + 1) / (tf_matrix + self.k * (1 - self.b + self.b * document_lengths)) + tf_matrix = tf_matrix.multiply(idf.reshape(-1, 1)) + + def _get_model_paths(self) -> Tuple[str, str, str, str]: + """ + Get the paths for saving the model components. + Returns a tuple containing the folder path, vectorizer path, term matrix path, and feature names path. + """ + folder_path = os.path.join( + self.EMBEDDINGS_PATH, + self._get_encoding_signature() + ) + + vectorizer_path = os.path.join(folder_path, "vectorizer.pkl") + tf_matrix_path = os.path.join(folder_path, "tf_matrix.pkl") + + return folder_path, vectorizer_path, tf_matrix_path + + def _save_model(self) -> None: + """ + Save the model components to disk. + This method saves the vectorizer, term matrix, and feature names to their respective files. + """ + + folder_path, vectorizer_path, tf_matrix_path = self._get_model_paths() + + # Create the folder if it doesn't exist + os.makedirs(folder_path, exist_ok=True) + + with open(vectorizer_path, 'wb') as f: + pickle.dump(self.vectorizer, f) + + with open(tf_matrix_path, 'wb') as f: + pickle.dump(self._tf_matrix, f) + + def _load_model(self) -> bool: + """ + Try to load the model components from disk. + If the model components are not found, return False. + If the model components are found, load them into the instance variables and return True. + """ + folder_path, vectorizer_path, tf_matrix_path = self._get_model_paths() + if not ( + os.path.exists(vectorizer_path) and + os.path.exists(tf_matrix_path)): + return False + + # Load the vectorizer + with open(vectorizer_path, 'rb') as f: + self.vectorizer = pickle.load(f) + + # Load the term matrix + with open(tf_matrix_path, 'rb') as f: + self._tf_matrix = pickle.load(f) + + self._document_lengths = self._tf_matrix.sum(axis=1) + self._average_document_length = np.mean(self._document_lengths) + self._idf = np.log(self._tf_matrix.shape[0] / self._document_lengths) + + return True + + def get_documents_chunks_encodings(self) -> Dict[int, List[np.ndarray]]: + """ + Get the encodings (embeddings) for each document chunk. + + Returns: + Dict[int, List[np.ndarray]]: A dictionary where keys are document IDs and values are lists of encodings (embeddings) for each chunk. + """ + if not hasattr(self, 'vectorizer'): + raise RuntimeError("The model has not been fitted yet. Call _fit_model() before getting encodings (embeddings).") + + encodings = self._tf_matrix.toarray() + n_chunks = encodings.shape[0] + + # Map the encodings back to the document IDs using the chunks_mapping + documents_chunks_encodings = {} + for i in range(n_chunks): + doc_id, _ = self.chunks_mapping[i] + if doc_id not in documents_chunks_encodings: + documents_chunks_encodings[doc_id] = [] + documents_chunks_encodings[doc_id].append(encodings[i]) + + return documents_chunks_encodings + + def encode(self, text: str) -> List[float]: + """ + Generate TF-IDF encodings (embeddings) for the given text. + + Args: + text (str): The input text to embed. + + Returns: + List[float]: A list representing the TF-IDF encodings (embeddings) of the input text. + """ + if not hasattr(self, 'vectorizer'): + raise RuntimeError("The model has not been fitted yet. Call _fit_model() before encoding (embedding) text.") + + # Transform the input text to get its TF-IDF representation + tfidf_vector = self.vectorizer.transform([text]) + return tfidf_vector.toarray() \ No newline at end of file diff --git a/DashAI/back/models/RAG/embeddings/tf_idf_embedding.py b/DashAI/back/models/RAG/encodings/sparse/tfidf_encoding.py similarity index 80% rename from DashAI/back/models/RAG/embeddings/tf_idf_embedding.py rename to DashAI/back/models/RAG/encodings/sparse/tfidf_encoding.py index cfdb9ed5b..560d6c2f2 100644 --- a/DashAI/back/models/RAG/embeddings/tf_idf_embedding.py +++ b/DashAI/back/models/RAG/encodings/sparse/tfidf_encoding.py @@ -1,5 +1,6 @@ import os -from DashAI.back.models.RAG.embeddings.sparse_embedding import SparseEmbedding +from DashAI.back.converters.hugging_face import embedding +from DashAI.back.models.RAG.encodings.sparse_encoding import SparseEncoding from DashAI.back.models.RAG.documents import BaseDocument, PDFDocument, TxtDocument from typing import List, Dict, Any, Tuple from sklearn.feature_extraction.text import TfidfVectorizer @@ -19,7 +20,7 @@ string_field ) -class TFIDFEmbeddingSchema(BaseSchema): +class TFIDFEncodingSchema(BaseSchema): strip_accents: schema_field( enum_field( @@ -115,10 +116,10 @@ class TFIDFEmbeddingSchema(BaseSchema): description="Apply sublinear tf scaling, i.e. replace tf with 1 + log(tf).", ) # type: ignore -class TFIDFEmbedding(SparseEmbedding): +class TFIDFEncoding(SparseEncoding): """ - TF-IDF embedding model for text documents. - This class implements the TF-IDF algorithm to generate embeddings for text documents. + TF-IDF encoding (embedding) model for text documents. + This class implements the TF-IDF algorithm to generate encodings (embeddings) for text documents. """ def __init__( @@ -139,7 +140,7 @@ def __init__( store_model: bool = True ) -> None: """ - Initialize the TF-IDF embedding model with the given document chunks. + Initialize the TF-IDF encoding (embedding) model with the given document chunks. Args: documents_chunks (Dict[int, List[str]]): A dictionary where keys are document IDs and values are lists of text chunks. @@ -209,19 +210,19 @@ def _hash_function(self, input_string: str) -> str: """ return hashlib.sha256(input_string.encode('utf-8')).hexdigest() - def _calculate_embeddings_hash(self) -> str: + def _get_encoding_signature(self) -> str: """ - Generate a hash to identify the embeddings for caching purposes. - - Hash is calculated over the documents' content to ensure consistency in embeddings, it must: - - Be consistent across runs with the same documents content, chunking strategy and embedding model parameters. + Generate a hash to identify the encoding (embeddings) for caching purposes. + + Hash is calculated over the documents' content to ensure consistency in encoding (embeddings), it must: + - Be consistent across runs with the same documents content, chunking strategy and encoding (embeddings) model parameters. - Change if the documents are modified. - Change if the documents content is modified. - Change if the chunking strategy is modified. - - Change if the embedding model parameters are modified. - + - Change if the encoding (embeddings) model parameters are modified. + Returns: - str: A hash string representing the embeddings. + str: A hash string representing the encoding (embeddings). """ params_hash = self._hash_function(str(self.hyperparameters)) documents_chunks_hash = self._hash_function(str(self.chunks_mapping)) @@ -247,7 +248,6 @@ def _fit_model(self) -> None: sublinear_tf=self.sublinear_tf ) self._term_matrix = self.vectorizer.fit_transform(self.chunks_texts) - self._feature_names = self.vectorizer.get_feature_names_out() def _get_model_paths(self) -> Tuple[str, str, str, str]: """ @@ -255,15 +255,14 @@ def _get_model_paths(self) -> Tuple[str, str, str, str]: Returns a tuple containing the folder path, vectorizer path, term matrix path, and feature names path. """ folder_path = os.path.join( - self.EMBEDDINGS_PATH, - self._calculate_embeddings_hash() + self.EMBEDDINGS_PATH, + self._get_encoding_signature() ) vectorizer_path = os.path.join(folder_path, "vectorizer.pkl") term_matrix_path = os.path.join(folder_path, "term_matrix.pkl") - feature_names_path = os.path.join(folder_path, "feature_names.pkl") - return folder_path, vectorizer_path, term_matrix_path, feature_names_path + return folder_path, vectorizer_path, term_matrix_path def _save_model(self) -> None: """ @@ -271,7 +270,7 @@ def _save_model(self) -> None: This method saves the vectorizer, term matrix, and feature names to their respective files. """ - folder_path, vectorizer_path, term_matrix_path, feature_names_path = self._get_model_paths() + folder_path, vectorizer_path, term_matrix_path = self._get_model_paths() # Create the folder if it doesn't exist os.makedirs(folder_path, exist_ok=True) @@ -284,21 +283,16 @@ def _save_model(self) -> None: with open(term_matrix_path, 'wb') as f: pickle.dump(self._term_matrix, f) - # Save the feature names - with open(feature_names_path, 'wb') as f: - pickle.dump(self._feature_names, f) - def _load_model(self) -> None: """ Try to load the model components from disk. If the model components are not found, return False. If the model components are found, load them into the instance variables and return True. """ - folder_path, vectorizer_path, term_matrix_path, feature_names_path = self._get_model_paths() + folder_path, vectorizer_path, term_matrix_path= self._get_model_paths() if not ( os.path.exists(vectorizer_path) and - os.path.exists(term_matrix_path) and - os.path.exists(feature_names_path)): + os.path.exists(term_matrix_path)): return False # Load the vectorizer @@ -309,48 +303,44 @@ def _load_model(self) -> None: with open(term_matrix_path, 'rb') as f: self._term_matrix = pickle.load(f) - # Load the feature names - with open(feature_names_path, 'rb') as f: - self._feature_names = pickle.load(f) - return True - def get_documents_chunks_embeddings(self) -> Dict[int, List[np.ndarray]]: + def get_documents_chunks_encodings(self) -> Dict[int, List[np.ndarray]]: """ - Get the embeddings for each document chunk. + Get the encodings (embeddings) for each document chunk. Returns: - Dict[int, List[np.ndarray]]: A dictionary where keys are document IDs and values are lists of embeddings for each chunk. + Dict[int, List[np.ndarray]]: A dictionary where keys are document IDs and values are lists of encodings (embeddings) for each chunk. """ if not hasattr(self, 'vectorizer'): - raise RuntimeError("The model has not been fitted yet. Call _fit_model() before getting embeddings.") + raise RuntimeError("The model has not been fitted yet. Call _fit_model() before getting encodings (embeddings).") - embeddings = self._term_matrix.toarray() - n_chunks = embeddings.shape[0] + encodings = self._term_matrix.toarray() + n_chunks = encodings.shape[0] - # Map the embeddings back to the document IDs using the chunks_mapping - documents_chunks_embeddings = {} + # Map the encodings back to the document IDs using the chunks_mapping + documents_chunks_encodings = {} for i in range(n_chunks): doc_id, _ = self.chunks_mapping[i] - if doc_id not in documents_chunks_embeddings: - documents_chunks_embeddings[doc_id] = [] - documents_chunks_embeddings[doc_id].append(embeddings[i]) + if doc_id not in documents_chunks_encodings: + documents_chunks_encodings[doc_id] = [] + documents_chunks_encodings[doc_id].append(encodings[i]) - return documents_chunks_embeddings - - def embed(self, text: str) -> List[float]: + return documents_chunks_encodings + + def encode(self, text: str) -> List[float]: """ - Generate TF-IDF embeddings for the given text. - + Generate TF-IDF encodings (embeddings) for the given text. + Args: text (str): The input text to embed. Returns: - List[float]: A list representing the TF-IDF embeddings of the input text. + List[float]: A list representing the TF-IDF encodings (embeddings) of the input text. """ if not hasattr(self, 'vectorizer'): - raise RuntimeError("The model has not been fitted yet. Call _fit_model() before embedding text.") + raise RuntimeError("The model has not been fitted yet. Call _fit_model() before encoding (embedding) text.") # Transform the input text to get its TF-IDF representation tfidf_vector = self.vectorizer.transform([text]) diff --git a/DashAI/back/models/RAG/embeddings/sparse_embedding.py b/DashAI/back/models/RAG/encodings/sparse_encoding.py similarity index 53% rename from DashAI/back/models/RAG/embeddings/sparse_embedding.py rename to DashAI/back/models/RAG/encodings/sparse_encoding.py index 706295673..cadba17d6 100644 --- a/DashAI/back/models/RAG/embeddings/sparse_embedding.py +++ b/DashAI/back/models/RAG/encodings/sparse_encoding.py @@ -1,29 +1,29 @@ import numpy as np from DashAI.back.models.RAG.documents import BaseDocument -from DashAI.back.models.RAG.embeddings.base_embedding import BaseEmbedding +from DashAI.back.models.RAG.encodings.encoding import Encoding from typing import Any, List -class SparseEmbedding(BaseEmbedding): +class SparseEncoding(Encoding): """ - Base class for sparse embedding models. - This class should be inherited by any specific sparse embedding model implementation. + Base class for sparse encoding (embedding) models. + This class should be inherited by any specific sparse encoding (embedding) model implementation. """ def __init__(self, documents: List[BaseDocument], **kwargs: Any): """ - Initialize the sparse embedding model with the given documents. + Initialize the sparse encoding (embedding) model with the given documents. :param documents: List of documents to be embedded. :param kwargs: Additional keyword arguments. """ raise NotImplementedError("Subclasses must implement the __init__ method.") - def embed(self, text: str) -> List|np.ndarray|Any: + def encode(self, text: str) -> List|np.ndarray|Any: """ - Method to generate sparse embeddings for the given text. + Method to generate sparse encodings (embeddings) for the given text. This method should be implemented by subclasses. :param text: The input text to embed. - :return: A list representing the sparse embeddings of the input text. + :return: A list representing the sparse encodings (embeddings) of the input text. """ raise NotImplementedError("Subclasses must implement this method.") \ No newline at end of file diff --git a/DashAI/back/models/RAG/embeddings/base_embedding.py b/DashAI/back/models/RAG/encodings/trainable_encoding.py similarity index 65% rename from DashAI/back/models/RAG/embeddings/base_embedding.py rename to DashAI/back/models/RAG/encodings/trainable_encoding.py index 025e112a6..44f032707 100644 --- a/DashAI/back/models/RAG/embeddings/base_embedding.py +++ b/DashAI/back/models/RAG/encodings/trainable_encoding.py @@ -1,40 +1,39 @@ from abc import ABCMeta import hashlib -from DashAI.back.config_object import ConfigObject from typing import Any, List import numpy as np from DashAI.back.models.RAG.documents.BaseDocument import BaseDocument +from DashAI.back.models.RAG.encodings.encoding import Encoding -class BaseEmbedding(ConfigObject, metaclass=ABCMeta): +class TrainableEncoding(Encoding): """ - Base class for all embedding models. - This class should be inherited by any specific embedding model implementation. + Base class for all encoding (embedding) models. + This class should be inherited by any specific encoding (embedding) model implementation. """ EMBEDDINGS_PATH = "RAG/embeddings" def __init__( self, - documents: List[BaseDocument], **kwargs: Any): """ - Initialize the embedding model with the given documents. + Initialize the encoding (embedding) model with the given documents. """ raise NotImplementedError("Subclasses must implement the __init__ method.") - def _calculate_embeddings_hash(self) -> str: + def _get_encoding_signature(self) -> str: """ - Generate a hash to identify the embeddings for caching purposes. - - Hash is calculated over the documents' content to ensure consistency in embeddings, it must: - - Be consistent across runs with the same documents content, chunking strategy and embedding model parameters. + Generate a hash to identify the encoding (embedding) for caching purposes. + + Hash is calculated over the documents' content to ensure consistency in encodings, it must: + - Be consistent across runs with the same documents content, chunking strategy and encoding model parameters. - Change if the documents are modified. - Change if the documents content is modified. - Change if the chunking strategy is modified. - - Change if the embedding model parameters are modified. - + - Change if the encoding model parameters are modified. + Returns: - str: A hash string representing the embeddings. + str: A hash string representing the encodings (embeddings). """ raise NotImplementedError("Subclasses must implement this method.") @@ -42,7 +41,7 @@ def _calculate_documents_chunks_hash(self) -> str: """ Generate a hash to identify the documents chunks' texts for caching purposes. - Hash is calculated over the chunks' texts to ensure consistency in embeddings, it must: + Hash is calculated over the chunks' texts to ensure consistency in encodings, it must: - Be consistent across runs with the same documents content and chunking strategy. - Change if the documents are modified. - Change if the documents content is modified. @@ -59,12 +58,12 @@ def _calculate_documents_chunks_hash(self) -> str: return hashlib.sha256(joint_text.encode('utf-8')).hexdigest() - def embed(self, text: str) -> List[float]|np.ndarray|Any: + def encode(self, text: str) -> List[float]|np.ndarray|Any: """ - Method to generate embeddings for the given text. + Method to generate encodings (embeddings) for the given text. This method should be implemented by subclasses. - - :param text: The input text to embed. - :return: A list representing the embeddings of the input text. + + :param text: The input text to encode (embed). + :return: A list representing the encodings (embeddings) of the input text. """ raise NotImplementedError("Subclasses must implement this method.") \ No newline at end of file diff --git a/DashAI/back/models/RAG/prompts/__init__.py b/DashAI/back/models/RAG/prompts/__init__.py index 95e26dcfe..5bae15c12 100644 --- a/DashAI/back/models/RAG/prompts/__init__.py +++ b/DashAI/back/models/RAG/prompts/__init__.py @@ -1,3 +1,3 @@ from DashAI.back.models.RAG.prompts.augmentation_prompt import AugmentationPrompt from DashAI.back.models.RAG.prompts.context_merge_prompt import ContextMergePrompt -from DashAI.back.models.RAG.prompts.base_prompt import BasePrompt \ No newline at end of file +from DashAI.back.models.RAG.prompts.prompt import Prompt \ No newline at end of file diff --git a/DashAI/back/models/RAG/prompts/augmentation_prompt.py b/DashAI/back/models/RAG/prompts/augmentation_prompt.py index a5d399b8a..125e825e3 100644 --- a/DashAI/back/models/RAG/prompts/augmentation_prompt.py +++ b/DashAI/back/models/RAG/prompts/augmentation_prompt.py @@ -1,8 +1,8 @@ from typing import List, Tuple, Any -from DashAI.back.models.RAG.prompts.base_prompt import BasePrompt +from DashAI.back.models.RAG.prompts.prompt import Prompt -class AugmentationPrompt(BasePrompt): +class AugmentationPrompt(Prompt): """ AugmentationPrompt class for generating augmented retrieval prompts, it uses the language model to generate keywords or phrases that can be used to augment the input. diff --git a/DashAI/back/models/RAG/prompts/context_merge_prompt.py b/DashAI/back/models/RAG/prompts/context_merge_prompt.py index 7f00a2787..42d5affe7 100644 --- a/DashAI/back/models/RAG/prompts/context_merge_prompt.py +++ b/DashAI/back/models/RAG/prompts/context_merge_prompt.py @@ -1,7 +1,7 @@ from typing import Any, List, Tuple -from DashAI.back.models.RAG.prompts.base_prompt import BasePrompt +from DashAI.back.models.RAG.prompts.prompt import Prompt -class ContextMergePrompt(BasePrompt): +class ContextMergePrompt(Prompt): """ ContextMergePrompt class for generating prompts that merge the use input, the retrieved documents and the chat history into a single context for the language model. diff --git a/DashAI/back/models/RAG/prompts/base_prompt.py b/DashAI/back/models/RAG/prompts/prompt.py similarity index 87% rename from DashAI/back/models/RAG/prompts/base_prompt.py rename to DashAI/back/models/RAG/prompts/prompt.py index 7f66fcc74..70a45fdc1 100644 --- a/DashAI/back/models/RAG/prompts/base_prompt.py +++ b/DashAI/back/models/RAG/prompts/prompt.py @@ -1,7 +1,8 @@ -from abc import ABC from typing import Any -class BasePrompt(ABC): +from DashAI.back.models.base_model import BaseModel + +class Prompt(BaseModel): """ Base class for all RAG prompt templates. This class defines the interface for creating and formatting prompts. diff --git a/DashAI/back/models/__init__.py b/DashAI/back/models/__init__.py index 09aa57b6d..e62e578c9 100644 --- a/DashAI/back/models/__init__.py +++ b/DashAI/back/models/__init__.py @@ -48,4 +48,4 @@ from DashAI.back.models.scikit_learn.sklearn_like_regressor import SklearnLikeRegressor from DashAI.back.models.scikit_learn.svc import SVC -from DashAI.back.models.RAG import RAGPipeline, BaseRetriever, TFIDFRetriever, DenseRetriever \ No newline at end of file +from DashAI.back.models.RAG import RAGPipeline, RetrieverModel, TFIDFRetriever, DenseRetriever \ No newline at end of file diff --git a/DashAI/front/src/api/component.ts b/DashAI/front/src/api/component.ts index 9a7306017..2286f8585 100644 --- a/DashAI/front/src/api/component.ts +++ b/DashAI/front/src/api/component.ts @@ -49,3 +49,10 @@ export const getComponents = async ({ }); return response.data; }; + +export const getChildComponents = async (componentName: string, recursive: boolean): Promise => { + const response = await api.get(`/v1/component/${componentName}/children`, { + params: { recursive }, + }); + return response.data; +}; \ No newline at end of file diff --git a/DashAI/front/src/api/rag.ts b/DashAI/front/src/api/rag.ts index 90500a6b8..e4b95479a 100644 --- a/DashAI/front/src/api/rag.ts +++ b/DashAI/front/src/api/rag.ts @@ -2,6 +2,8 @@ import api from "./api"; import { ISession } from "../types/session"; import { IGenerativeTask } from "../types/generativeTask"; import { IDocumentResponse } from "../types/documentResponse"; +import { IComponent } from "../types/component"; +import { getChildComponents } from "./component"; // Fetch all RAG sessions @@ -108,18 +110,25 @@ export const updateGenerativeSessionParams = async ( return response.data; } +export const getRetrievalParadigm = async (): Promise => { -export const getRetrieverComponents = async (): Promise => { + const response = getChildComponents('RetrieverModel', false); + if (!response) { + throw new Error(`Failed to fetch retrieval options`); + } + return response; +} - const response = await api.get( - `/v1/component/?select_types=RetrieverModel` - ); - if (response.status !== 200) { - throw new Error(`Failed to fetch retriever components: ${response.statusText}`); +export const getRetrieverComponents = async (retrievalParadigm: string): Promise => { + + const response = getChildComponents(retrievalParadigm, false); + + if (!response) { + throw new Error(`Failed to fetch retriever components`); } - return response.data; + return response; } diff --git a/DashAI/front/src/components/documents/DocumentTable.jsx b/DashAI/front/src/components/documents/DocumentTable.jsx index 320c96d90..1ecd4471e 100644 --- a/DashAI/front/src/components/documents/DocumentTable.jsx +++ b/DashAI/front/src/components/documents/DocumentTable.jsx @@ -174,7 +174,7 @@ function DocumentTable({ }, }, }} - getRowId={(row) => row.id} + getRowId={(row) => String(row.id)} pageSize={5} sortModel={[{ field: "id", sort: "asc" }]} pageSizeOptions={[5, 10]} diff --git a/DashAI/front/src/pages/generative/RAG/NewSessionModal.jsx b/DashAI/front/src/pages/generative/RAG/NewSessionModal.jsx index d4efa0d1d..d1377381f 100644 --- a/DashAI/front/src/pages/generative/RAG/NewSessionModal.jsx +++ b/DashAI/front/src/pages/generative/RAG/NewSessionModal.jsx @@ -18,7 +18,8 @@ import useMediaQuery from "@mui/material/useMediaQuery"; import DocumentSelectionStep from "./DocumentSelectionStep"; import RetrieverConfigurationStep from "./RetrieverConfigurationStep"; -import GeneratorConfigurationStep from "./GeneratorConfigurationStep"; +import GeneratorConfigurationStep from "./GeneratorConfigurationStep"; +//import ChunkingConfigurationStep from "./ChunkingConfigurationStep"; const steps = [ { @@ -26,6 +27,11 @@ const steps = [ label: "Select documents", component: DocumentSelectionStep, }, +// { +// name: "configure-chunking", +// label: "Configure chunking", +// component: ChunkingConfigurationStep, +// }, { name: "configure-retriever", label: "Configure retriever", @@ -45,6 +51,9 @@ const defaultNewSession = { displayName: "", parameters: { "documents": [], + // "chunking": { + // "parameters": {}, + // }, "retriever_model": { "name": "", "parameters": {}, @@ -65,9 +74,10 @@ export default function NewSessionModal({ }) { const theme = useTheme(); const screenSm = useMediaQuery(theme.breakpoints.down("sm")); + const [activeStep, setActiveStep] = useState(0); - const [sessionData, setSessionData] = useState(session || defaultNewSession); const [stepValidity, setStepValidity] = useState(new Array(steps.length).fill(false)); + const [sessionData, setSessionData] = useState(session || defaultNewSession); useEffect(() => { diff --git a/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx b/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx index 2d4069c06..9448eeabd 100644 --- a/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx +++ b/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx @@ -1,114 +1,74 @@ import { useState, useEffect, useCallback } from "react"; -import PropTypes from "prop-types"; -import { Box, Autocomplete, TextField, Typography, Button } from "@mui/material"; // Added Button and Typography for consistency -import { useFormik } from "formik"; // Import useFormik -import FormSchemaRenderFields from "../../../components/shared/FormSchemaRenderFields"; // Assuming this component is correctly implemented -import { getRetrieverComponents } from "../../../api/rag"; // Assuming this API call is correct -import { preprocessSchema, buildYupSchema } from "../../../components/generative/utils" - - - -export default function RetrieverConfigurationStep({ retrieverModel, setRetrieverModel, setNextEnabled }) { - const [retrievers, setRetrievers] = useState([]); - const [currentSelectedRetrieverOption, setCurrentSelectedRetrieverOption] = useState(null); - const [validationSchema, setValidationSchema] = useState(null); +import { Box, Autocomplete, TextField, Typography } from "@mui/material"; +import { DataGrid } from "@mui/x-data-grid"; +import EditModelDialog from "../../../components/experiments/EditModelDialog"; +import { getRetrieverComponents, getRetrievalParadigm } from "../../../api/rag"; +import { useSnackbar } from "notistack"; +import useSchema from "../../../hooks/useSchema"; + +export default function RetrieverConfigurationStep({ setNextEnabled }) { + const { enqueueSnackbar } = useSnackbar(); + const [retrievalParadigms, setRetrievalParadigms] = useState([]); + const [selectedRetrievalParadigm, setSelectedRetrievalParadigm] = useState(null); + + const [retrieverOptions, setRetrieverOptions] = useState([]); + const [selectedRetriever, setSelectedRetriever] = useState(null); + const [retrieverInitialParameters, setRetrieverInitialParameters] = useState({}); + const [retrieverParamsSchema, setRetrieverParamsSchema] = useState(null); + + const fetchRetrievalParadigms = async () => { + try { + const data = await getRetrievalParadigm(); + setRetrievalParadigms(data); + enqueueSnackbar('Retrieval paradigms loaded successfully!', { variant: 'success' }); + } catch (error) { + console.error("Error fetching retrieval paradigms:", error); + enqueueSnackbar('Failed to load retrieval paradigms.', { variant: 'error' }); + } + }; - const getInitialParamsFromSchema = useCallback((schemaProperties) => { - if (!schemaProperties) return {}; - return Object.keys(schemaProperties).reduce((acc, key) => { - acc[key] = schemaProperties[key].placeholder !== undefined - ? schemaProperties[key].placeholder - : ""; - return acc; - }, {}); + useEffect(() => { + fetchRetrievalParadigms(); }, []); - useEffect(() => { - const loadAndSetRetriever = async () => { - const data = await getRetrieverComponents(); - setRetrievers(data); + const fetchRetrievers = async () => { + if (!selectedRetrievalParadigm) { + setRetrieverOptions([]); + setSelectedRetriever(null); + return; + } - if (retrieverModel?.name) { - const existingRetriever = data.find(r => r.name === retrieverModel.name); - if (existingRetriever) { - setCurrentSelectedRetrieverOption(existingRetriever); - } + // For non-Sparse paradigms, only set retriever if schema and schema.properties exist + if (selectedRetrievalParadigm.schema && selectedRetrievalParadigm.schema.properties) { + setRetrieverOptions([selectedRetrievalParadigm]); + setSelectedRetriever(selectedRetrievalParadigm); + } else { + setRetrieverOptions([]); + setSelectedRetriever(null); } - }; - loadAndSetRetriever(); - }, [retrieverModel?.name]); - - const formik = useFormik({ - initialValues: retrieverModel?.parameters || {}, - validationSchema: validationSchema, - enableReinitialize: true, - onSubmit: (values) => { - }, - }); + }; useEffect(() => { + fetchRetrievers(); + }, [selectedRetrievalParadigm]); - const retrieverSchemaProperties = currentSelectedRetrieverOption?.schema?.properties; - - if (retrieverSchemaProperties) { - const processedProps = preprocessSchema(retrieverSchemaProperties); - setValidationSchema(buildYupSchema(processedProps)); - - const initialFormValues = Object.keys(processedProps).reduce( - (acc, key) => { - acc[key] = retrieverModel?.parameters?.[key] !== undefined - ? retrieverModel.parameters[key] - : (processedProps[key].placeholder !== undefined - ? processedProps[key].placeholder - : ""); - return acc; - }, - {}, - ); - formik.setValues(initialFormValues); - } else { - setValidationSchema(null); - formik.setValues({}); - } - }, [currentSelectedRetrieverOption, retrieverModel?.parameters]); - - useEffect(() => { - const isValid = !!currentSelectedRetrieverOption && formik.isValid; - setNextEnabled(isValid); - }, [currentSelectedRetrieverOption, formik.isValid, setNextEnabled]); + const handleRetrievalParadigmChange = (event, newValue) => { + setSelectedRetrievalParadigm(newValue); + setSelectedRetriever(null); + }; const handleRetrieverSelectionChange = (event, newValue) => { - setCurrentSelectedRetrieverOption(newValue); - - if (newValue) { - const initialParameters = getInitialParamsFromSchema(newValue.schema?.properties); - setRetrieverModel({ - name: newValue.name, - parameters: initialParameters, - }); - } else { - setRetrieverModel({ name: "", parameters: {} }); - } + setSelectedRetriever(newValue); + setRetrieverInitialParameters(useSchema({ modelName: newValue?.name })); }; - const handleParametersChange = (updatedValues) => { - formik.setValues((prevValues) => ({ - ...prevValues, - ...updatedValues, + const handleRetrieverParametersChange = (newParams) => { + setSelectedRetriever((prev) => ({ + ...prev, + parameters: newParams, })); - - setRetrieverModel({ - name: currentSelectedRetrieverOption.name, - parameters: { - ...formik.values, - ...updatedValues, - }, - }); - }; - - const processedProperties = currentSelectedRetrieverOption?.schema?.properties - ? preprocessSchema(currentSelectedRetrieverOption.schema.properties) - : {}; + console.log("Updated retriever model parameters:", newParams); + } return ( - - Configure Retriever Model + + Select retrieval paradigm option.name} - value={currentSelectedRetrieverOption} - onChange={handleRetrieverSelectionChange} + options={retrievalParadigms} + getOptionLabel={(option) => option.name} + value={selectedRetrievalParadigm} + onChange={handleRetrievalParadigmChange} isOptionEqualToValue={(option, value) => option.name === value?.name} - renderInput={(params) => } + renderInput={(params) => } sx={{ mb: 3 }} /> - {currentSelectedRetrieverOption && currentSelectedRetrieverOption.schema && ( -
- - - Parameters - - console.error("FormSchemaRenderFields Error:", error)} - errorsMessage={formik.errors} - /> - -
+ {selectedRetriever && ( + + + Configure retriever model + + [ + + ], + }]} + hideFooter + disableColumnMenu + disableColumnSelector + disableSelectionOnClick + /> + + )} + + {selectedRetriever && selectedRetriever.schema && !selectedRetriever.schema.properties && ( + + No parameters available for this retriever. + )}
); -} +} \ No newline at end of file diff --git a/RAG/embeddings/9864fa188a542eee3117fb4e3ed614fecb32905086735433d372c53e4d4b8f5a/feature_names.pkl b/RAG/embeddings/9864fa188a542eee3117fb4e3ed614fecb32905086735433d372c53e4d4b8f5a/feature_names.pkl new file mode 100644 index 0000000000000000000000000000000000000000..6084a4eeed682fd27c5b9d61666ad158cf246f46 GIT binary patch literal 1577 zcmZ8hJ&)Ts5Y1Y){Jq&la_wQtR9jzn#dTR=4@e&bluWM~%cPEycHcafq zl!;3am+pRJ_w95$S(bPK}S2nbBWvTz2D7y*mB_!oLCi4ZL^~Ks*3_X*A;lbJV3}q|7;@%F^-l4IT=~Mm?E~ zRXA^IhudUL!7*Y%2uuMUby0xS zTc`eO+%{exGVSj} zdo^IHy-@|{o4euCZRsqV2oDP#F@}{gobgm3R|FsyUvis53YBrGN`sDMMIEj6Z}qs9z|3jA8M8v&Z5( M0_rwtJkB>i0S-fQ-T(jq literal 0 HcmV?d00001 diff --git a/RAG/embeddings/9864fa188a542eee3117fb4e3ed614fecb32905086735433d372c53e4d4b8f5a/term_matrix.pkl b/RAG/embeddings/9864fa188a542eee3117fb4e3ed614fecb32905086735433d372c53e4d4b8f5a/term_matrix.pkl new file mode 100644 index 0000000000000000000000000000000000000000..aa935f934ddd778124e73352f523b9c548cd8276 GIT binary patch literal 2244 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, 'configurable_object': False, 'schema': None, 'metadata': {'inputs_types': ['ClassLabel', 'Value'], 'outputs_types': ['ClassLabel'], 'inputs_cardinality': 'n', 'outputs_cardinality': 1}, 'description': '\n Tabular classification in machine learning involves predicting categorical\n labels for structured data organized in tabular form (rows and columns).\n Models are trained to learn patterns and relationships in the data, enabling\n accurate classification of new instances.', 'display_name': None}, 'TextClassificationTask': {'name': 'TextClassificationTask', 'type': 'Task', 'class': , 'configurable_object': False, 'schema': None, 'metadata': {'inputs_types': ['Value'], 'outputs_types': ['ClassLabel'], 'inputs_cardinality': 1, 'outputs_cardinality': 1}, 'description': '\n Text classification is an essential Natural Language Processing (NLP) task that\n involves automatically assigning pre-defined categories or labels to text documents\n based on their content. It serves as the foundation for applications like sentiment\n analysis, spam filtering, topic classification, and document categorization.\n ', 'display_name': None}, 'TranslationTask': {'name': 'TranslationTask', 'type': 'Task', 'class': , 'configurable_object': False, 'schema': None, 'metadata': {'inputs_types': ['Value', 'Sequence'], 'outputs_types': ['Value', 'Sequence'], 'inputs_cardinality': 1, 'outputs_cardinality': 1}, 'description': '\n The translation task is natural language processing (NLP) task that involves\n converting text or speech from one language into another language while\n preserving the meaning and context.\n ', 'display_name': None}, 'ImageClassificationTask': {'name': 'ImageClassificationTask', 'type': 'Task', 'class': , 'configurable_object': False, 'schema': None, 'metadata': {'inputs_types': ['Image'], 'outputs_types': ['ClassLabel'], 'inputs_cardinality': 1, 'outputs_cardinality': 1}, 'description': None, 'display_name': None}, 'RegressionTask': {'name': 'RegressionTask', 'type': 'Task', 'class': , 'configurable_object': False, 'schema': None, 'metadata': {'inputs_types': ['Value'], 'outputs_types': ['Value'], 'inputs_cardinality': 'n', 'outputs_cardinality': 1}, 'description': '\n Regression in machine learning involves predicting continuous values for\n structured data organized in tabular form (rows and columns).\n Models are trained to learn patterns and relationships in the data,\n enabling accurate prediction of new instances.', 'display_name': None}}, 'GenerativeTask': {'TextToImageGenerationTask': {'name': 'TextToImageGenerationTask', 'type': 'GenerativeTask', 'class': , 'configurable_object': False, 'schema': None, 'metadata': {'inputs_types': ['str'], 'outputs_types': ['Image'], 'inputs_cardinality': 1, 'outputs_cardinality': 'n'}, 'description': 'This task generates images based on the provided input text.', 'display_name': 'Text to Image Generation'}, 'TextToTextGenerationTask': {'name': 'TextToTextGenerationTask', 'type': 'GenerativeTask', 'class': , 'configurable_object': False, 'schema': None, 'metadata': {'inputs_types': ['str'], 'outputs_types': ['str'], 'inputs_cardinality': 1, 'outputs_cardinality': 1}, 'description': 'This task uses a large language model (LLM) to generate text from a given prompt.', 'display_name': 'Text to Text Generation'}, 'ControlNetTask': {'name': 'ControlNetTask', 'type': 'GenerativeTask', 'class': , 'configurable_object': False, 'schema': None, 'metadata': {'inputs_types': ['Image', 'str'], 'outputs_types': ['Image'], 'inputs_cardinality': 2, 'outputs_cardinality': 'n'}, 'description': 'This task generates images based on the provided input text and image.', 'display_name': 'ControlNet'}, 'RAGTask': {'name': 'RAGTask', 'type': 'GenerativeTask', 'class': , 'configurable_object': False, 'schema': None, 'metadata': {'inputs_types': ['str'], 'outputs_types': ['str'], 'inputs_cardinality': 1, 'outputs_cardinality': 1}, 'description': 'This task generates a text response based on documents provided and chat.', 'display_name': 'Retreival-Augmented Generation (RAG) Task'}}, 'Model': {'SVC': {'name': 'SVC', 'type': 'Model', 'class': , 'configurable_object': True, 'schema': {'description': 'Support Vector Machine (SVM) is a machine learning algorithm that separates data\ninto different classes by finding the optimal hyperplane', 'properties': {'C': {'description': "The parameter 'C' is a regularization parameter. It must be of type positive number.", 'placeholder': {'fixed_value': 1.0, 'lower_bound': 1.0, 'optimize': False, 'upper_bound': 10.0}, 'title': 'C', 'type': 'object'}, 'coef0': {'description': "The 'coef0' parameter is a kernel independent value. It is only significant for kernel poly and sigmoid. It must be of type number.", 'placeholder': {'fixed_value': 1.0, 'lower_bound': 1.0, 'optimize': False, 'upper_bound': 10.0}, 'title': 'Coef0', 'type': 'object'}, 'degree': {'description': "The parameter 'degree' is the degree of the polynomial for the kernel = 'poly'. It must be of type number.", 'placeholder': {'fixed_value': 1.0, 'lower_bound': 1.0, 'optimize': False, 'upper_bound': 10.0}, 'title': 'Degree', 'type': 'object'}, 'gamma': {'description': "Coefficient for 'rbf', 'poly' and 'sigmoid' kernels. Must be in string format and can be 'scale' or 'auto'.", 'enum': ['scale', 'auto'], 'placeholder': 'scale', 'title': 'Gamma', 'type': 'string'}, 'kernel': {'description': "The 'kernel' parameter is the kernel used in the model. It must be a string equal to 'linear', 'poly', 'rbf' or 'sigmoid'.", 'enum': ['linear', 'poly', 'rbf', 'sigmoid'], 'placeholder': 'rbf', 'title': 'Kernel', 'type': 'string'}, 'max_iter': {'description': "The 'max_iter' parameter determines the iteration limit for the solver. It must be of type positive integer or -1 to indicate no limit.", 'placeholder': {'fixed_value': -1, 'lower_bound': 1, 'optimize': False, 'upper_bound': 10}, 'title': 'Max Iter', 'type': 'object'}, 'probability': {'description': "The parameter 'probability' indicates whether or not to predict with probabilities. It must be of type boolean.", 'placeholder': True, 'title': 'Probability', 'type': 'boolean'}, 'shrinking': {'description': "The 'shrinking' parameter determines whether a shrinking heristic is used. It must be of type boolean.", 'placeholder': True, 'title': 'Shrinking', 'type': 'boolean'}, 'tol': {'description': "The parameter 'tol' determines the tolerance for the stop criterion. It must be of type positive number.", 'placeholder': {'fixed_value': 1.0, 'lower_bound': 1.0, 'optimize': False, 'upper_bound': 10.0}, 'title': 'Tol', 'type': 'object'}, 'verbose': {'description': "The 'verbose' parameter allows to have a verbose output.It must be of type boolean.", 'placeholder': False, 'title': 'Verbose', 'type': 'boolean'}}, 'required': ['C', 'coef0', 'degree', 'gamma', 'kernel', 'max_iter', 'probability', 'shrinking', 'tol', 'verbose'], 'title': 'SVCSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'DecisionTreeClassifier': {'name': 'DecisionTreeClassifier', 'type': 'Model', 'class': , 'configurable_object': True, 'schema': {'description': 'Decision Trees are a set of are a non-parametric supervised learning method that\nlearns simple decision rules (structured as a tree) inferred from the data features.', 'properties': {'criterion': {'description': 'The function to measure the quality of a split. Supported criteria are gini for the Gini impurity and log_loss and entropy both for the Shannon information gain.', 'enum': ['entropy', 'gini', 'log_loss'], 'placeholder': 'entropy', 'title': 'Criterion', 'type': 'string'}, 'max_depth': {'description': 'The maximum depth of the tree. If None, then nodes are expanded until all leaves are pure or until all leaves contain less than min_samples_split samples.', 'placeholder': {'fixed_value': 1, 'lower_bound': 1, 'optimize': False, 'upper_bound': 10}, 'title': 'Max Depth', 'type': 'object'}, 'min_samples_split': {'description': 'The minimum number of samples required to split an internal node.', 'placeholder': {'fixed_value': 1, 'lower_bound': 1, 'optimize': False, 'upper_bound': 5}, 'title': 'Min Samples Split', 'type': 'object'}, 'min_samples_leaf': {'description': 'The minimum number of samples required to be at a leaf node.', 'placeholder': {'fixed_value': 1, 'lower_bound': 1, 'optimize': False, 'upper_bound': 5}, 'title': 'Min Samples Leaf', 'type': 'object'}, 'max_features': {'description': 'The number of features to consider when looking for the best split.', 'enum': ['auto', 'sqrt', 'log2'], 'placeholder': None, 'title': 'Max Features', 'type': 'string'}}, 'required': ['criterion', 'max_depth', 'min_samples_split', 'min_samples_leaf', 'max_features'], 'title': 'DecisionTreeClassifierSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'DummyClassifier': {'name': 'DummyClassifier', 'type': 'Model', 'class': , 'configurable_object': True, 'schema': {'description': 'DummyClassifier makes predictions that ignore the input features.', 'properties': {'strategy': {'description': 'Strategy to use to generate predictions.', 'enum': ['most_frequent', 'prior', 'stratified', 'uniform'], 'placeholder': 'prior', 'title': 'Strategy', 'type': 'string'}}, 'required': ['strategy'], 'title': 'DummyClassifierSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'GradientBoostingR': {'name': 'GradientBoostingR', 'type': 'Model', 'class': , 'configurable_object': True, 'schema': {'description': 'Gradient Boosting for regression.', 'properties': {'loss': {'description': 'Loss function to be optimized.', 'enum': ['squared_error', 'absolute_error', 'huber', 'quantile'], 'placeholder': 'squared_error', 'title': 'Loss', 'type': 'string'}, 'learning_rate': {'description': 'Learning rate shrinks the contribution of each tree.', 'placeholder': {'fixed_value': 0.1, 'lower_bound': 0.01, 'optimize': False, 'upper_bound': 1.0}, 'title': 'Learning Rate', 'type': 'object'}, 'n_estimators': {'description': 'The number of boosting stages to be run.', 'placeholder': {'fixed_value': 100, 'lower_bound': 10, 'optimize': False, 'upper_bound': 1000}, 'title': 'N Estimators', 'type': 'object'}, 'subsample': {'description': 'The fraction of samples to be used for fitting the individual base learners.', 'placeholder': {'fixed_value': 1.0, 'lower_bound': 0.1, 'optimize': False, 'upper_bound': 1.0}, 'title': 'Subsample', 'type': 'object'}, 'criterion': {'description': 'The function to measure the quality of a split.', 'enum': ['friedman_mse', 'mse', 'mae'], 'placeholder': 'friedman_mse', 'title': 'Criterion', 'type': 'string'}, 'min_samples_split': {'description': 'The minimum number of samples required to split an internal node.', 'placeholder': {'fixed_value': 2, 'lower_bound': 2, 'optimize': False, 'upper_bound': 20}, 'title': 'Min Samples Split', 'type': 'object'}, 'min_samples_leaf': {'description': 'The minimum number of samples required to be at a leaf node.', 'placeholder': {'fixed_value': 1, 'lower_bound': 1, 'optimize': False, 'upper_bound': 20}, 'title': 'Min Samples Leaf', 'type': 'object'}, 'min_weight_fraction_leaf': {'description': 'The minimum weighted fraction of the sum total of weights (of all the input samples) required to be at a leaf node.', 'placeholder': {'fixed_value': 0.0, 'lower_bound': 0.0, 'optimize': False, 'upper_bound': 0.5}, 'title': 'Min Weight Fraction Leaf', 'type': 'object'}, 'max_depth': {'anyOf': [{'type': 'object'}, {'type': 'integer'}, {'type': 'null'}], 'description': 'The maximum depth of the individual regression estimators.', 'placeholder': 3, 'title': 'Max Depth'}, 'min_impurity_decrease': {'description': 'A node will be split if this split induces a decrease of the impurity greater than or equal to this value.', 'placeholder': {'fixed_value': 0.0, 'lower_bound': 0.0, 'optimize': False, 'upper_bound': 0.5}, 'title': 'Min Impurity Decrease', 'type': 'object'}, 'random_state': {'anyOf': [{'type': 'object'}, {'type': 'integer'}, {'type': 'null'}], 'description': 'The seed of the pseudo-random number generator to use when shuffling the data.', 'placeholder': None, 'title': 'Random State'}, 'max_features': {'anyOf': [{'type': 'object'}, {'enum': ['sqrt', 'log2', None], 'type': 'string'}], 'description': 'The number of features to consider when looking for the best split.', 'placeholder': None, 'title': 'Max Features'}, 'alpha': {'description': 'The alpha-quantile of the Huber loss function and the quantile loss function.', 'placeholder': {'fixed_value': 0.9, 'lower_bound': 0.1, 'optimize': False, 'upper_bound': 1.0}, 'title': 'Alpha', 'type': 'object'}, 'verbose': {'description': 'Enable verbose output.', 'placeholder': {'fixed_value': 0, 'lower_bound': 0, 'optimize': False, 'upper_bound': 100}, 'title': 'Verbose', 'type': 'object'}, 'max_leaf_nodes': {'anyOf': [{'type': 'object'}, {'type': 'integer'}, {'type': 'null'}], 'description': 'Grow trees with max_leaf_nodes in best-first fashion.', 'placeholder': None, 'title': 'Max Leaf Nodes'}, 'warm_start': {'description': 'When set to True, reuse the solution of the previous callto fit and add more estimators to the ensemble.', 'placeholder': False, 'title': 'Warm Start', 'type': 'boolean'}, 'validation_fraction': {'description': 'The proportion of training data to set aside as validation set for early stopping.', 'placeholder': {'fixed_value': 0.1, 'lower_bound': 0.1, 'optimize': False, 'upper_bound': 0.5}, 'title': 'Validation Fraction', 'type': 'object'}, 'n_iter_no_change': {'anyOf': [{'type': 'object'}, {'type': 'integer'}, {'type': 'null'}], 'description': 'The number of iterations with no improvement to wait before stopping the training.', 'placeholder': None, 'title': 'N Iter No Change'}, 'tol': {'description': 'Tolerance for the early stopping.', 'placeholder': {'fixed_value': 0.0001, 'lower_bound': 1e-05, 'optimize': False, 'upper_bound': 0.1}, 'title': 'Tol', 'type': 'object'}, 'ccp_alpha': {'description': 'Complexity parameter used for Minimal Cost-Complexity Pruning.', 'placeholder': {'fixed_value': 0.0, 'lower_bound': 0.0, 'optimize': False, 'upper_bound': 1.0}, 'title': 'Ccp Alpha', 'type': 'object'}}, 'required': ['loss', 'learning_rate', 'n_estimators', 'subsample', 'criterion', 'min_samples_split', 'min_samples_leaf', 'min_weight_fraction_leaf', 'max_depth', 'min_impurity_decrease', 'random_state', 'max_features', 'alpha', 'verbose', 'max_leaf_nodes', 'warm_start', 'validation_fraction', 'n_iter_no_change', 'tol', 'ccp_alpha'], 'title': 'GradientBoostingRSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'HistGradientBoostingClassifier': {'name': 'HistGradientBoostingClassifier', 'type': 'Model', 'class': , 'configurable_object': True, 'schema': {'description': 'A gradient boosting classifier is a machine learning algorithm that combines\nmultiple weak prediction models (typically decision trees) to create a strong\npredictive model by training the models sequentially, in which each new model is\nfocused on correcting the errors made by the previous ones.', 'properties': {'learning_rate': {'description': 'The learning rate, also known as shrinkage. This is used as a multiplicative factor for the leaves values. Use 1 for no shrinkage.', 'placeholder': {'fixed_value': 0.1, 'lower_bound': 0.1, 'optimize': False, 'upper_bound': 1}, 'title': 'Learning Rate', 'type': 'object'}, 'max_iter': {'description': 'The maximum number of iterations of the boosting process, i.e. the maximum number of trees for binary classification.', 'placeholder': {'fixed_value': 100, 'lower_bound': 100, 'optimize': False, 'upper_bound': 250}, 'title': 'Max Iter', 'type': 'object'}, 'max_depth': {'description': 'The maximum depth of each tree. The depth of a tree is the number of edges to go from the root to the deepest leaf. Depth isnt constrained by default.', 'placeholder': {'fixed_value': 1, 'lower_bound': 1, 'optimize': False, 'upper_bound': 10}, 'title': 'Max Depth', 'type': 'object'}, 'max_leaf_nodes': {'description': 'The maximum number of leaves for each tree. Must be strictly greater than 1. If None, there is no maximum limit.', 'placeholder': {'fixed_value': 31, 'lower_bound': 10, 'optimize': False, 'upper_bound': 40}, 'title': 'Max Leaf Nodes', 'type': 'object'}, 'min_samples_leaf': {'description': 'The minimum number of samples required to be at a leaf node.', 'placeholder': {'fixed_value': 20, 'lower_bound': 2, 'optimize': False, 'upper_bound': 25}, 'title': 'Min Samples Leaf', 'type': 'object'}, 'l2_regularization': {'description': 'The L2 regularization parameter. Use 0 for no regularization.', 'placeholder': {'fixed_value': 0.0, 'lower_bound': 0.0, 'optimize': False, 'upper_bound': 1.0}, 'title': 'L2 Regularization', 'type': 'object'}}, 'required': ['learning_rate', 'max_iter', 'max_depth', 'max_leaf_nodes', 'min_samples_leaf', 'l2_regularization'], 'title': 'HistGradientBoostingClassifierSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'KNeighborsClassifier': {'name': 'KNeighborsClassifier', 'type': 'Model', 'class': , 'configurable_object': True, 'schema': {'description': 'KNN is a supervised classification method that determines the probability of\nan element belonging to a certain class by considering its k closest neighbors.', 'properties': {'n_neighbors': {'description': "The 'n_neighbors' parameter is the number of neighbors to consider in each input for classification. It must be an integer greater than or equal to 1.", 'placeholder': {'fixed_value': 5, 'lower_bound': 5, 'optimize': False, 'upper_bound': 10}, 'title': 'N Neighbors', 'type': 'object'}, 'weights': {'description': "The 'weights' parameter must be 'uniform' or 'distance'.", 'enum': ['uniform', 'distance'], 'placeholder': 'uniform', 'title': 'Weights', 'type': 'string'}, 'algorithm': {'description': "The 'algorithm' parameter must be 'auto', 'ball_tree', 'kd_tree', or 'brute'.", 'enum': ['auto', 'ball_tree', 'kd_tree', 'brute'], 'placeholder': 'auto', 'title': 'Algorithm', 'type': 'string'}}, 'required': ['n_neighbors', 'weights', 'algorithm'], 'title': 'KNeighborsClassifierSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'LogisticRegression': {'name': 'LogisticRegression', 'type': 'Model', 'class': , 'configurable_object': True, 'schema': {'description': 'Logistic Regression is a supervised classification method that uses a linear\nmodel plus a a logistic funcion to predict binary outcomes (it can be configured\nas multiclass via the one-vs-rest strategy).', 'properties': {'penalty': {'description': 'Specify the norm of the penalty', 'enum': ['l2', 'l1', 'elasticnet'], 'placeholder': 'l2', 'title': 'Penalty', 'type': 'string'}, 'tol': {'description': 'Tolerance for stopping criteria.', 'placeholder': {'fixed_value': 0.001, 'lower_bound': 0.001, 'optimize': False, 'upper_bound': 5}, 'title': 'Tol', 'type': 'object'}, 'C': {'description': 'Inverse of regularization strength, smaller values specify stronger regularization. Must be a positive number.', 'placeholder': {'fixed_value': 1.0, 'lower_bound': 1.0, 'optimize': False, 'upper_bound': 7.0}, 'title': 'C', 'type': 'object'}, 'max_iter': {'description': 'Maximum number of iterations taken for the solvers to converge.', 'placeholder': {'fixed_value': 100, 'lower_bound': 50, 'optimize': False, 'upper_bound': 250}, 'title': 'Max Iter', 'type': 'object'}}, 'required': ['penalty', 'tol', 'C', 'max_iter'], 'title': 'LogisticRegressionSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'MLPRegression': {'name': 'MLPRegression', 'type': 'Model', 'class': , 'configurable_object': True, 'schema': {'description': 'MLP Regressor for DashAI.', 'properties': {'activation': {'description': 'Activation function for the hidden layer.', 'enum': ['identity', 'logistic', 'tanh', 'relu'], 'placeholder': 'relu', 'title': 'Activation', 'type': 'string'}, 'solver': {'description': 'The solver for weight optimization.', 'enum': ['lbfgs', 'sgd', 'adam'], 'placeholder': 'adam', 'title': 'Solver', 'type': 'string'}, 'alpha': {'description': 'L2 penalty (regularization term) parameter.', 'placeholder': {'fixed_value': 0.0001, 'lower_bound': 1e-06, 'optimize': False, 'upper_bound': 0.1}, 'title': 'Alpha', 'type': 'object'}, 'batch_size': {'anyOf': [{'type': 'object'}, {'enum': ['auto'], 'type': 'string'}], 'description': 'Size of minibatches for stochastic optimizers.', 'placeholder': 'auto', 'title': 'Batch Size'}, 'learning_rate': {'description': 'Learning rate schedule for weight updates.', 'enum': ['constant', 'invscaling', 'adaptive'], 'placeholder': 'constant', 'title': 'Learning Rate', 'type': 'string'}, 'learning_rate_init': {'description': 'The initial learning rate used.', 'placeholder': {'fixed_value': 0.001, 'lower_bound': 1e-05, 'optimize': False, 'upper_bound': 0.1}, 'title': 'Learning Rate Init', 'type': 'object'}, 'power_t': {'description': 'The exponent for inverse scaling learning rate.', 'placeholder': {'fixed_value': 0.5, 'lower_bound': 0.1, 'optimize': False, 'upper_bound': 0.9}, 'title': 'Power T', 'type': 'object'}, 'max_iter': {'description': 'Maximum number of iterations.', 'placeholder': {'fixed_value': 200, 'lower_bound': 50, 'optimize': False, 'upper_bound': 1000}, 'title': 'Max Iter', 'type': 'object'}, 'shuffle': {'description': 'Whether to shuffle samples in each iteration.', 'placeholder': True, 'title': 'Shuffle', 'type': 'boolean'}, 'random_state': {'anyOf': [{'type': 'object'}, {'type': 'integer'}, {'type': 'null'}], 'description': 'The seed of the pseudo-random number generator to use when shuffling the data.', 'placeholder': None, 'title': 'Random State'}, 'tol': {'description': 'Tolerance for the optimization.', 'placeholder': {'fixed_value': 0.0001, 'lower_bound': 1e-06, 'optimize': False, 'upper_bound': 0.01}, 'title': 'Tol', 'type': 'object'}, 'verbose': {'description': 'Whether to print progress messages to stdout.', 'placeholder': False, 'title': 'Verbose', 'type': 'boolean'}, 'warm_start': {'description': 'When set to True, reuse the solution of the previous call to fit as initialization.', 'placeholder': False, 'title': 'Warm Start', 'type': 'boolean'}, 'momentum': {'description': 'Momentum for gradient descent update.', 'placeholder': {'fixed_value': 0.9, 'lower_bound': 0.0, 'optimize': False, 'upper_bound': 1.0}, 'title': 'Momentum', 'type': 'object'}, 'nesterovs_momentum': {'description': 'Whether to use Nesterovs momentum.', 'placeholder': True, 'title': 'Nesterovs Momentum', 'type': 'boolean'}, 'early_stopping': {'description': 'Whether to use early stopping to terminate training when validation score is not improving.', 'placeholder': False, 'title': 'Early Stopping', 'type': 'boolean'}, 'validation_fraction': {'description': 'The proportion of training data to set aside as validation set for early stopping.', 'placeholder': {'fixed_value': 0.1, 'lower_bound': 0.1, 'optimize': False, 'upper_bound': 0.5}, 'title': 'Validation Fraction', 'type': 'object'}, 'beta_1': {'description': 'Exponential decay rate for estimates of first moment vector in Adam optimizer.', 'placeholder': {'fixed_value': 0.9, 'lower_bound': 0.1, 'optimize': False, 'upper_bound': 0.999}, 'title': 'Beta 1', 'type': 'object'}, 'beta_2': {'description': 'Exponential decay rate for estimates of second moment vector in Adam optimizer.', 'placeholder': {'fixed_value': 0.999, 'lower_bound': 0.1, 'optimize': False, 'upper_bound': 0.999}, 'title': 'Beta 2', 'type': 'object'}, 'epsilon': {'description': 'Value for numerical stability in Adam optimizer.', 'placeholder': {'fixed_value': 1e-08, 'lower_bound': 1e-10, 'optimize': False, 'upper_bound': 1e-06}, 'title': 'Epsilon', 'type': 'object'}, 'n_iter_no_change': {'description': 'Maximum number of epochs to not meet tol improvement.', 'placeholder': {'fixed_value': 10, 'lower_bound': 1, 'optimize': False, 'upper_bound': 50}, 'title': 'N Iter No Change', 'type': 'object'}, 'max_fun': {'description': "Maximum number of loss function calls. Only used if solver='lbfgs'.", 'placeholder': {'fixed_value': 15000, 'lower_bound': 1000, 'optimize': False, 'upper_bound': 20000}, 'title': 'Max Fun', 'type': 'object'}}, 'required': ['activation', 'solver', 'alpha', 'batch_size', 'learning_rate', 'learning_rate_init', 'power_t', 'max_iter', 'shuffle', 'random_state', 'tol', 'verbose', 'warm_start', 'momentum', 'nesterovs_momentum', 'early_stopping', 'validation_fraction', 'beta_1', 'beta_2', 'epsilon', 'n_iter_no_change', 'max_fun'], 'title': 'MLPRegressorSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'RandomForestClassifier': {'name': 'RandomForestClassifier', 'type': 'Model', 'class': , 'configurable_object': True, 'schema': {'description': 'Random Forest (RF) is an ensemble machine learning algorithm that achieves\nenhanced performance by combining multiple decision trees and aggregating their\noutputs.', 'properties': {'n_estimators': {'description': "The 'n_estimators' parameter corresponds to the number of decision trees. It must be an integer greater than or equal to 1.", 'placeholder': {'fixed_value': 100, 'lower_bound': 50, 'optimize': False, 'upper_bound': 200}, 'title': 'N Estimators', 'type': 'object'}, 'max_depth': {'description': "The 'max_depth' parameter corresponds to the maximum depth of the tree. It must be an integer greater than or equal to 1.", 'placeholder': {'fixed_value': 2, 'lower_bound': 2, 'optimize': False, 'upper_bound': 10}, 'title': 'Max Depth', 'type': 'object'}, 'min_samples_split': {'description': "The 'min_samples_split' parameter is the minimum number of samples required to split an internal node. It must be a number greater than or equal to 2.", 'placeholder': {'fixed_value': 2, 'lower_bound': 2, 'optimize': False, 'upper_bound': 10}, 'title': 'Min Samples Split', 'type': 'object'}, 'min_samples_leaf': {'description': "The 'min_samples_leaf' parameter is the minimum number of samples required to be at a leaf node. It must be a number greater than or equal to 1.", 'placeholder': {'fixed_value': 1, 'lower_bound': 1, 'optimize': False, 'upper_bound': 10}, 'title': 'Min Samples Leaf', 'type': 'object'}, 'max_leaf_nodes': {'description': "The 'max_leaf_nodes' parameter must be an integer greater than or equal to 2.", 'placeholder': {'fixed_value': 2, 'lower_bound': 2, 'optimize': False, 'upper_bound': 10}, 'title': 'Max Leaf Nodes', 'type': 'object'}, 'random_state': {'description': "The 'random_state' parameter must be an integer greater than or equal to 0.", 'placeholder': {'fixed_value': 0, 'lower_bound': 0, 'optimize': False, 'upper_bound': 10}, 'title': 'Random State', 'type': 'object'}}, 'required': ['n_estimators', 'max_depth', 'min_samples_split', 'min_samples_leaf', 'max_leaf_nodes', 'random_state'], 'title': 'RandomForestClassifierSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'RandomForestRegression': {'name': 'RandomForestRegression', 'type': 'Model', 'class': , 'configurable_object': True, 'schema': {'description': 'Random Forest Regressor for DashAI.', 'properties': {'n_estimators': {'description': 'The number of trees in the forest.', 'placeholder': {'fixed_value': 100, 'lower_bound': 10, 'optimize': False, 'upper_bound': 1000}, 'title': 'N Estimators', 'type': 'object'}, 'criterion': {'description': 'The function to measure the quality of a split.', 'enum': ['squared_error', 'absolute_error', 'poisson'], 'placeholder': 'squared_error', 'title': 'Criterion', 'type': 'string'}, 'max_depth': {'anyOf': [{'type': 'object'}, {'type': 'integer'}, {'type': 'null'}], 'description': 'The maximum depth of the tree.', 'placeholder': None, 'title': 'Max Depth'}, 'min_samples_split': {'description': 'The minimum number of samples required to split an internal node.', 'placeholder': {'fixed_value': 2, 'lower_bound': 2, 'optimize': False, 'upper_bound': 20}, 'title': 'Min Samples Split', 'type': 'object'}, 'min_samples_leaf': {'description': 'The minimum number of samples required to be at a leaf node.', 'placeholder': {'fixed_value': 1, 'lower_bound': 1, 'optimize': False, 'upper_bound': 20}, 'title': 'Min Samples Leaf', 'type': 'object'}, 'min_weight_fraction_leaf': {'description': 'The minimum weighted fraction of the sum total of weights required to be at a leaf node.', 'placeholder': {'fixed_value': 0.0, 'lower_bound': 0.0, 'optimize': False, 'upper_bound': 0.5}, 'title': 'Min Weight Fraction Leaf', 'type': 'object'}, 'max_features': {'anyOf': [{'type': 'object'}, {'enum': ['auto', 'sqrt', 'log2', None], 'type': 'string'}], 'description': 'The number of features to consider when looking for the best split.', 'placeholder': 'sqrt', 'title': 'Max Features'}, 'max_leaf_nodes': {'anyOf': [{'type': 'object'}, {'type': 'integer'}, {'type': 'null'}], 'description': 'Grow trees with max_leaf_nodes in best-first fashion.', 'placeholder': None, 'title': 'Max Leaf Nodes'}, 'min_impurity_decrease': {'description': 'A node will be split if this split induces a decrease of the impurity greater than or equal to this value.', 'placeholder': {'fixed_value': 0.0, 'lower_bound': 0.0, 'optimize': False, 'upper_bound': 0.5}, 'title': 'Min Impurity Decrease', 'type': 'object'}, 'bootstrap': {'description': 'Whether bootstrap samples are used when building trees.', 'placeholder': True, 'title': 'Bootstrap', 'type': 'boolean'}, 'oob_score': {'description': 'Whether to use out-of-bag samples to estimate the generalization score.', 'placeholder': False, 'title': 'Oob Score', 'type': 'boolean'}, 'n_jobs': {'anyOf': [{'type': 'object'}, {'type': 'integer'}, {'type': 'null'}], 'description': 'The number of jobs to run in parallel for both fit and predict.', 'placeholder': None, 'title': 'N Jobs'}, 'random_state': {'anyOf': [{'type': 'object'}, {'type': 'integer'}, {'type': 'null'}], 'description': 'The seed of the pseudo-random number generator to use when shuffling the data.', 'placeholder': None, 'title': 'Random State'}, 'verbose': {'description': 'Controls the verbosity when fitting and predicting.', 'placeholder': {'fixed_value': 0, 'lower_bound': 0, 'optimize': False, 'upper_bound': 100}, 'title': 'Verbose', 'type': 'object'}, 'warm_start': {'description': 'When set to True, reuse the solution of the previous call to fit and add more estimators to the ensemble.', 'placeholder': False, 'title': 'Warm Start', 'type': 'boolean'}, 'ccp_alpha': {'description': 'Complexity parameter used for Minimal Cost-Complexity Pruning.', 'placeholder': {'fixed_value': 0.0, 'lower_bound': 0.0, 'optimize': False, 'upper_bound': 1.0}, 'title': 'Ccp Alpha', 'type': 'object'}, 'max_samples': {'anyOf': [{'type': 'object'}, {'type': 'number'}, {'type': 'null'}], 'description': 'If bootstrap is True, the number of samples to draw from X to train each base estimator.', 'placeholder': None, 'title': 'Max Samples'}}, 'required': ['n_estimators', 'criterion', 'max_depth', 'min_samples_split', 'min_samples_leaf', 'min_weight_fraction_leaf', 'max_features', 'max_leaf_nodes', 'min_impurity_decrease', 'bootstrap', 'oob_score', 'n_jobs', 'random_state', 'verbose', 'warm_start', 'ccp_alpha', 'max_samples'], 'title': 'RandomForestRegressionSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'DistilBertTransformer': {'name': 'DistilBertTransformer', 'type': 'Model', 'class': , 'configurable_object': True, 'schema': {'description': 'Distilbert is a transformer that allows you to classify text in English.\nThe implementation is based on huggingface distilbert-base in the case of\nthe uncased model, i.e. distilbert-base-uncased.', 'properties': {'num_train_epochs': {'description': 'Total number of training epochs to perform.', 'minimum': 1, 'placeholder': 1, 'title': 'Num Train Epochs', 'type': 'integer'}, 'batch_size': {'description': 'The batch size per GPU/TPU core/CPU for training', 'minimum': 1, 'placeholder': 16, 'title': 'Batch Size', 'type': 'integer'}, 'learning_rate': {'description': 'The initial learning rate for AdamW optimizer', 'minimum': 0.0, 'placeholder': 3e-05, 'title': 'Learning Rate', 'type': 'number'}, 'device': {'description': 'Hardware on which the training is run. If available, GPU is recommended for efficiency reasons. Otherwise, use CPU.', 'enum': ['gpu', 'cpu'], 'placeholder': 'gpu', 'title': 'Device', 'type': 'string'}, 'weight_decay': {'description': "Weight decay is a regularization technique used in training neural networks to prevent overfitting. In the context of the AdamW optimizer, the 'weight_decay' parameter is the rate at which the weights of all layers are reduced during training, provided that this rate is not zero.", 'minimum': 0.0, 'placeholder': 0.01, 'title': 'Weight Decay', 'type': 'number'}}, 'required': ['num_train_epochs', 'batch_size', 'learning_rate', 'device', 'weight_decay'], 'title': 'DistilBertTransformerSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'OpusMtEnESTransformer': {'name': 'OpusMtEnESTransformer', 'type': 'Model', 'class': , 'configurable_object': True, 'schema': {'description': 'opus-mt-en-es is a transformer pre-trained model that allows translation of\ntexts from English to Spanish.', 'properties': {'num_train_epochs': {'description': 'Total number of training epochs to perform.', 'minimum': 1, 'placeholder': 1, 'title': 'Num Train Epochs', 'type': 'integer'}, 'batch_size': {'description': 'The batch size per GPU/TPU core/CPU for training', 'minimum': 1, 'placeholder': 4, 'title': 'Batch Size', 'type': 'integer'}, 'learning_rate': {'description': 'The initial learning rate for AdamW optimizer', 'minimum': 0.0, 'placeholder': 2e-05, 'title': 'Learning Rate', 'type': 'number'}, 'device': {'description': 'Hardware on which the training is run. If available, GPU is recommended for efficiency reasons. Otherwise, use CPU.', 'enum': ['gpu', 'cpu'], 'placeholder': 'gpu', 'title': 'Device', 'type': 'string'}, 'weight_decay': {'description': "Weight decay is a regularization technique used in training neural networks to prevent overfitting. In the context of the AdamW optimizer, the 'weight_decay' parameter is the rate at which the weights of all layers are reduced during training, provided that this rate is not zero.", 'minimum': 0.0, 'placeholder': 0.01, 'title': 'Weight Decay', 'type': 'number'}}, 'required': ['num_train_epochs', 'batch_size', 'learning_rate', 'device', 'weight_decay'], 'title': 'OpusMtEnESTransformerSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'BagOfWordsTextClassificationModel': {'name': 'BagOfWordsTextClassificationModel', 'type': 'Model', 'class': , 'configurable_object': True, 'schema': {'description': 'NumericalWrapperForText is a metamodel that allows text classification using\ntabular classifiers and a tokenizer.', 'properties': {'tabular_classifier': {'description': 'Tabular model used as the underlying model to generate the text classifier.', 'parent': 'TabularClassificationModel', 'placeholder': {'component': 'SVC', 'params': {}}, 'properties': {'component': {'title': 'Component', 'type': 'string'}, 'params': {'title': 'Params', 'type': 'object'}}, 'required': ['component', 'params'], 'title': 'Tabular Classifier', 'type': 'object'}, 'ngram_min_n': {'description': 'The lower boundary of the range of n-values for different word n-grams or char n-grams to be extracted. It must be an integer greater or equal than 1', 'minimum': 1, 'placeholder': 1, 'title': 'Ngram Min N', 'type': 'integer'}, 'ngram_max_n': {'description': 'The upper boundary of the range of n-values for different word n-grams or char n-grams to be extracted. It must be an integer greater or equal than 1', 'minimum': 1, 'placeholder': 1, 'title': 'Ngram Max N', 'type': 'integer'}}, 'required': ['tabular_classifier', 'ngram_min_n', 'ngram_max_n'], 'title': 'BagOfWordsTextClassificationModelSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'RidgeRegression': {'name': 'RidgeRegression', 'type': 'Model', 'class': , 'configurable_object': True, 'schema': {'description': 'Ridge regression is a linear model that includes L2 regularization.', 'properties': {'alpha': {'description': 'Regularization strength; must be a positive float. Larger values specify stronger regularization.', 'placeholder': {'fixed_value': 1.0, 'lower_bound': 0.1, 'optimize': False, 'upper_bound': 10.0}, 'title': 'Alpha', 'type': 'object'}, 'fit_intercept': {'description': 'Whether to calculate the intercept for this model. If set to False, no intercept will be used in calculations (e.g., data is expected to be centered).', 'placeholder': True, 'title': 'Fit Intercept', 'type': 'boolean'}, 'copy_X': {'description': 'If True, X will be copied; else, it may be overwritten.', 'placeholder': True, 'title': 'Copy X', 'type': 'boolean'}, 'max_iter': {'description': 'Maximum number of iterations for conjugate gradient solver.', 'placeholder': {'fixed_value': 1000, 'lower_bound': 100, 'optimize': False, 'upper_bound': 10000}, 'title': 'Max Iter', 'type': 'object'}, 'tol': {'description': 'Precision of the solution.', 'placeholder': {'fixed_value': 0.001, 'lower_bound': 1e-05, 'optimize': False, 'upper_bound': 0.1}, 'title': 'Tol', 'type': 'object'}, 'solver': {'description': 'Solver to use in the computation. auto chooses the solver automatically based on the type of data.', 'enum': ['auto', 'svd', 'cholesky', 'lsqr', 'sparse_cg', 'sag', 'saga'], 'placeholder': 'auto', 'title': 'Solver', 'type': 'string'}, 'positive': {'description': 'When set to True, forces the coefficients to be positive.', 'placeholder': False, 'title': 'Positive', 'type': 'boolean'}, 'random_state': {'anyOf': [{'type': 'object'}, {'type': 'integer'}, {'type': 'null'}], 'description': 'The seed of the pseudo random number generator to use when shuffling the data. Pass an int for reproducible output across multiple function calls, or None to not set a specific seed.', 'placeholder': None, 'title': 'Random State'}}, 'required': ['alpha', 'fit_intercept', 'copy_X', 'max_iter', 'tol', 'solver', 'positive', 'random_state'], 'title': 'RidgeRegressionSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'LinearSVR': {'name': 'LinearSVR', 'type': 'Model', 'class': , 'configurable_object': True, 'schema': {'description': 'Support Vector Regression (SVR) using a linear kernel.', 'properties': {'epsilon': {'description': 'Epsilon parameter that specifies the epsilon-tube within which no penalty is associated.', 'placeholder': {'fixed_value': 0.0, 'lower_bound': 0.0, 'optimize': False, 'upper_bound': 1}, 'title': 'Epsilon', 'type': 'object'}, 'tol': {'description': 'Tolerance for stopping criterion.', 'placeholder': {'fixed_value': 0.0001, 'lower_bound': 1e-05, 'optimize': False, 'upper_bound': 0.1}, 'title': 'Tol', 'type': 'object'}, 'C': {'description': 'Regularization parameter. The strength of the regularization is inversely proportional to C.', 'placeholder': {'fixed_value': 1.0, 'lower_bound': 0.1, 'optimize': False, 'upper_bound': 10}, 'title': 'C', 'type': 'object'}, 'loss': {'description': "Specifies the loss function. 'epsilon_insensitive' is the standard SVR loss.", 'enum': ['epsilon_insensitive', 'squared_epsilon_insensitive'], 'placeholder': 'epsilon_insensitive', 'title': 'Loss', 'type': 'string'}, 'fit_intercept': {'description': 'Whether to calculate the intercept for this model.', 'placeholder': True, 'title': 'Fit Intercept', 'type': 'boolean'}, 'intercept_scaling': {'description': 'When fit_intercept is True, instance vector x becomes [x, self.intercept_scaling] in the primal problem.', 'placeholder': {'fixed_value': 1.0, 'lower_bound': 0.1, 'optimize': False, 'upper_bound': 10}, 'title': 'Intercept Scaling', 'type': 'object'}, 'dual': {'description': 'Select the algorithm to either solve the dual or primal optimization problem.', 'placeholder': True, 'title': 'Dual', 'type': 'boolean'}, 'verbose': {'description': 'Enable verbose output. Note that this setting takes advantage of a per-process runtime setting in libsvm.', 'placeholder': {'fixed_value': 0, 'lower_bound': 0, 'optimize': False, 'upper_bound': 100}, 'title': 'Verbose', 'type': 'object'}, 'random_state': {'anyOf': [{'type': 'object'}, {'type': 'integer'}, {'type': 'null'}], 'description': 'The seed of the pseudo-random number generator to use when shuffling the data.', 'placeholder': None, 'title': 'Random State'}, 'max_iter': {'description': 'The maximum number of iterations to be run.', 'placeholder': {'fixed_value': 1000, 'lower_bound': 100, 'optimize': False, 'upper_bound': 10000}, 'title': 'Max Iter', 'type': 'object'}}, 'required': ['epsilon', 'tol', 'C', 'loss', 'fit_intercept', 'intercept_scaling', 'dual', 'verbose', 'random_state', 'max_iter'], 'title': 'LinearSVRSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'LinearRegression': {'name': 'LinearRegression', 'type': 'Model', 'class': , 'configurable_object': True, 'schema': {'description': 'Linear regression model with optional intercept.', 'properties': {'fit_intercept': {'description': 'Whether to calculate the intercept for this model. If set to False, no intercept will be used in calculations (e.g., data is expected to be centered).', 'placeholder': True, 'title': 'Fit Intercept', 'type': 'boolean'}, 'copy_X': {'description': 'If True, X will be copied; else, it may be overwritten.', 'placeholder': True, 'title': 'Copy X', 'type': 'boolean'}, 'n_jobs': {'anyOf': [{'type': 'object'}, {'type': 'integer'}, {'type': 'null'}], 'description': 'The number of jobs to use for the computation. None means 1 job, while -1 means using all processors.', 'placeholder': None, 'title': 'N Jobs'}, 'positive': {'description': 'When set to True, forces the coefficients to be positive.', 'placeholder': False, 'title': 'Positive', 'type': 'boolean'}}, 'required': ['fit_intercept', 'copy_X', 'n_jobs', 'positive'], 'title': 'LinearRegressionSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'TFIDFRetriever': {'name': 'TFIDFRetriever', 'type': 'Model', 'class': , 'configurable_object': True, 'schema': {'description': 'Schema for the TFIDFRetriever.', 'properties': {'similarity_function': {'description': 'Similarity function to use for document retrieval.', 'enum': ['cosine', 'euclidean'], 'placeholder': 'cosine', 'title': 'Similarity Function', 'type': 'string'}, 'n_docs': {'description': 'Number of documents to retrieve.', 'minimum': 1, 'placeholder': 5, 'title': 'N Docs', 'type': 'integer'}, 'similarity_threshold': {'description': 'Maximum or minimum distance for retrieved documents based on the similarity_function.', 'placeholder': 0.5, 'title': 'Similarity Threshold', 'type': 'number'}, 'chunk_size': {'description': 'Size of chunks to split the documents into.', 'minimum': 1, 'placeholder': 512, 'title': 'Chunk Size', 'type': 'integer'}, 'chunk_overlap': {'description': 'Overlap between chunks when splitting documents.', 'minimum': 0, 'placeholder': 50, 'title': 'Chunk Overlap', 'type': 'integer'}}, 'required': ['similarity_function', 'n_docs', 'similarity_threshold', 'chunk_size', 'chunk_overlap'], 'title': 'TFIDFRetrieverSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'DenseRetriever': {'name': 'DenseRetriever', 'type': 'Model', 'class': , 'configurable_object': True, 'schema': {'description': 'Schema for Dense Retriever.', 'properties': {'encoding_model': {'description': 'Model to convert text into dense vector representations.', 'parent': 'HuggingFaceWrapper', 'placeholder': {'component': 'Embedding', 'params': {}}, 'properties': {'component': {'title': 'Component', 'type': 'string'}, 'params': {'title': 'Params', 'type': 'object'}}, 'required': ['component', 'params'], 'title': 'Encoding Model', 'type': 'object'}}, 'required': ['encoding_model'], 'title': 'DenseRetrieverSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}}, 'GenerativeModel': {'GemmaModel': {'name': 'GemmaModel', 'type': 'GenerativeModel', 'class': , 'configurable_object': True, 'schema': {'description': 'Schema for Gemma model.', 'properties': {'max_tokens': {'description': 'Maximum number of tokens to generate.', 'minimum': 1, 'placeholder': 100, 'title': 'Max Tokens', 'type': 'integer'}, 'temperature': {'description': 'Sampling temperature. Higher values make the output more random, while lower values make it more focused and deterministic.', 'maximum': 1.0, 'minimum': 0.0, 'placeholder': 0.7, 'title': 'Temperature', 'type': 'number'}, 'frequency_penalty': {'description': 'Penalty for repeated tokens in the output. Higher values reduce the likelihood of repetition, encouraging more diverse text generation.', 'maximum': 2.0, 'minimum': 0.0, 'placeholder': 0.1, 'title': 'Frequency Penalty', 'type': 'number'}, 'context_window': {'description': 'Maximum number of tokens the model can process in a single forward pass (context window size).', 'minimum': 1, 'placeholder': 512, 'title': 'Context Window', 'type': 'integer'}, 'device': {'description': 'The device to use for model inference.', 'enum': ['cpu'], 'placeholder': 'cpu', 'title': 'Device', 'type': 'string'}}, 'required': ['max_tokens', 'temperature', 'frequency_penalty', 'context_window', 'device'], 'title': 'GemmaSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'QwenModel': {'name': 'QwenModel', 'type': 'GenerativeModel', 'class': , 'configurable_object': True, 'schema': {'description': 'Schema for Qwen model.', 'properties': {'model_name': {'description': 'The specific Qwen model version to use.', 'enum': ['Qwen/Qwen2.5-0.5B-Instruct-GGUF', 'Qwen/Qwen2.5-1.5B-Instruct-GGUF', 'Qwen/Qwen3-4B-GGUF '], 'placeholder': 'Qwen/Qwen2.5-1.5B-Instruct-GGUF', 'title': 'Model Name', 'type': 'string'}, 'max_tokens': {'description': 'Maximum number of tokens to generate.', 'minimum': 1, 'placeholder': 100, 'title': 'Max Tokens', 'type': 'integer'}, 'temperature': {'description': 'Sampling temperature. Higher values make the output more random, while lower values make it more focused and deterministic.', 'maximum': 1.0, 'minimum': 0.0, 'placeholder': 0.7, 'title': 'Temperature', 'type': 'number'}, 'frequency_penalty': {'description': 'Penalty for repeated tokens in the output. Higher values reduce the likelihood of repetition, encouraging more diverse text generation.', 'maximum': 2.0, 'minimum': 0.0, 'placeholder': 0.1, 'title': 'Frequency Penalty', 'type': 'number'}, 'context_window': {'description': 'Maximum number of tokens the model can process in a single forward pass (context window size).', 'minimum': 1, 'placeholder': 512, 'title': 'Context Window', 'type': 'integer'}, 'device': {'description': 'The device to use for model inference.', 'enum': ['cpu'], 'placeholder': 'cpu', 'title': 'Device', 'type': 'string'}}, 'required': ['model_name', 'max_tokens', 'temperature', 'frequency_penalty', 'context_window', 'device'], 'title': 'QwenSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'StableDiffusionV2Model': {'name': 'StableDiffusionV2Model', 'type': 'GenerativeModel', 'class': , 'configurable_object': True, 'schema': {'description': 'Schema for Stable Diffusion V2 image generation.', 'properties': {'model_name': {'description': 'The specific Stable Diffusion model version to use.', 'enum': ['stabilityai/stable-diffusion-2', 'stabilityai/stable-diffusion-2-base', 'stabilityai/stable-diffusion-2-1', 'stabilityai/stable-diffusion-2-1-base'], 'placeholder': 'stabilityai/stable-diffusion-2', 'title': 'Model Name', 'type': 'string'}, 'negative_prompt': {'anyOf': [{'description': 'Text prompt for elements to avoid in the image.', 'placeholder': '', 'type': 'string'}, {'type': 'null'}], 'title': 'Negative Prompt'}, 'num_inference_steps': {'description': 'Number of denoising steps. Higher usually leads to better quality but slower inference.', 'minimum': 1, 'placeholder': 15, 'title': 'Num Inference Steps', 'type': 'integer'}, 'guidance_scale': {'description': 'How strongly the model follows the prompt. Higher = closer to prompt, but may reduce image quality.', 'minimum': 0.0, 'placeholder': 3.5, 'title': 'Guidance Scale', 'type': 'number'}, 'device': {'description': "Device for generation. Use 'cuda' if GPU is available.", 'enum': ['cuda:0', 'cpu'], 'placeholder': 'cuda:0', 'title': 'Device', 'type': 'string'}, 'seed': {'description': 'Random seed for reproducibility. Use negative value for random seed.', 'placeholder': -1, 'title': 'Seed', 'type': 'integer'}, 'width': {'description': 'Width of the generated image. Must be a multiple of 8.', 'maximum': 2048, 'minimum': 64, 'placeholder': 512, 'title': 'Width', 'type': 'integer'}, 'height': {'description': 'Height of the generated image. Must be a multiple of 8.', 'maximum': 2048, 'minimum': 64, 'placeholder': 512, 'title': 'Height', 'type': 'integer'}, 'num_images_per_prompt': {'description': 'Number of images to generate per prompt.', 'minimum': 1, 'placeholder': 1, 'title': 'Num Images Per Prompt', 'type': 'integer'}}, 'required': ['model_name', 'negative_prompt', 'num_inference_steps', 'guidance_scale', 'device', 'seed', 'width', 'height', 'num_images_per_prompt'], 'title': 'StableDiffusionSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'StableDiffusionV3Model': {'name': 'StableDiffusionV3Model', 'type': 'GenerativeModel', 'class': , 'configurable_object': True, 'schema': {'description': 'Schema for Stable Diffusion V3 image generation.', 'properties': {'model_name': {'description': 'The specific Stable Diffusion model version to use.', 'enum': ['stabilityai/stable-diffusion-3-medium-diffusers', 'stabilityai/stable-diffusion-3-medium-tensorrt', 'stabilityai/stable-diffusion-3.5-medium', 'stabilityai/stable-diffusion-3.5-large', 'stabilityai/stable-diffusion-3.5-large-turbo'], 'placeholder': 'stabilityai/stable-diffusion-3-medium-diffusers', 'title': 'Model Name', 'type': 'string'}, 'negative_prompt': {'anyOf': [{'description': 'Text prompt for elements to avoid in the image.', 'placeholder': '', 'type': 'string'}, {'type': 'null'}], 'title': 'Negative Prompt'}, 'num_inference_steps': {'description': 'Number of denoising steps. Higher usually leads to better quality but slower inference.', 'minimum': 1, 'placeholder': 15, 'title': 'Num Inference Steps', 'type': 'integer'}, 'guidance_scale': {'description': 'How strongly the model follows the prompt. Higher = closer to prompt, but may reduce image quality.', 'minimum': 0.0, 'placeholder': 3.5, 'title': 'Guidance Scale', 'type': 'number'}, 'device': {'description': "Device for generation. Use 'cuda' if GPU is available.", 'enum': ['cuda:0', 'cpu'], 'placeholder': 'cuda:0', 'title': 'Device', 'type': 'string'}, 'seed': {'description': 'Random seed for reproducibility. Use negative value for random seed.', 'placeholder': -1, 'title': 'Seed', 'type': 'integer'}, 'width': {'description': 'Width of the generated image. Must be a multiple of 8.', 'maximum': 2048, 'minimum': 64, 'placeholder': 512, 'title': 'Width', 'type': 'integer'}, 'height': {'description': 'Height of the generated image. Must be a multiple of 8.', 'maximum': 2048, 'minimum': 64, 'placeholder': 512, 'title': 'Height', 'type': 'integer'}, 'num_images_per_prompt': {'description': 'Number of images to generate per prompt.', 'minimum': 1, 'placeholder': 1, 'title': 'Num Images Per Prompt', 'type': 'integer'}}, 'required': ['model_name', 'negative_prompt', 'num_inference_steps', 'guidance_scale', 'device', 'seed', 'width', 'height', 'num_images_per_prompt'], 'title': 'StableDiffusionSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'StableDiffusionXLV1ControlNet': {'name': 'StableDiffusionXLV1ControlNet', 'type': 'GenerativeModel', 'class': , 'configurable_object': True, 'schema': {'properties': {'num_inference_steps': {'description': 'Number of denoising steps. Higher usually leads to better quality but slower inference.', 'minimum': 1, 'placeholder': 15, 'title': 'Num Inference Steps', 'type': 'integer'}, 'controlnet_conditioning_scale': {'description': 'Scale for the ControlNet conditioning. Higher values make the model follow the controlnet more closely.', 'minimum': 0.0, 'placeholder': 1.0, 'title': 'Controlnet Conditioning Scale', 'type': 'number'}, 'device': {'description': "Device for generation. Use 'cuda' if GPU is available.", 'enum': ['cuda:0', 'cpu'], 'placeholder': 'cuda:0', 'title': 'Device', 'type': 'string'}}, 'required': ['num_inference_steps', 'controlnet_conditioning_scale', 'device'], 'title': 'StableDiffusionXLV1ControlNetSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'RAGPipeline': {'name': 'RAGPipeline', 'type': 'GenerativeModel', 'class': , 'configurable_object': True, 'schema': {'description': 'Schema for RAG pipeline.', 'properties': {'documents': {'description': 'List of documents to be used in the RAG pipeline.', 'items': {'type': 'string'}, 'minItems': 1, 'placeholder': None, 'title': 'Documents', 'type': 'array'}, 'retriever_model': {'description': 'Retriever component used in the RAG pipeline.', 'parent': 'RetrieverModel', 'placeholder': {'component': 'TFIDFRetriever', 'params': {}}, 'properties': {'component': {'title': 'Component', 'type': 'string'}, 'params': {'title': 'Params', 'type': 'object'}}, 'required': ['component', 'params'], 'title': 'Retriever Model', 'type': 'object'}, 'generation_model': {'description': 'Text generation model used in the RAG pipeline.', 'parent': 'TextToTextGenerationTaskModel', 'placeholder': {'component': 'DeepSeek', 'params': {}}, 'properties': {'component': {'title': 'Component', 'type': 'string'}, 'params': {'title': 'Params', 'type': 'object'}}, 'required': ['component', 'params'], 'title': 'Generation Model', 'type': 'object'}}, 'required': ['documents', 'retriever_model', 'generation_model'], 'title': 'RAGPipelineSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}}, 'DataLoader': {'CSVDataLoader': {'name': 'CSVDataLoader', 'type': 'DataLoader', 'class': , 'configurable_object': True, 'schema': {'properties': {'name': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'description': 'Custom name to register your dataset. If no name is specified, the name of the uploaded file will be used.', 'placeholder': '', 'title': 'Name'}, 'separator': {'description': 'A separator character delimits the data in a CSV file.', 'enum': [',', ';', ' ', '\t'], 'placeholder': ',', 'title': 'Separator', 'type': 'string'}}, 'required': ['name', 'separator'], 'title': 'CSVDataloaderSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'JSONDataLoader': {'name': 'JSONDataLoader', 'type': 'DataLoader', 'class': , 'configurable_object': True, 'schema': {'properties': {'name': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'description': 'Custom name to register your dataset. If no name is specified, the name of the uploaded file will be used.', 'placeholder': '', 'title': 'Name'}, 'data_key': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'description': '\n In case the data has the form {data: [{col1: val1, col2: val2, ...]}}\n (also known as table in pandas), name of the field "data",\n where the list with dictionaries with the data should be found.\n\n In case the format is only a list of dictionaries (also known as\n "records" orient in pandas), set this value as null.\n ', 'placeholder': 'data', 'title': 'Data Key'}}, 'required': ['name', 'data_key'], 'title': 'JSONDataloaderSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'ExcelDataLoader': {'name': 'ExcelDataLoader', 'type': 'DataLoader', 'class': , 'configurable_object': True, 'schema': {'properties': {'name': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'description': 'Custom name to register your dataset. If no name is specified, the name of the uploaded file will be used.', 'placeholder': '', 'title': 'Name'}, 'sheet': {'anyOf': [{'minimum': 0, 'type': 'integer'}, {'type': 'string'}], 'description': '\n The name of the sheet to read or its zero-based index.\n If a string is provided, the reader will search for a sheet named exactly as\n the string.\n If an integer is provided, the reader will select the sheet at the corresponding\n index.\n By default, the first sheet will be read.\n ', 'placeholder': 0, 'title': 'Sheet'}, 'header': {'anyOf': [{'minimum': 0, 'type': 'integer'}, {'type': 'null'}], 'description': '\n The row number where the column names are located, indexed from 0.\n If null, the file will be considered to have no column names.\n ', 'placeholder': 0, 'title': 'Header'}, 'usecols': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'description': '\n If None, the reader will load all columns.\n If str, then indicates comma separated list of Excel column letters and column\n ranges (e.g. A:E or A,C,E:F). Ranges are inclusive of both sides.\n ', 'placeholder': None, 'title': 'Usecols'}}, 'required': ['name', 'sheet', 'header', 'usecols'], 'title': 'ExcelDataloaderSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}}, 'Metric': {'F1': {'name': 'F1', 'type': 'Metric', 'class': , 'configurable_object': False, 'schema': None, 'metadata': None, 'description': None, 'display_name': None}, 'Accuracy': {'name': 'Accuracy', 'type': 'Metric', 'class': , 'configurable_object': False, 'schema': None, 'metadata': None, 'description': None, 'display_name': None}, 'Precision': {'name': 'Precision', 'type': 'Metric', 'class': , 'configurable_object': False, 'schema': None, 'metadata': None, 'description': None, 'display_name': None}, 'Recall': {'name': 'Recall', 'type': 'Metric', 'class': , 'configurable_object': False, 'schema': None, 'metadata': None, 'description': None, 'display_name': None}, 'Bleu': {'name': 'Bleu', 'type': 'Metric', 'class': , 'configurable_object': False, 'schema': None, 'metadata': None, 'description': None, 'display_name': None}, 'Ter': {'name': 'Ter', 'type': 'Metric', 'class': , 'configurable_object': False, 'schema': None, 'metadata': None, 'description': None, 'display_name': None}, 'MAE': {'name': 'MAE', 'type': 'Metric', 'class': , 'configurable_object': False, 'schema': None, 'metadata': None, 'description': None, 'display_name': None}, 'RMSE': {'name': 'RMSE', 'type': 'Metric', 'class': , 'configurable_object': False, 'schema': None, 'metadata': None, 'description': None, 'display_name': None}}, 'Optimizer': {'OptunaOptimizer': {'name': 'OptunaOptimizer', 'type': 'Optimizer', 'class': , 'configurable_object': True, 'schema': {'properties': {'n_trials': {'description': "The parameter 'n_trials' is the quantity of trialsper study. It must be of type positive integer.", 'exclusiveMinimum': 0, 'placeholder': 10, 'title': 'N Trials', 'type': 'integer'}, 'sampler': {'description': "Coefficient for 'rbf', 'poly' and 'sigmoid' kernels. Must be in string format and can be 'scale' or 'auto'.", 'enum': ['TPESampler', 'CmaEsSampler', 'GridSampler', 'GPSampler', 'NSGAIISampler', 'QMCSampler', 'RandomSampler'], 'placeholder': 'TPESampler', 'title': 'Sampler', 'type': 'string'}, 'pruner': {'description': "Coefficient for 'rbf', 'poly' and 'sigmoid' kernels. Must be in string format and can be 'scale' or 'auto'.", 'enum': ['MedianPruner', 'None'], 'placeholder': 'None', 'title': 'Pruner', 'type': 'string'}}, 'required': ['n_trials', 'sampler', 'pruner'], 'title': 'OptunaSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'HyperOptOptimizer': {'name': 'HyperOptOptimizer', 'type': 'Optimizer', 'class': , 'configurable_object': True, 'schema': {'properties': {'n_trials': {'description': "The parameter 'n_trials' is the quantity of trialsper study. It must be of type positive integer.", 'exclusiveMinimum': 0, 'placeholder': 10, 'title': 'N Trials', 'type': 'integer'}, 'sampler': {'description': "Coefficient for 'rbf', 'poly' and 'sigmoid' kernels. Must be in string format and can be 'scale' or 'auto'.", 'enum': ['tpe', 'rand'], 'placeholder': 'tpe', 'title': 'Sampler', 'type': 'string'}}, 'required': ['n_trials', 'sampler'], 'title': 'HyperOptSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}}, 'Job': {'ExplainerJob': {'name': 'ExplainerJob', 'type': 'Job', 'class': , 'configurable_object': False, 'schema': None, 'metadata': None, 'description': None, 'display_name': None}, 'ModelJob': {'name': 'ModelJob', 'type': 'Job', 'class': , 'configurable_object': False, 'schema': None, 'metadata': None, 'description': None, 'display_name': None}, 'ExplorerJob': {'name': 'ExplorerJob', 'type': 'Job', 'class': , 'configurable_object': False, 'schema': None, 'metadata': None, 'description': None, 'display_name': None}, 'PredictJob': {'name': 'PredictJob', 'type': 'Job', 'class': , 'configurable_object': False, 'schema': None, 'metadata': None, 'description': None, 'display_name': None}, 'ConverterListJob': {'name': 'ConverterListJob', 'type': 'Job', 'class': , 'configurable_object': False, 'schema': None, 'metadata': None, 'description': None, 'display_name': None}, 'DatasetJob': {'name': 'DatasetJob', 'type': 'Job', 'class': , 'configurable_object': False, 'schema': None, 'metadata': None, 'description': None, 'display_name': None}, 'GenerativeJob': {'name': 'GenerativeJob', 'type': 'Job', 'class': , 'configurable_object': False, 'schema': None, 'metadata': None, 'description': None, 'display_name': None}}, 'LocalExplainer': {'KernelShap': {'name': 'KernelShap', 'type': 'LocalExplainer', 'class': , 'configurable_object': True, 'schema': {'description': "Kernel SHAP is a model-agnostic explainability method for approximating SHAP\nvalues to explain the output of machine learning model by attributing contributions\nof each feature to the model's prediction.", 'properties': {'link': {'description': "Link function to connect the feature importance values to the model's outputs. Options are 'identity' to use identity function or 'logit' to use log-odds function.", 'enum': ['identity', 'logit'], 'placeholder': 'identity', 'title': 'Link', 'type': 'string'}, 'fit_parameter_sample_background_data': {'description': "Parameter to fit the explainer. 'true' if the background data must be sampled, otherwise the entire train data set is used. Smaller datasets speed up the algorithm run time.", 'placeholder': False, 'title': 'Fit Parameter Sample Background Data', 'type': 'boolean'}, 'fit_parameter_n_background_samples': {'description': "Parameter to fit the explainer. If the parameter 'sample_background_data' is 'true', the number of background data samples to be drawn.", 'minimum': 1, 'placeholder': 1, 'title': 'Fit Parameter N Background Samples', 'type': 'integer'}, 'fit_parameter_sampling_method': {'description': "Parameter to fit the explainer. If the parameter 'sample_background_data' is 'true', whether to sample random samples with 'shuffle' option or summarize the data set with 'kmeans' option. If 'categorical_features' is 'true', 'shuffle' options used by default.", 'enum': ['shuffle', 'kmeans'], 'placeholder': 'shuffle', 'title': 'Fit Parameter Sampling Method', 'type': 'string'}}, 'required': ['link', 'fit_parameter_sample_background_data', 'fit_parameter_n_background_samples', 'fit_parameter_sampling_method'], 'title': 'KernelShapSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}}, 'GlobalExplainer': {'PartialDependence': {'name': 'PartialDependence', 'type': 'GlobalExplainer', 'class': , 'configurable_object': True, 'schema': {'description': 'PartialDependence of a feature shows the average prediction of a machine\nlearning model for each possible value of the feature.', 'properties': {'grid_resolution': {'description': 'The number of equidistant points to split the range of the target feature', 'minimum': 1, 'placeholder': 100, 'title': 'Grid Resolution', 'type': 'integer'}, 'lower_percentile': {'description': 'The lower percentile used to limit the feature values.', 'maximum': 0.99, 'minimum': 0.0, 'placeholder': 0.05, 'title': 'Lower Percentile', 'type': 'number'}, 'upper_percentile': {'description': 'The upper percentile used to limit the feature values.', 'maximum': 1.0, 'minimum': 0.01, 'placeholder': 0.95, 'title': 'Upper Percentile', 'type': 'number'}}, 'required': ['grid_resolution', 'lower_percentile', 'upper_percentile'], 'title': 'PartialDependenceSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}, 'PermutationFeatureImportance': {'name': 'PermutationFeatureImportance', 'type': 'GlobalExplainer', 'class': , 'configurable_object': True, 'schema': {'description': "Permutation Feature Importance is a explanation method to asses the\nimportance of each feature in a model by evaluating how much the model's\nperformance decreases when the values of a specific feature are randomly\nshuffled.", 'properties': {'scoring': {'description': 'Scorer to evaluate how the perfomance of the model changes when a particular feature is shuffled.', 'enum': ['accuracy', 'balanced_accuracy'], 'placeholder': 'accuracy', 'title': 'Scoring', 'type': 'string'}, 'n_repeats': {'description': 'Number of times to permute a feature.', 'minimum': 1, 'placeholder': 10, 'title': 'N Repeats', 'type': 'integer'}, 'random_state': {'description': 'Seed for the random number generator to control the permutations of each feature.', 'placeholder': 0, 'title': 'Random State', 'type': 'integer'}, 'max_samples': {'description': 'The number of samples to draw from the dataset to calculate feature importance at each repetition.', 'minimum': 1, 'placeholder': 100, 'title': 'Max Samples', 'type': 'integer'}}, 'required': ['scoring', 'n_repeats', 'random_state', 'max_samples'], 'title': 'PermutationFeatureImportanceSchema', 'type': 'object'}, 'metadata': None, 'description': None, 'display_name': None}}, 'Explorer': {'DescribeExplorer': {'name': 'DescribeExplorer', 'type': 'Explorer', 'class': , 'configurable_object': True, 'schema': {'properties': {'percentiles': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'description': "The percentiles to include in the exploration. Must be a list of integers between 0 and 100.\nExample: '25, 50, 75'", 'placeholder': '25, 50, 75', 'title': 'Percentiles'}, 'include': {'anyOf': [{'enum': ['all', 'number', 'object', 'category', 'datetime'], 'type': 'string'}, {'type': 'null'}], 'description': 'The data types to include in the exploration.\n', 'placeholder': 'all', 'title': 'Include'}, 'exclude': {'anyOf': [{'enum': ['object', 'number', 'category', 'datetime'], 'type': 'string'}, {'type': 'null'}], 'description': 'The data types to exclude in the exploration.', 'placeholder': None, 'title': 'Exclude'}}, 'required': ['percentiles', 'include', 'exclude'], 'title': 'DescribeExplorerSchema', 'type': 'object'}, 'metadata': {'allowed_dtypes': ['*'], 'restricted_dtypes': [], 'input_cardinality': {'min': 1}, 'display_name': 'Describe Dataset', 'allowed_value_types': ['*'], 'restricted_value_types': []}, 'description': 'DescribeExplorer is an explorer that describes the dataset. It returns a tabular representation of the dataset with the count, mean, std, min, 25%, 50%, 75%, and max values for numeric columns and count, unique, top, and freq values for object columns.\nThe user can specify the percentiles to include in the exploration and the data types to include or exclude.', 'display_name': 'Describe Dataset'}, 'ScatterPlotExplorer': {'name': 'ScatterPlotExplorer', 'type': 'Explorer', 'class': , 'configurable_object': True, 'schema': {'properties': {'color_group': {'anyOf': [{'type': 'string'}, {'minimum': 0, 'type': 'integer'}, {'type': 'null'}], 'description': 'The columnName or columnIndex to take for grouping colored points.', 'placeholder': None, 'title': 'Color Group'}, 'simbol_group': {'anyOf': [{'type': 'string'}, {'minimum': 0, 'type': 'integer'}, {'type': 'null'}], 'description': 'The columnName or columnIndex to take for grouping simbol of the points.', 'placeholder': None, 'title': 'Simbol Group'}, 'point_size': {'anyOf': [{'type': 'string'}, {'minimum': 0, 'type': 'integer'}, {'type': 'null'}], 'description': 'The columnName or columnIndex to take for size of each point.', 'placeholder': None, 'title': 'Point Size'}}, 'required': ['color_group', 'simbol_group', 'point_size'], 'title': 'ScatterPlotSchema', 'type': 'object'}, 'metadata': {'allowed_dtypes': ['*'], 'restricted_dtypes': [], 'input_cardinality': {'exact': 2}, 'display_name': 'Scatter Plot', 'allowed_value_types': ['*'], 'restricted_value_types': []}, 'description': 'ScatterPlotExplorer is an explorer that returns a scatter plot of selected columns of a dataset.', 'display_name': 'Scatter Plot'}, 'WordcloudExplorer': {'name': 'WordcloudExplorer', 'type': 'Explorer', 'class': , 'configurable_object': True, 'schema': {'properties': {'max_words': {'description': 'The maximum number of words to display in the wordcloud.', 'exclusiveMinimum': 0, 'placeholder': 200, 'title': 'Max Words', 'type': 'integer'}, 'background_color': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'description': 'The background color of the wordcloud. If None, the background will be transparent.', 'placeholder': None, 'title': 'Background Color'}}, 'required': ['max_words', 'background_color'], 'title': 'WordcloudSchema', 'type': 'object'}, 'metadata': {'allowed_dtypes': ['string'], 'restricted_dtypes': [], 'input_cardinality': {'min': 1}, 'display_name': 'Word Cloud', 'allowed_value_types': ['*'], 'restricted_value_types': []}, 'description': 'A wordcloud is a visual representation of text data, where the size of each word indicates its frequency in the text.\nThis explorer generates a wordcloud from the concatenated strings of all selected columns in the dataset.', 'display_name': 'Word Cloud'}, 'RowExplorer': {'name': 'RowExplorer', 'type': 'Explorer', 'class': , 'configurable_object': True, 'schema': {'properties': {'row_ammount': {'description': 'The maximum number of rows to take.', 'exclusiveMinimum': 0, 'placeholder': 50, 'title': 'Row Ammount', 'type': 'integer'}, 'shuffle': {'description': 'Shuffle the rows at exploration time.', 'placeholder': False, 'title': 'Shuffle', 'type': 'boolean'}, 'from_top': {'description': 'Take the rows from the Head of the dataset. Else, take from the Tail.', 'placeholder': True, 'title': 'From Top', 'type': 'boolean'}}, 'required': ['row_ammount', 'shuffle', 'from_top'], 'title': 'RowExplorerSchema', 'type': 'object'}, 'metadata': {'allowed_dtypes': ['*'], 'restricted_dtypes': [], 'input_cardinality': {'min': 1}, 'display_name': 'Show Rows', 'allowed_value_types': ['*'], 'restricted_value_types': []}, 'description': 'RowExplorer is an explorer that takes a number of rows from the dataset to display them on tabular format. It can take the rows from the top or the bottom of the dataset and shuffle them if needed.', 'display_name': 'Show Rows'}, 'BoxPlotExplorer': {'name': 'BoxPlotExplorer', 'type': 'Explorer', 'class': , 'configurable_object': True, 'schema': {'properties': {'horizontal': {'description': 'If True, the box plot will be horizontal, otherwise vertical.', 'placeholder': False, 'title': 'Horizontal', 'type': 'boolean'}, 'points': {'description': "One of 'all', 'outliers', or 'False'. Determines which points are shown.", 'enum': ['all', 'outliers', 'False'], 'placeholder': 'outliers', 'title': 'Points', 'type': 'string'}}, 'required': ['horizontal', 'points'], 'title': 'BoxPlotSchema', 'type': 'object'}, 'metadata': {'allowed_dtypes': ['*'], 'restricted_dtypes': [], 'input_cardinality': {'min': 1, 'max': 2}, 'display_name': 'Box Plot', 'allowed_value_types': ['*'], 'restricted_value_types': []}, 'description': 'BoxPlotExplorer is an explorer that returns a box plot of selected columns of a dataset.', 'display_name': 'Box Plot'}, 'MultiColumnBoxPlotExplorer': {'name': 'MultiColumnBoxPlotExplorer', 'type': 'Explorer', 'class': , 'configurable_object': True, 'schema': {'properties': {'horizontal': {'description': 'If True, the box plot will be horizontal, otherwise vertical.', 'placeholder': False, 'title': 'Horizontal', 'type': 'boolean'}, 'points': {'description': "One of 'all', 'outliers', or 'False'. Determines which points are shown.", 'enum': ['all', 'outliers', 'False'], 'placeholder': 'outliers', 'title': 'Points', 'type': 'string'}, 'opposite_axis': {'anyOf': [{'type': 'string'}, {'minimum': 0, 'type': 'integer'}, {'type': 'null'}], 'description': 'The columnName or columnIndex to take for the opposite axis.', 'placeholder': None, 'title': 'Opposite Axis'}}, 'required': ['horizontal', 'points', 'opposite_axis'], 'title': 'MultiColumnBoxPlotSchema', 'type': 'object'}, 'metadata': {'allowed_dtypes': ['*'], 'restricted_dtypes': [], 'input_cardinality': {'min': 1}, 'display_name': 'Multiple Column Box Plot', 'allowed_value_types': ['*'], 'restricted_value_types': []}, 'description': 'MultiColumnBoxPlotExplorer is an explorer that returns a figure with a box plot of multiple columns of a dataset in a single axis. The other axis is selected through the opposite_axis parameter.', 'display_name': 'Multiple Column Box Plot'}, 'CorrelationMatrixExplorer': {'name': 'CorrelationMatrixExplorer', 'type': 'Explorer', 'class': , 'configurable_object': True, 'schema': {'properties': {'method': {'description': "The correlation method to use. Must be one of 'pearson', 'kendall', or 'spearman'.", 'enum': ['pearson', 'kendall', 'spearman'], 'placeholder': 'pearson', 'title': 'Method', 'type': 'string'}, 'min_periods': {'description': "The minimum number of observations required per pair of columns to have a valid result. Only used if method is 'pearson' or 'spearman'.", 'exclusiveMinimum': 0, 'placeholder': 1, 'title': 'Min Periods', 'type': 'integer'}, 'numeric_only': {'description': 'If True, only include numeric columns when calculating correlation.If False, all columns are included.', 'placeholder': True, 'title': 'Numeric Only', 'type': 'boolean'}, 'plot': {'description': 'If True, the result will be plotted.', 'placeholder': True, 'title': 'Plot', 'type': 'boolean'}}, 'required': ['method', 'min_periods', 'numeric_only', 'plot'], 'title': 'CorrelationMatrixExplorerSchema', 'type': 'object'}, 'metadata': {'allowed_dtypes': ['*'], 'restricted_dtypes': [], 'input_cardinality': {'min': 2}, 'display_name': 'Correlation Matrix', 'allowed_value_types': ['*'], 'restricted_value_types': []}, 'description': 'CorrelationMatrixExplorer is an explorer that returns a correlation matrix of a dataset.\nIts result is a heatmap by default, but can also be returned as a tabular result.', 'display_name': 'Correlation Matrix'}, 'CovarianceMatrixExplorer': {'name': 'CovarianceMatrixExplorer', 'type': 'Explorer', 'class': , 'configurable_object': True, 'schema': {'properties': {'min_periods': {'description': 'The minimum number of observations required per pair of columns to have a valid result.', 'exclusiveMinimum': 0, 'placeholder': 1, 'title': 'Min Periods', 'type': 'integer'}, 'delta_degree_of_freedom': {'description': 'The delta degree of freedom to use when calculating the covariance matrix.Only used if numeric_only is True.', 'exclusiveMinimum': 0, 'placeholder': 1, 'title': 'Delta Degree Of Freedom', 'type': 'integer'}, 'numeric_only': {'description': 'If True, only include numeric columns when calculating correlation.If False, all columns are included.', 'placeholder': True, 'title': 'Numeric Only', 'type': 'boolean'}, 'plot': {'description': 'If True, the result will be plotted.', 'placeholder': True, 'title': 'Plot', 'type': 'boolean'}}, 'required': ['min_periods', 'delta_degree_of_freedom', 'numeric_only', 'plot'], 'title': 'CovarianceMatrixExplorerSchema', 'type': 'object'}, 'metadata': {'allowed_dtypes': ['*'], 'restricted_dtypes': [], 'input_cardinality': {'min': 2}, 'display_name': 'Covariance Matrix', 'allowed_value_types': ['*'], 'restricted_value_types': []}, 'description': 'CovarianceExplorer is an explorer that returns the covariance matrix of the dataset.\nIts result is a heatmap by default, but can also be returned as a tabular result.', 'display_name': 'Covariance Matrix'}, 'DensityHeatmapExplorer': {'name': 'DensityHeatmapExplorer', 'type': 'Explorer', 'class': , 'configurable_object': True, 'schema': {'properties': {'nbinsx': {'anyOf': [{'minimum': 1, 'type': 'integer'}, {'type': 'null'}], 'description': 'The number of bins along the x axis.', 'placeholder': None, 'title': 'Nbinsx'}, 'nbinsy': {'anyOf': [{'minimum': 1, 'type': 'integer'}, {'type': 'null'}], 'description': 'The number of bins along the y axis.', 'placeholder': None, 'title': 'Nbinsy'}}, 'required': ['nbinsx', 'nbinsy'], 'title': 'DensityHeatmapSchema', 'type': 'object'}, 'metadata': {'allowed_dtypes': ['*'], 'restricted_dtypes': [], 'input_cardinality': {'exact': 2}, 'display_name': 'Density Heatmap', 'allowed_value_types': ['*'], 'restricted_value_types': []}, 'description': 'DensityHeatmapExplorer is an explorer that returns a density heatmap of selected columns of a dataset.', 'display_name': 'Density Heatmap'}, 'ECDFPlotExplorer': {'name': 'ECDFPlotExplorer', 'type': 'Explorer', 'class': , 'configurable_object': True, 'schema': {'properties': {'color_column': {'anyOf': [{'type': 'string'}, {'minimum': 0, 'type': 'integer'}, {'type': 'null'}], 'description': 'The column to use for coloring the ECDF plot.', 'placeholder': None, 'title': 'Color Column'}, 'facet_col': {'anyOf': [{'type': 'string'}, {'minimum': 0, 'type': 'integer'}, {'type': 'null'}], 'description': 'The column to use for faceting the ECDF plot in the column direction.', 'placeholder': None, 'title': 'Facet Col'}, 'facet_row': {'anyOf': [{'type': 'string'}, {'minimum': 0, 'type': 'integer'}, {'type': 'null'}], 'description': 'The column to use for faceting the ECDF plot in the row direction.', 'placeholder': None, 'title': 'Facet Row'}, 'ecdf_norm': {'description': 'Specifies the type of normalization used for this ECDF plot.', 'enum': ['none', 'percent', 'probability'], 'placeholder': 'probability', 'title': 'Ecdf Norm', 'type': 'string'}}, 'required': ['color_column', 'facet_col', 'facet_row', 'ecdf_norm'], 'title': 'ECDFPlotSchema', 'type': 'object'}, 'metadata': {'allowed_dtypes': ['float64', 'float32'], 'restricted_dtypes': [], 'input_cardinality': {'min': 1}, 'display_name': 'Empirical Cumulative Distribution Plot', 'allowed_value_types': ['*'], 'restricted_value_types': []}, 'description': 'The ECDF plot is a non-parametric way to explore the distribution of a variable. It shows the proportion or count of observations falling below each unique value in the dataset.', 'display_name': 'Empirical Cumulative Distribution Plot'}, 'HistogramPlotExplorer': {'name': 'HistogramPlotExplorer', 'type': 'Explorer', 'class': , 'configurable_object': True, 'schema': {'properties': {'nbins': {'anyOf': [{'minimum': 1, 'type': 'integer'}, {'type': 'null'}], 'description': 'The number of bins to use for the histogram.', 'placeholder': None, 'title': 'Nbins'}, 'histfunc': {'description': 'Specifies the binning function used for this histogram trace.', 'enum': ['count', 'sum', 'avg', 'min', 'max'], 'placeholder': 'count', 'title': 'Histfunc', 'type': 'string'}, 'histnorm': {'description': 'Specifies the type of normalization used for this histogram trace.', 'enum': ['', 'percent', 'probability', 'density', 'probability density'], 'placeholder': '', 'title': 'Histnorm', 'type': 'string'}, 'color_group': {'anyOf': [{'type': 'string'}, {'minimum': 0, 'type': 'integer'}, {'type': 'null'}], 'description': 'The columnName or columnIndex to take for grouping colored points.', 'placeholder': None, 'title': 'Color Group'}, 'pattern_group': {'anyOf': [{'type': 'string'}, {'minimum': 0, 'type': 'integer'}, {'type': 'null'}], 'description': 'The columnName or columnIndex to take for grouping pattern of the points.', 'placeholder': None, 'title': 'Pattern Group'}}, 'required': ['nbins', 'histfunc', 'histnorm', 'color_group', 'pattern_group'], 'title': 'HistogramPlotSchema', 'type': 'object'}, 'metadata': {'allowed_dtypes': ['*'], 'restricted_dtypes': [], 'input_cardinality': {'exact': 1}, 'display_name': 'Histogram Plot', 'allowed_value_types': ['*'], 'restricted_value_types': []}, 'description': 'HistogramPlotExplorer is an explorer that returns a density heatmap of a selected column of a dataset.', 'display_name': 'Histogram Plot'}, 'ScatterMatrixExplorer': {'name': 'ScatterMatrixExplorer', 'type': 'Explorer', 'class': , 'configurable_object': True, 'schema': {'properties': {'color_group': {'anyOf': [{'type': 'string'}, {'minimum': 0, 'type': 'integer'}, {'type': 'null'}], 'description': 'The columnName or columnIndex to take for grouping colored points.', 'placeholder': None, 'title': 'Color Group'}, 'simbol_group': {'anyOf': [{'type': 'string'}, {'minimum': 0, 'type': 'integer'}, {'type': 'null'}], 'description': 'The columnName or columnIndex to take for grouping simbol of the points.', 'placeholder': None, 'title': 'Simbol Group'}}, 'required': ['color_group', 'simbol_group'], 'title': 'ScatterMatrixSchema', 'type': 'object'}, 'metadata': {'allowed_dtypes': ['*'], 'restricted_dtypes': [], 'input_cardinality': {'min': 2}, 'display_name': 'Multiple Scatter Plot', 'allowed_value_types': ['*'], 'restricted_value_types': []}, 'description': 'ScatterMatrixExplorer is an explorer that returns a scatter matrix plot of selected columns of a dataset. Multiple scatter plots are generated for each pair of columns. The diagonal plots are histograms of the columns. ', 'display_name': 'Multiple Scatter Plot'}, 'ParallelCategoriesExplorer': {'name': 'ParallelCategoriesExplorer', 'type': 'Explorer', 'class': , 'configurable_object': True, 'schema': {'properties': {'color_column': {'anyOf': [{'type': 'string'}, {'minimum': 0, 'type': 'integer'}, {'type': 'null'}], 'description': 'The column to use for coloring the data points. ', 'placeholder': None, 'title': 'Color Column'}}, 'required': ['color_column'], 'title': 'ParallelCategoriesSchema', 'type': 'object'}, 'metadata': {'allowed_dtypes': ['string'], 'restricted_dtypes': [], 'input_cardinality': {'min': 2}, 'display_name': 'Parallel Categories Plot', 'allowed_value_types': ['*'], 'restricted_value_types': []}, 'description': 'A parallel categories plot is a common way to visualize high-dimensional data. Each vertical line represents one data point, and the lines are connected by a series of horizontal lines. ', 'display_name': 'Parallel Categories Plot'}, 'ParallelCordinatesExplorer': {'name': 'ParallelCordinatesExplorer', 'type': 'Explorer', 'class': , 'configurable_object': True, 'schema': {'properties': {'color_column': {'anyOf': [{'type': 'string'}, {'minimum': 0, 'type': 'integer'}, {'type': 'null'}], 'description': 'The column to use for coloring the data points. ', 'placeholder': None, 'title': 'Color Column'}}, 'required': ['color_column'], 'title': 'ParallelCordinatesSchema', 'type': 'object'}, 'metadata': {'allowed_dtypes': ['float64', 'float32'], 'restricted_dtypes': [], 'input_cardinality': {'min': 2}, 'display_name': 'Parallel Cordinates Plot', 'allowed_value_types': ['*'], 'restricted_value_types': []}, 'description': 'A parallel coordinates plot is a common way to visualize high-dimensional data. Each vertical line represents one data point, and the lines are connected by a series of horizontal lines. ', 'display_name': 'Parallel Cordinates Plot'}}, 'Converter': {'ColumnRemover': {'name': 'ColumnRemover', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {}, 'title': 'ColumnRemoverSchema', 'type': 'object'}, 'metadata': None, 'description': 'Removes the columns selected in scope from the dataset.', 'display_name': None}, 'CharacterReplacer': {'name': 'CharacterReplacer', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'char_to_replace': {'description': 'The character or substring to be replaced. Cannot be empty.', 'placeholder': '', 'title': 'Char To Replace', 'type': 'string'}, 'replacement_char': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'description': "The character or substring to replace with. If null, 'char_to_replace' will be removed.", 'placeholder': None, 'title': 'Replacement Char'}}, 'required': ['char_to_replace', 'replacement_char'], 'title': 'CharacterReplacerSchema', 'type': 'object'}, 'metadata': None, 'description': 'Replaces or removes specified characters/substrings in selected string columns.', 'display_name': None}, 'FastICA': {'name': 'FastICA', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'n_components': {'anyOf': [{'minimum': 1, 'type': 'integer'}, {'type': 'null'}], 'description': 'Number of components to extract.', 'placeholder': None, 'title': 'N Components'}, 'algorithm': {'description': 'Apply parallel or deflational algorithm for FastICA.', 'enum': ['parallel', 'deflation'], 'placeholder': 'parallel', 'title': 'Algorithm', 'type': 'string'}, 'whiten': {'anyOf': [{'enum': ['arbitrary-variance', 'unit-variance'], 'type': 'string'}, {'type': 'boolean'}, {'type': 'null'}], 'description': 'If True, the data is whitened.', 'placeholder': 'unit-variance', 'title': 'Whiten'}, 'fun': {'description': 'The functional form of the G function used in the approximation to neg-entropy.', 'enum': ['logcosh', 'exp', 'cube'], 'placeholder': 'logcosh', 'title': 'Fun', 'type': 'string'}, 'fun_args': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'description': 'Arguments to the G function.', 'placeholder': None, 'title': 'Fun Args'}, 'max_iter': {'description': 'Maximum number of iterations to perform.', 'minimum': 1, 'placeholder': 200, 'title': 'Max Iter', 'type': 'integer'}, 'tol': {'description': 'Tolerance on update at each iteration.', 'minimum': 0.0, 'placeholder': 0.0001, 'title': 'Tol', 'type': 'number'}, 'w_init': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'description': 'Initial guess for the unmixing matrix.', 'placeholder': None, 'title': 'W Init'}, 'whiten_solver': {'description': 'The solver to use for whitening.', 'enum': ['eigh', 'svd'], 'placeholder': 'svd', 'title': 'Whiten Solver', 'type': 'string'}, 'random_state': {'anyOf': [{'type': 'integer'}, {'enum': ['RandomState'], 'type': 'string'}, {'type': 'null'}], 'description': 'Used to initialize w_init when not specified, with a normal distribution. Pass an int, for reproducible results across multiple function calls.', 'placeholder': None, 'title': 'Random State'}}, 'required': ['n_components', 'algorithm', 'whiten', 'fun', 'fun_args', 'max_iter', 'tol', 'w_init', 'whiten_solver', 'random_state'], 'title': 'FastICASchema', 'type': 'object'}, 'metadata': None, 'description': 'FastICA: a fast algorithm for Independent Component Analysis.', 'display_name': None}, 'IncrementalPCA': {'name': 'IncrementalPCA', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'n_components': {'anyOf': [{'minimum': 1, 'type': 'integer'}, {'type': 'null'}], 'description': 'Number of components to keep.', 'placeholder': 2, 'title': 'N Components'}, 'whiten': {'description': 'When True (False by default) the components_ vectors are multiplied by the square root of n_samples and then divided by the singular values to ensure uncorrelated outputs with unit component-wise variances.', 'placeholder': False, 'title': 'Whiten', 'type': 'boolean'}, 'copy': {'description': 'If False, data passed to fit are overwritten and running fit(X).transform(X) will not yield the expected results, use fit_transform(X) instead.', 'placeholder': True, 'title': 'Copy', 'type': 'boolean'}, 'batch_size': {'anyOf': [{'minimum': 1, 'type': 'integer'}, {'type': 'null'}], 'description': 'The number of samples to use for each batch.', 'placeholder': None, 'title': 'Batch Size'}}, 'required': ['n_components', 'whiten', 'copy', 'batch_size'], 'title': 'IncrementalPCASchema', 'type': 'object'}, 'metadata': None, 'description': 'Incremental principal components analysis (IPCA).', 'display_name': None}, 'PCA': {'name': 'PCA', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'n_components': {'anyOf': [{'minimum': 1, 'type': 'integer'}, {'exclusiveMaximum': 1.0, 'exclusiveMinimum': 0.0, 'type': 'number'}, {'enum': ['mle'], 'type': 'string'}, {'type': 'null'}], 'description': 'Number of components to keep. If None, all components are kept.', 'placeholder': 2, 'title': 'N Components'}, 'copy': {'description': 'If False, data passed to fit are overwritten and running fit(X).transform(X) will not yield the expected results, use fit_transform(X) instead.', 'placeholder': True, 'title': 'Copy', 'type': 'boolean'}, 'whiten': {'description': 'When True (False by default) the components_ vectors are multiplied by the square root of n_samples and then divided by the singular values to ensure uncorrelated outputs with unit component-wise variances. Whitening will remove some information from the transformed signal (the relative variance scales of the components) but can sometime improve the predictive accuracy of the downstream estimators by making their data respect some hard-wired assumptions.', 'placeholder': False, 'title': 'Whiten', 'type': 'boolean'}, 'svd_solver': {'description': "The solver to use for the eigendecomposition. If 'auto', it will choose the most appropriate solver based on the type of data passed.", 'enum': ['auto', 'full', 'covariance_eigh', 'arpack', 'randomized'], 'placeholder': 'auto', 'title': 'Svd Solver', 'type': 'string'}, 'tol': {'description': "Tolerance for singular values computed by svd_solver == 'arpack'.", 'minimum': 0.0, 'placeholder': 0.0, 'title': 'Tol', 'type': 'number'}, 'iterated_power': {'anyOf': [{'minimum': 1, 'type': 'integer'}, {'enum': ['auto'], 'type': 'string'}], 'description': "Number of iterations for the power method computed by svd_solver == 'randomized'.", 'placeholder': 'auto', 'title': 'Iterated Power'}, 'n_oversamples': {'description': "Number of power iterations used when svd_solver == 'randomized'.", 'minimum': 1, 'placeholder': 10, 'title': 'N Oversamples', 'type': 'integer'}, 'power_iteration_normalizer': {'anyOf': [{'enum': ['auto', 'QR', 'LU'], 'type': 'string'}, {'type': 'null'}], 'description': "Whether the power iteration normalizer should be computed with QR (the 'auto' option), LU decomposition ('LU') or left untouched ('QR'). Not used by ARPACK.", 'placeholder': 'auto', 'title': 'Power Iteration Normalizer'}, 'random_state': {'anyOf': [{'type': 'integer'}, {'enum': ['RandomState'], 'type': 'string'}, {'type': 'null'}], 'description': 'Used when the arpack or randomized solvers are used. Pass an int for reproducible results across multiple function calls.', 'placeholder': None, 'title': 'Random State'}}, 'required': ['n_components', 'copy', 'whiten', 'svd_solver', 'tol', 'iterated_power', 'n_oversamples', 'power_iteration_normalizer', 'random_state'], 'title': 'PCASchema', 'type': 'object'}, 'metadata': None, 'description': 'Principal component analysis (PCA).', 'display_name': None}, 'ConverterChain': {'name': 'ConverterChain', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'steps': {'description': 'Number of converters in the chain.', 'minimum': 1, 'placeholder': 1, 'title': 'Steps', 'type': 'integer'}}, 'required': ['steps'], 'title': 'ConverterChainSchema', 'type': 'object'}, 'metadata': None, 'description': 'A ConverterChain applies a sequence of converters to preprocess data, passing the output of one converter to the next, with its scope defined by the first converter (the chain itself).', 'display_name': None}, 'TruncatedSVD': {'name': 'TruncatedSVD', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'n_components': {'description': 'Desired dimensionality of output data.', 'exclusiveMinimum': 0, 'placeholder': 2, 'title': 'N Components', 'type': 'integer'}, 'algorithm': {'description': 'SVD solver to use.', 'enum': ['arpack', 'randomized'], 'placeholder': 'randomized', 'title': 'Algorithm', 'type': 'string'}, 'n_iter': {'description': 'Number of iterations for randomized SVD solver.', 'exclusiveMinimum': 0, 'placeholder': 5, 'title': 'N Iter', 'type': 'integer'}, 'n_oversamples': {'description': 'Number of power iterations used in randomized SVD solver.', 'exclusiveMinimum': 0, 'placeholder': 10, 'title': 'N Oversamples', 'type': 'integer'}, 'power_iteration_normalizer': {'description': 'Method to normalize the eigenvectors.', 'enum': ['auto', 'QR', 'LU', 'none'], 'placeholder': 'auto', 'title': 'Power Iteration Normalizer', 'type': 'string'}, 'random_state': {'anyOf': [{'type': 'integer'}, {'enum': ['RandomState'], 'type': 'string'}, {'type': 'null'}], 'description': 'Used during randomized svd. Pass an int for reproducible results across multiple function calls.', 'placeholder': None, 'title': 'Random State'}, 'tol': {'description': 'Tolerance for ARPACK.', 'minimum': 0.0, 'placeholder': 0.0, 'title': 'Tol', 'type': 'number'}}, 'required': ['n_components', 'algorithm', 'n_iter', 'n_oversamples', 'power_iteration_normalizer', 'random_state', 'tol'], 'title': 'TruncatedSVDSchema', 'type': 'object'}, 'metadata': None, 'description': 'This transformer performs linear dimensionality reduction by means of truncated singular value decomposition (SVD). Contrary to PCA, this estimator does not center the data before computing the singular value decomposition. This means it can work with sparse matrices efficiently.', 'display_name': None}, 'Binarizer': {'name': 'Binarizer', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'threshold': {'description': 'Feature values below or equal to this are replaced by 0, above it by 1.', 'placeholder': 0.0, 'title': 'Threshold', 'type': 'number'}, 'copy': {'description': 'Set to False to perform inplace binarization.', 'placeholder': True, 'title': 'Copy', 'type': 'boolean'}}, 'required': ['threshold', 'copy'], 'title': 'BinarizerSchema', 'type': 'object'}, 'metadata': None, 'description': 'Binarize data (set feature values to 0 or 1) according to a threshold.', 'display_name': None}, 'LabelBinarizer': {'name': 'LabelBinarizer', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'neg_label': {'description': 'Value with which negative labels must be encoded.', 'placeholder': 0, 'title': 'Neg Label', 'type': 'integer'}, 'pos_label': {'description': 'Value with which positive labels must be encoded.', 'placeholder': 1, 'title': 'Pos Label', 'type': 'integer'}}, 'required': ['neg_label', 'pos_label'], 'title': 'LabelBinarizerSchema', 'type': 'object'}, 'metadata': None, 'description': 'Binarize labels in a one-vs-all fashion.', 'display_name': None}, 'LabelEncoder': {'name': 'LabelEncoder', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {}, 'title': 'LabelEncoderSchema', 'type': 'object'}, 'metadata': None, 'description': 'Encode target labels with value between 0 and n_classes-1.', 'display_name': None}, 'MaxAbsScaler': {'name': 'MaxAbsScaler', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'copy': {'description': 'Set to False to perform inplace scaling.', 'placeholder': True, 'title': 'Copy', 'type': 'boolean'}}, 'required': ['copy'], 'title': 'MaxAbsScalerSchema', 'type': 'object'}, 'metadata': None, 'description': 'Scale each feature by its maximum absolute value.', 'display_name': None}, 'MinMaxScaler': {'name': 'MinMaxScaler', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'min_range': {'description': 'The minimum value of the range to scale the data to.', 'minimum': 0.0, 'placeholder': 0, 'title': 'Min Range', 'type': 'number'}, 'max_range': {'description': 'The maximum value of the range to scale the data to.', 'minimum': 0.0, 'placeholder': 1, 'title': 'Max Range', 'type': 'number'}, 'copy': {'description': 'Set to False to perform inplace row normalization.', 'placeholder': True, 'title': 'Copy', 'type': 'boolean'}, 'clip': {'description': 'Set to True to clip the data to the feature range.', 'placeholder': False, 'title': 'Clip', 'type': 'boolean'}}, 'required': ['min_range', 'max_range', 'copy', 'clip'], 'title': 'MinMaxScalerSchema', 'type': 'object'}, 'metadata': None, 'description': 'Transform features by scaling each feature to a given range.', 'display_name': None}, 'Normalizer': {'name': 'Normalizer', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'norm': {'description': 'The norm to use to normalize each non zero sample.', 'enum': ['l1', 'l2', 'max'], 'placeholder': 'l2', 'title': 'Norm', 'type': 'string'}, 'copy': {'description': 'Set to False to perform inplace row normalization.', 'placeholder': True, 'title': 'Copy', 'type': 'boolean'}}, 'required': ['norm', 'copy'], 'title': 'NormalizerSchema', 'type': 'object'}, 'metadata': None, 'description': 'Normalize samples individually to unit norm.', 'display_name': None}, 'OneHotEncoder': {'name': 'OneHotEncoder', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'categories': {'description': 'The categories of each feature.', 'placeholder': 'auto', 'title': 'Categories', 'type': 'string'}, 'drop': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'description': 'Specifies a methodology to use to drop one of the categories per feature.', 'placeholder': None, 'title': 'Drop'}, 'dtype': {'description': 'Desired dtype of output.', 'enum': ['int', 'np.float32', 'np.float64'], 'placeholder': 'np.float64', 'title': 'Dtype', 'type': 'string'}, 'handle_unknown': {'description': 'Whether to raise an error or ignore if an unknown categorical feature is present during transform.', 'enum': ['error', 'ignore', 'infrequent_if_exist'], 'placeholder': 'error', 'title': 'Handle Unknown', 'type': 'string'}, 'min_frequency': {'anyOf': [{'minimum': 0, 'type': 'integer'}, {'maximum': 1.0, 'minimum': 0.0, 'type': 'number'}, {'type': 'null'}], 'description': 'Minimum frequency of a category to be considered as frequent.', 'placeholder': None, 'title': 'Min Frequency'}, 'max_categories': {'anyOf': [{'minimum': 1, 'type': 'integer'}, {'type': 'null'}], 'description': 'Maximum number of categories to encode.', 'placeholder': None, 'title': 'Max Categories'}, 'feature_name_combiner': {'description': 'Method used to combine feature names.', 'enum': ['concat'], 'placeholder': 'concat', 'title': 'Feature Name Combiner', 'type': 'string'}}, 'required': ['categories', 'drop', 'dtype', 'handle_unknown', 'min_frequency', 'max_categories', 'feature_name_combiner'], 'title': 'OneHotEncoderSchema', 'type': 'object'}, 'metadata': None, 'description': 'Encode categorical integer features as a one-hot numeric array.', 'display_name': None}, 'OrdinalEncoder': {'name': 'OrdinalEncoder', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'categories': {'description': 'Categories (unique values) per feature.', 'placeholder': 'auto', 'title': 'Categories', 'type': 'string'}, 'dtype': {'description': 'Desired dtype of output.', 'enum': ['np.int32', 'np.int64', 'np.float32', 'np.float64'], 'placeholder': 'np.float64', 'title': 'Dtype', 'type': 'string'}, 'handle_unknown': {'description': 'Whether to raise an error or ignore if an unknown categorical feature is present during transform.', 'enum': ['error', 'use_encoded_value'], 'placeholder': 'error', 'title': 'Handle Unknown', 'type': 'string'}, 'unknown_value': {'anyOf': [{'enum': ['int', 'np.nan'], 'type': 'string'}, {'type': 'null'}], 'description': 'The value to use for unknown categories.', 'placeholder': None, 'title': 'Unknown Value'}, 'min_frequency': {'anyOf': [{'minimum': 1, 'type': 'integer'}, {'maximum': 1.0, 'minimum': 0.0, 'type': 'number'}, {'type': 'null'}], 'description': 'Minimum frequency of a category to be considered as frequent.', 'placeholder': None, 'title': 'Min Frequency'}, 'max_categories': {'anyOf': [{'minimum': 1, 'type': 'integer'}, {'type': 'null'}], 'description': 'Maximum number of categories to encode.', 'placeholder': None, 'title': 'Max Categories'}}, 'required': ['categories', 'dtype', 'handle_unknown', 'unknown_value', 'min_frequency', 'max_categories'], 'title': 'OrdinalEncoderSchema', 'type': 'object'}, 'metadata': None, 'description': 'Encode categorical features as an integer array.', 'display_name': None}, 'PolynomialFeatures': {'name': 'PolynomialFeatures', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'degree': {'description': 'The degree of the polynomial features.', 'minimum': 1, 'placeholder': 2, 'title': 'Degree', 'type': 'integer'}, 'interaction_only': {'description': 'If True, only interaction features are produced: features that are products of at most degree distinct input features (so not x[1] ** 2, x[0] * x[2] ** 3, etc.).', 'placeholder': False, 'title': 'Interaction Only', 'type': 'boolean'}, 'include_bias': {'description': 'If True (default), then include a bias column, the feature in which all polynomial powers are zero (i.e. a column of ones - acts as an intercept term in a linear model).', 'placeholder': True, 'title': 'Include Bias', 'type': 'boolean'}, 'order': {'description': "Order of output array in the dense case. 'F' order is faster to compute, but may slow down subsequent estimators.", 'enum': ['C', 'F'], 'placeholder': 'C', 'title': 'Order', 'type': 'string'}}, 'required': ['degree', 'interaction_only', 'include_bias', 'order'], 'title': 'PolynomialFeaturesSchema', 'type': 'object'}, 'metadata': None, 'description': 'Generate polynomial and interaction features.', 'display_name': None}, 'StandardScaler': {'name': 'StandardScaler', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'copy': {'description': 'If False, try to avoid a copy and do inplace scaling instead.', 'placeholder': True, 'title': 'Copy', 'type': 'boolean'}, 'with_mean': {'description': 'If True, center the data before scaling.', 'placeholder': True, 'title': 'With Mean', 'type': 'boolean'}, 'with_std': {'description': 'If True, scale the data to unit variance (or equivalently, unit standard deviation).', 'placeholder': True, 'title': 'With Std', 'type': 'boolean'}}, 'required': ['copy', 'with_mean', 'with_std'], 'title': 'StandardScalerSchema', 'type': 'object'}, 'metadata': None, 'description': 'Standardize features by removing the mean and scaling to unit variance.', 'display_name': None}, 'Embedding': {'name': 'Embedding', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'model_name': {'description': 'Name of the pre-trained model to use', 'enum': ['sentence-transformers/all-MiniLM-L6-v2', 'sentence-transformers/all-mpnet-base-v2', 'sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2', 'sentence-transformers/all-distilroberta-v1', 'bert-base-uncased', 'bert-large-uncased', 'bert-base-multilingual-cased', 'distilbert-base-uncased', 'roberta-base', 'roberta-large', 'distilroberta-base'], 'placeholder': 'sentence-transformers/all-MiniLM-L6-v2', 'title': 'Model Name', 'type': 'string'}, 'max_length': {'description': 'Maximum sequence length for tokenization', 'minimum': 1, 'placeholder': 512, 'title': 'Max Length', 'type': 'integer'}, 'batch_size': {'description': 'Number of samples to process at once', 'minimum': 1, 'placeholder': 32, 'title': 'Batch Size', 'type': 'integer'}, 'device': {'description': 'Device to use for computation', 'enum': ['cuda', 'cpu'], 'placeholder': 'cpu', 'title': 'Device', 'type': 'string'}, 'pooling_strategy': {'description': 'Strategy to pool token embeddings into sentence embedding', 'enum': ['mean', 'cls', 'max'], 'placeholder': 'mean', 'title': 'Pooling Strategy', 'type': 'string'}}, 'required': ['model_name', 'max_length', 'batch_size', 'device', 'pooling_strategy'], 'title': 'EmbeddingSchema', 'type': 'object'}, 'metadata': None, 'description': 'Convert text to embeddings using HuggingFace transformer models.', 'display_name': None}, 'VarianceThreshold': {'name': 'VarianceThreshold', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'threshold': {'description': 'Features with a variance lower than this threshold will be removed.', 'minimum': 0.0, 'placeholder': 0.0, 'title': 'Threshold', 'type': 'number'}}, 'required': ['threshold'], 'title': 'VarianceThresholdSchema', 'type': 'object'}, 'metadata': None, 'description': 'Feature selector that removes all low-variance features.', 'display_name': None}, 'SimpleImputer': {'name': 'SimpleImputer', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'missing_values': {'anyOf': [{'type': 'integer'}, {'type': 'number'}, {'type': 'string'}, {'type': 'null'}], 'description': 'The placeholder for the missing values.', 'placeholder': None, 'title': 'Missing Values'}, 'strategy': {'description': 'The imputation strategy.', 'enum': ['mean', 'median', 'most_frequent', 'constant'], 'placeholder': 'mean', 'title': 'Strategy', 'type': 'string'}, 'fill_value': {'anyOf': [{'type': 'integer'}, {'type': 'number'}, {'type': 'string'}, {'type': 'null'}], 'description': 'The value to replace missing values with.', 'placeholder': None, 'title': 'Fill Value'}, 'copy': {'description': 'If True, a copy of X will be created.', 'placeholder': True, 'title': 'Copy', 'type': 'boolean'}, 'add_indicator': {'description': 'If True, a MissingIndicator transform will stack onto output.', 'placeholder': False, 'title': 'Add Indicator', 'type': 'boolean'}, 'keep_empty_features': {'description': 'If True, empty features will be kept.', 'placeholder': False, 'title': 'Keep Empty Features', 'type': 'boolean'}}, 'required': ['missing_values', 'strategy', 'fill_value', 'copy', 'add_indicator', 'keep_empty_features'], 'title': 'SimpleImputerSchema', 'type': 'object'}, 'metadata': None, 'description': 'Univariate imputer for completing missing values with simple strategies.', 'display_name': None}, 'MissingIndicator': {'name': 'MissingIndicator', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'missing_values': {'anyOf': [{'type': 'integer'}, {'type': 'number'}, {'type': 'string'}, {'type': 'null'}], 'description': 'The placeholder for the missing values.', 'placeholder': None, 'title': 'Missing Values'}, 'features': {'description': 'The features to consider for missing values.', 'enum': ['missing-only', 'all'], 'placeholder': None, 'title': 'Features', 'type': 'string'}, 'error_on_new': {'description': 'Whether to raise an error on new missing values.', 'placeholder': True, 'title': 'Error On New', 'type': 'boolean'}}, 'required': ['missing_values', 'features', 'error_on_new'], 'title': 'MissingIndicatorSchema', 'type': 'object'}, 'metadata': None, 'description': 'Binary indicators for missing values.', 'display_name': None}, 'KNNImputer': {'name': 'KNNImputer', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'missing_values': {'anyOf': [{'type': 'integer'}, {'type': 'number'}, {'type': 'string'}, {'type': 'null'}], 'description': 'The placeholder for the missing values.', 'placeholder': None, 'title': 'Missing Values'}, 'n_neighbors': {'description': 'The number of nearest neighbors to use for imputation.', 'minimum': 1, 'placeholder': 5, 'title': 'N Neighbors', 'type': 'integer'}, 'weights': {'description': 'The weight function to use for imputation.', 'enum': ['uniform', 'distance'], 'placeholder': 'uniform', 'title': 'Weights', 'type': 'string'}, 'metric': {'description': 'The metric to use for imputation.', 'enum': ['nan_euclidean'], 'placeholder': 'nan_euclidean', 'title': 'Metric', 'type': 'string'}, 'copy': {'description': 'If True, a copy of X will be created.', 'placeholder': True, 'title': 'Copy', 'type': 'boolean'}, 'add_indicator': {'description': 'If True, a MissingIndicator transform will stack onto output.', 'placeholder': False, 'title': 'Add Indicator', 'type': 'boolean'}, 'keep_empty_features': {'description': 'If True, empty features will be kept.', 'placeholder': False, 'title': 'Keep Empty Features', 'type': 'boolean'}}, 'required': ['missing_values', 'n_neighbors', 'weights', 'metric', 'copy', 'add_indicator', 'keep_empty_features'], 'title': 'KNNImputerSchema', 'type': 'object'}, 'metadata': None, 'description': 'Imputation for completing missing values using k-Nearest Neighbors.', 'display_name': None}, 'AdditiveChi2Sampler': {'name': 'AdditiveChi2Sampler', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'sample_steps': {'description': 'The number of sample steps (shuffling) to perform.', 'minimum': 1, 'placeholder': 2, 'title': 'Sample Steps', 'type': 'integer'}, 'sample_interval': {'anyOf': [{'minimum': 1.0, 'type': 'number'}, {'type': 'null'}], 'description': 'The number of samples to generate between each original sample.', 'placeholder': None, 'title': 'Sample Interval'}}, 'required': ['sample_steps', 'sample_interval'], 'title': 'AdditiveChi2SamplerSchema', 'type': 'object'}, 'metadata': None, 'description': 'Uses sampling the fourier transform of the kernel characteristic at regular intervals.', 'display_name': None}, 'RBFSampler': {'name': 'RBFSampler', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'gamma': {'anyOf': [{'enum': ['scale'], 'type': 'string'}, {'exclusiveMinimum': 0.0, 'type': 'number'}], 'description': 'Parameter of the RBF kernel.', 'placeholder': 1.0, 'title': 'Gamma'}, 'n_components': {'description': 'The number of features to construct.', 'minimum': 1, 'placeholder': 100, 'title': 'N Components', 'type': 'integer'}, 'random_state': {'anyOf': [{'type': 'integer'}, {'enum': ['RandomState'], 'type': 'string'}, {'type': 'null'}], 'description': 'Pseudo-random number generator to control the generation of the random weights and random offset when fitting the training data. Pass an int for reproducible output across multiple function calls.', 'placeholder': None, 'title': 'Random State'}}, 'required': ['gamma', 'n_components', 'random_state'], 'title': 'RBFSamplerSchema', 'type': 'object'}, 'metadata': None, 'description': 'Approximates the feature map of an RBF kernel by Monte Carlo approximation of its Fourier transform.', 'display_name': None}, 'SkewedChi2Sampler': {'name': 'SkewedChi2Sampler', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'skewedness': {'description': 'The skewedness parameter of the chi-squared kernel.', 'exclusiveMinimum': 0.0, 'placeholder': 1.0, 'title': 'Skewedness', 'type': 'number'}, 'n_components': {'description': 'Number of Monte Carlo samples per original feature. Equals the dimensionality of the computed feature space.', 'minimum': 1, 'placeholder': 100, 'title': 'N Components', 'type': 'integer'}, 'random_state': {'anyOf': [{'type': 'integer'}, {'enum': ['RandomState'], 'type': 'string'}, {'type': 'null'}], 'description': 'Pseudo-random number generator to control the generation of the random weights and random offset when fitting the training data. Pass an int for reproducible output across multiple function calls.', 'placeholder': None, 'title': 'Random State'}}, 'required': ['skewedness', 'n_components', 'random_state'], 'title': 'SkewedChi2SamplerSchema', 'type': 'object'}, 'metadata': None, 'description': 'Approximates the feature map of a chi-squared kernel by Monte Carlo approximation of its Fourier transform.', 'display_name': None}, 'GenericUnivariateSelect': {'name': 'GenericUnivariateSelect', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'mode': {'description': 'Select features according to a percentile of the highest scores.', 'enum': ['percentile', 'k_best', 'fpr', 'fdr', 'fwe'], 'placeholder': 'percentile', 'title': 'Mode', 'type': 'string'}, 'param': {'anyOf': [{'enum': ['all'], 'type': 'string'}, {'type': 'number'}, {'type': 'integer'}, {'type': 'null'}], 'description': 'Parameter of the mode.', 'placeholder': 1e-05, 'title': 'Param'}}, 'required': ['mode', 'param'], 'title': 'GenericUnivariateSelectSchema', 'type': 'object'}, 'metadata': None, 'description': 'Univariate feature selector with configurable strategy.', 'display_name': None}, 'SelectPercentile': {'name': 'SelectPercentile', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'percentile': {'description': 'Percent of features to keep.', 'maximum': 100, 'minimum': 1, 'placeholder': 10, 'title': 'Percentile', 'type': 'integer'}}, 'required': ['percentile'], 'title': 'SelectPercentileSchema', 'type': 'object'}, 'metadata': None, 'description': 'Select features according to a percentile of the highest scores.', 'display_name': None}, 'SelectKBest': {'name': 'SelectKBest', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'k': {'anyOf': [{'enum': ['all'], 'type': 'string'}, {'minimum': 1, 'type': 'integer'}], 'description': 'Number of top features to select.', 'placeholder': 10, 'title': 'K'}}, 'required': ['k'], 'title': 'SelectKBestSchema', 'type': 'object'}, 'metadata': None, 'description': 'Select features according to the k highest scores.', 'display_name': None}, 'SelectFpr': {'name': 'SelectFpr', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'alpha': {'description': 'The highest p-value for features to be kept.', 'maximum': 1.0, 'minimum': 0.0, 'placeholder': 0.05, 'title': 'Alpha', 'type': 'number'}}, 'required': ['alpha'], 'title': 'SelectFprSchema', 'type': 'object'}, 'metadata': None, 'description': 'Filter: Select features according to a false positive rate test.', 'display_name': None}, 'SelectFdr': {'name': 'SelectFdr', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'alpha': {'description': 'The highest uncorrected p-value for features to be kept.', 'maximum': 1.0, 'minimum': 0.0, 'placeholder': 0.05, 'title': 'Alpha', 'type': 'number'}}, 'required': ['alpha'], 'title': 'SelectFdrSchema', 'type': 'object'}, 'metadata': None, 'description': 'Filter: Select features according to a false discovery rate test.', 'display_name': None}, 'SelectFwe': {'name': 'SelectFwe', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'alpha': {'description': 'The highest uncorrected p-value for features to be kept.', 'maximum': 1.0, 'minimum': 0.0, 'placeholder': 0.05, 'title': 'Alpha', 'type': 'number'}}, 'required': ['alpha'], 'title': 'SelectFweSchema', 'type': 'object'}, 'metadata': None, 'description': 'Filter: Select features according to a family-wise error rate test.', 'display_name': None}, 'Nystroem': {'name': 'Nystroem', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'kernel': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'description': 'The kernel to use for the approximation.', 'placeholder': 'rbf', 'title': 'Kernel'}, 'gamma': {'anyOf': [{'exclusiveMinimum': 0.0, 'type': 'number'}, {'type': 'null'}], 'description': 'The gamma parameter for the RBF, laplacian, polynomial, exponential chi2 and sigmoid kernels.', 'placeholder': None, 'title': 'Gamma'}, 'coef0': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'description': 'The coef0 parameter for the polynomial and sigmoid kernels.', 'placeholder': None, 'title': 'Coef0'}, 'degree': {'anyOf': [{'minimum': 1.0, 'type': 'number'}, {'type': 'null'}], 'description': 'The degree of the polynomial kernel.', 'placeholder': None, 'title': 'Degree'}, 'kernel_params': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'description': 'Additional parameters (keyword arguments) for the kernel function.', 'placeholder': None, 'title': 'Kernel Params'}, 'n_components': {'description': 'The number of features to construct.', 'minimum': 1, 'placeholder': 100, 'title': 'N Components', 'type': 'integer'}, 'random_state': {'anyOf': [{'type': 'integer'}, {'enum': ['RandomState'], 'type': 'string'}, {'type': 'null'}], 'description': 'The seed of the pseudo random number generator to use when shuffling the data.', 'placeholder': None, 'title': 'Random State'}, 'n_jobs': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'description': 'Number of parallel jobs to run.', 'placeholder': None, 'title': 'N Jobs'}}, 'required': ['kernel', 'gamma', 'coef0', 'degree', 'kernel_params', 'n_components', 'random_state', 'n_jobs'], 'title': 'NystroemSchema', 'type': 'object'}, 'metadata': None, 'description': 'Approximates the feature map of an RBF kernel by Monte Carlo approximation of its Fourier transform.', 'display_name': None}, 'SMOTEConverter': {'name': 'SMOTEConverter', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'sampling_strategy': {'anyOf': [{'exclusiveMinimum': 0.0, 'maximum': 1.0, 'type': 'number'}, {'enum': ['auto'], 'type': 'string'}], 'description': "Sampling strategy (float or 'auto') to determine minority class size.", 'placeholder': 'auto', 'title': 'Sampling Strategy'}, 'random_state': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'description': 'Seed for reproducibility.', 'placeholder': None, 'title': 'Random State'}, 'k_neighbors': {'description': 'Number of neighbors to use for generating synthetic samples.', 'minimum': 1, 'placeholder': 5, 'title': 'K Neighbors', 'type': 'integer'}}, 'required': ['sampling_strategy', 'random_state', 'k_neighbors'], 'title': 'SMOTESchema', 'type': 'object'}, 'metadata': None, 'description': 'SMOTE: Synthetic Minority Over-sampling Technique.', 'display_name': None}, 'SMOTEENNConverter': {'name': 'SMOTEENNConverter', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'sampling_strategy': {'anyOf': [{'exclusiveMinimum': 0.0, 'maximum': 1.0, 'type': 'number'}, {'enum': ['auto'], 'type': 'string'}], 'description': 'Sampling strategy to apply SMOTE and clean the dataset.', 'placeholder': 'auto', 'title': 'Sampling Strategy'}, 'random_state': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'description': 'Seed used for reproducibility.', 'placeholder': None, 'title': 'Random State'}, 'k_neighbors': {'description': 'Number of neighbors used by SMOTE.', 'minimum': 1, 'placeholder': 5, 'title': 'K Neighbors', 'type': 'integer'}}, 'required': ['sampling_strategy', 'random_state', 'k_neighbors'], 'title': 'SMOTEENNSchema', 'type': 'object'}, 'metadata': None, 'description': 'SMOTEENN: SMOTE with noise reduction via Edited Nearest Neighbors.', 'display_name': None}, 'RandomUnderSamplerConverter': {'name': 'RandomUnderSamplerConverter', 'type': 'Converter', 'class': , 'configurable_object': True, 'schema': {'properties': {'sampling_strategy': {'anyOf': [{'exclusiveMinimum': 0.0, 'maximum': 1.0, 'type': 'number'}, {'enum': ['auto'], 'type': 'string'}], 'description': "Sampling strategy (float or 'auto') to reduce majority class.", 'placeholder': 'auto', 'title': 'Sampling Strategy'}, 'random_state': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'description': 'Seed for reproducibility.', 'placeholder': None, 'title': 'Random State'}}, 'required': ['sampling_strategy', 'random_state'], 'title': 'RUSchema', 'type': 'object'}, 'metadata': None, 'description': 'Randomly remove samples from the majority class to balance the dataset.', 'display_name': None}}} \ No newline at end of file diff --git a/component_registry__foromatted.json b/component_registry__foromatted.json new file mode 100644 index 000000000..89716b10b --- /dev/null +++ b/component_registry__foromatted.json @@ -0,0 +1,6053 @@ +{ + "Task": { + "TabularClassificationTask": { + "name": "TabularClassificationTask", + "type": "Task", + "class": "DashAI.back.tasks.tabular_classification_task.TabularClassificationTask", + "configurable_object": false, + "schema": "None", + "metadata": { + "inputs_types": [ + "ClassLabel", + "Value" + ], + "outputs_types": [ + "ClassLabel" + ], + "inputs_cardinality": "n", + "outputs_cardinality": 1 + }, + "description": "\n Tabular classification in machine learning involves predicting categorical\n labels for structured data organized in tabular form (rows and columns).\n Models are trained to learn patterns and relationships in the data, enabling\n accurate classification of new instances.", + "display_name": "None" + }, + "TextClassificationTask": { + "name": "TextClassificationTask", + "type": "Task", + "class": "DashAI.back.tasks.text_classification_task.TextClassificationTask", + "configurable_object": false, + "schema": "None", + "metadata": { + "inputs_types": [ + "Value" + ], + "outputs_types": [ + "ClassLabel" + ], + "inputs_cardinality": 1, + "outputs_cardinality": 1 + }, + "description": "\n Text classification is an essential Natural Language Processing (NLP) task that\n involves automatically assigning pre-defined categories or labels to text documents\n based on their content. It serves as the foundation for applications like sentiment\n analysis, spam filtering, topic classification, and document categorization.\n ", + "display_name": "None" + }, + "TranslationTask": { + "name": "TranslationTask", + "type": "Task", + "class": "DashAI.back.tasks.translation_task.TranslationTask", + "configurable_object": false, + "schema": "None", + "metadata": { + "inputs_types": [ + "Value", + "Sequence" + ], + "outputs_types": [ + "Value", + "Sequence" + ], + "inputs_cardinality": 1, + "outputs_cardinality": 1 + }, + "description": "\n The translation task is natural language processing (NLP) task that involves\n converting text or speech from one language into another language while\n preserving the meaning and context.\n ", + "display_name": "None" + }, + "ImageClassificationTask": { + "name": "ImageClassificationTask", + "type": "Task", + "class": "DashAI.back.tasks.image_classification_task.ImageClassificationTask", + "configurable_object": false, + "schema": "None", + "metadata": { + "inputs_types": [ + "Image" + ], + "outputs_types": [ + "ClassLabel" + ], + "inputs_cardinality": 1, + "outputs_cardinality": 1 + }, + "description": "None", + "display_name": "None" + }, + "RegressionTask": { + "name": "RegressionTask", + "type": "Task", + "class": "DashAI.back.tasks.regression_task.RegressionTask", + "configurable_object": false, + "schema": "None", + "metadata": { + "inputs_types": [ + "Value" + ], + "outputs_types": [ + "Value" + ], + "inputs_cardinality": "n", + "outputs_cardinality": 1 + }, + "description": "\n Regression in machine learning involves predicting continuous values for\n structured data organized in tabular form (rows and columns).\n Models are trained to learn patterns and relationships in the data,\n enabling accurate prediction of new instances.", + "display_name": "None" + } + }, + "GenerativeTask": { + "TextToImageGenerationTask": { + "name": "TextToImageGenerationTask", + "type": "GenerativeTask", + "class": "DashAI.back.tasks.text_to_image_generation_task.TextToImageGenerationTask", + "configurable_object": false, + "schema": "None", + "metadata": { + "inputs_types": [ + "str" + ], + "outputs_types": [ + "Image" + ], + "inputs_cardinality": 1, + "outputs_cardinality": "n" + }, + "description": "This task generates images based on the provided input text.", + "display_name": "Text to Image Generation" + }, + "TextToTextGenerationTask": { + "name": "TextToTextGenerationTask", + "type": "GenerativeTask", + "class": "DashAI.back.tasks.text_to_text_generation_task.TextToTextGenerationTask", + "configurable_object": false, + "schema": "None", + "metadata": { + "inputs_types": [ + "str" + ], + "outputs_types": [ + "str" + ], + "inputs_cardinality": 1, + "outputs_cardinality": 1 + }, + "description": "This task uses a large language model (LLM) to generate text from a given prompt.", + "display_name": "Text to Text Generation" + }, + "ControlNetTask": { + "name": "ControlNetTask", + "type": "GenerativeTask", + "class": "DashAI.back.tasks.controlnet_task.ControlNetTask", + "configurable_object": false, + "schema": "None", + "metadata": { + "inputs_types": [ + "Image", + "str" + ], + "outputs_types": [ + "Image" + ], + "inputs_cardinality": 2, + "outputs_cardinality": "n" + }, + "description": "This task generates images based on the provided input text and image.", + "display_name": "ControlNet" + }, + "RAGTask": { + "name": "RAGTask", + "type": "GenerativeTask", + "class": "DashAI.back.tasks.RAG_task.RAGTask", + "configurable_object": false, + "schema": "None", + "metadata": { + "inputs_types": [ + "str" + ], + "outputs_types": [ + "str" + ], + "inputs_cardinality": 1, + "outputs_cardinality": 1 + }, + "description": "This task generates a text response based on documents provided and chat.", + "display_name": "Retreival-Augmented Generation (RAG) Task" + } + }, + "Model": { + "SVC": { + "name": "SVC", + "type": "Model", + "class": "DashAI.back.models.scikit_learn.svc.SVC", + "configurable_object": true, + "schema": { + "description": "Support Vector Machine (SVM) is a machine learning algorithm that separates data\ninto different classes by finding the optimal hyperplane", + "properties": { + "C": { + "description": "The parameter 'C' is a regularization parameter. It must be of type positive number.", + "placeholder": { + "fixed_value": 1, + "lower_bound": 1, + "optimize": false, + "upper_bound": 10 + }, + "title": "C", + "type": "object" + }, + "coef0": { + "description": "The 'coef0' parameter is a kernel independent value. It is only significant for kernel poly and sigmoid. It must be of type number.", + "placeholder": { + "fixed_value": 1, + "lower_bound": 1, + "optimize": false, + "upper_bound": 10 + }, + "title": "Coef0", + "type": "object" + }, + "degree": { + "description": "The parameter 'degree' is the degree of the polynomial for the kernel = 'poly'. It must be of type number.", + "placeholder": { + "fixed_value": 1, + "lower_bound": 1, + "optimize": false, + "upper_bound": 10 + }, + "title": "Degree", + "type": "object" + }, + "gamma": { + "description": "Coefficient for 'rbf', 'poly' and 'sigmoid' kernels. Must be in string format and can be scale or auto.", + "enum": [ + "scale", + "auto" + ], + "placeholder": "scale", + "title": "Gamma", + "type": "string" + }, + "kernel": { + "description": "The 'kernel' parameter is the kernel used in the model. It must be a string equal to 'linear', 'poly', 'rbf' or 'sigmoid'.", + "enum": [ + "linear", + "poly", + "rbf", + "sigmoid" + ], + "placeholder": "rbf", + "title": "Kernel", + "type": "string" + }, + "max_iter": { + "description": "The 'max_iter' parameter determines the iteration limit for the solver. It must be of type positive integer or -1 to indicate no limit.", + "placeholder": { + "fixed_value": -1, + "lower_bound": 1, + "optimize": false, + "upper_bound": 10 + }, + "title": "Max Iter", + "type": "object" + }, + "probability": { + "description": "The parameter 'probability' indicates whether or not to predict with probabilities. It must be of type boolean.", + "placeholder": true, + "title": "Probability", + "type": "boolean" + }, + "shrinking": { + "description": "The 'shrinking' parameter determines whether a shrinking heristic is used. It must be of type boolean.", + "placeholder": true, + "title": "Shrinking", + "type": "boolean" + }, + "tol": { + "description": "The parameter 'tol' determines the tolerance for the stop criterion. It must be of type positive number.", + "placeholder": { + "fixed_value": 1, + "lower_bound": 1, + "optimize": false, + "upper_bound": 10 + }, + "title": "Tol", + "type": "object" + }, + "verbose": { + "description": "The 'verbose' parameter allows to have a verbose output.It must be of type boolean.", + "placeholder": false, + "title": "Verbose", + "type": "boolean" + } + }, + "required": [ + "C", + "coef0", + "degree", + "gamma", + "kernel", + "max_iter", + "probability", + "shrinking", + "tol", + "verbose" + ], + "title": "SVCSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "DecisionTreeClassifier": { + "name": "DecisionTreeClassifier", + "type": "Model", + "class": "DashAI.back.models.scikit_learn.decision_tree_classifier.DecisionTreeClassifier", + "configurable_object": true, + "schema": { + "description": "Decision Trees are a set of are a non-parametric supervised learning method that\nlearns simple decision rules (structured as a tree) inferred from the data features.", + "properties": { + "criterion": { + "description": "The function to measure the quality of a split. Supported criteria are �gini� for the Gini impurity and �log_loss� and �entropy� both for the Shannon information gain.", + "enum": [ + "entropy", + "gini", + "log_loss" + ], + "placeholder": "entropy", + "title": "Criterion", + "type": "string" + }, + "max_depth": { + "description": "The maximum depth of the tree. If 'None', then nodes are expanded until all leaves are pure or until all leaves contain less than min_samples_split samples.", + "placeholder": { + "fixed_value": 1, + "lower_bound": 1, + "optimize": false, + "upper_bound": 10 + }, + "title": "Max Depth", + "type": "object" + }, + "min_samples_split": { + "description": "The minimum number of samples required to split an internal node.", + "placeholder": { + "fixed_value": 1, + "lower_bound": 1, + "optimize": false, + "upper_bound": 5 + }, + "title": "Min Samples Split", + "type": "object" + }, + "min_samples_leaf": { + "description": "The minimum number of samples required to be at a leaf node.", + "placeholder": { + "fixed_value": 1, + "lower_bound": 1, + "optimize": false, + "upper_bound": 5 + }, + "title": "Min Samples Leaf", + "type": "object" + }, + "max_features": { + "description": "The number of features to consider when looking for the best split.", + "enum": [ + "auto", + "sqrt", + "log2" + ], + "placeholder": "None", + "title": "Max Features", + "type": "string" + } + }, + "required": [ + "criterion", + "max_depth", + "min_samples_split", + "min_samples_leaf", + "max_features" + ], + "title": "DecisionTreeClassifierSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "DummyClassifier": { + "name": "DummyClassifier", + "type": "Model", + "class": "DashAI.back.models.scikit_learn.dummy_classifier.DummyClassifier", + "configurable_object": true, + "schema": { + "description": "DummyClassifier makes predictions that ignore the input features.", + "properties": { + "strategy": { + "description": "Strategy to use to generate predictions.", + "enum": [ + "most_frequent", + "prior", + "stratified", + "uniform" + ], + "placeholder": "prior", + "title": "Strategy", + "type": "string" + } + }, + "required": [ + "strategy" + ], + "title": "DummyClassifierSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "GradientBoostingR": { + "name": "GradientBoostingR", + "type": "Model", + "class": "DashAI.back.models.scikit_learn.gradient_boosting_regression.GradientBoostingR", + "configurable_object": true, + "schema": { + "description": "Gradient Boosting for regression.", + "properties": { + "loss": { + "description": "Loss function to be optimized.", + "enum": [ + "squared_error", + "absolute_error", + "huber", + "quantile" + ], + "placeholder": "squared_error", + "title": "Loss", + "type": "string" + }, + "learning_rate": { + "description": "Learning rate shrinks the contribution of each tree.", + "placeholder": { + "fixed_value": 0.1, + "lower_bound": 0.01, + "optimize": false, + "upper_bound": 1 + }, + "title": "Learning Rate", + "type": "object" + }, + "n_estimators": { + "description": "The number of boosting stages to be run.", + "placeholder": { + "fixed_value": 100, + "lower_bound": 10, + "optimize": false, + "upper_bound": 1000 + }, + "title": "N Estimators", + "type": "object" + }, + "subsample": { + "description": "The fraction of samples to be used for fitting the individual base learners.", + "placeholder": { + "fixed_value": 1, + "lower_bound": 0.1, + "optimize": false, + "upper_bound": 1 + }, + "title": "Subsample", + "type": "object" + }, + "criterion": { + "description": "The function to measure the quality of a split.", + "enum": [ + "friedman_mse", + "mse", + "mae" + ], + "placeholder": "friedman_mse", + "title": "Criterion", + "type": "string" + }, + "min_samples_split": { + "description": "The minimum number of samples required to split an internal node.", + "placeholder": { + "fixed_value": 2, + "lower_bound": 2, + "optimize": false, + "upper_bound": 20 + }, + "title": "Min Samples Split", + "type": "object" + }, + "min_samples_leaf": { + "description": "The minimum number of samples required to be at a leaf node.", + "placeholder": { + "fixed_value": 1, + "lower_bound": 1, + "optimize": false, + "upper_bound": 20 + }, + "title": "Min Samples Leaf", + "type": "object" + }, + "min_weight_fraction_leaf": { + "description": "The minimum weighted fraction of the sum total of weights (of all the input samples) required to be at a leaf node.", + "placeholder": { + "fixed_value": 0, + "lower_bound": 0, + "optimize": false, + "upper_bound": 0.5 + }, + "title": "Min Weight Fraction Leaf", + "type": "object" + }, + "max_depth": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The maximum depth of the individual regression estimators.", + "placeholder": 3, + "title": "Max Depth" + }, + "min_impurity_decrease": { + "description": "A node will be split if this split induces a decrease of the impurity greater than or equal to this value.", + "placeholder": { + "fixed_value": 0, + "lower_bound": 0, + "optimize": false, + "upper_bound": 0.5 + }, + "title": "Min Impurity Decrease", + "type": "object" + }, + "random_state": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The seed of the pseudo-random number generator to use when shuffling the data.", + "placeholder": "None", + "title": "Random State" + }, + "max_features": { + "anyOf": [ + { + "type": "object" + }, + { + "enum": [ + "sqrt", + "log2", + "None" + ], + "type": "string" + } + ], + "description": "The number of features to consider when looking for the best split.", + "placeholder": "None", + "title": "Max Features" + }, + "alpha": { + "description": "The alpha-quantile of the Huber loss function and the quantile loss function.", + "placeholder": { + "fixed_value": 0.9, + "lower_bound": 0.1, + "optimize": false, + "upper_bound": 1 + }, + "title": "Alpha", + "type": "object" + }, + "verbose": { + "description": "Enable verbose output.", + "placeholder": { + "fixed_value": 0, + "lower_bound": 0, + "optimize": false, + "upper_bound": 100 + }, + "title": "Verbose", + "type": "object" + }, + "max_leaf_nodes": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Grow trees with max_leaf_nodes in best-first fashion.", + "placeholder": "None", + "title": "Max Leaf Nodes" + }, + "warm_start": { + "description": "When set to true, reuse the solution of the previous callto fit and add more estimators to the ensemble.", + "placeholder": false, + "title": "Warm Start", + "type": "boolean" + }, + "validation_fraction": { + "description": "The proportion of training data to set aside as validation set for early stopping.", + "placeholder": { + "fixed_value": 0.1, + "lower_bound": 0.1, + "optimize": false, + "upper_bound": 0.5 + }, + "title": "Validation Fraction", + "type": "object" + }, + "n_iter_no_change": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The number of iterations with no improvement to wait before stopping the training.", + "placeholder": "None", + "title": "N Iter No Change" + }, + "tol": { + "description": "Tolerance for the early stopping.", + "placeholder": { + "fixed_value": 0.0001, + "lower_bound": 0.00001, + "optimize": false, + "upper_bound": 0.1 + }, + "title": "Tol", + "type": "object" + }, + "ccp_alpha": { + "description": "Complexity parameter used for Minimal Cost-Complexity Pruning.", + "placeholder": { + "fixed_value": 0, + "lower_bound": 0, + "optimize": false, + "upper_bound": 1 + }, + "title": "Ccp Alpha", + "type": "object" + } + }, + "required": [ + "loss", + "learning_rate", + "n_estimators", + "subsample", + "criterion", + "min_samples_split", + "min_samples_leaf", + "min_weight_fraction_leaf", + "max_depth", + "min_impurity_decrease", + "random_state", + "max_features", + "alpha", + "verbose", + "max_leaf_nodes", + "warm_start", + "validation_fraction", + "n_iter_no_change", + "tol", + "ccp_alpha" + ], + "title": "GradientBoostingRSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "HistGradientBoostingClassifier": { + "name": "HistGradientBoostingClassifier", + "type": "Model", + "class": "DashAI.back.models.scikit_learn.hist_gradient_boosting_classifier.HistGradientBoostingClassifier", + "configurable_object": true, + "schema": { + "description": "A gradient boosting classifier is a machine learning algorithm that combines\nmultiple weak prediction models (typically decision trees) to create a strong\npredictive model by training the models sequentially, in which each new model is\nfocused on correcting the errors made by the previous ones.", + "properties": { + "learning_rate": { + "description": "The learning rate, also known as shrinkage. This is used as a multiplicative factor for the leaves values. Use 1 for no shrinkage.", + "placeholder": { + "fixed_value": 0.1, + "lower_bound": 0.1, + "optimize": false, + "upper_bound": 1 + }, + "title": "Learning Rate", + "type": "object" + }, + "max_iter": { + "description": "The maximum number of iterations of the boosting process, i.e. the maximum number of trees for binary classification.", + "placeholder": { + "fixed_value": 100, + "lower_bound": 100, + "optimize": false, + "upper_bound": 250 + }, + "title": "Max Iter", + "type": "object" + }, + "max_depth": { + "description": "The maximum depth of each tree. The depth of a tree is the number of edges to go from the root to the deepest leaf. Depth isn�t constrained by default.", + "placeholder": { + "fixed_value": 1, + "lower_bound": 1, + "optimize": false, + "upper_bound": 10 + }, + "title": "Max Depth", + "type": "object" + }, + "max_leaf_nodes": { + "description": "The maximum number of leaves for each tree. Must be strictly greater than 1. If 'None', there is no maximum limit.", + "placeholder": { + "fixed_value": 31, + "lower_bound": 10, + "optimize": false, + "upper_bound": 40 + }, + "title": "Max Leaf Nodes", + "type": "object" + }, + "min_samples_leaf": { + "description": "The minimum number of samples required to be at a leaf node.", + "placeholder": { + "fixed_value": 20, + "lower_bound": 2, + "optimize": false, + "upper_bound": 25 + }, + "title": "Min Samples Leaf", + "type": "object" + }, + "l2_regularization": { + "description": "The L2 regularization parameter. Use 0 for no regularization.", + "placeholder": { + "fixed_value": 0, + "lower_bound": 0, + "optimize": false, + "upper_bound": 1 + }, + "title": "L2 Regularization", + "type": "object" + } + }, + "required": [ + "learning_rate", + "max_iter", + "max_depth", + "max_leaf_nodes", + "min_samples_leaf", + "l2_regularization" + ], + "title": "HistGradientBoostingClassifierSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "KNeighborsClassifier": { + "name": "KNeighborsClassifier", + "type": "Model", + "class": "DashAI.back.models.scikit_learn.k_neighbors_classifier.KNeighborsClassifier", + "configurable_object": true, + "schema": { + "description": "KNN is a supervised classification method that determines the probability of\nan element belonging to a certain class by considering its k closest neighbors.", + "properties": { + "n_neighbors": { + "description": "The 'n_neighbors' parameter is the number of neighbors to consider in each input for classification. It must be an integer greater than or equal to 1.", + "placeholder": { + "fixed_value": 5, + "lower_bound": 5, + "optimize": false, + "upper_bound": 10 + }, + "title": "N Neighbors", + "type": "object" + }, + "weights": { + "description": "The 'weights' parameter must be 'uniform' or 'distance'.", + "enum": [ + "uniform", + "distance" + ], + "placeholder": "uniform", + "title": "Weights", + "type": "string" + }, + "algorithm": { + "description": "The 'algorithm' parameter must be 'auto', 'ball_tree', 'kd_tree', or 'brute'.", + "enum": [ + "auto", + "ball_tree", + "kd_tree", + "brute" + ], + "placeholder": "auto", + "title": "Algorithm", + "type": "string" + } + }, + "required": [ + "n_neighbors", + "weights", + "algorithm" + ], + "title": "KNeighborsClassifierSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "LogisticRegression": { + "name": "LogisticRegression", + "type": "Model", + "class": "DashAI.back.models.scikit_learn.logistic_regression.LogisticRegression", + "configurable_object": true, + "schema": { + "description": "Logistic Regression is a supervised classification method that uses a linear\nmodel plus a a logistic funcion to predict binary outcomes (it can be configured\nas multiclass via the one-vs-rest strategy).", + "properties": { + "penalty": { + "description": "Specify the norm of the penalty", + "enum": [ + "l2", + "l1", + "elasticnet" + ], + "placeholder": "l2", + "title": "Penalty", + "type": "string" + }, + "tol": { + "description": "Tolerance for stopping criteria.", + "placeholder": { + "fixed_value": 0.001, + "lower_bound": 0.001, + "optimize": false, + "upper_bound": 5 + }, + "title": "Tol", + "type": "object" + }, + "C": { + "description": "Inverse of regularization strength, smaller values specify stronger regularization. Must be a positive number.", + "placeholder": { + "fixed_value": 1, + "lower_bound": 1, + "optimize": false, + "upper_bound": 7 + }, + "title": "C", + "type": "object" + }, + "max_iter": { + "description": "Maximum number of iterations taken for the solvers to converge.", + "placeholder": { + "fixed_value": 100, + "lower_bound": 50, + "optimize": false, + "upper_bound": 250 + }, + "title": "Max Iter", + "type": "object" + } + }, + "required": [ + "penalty", + "tol", + "C", + "max_iter" + ], + "title": "LogisticRegressionSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "MLPRegression": { + "name": "MLPRegression", + "type": "Model", + "class": "DashAI.back.models.scikit_learn.mlp_regression.MLPRegression", + "configurable_object": true, + "schema": { + "description": "MLP Regressor for DashAI.", + "properties": { + "activation": { + "description": "Activation function for the hidden layer.", + "enum": [ + "identity", + "logistic", + "tanh", + "relu" + ], + "placeholder": "relu", + "title": "Activation", + "type": "string" + }, + "solver": { + "description": "The solver for weight optimization.", + "enum": [ + "lbfgs", + "sgd", + "adam" + ], + "placeholder": "adam", + "title": "Solver", + "type": "string" + }, + "alpha": { + "description": "L2 penalty (regularization term) parameter.", + "placeholder": { + "fixed_value": 0.0001, + "lower_bound": 0.000001, + "optimize": false, + "upper_bound": 0.1 + }, + "title": "Alpha", + "type": "object" + }, + "batch_size": { + "anyOf": [ + { + "type": "object" + }, + { + "enum": [ + "auto" + ], + "type": "string" + } + ], + "description": "Size of minibatches for stochastic optimizers.", + "placeholder": "auto", + "title": "Batch Size" + }, + "learning_rate": { + "description": "Learning rate schedule for weight updates.", + "enum": [ + "constant", + "invscaling", + "adaptive" + ], + "placeholder": "constant", + "title": "Learning Rate", + "type": "string" + }, + "learning_rate_init": { + "description": "The initial learning rate used.", + "placeholder": { + "fixed_value": 0.001, + "lower_bound": 0.00001, + "optimize": false, + "upper_bound": 0.1 + }, + "title": "Learning Rate Init", + "type": "object" + }, + "power_t": { + "description": "The exponent for inverse scaling learning rate.", + "placeholder": { + "fixed_value": 0.5, + "lower_bound": 0.1, + "optimize": false, + "upper_bound": 0.9 + }, + "title": "Power T", + "type": "object" + }, + "max_iter": { + "description": "Maximum number of iterations.", + "placeholder": { + "fixed_value": 200, + "lower_bound": 50, + "optimize": false, + "upper_bound": 1000 + }, + "title": "Max Iter", + "type": "object" + }, + "shuffle": { + "description": "Whether to shuffle samples in each iteration.", + "placeholder": true, + "title": "Shuffle", + "type": "boolean" + }, + "random_state": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The seed of the pseudo-random number generator to use when shuffling the data.", + "placeholder": "None", + "title": "Random State" + }, + "tol": { + "description": "Tolerance for the optimization.", + "placeholder": { + "fixed_value": 0.0001, + "lower_bound": 0.000001, + "optimize": false, + "upper_bound": 0.01 + }, + "title": "Tol", + "type": "object" + }, + "verbose": { + "description": "Whether to print progress messages to stdout.", + "placeholder": false, + "title": "Verbose", + "type": "boolean" + }, + "warm_start": { + "description": "When set to true, reuse the solution of the previous call to fit as initialization.", + "placeholder": false, + "title": "Warm Start", + "type": "boolean" + }, + "momentum": { + "description": "Momentum for gradient descent update.", + "placeholder": { + "fixed_value": 0.9, + "lower_bound": 0, + "optimize": false, + "upper_bound": 1 + }, + "title": "Momentum", + "type": "object" + }, + "nesterovs_momentum": { + "description": "Whether to use Nesterov�s momentum.", + "placeholder": true, + "title": "Nesterovs Momentum", + "type": "boolean" + }, + "early_stopping": { + "description": "Whether to use early stopping to terminate training when validation score is not improving.", + "placeholder": false, + "title": "Early Stopping", + "type": "boolean" + }, + "validation_fraction": { + "description": "The proportion of training data to set aside as validation set for early stopping.", + "placeholder": { + "fixed_value": 0.1, + "lower_bound": 0.1, + "optimize": false, + "upper_bound": 0.5 + }, + "title": "Validation Fraction", + "type": "object" + }, + "beta_1": { + "description": "Exponential decay rate for estimates of first moment vector in Adam optimizer.", + "placeholder": { + "fixed_value": 0.9, + "lower_bound": 0.1, + "optimize": false, + "upper_bound": 0.999 + }, + "title": "Beta 1", + "type": "object" + }, + "beta_2": { + "description": "Exponential decay rate for estimates of second moment vector in Adam optimizer.", + "placeholder": { + "fixed_value": 0.999, + "lower_bound": 0.1, + "optimize": false, + "upper_bound": 0.999 + }, + "title": "Beta 2", + "type": "object" + }, + "epsilon": { + "description": "Value for numerical stability in Adam optimizer.", + "placeholder": { + "fixed_value": 1e-8, + "lower_bound": 1e-10, + "optimize": false, + "upper_bound": 0.000001 + }, + "title": "Epsilon", + "type": "object" + }, + "n_iter_no_change": { + "description": "Maximum number of epochs to not meet tol improvement.", + "placeholder": { + "fixed_value": 10, + "lower_bound": 1, + "optimize": false, + "upper_bound": 50 + }, + "title": "N Iter No Change", + "type": "object" + }, + "max_fun": { + "description": "Maximum number of loss function calls. Only used if solver='lbfgs'.", + "placeholder": { + "fixed_value": 15000, + "lower_bound": 1000, + "optimize": false, + "upper_bound": 20000 + }, + "title": "Max Fun", + "type": "object" + } + }, + "required": [ + "activation", + "solver", + "alpha", + "batch_size", + "learning_rate", + "learning_rate_init", + "power_t", + "max_iter", + "shuffle", + "random_state", + "tol", + "verbose", + "warm_start", + "momentum", + "nesterovs_momentum", + "early_stopping", + "validation_fraction", + "beta_1", + "beta_2", + "epsilon", + "n_iter_no_change", + "max_fun" + ], + "title": "MLPRegressorSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "RandomForestClassifier": { + "name": "RandomForestClassifier", + "type": "Model", + "class": "DashAI.back.models.scikit_learn.random_forest_classifier.RandomForestClassifier", + "configurable_object": true, + "schema": { + "description": "Random Forest (RF) is an ensemble machine learning algorithm that achieves\nenhanced performance by combining multiple decision trees and aggregating their\noutputs.", + "properties": { + "n_estimators": { + "description": "The 'n_estimators' parameter corresponds to the number of decision trees. It must be an integer greater than or equal to 1.", + "placeholder": { + "fixed_value": 100, + "lower_bound": 50, + "optimize": false, + "upper_bound": 200 + }, + "title": "N Estimators", + "type": "object" + }, + "max_depth": { + "description": "The 'max_depth' parameter corresponds to the maximum depth of the tree. It must be an integer greater than or equal to 1.", + "placeholder": { + "fixed_value": 2, + "lower_bound": 2, + "optimize": false, + "upper_bound": 10 + }, + "title": "Max Depth", + "type": "object" + }, + "min_samples_split": { + "description": "The 'min_samples_split' parameter is the minimum number of samples required to split an internal node. It must be a number greater than or equal to 2.", + "placeholder": { + "fixed_value": 2, + "lower_bound": 2, + "optimize": false, + "upper_bound": 10 + }, + "title": "Min Samples Split", + "type": "object" + }, + "min_samples_leaf": { + "description": "The 'min_samples_leaf' parameter is the minimum number of samples required to be at a leaf node. It must be a number greater than or equal to 1.", + "placeholder": { + "fixed_value": 1, + "lower_bound": 1, + "optimize": false, + "upper_bound": 10 + }, + "title": "Min Samples Leaf", + "type": "object" + }, + "max_leaf_nodes": { + "description": "The 'max_leaf_nodes' parameter must be an integer greater than or equal to 2.", + "placeholder": { + "fixed_value": 2, + "lower_bound": 2, + "optimize": false, + "upper_bound": 10 + }, + "title": "Max Leaf Nodes", + "type": "object" + }, + "random_state": { + "description": "The 'random_state' parameter must be an integer greater than or equal to 0.", + "placeholder": { + "fixed_value": 0, + "lower_bound": 0, + "optimize": false, + "upper_bound": 10 + }, + "title": "Random State", + "type": "object" + } + }, + "required": [ + "n_estimators", + "max_depth", + "min_samples_split", + "min_samples_leaf", + "max_leaf_nodes", + "random_state" + ], + "title": "RandomForestClassifierSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "RandomForestRegression": { + "name": "RandomForestRegression", + "type": "Model", + "class": "DashAI.back.models.scikit_learn.random_forest_regression.RandomForestRegression", + "configurable_object": true, + "schema": { + "description": "Random Forest Regressor for DashAI.", + "properties": { + "n_estimators": { + "description": "The number of trees in the forest.", + "placeholder": { + "fixed_value": 100, + "lower_bound": 10, + "optimize": false, + "upper_bound": 1000 + }, + "title": "N Estimators", + "type": "object" + }, + "criterion": { + "description": "The function to measure the quality of a split.", + "enum": [ + "squared_error", + "absolute_error", + "poisson" + ], + "placeholder": "squared_error", + "title": "Criterion", + "type": "string" + }, + "max_depth": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The maximum depth of the tree.", + "placeholder": "None", + "title": "Max Depth" + }, + "min_samples_split": { + "description": "The minimum number of samples required to split an internal node.", + "placeholder": { + "fixed_value": 2, + "lower_bound": 2, + "optimize": false, + "upper_bound": 20 + }, + "title": "Min Samples Split", + "type": "object" + }, + "min_samples_leaf": { + "description": "The minimum number of samples required to be at a leaf node.", + "placeholder": { + "fixed_value": 1, + "lower_bound": 1, + "optimize": false, + "upper_bound": 20 + }, + "title": "Min Samples Leaf", + "type": "object" + }, + "min_weight_fraction_leaf": { + "description": "The minimum weighted fraction of the sum total of weights required to be at a leaf node.", + "placeholder": { + "fixed_value": 0, + "lower_bound": 0, + "optimize": false, + "upper_bound": 0.5 + }, + "title": "Min Weight Fraction Leaf", + "type": "object" + }, + "max_features": { + "anyOf": [ + { + "type": "object" + }, + { + "enum": [ + "auto", + "sqrt", + "log2", + "None" + ], + "type": "string" + } + ], + "description": "The number of features to consider when looking for the best split.", + "placeholder": "sqrt", + "title": "Max Features" + }, + "max_leaf_nodes": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Grow trees with max_leaf_nodes in best-first fashion.", + "placeholder": "None", + "title": "Max Leaf Nodes" + }, + "min_impurity_decrease": { + "description": "A node will be split if this split induces a decrease of the impurity greater than or equal to this value.", + "placeholder": { + "fixed_value": 0, + "lower_bound": 0, + "optimize": false, + "upper_bound": 0.5 + }, + "title": "Min Impurity Decrease", + "type": "object" + }, + "bootstrap": { + "description": "Whether bootstrap samples are used when building trees.", + "placeholder": true, + "title": "Bootstrap", + "type": "boolean" + }, + "oob_score": { + "description": "Whether to use out-of-bag samples to estimate the generalization score.", + "placeholder": false, + "title": "Oob Score", + "type": "boolean" + }, + "n_jobs": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The number of jobs to run in parallel for both fit and predict.", + "placeholder": "None", + "title": "N Jobs" + }, + "random_state": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The seed of the pseudo-random number generator to use when shuffling the data.", + "placeholder": "None", + "title": "Random State" + }, + "verbose": { + "description": "Controls the verbosity when fitting and predicting.", + "placeholder": { + "fixed_value": 0, + "lower_bound": 0, + "optimize": false, + "upper_bound": 100 + }, + "title": "Verbose", + "type": "object" + }, + "warm_start": { + "description": "When set to true, reuse the solution of the previous call to fit and add more estimators to the ensemble.", + "placeholder": false, + "title": "Warm Start", + "type": "boolean" + }, + "ccp_alpha": { + "description": "Complexity parameter used for Minimal Cost-Complexity Pruning.", + "placeholder": { + "fixed_value": 0, + "lower_bound": 0, + "optimize": false, + "upper_bound": 1 + }, + "title": "Ccp Alpha", + "type": "object" + }, + "max_samples": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "If bootstrap is true, the number of samples to draw from X to train each base estimator.", + "placeholder": "None", + "title": "Max Samples" + } + }, + "required": [ + "n_estimators", + "criterion", + "max_depth", + "min_samples_split", + "min_samples_leaf", + "min_weight_fraction_leaf", + "max_features", + "max_leaf_nodes", + "min_impurity_decrease", + "bootstrap", + "oob_score", + "n_jobs", + "random_state", + "verbose", + "warm_start", + "ccp_alpha", + "max_samples" + ], + "title": "RandomForestRegressionSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "DistilBertTransformer": { + "name": "DistilBertTransformer", + "type": "Model", + "class": "DashAI.back.models.hugging_face.distilbert_transformer.DistilBertTransformer", + "configurable_object": true, + "schema": { + "description": "Distilbert is a transformer that allows you to classify text in English.\nThe implementation is based on huggingface distilbert-base in the case of\nthe uncased model, i.e. distilbert-base-uncased.", + "properties": { + "num_train_epochs": { + "description": "Total number of training epochs to perform.", + "minimum": 1, + "placeholder": 1, + "title": "Num Train Epochs", + "type": "integer" + }, + "batch_size": { + "description": "The batch size per GPU/TPU core/CPU for training", + "minimum": 1, + "placeholder": 16, + "title": "Batch Size", + "type": "integer" + }, + "learning_rate": { + "description": "The initial learning rate for AdamW optimizer", + "minimum": 0, + "placeholder": 0.00003, + "title": "Learning Rate", + "type": "number" + }, + "device": { + "description": "Hardware on which the training is run. If available, GPU is recommended for efficiency reasons. Otherwise, use CPU.", + "enum": [ + "gpu", + "cpu" + ], + "placeholder": "gpu", + "title": "Device", + "type": "string" + }, + "weight_decay": { + "description": "Weight decay is a regularization technique used in training neural networks to prevent overfitting. In the context of the AdamW optimizer, the 'weight_decay' parameter is the rate at which the weights of all layers are reduced during training, provided that this rate is not zero.", + "minimum": 0, + "placeholder": 0.01, + "title": "Weight Decay", + "type": "number" + } + }, + "required": [ + "num_train_epochs", + "batch_size", + "learning_rate", + "device", + "weight_decay" + ], + "title": "DistilBertTransformerSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "OpusMtEnESTransformer": { + "name": "OpusMtEnESTransformer", + "type": "Model", + "class": "DashAI.back.models.hugging_face.opus_mt_en_es_transformer.OpusMtEnESTransformer", + "configurable_object": true, + "schema": { + "description": "opus-mt-en-es is a transformer pre-trained model that allows translation of\ntexts from English to Spanish.", + "properties": { + "num_train_epochs": { + "description": "Total number of training epochs to perform.", + "minimum": 1, + "placeholder": 1, + "title": "Num Train Epochs", + "type": "integer" + }, + "batch_size": { + "description": "The batch size per GPU/TPU core/CPU for training", + "minimum": 1, + "placeholder": 4, + "title": "Batch Size", + "type": "integer" + }, + "learning_rate": { + "description": "The initial learning rate for AdamW optimizer", + "minimum": 0, + "placeholder": 0.00002, + "title": "Learning Rate", + "type": "number" + }, + "device": { + "description": "Hardware on which the training is run. If available, GPU is recommended for efficiency reasons. Otherwise, use CPU.", + "enum": [ + "gpu", + "cpu" + ], + "placeholder": "gpu", + "title": "Device", + "type": "string" + }, + "weight_decay": { + "description": "Weight decay is a regularization technique used in training neural networks to prevent overfitting. In the context of the AdamW optimizer, the 'weight_decay' parameter is the rate at which the weights of all layers are reduced during training, provided that this rate is not zero.", + "minimum": 0, + "placeholder": 0.01, + "title": "Weight Decay", + "type": "number" + } + }, + "required": [ + "num_train_epochs", + "batch_size", + "learning_rate", + "device", + "weight_decay" + ], + "title": "OpusMtEnESTransformerSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "BagOfWordsTextClassificationModel": { + "name": "BagOfWordsTextClassificationModel", + "type": "Model", + "class": "DashAI.back.models.scikit_learn.bow_text_classification_model.BagOfWordsTextClassificationModel", + "configurable_object": true, + "schema": { + "description": "NumericalWrapperForText is a metamodel that allows text classification using\ntabular classifiers and a tokenizer.", + "properties": { + "tabular_classifier": { + "description": "Tabular model used as the underlying model to generate the text classifier.", + "parent": "TabularClassificationModel", + "placeholder": { + "component": "SVC", + "params": {} + }, + "properties": { + "component": { + "title": "Component", + "type": "string" + }, + "params": { + "title": "Params", + "type": "object" + } + }, + "required": [ + "component", + "params" + ], + "title": "Tabular Classifier", + "type": "object" + }, + "ngram_min_n": { + "description": "The lower boundary of the range of n-values for different word n-grams or char n-grams to be extracted. It must be an integer greater or equal than 1", + "minimum": 1, + "placeholder": 1, + "title": "Ngram Min N", + "type": "integer" + }, + "ngram_max_n": { + "description": "The upper boundary of the range of n-values for different word n-grams or char n-grams to be extracted. It must be an integer greater or equal than 1", + "minimum": 1, + "placeholder": 1, + "title": "Ngram Max N", + "type": "integer" + } + }, + "required": [ + "tabular_classifier", + "ngram_min_n", + "ngram_max_n" + ], + "title": "BagOfWordsTextClassificationModelSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "RidgeRegression": { + "name": "RidgeRegression", + "type": "Model", + "class": "DashAI.back.models.scikit_learn.ridge_regression.RidgeRegression", + "configurable_object": true, + "schema": { + "description": "Ridge regression is a linear model that includes L2 regularization.", + "properties": { + "alpha": { + "description": "Regularization strength; must be a positive float. Larger values specify stronger regularization.", + "placeholder": { + "fixed_value": 1, + "lower_bound": 0.1, + "optimize": false, + "upper_bound": 10 + }, + "title": "Alpha", + "type": "object" + }, + "fit_intercept": { + "description": "Whether to calculate the intercept for this model. If set to false, no intercept will be used in calculations (e.g., data is expected to be centered).", + "placeholder": true, + "title": "Fit Intercept", + "type": "boolean" + }, + "copy_X": { + "description": "If true, X will be copied; else, it may be overwritten.", + "placeholder": true, + "title": "Copy X", + "type": "boolean" + }, + "max_iter": { + "description": "Maximum number of iterations for conjugate gradient solver.", + "placeholder": { + "fixed_value": 1000, + "lower_bound": 100, + "optimize": false, + "upper_bound": 10000 + }, + "title": "Max Iter", + "type": "object" + }, + "tol": { + "description": "Precision of the solution.", + "placeholder": { + "fixed_value": 0.001, + "lower_bound": 0.00001, + "optimize": false, + "upper_bound": 0.1 + }, + "title": "Tol", + "type": "object" + }, + "solver": { + "description": "Solver to use in the computation. �auto� chooses the solver automatically based on the type of data.", + "enum": [ + "auto", + "svd", + "cholesky", + "lsqr", + "sparse_cg", + "sag", + "saga" + ], + "placeholder": "auto", + "title": "Solver", + "type": "string" + }, + "positive": { + "description": "When set to true, forces the coefficients to be positive.", + "placeholder": false, + "title": "Positive", + "type": "boolean" + }, + "random_state": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The seed of the pseudo random number generator to use when shuffling the data. Pass an int for reproducible output across multiple function calls, or 'None' to not set a specific seed.", + "placeholder": "None", + "title": "Random State" + } + }, + "required": [ + "alpha", + "fit_intercept", + "copy_X", + "max_iter", + "tol", + "solver", + "positive", + "random_state" + ], + "title": "RidgeRegressionSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "LinearSVR": { + "name": "LinearSVR", + "type": "Model", + "class": "DashAI.back.models.scikit_learn.linearSVR.LinearSVR", + "configurable_object": true, + "schema": { + "description": "Support Vector Regression (SVR) using a linear kernel.", + "properties": { + "epsilon": { + "description": "Epsilon parameter that specifies the epsilon-tube within which no penalty is associated.", + "placeholder": { + "fixed_value": 0, + "lower_bound": 0, + "optimize": false, + "upper_bound": 1 + }, + "title": "Epsilon", + "type": "object" + }, + "tol": { + "description": "Tolerance for stopping criterion.", + "placeholder": { + "fixed_value": 0.0001, + "lower_bound": 0.00001, + "optimize": false, + "upper_bound": 0.1 + }, + "title": "Tol", + "type": "object" + }, + "C": { + "description": "Regularization parameter. The strength of the regularization is inversely proportional to C.", + "placeholder": { + "fixed_value": 1, + "lower_bound": 0.1, + "optimize": false, + "upper_bound": 10 + }, + "title": "C", + "type": "object" + }, + "loss": { + "description": "Specifies the loss function. 'epsilon_insensitive' is the standard SVR loss.", + "enum": [ + "epsilon_insensitive", + "squared_epsilon_insensitive" + ], + "placeholder": "epsilon_insensitive", + "title": "Loss", + "type": "string" + }, + "fit_intercept": { + "description": "Whether to calculate the intercept for this model.", + "placeholder": true, + "title": "Fit Intercept", + "type": "boolean" + }, + "intercept_scaling": { + "description": "When fit_intercept is true, instance vector x becomes [x, self.intercept_scaling] in the primal problem.", + "placeholder": { + "fixed_value": 1, + "lower_bound": 0.1, + "optimize": false, + "upper_bound": 10 + }, + "title": "Intercept Scaling", + "type": "object" + }, + "dual": { + "description": "Select the algorithm to either solve the dual or primal optimization problem.", + "placeholder": true, + "title": "Dual", + "type": "boolean" + }, + "verbose": { + "description": "Enable verbose output. Note that this setting takes advantage of a per-process runtime setting in libsvm.", + "placeholder": { + "fixed_value": 0, + "lower_bound": 0, + "optimize": false, + "upper_bound": 100 + }, + "title": "Verbose", + "type": "object" + }, + "random_state": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The seed of the pseudo-random number generator to use when shuffling the data.", + "placeholder": "None", + "title": "Random State" + }, + "max_iter": { + "description": "The maximum number of iterations to be run.", + "placeholder": { + "fixed_value": 1000, + "lower_bound": 100, + "optimize": false, + "upper_bound": 10000 + }, + "title": "Max Iter", + "type": "object" + } + }, + "required": [ + "epsilon", + "tol", + "C", + "loss", + "fit_intercept", + "intercept_scaling", + "dual", + "verbose", + "random_state", + "max_iter" + ], + "title": "LinearSVRSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "LinearRegression": { + "name": "LinearRegression", + "type": "Model", + "class": "DashAI.back.models.scikit_learn.linear_regression.LinearRegression", + "configurable_object": true, + "schema": { + "description": "Linear regression model with optional intercept.", + "properties": { + "fit_intercept": { + "description": "Whether to calculate the intercept for this model. If set to false, no intercept will be used in calculations (e.g., data is expected to be centered).", + "placeholder": true, + "title": "Fit Intercept", + "type": "boolean" + }, + "copy_X": { + "description": "If true, X will be copied; else, it may be overwritten.", + "placeholder": true, + "title": "Copy X", + "type": "boolean" + }, + "n_jobs": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The number of jobs to use for the computation. 'None' means 1 job, while -1 means using all processors.", + "placeholder": "None", + "title": "N Jobs" + }, + "positive": { + "description": "When set to true, forces the coefficients to be positive.", + "placeholder": false, + "title": "Positive", + "type": "boolean" + } + }, + "required": [ + "fit_intercept", + "copy_X", + "n_jobs", + "positive" + ], + "title": "LinearRegressionSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "TFIDFRetriever": { + "name": "TFIDFRetriever", + "type": "Model", + "class": "DashAI.back.models.RAG.Retrievers.TFIDFRetriever.TFIDFRetriever", + "configurable_object": true, + "schema": { + "description": "Schema for the TFIDFRetriever.", + "properties": { + "similarity_function": { + "description": "Similarity function to use for document retrieval.", + "enum": [ + "cosine", + "euclidean" + ], + "placeholder": "cosine", + "title": "Similarity Function", + "type": "string" + }, + "n_docs": { + "description": "Number of documents to retrieve.", + "minimum": 1, + "placeholder": 5, + "title": "N Docs", + "type": "integer" + }, + "similarity_threshold": { + "description": "Maximum or minimum distance for retrieved documents based on the similarity_function.", + "placeholder": 0.5, + "title": "Similarity Threshold", + "type": "number" + }, + "chunk_size": { + "description": "Size of chunks to split the documents into.", + "minimum": 1, + "placeholder": 512, + "title": "Chunk Size", + "type": "integer" + }, + "chunk_overlap": { + "description": "Overlap between chunks when splitting documents.", + "minimum": 0, + "placeholder": 50, + "title": "Chunk Overlap", + "type": "integer" + } + }, + "required": [ + "similarity_function", + "n_docs", + "similarity_threshold", + "chunk_size", + "chunk_overlap" + ], + "title": "TFIDFRetrieverSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "DenseRetriever": { + "name": "DenseRetriever", + "type": "Model", + "class": "DashAI.back.models.RAG.Retrievers.DenseRetriever.DenseRetriever", + "configurable_object": true, + "schema": { + "description": "Schema for Dense Retriever.", + "properties": { + "encoding_model": { + "description": "Model to convert text into dense vector representations.", + "parent": "HuggingFaceWrapper", + "placeholder": { + "component": "Embedding", + "params": {} + }, + "properties": { + "component": { + "title": "Component", + "type": "string" + }, + "params": { + "title": "Params", + "type": "object" + } + }, + "required": [ + "component", + "params" + ], + "title": "Encoding Model", + "type": "object" + } + }, + "required": [ + "encoding_model" + ], + "title": "DenseRetrieverSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + } + }, + "GenerativeModel": { + "GemmaModel": { + "name": "GemmaModel", + "type": "GenerativeModel", + "class": "DashAI.back.models.hugging_face.gemma_model.GemmaModel", + "configurable_object": true, + "schema": { + "description": "Schema for Gemma model.", + "properties": { + "max_tokens": { + "description": "Maximum number of tokens to generate.", + "minimum": 1, + "placeholder": 100, + "title": "Max Tokens", + "type": "integer" + }, + "temperature": { + "description": "Sampling temperature. Higher values make the output more random, while lower values make it more focused and deterministic.", + "maximum": 1, + "minimum": 0, + "placeholder": 0.7, + "title": "Temperature", + "type": "number" + }, + "frequency_penalty": { + "description": "Penalty for repeated tokens in the output. Higher values reduce the likelihood of repetition, encouraging more diverse text generation.", + "maximum": 2, + "minimum": 0, + "placeholder": 0.1, + "title": "Frequency Penalty", + "type": "number" + }, + "context_window": { + "description": "Maximum number of tokens the model can process in a single forward pass (context window size).", + "minimum": 1, + "placeholder": 512, + "title": "Context Window", + "type": "integer" + }, + "device": { + "description": "The device to use for model inference.", + "enum": [ + "cpu" + ], + "placeholder": "cpu", + "title": "Device", + "type": "string" + } + }, + "required": [ + "max_tokens", + "temperature", + "frequency_penalty", + "context_window", + "device" + ], + "title": "GemmaSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "QwenModel": { + "name": "QwenModel", + "type": "GenerativeModel", + "class": "DashAI.back.models.hugging_face.qwen_model.QwenModel", + "configurable_object": true, + "schema": { + "description": "Schema for Qwen model.", + "properties": { + "model_name": { + "description": "The specific Qwen model version to use.", + "enum": [ + "Qwen/Qwen2.5-0.5B-Instruct-GGUF", + "Qwen/Qwen2.5-1.5B-Instruct-GGUF", + "Qwen/Qwen3-4B-GGUF " + ], + "placeholder": "Qwen/Qwen2.5-1.5B-Instruct-GGUF", + "title": "Model Name", + "type": "string" + }, + "max_tokens": { + "description": "Maximum number of tokens to generate.", + "minimum": 1, + "placeholder": 100, + "title": "Max Tokens", + "type": "integer" + }, + "temperature": { + "description": "Sampling temperature. Higher values make the output more random, while lower values make it more focused and deterministic.", + "maximum": 1, + "minimum": 0, + "placeholder": 0.7, + "title": "Temperature", + "type": "number" + }, + "frequency_penalty": { + "description": "Penalty for repeated tokens in the output. Higher values reduce the likelihood of repetition, encouraging more diverse text generation.", + "maximum": 2, + "minimum": 0, + "placeholder": 0.1, + "title": "Frequency Penalty", + "type": "number" + }, + "context_window": { + "description": "Maximum number of tokens the model can process in a single forward pass (context window size).", + "minimum": 1, + "placeholder": 512, + "title": "Context Window", + "type": "integer" + }, + "device": { + "description": "The device to use for model inference.", + "enum": [ + "cpu" + ], + "placeholder": "cpu", + "title": "Device", + "type": "string" + } + }, + "required": [ + "model_name", + "max_tokens", + "temperature", + "frequency_penalty", + "context_window", + "device" + ], + "title": "QwenSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "StableDiffusionV2Model": { + "name": "StableDiffusionV2Model", + "type": "GenerativeModel", + "class": "DashAI.back.models.hugging_face.stable_diffusion_v2_model.StableDiffusionV2Model", + "configurable_object": true, + "schema": { + "description": "Schema for Stable Diffusion V2 image generation.", + "properties": { + "model_name": { + "description": "The specific Stable Diffusion model version to use.", + "enum": [ + "stabilityai/stable-diffusion-2", + "stabilityai/stable-diffusion-2-base", + "stabilityai/stable-diffusion-2-1", + "stabilityai/stable-diffusion-2-1-base" + ], + "placeholder": "stabilityai/stable-diffusion-2", + "title": "Model Name", + "type": "string" + }, + "negative_prompt": { + "anyOf": [ + { + "description": "Text prompt for elements to avoid in the image.", + "placeholder": "", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Negative Prompt" + }, + "num_inference_steps": { + "description": "Number of denoising steps. Higher usually leads to better quality but slower inference.", + "minimum": 1, + "placeholder": 15, + "title": "Num Inference Steps", + "type": "integer" + }, + "guidance_scale": { + "description": "How strongly the model follows the prompt. Higher = closer to prompt, but may reduce image quality.", + "minimum": 0, + "placeholder": 3.5, + "title": "Guidance Scale", + "type": "number" + }, + "device": { + "description": "Device for generation. Use 'cuda' if GPU is available.", + "enum": [ + "cuda:0", + "cpu" + ], + "placeholder": "cuda:0", + "title": "Device", + "type": "string" + }, + "seed": { + "description": "Random seed for reproducibility. Use negative value for random seed.", + "placeholder": -1, + "title": "Seed", + "type": "integer" + }, + "width": { + "description": "Width of the generated image. Must be a multiple of 8.", + "maximum": 2048, + "minimum": 64, + "placeholder": 512, + "title": "Width", + "type": "integer" + }, + "height": { + "description": "Height of the generated image. Must be a multiple of 8.", + "maximum": 2048, + "minimum": 64, + "placeholder": 512, + "title": "Height", + "type": "integer" + }, + "num_images_per_prompt": { + "description": "Number of images to generate per prompt.", + "minimum": 1, + "placeholder": 1, + "title": "Num Images Per Prompt", + "type": "integer" + } + }, + "required": [ + "model_name", + "negative_prompt", + "num_inference_steps", + "guidance_scale", + "device", + "seed", + "width", + "height", + "num_images_per_prompt" + ], + "title": "StableDiffusionSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "StableDiffusionV3Model": { + "name": "StableDiffusionV3Model", + "type": "GenerativeModel", + "class": "DashAI.back.models.hugging_face.stable_diffusion_v3_model.StableDiffusionV3Model", + "configurable_object": true, + "schema": { + "description": "Schema for Stable Diffusion V3 image generation.", + "properties": { + "model_name": { + "description": "The specific Stable Diffusion model version to use.", + "enum": [ + "stabilityai/stable-diffusion-3-medium-diffusers", + "stabilityai/stable-diffusion-3-medium-tensorrt", + "stabilityai/stable-diffusion-3.5-medium", + "stabilityai/stable-diffusion-3.5-large", + "stabilityai/stable-diffusion-3.5-large-turbo" + ], + "placeholder": "stabilityai/stable-diffusion-3-medium-diffusers", + "title": "Model Name", + "type": "string" + }, + "negative_prompt": { + "anyOf": [ + { + "description": "Text prompt for elements to avoid in the image.", + "placeholder": "", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Negative Prompt" + }, + "num_inference_steps": { + "description": "Number of denoising steps. Higher usually leads to better quality but slower inference.", + "minimum": 1, + "placeholder": 15, + "title": "Num Inference Steps", + "type": "integer" + }, + "guidance_scale": { + "description": "How strongly the model follows the prompt. Higher = closer to prompt, but may reduce image quality.", + "minimum": 0, + "placeholder": 3.5, + "title": "Guidance Scale", + "type": "number" + }, + "device": { + "description": "Device for generation. Use 'cuda' if GPU is available.", + "enum": [ + "cuda:0", + "cpu" + ], + "placeholder": "cuda:0", + "title": "Device", + "type": "string" + }, + "seed": { + "description": "Random seed for reproducibility. Use negative value for random seed.", + "placeholder": -1, + "title": "Seed", + "type": "integer" + }, + "width": { + "description": "Width of the generated image. Must be a multiple of 8.", + "maximum": 2048, + "minimum": 64, + "placeholder": 512, + "title": "Width", + "type": "integer" + }, + "height": { + "description": "Height of the generated image. Must be a multiple of 8.", + "maximum": 2048, + "minimum": 64, + "placeholder": 512, + "title": "Height", + "type": "integer" + }, + "num_images_per_prompt": { + "description": "Number of images to generate per prompt.", + "minimum": 1, + "placeholder": 1, + "title": "Num Images Per Prompt", + "type": "integer" + } + }, + "required": [ + "model_name", + "negative_prompt", + "num_inference_steps", + "guidance_scale", + "device", + "seed", + "width", + "height", + "num_images_per_prompt" + ], + "title": "StableDiffusionSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "StableDiffusionXLV1ControlNet": { + "name": "StableDiffusionXLV1ControlNet", + "type": "GenerativeModel", + "class": "DashAI.back.models.hugging_face.stable_diffusion_v1_depth_controlnet.StableDiffusionXLV1ControlNet", + "configurable_object": true, + "schema": { + "properties": { + "num_inference_steps": { + "description": "Number of denoising steps. Higher usually leads to better quality but slower inference.", + "minimum": 1, + "placeholder": 15, + "title": "Num Inference Steps", + "type": "integer" + }, + "controlnet_conditioning_scale": { + "description": "Scale for the ControlNet conditioning. Higher values make the model follow the controlnet more closely.", + "minimum": 0, + "placeholder": 1, + "title": "Controlnet Conditioning Scale", + "type": "number" + }, + "device": { + "description": "Device for generation. Use 'cuda' if GPU is available.", + "enum": [ + "cuda:0", + "cpu" + ], + "placeholder": "cuda:0", + "title": "Device", + "type": "string" + } + }, + "required": [ + "num_inference_steps", + "controlnet_conditioning_scale", + "device" + ], + "title": "StableDiffusionXLV1ControlNetSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "RAGPipeline": { + "name": "RAGPipeline", + "type": "GenerativeModel", + "class": "DashAI.back.models.RAG.RAG_pipeline.RAGPipeline", + "configurable_object": true, + "schema": { + "description": "Schema for RAG pipeline.", + "properties": { + "documents": { + "description": "List of documents to be used in the RAG pipeline.", + "items": { + "type": "string" + }, + "minItems": 1, + "placeholder": "None", + "title": "Documents", + "type": "array" + }, + "retriever_model": { + "description": "Retriever component used in the RAG pipeline.", + "parent": "RetrieverModel", + "placeholder": { + "component": "TFIDFRetriever", + "params": {} + }, + "properties": { + "component": { + "title": "Component", + "type": "string" + }, + "params": { + "title": "Params", + "type": "object" + } + }, + "required": [ + "component", + "params" + ], + "title": "Retriever Model", + "type": "object" + }, + "generation_model": { + "description": "Text generation model used in the RAG pipeline.", + "parent": "TextToTextGenerationTaskModel", + "placeholder": { + "component": "DeepSeek", + "params": {} + }, + "properties": { + "component": { + "title": "Component", + "type": "string" + }, + "params": { + "title": "Params", + "type": "object" + } + }, + "required": [ + "component", + "params" + ], + "title": "Generation Model", + "type": "object" + } + }, + "required": [ + "documents", + "retriever_model", + "generation_model" + ], + "title": "RAGPipelineSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + } + }, + "DataLoader": { + "CSVDataLoader": { + "name": "CSVDataLoader", + "type": "DataLoader", + "class": "DashAI.back.dataloaders.classes.csv_dataloader.CSVDataLoader", + "configurable_object": true, + "schema": { + "properties": { + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Custom name to register your dataset. If no name is specified, the name of the uploaded file will be used.", + "placeholder": "", + "title": "Name" + }, + "separator": { + "description": "A separator character delimits the data in a CSV file.", + "enum": [ + ",", + ";", + " ", + "\t" + ], + "placeholder": ",", + "title": "Separator", + "type": "string" + } + }, + "required": [ + "name", + "separator" + ], + "title": "CSVDataloaderSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "JSONDataLoader": { + "name": "JSONDataLoader", + "type": "DataLoader", + "class": "DashAI.back.dataloaders.classes.json_dataloader.JSONDataLoader", + "configurable_object": true, + "schema": { + "properties": { + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Custom name to register your dataset. If no name is specified, the name of the uploaded file will be used.", + "placeholder": "", + "title": "Name" + }, + "data_key": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "\n In case the data has the form {�data�: [{�col1�: val1, �col2�: val2, ...]}}\n (also known as �table� in pandas), name of the field 'data',\n where the list with dictionaries with the data should be found.\n\n In case the format is only a list of dictionaries (also known as\n 'records' orient in pandas), set this value as null.\n ", + "placeholder": "data", + "title": "Data Key" + } + }, + "required": [ + "name", + "data_key" + ], + "title": "JSONDataloaderSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "ExcelDataLoader": { + "name": "ExcelDataLoader", + "type": "DataLoader", + "class": "DashAI.back.dataloaders.classes.excel_dataloader.ExcelDataLoader", + "configurable_object": true, + "schema": { + "properties": { + "name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Custom name to register your dataset. If no name is specified, the name of the uploaded file will be used.", + "placeholder": "", + "title": "Name" + }, + "sheet": { + "anyOf": [ + { + "minimum": 0, + "type": "integer" + }, + { + "type": "string" + } + ], + "description": "\n The name of the sheet to read or its zero-based index.\n If a string is provided, the reader will search for a sheet named exactly as\n the string.\n If an integer is provided, the reader will select the sheet at the corresponding\n index.\n By default, the first sheet will be read.\n ", + "placeholder": 0, + "title": "Sheet" + }, + "header": { + "anyOf": [ + { + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "\n The row number where the column names are located, indexed from 0.\n If null, the file will be considered to have no column names.\n ", + "placeholder": 0, + "title": "Header" + }, + "usecols": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "\n If 'None', the reader will load all columns.\n If str, then indicates comma separated list of Excel column letters and column\n ranges (e.g. �A:E� or �A,C,E:F�). Ranges are inclusive of both sides.\n ", + "placeholder": "None", + "title": "Usecols" + } + }, + "required": [ + "name", + "sheet", + "header", + "usecols" + ], + "title": "ExcelDataloaderSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + } + }, + "Metric": { + "F1": { + "name": "F1", + "type": "Metric", + "class": "DashAI.back.metrics.classification.f1.F1", + "configurable_object": false, + "schema": "None", + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "Accuracy": { + "name": "Accuracy", + "type": "Metric", + "class": "DashAI.back.metrics.classification.accuracy.Accuracy", + "configurable_object": false, + "schema": "None", + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "Precision": { + "name": "Precision", + "type": "Metric", + "class": "DashAI.back.metrics.classification.precision.Precision", + "configurable_object": false, + "schema": "None", + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "Recall": { + "name": "Recall", + "type": "Metric", + "class": "DashAI.back.metrics.classification.recall.Recall", + "configurable_object": false, + "schema": "None", + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "Bleu": { + "name": "Bleu", + "type": "Metric", + "class": "DashAI.back.metrics.translation.bleu.Bleu", + "configurable_object": false, + "schema": "None", + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "Ter": { + "name": "Ter", + "type": "Metric", + "class": "DashAI.back.metrics.translation.ter.Ter", + "configurable_object": false, + "schema": "None", + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "MAE": { + "name": "MAE", + "type": "Metric", + "class": "DashAI.back.metrics.regression.mae.MAE", + "configurable_object": false, + "schema": "None", + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "RMSE": { + "name": "RMSE", + "type": "Metric", + "class": "DashAI.back.metrics.regression.rmse.RMSE", + "configurable_object": false, + "schema": "None", + "metadata": "None", + "description": "None", + "display_name": "None" + } + }, + "Optimizer": { + "OptunaOptimizer": { + "name": "OptunaOptimizer", + "type": "Optimizer", + "class": "DashAI.back.optimizers.optuna_optimizer.OptunaOptimizer", + "configurable_object": true, + "schema": { + "properties": { + "n_trials": { + "description": "The parameter 'n_trials' is the quantity of trialsper study. It must be of type positive integer.", + "exclusiveMinimum": 0, + "placeholder": 10, + "title": "N Trials", + "type": "integer" + }, + "sampler": { + "description": "Coefficient for 'rbf', 'poly' and 'sigmoid' kernels. Must be in string format and can be 'scale' or 'auto'.", + "enum": [ + "TPESampler", + "CmaEsSampler", + "GridSampler", + "GPSampler", + "NSGAIISampler", + "QMCSampler", + "RandomSampler" + ], + "placeholder": "TPESampler", + "title": "Sampler", + "type": "string" + }, + "pruner": { + "description": "Coefficient for 'rbf', 'poly' and 'sigmoid' kernels. Must be in string format and can be 'scale' or 'auto'.", + "enum": [ + "MedianPruner", + "None" + ], + "placeholder": "None", + "title": "Pruner", + "type": "string" + } + }, + "required": [ + "n_trials", + "sampler", + "pruner" + ], + "title": "OptunaSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "HyperOptOptimizer": { + "name": "HyperOptOptimizer", + "type": "Optimizer", + "class": "DashAI.back.optimizers.hyperopt_optimizer.HyperOptOptimizer", + "configurable_object": true, + "schema": { + "properties": { + "n_trials": { + "description": "The parameter 'n_trials'is the quantity of trialsper study. It must be of type positive integer.", + "exclusiveMinimum": 0, + "placeholder": 10, + "title": "N Trials", + "type": "integer" + }, + "sampler": { + "description": "Coefficient for 'rbf', 'poly' and 'sigmoid' kernels. Must be in string format and can be 'scale' or 'auto'.", + "enum": [ + "tpe", + "rand" + ], + "placeholder": "tpe", + "title": "Sampler", + "type": "string" + } + }, + "required": [ + "n_trials", + "sampler" + ], + "title": "HyperOptSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + } + }, + "Job": { + "ExplainerJob": { + "name": "ExplainerJob", + "type": "Job", + "class": "DashAI.back.job.explainer_job.ExplainerJob", + "configurable_object": false, + "schema": "None", + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "ModelJob": { + "name": "ModelJob", + "type": "Job", + "class": "DashAI.back.job.model_job.ModelJob", + "configurable_object": false, + "schema": "None", + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "ExplorerJob": { + "name": "ExplorerJob", + "type": "Job", + "class": "DashAI.back.job.explorer_job.ExplorerJob", + "configurable_object": false, + "schema": "None", + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "PredictJob": { + "name": "PredictJob", + "type": "Job", + "class": "DashAI.back.job.predict_job.PredictJob", + "configurable_object": false, + "schema": "None", + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "ConverterListJob": { + "name": "ConverterListJob", + "type": "Job", + "class": "DashAI.back.job.converter_job.ConverterListJob", + "configurable_object": false, + "schema": "None", + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "DatasetJob": { + "name": "DatasetJob", + "type": "Job", + "class": "DashAI.back.job.dataset_job.DatasetJob", + "configurable_object": false, + "schema": "None", + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "GenerativeJob": { + "name": "GenerativeJob", + "type": "Job", + "class": "DashAI.back.job.generative_job.GenerativeJob", + "configurable_object": false, + "schema": "None", + "metadata": "None", + "description": "None", + "display_name": "None" + } + }, + "LocalExplainer": { + "KernelShap": { + "name": "KernelShap", + "type": "LocalExplainer", + "class": "DashAI.back.explainability.explainers.kernel_shap.KernelShap", + "configurable_object": true, + "schema": { + "description": "Kernel SHAP is a model-agnostic explainability method for approximating SHAP\nvalues to explain the output of machine learning model by attributing contributions\nof each feature to the model's prediction.", + "properties": { + "link": { + "description": "Link function to connect the feature importance values to the model's outputs. Options are 'identity' to use identity function or 'logit' to use log-odds function.", + "enum": [ + "identity", + "logit" + ], + "placeholder": "identity", + "title": "Link", + "type": "string" + }, + "fit_parameter_sample_background_data": { + "description": "Parameter to fit the explainer. 'true' if the background data must be sampled, otherwise the entire train data set is used. Smaller datasets speed up the algorithm run time.", + "placeholder": false, + "title": "Fit Parameter Sample Background Data", + "type": "boolean" + }, + "fit_parameter_n_background_samples": { + "description": "Parameter to fit the explainer. If the parameter 'sample_background_data' is 'true', the number of background data samples to be drawn.", + "minimum": 1, + "placeholder": 1, + "title": "Fit Parameter N Background Samples", + "type": "integer" + }, + "fit_parameter_sampling_method": { + "description": "Parameter to fit the explainer. If the parameter 'sample_background_data' is 'true', whether to sample random samples with 'shuffle' option or summarize the data set with 'kmeans' option. If 'categorical_features' is 'true', 'shuffle' options used by default.", + "enum": [ + "shuffle", + "kmeans" + ], + "placeholder": "shuffle", + "title": "Fit Parameter Sampling Method", + "type": "string" + } + }, + "required": [ + "link", + "fit_parameter_sample_background_data", + "fit_parameter_n_background_samples", + "fit_parameter_sampling_method" + ], + "title": "KernelShapSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + } + }, + "GlobalExplainer": { + "PartialDependence": { + "name": "PartialDependence", + "type": "GlobalExplainer", + "class": "DashAI.back.explainability.explainers.partial_dependence.PartialDependence", + "configurable_object": true, + "schema": { + "description": "PartialDependence of a feature shows the average prediction of a machine\nlearning model for each possible value of the feature.", + "properties": { + "grid_resolution": { + "description": "The number of equidistant points to split the range of the target feature", + "minimum": 1, + "placeholder": 100, + "title": "Grid Resolution", + "type": "integer" + }, + "lower_percentile": { + "description": "The lower percentile used to limit the feature values.", + "maximum": 0.99, + "minimum": 0, + "placeholder": 0.05, + "title": "Lower Percentile", + "type": "number" + }, + "upper_percentile": { + "description": "The upper percentile used to limit the feature values.", + "maximum": 1, + "minimum": 0.01, + "placeholder": 0.95, + "title": "Upper Percentile", + "type": "number" + } + }, + "required": [ + "grid_resolution", + "lower_percentile", + "upper_percentile" + ], + "title": "PartialDependenceSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + }, + "PermutationFeatureImportance": { + "name": "PermutationFeatureImportance", + "type": "GlobalExplainer", + "class": "DashAI.back.explainability.explainers.permutation_feature_importance.PermutationFeatureImportance", + "configurable_object": true, + "schema": { + "description": "Permutation Feature Importance is a explanation method to asses the\nimportance of each feature in a model by evaluating how much the model's\nperformance decreases when the values of a specific feature are randomly\nshuffled.", + "properties": { + "scoring": { + "description": "Scorer to evaluate how the perfomance of the model changes when a particular feature is shuffled.", + "enum": [ + "accuracy", + "balanced_accuracy" + ], + "placeholder": "accuracy", + "title": "Scoring", + "type": "string" + }, + "n_repeats": { + "description": "Number of times to permute a feature.", + "minimum": 1, + "placeholder": 10, + "title": "N Repeats", + "type": "integer" + }, + "random_state": { + "description": "Seed for the random number generator to control the permutations of each feature.", + "placeholder": 0, + "title": "Random State", + "type": "integer" + }, + "max_samples": { + "description": "The number of samples to draw from the dataset to calculate feature importance at each repetition.", + "minimum": 1, + "placeholder": 100, + "title": "Max Samples", + "type": "integer" + } + }, + "required": [ + "scoring", + "n_repeats", + "random_state", + "max_samples" + ], + "title": "PermutationFeatureImportanceSchema", + "type": "object" + }, + "metadata": "None", + "description": "None", + "display_name": "None" + } + }, + "Explorer": { + "DescribeExplorer": { + "name": "DescribeExplorer", + "type": "Explorer", + "class": "DashAI.back.exploration.explorers.describe_explorer.DescribeExplorer", + "configurable_object": true, + "schema": { + "properties": { + "percentiles": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The percentiles to include in the exploration. Must be a list of integers between 0 and 100.\nExample: '25, 50, 75'", + "placeholder": "25, 50, 75", + "title": "Percentiles" + }, + "include": { + "anyOf": [ + { + "enum": [ + "all", + "number", + "object", + "category", + "datetime" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The data types to include in the exploration.\n", + "placeholder": "all", + "title": "Include" + }, + "exclude": { + "anyOf": [ + { + "enum": [ + "object", + "number", + "category", + "datetime" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The data types to exclude in the exploration.", + "placeholder": "None", + "title": "Exclude" + } + }, + "required": [ + "percentiles", + "include", + "exclude" + ], + "title": "DescribeExplorerSchema", + "type": "object" + }, + "metadata": { + "allowed_dtypes": [ + "*" + ], + "restricted_dtypes": [], + "input_cardinality": { + "min": 1 + }, + "display_name": "Describe Dataset", + "allowed_value_types": [ + "*" + ], + "restricted_value_types": [] + }, + "description": "DescribeExplorer is an explorer that describes the dataset. It returns a tabular representation of the dataset with the count, mean, std, min, 25%, 50%, 75%, and max values for numeric columns and count, unique, top, and freq values for object columns.\nThe user can specify the percentiles to include in the exploration and the data types to include or exclude.", + "display_name": "Describe Dataset" + }, + "ScatterPlotExplorer": { + "name": "ScatterPlotExplorer", + "type": "Explorer", + "class": "DashAI.back.exploration.explorers.scatter_plot.ScatterPlotExplorer", + "configurable_object": true, + "schema": { + "properties": { + "color_group": { + "anyOf": [ + { + "type": "string" + }, + { + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The columnName or columnIndex to take for grouping colored points.", + "placeholder": "None", + "title": "Color Group" + }, + "simbol_group": { + "anyOf": [ + { + "type": "string" + }, + { + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The columnName or columnIndex to take for grouping simbol of the points.", + "placeholder": "None", + "title": "Simbol Group" + }, + "point_size": { + "anyOf": [ + { + "type": "string" + }, + { + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The columnName or columnIndex to take for size of each point.", + "placeholder": "None", + "title": "Point Size" + } + }, + "required": [ + "color_group", + "simbol_group", + "point_size" + ], + "title": "ScatterPlotSchema", + "type": "object" + }, + "metadata": { + "allowed_dtypes": [ + "*" + ], + "restricted_dtypes": [], + "input_cardinality": { + "exact": 2 + }, + "display_name": "Scatter Plot", + "allowed_value_types": [ + "*" + ], + "restricted_value_types": [] + }, + "description": "ScatterPlotExplorer is an explorer that returns a scatter plot of selected columns of a dataset.", + "display_name": "Scatter Plot" + }, + "WordcloudExplorer": { + "name": "WordcloudExplorer", + "type": "Explorer", + "class": "DashAI.back.exploration.explorers.wordcloud.WordcloudExplorer", + "configurable_object": true, + "schema": { + "properties": { + "max_words": { + "description": "The maximum number of words to display in the wordcloud.", + "exclusiveMinimum": 0, + "placeholder": 200, + "title": "Max Words", + "type": "integer" + }, + "background_color": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The background color of the wordcloud. If 'None', the background will be transparent.", + "placeholder": "None", + "title": "Background Color" + } + }, + "required": [ + "max_words", + "background_color" + ], + "title": "WordcloudSchema", + "type": "object" + }, + "metadata": { + "allowed_dtypes": [ + "string" + ], + "restricted_dtypes": [], + "input_cardinality": { + "min": 1 + }, + "display_name": "Word Cloud", + "allowed_value_types": [ + "*" + ], + "restricted_value_types": [] + }, + "description": "A wordcloud is a visual representation of text data, where the size of each word indicates its frequency in the text.\nThis explorer generates a wordcloud from the concatenated strings of all selected columns in the dataset.", + "display_name": "Word Cloud" + }, + "RowExplorer": { + "name": "RowExplorer", + "type": "Explorer", + "class": "DashAI.back.exploration.explorers.row_explorer.RowExplorer", + "configurable_object": true, + "schema": { + "properties": { + "row_ammount": { + "description": "The maximum number of rows to take.", + "exclusiveMinimum": 0, + "placeholder": 50, + "title": "Row Ammount", + "type": "integer" + }, + "shuffle": { + "description": "Shuffle the rows at exploration time.", + "placeholder": false, + "title": "Shuffle", + "type": "boolean" + }, + "from_top": { + "description": "Take the rows from the Head of the dataset. Else, take from the Tail.", + "placeholder": true, + "title": "From Top", + "type": "boolean" + } + }, + "required": [ + "row_ammount", + "shuffle", + "from_top" + ], + "title": "RowExplorerSchema", + "type": "object" + }, + "metadata": { + "allowed_dtypes": [ + "*" + ], + "restricted_dtypes": [], + "input_cardinality": { + "min": 1 + }, + "display_name": "Show Rows", + "allowed_value_types": [ + "*" + ], + "restricted_value_types": [] + }, + "description": "RowExplorer is an explorer that takes a number of rows from the dataset to display them on tabular format. It can take the rows from the top or the bottom of the dataset and shuffle them if needed.", + "display_name": "Show Rows" + }, + "BoxPlotExplorer": { + "name": "BoxPlotExplorer", + "type": "Explorer", + "class": "DashAI.back.exploration.explorers.box_plot.BoxPlotExplorer", + "configurable_object": true, + "schema": { + "properties": { + "horizontal": { + "description": "If true, the box plot will be horizontal, otherwise vertical.", + "placeholder": false, + "title": "Horizontal", + "type": "boolean" + }, + "points": { + "description": "One of 'all', 'outliers', or 'false'. Determines which points are shown.", + "enum": [ + "all", + "outliers", + "false" + ], + "placeholder": "outliers", + "title": "Points", + "type": "string" + } + }, + "required": [ + "horizontal", + "points" + ], + "title": "BoxPlotSchema", + "type": "object" + }, + "metadata": { + "allowed_dtypes": [ + "*" + ], + "restricted_dtypes": [], + "input_cardinality": { + "min": 1, + "max": 2 + }, + "display_name": "Box Plot", + "allowed_value_types": [ + "*" + ], + "restricted_value_types": [] + }, + "description": "BoxPlotExplorer is an explorer that returns a box plot of selected columns of a dataset.", + "display_name": "Box Plot" + }, + "MultiColumnBoxPlotExplorer": { + "name": "MultiColumnBoxPlotExplorer", + "type": "Explorer", + "class": "DashAI.back.exploration.explorers.multibox_plot.MultiColumnBoxPlotExplorer", + "configurable_object": true, + "schema": { + "properties": { + "horizontal": { + "description": "If true, the box plot will be horizontal, otherwise vertical.", + "placeholder": false, + "title": "Horizontal", + "type": "boolean" + }, + "points": { + "description": "One of 'all', 'outliers', or 'false'. Determines which points are shown.", + "enum": [ + "all", + "outliers", + "false" + ], + "placeholder": "outliers", + "title": "Points", + "type": "string" + }, + "opposite_axis": { + "anyOf": [ + { + "type": "string" + }, + { + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The columnName or columnIndex to take for the opposite axis.", + "placeholder": "None", + "title": "Opposite Axis" + } + }, + "required": [ + "horizontal", + "points", + "opposite_axis" + ], + "title": "MultiColumnBoxPlotSchema", + "type": "object" + }, + "metadata": { + "allowed_dtypes": [ + "*" + ], + "restricted_dtypes": [], + "input_cardinality": { + "min": 1 + }, + "display_name": "Multiple Column Box Plot", + "allowed_value_types": [ + "*" + ], + "restricted_value_types": [] + }, + "description": "MultiColumnBoxPlotExplorer is an explorer that returns a figure with a box plot of multiple columns of a dataset in a single axis. The other axis is selected through the opposite_axis parameter.", + "display_name": "Multiple Column Box Plot" + }, + "CorrelationMatrixExplorer": { + "name": "CorrelationMatrixExplorer", + "type": "Explorer", + "class": "DashAI.back.exploration.explorers.corr_matrix.CorrelationMatrixExplorer", + "configurable_object": true, + "schema": { + "properties": { + "method": { + "description": "The correlation method to use. Must be one of 'pearson', 'kendall', or 'spearman'.", + "enum": [ + "pearson", + "kendall", + "spearman" + ], + "placeholder": "pearson", + "title": "Method", + "type": "string" + }, + "min_periods": { + "description": "The minimum number of observations required per pair of columns to have a valid result. Only used if method is 'pearson' or 'spearman'.", + "exclusiveMinimum": 0, + "placeholder": 1, + "title": "Min Periods", + "type": "integer" + }, + "numeric_only": { + "description": "If true, only include numeric columns when calculating correlation.If false, all columns are included.", + "placeholder": true, + "title": "Numeric Only", + "type": "boolean" + }, + "plot": { + "description": "If true, the result will be plotted.", + "placeholder": true, + "title": "Plot", + "type": "boolean" + } + }, + "required": [ + "method", + "min_periods", + "numeric_only", + "plot" + ], + "title": "CorrelationMatrixExplorerSchema", + "type": "object" + }, + "metadata": { + "allowed_dtypes": [ + "*" + ], + "restricted_dtypes": [], + "input_cardinality": { + "min": 2 + }, + "display_name": "Correlation Matrix", + "allowed_value_types": [ + "*" + ], + "restricted_value_types": [] + }, + "description": "CorrelationMatrixExplorer is an explorer that returns a correlation matrix of a dataset.\nIts result is a heatmap by default, but can also be returned as a tabular result.", + "display_name": "Correlation Matrix" + }, + "CovarianceMatrixExplorer": { + "name": "CovarianceMatrixExplorer", + "type": "Explorer", + "class": "DashAI.back.exploration.explorers.cov_matrix.CovarianceMatrixExplorer", + "configurable_object": true, + "schema": { + "properties": { + "min_periods": { + "description": "The minimum number of observations required per pair of columns to have a valid result.", + "exclusiveMinimum": 0, + "placeholder": 1, + "title": "Min Periods", + "type": "integer" + }, + "delta_degree_of_freedom": { + "description": "The delta degree of freedom to use when calculating the covariance matrix.Only used if numeric_only is true.", + "exclusiveMinimum": 0, + "placeholder": 1, + "title": "Delta Degree Of Freedom", + "type": "integer" + }, + "numeric_only": { + "description": "If true, only include numeric columns when calculating correlation.If false, all columns are included.", + "placeholder": true, + "title": "Numeric Only", + "type": "boolean" + }, + "plot": { + "description": "If true, the result will be plotted.", + "placeholder": true, + "title": "Plot", + "type": "boolean" + } + }, + "required": [ + "min_periods", + "delta_degree_of_freedom", + "numeric_only", + "plot" + ], + "title": "CovarianceMatrixExplorerSchema", + "type": "object" + }, + "metadata": { + "allowed_dtypes": [ + "*" + ], + "restricted_dtypes": [], + "input_cardinality": { + "min": 2 + }, + "display_name": "Covariance Matrix", + "allowed_value_types": [ + "*" + ], + "restricted_value_types": [] + }, + "description": "CovarianceExplorer is an explorer that returns the covariance matrix of the dataset.\nIts result is a heatmap by default, but can also be returned as a tabular result.", + "display_name": "Covariance Matrix" + }, + "DensityHeatmapExplorer": { + "name": "DensityHeatmapExplorer", + "type": "Explorer", + "class": "DashAI.back.exploration.explorers.density_heatmap.DensityHeatmapExplorer", + "configurable_object": true, + "schema": { + "properties": { + "nbinsx": { + "anyOf": [ + { + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The number of bins along the x axis.", + "placeholder": "None", + "title": "Nbinsx" + }, + "nbinsy": { + "anyOf": [ + { + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The number of bins along the y axis.", + "placeholder": "None", + "title": "Nbinsy" + } + }, + "required": [ + "nbinsx", + "nbinsy" + ], + "title": "DensityHeatmapSchema", + "type": "object" + }, + "metadata": { + "allowed_dtypes": [ + "*" + ], + "restricted_dtypes": [], + "input_cardinality": { + "exact": 2 + }, + "display_name": "Density Heatmap", + "allowed_value_types": [ + "*" + ], + "restricted_value_types": [] + }, + "description": "DensityHeatmapExplorer is an explorer that returns a density heatmap of selected columns of a dataset.", + "display_name": "Density Heatmap" + }, + "ECDFPlotExplorer": { + "name": "ECDFPlotExplorer", + "type": "Explorer", + "class": "DashAI.back.exploration.explorers.ecdf_plot.ECDFPlotExplorer", + "configurable_object": true, + "schema": { + "properties": { + "color_column": { + "anyOf": [ + { + "type": "string" + }, + { + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The column to use for coloring the ECDF plot.", + "placeholder": "None", + "title": "Color Column" + }, + "facet_col": { + "anyOf": [ + { + "type": "string" + }, + { + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The column to use for faceting the ECDF plot in the column direction.", + "placeholder": "None", + "title": "Facet Col" + }, + "facet_row": { + "anyOf": [ + { + "type": "string" + }, + { + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The column to use for faceting the ECDF plot in the row direction.", + "placeholder": "None", + "title": "Facet Row" + }, + "ecdf_norm": { + "description": "Specifies the type of normalization used for this ECDF plot.", + "enum": [ + "None", + "percent", + "probability" + ], + "placeholder": "probability", + "title": "Ecdf Norm", + "type": "string" + } + }, + "required": [ + "color_column", + "facet_col", + "facet_row", + "ecdf_norm" + ], + "title": "ECDFPlotSchema", + "type": "object" + }, + "metadata": { + "allowed_dtypes": [ + "float64", + "float32" + ], + "restricted_dtypes": [], + "input_cardinality": { + "min": 1 + }, + "display_name": "Empirical Cumulative Distribution Plot", + "allowed_value_types": [ + "*" + ], + "restricted_value_types": [] + }, + "description": "The ECDF plot is a non-parametric way to explore the distribution of a variable. It shows the proportion or count of observations falling below each unique value in the dataset.", + "display_name": "Empirical Cumulative Distribution Plot" + }, + "HistogramPlotExplorer": { + "name": "HistogramPlotExplorer", + "type": "Explorer", + "class": "DashAI.back.exploration.explorers.histogram_plot.HistogramPlotExplorer", + "configurable_object": true, + "schema": { + "properties": { + "nbins": { + "anyOf": [ + { + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The number of bins to use for the histogram.", + "placeholder": "None", + "title": "Nbins" + }, + "histfunc": { + "description": "Specifies the binning function used for this histogram trace.", + "enum": [ + "count", + "sum", + "avg", + "min", + "max" + ], + "placeholder": "count", + "title": "Histfunc", + "type": "string" + }, + "histnorm": { + "description": "Specifies the type of normalization used for this histogram trace.", + "enum": [ + "", + "percent", + "probability", + "density", + "probability density" + ], + "placeholder": "", + "title": "Histnorm", + "type": "string" + }, + "color_group": { + "anyOf": [ + { + "type": "string" + }, + { + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The columnName or columnIndex to take for grouping colored points.", + "placeholder": "None", + "title": "Color Group" + }, + "pattern_group": { + "anyOf": [ + { + "type": "string" + }, + { + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The columnName or columnIndex to take for grouping pattern of the points.", + "placeholder": "None", + "title": "Pattern Group" + } + }, + "required": [ + "nbins", + "histfunc", + "histnorm", + "color_group", + "pattern_group" + ], + "title": "HistogramPlotSchema", + "type": "object" + }, + "metadata": { + "allowed_dtypes": [ + "*" + ], + "restricted_dtypes": [], + "input_cardinality": { + "exact": 1 + }, + "display_name": "Histogram Plot", + "allowed_value_types": [ + "*" + ], + "restricted_value_types": [] + }, + "description": "HistogramPlotExplorer is an explorer that returns a density heatmap of a selected column of a dataset.", + "display_name": "Histogram Plot" + }, + "ScatterMatrixExplorer": { + "name": "ScatterMatrixExplorer", + "type": "Explorer", + "class": "DashAI.back.exploration.explorers.scatter_matrix.ScatterMatrixExplorer", + "configurable_object": true, + "schema": { + "properties": { + "color_group": { + "anyOf": [ + { + "type": "string" + }, + { + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The columnName or columnIndex to take for grouping colored points.", + "placeholder": "None", + "title": "Color Group" + }, + "simbol_group": { + "anyOf": [ + { + "type": "string" + }, + { + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The columnName or columnIndex to take for grouping simbol of the points.", + "placeholder": "None", + "title": "Simbol Group" + } + }, + "required": [ + "color_group", + "simbol_group" + ], + "title": "ScatterMatrixSchema", + "type": "object" + }, + "metadata": { + "allowed_dtypes": [ + "*" + ], + "restricted_dtypes": [], + "input_cardinality": { + "min": 2 + }, + "display_name": "Multiple Scatter Plot", + "allowed_value_types": [ + "*" + ], + "restricted_value_types": [] + }, + "description": "ScatterMatrixExplorer is an explorer that returns a scatter matrix plot of selected columns of a dataset. Multiple scatter plots are generated for each pair of columns. The diagonal plots are histograms of the columns. ", + "display_name": "Multiple Scatter Plot" + }, + "ParallelCategoriesExplorer": { + "name": "ParallelCategoriesExplorer", + "type": "Explorer", + "class": "DashAI.back.exploration.explorers.parallel_categories.ParallelCategoriesExplorer", + "configurable_object": true, + "schema": { + "properties": { + "color_column": { + "anyOf": [ + { + "type": "string" + }, + { + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The column to use for coloring the data points. ", + "placeholder": "None", + "title": "Color Column" + } + }, + "required": [ + "color_column" + ], + "title": "ParallelCategoriesSchema", + "type": "object" + }, + "metadata": { + "allowed_dtypes": [ + "string" + ], + "restricted_dtypes": [], + "input_cardinality": { + "min": 2 + }, + "display_name": "Parallel Categories Plot", + "allowed_value_types": [ + "*" + ], + "restricted_value_types": [] + }, + "description": "A parallel categories plot is a common way to visualize high-dimensional data. Each vertical line represents one data point, and the lines are connected by a series of horizontal lines. ", + "display_name": "Parallel Categories Plot" + }, + "ParallelCordinatesExplorer": { + "name": "ParallelCordinatesExplorer", + "type": "Explorer", + "class": "DashAI.back.exploration.explorers.parallel_cordinates.ParallelCordinatesExplorer", + "configurable_object": true, + "schema": { + "properties": { + "color_column": { + "anyOf": [ + { + "type": "string" + }, + { + "minimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The column to use for coloring the data points. ", + "placeholder": "None", + "title": "Color Column" + } + }, + "required": [ + "color_column" + ], + "title": "ParallelCordinatesSchema", + "type": "object" + }, + "metadata": { + "allowed_dtypes": [ + "float64", + "float32" + ], + "restricted_dtypes": [], + "input_cardinality": { + "min": 2 + }, + "display_name": "Parallel Cordinates Plot", + "allowed_value_types": [ + "*" + ], + "restricted_value_types": [] + }, + "description": "A parallel coordinates plot is a common way to visualize high-dimensional data. Each vertical line represents one data point, and the lines are connected by a series of horizontal lines. ", + "display_name": "Parallel Cordinates Plot" + } + }, + "Converter": { + "ColumnRemover": { + "name": "ColumnRemover", + "type": "Converter", + "class": "DashAI.back.converters.simple_converters.column_remover.ColumnRemover", + "configurable_object": true, + "schema": { + "properties": {}, + "title": "ColumnRemoverSchema", + "type": "object" + }, + "metadata": "None", + "description": "Removes the columns selected in scope from the dataset.", + "display_name": "None" + }, + "CharacterReplacer": { + "name": "CharacterReplacer", + "type": "Converter", + "class": "DashAI.back.converters.simple_converters.character_replacer.CharacterReplacer", + "configurable_object": true, + "schema": { + "properties": { + "char_to_replace": { + "description": "The character or substring to be replaced. Cannot be empty.", + "placeholder": "", + "title": "Char To Replace", + "type": "string" + }, + "replacement_char": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The character or substring to replace with. If null, 'char_to_replace' will be removed.", + "placeholder": "None", + "title": "Replacement Char" + } + }, + "required": [ + "char_to_replace", + "replacement_char" + ], + "title": "CharacterReplacerSchema", + "type": "object" + }, + "metadata": "None", + "description": "Replaces or removes specified characters/substrings in selected string columns.", + "display_name": "None" + }, + "FastICA": { + "name": "FastICA", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.fast_ica.FastICA", + "configurable_object": true, + "schema": { + "properties": { + "n_components": { + "anyOf": [ + { + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Number of components to extract.", + "placeholder": "None", + "title": "N Components" + }, + "algorithm": { + "description": "Apply parallel or deflational algorithm for FastICA.", + "enum": [ + "parallel", + "deflation" + ], + "placeholder": "parallel", + "title": "Algorithm", + "type": "string" + }, + "whiten": { + "anyOf": [ + { + "enum": [ + "arbitrary-variance", + "unit-variance" + ], + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "description": "If true, the data is whitened.", + "placeholder": "unit-variance", + "title": "Whiten" + }, + "fun": { + "description": "The functional form of the G function used in the approximation to neg-entropy.", + "enum": [ + "logcosh", + "exp", + "cube" + ], + "placeholder": "logcosh", + "title": "Fun", + "type": "string" + }, + "fun_args": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Arguments to the G function.", + "placeholder": "None", + "title": "Fun Args" + }, + "max_iter": { + "description": "Maximum number of iterations to perform.", + "minimum": 1, + "placeholder": 200, + "title": "Max Iter", + "type": "integer" + }, + "tol": { + "description": "Tolerance on update at each iteration.", + "minimum": 0, + "placeholder": 0.0001, + "title": "Tol", + "type": "number" + }, + "w_init": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Initial guess for the unmixing matrix.", + "placeholder": "None", + "title": "W Init" + }, + "whiten_solver": { + "description": "The solver to use for whitening.", + "enum": [ + "eigh", + "svd" + ], + "placeholder": "svd", + "title": "Whiten Solver", + "type": "string" + }, + "random_state": { + "anyOf": [ + { + "type": "integer" + }, + { + "enum": [ + "RandomState" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Used to initialize w_init when not specified, with a normal distribution. Pass an int, for reproducible results across multiple function calls.", + "placeholder": "None", + "title": "Random State" + } + }, + "required": [ + "n_components", + "algorithm", + "whiten", + "fun", + "fun_args", + "max_iter", + "tol", + "w_init", + "whiten_solver", + "random_state" + ], + "title": "FastICASchema", + "type": "object" + }, + "metadata": "None", + "description": "FastICA: a fast algorithm for Independent Component Analysis.", + "display_name": "None" + }, + "IncrementalPCA": { + "name": "IncrementalPCA", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.incremental_pca.IncrementalPCA", + "configurable_object": true, + "schema": { + "properties": { + "n_components": { + "anyOf": [ + { + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Number of components to keep.", + "placeholder": 2, + "title": "N Components" + }, + "whiten": { + "description": "When true (false by default) the components_ vectors are multiplied by the square root of n_samples and then divided by the singular values to ensure uncorrelated outputs with unit component-wise variances.", + "placeholder": false, + "title": "Whiten", + "type": "boolean" + }, + "copy": { + "description": "If false, data passed to fit are overwritten and running fit(X).transform(X) will not yield the expected results, use fit_transform(X) instead.", + "placeholder": true, + "title": "Copy", + "type": "boolean" + }, + "batch_size": { + "anyOf": [ + { + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "The number of samples to use for each batch.", + "placeholder": "None", + "title": "Batch Size" + } + }, + "required": [ + "n_components", + "whiten", + "copy", + "batch_size" + ], + "title": "IncrementalPCASchema", + "type": "object" + }, + "metadata": "None", + "description": "Incremental principal components analysis (IPCA).", + "display_name": "None" + }, + "PCA": { + "name": "PCA", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.pca.PCA", + "configurable_object": true, + "schema": { + "properties": { + "n_components": { + "anyOf": [ + { + "minimum": 1, + "type": "integer" + }, + { + "exclusiveMaximum": 1, + "exclusiveMinimum": 0, + "type": "number" + }, + { + "enum": [ + "mle" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Number of components to keep. If 'None', all components are kept.", + "placeholder": 2, + "title": "N Components" + }, + "copy": { + "description": "If false, data passed to fit are overwritten and running fit(X).transform(X) will not yield the expected results, use fit_transform(X) instead.", + "placeholder": true, + "title": "Copy", + "type": "boolean" + }, + "whiten": { + "description": "When true (false by default) the components_ vectors are multiplied by the square root of n_samples and then divided by the singular values to ensure uncorrelated outputs with unit component-wise variances. Whitening will remove some information from the transformed signal (the relative variance scales of the components) but can sometime improve the predictive accuracy of the downstream estimators by making their data respect some hard-wired assumptions.", + "placeholder": false, + "title": "Whiten", + "type": "boolean" + }, + "svd_solver": { + "description": "The solver to use for the eigendecomposition. If 'auto', it will choose the most appropriate solver based on the type of data passed.", + "enum": [ + "auto", + "full", + "covariance_eigh", + "arpack", + "randomized" + ], + "placeholder": "auto", + "title": "Svd Solver", + "type": "string" + }, + "tol": { + "description": "Tolerance for singular values computed by svd_solver == 'arpack'.", + "minimum": 0, + "placeholder": 0, + "title": "Tol", + "type": "number" + }, + "iterated_power": { + "anyOf": [ + { + "minimum": 1, + "type": "integer" + }, + { + "enum": [ + "auto" + ], + "type": "string" + } + ], + "description": "Number of iterations for the power method computed by svd_solver == 'randomized'.", + "placeholder": "auto", + "title": "Iterated Power" + }, + "n_oversamples": { + "description": "Number of power iterations used when svd_solver == 'randomized'.", + "minimum": 1, + "placeholder": 10, + "title": "N Oversamples", + "type": "integer" + }, + "power_iteration_normalizer": { + "anyOf": [ + { + "enum": [ + "auto", + "QR", + "LU" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Whether the power iteration normalizer should be computed with QR (the 'auto' option), LU decomposition ('LU') or left untouched ('QR'). Not used by ARPACK.", + "placeholder": "auto", + "title": "Power Iteration Normalizer" + }, + "random_state": { + "anyOf": [ + { + "type": "integer" + }, + { + "enum": [ + "RandomState" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Used when the �arpack� or �randomized� solvers are used. Pass an int for reproducible results across multiple function calls.", + "placeholder": "None", + "title": "Random State" + } + }, + "required": [ + "n_components", + "copy", + "whiten", + "svd_solver", + "tol", + "iterated_power", + "n_oversamples", + "power_iteration_normalizer", + "random_state" + ], + "title": "PCASchema", + "type": "object" + }, + "metadata": "None", + "description": "Principal component analysis (PCA).", + "display_name": "None" + }, + "ConverterChain": { + "name": "ConverterChain", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.converter_chain.ConverterChain", + "configurable_object": true, + "schema": { + "properties": { + "steps": { + "description": "Number of converters in the chain.", + "minimum": 1, + "placeholder": 1, + "title": "Steps", + "type": "integer" + } + }, + "required": [ + "steps" + ], + "title": "ConverterChainSchema", + "type": "object" + }, + "metadata": "None", + "description": "A ConverterChain applies a sequence of converters to preprocess data, passing the output of one converter to the next, with its scope defined by the first converter (the chain itself).", + "display_name": "None" + }, + "TruncatedSVD": { + "name": "TruncatedSVD", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.truncated_svd.TruncatedSVD", + "configurable_object": true, + "schema": { + "properties": { + "n_components": { + "description": "Desired dimensionality of output data.", + "exclusiveMinimum": 0, + "placeholder": 2, + "title": "N Components", + "type": "integer" + }, + "algorithm": { + "description": "SVD solver to use.", + "enum": [ + "arpack", + "randomized" + ], + "placeholder": "randomized", + "title": "Algorithm", + "type": "string" + }, + "n_iter": { + "description": "Number of iterations for randomized SVD solver.", + "exclusiveMinimum": 0, + "placeholder": 5, + "title": "N Iter", + "type": "integer" + }, + "n_oversamples": { + "description": "Number of power iterations used in randomized SVD solver.", + "exclusiveMinimum": 0, + "placeholder": 10, + "title": "N Oversamples", + "type": "integer" + }, + "power_iteration_normalizer": { + "description": "Method to normalize the eigenvectors.", + "enum": [ + "auto", + "QR", + "LU", + "None" + ], + "placeholder": "auto", + "title": "Power Iteration Normalizer", + "type": "string" + }, + "random_state": { + "anyOf": [ + { + "type": "integer" + }, + { + "enum": [ + "RandomState" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Used during randomized svd. Pass an int for reproducible results across multiple function calls.", + "placeholder": "None", + "title": "Random State" + }, + "tol": { + "description": "Tolerance for ARPACK.", + "minimum": 0, + "placeholder": 0, + "title": "Tol", + "type": "number" + } + }, + "required": [ + "n_components", + "algorithm", + "n_iter", + "n_oversamples", + "power_iteration_normalizer", + "random_state", + "tol" + ], + "title": "TruncatedSVDSchema", + "type": "object" + }, + "metadata": "None", + "description": "This transformer performs linear dimensionality reduction by means of truncated singular value decomposition (SVD). Contrary to PCA, this estimator does not center the data before computing the singular value decomposition. This means it can work with sparse matrices efficiently.", + "display_name": "None" + }, + "Binarizer": { + "name": "Binarizer", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.binarizer.Binarizer", + "configurable_object": true, + "schema": { + "properties": { + "threshold": { + "description": "Feature values below or equal to this are replaced by 0, above it by 1.", + "placeholder": 0, + "title": "Threshold", + "type": "number" + }, + "copy": { + "description": "Set to false to perform inplace binarization.", + "placeholder": true, + "title": "Copy", + "type": "boolean" + } + }, + "required": [ + "threshold", + "copy" + ], + "title": "BinarizerSchema", + "type": "object" + }, + "metadata": "None", + "description": "Binarize data (set feature values to 0 or 1) according to a threshold.", + "display_name": "None" + }, + "LabelBinarizer": { + "name": "LabelBinarizer", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.label_binarizer.LabelBinarizer", + "configurable_object": true, + "schema": { + "properties": { + "neg_label": { + "description": "Value with which negative labels must be encoded.", + "placeholder": 0, + "title": "Neg Label", + "type": "integer" + }, + "pos_label": { + "description": "Value with which positive labels must be encoded.", + "placeholder": 1, + "title": "Pos Label", + "type": "integer" + } + }, + "required": [ + "neg_label", + "pos_label" + ], + "title": "LabelBinarizerSchema", + "type": "object" + }, + "metadata": "None", + "description": "Binarize labels in a one-vs-all fashion.", + "display_name": "None" + }, + "LabelEncoder": { + "name": "LabelEncoder", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.label_encoder.LabelEncoder", + "configurable_object": true, + "schema": { + "properties": {}, + "title": "LabelEncoderSchema", + "type": "object" + }, + "metadata": "None", + "description": "Encode target labels with value between 0 and n_classes-1.", + "display_name": "None" + }, + "MaxAbsScaler": { + "name": "MaxAbsScaler", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.max_abs_scaler.MaxAbsScaler", + "configurable_object": true, + "schema": { + "properties": { + "copy": { + "description": "Set to false to perform inplace scaling.", + "placeholder": true, + "title": "Copy", + "type": "boolean" + } + }, + "required": [ + "copy" + ], + "title": "MaxAbsScalerSchema", + "type": "object" + }, + "metadata": "None", + "description": "Scale each feature by its maximum absolute value.", + "display_name": "None" + }, + "MinMaxScaler": { + "name": "MinMaxScaler", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.min_max_scaler.MinMaxScaler", + "configurable_object": true, + "schema": { + "properties": { + "min_range": { + "description": "The minimum value of the range to scale the data to.", + "minimum": 0, + "placeholder": 0, + "title": "Min Range", + "type": "number" + }, + "max_range": { + "description": "The maximum value of the range to scale the data to.", + "minimum": 0, + "placeholder": 1, + "title": "Max Range", + "type": "number" + }, + "copy": { + "description": "Set to false to perform inplace row normalization.", + "placeholder": true, + "title": "Copy", + "type": "boolean" + }, + "clip": { + "description": "Set to true to clip the data to the feature range.", + "placeholder": false, + "title": "Clip", + "type": "boolean" + } + }, + "required": [ + "min_range", + "max_range", + "copy", + "clip" + ], + "title": "MinMaxScalerSchema", + "type": "object" + }, + "metadata": "None", + "description": "Transform features by scaling each feature to a given range.", + "display_name": "None" + }, + "Normalizer": { + "name": "Normalizer", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.normalizer.Normalizer", + "configurable_object": true, + "schema": { + "properties": { + "norm": { + "description": "The norm to use to normalize each non zero sample.", + "enum": [ + "l1", + "l2", + "max" + ], + "placeholder": "l2", + "title": "Norm", + "type": "string" + }, + "copy": { + "description": "Set to false to perform inplace row normalization.", + "placeholder": true, + "title": "Copy", + "type": "boolean" + } + }, + "required": [ + "norm", + "copy" + ], + "title": "NormalizerSchema", + "type": "object" + }, + "metadata": "None", + "description": "Normalize samples individually to unit norm.", + "display_name": "None" + }, + "OneHotEncoder": { + "name": "OneHotEncoder", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.one_hot_encoder.OneHotEncoder", + "configurable_object": true, + "schema": { + "properties": { + "categories": { + "description": "The categories of each feature.", + "placeholder": "auto", + "title": "Categories", + "type": "string" + }, + "drop": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Specifies a methodology to use to drop one of the categories per feature.", + "placeholder": "None", + "title": "Drop" + }, + "dtype": { + "description": "Desired dtype of output.", + "enum": [ + "int", + "np.float32", + "np.float64" + ], + "placeholder": "np.float64", + "title": "Dtype", + "type": "string" + }, + "handle_unknown": { + "description": "Whether to raise an error or ignore if an unknown categorical feature is present during transform.", + "enum": [ + "error", + "ignore", + "infrequent_if_exist" + ], + "placeholder": "error", + "title": "Handle Unknown", + "type": "string" + }, + "min_frequency": { + "anyOf": [ + { + "minimum": 0, + "type": "integer" + }, + { + "maximum": 1, + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Minimum frequency of a category to be considered as frequent.", + "placeholder": "None", + "title": "Min Frequency" + }, + "max_categories": { + "anyOf": [ + { + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Maximum number of categories to encode.", + "placeholder": "None", + "title": "Max Categories" + }, + "feature_name_combiner": { + "description": "Method used to combine feature names.", + "enum": [ + "concat" + ], + "placeholder": "concat", + "title": "Feature Name Combiner", + "type": "string" + } + }, + "required": [ + "categories", + "drop", + "dtype", + "handle_unknown", + "min_frequency", + "max_categories", + "feature_name_combiner" + ], + "title": "OneHotEncoderSchema", + "type": "object" + }, + "metadata": "None", + "description": "Encode categorical integer features as a one-hot numeric array.", + "display_name": "None" + }, + "OrdinalEncoder": { + "name": "OrdinalEncoder", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.ordinal_encoder.OrdinalEncoder", + "configurable_object": true, + "schema": { + "properties": { + "categories": { + "description": "Categories (unique values) per feature.", + "placeholder": "auto", + "title": "Categories", + "type": "string" + }, + "dtype": { + "description": "Desired dtype of output.", + "enum": [ + "np.int32", + "np.int64", + "np.float32", + "np.float64" + ], + "placeholder": "np.float64", + "title": "Dtype", + "type": "string" + }, + "handle_unknown": { + "description": "Whether to raise an error or ignore if an unknown categorical feature is present during transform.", + "enum": [ + "error", + "use_encoded_value" + ], + "placeholder": "error", + "title": "Handle Unknown", + "type": "string" + }, + "unknown_value": { + "anyOf": [ + { + "enum": [ + "int", + "np.nan" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The value to use for unknown categories.", + "placeholder": "None", + "title": "Unknown Value" + }, + "min_frequency": { + "anyOf": [ + { + "minimum": 1, + "type": "integer" + }, + { + "maximum": 1, + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Minimum frequency of a category to be considered as frequent.", + "placeholder": "None", + "title": "Min Frequency" + }, + "max_categories": { + "anyOf": [ + { + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Maximum number of categories to encode.", + "placeholder": "None", + "title": "Max Categories" + } + }, + "required": [ + "categories", + "dtype", + "handle_unknown", + "unknown_value", + "min_frequency", + "max_categories" + ], + "title": "OrdinalEncoderSchema", + "type": "object" + }, + "metadata": "None", + "description": "Encode categorical features as an integer array.", + "display_name": "None" + }, + "PolynomialFeatures": { + "name": "PolynomialFeatures", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.polynomial_features.PolynomialFeatures", + "configurable_object": true, + "schema": { + "properties": { + "degree": { + "description": "The degree of the polynomial features.", + "minimum": 1, + "placeholder": 2, + "title": "Degree", + "type": "integer" + }, + "interaction_only": { + "description": "If true, only interaction features are produced: features that are products of at most degree distinct input features (so not x[1] ** 2, x[0] * x[2] ** 3, etc.).", + "placeholder": false, + "title": "Interaction Only", + "type": "boolean" + }, + "include_bias": { + "description": "If true (default), then include a bias column, the feature in which all polynomial powers are zero (i.e. a column of ones - acts as an intercept term in a linear model).", + "placeholder": true, + "title": "Include Bias", + "type": "boolean" + }, + "order": { + "description": "Order of output array in the dense case. 'F' order is faster to compute, but may slow down subsequent estimators.", + "enum": [ + "C", + "F" + ], + "placeholder": "C", + "title": "Order", + "type": "string" + } + }, + "required": [ + "degree", + "interaction_only", + "include_bias", + "order" + ], + "title": "PolynomialFeaturesSchema", + "type": "object" + }, + "metadata": "None", + "description": "Generate polynomial and interaction features.", + "display_name": "None" + }, + "StandardScaler": { + "name": "StandardScaler", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.standard_scaler.StandardScaler", + "configurable_object": true, + "schema": { + "properties": { + "copy": { + "description": "If false, try to avoid a copy and do inplace scaling instead.", + "placeholder": true, + "title": "Copy", + "type": "boolean" + }, + "with_mean": { + "description": "If true, center the data before scaling.", + "placeholder": true, + "title": "With Mean", + "type": "boolean" + }, + "with_std": { + "description": "If true, scale the data to unit variance (or equivalently, unit standard deviation).", + "placeholder": true, + "title": "With Std", + "type": "boolean" + } + }, + "required": [ + "copy", + "with_mean", + "with_std" + ], + "title": "StandardScalerSchema", + "type": "object" + }, + "metadata": "None", + "description": "Standardize features by removing the mean and scaling to unit variance.", + "display_name": "None" + }, + "Embedding": { + "name": "Embedding", + "type": "Converter", + "class": "DashAI.back.converters.hugging_face.embedding.Embedding", + "configurable_object": true, + "schema": { + "properties": { + "model_name": { + "description": "Name of the pre-trained model to use", + "enum": [ + "sentence-transformers/all-MiniLM-L6-v2", + "sentence-transformers/all-mpnet-base-v2", + "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2", + "sentence-transformers/all-distilroberta-v1", + "bert-base-uncased", + "bert-large-uncased", + "bert-base-multilingual-cased", + "distilbert-base-uncased", + "roberta-base", + "roberta-large", + "distilroberta-base" + ], + "placeholder": "sentence-transformers/all-MiniLM-L6-v2", + "title": "Model Name", + "type": "string" + }, + "max_length": { + "description": "Maximum sequence length for tokenization", + "minimum": 1, + "placeholder": 512, + "title": "Max Length", + "type": "integer" + }, + "batch_size": { + "description": "Number of samples to process at once", + "minimum": 1, + "placeholder": 32, + "title": "Batch Size", + "type": "integer" + }, + "device": { + "description": "Device to use for computation", + "enum": [ + "cuda", + "cpu" + ], + "placeholder": "cpu", + "title": "Device", + "type": "string" + }, + "pooling_strategy": { + "description": "Strategy to pool token embeddings into sentence embedding", + "enum": [ + "mean", + "cls", + "max" + ], + "placeholder": "mean", + "title": "Pooling Strategy", + "type": "string" + } + }, + "required": [ + "model_name", + "max_length", + "batch_size", + "device", + "pooling_strategy" + ], + "title": "EmbeddingSchema", + "type": "object" + }, + "metadata": "None", + "description": "Convert text to embeddings using HuggingFace transformer models.", + "display_name": "None" + }, + "VarianceThreshold": { + "name": "VarianceThreshold", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.variance_threshold.VarianceThreshold", + "configurable_object": true, + "schema": { + "properties": { + "threshold": { + "description": "Features with a variance lower than this threshold will be removed.", + "minimum": 0, + "placeholder": 0, + "title": "Threshold", + "type": "number" + } + }, + "required": [ + "threshold" + ], + "title": "VarianceThresholdSchema", + "type": "object" + }, + "metadata": "None", + "description": "Feature selector that removes all low-variance features.", + "display_name": "None" + }, + "SimpleImputer": { + "name": "SimpleImputer", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.simple_imputer.SimpleImputer", + "configurable_object": true, + "schema": { + "properties": { + "missing_values": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The placeholder for the missing values.", + "placeholder": "None", + "title": "Missing Values" + }, + "strategy": { + "description": "The imputation strategy.", + "enum": [ + "mean", + "median", + "most_frequent", + "constant" + ], + "placeholder": "mean", + "title": "Strategy", + "type": "string" + }, + "fill_value": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The value to replace missing values with.", + "placeholder": "None", + "title": "Fill Value" + }, + "copy": { + "description": "If true, a copy of X will be created.", + "placeholder": true, + "title": "Copy", + "type": "boolean" + }, + "add_indicator": { + "description": "If true, a MissingIndicator transform will stack onto output.", + "placeholder": false, + "title": "Add Indicator", + "type": "boolean" + }, + "keep_empty_features": { + "description": "If true, empty features will be kept.", + "placeholder": false, + "title": "Keep Empty Features", + "type": "boolean" + } + }, + "required": [ + "missing_values", + "strategy", + "fill_value", + "copy", + "add_indicator", + "keep_empty_features" + ], + "title": "SimpleImputerSchema", + "type": "object" + }, + "metadata": "None", + "description": "Univariate imputer for completing missing values with simple strategies.", + "display_name": "None" + }, + "MissingIndicator": { + "name": "MissingIndicator", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.missing_indicator.MissingIndicator", + "configurable_object": true, + "schema": { + "properties": { + "missing_values": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The placeholder for the missing values.", + "placeholder": "None", + "title": "Missing Values" + }, + "features": { + "description": "The features to consider for missing values.", + "enum": [ + "missing-only", + "all" + ], + "placeholder": "None", + "title": "Features", + "type": "string" + }, + "error_on_new": { + "description": "Whether to raise an error on new missing values.", + "placeholder": true, + "title": "Error On New", + "type": "boolean" + } + }, + "required": [ + "missing_values", + "features", + "error_on_new" + ], + "title": "MissingIndicatorSchema", + "type": "object" + }, + "metadata": "None", + "description": "Binary indicators for missing values.", + "display_name": "None" + }, + "KNNImputer": { + "name": "KNNImputer", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.knn_imputer.KNNImputer", + "configurable_object": true, + "schema": { + "properties": { + "missing_values": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The placeholder for the missing values.", + "placeholder": "None", + "title": "Missing Values" + }, + "n_neighbors": { + "description": "The number of nearest neighbors to use for imputation.", + "minimum": 1, + "placeholder": 5, + "title": "N Neighbors", + "type": "integer" + }, + "weights": { + "description": "The weight function to use for imputation.", + "enum": [ + "uniform", + "distance" + ], + "placeholder": "uniform", + "title": "Weights", + "type": "string" + }, + "metric": { + "description": "The metric to use for imputation.", + "enum": [ + "nan_euclidean" + ], + "placeholder": "nan_euclidean", + "title": "Metric", + "type": "string" + }, + "copy": { + "description": "If true, a copy of X will be created.", + "placeholder": true, + "title": "Copy", + "type": "boolean" + }, + "add_indicator": { + "description": "If true, a MissingIndicator transform will stack onto output.", + "placeholder": false, + "title": "Add Indicator", + "type": "boolean" + }, + "keep_empty_features": { + "description": "If true, empty features will be kept.", + "placeholder": false, + "title": "Keep Empty Features", + "type": "boolean" + } + }, + "required": [ + "missing_values", + "n_neighbors", + "weights", + "metric", + "copy", + "add_indicator", + "keep_empty_features" + ], + "title": "KNNImputerSchema", + "type": "object" + }, + "metadata": "None", + "description": "Imputation for completing missing values using k-Nearest Neighbors.", + "display_name": "None" + }, + "AdditiveChi2Sampler": { + "name": "AdditiveChi2Sampler", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.additive_chi_2_sampler.AdditiveChi2Sampler", + "configurable_object": true, + "schema": { + "properties": { + "sample_steps": { + "description": "The number of sample steps (shuffling) to perform.", + "minimum": 1, + "placeholder": 2, + "title": "Sample Steps", + "type": "integer" + }, + "sample_interval": { + "anyOf": [ + { + "minimum": 1, + "type": "number" + }, + { + "type": "null" + } + ], + "description": "The number of samples to generate between each original sample.", + "placeholder": "None", + "title": "Sample Interval" + } + }, + "required": [ + "sample_steps", + "sample_interval" + ], + "title": "AdditiveChi2SamplerSchema", + "type": "object" + }, + "metadata": "None", + "description": "Uses sampling the fourier transform of the kernel characteristic at regular intervals.", + "display_name": "None" + }, + "RBFSampler": { + "name": "RBFSampler", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.rbf_sampler.RBFSampler", + "configurable_object": true, + "schema": { + "properties": { + "gamma": { + "anyOf": [ + { + "enum": [ + "scale" + ], + "type": "string" + }, + { + "exclusiveMinimum": 0, + "type": "number" + } + ], + "description": "Parameter of the RBF kernel.", + "placeholder": 1, + "title": "Gamma" + }, + "n_components": { + "description": "The number of features to construct.", + "minimum": 1, + "placeholder": 100, + "title": "N Components", + "type": "integer" + }, + "random_state": { + "anyOf": [ + { + "type": "integer" + }, + { + "enum": [ + "RandomState" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Pseudo-random number generator to control the generation of the random weights and random offset when fitting the training data. Pass an int for reproducible output across multiple function calls.", + "placeholder": "None", + "title": "Random State" + } + }, + "required": [ + "gamma", + "n_components", + "random_state" + ], + "title": "RBFSamplerSchema", + "type": "object" + }, + "metadata": "None", + "description": "Approximates the feature map of an RBF kernel by Monte Carlo approximation of its Fourier transform.", + "display_name": "None" + }, + "SkewedChi2Sampler": { + "name": "SkewedChi2Sampler", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.skewed_chi_2_sampler.SkewedChi2Sampler", + "configurable_object": true, + "schema": { + "properties": { + "skewedness": { + "description": "The skewedness parameter of the chi-squared kernel.", + "exclusiveMinimum": 0, + "placeholder": 1, + "title": "Skewedness", + "type": "number" + }, + "n_components": { + "description": "Number of Monte Carlo samples per original feature. Equals the dimensionality of the computed feature space.", + "minimum": 1, + "placeholder": 100, + "title": "N Components", + "type": "integer" + }, + "random_state": { + "anyOf": [ + { + "type": "integer" + }, + { + "enum": [ + "RandomState" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Pseudo-random number generator to control the generation of the random weights and random offset when fitting the training data. Pass an int for reproducible output across multiple function calls.", + "placeholder": "None", + "title": "Random State" + } + }, + "required": [ + "skewedness", + "n_components", + "random_state" + ], + "title": "SkewedChi2SamplerSchema", + "type": "object" + }, + "metadata": "None", + "description": "Approximates the feature map of a chi-squared kernel by Monte Carlo approximation of its Fourier transform.", + "display_name": "None" + }, + "GenericUnivariateSelect": { + "name": "GenericUnivariateSelect", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.generic_univariate_select.GenericUnivariateSelect", + "configurable_object": true, + "schema": { + "properties": { + "mode": { + "description": "Select features according to a percentile of the highest scores.", + "enum": [ + "percentile", + "k_best", + "fpr", + "fdr", + "fwe" + ], + "placeholder": "percentile", + "title": "Mode", + "type": "string" + }, + "param": { + "anyOf": [ + { + "enum": [ + "all" + ], + "type": "string" + }, + { + "type": "number" + }, + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Parameter of the mode.", + "placeholder": 0.00001, + "title": "Param" + } + }, + "required": [ + "mode", + "param" + ], + "title": "GenericUnivariateSelectSchema", + "type": "object" + }, + "metadata": "None", + "description": "Univariate feature selector with configurable strategy.", + "display_name": "None" + }, + "SelectPercentile": { + "name": "SelectPercentile", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.select_percentile.SelectPercentile", + "configurable_object": true, + "schema": { + "properties": { + "percentile": { + "description": "Percent of features to keep.", + "maximum": 100, + "minimum": 1, + "placeholder": 10, + "title": "Percentile", + "type": "integer" + } + }, + "required": [ + "percentile" + ], + "title": "SelectPercentileSchema", + "type": "object" + }, + "metadata": "None", + "description": "Select features according to a percentile of the highest scores.", + "display_name": "None" + }, + "SelectKBest": { + "name": "SelectKBest", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.select_k_best.SelectKBest", + "configurable_object": true, + "schema": { + "properties": { + "k": { + "anyOf": [ + { + "enum": [ + "all" + ], + "type": "string" + }, + { + "minimum": 1, + "type": "integer" + } + ], + "description": "Number of top features to select.", + "placeholder": 10, + "title": "K" + } + }, + "required": [ + "k" + ], + "title": "SelectKBestSchema", + "type": "object" + }, + "metadata": "None", + "description": "Select features according to the k highest scores.", + "display_name": "None" + }, + "SelectFpr": { + "name": "SelectFpr", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.select_fpr.SelectFpr", + "configurable_object": true, + "schema": { + "properties": { + "alpha": { + "description": "The highest p-value for features to be kept.", + "maximum": 1, + "minimum": 0, + "placeholder": 0.05, + "title": "Alpha", + "type": "number" + } + }, + "required": [ + "alpha" + ], + "title": "SelectFprSchema", + "type": "object" + }, + "metadata": "None", + "description": "Filter: Select features according to a false positive rate test.", + "display_name": "None" + }, + "SelectFdr": { + "name": "SelectFdr", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.select_fdr.SelectFdr", + "configurable_object": true, + "schema": { + "properties": { + "alpha": { + "description": "The highest uncorrected p-value for features to be kept.", + "maximum": 1, + "minimum": 0, + "placeholder": 0.05, + "title": "Alpha", + "type": "number" + } + }, + "required": [ + "alpha" + ], + "title": "SelectFdrSchema", + "type": "object" + }, + "metadata": "None", + "description": "Filter: Select features according to a false discovery rate test.", + "display_name": "None" + }, + "SelectFwe": { + "name": "SelectFwe", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.select_fwe.SelectFwe", + "configurable_object": true, + "schema": { + "properties": { + "alpha": { + "description": "The highest uncorrected p-value for features to be kept.", + "maximum": 1, + "minimum": 0, + "placeholder": 0.05, + "title": "Alpha", + "type": "number" + } + }, + "required": [ + "alpha" + ], + "title": "SelectFweSchema", + "type": "object" + }, + "metadata": "None", + "description": "Filter: Select features according to a family-wise error rate test.", + "display_name": "None" + }, + "Nystroem": { + "name": "Nystroem", + "type": "Converter", + "class": "DashAI.back.converters.scikit_learn.nystroem.Nystroem", + "configurable_object": true, + "schema": { + "properties": { + "kernel": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The kernel to use for the approximation.", + "placeholder": "rbf", + "title": "Kernel" + }, + "gamma": { + "anyOf": [ + { + "exclusiveMinimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "description": "The gamma parameter for the RBF, laplacian, polynomial, exponential chi2 and sigmoid kernels.", + "placeholder": "None", + "title": "Gamma" + }, + "coef0": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "The coef0 parameter for the polynomial and sigmoid kernels.", + "placeholder": "None", + "title": "Coef0" + }, + "degree": { + "anyOf": [ + { + "minimum": 1, + "type": "number" + }, + { + "type": "null" + } + ], + "description": "The degree of the polynomial kernel.", + "placeholder": "None", + "title": "Degree" + }, + "kernel_params": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Additional parameters (keyword arguments) for the kernel function.", + "placeholder": "None", + "title": "Kernel Params" + }, + "n_components": { + "description": "The number of features to construct.", + "minimum": 1, + "placeholder": 100, + "title": "N Components", + "type": "integer" + }, + "random_state": { + "anyOf": [ + { + "type": "integer" + }, + { + "enum": [ + "RandomState" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The seed of the pseudo random number generator to use when shuffling the data.", + "placeholder": "None", + "title": "Random State" + }, + "n_jobs": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Number of parallel jobs to run.", + "placeholder": "None", + "title": "N Jobs" + } + }, + "required": [ + "kernel", + "gamma", + "coef0", + "degree", + "kernel_params", + "n_components", + "random_state", + "n_jobs" + ], + "title": "NystroemSchema", + "type": "object" + }, + "metadata": "None", + "description": "Approximates the feature map of an RBF kernel by Monte Carlo approximation of its Fourier transform.", + "display_name": "None" + }, + "SMOTEConverter": { + "name": "SMOTEConverter", + "type": "Converter", + "class": "DashAI.back.converters.imbalanced_learn.smote_converter.SMOTEConverter", + "configurable_object": true, + "schema": { + "properties": { + "sampling_strategy": { + "anyOf": [ + { + "exclusiveMinimum": 0, + "maximum": 1, + "type": "number" + }, + { + "enum": [ + "auto" + ], + "type": "string" + } + ], + "description": "Sampling strategy (float or 'auto') to determine minority class size.", + "placeholder": "auto", + "title": "Sampling Strategy" + }, + "random_state": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Seed for reproducibility.", + "placeholder": "None", + "title": "Random State" + }, + "k_neighbors": { + "description": "Number of neighbors to use for generating synthetic samples.", + "minimum": 1, + "placeholder": 5, + "title": "K Neighbors", + "type": "integer" + } + }, + "required": [ + "sampling_strategy", + "random_state", + "k_neighbors" + ], + "title": "SMOTESchema", + "type": "object" + }, + "metadata": "None", + "description": "SMOTE: Synthetic Minority Over-sampling Technique.", + "display_name": "None" + }, + "SMOTEENNConverter": { + "name": "SMOTEENNConverter", + "type": "Converter", + "class": "DashAI.back.converters.imbalanced_learn.smoteenn_converter.SMOTEENNConverter", + "configurable_object": true, + "schema": { + "properties": { + "sampling_strategy": { + "anyOf": [ + { + "exclusiveMinimum": 0, + "maximum": 1, + "type": "number" + }, + { + "enum": [ + "auto" + ], + "type": "string" + } + ], + "description": "Sampling strategy to apply SMOTE and clean the dataset.", + "placeholder": "auto", + "title": "Sampling Strategy" + }, + "random_state": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Seed used for reproducibility.", + "placeholder": "None", + "title": "Random State" + }, + "k_neighbors": { + "description": "Number of neighbors used by SMOTE.", + "minimum": 1, + "placeholder": 5, + "title": "K Neighbors", + "type": "integer" + } + }, + "required": [ + "sampling_strategy", + "random_state", + "k_neighbors" + ], + "title": "SMOTEENNSchema", + "type": "object" + }, + "metadata": "None", + "description": "SMOTEENN: SMOTE with noise reduction via Edited Nearest Neighbors.", + "display_name": "None" + }, + "RandomUnderSamplerConverter": { + "name": "RandomUnderSamplerConverter", + "type": "Converter", + "class": "DashAI.back.converters.imbalanced_learn.random_under_sampler_converter.RandomUnderSamplerConverter", + "configurable_object": true, + "schema": { + "properties": { + "sampling_strategy": { + "anyOf": [ + { + "exclusiveMinimum": 0, + "maximum": 1, + "type": "number" + }, + { + "enum": [ + "auto" + ], + "type": "string" + } + ], + "description": "Sampling strategy (float or 'auto') to reduce majority class.", + "placeholder": "auto", + "title": "Sampling Strategy" + }, + "random_state": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Seed for reproducibility.", + "placeholder": "None", + "title": "Random State" + } + }, + "required": [ + "sampling_strategy", + "random_state" + ], + "title": "RUSchema", + "type": "object" + }, + "metadata": "None", + "description": "Randomly remove samples from the majority class to balance the dataset.", + "display_name": "None" + } + } +} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index f80c8d769..02f5281bd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -449,5 +449,5 @@ zipp==3.20.2 # importlib-metadata # importlib-resources imblearn -chromadb==0.5.5 -chroma-hnswlib==0.7.6 \ No newline at end of file + +fasttext-wheel \ No newline at end of file diff --git a/test.py b/test.py new file mode 100644 index 000000000..f1b0e11a5 --- /dev/null +++ b/test.py @@ -0,0 +1,87 @@ +import requests + +""" +select_types: Annotated[Union[List[str], None], Query()], optional + If specified, the function return only the components that extend the + provided types (e.g., task, model, dataloader, etc...). + If None, the method returns all components in the registry, by default None. +ignore_types: Annotated[Union[List[str], None], Query()], optional + If specified, the function return every components that is not that extend + the provided types (e.g., task, model, dataloader, etc...). + If None, the method returns all components in the registry, by default None. +related_component : Union[str , None], optional + If specified, the function return only the components related with + the specified compatible component, (usually some task. as + TabularClassification, Translation, etc.), by default None. +component_parent : Union[str , None], optional + If specified, the function return only the components that inheirts the + indicated component (e.g., ScikitLearnLikeModel), by default None. +has_related_of_type : Union[str, None], optional + If specified, the function returns only components that have at least one + related component of the specified type (e.g., "Model"). This is useful for + filtering tasks that have associated models, by default None. +component_registry : ComponentRegistry + The current app component registry provided by dependency injection. """ + +#print("related component: RAGTask") +#print(requests.get("http://localhost:8000/api/v1/component/?related_component=RAGTask").json()) +#print() + +import json + +#response = requests.get("http://localhost:8000/api/v1/component/?select_types=Model&component_parent=RetrieverModel").json() +#for r in response: +# print(json.dumps(r, indent=2)) +# +#print() +#print() +#print() +#print() +#print() +# +#response = requests.get("http://localhost:8000/api/v1/component/?select_types=Model&related_component=RAGTask").json() +#for r in response: +# print(json.dumps(r, indent=2)) +# +#print() +#print() +#print() +#print() +#print() + + +queries = [ + #"component/Embedding", + #"component/RAGPipeline", + "component/RetrieverModel/children", + #"component/?component_parent=Encoding", + #"component/SparseRetriever/children/", + "component/DenseRetriever/", + "component/TFIDFRetriever/" + +] +print() + +for q in queries: + print(q) + response = requests.get(f"http://localhost:8000/api/v1/{q}") + print(json.dumps(response.json(), indent=2)) + print() + print() + print() + + + +#ESTA WEA NO FUNCIONA +#input() +#print("related component: Model, component parent: RetrieverModel") +#response = requests.get("http://localhost:8000/api/v1/component/?related_component=Model&component_parent=RetrieverModel").json() +#print(response) +#print() + +#ESTA WEA TAMPOCO +#input() +#print("related component: [Model, RetrieverModel ]") +#response = requests.get("http://localhost:8000/api/v1/component/?related_component=RAGTask&related_component=RetrieverModel").json() +#print(response) + diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..bc2d6d577 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "module": "ESNext", + "moduleResolution": "Bundler", + "target": "ES2022", + "jsx": "react-jsx", + "strictNullChecks": true, + "strictFunctionTypes": true, + "sourceMap": true + }, + "exclude": [ + "node_modules", + "**/node_modules/*" + ] +} \ No newline at end of file From 21d9872927008aa80c307d4d8a5a9a1b1371c990 Mon Sep 17 00:00:00 2001 From: sofiachavezb Date: Tue, 9 Sep 2025 16:30:18 -0300 Subject: [PATCH 009/218] changing from EditModelDialog to FormSchemaDialog+FormSchemaWithSelectedModel --- .gitignore | 3 +- .../RAG/RetrieverConfigurationStep.jsx | 85 ++++++++++++++----- 2 files changed, 67 insertions(+), 21 deletions(-) diff --git a/.gitignore b/.gitignore index 7972a2d3a..97f1f3645 100644 --- a/.gitignore +++ b/.gitignore @@ -181,4 +181,5 @@ __pycache__ .prettierrc -*.ipynb \ No newline at end of file +*.ipynb +*.pkl \ No newline at end of file diff --git a/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx b/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx index 9448eeabd..ffe460385 100644 --- a/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx +++ b/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx @@ -1,10 +1,14 @@ import { useState, useEffect, useCallback } from "react"; import { Box, Autocomplete, TextField, Typography } from "@mui/material"; import { DataGrid } from "@mui/x-data-grid"; -import EditModelDialog from "../../../components/experiments/EditModelDialog"; import { getRetrieverComponents, getRetrievalParadigm } from "../../../api/rag"; import { useSnackbar } from "notistack"; import useSchema from "../../../hooks/useSchema"; +import SettingsIcon from "@mui/icons-material/Settings"; +import { GridActionsCellItem } from "@mui/x-data-grid"; +import FormSchemaDialog from "../../../components/shared/FormSchemaDialog"; +import FormSchemaWithSelectedModel from "../../../components/shared/FormSchemaWithSelectedModel"; + export default function RetrieverConfigurationStep({ setNextEnabled }) { const { enqueueSnackbar } = useSnackbar(); @@ -13,8 +17,16 @@ export default function RetrieverConfigurationStep({ setNextEnabled }) { const [retrieverOptions, setRetrieverOptions] = useState([]); const [selectedRetriever, setSelectedRetriever] = useState(null); - const [retrieverInitialParameters, setRetrieverInitialParameters] = useState({}); const [retrieverParamsSchema, setRetrieverParamsSchema] = useState(null); + const { + modelSchema: retrieverModelSchema, + defaultValues: retrieverInitialParameters, + yupSchema: retrieverYupSchema, + loading: retrieverLoading, + } = useSchema({ modelName: selectedRetriever?.name }); + + + const [open, setOpen] = useState(false); const fetchRetrievalParadigms = async () => { try { @@ -38,14 +50,15 @@ export default function RetrieverConfigurationStep({ setNextEnabled }) { return; } - // For non-Sparse paradigms, only set retriever if schema and schema.properties exist - if (selectedRetrievalParadigm.schema && selectedRetrievalParadigm.schema.properties) { + if (selectedRetrievalParadigm.name === "SparseRetriever") { + const retrievers = await getRetrieverComponents(selectedRetrievalParadigm.name); + setRetrieverOptions(retrievers); + setSelectedRetriever(null); + } else { setRetrieverOptions([selectedRetrievalParadigm]); setSelectedRetriever(selectedRetrievalParadigm); - } else { - setRetrieverOptions([]); - setSelectedRetriever(null); } + }; useEffect(() => { @@ -54,12 +67,12 @@ export default function RetrieverConfigurationStep({ setNextEnabled }) { const handleRetrievalParadigmChange = (event, newValue) => { setSelectedRetrievalParadigm(newValue); - setSelectedRetriever(null); + fetchRetrievers() }; const handleRetrieverSelectionChange = (event, newValue) => { setSelectedRetriever(newValue); - setRetrieverInitialParameters(useSchema({ modelName: newValue?.name })); + console.log("Selected retriever model:", newValue); }; const handleRetrieverParametersChange = (newParams) => { @@ -94,6 +107,19 @@ export default function RetrieverConfigurationStep({ setNextEnabled }) { sx={{ mb: 3 }} /> + {selectedRetrievalParadigm && selectedRetrievalParadigm.name === "SparseRetriever" && ( + option.name} + value={selectedRetriever} + onChange={handleRetrieverSelectionChange} + isOptionEqualToValue={(option, value) => option.name === value?.name} + renderInput={(params) => } + sx={{ mb: 3 }} + /> + )} + {selectedRetriever && ( @@ -102,21 +128,40 @@ export default function RetrieverConfigurationStep({ setNextEnabled }) { [ - + <> + } + label="Edit" + onClick={() => setOpen(true)} + /> + { + handleRetrieverParametersChange(values); + setOpen(false); + }} + > + { + handleRetrieverParametersChange(values); + setOpen(false); + }} + onCancel={() => setOpen(false)} + /> + + ], }]} hideFooter From 16db412b3af2ec955c1f2f8733b6e8cc34712485 Mon Sep 17 00:00:00 2001 From: sofiachavezb Date: Tue, 9 Sep 2025 17:30:33 -0300 Subject: [PATCH 010/218] modified FormSchemaHeader --- .../shared/FormSchemaWithSelectedModel.jsx | 1 + .../RAG/RetrieverConfigurationStep.jsx | 76 +++++++++++++------ 2 files changed, 55 insertions(+), 22 deletions(-) diff --git a/DashAI/front/src/components/shared/FormSchemaWithSelectedModel.jsx b/DashAI/front/src/components/shared/FormSchemaWithSelectedModel.jsx index ca6fcb590..8736a9932 100644 --- a/DashAI/front/src/components/shared/FormSchemaWithSelectedModel.jsx +++ b/DashAI/front/src/components/shared/FormSchemaWithSelectedModel.jsx @@ -68,6 +68,7 @@ function FormSchemaWithSelectedModel({ )} + setSchemaDialogOpen(false); const fetchRetrievalParadigms = async () => { try { @@ -140,27 +154,45 @@ export default function RetrieverConfigurationStep({ setNextEnabled }) { key="edit-button" icon={} label="Edit" - onClick={() => setOpen(true)} + onClick={() => setSchemaDialogOpen(true)} /> - { - handleRetrieverParametersChange(values); - setOpen(false); - }} - > - { - handleRetrieverParametersChange(values); - setOpen(false); + setOpen(false)} - /> - + > + + + + + + + + {`${selectedRetriever.name} configuration`} + + + + + + { + handleRetrieverParametersChange(values); + setSchemaDialogOpen(false); + }} + onCancel={() => setSchemaDialogOpen(false)} + /> + + + ], }]} From 37fb3a8c2ca19f20653337f8b8622edbf1a257ba Mon Sep 17 00:00:00 2001 From: sofiachavezb Date: Tue, 9 Sep 2025 19:09:32 -0300 Subject: [PATCH 011/218] Modified EditModelDialog, logic merged into RetrieverConfigurationStep Note: can't use formSchemaStore in the same component because it produces context problems with React --- .../RAG/RetrieverConfigurationStep.jsx | 196 ++++++++++++------ 1 file changed, 136 insertions(+), 60 deletions(-) diff --git a/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx b/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx index f286eb75e..c8c5cc2db 100644 --- a/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx +++ b/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx @@ -1,4 +1,9 @@ -import { useState, useEffect, useCallback } from "react"; +import React, { + useState, + useEffect, + useCallback, + useMemo, +} from "react"; import { Box, Dialog, @@ -8,6 +13,7 @@ import { TextField, Typography, IconButton, + Stack, } from "@mui/material"; import ArrowBackOutlined from "@mui/icons-material/ArrowBackOutlined"; @@ -20,8 +26,12 @@ import SettingsIcon from "@mui/icons-material/Settings"; import { GridActionsCellItem } from "@mui/x-data-grid"; import FormSchemaDialog from "../../../components/shared/FormSchemaDialog"; import FormSchemaWithSelectedModel from "../../../components/shared/FormSchemaWithSelectedModel"; +import FormSchemaModelSelect from "../../../components/shared/FormSchemaModelSelect"; import FormSchemaContainer from "../../../components/shared/FormSchemaContainer"; -import FormSchemaHeader from "../../../components/shared/FormSchemaHeader"; +import { useFormSchemaStore } from "../../../contexts/schema"; +import FormSchemaBreadScrumbs from "../../../components/shared/FormSchemaBreadScrumbs"; +import FormSchema from "../../../components/shared/FormSchema"; + export default function RetrieverConfigurationStep({ setNextEnabled }) { const { enqueueSnackbar } = useSnackbar(); @@ -30,7 +40,8 @@ export default function RetrieverConfigurationStep({ setNextEnabled }) { const [retrieverOptions, setRetrieverOptions] = useState([]); const [selectedRetriever, setSelectedRetriever] = useState(null); - const [retrieverParamsSchema, setRetrieverParamsSchema] = useState(null); + const [schemaDialogOpen, setSchemaDialogOpen] = useState(false); + const { modelSchema: retrieverModelSchema, defaultValues: retrieverInitialParameters, @@ -38,10 +49,6 @@ export default function RetrieverConfigurationStep({ setNextEnabled }) { loading: retrieverLoading, } = useSchema({ modelName: selectedRetriever?.name }); - - const [schemaDialogOpen, setSchemaDialogOpen] = useState(false); - const handleSchemaDialogClose = () => setSchemaDialogOpen(false); - const fetchRetrievalParadigms = async () => { try { const data = await getRetrievalParadigm(); @@ -64,15 +71,14 @@ export default function RetrieverConfigurationStep({ setNextEnabled }) { return; } - if (selectedRetrievalParadigm.name === "SparseRetriever") { - const retrievers = await getRetrieverComponents(selectedRetrievalParadigm.name); - setRetrieverOptions(retrievers); - setSelectedRetriever(null); - } else { - setRetrieverOptions([selectedRetrievalParadigm]); - setSelectedRetriever(selectedRetrievalParadigm); - } - + if (selectedRetrievalParadigm.name === "SparseRetriever") { + const retrievers = await getRetrieverComponents(selectedRetrievalParadigm.name); + setRetrieverOptions(retrievers); + setSelectedRetriever(null); + } else { + setRetrieverOptions([selectedRetrievalParadigm]); + setSelectedRetriever(selectedRetrievalParadigm); + } }; useEffect(() => { @@ -81,7 +87,7 @@ export default function RetrieverConfigurationStep({ setNextEnabled }) { const handleRetrievalParadigmChange = (event, newValue) => { setSelectedRetrievalParadigm(newValue); - fetchRetrievers() + fetchRetrievers(); }; const handleRetrieverSelectionChange = (event, newValue) => { @@ -95,7 +101,7 @@ export default function RetrieverConfigurationStep({ setNextEnabled }) { parameters: newParams, })); console.log("Updated retriever model parameters:", newParams); - } + }; return ( [ - <> - } - label="Edit" - onClick={() => setSchemaDialogOpen(true)} - /> - [ + + } + label="Edit" + onClick={() => setSchemaDialogOpen(true)} + /> + setSchemaDialogOpen(false)} PaperProps={{ sx: { width: { md: 820 }, @@ -169,33 +174,19 @@ export default function RetrieverConfigurationStep({ setNextEnabled }) { }} > - - - - - - - {`${selectedRetriever.name} configuration`} - - - - - - { - handleRetrieverParametersChange(values); - setSchemaDialogOpen(false); - }} - onCancel={() => setSchemaDialogOpen(false)} - /> - - - - - ], - }]} + + + + + ], + }, + ]} hideFooter disableColumnMenu disableColumnSelector @@ -211,4 +202,89 @@ export default function RetrieverConfigurationStep({ setNextEnabled }) { )} ); +} + +function RetrieverConfigurationStepSubComponent({ + selectedRetriever, + retrieverInitialParameters, + schemaDialogOpen, + setSchemaDialogOpen, + handleRetrieverParametersChange, +}) { + const { + formValues, + properties, + propertyData, + valuesByProperties, + removeLastProperty, + setErrorForm, + } = useFormSchemaStore(); + + const [selectedModel, setSelectedModel] = useState( + selectedRetriever?.name || propertyData?.model, + ); + + const selectedProperty = Boolean(propertyData?.selected); + + const defaultValues = useMemo(() => { + if (selectedProperty) { + if (propertyData.params) { + return propertyData.params; + } else return null; + } + return retrieverInitialParameters ?? valuesByProperties; + }, [selectedModel, propertyData.params]); + + useEffect(() => { + if (propertyData.model) { + setSelectedModel(propertyData.model); + } else { + setSelectedModel(selectedRetriever?.name); + } + }, [propertyData.model, propertyData.params, selectedRetriever?.name]); + + return ( + <> + + + setSchemaDialogOpen(false)}> + + + + {`${selectedRetriever.name} configuration`} + + + + + + {Boolean(propertyData?.parent) && ( + <> + + + + )} + { + handleRetrieverParametersChange(formValues); + setSchemaDialogOpen(false); + }} + setError={setErrorForm} + onCancel={() => { + if (properties.length > 0) { + removeLastProperty(); + } else { + setSchemaDialogOpen(false); + } + }} + /> + + + + ); } \ No newline at end of file From 0d1143f3fe8458dcb07ca876e653292a578a4e22 Mon Sep 17 00:00:00 2001 From: sofiachavezb Date: Fri, 12 Sep 2025 11:58:48 -0300 Subject: [PATCH 012/218] awful retriever model working --- .../RAG/RetrieverConfigurationStep.jsx | 245 +++++++----------- 1 file changed, 98 insertions(+), 147 deletions(-) diff --git a/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx b/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx index c8c5cc2db..c34fd58a7 100644 --- a/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx +++ b/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx @@ -24,8 +24,6 @@ import { useSnackbar } from "notistack"; import useSchema from "../../../hooks/useSchema"; import SettingsIcon from "@mui/icons-material/Settings"; import { GridActionsCellItem } from "@mui/x-data-grid"; -import FormSchemaDialog from "../../../components/shared/FormSchemaDialog"; -import FormSchemaWithSelectedModel from "../../../components/shared/FormSchemaWithSelectedModel"; import FormSchemaModelSelect from "../../../components/shared/FormSchemaModelSelect"; import FormSchemaContainer from "../../../components/shared/FormSchemaContainer"; import { useFormSchemaStore } from "../../../contexts/schema"; @@ -33,6 +31,7 @@ import FormSchemaBreadScrumbs from "../../../components/shared/FormSchemaBreadSc import FormSchema from "../../../components/shared/FormSchema"; + export default function RetrieverConfigurationStep({ setNextEnabled }) { const { enqueueSnackbar } = useSnackbar(); const [retrievalParadigms, setRetrievalParadigms] = useState([]); @@ -40,15 +39,11 @@ export default function RetrieverConfigurationStep({ setNextEnabled }) { const [retrieverOptions, setRetrieverOptions] = useState([]); const [selectedRetriever, setSelectedRetriever] = useState(null); - const [schemaDialogOpen, setSchemaDialogOpen] = useState(false); - const { - modelSchema: retrieverModelSchema, - defaultValues: retrieverInitialParameters, - yupSchema: retrieverYupSchema, - loading: retrieverLoading, - } = useSchema({ modelName: selectedRetriever?.name }); + const {defaultValues: retrieverInitialParameters} = useSchema({ modelName: selectedRetriever?.name }); + + // Fetch paradigms const fetchRetrievalParadigms = async () => { try { const data = await getRetrievalParadigm(); @@ -64,13 +59,13 @@ export default function RetrieverConfigurationStep({ setNextEnabled }) { fetchRetrievalParadigms(); }, []); - const fetchRetrievers = async () => { + // Fetch retrievers when paradigm changes + const fetchRetrievers = useCallback(async () => { if (!selectedRetrievalParadigm) { setRetrieverOptions([]); setSelectedRetriever(null); return; } - if (selectedRetrievalParadigm.name === "SparseRetriever") { const retrievers = await getRetrieverComponents(selectedRetrievalParadigm.name); setRetrieverOptions(retrievers); @@ -79,136 +74,102 @@ export default function RetrieverConfigurationStep({ setNextEnabled }) { setRetrieverOptions([selectedRetrievalParadigm]); setSelectedRetriever(selectedRetrievalParadigm); } - }; + }, [selectedRetrievalParadigm]); useEffect(() => { fetchRetrievers(); - }, [selectedRetrievalParadigm]); + }, [selectedRetrievalParadigm, fetchRetrievers]); + // Handle paradigm change const handleRetrievalParadigmChange = (event, newValue) => { setSelectedRetrievalParadigm(newValue); - fetchRetrievers(); + setSelectedRetriever(null); // Reset retriever selection }; + // Handle retriever change const handleRetrieverSelectionChange = (event, newValue) => { setSelectedRetriever(newValue); - console.log("Selected retriever model:", newValue); + // Optionally reset config if needed }; + // Handle config change const handleRetrieverParametersChange = (newParams) => { setSelectedRetriever((prev) => ({ ...prev, parameters: newParams, })); - console.log("Updated retriever model parameters:", newParams); + setNextEnabled(true); }; + // Layout: two columns if retriever selected, else one column return ( - - - Select retrieval paradigm - - - option.name} - value={selectedRetrievalParadigm} - onChange={handleRetrievalParadigmChange} - isOptionEqualToValue={(option, value) => option.name === value?.name} - renderInput={(params) => } - sx={{ mb: 3 }} - /> - - {selectedRetrievalParadigm && selectedRetrievalParadigm.name === "SparseRetriever" && ( + + {/* Left column: paradigm/model selection */} + + + Select retrieval paradigm + option.name} - value={selectedRetriever} - onChange={handleRetrieverSelectionChange} + value={selectedRetrievalParadigm} + onChange={handleRetrievalParadigmChange} isOptionEqualToValue={(option, value) => option.name === value?.name} - renderInput={(params) => } - sx={{ mb: 3 }} + renderInput={(params) => } + sx={{ mb: 2 }} /> - )} + {selectedRetrievalParadigm && selectedRetrievalParadigm.name === "SparseRetriever" && ( + <> + + Select retriever model + + option.name} + value={selectedRetriever} + onChange={handleRetrieverSelectionChange} + isOptionEqualToValue={(option, value) => option.name === value?.name} + renderInput={(params) => } + /> + + )} + {selectedRetriever && selectedRetriever.schema && !selectedRetriever.schema.properties && ( + + No parameters available for this retriever. + + )} + + {/* Right column: configuration, only if retriever selected */} {selectedRetriever && ( - - - Configure retriever model - - [ - - } - label="Edit" - onClick={() => setSchemaDialogOpen(true)} - /> - setSchemaDialogOpen(false)} - PaperProps={{ - sx: { - width: { md: 820 }, - maxHeight: { lg: 700, xl: "auto" }, - maxWidth: 2000, - transition: "width 0.3s ease, height 0.3s ease", - }, - }} - > - - - - - - ], - }, - ]} - hideFooter - disableColumnMenu - disableColumnSelector - disableSelectionOnClick - /> + + + + )} - - {selectedRetriever && selectedRetriever.schema && !selectedRetriever.schema.properties && ( - - No parameters available for this retriever. - - )} ); } -function RetrieverConfigurationStepSubComponent({ +function ModelConfigurationSubcomponent({ selectedRetriever, retrieverInitialParameters, - schemaDialogOpen, - setSchemaDialogOpen, handleRetrieverParametersChange, }) { const { @@ -244,47 +205,37 @@ function RetrieverConfigurationStepSubComponent({ }, [propertyData.model, propertyData.params, selectedRetriever?.name]); return ( - <> - - - setSchemaDialogOpen(false)}> - - - - {`${selectedRetriever.name} configuration`} - - - - - - {Boolean(propertyData?.parent) && ( - <> - - - - )} - { - handleRetrieverParametersChange(formValues); - setSchemaDialogOpen(false); - }} - setError={setErrorForm} - onCancel={() => { - if (properties.length > 0) { - removeLastProperty(); - } else { - setSchemaDialogOpen(false); - } - }} + + + + + {`${selectedRetriever.name} configuration`} + + + {console.log("propertyData:", propertyData)} + {Boolean(propertyData?.parent) && ( + <> + + - - - + + )} + { + handleRetrieverParametersChange(formValues); + }} + setError={setErrorForm} + onCancel={() => { + if (properties.length > 0) { + removeLastProperty(); + } + }} + /> + ); } \ No newline at end of file From 1109f664f48abd6509d772d825cd98e2ce3e12d5 Mon Sep 17 00:00:00 2001 From: sofiachavezb Date: Tue, 16 Sep 2025 15:34:02 -0300 Subject: [PATCH 013/218] backup pre dev branch update --- DashAI/back/initial_components.py | 20 +- DashAI/back/models/RAG/RAG_pipeline.py | 10 + DashAI/back/models/RAG/Retrievers/__init__.py | 2 +- .../models/RAG/Retrievers/dense_retriever.py | 2 +- .../models/RAG/Retrievers/tfidf_retriever.py | 140 +++++++++- DashAI/back/models/RAG/__init__.py | 2 +- DashAI/back/models/RAG/dummy_retriever.py | 1 - DashAI/back/models/RAG/embeddings/__init__.py | 4 + .../models/RAG/embeddings/dense/__init__.py | 2 + .../dense/fasttext_embedding.py | 7 +- .../dense/huggingface_embedding.py | 6 +- .../dense_encoding.py} | 2 +- .../models/RAG/embeddings/sparse/__init__.py | 2 + .../sparse/bm25_encoding.py | 3 +- .../sparse/tfidf_encoding.py | 3 +- .../trainable_encoding.py | 4 +- DashAI/back/models/RAG/encodings/__init__.py | 6 - .../models/RAG/encodings/dense/__init__.py | 2 - .../models/RAG/encodings/dense_encoding.py | 24 -- .../models/RAG/encodings/sparse/__init__.py | 2 - .../models/RAG/encodings/sparse_encoding.py | 29 --- DashAI/front/src/api/rag.ts | 8 + .../RAG/ChunkingConfigurationStep.jsx | 85 ++++++ .../pages/generative/RAG/NewSessionModal.jsx | 31 ++- .../RAG/RetrieverConfigurationStep copy.jsx | 241 ++++++++++++++++++ .../RAG/RetrieverConfigurationStep.jsx | 113 ++------ 26 files changed, 553 insertions(+), 198 deletions(-) create mode 100644 DashAI/back/models/RAG/embeddings/__init__.py create mode 100644 DashAI/back/models/RAG/embeddings/dense/__init__.py rename DashAI/back/models/RAG/{encodings => embeddings}/dense/fasttext_embedding.py (88%) rename DashAI/back/models/RAG/{encodings => embeddings}/dense/huggingface_embedding.py (95%) rename DashAI/back/models/RAG/{encodings/encoding.py => embeddings/dense_encoding.py} (97%) create mode 100644 DashAI/back/models/RAG/embeddings/sparse/__init__.py rename DashAI/back/models/RAG/{encodings => embeddings}/sparse/bm25_encoding.py (98%) rename DashAI/back/models/RAG/{encodings => embeddings}/sparse/tfidf_encoding.py (99%) rename DashAI/back/models/RAG/{encodings => embeddings}/trainable_encoding.py (95%) delete mode 100644 DashAI/back/models/RAG/encodings/__init__.py delete mode 100644 DashAI/back/models/RAG/encodings/dense/__init__.py delete mode 100644 DashAI/back/models/RAG/encodings/dense_encoding.py delete mode 100644 DashAI/back/models/RAG/encodings/sparse/__init__.py delete mode 100644 DashAI/back/models/RAG/encodings/sparse_encoding.py create mode 100644 DashAI/front/src/pages/generative/RAG/ChunkingConfigurationStep.jsx create mode 100644 DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep copy.jsx diff --git a/DashAI/back/initial_components.py b/DashAI/back/initial_components.py index 0b73a8fb8..ba636a57a 100644 --- a/DashAI/back/initial_components.py +++ b/DashAI/back/initial_components.py @@ -98,19 +98,17 @@ CharacterChunkModel, TokenChunkModel, # Encodings - DenseEncoding, + DenseEmbedding, FastTextEmbedding, HuggingFaceEmbedding, - SparseEncoding, - TFIDFEncoding, - BM25Encoding, # Prompts AugmentationPrompt, ContextMergePrompt, # Retrievers DenseRetriever, SparseRetriever, - TFIDFRetriever + TFIDFRetriever, + TFIDFVectorizerModel, ) @@ -267,20 +265,22 @@ def get_initial_components(): # RAG CharacterChunkModel, TokenChunkModel, + # Chunking Models + CharacterChunkModel, + TokenChunkModel, # Encodings - DenseEncoding, + DenseEmbedding, FastTextEmbedding, HuggingFaceEmbedding, - SparseEncoding, - TFIDFEncoding, - BM25Encoding, # Prompts AugmentationPrompt, ContextMergePrompt, # Retrievers DenseRetriever, SparseRetriever, - TFIDFRetriever + TFIDFRetriever, + TFIDFVectorizerModel, + ] # Obtener plugins instalados diff --git a/DashAI/back/models/RAG/RAG_pipeline.py b/DashAI/back/models/RAG/RAG_pipeline.py index 854254d43..63f3b9c60 100644 --- a/DashAI/back/models/RAG/RAG_pipeline.py +++ b/DashAI/back/models/RAG/RAG_pipeline.py @@ -48,6 +48,16 @@ class RAGPipelineSchema(BaseSchema): description="List of documents to be used in the RAG pipeline." ) # type: ignore + chunking_model: schema_field( + component_field( + parent="BaseChunkingModel"), + description="Chunking model used to split documents into smaller pieces.", + placeholder={ + "component": "CharacterChunkModel", + "params": {} + } + ) # type: ignore + # RAG algorithm parameters retriever_model: schema_field( component_field(parent="RetrieverModel"), diff --git a/DashAI/back/models/RAG/Retrievers/__init__.py b/DashAI/back/models/RAG/Retrievers/__init__.py index 1da8bcd36..3e0d609ce 100644 --- a/DashAI/back/models/RAG/Retrievers/__init__.py +++ b/DashAI/back/models/RAG/Retrievers/__init__.py @@ -1,4 +1,4 @@ from DashAI.back.models.RAG.Retrievers.retriever_model import RetrieverModel -from DashAI.back.models.RAG.Retrievers.tfidf_retriever import TFIDFRetriever +from DashAI.back.models.RAG.Retrievers.tfidf_retriever import TFIDFRetriever, TFIDFVectorizerModel from DashAI.back.models.RAG.Retrievers.dense_retriever import DenseRetriever from DashAI.back.models.RAG.Retrievers.sparse_retriever import SparseRetriever \ No newline at end of file diff --git a/DashAI/back/models/RAG/Retrievers/dense_retriever.py b/DashAI/back/models/RAG/Retrievers/dense_retriever.py index 1ef42567f..6e4d8726e 100644 --- a/DashAI/back/models/RAG/Retrievers/dense_retriever.py +++ b/DashAI/back/models/RAG/Retrievers/dense_retriever.py @@ -19,7 +19,7 @@ class DenseRetrieverSchema(BaseSchema): encoding_model: schema_field( component_field( - parent="Encoding" + parent="DenseEmbedding" ), placeholder={"component": "Embedding", "params": {}}, description="Model to convert text into dense vector representations." diff --git a/DashAI/back/models/RAG/Retrievers/tfidf_retriever.py b/DashAI/back/models/RAG/Retrievers/tfidf_retriever.py index 6f2cf771a..4bda9de14 100644 --- a/DashAI/back/models/RAG/Retrievers/tfidf_retriever.py +++ b/DashAI/back/models/RAG/Retrievers/tfidf_retriever.py @@ -15,19 +15,147 @@ enum_field, float_field, int_field, + list_field, + string_field, + bool_field, + component_field ) +from DashAI.back.models.base_model import BaseModel similarities = { "cosine": cosine_similarity, "euclidean": euclidean_distances } +class TFIDFVectorizerSchema(BaseSchema): + + strip_accents: schema_field( + enum_field( + enum=["ascii", "unicode", None], + ), + placeholder=None, + description="Whether to strip accents from the text.", + ) # type: ignore + + lowercase: schema_field( + bool_field(), + placeholder=True, + description="Whether to convert all characters to lowercase.", + + ) # type: ignore + + analyzer: schema_field( + enum_field( + enum=["word", "char", "char_wb"], + ), + placeholder="word", + description="Whether the feature should be made of word or character n-grams. Option 'char_wb' creates character n-grams only from text inside word boundaries; n-grams at the edges of words are padded with space.", + ) # type: ignore + + stop_words: schema_field( + list_field( + string_field(), + min_items=1, + ), + placeholder=None, + description="List of stop words to be used in the TF-IDF vectorization.", + ) # type: ignore + + ngram_range: schema_field( + list_field( + int_field(), + min_items=2, + max_items=2, + ), + placeholder=[1, 1], + description="The lower and upper boundary of the range of n-values for different n-grams to be extracted.", + ) # type: ignore + + max_df: schema_field( + float_field( + ge=0.0, + le=1.0, + ), + placeholder=1.0, + description="When building the vocabulary ignore terms that have a document frequency strictly higher than the given threshold (corpus-specific stop words).", + ) # type: ignore + + min_df: schema_field( + float_field( + ge=0.0, + le=1.0, + ), + placeholder=1.0, + description="When building the vocabulary ignore terms that have a document frequency strictly lower than the given threshold (corpus-specific stop words).", + ) # type: ignore + + max_features: schema_field( + int_field( + ge=1, + ), + placeholder=None, + description="If not None, build a vocabulary that only consider the top max_features ordered by term frequency across the corpus.", + ) # type: ignore + + norm: schema_field( + enum_field( + enum=["l1", "l2", None], + ), + placeholder="l2", + description="The norm used to normalize term vectors. If None, no normalization is applied.", + ) # type: ignore + + use_idf: schema_field( + bool_field(), + placeholder=True, + description="Enable inverse-document-frequency reweighting.", + ) # type: ignore + + smooth_idf: schema_field( + bool_field(), + placeholder=True, + description="Smooth idf weights by adding one to document frequencies, as if an extra document was seen containing every term in the collection exactly once. This prevents zero divisions.", + ) # type: ignore + + sublinear_tf: schema_field( + bool_field(), + placeholder=False, + description="Apply sublinear tf scaling, i.e. replace tf with 1 + log(tf).", + ) # type: ignore + +class TFIDFVectorizerModel(BaseModel): + + SCHEMA = TFIDFVectorizerSchema + + def __init__(self, **kwargs) -> None: + self.params = kwargs + self.model = TfidfVectorizer( + strip_accents=kwargs.get("strip_accents", None), + lowercase=kwargs.get("lowercase", True), + analyzer=kwargs.get("analyzer", "word"), + stop_words=kwargs.get("stop_words", None), + ngram_range=tuple(kwargs.get("ngram_range", (1, 1))), + max_df=kwargs.get("max_df", 1.0), + min_df=kwargs.get("min_df", 1.0), + max_features=kwargs.get("max_features", None), + norm=kwargs.get("norm", "l2"), + use_idf=kwargs.get("use_idf", True), + smooth_idf=kwargs.get("smooth_idf", True), + sublinear_tf=kwargs.get("sublinear_tf", False), + ) class TFIDFRetrieverSchema(BaseSchema): """ Schema for the TFIDFRetriever. """ + TFIDFVectorizer: schema_field( + component_field(parent="TFIDFVectorizerModel"), + placeholder={"component": "TFIDFVectorizerModel", "params": {}}, + description="TF-IDF Vectorizer parameters.", + ) # type: ignore + + similarity_function: schema_field( enum_field(['cosine', 'euclidean']), placeholder="cosine", @@ -46,18 +174,6 @@ class TFIDFRetrieverSchema(BaseSchema): description="Maximum or minimum distance for retrieved documents based on the similarity_function." ) # type: ignore - chunk_size: schema_field( - int_field(ge=1), - placeholder=512, - description="Size of chunks to split the documents into." - ) # type: ignore - - chunk_overlap: schema_field( - int_field(ge=0), - placeholder=50, - description="Overlap between chunks when splitting documents." - ) # type: ignore - class TFIDFRetriever(SparseRetriever): """ A retriever that uses TF-IDF to retrieve documents based on a query. diff --git a/DashAI/back/models/RAG/__init__.py b/DashAI/back/models/RAG/__init__.py index 88a96fe60..189e18114 100644 --- a/DashAI/back/models/RAG/__init__.py +++ b/DashAI/back/models/RAG/__init__.py @@ -1,6 +1,6 @@ from DashAI.back.models.RAG.chunking_models import * from DashAI.back.models.RAG.documents import * -from DashAI.back.models.RAG.encodings import * +from DashAI.back.models.RAG.embeddings import * from DashAI.back.models.RAG.prompts import * from DashAI.back.models.RAG.Retrievers import * diff --git a/DashAI/back/models/RAG/dummy_retriever.py b/DashAI/back/models/RAG/dummy_retriever.py index 2f781668d..6a7136599 100644 --- a/DashAI/back/models/RAG/dummy_retriever.py +++ b/DashAI/back/models/RAG/dummy_retriever.py @@ -3,7 +3,6 @@ #from chromadb import Settings from typing import List, Dict from pypdf import PdfReader -from DashAI.back.models.RAG.encodings.tf_idf_encoding import TfidfEmbeddingFunction from DashAI.back.models.RAG.text_splitter import TextSplitter from DashAI.back.models.RAG.text_preprocessor import TextPreprocessor diff --git a/DashAI/back/models/RAG/embeddings/__init__.py b/DashAI/back/models/RAG/embeddings/__init__.py new file mode 100644 index 000000000..c6c567767 --- /dev/null +++ b/DashAI/back/models/RAG/embeddings/__init__.py @@ -0,0 +1,4 @@ +from DashAI.back.models.RAG.embeddings.dense_encoding import DenseEmbedding +from DashAI.back.models.RAG.embeddings.trainable_encoding import TrainableEncoding +from DashAI.back.models.RAG.embeddings.sparse import * +from DashAI.back.models.RAG.embeddings.dense import * \ No newline at end of file diff --git a/DashAI/back/models/RAG/embeddings/dense/__init__.py b/DashAI/back/models/RAG/embeddings/dense/__init__.py new file mode 100644 index 000000000..860badbfe --- /dev/null +++ b/DashAI/back/models/RAG/embeddings/dense/__init__.py @@ -0,0 +1,2 @@ +from DashAI.back.models.RAG.embeddings.dense.fasttext_embedding import FastTextEmbedding +from DashAI.back.models.RAG.embeddings.dense.huggingface_embedding import HuggingFaceEmbedding \ No newline at end of file diff --git a/DashAI/back/models/RAG/encodings/dense/fasttext_embedding.py b/DashAI/back/models/RAG/embeddings/dense/fasttext_embedding.py similarity index 88% rename from DashAI/back/models/RAG/encodings/dense/fasttext_embedding.py rename to DashAI/back/models/RAG/embeddings/dense/fasttext_embedding.py index 12c5e9e74..cf4f4bcbb 100644 --- a/DashAI/back/models/RAG/encodings/dense/fasttext_embedding.py +++ b/DashAI/back/models/RAG/embeddings/dense/fasttext_embedding.py @@ -3,13 +3,14 @@ import numpy as np from DashAI.back.core.schema_fields import enum_field +from DashAI.back.core.schema_fields.base_schema import BaseSchema from DashAI.back.core.schema_fields.schema_field import schema_field -from DashAI.back.models.RAG.encodings.dense_encoding import DenseEncoding +from DashAI.back.models.RAG.embeddings.dense_encoding import DenseEmbedding import fasttext from huggingface_hub import hf_hub_download -class FastTextEmbeddingSchema(DenseEncoding.SCHEMA): +class FastTextEmbeddingSchema(BaseSchema): model_name: schema_field( enum_field( [ @@ -32,7 +33,7 @@ class FastTextEmbeddingSchema(DenseEncoding.SCHEMA): "Pooling strategy to use", ) # type: ignore -class FastTextEmbedding(DenseEncoding): +class FastTextEmbedding(DenseEmbedding): """FastText embedding""" SCHEMA = FastTextEmbeddingSchema diff --git a/DashAI/back/models/RAG/encodings/dense/huggingface_embedding.py b/DashAI/back/models/RAG/embeddings/dense/huggingface_embedding.py similarity index 95% rename from DashAI/back/models/RAG/encodings/dense/huggingface_embedding.py rename to DashAI/back/models/RAG/embeddings/dense/huggingface_embedding.py index 23ce06f24..09ab807f1 100644 --- a/DashAI/back/models/RAG/encodings/dense/huggingface_embedding.py +++ b/DashAI/back/models/RAG/embeddings/dense/huggingface_embedding.py @@ -6,14 +6,12 @@ schema_field, enum_field ) -from DashAI.back.models.RAG.encodings.dense_encoding import DenseEncoding - from typing import Final, List import numpy as np import torch from transformers import AutoModel, AutoTokenizer -from DashAI.back.models.RAG.encodings.dense_encoding import DenseEncoding +from DashAI.back.models.RAG.embeddings.dense_encoding import DenseEmbedding from DashAI.back.core.schema_fields import ( enum_field, int_field, @@ -67,7 +65,7 @@ class HuggingFaceEmbeddingSchema(BaseSchema): ) # type: ignore -class HuggingFaceEmbedding(DenseEncoding): +class HuggingFaceEmbedding(DenseEmbedding): """HuggingFace embedding""" SCHEMA = HuggingFaceEmbeddingSchema diff --git a/DashAI/back/models/RAG/encodings/encoding.py b/DashAI/back/models/RAG/embeddings/dense_encoding.py similarity index 97% rename from DashAI/back/models/RAG/encodings/encoding.py rename to DashAI/back/models/RAG/embeddings/dense_encoding.py index 0e2d65c9c..64a4e1966 100644 --- a/DashAI/back/models/RAG/encodings/encoding.py +++ b/DashAI/back/models/RAG/embeddings/dense_encoding.py @@ -6,7 +6,7 @@ from DashAI.back.models.RAG.documents.BaseDocument import BaseDocument from DashAI.back.models.base_model import BaseModel -class Encoding(BaseModel): +class DenseEmbedding(BaseModel): """ Base class for all encoding (embedding) models. This class should be inherited by any specific encoding (embedding) model implementation. diff --git a/DashAI/back/models/RAG/embeddings/sparse/__init__.py b/DashAI/back/models/RAG/embeddings/sparse/__init__.py new file mode 100644 index 000000000..368a87c05 --- /dev/null +++ b/DashAI/back/models/RAG/embeddings/sparse/__init__.py @@ -0,0 +1,2 @@ +from DashAI.back.models.RAG.embeddings.sparse.bm25_encoding import BM25Encoding +from DashAI.back.models.RAG.embeddings.sparse.tfidf_encoding import TFIDFEncoding \ No newline at end of file diff --git a/DashAI/back/models/RAG/encodings/sparse/bm25_encoding.py b/DashAI/back/models/RAG/embeddings/sparse/bm25_encoding.py similarity index 98% rename from DashAI/back/models/RAG/encodings/sparse/bm25_encoding.py rename to DashAI/back/models/RAG/embeddings/sparse/bm25_encoding.py index f239a893d..0a57bdabc 100644 --- a/DashAI/back/models/RAG/encodings/sparse/bm25_encoding.py +++ b/DashAI/back/models/RAG/embeddings/sparse/bm25_encoding.py @@ -1,6 +1,5 @@ import os from DashAI.back.converters.hugging_face import embedding -from DashAI.back.models.RAG.encodings.sparse_encoding import SparseEncoding from DashAI.back.models.RAG.documents import BaseDocument, PDFDocument, TxtDocument from typing import List, Dict, Any, Tuple from sklearn.feature_extraction.text import TfidfVectorizer @@ -73,7 +72,7 @@ class BM25EncodingSchema(BaseSchema): ) # type: ignore -class BM25Encoding(SparseEncoding): +class BM25Encoding: """ BM25 encoding (embedding) model for text documents. This class implements the precomputation of BM25 scores for text documents. diff --git a/DashAI/back/models/RAG/encodings/sparse/tfidf_encoding.py b/DashAI/back/models/RAG/embeddings/sparse/tfidf_encoding.py similarity index 99% rename from DashAI/back/models/RAG/encodings/sparse/tfidf_encoding.py rename to DashAI/back/models/RAG/embeddings/sparse/tfidf_encoding.py index 560d6c2f2..ce32a30d0 100644 --- a/DashAI/back/models/RAG/encodings/sparse/tfidf_encoding.py +++ b/DashAI/back/models/RAG/embeddings/sparse/tfidf_encoding.py @@ -1,6 +1,5 @@ import os from DashAI.back.converters.hugging_face import embedding -from DashAI.back.models.RAG.encodings.sparse_encoding import SparseEncoding from DashAI.back.models.RAG.documents import BaseDocument, PDFDocument, TxtDocument from typing import List, Dict, Any, Tuple from sklearn.feature_extraction.text import TfidfVectorizer @@ -116,7 +115,7 @@ class TFIDFEncodingSchema(BaseSchema): description="Apply sublinear tf scaling, i.e. replace tf with 1 + log(tf).", ) # type: ignore -class TFIDFEncoding(SparseEncoding): +class TFIDFEncoding: """ TF-IDF encoding (embedding) model for text documents. This class implements the TF-IDF algorithm to generate encodings (embeddings) for text documents. diff --git a/DashAI/back/models/RAG/encodings/trainable_encoding.py b/DashAI/back/models/RAG/embeddings/trainable_encoding.py similarity index 95% rename from DashAI/back/models/RAG/encodings/trainable_encoding.py rename to DashAI/back/models/RAG/embeddings/trainable_encoding.py index 44f032707..f3d8d1001 100644 --- a/DashAI/back/models/RAG/encodings/trainable_encoding.py +++ b/DashAI/back/models/RAG/embeddings/trainable_encoding.py @@ -4,9 +4,9 @@ import numpy as np from DashAI.back.models.RAG.documents.BaseDocument import BaseDocument -from DashAI.back.models.RAG.encodings.encoding import Encoding +from DashAI.back.models.RAG.embeddings.dense_encoding import DenseEmbedding -class TrainableEncoding(Encoding): +class TrainableEncoding(DenseEmbedding): """ Base class for all encoding (embedding) models. This class should be inherited by any specific encoding (embedding) model implementation. diff --git a/DashAI/back/models/RAG/encodings/__init__.py b/DashAI/back/models/RAG/encodings/__init__.py deleted file mode 100644 index bf36b680c..000000000 --- a/DashAI/back/models/RAG/encodings/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from DashAI.back.models.RAG.encodings.encoding import Encoding -from DashAI.back.models.RAG.encodings.dense_encoding import DenseEncoding -from DashAI.back.models.RAG.encodings.sparse_encoding import SparseEncoding -from DashAI.back.models.RAG.encodings.trainable_encoding import TrainableEncoding -from DashAI.back.models.RAG.encodings.sparse import * -from DashAI.back.models.RAG.encodings.dense import * \ No newline at end of file diff --git a/DashAI/back/models/RAG/encodings/dense/__init__.py b/DashAI/back/models/RAG/encodings/dense/__init__.py deleted file mode 100644 index 549f15377..000000000 --- a/DashAI/back/models/RAG/encodings/dense/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from DashAI.back.models.RAG.encodings.dense.fasttext_embedding import FastTextEmbedding -from DashAI.back.models.RAG.encodings.dense.huggingface_embedding import HuggingFaceEmbedding \ No newline at end of file diff --git a/DashAI/back/models/RAG/encodings/dense_encoding.py b/DashAI/back/models/RAG/encodings/dense_encoding.py deleted file mode 100644 index 37b7ff6ba..000000000 --- a/DashAI/back/models/RAG/encodings/dense_encoding.py +++ /dev/null @@ -1,24 +0,0 @@ - -from DashAI.back.models.RAG.encodings.encoding import Encoding - - -class DenseEncoding(Encoding): - """ - Base class for all dense encoding (embedding) models. - """ - - def __init__(self, **kwargs): - """ - Initialize the dense encoding (embedding) model with the given documents. - """ - raise NotImplementedError("Subclasses must implement the __init__ method.") - - def encode(self, text: str): - """ - Method to generate dense encodings (embeddings) for the given text. - This method should be implemented by subclasses. - - :param text: The input text to encode (embed). - :return: A list representing the dense encodings (embeddings) of the input text. - """ - raise NotImplementedError("Subclasses must implement this method.") \ No newline at end of file diff --git a/DashAI/back/models/RAG/encodings/sparse/__init__.py b/DashAI/back/models/RAG/encodings/sparse/__init__.py deleted file mode 100644 index a2aa69555..000000000 --- a/DashAI/back/models/RAG/encodings/sparse/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from DashAI.back.models.RAG.encodings.sparse.bm25_encoding import BM25Encoding -from DashAI.back.models.RAG.encodings.sparse.tfidf_encoding import TFIDFEncoding \ No newline at end of file diff --git a/DashAI/back/models/RAG/encodings/sparse_encoding.py b/DashAI/back/models/RAG/encodings/sparse_encoding.py deleted file mode 100644 index cadba17d6..000000000 --- a/DashAI/back/models/RAG/encodings/sparse_encoding.py +++ /dev/null @@ -1,29 +0,0 @@ -import numpy as np -from DashAI.back.models.RAG.documents import BaseDocument -from DashAI.back.models.RAG.encodings.encoding import Encoding -from typing import Any, List - -class SparseEncoding(Encoding): - """ - Base class for sparse encoding (embedding) models. - This class should be inherited by any specific sparse encoding (embedding) model implementation. - """ - - def __init__(self, documents: List[BaseDocument], **kwargs: Any): - """ - Initialize the sparse encoding (embedding) model with the given documents. - - :param documents: List of documents to be embedded. - :param kwargs: Additional keyword arguments. - """ - raise NotImplementedError("Subclasses must implement the __init__ method.") - - def encode(self, text: str) -> List|np.ndarray|Any: - """ - Method to generate sparse encodings (embeddings) for the given text. - This method should be implemented by subclasses. - - :param text: The input text to embed. - :return: A list representing the sparse encodings (embeddings) of the input text. - """ - raise NotImplementedError("Subclasses must implement this method.") \ No newline at end of file diff --git a/DashAI/front/src/api/rag.ts b/DashAI/front/src/api/rag.ts index e4b95479a..b1d13100a 100644 --- a/DashAI/front/src/api/rag.ts +++ b/DashAI/front/src/api/rag.ts @@ -146,6 +146,14 @@ export const getGeneratorComponents = async (): Promise => { } +export const getChunkingComponents = async (): Promise => { + const response = await getChildComponents('BaseChunkingModel', false); + if (!response) { + throw new Error(`Failed to fetch chunking components`); + } + return response; +} + export const loadDocuments = async (): Promise => { const response = await api.get("/v1/document/"); if (response.status !== 200) { diff --git a/DashAI/front/src/pages/generative/RAG/ChunkingConfigurationStep.jsx b/DashAI/front/src/pages/generative/RAG/ChunkingConfigurationStep.jsx new file mode 100644 index 000000000..a9dd4b109 --- /dev/null +++ b/DashAI/front/src/pages/generative/RAG/ChunkingConfigurationStep.jsx @@ -0,0 +1,85 @@ +import React, { useState, useEffect, useCallback } from "react"; +import { Box, Autocomplete, TextField, Typography } from "@mui/material"; +import useSchema from "../../../hooks/useSchema"; +import { getChunkingComponents } from "../../../api/rag"; +import FormSchemaContainer from "../../../components/shared/FormSchemaContainer"; +import FormSchema from "../../../components/shared/FormSchema"; + +export default function ChunkingConfigurationStep({ chunkingModel, setChunkingModel, setNextEnabled }) { + const [chunkingOptions, setChunkingOptions] = useState([]); + const [selectedChunking, setSelectedChunking] = useState(null); + const { defaultValues } = useSchema({ modelName: selectedChunking?.name }); + + useEffect(() => { + const fetchChunkingModels = async () => { + const data = await getChunkingComponents(); + setChunkingOptions(data); + if (chunkingModel?.name) { + const existing = data.find(c => c.name === chunkingModel.name); + if (existing) setSelectedChunking(existing); + } + }; + fetchChunkingModels(); + }, [chunkingModel?.name]); + + useEffect(() => { + setNextEnabled(!!selectedChunking); + }, [selectedChunking, setNextEnabled]); + + const handleChunkingSelectionChange = (event, newValue) => { + setSelectedChunking(newValue); + if (newValue) { + setChunkingModel({ + name: newValue.name, + parameters: newValue.schema?.properties ? getInitialParamsFromSchema(newValue.schema.properties) : {}, + }); + } else { + setChunkingModel({ name: "", parameters: {} }); + } + }; + + const handleParametersChange = (params) => { + setChunkingModel({ + name: selectedChunking.name, + parameters: params, + }); + }; + + function getInitialParamsFromSchema(schemaProperties) { + if (!schemaProperties) return {}; + return Object.keys(schemaProperties).reduce((acc, key) => { + acc[key] = schemaProperties[key].placeholder !== undefined + ? schemaProperties[key].placeholder + : ""; + return acc; + }, {}); + } + + return ( + + + Configure Chunking Model + + option.name} + value={selectedChunking} + onChange={handleChunkingSelectionChange} + isOptionEqualToValue={(option, value) => option.name === value?.name} + renderInput={params => } + sx={{ mb: 3 }} + /> + {selectedChunking && selectedChunking.schema && ( + + setSelectedChunking(null)} + /> + + )} + + ); +} diff --git a/DashAI/front/src/pages/generative/RAG/NewSessionModal.jsx b/DashAI/front/src/pages/generative/RAG/NewSessionModal.jsx index d1377381f..f041ab7ad 100644 --- a/DashAI/front/src/pages/generative/RAG/NewSessionModal.jsx +++ b/DashAI/front/src/pages/generative/RAG/NewSessionModal.jsx @@ -17,9 +17,9 @@ import { useTheme } from "@mui/material/styles"; import useMediaQuery from "@mui/material/useMediaQuery"; import DocumentSelectionStep from "./DocumentSelectionStep"; +import ChunkingConfigurationStep from "./ChunkingConfigurationStep"; import RetrieverConfigurationStep from "./RetrieverConfigurationStep"; import GeneratorConfigurationStep from "./GeneratorConfigurationStep"; -//import ChunkingConfigurationStep from "./ChunkingConfigurationStep"; const steps = [ { @@ -27,11 +27,11 @@ const steps = [ label: "Select documents", component: DocumentSelectionStep, }, -// { -// name: "configure-chunking", -// label: "Configure chunking", -// component: ChunkingConfigurationStep, -// }, + { + name: "configure-chunking", + label: "Configure chunking", + component: ChunkingConfigurationStep, + }, { name: "configure-retriever", label: "Configure retriever", @@ -51,9 +51,9 @@ const defaultNewSession = { displayName: "", parameters: { "documents": [], - // "chunking": { - // "parameters": {}, - // }, + "chunking": { + "parameters": {}, + }, "retriever_model": { "name": "", "parameters": {}, @@ -241,6 +241,17 @@ export default function NewSessionModal({ /> )} {activeStep === 1 && ( + setSessionData(prev => ({ + ...prev, + parameters: { ...prev.parameters, chunking: model } + }))} + setNextEnabled={(isValid) => handleStepValidation(1, isValid)} + /> + )} + + {activeStep === 2 && ( setSessionData(prev => ({ @@ -250,7 +261,7 @@ export default function NewSessionModal({ setNextEnabled={(isValid) => handleStepValidation(1, isValid)} /> )} - {activeStep === 2 && ( + {activeStep === 3 && ( setSessionData(prev => ({ diff --git a/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep copy.jsx b/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep copy.jsx new file mode 100644 index 000000000..c34fd58a7 --- /dev/null +++ b/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep copy.jsx @@ -0,0 +1,241 @@ +import React, { + useState, + useEffect, + useCallback, + useMemo, +} from "react"; +import { + Box, + Dialog, + DialogTitle, + DialogContent, + Autocomplete, + TextField, + Typography, + IconButton, + Stack, + +} from "@mui/material"; +import ArrowBackOutlined from "@mui/icons-material/ArrowBackOutlined"; + +import { DataGrid } from "@mui/x-data-grid"; +import { getRetrieverComponents, getRetrievalParadigm } from "../../../api/rag"; +import { useSnackbar } from "notistack"; +import useSchema from "../../../hooks/useSchema"; +import SettingsIcon from "@mui/icons-material/Settings"; +import { GridActionsCellItem } from "@mui/x-data-grid"; +import FormSchemaModelSelect from "../../../components/shared/FormSchemaModelSelect"; +import FormSchemaContainer from "../../../components/shared/FormSchemaContainer"; +import { useFormSchemaStore } from "../../../contexts/schema"; +import FormSchemaBreadScrumbs from "../../../components/shared/FormSchemaBreadScrumbs"; +import FormSchema from "../../../components/shared/FormSchema"; + + + +export default function RetrieverConfigurationStep({ setNextEnabled }) { + const { enqueueSnackbar } = useSnackbar(); + const [retrievalParadigms, setRetrievalParadigms] = useState([]); + const [selectedRetrievalParadigm, setSelectedRetrievalParadigm] = useState(null); + + const [retrieverOptions, setRetrieverOptions] = useState([]); + const [selectedRetriever, setSelectedRetriever] = useState(null); + + const {defaultValues: retrieverInitialParameters} = useSchema({ modelName: selectedRetriever?.name }); + + + // Fetch paradigms + const fetchRetrievalParadigms = async () => { + try { + const data = await getRetrievalParadigm(); + setRetrievalParadigms(data); + enqueueSnackbar('Retrieval paradigms loaded successfully!', { variant: 'success' }); + } catch (error) { + console.error("Error fetching retrieval paradigms:", error); + enqueueSnackbar('Failed to load retrieval paradigms.', { variant: 'error' }); + } + }; + + useEffect(() => { + fetchRetrievalParadigms(); + }, []); + + // Fetch retrievers when paradigm changes + const fetchRetrievers = useCallback(async () => { + if (!selectedRetrievalParadigm) { + setRetrieverOptions([]); + setSelectedRetriever(null); + return; + } + if (selectedRetrievalParadigm.name === "SparseRetriever") { + const retrievers = await getRetrieverComponents(selectedRetrievalParadigm.name); + setRetrieverOptions(retrievers); + setSelectedRetriever(null); + } else { + setRetrieverOptions([selectedRetrievalParadigm]); + setSelectedRetriever(selectedRetrievalParadigm); + } + }, [selectedRetrievalParadigm]); + + useEffect(() => { + fetchRetrievers(); + }, [selectedRetrievalParadigm, fetchRetrievers]); + + // Handle paradigm change + const handleRetrievalParadigmChange = (event, newValue) => { + setSelectedRetrievalParadigm(newValue); + setSelectedRetriever(null); // Reset retriever selection + }; + + // Handle retriever change + const handleRetrieverSelectionChange = (event, newValue) => { + setSelectedRetriever(newValue); + // Optionally reset config if needed + }; + + // Handle config change + const handleRetrieverParametersChange = (newParams) => { + setSelectedRetriever((prev) => ({ + ...prev, + parameters: newParams, + })); + setNextEnabled(true); + }; + + // Layout: two columns if retriever selected, else one column + return ( + + {/* Left column: paradigm/model selection */} + + + Select retrieval paradigm + + option.name} + value={selectedRetrievalParadigm} + onChange={handleRetrievalParadigmChange} + isOptionEqualToValue={(option, value) => option.name === value?.name} + renderInput={(params) => } + sx={{ mb: 2 }} + /> + {selectedRetrievalParadigm && selectedRetrievalParadigm.name === "SparseRetriever" && ( + <> + + Select retriever model + + option.name} + value={selectedRetriever} + onChange={handleRetrieverSelectionChange} + isOptionEqualToValue={(option, value) => option.name === value?.name} + renderInput={(params) => } + /> + + )} + {selectedRetriever && selectedRetriever.schema && !selectedRetriever.schema.properties && ( + + No parameters available for this retriever. + + )} + + + {/* Right column: configuration, only if retriever selected */} + {selectedRetriever && ( + + + + + + )} + + ); +} + +function ModelConfigurationSubcomponent({ + selectedRetriever, + retrieverInitialParameters, + handleRetrieverParametersChange, +}) { + const { + formValues, + properties, + propertyData, + valuesByProperties, + removeLastProperty, + setErrorForm, + } = useFormSchemaStore(); + + const [selectedModel, setSelectedModel] = useState( + selectedRetriever?.name || propertyData?.model, + ); + + const selectedProperty = Boolean(propertyData?.selected); + + const defaultValues = useMemo(() => { + if (selectedProperty) { + if (propertyData.params) { + return propertyData.params; + } else return null; + } + return retrieverInitialParameters ?? valuesByProperties; + }, [selectedModel, propertyData.params]); + + useEffect(() => { + if (propertyData.model) { + setSelectedModel(propertyData.model); + } else { + setSelectedModel(selectedRetriever?.name); + } + }, [propertyData.model, propertyData.params, selectedRetriever?.name]); + + return ( + + + + + {`${selectedRetriever.name} configuration`} + + + {console.log("propertyData:", propertyData)} + {Boolean(propertyData?.parent) && ( + <> + + + + )} + { + handleRetrieverParametersChange(formValues); + }} + setError={setErrorForm} + onCancel={() => { + if (properties.length > 0) { + removeLastProperty(); + } + }} + /> + + ); +} \ No newline at end of file diff --git a/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx b/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx index c34fd58a7..5de8874ab 100644 --- a/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx +++ b/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx @@ -18,19 +18,17 @@ import { } from "@mui/material"; import ArrowBackOutlined from "@mui/icons-material/ArrowBackOutlined"; -import { DataGrid } from "@mui/x-data-grid"; import { getRetrieverComponents, getRetrievalParadigm } from "../../../api/rag"; import { useSnackbar } from "notistack"; import useSchema from "../../../hooks/useSchema"; -import SettingsIcon from "@mui/icons-material/Settings"; -import { GridActionsCellItem } from "@mui/x-data-grid"; + import FormSchemaModelSelect from "../../../components/shared/FormSchemaModelSelect"; import FormSchemaContainer from "../../../components/shared/FormSchemaContainer"; import { useFormSchemaStore } from "../../../contexts/schema"; import FormSchemaBreadScrumbs from "../../../components/shared/FormSchemaBreadScrumbs"; import FormSchema from "../../../components/shared/FormSchema"; - +import FormSchemaDialog from "../../../components/shared/FormSchemaDialog"; export default function RetrieverConfigurationStep({ setNextEnabled }) { const { enqueueSnackbar } = useSnackbar(); @@ -39,6 +37,7 @@ export default function RetrieverConfigurationStep({ setNextEnabled }) { const [retrieverOptions, setRetrieverOptions] = useState([]); const [selectedRetriever, setSelectedRetriever] = useState(null); + const [openConfig, setOpenConfig] = useState(false); const {defaultValues: retrieverInitialParameters} = useSchema({ modelName: selectedRetriever?.name }); @@ -83,12 +82,20 @@ export default function RetrieverConfigurationStep({ setNextEnabled }) { // Handle paradigm change const handleRetrievalParadigmChange = (event, newValue) => { setSelectedRetrievalParadigm(newValue); - setSelectedRetriever(null); // Reset retriever selection + if (newValue === "SparseRetriever") { + setSelectedRetriever(null); + } + else { + setRetrieverOptions([newValue]); + setSelectedRetriever(newValue); + } }; // Handle retriever change const handleRetrieverSelectionChange = (event, newValue) => { setSelectedRetriever(newValue); + setOpenConfig(true); + setNextEnabled(false); // Optionally reset config if needed }; @@ -152,90 +159,26 @@ export default function RetrieverConfigurationStep({ setNextEnabled }) { {/* Right column: configuration, only if retriever selected */} - {selectedRetriever && ( + {selectedRetriever && openConfig && ( - - { + setNextEnabled(true) + setOpenConfig(false) + }} + > + setOpenConfig(false)} /> - + )} ); } - -function ModelConfigurationSubcomponent({ - selectedRetriever, - retrieverInitialParameters, - handleRetrieverParametersChange, -}) { - const { - formValues, - properties, - propertyData, - valuesByProperties, - removeLastProperty, - setErrorForm, - } = useFormSchemaStore(); - - const [selectedModel, setSelectedModel] = useState( - selectedRetriever?.name || propertyData?.model, - ); - - const selectedProperty = Boolean(propertyData?.selected); - - const defaultValues = useMemo(() => { - if (selectedProperty) { - if (propertyData.params) { - return propertyData.params; - } else return null; - } - return retrieverInitialParameters ?? valuesByProperties; - }, [selectedModel, propertyData.params]); - - useEffect(() => { - if (propertyData.model) { - setSelectedModel(propertyData.model); - } else { - setSelectedModel(selectedRetriever?.name); - } - }, [propertyData.model, propertyData.params, selectedRetriever?.name]); - - return ( - - - - - {`${selectedRetriever.name} configuration`} - - - {console.log("propertyData:", propertyData)} - {Boolean(propertyData?.parent) && ( - <> - - - - )} - { - handleRetrieverParametersChange(formValues); - }} - setError={setErrorForm} - onCancel={() => { - if (properties.length > 0) { - removeLastProperty(); - } - }} - /> - - ); -} \ No newline at end of file From 259b9906c6b0b60a22e6157642ed5bab9a00c3bd Mon Sep 17 00:00:00 2001 From: sofiachavezb Date: Mon, 29 Sep 2025 12:58:59 -0300 Subject: [PATCH 014/218] WIP --- DashAI/back/models/RAG/RAG_pipeline.py | 4 +- DashAI/back/models/hugging_face/__init__.py | 3 +- .../shared/FormSchemaButtonGroup.jsx | 2 +- .../shared/FormSchemaRenderFields.jsx | 2 +- DashAI/front/src/contexts/schema.js | 2 +- .../RAG/ChunkingConfigurationStep.jsx | 46 +- .../generative/RAG/FormSchemaEmbedded.jsx | 113 + .../pages/generative/RAG/NewSessionModal.jsx | 32 +- .../RAG/RetrieverConfigurationStep.jsx | 128 +- DashAI/front/src/utils/schema.js | 4 +- component_registry.json | 1 - component_registry__foromatted.json | 6053 ----------------- 12 files changed, 237 insertions(+), 6153 deletions(-) create mode 100644 DashAI/front/src/pages/generative/RAG/FormSchemaEmbedded.jsx delete mode 100644 component_registry.json delete mode 100644 component_registry__foromatted.json diff --git a/DashAI/back/models/RAG/RAG_pipeline.py b/DashAI/back/models/RAG/RAG_pipeline.py index 63f3b9c60..97ad76b20 100644 --- a/DashAI/back/models/RAG/RAG_pipeline.py +++ b/DashAI/back/models/RAG/RAG_pipeline.py @@ -22,8 +22,7 @@ from DashAI.back.models.hugging_face import ( DeepSeekModel, - QwenModel, - GemmaModel) + QwenModel) retriever_models = { "TFIDFRetriever": TFIDFRetriever, @@ -33,7 +32,6 @@ generation_models = { "DeepSeekModel": DeepSeekModel, "QwenModel": QwenModel, - "GemmaModel": GemmaModel, } class RAGPipelineSchema(BaseSchema): diff --git a/DashAI/back/models/hugging_face/__init__.py b/DashAI/back/models/hugging_face/__init__.py index 340e9e6f0..c46bdfb0a 100644 --- a/DashAI/back/models/hugging_face/__init__.py +++ b/DashAI/back/models/hugging_face/__init__.py @@ -1,3 +1,2 @@ from DashAI.back.models.hugging_face.deep_seek_model import DeepSeekModel -from DashAI.back.models.hugging_face.qwen_model import QwenModel -from DashAI.back.models.hugging_face.gemma_model import GemmaModel \ No newline at end of file +from DashAI.back.models.hugging_face.qwen_model import QwenModel \ No newline at end of file diff --git a/DashAI/front/src/components/shared/FormSchemaButtonGroup.jsx b/DashAI/front/src/components/shared/FormSchemaButtonGroup.jsx index 1755c5886..fd707fd48 100644 --- a/DashAI/front/src/components/shared/FormSchemaButtonGroup.jsx +++ b/DashAI/front/src/components/shared/FormSchemaButtonGroup.jsx @@ -20,7 +20,7 @@ function FormSchemaButtonGroup({ {!autoSave && ( + + )} - {!showTableTitle && ( - - )} ); } From d6299fa5f26608ae520f53f638f4877c8189a03b Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 1 Oct 2025 10:53:34 -0300 Subject: [PATCH 017/218] refactor: Improve code readability and formatting in ChunkingConfigurationStep component --- .../RAG/ChunkingConfigurationStep.jsx | 55 ++++++++++++------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/DashAI/front/src/pages/generative/RAG/ChunkingConfigurationStep.jsx b/DashAI/front/src/pages/generative/RAG/ChunkingConfigurationStep.jsx index 04fa4090c..37715938e 100644 --- a/DashAI/front/src/pages/generative/RAG/ChunkingConfigurationStep.jsx +++ b/DashAI/front/src/pages/generative/RAG/ChunkingConfigurationStep.jsx @@ -4,14 +4,21 @@ import useSchema from "../../../hooks/useSchema"; import { getChunkingComponents } from "../../../api/rag"; import FormSchemaEmbedded from "./FormSchemaEmbedded"; -export default function ChunkingConfigurationStep({ chunkingModel, setChunkingModel, setNextEnabled }) { +export default function ChunkingConfigurationStep({ + chunkingModel, + setChunkingModel, + setNextEnabled, +}) { const [chunkingOptions, setChunkingOptions] = useState([]); const [selectedChunking, setSelectedChunking] = useState(null); const { defaultValues } = useSchema({ modelName: selectedChunking?.name }); // Memoize the initial values to prevent unnecessary re-renders const initialValues = useMemo(() => { - if (chunkingModel?.parameters && Object.keys(chunkingModel.parameters).length > 0) { + if ( + chunkingModel?.parameters && + Object.keys(chunkingModel.parameters).length > 0 + ) { return chunkingModel.parameters; } return defaultValues || {}; @@ -22,7 +29,7 @@ export default function ChunkingConfigurationStep({ chunkingModel, setChunkingMo const data = await getChunkingComponents(); setChunkingOptions(data); if (chunkingModel?.name) { - const existing = data.find(c => c.name === chunkingModel.name); + const existing = data.find((c) => c.name === chunkingModel.name); if (existing) setSelectedChunking(existing); } }; @@ -34,11 +41,10 @@ export default function ChunkingConfigurationStep({ chunkingModel, setChunkingMo return false; } if (!chunkingModel || !chunkingModel.parameters) { - return false; // Ensure parameters are required } - - return Object.keys(chunkingModel.parameters).every(param => { + + return Object.keys(chunkingModel.parameters).every((param) => { const value = chunkingModel.parameters[param]; return value !== undefined && value !== null && value !== ""; }); @@ -48,13 +54,14 @@ export default function ChunkingConfigurationStep({ chunkingModel, setChunkingMo setNextEnabled(isNextEnabled()); }, [selectedChunking, chunkingModel, setNextEnabled]); - const handleChunkingSelectionChange = (event, newValue) => { setSelectedChunking(newValue); if (newValue) { setChunkingModel({ name: newValue.name, - parameters: newValue.schema?.properties ? getInitialParamsFromSchema(newValue.schema.properties) : {}, + parameters: newValue.schema?.properties + ? getInitialParamsFromSchema(newValue.schema.properties) + : {}, }); } else { setChunkingModel({ name: "", parameters: {} }); @@ -74,35 +81,45 @@ export default function ChunkingConfigurationStep({ chunkingModel, setChunkingMo function getInitialParamsFromSchema(schemaProperties) { if (!schemaProperties) return {}; return Object.keys(schemaProperties).reduce((acc, key) => { - acc[key] = schemaProperties[key].placeholder !== undefined - ? schemaProperties[key].placeholder - : ""; + acc[key] = + schemaProperties[key].placeholder !== undefined + ? schemaProperties[key].placeholder + : ""; return acc; }, {}); } return ( - + Configure Chunking Model option.name} + getOptionLabel={(option) => option.name} value={selectedChunking} onChange={handleChunkingSelectionChange} isOptionEqualToValue={(option, value) => option.name === value?.name} - renderInput={params => } + renderInput={(params) => ( + + )} sx={{ mb: 3 }} /> {selectedChunking && selectedChunking.schema && ( setSelectedChunking(null)} - /> + model={selectedChunking.name} + initialValues={initialValues} + onFormSubmit={handleParametersSave} + autoSave={true} + /> )} ); From 8a853ab4b59fe32cf3d9f46bad76ba8a13f3cfa1 Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 1 Oct 2025 11:13:45 -0300 Subject: [PATCH 018/218] refactor: Simplify imports and improve code formatting in RetrieverConfigurationStep component --- .../RAG/RetrieverConfigurationStep.jsx | 109 ++++++++---------- 1 file changed, 50 insertions(+), 59 deletions(-) diff --git a/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx b/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx index 80f8314bd..7171d1948 100644 --- a/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx +++ b/DashAI/front/src/pages/generative/RAG/RetrieverConfigurationStep.jsx @@ -1,31 +1,10 @@ -import React, { - useState, - useEffect, - useCallback, - useMemo, -} from "react"; -import { - Box, - Dialog, - DialogTitle, - DialogContent, - Autocomplete, - TextField, - Typography, - IconButton, - Stack, - -} from "@mui/material"; -import ArrowBackOutlined from "@mui/icons-material/ArrowBackOutlined"; +import { useState, useEffect, useCallback } from "react"; +import { Box, Autocomplete, TextField, Typography } from "@mui/material"; import { getRetrieverComponents, getRetrievalParadigm } from "../../../api/rag"; import { useSnackbar } from "notistack"; import useSchema from "../../../hooks/useSchema"; -import FormSchemaModelSelect from "../../../components/shared/FormSchemaModelSelect"; -import FormSchemaContainer from "../../../components/shared/FormSchemaContainer"; -import { useFormSchemaStore } from "../../../contexts/schema"; -import FormSchemaBreadScrumbs from "../../../components/shared/FormSchemaBreadScrumbs"; import FormSchema from "../../../components/shared/FormSchema"; import FormSchemaDialog from "../../../components/shared/FormSchemaDialog"; @@ -33,24 +12,30 @@ import FormSchemaDialog from "../../../components/shared/FormSchemaDialog"; export default function RetrieverConfigurationStep({ setNextEnabled }) { const { enqueueSnackbar } = useSnackbar(); const [retrievalParadigms, setRetrievalParadigms] = useState([]); - const [selectedRetrievalParadigm, setSelectedRetrievalParadigm] = useState(null); + const [selectedRetrievalParadigm, setSelectedRetrievalParadigm] = + useState(null); const [retrieverOptions, setRetrieverOptions] = useState([]); const [selectedRetriever, setSelectedRetriever] = useState(null); const [openConfig, setOpenConfig] = useState(false); - const {defaultValues: retrieverInitialParameters} = useSchema({ modelName: selectedRetriever?.name }); + const { defaultValues: retrieverInitialParameters } = useSchema({ + modelName: selectedRetriever?.name, + }); - // Fetch paradigms const fetchRetrievalParadigms = async () => { try { const data = await getRetrievalParadigm(); setRetrievalParadigms(data); - enqueueSnackbar('Retrieval paradigms loaded successfully!', { variant: 'success' }); + enqueueSnackbar("Retrieval paradigms loaded successfully!", { + variant: "success", + }); } catch (error) { console.error("Error fetching retrieval paradigms:", error); - enqueueSnackbar('Failed to load retrieval paradigms.', { variant: 'error' }); + enqueueSnackbar("Failed to load retrieval paradigms.", { + variant: "error", + }); } }; @@ -66,7 +51,9 @@ export default function RetrieverConfigurationStep({ setNextEnabled }) { return; } if (selectedRetrievalParadigm.name === "SparseRetriever") { - const retrievers = await getRetrieverComponents(selectedRetrievalParadigm.name); + const retrievers = await getRetrieverComponents( + selectedRetrievalParadigm.name, + ); setRetrieverOptions(retrievers); setSelectedRetriever(null); } else { @@ -85,8 +72,7 @@ export default function RetrieverConfigurationStep({ setNextEnabled }) { console.log("Selected paradigm:", newValue); if (newValue === "SparseRetriever") { setSelectedRetriever(null); - } - else { + } else { setRetrieverOptions([newValue]); handleRetrieverSelectionChange(event, newValue); setOpenConfig(true); @@ -116,11 +102,7 @@ export default function RetrieverConfigurationStep({ setNextEnabled }) { // Layout: two columns if retriever selected, else one column return ( option.name === value?.name} - renderInput={(params) => } + renderInput={(params) => ( + + )} sx={{ mb: 2 }} /> - {selectedRetrievalParadigm && selectedRetrievalParadigm.name === "SparseRetriever" && ( - <> - - Select retriever model - - option.name} - value={selectedRetriever} - onChange={handleRetrieverSelectionChange} - isOptionEqualToValue={(option, value) => option.name === value?.name} - renderInput={(params) => } - /> - - )} - {selectedRetriever && selectedRetriever.schema && !selectedRetriever.schema.properties && ( - - No parameters available for this retriever. - - )} + {selectedRetrievalParadigm && + selectedRetrievalParadigm.name === "SparseRetriever" && ( + <> + + Select retriever model + + option.name} + value={selectedRetriever} + onChange={handleRetrieverSelectionChange} + isOptionEqualToValue={(option, value) => + option.name === value?.name + } + renderInput={(params) => ( + + )} + /> + + )} + {selectedRetriever && + selectedRetriever.schema && + !selectedRetriever.schema.properties && ( + + No parameters available for this retriever. + + )} {selectedRetriever && openConfig && ( )} - -); + + ); } From c7e82584d03bc6673c9784bb9c6134702b8a025f Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 1 Oct 2025 11:49:49 -0300 Subject: [PATCH 019/218] refactor: Enhance layout styling in FormSchemaButtonGroup component --- .../src/components/shared/FormSchemaButtonGroup.jsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/DashAI/front/src/components/shared/FormSchemaButtonGroup.jsx b/DashAI/front/src/components/shared/FormSchemaButtonGroup.jsx index fd707fd48..9b093cc19 100644 --- a/DashAI/front/src/components/shared/FormSchemaButtonGroup.jsx +++ b/DashAI/front/src/components/shared/FormSchemaButtonGroup.jsx @@ -11,7 +11,15 @@ function FormSchemaButtonGroup({ backButtonText = "Back", }) { return ( - + {onCancel && (
- + )} - + ); case LOADING: From 2f5b221657075a99e34a8aeb9cbaa5a235125797 Mon Sep 17 00:00:00 2001 From: sofiachavezb Date: Fri, 10 Oct 2025 14:38:24 -0300 Subject: [PATCH 045/218] Database schema implemented --- DashAI/back/api/api_v1/endpoints/documents.py | 110 +++++- DashAI/back/api/api_v1/schemas/__init__.py | 2 +- DashAI/back/api/api_v1/schemas/document.py | 11 +- DashAI/back/dependencies/database/models.py | 351 ++++++++++-------- .../models/RAG/chunking_models/__init__.py | 3 +- .../RAG/embeddings/sparse/bm25_encoding.py | 15 +- .../RAG/embeddings/sparse/tfidf_encoding.py | 31 +- 7 files changed, 320 insertions(+), 203 deletions(-) diff --git a/DashAI/back/api/api_v1/endpoints/documents.py b/DashAI/back/api/api_v1/endpoints/documents.py index 45b2f8ad9..97b03ff00 100644 --- a/DashAI/back/api/api_v1/endpoints/documents.py +++ b/DashAI/back/api/api_v1/endpoints/documents.py @@ -44,8 +44,10 @@ async def get_all_documents( DocumentResponse( id=doc.id, file_name=doc.file_name, + file_hash=doc.file_hash, created=doc.created, optional_metadata=doc.optional_metadata, + related_sessions=[session.id for session in doc.related_sessions_ids] if doc.related_sessions_ids else None, file_url=f"{base_url}/{doc.id}/download", ) ) @@ -76,8 +78,10 @@ async def get_document( return DocumentResponse( id=document.id, file_name=document.file_name, + file_hash=document.file_hash, created=document.created, optional_metadata=document.optional_metadata, + related_sessions=[session.id for session in document.related_sessions_ids] if document.related_sessions_ids else None, file_url=f"{base_url}/{document.id}/download", ) except exc.SQLAlchemyError as e: @@ -124,13 +128,14 @@ async def upload_document( Upload a new document to the RAG system with file content and metadata. The metadata should be a JSON string with required fields and an 'optional_metadata' dict. """ + print("A") docs_folder_path = config["DOCUMENTS_PATH"] if not docs_folder_path.exists(): raise HTTPException( status_code=500, detail=f"Documents folder {docs_folder_path} does not exist.", ) - + print("B") try: metadata_dict = json.loads(metadata) except json.JSONDecodeError: @@ -138,27 +143,27 @@ async def upload_document( file_name = metadata_dict.get("file_name") last_modified = metadata_dict.get("last_modified") - + print("C") if not file_name or not last_modified: raise HTTPException( status_code=400, detail="Missing required metadata fields: 'filename' and 'last_modified'", ) - + print("D") optional_metadata = metadata_dict.get("optional_metadata", {}) if not isinstance(optional_metadata, dict): raise HTTPException( status_code=400, detail="'optional_metadata' must be a dictionary", ) - + print("E") try: content_bytes = await file.read() except Exception: raise HTTPException(status_code=400, detail="Failed to read file content") hash256 = hashlib.sha256(content_bytes).hexdigest() - + print("F") with session_factory() as db: existing_doc = db.query(Document).filter_by(file_hash=hash256).first() if existing_doc: @@ -170,15 +175,18 @@ async def upload_document( return DocumentResponse( id=existing_doc.id, file_name=existing_doc.file_name, + file_hash=existing_doc.file_hash, created=existing_doc.created, + related_sessions=[session.id for session in existing_doc.related_sessions_ids], optional_metadata=existing_doc.optional_metadata, - file_url=f"{base_url}/{existing_doc.id}/download", + file_url=f"{base_url}/{existing_doc.id}/download" ) else: # Create a new document entry try: - new_id = db.query(Document).count() + 1 - file_path = os.path.join(docs_folder_path, f"{new_id}_{file_name}") + max_id = db.query(Document.id).order_by(Document.id.desc()).first() + new_id = (max_id[0] + 1) if max_id else 1 + file_path = os.path.join(docs_folder_path, f"{new_id}__{file_name}") with open(file_path, "wb") as f: f.write(content_bytes) @@ -188,8 +196,6 @@ async def upload_document( file_path=str(file_path), file_hash=hash256, optional_metadata=optional_metadata or None, - sessions_related=[], - pipelines_related=[], ) db.add(doc) db.commit() @@ -198,9 +204,12 @@ async def upload_document( return DocumentResponse( id=doc.id, file_name=doc.file_name, + file_hash=doc.file_hash, created=doc.created, + related_sessions=None, optional_metadata=doc.optional_metadata, file_url=f"{base_url}/{doc.id}/download", + ) except exc.SQLAlchemyError as e: log.exception(e) @@ -209,12 +218,12 @@ async def upload_document( detail="Internal database error", ) from e -@router.get("/sessions-related/{document_id}", response_model=List[int]) -async def get_document_sessions_related( +@router.get("/related-sessions/{document_id}", response_model=List[int]) +async def get_related_sessions( document_id: int, session_factory: sessionmaker = Depends(lambda: di["session_factory"]), ): - """Get all session IDs related to a specific document.""" + """Get all generative session IDs related to a specific document.""" with session_factory() as db: try: document = db.get(Document, document_id) @@ -223,8 +232,10 @@ async def get_document_sessions_related( status_code=status.HTTP_404_NOT_FOUND, detail=f"Document {document_id} does not exist in DB.", ) - session_ids = [session.id for session in document.sessions_related] - return session_ids + if not document.related_sessions_ids: + return [] + related_session_ids = [session.id for session in document.related_sessions_ids] + return related_session_ids except exc.SQLAlchemyError as e: log.exception(e) raise HTTPException( @@ -232,7 +243,6 @@ async def get_document_sessions_related( detail="Internal database error", ) from e - @router.delete("/{document_id}", status_code=status.HTTP_204_NO_CONTENT) async def delete_document( document_id: int, @@ -247,10 +257,15 @@ async def delete_document( status_code=status.HTTP_404_NOT_FOUND, detail=f"Document {document_id} does not exist in DB.", ) + + # Delete the physical file if os.path.exists(document.file_path): os.remove(document.file_path) + + # Delete the database record db.delete(document) db.commit() + return Response(status_code=status.HTTP_204_NO_CONTENT) except exc.SQLAlchemyError as e: log.exception(e) @@ -258,3 +273,66 @@ async def delete_document( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Internal database error", ) from e + except OSError as e: + log.exception(e) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="Error deleting physical file", + ) from e + + +@router.put("/{document_id}", response_model=DocumentResponse) +async def update_document_metadata( + document_id: int, + metadata: str = Form(...), + session_factory: sessionmaker = Depends(lambda: di["session_factory"]), +): + """Update a document's metadata.""" + with session_factory() as db: + try: + document = db.get(Document, document_id) + if not document: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Document {document_id} does not exist in DB.", + ) + + try: + metadata_dict = json.loads(metadata) + except json.JSONDecodeError: + raise HTTPException(status_code=400, detail="Invalid JSON in metadata") + + # Update fields that are allowed to be modified + if "file_name" in metadata_dict: + document.file_name = metadata_dict["file_name"] + + if "optional_metadata" in metadata_dict: + optional_metadata = metadata_dict["optional_metadata"] + if not isinstance(optional_metadata, dict): + raise HTTPException( + status_code=400, + detail="'optional_metadata' must be a dictionary", + ) + document.optional_metadata = optional_metadata + + document.last_modified = datetime.now() + + db.commit() + db.refresh(document) + + return DocumentResponse( + id=document.id, + file_name=document.file_name, + file_hash=document.file_hash, + created=document.created, + optional_metadata=document.optional_metadata, + related_sessions=[session.id for session in document.related_sessions_ids] if document.related_sessions_ids else None, + file_url=f"{base_url}/{document.id}/download", + ) + + except exc.SQLAlchemyError as e: + log.exception(e) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="Internal database error", + ) from e \ No newline at end of file diff --git a/DashAI/back/api/api_v1/schemas/__init__.py b/DashAI/back/api/api_v1/schemas/__init__.py index 79080d662..9d35150b8 100644 --- a/DashAI/back/api/api_v1/schemas/__init__.py +++ b/DashAI/back/api/api_v1/schemas/__init__.py @@ -1 +1 @@ -from DashAI.back.api.api_v1.schemas.document import DocumentResponse, DocumentUploadResponse \ No newline at end of file +from DashAI.back.api.api_v1.schemas.document import DocumentResponse \ No newline at end of file diff --git a/DashAI/back/api/api_v1/schemas/document.py b/DashAI/back/api/api_v1/schemas/document.py index 38b5517c7..765f611ad 100644 --- a/DashAI/back/api/api_v1/schemas/document.py +++ b/DashAI/back/api/api_v1/schemas/document.py @@ -1,19 +1,14 @@ from pydantic import BaseModel -from typing import Any, Dict, Optional +from typing import Any, Dict, List, Optional from datetime import datetime -class DocumentUploadResponse(BaseModel): - id: int - file_name: str - optional_metadata: Optional[dict] - created: datetime - file_hash: str - class DocumentResponse(BaseModel): id: int file_name: str + file_hash: str created: datetime optional_metadata: Optional[Dict[str, Any]] + related_sessions: List[int]|None file_url: str class Config: diff --git a/DashAI/back/dependencies/database/models.py b/DashAI/back/dependencies/database/models.py index 666a918c8..f6df5af0e 100644 --- a/DashAI/back/dependencies/database/models.py +++ b/DashAI/back/dependencies/database/models.py @@ -3,7 +3,7 @@ from datetime import datetime from typing import Any, Dict, List, Optional -from sqlalchemy import JSON, Boolean, DateTime, Enum, ForeignKey, Integer, String, UniqueConstraint, ARRAY +from sqlalchemy import JSON, Boolean, CheckConstraint, DateTime, Enum, ForeignKey, Integer, String, Text, UniqueConstraint, ARRAY from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import Mapped, mapped_column, relationship @@ -173,7 +173,7 @@ class Plugin(Base): name: Mapped[str] = mapped_column(String, unique=True, nullable=False) author: Mapped[str] = mapped_column(String, nullable=False) installed_version: Mapped[str] = mapped_column(String, nullable=False) - lastest_version: Mapped[str] = mapped_column(String, nullable=False) + latest_version: Mapped[str] = mapped_column(String, nullable=False) tags: Mapped[List["Tag"]] = relationship( back_populates="plugin", cascade="all, delete", lazy="selectin" ) @@ -374,7 +374,7 @@ class ProcessData(Base): process = relationship( "GenerativeProcess", foreign_keys=[process_id], overlaps="input,output" ) - + class GenerativeSession(Base): __tablename__ = "generative_session" @@ -410,6 +410,11 @@ class GenerativeSession(Base): processes: Mapped[List["GenerativeProcess"]] = relationship( "GenerativeProcess", cascade="all, delete-orphan", back_populates="session" ) + + # Relationship with RAGDocumentPipelineSessionLink + pipeline_links: Mapped[List["RAGDocumentPipelineSessionLink"]] = relationship( + back_populates="session" + ) class Pipeline(Base): @@ -608,243 +613,263 @@ def delete_result(self) -> None: self.end_time = None + + + + + + + + + + + + + +""" +RAG tables +""" + class Document(Base): - __tablename__ = "RAG_document" + __tablename__ = "document" """ - Table to store all the information about a document in the RAG system. + Table to store all the information about a document. """ - id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) + id: Mapped[int] = mapped_column(primary_key=True) file_name: Mapped[str] = mapped_column(String, nullable=False) + file_type: Mapped[str] = mapped_column(String, nullable=False) file_path: Mapped[str] = mapped_column(String, nullable=False) file_hash: Mapped[str] = mapped_column(String, nullable=False, unique=True) - created: Mapped[DateTime] = mapped_column(DateTime, default=datetime.now) - optional_metadata: Mapped[JSON] = mapped_column(JSON, nullable=True) - sessions_related: Mapped[Optional[List["GenerativeSession"]]] = relationship( - "GenerativeSession", backref="RAG_document" + + # Create a relationship for the related sessions and related chunks + pipeline_links: Mapped[List["RAGDocumentPipelineSessionLink"]] = relationship( + cascade="all, delete-orphan", + back_populates="document" + ) + + chunks: Mapped[List["RAGChunk"]] = relationship( + back_populates="document", + cascade="all, delete-orphan", ) - pipelines_related: Mapped[Optional[List["RAGPipeline"]]] = relationship( - "RAGPipeline", backref="RAG_document" + + embeddings_links: Mapped[List["RAGDocumentChunksEmbeddingsLink"]] = relationship( + cascade="all, delete-orphan" + ) + + @property + def sessions_related(self) -> List["GenerativeSession"]: + """Return a list of sessions related to the document.""" + return [link.session for link in self.pipeline_links] + + @property + def pipelines_related(self) -> List["RAGPipeline"]: + """Return a list of pipelines related to the document.""" + return [link.pipeline for link in self.pipeline_links] + + +class RAGChunk(Base): + __tablename__ = "rag_chunk" + """ + Table to store all the information about a chunk. + """ + id: Mapped[int] = mapped_column(primary_key=True) + text: Mapped[str] = mapped_column(Text, nullable=False) + document_id: Mapped[int] = mapped_column( + ForeignKey("document.id", ondelete="CASCADE"), nullable=False ) + document: Mapped["Document"] = relationship(back_populates="chunks") + __table_args__ = ( - UniqueConstraint('file_name', 'file_hash', name='_file_name_hash_uc'), - UniqueConstraint('file_path', 'file_hash', name='_file_path_hash_uc'), - UniqueConstraint('file_name', 'file_path', name='_file_name_path_uc'), + UniqueConstraint("id", "document_id", name="uix_chunk_document"), ) - def __repr__(self) -> str: - return f"" class RAGPipeline(Base): - __tablename__ = "RAG_pipeline" + __tablename__ = "rag_pipeline" """ - Table to store the RAG pipelines created by the user. + Table to store all the information about a RAG pipeline. """ - id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) - name: Mapped[str] = mapped_column(String, nullable=False, unique=True) - session: Mapped[int] = mapped_column( - ForeignKey("generative_session.id", ondelete="CASCADE"), nullable=False - ) + id: Mapped[int] = mapped_column(primary_key=True) + name: Mapped[str] = mapped_column(String, nullable=False) + description: Mapped[str] = mapped_column(String, nullable=True) parameters: Mapped[JSON] = mapped_column(JSON, nullable=True) - documents: Mapped[List["Document"]] = relationship( - "Document", backref="RAG_pipeline" - ) + chunking_model_id: Mapped[int] = mapped_column( - ForeignKey("RAG_chunking_model.id", ondelete="CASCADE"), nullable=False - ) - chunks: Mapped[List["RAGChunk"]] = relationship( - "RAGChunk", backref="RAG_pipeline", cascade="all, delete-orphan" - ) - retriever_model_id: Mapped[int] = mapped_column( - ForeignKey("RAG_retriever_model.id", ondelete="CASCADE"), nullable=False + ForeignKey("rag_chunking_model.id", ondelete="CASCADE"), nullable=False ) - created: Mapped[DateTime] = mapped_column(DateTime, default=datetime.now) - last_modified: Mapped[DateTime] = mapped_column( - DateTime, - default=datetime.now, - onupdate=datetime.now, + retriever_id: Mapped[int] = mapped_column( + ForeignKey("rag_retriever.id", ondelete="CASCADE"), nullable=False ) - - __table_args__ = ( - UniqueConstraint('id', 'session', name='_id_session_uc'), + + # Relationships + chunking_model: Mapped["RAGChunkingModel"] = relationship(back_populates="pipelines") + retriever: Mapped["RAGRetriever"] = relationship(back_populates="pipelines") + pipeline_links: Mapped[List["RAGDocumentPipelineSessionLink"]] = relationship( + cascade="all, delete-orphan", + back_populates="pipeline" ) class RAGChunkingModel(Base): - __tablename__ = "RAG_chunking_model" + __tablename__ = "rag_chunking_model" """ - Table to store all the chunking models used in RAG pipelines. + Table to store all the information about a chunking model. """ - id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) + id: Mapped[int] = mapped_column(primary_key=True) class_name: Mapped[str] = mapped_column(String, nullable=False) parameters: Mapped[JSON] = mapped_column(JSON, nullable=True) - sessions_related: Mapped[List["GenerativeSession"]] = relationship( - "GenerativeSession", backref="RAG_chunking_model" - ) - pipelines_related: Mapped[List["RAGPipeline"]] = relationship( - "RAGPipeline", backref="RAG_chunking_model" - ) - chunks: Mapped[List["RAGChunk"]] = relationship( - "RAGChunk", backref="RAG_chunking_model", cascade="all, delete-orphan" + + pipelines: Mapped[List["RAGPipeline"]] = relationship( + back_populates="chunking_model" ) - created: Mapped[DateTime] = mapped_column(DateTime, default=datetime.now) - last_modified: Mapped[DateTime] = mapped_column( - DateTime, - default=datetime.now, - onupdate=datetime.now, + document_links: Mapped[List["RAGDocumentChunksEmbeddingsLink"]] = relationship( + cascade="all, delete-orphan" ) -class RAGChunk(Base): - __tablename__ = "RAG_chunk" +class RAGRetriever(Base): + __tablename__ = "rag_retriever" """ - Table to store all the chunks of documents used in RAG pipelines. + Table to map the retriever model id to its dense or sparse retriever instance. """ - id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) - chunk_text: Mapped[str] = mapped_column(String, nullable=False) - document_id: Mapped[int] = mapped_column( - ForeignKey("RAG_document.id", ondelete="CASCADE"), nullable=False + id: Mapped[int] = mapped_column(primary_key=True) + class_name: Mapped[str] = mapped_column(String, nullable=False) # "SparseRetriever" or "DenseRetriever" + parameters: Mapped[JSON] = mapped_column(JSON, nullable=True) # The top-level parameters for the retriever, not the nested ones + sparse_id: Mapped[int] = mapped_column( + ForeignKey("rag_sparse_retriever.id", ondelete="CASCADE"), nullable=True ) - chunking_model_id: Mapped[int] = mapped_column( - ForeignKey("RAG_chunking_model.id", ondelete="CASCADE"), nullable=False + dense_id: Mapped[int] = mapped_column( + ForeignKey("rag_dense_retriever.id", ondelete="CASCADE"), nullable=True ) - created: Mapped[DateTime] = mapped_column(DateTime, default=datetime.now) - + + # Relationships + sparse_retriever: Mapped[Optional["RAGSparseRetriever"]] = relationship( + back_populates="related_retriever" + ) + dense_retriever: Mapped[Optional["RAGDenseRetriever"]] = relationship( + back_populates="related_retriever" + ) + pipelines: Mapped[List["RAGPipeline"]] = relationship( + back_populates="retriever" + ) + __table_args__ = ( - UniqueConstraint('chunk_text', 'document_id', name='_chunk_document_uc'), + CheckConstraint( + "(sparse_id IS NOT NULL AND class_name = 'SparseRetriever' AND dense_id IS NULL) OR " + "(dense_id IS NOT NULL AND class_name = 'DenseRetriever' AND sparse_id IS NULL)", + name="chk_retriever_paradigm", + ), ) - def __repr__(self) -> str: - return f"" - -class RAGRetrieverModel(Base): - __tablename__ = "RAG_retriever_model" +class RAGSparseRetriever(Base): + __tablename__ = "rag_sparse_retriever" """ - Table to store all the retriever models used in RAG pipelines. + Table to store all the information about a sparse retriever. """ - id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) - paradigm: Mapped[str] = mapped_column(String, nullable=False) + id: Mapped[int] = mapped_column(primary_key=True) class_name: Mapped[str] = mapped_column(String, nullable=False) parameters: Mapped[JSON] = mapped_column(JSON, nullable=True) - chunks_ids: Mapped[List[int]] = mapped_column(ARRAY(Integer), nullable=True) - - chunks: Mapped[List["RAGChunk"]] = relationship( - "RAGChunk", backref="RAG_retriever_model", cascade="all, delete-orphan" - ) - - sessions_related: Mapped[List["GenerativeSession"]] = relationship( - "GenerativeSession", backref="RAG_retriever_model" - ) - pipelines_related: Mapped[List["RAGPipeline"]] = relationship( - "RAGPipeline", backref="RAG_retriever_model" - ) - created: Mapped[DateTime] = mapped_column(DateTime, default=datetime.now) - last_modified: Mapped[DateTime] = mapped_column( - DateTime, - default=datetime.now, - onupdate=datetime.now, - ) + storage_folder: Mapped[str] = mapped_column(String, nullable=False) -class RAGRetriever(Base): - __tablename__ = "RAG_retriever" - """ - Abstract base class for RAG retrievers. - """ - + related_retriever: Mapped["RAGRetriever"] = relationship( + back_populates="sparse_retriever", uselist=False + ) class RAGDenseRetriever(Base): - __tablename__ = "RAG_dense_retriever" + __tablename__ = "rag_dense_retriever" """ - Table to store all the dense retriever models used in RAG pipelines. + Table to store all the information about a dense retriever. """ - id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) + id: Mapped[int] = mapped_column(primary_key=True) class_name: Mapped[str] = mapped_column(String, nullable=False) parameters: Mapped[JSON] = mapped_column(JSON, nullable=True) - retriever_model_id: Mapped[int] = mapped_column( - ForeignKey("RAG_retriever_model.id", ondelete="CASCADE"), nullable=False - ) - embedding_model_id: Mapped[int] = mapped_column( - ForeignKey("RAG_embedding_model.id", ondelete="CASCADE"), nullable=False + chunks_embeddings_id: Mapped[int] = mapped_column( + ForeignKey("rag_chunks_embeddings.id", ondelete="CASCADE"), nullable=False ) - chunks_embeddings: Mapped[List["RAGChunkEmbedding"]] = relationship( - "RAGChunkEmbedding", backref="RAG_dense_retriever", cascade="all, delete-orphan" + + # Relationships + related_retriever: Mapped["RAGRetriever"] = relationship( + back_populates="dense_retriever", uselist=False ) - created: Mapped[DateTime] = mapped_column(DateTime, default=datetime.now) - last_modified: Mapped[DateTime] = mapped_column( - DateTime, - default=datetime.now, - onupdate=datetime.now, + related_chunks_embeddings: Mapped["RAGChunksEmbeddings"] = relationship( + back_populates="related_dense_retrievers" ) -class RAGSparseRetriever(Base): - __tablename__ = "RAG_sparse_retriever" +class RAGChunksEmbeddings(Base): + __tablename__ = "rag_chunks_embeddings" """ - Table to store all the sparse retriever models used in RAG pipelines. + Table to store all the information about the chunks embeddings. """ - id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) + id: Mapped[int] = mapped_column(primary_key=True) class_name: Mapped[str] = mapped_column(String, nullable=False) parameters: Mapped[JSON] = mapped_column(JSON, nullable=True) - retriever_model_id: Mapped[int] = mapped_column( - ForeignKey("RAG_retriever_model.id", ondelete="CASCADE"), nullable=False - ) + embedding_dimension: Mapped[int] = mapped_column(Integer, nullable=False) storage_folder: Mapped[str] = mapped_column(String, nullable=False) - stored_files: Mapped[List[str]] = mapped_column(JSON, nullable=True) - created: Mapped[DateTime] = mapped_column(DateTime, default=datetime.now) - last_modified: Mapped[DateTime] = mapped_column( - DateTime, - default=datetime.now, - onupdate=datetime.now, + + related_dense_retrievers: Mapped[List["RAGDenseRetriever"]] = relationship( + back_populates="related_chunks_embeddings" ) + document_links: Mapped[List["RAGDocumentChunksEmbeddingsLink"]] = relationship( + cascade="all, delete-orphan" + ) + +""" +RAG relationship tables +""" -class RAGEmbeddingModel(Base): - __tablename__ = "RAG_embedding_model" +class RAGDocumentPipelineSessionLink(Base): + __tablename__ = "rag_document_pipeline_session_link" """ - Table to store all the embedding models used in RAG pipelines. + Association table to link documents and sessions (many-to-many relationship). """ - id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) - class_name: Mapped[str] = mapped_column(String, nullable=False) - parameters: Mapped[JSON] = mapped_column(JSON, nullable=True) - sessions_related: Mapped[List["GenerativeSession"]] = relationship( - "GenerativeSession", backref="RAG_embedding_model" + id: Mapped[int] = mapped_column(primary_key=True) + document_id: Mapped[int] = mapped_column( + ForeignKey("document.id", ondelete="CASCADE"), nullable=False ) - dense_retrievers: Mapped[List["RAGDenseRetriever"]] = relationship( - "RAGDenseRetriever", backref="RAG_embedding_model", cascade="all, delete-orphan" + session_id: Mapped[int] = mapped_column( + ForeignKey("generative_session.id", ondelete="CASCADE"), nullable=False ) - created: Mapped[DateTime] = mapped_column(DateTime, default=datetime.now) - last_modified: Mapped[DateTime] = mapped_column( - DateTime, - default=datetime.now, - onupdate=datetime.now, + pipeline_id: Mapped[int] = mapped_column( + ForeignKey("rag_pipeline.id", ondelete="CASCADE"), nullable=False + ) + + # Relationships + document: Mapped["Document"] = relationship(back_populates="pipeline_links") + pipeline: Mapped["RAGPipeline"] = relationship(back_populates="pipeline_links") + session: Mapped["GenerativeSession"] = relationship("GenerativeSession") + + # Constraints + __table_args__ = ( + UniqueConstraint("document_id", "session_id", name="uix_document_session"), + UniqueConstraint("session_id", "pipeline_id", name="uix_session_pipeline"), + UniqueConstraint("document_id", "pipeline_id", name="uix_document_pipeline"), ) -class RAGChunkEmbedding(Base): - __tablename__ = "RAG_chunk_embedding" +class RAGDocumentChunksEmbeddingsLink(Base): + __tablename__ = "rag_document_chunks_embeddings_link" """ - Table to store all the chunk embeddings used in RAG pipelines. + Association table to link documents, chunking models and chunks embeddings (many-to-many relationship). """ - id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) - chunk_id: Mapped[int] = mapped_column( - ForeignKey("RAG_chunk.id", ondelete="CASCADE"), nullable=False - ) - dimension: Mapped[int] = mapped_column(nullable=False) - embedding_vector: Mapped[List[float]] = mapped_column(JSON, nullable=False) - model: Mapped[int] = mapped_column( - ForeignKey("RAG_embedding_model.id", ondelete="CASCADE"), nullable=False - ) - created: Mapped[DateTime] = mapped_column(DateTime, default=datetime.now) - sessions_related: Mapped[List["GenerativeSession"]] = relationship( - "GenerativeSession", backref="RAG_chunk_embedding" + id: Mapped[int] = mapped_column(primary_key=True) + document_id: Mapped[int] = mapped_column( + ForeignKey("document.id", ondelete="CASCADE"), nullable=False ) - retrievers_related: Mapped[List["RAGDenseRetriever"]] = relationship( - "RAGDenseRetriever", backref="RAG_chunk_embedding" + + chunking_model_id: Mapped[int] = mapped_column( + ForeignKey("rag_chunking_model.id", ondelete="CASCADE"), nullable=False ) + chunks_embeddings_id: Mapped[int] = mapped_column( + ForeignKey("rag_chunks_embeddings.id", ondelete="CASCADE"), nullable=False + ) + # Constraints __table_args__ = ( - UniqueConstraint('chunk_id', 'model', name='_chunk_model_uc'), + UniqueConstraint("document_id", "chunking_model_id", "chunks_embeddings_id", name="uix_document_chunking_model_embeddings"), ) \ No newline at end of file diff --git a/DashAI/back/models/RAG/chunking_models/__init__.py b/DashAI/back/models/RAG/chunking_models/__init__.py index a935c5395..f21676cad 100644 --- a/DashAI/back/models/RAG/chunking_models/__init__.py +++ b/DashAI/back/models/RAG/chunking_models/__init__.py @@ -1,2 +1,3 @@ from DashAI.back.models.RAG.chunking_models.character_chunk_model import CharacterChunkModel -from DashAI.back.models.RAG.chunking_models.token_chunk_model import TokenChunkModel \ No newline at end of file +from DashAI.back.models.RAG.chunking_models.token_chunk_model import TokenChunkModel +from DashAI.back.models.RAG.chunking_models.base_chunking_model import BaseChunkingModel \ No newline at end of file diff --git a/DashAI/back/models/RAG/embeddings/sparse/bm25_encoding.py b/DashAI/back/models/RAG/embeddings/sparse/bm25_encoding.py index 389a8c2ed..3cb224ce7 100644 --- a/DashAI/back/models/RAG/embeddings/sparse/bm25_encoding.py +++ b/DashAI/back/models/RAG/embeddings/sparse/bm25_encoding.py @@ -13,17 +13,21 @@ float_field, int_field, bool_field, - string_field + string_field, + union_type, + none_type ) class BM25EncodingSchema(BaseSchema): strip_accents: schema_field( - enum_field( - enum=["ascii", "unicode", None], + none_type( + enum_field( + enum=["ascii", "unicode"], + ) ), placeholder=None, - description="Whether to strip accents from the text.", + description="""Remove accents and perform other character normalization during the preprocessing step. ‘ascii’ is a fast method that only works on characters that have a direct ASCII mapping. ‘unicode’ is a slightly slower method that works on any characters. None (default) means no character normalization is performed.""", ) # type: ignore lowercase: schema_field( @@ -33,6 +37,8 @@ class BM25EncodingSchema(BaseSchema): ) # type: ignore + + stop_words: schema_field( list_field( string_field(), @@ -61,6 +67,7 @@ class BM25EncodingSchema(BaseSchema): ) # type: ignore max_features: schema_field( + int_field( ge=1, ), diff --git a/DashAI/back/models/RAG/embeddings/sparse/tfidf_encoding.py b/DashAI/back/models/RAG/embeddings/sparse/tfidf_encoding.py index ce32a30d0..18b83ae52 100644 --- a/DashAI/back/models/RAG/embeddings/sparse/tfidf_encoding.py +++ b/DashAI/back/models/RAG/embeddings/sparse/tfidf_encoding.py @@ -16,17 +16,21 @@ float_field, int_field, bool_field, - string_field + string_field, + none_type, + union_type, ) class TFIDFEncodingSchema(BaseSchema): strip_accents: schema_field( - enum_field( - enum=["ascii", "unicode", None], + none_type( + enum_field( + enum=["ascii", "unicode"], + ) ), placeholder=None, - description="Whether to strip accents from the text.", + description="""Remove accents and perform other character normalization during the preprocessing step. ‘ascii’ is a fast method that only works on characters that have a direct ASCII mapping. ‘unicode’ is a slightly slower method that works on any characters. None (default) means no character normalization is performed.""", ) # type: ignore lowercase: schema_field( @@ -45,12 +49,17 @@ class TFIDFEncodingSchema(BaseSchema): ) # type: ignore stop_words: schema_field( - list_field( - string_field(), - min_items=1, + none_type( + list_field( + string_field(), + min_items=1, + ) ), placeholder=None, - description="List of stop words to be used in the TF-IDF vectorization.", + description=""" +List of stop words to be used in the TF-IDF vectorization. +If None, no stop words will be used. In this case, setting max_df to a higher value, such as in the range (0.7, 1.0), can automatically detect and filter stop words based on intra corpus document frequency of terms. +""", ) # type: ignore ngram_range: schema_field( @@ -82,8 +91,10 @@ class TFIDFEncodingSchema(BaseSchema): ) # type: ignore max_features: schema_field( - int_field( - ge=1, + none_type( + int_field( + ge=1, + ) ), placeholder=None, description="If not None, build a vocabulary that only consider the top max_features ordered by term frequency across the corpus.", From ef4c363a33c4ab252c2f70c3cd427a96192a2dee Mon Sep 17 00:00:00 2001 From: sofiachavezb Date: Fri, 10 Oct 2025 15:04:31 -0300 Subject: [PATCH 046/218] sessions creation updated --- DashAI/back/api/api_v1/endpoints/documents.py | 13 +++++++- .../api_v1/endpoints/generative_session.py | 15 +++++---- DashAI/back/dependencies/database/models.py | 32 +++++++++++++++++++ DashAI/back/models/RAG/RAG_pipeline.py | 12 +++++-- 4 files changed, 61 insertions(+), 11 deletions(-) diff --git a/DashAI/back/api/api_v1/endpoints/documents.py b/DashAI/back/api/api_v1/endpoints/documents.py index 97b03ff00..b0fe26048 100644 --- a/DashAI/back/api/api_v1/endpoints/documents.py +++ b/DashAI/back/api/api_v1/endpoints/documents.py @@ -44,8 +44,10 @@ async def get_all_documents( DocumentResponse( id=doc.id, file_name=doc.file_name, + file_type=doc.file_type, file_hash=doc.file_hash, created=doc.created, + last_modified=doc.last_modified, optional_metadata=doc.optional_metadata, related_sessions=[session.id for session in doc.related_sessions_ids] if doc.related_sessions_ids else None, file_url=f"{base_url}/{doc.id}/download", @@ -175,8 +177,10 @@ async def upload_document( return DocumentResponse( id=existing_doc.id, file_name=existing_doc.file_name, + file_type=existing_doc.file_type, file_hash=existing_doc.file_hash, created=existing_doc.created, + last_modified=existing_doc.last_modified, related_sessions=[session.id for session in existing_doc.related_sessions_ids], optional_metadata=existing_doc.optional_metadata, file_url=f"{base_url}/{existing_doc.id}/download" @@ -191,8 +195,12 @@ async def upload_document( with open(file_path, "wb") as f: f.write(content_bytes) + # Get file type from file extension + file_type = os.path.splitext(file_name)[1].lstrip('.') or 'unknown' + doc = Document( file_name=file_name, + file_type=file_type, file_path=str(file_path), file_hash=hash256, optional_metadata=optional_metadata or None, @@ -204,12 +212,13 @@ async def upload_document( return DocumentResponse( id=doc.id, file_name=doc.file_name, + file_type=doc.file_type, file_hash=doc.file_hash, created=doc.created, + last_modified=doc.last_modified, related_sessions=None, optional_metadata=doc.optional_metadata, file_url=f"{base_url}/{doc.id}/download", - ) except exc.SQLAlchemyError as e: log.exception(e) @@ -305,6 +314,8 @@ async def update_document_metadata( # Update fields that are allowed to be modified if "file_name" in metadata_dict: document.file_name = metadata_dict["file_name"] + # Update file_type when file_name changes + document.file_type = os.path.splitext(metadata_dict["file_name"])[1].lstrip('.') or 'unknown' if "optional_metadata" in metadata_dict: optional_metadata = metadata_dict["optional_metadata"] diff --git a/DashAI/back/api/api_v1/endpoints/generative_session.py b/DashAI/back/api/api_v1/endpoints/generative_session.py index 78747fe42..3c622706f 100644 --- a/DashAI/back/api/api_v1/endpoints/generative_session.py +++ b/DashAI/back/api/api_v1/endpoints/generative_session.py @@ -18,6 +18,7 @@ ) from DashAI.back.dependencies.registry import ComponentRegistry from DashAI.back.models import BaseGenerativeModel +from DashAI.back.models.RAG import PDFDocument, TxtDocument, BaseDocument from DashAI.back.tasks import BaseGenerativeTask from DashAI.back.tasks.RAG_task import RAGTask @@ -76,17 +77,17 @@ async def upload_generative_session( detail="RAG Task requires a non-empty list of document IDs.", ) - documents_paths = [] + documents_ids = [] for doc_id in params.parameters["documents"]: - doc = db.get(Document, doc_id) - if not doc: + document = db.get(Document, doc_id) + if not document: raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail=f"Document with ID {doc_id} not found.", + status_code=status.HTTP_400_BAD_REQUEST, + detail=f"Document with ID {doc_id} does not exist.", ) - documents_paths.append(doc.file_path) + documents_ids.append(document.id) - params.parameters["documents"] = documents_paths + params.parameters["documents"] = documents_ids # Continue with the session creation # Validate the model parameters diff --git a/DashAI/back/dependencies/database/models.py b/DashAI/back/dependencies/database/models.py index f6df5af0e..00fa509a1 100644 --- a/DashAI/back/dependencies/database/models.py +++ b/DashAI/back/dependencies/database/models.py @@ -640,6 +640,13 @@ class Document(Base): file_type: Mapped[str] = mapped_column(String, nullable=False) file_path: Mapped[str] = mapped_column(String, nullable=False) file_hash: Mapped[str] = mapped_column(String, nullable=False, unique=True) + optional_metadata: Mapped[Dict[str, Any]] = mapped_column(JSON, nullable=True) + created: Mapped[DateTime] = mapped_column(DateTime, default=datetime.now) + last_modified: Mapped[DateTime] = mapped_column( + DateTime, + default=datetime.now, + onupdate=datetime.now, + ) # Create a relationship for the related sessions and related chunks pipeline_links: Mapped[List["RAGDocumentPipelineSessionLink"]] = relationship( @@ -665,6 +672,11 @@ def sessions_related(self) -> List["GenerativeSession"]: def pipelines_related(self) -> List["RAGPipeline"]: """Return a list of pipelines related to the document.""" return [link.pipeline for link in self.pipeline_links] + + @property + def related_sessions_ids(self) -> List["GenerativeSession"]: + """Return a list of sessions related to the document.""" + return [link.session for link in self.pipeline_links] class RAGChunk(Base): @@ -685,6 +697,22 @@ class RAGChunk(Base): ) +class RAGPrompt(Base): + __tablename__ = "rag_prompt" + """ + Table to store all the information about a RAG prompt. + """ + id: Mapped[int] = mapped_column(primary_key=True) + class_name: Mapped[str] = mapped_column(String, nullable=False) + parameters: Mapped[JSON] = mapped_column(JSON, nullable=True) + + # Relationship with RAGPipeline + pipelines: Mapped[List["RAGPipeline"]] = relationship( + back_populates="prompt", + cascade="all, delete-orphan" + ) + + class RAGPipeline(Base): __tablename__ = "rag_pipeline" """ @@ -701,10 +729,14 @@ class RAGPipeline(Base): retriever_id: Mapped[int] = mapped_column( ForeignKey("rag_retriever.id", ondelete="CASCADE"), nullable=False ) + prompt_id: Mapped[int] = mapped_column( + ForeignKey("rag_prompt.id", ondelete="CASCADE"), nullable=False + ) # Relationships chunking_model: Mapped["RAGChunkingModel"] = relationship(back_populates="pipelines") retriever: Mapped["RAGRetriever"] = relationship(back_populates="pipelines") + prompt: Mapped["RAGPrompt"] = relationship(back_populates="pipelines") pipeline_links: Mapped[List["RAGDocumentPipelineSessionLink"]] = relationship( cascade="all, delete-orphan", back_populates="pipeline" diff --git a/DashAI/back/models/RAG/RAG_pipeline.py b/DashAI/back/models/RAG/RAG_pipeline.py index 9a6ff127c..be6f02457 100644 --- a/DashAI/back/models/RAG/RAG_pipeline.py +++ b/DashAI/back/models/RAG/RAG_pipeline.py @@ -14,6 +14,7 @@ from DashAI.back.models.RAG.chunking_models.base_chunking_model import BaseChunkingModel from DashAI.back.models.RAG.chunking_models.character_chunk_model import CharacterChunkModel from DashAI.back.models.RAG.chunking_models.token_chunk_model import TokenChunkModel +from DashAI.back.models.RAG.documents.BaseDocument import BaseDocument from DashAI.back.models.base_generative_model import BaseGenerativeModel from DashAI.back.models.text_to_text_generation_model import TextToTextGenerationTaskModel @@ -81,11 +82,10 @@ class RAGPipelineSchema(BaseSchema): # Document collection parameters documents: schema_field( list_field( - int_field(), - min_items=1, + int_field(gt=0) ), placeholder=None, - description="List of documents to be used in the RAG pipeline." + description="List of documents ids to be used in the RAG pipeline." ) # type: ignore chunking_model: schema_field( @@ -111,6 +111,12 @@ class RAGPipelineSchema(BaseSchema): description="Text generation model used in the RAG pipeline." ) # type: ignore + prompt_model: schema_field( + component_field(parent="Prompt"), + placeholder={"component": "DefaultGenerationPrompt", "params": {}}, + description="Prompt template used to format the input for the generation model." + ) # type: ignore + class RAGPipeline(BaseGenerativeModel): """Retrieval-Augmented Generation (RAG) pipeline.""" From 68598eb1cb51cbff19f5340bc65eca6a4c13faed Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 15 Oct 2025 17:40:12 -0300 Subject: [PATCH 047/218] refactor: Improve error handling and filter RAG sessions by task name in getRAGSessions --- DashAI/front/src/api/rag.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/DashAI/front/src/api/rag.ts b/DashAI/front/src/api/rag.ts index a154b7aa7..52dc2b6c4 100644 --- a/DashAI/front/src/api/rag.ts +++ b/DashAI/front/src/api/rag.ts @@ -12,7 +12,10 @@ export const getRAGSessions = async (): Promise => { throw new Error(`Failed to fetch RAG sessions: ${response.statusText}`); } - return response.data; + const ragSessions = response.data.filter( + (session) => session.task_name === "RAGTask", + ); + return ragSessions; }; export const getRAGSession = async (sessionId: number): Promise => { From fd2825a92fe82a89203deefd527d289a9d8ca513 Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 15 Oct 2025 18:00:15 -0300 Subject: [PATCH 048/218] refactor: Simplify session state updates with useCallback and improve initial values handling in RetrieverConfigurationStep --- .../RAG/NewSessionModal/NewSessionModal.jsx | 84 +++++++++++-------- .../RetrieverConfigurationStep.jsx | 46 +++++----- 2 files changed, 75 insertions(+), 55 deletions(-) diff --git a/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx b/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx index 6202ed345..5d9070bea 100644 --- a/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx +++ b/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx @@ -125,6 +125,48 @@ export default function NewSessionModal({ }); }, []); + const updateSessionDocuments = useCallback((docs) => { + setSessionData((prev) => ({ + ...prev, + parameters: { ...prev.parameters, documents: docs }, + })); + }, []); + + const updateSessionName = useCallback((name) => { + setSessionData((prev) => ({ + ...prev, + name: name, + })); + }, []); + + const updateSessionDescription = useCallback((description) => { + setSessionData((prev) => ({ + ...prev, + description: description, + })); + }, []); + + const updateRetrieverModel = useCallback((model) => { + setSessionData((prev) => ({ + ...prev, + parameters: { ...prev.parameters, retriever_model: model }, + })); + }, []); + + const updateChunkingModel = useCallback((model) => { + setSessionData((prev) => ({ + ...prev, + parameters: { ...prev.parameters, chunking_model: model }, + })); + }, []); + + const updateGeneratorModel = useCallback((model) => { + setSessionData((prev) => ({ + ...prev, + parameters: { ...prev.parameters, generator_model: model }, + })); + }, []); + const isNextOrFinishEnabled = () => { if (!stepValidity[activeStep]) { return false; @@ -235,50 +277,25 @@ export default function NewSessionModal({ {activeStep === 0 && ( - setSessionData((prev) => ({ - ...prev, - parameters: { ...prev.parameters, documents: docs }, - })) - } + setDocuments={updateSessionDocuments} setNextEnabled={(isValid) => handleStepValidation(0, isValid)} sessionName={sessionData.name} - setSesssionName={(name) => - setSessionData((prev) => ({ - ...prev, - name: name, - })) - } + setSesssionName={updateSessionName} sessionDescription={sessionData.description} - setSessionDescription={(description) => - setSessionData((prev) => ({ - ...prev, - description: description, - })) - } + setSessionDescription={updateSessionDescription} /> )} {activeStep === 2 && ( - setSessionData((prev) => ({ - ...prev, - parameters: { ...prev.parameters, retriever_model: model }, - })) - } + setRetrieverModel={updateRetrieverModel} setNextEnabled={(isValid) => handleStepValidation(2, isValid)} /> )} {activeStep === 1 && ( - setSessionData((prev) => ({ - ...prev, - parameters: { ...prev.parameters, chunking_model: model }, - })) - } + setChunkingModel={updateChunkingModel} setNextEnabled={(isValid) => handleStepValidation(1, isValid)} /> )} @@ -286,12 +303,7 @@ export default function NewSessionModal({ {activeStep === 3 && ( - setSessionData((prev) => ({ - ...prev, - parameters: { ...prev.parameters, generator_model: model }, - })) - } + setGeneratorModel={updateGeneratorModel} setNextEnabled={(isValid) => handleStepValidation(3, isValid)} /> )} diff --git a/DashAI/front/src/pages/generative/RAG/NewSessionModal/RetrieverConfigurationStep.jsx b/DashAI/front/src/pages/generative/RAG/NewSessionModal/RetrieverConfigurationStep.jsx index 32e75bcc7..ce5bf6911 100644 --- a/DashAI/front/src/pages/generative/RAG/NewSessionModal/RetrieverConfigurationStep.jsx +++ b/DashAI/front/src/pages/generative/RAG/NewSessionModal/RetrieverConfigurationStep.jsx @@ -1,4 +1,4 @@ -import { useState, useEffect, useCallback, useRef } from "react"; +import { useState, useEffect, useCallback, useRef, useMemo } from "react"; import PropTypes from "prop-types"; import { Box, Autocomplete, TextField, Typography } from "@mui/material"; @@ -19,6 +19,20 @@ function AutoSaveFormSchema({ }) { const formikRef = useRef(null); + const initialValues = useMemo(() => { + const baseValues = selectedRetriever.parameters || {}; + + // Merge with retrieverModel params (which contains user changes) + return { + ...baseValues, + ...(retrieverModel?.params || {}), + }; + }, [ + selectedRetriever.name, + selectedRetriever.parameters, + retrieverModel?.params, + ]); + useEffect(() => { if (formikRef.current && formikRef.current.values && currentFormValuesRef) { currentFormValuesRef.current = formikRef.current.values; @@ -29,10 +43,7 @@ function AutoSaveFormSchema({ { - const updatedRetriever = { - ...selectedRetriever, - parameters: newParams, - }; - setSelectedRetriever(updatedRetriever); + const handleRetrieverParametersSave = useCallback( + (newParams) => { + const newRetrieverModel = { + component: selectedRetriever?.name || "", + params: newParams, + }; - const newRetrieverModel = { - component: selectedRetriever?.name || "", - params: newParams, - }; - - setRetrieverModel(newRetrieverModel); - setNextEnabled(true); - }; + setRetrieverModel(newRetrieverModel); + setNextEnabled(true); + }, + [selectedRetriever?.name, setRetrieverModel, setNextEnabled], + ); return ( Date: Thu, 16 Oct 2025 05:38:24 -0300 Subject: [PATCH 049/218] baseline --- DashAI/back/api/api_v1/endpoints/documents.py | 16 +- DashAI/back/config.py | 1 + DashAI/back/dependencies/config_builder.py | 1 + DashAI/back/dependencies/database/models.py | 343 +++++--- DashAI/back/initial_components.py | 3 +- DashAI/back/job/generative_job.py | 6 + DashAI/back/models/RAG/Documents/__init__.py | 7 +- DashAI/back/models/RAG/RAG_pipeline.py | 513 ++++++----- .../models/RAG/Retrievers/dense_retriever.py | 252 +++++- .../models/RAG/Retrievers/retriever_model.py | 226 ++--- .../models/RAG/Retrievers/tfidf_retriever.py | 70 +- .../chunking_models/base_chunking_model.py | 201 ++++- .../chunking_models/character_chunk_model.py | 39 +- .../RAG/chunking_models/token_chunk_model.py | 20 +- .../base_document.py} | 6 +- DashAI/back/models/RAG/documents/chunk.py | 20 + .../models/RAG/documents/chunk_embedding.py | 17 + .../pdf_document.py} | 7 +- .../txt_document.py} | 6 +- .../embeddings/dense/fasttext_embedding.py | 17 +- .../embeddings/dense/huggingface_embedding.py | 31 +- .../models/RAG/embeddings/dense_embedding.py | 14 +- .../RAG/embeddings/trainable_encoding.py | 2 +- DashAI/back/models/RAG/exceptions.py | 0 .../custom_augmentation_prompt.py | 6 +- .../RAG/prompts/context_merge/__init__.py | 3 - .../context_merge/context_merge_prompt.py | 18 - .../custom_context_merge_prompt.py | 43 - .../generation/custom_generation_prompt.py | 10 +- .../default_QnA_generation_prompt.py | 4 + .../generation/default_generation_prompt.py | 6 +- .../prompts/generation/generation_prompt.py | 4 + DashAI/back/models/RAG/prompts/prompt.py | 37 +- DashAI/back/models/RAG/utils.py | 14 + .../models/text_to_text_generation_model.py | 2 + DashAI/front/src/api/job.ts | 18 + Untitled-1.ipynb | 796 ------------------ notas.md | 2 + 38 files changed, 1306 insertions(+), 1475 deletions(-) rename DashAI/back/models/RAG/{Documents/BaseDocument.py => documents/base_document.py} (92%) create mode 100644 DashAI/back/models/RAG/documents/chunk.py create mode 100644 DashAI/back/models/RAG/documents/chunk_embedding.py rename DashAI/back/models/RAG/{Documents/PDFDocument.py => documents/pdf_document.py} (89%) rename DashAI/back/models/RAG/{Documents/TxtDocument.py => documents/txt_document.py} (90%) create mode 100644 DashAI/back/models/RAG/exceptions.py delete mode 100644 DashAI/back/models/RAG/prompts/context_merge/__init__.py delete mode 100644 DashAI/back/models/RAG/prompts/context_merge/context_merge_prompt.py delete mode 100644 DashAI/back/models/RAG/prompts/context_merge/custom_context_merge_prompt.py delete mode 100644 Untitled-1.ipynb create mode 100644 notas.md diff --git a/DashAI/back/api/api_v1/endpoints/documents.py b/DashAI/back/api/api_v1/endpoints/documents.py index b0fe26048..6cfc7fa26 100644 --- a/DashAI/back/api/api_v1/endpoints/documents.py +++ b/DashAI/back/api/api_v1/endpoints/documents.py @@ -22,6 +22,7 @@ from DashAI.back.api.api_v1.schemas import DocumentResponse from DashAI.back.dependencies.database.models import Document +from DashAI.back.models.RAG.utils import hash_function router = APIRouter() log = logging.getLogger(__name__) @@ -130,14 +131,12 @@ async def upload_document( Upload a new document to the RAG system with file content and metadata. The metadata should be a JSON string with required fields and an 'optional_metadata' dict. """ - print("A") docs_folder_path = config["DOCUMENTS_PATH"] if not docs_folder_path.exists(): raise HTTPException( status_code=500, detail=f"Documents folder {docs_folder_path} does not exist.", ) - print("B") try: metadata_dict = json.loads(metadata) except json.JSONDecodeError: @@ -145,29 +144,25 @@ async def upload_document( file_name = metadata_dict.get("file_name") last_modified = metadata_dict.get("last_modified") - print("C") if not file_name or not last_modified: raise HTTPException( status_code=400, detail="Missing required metadata fields: 'filename' and 'last_modified'", ) - print("D") optional_metadata = metadata_dict.get("optional_metadata", {}) if not isinstance(optional_metadata, dict): raise HTTPException( status_code=400, detail="'optional_metadata' must be a dictionary", ) - print("E") try: content_bytes = await file.read() except Exception: raise HTTPException(status_code=400, detail="Failed to read file content") - hash256 = hashlib.sha256(content_bytes).hexdigest() - print("F") + file_content_hash = hash_function(content_bytes) with session_factory() as db: - existing_doc = db.query(Document).filter_by(file_hash=hash256).first() + existing_doc = db.query(Document).filter_by(file_hash=file_content_hash).first() if existing_doc: # Update existing document's information existing_doc.file_name = file_name @@ -202,7 +197,7 @@ async def upload_document( file_name=file_name, file_type=file_type, file_path=str(file_path), - file_hash=hash256, + file_hash=file_content_hash, optional_metadata=optional_metadata or None, ) db.add(doc) @@ -346,4 +341,5 @@ async def update_document_metadata( raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Internal database error", - ) from e \ No newline at end of file + ) from e + \ No newline at end of file diff --git a/DashAI/back/config.py b/DashAI/back/config.py index 97cd5b6a4..156d5083a 100644 --- a/DashAI/back/config.py +++ b/DashAI/back/config.py @@ -21,4 +21,5 @@ class DefaultSettings(BaseSettings): EXPLANATIONS_PATH: str = "explanations" EXPLORATIONS_PATH: str = "explorations" DOCUMENTS_PATH: str = "documents" + RAG_PATH: str = "rag" NOTEBOOK_PATH: str = "notebook" diff --git a/DashAI/back/dependencies/config_builder.py b/DashAI/back/dependencies/config_builder.py index 8aa64d836..4ee265377 100644 --- a/DashAI/back/dependencies/config_builder.py +++ b/DashAI/back/dependencies/config_builder.py @@ -62,5 +62,6 @@ def build_config_dict( config["LOGGING_LEVEL"] = getattr(logging, logging_level) config["INITIAL_COMPONENTS"] = get_initial_components() config["DOCUMENTS_PATH"] = local_path / config["DOCUMENTS_PATH"] + config["RAG_PATH"] = local_path / config["RAG_PATH"] return config diff --git a/DashAI/back/dependencies/database/models.py b/DashAI/back/dependencies/database/models.py index 00fa509a1..91c3c1efb 100644 --- a/DashAI/back/dependencies/database/models.py +++ b/DashAI/back/dependencies/database/models.py @@ -3,7 +3,7 @@ from datetime import datetime from typing import Any, Dict, List, Optional -from sqlalchemy import JSON, Boolean, CheckConstraint, DateTime, Enum, ForeignKey, Integer, String, Text, UniqueConstraint, ARRAY +from sqlalchemy import JSON, Boolean, CheckConstraint, Column, DateTime, Enum, ForeignKey, Integer, String, Text, UniqueConstraint, ARRAY from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import Mapped, mapped_column, relationship @@ -635,7 +635,7 @@ class Document(Base): """ Table to store all the information about a document. """ - id: Mapped[int] = mapped_column(primary_key=True) + id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) file_name: Mapped[str] = mapped_column(String, nullable=False) file_type: Mapped[str] = mapped_column(String, nullable=False) file_path: Mapped[str] = mapped_column(String, nullable=False) @@ -650,48 +650,78 @@ class Document(Base): # Create a relationship for the related sessions and related chunks pipeline_links: Mapped[List["RAGDocumentPipelineSessionLink"]] = relationship( + "RAGDocumentPipelineSessionLink", cascade="all, delete-orphan", back_populates="document" ) - chunks: Mapped[List["RAGChunk"]] = relationship( + chunks: Mapped[List["Chunk"]] = relationship( + "Chunk", back_populates="document", cascade="all, delete-orphan", ) - embeddings_links: Mapped[List["RAGDocumentChunksEmbeddingsLink"]] = relationship( + embedding_matrices: Mapped[List["RAGEmbeddingMatrix"]] = relationship( + "RAGEmbeddingMatrix", + back_populates="document", cascade="all, delete-orphan" ) @property - def sessions_related(self) -> List["GenerativeSession"]: + def get_related_sessions(self) -> List["GenerativeSession"]: """Return a list of sessions related to the document.""" return [link.session for link in self.pipeline_links] @property - def pipelines_related(self) -> List["RAGPipeline"]: + def get_related_pipelines(self) -> List["RAGPipeline"]: """Return a list of pipelines related to the document.""" return [link.pipeline for link in self.pipeline_links] + + def get_embedding_matrix(self, chunking_model_id: int, embedding_model_id: int) -> Optional["RAGEmbeddingMatrix"]: + """ + Get the embedding matrix for a specific combination of chunking and embedding models. - @property - def related_sessions_ids(self) -> List["GenerativeSession"]: - """Return a list of sessions related to the document.""" - return [link.session for link in self.pipeline_links] + Args: + chunking_model_id: ID of the chunking model + embedding_model_id: ID of the embedding model + + Returns: + The embedding matrix if found, None otherwise + """ + for matrix in self.embedding_matrices: + if (matrix.chunking_model_id == chunking_model_id and + matrix.embedding_model_id == embedding_model_id): + return matrix + return None -class RAGChunk(Base): - __tablename__ = "rag_chunk" +class Chunk(Base): + __tablename__ = "chunk" """ Table to store all the information about a chunk. """ - id: Mapped[int] = mapped_column(primary_key=True) - text: Mapped[str] = mapped_column(Text, nullable=False) + id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) document_id: Mapped[int] = mapped_column( ForeignKey("document.id", ondelete="CASCADE"), nullable=False ) + chunk_index: Mapped[int] = mapped_column(Integer, nullable=False) + chunking_model_id: Mapped[int] = mapped_column( + ForeignKey("rag_chunking_model.id", ondelete="CASCADE"), + nullable=False + ) + text: Mapped[str] = mapped_column(Text, nullable=False) + hash: Mapped[str] = mapped_column(String, nullable=False, unique=True) - document: Mapped["Document"] = relationship(back_populates="chunks") + document: Mapped["Document"] = relationship( + "Document", + back_populates="chunks" + ) + chunking_model: Mapped["RAGChunkingModel"] = relationship( + "RAGChunkingModel", + back_populates="chunks" + ) + __table_args__ = ( UniqueConstraint("id", "document_id", name="uix_chunk_document"), ) @@ -702,61 +732,119 @@ class RAGPrompt(Base): """ Table to store all the information about a RAG prompt. """ - id: Mapped[int] = mapped_column(primary_key=True) + id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) class_name: Mapped[str] = mapped_column(String, nullable=False) parameters: Mapped[JSON] = mapped_column(JSON, nullable=True) # Relationship with RAGPipeline pipelines: Mapped[List["RAGPipeline"]] = relationship( + "RAGPipeline", back_populates="prompt", cascade="all, delete-orphan" ) +class RAGGenerationModel(Base): + __tablename__ = "rag_generation_model" + """ + Table to store all the information about a generation model. + """ + id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) + class_name: Mapped[str] = mapped_column(String, nullable=False) + parameters: Mapped[JSON] = mapped_column(JSON, nullable=True) + + # Relationships + pipelines: Mapped[List["RAGPipeline"]] = relationship( + back_populates="generation_model" + ) + class RAGPipeline(Base): __tablename__ = "rag_pipeline" """ Table to store all the information about a RAG pipeline. """ - id: Mapped[int] = mapped_column(primary_key=True) + id: Mapped[int] = mapped_column( + primary_key=True, + autoincrement=True) + session_id: Mapped[int] = mapped_column( + ForeignKey( + "generative_session.id", + ondelete="CASCADE"), + nullable=False + ) name: Mapped[str] = mapped_column(String, nullable=False) description: Mapped[str] = mapped_column(String, nullable=True) parameters: Mapped[JSON] = mapped_column(JSON, nullable=True) chunking_model_id: Mapped[int] = mapped_column( - ForeignKey("rag_chunking_model.id", ondelete="CASCADE"), nullable=False + ForeignKey( + "rag_chunking_model.id", + ondelete="CASCADE"), + nullable=False ) - retriever_id: Mapped[int] = mapped_column( - ForeignKey("rag_retriever.id", ondelete="CASCADE"), nullable=False + retriever_model_id: Mapped[int] = mapped_column( + ForeignKey( + "rag_retriever.id", + ondelete="CASCADE"), + nullable=False ) prompt_id: Mapped[int] = mapped_column( - ForeignKey("rag_prompt.id", ondelete="CASCADE"), nullable=False + ForeignKey( + "rag_prompt.id", + ondelete="CASCADE"), + nullable=False ) - + generation_model_id: Mapped[int] = mapped_column( + ForeignKey( + "rag_generation_model.id", + ondelete="CASCADE"), + nullable=False + ) + # Relationships - chunking_model: Mapped["RAGChunkingModel"] = relationship(back_populates="pipelines") - retriever: Mapped["RAGRetriever"] = relationship(back_populates="pipelines") - prompt: Mapped["RAGPrompt"] = relationship(back_populates="pipelines") + chunking_model: Mapped["RAGChunkingModel"] = relationship( + "RAGChunkingModel", + back_populates="pipelines" + ) + retriever: Mapped["RAGRetriever"] = relationship( + "RAGRetriever", + back_populates="pipelines" + ) + prompt: Mapped["RAGPrompt"] = relationship( + "RAGPrompt", + back_populates="pipelines" + ) + generation_model: Mapped["RAGGenerationModel"] = relationship( + "RAGGenerationModel", + back_populates="pipelines" + ) pipeline_links: Mapped[List["RAGDocumentPipelineSessionLink"]] = relationship( - cascade="all, delete-orphan", + "RAGDocumentPipelineSessionLink", back_populates="pipeline" ) - class RAGChunkingModel(Base): __tablename__ = "rag_chunking_model" """ Table to store all the information about a chunking model. """ - id: Mapped[int] = mapped_column(primary_key=True) + id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) class_name: Mapped[str] = mapped_column(String, nullable=False) parameters: Mapped[JSON] = mapped_column(JSON, nullable=True) pipelines: Mapped[List["RAGPipeline"]] = relationship( + "RAGPipeline", back_populates="chunking_model" ) - document_links: Mapped[List["RAGDocumentChunksEmbeddingsLink"]] = relationship( - cascade="all, delete-orphan" + + embedding_matrices: Mapped[List["RAGEmbeddingMatrix"]] = relationship( + "RAGEmbeddingMatrix", + back_populates="chunking_model" + ) + + chunks: Mapped[List["Chunk"]] = relationship( + "Chunk", + back_populates="chunking_model" ) @@ -765,16 +853,17 @@ class RAGRetriever(Base): """ Table to map the retriever model id to its dense or sparse retriever instance. """ - id: Mapped[int] = mapped_column(primary_key=True) + id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) class_name: Mapped[str] = mapped_column(String, nullable=False) # "SparseRetriever" or "DenseRetriever" - parameters: Mapped[JSON] = mapped_column(JSON, nullable=True) # The top-level parameters for the retriever, not the nested ones - sparse_id: Mapped[int] = mapped_column( - ForeignKey("rag_sparse_retriever.id", ondelete="CASCADE"), nullable=True + dense_retriever_id: Mapped[Optional[int]] = mapped_column( + ForeignKey("rag_dense_retriever.id", ondelete="CASCADE"), + nullable=True ) - dense_id: Mapped[int] = mapped_column( - ForeignKey("rag_dense_retriever.id", ondelete="CASCADE"), nullable=True + sparse_retriever_id: Mapped[Optional[int]] = mapped_column( + ForeignKey("rag_sparse_retriever.id", ondelete="CASCADE"), + nullable=True ) - + # Relationships sparse_retriever: Mapped[Optional["RAGSparseRetriever"]] = relationship( back_populates="related_retriever" @@ -785,14 +874,15 @@ class RAGRetriever(Base): pipelines: Mapped[List["RAGPipeline"]] = relationship( back_populates="retriever" ) - + __table_args__ = ( CheckConstraint( - "(sparse_id IS NOT NULL AND class_name = 'SparseRetriever' AND dense_id IS NULL) OR " - "(dense_id IS NOT NULL AND class_name = 'DenseRetriever' AND sparse_id IS NULL)", - name="chk_retriever_paradigm", + "(class_name = 'SparseRetriever' AND sparse_retriever_id IS NOT NULL AND dense_retriever_id IS NULL) OR " + "(class_name = 'DenseRetriever' AND dense_retriever_id IS NOT NULL AND sparse_retriever_id IS NULL)", + name="chk_retriever_type" ), ) + class RAGSparseRetriever(Base): @@ -800,13 +890,14 @@ class RAGSparseRetriever(Base): """ Table to store all the information about a sparse retriever. """ - id: Mapped[int] = mapped_column(primary_key=True) + id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) class_name: Mapped[str] = mapped_column(String, nullable=False) parameters: Mapped[JSON] = mapped_column(JSON, nullable=True) storage_folder: Mapped[str] = mapped_column(String, nullable=False) related_retriever: Mapped["RAGRetriever"] = relationship( - back_populates="sparse_retriever", uselist=False + "RAGRetriever", + back_populates="sparse_retriever", ) @@ -815,93 +906,145 @@ class RAGDenseRetriever(Base): """ Table to store all the information about a dense retriever. """ - id: Mapped[int] = mapped_column(primary_key=True) + id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) class_name: Mapped[str] = mapped_column(String, nullable=False) parameters: Mapped[JSON] = mapped_column(JSON, nullable=True) - chunks_embeddings_id: Mapped[int] = mapped_column( - ForeignKey("rag_chunks_embeddings.id", ondelete="CASCADE"), nullable=False + embedding_model_id: Mapped[int] = mapped_column( + ForeignKey("rag_embedding_model.id", ondelete="CASCADE"), nullable=False ) - + # Relationships related_retriever: Mapped["RAGRetriever"] = relationship( - back_populates="dense_retriever", uselist=False + "RAGRetriever", + back_populates="dense_retriever", ) - related_chunks_embeddings: Mapped["RAGChunksEmbeddings"] = relationship( - back_populates="related_dense_retrievers" + embedding_model: Mapped["RAGEmbeddingModel"] = relationship( + "RAGEmbeddingModel", + back_populates="dense_retrievers" ) -class RAGChunksEmbeddings(Base): - __tablename__ = "rag_chunks_embeddings" +class RAGEmbeddingModel(Base): + __tablename__ = "rag_embedding_model" """ - Table to store all the information about the chunks embeddings. + Table to store embedding model configurations. """ - id: Mapped[int] = mapped_column(primary_key=True) + id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) class_name: Mapped[str] = mapped_column(String, nullable=False) parameters: Mapped[JSON] = mapped_column(JSON, nullable=True) - embedding_dimension: Mapped[int] = mapped_column(Integer, nullable=False) - storage_folder: Mapped[str] = mapped_column(String, nullable=False) - - related_dense_retrievers: Mapped[List["RAGDenseRetriever"]] = relationship( - back_populates="related_chunks_embeddings" - ) - document_links: Mapped[List["RAGDocumentChunksEmbeddingsLink"]] = relationship( + + # Relationships + embedding_matrices: Mapped[List["RAGEmbeddingMatrix"]] = relationship( + back_populates="embedding_model", cascade="all, delete-orphan" ) + dense_retrievers: Mapped[List["RAGDenseRetriever"]] = relationship( + back_populates="embedding_model" + ) -""" -RAG relationship tables -""" - -class RAGDocumentPipelineSessionLink(Base): - __tablename__ = "rag_document_pipeline_session_link" +class RAGEmbeddingMatrix(Base): + __tablename__ = "rag_embedding_matrix" """ - Association table to link documents and sessions (many-to-many relationship). + Table to store embedding matrices for each unique combination of + document, chunking model, and embedding model. """ - id: Mapped[int] = mapped_column(primary_key=True) + id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) document_id: Mapped[int] = mapped_column( ForeignKey("document.id", ondelete="CASCADE"), nullable=False ) - session_id: Mapped[int] = mapped_column( - ForeignKey("generative_session.id", ondelete="CASCADE"), nullable=False + chunking_model_id: Mapped[int] = mapped_column( + ForeignKey("rag_chunking_model.id", ondelete="CASCADE"), nullable=False ) - pipeline_id: Mapped[int] = mapped_column( - ForeignKey("rag_pipeline.id", ondelete="CASCADE"), nullable=False + embedding_model_id: Mapped[int] = mapped_column( + ForeignKey("rag_embedding_model.id", ondelete="CASCADE"), nullable=False + ) + storage_folder: Mapped[str] = mapped_column(String, nullable=False) + matrix_shape: Mapped[List[int]] = mapped_column(JSON, nullable=False) # [num_chunks, embedding_dim] + created: Mapped[DateTime] = mapped_column(DateTime, default=datetime.now) + last_modified: Mapped[DateTime] = mapped_column( + DateTime, + default=datetime.now, + onupdate=datetime.now, ) - - # Relationships - document: Mapped["Document"] = relationship(back_populates="pipeline_links") - pipeline: Mapped["RAGPipeline"] = relationship(back_populates="pipeline_links") - session: Mapped["GenerativeSession"] = relationship("GenerativeSession") - # Constraints - __table_args__ = ( - UniqueConstraint("document_id", "session_id", name="uix_document_session"), - UniqueConstraint("session_id", "pipeline_id", name="uix_session_pipeline"), - UniqueConstraint("document_id", "pipeline_id", name="uix_document_pipeline"), + # Relationships + document: Mapped["Document"] = relationship( + "Document", + back_populates="embedding_matrices" + ) + chunking_model: Mapped["RAGChunkingModel"] = relationship( + "RAGChunkingModel", + back_populates="embedding_matrices" + ) + embedding_model: Mapped["RAGEmbeddingModel"] = relationship( + "RAGEmbeddingModel", + back_populates="embedding_matrices" ) - -class RAGDocumentChunksEmbeddingsLink(Base): - __tablename__ = "rag_document_chunks_embeddings_link" - """ - Association table to link documents, chunking models and chunks embeddings (many-to-many relationship). - """ - id: Mapped[int] = mapped_column(primary_key=True) - document_id: Mapped[int] = mapped_column( - ForeignKey("document.id", ondelete="CASCADE"), nullable=False + # Constraints - ensure uniqueness of the combination + __table_args__ = ( + UniqueConstraint( + "document_id", + "chunking_model_id", + "embedding_model_id", + name="uix_document_chunking_embedding" + ), ) - chunking_model_id: Mapped[int] = mapped_column( - ForeignKey("rag_chunking_model.id", ondelete="CASCADE"), nullable=False - ) + @property + def num_chunks(self) -> int: + """Return the number of chunks in this embedding matrix.""" + return self.matrix_shape[0] if self.matrix_shape else 0 - chunks_embeddings_id: Mapped[int] = mapped_column( - ForeignKey("rag_chunks_embeddings.id", ondelete="CASCADE"), nullable=False - ) + @property + def embedding_dimension(self) -> int: + """Return the embedding dimension.""" + return self.matrix_shape[1] if len(self.matrix_shape) > 1 else 0 + + @classmethod + def get_by_tuple(cls, session, document_id: int, chunking_model_id: int, embedding_model_id: int) -> Optional["RAGEmbeddingMatrix"]: + """ + Get an embedding matrix by the tuple (document_id, chunking_model_id, embedding_model_id). + + Args: + session: SQLAlchemy session + document_id: ID of the document + chunking_model_id: ID of the chunking model + embedding_model_id: ID of the embedding model + + Returns: + The embedding matrix if found, None otherwise + """ + return session.query(cls).filter( + cls.document_id == document_id, + cls.chunking_model_id == chunking_model_id, + cls.embedding_model_id == embedding_model_id + ).first() + + - # Constraints + + +""" +RAG relationship tables +""" + +class RAGDocumentPipelineSessionLink(Base): + __tablename__ = "rag_document_pipeline_session_link" + + id = Column(Integer, primary_key=True, autoincrement=True) + document_id = Column(Integer, ForeignKey("document.id", ondelete="CASCADE"), nullable=False) + session_id = Column(Integer, ForeignKey("generative_session.id", ondelete="CASCADE"), nullable=False) + pipeline_id = Column(Integer, ForeignKey("rag_pipeline.id", ondelete="CASCADE"), nullable=False) + + # Relationships + document = relationship("Document", back_populates="pipeline_links") + pipeline = relationship("RAGPipeline", back_populates="pipeline_links") + session = relationship("GenerativeSession", back_populates="pipeline_links") + __table_args__ = ( - UniqueConstraint("document_id", "chunking_model_id", "chunks_embeddings_id", name="uix_document_chunking_model_embeddings"), + UniqueConstraint("document_id", "session_id", name="uix_document_session"), + UniqueConstraint("session_id", "pipeline_id", name="uix_session_pipeline"), + UniqueConstraint("document_id", "pipeline_id", name="uix_document_pipeline"), ) \ No newline at end of file diff --git a/DashAI/back/initial_components.py b/DashAI/back/initial_components.py index 07c1da0bf..14184c412 100644 --- a/DashAI/back/initial_components.py +++ b/DashAI/back/initial_components.py @@ -103,6 +103,7 @@ CustomAugmentationPrompt, # Chunking Models CharacterChunkModel, + TokenChunkModel, # Retrievers DenseRetriever, # Encodings @@ -281,8 +282,6 @@ def get_initial_components(): RandomUnderSamplerConverter, # RAG RAGPipeline, - CharacterChunkModel, - TokenChunkModel, # Chunking Models CharacterChunkModel, TokenChunkModel, diff --git a/DashAI/back/job/generative_job.py b/DashAI/back/job/generative_job.py index c032fef2a..71fa92530 100644 --- a/DashAI/back/job/generative_job.py +++ b/DashAI/back/job/generative_job.py @@ -16,6 +16,7 @@ from DashAI.back.job.base_job import BaseJob, JobError from DashAI.back.models.base_generative_model import BaseGenerativeModel from DashAI.back.tasks import BaseGenerativeTask +from DashAI.back.models.RAG.RAG_pipeline import RAGPipeline logging.basicConfig(level=logging.DEBUG) log = logging.getLogger(__name__) @@ -86,6 +87,11 @@ async def run( try: model_class = component_registry[generative_session.model_name]["class"] params = generative_session.parameters + if model_class == RAGPipeline: + params["db"] = db + params["component_registry"] = component_registry + params["session_id"] = generative_session.id + params["env_rag_path"] = config["RAG_PATH"] model: BaseGenerativeModel = model_class(**params) except Exception as e: log.exception(e) diff --git a/DashAI/back/models/RAG/Documents/__init__.py b/DashAI/back/models/RAG/Documents/__init__.py index 06bb27b6f..d88c9bd6b 100644 --- a/DashAI/back/models/RAG/Documents/__init__.py +++ b/DashAI/back/models/RAG/Documents/__init__.py @@ -1,3 +1,4 @@ -from .BaseDocument import BaseDocument -from .PDFDocument import PDFDocument -from .TxtDocument import TxtDocument \ No newline at end of file +from .base_document import BaseDocument +from .pdf_document import PDFDocument +from .txt_document import TxtDocument +from .chunk import Chunk \ No newline at end of file diff --git a/DashAI/back/models/RAG/RAG_pipeline.py b/DashAI/back/models/RAG/RAG_pipeline.py index be6f02457..b5832e6cd 100644 --- a/DashAI/back/models/RAG/RAG_pipeline.py +++ b/DashAI/back/models/RAG/RAG_pipeline.py @@ -1,4 +1,4 @@ -from typing import Any, Tuple, List, Dict +from typing import Any, Dict, List, Optional, Tuple from sqlalchemy.orm import Session from DashAI.back.core.schema_fields import ( @@ -10,73 +10,54 @@ string_field ) -from DashAI.back.dependencies.registry import component_registry -from DashAI.back.models.RAG.chunking_models.base_chunking_model import BaseChunkingModel -from DashAI.back.models.RAG.chunking_models.character_chunk_model import CharacterChunkModel -from DashAI.back.models.RAG.chunking_models.token_chunk_model import TokenChunkModel -from DashAI.back.models.RAG.documents.BaseDocument import BaseDocument +from DashAI.back.dependencies.database.models import ( + Document as DBDocument, + RAGPipeline as DBPipeline, + ) + +from DashAI.back.dependencies.registry.component_registry import ComponentRegistry from DashAI.back.models.base_generative_model import BaseGenerativeModel from DashAI.back.models.text_to_text_generation_model import TextToTextGenerationTaskModel - -from DashAI.back.models.RAG.chunking_models import ( - CharacterChunkModel, - TokenChunkModel, - BaseChunkingModel) - -chunking_models: Dict[str, BaseChunkingModel] = { - "CharacterChunkModel": CharacterChunkModel, - "TokenChunkModel": TokenChunkModel, +from DashAI.back.models.RAG.chunking_models.base_chunking_model import BaseChunkingModel +from DashAI.back.models.RAG.prompts import Prompt, DefaultGenerationPrompt, DefaultAugmentationPrompt +from DashAI.back.models.RAG.Retrievers.retriever_model import RetrieverModel + +from DashAI.back.models.RAG.documents import ( + BaseDocument, + TxtDocument, + PDFDocument, + Chunk +) +documents_models: Dict[str, BaseDocument] = { + "txt": TxtDocument, + "pdf": PDFDocument, } -from DashAI.back.models.RAG.Retrievers import ( - TFIDFRetriever, - DenseRetriever, - RetrieverModel) -retriever_models: Dict[str, RetrieverModel] = { - "TFIDFRetriever": TFIDFRetriever, - "DenseRetriever": DenseRetriever, -} +class RAGPipelineParametersError(Exception): + """Custom exception for invalid RAG pipeline parameters.""" -from DashAI.back.models.RAG.prompts import ( - DefaultGenerationPrompt, - DefaultAugmentationPrompt, - CustomGenerationPrompt, - CustomAugmentationPrompt -) -prompts = { - "DefaultGenerationPrompt": DefaultGenerationPrompt, - "DefaultAugmentationPrompt": DefaultAugmentationPrompt, - "CustomGenerationPrompt": CustomGenerationPrompt, - "CustomAugmentationPrompt": CustomAugmentationPrompt -} + def __init__(self, message: str): + super().__init__(message) -from DashAI.back.models.hugging_face import ( - DeepSeekModel, - QwenModel) +class RAGPipelineInitializationError(Exception): + """Custom exception for errors during RAG pipeline initialization.""" -chunking_models = { - "CharacterChunkModel": CharacterChunkModel, - "TokenChunkModel": TokenChunkModel, -} + def __init__(self, message: str): + super().__init__(message) -retriever_models = { - "TFIDFRetriever": TFIDFRetriever, - "DenseRetriever": DenseRetriever, -} +class RAGPipelineRuntimeError(Exception): + """Custom exception for errors during RAG pipeline execution.""" -generation_models = { - "DeepSeekModel": DeepSeekModel, - "QwenModel": QwenModel, -} + def __init__(self, message: str): + super().__init__(message) -class RAGPipelineParametersError(Exception): - """Custom exception for invalid RAG pipeline parameters.""" +class RAGDatabaseError(Exception): + """Custom exception for database-related errors in RAG pipeline.""" def __init__(self, message: str): super().__init__(message) - class RAGPipelineSchema(BaseSchema): """Schema for RAG pipeline.""" # Document collection parameters @@ -117,88 +98,80 @@ class RAGPipelineSchema(BaseSchema): description="Prompt template used to format the input for the generation model." ) # type: ignore - class RAGPipeline(BaseGenerativeModel): - """Retrieval-Augmented Generation (RAG) pipeline.""" + """Retrieval-Augmented Generation (RAG) pipeline. + + A pipeline that combines document retrieval with text generation to produce + contextually informed responses. The pipeline processes input through several stages: + 1. Document loading and chunking + 2. Information retrieval + 3. Context-aware text generation + """ COMPATIBLE_COMPONENTS = ["RAGTask"] - SCHEMA = RAGPipelineSchema - def __init__( self, - **kwargs): - """ - Initialize the DummyRetrieverModel with dummy parameters. + session_id: int = None + documents: Dict[int, BaseDocument] + chunking_model: BaseChunkingModel + chunking_model_id: int + chunks: Dict[int, Dict[int, Chunk]] + retriever: RetrieverModel + llm_model: TextToTextGenerationTaskModel + retrieval_algorithm: str + + def __init__(self, **kwargs: Any) -> None: + """Initialize the RAG pipeline with the specified components and configuration. Args: - distance_function (str): The distance function to use (e.g., "cosine", "euclidean"). - n_docs (int): The maximum number of documents to retrieve. - max_distance (float): The maximum distance allowed for retrieved documents. + kwargs: Configuration dictionary containing: + documents (List[int]): List of document IDs to use + chunking_model (dict): Configuration for the document chunking model + retriever_model (dict): Configuration for the retrieval model + generation_model (dict): Configuration for the text generation model + prompt_model (dict): Configuration for the prompt template + db (Session): Database session for document retrieval + + Raises: + RAGPipelineParametersError: If the configuration parameters are invalid + RAGPipelineInitializationError: If any component fails to initialize """ print("Initializing RAG pipeline") + self.session_id = kwargs.pop("session_id") + self.db: Session = kwargs.pop("db") + self.env_rag_path: str = kwargs.pop("env_rag_path") + + pipeline_db_model: DBPipeline = self.db.query(DBPipeline).filter_by(session_id=self.session_id).first() + if pipeline_db_model: + self.pipeline_db_model = pipeline_db_model + self.pipeline_id = pipeline_db_model.id + else: + self.pipeline_db_model = None + self.pipeline_id = None + self.component_registry: ComponentRegistry = kwargs.pop("component_registry") + self.documents_ids: List[int] = kwargs.pop("documents") + self.documents = self.load_documents_from_db(documents_ids=self.documents_ids) self.validate_params(kwargs) - - try: - documents_paths = kwargs['documents'] - chunking_model_args = kwargs['chunking_model'] - retriever_model_args = kwargs['retriever_model'] - generation_model_args = kwargs['generation_model'] - db:Session = kwargs['db'] - except KeyError as e: - raise ValueError(f"Missing required RAG pipeline parameter: {e}") - - for model in ['chunking_model', 'retriever_model', 'generation_model']: - assert kwargs[model]['component'], f"{model} component must be specified." - assert isinstance(kwargs[model]['params'], dict), f"{model} params must be a dictionary." - # Check they are not empty - assert kwargs[model]['params'] is not None, f"{model} params must be provided." - assert len(kwargs[model]['params']) > 0, f"{model} params cannot be empty." - - - - try: - chunking_model_class = chunking_models[chunking_model_args["component"]] - chunking_model_params = chunking_model_args['params'] - self.chunking_model: BaseChunkingModel = chunking_model_class(**chunking_model_params) - except KeyError as e: - raise ValueError(f"Invalid chunking model specified: {e}") - except Exception as e: - raise ValueError(f"Error initializing chunking model: {e}") - - try: - retriever_model_class = retriever_models[retriever_model_args["component"]] - retriever_params = retriever_model_args['params'] - except KeyError as e: - raise ValueError(f"Invalid retriever model specified: {e}") - - try: - generation_model_class = generation_models[generation_model_args["component"]] - generation_params = generation_model_args['params'] + try: + config = { + 'chunking_model': kwargs.pop('chunking_model'), + 'retriever_model': kwargs.pop('retriever_model'), + 'generation_model': kwargs.pop('generation_model'), + 'prompt_model': kwargs.pop('prompt_model'), + } except KeyError as e: - raise ValueError(f"Invalid generation model specified: {e}") + raise RAGPipelineParametersError(f"Missing required parameter: {str(e)}") - assert isinstance(documents_paths, list) and len(documents_paths) > 0, "Documents must be a non-empty list." - for path in documents_paths: - assert isinstance(path, str), f"Each document path must be a string, got {type(path)}" - - print(f"Initializing LLM model {generation_model_args['component']}") - self.llm_model: TextToTextGenerationTaskModel = generation_model_class(**generation_params) - - - new_retriever_args = { - 'documents_paths': documents_paths, - } - for key, value in retriever_params.items(): - new_retriever_args[key] = value - - new_retriever_args['chunking_model'] = self.chunking_model - # Rename TFIDFVectorizer to TFIDFVectorizer_parameters - if retriever_model_class == TFIDFRetriever: - new_retriever_args['TFIDFVectorizer_parameters'] = new_retriever_args.pop('TFIDFVectorizer') - print("Initializing retriever model") - self.retriever: RetrieverModel = retriever_model_class(**new_retriever_args) - + self.chunking_model = self.init_component(config["chunking_model"]) + self.chunks = self.chunking_model.get_chunks() + self.chunking_model_id = self.chunking_model.id + + self.retriever = self.init_component(config["retriever_model"]) + self.retriever_id = self.retriever.retriever_db_model.id + self.llm_model = self.init_component(config["generation_model"]) + self.prompt_model = self.init_component(config["prompt_model"]) + self.prompt_db_id = self.prompt_model.id self.retrieval_algorithm = "SINGLE_INTERACTION" print("RAG pipeline initialized") @@ -206,93 +179,257 @@ def validate_params( self, params: dict): """Validate RAG pipeline parameters.""" - required_keys = ["documents", "chunking_model", "retriever_model", "generation_model", "prompt"] + required_keys = ["chunking_model", "retriever_model", "generation_model", "prompt_model"] for key in required_keys: if key not in params: - raise RAGPipelineParametersError(f"Missing required parameter: {key}") - if not isinstance(params["documents"], list) or len(params["documents"]) == 0: - raise RAGPipelineParametersError("Documents must be a non-empty list.") - for model in ["chunking_model", "retriever_model", "generation_model"]: - if "component" not in params[model]: - raise RAGPipelineParametersError(f"Missing 'component' in {model}.") - if "params" not in params[model]: - raise RAGPipelineParametersError(f"Missing 'params' in {model}.") - if "documents_ids" in any(params["chunking_model"], params["retriever_model"], params["generation_model"]): - raise RAGPipelineParametersError("Models should not contain 'documents_ids'; it is specified globally.") - if not params["prompt"]["type"]: - raise RAGPipelineParametersError("Missing 'type' in prompt.") - if not params["prompt"]["template"]: - raise RAGPipelineParametersError("Missing 'template' in prompt.") - + raise RAGPipelineParametersError(f"Missing required parameter '{key}' in RAG pipeline configuration") + + + # Validate model components + for model in ["chunking_model", "retriever_model", "generation_model", "prompt_model"]: + args = params[model] + if "component" not in args: + raise RAGPipelineParametersError(f"Missing 'component' field in '{model}' configuration") + if "params" not in args: + raise RAGPipelineParametersError(f"Missing 'params' field in '{model}' configuration") + if args["component"] not in self.component_registry: + raise RAGPipelineParametersError(f"No components registered for type '{model}'") + if "Custom" in params["prompt_model"]["component"] and "template" not in params["prompt_model"]["params"]: + raise RAGPipelineParametersError("Custom prompt model requires a 'template' parameter in its configuration") + + def single_interaction( + self, + query: str, + history: Optional[List[Tuple[str, str]]] = None + ) -> List[Chunk]: + """Perform a single retrieval interaction based on the input query. + + Args: + query: The input query to use for document retrieval + history: Optional conversation history (not used in single interaction) + + Returns: + List of tuples containing (document_content, document_file, chunk_id) - def single_interaction(self, input: str, history: List[Tuple[str, str]] = None) -> List[Tuple[str, str, int]]: + Raises: + RAGPipelineRuntimeError: If document retrieval fails """ - Single interaction retrieval algorithm: input -> retrieve documents. + try: + return self.retriever.retrieve(query) + except Exception as e: + raise RAGPipelineRuntimeError(f"Document retrieval failed: {str(e)}") + + def augmented_interaction( + self, + query: str, + history: Optional[List[Tuple[str, str]]] = None, + max_search_terms: int = 5 + ) -> List[Chunk]: + """Perform an augmented retrieval interaction using generated search terms. + Args: - input (str): The input query. + query: The input query + history: Optional conversation history + max_search_terms: Maximum number of search terms to use + Returns: - str: The generated response. + List of tuples containing (document_content, document_file, chunk_id) + + Raises: + RAGPipelineRuntimeError: If any step of the augmented interaction fails """ + try: + search_terms = self._generate_search_terms(query, history, max_search_terms) + return self._retrieve_with_search_terms(search_terms) + except RAGPipelineRuntimeError: + raise + except Exception as e: + raise RAGPipelineRuntimeError(f"Failed during augmented interaction: {str(e)}") - documents = self.retriever.retrieve(input) + def _generate_search_terms( + self, + query: str, + history: Optional[List[Tuple[str, str]]], + max_terms: int + ) -> List[str]: + """Generate search terms from the input using the LLM. - return documents - - - def augmented_interaction(self, input: str, history: List[Tuple[str, str]] = None) -> List[Tuple[str, str, int]]: + Args: + query: Input query to generate search terms from + history: Optional conversation history + max_terms: Maximum number of search terms to return + + Returns: + List of generated search terms + + Raises: + RAGPipelineRuntimeError: If search term generation or parsing fails """ - Augmented interaction RAG algorithm: input -> generate lookup tokens -> retrieve documents -> generate response. + try: + augmentation_prompt = DefaultAugmentationPrompt.format( + input=query, + history=history, + n_search_terms=max_terms + ) + augmentation_response = self.llm_model.generate(augmentation_prompt)[0] + print(f"Augmentation response: {augmentation_response}") + + try: + search_terms = augmentation_response.split("keywords:")[1].strip() + search_terms = [term.strip() for term in search_terms.split(",")] + return search_terms[:max_terms] + except Exception as e: + raise RAGPipelineRuntimeError(f"Failed to parse search terms from model response: {str(e)}") + except Exception as e: + raise RAGPipelineRuntimeError(f"Failed to generate search terms: {str(e)}") + + def _retrieve_with_search_terms(self, search_terms: List[str]) -> List[Chunk]: + """Retrieve documents using the generated search terms. + Args: - input (str): The input query. + search_terms: List of search terms to use for retrieval + Returns: - str: The generated response. + List of Chunk objects + + Raises: + RAGPipelineRuntimeError: If document retrieval fails """ - augmentation_prompt = DefaultAugmentationPrompt.format( - input=input, - history=history, - n_search_terms=5 - ) - augmentation_response = self.llm_model.generate(augmentation_prompt)[0] - print(f"Augmentation response: {augmentation_response}") - search_terms = augmentation_response.split("keywords:")[1].strip() - search_terms = search_terms.split(",") - if len(search_terms) > 5: - search_terms = search_terms[:5] - print(f"Augmentation search terms: {search_terms}") - search_terms = [term.strip() for term in search_terms] - - documents = self.retriever.retrieve(search_terms) - - return documents + try: + print(f"Retrieving documents with search terms: {search_terms}") + return self.retriever.retrieve(search_terms) + except Exception as e: + raise RAGPipelineRuntimeError(f"Document retrieval failed: {str(e)}") - def generate(self, input: Tuple[str, List[Tuple[str,str]]]) -> str: + def generate(self, input_data: Tuple[str, List[Tuple[str, str]]]) -> List[str]: + """Generate a response based on the input and retrieved documents. + + Args: + input_data: Tuple containing (query, conversation_history) + + Returns: + List containing the generated response with source information + + Raises: + RAGPipelineRuntimeError: If any generation step fails """ - Generate a response based on the input and the retrieved documents. + try: + input_message = input_data + chunks = self.single_interaction(input_message) + chunks_texts = [] + for chunk in chunks: + chunk_id = chunk.id + document_id = chunk.document_id + document_position = chunk.document_position + document = self.documents[document_id] + chunks_texts.append(f"Document {document.file_name}, chunk nº {document_position}, text:\n {chunk.text}") + chunks_text = "\n\n".join(chunks_texts) + return self._generate_response(input_message, chunks_text) + except RAGPipelineRuntimeError: + raise + except Exception as e: + raise RAGPipelineRuntimeError(f"Failed during response generation: {str(e)}") + + def _generate_response(self, input_message: str, chunks_text: str) -> List[str]: + """Generate the final response using the LLM. + Args: - input: a tuple containing the input query and the conversation history. - input (str): The input query. - history (List[Tuple[str, str]]): The conversation history. + query: Original input query + context: Formatted context from retrieved chunks + Returns: - str: The generated response. + List containing the generated response with source information + + Raises: + RAGPipelineRuntimeError: If response generation fails + """ + try: + prompt = DefaultGenerationPrompt.format( + input=input_message, + history=None, + chunks=chunks_text + ) + print(f"Prompt: {prompt[:500]}...") + + response = self.llm_model.generate(prompt) + full_response = f"{response[0]}\n\nSources:{chunks_text}" + return [full_response] + except Exception as e: + raise RAGPipelineRuntimeError(f"Text generation failed: {str(e)}") + + def load_documents_from_db(self, documents_ids: List[int]) -> Dict[int, BaseDocument]: """ - message = input + Retrieve Document instances from the database based on their IDs. + + Args: + documents_ids: List of document IDs to retrieve + db: Database session for querying documents - chunks = self.single_interaction(message) - chunks_str = "RETRIEVED INFORMATION:\n\n" - for doc_content, doc_file, chunk in chunks: - doc_name = doc_file.split("/")[-1] - chunks_str += f"Document '{doc_name}' in chunk: {chunk}:\n{doc_content}\n\n" + Raises: + RAGDatabaseError: If a document ID is not found in the database - prompt = DefaultGenerationPrompt.format( - input=message, - history=None, - chunks=chunks_str - ) + Returns: + List of BaseDocument instances corresponding to the provided IDs - print(f"Prompt: {prompt}") + Raises: + RAGDatabaseError: If a document ID is not found in the database + """ + documents = {} + for doc_id in documents_ids: + db_doc: DBDocument = self.db.query(DBDocument).filter(DBDocument.id == doc_id).first() + if not db_doc: + raise RAGDatabaseError(f"Document with ID {doc_id} not found in the database.") + doc_class = documents_models[db_doc.file_type] + document: BaseDocument = doc_class( + id = db_doc.id, + file_name = db_doc.file_name, + file_path = db_doc.file_path, + created = db_doc.created, + optional_metadata = db_doc.optional_metadata) + documents[doc_id] = document + return documents + + def init_component( + self, + config: Dict[str, Any]) -> Any: + """ + Initialize a component based on the provided configuration, using the component registry. - response = self.llm_model.generate(prompt) + Args: + model_name: The key in the config dict for the component to initialize + config: Configuration dictionary containing component details - response = f"{response[0]}\n\nSources:{chunks_str}" + Returns: + An instance of the initialized component - return [response] + Raises: + RAGPipelineInitializationError: If the component fails to initialize + """ + + model_class_name = config['component'] + model_params = config['params'] + model_registry = self.component_registry[model_class_name] + model_class = model_registry['class'] + + if 'db' in model_class.REQUIRED_EXTRA_KWARGS: + model_params['db'] = self.db + model_params['pipeline_id'] = self.pipeline_id + if 'pipeline_id' in model_class.REQUIRED_EXTRA_KWARGS: + model_params['pipeline_id'] = self.pipeline_id + if 'component_registry' in model_class.REQUIRED_EXTRA_KWARGS: + model_params['component_registry'] = self.component_registry + if 'env_rag_path' in model_class.REQUIRED_EXTRA_KWARGS: + model_params['env_rag_path'] = self.env_rag_path + + if 'documents' in model_class.REQUIRED_EXTRA_KWARGS: + model_params['documents'] = self.documents + if 'chunks' in model_class.REQUIRED_EXTRA_KWARGS: + model_params['chunks'] = self.chunks + if 'chunking_model_id' in model_class.REQUIRED_EXTRA_KWARGS: + model_params['chunking_model_id'] = self.chunking_model_id + try: + model_instance = model_class(**model_params) + except Exception as e: + raise RAGPipelineInitializationError(f"Failed to initialize {model_class_name}: {str(e)}") + return model_instance + \ No newline at end of file diff --git a/DashAI/back/models/RAG/Retrievers/dense_retriever.py b/DashAI/back/models/RAG/Retrievers/dense_retriever.py index 683d33ae7..bd2d70f5d 100644 --- a/DashAI/back/models/RAG/Retrievers/dense_retriever.py +++ b/DashAI/back/models/RAG/Retrievers/dense_retriever.py @@ -1,11 +1,28 @@ +import os +from typing import Dict, List +import numpy as np +from sqlalchemy.orm import Session +from sklearn.metrics.pairwise import pairwise_distances + from DashAI.back.core.schema_fields import ( BaseSchema, component_field, enum_field, schema_field, + int_field ) - -from .retriever_model import RetrieverModel +from DashAI.back.dependencies.registry.component_registry import ComponentRegistry +from DashAI.back.dependencies.database.models import ( + RAGEmbeddingMatrix as EmbeddingMatrixDBModel, + RAGEmbeddingModel as EmbeddingDBModel, + RAGDenseRetriever as DenseRetrieverDBModel, + RAGRetriever as RetrieverDBModel, + RAGPipeline as PipelineDBModel, +) +from DashAI.back.models.RAG.documents import BaseDocument, Chunk +from DashAI.back.models.RAG.Retrievers.retriever_model import RetrieverModel +from DashAI.back.models.RAG.embeddings.dense import FastTextEmbedding, HuggingFaceEmbedding +from DashAI.back.models.RAG.embeddings.dense_embedding import DenseEmbedding class DenseRetrieverSchema(BaseSchema): """Schema for Dense Retriever.""" @@ -17,9 +34,20 @@ class DenseRetrieverSchema(BaseSchema): ) # type: ignore similarity_metric: schema_field( - enum_field(enum=["cosine", "dot_product", "euclidean"]), + enum_field(enum=[ + "cityblock", "cosine", "euclidean", "l1", "l2", "manhattan", "nan_euclidean", + "braycurtis", "canberra", "chebyshev", "correlation", "dice", "hamming", "jaccard", + "mahalanobis", "minkowski", "rogerstanimoto", "russellrao", "seuclidean", + "sokalmichener", "sokalsneath", "sqeuclidean", "yule" + ]), placeholder="cosine", - description="Similarity metric to use for comparing dense vectors.", + description="Distance metric to use for comparing dense vectors. For reference see https://scikit-learn.org/stable/modules/generated/sklearn.metrics.pairwise_distances.html#sklearn.metrics.pairwise_distances", + ) # type: ignore + + top_k: schema_field( + int_field(gt=0), + placeholder=5, + description="Number of top documents to retrieve." ) # type: ignore @@ -27,47 +55,203 @@ class DenseRetriever(RetrieverModel): """ Dense retriever class for retrieving documents based on dense vector representations. - This class is a placeholder and should be implemented with specific dense retrieval - logic. """ SCHEMA = DenseRetrieverSchema + pipeline_id: int + db: Session + component_registry: ComponentRegistry + env_rag_path: str|os.PathLike + + documents: Dict[int, BaseDocument] + chunks: Dict[int, Dict[int, Chunk]] + chunking_model_id: int + + id: int + retriever_db_model = RetrieverDBModel + dense_retriever_db_model: DenseRetrieverDBModel + embedding_model: DenseEmbedding + embedding_db_model: EmbeddingDBModel + embedding_db_matrices: Dict[int, EmbeddingMatrixDBModel] + + matrix_row_to_chunk_id: Dict[int, int] + chunk_id_to_doc_id: Dict[int, int] + def __init__(self, **kwargs): + # RetrieverModel class fetches retriever_db_model if exists super().__init__(**kwargs) + + + self.embedding_model: DenseEmbedding = self.params["encoding_model"] + self.embedding_class_name = self.embedding_model.__class__.__name__ + self.embedding_params = self.embedding_model.params + self.params["encoding_model"] = { + "component": self.embedding_class_name, + "params": self.embedding_params + } + self.fetch_db_models() + self.similarity_metric = self.params["similarity_metric"] + self.top_k = self.params["top_k"] + + if self.embedding_db_model is None: + self.embedding_db_model = self.create_embedding_db_model() + self.compute_missing_embeddings() + if not self.dense_retriever_db_model: + db_model = DenseRetrieverDBModel( + class_name=self.__class__.__name__, + parameters=self.params, + embedding_model_id=self.embedding_db_model.id + ) + self.db.add(db_model) + self.db.commit() + self.db.refresh(db_model) + self.dense_retriever_db_model = db_model + if not self.retriever_db_model: + retriever_db_model = RetrieverDBModel( + class_name=self.__class__.__name__, + dense_retriever_id=self.dense_retriever_db_model.id, + sparse_retriever_id=None + ) + self.db.add(retriever_db_model) + self.db.commit() + self.db.refresh(retriever_db_model) + self.retriever_db_model = retriever_db_model + + self.init_similarity_matrix() + + def __fetch_embedding_db_model(self)-> EmbeddingDBModel|None: + """Fetch the embedding database model if it exists.""" + embedding_db_model = self.db.query(EmbeddingDBModel).filter_by( + class_name=self.embedding_class_name, + parameters=self.embedding_params + ).first() + return embedding_db_model + + def fetch_db_models(self): + """Fetch all database models related to the retriever if they exist.""" + self.embedding_db_model = self.__fetch_embedding_db_model() + + self.embedding_db_matrices = {} + if self.embedding_db_model and self.chunking_model_id: + self.embedding_db_matrices = self.fetch_embedding_matrices() + + self.retriever_db_model = None + self.dense_retriever_db_model = None + if self.pipeline_id: + pipeline_model = self.db.query(PipelineDBModel).filter_by( + id=self.pipeline_id).first() + retriever_id = pipeline_model.retriever_model_id + self.retriever_db_model = self.db.query(RetrieverDBModel).filter_by( + id=retriever_id).first() + dense_retriever_id = self.retriever_db_model.dense_retriever_id + self.dense_retriever_db_model = self.db.query(DenseRetrieverDBModel).filter_by( + id=dense_retriever_id).first() + + def fetch_embedding_matrices(self) -> Dict[int, EmbeddingMatrixDBModel]: + """Load precomputed embeddings from the database if they exist.""" + embeddings_matrices_db_models = {} + for doc_id, doc_chunks in self.chunks.items(): + embedding_matrix_entry = ( + self.db.query(EmbeddingMatrixDBModel) + .filter_by( + document_id=doc_id, + chunking_model_id=self.chunking_model_id, + embedding_model_id=self.embedding_db_model.id + ).first() + ) + if embedding_matrix_entry: + embeddings_matrices_db_models[doc_id] = embedding_matrix_entry + + return embeddings_matrices_db_models - self.validate_and_transform(kwargs) - - self._documents_path = kwargs.get("documents_path") - self.documents = kwargs.get("documents") - self.chunking_model = kwargs.get("chunking_model") - self.encoding_model = kwargs.get("encoding_model") - self.similarity_metric = kwargs.get("similarity_metric", "cosine") - - assert self._documents_path is not None, "Documents path must be provided." - assert self.documents is not None and len(self.documents) > 0, "Documents must be provided and cannot be empty." - assert self.validate_documents_in_folder(self.documents), "Some documents are missing from the folder." - assert self.chunking_model is not None, "Chunking model must be provided." - assert self.encoding_model is not None, "Encoding model must be provided." - assert self.similarity_metric in ["cosine", "dot_product", "euclidean"], ( - f"Invalid similarity metric: {self.similarity_metric}. " - "Choose from 'cosine', 'dot_product', or 'euclidean'." + def create_embedding_db_model(self) -> EmbeddingDBModel: + """Create the embedding model in the database.""" + new_model = EmbeddingDBModel( + class_name=self.embedding_class_name, + parameters=self.embedding_params ) - assert self.n_docs > 0, "Number of documents must be greater than 0." + self.db.add(new_model) + self.db.commit() + self.db.refresh(new_model) + return new_model - print(f"DenseRetriever initialized with encoding model: {self.encoding_model} and similarity metric: {self.similarity_metric}") + def save(self): + """Save the dense retriever model to the database.""" + pass - def load(): - """Load the dense retriever model.""" - print("Loading DenseRetriever model...") - # Placeholder for loading logic - pass + def compute_missing_embeddings(self): + chunking_model_id = self.chunking_model_id + embedding_model_id = self.embedding_db_model.id + assert embedding_model_id and chunking_model_id, "Embedding model ID and chunking model ID must be set to compute embeddings." + for doc_id, doc_chunks in self.chunks.items(): + db_model = self.embedding_db_matrices.get(doc_id, None) + if db_model: + print(f"Embeddings for document {doc_id} already exist in the database ({db_model}). Skipping computation.") + continue + chunk_texts = [chunk.text for chunk in doc_chunks.values()] + embeddings = self.embedding_model.batch_encode(chunk_texts) + matrix_shape = embeddings.shape + folder_name = f"doc_id-{doc_id}__chunking_model_id-{chunking_model_id}__embedding_model_id-{embedding_model_id}" + storage_folder = os.path.join(self.env_rag_path, "embeddings", folder_name) + os.makedirs(storage_folder, exist_ok=True) + file_path = os.path.join(storage_folder, "embeddings.npy") + np.save(file_path, embeddings) + new_db_model = EmbeddingMatrixDBModel( + document_id=doc_id, + chunking_model_id=chunking_model_id, + embedding_model_id=embedding_model_id, + matrix_shape=list(matrix_shape), + storage_folder=storage_folder + ) + self.db.add(new_db_model) + self.db.commit() + self.db.refresh(new_db_model) + self.embedding_db_matrices[doc_id] = new_db_model - def save(): - """Save the dense retriever model.""" - print("Saving DenseRetriever model...") - # Placeholder for saving logic - pass + def init_similarity_matrix(self): + """Initialize the similarity matrix for all chunks.""" + self.similarity_matrix = None + self.matrix_row_to_chunk_id = {} + self.chunk_id_to_doc_id = {} # Initialize the missing dictionary + if not self.embedding_db_matrices: + import warnings + warnings.warn("No embedding matrices found to initialize similarity matrix.") + return + all_embeddings = [] + row_index = 0 + for doc_id, chunks in self.chunks.items(): + matrix_db_model = self.embedding_db_matrices[doc_id] + matrix_folder = matrix_db_model.storage_folder + matrix_path = os.path.join(matrix_folder, "embeddings.npy") + assert os.path.exists(matrix_path), f"Embedding matrix file not found at {matrix_path}" + for chunk_id, chunk in chunks.items(): + self.matrix_row_to_chunk_id[row_index] = chunk_id + self.chunk_id_to_doc_id[chunk_id] = doc_id + row_index += 1 + embeddings = np.load(matrix_path) + all_embeddings.append(embeddings) + self.similarity_matrix = np.vstack(all_embeddings) + def retrieve(self, query: str) -> List[Chunk]: + """Retrieve the top_k most similar chunks to the query.""" + if self.similarity_matrix is None: + raise ValueError("Similarity matrix not initialized.") + query_embedding = self.embedding_model.encode(query) + # Get distances and indices for all chunks + distances = pairwise_distances( + query_embedding.reshape(1, -1), + self.similarity_matrix, + metric=self.similarity_metric + )[0] + top_indices = np.argsort(distances)[:self.top_k] + results = [] + for idx in top_indices: + chunk_id = self.matrix_row_to_chunk_id[idx] + doc_id = self.chunk_id_to_doc_id[chunk_id] + chunk = self.chunks[doc_id][chunk_id] + results.append(chunk) + return results + \ No newline at end of file diff --git a/DashAI/back/models/RAG/Retrievers/retriever_model.py b/DashAI/back/models/RAG/Retrievers/retriever_model.py index 203e8f514..fe77b3499 100644 --- a/DashAI/back/models/RAG/Retrievers/retriever_model.py +++ b/DashAI/back/models/RAG/Retrievers/retriever_model.py @@ -1,149 +1,83 @@ -from abc import ABC +from abc import ABC, abstractmethod import os from typing import Any, Dict, List, Final -from DashAI.back.models.RAG.documents import BaseDocument, PDFDocument, TxtDocument -import hashlib +from DashAI.back.dependencies.registry.component_registry import ComponentRegistry +from DashAI.back.models.RAG.documents import BaseDocument, PDFDocument, TxtDocument, Chunk +from DashAI.back.dependencies.database.models import( + Document as DocumentDBModel, + Chunk as ChunkDBModel, + RAGRetriever as RetrieverDBModel, + RAGPipeline as PipelineDBModel, +) +from DashAI.back.models.RAG.utils import hash_function +from sqlalchemy.orm import Session from DashAI.back.models.base_model import BaseModel -SUPPORTED_DOCUMENT_TYPES = ['pdf', 'txt'] - class RetrieverModel(BaseModel): """ Abstract class to define the interface for retriever models. """ - RETRIEVERS_PATH = "./StoredRetrievers" - COMPATIBLE_COMPONENTS = ["RAGTask"] + REQUIRED_EXTRA_KWARGS: Final[List[str]] = ["pipeline_id", "db", "component_registry", "env_rag_path", "documents", "chunks", "chunking_model_id"] + id: int + pipeline_id: int + db: Session + component_registry: ComponentRegistry + env_rag_path: str|os.PathLike - def _load_document(self, document_path: str) -> BaseDocument: - """ - Load a document from the specified path. - - Args: - document_path (str): The path to the document file. - - Returns: - BaseDocument: An instance of a document class (PDFDocument or TxtDocument). - """ - if document_path.endswith('.pdf'): - return PDFDocument(document_path) - elif document_path.endswith('.txt'): - return TxtDocument(document_path) - else: - raise ValueError(f"Unsupported document type: {document_path}") - - def get_documents(self) -> Dict[str, BaseDocument]: - """ - Get the documents stored in the retriever. - Returns: - Dict[str, BaseDocument]: A dictionary where keys are document paths and values are document instances. - """ - assert self._documents_paths is not None, "Document paths must be provided." - assert len(self._documents_paths) > 0, "At least one document path must be provided." - - self._documents_paths = sorted(self._documents_paths) # Sort for consistent hashing in signature - documents = {} - for path in self._documents_paths: - doc = self._load_document(path) - documents[path] = doc - return documents - - def get_documents_chunks(self) -> Dict[str, List[str]]: - """ - Get the chunks of documents stored in the retriever. + documents: Dict[int, BaseDocument] + chunks: Dict[int, Dict[int, Chunk]] + chunking_model_id: int - Returns: - Dict[str, Dict[int, str]]: A dictionary where keys are document paths and values are - dictionaries of chunk indices and their corresponding text. - """ - documents = self.get_documents() - chunks = {} - for filename, doc in documents.items(): - chunks[filename] = doc.get_chunks(self.chunk_size, self.chunk_overlap) - return chunks - - def get_parameters(self) -> Dict[str, Any]: - """ - Get the parameters of the retriever. - - Returns: - Dict[str, Any]: A dictionary of retriever parameters. - """ - assert self.params is not None, "Retriever parameters are not set." - return self.params + retriever_db_model = RetrieverDBModel - def get_signature_parameters(self) -> Dict[str, Any]: - """ - Get the parameters used for storing the fitted retriever in the database. - This parameters are a subset of the retriever parameters, the non-signature parameters are - those whose change does not require a retraining of the retriever, i.e. n_docs, - max_distance, etc. + def __init__(self, **kwargs): + self.params = kwargs - Returns: - Dict[str, Any]: A dictionary of parameters that can be used for hashing. - """ - raise NotImplementedError("This method should be implemented by subclasses.") - - def _get_documents_signature(self) -> str: - """ - Generate a hash representing the current set of documents. - - Returns: - str: A hash string representing the documents. - """ - documents = sorted(self.get_documents().items()) - hashes = "" - for filename, doc in documents.items(): - doc_hash = doc.get_hash() - hashes += f"{filename}{doc_hash}" - return hashlib.sha256(hashes.encode('utf-8')).hexdigest() - - def _get_parameters_signature(self) -> str: - """ - Generate a hash representing the retriever parameters. - - Args: - parameters (Dict[str, Any]): A dictionary of retriever parameters. - - Returns: - str: A hash string representing the parameters. - """ - hashable_parameters = sorted(self.get_signature_parameters().items()) - params_string = "".join(f"{key}{value}" for key, value in hashable_parameters) - return hashlib.sha256(params_string.encode('utf-8')).hexdigest() - - def _get_model_signature(self) -> str: - """ - Generate a unique hash for the retriever based on its documents and parameters. - - Returns: - str: A hash string representing the retriever's state. - """ - documents_hash = self._get_documents_signature() - parameters_hash = self._get_parameters_signature() - return f"{self.__class__.__name__}_{documents_hash}_{parameters_hash}" + self.pipeline_id: int = self.params.pop("pipeline_id") + self.db: Session = self.params.pop("db") + self.component_registry: ComponentRegistry = self.params.pop("component_registry") + self.env_rag_path: str|os.PathLike = self.params.pop("env_rag_path") + self.documents: Dict[int, BaseDocument] = self.params.pop("documents") + self.chunks: Dict[int, Dict[int, Chunk]] = self.params.pop("chunks") + self.chunking_model_id: int = self.params.pop("chunking_model_id") + self.validate_chunks() + self.params = self.validate_and_transform(self.params) + + + if self.pipeline_id is not None: + existing_pipeline: PipelineDBModel = self.db.query(PipelineDBModel).filter( + PipelineDBModel.id == self.pipeline_id + ).first() + self.retriever_db_model = self.db.query(RetrieverDBModel).filter( + RetrieverDBModel.id == existing_pipeline.retriever_model_id + ).first() + assert self.retriever_db_model is not None, "Retriever model not found in the database, but pipeline exists." + else: + self.pipeline_id = None + self.retriever_db_model = None + + def validate_chunks(self) -> None: + """Validate the structure and content of the chunks dictionary.""" + if not isinstance(self.chunks, dict): + raise ValueError("Chunks must be a dictionary.") + for doc_id, doc_chunks in self.chunks.items(): + if not isinstance(doc_id, int): + raise ValueError(f"Document ID {doc_id} must be an integer.") + if not isinstance(doc_chunks, dict): + raise ValueError(f"Chunks for document ID {doc_id} must be a dictionary.") + for chunk_id, chunk in doc_chunks.items(): + if not isinstance(chunk_id, int): + raise ValueError(f"Chunk ID {chunk_id} in document ID {doc_id} must be an integer.") + if not isinstance(chunk, Chunk): + raise ValueError(f"Chunk {chunk_id} in document ID {doc_id} must be an instance of Chunk.") + assert chunk.document_id == doc_id, f"Chunk {chunk_id} doc_id {chunk.doc_id} does not match document ID {doc_id}." - def add_document(self, document: BaseDocument) -> None: - """ - Add a document to the retriever. - Args: - document (BaseDocument): The document to add. - """ - raise NotImplementedError("This method should be implemented by subclasses.") - - def remove_document(self, document_id: str) -> None: - """ - Remove a document from the retriever by its ID. - - Args: - document_id (str): The ID of the document to remove. - """ - raise NotImplementedError("This method should be implemented by subclasses.") - - def retrieve(self, **kwargs) -> List[BaseDocument]: + @abstractmethod + def retrieve(self, **kwargs) -> List[Chunk]: """ Retrieve documents based on the provided parameters. @@ -154,19 +88,21 @@ def retrieve(self, **kwargs) -> List[BaseDocument]: List[BaseDocument]: A list of retrieved documents. """ raise NotImplementedError("This method should be implemented by subclasses.") - - def validate_documents_in_folder(self, documents: List[BaseDocument]) -> bool: - """ - Validate that the provided documents exist in their specified paths. - - Args: - documents (List[BaseDocument]): A list of documents to validate. - - Returns: - bool: True if all specified documents are present in the folder, False otherwise. - """ - for doc in documents: - if not os.path.exists(doc.file_path): - print(f"Document {doc.file_path} is missing.") - return False - return True \ No newline at end of file + + def init_retriever_db_model(self, dense_retriver_db_id: int, sparse_retriver_db_id: int) -> RetrieverDBModel: + """Initialize the retriever model in the database.""" + assert dense_retriver_db_id or sparse_retriver_db_id, "At least one of dense_retriver_db_id or sparse_retriver_db_id must be provided." + class_name = self.__class__.__name__ + retriever_db_model = RetrieverDBModel( + class_name=class_name, + dense_retriever_id=dense_retriver_db_id, + sparse_retriever_id=sparse_retriver_db_id, + ) + self.db.add(retriever_db_model) + self.db.commit() + + def load(self): + pass + + def save(self): + pass \ No newline at end of file diff --git a/DashAI/back/models/RAG/Retrievers/tfidf_retriever.py b/DashAI/back/models/RAG/Retrievers/tfidf_retriever.py index fbe19ec05..9aea0ba2d 100644 --- a/DashAI/back/models/RAG/Retrievers/tfidf_retriever.py +++ b/DashAI/back/models/RAG/Retrievers/tfidf_retriever.py @@ -1,4 +1,3 @@ -import hashlib import os import pickle from typing import Dict, List, Tuple @@ -19,10 +18,11 @@ string_field, ) from DashAI.back.models.RAG.chunking_models.base_chunking_model import BaseChunkingModel -from DashAI.back.models.RAG.documents.BaseDocument import BaseDocument +from DashAI.back.models.RAG.documents.base_document import BaseDocument from DashAI.back.models.base_model import BaseModel from DashAI.back.models.RAG.documents import PDFDocument, TxtDocument from DashAI.back.models.RAG.Retrievers.sparse_retriever import SparseRetriever +from DashAI.back.models.RAG.utils import hash_function similarities = {"cosine": cosine_similarity, "euclidean": euclidean_distances} @@ -214,13 +214,7 @@ class TFIDFRetriever(SparseRetriever): def __init__( self, - documents_paths: List[str], - TFIDFVectorizer_parameters: Dict[str, any], - similarity_function: str, - n_docs: int, - use_similarity_threshold: bool, - similarity_threshold: float, - chunking_model: BaseChunkingModel, + **kwargs, ): """ Initialize the TFIDFRetriever with the given parameters. @@ -236,38 +230,30 @@ def __init__( chunk_overlap (int): The overlap between chunks. """ - assert isinstance(documents_paths, list), "Documents must be a list." - assert all(isinstance(doc, str) for doc in documents_paths), ( - "All documents must be strings." - ) - assert similarity_function in similarities, ( - f"similarity_function must be one of {list(similarities.keys())}." - ) - assert n_docs > 0, "Number of documents to retrieve must be greater than 0." - assert similarity_threshold >= 0, "Similarity threshold must be non-negative." - BASE_DOC_PATH = ( - "THIS IS A PLACEHOLDER, should be unnecesary after implementing " - "the document persistence storage in the database" - ) - new_documents_paths = [] - for doc_path in documents_paths: - new_path = os.path.join(BASE_DOC_PATH, doc_path) - new_documents_paths.append(new_path) - documents_paths = new_documents_paths - self._documents_paths = sorted(documents_paths) # Sort for consistent hashing - self.documents = self.load_documents(self._documents_paths) - self.similarity_function_name = similarity_function - self.similarity_function = similarities[similarity_function] - self.n_docs = n_docs - self.use_similarity_threshold = use_similarity_threshold - self.similarity_threshold = similarity_threshold + documents = kwargs.pop("documents") + assert isinstance(documents, list) and all( + isinstance(doc, BaseDocument) for doc in documents + ), "Documents must be a list of BaseDocument instances." + self.documents: List[BaseDocument] = documents + + chunking_model = kwargs.pop("chunking_model") + assert isinstance(chunking_model, BaseChunkingModel), "Chunking model must be a BaseChunkingModel instance." self.chunking_model = chunking_model + TFIDFVectorizer_parameters = kwargs.pop("TFIDFVectorizer") + self.validate_and_transform(kwargs) + vectorizer = TFIDFVectorizerModel(**TFIDFVectorizer_parameters) # Validate parameters + self.similarity_function_name = kwargs.pop("similarity_function", "cosine") + self.similarity_function = similarities[self.similarity_function_name] + self.n_docs = kwargs.pop("n_docs") + self.use_similarity_threshold = kwargs.pop("use_similarity_threshold", False) + self.similarity_threshold = kwargs.pop("similarity_threshold", 0.5) + self.params = { "vectorizer_params": TFIDFVectorizer_parameters, - "similarity_function": similarity_function, - "n_docs": n_docs, - "similarity_threshold": similarity_threshold, + "similarity_function": self.similarity_function, + "n_docs": self.n_docs, + "similarity_threshold": self.similarity_threshold, } @@ -288,7 +274,7 @@ def __init__( self._fit() self._save_state() - def load(self) -> None: + def load(self, db) -> None: pass def save(self) -> None: @@ -299,7 +285,7 @@ def load_documents(self, documents_paths: List[str]) -> List[BaseDocument]: for i, doc_path in enumerate(documents_paths): with open(doc_path, "rb") as doc_file: file_bytes = doc_file.read() - file_hash = hashlib.sha256(file_bytes).hexdigest() + file_hash = hash_function(file_bytes) file_name = os.path.basename(doc_path) file_path = doc_path @@ -312,7 +298,7 @@ def load_documents(self, documents_paths: List[str]) -> List[BaseDocument]: ) elif doc_path.endswith(".txt"): doc = TxtDocument( - id = i, + db_id = i, file_name=file_name, file_path=file_path, file_hash=file_hash @@ -343,9 +329,9 @@ def _get_cache_paths(self) -> tuple[str, str, str]: def _generate_cache_hash(self) -> str: hashable_params = self.get_signature_parameters() text = f"{hashable_params}" - params_hash = hashlib.sha256(text.encode("utf-8")).hexdigest() + params_hash = hash_function(text.encode("utf-8")) docs_hashes = [doc.file_hash for doc in self.documents] - docs_hash = hashlib.sha256("".join(docs_hashes).encode("utf-8")).hexdigest() + docs_hash = hash_function("".join(docs_hashes).encode("utf-8")) return f"tfidf_retriever_{params_hash}_{docs_hash}" def _load_state(self) -> bool: diff --git a/DashAI/back/models/RAG/chunking_models/base_chunking_model.py b/DashAI/back/models/RAG/chunking_models/base_chunking_model.py index 14c811fa1..1cd2353ef 100644 --- a/DashAI/back/models/RAG/chunking_models/base_chunking_model.py +++ b/DashAI/back/models/RAG/chunking_models/base_chunking_model.py @@ -1,7 +1,15 @@ from abc import ABCMeta, abstractmethod from DashAI.back.config_object import ConfigObject -from DashAI.back.models.RAG.documents.BaseDocument import BaseDocument -from typing import Dict, Final, List +from DashAI.back.models.RAG.documents.base_document import BaseDocument +from DashAI.back.models.RAG.documents.chunk import Chunk +from DashAI.back.dependencies.database.models import ( + RAGChunkingModel as DBChunkingModel, + Chunk as DBChunkModel, + RAGPipeline as PipelineDBModel, +) +from typing import Any, Dict, Final, List +from sqlalchemy.orm import Session +from DashAI.back.models.RAG.utils import hash_function class BaseChunkingModel(ConfigObject, metaclass=ABCMeta): """ @@ -10,33 +18,190 @@ class BaseChunkingModel(ConfigObject, metaclass=ABCMeta): """ TYPE: Final[str] = "ChunkingModel" + REQUIRED_EXTRA_KWARGS: Final[List[str]] = ["documents", "db", "pipeline_id"] + id: int + pipeline_id: int + class_name: str + parameters: Dict[str, Any] def __init__(self, **kwargs): """ Initialize the chunking model with any necessary parameters. """ - raise NotImplementedError("Subclasses must implement the __init__ method.") - + self.db: Session = kwargs.pop("db") + self.pipeline_id: int = kwargs.pop("pipeline_id") + self.documents: Dict[int, BaseDocument] = kwargs.pop("documents") + self.class_name = self.__class__.__name__ + self.parameters = self.validate_and_transform(kwargs) + self.init_model_in_db() + self.chunks = self.chunk_documents() + self.update_chunks_in_db() + @abstractmethod - def chunk_document(self, document: BaseDocument, **kwargs) -> List[str]: + def chunk_text(self, text: str, **kwargs) -> List[str]: """ - Method to be implemented by subclasses to perform document chunking. + Chunk the input text into smaller pieces. + + Args: + text (str): The input text to be chunked. + **kwargs: Additional parameters for chunking. - :param document: The input document to be chunked. - :return: A list of text chunks. + Returns: + List[str]: A list of text chunks. """ - raise NotImplementedError("Subclasses must implement this method.") - + raise NotImplementedError("Subclasses must implement the chunk_text method.") + + def chunk_document(self, document: BaseDocument) -> Dict[int, Chunk]: + """ + Chunk a single document using the chunk_text method. + + Args: + document (BaseDocument): The input document to be chunked. + **kwargs: Additional parameters for chunking, passed to `chunk_text`. + + Returns: + Dict[int, Chunk]: A dictionary mapping chunk indices to Chunk objects. + """ + assert isinstance(document, BaseDocument), "Input must be an instance of BaseDocument." + text = document.get_text() + chunks_text = self.chunk_text(text) + chunks = {} + for idx, chunk_text in enumerate(chunks_text): + chunk = Chunk( + id=None, + document_position=idx, + document_id=document.id, + text=chunk_text, + ) + chunks[idx] = chunk + return chunks - def chunk_documents(self, documents: List[BaseDocument], **kwargs) -> Dict[int, List[str]]: + def chunk_documents(self) -> Dict[int, Dict[int, Chunk]]: """ - Chunk multiple documents using the chunk_document method. - :param documents: A list of input documents to be chunked. - :return: A dictionary mapping document IDs to lists of text chunks. + Chunk documents using the chunk_document method. + + Returns: + Dict[int, Dict[int, Chunk]]: A dictionary mapping document IDs to their respective + dictionaries of chunk indices and Chunk objects. """ chunked_documents = {} - for document in documents: - chunks = self.chunk_document(document, **kwargs) - chunked_documents[document.id] = chunks + for document_id, document in self.documents.items(): + chunks = self.chunk_document(document) + chunked_documents[document_id] = chunks return chunked_documents - \ No newline at end of file + + def fetch_model_from_db(self): + """ + Retrieve the chunking model from the database if it exists. + """ + existing_pipeline: PipelineDBModel = self.db.query( + PipelineDBModel).filter_by(id=self.pipeline_id).first() + if existing_pipeline: + chunking_model_id = existing_pipeline.chunking_model_id + chunking_model = self.db.query(DBChunkingModel).filter_by( + id=chunking_model_id).first() + else: + chunking_model = self.db.query(DBChunkingModel).filter_by( + class_name=self.class_name, + parameters=self.parameters + ).first() + if chunking_model: + self.id = chunking_model.id + return chunking_model + self.id = None + return None + + def create_model_in_db(self) -> DBChunkingModel: + """ + Store the chunking model in the database. + """ + new_model = DBChunkingModel( + class_name=self.class_name, + parameters=self.parameters, + ) + self.db.add(new_model) + self.db.commit() + self.db.refresh(new_model) + self.id = new_model.id + return new_model + + def update_model_in_db(self) -> DBChunkingModel: + """ + Update the chunking model in the database. + """ + model = self.db.query(DBChunkingModel).filter_by(id=self.id).first() + if model: + # The relationship is managed through the foreign key on RAGPipeline + # No need to manually manage the pipelines collection here + self.db.commit() + self.db.refresh(model) + return model + + def init_model_in_db(self): + if self.fetch_model_from_db(): + db_model = self.update_model_in_db() + else: + db_model = self.create_model_in_db() + return db_model + + def fetch_chunks_from_db(self) -> Dict[int, Dict[int, Chunk]]: + """ + Fetch all chunks associated with the chunking model from the database. + + Returns: + Dict[int, Dict[int, Chunk]]: A dictionary mapping document IDs to their respective + dictionaries of chunk indices and Chunk objects. + """ + chunks = {} + for document_id, _ in self.documents.items(): + chunks[document_id] = {} + stored_chunks = self.db.query(DBChunkModel).filter_by( + chunking_model_id=self.id, + document_id=document_id + ) + for chunk in stored_chunks: + chunks[document_id][chunk.chunk_index] = Chunk( + document_position=chunk.chunk_index, + document_id=chunk.document_id, + text=chunk.text, + ) + return chunks + + def create_chunks_in_db(self, document_chunks: Dict[int, Chunk]) -> None: + """ + Store the chunks of a document in the database. + + Args: + document_chunks (Dict[int, Chunk]): A dictionary mapping chunk indices to Chunk objects. + """ + for idx, chunk in document_chunks.items(): + db_chunk = DBChunkModel( + document_id=chunk.document_id, + chunk_index=chunk.document_position, + chunking_model_id=self.id, + text=chunk.text, + hash=hash_function(chunk.text) + ) + self.db.add(db_chunk) + self.db.commit() + self.chunks[chunk.document_id][idx].id = db_chunk.id + + + def update_chunks_in_db(self) -> None: + """ + Update the chunks in the database if they do not already exist. + """ + existing_chunks = self.fetch_chunks_from_db() + for document_id, chunks in self.chunks.items(): + if document_id not in existing_chunks: + self.create_chunks_in_db(chunks) + + def get_chunks(self) -> Dict[int, Dict[int, Chunk]]: + """ + Get the chunks generated by the chunking model. + + Returns: + Dict[int, Dict[int, Chunk]]: A dictionary mapping document IDs to their respective + dictionaries of chunk indices and Chunk objects. + """ + return self.chunks \ No newline at end of file diff --git a/DashAI/back/models/RAG/chunking_models/character_chunk_model.py b/DashAI/back/models/RAG/chunking_models/character_chunk_model.py index aba0c69fa..08de7791e 100644 --- a/DashAI/back/models/RAG/chunking_models/character_chunk_model.py +++ b/DashAI/back/models/RAG/chunking_models/character_chunk_model.py @@ -6,7 +6,8 @@ schema_field, ) from DashAI.back.models.RAG.chunking_models.base_chunking_model import BaseChunkingModel -from DashAI.back.models.RAG.documents.BaseDocument import BaseDocument +from DashAI.back.models.RAG.documents.base_document import BaseDocument +from DashAI.back.models.RAG.documents.chunk import Chunk class CharacterChunkModelSchema(BaseSchema): @@ -33,31 +34,39 @@ class CharacterChunkModel(BaseChunkingModel): SCHEMA = CharacterChunkModelSchema - def __init__(self, chunk_size: int = 200, chunk_overlap: int = 20): + def __init__(self, **kwargs): """ Initialize the character chunking model with the specified chunk size and overlap. - :param chunk_size: Size of each chunk in characters. - :param chunk_overlap: Number of characters to overlap between chunks. + Args: + chunk_size (int): Size of each chunk in characters. + chunk_overlap (int): Number of characters to overlap between chunks. """ - self.chunk_size = chunk_size - self.chunk_overlap = chunk_overlap + self.chunk_size = kwargs["chunk_size"] + self.chunk_overlap = kwargs["chunk_overlap"] + super().__init__(**kwargs) - def chunk_document(self, document: BaseDocument) -> List[str]: + def chunk_text(self, text: str) -> List[str]: """ - Split the document into chunks based on character count. + Chunk the input text into smaller segments based on character count. - :param document: The input document to be chunked. - :return: A list of text chunks. + Args: + text (str): The input text to be chunked. + + Returns: + List[str]: A list of text chunks. """ - text = document.get_text() chunks = [] start = 0 + text_length = len(text) - while start < len(text): - end = min(start + self.chunk_size, len(text)) - chunks.append(text[start:end]) + while start < text_length: + end = min(start + self.chunk_size, text_length) + chunk = text[start:end] + chunks.append(chunk) + if end == text_length: + break start += self.chunk_size - self.chunk_overlap - return chunks + return chunks \ No newline at end of file diff --git a/DashAI/back/models/RAG/chunking_models/token_chunk_model.py b/DashAI/back/models/RAG/chunking_models/token_chunk_model.py index 08f074db5..a6f58ea88 100644 --- a/DashAI/back/models/RAG/chunking_models/token_chunk_model.py +++ b/DashAI/back/models/RAG/chunking_models/token_chunk_model.py @@ -1,3 +1,4 @@ +from typing import List from transformers import AutoTokenizer from DashAI.back.core.schema_fields import ( @@ -7,7 +8,6 @@ schema_field, ) from DashAI.back.models.RAG.chunking_models.base_chunking_model import BaseChunkingModel -from DashAI.back.models.RAG.documents import BaseDocument class TokenChunkModelSchema(BaseSchema): @@ -39,18 +39,18 @@ class TokenChunkModel(BaseChunkingModel): SCHEMA = TokenChunkModelSchema def __init__(self, **kwargs): - kwargs = self.validate_and_transform(kwargs) + pipeline_id = self.params.pop("pipeline_id") + + self.db_model = self.init_model_in_db(pipeline_id) - self.chunk_size = kwargs.get("chunk_size", 200) - self.chunk_overlap = kwargs.get("chunk_overlap", 20) + self.params = self.validate_and_transform(kwargs) - self.tokenizer_name = kwargs.get( - "tokenizer_name", "intfloat/e5-mistral-7b-instruct" - ) + self.chunk_size = self.params["chunk_size"] + self.chunk_overlap = self.params["chunk_overlap"] + self.tokenizer_name = self.params["tokenizer_name"] self.tokenizer = AutoTokenizer.from_pretrained(self.tokenizer_name) - - def chunk(self, document: BaseDocument): - text = document.get_text() + + def chunk_text(self, text: str) -> List[List[str]]: tokens = self.tokenizer.tokenize(text) diff --git a/DashAI/back/models/RAG/Documents/BaseDocument.py b/DashAI/back/models/RAG/documents/base_document.py similarity index 92% rename from DashAI/back/models/RAG/Documents/BaseDocument.py rename to DashAI/back/models/RAG/documents/base_document.py index 3f8c3b4fc..29bbc38f1 100644 --- a/DashAI/back/models/RAG/Documents/BaseDocument.py +++ b/DashAI/back/models/RAG/documents/base_document.py @@ -7,6 +7,8 @@ class BaseDocument(ABC): Base class for documents. """ + SUPPORTED_FILE_TYPES = ['pdf', 'txt'] + def __init__( self, id: int, @@ -103,8 +105,8 @@ def get_file_type(self) -> Optional[str]: Returns: Optional[str]: The filetype of the document, or None if not applicable. """ - return self.file_path.split('.')[-1] + return self.file_path.split('.')[-1].lower() if self.file_path else None def __repr__(self): - return f"BaseDocument(filename='{self.get_file_name()}', content='{self.get_text()[:50]}...', metadata={self.get_metadata()})" + return f"BaseDocument(id={self.id}, filename='{self.get_file_name()}', content='{self.get_text()[:50]}...', metadata={self.get_metadata()})" diff --git a/DashAI/back/models/RAG/documents/chunk.py b/DashAI/back/models/RAG/documents/chunk.py new file mode 100644 index 000000000..47baaa262 --- /dev/null +++ b/DashAI/back/models/RAG/documents/chunk.py @@ -0,0 +1,20 @@ + +from typing import Any, Dict, List +from DashAI.back.models.RAG.utils import hash_function +import numpy as np + +class Chunk: + """A class representing a chunk of a document.""" + + def __init__( + self, + id: int, + document_id: str, + document_position: int, + text: str, + ): + self.id = id + self.document_id = document_id + self.document_position = document_position + self.text = text + self.hash = hash_function(text) diff --git a/DashAI/back/models/RAG/documents/chunk_embedding.py b/DashAI/back/models/RAG/documents/chunk_embedding.py new file mode 100644 index 000000000..f221dfbd5 --- /dev/null +++ b/DashAI/back/models/RAG/documents/chunk_embedding.py @@ -0,0 +1,17 @@ +from typing import Any, List +import numpy as np + +from DashAI.back.models.RAG.documents.base_document import BaseDocument +from DashAI.back.models.RAG.documents.chunk import Chunk + + +class ChunkEmbedding: + def __init__( + self, + document: BaseDocument, + chunk: Chunk, + embedding: List[float]|np.ndarray|Any, + ): + self.document = document + self.chunk = chunk + self.embedding = embedding \ No newline at end of file diff --git a/DashAI/back/models/RAG/Documents/PDFDocument.py b/DashAI/back/models/RAG/documents/pdf_document.py similarity index 89% rename from DashAI/back/models/RAG/Documents/PDFDocument.py rename to DashAI/back/models/RAG/documents/pdf_document.py index 48dba5258..27476b195 100644 --- a/DashAI/back/models/RAG/Documents/PDFDocument.py +++ b/DashAI/back/models/RAG/documents/pdf_document.py @@ -1,7 +1,7 @@ -from .BaseDocument import BaseDocument -import os +from DashAI.back.models.RAG.documents.base_document import BaseDocument from PyPDF2 import PdfReader from typing import Optional, Dict, Any +from DashAI.back.models.RAG.utils import hash_function class PDFDocument(BaseDocument): """ @@ -13,7 +13,6 @@ def __init__( id: int, file_name: str, file_path: str, - file_hash: str, created: Optional[str] = None, optional_metadata: Optional[Dict[str, Any]] = None ): @@ -23,10 +22,10 @@ def __init__( id (int): The unique identifier of the document. file_name (str): The name of the file. file_path (str): The path to the file. - file_hash (str): A hash of the file content. created (Optional[str]): The creation date of the document. optional_metadata (Optional[Dict[str, Any]]): Additional metadata for the document. """ + file_hash = hash_function(file_path) super().__init__( id=id, file_name=file_name, diff --git a/DashAI/back/models/RAG/Documents/TxtDocument.py b/DashAI/back/models/RAG/documents/txt_document.py similarity index 90% rename from DashAI/back/models/RAG/Documents/TxtDocument.py rename to DashAI/back/models/RAG/documents/txt_document.py index fb5507d94..c2b4d0787 100644 --- a/DashAI/back/models/RAG/Documents/TxtDocument.py +++ b/DashAI/back/models/RAG/documents/txt_document.py @@ -1,6 +1,6 @@ -from .BaseDocument import BaseDocument +from DashAI.back.models.RAG.documents.base_document import BaseDocument +from DashAI.back.models.RAG.utils import hash_function from typing import Dict, Any, Optional -import os class TxtDocument(BaseDocument): """ @@ -12,7 +12,6 @@ def __init__( id: int, file_name: str, file_path: str, - file_hash: str, created: Optional[str] = None, optional_metadata: Optional[Dict[str, Any]] = None ): @@ -26,6 +25,7 @@ def __init__( created (Optional[str]): The creation date of the document. optional_metadata (Optional[Dict[str, Any]]): Additional metadata for the document. """ + file_hash = hash_function(file_path) super().__init__( id=id, file_name=file_name, diff --git a/DashAI/back/models/RAG/embeddings/dense/fasttext_embedding.py b/DashAI/back/models/RAG/embeddings/dense/fasttext_embedding.py index b62baae9c..e2eaec4f7 100644 --- a/DashAI/back/models/RAG/embeddings/dense/fasttext_embedding.py +++ b/DashAI/back/models/RAG/embeddings/dense/fasttext_embedding.py @@ -40,16 +40,17 @@ class FastTextEmbedding(DenseEmbedding): DESCRIPTION = "Convert text to embeddings using FastText." def __init__(self, **kwargs): - self.validate_and_transform(**kwargs) - self.model_name = kwargs.get("model_name") - self.pooling_strategy = kwargs.get("pooling_strategy") + self.params = self.validate_and_transform(kwargs) + self.model_name = self.params["model_name"] + self.pooling_strategy = self.params["pooling_strategy"] pooling_functions = { "mean": np.mean, "max": np.max } self.pooling_function = pooling_functions[self.pooling_strategy] + self.load() - def _load_model(self): + def load(self): """Load the FastText model.""" model_name = self.model_name.split("/")[-1] model_path = hf_hub_download(repo_id=self.model_name, filename=f"{model_name}.bin") @@ -59,4 +60,12 @@ def encode(self, text: str) -> np.ndarray: """Encode text into an embedding.""" token_embeddings = [self.model.get_word_vector(word) for word in text.split()] return self.pooling_function(np.array(token_embeddings), axis=0) + + def batch_encode(self, texts: List[str]) -> np.ndarray: + """Encode a batch of texts into embeddings.""" + all_embeddings = [] + for text in texts: + embedding = self.encode(text) + all_embeddings.append(embedding) + return np.array(all_embeddings) \ No newline at end of file diff --git a/DashAI/back/models/RAG/embeddings/dense/huggingface_embedding.py b/DashAI/back/models/RAG/embeddings/dense/huggingface_embedding.py index 5b62e4e9e..7bc764303 100644 --- a/DashAI/back/models/RAG/embeddings/dense/huggingface_embedding.py +++ b/DashAI/back/models/RAG/embeddings/dense/huggingface_embedding.py @@ -1,6 +1,3 @@ -from transformers import AutoModel - - from DashAI.back.core.schema_fields import ( BaseSchema, schema_field, @@ -72,24 +69,26 @@ class HuggingFaceEmbedding(DenseEmbedding): DESCRIPTION = "Convert text to embeddings using HuggingFace transformer models." def __init__(self, **kwargs): - super().__init__(**kwargs) - self.pooling_strategy = kwargs.get("pooling_strategy", "mean") - self.model_name = kwargs.get( - "model_name", "sentence-transformers/all-MiniLM-L6-v2" - ) - self.device = kwargs.get("device", "cpu") - self.max_length = kwargs.get("max_length", 512) - self.batch_size = kwargs.get("batch_size", 32) + self.params = self.validate_and_transform(kwargs) + self.pooling_strategy = self.params["pooling_strategy"] + self.model_name = self.params["model_name"] + self.device = self.params["device"] + self.max_length = self.params["max_length"] + self.batch_size = self.params["batch_size"] self.model = None self.tokenizer = None + self.load() + + def save(self): + pass - def _load_model(self): + def load(self): """Load the embedding model and tokenizer.""" self.tokenizer = AutoTokenizer.from_pretrained(self.model_name) self.model = AutoModel.from_pretrained(self.model_name).to(self.device) - self.model.eval() + self.embedding_dim = self.model.config.hidden_size - def _encode_texts(self, texts:List[str])-> List[np.ndarray]: + def batch_encode(self, texts:List[str])-> List[np.ndarray]: """Encode a list of texts into embeddings.""" # Tokenize encoded = self.tokenizer( @@ -121,5 +120,5 @@ def _encode_texts(self, texts:List[str])-> List[np.ndarray]: def encode(self, text: str) -> np.ndarray: """Encode a single text into an embedding.""" - embeddings = self._encode_texts([text]) - return embeddings[0] if embeddings else np.array([]) + embeddings = self.batch_encode([text]) + return embeddings.squeeze() diff --git a/DashAI/back/models/RAG/embeddings/dense_embedding.py b/DashAI/back/models/RAG/embeddings/dense_embedding.py index 64a4e1966..cd4311b5b 100644 --- a/DashAI/back/models/RAG/embeddings/dense_embedding.py +++ b/DashAI/back/models/RAG/embeddings/dense_embedding.py @@ -3,7 +3,7 @@ from typing import Any, List import numpy as np -from DashAI.back.models.RAG.documents.BaseDocument import BaseDocument +from DashAI.back.models.RAG.documents.base_document import BaseDocument from DashAI.back.models.base_model import BaseModel class DenseEmbedding(BaseModel): @@ -11,8 +11,8 @@ class DenseEmbedding(BaseModel): Base class for all encoding (embedding) models. This class should be inherited by any specific encoding (embedding) model implementation. """ - EMBEDDINGS_PATH = "RAG/embeddings" + embedding_dim: int def __init__( self, **kwargs: Any): @@ -29,4 +29,14 @@ def encode(self, text: str) -> List[float]|np.ndarray|Any: :param text: The input text to encode (embed). :return: A list representing the encodings (embeddings) of the input text. """ + raise NotImplementedError("Subclasses must implement this method.") + + def batch_encode(self, texts: List[str]) -> List[List[float]]|np.ndarray|Any: + """ + Method to generate encodings (embeddings) for a batch of texts. + This method should be implemented by subclasses. + + :param texts: A list of input texts to encode (embed). + :return: A list of lists representing the encodings (embeddings) of the input texts. + """ raise NotImplementedError("Subclasses must implement this method.") \ No newline at end of file diff --git a/DashAI/back/models/RAG/embeddings/trainable_encoding.py b/DashAI/back/models/RAG/embeddings/trainable_encoding.py index d210578b3..22934926c 100644 --- a/DashAI/back/models/RAG/embeddings/trainable_encoding.py +++ b/DashAI/back/models/RAG/embeddings/trainable_encoding.py @@ -3,7 +3,7 @@ from typing import Any, List import numpy as np -from DashAI.back.models.RAG.documents.BaseDocument import BaseDocument +from DashAI.back.models.RAG.documents.base_document import BaseDocument from DashAI.back.models.RAG.embeddings.dense_embedding import DenseEmbedding class TrainableEncoding(DenseEmbedding): diff --git a/DashAI/back/models/RAG/exceptions.py b/DashAI/back/models/RAG/exceptions.py new file mode 100644 index 000000000..e69de29bb diff --git a/DashAI/back/models/RAG/prompts/augmentation/custom_augmentation_prompt.py b/DashAI/back/models/RAG/prompts/augmentation/custom_augmentation_prompt.py index dcb82d36a..2a4888130 100644 --- a/DashAI/back/models/RAG/prompts/augmentation/custom_augmentation_prompt.py +++ b/DashAI/back/models/RAG/prompts/augmentation/custom_augmentation_prompt.py @@ -22,10 +22,8 @@ class CustomAugmentationPrompt(AugmentationPrompt): } - def __init__(self, template: str): - if not self.validate_template(template): - raise ValueError("The template is missing required placeholders.") - self.template = template + def __init__(self, **kwargs): + super().__init__(**kwargs) def format( diff --git a/DashAI/back/models/RAG/prompts/context_merge/__init__.py b/DashAI/back/models/RAG/prompts/context_merge/__init__.py deleted file mode 100644 index 89cef9e0f..000000000 --- a/DashAI/back/models/RAG/prompts/context_merge/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from DashAI.back.models.RAG.prompts.context_merge.context_merge_prompt import ContextMergePrompt -from DashAI.back.models.RAG.prompts.context_merge.default_context_merge_prompt import DefaultContextMergePrompt -from DashAI.back.models.RAG.prompts.context_merge.custom_context_merge_prompt import CustomContextMergePrompt \ No newline at end of file diff --git a/DashAI/back/models/RAG/prompts/context_merge/context_merge_prompt.py b/DashAI/back/models/RAG/prompts/context_merge/context_merge_prompt.py deleted file mode 100644 index fc1f089ff..000000000 --- a/DashAI/back/models/RAG/prompts/context_merge/context_merge_prompt.py +++ /dev/null @@ -1,18 +0,0 @@ -from typing import Any, List, Tuple -from DashAI.back.models.RAG.prompts.prompt import Prompt - -class ContextMergePrompt(Prompt): - """ - ContextMergePrompt class for generating prompts that merge the use input, the retrieved - documents and the chat history into a single context for the language model. - """ - required_placeholders = ["{input}", "{history}", "{chunks}"] - - @staticmethod - def format( - input: str, - history: List[Tuple[str, str]], - chunks: List[str], - **kwargs: Any - ) -> str: - raise NotImplementedError("Subclasses must implement this method.") \ No newline at end of file diff --git a/DashAI/back/models/RAG/prompts/context_merge/custom_context_merge_prompt.py b/DashAI/back/models/RAG/prompts/context_merge/custom_context_merge_prompt.py deleted file mode 100644 index 28b8403db..000000000 --- a/DashAI/back/models/RAG/prompts/context_merge/custom_context_merge_prompt.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import Any, List, Tuple -from DashAI.back.models.RAG.prompts.context_merge.context_merge_prompt import ContextMergePrompt - -class CustomContextMergePrompt(ContextMergePrompt): - """ - ContextMergePrompt class for generating prompts that merge the use input, the retrieved - documents and the chat history into a single context for the language model. - """ - required_placeholders = ["{input}", "{documents}", "{history}"] - - - def __init__(self, template: str): - if not self.validate_template(template): - raise ValueError("The template is missing required placeholders.") - self.template = template - - def format( - self, - input: str, - history: List[Tuple[str, str]], - chunks: List[str], - **kwargs: Any - ) -> str: - """ - Format the prompt using the provided template. - - Args: - input (str): The user input message. - history (List[Tuple[str, str]]): The chat history to be included in the context. - chunks (List[str]): The document chunks to be included in the context. - **kwargs: Additional keyword arguments for formatting. - - Returns: - str: The formatted prompt. - """ - buffer = self.template - if history: - buffer = buffer.replace("{history}", "\n".join( - [f"User message: {h_input}\n Response: {h_output}" for h_input, h_output in history] - )) - buffer = buffer.replace("{input}", input) - buffer = buffer.replace("{documents}", "\n".join(chunks)) - return buffer diff --git a/DashAI/back/models/RAG/prompts/generation/custom_generation_prompt.py b/DashAI/back/models/RAG/prompts/generation/custom_generation_prompt.py index e9f1a83e4..28fe2305d 100644 --- a/DashAI/back/models/RAG/prompts/generation/custom_generation_prompt.py +++ b/DashAI/back/models/RAG/prompts/generation/custom_generation_prompt.py @@ -15,16 +15,14 @@ class CustomGenerationPrompt(GenerationPrompt): "placeholder_descriptions": { "{input}": "The user input message.", "{history}": "The chat history (optional) to be included in the context.", - "{documents}": "The document chunks to be included in the context." + "{chunks}": "The document chunks to be included in the context." } } - def __init__(self, template: str): - if not self.validate_template(template): - raise ValueError("The template is missing required placeholders.") - self.template = template - + def __init__(self, **kwargs: Any): + super().__init__(**kwargs) + def format( self, input: str, diff --git a/DashAI/back/models/RAG/prompts/generation/default_QnA_generation_prompt.py b/DashAI/back/models/RAG/prompts/generation/default_QnA_generation_prompt.py index 2743173d1..d6735b137 100644 --- a/DashAI/back/models/RAG/prompts/generation/default_QnA_generation_prompt.py +++ b/DashAI/back/models/RAG/prompts/generation/default_QnA_generation_prompt.py @@ -34,6 +34,10 @@ class DefaultQnAGenerationPrompt(GenerationPrompt): "template": template } + def __init__(self, **kwargs): + super().__init__(**kwargs) + + @staticmethod def format( input: str, diff --git a/DashAI/back/models/RAG/prompts/generation/default_generation_prompt.py b/DashAI/back/models/RAG/prompts/generation/default_generation_prompt.py index f27cf999f..1a370dd72 100644 --- a/DashAI/back/models/RAG/prompts/generation/default_generation_prompt.py +++ b/DashAI/back/models/RAG/prompts/generation/default_generation_prompt.py @@ -37,12 +37,14 @@ class DefaultGenerationPrompt(GenerationPrompt): "template": template } + def __init__(self, **kwargs): + super().__init__(**kwargs) @staticmethod def format( input: str, history:List[Tuple[str, str]], - chunks: List[str], + chunks: str, **kwargs: Any ) -> str: """ @@ -61,5 +63,5 @@ def format( [f"User message: {h_input}\nResponse: {h_output}" for h_input, h_output in history] )) buffer = buffer.replace("{input}", input) - buffer = buffer.replace("{chunks}", "\n".join(chunks)) + buffer = buffer.replace("{chunks}", chunks) return buffer \ No newline at end of file diff --git a/DashAI/back/models/RAG/prompts/generation/generation_prompt.py b/DashAI/back/models/RAG/prompts/generation/generation_prompt.py index 23a35ebec..6df413f9b 100644 --- a/DashAI/back/models/RAG/prompts/generation/generation_prompt.py +++ b/DashAI/back/models/RAG/prompts/generation/generation_prompt.py @@ -1,5 +1,8 @@ from typing import Any, List, Tuple from DashAI.back.models.RAG.prompts.prompt import Prompt +from DashAI.back.dependencies.database.models import ( + RAGPrompt as PromptDBModel, +) class GenerationPrompt(Prompt): """ @@ -7,6 +10,7 @@ class GenerationPrompt(Prompt): """ required_placeholders = ["{input}", "{chunks}"] optional_placeholders = ["{history}"] + @staticmethod def format( diff --git a/DashAI/back/models/RAG/prompts/prompt.py b/DashAI/back/models/RAG/prompts/prompt.py index d3e278049..2c8aa4e6f 100644 --- a/DashAI/back/models/RAG/prompts/prompt.py +++ b/DashAI/back/models/RAG/prompts/prompt.py @@ -2,13 +2,15 @@ from DashAI.back.models.base_model import BaseModel from DashAI.back.core.schema_fields import BaseSchema, schema_field, string_field +from DashAI.back.dependencies.database.models import ( + RAGPrompt as PromptDBModel) class PromptSchema(BaseSchema): template: str = schema_field( string_field(), - "", - "The prompt template with placeholders.", + placeholder="", + description="The prompt template with placeholders.", ) @@ -19,11 +21,38 @@ class Prompt(BaseModel): """ SCHEMA = PromptSchema + REQUIRED_EXTRA_KWARGS = ["db"] + id: int - def __load__(self, **kwargs: Any) -> None: + def __init__(self, **kwargs): + self.db = kwargs.pop("db") + kwargs = self.validate_and_transform(kwargs) + self.template = kwargs.get("template") + assert self.validate_template(self.template), "The template is missing required placeholders." + self.class_name = self.__class__.__name__ + self.params = kwargs + + stored_model = self.db.query(PromptDBModel).filter_by( + class_name = self.class_name, + parameters = self.params + ).first() + if stored_model: + self.id = stored_model.id + else: + new_model = PromptDBModel( + class_name=self.class_name, + parameters=self.params + ) + self.db.add(new_model) + self.db.commit() + self.id = new_model.id + + + + def load(self, **kwargs: Any) -> None: pass - def __save__(self) -> None: + def save(self) -> None: pass @classmethod diff --git a/DashAI/back/models/RAG/utils.py b/DashAI/back/models/RAG/utils.py index e69de29bb..57d6901e5 100644 --- a/DashAI/back/models/RAG/utils.py +++ b/DashAI/back/models/RAG/utils.py @@ -0,0 +1,14 @@ +import hashlib + + +def hash_function(content) -> str: + """ + Generate a SHA-256 hash for the given content bytes. + + Args: + content (bytes): The content to hash. + """ + if isinstance(content, str): + content = content.encode("utf-8") + return hashlib.sha256(content).hexdigest() + diff --git a/DashAI/back/models/text_to_text_generation_model.py b/DashAI/back/models/text_to_text_generation_model.py index 782fdcb9e..4c4549c4a 100644 --- a/DashAI/back/models/text_to_text_generation_model.py +++ b/DashAI/back/models/text_to_text_generation_model.py @@ -5,3 +5,5 @@ class TextToTextGenerationTaskModel(BaseGenerativeModel): """Class for models associated to TextToTextGenerationTask.""" COMPATIBLE_COMPONENTS = ["TextToTextGenerationTask", "RAGTask"] + + REQUIRED_EXTRA_KWARGS = [] diff --git a/DashAI/front/src/api/job.ts b/DashAI/front/src/api/job.ts index 5393c7678..53c95983d 100644 --- a/DashAI/front/src/api/job.ts +++ b/DashAI/front/src/api/job.ts @@ -132,6 +132,24 @@ export const enqueueGenerativeProcessJob = async ( return response.data; }; +export const enqueueRAGProcessJob = async ( + processId: number, +): Promise => { + const data = { + job_type: "RAGJob", + kwargs: { rag_process_id: processId }, + }; + const formData = new FormData(); + formData.append("job_type", data.job_type); + formData.append("kwargs", JSON.stringify(data.kwargs)); + const response = await api.post("/v1/job/", formData, { + headers: { + "Content-Type": "multipart/form-data", + }, + }); + return response.data; +} + export const enqueueConverterJob = async ( converterListId: number, ): Promise => { diff --git a/Untitled-1.ipynb b/Untitled-1.ipynb deleted file mode 100644 index d77315c44..000000000 --- a/Untitled-1.ipynb +++ /dev/null @@ -1,796 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "145faa29", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "c:\\Users\\fcb11\\Documents\\GitHub\\DashAI\\.venv\\Lib\\site-packages\\tqdm\\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", - " from .autonotebook import tqdm as notebook_tqdm\n", - "c:\\Users\\fcb11\\Documents\\GitHub\\DashAI\\.venv\\Lib\\site-packages\\pydantic\\_internal\\_config.py:345: UserWarning: Valid config keys have changed in V2:\n", - "* 'orm_mode' has been renamed to 'from_attributes'\n", - " warnings.warn(message, UserWarning)\n" - ] - }, - { - "data": { - "text/plain": [ - "['#1#yukari is one of the most underrated Vocaloid voicebanks and characters\\n',\n", - " '#2#Yuzuki Yukari is the president of Independent Republic of Saint Joaquin\\n',\n", - " '#3#Yuzuki Yukari is well known by her participation in the Nuremberg trials\\n',\n", - " '#4#Yuzuki Yukari is responsible for the creation of Linux kernel, even if she is not recognized by that\\n',\n", - " '#5#Papi Micky is the Major of San Carlos\\n',\n", - " '#6#Papi Micky had an affair with Tio Rene Puente, but he did not recognize him as a lover, because he was engaged with Contralorito']" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from sklearn.feature_extraction.text import TfidfVectorizer\n", - "from typing import Dict, List\n", - "import hashlib\n", - "from DashAI.back.models.RAG.embeddings.tf_idf_embedding import TFIDFEmbedding\n", - "\n", - "\n", - "hasher = lambda x: hashlib.sha256(x.encode('utf-8')).hexdigest()\n", - "\n", - "\n", - "dummy_texts = []\n", - "\n", - "with open('dummy_texts.txt', 'r') as file:\n", - " dummy_texts = file.readlines()\n", - " \n", - "dummy_texts" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "59febbcb", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "75 #1#yukari is one of the most underrated Vocaloid voicebanks and characters\n", - "\n", - "75 #2#Yuzuki Yukari is the president of Independent Republic of Saint Joaquin\n", - "\n", - "76 #3#Yuzuki Yukari is well known by her participation in the Nuremberg trials\n", - "\n", - "104 #4#Yuzuki Yukari is responsible for the creation of Linux kernel, even if she is not recognized by that\n", - "\n", - "41 #5#Papi Micky is the Major of San Carlos\n", - "\n", - "131 #6#Papi Micky had an affair with Tio Rene Puente, but he did not recognize him as a lover, because he was engaged with Contralorito\n" - ] - } - ], - "source": [ - "for t in dummy_texts:\n", - " print(len(t), t)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "dd6c7ea9", - "metadata": {}, - "outputs": [], - "source": [ - "def generate_chunks(texts, size, overlap)-> Dict[int, List[str]]:\n", - " \"\"\"\n", - " Generate chunks of text from the provided texts.\n", - " Args:\n", - " texts (List[str]): List of text documents to chunk.\n", - " size (int): Size of each chunk.\n", - " overlap (int): Overlap size between chunks.\n", - " Returns:\n", - " Dict[int, List[str]]: Dictionary with document index as key and list of chunks as value.\n", - " \"\"\"\n", - " \n", - " documents_chunks = {}\n", - "\n", - " for i, text in enumerate(texts):\n", - " chunks = []\n", - " for j in range(0, len(text), size - overlap):\n", - " if j + size > len(text):\n", - " chunk = text[j:]\n", - " else:\n", - " chunk = text[j:j + size]\n", - " chunks.append(chunk)\n", - " documents_chunks[i] = chunks\n", - " return documents_chunks" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "30e25e89", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{0: ['#1#yukari is one of the most underrated Vocaloid voicebanks and characters\\n'],\n", - " 1: ['#2#Yuzuki Yukari is the president of Independent Republic of Saint Joaquin\\n'],\n", - " 2: ['#3#Yuzuki Yukari is well known by her participation in the Nuremberg trials\\n'],\n", - " 3: ['#4#Yuzuki Yukari is responsible for the creation of Linux kernel, even if she is not recognized by that\\n'],\n", - " 4: ['#5#Papi Micky is the Major of San Carlos\\n'],\n", - " 5: ['#6#Papi Micky had an affair with Tio Rene Puente, but he did not recognize him as a lover, because he was engaged with Contralorito']}" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "document_chunks = generate_chunks(dummy_texts, 200, 20)\n", - "document_chunks" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "a18c4a56", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{0: ['#1#yukari is one of the most underrated Vocaloid voicebanks and characters\\n'],\n", - " 1: ['#2#Yuzuki Yukari is the president of Independent Republic of Saint Joaquin\\n'],\n", - " 2: ['#3#Yuzuki Yukari is well known by her participation in the Nuremberg trials\\n'],\n", - " 3: ['#4#Yuzuki Yukari is responsible for the creation of Linux kernel, even if she is not recognized by that\\n'],\n", - " 4: ['#5#Papi Micky is the Major of San Carlos\\n'],\n", - " 5: ['#6#Papi Micky had an affair with Tio Rene Puente, but he did not recognize him as a lover, because he was engaged with Contralorito']}" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "document_chunks = generate_chunks(dummy_texts, 200, 0)\n", - "document_chunks" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "a9f0d850", - "metadata": {}, - "outputs": [], - "source": [ - "if False: # Set to True to run the test\n", - " for chunk_size in [40, 80, 1000, 2000]:\n", - " for chunk_overlap in [0, 20, 30]:\n", - " document_chunks = generate_chunks(dummy_texts, chunk_size, chunk_overlap)\n", - " tfidf_embedding = TFIDFEmbedding(\n", - " documents_chunks=document_chunks,\n", - " strip_accents='unicode',\n", - " lowercase=True,\n", - " analyzer='word',\n", - " ngram_range=(1, 2),\n", - " max_features=1000,\n", - " norm='l2',\n", - " use_idf=True,\n", - " smooth_idf=True,\n", - " sublinear_tf=False,\n", - " stop_words=None,\n", - " max_df=1.0,\n", - " min_df=1,\n", - " )\n", - " \n", - " print(f\"Chunk Size: {chunk_size}, Chunk Overlap: {chunk_overlap}\")\n", - " print(f\"Embeddings Hash: {tfidf_embedding._calculate_embeddings_hash()}\\n\")\n", - " del tfidf_embedding # Clean up to free memory\n", - " del document_chunks # Clean up to free memory" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "2130e475", - "metadata": {}, - "outputs": [], - "source": [ - "if False: # Set to True to run the test\n", - " for chunk_size in [200, 200, 200]:\n", - " for chunk_overlap in [0, 0, 50, 50]:\n", - " document_chunks = generate_chunks(dummy_texts, chunk_size, chunk_overlap)\n", - " tfidf_embedding = TFIDFEmbedding(\n", - " documents_chunks=document_chunks,\n", - " strip_accents='unicode',\n", - " lowercase=True,\n", - " analyzer='word',\n", - " ngram_range=(1, 2),\n", - " max_features=1000,\n", - " norm='l2',\n", - " use_idf=True,\n", - " smooth_idf=True,\n", - " sublinear_tf=False,\n", - " stop_words=None,\n", - " max_df=1.0,\n", - " min_df=1,\n", - " Store_model=False # Set to False to avoid saving the model during testing\n", - " )\n", - " \n", - " print(f\"Chunk Size: {chunk_size}, Chunk Overlap: {chunk_overlap}\")\n", - " print(f\"Embeddings Hash: {tfidf_embedding._calculate_embeddings_hash()}\\n\")\n", - " del tfidf_embedding # Clean up to free memory\n", - " del document_chunks # Clean up to free memory" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "625a05ec", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{0: ['#1#yukari is one of the most underrated Vocaloid voicebanks and characters\\n'],\n", - " 1: ['#2#Yuzuki Yukari is the president of Independent Republic of Saint Joaquin\\n'],\n", - " 2: ['#3#Yuzuki Yukari is well known by her participation in the Nuremberg trials\\n'],\n", - " 3: ['#4#Yuzuki Yukari is responsible for the creation of Linux kernel, even if she is not recognized by that\\n'],\n", - " 4: ['#5#Papi Micky is the Major of San Carlos\\n'],\n", - " 5: ['#6#Papi Micky had an affair with Tio Rene Puente, but he did not recognize him as a lover, because he was engaged with Contralorito']}" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "chunks_size_200_overlap_0 = generate_chunks(dummy_texts, 200, 0)\n", - "chunks_size_200_overlap_0" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "dbc4609e", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{0: ['#1#yukari is one of the most underrated Vocaloid voicebanks and characters\\n'],\n", - " 1: ['#2#Yuzuki Yukari is the president of Independent Republic of Saint Joaquin\\n'],\n", - " 2: ['#3#Yuzuki Yukari is well known by her participation in the Nuremberg trials\\n'],\n", - " 3: ['#4#Yuzuki Yukari is responsible for the creation of Linux kernel, even if she is not recognized by that\\n'],\n", - " 4: ['#5#Papi Micky is the Major of San Carlos\\n'],\n", - " 5: ['#6#Papi Micky had an affair with Tio Rene Puente, but he did not recognize him as a lover, because he was engaged with Contralorito']}" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "chunks_size_2000_overlap_0 = generate_chunks(dummy_texts, 2000, 0)\n", - "chunks_size_2000_overlap_0" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "b386ba62", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "TF-IDF model loaded successfully: False\n", - "Fitting the TF-IDF model...\n", - "Saving the TF-IDF model...\n", - "TF-IDF model fitted and saved.\n" - ] - } - ], - "source": [ - "embedding_chunk_size_200_overlap_0 = TFIDFEmbedding(\n", - " documents_chunks=chunks_size_200_overlap_0,\n", - " strip_accents='unicode',\n", - " lowercase=True,\n", - " analyzer='word',\n", - " ngram_range=(1, 2),\n", - " max_features=None,\n", - " norm='l2',\n", - " use_idf=True,\n", - " smooth_idf=True,\n", - " sublinear_tf=False,\n", - " stop_words=None,\n", - " max_df=1.0,\n", - " min_df=1,\n", - " store_model=True # Set to False to avoid saving the model during testing\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "df20a4dd", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "<6x129 sparse matrix of type ''\n", - "\twith 156 stored elements in Compressed Sparse Row format>" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "embedding_chunk_size_200_overlap_0._term_matrix" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "3887a18a", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array(['affair', 'affair with', 'an', 'an affair', 'and',\n", - " 'and characters', 'as', 'as lover', 'because', 'because he', 'but',\n", - " 'but he', 'by', 'by her', 'by that', 'carlos', 'characters',\n", - " 'contralorito', 'creation', 'creation of', 'did', 'did not',\n", - " 'engaged', 'engaged with', 'even', 'even if', 'for', 'for the',\n", - " 'had', 'had an', 'he', 'he did', 'he was', 'her',\n", - " 'her participation', 'him', 'him as', 'if', 'if she', 'in',\n", - " 'in the', 'independent', 'independent republic', 'is', 'is not',\n", - " 'is one', 'is responsible', 'is the', 'is well', 'joaquin',\n", - " 'kernel', 'kernel even', 'known', 'known by', 'linux',\n", - " 'linux kernel', 'lover', 'lover because', 'major', 'major of',\n", - " 'micky', 'micky had', 'micky is', 'most', 'most underrated', 'not',\n", - " 'not recognize', 'not recognized', 'nuremberg', 'nuremberg trials',\n", - " 'of', 'of independent', 'of linux', 'of saint', 'of san', 'of the',\n", - " 'one', 'one of', 'papi', 'papi micky', 'participation',\n", - " 'participation in', 'president', 'president of', 'puente',\n", - " 'puente but', 'recognize', 'recognize him', 'recognized',\n", - " 'recognized by', 'rene', 'rene puente', 'republic', 'republic of',\n", - " 'responsible', 'responsible for', 'saint', 'saint joaquin', 'san',\n", - " 'san carlos', 'she', 'she is', 'that', 'the', 'the creation',\n", - " 'the major', 'the most', 'the nuremberg', 'the president', 'tio',\n", - " 'tio rene', 'trials', 'underrated', 'underrated vocaloid',\n", - " 'vocaloid', 'vocaloid voicebanks', 'voicebanks', 'voicebanks and',\n", - " 'was', 'was engaged', 'well', 'well known', 'with',\n", - " 'with contralorito', 'with tio', 'yukari', 'yukari is', 'yuzuki',\n", - " 'yuzuki yukari'], dtype=object)" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "embedding_chunk_size_200_overlap_0._feature_names" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "3ed862f2", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "<6x129 sparse matrix of type ''\n", - "\twith 156 stored elements in Compressed Sparse Row format>" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "embedding_chunk_size_200_overlap_0._term_matrix" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "46446c8a", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", - " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", - " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", - " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", - " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", - " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", - " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", - " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", - " 0.]])" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "embedding_chunk_size_200_overlap_0.embed(\"affair\")" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "3592c77e", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[0.65787347, 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0.39028945, 0. , 0.45545397, 0.45545397]])" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "embedding_chunk_size_200_overlap_0.embed(\"affair yuzuki yukari\")" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "1c652c26", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", - " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", - " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", - " 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", - " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", - " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", - " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", - " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", - " 0.]])" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "embedding_chunk_size_200_overlap_0.embed(\"fnosn 090 aojfnsk linux\")" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "b1b8cf59", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "TF-IDF model loaded successfully: True\n" - ] - } - ], - "source": [ - "embedding_chunk_size_2000_overlap_0 = TFIDFEmbedding(\n", - " documents_chunks=chunks_size_2000_overlap_0,\n", - " strip_accents='unicode',\n", - " lowercase=True,\n", - " analyzer='word',\n", - " ngram_range=(1, 2),\n", - " max_features=None,\n", - " norm='l2',\n", - " use_idf=True,\n", - " smooth_idf=True,\n", - " sublinear_tf=False,\n", - " stop_words=None,\n", - " max_df=1.0,\n", - " min_df=1,\n", - " store_model=True # Set to False to avoid saving the model during testing\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "67f65c72", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[0.6234157 , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0.31939253, 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0.36984707, 0. , 0.43159844, 0.43159844]])" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "e1=embedding_chunk_size_200_overlap_0.embed(\"this is a yuzuki yukari affair\")\n", - "e1" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "id": "ba0999cb", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[0.6234157 , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0.31939253, 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0.36984707, 0. , 0.43159844, 0.43159844]])" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "e2 = embedding_chunk_size_2000_overlap_0.embed(\"this is a yuzuki yukari affair\")\n", - "e2" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "id": "74ec8dc4", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "(e1==e2).all() # Check if all elements are equal" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "id": "d6069a5e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "TF-IDF model loaded successfully: False\n", - "Fitting the TF-IDF model...\n", - "Saving the TF-IDF model...\n", - "TF-IDF model fitted and saved.\n" - ] - } - ], - "source": [ - "chunks_size_200_overlap_50 = generate_chunks(dummy_texts, 200, 50)\n", - "embedding_chunk_size_200_overlap_50 = TFIDFEmbedding(\n", - " documents_chunks=chunks_size_200_overlap_50,\n", - " strip_accents='unicode',\n", - " lowercase=True,\n", - " analyzer='word',\n", - " ngram_range=(1, 2),\n", - " max_features=1000,\n", - " norm='l2',\n", - " use_idf=True,\n", - " smooth_idf=True,\n", - " sublinear_tf=False,\n", - " stop_words=None,\n", - " max_df=1.0,\n", - " min_df=1,\n", - " store_model=True # Set to False to avoid saving the model during testing\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "19720b5a", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[0.6234157 , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0.31939253, 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0. , 0. , 0. , 0. , 0. ,\n", - " 0.36984707, 0. , 0.43159844, 0.43159844]])" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "e3 = embedding_chunk_size_200_overlap_50.embed(\"this is a yuzuki yukari affair\")\n", - "e3" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "id": "f2d061d6", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "(e1 == e3).all() # Check if all elements are equal\n", - "(e2 == e3).all() # Check if all elements are equal" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": ".venv", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.0" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notas.md b/notas.md new file mode 100644 index 000000000..ea9218d98 --- /dev/null +++ b/notas.md @@ -0,0 +1,2 @@ +* Por simplicidad, se asume que un documento almacenado en la base de datos no cambiará su contenido en el tiempo. Si se quiere dar soporte al tracking de versiones, una alternativa es que el frontend siempre envíe el archivo o un hash su contenido al backend, y que este verifique si ha cambiado. Si lo ha hecho, debería duplicar el RAGPipeline asociado, junto con sus subcomponentes, e inicializarlo con el nuevo contenido. +Desventaja asociada: el usuario debería mantener los archivos siempre en su path original. \ No newline at end of file From 63af25e429d8e888cf0498925b3f2c255ba82d50 Mon Sep 17 00:00:00 2001 From: sofiachavezb Date: Thu, 16 Oct 2025 07:57:27 -0300 Subject: [PATCH 050/218] baseline --- DashAI/back/api/api_v1/endpoints/documents.py | 30 +++++++++---------- DashAI/back/models/RAG/RAG_pipeline.py | 3 ++ .../models/RAG/Retrievers/dense_retriever.py | 18 ++++++----- .../models/RAG/Retrievers/retriever_model.py | 2 +- .../RAG/chunking_models/token_chunk_model.py | 28 ++++++++--------- .../embeddings/dense/fasttext_embedding.py | 3 ++ DashAI/front/src/api/rag.ts | 8 +++++ .../RAG/NewSessionModal/NewSessionModal.jsx | 12 ++++++++ 8 files changed, 65 insertions(+), 39 deletions(-) diff --git a/DashAI/back/api/api_v1/endpoints/documents.py b/DashAI/back/api/api_v1/endpoints/documents.py index 6cfc7fa26..7ca95999c 100644 --- a/DashAI/back/api/api_v1/endpoints/documents.py +++ b/DashAI/back/api/api_v1/endpoints/documents.py @@ -21,7 +21,9 @@ from sqlalchemy.orm import sessionmaker from DashAI.back.api.api_v1.schemas import DocumentResponse -from DashAI.back.dependencies.database.models import Document +from DashAI.back.dependencies.database.models import ( + Document as DocumentDBModel, +) from DashAI.back.models.RAG.utils import hash_function router = APIRouter() @@ -36,7 +38,7 @@ async def get_all_documents( """Get all documents with file_url included.""" with session_factory() as db: try: - documents = db.query(Document).all() + documents: List[DocumentDBModel] = db.query(DocumentDBModel).all() documents_responses = [] @@ -50,7 +52,7 @@ async def get_all_documents( created=doc.created, last_modified=doc.last_modified, optional_metadata=doc.optional_metadata, - related_sessions=[session.id for session in doc.related_sessions_ids] if doc.related_sessions_ids else None, + related_sessions=doc.get_related_sessions, file_url=f"{base_url}/{doc.id}/download", ) ) @@ -72,7 +74,7 @@ async def get_document( """Get metadata of a document by its ID.""" with session_factory() as db: try: - document = db.get(Document, document_id) + document = db.get(DocumentDBModel, document_id) if not document: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, @@ -102,7 +104,7 @@ async def download_document( ): """Download the actual file content of a document.""" with session_factory() as db: - document = db.get(Document, document_id) + document = db.query(DocumentDBModel).filter_by(id=document_id).first() if not document: raise HTTPException( status_code=404, @@ -162,7 +164,7 @@ async def upload_document( file_content_hash = hash_function(content_bytes) with session_factory() as db: - existing_doc = db.query(Document).filter_by(file_hash=file_content_hash).first() + existing_doc: DocumentDBModel = db.query(DocumentDBModel).filter_by(file_hash=file_content_hash).first() if existing_doc: # Update existing document's information existing_doc.file_name = file_name @@ -176,16 +178,14 @@ async def upload_document( file_hash=existing_doc.file_hash, created=existing_doc.created, last_modified=existing_doc.last_modified, - related_sessions=[session.id for session in existing_doc.related_sessions_ids], + related_sessions=existing_doc.get_related_sessions, optional_metadata=existing_doc.optional_metadata, file_url=f"{base_url}/{existing_doc.id}/download" ) else: # Create a new document entry try: - max_id = db.query(Document.id).order_by(Document.id.desc()).first() - new_id = (max_id[0] + 1) if max_id else 1 - file_path = os.path.join(docs_folder_path, f"{new_id}__{file_name}") + file_path = os.path.join(docs_folder_path, f"{file_name}_{file_content_hash}") with open(file_path, "wb") as f: f.write(content_bytes) @@ -193,7 +193,7 @@ async def upload_document( # Get file type from file extension file_type = os.path.splitext(file_name)[1].lstrip('.') or 'unknown' - doc = Document( + doc = DocumentDBModel( file_name=file_name, file_type=file_type, file_path=str(file_path), @@ -211,7 +211,7 @@ async def upload_document( file_hash=doc.file_hash, created=doc.created, last_modified=doc.last_modified, - related_sessions=None, + related_sessions=doc.get_related_sessions, optional_metadata=doc.optional_metadata, file_url=f"{base_url}/{doc.id}/download", ) @@ -230,7 +230,7 @@ async def get_related_sessions( """Get all generative session IDs related to a specific document.""" with session_factory() as db: try: - document = db.get(Document, document_id) + document = db.query(DocumentDBModel).filter_by(id=document_id).first() if not document: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, @@ -255,7 +255,7 @@ async def delete_document( """Delete a document from the RAG system by its ID.""" with session_factory() as db: try: - document = db.get(Document, document_id) + document = db.query(DocumentDBModel).filter_by(id=document_id).first() if not document: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, @@ -294,7 +294,7 @@ async def update_document_metadata( """Update a document's metadata.""" with session_factory() as db: try: - document = db.get(Document, document_id) + document = db.query(DocumentDBModel).filter_by(id=document_id).first() if not document: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, diff --git a/DashAI/back/models/RAG/RAG_pipeline.py b/DashAI/back/models/RAG/RAG_pipeline.py index b5832e6cd..27a95eed3 100644 --- a/DashAI/back/models/RAG/RAG_pipeline.py +++ b/DashAI/back/models/RAG/RAG_pipeline.py @@ -430,6 +430,9 @@ def init_component( try: model_instance = model_class(**model_params) except Exception as e: + import traceback + traceback.print_exc() + raise RAGPipelineInitializationError(f"Failed to initialize {model_class_name}: {str(e)}") return model_instance \ No newline at end of file diff --git a/DashAI/back/models/RAG/Retrievers/dense_retriever.py b/DashAI/back/models/RAG/Retrievers/dense_retriever.py index bd2d70f5d..a412a75e0 100644 --- a/DashAI/back/models/RAG/Retrievers/dense_retriever.py +++ b/DashAI/back/models/RAG/Retrievers/dense_retriever.py @@ -81,15 +81,17 @@ class DenseRetriever(RetrieverModel): def __init__(self, **kwargs): # RetrieverModel class fetches retriever_db_model if exists super().__init__(**kwargs) - - self.embedding_model: DenseEmbedding = self.params["encoding_model"] - self.embedding_class_name = self.embedding_model.__class__.__name__ - self.embedding_params = self.embedding_model.params - self.params["encoding_model"] = { - "component": self.embedding_class_name, - "params": self.embedding_params - } + embedding_args = self.params["encoding_model"]["properties"]["params"]["comp"] + self.embedding_class_name = embedding_args["component"] + self.embedding_params = embedding_args.get("params", {}) + embedding_class = self.component_registry[self.embedding_class_name]["class"] + self.embedding_model: DenseEmbedding = embedding_class(**self.embedding_params) + + #self.embedding_model: DenseEmbedding = self.params["encoding_model"] + #self.embedding_class_name = self.embedding_model.__class__.__name__ + #self.embedding_params = self.embedding_model.params + self.fetch_db_models() self.similarity_metric = self.params["similarity_metric"] self.top_k = self.params["top_k"] diff --git a/DashAI/back/models/RAG/Retrievers/retriever_model.py b/DashAI/back/models/RAG/Retrievers/retriever_model.py index fe77b3499..124c5995c 100644 --- a/DashAI/back/models/RAG/Retrievers/retriever_model.py +++ b/DashAI/back/models/RAG/Retrievers/retriever_model.py @@ -44,7 +44,7 @@ def __init__(self, **kwargs): self.chunks: Dict[int, Dict[int, Chunk]] = self.params.pop("chunks") self.chunking_model_id: int = self.params.pop("chunking_model_id") self.validate_chunks() - self.params = self.validate_and_transform(self.params) + #self.params = self.validate_and_transform(self.params) if self.pipeline_id is not None: diff --git a/DashAI/back/models/RAG/chunking_models/token_chunk_model.py b/DashAI/back/models/RAG/chunking_models/token_chunk_model.py index a6f58ea88..530018d95 100644 --- a/DashAI/back/models/RAG/chunking_models/token_chunk_model.py +++ b/DashAI/back/models/RAG/chunking_models/token_chunk_model.py @@ -39,24 +39,22 @@ class TokenChunkModel(BaseChunkingModel): SCHEMA = TokenChunkModelSchema def __init__(self, **kwargs): - pipeline_id = self.params.pop("pipeline_id") - - self.db_model = self.init_model_in_db(pipeline_id) - - self.params = self.validate_and_transform(kwargs) - - self.chunk_size = self.params["chunk_size"] - self.chunk_overlap = self.params["chunk_overlap"] - self.tokenizer_name = self.params["tokenizer_name"] + self.parameters = kwargs + self.chunk_size = self.parameters["chunk_size"] + self.chunk_overlap = self.parameters["chunk_overlap"] + self.tokenizer_name = self.parameters["tokenizer_name"] self.tokenizer = AutoTokenizer.from_pretrained(self.tokenizer_name) + super().__init__(**kwargs) + - def chunk_text(self, text: str) -> List[List[str]]: + def chunk_text(self, text: str) -> List[str]: tokens = self.tokenizer.tokenize(text) - chunks = [] - for i in range(0, len(tokens), self.chunk_size): - chunk = tokens[i : i + self.chunk_size] - chunks.append(chunk) + token_chunks = [] + while len(tokens) > 0: + chunk = tokens[: self.chunk_size] + token_chunks.append(self.tokenizer.convert_tokens_to_string(chunk)) + tokens = tokens[self.chunk_size - self.chunk_overlap :] - return chunks + return token_chunks diff --git a/DashAI/back/models/RAG/embeddings/dense/fasttext_embedding.py b/DashAI/back/models/RAG/embeddings/dense/fasttext_embedding.py index e2eaec4f7..e0061aa69 100644 --- a/DashAI/back/models/RAG/embeddings/dense/fasttext_embedding.py +++ b/DashAI/back/models/RAG/embeddings/dense/fasttext_embedding.py @@ -56,6 +56,9 @@ def load(self): model_path = hf_hub_download(repo_id=self.model_name, filename=f"{model_name}.bin") self.model = fasttext.load_model(model_path) + def save(self): + pass + def encode(self, text: str) -> np.ndarray: """Encode text into an embedding.""" token_embeddings = [self.model.get_word_vector(word) for word in text.split()] diff --git a/DashAI/front/src/api/rag.ts b/DashAI/front/src/api/rag.ts index 52dc2b6c4..93c5a0fb8 100644 --- a/DashAI/front/src/api/rag.ts +++ b/DashAI/front/src/api/rag.ts @@ -46,6 +46,10 @@ export const createRAGSession = async ( component: string; params: Record; }; + prompt_model: { + component: string; + params: Record; + }; }; const transformedSession: Omit = @@ -69,6 +73,10 @@ export const createRAGSession = async ( component: params.generation_model.component, params: params.generation_model.params, }, + prompt_model: { + component: params.prompt_model.component, + params: params.prompt_model.params, + }, }, }; diff --git a/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx b/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx index 5d9070bea..54ed4c9eb 100644 --- a/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx +++ b/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx @@ -63,6 +63,12 @@ const defaultNewSession = { component: "", params: {}, }, + prompt_model: { + component: "CustomGenerationPrompt", + params: { + template: "Answer to this message: {input}, with the following information: {chunks}", + }, + }, }, }; @@ -203,6 +209,12 @@ export default function NewSessionModal({ component: "", params: {}, }, + prompt_model: sessionData.parameters.prompt_model || { + component: "CustomGenerationPrompt", + params: { + template: "Answer to this message: {input}, with the following information: {chunks}", + } + }, }, }; From e0b02878e4e75575a3afba0e0f4b78ed6e5075ec Mon Sep 17 00:00:00 2001 From: Creylay Date: Thu, 16 Oct 2025 12:39:48 -0300 Subject: [PATCH 051/218] refactor: Integrate useRef for retriever step management and enhance form value handling in NewSessionModal and RetrieverConfigurationStep --- .../RAG/NewSessionModal/NewSessionModal.jsx | 20 +- .../RetrieverConfigurationStep.jsx | 425 ++++++++++-------- 2 files changed, 256 insertions(+), 189 deletions(-) diff --git a/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx b/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx index 54ed4c9eb..1c3be53a6 100644 --- a/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx +++ b/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useCallback } from "react"; +import React, { useState, useEffect, useCallback, useRef } from "react"; import { Button, Dialog, @@ -87,6 +87,7 @@ export default function NewSessionModal({ new Array(steps.length).fill(false), ); const [sessionData, setSessionData] = useState(session || defaultNewSession); + const retrieverStepRef = useRef(null); // Ref para el paso de retriever useEffect(() => { if (open) { @@ -299,6 +300,7 @@ export default function NewSessionModal({ )} {activeStep === 2 && ( handleStepValidation(2, isValid)} @@ -331,11 +333,17 @@ export default function NewSessionModal({ - ), - }, - { - field: "created", - headerName: "Created At", - flex: 0.4, - valueFormatter: (params) => new Date(params.value).toLocaleDateString(), - }, - { - field: "", - headerName: "Documents", - flex: 0.4, - valueGetter: (params) => params.row.parameters.documents?.length, - }, - { - field: "actions", - headerName: "Actions", - flex: 0.9, - renderCell: (params) => ( -
+ const columns = React.useMemo( + () => [ + { + field: "name", + headerName: "Session Name", + flex: 0.8, + renderCell: (params) => ( - - -
- ), - }, - ]; + + + + + ), + }, + ], + [onSelect, onEdit], + ); return ( From 6ce5ce5fdbc1a43fa43efc379c8e933f34e7eb59 Mon Sep 17 00:00:00 2001 From: Creylay Date: Mon, 20 Oct 2025 15:10:37 -0300 Subject: [PATCH 055/218] refactor: Remove unnecessary console logs and clean up code in NewSessionModal and RetrieverConfigurationStep --- .../RAG/NewSessionModal/NewSessionModal.jsx | 7 +-- .../RetrieverConfigurationStep.jsx | 51 ++----------------- 2 files changed, 5 insertions(+), 53 deletions(-) diff --git a/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx b/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx index 648f0e030..207e92e5c 100644 --- a/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx +++ b/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx @@ -88,7 +88,7 @@ export default function NewSessionModal({ new Array(steps.length).fill(false), ); const [sessionData, setSessionData] = useState(session || defaultNewSession); - const retrieverStepRef = useRef(null); // Ref para el paso de retriever + const retrieverStepRef = useRef(null); useEffect(() => { if (open) { @@ -336,12 +336,7 @@ export default function NewSessionModal({ - - + )} @@ -139,12 +192,14 @@ export default function DocumentSelectionTable({ } DocumentSelectionTable.propTypes = { - documents: PropTypes.arrayOf(PropTypes.shape({ - id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - createdAt: PropTypes.string.isRequired, - preview: PropTypes.string, - })).isRequired, + documents: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + createdAt: PropTypes.string.isRequired, + preview: PropTypes.string, + }), + ).isRequired, selectedIds: PropTypes.arrayOf(PropTypes.string).isRequired, onToggle: PropTypes.func.isRequired, onSelectAll: PropTypes.func.isRequired, From bb8e6d437f375ec81409a6030f80a914ff357c57 Mon Sep 17 00:00:00 2001 From: Creylay Date: Tue, 21 Oct 2025 13:04:49 -0300 Subject: [PATCH 059/218] refactor: Replace custom table implementation with DataGrid for improved performance and usability --- .../generative/RAG/DocumentSelectionTable.jsx | 275 +++++++----------- 1 file changed, 111 insertions(+), 164 deletions(-) diff --git a/DashAI/front/src/components/generative/RAG/DocumentSelectionTable.jsx b/DashAI/front/src/components/generative/RAG/DocumentSelectionTable.jsx index a359ae3a0..90ee530c6 100644 --- a/DashAI/front/src/components/generative/RAG/DocumentSelectionTable.jsx +++ b/DashAI/front/src/components/generative/RAG/DocumentSelectionTable.jsx @@ -1,22 +1,10 @@ -import { - Box, - Table, - TableBody, - TableCell, - TableHead, - TableRow, - Checkbox, - Typography, - IconButton, - Tooltip, - Button, - CircularProgress, - TablePagination, -} from "@mui/material"; +import React from "react"; +import { Box, IconButton, Tooltip, LinearProgress } from "@mui/material"; +import { DataGrid } from "@mui/x-data-grid"; import VisibilityIcon from "@mui/icons-material/Visibility"; import DeleteIcon from "@mui/icons-material/Delete"; import PropTypes from "prop-types"; -import { useState } from "react"; +import { formatDate } from "../../../utils"; export default function DocumentSelectionTable({ documents, @@ -27,166 +15,125 @@ export default function DocumentSelectionTable({ onRemove, isLoading = false, }) { - const [page, setPage] = useState(0); - const [rowsPerPage, setRowsPerPage] = useState(5); + const handleSelectionChange = (newSelection) => { + // Get currently selected IDs + const currentSet = new Set(selectedIds); + const newSet = new Set(newSelection); - const handleChangePage = (event, newPage) => { - setPage(newPage); - }; + // Find what was added + const added = newSelection.filter((id) => !currentSet.has(id)); + // Find what was removed + const removed = selectedIds.filter((id) => !newSet.has(id)); - const handleChangeRowsPerPage = (event) => { - setRowsPerPage(parseInt(event.target.value, 10)); - setPage(0); + if (added.length > 0) { + added.forEach((id) => onToggle(id)); + } + if (removed.length > 0) { + removed.forEach((id) => onToggle(id)); + } }; - // Calculate paginated documents - const paginatedDocuments = documents.slice( - page * rowsPerPage, - page * rowsPerPage + rowsPerPage, + const columns = React.useMemo( + () => [ + { + field: "id", + headerName: "ID", + minWidth: 50, + flex: 0.5, + editable: false, + }, + { + field: "file_name", + headerName: "Name", + minWidth: 250, + flex: 1, + editable: false, + }, + { + field: "created", + headerName: "Added On", + minWidth: 140, + flex: 0.5, + editable: false, + valueGetter: (value) => formatDate(value), + }, + { + field: "last_modified", + headerName: "Last Modified", + minWidth: 140, + flex: 0.5, + editable: false, + valueGetter: (value, row) => { + return row.optional_metadata?.last_modified + ? formatDate(row.optional_metadata.last_modified) + : "N/A"; + }, + }, + { + field: "actions", + type: "actions", + headerName: "Actions", + minWidth: 100, + flex: 0.3, + getActions: (params) => [ + + { + if (params.row.preview) { + window.open(params.row.preview, "_blank"); + } else { + console.warn("No preview URL available for this document."); + } + }} + > + + + , + + onRemove(params.row.id)}> + + + , + ], + }, + ], + [onRemove], ); - // Format the date to a more readable format - const formatDate = (dateString) => { - try { - const date = new Date(dateString); - return date.toLocaleString(); - } catch (e) { - return dateString; - } - }; - return ( - {isLoading ? ( - - - - ) : documents.length === 0 ? ( - - No documents available. - - ) : ( - <> - - - - - 0 && - selectedIds.length < documents.length - } - checked={ - selectedIds.length === documents.length && - documents.length > 0 - } - onChange={(event) => { - if (event.target.checked) { - onSelectAll(); - } else { - onDeselectAll(); - } - }} - /> - - Id - Name - Added On - Last Modified - Actions - - - - {paginatedDocuments.map((doc) => ( - - - onToggle(doc.id)} - /> - - {doc.id} - {doc.file_name} - {formatDate(doc.created)} - - {doc.optional_metadata?.last_modified - ? formatDate(doc.optional_metadata.last_modified) - : "N/A"} - - - - - { - if (doc.preview) window.open(doc.preview, "_blank"); - else - console.warn( - "No preview URL available for this document.", - ); - }} - > - - - - - onRemove(doc.id)} - > - - - - - - - ))} - -
- - - )} +
); } From 6918936f2a000cec62161bfc0cb0e418f481b38a Mon Sep 17 00:00:00 2001 From: Creylay Date: Tue, 21 Oct 2025 13:23:01 -0300 Subject: [PATCH 060/218] refactor: Adjust column width and enhance scrollbar styles in DocumentSelectionTable --- .../generative/RAG/DocumentSelectionTable.jsx | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/DashAI/front/src/components/generative/RAG/DocumentSelectionTable.jsx b/DashAI/front/src/components/generative/RAG/DocumentSelectionTable.jsx index 90ee530c6..c2c3bab7f 100644 --- a/DashAI/front/src/components/generative/RAG/DocumentSelectionTable.jsx +++ b/DashAI/front/src/components/generative/RAG/DocumentSelectionTable.jsx @@ -45,7 +45,7 @@ export default function DocumentSelectionTable({ { field: "file_name", headerName: "Name", - minWidth: 250, + minWidth: 220, flex: 1, editable: false, }, @@ -104,6 +104,9 @@ export default function DocumentSelectionTable({ return ( From 8b376e2f222d4bec03228e0ef778e99be90951bc Mon Sep 17 00:00:00 2001 From: Creylay Date: Tue, 21 Oct 2025 15:16:53 -0300 Subject: [PATCH 061/218] refactor: Improve styling for remove action button in DocumentSelectionTable --- .../components/generative/RAG/DocumentSelectionTable.jsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/DashAI/front/src/components/generative/RAG/DocumentSelectionTable.jsx b/DashAI/front/src/components/generative/RAG/DocumentSelectionTable.jsx index c2c3bab7f..1898356e2 100644 --- a/DashAI/front/src/components/generative/RAG/DocumentSelectionTable.jsx +++ b/DashAI/front/src/components/generative/RAG/DocumentSelectionTable.jsx @@ -91,7 +91,11 @@ export default function DocumentSelectionTable({ , - onRemove(params.row.id)}> + onRemove(params.row.id)} + sx={{ color: "error.main" }} + > , From e3935261d96a65fc16c608383eb1610462260e29 Mon Sep 17 00:00:00 2001 From: Creylay Date: Tue, 21 Oct 2025 15:34:28 -0300 Subject: [PATCH 062/218] refactor: Integrate DeleteItemModal for document removal confirmation in DocumentSelectionTable --- .../src/components/custom/DeleteItemModal.jsx | 6 +++--- .../generative/RAG/DocumentSelectionTable.jsx | 16 ++++++---------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/DashAI/front/src/components/custom/DeleteItemModal.jsx b/DashAI/front/src/components/custom/DeleteItemModal.jsx index 63a6a8486..0c2b63e9b 100644 --- a/DashAI/front/src/components/custom/DeleteItemModal.jsx +++ b/DashAI/front/src/components/custom/DeleteItemModal.jsx @@ -16,7 +16,7 @@ import TooltipedCellItem from "../shared/TooltipedCellItem"; * @param {Object} props * @param {Function} props.deleteFromTable - Function to delete the item from the table */ -function DeleteItemModal({ deleteFromTable }) { +function DeleteItemModal({ deleteFromTable, item = "item" }) { const [open, setOpen] = React.useState(false); const handleDelete = () => { deleteFromTable(); @@ -28,7 +28,7 @@ function DeleteItemModal({ deleteFromTable }) { key="delete-button" icon={} label="Delete" - tooltip="Delete item" + tooltip={`Delete ${item}`} onClick={() => setOpen(true)} sx={{ color: "error.main" }} /> @@ -36,7 +36,7 @@ function DeleteItemModal({ deleteFromTable }) { Confirm Deletion - Are you sure you want to delete this item? + Are you sure you want to delete this {item}? diff --git a/DashAI/front/src/components/generative/RAG/DocumentSelectionTable.jsx b/DashAI/front/src/components/generative/RAG/DocumentSelectionTable.jsx index 1898356e2..883090ede 100644 --- a/DashAI/front/src/components/generative/RAG/DocumentSelectionTable.jsx +++ b/DashAI/front/src/components/generative/RAG/DocumentSelectionTable.jsx @@ -2,9 +2,9 @@ import React from "react"; import { Box, IconButton, Tooltip, LinearProgress } from "@mui/material"; import { DataGrid } from "@mui/x-data-grid"; import VisibilityIcon from "@mui/icons-material/Visibility"; -import DeleteIcon from "@mui/icons-material/Delete"; import PropTypes from "prop-types"; import { formatDate } from "../../../utils"; +import DeleteItemModal from "../../custom/DeleteItemModal"; export default function DocumentSelectionTable({ documents, @@ -90,15 +90,11 @@ export default function DocumentSelectionTable({ , - - onRemove(params.row.id)} - sx={{ color: "error.main" }} - > - - - , + onRemove(params.row.id)} + item="document" + />, ], }, ], From a644f03e6e1c4bb5d092f87026c87b83f986d6ad Mon Sep 17 00:00:00 2001 From: Creylay Date: Tue, 21 Oct 2025 15:47:26 -0300 Subject: [PATCH 063/218] refactor: Add PromptConfigurationStep to NewSessionModal steps --- .../generative/RAG/NewSessionModal/NewSessionModal.jsx | 6 ++++++ .../RAG/NewSessionModal/PromptConfigurationStep.jsx | 0 2 files changed, 6 insertions(+) create mode 100644 DashAI/front/src/pages/generative/RAG/NewSessionModal/PromptConfigurationStep.jsx diff --git a/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx b/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx index 16d9c58c9..fdd624966 100644 --- a/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx +++ b/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx @@ -20,6 +20,7 @@ import DocumentSelectionStep from "./DocumentSelectionStep"; import ChunkingConfigurationStep from "./ChunkingConfigurationStep"; import RetrieverConfigurationStep from "./RetrieverConfigurationStep"; import GeneratorConfigurationStep from "./GeneratorConfigurationStep"; +import PromptConfigurationStep from "./PromptConfigurationStep"; import { generateSequentialName } from "../../../../utils/nameGenerator"; const steps = [ @@ -43,6 +44,11 @@ const steps = [ label: "Configure Language Model", component: GeneratorConfigurationStep, }, + { + name: "configure-prompt", + label: "Configure Prompt", + component: PromptConfigurationStep, + }, ]; const defaultNewSession = { diff --git a/DashAI/front/src/pages/generative/RAG/NewSessionModal/PromptConfigurationStep.jsx b/DashAI/front/src/pages/generative/RAG/NewSessionModal/PromptConfigurationStep.jsx new file mode 100644 index 000000000..e69de29bb From d9593ffb79872bc259131aa61447cf5a575cdc0a Mon Sep 17 00:00:00 2001 From: Creylay Date: Tue, 21 Oct 2025 16:21:27 -0300 Subject: [PATCH 064/218] refactor: Implement PromptConfigurationStep for improved session configuration --- .../RAG/NewSessionModal/NewSessionModal.jsx | 8 +++ .../PromptConfigurationStep.jsx | 58 +++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx b/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx index fdd624966..c4e4cbfc2 100644 --- a/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx +++ b/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx @@ -341,6 +341,14 @@ export default function NewSessionModal({ setNextEnabled={(isValid) => handleStepValidation(3, isValid)} /> )} + + {activeStep === 4 && ( + handleStepValidation(4, isValid)} + /> + )} diff --git a/DashAI/front/src/pages/generative/RAG/NewSessionModal/PromptConfigurationStep.jsx b/DashAI/front/src/pages/generative/RAG/NewSessionModal/PromptConfigurationStep.jsx index e69de29bb..1ec96b4d6 100644 --- a/DashAI/front/src/pages/generative/RAG/NewSessionModal/PromptConfigurationStep.jsx +++ b/DashAI/front/src/pages/generative/RAG/NewSessionModal/PromptConfigurationStep.jsx @@ -0,0 +1,58 @@ +import React, { useEffect } from "react"; +import { Box, Typography } from "@mui/material"; +import PropTypes from "prop-types"; + +export default function PromptConfigurationStep({ + sessionData, + setSessionData, + setNextEnabled, +}) { + // Set this step as always valid + useEffect(() => { + if (setNextEnabled) { + setNextEnabled(true); + } + }, [setNextEnabled]); + + return ( + + + Prompt Configuration + + + This step is currently under development. The default prompt template + will be used. + + + + Default template: + + + Answer to this message: {"{input}"}, with the following information:{" "} + {"{chunks}"} + + + + ); +} + +PromptConfigurationStep.propTypes = { + sessionData: PropTypes.object.isRequired, + setSessionData: PropTypes.func.isRequired, + setNextEnabled: PropTypes.func, +}; From da2f36988603f751230a70c5e0b7214a754dd141 Mon Sep 17 00:00:00 2001 From: Creylay Date: Tue, 21 Oct 2025 17:11:26 -0300 Subject: [PATCH 065/218] refactor: Add endpoint to retrieve all available RAG prompts with error handling --- .../api_v1/endpoints/generative_session.py | 67 ++++++++++++++++--- 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/DashAI/back/api/api_v1/endpoints/generative_session.py b/DashAI/back/api/api_v1/endpoints/generative_session.py index 3c622706f..fef7b1880 100644 --- a/DashAI/back/api/api_v1/endpoints/generative_session.py +++ b/DashAI/back/api/api_v1/endpoints/generative_session.py @@ -10,17 +10,16 @@ GenerativeSessionParams, ) from DashAI.back.dependencies.database.models import ( + Document, GenerativeProcess, GenerativeSession, GenerativeSessionParameterHistory, ProcessData, - Document + RAGPrompt, ) from DashAI.back.dependencies.registry import ComponentRegistry from DashAI.back.models import BaseGenerativeModel -from DashAI.back.models.RAG import PDFDocument, TxtDocument, BaseDocument from DashAI.back.tasks import BaseGenerativeTask - from DashAI.back.tasks.RAG_task import RAGTask router = APIRouter() @@ -61,22 +60,23 @@ async def upload_generative_session( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Task {params.task_name} is not registered.", ) from e - + # RAG Task specific handling - # Frontend will send the ids of the documents to be used in the RAG session - # but RAG pipeline expects the documents paths of the backend-stored documents + # Frontend will send the ids of the documents to be used in the + # RAG session but RAG pipeline expects the documents paths of the + # backend-stored documents if task_class == RAGTask: try: assert params.parameters["documents"] assert isinstance(params.parameters["documents"], list) - assert len(params.parameters["documents"]) > 0 + assert len(params.parameters["documents"]) > 0 - except (AssertionError, KeyError): + except (AssertionError, KeyError) as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="RAG Task requires a non-empty list of document IDs.", - ) - + ) from e + documents_ids = [] for doc_id in params.parameters["documents"]: document = db.get(Document, doc_id) @@ -144,6 +144,51 @@ async def upload_generative_session( ) from e +@router.get("/prompts", status_code=status.HTTP_200_OK) +async def get_all_prompts( + session_factory: sessionmaker = Depends(lambda: di["session_factory"]), +): + """Get all available RAG prompts. + + Parameters + ---------- + session_factory : Callable[..., ContextManager[Session]] + A factory that creates a context manager that handles a SQLAlchemy session. + The generated session can be used to access and query the database. + + Returns + ------- + list + A list of dictionaries with all prompts on the database. + + Raises + ------ + HTTPException + If there's an internal database error. + """ + with session_factory() as db: + try: + prompts = db.query(RAGPrompt).all() + + prompt_responses = [] + for prompt in prompts: + prompt_responses.append( + { + "id": prompt.id, + "class_name": prompt.class_name, + "parameters": prompt.parameters, + } + ) + + return prompt_responses + except exc.SQLAlchemyError as e: + log.exception(e) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="Internal database error", + ) from e + + @router.get("/{session_id}", status_code=status.HTTP_200_OK) async def get_generative_session( session_id: int, @@ -533,4 +578,4 @@ async def get_parameter_history_entry( raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Internal database error", - ) from e \ No newline at end of file + ) from e From 192ab64adf2f5978260c16fc9929417abb71f03f Mon Sep 17 00:00:00 2001 From: Creylay Date: Tue, 21 Oct 2025 17:11:39 -0300 Subject: [PATCH 066/218] refactor: Add getRAGPrompts function to fetch RAG prompts with error handling --- DashAI/front/src/api/rag.ts | 11 +++++++++++ DashAI/front/src/types/ragPrompt.ts | 7 +++++++ 2 files changed, 18 insertions(+) create mode 100644 DashAI/front/src/types/ragPrompt.ts diff --git a/DashAI/front/src/api/rag.ts b/DashAI/front/src/api/rag.ts index 93c5a0fb8..5a819acf9 100644 --- a/DashAI/front/src/api/rag.ts +++ b/DashAI/front/src/api/rag.ts @@ -3,6 +3,7 @@ import { ISession } from "../types/session"; import { IGenerativeTask } from "../types/generativeTask"; import { IDocumentResponse } from "../types/documentResponse"; import { IComponent } from "../types/component"; +import { IRAGPrompt } from "../types/ragPrompt"; import { getChildComponents } from "./component"; // Fetch all RAG sessions @@ -221,3 +222,13 @@ export const addDocument = async ({ return response.data; }; + +export const getRAGPrompts = async (): Promise => { + const response = await api.get( + "/v1/generative-session/prompts", + ); + if (response.status !== 200) { + throw new Error(`Failed to fetch RAG prompts: ${response.statusText}`); + } + return response.data; +}; diff --git a/DashAI/front/src/types/ragPrompt.ts b/DashAI/front/src/types/ragPrompt.ts new file mode 100644 index 000000000..87300586d --- /dev/null +++ b/DashAI/front/src/types/ragPrompt.ts @@ -0,0 +1,7 @@ +export interface IRAGPrompt { + id: number; + class_name: string; + parameters: { + template: string; + }; +} From 9181533d776039654a6d44b39ea6622e3f3a36a6 Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 22 Oct 2025 19:30:27 -0300 Subject: [PATCH 067/218] refactor: Clean up code formatting and improve readability in models.py --- DashAI/back/dependencies/database/models.py | 289 ++++++++++---------- 1 file changed, 137 insertions(+), 152 deletions(-) diff --git a/DashAI/back/dependencies/database/models.py b/DashAI/back/dependencies/database/models.py index 83e52b081..0668d53e7 100644 --- a/DashAI/back/dependencies/database/models.py +++ b/DashAI/back/dependencies/database/models.py @@ -3,7 +3,19 @@ from datetime import datetime from typing import Any, Dict, List, Optional -from sqlalchemy import JSON, Boolean, CheckConstraint, Column, DateTime, Enum, ForeignKey, Integer, String, Text, UniqueConstraint, ARRAY +from sqlalchemy import ( + JSON, + Boolean, + CheckConstraint, + Column, + DateTime, + Enum, + ForeignKey, + Integer, + String, + Text, + UniqueConstraint, +) from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import Mapped, mapped_column, relationship @@ -415,7 +427,7 @@ class GenerativeSession(Base): processes: Mapped[List["GenerativeProcess"]] = relationship( "GenerativeProcess", cascade="all, delete-orphan", back_populates="session" ) - + # Relationship with RAGDocumentPipelineSessionLink pipeline_links: Mapped[List["RAGDocumentPipelineSessionLink"]] = relationship( back_populates="session" @@ -620,23 +632,11 @@ def delete_result(self) -> None: self.end_time = None - - - - - - - - - - - - - """ RAG tables """ + class Document(Base): __tablename__ = "document" """ @@ -659,7 +659,7 @@ class Document(Base): pipeline_links: Mapped[List["RAGDocumentPipelineSessionLink"]] = relationship( "RAGDocumentPipelineSessionLink", cascade="all, delete-orphan", - back_populates="document" + back_populates="document", ) chunks: Mapped[List["Chunk"]] = relationship( @@ -667,37 +667,39 @@ class Document(Base): back_populates="document", cascade="all, delete-orphan", ) - + embedding_matrices: Mapped[List["RAGEmbeddingMatrix"]] = relationship( - "RAGEmbeddingMatrix", - back_populates="document", - cascade="all, delete-orphan" + "RAGEmbeddingMatrix", back_populates="document", cascade="all, delete-orphan" ) @property def get_related_sessions(self) -> List["GenerativeSession"]: """Return a list of sessions related to the document.""" return [link.session for link in self.pipeline_links] - + @property def get_related_pipelines(self) -> List["RAGPipeline"]: """Return a list of pipelines related to the document.""" return [link.pipeline for link in self.pipeline_links] - - def get_embedding_matrix(self, chunking_model_id: int, embedding_model_id: int) -> Optional["RAGEmbeddingMatrix"]: + + def get_embedding_matrix( + self, chunking_model_id: int, embedding_model_id: int + ) -> Optional["RAGEmbeddingMatrix"]: """ - Get the embedding matrix for a specific combination of chunking and embedding models. - + Get the embedding matrix for a given chunking and embedding model ids. + Args: - chunking_model_id: ID of the chunking model - embedding_model_id: ID of the embedding model - + chunking_model_id: ID of the chunking model. + embedding_model_id: ID of the embedding model. + Returns: - The embedding matrix if found, None otherwise + The embedding matrix if found, otherwise None. """ for matrix in self.embedding_matrices: - if (matrix.chunking_model_id == chunking_model_id and - matrix.embedding_model_id == embedding_model_id): + if ( + matrix.chunking_model_id == chunking_model_id + and matrix.embedding_model_id == embedding_model_id + ): return matrix return None @@ -711,27 +713,20 @@ class Chunk(Base): document_id: Mapped[int] = mapped_column( ForeignKey("document.id", ondelete="CASCADE"), nullable=False ) - chunk_index: Mapped[int] = mapped_column(Integer, nullable=False) + chunk_index: Mapped[int] = mapped_column(Integer, nullable=False) chunking_model_id: Mapped[int] = mapped_column( - ForeignKey("rag_chunking_model.id", ondelete="CASCADE"), - nullable=False + ForeignKey("rag_chunking_model.id", ondelete="CASCADE"), nullable=False ) text: Mapped[str] = mapped_column(Text, nullable=False) hash: Mapped[str] = mapped_column(String, nullable=False, unique=True) - document: Mapped["Document"] = relationship( - "Document", - back_populates="chunks" - ) - + document: Mapped["Document"] = relationship("Document", back_populates="chunks") + chunking_model: Mapped["RAGChunkingModel"] = relationship( - "RAGChunkingModel", - back_populates="chunks" + "RAGChunkingModel", back_populates="chunks" ) - __table_args__ = ( - UniqueConstraint("id", "document_id", name="uix_chunk_document"), - ) + __table_args__ = (UniqueConstraint("id", "document_id", name="uix_chunk_document"),) class RAGPrompt(Base): @@ -742,12 +737,16 @@ class RAGPrompt(Base): id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) class_name: Mapped[str] = mapped_column(String, nullable=False) parameters: Mapped[JSON] = mapped_column(JSON, nullable=True) - + created: Mapped[DateTime] = mapped_column(DateTime, default=datetime.now) + last_modified: Mapped[DateTime] = mapped_column( + DateTime, + default=datetime.now, + onupdate=datetime.now, + ) + # Relationship with RAGPipeline pipelines: Mapped[List["RAGPipeline"]] = relationship( - "RAGPipeline", - back_populates="prompt", - cascade="all, delete-orphan" + "RAGPipeline", back_populates="prompt", cascade="all, delete-orphan" ) @@ -759,77 +758,55 @@ class RAGGenerationModel(Base): id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) class_name: Mapped[str] = mapped_column(String, nullable=False) parameters: Mapped[JSON] = mapped_column(JSON, nullable=True) - + # Relationships pipelines: Mapped[List["RAGPipeline"]] = relationship( back_populates="generation_model" ) + class RAGPipeline(Base): __tablename__ = "rag_pipeline" """ Table to store all the information about a RAG pipeline. """ - id: Mapped[int] = mapped_column( - primary_key=True, - autoincrement=True) + id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) session_id: Mapped[int] = mapped_column( - ForeignKey( - "generative_session.id", - ondelete="CASCADE"), - nullable=False + ForeignKey("generative_session.id", ondelete="CASCADE"), nullable=False ) name: Mapped[str] = mapped_column(String, nullable=False) description: Mapped[str] = mapped_column(String, nullable=True) parameters: Mapped[JSON] = mapped_column(JSON, nullable=True) - + chunking_model_id: Mapped[int] = mapped_column( - ForeignKey( - "rag_chunking_model.id", - ondelete="CASCADE"), - nullable=False + ForeignKey("rag_chunking_model.id", ondelete="CASCADE"), nullable=False ) retriever_model_id: Mapped[int] = mapped_column( - ForeignKey( - "rag_retriever.id", - ondelete="CASCADE"), - nullable=False + ForeignKey("rag_retriever.id", ondelete="CASCADE"), nullable=False ) prompt_id: Mapped[int] = mapped_column( - ForeignKey( - "rag_prompt.id", - ondelete="CASCADE"), - nullable=False + ForeignKey("rag_prompt.id", ondelete="CASCADE"), nullable=False ) generation_model_id: Mapped[int] = mapped_column( - ForeignKey( - "rag_generation_model.id", - ondelete="CASCADE"), - nullable=False + ForeignKey("rag_generation_model.id", ondelete="CASCADE"), nullable=False ) # Relationships chunking_model: Mapped["RAGChunkingModel"] = relationship( - "RAGChunkingModel", - back_populates="pipelines" + "RAGChunkingModel", back_populates="pipelines" ) retriever: Mapped["RAGRetriever"] = relationship( - "RAGRetriever", - back_populates="pipelines" - ) - prompt: Mapped["RAGPrompt"] = relationship( - "RAGPrompt", - back_populates="pipelines" + "RAGRetriever", back_populates="pipelines" ) + prompt: Mapped["RAGPrompt"] = relationship("RAGPrompt", back_populates="pipelines") generation_model: Mapped["RAGGenerationModel"] = relationship( - "RAGGenerationModel", - back_populates="pipelines" + "RAGGenerationModel", back_populates="pipelines" ) pipeline_links: Mapped[List["RAGDocumentPipelineSessionLink"]] = relationship( - "RAGDocumentPipelineSessionLink", - back_populates="pipeline" + "RAGDocumentPipelineSessionLink", back_populates="pipeline" ) + class RAGChunkingModel(Base): __tablename__ = "rag_chunking_model" """ @@ -838,20 +815,17 @@ class RAGChunkingModel(Base): id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) class_name: Mapped[str] = mapped_column(String, nullable=False) parameters: Mapped[JSON] = mapped_column(JSON, nullable=True) - + pipelines: Mapped[List["RAGPipeline"]] = relationship( - "RAGPipeline", - back_populates="chunking_model" + "RAGPipeline", back_populates="chunking_model" ) - + embedding_matrices: Mapped[List["RAGEmbeddingMatrix"]] = relationship( - "RAGEmbeddingMatrix", - back_populates="chunking_model" + "RAGEmbeddingMatrix", back_populates="chunking_model" ) - + chunks: Mapped[List["Chunk"]] = relationship( - "Chunk", - back_populates="chunking_model" + "Chunk", back_populates="chunking_model" ) @@ -861,14 +835,14 @@ class RAGRetriever(Base): Table to map the retriever model id to its dense or sparse retriever instance. """ id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) - class_name: Mapped[str] = mapped_column(String, nullable=False) # "SparseRetriever" or "DenseRetriever" + class_name: Mapped[str] = mapped_column( + String, nullable=False + ) # "SparseRetriever" or "DenseRetriever" dense_retriever_id: Mapped[Optional[int]] = mapped_column( - ForeignKey("rag_dense_retriever.id", ondelete="CASCADE"), - nullable=True + ForeignKey("rag_dense_retriever.id", ondelete="CASCADE"), nullable=True ) sparse_retriever_id: Mapped[Optional[int]] = mapped_column( - ForeignKey("rag_sparse_retriever.id", ondelete="CASCADE"), - nullable=True + ForeignKey("rag_sparse_retriever.id", ondelete="CASCADE"), nullable=True ) # Relationships @@ -878,18 +852,21 @@ class RAGRetriever(Base): dense_retriever: Mapped[Optional["RAGDenseRetriever"]] = relationship( back_populates="related_retriever" ) - pipelines: Mapped[List["RAGPipeline"]] = relationship( - back_populates="retriever" - ) + pipelines: Mapped[List["RAGPipeline"]] = relationship(back_populates="retriever") __table_args__ = ( CheckConstraint( - "(class_name = 'SparseRetriever' AND sparse_retriever_id IS NOT NULL AND dense_retriever_id IS NULL) OR " - "(class_name = 'DenseRetriever' AND dense_retriever_id IS NOT NULL AND sparse_retriever_id IS NULL)", - name="chk_retriever_type" + ( + "(class_name = 'SparseRetriever' " + "AND sparse_retriever_id IS NOT NULL " + "AND dense_retriever_id IS NULL) OR " + "(class_name = 'DenseRetriever' " + "AND dense_retriever_id IS NOT NULL " + "AND sparse_retriever_id IS NULL)" + ), + name="chk_retriever_type", ), ) - class RAGSparseRetriever(Base): @@ -904,7 +881,7 @@ class RAGSparseRetriever(Base): related_retriever: Mapped["RAGRetriever"] = relationship( "RAGRetriever", - back_populates="sparse_retriever", + back_populates="sparse_retriever", ) @@ -923,11 +900,10 @@ class RAGDenseRetriever(Base): # Relationships related_retriever: Mapped["RAGRetriever"] = relationship( "RAGRetriever", - back_populates="dense_retriever", + back_populates="dense_retriever", ) embedding_model: Mapped["RAGEmbeddingModel"] = relationship( - "RAGEmbeddingModel", - back_populates="dense_retrievers" + "RAGEmbeddingModel", back_populates="dense_retrievers" ) @@ -939,11 +915,10 @@ class RAGEmbeddingModel(Base): id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) class_name: Mapped[str] = mapped_column(String, nullable=False) parameters: Mapped[JSON] = mapped_column(JSON, nullable=True) - + # Relationships embedding_matrices: Mapped[List["RAGEmbeddingMatrix"]] = relationship( - back_populates="embedding_model", - cascade="all, delete-orphan" + back_populates="embedding_model", cascade="all, delete-orphan" ) dense_retrievers: Mapped[List["RAGDenseRetriever"]] = relationship( back_populates="embedding_model" @@ -953,7 +928,7 @@ class RAGEmbeddingModel(Base): class RAGEmbeddingMatrix(Base): __tablename__ = "rag_embedding_matrix" """ - Table to store embedding matrices for each unique combination of + Table to store embedding matrices for each unique combination of document, chunking model, and embedding model. """ id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) @@ -967,91 +942,101 @@ class RAGEmbeddingMatrix(Base): ForeignKey("rag_embedding_model.id", ondelete="CASCADE"), nullable=False ) storage_folder: Mapped[str] = mapped_column(String, nullable=False) - matrix_shape: Mapped[List[int]] = mapped_column(JSON, nullable=False) # [num_chunks, embedding_dim] + matrix_shape: Mapped[List[int]] = mapped_column( + JSON, nullable=False + ) # [num_chunks, embedding_dim] created: Mapped[DateTime] = mapped_column(DateTime, default=datetime.now) last_modified: Mapped[DateTime] = mapped_column( DateTime, default=datetime.now, onupdate=datetime.now, ) - + # Relationships document: Mapped["Document"] = relationship( - "Document", - back_populates="embedding_matrices" + "Document", back_populates="embedding_matrices" ) chunking_model: Mapped["RAGChunkingModel"] = relationship( - "RAGChunkingModel", - back_populates="embedding_matrices" + "RAGChunkingModel", back_populates="embedding_matrices" ) embedding_model: Mapped["RAGEmbeddingModel"] = relationship( - "RAGEmbeddingModel", - back_populates="embedding_matrices" + "RAGEmbeddingModel", back_populates="embedding_matrices" ) # Constraints - ensure uniqueness of the combination __table_args__ = ( UniqueConstraint( - "document_id", - "chunking_model_id", - "embedding_model_id", - name="uix_document_chunking_embedding" + "document_id", + "chunking_model_id", + "embedding_model_id", + name="uix_document_chunking_embedding", ), ) - + @property def num_chunks(self) -> int: """Return the number of chunks in this embedding matrix.""" return self.matrix_shape[0] if self.matrix_shape else 0 - + @property def embedding_dimension(self) -> int: """Return the embedding dimension.""" return self.matrix_shape[1] if len(self.matrix_shape) > 1 else 0 - + @classmethod - def get_by_tuple(cls, session, document_id: int, chunking_model_id: int, embedding_model_id: int) -> Optional["RAGEmbeddingMatrix"]: + def get_by_tuple( + cls, session, document_id: int, chunking_model_id: int, embedding_model_id: int + ) -> Optional["RAGEmbeddingMatrix"]: """ - Get an embedding matrix by the tuple (document_id, chunking_model_id, embedding_model_id). - + Get an embedding matrix by tuple + (document_id, chunking_model_id, embedding_model_id). + Args: - session: SQLAlchemy session - document_id: ID of the document - chunking_model_id: ID of the chunking model - embedding_model_id: ID of the embedding model - + session: SQLAlchemy session. + document_id: ID of the document. + chunking_model_id: ID of the chunking model. + embedding_model_id: ID of the embedding model. + Returns: - The embedding matrix if found, None otherwise + The embedding matrix if found, otherwise None. """ - return session.query(cls).filter( - cls.document_id == document_id, - cls.chunking_model_id == chunking_model_id, - cls.embedding_model_id == embedding_model_id - ).first() - - - + return ( + session.query(cls) + .filter( + cls.document_id == document_id, + cls.chunking_model_id == chunking_model_id, + cls.embedding_model_id == embedding_model_id, + ) + .first() + ) """ RAG relationship tables """ + class RAGDocumentPipelineSessionLink(Base): __tablename__ = "rag_document_pipeline_session_link" - + id = Column(Integer, primary_key=True, autoincrement=True) - document_id = Column(Integer, ForeignKey("document.id", ondelete="CASCADE"), nullable=False) - session_id = Column(Integer, ForeignKey("generative_session.id", ondelete="CASCADE"), nullable=False) - pipeline_id = Column(Integer, ForeignKey("rag_pipeline.id", ondelete="CASCADE"), nullable=False) + document_id = Column( + Integer, ForeignKey("document.id", ondelete="CASCADE"), nullable=False + ) + session_id = Column( + Integer, ForeignKey("generative_session.id", ondelete="CASCADE"), nullable=False + ) + pipeline_id = Column( + Integer, ForeignKey("rag_pipeline.id", ondelete="CASCADE"), nullable=False + ) # Relationships document = relationship("Document", back_populates="pipeline_links") pipeline = relationship("RAGPipeline", back_populates="pipeline_links") session = relationship("GenerativeSession", back_populates="pipeline_links") - + __table_args__ = ( UniqueConstraint("document_id", "session_id", name="uix_document_session"), UniqueConstraint("session_id", "pipeline_id", name="uix_session_pipeline"), UniqueConstraint("document_id", "pipeline_id", name="uix_document_pipeline"), - ) \ No newline at end of file + ) From 3395e26b69bf5675518e594c625dea1733e2f746 Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 22 Oct 2025 19:42:51 -0300 Subject: [PATCH 068/218] refactor: Add optional name field to RAGPrompt model and set default prompt name in NewSessionModal --- DashAI/back/dependencies/database/models.py | 1 + DashAI/back/models/RAG/prompts/prompt.py | 58 +++++++++---------- .../RAG/NewSessionModal/NewSessionModal.jsx | 1 + 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/DashAI/back/dependencies/database/models.py b/DashAI/back/dependencies/database/models.py index 0668d53e7..c350fbcca 100644 --- a/DashAI/back/dependencies/database/models.py +++ b/DashAI/back/dependencies/database/models.py @@ -736,6 +736,7 @@ class RAGPrompt(Base): """ id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) class_name: Mapped[str] = mapped_column(String, nullable=False) + name: Mapped[str] = mapped_column(String, nullable=True) parameters: Mapped[JSON] = mapped_column(JSON, nullable=True) created: Mapped[DateTime] = mapped_column(DateTime, default=datetime.now) last_modified: Mapped[DateTime] = mapped_column( diff --git a/DashAI/back/models/RAG/prompts/prompt.py b/DashAI/back/models/RAG/prompts/prompt.py index 2c8aa4e6f..36e39e94f 100644 --- a/DashAI/back/models/RAG/prompts/prompt.py +++ b/DashAI/back/models/RAG/prompts/prompt.py @@ -1,17 +1,19 @@ from typing import Any, Dict, List -from DashAI.back.models.base_model import BaseModel from DashAI.back.core.schema_fields import BaseSchema, schema_field, string_field -from DashAI.back.dependencies.database.models import ( - RAGPrompt as PromptDBModel) +from DashAI.back.dependencies.database.models import RAGPrompt as PromptDBModel +from DashAI.back.models.base_model import BaseModel -class PromptSchema(BaseSchema): +class PromptSchema(BaseSchema): template: str = schema_field( string_field(), placeholder="", description="The prompt template with placeholders.", ) + name: str = schema_field( + string_field(), placeholder="", description="Optional name for the prompt." + ) class Prompt(BaseModel): @@ -23,32 +25,35 @@ class Prompt(BaseModel): SCHEMA = PromptSchema REQUIRED_EXTRA_KWARGS = ["db"] id: int + name: str def __init__(self, **kwargs): self.db = kwargs.pop("db") kwargs = self.validate_and_transform(kwargs) self.template = kwargs.get("template") - assert self.validate_template(self.template), "The template is missing required placeholders." + self.name = kwargs.get("name") + assert self.validate_template(self.template), ( + "The template is missing required placeholders." + ) self.class_name = self.__class__.__name__ self.params = kwargs - - stored_model = self.db.query(PromptDBModel).filter_by( - class_name = self.class_name, - parameters = self.params - ).first() + stored_model = ( + self.db.query(PromptDBModel) + .filter_by( + class_name=self.class_name, name=self.name, parameters=self.params + ) + .first() + ) if stored_model: self.id = stored_model.id else: new_model = PromptDBModel( - class_name=self.class_name, - parameters=self.params + class_name=self.class_name, name=self.name, parameters=self.params ) self.db.add(new_model) self.db.commit() self.id = new_model.id - - def load(self, **kwargs: Any) -> None: pass @@ -57,14 +62,9 @@ def save(self) -> None: @classmethod def get_metadata(cls) -> Dict[str, Any]: - if hasattr(cls, 'metadata'): - metadata = cls.metadata - else: - metadata = {} + metadata = cls.metadata if hasattr(cls, "metadata") else {} return metadata - - @classmethod def get_required_placeholders(cls) -> List[str]: """ @@ -72,19 +72,22 @@ def get_required_placeholders(cls) -> List[str]: Returns: List[str]: List of required placeholders. """ - assert hasattr(cls, 'required_placeholders'), "Subclasses must define 'required_placeholders' class attribute." + assert hasattr(cls, "required_placeholders"), ( + "Subclasses must define 'required_placeholders' class attribute." + ) return cls.required_placeholders - + def get_optional_placeholders(self) -> List[str]: """ Get the list of optional placeholders for the prompt template. Returns: List[str]: List of optional placeholders. """ - assert hasattr(self, 'optional_placeholders'), "Subclasses must define 'optional_placeholders' class attribute." + assert hasattr(self, "optional_placeholders"), ( + "Subclasses must define 'optional_placeholders' class attribute." + ) return self.optional_placeholders - @classmethod def validate_template(cls, template: str) -> bool: """ @@ -94,11 +97,7 @@ def validate_template(cls, template: str) -> bool: Returns: bool: True if the template is valid, False otherwise. """ - for placeholder in cls.required_placeholders: - if placeholder not in template: - return False - return True - + return all(placeholder in template for placeholder in cls.required_placeholders) @staticmethod def format(input: str, **kwargs: Any) -> str: @@ -111,4 +110,3 @@ def format(input: str, **kwargs: Any) -> str: str: The formatted prompt. """ raise NotImplementedError("Subclasses must implement this method.") - \ No newline at end of file diff --git a/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx b/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx index c4e4cbfc2..15cb1bd91 100644 --- a/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx +++ b/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx @@ -73,6 +73,7 @@ const defaultNewSession = { prompt_model: { component: "CustomGenerationPrompt", params: { + name: "Default Prompt", template: "Answer to this message: {input}, with the following information: {chunks}", }, From c4fec69fedb2e11e3bf9c67c8839aea9a1588abf Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 22 Oct 2025 22:14:36 -0300 Subject: [PATCH 069/218] refactor: Add optional fields for created date and last modified date in IRAGPrompt interface --- DashAI/front/src/types/ragPrompt.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/DashAI/front/src/types/ragPrompt.ts b/DashAI/front/src/types/ragPrompt.ts index 87300586d..2ea780787 100644 --- a/DashAI/front/src/types/ragPrompt.ts +++ b/DashAI/front/src/types/ragPrompt.ts @@ -1,7 +1,11 @@ export interface IRAGPrompt { id: number; class_name: string; + name?: string; + created?: string; + last_modified?: string; parameters: { template: string; + name?: string; }; } From c2119a5d427660a33eba89809b1e3432b368b611 Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 22 Oct 2025 22:14:47 -0300 Subject: [PATCH 070/218] refactor: Include name, created, and last modified fields in get_all_prompts response --- DashAI/back/api/api_v1/endpoints/generative_session.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DashAI/back/api/api_v1/endpoints/generative_session.py b/DashAI/back/api/api_v1/endpoints/generative_session.py index fef7b1880..d4d9dfffa 100644 --- a/DashAI/back/api/api_v1/endpoints/generative_session.py +++ b/DashAI/back/api/api_v1/endpoints/generative_session.py @@ -176,7 +176,10 @@ async def get_all_prompts( { "id": prompt.id, "class_name": prompt.class_name, + "name": prompt.name, "parameters": prompt.parameters, + "created": prompt.created, + "last_modified": prompt.last_modified, } ) From e484c99bf7ddf1ff34dae587247d764f10929e82 Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 22 Oct 2025 22:14:58 -0300 Subject: [PATCH 071/218] refactor: Implement TemplateModal and integrate with PromptSelectionTable for viewing templates --- .../src/components/custom/TemplateModal.jsx | 37 ++++++ .../generative/RAG/PromptSelectionTable.jsx | 109 ++++++++++++++++++ .../PromptConfigurationStep.jsx | 68 +++-------- 3 files changed, 160 insertions(+), 54 deletions(-) create mode 100644 DashAI/front/src/components/custom/TemplateModal.jsx create mode 100644 DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx diff --git a/DashAI/front/src/components/custom/TemplateModal.jsx b/DashAI/front/src/components/custom/TemplateModal.jsx new file mode 100644 index 000000000..0026600f4 --- /dev/null +++ b/DashAI/front/src/components/custom/TemplateModal.jsx @@ -0,0 +1,37 @@ +import React from "react"; +import PropTypes from "prop-types"; +import { + Dialog, + DialogTitle, + DialogContent, + DialogContentText, + DialogActions, + Button, + Typography, +} from "@mui/material"; + +export default function TemplateModal({ open, handleClose, template }) { + return ( + + Prompt Template + + + + {template} + + + + + + + + ); +} + +TemplateModal.propTypes = { + open: PropTypes.bool.isRequired, + handleClose: PropTypes.func.isRequired, + template: PropTypes.string, +}; diff --git a/DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx b/DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx new file mode 100644 index 000000000..fb570fc2a --- /dev/null +++ b/DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx @@ -0,0 +1,109 @@ +import React, { useState } from "react"; +import { Box, Paper, Tooltip, IconButton } from "@mui/material"; +import VisibilityIcon from "@mui/icons-material/Visibility"; +import { DataGrid } from "@mui/x-data-grid"; +import { formatDate } from "../../../utils"; +import TemplateModal from "../../custom/TemplateModal"; + +export default function PromptSelectionTable({ prompts = [] }) { + const [modalOpen, setModalOpen] = useState(false); + const [selectedTemplate, setSelectedTemplate] = useState(""); + + const handleViewTemplate = (template) => { + setSelectedTemplate(template); + setModalOpen(true); + }; + + const handleCloseModal = () => { + setModalOpen(false); + setSelectedTemplate(""); + }; + + const columns = React.useMemo( + () => [ + { + field: "id", + headerName: "ID", + minWidth: 50, + flex: 0.3, + editable: false, + }, + { + field: "name", + headerName: "Name", + minWidth: 140, + flex: 1, + editable: false, + }, + { + field: "class_name", + headerName: "Type", + minWidth: 140, + flex: 1, + editable: false, + }, + { + field: "created", + headerName: "Created", + minWidth: 140, + flex: 1, + editable: false, + valueGetter: (value) => formatDate(value), + }, + { + field: "last_modified", + headerName: "Edited", + minWidth: 140, + flex: 1, + editable: false, + valueGetter: (value) => formatDate(value), + }, + { + field: "actions", + type: "actions", + headerName: "Actions", + minWidth: 80, + flex: 0.4, + getActions: (params) => [ + + + handleViewTemplate(params.row.parameters?.template || "") + } + > + + + , + ], + }, + ], + [], + ); + + return ( + + + + + + + ); +} diff --git a/DashAI/front/src/pages/generative/RAG/NewSessionModal/PromptConfigurationStep.jsx b/DashAI/front/src/pages/generative/RAG/NewSessionModal/PromptConfigurationStep.jsx index 1ec96b4d6..d760ccb93 100644 --- a/DashAI/front/src/pages/generative/RAG/NewSessionModal/PromptConfigurationStep.jsx +++ b/DashAI/front/src/pages/generative/RAG/NewSessionModal/PromptConfigurationStep.jsx @@ -1,58 +1,18 @@ -import React, { useEffect } from "react"; -import { Box, Typography } from "@mui/material"; -import PropTypes from "prop-types"; +import { useEffect, useState } from "react"; +import PromptSelectionTable from "../../../../components/generative/RAG/PromptSelectionTable"; +import { getRAGPrompts } from "../../../../api/rag"; + +export default function PromptConfigurationStep({ setNextEnabled }) { + const [prompts, setPrompts] = useState([]); + const [loading, setLoading] = useState(true); -export default function PromptConfigurationStep({ - sessionData, - setSessionData, - setNextEnabled, -}) { - // Set this step as always valid useEffect(() => { - if (setNextEnabled) { - setNextEnabled(true); - } - }, [setNextEnabled]); + setNextEnabled && setNextEnabled(true); + getRAGPrompts() + .then((data) => setPrompts(data)) + .catch(() => setPrompts([])) + .finally(() => setLoading(false)); + }, []); - return ( - - - Prompt Configuration - - - This step is currently under development. The default prompt template - will be used. - - - - Default template: - - - Answer to this message: {"{input}"}, with the following information:{" "} - {"{chunks}"} - - - - ); + return ; } - -PromptConfigurationStep.propTypes = { - sessionData: PropTypes.object.isRequired, - setSessionData: PropTypes.func.isRequired, - setNextEnabled: PropTypes.func, -}; From 10a91b96d0570c27946365d3f0ab0fe3b39462b7 Mon Sep 17 00:00:00 2001 From: Creylay Date: Wed, 22 Oct 2025 23:52:09 -0300 Subject: [PATCH 072/218] feat: Add NewPromptModal component and integrate with PromptSelectionTable for creating new prompts --- .../generative/RAG/NewPromptModal.jsx | 52 ++++++++++++++ .../generative/RAG/PromptSelectionTable.jsx | 70 +++++++++++++++++-- .../PromptConfigurationStep.jsx | 36 +++++++++- 3 files changed, 150 insertions(+), 8 deletions(-) create mode 100644 DashAI/front/src/components/generative/RAG/NewPromptModal.jsx diff --git a/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx b/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx new file mode 100644 index 000000000..ae2161315 --- /dev/null +++ b/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx @@ -0,0 +1,52 @@ +import React from "react"; + +import { + Dialog, + DialogTitle, + DialogContent, + DialogActions, + Button, + Typography, + Grid, + IconButton, +} from "@mui/material"; +import CloseIcon from "@mui/icons-material/Close"; + +export default function NewPromptModal({ open, handleClose }) { + return ( + + + + + + Create New Prompt + + + + + + + + + + + + Hola mundo + + + + + + + + ); +} diff --git a/DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx b/DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx index fb570fc2a..f8a81bbb9 100644 --- a/DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx +++ b/DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx @@ -1,13 +1,30 @@ import React, { useState } from "react"; -import { Box, Paper, Tooltip, IconButton } from "@mui/material"; +import { + Box, + Paper, + Tooltip, + IconButton, + Button, + Grid, + Typography, +} from "@mui/material"; +import { AddCircleOutline as AddIcon } from "@mui/icons-material"; import VisibilityIcon from "@mui/icons-material/Visibility"; import { DataGrid } from "@mui/x-data-grid"; import { formatDate } from "../../../utils"; import TemplateModal from "../../custom/TemplateModal"; +import NewPromptModal from "./NewPromptModal"; -export default function PromptSelectionTable({ prompts = [] }) { +export default function PromptSelectionTable({ + prompts = [], + loading = false, + rowSelectionModel = [], + onRowSelectionModelChange, + showTableTitle = false, +}) { const [modalOpen, setModalOpen] = useState(false); const [selectedTemplate, setSelectedTemplate] = useState(""); + const [newPromptModalOpen, setNewPromptModalOpen] = useState(false); const handleViewTemplate = (template) => { setSelectedTemplate(template); @@ -82,8 +99,45 @@ export default function PromptSelectionTable({ prompts = [] }) { ); return ( - - + + {showTableTitle && ( + + + Prompts + + + + )} + {!showTableTitle && ( + + + + )} + + setNewPromptModalOpen(false)} + /> ); diff --git a/DashAI/front/src/pages/generative/RAG/NewSessionModal/PromptConfigurationStep.jsx b/DashAI/front/src/pages/generative/RAG/NewSessionModal/PromptConfigurationStep.jsx index d760ccb93..a507cb99e 100644 --- a/DashAI/front/src/pages/generative/RAG/NewSessionModal/PromptConfigurationStep.jsx +++ b/DashAI/front/src/pages/generative/RAG/NewSessionModal/PromptConfigurationStep.jsx @@ -2,17 +2,47 @@ import { useEffect, useState } from "react"; import PromptSelectionTable from "../../../../components/generative/RAG/PromptSelectionTable"; import { getRAGPrompts } from "../../../../api/rag"; -export default function PromptConfigurationStep({ setNextEnabled }) { +export default function PromptConfigurationStep({ + setNextEnabled, + sessionData, + setSessionData, +}) { const [prompts, setPrompts] = useState([]); const [loading, setLoading] = useState(true); + const [selectedPromptId, setSelectedPromptId] = useState([]); useEffect(() => { - setNextEnabled && setNextEnabled(true); getRAGPrompts() .then((data) => setPrompts(data)) .catch(() => setPrompts([])) .finally(() => setLoading(false)); }, []); - return ; + useEffect(() => { + setNextEnabled(true); + if (selectedPromptId.length > 0) { + const prompt = prompts.find((p) => p.id === selectedPromptId[0]); + if (prompt) { + setSessionData((prev) => ({ + ...prev, + parameters: { + ...prev.parameters, + prompt_model: { + component: prompt.class_name, + params: prompt.parameters, + }, + }, + })); + } + } + }, [selectedPromptId, prompts, setNextEnabled, setSessionData]); + + return ( + + ); } From 569cc188e8c3218eebe3eae8f18f8903b5e02270 Mon Sep 17 00:00:00 2001 From: sofiachavezb Date: Thu, 23 Oct 2025 00:10:59 -0300 Subject: [PATCH 073/218] Fixes --- DashAI/back/dependencies/database/utils.py | 2 +- .../RAG/embeddings/dense/fasttext_embedding.py | 3 +-- .../pages/plugins/components/PluginsTab.jsx | 2 +- .../chunk_to_doc_id_map | Bin 292646 -> 0 bytes .../tfidf_matrix | Bin 399742 -> 0 bytes .../vectorizer | Bin 179400 -> 0 bytes 6 files changed, 3 insertions(+), 4 deletions(-) delete mode 100644 StoredRetrievers/tfidf_retriever_4347afb95646b45e61cecd2c1f9843a2fadb1581a5320fff274602f196f73b3b_8a335fbf2b6f7ec123b9ddb885a8090cb16e035431fa30d7c63832dd8a728214/chunk_to_doc_id_map delete mode 100644 StoredRetrievers/tfidf_retriever_4347afb95646b45e61cecd2c1f9843a2fadb1581a5320fff274602f196f73b3b_8a335fbf2b6f7ec123b9ddb885a8090cb16e035431fa30d7c63832dd8a728214/tfidf_matrix delete mode 100644 StoredRetrievers/tfidf_retriever_4347afb95646b45e61cecd2c1f9843a2fadb1581a5320fff274602f196f73b3b_8a335fbf2b6f7ec123b9ddb885a8090cb16e035431fa30d7c63832dd8a728214/vectorizer diff --git a/DashAI/back/dependencies/database/utils.py b/DashAI/back/dependencies/database/utils.py index e9bbbd991..37d059a92 100644 --- a/DashAI/back/dependencies/database/utils.py +++ b/DashAI/back/dependencies/database/utils.py @@ -60,7 +60,7 @@ def add_plugin_to_db( name=raw_plugin.name, author=raw_plugin.author, installed_version=raw_plugin.installed_version, - lastest_version=raw_plugin.lastest_version, + latest_version=raw_plugin.lastest_version, summary=raw_plugin.summary, description=raw_plugin.description, description_content_type=raw_plugin.description_content_type, diff --git a/DashAI/back/models/RAG/embeddings/dense/fasttext_embedding.py b/DashAI/back/models/RAG/embeddings/dense/fasttext_embedding.py index e0061aa69..17217b153 100644 --- a/DashAI/back/models/RAG/embeddings/dense/fasttext_embedding.py +++ b/DashAI/back/models/RAG/embeddings/dense/fasttext_embedding.py @@ -52,8 +52,7 @@ def __init__(self, **kwargs): def load(self): """Load the FastText model.""" - model_name = self.model_name.split("/")[-1] - model_path = hf_hub_download(repo_id=self.model_name, filename=f"{model_name}.bin") + model_path = hf_hub_download(repo_id=self.model_name, filename="model.bin") self.model = fasttext.load_model(model_path) def save(self): diff --git a/DashAI/front/src/pages/plugins/components/PluginsTab.jsx b/DashAI/front/src/pages/plugins/components/PluginsTab.jsx index 9a3bfda0f..6158828f5 100644 --- a/DashAI/front/src/pages/plugins/components/PluginsTab.jsx +++ b/DashAI/front/src/pages/plugins/components/PluginsTab.jsx @@ -7,7 +7,7 @@ import { Link } from "react-router-dom"; import usePluginsTab from "../hooks/usePluginsTab"; import { Update as UpdateIcon } from "@mui/icons-material"; import { updatePluginsDBFromPypi as updatePluginsFromPypi } from "../../../api/plugins"; - +import { enqueueSnackbar } from "notistack"; /** * component to display plugins main tabs * @param {boolean} refreshPluginsFlag diff --git a/StoredRetrievers/tfidf_retriever_4347afb95646b45e61cecd2c1f9843a2fadb1581a5320fff274602f196f73b3b_8a335fbf2b6f7ec123b9ddb885a8090cb16e035431fa30d7c63832dd8a728214/chunk_to_doc_id_map b/StoredRetrievers/tfidf_retriever_4347afb95646b45e61cecd2c1f9843a2fadb1581a5320fff274602f196f73b3b_8a335fbf2b6f7ec123b9ddb885a8090cb16e035431fa30d7c63832dd8a728214/chunk_to_doc_id_map deleted file mode 100644 index bc08e600373ec72b1c81c04b947f4f9b1d91c068..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 292646 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 =Dl=A3zgD61T$Qy#<{9aW7g+w|MEI2XxX@TXK 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 TJ+&wXC6;H&dRtm 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

5A8dQ{5RTTcJjeRCm=A$+lhc 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 Xv*q1{kp(tJoM4aE_79lE`q=*m%P;A~ diff --git a/StoredRetrievers/tfidf_retriever_4347afb95646b45e61cecd2c1f9843a2fadb1581a5320fff274602f196f73b3b_8a335fbf2b6f7ec123b9ddb885a8090cb16e035431fa30d7c63832dd8a728214/tfidf_matrix b/StoredRetrievers/tfidf_retriever_4347afb95646b45e61cecd2c1f9843a2fadb1581a5320fff274602f196f73b3b_8a335fbf2b6f7ec123b9ddb885a8090cb16e035431fa30d7c63832dd8a728214/tfidf_matrix deleted file mode 100644 index e8c3acc49ac4b2cbd7b412872bd5174d245d7659..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 399742 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

7TU_*8XRe91csbVm+eHrQSV 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 diff --git a/StoredRetrievers/tfidf_retriever_4347afb95646b45e61cecd2c1f9843a2fadb1581a5320fff274602f196f73b3b_8a335fbf2b6f7ec123b9ddb885a8090cb16e035431fa30d7c63832dd8a728214/vectorizer b/StoredRetrievers/tfidf_retriever_4347afb95646b45e61cecd2c1f9843a2fadb1581a5320fff274602f196f73b3b_8a335fbf2b6f7ec123b9ddb885a8090cb16e035431fa30d7c63832dd8a728214/vectorizer deleted file mode 100644 index 84b56dd89586fc049f49d6d2104adb0bda29ee8a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 179400 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 From 2cab302ec2d3a8b780ff63aca013482682600631 Mon Sep 17 00:00:00 2001 From: sofiachavezb Date: Thu, 23 Oct 2025 00:42:28 -0300 Subject: [PATCH 074/218] added a fixed prompt to use while prompt configuration is developed --- DashAI/back/api/api_v1/endpoints/generative_session.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/DashAI/back/api/api_v1/endpoints/generative_session.py b/DashAI/back/api/api_v1/endpoints/generative_session.py index 3c622706f..83ea05440 100644 --- a/DashAI/back/api/api_v1/endpoints/generative_session.py +++ b/DashAI/back/api/api_v1/endpoints/generative_session.py @@ -87,6 +87,14 @@ async def upload_generative_session( ) documents_ids.append(document.id) + if "prompt_model" not in params.parameters: + params.parameters["prompt_model"] = { + 'component': 'CustomGenerationPrompt', + 'params': { + 'template': """Answer to this question\n{input}\nUsing the following documents as context:\n{chunks}\nThe chat history is:\n{history}""" + } + } + params.parameters["documents"] = documents_ids # Continue with the session creation From 11c848bd38a1b03d391fc07b25e2268c9fd43261 Mon Sep 17 00:00:00 2001 From: sofiachavezb Date: Thu, 23 Oct 2025 00:58:09 -0300 Subject: [PATCH 075/218] mini fix in documents table --- .../src/components/generative/RAG/DocumentSelectionTable.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DashAI/front/src/components/generative/RAG/DocumentSelectionTable.jsx b/DashAI/front/src/components/generative/RAG/DocumentSelectionTable.jsx index 883090ede..17a490bdf 100644 --- a/DashAI/front/src/components/generative/RAG/DocumentSelectionTable.jsx +++ b/DashAI/front/src/components/generative/RAG/DocumentSelectionTable.jsx @@ -64,7 +64,7 @@ export default function DocumentSelectionTable({ flex: 0.5, editable: false, valueGetter: (value, row) => { - return row.optional_metadata?.last_modified + return row?.optional_metadata?.last_modified ? formatDate(row.optional_metadata.last_modified) : "N/A"; }, From 231f81f08a01ab44f2c3f3707185e71b3134bc34 Mon Sep 17 00:00:00 2001 From: Creylay Date: Thu, 23 Oct 2025 01:12:43 -0300 Subject: [PATCH 076/218] feat: Add prompt type selection and template loading in NewPromptModal --- DashAI/front/src/api/rag.ts | 15 ++++ .../generative/RAG/NewPromptModal.jsx | 76 +++++++++++++++++-- 2 files changed, 86 insertions(+), 5 deletions(-) diff --git a/DashAI/front/src/api/rag.ts b/DashAI/front/src/api/rag.ts index 5a819acf9..4e23bf99a 100644 --- a/DashAI/front/src/api/rag.ts +++ b/DashAI/front/src/api/rag.ts @@ -232,3 +232,18 @@ export const getRAGPrompts = async (): Promise => { } return response.data; }; + +export const getGenerationPromptChildren = async (): Promise => { + const response = await api.get( + "/v1/component/GenerationPrompt/children", + { + params: { recursive: false }, + }, + ); + if (response.status !== 200) { + throw new Error( + `Failed to fetch GenerationPrompt children: ${response.statusText}`, + ); + } + return response.data; +}; diff --git a/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx b/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx index ae2161315..05e4b39a8 100644 --- a/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx +++ b/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx @@ -1,5 +1,5 @@ import React from "react"; - +import CloseIcon from "@mui/icons-material/Close"; import { Dialog, DialogTitle, @@ -9,10 +9,46 @@ import { Typography, Grid, IconButton, + FormControl, + InputLabel, + Select, + MenuItem, } from "@mui/material"; -import CloseIcon from "@mui/icons-material/Close"; + +import TextField from "@mui/material/TextField"; + +import { getGenerationPromptChildren } from "../../../api/rag"; export default function NewPromptModal({ open, handleClose }) { + const [promptTypes, setPromptTypes] = React.useState([]); + const [selectedPromptType, setSelectedPromptType] = React.useState(""); + const [promptName, setPromptName] = React.useState(""); + const [promptTemplate, setPromptTemplate] = React.useState(""); // <-- NUEVO + + React.useEffect(() => { + if (open) { + getGenerationPromptChildren() + .then((data) => setPromptTypes(data)) + .catch(() => setPromptTypes([])); + } + }, [open]); + + // MODIFICADO + const handlePromptTypeChange = (event) => { + const typeName = event.target.value; + setSelectedPromptType(typeName); + const selectedType = promptTypes.find((type) => type.name === typeName); + if ( + selectedType && + selectedType.metadata && + selectedType.metadata.template + ) { + setPromptTemplate(selectedType.metadata.template); + } else { + setPromptTemplate(""); + } + }; + return (

- - Hola mundo - + setPromptName(e.target.value)} + sx={{ mt: 2 }} + /> + + + Prompt Type + + + setPromptTemplate(e.target.value)} + sx={{ mt: 2 }} + /> From 9165d95bf131d68fedaf5d60ec03853f6c7e00dc Mon Sep 17 00:00:00 2001 From: sofiachavezb Date: Thu, 23 Oct 2025 01:17:46 -0300 Subject: [PATCH 077/218] model name typo fixed --- DashAI/back/models/hugging_face/qwen_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DashAI/back/models/hugging_face/qwen_model.py b/DashAI/back/models/hugging_face/qwen_model.py index d7f7fbd98..95866ebad 100644 --- a/DashAI/back/models/hugging_face/qwen_model.py +++ b/DashAI/back/models/hugging_face/qwen_model.py @@ -33,7 +33,7 @@ class QwenSchema(BaseSchema): enum=[ "Qwen/Qwen2.5-0.5B-Instruct-GGUF", "Qwen/Qwen2.5-1.5B-Instruct-GGUF", - "Qwen/Qwen3-4B-GGUF ", + "Qwen/Qwen3-4B-GGUF", ] ), placeholder="Qwen/Qwen2.5-1.5B-Instruct-GGUF", From 006608a468cf7d615f1e8f1d18b990143a96c21d Mon Sep 17 00:00:00 2001 From: Creylay Date: Thu, 23 Oct 2025 10:36:06 -0300 Subject: [PATCH 078/218] feat: Add endpoint to create new RAGPrompt entries in the database --- .../api_v1/endpoints/generative_session.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/DashAI/back/api/api_v1/endpoints/generative_session.py b/DashAI/back/api/api_v1/endpoints/generative_session.py index d4d9dfffa..60d353130 100644 --- a/DashAI/back/api/api_v1/endpoints/generative_session.py +++ b/DashAI/back/api/api_v1/endpoints/generative_session.py @@ -9,6 +9,7 @@ from DashAI.back.api.api_v1.schemas.generative_session_params import ( GenerativeSessionParams, ) +from DashAI.back.api.api_v1.schemas.rag_prompt import RAGPromptSchema from DashAI.back.dependencies.database.models import ( Document, GenerativeProcess, @@ -26,6 +27,24 @@ log = logging.getLogger(__name__) +@router.post("/prompts", status_code=status.HTTP_201_CREATED) +async def create_rag_prompt( + prompt: RAGPromptSchema, + session_factory: sessionmaker = Depends(lambda: di["session_factory"]), +): + """Create a new RAGPrompt entry in the database.""" + with session_factory() as db: + new_prompt = RAGPrompt( + class_name=prompt.class_name, + name=prompt.name, + parameters=prompt.parameters, + ) + db.add(new_prompt) + db.commit() + db.refresh(new_prompt) + return {"id": new_prompt.id} + + @router.post("/", status_code=status.HTTP_201_CREATED) async def upload_generative_session( params: GenerativeSessionParams, From 4e89d3c90bfc63a626b10b0e08955e6e810efd90 Mon Sep 17 00:00:00 2001 From: Creylay Date: Thu, 23 Oct 2025 10:36:26 -0300 Subject: [PATCH 079/218] feat: Add RAGPromptSchema model for prompt data validation --- DashAI/back/api/api_v1/schemas/rag_prompt.py | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 DashAI/back/api/api_v1/schemas/rag_prompt.py diff --git a/DashAI/back/api/api_v1/schemas/rag_prompt.py b/DashAI/back/api/api_v1/schemas/rag_prompt.py new file mode 100644 index 000000000..8c1665f39 --- /dev/null +++ b/DashAI/back/api/api_v1/schemas/rag_prompt.py @@ -0,0 +1,9 @@ +from typing import Any, Dict, Optional + +from pydantic import BaseModel + + +class RAGPromptSchema(BaseModel): + class_name: str + name: str + parameters: Optional[Dict[str, Any]] = None From e29fe848fb81261ef64876fc2b1b31910c58a4c4 Mon Sep 17 00:00:00 2001 From: Creylay Date: Thu, 23 Oct 2025 10:36:43 -0300 Subject: [PATCH 080/218] feat: Implement createRAGPrompt function for creating new RAG prompts --- DashAI/front/src/api/rag.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/DashAI/front/src/api/rag.ts b/DashAI/front/src/api/rag.ts index 4e23bf99a..75e6cc6bb 100644 --- a/DashAI/front/src/api/rag.ts +++ b/DashAI/front/src/api/rag.ts @@ -6,7 +6,18 @@ import { IComponent } from "../types/component"; import { IRAGPrompt } from "../types/ragPrompt"; import { getChildComponents } from "./component"; -// Fetch all RAG sessions +export const createRAGPrompt = async (prompt: { + class_name: string; + name: string; + parameters?: Record; +}): Promise<{ id: number }> => { + const response = await api.post("/v1/generative-session/prompts", prompt); + if (response.status !== 201) { + throw new Error(`Failed to create RAG prompt: ${response.statusText}`); + } + return response.data; +}; + export const getRAGSessions = async (): Promise => { const response = await api.get("/v1/generative-session/"); if (response.status !== 200) { From b97da26bc9c720a64dd3664eddd369abde30a4ca Mon Sep 17 00:00:00 2001 From: Creylay Date: Thu, 23 Oct 2025 10:39:09 -0300 Subject: [PATCH 081/218] feat: Update TemplateModal title and integrate prompt creation in NewPromptModal with prompt fetching in PromptSelectionTable --- .../src/components/custom/TemplateModal.jsx | 2 +- .../generative/RAG/NewPromptModal.jsx | 20 ++++++++++++++++--- .../generative/RAG/PromptSelectionTable.jsx | 20 ++++++++++++++++++- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/DashAI/front/src/components/custom/TemplateModal.jsx b/DashAI/front/src/components/custom/TemplateModal.jsx index 0026600f4..5c53fd0c5 100644 --- a/DashAI/front/src/components/custom/TemplateModal.jsx +++ b/DashAI/front/src/components/custom/TemplateModal.jsx @@ -13,7 +13,7 @@ import { export default function TemplateModal({ open, handleClose, template }) { return ( - Prompt Template + Prompt diff --git a/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx b/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx index 05e4b39a8..ef4f6e5bd 100644 --- a/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx +++ b/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx @@ -17,9 +17,9 @@ import { import TextField from "@mui/material/TextField"; -import { getGenerationPromptChildren } from "../../../api/rag"; +import { getGenerationPromptChildren, createRAGPrompt } from "../../../api/rag"; -export default function NewPromptModal({ open, handleClose }) { +export default function NewPromptModal({ open, handleClose, onPromptCreated }) { const [promptTypes, setPromptTypes] = React.useState([]); const [selectedPromptType, setSelectedPromptType] = React.useState(""); const [promptName, setPromptName] = React.useState(""); @@ -109,7 +109,21 @@ export default function NewPromptModal({ open, handleClose }) { - diff --git a/DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx b/DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx index f8a81bbb9..394fd7d51 100644 --- a/DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx +++ b/DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx @@ -14,6 +14,7 @@ import { DataGrid } from "@mui/x-data-grid"; import { formatDate } from "../../../utils"; import TemplateModal from "../../custom/TemplateModal"; import NewPromptModal from "./NewPromptModal"; +import { getRAGPrompts } from "../../../api/rag"; export default function PromptSelectionTable({ prompts = [], @@ -25,6 +26,15 @@ export default function PromptSelectionTable({ const [modalOpen, setModalOpen] = useState(false); const [selectedTemplate, setSelectedTemplate] = useState(""); const [newPromptModalOpen, setNewPromptModalOpen] = useState(false); + const [promptRows, setPromptRows] = useState([]); + React.useEffect(() => { + async function fetchPrompts() { + const initialPrompts = await getRAGPrompts(); + initialPrompts.sort((a, b) => new Date(b.created) - new Date(a.created)); + setPromptRows(initialPrompts); + } + fetchPrompts(); + }, []); const handleViewTemplate = (template) => { setSelectedTemplate(template); @@ -98,6 +108,13 @@ export default function PromptSelectionTable({ [], ); + const handlePromptCreated = async () => { + const updatedPrompts = await getRAGPrompts(); + updatedPrompts.sort((a, b) => new Date(b.created) - new Date(a.created)); + setPromptRows(updatedPrompts); + setNewPromptModalOpen(false); + }; + return ( {showTableTitle && ( @@ -139,7 +156,7 @@ export default function PromptSelectionTable({ )} setNewPromptModalOpen(false)} + onPromptCreated={handlePromptCreated} /> From f822d290bfe77e3445554f2a746ccaf9d9cac961 Mon Sep 17 00:00:00 2001 From: Creylay Date: Thu, 23 Oct 2025 10:50:31 -0300 Subject: [PATCH 082/218] feat: Update prompt selection logic to set next step enabled state based on selected prompt --- .../src/components/generative/RAG/PromptSelectionTable.jsx | 3 +++ .../generative/RAG/NewSessionModal/PromptConfigurationStep.jsx | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx b/DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx index 394fd7d51..9fd0778bf 100644 --- a/DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx +++ b/DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx @@ -112,6 +112,9 @@ export default function PromptSelectionTable({ const updatedPrompts = await getRAGPrompts(); updatedPrompts.sort((a, b) => new Date(b.created) - new Date(a.created)); setPromptRows(updatedPrompts); + if (updatedPrompts.length > 0 && onRowSelectionModelChange) { + onRowSelectionModelChange([updatedPrompts[0].id]); + } setNewPromptModalOpen(false); }; diff --git a/DashAI/front/src/pages/generative/RAG/NewSessionModal/PromptConfigurationStep.jsx b/DashAI/front/src/pages/generative/RAG/NewSessionModal/PromptConfigurationStep.jsx index a507cb99e..fd2c89cce 100644 --- a/DashAI/front/src/pages/generative/RAG/NewSessionModal/PromptConfigurationStep.jsx +++ b/DashAI/front/src/pages/generative/RAG/NewSessionModal/PromptConfigurationStep.jsx @@ -19,7 +19,7 @@ export default function PromptConfigurationStep({ }, []); useEffect(() => { - setNextEnabled(true); + setNextEnabled(selectedPromptId.length > 0); if (selectedPromptId.length > 0) { const prompt = prompts.find((p) => p.id === selectedPromptId[0]); if (prompt) { From 24993fc0a57be2be4d5c0ee57e9bb0c6d79fa2b6 Mon Sep 17 00:00:00 2001 From: sofiachavezb Date: Thu, 23 Oct 2025 17:52:59 -0300 Subject: [PATCH 083/218] Prompt instantiation using db ids --- .../api_v1/endpoints/generative_session.py | 52 ++++++++++++++++++- DashAI/back/models/RAG/RAG_pipeline.py | 30 +++++++---- .../augmentation/augmentation_prompt.py | 3 ++ .../custom_augmentation_prompt.py | 2 +- .../generation/custom_generation_prompt.py | 2 +- .../default_QnA_generation_prompt.py | 3 +- .../generation/default_generation_prompt.py | 3 +- DashAI/back/models/RAG/prompts/prompt.py | 29 +---------- DashAI/front/src/api/rag.ts | 11 ++-- .../generative/RAG/NewPromptModal.jsx | 5 +- .../generative/RAG/PromptSelectionTable.jsx | 4 +- .../RAG/NewSessionModal/NewSessionModal.jsx | 23 +++----- .../PromptConfigurationStep.jsx | 5 +- DashAI/front/src/types/ragPrompt.ts | 3 +- 14 files changed, 97 insertions(+), 78 deletions(-) diff --git a/DashAI/back/api/api_v1/endpoints/generative_session.py b/DashAI/back/api/api_v1/endpoints/generative_session.py index 60d353130..90ef66f37 100644 --- a/DashAI/back/api/api_v1/endpoints/generative_session.py +++ b/DashAI/back/api/api_v1/endpoints/generative_session.py @@ -9,6 +9,7 @@ from DashAI.back.api.api_v1.schemas.generative_session_params import ( GenerativeSessionParams, ) +from DashAI.back.models.RAG import DefaultGenerationPrompt, DefaultQnAGenerationPrompt, DefaultAugmentationPrompt from DashAI.back.api.api_v1.schemas.rag_prompt import RAGPromptSchema from DashAI.back.dependencies.database.models import ( Document, @@ -19,7 +20,8 @@ RAGPrompt, ) from DashAI.back.dependencies.registry import ComponentRegistry -from DashAI.back.models import BaseGenerativeModel +from DashAI.back.models.RAG import Prompt +from DashAI.back.models.base_generative_model import BaseGenerativeModel from DashAI.back.tasks import BaseGenerativeTask from DashAI.back.tasks.RAG_task import RAGTask @@ -30,10 +32,30 @@ @router.post("/prompts", status_code=status.HTTP_201_CREATED) async def create_rag_prompt( prompt: RAGPromptSchema, + component_registry: ComponentRegistry = Depends(lambda: di["component_registry"]), session_factory: sessionmaker = Depends(lambda: di["session_factory"]), ): """Create a new RAGPrompt entry in the database.""" with session_factory() as db: + prompt_class_name = prompt.class_name + if not prompt_class_name in component_registry: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=f"Component {prompt_class_name} is not registered.", + ) + prompt_component = component_registry[prompt_class_name] + prompt_class: Prompt = prompt_component["class"] + if not issubclass(prompt_class, Prompt): + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=f"Component {prompt_class_name} is not a valid Prompt subclass.", + ) + template_validation = prompt_class.validate_template(prompt.parameters["template"]) + if not template_validation: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=f"Invalid template for prompt {prompt.class_name}. Required tokens are: {prompt_class.get_required_placeholders()}", + ) new_prompt = RAGPrompt( class_name=prompt.class_name, name=prompt.name, @@ -189,6 +211,34 @@ async def get_all_prompts( try: prompts = db.query(RAGPrompt).all() + if len(prompts) == 0: + default_generation_prompt = RAGPrompt( + class_name=DefaultGenerationPrompt.__name__, + name="Default Generation Prompt", + parameters={ + 'template': DefaultAugmentationPrompt.template + }, + ) + default_qa_prompt = RAGPrompt( + class_name=DefaultQnAGenerationPrompt.__name__, + name="Default QnA Prompt", + parameters={ + 'template': DefaultQnAGenerationPrompt.template + }, + ) + default_augmentation_prompt = RAGPrompt( + class_name=DefaultAugmentationPrompt.__name__, + name="Default Augmentation Prompt", + parameters={ + 'template': DefaultAugmentationPrompt.template + }, + ) + db.add(default_generation_prompt) + db.add(default_qa_prompt) + db.add(default_augmentation_prompt) + db.commit() + prompts = db.query(RAGPrompt).all() + prompt_responses = [] for prompt in prompts: prompt_responses.append( diff --git a/DashAI/back/models/RAG/RAG_pipeline.py b/DashAI/back/models/RAG/RAG_pipeline.py index 5284a1b29..9e0f7546a 100644 --- a/DashAI/back/models/RAG/RAG_pipeline.py +++ b/DashAI/back/models/RAG/RAG_pipeline.py @@ -13,6 +13,7 @@ from DashAI.back.dependencies.database.models import ( Document as DBDocument, RAGPipeline as DBPipeline, + RAGPrompt as PromptDBModel ) from DashAI.back.dependencies.registry.component_registry import ComponentRegistry @@ -92,10 +93,10 @@ class RAGPipelineSchema(BaseSchema): description="Text generation model used in the RAG pipeline." ) # type: ignore - prompt_model: schema_field( - component_field(parent="Prompt"), - placeholder={"component": "DefaultGenerationPrompt", "params": {}}, - description="Prompt template used to format the input for the generation model." + prompt_id: schema_field( + int_field(gt=0), + placeholder=None, + description="Database ID of the prompt template to be used in the RAG pipeline." ) # type: ignore class RAGPipeline(BaseGenerativeModel): @@ -150,15 +151,25 @@ def __init__(self, **kwargs: Any) -> None: self.pipeline_db_model = None self.pipeline_id = None self.documents_ids: List[int] = kwargs.pop("documents") + self.prompt_db_id: int = kwargs.pop("prompt_id") + prompt_db_model: PromptDBModel = self.db.query(PromptDBModel).filter_by(id=self.prompt_db_id).first() + if not prompt_db_model: + raise RAGPipelineInitializationError(f"Prompt with ID {self.prompt_db_id} not found in the database.") + prompt_model_args = { + 'component': prompt_db_model.class_name, + 'params': prompt_db_model.parameters + } + self.documents = self.load_documents_from_db(documents_ids=self.documents_ids) self.validate_params(kwargs) - try: + try: + config = { 'chunking_model': kwargs.pop('chunking_model'), 'retriever_model': kwargs.pop('retriever_model'), 'generation_model': kwargs.pop('generation_model'), - 'prompt_model': kwargs.pop('prompt_model'), + 'prompt_model': prompt_model_args } except KeyError as e: raise RAGPipelineParametersError(f"Missing required parameter: {str(e)}") @@ -171,7 +182,6 @@ def __init__(self, **kwargs: Any) -> None: self.retriever_id = self.retriever.retriever_db_model.id self.llm_model = self.init_component(config["generation_model"]) self.prompt_model = self.init_component(config["prompt_model"]) - self.prompt_db_id = self.prompt_model.id self.retrieval_algorithm = "SINGLE_INTERACTION" print("RAG pipeline initialized") @@ -179,14 +189,14 @@ def validate_params( self, params: dict): """Validate RAG pipeline parameters.""" - required_keys = ["chunking_model", "retriever_model", "generation_model", "prompt_model"] + required_keys = ["chunking_model", "retriever_model", "generation_model"] for key in required_keys: if key not in params: raise RAGPipelineParametersError(f"Missing required parameter '{key}' in RAG pipeline configuration") # Validate model components - for model in ["chunking_model", "retriever_model", "generation_model", "prompt_model"]: + for model in ["chunking_model", "retriever_model", "generation_model"]: args = params[model] if "component" not in args: raise RAGPipelineParametersError(f"Missing 'component' field in '{model}' configuration") @@ -194,8 +204,6 @@ def validate_params( raise RAGPipelineParametersError(f"Missing 'params' field in '{model}' configuration") if args["component"] not in self.component_registry: raise RAGPipelineParametersError(f"No components registered for type '{model}'") - if "Custom" in params["prompt_model"]["component"] and "template" not in params["prompt_model"]["params"]: - raise RAGPipelineParametersError("Custom prompt model requires a 'template' parameter in its configuration") def single_interaction( self, diff --git a/DashAI/back/models/RAG/prompts/augmentation/augmentation_prompt.py b/DashAI/back/models/RAG/prompts/augmentation/augmentation_prompt.py index 060e70179..ccaf245e5 100644 --- a/DashAI/back/models/RAG/prompts/augmentation/augmentation_prompt.py +++ b/DashAI/back/models/RAG/prompts/augmentation/augmentation_prompt.py @@ -11,6 +11,9 @@ class AugmentationPrompt(Prompt): required_placeholders = ["{input}", "{n_search_terms}"] optional_placeholders = ["{history}"] + def __init__(self, **kwargs: Any): + self.template = kwargs.pop("template") + def format( self, input: str, diff --git a/DashAI/back/models/RAG/prompts/augmentation/custom_augmentation_prompt.py b/DashAI/back/models/RAG/prompts/augmentation/custom_augmentation_prompt.py index 2a4888130..052487d13 100644 --- a/DashAI/back/models/RAG/prompts/augmentation/custom_augmentation_prompt.py +++ b/DashAI/back/models/RAG/prompts/augmentation/custom_augmentation_prompt.py @@ -23,7 +23,7 @@ class CustomAugmentationPrompt(AugmentationPrompt): def __init__(self, **kwargs): - super().__init__(**kwargs) + self.template = kwargs.pop("template") def format( diff --git a/DashAI/back/models/RAG/prompts/generation/custom_generation_prompt.py b/DashAI/back/models/RAG/prompts/generation/custom_generation_prompt.py index 28fe2305d..9efff58b6 100644 --- a/DashAI/back/models/RAG/prompts/generation/custom_generation_prompt.py +++ b/DashAI/back/models/RAG/prompts/generation/custom_generation_prompt.py @@ -21,7 +21,7 @@ class CustomGenerationPrompt(GenerationPrompt): def __init__(self, **kwargs: Any): - super().__init__(**kwargs) + self.template = kwargs.pop("template") def format( self, diff --git a/DashAI/back/models/RAG/prompts/generation/default_QnA_generation_prompt.py b/DashAI/back/models/RAG/prompts/generation/default_QnA_generation_prompt.py index d6735b137..69bb3f46c 100644 --- a/DashAI/back/models/RAG/prompts/generation/default_QnA_generation_prompt.py +++ b/DashAI/back/models/RAG/prompts/generation/default_QnA_generation_prompt.py @@ -33,9 +33,10 @@ class DefaultQnAGenerationPrompt(GenerationPrompt): }, "template": template } + template = template def __init__(self, **kwargs): - super().__init__(**kwargs) + self.template = kwargs.pop("template") @staticmethod diff --git a/DashAI/back/models/RAG/prompts/generation/default_generation_prompt.py b/DashAI/back/models/RAG/prompts/generation/default_generation_prompt.py index e92e566d6..a38f4aff2 100644 --- a/DashAI/back/models/RAG/prompts/generation/default_generation_prompt.py +++ b/DashAI/back/models/RAG/prompts/generation/default_generation_prompt.py @@ -30,7 +30,8 @@ class DefaultGenerationPrompt(GenerationPrompt): } def __init__(self, **kwargs): - super().__init__(**kwargs) + self.template = kwargs.pop("template") + @staticmethod def format( diff --git a/DashAI/back/models/RAG/prompts/prompt.py b/DashAI/back/models/RAG/prompts/prompt.py index 36e39e94f..4d7ac24fc 100644 --- a/DashAI/back/models/RAG/prompts/prompt.py +++ b/DashAI/back/models/RAG/prompts/prompt.py @@ -23,36 +23,9 @@ class Prompt(BaseModel): """ SCHEMA = PromptSchema - REQUIRED_EXTRA_KWARGS = ["db"] id: int name: str - - def __init__(self, **kwargs): - self.db = kwargs.pop("db") - kwargs = self.validate_and_transform(kwargs) - self.template = kwargs.get("template") - self.name = kwargs.get("name") - assert self.validate_template(self.template), ( - "The template is missing required placeholders." - ) - self.class_name = self.__class__.__name__ - self.params = kwargs - stored_model = ( - self.db.query(PromptDBModel) - .filter_by( - class_name=self.class_name, name=self.name, parameters=self.params - ) - .first() - ) - if stored_model: - self.id = stored_model.id - else: - new_model = PromptDBModel( - class_name=self.class_name, name=self.name, parameters=self.params - ) - self.db.add(new_model) - self.db.commit() - self.id = new_model.id + REQUIRED_EXTRA_KWARGS = [] def load(self, **kwargs: Any) -> None: pass diff --git a/DashAI/front/src/api/rag.ts b/DashAI/front/src/api/rag.ts index 75e6cc6bb..f41fd1de5 100644 --- a/DashAI/front/src/api/rag.ts +++ b/DashAI/front/src/api/rag.ts @@ -44,6 +44,7 @@ export const getRAGSession = async (sessionId: number): Promise => { export const createRAGSession = async ( sessionData: Omit, ): Promise => { + console.log("Creating RAG session with data:", sessionData); const params = sessionData.parameters as { documents: number[]; chunking_model: { @@ -58,10 +59,7 @@ export const createRAGSession = async ( component: string; params: Record; }; - prompt_model: { - component: string; - params: Record; - }; + prompt_id: number; }; const transformedSession: Omit = @@ -85,10 +83,7 @@ export const createRAGSession = async ( component: params.generation_model.component, params: params.generation_model.params, }, - prompt_model: { - component: params.prompt_model.component, - params: params.prompt_model.params, - }, + prompt_id: params.prompt_id, }, }; diff --git a/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx b/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx index ef4f6e5bd..98a448c99 100644 --- a/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx +++ b/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx @@ -115,7 +115,10 @@ export default function NewPromptModal({ open, handleClose, onPromptCreated }) { await createRAGPrompt({ class_name: selectedPromptType, name: promptName, - parameters: { template: promptTemplate }, + parameters: { + template: promptTemplate, + /* name: promptName */ + }, }); if (onPromptCreated) { await onPromptCreated(); diff --git a/DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx b/DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx index 9fd0778bf..584d748ec 100644 --- a/DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx +++ b/DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx @@ -75,7 +75,7 @@ export default function PromptSelectionTable({ minWidth: 140, flex: 1, editable: false, - valueGetter: (value) => formatDate(value), + valueFormatter: (value) => formatDate(value.value), }, { field: "last_modified", @@ -83,7 +83,7 @@ export default function PromptSelectionTable({ minWidth: 140, flex: 1, editable: false, - valueGetter: (value) => formatDate(value), + valueFormatter: (value) => formatDate(value.value), }, { field: "actions", diff --git a/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx b/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx index 15cb1bd91..bccd19278 100644 --- a/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx +++ b/DashAI/front/src/pages/generative/RAG/NewSessionModal/NewSessionModal.jsx @@ -70,14 +70,7 @@ const defaultNewSession = { component: "", params: {}, }, - prompt_model: { - component: "CustomGenerationPrompt", - params: { - name: "Default Prompt", - template: - "Answer to this message: {input}, with the following information: {chunks}", - }, - }, + prompt_id: null, }, }; @@ -125,8 +118,10 @@ export default function NewSessionModal({ generator_model: { ...sessionGeneratorModel, }, - }, - }); + prompt_id: sessionParameters.prompt_id + } + } + ); } else { const { defaultName } = generateSequentialName({ base: "RAG_Session", @@ -230,13 +225,7 @@ export default function NewSessionModal({ component: "", params: {}, }, - prompt_model: sessionData.parameters.prompt_model || { - component: "CustomGenerationPrompt", - params: { - template: - "Answer to this message: {input}, with the following information: {chunks}", - }, - }, + prompt_id: sessionData.parameters.prompt_id, }, }; diff --git a/DashAI/front/src/pages/generative/RAG/NewSessionModal/PromptConfigurationStep.jsx b/DashAI/front/src/pages/generative/RAG/NewSessionModal/PromptConfigurationStep.jsx index fd2c89cce..98d9c7334 100644 --- a/DashAI/front/src/pages/generative/RAG/NewSessionModal/PromptConfigurationStep.jsx +++ b/DashAI/front/src/pages/generative/RAG/NewSessionModal/PromptConfigurationStep.jsx @@ -27,10 +27,7 @@ export default function PromptConfigurationStep({ ...prev, parameters: { ...prev.parameters, - prompt_model: { - component: prompt.class_name, - params: prompt.parameters, - }, + prompt_id: prompt.id, }, })); } diff --git a/DashAI/front/src/types/ragPrompt.ts b/DashAI/front/src/types/ragPrompt.ts index 2ea780787..61b1599d1 100644 --- a/DashAI/front/src/types/ragPrompt.ts +++ b/DashAI/front/src/types/ragPrompt.ts @@ -1,11 +1,10 @@ export interface IRAGPrompt { id: number; class_name: string; - name?: string; + name: string; created?: string; last_modified?: string; parameters: { template: string; - name?: string; }; } From f44e445ea621eeb98011cd24f3938973fc8e0417 Mon Sep 17 00:00:00 2001 From: Creylay Date: Fri, 24 Oct 2025 11:25:34 -0300 Subject: [PATCH 084/218] feat: Refactor getPromptChildren to handle multiple prompt types and consolidate API calls --- DashAI/front/src/api/rag.ts | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/DashAI/front/src/api/rag.ts b/DashAI/front/src/api/rag.ts index f41fd1de5..bc0cbc096 100644 --- a/DashAI/front/src/api/rag.ts +++ b/DashAI/front/src/api/rag.ts @@ -239,17 +239,21 @@ export const getRAGPrompts = async (): Promise => { return response.data; }; -export const getGenerationPromptChildren = async (): Promise => { - const response = await api.get( - "/v1/component/GenerationPrompt/children", - { - params: { recursive: false }, - }, - ); - if (response.status !== 200) { - throw new Error( - `Failed to fetch GenerationPrompt children: ${response.statusText}`, +export const getPromptChildren = async ( + types: string[] = ["GenerationPrompt", "AugmentationPrompt"], +): Promise => { + const allChildren: IComponent[] = []; + for (const type of types) { + const response = await api.get( + `/v1/component/${type}/children`, + { params: { recursive: false } }, ); + if (response.status !== 200) { + throw new Error( + `Failed to fetch ${type} children: ${response.statusText}`, + ); + } + allChildren.push(...response.data); } - return response.data; + return allChildren; }; From f5f470dc898e9d3697f7952816e65bf82c2ca798 Mon Sep 17 00:00:00 2001 From: Creylay Date: Fri, 24 Oct 2025 11:25:40 -0300 Subject: [PATCH 085/218] feat: Update API call in NewPromptModal to use getPromptChildren for fetching prompt types --- .../front/src/components/generative/RAG/NewPromptModal.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx b/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx index 98a448c99..b47199cd9 100644 --- a/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx +++ b/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx @@ -17,7 +17,7 @@ import { import TextField from "@mui/material/TextField"; -import { getGenerationPromptChildren, createRAGPrompt } from "../../../api/rag"; +import { getPromptChildren, createRAGPrompt } from "../../../api/rag"; export default function NewPromptModal({ open, handleClose, onPromptCreated }) { const [promptTypes, setPromptTypes] = React.useState([]); @@ -27,7 +27,7 @@ export default function NewPromptModal({ open, handleClose, onPromptCreated }) { React.useEffect(() => { if (open) { - getGenerationPromptChildren() + getPromptChildren() .then((data) => setPromptTypes(data)) .catch(() => setPromptTypes([])); } @@ -115,7 +115,7 @@ export default function NewPromptModal({ open, handleClose, onPromptCreated }) { await createRAGPrompt({ class_name: selectedPromptType, name: promptName, - parameters: { + parameters: { template: promptTemplate, /* name: promptName */ }, From 87d34eac50a1cf68adea5f2b1f1a58c34039769a Mon Sep 17 00:00:00 2001 From: Creylay Date: Fri, 24 Oct 2025 11:25:46 -0300 Subject: [PATCH 086/218] fix: Correct valueFormatter to valueGetter for date formatting in PromptSelectionTable --- .../src/components/generative/RAG/PromptSelectionTable.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx b/DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx index 584d748ec..9fd0778bf 100644 --- a/DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx +++ b/DashAI/front/src/components/generative/RAG/PromptSelectionTable.jsx @@ -75,7 +75,7 @@ export default function PromptSelectionTable({ minWidth: 140, flex: 1, editable: false, - valueFormatter: (value) => formatDate(value.value), + valueGetter: (value) => formatDate(value), }, { field: "last_modified", @@ -83,7 +83,7 @@ export default function PromptSelectionTable({ minWidth: 140, flex: 1, editable: false, - valueFormatter: (value) => formatDate(value.value), + valueGetter: (value) => formatDate(value), }, { field: "actions", From de0c063e86898d2cf97ce01d597f54ce248d7a98 Mon Sep 17 00:00:00 2001 From: Creylay Date: Fri, 24 Oct 2025 12:59:20 -0300 Subject: [PATCH 087/218] feat: Add required and optional placeholders display in NewPromptModal based on selected prompt type --- .../generative/RAG/NewPromptModal.jsx | 96 ++++++++++++++++++- 1 file changed, 94 insertions(+), 2 deletions(-) diff --git a/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx b/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx index b47199cd9..971507cb9 100644 --- a/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx +++ b/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx @@ -18,12 +18,16 @@ import { import TextField from "@mui/material/TextField"; import { getPromptChildren, createRAGPrompt } from "../../../api/rag"; +import HelpOutlineIcon from "@mui/icons-material/HelpOutline"; +import Tooltip from "@mui/material/Tooltip"; +import CheckCircleIcon from "@mui/icons-material/CheckCircle"; +import WarningAmberIcon from "@mui/icons-material/WarningAmber"; export default function NewPromptModal({ open, handleClose, onPromptCreated }) { const [promptTypes, setPromptTypes] = React.useState([]); const [selectedPromptType, setSelectedPromptType] = React.useState(""); const [promptName, setPromptName] = React.useState(""); - const [promptTemplate, setPromptTemplate] = React.useState(""); // <-- NUEVO + const [promptTemplate, setPromptTemplate] = React.useState(""); React.useEffect(() => { if (open) { @@ -33,7 +37,6 @@ export default function NewPromptModal({ open, handleClose, onPromptCreated }) { } }, [open]); - // MODIFICADO const handlePromptTypeChange = (event) => { const typeName = event.target.value; setSelectedPromptType(typeName); @@ -97,6 +100,95 @@ export default function NewPromptModal({ open, handleClose, onPromptCreated }) { ))} + {/* Mostrar placeholders si hay un tipo seleccionado, en listas verticales */} + {selectedPromptType && + (() => { + const selectedType = promptTypes.find( + (type) => type.name === selectedPromptType, + ); + if (!selectedType || !selectedType.metadata) return null; + return ( +
+ + Required Placeholders + +
    + {selectedType.metadata.required_placeholders?.map((ph) => { + const isPresent = promptTemplate.includes(ph); + return ( +
  • + {isPresent ? ( + + ) : ( + + )} + {ph} + + + +
  • + ); + })} +
+ + Optional Placeholders + +
    + {selectedType.metadata.optional_placeholders?.map((ph) => { + const isPresent = promptTemplate.includes(ph); + return ( +
  • + {isPresent && ( + + )} + {ph} + + + +
  • + ); + })} +
+
+ ); + })()} + Date: Fri, 24 Oct 2025 13:45:51 -0300 Subject: [PATCH 088/218] feat: Enhance display of required and optional placeholders in NewPromptModal with improved layout --- .../generative/RAG/NewPromptModal.jsx | 167 ++++++++++-------- 1 file changed, 91 insertions(+), 76 deletions(-) diff --git a/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx b/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx index 971507cb9..9455fb87e 100644 --- a/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx +++ b/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx @@ -107,84 +107,99 @@ export default function NewPromptModal({ open, handleClose, onPromptCreated }) { (type) => type.name === selectedPromptType, ); if (!selectedType || !selectedType.metadata) return null; + const required = selectedType.metadata.required_placeholders || []; + const optional = selectedType.metadata.optional_placeholders || []; return (
- - Required Placeholders - -
    - {selectedType.metadata.required_placeholders?.map((ph) => { - const isPresent = promptTemplate.includes(ph); - return ( -
  • - {isPresent ? ( - - ) : ( - - )} - {ph} - - - -
  • - ); - })} -
- - Optional Placeholders - -
    - {selectedType.metadata.optional_placeholders?.map((ph) => { - const isPresent = promptTemplate.includes(ph); - return ( -
  • - {isPresent && ( - - )} - {ph} - - - -
  • - ); - })} -
+
+
+ + Required Placeholders + +
    + {required.map((ph) => { + const isPresent = promptTemplate.includes(ph); + return ( +
  • + {isPresent ? ( + + ) : ( + + )} + {ph} + + + +
  • + ); + })} +
+
+
+ + Optional Placeholders + +
    + {optional.map((ph) => { + const isPresent = promptTemplate.includes(ph); + return ( +
  • + {isPresent && ( + + )} + {ph} + + + +
  • + ); + })} +
+
+
); })()} From 8aef3c76511b06eec68b6849b82f4d9777f1a2db Mon Sep 17 00:00:00 2001 From: Creylay Date: Fri, 24 Oct 2025 15:49:46 -0300 Subject: [PATCH 089/218] feat: Implement validation for required placeholders in NewPromptModal and update save button state --- .../generative/RAG/NewPromptModal.jsx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx b/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx index 9455fb87e..e0a6c6ee0 100644 --- a/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx +++ b/DashAI/front/src/components/generative/RAG/NewPromptModal.jsx @@ -29,6 +29,20 @@ export default function NewPromptModal({ open, handleClose, onPromptCreated }) { const [promptName, setPromptName] = React.useState(""); const [promptTemplate, setPromptTemplate] = React.useState(""); + const allRequiredPresent = React.useMemo(() => { + if (!selectedPromptType) return false; + const selectedType = promptTypes.find( + (type) => type.name === selectedPromptType, + ); + if (!selectedType || !selectedType.metadata) return false; + const required = selectedType.metadata.required_placeholders || []; + return required.every((ph) => promptTemplate.includes(ph)); + }, [selectedPromptType, promptTypes, promptTemplate]); + + const canSave = Boolean( + selectedPromptType && promptName.trim() && allRequiredPresent, + ); + React.useEffect(() => { if (open) { getPromptChildren() @@ -82,6 +96,10 @@ export default function NewPromptModal({ open, handleClose, onPromptCreated }) { value={promptName} onChange={(e) => setPromptName(e.target.value)} sx={{ mt: 2 }} + required + error={!promptName.trim()} + helperText={!promptName.trim() ? "Prompt name is required" : ""} + InputLabelProps={{ required: false }} /> @@ -218,6 +236,7 @@ export default function NewPromptModal({ open, handleClose, onPromptCreated }) {