################################################ | |
#Pfad, wo Docs/Bilder/Filme abgelegt werden können - lokal, also hier im HF Space (sonst auf eigenem Rechner) | |
PATH_WORK = "." | |
CHROMA_DIR = "/chroma/kkg" | |
CHROMA_PDF = './chroma/kkg/pdf' | |
CHROMA_WORD = './chroma/kkg/word' | |
CHROMA_EXCEL = './chroma/kkg/excel' | |
YOUTUBE_DIR = "/youtube" | |
HISTORY_PFAD = "/data/history" | |
############################################### | |
#URLs zu Dokumenten oder andere Inhalte, die einbezogen werden sollen | |
PDF_URL = "https://arxiv.org/pdf/2303.08774.pdf" | |
WEB_URL = "https://openai.com/research/gpt-4" | |
YOUTUBE_URL_1 = "https://www.youtube.com/watch?v=--khbXchTeE" | |
YOUTUBE_URL_2 = "https://www.youtube.com/watch?v=hdhZwyf24mE" | |
#YOUTUBE_URL_3 = "https://www.youtube.com/watch?v=vw-KWfKwvTQ" | |
#spezielle Webseiten als Datenbasis laden | |
urls = [ | |
"https://kkg.hamburg.de/unser-leitbild/" | |
"https://kkg.hamburg.de/unsere-schulcharta/", | |
"https://kkg.hamburg.de/koordination-unterrichtsentwicklung/", | |
"https://kkg.hamburg.de/konzept-medien-und-it-am-kkg/", | |
] | |
################################################## | |
#Normalisierung eines Prompts | |
################################################## | |
def normalise_prompt (prompt): | |
#alles Kleinbuchstaben | |
prompt_klein =prompt.lower() | |
#Word Tokenisation | |
tokens = word_tokenize(prompt_klein) | |
#Punktuierung entfernen | |
tokens = [word for word in tokens if word.isalnum()] | |
# Stop Word Entfernung | |
nltk.download('stopwords') | |
stop_words = set(stopwords.words('deutsch')) | |
tokens = [word for word in tokens if not word in stop_words] | |
# 5. Lemmatisierung: Worte in Grundform bringen, um Text besser vergleichen zu können | |
nltk.download('wordnet') | |
lemmatizer = WordNetLemmatizer() | |
tokens = [lemmatizer.lemmatize(word) for word in tokens] | |
# 6. Handling Special Characters (Remove non-alphanumeric characters) | |
tokens = [re.sub(r'\W+', '', word) for word in tokens] | |
# 7. Spell Check (optional, using a library like pyspellchecker) | |
from spellchecker import SpellChecker | |
spell = SpellChecker() | |
tokens = [spell.correction(word) for word in tokens] | |
# Join tokens back to sentence | |
normalized_prompt = ' '.join(tokens) | |
print("normaiserd prompt..................................") | |
print(normalized_prompt) | |
return normalized_prompt | |
################################################## | |
#RAG Hilfsfunktionen - Dokumenten bearbeiten für Vektorstore | |
################################################## | |
################################################## | |
# Funktion, um für einen best. File-typ ein directory-loader zu definieren | |
def create_directory_loader(file_type, directory_path): | |
#verscheidene Dokument loaders: | |
loaders = { | |
'.pdf': PyPDFLoader, | |
'.word': UnstructuredWordDocumentLoader, | |
} | |
return DirectoryLoader( | |
path=directory_path, | |
glob=f"**/*{file_type}", | |
loader_cls=loaders[file_type], | |
) | |
################################################ | |
#die Inhalte splitten, um in Vektordatenbank entsprechend zu laden als Splits | |
def document_loading_splitting(): | |
############################## | |
# Document loading | |
docs = [] | |
# kreiere einen DirectoryLoader für jeden file type | |
pdf_loader = create_directory_loader('.pdf', CHROMA_PDF) | |
word_loader = create_directory_loader('.word', CHROMA_WORD) | |
print("PDF Loader done............................") | |
# Load the files | |
pdf_documents = pdf_loader.load() | |
word_documents = word_loader.load() | |
#alle zusammen in docs... | |
docs.extend(pdf_documents) | |
docs.extend(word_documents) | |
#andere loader... | |
# Load PDF | |
#loader = PyPDFLoader(PDF_URL) | |
#docs.extend(loader.load()) | |
# Load Web | |
#loader = WebBaseLoader(WEB_URL) | |
#docs.extend(loader.load()) | |
# Load YouTube | |
#loader = GenericLoader(YoutubeAudioLoader([YOUTUBE_URL_1,YOUTUBE_URL_2], PATH_WORK + YOUTUBE_DIR), OpenAIWhisperParser()) | |
#docs.extend(loader.load()) | |
################################ | |
# Document splitting | |
text_splitter = RecursiveCharacterTextSplitter(chunk_overlap = 150, chunk_size = 1500) | |
splits = text_splitter.split_documents(docs) | |
return splits | |
########################################### | |
#Chroma DB die splits ablegen - vektorisiert... | |
def document_storage_chroma(splits): | |
#OpenAi embeddings---------------------------------- | |
Chroma.from_documents(documents = splits, embedding = OpenAIEmbeddings(disallowed_special = ()), persist_directory = PATH_WORK + CHROMA_DIR) | |
#HF embeddings-------------------------------------- | |
#Chroma.from_documents(documents = splits, embedding = HuggingFaceEmbeddings(model_name="sentence-transformers/all-mpnet-base-v2", model_kwargs={"device": "cpu"}, encode_kwargs={'normalize_embeddings': False}), persist_directory = PATH_WORK + CHROMA_DIR) | |
############################################ | |
#dokumente in chroma db vektorisiert ablegen können - die Db vorbereiten daüfur | |
def document_retrieval_chroma(llm, prompt): | |
#HF embeddings ----------------------------------- | |
#Alternative Embedding - für Vektorstore, um Ähnlichkeitsvektoren zu erzeugen - die ...InstructEmbedding ist sehr rechenaufwendig | |
embeddings = HuggingFaceInstructEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2", model_kwargs={"device": "cpu"}) | |
#etwas weniger rechenaufwendig: | |
#embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-mpnet-base-v2", model_kwargs={"device": "cpu"}, encode_kwargs={'normalize_embeddings': False}) | |
#ChromaDb um die embedings zu speichern | |
db = Chroma(embedding_function = embeddings, persist_directory = PATH_WORK + CHROMA_DIR) | |
return db | |
############################################ | |
# rag_chain Alternative für RAg mit Bild-Upload, da hier das llm so nicht genutzt werden kann und der prompt mit den RAG Erweiterungen anders übergeben wird | |
#langchain nutzen, um prompt an llm zu leiten, aber vorher in der VektorDB suchen, um passende splits zum Prompt hinzuzufügen | |
#prompt mit RAG!!! | |
def rag_chain(prompt, db, k=3): | |
rag_template = "Nutze ausschließlich die folgenden Kontext Teile am Ende, um die Frage zu beantworten . " + template + "Frage: " + prompt + "Kontext Teile: " | |
retrieved_chunks = db.similarity_search(prompt, k) | |
neu_prompt = rag_template | |
for i, chunk in enumerate(retrieved_chunks): | |
neu_prompt += f"{i+1}. {chunk}\n" | |
return neu_prompt | |