Und ja - Leerzeilen im Code werden ebenfalls gezählt. Eine kleine Demonstration der Arbeit finden Sie am Ende des Artikels.
Wir benötigen Python3 , das von Tesseract 5 heruntergeladen wurde , und das mehrsprachige Modell mit Distiluse-Basis aus dem Satz-Transformers- Paket . Wer schon versteht, was als nächstes passieren wird, wird nicht interessant sein.
In der Zwischenzeit wird alles aussehen, was wir brauchen:
Erste 18 Zeilen
import numpy as np
import os, sys, glob
os.environ['PATH'] += os.pathsep + os.path.join(os.getcwd(), 'Tesseract-OCR')
extensions = [
'.xlsx', '.docx', '.pptx',
'.pdf', '.txt', '.md', '.htm', 'html',
'.jpg', '.jpeg', '.png', '.gif'
]
import warnings; warnings.filterwarnings('ignore')
import torch, textract, pdfplumber
from cleantext import clean
from razdel import sentenize
from sklearn.neighbors import NearestNeighbors
from sentence_transformers import SentenceTransformer
embedder = SentenceTransformer('./distillUSE')
Es wird benötigt, wie Sie sehen können, anständig, und alles scheint fertig zu sein, aber Sie können nicht ohne eine Datei auskommen. Insbesondere Textract (nicht von Amazon, das bezahlt wird) funktioniert irgendwie nicht gut mit russischen PDFs , da Sie pdfplumber verwenden können . Außerdem ist es eine schwierige Aufgabe, den Text in Sätze zu zerlegen , und in diesem Fall leistet razdel hervorragende Arbeit mit der russischen Sprache .
Diejenigen, die noch nichts von Scikit-Learn gehört haben -
Die Hauptsache ist, den Text einer (beliebigen) Datei tatsächlich in einen Vektor umzuwandeln, was sie auch tun:
nächste 36 Codezeilen
def processor(path, embedder):
try:
if path.lower().endswith('.pdf'):
with pdfplumber.open(path) as pdf:
if len(pdf.pages):
text = ' '.join([
page.extract_text() or '' for page in pdf.pages if page
])
elif path.lower().endswith('.md') or path.lower().endswith('.txt'):
with open(path, 'r', encoding='UTF-8') as fd:
text = fd.read()
else:
text = textract.process(path, language='rus+eng').decode('UTF-8')
if path.lower()[-4:] in ['.jpg', 'jpeg', '.gif', '.png']:
text = clean(
text,
fix_unicode=False, lang='ru', to_ascii=False, lower=False,
no_line_breaks=True
)
else:
text = clean(
text,
lang='ru', to_ascii=False, lower=False, no_line_breaks=True
)
sentences = list(map(lambda substring: substring.text, sentenize(text)))
except Exception as exception:
return None
if not len(sentences):
return None
return {
'filepath': [path] * len(sentences),
'sentences': sentences,
'vectors': [vector.astype(float).tolist() for vector in embedder.encode(
sentences
)]
}
Nun, dann bleibt es eine Frage der Technik - alle Dateien durchzugehen, die Vektoren zu extrahieren und die der Abfrage am nächsten liegende Kosinusentfernung zu finden.
Verbleibender Code
def indexer(files, embedder):
for file in files:
processed = processor(file, embedder)
if processed is not None:
yield processed
def counter(path):
if not os.path.exists(path):
return None
for file in glob.iglob(path + '/**', recursive=True):
extension = os.path.splitext(file)[1].lower()
if extension in extensions:
yield file
def search(engine, text, sentences, files):
indices = engine.kneighbors(
embedder.encode([text])[0].astype(float).reshape(1, -1),
return_distance=True
)
distance = indices[0][0][0]
position = indices[1][0][0]
print(
' "%.3f' % (1 - distance / 2),
': "%s", "%s"' % (sentences[position], files[position])
)
print(' "%s"' % sys.argv[1])
paths = list(counter(sys.argv[1]))
print(' "%s"' % sys.argv[1])
db = list(indexer(paths, embedder))
sentences, files, vectors = [], [], []
for item in db:
sentences += item['sentences']
files += item['filepath']
vectors += item['vectors']
engine = NearestNeighbors(n_neighbors=1, metric='cosine').fit(
np.array(vectors).reshape(len(vectors), -1)
)
query = input(' : ')
while query:
search(engine, query, sentences, files)
query = input(' : ')
Sie können den gesamten Code folgendermaßen ausführen:
python3 app.py /path/to/your/files/
So ist es mit dem Code.
Und hier ist die versprochene Demo.
Ich nahm zwei Nachrichten von "Lenta.ru" und legte eine in eine GIF-Datei durch die berüchtigte Farbe und die zweite nur in eine Textdatei.
First.gif-Datei
Zweite TXT-Datei
, . .
, - . , , , . . , .
, , , . . .
, - - .
, №71 , , , . 10 , . — .
, - . , , , . . , .
, , , . . .
, - - .
, №71 , , , . 10 , . — .
Und hier ist eine GIF-Animation, wie es funktioniert. Mit der GPU funktioniert natürlich alles fröhlicher.
Danke fürs Lesen! Ich hoffe immer noch, dass diese Methode für jemanden nützlich sein wird.