In this blog we will walk through a comprehensive example of indexing research papers with extracting different metadata — beyond full text chunking and embedding — and build semantic embeddings for indexing and querying. Agradecemos muito se você pudesse Se você achar esse tutorial útil. ⭐ star CocoIndex no GitHub CocoIndex no GitHub Uso de Casos Pesquisa e recuperação acadêmica, bem como agentes de IA baseados em pesquisa Sistemas de recomendação de papel Pesquisa de Conhecimento Graph Análise semântica da literatura científica O que vamos alcançar Vamos dar uma olhada nisso como um exemplo. Pdf Aqui está o que queremos alcançar: Extract the paper metadata, including file name, title, author information, abstract, and number of pages. Build vector embeddings for the metadata, such as the title and abstract, for semantic search. Isso permite melhores resultados de pesquisa semântica orientados por metadados.Por exemplo, você pode combinar consultas de texto com títulos e resumos. Build an index of authors and all the file names associated with each author to answer questions like "Give me all the papers by Jeff Dean." If you want to perform full PDF embedding for the paper, you can also refer to . this article Você pode encontrar o código completo . aqui Se este artigo é útil para você, por favor, dê-nos uma estrela Para nos ajudar a crescer. GitHub Componentes principais PDF Preprocessing Reads PDFs using and extracts: pypdf Total number of pages First page content (used as a proxy for metadata-rich information) Markdown Conversion Converts the first page to Markdown using . Marker LLM-Powered Metadata Extraction Sends the first-page Markdown to GPT-4o using CocoIndex's function. ExtractByLlm Extracted metadata includes and more. (string) title (with name, email, and affiliation) authors (string) abstract Semantic Embedding The title is embedded directly using the model by the SentenceTransformer. all-MiniLM-L6-v2 Abstracts are chunked based on semantic punctuation and token count, then each chunk is embedded individually. Relational Data Collection Authors are unrolled and collected into an relation, enabling queries like: author_papers Show all papers by X Which co-authors worked with Y? pré-requisitos . Install PostgreSQL CocoIndex uses PostgreSQL internally for incremental processing. . Configure your OpenAI API key Alternativamente, temos suporte nativo para Gemini, Ollama, LiteLLM, . Guia Você pode escolher seu provedor de LLM favorito e pode trabalhar completamente no local. Definição de fluxo de indexação Este projeto demonstra um exemplo um pouco mais abrangente de compreensão de metadados mais perto de casos de uso do mundo real. Você verá o quão fácil é alcançar este design pelo CocoIndex dentro de 100 linhas de lógica de indexação - . Código Para ajudá-lo a navegar melhor pelo que vamos passar, aqui está um diagrama de fluxo. Importar uma lista de documentos em PDF. For each file: Extract the first page of the paper. Convert the first page to Markdown. Extract metadata (title, authors, abstract) from the first page. Split the abstract into chunks, and compute embeddings for each chunk. Export to the following tables in Postgres with PGVector: Metadata (title, authors, abstract) for each paper. Author-to-paper mapping, for author-based query. Embeddings for titles and abstract chunks, for semantic search. Vamos zoom nos passos. Importar os documentos @cocoindex.flow_def(name="PaperMetadata") def paper_metadata_flow( flow_builder: cocoindex.FlowBuilder, data_scope: cocoindex.DataScope ) -> None: data_scope["documents"] = flow_builder.add_source( cocoindex.sources.LocalFile(path="papers", binary=True), refresh_interval=datetime.timedelta(seconds=10), ) será criada uma tabela com subcampos ( , em por exemplo, flow_builder.add_source filename content Podemos referir-nos ao Para mais detalhes. Documentação Extrair e coletar metadados Extrair primeira página para informações básicas Defina uma função personalizada para extrair a primeira página e o número de páginas do PDF. @dataclasses.dataclass class PaperBasicInfo: num_pages: int first_page: bytes @cocoindex.op.function() def extract_basic_info(content: bytes) -> PaperBasicInfo: """Extract the first pages of a PDF.""" reader = PdfReader(io.BytesIO(content)) output = io.BytesIO() writer = PdfWriter() writer.add_page(reader.pages[0]) writer.write(output) return PaperBasicInfo(num_pages=len(reader.pages), first_page=output.getvalue()) Agora, coloque isso em seu fluxo. Nós extraímos metadados da primeira página para minimizar os custos de processamento, já que todo o PDF pode ser muito grande. with data_scope["documents"].row() as doc: doc["basic_info"] = doc["content"].transform(extract_basic_info) Após esta etapa, você deve ter as informações básicas de cada papel. Confira as informações básicas Vamos converter a primeira página para Markdown usando Marker. Alternativamente, você pode facilmente conectar seu parser PDF favorito, como Docling. Defina uma função de conversor de marcador e cache-a, uma vez que sua inicialização é intensiva em recursos. Isso garante que a mesma instância de conversor seja reutilizada para arquivos de entrada diferentes. @cache def get_marker_converter() -> PdfConverter: config_parser = ConfigParser({}) return PdfConverter( create_model_dict(), config=config_parser.generate_config_dict() ) Coloque-o em uma função custom. @cocoindex.op.function(gpu=True, cache=True, behavior_version=1) def pdf_to_markdown(content: bytes) -> str: """Convert to Markdown.""" with tempfile.NamedTemporaryFile(delete=True, suffix=".pdf") as temp_file: temp_file.write(content) temp_file.flush() text, _, _ = text_from_rendered(get_marker_converter()(temp_file.name)) return text Mande para a sua transformação with data_scope["documents"].row() as doc: doc["first_page_md"] = doc["basic_info"]["first_page"].transform( pdf_to_markdown ) Após esta etapa, você deve ter a primeira página de cada papel no formato Markdown. Extrair informações básicas com LLM Definir um esquema para a extração LLM. CocoIndex suporta nativamente a extração estruturada LLM com esquemas complexos e aninhados. Se você estiver interessado em aprender mais sobre esquemas aninhados, consulte . Este artigo @dataclasses.dataclass class PaperMetadata: """ Metadata for a paper. """ title: str authors: list[Author] abstract: str Coloque-o dentro da Com uma classe de dados definida, o CocoIndex analisará automaticamente a resposta LLM na classe de dados. ExtractByLlm doc["metadata"] = doc["first_page_md"].transform( cocoindex.functions.ExtractByLlm( llm_spec=cocoindex.LlmSpec( api_type=cocoindex.LlmApiType.OPENAI, model="gpt-4o" ), output_type=PaperMetadata, instruction="Please extract the metadata from the first page of the paper.", ) ) Após esta etapa, você deve ter os metadados de cada papel. Coleta de metadados em papel paper_metadata = data_scope.add_collector() with data_scope["documents"].row() as doc: # ... process # Collect metadata paper_metadata.collect( filename=doc["filename"], title=doc["metadata"]["title"], authors=doc["metadata"]["authors"], abstract=doc["metadata"]["abstract"], num_pages=doc["basic_info"]["num_pages"], ) Recolha tudo o que você precisa :) Colecção Dois Informação author filename autor Filho Aqui queremos coletar Autor → Papéis em uma tabela separada para construir uma funcionalidade de pesquisa. Simplesmente coletado pelo autor. author_papers = data_scope.add_collector() with data_scope["documents"].row() as doc: with doc["metadata"]["authors"].row() as author: author_papers.collect( author_name=author["name"], filename=doc["filename"], ) Cálculo e recolha de embeddings Título doc["title_embedding"] = doc["metadata"]["title"].transform( cocoindex.functions.SentenceTransformerEmbed( model="sentence-transformers/all-MiniLM-L6-v2" ) ) Abstração Divida o abstrato em pedaços, incorpore cada pedaço e recolha suas incorporações. Às vezes, o abstracto pode ser muito longo. doc["abstract_chunks"] = doc["metadata"]["abstract"].transform( cocoindex.functions.SplitRecursively( custom_languages=[ cocoindex.functions.CustomLanguageSpec( language_name="abstract", separators_regex=[r"[.?!]+\s+", r"[:;]\s+", r",\s+", r"\s+"], ) ] ), language="abstract", chunk_size=500, min_chunk_size=200, chunk_overlap=150, ) Após esta etapa, você deve ter os pedaços abstratos de cada papel. Misture cada pedaço e recolha suas inserções. with doc["abstract_chunks"].row() as chunk: chunk["embedding"] = chunk["text"].transform( cocoindex.functions.SentenceTransformerEmbed( model="sentence-transformers/all-MiniLM-L6-v2" ) ) Após esta etapa, você deve ter as incorporações dos pedaços abstratos de cada papel. Collect embeddings metadata_embeddings = data_scope.add_collector() with data_scope["documents"].row() as doc: # ... process # collect title embedding metadata_embeddings.collect( id=cocoindex.GeneratedField.UUID, filename=doc["filename"], location="title", text=doc["metadata"]["title"], embedding=doc["title_embedding"], ) with doc["abstract_chunks"].row() as chunk: # ... process # collect abstract chunks embeddings metadata_embeddings.collect( id=cocoindex.GeneratedField.UUID, filename=doc["filename"], location="abstract", text=chunk["text"], embedding=chunk["embedding"], ) Exportação Finalmente, exportamos os dados para o Postgres. paper_metadata.export( "paper_metadata", cocoindex.targets.Postgres(), primary_key_fields=["filename"], ) author_papers.export( "author_papers", cocoindex.targets.Postgres(), primary_key_fields=["author_name", "filename"], ) metadata_embeddings.export( "metadata_embeddings", cocoindex.targets.Postgres(), primary_key_fields=["id"], vector_indexes=[ cocoindex.VectorIndexDef( field_name="embedding", metric=cocoindex.VectorSimilarityMetric.COSINE_SIMILARITY, ) ], ) Neste exemplo, usamos o PGVector como lojas de inserção/ Com o CocoIndex, você pode fazer um interruptor de linha em outros bancos de dados Vector suportados, como o Qdrant. Para mais detalhes. Guia Nosso objetivo é padronizar as interfaces e torná-las como a construção de LEGO. Visão em CocoInsight passo a passo Você pode caminhar pelo projeto passo a passo em Para ver CocoInsight Exatamente como cada campo é construído e o que acontece por trás das cenas. Conheça o índice Você pode se referir a esta seção de Sobre Textos embutidos Como criar uma consulta contra embeddings. Por enquanto, o CocoIndex não fornece interface de consulta adicional.Podemos escrever SQL ou confiar no motor de consulta pelo armazenamento alvo. Muitos bancos de dados já otimizaram implementações de consulta com suas próprias melhores práticas O espaço de consulta tem excelentes soluções para consulta, rearranjo e outras funcionalidades relacionadas à pesquisa. Se você precisar de ajuda com a escrita da consulta, sinta-se livre para nos contactar em . Discordância Apoie-nos Estamos constantemente melhorando, e mais recursos e exemplos estão chegando em breve. Se este artigo é útil para você, por favor, dê-nos uma estrela Para nos ajudar a crescer. GitHub Obrigado pela leitura!