jonanfu commited on
Commit
a2a383d
·
1 Parent(s): b958ad2

corregir error de visualizar pdfs

Browse files
Files changed (1) hide show
  1. app.py +102 -78
app.py CHANGED
@@ -4,62 +4,47 @@ import os
4
  from io import BytesIO
5
  from pypdf import PdfReader
6
  from langchain.schema import Document
7
- from langchain.embeddings import HuggingFaceEmbeddings
8
  from langchain_pinecone import PineconeVectorStore
9
  from pinecone import Pinecone as PineconeClient, ServerlessSpec
10
 
11
- # Configuración de las variables de entorno
12
  hf_token = os.getenv("HUGGINGFACE_TOKEN")
13
  pinecone_api_key = os.getenv("PINECONE_API_KEY")
14
 
15
  st.set_page_config(page_title="Clasificador de CVs", layout="wide")
16
  st.title("🎯 Clasificador de CVs por Puesto de Trabajo")
17
 
 
 
 
 
 
 
 
 
 
18
  # Inputs
19
  titulo_puesto = st.text_input("🧑‍💼 Título del puesto", placeholder="Ej: Desarrollador Backend Senior")
20
  descripcion_puesto = st.text_area("📝 Descripción del puesto", height=200)
 
 
21
  uploaded_files = st.file_uploader("📎 Subir CVs (PDF)", type="pdf", accept_multiple_files=True)
22
 
23
  if uploaded_files:
24
- archivos_en_memoria = {file.name: BytesIO(file.read()) for file in uploaded_files}
25
- st.session_state["archivos_en_memoria"] = archivos_en_memoria
26
- st.success(f"Se han subido {len(archivos_en_memoria)} Pdf(s).")
27
-
28
- if st.button("📊 Procesar CVs"):
29
- st.write(st.session_state.get("archivos_en_memoria"))
30
- if not uploaded_files:
31
- st.warning("Primero sube al menos un CV.")
32
- elif not descripcion_puesto.strip():
33
- st.warning("Debes escribir una descripción del puesto.")
34
- else:
35
- # Inicializar Pinecone
36
- pc = PineconeClient(api_key=pinecone_api_key)
37
- index_name = "cv-index"
38
-
39
- if index_name not in pc.list_indexes().names():
40
- pc.create_index(
41
- name=index_name,
42
- dimension=384,
43
- metric='cosine',
44
- spec=ServerlessSpec(cloud='aws', region='us-east-1')
45
- )
46
- index = pc.Index(index_name)
47
-
48
- # Inicializar modelo de embeddings
49
- embedding = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
50
 
51
- # Vector store
52
- vector_store = PineconeVectorStore(index=index, embedding=embedding)
53
 
54
- archivos_en_memoria = st.session_state.get("archivos_en_memoria", {})
55
- if not archivos_en_memoria:
56
- st.warning("No se encontraron archivos en memoria.")
57
- st.stop()
58
 
59
- # Procesar archivos y crear documentos
60
- documents = []
61
- for filename, buffer in archivos_en_memoria.items():
62
- buffer.seek(0)
63
  reader = PdfReader(buffer)
64
  text = ""
65
  for page in reader.pages:
@@ -67,44 +52,83 @@ if st.button("📊 Procesar CVs"):
67
  if page_text:
68
  text += page_text + "\n"
69
 
70
- doc = Document(
71
- page_content=text.strip(),
72
- metadata={"filename": filename, "titulo_puesto": titulo_puesto}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  )
74
- documents.append(doc)
75
-
76
- # Subir documentos a Pinecone
77
- vector_store.add_documents(documents)
78
-
79
- # Búsqueda por similitud
80
- results = vector_store.similarity_search_with_score(descripcion_puesto, k=len(documents))
81
- st.success(f"{len(results)} CV(s) procesado(s).")
82
-
83
- # Mostrar resultados
84
- for doc, score in results:
85
- st.markdown("---")
86
- col1, col2 = st.columns([2, 1])
87
-
88
- filename = doc.metadata.get("filename")
89
- file_buffer = archivos_en_memoria.get(filename)
90
-
91
- with col1:
92
- if file_buffer:
93
- file_buffer.seek(0)
94
- base64_pdf = base64.b64encode(file_buffer.read()).decode("utf-8")
95
- pdf_display = f"""
96
- <iframe src="data:application/pdf;base64,{base64_pdf}" width="100%" height="500" type="application/pdf"></iframe>
97
- """
98
- st.markdown("#### 👀 Visualizador del PDF", unsafe_allow_html=True)
99
- st.markdown(pdf_display, unsafe_allow_html=True)
100
- else:
101
- st.warning(f"No se encontró el archivo `{filename}` en memoria.")
102
-
103
- with col2:
104
- st.markdown("#### 📄 Información del CV")
105
- st.write(f"**Nombre del archivo:** `{filename}`")
106
- st.write(f"**Score de similitud:** `{score * 100:.2f}%`")
107
-
108
- # Eliminar todos los vectores del índice (vaciar)
109
- index.delete(delete_all=True)
110
- st.success("🧹 Todos los vectores han sido eliminados del índice de Pinecone.")
 
4
  from io import BytesIO
5
  from pypdf import PdfReader
6
  from langchain.schema import Document
7
+ from langchain_community.embeddings import HuggingFaceEmbeddings
8
  from langchain_pinecone import PineconeVectorStore
9
  from pinecone import Pinecone as PineconeClient, ServerlessSpec
10
 
11
+ # Configuración de entorno
12
  hf_token = os.getenv("HUGGINGFACE_TOKEN")
13
  pinecone_api_key = os.getenv("PINECONE_API_KEY")
14
 
15
  st.set_page_config(page_title="Clasificador de CVs", layout="wide")
16
  st.title("🎯 Clasificador de CVs por Puesto de Trabajo")
17
 
18
+ # Cargar modelo de embeddings
19
+ @st.cache_resource(show_spinner="⏳ Cargando modelo de embeddings...")
20
+ def load_embeddings():
21
+ model = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
22
+ _ = model.embed_query("test") # Calentamiento
23
+ return model
24
+
25
+ embedding = load_embeddings()
26
+
27
  # Inputs
28
  titulo_puesto = st.text_input("🧑‍💼 Título del puesto", placeholder="Ej: Desarrollador Backend Senior")
29
  descripcion_puesto = st.text_area("📝 Descripción del puesto", height=200)
30
+
31
+ # Subida de archivos
32
  uploaded_files = st.file_uploader("📎 Subir CVs (PDF)", type="pdf", accept_multiple_files=True)
33
 
34
  if uploaded_files:
35
+ if "cv_data" not in st.session_state:
36
+ st.session_state["cv_data"] = {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
+ cv_data = st.session_state["cv_data"]
 
39
 
40
+ for file in uploaded_files:
41
+ if file.name in cv_data:
42
+ st.info(f"ℹ️ El archivo `{file.name}` ya fue subido. Ignorando duplicado.")
43
+ continue
44
 
45
+ buffer = BytesIO(file.read())
46
+ buffer.seek(0)
47
+ try:
 
48
  reader = PdfReader(buffer)
49
  text = ""
50
  for page in reader.pages:
 
52
  if page_text:
53
  text += page_text + "\n"
54
 
55
+ if text.strip():
56
+ cv_data[file.name] = {
57
+ "text": text.strip(),
58
+ "pdf": buffer
59
+ }
60
+ st.success(f"✅ Procesado `{file.name}` correctamente.")
61
+ else:
62
+ st.warning(f"⚠️ No se pudo extraer texto de `{file.name}`.")
63
+ except Exception as e:
64
+ st.error(f"❌ Error procesando `{file.name}`: {e}")
65
+
66
+ # Procesamiento de CVs
67
+ if st.button("📊 Procesar CVs"):
68
+ cv_data = st.session_state.get("cv_data", {})
69
+
70
+ if not cv_data:
71
+ st.warning("No hay CVs para procesar.")
72
+ st.stop()
73
+
74
+ if not descripcion_puesto.strip():
75
+ st.warning("Debes ingresar una descripción del puesto.")
76
+ st.stop()
77
+
78
+ # Inicializar Pinecone
79
+ pc = PineconeClient(api_key=pinecone_api_key)
80
+ index_name = "cv-index"
81
+
82
+ if index_name not in pc.list_indexes().names():
83
+ pc.create_index(
84
+ name=index_name,
85
+ dimension=384,
86
+ metric='cosine',
87
+ spec=ServerlessSpec(cloud='aws', region='us-east-1')
88
+ )
89
+ index = pc.Index(index_name)
90
+ index.delete(delete_all=True)
91
+
92
+ vector_store = PineconeVectorStore(index=index, embedding=embedding)
93
+
94
+ # Crear documentos
95
+ documents = []
96
+ for filename, data in cv_data.items():
97
+ doc = Document(
98
+ page_content=data["text"],
99
+ metadata={"filename": filename, "titulo_puesto": titulo_puesto}
100
+ )
101
+ documents.append(doc)
102
+
103
+ # Subir a Pinecone
104
+ vector_store.add_documents(documents)
105
+
106
+ # Búsqueda por similitud
107
+ results = vector_store.similarity_search_with_score(descripcion_puesto, k=len(documents))
108
+ st.success(f"{len(results)} CV(s) procesado(s).")
109
+
110
+ # Mostrar resultados
111
+ for doc, score in results:
112
+ filename = doc.metadata["filename"]
113
+ data = cv_data[filename]
114
+
115
+ st.markdown("---")
116
+ col1, col2 = st.columns([2, 1])
117
+
118
+ with col1:
119
+ data["pdf"].seek(0)
120
+ pdf_bytes = data["pdf"].read()
121
+ base64_pdf = base64.b64encode(pdf_bytes).decode("utf-8")
122
+ st.markdown(f"#### 👀 Visualizador: `{filename}`", unsafe_allow_html=True)
123
+ st.markdown(
124
+ f"""<embed src="data:application/pdf;base64,{base64_pdf}" width="100%" height="500" type="application/pdf">""",
125
+ unsafe_allow_html=True
126
  )
127
+
128
+ with col2:
129
+ st.markdown("#### 📄 Detalles")
130
+ st.write(f"**Nombre del archivo:** `{filename}`")
131
+ st.write(f"**Similitud con descripción:** `{score * 100:.2f}%`")
132
+
133
+ # Opcional: eliminar vectores del índice (descomenta si deseas limpiar después)
134
+