pmelnechuk commited on
Commit
a90a406
·
verified ·
1 Parent(s): ea74b05

Upload 3 files

Browse files
Files changed (3) hide show
  1. src/model_load.py +62 -0
  2. src/preprocess.py +73 -0
  3. src/vdb.py +16 -0
src/model_load.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain.chains import RetrievalQAWithSourcesChain
2
+ from langchain.llms import HuggingFacePipeline
3
+ from transformers import AutoTokenizer, pipeline, AutoModelForCausalLM, BitsAndBytesConfig
4
+ import torch
5
+ from langchain.prompts import PromptTemplate
6
+ from langchain.llms import HuggingFaceHub
7
+ from langchain.chains import LLMChain
8
+
9
+ def load_model():
10
+
11
+ model_name="tiiuae/Falcon3-7B-Instruct"
12
+ max_memory = {0: "24GB", "cpu": "30GB"}
13
+ # Cargar tokenizer y modelo de Hugging Face
14
+ tokenizer = AutoTokenizer.from_pretrained(model_name)
15
+ model = AutoModelForCausalLM.from_pretrained(model_name,
16
+ torch_dtype=torch.bfloat16).to("cuda")
17
+
18
+ # Crear pipeline de generación de texto
19
+ text_generation_pipeline = pipeline(
20
+ "text-generation",
21
+ model=model,
22
+ tokenizer=tokenizer,
23
+ max_new_tokens=128,
24
+ repetition_penalty=1.2,
25
+ device_map="auto"
26
+ )
27
+ # Crear el LLM compatible con LangChain
28
+ llm = HuggingFacePipeline(pipeline=text_generation_pipeline)
29
+
30
+ # Crear la plantilla de prompt que tomará el texto y la pregunta
31
+ prompt_template = """
32
+ Dado el siguiente texto extraído de varios documentos y una pregunta, crea una respuesta utilizando la información proporcionada. Si la pregunta sale por fuera de la información proporcionada responde con "No tengo información al respecto" y corta la respuesta.
33
+
34
+ **Documentos relevantes:**
35
+ {documento}
36
+
37
+ **Pregunta:**
38
+ {pregunta}
39
+
40
+ **Respuesta:**
41
+ """
42
+
43
+ # Crear el prompt con las variables necesarias
44
+ prompt = PromptTemplate(input_variables=["documento", "pregunta"], template=prompt_template)
45
+
46
+ # Crear una cadena de LLMChain que combine el retriever y el prompt
47
+ qa_chain = prompt | llm
48
+ return qa_chain
49
+ def ask(pregunta: str,retriever,qa_chain):
50
+
51
+
52
+
53
+ #Busqueda de documentos mediante el retriever
54
+ documentos=retriever.invoke(pregunta)
55
+
56
+ #Generacion de la respuesta
57
+ respuesta = qa_chain.invoke({
58
+ "documento": "\n".join([doc.page_content for doc in documentos]),
59
+ "pregunta": pregunta
60
+ })
61
+
62
+ return respuesta
src/preprocess.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_community.document_loaders import PyMuPDFLoader
2
+ from langchain.text_splitter import RecursiveCharacterTextSplitter
3
+ import re
4
+
5
+ class Loader:
6
+ """Clase encargada de la carga desde PDFs,
7
+ admite PDFs con texto seleccionable unicamente. Realiza
8
+ carga y devuelve lista de chunks de texto.
9
+ """
10
+ def __init__(self, path: str):
11
+ self.path = path
12
+
13
+ def load_docs(self, pag: slice = None):
14
+ """Carga el PDF y devuelve lista de chunks de texto."""
15
+ loader = PyMuPDFLoader(self.path)
16
+ docs = loader.load()
17
+ if pag:
18
+ docs = docs[pag]
19
+ return [doc.page_content for doc in docs]
20
+
21
+ @staticmethod
22
+ def limpiar_texto(texto: str) -> str:
23
+ """
24
+ Limpia el texto eliminando caracteres basura y normalizando espacios y saltos de línea.
25
+ Esta función está diseñada para preprocesar libros u otros documentos largos,
26
+ facilitando su uso en aplicaciones de Retrieval Augmented Generation (RAG).
27
+
28
+ Args:
29
+ texto (str): El texto original a limpiar.
30
+
31
+ Returns:
32
+ str: El texto limpio.
33
+ """
34
+ # 1. Eliminar saltos de línea, tabulaciones y otros caracteres de control
35
+ texto = re.sub(r'[\r\n\t]+', ' ', texto)
36
+
37
+ # 2. Eliminar caracteres no imprimibles (códigos de control)
38
+ texto = re.sub(r'[\x00-\x1F\x7F]', '', texto)
39
+
40
+ # 3. Sustituir múltiples espacios por uno solo
41
+ texto = re.sub(r'\s+', ' ', texto)
42
+
43
+ # 4. Eliminar caracteres que no sean letras, dígitos o signos de puntuación comunes
44
+ # Se conservan letras con acentos y caracteres propios del español.
45
+ texto = re.sub(r'[^\w\s.,;:¡!¿?\-áéíóúÁÉÍÓÚñÑ]', '', texto)
46
+
47
+ # 5. Eliminar espacios al inicio y al final
48
+ texto = texto.strip()
49
+
50
+ return texto
51
+
52
+ @staticmethod
53
+ def splitter(texto, chunk_size, chunk_overlap):
54
+ """
55
+ Divide el texto en chunks
56
+
57
+ Args:
58
+ chunk_size (int): Largo del chunk.
59
+ chunk_overlap (int): Sobreposición de chunks.
60
+ texto (list): lista de textos a procesar.
61
+
62
+ Returns:
63
+ list: Los textos en chunks.
64
+ """
65
+ splitter = RecursiveCharacterTextSplitter(
66
+ chunk_size=chunk_size,
67
+ chunk_overlap=chunk_overlap,
68
+ length_function=len,
69
+ separators=["\n\n", "\n", " ", ""]
70
+ )
71
+ chunks = splitter.create_documents(texto)
72
+
73
+ return chunks
src/vdb.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sentence_transformers import SentenceTransformer
2
+ from langchain.schema import Document
3
+
4
+
5
+
6
+ class EmbeddingGen:
7
+
8
+ def __init__(self, model_name: str):
9
+ self.model = SentenceTransformer(model_name)
10
+
11
+ def embed_documents(self, chunks):
12
+ return [self.model.encode(chunk) for chunk in chunks]
13
+
14
+ def embed_query(self, text):
15
+ return self.model.encode(text)
16
+