import requests import os, sys, json import gradio as gr import time import re import io #from PIL import Image, ImageDraw, ImageOps, ImageFont #import base64 import tempfile from PyPDF2 import PdfReader, PdfWriter #from langchain.chains import LLMChain, RetrievalQA from langchain_community.document_loaders import PyPDFLoader, UnstructuredWordDocumentLoader, DirectoryLoader from langchain_community.document_loaders.blob_loaders.youtube_audio import YoutubeAudioLoader #from langchain.document_loaders import GenericLoader #from langchain.schema import AIMessage, HumanMessage #from langchain_community.llms import HuggingFaceHub from langchain_huggingface import HuggingFaceEndpoint #from langchain_community.llms import HuggingFaceEndPoints from langchain_huggingface import HuggingFaceEmbeddings #from langchain_community.llms import HuggingFaceTextGenInference #from langchain_community.embeddings import HuggingFaceInstructEmbeddings, HuggingFaceEmbeddings, HuggingFaceBgeEmbeddings, HuggingFaceInferenceAPIEmbeddings #from langchain.prompts import PromptTemplate #from langchain.chains import Runnable................................. from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.vectorstores import Chroma from chromadb.errors import InvalidDimensionException from langchain_community.llms.huggingface_pipeline import HuggingFacePipeline from transformers import pipeline from huggingface_hub import InferenceApi from utils import * from beschreibungen import * #Konstanten #Validieren des PW ANTI_BOT_PW = os.getenv("VALIDATE_PW") ############################### #HF Authentifizierung HUGGINGFACEHUB_API_TOKEN = os.getenv("HF_READ") os.environ["HUGGINGFACEHUB_API_TOKEN"] = HUGGINGFACEHUB_API_TOKEN HEADERS = {"Authorization": f"Bearer {HUGGINGFACEHUB_API_TOKEN}"} # Hugging Face Token direkt im Code setzen hf_token = os.getenv("HF_READ") #max Anzahl der zurückgelieferten Dokumente ANZAHL_DOCS = 5 PATH_WORK = "." CHROMA_DIR = "/chroma/kkg" CHROMA_PDF = './chroma/kkg/pdf' CHROMA_WORD = './chroma/kkg/word' CHROMA_EXCEL = './chroma/kkg/excel' DOCS_DIR = "chroma/kkg/pdf" ########################################### # Alternativen, um HF Modelle in der rAG Chain einzusetzen ########################################### ####################################### #1. Alternative: HuggingFace Model name-------------------------------- #MODEL_NAME_HF = "HuggingFaceH4/zephyr-7b-alpha" #"t5-small" #"meta-llama/Meta-Llama-3-8B-Instruct" #"mistralai/Mistral-7B-Instruct-v0.3" #"microsoft/Phi-3-mini-4k-instruct" #"HuggingFaceH4/zephyr-7b-alpha" ############################################ #2. Alternative_ HuggingFace Reop ID-------------------------------- #repo_id = "meta-llama/Llama-2-13b-chat-hf" #repo_id = "HuggingFaceH4/zephyr-7b-alpha" #das Modell ist echt gut!!! Vom MIT #repo_id = "TheBloke/Yi-34B-Chat-GGUF" #repo_id = "meta-llama/Llama-2-70b-chat-hf" #repo_id = "tiiuae/falcon-40b" #repo_id = "Vicuna-33b" #repo_id = "alexkueck/ChatBotLI2Klein" #repo_id = "mistralai/Mistral-7B-v0.1" #repo_id = "internlm/internlm-chat-7b" #repo_id = "Qwen/Qwen-7B" #repo_id = "Salesforce/xgen-7b-8k-base" #repo_id = "Writer/camel-5b-hf" #repo_id = "databricks/dolly-v2-3b" #repo_id = "google/flan-t5-xxl" #repo_id = "mistralai/Mixtral-8x7B-Instruct-v0.1" #repo_id = "abacusai/Smaug-72B-v0.1" ########################################### #3. Alternative: HF API - URL #API_URL = "https://api-inference.huggingface.co/models/Falconsai/text_summarization" ############################################### #globale Variablen ############################################## #nur bei ersten Anfrage splitten der Dokumente - um die Vektordatenbank entsprechend zu füllen #splittet = False #DB für Vektorstore vektordatenbank = None retriever = None ############################################# # Allgemeine Konstanten #Filepath zu temp Folder (temp) mit File von ausgewähltem chatverlauf file_path_download = "" ################################################# ################################################# #Funktionen zur Verarbeitung ################################################ ############################################## #wenn löschen Button geklickt def clear_all(history, uploaded_file_paths, chats): dic_history = {schluessel: wert for schluessel, wert in history} #später wird die summary auf 50 tokens verkürzt, um die Anfrage nicht so teuer werden zu lassen #summary wird gebraucht für die Anfrage beim NN, um eine Überschrift des Eintrages zu generieren summary = "\n\n".join(f'{schluessel}: \n {wert}' for schluessel, wert in dic_history.items()) #falls file mit summay für download existiert hat: das zunächst löschen #cleanup(file_path_download) #noch nicht im Einsatz, aber hier werden alle Chats einer Sitzung gespeichert #den aktuellen Chatverlauf zum Download bereitstellen: if chats != {} : id_neu = len(chats)+1 chats[id_neu]= summary else: chats[0]= summary #Eine Überschrift zu dem jeweiligen Chatverlauf finden - abhängig vom Inhalt #file_path_download = save_and_download(summary) #headers, payload = process_chatverlauf(summary, MODEL_NAME, OAI_API_KEY) #response = requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=payload) #als json ausgeben #data = response.json() # Den "content" auswählen, da dort die Antwort der Ki enthalten ist #result = data['choices'][0]['message']['content'] #worte = result.split() #if len(worte) > 2: #file_path_download = "data/" + str(len(chats)) + "_Chatverlauf.pdf" #else: #file_path_download = "data/" + str(len(chats)) + "_" + result + ".pdf" #erstellePdf(file_path_download, result, dic_history) #die session variable in gradio erweitern und alle fliepath neu in das gr.File hochladen #uploaded_file_paths= uploaded_file_paths + [file_path_download] return None, gr.Image(visible=False), uploaded_file_paths, [], gr.File(uploaded_file_paths, label="Download-Chatverläufe", visible=True, file_count="multiple", interactive = False), chats #wenn löschen Button geklickt def clear_all3(history): #die session variable in gradio erweitern und alle fliepath neu in das gr.File hochladen uploaded_file_paths= "" return None, gr.Image(visible=False), [], ############################################## #History - die Frage oder das File eintragen... #in history_file ist ein file gespeichert, falls voher im Verlauf schon ein File hochgeladen wurde. #wird ein neuer File hochgeladen, so wird history_fiel dadurch ersetzt def add_text(chatbot, history, prompt, file, file_history): if (file == None): chatbot = chatbot +[(prompt, None)] else: file_history = file if (prompt == ""): chatbot=chatbot + [((file.name,), "Prompt fehlt!")] else: chatbot = chatbot +[("Hochgeladenes Dokument: "+ get_filename(file) +"\n" + prompt, None)] return chatbot, history, prompt, file, file_history, gr.Image(visible = False), "" """ def add_text2(chatbot, prompt): if (prompt == ""): chatbot = chatbot + [("", "Prompt fehlt!")] else: chatbot = chatbot + [(prompt, None)] return chatbot, prompt, "" """ ############################################ #nach dem Upload soll das zusätzliche Fenster mit dem image drinnen angezeigt werden def file_anzeigen(file): ext = analyze_file(file) if (ext == "png" or ext == "PNG" or ext == "jpg" or ext == "jpeg" or ext == "JPG" or ext == "JPEG"): return gr.Image(width=47, visible=True, interactive = False, height=47, min_width=47, show_label=False, show_share_button=False, show_download_button=False, scale = 0.5), file, file else: return gr.Image(width=47, visible=True, interactive = False, height=47, min_width=47, show_label=False, show_share_button=False, show_download_button=False, scale = 0.5), "data/file.png", file def file_loeschen(): return None, gr.Image(visible = False) ############################################ #wenn 'Stop' Button geklickt, dann Message dazu und das Eingabe-Fenster leeren def cancel_outputing(): reset_textbox() return "Stop Done" def reset_textbox(): return gr.update(value=""),"" #################################################### #aus einem Text-Prompt die Antwort von KI bekommen def generate_text (prompt, chatbot, history, vektordatenbank, retriever, top_p=0.6, temperature=0.2, max_new_tokens=4048, max_context_length_tokens=2048, repetition_penalty=1.3, top_k=35): if (prompt == ""): raise gr.Error("Prompt ist erforderlich.") try: ######################################### #Prompt mit History Daten zusammenstellen: #Prompt an history anhängen und einen Text daraus machen #history_text_und_prompt = generate_prompt_with_history(prompt, history) #oder an Hugging Face -------------------------- print("HF Anfrage.......................") #zusätzliche Dokumenten Splits aus DB zum Prompt hinzufügen (aus VektorDB - Chroma oder Mongo DB) print("LLM aufrufen mit RAG: .....................................................") ############################################## #Verschiedene Alternativen als llm übergeben an die rag-chain ############################################# #0. Alternative - repo ID # Verwenden Sie die Inference Api von huggingface_hub #llm = InferenceApi(repo_id, token=hf_token) #result = rag_chain(llm, history_text_und_prompt, retriever) ############################################## #1.Alternative mit Inference API ung HF EndPoint # Erstelle eine HuggingFaceEndPoints-Instanz mit den entsprechenden Endpunkt-Parametern """ llm = HuggingFaceEndpoint( endpoint_url=f"https://api-inference.huggingface.co/models/{MODEL_NAME_HF}", api_key=hf_token, temperature=0.5, max_length=1024, top_k=top_k, top_p=top_p, repetition_penalty=repetition_penalty ) result = rag_chain(llm, history_text_und_prompt, retriever) ############################################# #2. Alternative: mit API_URL #result = rag_chain(API_URL, history_text_und_prompt, retriever) ############################################# #3.te Alternative für pipeline # Erstelle eine Pipeline mit den gewünschten Parametern #llm = pipeline("text-generation", model=MODEL_NAME_HF, config={"temperature": 0.5, "max_length": 1024, "num_return_sequences": 1, "top_k": top_k, "top_p": top_p, "repetition_penalty": repetition_penalty}, trust_remote_code=True) #llm = pipeline("summarization", model=MODEL_NAME_HF, trust_remote_code=True) #result = rag_chain(llm, history_text_und_prompt, retriever) """ result = rag_chain_simpel(prompt, retriever) except Exception as e: raise gr.Error(e) return result, False ############################################################## #Eingaben der GUI verarbeiten def generate_auswahl(prompt_in, file, file_history, chatbot, history, anzahl_docs=4, top_p=0.6, temperature=0.5, max_new_tokens=4048, max_context_length_tokens=2048, repetition_penalty=1.3,top_k=5, validate=False): global vektordatenbank, retriever #nur wenn man sich validiert hat, kann die Anwendung los legen if (validate and not prompt_in == "" and not prompt_in == None): # Vektorstore initialisieren #falls schon ein File hochgeladen wurde, ist es in history_file gespeichert - falls ein neues File hochgeladen wurde, wird es anschließend neu gesetzt neu_file = file_history #prompt normalisieren bevor er an die KIs geht prompt = preprocess_text(prompt_in) #muss nur einmal ausgeführt werden... #?????????????????????????????????????????????? Nicht passend zum Promt??????????????????????????? if vektordatenbank == None: print("db neu aufbauen!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1") preprocessed_splits, split_to_original_mapping = document_loading_splitting() if preprocessed_splits: vektordatenbank, retriever = document_storage_chroma(preprocessed_splits) #kein Bild hochgeladen -> auf Text antworten... status = "Antwort der Vektordatenbank" results, status = generate_text(prompt, chatbot, history,vektordatenbank, retriever, top_p=0.6, temperature=0.5, max_new_tokens=4048, max_context_length_tokens=2048, repetition_penalty=1.3, top_k=3) #in results sind die preprocessed Splits enthalten, dargestellt werden sollen die orginalen: relevant_docs_org=[] for result in results['relevant_docs']: original_split = split_to_original_mapping[result.id] relevant_docs_org.append(original_split) #Ergebnisse für history und chatbot zusammenstellen summary = str(results['answer']) + "\n\nAuszüge dazu: " summary += " ".join([ '