În acest blog vom trece printr-un exemplu cuprinzător de indexare a lucrărilor de cercetare cu extragerea diferitelor metadate - dincolo de tăierea și încorporarea textului complet - și construirea de încorporări semantice pentru indexare și interogare. We would greatly appreciate it if you could Dacă ți se pare util acest tutorial. ⭐ star CocoIndex pe GitHub CocoIndex pe GitHub Folosește cazuri Căutarea și recuperarea academică, precum și agenții AI bazate pe cercetare Sisteme de recomandări pe hârtie Graficul cunoștințelor de cercetare Analiza semantică a literaturii ştiinţifice Ce vom realiza Să aruncăm o privire la acest Ca un exemplu. PDF în Iată ce vrem să realizăm: 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. Acest lucru permite rezultate de căutare semantică mai bune bazate pe metadate. De exemplu, puteți potrivi interogările text cu titluri și abstracte. 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 Puteți găsi codul complet . Aici Dacă acest articol vă este util, vă rugăm să ne dați o stea ⭐ la Pentru a ne ajuta să creștem. GitHub Componente de bază 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? Precondiţii . Install PostgreSQL CocoIndex uses PostgreSQL internally for incremental processing. . Configure your OpenAI API key Alternativ, avem suport nativ pentru Gemini, Ollama, LiteLLM, verificați . Ghidul Puteți alege furnizorul dvs. preferat LLM și puteți lucra complet la fața locului. Definirea fluxului de indexare Acest proiect demonstrează un exemplu puțin mai cuprinzător de înțelegere a metadatelor mai aproape de cazurile de utilizare din lumea reală. Veți vedea cât de ușor este să realizați acest design de către CocoIndex în 100 de linii de logică de indexare - . Codul Pentru a vă ajuta să navigați mai bine prin ceea ce vom trece, aici este o diagramă de flux. Importă o listă de documente în 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. Zoom în pași. Importul de documente @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), ) va crea un tabel cu subcâmpuri ( , , cu flow_builder.add_source filename content Putem face referire la Pentru mai multe detalii. Documentație Extrage și colectează metadate Extrage prima pagină pentru informații de bază Definiți o funcție particularizată pentru a extrage prima pagină și numărul de pagini din 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()) Introduceți acest lucru în fluxul dvs. Extragem metadatele din prima pagină pentru a minimiza costurile de procesare, deoarece întregul PDF poate fi foarte mare. with data_scope["documents"].row() as doc: doc["basic_info"] = doc["content"].transform(extract_basic_info) După această etapă, ar trebui să aveți informațiile de bază ale fiecărei lucrări. Parse informații de bază Vom converti prima pagină în Markdown folosind Marker. Alternativ, puteți conecta cu ușurință analizorul PDF preferat, cum ar fi Docling. Definiți o funcție de convertor de marker și cache-l, deoarece inițializarea sa este intensă în resurse. Acest lucru asigură faptul că aceeași instanță de conversie este reutilizată pentru diferite fișiere de intrare. @cache def get_marker_converter() -> PdfConverter: config_parser = ConfigParser({}) return PdfConverter( create_model_dict(), config=config_parser.generate_config_dict() ) Introduceți-l într-o funcție 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 Transmite-o la transformarea ta with data_scope["documents"].row() as doc: doc["first_page_md"] = doc["basic_info"]["first_page"].transform( pdf_to_markdown ) După această etapă, ar trebui să aveți prima pagină a fiecărei hârtii în formatul Markdown. Extrage informații de bază cu LLM Definiți o schemă pentru extracția LLM. CocoIndex acceptă în mod nativ extracția structurată LLM cu scheme complexe și încorporate. Dacă sunteți interesat să aflați mai multe despre schemele cuibate, consultați . Acest articol @dataclasses.dataclass class PaperMetadata: """ Metadata for a paper. """ title: str authors: list[Author] abstract: str Plasează-l în Cu o clasă de date definită, CocoIndex va analiza automat răspunsul LLM în clasa de date. 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.", ) ) După această etapă, ar trebui să aveți metadatele fiecărei lucrări. Colectarea metadatelor din hârtie 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"], ) Colectează tot ce ai nevoie :) Colecția două informaţie autorului Filetă autorului Filetă Aici vrem să colectăm Autor → Documente într-un tabel separat pentru a construi o funcționalitate de căutare. Colectate doar de către 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"], ) Calculează și colectează embeddings Titlul doc["title_embedding"] = doc["metadata"]["title"].transform( cocoindex.functions.SentenceTransformerEmbed( model="sentence-transformers/all-MiniLM-L6-v2" ) ) abstractă Împărțiți abstracte în bucăți, încorporați fiecare bucată și colectați încorporările lor. Uneori abstractul poate fi foarte lung. 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, ) După acest pas, ar trebui să aveți bucățile abstracte ale fiecărei hârtii. Împingeți fiecare bucată și colectați încorporările lor. with doc["abstract_chunks"].row() as chunk: chunk["embedding"] = chunk["text"].transform( cocoindex.functions.SentenceTransformerEmbed( model="sentence-transformers/all-MiniLM-L6-v2" ) ) După acest pas, ar trebui să aveți încorporările bucăților abstracte ale fiecărei hârtii. Colecția 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"], ) Exportul În cele din urmă, exportăm datele către 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, ) ], ) În acest exemplu, folosim PGVector ca magazine de încorporare/ Cu CocoIndex, puteți face un comutator de linie pe alte baze de date Vector acceptate, cum ar fi Qdrant. Pentru mai multe detalii. Ghidul Scopul nostru este de a standardiza interfețele și de a face ca construirea Lego. Vizualizați în CocoInsight pas cu pas Puteți merge prin proiect pas cu pas în Să vedem CocoInsight Exact cum este construit fiecare câmp și ce se întâmplă în spatele scenei. Caută index Puteți consulta această secțiune de Despre Textul încorporat Cum să construiți o interogare împotriva embeddings. Deocamdată, CocoIndex nu oferă interfețe de interogare suplimentare.Putem scrie SQL sau ne putem baza pe motorul de interogare de către stocarea țintă. Multe baze de date au optimizat deja implementările de interogări cu propriile cele mai bune practici Spațiul de interogare are soluții excelente pentru interogare, rearanjare și alte funcționalități legate de căutare. Dacă aveți nevoie de asistență cu scrierea interogării, vă rugăm să vă simțiți liber să ne contactați la . discordă Sprijină-ne Ne îmbunătățim în mod constant, iar mai multe caracteristici și exemple vin în curând. Dacă acest articol vă este util, vă rugăm să ne dați o stea ⭐ la Pentru a ne ajuta să creștem. GitHub Mulțumesc pentru lectură!