PDF-failide (näiteks teadusartiklite) eksportimine (või täpsemalt importimine) Weaviate'i andmebaasi koosneb neljast põhietapist:
Siin on samm-sammuline juhend, kuidas seda teha Pythoni abil.
Sul on vaja:
Kasutame langchain teeki PDF-ide lugemiseks ja tükeldamiseks ning weaviate-client teeki andmebaasiga suhtlemiseks.
pip install weaviate-client langchain langchain-community pypdf
See skript teeb järgmist: loob ühenduse, defineerib andmestruktuuri, loeb PDF-i, tükeldab selle ja saadab Weaviate'i.
import weaviate
import weaviate.classes.config as wc
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
import os
# 1. ÜHENDUSE LOOMINE
# Asenda oma andmetega. Kui kasutad lokaalset Dockerit, on kood veidi teine.
client = weaviate.connect_to_weaviate_cloud(
cluster_url="SINU_WEAVIATE_URL", # Nt: https://minu-klaster.weaviate.network
auth_credentials=weaviate.auth.AuthApiKey("SINU_WEAVIATE_API_KEY"),
headers={
"X-OpenAI-Api-Key": "SINU_OPENAI_KEY" # Või muu teenusepakkuja võti
}
)
def create_collection():
"""Loob andmebaasi skeemi (tabeli)"""
if client.collections.exists("TeadusArtikkel"):
client.collections.delete("TeadusArtikkel")
client.collections.create(
name="TeadusArtikkel",
# Konfigureerime automaatse vektoriseerimise (nt OpenAI abil)
vectorizer_config=wc.Configure.Vectorizer.text2vec_openai(),
# Defineerime metaandmete väljad
properties=[
wc.Property(name="title", data_type=wc.DataType.TEXT),
wc.Property(name="content", data_type=wc.DataType.TEXT),
wc.Property(name="page_number", data_type=wc.DataType.INT),
wc.Property(name="source", data_type=wc.DataType.TEXT),
]
)
print("Kollektsioon loodud.")
def process_and_upload_pdf(pdf_path):
"""Loeb PDFi, tükeldab ja saadab Weaviate'i"""
print(f"Töötlen faili: {pdf_path}")
# 2. TEKSTI ERALDAMINE JA TÜKELDAMINE
loader = PyPDFLoader(pdf_path)
documents = loader.load()
# Teadusartiklite puhul on oluline, et tükid (chunks) kattuksid veidi,
# et kontekst ei läheks kaduma.
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000, # Tähemärkide arv ühes tükis
chunk_overlap=200 # Kattuvus
)
chunks = text_splitter.split_documents(documents)
# 3. ANDMETE SAATMINE (BATCH IMPORT)
collection = client.collections.get("TeadusArtikkel")
# Kasutame kontekstihaldurit automaatseks partiide haldamiseks
with collection.batch.dynamic() as batch:
for chunk in chunks:
# Valmistame ette andmeobjekti
properties = {
"title": os.path.basename(pdf_path), # Faili nimi pealkirjaks
"content": chunk.page_content, # Teksti sisu
"page_number": chunk.metadata.get('page'),
"source": pdf_path
}
# Lisame partii nimekirja. Weaviate teeb vektoriseerimise taustal ise.
batch.add_object(
properties=properties
)
if len(collection.batch.failed_objects) > 0:
print(f"Vead: {collection.batch.failed_objects}")
else:
print(f"Edukalt imporditud {len(chunks)} tekstilõiku.")
# KÄIVITAMINE
try:
create_collection() # Käivita see ainult esimest korda või kui tahad tühjendada
# Määra oma PDF faili asukoht
process_and_upload_pdf("./minu_teadusartikkel.pdf")
finally:
client.close()
RecursiveCharacterTextSplitter on hea, sest see püüab hoida lauseid ja lõike tervikuna. chunk_size=1000 on tavaliselt optimaalne, kuid võid katsetada ka väiksematega (nt 512), kui soovid täpsemaid vastuseid.PyPDFLoader lihtsaid andmeid, kuid keerulisemateks juhtudeks võid vajada eraldi parserit (nt Grobid või Unstructured), mis oskab eristada viiteid, abstrakti ja sisu.pypdf) muudab tabelid tihti kasutuks tekstijadaks. Kui artiklites on olulisi tabeleid, kaalu Unstructured.io teegi kasutamist, mis oskab tabeleid paremini parsida.Kui sa ei soovi Pythoni skripte kirjutada, on Weaviate loonud avatud lähtekoodiga tööriista nimega Verba.
Installimiseks:
pip install goldenverba
verba start
Siin on kohandatud lahendus lokaalse Weaviate'i (Docker) jaoks.
Lokaalse Dockeri puhul on kaks olulist muudatust:
I'm presently focused on structuring the response methodically. Firstly, I am analyzing the user's specific requirements, including converting the code for local Docker instances and utilizing the Estonian language. My approach involves a Docker Compose configuration followed by the Python code adjustment and a final explanation of the required alterations. I will provide clear code snippets for easy understanding.
ige vektoriseerimise moodul (nttext2vec-openai või text2vec-transformers) oleks sisse lülitatud.connect_to_local meetodit.docker-compose.ymlEnne Pythoni koodi käivitamist veendu, et su docker-compose.yml failis on lubatud moodul text2vec-openai (kui kasutad OpenAI-d) või mõni muu mudel.
Salvesta see failina docker-compose.yml ja käivita docker compose up -d.
---
version: '3.4'
services:
weaviate:
command:
- --host
- 0.0.0.0
- --port
- '8080'
- --scheme
- http
image: cr.weaviate.io/semitechnologies/weaviate:1.24.10
ports:
- 8080:8080
- 50051:50051
volumes:
- weaviate_data:/var/lib/weaviate
restart: on-failure:0
environment:
# Lülitame sisse OpenAI mooduli (või asenda 'text2vec-transformers' täiesti lokaalseks)
ENABLE_MODULES: 'text2vec-openai'
DEFAULT_VECTORIZER_MODULE: 'text2vec-openai'
# Luba anonüümne ligipääs lokaalselt arendades
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'true'
PERSISTENCE_DATA_PATH: '/var/lib/weaviate'
QUERY_DEFAULTS_LIMIT: 25
volumes:
weaviate_data:
Siin on muudetud kood. Peamine erinevus on client = weaviate.connect_to_local(...) funktsiooni kasutamine.
import weaviate
import weaviate.classes.config as wc
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
import os
# 1. ÜHENDUSE LOOMINE (LOKAALNE DOCKER)
# Eeldus: Docker jookseb pordil 8080 ja gRPC pordil 50051
client = weaviate.connect_to_local(
port=8080,
grpc_port=50051,
# Isegi kui Weaviate on lokaalne, peame saatma OpenAI võtme päises,
# et Weaviate saaks "text2vec-openai" mooduliga suhelda.
# Kui kasutad täiesti lokaalset mudelit (nt Ollama või HuggingFace), pole seda vaja.
headers={
"X-OpenAI-Api-Key": "SINU_OPENAI_KEY"
}
)
def create_collection():
"""Loob andmebaasi skeemi"""
# Kontrollime, kas kollektsioon on olemas
if client.collections.exists("TeadusArtikkel"):
client.collections.delete("TeadusArtikkel")
client.collections.create(
name="TeadusArtikkel",
# See peab klappima sellega, mis on sinu docker-compose.yml failis ENABLE_MODULES all
vectorizer_config=wc.Configure.Vectorizer.text2vec_openai(),
properties=[
wc.Property(name="title", data_type=wc.DataType.TEXT),
wc.Property(name="content", data_type=wc.DataType.TEXT),
wc.Property(name="page_number", data_type=wc.DataType.INT),
wc.Property(name="source", data_type=wc.DataType.TEXT),
]
)
print("Kollektsioon 'TeadusArtikkel' loodud lokaalsesse baasi.")
def process_and_upload_pdf(pdf_path):
"""Loeb PDFi ja saadab Weaviate'i"""
if not os.path.exists(pdf_path):
print(f"Faili ei leitud: {pdf_path}")
return
print(f"Töötlen faili: {pdf_path}")
# 2. TEKSTI ERALDAMINE JA TÜKELDAMINE
loader = PyPDFLoader(pdf_path)
documents = loader.load()
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200
)
chunks = text_splitter.split_documents(documents)
# 3. ANDMETE SAATMINE
collection = client.collections.get("TeadusArtikkel")
# Kasutame batch importi
with collection.batch.dynamic() as batch:
for chunk in chunks:
properties = {
"title": os.path.basename(pdf_path),
"content": chunk.page_content,
"page_number": chunk.metadata.get('page', 0),
"source": pdf_path
}
batch.add_object(
properties=properties
)
if len(collection.batch.failed_objects) > 0:
print(f"Vead importimisel: {collection.batch.failed_objects}")
else:
print(f"Edukalt imporditud {len(chunks)} tekstilõiku lokaalsesse baasi.")
# KÄIVITAMINE
try:
# Kontrolli ühendust
if client.is_ready():
print("Ühendus Weaviate Dockeriga on korras.")
create_collection() # Esmakordsel käivitamisel
process_and_upload_pdf("./minu_teadusartikkel.pdf") # Asenda failinimi
else:
print("Ei saanud Weaviate Dockeriga ühendust. Kas 'docker compose up' on tehtud?")
finally:
client.close()
connect_to_local: Pilve URL-i asemel ühendume localhost (vaikimisi).headers: See on kriitiline. Kuigi andmebaas on sinu arvutis, toimub vektoriseerimine (teksti muutmine numbriteks) ikkagi Weaviate sees oleva mooduli kaudu. Kui see moodul on text2vec-openai, peab Weaviate saama sinu võtme, et saata tekst OpenAI serverisse ja saada vastu vektor.docker-compose.yml failis: ENABLE_MODULES: 'text2vec-transformers' (vajab GPU-d või palju RAM-i).vectorizer_config=wc.Configure.Vectorizer.text2vec_transformers().headers Pythoni koodist (võtit pole vaja).Lühike vastus: Ei, otseselt vektoriseerimiseks (embeddings) Perplexity praegu Weaviate'is ei tööta.
Pikem selgitus ja lahendus:
Weaviate'i ja RAG (Retrieval-Augmented Generation) süsteemides on kaks eraldi etappi, kus AI-d kasutatakse:
Vektoriseerimine (Embeddings): Teksti muutmine numbriteks, et Weaviate saaks otsida.
text2vec-perplexity ja Perplexity API on loodud teksti genereerimiseks, mitte vektorite loomiseks.text2vec-openai), Cohere'i või lokaalset mudelit (text2vec-transformers / HuggingFace).Genereerimine (Chat/Answer): Leitud teksti põhjal vastuse kirjutamine.
Kuna Perplexity ei saa teha vektoriseerimist, pead kasutama hübriidlahendust:
Siin on Pythoni näide, kuidas see töötab:
requests (Perplexity API jaoks)pip install requests
Eeldame, et andmed on juba Weaviate'is (kasutades eelmises vastuses toodud OpenAI koodi).
import weaviate
import requests
import json
# 1. ÜHENDUS WEAVIATE-GA (Otsingu jaoks)
client = weaviate.connect_to_local(
port=8080,
grpc_port=50051,
headers={"X-OpenAI-Api-Key": "SINU_OPENAI_KEY"} # Vaja vektoriseerimiseks otsingu ajal
)
def ask_perplexity_with_weaviate(query):
# A. OTSIME WEAVIATE-ST ASJAKOHAST INFOT
collection = client.collections.get("TeadusArtikkel")
# Otsime 3 kõige sarnasemat lõiku
response = collection.query.near_text(
query=query,
limit=3
)
# Paneme leitud info ühte stringi kokku (Kontekst)
context_text = ""
for obj in response.objects:
context_text += f"---\nAllikas: {obj.properties['title']}, lk {obj.properties['page_number']}\n"
context_text += f"Sisu: {obj.properties['content']}\n"
print(f"Leitud {len(response.objects)} asjakohast lõiku Weaviate'ist.\n")
# B. SAADAME KÜSIMUSE + KONTEKSTI PERPLEXITY API-SSE
perplexity_api_key = "SINU_PERPLEXITY_API_KEY"
url = "https://api.perplexity.ai/chat/completions"
# Koostame prompti
messages = [
{
"role": "system",
"content": "Sa oled abivalmis teadlane. Vasta küsimusele AINULT alljärgneva konteksti põhjal. Kui vastust kontekstis pole, ütle seda."
},
{
"role": "user",
"content": f"Kontekst:\n{context_text}\n\nKüsimus: {query}"
}
]
payload = {
"model": "llama-3.1-sonar-small-128k-online", # Või muu Perplexity mudel
"messages": messages,
"temperature": 0.1
}
headers = {
"Authorization": f"Bearer {perplexity_api_key}",
"Content-Type": "application/json"
}
# Teeme päringu Perplexitysse
response_pplx = requests.post(url, json=payload, headers=headers)
if response_pplx.status_code == 200:
answer = response_pplx.json()['choices'][0]['message']['content']
print(f"Vastus Perplexitylt:\n{answer}")
else:
print("Viga Perplexityga ühendumisel:", response_pplx.text)
# KÄIVITAMINE
try:
if client.is_ready():
ask_perplexity_with_weaviate("Mis on peamine järeldus selles artiklis?")
finally:
client.close()
text2vec-openai kasutamist docker-compose.yml failis. Perplexity ei saa seda asendada.requests kaudu), et genereerida ilus ja tark vastus, andes talle ette Weaviate'ist leitud toormaterjali. See annab sulle Perplexity "tarkuse" koos sinu oma privaatsete PDF-andmetega.DeepSeek API ise ei paku otsest PDF-failide töötlemist (tekstiks teisendamist, tabelite eraldamist jms). Siiski saad süsteemi ehitada järgmiste sammudega:
PDF → struktureeritud tekst
Kasuta teeke nagu PyPDF2, pdfminer või teenuseid nagu:
Unstructured IO, TikaTeksti jagamine chunk'ideks
Näide Pythonis:
from langchain_text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # märkide arv
chunk_overlap=50,
separators=["\n\n", "\n", ". ", " "]
)
chunks = text_splitter.split_text(tekst)
Vektorkujude loomine
Kasuta DeepSeek Embeddings API-t (mudel: text-embedding-3-large või 3-small):
import requests
response = requests.post(
"https://api.deepseek.com/v1/embeddings",
headers={"Authorization": "Bearer SINU_API_VÕTI"},
json={"input": chunks, "model": "text-embedding-3-large"}
)
embeddings = response.json()['data']
Vektorandmebaas
Salvesta embeddingud andmebaasi:
Päringud
Kui kasutaja esitab küsimuse:
k lähimat chunk'iresponse = requests.post(
"https://api.deepseek.com/v1/chat/completions",
headers={"Authorization": "Bearer KEY"},
json={
"model": "deepseek-chat",
"messages": [
{"role": "system", "content": "Vastad teaduslikule küsimusele konteksti põhjal."},
{"role": "user", "content": f"Kontekst: {retrieved_chunks}\n\nKüsimus: {user_question}"}
]
}
)
Kas soovid, et koostan täpsema koodinäite ühe konkreetse sammu jaoks (nt PDF töötlus või vektoriandmebaasi päring)?
Siin on täielik näide Pythoni koodist, mis teostab sinu taotletud töövoo - alates PDF-ist kuni vektorbaasi päringuteni, kasutades DeepSeek Embeddings API-t:
pip install PyPDF2 langchain langchain-community chromadb requests python-dotenv
.env fail (hoia API võtit turvaliselt)DEEPSEEK_API_KEY=sinu_võti_siia
import os
import requests
from PyPDF2 import PdfReader
from langchain_text_splitters import RecursiveCharacterTextSplitter
import chromadb
from chromadb.utils import embedding_functions
from dotenv import load_dotenv
# Laadi API võti
load_dotenv()
DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY")
# 1. PDF-st tekst
def extract_text_from_pdf(pdf_path):
text = ""
with open(pdf_path, "rb") as file:
reader = PdfReader(file)
for page in reader.pages:
text += page.extract_text() + "\n"
return text
# 2. Teksti jagamine chunk'ideks
def split_text(text):
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200,
separators=["\n\n", "\n", ". ", " ", ""]
)
return text_splitter.split_text(text)
# 3. DeepSeek Embeddings (kasutades ametlikku API-d)
def get_deepseek_embeddings(texts):
response = requests.post(
"https://api.deepseek.com/v1/embeddings",
headers={"Authorization": f"Bearer {DEEPSEEK_API_KEY}"},
json={"input": texts, "model": "text-embedding-3-large"}
)
return [item['embedding'] for item in response.json()['data']]
# 4. Salvesta ChromaDB-sse
def store_in_chroma(chunks, embeddings):
client = chromadb.PersistentClient(path="./vector_db")
# Kasuta DeepSeeki embeddereid
deepseek_ef = embedding_functions.EmbeddingFunction(
name="deepseek_embedder",
model="text-embedding-3-large"
)
collection = client.get_or_create_collection(
name="teadusartiklid",
embedding_function=deepseek_ef
)
# Lisa dokumendid koos embeddingutega
ids = [f"id_{i}" for i in range(len(chunks))]
collection.add(
ids=ids,
documents=chunks,
embeddings=embeddings
)
return collection
# 5. Päringu töötlemine
def query_database(collection, query, top_k=3):
# Genereeri päringu embedding
query_embedding = get_deepseek_embeddings([query])[0]
# Otsi vektorbaasist
results = collection.query(
query_embeddings=[query_embedding],
n_results=top_k
)
return results['documents'][0]
# 6. Vastuse genereerimine kontekstiga
def generate_contextual_answer(query, context_chunks):
context = "\n\n---\n\n".join(context_chunks)
response = requests.post(
"https://api.deepseek.com/v1/chat/completions",
headers={"Authorization": f"Bearer {DEEPSEEK_API_KEY}"},
json={
"model": "deepseek-chat",
"messages": [
{
"role": "system",
"content": f"Vasta küsimusele kasutades allpool antud konteksti. Kui vastust pole kontekstis, ütle 'Ei tea'.\n\nKONTEKST:\n{context}"
},
{"role": "user", "content": query}
],
"temperature": 0.3
}
)
return response.json()["choices"][0]["message"]["content"]
# Peameetod - kogu töövoo
def main(pdf_path, user_query):
# Samm 1-2: PDF -> chunk'id
text = extract_text_from_pdf(pdf_path)
chunks = split_text(text)
print(f"Tekst jagatud {len(chunks)} chunk'iks")
# Samm 3: Genereeri embeddingud
embeddings = get_deepseek_embeddings(chunks)
print("Embeddingud loodud")
# Samm 4: Salvesta vektorbaasi
collection = store_in_chroma(chunks, embeddings)
print("Andmed salvestatud ChromaDB-sse")
# Samm 5: Tee päring
print(f"\nPäring: {user_query}")
retrieved_chunks = query_database(collection, user_query)
# Samm 6: Genereeri vastus
answer = generate_contextual_answer(user_query, retrieved_chunks)
print(f"\nVastus: {answer}")
if __name__ == "__main__":
# Kasutamine
pdf_path = "teadusartikkel.pdf" # Asenda oma PDF failiga
user_query = "Mis on peamised järeldused selle uuringu kohta?"
main(pdf_path, user_query)
PDF töötlus:
extract_text_from_pdf() - eraldab teksti PDF-failistsplit_text() - jagab teksti mõistlikeks lõikudeksDeepSeek API integratsioon:
get_deepseek_embeddings() - teisendab tekstivektoreiteksgenerate_contextual_answer() - kasutab DeepSeeki kontekstipõhiseks vastamiseksVektorbaas:
Töövoog:
Tekst jagatud 42 chunk'iks
Embeddingud loodud
Andmed salvestatud ChromaDB-sse
Päring: Mis on uuringu peamised järeldused?
Vastus: Artiklis jõutakse kolme põhijärelduseni: 1) ... 2) ... 3) ...
teadusartikkel.pdf oma PDF-failiga.env failichunk_size) vastavalt sisuletop_k väärtust, et määrata tagastatavate lõikude arvKas soovid, et selgitaksin mõnda konkreetset osa lähemalt või näitaksin, kuidas seda Streamligi GUI-s kasutada?