|
|
from haystack import Pipeline |
|
|
from haystack.document_stores.in_memory import InMemoryDocumentStore |
|
|
from haystack.components.converters import PyPDFToDocument |
|
|
from haystack.components.websearch import SerperDevWebSearch |
|
|
from haystack.components.fetchers import LinkContentFetcher |
|
|
from haystack.components.converters import HTMLToDocument |
|
|
from haystack.components.preprocessors import DocumentCleaner |
|
|
from haystack.components.preprocessors import DocumentSplitter |
|
|
from haystack.components.rankers import TransformersSimilarityRanker |
|
|
from haystack.components.writers import DocumentWriter |
|
|
from haystack.components.embedders import SentenceTransformersTextEmbedder, SentenceTransformersDocumentEmbedder |
|
|
from haystack.components.retrievers.in_memory import InMemoryEmbeddingRetriever |
|
|
from haystack.components.retrievers.in_memory import InMemoryBM25Retriever |
|
|
from haystack.components.generators import OpenAIGenerator |
|
|
from haystack.components.builders.answer_builder import AnswerBuilder |
|
|
from haystack.components.builders.prompt_builder import PromptBuilder |
|
|
|
|
|
import os, sys |
|
|
|
|
|
import streamlit as st |
|
|
import streamlit.components.v1 as components |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
st.set_page_config(layout="wide") |
|
|
st.title("The Real ChatDvG") |
|
|
with st.container(): |
|
|
st.markdown("[Dirk von Gehlen](https://www.dirkvongehlen.de), kurz DvG, ist ein deutscher Journalist und Autor. Dies hier ist sein [KI-Spiegel](https://www.dirkvongehlen.de/ich/jetzt-wirds-persoenlich-das-bin-ja-ich-digitale-dezember-notizen/) ... oder vielleicht ist es doch der wahre DvG? Finde es heraus!") |
|
|
|
|
|
web_search = SerperDevWebSearch(top_k=5, |
|
|
allowed_domains=["https://www.dirkvongehlen.de"] |
|
|
) |
|
|
|
|
|
link_content = LinkContentFetcher() |
|
|
html_converter = HTMLToDocument() |
|
|
|
|
|
prompt = PromptBuilder(template="""Du bist Dirk von Gehlen, ein deutscher Journalist und Autor. |
|
|
Du magst alles run um das Internet, Digitalisierung und Innovation. |
|
|
Du machst gern Sport, gehst regelmäßig joggen und verfolgst im Fußball den VfL Bochum. |
|
|
Du arbeitest als Journalist und Autor und schreibst intelligent, humorvoll und charmant. |
|
|
Du schreibst Texte, erörterst zu Themen und beantwortest Fragen von deinen Lesern. |
|
|
Dazu nutzt die gegebenen Paragraphen. |
|
|
Die Paragraphen bestehen aus Teilen deiner Newsletter, Blog-Artikel und Büchern, die zur Frage deines Lesers passen. |
|
|
Falls du die Frage beantworten kannst, antworte detailliert, aber maximal 400 Worte. |
|
|
Schreibe in deinem Stil und deiner Sprache, wie in den gegebenen Paragraphen. |
|
|
Sei dabei humorvoll und charmant aber auch anspruchsvoll und nicht lächerlich. |
|
|
Stelle sicher, dass deine Antwort keinen Bias oder Vorurteile enthält. |
|
|
Wenn du eine Information aus einem Paragraphen verwendest, nutze immer Quellenangaben in der Form [Nummer des Paragraphs]. |
|
|
Nutze beispielsweise [x] um anzugeben, dass du Informationen aus [x] genutzt hast. |
|
|
Die Quellenangabe darf nur die Zahl erwähnen, die in eckigen Klammern [x] genannt ist. |
|
|
|
|
|
Anfrage: {{ query }} |
|
|
Hier die Paragraphen: |
|
|
{% for document in documents %} |
|
|
Paragraph[{{ loop.index }}]: |
|
|
{{ document.content }} |
|
|
{% endfor %} |
|
|
Dirk von Gehlen: """) |
|
|
|
|
|
prompt_node = OpenAIGenerator(model="gpt-4", |
|
|
generation_kwargs={"temperature":0.1, "frequency_penalty":0.8} |
|
|
) |
|
|
|
|
|
ranker = TransformersSimilarityRanker() |
|
|
ranker.warm_up() |
|
|
|
|
|
|
|
|
question = st.text_input("Deine Anfrage:") |
|
|
answers = "" |
|
|
|
|
|
|
|
|
if st.button("Los!"): |
|
|
|
|
|
p = Pipeline() |
|
|
p.add_component("search", web_search) |
|
|
p.add_component("fetcher", link_content) |
|
|
p.add_component("converter", html_converter) |
|
|
p.add_component(instance=DocumentCleaner(), name="cleaner") |
|
|
p.add_component(instance=DocumentSplitter(split_by="sentence", split_length=15), name="splitter") |
|
|
p.add_component(instance=ranker, name="ranker") |
|
|
p.add_component("prompt_builder", prompt) |
|
|
p.add_component("llm", prompt_node) |
|
|
p.add_component("answer_builder", AnswerBuilder()) |
|
|
|
|
|
p.connect("search.links", "fetcher.urls") |
|
|
p.connect("fetcher.streams", "converter.sources") |
|
|
p.connect("converter.documents", "cleaner.documents") |
|
|
p.connect("cleaner.documents", "splitter.documents") |
|
|
p.connect("splitter.documents", "ranker.documents") |
|
|
p.connect("ranker.documents", "prompt_builder.documents") |
|
|
p.connect("prompt_builder.prompt", "llm.prompt") |
|
|
p.connect("prompt_builder", "llm") |
|
|
p.connect("llm.replies", "answer_builder.replies") |
|
|
p.connect("prompt_builder.prompt", "llm.prompt") |
|
|
p.connect("ranker.documents", "answer_builder.documents") |
|
|
|
|
|
results = p.run( |
|
|
{ |
|
|
"search": {"query": question}, |
|
|
"ranker": {"query": question, "top_k": 3}, |
|
|
"prompt_builder": {"query": question}, |
|
|
"answer_builder": {"query": question} |
|
|
}, |
|
|
debug = True |
|
|
) |
|
|
|
|
|
answer = results["answer_builder"]['answers'][0].data |
|
|
urls = [ (d.meta["link"], d.meta["title"]) for d in results["search"]["documents"] ] |
|
|
print(urls, file=sys.stderr) |
|
|
|
|
|
print(answer, file=sys.stderr) |
|
|
|
|
|
with st.container(): |
|
|
for x in answer.splitlines(): |
|
|
st.markdown(x.strip()) |
|
|
for url, title in urls: |
|
|
st.markdown(f"""[{title}]({url})\n""") |
|
|
|