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